75#define DEBUG_TYPE "loop-unroll"
80 .forget_scev_loop_unroll;
86static const unsigned NoThreshold = std::numeric_limits<unsigned>::max();
94 std::optional<unsigned> UserThreshold, std::optional<bool> UserAllowPartial,
95 std::optional<bool> UserRuntime, std::optional<bool> UserUpperBound,
96 std::optional<unsigned> UserFullUnrollMaxCount) {
97 const ScalarOptions &Opts =
98 L->getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
102 UP.
Threshold = OptLevel > 2 ? Opts.unroll_threshold_aggressive
103 : Opts.unroll_threshold_default;
104 UP.MaxPercentThresholdBoost = 400;
105 UP.OptSizeThreshold = Opts.unroll_optsize_threshold;
106 UP.PartialThreshold = 150;
107 UP.PartialOptSizeThreshold = Opts.unroll_optsize_threshold;
108 UP.DefaultUnrollRuntimeCount = 8;
109 UP.MaxCount = std::numeric_limits<unsigned>::max();
110 UP.MaxUpperBound = 8;
111 UP.FullUnrollMaxCount = std::numeric_limits<unsigned>::max();
115 UP.AllowRemainder =
true;
116 UP.UnrollRemainder =
false;
117 UP.AllowExpensiveTripCount =
false;
119 UP.UpperBound =
false;
120 UP.UnrollAndJam =
false;
121 UP.UnrollAndJamInnerLoopThreshold = 60;
122 UP.MaxIterationsCountToAnalyze = 10;
124 UP.RuntimeUnrollMultiExit =
false;
125 UP.AddAdditionalAccumulators =
false;
128 TTI.getUnrollingPreferences(L, SE, UP, &ORE);
131 bool OptForSize = L->getHeader()->getParent()->hasOptSize() ||
137 UP.Threshold = UP.OptSizeThreshold;
138 UP.PartialThreshold = UP.PartialOptSizeThreshold;
139 UP.MaxPercentThresholdBoost = 100;
143 if (Opts.unroll_threshold)
144 UP.Threshold = *Opts.unroll_threshold;
145 if (Opts.unroll_partial_threshold)
146 UP.PartialThreshold = *Opts.unroll_partial_threshold;
147 if (Opts.unroll_max_percent_threshold_boost)
148 UP.MaxPercentThresholdBoost = *Opts.unroll_max_percent_threshold_boost;
149 if (Opts.unroll_max_count)
150 UP.MaxCount = *Opts.unroll_max_count;
151 if (Opts.unroll_max_upperbound)
152 UP.MaxUpperBound = *Opts.unroll_max_upperbound;
153 if (Opts.unroll_full_max_count)
154 UP.FullUnrollMaxCount = *Opts.unroll_full_max_count;
155 UP.Partial =
valueOr(Opts.unroll_allow_partial, UP.Partial);
156 UP.AllowRemainder =
valueOr(Opts.unroll_allow_remainder, UP.AllowRemainder);
157 UP.Runtime =
valueOr(Opts.unroll_runtime, UP.Runtime);
158 if (Opts.unroll_max_upperbound == 0)
159 UP.UpperBound =
false;
160 UP.UnrollRemainder =
valueOr(Opts.unroll_remainder, UP.UnrollRemainder);
161 if (Opts.unroll_max_iteration_count_to_analyze)
162 UP.MaxIterationsCountToAnalyze =
163 *Opts.unroll_max_iteration_count_to_analyze;
167 UP.Threshold = *UserThreshold;
168 UP.PartialThreshold = *UserThreshold;
170 if (UserAllowPartial)
171 UP.Partial = *UserAllowPartial;
173 UP.Runtime = *UserRuntime;
175 UP.UpperBound = *UserUpperBound;
176 if (UserFullUnrollMaxCount)
177 UP.FullUnrollMaxCount = *UserFullUnrollMaxCount;
190struct UnrolledInstState {
194 unsigned IsCounted : 1;
198struct UnrolledInstStateKeyInfo {
199 using PtrInfo = DenseMapInfo<Instruction *>;
200 using PairInfo = DenseMapInfo<std::pair<Instruction *, int>>;
202 static inline unsigned getHashValue(
const UnrolledInstState &S) {
203 return PairInfo::getHashValue({S.I, S.Iteration});
206 static inline bool isEqual(
const UnrolledInstState &
LHS,
207 const UnrolledInstState &
RHS) {
208 return PairInfo::isEqual({
LHS.I,
LHS.Iteration}, {
RHS.I,
RHS.Iteration});
212struct EstimatedUnrollCost {
214 unsigned UnrolledCost;
218 unsigned RolledDynamicCost;
240 unsigned MaxIterationsCountToAnalyze) {
244 assert(MaxIterationsCountToAnalyze <
245 (
unsigned)(std::numeric_limits<int>::max() / 2) &&
246 "The unroll iterations max is too large!");
250 if (!L->isInnermost()) {
252 <<
"Not analyzing loop cost: not an innermost loop.\n");
257 if (!TripCount || TripCount > MaxIterationsCountToAnalyze) {
259 <<
"Not analyzing loop cost: trip count "
260 << (TripCount ?
"too large" :
"unknown") <<
".\n");
294 auto AddCostRecursively = [&](
Instruction &RootI,
int Iteration) {
295 assert(Iteration >= 0 &&
"Cannot have a negative iteration!");
296 assert(CostWorklist.
empty() &&
"Must start with an empty cost list");
297 assert(PHIUsedList.
empty() &&
"Must start with an empty phi used list");
303 for (;; --Iteration) {
309 auto CostIter = InstCostMap.
find({
I, Iteration, 0, 0});
310 if (CostIter == InstCostMap.
end())
315 auto &Cost = *CostIter;
321 Cost.IsCounted =
true;
325 if (PhiI->getParent() == L->getHeader()) {
326 assert(Cost.IsFree &&
"Loop PHIs shouldn't be evaluated as they "
327 "inherently simplify during unrolling.");
335 PhiI->getIncomingValueForBlock(L->getLoopLatch())))
336 if (L->contains(OpI))
347 if (auto Res = SimplifiedValues.lookup(Op))
353 <<
"Adding cost of instruction (iteration " << Iteration
365 if (!OpI || !L->contains(OpI))
371 }
while (!CostWorklist.
empty());
373 if (PHIUsedList.
empty())
378 "Cannot track PHI-used values past the first iteration!");
386 assert(L->isLoopSimplifyForm() &&
"Must put loop into normal form first.");
387 assert(L->isLCSSAForm(DT) &&
388 "Must have loops in LCSSA form to track live-out values.");
391 <<
"Starting LoopUnroll profitability analysis...\n");
394 L->getHeader()->getParent()->hasMinSize() ?
400 for (
unsigned Iteration = 0; Iteration < TripCount; ++Iteration) {
413 PHI->getNumIncomingValues() == 2 &&
414 "Must have an incoming value only for the preheader and the latch.");
416 Value *V =
PHI->getIncomingValueForBlock(
417 Iteration == 0 ? L->getLoopPreheader() : L->getLoopLatch());
418 if (Iteration != 0 && SimplifiedValues.
count(V))
419 V = SimplifiedValues.
lookup(V);
424 SimplifiedValues.
clear();
425 while (!SimplifiedInputValues.
empty())
431 BBWorklist.
insert(L->getHeader());
433 for (
unsigned Idx = 0; Idx != BBWorklist.
size(); ++Idx) {
447 RolledDynamicCost +=
TTI.getInstructionCost(&
I,
CostKind);
452 bool IsFree = Analyzer.
visit(
I);
453 bool Inserted = InstCostMap.
insert({&
I, (int)Iteration,
457 assert(Inserted &&
"Cannot have a state for an unvisited instruction!");
465 const Function *Callee = CI->getCalledFunction();
466 if (!Callee ||
TTI.isLoweredToCall(Callee)) {
468 <<
"Can't analyze cost of loop with call\n");
475 if (
I.mayHaveSideEffects())
476 AddCostRecursively(
I, Iteration);
479 if (UnrolledCost > MaxUnrolledLoopSize) {
481 dbgs().
indent(3) <<
"Exceeded threshold.. exiting.\n";
483 <<
"UnrolledCost: " << UnrolledCost
484 <<
", MaxUnrolledLoopSize: " << MaxUnrolledLoopSize <<
"\n";
493 if (SimplifiedValues.
count(V))
494 V = SimplifiedValues.
lookup(V);
502 if (
auto *SimpleCond = getSimplifiedConstant(BI->getCondition())) {
505 KnownSucc = BI->getSuccessor(0);
508 KnownSucc = BI->getSuccessor(SimpleCondVal->isZero() ? 1 : 0);
511 if (
auto *SimpleCond = getSimplifiedConstant(
SI->getCondition())) {
514 KnownSucc =
SI->getSuccessor(0);
517 KnownSucc =
SI->findCaseValue(SimpleCondVal)->getCaseSuccessor();
521 if (L->contains(KnownSucc))
522 BBWorklist.
insert(KnownSucc);
524 ExitWorklist.
insert({BB, KnownSucc});
530 if (L->contains(Succ))
533 ExitWorklist.
insert({BB, Succ});
534 AddCostRecursively(*TI, Iteration);
539 if (UnrolledCost == RolledDynamicCost) {
541 dbgs().
indent(3) <<
"No opportunities found.. exiting.\n";
542 dbgs().
indent(3) <<
"UnrolledCost: " << UnrolledCost <<
"\n";
548 while (!ExitWorklist.
empty()) {
550 std::tie(ExitingBB, ExitBB) = ExitWorklist.
pop_back_val();
557 Value *
Op = PN->getIncomingValueForBlock(ExitingBB);
559 if (L->contains(OpI))
560 AddCostRecursively(*OpI, TripCount - 1);
565 "All instructions must have a valid cost, whether the "
566 "loop is rolled or unrolled.");
570 dbgs().
indent(3) <<
"UnrolledCost: " << UnrolledCost
571 <<
", RolledDynamicCost: " << RolledDynamicCost <<
"\n";
580 bool PrepareForLTO,
bool TripCountIsUniform) {
583 Metrics.analyzeBasicBlock(BB,
TTI, EphValues, PrepareForLTO, L);
585 NotDuplicatable =
Metrics.notDuplicatable;
602 if (LoopSize.isValid() && LoopSize < BEInsns + 1)
604 LoopSize = BEInsns + 1;
608 const Loop *L)
const {
609 auto ReportCannotUnroll = [&](
StringRef Reason) {
614 L->getStartLoc(), L->getHeader())
615 <<
"unable to unroll loop: " << Reason;
620 ReportCannotUnroll(
"contains convergent operations");
623 if (!LoopSize.isValid()) {
624 ReportCannotUnroll(
"loop size could not be computed");
627 if (NotDuplicatable) {
628 ReportCannotUnroll(
"contains non-duplicatable instructions");
636 unsigned LS = LoopSize.getValue();
637 assert(LS >= UP.
BEInsns &&
"LoopSize should not be less than BEInsns!");
680 "Unroll count hint metadata should have two operands.");
683 assert(
Count >= 1 &&
"Unroll count must be positive.");
693 .
get<ScalarOptions>()
694 .unroll_count.has_value()),
708 unsigned MaxPercentThresholdBoost) {
709 if (Cost.RolledDynamicCost >= std::numeric_limits<unsigned>::max() / 100)
711 else if (Cost.UnrolledCost != 0)
713 return std::min(100 * Cost.RolledDynamicCost / Cost.UnrolledCost,
714 MaxPercentThresholdBoost);
716 return MaxPercentThresholdBoost;
719static std::optional<unsigned>
722 const unsigned TripCount,
unsigned MaxTripCount,
734 << *Opts.unroll_count <<
".\n");
735 return *Opts.unroll_count;
738 <<
"Not unrolling with user count " << *Opts.unroll_count <<
": "
740 :
"remainder not allowed")
752 <<
"Not unrolling with pragma count " << PInfo.
PragmaCount
753 <<
": remainder not allowed, count does not divide trip "
754 <<
"multiple " << TripMultiple <<
".\n");
757 L->getStartLoc(), L->getHeader())
758 <<
"may be unable to unroll loop with count "
760 <<
": remainder loop is not allowed and count does not divide "
762 <<
ore::NV(
"TripMultiple", TripMultiple);
767 if (TripCount != 0) {
771 if (TripCount > Opts.pragma_unroll_full_max_iterations) {
773 <<
"Won't unroll; trip count is too large.\n");
776 "PragmaFullUnrollTripCountTooLarge",
777 L->getStartLoc(), L->getHeader())
778 <<
"may be unable to fully unroll loop: trip count "
779 <<
ore::NV(
"TripCount", TripCount) <<
" exceeds limit "
780 <<
ore::NV(
"Limit", Opts.pragma_unroll_full_max_iterations);
786 <<
"Fully unrolling with trip count: " << TripCount <<
".\n");
790 <<
"Not fully unrolling: unknown trip count.\n");
793 "PragmaFullUnrollUnknownTripCount",
794 L->getStartLoc(), L->getHeader())
795 <<
"may be unable to fully unroll loop: trip count is unknown";
802 <<
"Unrolling with max trip count: " << MaxTripCount <<
".\n");
814 assert(FullUnrollTripCount &&
"should be non-zero!");
818 <<
"Not unrolling: trip count " << FullUnrollTripCount
828 <<
" < threshold " << UP.
Threshold <<
".\n");
829 return FullUnrollTripCount;
833 <<
"Unrolled size " << UnrolledSize <<
" exceeds threshold "
834 << UP.
Threshold <<
"; checking for cost benefit.\n");
840 L, FullUnrollTripCount, DT, SE, EphValues,
TTI,
845 unsigned BoostedThreshold = UP.
Threshold * Boost / 100;
846 if (Cost->UnrolledCost < BoostedThreshold) {
848 return FullUnrollTripCount;
851 <<
"Not unrolling: cost " << Cost->UnrolledCost
852 <<
" >= boosted threshold " << BoostedThreshold <<
".\n");
858static std::optional<unsigned>
868 <<
"-unroll-allow-partial not given\n");
871 unsigned Count = TripCount;
879 <<
"Unrolled size exceeds threshold; reducing count "
880 <<
"from " <<
Count <<
" to " << NewCount <<
".\n");
901 <<
"Will not partially unroll: no profitable count.\n");
911 <<
"Partially unrolling with count: " <<
Count <<
"\n");
926 const unsigned MaxTripCount,
const bool MaxOrZero,
930 const ScalarOptions &Opts =
931 L->getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
936 << TripCount <<
", MaxTripCount=" << MaxTripCount
937 << (MaxOrZero ?
" (MaxOrZero)" :
"")
938 <<
", TripMultiple=" << TripMultiple <<
"\n");
943 dbgs().
indent(1) <<
"Explicit unroll requested:";
945 dbgs() <<
" user-count";
947 dbgs() <<
" pragma-full";
951 dbgs() <<
" pragma-enable";
959 if (Opts.unroll_count) {
961 "explicit unroll count");
964 <<
"Using explicit peel count: " << PP.
PeelCount <<
".\n");
980 if (
auto UnrollFactor =
982 MaxTripCount, UCE, UP, ORE)) {
987 return *UnrollFactor;
1003 if (
auto UnrollFactor =
1005 return *UnrollFactor;
1021 if (!TripCount && MaxTripCount && (UP.
UpperBound || MaxOrZero) &&
1023 if (
auto UnrollFactor =
1025 return *UnrollFactor;
1033 <<
"Peeling with count: " << PP.
PeelCount <<
".\n");
1047 return *UnrollFactor;
1049 "All cases when TripCount is constant should be covered here.");
1056 <<
"Not runtime unrolling: disabled by pragma.\n");
1063 << MaxTripCount <<
" is small (<= "
1069 if (L->getHeader()->getParent()->hasProfileData()) {
1071 if (*ProfileTripCount < Opts.flat_loop_tripcount_threshold)
1079 <<
"Will not try to unroll loop with runtime trip count "
1080 <<
"because -unroll-runtime not given\n");
1092 unsigned OrigCount =
Count;
1096 while (
Count != 0 && TripMultiple %
Count != 0)
1099 <<
"Remainder loop is restricted (that could be architecture "
1100 "specific or because the loop contains a convergent "
1101 "instruction), so unroll count must divide the trip "
1103 << TripMultiple <<
". Reducing unroll count from " << OrigCount
1104 <<
" to " <<
Count <<
".\n");
1110 if (MaxTripCount &&
Count > MaxTripCount)
1111 Count = MaxTripCount;
1117 <<
"Runtime unrolling with count: " <<
Count <<
"\n");
1126 bool OnlyFullUnroll,
bool OnlyWhenForced,
bool ForgetAllSCEV,
1127 bool PrepareForLTO, std::optional<unsigned> ProvidedThreshold,
1128 std::optional<bool> ProvidedAllowPartial,
1129 std::optional<bool> ProvidedRuntime,
1130 std::optional<bool> ProvidedUpperBound,
1131 std::optional<bool> ProvidedAllowPeeling,
1132 std::optional<bool> ProvidedAllowProfileBasedPeeling,
1133 std::optional<unsigned> ProvidedFullUnrollMaxCount,
1137 << L->getHeader()->getParent()->getName() <<
"] Loop %"
1138 << L->getHeader()->getName()
1139 <<
" (depth=" << L->getLoopDepth() <<
")\n");
1151 Loop *ParentL = L->getParentLoop();
1152 if (ParentL !=
nullptr &&
1156 <<
" llvm.loop.unroll_and_jam.\n");
1167 <<
"Not unrolling loop since it has llvm.loop.unroll_and_jam.\n");
1171 if (!L->isLoopSimplifyForm()) {
1173 <<
"Not unrolling loop which is not in loop-simplify form.\n");
1177 L->getStartLoc(), L->getHeader())
1178 <<
"unable to unroll loop: not in loop-simplify form";
1186 if (OnlyWhenForced && !(TM &
TM_Enable)) {
1188 <<
"disabled and loop not explicitly "
1193 bool OptForSize = L->getHeader()->getParent()->hasOptSize();
1195 L, SE,
TTI, BFI, PSI, ORE, OptLevel, ProvidedThreshold,
1196 ProvidedAllowPartial, ProvidedRuntime, ProvidedUpperBound,
1197 ProvidedFullUnrollMaxCount);
1199 L, SE,
TTI, ProvidedAllowPeeling, ProvidedAllowProfileBasedPeeling,
true);
1209 L->getStartLoc(), L->getHeader())
1210 <<
"unable to unroll loop: unroll threshold is zero";
1225 TripCountIsUniform);
1239 <<
"Not unrolling loop with inlinable calls.\n");
1243 "InlineCandidatesPreventUnroll",
1244 L->getStartLoc(), L->getHeader())
1245 <<
"unable to unroll loop: contains inlinable calls";
1256 unsigned TripCount = 0;
1257 unsigned TripMultiple = 1;
1259 L->getExitingBlocks(ExitingBlocks);
1260 for (
BasicBlock *ExitingBlock : ExitingBlocks)
1262 if (!TripCount || TC < TripCount)
1263 TripCount = TripMultiple = TC;
1269 BasicBlock *ExitingBlock = L->getLoopLatch();
1270 if (!ExitingBlock || !L->isLoopExiting(ExitingBlock))
1271 ExitingBlock = L->getExitingBlock();
1284 unsigned MaxTripCount = 0;
1285 bool MaxOrZero =
false;
1295 MaxTripCount, MaxOrZero, TripMultiple, UCE, UP, PP);
1298 <<
"Not unrolling: no viable strategy found.\n");
1302 L->getStartLoc(), L->getHeader())
1303 <<
"unable to unroll loop: no viable unroll count found";
1312 assert(
Count == 1 &&
"Cannot perform peel and unroll in the same step");
1313 LLVM_DEBUG(
dbgs() <<
"PEELING loop %" << L->getHeader()->getName()
1314 <<
" with iteration count " << PP.
PeelCount <<
"!\n");
1330 L->setLoopAlreadyUnrolled();
1335 if (OnlyFullUnroll && ((!TripCount && !MaxTripCount) ||
Count < TripCount ||
1336 Count < MaxTripCount)) {
1338 <<
"Not attempting partial/runtime unroll in FullLoopUnroll.\n");
1347 UP.
Runtime &= TripCount == 0 && TripMultiple %
Count != 0;
1350 MDNode *OrigLoopID = L->getLoopID();
1352 DebugLoc LoopStartLoc = L->getStartLoc();
1356 Loop *RemainderLoop =
nullptr;
1369 L, ULO, LI, &SE, &DT, &AC, &
TTI, &ORE, PreserveLCSSA, &RemainderLoop,
AA);
1373 <<
"Failed to unroll loop as explicitly requested.\n");
1376 LoopStartLoc, LoopHeader)
1377 <<
"failed to unroll loop as explicitly requested";
1386 LoopStartLoc, LoopHeader)
1387 <<
"unable to fully unroll loop as directed; "
1388 <<
"unrolled by factor " <<
ore::NV(
"UnrollCount", ULO.
Count);
1394 LoopStartLoc, LoopHeader)
1395 <<
"unable to unroll loop with requested count "
1397 <<
"; unrolled by factor " <<
ore::NV(
"UnrollCount", ULO.
Count);
1401 if (RemainderLoop) {
1402 std::optional<MDNode *> RemainderLoopID =
1405 if (RemainderLoopID)
1406 RemainderLoop->
setLoopID(*RemainderLoopID);
1410 std::optional<MDNode *> NewLoopID =
1414 L->setLoopID(*NewLoopID);
1418 return UnrollResult;
1425 L->setLoopAlreadyUnrolled();
1427 return UnrollResult;
1432class LoopUnroll :
public LoopPass {
1441 bool OnlyWhenForced;
1448 std::optional<unsigned> ProvidedThreshold;
1449 std::optional<bool> ProvidedAllowPartial;
1450 std::optional<bool> ProvidedRuntime;
1451 std::optional<bool> ProvidedUpperBound;
1452 std::optional<bool> ProvidedAllowPeeling;
1453 std::optional<bool> ProvidedAllowProfileBasedPeeling;
1454 std::optional<unsigned> ProvidedFullUnrollMaxCount;
1456 LoopUnroll(
int OptLevel = 2,
bool OnlyWhenForced =
false,
1457 bool ForgetAllSCEV =
false,
1458 std::optional<unsigned> Threshold = std::nullopt,
1459 std::optional<bool> AllowPartial = std::nullopt,
1460 std::optional<bool>
Runtime = std::nullopt,
1461 std::optional<bool> UpperBound = std::nullopt,
1462 std::optional<bool> AllowPeeling = std::nullopt,
1463 std::optional<bool> AllowProfileBasedPeeling = std::nullopt,
1464 std::optional<unsigned> ProvidedFullUnrollMaxCount = std::nullopt)
1465 : LoopPass(
ID), OptLevel(OptLevel), OnlyWhenForced(OnlyWhenForced),
1466 ForgetAllSCEV(ForgetAllSCEV), ProvidedThreshold(Threshold),
1467 ProvidedAllowPartial(AllowPartial), ProvidedRuntime(
Runtime),
1468 ProvidedUpperBound(UpperBound), ProvidedAllowPeeling(AllowPeeling),
1469 ProvidedAllowProfileBasedPeeling(AllowProfileBasedPeeling),
1470 ProvidedFullUnrollMaxCount(ProvidedFullUnrollMaxCount) {
1474 bool runOnLoop(
Loop *L, LPPassManager &LPM)
override {
1480 auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
1481 LoopInfo *LI = &getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
1482 ScalarEvolution &SE = getAnalysis<ScalarEvolutionWrapperPass>().getSE();
1483 const TargetTransformInfo &
TTI =
1484 getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
F);
1485 auto &AC = getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
1488 ? &getAnalysis<UniformityInfoWrapperPass>().getUniformityInfo()
1493 OptimizationRemarkEmitter ORE(&
F);
1494 bool PreserveLCSSA = mustPreserveAnalysisID(
LCSSAID);
1497 L, DT, LI, SE,
TTI, AC, ORE,
nullptr,
nullptr, PreserveLCSSA, OptLevel,
1498 false, OnlyWhenForced, ForgetAllSCEV,
1499 false, ProvidedThreshold, ProvidedAllowPartial,
1500 ProvidedRuntime, ProvidedUpperBound, ProvidedAllowPeeling,
1501 ProvidedAllowProfileBasedPeeling, ProvidedFullUnrollMaxCount, UI);
1503 if (Result == LoopUnrollResult::FullyUnrolled)
1506 return Result != LoopUnrollResult::Unmodified;
1511 void getAnalysisUsage(AnalysisUsage &AU)
const override {
1523char LoopUnroll::ID = 0;
1533 bool ForgetAllSCEV,
int Threshold,
1534 int AllowPartial,
int Runtime,
int UpperBound,
1539 return new LoopUnroll(
1540 OptLevel, OnlyWhenForced, ForgetAllSCEV,
1541 Threshold == -1 ? std::nullopt : std::optional<unsigned>(Threshold),
1542 AllowPartial == -1 ? std::nullopt : std::optional<bool>(AllowPartial),
1544 UpperBound == -1 ? std::nullopt : std::optional<bool>(UpperBound),
1545 AllowPeeling == -1 ? std::nullopt : std::optional<bool>(AllowPeeling));
1555 const ScalarOptions &Opts =
1556 L.getHeader()->getContext().getLibraryOptions().get<ScalarOptions>();
1560 Loop *ParentL = L.getParentLoop();
1567 std::string LoopName = std::string(L.getName());
1572 true, OptLevel,
true,
1573 OnlyWhenForced, ForgetSCEV, PrepareForLTO,
1574 std::nullopt,
false,
1586 ParentL->verifyLoop();
1605 bool IsCurrentLoopValid =
false;
1608 SibLoops.
append(ParentL->begin(), ParentL->end());
1612 if (SibLoop == &L) {
1613 IsCurrentLoopValid =
true;
1622 if (!IsCurrentLoopValid) {
1626 if (Opts.unroll_revisit_child_loops) {
1655 if (
auto *LAMProxy = AM.
getCachedResult<LoopAnalysisManagerFunctionProxy>(
F))
1656 LAM = &LAMProxy->getManager();
1661 auto *BFI = (PSI && PSI->hasProfileSummary()) ?
1671 for (
const auto &L : LI) {
1682 while (!Worklist.
empty()) {
1689 Loop *ParentL = L.getParentLoop();
1695 std::optional<bool> LocalAllowPeeling = UnrollOpts.AllowPeeling;
1696 if (PSI && PSI->hasHugeWorkingSetSize())
1697 LocalAllowPeeling =
false;
1698 std::string LoopName = std::string(L.getName());
1703 true, UnrollOpts.OptLevel,
1704 false, UnrollOpts.OnlyWhenForced,
1705 UnrollOpts.ForgetSCEV, UnrollOpts.PrepareForLTO,
1706 std::nullopt, UnrollOpts.AllowPartial,
1707 UnrollOpts.AllowRuntime, UnrollOpts.AllowUpperBound,
1708 LocalAllowPeeling, UnrollOpts.AllowProfileBasedPeeling,
1709 UnrollOpts.FullUnrollMaxCount, UI, &
AA);
1720 LAM->clear(L, LoopName);
1731 static_cast<PassInfoMixin<LoopUnrollPass> *
>(
this)->
printPipeline(
1732 OS, MapClassName2PassName);
1734 if (UnrollOpts.AllowPartial != std::nullopt)
1735 OS << (*UnrollOpts.AllowPartial ?
"" :
"no-") <<
"partial;";
1736 if (UnrollOpts.AllowPeeling != std::nullopt)
1737 OS << (*UnrollOpts.AllowPeeling ?
"" :
"no-") <<
"peeling;";
1738 if (UnrollOpts.AllowRuntime != std::nullopt)
1739 OS << (*UnrollOpts.AllowRuntime ?
"" :
"no-") <<
"runtime;";
1740 if (UnrollOpts.AllowUpperBound != std::nullopt)
1741 OS << (*UnrollOpts.AllowUpperBound ?
"" :
"no-") <<
"upperbound;";
1742 if (UnrollOpts.AllowProfileBasedPeeling != std::nullopt)
1743 OS << (*UnrollOpts.AllowProfileBasedPeeling ?
"" :
"no-")
1744 <<
"profile-peeling;";
1745 if (UnrollOpts.FullUnrollMaxCount != std::nullopt)
1746 OS <<
"full-unroll-max=" << UnrollOpts.FullUnrollMaxCount <<
';';
1747 if (UnrollOpts.PrepareForLTO)
1748 OS <<
"prepare-for-lto;";
1749 OS <<
'O' << UnrollOpts.OptLevel;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static cl::opt< OutputCostKind > CostKind("cost-kind", cl::desc("Target cost kind"), cl::init(OutputCostKind::RecipThroughput), cl::values(clEnumValN(OutputCostKind::RecipThroughput, "throughput", "Reciprocal throughput"), clEnumValN(OutputCostKind::Latency, "latency", "Instruction latency"), clEnumValN(OutputCostKind::CodeSize, "code-size", "Code size"), clEnumValN(OutputCostKind::SizeAndLatency, "size-latency", "Code size and latency"), clEnumValN(OutputCostKind::All, "all", "Print all cost kinds")))
This file defines DenseMapInfo traits for DenseMap.
This file defines the DenseMap class.
This file defines the DenseSet and SmallDenseSet classes.
This file provides various utilities for inspecting and working with the control flow graph in LLVM I...
This header defines various interfaces for pass management in LLVM.
This header provides classes for managing per-loop analyses.
This header provides classes for managing a pipeline of passes over loops in LLVM IR.
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 OnlyFullUnroll, bool OnlyWhenForced, bool ForgetAllSCEV, bool PrepareForLTO, 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, UniformityInfo *UI=nullptr, AAResults *AA=nullptr)
static bool hasUnrollFullPragma(const Loop *L)
static bool isSCEVUniform(const SCEV *S, UniformityInfo &UI)
Returns true if the SCEV expression is uniform, i.e., all threads in a convergent execution agree on ...
static unsigned unrollCountPragmaValue(const Loop *L)
static bool hasUnrollEnablePragma(const Loop *L)
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)
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)
Figure out if the loop is worth full unrolling.
static std::optional< unsigned > shouldPragmaUnroll(const ScalarOptions &Opts, Loop *L, const UnrollPragmaInfo &PInfo, const unsigned TripMultiple, const unsigned TripCount, unsigned MaxTripCount, const UnrollCostEstimator UCE, const TargetTransformInfo::UnrollingPreferences &UP, OptimizationRemarkEmitter *ORE)
static std::optional< unsigned > shouldPartialUnroll(const unsigned LoopSize, const unsigned TripCount, const UnrollCostEstimator UCE, const TargetTransformInfo::UnrollingPreferences &UP)
static const unsigned NoThreshold
A magic value for use with the Threshold parameter to indicate that the loop unroll should be perform...
static bool hasRuntimeUnrollDisablePragma(const Loop *L)
static unsigned getFullUnrollBoostingFactor(const EstimatedUnrollCost &Cost, unsigned MaxPercentThresholdBoost)
This file exposes an interface to building/using memory SSA to walk memory instructions using a use/d...
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
This file implements a set that has insertion order iteration characteristics.
This file defines the SmallPtrSet class.
This file defines the SmallVector class.
A manager for alias analyses.
PassT::Result * getCachedResult(IRUnitT &IR) const
Get the cached result of an analysis pass for a given IR unit.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
AnalysisUsage & addRequired()
A function analysis which provides an AssumptionCache.
An immutable pass that tracks lazily created AssumptionCache objects.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Analysis pass which computes BlockFrequencyInfo.
BlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation to estimate IR basic block frequen...
Conditional Branch instruction.
This is the shared class of boolean and integer constants.
This is an important base class in LLVM.
size_type count(const_arg_type_t< KeyT > Val) const
Return 1 if the specified key is in the map, 0 otherwise.
ValueT lookup(const_arg_type_t< KeyT > Val) const
Return the entry for the specified key, or a default constructed value if no such entry exists.
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Implements a dense probed hash-table based set.
Analysis pass which computes a DominatorTree.
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
CostType getValue() const
This function is intended to be used as sparingly as possible, since the class provides the full rang...
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
This class provides an interface for updating the loop pass manager based on mutations to the loop ne...
void addChildLoops(ArrayRef< Loop * > NewChildLoops)
Loop passes should use this method to indicate they have added new child loops of the current loop.
void markLoopAsDeleted(Loop &L, llvm::StringRef Name)
Loop passes should use this method to indicate they have deleted a loop from the nest.
void addSiblingLoops(ArrayRef< Loop * > NewSibLoops)
Loop passes should use this method to indicate they have added new sibling loops to the current loop.
void markLoopAsDeleted(Loop &L)
Analysis pass that exposes the LoopInfo for a function.
void verifyLoop() const
Verify loop structure.
LLVM_ABI PreservedAnalyses run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
LLVM_ABI void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)
Represents a single loop in the control flow graph.
void setLoopID(MDNode *LoopID) const
Set the llvm.loop loop id metadata for this loop.
const MDOperand & getOperand(unsigned I) const
unsigned getNumOperands() const
Return number of MDNode operands.
static LLVM_ABI PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
Pass interface - Implemented by all 'passes'.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
bool empty() const
Determine if the PriorityWorklist is empty or not.
An analysis pass based on the new PM to deliver ProfileSummaryInfo.
Analysis providing profile information.
This class represents an analyzed expression in the program.
LLVM_ABI ArrayRef< SCEVUse > operands() const
Return operands of this SCEV expression.
Analysis pass that exposes the ScalarEvolution for a function.
The main scalar evolution driver.
LLVM_ABI const SCEV * getBackedgeTakenCount(const Loop *L, ExitCountKind Kind=Exact)
If the specified loop has a predictable backedge-taken count, return it, otherwise return a SCEVCould...
LLVM_ABI unsigned getSmallConstantTripMultiple(const Loop *L, const SCEV *ExitCount)
Returns the largest constant divisor of the trip count as a normal unsigned value,...
LLVM_ABI unsigned getSmallConstantMaxTripCount(const Loop *L, SmallVectorImpl< const SCEVPredicate * > *Predicates=nullptr)
Returns the upper bound of the loop trip count as a normal unsigned value.
LLVM_ABI bool isBackedgeTakenCountMaxOrZero(const Loop *L)
Return true if the backedge taken count is either the value returned by getConstantMaxBackedgeTakenCo...
LLVM_ABI unsigned getSmallConstantTripCount(const Loop *L)
Returns the exact trip count of the loop if we can compute it, and the result is a small constant.
size_type size() const
Determine the number of elements in the SetVector.
void clear()
Completely clear the SetVector.
bool empty() const
Determine if the SetVector is empty or not.
bool insert(const value_type &X)
Insert a new element into the SetVector.
value_type pop_back_val()
A version of PriorityWorklist that selects small size optimized data structures for the vector and ma...
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
void insert_range(Range &&R)
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Analysis pass providing the TargetTransformInfo.
Produce an estimate of the unrolled cost of the specified loop.
ConvergenceKind Convergence
bool ConvergenceAllowsRuntime
LLVM_ABI bool canUnroll(OptimizationRemarkEmitter *ORE=nullptr, const Loop *L=nullptr) const
Whether it is legal to unroll this loop.
LLVM_ABI uint64_t getUnrolledLoopSize(const TargetTransformInfo::UnrollingPreferences &UP, unsigned Count) const
Returns loop size estimation for an unrolled loop with the given unroll count and the unrolling confi...
unsigned NumInlineCandidates
LLVM_ABI UnrollCostEstimator(const Loop *L, const TargetTransformInfo &TTI, const SmallPtrSetImpl< const Value * > &EphValues, unsigned BEInsns, bool PrepareForLTO=false, bool TripCountIsUniform=false)
uint64_t getRolledLoopSize() const
void visit(Iterator Start, Iterator End)
LLVM Value Representation.
std::pair< iterator, bool > insert(const ValueT &V)
iterator find(const_arg_type_t< ValueT > V)
An efficient, type-erasing, non-owning reference to a callable.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
Abstract Attribute helper functions.
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
DiagnosticInfoOptimizationBase::Argument NV
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool simplifyLoop(Loop *L, DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE, AssumptionCache *AC, MemorySSAUpdater *MSSAU, bool PreserveLCSSA)
Simplify each loop in a loop nest recursively.
GenericUniformityInfo< SSAContext > UniformityInfo
LLVM_ABI Pass * createLoopUnrollPass(int OptLevel=2, bool OnlyWhenForced=false, bool ForgetAllSCEV=false, int Threshold=-1, int AllowPartial=-1, int Runtime=-1, int UpperBound=-1, int AllowPeeling=-1)
LLVM_ABI std::optional< unsigned > getLoopEstimatedTripCount(Loop *L, unsigned *EstimatedLoopInvocationWeight=nullptr)
Return either:
LLVM_ABI unsigned 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, const UnrollCostEstimator &UCE, TargetTransformInfo::UnrollingPreferences &UP, TargetTransformInfo::PeelingPreferences &PP)
bool isEqual(const GCNRPTracker::LiveRegSet &S1, const GCNRPTracker::LiveRegSet &S2)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
auto successors(const MachineBasicBlock *BB)
@ Runtime
Detect stack use after return if not disabled runtime with (ASAN_OPTIONS=detect_stack_use_after_retur...
OuterAnalysisManagerProxy< ModuleAnalysisManager, Function > ModuleAnalysisManagerFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
LLVM_ABI bool getForgetSCEVInLoopUnroll(const cl::LibraryOptionsContext *LibraryOptions)
Returns -forget-scev-loop-unroll of LibraryOptions, or its global value if null.
LLVM_ABI bool formLCSSARecursively(Loop &L, const DominatorTree &DT, const LoopInfo *LI, ScalarEvolution *SE)
Put a loop nest into LCSSA form.
LLVM_ABI std::optional< MDNode * > makeFollowupLoopID(MDNode *OrigLoopID, ArrayRef< StringRef > FollowupAttrs, const char *InheritOptionsAttrsPrefix="", bool AlwaysNew=false)
Create a new loop identifier for a loop created from a loop transformation.
LLVM_ABI bool shouldOptimizeForSize(const MachineFunction *MF, ProfileSummaryInfo *PSI, const MachineBlockFrequencyInfo *BFI, PGSOQueryType QueryType=PGSOQueryType::Other)
Returns true if machine function MF is suggested to be size-optimized based on the profile.
LLVM_ABI TargetTransformInfo::UnrollingPreferences gatherUnrollingPreferences(Loop *L, ScalarEvolution &SE, const TargetTransformInfo &TTI, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, llvm::OptimizationRemarkEmitter &ORE, int OptLevel, std::optional< unsigned > UserThreshold, std::optional< bool > UserAllowPartial, std::optional< bool > UserRuntime, std::optional< bool > UserUpperBound, std::optional< unsigned > UserFullUnrollMaxCount)
Gather the various unrolling parameters based on the defaults, compiler flags, TTI overrides and user...
LLVM_ABI void simplifyLoopAfterUnroll(Loop *L, bool SimplifyIVs, LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT, AssumptionCache *AC, const TargetTransformInfo *TTI, ArrayRef< BasicBlock * > Blocks, AAResults *AA=nullptr)
Perform some cleanup and simplifications on loops after unrolling.
AnalysisManager< Loop, LoopStandardAnalysisResults & > LoopAnalysisManager
The loop analysis manager.
OutputIt transform(R &&Range, OutputIt d_first, UnaryFunction F)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere.
LLVM_ABI void initializeLoopUnrollPass(PassRegistry &)
LLVM_ABI TargetTransformInfo::PeelingPreferences gatherPeelingPreferences(Loop *L, ScalarEvolution &SE, const TargetTransformInfo &TTI, std::optional< bool > UserAllowPeeling, std::optional< bool > UserAllowProfileBasedPeeling, bool UnrollingSpecficValues=false)
LLVM_ABI CallBase * getLoopConvergenceHeart(const Loop *TheLoop)
Find the convergence heart of the loop.
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI TransformationMode hasUnrollAndJamTransformation(const Loop *L)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
LLVM_ABI void computePeelCount(Loop *L, unsigned LoopSize, TargetTransformInfo::PeelingPreferences &PP, unsigned TripCount, DominatorTree &DT, ScalarEvolution &SE, const TargetTransformInfo &TTI, AssumptionCache *AC=nullptr, unsigned Threshold=UINT_MAX)
LLVM_TEMPLATE_ABI void appendLoopsToWorklist(RangeT &&, SmallPriorityWorklist< Loop *, 4 > &)
Utility that implements appending of loops onto a worklist given a range.
LLVM_ABI cl::opt< unsigned > SCEVCheapExpansionBudget
LLVM_ABI TransformationMode hasUnrollTransformation(const Loop *L)
LoopUnrollResult
Represents the result of a UnrollLoop invocation.
@ PartiallyUnrolled
The loop was partially unrolled – we still have a loop, but with a smaller trip count.
@ Unmodified
The loop was not modified.
@ FullyUnrolled
The loop was fully unrolled into straight-line code.
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
LLVM_ABI void getLoopAnalysisUsage(AnalysisUsage &AU)
Helper to consistently add the set of standard passes to a loop pass's AnalysisUsage.
LLVM_ABI void peelLoop(Loop *L, unsigned PeelCount, bool PeelLast, LoopInfo *LI, ScalarEvolution *SE, DominatorTree &DT, AssumptionCache *AC, bool PreserveLCSSA, ValueToValueMapTy &VMap)
VMap is the value-map that maps instructions from the original loop to instructions in the last peele...
const char *const LLVMLoopUnrollFollowupAll
TransformationMode
The mode sets how eager a transformation should be applied.
@ TM_ForcedByUser
The transformation was directed by the user, e.g.
@ TM_Disable
The transformation should not be applied.
@ TM_Enable
The transformation should be applied without considering a cost model.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
LLVM_ABI MDNode * getUnrollMetadataForLoop(const Loop *L, StringRef Name)
DWARFExpression::Operation Op
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
const char *const LLVMLoopUnrollFollowupRemainder
LLVM_ABI PreservedAnalyses getLoopPassPreservedAnalyses()
Returns the minimum set of Analyses that all loop passes must preserve.
const char *const LLVMLoopUnrollFollowupUnrolled
void erase_if(Container &C, UnaryPredicate P)
Provide a container algorithm similar to C++ Library Fundamentals v2's erase_if which is equivalent t...
constexpr bool valueOr(BoolOrDefault X, bool Default)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI LoopUnrollResult UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT, AssumptionCache *AC, const llvm::TargetTransformInfo *TTI, OptimizationRemarkEmitter *ORE, bool PreserveLCSSA, Loop **RemainderLoop=nullptr, AAResults *AA=nullptr)
Unroll the given loop by Count.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Utility to calculate the size and a few similar metrics for a set of basic blocks.
static LLVM_ABI void collectEphemeralValues(const Loop *L, AssumptionCache *AC, SmallPtrSetImpl< const Value * > &EphValues)
Collect a loop's ephemeral values (those used only by an assume or similar intrinsics in the loop).
The adaptor from a function pass to a loop pass computes these analyses and makes them available to t...
TargetTransformInfo & TTI
const Instruction * Heart
bool RuntimeUnrollMultiExit
bool AllowExpensiveTripCount
bool AddAdditionalAccumulators
unsigned SCEVExpansionBudget
const bool PragmaFullUnroll
LLVM_ABI UnrollPragmaInfo(const Loop *L)
const unsigned PragmaCount
const bool ExplicitUnroll
const bool PragmaRuntimeUnrollDisable
const bool UserUnrollCount
const bool PragmaEnableUnroll