xref: /llvm-project/llvm/test/Transforms/InstCombine/strlen-4.ll (revision 635f93dff7f07a58af4e8a7c915dfdb1852bb76b)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; Verify that strlen calls with conditional expressions involving constant
3; string arguments with nonconstant offsets are folded as expected.
4;
5; RUN: opt < %s -passes=instcombine -S | FileCheck %s
6
7declare i64 @strlen(ptr)
8
9@sx = external global [0 x i8]
10@s3 = constant [4 x i8] c"123\00"
11@s5 = constant [6 x i8] c"12345\00"
12@s7 = constant [8 x i8] c"1234567\00"
13
14@s5_3 = constant [10 x i8] c"12345\00123\00"
15
16
17; Fold strlen (x ? s3 + i : s5) to x ? 3 - i : 5.
18
19define i64 @fold_strlen_s3_pi_s5(i1 %X, i64 %I) {
20; CHECK-LABEL: @fold_strlen_s3_pi_s5(
21; CHECK-NEXT:    [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 [[I:%.*]]
22; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[X:%.*]], ptr [[PS3_PI]], ptr @s5
23; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
24; CHECK-NEXT:    ret i64 [[LEN]]
25;
26
27  %ps3_pi = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %I
28  %sel = select i1 %X, ptr %ps3_pi, ptr @s5
29  %len = tail call i64 @strlen(ptr %sel)
30  ret i64 %len
31}
32
33
34; More complex expressions like the one below are not handled yet.
35; Fold: strlen (x ? s3 + i + 1 : s5) to x ? 2 - i : 5.
36
37define i64 @fold_strlen_s3_pi_p1_s5(i1 %0, i64 %1) {
38; XFAIL-CHECK-LABEL: @fold_strlen_s3_pi_p1_s5(
39; XFAIL-CHECK-NEXT:    [[DIF_I:%.*]] = sub i64 2, %1
40; XFAIL-CHECK-NEXT:    [[SEL:%.*]] = select i1 %0, i64 [[DIF_I]], i64 5
41; XFAIL-CHECK-NEXT:    ret i64 [[SEL]]
42; CHECK-LABEL: @fold_strlen_s3_pi_p1_s5(
43; CHECK-NEXT:    [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 [[TMP1:%.*]]
44; CHECK-NEXT:    [[PS3_PI_P1:%.*]] = getelementptr i8, ptr [[PS3_PI]], i64 1
45; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], ptr [[PS3_PI_P1]], ptr @s5
46; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
47; CHECK-NEXT:    ret i64 [[LEN]]
48;
49
50  %ps3_pi = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %1
51  %ps3_pi_p1 = getelementptr i8, ptr %ps3_pi, i64 1
52  %sel = select i1 %0, ptr %ps3_pi_p1, ptr @s5
53  %len = tail call i64 @strlen(ptr %sel)
54  ret i64 %len
55}
56
57
58; Avoid folding calls with conditional expressions involving constant
59; string arguments with embedded nuls such as:
60;   strlen (x ? s5_3 + i : s5).
61
62define i64 @call_strlen_s5_3_pi_s5(i1 %0, i64 %1) {
63; CHECK-LABEL: @call_strlen_s5_3_pi_s5(
64; CHECK-NEXT:    [[PS5_3_PI:%.*]] = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 [[TMP1:%.*]]
65; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], ptr [[PS5_3_PI]], ptr @s5
66; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
67; CHECK-NEXT:    ret i64 [[LEN]]
68;
69
70  %ps5_3_pi = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 %1
71  %sel = select i1 %0, ptr %ps5_3_pi, ptr @s5
72  %len = tail call i64 @strlen(ptr %sel)
73  ret i64 %len
74}
75
76
77; But do fold strlen (x ? s5_3 : s5 + j) to x ? 5 : 5 - j.
78
79define i64 @call_strlen_s5_3_s5_pj(i1 %X, i64 %J) {
80; CHECK-LABEL: @call_strlen_s5_3_s5_pj(
81; CHECK-NEXT:    [[PS5:%.*]] = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 [[J:%.*]]
82; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[X:%.*]], ptr @s5_3, ptr [[PS5]]
83; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
84; CHECK-NEXT:    ret i64 [[LEN]]
85;
86
87  %ps5 = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 %J
88  %sel = select i1 %X, ptr @s5_3, ptr %ps5
89  %len = tail call i64 @strlen(ptr %sel)
90  ret i64 %len
91}
92
93
94; Fold strlen (x ? s3: s5 + j) to x ? 3 : 5 - j.
95
96define i64 @fold_strlen_s3_s5_pj(i1 %X, i64 %J) {
97; CHECK-LABEL: @fold_strlen_s3_s5_pj(
98; CHECK-NEXT:    [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 [[J:%.*]]
99; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[X:%.*]], ptr @s3, ptr [[PS5_PJ]]
100; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
101; CHECK-NEXT:    ret i64 [[LEN]]
102;
103
104  %ps5_pj = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 %J
105  %sel = select i1 %X, ptr @s3, ptr %ps5_pj
106  %len = tail call i64 @strlen(ptr %sel)
107  ret i64 %len
108}
109
110
111; Same as above, avoid folding calls with conditional expressions involving
112; constant string arguments with embedded nuls such as:
113;   strlen (x ? s3 : s5_3 + j).
114
115define i64 @call_strlen_s3_s5_3_pj(i1 %0, i64 %1) {
116; CHECK-LABEL: @call_strlen_s3_s5_3_pj(
117; CHECK-NEXT:    [[PS5_3_PJ:%.*]] = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 [[TMP1:%.*]]
118; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[TMP0:%.*]], ptr @s3, ptr [[PS5_3_PJ]]
119; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
120; CHECK-NEXT:    ret i64 [[LEN]]
121;
122
123  %ps5_3_pj = getelementptr inbounds [10 x i8], ptr @s5_3, i64 0, i64 %1
124  %sel = select i1 %0, ptr @s3, ptr %ps5_3_pj
125  %len = tail call i64 @strlen(ptr %sel)
126  ret i64 %len
127}
128
129
130; Fold strlen (x ? s3 + i: s5 + j) to x ? 3 - i : 5 - j.
131
132define i64 @fold_strlen_s3_pi_s5_pj(i1 %X, i64 %I, i64 %J) {
133; CHECK-LABEL: @fold_strlen_s3_pi_s5_pj(
134; CHECK-NEXT:    [[PS3_PI:%.*]] = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 [[I:%.*]]
135; CHECK-NEXT:    [[PS5_PJ:%.*]] = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 [[J:%.*]]
136; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[X:%.*]], ptr [[PS3_PI]], ptr [[PS5_PJ]]
137; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
138; CHECK-NEXT:    ret i64 [[LEN]]
139;
140; Use CHECK-DAG since the two instructions below might be emitted in reverse
141; order.
142
143  %ps3_pi = getelementptr inbounds [4 x i8], ptr @s3, i64 0, i64 %I
144  %ps5_pj = getelementptr inbounds [6 x i8], ptr @s5, i64 0, i64 %J
145  %sel = select i1 %X, ptr %ps3_pi, ptr %ps5_pj
146  %len = tail call i64 @strlen(ptr %sel)
147  ret i64 %len
148}
149
150
151; Fold strlen(E) with E being two conditional expressions:
152;   strlen (x == 3 ? s3 : x == 5 ? s5 : s7) to x == 3 ? 3 : x == 5 ? 5 : 7.
153
154define i64 @fold_strlen_s3_s5_s7(i32 %X) {
155; CHECK-LABEL: @fold_strlen_s3_s5_s7(
156; CHECK-NEXT:    [[X_EQ_3:%.*]] = icmp eq i32 [[X:%.*]], 3
157; CHECK-NEXT:    [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5
158; CHECK-NEXT:    [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7
159; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[X_EQ_3]], ptr @s3, ptr [[SEL_X_EQ_5]]
160; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
161; CHECK-NEXT:    ret i64 [[LEN]]
162;
163
164  %x_eq_3 = icmp eq i32 %X, 3
165  %x_eq_5 = icmp eq i32 %X, 5
166  %sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7
167  %sel = select i1 %x_eq_3, ptr @s3, ptr %sel_x_eq_5
168  %len = tail call i64 @strlen(ptr %sel)
169  ret i64 %len
170}
171
172
173; Do not fold strlen (x == 3 ? sx : x == 5 ? s5 : s7).
174
175define i64 @call_strlen_sx_s5_s7(i32 %X) {
176; CHECK-LABEL: @call_strlen_sx_s5_s7(
177; CHECK-NEXT:    [[X_EQ_3:%.*]] = icmp eq i32 [[X:%.*]], 3
178; CHECK-NEXT:    [[X_EQ_5:%.*]] = icmp eq i32 [[X]], 5
179; CHECK-NEXT:    [[SEL_X_EQ_5:%.*]] = select i1 [[X_EQ_5]], ptr @s5, ptr @s7
180; CHECK-NEXT:    [[SEL:%.*]] = select i1 [[X_EQ_3]], ptr @sx, ptr [[SEL_X_EQ_5]]
181; CHECK-NEXT:    [[LEN:%.*]] = tail call i64 @strlen(ptr noundef nonnull dereferenceable(1) [[SEL]])
182; CHECK-NEXT:    ret i64 [[LEN]]
183;
184
185  %x_eq_3 = icmp eq i32 %X, 3
186  %x_eq_5 = icmp eq i32 %X, 5
187  %sel_x_eq_5 = select i1 %x_eq_5, ptr @s5, ptr @s7
188  %sel = select i1 %x_eq_3, ptr @sx, ptr %sel_x_eq_5
189  %len = tail call i64 @strlen(ptr %sel)
190  ret i64 %len
191}
192