diff options
Diffstat (limited to 'src/ir.cpp')
| -rw-r--r-- | src/ir.cpp | 1992 |
1 files changed, 1991 insertions, 1 deletions
diff --git a/src/ir.cpp b/src/ir.cpp index d76513e9c4..932fa837da 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1693,7 +1693,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont case NodeTypeSwitchRange: case NodeTypeErrorValueDecl: case NodeTypeTypeDecl: - zig_panic("TODO more IR gen"); + zig_panic("TODO more IR gen for node types"); } zig_unreachable(); } @@ -3966,6 +3966,8 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { return value; } +// TODO port over all this commented out code into new IR way of doing things + //static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context, // AstNode *node, const char *err_format, bool is_max) //{ @@ -7401,3 +7403,1991 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no // return nullptr; //} +// +//static LLVMValueRef gen_err_name(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeFnCallExpr); +// assert(g->generate_error_name_table); +// +// if (g->error_decls.length == 1) { +// LLVMBuildUnreachable(g->builder); +// return nullptr; +// } +// +// +// AstNode *err_val_node = node->data.fn_call_expr.params.at(0); +// LLVMValueRef err_val = gen_expr(g, err_val_node); +// +// if (want_debug_safety(g, node)) { +// LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(err_val)); +// LLVMValueRef end_val = LLVMConstInt(LLVMTypeOf(err_val), g->error_decls.length, false); +// add_bounds_check(g, err_val, LLVMIntNE, zero, LLVMIntULT, end_val); +// } +// +// LLVMValueRef indices[] = { +// LLVMConstNull(g->builtin_types.entry_usize->type_ref), +// err_val, +// }; +// return LLVMBuildInBoundsGEP(g->builder, g->err_name_table, indices, 2, ""); +//} +// +//static LLVMValueRef gen_cmp_exchange(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeFnCallExpr); +// +// AstNode *ptr_arg = node->data.fn_call_expr.params.at(0); +// AstNode *cmp_arg = node->data.fn_call_expr.params.at(1); +// AstNode *new_arg = node->data.fn_call_expr.params.at(2); +// AstNode *success_order_arg = node->data.fn_call_expr.params.at(3); +// AstNode *failure_order_arg = node->data.fn_call_expr.params.at(4); +// +// LLVMValueRef ptr_val = gen_expr(g, ptr_arg); +// LLVMValueRef cmp_val = gen_expr(g, cmp_arg); +// LLVMValueRef new_val = gen_expr(g, new_arg); +// +// ConstExprValue *success_order_val = &get_resolved_expr(success_order_arg)->const_val; +// ConstExprValue *failure_order_val = &get_resolved_expr(failure_order_arg)->const_val; +// +// assert(success_order_val->ok); +// assert(failure_order_val->ok); +// +// LLVMAtomicOrdering success_order = to_LLVMAtomicOrdering((AtomicOrder)success_order_val->data.x_enum.tag); +// LLVMAtomicOrdering failure_order = to_LLVMAtomicOrdering((AtomicOrder)failure_order_val->data.x_enum.tag); +// +// LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val, +// success_order, failure_order); +// +// return LLVMBuildExtractValue(g->builder, result_val, 1, ""); +//} +// +//static LLVMValueRef gen_div_exact(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeFnCallExpr); +// +// AstNode *op1_node = node->data.fn_call_expr.params.at(0); +// AstNode *op2_node = node->data.fn_call_expr.params.at(1); +// +// LLVMValueRef op1_val = gen_expr(g, op1_node); +// LLVMValueRef op2_val = gen_expr(g, op2_node); +// +// return gen_div(g, node, op1_val, op2_val, get_expr_type(op1_node), true); +//} +// +//static LLVMValueRef gen_truncate(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeFnCallExpr); +// +// TypeTableEntry *dest_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0)); +// AstNode *src_node = node->data.fn_call_expr.params.at(1); +// +// LLVMValueRef src_val = gen_expr(g, src_node); +// +// return LLVMBuildTrunc(g->builder, src_val, dest_type->type_ref, ""); +//} +// +//static LLVMValueRef gen_shl_with_overflow(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeFnCallExpr); +// +// size_t fn_call_param_count = node->data.fn_call_expr.params.length; +// assert(fn_call_param_count == 4); +// +// TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0)); +// assert(int_type->id == TypeTableEntryIdInt); +// +// LLVMValueRef val1 = gen_expr(g, node->data.fn_call_expr.params.at(1)); +// LLVMValueRef val2 = gen_expr(g, node->data.fn_call_expr.params.at(2)); +// LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3)); +// +// LLVMValueRef result = LLVMBuildShl(g->builder, val1, val2, ""); +// LLVMValueRef orig_val; +// if (int_type->data.integral.is_signed) { +// orig_val = LLVMBuildAShr(g->builder, result, val2, ""); +// } else { +// orig_val = LLVMBuildLShr(g->builder, result, val2, ""); +// } +// LLVMValueRef overflow_bit = LLVMBuildICmp(g->builder, LLVMIntNE, val1, orig_val, ""); +// +// LLVMBuildStore(g->builder, result, ptr_result); +// +// return overflow_bit; +//} +// +//static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeFnCallExpr); +// AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; +// assert(fn_ref_expr->type == NodeTypeSymbol); +// BuiltinFnEntry *builtin_fn = node->data.fn_call_expr.builtin_fn; +// +// switch (builtin_fn->id) { +// case BuiltinFnIdInvalid: +// case BuiltinFnIdTypeof: +// case BuiltinFnIdCInclude: +// case BuiltinFnIdCDefine: +// case BuiltinFnIdCUndef: +// case BuiltinFnIdImport: +// case BuiltinFnIdCImport: +// case BuiltinFnIdCompileErr: +// case BuiltinFnIdIntType: +// zig_unreachable(); +// case BuiltinFnIdCtz: +// case BuiltinFnIdClz: +// { +// size_t fn_call_param_count = node->data.fn_call_expr.params.length; +// assert(fn_call_param_count == 2); +// TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0)); +// assert(int_type->id == TypeTableEntryIdInt); +// LLVMValueRef fn_val = get_int_builtin_fn(g, int_type, builtin_fn->id); +// LLVMValueRef operand = gen_expr(g, node->data.fn_call_expr.params.at(1)); +// LLVMValueRef params[] { +// operand, +// LLVMConstNull(LLVMInt1Type()), +// }; +// return LLVMBuildCall(g->builder, fn_val, params, 2, ""); +// } +// case BuiltinFnIdAddWithOverflow: +// case BuiltinFnIdSubWithOverflow: +// case BuiltinFnIdMulWithOverflow: +// { +// size_t fn_call_param_count = node->data.fn_call_expr.params.length; +// assert(fn_call_param_count == 4); +// +// TypeTableEntry *int_type = get_type_for_type_node(node->data.fn_call_expr.params.at(0)); +// AddSubMul add_sub_mul; +// if (builtin_fn->id == BuiltinFnIdAddWithOverflow) { +// add_sub_mul = AddSubMulAdd; +// } else if (builtin_fn->id == BuiltinFnIdSubWithOverflow) { +// add_sub_mul = AddSubMulSub; +// } else if (builtin_fn->id == BuiltinFnIdMulWithOverflow) { +// add_sub_mul = AddSubMulMul; +// } else { +// zig_unreachable(); +// } +// LLVMValueRef fn_val = get_int_overflow_fn(g, int_type, add_sub_mul); +// +// LLVMValueRef op1 = gen_expr(g, node->data.fn_call_expr.params.at(1)); +// LLVMValueRef op2 = gen_expr(g, node->data.fn_call_expr.params.at(2)); +// LLVMValueRef ptr_result = gen_expr(g, node->data.fn_call_expr.params.at(3)); +// +// LLVMValueRef params[] = { +// op1, +// op2, +// }; +// +// LLVMValueRef result_struct = LLVMBuildCall(g->builder, fn_val, params, 2, ""); +// LLVMValueRef result = LLVMBuildExtractValue(g->builder, result_struct, 0, ""); +// LLVMValueRef overflow_bit = LLVMBuildExtractValue(g->builder, result_struct, 1, ""); +// LLVMBuildStore(g->builder, result, ptr_result); +// +// return overflow_bit; +// } +// case BuiltinFnIdShlWithOverflow: +// return gen_shl_with_overflow(g, node); +// case BuiltinFnIdMemcpy: +// { +// size_t fn_call_param_count = node->data.fn_call_expr.params.length; +// assert(fn_call_param_count == 3); +// +// AstNode *dest_node = node->data.fn_call_expr.params.at(0); +// TypeTableEntry *dest_type = get_expr_type(dest_node); +// +// LLVMValueRef dest_ptr = gen_expr(g, dest_node); +// LLVMValueRef src_ptr = gen_expr(g, node->data.fn_call_expr.params.at(1)); +// LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2)); +// +// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); +// +// LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); +// LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, ptr_u8, ""); +// +// uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type); +// +// LLVMValueRef params[] = { +// dest_ptr_casted, // dest pointer +// src_ptr_casted, // source pointer +// len_val, // byte count +// LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes +// LLVMConstNull(LLVMInt1Type()), // is volatile +// }; +// +// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); +// return nullptr; +// } +// case BuiltinFnIdMemset: +// { +// size_t fn_call_param_count = node->data.fn_call_expr.params.length; +// assert(fn_call_param_count == 3); +// +// AstNode *dest_node = node->data.fn_call_expr.params.at(0); +// TypeTableEntry *dest_type = get_expr_type(dest_node); +// +// LLVMValueRef dest_ptr = gen_expr(g, dest_node); +// LLVMValueRef char_val = gen_expr(g, node->data.fn_call_expr.params.at(1)); +// LLVMValueRef len_val = gen_expr(g, node->data.fn_call_expr.params.at(2)); +// +// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); +// +// LLVMValueRef dest_ptr_casted = LLVMBuildBitCast(g->builder, dest_ptr, ptr_u8, ""); +// +// uint64_t align_in_bytes = get_memcpy_align(g, dest_type->data.pointer.child_type); +// +// LLVMValueRef params[] = { +// dest_ptr_casted, // dest pointer +// char_val, // source pointer +// len_val, // byte count +// LLVMConstInt(LLVMInt32Type(), align_in_bytes, false), // align in bytes +// LLVMConstNull(LLVMInt1Type()), // is volatile +// }; +// +// LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, ""); +// return nullptr; +// } +// case BuiltinFnIdSizeof: +// case BuiltinFnIdAlignof: +// case BuiltinFnIdMinValue: +// case BuiltinFnIdMaxValue: +// case BuiltinFnIdMemberCount: +// case BuiltinFnIdConstEval: +// case BuiltinFnIdEmbedFile: +// // caught by constant expression eval codegen +// zig_unreachable(); +// case BuiltinFnIdCompileVar: +// return nullptr; +// case BuiltinFnIdErrName: +// return gen_err_name(g, node); +// case BuiltinFnIdBreakpoint: +// return LLVMBuildCall(g->builder, g->trap_fn_val, nullptr, 0, ""); +// case BuiltinFnIdFrameAddress: +// case BuiltinFnIdReturnAddress: +// { +// LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref); +// return LLVMBuildCall(g->builder, builtin_fn->fn_val, &zero, 1, ""); +// } +// case BuiltinFnIdCmpExchange: +// return gen_cmp_exchange(g, node); +// case BuiltinFnIdFence: +// return gen_fence(g, node); +// case BuiltinFnIdDivExact: +// return gen_div_exact(g, node); +// case BuiltinFnIdTruncate: +// return gen_truncate(g, node); +// case BuiltinFnIdUnreachable: +// zig_panic("moved to ir render"); +// case BuiltinFnIdSetFnTest: +// case BuiltinFnIdSetFnVisible: +// case BuiltinFnIdSetFnStaticEval: +// case BuiltinFnIdSetFnNoInline: +// case BuiltinFnIdSetDebugSafety: +// // do nothing +// return nullptr; +// } +// zig_unreachable(); +//} +// +//static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntry *enum_type, +// AstNode *arg_node) +//{ +// assert(node->type == NodeTypeFieldAccessExpr); +// +// uint64_t value = node->data.field_access_expr.type_enum_field->value; +// LLVMTypeRef tag_type_ref = enum_type->data.enumeration.tag_type->type_ref; +// LLVMValueRef tag_value = LLVMConstInt(tag_type_ref, value, false); +// +// if (enum_type->data.enumeration.gen_field_count == 0) { +// return tag_value; +// } else { +// TypeTableEntry *arg_node_type = nullptr; +// LLVMValueRef new_union_val = gen_expr(g, arg_node); +// if (arg_node) { +// arg_node_type = get_expr_type(arg_node); +// } else { +// arg_node_type = g->builtin_types.entry_void; +// } +// +// LLVMValueRef tmp_struct_ptr = node->data.field_access_expr.resolved_struct_val_expr.ptr; +// +// // populate the new tag value +// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); +// LLVMBuildStore(g->builder, tag_value, tag_field_ptr); +// +// if (arg_node_type->id != TypeTableEntryIdVoid) { +// // populate the union value +// TypeTableEntry *union_val_type = get_expr_type(arg_node); +// LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); +// LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, +// LLVMPointerType(union_val_type->type_ref, 0), ""); +// +// gen_assign_raw(g, arg_node, BinOpTypeAssign, bitcasted_union_field_ptr, new_union_val, +// union_val_type, union_val_type); +// +// } +// +// return tmp_struct_ptr; +// } +//} +// +//static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeFnCallExpr); +// +// if (node->data.fn_call_expr.is_builtin) { +// return gen_builtin_fn_call_expr(g, node); +// } +// +// FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; +// TypeTableEntry *struct_type = nullptr; +// AstNode *first_param_expr = nullptr; +// +// AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; +// if (fn_ref_expr->type == NodeTypeFieldAccessExpr && +// fn_ref_expr->data.field_access_expr.is_member_fn) +// { +// first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; +// struct_type = get_expr_type(first_param_expr); +// } +// +// TypeTableEntry *fn_type; +// LLVMValueRef fn_val; +// AstNode *generic_proto_node; +// if (fn_table_entry) { +// fn_val = fn_table_entry->fn_value; +// fn_type = fn_table_entry->type_entry; +// generic_proto_node = fn_table_entry->proto_node->data.fn_proto.generic_proto_node; +// } else { +// fn_val = gen_expr(g, fn_ref_expr); +// fn_type = get_expr_type(fn_ref_expr); +// generic_proto_node = nullptr; +// } +// +// TypeTableEntry *src_return_type = fn_type->data.fn.fn_type_id.return_type; +// +// bool ret_has_bits = type_has_bits(src_return_type); +// +// size_t fn_call_param_count = node->data.fn_call_expr.params.length; +// bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); +// size_t actual_param_count = fn_call_param_count + (struct_type ? 1 : 0) + (first_arg_ret ? 1 : 0); +// bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args; +// +// // don't really include void values +// LLVMValueRef *gen_param_values = allocate<LLVMValueRef>(actual_param_count); +// +// size_t gen_param_index = 0; +// if (first_arg_ret) { +// gen_param_values[gen_param_index] = node->data.fn_call_expr.tmp_ptr; +// gen_param_index += 1; +// } +// if (struct_type && type_has_bits(struct_type)) { +// gen_param_values[gen_param_index] = gen_expr(g, first_param_expr); +// assert(gen_param_values[gen_param_index]); +// gen_param_index += 1; +// } +// +// for (size_t call_i = 0; call_i < fn_call_param_count; call_i += 1) { +// size_t proto_i = call_i + (struct_type ? 1 : 0); +// if (generic_proto_node && +// generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline) +// { +// continue; +// } +// AstNode *expr_node = node->data.fn_call_expr.params.at(call_i); +// LLVMValueRef param_value = gen_expr(g, expr_node); +// assert(param_value); +// TypeTableEntry *param_type = get_expr_type(expr_node); +// if (is_var_args || type_has_bits(param_type)) { +// gen_param_values[gen_param_index] = param_value; +// gen_param_index += 1; +// } +// } +// +// LLVMValueRef result = ZigLLVMBuildCall(g->builder, fn_val, +// gen_param_values, gen_param_index, fn_type->data.fn.calling_convention, ""); +// +// if (src_return_type->id == TypeTableEntryIdUnreachable) { +// return LLVMBuildUnreachable(g->builder); +// } else if (!ret_has_bits) { +// return nullptr; +// } else if (first_arg_ret) { +// return node->data.fn_call_expr.tmp_ptr; +// } else { +// return result; +// } +//} +// +//static LLVMValueRef gen_array_base_ptr(CodeGen *g, AstNode *node) { +// TypeTableEntry *type_entry = get_expr_type(node); +// +// LLVMValueRef array_ptr; +// if (node->type == NodeTypeFieldAccessExpr) { +// array_ptr = gen_field_access_expr(g, node, true); +// if (type_entry->id == TypeTableEntryIdPointer) { +// // we have a double pointer so we must dereference it once +// array_ptr = LLVMBuildLoad(g->builder, array_ptr, ""); +// } +// } else { +// array_ptr = gen_expr(g, node); +// } +// +// assert(!array_ptr || LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); +// +// return array_ptr; +//} +// +//static LLVMValueRef gen_array_ptr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeArrayAccessExpr); +// +// AstNode *array_expr_node = node->data.array_access_expr.array_ref_expr; +// TypeTableEntry *array_type = get_expr_type(array_expr_node); +// +// LLVMValueRef array_ptr = gen_array_base_ptr(g, array_expr_node); +// +// LLVMValueRef subscript_value = gen_expr(g, node->data.array_access_expr.subscript); +// return gen_array_elem_ptr(g, node, array_ptr, array_type, subscript_value); +//} +// +//static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **out_type_entry) { +// assert(node->type == NodeTypeFieldAccessExpr); +// +// AstNode *struct_expr_node = node->data.field_access_expr.struct_expr; +// +// *out_type_entry = node->data.field_access_expr.type_struct_field->type_entry; +// if (!type_has_bits(*out_type_entry)) { +// return nullptr; +// } +// +// LLVMValueRef struct_ptr; +// if (struct_expr_node->type == NodeTypeSymbol) { +// VariableTableEntry *var = get_resolved_expr(struct_expr_node)->variable; +// assert(var); +// +// if (var->type->id == TypeTableEntryIdPointer) { +// struct_ptr = LLVMBuildLoad(g->builder, var->value_ref, ""); +// } else { +// struct_ptr = var->value_ref; +// } +// } else if (struct_expr_node->type == NodeTypeFieldAccessExpr) { +// struct_ptr = gen_field_access_expr(g, struct_expr_node, true); +// TypeTableEntry *field_type = get_expr_type(struct_expr_node); +// if (field_type->id == TypeTableEntryIdPointer) { +// // we have a double pointer so we must dereference it once +// struct_ptr = LLVMBuildLoad(g->builder, struct_ptr, ""); +// } +// } else { +// struct_ptr = gen_expr(g, struct_expr_node); +// } +// +// assert(LLVMGetTypeKind(LLVMTypeOf(struct_ptr)) == LLVMPointerTypeKind); +// assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(struct_ptr))) == LLVMStructTypeKind); +// +// size_t gen_field_index = node->data.field_access_expr.type_struct_field->gen_index; +// assert(gen_field_index != SIZE_MAX); +// +// return LLVMBuildStructGEP(g->builder, struct_ptr, gen_field_index, ""); +//} +// +//static LLVMValueRef gen_slice_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeSliceExpr); +// +// AstNode *array_ref_node = node->data.slice_expr.array_ref_expr; +// TypeTableEntry *array_type = get_expr_type(array_ref_node); +// +// LLVMValueRef tmp_struct_ptr = node->data.slice_expr.resolved_struct_val_expr.ptr; +// LLVMValueRef array_ptr = gen_array_base_ptr(g, array_ref_node); +// +// if (array_type->id == TypeTableEntryIdArray) { +// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); +// LLVMValueRef end_val; +// if (node->data.slice_expr.end) { +// end_val = gen_expr(g, node->data.slice_expr.end); +// } else { +// end_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref, array_type->data.array.len, false); +// } +// +// if (want_debug_safety(g, node)) { +// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); +// if (node->data.slice_expr.end) { +// LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->type_ref, +// array_type->data.array.len, false); +// add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, array_end); +// } +// } +// +// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); +// LLVMValueRef indices[] = { +// LLVMConstNull(g->builtin_types.entry_usize->type_ref), +// start_val, +// }; +// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, indices, 2, ""); +// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); +// +// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); +// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); +// LLVMBuildStore(g->builder, len_value, len_field_ptr); +// +// return tmp_struct_ptr; +// } else if (array_type->id == TypeTableEntryIdPointer) { +// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); +// LLVMValueRef end_val = gen_expr(g, node->data.slice_expr.end); +// +// if (want_debug_safety(g, node)) { +// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); +// } +// +// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 0, ""); +// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, array_ptr, &start_val, 1, ""); +// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); +// +// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, 1, ""); +// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); +// LLVMBuildStore(g->builder, len_value, len_field_ptr); +// +// return tmp_struct_ptr; +// } else if (array_type->id == TypeTableEntryIdStruct) { +// assert(array_type->data.structure.is_slice); +// assert(LLVMGetTypeKind(LLVMTypeOf(array_ptr)) == LLVMPointerTypeKind); +// assert(LLVMGetTypeKind(LLVMGetElementType(LLVMTypeOf(array_ptr))) == LLVMStructTypeKind); +// +// size_t ptr_index = array_type->data.structure.fields[0].gen_index; +// assert(ptr_index != SIZE_MAX); +// size_t len_index = array_type->data.structure.fields[1].gen_index; +// assert(len_index != SIZE_MAX); +// +// LLVMValueRef prev_end = nullptr; +// if (!node->data.slice_expr.end || want_debug_safety(g, node)) { +// LLVMValueRef src_len_ptr = LLVMBuildStructGEP(g->builder, array_ptr, len_index, ""); +// prev_end = LLVMBuildLoad(g->builder, src_len_ptr, ""); +// } +// +// LLVMValueRef start_val = gen_expr(g, node->data.slice_expr.start); +// LLVMValueRef end_val; +// if (node->data.slice_expr.end) { +// end_val = gen_expr(g, node->data.slice_expr.end); +// } else { +// end_val = prev_end; +// } +// +// if (want_debug_safety(g, node)) { +// assert(prev_end); +// add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); +// if (node->data.slice_expr.end) { +// add_bounds_check(g, end_val, LLVMIntEQ, nullptr, LLVMIntULE, prev_end); +// } +// } +// +// LLVMValueRef src_ptr_ptr = LLVMBuildStructGEP(g->builder, array_ptr, ptr_index, ""); +// LLVMValueRef src_ptr = LLVMBuildLoad(g->builder, src_ptr_ptr, ""); +// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, ptr_index, ""); +// LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr, &start_val, len_index, ""); +// LLVMBuildStore(g->builder, slice_start_ptr, ptr_field_ptr); +// +// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, len_index, ""); +// LLVMValueRef len_value = LLVMBuildNSWSub(g->builder, end_val, start_val, ""); +// LLVMBuildStore(g->builder, len_value, len_field_ptr); +// +// return tmp_struct_ptr; +// } else { +// zig_unreachable(); +// } +//} +// +// +//static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, +// TypeTableEntry **out_type_entry) +//{ +// LLVMValueRef target_ref; +// +// if (node->type == NodeTypeSymbol) { +// VariableTableEntry *var = get_resolved_expr(node)->variable; +// assert(var); +// +// *out_type_entry = var->type; +// target_ref = var->value_ref; +// } else if (node->type == NodeTypeArrayAccessExpr) { +// TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr); +// if (array_type->id == TypeTableEntryIdArray) { +// *out_type_entry = array_type->data.array.child_type; +// target_ref = gen_array_ptr(g, node); +// } else if (array_type->id == TypeTableEntryIdPointer) { +// *out_type_entry = array_type->data.pointer.child_type; +// target_ref = gen_array_ptr(g, node); +// } else if (array_type->id == TypeTableEntryIdStruct) { +// assert(array_type->data.structure.is_slice); +// *out_type_entry = array_type->data.structure.fields[0].type_entry->data.pointer.child_type; +// target_ref = gen_array_ptr(g, node); +// } else { +// zig_unreachable(); +// } +// } else if (node->type == NodeTypeFieldAccessExpr) { +// AstNode *struct_expr_node = node->data.field_access_expr.struct_expr; +// TypeTableEntry *struct_type = get_expr_type(struct_expr_node); +// if (struct_type->id == TypeTableEntryIdNamespace) { +// target_ref = gen_field_access_expr(g, node, true); +// *out_type_entry = get_expr_type(node); +// } else { +// target_ref = gen_field_ptr(g, node, out_type_entry); +// } +// } else if (node->type == NodeTypePrefixOpExpr) { +// assert(node->data.prefix_op_expr.prefix_op == PrefixOpDereference); +// AstNode *target_expr = node->data.prefix_op_expr.primary_expr; +// TypeTableEntry *type_entry = get_expr_type(target_expr); +// assert(type_entry->id == TypeTableEntryIdPointer); +// *out_type_entry = type_entry->data.pointer.child_type; +// return gen_expr(g, target_expr); +// } else { +// zig_panic("bad assign target"); +// } +// +// return target_ref; +//} +// +//static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeBinOpExpr); +// +// LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); +// LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); +// +// TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1); +// TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); +// return gen_arithmetic_bin_op(g, node, val1, val2, op1_type, op2_type, node->data.bin_op_expr.bin_op); +// +//} +// +//static LLVMValueRef gen_bool_and_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeBinOpExpr); +// +// LLVMValueRef val1 = gen_expr(g, node->data.bin_op_expr.op1); +// LLVMBasicBlockRef post_val1_block = LLVMGetInsertBlock(g->builder); +// +// // block for when val1 == true +// LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndTrue"); +// // block for when val1 == false (don't even evaluate the second part) +// LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolAndFalse"); +// +// LLVMBuildCondBr(g->builder, val1, true_block, false_block); +// +// LLVMPositionBuilderAtEnd(g->builder, true_block); +// LLVMValueRef val2 = gen_expr(g, node->data.bin_op_expr.op2); +// LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder); +// +// LLVMBuildBr(g->builder, false_block); +// +// LLVMPositionBuilderAtEnd(g->builder, false_block); +// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), ""); +// LLVMValueRef incoming_values[2] = {val1, val2}; +// LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block}; +// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); +// +// return phi; +//} +// +//static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) { +// assert(expr_node->type == NodeTypeBinOpExpr); +// +// LLVMValueRef val1 = gen_expr(g, expr_node->data.bin_op_expr.op1); +// LLVMBasicBlockRef post_val1_block = LLVMGetInsertBlock(g->builder); +// +// // block for when val1 == false +// LLVMBasicBlockRef false_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrFalse"); +// // block for when val1 == true (don't even evaluate the second part) +// LLVMBasicBlockRef true_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "BoolOrTrue"); +// +// LLVMBuildCondBr(g->builder, val1, true_block, false_block); +// +// LLVMPositionBuilderAtEnd(g->builder, false_block); +// LLVMValueRef val2 = gen_expr(g, expr_node->data.bin_op_expr.op2); +// +// LLVMBasicBlockRef post_val2_block = LLVMGetInsertBlock(g->builder); +// +// LLVMBuildBr(g->builder, true_block); +// +// LLVMPositionBuilderAtEnd(g->builder, true_block); +// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMInt1Type(), ""); +// LLVMValueRef incoming_values[2] = {val1, val2}; +// LLVMBasicBlockRef incoming_blocks[2] = {post_val1_block, post_val2_block}; +// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); +// +// return phi; +//} +// +//static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeBinOpExpr); +// +// AstNode *lhs_node = node->data.bin_op_expr.op1; +// +// TypeTableEntry *op1_type; +// +// LLVMValueRef target_ref = gen_lvalue(g, node, lhs_node, &op1_type); +// +// TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2); +// +// LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2); +// +// gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type); +// return nullptr; +//} +// +//static LLVMValueRef gen_unwrap_maybe_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeBinOpExpr); +// assert(node->data.bin_op_expr.bin_op == BinOpTypeUnwrapMaybe); +// +// AstNode *op1_node = node->data.bin_op_expr.op1; +// AstNode *op2_node = node->data.bin_op_expr.op2; +// +// LLVMValueRef maybe_struct_ref = gen_expr(g, op1_node); +// +// TypeTableEntry *maybe_type = get_expr_type(op1_node); +// assert(maybe_type->id == TypeTableEntryIdMaybe); +// TypeTableEntry *child_type = maybe_type->data.maybe.child_type; +// +// LLVMValueRef cond_value; +// if (child_type->id == TypeTableEntryIdPointer || +// child_type->id == TypeTableEntryIdFn) +// { +// cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, maybe_struct_ref, +// LLVMConstNull(child_type->type_ref), ""); +// } else { +// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 1, ""); +// cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); +// } +// +// LLVMBasicBlockRef non_null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNonNull"); +// LLVMBasicBlockRef null_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeNull"); +// LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEnd"); +// +// bool null_reachable = get_expr_type(op2_node)->id != TypeTableEntryIdUnreachable; +// +// LLVMBuildCondBr(g->builder, cond_value, non_null_block, null_block); +// +// LLVMPositionBuilderAtEnd(g->builder, non_null_block); +// LLVMValueRef non_null_result = gen_unwrap_maybe(g, op1_node, maybe_struct_ref); +// LLVMBuildBr(g->builder, end_block); +// LLVMBasicBlockRef post_non_null_result_block = LLVMGetInsertBlock(g->builder); +// +// LLVMPositionBuilderAtEnd(g->builder, null_block); +// LLVMValueRef null_result = gen_expr(g, op2_node); +// if (null_reachable) { +// LLVMBuildBr(g->builder, end_block); +// } +// LLVMBasicBlockRef post_null_result_block = LLVMGetInsertBlock(g->builder); +// +// LLVMPositionBuilderAtEnd(g->builder, end_block); +// if (null_reachable) { +// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(non_null_result), ""); +// LLVMValueRef incoming_values[2] = {non_null_result, null_result}; +// LLVMBasicBlockRef incoming_blocks[2] = {post_non_null_result_block, post_null_result_block}; +// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); +// return phi; +// } else { +// return non_null_result; +// } +// +// return nullptr; +//} +// +//static LLVMValueRef gen_unwrap_err_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeUnwrapErrorExpr); +// +// AstNode *op1 = node->data.unwrap_err_expr.op1; +// AstNode *op2 = node->data.unwrap_err_expr.op2; +// VariableTableEntry *var = node->data.unwrap_err_expr.var; +// +// LLVMValueRef expr_val = gen_expr(g, op1); +// TypeTableEntry *expr_type = get_expr_type(op1); +// TypeTableEntry *op2_type = get_expr_type(op2); +// assert(expr_type->id == TypeTableEntryIdErrorUnion); +// TypeTableEntry *child_type = expr_type->data.error.child_type; +// LLVMValueRef err_val; +// if (handle_is_ptr(expr_type)) { +// LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 0, ""); +// err_val = LLVMBuildLoad(g->builder, err_val_ptr, ""); +// } else { +// err_val = expr_val; +// } +// LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref); +// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); +// +// LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrOk"); +// LLVMBasicBlockRef err_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrError"); +// LLVMBasicBlockRef end_block; +// bool err_reachable = op2_type->id != TypeTableEntryIdUnreachable; +// bool have_end_block = err_reachable && type_has_bits(child_type); +// if (have_end_block) { +// end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "UnwrapErrEnd"); +// } +// +// LLVMBuildCondBr(g->builder, cond_val, ok_block, err_block); +// +// LLVMPositionBuilderAtEnd(g->builder, err_block); +// if (var) { +// LLVMBuildStore(g->builder, err_val, var->value_ref); +// } +// LLVMValueRef err_result = gen_expr(g, op2); +// if (have_end_block) { +// LLVMBuildBr(g->builder, end_block); +// } else if (err_reachable) { +// LLVMBuildBr(g->builder, ok_block); +// } +// +// LLVMPositionBuilderAtEnd(g->builder, ok_block); +// if (!type_has_bits(child_type)) { +// return nullptr; +// } +// LLVMValueRef child_val_ptr = LLVMBuildStructGEP(g->builder, expr_val, 1, ""); +// LLVMValueRef child_val = get_handle_value(g, child_val_ptr, child_type); +// +// if (!have_end_block) { +// return child_val; +// } +// +// LLVMBuildBr(g->builder, end_block); +// +// LLVMPositionBuilderAtEnd(g->builder, end_block); +// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(err_result), ""); +// LLVMValueRef incoming_values[2] = {child_val, err_result}; +// LLVMBasicBlockRef incoming_blocks[2] = {ok_block, err_block}; +// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); +// return phi; +//} +// +//static void gen_defers_for_block(CodeGen *g, BlockContext *inner_block, BlockContext *outer_block, +// bool gen_error_defers, bool gen_maybe_defers) +//{ +// while (inner_block != outer_block) { +// if (inner_block->node->type == NodeTypeDefer && +// ((inner_block->node->data.defer.kind == ReturnKindUnconditional) || +// (gen_error_defers && inner_block->node->data.defer.kind == ReturnKindError) || +// (gen_maybe_defers && inner_block->node->data.defer.kind == ReturnKindMaybe))) +// { +// gen_expr(g, inner_block->node->data.defer.expr); +// } +// inner_block = inner_block->parent; +// } +//} +// +//static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeReturnExpr); +// AstNode *param_node = node->data.return_expr.expr; +// assert(param_node); +// LLVMValueRef value = gen_expr(g, param_node); +// TypeTableEntry *value_type = get_expr_type(param_node); +// +// switch (node->data.return_expr.kind) { +// case ReturnKindUnconditional: +// { +// Expr *expr = get_resolved_expr(param_node); +// if (expr->const_val.ok) { +// if (value_type->id == TypeTableEntryIdErrorUnion) { +// if (expr->const_val.data.x_err.err) { +// expr->return_knowledge = ReturnKnowledgeKnownError; +// } else { +// expr->return_knowledge = ReturnKnowledgeKnownNonError; +// } +// } else if (value_type->id == TypeTableEntryIdMaybe) { +// if (expr->const_val.data.x_maybe) { +// expr->return_knowledge = ReturnKnowledgeKnownNonNull; +// } else { +// expr->return_knowledge = ReturnKnowledgeKnownNull; +// } +// } +// } +// return gen_return(g, node, value, expr->return_knowledge); +// } +// case ReturnKindError: +// { +// assert(value_type->id == TypeTableEntryIdErrorUnion); +// TypeTableEntry *child_type = value_type->data.error.child_type; +// +// LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetReturn"); +// LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "ErrRetContinue"); +// +// LLVMValueRef err_val; +// if (type_has_bits(child_type)) { +// LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, value, 0, ""); +// err_val = LLVMBuildLoad(g->builder, err_val_ptr, ""); +// } else { +// err_val = value; +// } +// LLVMValueRef zero = LLVMConstNull(g->err_tag_type->type_ref); +// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntEQ, err_val, zero, ""); +// LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block); +// +// LLVMPositionBuilderAtEnd(g->builder, return_block); +// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; +// if (return_type->id == TypeTableEntryIdPureError) { +// gen_return(g, node, err_val, ReturnKnowledgeKnownError); +// } else if (return_type->id == TypeTableEntryIdErrorUnion) { +// if (type_has_bits(return_type->data.error.child_type)) { +// assert(g->cur_ret_ptr); +// +// LLVMValueRef tag_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 0, ""); +// LLVMBuildStore(g->builder, err_val, tag_ptr); +// LLVMBuildRetVoid(g->builder); +// } else { +// gen_return(g, node, err_val, ReturnKnowledgeKnownError); +// } +// } else { +// zig_unreachable(); +// } +// +// LLVMPositionBuilderAtEnd(g->builder, continue_block); +// if (type_has_bits(child_type)) { +// LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); +// return get_handle_value(g, val_ptr, child_type); +// } else { +// return nullptr; +// } +// } +// case ReturnKindMaybe: +// { +// assert(value_type->id == TypeTableEntryIdMaybe); +// TypeTableEntry *child_type = value_type->data.maybe.child_type; +// +// LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetReturn"); +// LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeRetContinue"); +// +// LLVMValueRef maybe_val_ptr = LLVMBuildStructGEP(g->builder, value, 1, ""); +// LLVMValueRef is_non_null = LLVMBuildLoad(g->builder, maybe_val_ptr, ""); +// +// LLVMValueRef zero = LLVMConstNull(LLVMInt1Type()); +// LLVMValueRef cond_val = LLVMBuildICmp(g->builder, LLVMIntNE, is_non_null, zero, ""); +// LLVMBuildCondBr(g->builder, cond_val, continue_block, return_block); +// +// LLVMPositionBuilderAtEnd(g->builder, return_block); +// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; +// assert(return_type->id == TypeTableEntryIdMaybe); +// if (handle_is_ptr(return_type)) { +// assert(g->cur_ret_ptr); +// +// LLVMValueRef maybe_bit_ptr = LLVMBuildStructGEP(g->builder, g->cur_ret_ptr, 1, ""); +// LLVMBuildStore(g->builder, zero, maybe_bit_ptr); +// LLVMBuildRetVoid(g->builder); +// } else { +// LLVMValueRef ret_zero_value = LLVMConstNull(return_type->type_ref); +// gen_return(g, node, ret_zero_value, ReturnKnowledgeKnownNull); +// } +// +// LLVMPositionBuilderAtEnd(g->builder, continue_block); +// if (type_has_bits(child_type)) { +// LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, value, 0, ""); +// return get_handle_value(g, val_ptr, child_type); +// } else { +// return nullptr; +// } +// } +// } +// zig_unreachable(); +//} +// +//static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value, +// AstNode *then_node, AstNode *else_node) +//{ +// assert(then_node); +// assert(else_node); +// +// TypeTableEntry *then_type = get_expr_type(then_node); +// TypeTableEntry *else_type = get_expr_type(else_node); +// +// bool use_then_value = type_has_bits(then_type); +// bool use_else_value = type_has_bits(else_type); +// +// LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then"); +// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else"); +// +// LLVMBasicBlockRef endif_block = nullptr; +// bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable; +// bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable; +// if (then_endif_reachable || else_endif_reachable) { +// endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf"); +// } +// +// LLVMBuildCondBr(g->builder, cond_value, then_block, else_block); +// +// LLVMPositionBuilderAtEnd(g->builder, then_block); +// LLVMValueRef then_expr_result = gen_expr(g, then_node); +// if (then_endif_reachable) { +// clear_debug_source_node(g); +// LLVMBuildBr(g->builder, endif_block); +// } +// LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder); +// +// LLVMPositionBuilderAtEnd(g->builder, else_block); +// LLVMValueRef else_expr_result = gen_expr(g, else_node); +// if (else_endif_reachable) { +// clear_debug_source_node(g); +// LLVMBuildBr(g->builder, endif_block); +// } +// LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder); +// +// if (then_endif_reachable || else_endif_reachable) { +// LLVMPositionBuilderAtEnd(g->builder, endif_block); +// if (use_then_value && use_else_value) { +// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), ""); +// LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result}; +// LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block}; +// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); +// return phi; +// } else if (use_then_value) { +// return then_expr_result; +// } else if (use_else_value) { +// return else_expr_result; +// } +// } +// +// return nullptr; +//} +// +//static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeIfBoolExpr); +// assert(node->data.if_bool_expr.condition); +// assert(node->data.if_bool_expr.then_block); +// +// ConstExprValue *const_val = &get_resolved_expr(node->data.if_bool_expr.condition)->const_val; +// if (const_val->ok) { +// if (const_val->data.x_bool) { +// return gen_expr(g, node->data.if_bool_expr.then_block); +// } else if (node->data.if_bool_expr.else_node) { +// return gen_expr(g, node->data.if_bool_expr.else_node); +// } else { +// return nullptr; +// } +// } else { +// LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition); +// +// return gen_if_bool_expr_raw(g, node, cond_value, +// node->data.if_bool_expr.then_block, +// node->data.if_bool_expr.else_node); +// } +//} +// +//static LLVMValueRef gen_if_var_then_block(CodeGen *g, AstNode *node, VariableTableEntry *variable, bool maybe_is_ptr, +// LLVMValueRef init_val, TypeTableEntry *child_type, AstNode *then_node) +//{ +// if (node->data.if_var_expr.var_is_ptr) { +// LLVMValueRef payload_ptr; +// if (maybe_is_ptr) { +// zig_panic("TODO"); +// } else { +// payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, ""); +// } +// LLVMBuildStore(g->builder, payload_ptr, variable->value_ref); +// } else { +// LLVMValueRef payload_val; +// if (maybe_is_ptr) { +// payload_val = init_val; +// } else { +// LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, init_val, 0, ""); +// payload_val = get_handle_value(g, payload_ptr, child_type); +// } +// gen_assign_raw(g, node, BinOpTypeAssign, variable->value_ref, payload_val, +// variable->type, child_type); +// } +// gen_var_debug_decl(g, variable); +// +// return gen_expr(g, then_node); +//} +// +//static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeIfVarExpr); +// assert(node->data.if_var_expr.var_decl.expr); +// +// AstNodeVariableDeclaration *var_decl = &node->data.if_var_expr.var_decl; +// VariableTableEntry *variable = var_decl->variable; +// +// // test if value is the maybe state +// TypeTableEntry *expr_type = get_expr_type(var_decl->expr); +// TypeTableEntry *child_type = expr_type->data.maybe.child_type; +// +// LLVMValueRef init_val = gen_expr(g, var_decl->expr); +// +// +// AstNode *then_node = node->data.if_var_expr.then_block; +// AstNode *else_node = node->data.if_var_expr.else_node; +// bool maybe_is_ptr = child_type->id == TypeTableEntryIdPointer || child_type->id == TypeTableEntryIdFn; +// +// ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val; +// if (const_val->ok) { +// if (const_val->data.x_maybe) { +// return gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node); +// } else { +// return gen_expr(g, else_node); +// } +// } +// +// LLVMValueRef cond_value; +// if (maybe_is_ptr) { +// cond_value = LLVMBuildICmp(g->builder, LLVMIntNE, init_val, LLVMConstNull(child_type->type_ref), ""); +// } else { +// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, ""); +// cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, ""); +// } +// +// TypeTableEntry *then_type = get_expr_type(then_node); +// TypeTableEntry *else_type = get_expr_type(else_node); +// +// bool use_then_value = type_has_bits(then_type); +// bool use_else_value = type_has_bits(else_type); +// +// LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeThen"); +// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeElse"); +// +// LLVMBasicBlockRef endif_block; +// bool then_endif_reachable = then_type->id != TypeTableEntryIdUnreachable; +// bool else_endif_reachable = else_type->id != TypeTableEntryIdUnreachable; +// if (then_endif_reachable || else_endif_reachable) { +// endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "MaybeEndIf"); +// } +// +// LLVMBuildCondBr(g->builder, cond_value, then_block, else_block); +// +// LLVMPositionBuilderAtEnd(g->builder, then_block); +// LLVMValueRef then_expr_result = gen_if_var_then_block(g, node, variable, maybe_is_ptr, init_val, child_type, then_node); +// +// if (then_endif_reachable) { +// LLVMBuildBr(g->builder, endif_block); +// } +// LLVMBasicBlockRef after_then_block = LLVMGetInsertBlock(g->builder); +// +// +// LLVMPositionBuilderAtEnd(g->builder, else_block); +// LLVMValueRef else_expr_result = gen_expr(g, else_node); +// if (else_endif_reachable) { +// LLVMBuildBr(g->builder, endif_block); +// } +// LLVMBasicBlockRef after_else_block = LLVMGetInsertBlock(g->builder); +// +// if (then_endif_reachable || else_endif_reachable) { +// LLVMPositionBuilderAtEnd(g->builder, endif_block); +// if (use_then_value && use_else_value) { +// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(then_expr_result), ""); +// LLVMValueRef incoming_values[2] = {then_expr_result, else_expr_result}; +// LLVMBasicBlockRef incoming_blocks[2] = {after_then_block, after_else_block}; +// LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2); +// return phi; +// } else if (use_then_value) { +// return then_expr_result; +// } else if (use_else_value) { +// return else_expr_result; +// } +// } +// +// return nullptr; +//} +// +//static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { +// assert(block_node->type == NodeTypeBlock); +// +// LLVMValueRef return_value = nullptr; +// for (size_t i = 0; i < block_node->data.block.statements.length; i += 1) { +// AstNode *statement_node = block_node->data.block.statements.at(i); +// return_value = gen_expr(g, statement_node); +// } +// +// bool end_unreachable = implicit_return_type && implicit_return_type->id == TypeTableEntryIdUnreachable; +// if (end_unreachable) { +// return nullptr; +// } +// +// gen_defers_for_block(g, block_node->data.block.nested_block, block_node->data.block.child_block, +// false, false); +// +// if (implicit_return_type) { +// return gen_return(g, block_node, return_value, ReturnKnowledgeSkipDefers); +// } else { +// return return_value; +// } +//} +// +//static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeAsmExpr); +// +// AstNodeAsmExpr *asm_expr = &node->data.asm_expr; +// +// Buf *src_template = asm_expr->asm_template; +// +// Buf llvm_template = BUF_INIT; +// buf_resize(&llvm_template, 0); +// +// for (size_t token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) { +// AsmToken *asm_token = &asm_expr->token_list.at(token_i); +// switch (asm_token->id) { +// case AsmTokenIdTemplate: +// for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) { +// uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset)); +// if (c == '$') { +// buf_append_str(&llvm_template, "$$"); +// } else { +// buf_append_char(&llvm_template, c); +// } +// } +// break; +// case AsmTokenIdPercent: +// buf_append_char(&llvm_template, '%'); +// break; +// case AsmTokenIdVar: +// size_t index = find_asm_index(g, node, asm_token); +// assert(index < SIZE_MAX); +// buf_appendf(&llvm_template, "$%zu", index); +// break; +// } +// } +// +// Buf constraint_buf = BUF_INIT; +// buf_resize(&constraint_buf, 0); +// +// assert(asm_expr->return_count == 0 || asm_expr->return_count == 1); +// +// size_t total_constraint_count = asm_expr->output_list.length + +// asm_expr->input_list.length + +// asm_expr->clobber_list.length; +// size_t input_and_output_count = asm_expr->output_list.length + +// asm_expr->input_list.length - +// asm_expr->return_count; +// size_t total_index = 0; +// size_t param_index = 0; +// LLVMTypeRef *param_types = allocate<LLVMTypeRef>(input_and_output_count); +// LLVMValueRef *param_values = allocate<LLVMValueRef>(input_and_output_count); +// for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) { +// AsmOutput *asm_output = asm_expr->output_list.at(i); +// bool is_return = (asm_output->return_type != nullptr); +// assert(*buf_ptr(asm_output->constraint) == '='); +// if (is_return) { +// buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1); +// } else { +// buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1); +// } +// if (total_index + 1 < total_constraint_count) { +// buf_append_char(&constraint_buf, ','); +// } +// +// if (!is_return) { +// VariableTableEntry *variable = asm_output->variable; +// assert(variable); +// param_types[param_index] = LLVMTypeOf(variable->value_ref); +// param_values[param_index] = variable->value_ref; +// param_index += 1; +// } +// } +// for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) { +// AsmInput *asm_input = asm_expr->input_list.at(i); +// buf_append_buf(&constraint_buf, asm_input->constraint); +// if (total_index + 1 < total_constraint_count) { +// buf_append_char(&constraint_buf, ','); +// } +// +// TypeTableEntry *expr_type = get_expr_type(asm_input->expr); +// param_types[param_index] = expr_type->type_ref; +// param_values[param_index] = gen_expr(g, asm_input->expr); +// } +// for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) { +// Buf *clobber_buf = asm_expr->clobber_list.at(i); +// buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf)); +// if (total_index + 1 < total_constraint_count) { +// buf_append_char(&constraint_buf, ','); +// } +// } +// +// LLVMTypeRef ret_type; +// if (asm_expr->return_count == 0) { +// ret_type = LLVMVoidType(); +// } else { +// ret_type = get_expr_type(node)->type_ref; +// } +// LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false); +// +// bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0); +// LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), +// buf_ptr(&constraint_buf), is_volatile, false); +// +// set_debug_source_node(g, node); +// return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, ""); +//} +// +//static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeContainerInitExpr); +// +// TypeTableEntry *type_entry = get_expr_type(node); +// +// +// if (node->data.container_init_expr.enum_type) { +// size_t param_count = node->data.container_init_expr.entries.length; +// AstNode *arg1_node; +// if (param_count == 1) { +// arg1_node = node->data.container_init_expr.entries.at(0); +// } else { +// assert(param_count == 0); +// arg1_node = nullptr; +// } +// return gen_enum_value_expr(g, node->data.container_init_expr.type, +// node->data.container_init_expr.enum_type, arg1_node); +// } +// +// +// if (type_entry->id == TypeTableEntryIdStruct) { +// assert(node->data.container_init_expr.kind == ContainerInitKindStruct); +// +// size_t src_field_count = type_entry->data.structure.src_field_count; +// assert(src_field_count == node->data.container_init_expr.entries.length); +// +// StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr; +// LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr; +// +// for (size_t i = 0; i < src_field_count; i += 1) { +// AstNode *field_node = node->data.container_init_expr.entries.at(i); +// assert(field_node->type == NodeTypeStructValueField); +// TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field; +// if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) { +// continue; +// } +// assert(buf_eql_buf(type_struct_field->name, field_node->data.struct_val_field.name)); +// +// set_debug_source_node(g, field_node); +// LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, ""); +// AstNode *expr_node = field_node->data.struct_val_field.expr; +// LLVMValueRef value = gen_expr(g, expr_node); +// gen_assign_raw(g, field_node, BinOpTypeAssign, field_ptr, value, +// type_struct_field->type_entry, get_expr_type(expr_node)); +// } +// +// return tmp_struct_ptr; +// } else if (type_entry->id == TypeTableEntryIdVoid) { +// assert(node->data.container_init_expr.entries.length == 0); +// return nullptr; +// } else if (type_entry->id == TypeTableEntryIdArray) { +// StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr; +// LLVMValueRef tmp_array_ptr = struct_val_expr_node->ptr; +// +// size_t field_count = type_entry->data.array.len; +// assert(field_count == node->data.container_init_expr.entries.length); +// +// TypeTableEntry *child_type = type_entry->data.array.child_type; +// +// for (size_t i = 0; i < field_count; i += 1) { +// AstNode *field_node = node->data.container_init_expr.entries.at(i); +// LLVMValueRef elem_val = gen_expr(g, field_node); +// +// LLVMValueRef indices[] = { +// LLVMConstNull(g->builtin_types.entry_usize->type_ref), +// LLVMConstInt(g->builtin_types.entry_usize->type_ref, i, false), +// }; +// set_debug_source_node(g, field_node); +// LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, ""); +// gen_assign_raw(g, field_node, BinOpTypeAssign, elem_ptr, elem_val, +// child_type, get_expr_type(field_node)); +// } +// +// return tmp_array_ptr; +// } else { +// zig_unreachable(); +// } +//} +// +//static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeWhileExpr); +// assert(node->data.while_expr.condition); +// assert(node->data.while_expr.body); +// +// //AstNode *continue_expr_node = node->data.while_expr.continue_expr; +// +// bool condition_always_true = node->data.while_expr.condition_always_true; +// //bool contains_break = node->data.while_expr.contains_break; +// if (condition_always_true) { +// // generate a forever loop +// zig_panic("TODO IR"); +// +// //LLVMBasicBlockRef body_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileBody"); +// //LLVMBasicBlockRef continue_block = continue_expr_node ? +// // LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileContinue") : body_block; +// //LLVMBasicBlockRef end_block = nullptr; +// //if (contains_break) { +// // end_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "WhileEnd"); +// //} +// +// //set_debug_source_node(g, node); +// //LLVMBuildBr(g->builder, body_block); +// +// //if (continue_expr_node) { +// // LLVMPositionBuilderAtEnd(g->builder, continue_block); +// +// // gen_expr(g, continue_expr_node); +// +// // set_debug_source_node(g, node); +// // LLVMBuildBr(g->builder, body_block); +// //} +// +// //LLVMPositionBuilderAtEnd(g->builder, body_block); +// //g->break_block_stack.append(end_block); +// //g->continue_block_stack.append(continue_block); +// //gen_expr(g, node->data.while_expr.body); +// //g->break_block_stack.pop(); +// //g->continue_block_stack.pop(); +// +// //if (get_expr_type(node->data.while_expr.body)->id != TypeTableEntryIdUnreachable) { +// // set_debug_source_node(g, node); +// // LLVMBuildBr(g->builder, continue_block); +// //} +// +// //if (contains_break) { +// // LLVMPositionBuilderAtEnd(g->builder, end_block); +// //} +// } else { +// zig_panic("moved to ir.cpp"); +// } +// +// return nullptr; +//} + +//static LLVMValueRef gen_break(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeBreak); +// LLVMBasicBlockRef dest_block = g->break_block_stack.last(); +// +// set_debug_source_node(g, node); +// return LLVMBuildBr(g->builder, dest_block); +//} + +//static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeContinue); +// LLVMBasicBlockRef dest_block = g->continue_block_stack.last(); +// +// set_debug_source_node(g, node); +// return LLVMBuildBr(g->builder, dest_block); +//} +// +//static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, +// bool unwrap_maybe, LLVMValueRef *init_value, TypeTableEntry **expr_type, bool var_is_ptr) +//{ +// VariableTableEntry *variable = var_decl->variable; +// +// assert(variable); +// +// if (var_decl->expr) { +// *init_value = gen_expr(g, var_decl->expr); +// *expr_type = get_expr_type(var_decl->expr); +// } +// if (!type_has_bits(variable->type)) { +// return nullptr; +// } +// +// bool have_init_expr = false; +// bool want_zeroes = false; +// if (var_decl->expr) { +// ConstExprValue *const_val = &get_resolved_expr(var_decl->expr)->const_val; +// if (!const_val->ok || const_val->special == ConstValSpecialOther) { +// have_init_expr = true; +// } +// if (const_val->ok && const_val->special == ConstValSpecialZeroes) { +// want_zeroes = true; +// } +// } +// if (have_init_expr) { +// TypeTableEntry *expr_type = get_expr_type(var_decl->expr); +// LLVMValueRef value; +// if (unwrap_maybe) { +// assert(var_decl->expr); +// assert(expr_type->id == TypeTableEntryIdMaybe); +// value = gen_unwrap_maybe(g, var_decl->expr, *init_value); +// expr_type = expr_type->data.maybe.child_type; +// } else { +// value = *init_value; +// } +// gen_assign_raw(g, var_decl->expr, BinOpTypeAssign, variable->value_ref, +// value, variable->type, expr_type); +// } else { +// bool ignore_uninit = false; +// // handle runtime stack allocation +// if (var_decl->type) { +// TypeTableEntry *var_type = get_type_for_type_node(var_decl->type); +// if (var_type->id == TypeTableEntryIdStruct && +// var_type->data.structure.is_slice) +// { +// assert(var_decl->type->type == NodeTypeArrayType); +// AstNode *size_node = var_decl->type->data.array_type.size; +// if (size_node) { +// ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val; +// if (!const_val->ok) { +// TypeTableEntry *ptr_type = var_type->data.structure.fields[0].type_entry; +// assert(ptr_type->id == TypeTableEntryIdPointer); +// TypeTableEntry *child_type = ptr_type->data.pointer.child_type; +// +// LLVMValueRef size_val = gen_expr(g, size_node); +// +// set_debug_source_node(g, source_node); +// LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref, +// size_val, ""); +// +// size_t ptr_index = var_type->data.structure.fields[0].gen_index; +// assert(ptr_index != SIZE_MAX); +// size_t len_index = var_type->data.structure.fields[1].gen_index; +// assert(len_index != SIZE_MAX); +// +// // store the freshly allocated pointer in the unknown size array struct +// LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, +// variable->value_ref, ptr_index, ""); +// LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr); +// +// // store the size in the len field +// LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, +// variable->value_ref, len_index, ""); +// LLVMBuildStore(g->builder, size_val, len_field_ptr); +// +// // don't clobber what we just did with debug initialization +// ignore_uninit = true; +// } +// } +// } +// } +// bool want_safe = want_debug_safety(g, source_node); +// if (!ignore_uninit && (want_safe || want_zeroes)) { +// TypeTableEntry *usize = g->builtin_types.entry_usize; +// uint64_t size_bytes = LLVMStoreSizeOfType(g->target_data_ref, variable->type->type_ref); +// uint64_t align_bytes = get_memcpy_align(g, variable->type); +// +// // memset uninitialized memory to 0xa +// set_debug_source_node(g, source_node); +// LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0); +// LLVMValueRef fill_char = LLVMConstInt(LLVMInt8Type(), want_zeroes ? 0x00 : 0xaa, false); +// LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, variable->value_ref, ptr_u8, ""); +// LLVMValueRef byte_count = LLVMConstInt(usize->type_ref, size_bytes, false); +// LLVMValueRef align_in_bytes = LLVMConstInt(LLVMInt32Type(), align_bytes, false); +// LLVMValueRef params[] = { +// dest_ptr, +// fill_char, +// byte_count, +// align_in_bytes, +// LLVMConstNull(LLVMInt1Type()), // is volatile +// }; +// +// LLVMBuildCall(g->builder, g->memset_fn_val, params, 5, ""); +// } +// } +// +// gen_var_debug_decl(g, variable); +// return nullptr; +//} +// +//static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeSwitchExpr); +// +// if (node->data.switch_expr.const_chosen_prong_index != SIZE_MAX) { +// AstNode *prong_node = node->data.switch_expr.prongs.at(node->data.switch_expr.const_chosen_prong_index); +// assert(prong_node->type == NodeTypeSwitchProng); +// AstNode *prong_expr = prong_node->data.switch_prong.expr; +// return gen_expr(g, prong_expr); +// } +// +// TypeTableEntry *target_type = get_expr_type(node->data.switch_expr.expr); +// LLVMValueRef target_value_handle = gen_expr(g, node->data.switch_expr.expr); +// LLVMValueRef target_value; +// if (handle_is_ptr(target_type)) { +// if (target_type->id == TypeTableEntryIdEnum) { +// set_debug_source_node(g, node); +// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, ""); +// target_value = LLVMBuildLoad(g->builder, tag_field_ptr, ""); +// } else if (target_type->id == TypeTableEntryIdErrorUnion) { +// set_debug_source_node(g, node); +// LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, 0, ""); +// target_value = LLVMBuildLoad(g->builder, tag_field_ptr, ""); +// } else { +// zig_unreachable(); +// } +// } else { +// target_value = target_value_handle; +// } +// +// +// TypeTableEntry *switch_type = get_expr_type(node); +// bool result_has_bits = type_has_bits(switch_type); +// bool end_unreachable = (switch_type->id == TypeTableEntryIdUnreachable); +// +// LLVMBasicBlockRef end_block = end_unreachable ? +// nullptr : LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchEnd"); +// LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchElse"); +// size_t prong_count = node->data.switch_expr.prongs.length; +// +// set_debug_source_node(g, node); +// LLVMValueRef switch_instr = LLVMBuildSwitch(g->builder, target_value, else_block, prong_count); +// +// ZigList<LLVMValueRef> incoming_values = {0}; +// ZigList<LLVMBasicBlockRef> incoming_blocks = {0}; +// +// AstNode *else_prong = nullptr; +// for (size_t prong_i = 0; prong_i < prong_count; prong_i += 1) { +// AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); +// VariableTableEntry *prong_var = prong_node->data.switch_prong.var; +// +// LLVMBasicBlockRef prong_block; +// if (prong_node->data.switch_prong.items.length == 0) { +// assert(!else_prong); +// else_prong = prong_node; +// prong_block = else_block; +// } else { +// prong_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProng"); +// size_t prong_item_count = prong_node->data.switch_prong.items.length; +// bool make_item_blocks = prong_var && prong_item_count > 1; +// +// for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { +// AstNode *item_node = prong_node->data.switch_prong.items.at(item_i); +// +// assert(item_node->type != NodeTypeSwitchRange); +// LLVMValueRef val; +// if (target_type->id == TypeTableEntryIdEnum || +// target_type->id == TypeTableEntryIdErrorUnion) +// { +// assert(item_node->type == NodeTypeSymbol); +// TypeEnumField *enum_field = nullptr; +// uint32_t err_value = 0; +// if (target_type->id == TypeTableEntryIdEnum) { +// enum_field = item_node->data.symbol_expr.enum_field; +// assert(enum_field); +// val = LLVMConstInt(target_type->data.enumeration.tag_type->type_ref, +// enum_field->value, false); +// } else if (target_type->id == TypeTableEntryIdErrorUnion) { +// err_value = item_node->data.symbol_expr.err_value; +// val = LLVMConstInt(g->err_tag_type->type_ref, err_value, false); +// } else { +// zig_unreachable(); +// } +// +// if (prong_var && type_has_bits(prong_var->type)) { +// LLVMBasicBlockRef item_block; +// +// if (make_item_blocks) { +// item_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "SwitchProngItem"); +// LLVMAddCase(switch_instr, val, item_block); +// LLVMPositionBuilderAtEnd(g->builder, item_block); +// } else { +// LLVMAddCase(switch_instr, val, prong_block); +// LLVMPositionBuilderAtEnd(g->builder, prong_block); +// } +// +// AstNode *var_node = prong_node->data.switch_prong.var_symbol; +// set_debug_source_node(g, var_node); +// if (prong_node->data.switch_prong.var_is_target_expr) { +// gen_assign_raw(g, var_node, BinOpTypeAssign, +// prong_var->value_ref, target_value, prong_var->type, target_type); +// } else if (target_type->id == TypeTableEntryIdEnum) { +// assert(enum_field); +// assert(type_has_bits(enum_field->type_entry)); +// LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, target_value_handle, +// 1, ""); +// LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, +// LLVMPointerType(enum_field->type_entry->type_ref, 0), ""); +// LLVMValueRef handle_val = get_handle_value(g, bitcasted_union_field_ptr, +// enum_field->type_entry); +// +// gen_assign_raw(g, var_node, BinOpTypeAssign, +// prong_var->value_ref, handle_val, prong_var->type, enum_field->type_entry); +// } else if (target_type->id == TypeTableEntryIdErrorUnion) { +// if (err_value == 0) { +// // variable is the payload +// LLVMValueRef err_payload_ptr = LLVMBuildStructGEP(g->builder, +// target_value_handle, 1, ""); +// LLVMValueRef handle_val = get_handle_value(g, err_payload_ptr, prong_var->type); +// gen_assign_raw(g, var_node, BinOpTypeAssign, +// prong_var->value_ref, handle_val, prong_var->type, prong_var->type); +// } else { +// // variable is the pure error value +// LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, +// target_value_handle, 0, ""); +// LLVMValueRef handle_val = LLVMBuildLoad(g->builder, err_tag_ptr, ""); +// gen_assign_raw(g, var_node, BinOpTypeAssign, +// prong_var->value_ref, handle_val, prong_var->type, g->err_tag_type); +// } +// } else { +// zig_unreachable(); +// } +// if (make_item_blocks) { +// set_debug_source_node(g, var_node); +// LLVMBuildBr(g->builder, prong_block); +// } +// } else { +// LLVMAddCase(switch_instr, val, prong_block); +// } +// } else { +// assert(get_resolved_expr(item_node)->const_val.ok); +// val = gen_expr(g, item_node); +// LLVMAddCase(switch_instr, val, prong_block); +// } +// } +// } +// +// LLVMPositionBuilderAtEnd(g->builder, prong_block); +// AstNode *prong_expr = prong_node->data.switch_prong.expr; +// LLVMValueRef prong_val = gen_expr(g, prong_expr); +// +// if (get_expr_type(prong_expr)->id != TypeTableEntryIdUnreachable) { +// set_debug_source_node(g, prong_expr); +// LLVMBuildBr(g->builder, end_block); +// incoming_values.append(prong_val); +// incoming_blocks.append(LLVMGetInsertBlock(g->builder)); +// } +// } +// +// if (!else_prong) { +// LLVMPositionBuilderAtEnd(g->builder, else_block); +// set_debug_source_node(g, node); +// if (want_debug_safety(g, node)) { +// gen_debug_safety_crash(g); +// } else { +// LLVMBuildUnreachable(g->builder); +// } +// } +// +// if (end_unreachable) { +// return nullptr; +// } +// +// LLVMPositionBuilderAtEnd(g->builder, end_block); +// +// if (result_has_bits) { +// set_debug_source_node(g, node); +// LLVMValueRef phi = LLVMBuildPhi(g->builder, LLVMTypeOf(incoming_values.at(0)), ""); +// LLVMAddIncoming(phi, incoming_values.items, incoming_blocks.items, incoming_values.length); +// return phi; +// } else { +// return nullptr; +// } +//} +// +//static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { +// assert(node->type == NodeTypeArrayAccessExpr); +// +// LLVMValueRef ptr = gen_array_ptr(g, node); +// TypeTableEntry *child_type; +// TypeTableEntry *array_type = get_expr_type(node->data.array_access_expr.array_ref_expr); +// if (array_type->id == TypeTableEntryIdPointer) { +// child_type = array_type->data.pointer.child_type; +// } else if (array_type->id == TypeTableEntryIdStruct) { +// assert(array_type->data.structure.is_slice); +// TypeTableEntry *child_ptr_type = array_type->data.structure.fields[0].type_entry; +// assert(child_ptr_type->id == TypeTableEntryIdPointer); +// child_type = child_ptr_type->data.pointer.child_type; +// } else if (array_type->id == TypeTableEntryIdArray) { +// child_type = array_type->data.array.child_type; +// } else { +// zig_unreachable(); +// } +// +// if (is_lvalue || !ptr || handle_is_ptr(child_type)) { +// return ptr; +// } else { +// return LLVMBuildLoad(g->builder, ptr, ""); +// } +//} +// +//static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) { +// assert(node->type == NodeTypeFieldAccessExpr); +// +// AstNode *struct_expr = node->data.field_access_expr.struct_expr; +// TypeTableEntry *struct_type = get_expr_type(struct_expr); +// +// if (struct_type->id == TypeTableEntryIdArray) { +// Buf *name = node->data.field_access_expr.field_name; +// assert(buf_eql_str(name, "len")); +// return LLVMConstInt(g->builtin_types.entry_usize->type_ref, +// struct_type->data.array.len, false); +// } else if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && +// struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) +// { +// TypeTableEntry *type_entry; +// LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry); +// if (is_lvalue || handle_is_ptr(type_entry)) { +// return ptr; +// } else { +// return LLVMBuildLoad(g->builder, ptr, ""); +// } +// } else if (struct_type->id == TypeTableEntryIdMetaType) { +// assert(!is_lvalue); +// TypeTableEntry *child_type = get_type_for_type_node(struct_expr); +// if (child_type->id == TypeTableEntryIdEnum) { +// return gen_enum_value_expr(g, node, child_type, nullptr); +// } else { +// zig_unreachable(); +// } +// } else if (struct_type->id == TypeTableEntryIdNamespace) { +// VariableTableEntry *variable = get_resolved_expr(node)->variable; +// assert(variable); +// return gen_variable(g, node, variable); +// } else { +// zig_unreachable(); +// } +//} +// +//static LLVMValueRef gen_return(CodeGen *g, AstNode *source_node, LLVMValueRef value, ReturnKnowledge rk) { +// BlockContext *defer_inner_block = source_node->block_context; +// BlockContext *defer_outer_block = source_node->block_context->fn_entry->fn_def_node->block_context; +// if (rk == ReturnKnowledgeUnknown) { +// if (get_conditional_defer_count(defer_inner_block, defer_outer_block) > 0) { +// // generate branching code that checks the return value and generates defers +// // if the return value is error +// zig_panic("TODO"); +// } +// } else if (rk != ReturnKnowledgeSkipDefers) { +// gen_defers_for_block(g, defer_inner_block, defer_outer_block, +// rk == ReturnKnowledgeKnownError, rk == ReturnKnowledgeKnownNull); +// } +// +// TypeTableEntry *return_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; +// bool is_extern = g->cur_fn->type_entry->data.fn.fn_type_id.is_extern; +// if (handle_is_ptr(return_type)) { +// if (is_extern) { +// LLVMValueRef by_val_value = LLVMBuildLoad(g->builder, value, ""); +// LLVMBuildRet(g->builder, by_val_value); +// } else { +// assert(g->cur_ret_ptr); +// gen_assign_raw(g, source_node, BinOpTypeAssign, g->cur_ret_ptr, value, return_type, return_type); +// LLVMBuildRetVoid(g->builder); +// } +// } else { +// LLVMBuildRet(g->builder, value); +// } +// return nullptr; +//} +// +//static LLVMValueRef gen_goto(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeGoto); +// +// // generate defers for blocks that we exit +// LabelTableEntry *label = node->data.goto_expr.label_entry; +// BlockContext *this_context = node->block_context; +// BlockContext *target_context = label->decl_node->block_context; +// gen_defers_for_block(g, this_context, target_context, false, false); +// +// set_debug_source_node(g, node); +// LLVMBuildBr(g->builder, node->data.goto_expr.label_entry->basic_block); +// return nullptr; +//} +// +//static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) { +// AstNode *init_expr = node->data.variable_declaration.expr; +// if (node->data.variable_declaration.is_const && init_expr) { +// TypeTableEntry *init_expr_type = get_expr_type(init_expr); +// if (init_expr_type->id == TypeTableEntryIdNumLitFloat || +// init_expr_type->id == TypeTableEntryIdNumLitInt) +// { +// return nullptr; +// } +// } +// +// LLVMValueRef init_val = nullptr; +// TypeTableEntry *init_val_type; +// return gen_var_decl_raw(g, node, &node->data.variable_declaration, false, &init_val, &init_val_type, false); +//} +// +//static LLVMValueRef get_int_builtin_fn(CodeGen *g, TypeTableEntry *int_type, BuiltinFnId fn_id) { +// // [0-ctz,1-clz][0-8,1-16,2-32,3-64] +// size_t index0 = (fn_id == BuiltinFnIdCtz) ? 0 : 1; +// size_t index1 = bits_index(int_type->data.integral.bit_count); +// LLVMValueRef *fn = &g->int_builtin_fns[index0][index1]; +// if (!*fn) { +// const char *fn_name = (fn_id == BuiltinFnIdCtz) ? "cttz" : "ctlz"; +// Buf *llvm_name = buf_sprintf("llvm.%s.i%zu", fn_name, int_type->data.integral.bit_count); +// LLVMTypeRef param_types[] = { +// int_type->type_ref, +// LLVMInt1Type(), +// }; +// LLVMTypeRef fn_type = LLVMFunctionType(int_type->type_ref, param_types, 2, false); +// *fn = LLVMAddFunction(g->module, buf_ptr(llvm_name), fn_type); +// } +// return *fn; +//} +// +//static LLVMValueRef gen_fence(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeFnCallExpr); +// +// AstNode *atomic_order_arg = node->data.fn_call_expr.params.at(0); +// ConstExprValue *atomic_order_val = &get_resolved_expr(atomic_order_arg)->const_val; +// +// assert(atomic_order_val->ok); +// +// LLVMAtomicOrdering atomic_order = to_LLVMAtomicOrdering((AtomicOrder)atomic_order_val->data.x_enum.tag); +// +// LLVMBuildFence(g->builder, atomic_order, false, ""); +// return nullptr; +//} +// +//static LLVMAtomicOrdering to_LLVMAtomicOrdering(AtomicOrder atomic_order) { +// switch (atomic_order) { +// case AtomicOrderUnordered: return LLVMAtomicOrderingUnordered; +// case AtomicOrderMonotonic: return LLVMAtomicOrderingMonotonic; +// case AtomicOrderAcquire: return LLVMAtomicOrderingAcquire; +// case AtomicOrderRelease: return LLVMAtomicOrderingRelease; +// case AtomicOrderAcqRel: return LLVMAtomicOrderingAcquireRelease; +// case AtomicOrderSeqCst: return LLVMAtomicOrderingSequentiallyConsistent; +// } +// zig_unreachable(); +//} +// +//static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref) { +// TypeTableEntry *type_entry = get_expr_type(node); +// assert(type_entry->id == TypeTableEntryIdMaybe); +// TypeTableEntry *child_type = type_entry->data.maybe.child_type; +// if (child_type->id == TypeTableEntryIdPointer || +// child_type->id == TypeTableEntryIdFn) +// { +// return maybe_struct_ref; +// } else { +// LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, maybe_struct_ref, 0, ""); +// return get_handle_value(g, maybe_field_ptr, child_type); +// } +//} +// +//static size_t get_conditional_defer_count(BlockContext *inner_block, BlockContext *outer_block) { +// size_t result = 0; +// while (inner_block != outer_block) { +// if (inner_block->node->type == NodeTypeDefer && +// (inner_block->node->data.defer.kind == ReturnKindError || +// inner_block->node->data.defer.kind == ReturnKindMaybe)) +// { +// result += 1; +// } +// inner_block = inner_block->parent; +// } +// return result; +//} +// +//static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { +// const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; +// size_t len = tok->end - tok->start - 2; +// size_t result = 0; +// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { +// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); +// if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { +// return result; +// } +// } +// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { +// AsmInput *asm_input = node->data.asm_expr.input_list.at(i); +// if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { +// return result; +// } +// } +// return SIZE_MAX; +//} +// +//static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeSymbol); +// VariableTableEntry *variable = get_resolved_expr(node)->variable; +// if (variable) { +// return gen_variable(g, node, variable); +// } +// +// zig_unreachable(); +//} +// +//static LLVMValueRef gen_label(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeLabel); +// +// LabelTableEntry *label = node->data.label.label_entry; +// assert(label); +// +// LLVMBasicBlockRef basic_block = label->basic_block; +// if (label->entered_from_fallthrough) { +// set_debug_source_node(g, node); +// LLVMBuildBr(g->builder, basic_block); +// } +// LLVMPositionBuilderAtEnd(g->builder, basic_block); +// return nullptr; +//} +// +//static LLVMValueRef gen_variable(CodeGen *g, AstNode *source_node, VariableTableEntry *variable) { +// if (!type_has_bits(variable->type)) { +// return nullptr; +// } else { +// assert(variable->value_ref); +// return get_handle_value(g, variable->value_ref, variable->type); +// } +//} +// |
