forked from OSchip/llvm-project
[InstCombine] Refactor OptimizeOverflowCheck; NFCI
Extract method to compute overflow based on binop and signedness, and then make the result handling code generic. This extends the always-overflow handling to signed muls, but has currently no effect, as we don't compute always overflow for them (thus NFC). llvm-svn: 361721
This commit is contained in:
parent
352f598795
commit
39f2bebf41
|
@ -3936,100 +3936,82 @@ Instruction *InstCombiner::foldICmpWithCastAndCast(ICmpInst &ICmp) {
|
|||
return BinaryOperator::CreateNot(Result);
|
||||
}
|
||||
|
||||
static bool isNeutralValue(Instruction::BinaryOps BinaryOp, Value *RHS) {
|
||||
switch (BinaryOp) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported binary op");
|
||||
case Instruction::Add:
|
||||
case Instruction::Sub:
|
||||
return match(RHS, m_Zero());
|
||||
case Instruction::Mul:
|
||||
return match(RHS, m_One());
|
||||
}
|
||||
}
|
||||
|
||||
OverflowResult InstCombiner::computeOverflow(
|
||||
Instruction::BinaryOps BinaryOp, bool IsSigned,
|
||||
Value *LHS, Value *RHS, Instruction *CxtI) const {
|
||||
switch (BinaryOp) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported binary op");
|
||||
case Instruction::Add:
|
||||
if (IsSigned)
|
||||
return computeOverflowForSignedAdd(LHS, RHS, CxtI);
|
||||
else
|
||||
return computeOverflowForUnsignedAdd(LHS, RHS, CxtI);
|
||||
case Instruction::Sub:
|
||||
if (IsSigned)
|
||||
return computeOverflowForSignedSub(LHS, RHS, CxtI);
|
||||
else
|
||||
return computeOverflowForUnsignedSub(LHS, RHS, CxtI);
|
||||
case Instruction::Mul:
|
||||
if (IsSigned)
|
||||
return computeOverflowForSignedMul(LHS, RHS, CxtI);
|
||||
else
|
||||
return computeOverflowForUnsignedMul(LHS, RHS, CxtI);
|
||||
}
|
||||
}
|
||||
|
||||
bool InstCombiner::OptimizeOverflowCheck(
|
||||
Instruction::BinaryOps BinaryOp, bool IsSigned, Value *LHS, Value *RHS,
|
||||
Instruction &OrigI, Value *&Result, Constant *&Overflow) {
|
||||
if (OrigI.isCommutative() && isa<Constant>(LHS) && !isa<Constant>(RHS))
|
||||
std::swap(LHS, RHS);
|
||||
|
||||
auto SetResult = [&](Value *OpResult, Constant *OverflowVal, bool ReuseName) {
|
||||
Result = OpResult;
|
||||
Overflow = OverflowVal;
|
||||
if (ReuseName)
|
||||
Result->takeName(&OrigI);
|
||||
return true;
|
||||
};
|
||||
|
||||
// If the overflow check was an add followed by a compare, the insertion point
|
||||
// may be pointing to the compare. We want to insert the new instructions
|
||||
// before the add in case there are uses of the add between the add and the
|
||||
// compare.
|
||||
Builder.SetInsertPoint(&OrigI);
|
||||
|
||||
switch (BinaryOp) {
|
||||
default:
|
||||
llvm_unreachable("unsupported binary op");
|
||||
|
||||
case Instruction::Add: {
|
||||
// X + 0 -> {X, false}
|
||||
if (match(RHS, m_Zero()))
|
||||
return SetResult(LHS, Builder.getFalse(), false);
|
||||
|
||||
OverflowResult OR;
|
||||
if (!IsSigned) {
|
||||
OR = computeOverflowForUnsignedAdd(LHS, RHS, &OrigI);
|
||||
if (OR == OverflowResult::NeverOverflows)
|
||||
return SetResult(Builder.CreateNUWAdd(LHS, RHS), Builder.getFalse(),
|
||||
true);
|
||||
} else {
|
||||
OR = computeOverflowForSignedAdd(LHS, RHS, &OrigI);
|
||||
if (OR == OverflowResult::NeverOverflows)
|
||||
return SetResult(Builder.CreateNSWAdd(LHS, RHS), Builder.getFalse(),
|
||||
true);
|
||||
}
|
||||
|
||||
if (OR == OverflowResult::AlwaysOverflows)
|
||||
return SetResult(Builder.CreateAdd(LHS, RHS), Builder.getTrue(), true);
|
||||
break;
|
||||
if (isNeutralValue(BinaryOp, RHS)) {
|
||||
Result = LHS;
|
||||
Overflow = Builder.getFalse();
|
||||
return true;
|
||||
}
|
||||
|
||||
case Instruction::Sub: {
|
||||
// X - 0 -> {X, false}
|
||||
if (match(RHS, m_Zero()))
|
||||
return SetResult(LHS, Builder.getFalse(), false);
|
||||
|
||||
OverflowResult OR;
|
||||
if (!IsSigned) {
|
||||
OR = computeOverflowForUnsignedSub(LHS, RHS, &OrigI);
|
||||
if (OR == OverflowResult::NeverOverflows)
|
||||
return SetResult(Builder.CreateNUWSub(LHS, RHS), Builder.getFalse(),
|
||||
true);
|
||||
} else {
|
||||
OR = computeOverflowForSignedSub(LHS, RHS, &OrigI);
|
||||
if (OR == OverflowResult::NeverOverflows)
|
||||
return SetResult(Builder.CreateNSWSub(LHS, RHS), Builder.getFalse(),
|
||||
true);
|
||||
}
|
||||
|
||||
if (OR == OverflowResult::AlwaysOverflows)
|
||||
return SetResult(Builder.CreateSub(LHS, RHS), Builder.getTrue(), true);
|
||||
break;
|
||||
switch (computeOverflow(BinaryOp, IsSigned, LHS, RHS, &OrigI)) {
|
||||
case OverflowResult::MayOverflow:
|
||||
return false;
|
||||
case OverflowResult::AlwaysOverflows:
|
||||
Result = Builder.CreateBinOp(BinaryOp, LHS, RHS);
|
||||
Result->takeName(&OrigI);
|
||||
Overflow = Builder.getTrue();
|
||||
return true;
|
||||
case OverflowResult::NeverOverflows:
|
||||
Result = Builder.CreateBinOp(BinaryOp, LHS, RHS);
|
||||
Result->takeName(&OrigI);
|
||||
Overflow = Builder.getFalse();
|
||||
if (auto *Inst = dyn_cast<Instruction>(Result)) {
|
||||
if (IsSigned)
|
||||
Inst->setHasNoSignedWrap();
|
||||
else
|
||||
Inst->setHasNoUnsignedWrap();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case Instruction::Mul: {
|
||||
// X * 1 -> {X, false}
|
||||
if (match(RHS, m_One()))
|
||||
return SetResult(LHS, Builder.getFalse(), false);
|
||||
|
||||
OverflowResult OR;
|
||||
if (!IsSigned) {
|
||||
OR = computeOverflowForUnsignedMul(LHS, RHS, &OrigI);
|
||||
if (OR == OverflowResult::NeverOverflows)
|
||||
return SetResult(Builder.CreateNUWMul(LHS, RHS), Builder.getFalse(),
|
||||
true);
|
||||
if (OR == OverflowResult::AlwaysOverflows)
|
||||
return SetResult(Builder.CreateMul(LHS, RHS), Builder.getTrue(), true);
|
||||
} else {
|
||||
OR = computeOverflowForSignedMul(LHS, RHS, &OrigI);
|
||||
if (OR == OverflowResult::NeverOverflows)
|
||||
return SetResult(Builder.CreateNSWMul(LHS, RHS), Builder.getFalse(),
|
||||
true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
llvm_unreachable("Unexpected overflow result");
|
||||
}
|
||||
|
||||
/// Recognize and process idiom involving test for multiplication
|
||||
|
|
|
@ -692,7 +692,7 @@ public:
|
|||
}
|
||||
|
||||
OverflowResult computeOverflowForSignedMul(const Value *LHS,
|
||||
const Value *RHS,
|
||||
const Value *RHS,
|
||||
const Instruction *CxtI) const {
|
||||
return llvm::computeOverflowForSignedMul(LHS, RHS, DL, &AC, CxtI, &DT);
|
||||
}
|
||||
|
@ -720,6 +720,10 @@ public:
|
|||
return llvm::computeOverflowForSignedSub(LHS, RHS, DL, &AC, CxtI, &DT);
|
||||
}
|
||||
|
||||
OverflowResult computeOverflow(
|
||||
Instruction::BinaryOps BinaryOp, bool IsSigned,
|
||||
Value *LHS, Value *RHS, Instruction *CxtI) const;
|
||||
|
||||
/// Maximum size of array considered when transforming.
|
||||
uint64_t MaxArraySizeForCombine;
|
||||
|
||||
|
|
Loading…
Reference in New Issue