//===-- SimplifyIndVar.cpp - Induction variable simplification ------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file implements induction variable simplification. It does // not define any actual pass or policy, but provides a single function to // simplify a loop's induction variables based on ScalarEvolution. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Utils/SimplifyIndVar.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/ValueTracking.h" #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" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/LoopUtils.h" #include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" usingnamespacellvm; usingnamespacellvm::PatternMatch; #define DEBUG_TYPE … STATISTIC(NumElimIdentity, "Number of IV identities eliminated"); STATISTIC(NumElimOperand, "Number of IV operands folded into a use"); STATISTIC(NumFoldedUser, "Number of IV users folded into a constant"); STATISTIC(NumElimRem , "Number of IV remainder operations eliminated"); STATISTIC( NumSimplifiedSDiv, "Number of IV signed division operations converted to unsigned division"); STATISTIC( NumSimplifiedSRem, "Number of IV signed remainder operations converted to unsigned remainder"); STATISTIC(NumElimCmp , "Number of IV comparisons eliminated"); namespace { /// This is a utility for simplifying induction variables /// based on ScalarEvolution. It is the primary instrument of the /// IndvarSimplify pass, but it may also be directly invoked to cleanup after /// other loop passes that preserve SCEV. class SimplifyIndvar { … }; } /// Find a point in code which dominates all given instructions. We can safely /// assume that, whatever fact we can prove at the found point, this fact is /// also true for each of the given instructions. static Instruction *findCommonDominator(ArrayRef<Instruction *> Instructions, DominatorTree &DT) { … } /// Fold an IV operand into its use. This removes increments of an /// aligned IV when used by a instruction that ignores the low bits. /// /// IVOperand is guaranteed SCEVable, but UseInst may not be. /// /// Return the operand of IVOperand for this induction variable if IVOperand can /// be folded (in case more folding opportunities have been exposed). /// Otherwise return null. Value *SimplifyIndvar::foldIVUser(Instruction *UseInst, Instruction *IVOperand) { … } bool SimplifyIndvar::makeIVComparisonInvariant(ICmpInst *ICmp, Instruction *IVOperand) { … } /// SimplifyIVUsers helper for eliminating useless /// comparisons against an induction variable. void SimplifyIndvar::eliminateIVComparison(ICmpInst *ICmp, Instruction *IVOperand) { … } bool SimplifyIndvar::eliminateSDiv(BinaryOperator *SDiv) { … } // i %s n -> i %u n if i >= 0 and n >= 0 void SimplifyIndvar::replaceSRemWithURem(BinaryOperator *Rem) { … } // i % n --> i if i is in [0,n). void SimplifyIndvar::replaceRemWithNumerator(BinaryOperator *Rem) { … } // (i+1) % n --> (i+1)==n?0:(i+1) if i is in [0,n). void SimplifyIndvar::replaceRemWithNumeratorOrZero(BinaryOperator *Rem) { … } /// SimplifyIVUsers helper for eliminating useless remainder operations /// operating on an induction variable or replacing srem by urem. void SimplifyIndvar::simplifyIVRemainder(BinaryOperator *Rem, Instruction *IVOperand, bool IsSigned) { … } bool SimplifyIndvar::eliminateOverflowIntrinsic(WithOverflowInst *WO) { … } bool SimplifyIndvar::eliminateSaturatingIntrinsic(SaturatingInst *SI) { … } bool SimplifyIndvar::eliminateTrunc(TruncInst *TI) { … } /// Eliminate an operation that consumes a simple IV and has no observable /// side-effect given the range of IV values. IVOperand is guaranteed SCEVable, /// but UseInst may not be. bool SimplifyIndvar::eliminateIVUser(Instruction *UseInst, Instruction *IVOperand) { … } static Instruction *GetLoopInvariantInsertPosition(Loop *L, Instruction *Hint) { … } /// Replace the UseInst with a loop invariant expression if it is safe. bool SimplifyIndvar::replaceIVUserWithLoopInvariant(Instruction *I) { … } /// Eliminate redundant type cast between integer and float. bool SimplifyIndvar::replaceFloatIVWithIntegerIV(Instruction *UseInst) { … } /// Eliminate any operation that SCEV can prove is an identity function. bool SimplifyIndvar::eliminateIdentitySCEV(Instruction *UseInst, Instruction *IVOperand) { … } bool SimplifyIndvar::strengthenBinaryOp(BinaryOperator *BO, Instruction *IVOperand) { … } /// Annotate BO with nsw / nuw if it provably does not signed-overflow / /// unsigned-overflow. Returns true if anything changed, false otherwise. bool SimplifyIndvar::strengthenOverflowingOperation(BinaryOperator *BO, Instruction *IVOperand) { … } /// Annotate the Shr in (X << IVOperand) >> C as exact using the /// information from the IV's range. Returns true if anything changed, false /// otherwise. bool SimplifyIndvar::strengthenRightShift(BinaryOperator *BO, Instruction *IVOperand) { … } /// Add all uses of Def to the current IV's worklist. void SimplifyIndvar::pushIVUsers( Instruction *Def, SmallPtrSet<Instruction *, 16> &Simplified, SmallVectorImpl<std::pair<Instruction *, Instruction *>> &SimpleIVUsers) { … } /// Return true if this instruction generates a simple SCEV /// expression in terms of that IV. /// /// This is similar to IVUsers' isInteresting() but processes each instruction /// non-recursively when the operand is already known to be a simpleIVUser. /// static bool isSimpleIVUser(Instruction *I, const Loop *L, ScalarEvolution *SE) { … } /// Iteratively perform simplification on a worklist of users /// of the specified induction variable. Each successive simplification may push /// more users which may themselves be candidates for simplification. /// /// This algorithm does not require IVUsers analysis. Instead, it simplifies /// instructions in-place during analysis. Rather than rewriting induction /// variables bottom-up from their users, it transforms a chain of IVUsers /// top-down, updating the IR only when it encounters a clear optimization /// opportunity. /// /// Once DisableIVRewrite is default, LSR will be the only client of IVUsers. /// void SimplifyIndvar::simplifyUsers(PHINode *CurrIV, IVVisitor *V) { … } namespace llvm { void IVVisitor::anchor() { … } /// Simplify instructions that use this induction variable /// by using ScalarEvolution to analyze the IV's recurrence. /// Returns a pair where the first entry indicates that the function makes /// changes and the second entry indicates that it introduced new opportunities /// for loop unswitching. std::pair<bool, bool> simplifyUsersOfIV(PHINode *CurrIV, ScalarEvolution *SE, DominatorTree *DT, LoopInfo *LI, const TargetTransformInfo *TTI, SmallVectorImpl<WeakTrackingVH> &Dead, SCEVExpander &Rewriter, IVVisitor *V) { … } /// Simplify users of induction variables within this /// loop. This does not actually change or add IVs. bool simplifyLoopIVs(Loop *L, ScalarEvolution *SE, DominatorTree *DT, LoopInfo *LI, const TargetTransformInfo *TTI, SmallVectorImpl<WeakTrackingVH> &Dead) { … } } // namespace llvm namespace { //===----------------------------------------------------------------------===// // Widen Induction Variables - Extend the width of an IV to cover its // widest uses. //===----------------------------------------------------------------------===// class WidenIV { … }; } // namespace /// Determine the insertion point for this user. By default, insert immediately /// before the user. SCEVExpander or LICM will hoist loop invariants out of the /// loop. For PHI nodes, there may be multiple uses, so compute the nearest /// common dominator for the incoming blocks. A nullptr can be returned if no /// viable location is found: it may happen if User is a PHI and Def only comes /// to this PHI from unreachable blocks. static Instruction *getInsertPointForUses(Instruction *User, Value *Def, DominatorTree *DT, LoopInfo *LI) { … } WidenIV::WidenIV(const WideIVInfo &WI, LoopInfo *LInfo, ScalarEvolution *SEv, DominatorTree *DTree, SmallVectorImpl<WeakTrackingVH> &DI, bool HasGuards, bool UsePostIncrementRanges) : … { … } Value *WidenIV::createExtendInst(Value *NarrowOper, Type *WideType, bool IsSigned, Instruction *Use) { … } /// Instantiate a wide operation to replace a narrow operation. This only needs /// to handle operations that can evaluation to SCEVAddRec. It can safely return /// 0 for any operation we decide not to clone. Instruction *WidenIV::cloneIVUser(WidenIV::NarrowIVDefUse DU, const SCEVAddRecExpr *WideAR) { … } Instruction *WidenIV::cloneBitwiseIVUser(WidenIV::NarrowIVDefUse DU) { … } Instruction *WidenIV::cloneArithmeticIVUser(WidenIV::NarrowIVDefUse DU, const SCEVAddRecExpr *WideAR) { … } WidenIV::ExtendKind WidenIV::getExtendKind(Instruction *I) { … } const SCEV *WidenIV::getSCEVByOpCode(const SCEV *LHS, const SCEV *RHS, unsigned OpCode) const { … } namespace { // Represents a interesting integer binary operation for // getExtendedOperandRecurrence. This may be a shl that is being treated as a // multiply or a 'or disjoint' that is being treated as 'add nsw nuw'. struct BinaryOp { … }; } // end anonymous namespace static std::optional<BinaryOp> matchBinaryOp(Instruction *Op) { … } /// No-wrap operations can transfer sign extension of their result to their /// operands. Generate the SCEV value for the widened operation without /// actually modifying the IR yet. If the expression after extending the /// operands is an AddRec for this loop, return the AddRec and the kind of /// extension used. WidenIV::WidenedRecTy WidenIV::getExtendedOperandRecurrence(WidenIV::NarrowIVDefUse DU) { … } /// Is this instruction potentially interesting for further simplification after /// widening it's type? In other words, can the extend be safely hoisted out of /// the loop with SCEV reducing the value to a recurrence on the same loop. If /// so, return the extended recurrence and the kind of extension used. Otherwise /// return {nullptr, ExtendKind::Unknown}. WidenIV::WidenedRecTy WidenIV::getWideRecurrence(WidenIV::NarrowIVDefUse DU) { … } /// This IV user cannot be widened. Replace this use of the original narrow IV /// with a truncation of the new wide IV to isolate and eliminate the narrow IV. void WidenIV::truncateIVUse(NarrowIVDefUse DU) { … } /// If the narrow use is a compare instruction, then widen the compare // (and possibly the other operand). The extend operation is hoisted into the // loop preheader as far as possible. bool WidenIV::widenLoopCompare(WidenIV::NarrowIVDefUse DU) { … } // The widenIVUse avoids generating trunc by evaluating the use as AddRec, this // will not work when: // 1) SCEV traces back to an instruction inside the loop that SCEV can not // expand, eg. add %indvar, (load %addr) // 2) SCEV finds a loop variant, eg. add %indvar, %loopvariant // While SCEV fails to avoid trunc, we can still try to use instruction // combining approach to prove trunc is not required. This can be further // extended with other instruction combining checks, but for now we handle the // following case (sub can be "add" and "mul", "nsw + sext" can be "nus + zext") // // Src: // %c = sub nsw %b, %indvar // %d = sext %c to i64 // Dst: // %indvar.ext1 = sext %indvar to i64 // %m = sext %b to i64 // %d = sub nsw i64 %m, %indvar.ext1 // Therefore, as long as the result of add/sub/mul is extended to wide type, no // trunc is required regardless of how %b is generated. This pattern is common // when calculating address in 64 bit architecture bool WidenIV::widenWithVariantUse(WidenIV::NarrowIVDefUse DU) { … } /// Determine whether an individual user of the narrow IV can be widened. If so, /// return the wide clone of the user. Instruction *WidenIV::widenIVUse(WidenIV::NarrowIVDefUse DU, SCEVExpander &Rewriter, PHINode *OrigPhi, PHINode *WidePhi) { … } /// Add eligible users of NarrowDef to NarrowIVUsers. void WidenIV::pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef) { … } /// Process a single induction variable. First use the SCEVExpander to create a /// wide induction variable that evaluates to the same recurrence as the /// original narrow IV. Then use a worklist to forward traverse the narrow IV's /// def-use chain. After widenIVUse has processed all interesting IV users, the /// narrow IV will be isolated for removal by DeleteDeadPHIs. /// /// It would be simpler to delete uses as they are processed, but we must avoid /// invalidating SCEV expressions. PHINode *WidenIV::createWideIV(SCEVExpander &Rewriter) { … } /// Calculates control-dependent range for the given def at the given context /// by looking at dominating conditions inside of the loop void WidenIV::calculatePostIncRange(Instruction *NarrowDef, Instruction *NarrowUser) { … } /// Calculates PostIncRangeInfos map for the given IV void WidenIV::calculatePostIncRanges(PHINode *OrigPhi) { … } PHINode *llvm::createWideIV(const WideIVInfo &WI, LoopInfo *LI, ScalarEvolution *SE, SCEVExpander &Rewriter, DominatorTree *DT, SmallVectorImpl<WeakTrackingVH> &DeadInsts, unsigned &NumElimExt, unsigned &NumWidened, bool HasGuards, bool UsePostIncrementRanges) { … }