1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt %s -instsimplify -S | FileCheck %s
4 ; Here we subtract two values, check that subtraction did not overflow AND
5 ; that the result is non-zero. This can be simplified just to a comparison
6 ; between the base and offset.
9 declare void @use64(i64)
10 declare void @use1(i1)
12 declare void @llvm.assume(i1)
14 ; If we are checking that we either did not get null or got no overflow,
15 ; this is tautological and is always true.
17 define i1 @t1(i8 %base, i8 %offset) {
19 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
20 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
21 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]]
22 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
23 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
24 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
25 ; CHECK-NEXT: ret i1 true
27 %adjusted = sub i8 %base, %offset
28 call void @use8(i8 %adjusted)
29 %no_underflow = icmp uge i8 %base, %offset
30 call void @use1(i1 %no_underflow)
31 %not_null = icmp ne i8 %adjusted, 0
32 call void @use1(i1 %not_null)
33 %r = or i1 %not_null, %no_underflow
36 define i1 @t1_strict_bad(i8 %base, i8 %offset) {
37 ; CHECK-LABEL: @t1_strict_bad(
38 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
39 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
40 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
41 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
42 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
43 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
44 ; CHECK-NEXT: [[R:%.*]] = or i1 [[NOT_NULL]], [[NO_UNDERFLOW]]
45 ; CHECK-NEXT: ret i1 [[R]]
47 %adjusted = sub i8 %base, %offset
48 call void @use8(i8 %adjusted)
49 %no_underflow = icmp ugt i8 %base, %offset ; but not for non-strict predicate
50 call void @use1(i1 %no_underflow)
51 %not_null = icmp ne i8 %adjusted, 0
52 call void @use1(i1 %not_null)
53 %r = or i1 %not_null, %no_underflow
56 define i1 @t1_commutativity(i8 %base, i8 %offset) {
57 ; CHECK-LABEL: @t1_commutativity(
58 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
59 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
60 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]]
61 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
62 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
63 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
64 ; CHECK-NEXT: ret i1 true
66 %adjusted = sub i8 %base, %offset
67 call void @use8(i8 %adjusted)
68 %no_underflow = icmp ule i8 %offset, %base
69 call void @use1(i1 %no_underflow)
70 %not_null = icmp ne i8 %adjusted, 0
71 call void @use1(i1 %not_null)
72 %r = or i1 %not_null, %no_underflow
76 ; Likewise, if we are checking that we both got null and overflow happened,
77 ; it makes no sense and is always false.
79 define i1 @t2(i8 %base, i8 %offset) {
81 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
82 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
83 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]]
84 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
85 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
86 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
87 ; CHECK-NEXT: ret i1 false
89 %adjusted = sub i8 %base, %offset
90 call void @use8(i8 %adjusted)
91 %underflow = icmp ult i8 %base, %offset
92 call void @use1(i1 %underflow)
93 %null = icmp eq i8 %adjusted, 0
94 call void @use1(i1 %null)
95 %r = and i1 %null, %underflow
98 define i1 @t2_nonstrict_bad(i8 %base, i8 %offset) {
99 ; CHECK-LABEL: @t2_nonstrict_bad(
100 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
101 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
102 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp uge i8 [[ADJUSTED]], [[BASE]]
103 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
104 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
105 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
106 ; CHECK-NEXT: [[R:%.*]] = and i1 [[NULL]], [[UNDERFLOW]]
107 ; CHECK-NEXT: ret i1 [[R]]
109 %adjusted = sub i8 %base, %offset
110 call void @use8(i8 %adjusted)
111 %underflow = icmp uge i8 %adjusted, %base ; but not for non-strict predicate
112 call void @use1(i1 %underflow)
113 %null = icmp eq i8 %adjusted, 0
114 call void @use1(i1 %null)
115 %r = and i1 %null, %underflow
118 define i1 @t2_commutativity(i8 %base, i8 %offset) {
119 ; CHECK-LABEL: @t2_commutativity(
120 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
121 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
122 ; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ugt i8 [[OFFSET]], [[BASE]]
123 ; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]])
124 ; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
125 ; CHECK-NEXT: call void @use1(i1 [[NULL]])
126 ; CHECK-NEXT: ret i1 false
128 %adjusted = sub i8 %base, %offset
129 call void @use8(i8 %adjusted)
130 %underflow = icmp ugt i8 %offset, %base
131 call void @use1(i1 %underflow)
132 %null = icmp eq i8 %adjusted, 0
133 call void @use1(i1 %null)
134 %r = and i1 %null, %underflow
138 ; Overflow OR not zero => always true
139 define i1 @t3(i8 %base, i8 %offset) {
141 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
142 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
143 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]]
144 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
145 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0
146 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
147 ; CHECK-NEXT: ret i1 true
149 %adjusted = sub i8 %base, %offset
150 call void @use8(i8 %adjusted)
151 %no_underflow = icmp ule i8 %base, %offset
152 call void @use1(i1 %no_underflow)
153 %not_null = icmp ne i8 %adjusted, 0
154 call void @use1(i1 %not_null)
155 %r = or i1 %not_null, %no_underflow
159 ; No overflow and zero => always false
160 define i1 @t4(i8 %base, i8 %offset) {
162 ; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]]
163 ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]])
164 ; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]]
165 ; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]])
166 ; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0
167 ; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]])
168 ; CHECK-NEXT: ret i1 false
170 %adjusted = sub i8 %base, %offset
171 call void @use8(i8 %adjusted)
172 %no_underflow = icmp ugt i8 %base, %offset
173 call void @use1(i1 %no_underflow)
174 %not_null = icmp eq i8 %adjusted, 0
175 call void @use1(i1 %not_null)
176 %r = and i1 %not_null, %no_underflow