diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/all_types.hpp | 399 | ||||
| -rw-r--r-- | src/analyze.cpp | 38 | ||||
| -rw-r--r-- | src/analyze.hpp | 1 | ||||
| -rw-r--r-- | src/ast_render.cpp | 9 | ||||
| -rw-r--r-- | src/buffer.hpp | 10 | ||||
| -rw-r--r-- | src/codegen.cpp | 786 | ||||
| -rw-r--r-- | src/codegen.hpp | 5 | ||||
| -rw-r--r-- | src/compiler.cpp | 26 | ||||
| -rw-r--r-- | src/compiler.hpp | 1 | ||||
| -rw-r--r-- | src/config.h.in | 2 | ||||
| -rw-r--r-- | src/glibc.cpp | 406 | ||||
| -rw-r--r-- | src/glibc.hpp | 53 | ||||
| -rw-r--r-- | src/install_files.h | 1802 | ||||
| -rw-r--r-- | src/ir.cpp | 4803 | ||||
| -rw-r--r-- | src/ir_print.cpp | 369 | ||||
| -rw-r--r-- | src/link.cpp | 1168 | ||||
| -rw-r--r-- | src/main.cpp | 180 | ||||
| -rw-r--r-- | src/parser.cpp | 11 | ||||
| -rw-r--r-- | src/target.cpp | 92 | ||||
| -rw-r--r-- | src/target.hpp | 12 | ||||
| -rw-r--r-- | src/tokenizer.cpp | 117 | ||||
| -rw-r--r-- | src/tokenizer.hpp | 1 | ||||
| -rw-r--r-- | src/translate_c.cpp | 44 | ||||
| -rw-r--r-- | src/userland.cpp | 2 | ||||
| -rw-r--r-- | src/userland.h | 3 | ||||
| -rw-r--r-- | src/util.cpp | 26 | ||||
| -rw-r--r-- | src/util.hpp | 11 | ||||
| -rw-r--r-- | src/zig_clang.cpp | 161 | ||||
| -rw-r--r-- | src/zig_clang.h | 79 | ||||
| -rw-r--r-- | src/zig_llvm.cpp | 57 | ||||
| -rw-r--r-- | src/zig_llvm.h | 4 |
31 files changed, 8313 insertions, 2365 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 6595218bcf..3cdaf36cd9 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -34,12 +34,17 @@ struct CodeGen; struct ConstExprValue; struct IrInstruction; struct IrInstructionCast; +struct IrInstructionAllocaGen; struct IrBasicBlock; struct ScopeDecls; struct ZigWindowsSDK; struct Tld; struct TldExport; struct IrAnalyze; +struct ResultLoc; +struct ResultLocPeer; +struct ResultLocPeerParent; +struct ResultLocBitCast; enum X64CABIClass { X64CABIClass_Unknown, @@ -198,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 { @@ -289,6 +297,7 @@ struct RuntimeHintSlice { struct ConstGlobalRefs { LLVMValueRef llvm_value; LLVMValueRef llvm_global; + uint32_t align; }; struct ConstExprValue { @@ -325,6 +334,10 @@ struct ConstExprValue { RuntimeHintPtr rh_ptr; RuntimeHintSlice rh_slice; } data; + + // 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 { @@ -426,7 +439,7 @@ enum NodeType { NodeTypeVariableDeclaration, NodeTypeTestDecl, NodeTypeBinOpExpr, - NodeTypeUnwrapErrorExpr, + NodeTypeCatchExpr, NodeTypeFloatLiteral, NodeTypeIntLiteral, NodeTypeStringLiteral, @@ -1097,6 +1110,8 @@ struct ZigPackage { // reminder: hash tables must be initialized before use HashMap<Buf *, ZigPackage *, buf_hash, buf_eql_buf> package_table; + + bool added_to_cache; }; // Stuff that only applies to a struct which is the implicit root struct of a file @@ -1364,7 +1379,7 @@ struct ZigFn { AstNode *fn_no_inline_set_node; AstNode *fn_static_eval_set_node; - ZigList<IrInstruction *> alloca_list; + ZigList<IrInstructionAllocaGen *> alloca_gen_list; ZigList<ZigVar *> variable_list; Buf *section_name; @@ -1401,6 +1416,7 @@ enum BuiltinFnId { BuiltinFnIdMemberName, BuiltinFnIdField, BuiltinFnIdTypeInfo, + BuiltinFnIdHasField, BuiltinFnIdTypeof, BuiltinFnIdAddWithOverflow, BuiltinFnIdSubWithOverflow, @@ -1493,6 +1509,7 @@ enum BuiltinFnId { BuiltinFnIdAtomicRmw, BuiltinFnIdAtomicLoad, BuiltinFnIdHasDecl, + BuiltinFnIdUnionInit, }; struct BuiltinFnEntry { @@ -1744,7 +1761,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 { @@ -1787,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; @@ -1893,6 +1910,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; @@ -1903,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; @@ -1999,6 +2018,11 @@ struct ScopeDecls { bool any_imports_failed; }; +enum LVal { + LValNone, + LValPtr, +}; + // This scope comes from a block expression in user code. // NodeTypeBlock struct ScopeBlock { @@ -2007,12 +2031,14 @@ struct ScopeBlock { Buf *name; IrBasicBlock *end_block; IrInstruction *is_comptime; + ResultLocPeerParent *peer_parent; ZigList<IrInstruction *> *incoming_values; ZigList<IrBasicBlock *> *incoming_blocks; AstNode *safety_set_node; AstNode *fast_math_set_node; + LVal lval; bool safety_off; bool fast_math_on; }; @@ -2056,12 +2082,14 @@ struct ScopeCImport { struct ScopeLoop { Scope base; + LVal lval; Buf *name; IrBasicBlock *break_block; IrBasicBlock *continue_block; IrInstruction *is_comptime; ZigList<IrInstruction *> *incoming_values; ZigList<IrBasicBlock *> *incoming_blocks; + ResultLocPeerParent *peer_parent; }; // This scope blocks certain things from working such as comptime continue @@ -2138,6 +2166,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 @@ -2148,11 +2178,10 @@ struct IrBasicBlock { // if the branch is comptime. The instruction points to the reason // the basic block must be comptime. IrInstruction *must_be_comptime_source_instr; -}; - -enum LVal { - LValNone, - LValPtr, + IrInstruction *suspend_instruction_ref; + bool already_appended; + bool suspended; + bool in_resume_stack; }; // These instructions are in transition to having "pass 1" instructions @@ -2185,19 +2214,17 @@ enum IrInstructionId { IrInstructionIdUnionFieldPtr, IrInstructionIdElemPtr, IrInstructionIdVarPtr, - IrInstructionIdCall, + IrInstructionIdReturnPtr, + IrInstructionIdCallSrc, + IrInstructionIdCallGen, IrInstructionIdConst, IrInstructionIdReturn, IrInstructionIdCast, IrInstructionIdResizeSlice, IrInstructionIdContainerInitList, IrInstructionIdContainerInitFields, - IrInstructionIdStructInit, - IrInstructionIdUnionInit, IrInstructionIdUnreachable, IrInstructionIdTypeOf, - IrInstructionIdToPtrType, - IrInstructionIdPtrTypeChild, IrInstructionIdSetCold, IrInstructionIdSetRuntimeSafety, IrInstructionIdSetFloatMode, @@ -2222,6 +2249,7 @@ enum IrInstructionId { IrInstructionIdCDefine, IrInstructionIdCUndef, IrInstructionIdRef, + IrInstructionIdRefGen, IrInstructionIdCompileErr, IrInstructionIdCompileLog, IrInstructionIdErrName, @@ -2240,7 +2268,8 @@ enum IrInstructionId { IrInstructionIdBoolNot, IrInstructionIdMemset, IrInstructionIdMemcpy, - IrInstructionIdSlice, + IrInstructionIdSliceSrc, + IrInstructionIdSliceGen, IrInstructionIdMemberCount, IrInstructionIdMemberType, IrInstructionIdMemberName, @@ -2250,9 +2279,10 @@ enum IrInstructionId { IrInstructionIdHandle, IrInstructionIdAlignOf, IrInstructionIdOverflowOp, + IrInstructionIdTestErrSrc, + IrInstructionIdTestErrGen, IrInstructionIdMulAdd, IrInstructionIdFloatOp, - IrInstructionIdTestErr, IrInstructionIdUnwrapErrCode, IrInstructionIdUnwrapErrPayload, IrInstructionIdErrWrapCode, @@ -2261,7 +2291,7 @@ enum IrInstructionId { IrInstructionIdTestComptime, IrInstructionIdPtrCastSrc, IrInstructionIdPtrCastGen, - IrInstructionIdBitCast, + IrInstructionIdBitCastSrc, IrInstructionIdBitCastGen, IrInstructionIdWidenOrShorten, IrInstructionIdIntToPtr, @@ -2281,10 +2311,15 @@ enum IrInstructionId { IrInstructionIdByteOffsetOf, IrInstructionIdBitOffsetOf, IrInstructionIdTypeInfo, + IrInstructionIdHasField, IrInstructionIdTypeId, IrInstructionIdSetEvalBranchQuota, IrInstructionIdPtrType, IrInstructionIdAlignCast, + IrInstructionIdImplicitCast, + IrInstructionIdResolveResult, + IrInstructionIdResetResult, + IrInstructionIdResultPtr, IrInstructionIdOpaqueType, IrInstructionIdSetAlignStack, IrInstructionIdArgType, @@ -2323,10 +2358,14 @@ enum IrInstructionId { IrInstructionIdAssertNonNull, IrInstructionIdHasDecl, IrInstructionIdUndeclaredIdent, + IrInstructionIdAllocaSrc, + IrInstructionIdAllocaGen, + IrInstructionIdEndExpr, + IrInstructionIdPtrOfArrayToSlice, + IrInstructionIdUnionInitNamedField, }; struct IrInstruction { - IrInstructionId id; Scope *scope; AstNode *source_node; ConstExprValue value; @@ -2340,6 +2379,7 @@ 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; }; @@ -2350,14 +2390,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 { @@ -2367,6 +2407,7 @@ struct IrInstructionCondBr { IrBasicBlock *then_block; IrBasicBlock *else_block; IrInstruction *is_comptime; + ResultLoc *result_loc; }; struct IrInstructionBr { @@ -2419,6 +2460,7 @@ struct IrInstructionPhi { size_t incoming_count; IrBasicBlock **incoming_blocks; IrInstruction **incoming_values; + ResultLocPeerParent *peer_parent; }; enum IrUnOp { @@ -2434,8 +2476,9 @@ struct IrInstructionUnOp { IrInstruction base; IrUnOp op_id; - IrInstruction *value; LVal lval; + IrInstruction *value; + ResultLoc *result_loc; }; enum IrBinOp { @@ -2492,7 +2535,7 @@ struct IrInstructionLoadPtrGen { IrInstruction base; IrInstruction *ptr; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionStorePtr { @@ -2505,6 +2548,7 @@ struct IrInstructionStorePtr { struct IrInstructionFieldPtr { IrInstruction base; + bool initializing; IrInstruction *container_ptr; Buf *field_name_buffer; IrInstruction *field_name_expr; @@ -2521,9 +2565,10 @@ struct IrInstructionStructFieldPtr { struct IrInstructionUnionFieldPtr { IrInstruction base; + bool safety_check_on; + bool initializing; IrInstruction *union_ptr; TypeUnionField *field; - bool is_const; }; struct IrInstructionElemPtr { @@ -2531,8 +2576,8 @@ struct IrInstructionElemPtr { IrInstruction *array_ptr; IrInstruction *elem_index; + IrInstruction *init_array_type; PtrLen ptr_len; - bool is_const; bool safety_check_on; }; @@ -2543,14 +2588,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; @@ -2559,6 +2611,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; }; @@ -2581,7 +2648,6 @@ enum CastOp { CastOpNumLitToConcrete, CastOpErrSet, CastOpBitCast, - CastOpPtrOfArrayToSlice, }; // TODO get rid of this instruction, replace with instructions for each op code @@ -2591,14 +2657,13 @@ struct IrInstructionCast { IrInstruction *value; ZigType *dest_type; CastOp cast_op; - LLVMValueRef tmp_ptr; }; struct IrInstructionResizeSlice { IrInstruction base; IrInstruction *operand; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionContainerInitList { @@ -2607,15 +2672,15 @@ struct IrInstructionContainerInitList { IrInstruction *container_type; IrInstruction *elem_type; size_t item_count; - IrInstruction **items; - LLVMValueRef tmp_ptr; + IrInstruction **elem_result_loc_list; + IrInstruction *result_loc; }; struct IrInstructionContainerInitFieldsField { Buf *name; - IrInstruction *value; AstNode *source_node; TypeStructField *type_struct_field; + IrInstruction *result_loc; }; struct IrInstructionContainerInitFields { @@ -2624,29 +2689,7 @@ struct IrInstructionContainerInitFields { IrInstruction *container_type; size_t field_count; 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; - - ZigType *union_type; - TypeUnionField *field; - IrInstruction *init_value; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionUnreachable { @@ -2659,18 +2702,6 @@ struct IrInstructionTypeOf { IrInstruction *value; }; -struct IrInstructionToPtrType { - IrInstruction base; - - IrInstruction *ptr; -}; - -struct IrInstructionPtrTypeChild { - IrInstruction base; - - IrInstruction *value; -}; - struct IrInstructionSetCold { IrInstruction base; @@ -2764,8 +2795,9 @@ struct IrInstructionTestNonNull { struct IrInstructionOptionalUnwrapPtr { IrInstruction base; - IrInstruction *base_ptr; bool safety_check_on; + bool initializing; + IrInstruction *base_ptr; }; struct IrInstructionCtz { @@ -2805,11 +2837,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; @@ -2861,26 +2899,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 { @@ -2924,6 +2962,7 @@ struct IrInstructionToBytes { IrInstruction base; IrInstruction *target; + ResultLoc *result_loc; }; struct IrInstructionFromBytes { @@ -2931,6 +2970,7 @@ struct IrInstructionFromBytes { IrInstruction *dest_child_type; IrInstruction *target; + ResultLoc *result_loc; }; struct IrInstructionIntToFloat { @@ -2989,14 +3029,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 { @@ -3070,44 +3120,54 @@ struct IrInstructionAlignOf { }; // returns true if error, returns false if not error -struct IrInstructionTestErr { +struct IrInstructionTestErrSrc { IrInstruction base; - IrInstruction *value; + bool resolve_err_set; + IrInstruction *base_ptr; }; -struct IrInstructionUnwrapErrCode { +struct IrInstructionTestErrGen { IrInstruction base; IrInstruction *err_union; }; +// Takes an error union pointer, returns a pointer to the error code. +struct IrInstructionUnwrapErrCode { + IrInstruction base; + + bool initializing; + IrInstruction *err_union_ptr; +}; + struct IrInstructionUnwrapErrPayload { IrInstruction base; - IrInstruction *value; bool safety_check_on; + bool initializing; + IrInstruction *value; }; struct IrInstructionOptionalWrap { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionErrWrapPayload { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionErrWrapCode { IrInstruction base; - IrInstruction *value; - LLVMValueRef tmp_ptr; + IrInstruction *operand; + IrInstruction *result_loc; }; struct IrInstructionFnProto { @@ -3142,18 +3202,17 @@ struct IrInstructionPtrCastGen { bool safety_check_on; }; -struct IrInstructionBitCast { +struct IrInstructionBitCastSrc { IrInstruction base; - IrInstruction *dest_type; - IrInstruction *value; + IrInstruction *operand; + ResultLocBitCast *result_loc_bit_cast; }; struct IrInstructionBitCastGen { IrInstruction base; IrInstruction *operand; - LLVMValueRef tmp_ptr; }; struct IrInstructionWidenOrShorten { @@ -3229,8 +3288,8 @@ struct IrInstructionTypeName { struct IrInstructionDeclRef { IrInstruction base; - Tld *tld; LVal lval; + Tld *tld; }; struct IrInstructionPanic { @@ -3280,6 +3339,13 @@ struct IrInstructionTypeInfo { IrInstruction *type_value; }; +struct IrInstructionHasField { + IrInstruction base; + + IrInstruction *container_type; + IrInstruction *field_name; +}; + struct IrInstructionTypeId { IrInstruction base; @@ -3526,7 +3592,7 @@ struct IrInstructionVectorToArray { IrInstruction base; IrInstruction *vector; - LLVMValueRef tmp_ptr; + IrInstruction *result_loc; }; struct IrInstructionAssertZero { @@ -3541,6 +3607,15 @@ struct IrInstructionAssertNonNull { IrInstruction *target; }; +struct IrInstructionUnionInitNamedField { + IrInstruction base; + + IrInstruction *union_type; + IrInstruction *field_name; + IrInstruction *field_result_loc; + IrInstruction *result_loc; +}; + struct IrInstructionHasDecl { IrInstruction base; @@ -3554,6 +3629,139 @@ 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; +}; + +struct IrInstructionEndExpr { + IrInstruction base; + + IrInstruction *value; + ResultLoc *result_loc; +}; + +struct IrInstructionImplicitCast { + IrInstruction base; + + IrInstruction *dest_type; + IrInstruction *target; + ResultLoc *result_loc; +}; + +// This one is for writing through the result pointer. +struct IrInstructionResolveResult { + IrInstruction base; + + ResultLoc *result_loc; + 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 IrInstructionResetResult { + IrInstruction base; + + ResultLoc *result_loc; +}; + +struct IrInstructionPtrOfArrayToSlice { + IrInstruction base; + + IrInstruction *operand; + IrInstruction *result_loc; +}; + +enum ResultLocId { + ResultLocIdInvalid, + ResultLocIdNone, + ResultLocIdVar, + ResultLocIdReturn, + ResultLocIdPeer, + ResultLocIdPeerParent, + ResultLocIdInstruction, + ResultLocIdBitCast, +}; + +// Additions to this struct may need to be handled in +// ir_reset_result +struct ResultLoc { + ResultLocId id; + bool written; + IrInstruction *resolved_loc; // result ptr + IrInstruction *source_instruction; + IrInstruction *gen_instruction; // value to store to the result loc + ZigType *implicit_elem_type; +}; + +struct ResultLocNone { + ResultLoc base; +}; + +struct ResultLocVar { + ResultLoc base; + + ZigVar *var; +}; + +struct ResultLocReturn { + ResultLoc base; +}; + +struct IrSuspendPosition { + size_t basic_block_index; + size_t instruction_index; +}; + +struct ResultLocPeerParent { + ResultLoc base; + + bool skipped; + bool done_resuming; + IrBasicBlock *end_bb; + ResultLoc *parent; + ZigList<ResultLocPeer *> peers; + ZigType *resolved_type; + IrInstruction *is_comptime; +}; + +struct ResultLocPeer { + ResultLoc base; + + ResultLocPeerParent *parent; + IrBasicBlock *next_bb; + IrSuspendPosition suspend_pos; +}; + +// The result location is the source instruction +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; @@ -3581,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, @@ -3601,7 +3812,7 @@ struct FnWalkAttrs { struct FnWalkCall { ZigList<LLVMValueRef> *gen_param_values; - IrInstructionCall *inst; + IrInstructionCallGen *inst; bool is_var_args; }; diff --git a/src/analyze.cpp b/src/analyze.cpp index 13b35e0aff..3ec839464e 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -2995,7 +2995,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) { case NodeTypeBlock: case NodeTypeGroupedExpr: case NodeTypeBinOpExpr: - case NodeTypeUnwrapErrorExpr: + case NodeTypeCatchExpr: case NodeTypeFnCallExpr: case NodeTypeArrayAccessExpr: case NodeTypeSliceExpr: @@ -3896,22 +3896,21 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu Buf *pkg_root_src_dir = &package->root_src_dir; Buf resolved_root_src_dir = os_path_resolve(&pkg_root_src_dir, 1); - Buf namespace_name = BUF_INIT; - buf_init_from_buf(&namespace_name, &package->pkg_path); + Buf *namespace_name = buf_create_from_buf(&package->pkg_path); if (source_kind == SourceKindNonRoot) { assert(buf_starts_with_buf(resolved_path, &resolved_root_src_dir)); - if (buf_len(&namespace_name) != 0) { - buf_append_char(&namespace_name, NAMESPACE_SEP_CHAR); + if (buf_len(namespace_name) != 0) { + buf_append_char(namespace_name, NAMESPACE_SEP_CHAR); } // The namespace components are obtained from the relative path to the // source directory if (buf_len(&noextname) > buf_len(&resolved_root_src_dir)) { // Skip the trailing separator - buf_append_mem(&namespace_name, + buf_append_mem(namespace_name, buf_ptr(&noextname) + buf_len(&resolved_root_src_dir) + 1, buf_len(&noextname) - buf_len(&resolved_root_src_dir) - 1); } - buf_replace(&namespace_name, ZIG_OS_SEP_CHAR, NAMESPACE_SEP_CHAR); + buf_replace(namespace_name, ZIG_OS_SEP_CHAR, NAMESPACE_SEP_CHAR); } Buf *bare_name = buf_alloc(); os_path_extname(src_basename, bare_name, nullptr); @@ -3922,7 +3921,7 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu root_struct->line_offsets = tokenization.line_offsets; root_struct->path = resolved_path; root_struct->di_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname)); - ZigType *import_entry = get_root_container_type(g, buf_ptr(&namespace_name), bare_name, root_struct); + ZigType *import_entry = get_root_container_type(g, buf_ptr(namespace_name), bare_name, root_struct); if (source_kind == SourceKindRoot) { assert(g->root_import == nullptr); g->root_import = import_entry; @@ -3966,7 +3965,7 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *resolved_path, Bu } TldContainer *tld_container = allocate<TldContainer>(1); - init_tld(&tld_container->base, TldIdContainer, &namespace_name, VisibModPub, root_node, nullptr); + init_tld(&tld_container->base, TldIdContainer, namespace_name, VisibModPub, root_node, nullptr); tld_container->type_entry = import_entry; tld_container->decls_scope = import_entry->data.structure.decls_scope; g->resolve_queue.append(&tld_container->base); @@ -4181,6 +4180,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; @@ -4511,6 +4511,8 @@ bool fn_eval_cacheable(Scope *scope, ZigType *return_type) { ScopeVarDecl *var_scope = (ScopeVarDecl *)scope; if (type_is_invalid(var_scope->var->var_type)) return false; + if (var_scope->var->const_value->special == ConstValSpecialUndef) + return false; if (can_mutate_comptime_var_state(var_scope->var->const_value)) return false; } else if (scope->id == ScopeIdFnDef) { @@ -4710,7 +4712,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; } @@ -4998,12 +5000,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; @@ -5843,11 +5842,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, @@ -7281,6 +7275,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/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/ast_render.cpp b/src/ast_render.cpp index d93efe2193..154803f884 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -165,8 +165,8 @@ static const char *node_type_str(NodeType node_type) { return "Parens"; case NodeTypeBinOpExpr: return "BinOpExpr"; - case NodeTypeUnwrapErrorExpr: - return "UnwrapErrorExpr"; + case NodeTypeCatchExpr: + return "CatchExpr"; case NodeTypeFnCallExpr: return "FnCallExpr"; case NodeTypeArrayAccessExpr: @@ -444,9 +444,8 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { const char *extern_str = extern_string(node->data.fn_proto.is_extern); const char *export_str = export_string(node->data.fn_proto.is_export); const char *inline_str = inline_string(node->data.fn_proto.is_inline); - fprintf(ar->f, "%s%s%s%sfn", pub_str, inline_str, export_str, extern_str); + fprintf(ar->f, "%s%s%s%sfn ", pub_str, inline_str, export_str, extern_str); if (node->data.fn_proto.name != nullptr) { - fprintf(ar->f, " "); print_symbol(ar, node->data.fn_proto.name); } fprintf(ar->f, "("); @@ -1108,7 +1107,7 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { fprintf(ar->f, "]"); break; } - case NodeTypeUnwrapErrorExpr: + case NodeTypeCatchExpr: { render_node_ungrouped(ar, node->data.unwrap_err_expr.op1); fprintf(ar->f, " catch "); diff --git a/src/buffer.hpp b/src/buffer.hpp index d4a911fc21..d7254c18a7 100644 --- a/src/buffer.hpp +++ b/src/buffer.hpp @@ -136,11 +136,21 @@ static inline bool buf_eql_mem(Buf *buf, const char *mem, size_t mem_len) { return mem_eql_mem(buf_ptr(buf), buf_len(buf), mem, mem_len); } +static inline bool buf_eql_mem_ignore_case(Buf *buf, const char *mem, size_t mem_len) { + assert(buf->list.length); + return mem_eql_mem_ignore_case(buf_ptr(buf), buf_len(buf), mem, mem_len); +} + static inline bool buf_eql_str(Buf *buf, const char *str) { assert(buf->list.length); return buf_eql_mem(buf, str, strlen(str)); } +static inline bool buf_eql_str_ignore_case(Buf *buf, const char *str) { + assert(buf->list.length); + return buf_eql_mem_ignore_case(buf, str, strlen(str)); +} + static inline bool buf_starts_with_mem(Buf *buf, const char *mem, size_t mem_len) { if (buf_len(buf) < mem_len) { return false; diff --git a/src/codegen.cpp b/src/codegen.cpp index 41caa29dbd..234b28219b 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -24,9 +24,6 @@ #include <stdio.h> #include <errno.h> -#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"); @@ -180,6 +177,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); @@ -200,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)) { @@ -691,7 +690,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: @@ -859,9 +860,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; @@ -1339,7 +1338,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; @@ -1470,7 +1471,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; @@ -1526,7 +1529,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; @@ -1654,7 +1659,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; @@ -2004,6 +2011,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, @@ -2016,7 +2024,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 @@ -2025,11 +2033,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); } @@ -2310,7 +2316,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]; @@ -2404,17 +2410,33 @@ 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)) { + 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 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); } return nullptr; @@ -2952,7 +2974,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); @@ -2973,7 +2995,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); @@ -3006,12 +3028,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, @@ -3081,33 +3101,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) { @@ -3154,12 +3180,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(); } } @@ -3345,31 +3366,13 @@ 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; - 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; } @@ -3401,13 +3404,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) { @@ -3585,6 +3588,14 @@ static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrIn } } +static LLVMValueRef ir_render_return_ptr(CodeGen *g, IrExecutable *executable, + IrInstructionReturnPtr *instruction) +{ + src_assert(g->cur_ret_ptr != nullptr || !type_has_bits(instruction->base.value.type), + instruction->base.source_node); + 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; @@ -3736,7 +3747,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) { @@ -3759,8 +3770,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<LLVMValueRef> gen_param_values = {}; + LLVMValueRef result_loc = instruction->result_loc ? 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)); @@ -3768,7 +3780,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 = {}; @@ -3811,9 +3823,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) { @@ -3822,11 +3834,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, get_ptr_align(g, instruction->result_loc->value.type)); + return result_loc; } else { return result; } @@ -3835,6 +3847,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; @@ -3856,6 +3871,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; @@ -3863,8 +3881,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); @@ -3875,7 +3905,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 (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, ""); @@ -4075,14 +4110,17 @@ 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; 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"); @@ -4098,10 +4136,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, ""); } } } @@ -4224,17 +4268,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; } } @@ -4350,7 +4394,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; @@ -4526,28 +4572,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) { @@ -4619,16 +4665,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); @@ -4646,7 +4690,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); @@ -4877,10 +4923,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)) { @@ -4897,25 +4943,30 @@ 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; + 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; 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; + // 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, ""); } } 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 && + 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)) return nullptr; @@ -4951,13 +5002,18 @@ 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; } } -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); @@ -4965,23 +5021,32 @@ 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->value); + 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; } - 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) { @@ -4989,20 +5054,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) { @@ -5014,7 +5078,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)); @@ -5022,17 +5086,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) { @@ -5053,90 +5118,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; - - 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_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; @@ -5353,7 +5334,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; @@ -5499,12 +5482,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; + gen_store_untyped(g, vector, casted_ptr, get_ptr_align(g, instruction->result_loc->value.type), false); + return result_loc; } static LLVMValueRef ir_render_array_to_vector(CodeGen *g, IrExecutable *executable, @@ -5567,14 +5550,10 @@ 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); - switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdConst: case IrInstructionIdTypeOf: - case IrInstructionIdToPtrType: - case IrInstructionIdPtrTypeChild: case IrInstructionIdFieldPtr: case IrInstructionIdSetCold: case IrInstructionIdSetRuntimeSafety: @@ -5610,6 +5589,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdByteOffsetOf: case IrInstructionIdBitOffsetOf: case IrInstructionIdTypeInfo: + case IrInstructionIdHasField: case IrInstructionIdTypeId: case IrInstructionIdSetEvalBranchQuota: case IrInstructionIdPtrType: @@ -5636,10 +5616,23 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, case IrInstructionIdPtrCastSrc: case IrInstructionIdCmpxchgSrc: case IrInstructionIdLoadPtr: - case IrInstructionIdBitCast: case IrInstructionIdGlobalAsm: case IrInstructionIdHasDecl: case IrInstructionIdUndeclaredIdent: + case IrInstructionIdCallSrc: + case IrInstructionIdAllocaSrc: + case IrInstructionIdEndExpr: + case IrInstructionIdAllocaGen: + case IrInstructionIdImplicitCast: + case IrInstructionIdResolveResult: + case IrInstructionIdResetResult: + case IrInstructionIdResultPtr: + case IrInstructionIdContainerInitList: + case IrInstructionIdSliceSrc: + case IrInstructionIdRef: + case IrInstructionIdBitCastSrc: + case IrInstructionIdTestErrSrc: + case IrInstructionIdUnionInitNamedField: zig_unreachable(); case IrInstructionIdDeclVarGen: @@ -5664,10 +5657,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: @@ -5692,8 +5687,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: @@ -5708,8 +5703,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: @@ -5720,24 +5715,20 @@ 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: 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: 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: return ir_render_ptr_cast(g, executable, (IrInstructionPtrCastGen *)instruction); case IrInstructionIdBitCastGen: @@ -5754,8 +5745,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: @@ -5818,6 +5807,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(); } @@ -5829,7 +5820,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) { @@ -5837,6 +5827,9 @@ static void ir_render(CodeGen *g, ZigFn *fn_entry) { if (instruction->ref_count == 0 && !ir_has_side_effects(instruction)) continue; + 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); @@ -6626,7 +6619,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; } @@ -6751,7 +6745,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); @@ -6856,20 +6850,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) { @@ -6894,68 +6892,28 @@ static void do_code_gen(CodeGen *g) { } // allocate temporary stack data - 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 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 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; - } 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; - } 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; - } 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; - } 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; - } 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); - slot = &vector_to_array_instruction->tmp_ptr; - } else { - zig_unreachable(); + 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; + } } - *slot = build_alloca(g, slot_type, "", alignment_bytes); + instruction->base.llvm_value = build_alloca(g, child_type, instruction->name_hint, + get_ptr_align(g, ptr_type)); } 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 = {}; @@ -6982,8 +6940,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); @@ -7371,6 +7327,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); @@ -7460,6 +7417,7 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2); create_builtin_fn(g, BuiltinFnIdThis, "This", 0); create_builtin_fn(g, BuiltinFnIdHasDecl, "hasDecl", 2); + create_builtin_fn(g, BuiltinFnIdUnionInit, "unionInit", 3); } static const char *bool_to_str(bool b) { @@ -7962,6 +7920,14 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { } { 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" " Console,\n" " Windows,\n" @@ -7991,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)); @@ -8047,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); @@ -8098,6 +8078,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); @@ -8121,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); @@ -8131,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); } @@ -8171,8 +8153,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->llvm_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); @@ -8350,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); } } @@ -8377,6 +8360,10 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &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 @@ -8410,12 +8397,18 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &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"); } @@ -8565,9 +8558,9 @@ 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); +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; } @@ -8647,6 +8640,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) @@ -8687,17 +8712,13 @@ 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)) - { - g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g, g->root_package), "bootstrap.zig"); + 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 && 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) { @@ -8705,7 +8726,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); @@ -8720,10 +8741,10 @@ static void gen_root_source(CodeGen *g) { } -static void print_zig_cc_cmd(const char *zig_exe, ZigList<const char *> *args) { - fprintf(stderr, "%s", zig_exe); +static void print_zig_cc_cmd(ZigList<const char *> *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"); } @@ -8773,6 +8794,7 @@ 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]); } @@ -8860,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); } @@ -9420,6 +9442,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); @@ -9431,9 +9454,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) { + if (!pkg->added_to_cache) { cache_buf(ch, entry->key); add_cache_pkg(g, ch, entry->value); } @@ -9472,6 +9493,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); @@ -9489,6 +9515,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); @@ -9505,6 +9532,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); @@ -9612,7 +9640,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); } @@ -9676,10 +9704,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, @@ -9690,7 +9722,43 @@ 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); + + 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); } 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..5de36c1aab 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); @@ -58,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/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<Buf *> 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/config.h.in b/src/config.h.in index 93e31ad9b7..a99aab0d72 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -23,7 +23,5 @@ #define ZIG_LLD_LIBRARIES "@LLD_LIBRARIES@" #define ZIG_LLVM_CONFIG_EXE "@LLVM_CONFIG_EXE@" #define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@" -#define ZIG_STD_FILES "@ZIG_STD_FILES@" -#define ZIG_C_HEADER_FILES "@ZIG_C_HEADER_FILES@" #endif diff --git a/src/glibc.cpp b/src/glibc.cpp new file mode 100644 index 0000000000..d7ae47ed71 --- /dev/null +++ b/src/glibc.cpp @@ -0,0 +1,406 @@ +/* + * 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<ZigGLibCAbi>(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<Slice<uint8_t>> 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<Slice<uint8_t>> opt_component = SplitIterator_next(&it); + if (!opt_component.is_some) break; + SplitIterator line_it = memSplit(opt_component.value, str(" ")); + Optional<Slice<uint8_t>> 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<Slice<uint8_t>> 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<Slice<uint8_t>> opt_line = SplitIterator_next_separate(&it); + if (!opt_line.is_some) break; + + ver_list_base = allocate<ZigGLibCVerList>(glibc_abi->all_functions.length); + ZigTarget *target = allocate<ZigTarget>(1); + SplitIterator line_it = memSplit(opt_line.value, str(" ")); + for (;;) { + Optional<Slice<uint8_t>> opt_target = SplitIterator_next(&line_it); + if (!opt_target.is_some) break; + + SplitIterator component_it = memSplit(opt_target.value, str("-")); + Optional<Slice<uint8_t>> opt_arch = SplitIterator_next(&component_it); + assert(opt_arch.is_some); + Optional<Slice<uint8_t>> opt_os = SplitIterator_next(&component_it); + assert(opt_os.is_some); // it's always "linux" so we ignore it + Optional<Slice<uint8_t>> 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<Slice<uint8_t>> opt_line = SplitIterator_next_separate(&it); + assert(opt_line.is_some); + + SplitIterator line_it = memSplit(opt_line.value, str(" ")); + for (;;) { + Optional<Slice<uint8_t>> 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<CacheHash>(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; + + 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 <unistd.h> +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, 4096); + 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<ZigGLibCVersion> all_versions; + ZigList<ZigGLibCFn> all_functions; + // The value is a pointer to all_functions.length items and each item is an index + // into all_functions. + HashMap<const ZigTarget *, ZigGLibCVerList *, hash_glibc_target, eql_glibc_target> 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/install_files.h b/src/install_files.h new file mode 100644 index 0000000000..8b6a4dc059 --- /dev/null +++ b/src/install_files.h @@ -0,0 +1,1802 @@ +#ifndef ZIG_INSTALL_FILES_H +#define ZIG_INSTALL_FILES_H +static const char *ZIG_MUSL_SRC_FILES[] = { +"musl/src/aio/aio.c", +"musl/src/aio/aio_suspend.c", +"musl/src/aio/lio_listio.c", +"musl/src/complex/__cexp.c", +"musl/src/complex/__cexpf.c", +"musl/src/complex/cabs.c", +"musl/src/complex/cabsf.c", +"musl/src/complex/cabsl.c", +"musl/src/complex/cacos.c", +"musl/src/complex/cacosf.c", +"musl/src/complex/cacosh.c", +"musl/src/complex/cacoshf.c", +"musl/src/complex/cacoshl.c", +"musl/src/complex/cacosl.c", +"musl/src/complex/carg.c", +"musl/src/complex/cargf.c", +"musl/src/complex/cargl.c", +"musl/src/complex/casin.c", +"musl/src/complex/casinf.c", +"musl/src/complex/casinh.c", +"musl/src/complex/casinhf.c", +"musl/src/complex/casinhl.c", +"musl/src/complex/casinl.c", +"musl/src/complex/catan.c", +"musl/src/complex/catanf.c", +"musl/src/complex/catanh.c", +"musl/src/complex/catanhf.c", +"musl/src/complex/catanhl.c", +"musl/src/complex/catanl.c", +"musl/src/complex/ccos.c", +"musl/src/complex/ccosf.c", +"musl/src/complex/ccosh.c", +"musl/src/complex/ccoshf.c", +"musl/src/complex/ccoshl.c", +"musl/src/complex/ccosl.c", +"musl/src/complex/cexp.c", +"musl/src/complex/cexpf.c", +"musl/src/complex/cexpl.c", +"musl/src/complex/cimag.c", +"musl/src/complex/cimagf.c", +"musl/src/complex/cimagl.c", +"musl/src/complex/clog.c", +"musl/src/complex/clogf.c", +"musl/src/complex/clogl.c", +"musl/src/complex/conj.c", +"musl/src/complex/conjf.c", +"musl/src/complex/conjl.c", +"musl/src/complex/cpow.c", +"musl/src/complex/cpowf.c", +"musl/src/complex/cpowl.c", +"musl/src/complex/cproj.c", +"musl/src/complex/cprojf.c", +"musl/src/complex/cprojl.c", +"musl/src/complex/creal.c", +"musl/src/complex/crealf.c", +"musl/src/complex/creall.c", +"musl/src/complex/csin.c", +"musl/src/complex/csinf.c", +"musl/src/complex/csinh.c", +"musl/src/complex/csinhf.c", +"musl/src/complex/csinhl.c", +"musl/src/complex/csinl.c", +"musl/src/complex/csqrt.c", +"musl/src/complex/csqrtf.c", +"musl/src/complex/csqrtl.c", +"musl/src/complex/ctan.c", +"musl/src/complex/ctanf.c", +"musl/src/complex/ctanh.c", +"musl/src/complex/ctanhf.c", +"musl/src/complex/ctanhl.c", +"musl/src/complex/ctanl.c", +"musl/src/conf/confstr.c", +"musl/src/conf/fpathconf.c", +"musl/src/conf/legacy.c", +"musl/src/conf/pathconf.c", +"musl/src/conf/sysconf.c", +"musl/src/crypt/crypt.c", +"musl/src/crypt/crypt_blowfish.c", +"musl/src/crypt/crypt_des.c", +"musl/src/crypt/crypt_des.h", +"musl/src/crypt/crypt_md5.c", +"musl/src/crypt/crypt_r.c", +"musl/src/crypt/crypt_sha256.c", +"musl/src/crypt/crypt_sha512.c", +"musl/src/crypt/encrypt.c", +"musl/src/ctype/__ctype_b_loc.c", +"musl/src/ctype/__ctype_get_mb_cur_max.c", +"musl/src/ctype/__ctype_tolower_loc.c", +"musl/src/ctype/__ctype_toupper_loc.c", +"musl/src/ctype/alpha.h", +"musl/src/ctype/isalnum.c", +"musl/src/ctype/isalpha.c", +"musl/src/ctype/isascii.c", +"musl/src/ctype/isblank.c", +"musl/src/ctype/iscntrl.c", +"musl/src/ctype/isdigit.c", +"musl/src/ctype/isgraph.c", +"musl/src/ctype/islower.c", +"musl/src/ctype/isprint.c", +"musl/src/ctype/ispunct.c", +"musl/src/ctype/isspace.c", +"musl/src/ctype/isupper.c", +"musl/src/ctype/iswalnum.c", +"musl/src/ctype/iswalpha.c", +"musl/src/ctype/iswblank.c", +"musl/src/ctype/iswcntrl.c", +"musl/src/ctype/iswctype.c", +"musl/src/ctype/iswdigit.c", +"musl/src/ctype/iswgraph.c", +"musl/src/ctype/iswlower.c", +"musl/src/ctype/iswprint.c", +"musl/src/ctype/iswpunct.c", +"musl/src/ctype/iswspace.c", +"musl/src/ctype/iswupper.c", +"musl/src/ctype/iswxdigit.c", +"musl/src/ctype/isxdigit.c", +"musl/src/ctype/nonspacing.h", +"musl/src/ctype/punct.h", +"musl/src/ctype/toascii.c", +"musl/src/ctype/tolower.c", +"musl/src/ctype/toupper.c", +"musl/src/ctype/towctrans.c", +"musl/src/ctype/wcswidth.c", +"musl/src/ctype/wctrans.c", +"musl/src/ctype/wcwidth.c", +"musl/src/ctype/wide.h", +"musl/src/dirent/__dirent.h", +"musl/src/dirent/alphasort.c", +"musl/src/dirent/closedir.c", +"musl/src/dirent/dirfd.c", +"musl/src/dirent/fdopendir.c", +"musl/src/dirent/opendir.c", +"musl/src/dirent/readdir.c", +"musl/src/dirent/readdir_r.c", +"musl/src/dirent/rewinddir.c", +"musl/src/dirent/scandir.c", +"musl/src/dirent/seekdir.c", +"musl/src/dirent/telldir.c", +"musl/src/dirent/versionsort.c", +"musl/src/env/__environ.c", +"musl/src/env/__init_tls.c", +"musl/src/env/__libc_start_main.c", +"musl/src/env/__reset_tls.c", +"musl/src/env/__stack_chk_fail.c", +"musl/src/env/clearenv.c", +"musl/src/env/getenv.c", +"musl/src/env/putenv.c", +"musl/src/env/setenv.c", +"musl/src/env/unsetenv.c", +"musl/src/errno/__errno_location.c", +"musl/src/errno/__strerror.h", +"musl/src/errno/strerror.c", +"musl/src/exit/_Exit.c", +"musl/src/exit/abort.c", +"musl/src/exit/arm/__aeabi_atexit.c", +"musl/src/exit/assert.c", +"musl/src/exit/at_quick_exit.c", +"musl/src/exit/atexit.c", +"musl/src/exit/exit.c", +"musl/src/exit/quick_exit.c", +"musl/src/fcntl/creat.c", +"musl/src/fcntl/fcntl.c", +"musl/src/fcntl/open.c", +"musl/src/fcntl/openat.c", +"musl/src/fcntl/posix_fadvise.c", +"musl/src/fcntl/posix_fallocate.c", +"musl/src/fenv/__flt_rounds.c", +"musl/src/fenv/aarch64/fenv.s", +"musl/src/fenv/arm/fenv-hf.S", +"musl/src/fenv/arm/fenv.c", +"musl/src/fenv/fegetexceptflag.c", +"musl/src/fenv/feholdexcept.c", +"musl/src/fenv/fenv.c", +"musl/src/fenv/fesetexceptflag.c", +"musl/src/fenv/fesetround.c", +"musl/src/fenv/feupdateenv.c", +"musl/src/fenv/i386/fenv.s", +"musl/src/fenv/m68k/fenv.c", +"musl/src/fenv/mips/fenv-sf.c", +"musl/src/fenv/mips/fenv.S", +"musl/src/fenv/mips64/fenv-sf.c", +"musl/src/fenv/mips64/fenv.S", +"musl/src/fenv/mipsn32/fenv-sf.c", +"musl/src/fenv/mipsn32/fenv.S", +"musl/src/fenv/powerpc/fenv-sf.c", +"musl/src/fenv/powerpc/fenv.S", +"musl/src/fenv/powerpc64/fenv.c", +"musl/src/fenv/s390x/fenv.c", +"musl/src/fenv/sh/fenv-nofpu.c", +"musl/src/fenv/sh/fenv.S", +"musl/src/fenv/x32/fenv.s", +"musl/src/fenv/x86_64/fenv.s", +"musl/src/include/arpa/inet.h", +"musl/src/include/crypt.h", +"musl/src/include/errno.h", +"musl/src/include/features.h", +"musl/src/include/langinfo.h", +"musl/src/include/pthread.h", +"musl/src/include/resolv.h", +"musl/src/include/signal.h", +"musl/src/include/stdio.h", +"musl/src/include/stdlib.h", +"musl/src/include/string.h", +"musl/src/include/sys/auxv.h", +"musl/src/include/sys/mman.h", +"musl/src/include/sys/sysinfo.h", +"musl/src/include/sys/time.h", +"musl/src/include/time.h", +"musl/src/include/unistd.h", +"musl/src/internal/aarch64/syscall.s", +"musl/src/internal/arm/syscall.s", +"musl/src/internal/atomic.h", +"musl/src/internal/dynlink.h", +"musl/src/internal/fdpic_crt.h", +"musl/src/internal/floatscan.c", +"musl/src/internal/floatscan.h", +"musl/src/internal/futex.h", +"musl/src/internal/i386/syscall.s", +"musl/src/internal/intscan.c", +"musl/src/internal/intscan.h", +"musl/src/internal/ksigaction.h", +"musl/src/internal/libc.c", +"musl/src/internal/libc.h", +"musl/src/internal/libm.h", +"musl/src/internal/locale_impl.h", +"musl/src/internal/lock.h", +"musl/src/internal/m68k/syscall.s", +"musl/src/internal/malloc_impl.h", +"musl/src/internal/microblaze/syscall.s", +"musl/src/internal/mips/syscall.s", +"musl/src/internal/mips64/syscall.s", +"musl/src/internal/mipsn32/syscall.s", +"musl/src/internal/or1k/syscall.s", +"musl/src/internal/powerpc/syscall.s", +"musl/src/internal/powerpc64/syscall.s", +"musl/src/internal/procfdname.c", +"musl/src/internal/pthread_impl.h", +"musl/src/internal/s390x/syscall.s", +"musl/src/internal/sh/__shcall.c", +"musl/src/internal/sh/syscall.s", +"musl/src/internal/shgetc.c", +"musl/src/internal/shgetc.h", +"musl/src/internal/stdio_impl.h", +"musl/src/internal/syscall.c", +"musl/src/internal/syscall.h", +"musl/src/internal/syscall_ret.c", +"musl/src/internal/vdso.c", +"musl/src/internal/version.c", +"musl/src/internal/version.h", +"musl/src/internal/x32/syscall.s", +"musl/src/internal/x86_64/syscall.s", +"musl/src/ipc/ftok.c", +"musl/src/ipc/ipc.h", +"musl/src/ipc/msgctl.c", +"musl/src/ipc/msgget.c", +"musl/src/ipc/msgrcv.c", +"musl/src/ipc/msgsnd.c", +"musl/src/ipc/semctl.c", +"musl/src/ipc/semget.c", +"musl/src/ipc/semop.c", +"musl/src/ipc/semtimedop.c", +"musl/src/ipc/shmat.c", +"musl/src/ipc/shmctl.c", +"musl/src/ipc/shmdt.c", +"musl/src/ipc/shmget.c", +"musl/src/ldso/__dlsym.c", +"musl/src/ldso/aarch64/dlsym.s", +"musl/src/ldso/aarch64/tlsdesc.s", +"musl/src/ldso/arm/dlsym.s", +"musl/src/ldso/arm/find_exidx.c", +"musl/src/ldso/arm/tlsdesc.S", +"musl/src/ldso/dl_iterate_phdr.c", +"musl/src/ldso/dladdr.c", +"musl/src/ldso/dlclose.c", +"musl/src/ldso/dlerror.c", +"musl/src/ldso/dlinfo.c", +"musl/src/ldso/dlopen.c", +"musl/src/ldso/dlsym.c", +"musl/src/ldso/i386/dlsym.s", +"musl/src/ldso/i386/tlsdesc.s", +"musl/src/ldso/m68k/dlsym.s", +"musl/src/ldso/microblaze/dlsym.s", +"musl/src/ldso/mips/dlsym.s", +"musl/src/ldso/mips64/dlsym.s", +"musl/src/ldso/mipsn32/dlsym.s", +"musl/src/ldso/or1k/dlsym.s", +"musl/src/ldso/powerpc/dlsym.s", +"musl/src/ldso/powerpc64/dlsym.s", +"musl/src/ldso/s390x/dlsym.s", +"musl/src/ldso/sh/dlsym.s", +"musl/src/ldso/tlsdesc.c", +"musl/src/ldso/x32/dlsym.s", +"musl/src/ldso/x86_64/dlsym.s", +"musl/src/ldso/x86_64/tlsdesc.s", +"musl/src/legacy/cuserid.c", +"musl/src/legacy/daemon.c", +"musl/src/legacy/err.c", +"musl/src/legacy/euidaccess.c", +"musl/src/legacy/ftw.c", +"musl/src/legacy/futimes.c", +"musl/src/legacy/getdtablesize.c", +"musl/src/legacy/getloadavg.c", +"musl/src/legacy/getpagesize.c", +"musl/src/legacy/getpass.c", +"musl/src/legacy/getusershell.c", +"musl/src/legacy/isastream.c", +"musl/src/legacy/lutimes.c", +"musl/src/legacy/ulimit.c", +"musl/src/legacy/utmpx.c", +"musl/src/legacy/valloc.c", +"musl/src/linux/adjtime.c", +"musl/src/linux/adjtimex.c", +"musl/src/linux/arch_prctl.c", +"musl/src/linux/brk.c", +"musl/src/linux/cache.c", +"musl/src/linux/cap.c", +"musl/src/linux/chroot.c", +"musl/src/linux/clock_adjtime.c", +"musl/src/linux/clone.c", +"musl/src/linux/epoll.c", +"musl/src/linux/eventfd.c", +"musl/src/linux/fallocate.c", +"musl/src/linux/fanotify.c", +"musl/src/linux/flock.c", +"musl/src/linux/getdents.c", +"musl/src/linux/getrandom.c", +"musl/src/linux/inotify.c", +"musl/src/linux/ioperm.c", +"musl/src/linux/iopl.c", +"musl/src/linux/klogctl.c", +"musl/src/linux/memfd_create.c", +"musl/src/linux/mlock2.c", +"musl/src/linux/module.c", +"musl/src/linux/mount.c", +"musl/src/linux/name_to_handle_at.c", +"musl/src/linux/open_by_handle_at.c", +"musl/src/linux/personality.c", +"musl/src/linux/pivot_root.c", +"musl/src/linux/ppoll.c", +"musl/src/linux/prctl.c", +"musl/src/linux/prlimit.c", +"musl/src/linux/process_vm.c", +"musl/src/linux/ptrace.c", +"musl/src/linux/quotactl.c", +"musl/src/linux/readahead.c", +"musl/src/linux/reboot.c", +"musl/src/linux/remap_file_pages.c", +"musl/src/linux/sbrk.c", +"musl/src/linux/sendfile.c", +"musl/src/linux/setfsgid.c", +"musl/src/linux/setfsuid.c", +"musl/src/linux/setgroups.c", +"musl/src/linux/sethostname.c", +"musl/src/linux/setns.c", +"musl/src/linux/settimeofday.c", +"musl/src/linux/signalfd.c", +"musl/src/linux/splice.c", +"musl/src/linux/stime.c", +"musl/src/linux/swap.c", +"musl/src/linux/sync_file_range.c", +"musl/src/linux/syncfs.c", +"musl/src/linux/sysinfo.c", +"musl/src/linux/tee.c", +"musl/src/linux/timerfd.c", +"musl/src/linux/unshare.c", +"musl/src/linux/utimes.c", +"musl/src/linux/vhangup.c", +"musl/src/linux/vmsplice.c", +"musl/src/linux/wait3.c", +"musl/src/linux/wait4.c", +"musl/src/linux/x32/sysinfo.c", +"musl/src/linux/xattr.c", +"musl/src/locale/__lctrans.c", +"musl/src/locale/__mo_lookup.c", +"musl/src/locale/big5.h", +"musl/src/locale/bind_textdomain_codeset.c", +"musl/src/locale/c_locale.c", +"musl/src/locale/catclose.c", +"musl/src/locale/catgets.c", +"musl/src/locale/catopen.c", +"musl/src/locale/codepages.h", +"musl/src/locale/dcngettext.c", +"musl/src/locale/duplocale.c", +"musl/src/locale/freelocale.c", +"musl/src/locale/gb18030.h", +"musl/src/locale/hkscs.h", +"musl/src/locale/iconv.c", +"musl/src/locale/iconv_close.c", +"musl/src/locale/jis0208.h", +"musl/src/locale/ksc.h", +"musl/src/locale/langinfo.c", +"musl/src/locale/legacychars.h", +"musl/src/locale/locale_map.c", +"musl/src/locale/localeconv.c", +"musl/src/locale/newlocale.c", +"musl/src/locale/pleval.c", +"musl/src/locale/pleval.h", +"musl/src/locale/revjis.h", +"musl/src/locale/setlocale.c", +"musl/src/locale/strcoll.c", +"musl/src/locale/strfmon.c", +"musl/src/locale/strxfrm.c", +"musl/src/locale/textdomain.c", +"musl/src/locale/uselocale.c", +"musl/src/locale/wcscoll.c", +"musl/src/locale/wcsxfrm.c", +"musl/src/malloc/DESIGN", +"musl/src/malloc/aligned_alloc.c", +"musl/src/malloc/expand_heap.c", +"musl/src/malloc/lite_malloc.c", +"musl/src/malloc/malloc.c", +"musl/src/malloc/malloc_usable_size.c", +"musl/src/malloc/memalign.c", +"musl/src/malloc/posix_memalign.c", +"musl/src/math/__cos.c", +"musl/src/math/__cosdf.c", +"musl/src/math/__cosl.c", +"musl/src/math/__expo2.c", +"musl/src/math/__expo2f.c", +"musl/src/math/__fpclassify.c", +"musl/src/math/__fpclassifyf.c", +"musl/src/math/__fpclassifyl.c", +"musl/src/math/__invtrigl.c", +"musl/src/math/__invtrigl.h", +"musl/src/math/__polevll.c", +"musl/src/math/__rem_pio2.c", +"musl/src/math/__rem_pio2_large.c", +"musl/src/math/__rem_pio2f.c", +"musl/src/math/__rem_pio2l.c", +"musl/src/math/__signbit.c", +"musl/src/math/__signbitf.c", +"musl/src/math/__signbitl.c", +"musl/src/math/__sin.c", +"musl/src/math/__sindf.c", +"musl/src/math/__sinl.c", +"musl/src/math/__tan.c", +"musl/src/math/__tandf.c", +"musl/src/math/__tanl.c", +"musl/src/math/aarch64/ceil.c", +"musl/src/math/aarch64/ceilf.c", +"musl/src/math/aarch64/fabs.c", +"musl/src/math/aarch64/fabsf.c", +"musl/src/math/aarch64/floor.c", +"musl/src/math/aarch64/floorf.c", +"musl/src/math/aarch64/fma.c", +"musl/src/math/aarch64/fmaf.c", +"musl/src/math/aarch64/fmax.c", +"musl/src/math/aarch64/fmaxf.c", +"musl/src/math/aarch64/fmin.c", +"musl/src/math/aarch64/fminf.c", +"musl/src/math/aarch64/llrint.c", +"musl/src/math/aarch64/llrintf.c", +"musl/src/math/aarch64/llround.c", +"musl/src/math/aarch64/llroundf.c", +"musl/src/math/aarch64/lrint.c", +"musl/src/math/aarch64/lrintf.c", +"musl/src/math/aarch64/lround.c", +"musl/src/math/aarch64/lroundf.c", +"musl/src/math/aarch64/nearbyint.c", +"musl/src/math/aarch64/nearbyintf.c", +"musl/src/math/aarch64/rint.c", +"musl/src/math/aarch64/rintf.c", +"musl/src/math/aarch64/round.c", +"musl/src/math/aarch64/roundf.c", +"musl/src/math/aarch64/sqrt.c", +"musl/src/math/aarch64/sqrtf.c", +"musl/src/math/aarch64/trunc.c", +"musl/src/math/aarch64/truncf.c", +"musl/src/math/acos.c", +"musl/src/math/acosf.c", +"musl/src/math/acosh.c", +"musl/src/math/acoshf.c", +"musl/src/math/acoshl.c", +"musl/src/math/acosl.c", +"musl/src/math/arm/fabs.c", +"musl/src/math/arm/fabsf.c", +"musl/src/math/arm/fma.c", +"musl/src/math/arm/fmaf.c", +"musl/src/math/arm/sqrt.c", +"musl/src/math/arm/sqrtf.c", +"musl/src/math/asin.c", +"musl/src/math/asinf.c", +"musl/src/math/asinh.c", +"musl/src/math/asinhf.c", +"musl/src/math/asinhl.c", +"musl/src/math/asinl.c", +"musl/src/math/atan.c", +"musl/src/math/atan2.c", +"musl/src/math/atan2f.c", +"musl/src/math/atan2l.c", +"musl/src/math/atanf.c", +"musl/src/math/atanh.c", +"musl/src/math/atanhf.c", +"musl/src/math/atanhl.c", +"musl/src/math/atanl.c", +"musl/src/math/cbrt.c", +"musl/src/math/cbrtf.c", +"musl/src/math/cbrtl.c", +"musl/src/math/ceil.c", +"musl/src/math/ceilf.c", +"musl/src/math/ceill.c", +"musl/src/math/copysign.c", +"musl/src/math/copysignf.c", +"musl/src/math/copysignl.c", +"musl/src/math/cos.c", +"musl/src/math/cosf.c", +"musl/src/math/cosh.c", +"musl/src/math/coshf.c", +"musl/src/math/coshl.c", +"musl/src/math/cosl.c", +"musl/src/math/erf.c", +"musl/src/math/erff.c", +"musl/src/math/erfl.c", +"musl/src/math/exp.c", +"musl/src/math/exp10.c", +"musl/src/math/exp10f.c", +"musl/src/math/exp10l.c", +"musl/src/math/exp2.c", +"musl/src/math/exp2f.c", +"musl/src/math/exp2l.c", +"musl/src/math/expf.c", +"musl/src/math/expl.c", +"musl/src/math/expm1.c", +"musl/src/math/expm1f.c", +"musl/src/math/expm1l.c", +"musl/src/math/fabs.c", +"musl/src/math/fabsf.c", +"musl/src/math/fabsl.c", +"musl/src/math/fdim.c", +"musl/src/math/fdimf.c", +"musl/src/math/fdiml.c", +"musl/src/math/finite.c", +"musl/src/math/finitef.c", +"musl/src/math/floor.c", +"musl/src/math/floorf.c", +"musl/src/math/floorl.c", +"musl/src/math/fma.c", +"musl/src/math/fmaf.c", +"musl/src/math/fmal.c", +"musl/src/math/fmax.c", +"musl/src/math/fmaxf.c", +"musl/src/math/fmaxl.c", +"musl/src/math/fmin.c", +"musl/src/math/fminf.c", +"musl/src/math/fminl.c", +"musl/src/math/fmod.c", +"musl/src/math/fmodf.c", +"musl/src/math/fmodl.c", +"musl/src/math/frexp.c", +"musl/src/math/frexpf.c", +"musl/src/math/frexpl.c", +"musl/src/math/hypot.c", +"musl/src/math/hypotf.c", +"musl/src/math/hypotl.c", +"musl/src/math/i386/__invtrigl.s", +"musl/src/math/i386/acos.s", +"musl/src/math/i386/acosf.s", +"musl/src/math/i386/acosl.s", +"musl/src/math/i386/asin.s", +"musl/src/math/i386/asinf.s", +"musl/src/math/i386/asinl.s", +"musl/src/math/i386/atan.s", +"musl/src/math/i386/atan2.s", +"musl/src/math/i386/atan2f.s", +"musl/src/math/i386/atan2l.s", +"musl/src/math/i386/atanf.s", +"musl/src/math/i386/atanl.s", +"musl/src/math/i386/ceil.s", +"musl/src/math/i386/ceilf.s", +"musl/src/math/i386/ceill.s", +"musl/src/math/i386/exp.s", +"musl/src/math/i386/exp2.s", +"musl/src/math/i386/exp2f.s", +"musl/src/math/i386/exp2l.s", +"musl/src/math/i386/expf.s", +"musl/src/math/i386/expl.s", +"musl/src/math/i386/expm1.s", +"musl/src/math/i386/expm1f.s", +"musl/src/math/i386/expm1l.s", +"musl/src/math/i386/fabs.s", +"musl/src/math/i386/fabsf.s", +"musl/src/math/i386/fabsl.s", +"musl/src/math/i386/floor.s", +"musl/src/math/i386/floorf.s", +"musl/src/math/i386/floorl.s", +"musl/src/math/i386/fmod.s", +"musl/src/math/i386/fmodf.s", +"musl/src/math/i386/fmodl.s", +"musl/src/math/i386/hypot.s", +"musl/src/math/i386/hypotf.s", +"musl/src/math/i386/ldexp.s", +"musl/src/math/i386/ldexpf.s", +"musl/src/math/i386/ldexpl.s", +"musl/src/math/i386/llrint.s", +"musl/src/math/i386/llrintf.s", +"musl/src/math/i386/llrintl.s", +"musl/src/math/i386/log.s", +"musl/src/math/i386/log10.s", +"musl/src/math/i386/log10f.s", +"musl/src/math/i386/log10l.s", +"musl/src/math/i386/log1p.s", +"musl/src/math/i386/log1pf.s", +"musl/src/math/i386/log1pl.s", +"musl/src/math/i386/log2.s", +"musl/src/math/i386/log2f.s", +"musl/src/math/i386/log2l.s", +"musl/src/math/i386/logf.s", +"musl/src/math/i386/logl.s", +"musl/src/math/i386/lrint.s", +"musl/src/math/i386/lrintf.s", +"musl/src/math/i386/lrintl.s", +"musl/src/math/i386/remainder.s", +"musl/src/math/i386/remainderf.s", +"musl/src/math/i386/remainderl.s", +"musl/src/math/i386/remquo.s", +"musl/src/math/i386/remquof.s", +"musl/src/math/i386/remquol.s", +"musl/src/math/i386/rint.s", +"musl/src/math/i386/rintf.s", +"musl/src/math/i386/rintl.s", +"musl/src/math/i386/scalbln.s", +"musl/src/math/i386/scalblnf.s", +"musl/src/math/i386/scalblnl.s", +"musl/src/math/i386/scalbn.s", +"musl/src/math/i386/scalbnf.s", +"musl/src/math/i386/scalbnl.s", +"musl/src/math/i386/sqrt.s", +"musl/src/math/i386/sqrtf.s", +"musl/src/math/i386/sqrtl.s", +"musl/src/math/i386/trunc.s", +"musl/src/math/i386/truncf.s", +"musl/src/math/i386/truncl.s", +"musl/src/math/ilogb.c", +"musl/src/math/ilogbf.c", +"musl/src/math/ilogbl.c", +"musl/src/math/j0.c", +"musl/src/math/j0f.c", +"musl/src/math/j1.c", +"musl/src/math/j1f.c", +"musl/src/math/jn.c", +"musl/src/math/jnf.c", +"musl/src/math/ldexp.c", +"musl/src/math/ldexpf.c", +"musl/src/math/ldexpl.c", +"musl/src/math/lgamma.c", +"musl/src/math/lgamma_r.c", +"musl/src/math/lgammaf.c", +"musl/src/math/lgammaf_r.c", +"musl/src/math/lgammal.c", +"musl/src/math/llrint.c", +"musl/src/math/llrintf.c", +"musl/src/math/llrintl.c", +"musl/src/math/llround.c", +"musl/src/math/llroundf.c", +"musl/src/math/llroundl.c", +"musl/src/math/log.c", +"musl/src/math/log10.c", +"musl/src/math/log10f.c", +"musl/src/math/log10l.c", +"musl/src/math/log1p.c", +"musl/src/math/log1pf.c", +"musl/src/math/log1pl.c", +"musl/src/math/log2.c", +"musl/src/math/log2f.c", +"musl/src/math/log2l.c", +"musl/src/math/logb.c", +"musl/src/math/logbf.c", +"musl/src/math/logbl.c", +"musl/src/math/logf.c", +"musl/src/math/logl.c", +"musl/src/math/lrint.c", +"musl/src/math/lrintf.c", +"musl/src/math/lrintl.c", +"musl/src/math/lround.c", +"musl/src/math/lroundf.c", +"musl/src/math/lroundl.c", +"musl/src/math/modf.c", +"musl/src/math/modff.c", +"musl/src/math/modfl.c", +"musl/src/math/nan.c", +"musl/src/math/nanf.c", +"musl/src/math/nanl.c", +"musl/src/math/nearbyint.c", +"musl/src/math/nearbyintf.c", +"musl/src/math/nearbyintl.c", +"musl/src/math/nextafter.c", +"musl/src/math/nextafterf.c", +"musl/src/math/nextafterl.c", +"musl/src/math/nexttoward.c", +"musl/src/math/nexttowardf.c", +"musl/src/math/nexttowardl.c", +"musl/src/math/pow.c", +"musl/src/math/powerpc/fabs.c", +"musl/src/math/powerpc/fabsf.c", +"musl/src/math/powerpc/fma.c", +"musl/src/math/powerpc/fmaf.c", +"musl/src/math/powerpc/sqrt.c", +"musl/src/math/powerpc/sqrtf.c", +"musl/src/math/powerpc64/ceil.c", +"musl/src/math/powerpc64/ceilf.c", +"musl/src/math/powerpc64/fabs.c", +"musl/src/math/powerpc64/fabsf.c", +"musl/src/math/powerpc64/floor.c", +"musl/src/math/powerpc64/floorf.c", +"musl/src/math/powerpc64/fma.c", +"musl/src/math/powerpc64/fmaf.c", +"musl/src/math/powerpc64/fmax.c", +"musl/src/math/powerpc64/fmaxf.c", +"musl/src/math/powerpc64/fmin.c", +"musl/src/math/powerpc64/fminf.c", +"musl/src/math/powerpc64/lrint.c", +"musl/src/math/powerpc64/lrintf.c", +"musl/src/math/powerpc64/lround.c", +"musl/src/math/powerpc64/lroundf.c", +"musl/src/math/powerpc64/round.c", +"musl/src/math/powerpc64/roundf.c", +"musl/src/math/powerpc64/sqrt.c", +"musl/src/math/powerpc64/sqrtf.c", +"musl/src/math/powerpc64/trunc.c", +"musl/src/math/powerpc64/truncf.c", +"musl/src/math/powf.c", +"musl/src/math/powl.c", +"musl/src/math/remainder.c", +"musl/src/math/remainderf.c", +"musl/src/math/remainderl.c", +"musl/src/math/remquo.c", +"musl/src/math/remquof.c", +"musl/src/math/remquol.c", +"musl/src/math/rint.c", +"musl/src/math/rintf.c", +"musl/src/math/rintl.c", +"musl/src/math/round.c", +"musl/src/math/roundf.c", +"musl/src/math/roundl.c", +"musl/src/math/s390x/ceil.c", +"musl/src/math/s390x/ceilf.c", +"musl/src/math/s390x/ceill.c", +"musl/src/math/s390x/fabs.c", +"musl/src/math/s390x/fabsf.c", +"musl/src/math/s390x/fabsl.c", +"musl/src/math/s390x/floor.c", +"musl/src/math/s390x/floorf.c", +"musl/src/math/s390x/floorl.c", +"musl/src/math/s390x/fma.c", +"musl/src/math/s390x/fmaf.c", +"musl/src/math/s390x/nearbyint.c", +"musl/src/math/s390x/nearbyintf.c", +"musl/src/math/s390x/nearbyintl.c", +"musl/src/math/s390x/rint.c", +"musl/src/math/s390x/rintf.c", +"musl/src/math/s390x/rintl.c", +"musl/src/math/s390x/round.c", +"musl/src/math/s390x/roundf.c", +"musl/src/math/s390x/roundl.c", +"musl/src/math/s390x/sqrt.c", +"musl/src/math/s390x/sqrtf.c", +"musl/src/math/s390x/sqrtl.c", +"musl/src/math/s390x/trunc.c", +"musl/src/math/s390x/truncf.c", +"musl/src/math/s390x/truncl.c", +"musl/src/math/scalb.c", +"musl/src/math/scalbf.c", +"musl/src/math/scalbln.c", +"musl/src/math/scalblnf.c", +"musl/src/math/scalblnl.c", +"musl/src/math/scalbn.c", +"musl/src/math/scalbnf.c", +"musl/src/math/scalbnl.c", +"musl/src/math/signgam.c", +"musl/src/math/significand.c", +"musl/src/math/significandf.c", +"musl/src/math/sin.c", +"musl/src/math/sincos.c", +"musl/src/math/sincosf.c", +"musl/src/math/sincosl.c", +"musl/src/math/sinf.c", +"musl/src/math/sinh.c", +"musl/src/math/sinhf.c", +"musl/src/math/sinhl.c", +"musl/src/math/sinl.c", +"musl/src/math/sqrt.c", +"musl/src/math/sqrtf.c", +"musl/src/math/sqrtl.c", +"musl/src/math/tan.c", +"musl/src/math/tanf.c", +"musl/src/math/tanh.c", +"musl/src/math/tanhf.c", +"musl/src/math/tanhl.c", +"musl/src/math/tanl.c", +"musl/src/math/tgamma.c", +"musl/src/math/tgammaf.c", +"musl/src/math/tgammal.c", +"musl/src/math/trunc.c", +"musl/src/math/truncf.c", +"musl/src/math/truncl.c", +"musl/src/math/x32/__invtrigl.s", +"musl/src/math/x32/acosl.s", +"musl/src/math/x32/asinl.s", +"musl/src/math/x32/atan2l.s", +"musl/src/math/x32/atanl.s", +"musl/src/math/x32/ceill.s", +"musl/src/math/x32/exp2l.s", +"musl/src/math/x32/expl.s", +"musl/src/math/x32/expm1l.s", +"musl/src/math/x32/fabs.s", +"musl/src/math/x32/fabsf.s", +"musl/src/math/x32/fabsl.s", +"musl/src/math/x32/floorl.s", +"musl/src/math/x32/fma.c", +"musl/src/math/x32/fmaf.c", +"musl/src/math/x32/fmodl.s", +"musl/src/math/x32/llrint.s", +"musl/src/math/x32/llrintf.s", +"musl/src/math/x32/llrintl.s", +"musl/src/math/x32/log10l.s", +"musl/src/math/x32/log1pl.s", +"musl/src/math/x32/log2l.s", +"musl/src/math/x32/logl.s", +"musl/src/math/x32/lrint.s", +"musl/src/math/x32/lrintf.s", +"musl/src/math/x32/lrintl.s", +"musl/src/math/x32/remainderl.s", +"musl/src/math/x32/rintl.s", +"musl/src/math/x32/sqrt.s", +"musl/src/math/x32/sqrtf.s", +"musl/src/math/x32/sqrtl.s", +"musl/src/math/x32/truncl.s", +"musl/src/math/x86_64/__invtrigl.s", +"musl/src/math/x86_64/acosl.s", +"musl/src/math/x86_64/asinl.s", +"musl/src/math/x86_64/atan2l.s", +"musl/src/math/x86_64/atanl.s", +"musl/src/math/x86_64/ceill.s", +"musl/src/math/x86_64/exp2l.s", +"musl/src/math/x86_64/expl.s", +"musl/src/math/x86_64/expm1l.s", +"musl/src/math/x86_64/fabs.s", +"musl/src/math/x86_64/fabsf.s", +"musl/src/math/x86_64/fabsl.s", +"musl/src/math/x86_64/floorl.s", +"musl/src/math/x86_64/fma.c", +"musl/src/math/x86_64/fmaf.c", +"musl/src/math/x86_64/fmodl.s", +"musl/src/math/x86_64/llrint.s", +"musl/src/math/x86_64/llrintf.s", +"musl/src/math/x86_64/llrintl.s", +"musl/src/math/x86_64/log10l.s", +"musl/src/math/x86_64/log1pl.s", +"musl/src/math/x86_64/log2l.s", +"musl/src/math/x86_64/logl.s", +"musl/src/math/x86_64/lrint.s", +"musl/src/math/x86_64/lrintf.s", +"musl/src/math/x86_64/lrintl.s", +"musl/src/math/x86_64/remainderl.s", +"musl/src/math/x86_64/rintl.s", +"musl/src/math/x86_64/sqrt.s", +"musl/src/math/x86_64/sqrtf.s", +"musl/src/math/x86_64/sqrtl.s", +"musl/src/math/x86_64/truncl.s", +"musl/src/misc/a64l.c", +"musl/src/misc/basename.c", +"musl/src/misc/dirname.c", +"musl/src/misc/ffs.c", +"musl/src/misc/ffsl.c", +"musl/src/misc/ffsll.c", +"musl/src/misc/fmtmsg.c", +"musl/src/misc/forkpty.c", +"musl/src/misc/get_current_dir_name.c", +"musl/src/misc/getauxval.c", +"musl/src/misc/getdomainname.c", +"musl/src/misc/getentropy.c", +"musl/src/misc/gethostid.c", +"musl/src/misc/getopt.c", +"musl/src/misc/getopt_long.c", +"musl/src/misc/getpriority.c", +"musl/src/misc/getresgid.c", +"musl/src/misc/getresuid.c", +"musl/src/misc/getrlimit.c", +"musl/src/misc/getrusage.c", +"musl/src/misc/getsubopt.c", +"musl/src/misc/initgroups.c", +"musl/src/misc/ioctl.c", +"musl/src/misc/issetugid.c", +"musl/src/misc/lockf.c", +"musl/src/misc/login_tty.c", +"musl/src/misc/mntent.c", +"musl/src/misc/nftw.c", +"musl/src/misc/openpty.c", +"musl/src/misc/ptsname.c", +"musl/src/misc/pty.c", +"musl/src/misc/realpath.c", +"musl/src/misc/setdomainname.c", +"musl/src/misc/setpriority.c", +"musl/src/misc/setrlimit.c", +"musl/src/misc/syscall.c", +"musl/src/misc/syslog.c", +"musl/src/misc/uname.c", +"musl/src/misc/wordexp.c", +"musl/src/mman/madvise.c", +"musl/src/mman/mincore.c", +"musl/src/mman/mlock.c", +"musl/src/mman/mlockall.c", +"musl/src/mman/mmap.c", +"musl/src/mman/mprotect.c", +"musl/src/mman/mremap.c", +"musl/src/mman/msync.c", +"musl/src/mman/munlock.c", +"musl/src/mman/munlockall.c", +"musl/src/mman/munmap.c", +"musl/src/mman/posix_madvise.c", +"musl/src/mman/shm_open.c", +"musl/src/mq/mq_close.c", +"musl/src/mq/mq_getattr.c", +"musl/src/mq/mq_notify.c", +"musl/src/mq/mq_open.c", +"musl/src/mq/mq_receive.c", +"musl/src/mq/mq_send.c", +"musl/src/mq/mq_setattr.c", +"musl/src/mq/mq_timedreceive.c", +"musl/src/mq/mq_timedsend.c", +"musl/src/mq/mq_unlink.c", +"musl/src/multibyte/btowc.c", +"musl/src/multibyte/c16rtomb.c", +"musl/src/multibyte/c32rtomb.c", +"musl/src/multibyte/internal.c", +"musl/src/multibyte/internal.h", +"musl/src/multibyte/mblen.c", +"musl/src/multibyte/mbrlen.c", +"musl/src/multibyte/mbrtoc16.c", +"musl/src/multibyte/mbrtoc32.c", +"musl/src/multibyte/mbrtowc.c", +"musl/src/multibyte/mbsinit.c", +"musl/src/multibyte/mbsnrtowcs.c", +"musl/src/multibyte/mbsrtowcs.c", +"musl/src/multibyte/mbstowcs.c", +"musl/src/multibyte/mbtowc.c", +"musl/src/multibyte/wcrtomb.c", +"musl/src/multibyte/wcsnrtombs.c", +"musl/src/multibyte/wcsrtombs.c", +"musl/src/multibyte/wcstombs.c", +"musl/src/multibyte/wctob.c", +"musl/src/multibyte/wctomb.c", +"musl/src/network/accept.c", +"musl/src/network/accept4.c", +"musl/src/network/bind.c", +"musl/src/network/connect.c", +"musl/src/network/dn_comp.c", +"musl/src/network/dn_expand.c", +"musl/src/network/dn_skipname.c", +"musl/src/network/dns_parse.c", +"musl/src/network/ent.c", +"musl/src/network/ether.c", +"musl/src/network/freeaddrinfo.c", +"musl/src/network/gai_strerror.c", +"musl/src/network/getaddrinfo.c", +"musl/src/network/gethostbyaddr.c", +"musl/src/network/gethostbyaddr_r.c", +"musl/src/network/gethostbyname.c", +"musl/src/network/gethostbyname2.c", +"musl/src/network/gethostbyname2_r.c", +"musl/src/network/gethostbyname_r.c", +"musl/src/network/getifaddrs.c", +"musl/src/network/getnameinfo.c", +"musl/src/network/getpeername.c", +"musl/src/network/getservbyname.c", +"musl/src/network/getservbyname_r.c", +"musl/src/network/getservbyport.c", +"musl/src/network/getservbyport_r.c", +"musl/src/network/getsockname.c", +"musl/src/network/getsockopt.c", +"musl/src/network/h_errno.c", +"musl/src/network/herror.c", +"musl/src/network/hstrerror.c", +"musl/src/network/htonl.c", +"musl/src/network/htons.c", +"musl/src/network/if_freenameindex.c", +"musl/src/network/if_indextoname.c", +"musl/src/network/if_nameindex.c", +"musl/src/network/if_nametoindex.c", +"musl/src/network/in6addr_any.c", +"musl/src/network/in6addr_loopback.c", +"musl/src/network/inet_addr.c", +"musl/src/network/inet_aton.c", +"musl/src/network/inet_legacy.c", +"musl/src/network/inet_ntoa.c", +"musl/src/network/inet_ntop.c", +"musl/src/network/inet_pton.c", +"musl/src/network/listen.c", +"musl/src/network/lookup.h", +"musl/src/network/lookup_ipliteral.c", +"musl/src/network/lookup_name.c", +"musl/src/network/lookup_serv.c", +"musl/src/network/netlink.c", +"musl/src/network/netlink.h", +"musl/src/network/netname.c", +"musl/src/network/ns_parse.c", +"musl/src/network/ntohl.c", +"musl/src/network/ntohs.c", +"musl/src/network/proto.c", +"musl/src/network/recv.c", +"musl/src/network/recvfrom.c", +"musl/src/network/recvmmsg.c", +"musl/src/network/recvmsg.c", +"musl/src/network/res_init.c", +"musl/src/network/res_mkquery.c", +"musl/src/network/res_msend.c", +"musl/src/network/res_query.c", +"musl/src/network/res_querydomain.c", +"musl/src/network/res_send.c", +"musl/src/network/res_state.c", +"musl/src/network/resolvconf.c", +"musl/src/network/send.c", +"musl/src/network/sendmmsg.c", +"musl/src/network/sendmsg.c", +"musl/src/network/sendto.c", +"musl/src/network/serv.c", +"musl/src/network/setsockopt.c", +"musl/src/network/shutdown.c", +"musl/src/network/sockatmark.c", +"musl/src/network/socket.c", +"musl/src/network/socketpair.c", +"musl/src/passwd/fgetgrent.c", +"musl/src/passwd/fgetpwent.c", +"musl/src/passwd/fgetspent.c", +"musl/src/passwd/getgr_a.c", +"musl/src/passwd/getgr_r.c", +"musl/src/passwd/getgrent.c", +"musl/src/passwd/getgrent_a.c", +"musl/src/passwd/getgrouplist.c", +"musl/src/passwd/getpw_a.c", +"musl/src/passwd/getpw_r.c", +"musl/src/passwd/getpwent.c", +"musl/src/passwd/getpwent_a.c", +"musl/src/passwd/getspent.c", +"musl/src/passwd/getspnam.c", +"musl/src/passwd/getspnam_r.c", +"musl/src/passwd/lckpwdf.c", +"musl/src/passwd/nscd.h", +"musl/src/passwd/nscd_query.c", +"musl/src/passwd/putgrent.c", +"musl/src/passwd/putpwent.c", +"musl/src/passwd/putspent.c", +"musl/src/passwd/pwf.h", +"musl/src/prng/__rand48_step.c", +"musl/src/prng/__seed48.c", +"musl/src/prng/drand48.c", +"musl/src/prng/lcong48.c", +"musl/src/prng/lrand48.c", +"musl/src/prng/mrand48.c", +"musl/src/prng/rand.c", +"musl/src/prng/rand48.h", +"musl/src/prng/rand_r.c", +"musl/src/prng/random.c", +"musl/src/prng/seed48.c", +"musl/src/prng/srand48.c", +"musl/src/process/arm/vfork.s", +"musl/src/process/execl.c", +"musl/src/process/execle.c", +"musl/src/process/execlp.c", +"musl/src/process/execv.c", +"musl/src/process/execve.c", +"musl/src/process/execvp.c", +"musl/src/process/fdop.h", +"musl/src/process/fexecve.c", +"musl/src/process/fork.c", +"musl/src/process/i386/vfork.s", +"musl/src/process/posix_spawn.c", +"musl/src/process/posix_spawn_file_actions_addclose.c", +"musl/src/process/posix_spawn_file_actions_adddup2.c", +"musl/src/process/posix_spawn_file_actions_addopen.c", +"musl/src/process/posix_spawn_file_actions_destroy.c", +"musl/src/process/posix_spawn_file_actions_init.c", +"musl/src/process/posix_spawnattr_destroy.c", +"musl/src/process/posix_spawnattr_getflags.c", +"musl/src/process/posix_spawnattr_getpgroup.c", +"musl/src/process/posix_spawnattr_getsigdefault.c", +"musl/src/process/posix_spawnattr_getsigmask.c", +"musl/src/process/posix_spawnattr_init.c", +"musl/src/process/posix_spawnattr_sched.c", +"musl/src/process/posix_spawnattr_setflags.c", +"musl/src/process/posix_spawnattr_setpgroup.c", +"musl/src/process/posix_spawnattr_setsigdefault.c", +"musl/src/process/posix_spawnattr_setsigmask.c", +"musl/src/process/posix_spawnp.c", +"musl/src/process/s390x/vfork.s", +"musl/src/process/sh/vfork.s", +"musl/src/process/system.c", +"musl/src/process/vfork.c", +"musl/src/process/wait.c", +"musl/src/process/waitid.c", +"musl/src/process/waitpid.c", +"musl/src/process/x32/vfork.s", +"musl/src/process/x86_64/vfork.s", +"musl/src/regex/fnmatch.c", +"musl/src/regex/glob.c", +"musl/src/regex/regcomp.c", +"musl/src/regex/regerror.c", +"musl/src/regex/regexec.c", +"musl/src/regex/tre-mem.c", +"musl/src/regex/tre.h", +"musl/src/sched/affinity.c", +"musl/src/sched/sched_cpucount.c", +"musl/src/sched/sched_get_priority_max.c", +"musl/src/sched/sched_getcpu.c", +"musl/src/sched/sched_getparam.c", +"musl/src/sched/sched_getscheduler.c", +"musl/src/sched/sched_rr_get_interval.c", +"musl/src/sched/sched_setparam.c", +"musl/src/sched/sched_setscheduler.c", +"musl/src/sched/sched_yield.c", +"musl/src/search/hsearch.c", +"musl/src/search/insque.c", +"musl/src/search/lsearch.c", +"musl/src/search/tdelete.c", +"musl/src/search/tdestroy.c", +"musl/src/search/tfind.c", +"musl/src/search/tsearch.c", +"musl/src/search/tsearch.h", +"musl/src/search/twalk.c", +"musl/src/select/poll.c", +"musl/src/select/pselect.c", +"musl/src/select/select.c", +"musl/src/setjmp/aarch64/longjmp.s", +"musl/src/setjmp/aarch64/setjmp.s", +"musl/src/setjmp/arm/longjmp.s", +"musl/src/setjmp/arm/setjmp.s", +"musl/src/setjmp/i386/longjmp.s", +"musl/src/setjmp/i386/setjmp.s", +"musl/src/setjmp/longjmp.c", +"musl/src/setjmp/m68k/longjmp.s", +"musl/src/setjmp/m68k/setjmp.s", +"musl/src/setjmp/microblaze/longjmp.s", +"musl/src/setjmp/microblaze/setjmp.s", +"musl/src/setjmp/mips/longjmp.S", +"musl/src/setjmp/mips/setjmp.S", +"musl/src/setjmp/mips64/longjmp.S", +"musl/src/setjmp/mips64/setjmp.S", +"musl/src/setjmp/mipsn32/longjmp.S", +"musl/src/setjmp/mipsn32/setjmp.S", +"musl/src/setjmp/or1k/longjmp.s", +"musl/src/setjmp/or1k/setjmp.s", +"musl/src/setjmp/powerpc/longjmp.S", +"musl/src/setjmp/powerpc/setjmp.S", +"musl/src/setjmp/powerpc64/longjmp.s", +"musl/src/setjmp/powerpc64/setjmp.s", +"musl/src/setjmp/s390x/longjmp.s", +"musl/src/setjmp/s390x/setjmp.s", +"musl/src/setjmp/setjmp.c", +"musl/src/setjmp/sh/longjmp.S", +"musl/src/setjmp/sh/setjmp.S", +"musl/src/setjmp/x32/longjmp.s", +"musl/src/setjmp/x32/setjmp.s", +"musl/src/setjmp/x86_64/longjmp.s", +"musl/src/setjmp/x86_64/setjmp.s", +"musl/src/signal/aarch64/restore.s", +"musl/src/signal/aarch64/sigsetjmp.s", +"musl/src/signal/arm/restore.s", +"musl/src/signal/arm/sigsetjmp.s", +"musl/src/signal/block.c", +"musl/src/signal/getitimer.c", +"musl/src/signal/i386/restore.s", +"musl/src/signal/i386/sigsetjmp.s", +"musl/src/signal/kill.c", +"musl/src/signal/killpg.c", +"musl/src/signal/m68k/sigsetjmp.s", +"musl/src/signal/microblaze/restore.s", +"musl/src/signal/microblaze/sigsetjmp.s", +"musl/src/signal/mips/restore.s", +"musl/src/signal/mips/sigsetjmp.s", +"musl/src/signal/mips64/restore.s", +"musl/src/signal/mips64/sigsetjmp.s", +"musl/src/signal/mipsn32/restore.s", +"musl/src/signal/mipsn32/sigsetjmp.s", +"musl/src/signal/or1k/sigsetjmp.s", +"musl/src/signal/powerpc/restore.s", +"musl/src/signal/powerpc/sigsetjmp.s", +"musl/src/signal/powerpc64/restore.s", +"musl/src/signal/powerpc64/sigsetjmp.s", +"musl/src/signal/psiginfo.c", +"musl/src/signal/psignal.c", +"musl/src/signal/raise.c", +"musl/src/signal/restore.c", +"musl/src/signal/s390x/restore.s", +"musl/src/signal/s390x/sigsetjmp.s", +"musl/src/signal/setitimer.c", +"musl/src/signal/sh/restore.s", +"musl/src/signal/sh/sigsetjmp.s", +"musl/src/signal/sigaction.c", +"musl/src/signal/sigaddset.c", +"musl/src/signal/sigaltstack.c", +"musl/src/signal/sigandset.c", +"musl/src/signal/sigdelset.c", +"musl/src/signal/sigemptyset.c", +"musl/src/signal/sigfillset.c", +"musl/src/signal/sighold.c", +"musl/src/signal/sigignore.c", +"musl/src/signal/siginterrupt.c", +"musl/src/signal/sigisemptyset.c", +"musl/src/signal/sigismember.c", +"musl/src/signal/siglongjmp.c", +"musl/src/signal/signal.c", +"musl/src/signal/sigorset.c", +"musl/src/signal/sigpause.c", +"musl/src/signal/sigpending.c", +"musl/src/signal/sigprocmask.c", +"musl/src/signal/sigqueue.c", +"musl/src/signal/sigrelse.c", +"musl/src/signal/sigrtmax.c", +"musl/src/signal/sigrtmin.c", +"musl/src/signal/sigset.c", +"musl/src/signal/sigsetjmp.c", +"musl/src/signal/sigsetjmp_tail.c", +"musl/src/signal/sigsuspend.c", +"musl/src/signal/sigtimedwait.c", +"musl/src/signal/sigwait.c", +"musl/src/signal/sigwaitinfo.c", +"musl/src/signal/x32/restore.s", +"musl/src/signal/x32/sigsetjmp.s", +"musl/src/signal/x86_64/restore.s", +"musl/src/signal/x86_64/sigsetjmp.s", +"musl/src/stat/__xstat.c", +"musl/src/stat/chmod.c", +"musl/src/stat/fchmod.c", +"musl/src/stat/fchmodat.c", +"musl/src/stat/fstat.c", +"musl/src/stat/fstatat.c", +"musl/src/stat/futimens.c", +"musl/src/stat/futimesat.c", +"musl/src/stat/lchmod.c", +"musl/src/stat/lstat.c", +"musl/src/stat/mkdir.c", +"musl/src/stat/mkdirat.c", +"musl/src/stat/mkfifo.c", +"musl/src/stat/mkfifoat.c", +"musl/src/stat/mknod.c", +"musl/src/stat/mknodat.c", +"musl/src/stat/stat.c", +"musl/src/stat/statvfs.c", +"musl/src/stat/umask.c", +"musl/src/stat/utimensat.c", +"musl/src/stdio/__fclose_ca.c", +"musl/src/stdio/__fdopen.c", +"musl/src/stdio/__fmodeflags.c", +"musl/src/stdio/__fopen_rb_ca.c", +"musl/src/stdio/__lockfile.c", +"musl/src/stdio/__overflow.c", +"musl/src/stdio/__stdio_close.c", +"musl/src/stdio/__stdio_exit.c", +"musl/src/stdio/__stdio_read.c", +"musl/src/stdio/__stdio_seek.c", +"musl/src/stdio/__stdio_write.c", +"musl/src/stdio/__stdout_write.c", +"musl/src/stdio/__string_read.c", +"musl/src/stdio/__toread.c", +"musl/src/stdio/__towrite.c", +"musl/src/stdio/__uflow.c", +"musl/src/stdio/asprintf.c", +"musl/src/stdio/clearerr.c", +"musl/src/stdio/dprintf.c", +"musl/src/stdio/ext.c", +"musl/src/stdio/ext2.c", +"musl/src/stdio/fclose.c", +"musl/src/stdio/feof.c", +"musl/src/stdio/ferror.c", +"musl/src/stdio/fflush.c", +"musl/src/stdio/fgetc.c", +"musl/src/stdio/fgetln.c", +"musl/src/stdio/fgetpos.c", +"musl/src/stdio/fgets.c", +"musl/src/stdio/fgetwc.c", +"musl/src/stdio/fgetws.c", +"musl/src/stdio/fileno.c", +"musl/src/stdio/flockfile.c", +"musl/src/stdio/fmemopen.c", +"musl/src/stdio/fopen.c", +"musl/src/stdio/fopencookie.c", +"musl/src/stdio/fprintf.c", +"musl/src/stdio/fputc.c", +"musl/src/stdio/fputs.c", +"musl/src/stdio/fputwc.c", +"musl/src/stdio/fputws.c", +"musl/src/stdio/fread.c", +"musl/src/stdio/freopen.c", +"musl/src/stdio/fscanf.c", +"musl/src/stdio/fseek.c", +"musl/src/stdio/fsetpos.c", +"musl/src/stdio/ftell.c", +"musl/src/stdio/ftrylockfile.c", +"musl/src/stdio/funlockfile.c", +"musl/src/stdio/fwide.c", +"musl/src/stdio/fwprintf.c", +"musl/src/stdio/fwrite.c", +"musl/src/stdio/fwscanf.c", +"musl/src/stdio/getc.c", +"musl/src/stdio/getc.h", +"musl/src/stdio/getc_unlocked.c", +"musl/src/stdio/getchar.c", +"musl/src/stdio/getchar_unlocked.c", +"musl/src/stdio/getdelim.c", +"musl/src/stdio/getline.c", +"musl/src/stdio/gets.c", +"musl/src/stdio/getw.c", +"musl/src/stdio/getwc.c", +"musl/src/stdio/getwchar.c", +"musl/src/stdio/ofl.c", +"musl/src/stdio/ofl_add.c", +"musl/src/stdio/open_memstream.c", +"musl/src/stdio/open_wmemstream.c", +"musl/src/stdio/pclose.c", +"musl/src/stdio/perror.c", +"musl/src/stdio/popen.c", +"musl/src/stdio/printf.c", +"musl/src/stdio/putc.c", +"musl/src/stdio/putc.h", +"musl/src/stdio/putc_unlocked.c", +"musl/src/stdio/putchar.c", +"musl/src/stdio/putchar_unlocked.c", +"musl/src/stdio/puts.c", +"musl/src/stdio/putw.c", +"musl/src/stdio/putwc.c", +"musl/src/stdio/putwchar.c", +"musl/src/stdio/remove.c", +"musl/src/stdio/rename.c", +"musl/src/stdio/rewind.c", +"musl/src/stdio/scanf.c", +"musl/src/stdio/setbuf.c", +"musl/src/stdio/setbuffer.c", +"musl/src/stdio/setlinebuf.c", +"musl/src/stdio/setvbuf.c", +"musl/src/stdio/snprintf.c", +"musl/src/stdio/sprintf.c", +"musl/src/stdio/sscanf.c", +"musl/src/stdio/stderr.c", +"musl/src/stdio/stdin.c", +"musl/src/stdio/stdout.c", +"musl/src/stdio/swprintf.c", +"musl/src/stdio/swscanf.c", +"musl/src/stdio/tempnam.c", +"musl/src/stdio/tmpfile.c", +"musl/src/stdio/tmpnam.c", +"musl/src/stdio/ungetc.c", +"musl/src/stdio/ungetwc.c", +"musl/src/stdio/vasprintf.c", +"musl/src/stdio/vdprintf.c", +"musl/src/stdio/vfprintf.c", +"musl/src/stdio/vfscanf.c", +"musl/src/stdio/vfwprintf.c", +"musl/src/stdio/vfwscanf.c", +"musl/src/stdio/vprintf.c", +"musl/src/stdio/vscanf.c", +"musl/src/stdio/vsnprintf.c", +"musl/src/stdio/vsprintf.c", +"musl/src/stdio/vsscanf.c", +"musl/src/stdio/vswprintf.c", +"musl/src/stdio/vswscanf.c", +"musl/src/stdio/vwprintf.c", +"musl/src/stdio/vwscanf.c", +"musl/src/stdio/wprintf.c", +"musl/src/stdio/wscanf.c", +"musl/src/stdlib/abs.c", +"musl/src/stdlib/atof.c", +"musl/src/stdlib/atoi.c", +"musl/src/stdlib/atol.c", +"musl/src/stdlib/atoll.c", +"musl/src/stdlib/bsearch.c", +"musl/src/stdlib/div.c", +"musl/src/stdlib/ecvt.c", +"musl/src/stdlib/fcvt.c", +"musl/src/stdlib/gcvt.c", +"musl/src/stdlib/imaxabs.c", +"musl/src/stdlib/imaxdiv.c", +"musl/src/stdlib/labs.c", +"musl/src/stdlib/ldiv.c", +"musl/src/stdlib/llabs.c", +"musl/src/stdlib/lldiv.c", +"musl/src/stdlib/qsort.c", +"musl/src/stdlib/strtod.c", +"musl/src/stdlib/strtol.c", +"musl/src/stdlib/wcstod.c", +"musl/src/stdlib/wcstol.c", +"musl/src/string/arm/__aeabi_memcpy.s", +"musl/src/string/arm/__aeabi_memset.s", +"musl/src/string/arm/memcpy.c", +"musl/src/string/arm/memcpy_le.S", +"musl/src/string/bcmp.c", +"musl/src/string/bcopy.c", +"musl/src/string/bzero.c", +"musl/src/string/explicit_bzero.c", +"musl/src/string/i386/memcpy.s", +"musl/src/string/i386/memmove.s", +"musl/src/string/i386/memset.s", +"musl/src/string/index.c", +"musl/src/string/memccpy.c", +"musl/src/string/memchr.c", +"musl/src/string/memcmp.c", +"musl/src/string/memcpy.c", +"musl/src/string/memmem.c", +"musl/src/string/memmove.c", +"musl/src/string/mempcpy.c", +"musl/src/string/memrchr.c", +"musl/src/string/memset.c", +"musl/src/string/rindex.c", +"musl/src/string/stpcpy.c", +"musl/src/string/stpncpy.c", +"musl/src/string/strcasecmp.c", +"musl/src/string/strcasestr.c", +"musl/src/string/strcat.c", +"musl/src/string/strchr.c", +"musl/src/string/strchrnul.c", +"musl/src/string/strcmp.c", +"musl/src/string/strcpy.c", +"musl/src/string/strcspn.c", +"musl/src/string/strdup.c", +"musl/src/string/strerror_r.c", +"musl/src/string/strlcat.c", +"musl/src/string/strlcpy.c", +"musl/src/string/strlen.c", +"musl/src/string/strncasecmp.c", +"musl/src/string/strncat.c", +"musl/src/string/strncmp.c", +"musl/src/string/strncpy.c", +"musl/src/string/strndup.c", +"musl/src/string/strnlen.c", +"musl/src/string/strpbrk.c", +"musl/src/string/strrchr.c", +"musl/src/string/strsep.c", +"musl/src/string/strsignal.c", +"musl/src/string/strspn.c", +"musl/src/string/strstr.c", +"musl/src/string/strtok.c", +"musl/src/string/strtok_r.c", +"musl/src/string/strverscmp.c", +"musl/src/string/swab.c", +"musl/src/string/wcpcpy.c", +"musl/src/string/wcpncpy.c", +"musl/src/string/wcscasecmp.c", +"musl/src/string/wcscasecmp_l.c", +"musl/src/string/wcscat.c", +"musl/src/string/wcschr.c", +"musl/src/string/wcscmp.c", +"musl/src/string/wcscpy.c", +"musl/src/string/wcscspn.c", +"musl/src/string/wcsdup.c", +"musl/src/string/wcslen.c", +"musl/src/string/wcsncasecmp.c", +"musl/src/string/wcsncasecmp_l.c", +"musl/src/string/wcsncat.c", +"musl/src/string/wcsncmp.c", +"musl/src/string/wcsncpy.c", +"musl/src/string/wcsnlen.c", +"musl/src/string/wcspbrk.c", +"musl/src/string/wcsrchr.c", +"musl/src/string/wcsspn.c", +"musl/src/string/wcsstr.c", +"musl/src/string/wcstok.c", +"musl/src/string/wcswcs.c", +"musl/src/string/wmemchr.c", +"musl/src/string/wmemcmp.c", +"musl/src/string/wmemcpy.c", +"musl/src/string/wmemmove.c", +"musl/src/string/wmemset.c", +"musl/src/string/x86_64/memcpy.s", +"musl/src/string/x86_64/memmove.s", +"musl/src/string/x86_64/memset.s", +"musl/src/temp/__randname.c", +"musl/src/temp/mkdtemp.c", +"musl/src/temp/mkostemp.c", +"musl/src/temp/mkostemps.c", +"musl/src/temp/mkstemp.c", +"musl/src/temp/mkstemps.c", +"musl/src/temp/mktemp.c", +"musl/src/termios/cfgetospeed.c", +"musl/src/termios/cfmakeraw.c", +"musl/src/termios/cfsetospeed.c", +"musl/src/termios/tcdrain.c", +"musl/src/termios/tcflow.c", +"musl/src/termios/tcflush.c", +"musl/src/termios/tcgetattr.c", +"musl/src/termios/tcgetsid.c", +"musl/src/termios/tcsendbreak.c", +"musl/src/termios/tcsetattr.c", +"musl/src/thread/__lock.c", +"musl/src/thread/__set_thread_area.c", +"musl/src/thread/__syscall_cp.c", +"musl/src/thread/__timedwait.c", +"musl/src/thread/__tls_get_addr.c", +"musl/src/thread/__unmapself.c", +"musl/src/thread/__wait.c", +"musl/src/thread/aarch64/__set_thread_area.s", +"musl/src/thread/aarch64/__unmapself.s", +"musl/src/thread/aarch64/clone.s", +"musl/src/thread/aarch64/syscall_cp.s", +"musl/src/thread/arm/__aeabi_read_tp.s", +"musl/src/thread/arm/__set_thread_area.c", +"musl/src/thread/arm/__unmapself.s", +"musl/src/thread/arm/atomics.s", +"musl/src/thread/arm/clone.s", +"musl/src/thread/arm/syscall_cp.s", +"musl/src/thread/call_once.c", +"musl/src/thread/clone.c", +"musl/src/thread/cnd_broadcast.c", +"musl/src/thread/cnd_destroy.c", +"musl/src/thread/cnd_init.c", +"musl/src/thread/cnd_signal.c", +"musl/src/thread/cnd_timedwait.c", +"musl/src/thread/cnd_wait.c", +"musl/src/thread/default_attr.c", +"musl/src/thread/i386/__set_thread_area.s", +"musl/src/thread/i386/__unmapself.s", +"musl/src/thread/i386/clone.s", +"musl/src/thread/i386/syscall_cp.s", +"musl/src/thread/i386/tls.s", +"musl/src/thread/lock_ptc.c", +"musl/src/thread/m68k/__m68k_read_tp.s", +"musl/src/thread/m68k/clone.s", +"musl/src/thread/m68k/syscall_cp.s", +"musl/src/thread/microblaze/__set_thread_area.s", +"musl/src/thread/microblaze/__unmapself.s", +"musl/src/thread/microblaze/clone.s", +"musl/src/thread/microblaze/syscall_cp.s", +"musl/src/thread/mips/__unmapself.s", +"musl/src/thread/mips/clone.s", +"musl/src/thread/mips/syscall_cp.s", +"musl/src/thread/mips64/__unmapself.s", +"musl/src/thread/mips64/clone.s", +"musl/src/thread/mips64/syscall_cp.s", +"musl/src/thread/mipsn32/__unmapself.s", +"musl/src/thread/mipsn32/clone.s", +"musl/src/thread/mipsn32/syscall_cp.s", +"musl/src/thread/mtx_destroy.c", +"musl/src/thread/mtx_init.c", +"musl/src/thread/mtx_lock.c", +"musl/src/thread/mtx_timedlock.c", +"musl/src/thread/mtx_trylock.c", +"musl/src/thread/mtx_unlock.c", +"musl/src/thread/or1k/__set_thread_area.s", +"musl/src/thread/or1k/__unmapself.s", +"musl/src/thread/or1k/clone.s", +"musl/src/thread/or1k/syscall_cp.s", +"musl/src/thread/powerpc/__set_thread_area.s", +"musl/src/thread/powerpc/__unmapself.s", +"musl/src/thread/powerpc/clone.s", +"musl/src/thread/powerpc/syscall_cp.s", +"musl/src/thread/powerpc64/__set_thread_area.s", +"musl/src/thread/powerpc64/__unmapself.s", +"musl/src/thread/powerpc64/clone.s", +"musl/src/thread/powerpc64/syscall_cp.s", +"musl/src/thread/pthread_atfork.c", +"musl/src/thread/pthread_attr_destroy.c", +"musl/src/thread/pthread_attr_get.c", +"musl/src/thread/pthread_attr_init.c", +"musl/src/thread/pthread_attr_setdetachstate.c", +"musl/src/thread/pthread_attr_setguardsize.c", +"musl/src/thread/pthread_attr_setinheritsched.c", +"musl/src/thread/pthread_attr_setschedparam.c", +"musl/src/thread/pthread_attr_setschedpolicy.c", +"musl/src/thread/pthread_attr_setscope.c", +"musl/src/thread/pthread_attr_setstack.c", +"musl/src/thread/pthread_attr_setstacksize.c", +"musl/src/thread/pthread_barrier_destroy.c", +"musl/src/thread/pthread_barrier_init.c", +"musl/src/thread/pthread_barrier_wait.c", +"musl/src/thread/pthread_barrierattr_destroy.c", +"musl/src/thread/pthread_barrierattr_init.c", +"musl/src/thread/pthread_barrierattr_setpshared.c", +"musl/src/thread/pthread_cancel.c", +"musl/src/thread/pthread_cleanup_push.c", +"musl/src/thread/pthread_cond_broadcast.c", +"musl/src/thread/pthread_cond_destroy.c", +"musl/src/thread/pthread_cond_init.c", +"musl/src/thread/pthread_cond_signal.c", +"musl/src/thread/pthread_cond_timedwait.c", +"musl/src/thread/pthread_cond_wait.c", +"musl/src/thread/pthread_condattr_destroy.c", +"musl/src/thread/pthread_condattr_init.c", +"musl/src/thread/pthread_condattr_setclock.c", +"musl/src/thread/pthread_condattr_setpshared.c", +"musl/src/thread/pthread_create.c", +"musl/src/thread/pthread_detach.c", +"musl/src/thread/pthread_equal.c", +"musl/src/thread/pthread_getattr_np.c", +"musl/src/thread/pthread_getconcurrency.c", +"musl/src/thread/pthread_getcpuclockid.c", +"musl/src/thread/pthread_getschedparam.c", +"musl/src/thread/pthread_getspecific.c", +"musl/src/thread/pthread_join.c", +"musl/src/thread/pthread_key_create.c", +"musl/src/thread/pthread_key_delete.c", +"musl/src/thread/pthread_kill.c", +"musl/src/thread/pthread_mutex_consistent.c", +"musl/src/thread/pthread_mutex_destroy.c", +"musl/src/thread/pthread_mutex_getprioceiling.c", +"musl/src/thread/pthread_mutex_init.c", +"musl/src/thread/pthread_mutex_lock.c", +"musl/src/thread/pthread_mutex_setprioceiling.c", +"musl/src/thread/pthread_mutex_timedlock.c", +"musl/src/thread/pthread_mutex_trylock.c", +"musl/src/thread/pthread_mutex_unlock.c", +"musl/src/thread/pthread_mutexattr_destroy.c", +"musl/src/thread/pthread_mutexattr_init.c", +"musl/src/thread/pthread_mutexattr_setprotocol.c", +"musl/src/thread/pthread_mutexattr_setpshared.c", +"musl/src/thread/pthread_mutexattr_setrobust.c", +"musl/src/thread/pthread_mutexattr_settype.c", +"musl/src/thread/pthread_once.c", +"musl/src/thread/pthread_rwlock_destroy.c", +"musl/src/thread/pthread_rwlock_init.c", +"musl/src/thread/pthread_rwlock_rdlock.c", +"musl/src/thread/pthread_rwlock_timedrdlock.c", +"musl/src/thread/pthread_rwlock_timedwrlock.c", +"musl/src/thread/pthread_rwlock_tryrdlock.c", +"musl/src/thread/pthread_rwlock_trywrlock.c", +"musl/src/thread/pthread_rwlock_unlock.c", +"musl/src/thread/pthread_rwlock_wrlock.c", +"musl/src/thread/pthread_rwlockattr_destroy.c", +"musl/src/thread/pthread_rwlockattr_init.c", +"musl/src/thread/pthread_rwlockattr_setpshared.c", +"musl/src/thread/pthread_self.c", +"musl/src/thread/pthread_setattr_default_np.c", +"musl/src/thread/pthread_setcancelstate.c", +"musl/src/thread/pthread_setcanceltype.c", +"musl/src/thread/pthread_setconcurrency.c", +"musl/src/thread/pthread_setname_np.c", +"musl/src/thread/pthread_setschedparam.c", +"musl/src/thread/pthread_setschedprio.c", +"musl/src/thread/pthread_setspecific.c", +"musl/src/thread/pthread_sigmask.c", +"musl/src/thread/pthread_spin_destroy.c", +"musl/src/thread/pthread_spin_init.c", +"musl/src/thread/pthread_spin_lock.c", +"musl/src/thread/pthread_spin_trylock.c", +"musl/src/thread/pthread_spin_unlock.c", +"musl/src/thread/pthread_testcancel.c", +"musl/src/thread/s390x/__set_thread_area.s", +"musl/src/thread/s390x/__tls_get_offset.s", +"musl/src/thread/s390x/__unmapself.s", +"musl/src/thread/s390x/clone.s", +"musl/src/thread/s390x/syscall_cp.s", +"musl/src/thread/sem_destroy.c", +"musl/src/thread/sem_getvalue.c", +"musl/src/thread/sem_init.c", +"musl/src/thread/sem_open.c", +"musl/src/thread/sem_post.c", +"musl/src/thread/sem_timedwait.c", +"musl/src/thread/sem_trywait.c", +"musl/src/thread/sem_unlink.c", +"musl/src/thread/sem_wait.c", +"musl/src/thread/sh/__set_thread_area.c", +"musl/src/thread/sh/__unmapself.c", +"musl/src/thread/sh/__unmapself_mmu.s", +"musl/src/thread/sh/atomics.s", +"musl/src/thread/sh/clone.s", +"musl/src/thread/sh/syscall_cp.s", +"musl/src/thread/synccall.c", +"musl/src/thread/syscall_cp.c", +"musl/src/thread/thrd_create.c", +"musl/src/thread/thrd_exit.c", +"musl/src/thread/thrd_join.c", +"musl/src/thread/thrd_sleep.c", +"musl/src/thread/thrd_yield.c", +"musl/src/thread/tls.c", +"musl/src/thread/tss_create.c", +"musl/src/thread/tss_delete.c", +"musl/src/thread/tss_set.c", +"musl/src/thread/vmlock.c", +"musl/src/thread/x32/__set_thread_area.s", +"musl/src/thread/x32/__unmapself.s", +"musl/src/thread/x32/clone.s", +"musl/src/thread/x32/syscall_cp.s", +"musl/src/thread/x32/syscall_cp_fixup.c", +"musl/src/thread/x86_64/__set_thread_area.s", +"musl/src/thread/x86_64/__unmapself.s", +"musl/src/thread/x86_64/clone.s", +"musl/src/thread/x86_64/syscall_cp.s", +"musl/src/time/__map_file.c", +"musl/src/time/__month_to_secs.c", +"musl/src/time/__secs_to_tm.c", +"musl/src/time/__tm_to_secs.c", +"musl/src/time/__tz.c", +"musl/src/time/__year_to_secs.c", +"musl/src/time/asctime.c", +"musl/src/time/asctime_r.c", +"musl/src/time/clock.c", +"musl/src/time/clock_getcpuclockid.c", +"musl/src/time/clock_getres.c", +"musl/src/time/clock_gettime.c", +"musl/src/time/clock_nanosleep.c", +"musl/src/time/clock_settime.c", +"musl/src/time/ctime.c", +"musl/src/time/ctime_r.c", +"musl/src/time/difftime.c", +"musl/src/time/ftime.c", +"musl/src/time/getdate.c", +"musl/src/time/gettimeofday.c", +"musl/src/time/gmtime.c", +"musl/src/time/gmtime_r.c", +"musl/src/time/localtime.c", +"musl/src/time/localtime_r.c", +"musl/src/time/mktime.c", +"musl/src/time/nanosleep.c", +"musl/src/time/strftime.c", +"musl/src/time/strptime.c", +"musl/src/time/time.c", +"musl/src/time/time_impl.h", +"musl/src/time/timegm.c", +"musl/src/time/timer_create.c", +"musl/src/time/timer_delete.c", +"musl/src/time/timer_getoverrun.c", +"musl/src/time/timer_gettime.c", +"musl/src/time/timer_settime.c", +"musl/src/time/times.c", +"musl/src/time/timespec_get.c", +"musl/src/time/utime.c", +"musl/src/time/wcsftime.c", +"musl/src/unistd/_exit.c", +"musl/src/unistd/access.c", +"musl/src/unistd/acct.c", +"musl/src/unistd/alarm.c", +"musl/src/unistd/chdir.c", +"musl/src/unistd/chown.c", +"musl/src/unistd/close.c", +"musl/src/unistd/ctermid.c", +"musl/src/unistd/dup.c", +"musl/src/unistd/dup2.c", +"musl/src/unistd/dup3.c", +"musl/src/unistd/faccessat.c", +"musl/src/unistd/fchdir.c", +"musl/src/unistd/fchown.c", +"musl/src/unistd/fchownat.c", +"musl/src/unistd/fdatasync.c", +"musl/src/unistd/fsync.c", +"musl/src/unistd/ftruncate.c", +"musl/src/unistd/getcwd.c", +"musl/src/unistd/getegid.c", +"musl/src/unistd/geteuid.c", +"musl/src/unistd/getgid.c", +"musl/src/unistd/getgroups.c", +"musl/src/unistd/gethostname.c", +"musl/src/unistd/getlogin.c", +"musl/src/unistd/getlogin_r.c", +"musl/src/unistd/getpgid.c", +"musl/src/unistd/getpgrp.c", +"musl/src/unistd/getpid.c", +"musl/src/unistd/getppid.c", +"musl/src/unistd/getsid.c", +"musl/src/unistd/getuid.c", +"musl/src/unistd/isatty.c", +"musl/src/unistd/lchown.c", +"musl/src/unistd/link.c", +"musl/src/unistd/linkat.c", +"musl/src/unistd/lseek.c", +"musl/src/unistd/mips/pipe.s", +"musl/src/unistd/mips64/pipe.s", +"musl/src/unistd/mipsn32/pipe.s", +"musl/src/unistd/nice.c", +"musl/src/unistd/pause.c", +"musl/src/unistd/pipe.c", +"musl/src/unistd/pipe2.c", +"musl/src/unistd/posix_close.c", +"musl/src/unistd/pread.c", +"musl/src/unistd/preadv.c", +"musl/src/unistd/pwrite.c", +"musl/src/unistd/pwritev.c", +"musl/src/unistd/read.c", +"musl/src/unistd/readlink.c", +"musl/src/unistd/readlinkat.c", +"musl/src/unistd/readv.c", +"musl/src/unistd/renameat.c", +"musl/src/unistd/rmdir.c", +"musl/src/unistd/setegid.c", +"musl/src/unistd/seteuid.c", +"musl/src/unistd/setgid.c", +"musl/src/unistd/setpgid.c", +"musl/src/unistd/setpgrp.c", +"musl/src/unistd/setregid.c", +"musl/src/unistd/setresgid.c", +"musl/src/unistd/setresuid.c", +"musl/src/unistd/setreuid.c", +"musl/src/unistd/setsid.c", +"musl/src/unistd/setuid.c", +"musl/src/unistd/setxid.c", +"musl/src/unistd/sh/pipe.s", +"musl/src/unistd/sleep.c", +"musl/src/unistd/symlink.c", +"musl/src/unistd/symlinkat.c", +"musl/src/unistd/sync.c", +"musl/src/unistd/tcgetpgrp.c", +"musl/src/unistd/tcsetpgrp.c", +"musl/src/unistd/truncate.c", +"musl/src/unistd/ttyname.c", +"musl/src/unistd/ttyname_r.c", +"musl/src/unistd/ualarm.c", +"musl/src/unistd/unlink.c", +"musl/src/unistd/unlinkat.c", +"musl/src/unistd/usleep.c", +"musl/src/unistd/write.c", +"musl/src/unistd/writev.c", +}; +#endif diff --git a/src/ir.cpp b/src/ir.cpp index 0c79316652..5193a63ec4 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<IrInstruction *> src_implicit_return_type_list; + ZigList<IrSuspendPosition> resume_stack; IrBasicBlock *const_predecessor_bb; }; @@ -157,16 +158,19 @@ 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_analyze_instruction(IrAnalyze *ira, IrInstruction *instruction); +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); + 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); +static IrInstruction *ir_lval_wrap(IrBuilder *irb, Scope *scope, IrInstruction *value, LVal lval, ResultLoc *result_loc); +static IrInstruction *ir_expr_wrap(IrBuilder *irb, Scope *scope, IrInstruction *inst, 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); @@ -178,17 +182,31 @@ 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, ZigType *dest_type); +static IrInstruction *ir_resolve_result_raw(IrAnalyze *ira, IrInstruction *suspend_source_instr, + ResultLoc *result_loc, ZigType *value_type, IrInstruction *value, bool force_runtime, 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, 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, + 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 IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node, + LVal lval, ResultLoc *parent_result_loc); static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *const_val) { 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 +218,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(); @@ -246,6 +264,15 @@ static bool is_opt_err_set(ZigType *ty) { (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); } +static bool is_slice(ZigType *type) { + return type->id == ZigTypeIdStruct && type->data.structure.is_slice; +} + +static bool slice_is_const(ZigType *type) { + assert(is_slice(type)); + return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; +} + // This function returns true when you can change the type of a ConstExprValue and the // value remains meaningful. static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { @@ -282,8 +309,9 @@ static bool types_have_same_zig_comptime_repr(ZigType *a, ZigType *b) { return a->data.floating.bit_count == b->data.floating.bit_count; case ZigTypeIdInt: return a->data.integral.is_signed == b->data.integral.is_signed; - case ZigTypeIdArray: case ZigTypeIdStruct: + return is_slice(a) && is_slice(b); + case ZigTypeIdArray: case ZigTypeIdOptional: case ZigTypeIdErrorUnion: case ZigTypeIdEnum: @@ -386,6 +414,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; } @@ -475,8 +504,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 *) { @@ -511,14 +548,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; } @@ -611,12 +640,8 @@ 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; +static constexpr IrInstructionId ir_instruction_id(IrInstructionRefGen *) { + return IrInstructionIdRefGen; } static constexpr IrInstructionId ir_instruction_id(IrInstructionCompileErr *) { @@ -703,8 +728,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 *) { @@ -743,8 +772,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(IrInstructionMulAdd *) { @@ -787,8 +820,8 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrCastGen *) { return IrInstructionIdPtrCastGen; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCast *) { - return IrInstructionIdBitCast; +static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastSrc *) { + return IrInstructionIdBitCastSrc; } static constexpr IrInstructionId ir_instruction_id(IrInstructionBitCastGen *) { @@ -867,6 +900,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeInfo *) { return IrInstructionIdTypeInfo; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionHasField *) { + return IrInstructionIdHasField; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionTypeId *) { return IrInstructionIdTypeId; } @@ -883,6 +920,26 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAlignCast *) { return IrInstructionIdAlignCast; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionImplicitCast *) { + return IrInstructionIdImplicitCast; +} + +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; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionPtrOfArrayToSlice *) { + return IrInstructionIdPtrOfArrayToSlice; +} + static constexpr IrInstructionId ir_instruction_id(IrInstructionOpaqueType *) { return IrInstructionIdOpaqueType; } @@ -1023,6 +1080,22 @@ 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; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionEndExpr *) { + return IrInstructionIdEndExpr; +} + +static constexpr IrInstructionId ir_instruction_id(IrInstructionUnionInitNamedField *) { + return IrInstructionIdUnionInitNamedField; +} + template<typename T> static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) { T *special_instruction = allocate<T>(1); @@ -1074,13 +1147,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<IrInstructionReturn>(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; } @@ -1258,28 +1333,39 @@ 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_elem_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *array_ptr, - IrInstruction *elem_index, bool safety_check_on, PtrLen ptr_len) +static IrInstruction *ir_build_return_ptr(IrAnalyze *ira, IrInstruction *source_instruction, ZigType *ty) { + IrInstructionReturnPtr *instruction = ir_build_instruction<IrInstructionReturnPtr>(&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, + IrInstruction *init_array_type) { IrInstructionElemPtr *instruction = ir_build_instruction<IrInstructionElemPtr>(irb, scope, source_node); instruction->array_ptr = array_ptr; instruction->elem_index = elem_index; instruction->safety_check_on = safety_check_on; instruction->ptr_len = ptr_len; + instruction->init_array_type = init_array_type; ir_ref_instruction(array_ptr, irb->current_basic_block); ir_ref_instruction(elem_index, irb->current_basic_block); + if (init_array_type != nullptr) ir_ref_instruction(init_array_type, irb->current_basic_block); return &instruction->base; } static IrInstruction *ir_build_field_ptr_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *container_ptr, IrInstruction *field_name_expr) + IrInstruction *container_ptr, IrInstruction *field_name_expr, bool initializing) { IrInstructionFieldPtr *instruction = ir_build_instruction<IrInstructionFieldPtr>(irb, scope, source_node); instruction->container_ptr = container_ptr; instruction->field_name_buffer = nullptr; instruction->field_name_expr = field_name_expr; + instruction->initializing = initializing; ir_ref_instruction(container_ptr, irb->current_basic_block); ir_ref_instruction(field_name_expr, irb->current_basic_block); @@ -1288,18 +1374,32 @@ 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<IrInstructionFieldPtr>(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); return &instruction->base; } +static IrInstruction *ir_build_has_field(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *container_type, IrInstruction *field_name) +{ + IrInstructionHasField *instruction = ir_build_instruction<IrInstructionHasField>(irb, scope, source_node); + instruction->container_type = container_type; + instruction->field_name = field_name; + + ir_ref_instruction(container_type, irb->current_basic_block); + ir_ref_instruction(field_name, irb->current_basic_block); + + return &instruction->base; +} + static IrInstruction *ir_build_struct_field_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *struct_ptr, TypeStructField *field) { @@ -1313,9 +1413,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) + IrInstruction *union_ptr, TypeUnionField *field, bool safety_check_on, bool initializing) { IrInstructionUnionFieldPtr *instruction = ir_build_instruction<IrInstructionUnionFieldPtr>(irb, scope, source_node); + instruction->initializing = initializing; + instruction->safety_check_on = safety_check_on; instruction->union_ptr = union_ptr; instruction->field = field; @@ -1324,12 +1426,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<IrInstructionCall>(irb, scope, source_node); + IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node); call_instruction->fn_entry = fn_entry; call_instruction->fn_ref = fn_ref; call_instruction->is_comptime = is_comptime; @@ -1339,6 +1441,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) @@ -1349,8 +1452,37 @@ 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, ZigType *return_type) +{ + IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&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; + 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) + size_t incoming_count, IrBasicBlock **incoming_blocks, IrInstruction **incoming_values, + ResultLocPeerParent *peer_parent) { assert(incoming_count != 0); assert(incoming_count != SIZE_MAX); @@ -1359,6 +1491,7 @@ static IrInstruction *ir_build_phi(IrBuilder *irb, Scope *scope, AstNode *source phi_instruction->incoming_count = incoming_count; phi_instruction->incoming_blocks = incoming_blocks; phi_instruction->incoming_values = incoming_values; + phi_instruction->peer_parent = peer_parent; for (size_t i = 0; i < incoming_count; i += 1) { ir_ref_bb(incoming_blocks[i]); @@ -1412,12 +1545,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<IrInstructionUnOp>(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); @@ -1427,72 +1561,49 @@ 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, - IrInstruction *container_type, IrInstruction *elem_type, size_t item_count, IrInstruction **items) + IrInstruction *container_type, size_t item_count, IrInstruction **elem_result_loc_list, + IrInstruction *result_loc) { IrInstructionContainerInitList *container_init_list_instruction = ir_build_instruction<IrInstructionContainerInitList>(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; + container_init_list_instruction->elem_result_loc_list = elem_result_loc_list; + container_init_list_instruction->result_loc = result_loc; - 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); + ir_ref_instruction(elem_result_loc_list[i], irb->current_basic_block); } + if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); return &container_init_list_instruction->base; } static IrInstruction *ir_build_container_init_fields(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields) + IrInstruction *container_type, size_t field_count, IrInstructionContainerInitFieldsField *fields, + IrInstruction *result_loc) { IrInstructionContainerInitFields *container_init_fields_instruction = ir_build_instruction<IrInstructionContainerInitFields>(irb, scope, source_node); container_init_fields_instruction->container_type = container_type; container_init_fields_instruction->field_count = field_count; container_init_fields_instruction->fields = fields; + container_init_fields_instruction->result_loc = result_loc; ir_ref_instruction(container_type, irb->current_basic_block); for (size_t i = 0; i < field_count; i += 1) { - ir_ref_instruction(fields[i].value, irb->current_basic_block); + ir_ref_instruction(fields[i].result_loc, irb->current_basic_block); } + if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); 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<IrInstructionStructInit>(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) -{ - IrInstructionUnionInit *union_init_instruction = ir_build_instruction<IrInstructionUnionInit>(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<IrInstructionUnreachable>(irb, scope, source_node); @@ -1517,47 +1628,47 @@ 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 *align_value, IrInstruction *ptr) { IrInstructionDeclVarSrc *decl_var_instruction = ir_build_instruction<IrInstructionDeclVarSrc>(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->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<IrInstructionDeclVarGen>(&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; } 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<IrInstructionResizeSlice>(&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; } @@ -1598,27 +1709,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<IrInstructionToPtrType>(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<IrInstructionPtrTypeChild>( - 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<IrInstructionSetCold>(irb, scope, source_node); instruction->is_cold = is_cold; @@ -1744,40 +1834,59 @@ 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<IrInstructionOptionalUnwrapPtr>(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); return &instruction->base; } -static IrInstruction *ir_build_maybe_wrap(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionOptionalWrap *instruction = ir_build_instruction<IrInstructionOptionalWrap>(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<IrInstructionOptionalWrap>( + &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); + if (result_loc != nullptr) ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } -static IrInstruction *ir_build_err_wrap_payload(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionErrWrapPayload *instruction = ir_build_instruction<IrInstructionErrWrapPayload>(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<IrInstructionErrWrapPayload>( + &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; } -static IrInstruction *ir_build_err_wrap_code(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *value) { - IrInstructionErrWrapCode *instruction = ir_build_instruction<IrInstructionErrWrapCode>(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<IrInstructionErrWrapCode>( + &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; } @@ -1934,6 +2043,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<IrInstructionRefGen>(&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<IrInstructionCompileErr>(irb, scope, source_node); instruction->msg = msg; @@ -2011,8 +2135,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<IrInstructionCmpxchgSrc>(irb, scope, source_node); instruction->type_value = type_value; @@ -2022,6 +2145,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); @@ -2033,22 +2157,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<IrInstructionCmpxchgGen>(&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; } @@ -2107,19 +2234,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<IrInstructionToBytes>(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<IrInstructionFromBytes>(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); @@ -2221,14 +2354,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<IrInstructionSlice>(irb, scope, source_node); + IrInstructionSliceSrc *instruction = ir_build_instruction<IrInstructionSliceSrc>(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); @@ -2237,6 +2371,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<IrInstructionSliceGen>( + &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<IrInstructionMemberCount>(irb, scope, source_node); instruction->container = container; @@ -2390,34 +2544,49 @@ 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, bool resolve_err_set) { - IrInstructionTestErr *instruction = ir_build_instruction<IrInstructionTestErr>(irb, scope, source_node); - instruction->value = value; + IrInstructionTestErrSrc *instruction = ir_build_instruction<IrInstructionTestErrSrc>(irb, scope, source_node); + instruction->base_ptr = base_ptr; + instruction->resolve_err_set = resolve_err_set; - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(base_ptr, irb->current_basic_block); return &instruction->base; } -static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, +static IrInstruction *ir_build_test_err_gen(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *err_union) { - IrInstructionUnwrapErrCode *instruction = ir_build_instruction<IrInstructionUnwrapErrCode>(irb, scope, source_node); + IrInstructionTestErrGen *instruction = ir_build_instruction<IrInstructionTestErrGen>( + &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, irb->current_basic_block); + ir_ref_instruction(err_union, ira->new_irb.current_basic_block); + + return &instruction->base; +} + +static IrInstruction *ir_build_unwrap_err_code(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *err_union_ptr) +{ + IrInstructionUnwrapErrCode *instruction = ir_build_instruction<IrInstructionUnwrapErrCode>(irb, scope, source_node); + instruction->err_union_ptr = err_union_ptr; + + ir_ref_instruction(err_union_ptr, irb->current_basic_block); return &instruction->base; } 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<IrInstructionUnwrapErrPayload>(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); @@ -2487,28 +2656,28 @@ 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<IrInstructionLoadPtrGen>( &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; } -static IrInstruction *ir_build_bit_cast(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *dest_type, IrInstruction *value) +static IrInstruction *ir_build_bit_cast_src(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *operand, ResultLocBitCast *result_loc_bit_cast) { - IrInstructionBitCast *instruction = ir_build_instruction<IrInstructionBitCast>( - irb, scope, source_node); - instruction->dest_type = dest_type; - instruction->value = value; + IrInstructionBitCastSrc *instruction = ir_build_instruction<IrInstructionBitCastSrc>(irb, scope, source_node); + instruction->operand = operand; + instruction->result_loc_bit_cast = result_loc_bit_cast; - ir_ref_instruction(dest_type, irb->current_basic_block); - ir_ref_instruction(value, irb->current_basic_block); + ir_ref_instruction(operand, irb->current_basic_block); return &instruction->base; } @@ -2660,11 +2829,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<IrInstructionDeclRef>( - 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<IrInstructionDeclRef>(irb, scope, source_node); instruction->tld = tld; instruction->lval = lval; @@ -2792,6 +2958,53 @@ 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, ResultLoc *result_loc) +{ + IrInstructionImplicitCast *instruction = ir_build_instruction<IrInstructionImplicitCast>(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); + + 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<IrInstructionResolveResult>(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_reset_result(IrBuilder *irb, Scope *scope, AstNode *source_node, + ResultLoc *result_loc) +{ + IrInstructionResetResult *instruction = ir_build_instruction<IrInstructionResetResult>(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) +{ + IrInstructionResultPtr *instruction = ir_build_instruction<IrInstructionResultPtr>(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<IrInstructionOpaqueType>(irb, scope, source_node); @@ -3119,17 +3332,50 @@ static IrInstruction *ir_build_check_runtime_scope(IrBuilder *irb, Scope *scope, return &instruction->base; } +static IrInstruction *ir_build_union_init_named_field(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *union_type, IrInstruction *field_name, IrInstruction *field_result_loc, IrInstruction *result_loc) +{ + IrInstructionUnionInitNamedField *instruction = ir_build_instruction<IrInstructionUnionInitNamedField>(irb, scope, source_node); + instruction->union_type = union_type; + instruction->field_name = field_name; + instruction->field_result_loc = field_result_loc; + instruction->result_loc = result_loc; + + ir_ref_instruction(union_type, irb->current_basic_block); + ir_ref_instruction(field_name, irb->current_basic_block); + ir_ref_instruction(field_result_loc, irb->current_basic_block); + if (result_loc != nullptr) ir_ref_instruction(result_loc, irb->current_basic_block); + + return &instruction->base; +} + + 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<IrInstructionVectorToArray>(&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_ref_instruction(result_loc, ira->new_irb.current_basic_block); + + 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<IrInstructionPtrOfArrayToSlice>(&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_add_alloca(ira, &instruction->base, result_type); + ir_ref_instruction(operand, ira->new_irb.current_basic_block); + ir_ref_instruction(result_loc, ira->new_irb.current_basic_block); return &instruction->base; } @@ -3173,6 +3419,45 @@ 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<IrInstructionAllocaSrc>(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<IrInstructionAllocaGen>(&ira->new_irb, + source_instruction->scope, source_instruction->source_node); + instruction->align = align; + instruction->name_hint = name_hint; + + return instruction; +} + +static IrInstruction *ir_build_end_expr(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *value, ResultLoc *result_loc) +{ + IrInstructionEndExpr *instruction = ir_build_instruction<IrInstructionEndExpr>(irb, scope, source_node); + instruction->base.is_gen = true; + instruction->value = value; + 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; @@ -3273,6 +3558,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); } @@ -3361,7 +3647,7 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode return ir_build_cond_br(irb, scope, node, is_canceled_bool, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, is_comptime); } -static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { assert(node->type == NodeTypeReturnExpr); ZigFn *fn_entry = exec_fn_entry(irb->exec); @@ -3385,12 +3671,16 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, switch (node->data.return_expr.kind) { case ReturnKindUnconditional: { + ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1); + result_loc_ret->base.id = ResultLocIdReturn; + ir_build_reset_result(irb, scope, node, &result_loc_ret->base); + 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; @@ -3408,7 +3698,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, false); bool should_inline = ir_should_inline(irb->exec, scope); IrInstruction *is_comptime; @@ -3437,21 +3729,24 @@ 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); - 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, true); IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn"); IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue"); @@ -3466,19 +3761,27 @@ 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); + + ResultLocReturn *result_loc_ret = allocate<ResultLocReturn>(1); + result_loc_ret->base.id = ResultLocIdReturn; + ir_build_reset_result(irb, scope, node, &result_loc_ret->base); + ir_build_end_expr(irb, scope, node, err_val, &result_loc_ret->base); + if (irb->codegen->have_err_ret_tracing && !should_inline) { ir_build_save_err_ret_addr(irb, scope, node); } - ir_gen_async_return(irb, scope, node, err_val, false); + IrInstruction *ret_inst = ir_gen_async_return(irb, scope, node, err_val, false); + result_loc_ret->base.source_instruction = ret_inst; } 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 - return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); + return ir_expr_wrap(irb, scope, ir_build_load_ptr(irb, scope, node, unwrapped_ptr), result_loc); } } zig_unreachable(); @@ -3562,7 +3865,17 @@ static ZigVar *ir_create_var(IrBuilder *irb, AstNode *node, Scope *scope, Buf *n return var; } -static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node) { +static ResultLocPeer *create_peer_result(ResultLocPeerParent *peer_parent) { + ResultLocPeer *result = allocate<ResultLocPeer>(1); + result->base.id = ResultLocIdPeer; + result->base.source_instruction = peer_parent->base.source_instruction; + result->parent = peer_parent; + return result; +} + +static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode *block_node, LVal lval, + ResultLoc *result_loc) +{ assert(block_node->type == NodeTypeBlock); ZigList<IrInstruction *> incoming_values = {0}; @@ -3580,15 +3893,24 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode if (block_node->data.block.statements.length == 0) { // {} - return ir_build_const_void(irb, child_scope, block_node); + return ir_lval_wrap(irb, parent_scope, ir_build_const_void(irb, child_scope, block_node), lval, result_loc); } if (block_node->data.block.name != nullptr) { + scope_block->lval = lval; scope_block->incoming_blocks = &incoming_blocks; scope_block->incoming_values = &incoming_values; scope_block->end_block = ir_create_basic_block(irb, parent_scope, "BlockEnd"); scope_block->is_comptime = ir_build_const_bool(irb, parent_scope, block_node, ir_should_inline(irb->exec, parent_scope)); + + scope_block->peer_parent = allocate<ResultLocPeerParent>(1); + scope_block->peer_parent->base.id = ResultLocIdPeerParent; + scope_block->peer_parent->base.source_instruction = scope_block->is_comptime; + scope_block->peer_parent->end_bb = scope_block->end_block; + scope_block->peer_parent->is_comptime = scope_block->is_comptime; + scope_block->peer_parent->parent = result_loc; + ir_build_reset_result(irb, parent_scope, block_node, &scope_block->peer_parent->base); } bool is_continuation_unreachable = false; @@ -3602,6 +3924,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; @@ -3622,21 +3946,41 @@ static IrInstruction *ir_gen_block(IrBuilder *irb, Scope *parent_scope, AstNode return noreturn_return_value; } + if (scope_block->peer_parent != nullptr && scope_block->peer_parent->peers.length != 0) { + scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; + } ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); - return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); + IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, scope_block->peer_parent); + return ir_expr_wrap(irb, parent_scope, phi, result_loc); } else { incoming_blocks.append(irb->current_basic_block); - incoming_values.append(ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node))); + IrInstruction *else_expr_result = ir_mark_gen(ir_build_const_void(irb, parent_scope, block_node)); + + if (scope_block->peer_parent != nullptr) { + ResultLocPeer *peer_result = create_peer_result(scope_block->peer_parent); + scope_block->peer_parent->peers.append(peer_result); + ir_build_end_expr(irb, parent_scope, block_node, else_expr_result, &peer_result->base); + + if (scope_block->peer_parent->peers.length != 0) { + scope_block->peer_parent->peers.last()->next_bb = scope_block->end_block; + } + } + + incoming_values.append(else_expr_result); } if (block_node->data.block.name != nullptr) { ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); ir_mark_gen(ir_build_br(irb, parent_scope, block_node, scope_block->end_block, scope_block->is_comptime)); ir_set_cursor_at_end_and_append_block(irb, scope_block->end_block); - return ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); + IrInstruction *phi = ir_build_phi(irb, parent_scope, block_node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, scope_block->peer_parent); + return ir_expr_wrap(irb, parent_scope, phi, result_loc); } else { ir_gen_defers_for_block(irb, child_scope, outer_block_scope, false); - return ir_mark_gen(ir_mark_gen(ir_build_const_void(irb, child_scope, block_node))); + IrInstruction *void_inst = ir_mark_gen(ir_build_const_void(irb, child_scope, block_node)); + return ir_lval_wrap(irb, parent_scope, void_inst, lval, result_loc); } } @@ -3656,7 +4000,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) @@ -3667,7 +4011,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); @@ -3718,7 +4062,7 @@ static IrInstruction *ir_gen_bool_or(IrBuilder *irb, Scope *scope, AstNode *node incoming_blocks[0] = post_val1_block; incoming_blocks[1] = post_val2_block; - return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); + return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); } static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -3760,16 +4104,51 @@ static IrInstruction *ir_gen_bool_and(IrBuilder *irb, Scope *scope, AstNode *nod incoming_blocks[0] = post_val1_block; incoming_blocks[1] = post_val2_block; - return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); + return ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); } -static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node) { +static ResultLocPeerParent *ir_build_result_peers(IrBuilder *irb, IrInstruction *cond_br_inst, + IrBasicBlock *end_block, ResultLoc *parent, IrInstruction *is_comptime) +{ + ResultLocPeerParent *peer_parent = allocate<ResultLocPeerParent>(1); + peer_parent->base.id = ResultLocIdPeerParent; + peer_parent->base.source_instruction = cond_br_inst; + peer_parent->end_bb = end_block; + peer_parent->is_comptime = is_comptime; + peer_parent->parent = parent; + + 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; +} + +static ResultLocPeerParent *ir_build_binary_result_peers(IrBuilder *irb, IrInstruction *cond_br_inst, + IrBasicBlock *else_block, IrBasicBlock *end_block, ResultLoc *parent, IrInstruction *is_comptime) +{ + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, parent, is_comptime); + + peer_parent->peers.append(create_peer_result(peer_parent)); + peer_parent->peers.last()->next_bb = else_block; + + peer_parent->peers.append(create_peer_result(peer_parent)); + peer_parent->peers.last()->next_bb = end_block; + + return peer_parent; +} + +static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeBinOpExpr); 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; @@ -3786,10 +4165,14 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "OptionalNonNull"); IrBasicBlock *null_block = ir_create_basic_block(irb, parent_scope, "OptionalNull"); IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "OptionalEnd"); - ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, is_comptime); + IrInstruction *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_non_null, ok_block, null_block, 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(irb, op2_node, parent_scope); + IrInstruction *null_result = ir_gen_node_extra(irb, op2_node, parent_scope, LValNone, + &peer_parent->peers.at(0)->base); if (null_result == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; IrBasicBlock *after_null_block = irb->current_basic_block; @@ -3797,8 +4180,9 @@ 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.at(1)->base); IrBasicBlock *after_ok_block = irb->current_basic_block; ir_build_br(irb, parent_scope, node, end_block, is_comptime); @@ -3809,7 +4193,8 @@ static IrInstruction *ir_gen_orelse(IrBuilder *irb, Scope *parent_scope, AstNode IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); incoming_blocks[0] = after_null_block; incoming_blocks[1] = after_ok_block; - return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); + IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); + return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); } static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, AstNode *node) { @@ -3829,7 +4214,7 @@ static IrInstruction *ir_gen_error_union(IrBuilder *irb, Scope *parent_scope, As return ir_build_error_union(irb, parent_scope, node, err_set, payload); } -static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { assert(node->type == NodeTypeBinOpExpr); BinOpType bin_op_type = node->data.bin_op_expr.bin_op; @@ -3837,87 +4222,87 @@ static IrInstruction *ir_gen_bin_op(IrBuilder *irb, Scope *scope, AstNode *node) case BinOpTypeInvalid: zig_unreachable(); case BinOpTypeAssign: - return ir_gen_assign(irb, scope, node); + return ir_lval_wrap(irb, scope, ir_gen_assign(irb, scope, node), lval, result_loc); case BinOpTypeAssignTimes: - return ir_gen_assign_op(irb, scope, node, IrBinOpMult); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMult), lval, result_loc); case BinOpTypeAssignTimesWrap: - return ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMultWrap), lval, result_loc); case BinOpTypeAssignDiv: - return ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpDivUnspecified), lval, result_loc); case BinOpTypeAssignMod: - return ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpRemUnspecified), lval, result_loc); case BinOpTypeAssignPlus: - return ir_gen_assign_op(irb, scope, node, IrBinOpAdd); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAdd), lval, result_loc); case BinOpTypeAssignPlusWrap: - return ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpAddWrap), lval, result_loc); case BinOpTypeAssignMinus: - return ir_gen_assign_op(irb, scope, node, IrBinOpSub); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSub), lval, result_loc); case BinOpTypeAssignMinusWrap: - return ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpSubWrap), lval, result_loc); case BinOpTypeAssignBitShiftLeft: - return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); case BinOpTypeAssignBitShiftRight: - return ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); case BinOpTypeAssignBitAnd: - return ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinAnd), lval, result_loc); case BinOpTypeAssignBitXor: - return ir_gen_assign_op(irb, scope, node, IrBinOpBinXor); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinXor), lval, result_loc); case BinOpTypeAssignBitOr: - return ir_gen_assign_op(irb, scope, node, IrBinOpBinOr); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpBinOr), lval, result_loc); case BinOpTypeAssignMergeErrorSets: - return ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets); + return ir_lval_wrap(irb, scope, ir_gen_assign_op(irb, scope, node, IrBinOpMergeErrorSets), lval, result_loc); case BinOpTypeBoolOr: - return ir_gen_bool_or(irb, scope, node); + return ir_lval_wrap(irb, scope, ir_gen_bool_or(irb, scope, node), lval, result_loc); case BinOpTypeBoolAnd: - return ir_gen_bool_and(irb, scope, node); + return ir_lval_wrap(irb, scope, ir_gen_bool_and(irb, scope, node), lval, result_loc); case BinOpTypeCmpEq: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpEq), lval, result_loc); case BinOpTypeCmpNotEq: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpNotEq), lval, result_loc); case BinOpTypeCmpLessThan: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessThan), lval, result_loc); case BinOpTypeCmpGreaterThan: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterThan), lval, result_loc); case BinOpTypeCmpLessOrEq: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpLessOrEq), lval, result_loc); case BinOpTypeCmpGreaterOrEq: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpCmpGreaterOrEq), lval, result_loc); case BinOpTypeBinOr: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinOr), lval, result_loc); case BinOpTypeBinXor: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinXor), lval, result_loc); case BinOpTypeBinAnd: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBinAnd), lval, result_loc); case BinOpTypeBitShiftLeft: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftLeftLossy), lval, result_loc); case BinOpTypeBitShiftRight: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpBitShiftRightLossy), lval, result_loc); case BinOpTypeAdd: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAdd), lval, result_loc); case BinOpTypeAddWrap: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpAddWrap), lval, result_loc); case BinOpTypeSub: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpSub); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSub), lval, result_loc); case BinOpTypeSubWrap: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpSubWrap), lval, result_loc); case BinOpTypeMult: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpMult); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMult), lval, result_loc); case BinOpTypeMultWrap: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMultWrap), lval, result_loc); case BinOpTypeDiv: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpDivUnspecified), lval, result_loc); case BinOpTypeMod: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpRemUnspecified), lval, result_loc); case BinOpTypeArrayCat: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayCat), lval, result_loc); case BinOpTypeArrayMult: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpArrayMult), lval, result_loc); case BinOpTypeMergeErrorSets: - return ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets); + return ir_lval_wrap(irb, scope, ir_gen_bin_op_id(irb, scope, node, IrBinOpMergeErrorSets), lval, result_loc); case BinOpTypeUnwrapOptional: - return ir_gen_orelse(irb, scope, node); + return ir_gen_orelse(irb, scope, node, lval, result_loc); case BinOpTypeErrorUnion: - return ir_gen_error_union(irb, scope, node); + return ir_lval_wrap(irb, scope, ir_gen_error_union(irb, scope, node), lval, result_loc); } zig_unreachable(); } @@ -3962,12 +4347,12 @@ static void populate_invalid_variable_in_scope(CodeGen *g, Scope *scope, AstNode TldVar *tld_var = allocate<TldVar>(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); } -static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, ResultLoc *result_loc) { Error err; assert(node->type == NodeTypeSymbol); @@ -4001,7 +4386,7 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, if (lval == LValPtr) { return ir_build_ref(irb, scope, node, value, false, false); } else { - return value; + return ir_expr_wrap(irb, scope, value, result_loc); } } @@ -4009,15 +4394,22 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, ZigVar *var = find_variable(irb->codegen, scope, variable_name, &crossed_fndef_scope); if (var) { IrInstruction *var_ptr = ir_build_var_ptr_x(irb, scope, node, var, crossed_fndef_scope); - if (lval == LValPtr) + if (lval == LValPtr) { return var_ptr; - else - return ir_build_load_ptr(irb, scope, node, var_ptr); + } else { + return ir_expr_wrap(irb, scope, ir_build_load_ptr(irb, scope, node, var_ptr), result_loc); + } } Tld *tld = find_decl(irb->codegen, scope, variable_name); - if (tld) - return ir_build_decl_ref(irb, scope, node, tld, lval); + if (tld) { + IrInstruction *decl_ref = ir_build_decl_ref(irb, scope, node, tld, lval); + if (lval == LValPtr) { + return decl_ref; + } else { + return ir_expr_wrap(irb, scope, decl_ref, result_loc); + } + } if (get_container_scope(node->owner)->any_imports_failed) { // skip the error message since we had a failing import in this file @@ -4028,11 +4420,13 @@ static IrInstruction *ir_gen_symbol(IrBuilder *irb, Scope *scope, AstNode *node, return ir_build_undeclared_identifier(irb, scope, node, variable_name); } -static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) { +static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ 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; @@ -4042,11 +4436,12 @@ static IrInstruction *ir_gen_array_access(IrBuilder *irb, Scope *scope, AstNode return subscript_instruction; IrInstruction *ptr_instruction = ir_build_elem_ptr(irb, scope, node, array_ref_instruction, - subscript_instruction, true, PtrLenSingle); + subscript_instruction, true, PtrLenSingle, nullptr); if (lval == LValPtr) return ptr_instruction; - return ir_build_load_ptr(irb, scope, node, ptr_instruction); + IrInstruction *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); } static IrInstruction *ir_gen_field_access(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -4055,11 +4450,11 @@ 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; - 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) { @@ -4132,7 +4527,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; @@ -4168,7 +4565,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: { @@ -4178,7 +4575,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: { @@ -4188,7 +4585,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: { @@ -4198,7 +4595,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: { @@ -4208,7 +4605,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: { @@ -4218,12 +4615,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: { @@ -4238,7 +4635,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: { @@ -4258,7 +4655,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: { @@ -4273,7 +4670,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: { @@ -4283,7 +4680,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: { @@ -4297,7 +4694,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: { @@ -4307,7 +4704,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: { @@ -4317,7 +4714,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: @@ -4353,8 +4750,9 @@ 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)); - return ir_lval_wrap(irb, scope, cmpxchg, lval); + 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: { @@ -4364,7 +4762,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: { @@ -4379,7 +4777,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: { @@ -4394,7 +4792,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: { @@ -4409,7 +4807,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: { @@ -4424,7 +4822,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: { @@ -4439,7 +4837,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: case BuiltinFnIdSin: @@ -4467,7 +4865,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return arg1_value; IrInstruction *ir_sqrt = ir_build_float_op(irb, scope, node, arg0_value, arg1_value, builtin_fn->id); - return ir_lval_wrap(irb, scope, ir_sqrt, lval); + return ir_lval_wrap(irb, scope, ir_sqrt, lval, result_loc); } case BuiltinFnIdTruncate: { @@ -4482,7 +4880,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: { @@ -4497,7 +4895,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: { @@ -4512,7 +4910,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: { @@ -4527,7 +4925,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: { @@ -4541,8 +4939,8 @@ 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); - return ir_lval_wrap(irb, scope, result, lval); + 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: { @@ -4551,8 +4949,8 @@ 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); - return ir_lval_wrap(irb, scope, result, lval); + 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: { @@ -4567,7 +4965,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: { @@ -4582,7 +4980,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: { @@ -4592,7 +4990,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: { @@ -4602,7 +5000,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: { @@ -4612,7 +5010,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: { @@ -4627,7 +5025,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: { @@ -4642,7 +5040,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: { @@ -4662,7 +5060,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: { @@ -4682,7 +5080,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: { @@ -4692,7 +5090,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: { @@ -4708,7 +5106,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: { @@ -4724,12 +5122,12 @@ 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: { 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; @@ -4738,12 +5136,29 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg1_value == irb->codegen->invalid_instruction) return arg1_value; - IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, arg0_value, arg1_value); + IrInstruction *ptr_instruction = ir_build_field_ptr_instruction(irb, scope, node, + arg0_value, arg1_value, false); if (lval == LValPtr) return ptr_instruction; - return ir_build_load_ptr(irb, scope, node, ptr_instruction); + IrInstruction *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); + } + case BuiltinFnIdHasField: + { + 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; + + IrInstruction *type_info = ir_build_has_field(irb, scope, node, arg0_value, arg1_value); + return ir_lval_wrap(irb, scope, type_info, lval, result_loc); } case BuiltinFnIdTypeInfo: { @@ -4753,14 +5168,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")); @@ -4770,7 +5185,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); @@ -4779,18 +5194,18 @@ 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 BuiltinFnIdMulAdd: - return ir_lval_wrap(irb, scope, ir_gen_mul_add(irb, scope, node), lval); + return ir_lval_wrap(irb, scope, ir_gen_mul_add(irb, scope, node), lval, result_loc); case BuiltinFnIdTypeName: { AstNode *arg0_node = node->data.fn_call_expr.params.at(0); @@ -4799,7 +5214,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: { @@ -4809,7 +5224,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: { @@ -4824,22 +5239,31 @@ 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: { - 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<ResultLocBitCast>(1); + result_loc_bit_cast->base.id = ResultLocIdBitCast; + result_loc_bit_cast->base.source_instruction = dest_type; + 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(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); + 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: { @@ -4854,7 +5278,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: { @@ -4864,7 +5288,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: { @@ -4875,7 +5299,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: { @@ -4885,7 +5309,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: { @@ -4905,7 +5329,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: { @@ -4920,7 +5344,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: { @@ -4935,7 +5359,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: @@ -4961,8 +5385,9 @@ 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); - return ir_lval_wrap(irb, scope, call, lval); + 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, result_loc); } case BuiltinFnIdNewStackCall: { @@ -4991,8 +5416,9 @@ 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); - return ir_lval_wrap(irb, scope, call, lval); + 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, result_loc); } case BuiltinFnIdTypeId: { @@ -5002,7 +5428,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: { @@ -5017,7 +5443,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: { @@ -5032,7 +5458,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: { @@ -5042,7 +5468,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: { @@ -5057,17 +5483,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: { @@ -5077,7 +5503,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: { @@ -5092,7 +5518,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: { @@ -5112,12 +5538,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: { @@ -5146,10 +5572,11 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg4_value == irb->codegen->invalid_instruction) return arg4_value; - return ir_build_atomic_rmw(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value, + IrInstruction *inst = ir_build_atomic_rmw(irb, scope, node, arg0_value, arg1_value, arg2_value, arg3_value, arg4_value, // these 2 values don't mean anything since we passed non-null values for other args AtomicRmwOp_xchg, AtomicOrderMonotonic); + return ir_lval_wrap(irb, scope, inst, lval, result_loc); } case BuiltinFnIdAtomicLoad: { @@ -5168,9 +5595,10 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo if (arg2_value == irb->codegen->invalid_instruction) return arg2_value; - return ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value, + IrInstruction *inst = ir_build_atomic_load(irb, scope, node, arg0_value, arg1_value, arg2_value, // this value does not mean anything since we passed non-null values for other arg AtomicOrderMonotonic); + return ir_lval_wrap(irb, scope, inst, lval, result_loc); } case BuiltinFnIdIntToEnum: { @@ -5185,7 +5613,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: { @@ -5195,7 +5623,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: @@ -5233,7 +5661,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: { @@ -5248,17 +5676,36 @@ 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); + } + case BuiltinFnIdUnionInit: + { + AstNode *union_type_node = node->data.fn_call_expr.params.at(0); + IrInstruction *union_type_inst = ir_gen_node(irb, union_type_node, scope); + if (union_type_inst == irb->codegen->invalid_instruction) + return union_type_inst; + + AstNode *name_node = node->data.fn_call_expr.params.at(1); + IrInstruction *name_inst = ir_gen_node(irb, name_node, scope); + if (name_inst == irb->codegen->invalid_instruction) + return name_inst; + + AstNode *init_node = node->data.fn_call_expr.params.at(2); + + return ir_gen_union_init_expr(irb, scope, node, union_type_inst, name_inst, init_node, + lval, result_loc); } } 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); @@ -5284,12 +5731,14 @@ 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); - return ir_lval_wrap(irb, scope, fn_call, lval); + 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, 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); @@ -5310,12 +5759,16 @@ 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, node, condition, + then_block, else_block, is_comptime); + 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); 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.at(0)->base); if (then_expr_result == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; IrBasicBlock *after_then_block = irb->current_basic_block; @@ -5325,11 +5778,12 @@ 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.at(1)->base); if (else_expr_result == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; } else { else_expr_result = ir_build_const_void(irb, scope, node); + ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); } IrBasicBlock *after_else_block = irb->current_basic_block; if (!instr_is_unreachable(else_expr_result)) @@ -5343,14 +5797,15 @@ 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, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); } static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) { 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; @@ -5361,15 +5816,34 @@ 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) +static IrInstruction *ir_expr_wrap(IrBuilder *irb, Scope *scope, IrInstruction *inst, ResultLoc *result_loc) { + ir_build_end_expr(irb, scope, inst->source_node, inst, result_loc); + return inst; +} + +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 (value == irb->codegen->invalid_instruction) + } + + 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); + } else if (result_loc != nullptr) { + return ir_expr_wrap(irb, scope, value, result_loc); + } else { return value; + } - // 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); } static PtrLen star_token_to_ptr_len(TokenId token_id) { @@ -5442,21 +5916,22 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode ptr_len, align_value, bit_offset_start, host_int_bytes, is_allow_zero); } -static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, AstNode *expr_node, - LVal lval) +static IrInstruction *ir_gen_catch_unreachable(IrBuilder *irb, Scope *scope, AstNode *source_node, + AstNode *expr_node, LVal lval, ResultLoc *result_loc) { - 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 *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; if (lval == LValPtr) return payload_ptr; - return ir_build_load_ptr(irb, scope, source_node, payload_ptr); + IrInstruction *load_ptr = ir_build_load_ptr(irb, scope, source_node, payload_ptr); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); } static IrInstruction *ir_gen_bool_not(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -5470,7 +5945,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; @@ -5479,24 +5956,51 @@ 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), lval); + return ir_lval_wrap(irb, scope, ir_gen_node_extra(irb, expr_node, scope, LValPtr, nullptr), lval, result_loc); } } zig_unreachable(); } -static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_union_init_expr(IrBuilder *irb, Scope *scope, AstNode *source_node, + IrInstruction *union_type, IrInstruction *field_name, AstNode *expr_node, + LVal lval, ResultLoc *parent_result_loc) +{ + IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, source_node, parent_result_loc, union_type); + IrInstruction *field_ptr = ir_build_field_ptr_instruction(irb, scope, source_node, container_ptr, + field_name, true); + + ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(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, scope, LValNone, + &result_loc_inst->base); + if (expr_value == irb->codegen->invalid_instruction) + return expr_value; + + IrInstruction *init_union = ir_build_union_init_named_field(irb, scope, source_node, union_type, + field_name, field_ptr, container_ptr); + + return ir_lval_wrap(irb, scope, init_union, lval, parent_result_loc); +} + +static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *parent_result_loc) +{ assert(node->type == NodeTypeContainerInitExpr); AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr; @@ -5514,45 +6018,104 @@ static IrInstruction *ir_gen_container_init_expr(IrBuilder *irb, Scope *scope, A return container_type; } - if (kind == ContainerInitKindStruct) { - if (elem_type != nullptr) { - add_node_error(irb->codegen, container_init_expr->type, - buf_sprintf("initializing array with struct syntax")); - return irb->codegen->invalid_instruction; - } + switch (kind) { + case ContainerInitKindStruct: { + if (elem_type != nullptr) { + add_node_error(irb->codegen, container_init_expr->type, + buf_sprintf("initializing array with struct syntax")); + return irb->codegen->invalid_instruction; + } + + 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<IrInstructionContainerInitFieldsField>(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); + size_t field_count = container_init_expr->entries.length; + IrInstructionContainerInitFieldsField *fields = allocate<IrInstructionContainerInitFieldsField>(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; + Buf *name = entry_node->data.struct_val_field.name; + AstNode *expr_node = entry_node->data.struct_val_field.expr; - fields[i].name = name; - fields[i].value = expr_value; - fields[i].source_node = entry_node; + IrInstruction *field_ptr = ir_build_field_ptr(irb, scope, entry_node, container_ptr, name, true); + ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(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, scope, LValNone, + &result_loc_inst->base); + if (expr_value == irb->codegen->invalid_instruction) + return expr_value; + + fields[i].name = name; + 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); + + return ir_lval_wrap(irb, scope, init_fields, lval, parent_result_loc); } - 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<IrInstruction *>(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; + case ContainerInitKindArray: { + size_t item_count = container_init_expr->entries.length; - values[i] = expr_value; + 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); + } + + IrInstruction *container_ptr = ir_build_resolve_result(irb, scope, node, parent_result_loc, + container_type); + + IrInstruction **result_locs = allocate<IrInstruction *>(item_count); + for (size_t i = 0; i < item_count; i += 1) { + AstNode *expr_node = container_init_expr->entries.at(i); + + 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, container_type); + ResultLocInstruction *result_loc_inst = allocate<ResultLocInstruction>(1); + result_loc_inst->base.id = ResultLocIdInstruction; + result_loc_inst->base.source_instruction = elem_ptr; + ir_ref_instruction(elem_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, scope, LValNone, + &result_loc_inst->base); + if (expr_value == irb->codegen->invalid_instruction) + return expr_value; + + result_locs[i] = elem_ptr; + } + IrInstruction *init_list = ir_build_container_init_list(irb, scope, node, container_type, + item_count, result_locs, container_ptr); + return ir_lval_wrap(irb, scope, init_list, lval, parent_result_loc); } - return ir_build_container_init_list(irb, scope, node, container_type, elem_type, item_count, values); - } else { - zig_unreachable(); } + zig_unreachable(); +} + +static ResultLocVar *ir_build_var_result_loc(IrBuilder *irb, IrInstruction *alloca, ZigVar *var) { + ResultLocVar *result_loc_var = allocate<ResultLocVar>(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; +} + +static void build_decl_var_and_init(IrBuilder *irb, Scope *scope, AstNode *source_node, ZigVar *var, + 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 = 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); } static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -5565,9 +6128,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 { @@ -5578,8 +6144,8 @@ static IrInstruction *ir_gen_var_decl(IrBuilder *irb, Scope *scope, AstNode *nod bool is_const = variable_declaration->is_const; bool is_extern = variable_declaration->is_extern; - IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, - ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime); + bool is_comptime_scalar = ir_should_inline(irb->exec, scope) || variable_declaration->is_comptime; + IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, is_comptime_scalar); ZigVar *var = ir_create_var(irb, node, scope, variable_declaration->symbol, is_const, is_const, is_shadowable, is_comptime); // we detect IrInstructionIdDeclVarSrc in gen_block to make sure the next node @@ -5593,7 +6159,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; } @@ -5606,20 +6172,39 @@ 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 = 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 ? + create_comptime_scope(irb->codegen, variable_declaration->expr, scope) : scope; + // 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, init_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, + &result_loc_var->base); + 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, init_value); + 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) { +static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeWhileExpr); AstNode *continue_expr_node = node->data.while_expr.continue_expr; @@ -5654,25 +6239,33 @@ 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); - 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, 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; if (!instr_is_unreachable(is_err)) { - ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err, - else_block, body_block, is_comptime)); + cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_err, + else_block, body_block, is_comptime); + cond_br_inst->is_gen = true; + } else { + // for the purposes of the source instruction to ir_build_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, + is_comptime); + 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, - 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); + IrInstruction *payload_ptr = ir_build_unwrap_err_payload(irb, payload_scope, symbol_node, + 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); } ZigList<IrInstruction *> incoming_values = {0}; @@ -5684,7 +6277,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n loop_scope->is_comptime = is_comptime; loop_scope->incoming_blocks = &incoming_blocks; loop_scope->incoming_values = &incoming_values; + loop_scope->lval = lval; + loop_scope->peer_parent = peer_parent; + // Note the body block of the loop is not the place that lval and result_loc are used - + // it's actually in break statements, handled similarly to return statements. + // That is why we set those values in loop_scope above and not in this ir_gen_node call. IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); if (body_result == irb->codegen->invalid_instruction) return body_result; @@ -5713,10 +6311,15 @@ 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, 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 (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ResultLocPeer *peer_result = create_peer_result(peer_parent); + peer_parent->peers.append(peer_result); + IrInstruction *else_result = ir_gen_node_extra(irb, else_node, err_scope, lval, &peer_result->base); if (else_result == irb->codegen->invalid_instruction) return else_result; if (!instr_is_unreachable(else_result)) @@ -5730,8 +6333,13 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n incoming_blocks.append(after_cond_block); incoming_values.append(void_else_result); } + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } - return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); + IrInstruction *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); } else if (var_symbol != nullptr) { ir_set_cursor_at_end_and_append_block(irb, cond_block); Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); @@ -5741,23 +6349,32 @@ 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); IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node->data.while_expr.condition, maybe_val); 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; if (!instr_is_unreachable(is_non_null)) { - ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null, - body_block, else_block, is_comptime)); + cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, is_non_null, + body_block, else_block, is_comptime); + cond_br_inst->is_gen = true; + } else { + // for the purposes of the source instruction to ir_build_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, + is_comptime); + 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, nullptr, var_value); + 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); ZigList<IrInstruction *> incoming_values = {0}; ZigList<IrBasicBlock *> incoming_blocks = {0}; @@ -5768,7 +6385,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n loop_scope->is_comptime = is_comptime; loop_scope->incoming_blocks = &incoming_blocks; loop_scope->incoming_values = &incoming_values; + loop_scope->lval = lval; + loop_scope->peer_parent = peer_parent; + // Note the body block of the loop is not the place that lval and result_loc are used - + // it's actually in break statements, handled similarly to return statements. + // That is why we set those values in loop_scope above and not in this ir_gen_node call. IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); if (body_result == irb->codegen->invalid_instruction) return body_result; @@ -5793,7 +6415,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n if (else_node) { ir_set_cursor_at_end_and_append_block(irb, else_block); - else_result = ir_gen_node(irb, else_node, scope); + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ResultLocPeer *peer_result = create_peer_result(peer_parent); + peer_parent->peers.append(peer_result); + else_result = ir_gen_node_extra(irb, else_node, scope, lval, &peer_result->base); if (else_result == irb->codegen->invalid_instruction) return else_result; if (!instr_is_unreachable(else_result)) @@ -5808,8 +6435,13 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n incoming_blocks.append(after_cond_block); incoming_values.append(void_else_result); } + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } - return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); + IrInstruction *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); } else { ir_set_cursor_at_end_and_append_block(irb, cond_block); IrInstruction *cond_val = ir_gen_node(irb, node->data.while_expr.condition, scope); @@ -5817,11 +6449,18 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n return cond_val; 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; if (!instr_is_unreachable(cond_val)) { - ir_mark_gen(ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, - body_block, else_block, is_comptime)); + cond_br_inst = ir_build_cond_br(irb, scope, node->data.while_expr.condition, cond_val, + body_block, else_block, is_comptime); + cond_br_inst->is_gen = true; + } else { + // for the purposes of the source instruction to ir_build_result_peers + cond_br_inst = irb->current_basic_block->instruction_list.last(); } + ResultLocPeerParent *peer_parent = ir_build_result_peers(irb, cond_br_inst, end_block, result_loc, + is_comptime); ir_set_cursor_at_end_and_append_block(irb, body_block); ZigList<IrInstruction *> incoming_values = {0}; @@ -5835,7 +6474,12 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n loop_scope->is_comptime = is_comptime; loop_scope->incoming_blocks = &incoming_blocks; loop_scope->incoming_values = &incoming_values; + loop_scope->lval = lval; + loop_scope->peer_parent = peer_parent; + // Note the body block of the loop is not the place that lval and result_loc are used - + // it's actually in break statements, handled similarly to return statements. + // That is why we set those values in loop_scope above and not in this ir_gen_node call. IrInstruction *body_result = ir_gen_node(irb, node->data.while_expr.body, &loop_scope->base); if (body_result == irb->codegen->invalid_instruction) return body_result; @@ -5860,7 +6504,13 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n if (else_node) { ir_set_cursor_at_end_and_append_block(irb, else_block); - else_result = ir_gen_node(irb, else_node, subexpr_scope); + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ResultLocPeer *peer_result = create_peer_result(peer_parent); + peer_parent->peers.append(peer_result); + + else_result = ir_gen_node_extra(irb, else_node, subexpr_scope, lval, &peer_result->base); if (else_result == irb->codegen->invalid_instruction) return else_result; if (!instr_is_unreachable(else_result)) @@ -5875,12 +6525,19 @@ static IrInstruction *ir_gen_while_expr(IrBuilder *irb, Scope *scope, AstNode *n incoming_blocks.append(after_cond_block); incoming_values.append(void_else_result); } + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } - return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); + IrInstruction *phi = ir_build_phi(irb, scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); } } -static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node) { +static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeForExpr); AstNode *array_node = node->data.for_expr.array_expr; @@ -5895,76 +6552,67 @@ 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; - 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 *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); - 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; - 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); - IrInstruction *index_ptr = ir_build_var_ptr(irb, child_scope, node, index_var); + IrInstruction *zero = ir_build_const_usize(irb, parent_scope, node, 0); + build_decl_var_and_init(irb, parent_scope, index_var_source_node, index_var, zero, index_var_name, is_comptime); + parent_scope = index_var->child_scope; + 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, 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); 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)); + 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 = ir_build_result_peers(irb, cond_br_inst, 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, 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, nullptr); + // 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<IrInstruction *> incoming_values = {0}; ZigList<IrBasicBlock *> incoming_blocks = {0}; @@ -5974,7 +6622,12 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo loop_scope->is_comptime = is_comptime; loop_scope->incoming_blocks = &incoming_blocks; loop_scope->incoming_values = &incoming_values; + loop_scope->lval = LValNone; + loop_scope->peer_parent = peer_parent; + // Note the body block of the loop is not the place that lval and result_loc are used - + // it's actually in break statements, handled similarly to return statements. + // That is why we set those values in loop_scope above and not in this ir_gen_node call. IrInstruction *body_result = ir_gen_node(irb, body_node, &loop_scope->base); if (!instr_is_unreachable(body_result)) { @@ -5991,7 +6644,12 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo if (else_node) { ir_set_cursor_at_end_and_append_block(irb, else_block); - else_result = ir_gen_node(irb, else_node, parent_scope); + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } + ResultLocPeer *peer_result = create_peer_result(peer_parent); + peer_parent->peers.append(peer_result); + else_result = ir_gen_node_extra(irb, else_node, parent_scope, LValNone, &peer_result->base); if (else_result == irb->codegen->invalid_instruction) return else_result; if (!instr_is_unreachable(else_result)) @@ -6007,8 +6665,13 @@ static IrInstruction *ir_gen_for_expr(IrBuilder *irb, Scope *parent_scope, AstNo incoming_blocks.append(after_cond_block); incoming_values.append(void_else_value); } + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } - return ir_build_phi(irb, parent_scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); + IrInstruction *phi = ir_build_phi(irb, parent_scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); + return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); } static IrInstruction *ir_gen_bool_literal(IrBuilder *irb, Scope *scope, AstNode *node) { @@ -6293,7 +6956,9 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod input_list, output_types, output_vars, return_count, is_volatile); } -static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeIfOptional); Buf *var_symbol = node->data.test_expr.var_symbol; @@ -6302,7 +6967,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; @@ -6319,27 +6984,31 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN } else { is_comptime = ir_build_test_comptime(irb, scope, node, is_non_null); } - ir_build_cond_br(irb, scope, node, is_non_null, then_block, else_block, is_comptime); + IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, node, is_non_null, + then_block, else_block, is_comptime); + + 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); 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, var_symbol, is_const, is_const, is_shadowable, is_comptime); - 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); + 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; } else { var_scope = subexpr_scope; } - IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope); + IrInstruction *then_expr_result = ir_gen_node_extra(irb, then_node, var_scope, lval, + &peer_parent->peers.at(0)->base); if (then_expr_result == irb->codegen->invalid_instruction) return then_expr_result; IrBasicBlock *after_then_block = irb->current_basic_block; @@ -6349,11 +7018,12 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN 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.at(1)->base); if (else_expr_result == irb->codegen->invalid_instruction) return else_expr_result; } else { else_expr_result = ir_build_const_void(irb, scope, node); + ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); } IrBasicBlock *after_else_block = irb->current_basic_block; if (!instr_is_unreachable(else_expr_result)) @@ -6367,10 +7037,13 @@ static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstN 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, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); } -static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ assert(node->type == NodeTypeIfErrorExpr); AstNode *target_node = node->data.if_err_expr.target_node; @@ -6381,12 +7054,12 @@ 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; 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, true); IrBasicBlock *ok_block = ir_create_basic_block(irb, scope, "TryOk"); IrBasicBlock *else_block = ir_create_basic_block(irb, scope, "TryElse"); @@ -6394,27 +7067,31 @@ static IrInstruction *ir_gen_if_err_expr(IrBuilder *irb, Scope *scope, AstNode * bool force_comptime = ir_should_inline(irb->exec, scope); IrInstruction *is_comptime = force_comptime ? ir_build_const_bool(irb, scope, node, true) : ir_build_test_comptime(irb, scope, node, is_err); - ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); + IrInstruction *cond_br_inst = ir_build_cond_br(irb, scope, node, is_err, else_block, ok_block, is_comptime); + + 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); 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, var_symbol, var_is_const, var_is_const, is_shadowable, var_is_comptime); - 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); + 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); var_scope = var->child_scope; } else { var_scope = subexpr_scope; } - IrInstruction *then_expr_result = ir_gen_node(irb, then_node, var_scope); + IrInstruction *then_expr_result = ir_gen_node_extra(irb, then_node, var_scope, lval, + &peer_parent->peers.at(0)->base); if (then_expr_result == irb->codegen->invalid_instruction) return then_expr_result; IrBasicBlock *after_then_block = irb->current_basic_block; @@ -6427,23 +7104,23 @@ 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); + 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; } - else_expr_result = ir_gen_node(irb, else_node, err_var_scope); + else_expr_result = ir_gen_node_extra(irb, else_node, err_var_scope, lval, &peer_parent->peers.at(1)->base); if (else_expr_result == irb->codegen->invalid_instruction) return else_expr_result; } else { else_expr_result = ir_build_const_void(irb, scope, node); + ir_build_end_expr(irb, scope, node, else_expr_result, &peer_parent->peers.at(1)->base); } IrBasicBlock *after_else_block = irb->current_basic_block; if (!instr_is_unreachable(else_expr_result)) @@ -6457,14 +7134,15 @@ static IrInstruction *ir_gen_if_err_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, peer_parent); + return ir_expr_wrap(irb, scope, phi, result_loc); } static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *switch_node, AstNode *prong_node, IrBasicBlock *end_block, IrInstruction *is_comptime, IrInstruction *var_is_comptime, IrInstruction *target_value_ptr, IrInstruction **prong_values, size_t prong_values_len, ZigList<IrBasicBlock *> *incoming_blocks, ZigList<IrInstruction *> *incoming_values, - IrInstructionSwitchElseVar **out_switch_else_var) + IrInstructionSwitchElseVar **out_switch_else_var, LVal lval, ResultLoc *result_loc) { assert(switch_node->type == NodeTypeSwitchExpr); assert(prong_node->type == NodeTypeSwitchProng); @@ -6482,28 +7160,27 @@ static bool ir_gen_switch_prong_expr(IrBuilder *irb, Scope *scope, AstNode *swit ZigVar *var = ir_create_var(irb, var_symbol_node, scope, var_name, is_const, is_const, is_shadowable, var_is_comptime); child_scope = var->child_scope; - IrInstruction *var_value; + IrInstruction *var_ptr; if (out_switch_else_var != nullptr) { IrInstructionSwitchElseVar *switch_else_var = ir_build_switch_else_var(irb, scope, var_symbol_node, target_value_ptr); *out_switch_else_var = switch_else_var; - IrInstruction *var_ptr_value = &switch_else_var->base; - var_value = var_is_ptr ? var_ptr_value : ir_build_load_ptr(irb, scope, var_symbol_node, var_ptr_value); + IrInstruction *payload_ptr = &switch_else_var->base; + var_ptr = var_is_ptr ? ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr; } else if (prong_values != nullptr) { - IrInstruction *var_ptr_value = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, + IrInstruction *payload_ptr = ir_build_switch_var(irb, scope, var_symbol_node, target_value_ptr, 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); + var_ptr = var_is_ptr ? ir_build_ref(irb, scope, var_symbol_node, payload_ptr, true, false) : payload_ptr; } else { - var_value = var_is_ptr ? target_value_ptr : ir_build_load_ptr(irb, scope, var_symbol_node, -target_value_ptr); + var_ptr = var_is_ptr ? + ir_build_ref(irb, scope, var_symbol_node, target_value_ptr, true, false) : 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_ptr); } else { child_scope = scope; } - IrInstruction *expr_result = ir_gen_node(irb, expr_node, child_scope); + IrInstruction *expr_result = ir_gen_node_extra(irb, expr_node, child_scope, lval, result_loc); if (expr_result == irb->codegen->invalid_instruction) return false; if (!instr_is_unreachable(expr_result)) @@ -6513,11 +7190,13 @@ target_value_ptr); return true; } -static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node) { +static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ 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); @@ -6544,6 +7223,14 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * IrInstructionSwitchElseVar *switch_else_var = nullptr; + ResultLocPeerParent *peer_parent = allocate<ResultLocPeerParent>(1); + peer_parent->base.id = ResultLocIdPeerParent; + peer_parent->end_bb = end_block; + peer_parent->is_comptime = is_comptime; + peer_parent->parent = result_loc; + + ir_build_reset_result(irb, scope, node, &peer_parent->base); + // First do the else and the ranges Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, scope, is_comptime); Scope *comptime_scope = create_comptime_scope(irb->codegen, node, scope); @@ -6552,6 +7239,7 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * AstNode *prong_node = node->data.switch_expr.prongs.at(prong_i); size_t prong_item_count = prong_node->data.switch_prong.items.length; if (prong_item_count == 0) { + ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); if (else_prong) { ErrorMsg *msg = add_node_error(irb->codegen, prong_node, buf_sprintf("multiple else prongs in switch expression")); @@ -6562,15 +7250,21 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * else_prong = prong_node; IrBasicBlock *prev_block = irb->current_basic_block; + if (peer_parent->peers.length > 0) { + peer_parent->peers.last()->next_bb = else_block; + } + peer_parent->peers.append(this_peer_result_loc); ir_set_cursor_at_end_and_append_block(irb, else_block); if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, &incoming_blocks, &incoming_values, - &switch_else_var)) + &switch_else_var, LValNone, &this_peer_result_loc->base)) { return irb->codegen->invalid_instruction; } ir_set_cursor_at_end(irb, prev_block); } else if (prong_node->data.switch_prong.any_items_are_range) { + ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); + IrInstruction *ok_bit = nullptr; AstNode *last_item_node = nullptr; for (size_t item_i = 0; item_i < prong_item_count; item_i += 1) { @@ -6627,13 +7321,20 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * assert(ok_bit); assert(last_item_node); - ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, range_block_yes, - range_block_no, is_comptime)); + IrInstruction *br_inst = ir_mark_gen(ir_build_cond_br(irb, scope, last_item_node, ok_bit, + range_block_yes, range_block_no, is_comptime)); + if (peer_parent->base.source_instruction == nullptr) { + peer_parent->base.source_instruction = br_inst; + } + if (peer_parent->peers.length > 0) { + peer_parent->peers.last()->next_bb = range_block_yes; + } + peer_parent->peers.append(this_peer_result_loc); ir_set_cursor_at_end_and_append_block(irb, range_block_yes); if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, is_comptime, var_is_comptime, target_value_ptr, nullptr, 0, - &incoming_blocks, &incoming_values, nullptr)) + &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) { return irb->codegen->invalid_instruction; } @@ -6651,6 +7352,8 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * if (prong_node->data.switch_prong.any_items_are_range) continue; + ResultLocPeer *this_peer_result_loc = create_peer_result(peer_parent); + IrBasicBlock *prong_block = ir_create_basic_block(irb, scope, "SwitchProng"); IrInstruction **items = allocate<IrInstruction *>(prong_item_count); @@ -6674,10 +7377,14 @@ static IrInstruction *ir_gen_switch_expr(IrBuilder *irb, Scope *scope, AstNode * } IrBasicBlock *prev_block = irb->current_basic_block; + if (peer_parent->peers.length > 0) { + peer_parent->peers.last()->next_bb = prong_block; + } + peer_parent->peers.append(this_peer_result_loc); ir_set_cursor_at_end_and_append_block(irb, prong_block); if (!ir_gen_switch_prong_expr(irb, subexpr_scope, node, prong_node, end_block, is_comptime, var_is_comptime, target_value_ptr, items, prong_item_count, - &incoming_blocks, &incoming_values, nullptr)) + &incoming_blocks, &incoming_values, nullptr, LValNone, &this_peer_result_loc->base)) { return irb->codegen->invalid_instruction; } @@ -6686,38 +7393,57 @@ 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); + IrInstruction *switch_prongs_void = ir_build_check_switch_prongs(irb, scope, node, target_value, + check_ranges.items, check_ranges.length, else_prong != nullptr); + IrInstruction *br_instruction; if (cases.length == 0) { - ir_build_br(irb, scope, node, else_block, is_comptime); + br_instruction = ir_build_br(irb, scope, node, else_block, is_comptime); } else { IrInstructionSwitchBr *switch_br = ir_build_switch_br(irb, scope, node, target_value, else_block, cases.length, cases.items, is_comptime, switch_prongs_void); if (switch_else_var != nullptr) { switch_else_var->switch_br = switch_br; } + br_instruction = &switch_br->base; + } + if (peer_parent->base.source_instruction == nullptr) { + peer_parent->base.source_instruction = br_instruction; + } + for (size_t i = 0; i < peer_parent->peers.length; i += 1) { + peer_parent->peers.at(i)->base.source_instruction = peer_parent->base.source_instruction; } if (!else_prong) { + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = else_block; + } ir_set_cursor_at_end_and_append_block(irb, else_block); ir_build_unreachable(irb, scope, node); + } else { + if (peer_parent->peers.length != 0) { + peer_parent->peers.last()->next_bb = end_block; + } } ir_set_cursor_at_end_and_append_block(irb, end_block); assert(incoming_blocks.length == incoming_values.length); + IrInstruction *result_instruction; if (incoming_blocks.length == 0) { - return ir_build_const_void(irb, scope, node); + result_instruction = ir_build_const_void(irb, scope, node); } else { - return ir_build_phi(irb, scope, node, incoming_blocks.length, incoming_blocks.items, incoming_values.items); + result_instruction = ir_build_phi(irb, scope, node, incoming_blocks.length, + incoming_blocks.items, incoming_values.items, peer_parent); } + return ir_lval_wrap(irb, scope, result_instruction, lval, result_loc); } static IrInstruction *ir_gen_comptime(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval) { 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); + // purposefully pass null for result_loc and let EndExpr handle it + 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) { @@ -6730,7 +7456,11 @@ static IrInstruction *ir_gen_return_from_block(IrBuilder *irb, Scope *break_scop IrInstruction *result_value; if (node->data.break_expr.expr) { - result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope); + ResultLocPeer *peer_result = create_peer_result(block_scope->peer_parent); + block_scope->peer_parent->peers.append(peer_result); + + result_value = ir_gen_node_extra(irb, node->data.break_expr.expr, break_scope, block_scope->lval, + &peer_result->base); if (result_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; } else { @@ -6800,7 +7530,11 @@ static IrInstruction *ir_gen_break(IrBuilder *irb, Scope *break_scope, AstNode * IrInstruction *result_value; if (node->data.break_expr.expr) { - result_value = ir_gen_node(irb, node->data.break_expr.expr, break_scope); + ResultLocPeer *peer_result = create_peer_result(loop_scope->peer_parent); + loop_scope->peer_parent->peers.append(peer_result); + + result_value = ir_gen_node_extra(irb, node->data.break_expr.expr, break_scope, + loop_scope->lval, &peer_result->base); if (result_value == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; } else { @@ -6888,7 +7622,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; @@ -6896,7 +7630,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; @@ -6913,11 +7647,14 @@ 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) { - assert(node->type == NodeTypeUnwrapErrorExpr); +static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode *node, LVal lval, + ResultLoc *result_loc) +{ + assert(node->type == NodeTypeCatchExpr); AstNode *op1_node = node->data.unwrap_err_expr.op1; AstNode *op2_node = node->data.unwrap_err_expr.op2; @@ -6930,16 +7667,15 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode add_node_error(irb->codegen, var_node, buf_sprintf("unused variable: '%s'", buf_ptr(var_name))); return irb->codegen->invalid_instruction; } - return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, LValNone); + return ir_gen_catch_unreachable(irb, parent_scope, node, op1_node, lval, result_loc); } - 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; - 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, true); IrInstruction *is_comptime; if (ir_should_inline(irb->exec, parent_scope)) { @@ -6951,33 +7687,38 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode IrBasicBlock *ok_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrOk"); IrBasicBlock *err_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrError"); IrBasicBlock *end_block = ir_create_basic_block(irb, parent_scope, "UnwrapErrEnd"); - ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, is_comptime); + IrInstruction *cond_br_inst = ir_build_cond_br(irb, parent_scope, node, is_err, err_block, ok_block, 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, err_block); + Scope *subexpr_scope = create_runtime_scope(irb->codegen, node, parent_scope, is_comptime); Scope *err_scope; if (var_node) { assert(var_node->type == NodeTypeSymbol); Buf *var_name = var_node->data.symbol_expr.symbol; bool is_const = true; bool is_shadowable = false; - ZigVar *var = ir_create_var(irb, node, parent_scope, var_name, + ZigVar *var = ir_create_var(irb, node, subexpr_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, 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; + err_scope = subexpr_scope; } - IrInstruction *err_result = ir_gen_node(irb, op2_node, err_scope); + IrInstruction *err_result = ir_gen_node_extra(irb, op2_node, err_scope, LValNone, &peer_parent->peers.at(0)->base); if (err_result == irb->codegen->invalid_instruction) return irb->codegen->invalid_instruction; IrBasicBlock *after_err_block = irb->current_basic_block; if (!instr_is_unreachable(err_result)) - ir_mark_gen(ir_build_br(irb, err_scope, node, end_block, is_comptime)); + 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_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.at(1)->base); IrBasicBlock *after_ok_block = irb->current_basic_block; ir_build_br(irb, parent_scope, node, end_block, is_comptime); @@ -6988,7 +7729,8 @@ static IrInstruction *ir_gen_catch(IrBuilder *irb, Scope *parent_scope, AstNode IrBasicBlock **incoming_blocks = allocate<IrBasicBlock *>(2); incoming_blocks[0] = after_err_block; incoming_blocks[1] = after_ok_block; - return ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); + IrInstruction *phi = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, peer_parent); + return ir_lval_wrap(irb, parent_scope, phi, lval, result_loc); } static bool render_instance_name_recursive(CodeGen *codegen, Buf *name, Scope *outer_scope, Scope *inner_scope) { @@ -7264,7 +8006,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, @@ -7343,7 +8085,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, @@ -7410,12 +8152,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); } @@ -7437,11 +8179,11 @@ 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); - 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 @@ -7455,7 +8197,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, promise_result_type, nullptr, undefined_value); + 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); IrInstruction *save_token = ir_build_coro_save(irb, scope, node, irb->exec->coro_handle); @@ -7490,12 +8233,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); @@ -7671,7 +8414,8 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod incoming_values[0] = const_bool_true; incoming_blocks[1] = post_cancel_awaiter_block; incoming_values[1] = const_bool_false; - IrInstruction *destroy_ourselves = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values); + IrInstruction *destroy_ourselves = ir_build_phi(irb, parent_scope, node, 2, incoming_blocks, incoming_values, + nullptr); ir_gen_defers_for_block(irb, parent_scope, outer_scope, true); ir_mark_gen(ir_build_cond_br(irb, parent_scope, node, destroy_ourselves, irb->exec->coro_final_cleanup_block, irb->exec->coro_early_final, const_bool_false)); @@ -7680,7 +8424,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) { @@ -7694,37 +8438,37 @@ 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_gen_block(irb, scope, node, lval, result_loc); 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); + return 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); + return ir_gen_symbol(irb, scope, node, lval, result_loc); 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); + 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_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_gen_var_decl(irb, scope, node); case NodeTypeWhileExpr: - return ir_lval_wrap(irb, scope, ir_gen_while_expr(irb, scope, node), lval); + return 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_gen_for_expr(irb, scope, node, lval, result_loc); case NodeTypeArrayAccessExpr: - return ir_gen_array_access(irb, scope, node, lval); + return ir_gen_array_access(irb, scope, node, lval, result_loc); case NodeTypeReturnExpr: - return ir_gen_return(irb, scope, node, lval); + return ir_gen_return(irb, scope, node, lval, result_loc); case NodeTypeFieldAccessExpr: { IrInstruction *ptr_instruction = ir_gen_field_access(irb, scope, node); @@ -7733,86 +8477,89 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop if (lval == LValPtr) return ptr_instruction; - return ir_build_load_ptr(irb, scope, node, ptr_instruction); + IrInstruction *load_ptr = ir_build_load_ptr(irb, scope, node, ptr_instruction); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); } 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; // 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; - 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; - 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; - return ir_build_load_ptr(irb, scope, node, unwrapped_ptr); + IrInstruction *load_ptr = ir_build_load_ptr(irb, scope, node, unwrapped_ptr); + return ir_expr_wrap(irb, scope, load_ptr, result_loc); } 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_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_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_gen_switch_expr(irb, scope, node, lval, result_loc); case NodeTypeCompTime: - return ir_gen_comptime(irb, scope, node, lval); + return ir_expr_wrap(irb, scope, ir_gen_comptime(irb, scope, node, lval), result_loc); 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_build_unreachable(irb, scope, node); 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); - case NodeTypeUnwrapErrorExpr: - return ir_lval_wrap(irb, scope, ir_gen_catch(irb, scope, node), lval); + return ir_gen_slice(irb, scope, node, lval, result_loc); + case NodeTypeCatchExpr: + return 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); case NodeTypeInferredArrayType: add_node_error(irb->codegen, node, buf_sprintf("inferred array size invalid here")); @@ -7821,14 +8568,28 @@ 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 ResultLoc *no_result_loc(void) { + ResultLocNone *result_loc_none = allocate<ResultLocNone>(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. + 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); 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) { @@ -7879,17 +8640,19 @@ 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 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); + 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); 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); + 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); u8_ptr_type = ir_build_const_type(irb, coro_scope, node, @@ -7899,13 +8662,14 @@ 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); + build_decl_var_and_init(irb, coro_scope, node, coro_size_var, coro_size, "coro_size", const_bool_false); 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); + 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); @@ -7925,32 +8689,32 @@ 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); + 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); } @@ -7961,7 +8725,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; @@ -8009,7 +8773,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); } @@ -8017,7 +8781,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); @@ -8031,7 +8795,7 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec incoming_values[0] = const_bool_false; incoming_blocks[1] = irb->exec->coro_normal_final; incoming_values[1] = const_bool_true; - IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values); + IrInstruction *resume_awaiter = ir_build_phi(irb, scope, node, 2, incoming_blocks, incoming_values, nullptr); IrBasicBlock **merge_incoming_blocks = allocate<IrBasicBlock *>(2); IrInstruction **merge_incoming_values = allocate<IrInstruction *>(2); @@ -8039,12 +8803,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec merge_incoming_values[0] = ir_build_const_undefined(irb, scope, node); merge_incoming_blocks[1] = irb->exec->coro_normal_final; merge_incoming_values[1] = await_handle_in_block; - IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values); + IrInstruction *awaiter_handle = ir_build_phi(irb, scope, node, 2, merge_incoming_blocks, merge_incoming_values, nullptr); 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); @@ -8056,7 +8820,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<IrInstruction *>(arg_count); args[0] = implicit_allocator_ptr; // self @@ -8070,7 +8835,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 - ir_build_call(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr, nullptr); + ir_build_call_src(irb, scope, node, nullptr, shrink_fn, arg_count, args, false, FnInlineAuto, false, nullptr, + 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); @@ -8177,6 +8943,15 @@ static ConstExprValue *ir_exec_const_result(CodeGen *codegen, IrExecutable *exec } return &value->value; } else if (ir_has_side_effects(instruction)) { + if (instr_is_comptime(instruction)) { + switch (instruction->id) { + case IrInstructionIdUnwrapErrPayload: + case IrInstructionIdUnionFieldPtr: + continue; + default: + break; + } + } exec_add_error_node(codegen, exec, instruction->source_node, buf_sprintf("unable to evaluate constant expression")); return &codegen->invalid_instruction->value; @@ -9154,15 +9929,6 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc return false; } -static bool is_slice(ZigType *type) { - return type->id == ZigTypeIdStruct && type->data.structure.is_slice; -} - -static bool slice_is_const(ZigType *type) { - assert(is_slice(type)); - return type->data.structure.fields[slice_ptr_index].type_entry->data.pointer.is_const; -} - static bool is_tagged_union(ZigType *type) { if (type->id != ZigTypeIdUnion) return false; @@ -9533,9 +10299,21 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT { Error err; assert(instruction_count >= 1); - IrInstruction *prev_inst = instructions[0]; - if (type_is_invalid(prev_inst->value.type)) { - return ira->codegen->builtin_types.entry_invalid; + IrInstruction *prev_inst; + size_t i = 0; + for (;;) { + prev_inst = instructions[i]; + if (type_is_invalid(prev_inst->value.type)) { + return ira->codegen->builtin_types.entry_invalid; + } + if (prev_inst->value.type->id == ZigTypeIdUnreachable) { + i += 1; + if (i == instruction_count) { + return prev_inst->value.type; + } + continue; + } + break; } ErrorTableEntry **errors = nullptr; size_t errors_count = 0; @@ -9560,7 +10338,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT bool any_are_null = (prev_inst->value.type->id == ZigTypeIdNull); bool convert_to_const_slice = false; - for (size_t i = 1; i < instruction_count; i += 1) { + for (; i < instruction_count; i += 1) { IrInstruction *cur_inst = instructions[i]; ZigType *cur_type = cur_inst->value.type; ZigType *prev_type = prev_inst->value.type; @@ -9579,7 +10357,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT } if (prev_type->id == ZigTypeIdErrorSet) { - assert(err_set_type != nullptr); + ir_assert(err_set_type != nullptr, prev_inst); if (cur_type->id == ZigTypeIdErrorSet) { if (type_is_global_error_set(err_set_type)) { continue; @@ -9839,6 +10617,7 @@ static ZigType *ir_resolve_peer_types(IrAnalyze *ira, AstNode *source_node, ZigT if (prev_type->id == ZigTypeIdNull) { prev_inst = cur_inst; + any_are_null = true; continue; } @@ -10153,6 +10932,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 { @@ -10160,24 +10941,18 @@ 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); - *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<ConstExprValue>(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); + } } } } @@ -10195,7 +10970,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: { @@ -10295,7 +11069,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); @@ -10308,9 +11082,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; } } @@ -10352,7 +11123,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; @@ -10383,11 +11154,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, true, false); + 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) { @@ -10419,51 +11191,136 @@ static IrBasicBlock *ir_get_new_bb_runtime(IrAnalyze *ira, IrBasicBlock *old_bb, } static void ir_start_bb(IrAnalyze *ira, IrBasicBlock *old_bb, IrBasicBlock *const_predecessor_bb) { + ir_assert(!old_bb->suspended, old_bb->instruction_list.at(0)); ira->instruction_index = 0; ira->old_irb.current_basic_block = old_bb; ira->const_predecessor_bb = const_predecessor_bb; + ira->old_bb_index = old_bb->index; } -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; - while (ira->instruction_index < ira->old_irb.current_basic_block->instruction_list.length) { - IrInstruction *next_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index); - if (!next_instruction->is_gen) { - ir_add_error(ira, next_instruction, buf_sprintf("unreachable code")); - break; - } - ira->instruction_index += 1; +static IrInstruction *ira_suspend(IrAnalyze *ira, IrInstruction *old_instruction, IrBasicBlock *next_bb, + IrSuspendPosition *suspend_pos) +{ + if (ira->codegen->verbose_ir) { + fprintf(stderr, "suspend %s_%zu %s_%zu #%zu (%zu,%zu)\n", ira->old_irb.current_basic_block->name_hint, + ira->old_irb.current_basic_block->debug_id, + ira->old_irb.exec->basic_block_list.at(ira->old_bb_index)->name_hint, + ira->old_irb.exec->basic_block_list.at(ira->old_bb_index)->debug_id, + ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index)->debug_id, + ira->old_bb_index, ira->instruction_index); + } + suspend_pos->basic_block_index = ira->old_bb_index; + suspend_pos->instruction_index = ira->instruction_index; + + ira->old_irb.current_basic_block->suspended = true; + + // null next_bb means that the caller plans to call ira_resume before returning + if (next_bb != nullptr) { + 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(); + if (ira->codegen->verbose_ir) { + fprintf(stderr, "resume (%zu,%zu) ", pos.basic_block_index, pos.instruction_index); + } + 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); + assert(ira->old_irb.current_basic_block->in_resume_stack); + ira->old_irb.current_basic_block->in_resume_stack = false; + ira->old_irb.current_basic_block->suspended = false; + ira->instruction_index = pos.instruction_index; + assert(pos.instruction_index < ira->old_irb.current_basic_block->instruction_list.length); + if (ira->codegen->verbose_ir) { + fprintf(stderr, "%s_%zu #%zu\n", ira->old_irb.current_basic_block->name_hint, + ira->old_irb.current_basic_block->debug_id, + ira->old_irb.current_basic_block->instruction_list.at(pos.instruction_index)->debug_id); + } + 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; +} - size_t my_old_bb_index = ira->old_bb_index; +static void ir_start_next_bb(IrAnalyze *ira) { ira->old_bb_index += 1; bool need_repeat = true; for (;;) { while (ira->old_bb_index < ira->old_irb.exec->basic_block_list.length) { IrBasicBlock *old_bb = ira->old_irb.exec->basic_block_list.at(ira->old_bb_index); - if (old_bb->other == nullptr) { + if (old_bb->other == nullptr && old_bb->suspend_instruction_ref == nullptr) { ira->old_bb_index += 1; continue; } - if (old_bb->other->instruction_list.length != 0 || ira->old_bb_index == my_old_bb_index) { + // if it's already started, or + // if it's a suspended block, + // then skip it + if (old_bb->suspended || + (old_bb->other != nullptr && old_bb->other->instruction_list.length != 0) || + (old_bb->other != nullptr && old_bb->other->already_appended)) + { 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; + } + + if (old_bb->other == nullptr) { + old_bb->other = ir_get_new_bb_runtime(ira, old_bb, old_bb->suspend_instruction_ref); + } + ira->new_irb.current_basic_block = old_bb->other; ir_start_bb(ira, old_bb, nullptr); return; } - if (!need_repeat) + if (!need_repeat) { + if (ira->resume_stack.length != 0) { + ira_resume(ira); + } return; + } need_repeat = false; ira->old_bb_index = 0; continue; } } +static void ir_finish_bb(IrAnalyze *ira) { + if (!ira->new_irb.current_basic_block->already_appended) { + ira->new_irb.current_basic_block->already_appended = true; + if (ira->codegen->verbose_ir) { + fprintf(stderr, "append new bb %s_%zu\n", ira->new_irb.current_basic_block->name_hint, + ira->new_irb.current_basic_block->debug_id); + } + ira->new_irb.exec->basic_block_list.append(ira->new_irb.current_basic_block); + } + ira->instruction_index += 1; + while (ira->instruction_index < ira->old_irb.current_basic_block->instruction_list.length) { + IrInstruction *next_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index); + if (!next_instruction->is_gen) { + ir_add_error(ira, next_instruction, buf_sprintf("unreachable code")); + break; + } + ira->instruction_index += 1; + } + + ir_start_next_bb(ira); +} + static IrInstruction *ir_unreach_error(IrAnalyze *ira) { ira->old_bb_index = SIZE_MAX; ira->new_irb.exec->invalid = true; @@ -10524,6 +11381,12 @@ static IrInstruction *ir_const_undef(IrAnalyze *ira, IrInstruction *source_instr return result; } +static IrInstruction *ir_const_unreachable(IrAnalyze *ira, IrInstruction *source_instruction) { + IrInstruction *result = ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_unreachable); + result->value.special = ConstValSpecialStatic; + return result; +} + static IrInstruction *ir_const_void(IrAnalyze *ira, IrInstruction *source_instruction) { return ir_const(ira, source_instruction, ira->codegen->builtin_types.entry_void); } @@ -10721,7 +11584,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); @@ -10747,20 +11610,29 @@ 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 && 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, false); + 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; } 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; @@ -10770,7 +11642,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; @@ -10783,10 +11655,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, true, false); + 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; } @@ -10833,7 +11714,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); @@ -10857,10 +11740,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, true, false); + 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; } @@ -10920,20 +11813,21 @@ 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, true, false); + } 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; } 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 @@ -10942,7 +11836,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; @@ -10965,12 +11859,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, true, false); + 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; } @@ -11608,7 +12504,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 @@ -11617,7 +12513,14 @@ 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); + if (result_loc == nullptr) { + result_loc = no_result_loc(); + } + 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; + } + 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, @@ -11667,7 +12570,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; @@ -11683,7 +12586,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 @@ -11693,12 +12596,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; } @@ -11722,7 +12625,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); } } } @@ -11732,12 +12635,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; } @@ -11755,11 +12658,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; @@ -11841,7 +12744,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); } } @@ -11858,11 +12761,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; @@ -11870,9 +12773,9 @@ static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_inst } } - // *[N]T to [*]T + // *[N]T to [*]T and [*c]T if (wanted_type->id == ZigTypeIdPointer && - wanted_type->data.pointer.ptr_len == PtrLenUnknown && + (wanted_type->data.pointer.ptr_len == PtrLenUnknown || wanted_type->data.pointer.ptr_len == PtrLenC) && actual_type->id == ZigTypeIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle && actual_type->data.pointer.child_type->id == ZigTypeIdArray) @@ -11905,7 +12808,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); } } @@ -11936,11 +12839,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; @@ -11952,7 +12855,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. @@ -12076,7 +12979,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) @@ -12118,7 +13021,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)); @@ -12131,63 +13036,76 @@ 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_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) { +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, + 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 != ConstPtrMutRuntimeVar) { + 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<IrInstructionRef *>(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<IrInstructionRef *>(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, true, false); + 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) { @@ -12401,6 +13319,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; @@ -12563,7 +13489,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 && @@ -13005,7 +13931,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")); @@ -13380,8 +14306,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; @@ -13604,10 +14530,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]; @@ -13668,7 +14596,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; } } @@ -13765,12 +14694,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) { @@ -13785,18 +14708,40 @@ 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 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; + } + + // 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)) { result_type = ira->codegen->builtin_types.entry_invalid; } else if (result_type->id == ZigTypeIdUnreachable || result_type->id == ZigTypeIdOpaque) { - ir_add_error_node(ira, source_node, - buf_sprintf("variable of type '%s' not allowed", buf_ptr(&result_type->name))); - result_type = ira->codegen->builtin_types.entry_invalid; + zig_unreachable(); + } + + 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) { + 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); + } + } } switch (type_requires_comptime(ira->codegen, result_type)) { @@ -13813,18 +14758,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; @@ -13871,11 +14818,29 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, } } - if (casted_init_value->value.special != ConstValSpecialRuntime) { - if (var->mem_slot_index != SIZE_MAX) { + if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) { + // 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, &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); @@ -13892,7 +14857,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 IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructionExport *instruction) { @@ -14062,9 +15027,10 @@ static IrInstruction *ir_analyze_instruction_export(IrAnalyze *ira, IrInstructio break; } } break; + case ZigTypeIdInt: + break; case ZigTypeIdVoid: case ZigTypeIdBool: - case ZigTypeIdInt: case ZigTypeIdFloat: case ZigTypeIdPointer: case ZigTypeIdComptimeFloat: @@ -14186,7 +15152,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; } @@ -14194,7 +15160,436 @@ 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 = ConstValSpecialStatic; + result->base.value.data.x_ptr.special = ConstPtrSpecialRef; + 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))) + 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 ZigType *ir_result_loc_expected_type(IrAnalyze *ira, IrInstruction *suspend_source_instr, + ResultLoc *result_loc) +{ + switch (result_loc->id) { + case ResultLocIdInvalid: + case ResultLocIdPeerParent: + zig_unreachable(); + case ResultLocIdNone: + case ResultLocIdVar: + case ResultLocIdBitCast: + return nullptr; + case ResultLocIdInstruction: + return result_loc->source_instruction->child->value.type; + case ResultLocIdReturn: + return ira->explicit_return_type; + case ResultLocIdPeer: + return reinterpret_cast<ResultLocPeer*>(result_loc)->parent->resolved_type; + } + 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 void set_up_result_loc_for_inferred_comptime(IrInstruction *ptr) { + ConstExprValue *undef_child = create_const_vals(1); + undef_child->type = ptr->value.type->data.pointer.child_type; + undef_child->special = ConstValSpecialUndef; + ptr->value.special = ConstValSpecialStatic; + ptr->value.data.x_ptr.mut = ConstPtrMutInfer; + ptr->value.data.x_ptr.special = ConstPtrSpecialRef; + ptr->value.data.x_ptr.data.ref.pointee = undef_child; +} + +// 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, bool force_runtime, bool non_null_comptime) +{ + Error err; + if (result_loc->resolved_loc != nullptr) { + // 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; + switch (result_loc->id) { + case ResultLocIdInvalid: + case ResultLocIdPeerParent: + zig_unreachable(); + case ResultLocIdNone: { + if (value != nullptr) { + return nullptr; + } + // need to return a result location and don't have one. use a stack allocation + IrInstructionAllocaGen *alloca_gen = ir_create_alloca_gen(ira, suspend_source_instr, 0, ""); + if ((err = type_resolve(ira->codegen, value_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + alloca_gen->base.value.type = get_pointer_to_type_extra(ira->codegen, value_type, false, false, + PtrLenSingle, 0, 0, 0, false); + set_up_result_loc_for_inferred_comptime(&alloca_gen->base); + ZigFn *fn_entry = exec_fn_entry(ira->new_irb.exec); + 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; + } + case ResultLocIdVar: { + ResultLocVar *result_loc_var = reinterpret_cast<ResultLocVar *>(result_loc); + assert(result_loc->source_instruction->id == IrInstructionIdAllocaSrc); + + if (value_type->id == ZigTypeIdUnreachable || value_type->id == ZigTypeIdOpaque) { + ir_add_error(ira, result_loc->source_instruction, + buf_sprintf("variable of type '%s' not allowed", buf_ptr(&value_type->name))); + return ira->codegen->invalid_instruction; + } + + IrInstructionAllocaSrc *alloca_src = + reinterpret_cast<IrInstructionAllocaSrc *>(result_loc->source_instruction); + 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); + + 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; + } + IrInstruction *alloca_gen; + if (is_comptime && value != nullptr) { + 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 { + 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 ResultLocIdReturn: { + if (!non_null_comptime) { + bool is_comptime = value != nullptr && value->value.special != ConstValSpecialRuntime; + if (is_comptime) + return nullptr; + } + if ((err = type_resolve(ira->codegen, ira->explicit_return_type, ResolveStatusZeroBitsKnown))) { + return ira->codegen->invalid_instruction; + } + 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); + if (ir_should_inline(ira->old_irb.exec, result_loc->source_instruction->scope)) { + set_up_result_loc_for_inferred_comptime(result_loc->resolved_loc); + } + return result_loc->resolved_loc; + } + case ResultLocIdPeer: { + ResultLocPeer *result_peer = reinterpret_cast<ResultLocPeer *>(result_loc); + ResultLocPeerParent *peer_parent = result_peer->parent; + + if (peer_parent->peers.length == 1) { + IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, + value_type, value, force_runtime, non_null_comptime); + result_peer->suspend_pos.basic_block_index = SIZE_MAX; + result_peer->suspend_pos.instruction_index = SIZE_MAX; + 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 = parent_result_loc; + return result_loc->resolved_loc; + } + + bool is_comptime; + if (!ir_resolve_comptime(ira, peer_parent->is_comptime->child, &is_comptime)) + 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, force_runtime, non_null_comptime); + } + return nullptr; + } + + if (peer_parent->resolved_type == nullptr) { + if (peer_parent->end_bb->suspend_instruction_ref == nullptr) { + peer_parent->end_bb->suspend_instruction_ref = suspend_source_instr; + } + IrInstruction *unreach_inst = ira_suspend(ira, suspend_source_instr, result_peer->next_bb, + &result_peer->suspend_pos); + if (result_peer->next_bb == nullptr) { + ir_start_next_bb(ira); + } + return unreach_inst; + } + + IrInstruction *parent_result_loc = ir_resolve_result(ira, suspend_source_instr, peer_parent->parent, + peer_parent->resolved_type, nullptr, force_runtime, non_null_comptime); + if (parent_result_loc == nullptr || type_is_invalid(parent_result_loc->value.type) || + parent_result_loc->value.type->id == ZigTypeIdUnreachable) + { + return parent_result_loc; + } + // because is_comptime is false, we mark this a runtime pointer + parent_result_loc->value.special = ConstValSpecialRuntime; + result_loc->written = true; + result_loc->resolved_loc = parent_result_loc; + return result_loc->resolved_loc; + } + case ResultLocIdBitCast: { + ResultLocBitCast *result_bit_cast = reinterpret_cast<ResultLocBitCast *>(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 *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, bitcasted_value, force_runtime, non_null_comptime); + 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 *parent_ptr_type = parent_result_loc->value.type; + assert(parent_ptr_type->id == ZigTypeIdPointer); + if ((err = type_resolve(ira->codegen, parent_ptr_type->data.pointer.child_type, + ResolveStatusAlignmentKnown))) + { + return ira->codegen->invalid_instruction; + } + uint64_t parent_ptr_align = get_ptr_align(ira->codegen, parent_ptr_type); + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value_type, + parent_ptr_type->data.pointer.is_const, parent_ptr_type->data.pointer.is_volatile, PtrLenSingle, + parent_ptr_align, 0, 0, parent_ptr_type->data.pointer.allow_zero); + + 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(); +} + +static IrInstruction *ir_resolve_result(IrAnalyze *ira, IrInstruction *suspend_source_instr, + 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, force_runtime, non_null_comptime); + if (result_loc == nullptr || (instr_is_unreachable(result_loc) || type_is_invalid(result_loc->value.type))) + return result_loc; + + if ((force_runtime || (value != nullptr && !instr_is_comptime(value))) && + result_loc_pass1->written && result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) + { + result_loc->value.special = ConstValSpecialRuntime; + } + + 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 && + 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) { + return ir_analyze_unwrap_err_code(ira, suspend_source_instr, result_loc, true); + } else { + 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; + } + } + } else if (is_slice(actual_elem_type) && value_type->id == ZigTypeIdArray) { + // need to allow EndExpr to do the implicit cast from array to slice + result_loc_pass1->written = false; + } + return result_loc; +} + +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_with_result(ira, target, dest_type, instruction->result_loc); +} + +static IrInstruction *ir_analyze_instruction_resolve_result(IrAnalyze *ira, IrInstructionResolveResult *instruction) { + ZigType *implicit_elem_type = ir_resolve_type(ira, instruction->ty->child); + if (type_is_invalid(implicit_elem_type)) + return ira->codegen->invalid_instruction; + 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; + + ZigFn *fn = exec_fn_entry(ira->new_irb.exec); + if (fn != nullptr && fn->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync && + instruction->result_loc->id == ResultLocIdReturn) + { + result_loc = ir_resolve_result(ira, &instruction->base, no_result_loc(), + implicit_elem_type, nullptr, false, true); + if (result_loc != nullptr && + (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) + { + return result_loc; + } + result_loc->value.special = ConstValSpecialRuntime; + return result_loc; + } + + 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) { + result_loc->written = false; + result_loc->resolved_loc = nullptr; + result_loc->gen_instruction = nullptr; + result_loc->implicit_elem_type = nullptr; + switch (result_loc->id) { + case ResultLocIdInvalid: + zig_unreachable(); + case ResultLocIdPeerParent: { + ResultLocPeerParent *peer_parent = reinterpret_cast<ResultLocPeerParent *>(result_loc); + peer_parent->skipped = false; + peer_parent->done_resuming = false; + peer_parent->resolved_type = nullptr; + for (size_t i = 0; i < peer_parent->peers.length; i += 1) { + ir_reset_result(&peer_parent->peers.at(i)->base); + } + break; + } + case ResultLocIdVar: { + IrInstructionAllocaSrc *alloca_src = + reinterpret_cast<IrInstructionAllocaSrc *>(result_loc->source_instruction); + alloca_src->base.child = nullptr; + break; + } + case ResultLocIdPeer: + case ResultLocIdNone: + 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) { @@ -14202,7 +15597,7 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCall *c 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; } @@ -14227,10 +15622,15 @@ 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); - result->value.type = async_return_type; - return result; + 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, result_loc, + async_return_type); } static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, @@ -14253,7 +15653,7 @@ static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node casted_arg = arg; } - ConstExprValue *arg_val = ir_resolve_const(ira, casted_arg, UndefBad); + ConstExprValue *arg_val = ir_resolve_const(ira, casted_arg, UndefOk); if (!arg_val) return false; @@ -14309,7 +15709,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; } @@ -14480,7 +15880,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) @@ -14494,18 +15896,24 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source // ConstPtrMutComptimeVar, thus defeating the logic below. 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) { + if (ptr->value.data.x_ptr.mut == ConstPtrMutComptimeVar && + !ira->new_irb.current_basic_block->must_be_comptime_source_instr) + { ira->new_irb.current_basic_block->must_be_comptime_source_instr = source_instr; } 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; + } } } @@ -14534,7 +15942,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) { @@ -14637,7 +16045,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call 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; } @@ -14796,7 +16204,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call 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; } @@ -14840,7 +16248,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call 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; @@ -14889,7 +16297,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr); IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&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); @@ -14971,6 +16379,19 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call } FnTypeId *impl_fn_type_id = &impl_fn->type_entry->data.fn.fn_type_id; + 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, true); + if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || + instr_is_unreachable(result_loc))) + { + return result_loc; + } + } else { + result_loc = nullptr; + } + if (fn_type_can_fail(impl_fn_type_id)) { parent_fn_entry->calls_or_awaits_errorable_fn = true; } @@ -14979,18 +16400,14 @@ 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); - new_call_instruction->value.type = impl_fn_type_id->return_type; - - ir_add_alloca(ira, new_call_instruction, 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, + impl_fn_type_id->return_type); return ir_finish_anal(ira, new_call_instruction); } @@ -15018,7 +16435,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *call { 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; } @@ -15075,7 +16492,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); } @@ -15085,15 +16501,24 @@ 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); - new_call_instruction->value.type = return_type; - ir_add_alloca(ira, new_call_instruction, return_type); + 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, true); + if (result_loc != nullptr && (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc))) { + return result_loc; + } + } else { + result_loc = nullptr; + } + + 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); 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; @@ -15117,7 +16542,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); @@ -15170,7 +16596,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; @@ -15419,7 +16845,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; @@ -15438,6 +16864,19 @@ static IrInstruction *ir_analyze_instruction_un_op(IrAnalyze *ira, IrInstruction zig_unreachable(); } +static void ir_push_resume(IrAnalyze *ira, IrSuspendPosition pos) { + IrBasicBlock *old_bb = ira->old_irb.exec->basic_block_list.at(pos.basic_block_index); + if (old_bb->in_resume_stack) return; + ira->resume_stack.append(pos); + old_bb->in_resume_stack = true; +} + +static void ir_push_resume_block(IrAnalyze *ira, IrBasicBlock *old_bb) { + if (ira->resume_stack.length != 0) { + ir_push_resume(ira, {old_bb->index, 0}); + } +} + static IrInstruction *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr *br_instruction) { IrBasicBlock *old_dest_block = br_instruction->dest_block; @@ -15445,13 +16884,15 @@ static IrInstruction *ir_analyze_instruction_br(IrAnalyze *ira, IrInstructionBr if (!ir_resolve_comptime(ira, br_instruction->is_comptime->child, &is_comptime)) return ir_unreach_error(ira); - if (is_comptime || old_dest_block->ref_count == 1) + if (is_comptime || (old_dest_block->ref_count == 1 && old_dest_block->suspend_instruction_ref == nullptr)) return ir_inline_bb(ira, &br_instruction->base, old_dest_block); IrBasicBlock *new_bb = ir_get_new_bb_runtime(ira, old_dest_block, &br_instruction->base); if (new_bb == nullptr) return ir_unreach_error(ira); + ir_push_resume_block(ira, old_dest_block); + IrInstruction *result = ir_build_br(&ira->new_irb, br_instruction->base.scope, br_instruction->base.source_node, new_bb, nullptr); result->value.type = ira->codegen->builtin_types.entry_unreachable; @@ -15480,13 +16921,15 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi IrBasicBlock *old_dest_block = cond_is_true ? cond_br_instruction->then_block : cond_br_instruction->else_block; - if (is_comptime || old_dest_block->ref_count == 1) + if (is_comptime || (old_dest_block->ref_count == 1 && old_dest_block->suspend_instruction_ref == nullptr)) return ir_inline_bb(ira, &cond_br_instruction->base, old_dest_block); IrBasicBlock *new_dest_block = ir_get_new_bb_runtime(ira, old_dest_block, &cond_br_instruction->base); if (new_dest_block == nullptr) return ir_unreach_error(ira); + ir_push_resume_block(ira, old_dest_block); + IrInstruction *result = ir_build_br(&ira->new_irb, cond_br_instruction->base.scope, cond_br_instruction->base.source_node, new_dest_block, nullptr); result->value.type = ira->codegen->builtin_types.entry_unreachable; @@ -15502,6 +16945,9 @@ static IrInstruction *ir_analyze_instruction_cond_br(IrAnalyze *ira, IrInstructi if (new_else_block == nullptr) return ir_unreach_error(ira); + ir_push_resume_block(ira, cond_br_instruction->else_block); + ir_push_resume_block(ira, cond_br_instruction->then_block); + IrInstruction *result = ir_build_cond_br(&ira->new_irb, cond_br_instruction->base.scope, cond_br_instruction->base.source_node, casted_condition, new_then_block, new_else_block, nullptr); @@ -15540,6 +16986,80 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh zig_unreachable(); } + ResultLocPeerParent *peer_parent = phi_instruction->peer_parent; + if (peer_parent != nullptr && !peer_parent->skipped && !peer_parent->done_resuming && + peer_parent->peers.length >= 2) + { + if (peer_parent->resolved_type == nullptr) { + IrInstruction **instructions = allocate<IrInstruction *>(peer_parent->peers.length); + for (size_t i = 0; i < peer_parent->peers.length; i += 1) { + ResultLocPeer *this_peer = peer_parent->peers.at(i); + + IrInstruction *gen_instruction = this_peer->base.gen_instruction; + if (gen_instruction == nullptr) { + // unreachable instructions will cause implicit_elem_type to be null + if (this_peer->base.implicit_elem_type == nullptr) { + instructions[i] = ir_const_unreachable(ira, this_peer->base.source_instruction); + } else { + instructions[i] = ir_const(ira, this_peer->base.source_instruction, + this_peer->base.implicit_elem_type); + instructions[i]->value.special = ConstValSpecialRuntime; + } + } else { + instructions[i] = gen_instruction; + } + + } + ZigType *expected_type = ir_result_loc_expected_type(ira, &phi_instruction->base, peer_parent->parent); + peer_parent->resolved_type = ir_resolve_peer_types(ira, + peer_parent->base.source_instruction->source_node, expected_type, instructions, + peer_parent->peers.length); + + // 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, false, false); + if (parent_result_loc != nullptr && + (type_is_invalid(parent_result_loc->value.type) || instr_is_unreachable(parent_result_loc))) + { + 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<IrInstruction *> 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; + ira_suspend(ira, &phi_instruction->base, nullptr, &suspend_pos); + ir_push_resume(ira, suspend_pos); + + for (size_t i = 0; i < peer_parent->peers.length; i += 1) { + ResultLocPeer *opposite_peer = peer_parent->peers.at(peer_parent->peers.length - i - 1); + if (opposite_peer->base.implicit_elem_type != nullptr && + opposite_peer->base.implicit_elem_type->id != ZigTypeIdUnreachable) + { + ir_push_resume(ira, opposite_peer->suspend_pos); + } + } + + peer_parent->done_resuming = true; + return ira_resume(ira); + } + ZigList<IrBasicBlock*> new_incoming_blocks = {0}; ZigList<IrInstruction*> new_incoming_values = {0}; @@ -15609,10 +17129,11 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh for (size_t i = 0; i < new_incoming_values.length; i += 1) { IrInstruction *new_value = new_incoming_values.at(i); IrBasicBlock *predecessor = new_incoming_blocks.at(i); + ir_assert(predecessor->instruction_list.length != 0, &phi_instruction->base); IrInstruction *branch_instruction = predecessor->instruction_list.pop(); ir_set_cursor_at_end(&ira->new_irb, predecessor); IrInstruction *casted_value = ir_implicit_cast(ira, new_value, resolved_type); - if (casted_value == ira->codegen->invalid_instruction) { + if (type_is_invalid(casted_value->value.type)) { return ira->codegen->invalid_instruction; } new_incoming_values.items[i] = casted_value; @@ -15628,7 +17149,7 @@ static IrInstruction *ir_analyze_instruction_phi(IrAnalyze *ira, IrInstructionPh IrInstruction *result = ir_build_phi(&ira->new_irb, phi_instruction->base.scope, phi_instruction->base.source_node, - new_incoming_blocks.length, new_incoming_blocks.items, new_incoming_values.items); + new_incoming_blocks.length, new_incoming_blocks.items, new_incoming_values.items, nullptr); result->value.type = resolved_type; if (all_stack_ptrs) { @@ -15846,6 +17367,52 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct if (array_ptr_val == nullptr) return ira->codegen->invalid_instruction; + if (array_ptr_val->special == ConstValSpecialUndef && elem_ptr_instruction->init_array_type != nullptr) { + if (array_type->id == ZigTypeIdArray) { + array_ptr_val->data.x_array.special = ConstArraySpecialNone; + array_ptr_val->data.x_array.data.s_none.elements = create_const_vals(array_type->data.array.len); + array_ptr_val->special = ConstValSpecialStatic; + for (size_t i = 0; i < array_type->data.array.len; i += 1) { + ConstExprValue *elem_val = &array_ptr_val->data.x_array.data.s_none.elements[i]; + elem_val->special = ConstValSpecialUndef; + elem_val->type = array_type->data.array.child_type; + elem_val->parent.id = ConstParentIdArray; + elem_val->parent.data.p_array.array_val = array_ptr_val; + elem_val->parent.data.p_array.elem_index = i; + } + } else if (is_slice(array_type)) { + ZigType *actual_array_type = ir_resolve_type(ira, elem_ptr_instruction->init_array_type->child); + if (type_is_invalid(actual_array_type)) + return ira->codegen->invalid_instruction; + if (actual_array_type->id != ZigTypeIdArray) { + ir_add_error(ira, elem_ptr_instruction->init_array_type, + buf_sprintf("expected array type or [_], found slice")); + return ira->codegen->invalid_instruction; + } + + ConstExprValue *array_init_val = create_const_vals(1); + array_init_val->special = ConstValSpecialStatic; + array_init_val->type = actual_array_type; + array_init_val->data.x_array.special = ConstArraySpecialNone; + array_init_val->data.x_array.data.s_none.elements = create_const_vals(actual_array_type->data.array.len); + array_init_val->special = ConstValSpecialStatic; + for (size_t i = 0; i < actual_array_type->data.array.len; i += 1) { + ConstExprValue *elem_val = &array_init_val->data.x_array.data.s_none.elements[i]; + elem_val->special = ConstValSpecialUndef; + elem_val->type = actual_array_type->data.array.child_type; + elem_val->parent.id = ConstParentIdArray; + elem_val->parent.data.p_array.array_val = array_init_val; + elem_val->parent.data.p_array.elem_index = i; + } + + init_const_slice(ira->codegen, array_ptr_val, array_init_val, 0, actual_array_type->data.array.len, + false); + array_ptr_val->data.x_struct.fields[slice_ptr_index].data.x_ptr.mut = ConstPtrMutInfer; + } else { + zig_unreachable(); + } + } + if (array_ptr_val->special != ConstValSpecialRuntime && (array_type->id != ZigTypeIdPointer || array_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr)) @@ -15911,8 +17478,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } else if (is_slice(array_type)) { ConstExprValue *ptr_field = &array_ptr_val->data.x_struct.fields[slice_ptr_index]; if (ptr_field->data.x_ptr.special == ConstPtrSpecialHardCodedAddr) { - IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, - array_ptr, casted_elem_index, false, elem_ptr_instruction->ptr_len); + IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, + elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, false, + elem_ptr_instruction->ptr_len, nullptr); result->value.type = return_type; return result; } @@ -15965,7 +17533,16 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } return result; } else if (array_type->id == ZigTypeIdArray) { - IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type); + IrInstruction *result; + if (orig_array_ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { + result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, + elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, + false, elem_ptr_instruction->ptr_len, elem_ptr_instruction->init_array_type); + result->value.type = return_type; + result->value.special = ConstValSpecialStatic; + } else { + result = ir_const(ira, &elem_ptr_instruction->base, return_type); + } ConstExprValue *out_val = &result->value; out_val->data.x_ptr.special = ConstPtrSpecialBaseArray; out_val->data.x_ptr.mut = orig_array_ptr_val->data.x_ptr.mut; @@ -15977,7 +17554,6 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } } } - } else { // runtime known element index switch (type_requires_comptime(ira->codegen, return_type)) { @@ -16003,8 +17579,9 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct } } - IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, elem_ptr_instruction->base.source_node, - array_ptr, casted_elem_index, safety_check_on, elem_ptr_instruction->ptr_len); + IrInstruction *result = ir_build_elem_ptr(&ira->new_irb, elem_ptr_instruction->base.scope, + elem_ptr_instruction->base.source_node, array_ptr, casted_elem_index, safety_check_on, + elem_ptr_instruction->ptr_len, elem_ptr_instruction->init_array_type); result->value.type = return_type; return result; } @@ -16049,8 +17626,80 @@ 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; + 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; + 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 = 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; + } + } + 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) + IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type, bool initializing) { Error err; @@ -16059,81 +17708,55 @@ 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); } - } else if (bare_type->id == ZigTypeIdEnum) { + } + + if (bare_type->id == ZigTypeIdEnum) { return ir_analyze_container_member_access_inner(ira, bare_type, field_name, source_instr, container_ptr, container_type); - } else if (bare_type->id == ZigTypeIdUnion) { + } + + 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)) { - ConstExprValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); - if (!ptr_val) + if (field == nullptr) { + return ir_analyze_container_member_access_inner(ira, bare_type, field_name, + source_instr, container_ptr, container_type); + } + ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, + is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); + 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 *union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); + if (union_val == nullptr) + return ira->codegen->invalid_instruction; + if (type_is_invalid(union_val->type)) return ira->codegen->invalid_instruction; - if (ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { - ConstExprValue *union_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); - if (union_val == nullptr) - return ira->codegen->invalid_instruction; - if (type_is_invalid(union_val->type)) - return ira->codegen->invalid_instruction; + if (initializing) { + ConstExprValue *payload_val = create_const_vals(1); + payload_val->special = ConstValSpecialUndef; + payload_val->type = field->type_entry; + 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); + union_val->data.x_union.payload = payload_val; + } else { TypeUnionField *actual_field = find_union_field_by_tag(bare_type, &union_val->data.x_union.tag); if (actual_field == nullptr) zig_unreachable(); @@ -16144,33 +17767,35 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ buf_ptr(actual_field->name))); return ira->codegen->invalid_instruction; } + } - ConstExprValue *payload_val = union_val->data.x_union.payload; + ConstExprValue *payload_val = union_val->data.x_union.payload; - ZigType *field_type = field->type_entry; - ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, - is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); - IrInstruction *result = ir_const(ira, source_instr, ptr_type); - ConstExprValue *const_val = &result->value; - const_val->data.x_ptr.special = ConstPtrSpecialRef; - const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut; - const_val->data.x_ptr.data.ref.pointee = payload_val; - return result; + 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, true, initializing); + 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 = ConstPtrSpecialRef; + const_val->data.x_ptr.mut = container_ptr->value.data.x_ptr.mut; + const_val->data.x_ptr.data.ref.pointee = payload_val; + return result; } - - IrInstruction *result = ir_build_union_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, 0, 0, 0, false); - return result; - } else { - return ir_analyze_container_member_access_inner(ira, bare_type, field_name, - source_instr, container_ptr, container_type); } - } else { - zig_unreachable(); + + IrInstruction *result = ir_build_union_field_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, container_ptr, field, true, initializing); + result->value.type = ptr_type; + return result; } + + zig_unreachable(); } static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node) { @@ -16208,6 +17833,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); @@ -16222,6 +17852,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); } @@ -16237,23 +17870,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(); @@ -16295,14 +17918,14 @@ 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 *result = ir_analyze_container_field_ptr(ira, field_name, &field_ptr_instruction->base, container_child, bare_type); + 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 { - 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)) { + } else if (is_array_ref(container_type) && !field_ptr_instruction->initializing) { if (buf_eql_str(field_name, "len")) { ConstExprValue *len_val = create_const_vals(1); if (container_type->id == ZigTypeIdPointer) { @@ -16617,6 +18240,10 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc buf_sprintf("type '%s' does not support field access", buf_ptr(&child_type->name))); return ira->codegen->invalid_instruction; } + } else if (field_ptr_instruction->initializing) { + ir_add_error(ira, &field_ptr_instruction->base, + buf_sprintf("type '%s' does not support struct initialization syntax", buf_ptr(&container_type->name))); + return ira->codegen->invalid_instruction; } else { ir_add_error_node(ira, field_ptr_instruction->base.source_node, buf_sprintf("type '%s' does not support field access", buf_ptr(&container_type->name))); @@ -16640,7 +18267,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) { @@ -16651,64 +18278,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 @@ -17138,7 +18707,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); @@ -17168,7 +18737,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; } @@ -17183,34 +18752,84 @@ static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstr ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, 0, 0, 0, false); + bool same_comptime_repr = types_have_same_zig_comptime_repr(type_entry, child_type); + if (instr_is_comptime(base_ptr)) { - ConstExprValue *val = ir_resolve_const(ira, base_ptr, UndefBad); - if (!val) + ConstExprValue *ptr_val = ir_resolve_const(ira, base_ptr, UndefBad); + if (!ptr_val) return ira->codegen->invalid_instruction; - if (val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { - ConstExprValue *maybe_val = const_ptr_pointee(ira, ira->codegen, val, source_instr->source_node); - if (maybe_val == nullptr) + if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { + ConstExprValue *optional_val = const_ptr_pointee(ira, ira->codegen, ptr_val, source_instr->source_node); + if (optional_val == nullptr) return ira->codegen->invalid_instruction; - if (optional_value_is_null(maybe_val)) { + if (initializing && optional_val->special == ConstValSpecialUndef) { + switch (type_has_one_possible_value(ira->codegen, child_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueNo: + if (!same_comptime_repr) { + ConstExprValue *payload_val = create_const_vals(1); + payload_val->type = child_type; + payload_val->special = ConstValSpecialUndef; + payload_val->parent.id = ConstParentIdOptionalPayload; + payload_val->parent.data.p_optional_payload.optional_val = optional_val; + + optional_val->data.x_optional = payload_val; + optional_val->special = ConstValSpecialStatic; + } + break; + case OnePossibleValueYes: { + ConstExprValue *pointee = create_const_vals(1); + pointee->special = ConstValSpecialStatic; + pointee->type = child_type; + pointee->parent.id = ConstParentIdOptionalPayload; + pointee->parent.data.p_optional_payload.optional_val = optional_val; + + optional_val->special = ConstValSpecialStatic; + optional_val->data.x_optional = pointee; + break; + } + } + } else if (optional_value_is_null(optional_val)) { ir_add_error(ira, source_instr, buf_sprintf("unable to unwrap null")); return ira->codegen->invalid_instruction; } - IrInstruction *result = ir_const(ira, source_instr, result_type); - ConstExprValue *out_val = &result->value; - out_val->data.x_ptr.special = ConstPtrSpecialRef; - out_val->data.x_ptr.mut = val->data.x_ptr.mut; - if (types_have_same_zig_comptime_repr(type_entry, child_type)) { - out_val->data.x_ptr.data.ref.pointee = maybe_val; + + IrInstruction *result; + if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { + result = ir_build_optional_unwrap_ptr(&ira->new_irb, source_instr->scope, + source_instr->source_node, base_ptr, false, initializing); + result->value.type = result_type; + result->value.special = ConstValSpecialStatic; } else { - out_val->data.x_ptr.data.ref.pointee = maybe_val->data.x_optional; + result = ir_const(ira, source_instr, result_type); + } + ConstExprValue *result_val = &result->value; + result_val->data.x_ptr.special = ConstPtrSpecialRef; + result_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; + switch (type_has_one_possible_value(ira->codegen, child_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueNo: + if (same_comptime_repr) { + result_val->data.x_ptr.data.ref.pointee = optional_val; + } else { + assert(optional_val->data.x_optional != nullptr); + result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional; + } + break; + case OnePossibleValueYes: + assert(optional_val->data.x_optional != nullptr); + result_val->data.x_ptr.data.ref.pointee = optional_val->data.x_optional; + break; } return result; } } 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; } @@ -17222,7 +18841,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) { @@ -17523,7 +19143,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; } @@ -17553,7 +19173,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, @@ -17577,7 +19197,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; } @@ -17611,24 +19231,53 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru ZigType *enum_type = target_type->data.unionation.tag_type; assert(enum_type != nullptr); assert(enum_type->id == ZigTypeIdEnum); + assert(instruction->prongs_len > 0); - if (instruction->prongs_len != 1) { - return target_value_ptr; - } - - IrInstruction *prong_value = instruction->prongs_ptr[0]->child; - if (type_is_invalid(prong_value->value.type)) + IrInstruction *first_prong_value = instruction->prongs_ptr[0]->child; + if (type_is_invalid(first_prong_value->value.type)) return ira->codegen->invalid_instruction; - IrInstruction *casted_prong_value = ir_implicit_cast(ira, prong_value, enum_type); - if (type_is_invalid(casted_prong_value->value.type)) + IrInstruction *first_casted_prong_value = ir_implicit_cast(ira, first_prong_value, enum_type); + if (type_is_invalid(first_casted_prong_value->value.type)) return ira->codegen->invalid_instruction; - ConstExprValue *prong_val = ir_resolve_const(ira, casted_prong_value, UndefBad); - if (!prong_val) + ConstExprValue *first_prong_val = ir_resolve_const(ira, first_casted_prong_value, UndefBad); + if (first_prong_val == nullptr) return ira->codegen->invalid_instruction; - TypeUnionField *field = find_union_field_by_tag(target_type, &prong_val->data.x_enum_tag); + TypeUnionField *first_field = find_union_field_by_tag(target_type, &first_prong_val->data.x_enum_tag); + + ErrorMsg *invalid_payload_msg = nullptr; + for (size_t prong_i = 1; prong_i < instruction->prongs_len; prong_i += 1) { + IrInstruction *this_prong_inst = instruction->prongs_ptr[prong_i]->child; + if (type_is_invalid(this_prong_inst->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *this_casted_prong_value = ir_implicit_cast(ira, this_prong_inst, enum_type); + if (type_is_invalid(this_casted_prong_value->value.type)) + return ira->codegen->invalid_instruction; + + ConstExprValue *this_prong = ir_resolve_const(ira, this_casted_prong_value, UndefBad); + if (this_prong == nullptr) + return ira->codegen->invalid_instruction; + + TypeUnionField *payload_field = find_union_field_by_tag(target_type, &this_prong->data.x_enum_tag); + ZigType *payload_type = payload_field->type_entry; + if (first_field->type_entry != payload_type) { + if (invalid_payload_msg == nullptr) { + invalid_payload_msg = ir_add_error(ira, &instruction->base, + buf_sprintf("capture group with incompatible types")); + add_error_note(ira->codegen, invalid_payload_msg, first_prong_value->source_node, + buf_sprintf("type '%s' here", buf_ptr(&first_field->type_entry->name))); + } + add_error_note(ira->codegen, invalid_payload_msg, this_prong_inst->source_node, + buf_sprintf("type '%s' here", buf_ptr(&payload_field->type_entry->name))); + } + } + + if (invalid_payload_msg != nullptr) { + return ira->codegen->invalid_instruction; + } if (instr_is_comptime(target_value_ptr)) { ConstExprValue *target_val_ptr = ir_resolve_const(ira, target_value_ptr, UndefBad); @@ -17640,7 +19289,7 @@ static IrInstruction *ir_analyze_instruction_switch_var(IrAnalyze *ira, IrInstru return ira->codegen->invalid_instruction; IrInstruction *result = ir_const(ira, &instruction->base, - get_pointer_to_type(ira->codegen, field->type_entry, + get_pointer_to_type(ira->codegen, first_field->type_entry, target_val_ptr->type->data.pointer.is_const)); ConstExprValue *out_val = &result->value; out_val->data.x_ptr.special = ConstPtrSpecialRef; @@ -17650,8 +19299,8 @@ 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); - result->value.type = get_pointer_to_type(ira->codegen, field->type_entry, + instruction->base.scope, instruction->base.source_node, target_value_ptr, first_field, false, false); + result->value.type = get_pointer_to_type(ira->codegen, first_field->type_entry, target_value_ptr->value.type->data.pointer.is_const); return result; } else if (target_type->id == ZigTypeIdErrorSet) { @@ -17859,77 +19508,67 @@ static IrInstruction *ir_analyze_instruction_ref(IrAnalyze *ira, IrInstructionRe return ir_get_ref(ira, &ref_instruction->base, value, ref_instruction->is_const, ref_instruction->is_volatile); } -static IrInstruction *ir_analyze_container_init_fields_union(IrAnalyze *ira, IrInstruction *instruction, - ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) +static IrInstruction *ir_analyze_union_init(IrAnalyze *ira, IrInstruction *source_instruction, + AstNode *field_source_node, ZigType *union_type, Buf *field_name, IrInstruction *field_result_loc, + IrInstruction *result_loc) { Error err; - assert(container_type->id == ZigTypeIdUnion); - - if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) - return ira->codegen->invalid_instruction; - - if (instr_field_count != 1) { - ir_add_error(ira, instruction, - buf_sprintf("union initialization expects exactly one field")); - return ira->codegen->invalid_instruction; - } + assert(union_type->id == ZigTypeIdUnion); - IrInstructionContainerInitFieldsField *field = &fields[0]; - IrInstruction *field_value = field->value->child; - if (type_is_invalid(field_value->value.type)) + if ((err = type_resolve(ira->codegen, union_type, ResolveStatusSizeKnown))) return ira->codegen->invalid_instruction; - TypeUnionField *type_field = find_union_type_field(container_type, field->name); - if (!type_field) { - ir_add_error_node(ira, field->source_node, + TypeUnionField *type_field = find_union_type_field(union_type, field_name); + if (type_field == nullptr) { + ir_add_error_node(ira, field_source_node, buf_sprintf("no member named '%s' in union '%s'", - buf_ptr(field->name), buf_ptr(&container_type->name))); + buf_ptr(field_name), buf_ptr(&union_type->name))); return ira->codegen->invalid_instruction; } 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; - - if ((err = type_resolve(ira->codegen, casted_field_value->value.type, ResolveStatusZeroBitsKnown))) - return ira->codegen->invalid_instruction; - - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->scope) - || type_requires_comptime(ira->codegen, container_type) == ReqCompTimeYes; - if (is_comptime || casted_field_value->value.special != ConstValSpecialRuntime || - !type_has_bits(casted_field_value->value.type)) - { - ConstExprValue *field_val = ir_resolve_const(ira, casted_field_value, UndefOk); - if (!field_val) - return ira->codegen->invalid_instruction; + if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) { + if (instr_is_comptime(field_result_loc) && + field_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) + { + // nothing + } else { + result_loc->value.special = ConstValSpecialRuntime; + } + } - IrInstruction *result = ir_const(ira, instruction, container_type); - ConstExprValue *out_val = &result->value; - out_val->data.x_union.payload = field_val; - out_val->data.x_union.tag = type_field->enum_field->value; - out_val->parent.id = ConstParentIdUnion; - out_val->parent.data.p_union.union_val = out_val; + bool is_comptime = ir_should_inline(ira->new_irb.exec, source_instruction->scope) + || type_requires_comptime(ira->codegen, union_type) == ReqCompTimeYes; - return result; + IrInstruction *result = ir_get_deref(ira, source_instruction, result_loc, nullptr); + if (is_comptime && !instr_is_comptime(result)) { + ir_add_error(ira, field_result_loc, + buf_sprintf("unable to evaluate constant expression")); + return ira->codegen->invalid_instruction; } - - 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); - return new_instruction; + return result; } static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruction *instruction, - ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields) + ZigType *container_type, size_t instr_field_count, IrInstructionContainerInitFieldsField *fields, + 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); + if (instr_field_count != 1) { + ir_add_error(ira, instruction, + buf_sprintf("union initialization expects exactly one field")); + return ira->codegen->invalid_instruction; + } + IrInstructionContainerInitFieldsField *field = &fields[0]; + IrInstruction *field_result_loc = field->result_loc->child; + if (type_is_invalid(field_result_loc->value.type)) + return ira->codegen->invalid_instruction; + + return ir_analyze_union_init(ira, instruction, field->source_node, container_type, field->name, + field_result_loc, result_loc); } if (container_type->id != ZigTypeIdStruct || is_slice(container_type)) { ir_add_error(ira, instruction, @@ -17946,22 +19585,28 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc IrInstruction *first_non_const_instruction = nullptr; AstNode **field_assign_nodes = allocate<AstNode *>(actual_field_count); - - IrInstructionStructInitField *new_fields = allocate<IrInstructionStructInitField>(actual_field_count); + ZigList<IrInstruction *> 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<ConstGlobalRefs>(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); @@ -17975,10 +19620,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) { @@ -17988,26 +19629,18 @@ 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); - 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]; @@ -18033,182 +19666,177 @@ 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); + 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.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; } - 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; + return result; } static IrInstruction *ir_analyze_instruction_container_init_list(IrAnalyze *ira, IrInstructionContainerInitList *instruction) { - Error err; + ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); + if (type_is_invalid(container_type)) + return ira->codegen->invalid_instruction; size_t elem_count = instruction->item_count; - 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); - } - if (is_slice(container_type)) { - ir_add_error(ira, &instruction->base, + ir_add_error(ira, instruction->container_type, 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); - } 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; - if (container_type->id == ZigTypeIdArray) { - child_type = container_type->data.array.child_type; - if (container_type->data.array.len != elem_count) { - ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); - - ir_add_error(ira, &instruction->base, - buf_sprintf("expected %s literal, found %s literal", - buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); - return ira->codegen->invalid_instruction; - } - } else { - ZigType *pointer_type = container_type->data.structure.fields[slice_ptr_index].type_entry; - assert(pointer_type->id == ZigTypeIdPointer); - child_type = pointer_type->data.pointer.child_type; - } + } - if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) { + if (container_type->id == ZigTypeIdVoid) { + if (elem_count != 0) { + ir_add_error_node(ira, instruction->base.source_node, + buf_sprintf("void expression expects no arguments")); return ira->codegen->invalid_instruction; } + return ir_const_void(ira, &instruction->base); + } - ZigType *fixed_size_array_type = get_array_type(ira->codegen, child_type, elem_count); + if (container_type->id == ZigTypeIdStruct && elem_count == 0) { + 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); + } - ConstExprValue const_val = {}; - const_val.special = ConstValSpecialStatic; - const_val.type = fixed_size_array_type; - // const_val.global_refs = allocate<ConstGlobalRefs>(1); - const_val.data.x_array.data.s_none.elements = create_const_vals(elem_count); + if (container_type->id != ZigTypeIdArray) { + ir_add_error_node(ira, instruction->base.source_node, + buf_sprintf("type '%s' does not support array initialization", + buf_ptr(&container_type->name))); + return ira->codegen->invalid_instruction; + } - bool is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); + 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; + ir_assert(result_loc->value.type->id == ZigTypeIdPointer, &instruction->base); - IrInstruction **new_items = allocate<IrInstruction *>(elem_count); + ZigType *child_type = container_type->data.array.child_type; + if (container_type->data.array.len != elem_count) { + ZigType *literal_type = get_array_type(ira->codegen, child_type, elem_count); - IrInstruction *first_non_const_instruction = nullptr; + ir_add_error(ira, &instruction->base, + buf_sprintf("expected %s literal, found %s literal", + buf_ptr(&container_type->name), buf_ptr(&literal_type->name))); + return ira->codegen->invalid_instruction; + } - for (size_t i = 0; i < elem_count; i += 1) { - IrInstruction *arg_value = instruction->items[i]->child; - if (type_is_invalid(arg_value->value.type)) - return ira->codegen->invalid_instruction; + switch (type_has_one_possible_value(ira->codegen, container_type)) { + case OnePossibleValueInvalid: + return ira->codegen->invalid_instruction; + case OnePossibleValueYes: + return ir_const(ira, &instruction->base, container_type); + case OnePossibleValueNo: + break; + } - IrInstruction *casted_arg = ir_implicit_cast(ira, arg_value, child_type); - if (casted_arg == ira->codegen->invalid_instruction) - return ira->codegen->invalid_instruction; + bool is_comptime; + switch (type_requires_comptime(ira->codegen, container_type)) { + case ReqCompTimeInvalid: + return ira->codegen->invalid_instruction; + case ReqCompTimeNo: + is_comptime = ir_should_inline(ira->new_irb.exec, instruction->base.scope); + break; + case ReqCompTimeYes: + is_comptime = true; + break; + } - new_items[i] = casted_arg; + IrInstruction *first_non_const_instruction = nullptr; - if (const_val.special == ConstValSpecialStatic) { - if (is_comptime || casted_arg->value.special != ConstValSpecialRuntime) { - ConstExprValue *elem_val = ir_resolve_const(ira, casted_arg, UndefBad); - if (!elem_val) - return ira->codegen->invalid_instruction; + // The Result Location Mechanism has already emitted runtime instructions to + // initialize runtime elements and has omitted instructions for the comptime + // elements. However it is only now that we find out whether the array initialization + // can be a comptime value. So we must clean up the situation. If it turns out + // array initialization can be a comptime value, overwrite ConstPtrMutInfer with + // ConstPtrMutComptimeConst. Otherwise, emit instructions to runtime-initialize the + // elements that have comptime-known values. + ZigList<IrInstruction *> const_ptrs = {}; + + for (size_t i = 0; i < elem_count; i += 1) { + IrInstruction *elem_result_loc = instruction->elem_result_loc_list[i]->child; + if (type_is_invalid(elem_result_loc->value.type)) + return ira->codegen->invalid_instruction; - copy_const_val(&const_val.data.x_array.data.s_none.elements[i], elem_val, true); - } else { - first_non_const_instruction = casted_arg; - const_val.special = ConstValSpecialRuntime; - } - } + assert(elem_result_loc->value.type->id == ZigTypeIdPointer); + + if (instr_is_comptime(elem_result_loc) && + elem_result_loc->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) + { + const_ptrs.append(elem_result_loc); + } else { + first_non_const_instruction = elem_result_loc; } + } - if (const_val.special == ConstValSpecialStatic) { - IrInstruction *result = ir_const(ira, &instruction->base, nullptr); - ConstExprValue *out_val = &result->value; - copy_const_val(out_val, &const_val, false); - result->value.type = fixed_size_array_type; - for (size_t i = 0; i < elem_count; i += 1) { - ConstExprValue *elem_val = &out_val->data.x_array.data.s_none.elements[i]; - ConstParent *parent = get_const_val_parent(ira->codegen, elem_val); - if (parent != nullptr) { - parent->id = ConstParentIdArray; - parent->data.p_array.array_val = out_val; - parent->data.p_array.elem_index = i; - } + if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) { + if (const_ptrs.length != elem_count) { + result_loc->value.special = ConstValSpecialRuntime; + for (size_t i = 0; i < const_ptrs.length; i += 1) { + IrInstruction *elem_result_loc = const_ptrs.at(i); + assert(elem_result_loc->value.special == ConstValSpecialStatic); + IrInstruction *deref = ir_get_deref(ira, elem_result_loc, elem_result_loc, nullptr); + elem_result_loc->value.special = ConstValSpecialRuntime; + ir_analyze_store_ptr(ira, elem_result_loc, elem_result_loc, deref); } - return result; } + } - if (is_comptime) { - ir_add_error_node(ira, first_non_const_instruction->source_node, - buf_sprintf("unable to evaluate constant expression")); - return ira->codegen->invalid_instruction; - } + IrInstruction *result = ir_get_deref(ira, &instruction->base, result_loc, nullptr); + if (instr_is_comptime(result)) + return result; - IrInstruction *new_instruction = ir_build_container_init_list(&ira->new_irb, - instruction->base.scope, instruction->base.source_node, - nullptr, nullptr, elem_count, new_items); - new_instruction->value.type = fixed_size_array_type; - ir_add_alloca(ira, new_instruction, fixed_size_array_type); - return new_instruction; - } else if (container_type->id == ZigTypeIdVoid) { - if (elem_count != 0) { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("void expression expects no arguments")); - return ira->codegen->invalid_instruction; - } - return ir_const_void(ira, &instruction->base); - } else { - ir_add_error_node(ira, instruction->base.source_node, - buf_sprintf("type '%s' does not support array initialization", - buf_ptr(&container_type->name))); + if (is_comptime) { + ir_add_error_node(ira, first_non_const_instruction->source_node, + buf_sprintf("unable to evaluate constant expression")); return ira->codegen->invalid_instruction; } + + ZigType *result_elem_type = result_loc->value.type->data.pointer.child_type; + if (is_slice(result_elem_type)) { + ErrorMsg *msg = ir_add_error(ira, &instruction->base, + buf_sprintf("runtime-initialized array cannot be casted to slice type '%s'", + buf_ptr(&result_elem_type->name))); + add_error_note(ira->codegen, msg, first_non_const_instruction->source_node, + buf_sprintf("this value is not comptime-known")); + return ira->codegen->invalid_instruction; + } + return result; } static IrInstruction *ir_analyze_instruction_container_init_fields(IrAnalyze *ira, @@ -18219,8 +19847,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->field_count, instruction->fields, result_loc); } static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira, @@ -18489,12 +20122,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; @@ -19613,7 +21240,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; @@ -19900,12 +21527,21 @@ 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, + 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, true, false); + if (type_is_invalid(result_loc->value.type) || instr_is_unreachable(result_loc)) { + return result_loc; + } + } else { + result_loc = nullptr; + } + + 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) { @@ -20043,7 +21679,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; } @@ -20151,6 +21787,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, true, false); + if (result_loc != nullptr && (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; @@ -20170,9 +21812,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) { @@ -20224,9 +21864,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, true, false); + 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) { @@ -20258,7 +21902,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) { @@ -20280,7 +21924,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) { @@ -20332,7 +21976,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) { @@ -20493,7 +22137,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); @@ -20563,7 +22207,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 && @@ -20661,7 +22305,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); @@ -20673,7 +22317,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; @@ -20962,12 +22606,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, true, false); + 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) { @@ -21107,6 +22752,34 @@ static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstr } } +static IrInstruction *ir_analyze_instruction_has_field(IrAnalyze *ira, IrInstructionHasField *instruction) { + Error err; + ZigType *container_type = ir_resolve_type(ira, instruction->container_type->child); + if (type_is_invalid(container_type)) + return ira->codegen->invalid_instruction; + + if ((err = type_resolve(ira->codegen, container_type, ResolveStatusZeroBitsKnown))) + return ira->codegen->invalid_instruction; + + Buf *field_name = ir_resolve_str(ira, instruction->field_name->child); + if (field_name == nullptr) + return ira->codegen->invalid_instruction; + + bool result; + if (container_type->id == ZigTypeIdStruct) { + result = find_struct_type_field(container_type, field_name) != nullptr; + } else if (container_type->id == ZigTypeIdEnum) { + result = find_enum_type_field(container_type, field_name) != nullptr; + } else if (container_type->id == ZigTypeIdUnion) { + result = find_union_type_field(container_type, field_name) != nullptr; + } else { + ir_add_error(ira, instruction->container_type, + buf_sprintf("type '%s' does not support @hasField", buf_ptr(&container_type->name))); + return ira->codegen->invalid_instruction; + } + return ir_const_bool(ira, &instruction->base, result); +} + static IrInstruction *ir_analyze_instruction_breakpoint(IrAnalyze *ira, IrInstructionBreakpoint *instruction) { IrInstruction *result = ir_build_breakpoint(&ira->new_irb, instruction->base.scope, instruction->base.source_node); @@ -21291,6 +22964,19 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr return result; } +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)) + { + return instruction->result_loc->resolved_loc; + } + return ir_get_ref(ira, &instruction->base, result, true, false); +} + static void ir_eval_mul_add(IrAnalyze *ira, IrInstructionMulAdd *source_instr, ZigType *float_type, ConstExprValue *op1, ConstExprValue *op2, ConstExprValue *op3, ConstExprValue *out_val) { if (float_type->id == ZigTypeIdComptimeFloat) { @@ -21322,11 +23008,11 @@ static IrInstruction *ir_analyze_instruction_mul_add(IrAnalyze *ira, IrInstructi IrInstruction *type_value = instruction->type_value->child; if (type_is_invalid(type_value->value.type)) return ira->codegen->invalid_instruction; - + ZigType *expr_type = ir_resolve_type(ira, type_value); if (type_is_invalid(expr_type)) return ira->codegen->invalid_instruction; - + // Only allow float types, and vectors of floats. ZigType *float_type = (expr_type->id == ZigTypeIdVector) ? expr_type->data.vector.elem_type : expr_type; if (float_type->id != ZigTypeIdFloat) { @@ -21410,15 +23096,17 @@ static IrInstruction *ir_analyze_instruction_mul_add(IrAnalyze *ira, IrInstructi 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_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) @@ -21430,21 +23118,20 @@ static IrInstruction *ir_analyze_instruction_test_err(IrAnalyze *ira, IrInstruct } } - 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); + 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); + } } - 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 { @@ -21452,10 +23139,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->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. @@ -21471,40 +23157,79 @@ static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, IrI return ira->codegen->invalid_instruction; } + ZigType *err_set_type = type_entry->data.error_union.err_set_type; + ZigType *result_type = get_pointer_to_type_extra(ira->codegen, err_set_type, + ptr_type->data.pointer.is_const, ptr_type->data.pointer.is_volatile, PtrLenSingle, + ptr_type->data.pointer.explicit_alignment, 0, 0, false); + 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); + if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar && + ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) + { + 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); - IrInstruction *result = ir_const(ira, &instruction->base, - type_entry->data.error_union.err_set_type); - result->value.data.x_err_set = err; - return result; + if (initializing && err_union_val->special == ConstValSpecialUndef) { + ConstExprValue *vals = create_const_vals(2); + ConstExprValue *err_set_val = &vals[0]; + ConstExprValue *payload_val = &vals[1]; + + err_set_val->special = ConstValSpecialUndef; + err_set_val->type = err_set_type; + err_set_val->parent.id = ConstParentIdErrUnionCode; + err_set_val->parent.data.p_err_union_code.err_union_val = err_union_val; + + payload_val->special = ConstValSpecialUndef; + payload_val->type = type_entry->data.error_union.payload_type; + payload_val->parent.id = ConstParentIdErrUnionPayload; + payload_val->parent.data.p_err_union_payload.err_union_val = err_union_val; + + err_union_val->special = ConstValSpecialStatic; + err_union_val->data.x_err_union.error_set = err_set_val; + err_union_val->data.x_err_union.payload = payload_val; + } + ir_assert(err_union_val->special != ConstValSpecialRuntime, source_instr); + + IrInstruction *result; + if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { + result = ir_build_unwrap_err_code(&ira->new_irb, source_instr->scope, + source_instr->source_node, base_ptr); + result->value.type = result_type; + result->value.special = ConstValSpecialStatic; + } else { + result = ir_const(ira, source_instr, result_type); } + ConstExprValue *const_val = &result->value; + const_val->data.x_ptr.special = ConstPtrSpecialBaseErrorUnionCode; + const_val->data.x_ptr.data.base_err_union_code.err_union_val = err_union_val; + const_val->data.x_ptr.mut = ptr_val->data.x_ptr.mut; + return result; } } 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; + source_instr->scope, source_instr->source_node, base_ptr); + result->value.type = result_type; return result; } -static IrInstruction *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira, - IrInstructionUnwrapErrPayload *instruction) +static IrInstruction *ir_analyze_instruction_unwrap_err_code(IrAnalyze *ira, + IrInstructionUnwrapErrCode *instruction) { - assert(instruction->value->child); - IrInstruction *value = instruction->value->child; - if (type_is_invalid(value->value.type)) + IrInstruction *base_ptr = instruction->err_union_ptr->child; + if (type_is_invalid(base_ptr->value.type)) return ira->codegen->invalid_instruction; - ZigType *ptr_type = value->value.type; + 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) +{ + 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); @@ -21514,7 +23239,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; } @@ -21526,36 +23251,73 @@ 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 == ConstValSpecialUndef && initializing) { + ConstExprValue *vals = create_const_vals(2); + ConstExprValue *err_set_val = &vals[0]; + ConstExprValue *payload_val = &vals[1]; + + err_set_val->special = ConstValSpecialStatic; + err_set_val->type = type_entry->data.error_union.err_set_type; + err_set_val->data.x_err_set = nullptr; + + payload_val->special = ConstValSpecialUndef; + payload_val->type = payload_type; + + err_union_val->special = ConstValSpecialStatic; + err_union_val->data.x_err_union.error_set = err_set_val; + err_union_val->data.x_err_union.payload = payload_val; + } + 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; + if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { + 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; + result->value.special = ConstValSpecialStatic; + } else { + 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; + result->value.data.x_ptr.mut = ptr_val->data.x_ptr.mut; return result; } } } - 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); @@ -22047,14 +23809,19 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ } } - IrInstruction *result = ir_const(ira, source_instr, dest_type); + IrInstruction *result; + if (ptr->value.data.x_ptr.mut == ConstPtrMutInfer) { + result = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); + } else { + result = ir_const(ira, source_instr, dest_type); + } copy_const_val(&result->value, val, true); result->value.type = dest_type; // Keep the bigger alignment, it can only help- // unless the target is zero bits. if (src_align_bytes > dest_align_bytes && type_has_bits(dest_type)) { - result = ir_align_cast(ira, result, src_align_bytes, false); + result = ir_align_cast(ira, result, src_align_bytes, false); } return result; @@ -22138,6 +23905,8 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue case ZigTypeIdUndefined: case ZigTypeIdNull: case ZigTypeIdPromise: + case ZigTypeIdErrorUnion: + case ZigTypeIdErrorSet: zig_unreachable(); case ZigTypeIdVoid: return; @@ -22241,10 +24010,6 @@ static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue } case ZigTypeIdOptional: zig_panic("TODO buf_write_value_bytes maybe type"); - case ZigTypeIdErrorUnion: - zig_panic("TODO buf_write_value_bytes error union"); - case ZigTypeIdErrorSet: - zig_panic("TODO buf_write_value_bytes pure error type"); case ZigTypeIdFn: zig_panic("TODO buf_write_value_bytes fn type"); case ZigTypeIdUnion: @@ -22433,28 +24198,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) { @@ -22506,49 +24249,7 @@ static IrInstruction *ir_analyze_bit_cast(IrAnalyze *ira, IrInstruction *source_ return result; } - 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); - } - 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); + return ir_build_bit_cast_gen(ira, source_instr, value, dest_type); } static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *source_instr, IrInstruction *target, @@ -22618,58 +24319,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); - } - } - 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) { @@ -23183,7 +24841,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; } @@ -23455,7 +25113,7 @@ static IrInstruction *ir_analyze_instruction_float_op(IrAnalyze *ira, IrInstruct IrInstruction *type = instruction->type->child; if (type_is_invalid(type->value.type)) return ira->codegen->invalid_instruction; - + ZigType *expr_type = ir_resolve_type(ira, type); if (type_is_invalid(expr_type)) return ira->codegen->invalid_instruction; @@ -23721,12 +25379,85 @@ 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; + + bool was_written = instruction->result_loc->written; + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, instruction->result_loc, + value->value.type, value, false, false); + if (result_loc != nullptr) { + if (type_is_invalid(result_loc->value.type)) + return ira->codegen->invalid_instruction; + if (result_loc->value.type->id == ZigTypeIdUnreachable) + return result_loc; + + if (!was_written) { + IrInstruction *store_ptr = ir_analyze_store_ptr(ira, &instruction->base, result_loc, value); + if (type_is_invalid(store_ptr->value.type)) { + return ira->codegen->invalid_instruction; + } + } + + if (result_loc->value.data.x_ptr.mut == ConstPtrMutInfer) { + if (instr_is_comptime(value)) { + result_loc->value.data.x_ptr.mut = ConstPtrMutComptimeConst; + } else { + result_loc->value.special = ConstValSpecialRuntime; + } + } + } + + 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)) + return operand; + + IrInstruction *result_loc = ir_resolve_result(ira, &instruction->base, + &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; + + return instruction->result_loc_bit_cast->parent->gen_instruction; +} + +static IrInstruction *ir_analyze_instruction_union_init_named_field(IrAnalyze *ira, + IrInstructionUnionInitNamedField *instruction) +{ + ZigType *union_type = ir_resolve_type(ira, instruction->union_type->child); + if (type_is_invalid(union_type)) + return ira->codegen->invalid_instruction; + + if (union_type->id != ZigTypeIdUnion) { + ir_add_error(ira, instruction->union_type, + buf_sprintf("non-union type '%s' passed to @unionInit", buf_ptr(&union_type->name))); + return ira->codegen->invalid_instruction; + } + + Buf *field_name = ir_resolve_str(ira, instruction->field_name->child); + if (field_name == nullptr) + return ira->codegen->invalid_instruction; + + IrInstruction *field_result_loc = instruction->field_result_loc->child; + if (type_is_invalid(field_result_loc->value.type)) + return ira->codegen->invalid_instruction; + + IrInstruction *result_loc = instruction->result_loc->child; + if (type_is_invalid(result_loc->value.type)) + return ira->codegen->invalid_instruction; + + return ir_analyze_union_init(ira, &instruction->base, instruction->base.source_node, + union_type, field_name, field_result_loc, result_loc); +} + +static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: case IrInstructionIdWidenOrShorten: - case IrInstructionIdStructInit: - case IrInstructionIdUnionInit: case IrInstructionIdStructFieldPtr: case IrInstructionIdUnionFieldPtr: case IrInstructionIdOptionalWrap: @@ -23738,11 +25469,18 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio case IrInstructionIdCmpxchgGen: case IrInstructionIdArrayToVector: case IrInstructionIdVectorToArray: + case IrInstructionIdPtrOfArrayToSlice: case IrInstructionIdAssertZero: case IrInstructionIdAssertNonNull: case IrInstructionIdResizeSlice: case IrInstructionIdLoadPtrGen: case IrInstructionIdBitCastGen: + case IrInstructionIdCallGen: + case IrInstructionIdReturnPtr: + case IrInstructionIdAllocaGen: + case IrInstructionIdSliceGen: + case IrInstructionIdRefGen: + case IrInstructionIdTestErrGen: zig_unreachable(); case IrInstructionIdReturn: @@ -23765,8 +25503,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: @@ -23777,10 +25515,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio 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: @@ -23881,8 +25615,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio 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: @@ -23901,8 +25635,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio 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: @@ -23921,8 +25655,6 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio 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: @@ -23937,6 +25669,8 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio return ir_analyze_instruction_bit_offset_of(ira, (IrInstructionBitOffsetOf *)instruction); case IrInstructionIdTypeInfo: return ir_analyze_instruction_type_info(ira, (IrInstructionTypeInfo *) instruction); + case IrInstructionIdHasField: + return ir_analyze_instruction_has_field(ira, (IrInstructionHasField *) instruction); case IrInstructionIdTypeId: return ir_analyze_instruction_type_id(ira, (IrInstructionTypeId *)instruction); case IrInstructionIdSetEvalBranchQuota: @@ -23945,6 +25679,14 @@ static IrInstruction *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructio 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 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: return ir_analyze_instruction_opaque_type(ira, (IrInstructionOpaqueType *)instruction); case IrInstructionIdSetAlignStack: @@ -24021,17 +25763,18 @@ 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; + case IrInstructionIdEndExpr: + return ir_analyze_instruction_end_expr(ira, (IrInstructionEndExpr *)instruction); + case IrInstructionIdBitCastSrc: + return ir_analyze_instruction_bit_cast_src(ira, (IrInstructionBitCastSrc *)instruction); + case IrInstructionIdUnionInitNamedField: + return ir_analyze_instruction_union_init_named_field(ira, (IrInstructionUnionInitNamedField *)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, 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, @@ -24077,14 +25820,22 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ continue; } - 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 (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); + old_instruction->child = new_instruction; - // unreachable instructions do their own control flow. - if (new_instruction->value.type->id == ZigTypeIdUnreachable) - continue; + if (type_is_invalid(new_instruction->value.type)) { + return ira->codegen->builtin_types.entry_invalid; + } + + // unreachable instructions do their own control flow. + if (new_instruction->value.type->id == ZigTypeIdUnreachable) + continue; + } ira->instruction_index += 1; } @@ -24109,7 +25860,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: @@ -24156,27 +25908,29 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdResizeSlice: case IrInstructionIdGlobalAsm: case IrInstructionIdUndeclaredIdent: + case IrInstructionIdEndExpr: + case IrInstructionIdPtrOfArrayToSlice: + case IrInstructionIdSliceGen: + case IrInstructionIdOptionalWrap: + case IrInstructionIdVectorToArray: + case IrInstructionIdResetResult: return true; case IrInstructionIdPhi: case IrInstructionIdUnOp: case IrInstructionIdBinOp: case IrInstructionIdLoadPtr: - case IrInstructionIdLoadPtrGen: case IrInstructionIdConst: case IrInstructionIdCast: case IrInstructionIdContainerInitList: case IrInstructionIdContainerInitFields: - case IrInstructionIdStructInit: - case IrInstructionIdUnionInit: + case IrInstructionIdUnionInitNamedField: case IrInstructionIdFieldPtr: case IrInstructionIdElemPtr: case IrInstructionIdVarPtr: + case IrInstructionIdReturnPtr: case IrInstructionIdTypeOf: - case IrInstructionIdToPtrType: - case IrInstructionIdPtrTypeChild: case IrInstructionIdStructFieldPtr: - case IrInstructionIdUnionFieldPtr: case IrInstructionIdArrayType: case IrInstructionIdPromiseType: case IrInstructionIdSliceType: @@ -24198,7 +25952,7 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdIntType: case IrInstructionIdVectorType: case IrInstructionIdBoolNot: - case IrInstructionIdSlice: + case IrInstructionIdSliceSrc: case IrInstructionIdMemberCount: case IrInstructionIdMemberType: case IrInstructionIdMemberName: @@ -24206,16 +25960,13 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdReturnAddress: case IrInstructionIdFrameAddress: case IrInstructionIdHandle: - case IrInstructionIdTestErr: - case IrInstructionIdUnwrapErrCode: - case IrInstructionIdOptionalWrap: - case IrInstructionIdErrWrapCode: - case IrInstructionIdErrWrapPayload: + case IrInstructionIdTestErrSrc: + case IrInstructionIdTestErrGen: case IrInstructionIdFnProto: case IrInstructionIdTestComptime: case IrInstructionIdPtrCastSrc: case IrInstructionIdPtrCastGen: - case IrInstructionIdBitCast: + case IrInstructionIdBitCastSrc: case IrInstructionIdBitCastGen: case IrInstructionIdWidenOrShorten: case IrInstructionIdPtrToInt: @@ -24231,8 +25982,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdByteOffsetOf: case IrInstructionIdBitOffsetOf: case IrInstructionIdTypeInfo: + case IrInstructionIdHasField: case IrInstructionIdTypeId: case IrInstructionIdAlignCast: + case IrInstructionIdImplicitCast: + case IrInstructionIdResolveResult: case IrInstructionIdOpaqueType: case IrInstructionIdArgType: case IrInstructionIdTagType: @@ -24257,9 +26011,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdFromBytes: case IrInstructionIdToBytes: case IrInstructionIdEnumToInt: - case IrInstructionIdVectorToArray: case IrInstructionIdArrayToVector: case IrInstructionIdHasDecl: + case IrInstructionIdAllocaSrc: + case IrInstructionIdAllocaGen: + case IrInstructionIdResultPtr: return false; case IrInstructionIdAsm: @@ -24271,8 +26027,21 @@ 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<IrInstructionUnwrapErrCode *>(instruction)->initializing; + case IrInstructionIdUnionFieldPtr: + return reinterpret_cast<IrInstructionUnionFieldPtr *>(instruction)->initializing; + case IrInstructionIdErrWrapPayload: + return reinterpret_cast<IrInstructionErrWrapPayload *>(instruction)->result_loc != nullptr; + case IrInstructionIdErrWrapCode: + return reinterpret_cast<IrInstructionErrWrapCode *>(instruction)->result_loc != nullptr; + case IrInstructionIdLoadPtrGen: + return reinterpret_cast<IrInstructionLoadPtrGen *>(instruction)->result_loc != nullptr; + case IrInstructionIdRefGen: + return reinterpret_cast<IrInstructionRefGen *>(instruction)->result_loc != nullptr; } zig_unreachable(); } diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 165d9b4739..588a9b2882 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -57,13 +57,18 @@ static void ir_print_other_instruction(IrPrint *irp, IrInstruction *instruction) } static void ir_print_other_block(IrPrint *irp, IrBasicBlock *bb) { - fprintf(irp->f, "$%s_%" ZIG_PRI_usize "", bb->name_hint, bb->debug_id); + if (bb == nullptr) { + fprintf(irp->f, "(null block)"); + } else { + fprintf(irp->f, "$%s_%" ZIG_PRI_usize "", bb->name_hint, bb->debug_id); + } } 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) { @@ -188,7 +193,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 +206,56 @@ 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_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_peer(IrPrint *irp, ResultLocPeer *result_loc_peer) { + fprintf(irp->f, "peer(next="); + ir_print_other_block(irp, result_loc_peer->next_bb); + 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: + 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); + case ResultLocIdInstruction: + 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; + } + 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 +278,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) { @@ -270,10 +352,10 @@ static void ir_print_container_init_list(IrPrint *irp, IrInstructionContainerIni fprintf(irp->f, "...(%" ZIG_PRI_usize " items)...", instruction->item_count); } else { for (size_t i = 0; i < instruction->item_count; i += 1) { - IrInstruction *item = instruction->items[i]; + IrInstruction *result_loc = instruction->elem_result_loc_list[i]; if (i != 0) fprintf(irp->f, ", "); - ir_print_other_instruction(irp, item); + ir_print_other_instruction(irp, result_loc); } } fprintf(irp->f, "}"); @@ -286,32 +368,11 @@ static void ir_print_container_init_fields(IrPrint *irp, IrInstructionContainerI IrInstructionContainerInitFieldsField *field = &instruction->fields[i]; const char *comma = (i == 0) ? "" : ", "; fprintf(irp->f, "%s.%s = ", comma, buf_ptr(field->name)); - ir_print_other_instruction(irp, field->value); + ir_print_other_instruction(irp, field->result_loc); } 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; - - 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"); } @@ -331,14 +392,20 @@ 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, ".*"); } 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) { @@ -354,18 +421,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 "); @@ -618,6 +673,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); @@ -682,7 +744,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) { @@ -692,7 +755,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) { @@ -810,14 +874,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) { @@ -889,43 +965,49 @@ 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, ")"); } 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, ")"); } 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_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) { 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) { 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) { @@ -971,12 +1053,11 @@ static void ir_print_ptr_cast_gen(IrPrint *irp, IrInstructionPtrCastGen *instruc fprintf(irp->f, ")"); } -static void ir_print_bit_cast(IrPrint *irp, IrInstructionBitCast *instruction) { +static void ir_print_bit_cast_src(IrPrint *irp, IrInstructionBitCastSrc *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, ")"); + 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) { @@ -1043,7 +1124,15 @@ 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) { + 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) { @@ -1061,6 +1150,25 @@ 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, ")result="); + ir_print_other_instruction(irp, instruction->result_loc); +} + +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_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, ")"); } @@ -1162,6 +1270,14 @@ static void ir_print_type_info(IrPrint *irp, IrInstructionTypeInfo *instruction) fprintf(irp->f, ")"); } +static void ir_print_has_field(IrPrint *irp, IrInstructionHasField *instruction) { + fprintf(irp->f, "@hasField("); + ir_print_other_instruction(irp, instruction->container_type); + fprintf(irp->f, ","); + ir_print_other_instruction(irp, instruction->field_name); + fprintf(irp->f, ")"); +} + static void ir_print_type_id(IrPrint *irp, IrInstructionTypeId *instruction) { fprintf(irp->f, "@typeId("); ir_print_other_instruction(irp, instruction->type_value); @@ -1186,6 +1302,34 @@ 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_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_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); + 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()"); } @@ -1463,7 +1607,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); @@ -1482,6 +1626,18 @@ static void ir_print_undeclared_ident(IrPrint *irp, IrInstructionUndeclaredIdent fprintf(irp->f, "@undeclaredIdent(%s)", buf_ptr(instruction->name)); } +static void ir_print_union_init_named_field(IrPrint *irp, IrInstructionUnionInitNamedField *instruction) { + fprintf(irp->f, "@unionInit("); + ir_print_other_instruction(irp, instruction->union_type); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->field_name); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->field_result_loc); + fprintf(irp->f, ", "); + ir_print_other_instruction(irp, instruction->result_loc); + fprintf(irp->f, ")"); +} + static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -1502,8 +1658,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); @@ -1523,12 +1682,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; case IrInstructionIdUnreachable: ir_print_unreachable(irp, (IrInstructionUnreachable *)instruction); break; @@ -1538,6 +1691,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; @@ -1550,12 +1706,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; @@ -1634,6 +1784,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; @@ -1709,8 +1862,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); @@ -1739,8 +1895,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); @@ -1749,7 +1908,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); @@ -1769,8 +1928,8 @@ 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); + case IrInstructionIdBitCastSrc: + ir_print_bit_cast_src(irp, (IrInstructionBitCastSrc *)instruction); break; case IrInstructionIdBitCastGen: ir_print_bit_cast_gen(irp, (IrInstructionBitCastGen *)instruction); @@ -1826,6 +1985,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTypeInfo: ir_print_type_info(irp, (IrInstructionTypeInfo *)instruction); break; + case IrInstructionIdHasField: + ir_print_has_field(irp, (IrInstructionHasField *)instruction); + break; case IrInstructionIdTypeId: ir_print_type_id(irp, (IrInstructionTypeId *)instruction); break; @@ -1835,6 +1997,18 @@ 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 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; case IrInstructionIdOpaqueType: ir_print_opaque_type(irp, (IrInstructionOpaqueType *)instruction); break; @@ -1943,6 +2117,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; @@ -1958,6 +2135,18 @@ 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; + case IrInstructionIdEndExpr: + ir_print_end_expr(irp, (IrInstructionEndExpr *)instruction); + break; + case IrInstructionIdUnionInitNamedField: + ir_print_union_init_named_field(irp, (IrInstructionUnionInitNamedField *)instruction); + break; } fprintf(irp->f, "\n"); } diff --git a/src/link.cpp b/src/link.cpp index 277dcbc5c6..4a17ec892c 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -11,44 +11,577 @@ #include "analyze.hpp" #include "compiler.hpp" #include "install_files.h" +#include "glibc.hpp" + +static const char *msvcrt_common_src[] = { + "misc" OS_SEP "onexit_table.c", + "misc" OS_SEP "register_tls_atexit.c", + "stdio" OS_SEP "acrt_iob_func.c", + "misc" OS_SEP "_configthreadlocale.c", + "misc" OS_SEP "_get_current_locale.c", + "misc" OS_SEP "invalid_parameter_handler.c", + "misc" OS_SEP "output_format.c", + "misc" OS_SEP "purecall.c", + "secapi" OS_SEP "_access_s.c", + "secapi" OS_SEP "_cgets_s.c", + "secapi" OS_SEP "_cgetws_s.c", + "secapi" OS_SEP "_chsize_s.c", + "secapi" OS_SEP "_controlfp_s.c", + "secapi" OS_SEP "_cprintf_s.c", + "secapi" OS_SEP "_cprintf_s_l.c", + "secapi" OS_SEP "_ctime32_s.c", + "secapi" OS_SEP "_ctime64_s.c", + "secapi" OS_SEP "_cwprintf_s.c", + "secapi" OS_SEP "_cwprintf_s_l.c", + "secapi" OS_SEP "_gmtime32_s.c", + "secapi" OS_SEP "_gmtime64_s.c", + "secapi" OS_SEP "_localtime32_s.c", + "secapi" OS_SEP "_localtime64_s.c", + "secapi" OS_SEP "_mktemp_s.c", + "secapi" OS_SEP "_sopen_s.c", + "secapi" OS_SEP "_strdate_s.c", + "secapi" OS_SEP "_strtime_s.c", + "secapi" OS_SEP "_umask_s.c", + "secapi" OS_SEP "_vcprintf_s.c", + "secapi" OS_SEP "_vcprintf_s_l.c", + "secapi" OS_SEP "_vcwprintf_s.c", + "secapi" OS_SEP "_vcwprintf_s_l.c", + "secapi" OS_SEP "_vscprintf_p.c", + "secapi" OS_SEP "_vscwprintf_p.c", + "secapi" OS_SEP "_vswprintf_p.c", + "secapi" OS_SEP "_waccess_s.c", + "secapi" OS_SEP "_wasctime_s.c", + "secapi" OS_SEP "_wctime32_s.c", + "secapi" OS_SEP "_wctime64_s.c", + "secapi" OS_SEP "_wstrtime_s.c", + "secapi" OS_SEP "_wmktemp_s.c", + "secapi" OS_SEP "_wstrdate_s.c", + "secapi" OS_SEP "asctime_s.c", + "secapi" OS_SEP "memcpy_s.c", + "secapi" OS_SEP "memmove_s.c", + "secapi" OS_SEP "rand_s.c", + "secapi" OS_SEP "sprintf_s.c", + "secapi" OS_SEP "strerror_s.c", + "secapi" OS_SEP "vsprintf_s.c", + "secapi" OS_SEP "wmemcpy_s.c", + "secapi" OS_SEP "wmemmove_s.c", + "stdio" OS_SEP "mingw_lock.c", +}; + +static const char *msvcrt_i386_src[] = { + "misc" OS_SEP "lc_locale_func.c", -struct LinkJob { - CodeGen *codegen; - ZigList<const char *> args; - bool link_in_crt; - HashMap<Buf *, bool, buf_hash, buf_eql_buf> 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; +static const char *msvcrt_other_src[] = { + "misc" OS_SEP "__p___argv.c", + "misc" OS_SEP "__p__acmdln.c", + "misc" OS_SEP "__p__fmode.c", + "misc" OS_SEP "__p__wcmdln.c", +}; - 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; +static const char *mingwex_generic_src[] = { + "complex" OS_SEP "_cabs.c", + "complex" OS_SEP "cabs.c", + "complex" OS_SEP "cabsf.c", + "complex" OS_SEP "cabsl.c", + "complex" OS_SEP "cacos.c", + "complex" OS_SEP "cacosf.c", + "complex" OS_SEP "cacosl.c", + "complex" OS_SEP "carg.c", + "complex" OS_SEP "cargf.c", + "complex" OS_SEP "cargl.c", + "complex" OS_SEP "casin.c", + "complex" OS_SEP "casinf.c", + "complex" OS_SEP "casinl.c", + "complex" OS_SEP "catan.c", + "complex" OS_SEP "catanf.c", + "complex" OS_SEP "catanl.c", + "complex" OS_SEP "ccos.c", + "complex" OS_SEP "ccosf.c", + "complex" OS_SEP "ccosl.c", + "complex" OS_SEP "cexp.c", + "complex" OS_SEP "cexpf.c", + "complex" OS_SEP "cexpl.c", + "complex" OS_SEP "cimag.c", + "complex" OS_SEP "cimagf.c", + "complex" OS_SEP "cimagl.c", + "complex" OS_SEP "clog.c", + "complex" OS_SEP "clog10.c", + "complex" OS_SEP "clog10f.c", + "complex" OS_SEP "clog10l.c", + "complex" OS_SEP "clogf.c", + "complex" OS_SEP "clogl.c", + "complex" OS_SEP "conj.c", + "complex" OS_SEP "conjf.c", + "complex" OS_SEP "conjl.c", + "complex" OS_SEP "cpow.c", + "complex" OS_SEP "cpowf.c", + "complex" OS_SEP "cpowl.c", + "complex" OS_SEP "cproj.c", + "complex" OS_SEP "cprojf.c", + "complex" OS_SEP "cprojl.c", + "complex" OS_SEP "creal.c", + "complex" OS_SEP "crealf.c", + "complex" OS_SEP "creall.c", + "complex" OS_SEP "csin.c", + "complex" OS_SEP "csinf.c", + "complex" OS_SEP "csinl.c", + "complex" OS_SEP "csqrt.c", + "complex" OS_SEP "csqrtf.c", + "complex" OS_SEP "csqrtl.c", + "complex" OS_SEP "ctan.c", + "complex" OS_SEP "ctanf.c", + "complex" OS_SEP "ctanl.c", + "crt" OS_SEP "dllentry.c", + "crt" OS_SEP "dllmain.c", + "gdtoa" OS_SEP "arithchk.c", + "gdtoa" OS_SEP "dmisc.c", + "gdtoa" OS_SEP "dtoa.c", + "gdtoa" OS_SEP "g__fmt.c", + "gdtoa" OS_SEP "g_dfmt.c", + "gdtoa" OS_SEP "g_ffmt.c", + "gdtoa" OS_SEP "g_xfmt.c", + "gdtoa" OS_SEP "gdtoa.c", + "gdtoa" OS_SEP "gethex.c", + "gdtoa" OS_SEP "gmisc.c", + "gdtoa" OS_SEP "hd_init.c", + "gdtoa" OS_SEP "hexnan.c", + "gdtoa" OS_SEP "misc.c", + "gdtoa" OS_SEP "qnan.c", + "gdtoa" OS_SEP "smisc.c", + "gdtoa" OS_SEP "strtodg.c", + "gdtoa" OS_SEP "strtodnrp.c", + "gdtoa" OS_SEP "strtof.c", + "gdtoa" OS_SEP "strtopx.c", + "gdtoa" OS_SEP "sum.c", + "gdtoa" OS_SEP "ulp.c", + "math" OS_SEP "abs64.c", + "math" OS_SEP "cbrt.c", + "math" OS_SEP "cbrtf.c", + "math" OS_SEP "cbrtl.c", + "math" OS_SEP "cephes_emath.c", + "math" OS_SEP "copysign.c", + "math" OS_SEP "copysignf.c", + "math" OS_SEP "coshf.c", + "math" OS_SEP "coshl.c", + "math" OS_SEP "erfl.c", + "math" OS_SEP "expf.c", + "math" OS_SEP "fabs.c", + "math" OS_SEP "fabsf.c", + "math" OS_SEP "fabsl.c", + "math" OS_SEP "fdim.c", + "math" OS_SEP "fdimf.c", + "math" OS_SEP "fdiml.c", + "math" OS_SEP "fma.c", + "math" OS_SEP "fmaf.c", + "math" OS_SEP "fmal.c", + "math" OS_SEP "fmax.c", + "math" OS_SEP "fmaxf.c", + "math" OS_SEP "fmaxl.c", + "math" OS_SEP "fmin.c", + "math" OS_SEP "fminf.c", + "math" OS_SEP "fminl.c", + "math" OS_SEP "fp_consts.c", + "math" OS_SEP "fp_constsf.c", + "math" OS_SEP "fp_constsl.c", + "math" OS_SEP "fpclassify.c", + "math" OS_SEP "fpclassifyf.c", + "math" OS_SEP "fpclassifyl.c", + "math" OS_SEP "frexpf.c", + "math" OS_SEP "hypot.c", + "math" OS_SEP "hypotf.c", + "math" OS_SEP "hypotl.c", + "math" OS_SEP "isnan.c", + "math" OS_SEP "isnanf.c", + "math" OS_SEP "isnanl.c", + "math" OS_SEP "ldexpf.c", + "math" OS_SEP "lgamma.c", + "math" OS_SEP "lgammaf.c", + "math" OS_SEP "lgammal.c", + "math" OS_SEP "llrint.c", + "math" OS_SEP "llrintf.c", + "math" OS_SEP "llrintl.c", + "math" OS_SEP "llround.c", + "math" OS_SEP "llroundf.c", + "math" OS_SEP "llroundl.c", + "math" OS_SEP "log10f.c", + "math" OS_SEP "logf.c", + "math" OS_SEP "lrint.c", + "math" OS_SEP "lrintf.c", + "math" OS_SEP "lrintl.c", + "math" OS_SEP "lround.c", + "math" OS_SEP "lroundf.c", + "math" OS_SEP "lroundl.c", + "math" OS_SEP "modf.c", + "math" OS_SEP "modff.c", + "math" OS_SEP "modfl.c", + "math" OS_SEP "nextafterf.c", + "math" OS_SEP "nextafterl.c", + "math" OS_SEP "nexttoward.c", + "math" OS_SEP "nexttowardf.c", + "math" OS_SEP "powf.c", + "math" OS_SEP "powi.c", + "math" OS_SEP "powif.c", + "math" OS_SEP "powil.c", + "math" OS_SEP "rint.c", + "math" OS_SEP "rintf.c", + "math" OS_SEP "rintl.c", + "math" OS_SEP "round.c", + "math" OS_SEP "roundf.c", + "math" OS_SEP "roundl.c", + "math" OS_SEP "s_erf.c", + "math" OS_SEP "sf_erf.c", + "math" OS_SEP "signbit.c", + "math" OS_SEP "signbitf.c", + "math" OS_SEP "signbitl.c", + "math" OS_SEP "signgam.c", + "math" OS_SEP "sinhf.c", + "math" OS_SEP "sinhl.c", + "math" OS_SEP "sqrt.c", + "math" OS_SEP "sqrtf.c", + "math" OS_SEP "sqrtl.c", + "math" OS_SEP "tanhf.c", + "math" OS_SEP "tanhl.c", + "math" OS_SEP "tgamma.c", + "math" OS_SEP "tgammaf.c", + "math" OS_SEP "tgammal.c", + "math" OS_SEP "truncl.c", + "misc" OS_SEP "alarm.c", + "misc" OS_SEP "assert.c", + "misc" OS_SEP "basename.c", + "misc" OS_SEP "btowc.c", + "misc" OS_SEP "delay-f.c", + "misc" OS_SEP "delay-n.c", + "misc" OS_SEP "delayimp.c", + "misc" OS_SEP "difftime.c", + "misc" OS_SEP "difftime32.c", + "misc" OS_SEP "difftime64.c", + "misc" OS_SEP "dirent.c", + "misc" OS_SEP "dirname.c", + "misc" OS_SEP "execv.c", + "misc" OS_SEP "execve.c", + "misc" OS_SEP "execvp.c", + "misc" OS_SEP "execvpe.c", + "misc" OS_SEP "feclearexcept.c", + "misc" OS_SEP "fegetenv.c", + "misc" OS_SEP "fegetexceptflag.c", + "misc" OS_SEP "fegetround.c", + "misc" OS_SEP "feholdexcept.c", + "misc" OS_SEP "feraiseexcept.c", + "misc" OS_SEP "fesetenv.c", + "misc" OS_SEP "fesetexceptflag.c", + "misc" OS_SEP "fesetround.c", + "misc" OS_SEP "fetestexcept.c", + "misc" OS_SEP "feupdateenv.c", + "misc" OS_SEP "ftruncate.c", + "misc" OS_SEP "ftw.c", + "misc" OS_SEP "ftw64.c", + "misc" OS_SEP "fwide.c", + "misc" OS_SEP "getlogin.c", + "misc" OS_SEP "getopt.c", + "misc" OS_SEP "gettimeofday.c", + "misc" OS_SEP "imaxabs.c", + "misc" OS_SEP "imaxdiv.c", + "misc" OS_SEP "isblank.c", + "misc" OS_SEP "iswblank.c", + "misc" OS_SEP "mbrtowc.c", + "misc" OS_SEP "mbsinit.c", + "misc" OS_SEP "mempcpy.c", + "misc" OS_SEP "mingw-aligned-malloc.c", + "misc" OS_SEP "mingw-fseek.c", + "misc" OS_SEP "mingw_getsp.S", + "misc" OS_SEP "mingw_matherr.c", + "misc" OS_SEP "mingw_mbwc_convert.c", + "misc" OS_SEP "mingw_usleep.c", + "misc" OS_SEP "mingw_wcstod.c", + "misc" OS_SEP "mingw_wcstof.c", + "misc" OS_SEP "mingw_wcstold.c", + "misc" OS_SEP "mkstemp.c", + "misc" OS_SEP "seterrno.c", + "misc" OS_SEP "sleep.c", + "misc" OS_SEP "spawnv.c", + "misc" OS_SEP "spawnve.c", + "misc" OS_SEP "spawnvp.c", + "misc" OS_SEP "spawnvpe.c", + "misc" OS_SEP "strnlen.c", + "misc" OS_SEP "strsafe.c", + "misc" OS_SEP "strtoimax.c", + "misc" OS_SEP "strtold.c", + "misc" OS_SEP "strtoumax.c", + "misc" OS_SEP "tdelete.c", + "misc" OS_SEP "tfind.c", + "misc" OS_SEP "tsearch.c", + "misc" OS_SEP "twalk.c", + "misc" OS_SEP "uchar_c16rtomb.c", + "misc" OS_SEP "uchar_c32rtomb.c", + "misc" OS_SEP "uchar_mbrtoc16.c", + "misc" OS_SEP "uchar_mbrtoc32.c", + "misc" OS_SEP "wassert.c", + "misc" OS_SEP "wcrtomb.c", + "misc" OS_SEP "wcsnlen.c", + "misc" OS_SEP "wcstof.c", + "misc" OS_SEP "wcstoimax.c", + "misc" OS_SEP "wcstold.c", + "misc" OS_SEP "wcstoumax.c", + "misc" OS_SEP "wctob.c", + "misc" OS_SEP "wctrans.c", + "misc" OS_SEP "wctype.c", + "misc" OS_SEP "wdirent.c", + "misc" OS_SEP "winbs_uint64.c", + "misc" OS_SEP "winbs_ulong.c", + "misc" OS_SEP "winbs_ushort.c", + "misc" OS_SEP "wmemchr.c", + "misc" OS_SEP "wmemcmp.c", + "misc" OS_SEP "wmemcpy.c", + "misc" OS_SEP "wmemmove.c", + "misc" OS_SEP "wmempcpy.c", + "misc" OS_SEP "wmemset.c", + "stdio" OS_SEP "_Exit.c", + "stdio" OS_SEP "_findfirst64i32.c", + "stdio" OS_SEP "_findnext64i32.c", + "stdio" OS_SEP "_fstat.c", + "stdio" OS_SEP "_fstat64i32.c", + "stdio" OS_SEP "_ftime.c", + "stdio" OS_SEP "_getc_nolock.c", + "stdio" OS_SEP "_getwc_nolock.c", + "stdio" OS_SEP "_putc_nolock.c", + "stdio" OS_SEP "_putwc_nolock.c", + "stdio" OS_SEP "_stat.c", + "stdio" OS_SEP "_stat64i32.c", + "stdio" OS_SEP "_wfindfirst64i32.c", + "stdio" OS_SEP "_wfindnext64i32.c", + "stdio" OS_SEP "_wstat.c", + "stdio" OS_SEP "_wstat64i32.c", + "stdio" OS_SEP "asprintf.c", + "stdio" OS_SEP "atoll.c", + "stdio" OS_SEP "fgetpos64.c", + "stdio" OS_SEP "fopen64.c", + "stdio" OS_SEP "fseeko32.c", + "stdio" OS_SEP "fseeko64.c", + "stdio" OS_SEP "fsetpos64.c", + "stdio" OS_SEP "ftello.c", + "stdio" OS_SEP "ftello64.c", + "stdio" OS_SEP "ftruncate64.c", + "stdio" OS_SEP "lltoa.c", + "stdio" OS_SEP "lltow.c", + "stdio" OS_SEP "lseek64.c", + "stdio" OS_SEP "mingw_asprintf.c", + "stdio" OS_SEP "mingw_fprintf.c", + "stdio" OS_SEP "mingw_fprintfw.c", + "stdio" OS_SEP "mingw_fscanf.c", + "stdio" OS_SEP "mingw_fwscanf.c", + "stdio" OS_SEP "mingw_pformat.c", + "stdio" OS_SEP "mingw_pformatw.c", + "stdio" OS_SEP "mingw_printf.c", + "stdio" OS_SEP "mingw_printfw.c", + "stdio" OS_SEP "mingw_scanf.c", + "stdio" OS_SEP "mingw_snprintf.c", + "stdio" OS_SEP "mingw_snprintfw.c", + "stdio" OS_SEP "mingw_sprintf.c", + "stdio" OS_SEP "mingw_sprintfw.c", + "stdio" OS_SEP "mingw_sscanf.c", + "stdio" OS_SEP "mingw_swscanf.c", + "stdio" OS_SEP "mingw_vasprintf.c", + "stdio" OS_SEP "mingw_vfprintf.c", + "stdio" OS_SEP "mingw_vfprintfw.c", + "stdio" OS_SEP "mingw_vfscanf.c", + "stdio" OS_SEP "mingw_vprintf.c", + "stdio" OS_SEP "mingw_vprintfw.c", + "stdio" OS_SEP "mingw_vsnprintf.c", + "stdio" OS_SEP "mingw_vsnprintfw.c", + "stdio" OS_SEP "mingw_vsprintf.c", + "stdio" OS_SEP "mingw_vsprintfw.c", + "stdio" OS_SEP "mingw_wscanf.c", + "stdio" OS_SEP "mingw_wvfscanf.c", + "stdio" OS_SEP "scanf.S", + "stdio" OS_SEP "snprintf.c", + "stdio" OS_SEP "snwprintf.c", + "stdio" OS_SEP "strtof.c", + "stdio" OS_SEP "strtok_r.c", + "stdio" OS_SEP "truncate.c", + "stdio" OS_SEP "ulltoa.c", + "stdio" OS_SEP "ulltow.c", + "stdio" OS_SEP "vasprintf.c", + "stdio" OS_SEP "vfscanf.c", + "stdio" OS_SEP "vfscanf2.S", + "stdio" OS_SEP "vfwscanf.c", + "stdio" OS_SEP "vfwscanf2.S", + "stdio" OS_SEP "vscanf.c", + "stdio" OS_SEP "vscanf2.S", + "stdio" OS_SEP "vsnprintf.c", + "stdio" OS_SEP "vsnwprintf.c", + "stdio" OS_SEP "vsscanf.c", + "stdio" OS_SEP "vsscanf2.S", + "stdio" OS_SEP "vswscanf.c", + "stdio" OS_SEP "vswscanf2.S", + "stdio" OS_SEP "vwscanf.c", + "stdio" OS_SEP "vwscanf2.S", + "stdio" OS_SEP "wtoll.c", +}; - codegen_set_errmsg_color(child_gen, parent_gen->err_color); +static const char *mingwex_x86_src[] = { + "math" OS_SEP "x86" OS_SEP "acosf.c", + "math" OS_SEP "x86" OS_SEP "acosh.c", + "math" OS_SEP "x86" OS_SEP "acoshf.c", + "math" OS_SEP "x86" OS_SEP "acoshl.c", + "math" OS_SEP "x86" OS_SEP "acosl.c", + "math" OS_SEP "x86" OS_SEP "asinf.c", + "math" OS_SEP "x86" OS_SEP "asinh.c", + "math" OS_SEP "x86" OS_SEP "asinhf.c", + "math" OS_SEP "x86" OS_SEP "asinhl.c", + "math" OS_SEP "x86" OS_SEP "asinl.c", + "math" OS_SEP "x86" OS_SEP "atan2.c", + "math" OS_SEP "x86" OS_SEP "atan2f.c", + "math" OS_SEP "x86" OS_SEP "atan2l.c", + "math" OS_SEP "x86" OS_SEP "atanf.c", + "math" OS_SEP "x86" OS_SEP "atanh.c", + "math" OS_SEP "x86" OS_SEP "atanhf.c", + "math" OS_SEP "x86" OS_SEP "atanhl.c", + "math" OS_SEP "x86" OS_SEP "atanl.c", + "math" OS_SEP "x86" OS_SEP "ceilf.S", + "math" OS_SEP "x86" OS_SEP "ceill.S", + "math" OS_SEP "x86" OS_SEP "ceil.S", + "math" OS_SEP "x86" OS_SEP "_chgsignl.S", + "math" OS_SEP "x86" OS_SEP "copysignl.S", + "math" OS_SEP "x86" OS_SEP "cos.c", + "math" OS_SEP "x86" OS_SEP "cosf.c", + "math" OS_SEP "x86" OS_SEP "cosl.c", + "math" OS_SEP "x86" OS_SEP "cosl_internal.S", + "math" OS_SEP "x86" OS_SEP "cossin.c", + "math" OS_SEP "x86" OS_SEP "exp2f.S", + "math" OS_SEP "x86" OS_SEP "exp2l.S", + "math" OS_SEP "x86" OS_SEP "exp2.S", + "math" OS_SEP "x86" OS_SEP "exp.c", + "math" OS_SEP "x86" OS_SEP "expl.c", + "math" OS_SEP "x86" OS_SEP "expm1.c", + "math" OS_SEP "x86" OS_SEP "expm1f.c", + "math" OS_SEP "x86" OS_SEP "expm1l.c", + "math" OS_SEP "x86" OS_SEP "floorf.S", + "math" OS_SEP "x86" OS_SEP "floorl.S", + "math" OS_SEP "x86" OS_SEP "floor.S", + "math" OS_SEP "x86" OS_SEP "fmod.c", + "math" OS_SEP "x86" OS_SEP "fmodf.c", + "math" OS_SEP "x86" OS_SEP "fmodl.c", + "math" OS_SEP "x86" OS_SEP "frexpl.S", + "math" OS_SEP "x86" OS_SEP "fucom.c", + "math" OS_SEP "x86" OS_SEP "ilogbf.S", + "math" OS_SEP "x86" OS_SEP "ilogbl.S", + "math" OS_SEP "x86" OS_SEP "ilogb.S", + "math" OS_SEP "x86" OS_SEP "internal_logl.S", + "math" OS_SEP "x86" OS_SEP "ldexp.c", + "math" OS_SEP "x86" OS_SEP "ldexpl.c", + "math" OS_SEP "x86" OS_SEP "log10l.S", + "math" OS_SEP "x86" OS_SEP "log1pf.S", + "math" OS_SEP "x86" OS_SEP "log1pl.S", + "math" OS_SEP "x86" OS_SEP "log1p.S", + "math" OS_SEP "x86" OS_SEP "log2f.S", + "math" OS_SEP "x86" OS_SEP "log2l.S", + "math" OS_SEP "x86" OS_SEP "log2.S", + "math" OS_SEP "x86" OS_SEP "logb.c", + "math" OS_SEP "x86" OS_SEP "logbf.c", + "math" OS_SEP "x86" OS_SEP "logbl.c", + "math" OS_SEP "x86" OS_SEP "log.c", + "math" OS_SEP "x86" OS_SEP "logl.c", + "math" OS_SEP "x86" OS_SEP "nearbyintf.S", + "math" OS_SEP "x86" OS_SEP "nearbyintl.S", + "math" OS_SEP "x86" OS_SEP "nearbyint.S", + "math" OS_SEP "x86" OS_SEP "pow.c", + "math" OS_SEP "x86" OS_SEP "powl.c", + "math" OS_SEP "x86" OS_SEP "remainderf.S", + "math" OS_SEP "x86" OS_SEP "remainderl.S", + "math" OS_SEP "x86" OS_SEP "remainder.S", + "math" OS_SEP "x86" OS_SEP "remquof.S", + "math" OS_SEP "x86" OS_SEP "remquol.S", + "math" OS_SEP "x86" OS_SEP "remquo.S", + "math" OS_SEP "x86" OS_SEP "scalbnf.S", + "math" OS_SEP "x86" OS_SEP "scalbnl.S", + "math" OS_SEP "x86" OS_SEP "scalbn.S", + "math" OS_SEP "x86" OS_SEP "sin.c", + "math" OS_SEP "x86" OS_SEP "sinf.c", + "math" OS_SEP "x86" OS_SEP "sinl.c", + "math" OS_SEP "x86" OS_SEP "sinl_internal.S", + "math" OS_SEP "x86" OS_SEP "tanf.c", + "math" OS_SEP "x86" OS_SEP "tanl.S", + "math" OS_SEP "x86" OS_SEP "truncf.S", + "math" OS_SEP "x86" OS_SEP "trunc.S", +}; - codegen_set_mmacosx_version_min(child_gen, parent_gen->mmacosx_version_min); - codegen_set_mios_version_min(child_gen, parent_gen->mios_version_min); +static const char *mingwex_arm32_src[] = { + "math" OS_SEP "arm" OS_SEP "_chgsignl.S", + "math" OS_SEP "arm" OS_SEP "ceil.S", + "math" OS_SEP "arm" OS_SEP "ceilf.S", + "math" OS_SEP "arm" OS_SEP "ceill.S", + "math" OS_SEP "arm" OS_SEP "copysignl.c", + "math" OS_SEP "arm" OS_SEP "exp2.c", + "math" OS_SEP "arm" OS_SEP "floor.S", + "math" OS_SEP "arm" OS_SEP "floorf.S", + "math" OS_SEP "arm" OS_SEP "floorl.S", + "math" OS_SEP "arm" OS_SEP "ldexpl.c", + "math" OS_SEP "arm" OS_SEP "log2.c", + "math" OS_SEP "arm" OS_SEP "nearbyint.S", + "math" OS_SEP "arm" OS_SEP "nearbyintf.S", + "math" OS_SEP "arm" OS_SEP "nearbyintl.S", + "math" OS_SEP "arm" OS_SEP "scalbn.c", + "math" OS_SEP "arm" OS_SEP "sincos.c", + "math" OS_SEP "arm" OS_SEP "trunc.S", + "math" OS_SEP "arm" OS_SEP "truncf.S", +}; - child_gen->enable_cache = true; +static const char *mingwex_arm64_src[] = { + "math" OS_SEP "arm64" OS_SEP "ceilf.S", + "math" OS_SEP "arm64" OS_SEP "ceill.S", + "math" OS_SEP "arm64" OS_SEP "ceil.S", + "math" OS_SEP "arm64" OS_SEP "_chgsignl.S", + "math" OS_SEP "arm64" OS_SEP "copysignl.c", + "math" OS_SEP "arm64" OS_SEP "exp2f.S", + "math" OS_SEP "arm64" OS_SEP "exp2.S", + "math" OS_SEP "arm64" OS_SEP "floorf.S", + "math" OS_SEP "arm64" OS_SEP "floorl.S", + "math" OS_SEP "arm64" OS_SEP "floor.S", + "math" OS_SEP "arm64" OS_SEP "ldexpl.c", + "math" OS_SEP "arm64" OS_SEP "log2.c", + "math" OS_SEP "arm64" OS_SEP "nearbyintf.S", + "math" OS_SEP "arm64" OS_SEP "nearbyintl.S", + "math" OS_SEP "arm64" OS_SEP "nearbyint.S", + "math" OS_SEP "arm64" OS_SEP "scalbn.c", + "math" OS_SEP "arm64" OS_SEP "sincos.c", + "math" OS_SEP "arm64" OS_SEP "truncf.S", + "math" OS_SEP "arm64" OS_SEP "trunc.S", +}; - return child_gen; -} +struct MinGWDef { + const char *name; + const char *path; + bool always_link; +}; +static const MinGWDef mingw_def_list[] = { + {"msvcrt", "lib-common" OS_SEP "msvcrt.def.in", true}, + {"setupapi", "libarm32" OS_SEP "setupapi.def", false}, + {"setupapi", "libarm64" OS_SEP "setupapi.def", false}, + {"setupapi", "lib32" OS_SEP "setupapi.def", false}, + {"setupapi", "lib64" OS_SEP "setupapi.def", false}, + {"winmm", "lib-common" OS_SEP "winmm.def", false}, + {"gdi32", "lib-common" OS_SEP "gdi32.def", false}, + {"imm32", "lib-common" OS_SEP "imm32.def", false}, + {"version", "lib-common" OS_SEP "version.def", false}, + {"advapi32", "lib-common" OS_SEP "advapi32.def.in", true}, + {"oleaut32", "lib-common" OS_SEP "oleaut32.def.in", false}, + {"ole32", "lib-common" OS_SEP "ole32.def.in", false}, + {"shell32", "lib-common" OS_SEP "shell32.def", true}, + {"user32", "lib-common" OS_SEP "user32.def.in", true}, + {"kernel32", "lib-common" OS_SEP "kernel32.def.in", true}, + {"ntdll", "libarm32" OS_SEP "ntdll.def", true}, + {"ntdll", "lib32" OS_SEP "ntdll.def", true}, + {"ntdll", "lib64" OS_SEP "ntdll.def", true}, +}; + +struct LinkJob { + CodeGen *codegen; + ZigList<const char *> args; + bool link_in_crt; + HashMap<Buf *, bool, buf_hash, buf_eql_buf> rpath_table; +}; 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); @@ -76,18 +609,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")); @@ -150,6 +671,29 @@ static const char *build_libunwind(CodeGen *parent) { return buf_ptr(&child_gen->output_file_path); } +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)))); + + c_file->args.append("-isystem"); + c_file->args.append(buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "include" OS_SEP "any-windows-any", + buf_ptr(parent->zig_lib_dir)))); + + if (target_is_arm(parent->zig_target) && + target_arch_pointer_bit_width(parent->zig_target->arch) == 32) + { + c_file->args.append("-mfpu=vfp"); + } + + c_file->args.append("-std=gnu11"); + c_file->args.append("-D_CRTBLD"); + c_file->args.append("-D_WIN32_WINNT=0x0f00"); + c_file->args.append("-D__MSVCRT_VERSION__=0x700"); +} + static void glibc_add_include_dirs_arch(CFile *c_file, ZigLLVM_ArchType arch, const char *nptl, const char *dir) { bool is_x86 = arch == ZigLLVM_x86 || arch == ZigLLVM_x86_64; bool is_aarch64 = arch == ZigLLVM_aarch64 || arch == ZigLLVM_aarch64_be; @@ -591,9 +1135,183 @@ static const char *build_musl(CodeGen *parent) { return buf_ptr(&child_gen->output_file_path); } +static void add_msvcrt_os_dep(CodeGen *parent, CodeGen *child_gen, const char *src_path) { + CFile *c_file = allocate<CFile>(1); + c_file->source_path = buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s", + buf_ptr(parent->zig_lib_dir), src_path)); + c_file->args.append("-DHAVE_CONFIG_H"); + c_file->args.append("-D__LIBMSVCRT__"); + + c_file->args.append("-I"); + c_file->args.append(path_from_libc(parent, "mingw" OS_SEP "include")); + + 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("-isystem"); + c_file->args.append(path_from_libc(parent, "include" OS_SEP "any-windows-any")); + + c_file->args.append("-g"); + c_file->args.append("-O2"); + + child_gen->c_source_files.append(c_file); +} + +static void add_mingwex_os_dep(CodeGen *parent, CodeGen *child_gen, const char *src_path) { + CFile *c_file = allocate<CFile>(1); + c_file->source_path = buf_ptr(buf_sprintf("%s" OS_SEP "libc" OS_SEP "mingw" OS_SEP "%s", + buf_ptr(parent->zig_lib_dir), src_path)); + c_file->args.append("-DHAVE_CONFIG_H"); + + c_file->args.append("-I"); + c_file->args.append(path_from_libc(parent, "mingw")); + + c_file->args.append("-I"); + c_file->args.append(path_from_libc(parent, "mingw" OS_SEP "include")); + + 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"); + + c_file->args.append("-isystem"); + c_file->args.append(path_from_libc(parent, "include" OS_SEP "any-windows-any")); + + child_gen->c_source_files.append(c_file); +} static const char *get_libc_crt_file(CodeGen *parent, const char *file) { - if (parent->libc == nullptr && target_is_glibc(parent->zig_target)) { + if (parent->libc == nullptr && parent->zig_target->os == OsWindows) { + if (strcmp(file, "crt2.o") == 0) { + CFile *c_file = allocate<CFile>(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__"); + // 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.o") == 0) { + CFile *c_file = allocate<CFile>(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))); + mingw_add_cc_args(parent, c_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<CFile>(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("-isystem"); + c_file->args.append(path_from_libc(parent, "mingw" OS_SEP "include")); + + 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 if (strcmp(file, "msvcrt-os.lib") == 0) { + CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr); + codegen_set_out_name(child_gen, buf_create_from_str("msvcrt-os")); + + for (size_t i = 0; i < array_length(msvcrt_common_src); i += 1) { + add_msvcrt_os_dep(parent, child_gen, msvcrt_common_src[i]); + } + if (parent->zig_target->arch == ZigLLVM_x86) { + for (size_t i = 0; i < array_length(msvcrt_i386_src); i += 1) { + add_msvcrt_os_dep(parent, child_gen, msvcrt_i386_src[i]); + } + } else { + for (size_t i = 0; i < array_length(msvcrt_other_src); i += 1) { + add_msvcrt_os_dep(parent, child_gen, msvcrt_other_src[i]); + } + } + codegen_build_and_link(child_gen); + return buf_ptr(&child_gen->output_file_path); + } else if (strcmp(file, "mingwex.lib") == 0) { + CodeGen *child_gen = create_child_codegen(parent, nullptr, OutTypeLib, nullptr); + codegen_set_out_name(child_gen, buf_create_from_str("mingwex")); + + for (size_t i = 0; i < array_length(mingwex_generic_src); i += 1) { + add_mingwex_os_dep(parent, child_gen, mingwex_generic_src[i]); + } + if (parent->zig_target->arch == ZigLLVM_x86 || parent->zig_target->arch == ZigLLVM_x86_64) { + for (size_t i = 0; i < array_length(mingwex_x86_src); i += 1) { + add_mingwex_os_dep(parent, child_gen, mingwex_x86_src[i]); + } + } else if (target_is_arm(parent->zig_target)) { + if (target_arch_pointer_bit_width(parent->zig_target->arch) == 32) { + for (size_t i = 0; i < array_length(mingwex_arm32_src); i += 1) { + add_mingwex_os_dep(parent, child_gen, mingwex_arm32_src[i]); + } + } else { + for (size_t i = 0; i < array_length(mingwex_arm64_src); i += 1) { + add_mingwex_os_dep(parent, child_gen, mingwex_arm64_src[i]); + } + } + } else { + zig_unreachable(); + } + codegen_build_and_link(child_gen); + return buf_ptr(&child_gen->output_file_path); + } else { + zig_unreachable(); + } + } else if (parent->libc == nullptr && target_is_glibc(parent->zig_target)) { if (strcmp(file, "crti.o") == 0) { CFile *c_file = allocate<CFile>(1); c_file->source_path = glibc_start_asm_path(parent, "crti.S"); @@ -791,6 +1509,9 @@ 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; + child_gen->want_stack_check = WantStackCheckDisabled; + codegen_build_and_link(child_gen); return &child_gen->output_file_path; } @@ -890,6 +1611,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; @@ -988,6 +1733,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 @@ -1051,11 +1801,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)); @@ -1088,7 +1834,7 @@ static void construct_linker_job_wasm(LinkJob *lj) { lj->args.append("-error-limit=0"); if (g->out_type != OutTypeExe) { - lj->args.append("--no-entry"); // So lld doesn't look for _start. + lj->args.append("--no-entry"); // So lld doesn't look for _start. // If there are any C source files we cannot rely on individual exports. if (g->c_source_files.length != 0) { @@ -1125,8 +1871,12 @@ static void coff_append_machine_arg(CodeGen *g, ZigList<const char *> *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"); + } } } @@ -1154,8 +1904,7 @@ static void add_uefi_link_args(LinkJob *lj) { static void add_msvc_link_args(LinkJob *lj, bool is_library) { CodeGen *g = lj->codegen; - // TODO: https://github.com/ziglang/zig/issues/2064 - bool is_dynamic = true; // g->is_dynamic; + bool is_dynamic = g->is_dynamic; const char *lib_str = is_dynamic ? "" : "lib"; const char *d_str = (g->build_mode == BuildModeDebug) ? "d" : ""; @@ -1182,21 +1931,161 @@ static void add_msvc_link_args(LinkJob *lj, bool is_library) { lj->args.append("ntdll.lib"); } -static const char *get_libc_file(ZigLibCInstallation *lib, const char *file) { - Buf *out_buf = buf_alloc(); - os_path_join(&lib->crt_dir, buf_create_from_str(file), out_buf); - return buf_ptr(out_buf); +static void print_zig_cc_cmd(ZigList<const char *> *args) { + for (size_t arg_i = 0; arg_i < args->length; arg_i += 1) { + const char *space_str = (arg_i == 0) ? "" : " "; + fprintf(stderr, "%s%s", space_str, args->at(arg_i)); + } + fprintf(stderr, "\n"); } -static const char *get_libc_static_file(ZigLibCInstallation *lib, const char *file) { - Buf *out_buf = buf_alloc(); - os_path_join(&lib->static_crt_dir, buf_create_from_str(file), out_buf); - return buf_ptr(out_buf); +static const char *get_def_lib(CodeGen *parent, const char *name, Buf *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 "mingw" OS_SEP "%s", + buf_ptr(parent->zig_lib_dir), buf_ptr(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<CacheHash>(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<const char *> 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(&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(&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 bool is_linking_system_lib(CodeGen *g, const char *name) { + for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) { + LinkLib *link_lib = g->link_libs_list.at(lib_i); + if (buf_eql_str(link_lib->name, name)) { + return true; + } + } + return false; } 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) { @@ -1206,45 +2095,43 @@ static void add_mingw_link_args(LinkJob *lj, bool is_library) { } if (is_dll) { - lj->args.append(get_libc_file(g->libc, "dllcrt2.o")); + lj->args.append(get_libc_crt_file(g, "dllcrt2.o")); } else { - lj->args.append(get_libc_file(g->libc, "crt2.o")); - } - - lj->args.append(get_libc_static_file(g->libc, "crtbegin.o")); - - lj->args.append(get_libc_file(g->libc, "libmingw32.a")); - - if (is_dll) { - lj->args.append(get_libc_static_file(g->libc, "libgcc_s.a")); - lj->args.append(get_libc_static_file(g->libc, "libgcc.a")); - } else { - lj->args.append(get_libc_static_file(g->libc, "libgcc.a")); - lj->args.append(get_libc_static_file(g->libc, "libgcc_eh.a")); - } - - lj->args.append(get_libc_static_file(g->libc, "libssp.a")); - lj->args.append(get_libc_file(g->libc, "libmoldname.a")); - lj->args.append(get_libc_file(g->libc, "libmingwex.a")); - lj->args.append(get_libc_file(g->libc, "libmsvcrt.a")); - - if (detect_subsystem(g) == TargetSubsystemWindows) { - lj->args.append(get_libc_file(g->libc, "libgdi32.a")); - lj->args.append(get_libc_file(g->libc, "libcomdlg32.a")); + lj->args.append(get_libc_crt_file(g, "crt2.o")); + } + + lj->args.append(get_libc_crt_file(g, "mingw32.lib")); + lj->args.append(get_libc_crt_file(g, "mingwex.lib")); + lj->args.append(get_libc_crt_file(g, "msvcrt-os.lib")); + + for (size_t def_i = 0; def_i < array_length(mingw_def_list); def_i += 1) { + const char *name = mingw_def_list[def_i].name; + Buf *path = buf_create_from_str(mingw_def_list[def_i].path); + bool always_link = mingw_def_list[def_i].always_link; + bool is_this_arch = false; + if (buf_starts_with_str(path, "lib-common" OS_SEP)) { + is_this_arch = true; + } else if (target_is_arm(g->zig_target)) { + if (target_arch_pointer_bit_width(g->zig_target->arch) == 32) { + is_this_arch = buf_starts_with_str(path, "libarm32" OS_SEP); + } else { + is_this_arch = buf_starts_with_str(path, "libarm64" OS_SEP); + } + } else if (g->zig_target->arch == ZigLLVM_x86) { + is_this_arch = buf_starts_with_str(path, "lib32" OS_SEP); + } else if (g->zig_target->arch == ZigLLVM_x86_64) { + is_this_arch = buf_starts_with_str(path, "lib64" OS_SEP); + } + if (is_this_arch && (always_link || is_linking_system_lib(g, name))) { + lj->args.append(get_def_lib(g, name, path)); + } } - - lj->args.append(get_libc_file(g->libc, "libadvapi32.a")); - lj->args.append(get_libc_file(g->libc, "libadvapi32.a")); - lj->args.append(get_libc_file(g->libc, "libshell32.a")); - lj->args.append(get_libc_file(g->libc, "libuser32.a")); - lj->args.append(get_libc_file(g->libc, "libkernel32.a")); - - lj->args.append(get_libc_static_file(g->libc, "crtend.o")); } -static void add_win_link_args(LinkJob *lj, bool is_library) { +static void add_win_link_args(LinkJob *lj, bool is_library, bool *have_windows_dll_import_libs) { if (lj->link_in_crt) { if (target_abi_is_gnu(lj->codegen->zig_target->abi)) { + *have_windows_dll_import_libs = true; add_mingw_link_args(lj, is_library); } else { add_msvc_link_args(lj, is_library); @@ -1261,6 +2148,14 @@ static void add_win_link_args(LinkJob *lj, bool is_library) { } } +static bool is_mingw_link_lib(Buf *name) { + for (size_t def_i = 0; def_i < array_length(mingw_def_list); def_i += 1) { + if (buf_eql_str_ignore_case(name, mingw_def_list[def_i].name)) { + return true; + } + } + return false; +} static void construct_linker_job_coff(LinkJob *lj) { Error err; CodeGen *g = lj->codegen; @@ -1287,9 +2182,7 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(&g->output_file_path)))); - if (g->libc_link_lib != nullptr) { - assert(g->libc != nullptr); - + if (g->libc_link_lib != nullptr && g->libc != nullptr) { lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(&g->libc->crt_dir)))); if (target_abi_is_gnu(g->zig_target->abi)) { @@ -1310,17 +2203,18 @@ static void construct_linker_job_coff(LinkJob *lj) { lj->args.append((const char *)buf_ptr(g->link_objects.at(i))); } + bool have_windows_dll_import_libs = false; switch (detect_subsystem(g)) { case TargetSubsystemAuto: if (g->zig_target->os == OsUefi) { add_uefi_link_args(lj); } else { - add_win_link_args(lj, is_library); + add_win_link_args(lj, is_library, &have_windows_dll_import_libs); } break; case TargetSubsystemConsole: lj->args.append("-SUBSYSTEM:console"); - add_win_link_args(lj, is_library); + add_win_link_args(lj, is_library, &have_windows_dll_import_libs); break; case TargetSubsystemEfiApplication: lj->args.append("-SUBSYSTEM:efi_application"); @@ -1340,15 +2234,15 @@ static void construct_linker_job_coff(LinkJob *lj) { break; case TargetSubsystemNative: lj->args.append("-SUBSYSTEM:native"); - add_win_link_args(lj, is_library); + add_win_link_args(lj, is_library, &have_windows_dll_import_libs); break; case TargetSubsystemPosix: lj->args.append("-SUBSYSTEM:posix"); - add_win_link_args(lj, is_library); + add_win_link_args(lj, is_library, &have_windows_dll_import_libs); break; case TargetSubsystemWindows: lj->args.append("-SUBSYSTEM:windows"); - add_win_link_args(lj, is_library); + add_win_link_args(lj, is_library, &have_windows_dll_import_libs); break; } @@ -1370,47 +2264,54 @@ static void construct_linker_job_coff(LinkJob *lj) { if (buf_eql_str(link_lib->name, "c")) { continue; } - if (link_lib->provided_explicitly) { + bool is_sys_lib = is_mingw_link_lib(link_lib->name); + if (have_windows_dll_import_libs && is_sys_lib) { + continue; + } + // If we're linking in the CRT or the libs are provided explictly we don't want to generate def/libs + if ((lj->link_in_crt && is_sys_lib) || link_lib->provided_explicitly) { if (target_abi_is_gnu(lj->codegen->zig_target->abi)) { - Buf *lib_name = buf_sprintf("lib%s.a", buf_ptr(link_lib->name)); + Buf* lib_name = buf_sprintf("lib%s.a", buf_ptr(link_lib->name)); lj->args.append(buf_ptr(lib_name)); - } else { - lj->args.append(buf_ptr(link_lib->name)); } - } else { - buf_resize(def_contents, 0); - buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name)); - for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) { - Buf *symbol_name = link_lib->symbols.at(exp_i); - buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name)); + else { + Buf* lib_name = buf_sprintf("%s.lib", buf_ptr(link_lib->name)); + lj->args.append(buf_ptr(lib_name)); } - buf_appendf(def_contents, "\n"); + continue; + } - Buf *def_path = buf_alloc(); - os_path_join(g->output_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path); - if ((err = os_write_file(def_path, def_contents))) { - zig_panic("error writing def file: %s", err_str(err)); - } + buf_resize(def_contents, 0); + buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name)); + for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) { + Buf *symbol_name = link_lib->symbols.at(exp_i); + buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name)); + } + buf_appendf(def_contents, "\n"); - Buf *generated_lib_path = buf_alloc(); - os_path_join(g->output_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path); + Buf *def_path = buf_alloc(); + os_path_join(g->output_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path); + if ((err = os_write_file(def_path, def_contents))) { + zig_panic("error writing def file: %s", err_str(err)); + } - gen_lib_args.resize(0); - gen_lib_args.append("link"); + Buf *generated_lib_path = buf_alloc(); + os_path_join(g->output_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path); - coff_append_machine_arg(g, &gen_lib_args); - gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path)))); - gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path)))); - Buf diag = BUF_INIT; - ZigLLVM_ObjectFormatType target_ofmt = target_object_format(g->zig_target); - if (!zig_lld_link(target_ofmt, gen_lib_args.items, gen_lib_args.length, &diag)) { - fprintf(stderr, "%s\n", buf_ptr(&diag)); - exit(1); - } - lj->args.append(buf_ptr(generated_lib_path)); + gen_lib_args.resize(0); + gen_lib_args.append("link"); + + coff_append_machine_arg(g, &gen_lib_args); + gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path)))); + gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path)))); + Buf diag = BUF_INIT; + ZigLLVM_ObjectFormatType target_ofmt = target_object_format(g->zig_target); + if (!zig_lld_link(target_ofmt, gen_lib_args.items, gen_lib_args.length, &diag)) { + fprintf(stderr, "%s\n", buf_ptr(&diag)); + exit(1); } + lj->args.append(buf_ptr(generated_lib_path)); } - } @@ -1734,3 +2635,4 @@ void codegen_link(CodeGen *g) { exit(1); } } + diff --git a/src/main.cpp b/src/main.cpp index 9b1892061b..ce68e53d85 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 <stdio.h> @@ -74,6 +75,7 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -dynamic create a shared library (.so; .dll; .dylib)\n" " --strip exclude debug symbols\n" " -target [name] <arch><sub>-<os>-<abi> see the targets command\n" + " -target-glibc [version] target a specific glibc version (default: 2.17)\n" " --verbose-tokenize enable compiler debug output for tokenization\n" " --verbose-ast enable compiler debug output for AST parsing\n" " --verbose-link enable compiler debug output for linking\n" @@ -84,16 +86,19 @@ static int print_full_usage(const char *arg0, FILE *file, int return_code) { " -dirafter [dir] same as -isystem but do it last\n" " -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" + " --override-std-dir [arg] override path to Zig standard library\n" + " --override-lib-dir [arg] override path to Zig lib 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" + " --bundle-compiler-rt for static libraries, include compiler-rt symbols\n" " --dynamic-linker [path] set the path to ld.so\n" " --each-lib-rpath add rpath for each used dynamic library\n" " --library [lib] link against lib\n" " --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" @@ -187,10 +192,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; } @@ -259,21 +287,30 @@ static bool get_cache_opt(CacheOpt opt, bool default_value) { zig_unreachable(); } +static int zig_error_no_build_file(void) { + fprintf(stderr, + "No 'build.zig' file found, in the current directory or any parent directories.\n" + "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n" + "or see `zig --help` for more options.\n" + ); + return EXIT_FAILURE; +} + extern "C" int ZigClang_main(int argc, char **argv); int main(int argc, char **argv) { + stage2_attach_segfault_handler(); + char *arg0 = argv[0]; Error err; if (argc == 2 && strcmp(argv[1], "BUILD_INFO") == 0) { - printf("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", + printf("%s\n%s\n%s\n%s\n%s\n%s\n", ZIG_CMAKE_BINARY_DIR, ZIG_CXX_COMPILER, ZIG_LLVM_CONFIG_EXE, ZIG_LLD_INCLUDE_PATH, ZIG_LLD_LIBRARIES, - ZIG_STD_FILES, - ZIG_C_HEADER_FILES, ZIG_DIA_GUIDS_LIB); return 0; } @@ -424,6 +461,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<const char *> rpath_list = {0}; bool each_lib_rpath = false; ZigList<const char *> objects = {0}; @@ -450,6 +489,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<const char *> llvm_argv = {0}; llvm_argv.append("zig (LLVM option parsing)"); @@ -461,8 +501,7 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } const char *zig_exe_path = buf_ptr(&zig_exe_path_buf); - const char *build_file = "build.zig"; - bool asked_for_help = false; + const char *build_file = nullptr; init_all_targets(); @@ -473,7 +512,6 @@ int main(int argc, char **argv) { args.append(NULL); // placeholder for (int i = 2; i < argc; i += 1) { if (strcmp(argv[i], "--help") == 0) { - asked_for_help = true; args.append(argv[i]); } else if (i + 1 < argc && strcmp(argv[i], "--build-file") == 0) { build_file = argv[i + 1]; @@ -506,12 +544,36 @@ int main(int argc, char **argv) { ZigTarget target; get_native_target(&target); - Buf *build_file_buf = buf_create_from_str(build_file); + Buf *build_file_buf = buf_create_from_str((build_file != nullptr) ? build_file : "build.zig"); Buf build_file_abs = os_path_resolve(&build_file_buf, 1); Buf build_file_basename = BUF_INIT; Buf build_file_dirname = BUF_INIT; os_path_split(&build_file_abs, &build_file_dirname, &build_file_basename); + for (;;) { + bool build_file_exists; + if ((err = os_file_exists(&build_file_abs, &build_file_exists))) { + fprintf(stderr, "unable to check existence of '%s': %s\n", buf_ptr(&build_file_abs), err_str(err)); + return 1; + } + if (build_file_exists) + break; + + if (build_file != nullptr) { + // they asked for a specific build file path. only look for that one + return zig_error_no_build_file(); + } + + Buf *next_dir = buf_alloc(); + os_path_dirname(&build_file_dirname, next_dir); + if (buf_eql_buf(&build_file_dirname, next_dir)) { + // no more parent directories to search, give up + return zig_error_no_build_file(); + } + os_path_join(next_dir, &build_file_basename, &build_file_abs); + buf_init_from_buf(&build_file_dirname, next_dir); + } + Buf full_cache_dir = BUF_INIT; if (cache_dir == nullptr) { os_path_join(&build_file_dirname, buf_create_from_str(default_zig_cache_name), &full_cache_dir); @@ -529,51 +591,6 @@ int main(int argc, char **argv) { args.items[2] = buf_ptr(&build_file_dirname); args.items[3] = buf_ptr(&full_cache_dir); - bool build_file_exists; - if ((err = os_file_exists(&build_file_abs, &build_file_exists))) { - fprintf(stderr, "unable to open '%s': %s\n", buf_ptr(&build_file_abs), err_str(err)); - return 1; - } - if (!build_file_exists) { - if (asked_for_help) { - // This usage text has to be synchronized with std/special/build_runner.zig - fprintf(stdout, - "Usage: %s build [options]\n" - "\n" - "General Options:\n" - " --help Print this help and exit\n" - " --verbose Print commands before executing them\n" - " --prefix [path] Override default install prefix\n" - " --search-prefix [path] Add a path to look for binaries, libraries, headers\n" - "\n" - "Project-specific options become available when the build file is found.\n" - "\n" - "Advanced Options:\n" - " --build-file [file] Override path to build.zig\n" - " --cache-dir [path] Override path to cache directory\n" - " --override-std-dir [arg] Override path to Zig standard library\n" - " --override-lib-dir [arg] Override path to Zig lib library\n" - " --verbose-tokenize Enable compiler debug output for tokenization\n" - " --verbose-ast Enable compiler debug output for parsing into an AST\n" - " --verbose-link Enable compiler debug output for linking\n" - " --verbose-ir Enable compiler debug output for Zig IR\n" - " --verbose-llvm-ir Enable compiler debug output for LLVM IR\n" - " --verbose-cimport Enable compiler debug output for C imports\n" - " --verbose-cc Enable compiler debug output for C compilation\n" - "\n" - , zig_exe_path); - return EXIT_SUCCESS; - } - - fprintf(stderr, - "No 'build.zig' file found.\n" - "Initialize a 'build.zig' template file with `zig init-lib` or `zig init-exe`,\n" - "or build an executable directly with `zig build-exe $FILENAME.zig`.\n" - "See: `zig build --help` or `zig --help` for more options.\n" - ); - return EXIT_FAILURE; - } - ZigPackage *build_pkg = codegen_create_package(g, buf_ptr(&build_file_dirname), buf_ptr(&build_file_basename), "std.special"); g->root_package->package_table.put(buf_create_from_str("@build"), build_pkg); @@ -688,6 +705,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); @@ -790,6 +809,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) { @@ -911,9 +934,41 @@ 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))) { - fprintf(stderr, "invalid target: %s\n", err_str(err)); + if (err == ErrorUnknownArchitecture && target.arch != ZigLLVM_UnknownArch) { + fprintf(stderr, "'%s' requires a sub-architecture. Try one of these:\n", + target_arch_name(target.arch)); + SubArchList sub_arch_list = target_subarch_list(target.arch); + size_t subarch_count = target_subarch_count(sub_arch_list); + for (size_t sub_i = 0; sub_i < subarch_count; sub_i += 1) { + ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i); + fprintf(stderr, " %s%s\n", target_arch_name(target.arch), target_subarch_name(sub)); + } + return print_error_usage(arg0); + } else { + fprintf(stderr, "invalid target: %s\n", err_str(err)); + return print_error_usage(arg0); + } + } + if (target_is_glibc(&target)) { + target.glibc_version = allocate<ZigGLibCVersion>(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); } } @@ -925,7 +980,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); } @@ -958,6 +1013,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; @@ -1069,6 +1128,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); @@ -1089,6 +1149,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)); @@ -1168,6 +1229,9 @@ int main(int argc, char **argv) { return term.code; } else if (cmd == CmdBuild) { if (g->enable_cache) { +#if defined(ZIG_OS_WINDOWS) + buf_replace(&g->output_file_path, '/', '\\'); +#endif if (printf("%s\n", buf_ptr(&g->output_file_path)) < 0) return EXIT_FAILURE; } diff --git a/src/parser.cpp b/src/parser.cpp index 33f8836ef3..25541d5351 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -344,7 +344,7 @@ static AstNode *ast_parse_bin_op_expr( op->data.bin_op_expr.op1 = left; op->data.bin_op_expr.op2 = right; break; - case NodeTypeUnwrapErrorExpr: + case NodeTypeCatchExpr: op->data.unwrap_err_expr.op1 = left; op->data.unwrap_err_expr.op2 = right; break; @@ -1519,7 +1519,6 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) { // / IDENTIFIER // / IfTypeExpr // / INTEGER -// / KEYWORD_anyerror // / KEYWORD_comptime TypeExpr // / KEYWORD_error DOT IDENTIFIER // / KEYWORD_false @@ -1614,10 +1613,6 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) { return res; } - Token *error_type = eat_token_if(pc, TokenIdKeywordAnyerror); - if (error_type != nullptr) - return ast_create_node(pc, NodeTypeErrorType, error_type); - Token *comptime = eat_token_if(pc, TokenIdKeywordCompTime); if (comptime != nullptr) { AstNode *expr = ast_expect(pc, ast_parse_type_expr); @@ -2404,7 +2399,7 @@ static AstNode *ast_parse_bitwise_op(ParseContext *pc) { Token *catch_token = eat_token_if(pc, TokenIdKeywordCatch); if (catch_token != nullptr) { Token *payload = ast_parse_payload(pc); - AstNode *res = ast_create_node(pc, NodeTypeUnwrapErrorExpr, catch_token); + AstNode *res = ast_create_node(pc, NodeTypeCatchExpr, catch_token); if (payload != nullptr) res->data.unwrap_err_expr.symbol = token_symbol(pc, payload); @@ -2897,7 +2892,7 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont visit_field(&node->data.bin_op_expr.op1, visit, context); visit_field(&node->data.bin_op_expr.op2, visit, context); break; - case NodeTypeUnwrapErrorExpr: + case NodeTypeCatchExpr: visit_field(&node->data.unwrap_err_expr.op1, visit, context); visit_field(&node->data.unwrap_err_expr.symbol, visit, context); visit_field(&node->data.unwrap_err_expr.op2, visit, context); diff --git a/src/target.cpp b/src/target.cpp index 1d74304584..56c9a72c8f 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 <stdio.h> @@ -466,7 +468,33 @@ 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<Slice<uint8_t>> 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<Slice<uint8_t>> 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<Slice<uint8_t>> 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) { + // first zero initialize + *target = {}; + ZigLLVM_OSType os_type; ZigLLVM_ObjectFormatType oformat; // ignored; based on arch/os ZigLLVMGetNativeTarget( @@ -481,22 +509,32 @@ void get_native_target(ZigTarget *target) { if (target->abi == ZigLLVM_UnknownEnvironment) { target->abi = target_default_abi(target->arch, target->os); } + if (target_is_glibc(target)) { + target->glibc_version = allocate<ZigGLibCVersion>(1); + *target->glibc_version = {2, 17, 0}; +#ifdef ZIG_OS_LINUX + Error err; + if ((err = glibc_detect_native_version(target->glibc_version))) { + // Fall back to the default version. + } +#endif + } } Error target_parse_archsub(ZigLLVM_ArchType *out_arch, ZigLLVM_SubArchType *out_sub, const char *archsub_ptr, size_t archsub_len) { + *out_arch = ZigLLVM_UnknownArch; + *out_sub = ZigLLVM_NoSubArch; for (size_t arch_i = 0; arch_i < array_length(arch_list); arch_i += 1) { ZigLLVM_ArchType arch = arch_list[arch_i]; SubArchList sub_arch_list = target_subarch_list(arch); size_t subarch_count = target_subarch_count(sub_arch_list); - if (subarch_count == 0) { - if (mem_eql_str(archsub_ptr, archsub_len, target_arch_name(arch))) { - *out_arch = arch; - *out_sub = ZigLLVM_NoSubArch; + if (mem_eql_str(archsub_ptr, archsub_len, target_arch_name(arch))) { + *out_arch = arch; + if (subarch_count == 0) { return ErrorNone; } - continue; } for (size_t sub_i = 0; sub_i < subarch_count; sub_i += 1) { ZigLLVM_SubArchType sub = target_subarch_enum(sub_arch_list, sub_i); @@ -667,6 +705,10 @@ Error target_parse_abi(ZigLLVM_EnvironmentType *out_abi, const char *abi_ptr, si Error target_parse_triple(ZigTarget *target, const char *triple) { Error err; + + // first initialize all to zero + *target = {}; + SplitIterator it = memSplit(str(triple), str("-")); Optional<Slice<uint8_t>> opt_archsub = SplitIterator_next(&it); @@ -696,9 +738,6 @@ Error target_parse_triple(ZigTarget *target, const char *triple) { } else { target->abi = target_default_abi(target->arch, target->os); } - - target->vendor = ZigLLVM_UnknownVendor; - target->is_native = false; return ErrorNone; } @@ -714,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), @@ -945,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"; @@ -973,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"; @@ -988,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"; } @@ -1420,8 +1477,8 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { case OsKFreeBSD: case OsNetBSD: case OsHurd: - return ZigLLVM_GNU; case OsWindows: + return ZigLLVM_GNU; case OsUefi: return ZigLLVM_MSVC; case OsLinux: @@ -1465,18 +1522,23 @@ struct AvailableLibC { static const AvailableLibC libcs_available[] = { {ZigLLVM_aarch64_be, OsLinux, ZigLLVM_GNU}, {ZigLLVM_aarch64_be, OsLinux, ZigLLVM_Musl}, + {ZigLLVM_aarch64_be, OsWindows, ZigLLVM_GNU}, {ZigLLVM_aarch64, OsLinux, ZigLLVM_GNU}, {ZigLLVM_aarch64, OsLinux, ZigLLVM_MuslEABI}, + {ZigLLVM_aarch64, OsWindows, ZigLLVM_GNU}, {ZigLLVM_armeb, OsLinux, ZigLLVM_GNUEABI}, {ZigLLVM_armeb, OsLinux, ZigLLVM_GNUEABIHF}, {ZigLLVM_armeb, OsLinux, ZigLLVM_MuslEABI}, {ZigLLVM_armeb, OsLinux, ZigLLVM_MuslEABIHF}, + {ZigLLVM_armeb, OsWindows, ZigLLVM_GNU}, {ZigLLVM_arm, OsLinux, ZigLLVM_GNUEABI}, {ZigLLVM_arm, OsLinux, ZigLLVM_GNUEABIHF}, {ZigLLVM_arm, OsLinux, ZigLLVM_MuslEABI}, {ZigLLVM_arm, OsLinux, ZigLLVM_MuslEABIHF}, + {ZigLLVM_arm, OsWindows, ZigLLVM_GNU}, {ZigLLVM_x86, OsLinux, ZigLLVM_GNU}, {ZigLLVM_x86, OsLinux, ZigLLVM_Musl}, + {ZigLLVM_x86, OsWindows, ZigLLVM_GNU}, {ZigLLVM_mips64el, OsLinux, ZigLLVM_GNUABI64}, {ZigLLVM_mips64el, OsLinux, ZigLLVM_GNUABIN32}, {ZigLLVM_mips64el, OsLinux, ZigLLVM_Musl}, @@ -1504,6 +1566,7 @@ static const AvailableLibC libcs_available[] = { {ZigLLVM_x86_64, OsLinux, ZigLLVM_GNU}, {ZigLLVM_x86_64, OsLinux, ZigLLVM_GNUX32}, {ZigLLVM_x86_64, OsLinux, ZigLLVM_Musl}, + {ZigLLVM_x86_64, OsWindows, ZigLLVM_GNU}, }; bool target_can_build_libc(const ZigTarget *target) { @@ -1519,6 +1582,9 @@ bool target_can_build_libc(const ZigTarget *target) { } const char *target_libc_generic_name(const ZigTarget *target) { + if (target->os == OsWindows) { + return "mingw"; + } switch (target->abi) { case ZigLLVM_GNU: case ZigLLVM_GNUABIN32: diff --git a/src/target.hpp b/src/target.hpp index 7fca430df6..e7e102a8ce 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); @@ -139,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); diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index a0acde52e9..783b6e0e20 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -109,7 +109,6 @@ static const struct ZigKeyword zig_keywords[] = { {"align", TokenIdKeywordAlign}, {"allowzero", TokenIdKeywordAllowZero}, {"and", TokenIdKeywordAnd}, - {"anyerror", TokenIdKeywordAnyerror}, {"asm", TokenIdKeywordAsm}, {"async", TokenIdKeywordAsync}, {"await", TokenIdKeywordAwait}, @@ -190,6 +189,7 @@ enum TokenizeState { TokenizeStateFloatExponentNumber, // "123.456e-", "123.456e5", "123.456e5e-5" TokenizeStateString, TokenizeStateStringEscape, + TokenizeStateStringEscapeUnicodeStart, TokenizeStateCharLiteral, TokenizeStateCharLiteralEnd, TokenizeStateSawStar, @@ -241,7 +241,6 @@ struct Tokenize { int32_t exp_add_amt; bool is_exp_negative; size_t char_code_index; - size_t char_code_end; bool unicode; uint32_t char_code; int exponent_in_bin_or_dec; @@ -1071,24 +1070,10 @@ void tokenize(Buf *buf, Tokenization *out) { t.radix = 16; t.char_code = 0; t.char_code_index = 0; - t.char_code_end = 2; t.unicode = false; break; case 'u': - t.state = TokenizeStateCharCode; - t.radix = 16; - t.char_code = 0; - t.char_code_index = 0; - t.char_code_end = 4; - t.unicode = true; - break; - case 'U': - t.state = TokenizeStateCharCode; - t.radix = 16; - t.char_code = 0; - t.char_code_index = 0; - t.char_code_end = 6; - t.unicode = true; + t.state = TokenizeStateStringEscapeUnicodeStart; break; case 'n': handle_string_escape(&t, '\n'); @@ -1112,8 +1097,63 @@ void tokenize(Buf *buf, Tokenization *out) { invalid_char_error(&t, c); } break; + case TokenizeStateStringEscapeUnicodeStart: + switch (c) { + case '{': + t.state = TokenizeStateCharCode; + t.radix = 16; + t.char_code = 0; + t.char_code_index = 0; + t.unicode = true; + break; + default: + invalid_char_error(&t, c); + } + break; case TokenizeStateCharCode: { + if (t.unicode && c == '}') { + if (t.char_code_index == 0) { + tokenize_error(&t, "empty unicode escape sequence"); + break; + } + if (t.char_code > 0x10ffff) { + tokenize_error(&t, "unicode value out of range: %x", t.char_code); + break; + } + if (t.cur_tok->id == TokenIdCharLiteral) { + t.cur_tok->data.char_lit.c = t.char_code; + t.state = TokenizeStateCharLiteralEnd; + } else if (t.char_code <= 0x7f) { + // 00000000 00000000 00000000 0xxxxxxx + handle_string_escape(&t, (uint8_t)t.char_code); + } else if (t.char_code <= 0x7ff) { + // 00000000 00000000 00000xxx xx000000 + handle_string_escape(&t, (uint8_t)(0xc0 | (t.char_code >> 6))); + // 00000000 00000000 00000000 00xxxxxx + handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); + } else if (t.char_code <= 0xffff) { + // 00000000 00000000 xxxx0000 00000000 + handle_string_escape(&t, (uint8_t)(0xe0 | (t.char_code >> 12))); + // 00000000 00000000 0000xxxx xx000000 + handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); + // 00000000 00000000 00000000 00xxxxxx + handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); + } else if (t.char_code <= 0x10ffff) { + // 00000000 000xxx00 00000000 00000000 + handle_string_escape(&t, (uint8_t)(0xf0 | (t.char_code >> 18))); + // 00000000 000000xx xxxx0000 00000000 + handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 12) & 0x3f))); + // 00000000 00000000 0000xxxx xx000000 + handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); + // 00000000 00000000 00000000 00xxxxxx + handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); + } else { + zig_unreachable(); + } + break; + } + uint32_t digit_value = get_digit_value(c); if (digit_value >= t.radix) { tokenize_error(&t, "invalid digit: '%c'", c); @@ -1123,44 +1163,9 @@ void tokenize(Buf *buf, Tokenization *out) { t.char_code += digit_value; t.char_code_index += 1; - if (t.char_code_index >= t.char_code_end) { - if (t.unicode) { - if (t.char_code > 0x10ffff) { - tokenize_error(&t, "unicode value out of range: %x", t.char_code); - break; - } - if (t.cur_tok->id == TokenIdCharLiteral) { - t.cur_tok->data.char_lit.c = t.char_code; - t.state = TokenizeStateCharLiteralEnd; - } else if (t.char_code <= 0x7f) { - // 00000000 00000000 00000000 0xxxxxxx - handle_string_escape(&t, (uint8_t)t.char_code); - } else if (t.char_code <= 0x7ff) { - // 00000000 00000000 00000xxx xx000000 - handle_string_escape(&t, (uint8_t)(0xc0 | (t.char_code >> 6))); - // 00000000 00000000 00000000 00xxxxxx - handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); - } else if (t.char_code <= 0xffff) { - // 00000000 00000000 xxxx0000 00000000 - handle_string_escape(&t, (uint8_t)(0xe0 | (t.char_code >> 12))); - // 00000000 00000000 0000xxxx xx000000 - handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); - // 00000000 00000000 00000000 00xxxxxx - handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); - } else if (t.char_code <= 0x10ffff) { - // 00000000 000xxx00 00000000 00000000 - handle_string_escape(&t, (uint8_t)(0xf0 | (t.char_code >> 18))); - // 00000000 000000xx xxxx0000 00000000 - handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 12) & 0x3f))); - // 00000000 00000000 0000xxxx xx000000 - handle_string_escape(&t, (uint8_t)(0x80 | ((t.char_code >> 6) & 0x3f))); - // 00000000 00000000 00000000 00xxxxxx - handle_string_escape(&t, (uint8_t)(0x80 | (t.char_code & 0x3f))); - } - } else { - assert(t.char_code <= 255); - handle_string_escape(&t, (uint8_t)t.char_code); - } + if (!t.unicode && t.char_code_index >= 2) { + assert(t.char_code <= 255); + handle_string_escape(&t, (uint8_t)t.char_code); } } break; @@ -1409,6 +1414,7 @@ void tokenize(Buf *buf, Tokenization *out) { tokenize_error(&t, "unterminated string"); break; case TokenizeStateStringEscape: + case TokenizeStateStringEscapeUnicodeStart: case TokenizeStateCharCode: if (t.cur_tok->id == TokenIdStringLiteral) { tokenize_error(&t, "unterminated string"); @@ -1521,7 +1527,6 @@ const char * token_name(TokenId id) { case TokenIdFloatLiteral: return "FloatLiteral"; case TokenIdIntLiteral: return "IntLiteral"; case TokenIdKeywordAsync: return "async"; - case TokenIdKeywordAnyerror: return "anyerror"; case TokenIdKeywordAllowZero: return "allowzero"; case TokenIdKeywordAwait: return "await"; case TokenIdKeywordResume: return "resume"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index d5174c24de..83dbe99471 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -53,7 +53,6 @@ enum TokenId { TokenIdKeywordAlign, TokenIdKeywordAllowZero, TokenIdKeywordAnd, - TokenIdKeywordAnyerror, TokenIdKeywordAsm, TokenIdKeywordAsync, TokenIdKeywordAwait, diff --git a/src/translate_c.cpp b/src/translate_c.cpp index 28e4a7daa4..69c70958e5 100644 --- a/src/translate_c.cpp +++ b/src/translate_c.cpp @@ -833,6 +833,27 @@ static bool qual_type_has_wrapping_overflow(Context *c, ZigClangQualType qt) { } } +static bool type_is_function(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc) { + switch (ZigClangType_getTypeClass(ty)) { + case ZigClangType_FunctionProto: + case ZigClangType_FunctionNoProto: + return true; + case ZigClangType_Elaborated: { + const clang::ElaboratedType *elaborated_ty = reinterpret_cast<const clang::ElaboratedType*>(ty); + ZigClangQualType qt = bitcast(elaborated_ty->getNamedType()); + return type_is_function(c, ZigClangQualType_getTypePtr(qt), source_loc); + } + case ZigClangType_Typedef: { + const ZigClangTypedefType *typedef_ty = reinterpret_cast<const ZigClangTypedefType*>(ty); + const ZigClangTypedefNameDecl *typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); + ZigClangQualType underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl); + return type_is_function(c, ZigClangQualType_getTypePtr(underlying_type), source_loc); + } + default: + return false; + } +} + static bool type_is_opaque(Context *c, const ZigClangType *ty, ZigClangSourceLocation source_loc) { switch (ZigClangType_getTypeClass(ty)) { case ZigClangType_Builtin: { @@ -840,8 +861,23 @@ static bool type_is_opaque(Context *c, const ZigClangType *ty, ZigClangSourceLoc return ZigClangBuiltinType_getKind(builtin_ty) == ZigClangBuiltinTypeVoid; } case ZigClangType_Record: { - const clang::RecordType *record_ty = reinterpret_cast<const clang::RecordType*>(ty); - return record_ty->getDecl()->getDefinition() == nullptr; + const ZigClangRecordType *record_ty = reinterpret_cast<const ZigClangRecordType*>(ty); + const ZigClangRecordDecl *record_decl = ZigClangRecordType_getDecl(record_ty); + const ZigClangRecordDecl *record_def = ZigClangRecordDecl_getDefinition(record_decl); + if (record_def == nullptr) { + return true; + } + for (auto it = reinterpret_cast<const clang::RecordDecl *>(record_def)->field_begin(), + it_end = reinterpret_cast<const clang::RecordDecl *>(record_def)->field_end(); + it != it_end; ++it) + { + const clang::FieldDecl *field_decl = *it; + + if (field_decl->isBitField()) { + return true; + } + } + return false; } case ZigClangType_Elaborated: { const clang::ElaboratedType *elaborated_ty = reinterpret_cast<const clang::ElaboratedType*>(ty); @@ -1019,7 +1055,9 @@ static AstNode *trans_type(Context *c, const ZigClangType *ty, ZigClangSourceLoc return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); } - if (type_is_opaque(c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { + if (type_is_function(c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { + return trans_create_node_prefix_op(c, PrefixOpOptional, child_node); + } else if (type_is_opaque(c, ZigClangQualType_getTypePtr(child_qt), source_loc)) { AstNode *pointer_node = trans_create_node_ptr_type(c, ZigClangQualType_isConstQualified(child_qt), ZigClangQualType_isVolatileQualified(child_qt), diff --git a/src/userland.cpp b/src/userland.cpp index d0330669dd..d82f776cd6 100644 --- a/src/userland.cpp +++ b/src/userland.cpp @@ -26,6 +26,8 @@ void stage2_zen(const char **ptr, size_t *len) { stage2_panic(msg, strlen(msg)); } +void stage2_attach_segfault_handler(void) { } + void stage2_panic(const char *ptr, size_t len) { fwrite(ptr, 1, len, stderr); fprintf(stderr, "\n"); diff --git a/src/userland.h b/src/userland.h index eac28053e6..43bdbd18b1 100644 --- a/src/userland.h +++ b/src/userland.h @@ -114,6 +114,9 @@ ZIG_EXTERN_C void stage2_render_ast(struct Stage2Ast *ast, FILE *output_file); ZIG_EXTERN_C void stage2_zen(const char **ptr, size_t *len); // ABI warning +ZIG_EXTERN_C void stage2_attach_segfault_handler(void); + +// ABI warning ZIG_EXTERN_C ZIG_ATTRIBUTE_NORETURN void stage2_panic(const char *ptr, size_t len); // ABI warning 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<Slice<uint8_t>> SplitIterator_next(SplitIterator *self) { return Optional<Slice<uint8_t>>::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<Slice<uint8_t>> 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<Slice<uint8_t>>::some(self->buffer.slice(start, end)); +} + // Ported from std/mem.zig Slice<uint8_t> SplitIterator_rest(SplitIterator *self) { // move to beginning of token diff --git a/src/util.hpp b/src/util.hpp index f1942dd480..1fa33b30f9 100644 --- a/src/util.hpp +++ b/src/util.hpp @@ -12,6 +12,7 @@ #include <stdint.h> #include <string.h> #include <assert.h> +#include <ctype.h> #if defined(_MSC_VER) @@ -161,6 +162,15 @@ static inline bool mem_eql_mem(const char *a_ptr, size_t a_len, const char *b_pt return false; return memcmp(a_ptr, b_ptr, a_len) == 0; } +static inline bool mem_eql_mem_ignore_case(const char *a_ptr, size_t a_len, const char *b_ptr, size_t b_len) { + if (a_len != b_len) + return false; + for (size_t i = 0; i < a_len; i += 1) { + if (tolower(a_ptr[i]) != tolower(b_ptr[i])) + return false; + } + return true; +} static inline bool mem_eql_str(const char *mem, size_t mem_len, const char *str) { return mem_eql_mem(mem, mem_len, str, strlen(str)); @@ -314,6 +324,7 @@ struct SplitIterator { bool SplitIterator_isSplitByte(SplitIterator *self, uint8_t byte); Optional< Slice<uint8_t> > SplitIterator_next(SplitIterator *self); +Optional< Slice<uint8_t> > SplitIterator_next_separate(SplitIterator *self); Slice<uint8_t> SplitIterator_rest(SplitIterator *self); SplitIterator memSplit(Slice<uint8_t> buffer, Slice<uint8_t> split_bytes); diff --git a/src/zig_clang.cpp b/src/zig_clang.cpp index 28062ea69f..7c87f31125 100644 --- a/src/zig_clang.cpp +++ b/src/zig_clang.cpp @@ -21,6 +21,7 @@ #include <clang/Frontend/ASTUnit.h> #include <clang/Frontend/CompilerInstance.h> +#include <clang/AST/APValue.h> #include <clang/AST/Expr.h> #if __GNUC__ >= 8 @@ -1287,6 +1288,20 @@ static_assert((clang::StringLiteral::StringKind)ZigClangStringLiteral_StringKind static_assert((clang::StringLiteral::StringKind)ZigClangStringLiteral_StringKind_UTF16 == clang::StringLiteral::UTF16, ""); static_assert((clang::StringLiteral::StringKind)ZigClangStringLiteral_StringKind_UTF32 == clang::StringLiteral::UTF32, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Uninitialized == clang::APValue::ValueKind::Uninitialized, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Int == clang::APValue::ValueKind::Int, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Float == clang::APValue::ValueKind::Float, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_ComplexInt == clang::APValue::ValueKind::ComplexInt, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_ComplexFloat == clang::APValue::ValueKind::ComplexFloat, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_LValue == clang::APValue::ValueKind::LValue, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Vector == clang::APValue::ValueKind::Vector, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Array == clang::APValue::ValueKind::Array, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Struct == clang::APValue::ValueKind::Struct, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_Union == clang::APValue::ValueKind::Union, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_MemberPointer == clang::APValue::ValueKind::MemberPointer, ""); +static_assert((clang::APValue::ValueKind)ZigClangAPValue_ValueKind_AddrLabelDiff == clang::APValue::ValueKind::AddrLabelDiff, ""); + +static_assert(sizeof(ZigClangAPValue) == sizeof(clang::APValue), ""); static_assert(sizeof(ZigClangSourceLocation) == sizeof(clang::SourceLocation), ""); static ZigClangSourceLocation bitcast(clang::SourceLocation src) { @@ -1312,6 +1327,13 @@ static clang::QualType bitcast(ZigClangQualType src) { return dest; } +static_assert(sizeof(ZigClangExprEvalResult) == sizeof(clang::Expr::EvalResult), ""); +static ZigClangExprEvalResult bitcast(clang::Expr::EvalResult src) { + ZigClangExprEvalResult dest; + memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangExprEvalResult)); + return dest; +} + static_assert(sizeof(ZigClangAPValueLValueBase) == sizeof(clang::APValue::LValueBase), ""); static ZigClangAPValueLValueBase bitcast(clang::APValue::LValueBase src) { ZigClangAPValueLValueBase dest; @@ -1331,6 +1353,12 @@ static ZigClangCompoundStmt_const_body_iterator bitcast(clang::CompoundStmt::con return dest; } +static_assert(sizeof(ZigClangDeclStmt_const_decl_iterator) == sizeof(clang::DeclStmt::const_decl_iterator), ""); +static ZigClangDeclStmt_const_decl_iterator bitcast(clang::DeclStmt::const_decl_iterator src) { + ZigClangDeclStmt_const_decl_iterator dest; + memcpy(&dest, static_cast<void *>(&src), sizeof(ZigClangDeclStmt_const_decl_iterator)); + return dest; +} ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const ZigClangSourceManager *self, ZigClangSourceLocation Loc) @@ -1381,7 +1409,7 @@ ZigClangSourceManager *ZigClangASTUnit_getSourceManager(ZigClangASTUnit *self) { return reinterpret_cast<ZigClangSourceManager *>(result); } -bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *context, +bool ZigClangASTUnit_visitLocalTopLevelDecls(ZigClangASTUnit *self, void *context, bool (*Fn)(void *context, const ZigClangDecl *decl)) { return reinterpret_cast<clang::ASTUnit *>(self)->visitLocalTopLevelDecls(context, @@ -1540,6 +1568,11 @@ const ZigClangType *ZigClangQualType_getTypePtr(ZigClangQualType self) { return reinterpret_cast<const ZigClangType *>(ty); } +ZigClangTypeClass ZigClangQualType_getTypeClass(ZigClangQualType self) { + clang::QualType ty = bitcast(self); + return (ZigClangTypeClass)(ty->getTypeClass()); +} + void ZigClangQualType_addConst(ZigClangQualType *self) { reinterpret_cast<clang::QualType *>(self)->addConst(); } @@ -1815,6 +1848,21 @@ void ZigClangASTUnit_delete(struct ZigClangASTUnit *self) { delete reinterpret_cast<clang::ASTUnit *>(self); } +struct ZigClangQualType ZigClangVarDecl_getType(const struct ZigClangVarDecl *self) { + auto casted = reinterpret_cast<const clang::VarDecl *>(self); + return bitcast(casted->getType()); +} + +const struct ZigClangExpr *ZigClangVarDecl_getInit(const struct ZigClangVarDecl *self) { + auto casted = reinterpret_cast<const clang::VarDecl *>(self); + return reinterpret_cast<const ZigClangExpr *>(casted->getInit()); +} + +enum ZigClangVarDecl_TLSKind ZigClangVarDecl_getTLSKind(const ZigClangVarDecl *self) { + auto casted = reinterpret_cast<const clang::VarDecl *>(self); + return (ZigClangVarDecl_TLSKind)casted->getTLSKind(); +} + enum ZigClangBuiltinTypeKind ZigClangBuiltinType_getKind(const struct ZigClangBuiltinType *self) { auto casted = reinterpret_cast<const clang::BuiltinType *>(self); return (ZigClangBuiltinTypeKind)casted->getKind(); @@ -1862,6 +1910,16 @@ ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_end(const str return bitcast(casted->body_end()); } +ZigClangDeclStmt_const_decl_iterator ZigClangDeclStmt_decl_begin(const struct ZigClangDeclStmt *self) { + auto casted = reinterpret_cast<const clang::DeclStmt *>(self); + return bitcast(casted->decl_begin()); +} + +ZigClangDeclStmt_const_decl_iterator ZigClangDeclStmt_decl_end(const struct ZigClangDeclStmt *self) { + auto casted = reinterpret_cast<const clang::DeclStmt *>(self); + return bitcast(casted->decl_end()); +} + unsigned ZigClangAPFloat_convertToHexString(const ZigClangAPFloat *self, char *DST, unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM) { @@ -1888,3 +1946,104 @@ const struct ZigClangStringLiteral *ZigClangPredefinedExpr_getFunctionName( const clang::StringLiteral *result = casted->getFunctionName(); return reinterpret_cast<const struct ZigClangStringLiteral *>(result); } + +ZigClangSourceLocation ZigClangImplicitCastExpr_getBeginLoc(const struct ZigClangImplicitCastExpr *self) { + auto casted = reinterpret_cast<const clang::ImplicitCastExpr *>(self); + return bitcast(casted->getBeginLoc()); +} + +enum ZigClangCK ZigClangImplicitCastExpr_getCastKind(const struct ZigClangImplicitCastExpr *self) { + auto casted = reinterpret_cast<const clang::ImplicitCastExpr *>(self); + return (ZigClangCK)casted->getCastKind(); +} + +const struct ZigClangExpr *ZigClangImplicitCastExpr_getSubExpr(const struct ZigClangImplicitCastExpr *self) { + auto casted = reinterpret_cast<const clang::ImplicitCastExpr *>(self); + return reinterpret_cast<const struct ZigClangExpr *>(casted->getSubExpr()); +} + +struct ZigClangQualType ZigClangArrayType_getElementType(const struct ZigClangArrayType *self) { + auto casted = reinterpret_cast<const clang::ArrayType *>(self); + return bitcast(casted->getElementType()); +} + +const struct ZigClangValueDecl *ZigClangDeclRefExpr_getDecl(const struct ZigClangDeclRefExpr *self) { + auto casted = reinterpret_cast<const clang::DeclRefExpr *>(self); + return reinterpret_cast<const struct ZigClangValueDecl *>(casted->getDecl()); +} + +struct ZigClangQualType ZigClangParenType_getInnerType(const struct ZigClangParenType *self) { + auto casted = reinterpret_cast<const clang::ParenType *>(self); + return bitcast(casted->getInnerType()); +} + +struct ZigClangQualType ZigClangAttributedType_getEquivalentType(const struct ZigClangAttributedType *self) { + auto casted = reinterpret_cast<const clang::AttributedType *>(self); + return bitcast(casted->getEquivalentType()); +} + +struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *self) { + auto casted = reinterpret_cast<const clang::ElaboratedType *>(self); + return bitcast(casted->getNamedType()); +} + +struct ZigClangSourceLocation ZigClangCStyleCastExpr_getBeginLoc(const struct ZigClangCStyleCastExpr *self) { + auto casted = reinterpret_cast<const clang::CStyleCastExpr *>(self); + return bitcast(casted->getBeginLoc()); +} + +const struct ZigClangExpr *ZigClangCStyleCastExpr_getSubExpr(const struct ZigClangCStyleCastExpr *self) { + auto casted = reinterpret_cast<const clang::CStyleCastExpr *>(self); + return reinterpret_cast<const struct ZigClangExpr *>(casted->getSubExpr()); +} + +struct ZigClangQualType ZigClangCStyleCastExpr_getType(const struct ZigClangCStyleCastExpr *self) { + auto casted = reinterpret_cast<const clang::CStyleCastExpr *>(self); + return bitcast(casted->getType()); +} + +bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *self, struct ZigClangExprEvalResult *result, const struct ZigClangASTContext *ctx) { + auto casted_self = reinterpret_cast<const clang::IntegerLiteral *>(self); + auto casted_ctx = reinterpret_cast<const clang::ASTContext *>(ctx); + clang::Expr::EvalResult eval_result; + if (!casted_self->EvaluateAsInt(eval_result, *casted_ctx)) { + return false; + } + *result = bitcast(eval_result); + return true; +} + +struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct ZigClangIntegerLiteral *self) { + auto casted = reinterpret_cast<const clang::IntegerLiteral *>(self); + return bitcast(casted->getBeginLoc()); +} + +const struct ZigClangExpr *ZigClangReturnStmt_getRetValue(const struct ZigClangReturnStmt *self) { + auto casted = reinterpret_cast<const clang::ReturnStmt *>(self); + return reinterpret_cast<const struct ZigClangExpr *>(casted->getRetValue()); +} + +enum ZigClangBO ZigClangBinaryOperator_getOpcode(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast<const clang::BinaryOperator *>(self); + return (ZigClangBO)casted->getOpcode(); +} + +struct ZigClangSourceLocation ZigClangBinaryOperator_getBeginLoc(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast<const clang::BinaryOperator *>(self); + return bitcast(casted->getBeginLoc()); +} + +const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast<const clang::BinaryOperator *>(self); + return reinterpret_cast<const struct ZigClangExpr *>(casted->getLHS()); +} + +const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast<const clang::BinaryOperator *>(self); + return reinterpret_cast<const struct ZigClangExpr *>(casted->getRHS()); +} + +struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *self) { + auto casted = reinterpret_cast<const clang::BinaryOperator *>(self); + return bitcast(casted->getType()); +} diff --git a/src/zig_clang.h b/src/zig_clang.h index 1bdf34fc2f..9d03b592fd 100644 --- a/src/zig_clang.h +++ b/src/zig_clang.h @@ -30,6 +30,38 @@ struct ZigClangAPValueLValueBase { unsigned Version; }; +enum ZigClangAPValue_ValueKind { + ZigClangAPValue_ValueKind_Uninitialized, + ZigClangAPValue_ValueKind_Int, + ZigClangAPValue_ValueKind_Float, + ZigClangAPValue_ValueKind_ComplexInt, + ZigClangAPValue_ValueKind_ComplexFloat, + ZigClangAPValue_ValueKind_LValue, + ZigClangAPValue_ValueKind_Vector, + ZigClangAPValue_ValueKind_Array, + ZigClangAPValue_ValueKind_Struct, + ZigClangAPValue_ValueKind_Union, + ZigClangAPValue_ValueKind_MemberPointer, + ZigClangAPValue_ValueKind_AddrLabelDiff +}; + +struct ZigClangAPValue { + enum ZigClangAPValue_ValueKind Kind; + // experimentally-derived size of clang::APValue::DataType +#if defined(WIN32) && defined(_MSC_VER) + char Data[52]; +#else + char Data[68]; +#endif +}; + +struct ZigClangExprEvalResult { + bool HasSideEffects; + bool HasUndefinedBehavior; + void *SmallVectorImpl; + ZigClangAPValue Val; +}; + struct ZigClangAPValue; struct ZigClangAPSInt; struct ZigClangAPFloat; @@ -105,6 +137,7 @@ struct ZigClangFunctionType; struct ZigClangPredefinedExpr; typedef struct ZigClangStmt *const * ZigClangCompoundStmt_const_body_iterator; +typedef struct ZigClangDecl *const * ZigClangDeclStmt_const_decl_iterator; enum ZigClangBO { ZigClangBO_PtrMemD, @@ -732,6 +765,12 @@ enum ZigClangStringLiteral_StringKind { ZigClangStringLiteral_StringKind_UTF32, }; +enum ZigClangVarDecl_TLSKind { + ZigClangVarDecl_TLSKind_None, + ZigClangVarDecl_TLSKind_Static, + ZigClangVarDecl_TLSKind_Dynamic, +}; + ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangSourceManager_getSpellingLoc(const struct ZigClangSourceManager *, struct ZigClangSourceLocation Loc); ZIG_EXTERN_C const char *ZigClangSourceManager_getFilename(const struct ZigClangSourceManager *, @@ -754,7 +793,7 @@ ZIG_EXTERN_C void ZigClangErrorMsg_delete(struct Stage2ErrorMsg *ptr, size_t len ZIG_EXTERN_C struct ZigClangASTContext *ZigClangASTUnit_getASTContext(struct ZigClangASTUnit *); ZIG_EXTERN_C struct ZigClangSourceManager *ZigClangASTUnit_getSourceManager(struct ZigClangASTUnit *); -ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(struct ZigClangASTUnit *, void *context, +ZIG_EXTERN_C bool ZigClangASTUnit_visitLocalTopLevelDecls(struct ZigClangASTUnit *, void *context, bool (*Fn)(void *context, const struct ZigClangDecl *decl)); ZIG_EXTERN_C const struct ZigClangRecordDecl *ZigClangRecordType_getDecl(const struct ZigClangRecordType *record_ty); @@ -789,6 +828,10 @@ ZIG_EXTERN_C const char *ZigClangDecl_getName_bytes_begin(const struct ZigClangD ZIG_EXTERN_C enum ZigClangDeclKind ZigClangDecl_getKind(const struct ZigClangDecl *decl); ZIG_EXTERN_C const char *ZigClangDecl_getDeclKindName(const struct ZigClangDecl *decl); +ZIG_EXTERN_C struct ZigClangQualType ZigClangVarDecl_getType(const struct ZigClangVarDecl *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangVarDecl_getInit(const struct ZigClangVarDecl *var_decl); +ZIG_EXTERN_C enum ZigClangVarDecl_TLSKind ZigClangVarDecl_getTLSKind(const struct ZigClangVarDecl *var_decl); + ZIG_EXTERN_C bool ZigClangSourceLocation_eq(struct ZigClangSourceLocation a, struct ZigClangSourceLocation b); ZIG_EXTERN_C const struct ZigClangTypedefNameDecl *ZigClangTypedefType_getDecl(const struct ZigClangTypedefType *); @@ -796,6 +839,7 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangTypedefNameDecl_getUnderlyingType(c ZIG_EXTERN_C struct ZigClangQualType ZigClangQualType_getCanonicalType(struct ZigClangQualType); ZIG_EXTERN_C const struct ZigClangType *ZigClangQualType_getTypePtr(struct ZigClangQualType); +ZIG_EXTERN_C enum ZigClangTypeClass ZigClangQualType_getTypeClass(struct ZigClangQualType); ZIG_EXTERN_C void ZigClangQualType_addConst(struct ZigClangQualType *); ZIG_EXTERN_C bool ZigClangQualType_eq(struct ZigClangQualType, struct ZigClangQualType); ZIG_EXTERN_C bool ZigClangQualType_isConstQualified(struct ZigClangQualType); @@ -846,6 +890,9 @@ ZIG_EXTERN_C struct ZigClangQualType ZigClangFunctionProtoType_getParamType(cons ZIG_EXTERN_C ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_begin(const struct ZigClangCompoundStmt *self); ZIG_EXTERN_C ZigClangCompoundStmt_const_body_iterator ZigClangCompoundStmt_body_end(const struct ZigClangCompoundStmt *self); +ZIG_EXTERN_C ZigClangDeclStmt_const_decl_iterator ZigClangDeclStmt_decl_begin(const struct ZigClangDeclStmt *self); +ZIG_EXTERN_C ZigClangDeclStmt_const_decl_iterator ZigClangDeclStmt_decl_end(const struct ZigClangDeclStmt *self); + ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); @@ -855,4 +902,34 @@ ZIG_EXTERN_C const char *ZigClangStringLiteral_getString_bytes_begin_size(const ZIG_EXTERN_C const struct ZigClangStringLiteral *ZigClangPredefinedExpr_getFunctionName( const struct ZigClangPredefinedExpr *self); + +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangImplicitCastExpr_getBeginLoc(const struct ZigClangImplicitCastExpr *); +ZIG_EXTERN_C enum ZigClangCK ZigClangImplicitCastExpr_getCastKind(const struct ZigClangImplicitCastExpr *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangImplicitCastExpr_getSubExpr(const struct ZigClangImplicitCastExpr *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangArrayType_getElementType(const struct ZigClangArrayType *); + +ZIG_EXTERN_C const struct ZigClangValueDecl *ZigClangDeclRefExpr_getDecl(const struct ZigClangDeclRefExpr *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangParenType_getInnerType(const struct ZigClangParenType *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangAttributedType_getEquivalentType(const struct ZigClangAttributedType *); + +ZIG_EXTERN_C struct ZigClangQualType ZigClangElaboratedType_getNamedType(const struct ZigClangElaboratedType *); + +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangCStyleCastExpr_getBeginLoc(const struct ZigClangCStyleCastExpr *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangCStyleCastExpr_getSubExpr(const struct ZigClangCStyleCastExpr *); +ZIG_EXTERN_C struct ZigClangQualType ZigClangCStyleCastExpr_getType(const struct ZigClangCStyleCastExpr *); + +ZIG_EXTERN_C bool ZigClangIntegerLiteral_EvaluateAsInt(const struct ZigClangIntegerLiteral *, struct ZigClangExprEvalResult *, const struct ZigClangASTContext *); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangIntegerLiteral_getBeginLoc(const struct ZigClangIntegerLiteral *); + +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangReturnStmt_getRetValue(const struct ZigClangReturnStmt *); + +ZIG_EXTERN_C enum ZigClangBO ZigClangBinaryOperator_getOpcode(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangBinaryOperator_getBeginLoc(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getLHS(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C const struct ZigClangExpr *ZigClangBinaryOperator_getRHS(const struct ZigClangBinaryOperator *); +ZIG_EXTERN_C struct ZigClangQualType ZigClangBinaryOperator_getType(const struct ZigClangBinaryOperator *); + #endif diff --git a/src/zig_llvm.cpp b/src/zig_llvm.cpp index fe1b279cf0..c51c9e1a50 100644 --- a/src/zig_llvm.cpp +++ b/src/zig_llvm.cpp @@ -39,7 +39,9 @@ #include <llvm/Support/TargetParser.h> #include <llvm/Support/Timer.h> #include <llvm/Support/raw_ostream.h> +#include <llvm/Support/TargetRegistry.h> #include <llvm/Target/TargetMachine.h> +#include <llvm/Target/CodeGenCWrappers.h> #include <llvm/Transforms/Coroutines.h> #include <llvm/Transforms/IPO.h> #include <llvm/Transforms/IPO/AlwaysInliner.h> @@ -93,6 +95,61 @@ 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<Reloc::Model> 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<CodeModel::Model> 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; + + TargetMachine *TM = reinterpret_cast<Target*>(T)->createTargetMachine(Triple, CPU, Features, opt, RM, CM, + OL, JIT); + return reinterpret_cast<LLVMTargetMachineRef>(TM); +} + 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) diff --git a/src/zig_llvm.h b/src/zig_llvm.h index d667e0423d..8b7b0775f7 100644 --- a/src/zig_llvm.h +++ b/src/zig_llvm.h @@ -58,6 +58,10 @@ ZIG_EXTERN_C bool ZigLLVMTargetMachineEmitToFile(LLVMTargetMachineRef targ_machi const char *filename, enum ZigLLVM_EmitOutputType output_type, char **error_message, bool is_debug, 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); enum ZigLLVM_FnInline { |
