| author | |
| committer | |
| log | 9654a54d4a2729200d38dbb6eec827cb03dc0f90 |
| tree | 3b96d72cca0cb34c99f9a60f4b093e1fa4052dea |
| parent | 67c4b16d6e27f1d81e2e2f837bd53d958b9baa33 |
Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>9 files changed, 95 insertions(+), 9 deletions(-)
lib/std/builtin.zig+9| ... | ... | @@ -68,6 +68,14 @@ pub const GlobalLinkage = enum { |
| 68 | 68 | LinkOnce, |
| 69 | 69 | }; |
| 70 | 70 | |
| 71 | /// This data structure is used by the Zig language code generation and | |
| 72 | /// therefore must be kept in sync with the compiler implementation. | |
| 73 | pub const GlobalVisibility = enum { | |
| 74 | default, | |
| 75 | hidden, | |
| 76 | protected, | |
| 77 | }; | |
| 78 | ||
| 71 | 79 | /// This data structure is used by the Zig language code generation and |
| 72 | 80 | /// therefore must be kept in sync with the compiler implementation. |
| 73 | 81 | pub const AtomicOrder = enum { |
| ... | ... | @@ -655,6 +663,7 @@ pub const ExportOptions = struct { |
| 655 | 663 | name: []const u8, |
| 656 | 664 | linkage: GlobalLinkage = .Strong, |
| 657 | 665 | section: ?[]const u8 = null, |
| 666 | visibility: GlobalVisibility = .default, | |
| 658 | 667 | }; |
| 659 | 668 | |
| 660 | 669 | /// This data structure is used by the Zig language code generation and |
src/Sema.zig+5| ... | ... | @@ -4348,6 +4348,7 @@ pub fn analyzeExport( |
| 4348 | 4348 | .name = symbol_name, |
| 4349 | 4349 | .linkage = borrowed_options.linkage, |
| 4350 | 4350 | .section = section, |
| 4351 | .visibility = borrowed_options.visibility, | |
| 4351 | 4352 | }, |
| 4352 | 4353 | .src = src, |
| 4353 | 4354 | .link = switch (mod.comp.bin_file.tag) { |
| ... | ... | @@ -15007,6 +15008,9 @@ fn resolveExportOptions( |
| 15007 | 15008 | const section = try sema.fieldVal(block, src, options, "section", src); |
| 15008 | 15009 | const section_val = try sema.resolveConstValue(block, src, section); |
| 15009 | 15010 | |
| 15011 | const visibility = try sema.fieldVal(block, src, options, "visibility", src); | |
| 15012 | const visibility_val = try sema.resolveConstValue(block, src, visibility); | |
| 15013 | ||
| 15010 | 15014 | if (!section_val.isNull()) { |
| 15011 | 15015 | return sema.fail(block, src, "TODO: implement exporting with linksection", .{}); |
| 15012 | 15016 | } |
| ... | ... | @@ -15015,6 +15019,7 @@ fn resolveExportOptions( |
| 15015 | 15019 | .name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod), |
| 15016 | 15020 | .linkage = linkage_val.toEnum(std.builtin.GlobalLinkage), |
| 15017 | 15021 | .section = null, // TODO |
| 15022 | .visibility = visibility_val.toEnum(std.builtin.GlobalVisibility), | |
| 15018 | 15023 | }; |
| 15019 | 15024 | } |
| 15020 | 15025 |
src/codegen/llvm.zig+5| ... | ... | @@ -808,6 +808,11 @@ pub const Object = struct { |
| 808 | 808 | .Weak => llvm_global.setLinkage(.WeakODR), |
| 809 | 809 | .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), |
| 810 | 810 | } |
| 811 | switch (exports[0].options.visibility) { | |
| 812 | .default => llvm_global.setVisibility(.Default), | |
| 813 | .hidden => llvm_global.setVisibility(.Hidden), | |
| 814 | .protected => llvm_global.setVisibility(.Protected), | |
| 815 | } | |
| 811 | 816 | if (decl.val.castTag(.variable)) |variable| { |
| 812 | 817 | if (variable.data.is_threadlocal) { |
| 813 | 818 | llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel); |
src/codegen/llvm/bindings.zig+9| ... | ... | @@ -117,6 +117,9 @@ pub const Value = opaque { |
| 117 | 117 | pub const setLinkage = LLVMSetLinkage; |
| 118 | 118 | extern fn LLVMSetLinkage(Global: *const Value, Linkage: Linkage) void; |
| 119 | 119 | |
| 120 | pub const setVisibility = LLVMSetVisibility; | |
| 121 | extern fn LLVMSetVisibility(Global: *const Value, Linkage: Visibility) void; | |
| 122 | ||
| 120 | 123 | pub const setUnnamedAddr = LLVMSetUnnamedAddr; |
| 121 | 124 | extern fn LLVMSetUnnamedAddr(Global: *const Value, HasUnnamedAddr: Bool) void; |
| 122 | 125 | |
| ... | ... | @@ -1324,6 +1327,12 @@ pub const Linkage = enum(c_uint) { |
| 1324 | 1327 | LinkerPrivateWeak, |
| 1325 | 1328 | }; |
| 1326 | 1329 | |
| 1330 | pub const Visibility = enum(c_uint) { | |
| 1331 | Default, | |
| 1332 | Hidden, | |
| 1333 | Protected, | |
| 1334 | }; | |
| 1335 | ||
| 1327 | 1336 | pub const ThreadLocalMode = enum(c_uint) { |
| 1328 | 1337 | NotThreadLocal, |
| 1329 | 1338 | GeneralDynamicTLSModel, |
src/stage1/all_types.hpp+7| ... | ... | @@ -571,6 +571,12 @@ enum GlobalLinkageId { |
| 571 | 571 | GlobalLinkageIdLinkOnce, |
| 572 | 572 | }; |
| 573 | 573 | |
| 574 | enum GlobalVisibilityId { | |
| 575 | GlobalVisibilityIdDefault, | |
| 576 | GlobalVisibilityIdHidden, | |
| 577 | GlobalVisibilityIdProtected, | |
| 578 | }; | |
| 579 | ||
| 574 | 580 | enum TldId { |
| 575 | 581 | TldIdVar, |
| 576 | 582 | TldIdFn, |
| ... | ... | @@ -1654,6 +1660,7 @@ enum FnAnalState { |
| 1654 | 1660 | struct GlobalExport { |
| 1655 | 1661 | Buf name; |
| 1656 | 1662 | GlobalLinkageId linkage; |
| 1663 | GlobalVisibilityId visibility; | |
| 1657 | 1664 | }; |
| 1658 | 1665 | |
| 1659 | 1666 | struct ZigFn { |
src/stage1/analyze.cpp+7-5| ... | ... | @@ -3717,14 +3717,15 @@ ZigType *get_test_fn_type(CodeGen *g) { |
| 3717 | 3717 | return g->test_fn_type; |
| 3718 | 3718 | } |
| 3719 | 3719 | |
| 3720 | void add_var_export(CodeGen *g, ZigVar *var, const char *symbol_name, GlobalLinkageId linkage) { | |
| 3720 | void add_var_export(CodeGen *g, ZigVar *var, const char *symbol_name, GlobalLinkageId linkage, GlobalVisibilityId visibility) { | |
| 3721 | 3721 | GlobalExport *global_export = var->export_list.add_one(); |
| 3722 | 3722 | memset(global_export, 0, sizeof(GlobalExport)); |
| 3723 | 3723 | buf_init_from_str(&global_export->name, symbol_name); |
| 3724 | 3724 | global_export->linkage = linkage; |
| 3725 | global_export->visibility = visibility; | |
| 3725 | 3726 | } |
| 3726 | 3727 | |
| 3727 | void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, CallingConvention cc) { | |
| 3728 | void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, GlobalVisibilityId visibility, CallingConvention cc) { | |
| 3728 | 3729 | CallingConvention winapi_cc = g->zig_target->arch == ZigLLVM_x86 |
| 3729 | 3730 | ? CallingConventionStdcall |
| 3730 | 3731 | : CallingConventionC; |
| ... | ... | @@ -3749,6 +3750,7 @@ void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, G |
| 3749 | 3750 | memset(fn_export, 0, sizeof(GlobalExport)); |
| 3750 | 3751 | buf_init_from_str(&fn_export->name, symbol_name); |
| 3751 | 3752 | fn_export->linkage = linkage; |
| 3753 | fn_export->visibility = visibility; | |
| 3752 | 3754 | } |
| 3753 | 3755 | |
| 3754 | 3756 | static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| ... | ... | @@ -3852,13 +3854,13 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 3852 | 3854 | case CallingConventionWin64: |
| 3853 | 3855 | case CallingConventionPtxKernel: |
| 3854 | 3856 | add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), |
| 3855 | GlobalLinkageIdStrong, fn_cc); | |
| 3857 | GlobalLinkageIdStrong, GlobalVisibilityIdDefault, fn_cc); | |
| 3856 | 3858 | break; |
| 3857 | 3859 | case CallingConventionUnspecified: |
| 3858 | 3860 | // An exported function without a specific calling |
| 3859 | 3861 | // convention defaults to C |
| 3860 | 3862 | add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), |
| 3861 | GlobalLinkageIdStrong, CallingConventionC); | |
| 3863 | GlobalLinkageIdStrong, GlobalVisibilityIdDefault, CallingConventionC); | |
| 3862 | 3864 | break; |
| 3863 | 3865 | } |
| 3864 | 3866 | } |
| ... | ... | @@ -4321,7 +4323,7 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { |
| 4321 | 4323 | |
| 4322 | 4324 | if (is_export) { |
| 4323 | 4325 | validate_export_var_type(g, type, source_node); |
| 4324 | add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong); | |
| 4326 | add_var_export(g, tld_var->var, tld_var->var->name, GlobalLinkageIdStrong, GlobalVisibilityIdDefault); | |
| 4325 | 4327 | } |
| 4326 | 4328 | |
| 4327 | 4329 | if (is_extern) { |
src/stage1/analyze.hpp+2-2| ... | ... | @@ -221,8 +221,8 @@ ZigType *get_align_amt_type(CodeGen *g); |
| 221 | 221 | ZigPackage *new_anonymous_package(void); |
| 222 | 222 | |
| 223 | 223 | Buf *const_value_to_buffer(ZigValue *const_val); |
| 224 | void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, CallingConvention cc); | |
| 225 | void add_var_export(CodeGen *g, ZigVar *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage); | |
| 224 | void add_fn_export(CodeGen *g, ZigFn *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, GlobalVisibilityId visibility, CallingConvention cc); | |
| 225 | void add_var_export(CodeGen *g, ZigVar *fn_table_entry, const char *symbol_name, GlobalLinkageId linkage, GlobalVisibilityId visibility); | |
| 226 | 226 | |
| 227 | 227 | |
| 228 | 228 | ZigValue *get_builtin_value(CodeGen *codegen, const char *name); |
src/stage1/codegen.cpp+20| ... | ... | @@ -242,6 +242,18 @@ static LLVMLinkage to_llvm_linkage(GlobalLinkageId id, bool is_extern) { |
| 242 | 242 | zig_unreachable(); |
| 243 | 243 | } |
| 244 | 244 | |
| 245 | static LLVMVisibility to_llvm_visibility(GlobalVisibilityId id) { | |
| 246 | switch (id) { | |
| 247 | case GlobalVisibilityIdDefault: | |
| 248 | return LLVMDefaultVisibility; | |
| 249 | case GlobalVisibilityIdHidden: | |
| 250 | return LLVMHiddenVisibility; | |
| 251 | case GlobalVisibilityIdProtected: | |
| 252 | return LLVMProtectedVisibility; | |
| 253 | } | |
| 254 | zig_unreachable(); | |
| 255 | } | |
| 256 | ||
| 245 | 257 | struct CalcLLVMFieldIndex { |
| 246 | 258 | uint32_t offset; |
| 247 | 259 | uint32_t field_index; |
| ... | ... | @@ -400,6 +412,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 400 | 412 | const char *unmangled_name = buf_ptr(&fn->symbol_name); |
| 401 | 413 | const char *symbol_name; |
| 402 | 414 | GlobalLinkageId linkage; |
| 415 | GlobalVisibilityId visibility = GlobalVisibilityIdDefault; | |
| 403 | 416 | if (fn->body_node == nullptr) { |
| 404 | 417 | symbol_name = unmangled_name; |
| 405 | 418 | linkage = GlobalLinkageIdStrong; |
| ... | ... | @@ -410,6 +423,7 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 410 | 423 | GlobalExport *fn_export = &fn->export_list.items[0]; |
| 411 | 424 | symbol_name = buf_ptr(&fn_export->name); |
| 412 | 425 | linkage = fn_export->linkage; |
| 426 | visibility = fn_export->visibility; | |
| 413 | 427 | } |
| 414 | 428 | |
| 415 | 429 | CallingConvention cc = fn->type_entry->data.fn.fn_type_id.cc; |
| ... | ... | @@ -532,6 +546,8 @@ static LLVMValueRef make_fn_llvm_value(CodeGen *g, ZigFn *fn) { |
| 532 | 546 | LLVMSetUnnamedAddr(llvm_fn, true); |
| 533 | 547 | } |
| 534 | 548 | |
| 549 | LLVMSetVisibility(llvm_fn, to_llvm_visibility(visibility)); | |
| 550 | ||
| 535 | 551 | ZigType *return_type = fn_type->data.fn.fn_type_id.return_type; |
| 536 | 552 | if (return_type->id == ZigTypeIdUnreachable) { |
| 537 | 553 | addLLVMFnAttr(llvm_fn, "noreturn"); |
| ... | ... | @@ -8951,6 +8967,7 @@ static void do_code_gen(CodeGen *g) { |
| 8951 | 8967 | assert(var->decl_node); |
| 8952 | 8968 | |
| 8953 | 8969 | GlobalLinkageId linkage; |
| 8970 | GlobalVisibilityId visibility = GlobalVisibilityIdDefault; | |
| 8954 | 8971 | const char *unmangled_name = var->name; |
| 8955 | 8972 | const char *symbol_name; |
| 8956 | 8973 | if (var->export_list.length == 0) { |
| ... | ... | @@ -8965,6 +8982,7 @@ static void do_code_gen(CodeGen *g) { |
| 8965 | 8982 | GlobalExport *global_export = &var->export_list.items[0]; |
| 8966 | 8983 | symbol_name = buf_ptr(&global_export->name); |
| 8967 | 8984 | linkage = global_export->linkage; |
| 8985 | visibility = global_export->visibility; | |
| 8968 | 8986 | } |
| 8969 | 8987 | |
| 8970 | 8988 | LLVMValueRef global_value; |
| ... | ... | @@ -9010,6 +9028,8 @@ static void do_code_gen(CodeGen *g) { |
| 9010 | 9028 | set_global_tls(g, var, global_value); |
| 9011 | 9029 | } |
| 9012 | 9030 | |
| 9031 | LLVMSetVisibility(global_value, to_llvm_visibility(visibility)); | |
| 9032 | ||
| 9013 | 9033 | var->value_ref = global_value; |
| 9014 | 9034 | |
| 9015 | 9035 | for (size_t export_i = 1; export_i < var->export_list.length; export_i += 1) { |
src/stage1/ir.cpp+31-2| ... | ... | @@ -8635,6 +8635,25 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, Stage1AirInst *value, Glob |
| 8635 | 8635 | return true; |
| 8636 | 8636 | } |
| 8637 | 8637 | |
| 8638 | static bool ir_resolve_global_visibility(IrAnalyze *ira, Stage1AirInst *value, GlobalVisibilityId *out) { | |
| 8639 | if (type_is_invalid(value->value->type)) | |
| 8640 | return false; | |
| 8641 | ||
| 8642 | ZigType *global_visibility_type = get_builtin_type(ira->codegen, "GlobalVisibility"); | |
| 8643 | ||
| 8644 | Stage1AirInst *casted_value = ir_implicit_cast(ira, value, global_visibility_type); | |
| 8645 | if (type_is_invalid(casted_value->value->type)) | |
| 8646 | return false; | |
| 8647 | ||
| 8648 | ZigValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); | |
| 8649 | if (!const_val) | |
| 8650 | return false; | |
| 8651 | ||
| 8652 | *out = (GlobalVisibilityId)bigint_as_u32(&const_val->data.x_enum_tag); | |
| 8653 | return true; | |
| 8654 | } | |
| 8655 | ||
| 8656 | ||
| 8638 | 8657 | static bool ir_resolve_float_mode(IrAnalyze *ira, Stage1AirInst *value, FloatMode *out) { |
| 8639 | 8658 | if (type_is_invalid(value->value->type)) |
| 8640 | 8659 | return false; |
| ... | ... | @@ -11661,6 +11680,12 @@ static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirIns |
| 11661 | 11680 | if (type_is_invalid(section_inst->value->type)) |
| 11662 | 11681 | return ira->codegen->invalid_inst_gen; |
| 11663 | 11682 | |
| 11683 | TypeStructField *visibility_field = find_struct_type_field(options_type, buf_create_from_str("visibility")); | |
| 11684 | src_assert(visibility_field != nullptr, instruction->base.source_node); | |
| 11685 | Stage1AirInst *visibility_inst = ir_analyze_struct_value_field_value(ira, instruction->base.scope, instruction->base.source_node, options, visibility_field); | |
| 11686 | if (type_is_invalid(visibility_inst->value->type)) | |
| 11687 | return ira->codegen->invalid_inst_gen; | |
| 11688 | ||
| 11664 | 11689 | // The `section` field is optional, we have to unwrap it first |
| 11665 | 11690 | Stage1AirInst *non_null_check = ir_analyze_test_non_null(ira, instruction->base.scope, instruction->base.source_node, section_inst); |
| 11666 | 11691 | bool is_non_null; |
| ... | ... | @@ -11689,6 +11714,10 @@ static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirIns |
| 11689 | 11714 | if (!ir_resolve_global_linkage(ira, linkage_inst, &global_linkage_id)) |
| 11690 | 11715 | return ira->codegen->invalid_inst_gen; |
| 11691 | 11716 | |
| 11717 | GlobalVisibilityId global_visibility_id; | |
| 11718 | if (!ir_resolve_global_visibility(ira, visibility_inst, &global_visibility_id)) | |
| 11719 | return ira->codegen->invalid_inst_gen; | |
| 11720 | ||
| 11692 | 11721 | Buf *section_name = nullptr; |
| 11693 | 11722 | if (section_str_inst != nullptr && !(section_name = ir_resolve_str(ira, section_str_inst))) |
| 11694 | 11723 | return ira->codegen->invalid_inst_gen; |
| ... | ... | @@ -11751,7 +11780,7 @@ static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirIns |
| 11751 | 11780 | case CallingConventionSysV: |
| 11752 | 11781 | case CallingConventionWin64: |
| 11753 | 11782 | case CallingConventionPtxKernel: |
| 11754 | add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc); | |
| 11783 | add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, global_visibility_id, cc); | |
| 11755 | 11784 | fn_entry->section_name = section_name; |
| 11756 | 11785 | break; |
| 11757 | 11786 | } |
| ... | ... | @@ -11898,7 +11927,7 @@ static Stage1AirInst *ir_analyze_instruction_export(IrAnalyze *ira, Stage1ZirIns |
| 11898 | 11927 | if (load_ptr->ptr->id == Stage1AirInstIdVarPtr) { |
| 11899 | 11928 | Stage1AirInstVarPtr *var_ptr = reinterpret_cast<Stage1AirInstVarPtr *>(load_ptr->ptr); |
| 11900 | 11929 | ZigVar *var = var_ptr->var; |
| 11901 | add_var_export(ira->codegen, var, buf_ptr(symbol_name), global_linkage_id); | |
| 11930 | add_var_export(ira->codegen, var, buf_ptr(symbol_name), global_linkage_id, global_visibility_id); | |
| 11902 | 11931 | var->section_name = section_name; |
| 11903 | 11932 | } |
| 11904 | 11933 | } |