mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 04:02:41 +01:00
[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
cde56bba2d
commit
46218a275e
@ -505,6 +505,17 @@ public:
|
|||||||
/// Erase Value from ValueExprMap and ExprValueMap.
|
/// Erase Value from ValueExprMap and ExprValueMap.
|
||||||
void eraseValueFromMap(Value *V);
|
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
|
/// Return a SCEV expression for the full generality of the specified
|
||||||
/// expression.
|
/// expression.
|
||||||
const SCEV *getSCEV(Value *V);
|
const SCEV *getSCEV(Value *V);
|
||||||
|
@ -2244,6 +2244,81 @@ CollectAddOperandsWithScales(DenseMap<const SCEV *, APInt> &M,
|
|||||||
return Interesting;
|
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
|
// 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
|
// `OldFlags' as can't-wrap behavior. Infer a more aggressive set of
|
||||||
// can't-overflow flags for the operation if possible.
|
// can't-overflow flags for the operation if possible.
|
||||||
|
@ -422,46 +422,10 @@ void SimplifyIndvar::simplifyIVRemainder(BinaryOperator *Rem, Value *IVOperand,
|
|||||||
replaceSRemWithURem(Rem);
|
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) {
|
bool SimplifyIndvar::eliminateOverflowIntrinsic(WithOverflowInst *WO) {
|
||||||
const SCEV *LHS = SE->getSCEV(WO->getLHS());
|
const SCEV *LHS = SE->getSCEV(WO->getLHS());
|
||||||
const SCEV *RHS = SE->getSCEV(WO->getRHS());
|
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;
|
return false;
|
||||||
|
|
||||||
// Proved no overflow, nuke the overflow check and, if possible, the overflow
|
// 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) {
|
bool SimplifyIndvar::eliminateSaturatingIntrinsic(SaturatingInst *SI) {
|
||||||
const SCEV *LHS = SE->getSCEV(SI->getLHS());
|
const SCEV *LHS = SE->getSCEV(SI->getLHS());
|
||||||
const SCEV *RHS = SE->getSCEV(SI->getRHS());
|
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;
|
return false;
|
||||||
|
|
||||||
BinaryOperator *BO = BinaryOperator::Create(
|
BinaryOperator *BO = BinaryOperator::Create(
|
||||||
@ -756,37 +720,25 @@ bool SimplifyIndvar::eliminateIdentitySCEV(Instruction *UseInst,
|
|||||||
/// unsigned-overflow. Returns true if anything changed, false otherwise.
|
/// unsigned-overflow. Returns true if anything changed, false otherwise.
|
||||||
bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO,
|
bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO,
|
||||||
Value *IVOperand) {
|
Value *IVOperand) {
|
||||||
// Fastpath: we don't have any work to do if `BO` is `nuw` and `nsw`.
|
SCEV::NoWrapFlags Flags;
|
||||||
if (BO->hasNoUnsignedWrap() && BO->hasNoSignedWrap())
|
bool Deduced;
|
||||||
return false;
|
std::tie(Flags, Deduced) = SE->getStrengthenedNoWrapFlagsFromBinOp(
|
||||||
|
cast<OverflowingBinaryOperator>(BO));
|
||||||
|
|
||||||
if (BO->getOpcode() != Instruction::Add &&
|
if (!Deduced)
|
||||||
BO->getOpcode() != Instruction::Sub &&
|
return Deduced;
|
||||||
BO->getOpcode() != Instruction::Mul)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const SCEV *LHS = SE->getSCEV(BO->getOperand(0));
|
BO->setHasNoUnsignedWrap(ScalarEvolution::maskFlags(Flags, SCEV::FlagNUW) ==
|
||||||
const SCEV *RHS = SE->getSCEV(BO->getOperand(1));
|
SCEV::FlagNUW);
|
||||||
bool Changed = false;
|
BO->setHasNoSignedWrap(ScalarEvolution::maskFlags(Flags, SCEV::FlagNSW) ==
|
||||||
|
SCEV::FlagNSW);
|
||||||
|
|
||||||
if (!BO->hasNoUnsignedWrap() &&
|
// The getStrengthenedNoWrapFlagsFromBinOp() check inferred additional nowrap
|
||||||
willNotOverflow(SE, BO->getOpcode(), /* Signed */ false, LHS, RHS)) {
|
// flags on addrecs while performing zero/sign extensions. We could call
|
||||||
BO->setHasNoUnsignedWrap();
|
// forgetValue() here to make sure those flags also propagate to any other
|
||||||
Changed = true;
|
// 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;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Annotate the Shr in (X << IVOperand) >> C as exact using the
|
/// Annotate the Shr in (X << IVOperand) >> C as exact using the
|
||||||
|
Loading…
Reference in New Issue
Block a user