Skip to content

Commit 649b799

Browse files
authored
[NFC][WPD] Add constant propagation tests checking relative vtables (#138989)
This is a patch with precommitted tests to make #136630 easier to review. The `virtual-const-prop-small-alignment-*` tests check the output when the loaded int alignment is less than the vtable alignment. This also changes some constants to make it easier to differentiate between propagated values in vtables.
1 parent 8af397a commit 649b799

File tree

5 files changed

+845
-40
lines changed

5 files changed

+845
-40
lines changed
Lines changed: 101 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,40 @@
11
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility %s | FileCheck %s
22

33
target datalayout = "e-p:64:64"
4-
target triple = "x86_64-unknown-linux-gnu"
54

6-
; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x ptr], [0 x i8] } { [8 x i8] c"\00\00\00\01\00\00\00\02", [3 x ptr] [ptr @vf0i1, ptr @vf1i1, ptr @vf1i32], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]]
5+
;; Note that i16 is used here such that we can ensure all constants for "typeid"
6+
;; can come before the vtable. For this particular file, the intention is to only
7+
;; look at constants placed before the vtable, but with the next change, this
8+
;; would place the original i32s after the vtable due to extra padding needed to
9+
;; preserve alignment. Making them i16s allows them to stay at the beginning of
10+
;; the vtable. There are other tests where there's a mix of constants before and
11+
;; after the vtable but for this file we just want everything before the vtable.
12+
; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x ptr], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\03\00\02", [3 x ptr] [ptr @vf0i1, ptr @vf1i1, ptr @vf1i16], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]]
713
@vt1 = constant [3 x ptr] [
814
ptr @vf0i1,
915
ptr @vf1i1,
10-
ptr @vf1i32
16+
ptr @vf1i16
1117
], section "vt1sec", !type !0
1218

13-
; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x ptr], [0 x i8] } { [8 x i8] c"\00\00\00\02\00\00\00\01", [3 x ptr] [ptr @vf1i1, ptr @vf0i1, ptr @vf2i32], [0 x i8] zeroinitializer }, !type [[T8]]
19+
; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x ptr], [0 x i8] } { [8 x i8] c"\00\00\00\00\00\04\00\01", [3 x ptr] [ptr @vf1i1, ptr @vf0i1, ptr @vf2i16], [0 x i8] zeroinitializer }, !type [[T8]]
1420
@vt2 = constant [3 x ptr] [
1521
ptr @vf1i1,
1622
ptr @vf0i1,
17-
ptr @vf2i32
23+
ptr @vf2i16
1824
], !type !0
1925

20-
; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [5 x i8], [3 x ptr], [0 x i8] } { [5 x i8] c"\03\00\00\00\02", [3 x ptr] [ptr @vf0i1, ptr @vf1i1, ptr @vf3i32], [0 x i8] zeroinitializer }, align 1, !type [[T5:![0-9]+]]
26+
; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [4 x i8], [3 x ptr], [0 x i8] } { [4 x i8] c"\00\05\00\02", [3 x ptr] [ptr @vf0i1, ptr @vf1i1, ptr @vf3i16], [0 x i8] zeroinitializer }, align 2, !type [[T5:![0-9]+]]
2127
@vt3 = constant [3 x ptr] [
2228
ptr @vf0i1,
2329
ptr @vf1i1,
24-
ptr @vf3i32
25-
], align 1, !type !0
30+
ptr @vf3i16
31+
], align 2, !type !0
2632

27-
; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [16 x i8], [3 x ptr], [0 x i8] } { [16 x i8] c"\00\00\00\00\00\00\00\00\00\00\00\04\00\00\00\01", [3 x ptr] [ptr @vf1i1, ptr @vf0i1, ptr @vf4i32], [0 x i8] zeroinitializer }, align 16, !type [[T16:![0-9]+]]
33+
; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [16 x i8], [3 x ptr], [0 x i8] } { [16 x i8] c"\00\00\00\00\00\00\00\00\00\00\00\00\00\06\00\01", [3 x ptr] [ptr @vf1i1, ptr @vf0i1, ptr @vf4i16], [0 x i8] zeroinitializer }, align 16, !type [[T16:![0-9]+]]
2834
@vt4 = constant [3 x ptr] [
2935
ptr @vf1i1,
3036
ptr @vf0i1,
31-
ptr @vf4i32
37+
ptr @vf4i16
3238
], align 16, !type !0
3339

3440
; CHECK: @vt5 = {{.*}}, !type [[T0:![0-9]+]]
@@ -38,10 +44,35 @@ ptr @__cxa_pure_virtual,
3844
ptr @__cxa_pure_virtual
3945
], !type !0
4046

