xref: /llvm-project/llvm/test/Transforms/InstCombine/str-int-5.ll (revision 10f315dc9c96ec2413881ab55a285e35d80def88)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; Verify that calls to strtoul and strtoull are interpreted correctly even
3; in corner cases (or not folded).
4;
5; RUN: opt < %s -passes=instcombine -S | FileCheck %s
6
7declare i32 @strtoul(ptr, ptr, i32)
8declare i64 @strtoull(ptr, ptr, i32)
9
10
11; All POSIX whitespace characters.
12@ws = constant [7 x i8] c"\09\0d\0a\0b\0c \00"
13
14; A negative and positive number preceded by all POSIX whitespace.
15@ws_im123 = constant [11 x i8] c"\09\0d\0a\0b\0c -123\00"
16@ws_ip234 = constant [11 x i8] c"\09\0d\0a\0b\0c +234\00"
17
18@i32min = constant [13 x i8] c" -2147483648\00"
19@i32min_m1 = constant [13 x i8] c" -2147483649\00"
20@o32min = constant [15 x i8] c" +020000000000\00"
21@mo32min = constant [15 x i8] c" -020000000000\00"
22@x32min = constant [13 x i8] c" +0x80000000\00"
23@mx32min = constant [13 x i8] c" +0x80000000\00"
24
25@i32max = constant [12 x i8] c" 2147483647\00"
26@i32max_p1 = constant [12 x i8] c" 2147483648\00"
27@mX01 = constant [6 x i8] c" -0X1\00"
28
29@ui32max = constant [12 x i8] c" 4294967295\00"
30@ui32max_p1 = constant [12 x i8] c" 4294967296\00"
31
32@i64min = constant [22 x i8] c" -9223372036854775808\00"
33@i64min_m1 = constant [22 x i8] c" -9223372036854775809\00"
34
35@i64max = constant [21 x i8] c" 9223372036854775807\00"
36@i64max_p1 = constant [21 x i8] c" 9223372036854775808\00"
37
38@ui64max = constant [22 x i8] c" 18446744073709551615\00"
39@x64max = constant [20 x i8] c" 0xffffffffffffffff\00"
40@ui64max_p1 = constant [22 x i8] c" 18446744073709551616\00"
41
42@endptr = external global ptr
43
44
45; Exercise folding calls to 32-bit strtoul.
46
47define void @fold_strtoul(ptr %ps) {
48; CHECK-LABEL: @fold_strtoul(
49; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @ws_im123, i64 10), ptr @endptr, align 8
50; CHECK-NEXT:    store i32 -123, ptr [[PS:%.*]], align 4
51; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @ws_ip234, i64 10), ptr @endptr, align 8
52; CHECK-NEXT:    [[PS1:%.*]] = getelementptr i8, ptr [[PS]], i64 4
53; CHECK-NEXT:    store i32 234, ptr [[PS1]], align 4
54; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i32min_m1, i64 12), ptr @endptr, align 8
55; CHECK-NEXT:    [[PS2:%.*]] = getelementptr i8, ptr [[PS]], i64 8
56; CHECK-NEXT:    store i32 2147483647, ptr [[PS2]], align 4
57; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i32min, i64 12), ptr @endptr, align 8
58; CHECK-NEXT:    [[PS3:%.*]] = getelementptr i8, ptr [[PS]], i64 12
59; CHECK-NEXT:    store i32 -2147483648, ptr [[PS3]], align 4
60; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @o32min, i64 14), ptr @endptr, align 8
61; CHECK-NEXT:    [[PS4:%.*]] = getelementptr i8, ptr [[PS]], i64 16
62; CHECK-NEXT:    store i32 -2147483648, ptr [[PS4]], align 4
63; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @mo32min, i64 14), ptr @endptr, align 8
64; CHECK-NEXT:    [[PS5:%.*]] = getelementptr i8, ptr [[PS]], i64 20
65; CHECK-NEXT:    store i32 -2147483648, ptr [[PS5]], align 4
66; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @x32min, i64 12), ptr @endptr, align 8
67; CHECK-NEXT:    [[PS6:%.*]] = getelementptr i8, ptr [[PS]], i64 24
68; CHECK-NEXT:    store i32 -2147483648, ptr [[PS6]], align 4
69; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @mx32min, i64 12), ptr @endptr, align 8
70; CHECK-NEXT:    [[PS7:%.*]] = getelementptr i8, ptr [[PS]], i64 28
71; CHECK-NEXT:    store i32 -2147483648, ptr [[PS7]], align 4
72; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i32max, i64 11), ptr @endptr, align 8
73; CHECK-NEXT:    [[PS8:%.*]] = getelementptr i8, ptr [[PS]], i64 32
74; CHECK-NEXT:    store i32 2147483647, ptr [[PS8]], align 4
75; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @mX01, i64 5), ptr @endptr, align 8
76; CHECK-NEXT:    [[PS9:%.*]] = getelementptr i8, ptr [[PS]], i64 36
77; CHECK-NEXT:    store i32 -1, ptr [[PS9]], align 4
78; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i32max_p1, i64 11), ptr @endptr, align 8
79; CHECK-NEXT:    [[PS10:%.*]] = getelementptr i8, ptr [[PS]], i64 40
80; CHECK-NEXT:    store i32 -2147483648, ptr [[PS10]], align 4
81; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @ui32max, i64 11), ptr @endptr, align 8
82; CHECK-NEXT:    [[PS11:%.*]] = getelementptr i8, ptr [[PS]], i64 44
83; CHECK-NEXT:    store i32 -1, ptr [[PS11]], align 4
84; CHECK-NEXT:    ret void
85;
86; Fold a valid sequence with leading POSIX whitespace and a minus to
87; (uint32_t)-123.
88  %im123 = call i32 @strtoul(ptr @ws_im123, ptr @endptr, i32 10)
89  store i32 %im123, ptr %ps
90
91; Fold a valid sequence with leading POSIX whitespace and a plus to +234.
92  %ip234 = call i32 @strtoul(ptr @ws_ip234, ptr @endptr, i32 10)
93  %ps1 = getelementptr i32, ptr %ps, i32 1
94  store i32 %ip234, ptr %ps1
95
96; Fold the result of conversion that's equal to INT32_MIN - 1.
97  %i32min32m1 = call i32 @strtoul(ptr @i32min_m1, ptr @endptr, i32 10)
98  %ps2 = getelementptr i32, ptr %ps, i32 2
99  store i32 %i32min32m1, ptr %ps2
100
101; Fold INT32_MIN.
102  %i32min = call i32 @strtoul(ptr @i32min, ptr @endptr, i32 10)
103  %ps3 = getelementptr i32, ptr %ps, i32 3
104  store i32 %i32min, ptr %ps3
105
106; Fold INT32_MIN in octal.
107  %o32min = call i32 @strtoul(ptr @o32min, ptr @endptr, i32 0)
108  %ps4 = getelementptr i32, ptr %ps, i32 4
109  store i32 %o32min, ptr %ps4
110
111; Fold -INT32_MIN in octal.
112  %mo32min = call i32 @strtoul(ptr @mo32min, ptr @endptr, i32 0)
113  %ps5 = getelementptr i32, ptr %ps, i32 5
114  store i32 %mo32min, ptr %ps5
115
116; Fold INT32_MIN in hex.
117  %x32min = call i32 @strtoul(ptr @x32min, ptr @endptr, i32 0)
118  %ps6 = getelementptr i32, ptr %ps, i32 6
119  store i32 %x32min, ptr %ps6
120
121; Fold -INT32_MIN in hex.
122  %mx32min = call i32 @strtoul(ptr @mx32min, ptr @endptr, i32 0)
123  %ps7 = getelementptr i32, ptr %ps, i32 7
124  store i32 %x32min, ptr %ps7
125
126; Fold INT32_MAX.
127  %i32max = call i32 @strtoul(ptr @i32max, ptr @endptr, i32 10)
128  %ps8 = getelementptr i32, ptr %ps, i32 8
129  store i32 %i32max, ptr %ps8
130
131; Fold -0x01.
132  %mX01 = call i32 @strtoul(ptr @mX01, ptr @endptr, i32 0)
133  %ps9 = getelementptr i32, ptr %ps, i32 9
134  store i32 %mX01, ptr %ps9
135
136; Fold the result of conversion that's equal to INT32_MAX + 1.
137  %i32max32p1 = call i32 @strtoul(ptr @i32max_p1, ptr @endptr, i32 10)
138  %ps10 = getelementptr i32, ptr %ps, i32 10
139  store i32 %i32max32p1, ptr %ps10
140
141; Fold UINT32_MAX.
142  %ui32max = call i32 @strtoul(ptr @ui32max, ptr @endptr, i32 10)
143  %ps11 = getelementptr i32, ptr %ps, i32 11
144  store i32 %ui32max, ptr %ps11
145
146  ret void
147}
148
149
150; Exercise not folding calls to 32-bit strtoul.
151
152define void @call_strtoul(ptr %ps) {
153; CHECK-LABEL: @call_strtoul(
154; CHECK-NEXT:    [[MINM1:%.*]] = call i32 @strtoul(ptr nonnull @i64min_m1, ptr nonnull @endptr, i32 10)
155; CHECK-NEXT:    store i32 [[MINM1]], ptr [[PS:%.*]], align 4
156; CHECK-NEXT:    [[MAXP1:%.*]] = call i32 @strtoul(ptr nonnull @ui32max_p1, ptr nonnull @endptr, i32 10)
157; CHECK-NEXT:    [[PS1:%.*]] = getelementptr i8, ptr [[PS]], i64 4
158; CHECK-NEXT:    store i32 [[MAXP1]], ptr [[PS1]], align 4
159; CHECK-NEXT:    [[NWS:%.*]] = call i32 @strtoul(ptr nonnull @ws, ptr nonnull @endptr, i32 10)
160; CHECK-NEXT:    [[PS2:%.*]] = getelementptr i8, ptr [[PS]], i64 8
161; CHECK-NEXT:    store i32 [[NWS]], ptr [[PS2]], align 4
162; CHECK-NEXT:    [[NWSP6:%.*]] = call i32 @strtoul(ptr nonnull getelementptr inbounds nuw (i8, ptr @ws, i64 6), ptr nonnull @endptr, i32 10)
163; CHECK-NEXT:    [[PS3:%.*]] = getelementptr i8, ptr [[PS]], i64 12
164; CHECK-NEXT:    store i32 [[NWSP6]], ptr [[PS3]], align 4
165; CHECK-NEXT:    ret void
166;
167; Do not fold the result of conversion that overflows uint32_t.  This
168; could be folded into a constant provided errnor were set to ERANGE.
169  %minm1 = call i32 @strtoul(ptr @i64min_m1, ptr @endptr, i32 10)
170  store i32 %minm1, ptr %ps
171
172; Do not fold the result of conversion that's greater than UINT32_MAX
173; (same logic as above applies here).
174  %maxp1 = call i32 @strtoul(ptr @ui32max_p1, ptr @endptr, i32 10)
175  %ps1 = getelementptr i32, ptr %ps, i32 1
176  store i32 %maxp1, ptr %ps1
177
178; Do not fold a sequence consisting of just whitespace characters.
179  %nws = call i32 @strtoul(ptr @ws, ptr @endptr, i32 10)
180  %ps2 = getelementptr i32, ptr %ps, i32 2
181  store i32 %nws, ptr %ps2
182
183; Do not fold an empty sequence.  The library call may or may not end up
184; storing EINVAL in errno.
185  %pswsp6 = getelementptr [7 x i8], ptr @ws, i32 0, i32 6
186  %nwsp6 = call i32 @strtoul(ptr %pswsp6, ptr @endptr, i32 10)
187  %ps3 = getelementptr i32, ptr %ps, i32 3
188  store i32 %nwsp6, ptr %ps3
189
190  ret void
191}
192
193
194; Exercise folding calls to 64-bit strtoull.
195
196define void @fold_strtoull(ptr %ps) {
197; CHECK-LABEL: @fold_strtoull(
198; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @ws_im123, i64 10), ptr @endptr, align 8
199; CHECK-NEXT:    store i64 -123, ptr [[PS:%.*]], align 4
200; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @ws_ip234, i64 10), ptr @endptr, align 8
201; CHECK-NEXT:    [[PS1:%.*]] = getelementptr i8, ptr [[PS]], i64 8
202; CHECK-NEXT:    store i64 234, ptr [[PS1]], align 4
203; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i64min_m1, i64 21), ptr @endptr, align 8
204; CHECK-NEXT:    [[PS2:%.*]] = getelementptr i8, ptr [[PS]], i64 16
205; CHECK-NEXT:    store i64 9223372036854775807, ptr [[PS2]], align 4
206; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i32min, i64 12), ptr @endptr, align 8
207; CHECK-NEXT:    [[PS3:%.*]] = getelementptr i8, ptr [[PS]], i64 24
208; CHECK-NEXT:    store i64 -2147483648, ptr [[PS3]], align 4
209; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @o32min, i64 14), ptr @endptr, align 8
210; CHECK-NEXT:    [[PS4:%.*]] = getelementptr i8, ptr [[PS]], i64 32
211; CHECK-NEXT:    store i64 2147483648, ptr [[PS4]], align 4
212; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @x32min, i64 12), ptr @endptr, align 8
213; CHECK-NEXT:    [[PS5:%.*]] = getelementptr i8, ptr [[PS]], i64 40
214; CHECK-NEXT:    store i64 2147483648, ptr [[PS5]], align 4
215; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i64min, i64 21), ptr @endptr, align 8
216; CHECK-NEXT:    [[PS6:%.*]] = getelementptr i8, ptr [[PS]], i64 48
217; CHECK-NEXT:    store i64 -9223372036854775808, ptr [[PS6]], align 4
218; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i64max, i64 20), ptr @endptr, align 8
219; CHECK-NEXT:    [[PS7:%.*]] = getelementptr i8, ptr [[PS]], i64 56
220; CHECK-NEXT:    store i64 9223372036854775807, ptr [[PS7]], align 4
221; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @i64max_p1, i64 20), ptr @endptr, align 8
222; CHECK-NEXT:    [[PS8:%.*]] = getelementptr i8, ptr [[PS]], i64 64
223; CHECK-NEXT:    store i64 -9223372036854775808, ptr [[PS8]], align 4
224; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @ui64max, i64 21), ptr @endptr, align 8
225; CHECK-NEXT:    [[PS9:%.*]] = getelementptr i8, ptr [[PS]], i64 72
226; CHECK-NEXT:    store i64 -1, ptr [[PS9]], align 4
227; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @x64max, i64 19), ptr @endptr, align 8
228; CHECK-NEXT:    [[PS10:%.*]] = getelementptr i8, ptr [[PS]], i64 80
229; CHECK-NEXT:    store i64 -1, ptr [[PS10]], align 4
230; CHECK-NEXT:    ret void
231;
232; Fold a valid sequence with leading POSIX whitespace and a minus to
233; (uint64_t)-123.
234  %im123 = call i64 @strtoull(ptr @ws_im123, ptr @endptr, i32 10)
235  store i64 %im123, ptr %ps
236
237; Fold a valid sequence with leading POSIX whitespace and a plus to +234.
238  %ip234 = call i64 @strtoull(ptr @ws_ip234, ptr @endptr, i32 10)
239  %ps1 = getelementptr i64, ptr %ps, i32 1
240  store i64 %ip234, ptr %ps1
241
242; Fold the result of conversion that's equal to INT64_MIN - 1.
243  %i64min32m1 = call i64 @strtoull(ptr @i64min_m1, ptr @endptr, i32 10)
244  %ps2 = getelementptr i64, ptr %ps, i32 2
245  store i64 %i64min32m1, ptr %ps2
246
247; Fold INT32_MIN.
248  %i32min = call i64 @strtoull(ptr @i32min, ptr @endptr, i32 10)
249  %ps3 = getelementptr i64, ptr %ps, i32 3
250  store i64 %i32min, ptr %ps3
251
252; Fold INT32_MIN in octal.
253  %o32min = call i64 @strtoull(ptr @o32min, ptr @endptr, i32 0)
254  %ps4 = getelementptr i64, ptr %ps, i32 4
255  store i64 %o32min, ptr %ps4
256
257; Fold INT32_MIN in hex.
258  %x32min = call i64 @strtoull(ptr @x32min, ptr @endptr, i32 0)
259  %ps5 = getelementptr i64, ptr %ps, i32 5
260  store i64 %x32min, ptr %ps5
261
262; Fold INT64_MIN.
263  %i64min = call i64 @strtoull(ptr @i64min, ptr @endptr, i32 10)
264  %ps6 = getelementptr i64, ptr %ps, i32 6
265  store i64 %i64min, ptr %ps6
266
267; Fold INT64_MAX.
268  %i64max = call i64 @strtoull(ptr @i64max, ptr @endptr, i32 10)
269  %ps7 = getelementptr i64, ptr %ps, i32 7
270  store i64 %i64max, ptr %ps7
271
272; Fold the result of conversion that's equal to INT64_MAX + 1 to INT64_MIN.
273  %i64max32p1 = call i64 @strtoull(ptr @i64max_p1, ptr @endptr, i32 10)
274  %ps8 = getelementptr i64, ptr %ps, i32 8
275  store i64 %i64max32p1, ptr %ps8
276
277; Fold UINT64_MAX.
278  %ui64max = call i64 @strtoull(ptr @ui64max, ptr @endptr, i32 10)
279  %ps9 = getelementptr i64, ptr %ps, i32 9
280  store i64 %ui64max, ptr %ps9
281
282; Fold UINT64_MAX in hex.
283  %x64max = call i64 @strtoull(ptr @x64max, ptr @endptr, i32 0)
284  %ps10 = getelementptr i64, ptr %ps, i32 10
285  store i64 %x64max, ptr %ps10
286
287  ret void
288}
289
290
291; Exercise not folding calls to 64-bit strtoull.
292
293define void @call_strtoull(ptr %ps) {
294; CHECK-LABEL: @call_strtoull(
295; CHECK-NEXT:    [[MAXP1:%.*]] = call i64 @strtoull(ptr nonnull @ui64max_p1, ptr nonnull @endptr, i32 10)
296; CHECK-NEXT:    [[PS1:%.*]] = getelementptr i8, ptr [[PS:%.*]], i64 8
297; CHECK-NEXT:    store i64 [[MAXP1]], ptr [[PS1]], align 4
298; CHECK-NEXT:    [[NWS:%.*]] = call i64 @strtoull(ptr nonnull @ws, ptr nonnull @endptr, i32 10)
299; CHECK-NEXT:    [[PS2:%.*]] = getelementptr i8, ptr [[PS]], i64 16
300; CHECK-NEXT:    store i64 [[NWS]], ptr [[PS2]], align 4
301; CHECK-NEXT:    [[NWSP6:%.*]] = call i64 @strtoull(ptr nonnull getelementptr inbounds nuw (i8, ptr @ws, i64 6), ptr nonnull @endptr, i32 10)
302; CHECK-NEXT:    [[PS3:%.*]] = getelementptr i8, ptr [[PS]], i64 24
303; CHECK-NEXT:    store i64 [[NWSP6]], ptr [[PS3]], align 4
304; CHECK-NEXT:    ret void
305;
306; Do not fold the result of conversion that overflows uint64_t.  This
307; could be folded into a constant provided errnor were set to ERANGE.
308  %maxp1 = call i64 @strtoull(ptr @ui64max_p1, ptr @endptr, i32 10)
309  %ps1 = getelementptr i64, ptr %ps, i32 1
310  store i64 %maxp1, ptr %ps1
311
312; Do not fold a sequence consisting of just whitespace characters.
313  %nws = call i64 @strtoull(ptr @ws, ptr @endptr, i32 10)
314  %ps2 = getelementptr i64, ptr %ps, i32 2
315  store i64 %nws, ptr %ps2
316
317; Do not fold an empty sequence.  The library call may or may not end up
318; storing EINVAL in errno.
319  %pswsp6 = getelementptr [7 x i8], ptr @ws, i32 0, i32 6
320  %nwsp6 = call i64 @strtoull(ptr %pswsp6, ptr @endptr, i32 10)
321  %ps3 = getelementptr i64, ptr %ps, i32 3
322  store i64 %nwsp6, ptr %ps3
323
324  ret void
325}
326