diff --git a/compiler-rt/test/profile/coverage-weak.cpp b/compiler-rt/test/profile/coverage-weak.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/profile/coverage-weak.cpp @@ -0,0 +1,46 @@ +/// Test instrumentation can handle non-comdat weak functions. +// RUN: %clang_profgen -g -fcoverage-mapping -c -o %t1.o %s +// RUN: %clang_profgen -g -fcoverage-mapping -c -o %t2.o %s -DOBJECT_2 +// RUN: %clang_profgen -g -fcoverage-mapping %t1.o %t2.o -o %t.exe +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.exe +// RUN: llvm-profdata show %t.profraw --all-functions | FileCheck %s + +/// Additionally test associative comdat on Windows. +// RUN: %clang_profgen -g -fcoverage-mapping -c -o %t1.o %s -ffunction-sections +// RUN: %clang_profgen -g -fcoverage-mapping -c -o %t2.o %s -ffunction-sections -DOBJECT_2 +// RUN: %clang_profgen -g -fcoverage-mapping %t1.o %t2.o -o %t.exe +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t.exe +// RUN: llvm-profdata show %t.profraw --all-functions | FileCheck %s + +// CHECK: main: +// CHECK-NEXT: Hash: +// CHECK-NEXT: Counters: 1 +// CHECK-NEXT: Function count: 1 +// CHECK: {{.*}}weak{{.*}}: +// CHECK-NEXT: Hash: +// CHECK-NEXT: Counters: 1 +// CHECK-NEXT: Function count: 2 +// CHECK: {{.*}}foo{{.*}}: +// CHECK-NEXT: Hash: +// CHECK-NEXT: Counters: 1 +// CHECK-NEXT: Function count: 1 + +#ifdef OBJECT_2 +extern "C" int puts(const char *); + +__attribute__((weak)) void weak(const char *msg) { + puts(msg); +} + +void foo() { + weak("shared"); +} +#else +void weak(const char *msg); +void foo(); + +int main() { + weak("main"); + foo(); +} +#endif diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -821,15 +821,10 @@ PD = It->second; } - // Match the linkage and visibility of the name global. COFF supports using - // comdats with internal symbols, so do that if we can. + // Match the linkage and visibility of the name global. Function *Fn = Inc->getParent()->getParent(); GlobalValue::LinkageTypes Linkage = NamePtr->getLinkage(); GlobalValue::VisibilityTypes Visibility = NamePtr->getVisibility(); - if (TT.isOSBinFormatCOFF()) { - Linkage = GlobalValue::InternalLinkage; - Visibility = GlobalValue::DefaultVisibility; - } // Move the name variable to the right section. Place them in a COMDAT group // if the associated function is a COMDAT. This will make sure that only one @@ -838,23 +833,19 @@ // new comdat group for the counters and profiling data. If we use the comdat // of the parent function, that will result in relocations against discarded // sections. + // + // For COFF, put the counters, data, and values each into their own + // comdats. We can't use a group because the Visual C++ linker will + // report duplicate symbol errors if there are multiple external symbols + // with the same name marked IMAGE_COMDAT_SELECT_ASSOCIATIVE. + // + // For ELF, when not using COMDAT, put counters, data and values into a + // noduplicates COMDAT which is lowered to a zero-flag section group. This + // allows -z start-stop-gc to discard the entire group when the function is + // discarded. bool NeedComdat = needsComdatForCounter(*Fn, *M); - if (NeedComdat) { - if (TT.isOSBinFormatCOFF()) { - // For COFF, put the counters, data, and values each into their own - // comdats. We can't use a group because the Visual C++ linker will - // report duplicate symbol errors if there are multiple external symbols - // with the same name marked IMAGE_COMDAT_SELECT_ASSOCIATIVE. - Linkage = GlobalValue::LinkOnceODRLinkage; - Visibility = GlobalValue::HiddenVisibility; - } - } std::string DataVarName = getVarName(Inc, getInstrProfDataVarPrefix()); auto MaybeSetComdat = [=](GlobalVariable *GV) { - // For ELF, when not using COMDAT, put counters, data and values into - // a noduplicates COMDAT which is lowered to a zero-flag section group. - // This allows linker GC to discard the entire group when the function - // is discarded. bool UseComdat = (NeedComdat || TT.isOSBinFormatELF()); if (UseComdat) { auto GroupName = TT.isOSBinFormatCOFF() ? GV->getName() : DataVarName; diff --git a/llvm/test/Instrumentation/InstrProfiling/linkage.ll b/llvm/test/Instrumentation/InstrProfiling/linkage.ll --- a/llvm/test/Instrumentation/InstrProfiling/linkage.ll +++ b/llvm/test/Instrumentation/InstrProfiling/linkage.ll @@ -28,9 +28,9 @@ ; ELF: @__profd_foo = private global {{.*}} section "__llvm_prf_data", comdat, align 8 ; MACHO: @__profc_foo = private global ; MACHO: @__profd_foo = private global -; COFF: @__profc_foo = internal global +; COFF: @__profc_foo = private global ; COFF-NOT: comdat -; COFF: @__profd_foo = internal global +; COFF: @__profd_foo = private global define void @foo() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 0, i32 1, i32 0) ret void @@ -40,8 +40,8 @@ ; ELF: @__profd_foo_weak = weak hidden global {{.*}} section "__llvm_prf_data", comdat, align 8 ; MACHO: @__profc_foo_weak = weak hidden global ; MACHO: @__profd_foo_weak = weak hidden global -; COFF: @__profc_foo_weak = internal global -; COFF: @__profd_foo_weak = internal global +; COFF: @__profc_foo_weak = weak hidden global +; COFF: @__profd_foo_weak = weak hidden global define weak void @foo_weak() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @__profn_foo_weak, i32 0, i32 0), i64 0, i32 1, i32 0) ret void @@ -51,8 +51,8 @@ ; ELF: @"__profd_linkage.ll:foo_internal" = private global {{.*}} section "__llvm_prf_data", comdat, align 8 ; MACHO: @"__profc_linkage.ll:foo_internal" = private global ; MACHO: @"__profd_linkage.ll:foo_internal" = private global -; COFF: @"__profc_linkage.ll:foo_internal" = internal global -; COFF: @"__profd_linkage.ll:foo_internal" = internal global +; COFF: @"__profc_linkage.ll:foo_internal" = private global +; COFF: @"__profd_linkage.ll:foo_internal" = private global define internal void @foo_internal() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @"__profn_linkage.ll:foo_internal", i32 0, i32 0), i64 0, i32 1, i32 0) ret void @@ -62,8 +62,8 @@ ; ELF: @__profd_foo_inline = linkonce_odr hidden global {{.*}} section "__llvm_prf_data", comdat, align 8 ; MACHO: @__profc_foo_inline = linkonce_odr hidden global ; MACHO: @__profd_foo_inline = linkonce_odr hidden global -; COFF: @__profc_foo_inline = internal global{{.*}} section ".lprfc$M", align 8 -; COFF: @__profd_foo_inline = internal global{{.*}} section ".lprfd$M", align 8 +; COFF: @__profc_foo_inline = linkonce_odr hidden global{{.*}} section ".lprfc$M", align 8 +; COFF: @__profd_foo_inline = linkonce_odr hidden global{{.*}} section ".lprfd$M", align 8 define linkonce_odr void @foo_inline() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @__profn_foo_inline, i32 0, i32 0), i64 0, i32 1, i32 0) ret void diff --git a/llvm/test/Instrumentation/InstrProfiling/platform.ll b/llvm/test/Instrumentation/InstrProfiling/platform.ll --- a/llvm/test/Instrumentation/InstrProfiling/platform.ll +++ b/llvm/test/Instrumentation/InstrProfiling/platform.ll @@ -20,11 +20,11 @@ ; MACHO: @__profc_foo = private global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 ; ELF: @__profc_foo = private global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", comdat($__profd_foo), align 8 -; WINDOWS: @__profc_foo = internal global [1 x i64] zeroinitializer, section ".lprfc$M", align 8 +; WINDOWS: @__profc_foo = private global [1 x i64] zeroinitializer, section ".lprfc$M", align 8 ; MACHO: @__profd_foo = private {{.*}}, section "__DATA,__llvm_prf_data,regular,live_support", align 8 ; ELF: @__profd_foo = private {{.*}}, section "__llvm_prf_data", comdat, align 8 -; WINDOWS: @__profd_foo = internal global {{.*}}, section ".lprfd$M", align 8 +; WINDOWS: @__profd_foo = private global {{.*}}, section ".lprfd$M", align 8 ; ELF: @__llvm_prf_nm = private constant [{{.*}} x i8] c"{{.*}}", section "{{.*}}__llvm_prf_names", align 1 ; WINDOWS: @__llvm_prf_nm = private constant [{{.*}} x i8] c"{{.*}}", section "{{.*}}lprfn$M", align 1 diff --git a/llvm/test/Instrumentation/InstrProfiling/profiling.ll b/llvm/test/Instrumentation/InstrProfiling/profiling.ll --- a/llvm/test/Instrumentation/InstrProfiling/profiling.ll +++ b/llvm/test/Instrumentation/InstrProfiling/profiling.ll @@ -21,8 +21,8 @@ ; ELF: @__profd_foo = private {{.*}}, section "__llvm_prf_data", comdat, align 8 ; MACHO: @__profc_foo = private global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 ; MACHO: @__profd_foo = private {{.*}}, section "__DATA,__llvm_prf_data,regular,live_support", align 8 -; WIN: @__profc_foo = internal global [1 x i64] zeroinitializer, section ".lprfc$M", align 8 -; WIN: @__profd_foo = internal {{.*}}, section ".lprfd$M", align 8 +; WIN: @__profc_foo = private global [1 x i64] zeroinitializer, section ".lprfc$M", align 8 +; WIN: @__profd_foo = private {{.*}}, section ".lprfd$M", align 8 define void @foo() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_foo, i32 0, i32 0), i64 0, i32 1, i32 0) ret void @@ -32,8 +32,8 @@ ; ELF: @__profd_bar = private {{.*}}, section "__llvm_prf_data", comdat, align 8 ; MACHO: @__profc_bar = private global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 ; MACHO: @__profd_bar = private {{.*}}, section "__DATA,__llvm_prf_data,regular,live_support", align 8 -; WIN: @__profc_bar = internal global [1 x i64] zeroinitializer, section ".lprfc$M", align 8 -; WIN: @__profd_bar = internal {{.*}}, section ".lprfd$M", align 8 +; WIN: @__profc_bar = private global [1 x i64] zeroinitializer, section ".lprfc$M", align 8 +; WIN: @__profd_bar = private {{.*}}, section ".lprfd$M", align 8 define void @bar() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_bar, i32 0, i32 0), i64 0, i32 1, i32 0) ret void @@ -43,8 +43,8 @@ ; ELF: @__profd_baz = private {{.*}}, section "__llvm_prf_data", comdat, align 8 ; MACHO: @__profc_baz = private global [3 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 ; MACHO: @__profd_baz = private {{.*}}, section "__DATA,__llvm_prf_data,regular,live_support", align 8 -; WIN: @__profc_baz = internal global [3 x i64] zeroinitializer, section ".lprfc$M", align 8 -; WIN: @__profd_baz = internal {{.*}}, section ".lprfd$M", align 8 +; WIN: @__profc_baz = private global [3 x i64] zeroinitializer, section ".lprfc$M", align 8 +; WIN: @__profd_baz = private {{.*}}, section ".lprfd$M", align 8 define void @baz() { call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_baz, i32 0, i32 0), i64 0, i32 3, i32 0) call void @llvm.instrprof.increment(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @__profn_baz, i32 0, i32 0), i64 0, i32 3, i32 1)