Skip to content

Commit d545b4e

Browse files
dtcxzywaokblast
authored andcommitted
[SCCP] Strengthen two-instruction range checks (llvm#162008)
This patch implements the todo discussed in llvm#158495 (comment). It also fixes a regression introduced by llvm#161000. See also dtcxzyw/llvm-opt-benchmark#2890 (comment). IR diff: dtcxzyw/llvm-opt-benchmark#2892
1 parent 6795336 commit d545b4e

File tree

2 files changed

+46
-17
lines changed

2 files changed

+46
-17
lines changed

llvm/lib/Transforms/Utils/SCCPSolver.cpp

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -317,24 +317,29 @@ static Value *simplifyInstruction(SCCPSolver &Solver,
317317
// Early exit if we know nothing about X.
318318
if (LRange.isFullSet())
319319
return nullptr;
320-
// We are allowed to refine the comparison to either true or false for out
321-
// of range inputs. Here we refine the comparison to true, i.e. we relax
322-
// the range check.
323-
auto NewCR = CR->exactUnionWith(LRange.inverse());
324-
// TODO: Check if we can narrow the range check to an equality test.
325-
// E.g, for X in [0, 4), X - 3 u< 2 -> X == 3
326-
if (!NewCR)
320+
auto ConvertCRToICmp =
321+
[&](const std::optional<ConstantRange> &NewCR) -> Value * {
322+
ICmpInst::Predicate Pred;
323+
APInt RHS;
324+
// Check if we can represent NewCR as an icmp predicate.
325+
if (NewCR && NewCR->getEquivalentICmp(Pred, RHS)) {
326+
IRBuilder<NoFolder> Builder(&Inst);
327+
Value *NewICmp =
328+
Builder.CreateICmp(Pred, X, ConstantInt::get(X->getType(), RHS));
329+
InsertedValues.insert(NewICmp);
330+
return NewICmp;
331+
}
327332
return nullptr;
328-
ICmpInst::Predicate Pred;
329-
APInt RHS;
330-
// Check if we can represent NewCR as an icmp predicate.
331-
if (NewCR->getEquivalentICmp(Pred, RHS)) {
332-
IRBuilder<NoFolder> Builder(&Inst);
333-
Value *NewICmp =
334-
Builder.CreateICmp(Pred, X, ConstantInt::get(X->getType(), RHS));
335-
InsertedValues.insert(NewICmp);
336-
return NewICmp;
337-
}
333+
};
334+
// We are allowed to refine the comparison to either true or false for out
335+
// of range inputs.
336+
// Here we refine the comparison to false, and check if we can narrow the
337+
// range check to a simpler test.
338+
if (auto *V = ConvertCRToICmp(CR->exactIntersectWith(LRange)))
339+
return V;
340+
// Here we refine the comparison to true, i.e. we relax the range check.
341+
if (auto *V = ConvertCRToICmp(CR->exactUnionWith(LRange.inverse())))
342+
return V;
338343
}
339344
}
340345

llvm/test/Transforms/SCCP/relax-range-checks.ll

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,28 @@ define i1 @relax_range_check_multiuse(i8 range(i8 0, 5) %x) {
8989
ret i1 %ret
9090
}
9191

92+
define i1 @range_check_to_icmp_eq1(i32 range(i32 0, 4) %x) {
93+
; CHECK-LABEL: define i1 @range_check_to_icmp_eq1(
94+
; CHECK-SAME: i32 range(i32 0, 4) [[X:%.*]]) {
95+
; CHECK-NEXT: [[OFF:%.*]] = add nsw i32 [[X]], -3
96+
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], 3
97+
; CHECK-NEXT: ret i1 [[TMP1]]
98+
;
99+
%off = add nsw i32 %x, -3
100+
%cmp = icmp ult i32 %off, 2
101+
ret i1 %cmp
102+
}
103+
104+
define i1 @range_check_to_icmp_eq2(i32 range(i32 -1, 2) %x) {
105+
; CHECK-LABEL: define i1 @range_check_to_icmp_eq2(
106+
; CHECK-SAME: i32 range(i32 -1, 2) [[X:%.*]]) {
107+
; CHECK-NEXT: [[OFF:%.*]] = add nsw i32 [[X]], -1
108+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], 1
109+
; CHECK-NEXT: ret i1 [[CMP]]
110+
;
111+
%off = add nsw i32 %x, -1
112+
%cmp = icmp ult i32 %off, -2
113+
ret i1 %cmp
114+
}
115+
92116
declare void @use(i8)

0 commit comments

Comments
 (0)