[InstCombine] Signed saturation patterns
[llvm-complete.git] / test / Transforms / InstCombine / result-of-add-of-negative-is-non-zero-and-no-underflow.ll
blob5b48b5e30ff45eae1cb990757eb0ddac8ab45449
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt %s -instcombine -S | FileCheck %s
4 declare void @use8(i8)
6 declare void @use1(i1)
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
24   ret i1 %r
27 ; Ok, base is non-zero.
28 define i1 @t1(i8 %base, i8 %offset) {
29 ; CHECK-LABEL: @t1(
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
46   ret i1 %r
49 ; Ok, offset is non-zero.
50 define i1 @t2(i8 %base, i8 %offset) {
51 ; CHECK-LABEL: @t2(
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
68   ret i1 %r
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
93   ret i1 %r
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
116   ret i1 %r
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
141   ret i1 %r
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
162   ret i1 %r
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
182   ret i1 %r
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
202   ret i1 %r
205 ; We could have the opposite question, did we get null or overflow happened?
206 define i1 @t8(i8 %base, i8 %offset) {
207 ; CHECK-LABEL: @t8(
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
224   ret i1 %r
227 ; The comparison can be with any of the values being added.
228 define i1 @t9(i8 %base, i8 %offset) {
229 ; CHECK-LABEL: @t9(
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
246   ret i1 %r