Skip to content

Commit

Permalink
Refactor and unify linker visibility and fix issues with weak stdlib.
Browse files Browse the repository at this point in the history
  • Loading branch information
lerno committed Oct 11, 2024
1 parent 1b47128 commit cba2571
Show file tree
Hide file tree
Showing 18 changed files with 257 additions and 141 deletions.
128 changes: 76 additions & 52 deletions src/compiler/llvm_codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,15 @@ static void diagnostics_handler(LLVMDiagnosticInfoRef ref, void *context)

bool module_should_weaken(Module *module)
{
return str_eq("std", module->top_module->name->module);
Module *top = module->top_module;
return top && top->name->module == kw_std;
}

static void gencontext_init(GenContext *context, Module *module, LLVMContextRef shared_context)
{
assert(LLVMIsMultithreaded());
memset(context, 0, sizeof(GenContext));
if (compiler.build.type == TARGET_TYPE_DYNAMIC_LIB || compiler.build.type == TARGET_TYPE_STATIC_LIB)
{
context->weaken = module_should_weaken(module);
}
context->weaken = module_should_weaken(module);

if (shared_context)
{
Expand Down Expand Up @@ -131,8 +129,7 @@ LLVMValueRef llvm_get_selector(GenContext *c, const char *name)
LLVMValueRef selector = llvm_add_global_raw(c, sel_name, char_array_type, 0);
LLVMSetGlobalConstant(selector, 1);
LLVMSetInitializer(selector, llvm_get_zstring(c, name, name_len));
LLVMSetLinkage(selector, LLVMLinkOnceODRLinkage);
llvm_set_comdat(c, selector);
llvm_set_selector_linkage(c, selector);
return selector;
}

Expand Down Expand Up @@ -469,16 +466,76 @@ void llvm_set_global_tls(Decl *decl)
LLVMSetThreadLocalMode(optional_ref, thread_local_mode);
}
}

static void llvm_set_weak(GenContext *c, LLVMValueRef global)
{
LLVMSetLinkage(global, LLVMWeakAnyLinkage);
LLVMSetVisibility(global, LLVMDefaultVisibility);
llvm_set_comdat(c, global);
}

static void llvm_set_external_reference(GenContext *c, LLVMValueRef ref, bool is_weak)
{
LLVMSetLinkage(ref, is_weak ? LLVMExternalWeakLinkage : LLVMExternalLinkage);
LLVMSetVisibility(ref, LLVMDefaultVisibility);
}

void llvm_set_decl_linkage(GenContext *c, Decl *decl)
{
bool is_var = decl->decl_kind == DECL_VAR;
bool is_weak = decl->is_weak;
bool should_weaken = is_weak || (!decl->is_extern && module_should_weaken(decl->unit->module));
LLVMValueRef ref = decl->backend_ref;
LLVMValueRef opt_ref = is_var ? decl->var.optional_ref : NULL;
bool is_static = is_var && decl->var.is_static;
// Static variables in a different modules should be copied to the current module.
bool same_module = is_static || decl->unit->module == c->code_module;
if (decl->is_extern || !same_module)
{
llvm_set_external_reference(c, ref, should_weaken);
if (opt_ref) llvm_set_external_reference(c, opt_ref, should_weaken);
return;
}
if (decl_is_externally_visible(decl) && !is_static)
{
if (decl->is_export && compiler.platform.os == OS_TYPE_WIN32 && !compiler.build.win.def && decl->name != kw_main && decl->name != kw_mainstub)
{
LLVMSetDLLStorageClass(ref, LLVMDLLExportStorageClass);
}
if (is_weak)
{
llvm_set_weak(c, ref);
if (opt_ref) llvm_set_weak(c, opt_ref);
return;
}
if (should_weaken)
{
llvm_set_linkonce(c, ref);
if (opt_ref) llvm_set_linkonce(c, opt_ref);
return;
}
LLVMSetVisibility(ref, LLVMDefaultVisibility);
if (opt_ref) LLVMSetVisibility(opt_ref, LLVMDefaultVisibility);
return;
}

LLVMSetLinkage(ref, decl->is_weak ? LLVMLinkerPrivateWeakLinkage : LLVMInternalLinkage);
if (opt_ref) LLVMSetLinkage(opt_ref, LLVMInternalLinkage);
}

void llvm_set_internal_linkage(LLVMValueRef alloc)
{
LLVMSetLinkage(alloc, LLVMInternalLinkage);
LLVMSetVisibility(alloc, LLVMDefaultVisibility);
}
void llvm_set_private_linkage(LLVMValueRef alloc)

