From eb5693d91f7ff92b88c4a0dc3e5499dd0a700b34 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 28 Nov 2016 02:40:01 -0500 Subject: [PATCH] IR: function call porting progress also implemented container init generics is still todo --- src/all_types.hpp | 78 +- src/analyze.cpp | 111 +-- src/analyze.hpp | 2 +- src/codegen.cpp | 95 +- src/eval.cpp | 1 + src/ir.cpp | 2029 +++++++++++++---------------------------- src/ir_print.cpp | 146 ++- test/self_hosted2.zig | 13 + 8 files changed, 914 insertions(+), 1561 deletions(-) diff --git a/src/all_types.hpp b/src/all_types.hpp index 124eb81ba9..d16366d00a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -41,6 +41,7 @@ struct IrExecutable { bool invalid; ZigList all_labels; ZigList goto_list; + bool is_inline; }; enum OutType { @@ -82,6 +83,11 @@ struct ConstErrValue { ConstExprValue *payload; }; +struct ConstBoundFnValue { + FnTableEntry *fn; + IrInstruction *first_arg; +}; + enum ConstValSpecial { ConstValSpecialRuntime, ConstValSpecialStatic, @@ -100,6 +106,7 @@ struct ConstExprValue { BigNum x_bignum; bool x_bool; FnTableEntry *x_fn; + ConstBoundFnValue x_bound_fn; TypeTableEntry *x_type; ConstExprValue *x_maybe; ConstErrValue x_err; @@ -494,6 +501,7 @@ struct AstNodeIfBoolExpr { AstNode *condition; AstNode *then_block; AstNode *else_node; // null, block node, or other if expr node + bool is_inline; // TODO // populated by semantic analyzer }; @@ -503,6 +511,7 @@ struct AstNodeIfVarExpr { AstNode *then_block; AstNode *else_node; // null, block node, or other if expr node bool var_is_ptr; + bool is_inline; // TODO // populated by semantic analyzer TypeTableEntry *type; @@ -941,12 +950,18 @@ struct TypeTableEntryFn { LLVMTypeRef raw_type_ref; LLVMCallConv calling_convention; + + TypeTableEntry *bound_fn_parent; }; struct TypeTableEntryGenericFn { AstNode *decl_node; }; +struct TypeTableEntryBoundFn { + TypeTableEntry *fn_type; +}; + struct TypeTableEntryTypeDecl { TypeTableEntry *child_type; TypeTableEntry *canonical_type; @@ -978,6 +993,7 @@ enum TypeTableEntryId { TypeTableEntryIdNamespace, TypeTableEntryIdBlock, TypeTableEntryIdGenericFn, + TypeTableEntryIdBoundFn, }; struct TypeTableEntry { @@ -988,7 +1004,6 @@ struct TypeTableEntry { ZigLLVMDIType *di_type; bool zero_bits; - bool deep_const; union { TypeTableEntryPointer pointer; @@ -1003,6 +1018,7 @@ struct TypeTableEntry { TypeTableEntryFn fn; TypeTableEntryTypeDecl type_decl; TypeTableEntryGenericFn generic_fn; + TypeTableEntryBoundFn bound_fn; } data; // use these fields to make sure we don't duplicate type table entries for the same type @@ -1043,12 +1059,6 @@ enum FnAnalState { }; -enum WantPure { - WantPureAuto, - WantPureFalse, - WantPureTrue, -}; - enum FnInline { FnInlineAuto, FnInlineAlways, @@ -1067,10 +1077,6 @@ struct FnTableEntry { bool internal_linkage; bool is_extern; bool is_test; - bool is_pure; - WantPure want_pure; - AstNode *want_pure_attr_node; - AstNode *want_pure_return_type; FnInline fn_inline; FnAnalState anal_state; IrExecutable ir_executable; @@ -1085,6 +1091,9 @@ struct FnTableEntry { ZigList variable_list; }; +uint32_t fn_table_entry_hash(FnTableEntry*); +bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b); + enum BuiltinFnId { BuiltinFnIdInvalid, BuiltinFnIdMemcpy, @@ -1122,7 +1131,6 @@ enum BuiltinFnId { BuiltinFnIdUnreachable, BuiltinFnIdSetFnTest, BuiltinFnIdSetFnVisible, - BuiltinFnIdSetFnStaticEval, BuiltinFnIdSetFnNoInline, BuiltinFnIdSetDebugSafety, }; @@ -1385,6 +1393,7 @@ enum IrInstructionId { IrInstructionIdStorePtr, IrInstructionIdFieldPtr, IrInstructionIdStructFieldPtr, + IrInstructionIdEnumFieldPtr, IrInstructionIdElemPtr, IrInstructionIdVarPtr, IrInstructionIdCall, @@ -1393,6 +1402,7 @@ enum IrInstructionId { IrInstructionIdCast, IrInstructionIdContainerInitList, IrInstructionIdContainerInitFields, + IrInstructionIdStructInit, IrInstructionIdUnreachable, IrInstructionIdTypeOf, IrInstructionIdToPtrType, @@ -1578,6 +1588,14 @@ struct IrInstructionStructFieldPtr { bool is_const; }; +struct IrInstructionEnumFieldPtr { + IrInstruction base; + + IrInstruction *enum_ptr; + TypeEnumField *field; + bool is_const; +}; + struct IrInstructionElemPtr { IrInstruction base; @@ -1597,9 +1615,12 @@ struct IrInstructionVarPtr { struct IrInstructionCall { IrInstruction base; - IrInstruction *fn; + IrInstruction *fn_ref; + FnTableEntry *fn_entry; size_t arg_count; IrInstruction **args; + bool is_inline; + LLVMValueRef tmp_ptr; }; struct IrInstructionConst { @@ -1615,11 +1636,12 @@ struct IrInstructionReturn { IrInstruction *value; }; +// TODO get rid of this instruction, replace with instructions for each op code struct IrInstructionCast { IrInstruction base; IrInstruction *value; - IrInstruction *dest_type; + TypeTableEntry *dest_type; CastOp cast_op; LLVMValueRef tmp_ptr; }; @@ -1630,6 +1652,14 @@ struct IrInstructionContainerInitList { IrInstruction *container_type; size_t item_count; IrInstruction **items; + LLVMValueRef tmp_ptr; +}; + +struct IrInstructionContainerInitFieldsField { + Buf *name; + IrInstruction *value; + AstNode *source_node; + TypeStructField *type_struct_field; }; struct IrInstructionContainerInitFields { @@ -1637,8 +1667,21 @@ struct IrInstructionContainerInitFields { IrInstruction *container_type; size_t field_count; - Buf **field_names; - IrInstruction **field_values; + IrInstructionContainerInitFieldsField *fields; +}; + +struct IrInstructionStructInitField { + IrInstruction *value; + TypeStructField *type_struct_field; +}; + +struct IrInstructionStructInit { + IrInstruction base; + + TypeTableEntry *struct_type; + size_t field_count; + IrInstructionStructInitField *fields; + LLVMValueRef tmp_ptr; }; struct IrInstructionUnreachable { @@ -1790,4 +1833,7 @@ static const size_t slice_len_index = 1; static const size_t maybe_child_index = 0; static const size_t maybe_null_index = 1; +static const size_t enum_gen_tag_index = 0; +static const size_t enum_gen_union_index = 1; + #endif diff --git a/src/analyze.cpp b/src/analyze.cpp index 5662529b05..8b46bee9a2 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -84,46 +84,11 @@ AstNode *first_executing_node(AstNode *node) { zig_unreachable(); } -void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node) { - if (!context->fn_entry) return; - if (!context->fn_entry->is_pure) return; - - context->fn_entry->is_pure = false; - if (context->fn_entry->want_pure == WantPureTrue) { - context->fn_entry->proto_node->data.fn_proto.skip = true; - - ErrorMsg *msg = add_node_error(g, context->fn_entry->proto_node, - buf_sprintf("failed to evaluate function at compile time")); - - add_error_note(g, msg, node, - buf_sprintf("unable to evaluate this expression at compile time")); - - if (context->fn_entry->want_pure_attr_node) { - add_error_note(g, msg, context->fn_entry->want_pure_attr_node, - buf_sprintf("required to be compile-time function here")); - } - - if (context->fn_entry->want_pure_return_type) { - add_error_note(g, msg, context->fn_entry->want_pure_return_type, - buf_sprintf("required to be compile-time function because of return type '%s'", - buf_ptr(&context->fn_entry->type_entry->data.fn.fn_type_id.return_type->name))); - } - } -} - ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { // if this assert fails, then parseh generated code that // failed semantic analysis, which isn't supposed to happen assert(!node->owner->c_import_node); - // if an error occurs in a function then it becomes impure - if (node->block_context) { - FnTableEntry *fn_entry = node->block_context->fn_entry; - if (fn_entry) { - fn_entry->is_pure = false; - } - } - ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column, node->owner->source_code, node->owner->line_offsets, msg); @@ -217,6 +182,7 @@ bool type_is_complete(TypeTableEntry *type_entry) { case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: return true; } zig_unreachable(); @@ -241,7 +207,6 @@ TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) { static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdGenericFn); buf_init_from_str(&entry->name, "(generic function)"); - entry->deep_const = true; entry->zero_bits = true; entry->data.generic_fn.decl_node = decl_node; return entry; @@ -255,8 +220,6 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool } else { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPointer); - entry->deep_const = is_const && child_type->deep_const; - const char *const_str = is_const ? "const " : ""; buf_resize(&entry->name, 0); buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name)); @@ -298,8 +261,6 @@ TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { assert(child_type->type_ref); assert(child_type->di_type); - entry->deep_const = child_type->deep_const; - buf_resize(&entry->name, 0); buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name)); @@ -383,8 +344,6 @@ TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { entry->data.error.child_type = child_type; - entry->deep_const = child_type->deep_const; - if (!type_has_bits(child_type)) { entry->type_ref = g->err_tag_type->type_ref; entry->di_type = g->err_tag_type->di_type; @@ -456,7 +415,6 @@ TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdArray); entry->type_ref = child_type->type_ref ? LLVMArrayType(child_type->type_ref, array_size) : nullptr; entry->zero_bits = (array_size == 0) || child_type->zero_bits; - entry->deep_const = child_type->deep_const; buf_resize(&entry->name, 0); buf_appendf(&entry->name, "[%" PRIu64 "]%s", array_size, buf_ptr(&child_type->name)); @@ -507,8 +465,6 @@ TypeTableEntry *get_slice_type(CodeGen *g, TypeTableEntry *child_type, bool is_c TypeTableEntry *var_peer = get_slice_type(g, child_type, false); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdStruct); - entry->deep_const = child_type->deep_const; - buf_resize(&entry->name, 0); buf_appendf(&entry->name, "[]const %s", buf_ptr(&child_type->name)); @@ -657,7 +613,6 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * buf_init_from_str(&entry->name, name); - entry->deep_const = child_type->deep_const; entry->type_ref = child_type->type_ref; entry->di_type = child_type->di_type; entry->zero_bits = child_type->zero_bits; @@ -673,6 +628,23 @@ TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry * return entry; } +TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry) { + TypeTableEntry *fn_type = fn_entry->type_entry; + assert(fn_type->id == TypeTableEntryIdFn); + if (fn_type->data.fn.bound_fn_parent) + return fn_type->data.fn.bound_fn_parent; + + TypeTableEntry *bound_fn_type = new_type_table_entry(TypeTableEntryIdBoundFn); + bound_fn_type->data.bound_fn.fn_type = fn_type; + bound_fn_type->zero_bits = true; + + buf_resize(&bound_fn_type->name, 0); + buf_appendf(&bound_fn_type->name, "(bound %s)", buf_ptr(&fn_type->name)); + + fn_type->data.fn.bound_fn_parent = bound_fn_type; + return bound_fn_type; +} + // accepts ownership of fn_type_id memory TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_info) { auto table_entry = g->fn_type_table.maybe_get(fn_type_id); @@ -681,7 +653,6 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id, bool gen_debug_inf } TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn); - fn_type->deep_const = true; fn_type->data.fn.fn_type_id = *fn_type_id; if (fn_type_id->is_cold) { @@ -838,6 +809,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo TypeTableEntry *expected_type) { IrExecutable ir_executable = {0}; + ir_executable.is_inline = true; ir_gen(g, node, scope, &ir_executable); if (ir_executable.invalid) @@ -851,6 +823,7 @@ static IrInstruction *analyze_const_value(CodeGen *g, BlockContext *scope, AstNo fprintf(stderr, "}\n"); } IrExecutable analyzed_executable = {0}; + analyzed_executable.is_inline = true; analyzed_executable.backward_branch_quota = default_backward_branch_quota; TypeTableEntry *result_type = ir_analyze(g, &ir_executable, &analyzed_executable, expected_type, node); if (result_type->id == TypeTableEntryIdInvalid) @@ -884,8 +857,7 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B static bool fn_wants_full_static_eval(FnTableEntry *fn_table_entry) { assert(fn_table_entry); - AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; - return fn_proto->inline_arg_count == fn_proto->params.length && fn_table_entry->want_pure == WantPureTrue; + return false; } // fn_table_entry is populated if and only if there is a function definition for this prototype @@ -931,6 +903,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: if (!fn_proto->skip) { fn_proto->skip = true; add_node_error(g, child->data.param_decl.type, @@ -991,6 +964,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdVar: if (!fn_proto->skip) { fn_proto->skip = true; @@ -1023,9 +997,6 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor } if (fn_table_entry && fn_type_id.return_type->id == TypeTableEntryIdMetaType) { - fn_table_entry->want_pure = WantPureTrue; - fn_table_entry->want_pure_return_type = fn_proto->return_type; - ErrorMsg *err_msg = nullptr; for (size_t i = 0; i < fn_proto->params.length; i += 1) { AstNode *param_decl_node = fn_proto->params.at(i); @@ -1046,8 +1017,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor } } - - bool gen_debug_info = !(fn_table_entry && fn_wants_full_static_eval(fn_table_entry)); + bool gen_debug_info = fn_table_entry && !fn_wants_full_static_eval(fn_table_entry); return get_fn_type(g, &fn_type_id, gen_debug_info); } @@ -1167,8 +1137,6 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt assert(decl_node->type == NodeTypeContainerDecl); assert(enum_type->di_type); - enum_type->deep_const = true; - uint32_t field_count = decl_node->data.struct_decl.fields.length; enum_type->data.enumeration.src_field_count = field_count; @@ -1198,11 +1166,6 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt type_enum_field->type_entry = field_type; type_enum_field->value = i; - if (!field_type->deep_const) { - enum_type->deep_const = false; - } - - di_enumerators[i] = ZigLLVMCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i); if (field_type->id == TypeTableEntryIdStruct) { @@ -1362,8 +1325,6 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE assert(decl_node->type == NodeTypeContainerDecl); assert(struct_type->di_type); - struct_type->deep_const = true; - size_t field_count = decl_node->data.struct_decl.fields.length; struct_type->data.structure.src_field_count = field_count; @@ -1389,10 +1350,6 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE type_struct_field->src_index = i; type_struct_field->gen_index = SIZE_MAX; - if (!field_type->deep_const) { - struct_type->deep_const = false; - } - if (field_type->id == TypeTableEntryIdStruct) { resolve_struct_type(g, import, field_type); } else if (field_type->id == TypeTableEntryIdEnum) { @@ -1537,7 +1494,6 @@ static void preview_fn_proto_instance(CodeGen *g, ImportTableEntry *import, AstN fn_table_entry->proto_node = proto_node; fn_table_entry->fn_def_node = fn_def_node; fn_table_entry->is_extern = is_extern; - fn_table_entry->is_pure = fn_def_node != nullptr; get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_'); @@ -1852,6 +1808,7 @@ TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEnt case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: return type_entry; } zig_unreachable(); @@ -2100,6 +2057,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) { case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: return false; case TypeTableEntryIdBool: @@ -2314,6 +2272,7 @@ static bool is_container(TypeTableEntry *type_entry) { case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: return false; } zig_unreachable(); @@ -2361,6 +2320,7 @@ void resolve_container_type(CodeGen *g, TypeTableEntry *type_entry) { case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdInvalid: case TypeTableEntryIdVar: zig_unreachable(); @@ -2429,10 +2389,6 @@ static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) { if (fn_type->data.fn.gen_param_info) { var->gen_arg_index = fn_type->data.fn.gen_param_info[i].gen_index; } - - if (!type->deep_const) { - fn_table_entry->is_pure = false; - } } TypeTableEntry *expected_type = fn_type->data.fn.fn_type_id.return_type; @@ -2768,6 +2724,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) { case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdVar: zig_unreachable(); case TypeTableEntryIdUnreachable: @@ -2820,6 +2777,14 @@ static uint32_t hash_size(size_t x) { return x % UINT32_MAX; } +uint32_t fn_table_entry_hash(FnTableEntry* value) { + return ptr_hash(value); +} + +bool fn_table_entry_eql(FnTableEntry *a, FnTableEntry *b) { + return ptr_eq(a, b); +} + uint32_t fn_type_id_hash(FnTypeId *id) { uint32_t result = 0; result += id->is_extern ? 3349388391 : 0; @@ -2912,6 +2877,7 @@ static uint32_t hash_const_val(TypeTableEntry *type, ConstExprValue *const_val) case TypeTableEntryIdBlock: return hash_ptr(const_val->data.x_block); case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdInvalid: case TypeTableEntryIdUnreachable: case TypeTableEntryIdVar: @@ -2990,6 +2956,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry) case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdVar: zig_unreachable(); case TypeTableEntryIdArray: diff --git a/src/analyze.hpp b/src/analyze.hpp index 3ac5108686..fec528904a 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -31,6 +31,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import, ContainerKind kind, AstNode *decl_node, const char *name); TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x); TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type); +TypeTableEntry *get_bound_fn_type(CodeGen *g, FnTableEntry *fn_entry); bool handle_is_ptr(TypeTableEntry *type_entry); void find_libc_include_path(CodeGen *g); void find_libc_lib_path(CodeGen *g); @@ -52,7 +53,6 @@ VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *n AstNode *find_decl(BlockContext *context, Buf *name); void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only); TopLevelDecl *get_as_top_level_decl(AstNode *node); -void mark_impure_fn(CodeGen *g, BlockContext *context, AstNode *node); bool type_is_codegen_pointer(TypeTableEntry *type); TypeTableEntry *validate_var_type(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry); TypeTableEntry *container_ref_type(TypeTableEntry *type_entry); diff --git a/src/codegen.cpp b/src/codegen.cpp index c6e00419e9..28020356d1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1368,27 +1368,34 @@ static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrI } static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) { - LLVMValueRef fn_val = ir_llvm_value(g, instruction->fn); - TypeTableEntry *fn_type = instruction->fn->type_entry; + LLVMValueRef fn_val; + TypeTableEntry *fn_type; + if (instruction->fn_entry) { + fn_val = instruction->fn_entry->fn_value; + fn_type = instruction->fn_entry->type_entry; + } else { + assert(instruction->fn_ref); + fn_val = ir_llvm_value(g, instruction->fn_ref); + fn_type = instruction->fn_ref->type_entry; + } + 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 = instruction->arg_count; bool first_arg_ret = ret_has_bits && handle_is_ptr(src_return_type); - size_t actual_param_count = fn_call_param_count + (first_arg_ret ? 1 : 0); + size_t actual_param_count = instruction->arg_count + (first_arg_ret ? 1 : 0); bool is_var_args = fn_type->data.fn.fn_type_id.is_var_args; LLVMValueRef *gen_param_values = allocate(actual_param_count); size_t gen_param_index = 0; if (first_arg_ret) { - zig_panic("TODO"); - //gen_param_values[gen_param_index] = node->data.fn_call_expr.tmp_ptr; - //gen_param_index += 1; + gen_param_values[gen_param_index] = instruction->tmp_ptr; + gen_param_index += 1; } - for (size_t call_i = 0; call_i < fn_call_param_count; call_i += 1) { + for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { IrInstruction *param_instruction = instruction->args[call_i]; - LLVMValueRef param_value = ir_llvm_value(g, param_instruction); - assert(param_value); TypeTableEntry *param_type = param_instruction->type_entry; if (is_var_args || type_has_bits(param_type)) { + LLVMValueRef param_value = ir_llvm_value(g, param_instruction); + assert(param_value); gen_param_values[gen_param_index] = param_value; gen_param_index += 1; } @@ -1402,8 +1409,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr } else if (!ret_has_bits) { return nullptr; } else if (first_arg_ret) { - zig_panic("TODO"); - //return node->data.fn_call_expr.tmp_ptr; + return instruction->tmp_ptr; } else { return result; } @@ -1422,6 +1428,22 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa return LLVMBuildStructGEP(g->builder, struct_ptr, field->gen_index, ""); } +static LLVMValueRef ir_render_enum_field_ptr(CodeGen *g, IrExecutable *executable, + IrInstructionEnumFieldPtr *instruction) +{ + LLVMValueRef enum_ptr = ir_llvm_value(g, instruction->enum_ptr); + TypeEnumField *field = instruction->field; + + if (!type_has_bits(field->type_entry)) + return nullptr; + + LLVMTypeRef field_type_ref = LLVMPointerType(field->type_entry->type_ref, 0); + LLVMValueRef union_field_ptr = LLVMBuildStructGEP(g->builder, enum_ptr, enum_gen_union_index, ""); + LLVMValueRef bitcasted_union_field_ptr = LLVMBuildBitCast(g->builder, union_field_ptr, field_type_ref, ""); + + return bitcasted_union_field_ptr; +} + 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; @@ -1691,6 +1713,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdSwitchTarget: case IrInstructionIdStaticEval: case IrInstructionIdImport: + case IrInstructionIdContainerInitFields: zig_unreachable(); case IrInstructionIdReturn: return ir_render_return(g, executable, (IrInstructionReturn *)instruction); @@ -1720,6 +1743,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_call(g, executable, (IrInstructionCall *)instruction); case IrInstructionIdStructFieldPtr: return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); + case IrInstructionIdEnumFieldPtr: + return ir_render_enum_field_ptr(g, executable, (IrInstructionEnumFieldPtr *)instruction); case IrInstructionIdAsm: return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); case IrInstructionIdTestNull: @@ -1738,7 +1763,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_ref(g, executable, (IrInstructionRef *)instruction); case IrInstructionIdSwitchVar: case IrInstructionIdContainerInitList: - case IrInstructionIdContainerInitFields: + case IrInstructionIdStructInit: case IrInstructionIdEnumTag: case IrInstructionIdArrayLen: zig_panic("TODO render more IR instructions to LLVM"); @@ -1960,6 +1985,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdVar: zig_unreachable(); @@ -2197,7 +2223,6 @@ static void do_code_gen(CodeGen *g) { TypeTableEntry *fn_type = fn_table_entry->type_entry; - bool is_sret = false; if (!type_has_bits(fn_type->data.fn.fn_type_id.return_type)) { // nothing to do } else if (fn_type->data.fn.fn_type_id.return_type->id == TypeTableEntryIdPointer) { @@ -2208,10 +2233,6 @@ static void do_code_gen(CodeGen *g) { LLVMValueRef first_arg = LLVMGetParam(fn_table_entry->fn_value, 0); LLVMAddAttribute(first_arg, LLVMStructRetAttribute); ZigLLVMAddNonNullAttr(fn_table_entry->fn_value, 1); - is_sret = true; - } - if (fn_table_entry->is_pure && !is_sret && g->is_release_build) { - LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMReadOnlyAttribute); } @@ -2234,9 +2255,7 @@ static void do_code_gen(CodeGen *g) { if (param_is_noalias) { LLVMAddAttribute(argument_val, LLVMNoAliasAttribute); } - if ((param_type->id == TypeTableEntryIdPointer && (param_type->data.pointer.is_const || fn_table_entry->is_pure)) || - is_byval) - { + if ((param_type->id == TypeTableEntryIdPointer && param_type->data.pointer.is_const) || is_byval) { LLVMAddAttribute(argument_val, LLVMReadOnlyAttribute); } if (param_type->id == TypeTableEntryIdPointer) { @@ -2339,6 +2358,15 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdRef) { IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction; slot = &ref_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdContainerInitList) { + IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction; + slot = &container_init_list_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdStructInit) { + IrInstructionStructInit *struct_init_instruction = (IrInstructionStructInit *)instruction; + slot = &struct_init_instruction->tmp_ptr; + } else if (instruction->id == IrInstructionIdCall) { + IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; + slot = &call_instruction->tmp_ptr; } else { zig_unreachable(); } @@ -2464,46 +2492,39 @@ static void define_builtin_types(CodeGen *g) { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNamespace); buf_init_from_str(&entry->name, "(namespace)"); entry->zero_bits = true; - entry->deep_const = true; g->builtin_types.entry_namespace = entry; } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBlock); buf_init_from_str(&entry->name, "(block)"); entry->zero_bits = true; - entry->deep_const = true; g->builtin_types.entry_block = entry; } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat); buf_init_from_str(&entry->name, "(float literal)"); entry->zero_bits = true; - entry->deep_const = true; g->builtin_types.entry_num_lit_float = entry; } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt); buf_init_from_str(&entry->name, "(integer literal)"); entry->zero_bits = true; - entry->deep_const = true; g->builtin_types.entry_num_lit_int = entry; } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUndefLit); buf_init_from_str(&entry->name, "(undefined)"); - entry->deep_const = true; g->builtin_types.entry_undef = entry; } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNullLit); buf_init_from_str(&entry->name, "(null)"); - entry->deep_const = true; g->builtin_types.entry_null = entry; } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVar); buf_init_from_str(&entry->name, "(var)"); - entry->deep_const = true; g->builtin_types.entry_var = entry; } @@ -2514,7 +2535,6 @@ static void define_builtin_types(CodeGen *g) { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); entry->type_ref = LLVMIntType(size_in_bits); - entry->deep_const = true; const char u_or_i = is_signed ? 'i' : 'u'; buf_resize(&entry->name, 0); @@ -2554,7 +2574,6 @@ static void define_builtin_types(CodeGen *g) { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); entry->type_ref = LLVMIntType(size_in_bits); - entry->deep_const = true; buf_init_from_str(&entry->name, info->name); @@ -2574,7 +2593,6 @@ static void define_builtin_types(CodeGen *g) { { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdBool); entry->type_ref = LLVMInt1Type(); - entry->deep_const = true; buf_init_from_str(&entry->name, "bool"); uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref); uint64_t debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, entry->type_ref); @@ -2590,7 +2608,6 @@ static void define_builtin_types(CodeGen *g) { bool is_signed = is_signed_list[sign_i]; TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); - entry->deep_const = true; entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8); const char u_or_i = is_signed ? 'i' : 'u'; @@ -2616,7 +2633,6 @@ static void define_builtin_types(CodeGen *g) { } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); - entry->deep_const = true; entry->type_ref = LLVMFloatType(); buf_init_from_str(&entry->name, "f32"); entry->data.floating.bit_count = 32; @@ -2632,7 +2648,6 @@ static void define_builtin_types(CodeGen *g) { } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); - entry->deep_const = true; entry->type_ref = LLVMDoubleType(); buf_init_from_str(&entry->name, "f64"); entry->data.floating.bit_count = 64; @@ -2648,7 +2663,6 @@ static void define_builtin_types(CodeGen *g) { } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdFloat); - entry->deep_const = true; entry->type_ref = LLVMX86FP80Type(); buf_init_from_str(&entry->name, "c_long_double"); entry->data.floating.bit_count = 80; @@ -2664,7 +2678,6 @@ static void define_builtin_types(CodeGen *g) { } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdVoid); - entry->deep_const = true; entry->type_ref = LLVMVoidType(); entry->zero_bits = true; buf_init_from_str(&entry->name, "void"); @@ -2677,7 +2690,6 @@ static void define_builtin_types(CodeGen *g) { } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdUnreachable); - entry->deep_const = true; entry->type_ref = LLVMVoidType(); entry->zero_bits = true; buf_init_from_str(&entry->name, "unreachable"); @@ -2687,7 +2699,6 @@ static void define_builtin_types(CodeGen *g) { } { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMetaType); - entry->deep_const = true; buf_init_from_str(&entry->name, "type"); entry->zero_bits = true; g->builtin_types.entry_type = entry; @@ -2710,7 +2721,6 @@ static void define_builtin_types(CodeGen *g) { { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError); - entry->deep_const = true; buf_init_from_str(&entry->name, "error"); // TODO allow overriding this type and keep track of max value and emit an @@ -2726,7 +2736,6 @@ static void define_builtin_types(CodeGen *g) { { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); - entry->deep_const = true; entry->zero_bits = true; // only allowed at compile time buf_init_from_str(&entry->name, "@OS"); uint32_t field_count = target_os_count(); @@ -2752,7 +2761,6 @@ static void define_builtin_types(CodeGen *g) { { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); - entry->deep_const = true; entry->zero_bits = true; // only allowed at compile time buf_init_from_str(&entry->name, "@Arch"); uint32_t field_count = target_arch_count(); @@ -2784,7 +2792,6 @@ static void define_builtin_types(CodeGen *g) { { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); - entry->deep_const = true; entry->zero_bits = true; // only allowed at compile time buf_init_from_str(&entry->name, "@Environ"); uint32_t field_count = target_environ_count(); @@ -2811,7 +2818,6 @@ static void define_builtin_types(CodeGen *g) { { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); - entry->deep_const = true; entry->zero_bits = true; // only allowed at compile time buf_init_from_str(&entry->name, "@ObjectFormat"); uint32_t field_count = target_oformat_count(); @@ -2838,7 +2844,6 @@ static void define_builtin_types(CodeGen *g) { { TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum); - entry->deep_const = true; buf_init_from_str(&entry->name, "AtomicOrder"); uint32_t field_count = 6; entry->data.enumeration.src_field_count = field_count; @@ -2998,7 +3003,6 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn_with_arg_count(g, BuiltinFnIdUnreachable, "unreachable", 0); create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnTest, "setFnTest", 2); create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnVisible, "setFnVisible", 2); - create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnStaticEval, "setFnStaticEval", 2); create_builtin_fn_with_arg_count(g, BuiltinFnIdSetFnNoInline, "setFnNoInline", 2); create_builtin_fn_with_arg_count(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); } @@ -3287,6 +3291,7 @@ static void get_c_type(CodeGen *g, TypeTableEntry *type_entry, Buf *out_buf) { case TypeTableEntryIdInvalid: case TypeTableEntryIdMetaType: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdNumLitFloat: diff --git a/src/eval.cpp b/src/eval.cpp index 602401e68d..ee7102e62c 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -56,6 +56,7 @@ bool const_values_equal(ConstExprValue *a, ConstExprValue *b, TypeTableEntry *ty case TypeTableEntryIdBlock: zig_panic("TODO"); case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdInvalid: case TypeTableEntryIdUnreachable: case TypeTableEntryIdVar: diff --git a/src/ir.cpp b/src/ir.cpp index 9362a6c618..f1dadad84c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -49,6 +49,10 @@ ConstExprValue *const_ptr_pointee(ConstExprValue *const_val) { } } +static bool ir_should_inline(IrBuilder *irb) { + return irb->exec->is_inline; +} + static void ir_instruction_append(IrBasicBlock *basic_block, IrInstruction *instruction) { assert(basic_block); assert(instruction); @@ -160,6 +164,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionStructFieldPtr * return IrInstructionIdStructFieldPtr; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionEnumFieldPtr *) { + return IrInstructionIdEnumFieldPtr; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionElemPtr *) { return IrInstructionIdElemPtr; } @@ -276,6 +284,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) { return IrInstructionIdRef; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { + return IrInstructionIdStructInit; +} + template static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { T *special_instruction = allocate(1); @@ -293,15 +305,14 @@ static T *ir_build_instruction(IrBuilder *irb, AstNode *source_node) { return special_instruction; } -static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, IrInstruction *dest_type, - IrInstruction *value, CastOp cast_op) +static IrInstruction *ir_build_cast(IrBuilder *irb, AstNode *source_node, TypeTableEntry *dest_type, + IrInstruction *value, CastOp cast_op) { IrInstructionCast *cast_instruction = ir_build_instruction(irb, source_node); cast_instruction->dest_type = dest_type; cast_instruction->value = value; cast_instruction->cast_op = cast_op; - ir_ref_instruction(dest_type); ir_ref_instruction(value); return &cast_instruction->base; @@ -353,10 +364,14 @@ static IrInstruction *ir_build_return_from(IrBuilder *irb, IrInstruction *old_in return new_instruction; } -static IrInstruction *ir_create_const(IrBuilder *irb, AstNode *source_node, TypeTableEntry *type_entry) { +static IrInstruction *ir_create_const(IrBuilder *irb, AstNode *source_node, + TypeTableEntry *type_entry, bool depends_on_compile_var) +{ + assert(type_entry); IrInstructionConst *const_instruction = ir_create_instruction(irb->exec, source_node); const_instruction->base.type_entry = type_entry; const_instruction->base.static_value.special = ConstValSpecialStatic; + const_instruction->base.static_value.depends_on_compile_var = depends_on_compile_var; return &const_instruction->base; } @@ -452,6 +467,18 @@ static IrInstruction *ir_build_const_bool(IrBuilder *irb, AstNode *source_node, return &const_instruction->base; } +static IrInstruction *ir_build_const_bound_fn(IrBuilder *irb, AstNode *source_node, + FnTableEntry *fn_entry, IrInstruction *first_arg, bool depends_on_compile_var) +{ + IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); + const_instruction->base.type_entry = get_bound_fn_type(irb->codegen, fn_entry); + const_instruction->base.static_value.special = ConstValSpecialStatic; + const_instruction->base.static_value.depends_on_compile_var = depends_on_compile_var; + const_instruction->base.static_value.data.x_bound_fn.fn = fn_entry; + const_instruction->base.static_value.data.x_bound_fn.first_arg = first_arg; + return &const_instruction->base; +} + static IrInstruction *ir_build_const_str_lit(IrBuilder *irb, AstNode *source_node, Buf *str) { IrInstructionConst *const_instruction = ir_build_instruction(irb, source_node); TypeTableEntry *u8_type = irb->codegen->builtin_types.entry_u8; @@ -595,26 +622,48 @@ static IrInstruction *ir_build_struct_field_ptr_from(IrBuilder *irb, IrInstructi return new_instruction; } +static IrInstruction *ir_build_enum_field_ptr(IrBuilder *irb, AstNode *source_node, + IrInstruction *enum_ptr, TypeEnumField *field) +{ + IrInstructionEnumFieldPtr *instruction = ir_build_instruction(irb, source_node); + instruction->enum_ptr = enum_ptr; + instruction->field = field; + + ir_ref_instruction(enum_ptr); + + return &instruction->base; +} + +static IrInstruction *ir_build_enum_field_ptr_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *enum_ptr, TypeEnumField *type_enum_field) +{ + IrInstruction *new_instruction = ir_build_enum_field_ptr(irb, old_instruction->source_node, + enum_ptr, type_enum_field); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static IrInstruction *ir_build_call(IrBuilder *irb, AstNode *source_node, - IrInstruction *fn, size_t arg_count, IrInstruction **args) + FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args) { IrInstructionCall *call_instruction = ir_build_instruction(irb, source_node); - call_instruction->fn = fn; + call_instruction->fn_entry = fn_entry; + call_instruction->fn_ref = fn_ref; call_instruction->arg_count = arg_count; call_instruction->args = args; - ir_ref_instruction(fn); - for (size_t i = 0; i < arg_count; i += 1) { + if (fn_ref) + ir_ref_instruction(fn_ref); + for (size_t i = 0; i < arg_count; i += 1) ir_ref_instruction(args[i]); - } return &call_instruction->base; } static IrInstruction *ir_build_call_from(IrBuilder *irb, IrInstruction *old_instruction, - IrInstruction *fn, size_t arg_count, IrInstruction **args) + FnTableEntry *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args) { - IrInstruction *new_instruction = ir_build_call(irb, old_instruction->source_node, fn, arg_count, args); + IrInstruction *new_instruction = ir_build_call(irb, old_instruction->source_node, fn_entry, fn_ref, arg_count, args); ir_link_new_instruction(new_instruction, old_instruction); return new_instruction; } @@ -706,24 +755,55 @@ static IrInstruction *ir_build_container_init_list(IrBuilder *irb, AstNode *sour return &container_init_list_instruction->base; } +static IrInstruction *ir_build_container_init_list_from(IrBuilder *irb, IrInstruction *old_instruction, + IrInstruction *container_type, size_t item_count, IrInstruction **items) +{ + IrInstruction *new_instruction = ir_build_container_init_list(irb, old_instruction->source_node, + container_type, item_count, items); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, AstNode *source_node, - IrInstruction *container_type, size_t field_count, Buf **field_names, IrInstruction **field_values) + IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields) { IrInstructionContainerInitFields *container_init_fields_instruction = ir_build_instruction(irb, source_node); container_init_fields_instruction->container_type = container_type; container_init_fields_instruction->field_count = field_count; - container_init_fields_instruction->field_names = field_names; - container_init_fields_instruction->field_values = field_values; + container_init_fields_instruction->fields = fields; ir_ref_instruction(container_type); for (size_t i = 0; i < field_count; i += 1) { - ir_ref_instruction(field_values[i]); + ir_ref_instruction(fields[i].value); } return &container_init_fields_instruction->base; } +static IrInstruction *ir_build_struct_init(IrBuilder *irb, AstNode *source_node, + TypeTableEntry *struct_type, size_t field_count, IrInstructionStructInitField *fields) +{ + IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, source_node); + struct_init_instruction->struct_type = struct_type; + struct_init_instruction->field_count = field_count; + struct_init_instruction->fields = fields; + + for (size_t i = 0; i < field_count; i += 1) + ir_ref_instruction(fields[i].value); + + return &struct_init_instruction->base; +} + +static IrInstruction *ir_build_struct_init_from(IrBuilder *irb, IrInstruction *old_instruction, + TypeTableEntry *struct_type, size_t field_count, IrInstructionStructInitField *fields) +{ + IrInstruction *new_instruction = ir_build_struct_init(irb, old_instruction->source_node, + struct_type, field_count, fields); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static IrInstruction *ir_build_unreachable(IrBuilder *irb, AstNode *source_node) { IrInstructionUnreachable *unreachable_instruction = ir_build_instruction(irb, source_node); @@ -1442,7 +1522,7 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN ref_instruction = ir_build_const_fn(irb, source_node, fn_entry); } if (lval != LValPurposeNone) - return ir_build_un_op(irb, source_node, IrUnOpAddressOf, ref_instruction); + return ir_build_ref(irb, source_node, ref_instruction); else return ref_instruction; } else if (decl_node->type == NodeTypeContainerDecl) { @@ -1455,14 +1535,14 @@ static IrInstruction *ir_gen_decl_ref(IrBuilder *irb, AstNode *source_node, AstN ref_instruction = ir_build_const_type(irb, source_node, decl_node->data.struct_decl.type_entry); } if (lval != LValPurposeNone) - return ir_build_un_op(irb, source_node, IrUnOpAddressOf, ref_instruction); + return ir_build_ref(irb, source_node, ref_instruction); else return ref_instruction; } else if (decl_node->type == NodeTypeTypeDecl) { TypeTableEntry *child_type = decl_node->data.type_decl.child_type_entry; IrInstruction *ref_instruction = ir_build_const_type(irb, source_node, child_type); if (lval != LValPurposeNone) - return ir_build_un_op(irb, source_node, IrUnOpAddressOf, ref_instruction); + return ir_build_ref(irb, source_node, ref_instruction); else return ref_instruction; } else { @@ -1712,7 +1792,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, AstNode *node) { case BuiltinFnIdDivExact: case BuiltinFnIdTruncate: case BuiltinFnIdIntType: - case BuiltinFnIdSetFnStaticEval: case BuiltinFnIdSetFnNoInline: zig_panic("TODO IR gen more builtin functions"); } @@ -1726,9 +1805,9 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) { return ir_gen_builtin_fn_call(irb, node); AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; - IrInstruction *fn = ir_gen_node(irb, fn_ref_node, node->block_context); - if (fn == irb->codegen->invalid_instruction) - return fn; + IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, node->block_context); + if (fn_ref == irb->codegen->invalid_instruction) + return fn_ref; size_t arg_count = node->data.fn_call_expr.params.length; IrInstruction **args = allocate(arg_count); @@ -1737,7 +1816,7 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, AstNode *node) { args[i] = ir_gen_node(irb, arg_node, node->block_context); } - return ir_build_call(irb, node, fn, arg_count, args); + return ir_build_call(irb, node, nullptr, fn_ref, arg_count, args); } static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) { @@ -1754,7 +1833,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, AstNode *node) { IrBasicBlock *else_block = ir_build_basic_block(irb, "Else"); IrBasicBlock *endif_block = ir_build_basic_block(irb, "EndIf"); - bool is_inline = (node->block_context->fn_entry == nullptr); + bool is_inline = ir_should_inline(irb) || node->data.if_bool_expr.is_inline; ir_build_cond_br(irb, condition->source_node, condition, then_block, else_block, is_inline); ir_set_cursor_at_end(irb, then_block); @@ -1865,8 +1944,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node) if (kind == ContainerInitKindStruct) { size_t field_count = container_init_expr->entries.length; - IrInstruction **values = allocate(field_count); - Buf **names = allocate(field_count); + IrInstructionContainerInitFieldsField *fields = allocate(field_count); for (size_t i = 0; i < field_count; i += 1) { AstNode *entry_node = container_init_expr->entries.at(i); assert(entry_node->type == NodeTypeStructValueField); @@ -1877,10 +1955,11 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, AstNode *node) if (expr_value == irb->codegen->invalid_instruction) return expr_value; - names[i] = name; - values[i] = expr_value; + fields[i].name = name; + fields[i].value = expr_value; + fields[i].source_node = entry_node; } - return ir_build_container_init_fields(irb, node, container_type, field_count, names, values); + return ir_build_container_init_fields(irb, node, container_type, field_count, fields); } else if (kind == ContainerInitKindArray) { size_t item_count = container_init_expr->entries.length; IrInstruction **values = allocate(item_count); @@ -1919,7 +1998,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, AstNode *node) { bool is_shadowable = false; bool is_const = variable_declaration->is_const; bool is_extern = variable_declaration->is_extern; - bool is_inline = variable_declaration->is_inline; + bool is_inline = ir_should_inline(irb) || variable_declaration->is_inline; VariableTableEntry *var = ir_add_local_var(irb, node, node->block_context, variable_declaration->symbol, is_const, is_const, is_shadowable, is_inline); @@ -1943,7 +2022,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, AstNode *node) { ir_build_basic_block(irb, "WhileContinue") : cond_block; IrBasicBlock *end_block = ir_build_basic_block(irb, "WhileEnd"); - bool is_inline = node->data.while_expr.is_inline; + bool is_inline = ir_should_inline(irb) || node->data.while_expr.is_inline; ir_build_br(irb, node, cond_block, is_inline); if (continue_expr_node) { @@ -1998,7 +2077,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, AstNode *node) { } else { elem_var_type = ir_build_ptr_type_child(irb, elem_node, pointer_type); } - bool is_inline = node->data.for_expr.is_inline; + bool is_inline = ir_should_inline(irb) || node->data.for_expr.is_inline; BlockContext *child_scope = new_block_context(node, parent_scope); child_scope->parent_loop_node = node; @@ -2219,7 +2298,7 @@ static IrInstruction *ir_gen_if_var_expr(IrBuilder *irb, AstNode *node) { IrBasicBlock *else_block = ir_build_basic_block(irb, "MaybeElse"); IrBasicBlock *endif_block = ir_build_basic_block(irb, "MaybeEndIf"); - bool is_inline = (node->block_context->fn_entry == nullptr); + bool is_inline = ir_should_inline(irb) || node->data.if_var_expr.is_inline; ir_build_cond_br(irb, node, is_nonnull_value, then_block, else_block, is_inline); ir_set_cursor_at_end(irb, then_block); @@ -2322,7 +2401,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, AstNode *node) { size_t prong_count = node->data.switch_expr.prongs.length; ZigList cases = {0}; - bool is_inline = node->data.switch_expr.is_inline || (node->block_context->fn_entry == nullptr); + bool is_inline = ir_should_inline(irb) || node->data.switch_expr.is_inline; ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -2495,7 +2574,7 @@ static IrInstruction *ir_gen_label(IrBuilder *irb, AstNode *node) { node->block_context->label_table.put(label_name, label); } - bool is_inline = (node->block_context->fn_entry == nullptr); + bool is_inline = ir_should_inline(irb); ir_build_br(irb, node, label_block, is_inline); ir_set_cursor_at_end(irb, label_block); return ir_build_const_void(irb, node); @@ -2535,56 +2614,58 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex node->block_context = block_context; switch (node->type) { + case NodeTypeStructValueField: + zig_unreachable(); case NodeTypeBlock: - return ir_gen_block(irb, node); + return ir_lval_wrap(irb, ir_gen_block(irb, node), lval); case NodeTypeBinOpExpr: - return ir_gen_bin_op(irb, node); + return ir_lval_wrap(irb, ir_gen_bin_op(irb, node), lval); case NodeTypeNumberLiteral: - return ir_gen_num_lit(irb, node); + return ir_lval_wrap(irb, ir_gen_num_lit(irb, node), lval); case NodeTypeSymbol: return ir_gen_symbol(irb, node, lval); case NodeTypeFnCallExpr: return ir_lval_wrap(irb, ir_gen_fn_call(irb, node), lval); case NodeTypeIfBoolExpr: - return ir_gen_if_bool_expr(irb, node); + return ir_lval_wrap(irb, ir_gen_if_bool_expr(irb, node), lval); case NodeTypePrefixOpExpr: return ir_gen_prefix_op_expr(irb, node, lval); case NodeTypeContainerInitExpr: - return ir_gen_container_init_expr(irb, node); + return ir_lval_wrap(irb, ir_gen_container_init_expr(irb, node), lval); case NodeTypeVariableDeclaration: - return ir_gen_var_decl(irb, node); + return ir_lval_wrap(irb, ir_gen_var_decl(irb, node), lval); case NodeTypeWhileExpr: - return ir_gen_while_expr(irb, node); + return ir_lval_wrap(irb, ir_gen_while_expr(irb, node), lval); case NodeTypeForExpr: - return ir_gen_for_expr(irb, node); + return ir_lval_wrap(irb, ir_gen_for_expr(irb, node), lval); case NodeTypeArrayAccessExpr: return ir_gen_array_access(irb, node, lval); case NodeTypeReturnExpr: - return ir_gen_return(irb, node); + return ir_lval_wrap(irb, ir_gen_return(irb, node), lval); case NodeTypeFieldAccessExpr: return ir_gen_field_access(irb, node, lval); case NodeTypeThisLiteral: - return ir_gen_this_literal(irb, node); + return ir_lval_wrap(irb, ir_gen_this_literal(irb, node), lval); case NodeTypeBoolLiteral: - return ir_gen_bool_literal(irb, node); + return ir_lval_wrap(irb, ir_gen_bool_literal(irb, node), lval); case NodeTypeArrayType: - return ir_gen_array_type(irb, node); + return ir_lval_wrap(irb, ir_gen_array_type(irb, node), lval); case NodeTypeStringLiteral: - return ir_gen_string_literal(irb, node); + return ir_lval_wrap(irb, ir_gen_string_literal(irb, node), lval); case NodeTypeUndefinedLiteral: - return ir_gen_undefined_literal(irb, node); + return ir_lval_wrap(irb, ir_gen_undefined_literal(irb, node), lval); case NodeTypeAsmExpr: - return ir_gen_asm_expr(irb, node); + return ir_lval_wrap(irb, ir_gen_asm_expr(irb, node), lval); case NodeTypeNullLiteral: - return ir_gen_null_literal(irb, node); + return ir_lval_wrap(irb, ir_gen_null_literal(irb, node), lval); case NodeTypeIfVarExpr: - return ir_gen_if_var_expr(irb, node); + return ir_lval_wrap(irb, ir_gen_if_var_expr(irb, node), lval); case NodeTypeSwitchExpr: - return ir_gen_switch_expr(irb, node); + return ir_lval_wrap(irb, ir_gen_switch_expr(irb, node), lval); case NodeTypeLabel: - return ir_gen_label(irb, node); + return ir_lval_wrap(irb, ir_gen_label(irb, node), lval); case NodeTypeGoto: - return ir_gen_goto(irb, node); + return ir_lval_wrap(irb, ir_gen_goto(irb, node), lval); case NodeTypeTypeLiteral: return ir_lval_wrap(irb, ir_gen_type_literal(irb, node), lval); case NodeTypeUnwrapErrorExpr: @@ -2604,7 +2685,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, BlockContex case NodeTypeUse: case NodeTypeContainerDecl: case NodeTypeStructField: - case NodeTypeStructValueField: case NodeTypeSwitchProng: case NodeTypeSwitchRange: case NodeTypeErrorValueDecl: @@ -2642,7 +2722,7 @@ static bool ir_goto_pass2(IrBuilder *irb) { } label->used = true; - bool is_inline = goto_node->data.goto_expr.is_inline || (goto_node->block_context->fn_entry == nullptr); + bool is_inline = ir_should_inline(irb) || goto_node->data.goto_expr.is_inline; IrInstruction *new_instruction = ir_create_br(irb, goto_node, label->bb, is_inline); new_instruction->ref_count = old_instruction->ref_count; *slot = new_instruction; @@ -2703,6 +2783,21 @@ IrInstruction *ir_gen_fn(CodeGen *codegn, FnTableEntry *fn_entry) { return ir_gen(codegn, body_node, scope, ir_executable); } +static IrInstruction *ir_eval_fn(IrAnalyze *ira, IrInstruction *source_instruction, + size_t arg_count, IrInstruction **args) +{ + zig_panic("TODO ir_eval_fn"); +} + +static bool ir_emit_global_runtime_side_effect(IrAnalyze *ira, IrInstruction *source_instruction) { + if (ir_should_inline(&ira->new_irb)) { + add_node_error(ira->codegen, source_instruction->source_node, + buf_sprintf("unable to evaluate constant expression")); + return false; + } + return true; +} + static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruction, TypeTableEntry *other_type) { TypeTableEntry *other_type_underlying = get_underlying_type(other_type); @@ -2918,20 +3013,15 @@ static TypeTableEntry *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_nod } static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, - IrInstruction *dest_type, CastOp cast_op, bool need_alloca) + TypeTableEntry *wanted_type, CastOp cast_op, bool need_alloca) { - assert(dest_type->type_entry->id == TypeTableEntryIdMetaType); - assert(dest_type->static_value.special != ConstValSpecialRuntime); - TypeTableEntry *wanted_type = dest_type->static_value.data.x_type; - if (value->static_value.special != ConstValSpecialRuntime) { - IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->source_node, wanted_type); + IrInstruction *result = ir_create_const(&ira->new_irb, source_instr->source_node, wanted_type, false); eval_const_expr_implicit_cast(cast_op, &value->static_value, value->type_entry, &result->static_value, wanted_type); return result; } else { - IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->source_node, - dest_type, value, cast_op); + IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->source_node, wanted_type, value, cast_op); result->type_entry = wanted_type; if (need_alloca && source_instr->source_node->block_context->fn_entry) { source_instr->source_node->block_context->fn_entry->alloca_list.append(result); @@ -3126,12 +3216,8 @@ static FnTableEntry *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { } static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *dest_type, IrInstruction *value) + TypeTableEntry *wanted_type, IrInstruction *value) { - assert(dest_type->type_entry->id == TypeTableEntryIdMetaType); - assert(dest_type->static_value.special != ConstValSpecialRuntime); - - TypeTableEntry *wanted_type = dest_type->static_value.data.x_type; TypeTableEntry *actual_type = value->type_entry; TypeTableEntry *wanted_type_canon = get_underlying_type(wanted_type); TypeTableEntry *actual_type_canon = get_underlying_type(actual_type); @@ -3147,21 +3233,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit match or non-const to const if (types_match_const_cast_only(wanted_type, actual_type)) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpNoop, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); } // explicit cast from bool to int if (wanted_type_canon->id == TypeTableEntryIdInt && actual_type_canon->id == TypeTableEntryIdBool) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpBoolToInt, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBoolToInt, false); } // explicit cast from pointer to isize or usize if ((wanted_type_canon == isize_type || wanted_type_canon == usize_type) && type_is_codegen_pointer(actual_type_canon)) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPtrToInt, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPtrToInt, false); } @@ -3169,7 +3255,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (wanted_type_canon->id == TypeTableEntryIdPointer && (actual_type_canon == isize_type || actual_type_canon == usize_type)) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToPtr, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToPtr, false); } // explicit widening or shortening cast @@ -3178,21 +3264,21 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst (wanted_type_canon->id == TypeTableEntryIdFloat && actual_type_canon->id == TypeTableEntryIdFloat)) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpWidenOrShorten, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpWidenOrShorten, false); } // explicit cast from int to float if (wanted_type_canon->id == TypeTableEntryIdFloat && actual_type_canon->id == TypeTableEntryIdInt) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToFloat, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToFloat, false); } // explicit cast from float to int if (wanted_type_canon->id == TypeTableEntryIdInt && actual_type_canon->id == TypeTableEntryIdFloat) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpFloatToInt, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpFloatToInt, false); } // explicit cast from array to slice @@ -3202,7 +3288,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type, actual_type->data.array.child_type)) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpToUnknownSizeArray, true); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpToUnknownSizeArray, true); } // explicit cast from []T to []u8 or []u8 to []T @@ -3212,8 +3298,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst (wanted_type->data.structure.fields[0].type_entry->data.pointer.is_const || !actual_type->data.structure.fields[0].type_entry->data.pointer.is_const)) { - mark_impure_fn(ira->codegen, source_instr->source_node->block_context, source_instr->source_node); - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpResizeSlice, true); + if (!ir_emit_global_runtime_side_effect(ira, source_instr)) + return ira->codegen->invalid_instruction; + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpResizeSlice, true); } // explicit cast from [N]u8 to []T @@ -3221,11 +3308,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->id == TypeTableEntryIdArray && is_u8(actual_type->data.array.child_type)) { - mark_impure_fn(ira->codegen, source_instr->source_node->block_context, source_instr->source_node); + if (!ir_emit_global_runtime_side_effect(ira, source_instr)) + return ira->codegen->invalid_instruction; uint64_t child_type_size = type_size(ira->codegen, wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type); if (actual_type->data.array.len % child_type_size == 0) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpBytesToSlice, true); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpBytesToSlice, true); } else { add_node_error(ira->codegen, source_instr->source_node, buf_sprintf("unable to convert %s to %s: size mismatch", @@ -3238,7 +3326,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if ((actual_type->id == TypeTableEntryIdPointer || actual_type->id == TypeTableEntryIdFn) && (wanted_type->id == TypeTableEntryIdPointer || wanted_type->id == TypeTableEntryIdFn)) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPointerReinterpret, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPointerReinterpret, false); } // explicit cast from maybe pointer to another maybe pointer @@ -3249,13 +3337,13 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst (wanted_type->data.maybe.child_type->id == TypeTableEntryIdPointer || wanted_type->data.maybe.child_type->id == TypeTableEntryIdFn)) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpPointerReinterpret, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPointerReinterpret, false); } // explicit cast from child type of maybe type to maybe type if (wanted_type->id == TypeTableEntryIdMaybe) { if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type, + IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpMaybeWrap, true); cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull; return cast_instruction; @@ -3263,7 +3351,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->id == TypeTableEntryIdNumLitFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.maybe.child_type)) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type, + IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpMaybeWrap, true); cast_instruction->return_knowledge = ReturnKnowledgeKnownNonNull; return cast_instruction; @@ -3277,7 +3365,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (wanted_type->id == TypeTableEntryIdMaybe && actual_type->id == TypeTableEntryIdNullLit) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type, + IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNullToMaybe, true); cast_instruction->return_knowledge = ReturnKnowledgeKnownNull; return cast_instruction; @@ -3286,7 +3374,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst // explicit cast from child type of error type to error type if (wanted_type->id == TypeTableEntryIdErrorUnion) { if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type, + IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpErrorWrap, true); cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError; return cast_instruction; @@ -3294,7 +3382,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->id == TypeTableEntryIdNumLitFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error.child_type)) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type, + IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpErrorWrap, true); cast_instruction->return_knowledge = ReturnKnowledgeKnownNonError; return cast_instruction; @@ -3308,7 +3396,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (wanted_type->id == TypeTableEntryIdErrorUnion && actual_type->id == TypeTableEntryIdPureError) { - IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, dest_type, + IrInstruction *cast_instruction = ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpPureErrorWrap, false); cast_instruction->return_knowledge = ReturnKnowledgeKnownError; return cast_instruction; @@ -3333,7 +3421,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } else { zig_unreachable(); } - return ir_resolve_cast(ira, source_instr, value, dest_type, op, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false); } else { return ira->codegen->invalid_instruction; } @@ -3351,7 +3439,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (bignum_fits_in_bits(&bn, wanted_type->data.integral.bit_count, wanted_type->data.integral.is_signed)) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpErrToInt, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpErrToInt, false); } else { add_node_error(ira->codegen, source_instr->source_node, buf_sprintf("too many error values to fit in '%s'", buf_ptr(&wanted_type->name))); @@ -3364,7 +3452,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_type->id == TypeTableEntryIdEnum && wanted_type->data.enumeration.gen_field_count == 0) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpIntToEnum, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpIntToEnum, false); } // explicit cast from enum type with no payload to integer @@ -3372,12 +3460,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->id == TypeTableEntryIdEnum && actual_type->data.enumeration.gen_field_count == 0) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpEnumToInt, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpEnumToInt, false); } // explicit cast from undefined to anything if (actual_type->id == TypeTableEntryIdUndefLit) { - return ir_resolve_cast(ira, source_instr, value, dest_type, CastOpNoop, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); } add_node_error(ira->codegen, source_instr->source_node, @@ -3410,11 +3498,7 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, return ira->codegen->invalid_instruction; case ImplicitCastMatchResultYes: - { - IrInstruction *dest_type = ir_create_const_type(&ira->new_irb, value->source_node, expected_type); - IrInstruction *cast_instruction = ir_analyze_cast(ira, value, dest_type, value); - return cast_instruction; - } + return ir_analyze_cast(ira, value, expected_type, value); case ImplicitCastMatchResultReportedError: return ira->codegen->invalid_instruction; } @@ -3422,6 +3506,58 @@ static IrInstruction *ir_get_casted_value(IrAnalyze *ira, IrInstruction *value, zig_unreachable(); } +static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) { + TypeTableEntry *type_entry = ptr->type_entry; + if (type_entry->id == TypeTableEntryIdInvalid) { + return ira->codegen->invalid_instruction; + } else if (type_entry->id == TypeTableEntryIdPointer) { + TypeTableEntry *child_type = type_entry->data.pointer.child_type; + if (ptr->static_value.special != ConstValSpecialRuntime) { + ConstExprValue *pointee = const_ptr_pointee(&ptr->static_value); + if (pointee->special != ConstValSpecialRuntime) { + IrInstruction *result = ir_create_const(&ira->new_irb, source_instruction->source_node, + child_type, pointee->depends_on_compile_var); + result->static_value = *pointee; + return result; + } + } + IrInstruction *load_ptr_instruction = ir_build_load_ptr(&ira->new_irb, source_instruction->source_node, ptr); + load_ptr_instruction->type_entry = child_type; + return load_ptr_instruction; + } else { + add_node_error(ira->codegen, source_instruction->source_node, + buf_sprintf("attempt to dereference non pointer type '%s'", + buf_ptr(&type_entry->name))); + return ira->codegen->invalid_instruction; + } +} + +static TypeTableEntry *ir_analyze_ref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *value) { + if (value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + bool is_inline = ir_should_inline(&ira->new_irb); + if (is_inline || value->static_value.special != ConstValSpecialRuntime) { + ConstExprValue *val = ir_resolve_const(ira, value); + if (!val) + return ira->codegen->builtin_types.entry_invalid; + return ir_analyze_const_ptr(ira, source_instruction, val, value->type_entry, false); + } + + TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true); + if (handle_is_ptr(value->type_entry)) { + // this instruction is a noop - codegen can pass the pointer we already have as the result + ir_link_new_instruction(value, source_instruction); + return ptr_type; + } else { + FnTableEntry *fn_entry = source_instruction->source_node->block_context->fn_entry; + IrInstruction *new_instruction = ir_build_ref_from(&ira->new_irb, source_instruction, value); + fn_entry->alloca_list.append(new_instruction); + return ptr_type; + } +} + + static bool ir_resolve_usize(IrAnalyze *ira, IrInstruction *value, uint64_t *out) { if (value->type_entry->id == TypeTableEntryIdInvalid) return false; @@ -3580,6 +3716,7 @@ static TypeTableEntry *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: if (!is_equality_cmp) { add_node_error(ira->codegen, source_node, buf_sprintf("operator not allowed for type '%s'", buf_ptr(&resolved_type->name))); @@ -3944,6 +4081,7 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: // OK break; } @@ -3966,13 +4104,121 @@ static TypeTableEntry *ir_analyze_instruction_decl_var(IrAnalyze *ira, IrInstruc return ira->codegen->builtin_types.entry_void; } +static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, + FnTableEntry *fn_entry, TypeTableEntry *fn_type, IrInstruction *fn_ref, + IrInstruction *first_arg_ptr, bool is_inline) +{ + FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; + size_t first_arg_1_or_0 = first_arg_ptr ? 1 : 0; + size_t src_param_count = fn_type_id->param_count; + size_t call_param_count = call_instruction->arg_count + first_arg_1_or_0; + AstNode *source_node = call_instruction->base.source_node; + + AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;; + + if (fn_type_id->is_var_args) { + if (call_param_count < src_param_count) { + ErrorMsg *msg = add_node_error(ira->codegen, source_node, + buf_sprintf("expected at least %zu arguments, found %zu", src_param_count, call_param_count)); + if (fn_proto_node) { + add_error_note(ira->codegen, msg, fn_proto_node, + buf_sprintf("declared here")); + } + return ira->codegen->builtin_types.entry_invalid; + } + } else if (src_param_count != call_param_count) { + ErrorMsg *msg = add_node_error(ira->codegen, source_node, + buf_sprintf("expected %zu arguments, found %zu", src_param_count, call_param_count)); + if (fn_proto_node) { + add_error_note(ira->codegen, msg, fn_proto_node, + buf_sprintf("declared here")); + } + return ira->codegen->builtin_types.entry_invalid; + } + + IrInstruction **casted_args = allocate(call_param_count); + size_t next_arg_index = 0; + if (first_arg_ptr) { + IrInstruction *first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); + if (first_arg->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type; + if (param_type->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + IrInstruction *casted_arg = ir_get_casted_value(ira, first_arg, param_type); + if (casted_arg->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + if (is_inline && !ir_resolve_const(ira, casted_arg)) + return ira->codegen->builtin_types.entry_invalid; + + casted_args[next_arg_index] = casted_arg; + next_arg_index += 1; + } + for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) { + IrInstruction *old_arg = call_instruction->args[call_i]->other; + if (old_arg->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + IrInstruction *casted_arg; + if (next_arg_index < src_param_count) { + TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type; + if (param_type->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + casted_arg = ir_get_casted_value(ira, old_arg, param_type); + if (casted_arg->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + } else { + casted_arg = old_arg; + } + + if (is_inline && !ir_resolve_const(ira, casted_arg)) + return ira->codegen->builtin_types.entry_invalid; + + casted_args[next_arg_index] = casted_arg; + next_arg_index += 1; + } + + assert(next_arg_index == call_param_count); + + TypeTableEntry *return_type = fn_type_id->return_type; + if (return_type->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + if (is_inline) { + IrInstruction *result = ir_eval_fn(ira, &call_instruction->base, call_param_count, casted_args); + if (result->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + ConstExprValue *out_val = ir_build_const_from(ira, &call_instruction->base, + result->static_value.depends_on_compile_var); + *out_val = result->static_value; + return ir_finish_anal(ira, return_type); + } + + IrInstruction *new_call_instruction = ir_build_call_from(&ira->new_irb, &call_instruction->base, + fn_entry, fn_ref, call_param_count, casted_args); + + if (type_has_bits(return_type) && handle_is_ptr(return_type)) + call_instruction->base.source_node->block_context->fn_entry->alloca_list.append(new_call_instruction); + + return ir_finish_anal(ira, return_type); +} + static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) { - IrInstruction *fn_ref = call_instruction->fn->other; + IrInstruction *fn_ref = call_instruction->fn_ref->other; if (fn_ref->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; - if (fn_ref->static_value.special != ConstValSpecialRuntime) { + bool is_inline = call_instruction->is_inline || ir_should_inline(&ira->new_irb); + + if (is_inline || fn_ref->static_value.special != ConstValSpecialRuntime) { if (fn_ref->type_entry->id == TypeTableEntryIdMetaType) { + TypeTableEntry *dest_type = ir_resolve_type(ira, fn_ref); + if (!dest_type) + return ira->codegen->builtin_types.entry_invalid; + size_t actual_param_count = call_instruction->arg_count; if (actual_param_count != 1) { @@ -3982,38 +4228,39 @@ static TypeTableEntry *ir_analyze_instruction_call(IrAnalyze *ira, IrInstruction } IrInstruction *arg = call_instruction->args[0]->other; - IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, fn_ref, arg); - if (cast_instruction == ira->codegen->invalid_instruction) + + IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg); + if (cast_instruction->type_entry->id == TypeTableEntryIdInvalid) return ira->codegen->builtin_types.entry_invalid; ir_link_new_instruction(cast_instruction, &call_instruction->base); return ir_finish_anal(ira, cast_instruction->type_entry); } else if (fn_ref->type_entry->id == TypeTableEntryIdFn) { - // TODO fully port over the fn call analyze code to IR - FnTableEntry *fn_table_entry = fn_ref->static_value.data.x_fn; - TypeTableEntry *fn_type = fn_table_entry->type_entry; - - IrInstruction **casted_args = allocate(call_instruction->arg_count); - for (size_t i = 0; i < call_instruction->arg_count; i += 1) { - TypeTableEntry *param_type = fn_type->data.fn.fn_type_id.param_info[i].type; - IrInstruction *old_arg = call_instruction->args[i]->other; - if (old_arg->type_entry->id == TypeTableEntryIdInvalid) - return ira->codegen->builtin_types.entry_invalid; - casted_args[i] = ir_get_casted_value(ira, old_arg, param_type); - } - - ir_build_call_from(&ira->new_irb, &call_instruction->base, - fn_ref, call_instruction->arg_count, casted_args); - - return ir_finish_anal(ira, fn_type->data.fn.fn_type_id.return_type); + FnTableEntry *fn_table_entry = ir_resolve_fn(ira, fn_ref); + return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, + fn_ref, nullptr, is_inline); + } else if (fn_ref->type_entry->id == TypeTableEntryIdBoundFn) { + assert(fn_ref->static_value.special == ConstValSpecialStatic); + FnTableEntry *fn_table_entry = fn_ref->static_value.data.x_bound_fn.fn; + IrInstruction *first_arg_ptr = fn_ref->static_value.data.x_bound_fn.first_arg; + return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, + nullptr, first_arg_ptr, is_inline); + } else if (fn_ref->type_entry->id == TypeTableEntryIdGenericFn) { + zig_panic("TODO generic fn call"); } else { - zig_panic("TODO analyze more fn call types"); + add_node_error(ira->codegen, fn_ref->source_node, + buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->type_entry->name))); + return ira->codegen->builtin_types.entry_invalid; } - } else { - //ir_build_call_from(&ira->new_irb, &call_instruction->base, - // call_instruction->fn, call_instruction->arg_count, call_instruction->args); + } - zig_panic("TODO analyze fn call"); + if (fn_ref->type_entry->id == TypeTableEntryIdFn) { + return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->type_entry, + fn_ref, nullptr, false); + } else { + add_node_error(ira->codegen, fn_ref->source_node, + buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->type_entry->name))); + return ira->codegen->builtin_types.entry_invalid; } } @@ -4071,6 +4318,7 @@ static TypeTableEntry *ir_analyze_unary_prefix_op_err(IrAnalyze *ira, IrInstruct case TypeTableEntryIdUnion: case TypeTableEntryIdFn: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, value->static_value.depends_on_compile_var); @@ -4119,6 +4367,7 @@ static TypeTableEntry *ir_analyze_unary_address_of(IrAnalyze *ira, IrInstruction case TypeTableEntryIdUnreachable: case TypeTableEntryIdVar: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: add_node_error(ira->codegen, un_op_instruction->base.source_node, buf_sprintf("unable to get address of type '%s'", buf_ptr(&target_type->name))); // TODO if type decl, add note pointing to type decl declaration @@ -4217,6 +4466,7 @@ static TypeTableEntry *ir_analyze_maybe(IrAnalyze *ira, IrInstructionUnOp *un_op case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: { ConstExprValue *out_val = ir_build_const_from(ira, &un_op_instruction->base, value->static_value.depends_on_compile_var); @@ -4626,7 +4876,7 @@ static TypeTableEntry *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruc static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, TypeTableEntry *bare_struct_type, Buf *field_name, IrInstructionFieldPtr *field_ptr_instruction, - TypeTableEntry *container_type) + IrInstruction *container_ptr, TypeTableEntry *container_type) { if (!is_slice(bare_struct_type)) { BlockContext *container_block_context = get_container_block_context(bare_struct_type); @@ -4634,7 +4884,15 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, auto entry = container_block_context->decl_table.maybe_get(field_name); AstNode *fn_decl_node = entry ? entry->value : nullptr; if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) { - zig_panic("TODO member function call"); + resolve_top_level_decl(ira->codegen, fn_decl_node, false); + TopLevelDecl *tld = get_as_top_level_decl(fn_decl_node); + if (tld->resolution == TldResolutionInvalid) + return ira->codegen->builtin_types.entry_invalid; + FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry; + bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var; + IrInstruction *bound_fn_value = ir_build_const_bound_fn(&ira->new_irb, + field_ptr_instruction->base.source_node, fn_entry, container_ptr, depends_on_compile_var); + return ir_analyze_ref(ira, &field_ptr_instruction->base, bound_fn_value); } } add_node_error(ira->codegen, field_ptr_instruction->base.source_node, @@ -4643,14 +4901,12 @@ static TypeTableEntry *ir_analyze_container_member_access_inner(IrAnalyze *ira, } -static TypeTableEntry *ir_analyze_container_member_access(IrAnalyze *ira, Buf *field_name, - IrInstructionFieldPtr *field_ptr_instruction, TypeTableEntry *container_type) +static TypeTableEntry *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, + IrInstructionFieldPtr *field_ptr_instruction, IrInstruction *container_ptr, TypeTableEntry *container_type) { - IrInstruction *container_ptr = field_ptr_instruction->container_ptr->other; TypeTableEntry *bare_type = container_ref_type(container_type); - if (!type_is_complete(bare_type)) { + if (!type_is_complete(bare_type)) resolve_container_type(ira->codegen, bare_type); - } if (bare_type->id == TypeTableEntryIdStruct) { TypeStructField *field = find_struct_type_field(bare_type, field_name); @@ -4659,10 +4915,17 @@ static TypeTableEntry *ir_analyze_container_member_access(IrAnalyze *ira, Buf *f return get_pointer_to_type(ira->codegen, field->type_entry, false); } else { return ir_analyze_container_member_access_inner(ira, bare_type, field_name, - field_ptr_instruction, container_type); + field_ptr_instruction, container_ptr, container_type); } } else if (bare_type->id == TypeTableEntryIdEnum) { - zig_panic("TODO enum field ptr"); + TypeEnumField *field = find_enum_type_field(bare_type, field_name); + if (field) { + ir_build_enum_field_ptr_from(&ira->new_irb, &field_ptr_instruction->base, container_ptr, field); + return get_pointer_to_type(ira->codegen, field->type_entry, false); + } else { + return ir_analyze_container_member_access_inner(ira, bare_type, field_name, + field_ptr_instruction, container_ptr, container_type); + } } else if (bare_type->id == TypeTableEntryIdUnion) { zig_panic("TODO"); } else { @@ -4733,7 +4996,7 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru if (container_type->id == TypeTableEntryIdInvalid) { return container_type; } else if (is_container_ref(container_type)) { - return ir_analyze_container_member_access(ira, field_name, field_ptr_instruction, container_type); + return ir_analyze_container_field_ptr(ira, field_name, field_ptr_instruction, container_ptr, container_type); } else if (container_type->id == TypeTableEntryIdArray) { if (buf_eql_str(field_name, "len")) { ConstExprValue *len_val = allocate(1); @@ -4749,24 +5012,38 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru return ira->codegen->builtin_types.entry_invalid; } } else if (container_type->id == TypeTableEntryIdMetaType) { - zig_panic("TODO type field access"); - //TypeTableEntry *child_type = ir_resolve_type(ira, container_ptr); + ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr); + if (!container_ptr_val) + return ira->codegen->builtin_types.entry_invalid; + ConstExprValue *child_val = const_ptr_pointee(container_ptr_val); + TypeTableEntry *child_type = child_val->data.x_type; - //if (child_type->id == TypeTableEntryIdInvalid) { - // return ira->codegen->builtin_types.entry_invalid; - //} else if (child_type->id == TypeTableEntryIdEnum) { - // zig_panic("TODO enum type field"); - //} else if (child_type->id == TypeTableEntryIdStruct) { - // zig_panic("TODO struct type field"); - //} else if (child_type->id == TypeTableEntryIdPureError) { - // zig_panic("TODO error type field"); - //} else if (child_type->id == TypeTableEntryIdInt) { - // zig_panic("TODO integer type field"); - //} else { - // add_node_error(ira->codegen, source_node, - // buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); - // return ira->codegen->builtin_types.entry_invalid; - //} + if (child_type->id == TypeTableEntryIdInvalid) { + return ira->codegen->builtin_types.entry_invalid; + } else if (child_type->id == TypeTableEntryIdEnum) { + zig_panic("TODO enum type field"); + } else if (child_type->id == TypeTableEntryIdStruct) { + BlockContext *container_block_context = get_container_block_context(child_type); + auto entry = container_block_context->decl_table.maybe_get(field_name); + AstNode *decl_node = entry ? entry->value : nullptr; + if (decl_node) { + bool depends_on_compile_var = container_ptr->static_value.depends_on_compile_var; + return ir_analyze_decl_ref(ira, &field_ptr_instruction->base, decl_node, depends_on_compile_var); + } else { + add_node_error(ira->codegen, source_node, + buf_sprintf("container '%s' has no member called '%s'", + buf_ptr(&child_type->name), buf_ptr(field_name))); + return ira->codegen->builtin_types.entry_invalid; + } + } else if (child_type->id == TypeTableEntryIdPureError) { + zig_panic("TODO error type field"); + } else if (child_type->id == TypeTableEntryIdInt) { + zig_panic("TODO integer type field"); + } else { + add_node_error(ira->codegen, source_node, + buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } } else if (container_type->id == TypeTableEntryIdNamespace) { ConstExprValue *container_ptr_val = ir_resolve_const(ira, container_ptr); if (!container_ptr_val) @@ -4817,28 +5094,10 @@ static TypeTableEntry *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstru static TypeTableEntry *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstructionLoadPtr *load_ptr_instruction) { IrInstruction *ptr = load_ptr_instruction->ptr->other; - TypeTableEntry *type_entry = ptr->type_entry; - if (type_entry->id == TypeTableEntryIdInvalid) { - return type_entry; - } else if (type_entry->id == TypeTableEntryIdPointer) { - TypeTableEntry *child_type = type_entry->data.pointer.child_type; - if (ptr->static_value.special != ConstValSpecialRuntime) { - ConstExprValue *pointee = const_ptr_pointee(&ptr->static_value); - if (pointee->special != ConstValSpecialRuntime) { - ConstExprValue *out_val = ir_build_const_from(ira, &load_ptr_instruction->base, - pointee->depends_on_compile_var); - *out_val = *pointee; - return child_type; - } - } - ir_build_load_ptr_from(&ira->new_irb, &load_ptr_instruction->base, ptr); - return child_type; - } else { - add_node_error(ira->codegen, load_ptr_instruction->base.source_node, - buf_sprintf("attempt to dereference non pointer type '%s'", - buf_ptr(&type_entry->name))); - return ira->codegen->builtin_types.entry_invalid; - } + IrInstruction *result = ir_get_deref(ira, &load_ptr_instruction->base, ptr); + ir_link_new_instruction(result, &load_ptr_instruction->base); + assert(result->type_entry); + return result->type_entry; } static TypeTableEntry *ir_analyze_instruction_store_ptr(IrAnalyze *ira, IrInstructionStorePtr *store_ptr_instruction) { @@ -4911,6 +5170,7 @@ static TypeTableEntry *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructi case TypeTableEntryIdNamespace: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdMetaType: case TypeTableEntryIdVoid: case TypeTableEntryIdBool: @@ -5148,6 +5408,7 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, case TypeTableEntryIdFn: case TypeTableEntryIdNamespace: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: { TypeTableEntry *result_type = get_slice_type(ira->codegen, resolved_child_type, is_const); ConstExprValue *out_val = ir_build_const_from(ira, &slice_type_instruction->base, @@ -5161,8 +5422,9 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsm *asm_instruction) { assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr); - mark_impure_fn(ira->codegen, asm_instruction->base.source_node->block_context, - asm_instruction->base.source_node); + + if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base)) + return ira->codegen->builtin_types.entry_invalid; // TODO validate the output types and variable types @@ -5236,6 +5498,7 @@ static TypeTableEntry *ir_analyze_instruction_array_type(IrAnalyze *ira, case TypeTableEntryIdFn: case TypeTableEntryIdNamespace: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: { TypeTableEntry *result_type = get_array_type(ira->codegen, child_type, size); bool depends_on_compile_var = child_type_value->static_value.depends_on_compile_var || @@ -5306,6 +5569,7 @@ static TypeTableEntry *ir_analyze_instruction_size_of(IrAnalyze *ira, case TypeTableEntryIdNumLitFloat: case TypeTableEntryIdNumLitInt: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: case TypeTableEntryIdMetaType: case TypeTableEntryIdFn: case TypeTableEntryIdNamespace: @@ -5469,7 +5733,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_br(IrAnalyze *ira, return ir_unreach_error(ira); size_t case_count = switch_br_instruction->case_count; - bool is_inline = switch_br_instruction->is_inline; + bool is_inline = ir_should_inline(&ira->new_irb) || switch_br_instruction->is_inline; if (is_inline || target_value->static_value.special != ConstValSpecialRuntime) { ConstExprValue *target_val = ir_resolve_const(ira, target_value); @@ -5599,6 +5863,7 @@ static TypeTableEntry *ir_analyze_instruction_switch_target(IrAnalyze *ira, case TypeTableEntryIdUnion: case TypeTableEntryIdBlock: case TypeTableEntryIdGenericFn: + case TypeTableEntryIdBoundFn: add_node_error(ira->codegen, switch_target_instruction->base.source_node, buf_sprintf("invalid switch target type '%s'", buf_ptr(&target_type->name))); // TODO if this is a typedecl, add error note showing the declaration of the type decl @@ -5741,27 +6006,198 @@ static TypeTableEntry *ir_analyze_instruction_array_len(IrAnalyze *ira, static TypeTableEntry *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRef *ref_instruction) { IrInstruction *value = ref_instruction->value->other; - if (value->type_entry->id == TypeTableEntryIdInvalid) + return ir_analyze_ref(ira, &ref_instruction->base, value); +} + +static TypeTableEntry *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, + TypeTableEntry *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields, + bool depends_on_compile_var) +{ + size_t actual_field_count = container_type->data.structure.src_field_count; + + IrInstruction *first_non_const_instruction = nullptr; + + AstNode **field_assign_nodes = allocate(actual_field_count); + + IrInstructionStructInitField *new_fields = allocate(actual_field_count); + + FnTableEntry *fn_entry = instruction->source_node->block_context->fn_entry; + bool outside_fn = (fn_entry == nullptr); + + ConstExprValue const_val = {}; + const_val.special = ConstValSpecialStatic; + const_val.depends_on_compile_var = depends_on_compile_var; + const_val.data.x_struct.fields = allocate(actual_field_count); + for (size_t i = 0; i < instr_field_count; i += 1) { + IrInstructionContainerInitFieldsField *field = &fields[i]; + + IrInstruction *field_value = field->value->other; + if (field_value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + TypeStructField *type_field = find_struct_type_field(container_type, field->name); + if (!type_field) { + add_node_error(ira->codegen, field->source_node, + buf_sprintf("no member named '%s' in '%s'", + buf_ptr(field->name), buf_ptr(&container_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } + + if (type_field->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + size_t field_index = type_field->src_index; + AstNode *existing_assign_node = field_assign_nodes[field_index]; + if (existing_assign_node) { + ErrorMsg *msg = add_node_error(ira->codegen, field->source_node, buf_sprintf("duplicate field")); + add_error_note(ira->codegen, msg, existing_assign_node, buf_sprintf("other field here")); + continue; + } + field_assign_nodes[field_index] = field->source_node; + + new_fields[field_index].value = field_value; + new_fields[field_index].type_struct_field = type_field; + + if (const_val.special == ConstValSpecialStatic) { + if (outside_fn || field_value->static_value.special != ConstValSpecialRuntime) { + ConstExprValue *field_val = ir_resolve_const(ira, field_value); + if (!field_val) + return ira->codegen->builtin_types.entry_invalid; + + const_val.data.x_struct.fields[field_index] = *field_val; + const_val.depends_on_compile_var = const_val.depends_on_compile_var || field_val->depends_on_compile_var; + } else { + first_non_const_instruction = field_value; + const_val.special = ConstValSpecialRuntime; + } + } + } + + bool any_missing = false; + for (size_t i = 0; i < actual_field_count; i += 1) { + if (!field_assign_nodes[i]) { + add_node_error(ira->codegen, instruction->source_node, + buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name))); + any_missing = true; + } + } + if (any_missing) return ira->codegen->builtin_types.entry_invalid; - FnTableEntry *fn_entry = ref_instruction->base.source_node->block_context->fn_entry; - if (!fn_entry || value->static_value.special != ConstValSpecialRuntime) { - ConstExprValue *val = ir_resolve_const(ira, value); - if (!val) - return ira->codegen->builtin_types.entry_invalid; - return ir_analyze_const_ptr(ira, &ref_instruction->base, val, value->type_entry, false); + if (const_val.special == ConstValSpecialStatic) { + ConstExprValue *out_val = ir_build_const_from(ira, instruction, const_val.depends_on_compile_var); + *out_val = const_val; + return container_type; } - TypeTableEntry *ptr_type = get_pointer_to_type(ira->codegen, value->type_entry, true); - if (handle_is_ptr(value->type_entry)) { - // this instruction is a noop - codegen can pass the pointer we already have as the result - ir_link_new_instruction(value, &ref_instruction->base); - return ptr_type; - } else { - fn_entry->alloca_list.append(&ref_instruction->base); - ir_build_ref_from(&ira->new_irb, &ref_instruction->base, value); - return ptr_type; + if (outside_fn) { + add_node_error(ira->codegen, first_non_const_instruction->source_node, + buf_sprintf("unable to evaluate constant expression")); + return ira->codegen->builtin_types.entry_invalid; } + + IrInstruction *new_instruction = ir_build_struct_init_from(&ira->new_irb, instruction, + container_type, actual_field_count, new_fields); + fn_entry->alloca_list.append(new_instruction); + return container_type; +} + +static TypeTableEntry *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { + IrInstruction *container_type_value = instruction->container_type->other; + TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); + if (!container_type) + return ira->codegen->builtin_types.entry_invalid; + + size_t elem_count = instruction->item_count; + bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; + + if (container_type->id == TypeTableEntryIdStruct && !is_slice(container_type) && elem_count == 0) { + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, depends_on_compile_var); + } else if (is_slice(container_type)) { + TypeTableEntry *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; + assert(pointer_type->id == TypeTableEntryIdPointer); + TypeTableEntry *child_type = pointer_type->data.pointer.child_type; + + ConstExprValue const_val = {}; + const_val.special = ConstValSpecialStatic; + const_val.depends_on_compile_var = depends_on_compile_var; + const_val.data.x_array.elements = allocate(elem_count); + const_val.data.x_array.size = elem_count; + + FnTableEntry *fn_entry = instruction->base.source_node->block_context->fn_entry; + bool outside_fn = (fn_entry == nullptr); + + IrInstruction **new_items = allocate(elem_count); + + IrInstruction *first_non_const_instruction = nullptr; + + for (size_t i = 0; i < elem_count; i += 1) { + IrInstruction *arg_value = instruction->items[i]->other; + if (arg_value->type_entry->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + + new_items[i] = arg_value; + + if (const_val.special == ConstValSpecialStatic) { + if (outside_fn || arg_value->static_value.special != ConstValSpecialRuntime) { + ConstExprValue *elem_val = ir_resolve_const(ira, arg_value); + if (!elem_val) + return ira->codegen->builtin_types.entry_invalid; + + const_val.data.x_array.elements[i] = *elem_val; + const_val.depends_on_compile_var = const_val.depends_on_compile_var || elem_val->depends_on_compile_var; + } else { + first_non_const_instruction = arg_value; + const_val.special = ConstValSpecialRuntime; + } + } + } + + TypeTableEntry *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); + if (const_val.special == ConstValSpecialStatic) { + ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, const_val.depends_on_compile_var); + *out_val = const_val; + return fixed_size_array_type; + } + + if (outside_fn) { + add_node_error(ira->codegen, first_non_const_instruction->source_node, + buf_sprintf("unable to evaluate constant expression")); + return ira->codegen->builtin_types.entry_invalid; + } + + IrInstruction *new_instruction = ir_build_container_init_list_from(&ira->new_irb, &instruction->base, + container_type_value, elem_count, new_items); + fn_entry->alloca_list.append(new_instruction); + return fixed_size_array_type; + } else if (container_type->id == TypeTableEntryIdArray) { + // same as slice init but we make a compile error if the length is wrong + zig_panic("TODO array container init"); + } else if (container_type->id == TypeTableEntryIdVoid) { + if (elem_count != 0) { + add_node_error(ira->codegen, instruction->base.source_node, + buf_sprintf("void expression expects no arguments")); + return ira->codegen->builtin_types.entry_invalid; + } + return ir_analyze_void(ira, &instruction->base); + } else { + add_node_error(ira->codegen, instruction->base.source_node, + buf_sprintf("type '%s' does not support array initialization", + buf_ptr(&container_type->name))); + return ira->codegen->builtin_types.entry_invalid; + } +} + +static TypeTableEntry *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, IrInstructionContainerInitFields *instruction) { + IrInstruction *container_type_value = instruction->container_type->other; + TypeTableEntry *container_type = ir_resolve_type(ira, container_type_value); + if (!container_type) + return ira->codegen->builtin_types.entry_invalid; + + bool depends_on_compile_var = container_type_value->static_value.depends_on_compile_var; + + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, + instruction->field_count, instruction->fields, depends_on_compile_var); } static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { @@ -5844,10 +6280,14 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_array_len(ira, (IrInstructionArrayLen *)instruction); case IrInstructionIdRef: return ir_analyze_instruction_ref(ira, (IrInstructionRef *)instruction); - case IrInstructionIdCast: case IrInstructionIdContainerInitList: + return ir_analyze_instruction_container_init_list(ira, (IrInstructionContainerInitList *)instruction); case IrInstructionIdContainerInitFields: + return ir_analyze_instruction_container_init_fields(ira, (IrInstructionContainerInitFields *)instruction); + case IrInstructionIdCast: case IrInstructionIdStructFieldPtr: + case IrInstructionIdEnumFieldPtr: + case IrInstructionIdStructInit: zig_panic("TODO analyze more instructions"); } zig_unreachable(); @@ -5947,6 +6387,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: + case IrInstructionIdStructInit: case IrInstructionIdFieldPtr: case IrInstructionIdElemPtr: case IrInstructionIdVarPtr: @@ -5955,6 +6396,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPtrTypeChild: case IrInstructionIdArrayLen: case IrInstructionIdStructFieldPtr: + case IrInstructionIdEnumFieldPtr: case IrInstructionIdArrayType: case IrInstructionIdSliceType: case IrInstructionIdCompileVar: @@ -6393,46 +6835,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // return g->builtin_types.entry_void; //} // -//static TypeTableEntry *analyze_set_fn_static_eval(CodeGen *g, ImportTableEntry *import, -// BlockContext *context, AstNode *node) -//{ -// AstNode **fn_node = &node->data.fn_call_expr.params.at(0); -// AstNode **value_node = &node->data.fn_call_expr.params.at(1); -// -// FnTableEntry *fn_entry = resolve_const_expr_fn(g, import, context, fn_node); -// if (!fn_entry) { -// return g->builtin_types.entry_invalid; -// } -// -// bool want_static_eval; -// bool ok = resolve_const_expr_bool(g, import, context, value_node, &want_static_eval); -// if (!ok) { -// return g->builtin_types.entry_invalid; -// } -// -// if (fn_entry->fn_static_eval_set_node) { -// ErrorMsg *msg = add_node_error(g, node, buf_sprintf("function static eval attribute set twice")); -// add_error_note(g, msg, fn_entry->fn_static_eval_set_node, buf_sprintf("first set here")); -// return g->builtin_types.entry_invalid; -// } -// fn_entry->fn_static_eval_set_node = node; -// -// if (want_static_eval && !context->fn_entry->is_pure) { -// add_node_error(g, node, buf_sprintf("attribute appears too late within function")); -// return g->builtin_types.entry_invalid; -// } -// -// if (want_static_eval) { -// fn_entry->want_pure = WantPureTrue; -// fn_entry->want_pure_attr_node = node; -// } else { -// fn_entry->want_pure = WantPureFalse; -// fn_entry->is_pure = false; -// } -// -// return g->builtin_types.entry_void; -//} -// //static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, // TypeTableEntry *expected_type, AstNode *node) //{ @@ -6634,713 +7036,10 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // return analyze_set_fn_test(g, import, context, node); // case BuiltinFnIdSetFnNoInline: // return analyze_set_fn_no_inline(g, import, context, node); -// case BuiltinFnIdSetFnStaticEval: -// return analyze_set_fn_static_eval(g, import, context, node); // } // zig_unreachable(); //} -//static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import, -// BlockContext *context, AstNode *node) -//{ -// assert(node->type == NodeTypeContainerInitExpr); -// -// AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; -// -// ContainerInitKind kind = container_init_expr->kind; -// -// if (container_init_expr->type->type == NodeTypeFieldAccessExpr) { -// container_init_expr->type->data.field_access_expr.container_init_expr_node = node; -// } -// -// TypeTableEntry *container_meta_type = analyze_expression(g, import, context, nullptr, -// container_init_expr->type); -// -// if (container_meta_type->id == TypeTableEntryIdInvalid) { -// return g->builtin_types.entry_invalid; -// } -// -// if (node->data.container_init_expr.enum_type) { -// get_resolved_expr(node)->const_val = get_resolved_expr(container_init_expr->type)->const_val; -// return node->data.container_init_expr.enum_type; -// } -// -// TypeTableEntry *container_type = resolve_type(g, container_init_expr->type); -// -// if (container_type->id == TypeTableEntryIdInvalid) { -// return container_type; -// } else if (container_type->id == TypeTableEntryIdStruct && -// !container_type->data.structure.is_slice && -// (kind == ContainerInitKindStruct || (kind == ContainerInitKindArray && -// container_init_expr->entries.length == 0))) -// { -// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr; -// codegen->type_entry = container_type; -// codegen->source_node = node; -// -// -// size_t expr_field_count = container_init_expr->entries.length; -// size_t actual_field_count = container_type->data.structure.src_field_count; -// -// AstNode *non_const_expr_culprit = nullptr; -// -// size_t *field_use_counts = allocate(actual_field_count); -// ConstExprValue *const_val = &get_resolved_expr(node)->const_val; -// const_val->ok = true; -// const_val->data.x_struct.fields = allocate(actual_field_count); -// for (size_t i = 0; i < expr_field_count; i += 1) { -// AstNode *val_field_node = container_init_expr->entries.at(i); -// assert(val_field_node->type == NodeTypeStructValueField); -// -// val_field_node->block_context = context; -// -// TypeStructField *type_field = find_struct_type_field(container_type, -// val_field_node->data.struct_val_field.name); -// -// if (!type_field) { -// add_node_error(g, val_field_node, -// buf_sprintf("no member named '%s' in '%s'", -// buf_ptr(val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name))); -// continue; -// } -// -// if (type_field->type_entry->id == TypeTableEntryIdInvalid) { -// return g->builtin_types.entry_invalid; -// } -// -// size_t field_index = type_field->src_index; -// field_use_counts[field_index] += 1; -// if (field_use_counts[field_index] > 1) { -// add_node_error(g, val_field_node, buf_sprintf("duplicate field")); -// continue; -// } -// -// val_field_node->data.struct_val_field.type_struct_field = type_field; -// -// analyze_expression(g, import, context, type_field->type_entry, -// val_field_node->data.struct_val_field.expr); -// -// if (const_val->ok) { -// ConstExprValue *field_val = -// &get_resolved_expr(val_field_node->data.struct_val_field.expr)->const_val; -// if (field_val->ok) { -// const_val->data.x_struct.fields[field_index] = field_val; -// const_val->depends_on_compile_var = const_val->depends_on_compile_var || field_val->depends_on_compile_var; -// } else { -// const_val->ok = false; -// non_const_expr_culprit = val_field_node->data.struct_val_field.expr; -// } -// } -// } -// if (!const_val->ok) { -// assert(non_const_expr_culprit); -// if (context->fn_entry) { -// context->fn_entry->struct_val_expr_alloca_list.append(codegen); -// } else { -// add_node_error(g, non_const_expr_culprit, buf_sprintf("unable to evaluate constant expression")); -// } -// } -// -// for (size_t i = 0; i < actual_field_count; i += 1) { -// if (field_use_counts[i] == 0) { -// add_node_error(g, node, -// buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name))); -// } -// } -// return container_type; -// } else if (container_type->id == TypeTableEntryIdStruct && -// container_type->data.structure.is_slice && -// kind == ContainerInitKindArray) -// { -// size_t elem_count = container_init_expr->entries.length; -// -// TypeTableEntry *pointer_type = container_type->data.structure.fields[0].type_entry; -// assert(pointer_type->id == TypeTableEntryIdPointer); -// TypeTableEntry *child_type = pointer_type->data.pointer.child_type; -// -// ConstExprValue *const_val = &get_resolved_expr(node)->const_val; -// const_val->ok = true; -// const_val->data.x_array.fields = allocate(elem_count); -// -// for (size_t i = 0; i < elem_count; i += 1) { -// AstNode **elem_node = &container_init_expr->entries.at(i); -// analyze_expression(g, import, context, child_type, *elem_node); -// -// if (const_val->ok) { -// ConstExprValue *elem_const_val = &get_resolved_expr(*elem_node)->const_val; -// if (elem_const_val->ok) { -// const_val->data.x_array.fields[i] = elem_const_val; -// const_val->depends_on_compile_var = const_val->depends_on_compile_var || -// elem_const_val->depends_on_compile_var; -// } else { -// const_val->ok = false; -// } -// } -// } -// -// TypeTableEntry *fixed_size_array_type = get_array_type(g, child_type, elem_count); -// -// StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr; -// codegen->type_entry = fixed_size_array_type; -// codegen->source_node = node; -// if (!const_val->ok) { -// if (!context->fn_entry) { -// add_node_error(g, node, -// buf_sprintf("unable to evaluate constant expression")); -// } else { -// context->fn_entry->struct_val_expr_alloca_list.append(codegen); -// } -// } -// -// return fixed_size_array_type; -// } else if (container_type->id == TypeTableEntryIdArray) { -// zig_panic("TODO array container init"); -// return container_type; -// } else if (container_type->id == TypeTableEntryIdVoid) { -// if (container_init_expr->entries.length != 0) { -// add_node_error(g, node, buf_sprintf("void expression expects no arguments")); -// return g->builtin_types.entry_invalid; -// } else { -// return resolve_expr_const_val_as_void(g, node); -// } -// } else { -// add_node_error(g, node, -// buf_sprintf("type '%s' does not support %s initialization syntax", -// buf_ptr(&container_type->name), err_container_init_syntax_name(kind))); -// return g->builtin_types.entry_invalid; -// } -//} - - - -//static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// assert(node->type == NodeTypeFieldAccessExpr); -// -// AstNode **struct_expr_node = &node->data.field_access_expr.struct_expr; -// TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, *struct_expr_node); -// Buf *field_name = node->data.field_access_expr.field_name; -// -// if (struct_type->id == TypeTableEntryIdInvalid) { -// return struct_type; -// } else if (is_container_ref(struct_type)) { -// return analyze_container_member_access(g, field_name, node, struct_type); -// } else if (struct_type->id == TypeTableEntryIdArray) { -// if (buf_eql_str(field_name, "len")) { -// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, -// struct_type->data.array.len, false); -// } else { -// add_node_error(g, node, -// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), -// buf_ptr(&struct_type->name))); -// return g->builtin_types.entry_invalid; -// } -// } else if (struct_type->id == TypeTableEntryIdMetaType) { -// TypeTableEntry *child_type = resolve_type(g, *struct_expr_node); -// -// if (child_type->id == TypeTableEntryIdInvalid) { -// return g->builtin_types.entry_invalid; -// } else if (child_type->id == TypeTableEntryIdEnum) { -// AstNode *container_init_node = node->data.field_access_expr.container_init_expr_node; -// AstNode *value_node; -// if (container_init_node) { -// assert(container_init_node->type == NodeTypeContainerInitExpr); -// size_t param_count = container_init_node->data.container_init_expr.entries.length; -// if (param_count > 1) { -// AstNode *first_invalid_node = container_init_node->data.container_init_expr.entries.at(1); -// add_node_error(g, first_executing_node(first_invalid_node), -// buf_sprintf("enum values accept only one parameter")); -// return child_type; -// } else { -// if (param_count == 1) { -// value_node = container_init_node->data.container_init_expr.entries.at(0); -// } else { -// value_node = nullptr; -// } -// container_init_node->data.container_init_expr.enum_type = child_type; -// } -// } else { -// value_node = nullptr; -// } -// return analyze_enum_value_expr(g, import, context, node, value_node, child_type, field_name, node); -// } else if (child_type->id == TypeTableEntryIdStruct) { -// BlockContext *container_block_context = get_container_block_context(child_type); -// auto entry = container_block_context->decl_table.maybe_get(field_name); -// AstNode *decl_node = entry ? entry->value : nullptr; -// if (decl_node) { -// bool pointer_only = false; -// return analyze_decl_ref(g, node, decl_node, pointer_only, context, false); -// } else { -// add_node_error(g, node, -// buf_sprintf("container '%s' has no member called '%s'", -// buf_ptr(&child_type->name), buf_ptr(field_name))); -// return g->builtin_types.entry_invalid; -// } -// } else if (child_type->id == TypeTableEntryIdPureError) { -// return analyze_error_literal_expr(g, import, context, node, field_name); -// } else if (child_type->id == TypeTableEntryIdInt) { -// bool depends_on_compile_var = -// get_resolved_expr(*struct_expr_node)->const_val.depends_on_compile_var; -// if (buf_eql_str(field_name, "bit_count")) { -// return resolve_expr_const_val_as_unsigned_num_lit(g, node, expected_type, -// child_type->data.integral.bit_count, depends_on_compile_var); -// } else if (buf_eql_str(field_name, "is_signed")) { -// return resolve_expr_const_val_as_bool(g, node, child_type->data.integral.is_signed, -// depends_on_compile_var); -// } else { -// add_node_error(g, node, -// buf_sprintf("type '%s' has no member called '%s'", -// buf_ptr(&child_type->name), buf_ptr(field_name))); -// return g->builtin_types.entry_invalid; -// } -// } else { -// add_node_error(g, node, -// buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); -// return g->builtin_types.entry_invalid; -// } -// } else { -// add_node_error(g, node, -// buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); -// return g->builtin_types.entry_invalid; -// } -//} -// -//static TypeTableEntry *bad_method_call(CodeGen *g, AstNode *node, TypeTableEntry *container_type, -// TypeTableEntry *expected_param_type, FnTableEntry *fn_table_entry) -//{ -// ErrorMsg *msg = add_node_error(g, node, -// buf_sprintf("function called as method of '%s', but first parameter is of type '%s'", -// buf_ptr(&container_type->name), -// buf_ptr(&expected_param_type->name))); -// if (fn_table_entry) { -// add_error_note(g, msg, fn_table_entry->proto_node, buf_sprintf("function declared here")); -// } -// return g->builtin_types.entry_invalid; -//} -// -//// Before calling this function, set node->data.fn_call_expr.fn_table_entry if the function is known -//// at compile time. Otherwise this is a function pointer call. -//static TypeTableEntry *analyze_fn_call_ptr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *fn_type, -// AstNode *struct_node) -//{ -// assert(node->type == NodeTypeFnCallExpr); -// -// if (fn_type->id == TypeTableEntryIdInvalid) { -// return fn_type; -// } -// -// // The function call might include inline parameters which we need to ignore according to the -// // fn_type. -// FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry; -// AstNode *generic_proto_node = fn_table_entry ? -// fn_table_entry->proto_node->data.fn_proto.generic_proto_node : nullptr; -// -// // count parameters -// size_t struct_node_1_or_0 = struct_node ? 1 : 0; -// size_t src_param_count = fn_type->data.fn.fn_type_id.param_count + -// (generic_proto_node ? generic_proto_node->data.fn_proto.inline_arg_count : 0); -// size_t call_param_count = node->data.fn_call_expr.params.length; -// size_t expect_arg_count = src_param_count - struct_node_1_or_0; -// -// bool ok_invocation = true; -// -// if (fn_type->data.fn.fn_type_id.is_var_args) { -// if (call_param_count < expect_arg_count) { -// ok_invocation = false; -// add_node_error(g, node, -// buf_sprintf("expected at least %zu arguments, found %zu", src_param_count, call_param_count)); -// } -// } else if (expect_arg_count != call_param_count) { -// ok_invocation = false; -// add_node_error(g, node, -// buf_sprintf("expected %zu arguments, found %zu", expect_arg_count, call_param_count)); -// } -// -// bool all_args_const_expr = true; -// -// if (struct_node) { -// Expr *struct_expr = get_resolved_expr(struct_node); -// ConstExprValue *struct_const_val = &struct_expr->const_val; -// if (!struct_const_val->ok) { -// all_args_const_expr = false; -// } -// -// FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[0]; -// TypeTableEntry *expected_param_type = param_info->type; -// TypeTableEntry *container_bare_type = container_ref_type(struct_expr->type_entry); -// if (is_container_ref(expected_param_type)) { -// TypeTableEntry *param_bare_type = container_ref_type(expected_param_type); -// if (param_bare_type != container_bare_type) { -// return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry); -// } -// } else { -// return bad_method_call(g, node, container_bare_type, expected_param_type, fn_table_entry); -// } -// } -// -// // analyze each parameter. in the case of a method, we already analyzed the -// // first parameter in order to figure out which struct we were calling a method on. -// size_t next_type_i = struct_node_1_or_0; -// for (size_t call_i = 0; call_i < call_param_count; call_i += 1) { -// size_t proto_i = call_i + struct_node_1_or_0; -// AstNode **param_node = &node->data.fn_call_expr.params.at(call_i); -// // determine the expected type for each parameter -// TypeTableEntry *expected_param_type = nullptr; -// if (proto_i < src_param_count) { -// if (generic_proto_node && -// generic_proto_node->data.fn_proto.params.at(proto_i)->data.param_decl.is_inline) -// { -// continue; -// } -// -// FnTypeParamInfo *param_info = &fn_type->data.fn.fn_type_id.param_info[next_type_i]; -// next_type_i += 1; -// -// expected_param_type = param_info->type; -// } -// TypeTableEntry *param_type = analyze_expression(g, import, context, expected_param_type, *param_node); -// if (param_type->id == TypeTableEntryIdInvalid) { -// return param_type; -// } -// -// ConstExprValue *const_arg_val = &get_resolved_expr(*param_node)->const_val; -// if (!const_arg_val->ok) { -// all_args_const_expr = false; -// } -// } -// -// TypeTableEntry *return_type = fn_type->data.fn.fn_type_id.return_type; -// -// if (return_type->id == TypeTableEntryIdInvalid) { -// return return_type; -// } -// -// ConstExprValue *result_val = &get_resolved_expr(node)->const_val; -// if (ok_invocation && fn_table_entry && fn_table_entry->is_pure && fn_table_entry->want_pure != WantPureFalse) { -// if (fn_table_entry->anal_state == FnAnalStateReady) { -// analyze_fn_body(g, fn_table_entry); -// if (fn_table_entry->proto_node->data.fn_proto.skip) { -// return g->builtin_types.entry_invalid; -// } -// } -// if (all_args_const_expr) { -// if (fn_table_entry->is_pure && fn_table_entry->anal_state == FnAnalStateComplete) { -// if (eval_fn(g, node, fn_table_entry, result_val, 1000, struct_node)) { -// // function evaluation generated an error -// return g->builtin_types.entry_invalid; -// } -// return return_type; -// } -// } -// } -// if (!ok_invocation || !fn_table_entry || !fn_table_entry->is_pure || fn_table_entry->want_pure == WantPureFalse) { -// // calling an impure fn is impure -// mark_impure_fn(g, context, node); -// if (fn_table_entry && fn_table_entry->want_pure == WantPureTrue) { -// return g->builtin_types.entry_invalid; -// } -// } -// -// // TODO -// //if (handle_is_ptr(return_type)) { -// // if (context->fn_entry) { -// // context->fn_entry->cast_alloca_list.append(node); -// // } else if (!result_val->ok) { -// // add_node_error(g, node, buf_sprintf("unable to evaluate constant expression")); -// // } -// //} -// -// return return_type; -//} -// -//static TypeTableEntry *analyze_fn_call_with_inline_args(CodeGen *g, ImportTableEntry *import, -// BlockContext *parent_context, TypeTableEntry *expected_type, AstNode *call_node, -// FnTableEntry *fn_table_entry, AstNode *struct_node) -//{ -// assert(call_node->type == NodeTypeFnCallExpr); -// assert(fn_table_entry); -// -// AstNode *decl_node = fn_table_entry->proto_node; -// -// // count parameters -// size_t struct_node_1_or_0 = (struct_node ? 1 : 0); -// size_t src_param_count = decl_node->data.fn_proto.params.length; -// size_t call_param_count = call_node->data.fn_call_expr.params.length; -// -// if (src_param_count != call_param_count + struct_node_1_or_0) { -// add_node_error(g, call_node, -// buf_sprintf("expected %zu arguments, found %zu", src_param_count - struct_node_1_or_0, call_param_count)); -// return g->builtin_types.entry_invalid; -// } -// -// size_t inline_or_var_type_arg_count = decl_node->data.fn_proto.inline_or_var_type_arg_count; -// assert(inline_or_var_type_arg_count > 0); -// -// BlockContext *child_context = decl_node->owner->block_context; -// size_t next_generic_param_index = 0; -// -// GenericFnTypeId *generic_fn_type_id = allocate(1); -// generic_fn_type_id->decl_node = decl_node; -// generic_fn_type_id->generic_param_count = inline_or_var_type_arg_count; -// generic_fn_type_id->generic_params = allocate(inline_or_var_type_arg_count); -// -// size_t next_impl_i = 0; -// for (size_t call_i = 0; call_i < call_param_count; call_i += 1) { -// size_t proto_i = call_i + struct_node_1_or_0; -// AstNode *generic_param_decl_node = decl_node->data.fn_proto.params.at(proto_i); -// assert(generic_param_decl_node->type == NodeTypeParamDecl); -// -// AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type; -// TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner, child_context, -// *generic_param_type_node); -// if (expected_param_type->id == TypeTableEntryIdInvalid) { -// return expected_param_type; -// } -// -// bool is_var_type = (expected_param_type->id == TypeTableEntryIdVar); -// bool is_inline = generic_param_decl_node->data.param_decl.is_inline; -// if (!is_inline && !is_var_type) { -// next_impl_i += 1; -// continue; -// } -// -// -// AstNode **param_node = &call_node->data.fn_call_expr.params.at(call_i); -// TypeTableEntry *param_type = analyze_expression(g, import, parent_context, -// is_var_type ? nullptr : expected_param_type, *param_node); -// if (param_type->id == TypeTableEntryIdInvalid) { -// return param_type; -// } -// -// // set child_context so that the previous param is in scope -// child_context = new_block_context(generic_param_decl_node, child_context); -// -// ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val; -// if (is_inline && !const_val->ok) { -// add_node_error(g, *param_node, -// buf_sprintf("unable to evaluate constant expression for inline parameter")); -// -// return g->builtin_types.entry_invalid; -// } -// -// VariableTableEntry *var = add_local_var_shadowable(g, generic_param_decl_node, decl_node->owner, child_context, -// generic_param_decl_node->data.param_decl.name, param_type, true, *param_node, true); -// // This generic function instance could be called with anything, so when this variable is read it -// // needs to know that it depends on compile time variable data. -// var->force_depends_on_compile_var = true; -// -// GenericParamValue *generic_param_value = -// &generic_fn_type_id->generic_params[next_generic_param_index]; -// generic_param_value->type = param_type; -// generic_param_value->node = is_inline ? *param_node : nullptr; -// generic_param_value->impl_index = next_impl_i; -// next_generic_param_index += 1; -// -// if (!is_inline) { -// next_impl_i += 1; -// } -// } -// -// assert(next_generic_param_index == inline_or_var_type_arg_count); -// -// auto entry = g->generic_table.maybe_get(generic_fn_type_id); -// FnTableEntry *impl_fn; -// if (entry) { -// AstNode *impl_decl_node = entry->value; -// assert(impl_decl_node->type == NodeTypeFnProto); -// impl_fn = impl_decl_node->data.fn_proto.fn_table_entry; -// } else { -// AstNode *decl_node = generic_fn_type_id->decl_node; -// AstNode *impl_fn_def_node = ast_clone_subtree_special(decl_node->data.fn_proto.fn_def_node, -// &g->next_node_index, AstCloneSpecialOmitInlineParams); -// AstNode *impl_decl_node = impl_fn_def_node->data.fn_def.fn_proto; -// impl_decl_node->data.fn_proto.inline_arg_count = 0; -// impl_decl_node->data.fn_proto.inline_or_var_type_arg_count = 0; -// impl_decl_node->data.fn_proto.generic_proto_node = decl_node; -// -// // replace var arg types with actual types -// for (size_t generic_arg_i = 0; generic_arg_i < inline_or_var_type_arg_count; generic_arg_i += 1) { -// GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[generic_arg_i]; -// if (!generic_param_value->node) { -// size_t impl_i = generic_param_value->impl_index; -// AstNode *impl_param_decl_node = impl_decl_node->data.fn_proto.params.at(impl_i); -// assert(impl_param_decl_node->type == NodeTypeParamDecl); -// -// impl_param_decl_node->data.param_decl.type = create_ast_type_node(g, import, -// generic_param_value->type, impl_param_decl_node); -// normalize_parent_ptrs(impl_param_decl_node); -// } -// } -// -// preview_fn_proto_instance(g, import, impl_decl_node, child_context); -// g->generic_table.put(generic_fn_type_id, impl_decl_node); -// impl_fn = impl_decl_node->data.fn_proto.fn_table_entry; -// } -// -// call_node->data.fn_call_expr.fn_entry = impl_fn; -// return analyze_fn_call_ptr(g, import, parent_context, expected_type, call_node, -// impl_fn->type_entry, struct_node); -//} -// -//static TypeTableEntry *analyze_generic_fn_call(CodeGen *g, ImportTableEntry *import, BlockContext *parent_context, -// TypeTableEntry *expected_type, AstNode *node, TypeTableEntry *generic_fn_type) -//{ -// assert(node->type == NodeTypeFnCallExpr); -// assert(generic_fn_type->id == TypeTableEntryIdGenericFn); -// -// AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node; -// assert(decl_node->type == NodeTypeContainerDecl); -// ZigList *generic_params = &decl_node->data.struct_decl.generic_params; -// -// size_t expected_param_count = generic_params->length; -// size_t actual_param_count = node->data.fn_call_expr.params.length; -// -// if (actual_param_count != expected_param_count) { -// add_node_error(g, first_executing_node(node), -// buf_sprintf("expected %zu arguments, found %zu", expected_param_count, actual_param_count)); -// return g->builtin_types.entry_invalid; -// } -// -// GenericFnTypeId *generic_fn_type_id = allocate(1); -// generic_fn_type_id->decl_node = decl_node; -// generic_fn_type_id->generic_param_count = actual_param_count; -// generic_fn_type_id->generic_params = allocate(actual_param_count); -// -// BlockContext *child_context = decl_node->owner->block_context; -// for (size_t i = 0; i < actual_param_count; i += 1) { -// AstNode *generic_param_decl_node = generic_params->at(i); -// assert(generic_param_decl_node->type == NodeTypeParamDecl); -// -// AstNode **generic_param_type_node = &generic_param_decl_node->data.param_decl.type; -// -// TypeTableEntry *expected_param_type = analyze_type_expr(g, decl_node->owner, -// child_context, *generic_param_type_node); -// if (expected_param_type->id == TypeTableEntryIdInvalid) { -// return expected_param_type; -// } -// -// -// -// AstNode **param_node = &node->data.fn_call_expr.params.at(i); -// -// TypeTableEntry *param_type = analyze_expression(g, import, parent_context, expected_param_type, -// *param_node); -// if (param_type->id == TypeTableEntryIdInvalid) { -// return param_type; -// } -// -// // set child_context so that the previous param is in scope -// child_context = new_block_context(generic_param_decl_node, child_context); -// -// ConstExprValue *const_val = &get_resolved_expr(*param_node)->const_val; -// if (const_val->ok) { -// VariableTableEntry *var = add_local_var(g, generic_param_decl_node, decl_node->owner, child_context, -// generic_param_decl_node->data.param_decl.name, param_type, true, *param_node); -// var->force_depends_on_compile_var = true; -// } else { -// add_node_error(g, *param_node, buf_sprintf("unable to evaluate constant expression")); -// -// return g->builtin_types.entry_invalid; -// } -// -// GenericParamValue *generic_param_value = &generic_fn_type_id->generic_params[i]; -// generic_param_value->type = param_type; -// generic_param_value->node = *param_node; -// } -// -// auto entry = g->generic_table.maybe_get(generic_fn_type_id); -// if (entry) { -// AstNode *impl_decl_node = entry->value; -// assert(impl_decl_node->type == NodeTypeContainerDecl); -// TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry; -// return resolve_expr_const_val_as_type(g, node, type_entry, false); -// } -// -// // make a type from the generic parameters supplied -// assert(decl_node->type == NodeTypeContainerDecl); -// AstNode *impl_decl_node = ast_clone_subtree(decl_node, &g->next_node_index); -// g->generic_table.put(generic_fn_type_id, impl_decl_node); -// scan_struct_decl(g, import, child_context, impl_decl_node); -// TypeTableEntry *type_entry = impl_decl_node->data.struct_decl.type_entry; -// resolve_struct_type(g, import, type_entry); -// return resolve_expr_const_val_as_type(g, node, type_entry, false); -//} -// -//static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; -// -// if (node->data.fn_call_expr.is_builtin) { -// zig_panic("moved builtin fn call code to ir.cpp"); -// } -// -// TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr); -// if (invoke_type_entry->id == TypeTableEntryIdInvalid) { -// return g->builtin_types.entry_invalid; -// } -// -// // use constant expression evaluator to figure out the function at compile time. -// // otherwise we treat this as a function pointer. -// ConstExprValue *const_val = &get_resolved_expr(fn_ref_expr)->const_val; -// -// if (const_val->ok) { -// if (invoke_type_entry->id == TypeTableEntryIdMetaType) { -// zig_unreachable(); -// } else if (invoke_type_entry->id == TypeTableEntryIdFn) { -// AstNode *struct_node; -// if (fn_ref_expr->type == NodeTypeFieldAccessExpr && -// fn_ref_expr->data.field_access_expr.is_member_fn) -// { -// struct_node = fn_ref_expr->data.field_access_expr.struct_expr; -// } else { -// struct_node = nullptr; -// } -// -// FnTableEntry *fn_table_entry = const_val->data.x_fn; -// node->data.fn_call_expr.fn_entry = fn_table_entry; -// return analyze_fn_call_ptr(g, import, context, expected_type, node, -// fn_table_entry->type_entry, struct_node); -// } else if (invoke_type_entry->id == TypeTableEntryIdGenericFn) { -// TypeTableEntry *generic_fn_type = const_val->data.x_type; -// AstNode *decl_node = generic_fn_type->data.generic_fn.decl_node; -// if (decl_node->type == NodeTypeFnProto) { -// AstNode *struct_node; -// if (fn_ref_expr->type == NodeTypeFieldAccessExpr && -// fn_ref_expr->data.field_access_expr.is_member_fn) -// { -// struct_node = fn_ref_expr->data.field_access_expr.struct_expr; -// } else { -// struct_node = nullptr; -// } -// -// FnTableEntry *fn_table_entry = decl_node->data.fn_proto.fn_table_entry; -// if (fn_table_entry->proto_node->data.fn_proto.skip) { -// return g->builtin_types.entry_invalid; -// } -// return analyze_fn_call_with_inline_args(g, import, context, expected_type, node, -// fn_table_entry, struct_node); -// } else { -// return analyze_generic_fn_call(g, import, context, expected_type, node, const_val->data.x_type); -// } -// } else { -// add_node_error(g, fn_ref_expr, -// buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name))); -// return g->builtin_types.entry_invalid; -// } -// } -// -// // function pointer -// if (invoke_type_entry->id == TypeTableEntryIdFn) { -// return analyze_fn_call_ptr(g, import, context, expected_type, node, invoke_type_entry, nullptr); -// } else { -// add_node_error(g, fn_ref_expr, -// buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name))); -// return g->builtin_types.entry_invalid; -// } -//} //static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, // TypeTableEntry *expected_type, AstNode *node) //{ @@ -7476,68 +7175,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // return enum_type; //} // -//static TypeTableEntry *analyze_container_member_access_inner(CodeGen *g, -// TypeTableEntry *bare_struct_type, Buf *field_name, AstNode *node, TypeTableEntry *struct_type) -//{ -// assert(node->type == NodeTypeFieldAccessExpr); -// if (!is_slice(bare_struct_type)) { -// BlockContext *container_block_context = get_container_block_context(bare_struct_type); -// assert(container_block_context); -// auto entry = container_block_context->decl_table.maybe_get(field_name); -// AstNode *fn_decl_node = entry ? entry->value : nullptr; -// if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) { -// resolve_top_level_decl(g, fn_decl_node, false); -// TopLevelDecl *tld = get_as_top_level_decl(fn_decl_node); -// if (tld->resolution == TldResolutionInvalid) { -// return g->builtin_types.entry_invalid; -// } -// -// node->data.field_access_expr.is_member_fn = true; -// FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry; -// if (fn_entry->type_entry->id == TypeTableEntryIdGenericFn) { -// return resolve_expr_const_val_as_generic_fn(g, node, fn_entry->type_entry, false); -// } else { -// return resolve_expr_const_val_as_fn(g, node, fn_entry, false); -// } -// } -// } -// add_node_error(g, node, -// buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), buf_ptr(&bare_struct_type->name))); -// return g->builtin_types.entry_invalid; -//} -// -//static TypeTableEntry *analyze_container_member_access(CodeGen *g, -// Buf *field_name, AstNode *node, TypeTableEntry *struct_type) -//{ -// TypeTableEntry *bare_type = container_ref_type(struct_type); -// if (!type_is_complete(bare_type)) { -// resolve_container_type(g, bare_type); -// } -// -// node->data.field_access_expr.bare_container_type = bare_type; -// -// if (bare_type->id == TypeTableEntryIdStruct) { -// node->data.field_access_expr.type_struct_field = find_struct_type_field(bare_type, field_name); -// if (node->data.field_access_expr.type_struct_field) { -// return node->data.field_access_expr.type_struct_field->type_entry; -// } else { -// return analyze_container_member_access_inner(g, bare_type, field_name, -// node, struct_type); -// } -// } else if (bare_type->id == TypeTableEntryIdEnum) { -// node->data.field_access_expr.type_enum_field = find_enum_type_field(bare_type, field_name); -// if (node->data.field_access_expr.type_enum_field) { -// return node->data.field_access_expr.type_enum_field->type_entry; -// } else { -// return analyze_container_member_access_inner(g, bare_type, field_name, -// node, struct_type); -// } -// } else if (bare_type->id == TypeTableEntryIdUnion) { -// zig_panic("TODO"); -// } else { -// zig_unreachable(); -// } -//} // //static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, // AstNode *node) @@ -7887,19 +7524,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // return g->builtin_types.entry_invalid; //} // -//static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// TypeTableEntry *type_entry = analyze_fn_proto_type(g, import, context, expected_type, node, -// false, false, nullptr); -// -// if (type_entry->id == TypeTableEntryIdInvalid) { -// return type_entry; -// } -// -// return resolve_expr_const_val_as_type(g, node, type_entry, false); -//} -// //static void validate_voided_expr(CodeGen *g, AstNode *source_node, TypeTableEntry *type_entry) { // if (type_entry->id == TypeTableEntryIdMetaType) { // add_node_error(g, first_executing_node(source_node), buf_sprintf("expected expression, found type")); @@ -8239,92 +7863,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // } //} // -//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(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); // @@ -8356,46 +7894,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // 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); // @@ -8771,87 +8269,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // 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_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) { // assert(block_node->type == NodeTypeBlock); // @@ -8876,140 +8293,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // } //} // -//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(); @@ -9164,44 +8447,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // } //} // -//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; diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 98ed8ebcc1..0eaf43993f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -7,6 +7,8 @@ struct IrPrint { int indent_size; }; +static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction); + static void ir_print_indent(IrPrint *irp) { for (int i = 0; i < irp->indent; i += 1) { fprintf(irp->f, " "); @@ -35,25 +37,30 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const break; } switch (type_entry->id) { + case TypeTableEntryIdTypeDecl: + return ir_print_const_value(irp, type_entry->data.type_decl.canonical_type, const_val); case TypeTableEntryIdInvalid: fprintf(irp->f, "(invalid)"); - break; + return; + case TypeTableEntryIdVar: + fprintf(irp->f, "(var)"); + return; case TypeTableEntryIdVoid: fprintf(irp->f, "{}"); - break; + return; case TypeTableEntryIdNumLitFloat: fprintf(irp->f, "%f", const_val->data.x_bignum.data.x_float); - break; + return; case TypeTableEntryIdNumLitInt: { BigNum *bignum = &const_val->data.x_bignum; const char *negative_str = bignum->is_negative ? "-" : ""; fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint); - break; + return; } case TypeTableEntryIdMetaType: fprintf(irp->f, "%s", buf_ptr(&const_val->data.x_type->name)); - break; + return; case TypeTableEntryIdInt: { BigNum *bignum = &const_val->data.x_bignum; @@ -61,31 +68,38 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const const char *negative_str = bignum->is_negative ? "-" : ""; fprintf(irp->f, "%s%llu", negative_str, bignum->data.x_uint); } - break; + return; + case TypeTableEntryIdFloat: + { + BigNum *bignum = &const_val->data.x_bignum; + assert(bignum->kind == BigNumKindFloat); + fprintf(irp->f, "%f", bignum->data.x_float); + } + return; case TypeTableEntryIdUnreachable: fprintf(irp->f, "@unreachable()"); - break; + return; case TypeTableEntryIdBool: { const char *value = const_val->data.x_bool ? "true" : "false"; fprintf(irp->f, "%s", value); - break; + return; } case TypeTableEntryIdPointer: fprintf(irp->f, "&"); ir_print_const_value(irp, type_entry->data.pointer.child_type, const_ptr_pointee(const_val)); - break; + return; case TypeTableEntryIdFn: { FnTableEntry *fn_entry = const_val->data.x_fn; fprintf(irp->f, "%s", buf_ptr(&fn_entry->symbol_name)); - break; + return; } case TypeTableEntryIdBlock: { AstNode *node = const_val->data.x_block->node; fprintf(irp->f, "(scope:%zu:%zu)", node->line + 1, node->column + 1); - break; + return; } case TypeTableEntryIdArray: { @@ -99,12 +113,17 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const ir_print_const_value(irp, child_type, child_value); } fprintf(irp->f, "}"); - break; + return; } case TypeTableEntryIdNullLit: { fprintf(irp->f, "null"); - break; + return; + } + case TypeTableEntryIdUndefLit: + { + fprintf(irp->f, "undefined"); + return; } case TypeTableEntryIdMaybe: { @@ -113,26 +132,56 @@ static void ir_print_const_value(IrPrint *irp, TypeTableEntry *type_entry, Const } else { fprintf(irp->f, "null"); } - break; + return; } case TypeTableEntryIdNamespace: { ImportTableEntry *import = const_val->data.x_import; fprintf(irp->f, "(namespace: %s)", buf_ptr(import->path)); - break; + return; } - case TypeTableEntryIdVar: - case TypeTableEntryIdFloat: - case TypeTableEntryIdStruct: - case TypeTableEntryIdUndefLit: - case TypeTableEntryIdErrorUnion: - case TypeTableEntryIdPureError: - case TypeTableEntryIdEnum: - case TypeTableEntryIdUnion: - case TypeTableEntryIdTypeDecl: case TypeTableEntryIdGenericFn: - zig_panic("TODO render more constant types in IR printer"); + { + TypeTableEntry *type_entry = const_val->data.x_type; + AstNode *decl_node = type_entry->data.generic_fn.decl_node; + assert(decl_node->type == NodeTypeFnProto); + fprintf(irp->f, "%s", buf_ptr(decl_node->data.fn_proto.name)); + return; + } + case TypeTableEntryIdBoundFn: + { + FnTableEntry *fn_entry = const_val->data.x_bound_fn.fn; + fprintf(irp->f, "bound %s to ", buf_ptr(&fn_entry->symbol_name)); + ir_print_other_instruction(irp, const_val->data.x_bound_fn.first_arg); + return; + } + case TypeTableEntryIdStruct: + { + fprintf(irp->f, "(struct %s constant)", buf_ptr(&type_entry->name)); + return; + } + case TypeTableEntryIdEnum: + { + fprintf(irp->f, "(enum %s constant)", buf_ptr(&type_entry->name)); + return; + } + case TypeTableEntryIdErrorUnion: + { + fprintf(irp->f, "(error union %s constant)", buf_ptr(&type_entry->name)); + return; + } + case TypeTableEntryIdUnion: + { + fprintf(irp->f, "(union %s constant)", buf_ptr(&type_entry->name)); + return; + } + case TypeTableEntryIdPureError: + { + fprintf(irp->f, "(pure error constant)"); + return; + } } + zig_unreachable(); } static void ir_print_const_instruction(IrPrint *irp, IrInstruction *instruction) { @@ -285,12 +334,16 @@ static void ir_print_decl_var(IrPrint *irp, IrInstructionDeclVar *decl_var_instr static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) { fprintf(irp->f, "cast "); ir_print_other_instruction(irp, cast_instruction->value); - fprintf(irp->f, " to "); - ir_print_other_instruction(irp, cast_instruction->dest_type); + fprintf(irp->f, " to %s", buf_ptr(&cast_instruction->dest_type->name)); } static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) { - ir_print_other_instruction(irp, call_instruction->fn); + if (call_instruction->fn_entry) { + fprintf(irp->f, "%s", buf_ptr(&call_instruction->fn_entry->symbol_name)); + } else { + assert(call_instruction->fn_ref); + ir_print_other_instruction(irp, call_instruction->fn_ref); + } fprintf(irp->f, "("); for (size_t i = 0; i < call_instruction->arg_count; i += 1) { IrInstruction *arg = call_instruction->args[i]; @@ -347,13 +400,24 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI ir_print_other_instruction(irp, instruction->container_type); fprintf(irp->f, "{"); for (size_t i = 0; i < instruction->field_count; i += 1) { - Buf *name = instruction->field_names[i]; - IrInstruction *field_value = instruction->field_values[i]; + IrInstructionContainerInitFieldsField *field = &instruction->fields[i]; const char *comma = (i == 0) ? "" : ", "; - fprintf(irp->f, "%s.%s = ", comma, buf_ptr(name)); - ir_print_other_instruction(irp, field_value); + fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name)); + ir_print_other_instruction(irp, field->value); } - fprintf(irp->f, "}"); + fprintf(irp->f, "} // container init"); +} + +static void ir_print_struct_init(IrPrint *irp, IrInstructionStructInit *instruction) { + fprintf(irp->f, "%s {", buf_ptr(&instruction->struct_type->name)); + for (size_t i = 0; i < instruction->field_count; i += 1) { + IrInstructionStructInitField *field = &instruction->fields[i]; + Buf *field_name = field->type_struct_field->name; + const char *comma = (i == 0) ? "" : ", "; + fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field_name)); + ir_print_other_instruction(irp, field->value); + } + fprintf(irp->f, "} // struct init"); } static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { @@ -406,10 +470,9 @@ static void ir_print_ptr_type_child(IrPrint *irp, IrInstructionPtrTypeChild *ins } static void ir_print_field_ptr(IrPrint *irp, IrInstructionFieldPtr *instruction) { - fprintf(irp->f, "@FieldPtr(&"); + fprintf(irp->f, "fieldptr "); ir_print_other_instruction(irp, instruction->container_ptr); fprintf(irp->f, ".%s", buf_ptr(instruction->field_name)); - fprintf(irp->f, ")"); } static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr *instruction) { @@ -419,6 +482,13 @@ static void ir_print_struct_field_ptr(IrPrint *irp, IrInstructionStructFieldPtr fprintf(irp->f, ")"); } +static void ir_print_enum_field_ptr(IrPrint *irp, IrInstructionEnumFieldPtr *instruction) { + fprintf(irp->f, "@EnumFieldPtr(&"); + ir_print_other_instruction(irp, instruction->enum_ptr); + fprintf(irp->f, ".%s", buf_ptr(instruction->field->name)); + fprintf(irp->f, ")"); +} + static void ir_print_set_fn_test(IrPrint *irp, IrInstructionSetFnTest *instruction) { fprintf(irp->f, "@setFnTest("); ir_print_other_instruction(irp, instruction->fn_value); @@ -632,6 +702,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdContainerInitFields: ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction); break; + case IrInstructionIdStructInit: + ir_print_struct_init(irp, (IrInstructionStructInit *)instruction); + break; case IrInstructionIdUnreachable: ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); break; @@ -662,6 +735,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdStructFieldPtr: ir_print_struct_field_ptr(irp, (IrInstructionStructFieldPtr *)instruction); break; + case IrInstructionIdEnumFieldPtr: + ir_print_enum_field_ptr(irp, (IrInstructionEnumFieldPtr *)instruction); + break; case IrInstructionIdSetFnTest: ir_print_set_fn_test(irp, (IrInstructionSetFnTest *)instruction); break; diff --git a/test/self_hosted2.zig b/test/self_hosted2.zig index 6b5d12ffd1..980e14d65c 100644 --- a/test/self_hosted2.zig +++ b/test/self_hosted2.zig @@ -84,6 +84,18 @@ end: } var goto_counter: i32 = 0; + + +struct FooA { + fn add(a: i32, b: i32) -> i32 { a + b } +} +const foo_a = FooA {}; + +fn testStructStatic() { + const result = FooA.add(3, 4); + assert(result == 7); +} + fn assert(ok: bool) { if (!ok) @unreachable(); @@ -98,6 +110,7 @@ fn runAllTests() { testInlineSwitch(); testNamespaceFnCall(); gotoAndLabels(); + testStructStatic(); } export nakedcc fn _start() -> unreachable {