diff --git a/compiler-rt/test/CMakeLists.txt b/compiler-rt/test/CMakeLists.txt --- a/compiler-rt/test/CMakeLists.txt +++ b/compiler-rt/test/CMakeLists.txt @@ -22,7 +22,7 @@ # Use LLVM utils and Clang from the same build tree. list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS clang clang-resource-headers FileCheck count not llvm-config llvm-nm llvm-objdump - llvm-readobj llvm-symbolizer compiler-rt-headers sancov) + llvm-readelf llvm-readobj llvm-size llvm-symbolizer compiler-rt-headers sancov) if (WIN32) list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS KillTheDoctor) endif() diff --git a/compiler-rt/test/profile/CMakeLists.txt b/compiler-rt/test/profile/CMakeLists.txt --- a/compiler-rt/test/profile/CMakeLists.txt +++ b/compiler-rt/test/profile/CMakeLists.txt @@ -5,6 +5,9 @@ set(PROFILE_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND PROFILE_TEST_DEPS profile llvm-profdata llvm-cov) + if(NOT APPLE AND COMPILER_RT_HAS_LLD AND TARGET lld) + list(APPEND PROFILE_TEST_DEPS lld) + endif() endif() set(PROFILE_TEST_ARCH ${PROFILE_SUPPORTED_ARCH}) diff --git a/compiler-rt/test/profile/instrprof-gc-sections.c b/compiler-rt/test/profile/instrprof-gc-sections.c new file mode 100644 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-gc-sections.c @@ -0,0 +1,85 @@ +// REQUIRES: linux, lld-available + +// RUN: %clang_profgen=%t.profraw -fuse-ld=lld -fcoverage-mapping -mllvm -enable-name-compression=false -DCODE=1 -ffunction-sections -fdata-sections -Wl,--gc-sections -o %t %s +// RUN: %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-profdata show --all-functions %t.profdata | FileCheck %s -check-prefix=PROF +// RUN: llvm-cov show %t -instr-profile %t.profdata | FileCheck %s -check-prefix=COV +// RUN: llvm-nm %t | FileCheck %s -check-prefix=NM +// RUN: llvm-readelf -x __llvm_prf_names %t | FileCheck %s -check-prefix=PRF_NAMES +// RUN: llvm-size -A %t | FileCheck %s -check-prefix=PRF_CNTS + +// RUN: %clang_lto_profgen=%t.lto.profraw -fuse-ld=lld -fcoverage-mapping -mllvm -enable-name-compression=false -DCODE=1 -ffunction-sections -fdata-sections -Wl,--gc-sections -flto -o %t.lto %s +// RUN: %run %t.lto +// RUN: llvm-profdata merge -o %t.lto.profdata %t.lto.profraw +// RUN: llvm-profdata show --all-functions %t.lto.profdata | FileCheck %s -check-prefix=PROF +// RUN: llvm-cov show %t.lto -instr-profile %t.lto.profdata | FileCheck %s -check-prefix=COV +// RUN: llvm-nm %t.lto | FileCheck %s -check-prefix=NM +// RUN: llvm-readelf -x __llvm_prf_names %t.lto | FileCheck %s -check-prefix=PRF_NAMES +// RUN: llvm-size -A %t.lto | FileCheck %s -check-prefix=PRF_CNTS + +// Note: We expect foo() and some of the profiling data associated with it to +// be garbage collected. + +// Note: When there is no code in a program, we expect to see the exact same +// set of external functions provided by the profile runtime. + +// Note: We also check the IR instrumentation and expect foo() to be garbage +// collected as well. + +// RUN: %clang_pgogen=%t.pgo.profraw -fuse-ld=lld -DCODE=1 -ffunction-sections -fdata-sections -Wl,--gc-sections -o %t.pgo %s +// RUN: %run %t.pgo +// RUN: llvm-profdata merge -o %t.pgo.profdata %t.pgo.profraw +// RUN: llvm-profdata show --all-functions %t.pgo.profdata | FileCheck %s -check-prefix=PGO +// RUN: llvm-nm %t.pgo | FileCheck %s -check-prefix=NM + +#ifdef CODE + +// COV: [[@LINE+1]]{{ *}}|{{ *}}0|void foo() +void foo() {} + +// COV: [[@LINE+1]]{{ *}}|{{ *}}1|int main +int main() { return 0; } + +#endif // CODE + +// NM-NOT: foo + +// PROF: Counters: +// PROF-NEXT: main: +// PROF-NEXT: Hash: +// PROF-NEXT: Counters: 1 +// PROF-NEXT: Function count: 1 +// PROF-NEXT: Instrumentation level: Front-end +// PROF-NEXT: Functions shown: 1 +// PROF-NEXT: Total functions: 1 +// PROF-NEXT: Maximum function count: +// PROF-NEXT: Maximum internal block count: + +// Note: We don't expect the names of garbage collected functions to disappear +// from __llvm_prf_names, because collectPGOFuncNameStrings() glues the names +// together. + +// PRF_NAMES: Hex dump of section '__llvm_prf_names': +// PRF_NAMES-NEXT: {{.*}} 0800666f 6f016d61 696e{{.*$}} +// | | f o o # m a i n +// | |___________| +// | | +// UncompressedLen = 8 | +// | +// CompressedLen = 0 + +// Note: We expect the profile counters for garbage collected functions to also +// be garbage collected. + +// PRF_CNTS: __llvm_prf_cnts 8 + +// PGO: Counters: +// PGO-NEXT: main: +// PGO-NEXT: Hash: +// PGO-NEXT: Counters: 1 +// PGO-NEXT: Instrumentation level: IR +// PGO-NEXT: Functions shown: 1 +// PGO-NEXT: Total functions: 1 +// PGO-NEXT: Maximum function count: +// PGO-NEXT: Maximum internal block count: 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 @@ -830,9 +830,18 @@ } std::string DataVarName = getVarName(Inc, getInstrProfDataVarPrefix()); auto MaybeSetComdat = [=](GlobalVariable *GV) { - if (NeedComdat) - GV->setComdat(M->getOrInsertComdat(TT.isOSBinFormatCOFF() ? GV->getName() - : DataVarName)); + // 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; + Comdat *C = M->getOrInsertComdat(GroupName); + if (!NeedComdat) + C->setSelectionKind(Comdat::NoDuplicates); + GV->setComdat(C); + } }; uint64_t NumCounters = Inc->getNumCounters()->getZExtValue(); diff --git a/llvm/test/Instrumentation/InstrProfiling/icall.ll b/llvm/test/Instrumentation/InstrProfiling/icall.ll --- a/llvm/test/Instrumentation/InstrProfiling/icall.ll +++ b/llvm/test/Instrumentation/InstrProfiling/icall.ll @@ -43,8 +43,8 @@ attributes #0 = { nounwind } -; STATIC: @__profvp_foo = private global [1 x i64] zeroinitializer, section "{{[^"]+}}", align 8 -; STATIC: @__profvp_bar = private global [1 x i64] zeroinitializer, section "{{[^"]+}}", comdat($__profd_bar), align 8 +; STATIC: @__profvp_foo = private global [1 x i64] zeroinitializer, section "{{[^"]+}}" +; STATIC: @__profvp_bar = private global [1 x i64] zeroinitializer, section "{{[^"]+}}", comdat($__profd_bar) ; STATIC: @__llvm_prf_vnodes ; DYN-NOT: @__profvp_foo 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 @@ -1,16 +1,22 @@ ;; Check that runtime symbols get appropriate linkage. -; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s --check-prefixes=POSIX,MACHO -; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s --check-prefixes=POSIX,LINUX -; RUN: opt < %s -mtriple=x86_64-unknown-fuchsia -instrprof -S | FileCheck %s --check-prefixes=POSIX,LINUX +; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -instrprof -S | FileCheck %s --check-prefixes=MACHO +; RUN: opt < %s -mtriple=x86_64-unknown-linux -instrprof -S | FileCheck %s --check-prefixes=ELF +; RUN: opt < %s -mtriple=x86_64-unknown-fuchsia -instrprof -S | FileCheck %s --check-prefixes=ELF ; RUN: opt < %s -mtriple=x86_64-pc-win32-coff -instrprof -S | FileCheck %s --check-prefixes=COFF -; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -passes=instrprof -S | FileCheck %s --check-prefixes=POSIX,MACHO -; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes=instrprof -S | FileCheck %s --check-prefixes=POSIX,LINUX -; RUN: opt < %s -mtriple=x86_64-unknown-fuchsia -passes=instrprof -S | FileCheck %s --check-prefixes=POSIX,LINUX +; RUN: opt < %s -mtriple=x86_64-apple-macosx10.10.0 -passes=instrprof -S | FileCheck %s --check-prefixes=MACHO +; RUN: opt < %s -mtriple=x86_64-unknown-linux -passes=instrprof -S | FileCheck %s --check-prefixes=ELF +; RUN: opt < %s -mtriple=x86_64-unknown-fuchsia -passes=instrprof -S | FileCheck %s --check-prefixes=ELF ; RUN: opt < %s -mtriple=x86_64-pc-win32-coff -passes=instrprof -S | FileCheck %s --check-prefixes=COFF ; MACHO: @__llvm_profile_runtime = external global i32 -; LINUX-NOT: @__llvm_profile_runtime = external global i32 +; ELF-NOT: @__llvm_profile_runtime = external global i32 + +; ELF: $__profd_foo = comdat noduplicates +; ELF: $__profd_foo_weak = comdat noduplicates +; ELF: $"__profd_linkage.ll:foo_internal" = comdat noduplicates +; ELF: $__profd_foo_inline = comdat noduplicates +; ELF: $__profd_foo_extern = comdat any @__profn_foo = hidden constant [3 x i8] c"foo" @__profn_foo_weak = weak hidden constant [8 x i8] c"foo_weak" @@ -18,8 +24,10 @@ @__profn_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline" @__profn_foo_extern = linkonce_odr hidden constant [10 x i8] c"foo_extern" -; POSIX: @__profc_foo = hidden global -; POSIX: @__profd_foo = hidden global +; ELF: @__profc_foo = hidden global{{.*}}section "__llvm_prf_cnts", comdat($__profd_foo) +; ELF: @__profd_foo = hidden global{{.*}}section "__llvm_prf_data", comdat +; MACHO: @__profc_foo = hidden global +; MACHO: @__profd_foo = hidden global ; COFF: @__profc_foo = internal global ; COFF-NOT: comdat ; COFF: @__profd_foo = internal global @@ -28,8 +36,10 @@ ret void } -; POSIX: @__profc_foo_weak = weak hidden global -; POSIX: @__profd_foo_weak = weak hidden global +; ELF: @__profc_foo_weak = weak hidden global{{.*}}section "__llvm_prf_cnts", comdat($__profd_foo_weak) +; ELF: @__profd_foo_weak = weak hidden global{{.*}}section "__llvm_prf_data", comdat +; 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 define weak void @foo_weak() { @@ -37,8 +47,10 @@ ret void } -; POSIX: @"__profc_linkage.ll:foo_internal" = internal global -; POSIX: @"__profd_linkage.ll:foo_internal" = internal global +; ELF: @"__profc_linkage.ll:foo_internal" = internal global{{.*}}section "__llvm_prf_cnts", comdat($"__profd_linkage.ll:foo_internal") +; ELF: @"__profd_linkage.ll:foo_internal" = internal global{{.*}}section "__llvm_prf_data", comdat +; MACHO: @"__profc_linkage.ll:foo_internal" = internal global +; MACHO: @"__profd_linkage.ll:foo_internal" = internal global ; COFF: @"__profc_linkage.ll:foo_internal" = internal global ; COFF: @"__profd_linkage.ll:foo_internal" = internal global define internal void @foo_internal() { @@ -46,8 +58,10 @@ ret void } -; POSIX: @__profc_foo_inline = linkonce_odr hidden global -; POSIX: @__profd_foo_inline = linkonce_odr hidden global +; ELF: @__profc_foo_inline = linkonce_odr hidden global{{.*}}section "__llvm_prf_cnts", comdat($__profd_foo_inline) +; ELF: @__profd_foo_inline = linkonce_odr hidden global{{.*}}section "__llvm_prf_data", comdat +; 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 define linkonce_odr void @foo_inline() { @@ -55,8 +69,8 @@ ret void } -; LINUX: @__profc_foo_extern = linkonce_odr hidden global {{.*}}section "__llvm_prf_cnts", comdat($__profd_foo_extern), align 8 -; LINUX: @__profd_foo_extern = linkonce_odr hidden global {{.*}}section "__llvm_prf_data", comdat, align 8 +; ELF: @__profc_foo_extern = linkonce_odr hidden global {{.*}}section "__llvm_prf_cnts", comdat($__profd_foo_extern), align 8 +; ELF: @__profd_foo_extern = linkonce_odr hidden global {{.*}}section "__llvm_prf_data", comdat, align 8 ; MACHO: @__profc_foo_extern = linkonce_odr hidden global ; MACHO: @__profd_foo_extern = linkonce_odr hidden global ; COFF: @__profc_foo_extern = linkonce_odr hidden global {{.*}}section ".lprfc$M", comdat, align 8 @@ -73,5 +87,5 @@ ; MACHO: ret i32 %[[REG]] ; MACHO: } ; COFF: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() {{.*}} comdat { -; LINUX-NOT: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() {{.*}} { -; LINUX-NOT: %[[REG:.*]] = load i32, i32* @__llvm_profile_runtime +; ELF-NOT: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() {{.*}} { +; ELF-NOT: %[[REG:.*]] = load i32, i32* @__llvm_profile_runtime 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 @@ -19,11 +19,11 @@ ; WINDOWS-NOT: __profn_foo ; MACHO: @__profc_foo = hidden global [1 x i64] zeroinitializer, section "__DATA,__llvm_prf_cnts", align 8 -; ELF: @__profc_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8 +; ELF: @__profc_foo = hidden 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 ; MACHO: @__profd_foo = hidden {{.*}}, section "__DATA,__llvm_prf_data,regular,live_support", align 8 -; ELF: @__profd_foo = hidden {{.*}}, section "__llvm_prf_data", align 8 +; ELF: @__profd_foo = hidden {{.*}}, section "__llvm_prf_data", comdat, align 8 ; WINDOWS: @__profd_foo = internal global {{.*}}, section ".lprfd$M", align 8 ; ELF: @__llvm_prf_nm = private constant [{{.*}} x i8] c"{{.*}}", section "{{.*}}__llvm_prf_names", align 1 diff --git a/llvm/test/Transforms/PGOProfile/counter_promo.ll b/llvm/test/Transforms/PGOProfile/counter_promo.ll --- a/llvm/test/Transforms/PGOProfile/counter_promo.ll +++ b/llvm/test/Transforms/PGOProfile/counter_promo.ll @@ -60,7 +60,7 @@ ; ATOMIC_PROMO: atomicrmw add {{.*}} @__profc_foo{{.*}}0), i64 %[[LIVEOUT1]] seq_cst ; ATOMIC_PROMO-NEXT: atomicrmw add {{.*}} @__profc_foo{{.*}}1), i64 %[[LIVEOUT2]] seq_cst ; ATOMIC_PROMO-NEXT: atomicrmw add {{.*}} @__profc_foo{{.*}}2), i64 %[[LIVEOUT3]] seq_cst -; PROMO-NOT: @__profc_foo +; PROMO-NOT: @__profc_foo{{.*}}) } diff --git a/llvm/test/Transforms/PGOProfile/counter_promo_mexits.ll b/llvm/test/Transforms/PGOProfile/counter_promo_mexits.ll --- a/llvm/test/Transforms/PGOProfile/counter_promo_mexits.ll +++ b/llvm/test/Transforms/PGOProfile/counter_promo_mexits.ll @@ -69,7 +69,7 @@ ; PROMO-NEXT: %pgocount{{.*}} = load {{.*}} @__profc_foo{{.*}} 4) ; PROMO-NEXT: add ; PROMO-NEXT: store {{.*}}@__profc_foo{{.*}}4) -; PROMO-NOT: @__profc_foo +; PROMO-NOT: @__profc_foo{{.*}}) bb15: ; preds = %bb14, %bb4