diff options
| author | Andrew Kelley <superjoe30@gmail.com> | 2016-11-09 23:21:02 -0500 |
|---|---|---|
| committer | Andrew Kelley <superjoe30@gmail.com> | 2016-11-09 23:21:02 -0500 |
| commit | 9d19b8d66e5eb26ec739ce74b0635270cebf6343 (patch) | |
| tree | ee856044ffbc4adc199f94a0cceda4b5894d5051 /src/codegen.cpp | |
| parent | b8379b4c5b702badf15f668ad30369f4370e4490 (diff) | |
| download | zig-9d19b8d66e5eb26ec739ce74b0635270cebf6343.tar.gz zig-9d19b8d66e5eb26ec739ce74b0635270cebf6343.zip | |
IR: move unused codegen code to commented out in bottom of ir.cpp
Diffstat (limited to 'src/codegen.cpp')
| -rw-r--r-- | src/codegen.cpp | 2157 |
1 files changed, 0 insertions, 2157 deletions
diff --git a/src/codegen.cpp b/src/codegen.cpp index 9f30a37e0c..5fcaac8287 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -22,7 +22,6 @@ #include <stdio.h> #include <errno.h> - static void init_darwin_native(CodeGen *g) { char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET"); char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET"); @@ -227,27 +226,8 @@ void codegen_set_rdynamic(CodeGen *g, bool rdynamic) { g->linker_rdynamic = rdynamic; } -static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); -static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry); -static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue); -static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl, - bool unwrap_maybe, LLVMValueRef *init_val, TypeTableEntry **init_val_type, bool var_is_ptr); -static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, - LLVMValueRef target_ref, LLVMValueRef value, - TypeTableEntry *op1_type, TypeTableEntry *op2_type); -static LLVMValueRef gen_unwrap_maybe(CodeGen *g, AstNode *node, LLVMValueRef maybe_struct_ref); -static LLVMValueRef gen_div(CodeGen *g, AstNode *source_node, LLVMValueRef val1, LLVMValueRef val2, - TypeTableEntry *type_entry, bool exact); static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val); -static TypeTableEntry *get_type_for_type_node(AstNode *node) { - Expr *expr = get_resolved_expr(node); - assert(expr->type_entry->id == TypeTableEntryIdMetaType); - ConstExprValue *const_val = &expr->const_val; - assert(const_val->ok); - return const_val->data.x_type; -} - static void set_debug_source_node(CodeGen *g, AstNode *node) { assert(node->block_context); ZigLLVMSetCurrentDebugLocation(g->builder, node->line + 1, node->column + 1, node->block_context->di_scope); @@ -257,10 +237,6 @@ static void clear_debug_source_node(CodeGen *g) { ZigLLVMClearCurrentDebugLocation(g->builder); } -static TypeTableEntry *get_expr_type(AstNode *node) { - return get_resolved_expr(node)->type_entry; -} - enum AddSubMul { AddSubMulAdd = 0, AddSubMulSub = 1, @@ -329,24 +305,6 @@ static LLVMValueRef get_int_overflow_fn(CodeGen *g, TypeTableEntry *type_entry, return *fn; } -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 get_handle_value(CodeGen *g, LLVMValueRef ptr, TypeTableEntry *type) { if (handle_is_ptr(type)) { return ptr; @@ -413,349 +371,6 @@ static void add_bounds_check(CodeGen *g, LLVMValueRef target_val, LLVMPositionBuilderAtEnd(g->builder, ok_block); } -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 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_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_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 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_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeTableEntry *actual_type_non_canon, TypeTableEntry *wanted_type_non_canon, LLVMValueRef expr_val) { @@ -839,111 +454,6 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, AstNode *source_node, TypeT } } -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_elem_ptr(CodeGen *g, AstNode *source_node, LLVMValueRef array_ptr, TypeTableEntry *array_type, LLVMValueRef subscript_value) { @@ -993,286 +503,6 @@ static LLVMValueRef gen_array_elem_ptr(CodeGen *g, AstNode *source_node, LLVMVal } } -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_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_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); - } -} - -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_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_overflow_op(CodeGen *g, TypeTableEntry *type_entry, AddSubMul op, LLVMValueRef val1, LLVMValueRef val2) { @@ -1529,18 +759,6 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node, } zig_unreachable(); } -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 LLVMIntPredicate cmp_op_to_int_predicate(IrBinOp cmp_op, bool is_signed) { switch (cmp_op) { case IrBinOpCmpEq: @@ -1579,63 +797,6 @@ static LLVMRealPredicate cmp_op_to_real_predicate(IrBinOp cmp_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_struct_memcpy(CodeGen *g, LLVMValueRef src, LLVMValueRef dest, TypeTableEntry *type_entry) { @@ -1688,471 +849,6 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b return nullptr; } -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(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 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_bin_op_expr(CodeGen *g, AstNode *node) { - switch (node->data.bin_op_expr.bin_op) { - case BinOpTypeInvalid: - case BinOpTypeArrayCat: - case BinOpTypeArrayMult: - zig_unreachable(); - case BinOpTypeAssign: - case BinOpTypeAssignTimes: - case BinOpTypeAssignTimesWrap: - case BinOpTypeAssignDiv: - case BinOpTypeAssignMod: - case BinOpTypeAssignPlus: - case BinOpTypeAssignPlusWrap: - case BinOpTypeAssignMinus: - case BinOpTypeAssignMinusWrap: - case BinOpTypeAssignBitShiftLeft: - case BinOpTypeAssignBitShiftLeftWrap: - case BinOpTypeAssignBitShiftRight: - case BinOpTypeAssignBitAnd: - case BinOpTypeAssignBitXor: - case BinOpTypeAssignBitOr: - case BinOpTypeAssignBoolAnd: - case BinOpTypeAssignBoolOr: - return gen_assign_expr(g, node); - case BinOpTypeBoolOr: - return gen_bool_or_expr(g, node); - case BinOpTypeBoolAnd: - return gen_bool_and_expr(g, node); - case BinOpTypeCmpEq: - case BinOpTypeCmpNotEq: - case BinOpTypeCmpLessThan: - case BinOpTypeCmpGreaterThan: - case BinOpTypeCmpLessOrEq: - case BinOpTypeCmpGreaterOrEq: - zig_panic("moved to ir_render"); - case BinOpTypeUnwrapMaybe: - return gen_unwrap_maybe_expr(g, node); - case BinOpTypeBinOr: - case BinOpTypeBinXor: - case BinOpTypeBinAnd: - case BinOpTypeBitShiftLeft: - case BinOpTypeBitShiftLeftWrap: - case BinOpTypeBitShiftRight: - case BinOpTypeAdd: - case BinOpTypeAddWrap: - case BinOpTypeSub: - case BinOpTypeSubWrap: - case BinOpTypeMult: - case BinOpTypeMultWrap: - case BinOpTypeDiv: - case BinOpTypeMod: - return gen_arithmetic_bin_op_expr(g, node); - } - zig_unreachable(); -} - -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 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 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_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 void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) { BlockContext *block_context = var->block_context; AstNode *source_node = var->decl_node; @@ -2162,120 +858,6 @@ static void gen_var_debug_decl(CodeGen *g, VariableTableEntry *var) { LLVMGetInsertBlock(g->builder)); } -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 ir_llvm_value(CodeGen *g, IrInstruction *instruction) { if (!type_has_bits(instruction->type_entry)) return nullptr; @@ -3025,745 +1607,6 @@ static void ir_render(CodeGen *g, FnTableEntry *fn_entry) { } } -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 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_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_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 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_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_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_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_expr(CodeGen *g, AstNode *node) { - Expr *expr = get_resolved_expr(node); - if (expr->const_val.ok) { - if (!type_has_bits(expr->type_entry)) { - return nullptr; - } else { - assert(expr->const_llvm_val); - return expr->const_llvm_val; - } - } - switch (node->type) { - case NodeTypeBinOpExpr: - return gen_bin_op_expr(g, node); - case NodeTypeUnwrapErrorExpr: - return gen_unwrap_err_expr(g, node); - case NodeTypeReturnExpr: - return gen_return_expr(g, node); - case NodeTypeDefer: - // nothing to do - return nullptr; - case NodeTypeVariableDeclaration: - return gen_var_decl_expr(g, node); - case NodeTypePrefixOpExpr: - zig_panic("moved to ir render"); - case NodeTypeFnCallExpr: - return gen_fn_call_expr(g, node); - case NodeTypeArrayAccessExpr: - return gen_array_access_expr(g, node, false); - case NodeTypeSliceExpr: - return gen_slice_expr(g, node); - case NodeTypeFieldAccessExpr: - return gen_field_access_expr(g, node, false); - case NodeTypeIfBoolExpr: - return gen_if_bool_expr(g, node); - case NodeTypeIfVarExpr: - return gen_if_var_expr(g, node); - case NodeTypeWhileExpr: - return gen_while_expr(g, node); - case NodeTypeForExpr: - zig_panic("moved to ir render"); - case NodeTypeAsmExpr: - return gen_asm_expr(g, node); - case NodeTypeSymbol: - return gen_symbol(g, node); - case NodeTypeBlock: - return gen_block(g, node, nullptr); - case NodeTypeGoto: - return gen_goto(g, node); - case NodeTypeBreak: - zig_panic("TODO IR"); - case NodeTypeContinue: - zig_panic("TODO IR"); - case NodeTypeLabel: - return gen_label(g, node); - case NodeTypeContainerInitExpr: - return gen_container_init_expr(g, node); - case NodeTypeSwitchExpr: - return gen_switch_expr(g, node); - case NodeTypeNumberLiteral: - case NodeTypeBoolLiteral: - case NodeTypeStringLiteral: - case NodeTypeCharLiteral: - case NodeTypeNullLiteral: - case NodeTypeUndefinedLiteral: - case NodeTypeZeroesLiteral: - case NodeTypeThisLiteral: - case NodeTypeErrorType: - case NodeTypeTypeLiteral: - case NodeTypeArrayType: - case NodeTypeVarLiteral: - // caught by constant expression eval codegen - zig_unreachable(); - case NodeTypeRoot: - case NodeTypeFnProto: - case NodeTypeFnDef: - case NodeTypeFnDecl: - case NodeTypeParamDecl: - case NodeTypeUse: - case NodeTypeContainerDecl: - case NodeTypeStructField: - case NodeTypeStructValueField: - case NodeTypeSwitchProng: - case NodeTypeSwitchRange: - case NodeTypeErrorValueDecl: - case NodeTypeTypeDecl: - zig_unreachable(); - } - zig_unreachable(); -} - static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstExprValue *const_val) { assert(const_val->ok); |
