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
6declare i64 @strlen(i8*)
7
8%struct.A = type { [4 x i8], [5 x i8] }
9
10@a = constant [2 x %struct.A] [%struct.A { [4 x i8] c"1\00\00\00", [5 x i8] c"12\00\00\00" }, %struct.A { [4 x i8] c"123\00", [5 x i8] c"1234\00" }], align 16
11
12
13; Fold strlen(a[I].a + J) and strlen(a[I].b + J) with constant I and J
14; to constants.
15
16define void @fold_strlen_A(i64* %plen) {
17; CHECK-LABEL: @fold_strlen_A(
18; CHECK-NEXT:    [[LENA0A:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0))
19; CHECK-NEXT:    store i64 [[LENA0A]], i64* [[PLEN:%.*]], align 4
20; CHECK-NEXT:    [[LENA0AP1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 1))
21; CHECK-NEXT:    [[PLEN1:%.*]] = getelementptr i64, i64* [[PLEN]], i64 1
22; CHECK-NEXT:    store i64 [[LENA0AP1]], i64* [[PLEN1]], align 4
23; CHECK-NEXT:    [[LENA0AP2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 2))
24; CHECK-NEXT:    [[PLEN2:%.*]] = getelementptr i64, i64* [[PLEN]], i64 2
25; CHECK-NEXT:    store i64 [[LENA0AP2]], i64* [[PLEN2]], align 4
26; CHECK-NEXT:    [[LENA0AP3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 3))
27; CHECK-NEXT:    [[PLEN3:%.*]] = getelementptr i64, i64* [[PLEN]], i64 3
28; CHECK-NEXT:    store i64 [[LENA0AP3]], i64* [[PLEN3]], align 4
29; CHECK-NEXT:    [[LENA0B:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0))
30; CHECK-NEXT:    [[PLEN4:%.*]] = getelementptr i64, i64* [[PLEN]], i64 4
31; CHECK-NEXT:    store i64 [[LENA0B]], i64* [[PLEN4]], align 4
32; CHECK-NEXT:    [[LENA0BP1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1))
33; CHECK-NEXT:    [[PLEN5:%.*]] = getelementptr i64, i64* [[PLEN]], i64 5
34; CHECK-NEXT:    store i64 [[LENA0BP1]], i64* [[PLEN5]], align 4
35; CHECK-NEXT:    [[LENA0BP2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 2))
36; CHECK-NEXT:    [[PLEN6:%.*]] = getelementptr i64, i64* [[PLEN]], i64 6
37; CHECK-NEXT:    store i64 [[LENA0BP2]], i64* [[PLEN6]], align 4
38; CHECK-NEXT:    [[LENA0BP3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 3))
39; CHECK-NEXT:    [[PLEN7:%.*]] = getelementptr i64, i64* [[PLEN]], i64 7
40; CHECK-NEXT:    store i64 [[LENA0BP3]], i64* [[PLEN7]], align 4
41; CHECK-NEXT:    [[LENA0BP4:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 4))
42; CHECK-NEXT:    [[PLEN8:%.*]] = getelementptr i64, i64* [[PLEN]], i64 8
43; CHECK-NEXT:    store i64 [[LENA0BP4]], i64* [[PLEN8]], align 4
44; CHECK-NEXT:    [[LENA1A:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0))
45; CHECK-NEXT:    [[PLEN9:%.*]] = getelementptr i64, i64* [[PLEN]], i64 9
46; CHECK-NEXT:    store i64 [[LENA1A]], i64* [[PLEN9]], align 4
47; CHECK-NEXT:    [[LENA1AP1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 1))
48; CHECK-NEXT:    [[PLEN10:%.*]] = getelementptr i64, i64* [[PLEN]], i64 10
49; CHECK-NEXT:    store i64 [[LENA1AP1]], i64* [[PLEN10]], align 4
50; CHECK-NEXT:    [[LENA1AP2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2))
51; CHECK-NEXT:    [[PLEN11:%.*]] = getelementptr i64, i64* [[PLEN]], i64 11
52; CHECK-NEXT:    store i64 [[LENA1AP2]], i64* [[PLEN11]], align 4
53; CHECK-NEXT:    [[LENA1AP3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 3))
54; CHECK-NEXT:    [[PLEN12:%.*]] = getelementptr i64, i64* [[PLEN]], i64 12
55; CHECK-NEXT:    store i64 [[LENA1AP3]], i64* [[PLEN12]], align 4
56; CHECK-NEXT:    [[LENA1B:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0))
57; CHECK-NEXT:    [[PLEN14:%.*]] = getelementptr i64, i64* [[PLEN]], i64 14
58; CHECK-NEXT:    store i64 [[LENA1B]], i64* [[PLEN14]], align 4
59; CHECK-NEXT:    [[LENA1BP1:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 1))
60; CHECK-NEXT:    [[PLEN15:%.*]] = getelementptr i64, i64* [[PLEN]], i64 15
61; CHECK-NEXT:    store i64 [[LENA1BP1]], i64* [[PLEN15]], align 4
62; CHECK-NEXT:    [[LENA1BP2:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 2))
63; CHECK-NEXT:    [[PLEN16:%.*]] = getelementptr i64, i64* [[PLEN]], i64 16
64; CHECK-NEXT:    store i64 [[LENA1BP2]], i64* [[PLEN16]], align 4
65; CHECK-NEXT:    [[LENA1BP3:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3))
66; CHECK-NEXT:    [[PLEN17:%.*]] = getelementptr i64, i64* [[PLEN]], i64 17
67; CHECK-NEXT:    store i64 [[LENA1BP3]], i64* [[PLEN17]], align 4
68; CHECK-NEXT:    [[LENA1BP4:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) getelementptr inbounds ([2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 4))
69; CHECK-NEXT:    [[PLEN18:%.*]] = getelementptr i64, i64* [[PLEN]], i64 18
70; CHECK-NEXT:    store i64 [[LENA1BP4]], i64* [[PLEN18]], align 4
71; CHECK-NEXT:    ret void
72;
73; Fold strlen(a[0].a) to 1.
74  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 0
75  %lena0a = call i64 @strlen(i8* %pa0a)
76  %plen0 = getelementptr i64, i64* %plen, i32 0
77  store i64 %lena0a, i64* %plen0
78
79; Fold strlen(a[0].a + 1) to 0.
80  %pa0ap1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 1
81  %lena0ap1 = call i64 @strlen(i8* %pa0ap1)
82  %plen1 = getelementptr i64, i64* %plen, i32 1
83  store i64 %lena0ap1, i64* %plen1
84
85; Fold strlen(a[0].a + 2) to 0.
86  %pa0ap2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 2
87  %lena0ap2 = call i64 @strlen(i8* %pa0ap2)
88  %plen2 = getelementptr i64, i64* %plen, i32 2
89  store i64 %lena0ap2, i64* %plen2
90
91; Fold strlen(a[0].a + 3) to 0.
92  %pa0ap3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 3
93  %lena0ap3 = call i64 @strlen(i8* %pa0ap3)
94  %plen3 = getelementptr i64, i64* %plen, i32 3
95  store i64 %lena0ap3, i64* %plen3
96
97; Fold strlen(a[0].b) to 2.
98  %pa0b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 0
99  %lena0b = call i64 @strlen(i8* %pa0b)
100  %plen4 = getelementptr i64, i64* %plen, i32 4
101  store i64 %lena0b, i64* %plen4
102
103; Fold strlen(a[0].b + 1) to 1.
104  %pa0bp1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 1
105  %lena0bp1 = call i64 @strlen(i8* %pa0bp1)
106  %plen5 = getelementptr i64, i64* %plen, i32 5
107  store i64 %lena0bp1, i64* %plen5
108
109; Fold strlen(a[0].b + 2) to 0.
110  %pa0bp2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 2
111  %lena0bp2 = call i64 @strlen(i8* %pa0bp2)
112  %plen6 = getelementptr i64, i64* %plen, i32 6
113  store i64 %lena0bp2, i64* %plen6
114
115; Fold strlen(a[0].b + 3) to 0.
116  %pa0bp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 3
117  %lena0bp3 = call i64 @strlen(i8* %pa0bp3)
118  %plen7 = getelementptr i64, i64* %plen, i32 7
119  store i64 %lena0bp3, i64* %plen7
120
121; Fold strlen(a[0].b + 4) to 0.
122  %pa0bp4 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 4
123  %lena0bp4 = call i64 @strlen(i8* %pa0bp4)
124  %plen8 = getelementptr i64, i64* %plen, i32 8
125  store i64 %lena0bp4, i64* %plen8
126
127; Fold strlen(a[1].a) to 3.
128  %pa1a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 0
129  %lena1a = call i64 @strlen(i8* %pa1a)
130  %plen9 = getelementptr i64, i64* %plen, i32 9
131  store i64 %lena1a, i64* %plen9
132
133; Fold strlen(a[1].a + 1) to 2.
134  %pa1ap1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 1
135  %lena1ap1 = call i64 @strlen(i8* %pa1ap1)
136  %plen10 = getelementptr i64, i64* %plen, i32 10
137  store i64 %lena1ap1, i64* %plen10
138
139; Fold strlen(a[1].a + 2) to 1.
140  %pa1ap2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 2
141  %lena1ap2 = call i64 @strlen(i8* %pa1ap2)
142  %plen11 = getelementptr i64, i64* %plen, i32 11
143  store i64 %lena1ap2, i64* %plen11
144
145; Fold strlen(a[1].a + 3) to 0.
146  %pa1ap3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 3
147  %lena1ap3 = call i64 @strlen(i8* %pa1ap3)
148  %plen12 = getelementptr i64, i64* %plen, i32 12
149  store i64 %lena1ap3, i64* %plen12
150
151; Fold strlen(a[1].b) to 4.
152  %pa1b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 0
153  %lena1b = call i64 @strlen(i8* %pa1b)
154  %plen14 = getelementptr i64, i64* %plen, i32 14
155  store i64 %lena1b, i64* %plen14
156
157; Fold strlen(a[1].b + 1) to 3.
158  %pa1bp1 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 1
159  %lena1bp1 = call i64 @strlen(i8* %pa1bp1)
160  %plen15 = getelementptr i64, i64* %plen, i32 15
161  store i64 %lena1bp1, i64* %plen15
162
163; Fold strlen(a[1].b + 2) to 2.
164  %pa1bp2 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 2
165  %lena1bp2 = call i64 @strlen(i8* %pa1bp2)
166  %plen16 = getelementptr i64, i64* %plen, i32 16
167  store i64 %lena1bp2, i64* %plen16
168
169; Fold strlen(a[1].b + 3) to 1.
170  %pa1bp3 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 3
171  %lena1bp3 = call i64 @strlen(i8* %pa1bp3)
172  %plen17 = getelementptr i64, i64* %plen, i32 17
173  store i64 %lena1bp3, i64* %plen17
174
175; Fold strlen(a[1].b + 4) to 0.
176  %pa1bp4 = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 4
177  %lena1bp4 = call i64 @strlen(i8* %pa1bp4)
178  %plen18 = getelementptr i64, i64* %plen, i32 18
179  store i64 %lena1bp4, i64* %plen18
180
181  ret void
182}
183
184
185; TODO: Fold strlen(a[I].a + X) and strlen(a[I].b + X) with constant I and
186; variable X to (X - strlen(a[I].a)) and (X - strlen(a[I].b)) respectively.
187
188define void @fold_strlen_A_pI(i64* %plen, i64 %I) {
189; CHECK-LABEL: @fold_strlen_A_pI(
190; CHECK-NEXT:    [[PA0A:%.*]] = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 [[I:%.*]]
191; CHECK-NEXT:    [[LENA0A:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA0A]])
192; CHECK-NEXT:    store i64 [[LENA0A]], i64* [[PLEN:%.*]], align 4
193; CHECK-NEXT:    [[PA0B:%.*]] = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 [[I]]
194; CHECK-NEXT:    [[LENA0B:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA0B]])
195; CHECK-NEXT:    [[PLEN1:%.*]] = getelementptr i64, i64* [[PLEN]], i64 1
196; CHECK-NEXT:    store i64 [[LENA0B]], i64* [[PLEN1]], align 4
197; CHECK-NEXT:    [[PA1A:%.*]] = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 [[I]]
198; CHECK-NEXT:    [[LENA1A:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA1A]])
199; CHECK-NEXT:    [[PLEN2:%.*]] = getelementptr i64, i64* [[PLEN]], i64 2
200; CHECK-NEXT:    store i64 [[LENA1A]], i64* [[PLEN2]], align 4
201; CHECK-NEXT:    [[PA1B:%.*]] = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 [[I]]
202; CHECK-NEXT:    [[LENA1B:%.*]] = call i64 @strlen(i8* noundef nonnull dereferenceable(1) [[PA1B]])
203; CHECK-NEXT:    [[PLEN3:%.*]] = getelementptr i64, i64* [[PLEN]], i64 3
204; CHECK-NEXT:    store i64 [[LENA1B]], i64* [[PLEN3]], align 4
205; CHECK-NEXT:    ret void
206;
207  %pa0a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 0, i64 %I
208  %lena0a = call i64 @strlen(i8* %pa0a)
209  %plen0 = getelementptr i64, i64* %plen, i32 0
210  store i64 %lena0a, i64* %plen0
211
212  %pa0b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 0, i32 1, i64 %I
213  %lena0b = call i64 @strlen(i8* %pa0b)
214  %plen1 = getelementptr i64, i64* %plen, i32 1
215  store i64 %lena0b, i64* %plen1
216
217  %pa1a = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 0, i64 %I
218  %lena1a = call i64 @strlen(i8* %pa1a)
219  %plen2 = getelementptr i64, i64* %plen, i32 2
220  store i64 %lena1a, i64* %plen2
221
222  %pa1b = getelementptr [2 x %struct.A], [2 x %struct.A]* @a, i64 0, i64 1, i32 1, i64 %I
223  %lena1b = call i64 @strlen(i8* %pa1b)
224  %plen3 = getelementptr i64, i64* %plen, i32 3
225  store i64 %lena1b, i64* %plen3
226
227  ret void
228}
229