1; REQUIRES: x86-registered-target 2 3; Test devirtualization through the thin link and backend. 4 5; Generate split module with summary for hybrid Thin/Regular LTO WPD. 6; RUN: opt -thinlto-bc -thinlto-split-lto-unit -o %t.o %s 7 8; Check that we have module flag showing splitting enabled, and that we don't 9; generate summary information needed for index-based WPD. 10; RUN: llvm-modextract -b -n=0 %t.o -o %t.o.0 11; RUN: llvm-dis -o - %t.o.0 | FileCheck %s --check-prefix=ENABLESPLITFLAG --implicit-check-not=vTableFuncs --implicit-check-not=typeidCompatibleVTable 12; RUN: llvm-modextract -b -n=1 %t.o -o %t.o.1 13; RUN: llvm-dis -o - %t.o.1 | FileCheck %s --check-prefix=ENABLESPLITFLAG --implicit-check-not=vTableFuncs --implicit-check-not=typeidCompatibleVTable 14; ENABLESPLITFLAG: !{i32 1, !"EnableSplitLTOUnit", i32 1} 15 16; Generate unsplit module with summary for ThinLTO index-based WPD. 17; RUN: opt -thinlto-bc -o %t2.o %s 18 19; Check that we don't have module flag when splitting not enabled for ThinLTO, 20; and that we generate summary information needed for index-based WPD. 21; RUN: llvm-dis -o - %t2.o | FileCheck %s --check-prefix=NOENABLESPLITFLAG 22; NOENABLESPLITFLAG-DAG: !{i32 1, !"EnableSplitLTOUnit", i32 0} 23; NOENABLESPLITFLAG-DAG: [[An:\^[0-9]+]] = gv: (name: "_ZN1A1nEi" 24; NOENABLESPLITFLAG-DAG: [[Bf:\^[0-9]+]] = gv: (name: "_ZN1B1fEi" 25; NOENABLESPLITFLAG-DAG: [[Cf:\^[0-9]+]] = gv: (name: "_ZN1C1fEi" 26; NOENABLESPLITFLAG-DAG: [[Dm:\^[0-9]+]] = gv: (name: "_ZN1D1mEi" 27; NOENABLESPLITFLAG-DAG: [[B:\^[0-9]+]] = gv: (name: "_ZTV1B", {{.*}} vTableFuncs: ((virtFunc: [[Bf]], offset: 16), (virtFunc: [[An]], offset: 24)), refs: ([[Bf]], [[An]]) 28; NOENABLESPLITFLAG-DAG: [[C:\^[0-9]+]] = gv: (name: "_ZTV1C", {{.*}} vTableFuncs: ((virtFunc: [[Cf]], offset: 16), (virtFunc: [[An]], offset: 24)), refs: ([[An]], [[Cf]]) 29; NOENABLESPLITFLAG-DAG: [[D:\^[0-9]+]] = gv: (name: "_ZTV1D", {{.*}} vTableFuncs: ((virtFunc: [[Dm]], offset: 16)), refs: ([[Dm]]) 30; NOENABLESPLITFLAG-DAG: [[B_RV:\^[0-9]+]] = gv: (name: "_ZTV1B_RV", {{.*}} vTableFuncs: ((virtFunc: [[Bf]], offset: 8), (virtFunc: [[An]], offset: 12)), refs: ([[B_RV]], [[Bf]], [[An]]) 31; NOENABLESPLITFLAG-DAG: [[C_RV:\^[0-9]+]] = gv: (name: "_ZTV1C_RV", {{.*}} vTableFuncs: ((virtFunc: [[Cf]], offset: 8), (virtFunc: [[An]], offset: 12)), refs: ([[C_RV]], [[An]], [[Cf]]) 32; NOENABLESPLITFLAG-DAG: [[D_RV:\^[0-9]+]] = gv: (name: "_ZTV1D_RV", {{.*}} vTableFuncs: ((virtFunc: [[Dm]], offset: 8)), refs: ([[D_RV]], [[Dm]]) 33; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1A", summary: ((offset: 16, [[B]]), (offset: 16, [[C]]))) 34; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1B", summary: ((offset: 16, [[B]]))) 35; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1C", summary: ((offset: 16, [[C]]))) 36; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1A_RV", summary: ((offset: 8, [[B_RV]]), (offset: 8, [[C_RV]]))) 37; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1B_RV", summary: ((offset: 8, [[B_RV]]))) 38; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "_ZTS1C_RV", summary: ((offset: 8, [[C_RV]]))) 39; Type Id on _ZTV1D should have been promoted 40; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "1.{{.*}}", summary: ((offset: 16, [[D]]))) 41; NOENABLESPLITFLAG-DAG: typeidCompatibleVTable: (name: "2.{{.*}}", summary: ((offset: 8, [[D_RV]]))) 42 43; Index based WPD 44; RUN: llvm-lto2 run %t2.o -save-temps -pass-remarks=. \ 45; RUN: -whole-program-visibility \ 46; RUN: -o %t3 \ 47; RUN: -r=%t2.o,test,px \ 48; RUN: -r=%t2.o,test_rv,px \ 49; RUN: -r=%t2.o,_ZN1A1nEi,p \ 50; RUN: -r=%t2.o,_ZN1B1fEi,p \ 51; RUN: -r=%t2.o,_ZN1C1fEi,p \ 52; RUN: -r=%t2.o,_ZN1D1mEi,p \ 53; RUN: -r=%t2.o,_ZTV1B,px \ 54; RUN: -r=%t2.o,_ZTV1C,px \ 55; RUN: -r=%t2.o,_ZTV1D,px \ 56; RUN: -r=%t2.o,_ZTV1B_RV,px \ 57; RUN: -r=%t2.o,_ZTV1C_RV,px \ 58; RUN: -r=%t2.o,_ZTV1D_RV,px \ 59; RUN: 2>&1 | FileCheck %s --check-prefix=REMARK 60; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR 61 62; Check that we're able to prevent specific function from being 63; devirtualized when running index based WPD. 64; RUN: llvm-lto2 run %t2.o -save-temps -pass-remarks=. \ 65; RUN: -whole-program-visibility \ 66; RUN: -wholeprogramdevirt-skip=_ZN1A1nEi \ 67; RUN: -o %t3 \ 68; RUN: -r=%t2.o,test,px \ 69; RUN: -r=%t2.o,test_rv,px \ 70; RUN: -r=%t2.o,_ZN1A1nEi,p \ 71; RUN: -r=%t2.o,_ZN1B1fEi,p \ 72; RUN: -r=%t2.o,_ZN1C1fEi,p \ 73; RUN: -r=%t2.o,_ZN1D1mEi,p \ 74; RUN: -r=%t2.o,_ZTV1B,px \ 75; RUN: -r=%t2.o,_ZTV1C,px \ 76; RUN: -r=%t2.o,_ZTV1D,px \ 77; RUN: -r=%t2.o,_ZTV1B_RV,px \ 78; RUN: -r=%t2.o,_ZTV1C_RV,px \ 79; RUN: -r=%t2.o,_ZTV1D_RV,px \ 80; RUN: 2>&1 | FileCheck %s --check-prefix=SKIP 81 82; RUN: llvm-lto2 run %t.o -save-temps -pass-remarks=. \ 83; RUN: -whole-program-visibility \ 84; RUN: -o %t3 \ 85; RUN: -r=%t.o,test,px \ 86; RUN: -r=%t.o,test_rv,px \ 87; RUN: -r=%t.o,_ZN1A1nEi,p \ 88; RUN: -r=%t.o,_ZN1B1fEi,p \ 89; RUN: -r=%t.o,_ZN1C1fEi,p \ 90; RUN: -r=%t.o,_ZN1D1mEi,p \ 91; RUN: -r=%t.o,_ZTV1B, \ 92; RUN: -r=%t.o,_ZTV1C, \ 93; RUN: -r=%t.o,_ZTV1D, \ 94; RUN: -r=%t.o,_ZTV1B_RV, \ 95; RUN: -r=%t.o,_ZTV1C_RV, \ 96; RUN: -r=%t.o,_ZTV1D_RV, \ 97; RUN: -r=%t.o,_ZN1A1nEi, \ 98; RUN: -r=%t.o,_ZN1B1fEi, \ 99; RUN: -r=%t.o,_ZN1C1fEi, \ 100; RUN: -r=%t.o,_ZN1D1mEi, \ 101; RUN: -r=%t.o,_ZTV1B,px \ 102; RUN: -r=%t.o,_ZTV1C,px \ 103; RUN: -r=%t.o,_ZTV1D,px \ 104; RUN: -r=%t.o,_ZTV1B_RV,px \ 105; RUN: -r=%t.o,_ZTV1C_RV,px \ 106; RUN: -r=%t.o,_ZTV1D_RV,px \ 107; RUN: 2>&1 | FileCheck %s --check-prefix=REMARK --dump-input=fail 108; RUN: llvm-dis %t3.1.4.opt.bc -o - | FileCheck %s --check-prefix=CHECK-IR 109 110; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi 111; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi 112; REMARK-DAG: single-impl: devirtualized a call to _ZN1A1nEi 113; REMARK-DAG: single-impl: devirtualized a call to _ZN1D1mEi 114 115; SKIP-NOT: devirtualized a call to _ZN1A1nEi 116 117target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" 118target triple = "x86_64-grtev4-linux-gnu" 119 120%struct.A = type { ptr } 121%struct.B = type { %struct.A } 122%struct.C = type { %struct.A } 123%struct.D = type { ptr } 124 125@_ZTV1B = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr undef, ptr @_ZN1B1fEi, ptr @_ZN1A1nEi] }, !type !0, !type !1 126@_ZTV1C = constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr undef, ptr @_ZN1C1fEi, ptr @_ZN1A1nEi] }, !type !0, !type !2 127@_ZTV1D = constant { [3 x ptr] } { [3 x ptr] [ptr null, ptr undef, ptr @_ZN1D1mEi] }, !type !3 128 129@_ZTV1B_RV = constant { [4 x i32] } { [4 x i32] [ 130 i32 0, 131 i32 undef, 132 i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1B1fEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1B_RV, i32 0, i32 0, i32 2) to i64)) to i32), 133 i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A1nEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1B_RV, i32 0, i32 0, i32 3) to i64)) to i32) 134] }, !type !7, !type !8 135 136@_ZTV1C_RV = constant { [4 x i32] } { [4 x i32] [ 137 i32 0, 138 i32 undef, 139 i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1C1fEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1C_RV, i32 0, i32 0, i32 2) to i64)) to i32), 140 i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1A1nEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [4 x i32] }, ptr @_ZTV1C_RV, i32 0, i32 0, i32 3) to i64)) to i32) 141] }, !type !7, !type !9 142 143@_ZTV1D_RV = constant { [3 x i32] } { [3 x i32] [ 144 i32 0, 145 i32 undef, 146 i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @_ZN1D1mEi to i64), i64 ptrtoint (ptr getelementptr inbounds ({ [3 x i32] }, ptr @_ZTV1D_RV, i32 0, i32 0, i32 2) to i64)) to i32) 147] }, !type !10 148 149; CHECK-IR-LABEL: define {{(noundef )?}}i32 @test 150define i32 @test(ptr %obj, ptr %obj2, i32 %a) { 151entry: 152 %vtable = load ptr, ptr %obj 153 %p = call i1 @llvm.type.test(ptr %vtable, metadata !"_ZTS1A") 154 call void @llvm.assume(i1 %p) 155 %fptrptr = getelementptr ptr, ptr %vtable, i32 1 156 %fptr1 = load ptr, ptr %fptrptr, align 8 157 158 ; Check that the call was devirtualized. 159 ; CHECK-IR: %call = tail call i32 @_ZN1A1nEi 160 ; Ensure !prof and !callees metadata for indirect call promotion removed. 161 ; CHECK-IR-NOT: prof 162 ; CHECK-IR-NOT: callees 163 %call = tail call i32 %fptr1(ptr nonnull %obj, i32 %a), !prof !5, !callees !6 164 165 %fptr22 = load ptr, ptr %vtable, align 8 166 167 ; We still have to call it as virtual. 168 ; CHECK-IR: %call3 = tail call i32 %fptr22 169 %call3 = tail call i32 %fptr22(ptr nonnull %obj, i32 %call) 170 171 %vtable2 = load ptr, ptr %obj2 172 %p2 = call i1 @llvm.type.test(ptr %vtable2, metadata !4) 173 call void @llvm.assume(i1 %p2) 174 175 %fptr33 = load ptr, ptr %vtable2, align 8 176 177 ; Check that the call was devirtualized. 178 ; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi 179 %call4 = tail call i32 %fptr33(ptr nonnull %obj2, i32 %call3) 180 ret i32 %call4 181} 182; CHECK-IR-LABEL: ret i32 183; CHECK-IR-LABEL: } 184 185declare ptr @llvm.load.relative.i32(ptr, i32) 186 187; CHECK-IR-LABEL: define {{.*}}i32 @test_rv 188define i32 @test_rv(ptr %obj, ptr %obj2, i32 %a) { 189entry: 190 %vtable = load ptr, ptr %obj 191 %p = call i1 @llvm.type.test(ptr %vtable, metadata !"_ZTS1A_RV") 192 call void @llvm.assume(i1 %p) 193 %fptr1_rv = call ptr @llvm.load.relative.i32(ptr %vtable, i32 4) 194 195 ; Check that the call was devirtualized. 196 ; CHECK-IR: %call = tail call i32 @_ZN1A1nEi 197 ; Ensure !prof and !callees metadata for indirect call promotion removed. 198 ; CHECK-IR-NOT: prof 199 ; CHECK-IR-NOT: callees 200 %call = tail call i32 %fptr1_rv(ptr nonnull %obj, i32 %a), !prof !5, !callees !6 201 202 %fptr22_rv = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0) 203 204 ; We still have to call it as virtual. 205 ; CHECK-IR: %call3 = tail call i32 %fptr22 206 %call3 = tail call i32 %fptr22_rv(ptr nonnull %obj, i32 %call) 207 208 %vtable2 = load ptr, ptr %obj2 209 %p2 = call i1 @llvm.type.test(ptr %vtable2, metadata !11) 210 call void @llvm.assume(i1 %p2) 211 212 %fptr33_rv = call ptr @llvm.load.relative.i32(ptr %vtable2, i32 0) 213 214 ; Check that the call was devirtualized. 215 ; CHECK-IR: %call4 = tail call i32 @_ZN1D1mEi 216 %call4 = tail call i32 %fptr33_rv(ptr nonnull %obj2, i32 %call3) 217 ret i32 %call4 218} 219; CHECK-IR-LABEL: ret i32 220; CHECK-IR-LABEL: } 221 222declare i1 @llvm.type.test(ptr, metadata) 223declare void @llvm.assume(i1) 224 225define i32 @_ZN1B1fEi(ptr %this, i32 %a) #0 { 226 ret i32 0; 227} 228 229define i32 @_ZN1A1nEi(ptr %this, i32 %a) #0 { 230 ret i32 0; 231} 232 233define i32 @_ZN1C1fEi(ptr %this, i32 %a) #0 { 234 ret i32 0; 235} 236 237define i32 @_ZN1D1mEi(ptr %this, i32 %a) #0 { 238 ret i32 0; 239} 240 241; Make sure we don't inline or otherwise optimize out the direct calls. 242attributes #0 = { noinline optnone } 243 244!0 = !{i64 16, !"_ZTS1A"} 245!1 = !{i64 16, !"_ZTS1B"} 246!2 = !{i64 16, !"_ZTS1C"} 247!3 = !{i64 16, !4} 248!4 = distinct !{} 249!5 = !{!"VP", i32 0, i64 1, i64 1621563287929432257, i64 1} 250!6 = !{ptr @_ZN1A1nEi} 251 252!7 = !{i64 8, !"_ZTS1A_RV"} 253!8 = !{i64 8, !"_ZTS1B_RV"} 254!9 = !{i64 8, !"_ZTS1C_RV"} 255!10 = !{i64 8, !11} 256!11 = distinct !{} 257