[llvm] [LVI] Thread binop over select with constant arms (PR #110212)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 26 23:34:00 PDT 2024
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/110212
Motivating case from https://github.com/delta-io/delta-rs: https://alive2.llvm.org/ce/z/3mzr4C
>From 845810176ca91c957def4a714fe6d9f2d1e7c493 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 27 Sep 2024 14:31:57 +0800
Subject: [PATCH] [LVI] Thread binop over select with constant arms
---
llvm/lib/Analysis/LazyValueInfo.cpp | 61 ++++++++++++++++++++++++++++-
1 file changed, 59 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
index 30dc4ae30dbfa5..a1e6361f3f139f 100644
--- a/llvm/lib/Analysis/LazyValueInfo.cpp
+++ b/llvm/lib/Analysis/LazyValueInfo.cpp
@@ -924,17 +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-> // intersect(*getValueFromCondition(V, Cond, CondIsTrue,
+ // /*UseBlockValue=*/false)).
+ asConstantRange(V->getType());
+ };
+
+ auto ThreadBinOpOverSelect =
+ [&](Value *X, const ConstantRange &CRX, SelectInst *Y,
+ bool XIsLHS) -> std::optional<ValueLatticeElement> {
+ Value *Cond = Y->getCondition();
+ 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 =
+ ValueLatticeElement::get(TrueC).asConstantRange(X->getType());
+ ConstantRange FalseY =
+ ValueLatticeElement::get(FalseC).asConstantRange(X->getType());
+
+ 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;
+ // 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(I->getOperand(1), I, BB);
+ 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;
More information about the llvm-commits
mailing list