[SimplifyCFG] FoldTwoEntryPHINode(): consider *total* speculation cost, not per-BB...
[llvm-complete.git] / test / Transforms / InstCombine / result-of-add-of-negative-is-non-zero-and-no-underflow.ll
blob1a376c42648e0f6b96cb0c71f87762658ff23814
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.
8 declare void @use8(i8)
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
28   ret i1 %r
31 ; Ok, base is non-zero.
32 define i1 @t1(i8 %base, i8 %offset) {
33 ; CHECK-LABEL: @t1(
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
51   ret i1 %r
54 ; Ok, offset is non-zero.
55 define i1 @t2(i8 %base, i8 %offset) {
56 ; CHECK-LABEL: @t2(
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
74   ret i1 %r
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
99   ret i1 %r
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
122   ret i1 %r
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
147   ret i1 %r
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
169   ret i1 %r
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
190   ret i1 %r
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
211   ret i1 %r
214 ; We could have the opposite question, did we get null or overflow happened?
215 define i1 @t8(i8 %base, i8 %offset) {
216 ; CHECK-LABEL: @t8(
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
234   ret i1 %r