From 926e1c019ad2c4f3e42d23280e8f6ce8158d86b9 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 26 May 2019 11:43:37 +0000 Subject: [PATCH] [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). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@361721 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineCompares.cpp | 138 ++++++++---------- .../InstCombine/InstCombineInternal.h | 6 +- 2 files changed, 65 insertions(+), 79 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index d848aef2552..ab2da177d7b 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -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(LHS) && !isa(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(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 diff --git a/lib/Transforms/InstCombine/InstCombineInternal.h b/lib/Transforms/InstCombine/InstCombineInternal.h index 123025bbccf..434b0d59121 100644 --- a/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/lib/Transforms/InstCombine/InstCombineInternal.h @@ -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; -- 2.50.1