[llvm] [LVI] Thread binop over select with constant arms (PR #110212)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sun Dec 8 19:28:18 PST 2024
https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/110212
>From 35e083ee1f3f2b36de3d1fc8001a712e9e4a4e02 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 5 Dec 2024 08:13:23 +0800
Subject: [PATCH 1/4] [CVP] Add pre-commit tests. NFC.
---
.../CorrelatedValuePropagation/cond-at-use.ll | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
index 3af4c70a5621c8..9318006f7a13af 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
@@ -630,3 +630,41 @@ define i64 @test_shl_nsw_at_use(i64 noundef %x) {
%res = select i1 %cmp, i64 %shr, i64 0
ret i64 %res
}
+
+define i1 @test_icmp_mod(i64 noundef %x) {
+; CHECK-LABEL: @test_icmp_mod(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[REM:%.*]] = srem i64 [[X:%.*]], 86400
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[REM]], 0
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i64 86400, i64 0
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[COND]], [[REM]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[ADD]], 86399
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+entry:
+ %rem = srem i64 %x, 86400
+ %cmp = icmp slt i64 %rem, 0
+ %cond = select i1 %cmp, i64 86400, i64 0
+ %add = add nsw i64 %cond, %rem
+ %cmp1 = icmp ugt i64 %add, 86399
+ ret i1 %cmp1
+}
+
+define i1 @test_icmp_mod_undef(i64 %x) {
+; CHECK-LABEL: @test_icmp_mod_undef(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[REM:%.*]] = srem i64 [[X:%.*]], 86400
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[REM]], 0
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i64 86400, i64 0
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[COND]], [[REM]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[ADD]], 86399
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+entry:
+ %rem = srem i64 %x, 86400
+ %cmp = icmp slt i64 %rem, 0
+ %cond = select i1 %cmp, i64 86400, i64 0
+ %add = add nsw i64 %cond, %rem
+ %cmp1 = icmp ugt i64 %add, 86399
+ ret i1 %cmp1
+}
>From a9d3246c397549ec98d00bcf10aa6c870859a245 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 5 Dec 2024 08:21:48 +0800
Subject: [PATCH 2/4] [LVI] Thread binop over select with constant arms
---
llvm/lib/Analysis/LazyValueInfo.cpp | 60 ++++++++++++++++++-
.../CorrelatedValuePropagation/cond-at-use.ll | 3 +-
2 files changed, 59 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index c9849b86b664c8..3246bdded4f10c 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -924,18 +924,74 @@ LazyValueInfoImpl::solveBlockValueBinaryOpImpl(
Instruction *I, BasicBlock *BB,
std::function<ConstantRange(const ConstantRange &, const ConstantRange &)>
OpFn) {
+ Value *LHS = I->getOperand(0);
+ Value *RHS = I->getOperand(1);
+
+ auto GetValueFromCondition =
+ [&](Value *V, Value *Cond,
+ bool CondIsTrue) -> std::optional<ConstantRange> {
+ std::optional<ValueLatticeElement> OptVal = getBlockValue(V, BB, I);
+ if (!OptVal)
+ return std::nullopt;
+ return OptVal->asConstantRange(V->getType());
+ };
+
+ auto ThreadBinOpOverSelect =
+ [&](Value *X, const ConstantRange &CRX, SelectInst *Y,
+ bool XIsLHS) -> std::optional<ValueLatticeElement> {
+ Value *Cond = Y->getCondition();
+ // Only handle selects with constant values.
+ Constant *TrueC = dyn_cast<Constant>(Y->getTrueValue());
+ if (!TrueC)
+ return std::nullopt;
+ Constant *FalseC = dyn_cast<Constant>(Y->getFalseValue());
+ if (!FalseC)
+ return std::nullopt;
+ if (!isGuaranteedNotToBeUndef(Cond, AC))
+ return std::nullopt;
+
+ ConstantRange TrueX =
+ CRX.intersectWith(getValueFromCondition(X, Cond, /*CondIsTrue=*/true,
+ /*UseBlockValue=*/false)
+ ->asConstantRange(X->getType()));
+ ConstantRange FalseX =
+ CRX.intersectWith(getValueFromCondition(X, Cond, /*CondIsTrue=*/false,
+ /*UseBlockValue=*/false)
+ ->asConstantRange(X->getType()));
+ ConstantRange TrueY = TrueC->toConstantRange();
+ ConstantRange FalseY = FalseC->toConstantRange();
+
+ if (XIsLHS)
+ return ValueLatticeElement::getRange(
+ OpFn(TrueX, TrueY).unionWith(OpFn(FalseX, FalseY)));
+ return ValueLatticeElement::getRange(
+ OpFn(TrueY, TrueX).unionWith(OpFn(FalseY, FalseX)));
+ };
+
// Figure out the ranges of the operands. If that fails, use a
// conservative range, but apply the transfer rule anyways. This
// lets us pick up facts from expressions like "and i32 (call i32
// @foo()), 32"
- std::optional<ConstantRange> LHSRes = getRangeFor(I->getOperand(0), I, BB);
+ std::optional<ConstantRange> LHSRes = getRangeFor(LHS, I, BB);
if (!LHSRes)
return std::nullopt;
- std::optional<ConstantRange> RHSRes = getRangeFor(I->getOperand(1), I, BB);
+ // Try to thread binop over rhs select
+ if (auto *SI = dyn_cast<SelectInst>(RHS)) {
+ if (auto Res = ThreadBinOpOverSelect(LHS, *LHSRes, SI, /*XIsLHS=*/true))
+ return *Res;
+ }
+
+ std::optional<ConstantRange> RHSRes = getRangeFor(RHS, I, BB);
if (!RHSRes)
return std::nullopt;
+ // Try to thread binop over lhs select
+ if (auto *SI = dyn_cast<SelectInst>(LHS)) {
+ if (auto Res = ThreadBinOpOverSelect(RHS, *RHSRes, SI, /*XIsLHS=*/false))
+ return *Res;
+ }
+
const ConstantRange &LHSRange = *LHSRes;
const ConstantRange &RHSRange = *RHSRes;
return ValueLatticeElement::getRange(OpFn(LHSRange, RHSRange));
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
index 9318006f7a13af..66787c76b41a68 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
@@ -638,8 +638,7 @@ define i1 @test_icmp_mod(i64 noundef %x) {
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[REM]], 0
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i64 86400, i64 0
; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[COND]], [[REM]]
-; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i64 [[ADD]], 86399
-; CHECK-NEXT: ret i1 [[CMP1]]
+; CHECK-NEXT: ret i1 false
;
entry:
%rem = srem i64 %x, 86400
>From 93b15872c3a03e6bd90a99c453902b03c8f982a3 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 6 Dec 2024 14:13:23 +0800
Subject: [PATCH 3/4] [LVI] Address review comments.
---
llvm/lib/Analysis/LazyValueInfo.cpp | 9 ---------
1 file changed, 9 deletions(-)
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 3246bdded4f10c..349a0a1a2d3c42 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -927,15 +927,6 @@ LazyValueInfoImpl::solveBlockValueBinaryOpImpl(
Value *LHS = I->getOperand(0);
Value *RHS = I->getOperand(1);
- auto GetValueFromCondition =
- [&](Value *V, Value *Cond,
- bool CondIsTrue) -> std::optional<ConstantRange> {
- std::optional<ValueLatticeElement> OptVal = getBlockValue(V, BB, I);
- if (!OptVal)
- return std::nullopt;
- return OptVal->asConstantRange(V->getType());
- };
-
auto ThreadBinOpOverSelect =
[&](Value *X, const ConstantRange &CRX, SelectInst *Y,
bool XIsLHS) -> std::optional<ValueLatticeElement> {
>From c0130e24c1fe211966a67d24c0c9bfb11f38b632 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 9 Dec 2024 11:25:35 +0800
Subject: [PATCH 4/4] [CVP] Add more tests. NFC.
---
.../CorrelatedValuePropagation/cond-at-use.ll | 55 +++++++++++++++++++
1 file changed, 55 insertions(+)
diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
index 66787c76b41a68..cca648bb6ea23e 100644
--- a/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
+++ b/llvm/test/Transforms/CorrelatedValuePropagation/cond-at-use.ll
@@ -649,6 +649,42 @@ entry:
ret i1 %cmp1
}
+define i1 @test_icmp_mod_commuted1(i64 noundef %x) {
+; CHECK-LABEL: @test_icmp_mod_commuted1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[REM:%.*]] = srem i64 [[X:%.*]], 86400
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[REM]], 0
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i64 86400, i64 0
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[REM]], [[COND]]
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %rem = srem i64 %x, 86400
+ %cmp = icmp slt i64 %rem, 0
+ %cond = select i1 %cmp, i64 86400, i64 0
+ %add = add nsw i64 %rem, %cond
+ %cmp1 = icmp ugt i64 %add, 86399
+ ret i1 %cmp1
+}
+
+define i1 @test_icmp_mod_commuted2(i64 noundef %x) {
+; CHECK-LABEL: @test_icmp_mod_commuted2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[REM:%.*]] = srem i64 [[X:%.*]], 86400
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[REM]], -1
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i64 0, i64 86400
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[COND]], [[REM]]
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %rem = srem i64 %x, 86400
+ %cmp = icmp sgt i64 %rem, -1
+ %cond = select i1 %cmp, i64 0, i64 86400
+ %add = add nsw i64 %cond, %rem
+ %cmp1 = icmp ugt i64 %add, 86399
+ ret i1 %cmp1
+}
+
define i1 @test_icmp_mod_undef(i64 %x) {
; CHECK-LABEL: @test_icmp_mod_undef(
; CHECK-NEXT: entry:
@@ -667,3 +703,22 @@ entry:
%cmp1 = icmp ugt i64 %add, 86399
ret i1 %cmp1
}
+
+define i1 @test_icmp_mod_wrong_range(i64 noundef %x) {
+; CHECK-LABEL: @test_icmp_mod_wrong_range(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[REM:%.*]] = srem i64 [[X:%.*]], 86400
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[REM]], 0
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i64 86401, i64 0
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i64 [[COND]], [[REM]]
+; CHECK-NEXT: [[CMP1:%.*]] = icmp samesign ugt i64 [[ADD]], 86399
+; CHECK-NEXT: ret i1 [[CMP1]]
+;
+entry:
+ %rem = srem i64 %x, 86400
+ %cmp = icmp slt i64 %rem, 0
+ %cond = select i1 %cmp, i64 86401, i64 0
+ %add = add nsw i64 %cond, %rem
+ %cmp1 = icmp ugt i64 %add, 86399
+ ret i1 %cmp1
+}
More information about the llvm-commits
mailing list