1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt %s -instcombine -S | FileCheck %s
7 declare void @llvm.assume(i1)
9 ; Here we don't know that at least one of the values being added is non-zero
10 define i1 @t0_bad(i8 %base, i8 %offset) {
11 ; CHECK-LABEL: @t0_bad(
12 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]]
13 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
14 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
15 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
16 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
17 ; CHECK-NEXT: ret i1 [[R]]
19 %adjusted = add i8 %base, %offset
20 call void @use8(i8 %adjusted)
21 %not_null = icmp ne i8 %adjusted, 0
22 %no_underflow = icmp ult i8 %adjusted, %base
23 %r = and i1 %not_null, %no_underflow
27 ; Ok, base is non-zero.
28 define i1 @t1(i8 %base, i8 %offset) {
30 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
31 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
32 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
33 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
34 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[BASE]]
35 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
36 ; CHECK-NEXT: ret i1 [[TMP2]]
38 %cmp = icmp slt i8 %base, 0
39 call void @llvm.assume(i1 %cmp)
41 %adjusted = add i8 %base, %offset
42 call void @use8(i8 %adjusted)
43 %not_null = icmp ne i8 %adjusted, 0
44 %no_underflow = icmp ult i8 %adjusted, %base
45 %r = and i1 %not_null, %no_underflow
49 ; Ok, offset is non-zero.
50 define i1 @t2(i8 %base, i8 %offset) {
52 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[OFFSET:%.*]], 0
53 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
54 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET]]
55 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
56 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[OFFSET]]
57 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[BASE]]
58 ; CHECK-NEXT: ret i1 [[TMP2]]
60 %cmp = icmp slt i8 %offset, 0
61 call void @llvm.assume(i1 %cmp)
63 %adjusted = add i8 %base, %offset
64 call void @use8(i8 %adjusted)
65 %not_null = icmp ne i8 %adjusted, 0
66 %no_underflow = icmp ult i8 %adjusted, %base
67 %r = and i1 %not_null, %no_underflow
71 ; We need to produce extra instruction, so one of icmp's must go away.
72 define i1 @t3_oneuse0(i8 %base, i8 %offset) {
73 ; CHECK-LABEL: @t3_oneuse0(
74 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
75 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
76 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
77 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
78 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
79 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
80 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[BASE]]
81 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
82 ; CHECK-NEXT: ret i1 [[TMP2]]
84 %cmp = icmp slt i8 %base, 0
85 call void @llvm.assume(i1 %cmp)
87 %adjusted = add i8 %base, %offset
88 call void @use8(i8 %adjusted)
89 %not_null = icmp ne i8 %adjusted, 0
90 call void @use1(i1 %not_null)
91 %no_underflow = icmp ult i8 %adjusted, %base
92 %r = and i1 %not_null, %no_underflow
95 define i1 @t4_oneuse1(i8 %base, i8 %offset) {
96 ; CHECK-LABEL: @t4_oneuse1(
97 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
98 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
99 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
100 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
101 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
102 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
103 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[BASE]]
104 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
105 ; CHECK-NEXT: ret i1 [[TMP2]]
107 %cmp = icmp slt i8 %base, 0
108 call void @llvm.assume(i1 %cmp)
110 %adjusted = add i8 %base, %offset
111 call void @use8(i8 %adjusted)
112 %not_null = icmp ne i8 %adjusted, 0
113 %no_underflow = icmp ult i8 %adjusted, %base
114 call void @use1(i1 %no_underflow)
115 %r = and i1 %not_null, %no_underflow
118 define i1 @t5_oneuse2_bad(i8 %base, i8 %offset) {
119 ; CHECK-LABEL: @t5_oneuse2_bad(
120 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
121 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
122 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
123 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
124 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
125 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
126 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
127 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
128 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
129 ; CHECK-NEXT: ret i1 [[R]]
131 %cmp = icmp slt i8 %base, 0
132 call void @llvm.assume(i1 %cmp)
134 %adjusted = add i8 %base, %offset
135 call void @use8(i8 %adjusted)
136 %not_null = icmp ne i8 %adjusted, 0
137 call void @use1(i1 %not_null)
138 %no_underflow = icmp ult i8 %adjusted, %base
139 call void @use1(i1 %no_underflow)
140 %r = and i1 %not_null, %no_underflow
144 define i1 @t6_commutativity0(i8 %base, i8 %offset) {
145 ; CHECK-LABEL: @t6_commutativity0(
146 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
147 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
148 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
149 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
150 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[BASE]]
151 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
152 ; CHECK-NEXT: ret i1 [[TMP2]]
154 %cmp = icmp slt i8 %base, 0
155 call void @llvm.assume(i1 %cmp)
157 %adjusted = add i8 %base, %offset
158 call void @use8(i8 %adjusted)
159 %not_null = icmp ne i8 %adjusted, 0
160 %no_underflow = icmp ult i8 %adjusted, %base
161 %r = and i1 %no_underflow, %not_null ; swapped
164 define i1 @t7_commutativity1(i8 %base, i8 %offset) {
165 ; CHECK-LABEL: @t7_commutativity1(
166 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
167 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
168 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
169 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
170 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[BASE]]
171 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
172 ; CHECK-NEXT: ret i1 [[TMP2]]
174 %cmp = icmp slt i8 %base, 0
175 call void @llvm.assume(i1 %cmp)
177 %adjusted = add i8 %base, %offset
178 call void @use8(i8 %adjusted)
179 %not_null = icmp ne i8 %adjusted, 0
180 %no_underflow = icmp ugt i8 %base, %adjusted ; swapped
181 %r = and i1 %not_null, %no_underflow
184 define i1 @t7_commutativity3(i8 %base, i8 %offset) {
185 ; CHECK-LABEL: @t7_commutativity3(
186 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
187 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
188 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
189 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
190 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[BASE]]
191 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
192 ; CHECK-NEXT: ret i1 [[TMP2]]
194 %cmp = icmp slt i8 %base, 0
195 call void @llvm.assume(i1 %cmp)
197 %adjusted = add i8 %base, %offset
198 call void @use8(i8 %adjusted)
199 %not_null = icmp ne i8 %adjusted, 0
200 %no_underflow = icmp ugt i8 %base, %adjusted ; swapped
201 %r = and i1 %no_underflow, %not_null ; swapped
205 ; We could have the opposite question, did we get null or overflow happened?
206 define i1 @t8(i8 %base, i8 %offset) {
208 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
209 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
210 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
211 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
212 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[BASE]]
213 ; CHECK-NEXT: [[TMP2:%.*]] = icmp uge i8 [[TMP1]], [[OFFSET]]
214 ; CHECK-NEXT: ret i1 [[TMP2]]
216 %cmp = icmp slt i8 %base, 0
217 call void @llvm.assume(i1 %cmp)
219 %adjusted = add i8 %base, %offset
220 call void @use8(i8 %adjusted)
221 %not_null = icmp eq i8 %adjusted, 0
222 %no_underflow = icmp uge i8 %adjusted, %base
223 %r = or i1 %not_null, %no_underflow
227 ; The comparison can be with any of the values being added.
228 define i1 @t9(i8 %base, i8 %offset) {
230 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
231 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
232 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
233 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
234 ; CHECK-NEXT: [[TMP1:%.*]] = sub i8 0, [[BASE]]
235 ; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i8 [[TMP1]], [[OFFSET]]
236 ; CHECK-NEXT: ret i1 [[TMP2]]
238 %cmp = icmp slt i8 %base, 0
239 call void @llvm.assume(i1 %cmp)
241 %adjusted = add i8 %base, %offset
242 call void @use8(i8 %adjusted)
243 %not_null = icmp ne i8 %adjusted, 0
244 %no_underflow = icmp ult i8 %adjusted, %offset
245 %r = and i1 %not_null, %no_underflow