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 @@ -955,8 +955,9 @@ // // On COFF, a comdat leader cannot be local so we require DataReferencedByCode // to be false. - if (NS == 0 && (TT.isOSBinFormatELF() || - (!DataReferencedByCode && TT.isOSBinFormatCOFF()))) { + if (NS == 0 && !(Fn->GlobalValue::hasComdat() && !canRenameComdatFunc(*Fn)) && + (TT.isOSBinFormatELF() || + (!DataReferencedByCode && TT.isOSBinFormatCOFF()))) { Linkage = GlobalValue::PrivateLinkage; Visibility = GlobalValue::DefaultVisibility; } diff --git a/llvm/test/Instrumentation/InstrProfiling/comdat.ll b/llvm/test/Instrumentation/InstrProfiling/comdat.ll --- a/llvm/test/Instrumentation/InstrProfiling/comdat.ll +++ b/llvm/test/Instrumentation/InstrProfiling/comdat.ll @@ -16,31 +16,38 @@ ;--- main.ll declare void @llvm.instrprof.increment(i8*, i64, i32, i32) -$foo_inline = comdat any +$foo_inline0 = comdat any +$foo_inline1 = comdat any $foo_extern = comdat any -@__profn_foo_inline = linkonce_odr hidden constant [10 x i8] c"foo_inline" +@__profn_foo_inline0 = linkonce_odr hidden constant [11 x i8] c"foo_inline0" +@__profn_foo_inline1 = linkonce_odr hidden constant [11 x i8] c"foo_inline1" @__profn_foo_extern = linkonce_odr hidden constant [10 x i8] c"foo_extern" +; ELF: @__profc_foo_inline0 = linkonce_odr hidden global {{.*}}, section "__llvm_prf_cnts", comdat, align 8 +; ELF: @__profd_foo_inline0 = private global {{.*}}, section "__llvm_prf_data", comdat($__profc_foo_inline0), align 8 +define linkonce_odr void @foo_inline0() unnamed_addr comdat { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__profn_foo_inline0, i32 0, i32 0), i64 0, i32 1, i32 0) + ret void +} + ;; When value profiling is disabled, __profd_ variables are not referenced by ;; code. We can use private linkage. When enabled, __profd_ needs to be ;; non-local which requires separate comdat on COFF due to a link.exe limitation. -; ELF: @__profc_foo_inline = linkonce_odr hidden global {{.*}}, section "__llvm_prf_cnts", comdat, align 8 -; ELF0: @__profd_foo_inline = private global {{.*}}, section "__llvm_prf_data", comdat($__profc_foo_inline), align 8 -; ELF1: @__profd_foo_inline = linkonce_odr hidden global {{.*}}, section "__llvm_prf_data", comdat($__profc_foo_inline), align 8 -; COFF0: @__profc_foo_inline = linkonce_odr hidden global {{.*}}, section ".lprfc$M", comdat, align 8 -; COFF0: @__profd_foo_inline = private global {{.*}}, section ".lprfd$M", comdat($__profc_foo_inline), align 8 -; COFF1: @__profc_foo_inline = linkonce_odr hidden global {{.*}}, section ".lprfc$M", comdat, align 8 -; COFF1: @__profd_foo_inline = linkonce_odr hidden global {{.*}}, section ".lprfd$M", comdat, align 8 -define weak_odr void @foo_inline() comdat { - 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) +; ELF: @__profc_foo_inline1 = linkonce_odr hidden global {{.*}}, section "__llvm_prf_cnts", comdat, align 8 +; ELF: @__profd_foo_inline1 = linkonce_odr hidden global {{.*}}, section "__llvm_prf_data", comdat($__profc_foo_inline1), align 8 +; COFF0: @__profc_foo_inline1 = linkonce_odr hidden global {{.*}}, section ".lprfc$M", comdat, align 8 +; COFF0: @__profd_foo_inline1 = private global {{.*}}, section ".lprfd$M", comdat($__profc_foo_inline1), align 8 +; COFF1: @__profc_foo_inline1 = linkonce_odr hidden global {{.*}}, section ".lprfc$M", comdat, align 8 +; COFF1: @__profd_foo_inline1 = linkonce_odr hidden global {{.*}}, section ".lprfd$M", comdat, align 8 +define weak_odr void @foo_inline1() comdat { + call void @llvm.instrprof.increment(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @__profn_foo_inline1, i32 0, i32 0), i64 0, i32 1, i32 0) ret void } ; ELF: @__profc_foo_extern = linkonce_odr hidden global{{.*}}, section "__llvm_prf_cnts", comdat, align 8 -; ELF0: @__profd_foo_extern = private global{{.*}}, section "__llvm_prf_data", comdat($__profc_foo_extern), align 8 -; ELF1: @__profd_foo_extern = linkonce_odr hidden global{{.*}}, section "__llvm_prf_data", comdat($__profc_foo_extern), align 8 +; ELF: @__profd_foo_extern = private global{{.*}}, section "__llvm_prf_data", comdat($__profc_foo_extern), align 8 ; COFF: @__profc_foo_extern = linkonce_odr hidden global{{.*}}, section ".lprfc$M", comdat, align 8 ; COFF0: @__profd_foo_extern = private global{{.*}}, section ".lprfd$M", comdat($__profc_foo_extern), align 8 ; COFF1: @__profd_foo_extern = linkonce_odr hidden global{{.*}}, section ".lprfd$M", comdat, align 8 @@ -49,9 +56,9 @@ ret void } -; ELF: @llvm.compiler.used = appending global {{.*}} @__profd_foo_inline {{.*}} @__profd_foo_extern -; COFF0: @llvm.compiler.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo_inline {{.*}} @__profd_foo_extern -; COFF1: @llvm.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo_inline {{.*}} @__profd_foo_extern +; ELF: @llvm.compiler.used = appending global {{.*}} @__profd_foo_inline0 {{.*}} @__profd_foo_inline1 {{.*}} @__profd_foo_extern +; COFF0: @llvm.compiler.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo_inline0 {{.*}} @__profd_foo_inline1 {{.*}} @__profd_foo_extern +; COFF1: @llvm.used = appending global {{.*}} @__llvm_profile_runtime_user {{.*}} @__profd_foo_inline0 {{.*}} @__profd_foo_inline1 {{.*}} @__profd_foo_extern ;--- disable.ll !llvm.module.flags = !{!0} diff --git a/llvm/test/Transforms/PGOProfile/comdat.ll b/llvm/test/Transforms/PGOProfile/comdat.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/PGOProfile/comdat.ll @@ -0,0 +1,35 @@ +; There are two main cases where comdats are necessary: +; 1. standard inline functions (weak_odr / linkonce_odr) +; 2. available externally functions (C99 inline / extern template / dllimport) +; Check that we do the right thing for the two object formats with comdats, ELF +; and COFF. +; +; Test comdat functions. Non-comdat functions are tested in linkage.ll. +; RUN: opt < %s -mtriple=x86_64-linux -passes=pgo-instr-gen,instrprof -S | FileCheck %s --check-prefixes=ELF +; RUN: opt < %s -mtriple=x86_64-windows -passes=pgo-instr-gen,instrprof -S | FileCheck %s --check-prefixes=COFF + +;--- main.ll +declare void @llvm.instrprof.increment(i8*, i64, i32, i32) + +$unnamed = comdat any +$weakodr = comdat any + +; ELF: @__profc_unnamed.[[#]] = linkonce_odr hidden global {{.*}} comdat, align 8 +; ELF: @__profd_unnamed.[[#]] = private global {{.*}} comdat($__profc_unnamed.[[#]]), align 8 +; COFF: @__profc_unnamed.[[#]] = linkonce_odr hidden global {{.*}} comdat, align 8 +; COFF: @__profd_unnamed.[[#]] = linkonce_odr hidden global {{.*}} comdat, align 8 +define linkonce_odr void @unnamed() unnamed_addr comdat { + ret void +} + +;; weakodr in a comdat is not renamed. We may have other copies which are non-local +;; (if value profiling is enabled). If we cannot make this profd private, the non-prevailing, +;; when inlined into another function, may reference a discarded profd. + +; ELF: @__profc_weakodr = weak_odr hidden global {{.*}} comdat, align 8 +; ELF: @__profd_weakodr = weak_odr hidden global {{.*}} comdat($__profc_weakodr), align 8 +; COFF: @__profc_weakodr = weak_odr hidden global {{.*}} comdat, align 8 +; COFF: @__profd_weakodr = weak_odr hidden global {{.*}} comdat, align 8 +define weak_odr void @weakodr() comdat { + ret void +}