xref: /llvm-project/llvm/test/Transforms/InstCombine/str-int-3.ll (revision 193ea83dd7e879ddd4e3dfb1fa74a676b528e4a6)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; Verify that calls to atoi and related conversion functions with members
3; of constant structs as arguments are folded to constants as expected.
4; RUN: opt < %s -passes=instcombine -S | FileCheck %s
5
6declare i32 @atoi(ptr)
7declare i64 @atol(ptr)
8declare i64 @atoll(ptr)
9
10declare i64 @strtol(ptr, ptr, i32)
11declare i64 @strtoll(ptr, ptr, i32)
12
13%struct.A = type { [4 x i8], [5 x i8], [7 x i8] }
14
15@a = constant [2 x %struct.A] [%struct.A { [4 x i8] c"1\00\00\00", [5 x i8] c"12\00\00\00", [7 x i8] c"56789\00\00" }, %struct.A { [4 x i8] c"123\00", [5 x i8] c"1234\00", [7 x i8] c"67890\00\00" }]
16
17
18; Fold atoi(a[I].M) for constant I in [0, 1] and member M in [a, b]
19; to a constant.
20
21define void @fold_atoi_member(ptr %pi) {
22; CHECK-LABEL: @fold_atoi_member(
23; CHECK-NEXT:    store i32 1, ptr [[PI:%.*]], align 4
24; CHECK-NEXT:    [[PIA0B:%.*]] = getelementptr i8, ptr [[PI]], i64 4
25; CHECK-NEXT:    store i32 12, ptr [[PIA0B]], align 4
26; CHECK-NEXT:    [[PIA1A:%.*]] = getelementptr i8, ptr [[PI]], i64 8
27; CHECK-NEXT:    store i32 123, ptr [[PIA1A]], align 4
28; CHECK-NEXT:    [[PIA1B:%.*]] = getelementptr i8, ptr [[PI]], i64 12
29; CHECK-NEXT:    store i32 1234, ptr [[PIA1B]], align 4
30; CHECK-NEXT:    ret void
31;
32; Fold atoi(a[0].a) to 1.
33  %ia0a = call i32 @atoi(ptr @a)
34  store i32 %ia0a, ptr %pi
35
36; Fold atoi(a[0].b) to 12.
37  %pa0b = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 0
38  %ia0b = call i32 @atoi(ptr %pa0b)
39  %pia0b = getelementptr i32, ptr %pi, i32 1
40  store i32 %ia0b, ptr %pia0b
41
42; Fold atoi(a[1].a) to 123.
43  %pa1a = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 0
44  %ia1a = call i32 @atoi(ptr %pa1a)
45  %pia1a = getelementptr i32, ptr %pi, i32 2
46  store i32 %ia1a, ptr %pia1a
47
48; Fold atoi(a[1].b) to 1234.
49  %pa1b = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 0
50  %ia1b = call i32 @atoi(ptr %pa1b)
51  %pia1b = getelementptr i32, ptr %pi, i32 3
52  store i32 %ia1b, ptr %pia1b
53
54  ret void
55}
56
57
58; TODO: Fold atoi with an excessive offset.  It's undefined so folding it
59; to zero is valid and might prevent crashes or returning a bogus value,
60; even though it prevents detecting the bug by sanitizers.
61; This is not fully implemented because the out-of-bounds offset results
62; in the empty string which atoi (via strtol) is required to interpret as
63; a zero but for which it may set errno to EINVAL.  To fold only
64; the undefined calls the folder would have to differentiate between
65; the empty string an out-of-bounds pointer.
66
67define void @fold_atoi_offset_out_of_bounds(ptr %pi) {
68; CHECK-LABEL: @fold_atoi_offset_out_of_bounds(
69; CHECK-NEXT:    [[IA_0_0_32:%.*]] = call i32 @atoi(ptr nonnull getelementptr inbounds nuw (i8, ptr @a, i64 32))
70; CHECK-NEXT:    store i32 [[IA_0_0_32]], ptr [[PI:%.*]], align 4
71; CHECK-NEXT:    [[IA_0_0_33:%.*]] = call i32 @atoi(ptr getelementptr (i8, ptr @a, i64 33))
72; CHECK-NEXT:    store i32 [[IA_0_0_33]], ptr [[PI]], align 4
73; CHECK-NEXT:    ret void
74;
75; TODO: Check folding.
76; Fold atoi((const char*)a + sizeof a) to zero.
77  %ia_0_0_32 = call i32 @atoi(ptr getelementptr inbounds ([2 x %struct.A], ptr @a, i64 1, i64 0, i32 0, i64 0))
78  store i32 %ia_0_0_32, ptr %pi
79
80; Likewise, fold atoi((const char*)a + sizeof a + 1) to zero.
81  %pa_0_0_33 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 0, i64 33
82  %ia_0_0_33 = call i32 @atoi(ptr %pa_0_0_33)
83  store i32 %ia_0_0_33, ptr %pi
84
85  ret void
86}
87
88
89; Fold atol(a[I].M) for constant I in [0, 1] and member M in [a, b, c]
90; to a constant.
91
92define void @fold_atol_member(ptr %pi) {
93; CHECK-LABEL: @fold_atol_member(
94; CHECK-NEXT:    store i64 1, ptr [[PI:%.*]], align 4
95; CHECK-NEXT:    [[PIA0B:%.*]] = getelementptr i8, ptr [[PI]], i64 8
96; CHECK-NEXT:    store i64 12, ptr [[PIA0B]], align 4
97; CHECK-NEXT:    [[PIA0C:%.*]] = getelementptr i8, ptr [[PI]], i64 16
98; CHECK-NEXT:    store i64 56789, ptr [[PIA0C]], align 4
99; CHECK-NEXT:    [[PIA1A:%.*]] = getelementptr i8, ptr [[PI]], i64 24
100; CHECK-NEXT:    store i64 123, ptr [[PIA1A]], align 4
101; CHECK-NEXT:    [[PIA1B:%.*]] = getelementptr i8, ptr [[PI]], i64 32
102; CHECK-NEXT:    store i64 1234, ptr [[PIA1B]], align 4
103; CHECK-NEXT:    [[PIA1C:%.*]] = getelementptr i8, ptr [[PI]], i64 40
104; CHECK-NEXT:    store i64 67890, ptr [[PIA1C]], align 4
105; CHECK-NEXT:    ret void
106;
107; Fold atol(a[0].a) to 1.
108  %ia0a = call i64 @atol(ptr @a)
109  store i64 %ia0a, ptr %pi
110
111; Fold atol(a[0].b) to 12.
112  %pa0b = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 0
113  %ia0b = call i64 @atol(ptr %pa0b)
114  %pia0b = getelementptr i64, ptr %pi, i32 1
115  store i64 %ia0b, ptr %pia0b
116
117; Fold atol(a[0].c) to 56789.
118  %pa0c = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 2, i64 0
119  %ia0c = call i64 @atol(ptr %pa0c)
120  %pia0c = getelementptr i64, ptr %pi, i32 2
121  store i64 %ia0c, ptr %pia0c
122
123; Fold atol(a[1].a) to 123.
124  %pa1a = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 0
125  %ia1a = call i64 @atol(ptr %pa1a)
126  %pia1a = getelementptr i64, ptr %pi, i32 3
127  store i64 %ia1a, ptr %pia1a
128
129; Fold atol(a[1].b) to 1234.
130  %pa1b = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 0
131  %ia1b = call i64 @atol(ptr %pa1b)
132  %pia1b = getelementptr i64, ptr %pi, i32 4
133  store i64 %ia1b, ptr %pia1b
134
135; Fold atol(a[1].c) to 67890.
136  %pa1c = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 2, i64 0
137  %ia1c = call i64 @atol(ptr %pa1c)
138  %pia1c = getelementptr i64, ptr %pi, i32 5
139  store i64 %ia1c, ptr %pia1c
140
141  ret void
142}
143
144
145; Fold atoll(a[I].M + C) for constant I in [0, 1], member M in [a, b, c],
146; and C in a valid range to a constant.
147
148define void @fold_atoll_member_pC(ptr %pi) {
149; CHECK-LABEL: @fold_atoll_member_pC(
150; CHECK-NEXT:    store i64 1, ptr [[PI:%.*]], align 4
151; CHECK-NEXT:    [[PIA0BP1:%.*]] = getelementptr i8, ptr [[PI]], i64 8
152; CHECK-NEXT:    store i64 2, ptr [[PIA0BP1]], align 4
153; CHECK-NEXT:    [[PIA0CP3:%.*]] = getelementptr i8, ptr [[PI]], i64 16
154; CHECK-NEXT:    store i64 89, ptr [[PIA0CP3]], align 4
155; CHECK-NEXT:    [[PIA1AP2:%.*]] = getelementptr i8, ptr [[PI]], i64 24
156; CHECK-NEXT:    store i64 3, ptr [[PIA1AP2]], align 4
157; CHECK-NEXT:    [[PIA1BP3:%.*]] = getelementptr i8, ptr [[PI]], i64 32
158; CHECK-NEXT:    store i64 4, ptr [[PIA1BP3]], align 4
159; CHECK-NEXT:    [[PIA1CP4:%.*]] = getelementptr i8, ptr [[PI]], i64 40
160; CHECK-NEXT:    store i64 0, ptr [[PIA1CP4]], align 4
161; CHECK-NEXT:    ret void
162;
163; Fold atoll(a[0].a) to 1.
164  %ia0a = call i64 @atol(ptr @a)
165  store i64 %ia0a, ptr %pi
166
167; Fold atoll(a[0].b + 1) to 2.
168  %pa0bp1 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 1
169  %ia0bp1 = call i64 @atol(ptr %pa0bp1)
170  %pia0bp1 = getelementptr i64, ptr %pi, i32 1
171  store i64 %ia0bp1, ptr %pia0bp1
172
173; Fold atoll(a[0].c + 3) to 89.
174  %pa0cp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 2, i64 3
175  %ia0cp3 = call i64 @atol(ptr %pa0cp3)
176  %pia0cp3 = getelementptr i64, ptr %pi, i32 2
177  store i64 %ia0cp3, ptr %pia0cp3
178
179; Fold atoll(a[1].a + 2) to 3.
180  %pa1ap2 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 2
181  %ia1ap2 = call i64 @atol(ptr %pa1ap2)
182  %pia1ap2 = getelementptr i64, ptr %pi, i32 3
183  store i64 %ia1ap2, ptr %pia1ap2
184
185; Fold atoll(a[1].b + 3) to 4.
186  %pa1bp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 3
187  %ia1bp3 = call i64 @atol(ptr %pa1bp3)
188  %pia1bp3 = getelementptr i64, ptr %pi, i32 4
189  store i64 %ia1bp3, ptr %pia1bp3
190
191; Fold atoll(a[1].c + 4) to 0.
192  %pa1cp4 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 2, i64 4
193  %ia1cp4 = call i64 @atol(ptr %pa1cp4)
194  %pia1cp4 = getelementptr i64, ptr %pi, i32 5
195  store i64 %ia1cp4, ptr %pia1cp4
196
197  ret void
198}
199
200
201; Fold strtol(a[I].M + C, 0, 0) for constant I in [0, 1], member M in [a, b, c],
202; and C in a valid range to a constant.
203
204define void @fold_strtol_member_pC(ptr %pi) {
205; CHECK-LABEL: @fold_strtol_member_pC(
206; CHECK-NEXT:    store i64 1, ptr [[PI:%.*]], align 4
207; CHECK-NEXT:    [[PIA0BP1:%.*]] = getelementptr i8, ptr [[PI]], i64 8
208; CHECK-NEXT:    store i64 2, ptr [[PIA0BP1]], align 4
209; CHECK-NEXT:    [[PIA0CP3:%.*]] = getelementptr i8, ptr [[PI]], i64 16
210; CHECK-NEXT:    store i64 89, ptr [[PIA0CP3]], align 4
211; CHECK-NEXT:    [[PIA1AP2:%.*]] = getelementptr i8, ptr [[PI]], i64 24
212; CHECK-NEXT:    store i64 3, ptr [[PIA1AP2]], align 4
213; CHECK-NEXT:    [[PIA1BP3:%.*]] = getelementptr i8, ptr [[PI]], i64 32
214; CHECK-NEXT:    store i64 4, ptr [[PIA1BP3]], align 4
215; CHECK-NEXT:    [[PIA1CP4:%.*]] = getelementptr i8, ptr [[PI]], i64 40
216; CHECK-NEXT:    store i64 0, ptr [[PIA1CP4]], align 4
217; CHECK-NEXT:    ret void
218;
219; Fold strtol(a[0].a, 0, 0) to 1.
220  %ia0a = call i64 @strtol(ptr @a, ptr null, i32 0)
221  store i64 %ia0a, ptr %pi
222
223; Fold strtol(a[0].b + 1, 0, 0, ptr null, i32 0) to 2.
224  %pa0bp1 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 1
225  %ia0bp1 = call i64 @strtol(ptr %pa0bp1, ptr null, i32 0)
226  %pia0bp1 = getelementptr i64, ptr %pi, i32 1
227  store i64 %ia0bp1, ptr %pia0bp1
228
229; Fold strtol(a[0].c + 3, 0, 0, ptr null, i32 0) to 89.
230  %pa0cp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 2, i64 3
231  %ia0cp3 = call i64 @strtol(ptr %pa0cp3, ptr null, i32 0)
232  %pia0cp3 = getelementptr i64, ptr %pi, i32 2
233  store i64 %ia0cp3, ptr %pia0cp3
234
235; Fold strtol(a[1].a + 2, 0, 0, ptr null, i32 0) to 3.
236  %pa1ap2 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 2
237  %ia1ap2 = call i64 @strtol(ptr %pa1ap2, ptr null, i32 0)
238  %pia1ap2 = getelementptr i64, ptr %pi, i32 3
239  store i64 %ia1ap2, ptr %pia1ap2
240
241; Fold strtol(a[1].b + 3, 0, 0, ptr null, i32 0) to 4.
242  %pa1bp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 3
243  %ia1bp3 = call i64 @strtol(ptr %pa1bp3, ptr null, i32 0)
244  %pia1bp3 = getelementptr i64, ptr %pi, i32 4
245  store i64 %ia1bp3, ptr %pia1bp3
246
247; Fold strtol(a[1].c + 4, 0, 0, ptr null, i32 0) to 0.
248  %pa1cp4 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 2, i64 4
249  %ia1cp4 = call i64 @strtol(ptr %pa1cp4, ptr null, i32 0)
250  %pia1cp4 = getelementptr i64, ptr %pi, i32 5
251  store i64 %ia1cp4, ptr %pia1cp4
252
253  ret void
254}
255
256
257; Fold strtoll(a[I].M + C, 0, 0) for constant I in [0, 1], member M
258; in [a, b, c], and C in a valid range to a constant.
259
260define void @fold_strtoll_member_pC(ptr %pi) {
261; CHECK-LABEL: @fold_strtoll_member_pC(
262; CHECK-NEXT:    store i64 1, ptr [[PI:%.*]], align 4
263; CHECK-NEXT:    [[PIA0BP1:%.*]] = getelementptr i8, ptr [[PI]], i64 8
264; CHECK-NEXT:    store i64 2, ptr [[PIA0BP1]], align 4
265; CHECK-NEXT:    [[PIA0CP3:%.*]] = getelementptr i8, ptr [[PI]], i64 16
266; CHECK-NEXT:    store i64 89, ptr [[PIA0CP3]], align 4
267; CHECK-NEXT:    [[PIA1AP2:%.*]] = getelementptr i8, ptr [[PI]], i64 24
268; CHECK-NEXT:    store i64 3, ptr [[PIA1AP2]], align 4
269; CHECK-NEXT:    [[PIA1BP3:%.*]] = getelementptr i8, ptr [[PI]], i64 32
270; CHECK-NEXT:    store i64 4, ptr [[PIA1BP3]], align 4
271; CHECK-NEXT:    [[PIA1CP4:%.*]] = getelementptr i8, ptr [[PI]], i64 40
272; CHECK-NEXT:    store i64 0, ptr [[PIA1CP4]], align 4
273; CHECK-NEXT:    ret void
274;
275; Fold strtoll(a[0].a, 0, 0) to 1.
276  %ia0a = call i64 @strtoll(ptr @a, ptr null, i32 0)
277  store i64 %ia0a, ptr %pi
278
279; Fold strtoll(a[0].b + 1, 0, 0, ptr null, i32 0) to 2.
280  %pa0bp1 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 1, i64 1
281  %ia0bp1 = call i64 @strtoll(ptr %pa0bp1, ptr null, i32 0)
282  %pia0bp1 = getelementptr i64, ptr %pi, i32 1
283  store i64 %ia0bp1, ptr %pia0bp1
284
285; Fold strtoll(a[0].c + 3, 0, 0, ptr null, i32 0) to 89.
286  %pa0cp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 0, i32 2, i64 3
287  %ia0cp3 = call i64 @strtoll(ptr %pa0cp3, ptr null, i32 0)
288  %pia0cp3 = getelementptr i64, ptr %pi, i32 2
289  store i64 %ia0cp3, ptr %pia0cp3
290
291; Fold strtoll(a[1].a + 2, 0, 0, ptr null, i32 0) to 3.
292  %pa1ap2 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 0, i64 2
293  %ia1ap2 = call i64 @strtoll(ptr %pa1ap2, ptr null, i32 0)
294  %pia1ap2 = getelementptr i64, ptr %pi, i32 3
295  store i64 %ia1ap2, ptr %pia1ap2
296
297; Fold strtoll(a[1].b + 3, 0, 0, ptr null, i32 0) to 4.
298  %pa1bp3 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 1, i64 3
299  %ia1bp3 = call i64 @strtoll(ptr %pa1bp3, ptr null, i32 0)
300  %pia1bp3 = getelementptr i64, ptr %pi, i32 4
301  store i64 %ia1bp3, ptr %pia1bp3
302
303; Fold strtoll(a[1].c + 4, 0, 0, ptr null, i32 0) to 0.
304  %pa1cp4 = getelementptr [2 x %struct.A], ptr @a, i64 0, i64 1, i32 2, i64 4
305  %ia1cp4 = call i64 @strtoll(ptr %pa1cp4, ptr null, i32 0)
306  %pia1cp4 = getelementptr i64, ptr %pi, i32 5
307  store i64 %ia1cp4, ptr %pia1cp4
308
309  ret void
310}
311