Skip to content

Commit de41081

Browse files
committed
ValueTracking: teach implied-cond about samesign
isImpliedCondition benefits little from the icmp samesign feature: the only routine that can use this information is isImpliedCondICmps when it is matching against signed predicates, since icmp samesign is already canonicalized with an unsigned predicate. Add this support.
1 parent 37feced commit de41081

File tree

2 files changed

+220
-2
lines changed

2 files changed

+220
-2
lines changed

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9268,6 +9268,7 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
92689268
// case, invert the predicate to make it so.
92699269
CmpInst::Predicate LPred =
92709270
LHSIsTrue ? LHS->getPredicate() : LHS->getInversePredicate();
9271+
bool LHasSameSign = LHS->hasSameSign();
92719272

92729273
// We can have non-canonical operands, so try to normalize any common operand
92739274
// to L0/R0.
@@ -9321,7 +9322,8 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
93219322
// must be positive if X >= Y and no overflow".
93229323
// Take SGT as an example: L0:x > L1:y and C >= 0
93239324
// ==> R0:(x -nsw y) < R1:(-C) is false
9324-
if ((LPred == ICmpInst::ICMP_SGT || LPred == ICmpInst::ICMP_SGE) &&
9325+
if ((ICmpInst::isSigned(LPred) || LHasSameSign) &&
9326+
(ICmpInst::isGE(LPred) || ICmpInst::isGT(LPred)) &&
93259327
match(R0, m_NSWSub(m_Specific(L0), m_Specific(L1)))) {
93269328
if (match(R1, m_NonPositive()) &&
93279329
isImpliedCondMatchingOperands(LPred, RPred) == false)
@@ -9330,7 +9332,8 @@ static std::optional<bool> isImpliedCondICmps(const ICmpInst *LHS,
93309332

93319333
// Take SLT as an example: L0:x < L1:y and C <= 0
93329334
// ==> R0:(x -nsw y) < R1:(-C) is true
9333-
if ((LPred == ICmpInst::ICMP_SLT || LPred == ICmpInst::ICMP_SLE) &&
9335+
if ((ICmpInst::isSigned(LPred) || LHasSameSign) &&
9336+
(ICmpInst::isLE(LPred) || ICmpInst::isLT(LPred)) &&
93349337
match(R0, m_NSWSub(m_Specific(L0), m_Specific(L1)))) {
93359338
if (match(R1, m_NonNegative()) &&
93369339
isImpliedCondMatchingOperands(LPred, RPred) == true)
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
2+
; RUN: opt -passes=instsimplify -S %s | FileCheck %s
3+
4+
define i32 @gt_sub_nsw(i32 %x, i32 %y) {
5+
; CHECK-LABEL: define i32 @gt_sub_nsw(
6+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
7+
; CHECK-NEXT: [[ENTRY:.*:]]
8+
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i32 [[X]], [[Y]]
9+
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
10+
; CHECK: [[COND_TRUE]]:
11+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
12+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], 1
13+
; CHECK-NEXT: ret i32 [[ADD]]
14+
; CHECK: [[COND_END]]:
15+
; CHECK-NEXT: ret i32 0
16+
;
17+
entry:
18+
%cmp = icmp samesign ugt i32 %x, %y ; x>y ? abs (x-y+1): 0
19+
br i1 %cmp, label %cond.true, label %cond.end
20+
21+
cond.true: ; preds = %entry
22+
%sub = sub nsw i32 %x, %y
23+
%add = add nsw i32 %sub, 1
24+
%neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
25+
%abscond = icmp samesign ult i32 %sub, -1
26+
%abs = select i1 %abscond, i32 %neg, i32 %add
27+
ret i32 %abs
28+
29+
cond.end: ; preds = %entry, %cond.true
30+
ret i32 0
31+
}
32+
33+
define i32 @ge_sub_nsw(i32 %x, i32 %y) {
34+
; CHECK-LABEL: define i32 @ge_sub_nsw(
35+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
36+
; CHECK-NEXT: [[ENTRY:.*:]]
37+
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign uge i32 [[X]], [[Y]]
38+
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
39+
; CHECK: [[COND_TRUE]]:
40+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
41+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], 1
42+
; CHECK-NEXT: ret i32 [[ADD]]
43+
; CHECK: [[COND_END]]:
44+
; CHECK-NEXT: ret i32 0
45+
;
46+
entry:
47+
%cmp = icmp samesign uge i32 %x, %y ; x>=y ? abs (x-y+1): 0
48+
br i1 %cmp, label %cond.true, label %cond.end
49+
50+
cond.true: ; preds = %entry
51+
%sub = sub nsw i32 %x, %y
52+
%add = add nsw i32 %sub, 1
53+
%neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
54+
%abscond = icmp samesign ult i32 %sub, -1
55+
%abs = select i1 %abscond, i32 %neg, i32 %add
56+
ret i32 %abs
57+
58+
cond.end: ; preds = %entry, %cond.true
59+
ret i32 0
60+
}
61+
62+
define i8 @gt_sub_no_nsw(i8 %x, i8 %y) {
63+
; CHECK-LABEL: define i8 @gt_sub_no_nsw(
64+
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
65+
; CHECK-NEXT: [[ENTRY:.*:]]
66+
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i8 [[X]], [[Y]]
67+
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
68+
; CHECK: [[COND_TRUE]]:
69+
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
70+
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[SUB]], 1
71+
; CHECK-NEXT: [[NEG:%.*]] = xor i8 [[SUB]], -1
72+
; CHECK-NEXT: [[ABSCOND:%.*]] = icmp samesign ult i8 [[SUB]], -1
73+
; CHECK-NEXT: [[ABS:%.*]] = select i1 [[ABSCOND]], i8 [[NEG]], i8 [[ADD]]
74+
; CHECK-NEXT: ret i8 [[ABS]]
75+
; CHECK: [[COND_END]]:
76+
; CHECK-NEXT: ret i8 0
77+
;
78+
entry:
79+
%cmp = icmp samesign ugt i8 %x, %y
80+
br i1 %cmp, label %cond.true, label %cond.end
81+
82+
cond.true: ; preds = %entry
83+
%sub = sub i8 %x, %y
84+
%add = add i8 %sub, 1
85+
%neg = xor i8 %sub, -1
86+
%abscond = icmp samesign ult i8 %sub, -1
87+
%abs = select i1 %abscond, i8 %neg, i8 %add
88+
ret i8 %abs
89+
90+
cond.end: ; preds = %entry, %cond.true
91+
ret i8 0
92+
}
93+
94+
define i8 @ugt_sub_nsw(i8 %x, i8 %y) {
95+
; CHECK-LABEL: define i8 @ugt_sub_nsw(
96+
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
97+
; CHECK-NEXT: [[ENTRY:.*:]]
98+
; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i8 [[X]], [[Y]]
99+
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
100+
; CHECK: [[COND_TRUE]]:
101+
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
102+
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[SUB]], 1
103+
; CHECK-NEXT: [[NEG:%.*]] = xor i8 [[SUB]], -1
104+
; CHECK-NEXT: [[ABSCOND:%.*]] = icmp ult i8 [[SUB]], -1
105+
; CHECK-NEXT: [[ABS:%.*]] = select i1 [[ABSCOND]], i8 [[NEG]], i8 [[ADD]]
106+
; CHECK-NEXT: ret i8 [[ABS]]
107+
; CHECK: [[COND_END]]:
108+
; CHECK-NEXT: ret i8 0
109+
;
110+
entry:
111+
%cmp = icmp ugt i8 %x, %y
112+
br i1 %cmp, label %cond.true, label %cond.end
113+
114+
cond.true: ; preds = %entry
115+
%sub = sub i8 %x, %y
116+
%add = add i8 %sub, 1
117+
%neg = xor i8 %sub, -1
118+
%abscond = icmp ult i8 %sub, -1
119+
%abs = select i1 %abscond, i8 %neg, i8 %add
120+
ret i8 %abs
121+
122+
cond.end: ; preds = %entry, %cond.true
123+
ret i8 0
124+
}
125+
126+
define i32 @lt_sub_nsw(i32 %x, i32 %y) {
127+
; CHECK-LABEL: define i32 @lt_sub_nsw(
128+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
129+
; CHECK-NEXT: [[ENTRY:.*:]]
130+
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i32 [[X]], [[Y]]
131+
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
132+
; CHECK: [[COND_TRUE]]:
133+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
134+
; CHECK-NEXT: [[NEG:%.*]] = add nsw i32 [[SUB]], 1
135+
; CHECK-NEXT: ret i32 [[NEG]]
136+
; CHECK: [[COND_END]]:
137+
; CHECK-NEXT: ret i32 0
138+
;
139+
entry:
140+
%cmp = icmp samesign ult i32 %x, %y ; x<y ? abs (x-y+1): 0
141+
br i1 %cmp, label %cond.true, label %cond.end
142+
143+
cond.true: ; preds = %entry
144+
%sub = sub nsw i32 %x, %y
145+
%add = add nsw i32 %sub, 1
146+
%neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
147+
%abscond = icmp samesign ugt i32 %sub, -1
148+
%abs = select i1 %abscond, i32 %neg, i32 %add
149+
ret i32 %abs
150+
151+
cond.end: ; preds = %entry, %cond.true
152+
ret i32 0
153+
}
154+
155+
define i32 @le_sub_nsw(i32 %x, i32 %y) {
156+
; CHECK-LABEL: define i32 @le_sub_nsw(
157+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
158+
; CHECK-NEXT: [[ENTRY:.*:]]
159+
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ule i32 [[X]], [[Y]]
160+
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
161+
; CHECK: [[COND_TRUE]]:
162+
; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[X]], [[Y]]
163+
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[SUB]], 1
164+
; CHECK-NEXT: ret i32 [[ADD]]
165+
; CHECK: [[COND_END]]:
166+
; CHECK-NEXT: ret i32 0
167+
;
168+
entry:
169+
%cmp = icmp samesign ule i32 %x, %y ; x<=y ? abs (x-y+1): 0
170+
br i1 %cmp, label %cond.true, label %cond.end
171+
172+
cond.true: ; preds = %entry
173+
%sub = sub nsw i32 %x, %y
174+
%add = add nsw i32 %sub, 1
175+
%neg = xor i32 %sub, -1 ; sub nsw i32 0, %add
176+
%abscond = icmp samesign ugt i32 %sub, -1
177+
%abs = select i1 %abscond, i32 %neg, i32 %add
178+
ret i32 %abs
179+
180+
cond.end: ; preds = %entry, %cond.true
181+
ret i32 0
182+
}
183+
184+
define i8 @gt_sub_nsw_wrong_const(i8 %x, i8 %y) {
185+
; CHECK-LABEL: define i8 @gt_sub_nsw_wrong_const(
186+
; CHECK-SAME: i8 [[X:%.*]], i8 [[Y:%.*]]) {
187+
; CHECK-NEXT: [[ENTRY:.*:]]
188+
; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ugt i8 [[X]], [[Y]]
189+
; CHECK-NEXT: br i1 [[CMP]], label %[[COND_TRUE:.*]], label %[[COND_END:.*]]
190+
; CHECK: [[COND_TRUE]]:
191+
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
192+
; CHECK-NEXT: [[ADD:%.*]] = add i8 [[SUB]], 2
193+
; CHECK-NEXT: [[NEG:%.*]] = xor i8 [[SUB]], -1
194+
; CHECK-NEXT: [[ABSCOND:%.*]] = icmp samesign ult i8 [[SUB]], -2
195+
; CHECK-NEXT: [[ABS:%.*]] = select i1 [[ABSCOND]], i8 [[NEG]], i8 [[ADD]]
196+
; CHECK-NEXT: ret i8 [[ABS]]
197+
; CHECK: [[COND_END]]:
198+
; CHECK-NEXT: ret i8 0
199+
;
200+
entry:
201+
%cmp = icmp samesign ugt i8 %x, %y ; x>y ? abs (x-y+2): 0
202+
br i1 %cmp, label %cond.true, label %cond.end
203+
204+
cond.true: ; preds = %entry
205+
%sub = sub i8 %x, %y
206+
%add = add i8 %sub, 2 ; x-y+2
207+
%neg = xor i8 %sub, -1 ; y-x-1
208+
%neg1 = sub i8 %neg, 1 ; y-x-2
209+
%abscond = icmp samesign ult i8 %sub, -2
210+
%abs = select i1 %abscond, i8 %neg, i8 %add
211+
ret i8 %abs
212+
213+
cond.end: ; preds = %entry, %cond.true
214+
ret i8 0
215+
}

0 commit comments

Comments
 (0)