47+
;; Test relative vtables
48+
; CHECK: [[VT6RELDATA:@[^ ]*]] = private constant { [4 x i8], [3 x i32], [0 x i8] } { [4 x i8] c"\00\00\03\00", [3 x i32] [
49+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
50+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
51+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i16 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32)
52+
; CHECK-SAME: ], [0 x i8] zeroinitializer }, !type [[TREL:![0-9]+]]
53+
@vt6_rel = constant [3 x i32] [
54+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
55+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
56+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i16 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32)
57+
], !type !2
58+
59+
; CHECK: [[VT7RELDATA:@[^ ]*]] = private constant { [4 x i8], [3 x i32], [0 x i8] } { [4 x i8] c"\00\00\04\00", [3 x i32] [
60+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
61+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
62+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2i16 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32)
63+
; CHECK-SAME: ], [0 x i8] zeroinitializer }, !type [[TREL]]
64+
@vt7_rel = constant [3 x i32] [
65+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
66+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
67+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2i16 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32)
68+
], !type !2
69+
4170
; CHECK: @vt1 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT1DATA]], i32 0, i32 1)
4271
; CHECK: @vt2 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT2DATA]], i32 0, i32 1)
43-
; CHECK: @vt3 = alias [3 x ptr], getelementptr inbounds ({ [5 x i8], [3 x ptr], [0 x i8] }, ptr [[VT3DATA]], i32 0, i32 1)
72+
; CHECK: @vt3 = alias [3 x ptr], getelementptr inbounds ({ [4 x i8], [3 x ptr], [0 x i8] }, ptr [[VT3DATA]], i32 0, i32 1)
4473
; CHECK: @vt4 = alias [3 x ptr], getelementptr inbounds ({ [16 x i8], [3 x ptr], [0 x i8] }, ptr [[VT4DATA]], i32 0, i32 1)
74+
; CHECK: @vt6_rel = alias [3 x i32], getelementptr inbounds ({ [4 x i8], [3 x i32], [0 x i8] }, ptr [[VT6RELDATA]], i32 0, i32 1)
75+
; CHECK: @vt7_rel = alias [3 x i32], getelementptr inbounds ({ [4 x i8], [3 x i32], [0 x i8] }, ptr [[VT7RELDATA]], i32 0, i32 1)
4576

