@@ -519,6 +519,8 @@ static void destroy_instruction_src(IrInstSrc *inst) {
519
519
return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcTagType *>(inst));
520
520
case IrInstSrcIdExport:
521
521
return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExport *>(inst));
522
+ case IrInstSrcIdExtern:
523
+ return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcExtern *>(inst));
522
524
case IrInstSrcIdErrorReturnTrace:
523
525
return heap::c_allocator.destroy(reinterpret_cast<IrInstSrcErrorReturnTrace *>(inst));
524
526
case IrInstSrcIdErrorUnion:
@@ -755,6 +757,8 @@ void destroy_instruction_gen(IrInstGen *inst) {
755
757
return heap::c_allocator.destroy(reinterpret_cast<IrInstGenWasmMemorySize *>(inst));
756
758
case IrInstGenIdWasmMemoryGrow:
757
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
763
zig_unreachable();
760
764
}
@@ -1555,6 +1559,10 @@ static constexpr IrInstSrcId ir_inst_id(IrInstSrcExport *) {
1555
1559
return IrInstSrcIdExport;
1556
1560
}
1557
1561
1562
+ static constexpr IrInstSrcId ir_inst_id(IrInstSrcExtern *) {
1563
+ return IrInstSrcIdExtern;
1564
+ }
1565
+
1558
1566
static constexpr IrInstSrcId ir_inst_id(IrInstSrcErrorReturnTrace *) {
1559
1567
return IrInstSrcIdErrorReturnTrace;
1560
1568
}
@@ -1999,6 +2007,10 @@ static constexpr IrInstGenId ir_inst_id(IrInstGenWasmMemoryGrow *) {
1999
2007
return IrInstGenIdWasmMemoryGrow;
2000
2008
}
2001
2009
2010
+ static constexpr IrInstGenId ir_inst_id(IrInstGenExtern *) {
2011
+ return IrInstGenIdExtern;
2012
+ }
2013
+
2002
2014
template<typename T>
2003
2015
static T *ir_create_instruction(IrBuilderSrc *irb, Scope *scope, AstNode *source_node) {
2004
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
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
2849
static IrInstSrc *ir_build_load_ptr(IrBuilderSrc *irb, Scope *scope, AstNode *source_node, IrInstSrc *ptr) {
2811
2850
IrInstSrcLoadPtr *instruction = ir_build_instruction<IrInstSrcLoadPtr>(irb, scope, source_node);
2812
2851
instruction->ptr = ptr;
@@ -7376,6 +7415,30 @@ static IrInstSrc *ir_gen_builtin_fn_call(IrBuilderSrc *irb, Scope *scope, AstNod
7376
7415
IrInstSrc *ir_export = ir_build_export(irb, scope, node, target_value, casted_options_value);
7377
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
7442
case BuiltinFnIdErrorReturnTrace:
7380
7443
{
7381
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
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
19352
static bool exec_has_err_ret_trace(CodeGen *g, IrExecutableSrc *exec) {
19170
19353
ZigFn *fn_entry = exec_fn_entry(exec);
19171
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
32295
return ir_analyze_instruction_tag_type(ira, (IrInstSrcTagType *)instruction);
32113
32296
case IrInstSrcIdExport:
32114
32297
return ir_analyze_instruction_export(ira, (IrInstSrcExport *)instruction);
32298
+ case IrInstSrcIdExtern:
32299
+ return ir_analyze_instruction_extern(ira, (IrInstSrcExtern *)instruction);
32115
32300
case IrInstSrcIdErrorReturnTrace:
32116
32301
return ir_analyze_instruction_error_return_trace(ira, (IrInstSrcErrorReturnTrace *)instruction);
32117
32302
case IrInstSrcIdErrorUnion:
@@ -32347,6 +32532,7 @@ bool ir_inst_gen_has_side_effects(IrInstGen *instruction) {
32347
32532
case IrInstGenIdAwait:
32348
32533
case IrInstGenIdSpillBegin:
32349
32534
case IrInstGenIdWasmMemoryGrow:
32535
+ case IrInstGenIdExtern:
32350
32536
return true;
32351
32537
32352
32538
case IrInstGenIdPhi:
@@ -32467,6 +32653,7 @@ bool ir_inst_src_has_side_effects(IrInstSrc *instruction) {
32467
32653
case IrInstSrcIdPtrType:
32468
32654
case IrInstSrcIdSetAlignStack:
32469
32655
case IrInstSrcIdExport:
32656
+ case IrInstSrcIdExtern:
32470
32657
case IrInstSrcIdSaveErrRetAddr:
32471
32658
case IrInstSrcIdAddImplicitReturnType:
32472
32659
case IrInstSrcIdAtomicRmw:
0 commit comments