diff --git a/compiler-rt/test/profile/instrprof-discarded-comdat.ll b/compiler-rt/test/profile/instrprof-discarded-comdat.ll new file mode 100644 --- /dev/null +++ b/compiler-rt/test/profile/instrprof-discarded-comdat.ll @@ -0,0 +1,40 @@ +; Check that instrprof does not introduce references to discaded sections when +; using comdats. + +; Occasionally, it is possible that the same function can be compiled in +; different TUs with slightly different linkages, e.g., due to different +; compiler options. However, if these are comdat functions, a single +; implementation will be chosen at link time. we want to ensure that the +; profiling data does not contain a reference to the discarded section. + +; RUN: split-file %s %t + +; RUN: opt %t/a1.ll -disable-preinline -passes="pgo-instr-gen,instrprof" -S | llc --filetype=obj -o %t/a1.o +; RUN: opt %t/a2.ll -passes="pgo-instr-gen,instrprof" -S | llc --filetype=obj -o %t/a2.o + +; RUN: %clang -fPIC -shared -o %t/liba.so %t/a1.o %t/a2.o 2>&1 | FileCheck %s --allow-empty + +; Ensure that we don't get an error when linking +; CHECK-NOT: relocation refers to a discarded section: .text._ZN1CIiE1fEi + +;--- a1.ll +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" +$_ZN1CIiE1fEi = comdat any + +define weak void @_ZN1CIiE1fEi(ptr %this, i32 %x) comdat { +entry: + ret void +} + + + +;--- a2.ll +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" +$_ZN1CIiE1fEi = comdat any + +define linkonce_odr void @_ZN1CIiE1fEi(ptr %this, i32 %x) comdat { +entry: + ret void +} 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 @@ -823,6 +823,27 @@ return F->hasAddressTaken() || F->hasLinkOnceLinkage(); } +static inline Constant *getFuncAddrForProfData(Function *Fn) { + auto *Int8PtrTy = Type::getInt8PtrTy(Fn->getContext()); + // Use a nullptr in __llvm_profd, if we don't need the real address + if (!shouldRecordFunctionAddr(Fn)) + return ConstantPointerNull::get(Int8PtrTy); + + // If we can't use an alias, use the public symbol. + // This may require a relocation with an addend, but this is the only correct + // approach. Similarly, don't create an alias for COMDAT functions, since + // doing so may result in references to discarded sections. + if (Fn->isDeclarationForLinker() || Fn->hasComdat()) + return ConstantExpr::getBitCast(Fn, Int8PtrTy); + + // When possible use an alias to avoid relocations with addends + // By default we make it private + GlobalAlias *GA = GlobalAlias::create( + GlobalValue::LinkageTypes::PrivateLinkage, Fn->getName(), Fn); + + return ConstantExpr::getBitCast(GA, Int8PtrTy); +} + static bool needsRuntimeRegistrationOfSectionRange(const Triple &TT) { // Don't do this for Darwin. compiler-rt uses linker magic. if (TT.isOSDarwin()) @@ -1014,9 +1035,7 @@ }; auto *DataTy = StructType::get(Ctx, makeArrayRef(DataTypes)); - Constant *FunctionAddr = shouldRecordFunctionAddr(Fn) - ? ConstantExpr::getBitCast(Fn, Int8PtrTy) - : ConstantPointerNull::get(Int8PtrTy); + Constant *FunctionAddr = getFuncAddrForProfData(Fn); Constant *Int16ArrayVals[IPVK_Last + 1]; for (uint32_t Kind = IPVK_First; Kind <= IPVK_Last; ++Kind) diff --git a/llvm/test/Transforms/PGOProfile/prof_avoid_relocs.ll b/llvm/test/Transforms/PGOProfile/prof_avoid_relocs.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/prof_avoid_relocs.ll @@ -0,0 +1,23 @@ +; RUN: opt -S -passes=pgo-instr-gen,instrprof < %s | FileCheck %s + +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Test that we use private aliases to reference function addresses inside profile data + +; CHECK: @__profd_foo = private global {{.*}}, ptr @foo.1, +; CHECK-NOT: @__profd_foo = private global {{.*}}, ptr @foo, +; CHECK: @foo.1 = private alias i32 (i32), ptr @foo + +define i32 @foo(i32 %0) { +; CHECK-LABEL: @foo( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[PGOCOUNT:%.*]] = load i64, ptr @__profc_foo, align 8 +; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[PGOCOUNT]], 1 +; CHECK-NEXT: store i64 [[TMP1]], ptr @__profc_foo, align 8 +; CHECK-NEXT: ret i32 0 +; +entry: + ret i32 0 +} +