void llvm_set_private_declaration(LLVMValueRef alloc)
{
LLVMSetLinkage(alloc, LLVMPrivateLinkage);
LLVMSetVisibility(alloc, LLVMDefaultVisibility);
LLVMSetUnnamedAddress(alloc, LLVMGlobalUnnamedAddr);
}

void llvm_emit_global_variable_init(GenContext *c, Decl *decl)
{
assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST || decl->var.is_static);
Expand Down Expand Up @@ -587,34 +644,15 @@ void llvm_emit_global_variable_init(GenContext *c, Decl *decl)

LLVMSetGlobalConstant(global_ref, decl->var.kind == VARDECL_CONST);

if (decl->is_extern)
{
LLVMSetLinkage(global_ref, LLVMExternalLinkage);
if (optional_ref) LLVMSetLinkage(optional_ref, LLVMExternalLinkage);
}
else if (decl_is_externally_visible(decl) && !decl->var.is_static)
{
LLVMSetVisibility(global_ref, LLVMDefaultVisibility);
if (c->weaken) llvm_set_linkonce(c, global_ref);
if (optional_ref)
{
if (c->weaken) llvm_set_linkonce(c, optional_ref);
LLVMSetVisibility(optional_ref, LLVMDefaultVisibility);
}
}
else
{
LLVMSetLinkage(global_ref, LLVMInternalLinkage);
if (optional_ref) LLVMSetLinkage(optional_ref, LLVMInternalLinkage);
}

decl->backend_ref = global_ref;
if (old)
{
LLVMReplaceAllUsesWith(old, global_ref);
LLVMDeleteGlobal(old);
}

llvm_set_decl_linkage(c, decl);

}
static void gencontext_verify_ir(GenContext *context)
{
Expand Down Expand Up @@ -882,21 +920,22 @@ void llvm_set_comdat(GenContext *c, LLVMValueRef global)
LLVMSetComdat(global, comdat);
}

void llvm_set_linkonce(GenContext *c, LLVMValueRef global)
void llvm_set_selector_linkage(GenContext *c, LLVMValueRef selector)
{
LLVMSetLinkage(global, LLVMLinkOnceAnyLinkage);
LLVMSetVisibility(global, LLVMDefaultVisibility);
llvm_set_comdat(c, global);
LLVMSetVisibility(selector, LLVMDefaultVisibility);
LLVMSetLinkage(selector, LLVMLinkOnceODRLinkage);
llvm_set_comdat(c, selector);
}

void llvm_set_weak(GenContext *c, LLVMValueRef global)
void llvm_set_linkonce(GenContext *c, LLVMValueRef global)
{
LLVMSetLinkage(global, LLVMWeakAnyLinkage);
LLVMSetLinkage(global, LLVMLinkOnceAnyLinkage);
LLVMSetVisibility(global, LLVMDefaultVisibility);
llvm_set_comdat(c, global);
}



void llvm_value_set_int(GenContext *c, BEValue *value, Type *type, uint64_t i)
{
llvm_value_set(value, llvm_const_int(c, type, i), type);
Expand Down Expand Up @@ -1070,10 +1109,6 @@ void llvm_add_global_decl(GenContext *c, Decl *decl)
scratch_buffer_set_extern_decl_name(decl, true);
decl->backend_ref = llvm_add_global_raw(c, scratch_buffer_to_string(), type, decl->alignment);
}
if (!same_module)
{
LLVMSetLinkage(decl->backend_ref, LLVMExternalLinkage);
}
if (decl->var.kind == VARDECL_CONST)
{
LLVMSetGlobalConstant(decl->backend_ref, true);
Expand All @@ -1085,6 +1120,7 @@ void llvm_add_global_decl(GenContext *c, Decl *decl)
scratch_buffer_append(".f");
decl->var.optional_ref = llvm_add_global_raw(c, scratch_buffer_to_string(), anyfault, 0);
}
llvm_set_decl_linkage(c, decl);
llvm_set_global_tls(decl);
}

