[debug] Use poison instead of undef to set a killed dbg.assign address [NFC] (#119760)
[llvm-project.git] / llvm / lib / Transforms / Utils / MoveAutoInit.cpp
blob9b1b09bb3d8f2973fb5cbe778f2d478fb713171c
1 //===-- MoveAutoInit.cpp - move auto-init inst closer to their use site----===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 //
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"
27 using namespace llvm;
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) {
44 MemoryLocation ML;
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);
49 else
50 return std::nullopt;
52 if (isa<AllocaInst>(getUnderlyingObject(ML.Ptr)))
53 return ML;
54 else
55 return {};
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
60 /// condition.
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)
75 continue;
77 if (Visited.size() > MoveAutoInitThreshold)
78 return nullptr;
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
86 // dominator.
87 if (AA.getModRefInfo(MI, ML) != ModRefInfo::NoModRef &&
88 !MI->isLifetimeStartOrEnd() && MI != I) {
89 FoundClobberingUser = true;
90 CurrentDominator = CurrentDominator
91 ? DT.findNearestCommonDominator(CurrentDominator,
92 MI->getParent())
93 : MI->getParent();
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))
113 continue;
115 std::optional<MemoryLocation> ML = writeToAlloca(I);
116 if (!ML)
117 continue;
119 if (I.isVolatile())
120 continue;
122 BasicBlock *UsersDominator = usersDominator(ML.value(), &I, DT, MSSA);
123 if (!UsersDominator)
124 continue;
126 if (UsersDominator == &EntryBB)
127 continue;
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
137 // successors.
138 HasCycle = true;
139 for (BasicBlock *Successor : successors(CurrBB)) {
140 if (!TransitiveSuccessors.insert(Successor).second)
141 continue;
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.
148 if (HasCycle) {
149 BasicBlock *UsersDominatorHead = UsersDominator;
150 while (BasicBlock *UniquePredecessor =
151 UsersDominatorHead->getUniquePredecessor())
152 UsersDominatorHead = UniquePredecessor;
154 if (UsersDominatorHead == &EntryBB)
155 continue;
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))
163 continue;
165 if (!DT.isReachableFromEntry(Pred))
166 continue;
168 DominatingPredecessor =
169 DominatingPredecessor
170 ? DT.findNearestCommonDominator(DominatingPredecessor, Pred)
171 : Pred;
174 if (!DominatingPredecessor || DominatingPredecessor == &EntryBB)
175 continue;
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.
197 if (JobList.empty())
198 return false;
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);
211 if (VerifyMemorySSA)
212 MSSA.verifyMemorySSA();
214 NumMoved += JobList.size();
216 return true;
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>();
231 return PA;