[SCCP] Strengthen two-instruction range checks (#162008)
This patch implements the todo discussed in https://github.com/llvm/llvm-project/pull/158495#discussion_r2349609838. It also fixes a regression introduced by https://github.com/llvm/llvm-project/pull/161000. See also https://github.com/dtcxzyw/llvm-opt-benchmark/pull/2890#discussion_r2404016316. IR diff: https://github.com/dtcxzyw/llvm-opt-benchmark/pull/2892
This commit is contained in:
parent
550b2ef041
commit
5e92e7f4c0
@ -317,24 +317,29 @@ static Value *simplifyInstruction(SCCPSolver &Solver,
|
||||
// Early exit if we know nothing about X.
|
||||
if (LRange.isFullSet())
|
||||
return nullptr;
|
||||
// We are allowed to refine the comparison to either true or false for out
|
||||
// of range inputs. Here we refine the comparison to true, i.e. we relax
|
||||
// the range check.
|
||||
auto NewCR = CR->exactUnionWith(LRange.inverse());
|
||||
// TODO: Check if we can narrow the range check to an equality test.
|
||||
// E.g, for X in [0, 4), X - 3 u< 2 -> X == 3
|
||||
if (!NewCR)
|
||||
auto ConvertCRToICmp =
|
||||
[&](const std::optional<ConstantRange> &NewCR) -> Value * {
|
||||
ICmpInst::Predicate Pred;
|
||||
APInt RHS;
|
||||
// Check if we can represent NewCR as an icmp predicate.
|
||||
if (NewCR && NewCR->getEquivalentICmp(Pred, RHS)) {
|
||||
IRBuilder<NoFolder> Builder(&Inst);
|
||||
Value *NewICmp =
|
||||
Builder.CreateICmp(Pred, X, ConstantInt::get(X->getType(), RHS));
|
||||
InsertedValues.insert(NewICmp);
|
||||
return NewICmp;
|
||||
}
|
||||
return nullptr;
|
||||
ICmpInst::Predicate Pred;
|
||||
APInt RHS;
|
||||
// Check if we can represent NewCR as an icmp predicate.
|
||||
if (NewCR->getEquivalentICmp(Pred, RHS)) {
|
||||
IRBuilder<NoFolder> Builder(&Inst);
|
||||
Value *NewICmp =
|
||||
Builder.CreateICmp(Pred, X, ConstantInt::get(X->getType(), RHS));
|
||||
InsertedValues.insert(NewICmp);
|
||||
return NewICmp;
|
||||
}
|
||||
};
|
||||
// We are allowed to refine the comparison to either true or false for out
|
||||
// of range inputs.
|
||||
// Here we refine the comparison to false, and check if we can narrow the
|
||||
// range check to a simpler test.
|
||||
if (auto *V = ConvertCRToICmp(CR->exactIntersectWith(LRange)))
|
||||
return V;
|
||||
// Here we refine the comparison to true, i.e. we relax the range check.
|
||||
if (auto *V = ConvertCRToICmp(CR->exactUnionWith(LRange.inverse())))
|
||||
return V;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -89,4 +89,28 @@ define i1 @relax_range_check_multiuse(i8 range(i8 0, 5) %x) {
|
||||
ret i1 %ret
|
||||
}
|
||||
|
||||
define i1 @range_check_to_icmp_eq1(i32 range(i32 0, 4) %x) {
|
||||
; CHECK-LABEL: define i1 @range_check_to_icmp_eq1(
|
||||
; CHECK-SAME: i32 range(i32 0, 4) [[X:%.*]]) {
|
||||
; CHECK-NEXT: [[OFF:%.*]] = add nsw i32 [[X]], -3
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i32 [[X]], 3
|
||||
; CHECK-NEXT: ret i1 [[TMP1]]
|
||||
;
|
||||
%off = add nsw i32 %x, -3
|
||||
%cmp = icmp ult i32 %off, 2
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
define i1 @range_check_to_icmp_eq2(i32 range(i32 -1, 2) %x) {
|
||||
; CHECK-LABEL: define i1 @range_check_to_icmp_eq2(
|
||||
; CHECK-SAME: i32 range(i32 -1, 2) [[X:%.*]]) {
|
||||
; CHECK-NEXT: [[OFF:%.*]] = add nsw i32 [[X]], -1
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[X]], 1
|
||||
; CHECK-NEXT: ret i1 [[CMP]]
|
||||
;
|
||||
%off = add nsw i32 %x, -1
|
||||
%cmp = icmp ult i32 %off, -2
|
||||
ret i1 %cmp
|
||||
}
|
||||
|
||||
declare void @use(i8)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user