12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670 |
- //===- LoopUnroll.cpp - Loop unroller pass --------------------------------===//
- //
- // 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 pass implements a simple loop unroller. It works best when loops have
- // been canonicalized by the -indvars pass, allowing it to determine the trip
- // counts of loops easily.
- //===----------------------------------------------------------------------===//
- #include "llvm/Transforms/Scalar/LoopUnrollPass.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/DenseMapInfo.h"
- #include "llvm/ADT/DenseSet.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SetVector.h"
- #include "llvm/ADT/SmallPtrSet.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/Analysis/AssumptionCache.h"
- #include "llvm/Analysis/BlockFrequencyInfo.h"
- #include "llvm/Analysis/CodeMetrics.h"
- #include "llvm/Analysis/LoopAnalysisManager.h"
- #include "llvm/Analysis/LoopInfo.h"
- #include "llvm/Analysis/LoopPass.h"
- #include "llvm/Analysis/LoopUnrollAnalyzer.h"
- #include "llvm/Analysis/OptimizationRemarkEmitter.h"
- #include "llvm/Analysis/ProfileSummaryInfo.h"
- #include "llvm/Analysis/ScalarEvolution.h"
- #include "llvm/Analysis/TargetTransformInfo.h"
- #include "llvm/IR/BasicBlock.h"
- #include "llvm/IR/CFG.h"
- #include "llvm/IR/Constant.h"
- #include "llvm/IR/Constants.h"
- #include "llvm/IR/DiagnosticInfo.h"
- #include "llvm/IR/Dominators.h"
- #include "llvm/IR/Function.h"
- #include "llvm/IR/Instruction.h"
- #include "llvm/IR/Instructions.h"
- #include "llvm/IR/IntrinsicInst.h"
- #include "llvm/IR/Metadata.h"
- #include "llvm/IR/PassManager.h"
- #include "llvm/InitializePasses.h"
- #include "llvm/Pass.h"
- #include "llvm/Support/Casting.h"
- #include "llvm/Support/CommandLine.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/raw_ostream.h"
- #include "llvm/Transforms/Scalar.h"
- #include "llvm/Transforms/Scalar/LoopPassManager.h"
- #include "llvm/Transforms/Utils.h"
- #include "llvm/Transforms/Utils/LoopPeel.h"
- #include "llvm/Transforms/Utils/LoopSimplify.h"
- #include "llvm/Transforms/Utils/LoopUtils.h"
- #include "llvm/Transforms/Utils/SizeOpts.h"
- #include "llvm/Transforms/Utils/UnrollLoop.h"
- #include <algorithm>
- #include <cassert>
- #include <cstdint>
- #include <limits>
- #include <optional>
- #include <string>
- #include <tuple>
- #include <utility>
- using namespace llvm;
- #define DEBUG_TYPE "loop-unroll"
- cl::opt<bool> llvm::ForgetSCEVInLoopUnroll(
- "forget-scev-loop-unroll", cl::init(false), cl::Hidden,
- cl::desc("Forget everything in SCEV when doing LoopUnroll, instead of just"
- " the current top-most loop. This is sometimes preferred to reduce"
- " compile time."));
- static cl::opt<unsigned>
- UnrollThreshold("unroll-threshold", cl::Hidden,
- cl::desc("The cost threshold for loop unrolling"));
- static cl::opt<unsigned>
- UnrollOptSizeThreshold(
- "unroll-optsize-threshold", cl::init(0), cl::Hidden,
- cl::desc("The cost threshold for loop unrolling when optimizing for "
- "size"));
- static cl::opt<unsigned> UnrollPartialThreshold(
- "unroll-partial-threshold", cl::Hidden,
- cl::desc("The cost threshold for partial loop unrolling"));
- static cl::opt<unsigned> UnrollMaxPercentThresholdBoost(
- "unroll-max-percent-threshold-boost", cl::init(400), cl::Hidden,
- cl::desc("The maximum 'boost' (represented as a percentage >= 100) applied "
- "to the threshold when aggressively unrolling a loop due to the "
- "dynamic cost savings. If completely unrolling a loop will reduce "
- "the total runtime from X to Y, we boost the loop unroll "
- "threshold to DefaultThreshold*std::min(MaxPercentThresholdBoost, "
- "X/Y). This limit avoids excessive code bloat."));
- static cl::opt<unsigned> UnrollMaxIterationsCountToAnalyze(
- "unroll-max-iteration-count-to-analyze", cl::init(10), cl::Hidden,
- cl::desc("Don't allow loop unrolling to simulate more than this number of"
- "iterations when checking full unroll profitability"));
- static cl::opt<unsigned> UnrollCount(
- "unroll-count", cl::Hidden,
- cl::desc("Use this unroll count for all loops including those with "
- "unroll_count pragma values, for testing purposes"));
- static cl::opt<unsigned> UnrollMaxCount(
- "unroll-max-count", cl::Hidden,
- cl::desc("Set the max unroll count for partial and runtime unrolling, for"
- "testing purposes"));
- static cl::opt<unsigned> UnrollFullMaxCount(
- "unroll-full-max-count", cl::Hidden,
- cl::desc(
- "Set the max unroll count for full unrolling, for testing purposes"));
- static cl::opt<bool>
- UnrollAllowPartial("unroll-allow-partial", cl::Hidden,
- cl::desc("Allows loops to be partially unrolled until "
- "-unroll-threshold loop size is reached."));
- static cl::opt<bool> UnrollAllowRemainder(
- "unroll-allow-remainder", cl::Hidden,
- cl::desc("Allow generation of a loop remainder (extra iterations) "
- "when unrolling a loop."));
- static cl::opt<bool>
- UnrollRuntime("unroll-runtime", cl::Hidden,
- cl::desc("Unroll loops with run-time trip counts"));
- static cl::opt<unsigned> UnrollMaxUpperBound(
- "unroll-max-upperbound", cl::init(8), cl::Hidden,
- cl::desc(
- "The max of trip count upper bound that is considered in unrolling"));
- static cl::opt<unsigned> PragmaUnrollThreshold(
- "pragma-unroll-threshold", cl::init(16 * 1024), cl::Hidden,
- cl::desc("Unrolled size limit for loops with an unroll(full) or "
- "unroll_count pragma."));
- static cl::opt<unsigned> FlatLoopTripCountThreshold(
- "flat-loop-tripcount-threshold", cl::init(5), cl::Hidden,
- cl::desc("If the runtime tripcount for the loop is lower than the "
- "threshold, the loop is considered as flat and will be less "
- "aggressively unrolled."));
- static cl::opt<bool> UnrollUnrollRemainder(
- "unroll-remainder", cl::Hidden,
- cl::desc("Allow the loop remainder to be unrolled."));
- // This option isn't ever intended to be enabled, it serves to allow
- // experiments to check the assumptions about when this kind of revisit is
- // necessary.
- static cl::opt<bool> UnrollRevisitChildLoops(
- "unroll-revisit-child-loops", cl::Hidden,
- cl::desc("Enqueue and re-visit child loops in the loop PM after unrolling. "
- "This shouldn't typically be needed as child loops (or their "
- "clones) were already visited."));
- static cl::opt<unsigned> UnrollThresholdAggressive(
- "unroll-threshold-aggressive", cl::init(300), cl::Hidden,
- cl::desc("Threshold (max size of unrolled loop) to use in aggressive (O3) "
- "optimizations"));
- static cl::opt<unsigned>
- UnrollThresholdDefault("unroll-threshold-default", cl::init(150),
- cl::Hidden,
- cl::desc("Default threshold (max size of unrolled "
- "loop), used in all but O3 optimizations"));
- /// A magic value for use with the Threshold parameter to indicate
- /// that the loop unroll should be performed regardless of how much
- /// code expansion would result.
- static const unsigned NoThreshold = std::numeric_limits<unsigned>::max();
- /// Gather the various unrolling parameters based on the defaults, compiler
- /// flags, TTI overrides and user specified parameters.
- TargetTransformInfo::UnrollingPreferences llvm::gatherUnrollingPreferences(
- Loop *L, ScalarEvolution &SE, const TargetTransformInfo &TTI,
- BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI,
- OptimizationRemarkEmitter &ORE, int OptLevel,
- std::optional<unsigned> UserThreshold, std::optional<unsigned> UserCount,
- std::optional<bool> UserAllowPartial, std::optional<bool> UserRuntime,
- std::optional<bool> UserUpperBound,
- std::optional<unsigned> UserFullUnrollMaxCount) {
- TargetTransformInfo::UnrollingPreferences UP;
- // Set up the defaults
- UP.Threshold =
- OptLevel > 2 ? UnrollThresholdAggressive : UnrollThresholdDefault;
- UP.MaxPercentThresholdBoost = 400;
- UP.OptSizeThreshold = UnrollOptSizeThreshold;
- UP.PartialThreshold = 150;
- UP.PartialOptSizeThreshold = UnrollOptSizeThreshold;
- UP.Count = 0;
- UP.DefaultUnrollRuntimeCount = 8;
- UP.MaxCount = std::numeric_limits<unsigned>::max();
- UP.FullUnrollMaxCount = std::numeric_limits<unsigned>::max();
- UP.BEInsns = 2;
- UP.Partial = false;
- UP.Runtime = false;
- UP.AllowRemainder = true;
- UP.UnrollRemainder = false;
- UP.AllowExpensiveTripCount = false;
- UP.Force = false;
- UP.UpperBound = false;
- UP.UnrollAndJam = false;
- UP.UnrollAndJamInnerLoopThreshold = 60;
- UP.MaxIterationsCountToAnalyze = UnrollMaxIterationsCountToAnalyze;
- // Override with any target specific settings
- TTI.getUnrollingPreferences(L, SE, UP, &ORE);
- // Apply size attributes
- bool OptForSize = L->getHeader()->getParent()->hasOptSize() ||
- // Let unroll hints / pragmas take precedence over PGSO.
- (hasUnrollTransformation(L) != TM_ForcedByUser &&
- llvm::shouldOptimizeForSize(L->getHeader(), PSI, BFI,
- PGSOQueryType::IRPass));
- if (OptForSize) {
- UP.Threshold = UP.OptSizeThreshold;
- UP.PartialThreshold = UP.PartialOptSizeThreshold;
- UP.MaxPercentThresholdBoost = 100;
- }
- // Apply any user values specified by cl::opt
- if (UnrollThreshold.getNumOccurrences() > 0)
- UP.Threshold = UnrollThreshold;
- if (UnrollPartialThreshold.getNumOccurrences() > 0)
- UP.PartialThreshold = UnrollPartialThreshold;
- if (UnrollMaxPercentThresholdBoost.getNumOccurrences() > 0)
- UP.MaxPercentThresholdBoost = UnrollMaxPercentThresholdBoost;
- if (UnrollMaxCount.getNumOccurrences() > 0)
- UP.MaxCount = UnrollMaxCount;
- if (UnrollFullMaxCount.getNumOccurrences() > 0)
- UP.FullUnrollMaxCount = UnrollFullMaxCount;
- if (UnrollAllowPartial.getNumOccurrences() > 0)
- UP.Partial = UnrollAllowPartial;
- if (UnrollAllowRemainder.getNumOccurrences() > 0)
- UP.AllowRemainder = UnrollAllowRemainder;
- if (UnrollRuntime.getNumOccurrences() > 0)
- UP.Runtime = UnrollRuntime;
- if (UnrollMaxUpperBound == 0)
- UP.UpperBound = false;
- if (UnrollUnrollRemainder.getNumOccurrences() > 0)
- UP.UnrollRemainder = UnrollUnrollRemainder;
- if (UnrollMaxIterationsCountToAnalyze.getNumOccurrences() > 0)
- UP.MaxIterationsCountToAnalyze = UnrollMaxIterationsCountToAnalyze;
- // Apply user values provided by argument
- if (UserThreshold) {
- UP.Threshold = *UserThreshold;
- UP.PartialThreshold = *UserThreshold;
- }
- if (UserCount)
- UP.Count = *UserCount;
- if (UserAllowPartial)
- UP.Partial = *UserAllowPartial;
- if (UserRuntime)
- UP.Runtime = *UserRuntime;
- if (UserUpperBound)
- UP.UpperBound = *UserUpperBound;
- if (UserFullUnrollMaxCount)
- UP.FullUnrollMaxCount = *UserFullUnrollMaxCount;
- return UP;
- }
- namespace {
- /// A struct to densely store the state of an instruction after unrolling at
- /// each iteration.
- ///
- /// This is designed to work like a tuple of <Instruction *, int> for the
- /// purposes of hashing and lookup, but to be able to associate two boolean
- /// states with each key.
- struct UnrolledInstState {
- Instruction *I;
- int Iteration : 30;
- unsigned IsFree : 1;
- unsigned IsCounted : 1;
- };
- /// Hashing and equality testing for a set of the instruction states.
- struct UnrolledInstStateKeyInfo {
- using PtrInfo = DenseMapInfo<Instruction *>;
- using PairInfo = DenseMapInfo<std::pair<Instruction *, int>>;
- static inline UnrolledInstState getEmptyKey() {
- return {PtrInfo::getEmptyKey(), 0, 0, 0};
- }
- static inline UnrolledInstState getTombstoneKey() {
- return {PtrInfo::getTombstoneKey(), 0, 0, 0};
- }
- static inline unsigned getHashValue(const UnrolledInstState &S) {
- return PairInfo::getHashValue({S.I, S.Iteration});
- }
- static inline bool isEqual(const UnrolledInstState &LHS,
- const UnrolledInstState &RHS) {
- return PairInfo::isEqual({LHS.I, LHS.Iteration}, {RHS.I, RHS.Iteration});
- }
- };
- struct EstimatedUnrollCost {
- /// The estimated cost after unrolling.
- unsigned UnrolledCost;
- /// The estimated dynamic cost of executing the instructions in the
- /// rolled form.
- unsigned RolledDynamicCost;
- };
- struct PragmaInfo {
- PragmaInfo(bool UUC, bool PFU, unsigned PC, bool PEU)
- : UserUnrollCount(UUC), PragmaFullUnroll(PFU), PragmaCount(PC),
- PragmaEnableUnroll(PEU) {}
- const bool UserUnrollCount;
- const bool PragmaFullUnroll;
- const unsigned PragmaCount;
- const bool PragmaEnableUnroll;
- };
- } // end anonymous namespace
- /// Figure out if the loop is worth full unrolling.
- ///
- /// Complete loop unrolling can make some loads constant, and we need to know
- /// if that would expose any further optimization opportunities. This routine
- /// estimates this optimization. It computes cost of unrolled loop
- /// (UnrolledCost) and dynamic cost of the original loop (RolledDynamicCost). By
- /// dynamic cost we mean that we won't count costs of blocks that are known not
- /// to be executed (i.e. if we have a branch in the loop and we know that at the
- /// given iteration its condition would be resolved to true, we won't add up the
- /// cost of the 'false'-block).
- /// \returns Optional value, holding the RolledDynamicCost and UnrolledCost. If
- /// the analysis failed (no benefits expected from the unrolling, or the loop is
- /// too big to analyze), the returned value is std::nullopt.
- static std::optional<EstimatedUnrollCost> analyzeLoopUnrollCost(
- const Loop *L, unsigned TripCount, DominatorTree &DT, ScalarEvolution &SE,
- const SmallPtrSetImpl<const Value *> &EphValues,
- const TargetTransformInfo &TTI, unsigned MaxUnrolledLoopSize,
- unsigned MaxIterationsCountToAnalyze) {
- // We want to be able to scale offsets by the trip count and add more offsets
- // to them without checking for overflows, and we already don't want to
- // analyze *massive* trip counts, so we force the max to be reasonably small.
- assert(MaxIterationsCountToAnalyze <
- (unsigned)(std::numeric_limits<int>::max() / 2) &&
- "The unroll iterations max is too large!");
- // Only analyze inner loops. We can't properly estimate cost of nested loops
- // and we won't visit inner loops again anyway.
- if (!L->isInnermost())
- return std::nullopt;
- // Don't simulate loops with a big or unknown tripcount
- if (!TripCount || TripCount > MaxIterationsCountToAnalyze)
- return std::nullopt;
- SmallSetVector<BasicBlock *, 16> BBWorklist;
- SmallSetVector<std::pair<BasicBlock *, BasicBlock *>, 4> ExitWorklist;
- DenseMap<Value *, Value *> SimplifiedValues;
- SmallVector<std::pair<Value *, Value *>, 4> SimplifiedInputValues;
- // The estimated cost of the unrolled form of the loop. We try to estimate
- // this by simplifying as much as we can while computing the estimate.
- InstructionCost UnrolledCost = 0;
- // We also track the estimated dynamic (that is, actually executed) cost in
- // the rolled form. This helps identify cases when the savings from unrolling
- // aren't just exposing dead control flows, but actual reduced dynamic
- // instructions due to the simplifications which we expect to occur after
- // unrolling.
- InstructionCost RolledDynamicCost = 0;
- // We track the simplification of each instruction in each iteration. We use
- // this to recursively merge costs into the unrolled cost on-demand so that
- // we don't count the cost of any dead code. This is essentially a map from
- // <instruction, int> to <bool, bool>, but stored as a densely packed struct.
- DenseSet<UnrolledInstState, UnrolledInstStateKeyInfo> InstCostMap;
- // A small worklist used to accumulate cost of instructions from each
- // observable and reached root in the loop.
- SmallVector<Instruction *, 16> CostWorklist;
- // PHI-used worklist used between iterations while accumulating cost.
- SmallVector<Instruction *, 4> PHIUsedList;
- // Helper function to accumulate cost for instructions in the loop.
- auto AddCostRecursively = [&](Instruction &RootI, int Iteration) {
- assert(Iteration >= 0 && "Cannot have a negative iteration!");
- assert(CostWorklist.empty() && "Must start with an empty cost list");
- assert(PHIUsedList.empty() && "Must start with an empty phi used list");
- CostWorklist.push_back(&RootI);
- TargetTransformInfo::TargetCostKind CostKind =
- RootI.getFunction()->hasMinSize() ?
- TargetTransformInfo::TCK_CodeSize :
- TargetTransformInfo::TCK_SizeAndLatency;
- for (;; --Iteration) {
- do {
- Instruction *I = CostWorklist.pop_back_val();
- // InstCostMap only uses I and Iteration as a key, the other two values
- // don't matter here.
- auto CostIter = InstCostMap.find({I, Iteration, 0, 0});
- if (CostIter == InstCostMap.end())
- // If an input to a PHI node comes from a dead path through the loop
- // we may have no cost data for it here. What that actually means is
- // that it is free.
- continue;
- auto &Cost = *CostIter;
- if (Cost.IsCounted)
- // Already counted this instruction.
- continue;
- // Mark that we are counting the cost of this instruction now.
- Cost.IsCounted = true;
- // If this is a PHI node in the loop header, just add it to the PHI set.
- if (auto *PhiI = dyn_cast<PHINode>(I))
- if (PhiI->getParent() == L->getHeader()) {
- assert(Cost.IsFree && "Loop PHIs shouldn't be evaluated as they "
- "inherently simplify during unrolling.");
- if (Iteration == 0)
- continue;
- // Push the incoming value from the backedge into the PHI used list
- // if it is an in-loop instruction. We'll use this to populate the
- // cost worklist for the next iteration (as we count backwards).
- if (auto *OpI = dyn_cast<Instruction>(
- PhiI->getIncomingValueForBlock(L->getLoopLatch())))
- if (L->contains(OpI))
- PHIUsedList.push_back(OpI);
- continue;
- }
- // First accumulate the cost of this instruction.
- if (!Cost.IsFree) {
- UnrolledCost += TTI.getInstructionCost(I, CostKind);
- LLVM_DEBUG(dbgs() << "Adding cost of instruction (iteration "
- << Iteration << "): ");
- LLVM_DEBUG(I->dump());
- }
- // We must count the cost of every operand which is not free,
- // recursively. If we reach a loop PHI node, simply add it to the set
- // to be considered on the next iteration (backwards!).
- for (Value *Op : I->operands()) {
- // Check whether this operand is free due to being a constant or
- // outside the loop.
- auto *OpI = dyn_cast<Instruction>(Op);
- if (!OpI || !L->contains(OpI))
- continue;
- // Otherwise accumulate its cost.
- CostWorklist.push_back(OpI);
- }
- } while (!CostWorklist.empty());
- if (PHIUsedList.empty())
- // We've exhausted the search.
- break;
- assert(Iteration > 0 &&
- "Cannot track PHI-used values past the first iteration!");
- CostWorklist.append(PHIUsedList.begin(), PHIUsedList.end());
- PHIUsedList.clear();
- }
- };
- // Ensure that we don't violate the loop structure invariants relied on by
- // this analysis.
- assert(L->isLoopSimplifyForm() && "Must put loop into normal form first.");
- assert(L->isLCSSAForm(DT) &&
- "Must have loops in LCSSA form to track live-out values.");
- LLVM_DEBUG(dbgs() << "Starting LoopUnroll profitability analysis...\n");
- TargetTransformInfo::TargetCostKind CostKind =
- L->getHeader()->getParent()->hasMinSize() ?
- TargetTransformInfo::TCK_CodeSize : TargetTransformInfo::TCK_SizeAndLatency;
- // Simulate execution of each iteration of the loop counting instructions,
- // which would be simplified.
- // Since the same load will take different values on different iterations,
- // we literally have to go through all loop's iterations.
- for (unsigned Iteration = 0; Iteration < TripCount; ++Iteration) {
- LLVM_DEBUG(dbgs() << " Analyzing iteration " << Iteration << "\n");
- // Prepare for the iteration by collecting any simplified entry or backedge
- // inputs.
- for (Instruction &I : *L->getHeader()) {
- auto *PHI = dyn_cast<PHINode>(&I);
- if (!PHI)
- break;
- // The loop header PHI nodes must have exactly two input: one from the
- // loop preheader and one from the loop latch.
- assert(
- PHI->getNumIncomingValues() == 2 &&
- "Must have an incoming value only for the preheader and the latch.");
- Value *V = PHI->getIncomingValueForBlock(
- Iteration == 0 ? L->getLoopPreheader() : L->getLoopLatch());
- if (Iteration != 0 && SimplifiedValues.count(V))
- V = SimplifiedValues.lookup(V);
- SimplifiedInputValues.push_back({PHI, V});
- }
- // Now clear and re-populate the map for the next iteration.
- SimplifiedValues.clear();
- while (!SimplifiedInputValues.empty())
- SimplifiedValues.insert(SimplifiedInputValues.pop_back_val());
- UnrolledInstAnalyzer Analyzer(Iteration, SimplifiedValues, SE, L);
- BBWorklist.clear();
- BBWorklist.insert(L->getHeader());
- // Note that we *must not* cache the size, this loop grows the worklist.
- for (unsigned Idx = 0; Idx != BBWorklist.size(); ++Idx) {
- BasicBlock *BB = BBWorklist[Idx];
- // Visit all instructions in the given basic block and try to simplify
- // it. We don't change the actual IR, just count optimization
- // opportunities.
- for (Instruction &I : *BB) {
- // These won't get into the final code - don't even try calculating the
- // cost for them.
- if (isa<DbgInfoIntrinsic>(I) || EphValues.count(&I))
- continue;
- // Track this instruction's expected baseline cost when executing the
- // rolled loop form.
- RolledDynamicCost += TTI.getInstructionCost(&I, CostKind);
- // Visit the instruction to analyze its loop cost after unrolling,
- // and if the visitor returns true, mark the instruction as free after
- // unrolling and continue.
- bool IsFree = Analyzer.visit(I);
- bool Inserted = InstCostMap.insert({&I, (int)Iteration,
- (unsigned)IsFree,
- /*IsCounted*/ false}).second;
- (void)Inserted;
- assert(Inserted && "Cannot have a state for an unvisited instruction!");
- if (IsFree)
- continue;
- // Can't properly model a cost of a call.
- // FIXME: With a proper cost model we should be able to do it.
- if (auto *CI = dyn_cast<CallInst>(&I)) {
- const Function *Callee = CI->getCalledFunction();
- if (!Callee || TTI.isLoweredToCall(Callee)) {
- LLVM_DEBUG(dbgs() << "Can't analyze cost of loop with call\n");
- return std::nullopt;
- }
- }
- // If the instruction might have a side-effect recursively account for
- // the cost of it and all the instructions leading up to it.
- if (I.mayHaveSideEffects())
- AddCostRecursively(I, Iteration);
- // If unrolled body turns out to be too big, bail out.
- if (UnrolledCost > MaxUnrolledLoopSize) {
- LLVM_DEBUG(dbgs() << " Exceeded threshold.. exiting.\n"
- << " UnrolledCost: " << UnrolledCost
- << ", MaxUnrolledLoopSize: " << MaxUnrolledLoopSize
- << "\n");
- return std::nullopt;
- }
- }
- Instruction *TI = BB->getTerminator();
- auto getSimplifiedConstant = [&](Value *V) -> Constant * {
- if (SimplifiedValues.count(V))
- V = SimplifiedValues.lookup(V);
- return dyn_cast<Constant>(V);
- };
- // Add in the live successors by first checking whether we have terminator
- // that may be simplified based on the values simplified by this call.
- BasicBlock *KnownSucc = nullptr;
- if (BranchInst *BI = dyn_cast<BranchInst>(TI)) {
- if (BI->isConditional()) {
- if (auto *SimpleCond = getSimplifiedConstant(BI->getCondition())) {
- // Just take the first successor if condition is undef
- if (isa<UndefValue>(SimpleCond))
- KnownSucc = BI->getSuccessor(0);
- else if (ConstantInt *SimpleCondVal =
- dyn_cast<ConstantInt>(SimpleCond))
- KnownSucc = BI->getSuccessor(SimpleCondVal->isZero() ? 1 : 0);
- }
- }
- } else if (SwitchInst *SI = dyn_cast<SwitchInst>(TI)) {
- if (auto *SimpleCond = getSimplifiedConstant(SI->getCondition())) {
- // Just take the first successor if condition is undef
- if (isa<UndefValue>(SimpleCond))
- KnownSucc = SI->getSuccessor(0);
- else if (ConstantInt *SimpleCondVal =
- dyn_cast<ConstantInt>(SimpleCond))
- KnownSucc = SI->findCaseValue(SimpleCondVal)->getCaseSuccessor();
- }
- }
- if (KnownSucc) {
- if (L->contains(KnownSucc))
- BBWorklist.insert(KnownSucc);
- else
- ExitWorklist.insert({BB, KnownSucc});
- continue;
- }
- // Add BB's successors to the worklist.
- for (BasicBlock *Succ : successors(BB))
- if (L->contains(Succ))
- BBWorklist.insert(Succ);
- else
- ExitWorklist.insert({BB, Succ});
- AddCostRecursively(*TI, Iteration);
- }
- // If we found no optimization opportunities on the first iteration, we
- // won't find them on later ones too.
- if (UnrolledCost == RolledDynamicCost) {
- LLVM_DEBUG(dbgs() << " No opportunities found.. exiting.\n"
- << " UnrolledCost: " << UnrolledCost << "\n");
- return std::nullopt;
- }
- }
- while (!ExitWorklist.empty()) {
- BasicBlock *ExitingBB, *ExitBB;
- std::tie(ExitingBB, ExitBB) = ExitWorklist.pop_back_val();
- for (Instruction &I : *ExitBB) {
- auto *PN = dyn_cast<PHINode>(&I);
- if (!PN)
- break;
- Value *Op = PN->getIncomingValueForBlock(ExitingBB);
- if (auto *OpI = dyn_cast<Instruction>(Op))
- if (L->contains(OpI))
- AddCostRecursively(*OpI, TripCount - 1);
- }
- }
- assert(UnrolledCost.isValid() && RolledDynamicCost.isValid() &&
- "All instructions must have a valid cost, whether the "
- "loop is rolled or unrolled.");
- LLVM_DEBUG(dbgs() << "Analysis finished:\n"
- << "UnrolledCost: " << UnrolledCost << ", "
- << "RolledDynamicCost: " << RolledDynamicCost << "\n");
- return {{unsigned(*UnrolledCost.getValue()),
- unsigned(*RolledDynamicCost.getValue())}};
- }
- /// ApproximateLoopSize - Approximate the size of the loop.
- InstructionCost llvm::ApproximateLoopSize(
- const Loop *L, unsigned &NumCalls, bool &NotDuplicatable, bool &Convergent,
- const TargetTransformInfo &TTI,
- const SmallPtrSetImpl<const Value *> &EphValues, unsigned BEInsns) {
- CodeMetrics Metrics;
- for (BasicBlock *BB : L->blocks())
- Metrics.analyzeBasicBlock(BB, TTI, EphValues);
- NumCalls = Metrics.NumInlineCandidates;
- NotDuplicatable = Metrics.notDuplicatable;
- Convergent = Metrics.convergent;
- InstructionCost LoopSize = Metrics.NumInsts;
- // Don't allow an estimate of size zero. This would allows unrolling of loops
- // with huge iteration counts, which is a compile time problem even if it's
- // not a problem for code quality. Also, the code using this size may assume
- // that each loop has at least three instructions (likely a conditional
- // branch, a comparison feeding that branch, and some kind of loop increment
- // feeding that comparison instruction).
- if (LoopSize.isValid() && LoopSize < BEInsns + 1)
- // This is an open coded max() on InstructionCost
- LoopSize = BEInsns + 1;
- return LoopSize;
- }
- // Returns the loop hint metadata node with the given name (for example,
- // "llvm.loop.unroll.count"). If no such metadata node exists, then nullptr is
- // returned.
- static MDNode *getUnrollMetadataForLoop(const Loop *L, StringRef Name) {
- if (MDNode *LoopID = L->getLoopID())
- return GetUnrollMetadata(LoopID, Name);
- return nullptr;
- }
- // Returns true if the loop has an unroll(full) pragma.
- static bool hasUnrollFullPragma(const Loop *L) {
- return getUnrollMetadataForLoop(L, "llvm.loop.unroll.full");
- }
- // Returns true if the loop has an unroll(enable) pragma. This metadata is used
- // for both "#pragma unroll" and "#pragma clang loop unroll(enable)" directives.
- static bool hasUnrollEnablePragma(const Loop *L) {
- return getUnrollMetadataForLoop(L, "llvm.loop.unroll.enable");
- }
- // Returns true if the loop has an runtime unroll(disable) pragma.
- static bool hasRuntimeUnrollDisablePragma(const Loop *L) {
- return getUnrollMetadataForLoop(L, "llvm.loop.unroll.runtime.disable");
- }
- // If loop has an unroll_count pragma return the (necessarily
- // positive) value from the pragma. Otherwise return 0.
- static unsigned unrollCountPragmaValue(const Loop *L) {
- MDNode *MD = getUnrollMetadataForLoop(L, "llvm.loop.unroll.count");
- if (MD) {
- assert(MD->getNumOperands() == 2 &&
- "Unroll count hint metadata should have two operands.");
- unsigned Count =
- mdconst::extract<ConstantInt>(MD->getOperand(1))->getZExtValue();
- assert(Count >= 1 && "Unroll count must be positive.");
- return Count;
- }
- return 0;
- }
- // Computes the boosting factor for complete unrolling.
- // If fully unrolling the loop would save a lot of RolledDynamicCost, it would
- // be beneficial to fully unroll the loop even if unrolledcost is large. We
- // use (RolledDynamicCost / UnrolledCost) to model the unroll benefits to adjust
- // the unroll threshold.
- static unsigned getFullUnrollBoostingFactor(const EstimatedUnrollCost &Cost,
- unsigned MaxPercentThresholdBoost) {
- if (Cost.RolledDynamicCost >= std::numeric_limits<unsigned>::max() / 100)
- return 100;
- else if (Cost.UnrolledCost != 0)
- // The boosting factor is RolledDynamicCost / UnrolledCost
- return std::min(100 * Cost.RolledDynamicCost / Cost.UnrolledCost,
- MaxPercentThresholdBoost);
- else
- return MaxPercentThresholdBoost;
- }
- // Produce an estimate of the unrolled cost of the specified loop. This
- // is used to a) produce a cost estimate for partial unrolling and b) to
- // cheaply estimate cost for full unrolling when we don't want to symbolically
- // evaluate all iterations.
- class UnrollCostEstimator {
- const unsigned LoopSize;
- public:
- UnrollCostEstimator(Loop &L, unsigned LoopSize) : LoopSize(LoopSize) {}
- // Returns loop size estimation for unrolled loop, given the unrolling
- // configuration specified by UP.
- uint64_t
- getUnrolledLoopSize(const TargetTransformInfo::UnrollingPreferences &UP,
- const unsigned CountOverwrite = 0) const {
- assert(LoopSize >= UP.BEInsns &&
- "LoopSize should not be less than BEInsns!");
- if (CountOverwrite)
- return static_cast<uint64_t>(LoopSize - UP.BEInsns) * CountOverwrite +
- UP.BEInsns;
- else
- return static_cast<uint64_t>(LoopSize - UP.BEInsns) * UP.Count +
- UP.BEInsns;
- }
- };
- static std::optional<unsigned>
- shouldPragmaUnroll(Loop *L, const PragmaInfo &PInfo,
- const unsigned TripMultiple, const unsigned TripCount,
- const UnrollCostEstimator UCE,
- const TargetTransformInfo::UnrollingPreferences &UP) {
- // Using unroll pragma
- // 1st priority is unroll count set by "unroll-count" option.
- if (PInfo.UserUnrollCount) {
- if (UP.AllowRemainder &&
- UCE.getUnrolledLoopSize(UP, (unsigned)UnrollCount) < UP.Threshold)
- return (unsigned)UnrollCount;
- }
- // 2nd priority is unroll count set by pragma.
- if (PInfo.PragmaCount > 0) {
- if ((UP.AllowRemainder || (TripMultiple % PInfo.PragmaCount == 0)))
- return PInfo.PragmaCount;
- }
- if (PInfo.PragmaFullUnroll && TripCount != 0)
- return TripCount;
- // if didn't return until here, should continue to other priorties
- return std::nullopt;
- }
- static std::optional<unsigned> shouldFullUnroll(
- Loop *L, const TargetTransformInfo &TTI, DominatorTree &DT,
- ScalarEvolution &SE, const SmallPtrSetImpl<const Value *> &EphValues,
- const unsigned FullUnrollTripCount, const UnrollCostEstimator UCE,
- const TargetTransformInfo::UnrollingPreferences &UP) {
- assert(FullUnrollTripCount && "should be non-zero!");
- if (FullUnrollTripCount > UP.FullUnrollMaxCount)
- return std::nullopt;
- // When computing the unrolled size, note that BEInsns are not replicated
- // like the rest of the loop body.
- if (UCE.getUnrolledLoopSize(UP) < UP.Threshold)
- return FullUnrollTripCount;
- // The loop isn't that small, but we still can fully unroll it if that
- // helps to remove a significant number of instructions.
- // To check that, run additional analysis on the loop.
- if (std::optional<EstimatedUnrollCost> Cost = analyzeLoopUnrollCost(
- L, FullUnrollTripCount, DT, SE, EphValues, TTI,
- UP.Threshold * UP.MaxPercentThresholdBoost / 100,
- UP.MaxIterationsCountToAnalyze)) {
- unsigned Boost =
- getFullUnrollBoostingFactor(*Cost, UP.MaxPercentThresholdBoost);
- if (Cost->UnrolledCost < UP.Threshold * Boost / 100)
- return FullUnrollTripCount;
- }
- return std::nullopt;
- }
- static std::optional<unsigned>
- shouldPartialUnroll(const unsigned LoopSize, const unsigned TripCount,
- const UnrollCostEstimator UCE,
- const TargetTransformInfo::UnrollingPreferences &UP) {
- if (!TripCount)
- return std::nullopt;
- if (!UP.Partial) {
- LLVM_DEBUG(dbgs() << " will not try to unroll partially because "
- << "-unroll-allow-partial not given\n");
- return 0;
- }
- unsigned count = UP.Count;
- if (count == 0)
- count = TripCount;
- if (UP.PartialThreshold != NoThreshold) {
- // Reduce unroll count to be modulo of TripCount for partial unrolling.
- if (UCE.getUnrolledLoopSize(UP, count) > UP.PartialThreshold)
- count = (std::max(UP.PartialThreshold, UP.BEInsns + 1) - UP.BEInsns) /
- (LoopSize - UP.BEInsns);
- if (count > UP.MaxCount)
- count = UP.MaxCount;
- while (count != 0 && TripCount % count != 0)
- count--;
- if (UP.AllowRemainder && count <= 1) {
- // If there is no Count that is modulo of TripCount, set Count to
- // largest power-of-two factor that satisfies the threshold limit.
- // As we'll create fixup loop, do the type of unrolling only if
- // remainder loop is allowed.
- count = UP.DefaultUnrollRuntimeCount;
- while (count != 0 &&
- UCE.getUnrolledLoopSize(UP, count) > UP.PartialThreshold)
- count >>= 1;
- }
- if (count < 2) {
- count = 0;
- }
- } else {
- count = TripCount;
- }
- if (count > UP.MaxCount)
- count = UP.MaxCount;
- LLVM_DEBUG(dbgs() << " partially unrolling with count: " << count << "\n");
- return count;
- }
- // Returns true if unroll count was set explicitly.
- // Calculates unroll count and writes it to UP.Count.
- // Unless IgnoreUser is true, will also use metadata and command-line options
- // that are specific to to the LoopUnroll pass (which, for instance, are
- // irrelevant for the LoopUnrollAndJam pass).
- // FIXME: This function is used by LoopUnroll and LoopUnrollAndJam, but consumes
- // many LoopUnroll-specific options. The shared functionality should be
- // refactored into it own function.
- bool llvm::computeUnrollCount(
- Loop *L, const TargetTransformInfo &TTI, DominatorTree &DT, LoopInfo *LI,
- AssumptionCache *AC,
- ScalarEvolution &SE, const SmallPtrSetImpl<const Value *> &EphValues,
- OptimizationRemarkEmitter *ORE, unsigned TripCount, unsigned MaxTripCount,
- bool MaxOrZero, unsigned TripMultiple, unsigned LoopSize,
- TargetTransformInfo::UnrollingPreferences &UP,
- TargetTransformInfo::PeelingPreferences &PP, bool &UseUpperBound) {
- UnrollCostEstimator UCE(*L, LoopSize);
- const bool UserUnrollCount = UnrollCount.getNumOccurrences() > 0;
- const bool PragmaFullUnroll = hasUnrollFullPragma(L);
- const unsigned PragmaCount = unrollCountPragmaValue(L);
- const bool PragmaEnableUnroll = hasUnrollEnablePragma(L);
- const bool ExplicitUnroll = PragmaCount > 0 || PragmaFullUnroll ||
- PragmaEnableUnroll || UserUnrollCount;
- PragmaInfo PInfo(UserUnrollCount, PragmaFullUnroll, PragmaCount,
- PragmaEnableUnroll);
- // Use an explicit peel count that has been specified for testing. In this
- // case it's not permitted to also specify an explicit unroll count.
- if (PP.PeelCount) {
- if (UnrollCount.getNumOccurrences() > 0) {
- report_fatal_error("Cannot specify both explicit peel count and "
- "explicit unroll count", /*GenCrashDiag=*/false);
- }
- UP.Count = 1;
- UP.Runtime = false;
- return true;
- }
- // Check for explicit Count.
- // 1st priority is unroll count set by "unroll-count" option.
- // 2nd priority is unroll count set by pragma.
- if (auto UnrollFactor = shouldPragmaUnroll(L, PInfo, TripMultiple, TripCount,
- UCE, UP)) {
- UP.Count = *UnrollFactor;
- if (UserUnrollCount || (PragmaCount > 0)) {
- UP.AllowExpensiveTripCount = true;
- UP.Force = true;
- }
- UP.Runtime |= (PragmaCount > 0);
- return ExplicitUnroll;
- } else {
- if (ExplicitUnroll && TripCount != 0) {
- // If the loop has an unrolling pragma, we want to be more aggressive with
- // unrolling limits. Set thresholds to at least the PragmaUnrollThreshold
- // value which is larger than the default limits.
- UP.Threshold = std::max<unsigned>(UP.Threshold, PragmaUnrollThreshold);
- UP.PartialThreshold =
- std::max<unsigned>(UP.PartialThreshold, PragmaUnrollThreshold);
- }
- }
- // 3rd priority is exact full unrolling. This will eliminate all copies
- // of some exit test.
- UP.Count = 0;
- if (TripCount) {
- UP.Count = TripCount;
- if (auto UnrollFactor = shouldFullUnroll(L, TTI, DT, SE, EphValues,
- TripCount, UCE, UP)) {
- UP.Count = *UnrollFactor;
- UseUpperBound = false;
- return ExplicitUnroll;
- }
- }
- // 4th priority is bounded unrolling.
- // We can unroll by the upper bound amount if it's generally allowed or if
- // we know that the loop is executed either the upper bound or zero times.
- // (MaxOrZero unrolling keeps only the first loop test, so the number of
- // loop tests remains the same compared to the non-unrolled version, whereas
- // the generic upper bound unrolling keeps all but the last loop test so the
- // number of loop tests goes up which may end up being worse on targets with
- // constrained branch predictor resources so is controlled by an option.)
- // In addition we only unroll small upper bounds.
- // Note that the cost of bounded unrolling is always strictly greater than
- // cost of exact full unrolling. As such, if we have an exact count and
- // found it unprofitable, we'll never chose to bounded unroll.
- if (!TripCount && MaxTripCount && (UP.UpperBound || MaxOrZero) &&
- MaxTripCount <= UnrollMaxUpperBound) {
- UP.Count = MaxTripCount;
- if (auto UnrollFactor = shouldFullUnroll(L, TTI, DT, SE, EphValues,
- MaxTripCount, UCE, UP)) {
- UP.Count = *UnrollFactor;
- UseUpperBound = true;
- return ExplicitUnroll;
- }
- }
- // 5th priority is loop peeling.
- computePeelCount(L, LoopSize, PP, TripCount, DT, SE, AC, UP.Threshold);
- if (PP.PeelCount) {
- UP.Runtime = false;
- UP.Count = 1;
- return ExplicitUnroll;
- }
- // Before starting partial unrolling, set up.partial to true,
- // if user explicitly asked for unrolling
- if (TripCount)
- UP.Partial |= ExplicitUnroll;
- // 6th priority is partial unrolling.
- // Try partial unroll only when TripCount could be statically calculated.
- if (auto UnrollFactor = shouldPartialUnroll(LoopSize, TripCount, UCE, UP)) {
- UP.Count = *UnrollFactor;
- if ((PragmaFullUnroll || PragmaEnableUnroll) && TripCount &&
- UP.Count != TripCount)
- ORE->emit([&]() {
- return OptimizationRemarkMissed(DEBUG_TYPE,
- "FullUnrollAsDirectedTooLarge",
- L->getStartLoc(), L->getHeader())
- << "Unable to fully unroll loop as directed by unroll pragma "
- "because "
- "unrolled size is too large.";
- });
- if (UP.PartialThreshold != NoThreshold) {
- if (UP.Count == 0) {
- if (PragmaEnableUnroll)
- ORE->emit([&]() {
- return OptimizationRemarkMissed(DEBUG_TYPE,
- "UnrollAsDirectedTooLarge",
- L->getStartLoc(), L->getHeader())
- << "Unable to unroll loop as directed by unroll(enable) "
- "pragma "
- "because unrolled size is too large.";
- });
- }
- }
- return ExplicitUnroll;
- }
- assert(TripCount == 0 &&
- "All cases when TripCount is constant should be covered here.");
- if (PragmaFullUnroll)
- ORE->emit([&]() {
- return OptimizationRemarkMissed(
- DEBUG_TYPE, "CantFullUnrollAsDirectedRuntimeTripCount",
- L->getStartLoc(), L->getHeader())
- << "Unable to fully unroll loop as directed by unroll(full) "
- "pragma "
- "because loop has a runtime trip count.";
- });
- // 7th priority is runtime unrolling.
- // Don't unroll a runtime trip count loop when it is disabled.
- if (hasRuntimeUnrollDisablePragma(L)) {
- UP.Count = 0;
- return false;
- }
- // Don't unroll a small upper bound loop unless user or TTI asked to do so.
- if (MaxTripCount && !UP.Force && MaxTripCount < UnrollMaxUpperBound) {
- UP.Count = 0;
- return false;
- }
- // Check if the runtime trip count is too small when profile is available.
- if (L->getHeader()->getParent()->hasProfileData()) {
- if (auto ProfileTripCount = getLoopEstimatedTripCount(L)) {
- if (*ProfileTripCount < FlatLoopTripCountThreshold)
- return false;
- else
- UP.AllowExpensiveTripCount = true;
- }
- }
- UP.Runtime |= PragmaEnableUnroll || PragmaCount > 0 || UserUnrollCount;
- if (!UP.Runtime) {
- LLVM_DEBUG(
- dbgs() << " will not try to unroll loop with runtime trip count "
- << "-unroll-runtime not given\n");
- UP.Count = 0;
- return false;
- }
- if (UP.Count == 0)
- UP.Count = UP.DefaultUnrollRuntimeCount;
- // Reduce unroll count to be the largest power-of-two factor of
- // the original count which satisfies the threshold limit.
- while (UP.Count != 0 &&
- UCE.getUnrolledLoopSize(UP) > UP.PartialThreshold)
- UP.Count >>= 1;
- #ifndef NDEBUG
- unsigned OrigCount = UP.Count;
- #endif
- if (!UP.AllowRemainder && UP.Count != 0 && (TripMultiple % UP.Count) != 0) {
- while (UP.Count != 0 && TripMultiple % UP.Count != 0)
- UP.Count >>= 1;
- LLVM_DEBUG(
- dbgs() << "Remainder loop is restricted (that could architecture "
- "specific or because the loop contains a convergent "
- "instruction), so unroll count must divide the trip "
- "multiple, "
- << TripMultiple << ". Reducing unroll count from " << OrigCount
- << " to " << UP.Count << ".\n");
- using namespace ore;
- if (unrollCountPragmaValue(L) > 0 && !UP.AllowRemainder)
- ORE->emit([&]() {
- return OptimizationRemarkMissed(DEBUG_TYPE,
- "DifferentUnrollCountFromDirected",
- L->getStartLoc(), L->getHeader())
- << "Unable to unroll loop the number of times directed by "
- "unroll_count pragma because remainder loop is restricted "
- "(that could architecture specific or because the loop "
- "contains a convergent instruction) and so must have an "
- "unroll "
- "count that divides the loop trip multiple of "
- << NV("TripMultiple", TripMultiple) << ". Unrolling instead "
- << NV("UnrollCount", UP.Count) << " time(s).";
- });
- }
- if (UP.Count > UP.MaxCount)
- UP.Count = UP.MaxCount;
- if (MaxTripCount && UP.Count > MaxTripCount)
- UP.Count = MaxTripCount;
- LLVM_DEBUG(dbgs() << " runtime unrolling with count: " << UP.Count
- << "\n");
- if (UP.Count < 2)
- UP.Count = 0;
- return ExplicitUnroll;
- }
- static LoopUnrollResult
- tryToUnrollLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, ScalarEvolution &SE,
- const TargetTransformInfo &TTI, AssumptionCache &AC,
- OptimizationRemarkEmitter &ORE, BlockFrequencyInfo *BFI,
- ProfileSummaryInfo *PSI, bool PreserveLCSSA, int OptLevel,
- bool OnlyWhenForced, bool ForgetAllSCEV,
- std::optional<unsigned> ProvidedCount,
- std::optional<unsigned> ProvidedThreshold,
- std::optional<bool> ProvidedAllowPartial,
- std::optional<bool> ProvidedRuntime,
- std::optional<bool> ProvidedUpperBound,
- std::optional<bool> ProvidedAllowPeeling,
- std::optional<bool> ProvidedAllowProfileBasedPeeling,
- std::optional<unsigned> ProvidedFullUnrollMaxCount) {
- LLVM_DEBUG(dbgs() << "Loop Unroll: F["
- << L->getHeader()->getParent()->getName() << "] Loop %"
- << L->getHeader()->getName() << "\n");
- TransformationMode TM = hasUnrollTransformation(L);
- if (TM & TM_Disable)
- return LoopUnrollResult::Unmodified;
- // If this loop isn't forced to be unrolled, avoid unrolling it when the
- // parent loop has an explicit unroll-and-jam pragma. This is to prevent
- // automatic unrolling from interfering with the user requested
- // transformation.
- Loop *ParentL = L->getParentLoop();
- if (ParentL != nullptr &&
- hasUnrollAndJamTransformation(ParentL) == TM_ForcedByUser &&
- hasUnrollTransformation(L) != TM_ForcedByUser) {
- LLVM_DEBUG(dbgs() << "Not unrolling loop since parent loop has"
- << " llvm.loop.unroll_and_jam.\n");
- return LoopUnrollResult::Unmodified;
- }
- // If this loop isn't forced to be unrolled, avoid unrolling it when the
- // loop has an explicit unroll-and-jam pragma. This is to prevent automatic
- // unrolling from interfering with the user requested transformation.
- if (hasUnrollAndJamTransformation(L) == TM_ForcedByUser &&
- hasUnrollTransformation(L) != TM_ForcedByUser) {
- LLVM_DEBUG(
- dbgs()
- << " Not unrolling loop since it has llvm.loop.unroll_and_jam.\n");
- return LoopUnrollResult::Unmodified;
- }
- if (!L->isLoopSimplifyForm()) {
- LLVM_DEBUG(
- dbgs() << " Not unrolling loop which is not in loop-simplify form.\n");
- return LoopUnrollResult::Unmodified;
- }
- // When automatic unrolling is disabled, do not unroll unless overridden for
- // this loop.
- if (OnlyWhenForced && !(TM & TM_Enable))
- return LoopUnrollResult::Unmodified;
- bool OptForSize = L->getHeader()->getParent()->hasOptSize();
- unsigned NumInlineCandidates;
- bool NotDuplicatable;
- bool Convergent;
- TargetTransformInfo::UnrollingPreferences UP = gatherUnrollingPreferences(
- L, SE, TTI, BFI, PSI, ORE, OptLevel, ProvidedThreshold, ProvidedCount,
- ProvidedAllowPartial, ProvidedRuntime, ProvidedUpperBound,
- ProvidedFullUnrollMaxCount);
- TargetTransformInfo::PeelingPreferences PP = gatherPeelingPreferences(
- L, SE, TTI, ProvidedAllowPeeling, ProvidedAllowProfileBasedPeeling, true);
- // Exit early if unrolling is disabled. For OptForSize, we pick the loop size
- // as threshold later on.
- if (UP.Threshold == 0 && (!UP.Partial || UP.PartialThreshold == 0) &&
- !OptForSize)
- return LoopUnrollResult::Unmodified;
- SmallPtrSet<const Value *, 32> EphValues;
- CodeMetrics::collectEphemeralValues(L, &AC, EphValues);
- InstructionCost LoopSizeIC =
- ApproximateLoopSize(L, NumInlineCandidates, NotDuplicatable, Convergent,
- TTI, EphValues, UP.BEInsns);
- LLVM_DEBUG(dbgs() << " Loop Size = " << LoopSizeIC << "\n");
- if (!LoopSizeIC.isValid()) {
- LLVM_DEBUG(dbgs() << " Not unrolling loop which contains instructions"
- << " with invalid cost.\n");
- return LoopUnrollResult::Unmodified;
- }
- unsigned LoopSize = *LoopSizeIC.getValue();
- if (NotDuplicatable) {
- LLVM_DEBUG(dbgs() << " Not unrolling loop which contains non-duplicatable"
- << " instructions.\n");
- return LoopUnrollResult::Unmodified;
- }
- // When optimizing for size, use LoopSize + 1 as threshold (we use < Threshold
- // later), to (fully) unroll loops, if it does not increase code size.
- if (OptForSize)
- UP.Threshold = std::max(UP.Threshold, LoopSize + 1);
- if (NumInlineCandidates != 0) {
- LLVM_DEBUG(dbgs() << " Not unrolling loop with inlinable calls.\n");
- return LoopUnrollResult::Unmodified;
- }
- // Find the smallest exact trip count for any exit. This is an upper bound
- // on the loop trip count, but an exit at an earlier iteration is still
- // possible. An unroll by the smallest exact trip count guarantees that all
- // branches relating to at least one exit can be eliminated. This is unlike
- // the max trip count, which only guarantees that the backedge can be broken.
- unsigned TripCount = 0;
- unsigned TripMultiple = 1;
- SmallVector<BasicBlock *, 8> ExitingBlocks;
- L->getExitingBlocks(ExitingBlocks);
- for (BasicBlock *ExitingBlock : ExitingBlocks)
- if (unsigned TC = SE.getSmallConstantTripCount(L, ExitingBlock))
- if (!TripCount || TC < TripCount)
- TripCount = TripMultiple = TC;
- if (!TripCount) {
- // If no exact trip count is known, determine the trip multiple of either
- // the loop latch or the single exiting block.
- // TODO: Relax for multiple exits.
- BasicBlock *ExitingBlock = L->getLoopLatch();
- if (!ExitingBlock || !L->isLoopExiting(ExitingBlock))
- ExitingBlock = L->getExitingBlock();
- if (ExitingBlock)
- TripMultiple = SE.getSmallConstantTripMultiple(L, ExitingBlock);
- }
- // If the loop contains a convergent operation, the prelude we'd add
- // to do the first few instructions before we hit the unrolled loop
- // is unsafe -- it adds a control-flow dependency to the convergent
- // operation. Therefore restrict remainder loop (try unrolling without).
- //
- // TODO: This is quite conservative. In practice, convergent_op()
- // is likely to be called unconditionally in the loop. In this
- // case, the program would be ill-formed (on most architectures)
- // unless n were the same on all threads in a thread group.
- // Assuming n is the same on all threads, any kind of unrolling is
- // safe. But currently llvm's notion of convergence isn't powerful
- // enough to express this.
- if (Convergent)
- UP.AllowRemainder = false;
- // Try to find the trip count upper bound if we cannot find the exact trip
- // count.
- unsigned MaxTripCount = 0;
- bool MaxOrZero = false;
- if (!TripCount) {
- MaxTripCount = SE.getSmallConstantMaxTripCount(L);
- MaxOrZero = SE.isBackedgeTakenCountMaxOrZero(L);
- }
- // computeUnrollCount() decides whether it is beneficial to use upper bound to
- // fully unroll the loop.
- bool UseUpperBound = false;
- bool IsCountSetExplicitly = computeUnrollCount(
- L, TTI, DT, LI, &AC, SE, EphValues, &ORE, TripCount, MaxTripCount, MaxOrZero,
- TripMultiple, LoopSize, UP, PP, UseUpperBound);
- if (!UP.Count)
- return LoopUnrollResult::Unmodified;
- if (PP.PeelCount) {
- assert(UP.Count == 1 && "Cannot perform peel and unroll in the same step");
- LLVM_DEBUG(dbgs() << "PEELING loop %" << L->getHeader()->getName()
- << " with iteration count " << PP.PeelCount << "!\n");
- ORE.emit([&]() {
- return OptimizationRemark(DEBUG_TYPE, "Peeled", L->getStartLoc(),
- L->getHeader())
- << " peeled loop by " << ore::NV("PeelCount", PP.PeelCount)
- << " iterations";
- });
- ValueToValueMapTy VMap;
- if (peelLoop(L, PP.PeelCount, LI, &SE, DT, &AC, PreserveLCSSA, VMap)) {
- simplifyLoopAfterUnroll(L, true, LI, &SE, &DT, &AC, &TTI);
- // If the loop was peeled, we already "used up" the profile information
- // we had, so we don't want to unroll or peel again.
- if (PP.PeelProfiledIterations)
- L->setLoopAlreadyUnrolled();
- return LoopUnrollResult::PartiallyUnrolled;
- }
- return LoopUnrollResult::Unmodified;
- }
- // At this point, UP.Runtime indicates that run-time unrolling is allowed.
- // However, we only want to actually perform it if we don't know the trip
- // count and the unroll count doesn't divide the known trip multiple.
- // TODO: This decision should probably be pushed up into
- // computeUnrollCount().
- UP.Runtime &= TripCount == 0 && TripMultiple % UP.Count != 0;
- // Save loop properties before it is transformed.
- MDNode *OrigLoopID = L->getLoopID();
- // Unroll the loop.
- Loop *RemainderLoop = nullptr;
- LoopUnrollResult UnrollResult = UnrollLoop(
- L,
- {UP.Count, UP.Force, UP.Runtime, UP.AllowExpensiveTripCount,
- UP.UnrollRemainder, ForgetAllSCEV},
- LI, &SE, &DT, &AC, &TTI, &ORE, PreserveLCSSA, &RemainderLoop);
- if (UnrollResult == LoopUnrollResult::Unmodified)
- return LoopUnrollResult::Unmodified;
- if (RemainderLoop) {
- std::optional<MDNode *> RemainderLoopID =
- makeFollowupLoopID(OrigLoopID, {LLVMLoopUnrollFollowupAll,
- LLVMLoopUnrollFollowupRemainder});
- if (RemainderLoopID)
- RemainderLoop->setLoopID(*RemainderLoopID);
- }
- if (UnrollResult != LoopUnrollResult::FullyUnrolled) {
- std::optional<MDNode *> NewLoopID =
- makeFollowupLoopID(OrigLoopID, {LLVMLoopUnrollFollowupAll,
- LLVMLoopUnrollFollowupUnrolled});
- if (NewLoopID) {
- L->setLoopID(*NewLoopID);
- // Do not setLoopAlreadyUnrolled if loop attributes have been specified
- // explicitly.
- return UnrollResult;
- }
- }
- // If loop has an unroll count pragma or unrolled by explicitly set count
- // mark loop as unrolled to prevent unrolling beyond that requested.
- if (UnrollResult != LoopUnrollResult::FullyUnrolled && IsCountSetExplicitly)
- L->setLoopAlreadyUnrolled();
- return UnrollResult;
- }
- namespace {
- class LoopUnroll : public LoopPass {
- public:
- static char ID; // Pass ID, replacement for typeid
- int OptLevel;
- /// If false, use a cost model to determine whether unrolling of a loop is
- /// profitable. If true, only loops that explicitly request unrolling via
- /// metadata are considered. All other loops are skipped.
- bool OnlyWhenForced;
- /// If false, when SCEV is invalidated, only forget everything in the
- /// top-most loop (call forgetTopMostLoop), of the loop being processed.
- /// Otherwise, forgetAllLoops and rebuild when needed next.
- bool ForgetAllSCEV;
- std::optional<unsigned> ProvidedCount;
- std::optional<unsigned> ProvidedThreshold;
- std::optional<bool> ProvidedAllowPartial;
- std::optional<bool> ProvidedRuntime;
- std::optional<bool> ProvidedUpperBound;
- std::optional<bool> ProvidedAllowPeeling;
- std::optional<bool> ProvidedAllowProfileBasedPeeling;
- std::optional<unsigned> ProvidedFullUnrollMaxCount;
- LoopUnroll(int OptLevel = 2, bool OnlyWhenForced = false,
- bool ForgetAllSCEV = false,
- std::optional<unsigned> Threshold = std::nullopt,
- std::optional<unsigned> Count = std::nullopt,
- std::optional<bool> AllowPartial = std::nullopt,
- std::optional<bool> Runtime = std::nullopt,
- std::optional<bool> UpperBound = std::nullopt,
- std::optional<bool> AllowPeeling = std::nullopt,
- std::optional<bool> AllowProfileBasedPeeling = std::nullopt,
- std::optional<unsigned> ProvidedFullUnrollMaxCount = std::nullopt)
- : LoopPass(ID), OptLevel(OptLevel), OnlyWhenForced(OnlyWhenForced),
- ForgetAllSCEV(ForgetAllSCEV), ProvidedCount(std::move(Count)),
- ProvidedThreshold(Threshold), ProvidedAllowPartial(AllowPartial),
- ProvidedRuntime(Runtime), ProvidedUpperBound(UpperBound),
- ProvidedAllowPeeling(AllowPeeling),
- ProvidedAllowProfileBasedPeeling(AllowProfileBasedPeeling),
- ProvidedFullUnrollMaxCount(ProvidedFullUnrollMaxCount) {
- initializeLoopUnrollPass(*PassRegistry::getPassRegistry());
- }
- bool runOnLoop(Loop *L, LPPassManager &LPM) override {
- if (skipLoop(L))
- return false;
- Function &F = *L->getHeader()->getParent();
- auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
- LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
- ScalarEvolution &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
- const TargetTransformInfo &TTI =
- getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
- auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(F);
- // For the old PM, we can't use OptimizationRemarkEmitter as an analysis
- // pass. Function analyses need to be preserved across loop transformations
- // but ORE cannot be preserved (see comment before the pass definition).
- OptimizationRemarkEmitter ORE(&F);
- bool PreserveLCSSA = mustPreserveAnalysisID(LCSSAID);
- LoopUnrollResult Result = tryToUnrollLoop(
- L, DT, LI, SE, TTI, AC, ORE, nullptr, nullptr, PreserveLCSSA, OptLevel,
- OnlyWhenForced, ForgetAllSCEV, ProvidedCount, ProvidedThreshold,
- ProvidedAllowPartial, ProvidedRuntime, ProvidedUpperBound,
- ProvidedAllowPeeling, ProvidedAllowProfileBasedPeeling,
- ProvidedFullUnrollMaxCount);
- if (Result == LoopUnrollResult::FullyUnrolled)
- LPM.markLoopAsDeleted(*L);
- return Result != LoopUnrollResult::Unmodified;
- }
- /// This transformation requires natural loop information & requires that
- /// loop preheaders be inserted into the CFG...
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addRequired<AssumptionCacheTracker>();
- AU.addRequired<TargetTransformInfoWrapperPass>();
- // FIXME: Loop passes are required to preserve domtree, and for now we just
- // recreate dom info if anything gets unrolled.
- getLoopAnalysisUsage(AU);
- }
- };
- } // end anonymous namespace
- char LoopUnroll::ID = 0;
- INITIALIZE_PASS_BEGIN(LoopUnroll, "loop-unroll", "Unroll loops", false, false)
- INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker)
- INITIALIZE_PASS_DEPENDENCY(LoopPass)
- INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass)
- INITIALIZE_PASS_END(LoopUnroll, "loop-unroll", "Unroll loops", false, false)
- Pass *llvm::createLoopUnrollPass(int OptLevel, bool OnlyWhenForced,
- bool ForgetAllSCEV, int Threshold, int Count,
- int AllowPartial, int Runtime, int UpperBound,
- int AllowPeeling) {
- // TODO: It would make more sense for this function to take the optionals
- // directly, but that's dangerous since it would silently break out of tree
- // callers.
- return new LoopUnroll(
- OptLevel, OnlyWhenForced, ForgetAllSCEV,
- Threshold == -1 ? std::nullopt : std::optional<unsigned>(Threshold),
- Count == -1 ? std::nullopt : std::optional<unsigned>(Count),
- AllowPartial == -1 ? std::nullopt : std::optional<bool>(AllowPartial),
- Runtime == -1 ? std::nullopt : std::optional<bool>(Runtime),
- UpperBound == -1 ? std::nullopt : std::optional<bool>(UpperBound),
- AllowPeeling == -1 ? std::nullopt : std::optional<bool>(AllowPeeling));
- }
- Pass *llvm::createSimpleLoopUnrollPass(int OptLevel, bool OnlyWhenForced,
- bool ForgetAllSCEV) {
- return createLoopUnrollPass(OptLevel, OnlyWhenForced, ForgetAllSCEV, -1, -1,
- 0, 0, 0, 1);
- }
- PreservedAnalyses LoopFullUnrollPass::run(Loop &L, LoopAnalysisManager &AM,
- LoopStandardAnalysisResults &AR,
- LPMUpdater &Updater) {
- // For the new PM, we can't use OptimizationRemarkEmitter as an analysis
- // pass. Function analyses need to be preserved across loop transformations
- // but ORE cannot be preserved (see comment before the pass definition).
- OptimizationRemarkEmitter ORE(L.getHeader()->getParent());
- // Keep track of the previous loop structure so we can identify new loops
- // created by unrolling.
- Loop *ParentL = L.getParentLoop();
- SmallPtrSet<Loop *, 4> OldLoops;
- if (ParentL)
- OldLoops.insert(ParentL->begin(), ParentL->end());
- else
- OldLoops.insert(AR.LI.begin(), AR.LI.end());
- std::string LoopName = std::string(L.getName());
- bool Changed =
- tryToUnrollLoop(&L, AR.DT, &AR.LI, AR.SE, AR.TTI, AR.AC, ORE,
- /*BFI*/ nullptr, /*PSI*/ nullptr,
- /*PreserveLCSSA*/ true, OptLevel, OnlyWhenForced,
- ForgetSCEV, /*Count*/ std::nullopt,
- /*Threshold*/ std::nullopt, /*AllowPartial*/ false,
- /*Runtime*/ false, /*UpperBound*/ false,
- /*AllowPeeling*/ true,
- /*AllowProfileBasedPeeling*/ false,
- /*FullUnrollMaxCount*/ std::nullopt) !=
- LoopUnrollResult::Unmodified;
- if (!Changed)
- return PreservedAnalyses::all();
- // The parent must not be damaged by unrolling!
- #ifndef NDEBUG
- if (ParentL)
- ParentL->verifyLoop();
- #endif
- // Unrolling can do several things to introduce new loops into a loop nest:
- // - Full unrolling clones child loops within the current loop but then
- // removes the current loop making all of the children appear to be new
- // sibling loops.
- //
- // When a new loop appears as a sibling loop after fully unrolling,
- // its nesting structure has fundamentally changed and we want to revisit
- // it to reflect that.
- //
- // When unrolling has removed the current loop, we need to tell the
- // infrastructure that it is gone.
- //
- // Finally, we support a debugging/testing mode where we revisit child loops
- // as well. These are not expected to require further optimizations as either
- // they or the loop they were cloned from have been directly visited already.
- // But the debugging mode allows us to check this assumption.
- bool IsCurrentLoopValid = false;
- SmallVector<Loop *, 4> SibLoops;
- if (ParentL)
- SibLoops.append(ParentL->begin(), ParentL->end());
- else
- SibLoops.append(AR.LI.begin(), AR.LI.end());
- erase_if(SibLoops, [&](Loop *SibLoop) {
- if (SibLoop == &L) {
- IsCurrentLoopValid = true;
- return true;
- }
- // Otherwise erase the loop from the list if it was in the old loops.
- return OldLoops.contains(SibLoop);
- });
- Updater.addSiblingLoops(SibLoops);
- if (!IsCurrentLoopValid) {
- Updater.markLoopAsDeleted(L, LoopName);
- } else {
- // We can only walk child loops if the current loop remained valid.
- if (UnrollRevisitChildLoops) {
- // Walk *all* of the child loops.
- SmallVector<Loop *, 4> ChildLoops(L.begin(), L.end());
- Updater.addChildLoops(ChildLoops);
- }
- }
- return getLoopPassPreservedAnalyses();
- }
- PreservedAnalyses LoopUnrollPass::run(Function &F,
- FunctionAnalysisManager &AM) {
- auto &LI = AM.getResult<LoopAnalysis>(F);
- // There are no loops in the function. Return before computing other expensive
- // analyses.
- if (LI.empty())
- return PreservedAnalyses::all();
- auto &SE = AM.getResult<ScalarEvolutionAnalysis>(F);
- auto &TTI = AM.getResult<TargetIRAnalysis>(F);
- auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
- auto &AC = AM.getResult<AssumptionAnalysis>(F);
- auto &ORE = AM.getResult<OptimizationRemarkEmitterAnalysis>(F);
- LoopAnalysisManager *LAM = nullptr;
- if (auto *LAMProxy = AM.getCachedResult<LoopAnalysisManagerFunctionProxy>(F))
- LAM = &LAMProxy->getManager();
- auto &MAMProxy = AM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
- ProfileSummaryInfo *PSI =
- MAMProxy.getCachedResult<ProfileSummaryAnalysis>(*F.getParent());
- auto *BFI = (PSI && PSI->hasProfileSummary()) ?
- &AM.getResult<BlockFrequencyAnalysis>(F) : nullptr;
- bool Changed = false;
- // The unroller requires loops to be in simplified form, and also needs LCSSA.
- // Since simplification may add new inner loops, it has to run before the
- // legality and profitability checks. This means running the loop unroller
- // will simplify all loops, regardless of whether anything end up being
- // unrolled.
- for (const auto &L : LI) {
- Changed |=
- simplifyLoop(L, &DT, &LI, &SE, &AC, nullptr, false /* PreserveLCSSA */);
- Changed |= formLCSSARecursively(*L, DT, &LI, &SE);
- }
- // Add the loop nests in the reverse order of LoopInfo. See method
- // declaration.
- SmallPriorityWorklist<Loop *, 4> Worklist;
- appendLoopsToWorklist(LI, Worklist);
- while (!Worklist.empty()) {
- // Because the LoopInfo stores the loops in RPO, we walk the worklist
- // from back to front so that we work forward across the CFG, which
- // for unrolling is only needed to get optimization remarks emitted in
- // a forward order.
- Loop &L = *Worklist.pop_back_val();
- #ifndef NDEBUG
- Loop *ParentL = L.getParentLoop();
- #endif
- // Check if the profile summary indicates that the profiled application
- // has a huge working set size, in which case we disable peeling to avoid
- // bloating it further.
- std::optional<bool> LocalAllowPeeling = UnrollOpts.AllowPeeling;
- if (PSI && PSI->hasHugeWorkingSetSize())
- LocalAllowPeeling = false;
- std::string LoopName = std::string(L.getName());
- // The API here is quite complex to call and we allow to select some
- // flavors of unrolling during construction time (by setting UnrollOpts).
- LoopUnrollResult Result = tryToUnrollLoop(
- &L, DT, &LI, SE, TTI, AC, ORE, BFI, PSI,
- /*PreserveLCSSA*/ true, UnrollOpts.OptLevel, UnrollOpts.OnlyWhenForced,
- UnrollOpts.ForgetSCEV, /*Count*/ std::nullopt,
- /*Threshold*/ std::nullopt, UnrollOpts.AllowPartial,
- UnrollOpts.AllowRuntime, UnrollOpts.AllowUpperBound, LocalAllowPeeling,
- UnrollOpts.AllowProfileBasedPeeling, UnrollOpts.FullUnrollMaxCount);
- Changed |= Result != LoopUnrollResult::Unmodified;
- // The parent must not be damaged by unrolling!
- #ifndef NDEBUG
- if (Result != LoopUnrollResult::Unmodified && ParentL)
- ParentL->verifyLoop();
- #endif
- // Clear any cached analysis results for L if we removed it completely.
- if (LAM && Result == LoopUnrollResult::FullyUnrolled)
- LAM->clear(L, LoopName);
- }
- if (!Changed)
- return PreservedAnalyses::all();
- return getLoopPassPreservedAnalyses();
- }
- void LoopUnrollPass::printPipeline(
- raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
- static_cast<PassInfoMixin<LoopUnrollPass> *>(this)->printPipeline(
- OS, MapClassName2PassName);
- OS << "<";
- if (UnrollOpts.AllowPartial != std::nullopt)
- OS << (*UnrollOpts.AllowPartial ? "" : "no-") << "partial;";
- if (UnrollOpts.AllowPeeling != std::nullopt)
- OS << (*UnrollOpts.AllowPeeling ? "" : "no-") << "peeling;";
- if (UnrollOpts.AllowRuntime != std::nullopt)
- OS << (*UnrollOpts.AllowRuntime ? "" : "no-") << "runtime;";
- if (UnrollOpts.AllowUpperBound != std::nullopt)
- OS << (*UnrollOpts.AllowUpperBound ? "" : "no-") << "upperbound;";
- if (UnrollOpts.AllowProfileBasedPeeling != std::nullopt)
- OS << (*UnrollOpts.AllowProfileBasedPeeling ? "" : "no-")
- << "profile-peeling;";
- if (UnrollOpts.FullUnrollMaxCount != std::nullopt)
- OS << "full-unroll-max=" << UnrollOpts.FullUnrollMaxCount << ";";
- OS << "O" << UnrollOpts.OptLevel;
- OS << ">";
- }
|