1; Test that the memchr library call simplifier works correctly.
2; RUN: opt < %s -instcombine -S | FileCheck %s
3
4target 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"
5
6@hello = constant [14 x i8] c"hello world\5Cn\00"
7@hellonull = constant [14 x i8] c"hello\00world\5Cn\00"
8@null = constant [1 x i8] zeroinitializer
9@newlines = constant [3 x i8] c"\0D\0A\00"
10@single = constant [2 x i8] c"\1F\00"
11@spaces = constant [4 x i8] c" \0D\0A\00"
12@negative = constant [3 x i8] c"\FF\FE\00"
13@chp = global i8* zeroinitializer
14
15declare i8* @memchr(i8*, i32, i32)
16
17define void @test1() {
18; CHECK-LABEL: @test1
19; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 6)
20; CHECK-NOT: call i8* @memchr
21; CHECK: ret void
22
23  %str = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
24  %dst = call i8* @memchr(i8* %str, i32 119, i32 14)
25  store i8* %dst, i8** @chp
26  ret void
27}
28
29define void @test2() {
30; CHECK-LABEL: @test2
31; CHECK: store i8* null, i8** @chp, align 4
32; CHECK-NOT: call i8* @memchr
33; CHECK: ret void
34
35  %str = getelementptr [1 x i8], [1 x i8]* @null, i32 0, i32 0
36  %dst = call i8* @memchr(i8* %str, i32 119, i32 1)
37  store i8* %dst, i8** @chp
38  ret void
39}
40
41define void @test3() {
42; CHECK-LABEL: @test3
43; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13)
44; CHECK-NOT: call i8* @memchr
45; CHECK: ret void
46
47  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
48  %dst = call i8* @memchr(i8* %src, i32 0, i32 14)
49  store i8* %dst, i8** @chp
50  ret void
51}
52
53define void @test4(i32 %chr) {
54; CHECK-LABEL: @test4
55; CHECK: call i8* @memchr
56; CHECK-NOT: call i8* @memchr
57; CHECK: ret void
58
59  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
60  %dst = call i8* @memchr(i8* %src, i32 %chr, i32 14)
61  store i8* %dst, i8** @chp
62  ret void
63}
64
65define void @test5() {
66; CHECK-LABEL: @test5
67; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 13)
68; CHECK-NOT: call i8* @memchr
69; CHECK: ret void
70
71  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
72  %dst = call i8* @memchr(i8* %src, i32 65280, i32 14)
73  store i8* %dst, i8** @chp
74  ret void
75}
76
77define void @test6() {
78; CHECK-LABEL: @test6
79; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hello, i32 0, i32 6)
80; CHECK-NOT: call i8* @memchr
81; CHECK: ret void
82
83  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
84; Overflow, but we still find the right thing.
85  %dst = call i8* @memchr(i8* %src, i32 119, i32 100)
86  store i8* %dst, i8** @chp
87  ret void
88}
89
90define void @test7() {
91; CHECK-LABEL: @test7
92; CHECK: store i8* null, i8** @chp, align 4
93; CHECK-NOT: call i8* @memchr
94; CHECK: ret void
95
96  %src = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
97; Overflow
98  %dst = call i8* @memchr(i8* %src, i32 120, i32 100)
99  store i8* %dst, i8** @chp
100  ret void
101}
102
103define void @test8() {
104; CHECK-LABEL: @test8
105; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hellonull, i32 0, i32 6)
106; CHECK-NOT: call i8* @memchr
107; CHECK: ret void
108
109  %str = getelementptr [14 x i8], [14 x i8]* @hellonull, i32 0, i32 0
110  %dst = call i8* @memchr(i8* %str, i32 119, i32 14)
111  store i8* %dst, i8** @chp
112  ret void
113}
114
115define void @test9() {
116; CHECK-LABEL: @test9
117; CHECK: store i8* getelementptr inbounds ([14 x i8], [14 x i8]* @hellonull, i32 0, i32 6)
118; CHECK-NOT: call i8* @memchr
119; CHECK: ret void
120
121  %str = getelementptr [14 x i8], [14 x i8]* @hellonull, i32 0, i32 2
122  %dst = call i8* @memchr(i8* %str, i32 119, i32 12)
123  store i8* %dst, i8** @chp
124  ret void
125}
126
127define void @test10() {
128; CHECK-LABEL: @test10
129; CHECK: store i8* null, i8** @chp, align 4
130; CHECK-NOT: call i8* @memchr
131; CHECK: ret void
132
133  %str = getelementptr [14 x i8], [14 x i8]* @hello, i32 0, i32 0
134  %dst = call i8* @memchr(i8* %str, i32 119, i32 6)
135  store i8* %dst, i8** @chp
136  ret void
137}
138
139; Check transformation memchr("\r\n", C, 2) != nullptr -> (C & 9216) != 0
140define i1 @test11(i32 %C) {
141; CHECK-LABEL: @test11
142; CHECK-NEXT: [[TRUNC:%.*]] = trunc i32 %C to i16
143; CHECK-NEXT: %memchr.bounds = icmp ult i16 [[TRUNC]], 16
144; CHECK-NEXT: [[SHL:%.*]] = shl i16 1, [[TRUNC]]
145; CHECK-NEXT: [[AND:%.*]] = and i16 [[SHL]], 9216
146; CHECK-NEXT: %memchr.bits = icmp ne i16 [[AND]], 0
147; CHECK-NEXT: %memchr = and i1 %memchr.bounds, %memchr.bits
148; CHECK-NEXT: ret i1 %memchr
149
150  %dst = call i8* @memchr(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @newlines, i64 0, i64 0), i32 %C, i32 2)
151  %cmp = icmp ne i8* %dst, null
152  ret i1 %cmp
153}
154
155; No 64 bits here
156define i1 @test12(i32 %C) {
157; CHECK-LABEL: @test12
158; CHECK-NEXT: %dst = call i8* @memchr(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @spaces, i32 0, i32 0), i32 %C, i32 3)
159; CHECK-NEXT: %cmp = icmp ne i8* %dst, null
160; CHECK-NEXT: ret i1 %cmp
161
162  %dst = call i8* @memchr(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @spaces, i64 0, i64 0), i32 %C, i32 3)
163  %cmp = icmp ne i8* %dst, null
164  ret i1 %cmp
165}
166
167define i1 @test13(i32 %C) {
168; CHECK-LABEL: @test13
169; CHECK-NEXT: %memchr.bounds = icmp ult i32 %C, 32
170; CHECK-NEXT: [[SHL:%.*]] = shl i32 1, %C
171; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], -2147483647
172; CHECK-NEXT: %memchr.bits = icmp ne i32 [[AND]], 0
173; CHECK-NEXT: %memchr = and i1 %memchr.bounds, %memchr.bits
174; CHECK-NEXT: ret i1 %memchr
175
176  %dst = call i8* @memchr(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @single, i64 0, i64 0), i32 %C, i32 2)
177  %cmp = icmp ne i8* %dst, null
178  ret i1 %cmp
179}
180
181define i1 @test14(i32 %C) {
182; CHECK-LABEL: @test14
183; CHECK-NEXT: icmp eq i32 %C, 31
184; CHECK-NEXT: ret
185
186  %dst = call i8* @memchr(i8* getelementptr inbounds ([2 x i8], [2 x i8]* @single, i64 0, i64 0), i32 %C, i32 1)
187  %cmp = icmp ne i8* %dst, null
188  ret i1 %cmp
189}
190
191define i1 @test15(i32 %C) {
192; CHECK-LABEL: @test15
193; CHECK-NEXT: %dst = call i8* @memchr(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @negative, i32 0, i32 0), i32 %C, i32 3)
194; CHECK-NEXT: %cmp = icmp ne i8* %dst, null
195; CHECK-NEXT: ret i1 %cmp
196
197  %dst = call i8* @memchr(i8* getelementptr inbounds ([3 x i8], [3 x i8]* @negative, i64 0, i64 0), i32 %C, i32 3)
198  %cmp = icmp ne i8* %dst, null
199  ret i1 %cmp
200}
201