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 + +; 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 @@ -1014,9 +1014,17 @@ }; auto *DataTy = StructType::get(Ctx, makeArrayRef(DataTypes)); - Constant *FunctionAddr = shouldRecordFunctionAddr(Fn) - ? ConstantExpr::getBitCast(Fn, Int8PtrTy) - : ConstantPointerNull::get(Int8PtrTy); + Constant *FunctionAddr; + if (shouldRecordFunctionAddr(Fn)) { + // When possible use a private alias to avoid relocations + Constant *Addr = !Fn->isDeclarationForLinker() + ? static_cast(GlobalAlias::create( + GlobalValue::PrivateLinkage, Fn->getName(), Fn)) + : Fn; + FunctionAddr = ConstantExpr::getBitCast(Addr, Int8PtrTy); + } else { + FunctionAddr = ConstantPointerNull::get(Int8PtrTy); + } 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 +} +