Skip to content

Commit d18ca43

Browse files
authored
[ConstraintElimination] Add support for UCMP/SCMP intrinsics (#97974)
This adds checks to fold calls to `ucmp`/`scmp` where a comparative relationship between the arguments can be established.
1 parent ed17431 commit d18ca43

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed

llvm/lib/Transforms/Scalar/ConstraintElimination.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,8 @@ void State::addInfoFor(BasicBlock &BB) {
10871087
}
10881088
// Enqueue ssub_with_overflow for simplification.
10891089
case Intrinsic::ssub_with_overflow:
1090+
case Intrinsic::ucmp:
1091+
case Intrinsic::scmp:
10901092
WorkList.push_back(
10911093
FactOrCheck::getCheck(DT.getNode(&BB), cast<CallInst>(&I)));
10921094
break;
@@ -1448,6 +1450,28 @@ static bool checkAndReplaceMinMax(MinMaxIntrinsic *MinMax, ConstraintInfo &Info,
14481450
return false;
14491451
}
14501452

1453+
static bool checkAndReplaceCmp(CmpIntrinsic *I, ConstraintInfo &Info,
1454+
SmallVectorImpl<Instruction *> &ToRemove) {
1455+
Value *LHS = I->getOperand(0);
1456+
Value *RHS = I->getOperand(1);
1457+
if (checkCondition(I->getGTPredicate(), LHS, RHS, I, Info).value_or(false)) {
1458+
I->replaceAllUsesWith(ConstantInt::get(I->getType(), 1));
1459+
ToRemove.push_back(I);
1460+
return true;
1461+
}
1462+
if (checkCondition(I->getLTPredicate(), LHS, RHS, I, Info).value_or(false)) {
1463+
I->replaceAllUsesWith(ConstantInt::getSigned(I->getType(), -1));
1464+
ToRemove.push_back(I);
1465+
return true;
1466+
}
1467+
if (checkCondition(ICmpInst::ICMP_EQ, LHS, RHS, I, Info)) {
1468+
I->replaceAllUsesWith(ConstantInt::get(I->getType(), 0));
1469+
ToRemove.push_back(I);
1470+
return true;
1471+
}
1472+
return false;
1473+
}
1474+
14511475
static void
14521476
removeEntryFromStack(const StackEntry &E, ConstraintInfo &Info,
14531477
Module *ReproducerModule,
@@ -1750,6 +1774,8 @@ static bool eliminateConstraints(Function &F, DominatorTree &DT, LoopInfo &LI,
17501774
Changed |= Simplified;
17511775
} else if (auto *MinMax = dyn_cast<MinMaxIntrinsic>(Inst)) {
17521776
Changed |= checkAndReplaceMinMax(MinMax, Info, ToRemove);
1777+
} else if (auto *CmpIntr = dyn_cast<CmpIntrinsic>(Inst)) {
1778+
Changed |= checkAndReplaceCmp(CmpIntr, Info, ToRemove);
17531779
}
17541780
continue;
17551781
}
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s
3+
4+
define i8 @scmp_1(i32 %x, i32 %y) {
5+
; CHECK-LABEL: @scmp_1(
6+
; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[X:%.*]], [[Y:%.*]]
7+
; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]]
8+
; CHECK: true:
9+
; CHECK-NEXT: ret i8 1
10+
; CHECK: false:
11+
; CHECK-NEXT: ret i8 20
12+
;
13+
%cond = icmp sgt i32 %x, %y
14+
br i1 %cond, label %true, label %false
15+
true:
16+
%r = call i8 @llvm.scmp(i32 %x, i32 %y)
17+
ret i8 %r
18+
false:
19+
ret i8 20
20+
}
21+
22+
define i8 @ucmp_1(i32 %x, i32 %y) {
23+
; CHECK-LABEL: @ucmp_1(
24+
; CHECK-NEXT: [[COND:%.*]] = icmp ult i32 [[X:%.*]], [[Y:%.*]]
25+
; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]]
26+
; CHECK: true:
27+
; CHECK-NEXT: ret i8 -1
28+
; CHECK: false:
29+
; CHECK-NEXT: ret i8 20
30+
;
31+
%cond = icmp ult i32 %x, %y
32+
br i1 %cond, label %true, label %false
33+
true:
34+
%r = call i8 @llvm.ucmp(i32 %x, i32 %y)
35+
ret i8 %r
36+
false:
37+
ret i8 20
38+
}
39+
40+
define i8 @scmp_2(i32 %x, i32 %y) {
41+
; CHECK-LABEL: @scmp_2(
42+
; CHECK-NEXT: [[COND:%.*]] = icmp sge i32 [[X:%.*]], [[Y:%.*]]
43+
; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]]
44+
; CHECK: true:
45+
; CHECK-NEXT: ret i8 20
46+
; CHECK: false:
47+
; CHECK-NEXT: ret i8 -1
48+
;
49+
%cond = icmp sge i32 %x, %y
50+
br i1 %cond, label %true, label %false
51+
true:
52+
ret i8 20
53+
false:
54+
%r = call i8 @llvm.scmp(i32 %x, i32 %y)
55+
ret i8 %r
56+
}
57+
58+
define i8 @ucmp_2(i32 %x, i32 %y) {
59+
; CHECK-LABEL: @ucmp_2(
60+
; CHECK-NEXT: [[COND:%.*]] = icmp ule i32 [[X:%.*]], [[Y:%.*]]
61+
; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]]
62+
; CHECK: true:
63+
; CHECK-NEXT: ret i8 20
64+
; CHECK: false:
65+
; CHECK-NEXT: ret i8 1
66+
;
67+
%cond = icmp ule i32 %x, %y
68+
br i1 %cond, label %true, label %false
69+
true:
70+
ret i8 20
71+
false:
72+
%r = call i8 @llvm.ucmp(i32 %x, i32 %y)
73+
ret i8 %r
74+
}
75+
76+
define i8 @scmp_3(i32 %x, i32 %y) {
77+
; CHECK-LABEL: @scmp_3(
78+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
79+
; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]]
80+
; CHECK: true:
81+
; CHECK-NEXT: ret i8 0
82+
; CHECK: false:
83+
; CHECK-NEXT: ret i8 20
84+
;
85+
%cond = icmp eq i32 %x, %y
86+
br i1 %cond, label %true, label %false
87+
true:
88+
%r = call i8 @llvm.scmp(i32 %x, i32 %y)
89+
ret i8 %r
90+
false:
91+
ret i8 20
92+
}
93+
94+
define i8 @ucmp_3(i32 %x, i32 %y) {
95+
; CHECK-LABEL: @ucmp_3(
96+
; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X:%.*]], [[Y:%.*]]
97+
; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]]
98+
; CHECK: true:
99+
; CHECK-NEXT: ret i8 0
100+
; CHECK: false:
101+
; CHECK-NEXT: ret i8 20
102+
;
103+
%cond = icmp eq i32 %x, %y
104+
br i1 %cond, label %true, label %false
105+
true:
106+
%r = call i8 @llvm.ucmp(i32 %x, i32 %y)
107+
ret i8 %r
108+
false:
109+
ret i8 20
110+
}
111+
112+
; Negative test: signedness mismatch
113+
define i8 @scmp_4(i32 %x, i32 %y) {
114+
; CHECK-LABEL: @scmp_4(
115+
; CHECK-NEXT: [[COND:%.*]] = icmp ugt i32 [[X:%.*]], [[Y:%.*]]
116+
; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]]
117+
; CHECK: true:
118+
; CHECK-NEXT: ret i8 20
119+
; CHECK: false:
120+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
121+
; CHECK-NEXT: ret i8 [[R]]
122+
;
123+
%cond = icmp ugt i32 %x, %y
124+
br i1 %cond, label %true, label %false
125+
true:
126+
ret i8 20
127+
false:
128+
%r = call i8 @llvm.scmp(i32 %x, i32 %y)
129+
ret i8 %r
130+
}
131+
132+
define i8 @ucmp_4(i32 %x, i32 %y) {
133+
; CHECK-LABEL: @ucmp_4(
134+
; CHECK-NEXT: [[COND:%.*]] = icmp slt i32 [[X:%.*]], [[Y:%.*]]
135+
; CHECK-NEXT: br i1 [[COND]], label [[TRUE:%.*]], label [[FALSE:%.*]]
136+
; CHECK: true:
137+
; CHECK-NEXT: ret i8 20
138+
; CHECK: false:
139+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
140+
; CHECK-NEXT: ret i8 [[R]]
141+
;
142+
%cond = icmp slt i32 %x, %y
143+
br i1 %cond, label %true, label %false
144+
true:
145+
ret i8 20
146+
false:
147+
%r = call i8 @llvm.ucmp(i32 %x, i32 %y)
148+
ret i8 %r
149+
}

0 commit comments

Comments
 (0)