From c19bdc2d370f3a72ef492e2f4e6264e2a0dd91ec Mon Sep 17 00:00:00 2001 From: Shawn Landden Date: Mon, 6 May 2019 11:41:15 -0500 Subject: stage1: add @hasField() built-in This was quite straight-forward Closes: #1439 --- src/codegen.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 7dfdf71725..1253a6a6af 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5530,6 +5530,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdByteOffsetOf: case IrInstructionIdBitOffsetOf: case IrInstructionIdTypeInfo: + case IrInstructionIdHasField: case IrInstructionIdTypeId: case IrInstructionIdSetEvalBranchQuota: case IrInstructionIdPtrType: @@ -7271,6 +7272,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdMemberName, "memberName", 2); create_builtin_fn(g, BuiltinFnIdField, "field", 2); create_builtin_fn(g, BuiltinFnIdTypeInfo, "typeInfo", 1); + create_builtin_fn(g, BuiltinFnIdHasField, "hasField", 2); create_builtin_fn(g, BuiltinFnIdTypeof, "typeOf", 1); // TODO rename to TypeOf create_builtin_fn(g, BuiltinFnIdAddWithOverflow, "addWithOverflow", 4); create_builtin_fn(g, BuiltinFnIdSubWithOverflow, "subWithOverflow", 4); -- cgit v1.2.3 From 9b7ad124810e4a3df964927ace449502daa167f9 Mon Sep 17 00:00:00 2001 From: Robert Scott Date: Thu, 9 May 2019 02:28:14 -0700 Subject: Implement @unionInit --- src/all_types.hpp | 13 ++++++ src/codegen.cpp | 2 + src/ir.cpp | 90 ++++++++++++++++++++++++++++++++++++++---- src/ir_print.cpp | 14 +++++++ test/stage1/behavior/union.zig | 37 ++++++++++++++++- 5 files changed, 148 insertions(+), 8 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 3b6ac32ea5..2dd70f64f1 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1471,6 +1471,7 @@ enum BuiltinFnId { BuiltinFnIdErrorReturnTrace, BuiltinFnIdAtomicRmw, BuiltinFnIdAtomicLoad, + BuiltinFnIdUnionInit, }; struct BuiltinFnEntry { @@ -2297,6 +2298,7 @@ enum IrInstructionId { IrInstructionIdArrayToVector, IrInstructionIdAssertZero, IrInstructionIdAssertNonNull, + IrInstructionIdUnionInit2, }; struct IrInstruction { @@ -3503,6 +3505,17 @@ struct IrInstructionAssertNonNull { IrInstruction *target; }; +// TODO, need a better name. Using 2 because there is currently a IrInstructionUnionInit +// It seems like the first one should only be used during the analyze phase, but still +// don't understand it all. +struct IrInstructionUnionInit2 { + IrInstruction base; + + IrInstruction *union_type_value; + IrInstruction *field_name_expr; + IrInstruction *value; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index 3a34894bb3..39a8c194ac 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5616,6 +5616,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdLoadPtr: case IrInstructionIdBitCast: case IrInstructionIdGlobalAsm: + case IrInstructionIdUnionInit2: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -7409,6 +7410,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1); create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); + create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3); } static const char *bool_to_str(bool b) { diff --git a/src/ir.cpp b/src/ir.cpp index 2d81f0c219..643f6845c6 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -188,7 +188,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c assert(get_src_ptr_type(const_val->type) != nullptr); assert(const_val->special == ConstValSpecialStatic); ConstExprValue *result; - + switch (type_has_one_possible_value(g, const_val->type->data.pointer.child_type)) { case OnePossibleValueInvalid: zig_unreachable(); @@ -200,7 +200,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c case OnePossibleValueNo: break; } - + switch (const_val->data.x_ptr.special) { case ConstPtrSpecialInvalid: zig_unreachable(); @@ -1011,6 +1011,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAssertNonNull *) return IrInstructionIdAssertNonNull; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit2 *) { + return IrInstructionIdUnionInit2; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -1312,6 +1316,7 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast return &instruction->base; } + static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator, @@ -3025,6 +3030,21 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, return &instruction->base; } +static IrInstruction *ir_build_union_init_2(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *union_type_value, IrInstruction *field_name_expr, IrInstruction *value) { + IrInstructionUnionInit2 *instruction = ir_build_instruction(irb, scope, source_node); + instruction->union_type_value = union_type_value; + instruction->field_name_expr = field_name_expr; + instruction->value = value; + + ir_ref_instruction(union_type_value, irb->current_basic_block); + ir_ref_instruction(field_name_expr, irb->current_basic_block); + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + + static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *vector, ZigType *result_type) { @@ -3868,7 +3888,7 @@ static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode TldVar *tld_var = allocate(1); init_tld(&tld_var->base, TldIdVar, var_name, VisibModPub, node, &scope_decls->base); tld_var->base.resolution = TldResolutionInvalid; - tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, + tld_var->var = add_variable(g, node, &scope_decls->base, var_name, false, &g->invalid_instruction->value, &tld_var->base, g->builtin_types.entry_invalid); scope_decls->decl_table.put(var_name, &tld_var->base); } @@ -5098,6 +5118,29 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } return ir_lval_wrap(irb, scope, result, lval); } + case BuiltinFnIdUnionInit: + { + + AstNode *arg0_node = node->data.fn_call_expr.params.at(0); + IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); + if (arg0_value == irb->codegen->invalid_instruction) + return arg0_value; + + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); + IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + if (arg1_value == irb->codegen->invalid_instruction) + return arg1_value; + + AstNode *arg2_node = node->data.fn_call_expr.params.at(2); + IrInstruction *arg2_value = ir_gen_node(irb, arg2_node, scope); + if (arg2_value == irb->codegen->invalid_instruction) + return arg2_value; + + IrInstruction *result = ir_build_union_init_2(irb, scope, node, arg0_value, arg1_value, arg2_value); + + // TODO: Not sure if we need ir_lval_wrap or not. + return result; + } } zig_unreachable(); } @@ -6328,7 +6371,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit prong_values, prong_values_len); var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); } else { - var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, + var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); } IrInstruction *var_type = nullptr; // infer the type @@ -12372,7 +12415,7 @@ static IrInstruction *ir_analyze_bin_op_cmp(IrAnalyze *ira, IrInstructionBinOp * } else { return is_non_null; } - } else if (is_equality_cmp && + } else if (is_equality_cmp && ((op1->value.type->id == ZigTypeIdNull && op2->value.type->id == ZigTypeIdPointer && op2->value.type->data.pointer.ptr_len == PtrLenC) || (op2->value.type->id == ZigTypeIdNull && op1->value.type->id == ZigTypeIdPointer && @@ -19383,7 +19426,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct ir_add_error_node(ira, node, buf_sprintf("C import failed: unable to make dir: %s", err_str(err))); return ira->codegen->invalid_instruction; } - + if ((err = os_write_file(&tmp_c_file_path, &cimport_scope->buf))) { ir_add_error_node(ira, node, buf_sprintf("C import failed: unable to write .h file: %s", err_str(err))); return ira->codegen->invalid_instruction; @@ -20333,7 +20376,7 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio return ira->codegen->invalid_instruction; // TODO test this at comptime with u8 and non-u8 types - // TODO test with dest ptr being a global runtime variable + // TODO test with dest ptr being a global runtime variable if (casted_dest_ptr->value.special == ConstValSpecialStatic && casted_src_ptr->value.special == ConstValSpecialStatic && casted_count->value.special == ConstValSpecialStatic && @@ -23151,6 +23194,35 @@ static IrInstruction *ir_analyze_instruction_check_runtime_scope(IrAnalyze *ira, return ir_const_void(ira, &instruction->base); } +static IrInstruction *ir_analyze_instruction_union_init_2(IrAnalyze *ira, IrInstructionUnionInit2 *union_init_instruction) +{ + Error err; + IrInstruction *union_type_value = union_init_instruction->union_type_value->child; + ZigType *union_type = ir_resolve_type(ira, union_type_value); + if (type_is_invalid(union_type)) { + return ira->codegen->invalid_instruction; + } + + if (union_type->id != ZigTypeIdUnion) + return ira->codegen->invalid_instruction; + + if ((err = ensure_complete_type(ira->codegen, union_type))) + return ira->codegen->invalid_instruction; + + IrInstruction *field_name_expr = union_init_instruction->field_name_expr->child; + Buf *field_name = ir_resolve_str(ira, field_name_expr); + if (!field_name) + return ira->codegen->invalid_instruction; + + IrInstructionContainerInitFieldsField *fields = allocate(1); + + fields[0].name = field_name; + fields[0].value = union_init_instruction->value; + fields[0].source_node = union_init_instruction->base.source_node; + + return ir_analyze_container_init_fields_union(ira, &union_init_instruction->base, union_type, 1, fields); +} + static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -23445,6 +23517,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_enum_to_int(ira, (IrInstructionEnumToInt *)instruction); case IrInstructionIdCheckRuntimeScope: return ir_analyze_instruction_check_runtime_scope(ira, (IrInstructionCheckRuntimeScope *)instruction); + case IrInstructionIdUnionInit2: + return ir_analyze_instruction_union_init_2(ira, (IrInstructionUnionInit2 *)instruction); } zig_unreachable(); } @@ -23681,6 +23755,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdEnumToInt: case IrInstructionIdVectorToArray: case IrInstructionIdArrayToVector: + case IrInstructionIdUnionInit2: + return false; case IrInstructionIdAsm: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index d38b552749..6d98580d02 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1453,6 +1453,17 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_va } } + +static void ir_print_uniont_init_2(IrPrint *irp, IrInstructionUnionInit2 *instruction) { + fprintf(irp->f, "@unionInit("); + ir_print_other_instruction(irp, instruction->union_type_value); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->field_name_expr); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1920,6 +1931,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdResizeSlice: ir_print_resize_slice(irp, (IrInstructionResizeSlice *)instruction); break; + case IrInstructionIdUnionInit2: + ir_print_uniont_init_2(irp, (IrInstructionUnionInit2 *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index b8bb9a51b8..be96b659f6 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -374,7 +374,7 @@ const Attribute = union(enum) { fn setAttribute(attr: Attribute) void {} fn Setter(attr: Attribute) type { - return struct{ + return struct { fn set() void { setAttribute(attr); } @@ -402,3 +402,38 @@ test "comptime union field value equality" { expect(a0 != a1); expect(b0 != b1); } + +test "unionInit can modify a union type" { + const UnionInitEnum = union(enum) { + Boolean: bool, + Byte: u8, + }; + + var value: UnionInitEnum = undefined; + + value = @unionInit(UnionInitEnum, "Boolean", true); + expect(value.Boolean == true); + value.Boolean = false; + expect(value.Boolean == false); + + value = @unionInit(UnionInitEnum, "Byte", 2); + expect(value.Byte == 2); + value.Byte = 3; + expect(value.Byte == 3); +} + +test "unionInit can modify a pointer value" { + const UnionInitEnum = union(enum) { + Boolean: bool, + Byte: u8, + }; + + var value: UnionInitEnum = undefined; + var value_ptr = &value; + + value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true); + expect(value.Boolean == true); + + value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2); + expect(value.Byte == 2); +} -- cgit v1.2.3 From 5e1003bc81466b8ca0e3a3adb613bac8f34f2712 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 1 May 2019 01:56:06 -0400 Subject: no-copy semantics for basic runtime function call variable init ```zig export fn entry() void { var x: Foo = foo(); } ``` ```llvm define void @entry() #2 !dbg !37 { Entry: %x = alloca %Foo, align 4 call fastcc void @foo(%Foo* sret %x), !dbg !48 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !41, metadata !DIExpression()), !dbg !49 ret void, !dbg !50 } ``` --- BRANCH_TODO | 10 ++ CMakeLists.txt | 1 + src/all_types.hpp | 82 ++++++++++- src/codegen.cpp | 90 +++++++----- src/ir.cpp | 401 ++++++++++++++++++++++++++++++++++++++++-------------- src/ir_print.cpp | 88 +++++++++++- 6 files changed, 521 insertions(+), 151 deletions(-) create mode 100644 BRANCH_TODO (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO new file mode 100644 index 0000000000..294d3e677f --- /dev/null +++ b/BRANCH_TODO @@ -0,0 +1,10 @@ +Scratch pad for stuff to do before merging master +================================================= + +look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated + +migrate all the alloca_list to alloca_gen_list + +migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize + +inferred comptime diff --git a/CMakeLists.txt b/CMakeLists.txt index 1ff4cebf40..8e4b8e8c0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -6728,6 +6728,7 @@ add_custom_command( "-Doutput-dir=${CMAKE_BINARY_DIR}" WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" DEPENDS + zig0 "${CMAKE_SOURCE_DIR}/src-self-hosted/dep_tokenizer.zig" "${CMAKE_SOURCE_DIR}/src-self-hosted/stage1.zig" "${CMAKE_SOURCE_DIR}/src-self-hosted/translate_c.zig" diff --git a/src/all_types.hpp b/src/all_types.hpp index 2a6bb1feb5..ae8d9c3fb8 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -34,12 +34,14 @@ struct CodeGen; struct ConstExprValue; struct IrInstruction; struct IrInstructionCast; +struct IrInstructionAllocaGen; struct IrBasicBlock; struct ScopeDecls; struct ZigWindowsSDK; struct Tld; struct TldExport; struct IrAnalyze; +struct ResultLoc; enum X64CABIClass { X64CABIClass_Unknown, @@ -1359,6 +1361,7 @@ struct ZigFn { AstNode *fn_static_eval_set_node; ZigList alloca_list; + ZigList alloca_gen_list; ZigList variable_list; Buf *section_name; @@ -2171,7 +2174,9 @@ enum IrInstructionId { IrInstructionIdUnionFieldPtr, IrInstructionIdElemPtr, IrInstructionIdVarPtr, - IrInstructionIdCall, + IrInstructionIdReturnPtr, + IrInstructionIdCallSrc, + IrInstructionIdCallGen, IrInstructionIdConst, IrInstructionIdReturn, IrInstructionIdCast, @@ -2308,6 +2313,8 @@ enum IrInstructionId { IrInstructionIdAssertNonNull, IrInstructionIdHasDecl, IrInstructionIdUndeclaredIdent, + IrInstructionIdAllocaSrc, + IrInstructionIdAllocaGen, }; struct IrInstruction { @@ -2335,14 +2342,14 @@ struct IrInstructionDeclVarSrc { ZigVar *var; IrInstruction *var_type; IrInstruction *align_value; - IrInstruction *init_value; + IrInstruction *ptr; }; struct IrInstructionDeclVarGen { IrInstruction base; ZigVar *var; - IrInstruction *init_value; + IrInstruction *var_ptr; }; struct IrInstructionCondBr { @@ -2528,14 +2535,21 @@ struct IrInstructionVarPtr { ScopeFnDef *crossed_fndef_scope; }; -struct IrInstructionCall { +// For functions that have a return type for which handle_is_ptr is true, a +// result location pointer is the secret first parameter ("sret"). This +// instruction returns that pointer. +struct IrInstructionReturnPtr { + IrInstruction base; +}; + +struct IrInstructionCallSrc { IrInstruction base; IrInstruction *fn_ref; ZigFn *fn_entry; size_t arg_count; IrInstruction **args; - LLVMValueRef tmp_ptr; + ResultLoc *result_loc; IrInstruction *async_allocator; IrInstruction *new_stack; @@ -2544,6 +2558,21 @@ struct IrInstructionCall { bool is_comptime; }; +struct IrInstructionCallGen { + IrInstruction base; + + IrInstruction *fn_ref; + ZigFn *fn_entry; + size_t arg_count; + IrInstruction **args; + IrInstruction *result_loc; + + IrInstruction *async_allocator; + IrInstruction *new_stack; + FnInline fn_inline; + bool is_async; +}; + struct IrInstructionConst { IrInstruction base; }; @@ -3527,6 +3556,47 @@ struct IrInstructionUndeclaredIdent { Buf *name; }; +struct IrInstructionAllocaSrc { + IrInstruction base; + + IrInstruction *align; + IrInstruction *is_comptime; + const char *name_hint; +}; + +struct IrInstructionAllocaGen { + IrInstruction base; + + uint32_t align; + const char *name_hint; +}; + +enum ResultLocId { + ResultLocIdInvalid, + ResultLocIdNone, + ResultLocIdVar, + ResultLocIdReturn, +}; + +struct ResultLoc { + ResultLocId id; + IrInstruction *source_instruction; +}; + +struct ResultLocNone { + ResultLoc base; +}; + +struct ResultLocVar { + ResultLoc base; + + ZigVar *var; +}; + +struct ResultLocReturn { + ResultLoc base; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; @@ -3574,7 +3644,7 @@ struct FnWalkAttrs { struct FnWalkCall { ZigList *gen_param_values; - IrInstructionCall *inst; + IrInstructionCallGen *inst; bool is_var_args; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index 826a9463ac..2cb3584e68 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1982,6 +1982,7 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, LLVMValueRef ptr, ZigType *ptr_ty } static void gen_var_debug_decl(CodeGen *g, ZigVar *var) { + if (g->strip_debug_symbols) return; assert(var->di_loc_var != nullptr); AstNode *source_node = var->decl_node; ZigLLVMDILocation *debug_loc = ZigLLVMGetDebugLoc((unsigned)source_node->line + 1, @@ -2288,7 +2289,7 @@ void walk_function_params(CodeGen *g, ZigType *fn_type, FnWalk *fn_walk) { return; } if (fn_walk->id == FnWalkIdCall) { - IrInstructionCall *instruction = fn_walk->data.call.inst; + IrInstructionCallGen *instruction = fn_walk->data.call.inst; bool is_var_args = fn_walk->data.call.is_var_args; for (size_t call_i = 0; call_i < instruction->arg_count; call_i += 1) { IrInstruction *param_instruction = instruction->args[call_i]; @@ -3328,10 +3329,8 @@ static LLVMValueRef ir_render_bool_not(CodeGen *g, IrExecutable *executable, IrI return LLVMBuildICmp(g->builder, LLVMIntEQ, value, zero, ""); } -static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, - IrInstructionDeclVarGen *decl_var_instruction) -{ - ZigVar *var = decl_var_instruction->var; +static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrInstructionDeclVarGen *instruction) { + ZigVar *var = instruction->var; if (!type_has_bits(var->var_type)) return nullptr; @@ -3339,20 +3338,7 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, if (var->ref_count == 0 && g->build_mode != BuildModeDebug) return nullptr; - IrInstruction *init_value = decl_var_instruction->init_value; - - bool have_init_expr = !value_is_all_undef(&init_value->value); - - if (have_init_expr) { - ZigType *var_ptr_type = get_pointer_to_type_extra(g, var->var_type, false, false, - PtrLenSingle, var->align_bytes, 0, 0, false); - LLVMValueRef llvm_init_val = ir_llvm_value(g, init_value); - gen_assign_raw(g, var->value_ref, var_ptr_type, llvm_init_val); - } else if (ir_want_runtime_safety(g, &decl_var_instruction->base)) { - uint32_t align_bytes = (var->align_bytes == 0) ? get_abi_alignment(g, var->var_type) : var->align_bytes; - gen_undef_init(g, align_bytes, var->var_type, var->value_ref); - } - + var->value_ref = ir_llvm_value(g, instruction->var_ptr); gen_var_debug_decl(g, var); return nullptr; } @@ -3568,6 +3554,13 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn } } +static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, + IrInstructionReturnPtr *instruction) +{ + assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type)); + return g->cur_ret_ptr; +} + static LLVMValueRef ir_render_elem_ptr(CodeGen *g, IrExecutable *executable, IrInstructionElemPtr *instruction) { LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->array_ptr); ZigType *array_ptr_type = instruction->array_ptr->value.type; @@ -3719,7 +3712,7 @@ static void set_call_instr_sret(CodeGen *g, LLVMValueRef call_instr) { LLVMAddCallSiteAttribute(call_instr, 1, sret_attr); } -static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCall *instruction) { +static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstructionCallGen *instruction) { LLVMValueRef fn_val; ZigType *fn_type; if (instruction->fn_entry) { @@ -3742,8 +3735,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id); bool is_var_args = fn_type_id->is_var_args; ZigList gen_param_values = {}; + LLVMValueRef result_loc = first_arg_ret ? ir_llvm_value(g, instruction->result_loc) : nullptr; if (first_arg_ret) { - gen_param_values.append(instruction->tmp_ptr); + gen_param_values.append(result_loc); } if (prefix_arg_err_ret_stack) { gen_param_values.append(get_cur_err_ret_trace_val(g, instruction->base.scope)); @@ -3751,7 +3745,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr if (instruction->is_async) { gen_param_values.append(ir_llvm_value(g, instruction->async_allocator)); - LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_err_index, ""); gen_param_values.append(err_val_ptr); } FnWalk fn_walk = {}; @@ -3794,9 +3788,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr if (instruction->is_async) { - LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); + LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_payload_index, ""); LLVMBuildStore(g->builder, result, payload_ptr); - return instruction->tmp_ptr; + return result_loc; } if (src_return_type->id == ZigTypeIdUnreachable) { @@ -3805,11 +3799,11 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr return nullptr; } else if (first_arg_ret) { set_call_instr_sret(g, result); - return instruction->tmp_ptr; + return result_loc; } else if (handle_is_ptr(src_return_type)) { - auto store_instr = LLVMBuildStore(g->builder, result, instruction->tmp_ptr); - LLVMSetAlignment(store_instr, LLVMGetAlignment(instruction->tmp_ptr)); - return instruction->tmp_ptr; + LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc); + LLVMSetAlignment(store_instr, LLVMGetAlignment(result_loc)); + return result_loc; } else { return result; } @@ -5535,7 +5529,9 @@ static void set_debug_location(CodeGen *g, IrInstruction *instruction) { } static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { - set_debug_location(g, instruction); + if (!g->strip_debug_symbols) { + set_debug_location(g, instruction); + } switch (instruction->id) { case IrInstructionIdInvalid: @@ -5608,8 +5604,13 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdGlobalAsm: case IrInstructionIdHasDecl: case IrInstructionIdUndeclaredIdent: + case IrInstructionIdCallSrc: + case IrInstructionIdAllocaSrc: zig_unreachable(); + case IrInstructionIdAllocaGen: + return nullptr; + case IrInstructionIdDeclVarGen: return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); case IrInstructionIdReturn: @@ -5632,10 +5633,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_store_ptr(g, executable, (IrInstructionStorePtr *)instruction); case IrInstructionIdVarPtr: return ir_render_var_ptr(g, executable, (IrInstructionVarPtr *)instruction); + case IrInstructionIdReturnPtr: + return ir_render_return_ptr(g, executable, (IrInstructionReturnPtr *)instruction); case IrInstructionIdElemPtr: return ir_render_elem_ptr(g, executable, (IrInstructionElemPtr *)instruction); - case IrInstructionIdCall: - return ir_render_call(g, executable, (IrInstructionCall *)instruction); + case IrInstructionIdCallGen: + return ir_render_call(g, executable, (IrInstructionCallGen *)instruction); case IrInstructionIdStructFieldPtr: return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); case IrInstructionIdUnionFieldPtr: @@ -6851,6 +6854,26 @@ static void do_code_gen(CodeGen *g) { } // allocate temporary stack data + for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) { + IrInstructionAllocaGen *instruction = fn_table_entry->alloca_gen_list.at(alloca_i); + ZigType *ptr_type = instruction->base.value.type; + assert(ptr_type->id == ZigTypeIdPointer); + ZigType *child_type = ptr_type->data.pointer.child_type; + if (!type_has_bits(child_type)) + continue; + if (instruction->base.ref_count == 0) + continue; + if (instruction->base.value.special != ConstValSpecialRuntime) { + if (const_ptr_pointee(nullptr, g, &instruction->base.value, nullptr)->special != + ConstValSpecialRuntime) + { + continue; + } + } + instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint, + get_ptr_align(g, ptr_type)); + } + for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) { IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); LLVMValueRef *slot; @@ -6873,9 +6896,6 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdUnionInit) { IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction; slot = &union_init_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdCall) { - IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; - slot = &call_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdSlice) { IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; slot = &slice_instruction->tmp_ptr; @@ -6939,8 +6959,6 @@ static void do_code_gen(CodeGen *g) { } if (var->src_arg_index == SIZE_MAX) { - var->value_ref = build_alloca(g, var->var_type, buf_ptr(&var->name), var->align_bytes); - var->di_loc_var = ZigLLVMCreateAutoVariable(g->dbuilder, get_di_scope(g, var->parent_scope), buf_ptr(&var->name), import->data.structure.root_struct->di_file, (unsigned)(var->decl_node->line + 1), get_llvm_di_type(g, var->var_type), !g->strip_debug_symbols, 0); diff --git a/src/ir.cpp b/src/ir.cpp index fb9e7b51c7..5b6ce22620 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -157,7 +157,8 @@ enum UndefAllowed { }; static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); -static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval); +static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, + ResultLoc *result_loc); static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type); static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr); @@ -475,8 +476,16 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionVarPtr *) { return IrInstructionIdVarPtr; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionCall *) { - return IrInstructionIdCall; +static constexpr IrInstructionId ir_instruction_id(IrInstructionReturnPtr *) { + return IrInstructionIdReturnPtr; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionCallSrc *) { + return IrInstructionIdCallSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionCallGen *) { + return IrInstructionIdCallGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionConst *) { @@ -1019,6 +1028,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionUndeclaredIdent return IrInstructionIdUndeclaredIdent; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaSrc *) { + return IrInstructionIdAllocaSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaGen *) { + return IrInstructionIdAllocaGen; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -1254,6 +1271,13 @@ static IrInstruction *ir_build_var_ptr(IrBuilder *irb, Scope *scope, AstNode *so return ir_build_var_ptr_x(irb, scope, source_node, var, nullptr); } +static IrInstruction *ir_build_return_ptr(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) { + IrInstructionReturnPtr *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ty; + return &instruction->base; +} + static IrInstruction *ir_build_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr, IrInstruction *elem_index, bool safety_check_on, PtrLen ptr_len) { @@ -1320,12 +1344,12 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast return &instruction->base; } -static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *source_node, +static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, bool is_comptime, FnInline fn_inline, bool is_async, IrInstruction *async_allocator, - IrInstruction *new_stack) + IrInstruction *new_stack, ResultLoc *result_loc) { - IrInstructionCall *call_instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionCallSrc *call_instruction = ir_build_instruction(irb, scope, source_node); call_instruction->fn_entry = fn_entry; call_instruction->fn_ref = fn_ref; call_instruction->is_comptime = is_comptime; @@ -1335,6 +1359,7 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc call_instruction->is_async = is_async; call_instruction->async_allocator = async_allocator; call_instruction->new_stack = new_stack; + call_instruction->result_loc = result_loc; if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); for (size_t i = 0; i < arg_count; i += 1) @@ -1345,6 +1370,33 @@ static IrInstruction *ir_build_call(IrBuilder *irb, Scope *scope, AstNode *sourc return &call_instruction->base; } +static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, + ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, + FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *new_stack, + IrInstruction *result_loc) +{ + IrInstructionCallGen *call_instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + call_instruction->fn_entry = fn_entry; + call_instruction->fn_ref = fn_ref; + call_instruction->fn_inline = fn_inline; + call_instruction->args = args; + call_instruction->arg_count = arg_count; + call_instruction->is_async = is_async; + call_instruction->async_allocator = async_allocator; + call_instruction->new_stack = new_stack; + call_instruction->result_loc = result_loc; + + if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block); + for (size_t i = 0; i < arg_count; i += 1) + ir_ref_instruction(args[i], ira->new_irb.current_basic_block); + if (async_allocator != nullptr) ir_ref_instruction(async_allocator, ira->new_irb.current_basic_block); + if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + + return &call_instruction->base; +} + static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source_node, size_t incoming_count, IrBasicBlock **incoming_blocks, IrInstruction **incoming_values) { @@ -1511,7 +1563,7 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode * } static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *init_value) + ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *ptr) { IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction(irb, scope, source_node); decl_var_instruction->base.value.special = ConstValSpecialStatic; @@ -1519,26 +1571,26 @@ static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNod decl_var_instruction->var = var; decl_var_instruction->var_type = var_type; decl_var_instruction->align_value = align_value; - decl_var_instruction->init_value = init_value; + decl_var_instruction->ptr = ptr; if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block); if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); - ir_ref_instruction(init_value, irb->current_basic_block); + ir_ref_instruction(ptr, irb->current_basic_block); return &decl_var_instruction->base; } static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *source_instruction, - ZigVar *var, IrInstruction *init_value) + ZigVar *var, IrInstruction *var_ptr) { IrInstructionDeclVarGen *decl_var_instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); decl_var_instruction->base.value.special = ConstValSpecialStatic; decl_var_instruction->base.value.type = ira->codegen->builtin_types.entry_void; decl_var_instruction->var = var; - decl_var_instruction->init_value = init_value; + decl_var_instruction->var_ptr = var_ptr; - ir_ref_instruction(init_value, ira->new_irb.current_basic_block); + ir_ref_instruction(var_ptr, ira->new_irb.current_basic_block); return &decl_var_instruction->base; } @@ -3109,6 +3161,32 @@ static IrInstruction *ir_build_assert_non_null(IrAnalyze *ira, IrInstruction *so return &instruction->base; } +static IrInstruction *ir_build_alloca_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *align, const char *name_hint, IrInstruction *is_comptime) +{ + IrInstructionAllocaSrc *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base.is_gen = true; + instruction->align = align; + instruction->name_hint = name_hint; + instruction->is_comptime = is_comptime; + + if (align != nullptr) ir_ref_instruction(align, irb->current_basic_block); + if (is_comptime != nullptr) ir_ref_instruction(is_comptime, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstruction *source_instruction, + uint32_t align, const char *name_hint) +{ + IrInstructionAllocaGen *instruction = ir_create_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->align = align; + instruction->name_hint = name_hint; + + return instruction; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -3321,12 +3399,15 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, switch (node->data.return_expr.kind) { case ReturnKindUnconditional: { + ResultLocReturn *result_loc_ret = allocate(1); + result_loc_ret->base.id = ResultLocIdReturn; + IrInstruction *return_value; if (expr_node) { // Temporarily set this so that if we return a type it gets the name of the function ZigFn *prev_name_fn = irb->exec->name_fn; irb->exec->name_fn = exec_fn_entry(irb->exec); - return_value = ir_gen_node(irb, expr_node, scope); + return_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, &result_loc_ret->base); irb->exec->name_fn = prev_name_fn; if (return_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -3373,17 +3454,21 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, ir_build_br(irb, scope, node, ret_stmt_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ret_stmt_block); - return ir_gen_async_return(irb, scope, node, return_value, false); + IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false); + result_loc_ret->base.source_instruction = result; + return result; } else { // generate unconditional defers ir_gen_defers_for_block(irb, scope, outer_scope, false); - return ir_gen_async_return(irb, scope, node, return_value, false); + IrInstruction *result = ir_gen_async_return(irb, scope, node, return_value, false); + result_loc_ret->base.source_instruction = result; + return result; } } case ReturnKindError: { assert(expr_node); - IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); + IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr); @@ -3592,7 +3677,7 @@ static IrInstruction *ir_gen_bin_op_id(IrBuilder *irb, Scope *scope, AstNode *no } static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) { - IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr); + IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr); IrInstruction *rvalue = ir_gen_node(irb, node->data.bin_op_expr.op2, scope); if (lvalue == irb->codegen->invalid_instruction || rvalue == irb->codegen->invalid_instruction) @@ -3603,7 +3688,7 @@ static IrInstruction *ir_gen_assign(IrBuilder *irb, Scope *scope, AstNode *node) } static IrInstruction *ir_gen_assign_op(IrBuilder *irb, Scope *scope, AstNode *node, IrBinOp op_id) { - IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr); + IrInstruction *lvalue = ir_gen_node_extra(irb, node->data.bin_op_expr.op1, scope, LValPtr, nullptr); if (lvalue == irb->codegen->invalid_instruction) return lvalue; IrInstruction *op1 = ir_build_load_ptr(irb, scope, node->data.bin_op_expr.op1, lvalue); @@ -3705,7 +3790,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode AstNode *op1_node = node->data.bin_op_expr.op1; AstNode *op2_node = node->data.bin_op_expr.op2; - IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr); + IrInstruction *maybe_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr, nullptr); if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -3968,7 +4053,7 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode assert(node->type == NodeTypeArrayAccessExpr); AstNode *array_ref_node = node->data.array_access_expr.array_ref_expr; - IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPtr); + IrInstruction *array_ref_instruction = ir_gen_node_extra(irb, array_ref_node, scope, LValPtr, nullptr); if (array_ref_instruction == irb->codegen->invalid_instruction) return array_ref_instruction; @@ -3991,7 +4076,7 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode AstNode *container_ref_node = node->data.field_access_expr.struct_expr; Buf *field_name = node->data.field_access_expr.field_name; - IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPtr); + IrInstruction *container_ref_instruction = ir_gen_node_extra(irb, container_ref_node, scope, LValPtr, nullptr); if (container_ref_instruction == irb->codegen->invalid_instruction) return container_ref_instruction; @@ -4041,7 +4126,9 @@ static IrInstruction *ir_gen_this(IrBuilder *irb, Scope *orig_scope, AstNode *no zig_unreachable(); } -static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeFnCallExpr); AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; @@ -4625,7 +4712,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo case BuiltinFnIdField: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LValPtr); + IrInstruction *arg0_value = ir_gen_node_extra(irb, arg0_node, scope, LValPtr, nullptr); if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; @@ -4855,7 +4942,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; - IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr); + IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, + fn_inline, false, nullptr, nullptr, result_loc); return ir_lval_wrap(irb, scope, call, lval); } case BuiltinFnIdNewStackCall: @@ -4885,7 +4973,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return args[i]; } - IrInstruction *call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack); + IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, + FnInlineAuto, false, nullptr, new_stack, result_loc); return ir_lval_wrap(irb, scope, call, lval); } case BuiltinFnIdTypeId: @@ -5148,11 +5237,13 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo zig_unreachable(); } -static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeFnCallExpr); if (node->data.fn_call_expr.is_builtin) - return ir_gen_builtin_fn_call(irb, scope, node, lval); + return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc); AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); @@ -5178,8 +5269,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node } } - IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, - is_async, async_allocator, nullptr); + IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, + is_async, async_allocator, nullptr, result_loc); return ir_lval_wrap(irb, scope, fn_call, lval); } @@ -5244,7 +5335,7 @@ static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, Ast assert(node->type == NodeTypePrefixOpExpr); AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval); + IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval, nullptr); if (value == irb->codegen->invalid_instruction) return value; @@ -5339,7 +5430,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, LVal lval) { - IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); + IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -5384,7 +5475,7 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval); case PrefixOpAddrOf: { AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr), lval); + return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr), lval); } } zig_unreachable(); @@ -5486,17 +5577,27 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod // Parser should ensure that this never happens assert(variable_declaration->threadlocal_tok == nullptr); + IrInstruction *alloca = ir_build_alloca_src(irb, scope, node, align_value, + buf_ptr(variable_declaration->symbol), is_comptime); + + // Create a result location for the initialization expression. + ResultLocVar *result_loc_var = allocate(1); + result_loc_var->base.id = ResultLocIdVar; + result_loc_var->base.source_instruction = alloca; + result_loc_var->var = var; + // Temporarily set the name of the IrExecutable to the VariableDeclaration // so that the struct or enum from the init expression inherits the name. Buf *old_exec_name = irb->exec->name; irb->exec->name = variable_declaration->symbol; - IrInstruction *init_value = ir_gen_node(irb, variable_declaration->expr, scope); + IrInstruction *init_value = ir_gen_node_extra(irb, variable_declaration->expr, scope, LValNone, + &result_loc_var->base); irb->exec->name = old_exec_name; if (init_value == irb->codegen->invalid_instruction) return init_value; - return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, init_value); + return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, alloca); } static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -5534,7 +5635,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n } else { payload_scope = subexpr_scope; } - IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr); + IrInstruction *err_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, + LValPtr, nullptr); if (err_val_ptr == irb->codegen->invalid_instruction) return err_val_ptr; IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr); @@ -5621,7 +5723,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ZigVar *payload_var = ir_create_var(irb, symbol_node, subexpr_scope, var_symbol, true, false, false, is_comptime); Scope *child_scope = payload_var->child_scope; - IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, LValPtr); + IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, node->data.while_expr.condition, subexpr_scope, + LValPtr, nullptr); if (maybe_val_ptr == irb->codegen->invalid_instruction) return maybe_val_ptr; IrInstruction *maybe_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, maybe_val_ptr); @@ -5775,7 +5878,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo } assert(elem_node->type == NodeTypeSymbol); - IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPtr); + IrInstruction *array_val_ptr = ir_gen_node_extra(irb, array_node, parent_scope, LValPtr, nullptr); if (array_val_ptr == irb->codegen->invalid_instruction) return array_val_ptr; @@ -6182,7 +6285,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN AstNode *else_node = node->data.test_expr.else_node; bool var_is_ptr = node->data.test_expr.var_is_ptr; - IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); + IrInstruction *maybe_val_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); if (maybe_val_ptr == irb->codegen->invalid_instruction) return maybe_val_ptr; @@ -6261,7 +6364,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * Buf *var_symbol = node->data.if_err_expr.var_symbol; Buf *err_symbol = node->data.if_err_expr.err_symbol; - IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr); + IrInstruction *err_val_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr, nullptr); if (err_val_ptr == irb->codegen->invalid_instruction) return err_val_ptr; @@ -6397,7 +6500,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * assert(node->type == NodeTypeSwitchExpr); AstNode *target_node = node->data.switch_expr.expr; - IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr); + IrInstruction *target_value_ptr = ir_gen_node_extra(irb, target_node, scope, LValPtr, nullptr); if (target_value_ptr == irb->codegen->invalid_instruction) return target_value_ptr; IrInstruction *target_value = ir_build_switch_target(irb, scope, node, target_value_ptr); @@ -6597,7 +6700,7 @@ static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNo assert(node->type == NodeTypeCompTime); Scope *child_scope = create_comptime_scope(irb->codegen, node, parent_scope); - return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval); + return ir_gen_node_extra(irb, node->data.comptime_expr.expr, child_scope, lval, nullptr); } static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scope, AstNode *node, ScopeBlock *block_scope) { @@ -6776,7 +6879,7 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) AstNode *start_node = slice_expr->start; AstNode *end_node = slice_expr->end; - IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr); + IrInstruction *ptr_value = ir_gen_node_extra(irb, array_node, scope, LValPtr, nullptr); if (ptr_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -6814,7 +6917,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode } - IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr); + IrInstruction *err_union_ptr = ir_gen_node_extra(irb, op1_node, parent_scope, LValPtr, nullptr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -7560,7 +7663,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod } static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope, - LVal lval) + LVal lval, ResultLoc *result_loc) { assert(scope); switch (node->type) { @@ -7576,7 +7679,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeBlock: return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); case NodeTypeGroupedExpr: - return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval); + return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc); case NodeTypeBinOpExpr: return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval); case NodeTypeIntLiteral: @@ -7588,7 +7691,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeSymbol: return ir_gen_symbol(irb, scope, node, lval); case NodeTypeFnCallExpr: - return ir_gen_fn_call(irb, scope, node, lval); + return ir_gen_fn_call(irb, scope, node, lval, result_loc); case NodeTypeIfBoolExpr: return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval); case NodeTypePrefixOpExpr: @@ -7617,7 +7720,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop } case NodeTypePtrDeref: { AstNode *expr_node = node->data.ptr_deref_expr.target; - IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval); + IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval, nullptr); if (value == irb->codegen->invalid_instruction) return value; @@ -7629,7 +7732,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeUnwrapOptional: { AstNode *expr_node = node->data.unwrap_optional.expr; - IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr); + IrInstruction *maybe_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -7697,14 +7800,23 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop zig_unreachable(); } -static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval) { - IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval); +static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, + ResultLoc *result_loc) +{ + if (result_loc == nullptr) { + // Create a result location indicating there is none - but if one gets created + // it will be properly distributed. + ResultLocNone *result_loc_none = allocate(1); + result_loc_none->base.id = ResultLocIdNone; + result_loc = &result_loc_none->base; + } + IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction); return result; } static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { - return ir_gen_node_extra(irb, node, scope, LValNone); + return ir_gen_node_extra(irb, node, scope, LValNone, nullptr); } static void invalidate_exec(IrExecutable *exec) { @@ -7837,7 +7949,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec irb->exec->coro_final_cleanup_block = ir_create_basic_block(irb, scope, "FinalCleanup"); } - IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone); + IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr); assert(result); if (irb->exec->invalid) return false; @@ -7946,7 +8058,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // non-allocating. Basically coroutines are not supported right now until they are reworked. args[3] = ir_build_const_usize(irb, scope, node, 1); // new_size args[4] = ir_build_const_usize(irb, scope, node, 1); // new_align - ir_build_call(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr); + ResultLocNone *result_loc_none = allocate(1); + result_loc_none->base.id = ResultLocIdNone; + ir_build_call_src(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr, + nullptr, &result_loc_none->base); IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume"); ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false); @@ -13641,12 +13756,6 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, Error err; ZigVar *var = decl_var_instruction->var; - IrInstruction *init_value = decl_var_instruction->init_value->child; - if (type_is_invalid(init_value->value.type)) { - var->var_type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_instruction; - } - ZigType *explicit_type = nullptr; IrInstruction *var_type = nullptr; if (decl_var_instruction->var_type != nullptr) { @@ -13661,12 +13770,19 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, AstNode *source_node = decl_var_instruction->base.source_node; - IrInstruction *casted_init_value = ir_implicit_cast(ira, init_value, explicit_type); bool is_comptime_var = ir_get_var_is_comptime(var); bool var_class_requires_const = false; - ZigType *result_type = casted_init_value->value.type; + IrInstruction *var_ptr = decl_var_instruction->ptr->child; + if (type_is_invalid(var_ptr->value.type)) { + var->var_type = ira->codegen->builtin_types.entry_invalid; + return ira->codegen->invalid_instruction; + } + + assert(var_ptr->value.type->id == ZigTypeIdPointer); + + ZigType *result_type = var_ptr->value.type->data.pointer.child_type; if (type_is_invalid(result_type)) { result_type = ira->codegen->builtin_types.entry_invalid; } else if (result_type->id == ZigTypeIdUnreachable || result_type->id == ZigTypeIdOpaque) { @@ -13675,6 +13791,14 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, result_type = ira->codegen->builtin_types.entry_invalid; } + ConstExprValue *init_val = nullptr; + if (instr_is_comptime(var_ptr) && var_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) { + init_val = const_ptr_pointee(ira, ira->codegen, &var_ptr->value, decl_var_instruction->base.source_node); + if (is_comptime_var) { + var->const_value = init_val; + } + } + switch (type_requires_comptime(ira->codegen, result_type)) { case ReqCompTimeInvalid: result_type = ira->codegen->builtin_types.entry_invalid; @@ -13689,18 +13813,20 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } break; case ReqCompTimeNo: - if (casted_init_value->value.special == ConstValSpecialStatic && - casted_init_value->value.type->id == ZigTypeIdFn && - casted_init_value->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && - casted_init_value->value.data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) - { - var_class_requires_const = true; - if (!var->src_is_const && !is_comptime_var) { - ErrorMsg *msg = ir_add_error_node(ira, source_node, - buf_sprintf("functions marked inline must be stored in const or comptime var")); - AstNode *proto_node = casted_init_value->value.data.x_ptr.data.fn.fn_entry->proto_node; - add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here")); - result_type = ira->codegen->builtin_types.entry_invalid; + if (init_val != nullptr) { + if (init_val->special == ConstValSpecialStatic && + init_val->type->id == ZigTypeIdFn && + init_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && + init_val->data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) + { + var_class_requires_const = true; + if (!var->src_is_const && !is_comptime_var) { + ErrorMsg *msg = ir_add_error_node(ira, source_node, + buf_sprintf("functions marked inline must be stored in const or comptime var")); + AstNode *proto_node = init_val->data.x_ptr.data.fn.fn_entry->proto_node; + add_error_note(ira->codegen, msg, proto_node, buf_sprintf("declared here")); + result_type = ira->codegen->builtin_types.entry_invalid; + } } } break; @@ -13747,11 +13873,11 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } } - if (casted_init_value->value.special != ConstValSpecialRuntime) { + if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) { if (var->mem_slot_index != SIZE_MAX) { assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); - copy_const_val(mem_slot, &casted_init_value->value, !is_comptime_var || var->gen_is_const); + copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); if (is_comptime_var || (var_class_requires_const && var->gen_is_const)) { return ir_const_void(ira, &decl_var_instruction->base); @@ -13768,7 +13894,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, if (fn_entry) fn_entry->variable_list.append(var); - return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, casted_init_value); + return ir_build_var_decl_gen(ira, &decl_var_instruction->base, var, var_ptr); } static VarLinkage global_linkage_to_var_linkage(GlobalLinkageId id) { @@ -14076,7 +14202,67 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i zig_unreachable(); } -static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *call_instruction, ZigFn *fn_entry, +static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type, + uint32_t align, const char *name_hint, bool force_comptime) +{ + Error err; + + ConstExprValue *pointee = create_const_vals(1); + pointee->special = ConstValSpecialUndef; + + IrInstructionAllocaGen *result = ir_create_alloca_gen(ira, source_inst, align, name_hint); + result->base.value.special = force_comptime ? ConstValSpecialStatic : ConstValSpecialRuntime; + result->base.value.data.x_ptr.special = ConstPtrSpecialRef; + result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutRuntimeVar; + result->base.value.data.x_ptr.data.ref.pointee = pointee; + + if ((err = type_resolve(ira->codegen, var_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid); + + pointee->type = var_type; + result->base.value.type = get_pointer_to_type_extra(ira->codegen, var_type, false, false, + PtrLenSingle, align, 0, 0, false); + + ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); + if (fn_entry != nullptr) { + fn_entry->alloca_gen_list.append(result); + } + result->base.is_gen = true; + return &result->base; +} + +static IrInstruction *ir_resolve_result_loc(IrAnalyze *ira, ResultLoc *result_loc, ZigType *elem_type) { + switch (result_loc->id) { + case ResultLocIdInvalid: + zig_unreachable(); + case ResultLocIdNone: + return nullptr; + case ResultLocIdVar: { + // TODO implicit cast? + //ResultLocVar *result_loc_var = reinterpret_cast(result_loc); + assert(result_loc->source_instruction->id == IrInstructionIdAllocaSrc); + IrInstructionAllocaSrc *alloca_src = + reinterpret_cast(result_loc->source_instruction); + if (alloca_src->base.child == nullptr) { + uint32_t align = 0; // TODO + bool force_comptime = false; // TODO + IrInstruction *alloca_gen = ir_analyze_alloca(ira, result_loc->source_instruction, elem_type, align, + alloca_src->name_hint, force_comptime); + alloca_src->base.child = alloca_gen; + } + return alloca_src->base.child; + } + case ResultLocIdReturn: { + //ResultLocReturn *result_loc_ret = reinterpret_cast(result_loc); + // TODO implicit cast? + return ir_build_return_ptr(ira, result_loc->source_instruction, elem_type); + } + } + zig_unreachable(); +} + +static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) { @@ -14109,8 +14295,10 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c ZigType *promise_type = get_promise_type(ira->codegen, return_type); ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type); - IrInstruction *result = ir_build_call(&ira->new_irb, call_instruction->base.scope, call_instruction->base.source_node, - fn_entry, fn_ref, arg_count, casted_args, false, FnInlineAuto, true, async_allocator_inst, nullptr); + IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, async_return_type); + + IrInstruction *result = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, + casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc); result->value.type = async_return_type; return result; } @@ -14416,7 +14604,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source return result; } -static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call_instruction, +static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) { @@ -14861,19 +15049,17 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call if (call_instruction->is_async) { IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, fn_ref, casted_args, impl_param_count, async_allocator_inst); - ir_add_alloca(ira, result, result->value.type); return ir_finish_anal(ira, result); } assert(async_allocator_inst == nullptr); - IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb, - call_instruction->base.scope, call_instruction->base.source_node, - impl_fn, nullptr, impl_param_count, casted_args, false, fn_inline, - call_instruction->is_async, nullptr, casted_new_stack); + IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, + impl_fn_type_id->return_type); + IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, + impl_fn, nullptr, impl_param_count, casted_args, fn_inline, + call_instruction->is_async, nullptr, casted_new_stack, result_loc); new_call_instruction->value.type = impl_fn_type_id->return_type; - ir_add_alloca(ira, new_call_instruction, impl_fn_type_id->return_type); - return ir_finish_anal(ira, new_call_instruction); } @@ -14957,7 +15143,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, casted_args, call_param_count, async_allocator_inst); - ir_add_alloca(ira, result, result->value.type); return ir_finish_anal(ira, result); } @@ -14967,15 +15152,14 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call return ira->codegen->invalid_instruction; } - IrInstruction *new_call_instruction = ir_build_call(&ira->new_irb, - call_instruction->base.scope, call_instruction->base.source_node, - fn_entry, fn_ref, call_param_count, casted_args, false, fn_inline, false, nullptr, casted_new_stack); + IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, return_type); + IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, + call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack, result_loc); new_call_instruction->value.type = return_type; - ir_add_alloca(ira, new_call_instruction, return_type); return ir_finish_anal(ira, new_call_instruction); } -static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCall *call_instruction) { +static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction) { IrInstruction *fn_ref = call_instruction->fn_ref->child; if (type_is_invalid(fn_ref->value.type)) return ira->codegen->invalid_instruction; @@ -23304,6 +23488,9 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdResizeSlice: case IrInstructionIdLoadPtrGen: case IrInstructionIdBitCastGen: + case IrInstructionIdCallGen: + case IrInstructionIdReturnPtr: + case IrInstructionIdAllocaGen: zig_unreachable(); case IrInstructionIdReturn: @@ -23326,8 +23513,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_var_ptr(ira, (IrInstructionVarPtr *)instruction); case IrInstructionIdFieldPtr: return ir_analyze_instruction_field_ptr(ira, (IrInstructionFieldPtr *)instruction); - case IrInstructionIdCall: - return ir_analyze_instruction_call(ira, (IrInstructionCall *)instruction); + case IrInstructionIdCallSrc: + return ir_analyze_instruction_call(ira, (IrInstructionCallSrc *)instruction); case IrInstructionIdBr: return ir_analyze_instruction_br(ira, (IrInstructionBr *)instruction); case IrInstructionIdCondBr: @@ -23580,13 +23767,15 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_has_decl(ira, (IrInstructionHasDecl *)instruction); case IrInstructionIdUndeclaredIdent: return ir_analyze_instruction_undeclared_ident(ira, (IrInstructionUndeclaredIdent *)instruction); + case IrInstructionIdAllocaSrc: + return nullptr; } zig_unreachable(); } static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *old_instruction) { IrInstruction *new_instruction = ir_analyze_instruction_nocast(ira, old_instruction); - ir_assert(new_instruction->value.type != nullptr, old_instruction); + ir_assert(new_instruction->value.type != nullptr || new_instruction->value.type != nullptr, old_instruction); old_instruction->child = new_instruction; return new_instruction; } @@ -23637,13 +23826,15 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ } IrInstruction *new_instruction = ir_analyze_instruction(ira, old_instruction); - if (type_is_invalid(new_instruction->value.type) && ir_should_inline(new_exec, old_instruction->scope)) { - return ira->codegen->builtin_types.entry_invalid; - } + if (new_instruction != nullptr) { + if (type_is_invalid(new_instruction->value.type) && ir_should_inline(new_exec, old_instruction->scope)) { + return ira->codegen->builtin_types.entry_invalid; + } - // unreachable instructions do their own control flow. - if (new_instruction->value.type->id == ZigTypeIdUnreachable) - continue; + // unreachable instructions do their own control flow. + if (new_instruction->value.type->id == ZigTypeIdUnreachable) + continue; + } ira->instruction_index += 1; } @@ -23668,7 +23859,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdDeclVarSrc: case IrInstructionIdDeclVarGen: case IrInstructionIdStorePtr: - case IrInstructionIdCall: + case IrInstructionIdCallSrc: + case IrInstructionIdCallGen: case IrInstructionIdReturn: case IrInstructionIdUnreachable: case IrInstructionIdSetCold: @@ -23731,6 +23923,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFieldPtr: case IrInstructionIdElemPtr: case IrInstructionIdVarPtr: + case IrInstructionIdReturnPtr: case IrInstructionIdTypeOf: case IrInstructionIdToPtrType: case IrInstructionIdPtrTypeChild: @@ -23818,6 +24011,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdVectorToArray: case IrInstructionIdArrayToVector: case IrInstructionIdHasDecl: + case IrInstructionIdAllocaSrc: + case IrInstructionIdAllocaGen: return false; case IrInstructionIdAsm: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index bf9ced89c5..20581a65cf 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -188,7 +188,7 @@ static void ir_print_decl_var_src(IrPrint *irp, IrInstructionDeclVarSrc *decl_va fprintf(irp->f, " "); } fprintf(irp->f, "= "); - ir_print_other_instruction(irp, decl_var_instruction->init_value); + ir_print_other_instruction(irp, decl_var_instruction->ptr); if (decl_var_instruction->var->is_comptime != nullptr) { fprintf(irp->f, " // comptime = "); ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime); @@ -201,7 +201,29 @@ static void ir_print_cast(IrPrint *irp, IrInstructionCast *cast_instruction) { fprintf(irp->f, " to %s", buf_ptr(&cast_instruction->dest_type->name)); } -static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) { +static void ir_print_result_loc_var(IrPrint *irp, ResultLocVar *result_loc_var) { + fprintf(irp->f, "var("); + ir_print_other_instruction(irp, result_loc_var->base.source_instruction); + fprintf(irp->f, ")"); +} + +static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { + switch (result_loc->id) { + case ResultLocIdInvalid: + zig_unreachable(); + case ResultLocIdNone: + fprintf(irp->f, "none"); + return; + case ResultLocIdReturn: + fprintf(irp->f, "return"); + return; + case ResultLocIdVar: + return ir_print_result_loc_var(irp, (ResultLocVar *)result_loc); + } + zig_unreachable(); +} + +static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) { if (call_instruction->is_async) { fprintf(irp->f, "async"); if (call_instruction->async_allocator != nullptr) { @@ -224,7 +246,35 @@ static void ir_print_call(IrPrint *irp, IrInstructionCall *call_instruction) { fprintf(irp->f, ", "); ir_print_other_instruction(irp, arg); } - fprintf(irp->f, ")"); + fprintf(irp->f, ")result="); + ir_print_result_loc(irp, call_instruction->result_loc); +} + +static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instruction) { + if (call_instruction->is_async) { + fprintf(irp->f, "async"); + if (call_instruction->async_allocator != nullptr) { + fprintf(irp->f, "<"); + ir_print_other_instruction(irp, call_instruction->async_allocator); + fprintf(irp->f, ">"); + } + fprintf(irp->f, " "); + } + 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]; + if (i != 0) + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, arg); + } + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, call_instruction->result_loc); } static void ir_print_cond_br(IrPrint *irp, IrInstructionCondBr *cond_br_instruction) { @@ -331,6 +381,10 @@ static void ir_print_var_ptr(IrPrint *irp, IrInstructionVarPtr *instruction) { fprintf(irp->f, "&%s", buf_ptr(&instruction->var->name)); } +static void ir_print_return_ptr(IrPrint *irp, IrInstructionReturnPtr *instruction) { + fprintf(irp->f, "@ReturnPtr"); +} + static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { ir_print_other_instruction(irp, instruction->ptr); fprintf(irp->f, ".*"); @@ -1064,6 +1118,16 @@ static void ir_print_resize_slice(IrPrint *irp, IrInstructionResizeSlice *instru fprintf(irp->f, ")"); } +static void ir_print_alloca_src(IrPrint *irp, IrInstructionAllocaSrc *instruction) { + fprintf(irp->f, "Alloca(align="); + ir_print_other_instruction(irp, instruction->align); + fprintf(irp->f, ",name=%s)", instruction->name_hint); +} + +static void ir_print_alloca_gen(IrPrint *irp, IrInstructionAllocaGen *instruction) { + fprintf(irp->f, "Alloca(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint); +} + static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { fprintf(irp->f, "inttoerr "); ir_print_other_instruction(irp, instruction->target); @@ -1446,7 +1510,7 @@ static void ir_print_decl_var_gen(IrPrint *irp, IrInstructionDeclVarGen *decl_va fprintf(irp->f, "%s %s: %s align(%u) = ", var_or_const, name, buf_ptr(&var->var_type->name), var->align_bytes); - ir_print_other_instruction(irp, decl_var_instruction->init_value); + ir_print_other_instruction(irp, decl_var_instruction->var_ptr); if (decl_var_instruction->var->is_comptime != nullptr) { fprintf(irp->f, " // comptime = "); ir_print_other_instruction(irp, decl_var_instruction->var->is_comptime); @@ -1485,8 +1549,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdCast: ir_print_cast(irp, (IrInstructionCast *)instruction); break; - case IrInstructionIdCall: - ir_print_call(irp, (IrInstructionCall *)instruction); + case IrInstructionIdCallSrc: + ir_print_call_src(irp, (IrInstructionCallSrc *)instruction); + break; + case IrInstructionIdCallGen: + ir_print_call_gen(irp, (IrInstructionCallGen *)instruction); break; case IrInstructionIdUnOp: ir_print_un_op(irp, (IrInstructionUnOp *)instruction); @@ -1521,6 +1588,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdVarPtr: ir_print_var_ptr(irp, (IrInstructionVarPtr *)instruction); break; + case IrInstructionIdReturnPtr: + ir_print_return_ptr(irp, (IrInstructionReturnPtr *)instruction); + break; case IrInstructionIdLoadPtr: ir_print_load_ptr(irp, (IrInstructionLoadPtr *)instruction); break; @@ -1938,6 +2008,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdUndeclaredIdent: ir_print_undeclared_ident(irp, (IrInstructionUndeclaredIdent *)instruction); break; + case IrInstructionIdAllocaSrc: + ir_print_alloca_src(irp, (IrInstructionAllocaSrc *)instruction); + break; + case IrInstructionIdAllocaGen: + ir_print_alloca_gen(irp, (IrInstructionAllocaGen *)instruction); + break; } fprintf(irp->f, "\n"); } -- cgit v1.2.3 From a4aca787229e3b0b3dc992b747cc72a561c2078c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 30 May 2019 17:05:06 -0400 Subject: no-copy semantics for if expr ```zig export fn entry() void { var c = true; var x = if (c) u8(4) else u32(10); } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %c = alloca i1, align 1 %x = alloca i32, align 4 store i1 true, i1* %c, align 1, !dbg !44 call void @llvm.dbg.declare(metadata i1* %c, metadata !39, metadata !DIExpression()), !dbg !45 %0 = load i1, i1* %c, align 1, !dbg !46 br i1 %0, label %Then, label %Else, !dbg !46 Then: ; preds = %Entry br label %EndIf, !dbg !47 Else: ; preds = %Entry br label %EndIf, !dbg !47 EndIf: ; preds = %Else, %Then %1 = phi i32 [ 4, %Then ], [ 10, %Else ], !dbg !47 store i32 %1, i32* %x, align 4, !dbg !47 call void @llvm.dbg.declare(metadata i32* %x, metadata !42, metadata !DIExpression()), !dbg !48 ret void, !dbg !49 } ``` --- BRANCH_TODO | 18 ++ src/all_types.hpp | 43 ++++- src/codegen.cpp | 5 +- src/ir.cpp | 483 +++++++++++++++++++++++++++++++++++------------------- src/ir_print.cpp | 27 +++ 5 files changed, 404 insertions(+), 172 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 294d3e677f..ffcf35d810 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -8,3 +8,21 @@ migrate all the alloca_list to alloca_gen_list migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize inferred comptime + + + if (lval == LValNone) { + if (result_loc->id == ResultLocIdNone) + return value; + } + + assert(lval == LValPtr); + + // We needed a pointer to a value, but we got a value. So we create + // an instruction which just makes a pointer of it. + return ir_build_ref(irb, scope, value->source_node, value, false, false); + +handle if with no else + +handle comptime if condition + +handle mixed runtime and comptime peers diff --git a/src/all_types.hpp b/src/all_types.hpp index ae8d9c3fb8..79ad2f8958 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -42,6 +42,7 @@ struct Tld; struct TldExport; struct IrAnalyze; struct ResultLoc; +struct ResultLocPeer; enum X64CABIClass { X64CABIClass_Unknown, @@ -2127,6 +2128,8 @@ struct IrBasicBlock { const char *name_hint; size_t debug_id; size_t ref_count; + // index into the basic block list + size_t index; LLVMBasicBlockRef llvm_block; LLVMBasicBlockRef llvm_exit_block; // The instruction that referenced this basic block and caused us to @@ -2315,10 +2318,14 @@ enum IrInstructionId { IrInstructionIdUndeclaredIdent, IrInstructionIdAllocaSrc, IrInstructionIdAllocaGen, + IrInstructionIdEndExpr, }; struct IrInstruction { IrInstructionId id; + // true if this instruction was generated by zig and not from user code + bool is_gen; + Scope *scope; AstNode *source_node; ConstExprValue value; @@ -2332,8 +2339,6 @@ struct IrInstruction { // with this child field. IrInstruction *child; IrBasicBlock *owner_bb; - // true if this instruction was generated by zig and not from user code - bool is_gen; }; struct IrInstructionDeclVarSrc { @@ -3571,16 +3576,28 @@ struct IrInstructionAllocaGen { const char *name_hint; }; +struct IrInstructionEndExpr { + IrInstruction base; + + IrInstruction *value; + ResultLoc *result_loc; + LVal lval; +}; + enum ResultLocId { ResultLocIdInvalid, ResultLocIdNone, ResultLocIdVar, ResultLocIdReturn, + ResultLocIdPeer, + ResultLocIdPeerParent, }; struct ResultLoc { ResultLocId id; IrInstruction *source_instruction; + IrInstruction *gen_instruction; + ZigType *implicit_elem_type; }; struct ResultLocNone { @@ -3597,6 +3614,28 @@ struct ResultLocReturn { ResultLoc base; }; +struct ResultLocPeerParent { + ResultLoc base; + + ResultLoc *parent; + ResultLocPeer *peers; + size_t peer_count; + ZigType *resolved_type; +}; + +struct IrSuspendPosition { + size_t basic_block_index; + size_t instruction_index; +}; + +struct ResultLocPeer { + ResultLoc base; + + ResultLocPeerParent *parent; + IrBasicBlock *next_bb; + IrSuspendPosition suspend_pos; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index 2cb3584e68..ccbf911686 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5606,10 +5606,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdUndeclaredIdent: case IrInstructionIdCallSrc: case IrInstructionIdAllocaSrc: - zig_unreachable(); - + case IrInstructionIdEndExpr: case IrInstructionIdAllocaGen: - return nullptr; + zig_unreachable(); case IrInstructionIdDeclVarGen: return ir_render_decl_var(g, executable, (IrInstructionDeclVarGen *)instruction); diff --git a/src/ir.cpp b/src/ir.cpp index 5b6ce22620..c406a809ca 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -38,6 +38,7 @@ struct IrAnalyze { ZigType *explicit_return_type; AstNode *explicit_return_type_source_node; ZigList src_implicit_return_type_list; + ZigList resume_stack; IrBasicBlock *const_predecessor_bb; }; @@ -159,7 +160,6 @@ enum UndefAllowed { static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc); -static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type); static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr); static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); @@ -167,7 +167,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var); static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op); -static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval); +static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, ResultLoc *result_loc); static ZigType *adjust_ptr_align(CodeGen *g, ZigType *ptr_type, uint32_t new_align); static ZigType *adjust_slice_align(CodeGen *g, ZigType *slice_type, uint32_t new_align); static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *source_node, uint8_t *buf, ConstExprValue *val); @@ -184,6 +184,7 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc ZigType *ptr_type); static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *dest_type); +static IrInstruction *ir_resolve_result_runtime(IrAnalyze *ira, ResultLoc *result_loc, ZigType *elem_type); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -387,6 +388,7 @@ static IrBasicBlock *ir_create_basic_block(IrBuilder *irb, Scope *scope, const c result->scope = scope; result->name_hint = name_hint; result->debug_id = exec_next_debug_id(irb->exec); + result->index = SIZE_MAX; // set later return result; } @@ -1036,6 +1038,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAllocaGen *) { return IrInstructionIdAllocaGen; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionEndExpr *) { + return IrInstructionIdEndExpr; +} + template static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate(1); @@ -1373,10 +1379,11 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *new_stack, - IrInstruction *result_loc) + ResultLoc *result_loc, ZigType *return_type) { IrInstructionCallGen *call_instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); + call_instruction->base.value.type = return_type; call_instruction->fn_entry = fn_entry; call_instruction->fn_ref = fn_ref; call_instruction->fn_inline = fn_inline; @@ -1385,14 +1392,14 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in call_instruction->is_async = is_async; call_instruction->async_allocator = async_allocator; call_instruction->new_stack = new_stack; - call_instruction->result_loc = result_loc; + call_instruction->result_loc = ir_resolve_result_runtime(ira, result_loc, return_type); if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block); for (size_t i = 0; i < arg_count; i += 1) ir_ref_instruction(args[i], ira->new_irb.current_basic_block); if (async_allocator != nullptr) ir_ref_instruction(async_allocator, ira->new_irb.current_basic_block); if (new_stack != nullptr) ir_ref_instruction(new_stack, ira->new_irb.current_basic_block); - if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + if (call_instruction->result_loc != nullptr) ir_ref_instruction(call_instruction->result_loc, ira->new_irb.current_basic_block); return &call_instruction->base; } @@ -3187,6 +3194,19 @@ static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstructio return instruction; } +static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value, LVal lval, ResultLoc *result_loc) +{ + IrInstructionEndExpr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->value = value; + instruction->lval = lval; + instruction->result_loc = result_loc; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) { results[ReturnKindUnconditional] = 0; results[ReturnKindError] = 0; @@ -3287,6 +3307,7 @@ static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) { } static void ir_set_cursor_at_end_and_append_block(IrBuilder *irb, IrBasicBlock *basic_block) { + basic_block->index = irb->exec->basic_block_list.length; irb->exec->basic_block_list.append(basic_block); ir_set_cursor_at_end(irb, basic_block); } @@ -3623,6 +3644,8 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode // keep the last noreturn statement value around in case we need to return it noreturn_return_value = statement_value; } + // This logic must be kept in sync with + // [STMT_EXPR_TEST_THING] <--- (search this token) if (statement_node->type == NodeTypeDefer && statement_value != irb->codegen->invalid_instruction) { // defer starts a new scope child_scope = statement_node->data.defer.child_scope; @@ -4164,7 +4187,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg; IrInstruction *type_of = ir_build_typeof(irb, scope, node, arg); - return ir_lval_wrap(irb, scope, type_of, lval); + return ir_lval_wrap(irb, scope, type_of, lval, result_loc); } case BuiltinFnIdSetCold: { @@ -4174,7 +4197,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_cold = ir_build_set_cold(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_cold, lval); + return ir_lval_wrap(irb, scope, set_cold, lval, result_loc); } case BuiltinFnIdSetRuntimeSafety: { @@ -4184,7 +4207,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_safety = ir_build_set_runtime_safety(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_safety, lval); + return ir_lval_wrap(irb, scope, set_safety, lval, result_loc); } case BuiltinFnIdSetFloatMode: { @@ -4194,7 +4217,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_float_mode = ir_build_set_float_mode(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_float_mode, lval); + return ir_lval_wrap(irb, scope, set_float_mode, lval, result_loc); } case BuiltinFnIdSizeof: { @@ -4204,7 +4227,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *size_of = ir_build_size_of(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, size_of, lval); + return ir_lval_wrap(irb, scope, size_of, lval, result_loc); } case BuiltinFnIdImport: { @@ -4214,12 +4237,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *import = ir_build_import(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, import, lval); + return ir_lval_wrap(irb, scope, import, lval, result_loc); } case BuiltinFnIdCImport: { IrInstruction *c_import = ir_build_c_import(irb, scope, node); - return ir_lval_wrap(irb, scope, c_import, lval); + return ir_lval_wrap(irb, scope, c_import, lval, result_loc); } case BuiltinFnIdCInclude: { @@ -4234,7 +4257,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } IrInstruction *c_include = ir_build_c_include(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, c_include, lval); + return ir_lval_wrap(irb, scope, c_include, lval, result_loc); } case BuiltinFnIdCDefine: { @@ -4254,7 +4277,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } IrInstruction *c_define = ir_build_c_define(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, c_define, lval); + return ir_lval_wrap(irb, scope, c_define, lval, result_loc); } case BuiltinFnIdCUndef: { @@ -4269,7 +4292,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } IrInstruction *c_undef = ir_build_c_undef(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, c_undef, lval); + return ir_lval_wrap(irb, scope, c_undef, lval, result_loc); } case BuiltinFnIdCompileErr: { @@ -4279,7 +4302,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *compile_err = ir_build_compile_err(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, compile_err, lval); + return ir_lval_wrap(irb, scope, compile_err, lval, result_loc); } case BuiltinFnIdCompileLog: { @@ -4293,7 +4316,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } IrInstruction *compile_log = ir_build_compile_log(irb, scope, node, actual_param_count, args); - return ir_lval_wrap(irb, scope, compile_log, lval); + return ir_lval_wrap(irb, scope, compile_log, lval, result_loc); } case BuiltinFnIdErrName: { @@ -4303,7 +4326,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *err_name = ir_build_err_name(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, err_name, lval); + return ir_lval_wrap(irb, scope, err_name, lval, result_loc); } case BuiltinFnIdEmbedFile: { @@ -4313,7 +4336,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *embed_file = ir_build_embed_file(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, embed_file, lval); + return ir_lval_wrap(irb, scope, embed_file, lval, result_loc); } case BuiltinFnIdCmpxchgWeak: case BuiltinFnIdCmpxchgStrong: @@ -4350,7 +4373,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); - return ir_lval_wrap(irb, scope, cmpxchg, lval); + return ir_lval_wrap(irb, scope, cmpxchg, lval, result_loc); } case BuiltinFnIdFence: { @@ -4360,7 +4383,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *fence = ir_build_fence(irb, scope, node, arg0_value, AtomicOrderUnordered); - return ir_lval_wrap(irb, scope, fence, lval); + return ir_lval_wrap(irb, scope, fence, lval, result_loc); } case BuiltinFnIdDivExact: { @@ -4375,7 +4398,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdDivTrunc: { @@ -4390,7 +4413,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivTrunc, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdDivFloor: { @@ -4405,7 +4428,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpDivFloor, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdRem: { @@ -4420,7 +4443,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemRem, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdMod: { @@ -4435,7 +4458,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpRemMod, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdSqrt: { @@ -4450,7 +4473,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *ir_sqrt = ir_build_sqrt(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, ir_sqrt, lval); + return ir_lval_wrap(irb, scope, ir_sqrt, lval, result_loc); } case BuiltinFnIdTruncate: { @@ -4465,7 +4488,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *truncate = ir_build_truncate(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, truncate, lval); + return ir_lval_wrap(irb, scope, truncate, lval, result_loc); } case BuiltinFnIdIntCast: { @@ -4480,7 +4503,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_int_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdFloatCast: { @@ -4495,7 +4518,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_float_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdErrSetCast: { @@ -4510,7 +4533,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_err_set_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdFromBytes: { @@ -4525,7 +4548,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdToBytes: { @@ -4535,7 +4558,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdIntToFloat: { @@ -4550,7 +4573,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_int_to_float(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdFloatToInt: { @@ -4565,7 +4588,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_float_to_int(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdErrToInt: { @@ -4575,7 +4598,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_err_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdIntToErr: { @@ -4585,7 +4608,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_int_to_err(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdBoolToInt: { @@ -4595,7 +4618,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_bool_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdIntType: { @@ -4610,7 +4633,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *int_type = ir_build_int_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, int_type, lval); + return ir_lval_wrap(irb, scope, int_type, lval, result_loc); } case BuiltinFnIdVectorType: { @@ -4625,7 +4648,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *vector_type = ir_build_vector_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, vector_type, lval); + return ir_lval_wrap(irb, scope, vector_type, lval, result_loc); } case BuiltinFnIdMemcpy: { @@ -4645,7 +4668,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg2_value; IrInstruction *ir_memcpy = ir_build_memcpy(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, ir_memcpy, lval); + return ir_lval_wrap(irb, scope, ir_memcpy, lval, result_loc); } case BuiltinFnIdMemset: { @@ -4665,7 +4688,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg2_value; IrInstruction *ir_memset = ir_build_memset(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, ir_memset, lval); + return ir_lval_wrap(irb, scope, ir_memset, lval, result_loc); } case BuiltinFnIdMemberCount: { @@ -4675,7 +4698,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *member_count = ir_build_member_count(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, member_count, lval); + return ir_lval_wrap(irb, scope, member_count, lval, result_loc); } case BuiltinFnIdMemberType: { @@ -4691,7 +4714,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *member_type = ir_build_member_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, member_type, lval); + return ir_lval_wrap(irb, scope, member_type, lval, result_loc); } case BuiltinFnIdMemberName: { @@ -4707,7 +4730,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *member_name = ir_build_member_name(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, member_name, lval); + return ir_lval_wrap(irb, scope, member_name, lval, result_loc); } case BuiltinFnIdField: { @@ -4736,14 +4759,14 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *type_info = ir_build_type_info(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_info, lval); + return ir_lval_wrap(irb, scope, type_info, lval, result_loc); } case BuiltinFnIdBreakpoint: - return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_breakpoint(irb, scope, node), lval, result_loc); case BuiltinFnIdReturnAddress: - return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_return_address(irb, scope, node), lval, result_loc); case BuiltinFnIdFrameAddress: - return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_frame_address(irb, scope, node), lval, result_loc); case BuiltinFnIdHandle: if (!irb->exec->fn_entry) { add_node_error(irb->codegen, node, buf_sprintf("@handle() called outside of function definition")); @@ -4753,7 +4776,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo add_node_error(irb->codegen, node, buf_sprintf("@handle() in non-async function")); return irb->codegen->invalid_instruction; } - return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_handle(irb, scope, node), lval, result_loc); case BuiltinFnIdAlignOf: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -4762,16 +4785,16 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *align_of = ir_build_align_of(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, align_of, lval); + return ir_lval_wrap(irb, scope, align_of, lval, result_loc); } case BuiltinFnIdAddWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval); + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpAdd), lval, result_loc); case BuiltinFnIdSubWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval); + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpSub), lval, result_loc); case BuiltinFnIdMulWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval); + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpMul), lval, result_loc); case BuiltinFnIdShlWithOverflow: - return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval); + return ir_lval_wrap(irb, scope, ir_gen_overflow_op(irb, scope, node, IrOverflowOpShl), lval, result_loc); case BuiltinFnIdTypeName: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -4780,7 +4803,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *type_name = ir_build_type_name(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_name, lval); + return ir_lval_wrap(irb, scope, type_name, lval, result_loc); } case BuiltinFnIdPanic: { @@ -4790,7 +4813,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *panic = ir_build_panic(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, panic, lval); + return ir_lval_wrap(irb, scope, panic, lval, result_loc); } case BuiltinFnIdPtrCast: { @@ -4805,7 +4828,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *ptr_cast = ir_build_ptr_cast_src(irb, scope, node, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, ptr_cast, lval); + return ir_lval_wrap(irb, scope, ptr_cast, lval, result_loc); } case BuiltinFnIdBitCast: { @@ -4820,7 +4843,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, bit_cast, lval); + return ir_lval_wrap(irb, scope, bit_cast, lval, result_loc); } case BuiltinFnIdIntToPtr: { @@ -4835,7 +4858,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *int_to_ptr = ir_build_int_to_ptr(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, int_to_ptr, lval); + return ir_lval_wrap(irb, scope, int_to_ptr, lval, result_loc); } case BuiltinFnIdPtrToInt: { @@ -4845,7 +4868,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *ptr_to_int = ir_build_ptr_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, ptr_to_int, lval); + return ir_lval_wrap(irb, scope, ptr_to_int, lval, result_loc); } case BuiltinFnIdTagName: { @@ -4856,7 +4879,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *actual_tag = ir_build_union_tag(irb, scope, node, arg0_value); IrInstruction *tag_name = ir_build_tag_name(irb, scope, node, actual_tag); - return ir_lval_wrap(irb, scope, tag_name, lval); + return ir_lval_wrap(irb, scope, tag_name, lval, result_loc); } case BuiltinFnIdTagType: { @@ -4866,7 +4889,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *tag_type = ir_build_tag_type(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, tag_type, lval); + return ir_lval_wrap(irb, scope, tag_type, lval, result_loc); } case BuiltinFnIdFieldParentPtr: { @@ -4886,7 +4909,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg2_value; IrInstruction *field_parent_ptr = ir_build_field_parent_ptr(irb, scope, node, arg0_value, arg1_value, arg2_value, nullptr); - return ir_lval_wrap(irb, scope, field_parent_ptr, lval); + return ir_lval_wrap(irb, scope, field_parent_ptr, lval, result_loc); } case BuiltinFnIdByteOffsetOf: { @@ -4901,7 +4924,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *offset_of = ir_build_byte_offset_of(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, offset_of, lval); + return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); } case BuiltinFnIdBitOffsetOf: { @@ -4916,7 +4939,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, offset_of, lval); + return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); } case BuiltinFnIdInlineCall: case BuiltinFnIdNoInlineCall: @@ -4944,7 +4967,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, fn_inline, false, nullptr, nullptr, result_loc); - return ir_lval_wrap(irb, scope, call, lval); + return ir_lval_wrap(irb, scope, call, lval, result_loc); } case BuiltinFnIdNewStackCall: { @@ -4975,7 +4998,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, false, nullptr, new_stack, result_loc); - return ir_lval_wrap(irb, scope, call, lval); + return ir_lval_wrap(irb, scope, call, lval, result_loc); } case BuiltinFnIdTypeId: { @@ -4985,7 +5008,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *type_id = ir_build_type_id(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, type_id, lval); + return ir_lval_wrap(irb, scope, type_id, lval, result_loc); } case BuiltinFnIdShlExact: { @@ -5000,7 +5023,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftLeftExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdShrExact: { @@ -5015,7 +5038,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *bin_op = ir_build_bin_op(irb, scope, node, IrBinOpBitShiftRightExact, arg0_value, arg1_value, true); - return ir_lval_wrap(irb, scope, bin_op, lval); + return ir_lval_wrap(irb, scope, bin_op, lval, result_loc); } case BuiltinFnIdSetEvalBranchQuota: { @@ -5025,7 +5048,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_eval_branch_quota = ir_build_set_eval_branch_quota(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval); + return ir_lval_wrap(irb, scope, set_eval_branch_quota, lval, result_loc); } case BuiltinFnIdAlignCast: { @@ -5040,17 +5063,17 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *align_cast = ir_build_align_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, align_cast, lval); + return ir_lval_wrap(irb, scope, align_cast, lval, result_loc); } case BuiltinFnIdOpaqueType: { IrInstruction *opaque_type = ir_build_opaque_type(irb, scope, node); - return ir_lval_wrap(irb, scope, opaque_type, lval); + return ir_lval_wrap(irb, scope, opaque_type, lval, result_loc); } case BuiltinFnIdThis: { IrInstruction *this_inst = ir_gen_this(irb, scope, node); - return ir_lval_wrap(irb, scope, this_inst, lval); + return ir_lval_wrap(irb, scope, this_inst, lval, result_loc); } case BuiltinFnIdSetAlignStack: { @@ -5060,7 +5083,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *set_align_stack = ir_build_set_align_stack(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, set_align_stack, lval); + return ir_lval_wrap(irb, scope, set_align_stack, lval, result_loc); } case BuiltinFnIdArgType: { @@ -5075,7 +5098,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *arg_type = ir_build_arg_type(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, arg_type, lval); + return ir_lval_wrap(irb, scope, arg_type, lval, result_loc); } case BuiltinFnIdExport: { @@ -5095,12 +5118,12 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg2_value; IrInstruction *ir_export = ir_build_export(irb, scope, node, arg0_value, arg1_value, arg2_value); - return ir_lval_wrap(irb, scope, ir_export, lval); + return ir_lval_wrap(irb, scope, ir_export, lval, result_loc); } case BuiltinFnIdErrorReturnTrace: { IrInstruction *error_return_trace = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null); - return ir_lval_wrap(irb, scope, error_return_trace, lval); + return ir_lval_wrap(irb, scope, error_return_trace, lval, result_loc); } case BuiltinFnIdAtomicRmw: { @@ -5168,7 +5191,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *result = ir_build_int_to_enum(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdEnumToInt: { @@ -5178,7 +5201,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg0_value; IrInstruction *result = ir_build_enum_to_int(irb, scope, node, arg0_value); - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdCtz: case BuiltinFnIdPopCount: @@ -5216,7 +5239,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo default: zig_unreachable(); } - return ir_lval_wrap(irb, scope, result, lval); + return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdHasDecl: { @@ -5231,7 +5254,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *has_decl = ir_build_has_decl(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, has_decl, lval); + return ir_lval_wrap(irb, scope, has_decl, lval, result_loc); } } zig_unreachable(); @@ -5271,10 +5294,12 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr, result_loc); - return ir_lval_wrap(irb, scope, fn_call, lval); + return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); } -static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeIfBoolExpr); IrInstruction *condition = ir_gen_node(irb, node->data.if_bool_expr.condition, scope); @@ -5295,12 +5320,29 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "Else"); IrBasicBlock *endif_block = ir_create_basic_block(irb, scope, "EndIf"); - ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_comptime); + IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, condition->source_node, condition, + then_block, else_block, is_comptime); + + ResultLocPeerParent *peer_parent = allocate(1); + peer_parent->base.id = ResultLocIdPeerParent; + peer_parent->base.source_instruction = cond_br_inst; + peer_parent->parent = result_loc; + peer_parent->peer_count = 2; + peer_parent->peers = allocate(2); + peer_parent->peers[0].base.id = ResultLocIdPeer; + peer_parent->peers[0].base.source_instruction = cond_br_inst; + peer_parent->peers[0].parent = peer_parent; + peer_parent->peers[0].next_bb = else_block; + peer_parent->peers[1].base.id = ResultLocIdPeer; + peer_parent->peers[1].base.source_instruction = cond_br_inst; + peer_parent->peers[1].parent = peer_parent; + peer_parent->peers[1].next_bb = endif_block; ir_set_cursor_at_end_and_append_block(irb, then_block); Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); - IrInstruction *then_expr_result = ir_gen_node(irb, then_node, subexpr_scope); + IrInstruction *then_expr_result = ir_gen_node_extra(irb, then_node, subexpr_scope, lval, + &peer_parent->peers[0].base); if (then_expr_result == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; IrBasicBlock *after_then_block = irb->current_basic_block; @@ -5310,7 +5352,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode ir_set_cursor_at_end_and_append_block(irb, else_block); IrInstruction *else_expr_result; if (else_node) { - else_expr_result = ir_gen_node(irb, else_node, subexpr_scope); + else_expr_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_parent->peers[1].base); if (else_expr_result == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; } else { @@ -5328,7 +5370,8 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode incoming_blocks[0] = after_then_block; incoming_blocks[1] = after_else_block; - return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); + IrInstruction *phi = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); + return ir_lval_wrap(irb, scope, phi, lval, result_loc); } static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) { @@ -5346,15 +5389,28 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode return ir_gen_prefix_op_id_lval(irb, scope, node, op_id, LValNone); } -static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval) { - if (lval != LValPtr) - return value; - if (value == irb->codegen->invalid_instruction) +static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, + ResultLoc *result_loc) +{ + // This logic must be kept in sync with + // [STMT_EXPR_TEST_THING] <--- (search this token) + if (value == irb->codegen->invalid_instruction || + instr_is_unreachable(value) || + value->source_node->type == NodeTypeDefer || + value->id == IrInstructionIdDeclVarSrc) + { return value; + } + + if (lval == LValPtr) { + // We needed a pointer to a value, but we got a value. So we create + // an instruction which just makes a pointer of it. + return ir_build_ref(irb, scope, value->source_node, value, false, false); + } - // We needed a pointer to a value, but we got a value. So we create - // an instruction which just makes a const pointer of it. - return ir_build_ref(irb, scope, value->source_node, value, false, false); + // TODO remove the lval parameter here + ir_build_end_expr(irb, scope, value->source_node, value, lval, result_loc); + return value; } static PtrLen star_token_to_ptr_len(TokenId token_id) { @@ -5455,7 +5511,9 @@ static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *nod return ir_build_bool_not(irb, scope, node, value); } -static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypePrefixOpExpr); PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op; @@ -5464,18 +5522,18 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod case PrefixOpInvalid: zig_unreachable(); case PrefixOpBoolNot: - return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_bool_not(irb, scope, node), lval, result_loc); case PrefixOpBinNot: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval); + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpBinNot), lval, result_loc); case PrefixOpNegation: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval); + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegation), lval, result_loc); case PrefixOpNegationWrap: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval); + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpNegationWrap), lval, result_loc); case PrefixOpOptional: - return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval); + return ir_lval_wrap(irb, scope, ir_gen_prefix_op_id(irb, scope, node, IrUnOpOptional), lval, result_loc); case PrefixOpAddrOf: { AstNode *expr_node = node->data.prefix_op_expr.primary_expr; - return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr), lval); + return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr), lval, result_loc); } } zig_unreachable(); @@ -7677,33 +7735,33 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeTestDecl: zig_unreachable(); case NodeTypeBlock: - return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_block(irb, scope, node), lval, result_loc); case NodeTypeGroupedExpr: return ir_gen_node_raw(irb, node->data.grouped_expr, scope, lval, result_loc); case NodeTypeBinOpExpr: - return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_bin_op(irb, scope, node), lval, result_loc); case NodeTypeIntLiteral: - return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_int_lit(irb, scope, node), lval, result_loc); case NodeTypeFloatLiteral: - return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_float_lit(irb, scope, node), lval, result_loc); case NodeTypeCharLiteral: - return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_char_lit(irb, scope, node), lval, result_loc); case NodeTypeSymbol: return ir_gen_symbol(irb, scope, node, lval); case NodeTypeFnCallExpr: return ir_gen_fn_call(irb, scope, node, lval, result_loc); case NodeTypeIfBoolExpr: - return ir_lval_wrap(irb, scope, ir_gen_if_bool_expr(irb, scope, node), lval); + return ir_gen_if_bool_expr(irb, scope, node, lval, result_loc); case NodeTypePrefixOpExpr: - return ir_gen_prefix_op_expr(irb, scope, node, lval); + return ir_gen_prefix_op_expr(irb, scope, node, lval, result_loc); case NodeTypeContainerInitExpr: - return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval, result_loc); case NodeTypeVariableDeclaration: - return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval, result_loc); case NodeTypeWhileExpr: - return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node), lval, result_loc); case NodeTypeForExpr: - return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_for_expr(irb, scope, node), lval, result_loc); case NodeTypeArrayAccessExpr: return ir_gen_array_access(irb, scope, node, lval); case NodeTypeReturnExpr: @@ -7743,59 +7801,59 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); } case NodeTypeBoolLiteral: - return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_bool_literal(irb, scope, node), lval, result_loc); case NodeTypeArrayType: - return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_array_type(irb, scope, node), lval, result_loc); case NodeTypePointerType: - return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_pointer_type(irb, scope, node), lval, result_loc); case NodeTypePromiseType: - return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_promise_type(irb, scope, node), lval, result_loc); case NodeTypeStringLiteral: - return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_string_literal(irb, scope, node), lval, result_loc); case NodeTypeUndefinedLiteral: - return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_undefined_literal(irb, scope, node), lval, result_loc); case NodeTypeAsmExpr: - return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_asm_expr(irb, scope, node), lval, result_loc); case NodeTypeNullLiteral: - return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_null_literal(irb, scope, node), lval, result_loc); case NodeTypeIfErrorExpr: - return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_if_err_expr(irb, scope, node), lval, result_loc); case NodeTypeIfOptional: - return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_if_optional_expr(irb, scope, node), lval, result_loc); case NodeTypeSwitchExpr: - return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_switch_expr(irb, scope, node), lval, result_loc); case NodeTypeCompTime: return ir_gen_comptime(irb, scope, node, lval); case NodeTypeErrorType: - return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_error_type(irb, scope, node), lval, result_loc); case NodeTypeBreak: - return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_break(irb, scope, node), lval, result_loc); case NodeTypeContinue: - return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_continue(irb, scope, node), lval, result_loc); case NodeTypeUnreachable: - return ir_lval_wrap(irb, scope, ir_build_unreachable(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_build_unreachable(irb, scope, node), lval, result_loc); case NodeTypeDefer: - return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval, result_loc); case NodeTypeSliceExpr: - return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval, result_loc); case NodeTypeUnwrapErrorExpr: - return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval, result_loc); case NodeTypeContainerDecl: - return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval, result_loc); case NodeTypeFnProto: - return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval, result_loc); case NodeTypeErrorSetDecl: - return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_err_set_decl(irb, scope, node), lval, result_loc); case NodeTypeCancel: - return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_cancel(irb, scope, node), lval, result_loc); case NodeTypeResume: - return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_resume(irb, scope, node), lval, result_loc); case NodeTypeAwaitExpr: - return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_await_expr(irb, scope, node), lval, result_loc); case NodeTypeSuspend: - return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_suspend(irb, scope, node), lval, result_loc); case NodeTypeEnumLiteral: - return ir_lval_wrap(irb, scope, ir_gen_enum_literal(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_enum_literal(irb, scope, node), lval, result_loc); } zig_unreachable(); } @@ -10415,6 +10473,33 @@ static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *cons ira->const_predecessor_bb = const_predecessor_bb; } +static IrInstruction *ira_suspend(IrAnalyze *ira, IrInstruction *old_instruction, IrBasicBlock *next_bb, + IrSuspendPosition *suspend_pos) +{ + suspend_pos->basic_block_index = ira->old_bb_index; + suspend_pos->instruction_index = ira->instruction_index; + + ira->old_bb_index = next_bb->index; + ira->old_irb.current_basic_block = ira->old_irb.exec->basic_block_list.at(ira->old_bb_index); + assert(ira->old_irb.current_basic_block == next_bb); + ira->instruction_index = 0; + ira->const_predecessor_bb = nullptr; + next_bb->other = ir_get_new_bb_runtime(ira, next_bb, old_instruction); + ira->new_irb.current_basic_block = next_bb->other; + return ira->codegen->unreach_instruction; +} + +static IrInstruction *ira_resume(IrAnalyze *ira) { + IrSuspendPosition pos = ira->resume_stack.pop(); + ira->old_bb_index = pos.basic_block_index; + ira->old_irb.current_basic_block = ira->old_irb.exec->basic_block_list.at(ira->old_bb_index); + ira->instruction_index = pos.instruction_index; + ira->const_predecessor_bb = nullptr; + ira->new_irb.current_basic_block = ira->old_irb.current_basic_block->other; + assert(ira->new_irb.current_basic_block != nullptr); + return ira->codegen->unreach_instruction; +} + static void ir_finish_bb(IrAnalyze *ira) { ira->new_irb.exec->basic_block_list.append(ira->new_irb.current_basic_block); ira->instruction_index += 1; @@ -10442,8 +10527,15 @@ static void ir_finish_bb(IrAnalyze *ira) { ira->old_bb_index += 1; continue; } - ira->new_irb.current_basic_block = old_bb->other; + // if there is a resume_stack, pop one from there rather than moving on. + // the last item of the resume stack will be a basic block that will + // move on to the next one below + if (ira->resume_stack.length != 0) { + ira_resume(ira); + return; + } + ira->new_irb.current_basic_block = old_bb->other; ir_start_bb(ira, old_bb, nullptr); return; } @@ -14232,9 +14324,26 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in return &result->base; } -static IrInstruction *ir_resolve_result_loc(IrAnalyze *ira, ResultLoc *result_loc, ZigType *elem_type) { +static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_loc) { + switch (result_loc->id) { + case ResultLocIdInvalid: + case ResultLocIdPeerParent: + case ResultLocIdPeer: + zig_unreachable(); + case ResultLocIdNone: + case ResultLocIdVar: + return nullptr; + case ResultLocIdReturn: + return ira->explicit_return_type; + } + zig_unreachable(); +} + +static IrInstruction *ir_resolve_result_runtime(IrAnalyze *ira, ResultLoc *result_loc, ZigType *elem_type) { + result_loc->implicit_elem_type = elem_type; switch (result_loc->id) { case ResultLocIdInvalid: + case ResultLocIdPeerParent: zig_unreachable(); case ResultLocIdNone: return nullptr; @@ -14254,14 +14363,21 @@ static IrInstruction *ir_resolve_result_loc(IrAnalyze *ira, ResultLoc *result_lo return alloca_src->base.child; } case ResultLocIdReturn: { - //ResultLocReturn *result_loc_ret = reinterpret_cast(result_loc); - // TODO implicit cast? - return ir_build_return_ptr(ira, result_loc->source_instruction, elem_type); + ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false); + return ir_build_return_ptr(ira, result_loc->source_instruction, ptr_return_type); } + case ResultLocIdPeer: + return nullptr; } zig_unreachable(); } +static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, IrInstruction *value) { + IrInstruction *result_inst = ir_resolve_result_runtime(ira, result_loc, value->value.type); + result_loc->gen_instruction = value; + return result_inst; +} + static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) @@ -14295,12 +14411,9 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc ZigType *promise_type = get_promise_type(ira->codegen, return_type); ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type); - IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, async_return_type); - - IrInstruction *result = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, - casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc); - result->value.type = async_return_type; - return result; + return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, + casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, call_instruction->result_loc, + async_return_type); } static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, @@ -15053,12 +15166,10 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c } assert(async_allocator_inst == nullptr); - IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, - impl_fn_type_id->return_type); IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, impl_fn, nullptr, impl_param_count, casted_args, fn_inline, - call_instruction->is_async, nullptr, casted_new_stack, result_loc); - new_call_instruction->value.type = impl_fn_type_id->return_type; + call_instruction->is_async, nullptr, casted_new_stack, call_instruction->result_loc, + impl_fn_type_id->return_type); return ir_finish_anal(ira, new_call_instruction); } @@ -15152,10 +15263,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ira->codegen->invalid_instruction; } - IrInstruction *result_loc = ir_resolve_result_loc(ira, call_instruction->result_loc, return_type); IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, - call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack, result_loc); - new_call_instruction->value.type = return_type; + call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack, + call_instruction->result_loc, return_type); return ir_finish_anal(ira, new_call_instruction); } @@ -23466,7 +23576,47 @@ static IrInstruction *ir_analyze_instruction_undeclared_ident(IrAnalyze *ira, Ir return ira->codegen->invalid_instruction; } -static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { +static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstructionEndExpr *instruction) { + IrInstruction *value = instruction->value->child; + if (type_is_invalid(value->value.type)) + return ira->codegen->invalid_instruction; + + assert(instruction->lval == LValNone); + + if (instruction->result_loc->id == ResultLocIdPeer) { + ResultLocPeer *result_peer = reinterpret_cast(instruction->result_loc); + ResultLocPeerParent *peer_parent = result_peer->parent; + + if (peer_parent->resolved_type == nullptr && !ira->const_predecessor_bb) { + instruction->result_loc->implicit_elem_type = value->value.type; + instruction->result_loc->gen_instruction = value; + IrInstruction *suspended_inst = ira_suspend(ira, &instruction->base, result_peer->next_bb, + &result_peer->suspend_pos); + bool last_one = (result_peer == &peer_parent->peers[peer_parent->peer_count - 1]); + if (!last_one) { + return suspended_inst; + } + IrInstruction **instructions = allocate(peer_parent->peer_count); + for (size_t i = 0; i < peer_parent->peer_count; i += 1) { + instructions[i] = peer_parent->peers[i].base.gen_instruction; + ira->resume_stack.append(peer_parent->peers[peer_parent->peer_count - i - 1].suspend_pos); + } + ZigType *expected_type = ir_result_loc_expected_type(ira, peer_parent->parent); + peer_parent->resolved_type = ir_resolve_peer_types(ira, + peer_parent->base.source_instruction->source_node, expected_type, instructions, + peer_parent->peer_count); + return ira_resume(ira); + } + } + IrInstruction *result_loc = ir_resolve_result(ira, instruction->result_loc, value); + if (result_loc != nullptr) { + ir_analyze_store_ptr(ira, &instruction->base, result_loc, value); + } + + return ir_const_void(ira, &instruction->base); +} + +static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdWidenOrShorten: @@ -23769,17 +23919,12 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_undeclared_ident(ira, (IrInstructionUndeclaredIdent *)instruction); case IrInstructionIdAllocaSrc: return nullptr; + case IrInstructionIdEndExpr: + return ir_analyze_instruction_end_expr(ira, (IrInstructionEndExpr *)instruction); } zig_unreachable(); } -static IrInstruction *ir_analyze_instruction(IrAnalyze *ira, IrInstruction *old_instruction) { - IrInstruction *new_instruction = ir_analyze_instruction_nocast(ira, old_instruction); - ir_assert(new_instruction->value.type != nullptr || new_instruction->value.type != nullptr, old_instruction); - old_instruction->child = new_instruction; - return new_instruction; -} - // This function attempts to evaluate IR code while doing type checking and other analysis. // It emits a new IrExecutable which is partially evaluated IR code. ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, @@ -23825,8 +23970,11 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ continue; } - IrInstruction *new_instruction = ir_analyze_instruction(ira, old_instruction); + IrInstruction *new_instruction = ir_analyze_instruction_base(ira, old_instruction); if (new_instruction != nullptr) { + ir_assert(new_instruction->value.type != nullptr || new_instruction->value.type != nullptr, old_instruction); + old_instruction->child = new_instruction; + if (type_is_invalid(new_instruction->value.type) && ir_should_inline(new_exec, old_instruction->scope)) { return ira->codegen->builtin_types.entry_invalid; } @@ -23907,6 +24055,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdResizeSlice: case IrInstructionIdGlobalAsm: case IrInstructionIdUndeclaredIdent: + case IrInstructionIdEndExpr: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 20581a65cf..8eb693671a 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -158,6 +158,16 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { zig_unreachable(); } +static const char *ir_lval_str(LVal lval) { + switch (lval) { + case LValNone: + return "None"; + case LValPtr: + return "Ptr"; + } + zig_unreachable(); +} + static void ir_print_un_op(IrPrint *irp, IrInstructionUnOp *un_op_instruction) { fprintf(irp->f, "%s ", ir_un_op_id_str(un_op_instruction->op_id)); ir_print_other_instruction(irp, un_op_instruction->value); @@ -219,6 +229,12 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { return; case ResultLocIdVar: return ir_print_result_loc_var(irp, (ResultLocVar *)result_loc); + case ResultLocIdPeer: + fprintf(irp->f, "peer"); + return; + case ResultLocIdPeerParent: + fprintf(irp->f, "peer_parent"); + return; } zig_unreachable(); } @@ -1128,6 +1144,14 @@ static void ir_print_alloca_gen(IrPrint *irp, IrInstructionAllocaGen *instructio fprintf(irp->f, "Alloca(align=%" PRIu32 ",name=%s)", instruction->align, instruction->name_hint); } +static void ir_print_end_expr(IrPrint *irp, IrInstructionEndExpr *instruction) { + fprintf(irp->f, "EndExpr(result="); + ir_print_result_loc(irp, instruction->result_loc); + fprintf(irp->f, ",value="); + ir_print_other_instruction(irp, instruction->value); + fprintf(irp->f, ",lval=%s)", ir_lval_str(instruction->lval)); +} + static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { fprintf(irp->f, "inttoerr "); ir_print_other_instruction(irp, instruction->target); @@ -2014,6 +2038,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdAllocaGen: ir_print_alloca_gen(irp, (IrInstructionAllocaGen *)instruction); break; + case IrInstructionIdEndExpr: + ir_print_end_expr(irp, (IrInstructionEndExpr *)instruction); + break; } fprintf(irp->f, "\n"); } -- cgit v1.2.3 From ccce3d852681bfe60bce92a6766b4f431dd73571 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 31 May 2019 01:36:57 -0400 Subject: no-copy semantics for function forwarding ```zig fn foo() Foo { return bar(); } ``` ```llvm define internal fastcc void @foo(%Foo* nonnull sret) unnamed_addr #2 !dbg !48 { Entry: call fastcc void @bar(%Foo* sret %0), !dbg !52 ret void, !dbg !54 } ``` --- src/analyze.cpp | 2 +- src/codegen.cpp | 8 ++++++-- src/ir.cpp | 11 +++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index a62c24460e..24c81d2a3f 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -7278,6 +7278,6 @@ void src_assert(bool ok, AstNode *source_node) { buf_ptr(source_node->owner->data.structure.root_struct->path), (unsigned)source_node->line + 1, (unsigned)source_node->column + 1); } - const char *msg = "assertion failed"; + const char *msg = "assertion failed. This is a bug in the Zig compiler."; stage2_panic(msg, strlen(msg)); } diff --git a/src/codegen.cpp b/src/codegen.cpp index ccbf911686..d468b60183 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1995,7 +1995,7 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { if (!type_has_bits(instruction->value.type)) return nullptr; if (!instruction->llvm_value) { - assert(instruction->value.special != ConstValSpecialRuntime); + src_assert(instruction->value.special != ConstValSpecialRuntime, instruction->source_node); assert(instruction->value.type); render_const_val(g, &instruction->value, ""); // we might have to do some pointer casting here due to the way union @@ -2388,7 +2388,11 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { assert(g->cur_ret_ptr); - gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); + if (return_instruction->value->value.special != ConstValSpecialRuntime) { + // if it's comptime we have to do this but if it's runtime trust that + // result location mechanism took care of it. + gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); + } LLVMBuildRetVoid(g->builder); } else if (handle_is_ptr(return_type)) { LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); diff --git a/src/ir.cpp b/src/ir.cpp index f700404f29..3420a85fce 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1382,6 +1382,9 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in FnInline fn_inline, bool is_async, IrInstruction *async_allocator, IrInstruction *new_stack, ResultLoc *result_loc, ZigType *return_type) { + // must be resolved before building the call instruction + IrInstruction *resolved_result_loc = ir_resolve_result(ira, result_loc, return_type, nullptr); + IrInstructionCallGen *call_instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); call_instruction->base.value.type = return_type; @@ -1393,7 +1396,7 @@ static IrInstruction *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_in call_instruction->is_async = is_async; call_instruction->async_allocator = async_allocator; call_instruction->new_stack = new_stack; - call_instruction->result_loc = ir_resolve_result(ira, result_loc, return_type, nullptr); + call_instruction->result_loc = resolved_result_loc; if (fn_ref != nullptr) ir_ref_instruction(fn_ref, ira->new_irb.current_basic_block); for (size_t i = 0; i < arg_count; i += 1) @@ -14347,10 +14350,14 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_lo } // give nullptr for value to resolve it at runtime -// returns a result location, or nullptr if the result location was already taken care of by this function +// returns a result location, or nullptr if the result location was already taken care of static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, ZigType *value_type, IrInstruction *value) { + if (result_loc->implicit_elem_type != nullptr) { + // already resolved + return nullptr; + } result_loc->gen_instruction = value; result_loc->implicit_elem_type = value_type; switch (result_loc->id) { -- cgit v1.2.3 From eb8a132d23c5c2a365eb3a8034a381cb74c3436c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Jun 2019 17:46:58 -0400 Subject: var types, alignment, and comptime --- BRANCH_TODO | 47 ++++++++++++++++++ src/all_types.hpp | 9 +++- src/codegen.cpp | 1 + src/ir.cpp | 145 +++++++++++++++++++++++++++--------------------------- src/ir_print.cpp | 23 ++++----- 5 files changed, 141 insertions(+), 84 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 85fc9d9e18..6509246908 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,6 +1,14 @@ Scratch pad for stuff to do before merging master ================================================= + * alignment of consts + * implicit casts + * for loops + * switch expression + * struct initializations + * function call parameters + * bitCast + look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated migrate all the alloca_list to alloca_gen_list @@ -22,3 +30,42 @@ inferred comptime return ir_build_ref(irb, scope, value->source_node, value, false, false); handle if with no else + +for loops: + IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); + + IrInstruction *elem_var_type; + if (node->data.for_expr.elem_is_ptr) { + elem_var_type = pointer_type; + } else { + elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); + } + IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); +- do they need to have an implicit cast in there for the elem variable? +static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { + IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->ptr = ptr; + + ir_ref_instruction(ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value) +{ + IrInstructionPtrTypeChild *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + +coroutines + ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); + IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); +- implicit cast for the var decl + IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, + get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); diff --git a/src/all_types.hpp b/src/all_types.hpp index 79ad2f8958..c6346ca009 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2277,6 +2277,7 @@ enum IrInstructionId { IrInstructionIdSetEvalBranchQuota, IrInstructionIdPtrType, IrInstructionIdAlignCast, + IrInstructionIdImplicitCast, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, @@ -3581,7 +3582,13 @@ struct IrInstructionEndExpr { IrInstruction *value; ResultLoc *result_loc; - LVal lval; +}; + +struct IrInstructionImplicitCast { + IrInstruction base; + + IrInstruction *dest_type; + IrInstruction *target; }; enum ResultLocId { diff --git a/src/codegen.cpp b/src/codegen.cpp index d468b60183..da4be1bf23 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5612,6 +5612,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdAllocaSrc: case IrInstructionIdEndExpr: case IrInstructionIdAllocaGen: + case IrInstructionIdImplicitCast: zig_unreachable(); case IrInstructionIdDeclVarGen: diff --git a/src/ir.cpp b/src/ir.cpp index 3007edff84..35e71be1c2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -891,6 +891,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignCast *) { return IrInstructionIdAlignCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionImplicitCast *) { + return IrInstructionIdImplicitCast; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { return IrInstructionIdOpaqueType; } @@ -1574,17 +1578,15 @@ static IrInstruction *ir_build_store_ptr(IrBuilder *irb, Scope *scope, AstNode * } static IrInstruction *ir_build_var_decl_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigVar *var, IrInstruction *var_type, IrInstruction *align_value, IrInstruction *ptr) + ZigVar *var, IrInstruction *align_value, IrInstruction *ptr) { IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction(irb, scope, source_node); decl_var_instruction->base.value.special = ConstValSpecialStatic; decl_var_instruction->base.value.type = irb->codegen->builtin_types.entry_void; decl_var_instruction->var = var; - decl_var_instruction->var_type = var_type; decl_var_instruction->align_value = align_value; decl_var_instruction->ptr = ptr; - if (var_type != nullptr) ir_ref_instruction(var_type, irb->current_basic_block); if (align_value != nullptr) ir_ref_instruction(align_value, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); @@ -1655,27 +1657,6 @@ static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } -static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { - IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) -{ - IrInstructionPtrTypeChild *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_set_cold(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_cold) { IrInstructionSetCold *instruction = ir_build_instruction(irb, scope, source_node); instruction->is_cold = is_cold; @@ -2780,6 +2761,19 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } +static IrInstruction *ir_build_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *dest_type, IrInstruction *target) +{ + IrInstructionImplicitCast *instruction = ir_build_instruction(irb, scope, source_node); + instruction->dest_type = dest_type; + instruction->target = target; + + ir_ref_instruction(dest_type, irb->current_basic_block); + ir_ref_instruction(target, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionOpaqueType *instruction = ir_build_instruction(irb, scope, source_node); @@ -3199,11 +3193,10 @@ static IrInstructionAllocaGen *ir_create_alloca_gen(IrAnalyze *ira, IrInstructio } static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value, LVal lval, ResultLoc *result_loc) + IrInstruction *value, ResultLoc *result_loc) { IrInstructionEndExpr *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; - instruction->lval = lval; instruction->result_loc = result_loc; ir_ref_instruction(value, irb->current_basic_block); @@ -5399,8 +5392,7 @@ static IrInstruction *ir_gen_prefix_op_id(IrBuilder *irb, Scope *scope, AstNode } static IrInstruction *ir_expr_wrap(IrBuilder *irb, Scope *scope, IrInstruction *inst, ResultLoc *result_loc) { - // TODO remove the lval parameter here - ir_build_end_expr(irb, scope, inst->source_node, inst, LValNone, result_loc); + ir_build_end_expr(irb, scope, inst->source_node, inst, result_loc); return inst; } @@ -5607,9 +5599,12 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod return irb->codegen->invalid_instruction; } + // Used for the type expr and the align expr + Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); + IrInstruction *type_instruction; if (variable_declaration->type != nullptr) { - type_instruction = ir_gen_node(irb, variable_declaration->type, scope); + type_instruction = ir_gen_node(irb, variable_declaration->type, comptime_scope); if (type_instruction == irb->codegen->invalid_instruction) return type_instruction; } else { @@ -5635,7 +5630,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod IrInstruction *align_value = nullptr; if (variable_declaration->align_expr != nullptr) { - align_value = ir_gen_node(irb, variable_declaration->align_expr, scope); + align_value = ir_gen_node(irb, variable_declaration->align_expr, comptime_scope); if (align_value == irb->codegen->invalid_instruction) return align_value; } @@ -5656,19 +5651,24 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod result_loc_var->base.id = ResultLocIdVar; result_loc_var->base.source_instruction = alloca; result_loc_var->var = var; + ResultLoc *init_result_loc = (type_instruction == nullptr) ? &result_loc_var->base : nullptr; // Temporarily set the name of the IrExecutable to the VariableDeclaration // so that the struct or enum from the init expression inherits the name. Buf *old_exec_name = irb->exec->name; irb->exec->name = variable_declaration->symbol; - IrInstruction *init_value = ir_gen_node_extra(irb, variable_declaration->expr, scope, LValNone, - &result_loc_var->base); + IrInstruction *init_value = ir_gen_node_extra(irb, variable_declaration->expr, scope, LValNone, init_result_loc); irb->exec->name = old_exec_name; if (init_value == irb->codegen->invalid_instruction) - return init_value; + return irb->codegen->invalid_instruction; + + if (type_instruction != nullptr) { + IrInstruction *implicit_cast = ir_build_implicit_cast(irb, scope, node, type_instruction, init_value); + ir_build_end_expr(irb, scope, node, implicit_cast, &result_loc_var->base); + } - return ir_build_var_decl_src(irb, scope, node, var, type_instruction, align_value, alloca); + return ir_build_var_decl_src(irb, scope, node, var, align_value, alloca); } static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -5725,7 +5725,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n err_val_ptr, false); IrInstruction *var_value = node->data.while_expr.var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); - ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, nullptr, var_value); + ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); } ZigList incoming_values = {0}; @@ -5767,7 +5767,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n true, false, false, is_comptime); Scope *err_scope = err_var->child_scope; IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); - ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, nullptr, err_var_value); + ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, err_var_value); IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); if (else_result == irb->codegen->invalid_instruction) @@ -5811,7 +5811,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); IrInstruction *var_value = node->data.while_expr.var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); - ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, nullptr, var_value); + ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_value); ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -5953,14 +5953,6 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo if (array_val_ptr == irb->codegen->invalid_instruction) return array_val_ptr; - IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); - IrInstruction *elem_var_type; - if (node->data.for_expr.elem_is_ptr) { - elem_var_type = pointer_type; - } else { - elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); - } - IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); @@ -5970,7 +5962,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo Scope *child_scope = elem_var->child_scope; IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); - ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, elem_var_type, nullptr, undefined_value); + ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, nullptr, undefined_value); IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); AstNode *index_var_source_node; @@ -5985,10 +5977,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo } child_scope = index_var->child_scope; - IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); - ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, usize, nullptr, zero); + ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, nullptr, zero); IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); @@ -6380,7 +6371,6 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); Scope *var_scope; if (var_symbol) { - IrInstruction *var_type = nullptr; bool is_shadowable = false; bool is_const = true; ZigVar *var = ir_create_var(irb, node, subexpr_scope, @@ -6388,7 +6378,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); - ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_value); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -6455,7 +6445,6 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); Scope *var_scope; if (var_symbol) { - IrInstruction *var_type = nullptr; bool is_shadowable = false; IrInstruction *var_is_comptime = force_comptime ? ir_build_const_bool(irb, subexpr_scope, node, true) : ir_build_test_comptime(irb, subexpr_scope, node, err_val); ZigVar *var = ir_create_var(irb, node, subexpr_scope, @@ -6463,7 +6452,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); IrInstruction *var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, subexpr_scope, node, var_ptr_value); - ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_value); var_scope = var->child_scope; } else { var_scope = subexpr_scope; @@ -6481,14 +6470,13 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * if (else_node) { Scope *err_var_scope; if (err_symbol) { - IrInstruction *var_type = nullptr; bool is_shadowable = false; bool is_const = true; ZigVar *var = ir_create_var(irb, node, subexpr_scope, err_symbol, is_const, is_const, is_shadowable, is_comptime); IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); - ir_build_var_decl_src(irb, subexpr_scope, node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_value); err_var_scope = var->child_scope; } else { err_var_scope = subexpr_scope; @@ -6551,8 +6539,7 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, target_value_ptr); } - IrInstruction *var_type = nullptr; // infer the type - ir_build_var_decl_src(irb, scope, var_symbol_node, var, var_type, nullptr, var_value); + ir_build_var_decl_src(irb, scope, var_symbol_node, var, nullptr, var_value); } else { child_scope = scope; } @@ -7018,7 +7005,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode is_const, is_const, is_shadowable, is_comptime); err_scope = var->child_scope; IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); - ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, nullptr, err_val); + ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, err_val); } else { err_scope = parent_scope; } @@ -7509,7 +7496,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); ir_build_await_bookkeeping(irb, scope, node, promise_result_type); - ir_build_var_decl_src(irb, scope, node, result_var, promise_result_type, nullptr, undefined_value); + ir_build_var_decl_src(irb, scope, node, result_var, nullptr, undefined_value); IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); @@ -7940,17 +7927,13 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); - ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); - IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa - ir_build_var_decl_src(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef); + ir_build_var_decl_src(irb, coro_scope, node, promise_var, nullptr, undef); coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); - IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, - get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); - ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, await_handle_type_val, nullptr, null_value); + ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, nullptr, null_value); irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); u8_ptr_type = ir_build_const_type(irb, coro_scope, node, @@ -7960,11 +7943,11 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec coro_id = ir_build_coro_id(irb, coro_scope, node, promise_as_u8_ptr); coro_size_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *coro_size = ir_build_coro_size(irb, coro_scope, node); - ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, nullptr, coro_size); + ir_build_var_decl_src(irb, coro_scope, node, coro_size_var, nullptr, coro_size); IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, coro_scope, node, ImplicitAllocatorIdArg); irb->exec->coro_allocator_var = ir_create_var(irb, node, coro_scope, nullptr, true, true, true, const_bool_false); - ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, nullptr, implicit_allocator_ptr); + ir_build_var_decl_src(irb, coro_scope, node, irb->exec->coro_allocator_var, nullptr, implicit_allocator_ptr); Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME); IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name); IrInstruction *realloc_fn = ir_build_load_ptr(irb, coro_scope, node, realloc_fn_ptr); @@ -14375,20 +14358,24 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, Z case ResultLocIdNone: return nullptr; case ResultLocIdVar: { - // TODO implicit cast? ResultLocVar *result_loc_var = reinterpret_cast(result_loc); assert(result_loc->source_instruction->id == IrInstructionIdAllocaSrc); IrInstructionAllocaSrc *alloca_src = reinterpret_cast(result_loc->source_instruction); if (alloca_src->base.child == nullptr) { - uint32_t align = 0; // TODO - bool force_comptime = false; // TODO bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime && result_loc_var->var->gen_is_const; IrInstruction *alloca_gen; if (is_comptime) { alloca_gen = ir_get_ref(ira, result_loc->source_instruction, value, true, false); } else { + uint32_t align = 0; + if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) { + return ira->codegen->invalid_instruction; + } + bool force_comptime; + if (!ir_resolve_comptime(ira, alloca_src->is_comptime->child, &force_comptime)) + return ira->codegen->invalid_instruction; alloca_gen = ir_analyze_alloca(ira, result_loc->source_instruction, value_type, align, alloca_src->name_hint, force_comptime); } @@ -14409,6 +14396,19 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, Z zig_unreachable(); } +static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrInstructionImplicitCast *instruction) { + ZigType *dest_type = ir_resolve_type(ira, instruction->dest_type->child); + if (type_is_invalid(dest_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *target = instruction->target->child; + if (type_is_invalid(target->value.type)) + return ira->codegen->invalid_instruction; + + return ir_implicit_cast(ira, target, dest_type); +} + + static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) @@ -23612,8 +23612,6 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - assert(instruction->lval == LValNone); - if (instruction->result_loc->id == ResultLocIdPeer) { ResultLocPeer *result_peer = reinterpret_cast(instruction->result_loc); ResultLocPeerParent *peer_parent = result_peer->parent; @@ -23640,7 +23638,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct } } IrInstruction *result_loc = ir_resolve_result(ira, instruction->result_loc, value->value.type, value); - if (result_loc != nullptr) { + if (result_loc != nullptr && !type_is_invalid(result_loc->value.type)) { ir_analyze_store_ptr(ira, &instruction->base, result_loc, value); } @@ -23874,6 +23872,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_ptr_type(ira, (IrInstructionPtrType *)instruction); case IrInstructionIdAlignCast: return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction); + case IrInstructionIdImplicitCast: + return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction); case IrInstructionIdOpaqueType: return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); case IrInstructionIdSetAlignStack: @@ -24165,6 +24165,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTypeInfo: case IrInstructionIdTypeId: case IrInstructionIdAlignCast: + case IrInstructionIdImplicitCast: case IrInstructionIdOpaqueType: case IrInstructionIdArgType: case IrInstructionIdTagType: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 8eb693671a..fca5f2edc2 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -158,16 +158,6 @@ static const char *ir_un_op_id_str(IrUnOp op_id) { zig_unreachable(); } -static const char *ir_lval_str(LVal lval) { - switch (lval) { - case LValNone: - return "None"; - case LValPtr: - return "Ptr"; - } - zig_unreachable(); -} - static void ir_print_un_op(IrPrint *irp, IrInstructionUnOp *un_op_instruction) { fprintf(irp->f, "%s ", ir_un_op_id_str(un_op_instruction->op_id)); ir_print_other_instruction(irp, un_op_instruction->value); @@ -1149,7 +1139,7 @@ static void ir_print_end_expr(IrPrint *irp, IrInstructionEndExpr *instruction) { ir_print_result_loc(irp, instruction->result_loc); fprintf(irp->f, ",value="); ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ",lval=%s)", ir_lval_str(instruction->lval)); + fprintf(irp->f, ")"); } static void ir_print_int_to_err(IrPrint *irp, IrInstructionIntToErr *instruction) { @@ -1274,6 +1264,14 @@ static void ir_print_align_cast(IrPrint *irp, IrInstructionAlignCast *instructio fprintf(irp->f, ")"); } +static void ir_print_implicit_cast(IrPrint *irp, IrInstructionImplicitCast *instruction) { + fprintf(irp->f, "@implicitCast("); + ir_print_other_instruction(irp, instruction->dest_type); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->target); + fprintf(irp->f, ")"); +} + static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) { fprintf(irp->f, "@OpaqueType()"); } @@ -1912,6 +1910,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdAlignCast: ir_print_align_cast(irp, (IrInstructionAlignCast *)instruction); break; + case IrInstructionIdImplicitCast: + ir_print_implicit_cast(irp, (IrInstructionImplicitCast *)instruction); + break; case IrInstructionIdOpaqueType: ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); break; -- cgit v1.2.3 From b6108eed522b7a0122d305dc1a74de8f12f20d5b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Jun 2019 19:11:41 -0400 Subject: fix alignment of consts --- BRANCH_TODO | 1 - src/all_types.hpp | 1 + src/codegen.cpp | 3 ++- src/ir.cpp | 21 ++++++++++++--------- 4 files changed, 15 insertions(+), 11 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 6509246908..e809e2b4d8 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,6 @@ Scratch pad for stuff to do before merging master ================================================= - * alignment of consts * implicit casts * for loops * switch expression diff --git a/src/all_types.hpp b/src/all_types.hpp index c6346ca009..0df5384c7a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -292,6 +292,7 @@ struct RuntimeHintSlice { struct ConstGlobalRefs { LLVMValueRef llvm_value; LLVMValueRef llvm_global; + uint32_t align; }; struct ConstExprValue { diff --git a/src/codegen.cpp b/src/codegen.cpp index da4be1bf23..b03068eb7d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6599,7 +6599,8 @@ static void render_const_val_global(CodeGen *g, ConstExprValue *const_val, const LLVMSetLinkage(global_value, LLVMInternalLinkage); LLVMSetGlobalConstant(global_value, true); LLVMSetUnnamedAddr(global_value, true); - LLVMSetAlignment(global_value, get_abi_alignment(g, const_val->type)); + LLVMSetAlignment(global_value, (const_val->global_refs->align == 0) ? + get_abi_alignment(g, const_val->type) : const_val->global_refs->align); const_val->global_refs->llvm_global = global_value; } diff --git a/src/ir.cpp b/src/ir.cpp index 35e71be1c2..f8e77cdd72 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14363,19 +14363,22 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, ResultLoc *result_loc, Z IrInstructionAllocaSrc *alloca_src = reinterpret_cast(result_loc->source_instruction); if (alloca_src->base.child == nullptr) { - bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime && - result_loc_var->var->gen_is_const; + bool force_comptime; + if (!ir_resolve_comptime(ira, alloca_src->is_comptime->child, &force_comptime)) + return ira->codegen->invalid_instruction; + bool is_comptime = force_comptime || (value != nullptr && + value->value.special != ConstValSpecialRuntime && result_loc_var->var->gen_is_const); + uint32_t align = 0; + if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) { + return ira->codegen->invalid_instruction; + } IrInstruction *alloca_gen; if (is_comptime) { + if (align > value->value.global_refs->align) { + value->value.global_refs->align = align; + } alloca_gen = ir_get_ref(ira, result_loc->source_instruction, value, true, false); } else { - uint32_t align = 0; - if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) { - return ira->codegen->invalid_instruction; - } - bool force_comptime; - if (!ir_resolve_comptime(ira, alloca_src->is_comptime->child, &force_comptime)) - return ira->codegen->invalid_instruction; alloca_gen = ir_analyze_alloca(ira, result_loc->source_instruction, value_type, align, alloca_src->name_hint, force_comptime); } -- cgit v1.2.3 From d4054e35fe3a6ba4b4f0d1a0da0e0149f21b49a4 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Jun 2019 20:56:22 -0400 Subject: while loops Note that neither the payload capture variable nor the error capture variable require a stack allocation. ```zig export fn entry() void { var c: anyerror!i32 = 1234; while (c) |hi| {} else |e| {} } ``` ```llvm define void @entry() #2 !dbg !39 { Entry: %c = alloca { i16, i32 }, align 4 %0 = bitcast { i16, i32 }* %c to i8*, !dbg !52 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast ({ i16, i32 }* @0 to i8*), i64 8, i1 false), !dbg !52 call void @llvm.dbg.declare(metadata { i16, i32 }* %c, metadata !43, metadata !DIExpression()), !dbg !52 br label %WhileCond, !dbg !53 WhileCond: ; preds = %WhileBody, %Entry %1 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %c, i32 0, i32 0, !dbg !54 %2 = load i16, i16* %1, align 2, !dbg !54 %3 = icmp ne i16 %2, 0, !dbg !54 br i1 %3, label %WhileElse, label %WhileBody, !dbg !54 WhileBody: ; preds = %WhileCond %4 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %c, i32 0, i32 1, !dbg !53 call void @llvm.dbg.declare(metadata i32* %4, metadata !50, metadata !DIExpression()), !dbg !53 br label %WhileCond, !dbg !53 WhileElse: ; preds = %WhileCond %5 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %c, i32 0, i32 0, !dbg !55 call void @llvm.dbg.declare(metadata i16* %5, metadata !51, metadata !DIExpression()), !dbg !55 ret void, !dbg !56 } ``` --- BRANCH_TODO | 43 ++-------------------- src/all_types.hpp | 3 +- src/codegen.cpp | 14 ++++---- src/ir.cpp | 106 ++++++++++++++++++++++++++++++++++++++---------------- src/ir_print.cpp | 2 +- 5 files changed, 86 insertions(+), 82 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index e809e2b4d8..c85a7aea81 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,8 @@ Scratch pad for stuff to do before merging master ================================================= - * implicit casts +migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize + * for loops * switch expression * struct initializations @@ -12,8 +13,6 @@ look at all the ir_gen_node ir_gen_node_extra calls and make sure result locatio migrate all the alloca_list to alloca_gen_list -migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize - inferred comptime @@ -30,41 +29,3 @@ inferred comptime handle if with no else -for loops: - IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); - - IrInstruction *elem_var_type; - if (node->data.for_expr.elem_is_ptr) { - elem_var_type = pointer_type; - } else { - elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); - } - IrInstruction *usize = ir_build_const_type(irb, child_scope, node, irb->codegen->builtin_types.entry_usize); -- do they need to have an implicit cast in there for the elem variable? -static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { - IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) -{ - IrInstructionPtrTypeChild *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - -coroutines - ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); - IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); -- implicit cast for the var decl - IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, - get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); diff --git a/src/all_types.hpp b/src/all_types.hpp index 0df5384c7a..8726c562d9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3087,10 +3087,11 @@ struct IrInstructionTestErr { IrInstruction *value; }; +// Takes an error union pointer, returns a pointer to the error code. struct IrInstructionUnwrapErrCode { IrInstruction base; - IrInstruction *err_union; + IrInstruction *err_union_ptr; }; struct IrInstructionUnwrapErrPayload { diff --git a/src/codegen.cpp b/src/codegen.cpp index b03068eb7d..84d5777530 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4878,18 +4878,16 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) { - ZigType *ptr_type = instruction->err_union->value.type; + ZigType *ptr_type = instruction->err_union_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union); - LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); - - if (type_has_bits(payload_type)) { - LLVMValueRef err_val_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); - return gen_load_untyped(g, err_val_ptr, 0, false, ""); + LLVMValueRef err_union_ptr = ir_llvm_value(g, instruction->err_union_ptr); + if (!type_has_bits(payload_type)) { + return err_union_ptr; } else { - return err_union_handle; + LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); + return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); } } diff --git a/src/ir.cpp b/src/ir.cpp index f8e77cdd72..1afa435d19 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1657,6 +1657,27 @@ static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } +static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { + IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); + instruction->ptr = ptr; + + ir_ref_instruction(ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value) +{ + IrInstructionPtrTypeChild *instruction = ir_build_instruction( + irb, scope, source_node); + instruction->value = value; + + ir_ref_instruction(value, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_set_cold(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_cold) { IrInstructionSetCold *instruction = ir_build_instruction(irb, scope, source_node); instruction->is_cold = is_cold; @@ -2371,12 +2392,12 @@ static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *s } static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *err_union) + IrInstruction *err_union_ptr) { IrInstructionUnwrapErrCode *instruction = ir_build_instruction(irb, scope, source_node); - instruction->err_union = err_union; + instruction->err_union_ptr = err_union_ptr; - ir_ref_instruction(err_union, irb->current_basic_block); + ir_ref_instruction(err_union_ptr, irb->current_basic_block); return &instruction->base; } @@ -3505,7 +3526,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, ir_set_cursor_at_end_and_append_block(irb, return_block); if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) { - IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); + IrInstruction *err_val_ptr = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr); + IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); if (irb->codegen->have_err_ret_tracing && !should_inline) { ir_build_save_err_ret_addr(irb, scope, node); } @@ -5721,11 +5743,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, body_block); if (var_symbol) { - IrInstruction *var_ptr_value = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node, + IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node, err_val_ptr, false); - IrInstruction *var_value = node->data.while_expr.var_is_ptr ? - var_ptr_value : ir_build_load_ptr(irb, payload_scope, symbol_node, var_ptr_value); - ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_value); + IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? + ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr; + ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr); } ZigList incoming_values = {0}; @@ -5766,8 +5788,8 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ZigVar *err_var = ir_create_var(irb, err_symbol_node, scope, err_symbol, true, false, false, is_comptime); Scope *err_scope = err_var->child_scope; - IrInstruction *err_var_value = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); - ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, err_var_value); + IrInstruction *err_ptr = ir_build_unwrap_err_code(irb, err_scope, err_symbol_node, err_val_ptr); + ir_build_var_decl_src(irb, err_scope, symbol_node, err_var, nullptr, err_ptr); IrInstruction *else_result = ir_gen_node(irb, else_node, err_scope); if (else_result == irb->codegen->invalid_instruction) @@ -5808,10 +5830,10 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n } ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstruction *var_ptr_value = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); - IrInstruction *var_value = node->data.while_expr.var_is_ptr ? - var_ptr_value : ir_build_load_ptr(irb, child_scope, symbol_node, var_ptr_value); - ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_value); + IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); + IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? + ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr; + ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr); ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -5953,6 +5975,15 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo if (array_val_ptr == irb->codegen->invalid_instruction) return array_val_ptr; + IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); + + IrInstruction *elem_var_type; + if (node->data.for_expr.elem_is_ptr) { + elem_var_type = pointer_type; + } else { + elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); + } + IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); @@ -5961,8 +5992,9 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); Scope *child_scope = elem_var->child_scope; - IrInstruction *undefined_value = ir_build_const_undefined(irb, child_scope, elem_node); - ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, nullptr, undefined_value); + IrInstruction *undef = ir_build_const_undefined(irb, parent_scope, elem_node); + IrInstruction *undef_elem_var_type = ir_build_implicit_cast(irb, parent_scope, elem_node, elem_var_type, undef); + ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, nullptr, undef_elem_var_type); IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); AstNode *index_var_source_node; @@ -6475,8 +6507,8 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * ZigVar *var = ir_create_var(irb, node, subexpr_scope, err_symbol, is_const, is_const, is_shadowable, is_comptime); - IrInstruction *var_value = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); - ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_value); + IrInstruction *err_ptr = ir_build_unwrap_err_code(irb, subexpr_scope, node, err_val_ptr); + ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, err_ptr); err_var_scope = var->child_scope; } else { err_var_scope = subexpr_scope; @@ -7004,8 +7036,8 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode ZigVar *var = ir_create_var(irb, node, parent_scope, var_name, is_const, is_const, is_shadowable, is_comptime); err_scope = var->child_scope; - IrInstruction *err_val = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); - ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, err_val); + IrInstruction *err_ptr = ir_build_unwrap_err_code(irb, err_scope, node, err_union_ptr); + ir_build_var_decl_src(irb, err_scope, var_node, var, nullptr, err_ptr); } else { err_scope = parent_scope; } @@ -7482,7 +7514,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise); IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false); - IrInstruction *undefined_value = ir_build_const_undefined(irb, scope, node); + IrInstruction *undef = ir_build_const_undefined(irb, scope, node); IrInstruction *usize_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_usize); IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); IrInstruction *inverted_ptr_mask = ir_build_const_usize(irb, scope, node, 0x7); // 0b111 @@ -7496,7 +7528,8 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); ir_build_await_bookkeeping(irb, scope, node, promise_result_type); - ir_build_var_decl_src(irb, scope, node, result_var, nullptr, undefined_value); + IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef); + ir_build_var_decl_src(irb, scope, node, result_var, nullptr, undef_promise_result); IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); @@ -7928,12 +7961,18 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type; IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node); // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa - ir_build_var_decl_src(irb, coro_scope, node, promise_var, nullptr, undef); + ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); + IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); + IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef); + ir_build_var_decl_src(irb, coro_scope, node, promise_var, nullptr, undef_coro_frame); coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); ZigVar *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false); IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); - ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, nullptr, null_value); + IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, + get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); + IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value); + ir_build_var_decl_src(irb, coro_scope, node, await_handle_var, nullptr, null_await_handle); irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); u8_ptr_type = ir_build_const_type(irb, coro_scope, node, @@ -13872,7 +13911,8 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, return ira->codegen->invalid_instruction; } - assert(var_ptr->value.type->id == ZigTypeIdPointer); + // The ir_build_var_decl_src call is supposed to pass a pointer to the allocation, not an initialization value. + ir_assert(var_ptr->value.type->id == ZigTypeIdPointer, &decl_var_instruction->base); ZigType *result_type = var_ptr->value.type->data.pointer.child_type; if (type_is_invalid(result_type)) { @@ -21526,13 +21566,14 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) { - IrInstruction *base_ptr = instruction->err_union->child; + IrInstruction *base_ptr = instruction->err_union_ptr->child; if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; ZigType *ptr_type = base_ptr->value.type; // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. assert(ptr_type->id == ZigTypeIdPointer); + bool is_ptr_const = ptr_type->data.pointer.is_const; ZigType *type_entry = ptr_type->data.pointer.child_type; if (type_is_invalid(type_entry)) @@ -21554,19 +21595,22 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrI return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; - assert(err); + assert(err != nullptr); - IrInstruction *result = ir_const(ira, &instruction->base, + IrInstruction *err_set_val = ir_const(ira, &instruction->base, type_entry->data.error_union.err_set_type); - result->value.data.x_err_set = err; - return result; + err_set_val->value.data.x_err_set = err; + err_set_val->value.parent.id = ConstParentIdErrUnionCode; + err_set_val->value.parent.data.p_err_union_code.err_union_val = err_union_val; + + return ir_get_ref(ira, &instruction->base, err_set_val, is_ptr_const, false); } } } IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, instruction->base.scope, instruction->base.source_node, base_ptr); - result->value.type = type_entry->data.error_union.err_set_type; + result->value.type = get_pointer_to_type(ira->codegen, type_entry->data.error_union.err_set_type, is_ptr_const); return result; } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index fca5f2edc2..7906d57be0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -957,7 +957,7 @@ static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *instruction) { fprintf(irp->f, "UnwrapErrorCode("); - ir_print_other_instruction(irp, instruction->err_union); + ir_print_other_instruction(irp, instruction->err_union_ptr); fprintf(irp->f, ")"); } -- cgit v1.2.3 From 143d6ada8f93872b94a8f20927e11cae243028d9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 3 Jun 2019 21:40:56 -0400 Subject: no-copy semantics for for loops Note that only the index variable requires a stack allocation, and the memcpy for the element is gone. ```zig export fn entry() void { var buf: [10]i32 = undefined; for (buf) |x| {} } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %buf = alloca [10 x i32], align 4 %i = alloca i64, align 8 %0 = bitcast [10 x i32]* %buf to i8*, !dbg !47 call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 40, i1 false), !dbg !47 call void @llvm.dbg.declare(metadata [10 x i32]* %buf, metadata !39, metadata !DIExpression()), !dbg !47 store i64 0, i64* %i, align 8, !dbg !48 call void @llvm.dbg.declare(metadata i64* %i, metadata !45, metadata !DIExpression()), !dbg !48 br label %ForCond, !dbg !48 ForCond: ; preds = %ForBody, %Entry %1 = load i64, i64* %i, align 8, !dbg !48 %2 = icmp ult i64 %1, 10, !dbg !48 br i1 %2, label %ForBody, label %ForEnd, !dbg !48 ForBody: ; preds = %ForCond %3 = getelementptr inbounds [10 x i32], [10 x i32]* %buf, i64 0, i64 %1, !dbg !48 call void @llvm.dbg.declare(metadata i32* %3, metadata !46, metadata !DIExpression()), !dbg !49 %4 = add nuw i64 %1, 1, !dbg !48 store i64 %4, i64* %i, align 8, !dbg !48 br label %ForCond, !dbg !48 ForEnd: ; preds = %ForCond ret void, !dbg !50 } ``` --- BRANCH_TODO | 1 - src/all_types.hpp | 14 ---- src/codegen.cpp | 2 - src/ir.cpp | 187 +++++++++++++----------------------------------------- src/ir_print.cpp | 18 ------ 5 files changed, 44 insertions(+), 178 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index c85a7aea81..70fad23791 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -3,7 +3,6 @@ Scratch pad for stuff to do before merging master migrate ir_build_var_decl_src to use ir_build_alloca_src and explicitly initialize - * for loops * switch expression * struct initializations * function call parameters diff --git a/src/all_types.hpp b/src/all_types.hpp index 8726c562d9..6f504efd9c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2191,8 +2191,6 @@ enum IrInstructionId { IrInstructionIdUnionInit, IrInstructionIdUnreachable, IrInstructionIdTypeOf, - IrInstructionIdToPtrType, - IrInstructionIdPtrTypeChild, IrInstructionIdSetCold, IrInstructionIdSetRuntimeSafety, IrInstructionIdSetFloatMode, @@ -2679,18 +2677,6 @@ struct IrInstructionTypeOf { IrInstruction *value; }; -struct IrInstructionToPtrType { - IrInstruction base; - - IrInstruction *ptr; -}; - -struct IrInstructionPtrTypeChild { - IrInstruction base; - - IrInstruction *value; -}; - struct IrInstructionSetCold { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 84d5777530..eecc2239db 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5539,8 +5539,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdInvalid: case IrInstructionIdConst: case IrInstructionIdTypeOf: - case IrInstructionIdToPtrType: - case IrInstructionIdPtrTypeChild: case IrInstructionIdFieldPtr: case IrInstructionIdSetCold: case IrInstructionIdSetRuntimeSafety: diff --git a/src/ir.cpp b/src/ir.cpp index 1afa435d19..3b0ed7a17d 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -523,14 +523,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeOf *) { return IrInstructionIdTypeOf; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionToPtrType *) { - return IrInstructionIdToPtrType; -} - -static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrTypeChild *) { - return IrInstructionIdPtrTypeChild; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionSetCold *) { return IrInstructionIdSetCold; } @@ -1657,27 +1649,6 @@ static IrInstruction *ir_build_typeof(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } -static IrInstruction *ir_build_to_ptr_type(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *ptr) { - IrInstructionToPtrType *instruction = ir_build_instruction(irb, scope, source_node); - instruction->ptr = ptr; - - ir_ref_instruction(ptr, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_ptr_type_child(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) -{ - IrInstructionPtrTypeChild *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->value = value; - - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_set_cold(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *is_cold) { IrInstructionSetCold *instruction = ir_build_instruction(irb, scope, source_node); instruction->is_cold = is_cold; @@ -5611,6 +5582,14 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A } } +static ResultLocVar *create_var_result_loc(IrInstruction *alloca, ZigVar *var) { + ResultLocVar *result_loc_var = allocate(1); + result_loc_var->base.id = ResultLocIdVar; + result_loc_var->base.source_instruction = alloca; + result_loc_var->var = var; + return result_loc_var; +} + static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *node) { assert(node->type == NodeTypeVariableDeclaration); @@ -5669,10 +5648,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod buf_ptr(variable_declaration->symbol), is_comptime); // Create a result location for the initialization expression. - ResultLocVar *result_loc_var = allocate(1); - result_loc_var->base.id = ResultLocIdVar; - result_loc_var->base.source_instruction = alloca; - result_loc_var->var = var; + ResultLocVar *result_loc_var = create_var_result_loc(alloca, var); ResultLoc *init_result_loc = (type_instruction == nullptr) ? &result_loc_var->base : nullptr; // Temporarily set the name of the IrExecutable to the VariableDeclaration @@ -5975,73 +5951,62 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo if (array_val_ptr == irb->codegen->invalid_instruction) return array_val_ptr; - IrInstruction *pointer_type = ir_build_to_ptr_type(irb, parent_scope, array_node, array_val_ptr); - - IrInstruction *elem_var_type; - if (node->data.for_expr.elem_is_ptr) { - elem_var_type = pointer_type; - } else { - elem_var_type = ir_build_ptr_type_child(irb, parent_scope, elem_node, pointer_type); - } - IrInstruction *is_comptime = ir_build_const_bool(irb, parent_scope, node, ir_should_inline(irb->exec, parent_scope) || node->data.for_expr.is_inline); - // TODO make it an error to write to element variable or i variable. - Buf *elem_var_name = elem_node->data.symbol_expr.symbol; - ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); - Scope *child_scope = elem_var->child_scope; - - IrInstruction *undef = ir_build_const_undefined(irb, parent_scope, elem_node); - IrInstruction *undef_elem_var_type = ir_build_implicit_cast(irb, parent_scope, elem_node, elem_var_type, undef); - ir_build_var_decl_src(irb, child_scope, elem_node, elem_var, nullptr, undef_elem_var_type); - IrInstruction *elem_var_ptr = ir_build_var_ptr(irb, child_scope, node, elem_var); - AstNode *index_var_source_node; ZigVar *index_var; + const char *index_var_name; if (index_node) { index_var_source_node = index_node; - Buf *index_var_name = index_node->data.symbol_expr.symbol; - index_var = ir_create_var(irb, index_node, child_scope, index_var_name, true, false, false, is_comptime); + Buf *index_var_name_buf = index_node->data.symbol_expr.symbol; + index_var = ir_create_var(irb, index_node, parent_scope, index_var_name_buf, true, false, false, is_comptime); + index_var_name = buf_ptr(index_var_name_buf); } else { index_var_source_node = node; - index_var = ir_create_var(irb, node, child_scope, nullptr, true, false, true, is_comptime); + index_var = ir_create_var(irb, node, parent_scope, nullptr, true, false, true, is_comptime); + index_var_name = "i"; } - child_scope = index_var->child_scope; + parent_scope = index_var->parent_scope; - IrInstruction *zero = ir_build_const_usize(irb, child_scope, node, 0); - IrInstruction *one = ir_build_const_usize(irb, child_scope, node, 1); - ir_build_var_decl_src(irb, child_scope, index_var_source_node, index_var, nullptr, zero); - IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); + IrInstruction *index_alloca = ir_build_alloca_src(irb, parent_scope, node, nullptr, index_var_name, is_comptime); + ResultLocVar *var_result_loc = create_var_result_loc(index_alloca, index_var); + IrInstruction *zero = ir_build_const_usize(irb, parent_scope, node, 0); + ir_build_end_expr(irb, parent_scope, node, zero, &var_result_loc->base); + ir_build_var_decl_src(irb, parent_scope, index_var_source_node, index_var, nullptr, index_alloca); + IrInstruction *one = ir_build_const_usize(irb, parent_scope, node, 1); + IrInstruction *index_ptr = ir_build_var_ptr(irb, parent_scope, node, index_var); - IrBasicBlock *cond_block = ir_create_basic_block(irb, child_scope, "ForCond"); - IrBasicBlock *body_block = ir_create_basic_block(irb, child_scope, "ForBody"); - IrBasicBlock *end_block = ir_create_basic_block(irb, child_scope, "ForEnd"); - IrBasicBlock *else_block = else_node ? ir_create_basic_block(irb, child_scope, "ForElse") : end_block; - IrBasicBlock *continue_block = ir_create_basic_block(irb, child_scope, "ForContinue"); + + IrBasicBlock *cond_block = ir_create_basic_block(irb, parent_scope, "ForCond"); + IrBasicBlock *body_block = ir_create_basic_block(irb, parent_scope, "ForBody"); + IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "ForEnd"); + IrBasicBlock *else_block = else_node ? ir_create_basic_block(irb, parent_scope, "ForElse") : end_block; + IrBasicBlock *continue_block = ir_create_basic_block(irb, parent_scope, "ForContinue"); Buf *len_field_name = buf_create_from_str("len"); - IrInstruction *len_ref = ir_build_field_ptr(irb, child_scope, node, array_val_ptr, len_field_name); - IrInstruction *len_val = ir_build_load_ptr(irb, child_scope, node, len_ref); - ir_build_br(irb, child_scope, node, cond_block, is_comptime); + IrInstruction *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name); + IrInstruction *len_val = ir_build_load_ptr(irb, parent_scope, node, len_ref); + ir_build_br(irb, parent_scope, node, cond_block, is_comptime); ir_set_cursor_at_end_and_append_block(irb, cond_block); - IrInstruction *index_val = ir_build_load_ptr(irb, child_scope, node, index_ptr); - IrInstruction *cond = ir_build_bin_op(irb, child_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); + IrInstruction *index_val = ir_build_load_ptr(irb, parent_scope, node, index_ptr); + IrInstruction *cond = ir_build_bin_op(irb, parent_scope, node, IrBinOpCmpLessThan, index_val, len_val, false); IrBasicBlock *after_cond_block = irb->current_basic_block; IrInstruction *void_else_value = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, parent_scope, node)); - ir_mark_gen(ir_build_cond_br(irb, child_scope, node, cond, body_block, else_block, is_comptime)); + ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, cond, body_block, else_block, is_comptime)); ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstruction *elem_ptr = ir_build_elem_ptr(irb, child_scope, node, array_val_ptr, index_val, false, PtrLenSingle); - IrInstruction *elem_val; - if (node->data.for_expr.elem_is_ptr) { - elem_val = elem_ptr; - } else { - elem_val = ir_build_load_ptr(irb, child_scope, node, elem_ptr); - } - ir_mark_gen(ir_build_store_ptr(irb, child_scope, node, elem_var_ptr, elem_val)); + IrInstruction *elem_ptr = ir_build_elem_ptr(irb, parent_scope, node, array_val_ptr, index_val, false, PtrLenSingle); + // TODO make it an error to write to element variable or i variable. + Buf *elem_var_name = elem_node->data.symbol_expr.symbol; + ZigVar *elem_var = ir_create_var(irb, elem_node, parent_scope, elem_var_name, true, false, false, is_comptime); + Scope *child_scope = elem_var->child_scope; + + IrInstruction *var_ptr = node->data.for_expr.elem_is_ptr ? + ir_build_ref(irb, parent_scope, elem_node, elem_ptr, true, false) : elem_ptr; + ir_build_var_decl_src(irb, parent_scope, elem_node, elem_var, nullptr, var_ptr); ZigList incoming_values = {0}; ZigList incoming_blocks = {0}; @@ -16901,64 +16866,6 @@ static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructio return ir_const_type(ira, &typeof_instruction->base, type_entry); } -static IrInstruction *ir_analyze_instruction_to_ptr_type(IrAnalyze *ira, - IrInstructionToPtrType *to_ptr_type_instruction) -{ - Error err; - IrInstruction *ptr_ptr = to_ptr_type_instruction->ptr->child; - if (type_is_invalid(ptr_ptr->value.type)) - return ira->codegen->invalid_instruction; - - ZigType *ptr_ptr_type = ptr_ptr->value.type; - assert(ptr_ptr_type->id == ZigTypeIdPointer); - ZigType *type_entry = ptr_ptr_type->data.pointer.child_type; - - ZigType *ptr_type; - if (type_entry->id == ZigTypeIdArray) { - ptr_type = get_pointer_to_type(ira->codegen, type_entry->data.array.child_type, ptr_ptr_type->data.pointer.is_const); - } else if (is_array_ref(type_entry)) { - ptr_type = get_pointer_to_type(ira->codegen, - type_entry->data.pointer.child_type->data.array.child_type, type_entry->data.pointer.is_const); - } else if (is_slice(type_entry)) { - ZigType *slice_ptr_type = type_entry->data.structure.fields[0].type_entry; - ptr_type = adjust_ptr_len(ira->codegen, slice_ptr_type, PtrLenSingle); - // If the pointer is over-aligned, we may have to reduce it based on the alignment of the element type. - if (slice_ptr_type->data.pointer.explicit_alignment != 0) { - ZigType *elem_type = slice_ptr_type->data.pointer.child_type; - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) - return ira->codegen->invalid_instruction; - uint32_t elem_align = get_abi_alignment(ira->codegen, elem_type); - uint32_t reduced_align = min(elem_align, slice_ptr_type->data.pointer.explicit_alignment); - ptr_type = adjust_ptr_align(ira->codegen, ptr_type, reduced_align); - } - } else if (type_entry->id == ZigTypeIdArgTuple) { - zig_panic("TODO for loop on var args"); - } else { - ir_add_error_node(ira, to_ptr_type_instruction->base.source_node, - buf_sprintf("expected array type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - } - - return ir_const_type(ira, &to_ptr_type_instruction->base, ptr_type); -} - -static IrInstruction *ir_analyze_instruction_ptr_type_child(IrAnalyze *ira, - IrInstructionPtrTypeChild *ptr_type_child_instruction) -{ - IrInstruction *type_value = ptr_type_child_instruction->value->child; - ZigType *type_entry = ir_resolve_type(ira, type_value); - if (type_is_invalid(type_entry)) - return ira->codegen->invalid_instruction; - - if (type_entry->id != ZigTypeIdPointer) { - ir_add_error_node(ira, ptr_type_child_instruction->base.source_node, - buf_sprintf("expected pointer type, found '%s'", buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; - } - - return ir_const_type(ira, &ptr_type_child_instruction->base, type_entry->data.pointer.child_type); -} - static IrInstruction *ir_analyze_instruction_set_cold(IrAnalyze *ira, IrInstructionSetCold *instruction) { if (ira->new_irb.exec->is_inline) { // ignore setCold when running functions at compile time @@ -23751,10 +23658,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_phi(ira, (IrInstructionPhi *)instruction); case IrInstructionIdTypeOf: return ir_analyze_instruction_typeof(ira, (IrInstructionTypeOf *)instruction); - case IrInstructionIdToPtrType: - return ir_analyze_instruction_to_ptr_type(ira, (IrInstructionToPtrType *)instruction); - case IrInstructionIdPtrTypeChild: - return ir_analyze_instruction_ptr_type_child(ira, (IrInstructionPtrTypeChild *)instruction); case IrInstructionIdSetCold: return ir_analyze_instruction_set_cold(ira, (IrInstructionSetCold *)instruction); case IrInstructionIdSetRuntimeSafety: @@ -24152,8 +24055,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdVarPtr: case IrInstructionIdReturnPtr: case IrInstructionIdTypeOf: - case IrInstructionIdToPtrType: - case IrInstructionIdPtrTypeChild: case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: case IrInstructionIdArrayType: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7906d57be0..dbc5ea364c 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -414,18 +414,6 @@ static void ir_print_typeof(IrPrint *irp, IrInstructionTypeOf *instruction) { fprintf(irp->f, ")"); } -static void ir_print_to_ptr_type(IrPrint *irp, IrInstructionToPtrType *instruction) { - fprintf(irp->f, "@toPtrType("); - ir_print_other_instruction(irp, instruction->ptr); - fprintf(irp->f, ")"); -} - -static void ir_print_ptr_type_child(IrPrint *irp, IrInstructionPtrTypeChild *instruction) { - fprintf(irp->f, "@ptrTypeChild("); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); -} - static void ir_print_field_ptr(IrPrint *irp, IrInstructionFieldPtr *instruction) { if (instruction->field_name_buffer) { fprintf(irp->f, "fieldptr "); @@ -1625,12 +1613,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTypeOf: ir_print_typeof(irp, (IrInstructionTypeOf *)instruction); break; - case IrInstructionIdToPtrType: - ir_print_to_ptr_type(irp, (IrInstructionToPtrType *)instruction); - break; - case IrInstructionIdPtrTypeChild: - ir_print_ptr_type_child(irp, (IrInstructionPtrTypeChild *)instruction); - break; case IrInstructionIdFieldPtr: ir_print_field_ptr(irp, (IrInstructionFieldPtr *)instruction); break; -- cgit v1.2.3 From 771e88951a9af48335abe14e4c44b5c4f5b252de Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 8 Jun 2019 18:51:31 -0400 Subject: result location mechanism for struct initialization ```zig export fn entry() void { const static = Foo{ .x = 9, .bar = Bar{ .y = 10 }, }; const runtime = foo(true); } fn foo(c: bool) Foo { return Foo{ .x = 12, .bar = if (c) bar1() else bar2(), }; } fn bar1() Bar { return Bar{ .y = 34 }; } fn bar2() Bar { return Bar{ .y = 56 }; } ``` ```llvm @0 = internal unnamed_addr constant %Foo { i32 9, %Bar { i32 10 } }, align 4 @1 = internal unnamed_addr constant %Bar { i32 34 }, align 4 @2 = internal unnamed_addr constant %Bar { i32 56 }, align 4 define void @entry() #2 !dbg !35 { Entry: %runtime = alloca %Foo, align 4 call void @llvm.dbg.declare(metadata %Foo* @0, metadata !39, metadata !DIExpression()), !dbg !50 call fastcc void @foo(%Foo* sret %runtime, i1 true), !dbg !51 call void @llvm.dbg.declare(metadata %Foo* %runtime, metadata !49, metadata !DIExpression()), !dbg !52 ret void, !dbg !53 } define internal fastcc void @foo(%Foo* nonnull sret, i1) unnamed_addr #2 !dbg !54 { Entry: %c = alloca i1, align 1 store i1 %1, i1* %c, align 1 call void @llvm.dbg.declare(metadata i1* %c, metadata !60, metadata !DIExpression()), !dbg !61 %2 = getelementptr inbounds %Foo, %Foo* %0, i32 0, i32 0, !dbg !62 store i32 12, i32* %2, align 4, !dbg !62 %3 = getelementptr inbounds %Foo, %Foo* %0, i32 0, i32 1, !dbg !64 %4 = load i1, i1* %c, align 1, !dbg !65 br i1 %4, label %Then, label %Else, !dbg !65 Then: ; preds = %Entry call fastcc void @bar1(%Bar* sret %3), !dbg !66 br label %EndIf, !dbg !64 Else: ; preds = %Entry call fastcc void @bar2(%Bar* sret %3), !dbg !67 br label %EndIf, !dbg !64 EndIf: ; preds = %Else, %Then ret void, !dbg !68 } define internal fastcc void @bar1(%Bar* nonnull sret) unnamed_addr #2 !dbg !69 { Entry: %1 = bitcast %Bar* %0 to i8*, !dbg !73 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 bitcast (%Bar* @1 to i8*), i64 4, i1 false), !dbg !73 ret void, !dbg !73 } define internal fastcc void @bar2(%Bar* nonnull sret) unnamed_addr #2 !dbg !75 { Entry: %1 = bitcast %Bar* %0 to i8*, !dbg !76 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 bitcast (%Bar* @2 to i8*), i64 4, i1 false), !dbg !76 ret void, !dbg !76 } !39 = !DILocalVariable(name: "static", scope: !40, file: !5, line: 2, type: !41) !49 = !DILocalVariable(name: "runtime", scope: !40, file: !5, line: 6, type: !41) ``` --- BRANCH_TODO | 8 +- src/all_types.hpp | 49 ++++++++---- src/analyze.cpp | 6 ++ src/analyze.hpp | 1 + src/codegen.cpp | 73 +++++++++-------- src/ir.cpp | 236 +++++++++++++++++++++++++++++++++++++----------------- src/ir_print.cpp | 40 +++++---- 7 files changed, 270 insertions(+), 143 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index fc8a654772..843703e20b 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,8 +1,8 @@ Scratch pad for stuff to do before merging master ================================================= - * struct initializations - * function call parameters + * array initializations + * union initializations * bitCast look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated @@ -25,7 +25,3 @@ inferred comptime return ir_build_ref(irb, scope, value->source_node, value, false, false); handle if with no else - - - - diff --git a/src/all_types.hpp b/src/all_types.hpp index 0061b5999f..fbd788c9d9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1957,6 +1957,7 @@ enum ScopeId { ScopeIdCompTime, ScopeIdCoroPrelude, ScopeIdRuntime, + ScopeIdElide, }; struct Scope { @@ -1970,6 +1971,14 @@ struct Scope { ScopeId id; }; +// This scope, when activated, causes all the instructions in the scope to be omitted +// from the generated code. +struct ScopeElide { + Scope base; + + bool activated; +}; + // This scope comes from global declarations or from // declarations in a container declaration // NodeTypeContainerDecl @@ -2189,7 +2198,6 @@ enum IrInstructionId { IrInstructionIdResizeSlice, IrInstructionIdContainerInitList, IrInstructionIdContainerInitFields, - IrInstructionIdStructInit, IrInstructionIdUnionInit, IrInstructionIdUnreachable, IrInstructionIdTypeOf, @@ -2279,6 +2287,7 @@ enum IrInstructionId { IrInstructionIdPtrType, IrInstructionIdAlignCast, IrInstructionIdImplicitCast, + IrInstructionIdResolveResult, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, @@ -2366,6 +2375,7 @@ struct IrInstructionCondBr { IrBasicBlock *then_block; IrBasicBlock *else_block; IrInstruction *is_comptime; + ResultLoc *result_loc; }; struct IrInstructionBr { @@ -2646,20 +2656,6 @@ struct IrInstructionContainerInitFields { IrInstructionContainerInitFieldsField *fields; }; -struct IrInstructionStructInitField { - IrInstruction *value; - TypeStructField *type_struct_field; -}; - -struct IrInstructionStructInit { - IrInstruction base; - - ZigType *struct_type; - size_t field_count; - IrInstructionStructInitField *fields; - LLVMValueRef tmp_ptr; -}; - struct IrInstructionUnionInit { IrInstruction base; @@ -3581,13 +3577,22 @@ struct IrInstructionImplicitCast { IrInstruction *target; }; +struct IrInstructionResolveResult { + IrInstruction base; + + ResultLoc *result_loc; + IrInstruction *ty; +}; + enum ResultLocId { ResultLocIdInvalid, ResultLocIdNone, ResultLocIdVar, + ResultLocIdField, ResultLocIdReturn, ResultLocIdPeer, ResultLocIdPeerParent, + ResultLocIdInstruction, }; struct ResultLoc { @@ -3597,6 +3602,7 @@ struct ResultLoc { IrInstruction *source_instruction; IrInstruction *gen_instruction; // value to store to the result loc ZigType *implicit_elem_type; + ScopeElide *scope_elide; }; struct ResultLocNone { @@ -3609,6 +3615,14 @@ struct ResultLocVar { ZigVar *var; }; +struct ResultLocField { + ResultLoc base; + + ResultLoc *parent; + Buf *name; + IrInstruction *container_type; +}; + struct ResultLocReturn { ResultLoc base; }; @@ -3636,6 +3650,11 @@ struct ResultLocPeer { IrSuspendPosition suspend_pos; }; +// The result location is the source instruction +struct ResultLocInstruction { + ResultLoc base; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/analyze.cpp b/src/analyze.cpp index 771e11e93f..6299ac6699 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -166,6 +166,12 @@ Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruct return &scope->base; } +ScopeElide *create_elide_scope(CodeGen *g, AstNode *node, Scope *parent) { + ScopeElide *scope = allocate(1); + init_scope(g, &scope->base, ScopeIdElide, node, parent); + return scope; +} + ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent) { assert(node->type == NodeTypeSuspend); ScopeSuspend *scope = allocate(1); diff --git a/src/analyze.hpp b/src/analyze.hpp index 57f1072355..2f3ec663da 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -121,6 +121,7 @@ ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn * Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent); Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); +ScopeElide *create_elide_scope(CodeGen *g, AstNode *node, Scope *parent); void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); diff --git a/src/codegen.cpp b/src/codegen.cpp index eecc2239db..4fa13c39a2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -715,6 +715,7 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { case ScopeIdCompTime: case ScopeIdCoroPrelude: case ScopeIdRuntime: + case ScopeIdElide: return get_di_scope(g, scope->parent); } zig_unreachable(); @@ -2383,7 +2384,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut } static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { - LLVMValueRef value = ir_llvm_value(g, return_instruction->value); ZigType *return_type = return_instruction->value->value.type; if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { @@ -2391,13 +2391,16 @@ static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrIns if (return_instruction->value->value.special != ConstValSpecialRuntime) { // if it's comptime we have to do this but if it's runtime trust that // result location mechanism took care of it. + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); } LLVMBuildRetVoid(g->builder); } else if (handle_is_ptr(return_type)) { + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); LLVMBuildRet(g->builder, by_val_value); } else { + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); LLVMBuildRet(g->builder, value); } return nullptr; @@ -5032,29 +5035,6 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir return get_handle_value(g, tag_field_ptr, tag_type, ptr_type); } -static LLVMValueRef ir_render_struct_init(CodeGen *g, IrExecutable *executable, IrInstructionStructInit *instruction) { - for (size_t i = 0; i < instruction->field_count; i += 1) { - IrInstructionStructInitField *field = &instruction->fields[i]; - TypeStructField *type_struct_field = field->type_struct_field; - if (!type_has_bits(type_struct_field->type_entry)) - continue; - - LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, - (unsigned)type_struct_field->gen_index, ""); - LLVMValueRef value = ir_llvm_value(g, field->value); - - uint32_t field_align_bytes = get_abi_alignment(g, type_struct_field->type_entry); - uint32_t host_int_bytes = get_host_int_bytes(g, instruction->struct_type, type_struct_field); - - ZigType *ptr_type = get_pointer_to_type_extra(g, type_struct_field->type_entry, - false, false, PtrLenSingle, field_align_bytes, - (uint32_t)type_struct_field->bit_offset_in_host, host_int_bytes, false); - - gen_assign_raw(g, field_ptr, ptr_type, value); - } - return instruction->tmp_ptr; -} - static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) { TypeUnionField *type_union_field = instruction->field; @@ -5531,10 +5511,6 @@ static void set_debug_location(CodeGen *g, IrInstruction *instruction) { } static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { - if (!g->strip_debug_symbols) { - set_debug_location(g, instruction); - } - switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdConst: @@ -5609,6 +5585,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdEndExpr: case IrInstructionIdAllocaGen: case IrInstructionIdImplicitCast: + case IrInstructionIdResolveResult: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5705,8 +5682,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); case IrInstructionIdUnionTag: return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction); - case IrInstructionIdStructInit: - return ir_render_struct_init(g, executable, (IrInstructionStructInit *)instruction); case IrInstructionIdUnionInit: return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); case IrInstructionIdPtrCastGen: @@ -5791,6 +5766,34 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, zig_unreachable(); } +static bool scope_is_elided(Scope *scope) { + for (;;) { + switch (scope->id) { + case ScopeIdDecls: + case ScopeIdCompTime: + case ScopeIdCImport: + zig_unreachable(); + case ScopeIdElide: + if (reinterpret_cast(scope)->activated) + return true; + // fallthrough + case ScopeIdBlock: + case ScopeIdDefer: + case ScopeIdDeferExpr: + case ScopeIdVarDecl: + case ScopeIdLoop: + case ScopeIdSuspend: + case ScopeIdCoroPrelude: + case ScopeIdRuntime: + scope = scope->parent; + continue; + case ScopeIdFnDef: + return false; + } + zig_unreachable(); + } +} + static void ir_render(CodeGen *g, ZigFn *fn_entry) { assert(fn_entry); @@ -5806,7 +5809,12 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) continue; - instruction->llvm_value = ir_render_instruction(g, executable, instruction); + if (!scope_is_elided(instruction->scope)) { + if (!g->strip_debug_symbols) { + set_debug_location(g, instruction); + } + instruction->llvm_value = ir_render_instruction(g, executable, instruction); + } } current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder); } @@ -6891,9 +6899,6 @@ static void do_code_gen(CodeGen *g) { } 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 == IrInstructionIdUnionInit) { IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction; slot = &union_init_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 7f5b7da6e1..d34630554c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -616,10 +616,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) { return IrInstructionIdRef; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionStructInit *) { - return IrInstructionIdStructInit; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { return IrInstructionIdUnionInit; } @@ -888,6 +884,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionImplicitCast *) return IrInstructionIdImplicitCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *) { + return IrInstructionIdResolveResult; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { return IrInstructionIdOpaqueType; } @@ -1517,20 +1517,6 @@ static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scop return &container_init_fields_instruction->base; } -static IrInstruction *ir_build_struct_init(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigType *struct_type, size_t field_count, IrInstructionStructInitField *fields) -{ - IrInstructionStructInit *struct_init_instruction = ir_build_instruction(irb, scope, 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, irb->current_basic_block); - - return &struct_init_instruction->base; -} - static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigType *union_type, TypeUnionField *field, IrInstruction *init_value) { @@ -2764,6 +2750,18 @@ static IrInstruction *ir_build_implicit_cast(IrBuilder *irb, Scope *scope, AstNo return &instruction->base; } +static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc, IrInstruction *ty) +{ + IrInstructionResolveResult *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_loc = result_loc; + instruction->ty = ty; + + ir_ref_instruction(ty, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionOpaqueType *instruction = ir_build_instruction(irb, scope, source_node); @@ -3220,6 +3218,7 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco case ScopeIdSuspend: case ScopeIdCompTime: case ScopeIdRuntime: + case ScopeIdElide: scope = scope->parent; continue; case ScopeIdDeferExpr: @@ -3276,6 +3275,7 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o case ScopeIdSuspend: case ScopeIdCompTime: case ScopeIdRuntime: + case ScopeIdElide: scope = scope->parent; continue; case ScopeIdDeferExpr: @@ -5549,7 +5549,9 @@ static IrInstruction *ir_gen_prefix_op_expr(IrBuilder *irb, Scope *scope, AstNod zig_unreachable(); } -static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeContainerInitExpr); AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; @@ -5559,39 +5561,61 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A if (container_type == irb->codegen->invalid_instruction) return container_type; - if (kind == ContainerInitKindStruct) { - size_t field_count = container_init_expr->entries.length; - 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); - - Buf *name = entry_node->data.struct_val_field.name; - AstNode *expr_node = entry_node->data.struct_val_field.expr; - IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope); - if (expr_value == irb->codegen->invalid_instruction) - return expr_value; - - fields[i].name = name; - fields[i].value = expr_value; - fields[i].source_node = entry_node; - } - return ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields); - } else if (kind == ContainerInitKindArray) { - size_t item_count = container_init_expr->entries.length; - IrInstruction **values = allocate(item_count); - for (size_t i = 0; i < item_count; i += 1) { - AstNode *expr_node = container_init_expr->entries.at(i); - IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope); - if (expr_value == irb->codegen->invalid_instruction) - return expr_value; - - values[i] = expr_value; - } - return ir_build_container_init_list(irb, scope, node, container_type, item_count, values); - } else { - zig_unreachable(); + switch (kind) { + case ContainerInitKindStruct: { + src_assert(result_loc->scope_elide == nullptr, node); + result_loc->scope_elide = create_elide_scope(irb->codegen, node, scope); + size_t field_count = container_init_expr->entries.length; + 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); + + Buf *name = entry_node->data.struct_val_field.name; + AstNode *expr_node = entry_node->data.struct_val_field.expr; + + ResultLoc *child_result_loc = nullptr; + if (result_loc != nullptr) { + IrInstruction *container_ptr = ir_build_resolve_result(irb, &result_loc->scope_elide->base, + expr_node, result_loc, container_type); + IrInstruction *field_ptr = ir_build_field_ptr(irb, &result_loc->scope_elide->base, expr_node, + container_ptr, name); + ResultLocInstruction *result_loc_inst = allocate(1); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = field_ptr; + ir_ref_instruction(field_ptr, irb->current_basic_block); + child_result_loc = &result_loc_inst->base; + } + + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, &result_loc->scope_elide->base, + LValNone, child_result_loc); + if (expr_value == irb->codegen->invalid_instruction) + return expr_value; + + fields[i].name = name; + fields[i].value = expr_value; + fields[i].source_node = entry_node; + } + IrInstruction *init_fields = ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields); + + return ir_lval_wrap(irb, scope, init_fields, lval, result_loc); + } + case ContainerInitKindArray: { + size_t item_count = container_init_expr->entries.length; + IrInstruction **values = allocate(item_count); + for (size_t i = 0; i < item_count; i += 1) { + AstNode *expr_node = container_init_expr->entries.at(i); + IrInstruction *expr_value = ir_gen_node(irb, expr_node, scope); + if (expr_value == irb->codegen->invalid_instruction) + return expr_value; + + values[i] = expr_value; + } + IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, item_count, values); + return ir_lval_wrap(irb, scope, init_list, lval, result_loc); + } } + zig_unreachable(); } static ResultLocVar *create_var_result_loc(IrInstruction *alloca, ZigVar *var) { @@ -7885,7 +7909,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypePrefixOpExpr: return ir_gen_prefix_op_expr(irb, scope, node, lval, result_loc); case NodeTypeContainerInitExpr: - return ir_lval_wrap(irb, scope, ir_gen_container_init_expr(irb, scope, node), lval, result_loc); + return ir_gen_container_init_expr(irb, scope, node, lval, result_loc); case NodeTypeVariableDeclaration: return ir_lval_wrap(irb, scope, ir_gen_var_decl(irb, scope, node), lval, result_loc); case NodeTypeWhileExpr: @@ -14468,7 +14492,9 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in return &result->base; } -static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_loc) { +static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspend_source_instr, + ResultLoc *result_loc) +{ switch (result_loc->id) { case ResultLocIdInvalid: case ResultLocIdPeerParent: @@ -14476,6 +14502,30 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, ResultLoc *result_lo case ResultLocIdNone: case ResultLocIdVar: return nullptr; + case ResultLocIdInstruction: + return result_loc->source_instruction->child->value.type; + case ResultLocIdField: { + if (result_loc->resolved_loc != nullptr) { + ZigType *ptr_type = result_loc->resolved_loc->value.type; + assert(ptr_type->id == ZigTypeIdPointer); + return ptr_type->data.pointer.child_type; + } + ResultLocField *result_loc_field = reinterpret_cast(result_loc); + ZigType *container_type = ir_resolve_type(ira, result_loc_field->container_type->child); + if (type_is_invalid(container_type)) + return ira->codegen->builtin_types.entry_invalid; + if (container_type->id == ZigTypeIdStruct) { + TypeStructField *field = find_struct_type_field(container_type, result_loc_field->name); + if (field == nullptr) { + return ira->codegen->builtin_types.entry_invalid; + } + return field->type_entry; + } else if (container_type->id == ZigTypeIdUnion) { + zig_panic("TODO"); + } else { + zig_unreachable(); + } + } case ResultLocIdReturn: return ira->explicit_return_type; case ResultLocIdPeer: @@ -14491,7 +14541,10 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s ResultLoc *result_loc, ZigType *value_type, IrInstruction *value) { if (result_loc->resolved_loc != nullptr) { - return result_loc->resolved_loc; + // allow to redo the result location if the value is known and comptime and the previous one isn't + if (value == nullptr || !instr_is_comptime(value) || instr_is_comptime(result_loc->resolved_loc)) { + return result_loc->resolved_loc; + } } result_loc->gen_instruction = value; result_loc->implicit_elem_type = value_type; @@ -14524,7 +14577,7 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s return ira->codegen->invalid_instruction; bool is_comptime = force_comptime || (value != nullptr && value->value.special != ConstValSpecialRuntime && result_loc_var->var->gen_is_const); - if (alloca_src->base.child == nullptr) { + if (alloca_src->base.child == nullptr || is_comptime) { uint32_t align = 0; if (alloca_src->align != nullptr && !ir_resolve_align(ira, alloca_src->align->child, &align)) { return ira->codegen->invalid_instruction; @@ -14539,12 +14592,40 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s alloca_gen = ir_analyze_alloca(ira, result_loc->source_instruction, value_type, align, alloca_src->name_hint, force_comptime); } + if (alloca_src->base.child != nullptr) { + alloca_src->base.child->ref_count = 0; + } alloca_src->base.child = alloca_gen; } result_loc->written = true; result_loc->resolved_loc = is_comptime ? nullptr : alloca_src->base.child; return result_loc->resolved_loc; } + case ResultLocIdInstruction: { + result_loc->written = true; + result_loc->resolved_loc = result_loc->source_instruction->child; + return result_loc->resolved_loc; + } + case ResultLocIdField: { + ResultLocField *result_loc_field = reinterpret_cast(result_loc); + + ZigType *container_type = ir_resolve_type(ira, result_loc_field->container_type->child); + if (type_is_invalid(container_type)) + return ira->codegen->invalid_instruction; + + IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, + result_loc_field->parent, container_type, nullptr); + if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || + parent_result_loc->value.type->id == ZigTypeIdUnreachable) + { + return parent_result_loc; + } + + result_loc->written = true; + result_loc->resolved_loc = ir_analyze_container_field_ptr(ira, result_loc_field->name, + suspend_source_instr, parent_result_loc, container_type); + return result_loc->resolved_loc; + } case ResultLocIdReturn: { bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; if (is_comptime) return nullptr; @@ -14593,7 +14674,7 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s ira->resume_stack.append(opposite_peer->suspend_pos); } } - ZigType *expected_type = ir_result_loc_expected_type(ira, peer_parent->parent); + ZigType *expected_type = ir_result_loc_expected_type(ira, suspend_source_instr, peer_parent->parent); peer_parent->resolved_type = ir_resolve_peer_types(ira, peer_parent->base.source_instruction->source_node, expected_type, instructions, peer_parent->peer_count); @@ -14626,6 +14707,12 @@ static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrIns return ir_implicit_cast(ira, target, dest_type); } +static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { + ZigType *ty = ir_resolve_type(ira, instruction->ty->child); + if (type_is_invalid(ty)) + return ira->codegen->invalid_instruction; + return ir_resolve_result(ira, &instruction->base, instruction->result_loc, ty, nullptr); +} static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, @@ -18330,8 +18417,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc AstNode **field_assign_nodes = allocate(actual_field_count); - IrInstructionStructInitField *new_fields = allocate(actual_field_count); - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; @@ -18371,9 +18456,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc } field_assign_nodes[field_index] = field->source_node; - new_fields[field_index].value = casted_field_value; - new_fields[field_index].type_struct_field = type_field; - if (const_val.special == ConstValSpecialStatic) { if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) { ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); @@ -18416,9 +18498,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstruction *runtime_inst = ir_const(ira, instruction, field->init_val->type); copy_const_val(&runtime_inst->value, field->init_val, true); - new_fields[i].value = runtime_inst; - new_fields[i].type_struct_field = field; - if (const_val.special == ConstValSpecialStatic) { copy_const_val(&const_val.data.x_struct.fields[i], field->init_val, true); } @@ -18451,12 +18530,11 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc return ira->codegen->invalid_instruction; } - IrInstruction *new_instruction = ir_build_struct_init(&ira->new_irb, - instruction->scope, instruction->source_node, - container_type, actual_field_count, new_fields); - new_instruction->value.type = container_type; - ir_add_alloca(ira, new_instruction, container_type); - return new_instruction; + // this instruction should not get to codegen + IrInstruction *result = ir_const(ira, instruction, container_type); + // this is how we signal to EndExpr the value is not comptime known + result->value.special = ConstValSpecialRuntime; + return result; } static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, @@ -23794,7 +23872,18 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - if (!instruction->result_loc->written) { + bool want_resolve_result = instruction->result_loc->written; + if (instruction->result_loc->written) { + if (instruction->result_loc->scope_elide != nullptr && instr_is_comptime(value)) { + want_resolve_result = true; + instruction->result_loc->scope_elide->activated = true; + } else { + want_resolve_result = false; + } + } else { + want_resolve_result = true; + } + if (want_resolve_result) { IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, value->value.type, value); if (result_loc != nullptr) { @@ -23815,7 +23904,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdWidenOrShorten: - case IrInstructionIdStructInit: case IrInstructionIdUnionInit: case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: @@ -24036,6 +24124,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_align_cast(ira, (IrInstructionAlignCast *)instruction); case IrInstructionIdImplicitCast: return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction); + case IrInstructionIdResolveResult: + return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction); case IrInstructionIdOpaqueType: return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); case IrInstructionIdSetAlignStack: @@ -24260,7 +24350,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: - case IrInstructionIdStructInit: case IrInstructionIdUnionInit: case IrInstructionIdFieldPtr: case IrInstructionIdElemPtr: @@ -24326,6 +24415,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTypeId: case IrInstructionIdAlignCast: case IrInstructionIdImplicitCast: + case IrInstructionIdResolveResult: case IrInstructionIdOpaqueType: case IrInstructionIdArgType: case IrInstructionIdTagType: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7d56b157d5..0f80a9b9e3 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -207,6 +207,18 @@ static void ir_print_result_loc_var(IrPrint *irp, ResultLocVar *result_loc_var) fprintf(irp->f, ")"); } +static void ir_print_result_loc_instruction(IrPrint *irp, ResultLocInstruction *result_loc_inst) { + fprintf(irp->f, "inst("); + ir_print_other_instruction(irp, result_loc_inst->base.source_instruction); + fprintf(irp->f, ")"); +} + +static void ir_print_result_loc_field(IrPrint *irp, ResultLocField *result_loc_field) { + fprintf(irp->f, "field(name=%s,type=", buf_ptr(result_loc_field->name)); + ir_print_other_instruction(irp, result_loc_field->container_type); + fprintf(irp->f, ")"); +} + static void ir_print_result_loc_peer(IrPrint *irp, ResultLocPeer *result_loc_peer) { fprintf(irp->f, "peer(next="); ir_print_other_block(irp, result_loc_peer->next_bb); @@ -225,6 +237,10 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { return; case ResultLocIdVar: return ir_print_result_loc_var(irp, (ResultLocVar *)result_loc); + case ResultLocIdInstruction: + return ir_print_result_loc_instruction(irp, (ResultLocInstruction *)result_loc); + case ResultLocIdField: + return ir_print_result_loc_field(irp, (ResultLocField *)result_loc); case ResultLocIdPeer: return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc); case ResultLocIdPeerParent: @@ -352,18 +368,6 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI 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_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) { Buf *field_name = instruction->field->enum_field->name; @@ -1265,6 +1269,12 @@ static void ir_print_implicit_cast(IrPrint *irp, IrInstructionImplicitCast *inst fprintf(irp->f, ")"); } +static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *instruction) { + fprintf(irp->f, "ResolveResult("); + ir_print_result_loc(irp, instruction->result_loc); + fprintf(irp->f, ")"); +} + static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) { fprintf(irp->f, "@OpaqueType()"); } @@ -1588,9 +1598,6 @@ 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 IrInstructionIdUnionInit: ir_print_union_init(irp, (IrInstructionUnionInit *)instruction); break; @@ -1900,6 +1907,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdImplicitCast: ir_print_implicit_cast(irp, (IrInstructionImplicitCast *)instruction); break; + case IrInstructionIdResolveResult: + ir_print_resolve_result(irp, (IrInstructionResolveResult *)instruction); + break; case IrInstructionIdOpaqueType: ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); break; -- cgit v1.2.3 From 4e2b2822f18577edb614bdc3ec6808a0587662e5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 9 Jun 2019 19:55:15 -0400 Subject: inferred array size of array literals works --- src/codegen.cpp | 27 +-------------------------- src/ir.cpp | 35 ++++++++++++++--------------------- 2 files changed, 15 insertions(+), 47 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 763e1e1c50..b28f041391 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5072,30 +5072,6 @@ static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, I return instruction->tmp_ptr; } -static LLVMValueRef ir_render_container_init_list(CodeGen *g, IrExecutable *executable, - IrInstructionContainerInitList *instruction) -{ - ZigType *array_type = instruction->base.value.type; - assert(array_type->id == ZigTypeIdArray); - LLVMValueRef tmp_array_ptr = instruction->tmp_ptr; - assert(tmp_array_ptr); - - size_t field_count = instruction->item_count; - - ZigType *child_type = array_type->data.array.child_type; - for (size_t i = 0; i < field_count; i += 1) { - LLVMValueRef elem_val = ir_llvm_value(g, instruction->items[i]); - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, i, false), - }; - LLVMValueRef elem_ptr = LLVMBuildInBoundsGEP(g->builder, tmp_array_ptr, indices, 2, ""); - gen_assign_raw(g, elem_ptr, get_pointer_to_type(g, child_type, false), elem_val); - } - - return tmp_array_ptr; -} - static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope)); return nullptr; @@ -5586,6 +5562,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdAllocaGen: case IrInstructionIdImplicitCast: case IrInstructionIdResolveResult: + case IrInstructionIdContainerInitList: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5700,8 +5677,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_int_to_err(g, executable, (IrInstructionIntToErr *)instruction); case IrInstructionIdErrToInt: return ir_render_err_to_int(g, executable, (IrInstructionErrToInt *)instruction); - case IrInstructionIdContainerInitList: - return ir_render_container_init_list(g, executable, (IrInstructionContainerInitList *)instruction); case IrInstructionIdPanic: return ir_render_panic(g, executable, (IrInstructionPanic *)instruction); case IrInstructionIdTagName: diff --git a/src/ir.cpp b/src/ir.cpp index 84c7dc6342..b29af2a1e2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1484,17 +1484,15 @@ static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *sour } static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *container_type, IrInstruction *elem_type, size_t item_count, IrInstruction **items) + IrInstruction *container_type, size_t item_count, IrInstruction **items) { IrInstructionContainerInitList *container_init_list_instruction = ir_build_instruction(irb, scope, source_node); container_init_list_instruction->container_type = container_type; - container_init_list_instruction->elem_type = elem_type; container_init_list_instruction->item_count = item_count; container_init_list_instruction->items = items; - if (container_type != nullptr) ir_ref_instruction(container_type, irb->current_basic_block); - if (elem_type != nullptr) ir_ref_instruction(elem_type, irb->current_basic_block); + ir_ref_instruction(container_type, irb->current_basic_block); for (size_t i = 0; i < item_count; i += 1) { ir_ref_instruction(items[i], irb->current_basic_block); } @@ -5620,11 +5618,17 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A src_assert(result_loc->scope_elide == nullptr, node); result_loc->scope_elide = create_elide_scope(irb->codegen, node, scope); + size_t item_count = container_init_expr->entries.length; + + if (container_type == nullptr) { + IrInstruction *item_count_inst = ir_build_const_usize(irb, scope, node, item_count); + container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); + } + src_assert(result_loc != nullptr, node); IrInstruction *container_ptr = ir_build_resolve_result(irb, &result_loc->scope_elide->base, node, result_loc, container_type); - size_t item_count = container_init_expr->entries.length; IrInstruction **values = allocate(item_count); for (size_t i = 0; i < item_count; i += 1) { AstNode *expr_node = container_init_expr->entries.at(i); @@ -5644,7 +5648,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A values[i] = expr_value; } - IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, elem_type, + IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, item_count, values); return ir_lval_wrap(irb, scope, init_list, lval, result_loc); } @@ -18538,22 +18542,11 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, { Error err; - size_t elem_count = instruction->item_count; + ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); + if (type_is_invalid(container_type)) + return ira->codegen->invalid_instruction; - ZigType *container_type; - if (instruction->container_type != nullptr) { - container_type = ir_resolve_type(ira, instruction->container_type->child); - if (type_is_invalid(container_type)) - return ira->codegen->invalid_instruction; - } else { - ZigType *elem_type = ir_resolve_type(ira, instruction->elem_type->child); - if (type_is_invalid(elem_type)) - return ira->codegen->invalid_instruction; - if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) { - return ira->codegen->invalid_instruction; - } - container_type = get_array_type(ira->codegen, elem_type, elem_count); - } + size_t elem_count = instruction->item_count; if (is_slice(container_type)) { ir_add_error(ira, &instruction->base, -- cgit v1.2.3 From 1a51bf63047e9a3cd6ae3273296fded82009235c Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 11:15:32 -0400 Subject: hook up result locations for union initializations ```zig export fn entry() void { var x = Foo{ .bar = bar() }; } ``` ```llvm define void @entry() #2 !dbg !44 { Entry: %x = alloca %Foo, align 4 %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 1, !dbg !68 store i1 true, i1* %0, align 1, !dbg !68 %1 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0, !dbg !68 %2 = bitcast { i32, [4 x i8] }* %1 to %Bar*, !dbg !68 call fastcc void @bar(%Bar* sret %2), !dbg !68 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !48, metadata !DIExpression()), !dbg !69 ret void, !dbg !70 } ``` --- BRANCH_TODO | 1 - src/all_types.hpp | 13 +------ src/codegen.cpp | 49 +++--------------------- src/ir.cpp | 109 ++++++++++++++++++++++++------------------------------ src/ir_print.cpp | 12 ------ 5 files changed, 56 insertions(+), 128 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index df4375ad7d..2744901bfa 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,6 @@ Scratch pad for stuff to do before merging master ================================================= - * union initializations * bitCast look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated diff --git a/src/all_types.hpp b/src/all_types.hpp index 703ff5aea1..35e9786baa 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2204,7 +2204,6 @@ enum IrInstructionId { IrInstructionIdResizeSlice, IrInstructionIdContainerInitList, IrInstructionIdContainerInitFields, - IrInstructionIdUnionInit, IrInstructionIdUnreachable, IrInstructionIdTypeOf, IrInstructionIdSetCold, @@ -2520,6 +2519,7 @@ struct IrInstructionStorePtr { struct IrInstructionFieldPtr { IrInstruction base; + bool initializing; IrInstruction *container_ptr; Buf *field_name_buffer; IrInstruction *field_name_expr; @@ -2536,9 +2536,9 @@ struct IrInstructionStructFieldPtr { struct IrInstructionUnionFieldPtr { IrInstruction base; + bool initializing; IrInstruction *union_ptr; TypeUnionField *field; - bool is_const; }; struct IrInstructionElemPtr { @@ -2663,15 +2663,6 @@ struct IrInstructionContainerInitFields { IrInstructionContainerInitFieldsField *fields; }; -struct IrInstructionUnionInit { - IrInstruction base; - - ZigType *union_type; - TypeUnionField *field; - IrInstruction *init_value; - LLVMValueRef tmp_ptr; -}; - struct IrInstructionUnreachable { IrInstruction base; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index b28f041391..eb2e92f627 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3859,7 +3859,12 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab return bitcasted_union_field_ptr; } - if (ir_want_runtime_safety(g, &instruction->base)) { + if (instruction->initializing) { + LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); + LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), + &field->enum_field->value); + gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); + } else if (ir_want_runtime_safety(g, &instruction->base)) { LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, ""); @@ -5035,43 +5040,6 @@ static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, Ir return get_handle_value(g, tag_field_ptr, tag_type, ptr_type); } -static LLVMValueRef ir_render_union_init(CodeGen *g, IrExecutable *executable, IrInstructionUnionInit *instruction) { - TypeUnionField *type_union_field = instruction->field; - - if (!type_has_bits(type_union_field->type_entry)) - return nullptr; - - uint32_t field_align_bytes = get_abi_alignment(g, type_union_field->type_entry); - ZigType *ptr_type = get_pointer_to_type_extra(g, type_union_field->type_entry, - false, false, PtrLenSingle, field_align_bytes, - 0, 0, false); - - LLVMValueRef uncasted_union_ptr; - // Even if safety is off in this block, if the union type has the safety field, we have to populate it - // correctly. Otherwise safety code somewhere other than here could fail. - ZigType *union_type = instruction->union_type; - if (union_type->data.unionation.gen_tag_index != SIZE_MAX) { - LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, - union_type->data.unionation.gen_tag_index, ""); - - LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), - &type_union_field->enum_field->value); - gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - - uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, - (unsigned)union_type->data.unionation.gen_union_index, ""); - } else { - uncasted_union_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, (unsigned)0, ""); - } - - LLVMValueRef field_ptr = LLVMBuildBitCast(g->builder, uncasted_union_ptr, get_llvm_type(g, ptr_type), ""); - LLVMValueRef value = ir_llvm_value(g, instruction->init_value); - - gen_assign_raw(g, field_ptr, ptr_type, value); - - return instruction->tmp_ptr; -} - static LLVMValueRef ir_render_panic(CodeGen *g, IrExecutable *executable, IrInstructionPanic *instruction) { gen_panic(g, ir_llvm_value(g, instruction->msg), get_cur_err_ret_trace_val(g, instruction->base.scope)); return nullptr; @@ -5659,8 +5627,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_err_wrap_payload(g, executable, (IrInstructionErrWrapPayload *)instruction); case IrInstructionIdUnionTag: return ir_render_union_tag(g, executable, (IrInstructionUnionTag *)instruction); - case IrInstructionIdUnionInit: - return ir_render_union_init(g, executable, (IrInstructionUnionInit *)instruction); case IrInstructionIdPtrCastGen: return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); case IrInstructionIdBitCastGen: @@ -6874,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdContainerInitList) { IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction; slot = &container_init_list_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdUnionInit) { - IrInstructionUnionInit *union_init_instruction = (IrInstructionUnionInit *)instruction; - slot = &union_init_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdSlice) { IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; slot = &slice_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index b29af2a1e2..05f95a2480 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -164,7 +164,7 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr); static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, - IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); + IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing); static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var); static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op); static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, ResultLoc *result_loc); @@ -616,10 +616,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) { return IrInstructionIdRef; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInit *) { - return IrInstructionIdUnionInit; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) { return IrInstructionIdCompileErr; } @@ -1312,12 +1308,13 @@ static IrInstruction *ir_build_field_ptr_instruction(IrBuilder *irb, Scope *scop } static IrInstruction *ir_build_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *container_ptr, Buf *field_name) + IrInstruction *container_ptr, Buf *field_name, bool initializing) { IrInstructionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->container_ptr = container_ptr; instruction->field_name_buffer = field_name; instruction->field_name_expr = nullptr; + instruction->initializing = initializing; ir_ref_instruction(container_ptr, irb->current_basic_block); @@ -1337,9 +1334,10 @@ static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, As } static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *union_ptr, TypeUnionField *field) + IrInstruction *union_ptr, TypeUnionField *field, bool initializing) { IrInstructionUnionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->initializing = initializing; instruction->union_ptr = union_ptr; instruction->field = field; @@ -1517,19 +1515,6 @@ static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scop return &container_init_fields_instruction->base; } -static IrInstruction *ir_build_union_init(IrBuilder *irb, Scope *scope, AstNode *source_node, - ZigType *union_type, TypeUnionField *field, IrInstruction *init_value) -{ - IrInstructionUnionInit *union_init_instruction = ir_build_instruction(irb, scope, source_node); - union_init_instruction->union_type = union_type; - union_init_instruction->field = field; - union_init_instruction->init_value = init_value; - - ir_ref_instruction(init_value, irb->current_basic_block); - - return &union_init_instruction->base; -} - static IrInstruction *ir_build_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionUnreachable *unreachable_instruction = ir_build_instruction(irb, scope, source_node); @@ -4121,7 +4106,7 @@ static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode if (container_ref_instruction == irb->codegen->invalid_instruction) return container_ref_instruction; - return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name); + return ir_build_field_ptr(irb, scope, node, container_ref_instruction, field_name, false); } static IrInstruction *ir_gen_overflow_op(IrBuilder *irb, Scope *scope, AstNode *node, IrOverflowOp op) { @@ -5594,7 +5579,7 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A AstNode *expr_node = entry_node->data.struct_val_field.expr; IrInstruction *field_ptr = ir_build_field_ptr(irb, &result_loc->scope_elide->base, expr_node, - container_ptr, name); + container_ptr, name, true); ResultLocInstruction *result_loc_inst = allocate(1); result_loc_inst->base.id = ResultLocIdInstruction; result_loc_inst->base.source_instruction = field_ptr; @@ -6105,7 +6090,7 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo IrBasicBlock *continue_block = ir_create_basic_block(irb, parent_scope, "ForContinue"); Buf *len_field_name = buf_create_from_str("len"); - IrInstruction *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name); + IrInstruction *len_ref = ir_build_field_ptr(irb, parent_scope, node, array_val_ptr, len_field_name, false); IrInstruction *len_val = ir_build_load_ptr(irb, parent_scope, node, len_ref); ir_build_br(irb, parent_scope, node, cond_block, is_comptime); @@ -7496,7 +7481,7 @@ static IrInstruction *ir_gen_cancel_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, - atomic_state_field_name); + atomic_state_field_name, false); // set the is_canceled bit IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, @@ -7575,7 +7560,7 @@ static IrInstruction *ir_gen_resume_target(IrBuilder *irb, Scope *scope, AstNode IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, casted_target_inst); Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, - atomic_state_field_name); + atomic_state_field_name, false); // clear the is_suspended bit IrInstruction *prev_atomic_value = ir_build_atomic_rmw(irb, scope, node, @@ -7642,12 +7627,12 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *coro_promise_ptr = ir_build_coro_promise(irb, scope, node, target_inst); Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); - IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); + IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false); if (irb->codegen->have_err_ret_tracing) { IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull); Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME); - IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); + IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false); ir_build_store_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr); } @@ -7669,7 +7654,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); IrInstruction *atomic_state_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, - atomic_state_field_name); + atomic_state_field_name, false); IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node, irb->codegen->builtin_types.entry_promise); IrInstruction *const_bool_false = ir_build_const_bool(irb, scope, node, false); @@ -7723,12 +7708,12 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, no_suspend_block); if (irb->codegen->have_err_ret_tracing) { Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); - IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name); + IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false); IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::NonNull); ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr); } Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); - IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); + IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false); // If the type of the result handle_is_ptr then this does not actually perform a load. But we need it to, // because we're about to destroy the memory. So we store it into our result variable. IrInstruction *no_suspend_result = ir_build_load_ptr(irb, scope, node, promise_result_ptr); @@ -8152,7 +8137,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec build_decl_var_and_init(irb, coro_scope, node, irb->exec->coro_allocator_var, implicit_allocator_ptr, "allocator", const_bool_false); Buf *realloc_field_name = buf_create_from_str(ASYNC_REALLOC_FIELD_NAME); - IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name); + IrInstruction *realloc_fn_ptr = ir_build_field_ptr(irb, coro_scope, node, implicit_allocator_ptr, realloc_field_name, false); IrInstruction *realloc_fn = ir_build_load_ptr(irb, coro_scope, node, realloc_fn_ptr); IrInstruction *maybe_coro_mem_ptr = ir_build_coro_alloc_helper(irb, coro_scope, node, realloc_fn, coro_size); IrInstruction *alloc_result_is_ok = ir_build_test_nonnull(irb, coro_scope, node, maybe_coro_mem_ptr); @@ -8172,30 +8157,30 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec Buf *atomic_state_field_name = buf_create_from_str(ATOMIC_STATE_FIELD_NAME); irb->exec->atomic_state_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, - atomic_state_field_name); + atomic_state_field_name, false); IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); ir_build_store_ptr(irb, scope, node, irb->exec->atomic_state_field_ptr, zero); Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME); - irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name); + irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name, false); result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME); - irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name); + irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name, false); ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr); if (irb->codegen->have_err_ret_tracing) { // initialize the error return trace Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME); - IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name); + IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name, false); Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME); - err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name); + err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name, false); ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr); // coordinate with builtin.zig Buf *index_name = buf_create_from_str("index"); - IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name); + IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name, false); ir_build_store_ptr(irb, scope, node, index_ptr, zero); Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses"); - IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name); + IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name, false); IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false); ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value); @@ -8256,7 +8241,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec } if (irb->codegen->have_err_ret_tracing) { Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME); - IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name); + IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name, false); IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr); ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr); } @@ -8291,7 +8276,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec Buf *shrink_field_name = buf_create_from_str(ASYNC_SHRINK_FIELD_NAME); IrInstruction *implicit_allocator_ptr = ir_build_get_implicit_allocator(irb, scope, node, ImplicitAllocatorIdLocalVar); - IrInstruction *shrink_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, shrink_field_name); + IrInstruction *shrink_fn_ptr = ir_build_field_ptr(irb, scope, node, implicit_allocator_ptr, shrink_field_name, false); IrInstruction *shrink_fn = ir_build_load_ptr(irb, scope, node, shrink_fn_ptr); IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0); IrInstruction *coro_mem_ptr_maybe = ir_build_coro_free(irb, scope, node, coro_id, irb->exec->coro_handle); @@ -14722,7 +14707,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc ir_assert(async_allocator_inst->value.type->id == ZigTypeIdPointer, &call_instruction->base); ZigType *container_type = async_allocator_inst->value.type->data.pointer.child_type; IrInstruction *field_ptr_inst = ir_analyze_container_field_ptr(ira, realloc_field_name, &call_instruction->base, - async_allocator_inst, container_type); + async_allocator_inst, container_type, false); if (type_is_invalid(field_ptr_inst->value.type)) { return ira->codegen->invalid_instruction; } @@ -16580,7 +16565,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, } static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, - IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type) + IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing) { Error err; @@ -16664,15 +16649,19 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ if (type_is_invalid(union_val->type)) return ira->codegen->invalid_instruction; - TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag); - if (actual_field == nullptr) - zig_unreachable(); + if (initializing) { + bigint_init_bigint(&union_val->data.x_union.tag, &field->enum_field->value); + } else { + TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag); + if (actual_field == nullptr) + zig_unreachable(); - if (field != actual_field) { - ir_add_error_node(ira, source_instr->source_node, - buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name), - buf_ptr(actual_field->name))); - return ira->codegen->invalid_instruction; + if (field != actual_field) { + ir_add_error_node(ira, source_instr->source_node, + buf_sprintf("accessing union field '%s' while field '%s' is set", buf_ptr(field_name), + buf_ptr(actual_field->name))); + return ira->codegen->invalid_instruction; + } } ConstExprValue *payload_val = union_val->data.x_union.payload; @@ -16690,7 +16679,8 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ } } - IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, container_ptr, field); + IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, container_ptr, field, initializing); result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); return result; @@ -16826,10 +16816,10 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc if (container_type->id == ZigTypeIdPointer) { ZigType *bare_type = container_ref_type(container_type); IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr); - IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type); + IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type, field_ptr_instruction->initializing); return result; } else { - IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_ptr, container_type); + IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_ptr, container_type, field_ptr_instruction->initializing); return result; } } else if (is_array_ref(container_type)) { @@ -18120,7 +18110,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru } IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, target_value_ptr, field); + instruction->base.scope, instruction->base.source_node, target_value_ptr, field, false); result->value.type = get_pointer_to_type(ira->codegen, field->type_entry, target_value_ptr->value.type->data.pointer.is_const); return result; @@ -18386,11 +18376,10 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI return result; } - IrInstruction *new_instruction = ir_build_union_init(&ira->new_irb, - instruction->scope, instruction->source_node, - container_type, type_field, casted_field_value); - new_instruction->value.type = container_type; - ir_add_alloca(ira, new_instruction, container_type); + // this instruction should not get to codegen + IrInstruction *new_instruction = ir_const(ira, instruction, container_type); + // this is how we signal to EndExpr the value is not comptime known + new_instruction->value.special = ConstValSpecialRuntime; return new_instruction; } @@ -23907,7 +23896,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdWidenOrShorten: - case IrInstructionIdUnionInit: case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: case IrInstructionIdOptionalWrap: @@ -24353,7 +24341,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: - case IrInstructionIdUnionInit: case IrInstructionIdFieldPtr: case IrInstructionIdElemPtr: case IrInstructionIdVarPtr: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 9181f66be5..42b93aec4e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -360,15 +360,6 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI fprintf(irp->f, "} // container init"); } -static void ir_print_union_init(IrPrint *irp, IrInstructionUnionInit *instruction) { - Buf *field_name = instruction->field->enum_field->name; - - fprintf(irp->f, "%s {", buf_ptr(&instruction->union_type->name)); - fprintf(irp->f, ".%s = ", buf_ptr(field_name)); - ir_print_other_instruction(irp, instruction->init_value); - fprintf(irp->f, "} // union init"); -} - static void ir_print_unreachable(IrPrint *irp, IrInstructionUnreachable *instruction) { fprintf(irp->f, "unreachable"); } @@ -1590,9 +1581,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdContainerInitFields: ir_print_container_init_fields(irp, (IrInstructionContainerInitFields *)instruction); break; - case IrInstructionIdUnionInit: - ir_print_union_init(irp, (IrInstructionUnionInit *)instruction); - break; case IrInstructionIdUnreachable: ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); break; -- cgit v1.2.3 From 17b1ac5d03cd32e047d917a88e029c143cb5d119 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 12:24:19 -0400 Subject: result location semantics for `@bitCast` ```zig export fn entry() void { var x = @bitCast(f32, foo()); } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %x = alloca float, align 4 %0 = bitcast float* %x to %Foo*, !dbg !42 call fastcc void @foo(%Foo* sret %0), !dbg !42 call void @llvm.dbg.declare(metadata float* %x, metadata !39, metadata !DIExpression()), !dbg !43 ret void, !dbg !44 } ``` --- BRANCH_TODO | 4 +- src/all_types.hpp | 18 +++--- src/codegen.cpp | 14 +---- src/ir.cpp | 178 ++++++++++++++++++++++++++---------------------------- src/ir_print.cpp | 19 +++--- 5 files changed, 103 insertions(+), 130 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 2744901bfa..296d8a24fd 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,8 +1,6 @@ Scratch pad for stuff to do before merging master ================================================= - * bitCast - look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated return ir_gen_comptime(irb, scope, node, lval); @@ -23,3 +21,5 @@ inferred comptime return ir_build_ref(irb, scope, value->source_node, value, false, false); handle if with no else + + diff --git a/src/all_types.hpp b/src/all_types.hpp index 35e9786baa..ef4d94880b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2267,7 +2267,6 @@ enum IrInstructionId { IrInstructionIdTestComptime, IrInstructionIdPtrCastSrc, IrInstructionIdPtrCastGen, - IrInstructionIdBitCast, IrInstructionIdBitCastGen, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, @@ -2645,7 +2644,6 @@ struct IrInstructionContainerInitList { IrInstruction *elem_type; size_t item_count; IrInstruction **items; - LLVMValueRef tmp_ptr; }; struct IrInstructionContainerInitFieldsField { @@ -3136,18 +3134,10 @@ struct IrInstructionPtrCastGen { bool safety_check_on; }; -struct IrInstructionBitCast { - IrInstruction base; - - IrInstruction *dest_type; - IrInstruction *value; -}; - struct IrInstructionBitCastGen { IrInstruction base; IrInstruction *operand; - LLVMValueRef tmp_ptr; }; struct IrInstructionWidenOrShorten { @@ -3590,6 +3580,7 @@ enum ResultLocId { ResultLocIdPeer, ResultLocIdPeerParent, ResultLocIdInstruction, + ResultLocIdBitCast, }; struct ResultLoc { @@ -3644,6 +3635,13 @@ struct ResultLocInstruction { ResultLoc base; }; +// The source_instruction is the destination type +struct ResultLocBitCast { + ResultLoc base; + + ResultLoc *parent; +}; + static const size_t slice_ptr_index = 0; static const size_t slice_len_index = 1; diff --git a/src/codegen.cpp b/src/codegen.cpp index eb2e92f627..894d22d471 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3145,12 +3145,7 @@ static LLVMValueRef ir_render_bit_cast(CodeGen *g, IrExecutable *executable, uint32_t alignment = get_abi_alignment(g, actual_type); return gen_load_untyped(g, bitcasted_ptr, alignment, false, ""); } else { - assert(instruction->tmp_ptr != nullptr); - LLVMTypeRef wanted_ptr_type_ref = LLVMPointerType(get_llvm_type(g, actual_type), 0); - LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, wanted_ptr_type_ref, ""); - uint32_t alignment = get_abi_alignment(g, wanted_type); - gen_store_untyped(g, value, bitcasted_ptr, alignment, false); - return instruction->tmp_ptr; + zig_unreachable(); } } @@ -5520,7 +5515,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdPtrCastSrc: case IrInstructionIdCmpxchgSrc: case IrInstructionIdLoadPtr: - case IrInstructionIdBitCast: case IrInstructionIdGlobalAsm: case IrInstructionIdHasDecl: case IrInstructionIdUndeclaredIdent: @@ -6837,9 +6831,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdContainerInitList) { - IrInstructionContainerInitList *container_init_list_instruction = (IrInstructionContainerInitList *)instruction; - slot = &container_init_list_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdSlice) { IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; slot = &slice_instruction->tmp_ptr; @@ -6861,9 +6852,6 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdLoadPtrGen) { IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; slot = &load_ptr_inst->tmp_ptr; - } else if (instruction->id == IrInstructionIdBitCastGen) { - IrInstructionBitCastGen *bit_cast_inst = (IrInstructionBitCastGen *)instruction; - slot = &bit_cast_inst->tmp_ptr; } else if (instruction->id == IrInstructionIdVectorToArray) { IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); diff --git a/src/ir.cpp b/src/ir.cpp index 05f95a2480..26d0d59b28 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -780,10 +780,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { return IrInstructionIdPtrCastGen; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { - return IrInstructionIdBitCast; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) { return IrInstructionIdBitCastGen; } @@ -2429,20 +2425,6 @@ static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *sourc return &instruction->base; } -static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *dest_type, IrInstruction *value) -{ - IrInstructionBitCast *instruction = ir_build_instruction( - irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->value = value; - - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(value, irb->current_basic_block); - - return &instruction->base; -} - static IrInstruction *ir_build_bit_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *operand, ZigType *ty) { @@ -4836,18 +4818,23 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo } case BuiltinFnIdBitCast: { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_instruction) - return arg0_value; + AstNode *dest_type_node = node->data.fn_call_expr.params.at(0); + IrInstruction *dest_type = ir_gen_node(irb, dest_type_node, scope); + if (dest_type == irb->codegen->invalid_instruction) + return dest_type; + + ResultLocBitCast *result_loc_bit_cast = allocate(1); + result_loc_bit_cast->base.id = ResultLocIdBitCast; + result_loc_bit_cast->base.source_instruction = dest_type; + result_loc_bit_cast->parent = result_loc; AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); + IrInstruction *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone, + &result_loc_bit_cast->base); if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *bit_cast = ir_build_bit_cast(irb, scope, node, arg0_value, arg1_value); - return ir_lval_wrap(irb, scope, bit_cast, lval, result_loc); + return ir_lval_wrap(irb, scope, arg1_value, lval, result_loc); } case BuiltinFnIdIntToPtr: { @@ -14059,9 +14046,10 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, bool var_class_requires_const = false; IrInstruction *var_ptr = decl_var_instruction->ptr->child; - // if this assertion trips there may be a missing ir_expr_wrap in pass1 IR generation. - ir_assert(var_ptr != nullptr, &decl_var_instruction->base); - if (type_is_invalid(var_ptr->value.type)) { + // if this is null, a compiler error happened and did not initialize the variable. + // if there are no compile errors there may be a missing ir_expr_wrap in pass1 IR generation. + if (var_ptr == nullptr || type_is_invalid(var_ptr->value.type)) { + ir_assert(var_ptr != nullptr || ira->codegen->errors.length != 0, &decl_var_instruction->base); var->var_type = ira->codegen->builtin_types.entry_invalid; return ira->codegen->invalid_instruction; } @@ -14528,6 +14516,7 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspe zig_unreachable(); case ResultLocIdNone: case ResultLocIdVar: + case ResultLocIdBitCast: return nullptr; case ResultLocIdInstruction: return result_loc->source_instruction->child->value.type; @@ -14539,6 +14528,28 @@ static ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspe zig_unreachable(); } +static bool type_can_bit_cast(ZigType *t) { + switch (t->id) { + case ZigTypeIdInvalid: + zig_unreachable(); + case ZigTypeIdMetaType: + case ZigTypeIdOpaque: + case ZigTypeIdBoundFn: + case ZigTypeIdArgTuple: + case ZigTypeIdUnreachable: + case ZigTypeIdComptimeFloat: + case ZigTypeIdComptimeInt: + case ZigTypeIdEnumLiteral: + case ZigTypeIdUndefined: + case ZigTypeIdNull: + case ZigTypeIdPointer: + return false; + default: + // TODO list these types out explicitly, there are probably some other invalid ones here + return true; + } +} + // give nullptr for value to resolve it at runtime // returns a result location, or nullptr if the result location was already taken care of // when calling this function, at the callsite must check for result type noreturn and propagate it up @@ -14676,6 +14687,50 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s result_loc->resolved_loc = parent_result_loc; return result_loc->resolved_loc; } + case ResultLocIdBitCast: { + ResultLocBitCast *result_bit_cast = reinterpret_cast(result_loc); + ZigType *dest_type = ir_resolve_type(ira, result_bit_cast->base.source_instruction->child); + if (type_is_invalid(dest_type)) + return ira->codegen->invalid_instruction; + + if (get_codegen_ptr_type(dest_type) != nullptr) { + ir_add_error(ira, result_loc->source_instruction, + buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + if (!type_can_bit_cast(dest_type)) { + ir_add_error(ira, result_loc->source_instruction, + buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); + return ira->codegen->invalid_instruction; + } + + if (get_codegen_ptr_type(value_type) != nullptr) { + ir_add_error(ira, suspend_source_instr, + buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&value_type->name))); + return ira->codegen->invalid_instruction; + } + + if (!type_can_bit_cast(value_type)) { + ir_add_error(ira, suspend_source_instr, + buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&value_type->name))); + return ira->codegen->invalid_instruction; + } + + + IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent, + dest_type, nullptr); + if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || + parent_result_loc->value.type->id == ZigTypeIdUnreachable) + { + return parent_result_loc; + } + ZigType *ptr_type = get_pointer_to_type(ira->codegen, value_type, false); + result_loc->written = true; + result_loc->resolved_loc = ir_analyze_ptr_cast(ira, suspend_source_instr, parent_result_loc, + ptr_type, result_bit_cast->base.source_instruction, false); + return result_loc->resolved_loc; + } } zig_unreachable(); } @@ -22755,28 +22810,6 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou zig_unreachable(); } -static bool type_can_bit_cast(ZigType *t) { - switch (t->id) { - case ZigTypeIdInvalid: - zig_unreachable(); - case ZigTypeIdMetaType: - case ZigTypeIdOpaque: - case ZigTypeIdBoundFn: - case ZigTypeIdArgTuple: - case ZigTypeIdUnreachable: - case ZigTypeIdComptimeFloat: - case ZigTypeIdComptimeInt: - case ZigTypeIdEnumLiteral: - case ZigTypeIdUndefined: - case ZigTypeIdNull: - case ZigTypeIdPointer: - return false; - default: - // TODO list these types out explicitly, there are probably some other invalid ones here - return true; - } -} - static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *dest_type) { @@ -22829,50 +22862,10 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ } IrInstruction *result = ir_build_bit_cast_gen(ira, source_instr, value, dest_type); - if (handle_is_ptr(dest_type) && !handle_is_ptr(src_type)) { - ir_add_alloca(ira, result, dest_type); - } + assert(!(handle_is_ptr(dest_type) && !handle_is_ptr(src_type))); return result; } -static IrInstruction *ir_analyze_instruction_bit_cast(IrAnalyze *ira, IrInstructionBitCast *instruction) { - IrInstruction *dest_type_value = instruction->dest_type->child; - ZigType *dest_type = ir_resolve_type(ira, dest_type_value); - if (type_is_invalid(dest_type)) - return ira->codegen->invalid_instruction; - - IrInstruction *value = instruction->value->child; - ZigType *src_type = value->value.type; - if (type_is_invalid(src_type)) - return ira->codegen->invalid_instruction; - - if (get_codegen_ptr_type(src_type) != nullptr) { - ir_add_error(ira, value, - buf_sprintf("unable to @bitCast from pointer type '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_instruction; - } - - if (!type_can_bit_cast(src_type)) { - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast from type '%s'", buf_ptr(&src_type->name))); - return ira->codegen->invalid_instruction; - } - - if (get_codegen_ptr_type(dest_type) != nullptr) { - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast to pointer type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - - if (!type_can_bit_cast(dest_type)) { - ir_add_error(ira, dest_type_value, - buf_sprintf("unable to @bitCast to type '%s'", buf_ptr(&dest_type->name))); - return ira->codegen->invalid_instruction; - } - - return ir_analyze_bit_cast(ira, &instruction->base, value, dest_type); -} - static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *ptr_type) { @@ -24089,8 +24082,6 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_panic(ira, (IrInstructionPanic *)instruction); case IrInstructionIdPtrCastSrc: return ir_analyze_instruction_ptr_cast(ira, (IrInstructionPtrCastSrc *)instruction); - case IrInstructionIdBitCast: - return ir_analyze_instruction_bit_cast(ira, (IrInstructionBitCast *)instruction); case IrInstructionIdIntToPtr: return ir_analyze_instruction_int_to_ptr(ira, (IrInstructionIntToPtr *)instruction); case IrInstructionIdPtrToInt: @@ -24386,7 +24377,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: case IrInstructionIdPtrCastGen: - case IrInstructionIdBitCast: case IrInstructionIdBitCastGen: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 42b93aec4e..925d802e6d 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -219,6 +219,12 @@ static void ir_print_result_loc_peer(IrPrint *irp, ResultLocPeer *result_loc_pee fprintf(irp->f, ")"); } +static void ir_print_result_loc_bit_cast(IrPrint *irp, ResultLocBitCast *result_loc_bit_cast) { + fprintf(irp->f, "bitcast(ty="); + ir_print_other_instruction(irp, result_loc_bit_cast->base.source_instruction); + fprintf(irp->f, ")"); +} + static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { switch (result_loc->id) { case ResultLocIdInvalid: @@ -235,6 +241,8 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { return ir_print_result_loc_instruction(irp, (ResultLocInstruction *)result_loc); case ResultLocIdPeer: return ir_print_result_loc_peer(irp, (ResultLocPeer *)result_loc); + case ResultLocIdBitCast: + return ir_print_result_loc_bit_cast(irp, (ResultLocBitCast *)result_loc); case ResultLocIdPeerParent: fprintf(irp->f, "peer_parent"); return; @@ -1011,14 +1019,6 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc fprintf(irp->f, ")"); } -static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { - fprintf(irp->f, "@bitCast("); - ir_print_other_instruction(irp, instruction->dest_type); - fprintf(irp->f, ","); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); -} - static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) { fprintf(irp->f, "@bitCast("); ir_print_other_instruction(irp, instruction->operand); @@ -1818,9 +1818,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdPtrCastGen: ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction); break; - case IrInstructionIdBitCast: - ir_print_bit_cast(irp, (IrInstructionBitCast *)instruction); - break; case IrInstructionIdBitCastGen: ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction); break; -- cgit v1.2.3 From c36289511629e01bbd32bc5f1133f5ed5997d1e0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 15:49:45 -0400 Subject: result location semantics for slices ```zig export fn entry() void { var buf: [10]u8 = undefined; const slice1: []const u8 = &buf; const slice2 = buf[0..]; } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %buf = alloca [10 x i8], align 1 %slice1 = alloca %"[]u8", align 8 %slice2 = alloca %"[]u8", align 8 %0 = bitcast [10 x i8]* %buf to i8*, !dbg !46 call void @llvm.memset.p0i8.i64(i8* align 1 %0, i8 -86, i64 10, i1 false), !dbg !46 call void @llvm.dbg.declare(metadata [10 x i8]* %buf, metadata !39, metadata !DIExpression()), !dbg !46 %1 = getelementptr inbounds %"[]u8", %"[]u8"* %slice1, i32 0, i32 0, !dbg !47 %2 = getelementptr inbounds [10 x i8], [10 x i8]* %buf, i64 0, i64 0, !dbg !47 store i8* %2, i8** %1, align 8, !dbg !47 %3 = getelementptr inbounds %"[]u8", %"[]u8"* %slice1, i32 0, i32 1, !dbg !47 store i64 10, i64* %3, align 8, !dbg !47 call void @llvm.dbg.declare(metadata %"[]u8"* %slice1, metadata !44, metadata !DIExpression()), !dbg !48 %4 = getelementptr inbounds %"[]u8", %"[]u8"* %slice2, i32 0, i32 0, !dbg !49 %5 = getelementptr inbounds [10 x i8], [10 x i8]* %buf, i64 0, i64 0, !dbg !49 store i8* %5, i8** %4, align 8, !dbg !49 %6 = getelementptr inbounds %"[]u8", %"[]u8"* %slice2, i32 0, i32 1, !dbg !49 store i64 10, i64* %6, align 8, !dbg !49 call void @llvm.dbg.declare(metadata %"[]u8"* %slice2, metadata !45, metadata !DIExpression()), !dbg !50 ret void, !dbg !51 } ``` --- BRANCH_TODO | 3 - src/all_types.hpp | 27 +++++++-- src/codegen.cpp | 72 ++++++++++++----------- src/ir.cpp | 172 +++++++++++++++++++++++++++++++++++++----------------- src/ir_print.cpp | 33 +++++++++-- 5 files changed, 210 insertions(+), 97 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 296d8a24fd..e744162fa0 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -20,6 +20,3 @@ inferred comptime // an instruction which just makes a pointer of it. return ir_build_ref(irb, scope, value->source_node, value, false, false); -handle if with no else - - diff --git a/src/all_types.hpp b/src/all_types.hpp index ef4d94880b..73580619ed 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2248,7 +2248,8 @@ enum IrInstructionId { IrInstructionIdBoolNot, IrInstructionIdMemset, IrInstructionIdMemcpy, - IrInstructionIdSlice, + IrInstructionIdSliceSrc, + IrInstructionIdSliceGen, IrInstructionIdMemberCount, IrInstructionIdMemberType, IrInstructionIdMemberName, @@ -2334,6 +2335,7 @@ enum IrInstructionId { IrInstructionIdAllocaSrc, IrInstructionIdAllocaGen, IrInstructionIdEndExpr, + IrInstructionIdPtrOfArrayToSlice, }; struct IrInstruction { @@ -2617,7 +2619,6 @@ enum CastOp { CastOpNumLitToConcrete, CastOpErrSet, CastOpBitCast, - CastOpPtrOfArrayToSlice, }; // TODO get rid of this instruction, replace with instructions for each op code @@ -2989,14 +2990,24 @@ struct IrInstructionMemcpy { IrInstruction *count; }; -struct IrInstructionSlice { +struct IrInstructionSliceSrc { IrInstruction base; + bool safety_check_on; IrInstruction *ptr; IrInstruction *start; IrInstruction *end; + ResultLoc *result_loc; +}; + +struct IrInstructionSliceGen { + IrInstruction base; + bool safety_check_on; - LLVMValueRef tmp_ptr; + IrInstruction *ptr; + IrInstruction *start; + IrInstruction *end; + IrInstruction *result_loc; }; struct IrInstructionMemberCount { @@ -3563,6 +3574,7 @@ struct IrInstructionImplicitCast { IrInstruction *dest_type; IrInstruction *target; + ResultLoc *result_loc; }; struct IrInstructionResolveResult { @@ -3572,6 +3584,13 @@ struct IrInstructionResolveResult { IrInstruction *ty; }; +struct IrInstructionPtrOfArrayToSlice { + IrInstruction base; + + IrInstruction *operand; + IrInstruction *result_loc; +}; + enum ResultLocId { ResultLocIdInvalid, ResultLocIdNone, diff --git a/src/codegen.cpp b/src/codegen.cpp index 894d22d471..f748c575b0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3072,33 +3072,39 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, return expr_val; case CastOpBitCast: return LLVMBuildBitCast(g->builder, expr_val, get_llvm_type(g, wanted_type), ""); - case CastOpPtrOfArrayToSlice: { - assert(cast_instruction->tmp_ptr); - assert(actual_type->id == ZigTypeIdPointer); - ZigType *array_type = actual_type->data.pointer.child_type; - assert(array_type->id == ZigTypeIdArray); - - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - slice_ptr_index, ""); - LLVMValueRef indices[] = { - LLVMConstNull(g->builtin_types.entry_usize->llvm_type), - LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), - }; - LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); - gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); - - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr, - slice_len_index, ""); - LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, - array_type->data.array.len, false); - gen_store_untyped(g, len_value, len_field_ptr, 0, false); - - return cast_instruction->tmp_ptr; - } } zig_unreachable(); } +static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *executable, + IrInstructionPtrOfArrayToSlice *instruction) +{ + ZigType *actual_type = instruction->operand->value.type; + LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); + assert(expr_val); + + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); + + assert(actual_type->id == ZigTypeIdPointer); + ZigType *array_type = actual_type->data.pointer.child_type; + assert(array_type->id == ZigTypeIdArray); + + LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, slice_ptr_index, ""); + LLVMValueRef indices[] = { + LLVMConstNull(g->builtin_types.entry_usize->llvm_type), + LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), + }; + LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); + gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); + + LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, slice_len_index, ""); + LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, + array_type->data.array.len, false); + gen_store_untyped(g, len_value, len_field_ptr, 0, false); + + return result_loc; +} + static LLVMValueRef ir_render_ptr_cast(CodeGen *g, IrExecutable *executable, IrInstructionPtrCastGen *instruction) { @@ -4603,16 +4609,14 @@ static LLVMValueRef ir_render_memcpy(CodeGen *g, IrExecutable *executable, IrIns return nullptr; } -static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSlice *instruction) { - assert(instruction->tmp_ptr); - +static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInstructionSliceGen *instruction) { LLVMValueRef array_ptr_ptr = ir_llvm_value(g, instruction->ptr); ZigType *array_ptr_type = instruction->ptr->value.type; assert(array_ptr_type->id == ZigTypeIdPointer); ZigType *array_type = array_ptr_type->data.pointer.child_type; LLVMValueRef array_ptr = get_handle_value(g, array_ptr_ptr, array_type, array_ptr_type); - LLVMValueRef tmp_struct_ptr = instruction->tmp_ptr; + LLVMValueRef tmp_struct_ptr = ir_llvm_value(g, instruction->result_loc); bool want_runtime_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base); @@ -4630,7 +4634,9 @@ static LLVMValueRef ir_render_slice(CodeGen *g, IrExecutable *executable, IrInst end_val = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); } if (want_runtime_safety) { - add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); + if (instruction->start->value.special == ConstValSpecialRuntime || instruction->end) { + add_bounds_check(g, start_val, LLVMIntEQ, nullptr, LLVMIntULE, end_val); + } if (instruction->end) { LLVMValueRef array_end = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, array_type->data.array.len, false); @@ -5525,6 +5531,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdImplicitCast: case IrInstructionIdResolveResult: case IrInstructionIdContainerInitList: + case IrInstructionIdSliceSrc: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5595,8 +5602,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_memset(g, executable, (IrInstructionMemset *)instruction); case IrInstructionIdMemcpy: return ir_render_memcpy(g, executable, (IrInstructionMemcpy *)instruction); - case IrInstructionIdSlice: - return ir_render_slice(g, executable, (IrInstructionSlice *)instruction); + case IrInstructionIdSliceGen: + return ir_render_slice(g, executable, (IrInstructionSliceGen *)instruction); case IrInstructionIdBreakpoint: return ir_render_breakpoint(g, executable, (IrInstructionBreakpoint *)instruction); case IrInstructionIdReturnAddress: @@ -5697,6 +5704,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_assert_non_null(g, executable, (IrInstructionAssertNonNull *)instruction); case IrInstructionIdResizeSlice: return ir_render_resize_slice(g, executable, (IrInstructionResizeSlice *)instruction); + case IrInstructionIdPtrOfArrayToSlice: + return ir_render_ptr_of_array_to_slice(g, executable, (IrInstructionPtrOfArrayToSlice *)instruction); } zig_unreachable(); } @@ -6831,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdSlice) { - IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; - slot = &slice_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdOptionalWrap) { IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction; slot = &maybe_wrap_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 26d0d59b28..cc28d3981c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -700,8 +700,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionMemcpy *) { return IrInstructionIdMemcpy; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionSlice *) { - return IrInstructionIdSlice; +static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceSrc *) { + return IrInstructionIdSliceSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceGen *) { + return IrInstructionIdSliceGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionMemberCount *) { @@ -880,6 +884,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *) return IrInstructionIdResolveResult; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) { + return IrInstructionIdPtrOfArrayToSlice; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { return IrInstructionIdOpaqueType; } @@ -2216,14 +2224,15 @@ static IrInstruction *ir_build_memcpy(IrBuilder *irb, Scope *scope, AstNode *sou return &instruction->base; } -static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on) +static IrInstruction *ir_build_slice_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, ResultLoc *result_loc) { - IrInstructionSlice *instruction = ir_build_instruction(irb, scope, source_node); + IrInstructionSliceSrc *instruction = ir_build_instruction(irb, scope, source_node); instruction->ptr = ptr; instruction->start = start; instruction->end = end; instruction->safety_check_on = safety_check_on; + instruction->result_loc = result_loc; ir_ref_instruction(ptr, irb->current_basic_block); ir_ref_instruction(start, irb->current_basic_block); @@ -2232,6 +2241,26 @@ static IrInstruction *ir_build_slice(IrBuilder *irb, Scope *scope, AstNode *sour return &instruction->base; } +static IrInstruction *ir_build_slice_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *slice_type, + IrInstruction *ptr, IrInstruction *start, IrInstruction *end, bool safety_check_on, IrInstruction *result_loc) +{ + IrInstructionSliceGen *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = slice_type; + instruction->ptr = ptr; + instruction->start = start; + instruction->end = end; + instruction->safety_check_on = safety_check_on; + instruction->result_loc = result_loc; + + ir_ref_instruction(ptr, ira->new_irb.current_basic_block); + ir_ref_instruction(start, ira->new_irb.current_basic_block); + if (end) ir_ref_instruction(end, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_member_count(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *container) { IrInstructionMemberCount *instruction = ir_build_instruction(irb, scope, source_node); instruction->container = container; @@ -2705,11 +2734,12 @@ static IrInstruction *ir_build_align_cast(IrBuilder *irb, Scope *scope, AstNode } static IrInstruction *ir_build_implicit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *dest_type, IrInstruction *target) + IrInstruction *dest_type, IrInstruction *target, ResultLoc *result_loc) { IrInstructionImplicitCast *instruction = ir_build_instruction(irb, scope, source_node); instruction->dest_type = dest_type; instruction->target = target; + instruction->result_loc = result_loc; ir_ref_instruction(dest_type, irb->current_basic_block); ir_ref_instruction(target, irb->current_basic_block); @@ -3082,6 +3112,21 @@ static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *so return &instruction->base; } +static IrInstruction *ir_build_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instruction, + ZigType *result_type, IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionPtrOfArrayToSlice *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->operand = operand; + instruction->result_loc = result_loc; + + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_array_to_vector(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *array, ZigType *result_type) { @@ -5717,7 +5762,8 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod return irb->codegen->invalid_instruction; if (type_instruction != nullptr) { - IrInstruction *implicit_cast = ir_build_implicit_cast(irb, scope, node, type_instruction, init_value); + IrInstruction *implicit_cast = ir_build_implicit_cast(irb, scope, node, type_instruction, init_value, + &result_loc_var->base); ir_build_end_expr(irb, scope, node, implicit_cast, &result_loc_var->base); } @@ -7086,7 +7132,7 @@ static IrInstruction *ir_gen_defer(IrBuilder *irb, Scope *parent_scope, AstNode return ir_build_const_void(irb, parent_scope, node); } -static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { assert(node->type == NodeTypeSliceExpr); AstNodeSliceExpr *slice_expr = &node->data.slice_expr; @@ -7111,7 +7157,8 @@ static IrInstruction *ir_gen_slice(IrBuilder *irb, Scope *scope, AstNode *node) end_value = nullptr; } - return ir_build_slice(irb, scope, node, ptr_value, start_value, end_value, true); + IrInstruction *slice = ir_build_slice_src(irb, scope, node, ptr_value, start_value, end_value, true, result_loc); + return ir_lval_wrap(irb, scope, slice, lval, result_loc); } static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval, @@ -7659,7 +7706,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *scope, AstNode *n IrInstruction *target_promise_type = ir_build_typeof(irb, scope, node, target_inst); IrInstruction *promise_result_type = ir_build_promise_result_type(irb, scope, node, target_promise_type); ir_build_await_bookkeeping(irb, scope, node, promise_result_type); - IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef); + IrInstruction *undef_promise_result = ir_build_implicit_cast(irb, scope, node, promise_result_type, undef, nullptr); build_decl_var_and_init(irb, scope, node, result_var, undef_promise_result, "result", const_bool_false); IrInstruction *my_result_var_ptr = ir_build_var_ptr(irb, scope, node, result_var); ir_build_store_ptr(irb, scope, node, result_ptr_field_ptr, my_result_var_ptr); @@ -8001,7 +8048,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop case NodeTypeDefer: return ir_lval_wrap(irb, scope, ir_gen_defer(irb, scope, node), lval, result_loc); case NodeTypeSliceExpr: - return ir_lval_wrap(irb, scope, ir_gen_slice(irb, scope, node), lval, result_loc); + return ir_gen_slice(irb, scope, node, lval, result_loc); case NodeTypeCatchExpr: return ir_gen_catch(irb, scope, node, lval, result_loc); case NodeTypeContainerDecl: @@ -8028,15 +8075,19 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop zig_unreachable(); } +static ResultLoc *no_result_loc(void) { + ResultLocNone *result_loc_none = allocate(1); + result_loc_none->base.id = ResultLocIdNone; + return &result_loc_none->base; +} + static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc) { if (result_loc == nullptr) { // Create a result location indicating there is none - but if one gets created // it will be properly distributed. - ResultLocNone *result_loc_none = allocate(1); - result_loc_none->base.id = ResultLocIdNone; - result_loc = &result_loc_none->base; + result_loc = no_result_loc(); } IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction); @@ -8098,7 +8149,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa ZigType *coro_frame_type = get_promise_frame_type(irb->codegen, return_type); IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type); - IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef); + IrInstruction *undef_coro_frame = ir_build_implicit_cast(irb, coro_scope, node, coro_frame_type_value, undef, nullptr); build_decl_var_and_init(irb, coro_scope, node, promise_var, undef_coro_frame, "promise", const_bool_false); coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var); @@ -8106,7 +8157,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node); IrInstruction *await_handle_type_val = ir_build_const_type(irb, coro_scope, node, get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise)); - IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value); + IrInstruction *null_await_handle = ir_build_implicit_cast(irb, coro_scope, node, await_handle_type_val, null_value, nullptr); build_decl_var_and_init(irb, coro_scope, node, await_handle_var, null_await_handle, "await_handle", const_bool_false); irb->exec->await_handle_var_ptr = ir_build_var_ptr(irb, coro_scope, node, await_handle_var); @@ -8169,7 +8220,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses"); IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name, false); - IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false); + IrInstruction *slice_value = ir_build_slice_src(irb, scope, node, return_addresses_ptr, zero, nullptr, false, no_result_loc()); ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value); } @@ -8275,7 +8326,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec IrInstruction *coro_mem_ptr_ref = ir_build_ref(irb, scope, node, coro_mem_ptr, true, false); IrInstruction *coro_size_ptr = ir_build_var_ptr(irb, scope, node, coro_size_var); IrInstruction *coro_size = ir_build_load_ptr(irb, scope, node, coro_size_ptr); - IrInstruction *mem_slice = ir_build_slice(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false); + IrInstruction *mem_slice = ir_build_slice_src(irb, scope, node, coro_mem_ptr_ref, zero, coro_size, false, + no_result_loc()); size_t arg_count = 5; IrInstruction **args = allocate(arg_count); args[0] = implicit_allocator_ptr; // self @@ -10417,7 +10469,6 @@ static bool eval_const_expr_implicit_cast(IrAnalyze *ira, IrInstruction *source_ zig_unreachable(); case CastOpErrSet: case CastOpBitCast: - case CastOpPtrOfArrayToSlice: zig_panic("TODO"); case CastOpNoop: { @@ -10574,7 +10625,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_unknown_len_ptr(IrAnalyze *ira, } static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *value, ZigType *wanted_type) + IrInstruction *value, ZigType *wanted_type, ResultLoc *result_loc) { Error err; @@ -10605,11 +10656,12 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc } } - IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, - wanted_type, value, CastOpPtrOfArrayToSlice); - result->value.type = wanted_type; - ir_add_alloca(ira, result, wanted_type); - return result; + if (result_loc == nullptr) result_loc = no_result_loc(); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + return ir_build_ptr_of_array_to_slice(ira, source_instr, wanted_type, value, result_loc_inst); } static IrBasicBlock *ir_get_new_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrInstruction *ref_old_instruction) { @@ -11195,7 +11247,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi } static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *array_arg, ZigType *wanted_type) + IrInstruction *array_arg, ZigType *wanted_type, ResultLoc *result_loc) { assert(is_slice(wanted_type)); // In this function we honor the const-ness of wanted_type, because @@ -11227,12 +11279,14 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false); - IrInstruction *result = ir_build_slice(&ira->new_irb, source_instr->scope, - source_instr->source_node, array_ptr, start, end, false); - result->value.type = wanted_type; + if (result_loc == nullptr) result_loc = no_result_loc(); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + IrInstruction *result = ir_build_slice_gen(ira, source_instr, wanted_type, array_ptr, start, end, false, result_loc_inst); result->value.data.rh_slice.id = RuntimeHintSliceIdLen; result->value.data.rh_slice.len = array_type->data.array.len; - ir_add_alloca(ira, result, result->value.type); return result; } @@ -11929,7 +11983,7 @@ static bool is_pointery_and_elem_is_not_pointery(ZigType *ty) { } static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, - ZigType *wanted_type, IrInstruction *value) + ZigType *wanted_type, IrInstruction *value, ResultLoc *result_loc) { Error err; ZigType *actual_type = value->value.type; @@ -12017,11 +12071,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value, nullptr); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12103,7 +12157,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type); + return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type, result_loc); } } @@ -12120,11 +12174,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value, nullptr); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12167,7 +12221,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst array_type->data.array.child_type, source_node, !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk) { - return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type); + return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type, result_loc); } } @@ -12198,11 +12252,11 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type, source_node, false).id == ConstCastResultIdOk) { - IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value); + IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value, nullptr); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1); + IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1, result_loc); if (type_is_invalid(cast2->value.type)) return ira->codegen->invalid_instruction; @@ -12380,7 +12434,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst return ira->codegen->invalid_instruction; } -static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type) { +static IrInstruction *ir_implicit_cast_with_result(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type, + ResultLoc *result_loc) +{ assert(value); assert(value != ira->codegen->invalid_instruction); assert(!expected_type || !type_is_invalid(expected_type)); @@ -12393,7 +12449,11 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig if (value->value.type->id == ZigTypeIdUnreachable) return value; - return ir_analyze_cast(ira, value, expected_type, value); + return ir_analyze_cast(ira, value, expected_type, value, result_loc); +} + +static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type) { + return ir_implicit_cast_with_result(ira, value, expected_type, nullptr); } static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) { @@ -14744,7 +14804,7 @@ static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrIns if (type_is_invalid(target->value.type)) return ira->codegen->invalid_instruction; - return ir_implicit_cast(ira, target, dest_type); + return ir_implicit_cast_with_result(ira, target, dest_type, instruction->result_loc); } static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { @@ -15687,7 +15747,8 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC IrInstruction *arg = call_instruction->args[0]->child; - IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg); + IrInstruction *cast_instruction = ir_analyze_cast(ira, &call_instruction->base, dest_type, arg, + call_instruction->result_loc); if (type_is_invalid(cast_instruction->value.type)) return ira->codegen->invalid_instruction; return ir_finish_anal(ira, cast_instruction); @@ -21165,7 +21226,7 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio return result; } -static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSlice *instruction) { +static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstructionSliceSrc *instruction) { IrInstruction *ptr_ptr = instruction->ptr->child; if (type_is_invalid(ptr_ptr->value.type)) return ira->codegen->invalid_instruction; @@ -21454,12 +21515,13 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction return result; } - IrInstruction *new_instruction = ir_build_slice(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, - ptr_ptr, casted_start, end, instruction->safety_check_on); - new_instruction->value.type = return_type; - ir_add_alloca(ira, new_instruction, return_type); - return new_instruction; + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + return_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + return ir_build_slice_gen(ira, &instruction->base, return_type, + ptr_ptr, casted_start, end, instruction->safety_check_on, result_loc); } static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInstructionMemberCount *instruction) { @@ -23900,6 +23962,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdCmpxchgGen: case IrInstructionIdArrayToVector: case IrInstructionIdVectorToArray: + case IrInstructionIdPtrOfArrayToSlice: case IrInstructionIdAssertZero: case IrInstructionIdAssertNonNull: case IrInstructionIdResizeSlice: @@ -23908,6 +23971,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdCallGen: case IrInstructionIdReturnPtr: case IrInstructionIdAllocaGen: + case IrInstructionIdSliceGen: zig_unreachable(); case IrInstructionIdReturn: @@ -24042,8 +24106,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction); case IrInstructionIdMemcpy: return ir_analyze_instruction_memcpy(ira, (IrInstructionMemcpy *)instruction); - case IrInstructionIdSlice: - return ir_analyze_instruction_slice(ira, (IrInstructionSlice *)instruction); + case IrInstructionIdSliceSrc: + return ir_analyze_instruction_slice(ira, (IrInstructionSliceSrc *)instruction); case IrInstructionIdMemberCount: return ir_analyze_instruction_member_count(ira, (IrInstructionMemberCount *)instruction); case IrInstructionIdMemberType: @@ -24321,6 +24385,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdGlobalAsm: case IrInstructionIdUndeclaredIdent: case IrInstructionIdEndExpr: + case IrInstructionIdPtrOfArrayToSlice: + case IrInstructionIdSliceGen: return true; case IrInstructionIdPhi: @@ -24360,7 +24426,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdIntType: case IrInstructionIdVectorType: case IrInstructionIdBoolNot: - case IrInstructionIdSlice: + case IrInstructionIdSliceSrc: case IrInstructionIdMemberCount: case IrInstructionIdMemberType: case IrInstructionIdMemberName: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 925d802e6d..e80ddf401b 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -858,14 +858,26 @@ static void ir_print_memcpy(IrPrint *irp, IrInstructionMemcpy *instruction) { fprintf(irp->f, ")"); } -static void ir_print_slice(IrPrint *irp, IrInstructionSlice *instruction) { +static void ir_print_slice_src(IrPrint *irp, IrInstructionSliceSrc *instruction) { ir_print_other_instruction(irp, instruction->ptr); fprintf(irp->f, "["); ir_print_other_instruction(irp, instruction->start); fprintf(irp->f, ".."); if (instruction->end) ir_print_other_instruction(irp, instruction->end); - fprintf(irp->f, "]"); + fprintf(irp->f, "]result="); + ir_print_result_loc(irp, instruction->result_loc); +} + +static void ir_print_slice_gen(IrPrint *irp, IrInstructionSliceGen *instruction) { + ir_print_other_instruction(irp, instruction->ptr); + fprintf(irp->f, "["); + ir_print_other_instruction(irp, instruction->start); + fprintf(irp->f, ".."); + if (instruction->end) + ir_print_other_instruction(irp, instruction->end); + fprintf(irp->f, "]result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_member_count(IrPrint *irp, IrInstructionMemberCount *instruction) { @@ -1086,6 +1098,13 @@ static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *i fprintf(irp->f, ")"); } +static void ir_print_ptr_of_array_to_slice(IrPrint *irp, IrInstructionPtrOfArrayToSlice *instruction) { + fprintf(irp->f, "PtrOfArrayToSlice("); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); +} + static void ir_print_assert_zero(IrPrint *irp, IrInstructionAssertZero *instruction) { fprintf(irp->f, "AssertZero("); ir_print_other_instruction(irp, instruction->target); @@ -1758,8 +1777,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdMemcpy: ir_print_memcpy(irp, (IrInstructionMemcpy *)instruction); break; - case IrInstructionIdSlice: - ir_print_slice(irp, (IrInstructionSlice *)instruction); + case IrInstructionIdSliceSrc: + ir_print_slice_src(irp, (IrInstructionSliceSrc *)instruction); + break; + case IrInstructionIdSliceGen: + ir_print_slice_gen(irp, (IrInstructionSliceGen *)instruction); break; case IrInstructionIdMemberCount: ir_print_member_count(irp, (IrInstructionMemberCount *)instruction); @@ -1992,6 +2014,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdVectorToArray: ir_print_vector_to_array(irp, (IrInstructionVectorToArray *)instruction); break; + case IrInstructionIdPtrOfArrayToSlice: + ir_print_ptr_of_array_to_slice(irp, (IrInstructionPtrOfArrayToSlice *)instruction); + break; case IrInstructionIdAssertZero: ir_print_assert_zero(irp, (IrInstructionAssertZero *)instruction); break; -- cgit v1.2.3 From eaa9d8bdac7f64e38a39607e5d5574f88f8fe875 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 16:20:13 -0400 Subject: result location semantics for optional wrap --- src/all_types.hpp | 4 ++-- src/codegen.cpp | 13 +++++-------- src/ir.cpp | 33 +++++++++++++++++++++------------ src/ir_print.cpp | 11 ++++++----- 4 files changed, 34 insertions(+), 27 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 73580619ed..d2e7a7f631 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3095,8 +3095,8 @@ struct IrInstructionUnwrapErrPayload { struct IrInstructionOptionalWrap { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionErrWrapPayload { diff --git a/src/codegen.cpp b/src/codegen.cpp index f748c575b0..e88cee4186 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4956,20 +4956,20 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I return LLVMConstInt(LLVMInt1Type(), 1, false); } - LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); + LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); if (!handle_is_ptr(wanted_type)) { return payload_val; } - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); + LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, ""); // child_type and instruction->value->value.type may differ by constness gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); - LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, ""); + LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_null_index, ""); gen_store_untyped(g, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr, 0, false); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapCode *instruction) { @@ -6840,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdOptionalWrap) { - IrInstructionOptionalWrap *maybe_wrap_instruction = (IrInstructionOptionalWrap *)instruction; - slot = &maybe_wrap_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdErrWrapPayload) { IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction; slot = &err_wrap_payload_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index cc28d3981c..58f6b14450 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1758,11 +1758,17 @@ static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, return &instruction->base; } -static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionOptionalWrap *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; +static IrInstruction *ir_build_optional_wrap(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_ty, + IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionOptionalWrap *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_ty; + instruction->operand = operand; + instruction->result_loc = result_loc; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11035,7 +11041,7 @@ static ZigFn *ir_resolve_fn(IrAnalyze *ira, IrInstruction *fn_value) { } static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, - ZigType *wanted_type) + ZigType *wanted_type, ResultLoc *result_loc) { assert(wanted_type->id == ZigTypeIdOptional); @@ -11061,10 +11067,13 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so return &const_instruction->base; } - IrInstruction *result = ir_build_maybe_wrap(&ira->new_irb, source_instr->scope, source_instr->source_node, value); - result->value.type = wanted_type; + if (result_loc == nullptr) result_loc = no_result_loc(); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + IrInstruction *result = ir_build_optional_wrap(ira, source_instr, wanted_type, value, result_loc_inst); result->value.data.rh_maybe = RuntimeHintOptionalNonNull; - ir_add_alloca(ira, result, wanted_type); return result; } @@ -12009,12 +12018,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type, result_loc); } else if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) { - return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, value, wanted_type, result_loc); } else { return ira->codegen->invalid_instruction; } @@ -12038,7 +12047,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst wanted_child_type); if (type_is_invalid(cast1->value.type)) return ira->codegen->invalid_instruction; - return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type); + return ir_analyze_optional_wrap(ira, source_instr, cast1, wanted_type, result_loc); } } } @@ -24387,6 +24396,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdEndExpr: case IrInstructionIdPtrOfArrayToSlice: case IrInstructionIdSliceGen: + case IrInstructionIdOptionalWrap: return true; case IrInstructionIdPhi: @@ -24436,7 +24446,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdHandle: case IrInstructionIdTestErr: case IrInstructionIdUnwrapErrCode: - case IrInstructionIdOptionalWrap: case IrInstructionIdErrWrapCode: case IrInstructionIdErrWrapPayload: case IrInstructionIdFnProto: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index e80ddf401b..6cad5c1dea 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -970,10 +970,11 @@ static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayl } } -static void ir_print_maybe_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) { - fprintf(irp->f, "@maybeWrap("); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); +static void ir_print_optional_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) { + fprintf(irp->f, "@optionalWrap("); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instruction) { @@ -1820,7 +1821,7 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_unwrap_err_payload(irp, (IrInstructionUnwrapErrPayload *)instruction); break; case IrInstructionIdOptionalWrap: - ir_print_maybe_wrap(irp, (IrInstructionOptionalWrap *)instruction); + ir_print_optional_wrap(irp, (IrInstructionOptionalWrap *)instruction); break; case IrInstructionIdErrWrapCode: ir_print_err_wrap_code(irp, (IrInstructionErrWrapCode *)instruction); -- cgit v1.2.3 From 4f085b8d2c8ffb03dd15b789ad5867904faae13d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 16:55:07 -0400 Subject: result location semantics for error union wrapping a payload --- BRANCH_TODO | 14 +------------- src/all_types.hpp | 4 ++-- src/codegen.cpp | 16 +++++++--------- src/ir.cpp | 43 ++++++++++++++++++++++++++++++------------- src/ir_print.cpp | 5 +++-- 5 files changed, 43 insertions(+), 39 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index e744162fa0..f6fd78dbaa 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -6,17 +6,5 @@ look at all the ir_gen_node ir_gen_node_extra calls and make sure result locatio migrate all the alloca_list to alloca_gen_list -inferred comptime - - - if (lval == LValNone) { - if (result_loc->id == ResultLocIdNone) - return value; - } - - assert(lval == LValPtr); - - // We needed a pointer to a value, but we got a value. So we create - // an instruction which just makes a pointer of it. - return ir_build_ref(irb, scope, value->source_node, value, false, false); +comptime expressions diff --git a/src/all_types.hpp b/src/all_types.hpp index d2e7a7f631..f13f16152d 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3102,8 +3102,8 @@ struct IrInstructionOptionalWrap { struct IrInstructionErrWrapPayload { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionErrWrapCode { diff --git a/src/codegen.cpp b/src/codegen.cpp index e88cee4186..69b234d160 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5002,7 +5002,7 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa ZigType *err_set_type = wanted_type->data.error_union.err_set_type; if (!type_has_bits(err_set_type)) { - return ir_llvm_value(g, instruction->value); + return ir_llvm_value(g, instruction->operand); } LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); @@ -5010,17 +5010,18 @@ static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executa if (!type_has_bits(payload_type)) return ok_err_val; - assert(instruction->tmp_ptr); - LLVMValueRef payload_val = ir_llvm_value(g, instruction->value); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); + + LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_err_index, ""); gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); - LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, ""); + LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_payload_index, ""); gen_assign_raw(g, payload_ptr, get_pointer_to_type(g, payload_type, false), payload_val); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_union_tag(CodeGen *g, IrExecutable *executable, IrInstructionUnionTag *instruction) { @@ -6840,9 +6841,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdErrWrapPayload) { - IrInstructionErrWrapPayload *err_wrap_payload_instruction = (IrInstructionErrWrapPayload *)instruction; - slot = &err_wrap_payload_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdErrWrapCode) { IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; slot = &err_wrap_code_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 58f6b14450..10752cdc64 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1773,11 +1773,17 @@ static IrInstruction *ir_build_optional_wrap(IrAnalyze *ira, IrInstruction *sour return &instruction->base; } -static IrInstruction *ir_build_err_wrap_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionErrWrapPayload *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; +static IrInstruction *ir_build_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instruction, + ZigType *result_type, IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionErrWrapPayload *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->operand = operand; + instruction->result_loc = result_loc; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11078,12 +11084,13 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so } static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *value, ZigType *wanted_type) + IrInstruction *value, ZigType *wanted_type, ResultLoc *result_loc) { assert(wanted_type->id == ZigTypeIdErrorUnion); + ZigType *payload_type = wanted_type->data.error_union.payload_type; + ZigType *err_set_type = wanted_type->data.error_union.err_set_type; if (instr_is_comptime(value)) { - ZigType *payload_type = wanted_type->data.error_union.payload_type; IrInstruction *casted_payload = ir_implicit_cast(ira, value, payload_type); if (type_is_invalid(casted_payload->value.type)) return ira->codegen->invalid_instruction; @@ -11093,7 +11100,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction return ira->codegen->invalid_instruction; ConstExprValue *err_set_val = create_const_vals(1); - err_set_val->type = wanted_type->data.error_union.err_set_type; + err_set_val->type = err_set_type; err_set_val->special = ConstValSpecialStatic; err_set_val->data.x_err_set = nullptr; @@ -11106,10 +11113,19 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction return &const_instruction->base; } - IrInstruction *result = ir_build_err_wrap_payload(&ira->new_irb, source_instr->scope, source_instr->source_node, value); - result->value.type = wanted_type; + IrInstruction *result_loc_inst; + if (handle_is_ptr(wanted_type)) { + if (result_loc == nullptr) result_loc = no_result_loc(); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + } else { + result_loc_inst = nullptr; + } + + IrInstruction *result = ir_build_err_wrap_payload(ira, source_instr, wanted_type, value, result_loc_inst); result->value.data.rh_error_union = RuntimeHintErrorUnionNonError; - ir_add_alloca(ira, result, wanted_type); return result; } @@ -12057,12 +12073,12 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type, result_loc); } else if (actual_type->id == ZigTypeIdComptimeInt || actual_type->id == ZigTypeIdComptimeFloat) { if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) { - return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type); + return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type, result_loc); } else { return ira->codegen->invalid_instruction; } @@ -24447,7 +24463,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTestErr: case IrInstructionIdUnwrapErrCode: case IrInstructionIdErrWrapCode: - case IrInstructionIdErrWrapPayload: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: @@ -24512,6 +24527,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { (IrInstructionUnwrapErrPayload *)instruction; return unwrap_err_payload_instruction->safety_check_on; } + case IrInstructionIdErrWrapPayload: + return reinterpret_cast(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 6cad5c1dea..7cff6f3d70 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -985,8 +985,9 @@ static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instr static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload *instruction) { fprintf(irp->f, "@errWrapPayload("); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_fn_proto(IrPrint *irp, IrInstructionFnProto *instruction) { -- cgit v1.2.3 From b9c033ae1ac9c21a5729407b9a6ede88854654aa Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 17:28:25 -0400 Subject: result location semantics for error union wrapping an error --- src/all_types.hpp | 4 +-- src/codegen.cpp | 18 ++++++-------- src/ir.cpp | 73 +++++++++++++++++++++++++++++++++++++------------------ src/ir_print.cpp | 5 ++-- 4 files changed, 61 insertions(+), 39 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index f13f16152d..7c06719e90 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3109,8 +3109,8 @@ struct IrInstructionErrWrapPayload { struct IrInstructionErrWrapCode { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionFnProto { diff --git a/src/codegen.cpp b/src/codegen.cpp index 69b234d160..ce844806d9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4977,20 +4977,19 @@ static LLVMValueRef ir_render_err_wrap_code(CodeGen *g, IrExecutable *executable assert(wanted_type->id == ZigTypeIdErrorUnion); - ZigType *payload_type = wanted_type->data.error_union.payload_type; - ZigType *err_set_type = wanted_type->data.error_union.err_set_type; + LLVMValueRef err_val = ir_llvm_value(g, instruction->operand); - LLVMValueRef err_val = ir_llvm_value(g, instruction->value); - - if (!type_has_bits(payload_type) || !type_has_bits(err_set_type)) + if (!handle_is_ptr(wanted_type)) return err_val; - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); - LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_err_index, ""); + LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, result_loc, err_union_err_index, ""); gen_store_untyped(g, err_val, err_tag_ptr, 0, false); - return instruction->tmp_ptr; + // TODO store undef to the payload + + return result_loc; } static LLVMValueRef ir_render_err_wrap_payload(CodeGen *g, IrExecutable *executable, IrInstructionErrWrapPayload *instruction) { @@ -6841,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdErrWrapCode) { - IrInstructionErrWrapCode *err_wrap_code_instruction = (IrInstructionErrWrapCode *)instruction; - slot = &err_wrap_code_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdCmpxchgGen) { IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; slot = &cmpxchg_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 10752cdc64..1a0c7d3144 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1788,11 +1788,17 @@ static IrInstruction *ir_build_err_wrap_payload(IrAnalyze *ira, IrInstruction *s return &instruction->base; } -static IrInstruction *ir_build_err_wrap_code(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionErrWrapCode *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; +static IrInstruction *ir_build_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instruction, + ZigType *result_type, IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionErrWrapCode *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->operand = operand; + instruction->result_loc = result_loc; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11172,7 +11178,9 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou return result; } -static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *wanted_type) { +static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, + ZigType *wanted_type, ResultLoc *result_loc) +{ assert(wanted_type->id == ZigTypeIdErrorUnion); IrInstruction *casted_value = ir_implicit_cast(ira, value, wanted_type->data.error_union.err_set_type); @@ -11196,10 +11204,20 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so return &const_instruction->base; } - IrInstruction *result = ir_build_err_wrap_code(&ira->new_irb, source_instr->scope, source_instr->source_node, value); - result->value.type = wanted_type; + IrInstruction *result_loc_inst; + if (handle_is_ptr(wanted_type)) { + if (result_loc == nullptr) result_loc = no_result_loc(); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + } else { + result_loc_inst = nullptr; + } + + + IrInstruction *result = ir_build_err_wrap_code(ira, source_instr, wanted_type, value, result_loc_inst); result->value.data.rh_error_union = RuntimeHintErrorUnionError; - ir_add_alloca(ira, result, wanted_type); return result; } @@ -12293,7 +12311,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (wanted_type->id == ZigTypeIdErrorUnion && actual_type->id == ZigTypeIdErrorSet) { - return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type); + return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type, result_loc); } // cast from typed number to integer or float literal. @@ -15615,12 +15633,16 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c } FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; - IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, - impl_fn_type_id->return_type, nullptr); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value.type) || result_loc->value.type->id == ZigTypeIdUnreachable)) - { - return result_loc; + IrInstruction *result_loc; + if (handle_is_ptr(impl_fn_type_id->return_type)) { + result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, + impl_fn_type_id->return_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + call_instruction->result_loc->written = true; + } else { + result_loc = nullptr; } if (fn_type_can_fail(impl_fn_type_id)) { @@ -15634,7 +15656,6 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ir_finish_anal(ira, result); } - call_instruction->result_loc->written = handle_is_ptr(impl_fn_type_id->return_type); assert(async_allocator_inst == nullptr); IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, impl_fn, nullptr, impl_param_count, casted_args, fn_inline, @@ -15733,15 +15754,18 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c return ira->codegen->invalid_instruction; } - IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, - return_type, nullptr); - if (result_loc != nullptr && - (type_is_invalid(result_loc->value.type) || result_loc->value.type->id == ZigTypeIdUnreachable)) - { - return result_loc; + IrInstruction *result_loc; + if (handle_is_ptr(return_type)) { + result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, + return_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + call_instruction->result_loc->written = true; + } else { + result_loc = nullptr; } - call_instruction->result_loc->written = handle_is_ptr(return_type); IrInstruction *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, call_param_count, casted_args, fn_inline, false, nullptr, casted_new_stack, result_loc, return_type); @@ -24462,7 +24486,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdHandle: case IrInstructionIdTestErr: case IrInstructionIdUnwrapErrCode: - case IrInstructionIdErrWrapCode: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: @@ -24529,6 +24552,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { } case IrInstructionIdErrWrapPayload: return reinterpret_cast(instruction)->result_loc != nullptr; + case IrInstructionIdErrWrapCode: + return reinterpret_cast(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 7cff6f3d70..30ca2aa73e 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -979,8 +979,9 @@ static void ir_print_optional_wrap(IrPrint *irp, IrInstructionOptionalWrap *inst static void ir_print_err_wrap_code(IrPrint *irp, IrInstructionErrWrapCode *instruction) { fprintf(irp->f, "@errWrapCode("); - ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload *instruction) { -- cgit v1.2.3 From ee3f7e20f64d715ff22eeff0b7b355bca1981ea1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 17:49:36 -0400 Subject: result location semantics for cmpxchg --- src/all_types.hpp | 12 ++++++------ src/codegen.cpp | 19 ++++++++----------- src/ir.cpp | 33 +++++++++++++++++++++++---------- src/ir_print.cpp | 6 ++++-- 4 files changed, 41 insertions(+), 29 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 7c06719e90..7a4a450c49 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2862,26 +2862,26 @@ struct IrInstructionEmbedFile { struct IrInstructionCmpxchgSrc { IrInstruction base; + bool is_weak; IrInstruction *type_value; IrInstruction *ptr; IrInstruction *cmp_value; IrInstruction *new_value; IrInstruction *success_order_value; IrInstruction *failure_order_value; - - bool is_weak; + ResultLoc *result_loc; }; struct IrInstructionCmpxchgGen { IrInstruction base; + bool is_weak; + AtomicOrder success_order; + AtomicOrder failure_order; IrInstruction *ptr; IrInstruction *cmp_value; IrInstruction *new_value; - LLVMValueRef tmp_ptr; - AtomicOrder success_order; - AtomicOrder failure_order; - bool is_weak; + IrInstruction *result_loc; }; struct IrInstructionFence { diff --git a/src/codegen.cpp b/src/codegen.cpp index ce844806d9..7845ee7289 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4516,28 +4516,28 @@ static LLVMValueRef ir_render_cmpxchg(CodeGen *g, IrExecutable *executable, IrIn LLVMValueRef result_val = ZigLLVMBuildCmpXchg(g->builder, ptr_val, cmp_val, new_val, success_order, failure_order, instruction->is_weak); - ZigType *maybe_type = instruction->base.value.type; - assert(maybe_type->id == ZigTypeIdOptional); - ZigType *child_type = maybe_type->data.maybe.child_type; + ZigType *optional_type = instruction->base.value.type; + assert(optional_type->id == ZigTypeIdOptional); + ZigType *child_type = optional_type->data.maybe.child_type; - if (!handle_is_ptr(maybe_type)) { + if (!handle_is_ptr(optional_type)) { LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); return LLVMBuildSelect(g->builder, success_bit, LLVMConstNull(get_llvm_type(g, child_type)), payload_val, ""); } - assert(instruction->tmp_ptr != nullptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); assert(type_has_bits(child_type)); LLVMValueRef payload_val = LLVMBuildExtractValue(g->builder, result_val, 0, ""); - LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); + LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_child_index, ""); gen_assign_raw(g, val_ptr, get_pointer_to_type(g, child_type, false), payload_val); LLVMValueRef success_bit = LLVMBuildExtractValue(g->builder, result_val, 1, ""); LLVMValueRef nonnull_bit = LLVMBuildNot(g->builder, success_bit, ""); - LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, ""); + LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, result_loc, maybe_null_index, ""); gen_store_untyped(g, nonnull_bit, maybe_ptr, 0, false); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_fence(CodeGen *g, IrExecutable *executable, IrInstructionFence *instruction) { @@ -6840,9 +6840,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdCmpxchgGen) { - IrInstructionCmpxchgGen *cmpxchg_instruction = (IrInstructionCmpxchgGen *)instruction; - slot = &cmpxchg_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdResizeSlice) { IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction; slot = &resize_slice_instruction->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 1a0c7d3144..6a2ad9125c 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2032,8 +2032,7 @@ static IrInstruction *ir_build_embed_file(IrBuilder *irb, Scope *scope, AstNode static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *type_value, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, - IrInstruction *success_order_value, IrInstruction *failure_order_value, - bool is_weak) + IrInstruction *success_order_value, IrInstruction *failure_order_value, bool is_weak, ResultLoc *result_loc) { IrInstructionCmpxchgSrc *instruction = ir_build_instruction(irb, scope, source_node); instruction->type_value = type_value; @@ -2043,6 +2042,7 @@ static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode instruction->success_order_value = success_order_value; instruction->failure_order_value = failure_order_value; instruction->is_weak = is_weak; + instruction->result_loc = result_loc; ir_ref_instruction(type_value, irb->current_basic_block); ir_ref_instruction(ptr, irb->current_basic_block); @@ -2054,22 +2054,25 @@ static IrInstruction *ir_build_cmpxchg_src(IrBuilder *irb, Scope *scope, AstNode return &instruction->base; } -static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, +static IrInstruction *ir_build_cmpxchg_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_type, IrInstruction *ptr, IrInstruction *cmp_value, IrInstruction *new_value, - AtomicOrder success_order, AtomicOrder failure_order, bool is_weak) + AtomicOrder success_order, AtomicOrder failure_order, bool is_weak, IrInstruction *result_loc) { IrInstructionCmpxchgGen *instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; instruction->ptr = ptr; instruction->cmp_value = cmp_value; instruction->new_value = new_value; instruction->success_order = success_order; instruction->failure_order = failure_order; instruction->is_weak = is_weak; + instruction->result_loc = result_loc; ir_ref_instruction(ptr, ira->new_irb.current_basic_block); ir_ref_instruction(cmp_value, ira->new_irb.current_basic_block); ir_ref_instruction(new_value, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -4420,7 +4423,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg5_value; IrInstruction *cmpxchg = ir_build_cmpxchg_src(irb, scope, node, arg0_value, arg1_value, - arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak)); + arg2_value, arg3_value, arg4_value, arg5_value, (builtin_fn->id == BuiltinFnIdCmpxchgWeak), + result_loc); return ir_lval_wrap(irb, scope, cmpxchg, lval, result_loc); } case BuiltinFnIdFence: @@ -20439,6 +20443,18 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi if (type_is_invalid(ptr->value.type)) return ira->codegen->invalid_instruction; + ZigType *result_type = get_optional_type(ira->codegen, operand_type); + IrInstruction *result_loc; + if (handle_is_ptr(result_type)) { + result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + result_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + } else { + result_loc = nullptr; + } + // TODO let this be volatile ZigType *ptr_type = get_pointer_to_type(ira->codegen, operand_type, false); IrInstruction *casted_ptr = ir_implicit_cast(ira, ptr, ptr_type); @@ -20502,12 +20518,9 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi zig_panic("TODO compile-time execution of cmpxchg"); } - IrInstruction *result = ir_build_cmpxchg_gen(ira, &instruction->base, + return ir_build_cmpxchg_gen(ira, &instruction->base, result_type, casted_ptr, casted_cmp_value, casted_new_value, - success_order, failure_order, instruction->is_weak); - result->value.type = get_optional_type(ira->codegen, operand_type); - ir_add_alloca(ira, result, result->value.type); - return result; + success_order, failure_order, instruction->is_weak, result_loc); } static IrInstruction *ir_analyze_instruction_fence(IrAnalyze *ira, IrInstructionFence *instruction) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 30ca2aa73e..1dd84254fc 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -730,7 +730,8 @@ static void ir_print_cmpxchg_src(IrPrint *irp, IrInstructionCmpxchgSrc *instruct ir_print_other_instruction(irp, instruction->success_order_value); fprintf(irp->f, ", "); ir_print_other_instruction(irp, instruction->failure_order_value); - fprintf(irp->f, ")"); + fprintf(irp->f, ")result="); + ir_print_result_loc(irp, instruction->result_loc); } static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruction) { @@ -740,7 +741,8 @@ static void ir_print_cmpxchg_gen(IrPrint *irp, IrInstructionCmpxchgGen *instruct ir_print_other_instruction(irp, instruction->cmp_value); fprintf(irp->f, ", "); ir_print_other_instruction(irp, instruction->new_value); - fprintf(irp->f, ", TODO print atomic orders)"); + fprintf(irp->f, ", TODO print atomic orders)result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_fence(IrPrint *irp, IrInstructionFence *instruction) { -- cgit v1.2.3 From 65f6ea66f4a86c45004547bb5ac079b8286f980e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 18:34:27 -0400 Subject: result loc semantics for `@sliceToBytes` and `@bytesToSlice` --- src/all_types.hpp | 4 +++- src/codegen.cpp | 13 ++++--------- src/ir.cpp | 42 ++++++++++++++++++++++++++++++------------ src/ir_print.cpp | 3 ++- 4 files changed, 39 insertions(+), 23 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 7a4a450c49..e196b6f38f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2635,7 +2635,7 @@ struct IrInstructionResizeSlice { IrInstruction base; IrInstruction *operand; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionContainerInitList { @@ -2925,6 +2925,7 @@ struct IrInstructionToBytes { IrInstruction base; IrInstruction *target; + ResultLoc *result_loc; }; struct IrInstructionFromBytes { @@ -2932,6 +2933,7 @@ struct IrInstructionFromBytes { IrInstruction *dest_child_type; IrInstruction *target; + ResultLoc *result_loc; }; struct IrInstructionIntToFloat { diff --git a/src/codegen.cpp b/src/codegen.cpp index 7845ee7289..d84bcd1327 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2943,7 +2943,7 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutable *executable, LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); assert(expr_val); - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); assert(wanted_type->id == ZigTypeIdStruct); assert(wanted_type->data.structure.is_slice); assert(actual_type->id == ZigTypeIdStruct); @@ -2964,7 +2964,7 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutable *executable, LLVMValueRef src_ptr = gen_load_untyped(g, src_ptr_ptr, 0, false, ""); LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, src_ptr, get_llvm_type(g, wanted_type->data.structure.fields[0].type_entry), ""); - LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, + LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)wanted_ptr_index, ""); gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false); @@ -2997,12 +2997,10 @@ static LLVMValueRef ir_render_resize_slice(CodeGen *g, IrExecutable *executable, zig_unreachable(); } - LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, - (unsigned)wanted_len_index, ""); + LLVMValueRef dest_len_ptr = LLVMBuildStructGEP(g->builder, result_loc, (unsigned)wanted_len_index, ""); gen_store_untyped(g, new_len, dest_len_ptr, 0, false); - - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, @@ -6840,9 +6838,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdResizeSlice) { - IrInstructionResizeSlice *resize_slice_instruction = (IrInstructionResizeSlice *)instruction; - slot = &resize_slice_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdLoadPtrGen) { IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; slot = &load_ptr_inst->tmp_ptr; diff --git a/src/ir.cpp b/src/ir.cpp index 6a2ad9125c..31235acb85 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1574,14 +1574,16 @@ static IrInstruction *ir_build_var_decl_gen(IrAnalyze *ira, IrInstruction *sourc } static IrInstruction *ir_build_resize_slice(IrAnalyze *ira, IrInstruction *source_instruction, - IrInstruction *operand, ZigType *ty) + IrInstruction *operand, ZigType *ty, IrInstruction *result_loc) { IrInstructionResizeSlice *instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = ty; instruction->operand = operand; + instruction->result_loc = result_loc; ir_ref_instruction(operand, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -2131,19 +2133,25 @@ static IrInstruction *ir_build_err_set_cast(IrBuilder *irb, Scope *scope, AstNod return &instruction->base; } -static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target) { +static IrInstruction *ir_build_to_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *target, + ResultLoc *result_loc) +{ IrInstructionToBytes *instruction = ir_build_instruction(irb, scope, source_node); instruction->target = target; + instruction->result_loc = result_loc; ir_ref_instruction(target, irb->current_basic_block); return &instruction->base; } -static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_child_type, IrInstruction *target) { +static IrInstruction *ir_build_from_bytes(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *dest_child_type, IrInstruction *target, ResultLoc *result_loc) +{ IrInstructionFromBytes *instruction = ir_build_instruction(irb, scope, source_node); instruction->dest_child_type = dest_child_type; instruction->target = target; + instruction->result_loc = result_loc; ir_ref_instruction(dest_child_type, irb->current_basic_block); ir_ref_instruction(target, irb->current_basic_block); @@ -4599,7 +4607,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value); + IrInstruction *result = ir_build_from_bytes(irb, scope, node, arg0_value, arg1_value, result_loc); return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdToBytes: @@ -4609,7 +4617,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg0_value == irb->codegen->invalid_instruction) return arg0_value; - IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value); + IrInstruction *result = ir_build_to_bytes(irb, scope, node, arg0_value, result_loc); return ir_lval_wrap(irb, scope, result, lval, result_loc); } case BuiltinFnIdIntToFloat: @@ -5681,7 +5689,8 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A ir_ref_instruction(elem_ptr, irb->current_basic_block); ResultLoc *child_result_loc = &result_loc_inst->base; - IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, child_result_loc); + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, &result_loc->scope_elide->base, + LValNone, child_result_loc); if (expr_value == irb->codegen->invalid_instruction) return expr_value; @@ -14687,6 +14696,7 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s if (fn_entry != nullptr) { fn_entry->alloca_gen_list.append(alloca_gen); } + result_loc->written = true; result_loc->resolved_loc = &alloca_gen->base; return result_loc->resolved_loc; } @@ -20766,6 +20776,12 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru } } + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + dest_slice_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + if (casted_value->value.data.rh_slice.id == RuntimeHintSliceIdLen) { known_len = casted_value->value.data.rh_slice.len; have_known_len = true; @@ -20785,9 +20801,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru } } - IrInstruction *result = ir_build_resize_slice(ira, &instruction->base, casted_value, dest_slice_type); - ir_add_alloca(ira, result, dest_slice_type); - return result; + return ir_build_resize_slice(ira, &instruction->base, casted_value, dest_slice_type, result_loc); } static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstructionToBytes *instruction) { @@ -20839,9 +20853,13 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct return result; } - IrInstruction *result = ir_build_resize_slice(ira, &instruction->base, target, dest_slice_type); - ir_add_alloca(ira, result, dest_slice_type); - return result; + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + dest_slice_type, nullptr); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + + return ir_build_resize_slice(ira, &instruction->base, target, dest_slice_type, result_loc); } static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1dd84254fc..3729fab308 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1125,7 +1125,8 @@ static void ir_print_assert_non_null(IrPrint *irp, IrInstructionAssertNonNull *i static void ir_print_resize_slice(IrPrint *irp, IrInstructionResizeSlice *instruction) { fprintf(irp->f, "@resizeSlice("); ir_print_other_instruction(irp, instruction->operand); - fprintf(irp->f, ")"); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_alloca_src(IrPrint *irp, IrInstructionAllocaSrc *instruction) { -- cgit v1.2.3 From 9a324ecb42f69791d49bc8e62e935aec75b5e920 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 19:11:34 -0400 Subject: result loc semantics for loading packed struct pointer to packed struct ```zig export fn entry() void { var x = foo(); var ptr = &x.b; var y = ptr.*; } const Foo = packed struct { a: u24 = 1, b: Bar = Bar{}, }; const Bar = packed struct { a: u4 = 2, b: u4 = 3, }; ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %x = alloca %Foo, align 1 %ptr = alloca i32*, align 8 %y = alloca %Bar, align 1 call fastcc void @foo(%Foo* sret %x), !dbg !55 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !39, metadata !DIExpression()), !dbg !56 %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0, !dbg !57 store i32* %0, i32** %ptr, align 8, !dbg !57 call void @llvm.dbg.declare(metadata i32** %ptr, metadata !51, metadata !DIExpression()), !dbg !58 %1 = load i32*, i32** %ptr, align 8, !dbg !59 %2 = load i32, i32* %1, align 1, !dbg !60 %3 = lshr i32 %2, 24, !dbg !60 %4 = trunc i32 %3 to i8, !dbg !60 %5 = bitcast %Bar* %y to i8*, !dbg !60 store i8 %4, i8* %5, !dbg !60 call void @llvm.dbg.declare(metadata %Bar* %y, metadata !54, metadata !DIExpression()), !dbg !61 ret void, !dbg !62 } ``` --- src/all_types.hpp | 5 +- src/codegen.cpp | 9 ++-- src/ir.cpp | 145 ++++++++++++++++++++++++++++++------------------------ src/ir_print.cpp | 4 +- 4 files changed, 90 insertions(+), 73 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index e196b6f38f..d7e11f7102 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2449,8 +2449,9 @@ struct IrInstructionUnOp { IrInstruction base; IrUnOp op_id; - IrInstruction *value; LVal lval; + IrInstruction *value; + ResultLoc *result_loc; }; enum IrBinOp { @@ -2507,7 +2508,7 @@ struct IrInstructionLoadPtrGen { IrInstruction base; IrInstruction *ptr; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionStorePtr { diff --git a/src/codegen.cpp b/src/codegen.cpp index d84bcd1327..994194c5eb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3376,13 +3376,13 @@ static LLVMValueRef ir_render_load_ptr(CodeGen *g, IrExecutable *executable, IrI LLVMValueRef shifted_value = LLVMBuildLShr(g->builder, containing_int, shift_amt_val, ""); if (handle_is_ptr(child_type)) { - assert(instruction->tmp_ptr != nullptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); LLVMTypeRef same_size_int = LLVMIntType(size_in_bits); LLVMValueRef truncated_int = LLVMBuildTrunc(g->builder, shifted_value, same_size_int, ""); - LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, + LLVMValueRef bitcasted_ptr = LLVMBuildBitCast(g->builder, result_loc, LLVMPointerType(same_size_int, 0), ""); LLVMBuildStore(g->builder, truncated_int, bitcasted_ptr); - return instruction->tmp_ptr; + return result_loc; } if (child_type->id == ZigTypeIdFloat) { @@ -6838,9 +6838,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdLoadPtrGen) { - IrInstructionLoadPtrGen *load_ptr_inst = (IrInstructionLoadPtrGen *)instruction; - slot = &load_ptr_inst->tmp_ptr; } else if (instruction->id == IrInstructionIdVectorToArray) { IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); diff --git a/src/ir.cpp b/src/ir.cpp index 31235acb85..305b534791 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -161,7 +161,8 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, ResultLoc *result_loc); static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, ZigType *expected_type); -static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr); +static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr, + ResultLoc *result_loc); static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing); @@ -1467,12 +1468,13 @@ static IrInstruction *ir_build_ptr_type(IrBuilder *irb, Scope *scope, AstNode *s } static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, - IrInstruction *value, LVal lval) + IrInstruction *value, LVal lval, ResultLoc *result_loc) { IrInstructionUnOp *instruction = ir_build_instruction(irb, scope, source_node); instruction->op_id = op_id; instruction->value = value; instruction->lval = lval; + instruction->result_loc = result_loc; ir_ref_instruction(value, irb->current_basic_block); @@ -1482,7 +1484,7 @@ static IrInstruction *ir_build_un_op_lval(IrBuilder *irb, Scope *scope, AstNode static IrInstruction *ir_build_un_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrUnOp op_id, IrInstruction *value) { - return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone); + return ir_build_un_op_lval(irb, scope, source_node, op_id, value, LValNone, nullptr); } static IrInstruction *ir_build_container_init_list(IrBuilder *irb, Scope *scope, AstNode *source_node, @@ -2471,14 +2473,16 @@ static IrInstruction *ir_build_ptr_cast_gen(IrAnalyze *ira, IrInstruction *sourc } static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *source_instruction, - IrInstruction *ptr, ZigType *ty) + IrInstruction *ptr, ZigType *ty, IrInstruction *result_loc) { IrInstructionLoadPtrGen *instruction = ir_build_instruction( &ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = ty; instruction->ptr = ptr; + instruction->result_loc = result_loc; ir_ref_instruction(ptr, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -8028,7 +8032,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop // We essentially just converted any lvalue from &(x.*) to (&x).*; // this inhibits checking that x is a pointer later, so we directly // record whether the pointer check is needed - return ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval); + IrInstruction *un_op = ir_build_un_op_lval(irb, scope, node, IrUnOpDereference, value, lval, result_loc); + return ir_expr_wrap(irb, scope, un_op, result_loc); } case NodeTypeUnwrapOptional: { AstNode *expr_node = node->data.unwrap_optional.expr; @@ -11312,7 +11317,7 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s IrInstruction *array_ptr = nullptr; IrInstruction *array; if (array_arg->value.type->id == ZigTypeIdPointer) { - array = ir_get_deref(ira, source_instr, array_arg); + array = ir_get_deref(ira, source_instr, array_arg, nullptr); array_ptr = array_arg; } else { array = array_arg; @@ -12512,60 +12517,71 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig return ir_implicit_cast_with_result(ira, value, expected_type, nullptr); } -static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) { +static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr, + ResultLoc *result_loc) +{ Error err; ZigType *type_entry = ptr->value.type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id == ZigTypeIdPointer) { - ZigType *child_type = type_entry->data.pointer.child_type; - // if the child type has one possible value, the deref is comptime - switch (type_has_one_possible_value(ira->codegen, child_type)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_instruction; - case OnePossibleValueYes: - return ir_const(ira, source_instruction, child_type); - case OnePossibleValueNo: - break; + + if (type_entry->id != ZigTypeIdPointer) { + ir_add_error_node(ira, source_instruction->source_node, + buf_sprintf("attempt to dereference non-pointer type '%s'", + buf_ptr(&type_entry->name))); + return ira->codegen->invalid_instruction; + } + + ZigType *child_type = type_entry->data.pointer.child_type; + // if the child type has one possible value, the deref is comptime + switch (type_has_one_possible_value(ira->codegen, child_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + return ir_const(ira, source_instruction, child_type); + case OnePossibleValueNo: + break; + } + if (instr_is_comptime(ptr)) { + if (ptr->value.special == ConstValSpecialUndef) { + ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value")); + return ira->codegen->invalid_instruction; } - if (instr_is_comptime(ptr)) { - if (ptr->value.special == ConstValSpecialUndef) { - ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value")); - return ira->codegen->invalid_instruction; - } - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst || - ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) - { - ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); - if (pointee->special != ConstValSpecialRuntime) { - IrInstruction *result = ir_const(ira, source_instruction, child_type); + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst || + ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) + { + ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); + if (pointee->special != ConstValSpecialRuntime) { + IrInstruction *result = ir_const(ira, source_instruction, child_type); - if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, - &ptr->value))) - { - return ira->codegen->invalid_instruction; - } - result->value.type = child_type; - return result; + if ((err = ir_read_const_ptr(ira, ira->codegen, source_instruction->source_node, &result->value, + &ptr->value))) + { + return ira->codegen->invalid_instruction; } + result->value.type = child_type; + return result; } } - // if the instruction is a const ref instruction we can skip it - if (ptr->id == IrInstructionIdRef) { - IrInstructionRef *ref_inst = reinterpret_cast(ptr); - return ref_inst->value; - } - IrInstruction *result = ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type); - if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { - ir_add_alloca(ira, result, child_type); + } + // if the instruction is a const ref instruction we can skip it + if (ptr->id == IrInstructionIdRef) { + IrInstructionRef *ref_inst = reinterpret_cast(ptr); + return ref_inst->value; + } + + IrInstruction *result_loc_inst; + if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { + if (result_loc == nullptr) result_loc = no_result_loc(); + result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; } - return result; } else { - ir_add_error_node(ira, source_instruction->source_node, - buf_sprintf("attempt to dereference non-pointer type '%s'", - buf_ptr(&type_entry->name))); - return ira->codegen->invalid_instruction; + result_loc_inst = nullptr; } + + return ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type, result_loc_inst); } static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) { @@ -14585,7 +14601,7 @@ IrInstruction *ir_get_implicit_allocator(IrAnalyze *ira, IrInstruction *source_i ZigVar *coro_allocator_var = ira->old_irb.exec->coro_allocator_var; assert(coro_allocator_var != nullptr); IrInstruction *var_ptr_inst = ir_get_var_ptr(ira, source_instr, coro_allocator_var); - IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst); + IrInstruction *result = ir_get_deref(ira, source_instr, var_ptr_inst, nullptr); assert(result->value.type != nullptr); return result; } @@ -15313,7 +15329,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) { first_arg = first_arg_ptr; } else { - first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); + first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr); if (type_is_invalid(first_arg->value.type)) return ira->codegen->invalid_instruction; } @@ -15472,7 +15488,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) { first_arg = first_arg_ptr; } else { - first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); + first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr); if (type_is_invalid(first_arg->value.type)) return ira->codegen->invalid_instruction; } @@ -15516,7 +15532,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c if (type_is_invalid(arg_var_ptr_inst->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst); + IrInstruction *arg_tuple_arg = ir_get_deref(ira, arg, arg_var_ptr_inst, nullptr); if (type_is_invalid(arg_tuple_arg->value.type)) return ira->codegen->invalid_instruction; @@ -15702,7 +15718,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c { first_arg = first_arg_ptr; } else { - first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr); + first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr, nullptr); if (type_is_invalid(first_arg->value.type)) return ira->codegen->invalid_instruction; } @@ -16113,7 +16129,7 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr); + IrInstruction *result = ir_get_deref(ira, &instruction->base, ptr, instruction->result_loc); if (result == ira->codegen->invalid_instruction) return ira->codegen->invalid_instruction; @@ -16994,7 +17010,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc assert(container_ptr->value.type->id == ZigTypeIdPointer); if (container_type->id == ZigTypeIdPointer) { ZigType *bare_type = container_ref_type(container_type); - IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr); + IrInstruction *container_child = ir_get_deref(ira, &field_ptr_instruction->base, container_ptr, nullptr); IrInstruction *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type, field_ptr_instruction->initializing); return result; } else { @@ -17339,7 +17355,7 @@ static IrInstruction *ir_analyze_instruction_load_ptr(IrAnalyze *ira, IrInstruct IrInstruction *ptr = instruction->ptr->child; if (type_is_invalid(ptr->value.type)) return ira->codegen->invalid_instruction; - return ir_get_deref(ira, &instruction->base, ptr); + return ir_get_deref(ira, &instruction->base, ptr, nullptr); } static IrInstruction *ir_analyze_instruction_typeof(IrAnalyze *ira, IrInstructionTypeOf *typeof_instruction) { @@ -17807,7 +17823,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr } if (!safety_check_on) return base_ptr; - IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr); + IrInstruction *c_ptr_val = ir_get_deref(ira, source_instr, base_ptr, nullptr); ir_build_assert_non_null(ira, source_instr, c_ptr_val); return base_ptr; } @@ -18162,7 +18178,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); + IrInstruction *result = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr); result->value.type = target_type; return result; } @@ -18192,7 +18208,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); + IrInstruction *union_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr); union_value->value.type = target_type; IrInstruction *union_tag_inst = ir_build_union_tag(&ira->new_irb, switch_target_instruction->base.scope, @@ -18216,7 +18232,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, return result; } - IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr); + IrInstruction *enum_value = ir_get_deref(ira, &switch_target_instruction->base, target_value_ptr, nullptr); enum_value->value.type = target_type; return enum_value; } @@ -23105,7 +23121,7 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, if (lval == LValPtr) { return var_ptr; } else { - return ir_get_deref(ira, &instruction->base, var_ptr); + return ir_get_deref(ira, &instruction->base, var_ptr, nullptr); } } case TldIdFn: { @@ -23640,7 +23656,7 @@ static IrInstruction *ir_analyze_instruction_atomic_load(IrAnalyze *ira, IrInstr } if (instr_is_comptime(casted_ptr)) { - IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr); + IrInstruction *result = ir_get_deref(ira, &instruction->base, casted_ptr, nullptr); ir_assert(result->value.type != nullptr, &instruction->base); return result; } @@ -24474,7 +24490,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdUnOp: case IrInstructionIdBinOp: case IrInstructionIdLoadPtr: - case IrInstructionIdLoadPtrGen: case IrInstructionIdConst: case IrInstructionIdCast: case IrInstructionIdContainerInitList: @@ -24585,6 +24600,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { return reinterpret_cast(instruction)->result_loc != nullptr; case IrInstructionIdErrWrapCode: return reinterpret_cast(instruction)->result_loc != nullptr; + case IrInstructionIdLoadPtrGen: + return reinterpret_cast(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 3729fab308..4bec292997 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -397,8 +397,10 @@ static void ir_print_load_ptr(IrPrint *irp, IrInstructionLoadPtr *instruction) { } static void ir_print_load_ptr_gen(IrPrint *irp, IrInstructionLoadPtrGen *instruction) { + fprintf(irp->f, "loadptr("); ir_print_other_instruction(irp, instruction->ptr); - fprintf(irp->f, ".*"); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_store_ptr(IrPrint *irp, IrInstructionStorePtr *instruction) { -- cgit v1.2.3 From 4582ec518f9984a26c68b8427a914bad6dc80c4a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 19:49:24 -0400 Subject: result location semantics for vector to array ```zig export fn entry() void { var x: @Vector(4, i32) = undefined; var y: [4]i32 = x; } ``` ```llvm define void @entry() #2 !dbg !35 { Entry: %x = alloca <4 x i32>, align 16 %y = alloca [4 x i32], align 4 %0 = bitcast <4 x i32>* %x to i8*, !dbg !47 call void @llvm.memset.p0i8.i64(i8* align 16 %0, i8 -86, i64 16, i1 false), !dbg !47 call void @llvm.dbg.declare(metadata <4 x i32>* %x, metadata !39, metadata !DIExpression()), !dbg !47 %1 = load <4 x i32>, <4 x i32>* %x, align 16, !dbg !48 %2 = bitcast [4 x i32]* %y to <4 x i32>*, !dbg !48 store <4 x i32> %1, <4 x i32>* %2, align 16, !dbg !48 call void @llvm.dbg.declare(metadata [4 x i32]* %y, metadata !45, metadata !DIExpression()), !dbg !49 ret void, !dbg !50 } ``` --- src/all_types.hpp | 2 +- src/codegen.cpp | 10 +++------- src/ir.cpp | 18 +++++++++++------- src/ir_print.cpp | 3 ++- 4 files changed, 17 insertions(+), 16 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index d7e11f7102..6e04fada04 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3522,7 +3522,7 @@ struct IrInstructionVectorToArray { IrInstruction base; IrInstruction *vector; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionAssertZero { diff --git a/src/codegen.cpp b/src/codegen.cpp index 994194c5eb..53800d4eec 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5386,12 +5386,12 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab ZigType *array_type = instruction->base.value.type; assert(array_type->id == ZigTypeIdArray); assert(handle_is_ptr(array_type)); - assert(instruction->tmp_ptr); + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); LLVMValueRef vector = ir_llvm_value(g, instruction->vector); - LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, instruction->tmp_ptr, + LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); gen_store_untyped(g, vector, casted_ptr, 0, false); - return instruction->tmp_ptr; + return result_loc; } static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executable, @@ -6838,10 +6838,6 @@ static void do_code_gen(CodeGen *g) { slot = &ref_instruction->tmp_ptr; assert(instruction->value.type->id == ZigTypeIdPointer); slot_type = instruction->value.type->data.pointer.child_type; - } else if (instruction->id == IrInstructionIdVectorToArray) { - IrInstructionVectorToArray *vector_to_array_instruction = (IrInstructionVectorToArray *)instruction; - alignment_bytes = get_abi_alignment(g, vector_to_array_instruction->vector->value.type); - slot = &vector_to_array_instruction->tmp_ptr; } else { zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 305b534791..8282b8de2a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -3131,16 +3131,16 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, } static IrInstruction *ir_build_vector_to_array(IrAnalyze *ira, IrInstruction *source_instruction, - IrInstruction *vector, ZigType *result_type) + ZigType *result_type, IrInstruction *vector, IrInstruction *result_loc) { IrInstructionVectorToArray *instruction = ir_build_instruction(&ira->new_irb, source_instruction->scope, source_instruction->source_node); instruction->base.value.type = result_type; instruction->vector = vector; + instruction->result_loc = result_loc; ir_ref_instruction(vector, ira->new_irb.current_basic_block); - - ir_add_alloca(ira, &instruction->base, result_type); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11985,7 +11985,7 @@ static IrInstruction *ir_analyze_array_to_vector(IrAnalyze *ira, IrInstruction * } static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *vector, ZigType *array_type) + IrInstruction *vector, ZigType *array_type, ResultLoc *result_loc) { if (instr_is_comptime(vector)) { // arrays and vectors have the same ConstExprValue representation @@ -11994,7 +11994,11 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction * result->value.type = array_type; return result; } - return ir_build_vector_to_array(ira, source_instr, vector, array_type); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } + return ir_build_vector_to_array(ira, source_instr, array_type, vector, result_loc_inst); } static IrInstruction *ir_analyze_int_to_c_ptr(IrAnalyze *ira, IrInstruction *source_instr, @@ -12453,7 +12457,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst types_match_const_cast_only(ira, wanted_type->data.array.child_type, actual_type->data.vector.elem_type, source_node, false).id == ConstCastResultIdOk) { - return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type); + return ir_analyze_vector_to_array(ira, source_instr, value, wanted_type, result_loc); } // cast from [N]T to @Vector(N, T) @@ -24484,6 +24488,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdPtrOfArrayToSlice: case IrInstructionIdSliceGen: case IrInstructionIdOptionalWrap: + case IrInstructionIdVectorToArray: return true; case IrInstructionIdPhi: @@ -24578,7 +24583,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFromBytes: case IrInstructionIdToBytes: case IrInstructionIdEnumToInt: - case IrInstructionIdVectorToArray: case IrInstructionIdArrayToVector: case IrInstructionIdHasDecl: case IrInstructionIdAllocaSrc: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 4bec292997..90fd5aa069 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1102,7 +1102,8 @@ static void ir_print_array_to_vector(IrPrint *irp, IrInstructionArrayToVector *i static void ir_print_vector_to_array(IrPrint *irp, IrInstructionVectorToArray *instruction) { fprintf(irp->f, "VectorToArray("); ir_print_other_instruction(irp, instruction->vector); - fprintf(irp->f, ")"); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); } static void ir_print_ptr_of_array_to_slice(IrPrint *irp, IrInstructionPtrOfArrayToSlice *instruction) { -- cgit v1.2.3 From f6d4e2565e7c0eea7e50e50dd808246d65d9f200 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 23:51:43 -0400 Subject: use result loc for ref instruction --- src/all_types.hpp | 9 ++++++++- src/codegen.cpp | 22 +++++++++------------- src/ir.cpp | 44 ++++++++++++++++++++++++++++++++------------ src/ir_print.cpp | 10 ++++++++++ 4 files changed, 59 insertions(+), 26 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index a758f5d906..bd72a4fccf 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2234,6 +2234,7 @@ enum IrInstructionId { IrInstructionIdCDefine, IrInstructionIdCUndef, IrInstructionIdRef, + IrInstructionIdRefGen, IrInstructionIdCompileErr, IrInstructionIdCompileLog, IrInstructionIdErrName, @@ -2812,11 +2813,17 @@ struct IrInstructionRef { IrInstruction base; IrInstruction *value; - LLVMValueRef tmp_ptr; bool is_const; bool is_volatile; }; +struct IrInstructionRefGen { + IrInstruction base; + + IrInstruction *operand; + IrInstruction *result_loc; +}; + struct IrInstructionCompileErr { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 53800d4eec..5e3938a4ae 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4212,17 +4212,17 @@ static LLVMValueRef ir_render_phi(CodeGen *g, IrExecutable *executable, IrInstru return phi; } -static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRef *instruction) { +static LLVMValueRef ir_render_ref(CodeGen *g, IrExecutable *executable, IrInstructionRefGen *instruction) { if (!type_has_bits(instruction->base.value.type)) { return nullptr; } - LLVMValueRef value = ir_llvm_value(g, instruction->value); - if (handle_is_ptr(instruction->value->value.type)) { + LLVMValueRef value = ir_llvm_value(g, instruction->operand); + if (handle_is_ptr(instruction->operand->value.type)) { return value; } else { - assert(instruction->tmp_ptr); - gen_store_untyped(g, value, instruction->tmp_ptr, 0, false); - return instruction->tmp_ptr; + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); + gen_store_untyped(g, value, result_loc, 0, false); + return result_loc; } } @@ -5530,6 +5530,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdResolveResult: case IrInstructionIdContainerInitList: case IrInstructionIdSliceSrc: + case IrInstructionIdRef: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5584,8 +5585,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_bit_reverse(g, executable, (IrInstructionBitReverse *)instruction); case IrInstructionIdPhi: return ir_render_phi(g, executable, (IrInstructionPhi *)instruction); - case IrInstructionIdRef: - return ir_render_ref(g, executable, (IrInstructionRef *)instruction); + case IrInstructionIdRefGen: + return ir_render_ref(g, executable, (IrInstructionRefGen *)instruction); case IrInstructionIdErrName: return ir_render_err_name(g, executable, (IrInstructionErrName *)instruction); case IrInstructionIdCmpxchgGen: @@ -6833,11 +6834,6 @@ static void do_code_gen(CodeGen *g) { if (instruction->id == IrInstructionIdCast) { IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; slot = &cast_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdRef) { - IrInstructionRef *ref_instruction = (IrInstructionRef *)instruction; - slot = &ref_instruction->tmp_ptr; - assert(instruction->value.type->id == ZigTypeIdPointer); - slot_type = instruction->value.type->data.pointer.child_type; } else { zig_unreachable(); } diff --git a/src/ir.cpp b/src/ir.cpp index 16638de6b3..d132f5110f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -617,6 +617,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionRef *) { return IrInstructionIdRef; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionRefGen *) { + return IrInstructionIdRefGen; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) { return IrInstructionIdCompileErr; } @@ -1961,6 +1965,21 @@ static IrInstruction *ir_build_ref(IrBuilder *irb, Scope *scope, AstNode *source return &instruction->base; } +static IrInstruction *ir_build_ref_gen(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *result_type, + IrInstruction *operand, IrInstruction *result_loc) +{ + IrInstructionRefGen *instruction = ir_build_instruction(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = result_type; + instruction->operand = operand; + instruction->result_loc = result_loc; + + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_compile_err(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *msg) { IrInstructionCompileErr *instruction = ir_build_instruction(irb, scope, source_node); instruction->msg = msg; @@ -2636,11 +2655,8 @@ static IrInstruction *ir_build_type_name(IrBuilder *irb, Scope *scope, AstNode * return &instruction->base; } -static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, - Tld *tld, LVal lval) -{ - IrInstructionDeclRef *instruction = ir_build_instruction( - irb, scope, source_node); +static IrInstruction *ir_build_decl_ref(IrBuilder *irb, Scope *scope, AstNode *source_node, Tld *tld, LVal lval) { + IrInstructionDeclRef *instruction = ir_build_instruction(irb, scope, source_node); instruction->tld = tld; instruction->lval = lval; @@ -11335,15 +11351,16 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - IrInstruction *new_instruction = ir_build_ref(&ira->new_irb, source_instruction->scope, - source_instruction->source_node, value, is_const, is_volatile); - new_instruction->value.type = ptr_type; - new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; + + IrInstruction *result_loc; if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { - ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); - assert(fn_entry); - fn_entry->alloca_list.append(new_instruction); + result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr); + } else { + result_loc = nullptr; } + + IrInstruction *new_instruction = ir_build_ref_gen(ira, source_instruction, ptr_type, value, result_loc); + new_instruction->value.data.rh_ptr = RuntimeHintPtrStack; return new_instruction; } @@ -24119,6 +24136,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdReturnPtr: case IrInstructionIdAllocaGen: case IrInstructionIdSliceGen: + case IrInstructionIdRefGen: zig_unreachable(); case IrInstructionIdReturn: @@ -24653,6 +24671,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { return reinterpret_cast(instruction)->result_loc != nullptr; case IrInstructionIdLoadPtrGen: return reinterpret_cast(instruction)->result_loc != nullptr; + case IrInstructionIdRefGen: + return reinterpret_cast(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 90fd5aa069..1935c0d7f6 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -668,6 +668,13 @@ static void ir_print_ref(IrPrint *irp, IrInstructionRef *instruction) { ir_print_other_instruction(irp, instruction->value); } +static void ir_print_ref_gen(IrPrint *irp, IrInstructionRefGen *instruction) { + fprintf(irp->f, "@ref("); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); +} + static void ir_print_compile_err(IrPrint *irp, IrInstructionCompileErr *instruction) { fprintf(irp->f, "@compileError("); ir_print_other_instruction(irp, instruction->msg); @@ -1711,6 +1718,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdRef: ir_print_ref(irp, (IrInstructionRef *)instruction); break; + case IrInstructionIdRefGen: + ir_print_ref_gen(irp, (IrInstructionRefGen *)instruction); + break; case IrInstructionIdCompileErr: ir_print_compile_err(irp, (IrInstructionCompileErr *)instruction); break; -- cgit v1.2.3 From d504318f2e0f3054c772abbd34f938f2cefa6ccc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 10 Jun 2019 23:54:28 -0400 Subject: remove the final legacy stack allocation --- BRANCH_TODO | 3 --- src/all_types.hpp | 2 -- src/codegen.cpp | 14 -------------- src/ir.cpp | 25 ++++++------------------- 4 files changed, 6 insertions(+), 38 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index f6fd78dbaa..f730eb64f5 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -4,7 +4,4 @@ Scratch pad for stuff to do before merging master look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated return ir_gen_comptime(irb, scope, node, lval); -migrate all the alloca_list to alloca_gen_list - comptime expressions - diff --git a/src/all_types.hpp b/src/all_types.hpp index bd72a4fccf..1d935fee2b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1369,7 +1369,6 @@ struct ZigFn { AstNode *fn_no_inline_set_node; AstNode *fn_static_eval_set_node; - ZigList alloca_list; ZigList alloca_gen_list; ZigList variable_list; @@ -2635,7 +2634,6 @@ struct IrInstructionCast { IrInstruction *value; ZigType *dest_type; CastOp cast_op; - LLVMValueRef tmp_ptr; }; struct IrInstructionResizeSlice { diff --git a/src/codegen.cpp b/src/codegen.cpp index 5e3938a4ae..a75ef29169 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6826,20 +6826,6 @@ static void do_code_gen(CodeGen *g) { get_ptr_align(g, ptr_type)); } - for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_list.length; alloca_i += 1) { - IrInstruction *instruction = fn_table_entry->alloca_list.at(alloca_i); - LLVMValueRef *slot; - ZigType *slot_type = instruction->value.type; - uint32_t alignment_bytes = 0; - if (instruction->id == IrInstructionIdCast) { - IrInstructionCast *cast_instruction = (IrInstructionCast *)instruction; - slot = &cast_instruction->tmp_ptr; - } else { - zig_unreachable(); - } - *slot = build_alloca(g, slot_type, "", alignment_bytes); - } - ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base); unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0; diff --git a/src/ir.cpp b/src/ir.cpp index d132f5110f..07df62fd02 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -181,7 +181,6 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed); static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs); static Error resolve_ptr_align(IrAnalyze *ira, ZigType *ty, uint32_t *result_align); -static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry); static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, ZigType *ptr_type); static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, @@ -10497,15 +10496,6 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT } } -static void ir_add_alloca(IrAnalyze *ira, IrInstruction *instruction, ZigType *type_entry) { - if (type_has_bits(type_entry) && handle_is_ptr(type_entry)) { - ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); - if (fn_entry != nullptr) { - fn_entry->alloca_list.append(instruction); - } - } -} - static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs) { ConstGlobalRefs *global_refs = dest->global_refs; assert(!same_global_refs || src->global_refs != nullptr); @@ -10631,7 +10621,7 @@ static IrInstruction *ir_const(IrAnalyze *ira, IrInstruction *old_instruction, Z } static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, - ZigType *wanted_type, CastOp cast_op, bool need_alloca) + ZigType *wanted_type, CastOp cast_op) { if (instr_is_comptime(value) || !type_has_bits(wanted_type)) { IrInstruction *result = ir_const(ira, source_instr, wanted_type); @@ -10644,9 +10634,6 @@ static IrInstruction *ir_resolve_cast(IrAnalyze *ira, IrInstruction *source_inst } else { IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, wanted_type, value, cast_op); result->value.type = wanted_type; - if (need_alloca) { - ir_add_alloca(ira, result, wanted_type); - } return result; } } @@ -12121,7 +12108,7 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst if (const_cast_result.id == ConstCastResultIdInvalid) return ira->codegen->invalid_instruction; if (const_cast_result.id == ConstCastResultIdOk) { - return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false); + return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop); } // cast from T to ?T @@ -20752,7 +20739,7 @@ static IrInstruction *ir_analyze_instruction_float_cast(IrAnalyze *ira, IrInstru } else { op = CastOpNumLitToConcrete; } - return ir_resolve_cast(ira, &instruction->base, target, dest_type, op, false); + return ir_resolve_cast(ira, &instruction->base, target, dest_type, op); } else { return ira->codegen->invalid_instruction; } @@ -20975,7 +20962,7 @@ static IrInstruction *ir_analyze_instruction_int_to_float(IrAnalyze *ira, IrInst return ira->codegen->invalid_instruction; } - return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpIntToFloat, false); + return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpIntToFloat); } static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInstructionFloatToInt *instruction) { @@ -20997,7 +20984,7 @@ static IrInstruction *ir_analyze_instruction_float_to_int(IrAnalyze *ira, IrInst return ira->codegen->invalid_instruction; } - return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpFloatToInt, false); + return ir_resolve_cast(ira, &instruction->base, target, dest_type, CastOpFloatToInt); } static IrInstruction *ir_analyze_instruction_err_to_int(IrAnalyze *ira, IrInstructionErrToInt *instruction) { @@ -21049,7 +21036,7 @@ static IrInstruction *ir_analyze_instruction_bool_to_int(IrAnalyze *ira, IrInstr } ZigType *u1_type = get_int_type(ira->codegen, false, 1); - return ir_resolve_cast(ira, &instruction->base, target, u1_type, CastOpBoolToInt, false); + return ir_resolve_cast(ira, &instruction->base, target, u1_type, CastOpBoolToInt); } static IrInstruction *ir_analyze_instruction_int_type(IrAnalyze *ira, IrInstructionIntType *instruction) { -- cgit v1.2.3 From 7411a88d5f8109ced238cf14205ae36575f02f21 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 00:27:10 -0400 Subject: fix comptime function calls --- BRANCH_TODO | 4 ++-- src/analyze.cpp | 28 ++++++++++++++++++++++++++++ src/analyze.hpp | 1 + src/codegen.cpp | 28 ---------------------------- src/ir.cpp | 2 ++ 5 files changed, 33 insertions(+), 30 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index f730eb64f5..854b2c0ee7 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,7 @@ Scratch pad for stuff to do before merging master ================================================= +uncomment all the behavior tests + look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated return ir_gen_comptime(irb, scope, node, lval); - -comptime expressions diff --git a/src/analyze.cpp b/src/analyze.cpp index 0168dad6ea..beaa9f1486 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -7293,3 +7293,31 @@ void src_assert(bool ok, AstNode *source_node) { const char *msg = "assertion failed. This is a bug in the Zig compiler."; stage2_panic(msg, strlen(msg)); } + +bool scope_is_elided(Scope *scope) { + for (;;) { + switch (scope->id) { + case ScopeIdElide: + if (reinterpret_cast(scope)->activated) + return true; + // fallthrough + case ScopeIdBlock: + case ScopeIdDefer: + case ScopeIdDeferExpr: + case ScopeIdVarDecl: + case ScopeIdLoop: + case ScopeIdSuspend: + case ScopeIdCoroPrelude: + case ScopeIdRuntime: + scope = scope->parent; + continue; + case ScopeIdFnDef: + case ScopeIdCompTime: + case ScopeIdDecls: + case ScopeIdCImport: + return false; + } + zig_unreachable(); + } +} + diff --git a/src/analyze.hpp b/src/analyze.hpp index 2f3ec663da..2c5250d7e9 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -253,5 +253,6 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa void src_assert(bool ok, AstNode *source_node); bool is_container(ZigType *type_entry); ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); +bool scope_is_elided(Scope *scope); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index a75ef29169..7ee299aab7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5709,34 +5709,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, zig_unreachable(); } -static bool scope_is_elided(Scope *scope) { - for (;;) { - switch (scope->id) { - case ScopeIdDecls: - case ScopeIdCompTime: - case ScopeIdCImport: - zig_unreachable(); - case ScopeIdElide: - if (reinterpret_cast(scope)->activated) - return true; - // fallthrough - case ScopeIdBlock: - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCoroPrelude: - case ScopeIdRuntime: - scope = scope->parent; - continue; - case ScopeIdFnDef: - return false; - } - zig_unreachable(); - } -} - static void ir_render(CodeGen *g, ZigFn *fn_entry) { assert(fn_entry); diff --git a/src/ir.cpp b/src/ir.cpp index 07df62fd02..1ea509745e 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -8503,6 +8503,8 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec IrBasicBlock *bb = exec->basic_block_list.at(0); for (size_t i = 0; i < bb->instruction_list.length; i += 1) { IrInstruction *instruction = bb->instruction_list.at(i); + if (scope_is_elided(instruction->scope)) + continue; if (instruction->id == IrInstructionIdReturn) { IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction; IrInstruction *value = ret_inst->value; -- cgit v1.2.3 From 06f307ff77adac0451b10643a033714c1d309010 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 12:19:57 -0400 Subject: fix implicit casting return value struct/arary init to optional --- BRANCH_TODO | 3 +++ src/all_types.hpp | 3 ++- src/codegen.cpp | 37 ++++++++++++++++++++++--------------- src/ir.cpp | 49 +++++++++++++++++++++++++++++++++++-------------- src/ir_print.cpp | 5 +++-- 5 files changed, 65 insertions(+), 32 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 854b2c0ee7..fba18ed35b 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,6 +1,9 @@ Scratch pad for stuff to do before merging master ================================================= +struct & array init when the result is casted to anyerror!T +struct & array init when the result is casted to anyerror!?T + uncomment all the behavior tests look at all the ir_gen_node ir_gen_node_extra calls and make sure result locations are properly propagated diff --git a/src/all_types.hpp b/src/all_types.hpp index 1d935fee2b..35f8745fd6 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2770,8 +2770,9 @@ struct IrInstructionTestNonNull { struct IrInstructionOptionalUnwrapPtr { IrInstruction base; - IrInstruction *base_ptr; bool safety_check_on; + bool initializing; + IrInstruction *base_ptr; }; struct IrInstructionCtz { diff --git a/src/codegen.cpp b/src/codegen.cpp index 7ee299aab7..2d1ea07bf3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -838,9 +838,7 @@ static LLVMValueRef gen_store_untyped(CodeGen *g, LLVMValueRef value, LLVMValueR { LLVMValueRef instruction = LLVMBuildStore(g->builder, value, ptr); if (is_volatile) LLVMSetVolatile(instruction, true); - if (alignment == 0) { - LLVMSetAlignment(instruction, LLVMABIAlignmentOfType(g->target_data_ref, LLVMTypeOf(value))); - } else { + if (alignment != 0) { LLVMSetAlignment(instruction, alignment); } return instruction; @@ -2384,16 +2382,19 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut } static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { + if (return_instruction->value == nullptr) { + LLVMBuildRetVoid(g->builder); + return nullptr; + } + ZigType *return_type = return_instruction->value->value.type; if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { assert(g->cur_ret_ptr); - if (return_instruction->value->value.special != ConstValSpecialRuntime) { - // if it's comptime we have to do this but if it's runtime trust that - // result location mechanism took care of it. - LLVMValueRef value = ir_llvm_value(g, return_instruction->value); - gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); - } + src_assert(return_instruction->value->value.special != ConstValSpecialRuntime, + return_instruction->base.source_node); + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); + gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); LLVMBuildRetVoid(g->builder); } else if (handle_is_ptr(return_type)) { LLVMValueRef value = ir_llvm_value(g, return_instruction->value); @@ -4068,9 +4069,9 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec ZigType *maybe_type = ptr_type->data.pointer.child_type; assert(maybe_type->id == ZigTypeIdOptional); ZigType *child_type = maybe_type->data.maybe.child_type; - LLVMValueRef maybe_ptr = ir_llvm_value(g, instruction->base_ptr); - if (ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on) { - LLVMValueRef maybe_handle = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); + LLVMValueRef base_ptr = ir_llvm_value(g, instruction->base_ptr); + if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { + LLVMValueRef maybe_handle = get_handle_value(g, base_ptr, maybe_type, ptr_type); LLVMValueRef non_null_bit = gen_non_null_bit(g, maybe_type, maybe_handle); LLVMBasicBlockRef fail_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalFail"); LLVMBasicBlockRef ok_block = LLVMAppendBasicBlock(g->cur_fn_val, "UnwrapOptionalOk"); @@ -4086,10 +4087,16 @@ static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *exec } else { bool is_scalar = !handle_is_ptr(maybe_type); if (is_scalar) { - return maybe_ptr; + return base_ptr; } else { - LLVMValueRef maybe_struct_ref = get_handle_value(g, maybe_ptr, maybe_type, ptr_type); - return LLVMBuildStructGEP(g->builder, maybe_struct_ref, maybe_child_index, ""); + LLVMValueRef optional_struct_ref = get_handle_value(g, base_ptr, maybe_type, ptr_type); + if (instruction->initializing) { + LLVMValueRef non_null_bit_ptr = LLVMBuildStructGEP(g->builder, optional_struct_ref, + maybe_null_index, ""); + LLVMValueRef non_null_bit = LLVMConstInt(LLVMInt1Type(), 1, false); + gen_store_untyped(g, non_null_bit, non_null_bit_ptr, 0, false); + } + return LLVMBuildStructGEP(g->builder, optional_struct_ref, maybe_child_index, ""); } } } diff --git a/src/ir.cpp b/src/ir.cpp index b05fe835b7..31c40ac168 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -187,6 +187,8 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ ZigType *dest_type); static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr, ResultLoc *result_loc, ZigType *value_type, IrInstruction *value); +static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on, bool initializing); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -1095,13 +1097,15 @@ static IrInstruction *ir_build_cond_br(IrBuilder *irb, Scope *scope, AstNode *so return &cond_br_instruction->base; } -static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *return_value) { +static IrInstruction *ir_build_return(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *return_value) +{ IrInstructionReturn *return_instruction = ir_build_instruction(irb, scope, source_node); return_instruction->base.value.type = irb->codegen->builtin_types.entry_unreachable; return_instruction->base.value.special = ConstValSpecialStatic; return_instruction->value = return_value; - ir_ref_instruction(return_value, irb->current_basic_block); + if (return_value != nullptr) ir_ref_instruction(return_value, irb->current_basic_block); return &return_instruction->base; } @@ -1756,11 +1760,12 @@ static IrInstruction *ir_build_test_nonnull(IrBuilder *irb, Scope *scope, AstNod } static IrInstruction *ir_build_optional_unwrap_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *base_ptr, bool safety_check_on) + IrInstruction *base_ptr, bool safety_check_on, bool initializing) { IrInstructionOptionalUnwrapPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->base_ptr = base_ptr; instruction->safety_check_on = safety_check_on; + instruction->initializing = initializing; ir_ref_instruction(base_ptr, irb->current_basic_block); @@ -3918,7 +3923,7 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode ir_mark_gen(ir_build_br(irb, parent_scope, node, end_block, is_comptime)); ir_set_cursor_at_end_and_append_block(irb, ok_block); - IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, parent_scope, node, maybe_ptr, false, false); IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers[1].base); IrBasicBlock *after_ok_block = irb->current_basic_block; @@ -6009,7 +6014,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, result_loc); ir_set_cursor_at_end_and_append_block(irb, body_block); - IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false); + IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, child_scope, symbol_node, maybe_val_ptr, false, false); IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? ir_build_ref(irb, child_scope, symbol_node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, child_scope, symbol_node, payload_var, nullptr, var_ptr); @@ -6609,7 +6614,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_symbol, is_const, is_const, is_shadowable, is_comptime); - IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false); + IrInstruction *payload_ptr = ir_build_optional_unwrap_ptr(irb, subexpr_scope, node, maybe_val_ptr, false, false); IrInstruction *var_ptr = var_is_ptr ? ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr); var_scope = var->child_scope; @@ -8094,7 +8099,7 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop if (maybe_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true); + IrInstruction *unwrapped_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, maybe_ptr, true, false); if (lval == LValPtr) return unwrapped_ptr; @@ -8375,7 +8380,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // a register or local variable which does not get spilled into the frame, // otherwise llvm tries to access memory inside the destroyed frame. IrInstruction *unwrapped_await_handle_ptr = ir_build_optional_unwrap_ptr(irb, scope, node, - irb->exec->await_handle_var_ptr, false); + irb->exec->await_handle_var_ptr, false, false); IrInstruction *await_handle_in_block = ir_build_load_ptr(irb, scope, node, unwrapped_await_handle_ptr); ir_build_br(irb, scope, node, check_free_block, const_bool_false); @@ -12871,6 +12876,14 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio if (type_is_invalid(value->value.type)) return ir_unreach_error(ira); + if (!instr_is_comptime(value) && handle_is_ptr(ira->explicit_return_type)) { + // result location mechanism took care of it. + IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, + instruction->base.source_node, nullptr); + result->value.type = ira->codegen->builtin_types.entry_unreachable; + return ir_finish_anal(ira, result); + } + IrInstruction *casted_value = ir_implicit_cast(ira, value, ira->explicit_return_type); if (type_is_invalid(casted_value->value.type)) { AstNode *source_node = ira->explicit_return_type_source_node; @@ -14925,10 +14938,17 @@ static IrInstruction *ir_analyze_instruction_implicit_cast(IrAnalyze *ira, IrIns } static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { - ZigType *ty = ir_resolve_type(ira, instruction->ty->child); - if (type_is_invalid(ty)) + ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); + if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_instruction; - return ir_resolve_result(ira, &instruction->base, instruction->result_loc, ty, nullptr); + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + implicit_elem_type, nullptr); + ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); + ZigType *actual_elem_type = result_loc->value.type->data.pointer.child_type; + if (actual_elem_type->id == ZigTypeIdOptional && implicit_elem_type->id != ZigTypeIdOptional) { + return ir_analyze_unwrap_optional_payload(ira, &instruction->base, result_loc, false, true); + } + return result_loc; } static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, @@ -17876,7 +17896,7 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns } static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, - IrInstruction *base_ptr, bool safety_check_on) + IrInstruction *base_ptr, bool safety_check_on, bool initializing) { ZigType *ptr_type = base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); @@ -17948,7 +17968,7 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr } IrInstruction *result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope, - source_instr->source_node, base_ptr, safety_check_on); + source_instr->source_node, base_ptr, safety_check_on, initializing); result->value.type = result_type; return result; } @@ -17960,7 +17980,8 @@ static IrInstruction *ir_analyze_instruction_optional_unwrap_ptr(IrAnalyze *ira, if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; - return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, instruction->safety_check_on); + return ir_analyze_unwrap_optional_payload(ira, &instruction->base, base_ptr, + instruction->safety_check_on, false); } static IrInstruction *ir_analyze_instruction_ctz(IrAnalyze *ira, IrInstructionCtz *instruction) { diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1935c0d7f6..64e6f07ade 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -61,9 +61,10 @@ static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) { } static void ir_print_return(IrPrint *irp, IrInstructionReturn *return_instruction) { - assert(return_instruction->value); fprintf(irp->f, "return "); - ir_print_other_instruction(irp, return_instruction->value); + if (return_instruction->value != nullptr) { + ir_print_other_instruction(irp, return_instruction->value); + } } static void ir_print_const(IrPrint *irp, IrInstructionConst *const_instruction) { -- cgit v1.2.3 From fc8d8812404e79716e15fd301058032485e8bb64 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 13:27:01 -0400 Subject: fix struct and array init when result casted to anyerror!?T --- BRANCH_TODO | 1 - src/all_types.hpp | 10 +++++----- src/codegen.cpp | 7 ++++++- src/ir.cpp | 54 +++++++++++++++++++++++++++++++++--------------------- 4 files changed, 44 insertions(+), 28 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index fba18ed35b..881a2f7d26 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -1,7 +1,6 @@ Scratch pad for stuff to do before merging master ================================================= -struct & array init when the result is casted to anyerror!T struct & array init when the result is casted to anyerror!?T uncomment all the behavior tests diff --git a/src/all_types.hpp b/src/all_types.hpp index 35f8745fd6..598394cb45 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2343,10 +2343,6 @@ enum IrInstructionId { }; struct IrInstruction { - IrInstructionId id; - // true if this instruction was generated by zig and not from user code - bool is_gen; - Scope *scope; AstNode *source_node; ConstExprValue value; @@ -2360,6 +2356,9 @@ struct IrInstruction { // with this child field. IrInstruction *child; IrBasicBlock *owner_bb; + IrInstructionId id; + // true if this instruction was generated by zig and not from user code + bool is_gen; }; struct IrInstructionDeclVarSrc { @@ -3102,8 +3101,9 @@ struct IrInstructionUnwrapErrCode { struct IrInstructionUnwrapErrPayload { IrInstruction base; - IrInstruction *value; bool safety_check_on; + bool initializing; + IrInstruction *value; }; struct IrInstructionOptionalWrap { diff --git a/src/codegen.cpp b/src/codegen.cpp index 2d1ea07bf3..a040d377cf 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4908,7 +4908,7 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) { - bool want_safety = ir_want_runtime_safety(g, &instruction->base) && instruction->safety_check_on && + bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) && g->errors_by_index.length > 1; if (!want_safety && !type_has_bits(instruction->base.value.type)) return nullptr; @@ -4944,6 +4944,11 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu } if (type_has_bits(payload_type)) { + if (instruction->initializing) { + LLVMValueRef err_tag_ptr = LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); + LLVMValueRef ok_err_val = LLVMConstNull(get_llvm_type(g, g->err_tag_type)); + gen_store_untyped(g, ok_err_val, err_tag_ptr, 0, false); + } return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_payload_index, ""); } else { return nullptr; diff --git a/src/ir.cpp b/src/ir.cpp index 31c40ac168..b841f8032f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -189,6 +189,8 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s ResultLoc *result_loc, ZigType *value_type, IrInstruction *value); static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing); +static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on, bool initializing); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -2424,11 +2426,12 @@ static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, Ast } static IrInstruction *ir_build_unwrap_err_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value, bool safety_check_on) + IrInstruction *value, bool safety_check_on, bool initializing) { IrInstructionUnwrapErrPayload *instruction = ir_build_instruction(irb, scope, source_node); instruction->value = value; instruction->safety_check_on = safety_check_on; + instruction->initializing = initializing; ir_ref_instruction(value, irb->current_basic_block); @@ -3572,7 +3575,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, } ir_set_cursor_at_end_and_append_block(irb, continue_block); - IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false); + IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false, false); if (lval == LValPtr) return unwrapped_ptr; else @@ -5578,7 +5581,7 @@ static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, Ast if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, source_node, err_union_ptr, true); + IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, scope, source_node, err_union_ptr, true, false); if (payload_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; @@ -5915,7 +5918,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n ir_set_cursor_at_end_and_append_block(irb, body_block); if (var_symbol) { IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node, - err_val_ptr, false); + err_val_ptr, false, false); IrInstruction *var_ptr = node->data.while_expr.var_is_ptr ? ir_build_ref(irb, payload_scope, symbol_node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, payload_scope, symbol_node, payload_var, nullptr, var_ptr); @@ -6694,7 +6697,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * ZigVar *var = ir_create_var(irb, node, subexpr_scope, var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); - IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false); + IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, subexpr_scope, node, err_val_ptr, false, false); IrInstruction *var_ptr = var_is_ptr ? ir_build_ref(irb, subexpr_scope, node, payload_ptr, true, false) : payload_ptr; ir_build_var_decl_src(irb, subexpr_scope, node, var, nullptr, var_ptr); @@ -7316,7 +7319,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode ir_mark_gen(ir_build_br(irb, err_scope, node, end_block, is_comptime)); ir_set_cursor_at_end_and_append_block(irb, ok_block); - IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false); + IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, parent_scope, node, err_union_ptr, false, false); IrInstruction *unwrapped_payload = ir_build_load_ptr(irb, parent_scope, node, unwrapped_ptr); ir_build_end_expr(irb, parent_scope, node, unwrapped_payload, &peer_parent->peers[1].base); IrBasicBlock *after_ok_block = irb->current_basic_block; @@ -14947,6 +14950,8 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn ZigType *actual_elem_type = result_loc->value.type->data.pointer.child_type; if (actual_elem_type->id == ZigTypeIdOptional && implicit_elem_type->id != ZigTypeIdOptional) { return ir_analyze_unwrap_optional_payload(ira, &instruction->base, result_loc, false, true); + } else if (actual_elem_type->id == ZigTypeIdErrorUnion && implicit_elem_type->id != ZigTypeIdErrorUnion) { + return ir_analyze_unwrap_error_payload(ira, &instruction->base, result_loc, false, true); } return result_loc; } @@ -22136,14 +22141,10 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrI return result; } -static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, - IrInstructionUnwrapErrPayload *instruction) +static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool safety_check_on, bool initializing) { - assert(instruction->value->child); - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) - return ira->codegen->invalid_instruction; - ZigType *ptr_type = value->value.type; + ZigType *ptr_type = base_ptr->value.type; // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. assert(ptr_type->id == ZigTypeIdPointer); @@ -22153,7 +22154,7 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, return ira->codegen->invalid_instruction; if (type_entry->id != ZigTypeIdErrorUnion) { - ir_add_error(ira, value, + ir_add_error(ira, base_ptr, buf_sprintf("expected error union type, found '%s'", buf_ptr(&type_entry->name))); return ira->codegen->invalid_instruction; } @@ -22165,23 +22166,23 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, ZigType *result_type = get_pointer_to_type_extra(ira->codegen, payload_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false); - if (instr_is_comptime(value)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, value, UndefBad); + if (instr_is_comptime(base_ptr)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); if (!ptr_val) return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (err_union_val == nullptr) return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; if (err != nullptr) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, source_instr, buf_sprintf("caught unexpected error '%s'", buf_ptr(&err->name))); return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_const(ira, &instruction->base, result_type); + IrInstruction *result = ir_const(ira, source_instr, result_type); result->value.data.x_ptr.special = ConstPtrSpecialRef; result->value.data.x_ptr.data.ref.pointee = err_union_val->data.x_err_union.payload; return result; @@ -22189,12 +22190,23 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, } } - IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value, instruction->safety_check_on); + IrInstruction *result = ir_build_unwrap_err_payload(&ira->new_irb, source_instr->scope, + source_instr->source_node, base_ptr, safety_check_on, initializing); result->value.type = result_type; return result; } +static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, + IrInstructionUnwrapErrPayload *instruction) +{ + assert(instruction->value->child); + IrInstruction *value = instruction->value->child; + if (type_is_invalid(value->value.type)) + return ira->codegen->invalid_instruction; + + return ir_analyze_unwrap_error_payload(ira, &instruction->base, value, instruction->safety_check_on, false); +} + static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) { AstNode *proto_node = instruction->base.source_node; assert(proto_node->type == NodeTypeFnProto); -- cgit v1.2.3 From e1d14e73b5f9c7a8d1a92ccd36cb689d625faf57 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 15:44:06 -0400 Subject: fix `@bitCast` semantics when there is no parent result loc --- src/all_types.hpp | 9 +++++++++ src/codegen.cpp | 1 + src/ir.cpp | 41 +++++++++++++++++++++++++++++++++++++++-- src/ir_print.cpp | 10 ++++++++++ 4 files changed, 59 insertions(+), 2 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 598394cb45..7a6123b145 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -44,6 +44,7 @@ struct IrAnalyze; struct ResultLoc; struct ResultLocPeer; struct ResultLocPeerParent; +struct ResultLocBitCast; enum X64CABIClass { X64CABIClass_Unknown, @@ -2272,6 +2273,7 @@ enum IrInstructionId { IrInstructionIdTestComptime, IrInstructionIdPtrCastSrc, IrInstructionIdPtrCastGen, + IrInstructionIdBitCastSrc, IrInstructionIdBitCastGen, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, @@ -3159,6 +3161,13 @@ struct IrInstructionPtrCastGen { bool safety_check_on; }; +struct IrInstructionBitCastSrc { + IrInstruction base; + + IrInstruction *operand; + ResultLocBitCast *result_loc_bit_cast; +}; + struct IrInstructionBitCastGen { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index a040d377cf..beee678888 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5543,6 +5543,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdContainerInitList: case IrInstructionIdSliceSrc: case IrInstructionIdRef: + case IrInstructionIdBitCastSrc: zig_unreachable(); case IrInstructionIdDeclVarGen: diff --git a/src/ir.cpp b/src/ir.cpp index d1289bb89d..df7a593601 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -792,6 +792,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { return IrInstructionIdPtrCastGen; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastSrc *) { + return IrInstructionIdBitCastSrc; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) { return IrInstructionIdBitCastGen; } @@ -2515,6 +2519,18 @@ static IrInstruction *ir_build_load_ptr_gen(IrAnalyze *ira, IrInstruction *sourc return &instruction->base; } +static IrInstruction *ir_build_bit_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *operand, ResultLocBitCast *result_loc_bit_cast) +{ + IrInstructionBitCastSrc *instruction = ir_build_instruction(irb, scope, source_node); + instruction->operand = operand; + instruction->result_loc_bit_cast = result_loc_bit_cast; + + ir_ref_instruction(operand, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_bit_cast_gen(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *operand, ZigType *ty) { @@ -4941,7 +4957,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - return ir_lval_wrap(irb, scope, arg1_value, lval, result_loc); + IrInstruction *bitcast = ir_build_bit_cast_src(irb, scope, arg1_node, arg1_value, result_loc_bit_cast); + return ir_lval_wrap(irb, scope, bitcast, lval, result_loc); } case BuiltinFnIdIntToPtr: { @@ -14910,9 +14927,15 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s return ira->codegen->invalid_instruction; } + IrInstruction *bitcasted_value; + if (value != nullptr) { + bitcasted_value = ir_analyze_bit_cast(ira, result_loc->source_instruction, value, dest_type); + } else { + bitcasted_value = nullptr; + } IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent, - dest_type, nullptr); + dest_type, bitcasted_value); if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || parent_result_loc->value.type->id == ZigTypeIdUnreachable) { @@ -24168,6 +24191,17 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct return ir_const_void(ira, &instruction->base); } +static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInstructionBitCastSrc *instruction) { + IrInstruction *operand = instruction->operand->child; + if (type_is_invalid(operand->value.type) || instr_is_comptime(operand) || + instruction->result_loc_bit_cast->parent->gen_instruction == nullptr) + { + return operand; + } + + return instruction->result_loc_bit_cast->parent->gen_instruction; +} + static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -24472,6 +24506,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return nullptr; case IrInstructionIdEndExpr: return ir_analyze_instruction_end_expr(ira, (IrInstructionEndExpr *)instruction); + case IrInstructionIdBitCastSrc: + return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction); } zig_unreachable(); } @@ -24663,6 +24699,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: case IrInstructionIdPtrCastGen: + case IrInstructionIdBitCastSrc: case IrInstructionIdBitCastGen: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 64e6f07ade..4b8b175be0 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1046,6 +1046,13 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc fprintf(irp->f, ")"); } +static void ir_print_bit_cast_src(IrPrint *irp, IrInstructionBitCastSrc *instruction) { + fprintf(irp->f, "@bitCast("); + ir_print_other_instruction(irp, instruction->operand); + fprintf(irp->f, ")result="); + ir_print_result_loc(irp, &instruction->result_loc_bit_cast->base); +} + static void ir_print_bit_cast_gen(IrPrint *irp, IrInstructionBitCastGen *instruction) { fprintf(irp->f, "@bitCast("); ir_print_other_instruction(irp, instruction->operand); @@ -1860,6 +1867,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdPtrCastGen: ir_print_ptr_cast_gen(irp, (IrInstructionPtrCastGen *)instruction); break; + case IrInstructionIdBitCastSrc: + ir_print_bit_cast_src(irp, (IrInstructionBitCastSrc *)instruction); + break; case IrInstructionIdBitCastGen: ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction); break; -- cgit v1.2.3 From b3a4ec1bd209c022445b6f70385b3f88517e72f9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 11 Jun 2019 16:04:04 -0400 Subject: fix returning scalar values ```zig export fn entry1() i32 { return bar(); } ``` ```llvm define i32 @entry1() #2 !dbg !35 { Entry: %0 = call fastcc i32 @bar(), !dbg !39 ret i32 %0, !dbg !41 } ``` --- src/codegen.cpp | 3 ++- src/ir.cpp | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index beee678888..a035c6b332 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3564,7 +3564,8 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, IrInstructionReturnPtr *instruction) { - assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type)); + src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type), + instruction->base.source_node); return g->cur_ret_ptr; } diff --git a/src/ir.cpp b/src/ir.cpp index df7a593601..b3d5109e93 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14866,7 +14866,11 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s } case ResultLocIdReturn: { bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; - if (is_comptime) return nullptr; + if (is_comptime) + return nullptr; + if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type)) + return nullptr; + ZigType *ptr_return_type = get_pointer_to_type(ira->codegen, ira->explicit_return_type, false); result_loc->written = true; result_loc->resolved_loc = ir_build_return_ptr(ira, result_loc->source_instruction, ptr_return_type); -- cgit v1.2.3 From 4ea7685a5bf2abc504571939984b9eda7441ef5d Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 11 Jun 2019 16:05:56 -0500 Subject: made root package available to all other packages --- src/codegen.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 12b07ea6bc..cb767bcea7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8505,10 +8505,8 @@ static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *ba return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain); } -static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) { - ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); - package->package_table.put(buf_create_from_str("@root"), pkg_with_main); - return package; +static ZigPackage *create_bootstrap_pkg(CodeGen *g) { + return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); } static ZigPackage *create_test_runner_pkg(CodeGen *g) { @@ -8632,12 +8630,12 @@ static void gen_root_source(CodeGen *g) { !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); } if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib && g->is_dynamic) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap_lib.zig"); } if (!g->error_during_imports) { @@ -8645,7 +8643,7 @@ static void gen_root_source(CodeGen *g) { } if (g->is_test_build) { create_test_compile_var_and_add_test_runner(g); - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->test_runner_package), "bootstrap.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); if (!g->error_during_imports) { semantic_analyze(g); @@ -9629,6 +9627,13 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c if (g->std_package != nullptr) { assert(g->compile_var_package != nullptr); pkg->package_table.put(buf_create_from_str("std"), g->std_package); + + if (g->is_test_build) { + pkg->package_table.put(buf_create_from_str("@root"), g->test_runner_package); + } else { + pkg->package_table.put(buf_create_from_str("@root"), g->root_package); + } + pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); } return pkg; -- cgit v1.2.3 From e12c7d88b28200bc64a538cd4812bfe58a6b6b78 Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 11 Jun 2019 16:06:24 -0500 Subject: made root package available to itself --- src/codegen.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index cb767bcea7..a50a416e40 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -180,6 +180,8 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->root_package = new_package(".", "", ""); } + g->root_package->package_table.put(buf_create_from_str("@root"), g->root_package); + g->zig_std_special_dir = buf_alloc(); os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir); -- cgit v1.2.3 From 3ed6acd2d20de0a2a08ddf6549fb06a66687d96a Mon Sep 17 00:00:00 2001 From: emekoi Date: Tue, 11 Jun 2019 18:40:55 -0500 Subject: fixed infinite loop when caching packages --- src/codegen.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index a50a416e40..56bc9827c5 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9373,6 +9373,8 @@ static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) { // TODO: I think we need a more sophisticated detection of // packages we have already seen if (entry->value != pkg) { + auto root = pkg->package_table.maybe_get(buf_create_from_str("@root")); + if (root != nullptr && entry->value == root->value) continue; cache_buf(ch, entry->key); add_cache_pkg(g, ch, entry->value); } -- cgit v1.2.3 From 2ba29a1907264d6466f187cd89552a63160d3922 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 14 Jun 2019 11:01:38 -0400 Subject: fix peer result location with error code and payload --- src/all_types.hpp | 1 + src/codegen.cpp | 1 + src/ir.cpp | 67 ++++++++++++++++++++++++++++++++++++------------ test/stage1/behavior.zig | 14 +++++----- 4 files changed, 59 insertions(+), 24 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index d81fec19e9..4609d246b6 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3099,6 +3099,7 @@ struct IrInstructionTestErr { struct IrInstructionUnwrapErrCode { IrInstruction base; + bool initializing; IrInstruction *err_union_ptr; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index a035c6b332..def2f6f8eb 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4901,6 +4901,7 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab if (!type_has_bits(payload_type)) { return err_union_ptr; } else { + // TODO assign undef to the payload LLVMValueRef err_union_handle = get_handle_value(g, err_union_ptr, err_union_type, ptr_type); return LLVMBuildStructGEP(g->builder, err_union_handle, err_union_err_index, ""); } diff --git a/src/ir.cpp b/src/ir.cpp index a292f9a79b..5dfd84ff15 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -193,6 +193,8 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr IrInstruction *base_ptr, bool safety_check_on, bool initializing); static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing); +static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool initializing); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -15016,13 +15018,17 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) { return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, result_loc, false, true); } else if (actual_elem_type->id == ZigTypeIdErrorUnion && value_type->id != ZigTypeIdErrorUnion) { - IrInstruction *unwrapped_err_ptr = ir_analyze_unwrap_error_payload(ira, suspend_source_instr, - result_loc, false, true); - ZigType *actual_payload_type = actual_elem_type->data.error_union.payload_type; - if (actual_payload_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) { - return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, unwrapped_err_ptr, false, true); + if (value_type->id == ZigTypeIdErrorSet) { + return ir_analyze_unwrap_err_code(ira, suspend_source_instr, result_loc, true); } else { - return unwrapped_err_ptr; + IrInstruction *unwrapped_err_ptr = ir_analyze_unwrap_error_payload(ira, suspend_source_instr, + result_loc, false, true); + ZigType *actual_payload_type = actual_elem_type->data.error_union.payload_type; + if (actual_payload_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) { + return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, unwrapped_err_ptr, false, true); + } else { + return unwrapped_err_ptr; + } } } return result_loc; @@ -16437,6 +16443,9 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh peer_parent->base.source_instruction->source_node, expected_type, instructions, peer_parent->peer_count); + // the logic below assumes there are no instructions in the new current basic block yet + ir_assert(ira->new_irb.current_basic_block->instruction_list.length == 0, &phi_instruction->base); + // In case resolving the parent activates a suspend, do it now IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent, peer_parent->resolved_type, nullptr); @@ -16445,6 +16454,21 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh { return parent_result_loc; } + // If the above code generated any instructions in the current basic block, we need + // to move them to the peer parent predecessor. + ZigList instrs_to_move = {}; + while (ira->new_irb.current_basic_block->instruction_list.length != 0) { + instrs_to_move.append(ira->new_irb.current_basic_block->instruction_list.pop()); + } + if (instrs_to_move.length != 0) { + IrBasicBlock *predecessor = peer_parent->base.source_instruction->child->owner_bb; + IrInstruction *branch_instruction = predecessor->instruction_list.pop(); + ir_assert(branch_instruction->value.type->id == ZigTypeIdUnreachable, &phi_instruction->base); + while (instrs_to_move.length != 0) { + predecessor->instruction_list.append(instrs_to_move.pop()); + } + predecessor->instruction_list.append(branch_instruction); + } } IrSuspendPosition suspend_pos; @@ -22213,10 +22237,9 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } } -static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrInstructionUnwrapErrCode *instruction) { - IrInstruction *base_ptr = instruction->err_union_ptr->child; - if (type_is_invalid(base_ptr->value.type)) - return ira->codegen->invalid_instruction; +static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *base_ptr, bool initializing) +{ ZigType *ptr_type = base_ptr->value.type; // This will be a pointer type because unwrap err payload IR instruction operates on a pointer to a thing. @@ -22238,30 +22261,38 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrI if (!ptr_val) return ira->codegen->invalid_instruction; if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, instruction->base.source_node); + ConstExprValue *err_union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); if (err_union_val == nullptr) return ira->codegen->invalid_instruction; if (err_union_val->special != ConstValSpecialRuntime) { ErrorTableEntry *err = err_union_val->data.x_err_union.error_set->data.x_err_set; assert(err != nullptr); - IrInstruction *err_set_val = ir_const(ira, &instruction->base, - type_entry->data.error_union.err_set_type); + IrInstruction *err_set_val = ir_const(ira, source_instr, type_entry->data.error_union.err_set_type); err_set_val->value.data.x_err_set = err; err_set_val->value.parent.id = ConstParentIdErrUnionCode; err_set_val->value.parent.data.p_err_union_code.err_union_val = err_union_val; - return ir_get_ref(ira, &instruction->base, err_set_val, is_ptr_const, false); + return ir_get_ref(ira, source_instr, err_set_val, is_ptr_const, false); } } } IrInstruction *result = ir_build_unwrap_err_code(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, base_ptr); + source_instr->scope, source_instr->source_node, base_ptr); result->value.type = get_pointer_to_type(ira->codegen, type_entry->data.error_union.err_set_type, is_ptr_const); return result; } +static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, + IrInstructionUnwrapErrCode *instruction) +{ + IrInstruction *base_ptr = instruction->err_union_ptr->child; + if (type_is_invalid(base_ptr->value.type)) + return ira->codegen->invalid_instruction; + return ir_analyze_unwrap_err_code(ira, &instruction->base, base_ptr, false); +} + static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing) { @@ -24783,7 +24814,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFrameAddress: case IrInstructionIdHandle: case IrInstructionIdTestErr: - case IrInstructionIdUnwrapErrCode: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: @@ -24846,8 +24876,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { { IrInstructionUnwrapErrPayload *unwrap_err_payload_instruction = (IrInstructionUnwrapErrPayload *)instruction; - return unwrap_err_payload_instruction->safety_check_on; + return unwrap_err_payload_instruction->safety_check_on || + unwrap_err_payload_instruction->initializing; } + case IrInstructionIdUnwrapErrCode: + return reinterpret_cast(instruction)->initializing; case IrInstructionIdErrWrapPayload: return reinterpret_cast(instruction)->result_loc != nullptr; case IrInstructionIdErrWrapCode: diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 56a3860199..56862e07a7 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -21,7 +21,7 @@ comptime { _ = @import("behavior/bugs/1486.zig"); _ = @import("behavior/bugs/1500.zig"); _ = @import("behavior/bugs/1607.zig"); - //_ = @import("behavior/bugs/1851.zig"); + _ = @import("behavior/bugs/1851.zig"); _ = @import("behavior/bugs/1914.zig"); _ = @import("behavior/bugs/2006.zig"); _ = @import("behavior/bugs/2114.zig"); @@ -41,16 +41,16 @@ comptime { _ = @import("behavior/byval_arg_var.zig"); //_ = @import("behavior/cancel.zig"); //_ = @import("behavior/cast.zig"); - //_ = @import("behavior/const_slice_child.zig"); + _ = @import("behavior/const_slice_child.zig"); //_ = @import("behavior/coroutine_await_struct.zig"); //_ = @import("behavior/coroutines.zig"); - //_ = @import("behavior/defer.zig"); + _ = @import("behavior/defer.zig"); //_ = @import("behavior/enum.zig"); //_ = @import("behavior/enum_with_members.zig"); //_ = @import("behavior/error.zig"); //_ = @import("behavior/eval.zig"); _ = @import("behavior/field_parent_ptr.zig"); - //_ = @import("behavior/fn.zig"); + _ = @import("behavior/fn.zig"); _ = @import("behavior/fn_in_struct_in_comptime.zig"); _ = @import("behavior/for.zig"); //_ = @import("behavior/generics.zig"); @@ -59,13 +59,13 @@ comptime { //_ = @import("behavior/import.zig"); _ = @import("behavior/incomplete_struct_param_tld.zig"); _ = @import("behavior/inttoptr.zig"); - //_ = @import("behavior/ir_block_deps.zig"); + _ = @import("behavior/ir_block_deps.zig"); //_ = @import("behavior/math.zig"); //_ = @import("behavior/merge_error_sets.zig"); //_ = @import("behavior/misc.zig"); _ = @import("behavior/namespace_depends_on_compile_var.zig"); _ = @import("behavior/new_stack_call.zig"); - //_ = @import("behavior/null.zig"); + _ = @import("behavior/null.zig"); //_ = @import("behavior/optional.zig"); //_ = @import("behavior/pointers.zig"); _ = @import("behavior/popcount.zig"); @@ -93,7 +93,7 @@ comptime { //_ = @import("behavior/union.zig"); _ = @import("behavior/var_args.zig"); _ = @import("behavior/vector.zig"); - //_ = @import("behavior/void.zig"); + _ = @import("behavior/void.zig"); //_ = @import("behavior/while.zig"); _ = @import("behavior/widening.zig"); } -- cgit v1.2.3 From 6bf193af192ffaf3465958a243ec8fc8941cfe4d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 15 Jun 2019 12:28:21 -0400 Subject: better result location semantics with optionals and return locations somewhere along this branch, #1901 has been fixed. --- BRANCH_TODO | 5 +- src/all_types.hpp | 24 +++++++- src/codegen.cpp | 36 ++++++++---- src/ir.cpp | 114 ++++++++++++++++++++++++++++---------- src/ir_print.cpp | 33 ++++++++--- std/os.zig | 2 +- std/special/panic.zig | 23 ++++++-- std/special/test_runner.zig | 22 +++----- test/stage1/behavior.zig | 18 +++--- test/stage1/behavior/cast.zig | 16 +++--- test/stage1/behavior/error.zig | 84 ++++++++++++++-------------- test/stage1/behavior/generics.zig | 26 ++++----- test/stage1/behavior/optional.zig | 3 +- test/stage1/behavior/while.zig | 44 +++++++-------- 14 files changed, 281 insertions(+), 169 deletions(-) (limited to 'src/codegen.cpp') diff --git a/BRANCH_TODO b/BRANCH_TODO index 79616923bd..011630f315 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -4,10 +4,7 @@ Scratch pad for stuff to do before merging master uncomment all the behavior tests diff master branch to make sure -restore test_runner.zig to master branch - - also the default panic function and unexpected_error_tracing. see the commit - that adds this text to BRANCH_TODO file. - - and std/specia/bootstrap.zig +restore bootstrap.zig to master get an empty file compiling successfully (with no panic fn override) diff --git a/src/all_types.hpp b/src/all_types.hpp index 4497f7bfc7..73726de39b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2257,7 +2257,8 @@ enum IrInstructionId { IrInstructionIdHandle, IrInstructionIdAlignOf, IrInstructionIdOverflowOp, - IrInstructionIdTestErr, + IrInstructionIdTestErrSrc, + IrInstructionIdTestErrGen, IrInstructionIdUnwrapErrCode, IrInstructionIdUnwrapErrPayload, IrInstructionIdErrWrapCode, @@ -2292,6 +2293,7 @@ enum IrInstructionId { IrInstructionIdAlignCast, IrInstructionIdImplicitCast, IrInstructionIdResolveResult, + IrInstructionIdResultPtr, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, @@ -3082,10 +3084,16 @@ struct IrInstructionAlignOf { }; // returns true if error, returns false if not error -struct IrInstructionTestErr { +struct IrInstructionTestErrSrc { IrInstruction base; - IrInstruction *value; + IrInstruction *base_ptr; +}; + +struct IrInstructionTestErrGen { + IrInstruction base; + + IrInstruction *err_union; }; // Takes an error union pointer, returns a pointer to the error code. @@ -3596,6 +3604,7 @@ struct IrInstructionImplicitCast { ResultLoc *result_loc; }; +// This one is for writing through the result pointer. struct IrInstructionResolveResult { IrInstruction base; @@ -3603,6 +3612,15 @@ struct IrInstructionResolveResult { IrInstruction *ty; }; +// This one is when you want to read the value of the result. +// You have to give the value in case it is comptime. +struct IrInstructionResultPtr { + IrInstruction base; + + ResultLoc *result_loc; + IrInstruction *result; +}; + struct IrInstructionPtrOfArrayToSlice { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 764f79b130..42670f9005 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1323,7 +1323,9 @@ static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) { LLVMBuildRetVoid(g->builder); LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->add_error_return_trace_addr_fn_val = fn_val; return fn_val; @@ -1454,7 +1456,9 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { LLVMBuildBr(g->builder, loop_block); LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->merge_err_ret_traces_fn_val = fn_val; return fn_val; @@ -1510,7 +1514,9 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { LLVMBuildRetVoid(g->builder); LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->return_err_fn = fn_val; return fn_val; @@ -1638,7 +1644,9 @@ static LLVMValueRef get_safety_crash_err_fn(CodeGen *g) { gen_panic(g, msg_slice, err_ret_trace_arg); LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->safety_crash_err_fn = fn_val; return fn_val; @@ -4353,7 +4361,9 @@ static LLVMValueRef get_enum_tag_name_function(CodeGen *g, ZigType *enum_type) { g->cur_fn = prev_cur_fn; g->cur_fn_val = prev_cur_fn_val; LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } enum_type->data.enumeration.name_function = fn_val; return fn_val; @@ -4880,10 +4890,10 @@ static LLVMValueRef ir_render_overflow_op(CodeGen *g, IrExecutable *executable, return overflow_bit; } -static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErr *instruction) { - ZigType *err_union_type = instruction->value->value.type; +static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrInstructionTestErrGen *instruction) { + ZigType *err_union_type = instruction->err_union->value.type; ZigType *payload_type = err_union_type->data.error_union.payload_type; - LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->value); + LLVMValueRef err_union_handle = ir_llvm_value(g, instruction->err_union); LLVMValueRef err_val; if (type_has_bits(payload_type)) { @@ -5276,7 +5286,9 @@ static LLVMValueRef get_coro_alloc_helper_fn_val(CodeGen *g, LLVMTypeRef alloc_f g->cur_fn = prev_cur_fn; g->cur_fn_val = prev_cur_fn_val; LLVMPositionBuilderAtEnd(g->builder, prev_block); - LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + if (!g->strip_debug_symbols) { + LLVMSetCurrentDebugLocation(g->builder, prev_debug_location); + } g->coro_alloc_helper_fn_val = fn_val; return fn_val; @@ -5549,10 +5561,12 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdAllocaGen: case IrInstructionIdImplicitCast: case IrInstructionIdResolveResult: + case IrInstructionIdResultPtr: case IrInstructionIdContainerInitList: case IrInstructionIdSliceSrc: case IrInstructionIdRef: case IrInstructionIdBitCastSrc: + case IrInstructionIdTestErrSrc: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5635,8 +5649,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_handle(g, executable, (IrInstructionHandle *)instruction); case IrInstructionIdOverflowOp: return ir_render_overflow_op(g, executable, (IrInstructionOverflowOp *)instruction); - case IrInstructionIdTestErr: - return ir_render_test_err(g, executable, (IrInstructionTestErr *)instruction); + case IrInstructionIdTestErrGen: + return ir_render_test_err(g, executable, (IrInstructionTestErrGen *)instruction); case IrInstructionIdUnwrapErrCode: return ir_render_unwrap_err_code(g, executable, (IrInstructionUnwrapErrCode *)instruction); case IrInstructionIdUnwrapErrPayload: diff --git a/src/ir.cpp b/src/ir.cpp index 01d824b80c..b6f45a5325 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -756,8 +756,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionOverflowOp *) { return IrInstructionIdOverflowOp; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErr *) { - return IrInstructionIdTestErr; +static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrSrc *) { + return IrInstructionIdTestErrSrc; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionTestErrGen *) { + return IrInstructionIdTestErrGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionUnwrapErrCode *) { @@ -900,6 +904,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *) return IrInstructionIdResolveResult; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) { + return IrInstructionIdResultPtr; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) { return IrInstructionIdPtrOfArrayToSlice; } @@ -2418,13 +2426,26 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s return &instruction->base; } -static IrInstruction *ir_build_test_err(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *value) +static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *base_ptr) { - IrInstructionTestErr *instruction = ir_build_instruction(irb, scope, source_node); - instruction->value = value; + IrInstructionTestErrSrc *instruction = ir_build_instruction(irb, scope, source_node); + instruction->base_ptr = base_ptr; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(base_ptr, irb->current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_test_err_gen(IrAnalyze *ira, IrInstruction *source_instruction, + IrInstruction *err_union) +{ + IrInstructionTestErrGen *instruction = ir_build_instruction( + &ira->new_irb, source_instruction->scope, source_instruction->source_node); + instruction->base.value.type = ira->codegen->builtin_types.entry_bool; + instruction->err_union = err_union; + + ir_ref_instruction(err_union, ira->new_irb.current_basic_block); return &instruction->base; } @@ -2844,6 +2865,18 @@ static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstN return &instruction->base; } +static IrInstruction *ir_build_result_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc, IrInstruction *result) +{ + IrInstructionResultPtr *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_loc = result_loc; + instruction->result = result; + + ir_ref_instruction(result, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_opaque_type(IrBuilder *irb, Scope *scope, AstNode *source_node) { IrInstructionOpaqueType *instruction = ir_build_instruction(irb, scope, source_node); @@ -3531,7 +3564,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, ir_gen_defers_for_block(irb, scope, outer_scope, false); } - IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value); + IrInstruction *ret_ptr = ir_build_result_ptr(irb, scope, node, &result_loc_ret->base, + return_value); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr); bool should_inline = ir_should_inline(irb->exec, scope); IrInstruction *is_comptime; @@ -3577,8 +3612,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *err_union_val = ir_build_load_ptr(irb, scope, node, err_union_ptr); - IrInstruction *is_err_val = ir_build_test_err(irb, scope, node, err_union_val); + IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr); IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); @@ -5940,8 +5974,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n LValPtr, nullptr); if (err_val_ptr == irb->codegen->invalid_instruction) return err_val_ptr; - IrInstruction *err_val = ir_build_load_ptr(irb, scope, node->data.while_expr.condition, err_val_ptr); - IrInstruction *is_err = ir_build_test_err(irb, scope, node->data.while_expr.condition, err_val); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr); IrBasicBlock *after_cond_block = irb->current_basic_block; IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); IrInstruction *cond_br_inst; @@ -6722,7 +6755,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * return err_val_ptr; IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); - IrInstruction *is_err = ir_build_test_err(irb, scope, node, err_val); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr); IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk"); IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse"); @@ -7330,8 +7363,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *err_union_val = ir_build_load_ptr(irb, parent_scope, node, err_union_ptr); - IrInstruction *is_err = ir_build_test_err(irb, parent_scope, node, err_union_val); + IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr); IrInstruction *is_comptime; if (ir_should_inline(irb->exec, parent_scope)) { @@ -15010,7 +15042,9 @@ static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_s return result_loc; ir_assert(result_loc->value.type->id == ZigTypeIdPointer, suspend_source_instr); ZigType *actual_elem_type = result_loc->value.type->data.pointer.child_type; - if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional) { + if (actual_elem_type->id == ZigTypeIdOptional && value_type->id != ZigTypeIdOptional && + value_type->id != ZigTypeIdNull) + { return ir_analyze_unwrap_optional_payload(ira, suspend_source_instr, result_loc, false, true); } else if (actual_elem_type->id == ZigTypeIdErrorUnion && value_type->id != ZigTypeIdErrorUnion) { if (value_type->id == ZigTypeIdErrorSet) { @@ -22190,15 +22224,34 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr return result; } -static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErr *instruction) { - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) +static IrInstruction *ir_analyze_instruction_result_ptr(IrAnalyze *ira, IrInstructionResultPtr *instruction) { + IrInstruction *result = instruction->result->child; + if (type_is_invalid(result->value.type)) + return result; + + if (instruction->result_loc->written && instruction->result_loc->resolved_loc != nullptr && + !instr_is_comptime(result)) + { + IrInstruction *result_ptr = instruction->result_loc->resolved_loc; + // Convert the pointer to the result type. They should be the same, except this will resolve + // inferred error sets. + ZigType *new_ptr_type = get_pointer_to_type(ira->codegen, result->value.type, true); + return ir_analyze_ptr_cast(ira, &instruction->base, result_ptr, new_ptr_type, &instruction->base, false); + } + return ir_get_ref(ira, &instruction->base, result, true, false); +} + +static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstructionTestErrSrc *instruction) { + IrInstruction *base_ptr = instruction->base_ptr->child; + if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; + IrInstruction *value = ir_get_deref(ira, &instruction->base, base_ptr, nullptr); ZigType *type_entry = value->value.type; - if (type_is_invalid(type_entry)) { + if (type_is_invalid(type_entry)) return ira->codegen->invalid_instruction; - } else if (type_entry->id == ZigTypeIdErrorUnion) { + + if (type_entry->id == ZigTypeIdErrorUnion) { if (instr_is_comptime(value)) { ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad); if (!err_union_val) @@ -22221,10 +22274,7 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct return ir_const_bool(ira, &instruction->base, false); } - IrInstruction *result = ir_build_test_err(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, value); - result->value.type = ira->codegen->builtin_types.entry_bool; - return result; + return ir_build_test_err_gen(ira, &instruction->base, value); } else if (type_entry->id == ZigTypeIdErrorSet) { return ir_const_bool(ira, &instruction->base, true); } else { @@ -24343,6 +24393,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction case IrInstructionIdAllocaGen: case IrInstructionIdSliceGen: case IrInstructionIdRefGen: + case IrInstructionIdTestErrGen: zig_unreachable(); case IrInstructionIdReturn: @@ -24497,8 +24548,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_align_of(ira, (IrInstructionAlignOf *)instruction); case IrInstructionIdOverflowOp: return ir_analyze_instruction_overflow_op(ira, (IrInstructionOverflowOp *)instruction); - case IrInstructionIdTestErr: - return ir_analyze_instruction_test_err(ira, (IrInstructionTestErr *)instruction); + case IrInstructionIdTestErrSrc: + return ir_analyze_instruction_test_err(ira, (IrInstructionTestErrSrc *)instruction); case IrInstructionIdUnwrapErrCode: return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction); case IrInstructionIdUnwrapErrPayload: @@ -24543,6 +24594,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction); case IrInstructionIdResolveResult: return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction); + case IrInstructionIdResultPtr: + return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction); case IrInstructionIdOpaqueType: return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); case IrInstructionIdSetAlignStack: @@ -24672,6 +24725,9 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ continue; } + if (ira->codegen->verbose_ir) { + fprintf(stderr, "analyze #%zu\n", old_instruction->debug_id); + } IrInstruction *new_instruction = ir_analyze_instruction_base(ira, old_instruction); if (new_instruction != nullptr) { ir_assert(new_instruction->value.type != nullptr || new_instruction->value.type != nullptr, old_instruction); @@ -24808,7 +24864,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdReturnAddress: case IrInstructionIdFrameAddress: case IrInstructionIdHandle: - case IrInstructionIdTestErr: + case IrInstructionIdTestErrSrc: + case IrInstructionIdTestErrGen: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: @@ -24860,6 +24917,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdHasDecl: case IrInstructionIdAllocaSrc: case IrInstructionIdAllocaGen: + case IrInstructionIdResultPtr: return false; case IrInstructionIdAsm: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 4b8b175be0..9750b30e33 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -961,9 +961,15 @@ static void ir_print_overflow_op(IrPrint *irp, IrInstructionOverflowOp *instruct fprintf(irp->f, ")"); } -static void ir_print_test_err(IrPrint *irp, IrInstructionTestErr *instruction) { +static void ir_print_test_err_src(IrPrint *irp, IrInstructionTestErrSrc *instruction) { fprintf(irp->f, "@testError("); - ir_print_other_instruction(irp, instruction->value); + ir_print_other_instruction(irp, instruction->base_ptr); + fprintf(irp->f, ")"); +} + +static void ir_print_test_err_gen(IrPrint *irp, IrInstructionTestErrGen *instruction) { + fprintf(irp->f, "@testError("); + ir_print_other_instruction(irp, instruction->err_union); fprintf(irp->f, ")"); } @@ -976,10 +982,7 @@ static void ir_print_unwrap_err_code(IrPrint *irp, IrInstructionUnwrapErrCode *i static void ir_print_unwrap_err_payload(IrPrint *irp, IrInstructionUnwrapErrPayload *instruction) { fprintf(irp->f, "ErrorUnionFieldPayload("); ir_print_other_instruction(irp, instruction->value); - fprintf(irp->f, ")"); - if (!instruction->safety_check_on) { - fprintf(irp->f, " // no safety"); - } + fprintf(irp->f, ")safety=%d,init=%d",instruction->safety_check_on, instruction->initializing); } static void ir_print_optional_wrap(IrPrint *irp, IrInstructionOptionalWrap *instruction) { @@ -1301,6 +1304,14 @@ static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *in fprintf(irp->f, ")"); } +static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) { + fprintf(irp->f, "ResultPtr("); + ir_print_result_loc(irp, instruction->result_loc); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->result); + fprintf(irp->f, ")"); +} + static void ir_print_opaque_type(IrPrint *irp, IrInstructionOpaqueType *instruction) { fprintf(irp->f, "@OpaqueType()"); } @@ -1837,8 +1848,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdOverflowOp: ir_print_overflow_op(irp, (IrInstructionOverflowOp *)instruction); break; - case IrInstructionIdTestErr: - ir_print_test_err(irp, (IrInstructionTestErr *)instruction); + case IrInstructionIdTestErrSrc: + ir_print_test_err_src(irp, (IrInstructionTestErrSrc *)instruction); + break; + case IrInstructionIdTestErrGen: + ir_print_test_err_gen(irp, (IrInstructionTestErrGen *)instruction); break; case IrInstructionIdUnwrapErrCode: ir_print_unwrap_err_code(irp, (IrInstructionUnwrapErrCode *)instruction); @@ -1939,6 +1953,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdResolveResult: ir_print_resolve_result(irp, (IrInstructionResolveResult *)instruction); break; + case IrInstructionIdResultPtr: + ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction); + break; case IrInstructionIdOpaqueType: ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); break; diff --git a/std/os.zig b/std/os.zig index 3409dcf6c6..a0f8d1f12b 100644 --- a/std/os.zig +++ b/std/os.zig @@ -2487,7 +2487,7 @@ pub fn toPosixPath(file_path: []const u8) ![PATH_MAX]u8 { /// if this happens the fix is to add the error code to the corresponding /// switch expression, possibly introduce a new error in the error set, and /// send a patch to Zig. -pub const unexpected_error_tracing = false; +pub const unexpected_error_tracing = builtin.mode == .Debug; pub const UnexpectedError = error{ /// The Operating System returned an undocumented error code. diff --git a/std/special/panic.zig b/std/special/panic.zig index 50dc5e0c65..92e0d9164c 100644 --- a/std/special/panic.zig +++ b/std/special/panic.zig @@ -7,8 +7,23 @@ const builtin = @import("builtin"); const std = @import("std"); pub fn panic(msg: []const u8, error_return_trace: ?*builtin.StackTrace) noreturn { - const stderr = std.io.getStdErr() catch std.process.abort(); - stderr.write("panic: ") catch std.process.abort(); - stderr.write(msg) catch std.process.abort(); - std.process.abort(); + @setCold(true); + switch (builtin.os) { + .freestanding => { + while (true) {} + }, + .wasi => { + std.debug.warn("{}", msg); + _ = std.os.wasi.proc_raise(std.os.wasi.SIGABRT); + unreachable; + }, + .uefi => { + // TODO look into using the debug info and logging helpful messages + std.os.abort(); + }, + else => { + const first_trace_addr = @returnAddress(); + std.debug.panicExtra(error_return_trace, first_trace_addr, "{}", msg); + }, + } } diff --git a/std/special/test_runner.zig b/std/special/test_runner.zig index 001b26ebb0..db01293059 100644 --- a/std/special/test_runner.zig +++ b/std/special/test_runner.zig @@ -2,34 +2,28 @@ const std = @import("std"); const io = std.io; const builtin = @import("builtin"); const test_fn_list = builtin.test_functions; +const warn = std.debug.warn; -pub fn main() void { - const stderr = io.getStdErr() catch std.process.abort(); - +pub fn main() !void { var ok_count: usize = 0; var skip_count: usize = 0; for (test_fn_list) |test_fn, i| { - stderr.write("test ") catch std.process.abort(); - stderr.write(test_fn.name) catch std.process.abort(); + warn("{}/{} {}...", i + 1, test_fn_list.len, test_fn.name); if (test_fn.func()) |_| { ok_count += 1; - stderr.write("...OK\n") catch std.process.abort(); + warn("OK\n"); } else |err| switch (err) { error.SkipZigTest => { skip_count += 1; - stderr.write("...SKIP\n") catch std.process.abort(); - }, - else => { - stderr.write("error: ") catch std.process.abort(); - stderr.write(@errorName(err)) catch std.process.abort(); - std.process.abort(); + warn("SKIP\n"); }, + else => return err, } } if (ok_count == test_fn_list.len) { - stderr.write("All tests passed.\n") catch std.process.abort(); + warn("All tests passed.\n"); } else { - stderr.write("Some tests skipped.\n") catch std.process.abort(); + warn("{} passed; {} skipped.\n", ok_count, skip_count); } } diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 411785a5c4..90ad30e55c 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -40,46 +40,46 @@ comptime { //_ = @import("behavior/bugs/920.zig"); _ = @import("behavior/byval_arg_var.zig"); //_ = @import("behavior/cancel.zig"); - _ = @import("behavior/cast.zig"); // TODO + _ = @import("behavior/cast.zig"); _ = @import("behavior/const_slice_child.zig"); //_ = @import("behavior/coroutine_await_struct.zig"); //_ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); _ = @import("behavior/enum.zig"); _ = @import("behavior/enum_with_members.zig"); - //_ = @import("behavior/error.zig"); + _ = @import("behavior/error.zig"); // TODO _ = @import("behavior/eval.zig"); // TODO _ = @import("behavior/field_parent_ptr.zig"); _ = @import("behavior/fn.zig"); _ = @import("behavior/fn_in_struct_in_comptime.zig"); _ = @import("behavior/for.zig"); - _ = @import("behavior/generics.zig"); // TODO + _ = @import("behavior/generics.zig"); _ = @import("behavior/hasdecl.zig"); _ = @import("behavior/if.zig"); - //_ = @import("behavior/import.zig"); + _ = @import("behavior/import.zig"); _ = @import("behavior/incomplete_struct_param_tld.zig"); _ = @import("behavior/inttoptr.zig"); _ = @import("behavior/ir_block_deps.zig"); - //_ = @import("behavior/math.zig"); + _ = @import("behavior/math.zig"); _ = @import("behavior/merge_error_sets.zig"); _ = @import("behavior/misc.zig"); // TODO _ = @import("behavior/namespace_depends_on_compile_var.zig"); _ = @import("behavior/new_stack_call.zig"); _ = @import("behavior/null.zig"); _ = @import("behavior/optional.zig"); // TODO - //_ = @import("behavior/pointers.zig"); + _ = @import("behavior/pointers.zig"); _ = @import("behavior/popcount.zig"); _ = @import("behavior/ptrcast.zig"); // TODO _ = @import("behavior/pub_enum.zig"); _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("behavior/reflection.zig"); _ = @import("behavior/sizeof_and_typeof.zig"); - //_ = @import("behavior/slice.zig"); + _ = @import("behavior/slice.zig"); _ = @import("behavior/slicetobytes.zig"); //_ = @import("behavior/struct.zig"); _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/struct_contains_slice_of_itself.zig"); - //_ = @import("behavior/switch.zig"); + _ = @import("behavior/switch.zig"); //_ = @import("behavior/switch_prong_err_enum.zig"); _ = @import("behavior/switch_prong_implicit_cast.zig"); _ = @import("behavior/syntax.zig"); @@ -87,7 +87,7 @@ comptime { _ = @import("behavior/truncate.zig"); _ = @import("behavior/try.zig"); _ = @import("behavior/type_info.zig"); - //_ = @import("behavior/typename.zig"); + _ = @import("behavior/typename.zig"); _ = @import("behavior/undefined.zig"); _ = @import("behavior/underscore.zig"); _ = @import("behavior/union.zig"); diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index f659f6d9ae..0a2ffb6c2f 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -124,14 +124,14 @@ fn returnNullLitFromOptionalTypeErrorRef() anyerror!?*A { return null; } -//test "peer type resolution: ?T and T" { -// expect(peerTypeTAndOptionalT(true, false).? == 0); -// expect(peerTypeTAndOptionalT(false, false).? == 3); -// comptime { -// expect(peerTypeTAndOptionalT(true, false).? == 0); -// expect(peerTypeTAndOptionalT(false, false).? == 3); -// } -//} +test "peer type resolution: ?T and T" { + expect(peerTypeTAndOptionalT(true, false).? == 0); + expect(peerTypeTAndOptionalT(false, false).? == 3); + comptime { + expect(peerTypeTAndOptionalT(true, false).? == 0); + expect(peerTypeTAndOptionalT(false, false).? == 3); + } +} fn peerTypeTAndOptionalT(c: bool, b: bool) ?usize { if (c) { return if (b) null else usize(0); diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index babefba6f5..861c500751 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -249,48 +249,48 @@ fn intLiteral(str: []const u8) !?i64 { return error.T; } -test "nested error union function call in optional unwrap" { - const S = struct { - const Foo = struct { - a: i32, - }; - - fn errorable() !i32 { - var x: Foo = (try getFoo()) orelse return error.Other; - return x.a; - } - - fn errorable2() !i32 { - var x: Foo = (try getFoo2()) orelse return error.Other; - return x.a; - } - - fn errorable3() !i32 { - var x: Foo = (try getFoo3()) orelse return error.Other; - return x.a; - } - - fn getFoo() anyerror!?Foo { - return Foo{ .a = 1234 }; - } - - fn getFoo2() anyerror!?Foo { - return error.Failure; - } - - fn getFoo3() anyerror!?Foo { - return null; - } - }; - expect((try S.errorable()) == 1234); - expectError(error.Failure, S.errorable2()); - expectError(error.Other, S.errorable3()); - comptime { - expect((try S.errorable()) == 1234); - expectError(error.Failure, S.errorable2()); - expectError(error.Other, S.errorable3()); - } -} +//test "nested error union function call in optional unwrap" { +// const S = struct { +// const Foo = struct { +// a: i32, +// }; +// +// fn errorable() !i32 { +// var x: Foo = (try getFoo()) orelse return error.Other; +// return x.a; +// } +// +// fn errorable2() !i32 { +// var x: Foo = (try getFoo2()) orelse return error.Other; +// return x.a; +// } +// +// fn errorable3() !i32 { +// var x: Foo = (try getFoo3()) orelse return error.Other; +// return x.a; +// } +// +// fn getFoo() anyerror!?Foo { +// return Foo{ .a = 1234 }; +// } +// +// fn getFoo2() anyerror!?Foo { +// return error.Failure; +// } +// +// fn getFoo3() anyerror!?Foo { +// return null; +// } +// }; +// expect((try S.errorable()) == 1234); +// expectError(error.Failure, S.errorable2()); +// expectError(error.Other, S.errorable3()); +// comptime { +// expect((try S.errorable()) == 1234); +// expectError(error.Failure, S.errorable2()); +// expectError(error.Other, S.errorable3()); +// } +//} test "widen cast integer payload of error union function call" { const S = struct { diff --git a/test/stage1/behavior/generics.zig b/test/stage1/behavior/generics.zig index c514735d17..664b982c21 100644 --- a/test/stage1/behavior/generics.zig +++ b/test/stage1/behavior/generics.zig @@ -80,19 +80,19 @@ test "function with return type type" { expect(list2.prealloc_items.len == 8); } -//test "generic struct" { -// var a1 = GenNode(i32){ -// .value = 13, -// .next = null, -// }; -// var b1 = GenNode(bool){ -// .value = true, -// .next = null, -// }; -// expect(a1.value == 13); -// expect(a1.value == a1.getVal()); -// expect(b1.getVal()); -//} +test "generic struct" { + var a1 = GenNode(i32){ + .value = 13, + .next = null, + }; + var b1 = GenNode(bool){ + .value = true, + .next = null, + }; + expect(a1.value == 13); + expect(a1.value == a1.getVal()); + expect(b1.getVal()); +} fn GenNode(comptime T: type) type { return struct { value: T, diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig index 0539d1c201..09260c4778 100644 --- a/test/stage1/behavior/optional.zig +++ b/test/stage1/behavior/optional.zig @@ -76,6 +76,5 @@ test "unwrap function call with optional pointer return value" { } }; S.entry(); - // TODO https://github.com/ziglang/zig/issues/1901 - //comptime S.entry(); + comptime S.entry(); } diff --git a/test/stage1/behavior/while.zig b/test/stage1/behavior/while.zig index 5e486a2495..29ad90ed17 100644 --- a/test/stage1/behavior/while.zig +++ b/test/stage1/behavior/while.zig @@ -82,28 +82,28 @@ test "while with else" { expect(got_else == 1); } -//test "while with optional as condition" { -// numbers_left = 10; -// var sum: i32 = 0; -// while (getNumberOrNull()) |value| { -// sum += value; -// } -// expect(sum == 45); -//} -// -//test "while with optional as condition with else" { -// numbers_left = 10; -// var sum: i32 = 0; -// var got_else: i32 = 0; -// while (getNumberOrNull()) |value| { -// sum += value; -// expect(got_else == 0); -// } else { -// got_else += 1; -// } -// expect(sum == 45); -// expect(got_else == 1); -//} +test "while with optional as condition" { + numbers_left = 10; + var sum: i32 = 0; + while (getNumberOrNull()) |value| { + sum += value; + } + expect(sum == 45); +} + +test "while with optional as condition with else" { + numbers_left = 10; + var sum: i32 = 0; + var got_else: i32 = 0; + while (getNumberOrNull()) |value| { + sum += value; + expect(got_else == 0); + } else { + got_else += 1; + } + expect(sum == 45); + expect(got_else == 1); +} test "while with error union condition" { numbers_left = 10; -- cgit v1.2.3 From 9564c05cd5641095d48baf982a372f00bdf02659 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 15 Jun 2019 19:19:13 -0400 Subject: better result location handling of inline loops --- src/all_types.hpp | 9 ++++ src/codegen.cpp | 1 + src/ir.cpp | 111 ++++++++++++++++++++++++++++++++-------- src/ir_print.cpp | 9 ++++ test/stage1/behavior.zig | 6 +-- test/stage1/behavior/eval.zig | 20 ++++++-- test/stage1/behavior/struct.zig | 40 +++++++-------- 7 files changed, 146 insertions(+), 50 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 73726de39b..49b71e1eed 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2293,6 +2293,7 @@ enum IrInstructionId { IrInstructionIdAlignCast, IrInstructionIdImplicitCast, IrInstructionIdResolveResult, + IrInstructionIdResetResult, IrInstructionIdResultPtr, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, @@ -3621,6 +3622,12 @@ struct IrInstructionResultPtr { IrInstruction *result; }; +struct IrInstructionResetResult { + IrInstruction base; + + ResultLoc *result_loc; +}; + struct IrInstructionPtrOfArrayToSlice { IrInstruction base; @@ -3639,6 +3646,8 @@ enum ResultLocId { ResultLocIdBitCast, }; +// Additions to this struct may need to be handled in +// ir_reset_result struct ResultLoc { ResultLocId id; bool written; diff --git a/src/codegen.cpp b/src/codegen.cpp index 42670f9005..4c212c95ab 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5561,6 +5561,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdAllocaGen: case IrInstructionIdImplicitCast: case IrInstructionIdResolveResult: + case IrInstructionIdResetResult: case IrInstructionIdResultPtr: case IrInstructionIdContainerInitList: case IrInstructionIdSliceSrc: diff --git a/src/ir.cpp b/src/ir.cpp index b6f45a5325..d48c013caf 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -166,6 +166,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg); static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing); +static void ir_assert(bool ok, IrInstruction *source_instruction); static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, ZigVar *var); static ZigType *ir_resolve_atomic_operand_type(IrAnalyze *ira, IrInstruction *op); static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, ResultLoc *result_loc); @@ -904,6 +905,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionResolveResult *) return IrInstructionIdResolveResult; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionResetResult *) { + return IrInstructionIdResetResult; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionResultPtr *) { return IrInstructionIdResultPtr; } @@ -2865,6 +2870,15 @@ static IrInstruction *ir_build_resolve_result(IrBuilder *irb, Scope *scope, AstN return &instruction->base; } +static IrInstruction *ir_build_reset_result(IrBuilder *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc) +{ + IrInstructionResetResult *instruction = ir_build_instruction(irb, scope, source_node); + instruction->result_loc = result_loc; + + return &instruction->base; +} + static IrInstruction *ir_build_result_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, ResultLoc *result_loc, IrInstruction *result) { @@ -3540,6 +3554,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, { ResultLocReturn *result_loc_ret = allocate(1); result_loc_ret->base.id = ResultLocIdReturn; + ir_build_reset_result(irb, scope, node, &result_loc_ret->base); IrInstruction *return_value; if (expr_node) { @@ -3929,7 +3944,7 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); } -static ResultLocPeerParent *create_binary_result_peers(IrInstruction *cond_br_inst, +static ResultLocPeerParent *ir_build_binary_result_peers(IrBuilder *irb, IrInstruction *cond_br_inst, IrBasicBlock *else_block, IrBasicBlock *endif_block, ResultLoc *parent, IrInstruction *is_comptime) { ResultLocPeerParent *peer_parent = allocate(1); @@ -3948,6 +3963,13 @@ static ResultLocPeerParent *create_binary_result_peers(IrInstruction *cond_br_in peer_parent->peers[1].base.source_instruction = cond_br_inst; peer_parent->peers[1].parent = peer_parent; peer_parent->peers[1].next_bb = endif_block; + + IrInstruction *popped_inst = irb->current_basic_block->instruction_list.pop(); + ir_assert(popped_inst == cond_br_inst, cond_br_inst); + + ir_build_reset_result(irb, cond_br_inst->scope, cond_br_inst->source_node, &peer_parent->base); + irb->current_basic_block->instruction_list.append(popped_inst); + return peer_parent; } @@ -3978,8 +4000,8 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd"); IrInstruction *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, ok_block, end_block, result_loc, - is_comptime); + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, ok_block, end_block, + result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, null_block); IrInstruction *null_result = ir_gen_node_extra(irb, op2_node, parent_scope, lval, &peer_parent->peers[0].base); @@ -5006,6 +5028,8 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo ir_ref_instruction(dest_type, irb->current_basic_block); result_loc_bit_cast->parent = result_loc; + ir_build_reset_result(irb, scope, node, &result_loc_bit_cast->base); + AstNode *arg1_node = node->data.fn_call_expr.params.at(1); IrInstruction *arg1_value = ir_gen_node_extra(irb, arg1_node, scope, LValNone, &result_loc_bit_cast->base); @@ -5494,8 +5518,7 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, condition->source_node, condition, then_block, else_block, is_comptime); - - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, endif_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, then_block); @@ -5832,11 +5855,14 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A zig_unreachable(); } -static ResultLocVar *create_var_result_loc(IrInstruction *alloca, ZigVar *var) { +static ResultLocVar *ir_build_var_result_loc(IrBuilder *irb, IrInstruction *alloca, ZigVar *var) { ResultLocVar *result_loc_var = allocate(1); result_loc_var->base.id = ResultLocIdVar; result_loc_var->base.source_instruction = alloca; result_loc_var->var = var; + + ir_build_reset_result(irb, alloca->scope, alloca->source_node, &result_loc_var->base); + return result_loc_var; } @@ -5844,7 +5870,7 @@ static void build_decl_var_and_init(IrBuilder *irb, Scope *scope, AstNode *sourc IrInstruction *init, const char *name_hint, IrInstruction *is_comptime) { IrInstruction *alloca = ir_build_alloca_src(irb, scope, source_node, nullptr, name_hint, is_comptime); - ResultLocVar *var_result_loc = create_var_result_loc(alloca, var); + ResultLocVar *var_result_loc = ir_build_var_result_loc(irb, alloca, var); ir_build_end_expr(irb, scope, source_node, init, &var_result_loc->base); ir_build_var_decl_src(irb, scope, source_node, var, nullptr, alloca); } @@ -5907,7 +5933,7 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod buf_ptr(variable_declaration->symbol), is_comptime); // Create a result location for the initialization expression. - ResultLocVar *result_loc_var = create_var_result_loc(alloca, var); + ResultLocVar *result_loc_var = ir_build_var_result_loc(irb, alloca, var); ResultLoc *init_result_loc = (type_instruction == nullptr) ? &result_loc_var->base : nullptr; Scope *init_scope = is_comptime_scalar ? @@ -5983,10 +6009,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n else_block, body_block, is_comptime); cond_br_inst->is_gen = true; } else { - cond_br_inst = is_err; // for the purposes of the source instruction to create_binary_result_peers + // for the purposes of the source instruction to ir_build_binary_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, end_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); @@ -6085,10 +6112,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n body_block, else_block, is_comptime); cond_br_inst->is_gen = true; } else { - cond_br_inst = is_non_null; // for the purposes of source instruction for create_binary_result_peers + // for the purposes of the source instruction to ir_build_binary_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, end_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); @@ -6168,10 +6196,11 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n body_block, else_block, is_comptime); cond_br_inst->is_gen = true; } else { - cond_br_inst = cond_val; // for the source instruction arg to create_binary_result_peers + // for the purposes of the source instruction to ir_build_binary_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, end_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); @@ -6303,8 +6332,8 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo IrInstruction *cond_br_inst = ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, cond, body_block, else_block, is_comptime)); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, end_block, result_loc, - is_comptime); + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, end_block, + result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); IrInstruction *elem_ptr = ir_build_elem_ptr(irb, parent_scope, node, array_val_ptr, index_val, false, @@ -6683,7 +6712,7 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, endif_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, then_block); @@ -6765,7 +6794,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstruction *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err); IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, else_block, endif_block, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, else_block, endif_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, ok_block); @@ -7093,6 +7122,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, check_ranges.items, check_ranges.length, else_prong != nullptr); + ir_build_reset_result(irb, scope, node, &peer_parent->base); + IrInstruction *br_instruction; if (cases.length == 0) { br_instruction = ir_build_br(irb, scope, node, else_block, is_comptime); @@ -7377,7 +7408,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrEnd"); IrInstruction *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_comptime); - ResultLocPeerParent *peer_parent = create_binary_result_peers(cond_br_inst, ok_block, end_block, result_loc, + ResultLocPeerParent *peer_parent = ir_build_binary_result_peers(irb, cond_br_inst, ok_block, end_block, result_loc, is_comptime); ir_set_cursor_at_end_and_append_block(irb, err_block); @@ -8268,6 +8299,7 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc // Create a result location indicating there is none - but if one gets created // it will be properly distributed. result_loc = no_result_loc(); + ir_build_reset_result(irb, scope, node, result_loc); } IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction); @@ -8521,10 +8553,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec // non-allocating. Basically coroutines are not supported right now until they are reworked. args[3] = ir_build_const_usize(irb, scope, node, 1); // new_size args[4] = ir_build_const_usize(irb, scope, node, 1); // new_align - ResultLocNone *result_loc_none = allocate(1); - result_loc_none->base.id = ResultLocIdNone; ir_build_call_src(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr, - nullptr, &result_loc_none->base); + nullptr, no_result_loc()); IrBasicBlock *resume_block = ir_create_basic_block(irb, scope, "Resume"); ir_build_cond_br(irb, scope, node, resume_awaiter, resume_block, irb->exec->coro_suspend_block, const_bool_false); @@ -15082,6 +15112,40 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn return ir_resolve_result(ira, &instruction->base, instruction->result_loc, implicit_elem_type, nullptr); } +static void ir_reset_result(ResultLoc *result_loc) { + result_loc->written = false; + result_loc->resolved_loc = nullptr; + result_loc->gen_instruction = nullptr; + result_loc->implicit_elem_type = nullptr; + // TODO handle result_loc->scope_elide = + switch (result_loc->id) { + case ResultLocIdInvalid: + zig_unreachable(); + case ResultLocIdPeerParent: { + ResultLocPeerParent *peer_parent = reinterpret_cast(result_loc); + peer_parent->skipped = false; + peer_parent->done_resuming = false; + peer_parent->resolved_type = nullptr; + for (size_t i = 0; i < peer_parent->peer_count; i += 1) { + ir_reset_result(&peer_parent->peers[i].base); + } + break; + } + case ResultLocIdPeer: + case ResultLocIdNone: + case ResultLocIdVar: + case ResultLocIdReturn: + case ResultLocIdInstruction: + case ResultLocIdBitCast: + break; + } +} + +static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInstructionResetResult *instruction) { + ir_reset_result(instruction->result_loc); + return ir_const_void(ira, &instruction->base); +} + static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, IrInstruction *async_allocator_inst) @@ -24594,6 +24658,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction return ir_analyze_instruction_implicit_cast(ira, (IrInstructionImplicitCast *)instruction); case IrInstructionIdResolveResult: return ir_analyze_instruction_resolve_result(ira, (IrInstructionResolveResult *)instruction); + case IrInstructionIdResetResult: + return ir_analyze_instruction_reset_result(ira, (IrInstructionResetResult *)instruction); case IrInstructionIdResultPtr: return ir_analyze_instruction_result_ptr(ira, (IrInstructionResultPtr *)instruction); case IrInstructionIdOpaqueType: @@ -24818,6 +24884,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdSliceGen: case IrInstructionIdOptionalWrap: case IrInstructionIdVectorToArray: + case IrInstructionIdResetResult: return true; case IrInstructionIdPhi: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 9750b30e33..b66827fb92 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -1304,6 +1304,12 @@ static void ir_print_resolve_result(IrPrint *irp, IrInstructionResolveResult *in fprintf(irp->f, ")"); } +static void ir_print_reset_result(IrPrint *irp, IrInstructionResetResult *instruction) { + fprintf(irp->f, "ResetResult("); + ir_print_result_loc(irp, instruction->result_loc); + fprintf(irp->f, ")"); +} + static void ir_print_result_ptr(IrPrint *irp, IrInstructionResultPtr *instruction) { fprintf(irp->f, "ResultPtr("); ir_print_result_loc(irp, instruction->result_loc); @@ -1953,6 +1959,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdResolveResult: ir_print_resolve_result(irp, (IrInstructionResolveResult *)instruction); break; + case IrInstructionIdResetResult: + ir_print_reset_result(irp, (IrInstructionResetResult *)instruction); + break; case IrInstructionIdResultPtr: ir_print_result_ptr(irp, (IrInstructionResultPtr *)instruction); break; diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 90ad30e55c..6aa6ab48cb 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -37,7 +37,7 @@ comptime { _ = @import("behavior/bugs/718.zig"); _ = @import("behavior/bugs/726.zig"); _ = @import("behavior/bugs/828.zig"); - //_ = @import("behavior/bugs/920.zig"); + _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/byval_arg_var.zig"); //_ = @import("behavior/cancel.zig"); _ = @import("behavior/cast.zig"); @@ -76,7 +76,7 @@ comptime { _ = @import("behavior/sizeof_and_typeof.zig"); _ = @import("behavior/slice.zig"); _ = @import("behavior/slicetobytes.zig"); - //_ = @import("behavior/struct.zig"); + _ = @import("behavior/struct.zig"); // TODO _ = @import("behavior/struct_contains_null_ptr_itself.zig"); _ = @import("behavior/struct_contains_slice_of_itself.zig"); _ = @import("behavior/switch.zig"); @@ -94,6 +94,6 @@ comptime { _ = @import("behavior/var_args.zig"); _ = @import("behavior/vector.zig"); _ = @import("behavior/void.zig"); - _ = @import("behavior/while.zig"); // TODO + _ = @import("behavior/while.zig"); _ = @import("behavior/widening.zig"); } diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 595e83b087..49c7380f2b 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -176,9 +176,9 @@ test "const slice" { } } -//test "try to trick eval with runtime if" { -// expect(testTryToTrickEvalWithRuntimeIf(true) == 10); -//} +test "try to trick eval with runtime if" { + expect(testTryToTrickEvalWithRuntimeIf(true) == 10); +} fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { comptime var i: usize = 0; @@ -190,6 +190,17 @@ fn testTryToTrickEvalWithRuntimeIf(b: bool) usize { } } +//test "inlined loop has array literal with elided runtime scope on first iteration but not second iteration" { +// var runtime = [1]i32{3}; +// comptime var i: usize = 0; +// inline while (i < 2) : (i += 1) { +// const result = if (i == 0) [1]i32{2} else runtime; +// } +// comptime { +// expect(i == 2); +// } +//} + fn max(comptime T: type, a: T, b: T) T { if (T == bool) { return a or b; @@ -756,8 +767,7 @@ test "comptime bitwise operators" { test "*align(1) u16 is the same as *align(1:0:2) u16" { comptime { expect(*align(1:0:2) u16 == *align(1) u16); - // TODO add parsing support for this syntax - //expect(*align(:0:2) u16 == *u16); + expect(*align(:0:2) u16 == *u16); } } diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 0ebd0654d0..ccdff3503e 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -529,26 +529,26 @@ test "access to global struct fields" { expect(g_foo.bar.value == 42); } -test "packed struct with fp fields" { - const S = packed struct { - data: [3]f32, - - pub fn frob(self: *@This()) void { - self.data[0] += self.data[1] + self.data[2]; - self.data[1] += self.data[0] + self.data[2]; - self.data[2] += self.data[0] + self.data[1]; - } - }; - - var s: S = undefined; - s.data[0] = 1.0; - s.data[1] = 2.0; - s.data[2] = 3.0; - s.frob(); - expectEqual(f32(6.0), s.data[0]); - expectEqual(f32(11.0), s.data[1]); - expectEqual(f32(20.0), s.data[2]); -} +//test "packed struct with fp fields" { +// const S = packed struct { +// data: [3]f32, +// +// pub fn frob(self: *@This()) void { +// self.data[0] += self.data[1] + self.data[2]; +// self.data[1] += self.data[0] + self.data[2]; +// self.data[2] += self.data[0] + self.data[1]; +// } +// }; +// +// var s: S = undefined; +// s.data[0] = 1.0; +// s.data[1] = 2.0; +// s.data[2] = 3.0; +// s.frob(); +// expectEqual(f32(6.0), s.data[0]); +// expectEqual(f32(11.0), s.data[1]); +// expectEqual(f32(20.0), s.data[2]); +//} test "use within struct scope" { const S = struct { -- cgit v1.2.3 From b025193de5b951734e5108e4762e5dc40359431b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 17 Jun 2019 13:31:19 -0400 Subject: inferred comptime values rather than elided scopes because of this example: ```zig export fn entry(b: bool) usize { var runtime = [1]i32{3}; comptime var i: usize = 0; inline while (i < 2) : (i += 1) { const result = if (i == 0) [1]i32{2} else runtime; } comptime { return i; } } ``` The problem is that the concept of "resetting" a result location, introduced in the previous commit, cannot handle elision scopes. This concept is inherently broken with inline loops. --- src/all_types.hpp | 14 +- src/analyze.cpp | 35 +---- src/analyze.hpp | 2 - src/codegen.cpp | 9 +- src/ir.cpp | 383 ++++++++++++++++++++++++++++-------------------------- 5 files changed, 208 insertions(+), 235 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 49b71e1eed..f63d6a902b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -203,6 +203,9 @@ enum ConstPtrMut { // The pointer points to memory that is known only at runtime. // For example it may point to the initializer value of a variable. ConstPtrMutRuntimeVar, + // The pointer points to memory for which it must be inferred whether the + // value is comptime known or not. + ConstPtrMutInfer, }; struct ConstPtrValue { @@ -1957,7 +1960,6 @@ enum ScopeId { ScopeIdCompTime, ScopeIdCoroPrelude, ScopeIdRuntime, - ScopeIdElide, }; struct Scope { @@ -1971,14 +1973,6 @@ struct Scope { ScopeId id; }; -// This scope, when activated, causes all the instructions in the scope to be omitted -// from the generated code. -struct ScopeElide { - Scope base; - - bool activated; -}; - // This scope comes from global declarations or from // declarations in a container declaration // NodeTypeContainerDecl @@ -2655,6 +2649,7 @@ struct IrInstructionContainerInitFieldsField { IrInstruction *value; AstNode *source_node; TypeStructField *type_struct_field; + IrInstruction *result_loc; }; struct IrInstructionContainerInitFields { @@ -3655,7 +3650,6 @@ struct ResultLoc { IrInstruction *source_instruction; IrInstruction *gen_instruction; // value to store to the result loc ZigType *implicit_elem_type; - ScopeElide *scope_elide; }; struct ResultLocNone { diff --git a/src/analyze.cpp b/src/analyze.cpp index 1f9b1ffbed..b39b1e35ca 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -166,12 +166,6 @@ Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruct return &scope->base; } -ScopeElide *create_elide_scope(CodeGen *g, AstNode *node, Scope *parent) { - ScopeElide *scope = allocate(1); - init_scope(g, &scope->base, ScopeIdElide, node, parent); - return scope; -} - ScopeSuspend *create_suspend_scope(CodeGen *g, AstNode *node, Scope *parent) { assert(node->type == NodeTypeSuspend); ScopeSuspend *scope = allocate(1); @@ -4187,6 +4181,7 @@ static uint32_t hash_const_val_ptr(ConstExprValue *const_val) { case ConstPtrMutComptimeConst: hash_val += (uint32_t)4214318515; break; + case ConstPtrMutInfer: case ConstPtrMutComptimeVar: hash_val += (uint32_t)1103195694; break; @@ -7286,31 +7281,3 @@ void src_assert(bool ok, AstNode *source_node) { const char *msg = "assertion failed. This is a bug in the Zig compiler."; stage2_panic(msg, strlen(msg)); } - -bool scope_is_elided(Scope *scope) { - for (;;) { - switch (scope->id) { - case ScopeIdElide: - if (reinterpret_cast(scope)->activated) - return true; - // fallthrough - case ScopeIdBlock: - case ScopeIdDefer: - case ScopeIdDeferExpr: - case ScopeIdVarDecl: - case ScopeIdLoop: - case ScopeIdSuspend: - case ScopeIdCoroPrelude: - case ScopeIdRuntime: - scope = scope->parent; - continue; - case ScopeIdFnDef: - case ScopeIdCompTime: - case ScopeIdDecls: - case ScopeIdCImport: - return false; - } - zig_unreachable(); - } -} - diff --git a/src/analyze.hpp b/src/analyze.hpp index c1dd482a7a..8d78ef86e2 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -121,7 +121,6 @@ ScopeFnDef *create_fndef_scope(CodeGen *g, AstNode *node, Scope *parent, ZigFn * Scope *create_comptime_scope(CodeGen *g, AstNode *node, Scope *parent); Scope *create_coro_prelude_scope(CodeGen *g, AstNode *node, Scope *parent); Scope *create_runtime_scope(CodeGen *g, AstNode *node, Scope *parent, IrInstruction *is_comptime); -ScopeElide *create_elide_scope(CodeGen *g, AstNode *node, Scope *parent); void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str); ConstExprValue *create_const_str_lit(CodeGen *g, Buf *str); @@ -254,6 +253,5 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa void src_assert(bool ok, AstNode *source_node); bool is_container(ZigType *type_entry); ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); -bool scope_is_elided(Scope *scope); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index 4c212c95ab..547840514a 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -722,7 +722,6 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { case ScopeIdCompTime: case ScopeIdCoroPrelude: case ScopeIdRuntime: - case ScopeIdElide: return get_di_scope(g, scope->parent); } zig_unreachable(); @@ -5761,12 +5760,10 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) continue; - if (!scope_is_elided(instruction->scope)) { - if (!g->strip_debug_symbols) { - set_debug_location(g, instruction); - } - instruction->llvm_value = ir_render_instruction(g, executable, instruction); + if (!g->strip_debug_symbols) { + set_debug_location(g, instruction); } + instruction->llvm_value = ir_render_instruction(g, executable, instruction); } current_block->llvm_exit_block = LLVMGetInsertBlock(g->builder); } diff --git a/src/ir.cpp b/src/ir.cpp index d48c013caf..32f6b4c22a 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -196,6 +196,8 @@ static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruct IrInstruction *base_ptr, bool safety_check_on, bool initializing); static IrInstruction *ir_analyze_unwrap_err_code(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool initializing); +static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source_instr, + IrInstruction *ptr, IrInstruction *uncasted_value); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { assert(get_src_ptr_type(const_val->type) != nullptr); @@ -3363,7 +3365,6 @@ static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_sco case ScopeIdSuspend: case ScopeIdCompTime: case ScopeIdRuntime: - case ScopeIdElide: scope = scope->parent; continue; case ScopeIdDeferExpr: @@ -3420,7 +3421,6 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o case ScopeIdSuspend: case ScopeIdCompTime: case ScopeIdRuntime: - case ScopeIdElide: scope = scope->parent; continue; case ScopeIdDeferExpr: @@ -5758,15 +5758,8 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A return irb->codegen->invalid_instruction; } - IrInstruction *container_ptr = nullptr; - if (!ir_should_inline(irb->exec, scope)) { - src_assert(parent_result_loc->scope_elide == nullptr, node); - parent_result_loc->scope_elide = create_elide_scope(irb->codegen, node, scope); - - src_assert(parent_result_loc != nullptr, node); - container_ptr = ir_build_resolve_result(irb, &parent_result_loc->scope_elide->base, - node, parent_result_loc, container_type); - } + IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, + container_type); size_t field_count = container_init_expr->entries.length; IrInstructionContainerInitFieldsField *fields = allocate(field_count); @@ -5777,27 +5770,22 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A Buf *name = entry_node->data.struct_val_field.name; AstNode *expr_node = entry_node->data.struct_val_field.expr; - Scope *val_scope = scope; - ResultLoc *child_result_loc = nullptr; - if (container_ptr != nullptr) { - IrInstruction *field_ptr = ir_build_field_ptr(irb, &parent_result_loc->scope_elide->base, - expr_node, container_ptr, name, true); - ResultLocInstruction *result_loc_inst = allocate(1); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = field_ptr; - ir_ref_instruction(field_ptr, irb->current_basic_block); - child_result_loc = &result_loc_inst->base; - val_scope = &parent_result_loc->scope_elide->base; - } + IrInstruction *field_ptr = ir_build_field_ptr(irb, scope, expr_node, container_ptr, name, true); + ResultLocInstruction *result_loc_inst = allocate(1); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = field_ptr; + ir_ref_instruction(field_ptr, irb->current_basic_block); + ir_build_reset_result(irb, scope, expr_node, &result_loc_inst->base); - IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, val_scope, LValNone, - child_result_loc); + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, + &result_loc_inst->base); if (expr_value == irb->codegen->invalid_instruction) return expr_value; fields[i].name = name; fields[i].value = expr_value; fields[i].source_node = entry_node; + fields[i].result_loc = field_ptr; } IrInstruction *init_fields = ir_build_container_init_fields(irb, scope, node, container_type, field_count, fields, container_ptr); @@ -5812,36 +5800,23 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A container_type = ir_build_array_type(irb, scope, node, item_count_inst, elem_type); } - IrInstruction *container_ptr = nullptr; - if (!ir_should_inline(irb->exec, scope)) { - src_assert(parent_result_loc->scope_elide == nullptr, node); - parent_result_loc->scope_elide = create_elide_scope(irb->codegen, node, scope); - - container_ptr = ir_build_resolve_result(irb, &parent_result_loc->scope_elide->base, - node, parent_result_loc, container_type); - } + IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, + container_type); IrInstruction **values = allocate(item_count); for (size_t i = 0; i < item_count; i += 1) { AstNode *expr_node = container_init_expr->entries.at(i); - ResultLoc *child_result_loc = nullptr; - Scope *val_scope = scope; - if (container_ptr != nullptr) { - IrInstruction *elem_index = ir_build_const_usize(irb, &parent_result_loc->scope_elide->base, - expr_node, i); - IrInstruction *elem_ptr = ir_build_elem_ptr(irb, &parent_result_loc->scope_elide->base, - expr_node, container_ptr, elem_index, false, PtrLenSingle, true); - ResultLocInstruction *result_loc_inst = allocate(1); - result_loc_inst->base.id = ResultLocIdInstruction; - result_loc_inst->base.source_instruction = elem_ptr; - ir_ref_instruction(elem_ptr, irb->current_basic_block); - child_result_loc = &result_loc_inst->base; - val_scope = &parent_result_loc->scope_elide->base; - } + IrInstruction *elem_index = ir_build_const_usize(irb, scope, expr_node, i); + IrInstruction *elem_ptr = ir_build_elem_ptr(irb, scope, expr_node, container_ptr, elem_index, + false, PtrLenSingle, true); + ResultLocInstruction *result_loc_inst = allocate(1); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = elem_ptr; + ir_ref_instruction(elem_ptr, irb->current_basic_block); - IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, val_scope, LValNone, - child_result_loc); + IrInstruction *expr_value = ir_gen_node_extra(irb, expr_node, scope, LValNone, + &result_loc_inst->base); if (expr_value == irb->codegen->invalid_instruction) return expr_value; @@ -8651,8 +8626,6 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec IrBasicBlock *bb = exec->basic_block_list.at(0); for (size_t i = 0; i < bb->instruction_list.length; i += 1) { IrInstruction *instruction = bb->instruction_list.at(i); - if (scope_is_elided(instruction->scope)) - continue; if (instruction->id == IrInstructionIdReturn) { IrInstructionReturn *ret_inst = (IrInstructionReturn *)instruction; IrInstruction *value = ret_inst->value; @@ -12745,9 +12718,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc ir_add_error(ira, ptr, buf_sprintf("attempt to dereference undefined value")); return ira->codegen->invalid_instruction; } - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst || - ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) - { + if (ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) { ConstExprValue *pointee = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); if (pointee->special != ConstValSpecialRuntime) { IrInstruction *result = ir_const(ira, source_instruction, child_type); @@ -14487,7 +14458,25 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) { - if (var->mem_slot_index != SIZE_MAX) { + // Resolve ConstPtrMutInfer + if (var->gen_is_const) { + var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst; + } else if (is_comptime_var) { + var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeVar; + } else { + // we need a runtime ptr but we have a comptime val. + // since it's a comptime val there are no instructions for it. + // we memcpy the init value here + IrInstruction *deref = ir_get_deref(ira, var_ptr, var_ptr, nullptr); + // If this assertion trips, something is wrong with the IR instructions, because + // we expected the above deref to return a constant value, but it created a runtime + // instruction. + assert(deref->value.special != ConstValSpecialRuntime); + var_ptr->value.special = ConstValSpecialRuntime; + ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref); + } + + if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) { assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); @@ -14818,9 +14807,9 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in pointee->special = ConstValSpecialUndef; IrInstructionAllocaGen *result = ir_create_alloca_gen(ira, source_inst, align, name_hint); - result->base.value.special = force_comptime ? ConstValSpecialStatic : ConstValSpecialRuntime; + result->base.value.special = ConstValSpecialStatic; result->base.value.data.x_ptr.special = ConstPtrSpecialRef; - result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutRuntimeVar; + result->base.value.data.x_ptr.mut = force_comptime ? ConstPtrMutComptimeVar : ConstPtrMutInfer; result->base.value.data.x_ptr.data.ref.pointee = pointee; if ((err = type_resolve(ira->codegen, var_type, ResolveStatusZeroBitsKnown))) @@ -15109,7 +15098,10 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_instruction; - return ir_resolve_result(ira, &instruction->base, instruction->result_loc, implicit_elem_type, nullptr); + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, implicit_elem_type, nullptr); + if (result_loc != nullptr) + return result_loc; + zig_panic("TODO"); } static void ir_reset_result(ResultLoc *result_loc) { @@ -15431,7 +15423,9 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source ir_add_error(ira, source_instr, buf_sprintf("cannot assign to constant")); return ira->codegen->invalid_instruction; } - if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar) { + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar || + ptr->value.data.x_ptr.mut == ConstPtrMutInfer) + { if (instr_is_comptime(value)) { ConstExprValue *dest_val = const_ptr_pointee(ira, ira->codegen, &ptr->value, source_instr->source_node); if (dest_val == nullptr) @@ -15451,12 +15445,16 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source return ir_const_void(ira, source_instr); } } - ir_add_error(ira, source_instr, - buf_sprintf("cannot store runtime value in compile time variable")); - ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); - dest_val->type = ira->codegen->builtin_types.entry_invalid; + if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) { + ptr->value.special = ConstValSpecialRuntime; + } else { + ir_add_error(ira, source_instr, + buf_sprintf("cannot store runtime value in compile time variable")); + ConstExprValue *dest_val = const_ptr_pointee_unchecked(ira->codegen, &ptr->value); + dest_val->type = ira->codegen->builtin_types.entry_invalid; - return ira->codegen->invalid_instruction; + return ira->codegen->invalid_instruction; + } } } @@ -17091,6 +17089,81 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, return ira->codegen->invalid_instruction; } +static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, + TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing) +{ + switch (type_has_one_possible_value(ira->codegen, field->type_entry)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: { + IrInstruction *elem = ir_const(ira, source_instr, field->type_entry); + return ir_get_ref(ira, source_instr, elem, false, false); + } + case OnePossibleValueNo: + break; + } + assert(struct_ptr->value.type->id == ZigTypeIdPointer); + bool is_packed = (struct_type->data.structure.layout == ContainerLayoutPacked); + uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry); + uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; + uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; + uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? + get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; + bool is_const = struct_ptr->value.type->data.pointer.is_const; + bool is_volatile = struct_ptr->value.type->data.pointer.is_volatile; + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, + is_const, is_volatile, PtrLenSingle, align_bytes, + (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), + (uint32_t)host_int_bytes_for_result_type, false); + if (instr_is_comptime(struct_ptr)) { + ConstExprValue *ptr_val = ir_resolve_const(ira, struct_ptr, UndefBad); + if (!ptr_val) + return ira->codegen->invalid_instruction; + + if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { + ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); + if (struct_val == nullptr) + return ira->codegen->invalid_instruction; + if (type_is_invalid(struct_val->type)) + return ira->codegen->invalid_instruction; + if (struct_val->special == ConstValSpecialUndef && initializing) { + struct_val->data.x_struct.fields = create_const_vals(struct_type->data.structure.src_field_count); + struct_val->special = ConstValSpecialStatic; + for (size_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) { + ConstExprValue *field_val = &struct_val->data.x_struct.fields[i]; + field_val->special = ConstValSpecialUndef; + field_val->type = struct_type->data.structure.fields[i].type_entry; + ConstParent *parent = get_const_val_parent(ira->codegen, field_val); + if (parent != nullptr) { + parent->id = ConstParentIdStruct; + parent->data.p_struct.struct_val = struct_val; + parent->data.p_struct.field_index = i; + } + } + } + IrInstruction *result; + if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { + result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, struct_ptr, field); + result->value.type = ptr_type; + result->value.special = ConstValSpecialStatic; + } else { + result = ir_const(ira, source_instr, ptr_type); + } + ConstExprValue *const_val = &result->value; + const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; + const_val->data.x_ptr.mut = struct_ptr->value.data.x_ptr.mut; + const_val->data.x_ptr.data.base_struct.struct_val = struct_val; + const_val->data.x_ptr.data.base_struct.field_index = field->src_index; + return result; + } + } + IrInstruction *result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, + struct_ptr, field); + result->value.type = ptr_type; + return result; +} + static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_name, IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing) { @@ -17101,59 +17174,10 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ira->codegen->invalid_instruction; assert(container_ptr->value.type->id == ZigTypeIdPointer); - bool is_const = container_ptr->value.type->data.pointer.is_const; - bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; if (bare_type->id == ZigTypeIdStruct) { TypeStructField *field = find_struct_type_field(bare_type, field_name); - if (field) { - switch (type_has_one_possible_value(ira->codegen, field->type_entry)) { - case OnePossibleValueInvalid: - return ira->codegen->invalid_instruction; - case OnePossibleValueYes: { - IrInstruction *elem = ir_const(ira, source_instr, field->type_entry); - return ir_get_ref(ira, source_instr, elem, false, false); - } - case OnePossibleValueNo: - break; - } - bool is_packed = (bare_type->data.structure.layout == ContainerLayoutPacked); - uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry); - uint32_t ptr_bit_offset = container_ptr->value.type->data.pointer.bit_offset_in_host; - uint32_t ptr_host_int_bytes = container_ptr->value.type->data.pointer.host_int_bytes; - uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? - get_host_int_bytes(ira->codegen, bare_type, field) : ptr_host_int_bytes; - if (instr_is_comptime(container_ptr)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (!ptr_val) - return ira->codegen->invalid_instruction; - - if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ConstExprValue *struct_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); - if (struct_val == nullptr) - return ira->codegen->invalid_instruction; - if (type_is_invalid(struct_val->type)) - return ira->codegen->invalid_instruction; - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, - is_const, is_volatile, PtrLenSingle, align_bytes, - (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), - (uint32_t)host_int_bytes_for_result_type, false); - IrInstruction *result = ir_const(ira, source_instr, ptr_type); - ConstExprValue *const_val = &result->value; - const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; - const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut; - const_val->data.x_ptr.data.base_struct.struct_val = struct_val; - const_val->data.x_ptr.data.base_struct.field_index = field->src_index; - return result; - } - } - IrInstruction *result = ir_build_struct_field_ptr(&ira->new_irb, source_instr->scope, source_instr->source_node, - container_ptr, field); - result->value.type = get_pointer_to_type_extra(ira->codegen, field->type_entry, is_const, is_volatile, - PtrLenSingle, - align_bytes, - (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), - host_int_bytes_for_result_type, false); - return result; + if (field != nullptr) { + return ir_analyze_struct_field_ptr(ira, source_instr, field, container_ptr, bare_type, initializing); } else { return ir_analyze_container_member_access_inner(ira, bare_type, field_name, source_instr, container_ptr, container_type); @@ -17162,6 +17186,9 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ return ir_analyze_container_member_access_inner(ira, bare_type, field_name, source_instr, container_ptr, container_type); } else if (bare_type->id == ZigTypeIdUnion) { + bool is_const = container_ptr->value.type->data.pointer.is_const; + bool is_volatile = container_ptr->value.type->data.pointer.is_volatile; + TypeUnionField *field = find_union_type_field(bare_type, field_name); if (field) { if (instr_is_comptime(container_ptr)) { @@ -18849,7 +18876,7 @@ static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRe static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction, ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields, - IrInstruction *old_result_loc) + IrInstruction *result_loc) { Error err; assert(container_type->id == ZigTypeIdUnion); @@ -18905,21 +18932,17 @@ static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrI return result; } - ir_assert(old_result_loc != nullptr, instruction); - IrInstruction *result_loc = old_result_loc->child; - if (type_is_invalid(result_loc->value.type)) - return result_loc; return ir_get_deref(ira, instruction, result_loc, nullptr); } static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields, - IrInstruction *old_result_loc) + IrInstruction *result_loc) { Error err; if (container_type->id == ZigTypeIdUnion) { return ir_analyze_container_init_fields_union(ira, instruction, container_type, instr_field_count, - fields, old_result_loc); + fields, result_loc); } if (container_type->id != ZigTypeIdStruct || is_slice(container_type)) { ir_add_error(ira, instruction, @@ -18936,20 +18959,28 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstruction *first_non_const_instruction = nullptr; AstNode **field_assign_nodes = allocate(actual_field_count); + ZigList const_ptrs = {}; bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; - ConstExprValue const_val = {}; - const_val.special = ConstValSpecialStatic; - const_val.type = container_type; - // const_val.global_refs = allocate(1); - const_val.data.x_struct.fields = create_const_vals(actual_field_count); + + // Here we iterate over the fields that have been initialized, and emit + // compile errors for missing fields and duplicate fields. + // It is only now that we find out whether the struct initialization can be a comptime + // value, but we have already emitted runtime instructions for the fields that + // were initialized with runtime values, and have omitted instructions that would have + // initialized fields with comptime values. + // So now we must clean up this situation. If it turns out the struct initialization can + // be a comptime value, overwrite ConstPtrMutInfer with ConstPtrMutComptimeConst. + // Otherwise, we must emit instructions to runtime-initialize the fields that have + // comptime-known values. + for (size_t i = 0; i < instr_field_count; i += 1) { IrInstructionContainerInitFieldsField *field = &fields[i]; - IrInstruction *field_value = field->value->child; - if (type_is_invalid(field_value->value.type)) + IrInstruction *field_result_loc = field->result_loc->child; + if (type_is_invalid(field_result_loc->value.type)) return ira->codegen->invalid_instruction; TypeStructField *type_field = find_struct_type_field(container_type, field->name); @@ -18963,10 +18994,6 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc if (type_is_invalid(type_field->type_entry)) return ira->codegen->invalid_instruction; - IrInstruction *casted_field_value = ir_implicit_cast(ira, field_value, type_field->type_entry); - if (casted_field_value == ira->codegen->invalid_instruction) - return ira->codegen->invalid_instruction; - size_t field_index = type_field->src_index; AstNode *existing_assign_node = field_assign_nodes[field_index]; if (existing_assign_node) { @@ -18976,23 +19003,18 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc } field_assign_nodes[field_index] = field->source_node; - if (const_val.special == ConstValSpecialStatic) { - if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime) { - ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); - if (!field_val) - return ira->codegen->invalid_instruction; - - copy_const_val(&const_val.data.x_struct.fields[field_index], field_val, true); - } else { - first_non_const_instruction = casted_field_value; - const_val.special = ConstValSpecialRuntime; - } + if (instr_is_comptime(field_result_loc) && + field_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) + { + const_ptrs.append(field_result_loc); + } else { + first_non_const_instruction = field_result_loc; } } bool any_missing = false; for (size_t i = 0; i < actual_field_count; i += 1) { - if (field_assign_nodes[i]) continue; + if (field_assign_nodes[i] != nullptr) continue; // look for a default field value TypeStructField *field = &container_type->data.structure.fields[i]; @@ -19018,44 +19040,41 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstruction *runtime_inst = ir_const(ira, instruction, field->init_val->type); copy_const_val(&runtime_inst->value, field->init_val, true); - if (const_val.special == ConstValSpecialStatic) { - copy_const_val(&const_val.data.x_struct.fields[i], field->init_val, true); + IrInstruction *field_ptr = ir_analyze_struct_field_ptr(ira, instruction, field, result_loc, + container_type, true); + ir_analyze_store_ptr(ira, instruction, field_ptr, runtime_inst); + if (instr_is_comptime(field_ptr) && field_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) { + const_ptrs.append(field_ptr); + } else { + first_non_const_instruction = result_loc; } } if (any_missing) return ira->codegen->invalid_instruction; - if (const_val.special == ConstValSpecialStatic) { - IrInstruction *result = ir_const(ira, instruction, nullptr); - ConstExprValue *out_val = &result->value; - copy_const_val(out_val, &const_val, false); - out_val->type = container_type; - - for (size_t i = 0; i < instr_field_count; i += 1) { - ConstExprValue *field_val = &out_val->data.x_struct.fields[i]; - ConstParent *parent = get_const_val_parent(ira->codegen, field_val); - if (parent != nullptr) { - parent->id = ConstParentIdStruct; - parent->data.p_struct.field_index = i; - parent->data.p_struct.struct_val = out_val; + if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) { + if (const_ptrs.length == actual_field_count) { + result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst; + } else { + result_loc->value.special = ConstValSpecialRuntime; + for (size_t i = 0; i < const_ptrs.length; i += 1) { + IrInstruction *field_result_loc = const_ptrs.at(i); + IrInstruction *deref = ir_get_deref(ira, field_result_loc, field_result_loc, nullptr); + field_result_loc->value.special = ConstValSpecialRuntime; + ir_analyze_store_ptr(ira, field_result_loc, field_result_loc, deref); } } - - return result; } - if (is_comptime) { + IrInstruction *result = ir_get_deref(ira, instruction, result_loc, nullptr); + + if (is_comptime && !instr_is_comptime(result)) { ir_add_error_node(ira, first_non_const_instruction->source_node, buf_sprintf("unable to evaluate constant expression")); return ira->codegen->invalid_instruction; } - - ir_assert(old_result_loc != nullptr, instruction); - IrInstruction *result_loc = old_result_loc->child; - if (type_is_invalid(result_loc->value.type)) - return result_loc; - return ir_get_deref(ira, instruction, result_loc, nullptr); + return result; } static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, @@ -19074,8 +19093,11 @@ static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, buf_sprintf("expected array type or [_], found slice")); return ira->codegen->invalid_instruction; } else if (container_type->id == ZigTypeIdStruct && !is_slice(container_type) && elem_count == 0) { - return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, - instruction->result_loc); + ir_assert(instruction->result_loc != nullptr, &instruction->base); + IrInstruction *result_loc = instruction->result_loc->child; + if (type_is_invalid(result_loc->value.type)) + return result_loc; + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, 0, nullptr, result_loc); } else if (container_type->id == ZigTypeIdArray) { // array is same as slice init but we make a compile error if the length is wrong ZigType *child_type; @@ -19199,8 +19221,13 @@ static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ir if (type_is_invalid(container_type)) return ira->codegen->invalid_instruction; + ir_assert(instruction->result_loc != nullptr, &instruction->base); + IrInstruction *result_loc = instruction->result_loc->child; + if (type_is_invalid(result_loc->value.type)) + return result_loc; + return ir_analyze_container_init_fields(ira, &instruction->base, container_type, - instruction->field_count, instruction->fields, instruction->result_loc); + instruction->field_count, instruction->fields, result_loc); } static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira, @@ -24390,17 +24417,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct if (type_is_invalid(value->value.type)) return ira->codegen->invalid_instruction; - bool want_resolve_result; - if (instruction->result_loc->written) { - if (instruction->result_loc->scope_elide != nullptr && instr_is_comptime(value)) { - want_resolve_result = true; - instruction->result_loc->scope_elide->activated = true; - } else { - want_resolve_result = false; - } - } else { - want_resolve_result = true; - } + bool want_resolve_result = !instruction->result_loc->written; if (want_resolve_result) { IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, value->value.type, value); -- cgit v1.2.3 From e27da17ff2cc45c93ab95defd937fd8038751b51 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 18 Jun 2019 17:07:27 -0400 Subject: back to many behavioral tests passing --- src/codegen.cpp | 4 +--- src/ir.cpp | 2 +- test/stage1/behavior.zig | 4 ++-- test/stage1/behavior/cast.zig | 36 ++++++++++++++++++------------------ test/stage1/behavior/enum.zig | 32 ++++++++++++++++---------------- test/stage1/behavior/error.zig | 16 ++++++++-------- test/stage1/behavior/struct.zig | 12 ++++++------ 7 files changed, 52 insertions(+), 54 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 547840514a..dc2a4f55df 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2017,11 +2017,9 @@ static LLVMValueRef ir_llvm_value(CodeGen *g, IrInstruction *instruction) { render_const_val_global(g, &instruction->value, ""); ZigType *ptr_type = get_pointer_to_type(g, instruction->value.type, true); instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_global, get_llvm_type(g, ptr_type), ""); - } else if (get_codegen_ptr_type(instruction->value.type) != nullptr) { + } else { instruction->llvm_value = LLVMBuildBitCast(g->builder, instruction->value.global_refs->llvm_value, get_llvm_type(g, instruction->value.type), ""); - } else { - instruction->llvm_value = instruction->value.global_refs->llvm_value; } assert(instruction->llvm_value); } diff --git a/src/ir.cpp b/src/ir.cpp index 90d79995e1..4d2221ab39 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -14999,7 +14999,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe return parent_result_loc; } // because is_comptime is false, we mark this a runtime pointer - parent_result_loc->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; + parent_result_loc->value.special = ConstValSpecialRuntime; result_loc->written = true; result_loc->resolved_loc = parent_result_loc; return result_loc->resolved_loc; diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 6aa6ab48cb..ccbec6849a 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -40,12 +40,12 @@ comptime { _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/byval_arg_var.zig"); //_ = @import("behavior/cancel.zig"); - _ = @import("behavior/cast.zig"); + _ = @import("behavior/cast.zig"); // TODO _ = @import("behavior/const_slice_child.zig"); //_ = @import("behavior/coroutine_await_struct.zig"); //_ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); - _ = @import("behavior/enum.zig"); + _ = @import("behavior/enum.zig"); // TODO _ = @import("behavior/enum_with_members.zig"); _ = @import("behavior/error.zig"); // TODO _ = @import("behavior/eval.zig"); // TODO diff --git a/test/stage1/behavior/cast.zig b/test/stage1/behavior/cast.zig index 0a2ffb6c2f..c148523a72 100644 --- a/test/stage1/behavior/cast.zig +++ b/test/stage1/behavior/cast.zig @@ -165,10 +165,10 @@ fn castToOptionalSlice() ?[]const u8 { return "hi"; } -test "implicitly cast from [0]T to anyerror![]T" { - testCastZeroArrayToErrSliceMut(); - comptime testCastZeroArrayToErrSliceMut(); -} +//test "implicitly cast from [0]T to anyerror![]T" { +// testCastZeroArrayToErrSliceMut(); +// comptime testCastZeroArrayToErrSliceMut(); +//} fn testCastZeroArrayToErrSliceMut() void { expect((gimmeErrOrSlice() catch unreachable).len == 0); @@ -178,20 +178,20 @@ fn gimmeErrOrSlice() anyerror![]u8 { return [_]u8{}; } -test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { - { - var data = "hi"; - const slice = data[0..]; - expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } - comptime { - var data = "hi"; - const slice = data[0..]; - expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); - expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); - } -} +//test "peer type resolution: [0]u8, []const u8, and anyerror![]u8" { +// { +// var data = "hi"; +// const slice = data[0..]; +// expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); +// expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); +// } +// comptime { +// var data = "hi"; +// const slice = data[0..]; +// expect((try peerTypeEmptyArrayAndSliceAndError(true, slice)).len == 0); +// expect((try peerTypeEmptyArrayAndSliceAndError(false, slice)).len == 1); +// } +//} fn peerTypeEmptyArrayAndSliceAndError(a: bool, slice: []u8) anyerror![]u8 { if (a) { return [_]u8{}; diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index 51f4f0e196..e06a075974 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1,22 +1,22 @@ const expect = @import("std").testing.expect; const mem = @import("std").mem; -test "enum type" { - const foo1 = Foo{ .One = 13 }; - const foo2 = Foo{ - .Two = Point{ - .x = 1234, - .y = 5678, - }, - }; - const bar = Bar.B; - - expect(bar == Bar.B); - expect(@memberCount(Foo) == 3); - expect(@memberCount(Bar) == 4); - expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); - expect(@sizeOf(Bar) == 1); -} +//test "enum type" { +// const foo1 = Foo{ .One = 13 }; +// const foo2 = Foo{ +// .Two = Point{ +// .x = 1234, +// .y = 5678, +// }, +// }; +// const bar = Bar.B; +// +// expect(bar == Bar.B); +// expect(@memberCount(Foo) == 3); +// expect(@memberCount(Bar) == 4); +// expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); +// expect(@sizeOf(Bar) == 1); +//} test "enum as return value" { switch (returnAnInt(13)) { diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index 861c500751..1f8f8b36e4 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -130,10 +130,10 @@ fn testExplicitErrorSetCast(set1: Set1) void { expect(y == error.A); } -test "comptime test error for empty error set" { - testComptimeTestErrorEmptySet(1234); - comptime testComptimeTestErrorEmptySet(1234); -} +//test "comptime test error for empty error set" { +// testComptimeTestErrorEmptySet(1234); +// comptime testComptimeTestErrorEmptySet(1234); +//} const EmptyErrorSet = error{}; @@ -204,10 +204,10 @@ fn foo2(f: fn () anyerror!void) void { fn bar2() (error{}!void) {} -test "error: Zero sized error set returned with value payload crash" { - _ = foo3(0) catch {}; - _ = comptime foo3(0) catch {}; -} +//test "error: Zero sized error set returned with value payload crash" { +// _ = foo3(0) catch {}; +// _ = comptime foo3(0) catch {}; +//} const Error = error{}; fn foo3(b: usize) Error!usize { diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index ccdff3503e..a08dec5359 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -522,12 +522,12 @@ const S0 = struct { } }; -var g_foo: S0 = S0.init(); - -test "access to global struct fields" { - g_foo.bar.value = 42; - expect(g_foo.bar.value == 42); -} +//var g_foo: S0 = S0.init(); +// +//test "access to global struct fields" { +// g_foo.bar.value = 42; +// expect(g_foo.bar.value == 42); +//} //test "packed struct with fp fields" { // const S = packed struct { -- cgit v1.2.3 From b588a803bf4493d2fd1892fe172b9ce8cfb0ca30 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 14:35:59 -0400 Subject: fix comptime modification of const struct field --- src/all_types.hpp | 3 +++ src/analyze.cpp | 2 +- src/codegen.cpp | 2 +- src/ir.cpp | 43 +++++++++++++++++++++++++++---------------- test/stage1/behavior.zig | 2 +- test/stage1/behavior/eval.zig | 16 ++++++++-------- 6 files changed, 41 insertions(+), 27 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 01f084218d..efb74e5ec3 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -334,6 +334,9 @@ struct ConstExprValue { RuntimeHintPtr rh_ptr; RuntimeHintSlice rh_slice; } data; + + ConstExprValue(const ConstExprValue &other) = delete; // plz zero initialize with {} + ConstExprValue& operator= (const ConstExprValue &other) = delete; // use copy_const_val }; enum ReturnKnowledge { diff --git a/src/analyze.cpp b/src/analyze.cpp index b39b1e35ca..d048dd9770 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -4711,7 +4711,7 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { void init_const_str_lit(CodeGen *g, ConstExprValue *const_val, Buf *str) { auto entry = g->string_literals_table.maybe_get(str); if (entry != nullptr) { - *const_val = *entry->value; + memcpy(const_val, entry->value, sizeof(ConstExprValue)); return; } diff --git a/src/codegen.cpp b/src/codegen.cpp index dc2a4f55df..8f3a8df451 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -6676,7 +6676,7 @@ static void do_code_gen(CodeGen *g) { zig_panic("TODO debug info for var with ptr casted value"); } ZigType *var_type = g->builtin_types.entry_f128; - ConstExprValue coerced_value; + ConstExprValue coerced_value = {}; coerced_value.special = ConstValSpecialStatic; coerced_value.type = var_type; coerced_value.data.x_f128 = bigfloat_to_f128(&const_val->data.x_bigfloat); diff --git a/src/ir.cpp b/src/ir.cpp index 83199fc0cc..3d125da1a1 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10624,13 +10624,16 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT static void copy_const_val(ConstExprValue *dest, ConstExprValue *src, bool same_global_refs) { ConstGlobalRefs *global_refs = dest->global_refs; - assert(!same_global_refs || src->global_refs != nullptr); - *dest = *src; + memcpy(dest, src, sizeof(ConstExprValue)); if (!same_global_refs) { dest->global_refs = global_refs; + if (src->special == ConstValSpecialUndef) + return; if (dest->type->id == ZigTypeIdStruct) { - dest->data.x_struct.fields = allocate_nonzero(dest->type->data.structure.src_field_count); - memcpy(dest->data.x_struct.fields, src->data.x_struct.fields, sizeof(ConstExprValue) * dest->type->data.structure.src_field_count); + dest->data.x_struct.fields = create_const_vals(dest->type->data.structure.src_field_count); + for (size_t i = 0; i < dest->type->data.structure.src_field_count; i += 1) { + copy_const_val(&dest->data.x_struct.fields[i], &src->data.x_struct.fields[i], false); + } } } } @@ -13579,7 +13582,7 @@ static ErrorMsg *ir_eval_math_op_scalar(IrAnalyze *ira, IrInstruction *source_in } } else { float_div_trunc(out_val, op1_val, op2_val); - ConstExprValue remainder; + ConstExprValue remainder = {}; float_rem(&remainder, op1_val, op2_val); if (float_cmp_zero(&remainder) != CmpEQ) { return ir_add_error(ira, source_instr, buf_sprintf("exact division had a remainder")); @@ -13954,8 +13957,8 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp // have a remainder function ambiguity problem ok = true; } else { - ConstExprValue rem_result; - ConstExprValue mod_result; + ConstExprValue rem_result = {}; + ConstExprValue mod_result = {}; float_rem(&rem_result, op1_val, op2_val); float_mod(&mod_result, op1_val, op2_val); ok = float_cmp(&rem_result, &mod_result) == CmpEQ; @@ -14178,10 +14181,12 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i size_t next_index = 0; for (size_t i = op1_array_index; i < op1_array_end; i += 1, next_index += 1) { - out_array_val->data.x_array.data.s_none.elements[next_index] = op1_array_val->data.x_array.data.s_none.elements[i]; + copy_const_val(&out_array_val->data.x_array.data.s_none.elements[next_index], + &op1_array_val->data.x_array.data.s_none.elements[i], true); } for (size_t i = op2_array_index; i < op2_array_end; i += 1, next_index += 1) { - out_array_val->data.x_array.data.s_none.elements[next_index] = op2_array_val->data.x_array.data.s_none.elements[i]; + copy_const_val(&out_array_val->data.x_array.data.s_none.elements[next_index], + &op2_array_val->data.x_array.data.s_none.elements[i], true); } if (next_index < new_len) { ConstExprValue *null_byte = &out_array_val->data.x_array.data.s_none.elements[next_index]; @@ -14242,7 +14247,8 @@ static IrInstruction *ir_analyze_array_mult(IrAnalyze *ira, IrInstructionBinOp * uint64_t i = 0; for (uint64_t x = 0; x < mult_amt; x += 1) { for (uint64_t y = 0; y < old_array_len; y += 1) { - out_val->data.x_array.data.s_none.elements[i] = array_val->data.x_array.data.s_none.elements[y]; + copy_const_val(&out_val->data.x_array.data.s_none.elements[i], + &array_val->data.x_array.data.s_none.elements[y], true); i += 1; } } @@ -14382,7 +14388,12 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, if (instr_is_comptime(var_ptr) && var_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) { init_val = const_ptr_pointee(ira, ira->codegen, &var_ptr->value, decl_var_instruction->base.source_node); if (is_comptime_var) { - var->const_value = init_val; + if (var->gen_is_const) { + var->const_value = init_val; + } else { + var->const_value = create_const_vals(1); + copy_const_val(var->const_value, init_val, false); + } } } @@ -15291,7 +15302,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod arg_val = create_const_runtime(casted_arg->value.type); } if (arg_part_of_generic_id) { - generic_id->params[generic_id->param_count] = *arg_val; + copy_const_val(&generic_id->params[generic_id->param_count], arg_val, true); generic_id->param_count += 1; } @@ -15476,7 +15487,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source // * "string literal used as comptime slice is memoized" // * "comptime modification of const struct field" - except modified to avoid // ConstPtrMutComptimeVar, thus defeating the logic below. - bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar; + bool same_global_refs = ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; copy_const_val(dest_val, &value->value, same_global_refs); if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr; @@ -15877,7 +15888,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr); IrInstructionConst *const_instruction = ir_create_instruction(&ira->new_irb, impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); - const_instruction->base.value = *align_result; + copy_const_val(&const_instruction->base.value, align_result, true); uint32_t align_bytes = 0; ir_resolve_align(ira, &const_instruction->base, &align_bytes); @@ -21667,7 +21678,7 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio ConstExprValue *byte_val = &casted_byte->value; for (size_t i = start; i < end; i += 1) { - dest_elements[i] = *byte_val; + copy_const_val(&dest_elements[i], byte_val, true); } return ir_const_void(ira, &instruction->base); @@ -21835,7 +21846,7 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio // TODO check for noalias violations - this should be generalized to work for any function for (size_t i = 0; i < count; i += 1) { - dest_elements[dest_start + i] = src_elements[src_start + i]; + copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); } return ir_const_void(ira, &instruction->base); diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index ccbec6849a..77fc482ccc 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -48,7 +48,7 @@ comptime { _ = @import("behavior/enum.zig"); // TODO _ = @import("behavior/enum_with_members.zig"); _ = @import("behavior/error.zig"); // TODO - _ = @import("behavior/eval.zig"); // TODO + _ = @import("behavior/eval.zig"); _ = @import("behavior/field_parent_ptr.zig"); _ = @import("behavior/fn.zig"); _ = @import("behavior/fn_in_struct_in_comptime.zig"); diff --git a/test/stage1/behavior/eval.zig b/test/stage1/behavior/eval.zig index 62cedbc76f..97d3a269cc 100644 --- a/test/stage1/behavior/eval.zig +++ b/test/stage1/behavior/eval.zig @@ -583,14 +583,14 @@ pub const Info = struct { pub const diamond_info = Info{ .version = 0 }; -//test "comptime modification of const struct field" { -// comptime { -// var res = diamond_info; -// res.version = 1; -// expect(diamond_info.version == 0); -// expect(res.version == 1); -// } -//} +test "comptime modification of const struct field" { + comptime { + var res = diamond_info; + res.version = 1; + expect(diamond_info.version == 0); + expect(res.version == 1); + } +} test "pointer to type" { comptime { -- cgit v1.2.3 From 974db231a08731f642dbf72d716f669fed2bd2ab Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 16:16:47 -0400 Subject: fix extraneous nested union field instruction --- src/codegen.cpp | 7 ++++++- test/stage1/behavior.zig | 2 +- test/stage1/behavior/enum.zig | 32 ++++++++++++++++---------------- 3 files changed, 23 insertions(+), 18 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 8f3a8df451..bd3bae66fc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3853,6 +3853,9 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executable, IrInstructionUnionFieldPtr *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + ZigType *union_ptr_type = instruction->union_ptr->value.type; assert(union_ptr_type->id == ZigTypeIdPointer); ZigType *union_type = union_ptr_type->data.pointer.child_type; @@ -4077,6 +4080,9 @@ static LLVMValueRef ir_render_test_non_null(CodeGen *g, IrExecutable *executable static LLVMValueRef ir_render_optional_unwrap_ptr(CodeGen *g, IrExecutable *executable, IrInstructionOptionalUnwrapPtr *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + ZigType *ptr_type = instruction->base_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *maybe_type = ptr_type->data.pointer.child_type; @@ -5750,7 +5756,6 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { assert(executable->basic_block_list.length > 0); for (size_t block_i = 0; block_i < executable->basic_block_list.length; block_i += 1) { IrBasicBlock *current_block = executable->basic_block_list.at(block_i); - //assert(current_block->ref_count > 0); assert(current_block->llvm_block); LLVMPositionBuilderAtEnd(g->builder, current_block->llvm_block); for (size_t instr_i = 0; instr_i < current_block->instruction_list.length; instr_i += 1) { diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 5ad6b94f3f..0e93290cc4 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -45,7 +45,7 @@ comptime { //_ = @import("behavior/coroutine_await_struct.zig"); //_ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); - _ = @import("behavior/enum.zig"); // TODO + _ = @import("behavior/enum.zig"); _ = @import("behavior/enum_with_members.zig"); _ = @import("behavior/error.zig"); // TODO _ = @import("behavior/eval.zig"); diff --git a/test/stage1/behavior/enum.zig b/test/stage1/behavior/enum.zig index e06a075974..51f4f0e196 100644 --- a/test/stage1/behavior/enum.zig +++ b/test/stage1/behavior/enum.zig @@ -1,22 +1,22 @@ const expect = @import("std").testing.expect; const mem = @import("std").mem; -//test "enum type" { -// const foo1 = Foo{ .One = 13 }; -// const foo2 = Foo{ -// .Two = Point{ -// .x = 1234, -// .y = 5678, -// }, -// }; -// const bar = Bar.B; -// -// expect(bar == Bar.B); -// expect(@memberCount(Foo) == 3); -// expect(@memberCount(Bar) == 4); -// expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); -// expect(@sizeOf(Bar) == 1); -//} +test "enum type" { + const foo1 = Foo{ .One = 13 }; + const foo2 = Foo{ + .Two = Point{ + .x = 1234, + .y = 5678, + }, + }; + const bar = Bar.B; + + expect(bar == Bar.B); + expect(@memberCount(Foo) == 3); + expect(@memberCount(Bar) == 4); + expect(@sizeOf(Foo) == @sizeOf(FooNoVoid)); + expect(@sizeOf(Bar) == 1); +} test "enum as return value" { switch (returnAnInt(13)) { -- cgit v1.2.3 From 96931228af745b8e69c138b3b83893dafa166cfe Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 16:29:46 -0400 Subject: fix comptime test error for empty error set --- src/all_types.hpp | 1 + src/codegen.cpp | 6 ++++++ src/ir.cpp | 26 ++++++++++++++++++++------ test/stage1/behavior/error.zig | 16 ++++++++-------- 4 files changed, 35 insertions(+), 14 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index efb74e5ec3..e376c4d4e8 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -3085,6 +3085,7 @@ struct IrInstructionAlignOf { struct IrInstructionTestErrSrc { IrInstruction base; + bool resolve_err_set; IrInstruction *base_ptr; }; diff --git a/src/codegen.cpp b/src/codegen.cpp index bd3bae66fc..05bdf92555 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4913,6 +4913,9 @@ static LLVMValueRef ir_render_test_err(CodeGen *g, IrExecutable *executable, IrI static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrCode *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + ZigType *ptr_type = instruction->err_union_ptr->value.type; assert(ptr_type->id == ZigTypeIdPointer); ZigType *err_union_type = ptr_type->data.pointer.child_type; @@ -4930,6 +4933,9 @@ static LLVMValueRef ir_render_unwrap_err_code(CodeGen *g, IrExecutable *executab static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *executable, IrInstructionUnwrapErrPayload *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + bool want_safety = instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base) && g->errors_by_index.length > 1; if (!want_safety && !type_has_bits(instruction->base.value.type)) diff --git a/src/ir.cpp b/src/ir.cpp index 6dfaa168ec..6de4202c5f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -2446,10 +2446,11 @@ static IrInstruction *ir_build_align_of(IrBuilder *irb, Scope *scope, AstNode *s } static IrInstruction *ir_build_test_err_src(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *base_ptr) + IrInstruction *base_ptr, bool resolve_err_set) { IrInstructionTestErrSrc *instruction = ir_build_instruction(irb, scope, source_node); instruction->base_ptr = base_ptr; + instruction->resolve_err_set = resolve_err_set; ir_ref_instruction(base_ptr, irb->current_basic_block); @@ -3593,7 +3594,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *ret_ptr = ir_build_result_ptr(irb, scope, node, &result_loc_ret->base, return_value); - IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, ret_ptr, false); bool should_inline = ir_should_inline(irb->exec, scope); IrInstruction *is_comptime; @@ -3639,7 +3640,7 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, IrInstruction *err_union_ptr = ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr); if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr); + IrInstruction *is_err_val = ir_build_test_err_src(irb, scope, node, err_union_ptr, true); IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); @@ -5987,7 +5988,7 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n LValPtr, nullptr); if (err_val_ptr == irb->codegen->invalid_instruction) return err_val_ptr; - IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node->data.while_expr.condition, err_val_ptr, true); IrBasicBlock *after_cond_block = irb->current_basic_block; IrInstruction *void_else_result = else_node ? nullptr : ir_mark_gen(ir_build_const_void(irb, scope, node)); IrInstruction *cond_br_inst; @@ -6771,7 +6772,7 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * return err_val_ptr; IrInstruction *err_val = ir_build_load_ptr(irb, scope, node, err_val_ptr); - IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr); + IrInstruction *is_err = ir_build_test_err_src(irb, scope, node, err_val_ptr, true); IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk"); IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse"); @@ -7381,7 +7382,7 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode if (err_union_ptr == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; - IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr); + IrInstruction *is_err = ir_build_test_err_src(irb, parent_scope, node, err_union_ptr, true); IrInstruction *is_comptime; if (ir_should_inline(irb->exec, parent_scope)) { @@ -22512,6 +22513,19 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } } + if (instruction->resolve_err_set) { + ZigType *err_set_type = type_entry->data.error_union.err_set_type; + if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) { + return ira->codegen->invalid_instruction; + } + if (!type_is_global_error_set(err_set_type) && + err_set_type->data.error_set.err_count == 0) + { + assert(err_set_type->data.error_set.infer_fn == nullptr); + return ir_const_bool(ira, &instruction->base, false); + } + } + return ir_build_test_err_gen(ira, &instruction->base, value); } else if (type_entry->id == ZigTypeIdErrorSet) { return ir_const_bool(ira, &instruction->base, true); diff --git a/test/stage1/behavior/error.zig b/test/stage1/behavior/error.zig index 1f8f8b36e4..861c500751 100644 --- a/test/stage1/behavior/error.zig +++ b/test/stage1/behavior/error.zig @@ -130,10 +130,10 @@ fn testExplicitErrorSetCast(set1: Set1) void { expect(y == error.A); } -//test "comptime test error for empty error set" { -// testComptimeTestErrorEmptySet(1234); -// comptime testComptimeTestErrorEmptySet(1234); -//} +test "comptime test error for empty error set" { + testComptimeTestErrorEmptySet(1234); + comptime testComptimeTestErrorEmptySet(1234); +} const EmptyErrorSet = error{}; @@ -204,10 +204,10 @@ fn foo2(f: fn () anyerror!void) void { fn bar2() (error{}!void) {} -//test "error: Zero sized error set returned with value payload crash" { -// _ = foo3(0) catch {}; -// _ = comptime foo3(0) catch {}; -//} +test "error: Zero sized error set returned with value payload crash" { + _ = foo3(0) catch {}; + _ = comptime foo3(0) catch {}; +} const Error = error{}; fn foo3(b: usize) Error!usize { -- cgit v1.2.3 From 4ffab5b85f03f63a7e724698482f8497cacc7212 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 18:47:02 -0400 Subject: fix optional pointer to size zero struct --- src/codegen.cpp | 15 ++++++++++++--- src/ir.cpp | 15 ++++++++++----- test/stage1/behavior.zig | 4 ++-- test/stage1/behavior/optional.zig | 10 +++++----- test/stage1/behavior/ptrcast.zig | 14 +++++++------- 5 files changed, 36 insertions(+), 22 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 05bdf92555..b55b8a1094 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -4983,7 +4983,7 @@ static LLVMValueRef ir_render_unwrap_err_payload(CodeGen *g, IrExecutable *execu } } -static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) { +static LLVMValueRef ir_render_optional_wrap(CodeGen *g, IrExecutable *executable, IrInstructionOptionalWrap *instruction) { ZigType *wanted_type = instruction->base.value.type; assert(wanted_type->id == ZigTypeIdOptional); @@ -4991,11 +4991,20 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I ZigType *child_type = wanted_type->data.maybe.child_type; if (!type_has_bits(child_type)) { - return LLVMConstInt(LLVMInt1Type(), 1, false); + LLVMValueRef result = LLVMConstAllOnes(LLVMInt1Type()); + if (instruction->result_loc != nullptr) { + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); + gen_store_untyped(g, result, result_loc, 0, false); + } + return result; } LLVMValueRef payload_val = ir_llvm_value(g, instruction->operand); if (!handle_is_ptr(wanted_type)) { + if (instruction->result_loc != nullptr) { + LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); + gen_store_untyped(g, payload_val, result_loc, 0, false); + } return payload_val; } @@ -5666,7 +5675,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdUnwrapErrPayload: return ir_render_unwrap_err_payload(g, executable, (IrInstructionUnwrapErrPayload *)instruction); case IrInstructionIdOptionalWrap: - return ir_render_maybe_wrap(g, executable, (IrInstructionOptionalWrap *)instruction); + return ir_render_optional_wrap(g, executable, (IrInstructionOptionalWrap *)instruction); case IrInstructionIdErrWrapCode: return ir_render_err_wrap_code(g, executable, (IrInstructionErrWrapCode *)instruction); case IrInstructionIdErrWrapPayload: diff --git a/src/ir.cpp b/src/ir.cpp index 356a1a8cc8..0a920c0974 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1826,7 +1826,7 @@ static IrInstruction *ir_build_optional_wrap(IrAnalyze *ira, IrInstruction *sour instruction->result_loc = result_loc; ir_ref_instruction(operand, ira->new_irb.current_basic_block); - ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -11277,10 +11277,15 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so return &const_instruction->base; } - if (result_loc == nullptr) result_loc = no_result_loc(); - IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); - if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { - return result_loc_inst; + if (result_loc == nullptr && handle_is_ptr(wanted_type)) { + result_loc = no_result_loc(); + } + IrInstruction *result_loc_inst = nullptr; + if (result_loc != nullptr) { + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { + return result_loc_inst; + } } IrInstruction *result = ir_build_optional_wrap(ira, source_instr, wanted_type, value, result_loc_inst); result->value.data.rh_maybe = RuntimeHintOptionalNonNull; diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 5824f9380f..0387f3c045 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -66,10 +66,10 @@ comptime { _ = @import("behavior/namespace_depends_on_compile_var.zig"); _ = @import("behavior/new_stack_call.zig"); _ = @import("behavior/null.zig"); - _ = @import("behavior/optional.zig"); // TODO + _ = @import("behavior/optional.zig"); _ = @import("behavior/pointers.zig"); _ = @import("behavior/popcount.zig"); - _ = @import("behavior/ptrcast.zig"); // TODO + _ = @import("behavior/ptrcast.zig"); _ = @import("behavior/pub_enum.zig"); _ = @import("behavior/ref_var_in_if_after_if_2nd_switch_prong.zig"); _ = @import("behavior/reflection.zig"); diff --git a/test/stage1/behavior/optional.zig b/test/stage1/behavior/optional.zig index 09260c4778..b33e250383 100644 --- a/test/stage1/behavior/optional.zig +++ b/test/stage1/behavior/optional.zig @@ -2,11 +2,11 @@ const expect = @import("std").testing.expect; pub const EmptyStruct = struct {}; -//test "optional pointer to size zero struct" { -// var e = EmptyStruct{}; -// var o: ?*EmptyStruct = &e; -// expect(o != null); -//} +test "optional pointer to size zero struct" { + var e = EmptyStruct{}; + var o: ?*EmptyStruct = &e; + expect(o != null); +} test "equality compare nullable pointers" { testNullPtrsEql(); diff --git a/test/stage1/behavior/ptrcast.zig b/test/stage1/behavior/ptrcast.zig index 004ae4dd83..bf92888214 100644 --- a/test/stage1/behavior/ptrcast.zig +++ b/test/stage1/behavior/ptrcast.zig @@ -59,10 +59,10 @@ test "comptime ptrcast keeps larger alignment" { } } -//test "implicit optional pointer to optional c_void pointer" { -// var buf: [4]u8 = "aoeu"; -// var x: ?[*]u8 = &buf; -// var y: ?*c_void = x; -// var z = @ptrCast(*[4]u8, y); -// expect(std.mem.eql(u8, z, "aoeu")); -//} +test "implicit optional pointer to optional c_void pointer" { + var buf: [4]u8 = "aoeu"; + var x: ?[*]u8 = &buf; + var y: ?*c_void = x; + var z = @ptrCast(*[4]u8, y); + expect(std.mem.eql(u8, z, "aoeu")); +} -- cgit v1.2.3 From 78eeb6e9aea9c280513faaa83f9df959b7ac6f59 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 19 Jun 2019 22:29:39 -0400 Subject: fix double getelementptr of runtime global --- src/codegen.cpp | 3 + src/ir.cpp | 186 +++++++++++++++------------------------- test/stage1/behavior/struct.zig | 12 +-- 3 files changed, 76 insertions(+), 125 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 6830007f32..5cb65b38f3 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3832,6 +3832,9 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executable, IrInstructionStructFieldPtr *instruction) { + if (instruction->base.value.special != ConstValSpecialRuntime) + return nullptr; + LLVMValueRef struct_ptr = ir_llvm_value(g, instruction->struct_ptr); // not necessarily a pointer. could be ZigTypeIdStruct ZigType *struct_ptr_type = instruction->struct_ptr->value.type; diff --git a/src/ir.cpp b/src/ir.cpp index b2ff8f5896..9ac83443ab 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -187,9 +187,9 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *value, ZigType *dest_type); static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, IrInstruction *value); + ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool non_null_comptime); static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime); + ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, bool non_null_comptime); static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *base_ptr, bool safety_check_on, bool initializing); static IrInstruction *ir_analyze_unwrap_error_payload(IrAnalyze *ira, IrInstruction *source_instr, @@ -10844,7 +10844,7 @@ static IrInstruction *ir_resolve_ptr_of_array_to_slice(IrAnalyze *ira, IrInstruc } if (result_loc == nullptr) result_loc = no_result_loc(); - IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -11282,7 +11282,7 @@ static IrInstruction *ir_analyze_optional_wrap(IrAnalyze *ira, IrInstruction *so } IrInstruction *result_loc_inst = nullptr; if (result_loc != nullptr) { - result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -11325,7 +11325,7 @@ static IrInstruction *ir_analyze_err_wrap_payload(IrAnalyze *ira, IrInstruction IrInstruction *result_loc_inst; if (handle_is_ptr(wanted_type)) { if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -11410,7 +11410,7 @@ static IrInstruction *ir_analyze_err_wrap_code(IrAnalyze *ira, IrInstruction *so IrInstruction *result_loc_inst; if (handle_is_ptr(wanted_type)) { if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -11483,7 +11483,7 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi IrInstruction *result_loc; if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { - result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true); + result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true, false); } else { result_loc = nullptr; } @@ -11527,7 +11527,7 @@ static IrInstruction *ir_analyze_array_to_slice(IrAnalyze *ira, IrInstruction *s if (!array_ptr) array_ptr = ir_get_ref(ira, source_instr, array, true, false); if (result_loc == nullptr) result_loc = no_result_loc(); - IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, wanted_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -12180,7 +12180,7 @@ static IrInstruction *ir_analyze_vector_to_array(IrAnalyze *ira, IrInstruction * result->value.type = array_type; return result; } - IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr, true); + IrInstruction *result_loc_inst = ir_resolve_result(ira, source_instr, result_loc, array_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -12761,7 +12761,7 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc IrInstruction *result_loc_inst; if (type_entry->data.pointer.host_int_bytes != 0 && handle_is_ptr(child_type)) { if (result_loc == nullptr) result_loc = no_result_loc(); - result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, true); + result_loc_inst = ir_resolve_result(ira, source_instruction, result_loc, child_type, nullptr, true, false); if (type_is_invalid(result_loc_inst->value.type) || instr_is_unreachable(result_loc_inst)) { return result_loc_inst; } @@ -14910,7 +14910,7 @@ static void set_up_result_loc_for_inferred_comptime(IrInstruction *ptr) { // when calling this function, at the callsite must check for result type noreturn and propagate it up static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr, - ResultLoc *result_loc, ZigType *value_type, IrInstruction *value) + ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool non_null_comptime) { Error err; if (result_loc->resolved_loc != nullptr) { @@ -14984,9 +14984,11 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe return result_loc->resolved_loc; } case ResultLocIdReturn: { - bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; - if (is_comptime) - return nullptr; + if (!non_null_comptime) { + bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; + if (is_comptime) + return nullptr; + } if (!type_has_bits(ira->explicit_return_type) || !handle_is_ptr(ira->explicit_return_type)) return nullptr; @@ -15005,6 +15007,10 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe return ira->codegen->invalid_instruction; peer_parent->skipped = is_comptime; if (peer_parent->skipped) { + if (non_null_comptime) { + return ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, + value_type, value, false, non_null_comptime); + } return nullptr; } @@ -15016,7 +15022,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe } IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, - peer_parent->resolved_type, nullptr, false); + peer_parent->resolved_type, nullptr, false, non_null_comptime); if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || parent_result_loc->value.type->id == ZigTypeIdUnreachable) { @@ -15066,7 +15072,7 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe } IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, result_bit_cast->parent, - dest_type, bitcasted_value, false); + dest_type, bitcasted_value, false, non_null_comptime); if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || parent_result_loc->value.type->id == ZigTypeIdUnreachable) { @@ -15094,10 +15100,11 @@ static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspe } static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr, - ResultLoc *result_loc_pass1, ZigType *value_type, IrInstruction *value, bool force_runtime) + ResultLoc *result_loc_pass1, ZigType *value_type, IrInstruction *value, bool force_runtime, + bool non_null_comptime) { IrInstruction *result_loc = ir_resolve_result_raw(ira, suspend_source_instr, result_loc_pass1, value_type, - value); + value, non_null_comptime); if (result_loc == nullptr || (instr_is_unreachable(result_loc) || type_is_invalid(result_loc->value.type))) return result_loc; @@ -15144,23 +15151,16 @@ static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrIn ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); if (type_is_invalid(implicit_elem_type)) return ira->codegen->invalid_instruction; - ResultLoc *old_result_loc = instruction->result_loc; - for (;;) { - IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, old_result_loc, - implicit_elem_type, nullptr, false); - if (result_loc != nullptr) - return result_loc; + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + implicit_elem_type, nullptr, false, true); + if (result_loc != nullptr) + return result_loc; - if (instruction->result_loc->id == ResultLocIdPeer) { - old_result_loc = reinterpret_cast(instruction->result_loc)->parent->parent; - continue; - } - IrInstruction *result = ir_const(ira, &instruction->base, implicit_elem_type); - result->value.special = ConstValSpecialUndef; - IrInstruction *ptr = ir_get_ref(ira, &instruction->base, result, false, false); - ptr->value.data.x_ptr.mut = ConstPtrMutComptimeVar; - return ptr; - } + IrInstruction *result = ir_const(ira, &instruction->base, implicit_elem_type); + result->value.special = ConstValSpecialUndef; + IrInstruction *ptr = ir_get_ref(ira, &instruction->base, result, false, false); + ptr->value.data.x_ptr.mut = ConstPtrMutComptimeVar; + return ptr; } static void ir_reset_result(ResultLoc *result_loc) { @@ -15500,7 +15500,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source // * "string literal used as comptime slice is memoized" // * "comptime modification of const struct field" - except modified to avoid // ConstPtrMutComptimeVar, thus defeating the logic below. - bool same_global_refs = ptr->value.data.x_ptr.mut == ConstPtrMutComptimeConst; + bool same_global_refs = ptr->value.data.x_ptr.mut != ConstPtrMutComptimeVar; copy_const_val(dest_val, &value->value, same_global_refs); if (!ira->new_irb.current_basic_block->must_be_comptime_source_instr) { ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr; @@ -15986,7 +15986,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c IrInstruction *result_loc; if (handle_is_ptr(impl_fn_type_id->return_type)) { result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, - impl_fn_type_id->return_type, nullptr, true); + impl_fn_type_id->return_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -16106,7 +16106,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c IrInstruction *result_loc; if (handle_is_ptr(return_type)) { result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, - return_type, nullptr, true); + return_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -16198,7 +16198,7 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source if (dst_size <= src_size) { if (src_size == dst_size && types_have_same_zig_comptime_repr(pointee->type, out_val->type)) { - copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut == ConstPtrMutComptimeConst); + copy_const_val(out_val, pointee, ptr_val->data.x_ptr.mut != ConstPtrMutComptimeVar); return ErrorNone; } Buf buf = BUF_INIT; @@ -16600,7 +16600,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh // In case resolving the parent activates a suspend, do it now IrInstruction *parent_result_loc = ir_resolve_result(ira, &phi_instruction->base, peer_parent->parent, - peer_parent->resolved_type, nullptr, false); + peer_parent->resolved_type, nullptr, false, false); if (parent_result_loc != nullptr && (type_is_invalid(parent_result_loc->value.type) || instr_is_unreachable(parent_result_loc))) { @@ -17246,11 +17246,10 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction field_val->special = ConstValSpecialUndef; field_val->type = struct_type->data.structure.fields[i].type_entry; ConstParent *parent = get_const_val_parent(ira->codegen, field_val); - if (parent != nullptr) { - parent->id = ConstParentIdStruct; - parent->data.p_struct.struct_val = struct_val; - parent->data.p_struct.field_index = i; - } + assert(parent != nullptr); + parent->id = ConstParentIdStruct; + parent->data.p_struct.struct_val = struct_val; + parent->data.p_struct.field_index = i; } } IrInstruction *result; @@ -17264,7 +17263,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction } ConstExprValue *const_val = &result->value; const_val->data.x_ptr.special = ConstPtrSpecialBaseStruct; - const_val->data.x_ptr.mut = struct_ptr->value.data.x_ptr.mut; + const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; const_val->data.x_ptr.data.base_struct.struct_val = struct_val; const_val->data.x_ptr.data.base_struct.field_index = field->src_index; return result; @@ -17414,6 +17413,11 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, link_lib->symbols.append(symbol_name); } +static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) { + ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); + emit_error_notes_for_ref_stack(ira->codegen, msg); + return ira->codegen->invalid_instruction; +} static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) { resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node); @@ -17428,6 +17432,9 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ { TldVar *tld_var = (TldVar *)tld; ZigVar *var = tld_var->var; + if (var == nullptr) { + return ir_error_dependency_loop(ira, source_instruction); + } if (tld_var->extern_lib_name != nullptr) { add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, source_instruction->source_node); } @@ -17443,23 +17450,13 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ if (type_is_invalid(fn_entry->type_entry)) return ira->codegen->invalid_instruction; - // TODO instead of allocating this every time, put it in the tld value and we can reference - // the same one every time - ConstExprValue *const_val = create_const_vals(1); - const_val->special = ConstValSpecialStatic; - const_val->type = fn_entry->type_entry; - const_val->data.x_ptr.data.fn.fn_entry = fn_entry; - const_val->data.x_ptr.special = ConstPtrSpecialFunction; - const_val->data.x_ptr.mut = ConstPtrMutComptimeConst; - if (tld_fn->extern_lib_name != nullptr) { add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, source_instruction->source_node); } - bool ptr_is_const = true; - bool ptr_is_volatile = false; - return ir_get_const_ptr(ira, source_instruction, const_val, fn_entry->type_entry, - ConstPtrMutComptimeConst, ptr_is_const, ptr_is_volatile, 0); + IrInstruction *fn_inst = ir_create_const_fn(&ira->new_irb, source_instruction->scope, + source_instruction->source_node, fn_entry); + return ir_get_ref(ira, source_instruction, fn_inst, true, false); } } zig_unreachable(); @@ -19673,12 +19670,6 @@ static IrInstruction *ir_analyze_instruction_bit_offset_of(IrAnalyze *ira, return ir_const_unsigned(ira, &instruction->base, bit_offset); } -static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) { - ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); - emit_error_notes_for_ref_stack(ira->codegen, msg); - return ira->codegen->invalid_instruction; -} - static void ensure_field_index(ZigType *type, const char *field_name, size_t index) { Buf *field_name_buf; @@ -21088,7 +21079,7 @@ static IrInstruction *ir_analyze_instruction_cmpxchg(IrAnalyze *ira, IrInstructi IrInstruction *result_loc; if (handle_is_ptr(result_type)) { result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - result_type, nullptr, true); + result_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -21345,7 +21336,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru } IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - dest_slice_type, nullptr, true); + dest_slice_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -21422,7 +21413,7 @@ static IrInstruction *ir_analyze_instruction_to_bytes(IrAnalyze *ira, IrInstruct } IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - dest_slice_type, nullptr, true); + dest_slice_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -22164,7 +22155,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction } IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - return_type, nullptr, true); + return_type, nullptr, true, false); if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { return result_loc; } @@ -23729,58 +23720,15 @@ static IrInstruction *ir_analyze_instruction_int_to_ptr(IrAnalyze *ira, IrInstru static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, IrInstructionDeclRef *instruction) { - Tld *tld = instruction->tld; - LVal lval = instruction->lval; - - resolve_top_level_decl(ira->codegen, tld, instruction->base.source_node); - if (tld->resolution == TldResolutionInvalid) + IrInstruction *ref_instruction = ir_analyze_decl_ref(ira, &instruction->base, instruction->tld); + if (type_is_invalid(ref_instruction->value.type)) return ira->codegen->invalid_instruction; - switch (tld->id) { - case TldIdContainer: - case TldIdCompTime: - zig_unreachable(); - case TldIdVar: { - TldVar *tld_var = (TldVar *)tld; - ZigVar *var = tld_var->var; - - if (var == nullptr) { - return ir_error_dependency_loop(ira, &instruction->base); - } - - IrInstruction *var_ptr = ir_get_var_ptr(ira, &instruction->base, var); - if (type_is_invalid(var_ptr->value.type)) - return ira->codegen->invalid_instruction; - - if (tld_var->extern_lib_name != nullptr) { - add_link_lib_symbol(ira, tld_var->extern_lib_name, &var->name, instruction->base.source_node); - } - - if (lval == LValPtr) { - return var_ptr; - } else { - return ir_get_deref(ira, &instruction->base, var_ptr, nullptr); - } - } - case TldIdFn: { - TldFn *tld_fn = (TldFn *)tld; - ZigFn *fn_entry = tld_fn->fn_entry; - ir_assert(fn_entry->type_entry, &instruction->base); - - if (tld_fn->extern_lib_name != nullptr) { - add_link_lib_symbol(ira, tld_fn->extern_lib_name, &fn_entry->symbol_name, instruction->base.source_node); - } - - IrInstruction *ref_instruction = ir_create_const_fn(&ira->new_irb, instruction->base.scope, - instruction->base.source_node, fn_entry); - if (lval == LValPtr) { - return ir_get_ref(ira, &instruction->base, ref_instruction, true, false); - } else { - return ref_instruction; - } - } + if (instruction->lval == LValPtr) { + return ref_instruction; + } else { + return ir_get_deref(ira, &instruction->base, ref_instruction, nullptr); } - zig_unreachable(); } static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstructionPtrToInt *instruction) { @@ -24655,7 +24603,7 @@ static IrInstruction *ir_analyze_instruction_end_expr(IrAnalyze *ira, IrInstruct bool was_written = instruction->result_loc->written; IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, - value->value.type, value, false); + value->value.type, value, false, false); if (result_loc != nullptr) { if (type_is_invalid(result_loc->value.type)) return ira->codegen->invalid_instruction; @@ -24684,7 +24632,7 @@ static IrInstruction *ir_analyze_instruction_bit_cast_src(IrAnalyze *ira, IrInst return operand; IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, - &instruction->result_loc_bit_cast->base, operand->value.type, operand, false); + &instruction->result_loc_bit_cast->base, operand->value.type, operand, false, false); if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) return result_loc; diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index a08dec5359..ccdff3503e 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -522,12 +522,12 @@ const S0 = struct { } }; -//var g_foo: S0 = S0.init(); -// -//test "access to global struct fields" { -// g_foo.bar.value = 42; -// expect(g_foo.bar.value == 42); -//} +var g_foo: S0 = S0.init(); + +test "access to global struct fields" { + g_foo.bar.value = 42; + expect(g_foo.bar.value == 42); +} //test "packed struct with fp fields" { // const S = packed struct { -- cgit v1.2.3 From 237233b04bdbbb82a5ce881a074fdd4ca55fe58f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 20 Jun 2019 18:15:27 -0400 Subject: fix coroutines --- src/codegen.cpp | 2 +- src/ir.cpp | 8 +++++++- test/stage1/behavior.zig | 6 +++--- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 5cb65b38f3..79c92964f6 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3755,7 +3755,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id); bool is_var_args = fn_type_id->is_var_args; ZigList gen_param_values = {}; - LLVMValueRef result_loc = first_arg_ret ? ir_llvm_value(g, instruction->result_loc) : nullptr; + LLVMValueRef result_loc = (first_arg_ret || instruction->is_async) ? ir_llvm_value(g, instruction->result_loc) : nullptr; if (first_arg_ret) { gen_param_values.append(result_loc); } diff --git a/src/ir.cpp b/src/ir.cpp index 4dbc20cf48..c3ed14770f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -15252,8 +15252,14 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc ZigType *promise_type = get_promise_type(ira->codegen, return_type); ZigType *async_return_type = get_error_union_type(ira->codegen, alloc_fn_error_set_type, promise_type); + IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, no_result_loc(), + async_return_type, nullptr, true, true); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + return ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, - casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, nullptr, + casted_args, FnInlineAuto, true, async_allocator_inst, nullptr, result_loc, async_return_type); } diff --git a/test/stage1/behavior.zig b/test/stage1/behavior.zig index 8fcd9b86b8..f477bb64ed 100644 --- a/test/stage1/behavior.zig +++ b/test/stage1/behavior.zig @@ -39,11 +39,11 @@ comptime { _ = @import("behavior/bugs/828.zig"); _ = @import("behavior/bugs/920.zig"); _ = @import("behavior/byval_arg_var.zig"); - //_ = @import("behavior/cancel.zig"); + _ = @import("behavior/cancel.zig"); _ = @import("behavior/cast.zig"); _ = @import("behavior/const_slice_child.zig"); - //_ = @import("behavior/coroutine_await_struct.zig"); - //_ = @import("behavior/coroutines.zig"); + _ = @import("behavior/coroutine_await_struct.zig"); + _ = @import("behavior/coroutines.zig"); _ = @import("behavior/defer.zig"); _ = @import("behavior/enum.zig"); _ = @import("behavior/enum_with_members.zig"); -- cgit v1.2.3 From 142e77abbb8a88c2c6473921d0c600faf3d34a62 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 21 Jun 2019 14:44:49 -0400 Subject: fix extern functions returning byval structs --- src/codegen.cpp | 48 +++++++++++++++++++++++++---------------- test/stage1/behavior/struct.zig | 21 ++++++++++++++++++ 2 files changed, 50 insertions(+), 19 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 79c92964f6..5b7169f312 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2394,24 +2394,31 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut } static LLVMValueRef ir_render_return(CodeGen *g, IrExecutable *executable, IrInstructionReturn *return_instruction) { - if (return_instruction->value == nullptr) { - LLVMBuildRetVoid(g->builder); - return nullptr; - } - - ZigType *return_type = return_instruction->value->value.type; - if (want_first_arg_sret(g, &g->cur_fn->type_entry->data.fn.fn_type_id)) { + if (return_instruction->value == nullptr) { + LLVMBuildRetVoid(g->builder); + return nullptr; + } assert(g->cur_ret_ptr); src_assert(return_instruction->value->value.special != ConstValSpecialRuntime, return_instruction->base.source_node); LLVMValueRef value = ir_llvm_value(g, return_instruction->value); + ZigType *return_type = return_instruction->value->value.type; gen_assign_raw(g, g->cur_ret_ptr, get_pointer_to_type(g, return_type, false), value); LLVMBuildRetVoid(g->builder); - } else if (handle_is_ptr(return_type)) { - LLVMValueRef value = ir_llvm_value(g, return_instruction->value); - LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); - LLVMBuildRet(g->builder, by_val_value); + } else if (g->cur_fn->type_entry->data.fn.fn_type_id.cc != CallingConventionAsync && + handle_is_ptr(g->cur_fn->type_entry->data.fn.fn_type_id.return_type)) + { + if (return_instruction->value == nullptr) { + LLVMValueRef by_val_value = gen_load_untyped(g, g->cur_ret_ptr, 0, false, ""); + LLVMBuildRet(g->builder, by_val_value); + } else { + LLVMValueRef value = ir_llvm_value(g, return_instruction->value); + LLVMValueRef by_val_value = gen_load_untyped(g, value, 0, false, ""); + LLVMBuildRet(g->builder, by_val_value); + } + } else if (return_instruction->value == nullptr) { + LLVMBuildRetVoid(g->builder); } else { LLVMValueRef value = ir_llvm_value(g, return_instruction->value); LLVMBuildRet(g->builder, value); @@ -3755,7 +3762,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr bool prefix_arg_err_ret_stack = get_prefix_arg_err_ret_stack(g, fn_type_id); bool is_var_args = fn_type_id->is_var_args; ZigList gen_param_values = {}; - LLVMValueRef result_loc = (first_arg_ret || instruction->is_async) ? ir_llvm_value(g, instruction->result_loc) : nullptr; + LLVMValueRef result_loc = instruction->result_loc ? ir_llvm_value(g, instruction->result_loc) : nullptr; if (first_arg_ret) { gen_param_values.append(result_loc); } @@ -6804,20 +6811,24 @@ static void do_code_gen(CodeGen *g) { FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id; CallingConvention cc = fn_type_id->cc; bool is_c_abi = cc == CallingConventionC; + bool want_sret = want_first_arg_sret(g, fn_type_id); LLVMValueRef fn = fn_llvm_value(g, fn_table_entry); g->cur_fn = fn_table_entry; g->cur_fn_val = fn; - ZigType *return_type = fn_type_id->return_type; - if (handle_is_ptr(return_type)) { + + build_all_basic_blocks(g, fn_table_entry); + clear_debug_source_node(g); + + if (want_sret) { g->cur_ret_ptr = LLVMGetParam(fn, 0); + } else if (handle_is_ptr(fn_type_id->return_type)) { + g->cur_ret_ptr = build_alloca(g, fn_type_id->return_type, "result", 0); + // TODO add debug info variable for this } else { g->cur_ret_ptr = nullptr; } - build_all_basic_blocks(g, fn_table_entry); - clear_debug_source_node(g); - uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry); bool have_err_ret_trace_arg = err_ret_trace_arg_index != UINT32_MAX; if (have_err_ret_trace_arg) { @@ -6863,8 +6874,7 @@ static void do_code_gen(CodeGen *g) { } ZigType *import = get_scope_import(&fn_table_entry->fndef_scope->base); - - unsigned gen_i_init = want_first_arg_sret(g, fn_type_id) ? 1 : 0; + unsigned gen_i_init = want_sret ? 1 : 0; // create debug variable declarations for variables and allocate all local variables FnWalk fn_walk_var = {}; diff --git a/test/stage1/behavior/struct.zig b/test/stage1/behavior/struct.zig index 0ebd0654d0..b86b171daf 100644 --- a/test/stage1/behavior/struct.zig +++ b/test/stage1/behavior/struct.zig @@ -578,3 +578,24 @@ test "default struct initialization fields" { }; expectEqual(1239, x.a + x.b); } + +test "extern fn returns struct by value" { + const S = struct { + fn entry() void { + var x = makeBar(10); + expectEqual(i32(10), x.handle); + } + + const ExternBar = extern struct { + handle: i32, + }; + + extern fn makeBar(t: i32) ExternBar { + return ExternBar{ + .handle = t, + }; + } + }; + S.entry(); + comptime S.entry(); +} -- cgit v1.2.3 From 86f362ce8e878188d40393e6f2feba0c60ddbcf0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 22 Jun 2019 16:18:42 -0400 Subject: elide redundant safety check when switching on tagged unions --- src/all_types.hpp | 1 + src/codegen.cpp | 2 +- src/ir.cpp | 9 +++++---- std/zig/render.zig | 6 +++--- 4 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 213a64dd9d..5b75d9f96a 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -2540,6 +2540,7 @@ struct IrInstructionStructFieldPtr { struct IrInstructionUnionFieldPtr { IrInstruction base; + bool safety_check_on; bool initializing; IrInstruction *union_ptr; TypeUnionField *field; diff --git a/src/codegen.cpp b/src/codegen.cpp index 5b7169f312..4eea729dd9 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3890,7 +3890,7 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), &field->enum_field->value); gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); - } else if (ir_want_runtime_safety(g, &instruction->base)) { + } else if (instruction->safety_check_on && ir_want_runtime_safety(g, &instruction->base)) { LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, union_type->data.unionation.gen_tag_index, ""); LLVMValueRef tag_value = gen_load_untyped(g, tag_field_ptr, 0, false, ""); diff --git a/src/ir.cpp b/src/ir.cpp index e943788f97..823ddb13a3 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -1384,10 +1384,11 @@ static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, As } static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *union_ptr, TypeUnionField *field, bool initializing) + IrInstruction *union_ptr, TypeUnionField *field, bool safety_check_on, bool initializing) { IrInstructionUnionFieldPtr *instruction = ir_build_instruction(irb, scope, source_node); instruction->initializing = initializing; + instruction->safety_check_on = safety_check_on; instruction->union_ptr = union_ptr; instruction->field = field; @@ -17514,7 +17515,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ IrInstruction *result; if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, - source_instr->source_node, container_ptr, field, initializing); + source_instr->source_node, container_ptr, field, true, initializing); result->value.type = ptr_type; result->value.special = ConstValSpecialStatic; } else { @@ -17529,7 +17530,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ } IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, - source_instr->source_node, container_ptr, field, initializing); + source_instr->source_node, container_ptr, field, true, initializing); result->value.type = ptr_type; return result; } @@ -19005,7 +19006,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru } IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, target_value_ptr, field, false); + instruction->base.scope, instruction->base.source_node, target_value_ptr, field, false, false); result->value.type = get_pointer_to_type(ira->codegen, field->type_entry, target_value_ptr->value.type->data.pointer.is_const); return result; diff --git a/std/zig/render.zig b/std/zig/render.zig index ef5c8f2346..2e8e4481be 100644 --- a/std/zig/render.zig +++ b/std/zig/render.zig @@ -939,10 +939,10 @@ fn renderExpression( } switch (container_decl.init_arg_expr) { - ast.Node.ContainerDecl.InitArg.None => { + .None => { try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.Space); // union }, - ast.Node.ContainerDecl.InitArg.Enum => |enum_tag_type| { + .Enum => |enum_tag_type| { try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union const lparen = tree.nextToken(container_decl.kind_token); @@ -962,7 +962,7 @@ fn renderExpression( try renderToken(tree, stream, tree.nextToken(enum_token), indent, start_col, Space.Space); // ) } }, - ast.Node.ContainerDecl.InitArg.Type => |type_expr| { + .Type => |type_expr| { try renderToken(tree, stream, container_decl.kind_token, indent, start_col, Space.None); // union const lparen = tree.nextToken(container_decl.kind_token); -- cgit v1.2.3 From 3021e5ca67acca6cf7420bc5e2400aa6965596f9 Mon Sep 17 00:00:00 2001 From: Michael Dusan Date: Mon, 24 Jun 2019 14:38:22 -0400 Subject: align (vector -> array) store to result location --- src/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 4eea729dd9..e12f89756d 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -5451,7 +5451,7 @@ static LLVMValueRef ir_render_vector_to_array(CodeGen *g, IrExecutable *executab LLVMValueRef vector = ir_llvm_value(g, instruction->vector); LLVMValueRef casted_ptr = LLVMBuildBitCast(g->builder, result_loc, LLVMPointerType(get_llvm_type(g, instruction->vector->value.type), 0), ""); - gen_store_untyped(g, vector, casted_ptr, 0, false); + gen_store_untyped(g, vector, casted_ptr, get_ptr_align(g, instruction->result_loc->value.type), false); return result_loc; } -- cgit v1.2.3 From c61e0a078cea2a6845ed7b03189409829d2cdf24 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 25 Jun 2019 11:31:38 -0400 Subject: fix union init with void payload all std lib tests passing now --- src/analyze.cpp | 14 +++----------- src/analyze.hpp | 1 - src/codegen.cpp | 14 +++++++++++++- src/ir.cpp | 18 +++++++----------- std/zig/parser_test.zig | 12 +----------- test/stage1/behavior/union.zig | 20 ++++++++++++++++++++ 6 files changed, 44 insertions(+), 35 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/analyze.cpp b/src/analyze.cpp index 85e390f2e0..d3a9376c5d 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -5001,12 +5001,9 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { field_val->type = wanted_type->data.structure.fields[i].type_entry; assert(field_val->type); init_const_undefined(g, field_val); - ConstParent *parent = get_const_val_parent(g, field_val); - if (parent != nullptr) { - parent->id = ConstParentIdStruct; - parent->data.p_struct.struct_val = const_val; - parent->data.p_struct.field_index = i; - } + field_val->parent.id = ConstParentIdStruct; + field_val->parent.data.p_struct.struct_val = const_val; + field_val->parent.data.p_struct.field_index = i; } } else { const_val->special = ConstValSpecialUndef; @@ -5842,11 +5839,6 @@ void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { zig_unreachable(); } -// Deprecated. Reference the parent field directly. -ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value) { - return &value->parent; -} - static const ZigTypeId all_type_ids[] = { ZigTypeIdMetaType, ZigTypeIdVoid, diff --git a/src/analyze.hpp b/src/analyze.hpp index 8d78ef86e2..a6ad92110e 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -180,7 +180,6 @@ void init_const_undefined(CodeGen *g, ConstExprValue *const_val); ConstExprValue *create_const_vals(size_t count); ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); -ConstParent *get_const_val_parent(CodeGen *g, ConstExprValue *value); void expand_undef_array(CodeGen *g, ConstExprValue *const_val); void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value); diff --git a/src/codegen.cpp b/src/codegen.cpp index e12f89756d..2e430a60e0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3873,8 +3873,20 @@ static LLVMValueRef ir_render_union_field_ptr(CodeGen *g, IrExecutable *executab TypeUnionField *field = instruction->field; - if (!type_has_bits(field->type_entry)) + if (!type_has_bits(field->type_entry)) { + if (union_type->data.unionation.gen_tag_index == SIZE_MAX) { + return nullptr; + } + if (instruction->initializing) { + LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); + LLVMValueRef tag_field_ptr = LLVMBuildStructGEP(g->builder, union_ptr, + union_type->data.unionation.gen_tag_index, ""); + LLVMValueRef tag_value = bigint_to_llvm_const(get_llvm_type(g, union_type->data.unionation.tag_type), + &field->enum_field->value); + gen_store_untyped(g, tag_value, tag_field_ptr, 0, false); + } return nullptr; + } LLVMValueRef union_ptr = ir_llvm_value(g, instruction->union_ptr); LLVMTypeRef field_type_ref = LLVMPointerType(get_llvm_type(g, field->type_entry), 0); diff --git a/src/ir.cpp b/src/ir.cpp index 32e3692afd..2991dd5186 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -17425,11 +17425,9 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction ConstExprValue *field_val = &struct_val->data.x_struct.fields[i]; field_val->special = ConstValSpecialUndef; field_val->type = struct_type->data.structure.fields[i].type_entry; - ConstParent *parent = get_const_val_parent(ira->codegen, field_val); - assert(parent != nullptr); - parent->id = ConstParentIdStruct; - parent->data.p_struct.struct_val = struct_val; - parent->data.p_struct.field_index = i; + field_val->parent.id = ConstParentIdStruct; + field_val->parent.data.p_struct.struct_val = struct_val; + field_val->parent.data.p_struct.field_index = i; } } IrInstruction *result; @@ -17507,11 +17505,8 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ ConstExprValue *payload_val = create_const_vals(1); payload_val->special = ConstValSpecialUndef; payload_val->type = field->type_entry; - ConstParent *parent = get_const_val_parent(ira->codegen, payload_val); - if (parent != nullptr) { - parent->id = ConstParentIdUnion; - parent->data.p_union.union_val = union_val; - } + payload_val->parent.id = ConstParentIdUnion; + payload_val->parent.data.p_union.union_val = union_val; union_val->special = ConstValSpecialStatic; bigint_init_bigint(&union_val->data.x_union.tag, &field->enum_field->value); @@ -25289,7 +25284,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdReturnPtr: case IrInstructionIdTypeOf: case IrInstructionIdStructFieldPtr: - case IrInstructionIdUnionFieldPtr: case IrInstructionIdArrayType: case IrInstructionIdPromiseType: case IrInstructionIdSliceType: @@ -25389,6 +25383,8 @@ bool ir_has_side_effects(IrInstruction *instruction) { } case IrInstructionIdUnwrapErrCode: return reinterpret_cast(instruction)->initializing; + case IrInstructionIdUnionFieldPtr: + return reinterpret_cast(instruction)->initializing; case IrInstructionIdErrWrapPayload: return reinterpret_cast(instruction)->result_loc != nullptr; case IrInstructionIdErrWrapCode: diff --git a/std/zig/parser_test.zig b/std/zig/parser_test.zig index 29b70d0a6e..a004089fec 100644 --- a/std/zig/parser_test.zig +++ b/std/zig/parser_test.zig @@ -1,4 +1,4 @@ -// TODO remove `use` keyword eventually +// TODO remove `use` keyword eventually: https://github.com/ziglang/zig/issues/2591 test "zig fmt: change use to usingnamespace" { try testTransform( \\use @import("std"); @@ -105,7 +105,6 @@ test "zig fmt: linksection" { } test "zig fmt: correctly move doc comments on struct fields" { - if (true) return error.SkipZigTest; // TODO try testTransform( \\pub const section_64 = extern struct { \\ sectname: [16]u8, /// name of this section @@ -917,7 +916,6 @@ test "zig fmt: statements with empty line between" { } test "zig fmt: ptr deref operator and unwrap optional operator" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\const a = b.*; \\const a = b.?; @@ -1020,7 +1018,6 @@ test "zig fmt: same-line comment after a statement" { } test "zig fmt: same-line comment after var decl in struct" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub const vfs_cap_data = extern struct { \\ const Data = struct {}; // when on disk. @@ -1030,7 +1027,6 @@ test "zig fmt: same-line comment after var decl in struct" { } test "zig fmt: same-line comment after field decl" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub const dirent = extern struct { \\ d_name: u8, @@ -1106,7 +1102,6 @@ test "zig fmt: line comments in struct initializer" { } test "zig fmt: first line comment in struct initializer" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub async fn acquire(self: *Self) HeldLock { \\ return HeldLock{ @@ -1120,7 +1115,6 @@ test "zig fmt: first line comment in struct initializer" { } test "zig fmt: doc comments before struct field" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub const Allocator = struct { \\ /// Allocate byte_count bytes and return them in a slice, with the @@ -1218,7 +1212,6 @@ test "zig fmt: comments before switch prong" { } test "zig fmt: comments before var decl in struct" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\pub const vfs_cap_data = extern struct { \\ // All of these are mandated as little endian @@ -1609,7 +1602,6 @@ test "zig fmt: indexing" { } test "zig fmt: struct declaration" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\const S = struct { \\ const Self = @This(); @@ -1641,7 +1633,6 @@ test "zig fmt: struct declaration" { } test "zig fmt: enum declaration" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\const E = enum { \\ Ok, @@ -1670,7 +1661,6 @@ test "zig fmt: enum declaration" { } test "zig fmt: union declaration" { - if (true) return error.SkipZigTest; // TODO try testCanonical( \\const U = union { \\ Int: u8, diff --git a/test/stage1/behavior/union.zig b/test/stage1/behavior/union.zig index 0e8e9f4eda..410b7e9615 100644 --- a/test/stage1/behavior/union.zig +++ b/test/stage1/behavior/union.zig @@ -402,3 +402,23 @@ test "comptime union field value equality" { expect(a0 != a1); expect(b0 != b1); } + +test "return union init with void payload" { + const S = struct { + fn entry() void { + expect(func().state == State.one); + } + const Outer = union(enum) { + state: State, + }; + const State = union(enum) { + one: void, + two: u32, + }; + fn func() Outer { + return Outer{ .state = State{ .one = {} }}; + } + }; + S.entry(); + comptime S.entry(); +} -- cgit v1.2.3 From 33f996bb163568c9bb10e5044ed9df53599a917f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Jun 2019 14:00:44 -0400 Subject: all tests passing on linux --- doc/langref.html.in | 2 +- src/all_types.hpp | 5 +++-- src/codegen.cpp | 4 +++- src/ir.cpp | 4 +++- std/event/lock.zig | 3 +-- 5 files changed, 11 insertions(+), 7 deletions(-) (limited to 'src/codegen.cpp') diff --git a/doc/langref.html.in b/doc/langref.html.in index a8673a3d77..92c1aeba8e 100644 --- a/doc/langref.html.in +++ b/doc/langref.html.in @@ -5096,7 +5096,7 @@ fn gimmeTheBiggerInteger(a: u64, b: u64) u64 {

For example, if we were to introduce another function to the above snippet:

- {#code_begin|test_err|values of type 'type' must be comptime known#} + {#code_begin|test_err|cannot store runtime value in type 'type'#} fn max(comptime T: type, a: T, b: T) T { return if (a > b) a else b; } diff --git a/src/all_types.hpp b/src/all_types.hpp index 5b75d9f96a..4be6f57593 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -335,8 +335,9 @@ struct ConstExprValue { RuntimeHintSlice rh_slice; } data; - ConstExprValue(const ConstExprValue &other) = delete; // plz zero initialize with {} - ConstExprValue& operator= (const ConstExprValue &other) = delete; // use copy_const_val + // uncomment these to find bugs. can't leave them uncommented because of a gcc-9 warning + //ConstExprValue(const ConstExprValue &other) = delete; // plz zero initialize with {} + //ConstExprValue& operator= (const ConstExprValue &other) = delete; // use copy_const_val }; enum ReturnKnowledge { diff --git a/src/codegen.cpp b/src/codegen.cpp index 2e430a60e0..0942c671ff 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -691,7 +691,9 @@ static ZigLLVMDIScope *get_di_scope(CodeGen *g, Scope *scope) { is_definition, scope_line, flags, is_optimized, nullptr); scope->di_scope = ZigLLVMSubprogramToScope(subprogram); - ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); + if (!g->strip_debug_symbols) { + ZigLLVMFnSetSubprogram(fn_llvm_value(g, fn_table_entry), subprogram); + } return scope->di_scope; } case ScopeIdDecls: diff --git a/src/ir.cpp b/src/ir.cpp index 794d41ce22..480493d2ce 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -10726,6 +10726,8 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT } else if (prev_inst->value.type->id == ZigTypeIdOptional) { return prev_inst->value.type; } else { + if ((err = type_resolve(ira->codegen, prev_inst->value.type, ResolveStatusSizeKnown))) + return ira->codegen->builtin_types.entry_invalid; return get_optional_type(ira->codegen, prev_inst->value.type); } } else { @@ -21547,7 +21549,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, dest_slice_type, nullptr, true, false); - if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) { return result_loc; } diff --git a/std/event/lock.zig b/std/event/lock.zig index 6e7a2bbda7..6c2b29b813 100644 --- a/std/event/lock.zig +++ b/std/event/lock.zig @@ -123,8 +123,7 @@ pub const Lock = struct { }; test "std.event.Lock" { - // https://github.com/ziglang/zig/issues/2377 - //if (true) return error.SkipZigTest; + if (builtin.single_threaded) return error.SkipZigTest; const allocator = std.heap.direct_allocator; -- cgit v1.2.3 From 517bdea7549453d958c31cf2af5dc298ea5508a9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Jun 2019 16:27:24 -0400 Subject: fix incorrectly omitting variable declarations in non-debug modes --- src/codegen.cpp | 3 --- 1 file changed, 3 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 7601008e16..8842e161cc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3373,9 +3373,6 @@ static LLVMValueRef ir_render_decl_var(CodeGen *g, IrExecutable *executable, IrI if (!type_has_bits(var->var_type)) return nullptr; - if (var->ref_count == 0 && g->build_mode != BuildModeDebug) - return nullptr; - var->value_ref = ir_llvm_value(g, instruction->var_ptr); gen_var_debug_decl(g, var); return nullptr; -- cgit v1.2.3 From 69c7c5de09e16e96a6ea5207ef8b3a21e9d119f9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 27 Jun 2019 19:15:33 -0400 Subject: fixups * better detection for already seen packages * "root" instead of "@root" --- src/all_types.hpp | 2 ++ src/codegen.cpp | 30 ++++++++++++++---------------- std/special/bootstrap.zig | 5 ++--- 3 files changed, 18 insertions(+), 19 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index 774a00fdb7..bb5bef04bb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1110,6 +1110,8 @@ struct ZigPackage { // reminder: hash tables must be initialized before use HashMap package_table; + + bool added_to_cache; }; // Stuff that only applies to a struct which is the implicit root struct of a file diff --git a/src/codegen.cpp b/src/codegen.cpp index 1a01e135d2..6ad779fd24 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -180,7 +180,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->root_package = new_package(".", "", ""); } - g->root_package->package_table.put(buf_create_from_str("@root"), g->root_package); + g->root_package->package_table.put(buf_create_from_str("root"), g->root_package); g->zig_std_special_dir = buf_alloc(); os_path_join(g->zig_std_dir, buf_sprintf("special"), g->zig_std_special_dir); @@ -8055,6 +8055,8 @@ static Error define_builtin_compile_vars(CodeGen *g) { g->root_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); g->std_package->package_table.put(buf_create_from_str("std"), g->std_package); + g->std_package->package_table.put(buf_create_from_str("root"), + g->is_test_build ? g->test_runner_package : g->root_package); g->compile_var_import = add_source_file(g, g->compile_var_package, builtin_zig_path, contents, SourceKindPkgMain); @@ -8522,8 +8524,10 @@ static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *ba return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain); } -static ZigPackage *create_bootstrap_pkg(CodeGen *g) { - return codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); +static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) { + ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); + package->package_table.put(buf_create_from_str("root"), pkg_with_main); + return package; } static ZigPackage *create_test_runner_pkg(CodeGen *g) { @@ -8647,12 +8651,12 @@ static void gen_root_source(CodeGen *g) { !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig"); } if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib && g->is_dynamic) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap_lib.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); } if (!g->error_during_imports) { @@ -8660,7 +8664,7 @@ static void gen_root_source(CodeGen *g) { } if (g->is_test_build) { create_test_compile_var_and_add_test_runner(g); - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig"); + g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->test_runner_package), "bootstrap.zig"); if (!g->error_during_imports) { semantic_analyze(g); @@ -9375,6 +9379,7 @@ void codegen_add_time_event(CodeGen *g, const char *name) { static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) { if (buf_len(&pkg->root_src_path) == 0) return; + pkg->added_to_cache = true; Buf *rel_full_path = buf_alloc(); os_path_join(&pkg->root_src_dir, &pkg->root_src_path, rel_full_path); @@ -9386,11 +9391,7 @@ static void add_cache_pkg(CodeGen *g, CacheHash *ch, ZigPackage *pkg) { if (!entry) break; - // TODO: I think we need a more sophisticated detection of - // packages we have already seen - if (entry->value != pkg) { - auto root = pkg->package_table.maybe_get(buf_create_from_str("@root")); - if (root != nullptr && entry->value == root->value) continue; + if (!pkg->added_to_cache) { cache_buf(ch, entry->key); add_cache_pkg(g, ch, entry->value); } @@ -9648,11 +9649,8 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c assert(g->compile_var_package != nullptr); pkg->package_table.put(buf_create_from_str("std"), g->std_package); - if (g->is_test_build) { - pkg->package_table.put(buf_create_from_str("@root"), g->test_runner_package); - } else { - pkg->package_table.put(buf_create_from_str("@root"), g->root_package); - } + ZigPackage *main_pkg = g->is_test_build ? g->test_runner_package : g->root_package; + pkg->package_table.put(buf_create_from_str("root"), main_pkg); pkg->package_table.put(buf_create_from_str("builtin"), g->compile_var_package); } diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index f1286bd659..7177f58b8a 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -1,7 +1,6 @@ -// This file is in a package which has the root source file exposed as "@root". -// It is included in the compilation unit when exporting an executable. +// This file is included in the compilation unit when exporting an executable. -const root = @import("@root"); +const root = @import("root"); const std = @import("std"); const builtin = @import("builtin"); const assert = std.debug.assert; -- cgit v1.2.3 From 4b7e04f75aef8da6d2f95977cee69cd9b3b440a5 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 28 Jun 2019 02:00:56 -0400 Subject: rename std/special/bootstrap.zig to std/special/start.zig --- CMakeLists.txt | 6 +- src/all_types.hpp | 2 +- src/codegen.cpp | 10 +-- std/special/bootstrap.zig | 146 ---------------------------------- std/special/bootstrap_lib.zig | 16 ---- std/special/bootstrap_windows_tls.zig | 36 --------- std/special/start.zig | 146 ++++++++++++++++++++++++++++++++++ std/special/start_lib.zig | 16 ++++ std/special/start_windows_tls.zig | 36 +++++++++ 9 files changed, 207 insertions(+), 207 deletions(-) delete mode 100644 std/special/bootstrap.zig delete mode 100644 std/special/bootstrap_lib.zig delete mode 100644 std/special/bootstrap_windows_tls.zig create mode 100644 std/special/start.zig create mode 100644 std/special/start_lib.zig create mode 100644 std/special/start_windows_tls.zig (limited to 'src/codegen.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d34a253a5..a2b5bfc469 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -651,9 +651,9 @@ set(ZIG_STD_FILES "rb.zig" "segmented_list.zig" "sort.zig" - "special/bootstrap.zig" - "special/bootstrap_lib.zig" - "special/bootstrap_windows_tls.zig" + "special/start.zig" + "special/start_lib.zig" + "special/start_windows_tls.zig" "special/build_runner.zig" "special/c.zig" "special/compiler_rt.zig" diff --git a/src/all_types.hpp b/src/all_types.hpp index bb5bef04bb..0dc86c4f55 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1759,7 +1759,7 @@ struct CodeGen { ZigPackage *compile_var_package; ZigType *compile_var_import; ZigType *root_import; - ZigType *bootstrap_import; + ZigType *start_import; ZigType *test_runner_import; struct { diff --git a/src/codegen.cpp b/src/codegen.cpp index 6ad779fd24..72ba3c6c99 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8524,8 +8524,8 @@ static ZigType *add_special_code(CodeGen *g, ZigPackage *package, const char *ba return add_source_file(g, package, resolved_path, import_code, SourceKindPkgMain); } -static ZigPackage *create_bootstrap_pkg(CodeGen *g, ZigPackage *pkg_with_main) { - ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "bootstrap.zig", "std.special"); +static ZigPackage *create_start_pkg(CodeGen *g, ZigPackage *pkg_with_main) { + ZigPackage *package = codegen_create_package(g, buf_ptr(g->zig_std_special_dir), "start.zig", "std.special"); package->package_table.put(buf_create_from_str("root"), pkg_with_main); return package; } @@ -8651,12 +8651,12 @@ static void gen_root_source(CodeGen *g) { !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig"); + g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start.zig"); } if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && g->out_type == OutTypeLib && g->is_dynamic) { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap_lib.zig"); + g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start_lib.zig"); } if (!g->error_during_imports) { @@ -8664,7 +8664,7 @@ static void gen_root_source(CodeGen *g) { } if (g->is_test_build) { create_test_compile_var_and_add_test_runner(g); - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->test_runner_package), "bootstrap.zig"); + g->start_import = add_special_code(g, create_start_pkg(g, g->test_runner_package), "start.zig"); if (!g->error_during_imports) { semantic_analyze(g); diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig deleted file mode 100644 index 7177f58b8a..0000000000 --- a/std/special/bootstrap.zig +++ /dev/null @@ -1,146 +0,0 @@ -// This file is included in the compilation unit when exporting an executable. - -const root = @import("root"); -const std = @import("std"); -const builtin = @import("builtin"); -const assert = std.debug.assert; - -var argc_ptr: [*]usize = undefined; - -const is_wasm = switch (builtin.arch) { - .wasm32, .wasm64 => true, - else => false, -}; - -comptime { - if (builtin.link_libc) { - @export("main", main, .Strong); - } else if (builtin.os == .windows) { - @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); - } else if (is_wasm and builtin.os == .freestanding) { - @export("_start", wasm_freestanding_start, .Strong); - } else { - @export("_start", _start, .Strong); - } -} - -extern fn wasm_freestanding_start() void { - _ = callMain(); -} - -nakedcc fn _start() noreturn { - if (builtin.os == builtin.Os.wasi) { - std.os.wasi.proc_exit(callMain()); - } - - switch (builtin.arch) { - .x86_64 => { - argc_ptr = asm ("lea (%%rsp), %[argc]" - : [argc] "=r" (-> [*]usize) - ); - }, - .i386 => { - argc_ptr = asm ("lea (%%esp), %[argc]" - : [argc] "=r" (-> [*]usize) - ); - }, - .aarch64, .aarch64_be => { - argc_ptr = asm ("mov %[argc], sp" - : [argc] "=r" (-> [*]usize) - ); - }, - else => @compileError("unsupported arch"), - } - // If LLVM inlines stack variables into _start, they will overwrite - // the command line argument data. - @noInlineCall(posixCallMainAndExit); -} - -extern fn WinMainCRTStartup() noreturn { - @setAlignStack(16); - if (!builtin.single_threaded) { - _ = @import("bootstrap_windows_tls.zig"); - } - std.os.windows.kernel32.ExitProcess(callMain()); -} - -// TODO https://github.com/ziglang/zig/issues/265 -fn posixCallMainAndExit() noreturn { - if (builtin.os == builtin.Os.freebsd) { - @setAlignStack(16); - } - const argc = argc_ptr[0]; - const argv = @ptrCast([*][*]u8, argc_ptr + 1); - - const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1); - var envp_count: usize = 0; - while (envp_optional[envp_count]) |_| : (envp_count += 1) {} - const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; - - if (builtin.os == .linux) { - // Find the beginning of the auxiliary vector - const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); - std.os.linux.elf_aux_maybe = auxv; - // Initialize the TLS area - std.os.linux.tls.initTLS(); - - if (std.os.linux.tls.tls_image) |tls_img| { - const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size); - const tp = std.os.linux.tls.copyTLS(tls_addr); - std.os.linux.tls.setThreadPointer(tp); - } - } - - std.os.exit(callMainWithArgs(argc, argv, envp)); -} - -// This is marked inline because for some reason LLVM in release mode fails to inline it, -// and we want fewer call frames in stack traces. -inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { - std.os.argv = argv[0..argc]; - std.os.environ = envp; - return callMain(); -} - -extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { - var env_count: usize = 0; - while (c_envp[env_count] != null) : (env_count += 1) {} - const envp = @ptrCast([*][*]u8, c_envp)[0..env_count]; - return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp); -} - -// This is marked inline because for some reason LLVM in release mode fails to inline it, -// and we want fewer call frames in stack traces. -inline fn callMain() u8 { - switch (@typeId(@typeOf(root.main).ReturnType)) { - .NoReturn => { - root.main(); - }, - .Void => { - root.main(); - return 0; - }, - .Int => { - if (@typeOf(root.main).ReturnType.bit_count != 8) { - @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"); - } - return root.main(); - }, - .ErrorUnion => { - root.main() catch |err| { - std.debug.warn("error: {}\n", @errorName(err)); - if (builtin.os != builtin.Os.zen) { - if (@errorReturnTrace()) |trace| { - std.debug.dumpStackTrace(trace.*); - } - } - return 1; - }; - return 0; - }, - else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"), - } -} - -const main_thread_tls_align = 32; -var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64; diff --git a/std/special/bootstrap_lib.zig b/std/special/bootstrap_lib.zig deleted file mode 100644 index 701eee389d..0000000000 --- a/std/special/bootstrap_lib.zig +++ /dev/null @@ -1,16 +0,0 @@ -// This file is included in the compilation unit when exporting a DLL on windows. - -const std = @import("std"); -const builtin = @import("builtin"); - -comptime { - @export("_DllMainCRTStartup", _DllMainCRTStartup, builtin.GlobalLinkage.Strong); -} - -stdcallcc fn _DllMainCRTStartup( - hinstDLL: std.os.windows.HINSTANCE, - fdwReason: std.os.windows.DWORD, - lpReserved: std.os.windows.LPVOID, -) std.os.windows.BOOL { - return std.os.windows.TRUE; -} diff --git a/std/special/bootstrap_windows_tls.zig b/std/special/bootstrap_windows_tls.zig deleted file mode 100644 index 71165d355b..0000000000 --- a/std/special/bootstrap_windows_tls.zig +++ /dev/null @@ -1,36 +0,0 @@ -const std = @import("std"); - -export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; -export var _tls_start: u8 linksection(".tls") = 0; -export var _tls_end: u8 linksection(".tls$ZZZ") = 0; -export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; -export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; - -// TODO this is how I would like it to be expressed -// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate -// why they do that. -//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY { -// .StartAddressOfRawData = @ptrToInt(&_tls_start), -// .EndAddressOfRawData = @ptrToInt(&_tls_end), -// .AddressOfIndex = @ptrToInt(&_tls_index), -// .AddressOfCallBacks = @ptrToInt(__xl_a), -// .SizeOfZeroFill = 0, -// .Characteristics = 0, -//}; -// This is the workaround because we can't do @ptrToInt at comptime like that. -pub const IMAGE_TLS_DIRECTORY = extern struct { - StartAddressOfRawData: *c_void, - EndAddressOfRawData: *c_void, - AddressOfIndex: *c_void, - AddressOfCallBacks: *c_void, - SizeOfZeroFill: u32, - Characteristics: u32, -}; -export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ - .StartAddressOfRawData = &_tls_start, - .EndAddressOfRawData = &_tls_end, - .AddressOfIndex = &_tls_index, - .AddressOfCallBacks = &__xl_a, - .SizeOfZeroFill = 0, - .Characteristics = 0, -}; diff --git a/std/special/start.zig b/std/special/start.zig new file mode 100644 index 0000000000..45348feab0 --- /dev/null +++ b/std/special/start.zig @@ -0,0 +1,146 @@ +// This file is included in the compilation unit when exporting an executable. + +const root = @import("root"); +const std = @import("std"); +const builtin = @import("builtin"); +const assert = std.debug.assert; + +var argc_ptr: [*]usize = undefined; + +const is_wasm = switch (builtin.arch) { + .wasm32, .wasm64 => true, + else => false, +}; + +comptime { + if (builtin.link_libc) { + @export("main", main, .Strong); + } else if (builtin.os == .windows) { + @export("WinMainCRTStartup", WinMainCRTStartup, .Strong); + } else if (is_wasm and builtin.os == .freestanding) { + @export("_start", wasm_freestanding_start, .Strong); + } else { + @export("_start", _start, .Strong); + } +} + +extern fn wasm_freestanding_start() void { + _ = callMain(); +} + +nakedcc fn _start() noreturn { + if (builtin.os == builtin.Os.wasi) { + std.os.wasi.proc_exit(callMain()); + } + + switch (builtin.arch) { + .x86_64 => { + argc_ptr = asm ("lea (%%rsp), %[argc]" + : [argc] "=r" (-> [*]usize) + ); + }, + .i386 => { + argc_ptr = asm ("lea (%%esp), %[argc]" + : [argc] "=r" (-> [*]usize) + ); + }, + .aarch64, .aarch64_be => { + argc_ptr = asm ("mov %[argc], sp" + : [argc] "=r" (-> [*]usize) + ); + }, + else => @compileError("unsupported arch"), + } + // If LLVM inlines stack variables into _start, they will overwrite + // the command line argument data. + @noInlineCall(posixCallMainAndExit); +} + +extern fn WinMainCRTStartup() noreturn { + @setAlignStack(16); + if (!builtin.single_threaded) { + _ = @import("start_windows_tls.zig"); + } + std.os.windows.kernel32.ExitProcess(callMain()); +} + +// TODO https://github.com/ziglang/zig/issues/265 +fn posixCallMainAndExit() noreturn { + if (builtin.os == builtin.Os.freebsd) { + @setAlignStack(16); + } + const argc = argc_ptr[0]; + const argv = @ptrCast([*][*]u8, argc_ptr + 1); + + const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1); + var envp_count: usize = 0; + while (envp_optional[envp_count]) |_| : (envp_count += 1) {} + const envp = @ptrCast([*][*]u8, envp_optional)[0..envp_count]; + + if (builtin.os == .linux) { + // Find the beginning of the auxiliary vector + const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); + std.os.linux.elf_aux_maybe = auxv; + // Initialize the TLS area + std.os.linux.tls.initTLS(); + + if (std.os.linux.tls.tls_image) |tls_img| { + const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size); + const tp = std.os.linux.tls.copyTLS(tls_addr); + std.os.linux.tls.setThreadPointer(tp); + } + } + + std.os.exit(callMainWithArgs(argc, argv, envp)); +} + +// This is marked inline because for some reason LLVM in release mode fails to inline it, +// and we want fewer call frames in stack traces. +inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 { + std.os.argv = argv[0..argc]; + std.os.environ = envp; + return callMain(); +} + +extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 { + var env_count: usize = 0; + while (c_envp[env_count] != null) : (env_count += 1) {} + const envp = @ptrCast([*][*]u8, c_envp)[0..env_count]; + return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp); +} + +// This is marked inline because for some reason LLVM in release mode fails to inline it, +// and we want fewer call frames in stack traces. +inline fn callMain() u8 { + switch (@typeId(@typeOf(root.main).ReturnType)) { + .NoReturn => { + root.main(); + }, + .Void => { + root.main(); + return 0; + }, + .Int => { + if (@typeOf(root.main).ReturnType.bit_count != 8) { + @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"); + } + return root.main(); + }, + .ErrorUnion => { + root.main() catch |err| { + std.debug.warn("error: {}\n", @errorName(err)); + if (builtin.os != builtin.Os.zen) { + if (@errorReturnTrace()) |trace| { + std.debug.dumpStackTrace(trace.*); + } + } + return 1; + }; + return 0; + }, + else => @compileError("expected return type of main to be 'u8', 'noreturn', 'void', or '!void'"), + } +} + +const main_thread_tls_align = 32; +var main_thread_tls_bytes: [64]u8 align(main_thread_tls_align) = [1]u8{0} ** 64; diff --git a/std/special/start_lib.zig b/std/special/start_lib.zig new file mode 100644 index 0000000000..701eee389d --- /dev/null +++ b/std/special/start_lib.zig @@ -0,0 +1,16 @@ +// This file is included in the compilation unit when exporting a DLL on windows. + +const std = @import("std"); +const builtin = @import("builtin"); + +comptime { + @export("_DllMainCRTStartup", _DllMainCRTStartup, builtin.GlobalLinkage.Strong); +} + +stdcallcc fn _DllMainCRTStartup( + hinstDLL: std.os.windows.HINSTANCE, + fdwReason: std.os.windows.DWORD, + lpReserved: std.os.windows.LPVOID, +) std.os.windows.BOOL { + return std.os.windows.TRUE; +} diff --git a/std/special/start_windows_tls.zig b/std/special/start_windows_tls.zig new file mode 100644 index 0000000000..71165d355b --- /dev/null +++ b/std/special/start_windows_tls.zig @@ -0,0 +1,36 @@ +const std = @import("std"); + +export var _tls_index: u32 = std.os.windows.TLS_OUT_OF_INDEXES; +export var _tls_start: u8 linksection(".tls") = 0; +export var _tls_end: u8 linksection(".tls$ZZZ") = 0; +export var __xl_a: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLA") = null; +export var __xl_z: std.os.windows.PIMAGE_TLS_CALLBACK linksection(".CRT$XLZ") = null; + +// TODO this is how I would like it to be expressed +// TODO also note, ReactOS has a +1 on StartAddressOfRawData and AddressOfCallBacks. Investigate +// why they do that. +//export const _tls_used linksection(".rdata$T") = std.os.windows.IMAGE_TLS_DIRECTORY { +// .StartAddressOfRawData = @ptrToInt(&_tls_start), +// .EndAddressOfRawData = @ptrToInt(&_tls_end), +// .AddressOfIndex = @ptrToInt(&_tls_index), +// .AddressOfCallBacks = @ptrToInt(__xl_a), +// .SizeOfZeroFill = 0, +// .Characteristics = 0, +//}; +// This is the workaround because we can't do @ptrToInt at comptime like that. +pub const IMAGE_TLS_DIRECTORY = extern struct { + StartAddressOfRawData: *c_void, + EndAddressOfRawData: *c_void, + AddressOfIndex: *c_void, + AddressOfCallBacks: *c_void, + SizeOfZeroFill: u32, + Characteristics: u32, +}; +export const _tls_used linksection(".rdata$T") = IMAGE_TLS_DIRECTORY{ + .StartAddressOfRawData = &_tls_start, + .EndAddressOfRawData = &_tls_end, + .AddressOfIndex = &_tls_index, + .AddressOfCallBacks = &__xl_a, + .SizeOfZeroFill = 0, + .Characteristics = 0, +}; -- cgit v1.2.3 From 7586f613d58db8f210649c890c467edce11643b9 Mon Sep 17 00:00:00 2001 From: Timon Kruiper Date: Fri, 28 Jun 2019 00:58:35 +0200 Subject: Added function-section functionality --- src-self-hosted/llvm.zig | 1 + src/all_types.hpp | 1 + src/codegen.cpp | 7 ++++--- src/link.cpp | 2 ++ src/main.cpp | 5 +++++ src/zig_llvm.cpp | 4 +++- src/zig_llvm.h | 2 +- 7 files changed, 17 insertions(+), 5 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index 5cb95682ab..149b534ea0 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -283,6 +283,7 @@ extern fn ZigLLVMTargetMachineEmitToFile( error_message: *[*]u8, is_debug: bool, is_small: bool, + function_sections: bool, ) bool; pub const BuildCall = ZigLLVMBuildCall; diff --git a/src/all_types.hpp b/src/all_types.hpp index 0dc86c4f55..3f957ddc0c 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1908,6 +1908,7 @@ struct CodeGen { bool have_pic; bool have_dynamic_link; // this is whether the final thing will be dynamically linked. see also is_dynamic bool have_stack_probing; + bool function_sections; Buf *mmacosx_version_min; Buf *mios_version_min; diff --git a/src/codegen.cpp b/src/codegen.cpp index 72ba3c6c99..ba6cab4285 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7042,7 +7042,7 @@ static void zig_llvm_emit_output(CodeGen *g) { case EmitFileTypeBinary: if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report)) + g->enable_time_report, g->function_sections)) { zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); } @@ -7058,7 +7058,7 @@ static void zig_llvm_emit_output(CodeGen *g) { case EmitFileTypeAssembly: if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report)) + g->enable_time_report, g->function_sections)) { zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg); } @@ -7068,7 +7068,7 @@ static void zig_llvm_emit_output(CodeGen *g) { case EmitFileTypeLLVMIr: if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report)) + g->enable_time_report, g->function_sections)) { zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg); } @@ -8735,6 +8735,7 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { cache_str(cache_hash, g->clang_argv[arg_i]); } + cache_bool(cache_hash, g->function_sections); *out_cache_hash = cache_hash; return ErrorNone; diff --git a/src/link.cpp b/src/link.cpp index 277dcbc5c6..401f477760 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -791,6 +791,8 @@ static Buf *build_a_raw(CodeGen *parent_gen, const char *aname, Buf *full_path, new_link_lib->provided_explicitly = parent_gen->libc_link_lib->provided_explicitly; } + child_gen->function_sections = true; + codegen_build_and_link(child_gen); return &child_gen->output_file_path; } diff --git a/src/main.cpp b/src/main.cpp index 57eeef59df..0074b0ddf8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,6 +85,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -isystem [dir] add additional search path for other .h files\n" " -mllvm [arg] forward an arg to LLVM's option processing\n" " --override-std-dir [arg] use an alternate Zig standard library\n" + " -ffunction-sections places each function in a seperate section\n" "\n" "Link Options:\n" " --bundle-compiler-rt [path] for static libraries, include compiler-rt symbols\n" @@ -450,6 +451,7 @@ int main(int argc, char **argv) { ValgrindSupport valgrind_support = ValgrindSupportAuto; WantPIC want_pic = WantPICAuto; WantStackCheck want_stack_check = WantStackCheckAuto; + bool function_sections = false; ZigList llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -688,6 +690,8 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } cur_pkg = cur_pkg->parent; + } else if (strcmp(arg, "-ffunction-sections") == 0) { + function_sections = true; } else if (i + 1 >= argc) { fprintf(stderr, "Expected another argument after %s\n", arg); return print_error_usage(arg0); @@ -1101,6 +1105,7 @@ int main(int argc, char **argv) { g->bundle_compiler_rt = bundle_compiler_rt; codegen_set_errmsg_color(g, color); g->system_linker_hack = system_linker_hack; + g->function_sections = function_sections; for (size_t i = 0; i < lib_dirs.length; i += 1) { codegen_add_lib_dir(g, lib_dirs.at(i)); diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index fe1b279cf0..bd118d936b 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -95,7 +95,7 @@ static const bool assertions_on = false; bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, - bool is_small, bool time_report) + bool is_small, bool time_report, bool function_sections) { TimePassesIsEnabled = time_report; @@ -108,6 +108,8 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM TargetMachine* target_machine = reinterpret_cast(targ_machine_ref); target_machine->setO0WantsFastISel(true); + target_machine->Options.FunctionSections = function_sections; + Module* module = unwrap(module_ref); PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder(); diff --git a/src/zig_llvm.h b/src/zig_llvm.h index d667e0423d..985933242d 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -56,7 +56,7 @@ enum ZigLLVM_EmitOutputType { ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, - bool is_small, bool time_report); + bool is_small, bool time_report, bool function_sections); ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref); -- cgit v1.2.3 From bbc0d440b86a1783c1fddc5e594f9b4067016489 Mon Sep 17 00:00:00 2001 From: Timon Kruiper Date: Mon, 1 Jul 2019 15:22:57 +0200 Subject: Added ZigLLVMCreateTargetMachine and pass function-sections flag Also added extra cache line Added the ZigLVVMCreateTargetMachine to self hosted zig code --- src-self-hosted/compilation.zig | 1 + src-self-hosted/llvm.zig | 6 ++--- src/codegen.cpp | 12 +++++---- src/zig_llvm.cpp | 60 ++++++++++++++++++++++++++++++++++++++--- src/zig_llvm.h | 6 ++++- 5 files changed, 73 insertions(+), 12 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src-self-hosted/compilation.zig b/src-self-hosted/compilation.zig index bd20442d4b..a64e52a2b6 100644 --- a/src-self-hosted/compilation.zig +++ b/src-self-hosted/compilation.zig @@ -516,6 +516,7 @@ pub const Compilation = struct { opt_level, reloc_mode, llvm.CodeModelDefault, + false // TODO: add -ffunction-sections option ) orelse return error.OutOfMemory; defer llvm.DisposeTargetMachine(comp.target_machine); diff --git a/src-self-hosted/llvm.zig b/src-self-hosted/llvm.zig index 149b534ea0..40d414e5f7 100644 --- a/src-self-hosted/llvm.zig +++ b/src-self-hosted/llvm.zig @@ -163,8 +163,8 @@ extern fn LLVMCopyStringRepOfTargetData(TD: *TargetData) ?[*]u8; pub const CreateTargetDataLayout = LLVMCreateTargetDataLayout; extern fn LLVMCreateTargetDataLayout(T: *TargetMachine) ?*TargetData; -pub const CreateTargetMachine = LLVMCreateTargetMachine; -extern fn LLVMCreateTargetMachine( +pub const CreateTargetMachine = ZigLLVMCreateTargetMachine; +extern fn ZigLLVMCreateTargetMachine( T: *Target, Triple: [*]const u8, CPU: [*]const u8, @@ -172,6 +172,7 @@ extern fn LLVMCreateTargetMachine( Level: CodeGenOptLevel, Reloc: RelocMode, CodeModel: CodeModel, + function_sections: bool, ) ?*TargetMachine; pub const GetHostCPUName = LLVMGetHostCPUName; @@ -283,7 +284,6 @@ extern fn ZigLLVMTargetMachineEmitToFile( error_message: *[*]u8, is_debug: bool, is_small: bool, - function_sections: bool, ) bool; pub const BuildCall = ZigLLVMBuildCall; diff --git a/src/codegen.cpp b/src/codegen.cpp index ba6cab4285..84e70df1c7 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7042,7 +7042,7 @@ static void zig_llvm_emit_output(CodeGen *g) { case EmitFileTypeBinary: if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), ZigLLVM_EmitBinary, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report, g->function_sections)) + g->enable_time_report)) { zig_panic("unable to write object file %s: %s", buf_ptr(output_path), err_msg); } @@ -7058,7 +7058,7 @@ static void zig_llvm_emit_output(CodeGen *g) { case EmitFileTypeAssembly: if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), ZigLLVM_EmitAssembly, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report, g->function_sections)) + g->enable_time_report)) { zig_panic("unable to write assembly file %s: %s", buf_ptr(output_path), err_msg); } @@ -7068,7 +7068,7 @@ static void zig_llvm_emit_output(CodeGen *g) { case EmitFileTypeLLVMIr: if (ZigLLVMTargetMachineEmitToFile(g->target_machine, g->module, buf_ptr(output_path), ZigLLVM_EmitLLVMIr, &err_msg, g->build_mode == BuildModeDebug, is_small, - g->enable_time_report, g->function_sections)) + g->enable_time_report)) { zig_panic("unable to write llvm-ir file %s: %s", buf_ptr(output_path), err_msg); } @@ -8130,8 +8130,9 @@ static void init(CodeGen *g) { target_specific_features = ""; } - g->target_machine = LLVMCreateTargetMachine(target_ref, buf_ptr(&g->triple_str), - target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, LLVMCodeModelDefault); + g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->triple_str), + target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, + LLVMCodeModelDefault, g->function_sections); g->target_data_ref = LLVMCreateTargetDataLayout(g->target_machine); @@ -9448,6 +9449,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_bool(ch, g->have_dynamic_link); cache_bool(ch, g->have_stack_probing); cache_bool(ch, g->is_dummy_so); + cache_bool(ch, g->function_sections); cache_buf_opt(ch, g->mmacosx_version_min); cache_buf_opt(ch, g->mios_version_min); cache_usize(ch, g->version_major); diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index bd118d936b..f8d2ccce7e 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -39,7 +39,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -93,9 +95,63 @@ static const bool assertions_on = true; static const bool assertions_on = false; #endif +LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple, + const char *CPU, const char *Features, LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc, + LLVMCodeModel CodeModel, bool function_sections) +{ + Optional RM; + switch (Reloc){ + case LLVMRelocStatic: + RM = Reloc::Static; + break; + case LLVMRelocPIC: + RM = Reloc::PIC_; + break; + case LLVMRelocDynamicNoPic: + RM = Reloc::DynamicNoPIC; + break; + case LLVMRelocROPI: + RM = Reloc::ROPI; + break; + case LLVMRelocRWPI: + RM = Reloc::RWPI; + break; + case LLVMRelocROPI_RWPI: + RM = Reloc::ROPI_RWPI; + break; + default: + break; + } + + bool JIT; + Optional CM = unwrap(CodeModel, JIT); + + CodeGenOpt::Level OL; + switch (Level) { + case LLVMCodeGenLevelNone: + OL = CodeGenOpt::None; + break; + case LLVMCodeGenLevelLess: + OL = CodeGenOpt::Less; + break; + case LLVMCodeGenLevelAggressive: + OL = CodeGenOpt::Aggressive; + break; + default: + OL = CodeGenOpt::Default; + break; + } + + TargetOptions opt; + opt.FunctionSections = function_sections; + + return reinterpret_cast(const_cast( + reinterpret_cast(T)->createTargetMachine(Triple, CPU, Features, opt, RM, CM, OL, JIT))); +} + bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, const char *filename, ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, - bool is_small, bool time_report, bool function_sections) + bool is_small, bool time_report) { TimePassesIsEnabled = time_report; @@ -108,8 +164,6 @@ bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMM TargetMachine* target_machine = reinterpret_cast(targ_machine_ref); target_machine->setO0WantsFastISel(true); - target_machine->Options.FunctionSections = function_sections; - Module* module = unwrap(module_ref); PassManagerBuilder *PMBuilder = new(std::nothrow) PassManagerBuilder(); diff --git a/src/zig_llvm.h b/src/zig_llvm.h index 985933242d..8b7b0775f7 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -56,7 +56,11 @@ enum ZigLLVM_EmitOutputType { ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, - bool is_small, bool time_report, bool function_sections); + bool is_small, bool time_report); + +ZIG_EXTERN_C LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, const char *Triple, + const char *CPU, const char *Features, LLVMCodeGenOptLevel Level, LLVMRelocMode Reloc, + LLVMCodeModel CodeModel, bool function_sections); ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref); -- cgit v1.2.3 From 704444a6e329ee3bb7a99f8b2cc6cebde18b93cd Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 2 Jul 2019 14:26:54 -0400 Subject: improved logic on whether to include start files --- src/codegen.cpp | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 72ba3c6c99..4b131cc2af 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8606,6 +8606,38 @@ static Buf *get_resolved_root_src_path(CodeGen *g) { return resolved_path; } +static bool want_startup_code(CodeGen *g) { + // Test builds get handled separately. + if (g->is_test_build) + return false; + + // start code does not handle UEFI target + if (g->zig_target->os == OsUefi) + return false; + + // WASM freestanding can still have an entry point but other freestanding targets do not. + if (g->zig_target->os == OsFreestanding && !target_is_wasm(g->zig_target)) + return false; + + // Declaring certain export functions means skipping the start code + if (g->have_c_main || g->have_winmain || g->have_winmain_crt_startup) + return false; + + // If there is a pub main in the root source file, that means we need start code. + if (g->have_pub_main) + return true; + + if (g->out_type == OutTypeExe) { + // For build-exe, we might add start code even though there is no pub main, so that the + // programmer gets the "no pub main" compile error. However if linking libc and there is + // a C source file, that might have main(). + return g->c_source_files.length == 0 || g->libc_link_lib == nullptr; + } + + // For objects and libraries, and we don't have pub main, no start code. + return false; +} + static void gen_root_source(CodeGen *g) { Buf *resolved_path = get_resolved_root_src_path(g); if (resolved_path == nullptr) @@ -8646,11 +8678,7 @@ static void gen_root_source(CodeGen *g) { } report_errors_and_maybe_exit(g); - if (!g->is_test_build && (g->zig_target->os != OsFreestanding || target_is_wasm(g->zig_target)) && - g->zig_target->os != OsUefi && - !g->have_c_main && !g->have_winmain && !g->have_winmain_crt_startup && - ((g->have_pub_main && g->out_type == OutTypeObj) || g->out_type == OutTypeExe)) - { + if (want_startup_code(g)) { g->start_import = add_special_code(g, create_start_pkg(g, g->root_package), "start.zig"); } if (g->zig_target->os == OsWindows && !g->have_dllmain_crt_startup && -- cgit v1.2.3 From b05b5649df341573c0a42de503ceb025c4129473 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 2 Jul 2019 16:10:22 -0400 Subject: print dir name on failure to write to cache dir closes #2429 --- src/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 4b131cc2af..ce7cc4d4fc 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9598,7 +9598,7 @@ void codegen_build_and_link(CodeGen *g) { fprintf(stderr, "Unable to check cache: %s is not a directory\n", buf_ptr(manifest_dir)); } else { - fprintf(stderr, "Unable to check cache: %s\n", err_str(err)); + fprintf(stderr, "Unable to check cache: %s: %s\n", buf_ptr(manifest_dir), err_str(err)); } exit(1); } -- cgit v1.2.3 From 4606baee072f832ef794d86f428a7f27d91c6a11 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 3 Jul 2019 15:46:27 -0400 Subject: add -ffunction-sections arg when building C objects the other changes in this commit are minor tidying up --- src/codegen.cpp | 6 +++++- src/zig_llvm.cpp | 5 +++-- 2 files changed, 8 insertions(+), 3 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index c6038c16c3..47e5f542e2 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8341,6 +8341,10 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa args.append("-nostdinc"); args.append("-fno-spell-checking"); + if (g->function_sections) { + args.append("-ffunction-sections"); + } + if (translate_c) { // this gives us access to preprocessing entities, presumably at // the cost of performance @@ -8765,10 +8769,10 @@ Error create_c_object_cache(CodeGen *g, CacheHash **out_cache_hash, bool verbose cache_int(cache_hash, g->build_mode); cache_bool(cache_hash, g->have_pic); cache_bool(cache_hash, want_valgrind_support(g)); + cache_bool(cache_hash, g->function_sections); for (size_t arg_i = 0; arg_i < g->clang_argv_len; arg_i += 1) { cache_str(cache_hash, g->clang_argv[arg_i]); } - cache_bool(cache_hash, g->function_sections); *out_cache_hash = cache_hash; return ErrorNone; diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index f8d2ccce7e..c51c9e1a50 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -145,8 +145,9 @@ LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, const char *Tri TargetOptions opt; opt.FunctionSections = function_sections; - return reinterpret_cast(const_cast( - reinterpret_cast(T)->createTargetMachine(Triple, CPU, Features, opt, RM, CM, OL, JIT))); + TargetMachine *TM = reinterpret_cast(T)->createTargetMachine(Triple, CPU, Features, opt, RM, CM, + OL, JIT); + return reinterpret_cast(TM); } bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machine_ref, LLVMModuleRef module_ref, -- cgit v1.2.3 From 7ccf7807b3f12428adc5d9ca0ede4e3f4ec6dbbc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 7 Jul 2019 17:06:09 -0400 Subject: ability to target any glibc version --- CMakeLists.txt | 4 + src/all_types.hpp | 4 + src/codegen.cpp | 36 ++++- src/codegen.hpp | 3 + src/compiler.cpp | 26 ++++ src/compiler.hpp | 1 + src/glibc.cpp | 410 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/glibc.hpp | 53 +++++++ src/link.cpp | 79 +++++------ src/main.cpp | 56 +++++++- src/target.cpp | 36 +++++ src/target.hpp | 9 ++ src/util.cpp | 26 ++++ src/util.hpp | 1 + 14 files changed, 691 insertions(+), 53 deletions(-) create mode 100644 src/glibc.cpp create mode 100644 src/glibc.hpp (limited to 'src/codegen.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index a174e2172b..907bcf8769 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -421,6 +421,7 @@ set(ZIG_MAIN_SRC "${CMAKE_SOURCE_DIR}/src/main.cpp") set(ZIG0_SHIM_SRC "${CMAKE_SOURCE_DIR}/src/userland.cpp") set(ZIG_SOURCES + "${CMAKE_SOURCE_DIR}/src/glibc.cpp" "${CMAKE_SOURCE_DIR}/src/analyze.cpp" "${CMAKE_SOURCE_DIR}/src/ast_render.cpp" "${CMAKE_SOURCE_DIR}/src/bigfloat.cpp" @@ -2667,6 +2668,9 @@ set(ZIG_MUSL_SRC_FILES ) set(ZIG_LIBC_FILES + "glibc/abi.txt" + "glibc/fns.txt" + "glibc/vers.txt" "glibc/bits/byteswap.h" "glibc/bits/endian.h" "glibc/bits/floatn-common.h" diff --git a/src/all_types.hpp b/src/all_types.hpp index 8e236c4593..b49ed9820b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1921,6 +1921,7 @@ struct CodeGen { Buf *zig_lib_dir; Buf *zig_std_dir; Buf *dynamic_linker_path; + Buf *version_script_path; const char **llvm_argv; size_t llvm_argv_len; @@ -3788,6 +3789,9 @@ static const size_t stack_trace_ptr_count = 32; #define NAMESPACE_SEP_CHAR '.' #define NAMESPACE_SEP_STR "." +#define CACHE_OUT_SUBDIR "o" +#define CACHE_HASH_SUBDIR "h" + enum FloatMode { FloatModeStrict, FloatModeOptimized, diff --git a/src/codegen.cpp b/src/codegen.cpp index 47e5f542e2..57be8beed1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -24,9 +24,6 @@ #include #include -#define CACHE_OUT_SUBDIR "o" -#define CACHE_HASH_SUBDIR "h" - static void init_darwin_native(CodeGen *g) { char *osx_target = getenv("MACOSX_DEPLOYMENT_TARGET"); char *ios_target = getenv("IPHONEOS_DEPLOYMENT_TARGET"); @@ -9502,6 +9499,7 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_buf(ch, &g->libc->kernel32_lib_dir); } cache_buf_opt(ch, g->dynamic_linker_path); + cache_buf_opt(ch, g->version_script_path); // gen_c_objects appends objects to g->link_objects which we want to include in the hash gen_c_objects(g); @@ -9695,3 +9693,35 @@ ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const c } return pkg; } + +CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, + ZigLibCInstallation *libc) +{ + CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type, + parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path()); + child_gen->disable_gen_h = true; + child_gen->want_stack_check = WantStackCheckDisabled; + child_gen->verbose_tokenize = parent_gen->verbose_tokenize; + child_gen->verbose_ast = parent_gen->verbose_ast; + child_gen->verbose_link = parent_gen->verbose_link; + child_gen->verbose_ir = parent_gen->verbose_ir; + child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir; + child_gen->verbose_cimport = parent_gen->verbose_cimport; + child_gen->verbose_cc = parent_gen->verbose_cc; + child_gen->llvm_argv = parent_gen->llvm_argv; + child_gen->dynamic_linker_path = parent_gen->dynamic_linker_path; + + codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); + child_gen->want_pic = parent_gen->have_pic ? WantPICEnabled : WantPICDisabled; + child_gen->valgrind_support = ValgrindSupportDisabled; + + codegen_set_errmsg_color(child_gen, parent_gen->err_color); + + codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min); + codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min); + + child_gen->enable_cache = true; + + return child_gen; +} + diff --git a/src/codegen.hpp b/src/codegen.hpp index 9a340d7205..d7cabe879e 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -20,6 +20,9 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget OutType out_type, BuildMode build_mode, Buf *zig_lib_dir, Buf *override_std_dir, ZigLibCInstallation *libc, Buf *cache_dir); +CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, + ZigLibCInstallation *libc); + void codegen_set_clang_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_llvm_argv(CodeGen *codegen, const char **args, size_t len); void codegen_set_is_test(CodeGen *codegen, bool is_test); diff --git a/src/compiler.cpp b/src/compiler.cpp index 8bfe87bfcd..5d401f1851 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -9,9 +9,13 @@ static Buf saved_stage1_path = BUF_INIT; static Buf saved_lib_dir = BUF_INIT; static Buf saved_special_dir = BUF_INIT; static Buf saved_std_dir = BUF_INIT; + static Buf saved_dynamic_linker_path = BUF_INIT; static bool searched_for_dyn_linker = false; +static Buf saved_libc_path = BUF_INIT; +static bool searched_for_libc = false; + Buf *get_stage1_cache_path(void) { if (saved_stage1_path.list.length != 0) { return &saved_stage1_path; @@ -36,6 +40,28 @@ static void detect_dynamic_linker(Buf *lib_path) { #endif } +const Buf *get_self_libc_path(void) { + for (;;) { + if (saved_libc_path.list.length != 0) { + return &saved_libc_path; + } + if (searched_for_libc) + return nullptr; + ZigList lib_paths = {}; + Error err; + if ((err = os_self_exe_shared_libs(lib_paths))) + return nullptr; + for (size_t i = 0; i < lib_paths.length; i += 1) { + Buf *lib_path = lib_paths.at(i); + if (buf_ends_with_str(lib_path, "libc.so.6")) { + buf_init_from_buf(&saved_libc_path, lib_path); + return &saved_libc_path; + } + } + searched_for_libc = true; + } +} + Buf *get_self_dynamic_linker_path(void) { for (;;) { if (saved_dynamic_linker_path.list.length != 0) { diff --git a/src/compiler.hpp b/src/compiler.hpp index 4d682ba2fa..62991570f0 100644 --- a/src/compiler.hpp +++ b/src/compiler.hpp @@ -14,6 +14,7 @@ Buf *get_stage1_cache_path(void); Error get_compiler_id(Buf **result); Buf *get_self_dynamic_linker_path(void); +Buf *get_self_libc_path(void); Buf *get_zig_lib_dir(void); Buf *get_zig_special_dir(Buf *zig_lib_dir); diff --git a/src/glibc.cpp b/src/glibc.cpp new file mode 100644 index 0000000000..a226b23a9a --- /dev/null +++ b/src/glibc.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (c) 2019 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#include "glibc.hpp" +#include "compiler.hpp" +#include "cache_hash.hpp" +#include "codegen.hpp" + +static const ZigGLibCLib glibc_libs[] = { + {"c", 6}, + {"m", 6}, + {"pthread", 0}, + {"dl", 2}, + {"rt", 1}, +}; + +Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbose) { + Error err; + + ZigGLibCAbi *glibc_abi = allocate(1); + glibc_abi->vers_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "vers.txt", buf_ptr(zig_lib_dir)); + glibc_abi->fns_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "fns.txt", buf_ptr(zig_lib_dir)); + glibc_abi->abi_txt_path = buf_sprintf("%s" OS_SEP "libc" OS_SEP "glibc" OS_SEP "abi.txt", buf_ptr(zig_lib_dir)); + glibc_abi->version_table.init(16); + + Buf *vers_txt_contents = buf_alloc(); + if ((err = os_fetch_file_path(glibc_abi->vers_txt_path, vers_txt_contents))) { + if (verbose) { + fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->vers_txt_path), err_str(err)); + } + return err; + } + Buf *fns_txt_contents = buf_alloc(); + if ((err = os_fetch_file_path(glibc_abi->fns_txt_path, fns_txt_contents))) { + if (verbose) { + fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->fns_txt_path), err_str(err)); + } + return err; + } + Buf *abi_txt_contents = buf_alloc(); + if ((err = os_fetch_file_path(glibc_abi->abi_txt_path, abi_txt_contents))) { + if (verbose) { + fprintf(stderr, "Unable to read %s: %s\n", buf_ptr(glibc_abi->abi_txt_path), err_str(err)); + } + return err; + } + + { + SplitIterator it = memSplit(buf_to_slice(vers_txt_contents), str("\n")); + for (;;) { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) break; + Buf *ver_buf = buf_create_from_slice(opt_component.value); + ZigGLibCVersion *this_ver = glibc_abi->all_versions.add_one(); + if ((err = target_parse_glibc_version(this_ver, buf_ptr(ver_buf)))) { + if (verbose) { + fprintf(stderr, "Unable to parse glibc version '%s': %s\n", buf_ptr(ver_buf), err_str(err)); + } + return err; + } + } + } + { + SplitIterator it = memSplit(buf_to_slice(fns_txt_contents), str("\n")); + for (;;) { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) break; + SplitIterator line_it = memSplit(opt_component.value, str(" ")); + Optional> opt_fn_name = SplitIterator_next(&line_it); + if (!opt_fn_name.is_some) { + if (verbose) { + fprintf(stderr, "%s: Expected function name\n", buf_ptr(glibc_abi->fns_txt_path)); + } + return ErrorInvalidFormat; + } + Optional> opt_lib_name = SplitIterator_next(&line_it); + if (!opt_lib_name.is_some) { + if (verbose) { + fprintf(stderr, "%s: Expected lib name\n", buf_ptr(glibc_abi->fns_txt_path)); + } + return ErrorInvalidFormat; + } + + Buf *this_fn_name = buf_create_from_slice(opt_fn_name.value); + Buf *this_lib_name = buf_create_from_slice(opt_lib_name.value); + glibc_abi->all_functions.append({ this_fn_name, glibc_lib_find(buf_ptr(this_lib_name)) }); + } + } + { + SplitIterator it = memSplit(buf_to_slice(abi_txt_contents), str("\n")); + ZigGLibCVerList *ver_list_base = nullptr; + for (;;) { + if (ver_list_base == nullptr) { + Optional> opt_line = SplitIterator_next_separate(&it); + if (!opt_line.is_some) break; + + ver_list_base = allocate(glibc_abi->all_functions.length); + ZigTarget *target = allocate(1); + SplitIterator line_it = memSplit(opt_line.value, str(" ")); + for (;;) { + Optional> opt_target = SplitIterator_next(&line_it); + if (!opt_target.is_some) break; + + SplitIterator component_it = memSplit(opt_target.value, str("-")); + Optional> opt_arch = SplitIterator_next(&component_it); + assert(opt_arch.is_some); + Optional> opt_os = SplitIterator_next(&component_it); + assert(opt_os.is_some); // it's always "linux" so we ignore it + Optional> opt_abi = SplitIterator_next(&component_it); + assert(opt_abi.is_some); + + + err = target_parse_archsub(&target->arch, &target->sub_arch, + (char*)opt_arch.value.ptr, opt_arch.value.len); + // there's no sub arch so we might get an error, but the arch is still populated + assert(err == ErrorNone || err == ErrorUnknownArchitecture); + + target->os = OsLinux; + + err = target_parse_abi(&target->abi, (char*)opt_abi.value.ptr, opt_abi.value.len); + assert(err == ErrorNone); + + glibc_abi->version_table.put(target, ver_list_base); + } + continue; + } + for (size_t fn_i = 0; fn_i < glibc_abi->all_functions.length; fn_i += 1) { + ZigGLibCVerList *ver_list = &ver_list_base[fn_i]; + Optional> opt_line = SplitIterator_next_separate(&it); + assert(opt_line.is_some); + + SplitIterator line_it = memSplit(opt_line.value, str(" ")); + for (;;) { + Optional> opt_ver = SplitIterator_next(&line_it); + if (!opt_ver.is_some) break; + assert(ver_list->len < 8); // increase the array len in the type + + unsigned long ver_index = strtoul(buf_ptr(buf_create_from_slice(opt_ver.value)), nullptr, 10); + assert(ver_index < 255); // use a bigger integer in the type + ver_list->versions[ver_list->len] = ver_index; + ver_list->len += 1; + } + } + ver_list_base = nullptr; + } + } + + *out_result = glibc_abi; + return ErrorNone; +} + +Error glibc_build_dummies_and_maps(CodeGen *g, const ZigGLibCAbi *glibc_abi, const ZigTarget *target, + Buf **out_dir, bool verbose) +{ + Error err; + + Buf *cache_dir = get_stage1_cache_path(); + CacheHash *cache_hash = allocate(1); + Buf *manifest_dir = buf_sprintf("%s" OS_SEP CACHE_HASH_SUBDIR, buf_ptr(cache_dir)); + cache_init(cache_hash, manifest_dir); + + Buf *compiler_id; + if ((err = get_compiler_id(&compiler_id))) { + if (verbose) { + fprintf(stderr, "unable to get compiler id: %s\n", err_str(err)); + } + return err; + } + cache_buf(cache_hash, compiler_id); + cache_int(cache_hash, target->arch); + cache_int(cache_hash, target->abi); + cache_int(cache_hash, target->glibc_version->major); + cache_int(cache_hash, target->glibc_version->minor); + cache_int(cache_hash, target->glibc_version->patch); + + Buf digest = BUF_INIT; + buf_resize(&digest, 0); + if ((err = cache_hit(cache_hash, &digest))) { + // Treat an invalid format error as a cache miss. + if (err != ErrorInvalidFormat) + return err; + } + // We should always get a cache hit because there are no + // files in the input hash. + assert(buf_len(&digest) != 0); + + Buf *dummy_dir = buf_alloc(); + os_path_join(manifest_dir, &digest, dummy_dir); + + if ((err = os_make_path(dummy_dir))) + return err; + + Buf *test_if_exists_path = buf_alloc(); + os_path_join(dummy_dir, buf_create_from_str("ok"), test_if_exists_path); + + bool hit; + if ((err = os_file_exists(test_if_exists_path, &hit))) + return err; + + // TODO this is for debugging + fprintf(stderr, "dummy so dir: %s\n", buf_ptr(dummy_dir)); + + if (hit) { + *out_dir = dummy_dir; + return ErrorNone; + } + + + ZigGLibCVerList *ver_list_base = glibc_abi->version_table.get(target); + + uint8_t target_ver_index = 0; + for (;target_ver_index < glibc_abi->all_versions.length; target_ver_index += 1) { + const ZigGLibCVersion *this_ver = &glibc_abi->all_versions.at(target_ver_index); + if (this_ver->major == target->glibc_version->major && + this_ver->minor == target->glibc_version->minor && + this_ver->patch == target->glibc_version->patch) + { + break; + } + } + if (target_ver_index == glibc_abi->all_versions.length) { + if (verbose) { + fprintf(stderr, "Unrecognized glibc version: %d.%d.%d\n", + target->glibc_version->major, + target->glibc_version->minor, + target->glibc_version->patch); + } + return ErrorUnknownABI; + } + + Buf *map_file_path = buf_sprintf("%s" OS_SEP "all.map", buf_ptr(dummy_dir)); + Buf *map_contents = buf_alloc(); + + for (uint8_t ver_i = 0; ver_i < glibc_abi->all_versions.length; ver_i += 1) { + const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_i); + if (ver->patch == 0) { + buf_appendf(map_contents, "GLIBC_%d.%d { };\n", ver->major, ver->minor); + } else { + buf_appendf(map_contents, "GLIBC_%d.%d.%d { };\n", ver->major, ver->minor, ver->patch); + } + } + + if ((err = os_write_file(map_file_path, map_contents))) { + if (verbose) { + fprintf(stderr, "unable to write %s: %s", buf_ptr(map_file_path), err_str(err)); + } + return err; + } + + + for (size_t lib_i = 0; lib_i < array_length(glibc_libs); lib_i += 1) { + const ZigGLibCLib *lib = &glibc_libs[lib_i]; + Buf *zig_file_path = buf_sprintf("%s" OS_SEP "%s.zig", buf_ptr(dummy_dir), lib->name); + Buf *zig_body = buf_alloc(); + Buf *zig_footer = buf_alloc(); + + buf_appendf(zig_body, "comptime {\n"); + buf_appendf(zig_body, " asm (\n"); + + for (size_t fn_i = 0; fn_i < glibc_abi->all_functions.length; fn_i += 1) { + const ZigGLibCFn *libc_fn = &glibc_abi->all_functions.at(fn_i); + if (libc_fn->lib != lib) continue; + ZigGLibCVerList *ver_list = &ver_list_base[fn_i]; + // Pick the default symbol version: + // - If there are no versions, don't emit it + // - Take the greatest one <= than the target one + // - If none of them is <= than the + // specified one don't pick any default version + if (ver_list->len == 0) continue; + uint8_t chosen_def_ver_index = 255; + for (uint8_t ver_i = 0; ver_i < ver_list->len; ver_i += 1) { + uint8_t ver_index = ver_list->versions[ver_i]; + if ((chosen_def_ver_index == 255 || ver_index > chosen_def_ver_index) && + target_ver_index >= ver_index) + { + chosen_def_ver_index = ver_index; + } + } + for (uint8_t ver_i = 0; ver_i < ver_list->len; ver_i += 1) { + uint8_t ver_index = ver_list->versions[ver_i]; + + Buf *stub_name; + const ZigGLibCVersion *ver = &glibc_abi->all_versions.at(ver_index); + const char *sym_name = buf_ptr(libc_fn->name); + if (ver->patch == 0) { + stub_name = buf_sprintf("%s_%d_%d", sym_name, ver->major, ver->minor); + } else { + stub_name = buf_sprintf("%s_%d_%d_%d", sym_name, ver->major, ver->minor, ver->patch); + } + + buf_appendf(zig_footer, "export fn %s() void {}\n", buf_ptr(stub_name)); + + // Default symbol version definition vs normal symbol version definition + const char *at_sign_str = (chosen_def_ver_index != 255 && + ver_index == chosen_def_ver_index) ? "@@" : "@"; + if (ver->patch == 0) { + buf_appendf(zig_body, " \\\\ .symver %s, %s%sGLIBC_%d.%d\n", + buf_ptr(stub_name), sym_name, at_sign_str, ver->major, ver->minor); + } else { + buf_appendf(zig_body, " \\\\ .symver %s, %s%sGLIBC_%d.%d.%d\n", + buf_ptr(stub_name), sym_name, at_sign_str, ver->major, ver->minor, ver->patch); + } + // Hide the stub to keep the symbol table clean + buf_appendf(zig_body, " \\\\ .hidden %s\n", buf_ptr(stub_name)); + } + } + + buf_appendf(zig_body, " );\n"); + buf_appendf(zig_body, "}\n"); + buf_append_buf(zig_body, zig_footer); + + if ((err = os_write_file(zig_file_path, zig_body))) { + if (verbose) { + fprintf(stderr, "unable to write %s: %s", buf_ptr(zig_file_path), err_str(err)); + } + return err; + } + + CodeGen *child_gen = create_child_codegen(g, zig_file_path, OutTypeLib, nullptr); + codegen_set_out_name(child_gen, buf_create_from_str(lib->name)); + codegen_set_lib_version(child_gen, lib->sover, 0, 0); + child_gen->is_dynamic = true; + child_gen->is_dummy_so = true; + child_gen->version_script_path = map_file_path; + child_gen->enable_cache = false; + child_gen->output_dir = dummy_dir; + codegen_build_and_link(child_gen); + } + + if ((err = os_write_file(test_if_exists_path, buf_alloc()))) { + if (verbose) { + fprintf(stderr, "unable to write %s: %s", buf_ptr(test_if_exists_path), err_str(err)); + } + return err; + } + *out_dir = dummy_dir; + return ErrorNone; +} + +uint32_t hash_glibc_target(const ZigTarget *x) { + return x->arch * 3250106448 + + x->os * 542534372 + + x->abi * 59162639; +} + +bool eql_glibc_target(const ZigTarget *a, const ZigTarget *b) { + return a->arch == b->arch && + a->os == b->os && + a->abi == b->abi; +} + +#ifdef ZIG_OS_LINUX +#include +#include +Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) { + Buf *self_libc_path = get_self_libc_path(); + if (self_libc_path == nullptr) { + // TODO There is still more we could do to detect the native glibc version. For example, + // we could look at the ELF file of `/usr/bin/env`, find `libc.so.6`, and then `readlink` + // to find out the glibc version. This is relevant for the static zig builds distributed + // on the download page, since the above detection based on zig's own dynamic linking + // will not work. + + return ErrorUnknownABI; + } + Buf *link_name = buf_alloc(); + buf_resize(link_name, PATH_MAX); + ssize_t amt = readlink(buf_ptr(self_libc_path), buf_ptr(link_name), buf_len(link_name)); + if (amt == -1) { + return ErrorUnknownABI; + } + buf_resize(link_name, amt); + if (!buf_starts_with_str(link_name, "libc-") || !buf_ends_with_str(link_name, ".so")) { + return ErrorUnknownABI; + } + // example: "libc-2.3.4.so" + // example: "libc-2.27.so" + buf_resize(link_name, buf_len(link_name) - 3); // chop off ".so" + glibc_ver->major = 2; + glibc_ver->minor = 0; + glibc_ver->patch = 0; + return target_parse_glibc_version(glibc_ver, buf_ptr(link_name) + 5); +} +#else +Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver) { + return ErrorUnknownABI; +} +#endif + +size_t glibc_lib_count(void) { + return array_length(glibc_libs); +} + +const ZigGLibCLib *glibc_lib_enum(size_t index) { + assert(index < array_length(glibc_libs)); + return &glibc_libs[index]; +} + +const ZigGLibCLib *glibc_lib_find(const char *name) { + for (size_t i = 0; i < array_length(glibc_libs); i += 1) { + if (strcmp(glibc_libs[i].name, name) == 0) { + return &glibc_libs[i]; + } + } + return nullptr; +} diff --git a/src/glibc.hpp b/src/glibc.hpp new file mode 100644 index 0000000000..50796197d4 --- /dev/null +++ b/src/glibc.hpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2019 Andrew Kelley + * + * This file is part of zig, which is MIT licensed. + * See http://opensource.org/licenses/MIT + */ + +#ifndef ZIG_GLIBC_HPP +#define ZIG_GLIBC_HPP + +#include "all_types.hpp" + +struct ZigGLibCLib { + const char *name; + uint8_t sover; +}; + +struct ZigGLibCFn { + Buf *name; + const ZigGLibCLib *lib; +}; + +struct ZigGLibCVerList { + uint8_t versions[8]; // 8 is just the max number, we know statically it's big enough + uint8_t len; +}; + +uint32_t hash_glibc_target(const ZigTarget *x); +bool eql_glibc_target(const ZigTarget *a, const ZigTarget *b); + +struct ZigGLibCAbi { + Buf *abi_txt_path; + Buf *vers_txt_path; + Buf *fns_txt_path; + ZigList all_versions; + ZigList all_functions; + // The value is a pointer to all_functions.length items and each item is an index + // into all_functions. + HashMap version_table; +}; + +Error glibc_load_metadata(ZigGLibCAbi **out_result, Buf *zig_lib_dir, bool verbose); +Error glibc_build_dummies_and_maps(CodeGen *codegen, const ZigGLibCAbi *glibc_abi, const ZigTarget *target, + Buf **out_dir, bool verbose); + +// returns ErrorUnknownABI when glibc is not the native libc +Error glibc_detect_native_version(ZigGLibCVersion *glibc_ver); + +size_t glibc_lib_count(void); +const ZigGLibCLib *glibc_lib_enum(size_t index); +const ZigGLibCLib *glibc_lib_find(const char *name); + +#endif diff --git a/src/link.cpp b/src/link.cpp index 401f477760..7b41f3b556 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -11,6 +11,7 @@ #include "analyze.hpp" #include "compiler.hpp" #include "install_files.h" +#include "glibc.hpp" struct LinkJob { CodeGen *codegen; @@ -19,37 +20,6 @@ struct LinkJob { HashMap rpath_table; }; -static CodeGen *create_child_codegen(CodeGen *parent_gen, Buf *root_src_path, OutType out_type, - ZigLibCInstallation *libc) -{ - CodeGen *child_gen = codegen_create(nullptr, root_src_path, parent_gen->zig_target, out_type, - parent_gen->build_mode, parent_gen->zig_lib_dir, parent_gen->zig_std_dir, libc, get_stage1_cache_path()); - child_gen->disable_gen_h = true; - child_gen->want_stack_check = WantStackCheckDisabled; - child_gen->verbose_tokenize = parent_gen->verbose_tokenize; - child_gen->verbose_ast = parent_gen->verbose_ast; - child_gen->verbose_link = parent_gen->verbose_link; - child_gen->verbose_ir = parent_gen->verbose_ir; - child_gen->verbose_llvm_ir = parent_gen->verbose_llvm_ir; - child_gen->verbose_cimport = parent_gen->verbose_cimport; - child_gen->verbose_cc = parent_gen->verbose_cc; - child_gen->llvm_argv = parent_gen->llvm_argv; - child_gen->dynamic_linker_path = parent_gen->dynamic_linker_path; - - codegen_set_strip(child_gen, parent_gen->strip_debug_symbols); - child_gen->want_pic = parent_gen->have_pic ? WantPICEnabled : WantPICDisabled; - child_gen->valgrind_support = ValgrindSupportDisabled; - - codegen_set_errmsg_color(child_gen, parent_gen->err_color); - - codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min); - codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min); - - child_gen->enable_cache = true; - - return child_gen; -} - static const char *build_libc_object(CodeGen *parent_gen, const char *name, CFile *c_file) { CodeGen *child_gen = create_child_codegen(parent_gen, nullptr, OutTypeObj, nullptr); codegen_set_out_name(child_gen, buf_create_from_str(name)); @@ -76,18 +46,6 @@ static const char *path_from_libunwind(CodeGen *g, const char *subpath) { return path_from_zig_lib(g, "libunwind", subpath); } -static const char *build_dummy_so(CodeGen *parent, const char *name, size_t major_version) { - Buf *glibc_dummy_root_src = buf_sprintf("%s" OS_SEP "libc" OS_SEP "dummy" OS_SEP "%s.zig", - buf_ptr(parent->zig_lib_dir), name); - CodeGen *child_gen = create_child_codegen(parent, glibc_dummy_root_src, OutTypeLib, nullptr); - codegen_set_out_name(child_gen, buf_create_from_str(name)); - codegen_set_lib_version(child_gen, major_version, 0, 0); - child_gen->is_dynamic = true; - child_gen->is_dummy_so = true; - codegen_build_and_link(child_gen); - return buf_ptr(&child_gen->output_file_path); -} - static const char *build_libunwind(CodeGen *parent) { CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr); codegen_set_out_name(child_gen, buf_create_from_str("unwind")); @@ -892,6 +850,30 @@ static void add_rpath(LinkJob *lj, Buf *rpath) { lj->rpath_table.put(rpath, true); } +static void add_glibc_libs(LinkJob *lj) { + Error err; + ZigGLibCAbi *glibc_abi; + if ((err = glibc_load_metadata(&glibc_abi, lj->codegen->zig_lib_dir, true))) { + fprintf(stderr, "%s\n", err_str(err)); + exit(1); + } + + Buf *artifact_dir; + if ((err = glibc_build_dummies_and_maps(lj->codegen, glibc_abi, lj->codegen->zig_target, + &artifact_dir, true))) + { + fprintf(stderr, "%s\n", err_str(err)); + exit(1); + } + + size_t lib_count = glibc_lib_count(); + for (size_t i = 0; i < lib_count; i += 1) { + const ZigGLibCLib *lib = glibc_lib_enum(i); + Buf *so_path = buf_sprintf("%s" OS_SEP "lib%s.so.%d.0.0", buf_ptr(artifact_dir), lib->name, lib->sover); + lj->args.append(buf_ptr(so_path)); + } +} + static void construct_linker_job_elf(LinkJob *lj) { CodeGen *g = lj->codegen; @@ -990,6 +972,11 @@ static void construct_linker_job_elf(LinkJob *lj) { if (is_dyn_lib) { lj->args.append("-soname"); lj->args.append(buf_ptr(soname)); + + if (g->version_script_path != nullptr) { + lj->args.append("-version-script"); + lj->args.append(buf_ptr(g->version_script_path)); + } } // .o files @@ -1053,11 +1040,7 @@ static void construct_linker_job_elf(LinkJob *lj) { } } else if (target_is_glibc(g->zig_target)) { lj->args.append(build_libunwind(g)); - lj->args.append(build_dummy_so(g, "c", 6)); - lj->args.append(build_dummy_so(g, "m", 6)); - lj->args.append(build_dummy_so(g, "pthread", 0)); - lj->args.append(build_dummy_so(g, "dl", 2)); - lj->args.append(build_dummy_so(g, "rt", 1)); + add_glibc_libs(lj); lj->args.append(get_libc_crt_file(g, "libc_nonshared.a")); } else if (target_is_musl(g->zig_target)) { lj->args.append(build_libunwind(g)); diff --git a/src/main.cpp b/src/main.cpp index 179b4fddb0..17d3d627ea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -15,6 +15,7 @@ #include "target.hpp" #include "libc_installation.hpp" #include "userland.h" +#include "glibc.hpp" #include @@ -96,6 +97,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " --forbid-library [lib] make it an error to link against lib\n" " --library-path [dir] add a directory to the library search path\n" " --linker-script [path] use a custom linker script\n" + " --version-script [path] provide a version .map file\n" " --object [obj] add object file to build\n" " -L[dir] alias for --library-path\n" " -rdynamic add all symbols to the dynamic symbol table\n" @@ -189,10 +191,33 @@ static int print_target_list(FILE *f) { for (size_t i = 0; i < libc_count; i += 1) { ZigTarget libc_target; target_libc_enum(i, &libc_target); - fprintf(f, " %s-%s-%s\n", target_arch_name(libc_target.arch), - target_os_name(libc_target.os), target_abi_name(libc_target.abi)); + bool is_native = native.arch == libc_target.arch && + native.os == libc_target.os && + native.abi == libc_target.abi; + const char *native_str = is_native ? " (native)" : ""; + fprintf(f, " %s-%s-%s%s\n", target_arch_name(libc_target.arch), + target_os_name(libc_target.os), target_abi_name(libc_target.abi), native_str); } + fprintf(f, "\nAvailable glibc versions:\n"); + ZigGLibCAbi *glibc_abi; + Error err; + if ((err = glibc_load_metadata(&glibc_abi, get_zig_lib_dir(), true))) { + return EXIT_FAILURE; + } + for (size_t i = 0; i < glibc_abi->all_versions.length; i += 1) { + ZigGLibCVersion *this_ver = &glibc_abi->all_versions.at(i); + bool is_native = native.glibc_version != nullptr && + native.glibc_version->major == this_ver->major && + native.glibc_version->minor == this_ver->minor && + native.glibc_version->patch == this_ver->patch; + const char *native_str = is_native ? " (native)" : ""; + if (this_ver->patch == 0) { + fprintf(f, " %d.%d%s\n", this_ver->major, this_ver->minor, native_str); + } else { + fprintf(f, " %d.%d.%d%s\n", this_ver->major, this_ver->minor, this_ver->patch, native_str); + } + } return EXIT_SUCCESS; } @@ -437,6 +462,8 @@ int main(int argc, char **argv) { const char *mmacosx_version_min = nullptr; const char *mios_version_min = nullptr; const char *linker_script = nullptr; + Buf *version_script = nullptr; + const char *target_glibc = nullptr; ZigList rpath_list = {0}; bool each_lib_rpath = false; ZigList objects = {0}; @@ -783,6 +810,10 @@ int main(int argc, char **argv) { frameworks.append(argv[i]); } else if (strcmp(arg, "--linker-script") == 0) { linker_script = argv[i]; + } else if (strcmp(arg, "--version-script") == 0) { + version_script = buf_create_from_str(argv[i]); + } else if (strcmp(arg, "-target-glibc") == 0) { + target_glibc = argv[i]; } else if (strcmp(arg, "-rpath") == 0) { rpath_list.append(argv[i]); } else if (strcmp(arg, "--test-filter") == 0) { @@ -904,6 +935,10 @@ int main(int argc, char **argv) { ZigTarget target; if (target_string == nullptr) { get_native_target(&target); + if (target_glibc != nullptr) { + fprintf(stderr, "-target-glibc provided but no -target parameter\n"); + return print_error_usage(arg0); + } } else { if ((err = target_parse_triple(&target, target_string))) { if (err == ErrorUnknownArchitecture && target.arch != ZigLLVM_UnknownArch) { @@ -921,6 +956,22 @@ int main(int argc, char **argv) { return print_error_usage(arg0); } } + if (target_is_glibc(&target)) { + target.glibc_version = allocate(1); + + if (target_glibc != nullptr) { + if ((err = target_parse_glibc_version(target.glibc_version, target_glibc))) { + fprintf(stderr, "invalid glibc version '%s': %s\n", target_glibc, err_str(err)); + return print_error_usage(arg0); + } + } else { + // Default cross-compiling glibc version + *target.glibc_version = {2, 17, 0}; + } + } else if (target_glibc != nullptr) { + fprintf(stderr, "'%s' is not a glibc-compatible target", target_string); + return print_error_usage(arg0); + } } if (output_dir != nullptr && enable_cache == CacheOptOn) { @@ -1074,6 +1125,7 @@ int main(int argc, char **argv) { codegen_set_is_test(g, cmd == CmdTest); g->want_single_threaded = want_single_threaded; codegen_set_linker_script(g, linker_script); + g->version_script_path = version_script; if (each_lib_rpath) codegen_set_each_lib_rpath(g, each_lib_rpath); diff --git a/src/target.cpp b/src/target.cpp index f646b33e22..eace930940 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -10,6 +10,8 @@ #include "target.hpp" #include "util.hpp" #include "os.hpp" +#include "compiler.hpp" +#include "glibc.hpp" #include @@ -466,6 +468,29 @@ const char *target_abi_name(ZigLLVM_EnvironmentType abi) { return ZigLLVMGetEnvironmentTypeName(abi); } +Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) { + glibc_ver->major = 2; + glibc_ver->minor = 0; + glibc_ver->patch = 0; + SplitIterator it = memSplit(str(text), str("GLIBC_.")); + { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) return ErrorUnknownABI; + glibc_ver->major = strtoul(buf_ptr(buf_create_from_slice(opt_component.value)), nullptr, 10); + } + { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) return ErrorNone; + glibc_ver->minor = strtoul(buf_ptr(buf_create_from_slice(opt_component.value)), nullptr, 10); + } + { + Optional> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) return ErrorNone; + glibc_ver->patch = strtoul(buf_ptr(buf_create_from_slice(opt_component.value)), nullptr, 10); + } + return ErrorNone; +} + void get_native_target(ZigTarget *target) { ZigLLVM_OSType os_type; ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os @@ -481,6 +506,17 @@ void get_native_target(ZigTarget *target) { if (target->abi == ZigLLVM_UnknownEnvironment) { target->abi = target_default_abi(target->arch, target->os); } + target->glibc_version = nullptr; +#ifdef ZIG_OS_LINUX + if (target_is_glibc(target)) { + target->glibc_version = allocate(1); + Error err; + if ((err = glibc_detect_native_version(target->glibc_version))) { + // Use a default version. + *target->glibc_version = {2, 17, 0}; + } + } +#endif } Error target_parse_archsub(ZigLLVM_ArchType *out_arch, ZigLLVM_SubArchType *out_sub, diff --git a/src/target.hpp b/src/target.hpp index 7fca430df6..99e38f1c62 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -77,12 +77,19 @@ enum TargetSubsystem { TargetSubsystemAuto }; +struct ZigGLibCVersion { + uint32_t major; // always 2 + uint32_t minor; + uint32_t patch; +}; + struct ZigTarget { ZigLLVM_ArchType arch; ZigLLVM_SubArchType sub_arch; ZigLLVM_VendorType vendor; Os os; ZigLLVM_EnvironmentType abi; + ZigGLibCVersion *glibc_version; // null means default bool is_native; }; @@ -105,6 +112,8 @@ Error target_parse_archsub(ZigLLVM_ArchType *arch, ZigLLVM_SubArchType *sub, Error target_parse_os(Os *os, const char *os_ptr, size_t os_len); Error target_parse_abi(ZigLLVM_EnvironmentType *abi, const char *abi_ptr, size_t abi_len); +Error target_parse_glibc_version(ZigGLibCVersion *out, const char *text); + size_t target_arch_count(void); ZigLLVM_ArchType target_arch_enum(size_t index); const char *target_arch_name(ZigLLVM_ArchType arch); diff --git a/src/util.cpp b/src/util.cpp index 9a6a382993..65b1fe3082 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -86,6 +86,32 @@ Optional> SplitIterator_next(SplitIterator *self) { return Optional>::some(self->buffer.slice(start, end)); } +// Ported from std/mem.zig. +// This one won't collapse multiple separators into one, so you could use it, for example, +// to parse Comma Separated Value format. +Optional> SplitIterator_next_separate(SplitIterator *self) { + // move to beginning of token + if (self->index < self->buffer.len && + SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) + { + self->index += 1; + } + size_t start = self->index; + if (start == self->buffer.len) { + return {}; + } + + // move to end of token + while (self->index < self->buffer.len && + !SplitIterator_isSplitByte(self, self->buffer.ptr[self->index])) + { + self->index += 1; + } + size_t end = self->index; + + return Optional>::some(self->buffer.slice(start, end)); +} + // Ported from std/mem.zig Slice SplitIterator_rest(SplitIterator *self) { // move to beginning of token diff --git a/src/util.hpp b/src/util.hpp index f1942dd480..6f26725135 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -314,6 +314,7 @@ struct SplitIterator { bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte); Optional< Slice > SplitIterator_next(SplitIterator *self); +Optional< Slice > SplitIterator_next_separate(SplitIterator *self); Slice SplitIterator_rest(SplitIterator *self); SplitIterator memSplit(Slice buffer, Slice split_bytes); -- cgit v1.2.3 From 56d818565015b8213f6c070236658c8796c86d0a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 7 Jul 2019 17:55:25 -0400 Subject: expose glibc version in builtin --- src/codegen.cpp | 27 +++++++++++++++++++++++++++ src/main.cpp | 4 ++++ std/build.zig | 11 ++++++++--- 3 files changed, 39 insertions(+), 3 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 57be8beed1..59d3e1f4a0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -7918,6 +7918,14 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { //assert(EndianBig == 0); //assert(EndianLittle == 1); } + { + buf_appendf(contents, + "pub const Version = struct {\n" + " major: u32,\n" + " minor: u32,\n" + " patch: u32,\n" + "};\n\n"); + } { buf_appendf(contents, "pub const SubSystem = enum {\n" @@ -7949,6 +7957,15 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { buf_appendf(contents, "pub const os = Os.%s;\n", cur_os); buf_appendf(contents, "pub const arch = %s;\n", cur_arch); buf_appendf(contents, "pub const abi = Abi.%s;\n", cur_abi); + if (g->libc_link_lib != nullptr && g->zig_target->glibc_version != nullptr) { + buf_appendf(contents, + "pub const glibc_version: ?Version = Version{.major = %d, .minor = %d, .patch = %d};\n", + g->zig_target->glibc_version->major, + g->zig_target->glibc_version->minor, + g->zig_target->glibc_version->patch); + } else { + buf_appendf(contents, "pub const glibc_version: ?Version = null;\n"); + } buf_appendf(contents, "pub const object_format = ObjectFormat.%s;\n", cur_obj_fmt); buf_appendf(contents, "pub const mode = %s;\n", build_mode_to_str(g->build_mode)); buf_appendf(contents, "pub const link_libc = %s;\n", bool_to_str(g->libc_link_lib != nullptr)); @@ -8005,6 +8022,11 @@ static Error define_builtin_compile_vars(CodeGen *g) { cache_int(&cache_hash, g->zig_target->vendor); cache_int(&cache_hash, g->zig_target->os); cache_int(&cache_hash, g->zig_target->abi); + if (g->zig_target->glibc_version != nullptr) { + cache_int(&cache_hash, g->zig_target->glibc_version->major); + cache_int(&cache_hash, g->zig_target->glibc_version->minor); + cache_int(&cache_hash, g->zig_target->glibc_version->patch); + } cache_bool(&cache_hash, g->have_err_ret_tracing); cache_bool(&cache_hash, g->libc_link_lib != nullptr); cache_bool(&cache_hash, g->valgrind_support); @@ -9465,6 +9487,11 @@ static Error check_cache(CodeGen *g, Buf *manifest_dir, Buf *digest) { cache_int(ch, g->zig_target->vendor); cache_int(ch, g->zig_target->os); cache_int(ch, g->zig_target->abi); + if (g->zig_target->glibc_version != nullptr) { + cache_int(ch, g->zig_target->glibc_version->major); + cache_int(ch, g->zig_target->glibc_version->minor); + cache_int(ch, g->zig_target->glibc_version->patch); + } cache_int(ch, detect_subsystem(g)); cache_bool(ch, g->strip_debug_symbols); cache_bool(ch, g->is_test_build); diff --git a/src/main.cpp b/src/main.cpp index 43fa75178b..9329229a7b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1015,6 +1015,10 @@ int main(int argc, char **argv) { CodeGen *g = codegen_create(main_pkg_path, nullptr, &target, out_type, build_mode, override_lib_dir, override_std_dir, nullptr, nullptr); codegen_set_strip(g, strip); + for (size_t i = 0; i < link_libs.length; i += 1) { + LinkLib *link_lib = codegen_add_link_lib(g, buf_create_from_str(link_libs.at(i))); + link_lib->provided_explicitly = true; + } g->subsystem = subsystem; g->valgrind_support = valgrind_support; g->want_pic = want_pic; diff --git a/std/build.zig b/std/build.zig index f1cdc2f926..87f589bc5b 100644 --- a/std/build.zig +++ b/std/build.zig @@ -1011,7 +1011,8 @@ pub const LibExeObjStep = struct { builder: *Builder, name: []const u8, target: Target, - linker_script: ?[]const u8, + linker_script: ?[]const u8 = null, + version_script: ?[]const u8 = null, out_filename: []const u8, is_dynamic: bool, version: Version, @@ -1118,7 +1119,6 @@ pub const LibExeObjStep = struct { .root_src = root_src, .name = name, .target = Target.Native, - .linker_script = null, .frameworks = BufSet.init(builder.allocator), .step = Step.init(name, builder.allocator, make), .version = ver, @@ -1596,7 +1596,12 @@ pub const LibExeObjStep = struct { if (self.linker_script) |linker_script| { zig_args.append("--linker-script") catch unreachable; - zig_args.append(linker_script) catch unreachable; + zig_args.append(builder.pathFromRoot(linker_script)) catch unreachable; + } + + if (self.version_script) |version_script| { + try zig_args.append("--version-script"); + try zig_args.append(builder.pathFromRoot(version_script)); } if (self.exec_cmd_args) |exec_cmd_args| { -- cgit v1.2.3 From ea90a3a9a16af83efdd8878285d5f53ae36ba9f3 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 10 Jul 2019 14:13:00 -0400 Subject: mingw: building and linking mingw32.lib --- CMakeLists.txt | 34 + libc/include/any-windows-any/_mingw.h | 2 +- libc/mingw/crt/CRT_fp10.c | 32 + libc/mingw/crt/_newmode.c | 7 + libc/mingw/crt/charmax.c | 22 + libc/mingw/crt/cinitexe.c | 13 + libc/mingw/crt/crt0_c.c | 20 + libc/mingw/crt/crt0_w.c | 25 + libc/mingw/crt/crt_handler.c | 290 +++++ libc/mingw/crt/cxa_atexit.c | 151 +++ libc/mingw/crt/dll_argv.c | 25 + libc/mingw/crt/dllargv.c | 22 + libc/mingw/crt/gccmain.c | 85 ++ libc/mingw/crt/gs_support.c | 154 +++ libc/mingw/crt/merr.c | 76 ++ libc/mingw/crt/mingw_helpers.c | 31 + libc/mingw/crt/natstart.c | 14 + libc/mingw/crt/pesect.c | 230 ++++ libc/mingw/crt/pseudo-reloc-list.c | 8 + libc/mingw/crt/pseudo-reloc.c | 487 +++++++++ libc/mingw/crt/tlsmcrt.c | 13 + libc/mingw/crt/tlsmthread.c | 33 + libc/mingw/crt/tlssup.c | 175 +++ libc/mingw/crt/tlsthrd.c | 158 +++ libc/mingw/crt/udll_argv.c | 16 + libc/mingw/crt/udllargc.c | 16 + libc/mingw/crt/wildcard.c | 33 + libc/mingw/crt/xncommod.c | 7 + libc/mingw/crt/xthdloc.c | 7 + libc/mingw/crt/xtxtmode.c | 6 + libc/mingw/def-include/func.def.in | 57 + libc/mingw/def-include/msvcrt-common.def.in | 145 +++ libc/mingw/include/config.h | 74 ++ libc/mingw/lib-common/msvcrt.def.in | 1577 +++++++++++++++++++++++++++ src/codegen.cpp | 6 +- src/codegen.hpp | 2 + src/link.cpp | 227 +++- 37 files changed, 4269 insertions(+), 11 deletions(-) create mode 100644 libc/mingw/crt/CRT_fp10.c create mode 100644 libc/mingw/crt/_newmode.c create mode 100644 libc/mingw/crt/charmax.c create mode 100644 libc/mingw/crt/cinitexe.c create mode 100644 libc/mingw/crt/crt0_c.c create mode 100644 libc/mingw/crt/crt0_w.c create mode 100644 libc/mingw/crt/crt_handler.c create mode 100644 libc/mingw/crt/cxa_atexit.c create mode 100644 libc/mingw/crt/dll_argv.c create mode 100644 libc/mingw/crt/dllargv.c create mode 100644 libc/mingw/crt/gccmain.c create mode 100644 libc/mingw/crt/gs_support.c create mode 100644 libc/mingw/crt/merr.c create mode 100644 libc/mingw/crt/mingw_helpers.c create mode 100644 libc/mingw/crt/natstart.c create mode 100644 libc/mingw/crt/pesect.c create mode 100644 libc/mingw/crt/pseudo-reloc-list.c create mode 100644 libc/mingw/crt/pseudo-reloc.c create mode 100644 libc/mingw/crt/tlsmcrt.c create mode 100644 libc/mingw/crt/tlsmthread.c create mode 100644 libc/mingw/crt/tlssup.c create mode 100644 libc/mingw/crt/tlsthrd.c create mode 100644 libc/mingw/crt/udll_argv.c create mode 100644 libc/mingw/crt/udllargc.c create mode 100644 libc/mingw/crt/wildcard.c create mode 100644 libc/mingw/crt/xncommod.c create mode 100644 libc/mingw/crt/xthdloc.c create mode 100644 libc/mingw/crt/xtxtmode.c create mode 100644 libc/mingw/def-include/func.def.in create mode 100644 libc/mingw/def-include/msvcrt-common.def.in create mode 100644 libc/mingw/include/config.h create mode 100644 libc/mingw/lib-common/msvcrt.def.in (limited to 'src/codegen.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ffa3907af..3897c74912 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7583,11 +7583,45 @@ set(ZIG_LIBC_FILES "include/x86_64-linux-musl/bits/user.h" "include/wasm32-freestanding-musl/bits/alltypes.h" "include/wasm32-freestanding-musl/errno.h" + "mingw/crt/CRT_fp10.c" + "mingw/crt/_newmode.c" + "mingw/crt/charmax.c" + "mingw/crt/cinitexe.c" + "mingw/crt/crt0_c.c" + "mingw/crt/crt0_w.c" + "mingw/crt/crt_handler.c" "mingw/crt/crtdll.c" "mingw/crt/crtexe.c" + "mingw/crt/cxa_atexit.c" + "mingw/crt/dll_argv.c" + "mingw/crt/dllargv.c" + "mingw/crt/gccmain.c" + "mingw/crt/gs_support.c" + "mingw/crt/merr.c" + "mingw/crt/mingw_helpers.c" + "mingw/crt/natstart.c" + "mingw/crt/pesect.c" + "mingw/crt/pseudo-reloc-list.c" + "mingw/crt/pseudo-reloc.c" + "mingw/crt/tlsmcrt.c" + "mingw/crt/tlsmthread.c" + "mingw/crt/tlssup.c" + "mingw/crt/tlsthrd.c" + "mingw/crt/udll_argv.c" + "mingw/crt/udllargc.c" + "mingw/crt/wildcard.c" + "mingw/crt/xncommod.c" + "mingw/crt/xthdloc.c" + "mingw/crt/xtxtmode.c" + "mingw/def-include/.func.def.in.swp" + "mingw/def-include/.msvcrt-common.def.in.swp" + "mingw/def-include/func.def.in" + "mingw/def-include/msvcrt-common.def.in" + "mingw/include/config.h" "mingw/include/internal.h" "mingw/include/oscalls.h" "mingw/include/sect_attribs.h" + "mingw/lib-common/msvcrt.def.in" "musl/arch/aarch64/atomic_arch.h" "musl/arch/aarch64/bits/alltypes.h.in" "musl/arch/aarch64/bits/endian.h" diff --git a/libc/include/any-windows-any/_mingw.h b/libc/include/any-windows-any/_mingw.h index 578121431d..8195a435e9 100644 --- a/libc/include/any-windows-any/_mingw.h +++ b/libc/include/any-windows-any/_mingw.h @@ -224,7 +224,7 @@ limitations in handling dllimport attribute. */ #ifndef __MSVCRT_VERSION__ /* High byte is the major version, low byte is the minor. */ -# define __MSVCRT_VERSION__ 0x1400 +# define __MSVCRT_VERSION__ 0x700 #endif diff --git a/libc/mingw/crt/CRT_fp10.c b/libc/mingw/crt/CRT_fp10.c new file mode 100644 index 0000000000..f39b5175f7 --- /dev/null +++ b/libc/mingw/crt/CRT_fp10.c @@ -0,0 +1,32 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +void _fpreset (void); + +void _fpreset (void) +{ +#if defined(_ARM_) || defined(__arm__) + __asm__ __volatile__ ( + "vmsr fpscr, %0\n\t" : : "r"(0 /* INITIAL_FPSCR */)); +#elif defined(_ARM64_) || defined(__aarch64__) + __asm__ __volatile__ ( + "msr fpcr, %0\n\t" : : "r"(0LL /* INITIAL_FPSCR */)); +#else +#ifdef __GNUC__ + __asm__ ("fninit"); +#else /* msvc: */ + __asm fninit; +#endif +#endif +} + +#ifdef __GNUC__ +void __attribute__ ((alias ("_fpreset"))) fpreset(void); +#else +void fpreset(void) { + _fpreset(); +} +#endif diff --git a/libc/mingw/crt/_newmode.c b/libc/mingw/crt/_newmode.c new file mode 100644 index 0000000000..2bb5d94a27 --- /dev/null +++ b/libc/mingw/crt/_newmode.c @@ -0,0 +1,7 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +int _newmode = 0; diff --git a/libc/mingw/crt/charmax.c b/libc/mingw/crt/charmax.c new file mode 100644 index 0000000000..08aa5a1d3e --- /dev/null +++ b/libc/mingw/crt/charmax.c @@ -0,0 +1,22 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include +#include +#include + +__declspec(dllimport) int __lconv_init (void); + +int mingw_initcharmax = 0; + +int _charmax = 255; + +static int my_lconv_init(void) +{ + return __lconv_init(); +} + +_CRTALLOC(".CRT$XIC") _PIFV __mingw_pinit = my_lconv_init; diff --git a/libc/mingw/crt/cinitexe.c b/libc/mingw/crt/cinitexe.c new file mode 100644 index 0000000000..ee441ed77f --- /dev/null +++ b/libc/mingw/crt/cinitexe.c @@ -0,0 +1,13 @@ +#include +#include + +#ifdef _MSC_VER +#pragma comment(linker, "/merge:.CRT=.rdata") +#endif + +typedef void (__cdecl *_PVFV)(void); + +_CRTALLOC(".CRT$XIA") _PVFV __xi_a[] = { NULL }; +_CRTALLOC(".CRT$XIZ") _PVFV __xi_z[] = { NULL }; +_CRTALLOC(".CRT$XCA") _PVFV __xc_a[] = { NULL }; +_CRTALLOC(".CRT$XCZ") _PVFV __xc_z[] = { NULL }; diff --git a/libc/mingw/crt/crt0_c.c b/libc/mingw/crt/crt0_c.c new file mode 100644 index 0000000000..e42dd320f4 --- /dev/null +++ b/libc/mingw/crt/crt0_c.c @@ -0,0 +1,20 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include + +extern HINSTANCE __mingw_winmain_hInstance; +extern LPSTR __mingw_winmain_lpCmdLine; +extern DWORD __mingw_winmain_nShowCmd; + +/*ARGSUSED*/ +int main (int __UNUSED_PARAM(flags), + char ** __UNUSED_PARAM(cmdline), + char ** __UNUSED_PARAM(inst)) +{ + return (int) WinMain (__mingw_winmain_hInstance, NULL, + __mingw_winmain_lpCmdLine, __mingw_winmain_nShowCmd); +} diff --git a/libc/mingw/crt/crt0_w.c b/libc/mingw/crt/crt0_w.c new file mode 100644 index 0000000000..ab099c9632 --- /dev/null +++ b/libc/mingw/crt/crt0_w.c @@ -0,0 +1,25 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +#include + +/* Do the UNICODE prototyping of WinMain. Be aware that in winbase.h WinMain is a macro + defined to wWinMain. */ +int WINAPI wWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPWSTR lpCmdLine,int nShowCmd); + +extern HINSTANCE __mingw_winmain_hInstance; +extern LPWSTR __mingw_winmain_lpCmdLine; +extern DWORD __mingw_winmain_nShowCmd; + +int wmain (int, wchar_t **, wchar_t **); + +/*ARGSUSED*/ +int wmain (int __UNUSED_PARAM(flags), + wchar_t ** __UNUSED_PARAM(cmdline), + wchar_t ** __UNUSED_PARAM(inst)) +{ + return (int) wWinMain (__mingw_winmain_hInstance, NULL, + __mingw_winmain_lpCmdLine, __mingw_winmain_nShowCmd); +} diff --git a/libc/mingw/crt/crt_handler.c b/libc/mingw/crt/crt_handler.c new file mode 100644 index 0000000000..6571e69e8f --- /dev/null +++ b/libc/mingw/crt/crt_handler.c @@ -0,0 +1,290 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined (_WIN64) && defined (__ia64__) +#error FIXME: Unsupported __ImageBase implementation. +#else +#ifndef _MSC_VER +#define __ImageBase __MINGW_LSYMBOL(_image_base__) +#endif +/* This symbol is defined by the linker. */ +extern IMAGE_DOS_HEADER __ImageBase; +#endif + +#pragma pack(push,1) +typedef struct _UNWIND_INFO { + BYTE VersionAndFlags; + BYTE PrologSize; + BYTE CountOfUnwindCodes; + BYTE FrameRegisterAndOffset; + ULONG AddressOfExceptionHandler; +} UNWIND_INFO,*PUNWIND_INFO; +#pragma pack(pop) + +PIMAGE_SECTION_HEADER _FindPESectionByName (const char *); +PIMAGE_SECTION_HEADER _FindPESectionExec (size_t); +PBYTE _GetPEImageBase (void); + +int __mingw_init_ehandler (void); +extern void _fpreset (void); + +#if defined(__x86_64__) && !defined(_MSC_VER) +EXCEPTION_DISPOSITION __mingw_SEH_error_handler(struct _EXCEPTION_RECORD *, void *, struct _CONTEXT *, void *); + +#define MAX_PDATA_ENTRIES 32 +static RUNTIME_FUNCTION emu_pdata[MAX_PDATA_ENTRIES]; +static UNWIND_INFO emu_xdata[MAX_PDATA_ENTRIES]; + +int +__mingw_init_ehandler (void) +{ + static int was_here = 0; + size_t e = 0; + PIMAGE_SECTION_HEADER pSec; + PBYTE _ImageBase = _GetPEImageBase (); + + if (was_here || !_ImageBase) + return was_here; + was_here = 1; + if (_FindPESectionByName (".pdata") != NULL) + return 1; + + /* Allocate # of e tables and entries. */ + memset (emu_pdata, 0, sizeof (RUNTIME_FUNCTION) * MAX_PDATA_ENTRIES); + memset (emu_xdata, 0, sizeof (UNWIND_INFO) * MAX_PDATA_ENTRIES); + + e = 0; + /* Fill tables and entries. */ + while (e < MAX_PDATA_ENTRIES && (pSec = _FindPESectionExec (e)) != NULL) + { + emu_xdata[e].VersionAndFlags = 9; /* UNW_FLAG_EHANDLER | UNW_VERSION */ + emu_xdata[e].AddressOfExceptionHandler = + (DWORD)(size_t) ((LPBYTE)__mingw_SEH_error_handler - _ImageBase); + emu_pdata[e].BeginAddress = pSec->VirtualAddress; + emu_pdata[e].EndAddress = pSec->VirtualAddress + pSec->Misc.VirtualSize; + emu_pdata[e].UnwindData = + (DWORD)(size_t)((LPBYTE)&emu_xdata[e] - _ImageBase); + ++e; + } +#ifdef _DEBUG_CRT + if (!e || e > MAX_PDATA_ENTRIES) + abort (); +#endif + /* RtlAddFunctionTable. */ + if (e != 0) + RtlAddFunctionTable (emu_pdata, e, (DWORD64)_ImageBase); + return 1; +} + +extern void _fpreset (void); + +EXCEPTION_DISPOSITION +__mingw_SEH_error_handler (struct _EXCEPTION_RECORD* ExceptionRecord, + void *EstablisherFrame __attribute__ ((unused)), + struct _CONTEXT* ContextRecord __attribute__ ((unused)), + void *DispatcherContext __attribute__ ((unused))) +{ + EXCEPTION_DISPOSITION action = ExceptionContinueSearch; /* EXCEPTION_CONTINUE_SEARCH; */ + void (*old_handler) (int); + int reset_fpu = 0; + + switch (ExceptionRecord->ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + /* test if the user has set SIGSEGV */ + old_handler = signal (SIGSEGV, SIG_DFL); + if (old_handler == SIG_IGN) + { + /* this is undefined if the signal was raised by anything other + than raise (). */ + signal (SIGSEGV, SIG_IGN); + action = 0; //EXCEPTION_CONTINUE_EXECUTION; + } + else if (old_handler != SIG_DFL) + { + /* This means 'old' is a user defined function. Call it */ + (*old_handler) (SIGSEGV); + action = 0; // EXCEPTION_CONTINUE_EXECUTION; + } + else + action = 4; /* EXCEPTION_EXECUTE_HANDLER; */ + break; + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_PRIV_INSTRUCTION: + /* test if the user has set SIGILL */ + old_handler = signal (SIGILL, SIG_DFL); + if (old_handler == SIG_IGN) + { + /* this is undefined if the signal was raised by anything other + than raise (). */ + signal (SIGILL, SIG_IGN); + action = 0; // EXCEPTION_CONTINUE_EXECUTION; + } + else if (old_handler != SIG_DFL) + { + /* This means 'old' is a user defined function. Call it */ + (*old_handler) (SIGILL); + action = 0; // EXCEPTION_CONTINUE_EXECUTION; + } + else + action = 4; /* EXCEPTION_EXECUTE_HANDLER;*/ + break; + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_FLT_INEXACT_RESULT: + reset_fpu = 1; + /* fall through. */ + + case EXCEPTION_INT_DIVIDE_BY_ZERO: + /* test if the user has set SIGFPE */ + old_handler = signal (SIGFPE, SIG_DFL); + if (old_handler == SIG_IGN) + { + signal (SIGFPE, SIG_IGN); + if (reset_fpu) + _fpreset (); + action = 0; // EXCEPTION_CONTINUE_EXECUTION; + } + else if (old_handler != SIG_DFL) + { + /* This means 'old' is a user defined function. Call it */ + (*old_handler) (SIGFPE); + action = 0; // EXCEPTION_CONTINUE_EXECUTION; + } + break; + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_INT_OVERFLOW: + case EXCEPTION_INVALID_HANDLE: + /*case EXCEPTION_POSSIBLE_DEADLOCK: */ + action = 0; // EXCEPTION_CONTINUE_EXECUTION; + break; + default: + break; + } + return action; +} + +#endif + +LPTOP_LEVEL_EXCEPTION_FILTER __mingw_oldexcpt_handler = NULL; + +long CALLBACK +_gnu_exception_handler (EXCEPTION_POINTERS *exception_data); + +#define GCC_MAGIC (('G' << 16) | ('C' << 8) | 'C' | (1U << 29)) + +long CALLBACK +_gnu_exception_handler (EXCEPTION_POINTERS *exception_data) +{ + void (*old_handler) (int); + long action = EXCEPTION_CONTINUE_SEARCH; + int reset_fpu = 0; + +#ifdef __SEH__ + if ((exception_data->ExceptionRecord->ExceptionCode & 0x20ffffff) == GCC_MAGIC) + { + if ((exception_data->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE) == 0) + return EXCEPTION_CONTINUE_EXECUTION; + } +#endif + + switch (exception_data->ExceptionRecord->ExceptionCode) + { + case EXCEPTION_ACCESS_VIOLATION: + /* test if the user has set SIGSEGV */ + old_handler = signal (SIGSEGV, SIG_DFL); + if (old_handler == SIG_IGN) + { + /* this is undefined if the signal was raised by anything other + than raise (). */ + signal (SIGSEGV, SIG_IGN); + action = EXCEPTION_CONTINUE_EXECUTION; + } + else if (old_handler != SIG_DFL) + { + /* This means 'old' is a user defined function. Call it */ + (*old_handler) (SIGSEGV); + action = EXCEPTION_CONTINUE_EXECUTION; + } + break; + + case EXCEPTION_ILLEGAL_INSTRUCTION: + case EXCEPTION_PRIV_INSTRUCTION: + /* test if the user has set SIGILL */ + old_handler = signal (SIGILL, SIG_DFL); + if (old_handler == SIG_IGN) + { + /* this is undefined if the signal was raised by anything other + than raise (). */ + signal (SIGILL, SIG_IGN); + action = EXCEPTION_CONTINUE_EXECUTION; + } + else if (old_handler != SIG_DFL) + { + /* This means 'old' is a user defined function. Call it */ + (*old_handler) (SIGILL); + action = EXCEPTION_CONTINUE_EXECUTION; + } + break; + + case EXCEPTION_FLT_INVALID_OPERATION: + case EXCEPTION_FLT_DIVIDE_BY_ZERO: + case EXCEPTION_FLT_DENORMAL_OPERAND: + case EXCEPTION_FLT_OVERFLOW: + case EXCEPTION_FLT_UNDERFLOW: + case EXCEPTION_FLT_INEXACT_RESULT: + reset_fpu = 1; + /* fall through. */ + + case EXCEPTION_INT_DIVIDE_BY_ZERO: + /* test if the user has set SIGFPE */ + old_handler = signal (SIGFPE, SIG_DFL); + if (old_handler == SIG_IGN) + { + signal (SIGFPE, SIG_IGN); + if (reset_fpu) + _fpreset (); + action = EXCEPTION_CONTINUE_EXECUTION; + } + else if (old_handler != SIG_DFL) + { + /* This means 'old' is a user defined function. Call it */ + (*old_handler) (SIGFPE); + action = EXCEPTION_CONTINUE_EXECUTION; + } + break; +#ifdef _WIN64 + case EXCEPTION_DATATYPE_MISALIGNMENT: + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: + case EXCEPTION_FLT_STACK_CHECK: + case EXCEPTION_INT_OVERFLOW: + case EXCEPTION_INVALID_HANDLE: + /*case EXCEPTION_POSSIBLE_DEADLOCK: */ + action = EXCEPTION_CONTINUE_EXECUTION; + break; +#endif + default: + break; + } + + if (action == EXCEPTION_CONTINUE_SEARCH && __mingw_oldexcpt_handler) + action = (*__mingw_oldexcpt_handler)(exception_data); + return action; +} diff --git a/libc/mingw/crt/cxa_atexit.c b/libc/mingw/crt/cxa_atexit.c new file mode 100644 index 0000000000..06912a8266 --- /dev/null +++ b/libc/mingw/crt/cxa_atexit.c @@ -0,0 +1,151 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include +#include +#include + + +typedef void (__thiscall * dtor_fn)(void*); +int __cxa_atexit(dtor_fn dtor, void *obj, void *dso); +int __cxa_thread_atexit(dtor_fn dtor, void *obj, void *dso); + +typedef struct dtor_obj dtor_obj; +struct dtor_obj { + dtor_fn dtor; + void *obj; + dtor_obj *next; +}; + +HANDLE __dso_handle; +extern char __mingw_module_is_dll; + +static CRITICAL_SECTION lock; +static int inited = 0; +static dtor_obj *global_dtors = NULL; +static __thread dtor_obj *tls_dtors = NULL; + +int __cxa_atexit(dtor_fn dtor, void *obj, void *dso) { + if (!inited) + return 1; + assert(!dso || dso == &__dso_handle); + dtor_obj *handler = (dtor_obj *) calloc(1, sizeof(*handler)); + if (!handler) + return 1; + handler->dtor = dtor; + handler->obj = obj; + EnterCriticalSection(&lock); + handler->next = global_dtors; + global_dtors = handler; + LeaveCriticalSection(&lock); + return 0; +} + +static void run_dtor_list(dtor_obj **ptr) { + dtor_obj *list = *ptr; + while (list) { + list->dtor(list->obj); + dtor_obj *next = list->next; + free(list); + list = next; + } + *ptr = NULL; +} + +int __cxa_thread_atexit(dtor_fn dtor, void *obj, void *dso) { + if (!inited) + return 1; + assert(!dso || dso == &__dso_handle); + dtor_obj *handler = (dtor_obj *) calloc(1, sizeof(*handler)); + if (!handler) + return 1; + handler->dtor = dtor; + handler->obj = obj; + handler->next = tls_dtors; + tls_dtors = handler; + return 0; +} + +static void WINAPI tls_atexit_callback(HANDLE __UNUSED_PARAM(hDllHandle), DWORD dwReason, LPVOID __UNUSED_PARAM(lpReserved)) { + if (dwReason == DLL_PROCESS_DETACH) { + run_dtor_list(&tls_dtors); + run_dtor_list(&global_dtors); + } +} + +static void WINAPI tls_callback(HANDLE hDllHandle, DWORD dwReason, LPVOID __UNUSED_PARAM(lpReserved)) { + switch (dwReason) { + case DLL_PROCESS_ATTACH: + if (inited == 0) { + InitializeCriticalSection(&lock); + __dso_handle = hDllHandle; + /* + * We can only call _register_thread_local_exe_atexit_callback once + * in a process; if we call it a second time the process terminates. + * When DLLs are unloaded, this callback is invoked before we run the + * _onexit tables, but for exes, we need to ask this to be called before + * all other registered atexit functions. + * Since we are registered as a normal TLS callback, we will be called + * another time later as well, but that doesn't matter, it's safe to + * invoke this with DLL_PROCESS_DETACH twice. + */ + if (!__mingw_module_is_dll) + _register_thread_local_exe_atexit_callback(tls_atexit_callback); + } + inited = 1; + break; + case DLL_PROCESS_DETACH: + /* + * If there are other threads still running that haven't been detached, + * we don't attempt to run their destructors (MSVC doesn't either), but + * simply leak the destructor list and whatever resources the destructors + * would have released. + * + * From Vista onwards, we could have used FlsAlloc to get a TLS key that + * runs a destructor on each thread that has a value attached ot it, but + * since MSVC doesn't run destructors on other threads in this case, + * users shouldn't assume it and we don't attempt to do anything potentially + * risky about it. TL;DR, threads with pending TLS destructors for a DLL + * need to be joined before unloading the DLL. + * + * This gets called both when exiting cleanly (via exit or returning from + * main, or when a DLL is unloaded), and when exiting bypassing some of + * the cleanup, by calling _exit or ExitProcess. In the latter cases, + * destructors (both TLS and global) in loaded DLLs still get called, + * but only TLS destructors get called for the main executable, global + * variables' destructors don't run. (This matches what MSVC does with + * a dynamically linked CRT.) + */ + run_dtor_list(&tls_dtors); + if (__mingw_module_is_dll) { + /* For DLLs, run dtors when detached. For EXEs, run dtors via the + * thread local atexit callback, to make sure they don't run when + * exiting the process with _exit or ExitProcess. */ + run_dtor_list(&global_dtors); + } + if (inited == 1) { + inited = 0; + DeleteCriticalSection(&lock); + } + break; + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + run_dtor_list(&tls_dtors); + break; + } +} + +_CRTALLOC(".CRT$XLE") PIMAGE_TLS_CALLBACK __xl_e = (PIMAGE_TLS_CALLBACK) tls_callback; diff --git a/libc/mingw/crt/dll_argv.c b/libc/mingw/crt/dll_argv.c new file mode 100644 index 0000000000..22397af50c --- /dev/null +++ b/libc/mingw/crt/dll_argv.c @@ -0,0 +1,25 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#ifdef CRTDLL +#undef CRTDLL +#endif + +#include + +extern int _dowildcard; + +#ifdef WPRFLAG +int __CRTDECL +__wsetargv (void) +#else +int __CRTDECL +__setargv (void) +#endif +{ + _dowildcard = 1; + return 0; +} diff --git a/libc/mingw/crt/dllargv.c b/libc/mingw/crt/dllargv.c new file mode 100644 index 0000000000..7cd98dad82 --- /dev/null +++ b/libc/mingw/crt/dllargv.c @@ -0,0 +1,22 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#ifdef CRTDLL +#undef CRTDLL +#endif + +#include + +#ifdef WPRFLAG +int __CRTDECL +_wsetargv (void) +#else +int __CRTDECL +_setargv (void) +#endif +{ + return 0; +} diff --git a/libc/mingw/crt/gccmain.c b/libc/mingw/crt/gccmain.c new file mode 100644 index 0000000000..030cdce60b --- /dev/null +++ b/libc/mingw/crt/gccmain.c @@ -0,0 +1,85 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +typedef void (*func_ptr) (void); +extern func_ptr __CTOR_LIST__[]; +extern func_ptr __DTOR_LIST__[]; + +void __do_global_dtors (void); +void __do_global_ctors (void); +void __main (void); + +void +__do_global_dtors (void) +{ + static func_ptr *p = __DTOR_LIST__ + 1; + + while (*p) + { + (*(p)) (); + p++; + } +} + +#ifndef HAVE_CTOR_LIST +// If the linker didn't provide __CTOR_LIST__, we provided it ourselves, +// and then we also know we have __CTOR_END__ available. +extern func_ptr __CTOR_END__[]; +extern func_ptr __DTOR_END__[]; + +void __do_global_ctors (void) +{ + static func_ptr *p = __CTOR_END__ - 1; + while (*p != (func_ptr) -1) { + (*(p))(); + p--; + } + atexit (__do_global_dtors); +} + +#else +// old method that iterates the list twice because old linker scripts do not have __CTOR_END__ + +void +__do_global_ctors (void) +{ + unsigned long nptrs = (unsigned long) (ptrdiff_t) __CTOR_LIST__[0]; + unsigned long i; + + if (nptrs == (unsigned long) -1) + { + for (nptrs = 0; __CTOR_LIST__[nptrs + 1] != 0; nptrs++); + } + + for (i = nptrs; i >= 1; i--) + { + __CTOR_LIST__[i] (); + } + + atexit (__do_global_dtors); +} + +#endif + +static int initialized = 0; + +void +__main (void) +{ + if (!initialized) + { + initialized = 1; + __do_global_ctors (); + } +} diff --git a/libc/mingw/crt/gs_support.c b/libc/mingw/crt/gs_support.c new file mode 100644 index 0000000000..0c6ac68cd8 --- /dev/null +++ b/libc/mingw/crt/gs_support.c @@ -0,0 +1,154 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#define WIN32_NO_STATUS +#include /* abort () */ +#include +#undef WIN32_NO_STATUS +#include /* STATUS macros */ +#ifdef _WIN64 +#include +#endif + +#ifdef _WIN64 +#define DEFAULT_SECURITY_COOKIE 0x00002B992DDFA232ll +#else +#define DEFAULT_SECURITY_COOKIE 0xBB40E64E +#endif + +/* Externals. */ + +typedef LONG NTSTATUS; /* same as in ntdef.h / winternl.h */ + +#define UNW_FLAG_NHANDLER 0x0 + +typedef union +{ + unsigned __int64 ft_scalar; + FILETIME ft_struct; +} FT; + +static EXCEPTION_RECORD GS_ExceptionRecord; +static CONTEXT GS_ContextRecord; + +static const EXCEPTION_POINTERS GS_ExceptionPointers = { + &GS_ExceptionRecord,&GS_ContextRecord +}; + +DECLSPEC_SELECTANY UINT_PTR __security_cookie = DEFAULT_SECURITY_COOKIE; +DECLSPEC_SELECTANY UINT_PTR __security_cookie_complement = ~(DEFAULT_SECURITY_COOKIE); + +void __cdecl __security_init_cookie (void); + +void __cdecl +__security_init_cookie (void) +{ + UINT_PTR cookie; + FT systime = { 0, }; + LARGE_INTEGER perfctr; + + if (__security_cookie != DEFAULT_SECURITY_COOKIE) + { + __security_cookie_complement = ~__security_cookie; + return; + } + + GetSystemTimeAsFileTime (&systime.ft_struct); +#ifdef _WIN64 + cookie = systime.ft_scalar; +#else + cookie = systime.ft_struct.dwLowDateTime; + cookie ^= systime.ft_struct.dwHighDateTime; +#endif + + cookie ^= GetCurrentProcessId (); + cookie ^= GetCurrentThreadId (); + cookie ^= GetTickCount (); + + QueryPerformanceCounter (&perfctr); +#ifdef _WIN64 + cookie ^= perfctr.QuadPart; +#else + cookie ^= perfctr.LowPart; + cookie ^= perfctr.HighPart; +#endif + +#ifdef _WIN64 + cookie &= 0x0000ffffffffffffll; +#endif + + if (cookie == DEFAULT_SECURITY_COOKIE) + cookie = DEFAULT_SECURITY_COOKIE + 1; + __security_cookie = cookie; + __security_cookie_complement = ~cookie; +} + + +#if defined(__GNUC__) /* wrap msvc intrinsics onto gcc builtins */ +#undef _ReturnAddress +#undef _AddressOfReturnAddress +#define _ReturnAddress() __builtin_return_address(0) +#define _AddressOfReturnAddress() __builtin_frame_address (0) +#endif /* __GNUC__ */ + +__declspec(noreturn) void __cdecl __report_gsfailure (ULONG_PTR); + +#define UNUSED_PARAM(x) { x = x; } +__declspec(noreturn) void __cdecl +__report_gsfailure (ULONG_PTR StackCookie) +{ + volatile UINT_PTR cookie[2] __MINGW_ATTRIB_UNUSED; +#if defined(_WIN64) && !defined(__aarch64__) + ULONG64 controlPC, imgBase, establisherFrame; + PRUNTIME_FUNCTION fctEntry; + PVOID hndData; + + RtlCaptureContext (&GS_ContextRecord); + controlPC = GS_ContextRecord.Rip; + fctEntry = RtlLookupFunctionEntry (controlPC, &imgBase, NULL); + if (fctEntry != NULL) + { + RtlVirtualUnwind (UNW_FLAG_NHANDLER, imgBase, controlPC, fctEntry, + &GS_ContextRecord, &hndData, &establisherFrame, NULL); + } + else +#endif /* _WIN64 */ + { +#if defined(__x86_64__) || defined(_AMD64_) + GS_ContextRecord.Rip = (ULONGLONG) _ReturnAddress(); + GS_ContextRecord.Rsp = (ULONGLONG) _AddressOfReturnAddress() + 8; +#elif defined(__i386__) || defined(_X86_) + GS_ContextRecord.Eip = (DWORD) _ReturnAddress(); + GS_ContextRecord.Esp = (DWORD) _AddressOfReturnAddress() + 4; +#elif defined(__arm__) || defined(_ARM_) + GS_ContextRecord.Pc = (DWORD) _ReturnAddress(); + GS_ContextRecord.Sp = (DWORD) _AddressOfReturnAddress() + 4; +#endif /* _WIN64 */ + } + +#if defined(__x86_64__) || defined(_AMD64_) + GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Rip; + GS_ContextRecord.Rcx = StackCookie; +#elif defined(__i386__) || defined(_X86_) + GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Eip; + GS_ContextRecord.Ecx = StackCookie; +#elif defined(__arm__) || defined(_ARM_) + GS_ExceptionRecord.ExceptionAddress = (PVOID) GS_ContextRecord.Pc; + UNUSED_PARAM(StackCookie); +#endif /* _WIN64 */ + GS_ExceptionRecord.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN; + GS_ExceptionRecord.ExceptionFlags = EXCEPTION_NONCONTINUABLE; + cookie[0] = __security_cookie; + cookie[1] = __security_cookie_complement; + SetUnhandledExceptionFilter (NULL); + UnhandledExceptionFilter ((EXCEPTION_POINTERS *) &GS_ExceptionPointers); + TerminateProcess (GetCurrentProcess (), STATUS_STACK_BUFFER_OVERRUN); + abort(); +} + diff --git a/libc/mingw/crt/merr.c b/libc/mingw/crt/merr.c new file mode 100644 index 0000000000..f3dff58049 --- /dev/null +++ b/libc/mingw/crt/merr.c @@ -0,0 +1,76 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include +#include +#include + +typedef int (__cdecl *fUserMathErr)(struct _exception *); +static fUserMathErr stUserMathErr; + +void __mingw_raise_matherr (int typ, const char *name, double a1, double a2, + double rslt) +{ + struct _exception ex; + if (!stUserMathErr) + return; + ex.type = typ; + ex.name = (char*)name; + ex.arg1 = a1; + ex.arg2 = a2; + ex.retval = rslt; + (*stUserMathErr)(&ex); +} + +#undef __setusermatherr + +void __mingw_setusermatherr (int (__cdecl *f)(struct _exception *)) +{ + stUserMathErr = f; + __setusermatherr (f); +} + +int __CRTDECL +_matherr (struct _exception *pexcept) +{ + const char * type; + + switch(pexcept->type) + { + case _DOMAIN: + type = "Argument domain error (DOMAIN)"; + break; + + case _SING: + type = "Argument singularity (SIGN)"; + break; + + case _OVERFLOW: + type = "Overflow range error (OVERFLOW)"; + break; + + case _PLOSS: + type = "Partial loss of significance (PLOSS)"; + break; + + case _TLOSS: + type = "Total loss of significance (TLOSS)"; + break; + + case _UNDERFLOW: + type = "The result is too small to be represented (UNDERFLOW)"; + break; + + default: + type = "Unknown error"; + break; + } + + fprintf (stderr, "_matherr(): %s in %s(%g, %g) (retval=%g)\n", + type, pexcept->name, pexcept->arg1, pexcept->arg2, pexcept->retval); + return 0; +} + diff --git a/libc/mingw/crt/mingw_helpers.c b/libc/mingw/crt/mingw_helpers.c new file mode 100644 index 0000000000..28c56bc3c5 --- /dev/null +++ b/libc/mingw/crt/mingw_helpers.c @@ -0,0 +1,31 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback; + +void * __cdecl +_decode_pointer (void *codedptr) +{ + return (void *) codedptr; +} + +void * __cdecl +_encode_pointer (void *ptr) +{ + return ptr; +} + +/* 0:console, 1:windows. */ +int mingw_app_type = 0; diff --git a/libc/mingw/crt/natstart.c b/libc/mingw/crt/natstart.c new file mode 100644 index 0000000000..06def19d51 --- /dev/null +++ b/libc/mingw/crt/natstart.c @@ -0,0 +1,14 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include +#include + +_PGLOBAL +volatile unsigned int __native_dllmain_reason = UINT_MAX; +volatile unsigned int __native_vcclrit_reason = UINT_MAX; +volatile __enative_startup_state __native_startup_state; +volatile void *__native_startup_lock; diff --git a/libc/mingw/crt/pesect.c b/libc/mingw/crt/pesect.c new file mode 100644 index 0000000000..28c34f8cad --- /dev/null +++ b/libc/mingw/crt/pesect.c @@ -0,0 +1,230 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#include +#include + +#if defined (_WIN64) && defined (__ia64__) +#error FIXME: Unsupported __ImageBase implementation. +#else +#ifdef __GNUC__ +/* Hack, for bug in ld. Will be removed soon. */ +#define __ImageBase __MINGW_LSYMBOL(_image_base__) +#endif +/* This symbol is defined by the linker. */ +extern IMAGE_DOS_HEADER __ImageBase; +#endif + +WINBOOL _ValidateImageBase (PBYTE); + +WINBOOL +_ValidateImageBase (PBYTE pImageBase) +{ + PIMAGE_DOS_HEADER pDOSHeader; + PIMAGE_NT_HEADERS pNTHeader; + PIMAGE_OPTIONAL_HEADER pOptHeader; + + pDOSHeader = (PIMAGE_DOS_HEADER) pImageBase; + if (pDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) + return FALSE; + pNTHeader = (PIMAGE_NT_HEADERS) ((PBYTE) pDOSHeader + pDOSHeader->e_lfanew); + if (pNTHeader->Signature != IMAGE_NT_SIGNATURE) + return FALSE; + pOptHeader = (PIMAGE_OPTIONAL_HEADER) &pNTHeader->OptionalHeader; + if (pOptHeader->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC) + return FALSE; + return TRUE; +} + +PIMAGE_SECTION_HEADER _FindPESection (PBYTE, DWORD_PTR); + +PIMAGE_SECTION_HEADER +_FindPESection (PBYTE pImageBase, DWORD_PTR rva) +{ + PIMAGE_NT_HEADERS pNTHeader; + PIMAGE_SECTION_HEADER pSection; + unsigned int iSection; + + pNTHeader = (PIMAGE_NT_HEADERS) (pImageBase + ((PIMAGE_DOS_HEADER) pImageBase)->e_lfanew); + + for (iSection = 0, pSection = IMAGE_FIRST_SECTION (pNTHeader); + iSection < pNTHeader->FileHeader.NumberOfSections; + ++iSection,++pSection) + { + if (rva >= pSection->VirtualAddress + && rva < pSection->VirtualAddress + pSection->Misc.VirtualSize) + return pSection; + } + return NULL; +} + +PIMAGE_SECTION_HEADER _FindPESectionByName (const char *); + +PIMAGE_SECTION_HEADER +_FindPESectionByName (const char *pName) +{ + PBYTE pImageBase; + PIMAGE_NT_HEADERS pNTHeader; + PIMAGE_SECTION_HEADER pSection; + unsigned int iSection; + + /* Long names aren't supported. */ + if (strlen (pName) > IMAGE_SIZEOF_SHORT_NAME) + return NULL; + + pImageBase = (PBYTE) &__ImageBase; + if (! _ValidateImageBase (pImageBase)) + return NULL; + + pNTHeader = (PIMAGE_NT_HEADERS) (pImageBase + ((PIMAGE_DOS_HEADER) pImageBase)->e_lfanew); + + for (iSection = 0, pSection = IMAGE_FIRST_SECTION (pNTHeader); + iSection < pNTHeader->FileHeader.NumberOfSections; + ++iSection,++pSection) + { + if (!strncmp ((char *) &pSection->Name[0], pName, IMAGE_SIZEOF_SHORT_NAME)) + return pSection; + } + return NULL; +} + +int __mingw_GetSectionCount (void); +PIMAGE_SECTION_HEADER __mingw_GetSectionForAddress (LPVOID p); + +PIMAGE_SECTION_HEADER +__mingw_GetSectionForAddress (LPVOID p) +{ + PBYTE pImageBase; + DWORD_PTR rva; + + pImageBase = (PBYTE) &__ImageBase; + if (! _ValidateImageBase (pImageBase)) + return NULL; + + rva = (DWORD_PTR) (((PBYTE) p) - pImageBase); + return _FindPESection (pImageBase, rva); +} + +int +__mingw_GetSectionCount (void) +{ + PBYTE pImageBase; + PIMAGE_NT_HEADERS pNTHeader; + + pImageBase = (PBYTE) &__ImageBase; + if (! _ValidateImageBase (pImageBase)) + return 0; + + pNTHeader = (PIMAGE_NT_HEADERS) (pImageBase + ((PIMAGE_DOS_HEADER) pImageBase)->e_lfanew); + + return (int) pNTHeader->FileHeader.NumberOfSections; +} + + +PIMAGE_SECTION_HEADER _FindPESectionExec (size_t); + +PIMAGE_SECTION_HEADER +_FindPESectionExec (size_t eNo) +{ + PBYTE pImageBase; + PIMAGE_NT_HEADERS pNTHeader; + PIMAGE_SECTION_HEADER pSection; + unsigned int iSection; + + pImageBase = (PBYTE) &__ImageBase; + if (! _ValidateImageBase (pImageBase)) + return NULL; + + pNTHeader = (PIMAGE_NT_HEADERS) (pImageBase + ((PIMAGE_DOS_HEADER) pImageBase)->e_lfanew); + + for (iSection = 0, pSection = IMAGE_FIRST_SECTION (pNTHeader); + iSection < pNTHeader->FileHeader.NumberOfSections; + ++iSection,++pSection) + { + if ((pSection->Characteristics & IMAGE_SCN_MEM_EXECUTE) != 0) + { + if (!eNo) + return pSection; + --eNo; + } + } + return NULL; +} + +PBYTE _GetPEImageBase (void); + +PBYTE +_GetPEImageBase (void) +{ + PBYTE pImageBase; + pImageBase = (PBYTE) &__ImageBase; + if (! _ValidateImageBase (pImageBase)) + return NULL; + return pImageBase; +} + +WINBOOL _IsNonwritableInCurrentImage (PBYTE); + +WINBOOL +_IsNonwritableInCurrentImage (PBYTE pTarget) +{ + PBYTE pImageBase; + DWORD_PTR rvaTarget; + PIMAGE_SECTION_HEADER pSection; + + pImageBase = (PBYTE) &__ImageBase; + if (! _ValidateImageBase (pImageBase)) + return FALSE; + rvaTarget = pTarget - pImageBase; + pSection = _FindPESection (pImageBase, rvaTarget); + if (pSection == NULL) + return FALSE; + return (pSection->Characteristics & IMAGE_SCN_MEM_WRITE) == 0; +} + +const char * +__mingw_enum_import_library_names (int); + +const char * +__mingw_enum_import_library_names (int i) +{ + PBYTE pImageBase; + PIMAGE_NT_HEADERS pNTHeader; + PIMAGE_IMPORT_DESCRIPTOR importDesc; + PIMAGE_SECTION_HEADER pSection; + DWORD importsStartRVA; + + pImageBase = (PBYTE) &__ImageBase; + if (! _ValidateImageBase (pImageBase)) + return NULL; + + pNTHeader = (PIMAGE_NT_HEADERS) (pImageBase + ((PIMAGE_DOS_HEADER) pImageBase)->e_lfanew); + + importsStartRVA = pNTHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress; + if (!importsStartRVA) + return NULL; + + pSection = _FindPESection (pImageBase, importsStartRVA); + if (!pSection) + return NULL; + + importDesc = (PIMAGE_IMPORT_DESCRIPTOR) (pImageBase + importsStartRVA); + if (!importDesc) + return NULL; + + for (;;) + { + if (importDesc->TimeDateStamp == 0 && importDesc->Name == 0) + break; + + if (i <= 0) + return (char *) (pImageBase + importDesc->Name); + --i; + importDesc++; + } + + return NULL; +} diff --git a/libc/mingw/crt/pseudo-reloc-list.c b/libc/mingw/crt/pseudo-reloc-list.c new file mode 100644 index 0000000000..5b903c21d2 --- /dev/null +++ b/libc/mingw/crt/pseudo-reloc-list.c @@ -0,0 +1,8 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +char __RUNTIME_PSEUDO_RELOC_LIST_END__ = 0; +char __RUNTIME_PSEUDO_RELOC_LIST__ = 0; diff --git a/libc/mingw/crt/pseudo-reloc.c b/libc/mingw/crt/pseudo-reloc.c new file mode 100644 index 0000000000..6210368bac --- /dev/null +++ b/libc/mingw/crt/pseudo-reloc.c @@ -0,0 +1,487 @@ +/* pseudo-reloc.c + + Contributed by Egor Duda + Modified by addition of runtime_pseudo_reloc version 2 + by Kai Tietz + + THIS SOFTWARE IS NOT COPYRIGHTED + + This source code is offered for use in the public domain. You may + use, modify or distribute it freely. + + This code is distributed in the hope that it will be useful but + WITHOUT ANY WARRANTY. ALL WARRENTIES, EXPRESS OR IMPLIED ARE HEREBY + DISCLAMED. This includes but is not limited to warrenties of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + +#include +#include +#include +#include +#include +#include + +#if defined(__CYGWIN__) +#include +#include +#include +/* copied from winsup.h */ +# define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy"))) +/* custom status code: */ +#define STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION ((NTSTATUS) 0xe0000269) +#define SHORT_MSG_BUF_SZ 128 +#else +# define NO_COPY +#endif + +#ifdef __GNUC__ +#define ATTRIBUTE_NORETURN __attribute__ ((noreturn)) +#else +#define ATTRIBUTE_NORETURN +#endif + +#ifndef __MINGW_LSYMBOL +#define __MINGW_LSYMBOL(sym) sym +#endif + +extern char __RUNTIME_PSEUDO_RELOC_LIST__; +extern char __RUNTIME_PSEUDO_RELOC_LIST_END__; +extern char __MINGW_LSYMBOL(_image_base__); + +void _pei386_runtime_relocator (void); + +/* v1 relocation is basically: + * *(base + .target) += .addend + * where (base + .target) is always assumed to point + * to a DWORD (4 bytes). + */ +typedef struct { + DWORD addend; + DWORD target; +} runtime_pseudo_reloc_item_v1; + +/* v2 relocation is more complex. In effect, it is + * *(base + .target) += *(base + .sym) - (base + .sym) + * with care taken in both reading, sign extension, and writing + * because .flags may indicate that (base + .target) may point + * to a BYTE, WORD, DWORD, or QWORD (w64). + */ +typedef struct { + DWORD sym; + DWORD target; + DWORD flags; +} runtime_pseudo_reloc_item_v2; + +typedef struct { + DWORD magic1; + DWORD magic2; + DWORD version; +} runtime_pseudo_reloc_v2; + +static void ATTRIBUTE_NORETURN +__report_error (const char *msg, ...) +{ +#ifdef __CYGWIN__ + /* This function is used to print short error messages + * to stderr, which may occur during DLL initialization + * while fixing up 'pseudo' relocations. This early, we + * may not be able to use cygwin stdio functions, so we + * use the win32 WriteFile api. This should work with both + * normal win32 console IO handles, redirected ones, and + * cygwin ptys. + */ + char buf[SHORT_MSG_BUF_SZ]; + wchar_t module[PATH_MAX]; + char * posix_module = NULL; + static const char UNKNOWN_MODULE[] = ": "; + static const size_t UNKNOWN_MODULE_LEN = sizeof (UNKNOWN_MODULE) - 1; + static const char CYGWIN_FAILURE_MSG[] = "Cygwin runtime failure: "; + static const size_t CYGWIN_FAILURE_MSG_LEN = sizeof (CYGWIN_FAILURE_MSG) - 1; + DWORD len; + DWORD done; + va_list args; + HANDLE errh = GetStdHandle (STD_ERROR_HANDLE); + ssize_t modulelen = GetModuleFileNameW (NULL, module, PATH_MAX); + + if (errh == INVALID_HANDLE_VALUE) + cygwin_internal (CW_EXIT_PROCESS, + STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, + 1); + + if (modulelen > 0) + posix_module = cygwin_create_path (CCP_WIN_W_TO_POSIX, module); + + va_start (args, msg); + len = (DWORD) vsnprintf (buf, SHORT_MSG_BUF_SZ, msg, args); + va_end (args); + buf[SHORT_MSG_BUF_SZ-1] = '\0'; /* paranoia */ + + if (posix_module) + { + WriteFile (errh, (PCVOID)CYGWIN_FAILURE_MSG, + CYGWIN_FAILURE_MSG_LEN, &done, NULL); + WriteFile (errh, (PCVOID)posix_module, + strlen(posix_module), &done, NULL); + WriteFile (errh, (PCVOID)": ", 2, &done, NULL); + WriteFile (errh, (PCVOID)buf, len, &done, NULL); + free (posix_module); + } + else + { + WriteFile (errh, (PCVOID)CYGWIN_FAILURE_MSG, + CYGWIN_FAILURE_MSG_LEN, &done, NULL); + WriteFile (errh, (PCVOID)UNKNOWN_MODULE, + UNKNOWN_MODULE_LEN, &done, NULL); + WriteFile (errh, (PCVOID)buf, len, &done, NULL); + } + WriteFile (errh, (PCVOID)"\n", 1, &done, NULL); + + cygwin_internal (CW_EXIT_PROCESS, + STATUS_ILLEGAL_DLL_PSEUDO_RELOCATION, + 1); + /* not reached, but silences noreturn warning */ + abort (); +#else + va_list argp; + va_start (argp, msg); +# ifdef __MINGW64_VERSION_MAJOR + fprintf (stderr, "Mingw-w64 runtime failure:\n"); + vfprintf (stderr, msg, argp); +# else + fprintf (stderr, "Mingw runtime failure:\n"); + vfprintf (stderr, msg, argp); +#endif + va_end (argp); + abort (); +#endif +} + +/* For mingw-w64 we have additional helpers to get image information + on runtime. This allows us to cache for pseudo-relocation pass + the temporary access of code/read-only sections. + This step speeds up pseudo-relocation pass. */ +#ifdef __MINGW64_VERSION_MAJOR +extern int __mingw_GetSectionCount (void); +extern PIMAGE_SECTION_HEADER __mingw_GetSectionForAddress (LPVOID p); +extern PBYTE _GetPEImageBase (void); + +typedef struct sSecInfo { + /* Keeps altered section flags, or zero if nothing was changed. */ + DWORD old_protect; + PVOID base_address; + SIZE_T region_size; + PBYTE sec_start; + PIMAGE_SECTION_HEADER hash; +} sSecInfo; + +static sSecInfo *the_secs = NULL; +static int maxSections = 0; + +static void +mark_section_writable (LPVOID addr) +{ + MEMORY_BASIC_INFORMATION b; + PIMAGE_SECTION_HEADER h; + int i; + + for (i = 0; i < maxSections; i++) + { + if (the_secs[i].sec_start <= ((LPBYTE) addr) + && ((LPBYTE) addr) < (the_secs[i].sec_start + the_secs[i].hash->Misc.VirtualSize)) + return; + } + h = __mingw_GetSectionForAddress (addr); + if (!h) + { + __report_error ("Address %p has no image-section", addr); + return; + } + the_secs[i].hash = h; + the_secs[i].old_protect = 0; + the_secs[i].sec_start = _GetPEImageBase () + h->VirtualAddress; + + if (!VirtualQuery (the_secs[i].sec_start, &b, sizeof(b))) + { + __report_error (" VirtualQuery failed for %d bytes at address %p", + (int) h->Misc.VirtualSize, the_secs[i].sec_start); + return; + } + + if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE + && b.Protect != PAGE_EXECUTE_WRITECOPY && b.Protect != PAGE_WRITECOPY) + { + the_secs[i].base_address = b.BaseAddress; + the_secs[i].region_size = b.RegionSize; + if (!VirtualProtect (b.BaseAddress, b.RegionSize, + PAGE_EXECUTE_READWRITE, + &the_secs[i].old_protect)) + __report_error (" VirtualProtect failed with code 0x%x", + (int) GetLastError ()); + } + ++maxSections; + return; +} + +static void +restore_modified_sections (void) +{ + int i; + DWORD oldprot; + + for (i = 0; i < maxSections; i++) + { + if (the_secs[i].old_protect == 0) + continue; + VirtualProtect (the_secs[i].base_address, the_secs[i].region_size, + the_secs[i].old_protect, &oldprot); + } +} + +#endif /* __MINGW64_VERSION_MAJOR */ + +/* This function temporarily marks the page containing addr + * writable, before copying len bytes from *src to *addr, and + * then restores the original protection settings to the page. + * + * Using this function eliminates the requirement with older + * pseudo-reloc implementations, that sections containing + * pseudo-relocs (such as .text and .rdata) be permanently + * marked writable. This older behavior sabotaged any memory + * savings achieved by shared libraries on win32 -- and was + * slower, too. However, on cygwin as of binutils 2.20 the + * .text section is still marked writable, and the .rdata section + * is folded into the (writable) .data when --enable-auto-import. + */ +static void +__write_memory (void *addr, const void *src, size_t len) +{ + if (!len) + return; + +#ifdef __MINGW64_VERSION_MAJOR + /* Mark the section writable once, and unset it in + * restore_modified_sections */ + mark_section_writable ((LPVOID) addr); +#else + MEMORY_BASIC_INFORMATION b; + DWORD oldprot = 0; + int call_unprotect = 0; + + if (!VirtualQuery (addr, &b, sizeof(b))) + { + __report_error (" VirtualQuery failed for %d bytes at address %p", + (int) sizeof(b), addr); + } + + /* Temporarily allow write access to read-only protected memory. */ + if (b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE + && b.Protect != PAGE_WRITECOPY && b.Protect != PAGE_EXECUTE_WRITECOPY) + { + call_unprotect = 1; + VirtualProtect (b.BaseAddress, b.RegionSize, PAGE_EXECUTE_READWRITE, + &oldprot); + } +#endif + + /* write the data. */ + memcpy (addr, src, len); + +#ifndef __MINGW64_VERSION_MAJOR + /* Restore original protection. */ + if (call_unprotect + && b.Protect != PAGE_EXECUTE_READWRITE && b.Protect != PAGE_READWRITE + && b.Protect != PAGE_WRITECOPY && b.Protect != PAGE_EXECUTE_WRITECOPY) + VirtualProtect (b.BaseAddress, b.RegionSize, oldprot, &oldprot); +#endif +} + +#define RP_VERSION_V1 0 +#define RP_VERSION_V2 1 + +static void +do_pseudo_reloc (void * start, void * end, void * base) +{ + ptrdiff_t addr_imp, reldata; + ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start); + runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start; + runtime_pseudo_reloc_item_v2 *r; + + /* A valid relocation list will contain at least one entry, and + * one v1 data structure (the smallest one) requires two DWORDs. + * So, if the relocation list is smaller than 8 bytes, bail. + */ + if (reloc_target < 8) + return; + + /* Check if this is the old pseudo relocation version. */ + /* There are two kinds of v1 relocation lists: + * 1) With a (v2-style) version header. In this case, the + * first entry in the list is a 3-DWORD structure, with + * value: + * { 0, 0, RP_VERSION_V1 } + * In this case, we skip to the next entry in the list, + * knowing that all elements after the head item can + * be cast to runtime_pseudo_reloc_item_v1. + * 2) Without a (v2-style) version header. In this case, the + * first element in the list IS an actual v1 relocation + * record, which is two DWORDs. Because there will never + * be a case where a v1 relocation record has both + * addend == 0 and target == 0, this case will not be + * confused with the prior one. + * All current binutils, when generating a v1 relocation list, + * use the second (e.g. original) form -- that is, without the + * v2-style version header. + */ + if (reloc_target >= 12 + && v2_hdr->magic1 == 0 && v2_hdr->magic2 == 0 + && v2_hdr->version == RP_VERSION_V1) + { + /* We have a list header item indicating that the rest + * of the list contains v1 entries. Move the pointer to + * the first true v1 relocation record. By definition, + * that v1 element will not have both addend == 0 and + * target == 0 (and thus, when interpreted as a + * runtime_pseudo_reloc_v2, it will not have both + * magic1 == 0 and magic2 == 0). + */ + v2_hdr++; + } + + if (v2_hdr->magic1 != 0 || v2_hdr->magic2 != 0) + { + /************************* + * Handle v1 relocations * + *************************/ + runtime_pseudo_reloc_item_v1 * o; + for (o = (runtime_pseudo_reloc_item_v1 *) v2_hdr; + o < (runtime_pseudo_reloc_item_v1 *)end; + o++) + { + DWORD newval; + reloc_target = (ptrdiff_t) base + o->target; + newval = (*((DWORD*) reloc_target)) + o->addend; + __write_memory ((void *) reloc_target, &newval, sizeof(DWORD)); + } + return; + } + + /* If we got this far, then we have relocations of version 2 or newer */ + + /* Check if this is a known version. */ + if (v2_hdr->version != RP_VERSION_V2) + { + __report_error (" Unknown pseudo relocation protocol version %d.\n", + (int) v2_hdr->version); + return; + } + + /************************* + * Handle v2 relocations * + *************************/ + + /* Walk over header. */ + r = (runtime_pseudo_reloc_item_v2 *) &v2_hdr[1]; + + for (; r < (runtime_pseudo_reloc_item_v2 *) end; r++) + { + /* location where new address will be written */ + reloc_target = (ptrdiff_t) base + r->target; + + /* get sym pointer. It points either to the iat entry + * of the referenced element, or to the stub function. + */ + addr_imp = (ptrdiff_t) base + r->sym; + addr_imp = *((ptrdiff_t *) addr_imp); + + /* read existing relocation value from image, casting to the + * bitsize indicated by the 8 LSBs of flags. If the value is + * negative, manually sign-extend to ptrdiff_t width. Raise an + * error if the bitsize indicated by the 8 LSBs of flags is not + * supported. + */ + switch ((r->flags & 0xff)) + { + case 8: + reldata = (ptrdiff_t) (*((unsigned char *)reloc_target)); + if ((reldata & 0x80) != 0) + reldata |= ~((ptrdiff_t) 0xff); + break; + case 16: + reldata = (ptrdiff_t) (*((unsigned short *)reloc_target)); + if ((reldata & 0x8000) != 0) + reldata |= ~((ptrdiff_t) 0xffff); + break; + case 32: + reldata = (ptrdiff_t) (*((unsigned int *)reloc_target)); +#ifdef _WIN64 + if ((reldata & 0x80000000) != 0) + reldata |= ~((ptrdiff_t) 0xffffffff); +#endif + break; +#ifdef _WIN64 + case 64: + reldata = (ptrdiff_t) (*((unsigned long long *)reloc_target)); + break; +#endif + default: + reldata=0; + __report_error (" Unknown pseudo relocation bit size %d.\n", + (int) (r->flags & 0xff)); + break; + } + + /* Adjust the relocation value */ + reldata -= ((ptrdiff_t) base + r->sym); + reldata += addr_imp; + + /* Write the new relocation value back to *reloc_target */ + switch ((r->flags & 0xff)) + { + case 8: + __write_memory ((void *) reloc_target, &reldata, 1); + break; + case 16: + __write_memory ((void *) reloc_target, &reldata, 2); + break; + case 32: + __write_memory ((void *) reloc_target, &reldata, 4); + break; +#ifdef _WIN64 + case 64: + __write_memory ((void *) reloc_target, &reldata, 8); + break; +#endif + } + } +} + +void +_pei386_runtime_relocator (void) +{ + static NO_COPY int was_init = 0; +#ifdef __MINGW64_VERSION_MAJOR + int mSecs; +#endif /* __MINGW64_VERSION_MAJOR */ + + if (was_init) + return; + ++was_init; +#ifdef __MINGW64_VERSION_MAJOR + mSecs = __mingw_GetSectionCount (); + the_secs = (sSecInfo *) alloca (sizeof (sSecInfo) * (size_t) mSecs); + maxSections = 0; +#endif /* __MINGW64_VERSION_MAJOR */ + + do_pseudo_reloc (&__RUNTIME_PSEUDO_RELOC_LIST__, + &__RUNTIME_PSEUDO_RELOC_LIST_END__, +#ifdef __GNUC__ + &__MINGW_LSYMBOL(_image_base__) +#else + &__ImageBase +#endif + ); +#ifdef __MINGW64_VERSION_MAJOR + restore_modified_sections (); +#endif /* __MINGW64_VERSION_MAJOR */ +} diff --git a/libc/mingw/crt/tlsmcrt.c b/libc/mingw/crt/tlsmcrt.c new file mode 100644 index 0000000000..506bc0ab97 --- /dev/null +++ b/libc/mingw/crt/tlsmcrt.c @@ -0,0 +1,13 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + * + * Written by Kai Tietz + */ + +/* We support TLS cleanup code in any case. If shared version of libgcc is used _CRT_MT has value 1, + otherwise + we do tls cleanup in runtime and _CRT_MT has value 2. */ +int _CRT_MT = 2; + diff --git a/libc/mingw/crt/tlsmthread.c b/libc/mingw/crt/tlsmthread.c new file mode 100644 index 0000000000..9e04b05aeb --- /dev/null +++ b/libc/mingw/crt/tlsmthread.c @@ -0,0 +1,33 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + * + * Written by Kai Tietz + */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +int __mingwthr_key_dtor (DWORD key, void (*dtor)(void *)); +int __mingwthr_remove_key_dtor (DWORD key); + +extern int ___w64_mingwthr_remove_key_dtor (DWORD key); +extern int ___w64_mingwthr_add_key_dtor (DWORD key, void (*dtor)(void *)); + +int +__mingwthr_remove_key_dtor (DWORD key) +{ + return ___w64_mingwthr_remove_key_dtor (key); +} + +int +__mingwthr_key_dtor (DWORD key, void (*dtor)(void *)) +{ + if (dtor) + return ___w64_mingwthr_add_key_dtor (key, dtor); + + return 0; +} diff --git a/libc/mingw/crt/tlssup.c b/libc/mingw/crt/tlssup.c new file mode 100644 index 0000000000..582fa8519e --- /dev/null +++ b/libc/mingw/crt/tlssup.c @@ -0,0 +1,175 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + * + * Written by Kai Tietz + */ + +#ifdef CRTDLL +#undef CRTDLL +#endif + +#include + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include + +#include +#include +#include +#include + +extern WINBOOL __mingw_TLScallback (HANDLE hDllHandle, DWORD reason, LPVOID reserved); + +#define FUNCS_PER_NODE 30 + +typedef struct TlsDtorNode { + int count; + struct TlsDtorNode *next; + _PVFV funcs[FUNCS_PER_NODE]; +} TlsDtorNode; + +ULONG _tls_index = 0; + +/* TLS raw template data start and end. + We use here pointer-types for start/end so that tls-data remains + aligned on pointer-size-width. This seems to be required for + pe-loader. */ +_CRTALLOC(".tls") char *_tls_start = NULL; +_CRTALLOC(".tls$ZZZ") char *_tls_end = NULL; + +_CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0; +_CRTALLOC(".CRT$XLZ") PIMAGE_TLS_CALLBACK __xl_z = 0; + +const IMAGE_TLS_DIRECTORY _tls_used = { + (ULONG_PTR) &_tls_start, (ULONG_PTR) &_tls_end, + (ULONG_PTR) &_tls_index, (ULONG_PTR) (&__xl_a+1), + (ULONG) 0, (ULONG) 0 +}; + +#ifndef __CRT_THREAD +#ifdef HAVE_ATTRIBUTE_THREAD +#define __CRT_THREAD __declspec(thread) +#else +#define __CRT_THREAD __thread +#endif +#endif + +#define DISABLE_MS_TLS 1 + +static _CRTALLOC(".CRT$XDA") _PVFV __xd_a = 0; +static _CRTALLOC(".CRT$XDZ") _PVFV __xd_z = 0; + +#if !defined (DISABLE_MS_TLS) +static __CRT_THREAD TlsDtorNode *dtor_list; +static __CRT_THREAD TlsDtorNode dtor_list_head; +#endif + +extern int _CRT_MT; + +BOOL WINAPI __dyn_tls_init (HANDLE, DWORD, LPVOID); + +BOOL WINAPI +__dyn_tls_init (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) +{ + _PVFV *pfunc; + uintptr_t ps; + + /* We don't let us trick here. */ + if (_CRT_MT != 2) + _CRT_MT = 2; + + if (dwReason != DLL_THREAD_ATTACH) + { + if (dwReason == DLL_PROCESS_ATTACH) + __mingw_TLScallback (hDllHandle, dwReason, lpreserved); + return TRUE; + } + + ps = (uintptr_t) &__xd_a; + ps += sizeof (uintptr_t); + for ( ; ps != (uintptr_t) &__xd_z; ps += sizeof (uintptr_t)) + { + pfunc = (_PVFV *) ps; + if (*pfunc != NULL) + (*pfunc)(); + } + return TRUE; +} + +const PIMAGE_TLS_CALLBACK __dyn_tls_init_callback = (const PIMAGE_TLS_CALLBACK) __dyn_tls_init; +_CRTALLOC(".CRT$XLC") PIMAGE_TLS_CALLBACK __xl_c = (PIMAGE_TLS_CALLBACK) __dyn_tls_init; + +int __cdecl __tlregdtor (_PVFV); + +int __cdecl +__tlregdtor (_PVFV func) +{ + if (!func) + return 0; +#if !defined (DISABLE_MS_TLS) + if (dtor_list == NULL) + { + dtor_list = &dtor_list_head; + dtor_list_head.count = 0; + } + else if (dtor_list->count == FUNCS_PER_NODE) + { + TlsDtorNode *pnode = (TlsDtorNode *) malloc (sizeof (TlsDtorNode)); + if (pnode == NULL) + return -1; + pnode->count = 0; + pnode->next = dtor_list; + dtor_list = pnode; + + dtor_list->count = 0; + } + dtor_list->funcs[dtor_list->count++] = func; +#endif + return 0; +} + +static BOOL WINAPI +__dyn_tls_dtor (HANDLE hDllHandle, DWORD dwReason, LPVOID lpreserved) +{ +#if !defined (DISABLE_MS_TLS) + TlsDtorNode *pnode, *pnext; + int i; +#endif + + if (dwReason != DLL_THREAD_DETACH && dwReason != DLL_PROCESS_DETACH) + return TRUE; + /* As TLS variables are detroyed already by DLL_THREAD_DETACH + call, we have to avoid access on the possible DLL_PROCESS_DETACH + call the already destroyed TLS vars. + TODO: The used local thread based variables have to be handled + manually, so that we can control their lifetime here. */ +#if !defined (DISABLE_MS_TLS) + if (dwReason != DLL_PROCESS_DETACH) + { + for (pnode = dtor_list; pnode != NULL; pnode = pnext) + { + for (i = pnode->count - 1; i >= 0; --i) + { + if (pnode->funcs[i] != NULL) + (*pnode->funcs[i])(); + } + pnext = pnode->next; + if (pnext != NULL) + free ((void *) pnode); + } + } +#endif + __mingw_TLScallback (hDllHandle, dwReason, lpreserved); + return TRUE; +} + +_CRTALLOC(".CRT$XLD") PIMAGE_TLS_CALLBACK __xl_d = (PIMAGE_TLS_CALLBACK) __dyn_tls_dtor; + + +int mingw_initltsdrot_force = 0; +int mingw_initltsdyn_force = 0; +int mingw_initltssuo_force = 0; diff --git a/libc/mingw/crt/tlsthrd.c b/libc/mingw/crt/tlsthrd.c new file mode 100644 index 0000000000..bebe27b370 --- /dev/null +++ b/libc/mingw/crt/tlsthrd.c @@ -0,0 +1,158 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + * + * Written by Kai Tietz + * + * This file is used by if gcc is built with --enable-threads=win32. + * + * Based on version created by Mumit Khan + * + */ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +extern void __cdecl __MINGW_NOTHROW _fpreset (void); +WINBOOL __mingw_TLScallback (HANDLE hDllHandle, DWORD reason, LPVOID reserved); +int ___w64_mingwthr_remove_key_dtor (DWORD key); +int ___w64_mingwthr_add_key_dtor (DWORD key, void (*dtor)(void *)); + +/* To protect the thread/key association data structure modifications. */ +static CRITICAL_SECTION __mingwthr_cs; +static volatile int __mingwthr_cs_init = 0; + +typedef struct __mingwthr_key __mingwthr_key_t; + +/* The list of threads active with key/dtor pairs. */ +struct __mingwthr_key { + DWORD key; + void (*dtor)(void *); + __mingwthr_key_t volatile *next; +}; + + +static __mingwthr_key_t volatile *key_dtor_list; + +int +___w64_mingwthr_add_key_dtor (DWORD key, void (*dtor)(void *)) +{ + __mingwthr_key_t *new_key; + + if (__mingwthr_cs_init == 0) + return 0; + new_key = (__mingwthr_key_t *) calloc (1, sizeof (__mingwthr_key_t)); + if (new_key == NULL) + return -1; + + new_key->key = key; + new_key->dtor = dtor; + + EnterCriticalSection (&__mingwthr_cs); + + new_key->next = key_dtor_list; + key_dtor_list = new_key; + + LeaveCriticalSection (&__mingwthr_cs); + return 0; +} + +int +___w64_mingwthr_remove_key_dtor (DWORD key) +{ + __mingwthr_key_t volatile *prev_key; + __mingwthr_key_t volatile *cur_key; + + if (__mingwthr_cs_init == 0) + return 0; + + EnterCriticalSection (&__mingwthr_cs); + + prev_key = NULL; + cur_key = key_dtor_list; + + while (cur_key != NULL) + { + if ( cur_key->key == key) + { + if (prev_key == NULL) + key_dtor_list = cur_key->next; + else + prev_key->next = cur_key->next; + + free ((void*)cur_key); + break; + } + prev_key = cur_key; + cur_key = cur_key->next; + } + + LeaveCriticalSection (&__mingwthr_cs); + return 0; +} + +static void +__mingwthr_run_key_dtors (void) +{ + __mingwthr_key_t volatile *keyp; + + if (__mingwthr_cs_init == 0) + return; + EnterCriticalSection (&__mingwthr_cs); + + for (keyp = key_dtor_list; keyp; ) + { + LPVOID value = TlsGetValue (keyp->key); + if (GetLastError () == ERROR_SUCCESS) + { + if (value) + (*keyp->dtor) (value); + } + keyp = keyp->next; + } + + LeaveCriticalSection (&__mingwthr_cs); +} + +WINBOOL +__mingw_TLScallback (HANDLE __UNUSED_PARAM(hDllHandle), + DWORD reason, + LPVOID __UNUSED_PARAM(reserved)) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + if (__mingwthr_cs_init == 0) + InitializeCriticalSection (&__mingwthr_cs); + __mingwthr_cs_init = 1; + break; + case DLL_PROCESS_DETACH: + __mingwthr_run_key_dtors(); + if (__mingwthr_cs_init == 1) + { + __mingwthr_key_t volatile *keyp, *t; + for (keyp = key_dtor_list; keyp; ) + { + t = keyp->next; + free((void *)keyp); + keyp = t; + } + key_dtor_list = NULL; + __mingwthr_cs_init = 0; + DeleteCriticalSection (&__mingwthr_cs); + } + break; + case DLL_THREAD_ATTACH: + _fpreset(); + break; + case DLL_THREAD_DETACH: + __mingwthr_run_key_dtors(); + break; + } + return TRUE; +} + diff --git a/libc/mingw/crt/udll_argv.c b/libc/mingw/crt/udll_argv.c new file mode 100644 index 0000000000..a60927cffe --- /dev/null +++ b/libc/mingw/crt/udll_argv.c @@ -0,0 +1,16 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#ifndef UNICODE +#define UNICODE +#endif +#ifndef _UNICODE +#define _UNICODE +#endif +#define WPRFLAG 1 + +#include "dll_argv.c" + diff --git a/libc/mingw/crt/udllargc.c b/libc/mingw/crt/udllargc.c new file mode 100644 index 0000000000..f6ab6b1a77 --- /dev/null +++ b/libc/mingw/crt/udllargc.c @@ -0,0 +1,16 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +#ifndef UNICODE +#define UNICODE +#endif +#ifndef _UNICODE +#define _UNICODE +#endif +#define WPRFLAG 1 + +#include "dllargv.c" + diff --git a/libc/mingw/crt/wildcard.c b/libc/mingw/crt/wildcard.c new file mode 100644 index 0000000000..b53cc18ec0 --- /dev/null +++ b/libc/mingw/crt/wildcard.c @@ -0,0 +1,33 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +/* _dowildcard is an int that controls the globbing of the command line. + * If _dowildcard is non-zero, the command line will be globbed: *.* + * will be expanded to be all files in the startup directory. + * + * In the mingw-w64 library the _dowildcard variable is defined as being + * 0, therefore command line globbing is DISABLED by default. To turn it + * on and to leave wildcard command line processing MS's globbing code, + * include a line in one of your source modules defining _dowildcard and + * setting it to -1, like so: + * int _dowildcard = -1; + * + * Alternatively, the mingw-w64 library can be configured using the + * --enable-wildcard option and compiled thusly upon which the resulting + * library will have _dowildcard as -1 and command line globbing will be + * enabled by default. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifndef __ENABLE_GLOBBING +#define __ENABLE_GLOBBING 0 /* -1 */ +#endif + +int _dowildcard = __ENABLE_GLOBBING; + diff --git a/libc/mingw/crt/xncommod.c b/libc/mingw/crt/xncommod.c new file mode 100644 index 0000000000..b2ec312f09 --- /dev/null +++ b/libc/mingw/crt/xncommod.c @@ -0,0 +1,7 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +int _commode = 0; diff --git a/libc/mingw/crt/xthdloc.c b/libc/mingw/crt/xthdloc.c new file mode 100644 index 0000000000..973ff45b16 --- /dev/null +++ b/libc/mingw/crt/xthdloc.c @@ -0,0 +1,7 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ + +int __globallocalestatus = ~0x1; diff --git a/libc/mingw/crt/xtxtmode.c b/libc/mingw/crt/xtxtmode.c new file mode 100644 index 0000000000..dcbbe11846 --- /dev/null +++ b/libc/mingw/crt/xtxtmode.c @@ -0,0 +1,6 @@ +/** + * This file has no copyright assigned and is placed in the Public Domain. + * This file is part of the mingw-w64 runtime package. + * No warranty is given; refer to the file DISCLAIMER.PD within this package. + */ +int _fmode = 0; diff --git a/libc/mingw/def-include/func.def.in b/libc/mingw/def-include/func.def.in new file mode 100644 index 0000000000..58cc36d860 --- /dev/null +++ b/libc/mingw/def-include/func.def.in @@ -0,0 +1,57 @@ +// F32 - function available on all 32 bit architectures +// F64 - function available on all 64 bit architectures +// F_X86_ANY - function available on i386 and x86_64 +// F_I386 - function available only on i386 +// F_X64 - function available only on x86_64 +// F_ARM32 - function available only on arm32 +// F_ARM64 - function available only on arm64 +// F_ARM_ANY - function available on 32 and 64 bit arm +// F_NON_I386 - function available on everything but i386 +#if defined(DEF_X64) +#define F64(x) x +#define F_X64(x) x +#define F_X86_ANY(x) x +#define F_NON_I386(x) x +#elif defined(DEF_I386) +#define F32(x) x +#define F_I386(x) x +#define F_X86_ANY(x) x +#elif defined(DEF_ARM32) +#define F32(x) x +#define F_ARM32(x) x +#define F_ARM_ANY(x) x +#define F_NON_I386(x) x +#elif defined(DEF_ARM64) +#define F64(x) x +#define F_ARM64(x) x +#define F_ARM_ANY(x) x +#define F_NON_I386(x) x +#endif + +#ifndef F32 +#define F32(x) +#endif +#ifndef F64 +#define F64(x) +#endif +#ifndef F_X86_ANY +#define F_X86_ANY(x) +#endif +#ifndef F_I386 +#define F_I386(x) +#endif +#ifndef F_X64 +#define F_X64(x) +#endif +#ifndef F_ARM_ANY +#define F_ARM_ANY(x) +#endif +#ifndef F_ARM32 +#define F_ARM32(x) +#endif +#ifndef F_ARM64 +#define F_ARM64(x) +#endif +#ifndef F_NON_I386 +#define F_NON_I386(x) +#endif diff --git a/libc/mingw/def-include/msvcrt-common.def.in b/libc/mingw/def-include/msvcrt-common.def.in new file mode 100644 index 0000000000..364e4409dd --- /dev/null +++ b/libc/mingw/def-include/msvcrt-common.def.in @@ -0,0 +1,145 @@ +#define ADD_UNDERSCORE(symbol) symbol == _ ## symbol +#define ADD_DOUBLE_UNDERSCORE(symbol) symbol == __ ## symbol + +ADD_DOUBLE_UNDERSCORE(iscsymf) +ADD_DOUBLE_UNDERSCORE(iscsym) +ADD_DOUBLE_UNDERSCORE(isascii) +ADD_DOUBLE_UNDERSCORE(toascii) + +wcscmpi == _wcsicmp +strcasecmp == _stricmp +strncasecmp == _strnicmp + +ADD_UNDERSCORE(access) +ADD_UNDERSCORE(chdir) +ADD_UNDERSCORE(chmod) +ADD_UNDERSCORE(chsize) +ADD_UNDERSCORE(close) +ADD_UNDERSCORE(creat) +ADD_UNDERSCORE(cwait) +ADD_UNDERSCORE(dup) +ADD_UNDERSCORE(dup2) +ADD_UNDERSCORE(ecvt) +ADD_UNDERSCORE(eof) +ADD_UNDERSCORE(execl) +ADD_UNDERSCORE(execle) +ADD_UNDERSCORE(execlp) +ADD_UNDERSCORE(execlpe) +ADD_UNDERSCORE(execv) +ADD_UNDERSCORE(execve) +ADD_UNDERSCORE(execvp) +ADD_UNDERSCORE(execvpe) +ADD_UNDERSCORE(fcvt) +ADD_UNDERSCORE(fdopen) +ADD_UNDERSCORE(fgetchar) +ADD_UNDERSCORE(fgetwchar) +ADD_UNDERSCORE(filelength) +ADD_UNDERSCORE(fileno) +; fpreset) +ADD_UNDERSCORE(fputchar) +ADD_UNDERSCORE(fputwchar) +;fstat) +;ftime) +ADD_UNDERSCORE(gcvt) +ADD_UNDERSCORE(getch) +ADD_UNDERSCORE(getche) +ADD_UNDERSCORE(getcwd) +ADD_UNDERSCORE(getpid) +ADD_UNDERSCORE(getw) +ADD_UNDERSCORE(heapwalk) +ADD_UNDERSCORE(isatty) +ADD_UNDERSCORE(itoa) +ADD_UNDERSCORE(kbhit) +ADD_UNDERSCORE(lfind) +ADD_UNDERSCORE(lsearch) +ADD_UNDERSCORE(lseek) +ADD_UNDERSCORE(ltoa) +ADD_UNDERSCORE(memccpy) +ADD_UNDERSCORE(memicmp) +ADD_UNDERSCORE(mkdir) +ADD_UNDERSCORE(mktemp) +ADD_UNDERSCORE(open) +ADD_UNDERSCORE(pclose) +ADD_UNDERSCORE(popen) +ADD_UNDERSCORE(putch) +ADD_UNDERSCORE(putenv) +ADD_UNDERSCORE(putw) +ADD_UNDERSCORE(read) +ADD_UNDERSCORE(rmdir) +ADD_UNDERSCORE(rmtmp) +ADD_UNDERSCORE(searchenv) +ADD_UNDERSCORE(setmode) +ADD_UNDERSCORE(sopen) +ADD_UNDERSCORE(spawnl) +ADD_UNDERSCORE(spawnle) +ADD_UNDERSCORE(spawnlp) +ADD_UNDERSCORE(spawnlpe) +ADD_UNDERSCORE(spawnv) +ADD_UNDERSCORE(spawnve) +ADD_UNDERSCORE(spawnvp) +ADD_UNDERSCORE(spawnvpe) +;stat) +#ifndef UCRTBASE +ADD_UNDERSCORE(strcmpi) +#endif +ADD_UNDERSCORE(strdup) +ADD_UNDERSCORE(stricmp) +ADD_UNDERSCORE(stricoll) +ADD_UNDERSCORE(strlwr) +ADD_UNDERSCORE(strnicmp) +ADD_UNDERSCORE(strnset) +ADD_UNDERSCORE(strrev) +ADD_UNDERSCORE(strset) +ADD_UNDERSCORE(strupr) +ADD_UNDERSCORE(swab) +ADD_UNDERSCORE(tell) +ADD_UNDERSCORE(tempnam) +#ifndef UCRTBASE +ADD_UNDERSCORE(tzset) +#endif +ADD_UNDERSCORE(umask) +ADD_UNDERSCORE(ungetch) +ADD_UNDERSCORE(unlink) +#ifndef UCRTBASE +ADD_UNDERSCORE(utime) +#endif +ADD_UNDERSCORE(wcsdup) +ADD_UNDERSCORE(wcsicmp) +ADD_UNDERSCORE(wcsicoll) +ADD_UNDERSCORE(wcslwr) +ADD_UNDERSCORE(wcsnicmp) +ADD_UNDERSCORE(wcsnset) +ADD_UNDERSCORE(wcsrev) +ADD_UNDERSCORE(wcsset) +ADD_UNDERSCORE(wcsupr) +ADD_UNDERSCORE(wpopen) +ADD_UNDERSCORE(write) +; non-ANSI functions declared in math.h +ADD_UNDERSCORE(j0) +ADD_UNDERSCORE(j1) +ADD_UNDERSCORE(jn) +ADD_UNDERSCORE(y0) +ADD_UNDERSCORE(y1) +ADD_UNDERSCORE(yn) +ADD_UNDERSCORE(chgsign) +;scalb +ADD_UNDERSCORE(finite) +ADD_UNDERSCORE(fpclass) +; C99 functions +;cabs +ADD_UNDERSCORE(hypot) +;logb +ADD_UNDERSCORE(nextafter) + +#ifndef UCRTBASE +_daylight DATA +_timezone DATA +_tzname DATA +ADD_UNDERSCORE(daylight) +ADD_UNDERSCORE(timezone) +ADD_UNDERSCORE(tzname) + +ADD_UNDERSCORE(vsnprintf_s) + +longjmp DATA +#endif diff --git a/libc/mingw/include/config.h b/libc/mingw/include/config.h new file mode 100644 index 0000000000..45931b832a --- /dev/null +++ b/libc/mingw/include/config.h @@ -0,0 +1,74 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Whether the linker provides __CTOR_LIST__ */ +/* #undef HAVE_CTOR_LIST */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Name of package */ +#define PACKAGE "mingw-w64-runtime" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "mingw-w64-public@lists.sourceforge.net" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "mingw-w64-runtime" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "mingw-w64-runtime 4.0b" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "mingw-w64-runtime" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "4.0b" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Version number of package */ +#define VERSION "4.0b" + +/* Build DFP support */ +/* #undef __ENABLE_DFP */ + +/* Define as -1 to enable command line globbing or 0 to disable it. */ +#define __ENABLE_GLOBBING 0 + +/* Build DFP support */ +/* #undef __ENABLE_PRINTF128 */ + +/* Build DFP support */ +/* #undef __ENABLE_REGISTEREDPRINTF */ + +/* Build softmath routines */ +/* #undef __ENABLE_SOFTMATH */ diff --git a/libc/mingw/lib-common/msvcrt.def.in b/libc/mingw/lib-common/msvcrt.def.in new file mode 100644 index 0000000000..1a1db2b4e0 --- /dev/null +++ b/libc/mingw/lib-common/msvcrt.def.in @@ -0,0 +1,1577 @@ +LIBRARY "msvcrt.dll" +EXPORTS + +#include "func.def.in" +#include "msvcrt-common.def.in" + +#ifdef DEF_I386 +_CIacos +_CIasin +_CIatan +_CIatan2 +_CIcos +_CIcosh +_CIexp +_CIfmod +_CIlog +_CIlog10 +_CIpow +_CIsin +_CIsinh +_CIsqrt +_CItan +_CItanh +#endif + +#ifdef DEF_X64 +$I10_OUTPUT +; public: __cdecl __non_rtti_object::__non_rtti_object(class __non_rtti_object const & __ptr64) __ptr64 +; GCC = __ZN17__non_rtti_objectC2ERKS_ +??0__non_rtti_object@@QEAA@AEBV0@@Z +; public: __cdecl __non_rtti_object::__non_rtti_object(char const * __ptr64) __ptr64 +; GCC = __ZN17__non_rtti_objectC1ERKS_ +??0__non_rtti_object@@QEAA@PEBD@Z +; private: __cdecl bad_cast::bad_cast(char const * __ptr64 const * __ptr64) __ptr64 +??0bad_cast@@AEAA@PEBQEBD@Z +; public: __cdecl bad_cast::bad_cast(char const * __ptr64 const & __ptr64) __ptr64 +??0bad_cast@@QEAA@AEBQEBD@Z +; public: __cdecl bad_cast::bad_cast(class bad_cast const & __ptr64) __ptr64 +??0bad_cast@@QEAA@AEBV0@@Z +; public: __cdecl bad_cast::bad_cast(char const * __ptr64) __ptr64 +??0bad_cast@@QEAA@PEBD@Z +; public: __cdecl bad_typeid::bad_typeid(class bad_typeid const & __ptr64) __ptr64 +??0bad_typeid@@QEAA@AEBV0@@Z +; public: __cdecl bad_typeid::bad_typeid(char const * __ptr64) __ptr64 +??0bad_typeid@@QEAA@PEBD@Z +; public: __cdecl exception::exception(char const * __ptr64 const & __ptr64) __ptr64 +??0exception@@QEAA@AEBQEBD@Z +; public: __cdecl exception::exception(char const * __ptr64 const & __ptr64,int) __ptr64 +??0exception@@QEAA@AEBQEBDH@Z +; public: __cdecl exception::exception(class exception const & __ptr64) __ptr64 +??0exception@@QEAA@AEBV0@@Z +; public: __cdecl exception::exception(void) __ptr64 +??0exception@@QEAA@XZ +; public: virtual __cdecl __non_rtti_object::~__non_rtti_object(void) __ptr64 +??1__non_rtti_object@@UEAA@XZ +; public: virtual __cdecl bad_cast::~bad_cast(void) __ptr64 +??1bad_cast@@UEAA@XZ +; public: virtual __cdecl bad_typeid::~bad_typeid(void) __ptr64 +??1bad_typeid@@UEAA@XZ +; public: virtual __cdecl exception::~exception(void) __ptr64 +??1exception@@UEAA@XZ +; public: virtual __cdecl type_info::~type_info(void) __ptr64 +??1type_info@@UEAA@XZ +; void * __ptr64 __cdecl operator new(unsigned __int64) +; GCC = __Znwy +??2@YAPEAX_K@Z +; void __cdecl operator delete(void * __ptr64) +; GCC = __ZdlPv +??3@YAXPEAX@Z +; public: class __non_rtti_object & __ptr64 __cdecl __non_rtti_object::operator=(class __non_rtti_object const & __ptr64) __ptr64 +??4__non_rtti_object@@QEAAAEAV0@AEBV0@@Z +; public: class bad_cast & __ptr64 __cdecl bad_cast::operator=(class bad_cast const & __ptr64) __ptr64 +??4bad_cast@@QEAAAEAV0@AEBV0@@Z +; public: class bad_typeid & __ptr64 __cdecl bad_typeid::operator=(class bad_typeid const & __ptr64) __ptr64 +??4bad_typeid@@QEAAAEAV0@AEBV0@@Z +; public: class exception & __ptr64 __cdecl exception::operator=(class exception const & __ptr64) __ptr64 +??4exception@@QEAAAEAV0@AEBV0@@Z +; public: int __cdecl type_info::operator==(class type_info const & __ptr64)const __ptr64 +??8type_info@@QEBAHAEBV0@@Z +; public: int __cdecl type_info::operator!=(class type_info const & __ptr64)const __ptr64 +??9type_info@@QEBAHAEBV0@@Z +; const __non_rtti_object::`vftable' +??_7__non_rtti_object@@6B@ +; const bad_cast::`vftable' +??_7bad_cast@@6B@ +; const bad_typeid::`vftable' +??_7bad_typeid@@6B@ +; const exception::`vftable' +??_7exception@@6B@ +; public: void __cdecl bad_cast::`default constructor closure'(void) __ptr64 +??_Fbad_cast@@QEAAXXZ +; public: void __cdecl bad_typeid::`default constructor closure'(void) __ptr64 +??_Fbad_typeid@@QEAAXXZ +; void * __ptr64 __cdecl operator new[](unsigned __int64) +; GNU = __Znay +??_U@YAPEAX_K@Z +; void __cdecl operator delete[](void * __ptr64) +; GNU = __ZdaPv +??_V@YAXPEAX@Z +; int (__cdecl*__cdecl _query_new_handler(void))(unsigned __int64) +; GNU = __Z18_query_new_handlerv +?_query_new_handler@@YAP6AH_K@ZXZ +; int __cdecl _query_new_mode(void) +; GNU = __Z15_query_new_modev +?_query_new_mode@@YAHXZ +; int (__cdecl*__cdecl _set_new_handler(int (__cdecl*)(unsigned __int64)))(unsigned __int64) +; GNU = __Z16_set_new_handlerPFiyE +?_set_new_handler@@YAP6AH_K@ZP6AH0@Z@Z +; int __cdecl _set_new_mode(int) +; GNU = __Z13_set_new_modei +?_set_new_mode@@YAHH@Z +; void (__cdecl*__cdecl _set_se_translator(void (__cdecl*)(unsigned int,struct _EXCEPTION_POINTERS * __ptr64)))(unsigned int,struct _EXCEPTION_POINTERS * __ptr64) +; GNU = __Z18_set_se_translatorPFvjP19_EXCEPTION_POINTERSE +?_set_se_translator@@YAP6AXIPEAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z +; public: int __cdecl type_info::before(class type_info const & __ptr64)const __ptr64 +?before@type_info@@QEBAHAEBV1@@Z +; public: char const * __ptr64 __cdecl type_info::name(void)const __ptr64 +?name@type_info@@QEBAPEBDXZ +; public: char const * __ptr64 __cdecl type_info::raw_name(void)const __ptr64 +?raw_name@type_info@@QEBAPEBDXZ +; void (__cdecl*__cdecl set_new_handler(void (__cdecl*)(void)))(void) +; GNU = __Z15set_new_handlerPFvvE +?set_new_handler@@YAP6AXXZP6AXXZ@Z +; void (__cdecl*__cdecl set_terminate(void (__cdecl*)(void)))(void) +; GNU = __Z13set_terminatePFvvE +?set_terminate@@YAP6AXXZP6AXXZ@Z +; void (__cdecl*__cdecl set_unexpected(void (__cdecl*)(void)))(void) +; GNU = __Z14set_unexpectedPFvvE +?set_unexpected@@YAP6AXXZP6AXXZ@Z +; void __cdecl terminate(void) +; GNU = __Z9terminatev +?terminate@@YAXXZ +; void __cdecl unexpected(void) +; GNU = __Z10unexpectedv +?unexpected@@YAXXZ +; public: virtual char const * __ptr64 __cdecl exception::what(void)const __ptr64 +?what@exception@@UEBAPEBDXZ +#endif + +#ifdef DEF_ARM32 +??0__non_rtti_object@@QAA@ABV0@@Z +??0__non_rtti_object@@QAA@PBD@Z +??0bad_cast@@AAA@PBQBD@Z +??0bad_cast@@QAA@ABV0@@Z +??0bad_cast@@QAA@PBD@Z +??0bad_typeid@@QAA@ABV0@@Z +??0bad_typeid@@QAA@PBD@Z +??0exception@@QAA@ABQBD@Z +??0exception@@QAA@ABQBDH@Z +??0exception@@QAA@ABV0@@Z +??0exception@@QAA@XZ +??1__non_rtti_object@@UAA@XZ +??1bad_cast@@UAA@XZ +??1bad_typeid@@UAA@XZ +??1exception@@UAA@XZ +??1type_info@@UAA@XZ +??2@YAPAXI@Z +??2@YAPAXIHPBDH@Z +??3@YAXPAX@Z +??4__non_rtti_object@@QAAAAV0@ABV0@@Z +??4bad_cast@@QAAAAV0@ABV0@@Z +??4bad_typeid@@QAAAAV0@ABV0@@Z +??4exception@@QAAAAV0@ABV0@@Z +??8type_info@@QBAHABV0@@Z +??9type_info@@QBAHABV0@@Z +??_7__non_rtti_object@@6B@ DATA +??_7bad_cast@@6B@ DATA +??_7bad_typeid@@6B@ DATA +??_7exception@@6B@ DATA +??_Fbad_cast@@QAAXXZ +??_Fbad_typeid@@QAAXXZ +??_U@YAPAXI@Z +??_U@YAPAXIHPBDH@Z +??_V@YAXPAX@Z +_CallMemberFunction0 +_CallMemberFunction1 +_CallMemberFunction2 +__ExceptionPtrAssign +__ExceptionPtrCompare +__ExceptionPtrCopy +__ExceptionPtrCopyException +__ExceptionPtrCreate +__ExceptionPtrCurrentException +__ExceptionPtrDestroy +__ExceptionPtrRethrow +__ExceptionPtrSwap +__ExceptionPtrToBool +?_query_new_handler@@YAP6AHI@ZXZ +?_set_new_handler@@YAP6AHI@ZP6AHI@Z@Z +?_set_new_mode@@YAHH@Z +?_set_se_translator@@YAP6AXIPAU_EXCEPTION_POINTERS@@@ZP6AXI0@Z@Z +?before@type_info@@QBAHABV1@@Z +?name@type_info@@QBAPBDXZ +?raw_name@type_info@@QBAPBDXZ +?set_terminate@@YAP6AXXZP6AXXZ@Z +?set_unexpected@@YAP6AXXZP6AXXZ@Z +?terminate@@YAXXZ +?unexpected@@YAXXZ +?what@exception@@UBAPBDXZ +#endif + +#ifdef DEF_ARM32 +_CrtCheckMemory +_CrtDbgBreak +_CrtDbgReport +_CrtDbgReportV +_CrtDbgReportW +_CrtDbgReportWV +_CrtDoForAllClientObjects +_CrtDumpMemoryLeaks +_CrtIsMemoryBlock +_CrtIsValidHeapPointer +_CrtIsValidPointer +_CrtMemCheckpoint +_CrtMemDifference +_CrtMemDumpAllObjectsSince +_CrtMemDumpStatistics +_CrtReportBlockType +_CrtSetAllocHook +_CrtSetBreakAlloc +_CrtSetDbgBlockType +_CrtSetDbgFlag +_CrtSetDumpClient +_CrtSetReportFile +_CrtSetReportHook +_CrtSetReportHook2 +_CrtSetReportMode +#endif +_CxxThrowException +F_I386(_EH_prolog) +_Getdays +_Getmonths +_Gettnames +_HUGE DATA +_Strftime +F_ARM_ANY(_W_Getdays) +F_ARM_ANY(_W_Getmonths) +F_ARM_ANY(_W_Gettnames) +F_ARM_ANY(_Wcsftime) +_XcptFilter +F_ARM_ANY(__AdjustPointer) +F_NON_I386(__C_specific_handler) +__CppXcptFilter +F_I386(__CxxCallUnwindDtor) +F_I386(__CxxCallUnwindVecDtor) +F_I386(__CxxDetectRethrow) +F_I386(__CxxExceptionFilter) +__CxxFrameHandler +F_ARM_ANY(__CxxFrameHandler3) +F_I386(__CxxLongjmpUnwind) +F_I386(__CxxQueryExceptionSize) +F_I386(__CxxRegisterExceptionObject) +F_I386(__CxxUnregisterExceptionObject) +__DestructExceptionObject +__RTCastToVoid +__RTDynamicCast +__RTtypeid +__STRINGTOLD +F_NON_I386(___lc_codepage_func) +___lc_collate_cp_func +___lc_handle_func +___mb_cur_max_func +___setlc_active_func +___unguarded_readlc_active_add_func +__argc DATA +__argv DATA +__badioinfo DATA +F_I386(__buffer_overrun) +__crtCompareStringA +__crtCompareStringW +__crtGetLocaleInfoW +__crtGetStringTypeW +__crtLCMapStringA +__crtLCMapStringW +F_ARM_ANY(__daylight) +__dllonexit +__doserrno +F_ARM_ANY(__dstbias) +__fpecode +__getmainargs +F_X86_ANY(__initenv DATA) +__iob_func +__isascii +__iscsym +__iscsymf +F_I386(__lc_clike) +__lc_codepage DATA +__lc_collate_cp DATA +__lc_handle DATA +__lconv_init +__mb_cur_max DATA +#ifdef DEF_I386 +__p___argc +__p___argv +__p___initenv +__p___mb_cur_max +__p___wargv +__p___winitenv +__p__acmdln +__p__amblksiz +__p__commode +__p__daylight +__p__dstbias +__p__environ +__p__fileinfo +__p__fmode +__p__iob +__p__mbcasemap +__p__mbctype +__p__osver +__p__pctype +__p__pgmptr +__p__pwctype +__p__timezone +__p__tzname +__p__wcmdln +__p__wenviron +__p__winmajor +__p__winminor +__p__winver +__p__wpgmptr +#endif +__pctype_func +__pioinfo DATA +__pwctype_func +__pxcptinfoptrs +F_I386(__security_error_handler) +__set_app_type +F_I386(__set_buffer_overrun_handler) +__setlc_active DATA +__setusermatherr +F_ARM_ANY(__strncnt) +__threadhandle +__threadid +__toascii +__uncaught_exception +__unDName +__unDNameEx +__unguarded_readlc_active DATA +__wargv DATA +__wcserror +F_NON_I386(__wcserror_s) +F_ARM_ANY(__wcsncnt) +__wgetmainargs +F_X86_ANY(__winitenv DATA) +F_I386(_abnormal_termination) +F_NON_I386(_abs64) +_access +; _access_s Replaced by emu +_acmdln DATA +#ifdef DEF_I386 +_adj_fdiv_m16i +_adj_fdiv_m32 +_adj_fdiv_m32i +_adj_fdiv_m64 +_adj_fdiv_r +_adj_fdivr_m16i +_adj_fdivr_m32 +_adj_fdivr_m32i +_adj_fdivr_m64 +_adj_fpatan +_adj_fprem +_adj_fprem1 +_adj_fptan +_adjust_fdiv DATA +#endif +_aexit_rtn DATA +_aligned_free +F_ARM_ANY(_aligned_free_dbg) +_aligned_malloc +F_ARM_ANY(_aligned_malloc_dbg) +_aligned_offset_malloc +F_ARM_ANY(_aligned_offset_malloc_dbg) +_aligned_offset_realloc +F_ARM_ANY(_aligned_offset_realloc_dbg) +_aligned_realloc +F_ARM_ANY(_aligned_realloc_dbg) +_amsg_exit +_assert DATA +_atodbl +_atodbl_l +_atof_l +_atoflt_l +_atoi64 +_atoi64_l +_atoi_l +_atol_l +_atoldbl +F_NON_I386(_atoldbl_l) +_beep +_beginthread +_beginthreadex +_c_exit +_cabs DATA +_callnewh +F_ARM_ANY(_calloc_dbg) +_cexit +_cgets +; _cgets_s replaced by emu +_cgetws +; _cgetws_s replaced by emu +_chdir +_chdrive +_chgsign +F_NON_I386(_chgsignf) +_chmod +F_I386(_chkesp) +_chsize +; _chsize_s replaced by emu +F_ARM_ANY(_chvalidator) +F_ARM_ANY(_chvalidator_l) +_clearfp +_close +_commit +_commode DATA +_control87 +_controlfp +; _controlfp_s replaced by emu +_copysign +F_NON_I386(_copysignf) +_cprintf +_cprintf_l +_cprintf_p +_cprintf_p_l +; _cprintf_s Replaced by emu +; _cprintf_s_l likewise. +_cputs +_cputws +F_I386(_CRT_RTC_INIT) +_creat +_create_locale +F_ARM32(_crtAssertBusy) +F_ARM32(_crtBreakAlloc) +F_ARM32(_crtDbgFlag) +_cscanf +_cscanf_l +_cscanf_s +_cscanf_s_l +F_ARM_ANY(_ctime32) +F_I386(_ctime32 == ctime) +; _ctime32_s replaced by emu +_ctime64 +; _ctime64_s replaced by emu +_ctype F_I386(DATA) +_cwait +_cwprintf +_cwprintf_l +_cwprintf_p +_cwprintf_p_l +; _cwprintf_s Replaced by emu +; _cwprintf_s_l Likewise. +_cwscanf +_cwscanf_l +_cwscanf_s +_cwscanf_s_l +_dstbias DATA +F_ARM_ANY(_daylight DATA) +F_ARM_ANY(_difftime32) +F_ARM_ANY(_difftime64) +_dup +_dup2 +_ecvt +_ecvt_s +_endthread +_endthreadex +F_X86_ANY(_environ DATA) +_eof +_errno +F_I386(_except_handler2) +F_I386(_except_handler3) +_execl +_execle +_execlp +_execlpe +_execv +_execve +_execvp +_execvpe +_exit +_expand +F_ARM_ANY(_expand_dbg) +_fcloseall +_fcvt +_fcvt_s +_fdopen +_fgetchar +_fgetwchar +_filbuf +F_X86_ANY(_fileinfo DATA) +_filelength +_filelengthi64 +_fileno +_findclose +_findfirst +F32(_findfirst32 == _findfirst) +_findfirst64 +_findfirsti64 +F32(_findfirst32i64 == _findfirsti64) +F64(_findfirst64i32 == _findfirst) +_findnext +F32(_findnext32 == _findnext) +_findnext64 +_findnexti64 +F32(_findnext32i64 == _findnexti64) +F64(_findnext64i32 == _findnext) +_finite +F_NON_I386(_finitef) +_flsbuf +_flushall +_fmode DATA +_fpclass +F_X64(_fpclassf) +F_I386(_fpieee_flt) +F_ARM_ANY(_fpieee_flt) +_fpreset DATA +_fprintf_l +_fprintf_p +_fprintf_p_l +_fprintf_s_l +_fputchar +_fputwchar +F_ARM_ANY(_free_dbg) +_free_locale +F_ARM_ANY(_freea) +F_NON_I386(_fscanf_l) +F_NON_I386(_fscanf_s_l) +F_ARM_ANY(_fseeki64) +_fsopen +_fstat +F32(_fstat32 == _fstat) +_fstat64 +_fstati64 +F64(_fstat64i32 == _fstat) +_ftime +F_ARM_ANY(_ftime32) +_ftime32_s +_ftime64 +_ftime64_s +F32(_ftime_s == _ftime32_s) +F64(_ftime_s == _ftime64_s) +F_I386(_ftol) +_fullpath +F_ARM_ANY(_fullpath_dbg) +_futime +F_ARM_ANY(_futime32) +_futime64 +_fwprintf_l +_fwprintf_p +_fwprintf_p_l +_fwprintf_s_l +_fwscanf_l +_fwscanf_s_l +_gcvt +_gcvt_s +F_ARM_ANY(_get_current_locale) +F_ARM_ANY(_get_doserrno) +F_ARM_ANY(_get_environ) +F_ARM_ANY(_get_errno) +F_ARM_ANY(_get_fileinfo) +F_ARM_ANY(_get_fmode) +_get_heap_handle +_get_osfhandle +;_get_output_format provided by emu +_get_sbh_threshold +F_ARM_ANY(_get_wenviron) +_getch +_getche +_getcwd +_getdcwd +_getdiskfree +_getdllprocaddr +_getdrive +_getdrives +_getmaxstdio +_getmbcp +_getpid +_getsystime +_getw +_getwch +_getwche +_getws +F_I386(_global_unwind2) +_gmtime32 F_I386(== gmtime) +; _gmtime32_s replaced by emu +_gmtime64 +; _gmtime64_s replaced by emu +_heapadd +_heapchk +_heapmin +_heapset +_heapused +_heapwalk +_hypot +F_NON_I386(_hypotf) +_i64toa +_i64toa_s +_i64tow +_i64tow_s +_initterm +F_ARM_ANY(_initterm_e) +F_I386(_inp) +F_I386(_inpd) +F_I386(_inpw) +F_ARM_ANY(_invalid_parameter) +_iob DATA +_isalnum_l +_isalpha_l +_isatty +_iscntrl_l +_isctype +_isctype_l +_isdigit_l +_isgraph_l +_isleadbyte_l +_islower_l +_ismbbalnum +_ismbbalnum_l +_ismbbalpha +_ismbbalpha_l +_ismbbgraph +_ismbbgraph_l +_ismbbkalnum +_ismbbkalnum_l +_ismbbkana +_ismbbkana_l +_ismbbkprint +_ismbbkprint_l +_ismbbkpunct +_ismbbkpunct_l +_ismbblead +_ismbblead_l +_ismbbprint +_ismbbprint_l +_ismbbpunct +_ismbbpunct_l +_ismbbtrail +_ismbbtrail_l +_ismbcalnum +_ismbcalnum_l +_ismbcalpha +_ismbcalpha_l +_ismbcdigit +_ismbcdigit_l +_ismbcgraph +_ismbcgraph_l +_ismbchira +_ismbchira_l +_ismbckata +_ismbckata_l +_ismbcl0 +_ismbcl0_l +_ismbcl1 +_ismbcl1_l +_ismbcl2 +_ismbcl2_l +_ismbclegal +_ismbclegal_l +_ismbclower +_ismbclower_l +_ismbcprint +_ismbcprint_l +_ismbcpunct +_ismbcpunct_l +_ismbcspace +_ismbcspace_l +_ismbcsymbol +_ismbcsymbol_l +_ismbcupper +_ismbcupper_l +_ismbslead +_ismbslead_l +_ismbstrail +_ismbstrail_l +_isnan +F_X64(_isnanf) +_isprint_l +_isspace_l +_isupper_l +_iswalnum_l +_iswalpha_l +_iswcntrl_l +_iswctype_l +_iswdigit_l +_iswgraph_l +_iswlower_l +_iswprint_l +_iswpunct_l +_iswspace_l +_iswupper_l +_iswxdigit_l +_isxdigit_l +_itoa +_itoa_s +_itow +_itow_s +_j0 +_j1 +_jn +_kbhit +_lfind +_loaddll +F_NON_I386(_lfind_s) +F_X64(_local_unwind) +F_I386(_local_unwind2) +_localtime32 F_I386(== localtime) +; _localtime32_s replaced by emu +_localtime64 +; _localtime64_s replaced by emu +_lock +_locking +_logb +F_NON_I386(_logbf) +F_I386(_longjmpex) +_lrotl +_lrotr +_lsearch +F_NON_I386(_lsearch_s) +_lseek +_lseeki64 +_ltoa +F_NON_I386(_ltoa_s) +_ltow +F_NON_I386(_ltow_s) +_makepath +_makepath_s +F_ARM_ANY(_malloc_dbg) +_mbbtombc +_mbbtombc_l +_mbbtype +_mbcasemap F_NON_I386(DATA) +_mbccpy +_mbccpy_l +_mbccpy_s +_mbccpy_s_l +_mbcjistojms +_mbcjistojms_l +_mbcjmstojis +_mbcjmstojis_l +_mbclen +_mbclen_l +_mbctohira +_mbctohira_l +_mbctokata +_mbctokata_l +_mbctolower +_mbctolower_l +_mbctombb +_mbctombb_l +_mbctoupper +_mbctoupper_l +_mbctype DATA +_mblen_l +_mbsbtype +_mbsbtype_l +_mbscat +_mbscat_s +_mbscat_s_l +_mbschr +_mbschr_l +_mbscmp +_mbscmp_l +_mbscoll +_mbscoll_l +_mbscpy +_mbscpy_s +_mbscpy_s_l +_mbscspn +_mbscspn_l +_mbsdec +_mbsdec_l +_mbsdup +_mbsicmp +_mbsicmp_l +_mbsicoll +_mbsicoll_l +_mbsinc +_mbsinc_l +_mbslen +_mbslen_l +_mbslwr +_mbslwr_l +_mbslwr_s +_mbslwr_s_l +_mbsnbcat +_mbsnbcat_l +_mbsnbcat_s +_mbsnbcat_s_l +_mbsnbcmp +_mbsnbcmp_l +_mbsnbcnt +_mbsnbcnt_l +_mbsnbcoll +_mbsnbcoll_l +_mbsnbcpy +_mbsnbcpy_l +_mbsnbcpy_s +_mbsnbcpy_s_l +_mbsnbicmp +_mbsnbicmp_l +_mbsnbicoll +_mbsnbicoll_l +_mbsnbset +_mbsnbset_l +_mbsnbset_s +_mbsnbset_s_l +_mbsncat +_mbsncat_l +_mbsncat_s +_mbsncat_s_l +_mbsnccnt +_mbsnccnt_l +_mbsncmp +_mbsncmp_l +_mbsncoll +_mbsncoll_l +_mbsncpy +_mbsncpy_l +_mbsncpy_s +_mbsncpy_s_l +_mbsnextc +_mbsnextc_l +_mbsnicmp +_mbsnicmp_l +_mbsnicoll +_mbsnicoll_l +_mbsninc +_mbsninc_l +_mbsnlen +_mbsnlen_l +_mbsnset +_mbsnset_l +_mbsnset_s +_mbsnset_s_l +_mbspbrk +_mbspbrk_l +_mbsrchr +_mbsrchr_l +_mbsrev +_mbsrev_l +_mbsset +_mbsset_l +_mbsset_s +_mbsset_s_l +_mbsspn +_mbsspn_l +_mbsspnp +_mbsspnp_l +_mbsstr +_mbsstr_l +_mbstok +_mbstok_l +_mbstok_s +_mbstok_s_l +_mbstowcs_l +_mbstowcs_s_l +_mbstrlen +_mbstrlen_l +_mbstrnlen +_mbstrnlen_l +_mbsupr +_mbsupr_l +_mbsupr_s +_mbsupr_s_l +_mbtowc_l +_memccpy +F_ARM_ANY(_memcpy_strict_align) +_memicmp +_memicmp_l +_mkdir +_mkgmtime +F_I386(_mkgmtime32) +F_ARM_ANY(_mkgmtime32) +F_NON_I386(_mkgmtime64) +_mktemp +; _mktemp_s replaced by emu +F_I386(_mktime32 == mktime) +F_ARM_ANY(_mktime32) +_mktime64 +_msize +F_ARM_ANY(_msize_dbg) +_nextafter +F_X64(_nextafterf) +_onexit +_open +_open_osfhandle +_osplatform DATA +_osver DATA +F_I386(_outp) +F_I386(_outpd) +F_I386(_outpw) +_pclose +_pctype DATA +_pgmptr DATA +_pipe +_popen +_printf_l +_printf_p +_printf_p_l +_printf_s_l +_purecall +_putch +_putenv +_putenv_s +_putw +_putwch +_putws +_pwctype DATA +_read +F_ARM_ANY(_realloc_dbg) +_resetstkoflw +_rmdir +_rmtmp +_rotl +F_NON_I386(_rotl64) +_rotr +F_NON_I386(_rotr64) +#ifdef DEF_I386 +_safe_fdiv +_safe_fdivr +_safe_fprem +_safe_fprem1 +#endif +_scalb +F_X64(_scalbf) +_scanf_l +_scanf_s_l +_scprintf +_scprintf_l +_scprintf_p_l +_scwprintf +_scwprintf_l +_scwprintf_p_l +_searchenv +_searchenv_s +F_I386(_seh_longjmp_unwind) +F_ARM_ANY(_set_controlfp) +F_ARM_ANY(_set_doserrno) +F_ARM_ANY(_set_errno) +_set_error_mode +F_ARM_ANY(_set_fileinfo) +F_ARM_ANY(_set_fmode) +; Does not seem to present even on Win7 msvcrt +;_set_purecall_handler +_set_sbh_threshold +; _set_output_format provided by emu +F_I386(_set_SSE2_enable) +F_I386(_set_security_error_handler) +_seterrormode +_setjmp +F_I386(_setjmp3) +F_NON_I386(_setjmpex) +_setmaxstdio +_setmbcp +_setmode +_setsystime +_sleep +_snprintf +_snprintf_c +_snprintf_c_l +_snprintf_l +_snprintf_s +_snprintf_s_l +_snscanf +_snscanf_l +_snscanf_s +_snscanf_s_l +_snwprintf +snwprintf == _snwprintf +_snwprintf_l +_snwprintf_s +_snwprintf_s_l +_snwscanf +_snwscanf_l +_snwscanf_s +_snwscanf_s_l +_sopen +; _sopen_s replaced by emu +_spawnl +_spawnle +_spawnlp +_spawnlpe +_spawnv +_spawnve +_spawnvp +_spawnvpe +_splitpath +_splitpath_s +_sprintf_l +_sprintf_p_l +_sprintf_s_l +_sscanf_l +_sscanf_s_l +_stat +_stat64 +_stati64 +F32(_stat32 == _stat) +F64(_stat64i32 == _stat) +_statusfp +_strcmpi +_strcoll_l +_strdate +; _strdate_s replaced by emu +_strdup +F_ARM_ANY(_strdup_dbg) +_strerror +_strerror_s +_stricmp +_stricmp_l +_stricoll +_stricoll_l +_strlwr +_strlwr_l +_strlwr_s +_strlwr_s_l +_strncoll +_strncoll_l +_strnicmp +_strnicmp_l +_strnicoll +_strnicoll_l +_strnset +_strnset_s +_strrev +_strset +_strset_s +_strtime +; _strtime_s replaced by emu +_strtod_l +_strtoi64 +_strtoi64_l +_strtol_l +_strtoui64 +_strtoui64_l +_strtoul_l +_strupr +_strupr_l +_strupr_s +_strupr_s_l +_strxfrm_l +_swab +_swprintf == swprintf +F_NON_I386(_swprintf_c) +_swprintf_c_l +_swprintf_p_l +_swprintf_s_l +_swscanf_l +_swscanf_s_l +_sys_errlist DATA +_sys_nerr DATA +_tell +_telli64 +_tempnam +F_ARM_ANY(_tempnam_dbg) +F_I386(_time32 == time) +F_ARM_ANY(_time32) +_time64 +_tolower +_tolower_l +_toupper +_toupper_l +_towlower_l +_towupper_l +_tzset +_ui64toa +_ui64toa_s +_ui64tow +_ui64tow_s +_ultoa +_ultoa_s +_ultow +_ultow_s +_umask +; _umask_s replaced by emu +_ungetch +_ungetwch +_unlink +_unloaddll +_unlock +_utime +F_ARM_ANY(_utime32) +_utime64 +_vcprintf +_vcprintf_l +_vcprintf_p +_vcprintf_p_l +; _vcprintf_s Replaced by emu +; _vcprintf_s_l Likewise. +_vcwprintf +_vcwprintf_l +_vcwprintf_p +_vcwprintf_p_l +; _vcwprintf_s Replaced by emu +; _vcwprintf_s_l Likewise. +_vfprintf_l +_vfprintf_p +_vfprintf_p_l +_vfprintf_s_l +_vfwprintf_l +_vfwprintf_p +_vfwprintf_p_l +_vfwprintf_s_l +_vprintf_l +_vprintf_p +_vprintf_p_l +_vprintf_s_l +_vscprintf +_vscprintf_l +_vscprintf_p_l +_vscwprintf +_vscwprintf_l +_vscwprintf_p_l +_vsnprintf +_vsnprintf_c +_vsnprintf_c_l +_vsnprintf_l +_vsnprintf_s +_vsnprintf_s_l +_vsnwprintf +vsnwprintf == _vsnwprintf +_vsnwprintf_l +_vsnwprintf_s +_vsnwprintf_s_l +_vsprintf_l +_vsprintf_p +_vsprintf_p_l +_vsprintf_s_l +_vswprintf F_I386(== vswprintf) +_vswprintf_c +_vswprintf_c_l +_vswprintf_l +_vswprintf_p_l +_vswprintf_s_l +_vwprintf_l +_vwprintf_p +_vwprintf_p_l +_vwprintf_s_l +_waccess +; _waccess_s Replaced by emu +_wasctime +; _wasctime_s Replaced by emu +F_ARM_ANY(_wassert) +_wchdir +_wchmod +_wcmdln DATA +_wcreat +_wcscoll_l +_wcsdup +F_ARM_ANY(_wcsdup_dbg) +_wcserror +_wcserror_s +_wcsftime_l +_wcsicmp +_wcsicmp_l +_wcsicoll +_wcsicoll_l +_wcslwr +_wcslwr_l +_wcslwr_s +_wcslwr_s_l +_wcsncoll +_wcsncoll_l +_wcsnicmp +_wcsnicmp_l +_wcsnicoll +_wcsnicoll_l +_wcsnset +_wcsnset_s +_wcsrev +_wcsset +_wcsset_s +F_ARM_ANY(_wcstod_l) +_wcstoi64 +_wcstoi64_l +_wcstol_l +_wcstombs_l +_wcstombs_s_l +_wcstoui64 +_wcstoui64_l +_wcstoul_l +_wcsupr +_wcsupr_l +_wcsupr_s +_wcsupr_s_l +_wcsxfrm_l +_wctime +F_I386(_wctime32 == _wctime) +F_ARM_ANY(_wctime32) +; _wctime32_s replaced by emu +_wctime64 +; _wctime64_s replaced by emu +_wctomb_l +_wctomb_s_l +_wctype +F_X86_ANY(_wenviron DATA) +_wexecl +_wexecle +_wexeclp +_wexeclpe +_wexecv +_wexecve +_wexecvp +_wexecvpe +_wfdopen +_wfindfirst +F32(_wfindfirst32 == _wfindfirst) +_wfindfirst64 +_wfindfirsti64 +F32(_wfindfirst32i64 == _wfindfirsti64) +F64(_wfindfirst64i32 == _wfindfirst) +_wfindnext +F32(_wfindnext32 == _wfindnext) +_wfindnext64 +_wfindnexti64 +F32(_wfindnext32i64 == _wfindnexti64) +F64(_wfindnext64i32 == _wfindnext) +_wfopen +_wfopen_s +_wfreopen +_wfreopen_s +_wfsopen +_wfullpath +F_ARM_ANY(_wfullpath_dbg) +_wgetcwd +_wgetdcwd +_wgetenv +_wgetenv_s +_winmajor DATA +_winminor DATA +_winput_s +_winver DATA +_wmakepath +_wmakepath_s +_wmkdir +_wmktemp +; _wmktemp_s replaced by emu +_wopen +_woutput_s +_wperror +_wpgmptr DATA +_wpopen +_wprintf_l +_wprintf_p +_wprintf_p_l +_wprintf_s_l +_wputenv +_wputenv_s +_wremove +_wrename +_write +_wrmdir +_wscanf_l +_wscanf_s_l +_wsearchenv +_wsearchenv_s +_wsetlocale +_wsopen +_wsopen_s +_wspawnl +_wspawnle +_wspawnlp +_wspawnlpe +_wspawnv +_wspawnve +_wspawnvp +_wspawnvpe +_wsplitpath +_wsplitpath_s +_wstat +_wstat64 +_wstati64 +F32(_wstat32 == _wstat) +F64(_wstat64i32 == _wstat) +_wstrdate +; _wstrdate_s replaced by emu +_wstrtime +; _wstrtime_s replaced by emu +_wsystem +_wtempnam +F_ARM_ANY(_wtempnam_dbg) +_wtmpnam +_wtmpnam_s +_wtof +_wtof_l +_wtoi +_wtoi64 +_wtoi64_l +_wtoi_l +_wtol +_wtol_l +_wunlink +_wutime +F_ARM_ANY(_wutime32) +_wutime64 +_y0 +_y1 +_yn +abort +abs +acos +F_NON_I386(acosf F_X86_ANY(DATA)) +asctime +; asctime_s replaced by emu +asin +F_NON_I386(asinf F_X86_ANY(DATA)) +atan +atan2 F_X86_ANY(DATA) +F_NON_I386(atan2f F_X86_ANY(DATA)) +F_NON_I386(atanf F_X86_ANY(DATA)) +atexit DATA +atof +atoi +atol +bsearch +bsearch_s +F_ARM_ANY(btowc) +calloc +ceil DATA +F_NON_I386(ceilf DATA) +clearerr +clearerr_s +clock +cos F_X86_ANY(DATA) +F_NON_I386(cosf F_X86_ANY(DATA)) +cosh +F_NON_I386(coshf DATA) +ctime +difftime +div +exit +exp F_X86_ANY(DATA) +F_NON_I386(expf F_X86_ANY(DATA)) +fabs DATA +F_ARM_ANY(fabsf) +fclose +feof +ferror +fflush +fgetc +fgetpos +fgets +fgetwc +fgetws +floor DATA +F_NON_I386(floorf DATA) +fmod F_X86_ANY(DATA) +F_NON_I386(fmodf F_X86_ANY(DATA)) +fopen +fopen_s +fprintf +fprintf_s +fputc +fputs +fputwc +fputws +fread +free +freopen +freopen_s +; If we implement frexp, we can set it to DATA only. +frexp +fscanf +fscanf_s +fseek +fsetpos +ftell +fwprintf +__ms_fwprintf == fwprintf +fwprintf_s +fwrite +fwscanf +fwscanf_s +getc +getchar +getenv +getenv_s +gets +getwc +getwchar +gmtime +is_wctype +isalnum +isalpha +iscntrl +isdigit +isgraph +isleadbyte +islower +isprint +ispunct +isspace +isupper +iswalnum +iswalpha +iswascii +iswcntrl +iswctype +iswdigit +iswgraph +iswlower +iswprint +iswpunct +iswspace +iswupper +iswxdigit +isxdigit +labs +ldexp F_X86_ANY(DATA) +ldiv +localeconv +localtime +log F_X86_ANY(DATA) +log10 +F_NON_I386(log10f F_X86_ANY(DATA)) +F_NON_I386(logf F_X86_ANY(DATA)) +F_ARM_ANY(longjmp) +malloc +mblen +F_ARM_ANY(mbrlen) +F_ARM_ANY(mbrtowc) +F_ARM_ANY(mbsdup_dbg) +F_ARM_ANY(mbsrtowcs) +mbsrtowcs_s +mbstowcs +mbstowcs_s +mbtowc +memchr +memcmp +memcpy +; memcpy_s replaced by emu +memmove +; memmove_s replaced by emu +memset +mktime +modf DATA +F_NON_I386(modff DATA) +perror +pow F_X86_ANY(DATA) +F_NON_I386(powf F_X86_ANY(DATA)) +printf +printf_s +putc +putchar +puts +putwc +putwchar +qsort +qsort_s +raise +rand +; rand_s replaced by emu +realloc +remove +rename +rewind +scanf +scanf_s +setbuf +F_NON_I386(setjmp) +setlocale +setvbuf +signal +sin F_X86_ANY(DATA) +F_NON_I386(sinf F_X86_ANY(DATA)) +; if we implement sinh, we can set it DATA only. +sinh +F_NON_I386(sinhf DATA) +sprintf +; sprintf_s replaced by emu +sqrt DATA +F_NON_I386(sqrtf DATA) +srand +sscanf +sscanf_s +strcat +strcat_s +strchr +strcmp +strcoll +strcpy +strcpy_s +strcspn +strerror +; strerror_s replaced by emu +strftime +strlen +strncat +strncat_s +strncmp +strncpy +strncpy_s +; strnlen replaced by emu +strpbrk +strrchr +strspn +strstr +strtod +strtok +strtok_s +strtol +strtoul +strxfrm +swprintf +swprintf_s +swscanf +swscanf_s +system +tan +F_NON_I386(tanf F_X86_ANY(DATA)) +; if we implement tanh, we can set it to DATA only. +tanh +F_ARM_ANY(tanhf) +time F_NON_I386(== _time64) +tmpfile +tmpfile_s +tmpnam +tmpnam_s +tolower +toupper +towlower +towupper +ungetc +ungetwc +F_ARM_ANY(utime) +vfprintf +vfprintf_s +vfwprintf +vfwprintf_s +vprintf +vprintf_s +vsnprintf == _vsnprintf +snprintf == _snprintf +vsprintf +; vsprintf_s replaced by emu +vswprintf +vswprintf_s +vwprintf +vwprintf_s +F_ARM_ANY(wcrtomb) +wcrtomb_s +wcscat +wcscat_s +wcschr +wcscmp +wcscoll +wcscpy +wcscpy_s +wcscspn +wcsftime +wcslen +wcsncat +wcsncat_s +wcsncmp +wcsncpy +wcsncpy_s +; We provide replacement implementation in libmingwex +wcsnlen DATA +wcspbrk +wcsrchr +F_ARM_ANY(wcsrtombs) +wcsrtombs_s +wcsspn +wcsstr +wcstod +wcstok +wcstok_s +wcstol +wcstombs +wcstombs_s +wcstoul +wcsxfrm +F_ARM_ANY(wctob) +wctomb +wctomb_s +wprintf +wprintf_s +wscanf +wscanf_s diff --git a/src/codegen.cpp b/src/codegen.cpp index 59d3e1f4a0..f9933aaf28 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -9698,10 +9698,14 @@ void codegen_build_and_link(CodeGen *g) { } } + codegen_release_caches(g); + codegen_add_time_event(g, "Done"); +} + +void codegen_release_caches(CodeGen *g) { while (g->caches_to_release.length != 0) { cache_release(g->caches_to_release.pop()); } - codegen_add_time_event(g, "Done"); } ZigPackage *codegen_create_package(CodeGen *g, const char *root_src_dir, const char *root_src_path, diff --git a/src/codegen.hpp b/src/codegen.hpp index d7cabe879e..5de36c1aab 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -61,4 +61,6 @@ Buf *codegen_generate_builtin_source(CodeGen *g); TargetSubsystem detect_subsystem(CodeGen *g); +void codegen_release_caches(CodeGen *codegen); + #endif diff --git a/src/link.cpp b/src/link.cpp index fd1a77c1e9..ef5db4c4ad 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -573,17 +573,18 @@ static const char *build_musl(CodeGen *parent) { static const char *get_libc_crt_file(CodeGen *parent, const char *file) { if (parent->libc == nullptr && parent->zig_target->os == OsWindows) { - if (strcmp(file, "crt2u.obj") == 0) { + if (strcmp(file, "crt2.obj") == 0) { CFile *c_file = allocate(1); c_file->source_path = buf_ptr(buf_sprintf( "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "crt" OS_SEP "crtexe.c", buf_ptr(parent->zig_lib_dir))); mingw_add_cc_args(parent, c_file); c_file->args.append("-U__CRTDLL__"); c_file->args.append("-D__MSVCRT__"); - c_file->args.append("-DUNICODE"); - c_file->args.append("-D_UNICODE"); - c_file->args.append("-DWPRFLAG=1"); - return build_libc_object(parent, "crt2u", c_file); + // Uncomment these 3 things for crtu + //c_file->args.append("-DUNICODE"); + //c_file->args.append("-D_UNICODE"); + //c_file->args.append("-DWPRFLAG=1"); + return build_libc_object(parent, "crt2", c_file); } else if (strcmp(file, "dllcrt2.obj") == 0) { CFile *c_file = allocate(1); c_file->source_path = buf_ptr(buf_sprintf( @@ -592,6 +593,64 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) { c_file->args.append("-U__CRTDLL__"); c_file->args.append("-D__MSVCRT__"); return build_libc_object(parent, "dllcrt2", c_file); + } else if (strcmp(file, "mingw32.lib") == 0) { + CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr); + codegen_set_out_name(child_gen, buf_create_from_str("mingw32")); + + static const char *deps[] = { + "mingw" OS_SEP "crt" OS_SEP "crt0_c.c", + "mingw" OS_SEP "crt" OS_SEP "dll_argv.c", + "mingw" OS_SEP "crt" OS_SEP "gccmain.c", + "mingw" OS_SEP "crt" OS_SEP "natstart.c", + "mingw" OS_SEP "crt" OS_SEP "pseudo-reloc-list.c", + "mingw" OS_SEP "crt" OS_SEP "wildcard.c", + "mingw" OS_SEP "crt" OS_SEP "charmax.c", + "mingw" OS_SEP "crt" OS_SEP "crt0_w.c", + "mingw" OS_SEP "crt" OS_SEP "dllargv.c", + "mingw" OS_SEP "crt" OS_SEP "gs_support.c", + "mingw" OS_SEP "crt" OS_SEP "_newmode.c", + "mingw" OS_SEP "crt" OS_SEP "tlssup.c", + "mingw" OS_SEP "crt" OS_SEP "xncommod.c", + "mingw" OS_SEP "crt" OS_SEP "cinitexe.c", + "mingw" OS_SEP "crt" OS_SEP "merr.c", + "mingw" OS_SEP "crt" OS_SEP "pesect.c", + "mingw" OS_SEP "crt" OS_SEP "udllargc.c", + "mingw" OS_SEP "crt" OS_SEP "xthdloc.c", + "mingw" OS_SEP "crt" OS_SEP "CRT_fp10.c", + "mingw" OS_SEP "crt" OS_SEP "mingw_helpers.c", + "mingw" OS_SEP "crt" OS_SEP "pseudo-reloc.c", + "mingw" OS_SEP "crt" OS_SEP "udll_argv.c", + "mingw" OS_SEP "crt" OS_SEP "xtxtmode.c", + "mingw" OS_SEP "crt" OS_SEP "crt_handler.c", + "mingw" OS_SEP "crt" OS_SEP "tlsthrd.c", + "mingw" OS_SEP "crt" OS_SEP "tlsmthread.c", + "mingw" OS_SEP "crt" OS_SEP "tlsmcrt.c", + "mingw" OS_SEP "crt" OS_SEP "cxa_atexit.c", + }; + for (size_t i = 0; i < array_length(deps); i += 1) { + CFile *c_file = allocate(1); + c_file->source_path = path_from_libc(parent, deps[i]); + c_file->args.append("-DHAVE_CONFIG_H"); + c_file->args.append("-D_SYSCRT=1"); + c_file->args.append("-DCRTDLL=1"); + + c_file->args.append("-isystem"); + c_file->args.append(path_from_libc(parent, "include" OS_SEP "any-windows-any")); + + c_file->args.append("-I"); + c_file->args.append(path_from_libc(parent, "mingw" OS_SEP "include" OS_SEP)); + + c_file->args.append("-std=gnu99"); + c_file->args.append("-D_CRTBLD"); + c_file->args.append("-D_WIN32_WINNT=0x0f00"); + c_file->args.append("-D__MSVCRT_VERSION__=0x700"); + c_file->args.append("-g"); + c_file->args.append("-O2"); + + child_gen->c_source_files.append(c_file); + } + codegen_build_and_link(child_gen); + return buf_ptr(&child_gen->output_file_path); } else { zig_unreachable(); } @@ -1154,8 +1213,12 @@ static void coff_append_machine_arg(CodeGen *g, ZigList *list) { list->append("-MACHINE:X86"); } else if (g->zig_target->arch == ZigLLVM_x86_64) { list->append("-MACHINE:X64"); - } else if (g->zig_target->arch == ZigLLVM_arm) { - list->append("-MACHINE:ARM"); + } else if (target_is_arm(g->zig_target)) { + if (target_arch_pointer_bit_width(g->zig_target->arch) == 32) { + list->append("-MACHINE:ARM"); + } else { + list->append("-MACHINE:ARM64"); + } } } @@ -1223,9 +1286,150 @@ static const char *get_libc_static_file(ZigLibCInstallation *lib, const char *fi return buf_ptr(out_buf); } +static void print_zig_cc_cmd(const char *zig_exe, ZigList *args) { + fprintf(stderr, "%s", zig_exe); + for (size_t arg_i = 0; arg_i < args->length; arg_i += 1) { + fprintf(stderr, " %s", args->at(arg_i)); + } + fprintf(stderr, "\n"); +} + +static const char *get_def_lib(CodeGen *parent, const char *name, const char *def_in_rel_path) { + Error err; + + Buf *self_exe_path = buf_alloc(); + if ((err = os_self_exe_path(self_exe_path))) { + fprintf(stderr, "Unable to get self exe path: %s\n", err_str(err)); + exit(1); + } + Buf *compiler_id; + if ((err = get_compiler_id(&compiler_id))) { + fprintf(stderr, "Unable to get compiler id: %s\n", err_str(err)); + exit(1); + } + + Buf *cache_dir = get_stage1_cache_path(); + Buf *o_dir = buf_sprintf("%s" OS_SEP CACHE_OUT_SUBDIR, buf_ptr(cache_dir)); + Buf *manifest_dir = buf_sprintf("%s" OS_SEP CACHE_HASH_SUBDIR, buf_ptr(cache_dir)); + + Buf *def_in_file = buf_sprintf("%s" OS_SEP "libc" OS_SEP "%s", buf_ptr(parent->zig_lib_dir), def_in_rel_path); + Buf *def_include_dir = buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "def-include", + buf_ptr(parent->zig_lib_dir)); + + CacheHash *cache_hash = allocate(1); + cache_init(cache_hash, manifest_dir); + + cache_buf(cache_hash, compiler_id); + cache_file(cache_hash, def_in_file); + cache_buf(cache_hash, def_include_dir); + cache_int(cache_hash, parent->zig_target->arch); + + Buf digest = BUF_INIT; + buf_resize(&digest, 0); + if ((err = cache_hit(cache_hash, &digest))) { + if (err != ErrorInvalidFormat) { + if (err == ErrorCacheUnavailable) { + // already printed error + } else { + fprintf(stderr, "unable to check cache when processing .def.in file: %s\n", err_str(err)); + } + exit(1); + } + } + + Buf *artifact_dir; + Buf *lib_final_path; + Buf *final_lib_basename = buf_sprintf("%s.lib", name); + + bool is_cache_miss = (buf_len(&digest) == 0); + if (is_cache_miss) { + if ((err = cache_final(cache_hash, &digest))) { + fprintf(stderr, "Unable to finalize cache hash: %s\n", err_str(err)); + exit(1); + } + artifact_dir = buf_alloc(); + os_path_join(o_dir, &digest, artifact_dir); + if ((err = os_make_path(artifact_dir))) { + fprintf(stderr, "Unable to create output directory '%s': %s", + buf_ptr(artifact_dir), err_str(err)); + exit(1); + } + Buf *final_def_basename = buf_sprintf("%s.def", name); + Buf *def_final_path = buf_alloc(); + os_path_join(artifact_dir, final_def_basename, def_final_path); + + ZigList args = {}; + args.append(buf_ptr(self_exe_path)); + args.append("cc"); + args.append("-x"); + args.append("c"); + args.append(buf_ptr(def_in_file)); + args.append("-Wp,-w"); + args.append("-undef"); + args.append("-P"); + args.append("-I"); + args.append(buf_ptr(def_include_dir)); + if (target_is_arm(parent->zig_target)) { + if (target_arch_pointer_bit_width(parent->zig_target->arch) == 32) { + args.append("-DDEF_ARM32"); + } else { + args.append("-DDEF_ARM64"); + } + } else if (parent->zig_target->arch == ZigLLVM_x86) { + args.append("-DDEF_I386"); + } else if (parent->zig_target->arch == ZigLLVM_x86_64) { + args.append("-DDEF_X64"); + } else { + zig_unreachable(); + } + args.append("-E"); + args.append("-o"); + args.append(buf_ptr(def_final_path)); + + if (parent->verbose_cc) { + print_zig_cc_cmd("zig", &args); + } + Termination term; + os_spawn_process(args, &term); + if (term.how != TerminationIdClean || term.code != 0) { + fprintf(stderr, "\nThe following command failed:\n"); + print_zig_cc_cmd(buf_ptr(self_exe_path), &args); + exit(1); + } + + lib_final_path = buf_alloc(); + os_path_join(artifact_dir, final_lib_basename, lib_final_path); + + args.resize(0); + args.append("link"); + coff_append_machine_arg(parent, &args); + + args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_final_path)))); + args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(lib_final_path)))); + + Buf diag = BUF_INIT; + ZigLLVM_ObjectFormatType target_ofmt = target_object_format(parent->zig_target); + if (!zig_lld_link(target_ofmt, args.items, args.length, &diag)) { + fprintf(stderr, "%s\n", buf_ptr(&diag)); + exit(1); + } + } else { + // cache hit + artifact_dir = buf_alloc(); + os_path_join(o_dir, &digest, artifact_dir); + lib_final_path = buf_alloc(); + os_path_join(artifact_dir, final_lib_basename, lib_final_path); + } + parent->caches_to_release.append(cache_hash); + + return buf_ptr(lib_final_path); +} + static void add_mingw_link_args(LinkJob *lj, bool is_library) { CodeGen *g = lj->codegen; + lj->args.append("-lldmingw"); + bool is_dll = g->out_type == OutTypeLib && g->is_dynamic; if (g->zig_target->arch == ZigLLVM_x86) { @@ -1238,8 +1442,11 @@ static void add_mingw_link_args(LinkJob *lj, bool is_library) { if (is_dll) { lj->args.append(get_libc_crt_file(g, "dllcrt2.obj")); } else { - lj->args.append(get_libc_crt_file(g, "crt2u.obj")); + lj->args.append(get_libc_crt_file(g, "crt2.obj")); } + + lj->args.append(get_libc_crt_file(g, "mingw32.lib")); + lj->args.append(get_def_lib(g, "msvcrt", "mingw" OS_SEP "lib-common" OS_SEP "msvcrt.def.in")); } else { if (is_dll) { lj->args.append(get_libc_file(g->libc, "dllcrt2.o")); @@ -1388,7 +1595,7 @@ static void construct_linker_job_coff(LinkJob *lj) { } if (g->out_type == OutTypeExe || (g->out_type == OutTypeLib && g->is_dynamic)) { - if (!g->is_dummy_so) { + if (g->libc_link_lib == nullptr && !g->is_dummy_so) { Buf *libc_a_path = build_c(g, OutTypeLib); lj->args.append(buf_ptr(libc_a_path)); } @@ -1762,10 +1969,12 @@ void codegen_link(CodeGen *g) { } os_spawn_process(args, &term); if (term.how != TerminationIdClean || term.code != 0) { + codegen_release_caches(g); exit(1); } } else if (!zig_lld_link(target_object_format(g->zig_target), lj.args.items, lj.args.length, &diag)) { fprintf(stderr, "%s\n", buf_ptr(&diag)); + codegen_release_caches(g); exit(1); } } -- cgit v1.2.3 From d9c4c96bf2755fba09cdf6c7f56b97b66b5255eb Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 11 Jul 2019 23:48:13 -0400 Subject: add -Wno-pragma-pack when targeting windows-gnu windows.h has files such as pshpack1.h which do #pragma packing, triggering a clang warning. So for this target, this warning is disabled. this commit also improves the error message printed when no libc can be used, printing the "zig triple" rather than the "llvm triple". --- src/all_types.hpp | 2 +- src/codegen.cpp | 24 +++++++++++++++--------- src/main.cpp | 2 +- src/target.cpp | 11 ++++++++++- src/target.hpp | 3 ++- 5 files changed, 29 insertions(+), 13 deletions(-) (limited to 'src/codegen.cpp') diff --git a/src/all_types.hpp b/src/all_types.hpp index b49ed9820b..3cdaf36cd9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1804,7 +1804,7 @@ struct CodeGen { ZigType *err_tag_type; ZigType *test_fn_type; - Buf triple_str; + Buf llvm_triple_str; Buf global_asm; Buf output_file_path; Buf o_file_output_path; diff --git a/src/codegen.cpp b/src/codegen.cpp index f9933aaf28..891e8ace92 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -199,7 +199,7 @@ CodeGen *codegen_create(Buf *main_pkg_path, Buf *root_src_path, const ZigTarget g->link_libs_list.append(g->libc_link_lib); } - get_target_triple(&g->triple_str, g->zig_target); + target_triple_llvm(&g->llvm_triple_str, g->zig_target); g->pointer_size_bytes = target_arch_pointer_bit_width(g->zig_target->arch) / 8; if (!target_has_debug_info(g->zig_target)) { @@ -8103,7 +8103,7 @@ static void init(CodeGen *g) { assert(g->root_out_name); g->module = LLVMModuleCreateWithName(buf_ptr(g->root_out_name)); - LLVMSetTarget(g->module, buf_ptr(&g->triple_str)); + LLVMSetTarget(g->module, buf_ptr(&g->llvm_triple_str)); if (target_object_format(g->zig_target) == ZigLLVM_COFF) { ZigLLVMAddModuleCodeViewFlag(g->module); @@ -8113,13 +8113,13 @@ static void init(CodeGen *g) { LLVMTargetRef target_ref; char *err_msg = nullptr; - if (LLVMGetTargetFromTriple(buf_ptr(&g->triple_str), &target_ref, &err_msg)) { + if (LLVMGetTargetFromTriple(buf_ptr(&g->llvm_triple_str), &target_ref, &err_msg)) { fprintf(stderr, "Zig is expecting LLVM to understand this target: '%s'\n" "However LLVM responded with: \"%s\"\n" "Zig is unable to continue. This is a bug in Zig:\n" "https://github.com/ziglang/zig/issues/438\n" - , buf_ptr(&g->triple_str), err_msg); + , buf_ptr(&g->llvm_triple_str), err_msg); exit(1); } @@ -8153,7 +8153,7 @@ static void init(CodeGen *g) { target_specific_features = ""; } - g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->triple_str), + g->target_machine = ZigLLVMCreateTargetMachine(target_ref, buf_ptr(&g->llvm_triple_str), target_specific_cpu_args, target_specific_features, opt_level, reloc_mode, LLVMCodeModelDefault, g->function_sections); @@ -8333,12 +8333,12 @@ static void detect_libc(CodeGen *g) { !target_os_is_darwin(g->zig_target->os)) { Buf triple_buf = BUF_INIT; - get_target_triple(&triple_buf, g->zig_target); + target_triple_zig(&triple_buf, g->zig_target); fprintf(stderr, "Zig is unable to provide a libc for the chosen target '%s'.\n" "The target is non-native, so Zig also cannot use the native libc installation.\n" - "Choose a target which has a libc available, or provide a libc installation text file.\n" - "See `zig libc --help` for more details.\n", buf_ptr(&triple_buf)); + "Choose a target which has a libc available (see `zig targets`), or\n" + "provide a libc installation text file (see `zig libc --help`).\n", buf_ptr(&triple_buf)); exit(1); } } @@ -8397,12 +8397,18 @@ void add_cc_args(CodeGen *g, ZigList &args, const char *out_dep_pa args.append("-march=native"); } else { args.append("-target"); - args.append(buf_ptr(&g->triple_str)); + args.append(buf_ptr(&g->llvm_triple_str)); } if (g->zig_target->os == OsFreestanding) { args.append("-ffreestanding"); } + // windows.h has files such as pshpack1.h which do #pragma packing, triggering a clang warning. + // So for this target, we disable this warning. + if (g->zig_target->os == OsWindows && target_abi_is_gnu(g->zig_target->abi)) { + args.append("-Wno-pragma-pack"); + } + if (!g->strip_debug_symbols) { args.append("-g"); } diff --git a/src/main.cpp b/src/main.cpp index 9329229a7b..f132dce176 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -982,7 +982,7 @@ int main(int argc, char **argv) { if (target_requires_pic(&target, have_libc) && want_pic == WantPICDisabled) { Buf triple_buf = BUF_INIT; - get_target_triple(&triple_buf, &target); + target_triple_zig(&triple_buf, &target); fprintf(stderr, "`--disable-pic` is incompatible with target '%s'\n", buf_ptr(&triple_buf)); return print_error_usage(arg0); } diff --git a/src/target.cpp b/src/target.cpp index 270bb057df..a0f842a5ac 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -753,7 +753,16 @@ void init_all_targets(void) { LLVMInitializeAllAsmParsers(); } -void get_target_triple(Buf *triple, const ZigTarget *target) { +void target_triple_zig(Buf *triple, const ZigTarget *target) { + buf_resize(triple, 0); + buf_appendf(triple, "%s%s-%s-%s", + ZigLLVMGetArchTypeName(target->arch), + ZigLLVMGetSubArchTypeName(target->sub_arch), + ZigLLVMGetOSTypeName(get_llvm_os_type(target->os)), + ZigLLVMGetEnvironmentTypeName(target->abi)); +} + +void target_triple_llvm(Buf *triple, const ZigTarget *target) { buf_resize(triple, 0); buf_appendf(triple, "%s%s-%s-%s-%s", ZigLLVMGetArchTypeName(target->arch), diff --git a/src/target.hpp b/src/target.hpp index 99e38f1c62..e7e102a8ce 100644 --- a/src/target.hpp +++ b/src/target.hpp @@ -148,7 +148,8 @@ const char *target_oformat_name(ZigLLVM_ObjectFormatType oformat); ZigLLVM_ObjectFormatType target_object_format(const ZigTarget *target); void get_native_target(ZigTarget *target); -void get_target_triple(Buf *triple, const ZigTarget *target); +void target_triple_llvm(Buf *triple, const ZigTarget *target); +void target_triple_zig(Buf *triple, const ZigTarget *target); void init_all_targets(void); -- cgit v1.2.3 From 7b8ba871a9d14a26972caabc37aee1fb1f15006e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 12 Jul 2019 14:44:34 -0400 Subject: mingw libc: solve the segfault having to do with destructors * fixed --verbose-cc printing an extra "zig" before the rest of the command line * windows-gnu targets use libfoo.a, foo.o extensions to match mingw conventions. --- libc/mingw/include/config.h | 2 +- src/codegen.cpp | 10 +++++----- src/link.cpp | 20 +++++++++++--------- src/target.cpp | 15 ++++++++++++--- 4 files changed, 29 insertions(+), 18 deletions(-) (limited to 'src/codegen.cpp') diff --git a/libc/mingw/include/config.h b/libc/mingw/include/config.h index 45931b832a..2c96636426 100644 --- a/libc/mingw/include/config.h +++ b/libc/mingw/include/config.h @@ -2,7 +2,7 @@ /* config.h.in. Generated from configure.ac by autoheader. */ /* Whether the linker provides __CTOR_LIST__ */ -/* #undef HAVE_CTOR_LIST */ +#define HAVE_CTOR_LIST 1 /* Define to 1 if you have the header file. */ #define HAVE_INTTYPES_H 1 diff --git a/src/codegen.cpp b/src/codegen.cpp index 891e8ace92..94e2a98b2f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -8741,10 +8741,10 @@ static void gen_root_source(CodeGen *g) { } -static void print_zig_cc_cmd(const char *zig_exe, ZigList *args) { - fprintf(stderr, "%s", zig_exe); +static void print_zig_cc_cmd(ZigList *args) { for (size_t arg_i = 0; arg_i < args->length; arg_i += 1) { - fprintf(stderr, " %s", args->at(arg_i)); + const char *space_str = (arg_i == 0) ? "" : " "; + fprintf(stderr, "%s%s", space_str, args->at(arg_i)); } fprintf(stderr, "\n"); } @@ -8882,12 +8882,12 @@ static void gen_c_object(CodeGen *g, Buf *self_exe_path, CFile *c_file) { } if (g->verbose_cc) { - print_zig_cc_cmd("zig", &args); + print_zig_cc_cmd(&args); } os_spawn_process(args, &term); if (term.how != TerminationIdClean || term.code != 0) { fprintf(stderr, "\nThe following command failed:\n"); - print_zig_cc_cmd(buf_ptr(self_exe_path), &args); + print_zig_cc_cmd(&args); exit(1); } diff --git a/src/link.cpp b/src/link.cpp index 8cc6f629fc..bfceef74ea 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -646,6 +646,8 @@ static const char *build_libunwind(CodeGen *parent) { } static void mingw_add_cc_args(CodeGen *parent, CFile *c_file) { + c_file->args.append("-DHAVE_CONFIG_H"); + c_file->args.append("-I"); c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "include", buf_ptr(parent->zig_lib_dir)))); @@ -1158,7 +1160,7 @@ static void add_mingwex_os_dep(CodeGen *parent, CodeGen *child_gen, const char * static const char *get_libc_crt_file(CodeGen *parent, const char *file) { if (parent->libc == nullptr && parent->zig_target->os == OsWindows) { - if (strcmp(file, "crt2.obj") == 0) { + if (strcmp(file, "crt2.o") == 0) { CFile *c_file = allocate(1); c_file->source_path = buf_ptr(buf_sprintf( "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "crt" OS_SEP "crtexe.c", buf_ptr(parent->zig_lib_dir))); @@ -1170,7 +1172,7 @@ static const char *get_libc_crt_file(CodeGen *parent, const char *file) { //c_file->args.append("-D_UNICODE"); //c_file->args.append("-DWPRFLAG=1"); return build_libc_object(parent, "crt2", c_file); - } else if (strcmp(file, "dllcrt2.obj") == 0) { + } else if (strcmp(file, "dllcrt2.o") == 0) { CFile *c_file = allocate(1); c_file->source_path = buf_ptr(buf_sprintf( "%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "crt" OS_SEP "crtdll.c", buf_ptr(parent->zig_lib_dir))); @@ -1916,10 +1918,10 @@ static const char *get_libc_static_file(ZigLibCInstallation *lib, const char *fi return buf_ptr(out_buf); } -static void print_zig_cc_cmd(const char *zig_exe, ZigList *args) { - fprintf(stderr, "%s", zig_exe); +static void print_zig_cc_cmd(ZigList *args) { for (size_t arg_i = 0; arg_i < args->length; arg_i += 1) { - fprintf(stderr, " %s", args->at(arg_i)); + const char *space_str = (arg_i == 0) ? "" : " "; + fprintf(stderr, "%s%s", space_str, args->at(arg_i)); } fprintf(stderr, "\n"); } @@ -2017,13 +2019,13 @@ static const char *get_def_lib(CodeGen *parent, const char *name, const char *de args.append(buf_ptr(def_final_path)); if (parent->verbose_cc) { - print_zig_cc_cmd("zig", &args); + print_zig_cc_cmd(&args); } Termination term; os_spawn_process(args, &term); if (term.how != TerminationIdClean || term.code != 0) { fprintf(stderr, "\nThe following command failed:\n"); - print_zig_cc_cmd(buf_ptr(self_exe_path), &args); + print_zig_cc_cmd(&args); exit(1); } @@ -2070,9 +2072,9 @@ static void add_mingw_link_args(LinkJob *lj, bool is_library) { if (g->libc == nullptr) { if (is_dll) { - lj->args.append(get_libc_crt_file(g, "dllcrt2.obj")); + lj->args.append(get_libc_crt_file(g, "dllcrt2.o")); } else { - lj->args.append(get_libc_crt_file(g, "crt2.obj")); + lj->args.append(get_libc_crt_file(g, "crt2.o")); } lj->args.append(get_libc_crt_file(g, "mingw32.lib")); diff --git a/src/target.cpp b/src/target.cpp index a0f842a5ac..56c9a72c8f 100644 --- a/src/target.cpp +++ b/src/target.cpp @@ -993,7 +993,9 @@ bool target_allows_addr_zero(const ZigTarget *target) { } const char *target_o_file_ext(const ZigTarget *target) { - if (target->abi == ZigLLVM_MSVC || target->os == OsWindows || target->os == OsUefi) { + if (target->abi == ZigLLVM_MSVC || + (target->os == OsWindows && !target_abi_is_gnu(target->abi)) || + target->os == OsUefi) { return ".obj"; } else { return ".o"; @@ -1021,7 +1023,10 @@ const char *target_exe_file_ext(const ZigTarget *target) { } const char *target_lib_file_prefix(const ZigTarget *target) { - if (target->os == OsWindows || target->os == OsUefi || target_is_wasm(target)) { + if ((target->os == OsWindows && !target_abi_is_gnu(target->abi)) || + target->os == OsUefi || + target_is_wasm(target)) + { return ""; } else { return "lib"; @@ -1036,7 +1041,11 @@ const char *target_lib_file_ext(const ZigTarget *target, bool is_static, } if (target->os == OsWindows || target->os == OsUefi) { if (is_static) { - return ".lib"; + if (target->os == OsWindows && target_abi_is_gnu(target->abi)) { + return ".a"; + } else { + return ".lib"; + } } else { return ".dll"; } -- cgit v1.2.3 From 776423bbf72312e756eb661b616f0e1bb805f568 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 15 Jul 2019 23:44:44 -0400 Subject: fix result location alignment in ir_render_call --- src/codegen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/codegen.cpp') diff --git a/src/codegen.cpp b/src/codegen.cpp index 94e2a98b2f..234b28219b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -3837,7 +3837,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr return result_loc; } else if (handle_is_ptr(src_return_type)) { LLVMValueRef store_instr = LLVMBuildStore(g->builder, result, result_loc); - LLVMSetAlignment(store_instr, LLVMGetAlignment(result_loc)); + LLVMSetAlignment(store_instr, get_ptr_align(g, instruction->result_loc->value.type)); return result_loc; } else { return result; -- cgit v1.2.3