authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-21 09:41:49-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-11-21 09:41:49-08:00
log7dcda5b0e8b2a6e001c4fa29d748cd093ca57436
tree75fdb247bdad82586755f01d647d0dc952c16cc4
parentbf0cc32aa64002299361a30c5e4b701e99da5dea
parentccdaf946b969661220737ec747e5a720b13d0bc7
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #7182 from LemonBoy/externnnn

Initial implementation of @extern builtin

6 files changed, 272 insertions(+), 5 deletions(-)

lib/std/builtin.zig+9
...@@ -643,6 +643,15 @@ pub const ExportOptions = struct {...@@ -643,6 +643,15 @@ pub const ExportOptions = struct {
643 section: ?[]const u8 = null,643 section: ?[]const u8 = null,
644};644};
645645
646/// This data structure is used by the Zig language code generation and
647/// therefore must be kept in sync with the compiler implementation.
648pub const ExternOptions = struct {
649 name: []const u8,
650 library_name: ?[]const u8 = null,
651 linkage: GlobalLinkage = .Strong,
652 is_thread_local: bool = false,
653};
654
646/// This function type is used by the Zig language code generation and655/// This function type is used by the Zig language code generation and
647/// therefore must be kept in sync with the compiler implementation.656/// therefore must be kept in sync with the compiler implementation.
648pub const TestFn = struct {657pub const TestFn = struct {
src/stage1/all_types.hpp+18
...@@ -1808,6 +1808,7 @@ enum BuiltinFnId {...@@ -1808,6 +1808,7 @@ enum BuiltinFnId {
1808 BuiltinFnIdThis,1808 BuiltinFnIdThis,
1809 BuiltinFnIdSetAlignStack,1809 BuiltinFnIdSetAlignStack,
1810 BuiltinFnIdExport,1810 BuiltinFnIdExport,
1811 BuiltinFnIdExtern,
1811 BuiltinFnIdErrorReturnTrace,1812 BuiltinFnIdErrorReturnTrace,
1812 BuiltinFnIdAtomicRmw,1813 BuiltinFnIdAtomicRmw,
1813 BuiltinFnIdAtomicLoad,1814 BuiltinFnIdAtomicLoad,
...@@ -2619,6 +2620,7 @@ enum IrInstSrcId {...@@ -2619,6 +2620,7 @@ enum IrInstSrcId {
2619 IrInstSrcIdSetAlignStack,2620 IrInstSrcIdSetAlignStack,
2620 IrInstSrcIdArgType,2621 IrInstSrcIdArgType,
2621 IrInstSrcIdExport,2622 IrInstSrcIdExport,
2623 IrInstSrcIdExtern,
2622 IrInstSrcIdErrorReturnTrace,2624 IrInstSrcIdErrorReturnTrace,
2623 IrInstSrcIdErrorUnion,2625 IrInstSrcIdErrorUnion,
2624 IrInstSrcIdAtomicRmw,2626 IrInstSrcIdAtomicRmw,
...@@ -2736,6 +2738,7 @@ enum IrInstGenId {...@@ -2736,6 +2738,7 @@ enum IrInstGenId {
2736 IrInstGenIdConst,2738 IrInstGenIdConst,
2737 IrInstGenIdWasmMemorySize,2739 IrInstGenIdWasmMemorySize,
2738 IrInstGenIdWasmMemoryGrow,2740 IrInstGenIdWasmMemoryGrow,
2741 IrInstGenIdExtern,
2739};2742};
27402743
2741// Common fields between IrInstSrc and IrInstGen. This allows future passes2744// Common fields between IrInstSrc and IrInstGen. This allows future passes
...@@ -4146,6 +4149,21 @@ struct IrInstSrcExport {...@@ -4146,6 +4149,21 @@ struct IrInstSrcExport {
4146 IrInstSrc *options;4149 IrInstSrc *options;
4147};4150};
41484151
4152struct IrInstSrcExtern {
4153 IrInstSrc base;
4154
4155 IrInstSrc *type;
4156 IrInstSrc *options;
4157};
4158
4159struct IrInstGenExtern {
4160 IrInstGen base;
4161
4162 Buf *name;
4163 GlobalLinkageId linkage;
4164 bool is_thread_local;
4165};
4166
4149enum IrInstErrorReturnTraceOptional {4167enum IrInstErrorReturnTraceOptional {
4150 IrInstErrorReturnTraceNull,4168 IrInstErrorReturnTraceNull,
4151 IrInstErrorReturnTraceNonNull,4169 IrInstErrorReturnTraceNonNull,
src/stage1/codegen.cpp+27
...@@ -6389,6 +6389,30 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutableGen *executable, IrI...@@ -6389,6 +6389,30 @@ static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutableGen *executable, IrI
6389 return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), "");6389 return LLVMBuildTrunc(g->builder, shifted, get_llvm_type(g, expr_type), "");
6390}6390}
63916391
6392static LLVMValueRef ir_render_extern(CodeGen *g, IrExecutableGen *executable,
6393 IrInstGenExtern *instruction)
6394{
6395 ZigType *expr_type = instruction->base.value->type;
6396 assert(get_src_ptr_type(expr_type));
6397
6398 const char *symbol_name = buf_ptr(instruction->name);
6399 const LLVMLinkage linkage = to_llvm_linkage(instruction->linkage, true);
6400
6401 LLVMValueRef global_value = LLVMGetNamedGlobal(g->module, symbol_name);
6402 if (global_value == nullptr) {
6403 global_value = LLVMAddGlobal(g->module, get_llvm_type(g, expr_type), symbol_name);
6404 LLVMSetLinkage(global_value, linkage);
6405 LLVMSetGlobalConstant(global_value, true);
6406 if (instruction->is_thread_local)
6407 LLVMSetThreadLocalMode(global_value, LLVMGeneralDynamicTLSModel);
6408 } else if (LLVMGetLinkage(global_value) != linkage) {
6409 // XXX: Handle this case better!
6410 zig_panic("duplicate extern symbol");
6411 }
6412
6413 return LLVMBuildBitCast(g->builder, global_value, get_llvm_type(g, expr_type), "");
6414}
6415
6392static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutableGen *executable, IrInstGenBitReverse *instruction) {6416static LLVMValueRef ir_render_bit_reverse(CodeGen *g, IrExecutableGen *executable, IrInstGenBitReverse *instruction) {
6393 LLVMValueRef op = ir_llvm_value(g, instruction->op);6417 LLVMValueRef op = ir_llvm_value(g, instruction->op);
6394 ZigType *int_type = instruction->base.value->type;6418 ZigType *int_type = instruction->base.value->type;
...@@ -6902,6 +6926,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl...@@ -6902,6 +6926,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutableGen *executabl
6902 return ir_render_wasm_memory_size(g, executable, (IrInstGenWasmMemorySize *) instruction);6926 return ir_render_wasm_memory_size(g, executable, (IrInstGenWasmMemorySize *) instruction);
6903 case IrInstGenIdWasmMemoryGrow:6927 case IrInstGenIdWasmMemoryGrow:
6904 return ir_render_wasm_memory_grow(g, executable, (IrInstGenWasmMemoryGrow *) instruction);6928 return ir_render_wasm_memory_grow(g, executable, (IrInstGenWasmMemoryGrow *) instruction);
6929 case IrInstGenIdExtern:
6930 return ir_render_extern(g, executable, (IrInstGenExtern *) instruction);
6905 }6931 }
6906 zig_unreachable();6932 zig_unreachable();
6907}6933}
...@@ -8800,6 +8826,7 @@ static void define_builtin_fns(CodeGen *g) {...@@ -8800,6 +8826,7 @@ static void define_builtin_fns(CodeGen *g) {
8800 create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);8826 create_builtin_fn(g, BuiltinFnIdAlignCast, "alignCast", 2);
8801 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);8827 create_builtin_fn(g, BuiltinFnIdSetAlignStack, "setAlignStack", 1);
8802 create_builtin_fn(g, BuiltinFnIdExport, "export", 2);8828 create_builtin_fn(g, BuiltinFnIdExport, "export", 2);
8829 create_builtin_fn(g, BuiltinFnIdExtern, "extern", 2);
8803 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);8830 create_builtin_fn(g, BuiltinFnIdErrorReturnTrace, "errorReturnTrace", 0);
8804 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);8831 create_builtin_fn(g, BuiltinFnIdAtomicRmw, "atomicRmw", 5);
8805 create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);8832 create_builtin_fn(g, BuiltinFnIdAtomicLoad, "atomicLoad", 3);
src/stage1/ir.cpp+187
...@@ -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}
15571561
1562static constexpr IrInstSrcId ir_inst_id(IrInstSrcExtern *) {
1563 return IrInstSrcIdExtern;
1564}
1565
1558static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorReturnTrace *) {1566static 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}
20012009
2010static constexpr IrInstGenId ir_inst_id(IrInstGenExtern *) {
2011 return IrInstGenIdExtern;
2012}
2013
2002template<typename T>2014template<typename T>
2003static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {2015static 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}
28092821
2822static 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
2836static 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
2810static IrInstSrc *ir_build_load_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *ptr) {2849static 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}
1916819231
19232static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, AstNode *source_node);
19233
19234static 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
19169static bool exec_has_err_ret_trace(CodeGen *g, IrExecutableSrc *exec) {19352static 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;
...@@ -32112,6 +32295,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc...@@ -32112,6 +32295,8 @@ static IrInstGen *ir_analyze_instruction_base(IrAnalyze *ira, IrInstSrc *instruc
32112 return ir_analyze_instruction_tag_type(ira, (IrInstSrcTagType *)instruction);32295 return ir_analyze_instruction_tag_type(ira, (IrInstSrcTagType *)instruction);
32113 case IrInstSrcIdExport:32296 case IrInstSrcIdExport:
32114 return ir_analyze_instruction_export(ira, (IrInstSrcExport *)instruction);32297 return ir_analyze_instruction_export(ira, (IrInstSrcExport *)instruction);
32298 case IrInstSrcIdExtern:
32299 return ir_analyze_instruction_extern(ira, (IrInstSrcExtern *)instruction);
32115 case IrInstSrcIdErrorReturnTrace:32300 case IrInstSrcIdErrorReturnTrace:
32116 return ir_analyze_instruction_error_return_trace(ira, (IrInstSrcErrorReturnTrace *)instruction);32301 return ir_analyze_instruction_error_return_trace(ira, (IrInstSrcErrorReturnTrace *)instruction);
32117 case IrInstSrcIdErrorUnion:32302 case IrInstSrcIdErrorUnion:
...@@ -32347,6 +32532,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {...@@ -32347,6 +32532,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {
32347 case IrInstGenIdAwait:32532 case IrInstGenIdAwait:
32348 case IrInstGenIdSpillBegin:32533 case IrInstGenIdSpillBegin:
32349 case IrInstGenIdWasmMemoryGrow:32534 case IrInstGenIdWasmMemoryGrow:
32535 case IrInstGenIdExtern:
32350 return true;32536 return true;
3235132537
32352 case IrInstGenIdPhi:32538 case IrInstGenIdPhi:
...@@ -32467,6 +32653,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {...@@ -32467,6 +32653,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
32467 case IrInstSrcIdPtrType:32653 case IrInstSrcIdPtrType:
32468 case IrInstSrcIdSetAlignStack:32654 case IrInstSrcIdSetAlignStack:
32469 case IrInstSrcIdExport:32655 case IrInstSrcIdExport:
32656 case IrInstSrcIdExtern:
32470 case IrInstSrcIdSaveErrRetAddr:32657 case IrInstSrcIdSaveErrRetAddr:
32471 case IrInstSrcIdAddImplicitReturnType:32658 case IrInstSrcIdAddImplicitReturnType:
32472 case IrInstSrcIdAtomicRmw:32659 case IrInstSrcIdAtomicRmw:
src/stage1/ir_print.cpp+23
...@@ -314,6 +314,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {...@@ -314,6 +314,8 @@ const char* ir_inst_src_type_str(IrInstSrcId id) {
314 return "SrcArgType";314 return "SrcArgType";
315 case IrInstSrcIdExport:315 case IrInstSrcIdExport:
316 return "SrcExport";316 return "SrcExport";
317 case IrInstSrcIdExtern:
318 return "SrcExtern";
317 case IrInstSrcIdErrorReturnTrace:319 case IrInstSrcIdErrorReturnTrace:
318 return "SrcErrorReturnTrace";320 return "SrcErrorReturnTrace";
319 case IrInstSrcIdErrorUnion:321 case IrInstSrcIdErrorUnion:
...@@ -544,6 +546,8 @@ const char* ir_inst_gen_type_str(IrInstGenId id) {...@@ -544,6 +546,8 @@ const char* ir_inst_gen_type_str(IrInstGenId id) {
544 return "GenWasmMemorySize";546 return "GenWasmMemorySize";
545 case IrInstGenIdWasmMemoryGrow:547 case IrInstGenIdWasmMemoryGrow:
546 return "GenWasmMemoryGrow";548 return "GenWasmMemoryGrow";
549 case IrInstGenIdExtern:
550 return "GenExtrern";
547 }551 }
548 zig_unreachable();552 zig_unreachable();
549}553}
...@@ -2364,6 +2368,18 @@ static void ir_print_export(IrPrintSrc *irp, IrInstSrcExport *instruction) {...@@ -2364,6 +2368,18 @@ static void ir_print_export(IrPrintSrc *irp, IrInstSrcExport *instruction) {
2364 fprintf(irp->f, ")");2368 fprintf(irp->f, ")");
2365}2369}
23662370
2371static void ir_print_extern(IrPrintGen *irp, IrInstGenExtern *instruction) {
2372 fprintf(irp->f, "@extern(...)");
2373}
2374
2375static void ir_print_extern(IrPrintSrc *irp, IrInstSrcExtern *instruction) {
2376 fprintf(irp->f, "@extern(");
2377 ir_print_other_inst_src(irp, instruction->type);
2378 fprintf(irp->f, ",");
2379 ir_print_other_inst_src(irp, instruction->options);
2380 fprintf(irp->f, ")");
2381}
2382
2367static void ir_print_error_return_trace(IrPrintSrc *irp, IrInstSrcErrorReturnTrace *instruction) {2383static void ir_print_error_return_trace(IrPrintSrc *irp, IrInstSrcErrorReturnTrace *instruction) {
2368 fprintf(irp->f, "@errorReturnTrace(");2384 fprintf(irp->f, "@errorReturnTrace(");
2369 switch (instruction->optional) {2385 switch (instruction->optional) {
...@@ -2943,6 +2959,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai...@@ -2943,6 +2959,9 @@ static void ir_print_inst_src(IrPrintSrc *irp, IrInstSrc *instruction, bool trai
2943 case IrInstSrcIdExport:2959 case IrInstSrcIdExport:
2944 ir_print_export(irp, (IrInstSrcExport *)instruction);2960 ir_print_export(irp, (IrInstSrcExport *)instruction);
2945 break;2961 break;
2962 case IrInstSrcIdExtern:
2963 ir_print_extern(irp, (IrInstSrcExtern*)instruction);
2964 break;
2946 case IrInstSrcIdErrorReturnTrace:2965 case IrInstSrcIdErrorReturnTrace:
2947 ir_print_error_return_trace(irp, (IrInstSrcErrorReturnTrace *)instruction);2966 ir_print_error_return_trace(irp, (IrInstSrcErrorReturnTrace *)instruction);
2948 break;2967 break;
...@@ -3294,6 +3313,10 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai...@@ -3294,6 +3313,10 @@ static void ir_print_inst_gen(IrPrintGen *irp, IrInstGen *instruction, bool trai
3294 case IrInstGenIdWasmMemoryGrow:3313 case IrInstGenIdWasmMemoryGrow:
3295 ir_print_wasm_memory_grow(irp, (IrInstGenWasmMemoryGrow *)instruction);3314 ir_print_wasm_memory_grow(irp, (IrInstGenWasmMemoryGrow *)instruction);
3296 break;3315 break;
3316 case IrInstGenIdExtern:
3317 ir_print_extern(irp, (IrInstGenExtern *)instruction);
3318 break;
3319
3297 }3320 }
3298 fprintf(irp->f, "\n");3321 fprintf(irp->f, "\n");
3299}3322}
src/stage1/parser.cpp+8-5
...@@ -1652,18 +1652,21 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {...@@ -1652,18 +1652,21 @@ static AstNode *ast_parse_primary_type_expr(ParseContext *pc) {
1652 // TODO: This is not in line with the grammar.1652 // TODO: This is not in line with the grammar.
1653 // Because the prev stage 1 tokenizer does not parse1653 // Because the prev stage 1 tokenizer does not parse
1654 // @[a-zA-Z_][a-zA-Z0-9_] as one token, it has to do a1654 // @[a-zA-Z_][a-zA-Z0-9_] as one token, it has to do a
1655 // hack, where it accepts '@' (IDENTIFIER / KEYWORD_export).1655 // hack, where it accepts '@' (IDENTIFIER / KEYWORD_export /
1656 // KEYWORD_extern).
1656 // I'd say that it's better if '@' is part of the builtin1657 // I'd say that it's better if '@' is part of the builtin
1657 // identifier token.1658 // identifier token.
1658 Token *at_sign = eat_token_if(pc, TokenIdAtSign);1659 Token *at_sign = eat_token_if(pc, TokenIdAtSign);
1659 if (at_sign != nullptr) {1660 if (at_sign != nullptr) {
1660 Buf *name;1661 Buf *name;
1661 Token *token = eat_token_if(pc, TokenIdKeywordExport);1662 Token *token;
1662 if (token == nullptr) {1663 if ((token = eat_token_if(pc, TokenIdKeywordExport)) != nullptr) {
1664 name = buf_create_from_str("export");
1665 } else if ((token = eat_token_if(pc, TokenIdKeywordExtern)) != nullptr) {
1666 name = buf_create_from_str("extern");
1667 } else {
1663 token = expect_token(pc, TokenIdSymbol);1668 token = expect_token(pc, TokenIdSymbol);
1664 name = token_buf(token);1669 name = token_buf(token);
1665 } else {
1666 name = buf_create_from_str("export");
1667 }1670 }
16681671
1669 AstNode *res = ast_expect(pc, ast_parse_fn_call_arguments);1672 AstNode *res = ast_expect(pc, ast_parse_fn_call_arguments);