mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-10-05 22:02:55 +01:00
Give internal linkage to global init function. (#6591)
The mangled name of the global init function is the same for all files in a package, so giving it external linkage results in link errors if more than one file in a package has global initializers. We never need to refer to it from outside the file, so give it internal linkage. This also requires that we stop eagerly emitting a declaration of it -- if it's empty, we don't emit a definition, and LLVM doesn't allow us to emit an undefined declaration of an internal linkage symbol.
This commit is contained in:
@@ -90,6 +90,11 @@ auto FileContext::PrepareToLower() -> void {
|
||||
|
||||
// Lower function declarations.
|
||||
for (auto [id, _] : sem_ir_->functions().enumerate()) {
|
||||
if (id == sem_ir().global_ctor_id()) {
|
||||
// The global constructor is only lowered when we generate its definition.
|
||||
// LLVM doesn't allow an internal linkage function to be undefined.
|
||||
continue;
|
||||
}
|
||||
functions_.Set(id, BuildFunctionDecl(id));
|
||||
}
|
||||
|
||||
@@ -151,11 +156,12 @@ auto FileContext::LowerDefinitions() -> void {
|
||||
// variables.
|
||||
if (auto global_ctor_id = sem_ir().global_ctor_id();
|
||||
global_ctor_id.has_value()) {
|
||||
auto* llvm_function = BuildFunctionDecl(global_ctor_id);
|
||||
functions_.Set(global_ctor_id, llvm_function);
|
||||
const auto& global_ctor = sem_ir().functions().Get(global_ctor_id);
|
||||
BuildFunctionBody(global_ctor_id, SemIR::SpecificId::None, global_ctor,
|
||||
*this, global_ctor);
|
||||
llvm::appendToGlobalCtors(llvm_module(),
|
||||
GetFunction(sem_ir().global_ctor_id()),
|
||||
llvm::appendToGlobalCtors(llvm_module(), llvm_function,
|
||||
/*Priority=*/0);
|
||||
}
|
||||
}
|
||||
@@ -460,6 +466,11 @@ auto FileContext::BuildFunctionDecl(SemIR::FunctionId function_id,
|
||||
// `available_externally` definition.
|
||||
auto linkage = specific_id.has_value() ? llvm::Function::LinkOnceODRLinkage
|
||||
: llvm::Function::ExternalLinkage;
|
||||
if (function_id == sem_ir().global_ctor_id()) {
|
||||
// The global constructor name would collide with global constructors for
|
||||
// other files in the same package, so use an internal linkage symbol.
|
||||
linkage = llvm::Function::InternalLinkage;
|
||||
}
|
||||
|
||||
Mangler m(*this);
|
||||
std::string mangled_name = m.Mangle(function_id, specific_id);
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ var a: A = {};
|
||||
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 @_Ca.Main, ptr align 1 @A.val.loc14_1, i64 0, i1 false), !dbg !7
|
||||
// CHECK:STDOUT: ret void, !dbg !8
|
||||
|
||||
+4
-7
@@ -31,19 +31,16 @@ var a: A = {};
|
||||
// CHECK:STDOUT: ret void, !dbg !8
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !9 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !9 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 1 @_Ca.Main, ptr align 1 @A.val.loc15_12, i64 0, i1 false), !dbg !12
|
||||
// CHECK:STDOUT: ret void, !dbg !13
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite)
|
||||
// CHECK:STDOUT: declare void @llvm.memcpy.p0.p0.i64(ptr noalias writeonly captures(none), ptr noalias readonly captures(none), i64, i1 immarg) #1
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; uselistorder directives
|
||||
// CHECK:STDOUT: uselistorder ptr @llvm.memcpy.p0.p0.i64, { 1, 0 }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: attributes #0 = { nounwind }
|
||||
// CHECK:STDOUT: attributes #1 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
||||
// CHECK:STDOUT:
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ var a: i32 = 0;
|
||||
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: store i32 0, ptr @_Ca.Main, align 4, !dbg !7
|
||||
// CHECK:STDOUT: ret void, !dbg !8
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ var a: i32 = test_a();
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !9 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !9 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: %test_a.call = call i32 @_Ctest_a.Main(), !dbg !12
|
||||
// CHECK:STDOUT: store i32 %test_a.call, ptr @_Ca.Main, align 4, !dbg !13
|
||||
|
||||
+1
-1
@@ -32,7 +32,7 @@ fn F() -> i32 {
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !10 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !10 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: store i32 5, ptr @_Ca.Main, align 4, !dbg !13
|
||||
// CHECK:STDOUT: %.loc14 = load i32, ptr @_Ca.Main, align 4, !dbg !14
|
||||
|
||||
+4
-4
@@ -57,7 +57,7 @@ var (_: i32, _: i32) = (3, 4);
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !9 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !9 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: store i32 1, ptr @_Ca.Main, align 4, !dbg !12
|
||||
// CHECK:STDOUT: ret void, !dbg !13
|
||||
@@ -102,7 +102,7 @@ var (_: i32, _: i32) = (3, 4);
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !11 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !11 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: store i32 2, ptr @_Cb.Main, align 4, !dbg !14
|
||||
// CHECK:STDOUT: store i32 3, ptr @_Cc.Main, align 4, !dbg !15
|
||||
@@ -151,7 +151,7 @@ var (_: i32, _: i32) = (3, 4);
|
||||
// CHECK:STDOUT: }
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !11 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !11 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 @_Cd.Main, ptr align 4 @tuple.0a0.loc4_1, i64 8, i1 false), !dbg !14
|
||||
// CHECK:STDOUT: ret void, !dbg !15
|
||||
@@ -195,7 +195,7 @@ var (_: i32, _: i32) = (3, 4);
|
||||
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 @_Cx.Main, ptr align 4 @tuple.21c.loc4_1, i64 8, i1 false), !dbg !7
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 @var.anon.var_patt.loc5, ptr align 4 @tuple.ffd.loc5_1, i64 8, i1 false), !dbg !8
|
||||
|
||||
+2
-2
@@ -55,7 +55,7 @@ fn Z() -> i32 { return z; }
|
||||
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: store i32 42, ptr @_Cv.Main, align 4, !dbg !7
|
||||
// CHECK:STDOUT: ret void, !dbg !8
|
||||
@@ -113,7 +113,7 @@ fn Z() -> i32 { return z; }
|
||||
// CHECK:STDOUT: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 0, ptr @_C__global_init.Main, ptr null }]
|
||||
// CHECK:STDOUT:
|
||||
// CHECK:STDOUT: ; Function Attrs: nounwind
|
||||
// CHECK:STDOUT: define void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: define internal void @_C__global_init.Main() #0 !dbg !4 {
|
||||
// CHECK:STDOUT: entry:
|
||||
// CHECK:STDOUT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 @_Cv.Main, ptr align 4 @tuple.21c.loc4_1, i64 8, i1 false), !dbg !7
|
||||
// CHECK:STDOUT: store i32 4, ptr @_Cy.Main, align 4, !dbg !8
|
||||
|
||||
Reference in New Issue
Block a user