| ... | @@ -519,6 +519,8 @@ static void destroy_instruction_src(IrInstSrc *inst) { | ... | @@ -519,6 +519,8 @@ static void destroy_instruction_src(IrInstSrc *inst) { |
| 519 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTagType *>(inst)); | 519 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTagType *>(inst)); |
| 520 | case IrInstSrcIdExport: | 520 | case IrInstSrcIdExport: |
| 521 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExport *>(inst)); | 521 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExport *>(inst)); |
| | 522 | case IrInstSrcIdExtern: |
| | 523 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExtern *>(inst)); |
| 522 | case IrInstSrcIdErrorReturnTrace: | 524 | case IrInstSrcIdErrorReturnTrace: |
| 523 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrorReturnTrace *>(inst)); | 525 | return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrorReturnTrace *>(inst)); |
| 524 | case IrInstSrcIdErrorUnion: | 526 | case IrInstSrcIdErrorUnion: |
| ... | @@ -755,6 +757,8 @@ void destroy_instruction_gen(IrInstGen *inst) { | ... | @@ -755,6 +757,8 @@ void destroy_instruction_gen(IrInstGen *inst) { |
| 755 | return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemorySize *>(inst)); | 757 | return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemorySize *>(inst)); |
| 756 | case IrInstGenIdWasmMemoryGrow: | 758 | case IrInstGenIdWasmMemoryGrow: |
| 757 | return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemoryGrow *>(inst)); | 759 | return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemoryGrow *>(inst)); |
| | 760 | case IrInstGenIdExtern: |
| | 761 | return heap::c_allocator.destroy(reinterpret_cast<IrInstGenExtern *>(inst)); |
| 758 | } | 762 | } |
| 759 | zig_unreachable(); | 763 | zig_unreachable(); |
| 760 | } | 764 | } |
| ... | @@ -1555,6 +1559,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcExport *) { | ... | @@ -1555,6 +1559,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcExport *) { |
| 1555 | return IrInstSrcIdExport; | 1559 | return IrInstSrcIdExport; |
| 1556 | } | 1560 | } |
| 1557 | | 1561 | |
| | 1562 | static constexpr IrInstSrcId ir_inst_id(IrInstSrcExtern *) { |
| | 1563 | return IrInstSrcIdExtern; |
| | 1564 | } |
| | 1565 | |
| 1558 | static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorReturnTrace *) { | 1566 | static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorReturnTrace *) { |
| 1559 | return IrInstSrcIdErrorReturnTrace; | 1567 | return IrInstSrcIdErrorReturnTrace; |
| 1560 | } | 1568 | } |
| ... | @@ -1999,6 +2007,10 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemoryGrow *) { | ... | @@ -1999,6 +2007,10 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemoryGrow *) { |
| 1999 | return IrInstGenIdWasmMemoryGrow; | 2007 | return IrInstGenIdWasmMemoryGrow; |
| 2000 | } | 2008 | } |
| 2001 | | 2009 | |
| | 2010 | static constexpr IrInstGenId ir_inst_id(IrInstGenExtern *) { |
| | 2011 | return IrInstGenIdExtern; |
| | 2012 | } |
| | 2013 | |
| 2002 | template<typename T> | 2014 | template<typename T> |
| 2003 | static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { | 2015 | static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) { |
| 2004 | T *special_instruction = heap::c_allocator.create<T>(); | 2016 | T *special_instruction = heap::c_allocator.create<T>(); |
| ... | @@ -2807,6 +2819,33 @@ static IrInstSrc *ir_build_export(IrBuilderSrc *irb, Scope *scope, AstNode *sour | ... | @@ -2807,6 +2819,33 @@ static IrInstSrc *ir_build_export(IrBuilderSrc *irb, Scope *scope, AstNode *sour |
| 2807 | return &export_instruction->base; | 2819 | return &export_instruction->base; |
| 2808 | } | 2820 | } |
| 2809 | | 2821 | |
| | 2822 | static IrInstSrc *ir_build_extern(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, |
| | 2823 | IrInstSrc *type, IrInstSrc *options) |
| | 2824 | { |
| | 2825 | IrInstSrcExtern *extern_instruction = ir_build_instruction<IrInstSrcExtern>( |
| | 2826 | irb, scope, source_node); |
| | 2827 | extern_instruction->type = type; |
| | 2828 | extern_instruction->options = options; |
| | 2829 | |
| | 2830 | ir_ref_instruction(type, irb->current_basic_block); |
| | 2831 | ir_ref_instruction(options, irb->current_basic_block); |
| | 2832 | |
| | 2833 | return &extern_instruction->base; |
| | 2834 | } |
| | 2835 | |
| | 2836 | static IrInstGen *ir_build_extern_gen(IrAnalyze *ira, IrInst *source_instr, Buf *name, |
| | 2837 | GlobalLinkageId linkage, bool is_thread_local, ZigType *expr_type) |
| | 2838 | { |
| | 2839 | IrInstGenExtern *instruction = ir_build_inst_gen<IrInstGenExtern>(&ira->new_irb, |
| | 2840 | source_instr->scope, source_instr->source_node); |
| | 2841 | instruction->base.value->type = expr_type; |
| | 2842 | instruction->name = name; |
| | 2843 | instruction->linkage = linkage; |
| | 2844 | instruction->is_thread_local = is_thread_local; |
| | 2845 | |
| | 2846 | return &instruction->base; |
| | 2847 | } |
| | 2848 | |
| 2810 | static IrInstSrc *ir_build_load_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *ptr) { | 2849 | static IrInstSrc *ir_build_load_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *ptr) { |
| 2811 | IrInstSrcLoadPtr *instruction = ir_build_instruction<IrInstSrcLoadPtr>(irb, scope, source_node); | 2850 | IrInstSrcLoadPtr *instruction = ir_build_instruction<IrInstSrcLoadPtr>(irb, scope, source_node); |
| 2812 | instruction->ptr = ptr; | 2851 | instruction->ptr = ptr; |
| ... | @@ -7376,6 +7415,30 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod | ... | @@ -7376,6 +7415,30 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod |
| 7376 | IrInstSrc *ir_export = ir_build_export(irb, scope, node, target_value, casted_options_value); | 7415 | IrInstSrc *ir_export = ir_build_export(irb, scope, node, target_value, casted_options_value); |
| 7377 | return ir_lval_wrap(irb, scope, ir_export, lval, result_loc); | 7416 | return ir_lval_wrap(irb, scope, ir_export, lval, result_loc); |
| 7378 | } | 7417 | } |
| | 7418 | case BuiltinFnIdExtern: |
| | 7419 | { |
| | 7420 | // Cast the options parameter to the options type |
| | 7421 | ZigType *options_type = get_builtin_type(irb->codegen, "ExternOptions"); |
| | 7422 | IrInstSrc *options_type_inst = ir_build_const_type(irb, scope, node, options_type); |
| | 7423 | ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, options_type_inst, no_result_loc()); |
| | 7424 | |
| | 7425 | AstNode *type_node = node->data.fn_call_expr.params.at(0); |
| | 7426 | IrInstSrc *type_value = ir_gen_node(irb, type_node, scope); |
| | 7427 | if (type_value == irb->codegen->invalid_inst_src) |
| | 7428 | return type_value; |
| | 7429 | |
| | 7430 | AstNode *options_node = node->data.fn_call_expr.params.at(1); |
| | 7431 | IrInstSrc *options_value = ir_gen_node_extra(irb, options_node, |
| | 7432 | scope, LValNone, &result_loc_cast->base); |
| | 7433 | if (options_value == irb->codegen->invalid_inst_src) |
| | 7434 | return options_value; |
| | 7435 | |
| | 7436 | IrInstSrc *casted_options_value = ir_build_implicit_cast( |
| | 7437 | irb, scope, options_node, options_value, result_loc_cast); |
| | 7438 | |
| | 7439 | IrInstSrc *ir_extern = ir_build_extern(irb, scope, node, type_value, casted_options_value); |
| | 7440 | return ir_lval_wrap(irb, scope, ir_extern, lval, result_loc); |
| | 7441 | } |
| 7379 | case BuiltinFnIdErrorReturnTrace: | 7442 | case BuiltinFnIdErrorReturnTrace: |
| 7380 | { | 7443 | { |
| 7381 | IrInstSrc *error_return_trace = ir_build_error_return_trace_src(irb, scope, node, | 7444 | IrInstSrc *error_return_trace = ir_build_error_return_trace_src(irb, scope, node, |
| ... | @@ -19166,6 +19229,126 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport | ... | @@ -19166,6 +19229,126 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport |
| 19166 | return ir_const_void(ira, &instruction->base.base); | 19229 | return ir_const_void(ira, &instruction->base.base); |
| 19167 | } | 19230 | } |
| 19168 | | 19231 | |
| | 19232 | static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node); |
| | 19233 | |
| | 19234 | static IrInstGen *ir_analyze_instruction_extern(IrAnalyze *ira, IrInstSrcExtern *instruction) { |
| | 19235 | IrInstGen *type_inst = instruction->type->child; |
| | 19236 | if (type_is_invalid(type_inst->value->type)) |
| | 19237 | return ira->codegen->invalid_inst_gen; |
| | 19238 | |
| | 19239 | IrInstGen *options = instruction->options->child; |
| | 19240 | if (type_is_invalid(options->value->type)) |
| | 19241 | return ira->codegen->invalid_inst_gen; |
| | 19242 | |
| | 19243 | ZigType *options_type = options->value->type; |
| | 19244 | assert(options_type->id == ZigTypeIdStruct); |
| | 19245 | |
| | 19246 | TypeStructField *name_field = find_struct_type_field(options_type, buf_create_from_str("name")); |
| | 19247 | ir_assert(name_field != nullptr, &instruction->base.base); |
| | 19248 | IrInstGen *name_inst = ir_analyze_struct_value_field_value(ira, &instruction->base.base, options, name_field); |
| | 19249 | if (type_is_invalid(name_inst->value->type)) |
| | 19250 | return ira->codegen->invalid_inst_gen; |
| | 19251 | |
| | 19252 | TypeStructField *linkage_field = find_struct_type_field(options_type, buf_create_from_str("linkage")); |
| | 19253 | ir_assert(linkage_field != nullptr, &instruction->base.base); |
| | 19254 | IrInstGen *linkage_inst = ir_analyze_struct_value_field_value(ira, &instruction->base.base, options, linkage_field); |
| | 19255 | if (type_is_invalid(linkage_inst->value->type)) |
| | 19256 | return ira->codegen->invalid_inst_gen; |
| | 19257 | |
| | 19258 | TypeStructField *is_thread_local_field = find_struct_type_field(options_type, buf_create_from_str("is_thread_local")); |
| | 19259 | ir_assert(is_thread_local_field != nullptr, &instruction->base.base); |
| | 19260 | IrInstGen *is_thread_local_inst = ir_analyze_struct_value_field_value(ira, &instruction->base.base, options, is_thread_local_field); |
| | 19261 | if (type_is_invalid(is_thread_local_inst->value->type)) |
| | 19262 | return ira->codegen->invalid_inst_gen; |
| | 19263 | |
| | 19264 | TypeStructField *library_name_field = find_struct_type_field(options_type, buf_create_from_str("library_name")); |
| | 19265 | ir_assert(library_name_field != nullptr, &instruction->base.base); |
| | 19266 | IrInstGen *library_name_inst = ir_analyze_struct_value_field_value(ira, &instruction->base.base, options, library_name_field); |
| | 19267 | if (type_is_invalid(library_name_inst->value->type)) |
| | 19268 | return ira->codegen->invalid_inst_gen; |
| | 19269 | |
| | 19270 | // The `library_name` field is optional, we have to unwrap it first |
| | 19271 | IrInstGen *non_null_check = ir_analyze_test_non_null(ira, &instruction->base.base, library_name_inst); |
| | 19272 | bool is_non_null; |
| | 19273 | if (!ir_resolve_bool(ira, non_null_check, &is_non_null)) |
| | 19274 | return ira->codegen->invalid_inst_gen; |
| | 19275 | |
| | 19276 | IrInstGen *library_name_val_inst = nullptr; |
| | 19277 | if (is_non_null) { |
| | 19278 | library_name_val_inst = ir_analyze_optional_value_payload_value(ira, &instruction->base.base, library_name_inst, false); |
| | 19279 | if (type_is_invalid(library_name_val_inst->value->type)) |
| | 19280 | return ira->codegen->invalid_inst_gen; |
| | 19281 | } |
| | 19282 | |
| | 19283 | // Resolve all the comptime values |
| | 19284 | ZigType *value_type = ir_resolve_type(ira, type_inst); |
| | 19285 | if (type_is_invalid(value_type)) |
| | 19286 | return ira->codegen->invalid_inst_gen; |
| | 19287 | |
| | 19288 | if (get_src_ptr_type(value_type) == nullptr) { |
| | 19289 | ir_add_error(ira, &name_inst->base, |
| | 19290 | buf_sprintf("expected (optional) pointer type or function")); |
| | 19291 | return ira->codegen->invalid_inst_gen; |
| | 19292 | } |
| | 19293 | |
| | 19294 | Buf *symbol_name = ir_resolve_str(ira, name_inst); |
| | 19295 | if (!symbol_name) |
| | 19296 | return ira->codegen->invalid_inst_gen; |
| | 19297 | |
| | 19298 | if (buf_len(symbol_name) == 0) { |
| | 19299 | ir_add_error(ira, &name_inst->base, |
| | 19300 | buf_sprintf("extern symbol name cannot be empty")); |
| | 19301 | return ira->codegen->invalid_inst_gen; |
| | 19302 | } |
| | 19303 | |
| | 19304 | Buf *library_name = nullptr; |
| | 19305 | if (library_name_val_inst) { |
| | 19306 | library_name = ir_resolve_str(ira, library_name_val_inst); |
| | 19307 | if (!library_name) |
| | 19308 | return ira->codegen->invalid_inst_gen; |
| | 19309 | |
| | 19310 | if (buf_len(library_name) == 0) { |
| | 19311 | ir_add_error(ira, &library_name_inst->base, |
| | 19312 | buf_sprintf("library name name cannot be empty")); |
| | 19313 | return ira->codegen->invalid_inst_gen; |
| | 19314 | } |
| | 19315 | |
| | 19316 | add_link_lib_symbol(ira, library_name, symbol_name, instruction->base.base.source_node); |
| | 19317 | |
| | 19318 | buf_destroy(library_name); |
| | 19319 | } |
| | 19320 | |
| | 19321 | GlobalLinkageId global_linkage_id; |
| | 19322 | if (!ir_resolve_global_linkage(ira, linkage_inst, &global_linkage_id)) |
| | 19323 | return ira->codegen->invalid_inst_gen; |
| | 19324 | |
| | 19325 | bool is_thread_local; |
| | 19326 | if (!ir_resolve_bool(ira, is_thread_local_inst, &is_thread_local)) |
| | 19327 | return ira->codegen->invalid_inst_gen; |
| | 19328 | |
| | 19329 | ZigType *expr_type = value_type; |
| | 19330 | if (global_linkage_id == GlobalLinkageIdWeak && value_type->id != ZigTypeIdOptional) |
| | 19331 | expr_type = get_optional_type(ira->codegen, expr_type); |
| | 19332 | |
| | 19333 | // Create a bogus Tld object to keep track of the extern symbol. |
| | 19334 | // XXX: Find a better way to do this (in stage2). |
| | 19335 | TldFn *tld_fn = heap::c_allocator.create<TldFn>(); |
| | 19336 | tld_fn->base.id = TldIdFn; |
| | 19337 | tld_fn->base.source_node = instruction->base.base.source_node; |
| | 19338 | |
| | 19339 | auto entry = ira->codegen->external_symbol_names.put_unique(symbol_name, &tld_fn->base); |
| | 19340 | if (entry) { |
| | 19341 | AstNode *other_extern_node = entry->value->source_node; |
| | 19342 | ErrorMsg *msg = ir_add_error(ira, &instruction->base.base, |
| | 19343 | buf_sprintf("extern symbol collision: '%s'", buf_ptr(symbol_name))); |
| | 19344 | add_error_note(ira->codegen, msg, other_extern_node, buf_sprintf("other symbol is here")); |
| | 19345 | return ira->codegen->invalid_inst_gen; |
| | 19346 | } |
| | 19347 | |
| | 19348 | return ir_build_extern_gen(ira, &instruction->base.base, symbol_name, global_linkage_id, |
| | 19349 | is_thread_local, expr_type); |
| | 19350 | } |
| | 19351 | |
| 19169 | static bool exec_has_err_ret_trace(CodeGen *g, IrExecutableSrc *exec) { | 19352 | static bool exec_has_err_ret_trace(CodeGen *g, IrExecutableSrc *exec) { |
| 19170 | ZigFn *fn_entry = exec_fn_entry(exec); | 19353 | ZigFn *fn_entry = exec_fn_entry(exec); |
| 19171 | return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing; | 19354 | return fn_entry != nullptr && fn_entry->calls_or_awaits_errorable_fn && g->have_err_ret_tracing; |
| ... | @@ -32110,6 +32293,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc | ... | @@ -32110,6 +32293,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc |
| 32110 | return ir_analyze_instruction_tag_type(ira, (IrInstSrcTagType *)instruction); | 32293 | return ir_analyze_instruction_tag_type(ira, (IrInstSrcTagType *)instruction); |
| 32111 | case IrInstSrcIdExport: | 32294 | case IrInstSrcIdExport: |
| 32112 | return ir_analyze_instruction_export(ira, (IrInstSrcExport *)instruction); | 32295 | return ir_analyze_instruction_export(ira, (IrInstSrcExport *)instruction); |
| | 32296 | case IrInstSrcIdExtern: |
| | 32297 | return ir_analyze_instruction_extern(ira, (IrInstSrcExtern *)instruction); |
| 32113 | case IrInstSrcIdErrorReturnTrace: | 32298 | case IrInstSrcIdErrorReturnTrace: |
| 32114 | return ir_analyze_instruction_error_return_trace(ira, (IrInstSrcErrorReturnTrace *)instruction); | 32299 | return ir_analyze_instruction_error_return_trace(ira, (IrInstSrcErrorReturnTrace *)instruction); |
| 32115 | case IrInstSrcIdErrorUnion: | 32300 | case IrInstSrcIdErrorUnion: |
| ... | @@ -32345,6 +32530,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) { | ... | @@ -32345,6 +32530,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) { |
| 32345 | case IrInstGenIdAwait: | 32530 | case IrInstGenIdAwait: |
| 32346 | case IrInstGenIdSpillBegin: | 32531 | case IrInstGenIdSpillBegin: |
| 32347 | case IrInstGenIdWasmMemoryGrow: | 32532 | case IrInstGenIdWasmMemoryGrow: |
| | 32533 | case IrInstGenIdExtern: |
| 32348 | return true; | 32534 | return true; |
| 32349 | | 32535 | |
| 32350 | case IrInstGenIdPhi: | 32536 | case IrInstGenIdPhi: |
| ... | @@ -32465,6 +32651,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) { | ... | @@ -32465,6 +32651,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) { |
| 32465 | case IrInstSrcIdPtrType: | 32651 | case IrInstSrcIdPtrType: |
| 32466 | case IrInstSrcIdSetAlignStack: | 32652 | case IrInstSrcIdSetAlignStack: |
| 32467 | case IrInstSrcIdExport: | 32653 | case IrInstSrcIdExport: |
| | 32654 | case IrInstSrcIdExtern: |
| 32468 | case IrInstSrcIdSaveErrRetAddr: | 32655 | case IrInstSrcIdSaveErrRetAddr: |
| 32469 | case IrInstSrcIdAddImplicitReturnType: | 32656 | case IrInstSrcIdAddImplicitReturnType: |
| 32470 | case IrInstSrcIdAtomicRmw: | 32657 | case IrInstSrcIdAtomicRmw: |