1; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility %s | FileCheck --check-prefixes=CHECK,RETP %s 2; RUN: sed -e 's,+retpoline,-retpoline,g' %s | opt -S -passes=wholeprogramdevirt -whole-program-visibility | FileCheck --check-prefixes=CHECK,NORETP %s 3 4; RUN: opt -passes=wholeprogramdevirt -whole-program-visibility -wholeprogramdevirt-summary-action=export -wholeprogramdevirt-read-summary=%S/Inputs/export.yaml -wholeprogramdevirt-write-summary=%t -S -o - %s | FileCheck --check-prefixes=CHECK,RETP %s 5 6; RUN: opt -passes='wholeprogramdevirt,default<O3>' -whole-program-visibility -wholeprogramdevirt-summary-action=export -wholeprogramdevirt-read-summary=%S/Inputs/export.yaml -wholeprogramdevirt-write-summary=%t -S -o - %s | FileCheck --check-prefixes=CHECK %s 7 8; RUN: FileCheck --check-prefix=SUMMARY %s < %t 9 10; SUMMARY: TypeIdMap: 11; SUMMARY-NEXT: typeid1_rv: 12; SUMMARY-NEXT: TTRes: 13; SUMMARY-NEXT: Kind: Unknown 14; SUMMARY-NEXT: SizeM1BitWidth: 0 15; SUMMARY-NEXT: AlignLog2: 0 16; SUMMARY-NEXT: SizeM1: 0 17; SUMMARY-NEXT: BitMask: 0 18; SUMMARY-NEXT: InlineBits: 0 19; SUMMARY-NEXT: WPDRes: 20; SUMMARY-NEXT: 0: 21; SUMMARY-NEXT: Kind: BranchFunnel 22; SUMMARY-NEXT: SingleImplName: '' 23; SUMMARY-NEXT: ResByArg: 24; SUMMARY-NEXT: typeid2_rv: 25; SUMMARY-NEXT: TTRes: 26; SUMMARY-NEXT: Kind: Unknown 27; SUMMARY-NEXT: SizeM1BitWidth: 0 28; SUMMARY-NEXT: AlignLog2: 0 29; SUMMARY-NEXT: SizeM1: 0 30; SUMMARY-NEXT: BitMask: 0 31; SUMMARY-NEXT: InlineBits: 0 32; SUMMARY-NEXT: WPDRes: 33; SUMMARY-NEXT: 0: 34; SUMMARY-NEXT: Kind: Indir 35; SUMMARY-NEXT: SingleImplName: '' 36; SUMMARY-NEXT: ResByArg: 37; SUMMARY-NEXT: typeid3_rv: 38; SUMMARY-NEXT: TTRes: 39; SUMMARY-NEXT: Kind: Unknown 40; SUMMARY-NEXT: SizeM1BitWidth: 0 41; SUMMARY-NEXT: AlignLog2: 0 42; SUMMARY-NEXT: SizeM1: 0 43; SUMMARY-NEXT: BitMask: 0 44; SUMMARY-NEXT: InlineBits: 0 45; SUMMARY-NEXT: WPDRes: 46; SUMMARY-NEXT: 0: 47; SUMMARY-NEXT: Kind: BranchFunnel 48; SUMMARY-NEXT: SingleImplName: '' 49; SUMMARY-NEXT: ResByArg: 50; SUMMARY-NEXT: typeid3: 51; SUMMARY-NEXT: TTRes: 52; SUMMARY-NEXT: Kind: Unknown 53; SUMMARY-NEXT: SizeM1BitWidth: 0 54; SUMMARY-NEXT: AlignLog2: 0 55; SUMMARY-NEXT: SizeM1: 0 56; SUMMARY-NEXT: BitMask: 0 57; SUMMARY-NEXT: InlineBits: 0 58; SUMMARY-NEXT: WPDRes: 59; SUMMARY-NEXT: 0: 60; SUMMARY-NEXT: Kind: BranchFunnel 61; SUMMARY-NEXT: SingleImplName: '' 62; SUMMARY-NEXT: ResByArg: 63; SUMMARY-NEXT: typeid1: 64; SUMMARY-NEXT: TTRes: 65; SUMMARY-NEXT: Kind: Unknown 66; SUMMARY-NEXT: SizeM1BitWidth: 0 67; SUMMARY-NEXT: AlignLog2: 0 68; SUMMARY-NEXT: SizeM1: 0 69; SUMMARY-NEXT: BitMask: 0 70; SUMMARY-NEXT: InlineBits: 0 71; SUMMARY-NEXT: WPDRes: 72; SUMMARY-NEXT: 0: 73; SUMMARY-NEXT: Kind: BranchFunnel 74; SUMMARY-NEXT: SingleImplName: '' 75; SUMMARY-NEXT: ResByArg: 76; SUMMARY-NEXT: typeid2: 77; SUMMARY-NEXT: TTRes: 78; SUMMARY-NEXT: Kind: Unknown 79; SUMMARY-NEXT: SizeM1BitWidth: 0 80; SUMMARY-NEXT: AlignLog2: 0 81; SUMMARY-NEXT: SizeM1: 0 82; SUMMARY-NEXT: BitMask: 0 83; SUMMARY-NEXT: InlineBits: 0 84; SUMMARY-NEXT: WPDRes: 85; SUMMARY-NEXT: 0: 86; SUMMARY-NEXT: Kind: Indir 87; SUMMARY-NEXT: SingleImplName: '' 88; SUMMARY-NEXT: ResByArg: 89 90target datalayout = "e-p:64:64" 91target triple = "x86_64-unknown-linux-gnu" 92 93@vt1_1 = constant [1 x ptr] [ptr @vf1_1], !type !0 94@vt1_2 = constant [1 x ptr] [ptr @vf1_2], !type !0 95 96declare i32 @vf1_1(ptr %this, i32 %arg) 97declare i32 @vf1_2(ptr %this, i32 %arg) 98 99@vt2_1 = constant [1 x ptr] [ptr @vf2_1], !type !1 100@vt2_2 = constant [1 x ptr] [ptr @vf2_2], !type !1 101@vt2_3 = constant [1 x ptr] [ptr @vf2_3], !type !1 102@vt2_4 = constant [1 x ptr] [ptr @vf2_4], !type !1 103@vt2_5 = constant [1 x ptr] [ptr @vf2_5], !type !1 104@vt2_6 = constant [1 x ptr] [ptr @vf2_6], !type !1 105@vt2_7 = constant [1 x ptr] [ptr @vf2_7], !type !1 106@vt2_8 = constant [1 x ptr] [ptr @vf2_8], !type !1 107@vt2_9 = constant [1 x ptr] [ptr @vf2_9], !type !1 108@vt2_10 = constant [1 x ptr] [ptr @vf2_10], !type !1 109@vt2_11 = constant [1 x ptr] [ptr @vf2_11], !type !1 110 111declare i32 @vf2_1(ptr %this, i32 %arg) 112declare i32 @vf2_2(ptr %this, i32 %arg) 113declare i32 @vf2_3(ptr %this, i32 %arg) 114declare i32 @vf2_4(ptr %this, i32 %arg) 115declare i32 @vf2_5(ptr %this, i32 %arg) 116declare i32 @vf2_6(ptr %this, i32 %arg) 117declare i32 @vf2_7(ptr %this, i32 %arg) 118declare i32 @vf2_8(ptr %this, i32 %arg) 119declare i32 @vf2_9(ptr %this, i32 %arg) 120declare i32 @vf2_10(ptr %this, i32 %arg) 121declare i32 @vf2_11(ptr %this, i32 %arg) 122 123@vt3_1 = constant [1 x ptr] [ptr @vf3_1], !type !2 124@vt3_2 = constant [1 x ptr] [ptr @vf3_2], !type !2 125 126declare i32 @vf3_1(ptr %this, i32 %arg) 127declare i32 @vf3_2(ptr %this, i32 %arg) 128 129@vt4_1 = constant [1 x ptr] [ptr @vf4_1], !type !3 130@vt4_2 = constant [1 x ptr] [ptr @vf4_2], !type !3 131 132declare i32 @vf4_1(ptr %this, i32 %arg) 133declare i32 @vf4_2(ptr %this, i32 %arg) 134 135declare ptr @llvm.load.relative.i32(ptr, i32) 136 137;; These are relative vtables equivalent to the ones above. 138@vt1_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1_1 to i64), i64 ptrtoint (ptr @vt1_1_rv to i64)) to i32)], !type !5 139@vt1_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1_2 to i64), i64 ptrtoint (ptr @vt1_2_rv to i64)) to i32)], !type !5 140 141@vt2_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_1 to i64), i64 ptrtoint (ptr @vt2_1_rv to i64)) to i32)], !type !6 142@vt2_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_2 to i64), i64 ptrtoint (ptr @vt2_2_rv to i64)) to i32)], !type !6 143@vt2_3_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_3 to i64), i64 ptrtoint (ptr @vt2_3_rv to i64)) to i32)], !type !6 144@vt2_4_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_4 to i64), i64 ptrtoint (ptr @vt2_4_rv to i64)) to i32)], !type !6 145@vt2_5_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_5 to i64), i64 ptrtoint (ptr @vt2_5_rv to i64)) to i32)], !type !6 146@vt2_6_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_6 to i64), i64 ptrtoint (ptr @vt2_6_rv to i64)) to i32)], !type !6 147@vt2_7_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_7 to i64), i64 ptrtoint (ptr @vt2_7_rv to i64)) to i32)], !type !6 148@vt2_8_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_8 to i64), i64 ptrtoint (ptr @vt2_8_rv to i64)) to i32)], !type !6 149@vt2_9_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_9 to i64), i64 ptrtoint (ptr @vt2_9_rv to i64)) to i32)], !type !6 150@vt2_10_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_10 to i64), i64 ptrtoint (ptr @vt2_10_rv to i64)) to i32)], !type !6 151@vt2_11_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2_11 to i64), i64 ptrtoint (ptr @vt2_11_rv to i64)) to i32)], !type !6 152 153@vt3_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf3_1 to i64), i64 ptrtoint (ptr @vt3_1_rv to i64)) to i32)], !type !7 154@vt3_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf3_2 to i64), i64 ptrtoint (ptr @vt3_2_rv to i64)) to i32)], !type !7 155 156@vt4_1_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4_1 to i64), i64 ptrtoint (ptr @vt4_1_rv to i64)) to i32)], !type !8 157@vt4_2_rv = constant [1 x i32] [i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4_2 to i64), i64 ptrtoint (ptr @vt4_2_rv to i64)) to i32)], !type !8 158 159 160; CHECK-LABEL: define i32 @fn1 161; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 162define i32 @fn1(ptr %obj) #0 { 163 %vtable = load ptr, ptr %obj 164 %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid1") 165 call void @llvm.assume(i1 %p) 166 %fptr = load ptr, ptr %vtable 167 ; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest %vtable, ptr %obj, i32 1) 168 %result = call i32 %fptr(ptr %obj, i32 1) 169 ; NORETP: call i32 % 170 ret i32 %result 171} 172 173; CHECK-LABEL: define i32 @fn1_rv 174; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 175define i32 @fn1_rv(ptr %obj) #0 { 176 %vtable = load ptr, ptr %obj 177 %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid1_rv") 178 call void @llvm.assume(i1 %p) 179 %fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0) 180 ; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest %vtable, ptr %obj, i32 1) 181 %result = call i32 %fptr(ptr %obj, i32 1) 182 ; NORETP: call i32 % 183 ret i32 %result 184} 185 186; CHECK-LABEL: define i32 @fn2 187; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 188define i32 @fn2(ptr %obj) #0 { 189 %vtable = load ptr, ptr %obj 190 %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2") 191 call void @llvm.assume(i1 %p) 192 %fptr = load ptr, ptr %vtable 193 ; CHECK: call i32 % 194 %result = call i32 %fptr(ptr %obj, i32 1) 195 ret i32 %result 196} 197 198; CHECK-LABEL: define i32 @fn2_rv 199; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 200define i32 @fn2_rv(ptr %obj) #0 { 201 %vtable = load ptr, ptr %obj 202 %p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2_rv") 203 call void @llvm.assume(i1 %p) 204 %fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0) 205 ; CHECK: call i32 % 206 %result = call i32 %fptr(ptr %obj, i32 1) 207 ret i32 %result 208} 209 210; CHECK-LABEL: define i32 @fn3 211; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 212define i32 @fn3(ptr %obj) #0 { 213 %vtable = load ptr, ptr %obj 214 %p = call i1 @llvm.type.test(ptr %vtable, metadata !4) 215 call void @llvm.assume(i1 %p) 216 %fptr = load ptr, ptr %vtable 217 ; RETP: call i32 @branch_funnel(ptr 218 ; NORETP: call i32 % 219 %result = call i32 %fptr(ptr %obj, i32 1) 220 ret i32 %result 221} 222 223; CHECK-LABEL: define i32 @fn3_rv 224; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 225define i32 @fn3_rv(ptr %obj) #0 { 226 %vtable = load ptr, ptr %obj 227 %p = call i1 @llvm.type.test(ptr %vtable, metadata !9) 228 call void @llvm.assume(i1 %p) 229 %fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0) 230 ; RETP: call i32 @branch_funnel.1(ptr 231 ; NORETP: call i32 % 232 %result = call i32 %fptr(ptr %obj, i32 1) 233 ret i32 %result 234} 235 236; CHECK-LABEL: define i32 @fn4 237; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 238define i32 @fn4(ptr %obj) #0 { 239 %p = call i1 @llvm.type.test(ptr @vt1_1, metadata !"typeid1") 240 call void @llvm.assume(i1 %p) 241 %fptr = load ptr, ptr @vt1_1 242 ; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest @vt1_1, ptr %obj, i32 1) 243 %result = call i32 %fptr(ptr %obj, i32 1) 244 ; NORETP: call i32 % 245 ret i32 %result 246} 247 248; CHECK-LABEL: define i32 @fn4_cpy 249; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 250define i32 @fn4_cpy(ptr %obj) #0 { 251 %p = call i1 @llvm.type.test(ptr @vt1_1, metadata !"typeid1") 252 call void @llvm.assume(i1 %p) 253 %fptr = load ptr, ptr @vt1_1 254 ; RETP: call i32 @__typeid_typeid1_0_branch_funnel(ptr nest @vt1_1, ptr %obj, i32 1) 255 %result = call i32 %fptr(ptr %obj, i32 1) 256 ; NORETP: call i32 % 257 ret i32 %result 258} 259 260; CHECK-LABEL: define i32 @fn4_rv 261; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 262define i32 @fn4_rv(ptr %obj) #0 { 263 %p = call i1 @llvm.type.test(ptr @vt1_1_rv, metadata !"typeid1_rv") 264 call void @llvm.assume(i1 %p) 265 %fptr = call ptr @llvm.load.relative.i32(ptr @vt1_1_rv, i32 0) 266 ; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest @vt1_1_rv, ptr %obj, i32 1) 267 %result = call i32 %fptr(ptr %obj, i32 1) 268 ; NORETP: call i32 % 269 ret i32 %result 270} 271 272; CHECK-LABEL: define i32 @fn4_rv_cpy 273; CHECK-NOT: call void (...) @llvm.icall.branch.funnel 274define i32 @fn4_rv_cpy(ptr %obj) #0 { 275 %p = call i1 @llvm.type.test(ptr @vt1_1_rv, metadata !"typeid1_rv") 276 call void @llvm.assume(i1 %p) 277 %fptr = call ptr @llvm.load.relative.i32(ptr @vt1_1_rv, i32 0) 278 ; RETP: call i32 @__typeid_typeid1_rv_0_branch_funnel(ptr nest @vt1_1_rv, ptr %obj, i32 1) 279 %result = call i32 %fptr(ptr %obj, i32 1) 280 ; NORETP: call i32 % 281 ret i32 %result 282} 283 284; CHECK-LABEL: define hidden void @__typeid_typeid1_0_branch_funnel(ptr nest %0, ...) 285; CHECK-NEXT: musttail call void (...) @llvm.icall.branch.funnel(ptr %0, ptr {{(nonnull )?}}@vt1_1, ptr {{(nonnull )?}}@vf1_1, ptr {{(nonnull )?}}@vt1_2, ptr {{(nonnull )?}}@vf1_2, ...) 286 287; CHECK-LABEL: define hidden void @__typeid_typeid1_rv_0_branch_funnel(ptr nest %0, ...) 288; CHECK-NEXT: musttail call void (...) @llvm.icall.branch.funnel(ptr %0, ptr {{(nonnull )?}}@vt1_1_rv, ptr {{(nonnull )?}}@vf1_1, ptr {{(nonnull )?}}@vt1_2_rv, ptr {{(nonnull )?}}@vf1_2, ...) 289 290; CHECK: define internal void @branch_funnel(ptr 291; CHECK: define internal void @branch_funnel.1(ptr 292 293declare i1 @llvm.type.test(ptr, metadata) 294declare void @llvm.assume(i1) 295 296!0 = !{i32 0, !"typeid1"} 297!1 = !{i32 0, !"typeid2"} 298!2 = !{i32 0, !"typeid3"} 299!3 = !{i32 0, !4} 300!4 = distinct !{} 301!5 = !{i32 0, !"typeid1_rv"} 302!6 = !{i32 0, !"typeid2_rv"} 303!7 = !{i32 0, !"typeid3_rv"} 304!8 = !{i32 0, !9} 305!9 = distinct !{} 306 307attributes #0 = { "target-features"="+retpoline" } 308