1 //===-- MoveAutoInit.cpp - move auto-init inst closer to their use site----===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This pass moves instruction maked as auto-init closer to the basic block that
10 // use it, eventually removing it from some control path of the function.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Transforms/Utils/MoveAutoInit.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/Analysis/MemorySSA.h"
18 #include "llvm/Analysis/MemorySSAUpdater.h"
19 #include "llvm/Analysis/ValueTracking.h"
20 #include "llvm/IR/DebugInfo.h"
21 #include "llvm/IR/Dominators.h"
22 #include "llvm/IR/Instructions.h"
23 #include "llvm/IR/IntrinsicInst.h"
24 #include "llvm/Support/CommandLine.h"
25 #include "llvm/Transforms/Utils/LoopUtils.h"
29 #define DEBUG_TYPE "move-auto-init"
31 STATISTIC(NumMoved
, "Number of instructions moved");
33 static cl::opt
<unsigned> MoveAutoInitThreshold(
34 "move-auto-init-threshold", cl::Hidden
, cl::init(128),
35 cl::desc("Maximum instructions to analyze per moved initialization"));
37 static bool hasAutoInitMetadata(const Instruction
&I
) {
38 return I
.hasMetadata(LLVMContext::MD_annotation
) &&
39 any_of(I
.getMetadata(LLVMContext::MD_annotation
)->operands(),
40 [](const MDOperand
&Op
) { return Op
.equalsStr("auto-init"); });
43 static std::optional
<MemoryLocation
> writeToAlloca(const Instruction
&I
) {
45 if (auto *MI
= dyn_cast
<MemIntrinsic
>(&I
))
46 ML
= MemoryLocation::getForDest(MI
);
47 else if (auto *SI
= dyn_cast
<StoreInst
>(&I
))
48 ML
= MemoryLocation::get(SI
);
52 if (isa
<AllocaInst
>(getUnderlyingObject(ML
.Ptr
)))
58 /// Finds a BasicBlock in the CFG where instruction `I` can be moved to while
59 /// not changing the Memory SSA ordering and being guarded by at least one
61 static BasicBlock
*usersDominator(const MemoryLocation
&ML
, Instruction
*I
,
62 DominatorTree
&DT
, MemorySSA
&MSSA
) {
63 BasicBlock
*CurrentDominator
= nullptr;
64 MemoryUseOrDef
&IMA
= *MSSA
.getMemoryAccess(I
);
65 BatchAAResults
AA(MSSA
.getAA());
67 SmallPtrSet
<MemoryAccess
*, 8> Visited
;
69 auto AsMemoryAccess
= [](User
*U
) { return cast
<MemoryAccess
>(U
); };
70 SmallVector
<MemoryAccess
*> WorkList(map_range(IMA
.users(), AsMemoryAccess
));
72 while (!WorkList
.empty()) {
73 MemoryAccess
*MA
= WorkList
.pop_back_val();
74 if (!Visited
.insert(MA
).second
)
77 if (Visited
.size() > MoveAutoInitThreshold
)
80 bool FoundClobberingUser
= false;
81 if (auto *M
= dyn_cast
<MemoryUseOrDef
>(MA
)) {
82 Instruction
*MI
= M
->getMemoryInst();
84 // If this memory instruction may not clobber `I`, we can skip it.
85 // LifetimeEnd is a valid user, but we do not want it in the user
87 if (AA
.getModRefInfo(MI
, ML
) != ModRefInfo::NoModRef
&&
88 !MI
->isLifetimeStartOrEnd() && MI
!= I
) {
89 FoundClobberingUser
= true;
90 CurrentDominator
= CurrentDominator
91 ? DT
.findNearestCommonDominator(CurrentDominator
,
96 if (!FoundClobberingUser
) {
97 auto UsersAsMemoryAccesses
= map_range(MA
->users(), AsMemoryAccess
);
98 append_range(WorkList
, UsersAsMemoryAccesses
);
101 return CurrentDominator
;
104 static bool runMoveAutoInit(Function
&F
, DominatorTree
&DT
, MemorySSA
&MSSA
) {
105 BasicBlock
&EntryBB
= F
.getEntryBlock();
106 SmallVector
<std::pair
<Instruction
*, BasicBlock
*>> JobList
;
109 // Compute movable instructions.
111 for (Instruction
&I
: EntryBB
) {
112 if (!hasAutoInitMetadata(I
))
115 std::optional
<MemoryLocation
> ML
= writeToAlloca(I
);
122 BasicBlock
*UsersDominator
= usersDominator(ML
.value(), &I
, DT
, MSSA
);
126 if (UsersDominator
== &EntryBB
)
129 // Traverse the CFG to detect cycles `UsersDominator` would be part of.
130 SmallPtrSet
<BasicBlock
*, 8> TransitiveSuccessors
;
131 SmallVector
<BasicBlock
*> WorkList(successors(UsersDominator
));
132 bool HasCycle
= false;
133 while (!WorkList
.empty()) {
134 BasicBlock
*CurrBB
= WorkList
.pop_back_val();
135 if (CurrBB
== UsersDominator
)
136 // No early exit because we want to compute the full set of transitive
139 for (BasicBlock
*Successor
: successors(CurrBB
)) {
140 if (!TransitiveSuccessors
.insert(Successor
).second
)
142 WorkList
.push_back(Successor
);
146 // Don't insert if that could create multiple execution of I,
147 // but we can insert it in the non back-edge predecessors, if it exists.
149 BasicBlock
*UsersDominatorHead
= UsersDominator
;
150 while (BasicBlock
*UniquePredecessor
=
151 UsersDominatorHead
->getUniquePredecessor())
152 UsersDominatorHead
= UniquePredecessor
;
154 if (UsersDominatorHead
== &EntryBB
)
157 BasicBlock
*DominatingPredecessor
= nullptr;
158 for (BasicBlock
*Pred
: predecessors(UsersDominatorHead
)) {
159 // If one of the predecessor of the dominator also transitively is a
160 // successor, moving to the dominator would do the inverse of loop
161 // hoisting, and we don't want that.
162 if (TransitiveSuccessors
.count(Pred
))
165 if (!DT
.isReachableFromEntry(Pred
))
168 DominatingPredecessor
=
169 DominatingPredecessor
170 ? DT
.findNearestCommonDominator(DominatingPredecessor
, Pred
)
174 if (!DominatingPredecessor
|| DominatingPredecessor
== &EntryBB
)
177 UsersDominator
= DominatingPredecessor
;
180 // CatchSwitchInst blocks can only have one instruction, so they are not
181 // good candidates for insertion.
182 while (isa
<CatchSwitchInst
>(UsersDominator
->getFirstNonPHI())) {
183 for (BasicBlock
*Pred
: predecessors(UsersDominator
))
184 if (DT
.isReachableFromEntry(Pred
))
185 UsersDominator
= DT
.findNearestCommonDominator(UsersDominator
, Pred
);
188 // We finally found a place where I can be moved while not introducing extra
189 // execution, and guarded by at least one condition.
190 if (UsersDominator
!= &EntryBB
)
191 JobList
.emplace_back(&I
, UsersDominator
);
195 // Perform the actual substitution.
200 MemorySSAUpdater
MSSAU(&MSSA
);
202 // Reverse insertion to respect relative order between instructions:
203 // if two instructions are moved from the same BB to the same BB, we insert
204 // the second one in the front, then the first on top of it.
205 for (auto &Job
: reverse(JobList
)) {
206 Job
.first
->moveBefore(*Job
.second
, Job
.second
->getFirstInsertionPt());
207 MSSAU
.moveToPlace(MSSA
.getMemoryAccess(Job
.first
), Job
.first
->getParent(),
208 MemorySSA::InsertionPlace::Beginning
);
212 MSSA
.verifyMemorySSA();
214 NumMoved
+= JobList
.size();
219 PreservedAnalyses
MoveAutoInitPass::run(Function
&F
,
220 FunctionAnalysisManager
&AM
) {
222 auto &DT
= AM
.getResult
<DominatorTreeAnalysis
>(F
);
223 auto &MSSA
= AM
.getResult
<MemorySSAAnalysis
>(F
).getMSSA();
224 if (!runMoveAutoInit(F
, DT
, MSSA
))
225 return PreservedAnalyses::all();
227 PreservedAnalyses PA
;
228 PA
.preserve
<DominatorTreeAnalysis
>();
229 PA
.preserve
<MemorySSAAnalysis
>();
230 PA
.preserveSet
<CFGAnalyses
>();