Skip to content

Commit fc48e19

Browse files
author
git apple-llvm automerger
committed
Merge commit '649b7994fb27' from llvm.org/main into next
2 parents 49a6e65 + 649b799 commit fc48e19

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)