diff options
Diffstat (limited to 'lib/Transforms/Utils/SimplifyIndVar.cpp')
-rw-r--r-- | lib/Transforms/Utils/SimplifyIndVar.cpp | 200 |
1 files changed, 85 insertions, 115 deletions
diff --git a/lib/Transforms/Utils/SimplifyIndVar.cpp b/lib/Transforms/Utils/SimplifyIndVar.cpp index 7faf291e73d9..cbb114f9a47a 100644 --- a/lib/Transforms/Utils/SimplifyIndVar.cpp +++ b/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -1,9 +1,8 @@ //===-- SimplifyIndVar.cpp - Induction variable simplification ------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -23,6 +22,7 @@ #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" @@ -80,7 +80,8 @@ namespace { bool eliminateIdentitySCEV(Instruction *UseInst, Instruction *IVOperand); bool replaceIVUserWithLoopInvariant(Instruction *UseInst); - bool eliminateOverflowIntrinsic(CallInst *CI); + bool eliminateOverflowIntrinsic(WithOverflowInst *WO); + bool eliminateSaturatingIntrinsic(SaturatingInst *SI); bool eliminateTrunc(TruncInst *TI); bool eliminateIVUser(Instruction *UseInst, Instruction *IVOperand); bool makeIVComparisonInvariant(ICmpInst *ICmp, Value *IVOperand); @@ -401,61 +402,29 @@ void SimplifyIndvar::simplifyIVRemainder(BinaryOperator *Rem, Value *IVOperand, replaceSRemWithURem(Rem); } -bool SimplifyIndvar::eliminateOverflowIntrinsic(CallInst *CI) { - auto *F = CI->getCalledFunction(); - if (!F) - return false; - - typedef const SCEV *(ScalarEvolution::*OperationFunctionTy)( - const SCEV *, const SCEV *, SCEV::NoWrapFlags, unsigned); - typedef const SCEV *(ScalarEvolution::*ExtensionFunctionTy)( - const SCEV *, Type *, unsigned); - - OperationFunctionTy Operation; - ExtensionFunctionTy Extension; - - Instruction::BinaryOps RawOp; - - // We always have exactly one of nsw or nuw. If NoSignedOverflow is false, we - // have nuw. - bool NoSignedOverflow; - - switch (F->getIntrinsicID()) { +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: - return false; - - case Intrinsic::sadd_with_overflow: - Operation = &ScalarEvolution::getAddExpr; - Extension = &ScalarEvolution::getSignExtendExpr; - RawOp = Instruction::Add; - NoSignedOverflow = true; - break; - - case Intrinsic::uadd_with_overflow: + llvm_unreachable("Unsupported binary op"); + case Instruction::Add: Operation = &ScalarEvolution::getAddExpr; - Extension = &ScalarEvolution::getZeroExtendExpr; - RawOp = Instruction::Add; - NoSignedOverflow = false; break; - - case Intrinsic::ssub_with_overflow: + case Instruction::Sub: Operation = &ScalarEvolution::getMinusSCEV; - Extension = &ScalarEvolution::getSignExtendExpr; - RawOp = Instruction::Sub; - NoSignedOverflow = true; break; - - case Intrinsic::usub_with_overflow: - Operation = &ScalarEvolution::getMinusSCEV; - Extension = &ScalarEvolution::getZeroExtendExpr; - RawOp = Instruction::Sub; - NoSignedOverflow = false; + case Instruction::Mul: + Operation = &ScalarEvolution::getMulExpr; break; } - const SCEV *LHS = SE->getSCEV(CI->getArgOperand(0)); - const SCEV *RHS = SE->getSCEV(CI->getArgOperand(1)); + 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); @@ -466,27 +435,32 @@ bool SimplifyIndvar::eliminateOverflowIntrinsic(CallInst *CI) { const SCEV *B = (SE->*Operation)((SE->*Extension)(LHS, WideTy, 0), (SE->*Extension)(RHS, WideTy, 0), SCEV::FlagAnyWrap, 0); + return A == B; +} - if (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)) return false; // Proved no overflow, nuke the overflow check and, if possible, the overflow // intrinsic as well. BinaryOperator *NewResult = BinaryOperator::Create( - RawOp, CI->getArgOperand(0), CI->getArgOperand(1), "", CI); + WO->getBinaryOp(), WO->getLHS(), WO->getRHS(), "", WO); - if (NoSignedOverflow) + if (WO->isSigned()) NewResult->setHasNoSignedWrap(true); else NewResult->setHasNoUnsignedWrap(true); SmallVector<ExtractValueInst *, 4> ToDelete; - for (auto *U : CI->users()) { + for (auto *U : WO->users()) { if (auto *EVI = dyn_cast<ExtractValueInst>(U)) { if (EVI->getIndices()[0] == 1) - EVI->replaceAllUsesWith(ConstantInt::getFalse(CI->getContext())); + EVI->replaceAllUsesWith(ConstantInt::getFalse(WO->getContext())); else { assert(EVI->getIndices()[0] == 0 && "Only two possibilities!"); EVI->replaceAllUsesWith(NewResult); @@ -498,9 +472,28 @@ bool SimplifyIndvar::eliminateOverflowIntrinsic(CallInst *CI) { for (auto *EVI : ToDelete) EVI->eraseFromParent(); - if (CI->use_empty()) - CI->eraseFromParent(); + if (WO->use_empty()) + WO->eraseFromParent(); + + return true; +} + +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)) + return false; + + BinaryOperator *BO = BinaryOperator::Create( + SI->getBinaryOp(), SI->getLHS(), SI->getRHS(), SI->getName(), SI); + if (SI->isSigned()) + BO->setHasNoSignedWrap(); + else + BO->setHasNoUnsignedWrap(); + SI->replaceAllUsesWith(BO); + DeadInsts.emplace_back(SI); + Changed = true; return true; } @@ -548,20 +541,19 @@ bool SimplifyIndvar::eliminateTrunc(TruncInst *TI) { if (isa<Instruction>(U) && !DT->isReachableFromEntry(cast<Instruction>(U)->getParent())) continue; - if (ICmpInst *ICI = dyn_cast<ICmpInst>(U)) { - if (ICI->getOperand(0) == TI && L->isLoopInvariant(ICI->getOperand(1))) { - assert(L->contains(ICI->getParent()) && "LCSSA form broken?"); - // If we cannot get rid of trunc, bail. - if (ICI->isSigned() && !DoesSExtCollapse) - return false; - if (ICI->isUnsigned() && !DoesZExtCollapse) - return false; - // For equality, either signed or unsigned works. - ICmpUsers.push_back(ICI); - } else - return false; - } else + ICmpInst *ICI = dyn_cast<ICmpInst>(U); + if (!ICI) return false; + assert(L->contains(ICI->getParent()) && "LCSSA form broken?"); + if (!(ICI->getOperand(0) == TI && L->isLoopInvariant(ICI->getOperand(1))) && + !(ICI->getOperand(1) == TI && L->isLoopInvariant(ICI->getOperand(0)))) return false; + // If we cannot get rid of trunc, bail. + if (ICI->isSigned() && !DoesSExtCollapse) + return false; + if (ICI->isUnsigned() && !DoesZExtCollapse) + return false; + // For equality, either signed or unsigned works. + ICmpUsers.push_back(ICI); } auto CanUseZExt = [&](ICmpInst *ICI) { @@ -584,7 +576,8 @@ bool SimplifyIndvar::eliminateTrunc(TruncInst *TI) { }; // Replace all comparisons against trunc with comparisons against IV. for (auto *ICI : ICmpUsers) { - auto *Op1 = ICI->getOperand(1); + bool IsSwapped = L->isLoopInvariant(ICI->getOperand(0)); + auto *Op1 = IsSwapped ? ICI->getOperand(0) : ICI->getOperand(1); Instruction *Ext = nullptr; // For signed/unsigned predicate, replace the old comparison with comparison // of immediate IV against sext/zext of the invariant argument. If we can @@ -593,6 +586,7 @@ bool SimplifyIndvar::eliminateTrunc(TruncInst *TI) { // TODO: If we see a signed comparison which can be turned into unsigned, // we can do it here for canonicalization purposes. ICmpInst::Predicate Pred = ICI->getPredicate(); + if (IsSwapped) Pred = ICmpInst::getSwappedPredicate(Pred); if (CanUseZExt(ICI)) { assert(DoesZExtCollapse && "Unprofitable zext?"); Ext = new ZExtInst(Op1, IVTy, "zext", ICI); @@ -636,8 +630,12 @@ bool SimplifyIndvar::eliminateIVUser(Instruction *UseInst, return eliminateSDiv(Bin); } - if (auto *CI = dyn_cast<CallInst>(UseInst)) - if (eliminateOverflowIntrinsic(CI)) + if (auto *WO = dyn_cast<WithOverflowInst>(UseInst)) + if (eliminateOverflowIntrinsic(WO)) + return true; + + if (auto *SI = dyn_cast<SaturatingInst>(UseInst)) + if (eliminateSaturatingIntrinsic(SI)) return true; if (auto *TI = dyn_cast<TruncInst>(UseInst)) @@ -730,59 +728,31 @@ 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; - const SCEV *(ScalarEvolution::*GetExprForBO)(const SCEV *, const SCEV *, - SCEV::NoWrapFlags, unsigned); - switch (BO->getOpcode()) { - default: + if (BO->getOpcode() != Instruction::Add && + BO->getOpcode() != Instruction::Sub && + BO->getOpcode() != Instruction::Mul) return false; - case Instruction::Add: - GetExprForBO = &ScalarEvolution::getAddExpr; - break; - - case Instruction::Sub: - GetExprForBO = &ScalarEvolution::getMinusSCEV; - break; - - case Instruction::Mul: - GetExprForBO = &ScalarEvolution::getMulExpr; - break; - } - - unsigned BitWidth = cast<IntegerType>(BO->getType())->getBitWidth(); - Type *WideTy = IntegerType::get(BO->getContext(), BitWidth * 2); const SCEV *LHS = SE->getSCEV(BO->getOperand(0)); const SCEV *RHS = SE->getSCEV(BO->getOperand(1)); - bool Changed = false; - if (!BO->hasNoUnsignedWrap()) { - const SCEV *ExtendAfterOp = SE->getZeroExtendExpr(SE->getSCEV(BO), WideTy); - const SCEV *OpAfterExtend = (SE->*GetExprForBO)( - SE->getZeroExtendExpr(LHS, WideTy), SE->getZeroExtendExpr(RHS, WideTy), - SCEV::FlagAnyWrap, 0u); - if (ExtendAfterOp == OpAfterExtend) { - BO->setHasNoUnsignedWrap(); - SE->forgetValue(BO); - Changed = true; - } + if (!BO->hasNoUnsignedWrap() && + willNotOverflow(SE, BO->getOpcode(), /* Signed */ false, LHS, RHS)) { + BO->setHasNoUnsignedWrap(); + SE->forgetValue(BO); + Changed = true; } - if (!BO->hasNoSignedWrap()) { - const SCEV *ExtendAfterOp = SE->getSignExtendExpr(SE->getSCEV(BO), WideTy); - const SCEV *OpAfterExtend = (SE->*GetExprForBO)( - SE->getSignExtendExpr(LHS, WideTy), SE->getSignExtendExpr(RHS, WideTy), - SCEV::FlagAnyWrap, 0u); - if (ExtendAfterOp == OpAfterExtend) { - BO->setHasNoSignedWrap(); - SE->forgetValue(BO); - Changed = true; - } + if (!BO->hasNoSignedWrap() && + willNotOverflow(SE, BO->getOpcode(), /* Signed */ true, LHS, RHS)) { + BO->setHasNoSignedWrap(); + SE->forgetValue(BO); + Changed = true; } return Changed; |