Expand Down Expand Up @@ -1254,10 +1290,6 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
}
assert(decl->var.kind == VARDECL_GLOBAL || decl->var.kind == VARDECL_CONST);
llvm_add_global_decl(c, decl);
if (decl->is_export && compiler.platform.os == OS_TYPE_WIN32 && !compiler.build.win.def)
{
LLVMSetDLLStorageClass(decl->backend_ref, LLVMDLLExportStorageClass);
}
return decl->backend_ref;
case DECL_FUNC:
if (decl->func_decl.attr_interface_method)
Expand All @@ -1275,15 +1307,7 @@ LLVMValueRef llvm_get_ref(GenContext *c, Decl *decl)
backend_ref = decl->backend_ref = LLVMAddFunction(c->module, scratch_buffer_to_string(), type);
}
llvm_append_function_attributes(c, decl);
if (decl->is_export && compiler.platform.os == OS_TYPE_WIN32 && !compiler.build.win.def && decl->name != kw_main && decl->name != kw_mainstub)
{
LLVMSetDLLStorageClass(backend_ref, LLVMDLLExportStorageClass);
}
if (decl_is_local(decl))
{
assert(decl->unit->module == c->code_module);
llvm_set_internal_linkage(backend_ref);
}
llvm_set_decl_linkage(c, decl);
return backend_ref;
case DECL_DEFINE:
return llvm_get_ref(c, decl->define_decl.alias);
Expand Down
9 changes: 3 additions & 6 deletions src/compiler/llvm_codegen_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1730,8 +1730,7 @@ void llvm_emit_initialize_reference_temporary_const(GenContext *c, BEValue *ref,
AlignSize alignment = type_alloca_alignment(initializer->type);
LLVMTypeRef type = LLVMTypeOf(value);
LLVMValueRef global_copy = llvm_add_global_raw(c, ".__const", type, alignment);
llvm_set_private_linkage(global_copy);
LLVMSetUnnamedAddress(global_copy, LLVMGlobalUnnamedAddr);
llvm_set_private_declaration(global_copy);

// Set the value and make it constant
LLVMSetInitializer(global_copy, value);
Expand Down Expand Up @@ -5056,8 +5055,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
LLVMTypeRef val_type = llvm_get_type(c, init->type);
LLVMValueRef global_copy = llvm_add_global_raw(c, ".__const_slice", val_type, alignment);
LLVMSetInitializer(global_copy, value);
llvm_set_private_linkage(global_copy);
LLVMSetUnnamedAddress(global_copy, LLVMGlobalUnnamedAddr);
llvm_set_private_declaration(global_copy);
assert(type_is_arraylike(init->type));
LLVMValueRef val = llvm_emit_aggregate_two(c, type, global_copy,
llvm_const_int(c, type_usz, init->type->array.len));
Expand Down Expand Up @@ -5131,8 +5129,7 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr)
if (!is_bytes) size++;
if (is_array && type->array.len > size) size = type->array.len;
LLVMValueRef global_name = llvm_add_global_raw(c, is_bytes ? ".bytes" : ".str", LLVMArrayType(llvm_get_type(c, type_char), size), 1);
llvm_set_private_linkage(global_name);
LLVMSetUnnamedAddress(global_name, LLVMGlobalUnnamedAddr);
llvm_set_private_declaration(global_name);
LLVMSetGlobalConstant(global_name, 1);
LLVMValueRef data = is_bytes
? llvm_get_bytes(c, expr->const_expr.bytes.ptr, expr->const_expr.bytes.len)
Expand Down
23 changes: 0 additions & 23 deletions src/compiler/llvm_codegen_function.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,29 +644,6 @@ void llvm_emit_function_decl(GenContext *c, Decl *decl)
{
llvm_emit_debug_function(c, decl);
}

if (decl->is_extern)
{
if (decl->is_weak)
{
LLVMSetLinkage(function, LLVMExternalWeakLinkage);
llvm_set_comdat(c, function);
}
else
{
LLVMSetLinkage(function, LLVMExternalLinkage);
}
LLVMSetVisibility(function, LLVMDefaultVisibility);
return;
}
if (decl_is_local(decl))
{
LLVMSetLinkage(function, decl->is_weak ? LLVMLinkerPrivateWeakLinkage : LLVMInternalLinkage);
LLVMSetVisibility(function, LLVMDefaultVisibility);
return;
}
if (c->weaken) llvm_set_linkonce(c, function);
if (decl->is_weak) llvm_set_weak(c, function);
}


