diff --git a/toolchain/lower/file_context.cpp b/toolchain/lower/file_context.cpp index d2cb011995ff..9e2577ad2078 100644 --- a/toolchain/lower/file_context.cpp +++ b/toolchain/lower/file_context.cpp @@ -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); diff --git a/toolchain/lower/testdata/global/class_obj.carbon b/toolchain/lower/testdata/global/class_obj.carbon index 3017f8210901..0d6218dd09a3 100644 --- a/toolchain/lower/testdata/global/class_obj.carbon +++ b/toolchain/lower/testdata/global/class_obj.carbon @@ -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 diff --git a/toolchain/lower/testdata/global/class_with_fun.carbon b/toolchain/lower/testdata/global/class_with_fun.carbon index a9646a926b75..8253c4ff96a0 100644 --- a/toolchain/lower/testdata/global/class_with_fun.carbon +++ b/toolchain/lower/testdata/global/class_with_fun.carbon @@ -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: diff --git a/toolchain/lower/testdata/global/simple_init.carbon b/toolchain/lower/testdata/global/simple_init.carbon index 8e37d9c6ce35..48d9bbdb2a14 100644 --- a/toolchain/lower/testdata/global/simple_init.carbon +++ b/toolchain/lower/testdata/global/simple_init.carbon @@ -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 diff --git a/toolchain/lower/testdata/global/simple_with_fun.carbon b/toolchain/lower/testdata/global/simple_with_fun.carbon index ced70c367645..fce9a63639fb 100644 --- a/toolchain/lower/testdata/global/simple_with_fun.carbon +++ b/toolchain/lower/testdata/global/simple_with_fun.carbon @@ -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 diff --git a/toolchain/lower/testdata/global/use.carbon b/toolchain/lower/testdata/global/use.carbon index 4bd6844e7805..201fbe9fa5b0 100644 --- a/toolchain/lower/testdata/global/use.carbon +++ b/toolchain/lower/testdata/global/use.carbon @@ -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 diff --git a/toolchain/lower/testdata/var/global.carbon b/toolchain/lower/testdata/var/global.carbon index da79f856abcf..8b9f96c89d67 100644 --- a/toolchain/lower/testdata/var/global.carbon +++ b/toolchain/lower/testdata/var/global.carbon @@ -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 diff --git a/toolchain/lower/testdata/var/import.carbon b/toolchain/lower/testdata/var/import.carbon index b7a8d0d09829..89d64112c5ef 100644 --- a/toolchain/lower/testdata/var/import.carbon +++ b/toolchain/lower/testdata/var/import.carbon @@ -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