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;
- }
-
- 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;
+ if (isNeutralValue(BinaryOp, RHS)) {
+ Result = LHS;
+ Overflow = Builder.getFalse();
+ 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;
- }
+ 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;
}
- return false;
+ llvm_unreachable("Unexpected overflow result");
}
/// Recognize and process idiom involving test for multiplication