1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; Verify that strlen calls with members of constant structs are folded.
3;
4; RUN: opt < %s -passes=instcombine -S | FileCheck %s
5
6; struct A_a4 { char a[4]; };
7%struct.A_a4 = type { [4 x i8] }
8
9; struct A_a4_a5 { char a[4], b[5]; };
10%struct.A_a4_a5 = type { [4 x i8], [5 x i8] }
11
12; struct A_a4_i32_a5 { char a[4]; int32_t i; char b[5]; };
13%struct.A_a4_i32_a5 = type { [4 x i8], i32, [5 x i8] }
14
15@a_s3 = constant %struct.A_a4 { [4 x i8 ] c"123\00" }
16@a_s3_s4 = constant %struct.A_a4_a5 { [4 x i8 ] c"123\00", [5 x i8] c"1234\00" }
17@a_s3_i32_s4 = constant %struct.A_a4_i32_a5 { [4 x i8 ] c"123\00", i32 -1, [5 x i8] c"1234\00" }
18
19; Structs with flexible array members.
20@ax_s3 = constant { i8, [4 x i8] } { i8 3, [4 x i8] c"123\00" }
21@ax_s5 = constant { i16, [6 x i8] } { i16 5, [6 x i8] c"12345\00" }
22@ax_s7 = constant { i32, i32, [8 x i8] } { i32 7, i32 0, [8 x i8] c"1234567\00" }
23
24@ax = external global [0 x i64]
25
26
27declare i64 @strlen(i8*)
28
29
30; Fold strlen(a_s3.a) to 3.
31
32define i64 @fold_strlen_a_S3_to_3() {
33; CHECK-LABEL: @fold_strlen_a_S3_to_3(
34; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 0))
35; CHECK-NEXT:    ret i64 [[LEN]]
36;
37  %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 0
38  %len = call i64 @strlen(i8* %ptr)
39  ret i64 %len
40}
41
42
43; Fold strlen(&a_s3.a[1]) to 2.
44
45define i64 @fold_strlen_a_S3_p1_to_2() {
46; CHECK-LABEL: @fold_strlen_a_S3_p1_to_2(
47; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 1))
48; CHECK-NEXT:    ret i64 [[LEN]]
49;
50  %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 1
51  %len = call i64 @strlen(i8* %ptr)
52  ret i64 %len
53}
54
55
56; Fold strlen(&a_s3.a[2]) to 1.
57
58define i64 @fold_strlen_a_S3_p2_to_1() {
59; CHECK-LABEL: @fold_strlen_a_S3_p2_to_1(
60; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 2))
61; CHECK-NEXT:    ret i64 [[LEN]]
62;
63  %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 2
64  %len = call i64 @strlen(i8* %ptr)
65  ret i64 %len
66}
67
68
69; Fold strlen(&a_s3.a[3]) to 0.
70
71define i64 @fold_strlen_a_S3_p3_to_0() {
72; CHECK-LABEL: @fold_strlen_a_S3_p3_to_0(
73; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4:%.*]], %struct.A_a4* @a_s3, i64 0, i32 0, i64 3))
74; CHECK-NEXT:    ret i64 [[LEN]]
75;
76  %ptr = getelementptr %struct.A_a4, %struct.A_a4* @a_s3, i32 0, i32 0, i32 3
77  %len = call i64 @strlen(i8* %ptr)
78  ret i64 %len
79}
80
81
82; Fold strlen(a_s3_s4.a) to 3.
83
84define i64 @fold_strlen_a_S3_s4_to_3() {
85; CHECK-LABEL: @fold_strlen_a_S3_s4_to_3(
86; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 0, i64 0))
87; CHECK-NEXT:    ret i64 [[LEN]]
88;
89  %ptr = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 0
90  %len = call i64 @strlen(i8* %ptr)
91  ret i64 %len
92}
93
94
95; Fold strlen(&a_s3_s4.a[2]) to 1.
96
97define i64 @fold_strlen_a_S3_p2_s4_to_1() {
98; CHECK-LABEL: @fold_strlen_a_S3_p2_s4_to_1(
99; CHECK-NEXT:    [[LEN:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 0, i64 2))
100; CHECK-NEXT:    ret i64 [[LEN]]
101;
102  %ptr = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 2
103  %len = call i64 @strlen(i8* %ptr)
104  ret i64 %len
105}
106
107
108; Fold strlen(a_s3_s4.b) to 4.
109; Exercise both variants of the GEP index.
110
111define void @fold_strlen_a_s3_S4_to_4() {
112; CHECK-LABEL: @fold_strlen_a_s3_S4_to_4(
113; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 0))
114; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
115; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 0))
116; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
117; CHECK-NEXT:    ret void
118;
119  %p1 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 4
120  %len1 = call i64 @strlen(i8* %p1)
121  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
122  store i64 %len1, i64* %pax0
123
124  %p2 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 1, i32 0
125  %len2 = call i64 @strlen(i8* %p2)
126  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
127  store i64 %len1, i64* %pax1
128
129  ret void
130}
131
132
133; Fold strlen(&a_s3_s4.b[1]) to 3.
134; Exercise both variants of the GEP index.
135
136define void @fold_strlen_a_s3_S4_p1_to_3() {
137; CHECK-LABEL: @fold_strlen_a_s3_S4_p1_to_3(
138; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5:%.*]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 1))
139; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
140; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_A5]], %struct.A_a4_a5* @a_s3_s4, i64 0, i32 1, i64 1))
141; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
142; CHECK-NEXT:    ret void
143;
144  %p1 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 0, i32 5
145  %len1 = call i64 @strlen(i8* %p1)
146  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
147  store i64 %len1, i64* %pax0
148
149  %p2 = getelementptr %struct.A_a4_a5, %struct.A_a4_a5* @a_s3_s4, i32 0, i32 1, i32 1
150  %len2 = call i64 @strlen(i8* %p2)
151  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
152  store i64 %len1, i64* %pax1
153
154  ret void
155}
156
157
158; Fold strlen(a_s3_i32_s4.b) to 4.
159; Exercise both variants of the GEP index.
160
161define void @fold_strlen_a_s3_i32_S4_to_4() {
162; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_to_4(
163; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0))
164; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
165; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0))
166; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
167; CHECK-NEXT:    ret void
168;
169  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 8
170  %len1 = call i64 @strlen(i8* %p1)
171  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
172  store i64 %len1, i64* %pax0
173
174  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 0
175  %len2 = call i64 @strlen(i8* %p2)
176  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
177  store i64 %len1, i64* %pax1
178
179  ret void
180}
181
182
183; Fold strlen(&a_s3_i32_s4.b[1]) to 3.
184; Exercise both variants of the GEP index.
185
186define void @fold_strlen_a_s3_i32_S4_p1_to_3() {
187; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p1_to_3(
188; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 1))
189; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
190; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 0))
191; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
192; CHECK-NEXT:    ret void
193;
194  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 9
195  %len1 = call i64 @strlen(i8* %p1)
196  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
197  store i64 %len1, i64* %pax0
198
199  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 0
200  %len2 = call i64 @strlen(i8* %p2)
201  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
202  store i64 %len1, i64* %pax1
203
204  ret void
205}
206
207
208; Fold strlen(&a_s3_i32_s4.b[2]) to 2.
209; Exercise both variants of the GEP index.
210
211define void @fold_strlen_a_s3_i32_S4_p2_to_2() {
212; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p2_to_2(
213; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 2))
214; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
215; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 2))
216; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
217; CHECK-NEXT:    ret void
218;
219  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 10
220  %len1 = call i64 @strlen(i8* %p1)
221  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
222  store i64 %len1, i64* %pax0
223
224  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 2
225  %len2 = call i64 @strlen(i8* %p2)
226  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
227  store i64 %len1, i64* %pax1
228
229  ret void
230}
231
232
233; Fold strlen(&a_s3_i32_s4.b[3]) to 1.
234; Exercise both variants of the GEP index.
235
236define void @fold_strlen_a_s3_i32_S4_p3_to_1() {
237; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p3_to_1(
238; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 3))
239; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
240; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 3))
241; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
242; CHECK-NEXT:    ret void
243;
244  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 11
245  %len1 = call i64 @strlen(i8* %p1)
246  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
247  store i64 %len1, i64* %pax0
248
249  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 3
250  %len2 = call i64 @strlen(i8* %p2)
251  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
252  store i64 %len1, i64* %pax1
253
254  ret void
255}
256
257
258; Fold strlen(&a_s3_i32_s4.b[4]) to 0.
259; Exercise both variants of the GEP index.
260
261define void @fold_strlen_a_s3_i32_S4_p4_to_0() {
262; CHECK-LABEL: @fold_strlen_a_s3_i32_S4_p4_to_0(
263; CHECK-NEXT:    [[LEN1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5:%.*]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 4))
264; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
265; CHECK-NEXT:    [[LEN2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([[STRUCT_A_A4_I32_A5]], %struct.A_a4_i32_a5* @a_s3_i32_s4, i64 0, i32 2, i64 4))
266; CHECK-NEXT:    store i64 [[LEN1]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
267; CHECK-NEXT:    ret void
268;
269  %p1 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 0, i32 12
270  %len1 = call i64 @strlen(i8* %p1)
271  %pax0 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
272  store i64 %len1, i64* %pax0
273
274  %p2 = getelementptr %struct.A_a4_i32_a5, %struct.A_a4_i32_a5* @a_s3_i32_s4, i32 0, i32 2, i32 4
275  %len2 = call i64 @strlen(i8* %p2)
276  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
277  store i64 %len1, i64* %pax1
278
279  ret void
280}
281
282
283; Fold strlen(ax_sN.a) of an constant initialized flexible array member
284; to N for N in { 3, 5, 7 }.
285
286define void @fold_strlen_ax_s() {
287; CHECK-LABEL: @fold_strlen_ax_s(
288; CHECK-NEXT:    [[LEN3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i8, [4 x i8] }, { i8, [4 x i8] }* @ax_s3, i64 0, i32 1, i64 0))
289; CHECK-NEXT:    store i64 [[LEN3]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 0), align 4
290; CHECK-NEXT:    [[LEN5:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i16, [6 x i8] }, { i16, [6 x i8] }* @ax_s5, i64 0, i32 1, i64 0))
291; CHECK-NEXT:    store i64 [[LEN5]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 1), align 4
292; CHECK-NEXT:    [[LEN7:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ({ i32, i32, [8 x i8] }, { i32, i32, [8 x i8] }* @ax_s7, i64 0, i32 2, i64 0))
293; CHECK-NEXT:    store i64 [[LEN7]], i64* getelementptr inbounds ([0 x i64], [0 x i64]* @ax, i64 0, i64 2), align 4
294; CHECK-NEXT:    ret void
295;
296  %pax_s3 = getelementptr { i8, [4 x i8] }, { i8, [4 x i8] }* @ax_s3, i64 0, i32 1, i64 0
297  %len3 = call i64 @strlen(i8* %pax_s3)
298  %pax1 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 0
299  store i64 %len3, i64* %pax1
300
301  %pax_s5 = getelementptr { i16, [6 x i8] }, { i16, [6 x i8] }* @ax_s5, i64 0, i32 1, i64 0
302  %len5 = call i64 @strlen(i8* %pax_s5)
303  %pax2 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 1
304  store i64 %len5, i64* %pax2
305
306  %pax_s7 = getelementptr { i32, i32, [8 x i8] }, { i32, i32, [8 x i8] }* @ax_s7, i64 0, i32 2, i64 0
307  %len7 = call i64 @strlen(i8* %pax_s7)
308  %pax3 = getelementptr inbounds [0 x i64], [0 x i64]* @ax, i64 0, i64 2
309  store i64 %len7, i64* %pax3
310
311  ret void
312}
313