Skip to content

Commit 86ef039

Browse files
authored
[InstCombine] Simplify compare abs(X) and X. (#76385)
fix #72653 proof: https://alive2.llvm.org/ce/z/LZzZaj
1 parent 190a75b commit 86ef039

File tree

2 files changed

+270
-0
lines changed

2 files changed

+270
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6868,6 +6868,57 @@ Instruction *InstCombinerImpl::foldICmpCommutative(ICmpInst::Predicate Pred,
68686868
return foldICmpAddOpConst(X, *C, Pred);
68696869
}
68706870

6871+
// abs(X) >= X --> true
6872+
// abs(X) u<= X --> true
6873+
// abs(X) < X --> false
6874+
// abs(X) u> X --> false
6875+
// abs(X) u>= X --> IsIntMinPosion ? `X > -1`: `X u<= INTMIN`
6876+
// abs(X) <= X --> IsIntMinPosion ? `X > -1`: `X u<= INTMIN`
6877+
// abs(X) == X --> IsIntMinPosion ? `X > -1`: `X u<= INTMIN`
6878+
// abs(X) u< X --> IsIntMinPosion ? `X < 0` : `X > INTMIN`
6879+
// abs(X) > X --> IsIntMinPosion ? `X < 0` : `X > INTMIN`
6880+
// abs(X) != X --> IsIntMinPosion ? `X < 0` : `X > INTMIN`
6881+
{
6882+
Value *X;
6883+
Constant *C;
6884+
if (match(Op0, m_Intrinsic<Intrinsic::abs>(m_Value(X), m_Constant(C))) &&
6885+
match(Op1, m_Specific(X))) {
6886+
Value *NullValue = Constant::getNullValue(X->getType());
6887+
Value *AllOnesValue = Constant::getAllOnesValue(X->getType());
6888+
const APInt SMin =
6889+
APInt::getSignedMinValue(X->getType()->getScalarSizeInBits());
6890+
bool IsIntMinPosion = C->isAllOnesValue();
6891+
switch (Pred) {
6892+
case CmpInst::ICMP_ULE:
6893+
case CmpInst::ICMP_SGE:
6894+
return replaceInstUsesWith(CxtI, ConstantInt::getTrue(CxtI.getType()));
6895+
case CmpInst::ICMP_UGT:
6896+
case CmpInst::ICMP_SLT:
6897+
return replaceInstUsesWith(CxtI, ConstantInt::getFalse(CxtI.getType()));
6898+
case CmpInst::ICMP_UGE:
6899+
case CmpInst::ICMP_SLE:
6900+
case CmpInst::ICMP_EQ: {
6901+
return replaceInstUsesWith(
6902+
CxtI, IsIntMinPosion
6903+
? Builder.CreateICmpSGT(X, AllOnesValue)
6904+
: Builder.CreateICmpULT(
6905+
X, ConstantInt::get(X->getType(), SMin + 1)));
6906+
}
6907+
case CmpInst::ICMP_ULT:
6908+
case CmpInst::ICMP_SGT:
6909+
case CmpInst::ICMP_NE: {
6910+
return replaceInstUsesWith(
6911+
CxtI, IsIntMinPosion
6912+
? Builder.CreateICmpSLT(X, NullValue)
6913+
: Builder.CreateICmpUGT(
6914+
X, ConstantInt::get(X->getType(), SMin)));
6915+
}
6916+
default:
6917+
llvm_unreachable("Invalid predicate!");
6918+
}
6919+
}
6920+
}
6921+
68716922
return nullptr;
68726923
}
68736924

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3+
4+
declare i4 @llvm.abs.i4(i4, i1)
5+
6+
define i1 @icmp_sge_abs(i4 %arg) {
7+
; CHECK-LABEL: @icmp_sge_abs(
8+
; CHECK-NEXT: ret i1 true
9+
;
10+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
11+
%cmp = icmp sge i4 %abs, %arg
12+
ret i1 %cmp
13+
}
14+
15+
define i1 @icmp_sge_abs_false(i4 %arg) {
16+
; CHECK-LABEL: @icmp_sge_abs_false(
17+
; CHECK-NEXT: ret i1 true
18+
;
19+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
20+
%cmp = icmp sge i4 %abs, %arg
21+
ret i1 %cmp
22+
}
23+
24+
define i1 @icmp_eq_abs(i4 %arg) {
25+
; CHECK-LABEL: @icmp_eq_abs(
26+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i4 [[ARG:%.*]], -1
27+
; CHECK-NEXT: ret i1 [[CMP]]
28+
;
29+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
30+
%cmp = icmp eq i4 %abs, %arg
31+
ret i1 %cmp
32+
}
33+
34+
define i1 @icmp_eq_abs_false(i4 %arg) {
35+
; CHECK-LABEL: @icmp_eq_abs_false(
36+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i4 [[ARG:%.*]], -7
37+
; CHECK-NEXT: ret i1 [[CMP]]
38+
;
39+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
40+
%cmp = icmp eq i4 %abs, %arg
41+
ret i1 %cmp
42+
}
43+
44+
define i1 @icmp_ne_abs(i4 %arg) {
45+
; CHECK-LABEL: @icmp_ne_abs(
46+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i4 [[ARG:%.*]], 0
47+
; CHECK-NEXT: ret i1 [[CMP]]
48+
;
49+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
50+
%cmp = icmp ne i4 %abs, %arg
51+
ret i1 %cmp
52+
}
53+
54+
define i1 @icmp_ne_abs_false(i4 %arg) {
55+
; CHECK-LABEL: @icmp_ne_abs_false(
56+
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i4 [[ARG:%.*]], -8
57+
; CHECK-NEXT: ret i1 [[CMP]]
58+
;
59+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
60+
%cmp = icmp ne i4 %abs, %arg
61+
ret i1 %cmp
62+
}
63+
64+
define i1 @icmp_sle_abs(i4 %arg) {
65+
; CHECK-LABEL: @icmp_sle_abs(
66+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i4 [[ARG:%.*]], -1
67+
; CHECK-NEXT: ret i1 [[CMP]]
68+
;
69+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
70+
%cmp = icmp sle i4 %abs, %arg
71+
ret i1 %cmp
72+
}
73+
74+
define i1 @icmp_sle_abs_false(i4 %arg) {
75+
; CHECK-LABEL: @icmp_sle_abs_false(
76+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i4 [[ARG:%.*]], -7
77+
; CHECK-NEXT: ret i1 [[CMP]]
78+
;
79+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
80+
%cmp = icmp sle i4 %abs, %arg
81+
ret i1 %cmp
82+
}
83+
84+
define i1 @icmp_slt_abs(i4 %arg) {
85+
; CHECK-LABEL: @icmp_slt_abs(
86+
; CHECK-NEXT: ret i1 false
87+
;
88+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
89+
%cmp = icmp slt i4 %abs, %arg
90+
ret i1 %cmp
91+
}
92+
93+
define i1 @icmp_slt_abs_false(i4 %arg) {
94+
; CHECK-LABEL: @icmp_slt_abs_false(
95+
; CHECK-NEXT: ret i1 false
96+
;
97+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
98+
%cmp = icmp slt i4 %abs, %arg
99+
ret i1 %cmp
100+
}
101+
102+
define i1 @icmp_sgt_abs(i4 %arg) {
103+
; CHECK-LABEL: @icmp_sgt_abs(
104+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i4 [[ARG:%.*]], 0
105+
; CHECK-NEXT: ret i1 [[CMP]]
106+
;
107+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
108+
%cmp = icmp sgt i4 %abs, %arg
109+
ret i1 %cmp
110+
}
111+
112+
define i1 @icmp_sgt_abs_false(i4 %arg) {
113+
; CHECK-LABEL: @icmp_sgt_abs_false(
114+
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i4 [[ARG:%.*]], -8
115+
; CHECK-NEXT: ret i1 [[CMP]]
116+
;
117+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
118+
%cmp = icmp sgt i4 %abs, %arg
119+
ret i1 %cmp
120+
}
121+
122+
define i1 @icmp_ugt_abs(i4 %arg) {
123+
; CHECK-LABEL: @icmp_ugt_abs(
124+
; CHECK-NEXT: ret i1 false
125+
;
126+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
127+
%cmp = icmp ugt i4 %abs, %arg
128+
ret i1 %cmp
129+
}
130+
131+
define i1 @icmp_ugt_abs_false(i4 %arg) {
132+
; CHECK-LABEL: @icmp_ugt_abs_false(
133+
; CHECK-NEXT: ret i1 false
134+
;
135+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
136+
%cmp = icmp ugt i4 %abs, %arg
137+
ret i1 %cmp
138+
}
139+
140+
define i1 @icmp_uge_abs(i4 %arg) {
141+
; CHECK-LABEL: @icmp_uge_abs(
142+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i4 [[ARG:%.*]], -1
143+
; CHECK-NEXT: ret i1 [[CMP]]
144+
;
145+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
146+
%cmp = icmp uge i4 %abs, %arg
147+
ret i1 %cmp
148+
}
149+
150+
define i1 @icmp_uge_abs_false(i4 %arg) {
151+
; CHECK-LABEL: @icmp_uge_abs_false(
152+
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i4 [[ARG:%.*]], -7
153+
; CHECK-NEXT: ret i1 [[CMP]]
154+
;
155+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
156+
%cmp = icmp uge i4 %abs, %arg
157+
ret i1 %cmp
158+
}
159+
160+
define i1 @icmp_ule_abs(i4 %arg) {
161+
; CHECK-LABEL: @icmp_ule_abs(
162+
; CHECK-NEXT: ret i1 true
163+
;
164+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
165+
%cmp = icmp ule i4 %abs, %arg
166+
ret i1 %cmp
167+
}
168+
169+
define i1 @icmp_ule_abs_false(i4 %arg) {
170+
; CHECK-LABEL: @icmp_ule_abs_false(
171+
; CHECK-NEXT: ret i1 true
172+
;
173+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
174+
%cmp = icmp ule i4 %abs, %arg
175+
ret i1 %cmp
176+
}
177+
178+
define i1 @icmp_ult_abs(i4 %arg) {
179+
; CHECK-LABEL: @icmp_ult_abs(
180+
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i4 [[ARG:%.*]], 0
181+
; CHECK-NEXT: ret i1 [[CMP]]
182+
;
183+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
184+
%cmp = icmp ult i4 %abs, %arg
185+
ret i1 %cmp
186+
}
187+
188+
define i1 @icmp_ult_abs_false(i4 %arg) {
189+
; CHECK-LABEL: @icmp_ult_abs_false(
190+
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i4 [[ARG:%.*]], -8
191+
; CHECK-NEXT: ret i1 [[CMP]]
192+
;
193+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 false)
194+
%cmp = icmp ult i4 %abs, %arg
195+
ret i1 %cmp
196+
}
197+
198+
define i1 @icmp_sge_abs2(i4 %arg) {
199+
; CHECK-LABEL: @icmp_sge_abs2(
200+
; CHECK-NEXT: [[X:%.*]] = mul i4 [[ARG:%.*]], [[ARG]]
201+
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i4 [[X]], -1
202+
; CHECK-NEXT: ret i1 [[CMP]]
203+
;
204+
%x = mul i4 %arg, %arg ; thwart complexity-based canonicalization
205+
%abs = call i4 @llvm.abs.i4(i4 %x, i1 true)
206+
%cmp = icmp sge i4 %x, %abs
207+
ret i1 %cmp
208+
}
209+
210+
define i1 @icmp_sge_abs_mismatched_op(i4 %arg, i4 %arg2) {
211+
; CHECK-LABEL: @icmp_sge_abs_mismatched_op(
212+
; CHECK-NEXT: [[ABS:%.*]] = call i4 @llvm.abs.i4(i4 [[ARG:%.*]], i1 true)
213+
; CHECK-NEXT: [[CMP:%.*]] = icmp sge i4 [[ABS]], [[ARG2:%.*]]
214+
; CHECK-NEXT: ret i1 [[CMP]]
215+
;
216+
%abs = call i4 @llvm.abs.i4(i4 %arg, i1 true)
217+
%cmp = icmp sge i4 %abs, %arg2
218+
ret i1 %cmp
219+
}

0 commit comments

Comments
 (0)