[llvm] e350494 - [NFC] Promote willNotOverflow() / getStrengthenedNoWrapFlagsFromBinOp() from IndVars into SCEV proper
Roman Lebedev via llvm-commits
llvm-commits at lists.llvm.org
Sat Jun 5 02:18:19 PDT 2021
Author: Roman Lebedev
Date: 2021-06-05T12:17:51+03:00
New Revision: e350494fb044c5badec9cd8bfd7ab05026babf81
URL: https://github.com/llvm/llvm-project/commit/e350494fb044c5badec9cd8bfd7ab05026babf81
DIFF: https://github.com/llvm/llvm-project/commit/e350494fb044c5badec9cd8bfd7ab05026babf81.diff
LOG: [NFC] Promote willNotOverflow() / getStrengthenedNoWrapFlagsFromBinOp() from IndVars into SCEV proper
We might want to use it when creating SCEV proper in createSCEV(),
now that we don't `forgetValue()` in `SimplifyIndvar::strengthenOverflowingOperation()`,
which might have caused us to loose some optimization potential.
Added:
Modified:
llvm/include/llvm/Analysis/ScalarEvolution.h
llvm/lib/Analysis/ScalarEvolution.cpp
llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/ScalarEvolution.h b/llvm/include/llvm/Analysis/ScalarEvolution.h
index bddd2cf78354b..68406c90dd27e 100644
--- a/llvm/include/llvm/Analysis/ScalarEvolution.h
+++ b/llvm/include/llvm/Analysis/ScalarEvolution.h
@@ -505,6 +505,17 @@ class ScalarEvolution {
/// Erase Value from ValueExprMap and ExprValueMap.
void eraseValueFromMap(Value *V);
+ /// Is operation \p BinOp between \p LHS and \p RHS provably does not have
+ /// a signed/unsigned overflow (\p Signed)?
+ bool willNotOverflow(Instruction::BinaryOps BinOp, bool Signed,
+ const SCEV *LHS, const SCEV *RHS);
+
+ /// Parse NSW/NUW flags from add/sub/mul IR binary operation \p Op into
+ /// SCEV no-wrap flags, and deduce flag[s] that aren't known yet.
+ /// Does not mutate the original instruction.
+ std::pair<SCEV::NoWrapFlags, bool /*Deduced*/>
+ getStrengthenedNoWrapFlagsFromBinOp(const OverflowingBinaryOperator *OBO);
+
/// Return a SCEV expression for the full generality of the specified
/// expression.
const SCEV *getSCEV(Value *V);
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 0d3d781d6ff46..7a8369b9ea013 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -2244,6 +2244,81 @@ CollectAddOperandsWithScales(DenseMap<const SCEV *, APInt> &M,
return Interesting;
}
+bool ScalarEvolution::willNotOverflow(Instruction::BinaryOps BinOp, bool Signed,
+ const SCEV *LHS, const SCEV *RHS) {
+ const SCEV *(ScalarEvolution::*Operation)(const SCEV *, const SCEV *,
+ SCEV::NoWrapFlags, unsigned);
+ switch (BinOp) {
+ default:
+ llvm_unreachable("Unsupported binary op");
+ case Instruction::Add:
+ Operation = &ScalarEvolution::getAddExpr;
+ break;
+ case Instruction::Sub:
+ Operation = &ScalarEvolution::getMinusSCEV;
+ break;
+ case Instruction::Mul:
+ Operation = &ScalarEvolution::getMulExpr;
+ break;
+ }
+
+ const SCEV *(ScalarEvolution::*Extension)(const SCEV *, Type *, unsigned) =
+ Signed ? &ScalarEvolution::getSignExtendExpr
+ : &ScalarEvolution::getZeroExtendExpr;
+
+ // Check ext(LHS op RHS) == ext(LHS) op ext(RHS)
+ auto *NarrowTy = cast<IntegerType>(LHS->getType());
+ auto *WideTy =
+ IntegerType::get(NarrowTy->getContext(), NarrowTy->getBitWidth() * 2);
+
+ const SCEV *A = (this->*Extension)(
+ (this->*Operation)(LHS, RHS, SCEV::FlagAnyWrap, 0), WideTy, 0);
+ const SCEV *B = (this->*Operation)((this->*Extension)(LHS, WideTy, 0),
+ (this->*Extension)(RHS, WideTy, 0),
+ SCEV::FlagAnyWrap, 0);
+ return A == B;
+}
+
+std::pair<SCEV::NoWrapFlags, bool /*Deduced*/>
+ScalarEvolution::getStrengthenedNoWrapFlagsFromBinOp(
+ const OverflowingBinaryOperator *OBO) {
+ SCEV::NoWrapFlags Flags = SCEV::NoWrapFlags::FlagAnyWrap;
+
+ if (OBO->hasNoUnsignedWrap())
+ Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
+ if (OBO->hasNoSignedWrap())
+ Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW);
+
+ bool Deduced = false;
+
+ if (OBO->hasNoUnsignedWrap() && OBO->hasNoSignedWrap())
+ return {Flags, Deduced};
+
+ if (OBO->getOpcode() != Instruction::Add &&
+ OBO->getOpcode() != Instruction::Sub &&
+ OBO->getOpcode() != Instruction::Mul)
+ return {Flags, Deduced};
+
+ const SCEV *LHS = getSCEV(OBO->getOperand(0));
+ const SCEV *RHS = getSCEV(OBO->getOperand(1));
+
+ if (!OBO->hasNoUnsignedWrap() &&
+ willNotOverflow((Instruction::BinaryOps)OBO->getOpcode(),
+ /* Signed */ false, LHS, RHS)) {
+ Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW);
+ Deduced = true;
+ }
+
+ if (!OBO->hasNoSignedWrap() &&
+ willNotOverflow((Instruction::BinaryOps)OBO->getOpcode(),
+ /* Signed */ true, LHS, RHS)) {
+ Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNSW);
+ Deduced = true;
+ }
+
+ return {Flags, Deduced};
+}
+
// We're trying to construct a SCEV of type `Type' with `Ops' as operands and
// `OldFlags' as can't-wrap behavior. Infer a more aggressive set of
// can't-overflow flags for the operation if possible.
diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
index 246bc0adaf6c8..ff60667e72b3c 100644
--- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp
@@ -422,46 +422,10 @@ void SimplifyIndvar::simplifyIVRemainder(BinaryOperator *Rem, Value *IVOperand,
replaceSRemWithURem(Rem);
}
-static bool willNotOverflow(ScalarEvolution *SE, Instruction::BinaryOps BinOp,
- bool Signed, const SCEV *LHS, const SCEV *RHS) {
- const SCEV *(ScalarEvolution::*Operation)(const SCEV *, const SCEV *,
- SCEV::NoWrapFlags, unsigned);
- switch (BinOp) {
- default:
- llvm_unreachable("Unsupported binary op");
- case Instruction::Add:
- Operation = &ScalarEvolution::getAddExpr;
- break;
- case Instruction::Sub:
- Operation = &ScalarEvolution::getMinusSCEV;
- break;
- case Instruction::Mul:
- Operation = &ScalarEvolution::getMulExpr;
- break;
- }
-
- const SCEV *(ScalarEvolution::*Extension)(const SCEV *, Type *, unsigned) =
- Signed ? &ScalarEvolution::getSignExtendExpr
- : &ScalarEvolution::getZeroExtendExpr;
-
- // Check ext(LHS op RHS) == ext(LHS) op ext(RHS)
- auto *NarrowTy = cast<IntegerType>(LHS->getType());
- auto *WideTy =
- IntegerType::get(NarrowTy->getContext(), NarrowTy->getBitWidth() * 2);
-
- const SCEV *A =
- (SE->*Extension)((SE->*Operation)(LHS, RHS, SCEV::FlagAnyWrap, 0),
- WideTy, 0);
- const SCEV *B =
- (SE->*Operation)((SE->*Extension)(LHS, WideTy, 0),
- (SE->*Extension)(RHS, WideTy, 0), SCEV::FlagAnyWrap, 0);
- return A == B;
-}
-
bool SimplifyIndvar::eliminateOverflowIntrinsic(WithOverflowInst *WO) {
const SCEV *LHS = SE->getSCEV(WO->getLHS());
const SCEV *RHS = SE->getSCEV(WO->getRHS());
- if (!willNotOverflow(SE, WO->getBinaryOp(), WO->isSigned(), LHS, RHS))
+ if (!SE->willNotOverflow(WO->getBinaryOp(), WO->isSigned(), LHS, RHS))
return false;
// Proved no overflow, nuke the overflow check and, if possible, the overflow
@@ -502,7 +466,7 @@ bool SimplifyIndvar::eliminateOverflowIntrinsic(WithOverflowInst *WO) {
bool SimplifyIndvar::eliminateSaturatingIntrinsic(SaturatingInst *SI) {
const SCEV *LHS = SE->getSCEV(SI->getLHS());
const SCEV *RHS = SE->getSCEV(SI->getRHS());
- if (!willNotOverflow(SE, SI->getBinaryOp(), SI->isSigned(), LHS, RHS))
+ if (!SE->willNotOverflow(SI->getBinaryOp(), SI->isSigned(), LHS, RHS))
return false;
BinaryOperator *BO = BinaryOperator::Create(
@@ -756,37 +720,25 @@ bool SimplifyIndvar::eliminateIdentitySCEV(Instruction *UseInst,
/// unsigned-overflow. Returns true if anything changed, false otherwise.
bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO,
Value *IVOperand) {
- // Fastpath: we don't have any work to do if `BO` is `nuw` and `nsw`.
- if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
- return false;
-
- if (BO->getOpcode() != Instruction::Add &&
- BO->getOpcode() != Instruction::Sub &&
- BO->getOpcode() != Instruction::Mul)
- return false;
-
- const SCEV *LHS = SE->getSCEV(BO->getOperand(0));
- const SCEV *RHS = SE->getSCEV(BO->getOperand(1));
- bool Changed = false;
-
- if (!BO->hasNoUnsignedWrap() &&
- willNotOverflow(SE, BO->getOpcode(), /* Signed */ false, LHS, RHS)) {
- BO->setHasNoUnsignedWrap();
- Changed = true;
- }
-
- if (!BO->hasNoSignedWrap() &&
- willNotOverflow(SE, BO->getOpcode(), /* Signed */ true, LHS, RHS)) {
- BO->setHasNoSignedWrap();
- Changed = true;
- }
-
- // The willNotOverflow() check might infer additional nowrap flags on addrecs
- // while performing zero/sign extensions. We could call forgetValue() here
- // to make sure those flags also propagate to any other SCEV expressions
- // based on the addrec. However, this can have pathological compile-time
- // impact, see https://bugs.llvm.org/show_bug.cgi?id=50384.
- return Changed;
+ SCEV::NoWrapFlags Flags;
+ bool Deduced;
+ std::tie(Flags, Deduced) = SE->getStrengthenedNoWrapFlagsFromBinOp(
+ cast<OverflowingBinaryOperator>(BO));
+
+ if (!Deduced)
+ return Deduced;
+
+ BO->setHasNoUnsignedWrap(ScalarEvolution::maskFlags(Flags, SCEV::FlagNUW) ==
+ SCEV::FlagNUW);
+ BO->setHasNoSignedWrap(ScalarEvolution::maskFlags(Flags, SCEV::FlagNSW) ==
+ SCEV::FlagNSW);
+
+ // The getStrengthenedNoWrapFlagsFromBinOp() check inferred additional nowrap
+ // flags on addrecs while performing zero/sign extensions. We could call
+ // forgetValue() here to make sure those flags also propagate to any other
+ // SCEV expressions based on the addrec. However, this can have pathological
+ // compile-time impact, see https://bugs.llvm.org/show_bug.cgi?id=50384.
+ return Deduced;
}
/// Annotate the Shr in (X << IVOperand) >> C as exact using the
More information about the llvm-commits
mailing list