Index: compiler-rt/test/profile/instrprof-gc-sections.c =================================================================== --- /dev/null +++ compiler-rt/test/profile/instrprof-gc-sections.c @@ -0,0 +1,91 @@ +// REQUIRES: linux, lld-available + +// RUN: %clang_profgen=%t.profraw -fuse-ld=lld -fcoverage-mapping -mllvm -counter-associated-metadata -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-readelf -x __llvm_prf_cnts %t | FileCheck %s -check-prefix=PRF_CNTS + +// RUN: %clang_lto_profgen=%t.lto.profraw -fuse-ld=lld -fcoverage-mapping -mllvm -counter-associated-metadata -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-readelf -x __llvm_prf_cnts %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. + +// RUN: %clang_profgen -fuse-ld=lld -fcoverage-mapping -mllvm -counter-associated-metadata -ffunction-sections -fdata-sections -Wl,--gc-sections -shared -o %t.nocode.so %s +// RUN: llvm-nm -jgU %t.nocode.so | grep -vE "__start_.*|__stop_.*" > %t.nocode.syms +// RUN: llvm-nm -jgU %t | grep -vE "main|_start|_IO_stdin_used|__libc_.*" > %t.code.syms +// RUN: diff %t.nocode.syms %t.code.syms + +// 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 -mllvm -counter-associated-metadata -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: Hex dump of section '__llvm_prf_cnts': +// PRF_CNTS-NEXT: {{.*}} 00000000 00000000 {{.*$}} + +// 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: Index: llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -69,6 +69,11 @@ cl::desc("Enable relocating counters at runtime."), cl::init(false)); +cl::opt CounterAssociatedMetadata( + "counter-associated-metadata", + cl::desc("Set counter associated metadata to enable garbage collection at link time."), + cl::init(false)); + cl::opt ValueProfileStaticAlloc( "vp-static-alloc", cl::desc("Do static counter allocation for value profiler"), @@ -850,6 +855,9 @@ CounterPtr->setAlignment(Align(8)); MaybeSetComdat(CounterPtr); CounterPtr->setLinkage(Linkage); + if (CounterAssociatedMetadata) + CounterPtr->setMetadata(LLVMContext::MD_associated, + MDNode::get(Ctx, ValueAsMetadata::get(CounterPtr))); auto *Int8PtrTy = Type::getInt8PtrTy(Ctx); // Allocate statically the array of pointers to value profile nodes for @@ -871,6 +879,10 @@ getInstrProfSectionName(IPSK_vals, TT.getObjectFormat())); ValuesVar->setAlignment(Align(8)); MaybeSetComdat(ValuesVar); + if (CounterAssociatedMetadata) + ValuesVar->setMetadata( + LLVMContext::MD_associated, + MDNode::get(Ctx, ValueAsMetadata::get(CounterPtr))); ValuesPtrExpr = ConstantExpr::getBitCast(ValuesVar, Type::getInt8PtrTy(Ctx)); } @@ -905,6 +917,9 @@ Data->setAlignment(Align(INSTR_PROF_DATA_ALIGNMENT)); MaybeSetComdat(Data); Data->setLinkage(Linkage); + if (CounterAssociatedMetadata) + Data->setMetadata(LLVMContext::MD_associated, + MDNode::get(Ctx, ValueAsMetadata::get(CounterPtr))); PD.RegionCounters = CounterPtr; PD.DataVar = Data; Index: llvm/test/Instrumentation/InstrProfiling/associated.ll =================================================================== --- /dev/null +++ llvm/test/Instrumentation/InstrProfiling/associated.ll @@ -0,0 +1,17 @@ +; RUN: opt < %s -instrprof -counter-associated-metadata -S | FileCheck %s +; RUN: opt < %s -passes=instrprof -counter-associated-metadata -S | FileCheck %s + +@__profn_foo = hidden constant [3 x i8] c"foo" + +; CHECK: @__profc_foo = hidden global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8, !associated !0 +; CHECK: @__profd_foo = hidden global {{.*}}, section "__llvm_prf_data", align 8, !associated !1 + +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 +} + +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) + +; CHECK: !0 = !{} +; CHECK: !1 = !{[1 x i64]* @__profc_foo} Index: llvm/test/Transforms/PGOProfile/associated.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/PGOProfile/associated.ll @@ -0,0 +1,12 @@ +; RUN: opt < %s -pgo-instr-gen -instrprof -counter-associated-metadata -S | FileCheck %s +; RUN: opt < %s -passes=pgo-instr-gen,instrprof -counter-associated-metadata -S | FileCheck %s + +; CHECK: @__profc_foo = private global [1 x i64] zeroinitializer, section "__llvm_prf_cnts", align 8, !associated !0 +; CHECK: @__profd_foo = private global {{.*}}, section "__llvm_prf_data", align 8, !associated !1 + +define void @foo() { + ret void +} + +; CHECK: !0 = !{} +; CHECK: !1 = !{[1 x i64]* @__profc_foo} Index: llvm/test/Transforms/PGOProfile/counter_promo.ll =================================================================== --- llvm/test/Transforms/PGOProfile/counter_promo.ll +++ 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{{.*}}) } Index: llvm/test/Transforms/PGOProfile/counter_promo_mexits.ll =================================================================== --- llvm/test/Transforms/PGOProfile/counter_promo_mexits.ll +++ 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