|
| 1 | +// This is a regression test for ThinLTO indirect-call-promotion when candidate |
| 2 | +// callees need to be imported from another IR module. In the C++ test case, |
| 3 | +// `main` calls `global_func` which is defined in another module. `global_func` |
| 4 | +// has two indirect callees, one has external linkage and one has local linkage. |
| 5 | +// All three functions should be imported into the IR module of main. |
| 6 | + |
| 7 | +// What the test does: |
| 8 | +// - Generate raw profiles from executables and convert it to indexed profiles. |
| 9 | +// During the conversion, a profiled callee address in raw profiles will be |
| 10 | +// converted to function hash in indexed profiles. |
| 11 | +// - Run IRPGO profile use and ThinTLO prelink pipeline and get LLVM bitcodes |
| 12 | +// for both cpp files in the C++ test case. |
| 13 | +// - Generate ThinLTO summary file with LLVM bitcodes, and run `function-import` pass. |
| 14 | +// - Run `pgo-icall-prom` pass for the IR module which needs to import callees. |
| 15 | + |
| 16 | +// Use lld as linker for more robust test. We need to REQUIRE LLVMgold.so for |
| 17 | +// LTO if default linker is GNU ld or gold anyway. |
| 18 | +// REQUIRES: lld-available |
| 19 | + |
| 20 | +// Test should fail where linkage-name and mangled-name diverges, see issue https://github.com/llvm/llvm-project/issues/74565). |
| 21 | +// Currently, this name divergence happens on Mach-O object file format, or on |
| 22 | +// many (but not all) 32-bit Windows systems. |
| 23 | +// |
| 24 | +// XFAIL: system-darwin |
| 25 | +// |
| 26 | +// Mark 32-bit Windows as UNSUPPORTED for now as opposed to XFAIL. This test |
| 27 | +// should fail on many (but not all) 32-bit Windows systems and succeed on the |
| 28 | +// rest. The flexibility in triple string parsing makes it tricky to capture |
| 29 | +// both sets accurately. i[3-9]86 specifies arch as Triple::ArchType::x86, (win32|windows) |
| 30 | +// specifies OS as Triple::OS::Win32 |
| 31 | +// |
| 32 | +// UNSUPPORTED: target={{i.86.*windows.*}} |
| 33 | + |
| 34 | +// RUN: rm -rf %t && split-file %s %t && cd %t |
| 35 | + |
| 36 | +// Do setup work for all below tests. |
| 37 | +// Generate raw profiles from real programs and convert it into indexed profiles. |
| 38 | +// Use clangxx_pgogen for IR level instrumentation for C++. |
| 39 | +// RUN: %clangxx_pgogen -fuse-ld=lld -O2 lib.cpp main.cpp -o main |
| 40 | +// RUN: env LLVM_PROFILE_FILE=main.profraw %run ./main |
| 41 | +// RUN: llvm-profdata merge main.profraw -o main.profdata |
| 42 | + |
| 43 | +// Use profile on lib and get bitcode, test that local function callee0 has |
| 44 | +// expected !PGOFuncName metadata and external function callee1 doesn't have |
| 45 | +// !PGOFuncName metadata. Explicitly skip ICP pass to test ICP happens as |
| 46 | +// expected in the IR module that imports functions from lib. |
| 47 | +// RUN: %clang -mllvm -disable-icp -fprofile-use=main.profdata -flto=thin -O2 -c lib.cpp -o lib.bc |
| 48 | +// RUN: llvm-dis lib.bc -o - | FileCheck %s --check-prefix=PGOName |
| 49 | + |
| 50 | +// Use profile on main and get bitcode. |
| 51 | +// RUN: %clang -fprofile-use=main.profdata -flto=thin -O2 -c main.cpp -o main.bc |
| 52 | + |
| 53 | +// Run llvm-lto to get summary file. |
| 54 | +// RUN: llvm-lto -thinlto -o summary main.bc lib.bc |
| 55 | + |
| 56 | +// Test the imports of functions. Default import thresholds would work but do |
| 57 | +// explicit override to be more futureproof. Note all functions have one basic |
| 58 | +// block with a function-entry-count of one, so they are actually hot functions |
| 59 | +// per default profile summary hotness cutoff. |
| 60 | +// RUN: opt -passes=function-import -import-instr-limit=100 -import-cold-multiplier=1 -summary-file summary.thinlto.bc main.bc -o main.import.bc -print-imports 2>&1 | FileCheck %s --check-prefix=IMPORTS |
| 61 | +// Test that '_Z11global_funcv' has indirect calls annotated with value profiles. |
| 62 | +// RUN: llvm-dis main.import.bc -o - | FileCheck %s --check-prefix=IR |
| 63 | + |
| 64 | +// Test that both candidates are ICP'ed and there is no `!VP` in the IR. |
| 65 | +// RUN: opt main.import.bc -icp-lto -passes=pgo-icall-prom -S -pass-remarks=pgo-icall-prom 2>&1 | FileCheck %s --check-prefixes=ICP-IR,ICP-REMARK --implicit-check-not="!VP" |
| 66 | + |
| 67 | +// IMPORTS: main.cpp: Import _Z7callee1v |
| 68 | +// IMPORTS: main.cpp: Import _ZL7callee0v.llvm.[[#]] |
| 69 | +// IMPORTS: main.cpp: Import _Z11global_funcv |
| 70 | + |
| 71 | +// PGOName: define {{(dso_local )?}}void @_Z7callee1v() #[[#]] !prof ![[#]] { |
| 72 | +// PGOName: define internal void @_ZL7callee0v() #[[#]] !prof ![[#]] !PGOFuncName ![[#MD:]] { |
| 73 | +// PGOName: ![[#MD]] = !{!"{{.*}}lib.cpp;_ZL7callee0v"} |
| 74 | + |
| 75 | +// IR-LABEL: define available_externally {{.*}} void @_Z11global_funcv() {{.*}} !prof ![[#]] { |
| 76 | +// IR-NEXT: entry: |
| 77 | +// IR-NEXT: %0 = load ptr, ptr @calleeAddrs |
| 78 | +// IR-NEXT: tail call void %0(), !prof ![[#PROF1:]] |
| 79 | +// IR-NEXT: %1 = load ptr, ptr getelementptr inbounds ([2 x ptr], ptr @calleeAddrs, |
| 80 | +// IR-NEXT: tail call void %1(), !prof ![[#PROF2:]] |
| 81 | + |
| 82 | +// The GUID of indirect callee is the MD5 hash of `/path/to/lib.cpp;_ZL7callee0v` |
| 83 | +// that depends on the directory. Use [[#]] for its MD5 hash. |
| 84 | +// Use {{.*}} for integer types so the test works on 32-bit and 64-bit systems. |
| 85 | +// IR: ![[#PROF1]] = !{!"VP", i32 0, {{.*}} 1, {{.*}} [[#]], {{.*}} 1} |
| 86 | +// IR: ![[#PROF2]] = !{!"VP", i32 0, {{.*}} 1, {{.*}} -3993653843325621743, {{.*}} 1} |
| 87 | + |
| 88 | +// ICP-REMARK: Promote indirect call to _ZL7callee0v.llvm.[[#]] with count 1 out of 1 |
| 89 | +// ICP-REMARK: Promote indirect call to _Z7callee1v with count 1 out of 1 |
| 90 | + |
| 91 | +// ICP-IR: br i1 %[[#]], label %if.true.direct_targ, label %if.false.orig_indirect, !prof ![[#BRANCH_WEIGHT1:]] |
| 92 | +// ICP-IR: br i1 %[[#]], label %if.true.direct_targ1, label %if.false.orig_indirect2, !prof ![[#BRANCH_WEIGHT1]] |
| 93 | +// ICP-IR: ![[#BRANCH_WEIGHT1]] = !{!"branch_weights", i32 1, i32 0} |
| 94 | + |
| 95 | +//--- lib.h |
| 96 | +void global_func(); |
| 97 | + |
| 98 | +//--- lib.cpp |
| 99 | +#include "lib.h" |
| 100 | +static void callee0() {} |
| 101 | +void callee1() {} |
| 102 | +typedef void (*FPT)(); |
| 103 | +FPT calleeAddrs[] = {callee0, callee1}; |
| 104 | +// `global_func`` might call one of two indirect callees. callee0 has internal |
| 105 | +// linkage and callee1 has external linkage. |
| 106 | +void global_func() { |
| 107 | + FPT fp = calleeAddrs[0]; |
| 108 | + fp(); |
| 109 | + fp = calleeAddrs[1]; |
| 110 | + fp(); |
| 111 | +} |
| 112 | + |
| 113 | +//--- main.cpp |
| 114 | +#include "lib.h" |
| 115 | +int main() { global_func(); } |
0 commit comments