4677
define i1 @vf0i1(ptr %this) readnone {
4778
ret i1 0
@@ -51,20 +82,20 @@ define i1 @vf1i1(ptr %this) readnone {
5182
ret i1 1
5283
}
5384

54-
define i32 @vf1i32(ptr %this) readnone {
55-
ret i32 1
85+
define i16 @vf1i16(ptr %this) readnone {
86+
ret i16 3
5687
}
5788

58-
define i32 @vf2i32(ptr %this) readnone {
59-
ret i32 2
89+
define i16 @vf2i16(ptr %this) readnone {
90+
ret i16 4
6091
}
6192

62-
define i32 @vf3i32(ptr %this) readnone {
63-
ret i32 3
93+
define i16 @vf3i16(ptr %this) readnone {
94+
ret i16 5
6495
}
6596

66-
define i32 @vf4i32(ptr %this) readnone {
67-
ret i32 4
97+
define i16 @vf4i16(ptr %this) readnone {
98+
ret i16 6
6899
}
69100

70101
; CHECK: define i1 @call1(
@@ -87,7 +118,7 @@ define i1 @call2(ptr %obj) {
87118
%vtable = load ptr, ptr %obj
88119
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid")
89120
call void @llvm.assume(i1 %p)
90-
%fptrptr = getelementptr [3 x ptr], ptr %vtable, i32 0, i32 1
121+
%fptrptr = getelementptr [3 x ptr], ptr %vtable, i16 0, i16 1
91122
%fptr = load ptr, ptr %fptrptr
92123
; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -1
93124
; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, ptr [[VTGEP2]]
@@ -98,27 +129,68 @@ define i1 @call2(ptr %obj) {
98129
ret i1 %result
99130
}
100131

101-
; CHECK: define i32 @call3(
102-
define i32 @call3(ptr %obj) {
132+
; CHECK: define i16 @call3(
133+
define i16 @call3(ptr %obj) {
103134
%vtable = load ptr, ptr %obj
104135
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid")
105136
call void @llvm.assume(i1 %p)
106-
%fptrptr = getelementptr [3 x ptr], ptr %vtable, i32 0, i32 2
137+
%fptrptr = getelementptr [3 x ptr], ptr %vtable, i16 0, i16 2
107138
%fptr = load ptr, ptr %fptrptr
108-
; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -5
109-
; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, ptr [[VTGEP3]]
110-
%result = call i32 %fptr(ptr %obj)
111-
; CHECK: ret i32 [[VTLOAD3]]
112-
ret i32 %result
139+
; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -3
140+
; CHECK: [[VTLOAD3:%[^ ]*]] = load i16, ptr [[VTGEP3]]
141+
%result = call i16 %fptr(ptr %obj)
142+
; CHECK: ret i16 [[VTLOAD3]]
143+
ret i16 %result
144+
}
145+
146+
; CHECK: define i1 @call1_rel(
147+
define i1 @call1_rel(ptr %obj) {
148+
%vtable = load ptr, ptr %obj
149+
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid3")
150+
call void @llvm.assume(i1 %p)
151+
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
152+
%result = call i1 %fptr(ptr %obj)
153+
ret i1 %result
154+
; CHECK: [[RES:%[^ ]*]] = icmp eq ptr %vtable, @vt7_rel
155+
; CHECK: ret i1 [[RES]]
156+
}
157+
158+
; CHECK: define i1 @call2_rel(
159+
define i1 @call2_rel(ptr %obj) {
160+
%vtable = load ptr, ptr %obj
161+
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid3")
162+
call void @llvm.assume(i1 %p)
163+
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 4)
164+
%result = call i1 %fptr(ptr %obj)
165+
ret i1 %result
166+
; CHECK: [[RES:%[^ ]*]] = icmp eq ptr %vtable, @vt6_rel
167+
; CHECK: ret i1 [[RES]]
168+
}
169+
170+
; CHECK: define i16 @call3_rel(
171+
define i16 @call3_rel(ptr %obj) {
172+
%vtable = load ptr, ptr %obj
173+
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid3")
174+
call void @llvm.assume(i1 %p)
175+
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 8)
176+
; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -2
177+
; CHECK: [[VTLOAD3:%[^ ]*]] = load i16, ptr [[VTGEP3]]
178+
%result = call i16 %fptr(ptr %obj)
179+
; CHECK: ret i16 [[VTLOAD3]]
180+
ret i16 %result
113181
}
114182

115183
declare i1 @llvm.type.test(ptr, metadata)
116184
declare void @llvm.assume(i1)
117185
declare void @__cxa_pure_virtual()
186+
declare ptr @llvm.load.relative.i32(ptr, i32)
118187

119188
; CHECK: [[T8]] = !{i32 8, !"typeid"}
120-
; CHECK: [[T5]] = !{i32 5, !"typeid"}
189+
; CHECK: [[T5]] = !{i32 4, !"typeid"}
121190
; CHECK: [[T16]] = !{i32 16, !"typeid"}
122191
; CHECK: [[T0]] = !{i32 0, !"typeid"}
192+
; CHECK: [[TREL]] = !{i32 4, !"typeid3"}
123193

124194
!0 = !{i32 0, !"typeid"}
195+
!1 = !{i32 0, !"typeid2"}
196+
!2 = !{i32 0, !"typeid3"}

llvm/test/Transforms/WholeProgramDevirt/virtual-const-prop-check.ll

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@
77
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility -pass-remarks=wholeprogramdevirt -wholeprogramdevirt-skip=vf0i1 %s 2>&1 | FileCheck %s --check-prefix=SKIP
88
; We have two set of call targets {vf0i1, vf1i1} and {vf1i32, vf2i32, vf3i32, vf4i32}.
99
; The command below prevents both of them from devirtualization.
10-
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility -pass-remarks=wholeprogramdevirt -wholeprogramdevirt-skip=vf0i1,vf1i32 %s 2>&1 | FileCheck %s --check-prefix=SKIP-ALL
10+
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility -pass-remarks=wholeprogramdevirt -wholeprogramdevirt-skip=vf0i1,vf1i32,vf3i32 %s 2>&1 | FileCheck %s --check-prefix=SKIP-ALL
1111
; Check wildcard
1212
; RUN: opt -S -passes=wholeprogramdevirt -whole-program-visibility -pass-remarks=wholeprogramdevirt -wholeprogramdevirt-skip=vf?i1 %s 2>&1 | FileCheck %s --check-prefix=SKIP
1313

1414
target datalayout = "e-p:64:64"
1515
target triple = "x86_64-unknown-linux-gnu"
1616

17+
; CHECK: remark: <unknown>:0:0: unique-ret-val: devirtualized a call to vf0i1
18+
; CHECK: remark: <unknown>:0:0: unique-ret-val: devirtualized a call to vf1i1
19+
; CHECK: remark: <unknown>:0:0: virtual-const-prop: devirtualized a call to vf3i32
1720
; CHECK: remark: <unknown>:0:0: virtual-const-prop-1-bit: devirtualized a call to vf0i1
1821
; CHECK: remark: <unknown>:0:0: virtual-const-prop-1-bit: devirtualized a call to vf1i1
1922
; CHECK: remark: <unknown>:0:0: virtual-const-prop: devirtualized a call to vf1i32
@@ -69,10 +72,35 @@ ptr @__cxa_pure_virtual,
6972
ptr @__cxa_pure_virtual
7073
], !type !0
7174

75+
;; Test relative vtables
76+
; CHECK: [[VT6RELDATA:@[^ ]*]] = private constant { [4 x i8], [3 x i32], [0 x i8] } { [4 x i8] c"\03\00\00\00", [3 x i32] [
77+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
78+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
79+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf3i32 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32)
80+
; CHECK-SAME: ], [0 x i8] zeroinitializer }, !type [[TREL:![0-9]+]]
81+
@vt6_rel = constant [3 x i32] [
82+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
83+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
84+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf3i32 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32)
85+
], !type !1
86+
87+
; CHECK: [[VT7RELDATA:@[^ ]*]] = private constant { [4 x i8], [3 x i32], [0 x i8] } { [4 x i8] c"\04\00\00\00", [3 x i32] [
88+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
89+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
90+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4i32 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32)
91+
; CHECK-SAME: ], [0 x i8] zeroinitializer }, !type [[TREL]]
92+
@vt7_rel = constant [3 x i32] [
93+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
94+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
95+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf4i32 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32)
96+
], !type !1
97+
7298
; CHECK: @vt1 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT1DATA]], i32 0, i32 1)
7399
; CHECK: @vt2 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT2DATA]], i32 0, i32 1)
74100
; CHECK: @vt3 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT3DATA]], i32 0, i32 1)
75101
; CHECK: @vt4 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT4DATA]], i32 0, i32 1)
102+
; CHECK: @vt6_rel = alias [3 x i32], getelementptr inbounds ({ [4 x i8], [3 x i32], [0 x i8] }, ptr [[VT6RELDATA]], i32 0, i32 1)
103+
; CHECK: @vt7_rel = alias [3 x i32], getelementptr inbounds ({ [4 x i8], [3 x i32], [0 x i8] }, ptr [[VT7RELDATA]], i32 0, i32 1)
76104

