forked from OSchip/llvm-project
[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.
This commit is contained in:
parent
92ce29ee45
commit
e350494fb0
|
@ -505,6 +505,17 @@ public:
|
|||
/// 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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
SCEV::NoWrapFlags Flags;
|
||||
bool Deduced;
|
||||
std::tie(Flags, Deduced) = SE->getStrengthenedNoWrapFlagsFromBinOp(
|
||||
cast<OverflowingBinaryOperator>(BO));
|
||||
|
||||
if (BO->getOpcode() != Instruction::Add &&
|
||||
BO->getOpcode() != Instruction::Sub &&
|
||||
BO->getOpcode() != Instruction::Mul)
|
||||
return false;
|
||||
if (!Deduced)
|
||||
return Deduced;
|
||||
|
||||
const SCEV *LHS = SE->getSCEV(BO->getOperand(0));
|
||||
const SCEV *RHS = SE->getSCEV(BO->getOperand(1));
|
||||
bool Changed = false;
|
||||
BO->setHasNoUnsignedWrap(ScalarEvolution::maskFlags(Flags, SCEV::FlagNUW) ==
|
||||
SCEV::FlagNUW);
|
||||
BO->setHasNoSignedWrap(ScalarEvolution::maskFlags(Flags, SCEV::FlagNSW) ==
|
||||
SCEV::FlagNSW);
|
||||
|
||||
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;
|
||||
// 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
|
||||
|
|
Loading…
Reference in New Issue