Skip to content

Commit 0a8b2cf

Browse files
committed
[NFC][WPD] Add constant propagation tests to account for relative vtables
This is a patch with precommitted tests to make llvm#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 3212555 commit 0a8b2cf

File tree

5 files changed

+810
-40
lines changed

5 files changed

+810
-40
lines changed
Lines changed: 96 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,35 @@
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.
7+
; 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]+]]
78
@vt1 = constant [3 x ptr] [
89
ptr @vf0i1,
910
ptr @vf1i1,
10-
ptr @vf1i32
11+
ptr @vf1i16
1112
], section "vt1sec", !type !0
1213

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]]
14+
; 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]]
1415
@vt2 = constant [3 x ptr] [
1516
ptr @vf1i1,
1617
ptr @vf0i1,
17-
ptr @vf2i32
18+
ptr @vf2i16
1819
], !type !0
1920

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]+]]
21+
; 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]+]]
2122
@vt3 = constant [3 x ptr] [
2223
ptr @vf0i1,
2324
ptr @vf1i1,
24-
ptr @vf3i32
25-
], align 1, !type !0
25+
ptr @vf3i16
26+
], align 2, !type !0
2627

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]+]]
28+
; 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]+]]
2829
@vt4 = constant [3 x ptr] [
2930
ptr @vf1i1,
3031
ptr @vf0i1,
31-
ptr @vf4i32
32+
ptr @vf4i16
3233
], align 16, !type !0
3334

3435
; CHECK: @vt5 = {{.*}}, !type [[T0:![0-9]+]]
@@ -38,10 +39,35 @@ ptr @__cxa_pure_virtual,
3839
ptr @__cxa_pure_virtual
3940
], !type !0
4041

42+
;; Test relative vtables
43+
; CHECK: [[VT6RELDATA:@[^ ]*]] = private constant { [4 x i8], [3 x i32], [0 x i8] } { [4 x i8] c"\00\00\03\00", [3 x i32] [
44+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
45+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
46+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i16 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32)
47+
; CHECK-SAME: ], [0 x i8] zeroinitializer }, !type [[TREL:![0-9]+]]
48+
@vt6_rel = constant [3 x i32] [
49+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
50+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32),
51+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i16 to i64), i64 ptrtoint (ptr @vt6_rel to i64)) to i32)
52+
], !type !2
53+
54+
; CHECK: [[VT7RELDATA:@[^ ]*]] = private constant { [4 x i8], [3 x i32], [0 x i8] } { [4 x i8] c"\00\00\04\00", [3 x i32] [
55+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
56+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
57+
; CHECK-SAME: i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2i16 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32)
58+
; CHECK-SAME: ], [0 x i8] zeroinitializer }, !type [[TREL]]
59+
@vt7_rel = constant [3 x i32] [
60+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf1i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
61+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf0i1 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32),
62+
i32 trunc (i64 sub (i64 ptrtoint (ptr dso_local_equivalent @vf2i16 to i64), i64 ptrtoint (ptr @vt7_rel to i64)) to i32)
63+
], !type !2
64+
4165
; CHECK: @vt1 = alias [3 x ptr], getelementptr inbounds ({ [8 x i8], [3 x ptr], [0 x i8] }, ptr [[VT1DATA]], i32 0, i32 1)
4266
; 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)
67+
; CHECK: @vt3 = alias [3 x ptr], getelementptr inbounds ({ [4 x i8], [3 x ptr], [0 x i8] }, ptr [[VT3DATA]], i32 0, i32 1)
4468
; CHECK: @vt4 = alias [3 x ptr], getelementptr inbounds ({ [16 x i8], [3 x ptr], [0 x i8] }, ptr [[VT4DATA]], i32 0, i32 1)
69+
; CHECK: @vt6_rel = alias [3 x i32], getelementptr inbounds ({ [4 x i8], [3 x i32], [0 x i8] }, ptr [[VT6RELDATA]], i32 0, i32 1)
70+
; CHECK: @vt7_rel = alias [3 x i32], getelementptr inbounds ({ [4 x i8], [3 x i32], [0 x i8] }, ptr [[VT7RELDATA]], i32 0, i32 1)
4571