77105
define i1 @vf0i1(ptr %this) readnone {
78106
ret i1 0
@@ -144,15 +172,56 @@ define i32 @call3(ptr %obj) {
144172
ret i32 %result
145173
}
146174

175+
; CHECK: define i1 @call1_rel(
176+
define i1 @call1_rel(ptr %obj) {
177+
%vtable = load ptr, ptr %obj
178+
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
179+
call void @llvm.assume(i1 %p)
180+
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
181+
%result = call i1 %fptr(ptr %obj)
182+
ret i1 %result
183+
; CHECK: [[RES:%[^ ]*]] = icmp eq ptr %vtable, @vt7_rel
184+
; CHECK: ret i1 [[RES]]
185+
}
186+
187+
; CHECK: define i1 @call2_rel(
188+
define i1 @call2_rel(ptr %obj) {
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 = call ptr @llvm.load.relative.i32(ptr %vtable, i32 4)
193+
%result = call i1 %fptr(ptr %obj)
194+
ret i1 %result
195+
; CHECK: [[RES:%[^ ]*]] = icmp eq ptr %vtable, @vt6_rel
196+
; CHECK: ret i1 [[RES]]
197+
}
198+
199+
; CHECK: define i32 @call3_rel(
200+
define i32 @call3_rel(ptr %obj) {
201+
%vtable = load ptr, ptr %obj
202+
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid2")
203+
call void @llvm.assume(i1 %p)
204+
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 8)
205+
; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -4
206+
; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, ptr [[VTGEP3]]
207+
%result = call i32 %fptr(ptr %obj)
208+
; CHECK: ret i32 [[VTLOAD3]]
209+
ret i32 %result
210+
}
211+
147212
declare {ptr, i1} @llvm.type.checked.load(ptr, i32, metadata)
148213
declare void @llvm.assume(i1)
149214
declare void @__cxa_pure_virtual()
215+
declare ptr @llvm.load.relative.i32(ptr, i32)
150216

151217
; CHECK: [[T8]] = !{i32 8, !"typeid"}
152218
; CHECK: [[T0]] = !{i32 0, !"typeid"}
219+
; CHECK: [[TREL]] = !{i32 4, !"typeid2"}
153220

154221
!0 = !{i32 0, !"typeid"}
222+
!1 = !{i32 0, !"typeid2"}
155223

156224
; CHECK: 6 wholeprogramdevirt - Number of whole program devirtualization targets
157-
; CHECK: 1 wholeprogramdevirt - Number of virtual constant propagations
225+
; CHECK: 2 wholeprogramdevirt - Number of unique return value optimizations
226+
; CHECK: 2 wholeprogramdevirt - Number of virtual constant propagations
158227
; CHECK: 2 wholeprogramdevirt - Number of 1 bit virtual constant propagations

0 commit comments

Comments
 (0)