[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:
Yingwei Zheng 2025-10-06 15:14:46 +08:00 committed by GitHub
parent 550b2ef041
commit 5e92e7f4c0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 46 additions and 17 deletions

View File

@ -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;
}
}

View File

@ -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)