6 changes: 4 additions & 2 deletions src/compiler/llvm_codegen_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -364,10 +364,12 @@ void llvm_attribute_add_type(GenContext *c, LLVMValueRef value_to_add_attribute_
void llvm_attribute_add_int(GenContext *c, LLVMValueRef value_to_add_attribute_to, unsigned attribute, uint64_t val, int index);

// -- Linking --
void llvm_set_selector_linkage(GenContext *c, LLVMValueRef selector);
void llvm_set_linkonce(GenContext *c, LLVMValueRef global);
void llvm_set_comdat(GenContext *c, LLVMValueRef global);
void llvm_set_weak(GenContext *c, LLVMValueRef global);
void llvm_set_private_linkage(LLVMValueRef alloc);
void llvm_set_private_declaration(LLVMValueRef alloc);
void llvm_set_decl_linkage(GenContext *c, Decl *decl);

void llvm_set_internal_linkage(LLVMValueRef alloc);
void llvm_set_global_tls(Decl *decl);

Expand Down
3 changes: 1 addition & 2 deletions src/compiler/llvm_codegen_stmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ void llvm_emit_local_static(GenContext *c, Decl *decl, BEValue *value)
decl->var.optional_ref = llvm_add_global_raw(c, scratch_buffer_to_string(), anyfault, 0);
}
llvm_emit_global_variable_init(c, decl);

// Pop the builder
c->builder = builder;
llvm_value_set_decl(c, value, decl);
Expand Down Expand Up @@ -850,7 +849,7 @@ static void llvm_emit_switch_jump_table(GenContext *c,
LLVMValueRef jmptable = llvm_add_global_raw(c, "jumptable", llvm_array_type, alignment);
switch_ast->switch_stmt.codegen.jump.jmptable = jmptable;

llvm_set_private_linkage(jmptable);
llvm_set_private_declaration(jmptable);
LLVMSetGlobalConstant(jmptable, 1);
BEValue array_value;

Expand Down
2 changes: 1 addition & 1 deletion src/compiler/llvm_codegen_value.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void llvm_value_addr(GenContext *c, BEValue *value)
{
LLVMValueRef val = llvm_load_value_store(c, value);
LLVMValueRef ref = llvm_add_global_raw(c, ".taddr", LLVMTypeOf(val), 0);
llvm_set_private_linkage(ref);
llvm_set_private_declaration(ref);
LLVMSetInitializer(ref, val);
llvm_value_set_address_abi_aligned(value, ref, value->type);
}
Expand Down
15 changes: 7 additions & 8 deletions test/test_suite/arrays/global_init.c3t
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,21 @@ fn void main() {

/* #expect: test.ll

@.taddr = private global i32 3, align 4
@.taddr = private unnamed_addr global i32 3, align 4
@test.foo = local_unnamed_addr global ptr @.taddr, align 8
@test.a = global i32 0, align 4
@test.c = local_unnamed_addr global i32 0, align 4
@test.d = local_unnamed_addr global i32 0, align 4
@test.abc = local_unnamed_addr global [3 x i32] zeroinitializer, align 4
@test.b = local_unnamed_addr global ptr getelementptr
@test.bf = local_unnamed_addr global ptr getelementptr
@test.b = local_unnamed_addr global ptr getelementptr (i8, ptr @test.a, i64 28), align 8
@test.bf = local_unnamed_addr global ptr getelementptr (i8, ptr @test.abc, i64 16), align 8
@test.bf2 = local_unnamed_addr global ptr getelementptr inbounds (i8, ptr @test.abc, i64 8), align 8
@test.bf3 = local_unnamed_addr global ptr getelementptr
@.taddr.9 = private global i32 42, align 4
@.taddr.10 = private global i8 99, align 1
@.taddr.11 = private global %"char[]" { ptr @.str, i64 3 }, align 8
@test.bf3 = local_unnamed_addr global ptr getelementptr (i8, ptr @test.abc, i64 16), align 8
@.taddr.9 = private unnamed_addr global i32 42, align 4
@.taddr.10 = private unnamed_addr global i8 99, align 1
@.taddr.11 = private unnamed_addr global %"char[]" { ptr @.str, i64 3 }, align 8
@main.x = internal unnamed_addr global [3 x %any] [%any { ptr @.taddr.9, i64 ptrtoint (ptr @"$ct.int" to i64) }, %any { ptr @.taddr.10, i64 ptrtoint (ptr @"$ct.char" to i64) }, %any { ptr @.taddr.11, i64 ptrtoint (ptr @"$ct.String" to i64) }], align 16

; Function Attrs:
define void @test.main() #0 {
entry:
%bf34 = alloca ptr, align 8
Expand Down
Loading

0 comments on commit cba2571

Please sign in to comment.