xref: /llvm-project/llvm/test/Transforms/InstCombine/memchr.ll (revision 10f315dc9c96ec2413881ab55a285e35d80def88)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; Test that the memchr library call simplifier works correctly.
3; RUN: opt < %s -passes=instcombine -S | FileCheck %s
4
5target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128-n8:16:32"
6
7@hello = constant [14 x i8] c"hello world\5Cn\00"
8@hellonull = constant [14 x i8] c"hello\00world\5Cn\00"
9@null = constant [1 x i8] zeroinitializer
10@newlines = constant [3 x i8] c"\0D\0A\00"
11@single = constant [2 x i8] c"\1F\00"
12@spaces = constant [4 x i8] c" \0D\0A\00"
13@negative = constant [3 x i8] c"\FF\FE\00"
14@chp = global ptr zeroinitializer
15
16declare ptr @memchr(ptr, i32, i32)
17
18define void @test1() {
19; CHECK-LABEL: @test1(
20; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @hello, i32 6), ptr @chp, align 4
21; CHECK-NEXT:    ret void
22;
23  %dst = call ptr @memchr(ptr @hello, i32 119, i32 14)
24  store ptr %dst, ptr @chp
25  ret void
26}
27
28define void @test2() {
29; CHECK-LABEL: @test2(
30; CHECK-NEXT:    store ptr null, ptr @chp, align 4
31; CHECK-NEXT:    ret void
32;
33  %dst = call ptr @memchr(ptr @null, i32 119, i32 1)
34  store ptr %dst, ptr @chp
35  ret void
36}
37
38define void @test3() {
39; CHECK-LABEL: @test3(
40; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @hello, i32 13), ptr @chp, align 4
41; CHECK-NEXT:    ret void
42;
43  %dst = call ptr @memchr(ptr @hello, i32 0, i32 14)
44  store ptr %dst, ptr @chp
45  ret void
46}
47
48define void @test4(i32 %chr) {
49; CHECK-LABEL: @test4(
50; CHECK-NEXT:    [[DST:%.*]] = call ptr @memchr(ptr noundef nonnull dereferenceable(1) @hello, i32 [[CHR:%.*]], i32 14)
51; CHECK-NEXT:    store ptr [[DST]], ptr @chp, align 4
52; CHECK-NEXT:    ret void
53;
54  %dst = call ptr @memchr(ptr @hello, i32 %chr, i32 14)
55  store ptr %dst, ptr @chp
56  ret void
57}
58
59define void @test5() {
60; CHECK-LABEL: @test5(
61; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @hello, i32 13), ptr @chp, align 4
62; CHECK-NEXT:    ret void
63;
64  %dst = call ptr @memchr(ptr @hello, i32 65280, i32 14)
65  store ptr %dst, ptr @chp
66  ret void
67}
68
69define void @test6() {
70; CHECK-LABEL: @test6(
71; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @hello, i32 6), ptr @chp, align 4
72; CHECK-NEXT:    ret void
73;
74; Overflow, but we still find the right thing.
75  %dst = call ptr @memchr(ptr @hello, i32 119, i32 100)
76  store ptr %dst, ptr @chp
77  ret void
78}
79
80define void @test7() {
81; CHECK-LABEL: @test7(
82; CHECK-NEXT:    store ptr null, ptr @chp, align 4
83; CHECK-NEXT:    ret void
84;
85; Overflow
86  %dst = call ptr @memchr(ptr @hello, i32 120, i32 100)
87  store ptr %dst, ptr @chp
88  ret void
89}
90
91define void @test8() {
92; CHECK-LABEL: @test8(
93; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @hellonull, i32 6), ptr @chp, align 4
94; CHECK-NEXT:    ret void
95;
96  %dst = call ptr @memchr(ptr @hellonull, i32 119, i32 14)
97  store ptr %dst, ptr @chp
98  ret void
99}
100
101define void @test9() {
102; CHECK-LABEL: @test9(
103; CHECK-NEXT:    store ptr getelementptr inbounds nuw (i8, ptr @hellonull, i32 6), ptr @chp, align 4
104; CHECK-NEXT:    ret void
105;
106  %str = getelementptr [14 x i8], ptr @hellonull, i32 0, i32 2
107  %dst = call ptr @memchr(ptr %str, i32 119, i32 12)
108  store ptr %dst, ptr @chp
109  ret void
110}
111
112define void @test10() {
113; CHECK-LABEL: @test10(
114; CHECK-NEXT:    store ptr null, ptr @chp, align 4
115; CHECK-NEXT:    ret void
116;
117  %dst = call ptr @memchr(ptr @hello, i32 119, i32 6)
118  store ptr %dst, ptr @chp
119  ret void
120}
121
122; Check transformation memchr("\r\n", C, 3) != nullptr -> (C & 9217) != 0
123define i1 @test11(i32 %C) {
124; CHECK-LABEL: @test11(
125; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i16
126; CHECK-NEXT:    [[TMP2:%.*]] = and i16 [[TMP1]], 255
127; CHECK-NEXT:    [[MEMCHR_BOUNDS:%.*]] = icmp samesign ult i16 [[TMP2]], 16
128; CHECK-NEXT:    [[TMP3:%.*]] = shl nuw i16 1, [[TMP2]]
129; CHECK-NEXT:    [[TMP4:%.*]] = and i16 [[TMP3]], 9217
130; CHECK-NEXT:    [[MEMCHR_BITS:%.*]] = icmp ne i16 [[TMP4]], 0
131; CHECK-NEXT:    [[MEMCHR:%.*]] = select i1 [[MEMCHR_BOUNDS]], i1 [[MEMCHR_BITS]], i1 false
132; CHECK-NEXT:    ret i1 [[MEMCHR]]
133;
134  %dst = call ptr @memchr(ptr @newlines, i32 %C, i32 3)
135  %cmp = icmp ne ptr %dst, null
136  ret i1 %cmp
137}
138
139; No 64 bits here
140define i1 @test12(i32 %C) {
141; CHECK-LABEL: @test12(
142; CHECK-NEXT:    [[DST:%.*]] = call ptr @memchr(ptr noundef nonnull dereferenceable(1) @spaces, i32 [[C:%.*]], i32 3)
143; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[DST]], null
144; CHECK-NEXT:    ret i1 [[CMP]]
145;
146  %dst = call ptr @memchr(ptr @spaces, i32 %C, i32 3)
147  %cmp = icmp ne ptr %dst, null
148  ret i1 %cmp
149}
150
151define i1 @test13(i32 %C) {
152; CHECK-LABEL: @test13(
153; CHECK-NEXT:    [[TMP1:%.*]] = trunc i32 [[C:%.*]] to i8
154; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[TMP1]], 0
155; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq i8 [[TMP1]], 31
156; CHECK-NEXT:    [[CMP:%.*]] = or i1 [[TMP3]], [[TMP2]]
157; CHECK-NEXT:    ret i1 [[CMP]]
158;
159  %dst = call ptr @memchr(ptr @single, i32 %C, i32 2)
160  %cmp = icmp ne ptr %dst, null
161  ret i1 %cmp
162}
163
164define i1 @test14(i32 %C) {
165; CHECK-LABEL: @test14(
166; CHECK-NEXT:    [[TMP1:%.*]] = and i32 [[C:%.*]], 255
167; CHECK-NEXT:    [[MEMCHR_CHAR0CMP:%.*]] = icmp eq i32 [[TMP1]], 31
168; CHECK-NEXT:    ret i1 [[MEMCHR_CHAR0CMP]]
169;
170  %dst = call ptr @memchr(ptr @single, i32 %C, i32 1)
171  %cmp = icmp ne ptr %dst, null
172  ret i1 %cmp
173}
174
175define i1 @test15(i32 %C, i32 %n) {
176; CHECK-LABEL: @test15(
177; CHECK-NEXT:    [[DST:%.*]] = call ptr @memchr(ptr nonnull @negative, i32 [[C:%.*]], i32 [[N:%.*]])
178; CHECK-NEXT:    [[CMP:%.*]] = icmp ne ptr [[DST]], null
179; CHECK-NEXT:    ret i1 [[CMP]]
180;
181  %dst = call ptr @memchr(ptr @negative, i32 %C, i32 %n)
182  %cmp = icmp ne ptr %dst, null
183  ret i1 %cmp
184}
185
186@s = internal constant [1 x i8] [i8 0], align 1
187define ptr @pr32124() {
188; CHECK-LABEL: @pr32124(
189; CHECK-NEXT:    ret ptr @s
190;
191  %res = tail call ptr @memchr(ptr @s, i32 0, i32 1)
192  ret ptr %res
193}
194
195define ptr @test16(ptr %str, i32 %c, i32 %n) {
196; CHECK-LABEL: @test16(
197; CHECK-NEXT:    [[RET:%.*]] = call ptr @memchr(ptr [[STR:%.*]], i32 [[C:%.*]], i32 [[N:%.*]])
198; CHECK-NEXT:    ret ptr [[RET]]
199;
200
201  %ret = call ptr @memchr(ptr %str, i32 %c, i32 %n)
202  ret ptr %ret
203}
204
205define ptr @test17(ptr %str, i32 %c, i32 %n) {
206; CHECK-LABEL: @test17(
207; CHECK-NEXT:    [[RET:%.*]] = call ptr @memchr(ptr nonnull [[STR:%.*]], i32 [[C:%.*]], i32 [[N:%.*]])
208; CHECK-NEXT:    ret ptr [[RET]]
209;
210
211  %ret = call ptr @memchr(ptr nonnull %str, i32 %c, i32 %n)
212  ret ptr %ret
213}
214
215define ptr @test18(ptr %str, i32 %c) {
216; CHECK-LABEL: @test18(
217; CHECK-NEXT:    [[RET:%.*]] = call ptr @memchr(ptr noundef nonnull dereferenceable(1) [[STR:%.*]], i32 [[C:%.*]], i32 5)
218; CHECK-NEXT:    ret ptr [[RET]]
219;
220
221  %ret = call ptr @memchr(ptr %str, i32 %c, i32 5)
222  ret ptr %ret
223}
224
225define ptr @test19(ptr %str, i32 %c) null_pointer_is_valid {
226; CHECK-LABEL: @test19(
227; CHECK-NEXT:    [[RET:%.*]] = call ptr @memchr(ptr noundef [[STR:%.*]], i32 [[C:%.*]], i32 5)
228; CHECK-NEXT:    ret ptr [[RET]]
229;
230
231  %ret = call ptr @memchr(ptr %str, i32 %c, i32 5)
232  ret ptr %ret
233}
234