4672
define i1 @vf0i1(ptr %this) readnone {
4773
ret i1 0
@@ -51,20 +77,20 @@ define i1 @vf1i1(ptr %this) readnone {
5177
ret i1 1
5278
}
5379

54-
define i32 @vf1i32(ptr %this) readnone {
55-
ret i32 1
80+
define i16 @vf1i16(ptr %this) readnone {
81+
ret i16 3
5682
}
5783

58-
define i32 @vf2i32(ptr %this) readnone {
59-
ret i32 2
84+
define i16 @vf2i16(ptr %this) readnone {
85+
ret i16 4
6086
}
6187

62-
define i32 @vf3i32(ptr %this) readnone {
63-
ret i32 3
88+
define i16 @vf3i16(ptr %this) readnone {
89+
ret i16 5
6490
}
6591

66-
define i32 @vf4i32(ptr %this) readnone {
67-
ret i32 4
92+
define i16 @vf4i16(ptr %this) readnone {
93+
ret i16 6
6894
}
6995

7096
; CHECK: define i1 @call1(
@@ -87,7 +113,7 @@ define i1 @call2(ptr %obj) {
87113
%vtable = load ptr, ptr %obj
88114
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid")
89115
call void @llvm.assume(i1 %p)
90-
%fptrptr = getelementptr [3 x ptr], ptr %vtable, i32 0, i32 1
116+
%fptrptr = getelementptr [3 x ptr], ptr %vtable, i16 0, i16 1
91117
%fptr = load ptr, ptr %fptrptr
92118
; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -1
93119
; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, ptr [[VTGEP2]]
@@ -98,27 +124,68 @@ define i1 @call2(ptr %obj) {
98124
ret i1 %result
99125
}
100126

101-
; CHECK: define i32 @call3(
102-
define i32 @call3(ptr %obj) {
127+
; CHECK: define i16 @call3(
128+
define i16 @call3(ptr %obj) {
103129
%vtable = load ptr, ptr %obj
104130
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid")
105131
call void @llvm.assume(i1 %p)
106-
%fptrptr = getelementptr [3 x ptr], ptr %vtable, i32 0, i32 2
132+
%fptrptr = getelementptr [3 x ptr], ptr %vtable, i16 0, i16 2
107133
%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
134+
; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -3
135+
; CHECK: [[VTLOAD3:%[^ ]*]] = load i16, ptr [[VTGEP3]]
136+
%result = call i16 %fptr(ptr %obj)
137+
; CHECK: ret i16 [[VTLOAD3]]
138+
ret i16 %result
139+
}
140+
141+
; CHECK: define i1 @call1_rel(
142+
define i1 @call1_rel(ptr %obj) {
143+
%vtable = load ptr, ptr %obj
144+
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid3")
145+
call void @llvm.assume(i1 %p)
146+
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 0)
147+
%result = call i1 %fptr(ptr %obj)
148+
ret i1 %result
149+
; CHECK: [[RES:%[^ ]*]] = icmp eq ptr %vtable, @vt7_rel
150+
; CHECK: ret i1 [[RES]]
151+
}
152+
153+
; CHECK: define i1 @call2_rel(
154+
define i1 @call2_rel(ptr %obj) {
155+
%vtable = load ptr, ptr %obj
156+
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid3")
157+
call void @llvm.assume(i1 %p)
158+
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 4)
159+
%result = call i1 %fptr(ptr %obj)
160+
ret i1 %result
161+
; CHECK: [[RES:%[^ ]*]] = icmp eq ptr %vtable, @vt6_rel
162+
; CHECK: ret i1 [[RES]]
163+
}
164+
165+
; CHECK: define i16 @call3_rel(
166+
define i16 @call3_rel(ptr %obj) {
167+
%vtable = load ptr, ptr %obj
168+
%p = call i1 @llvm.type.test(ptr %vtable, metadata !"typeid3")
169+
call void @llvm.assume(i1 %p)
170+
%fptr = call ptr @llvm.load.relative.i32(ptr %vtable, i32 8)
171+
; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, ptr %vtable, i32 -2
172+
; CHECK: [[VTLOAD3:%[^ ]*]] = load i16, ptr [[VTGEP3]]
173+
%result = call i16 %fptr(ptr %obj)
174+
; CHECK: ret i16 [[VTLOAD3]]
175+
ret i16 %result
113176
}
114177

115178
declare i1 @llvm.type.test(ptr, metadata)
116179
declare void @llvm.assume(i1)
117180
declare void @__cxa_pure_virtual()
181+
declare ptr @llvm.load.relative.i32(ptr, i32)
118182

119183
; CHECK: [[T8]] = !{i32 8, !"typeid"}
120-
; CHECK: [[T5]] = !{i32 5, !"typeid"}
184+
; CHECK: [[T5]] = !{i32 4, !"typeid"}
121185
; CHECK: [[T16]] = !{i32 16, !"typeid"}
122186
; CHECK: [[T0]] = !{i32 0, !"typeid"}
187+
; CHECK: [[TREL]] = !{i32 4, !"typeid3"}
123188

124189
!0 = !{i32 0, !"typeid"}
190+
!1 = !{i32 0, !"typeid2"}
191+
!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)