Skip to content

Commit fb76d24

Browse files
committed
[LowerConstantIntrinsics] Improve tests related to llvm.objectsize. NFC
Adding some new test cases (including FIXME:s) to highlight some bugs related to lowering of llvm.objectsize. One special case is when there are getelementptr instruction with index types that are larger than the index type size for the pointer being analysed. This will add a couple of tests to show what happens both when using a smaller and larger index type, and when having out-of-bounds indices (both too large and negative).
1 parent 2e3fa4b commit fb76d24

File tree

2 files changed

+309
-4
lines changed

2 files changed

+309
-4
lines changed
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -passes='sroa,instcombine,lower-constant-intrinsics,dce' -S < %s | FileCheck --check-prefixes CHECK,CHECK-REF %s
3+
; RUN: opt -passes=lower-constant-intrinsics,dce -S < %s | FileCheck --check-prefixes CHECK,CHECK-TST %s
4+
5+
; Some extra tests using 16-bit pointers and 16-bit index type size. This
6+
; allows us to for example test what happens when the index type used in a
7+
; getelementptr does not match with the index type size (e.g. when not running
8+
; full opt pipeline before the lower-constant-intrinsics pass).
9+
10+
target datalayout = "e-p:16:16:16"
11+
12+
13+
define i32 @possible_out_of_bounds_gep_i8(i1 %c0, i1 %c1) {
14+
; CHECK-LABEL: define i32 @possible_out_of_bounds_gep_i8(
15+
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
16+
; CHECK-NEXT: [[ENTRY:.*:]]
17+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 3, i32 0
18+
; CHECK-NEXT: ret i32 [[RES]]
19+
;
20+
entry:
21+
%obj = alloca [5 x i8]
22+
%offset = select i1 %c0, i8 2, i8 10
23+
%ptr.slide = getelementptr i8, ptr %obj, i8 %offset
24+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
25+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
26+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
27+
ret i32 %res
28+
}
29+
30+
define i32 @possible_out_of_bounds_gep_i16(i1 %c0, i1 %c1) {
31+
; CHECK-LABEL: define i32 @possible_out_of_bounds_gep_i16(
32+
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
33+
; CHECK-NEXT: [[ENTRY:.*:]]
34+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 3, i32 0
35+
; CHECK-NEXT: ret i32 [[RES]]
36+
;
37+
entry:
38+
%obj = alloca [5 x i8]
39+
%offset = select i1 %c0, i16 2, i16 10
40+
%ptr.slide = getelementptr i8, ptr %obj, i16 %offset
41+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
42+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
43+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
44+
ret i32 %res
45+
}
46+
47+
define i32 @possible_out_of_bounds_gep_i32(i1 %c0, i1 %c1) {
48+
; CHECK-LABEL: define i32 @possible_out_of_bounds_gep_i32(
49+
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
50+
; CHECK-NEXT: [[ENTRY:.*:]]
51+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 3, i32 0
52+
; CHECK-NEXT: ret i32 [[RES]]
53+
;
54+
entry:
55+
%obj = alloca [5 x i8]
56+
%offset = select i1 %c0, i32 2, i32 10
57+
%ptr.slide = getelementptr i8, ptr %obj, i32 %offset
58+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
59+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
60+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
61+
ret i32 %res
62+
}
63+
64+
; SROA would produce IR like this if applied to @possible_out_of_bounds_gep_i16.
65+
; FIXME: The %objsize_min result here looks wrong.
66+
define i32 @possible_out_of_bounds_gep_i16_sroa(i1 %c0, i1 %c1) {
67+
; CHECK-REF-LABEL: define i32 @possible_out_of_bounds_gep_i16_sroa(
68+
; CHECK-REF-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
69+
; CHECK-REF-NEXT: [[ENTRY:.*:]]
70+
; CHECK-REF-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 3, i32 0
71+
; CHECK-REF-NEXT: ret i32 [[RES]]
72+
;
73+
; CHECK-TST-LABEL: define i32 @possible_out_of_bounds_gep_i16_sroa(
74+
; CHECK-TST-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
75+
; CHECK-TST-NEXT: [[ENTRY:.*:]]
76+
; CHECK-TST-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 3, i32 65531
77+
; CHECK-TST-NEXT: ret i32 [[RES]]
78+
;
79+
entry:
80+
%obj = alloca [5 x i8], align 1
81+
%.sroa.gep = getelementptr i8, ptr %obj, i16 2
82+
%.sroa.gep1 = getelementptr i8, ptr %obj, i16 10
83+
%offset.sroa.sel = select i1 %c0, ptr %.sroa.gep, ptr %.sroa.gep1
84+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %offset.sroa.sel, i1 false, i1 true, i1 false)
85+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %offset.sroa.sel, i1 true, i1 true, i1 false)
86+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
87+
ret i32 %res
88+
}
89+
90+
; Indices are truncated to the pointer size in a gep. So "i32 -65526" should
91+
; be truncated to "i16 10".
92+
; FIXME: The TST result here is incorrect!
93+
define i32 @possible_out_of_bounds_gep_i32_trunc(i1 %c0, i1 %c1) {
94+
; CHECK-REF-LABEL: define i32 @possible_out_of_bounds_gep_i32_trunc(
95+
; CHECK-REF-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
96+
; CHECK-REF-NEXT: [[ENTRY:.*:]]
97+
; CHECK-REF-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 3, i32 0
98+
; CHECK-REF-NEXT: ret i32 [[RES]]
99+
;
100+
; CHECK-TST-LABEL: define i32 @possible_out_of_bounds_gep_i32_trunc(
101+
; CHECK-TST-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
102+
; CHECK-TST-NEXT: [[ENTRY:.*:]]
103+
; CHECK-TST-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 0, i32 3
104+
; CHECK-TST-NEXT: ret i32 [[RES]]
105+
;
106+
entry:
107+
%obj = alloca [5 x i8]
108+
%offset = select i1 %c0, i32 2, i32 -65526 ; 0xffff000a
109+
%ptr.slide = getelementptr i8, ptr %obj, i32 %offset
110+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
111+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
112+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
113+
ret i32 %res
114+
}
115+
116+
define i32 @out_of_bounds_gep_i8(i1 %c0, i1 %c1) {
117+
; CHECK-REF-LABEL: define i32 @out_of_bounds_gep_i8(
118+
; CHECK-REF-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
119+
; CHECK-REF-NEXT: [[ENTRY:.*:]]
120+
; CHECK-REF-NEXT: [[RES:%.*]] = sext i1 [[C1]] to i32
121+
; CHECK-REF-NEXT: ret i32 [[RES]]
122+
;
123+
; CHECK-TST-LABEL: define i32 @out_of_bounds_gep_i8(
124+
; CHECK-TST-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
125+
; CHECK-TST-NEXT: [[ENTRY:.*:]]
126+
; CHECK-TST-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 -1, i32 0
127+
; CHECK-TST-NEXT: ret i32 [[RES]]
128+
;
129+
entry:
130+
%obj = alloca [5 x i8]
131+
%ptr.slide = getelementptr i8, ptr %obj, i8 -128
132+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
133+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
134+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
135+
ret i32 %res
136+
}
137+
138+
define i32 @out_of_bounds_gep_i32(i1 %c0, i1 %c1) {
139+
; CHECK-LABEL: define i32 @out_of_bounds_gep_i32(
140+
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
141+
; CHECK-NEXT: [[ENTRY:.*:]]
142+
; CHECK-NEXT: ret i32 0
143+
;
144+
entry:
145+
%obj = alloca [5 x i8]
146+
%ptr.slide = getelementptr i8, ptr %obj, i32 10
147+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
148+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
149+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
150+
ret i32 %res
151+
}
152+
153+
define i32 @out_of_bounds_gep_i32_trunc(i1 %c0, i1 %c1) {
154+
; CHECK-LABEL: define i32 @out_of_bounds_gep_i32_trunc(
155+
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
156+
; CHECK-NEXT: [[ENTRY:.*:]]
157+
; CHECK-NEXT: ret i32 0
158+
;
159+
entry:
160+
%obj = alloca [5 x i8]
161+
%ptr.slide = getelementptr i8, ptr %obj, i32 -65526
162+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
163+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
164+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
165+
ret i32 %res
166+
}
167+
168+
; In this test the index will be out-of-bounds, but the current analysis won't
169+
; detect that. The analysis will find out that %offset is in the range [-2,
170+
; 10] which includes valid offsets that aren't out-of-bounds. Therefore we can
171+
; expect the result -1 for %objsize_max.
172+
define i32 @out_of_bounds_gep_i16_pos_neg(i1 %c0, i1 %c1) {
173+
; CHECK-REF-LABEL: define i32 @out_of_bounds_gep_i16_pos_neg(
174+
; CHECK-REF-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
175+
; CHECK-REF-NEXT: [[ENTRY:.*:]]
176+
; CHECK-REF-NEXT: [[RES:%.*]] = sext i1 [[C1]] to i32
177+
; CHECK-REF-NEXT: ret i32 [[RES]]
178+
;
179+
; CHECK-TST-LABEL: define i32 @out_of_bounds_gep_i16_pos_neg(
180+
; CHECK-TST-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
181+
; CHECK-TST-NEXT: [[ENTRY:.*:]]
182+
; CHECK-TST-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 -1, i32 0
183+
; CHECK-TST-NEXT: ret i32 [[RES]]
184+
;
185+
entry:
186+
%obj = alloca [5 x i8]
187+
%offset = select i1 %c0, i32 10, i32 -2
188+
%ptr.slide = getelementptr i8, ptr %obj, i32 %offset
189+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
190+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
191+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
192+
ret i32 %res
193+
}
194+
195+
; With 16-bit index size %offset is either 32767 or -32768. Thus, when
196+
; aggregating the possible offsets it we know that it is in the range [-32768,
197+
; 32767], which includes valid offsets that aren't out-of-bounds. This is
198+
; similar to the out_of_bounds_gep_i16_pos_neg test above, and we can expect
199+
; the result -1 for %objsize_max.
200+
define i32 @out_of_bounds_gep_i32_trunc_select(i1 %c0, i1 %c1) {
201+
; CHECK-REF-LABEL: define i32 @out_of_bounds_gep_i32_trunc_select(
202+
; CHECK-REF-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
203+
; CHECK-REF-NEXT: [[ENTRY:.*:]]
204+
; CHECK-REF-NEXT: [[RES:%.*]] = sext i1 [[C1]] to i32
205+
; CHECK-REF-NEXT: ret i32 [[RES]]
206+
;
207+
; CHECK-TST-LABEL: define i32 @out_of_bounds_gep_i32_trunc_select(
208+
; CHECK-TST-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
209+
; CHECK-TST-NEXT: [[ENTRY:.*:]]
210+
; CHECK-TST-NEXT: ret i32 0
211+
;
212+
entry:
213+
%obj = alloca [5 x i8]
214+
%offset = select i1 %c0, i32 32767, i32 32768
215+
%ptr.slide = getelementptr i8, ptr %obj, i32 %offset
216+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
217+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
218+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
219+
ret i32 %res
220+
}
221+
222+
; FIXME: Is 3 really correct for %objsize_min here?
223+
define i32 @possible_out_of_bounds_gep_i8_neg(i1 %c0, i1 %c1) {
224+
; CHECK-LABEL: define i32 @possible_out_of_bounds_gep_i8_neg(
225+
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
226+
; CHECK-NEXT: [[ENTRY:.*:]]
227+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 -1, i32 3
228+
; CHECK-NEXT: ret i32 [[RES]]
229+
;
230+
entry:
231+
%obj = alloca [5 x i8]
232+
%offset = select i1 %c0, i8 2, i8 -10
233+
%ptr.slide = getelementptr i8, ptr %obj, i8 %offset
234+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
235+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
236+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
237+
ret i32 %res
238+
}
239+
240+
; FIXME: Is 3 really correct for %objsize_min here?
241+
define i32 @possible_out_of_bounds_gep_i16_neg(i1 %c0, i1 %c1) {
242+
; CHECK-LABEL: define i32 @possible_out_of_bounds_gep_i16_neg(
243+
; CHECK-SAME: i1 [[C0:%.*]], i1 [[C1:%.*]]) {
244+
; CHECK-NEXT: [[ENTRY:.*:]]
245+
; CHECK-NEXT: [[RES:%.*]] = select i1 [[C1]], i32 -1, i32 3
246+
; CHECK-NEXT: ret i32 [[RES]]
247+
;
248+
entry:
249+
%obj = alloca [5 x i8]
250+
%offset = select i1 %c0, i16 2, i16 -10
251+
%ptr.slide = getelementptr i8, ptr %obj, i16 %offset
252+
%objsize_max = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 false, i1 true, i1 false)
253+
%objsize_min = call i32 @llvm.objectsize.i32.p0(ptr %ptr.slide, i1 true, i1 true, i1 false)
254+
%res = select i1 %c1, i32 %objsize_max, i32 %objsize_min
255+
ret i32 %res
256+
}

llvm/test/Transforms/LowerConstantIntrinsics/builtin-object-size-phi.ll

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,12 @@ if.end:
200200
ret i64 %size
201201
}
202202

203-
define i64 @pick_negative_offset_different_width(i32 %n) {
204-
; CHECK-LABEL: @pick_negative_offset_different_width(
203+
; FIXME: The result here looks weird. Either we reference into buffer0 with an
204+
; oob offset. Or we reference buffer1 (8 bytes) with a 4 byte
205+
; offset. The result 5 is wrong in both cases. Probably better to
206+
; return -1 here since we do not know if we have an oob pointer.
207+
define i64 @pick_negative_offset_different_width_index_maybe_too_small(i32 %n, i1 %c) {
208+
; CHECK-LABEL: @pick_negative_offset_different_width_index_maybe_too_small(
205209
; CHECK-NEXT: entry:
206210
; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 4, align 1
207211
; CHECK-NEXT: [[BUFFER1:%.*]] = alloca i8, i64 8, align 1
@@ -216,7 +220,8 @@ define i64 @pick_negative_offset_different_width(i32 %n) {
216220
; CHECK: if.end:
217221
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED0]], [[IF_ELSE]] ], [ [[OFFSETED1]], [[IF_END]] ]
218222
; CHECK-NEXT: [[POFFSETED:%.*]] = getelementptr i8, ptr [[P]], i64 -2
219-
; CHECK-NEXT: ret i64 5
223+
; CHECK-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 5, i64 0
224+
; CHECK-NEXT: ret i64 [[SIZE]]
220225
;
221226
entry:
222227
%buffer0 = alloca i8, i64 4
@@ -235,7 +240,51 @@ if.else:
235240
if.end:
236241
%p = phi ptr [ %offseted0, %if.then ], [ %offseted1, %if.else ]
237242
%poffseted = getelementptr i8, ptr %p, i64 -2
238-
%size = call i64 @llvm.objectsize.i64.p0(ptr %poffseted, i1 false, i1 false, i1 false)
243+
%sizemax = call i64 @llvm.objectsize.i64.p0(ptr %poffseted, i1 false, i1 false, i1 false)
244+
%sizemin = call i64 @llvm.objectsize.i64.p0(ptr %poffseted, i1 true, i1 false, i1 false)
245+
%size = select i1 %c, i64 %sizemax, i64 %sizemin
246+
ret i64 %size
247+
}
248+
249+
define i64 @pick_negative_offset_different_width_index_maybe_too_large(i32 %n, i1 %c) {
250+
; CHECK-LABEL: @pick_negative_offset_different_width_index_maybe_too_large(
251+
; CHECK-NEXT: entry:
252+
; CHECK-NEXT: [[BUFFER0:%.*]] = alloca i8, i64 4, align 1
253+
; CHECK-NEXT: [[BUFFER1:%.*]] = alloca i8, i64 8, align 1
254+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[N:%.*]], 0
255+
; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
256+
; CHECK: if.then:
257+
; CHECK-NEXT: [[OFFSETED0:%.*]] = getelementptr i8, ptr [[BUFFER0]], i64 1
258+
; CHECK-NEXT: br label [[IF_END:%.*]]
259+
; CHECK: if.else:
260+
; CHECK-NEXT: [[OFFSETED1:%.*]] = getelementptr i8, ptr [[BUFFER1]], i64 6
261+
; CHECK-NEXT: br label [[IF_END]]
262+
; CHECK: if.end:
263+
; CHECK-NEXT: [[P:%.*]] = phi ptr [ [[OFFSETED0]], [[IF_THEN]] ], [ [[OFFSETED1]], [[IF_ELSE]] ]
264+
; CHECK-NEXT: [[POFFSETED:%.*]] = getelementptr i8, ptr [[P]], i64 2
265+
; CHECK-NEXT: [[SIZE:%.*]] = select i1 [[C:%.*]], i64 1, i64 0
266+
; CHECK-NEXT: ret i64 [[SIZE]]
267+
;
268+
entry:
269+
%buffer0 = alloca i8, i64 4
270+
%buffer1 = alloca i8, i64 8
271+
%cond = icmp eq i32 %n, 0
272+
br i1 %cond, label %if.then, label %if.else
273+
274+
if.then:
275+
%offseted0 = getelementptr i8, ptr %buffer0, i64 1
276+
br label %if.end
277+
278+
if.else:
279+
%offseted1 = getelementptr i8, ptr %buffer1, i64 6
280+
br label %if.end
281+
282+
if.end:
283+
%p = phi ptr [ %offseted0, %if.then ], [ %offseted1, %if.else ]
284+
%poffseted = getelementptr i8, ptr %p, i64 2
285+
%sizemax = call i64 @llvm.objectsize.i64.p0(ptr %poffseted, i1 false, i1 false, i1 false)
286+
%sizemin = call i64 @llvm.objectsize.i64.p0(ptr %poffseted, i1 true, i1 false, i1 false)
287+
%size = select i1 %c, i64 %sizemax, i64 %sizemin
239288
ret i64 %size
240289
}
241290

0 commit comments

Comments
 (0)