1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt %s -instcombine -S | FileCheck %s
4 ; Here we add unsigned two values, check that addition did not underflow AND
5 ; that the result is non-zero. This can be simplified just to a comparison
6 ; between the base and negated offset.
10 declare void @use1(i1)
11 declare void @llvm.assume(i1)
13 ; Here we don't know that at least one of the values being added is non-zero
14 define i1 @t0_bad(i8 %base, i8 %offset) {
15 ; CHECK-LABEL: @t0_bad(
16 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET:%.*]]
17 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
18 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
19 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
20 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
21 ; CHECK-NEXT: ret i1 [[R]]
23 %adjusted = add i8 %base, %offset
24 call void @use8(i8 %adjusted)
25 %not_null = icmp ne i8 %adjusted, 0
26 %no_underflow = icmp ult i8 %adjusted, %base
27 %r = and i1 %not_null, %no_underflow
31 ; Ok, base is non-zero.
32 define i1 @t1(i8 %base, i8 %offset) {
34 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
35 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
36 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
37 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
38 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
39 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
40 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
41 ; CHECK-NEXT: ret i1 [[R]]
43 %cmp = icmp slt i8 %base, 0
44 call void @llvm.assume(i1 %cmp)
46 %adjusted = add i8 %base, %offset
47 call void @use8(i8 %adjusted)
48 %not_null = icmp ne i8 %adjusted, 0
49 %no_underflow = icmp ult i8 %adjusted, %base
50 %r = and i1 %not_null, %no_underflow
54 ; Ok, offset is non-zero.
55 define i1 @t2(i8 %base, i8 %offset) {
57 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[OFFSET:%.*]], 0
58 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
59 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET]]
60 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
61 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
62 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
63 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
64 ; CHECK-NEXT: ret i1 [[R]]
66 %cmp = icmp slt i8 %offset, 0
67 call void @llvm.assume(i1 %cmp)
69 %adjusted = add i8 %base, %offset
70 call void @use8(i8 %adjusted)
71 %not_null = icmp ne i8 %adjusted, 0
72 %no_underflow = icmp ult i8 %adjusted, %base
73 %r = and i1 %not_null, %no_underflow
77 ; We need to produce extra instruction, so one of icmp's must go away.
78 define i1 @t3_oneuse0(i8 %base, i8 %offset) {
79 ; CHECK-LABEL: @t3_oneuse0(
80 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
81 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
82 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
83 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
84 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
85 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
86 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
87 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
88 ; CHECK-NEXT: ret i1 [[R]]
90 %cmp = icmp slt i8 %base, 0
91 call void @llvm.assume(i1 %cmp)
93 %adjusted = add i8 %base, %offset
94 call void @use8(i8 %adjusted)
95 %not_null = icmp ne i8 %adjusted, 0
96 call void @use1(i1 %not_null)
97 %no_underflow = icmp ult i8 %adjusted, %base
98 %r = and i1 %not_null, %no_underflow
101 define i1 @t4_oneuse1(i8 %base, i8 %offset) {
102 ; CHECK-LABEL: @t4_oneuse1(
103 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
104 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
105 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
106 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
107 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
108 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
109 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
110 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
111 ; CHECK-NEXT: ret i1 [[R]]
113 %cmp = icmp slt i8 %base, 0
114 call void @llvm.assume(i1 %cmp)
116 %adjusted = add i8 %base, %offset
117 call void @use8(i8 %adjusted)
118 %not_null = icmp ne i8 %adjusted, 0
119 %no_underflow = icmp ult i8 %adjusted, %base
120 call void @use1(i1 %no_underflow)
121 %r = and i1 %not_null, %no_underflow
124 define i1 @t5_oneuse2_bad(i8 %base, i8 %offset) {
125 ; CHECK-LABEL: @t5_oneuse2_bad(
126 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
127 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
128 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
129 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
130 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
131 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
132 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
133 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
134 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
135 ; CHECK-NEXT: ret i1 [[R]]
137 %cmp = icmp slt i8 %base, 0
138 call void @llvm.assume(i1 %cmp)
140 %adjusted = add i8 %base, %offset
141 call void @use8(i8 %adjusted)
142 %not_null = icmp ne i8 %adjusted, 0
143 call void @use1(i1 %not_null)
144 %no_underflow = icmp ult i8 %adjusted, %base
145 call void @use1(i1 %no_underflow)
146 %r = and i1 %not_null, %no_underflow
150 define i1 @t6_commutativity0(i8 %base, i8 %offset) {
151 ; CHECK-LABEL: @t6_commutativity0(
152 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
153 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
154 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
155 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
156 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
157 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]]
158 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]]
159 ; CHECK-NEXT: ret i1 [[R]]
161 %cmp = icmp slt i8 %base, 0
162 call void @llvm.assume(i1 %cmp)
164 %adjusted = add i8 %base, %offset
165 call void @use8(i8 %adjusted)
166 %not_null = icmp ne i8 %adjusted, 0
167 %no_underflow = icmp ult i8 %adjusted, %base
168 %r = and i1 %no_underflow, %not_null ; swapped
171 define i1 @t7_commutativity1(i8 %base, i8 %offset) {
172 ; CHECK-LABEL: @t7_commutativity1(
173 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
174 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
175 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
176 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
177 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
178 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]]
179 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
180 ; CHECK-NEXT: ret i1 [[R]]
182 %cmp = icmp slt i8 %base, 0
183 call void @llvm.assume(i1 %cmp)
185 %adjusted = add i8 %base, %offset
186 call void @use8(i8 %adjusted)
187 %not_null = icmp ne i8 %adjusted, 0
188 %no_underflow = icmp uge i8 %base, %adjusted ; swapped
189 %r = and i1 %not_null, %no_underflow
192 define i1 @t7_commutativity3(i8 %base, i8 %offset) {
193 ; CHECK-LABEL: @t7_commutativity3(
194 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
195 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
196 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
197 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
198 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
199 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[ADJUSTED]], [[BASE]]
200 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NO_UNDERFLOW]], [[NOT_NULL]]
201 ; CHECK-NEXT: ret i1 [[R]]
203 %cmp = icmp slt i8 %base, 0
204 call void @llvm.assume(i1 %cmp)
206 %adjusted = add i8 %base, %offset
207 call void @use8(i8 %adjusted)
208 %not_null = icmp ne i8 %adjusted, 0
209 %no_underflow = icmp uge i8 %base, %adjusted ; swapped
210 %r = and i1 %no_underflow, %not_null ; swapped
214 ; We could have the opposite question, did we get null or overflow happened?
215 define i1 @t8(i8 %base, i8 %offset) {
217 ; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[BASE:%.*]], 0
218 ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]])
219 ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]]
220 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
221 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
222 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[ADJUSTED]], [[BASE]]
223 ; CHECK-NEXT: [[R:%.*]] = or i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
224 ; CHECK-NEXT: ret i1 [[R]]
226 %cmp = icmp slt i8 %base, 0
227 call void @llvm.assume(i1 %cmp)
229 %adjusted = add i8 %base, %offset
230 call void @use8(i8 %adjusted)
231 %not_null = icmp eq i8 %adjusted, 0
232 %no_underflow = icmp uge i8 %adjusted, %base
233 %r = or i1 %not_null, %no_underflow