xref: /llvm-project/llvm/lib/Transforms/Utils/MoveAutoInit.cpp (revision 6292a808b3524d9ba6f4ce55bc5b9e547b088dd8)
1afa13ba1Sserge-sans-paille //===-- MoveAutoInit.cpp - move auto-init inst closer to their use site----===//
2afa13ba1Sserge-sans-paille //
3afa13ba1Sserge-sans-paille // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4afa13ba1Sserge-sans-paille // See https://llvm.org/LICENSE.txt for license information.
5afa13ba1Sserge-sans-paille // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6afa13ba1Sserge-sans-paille //
7afa13ba1Sserge-sans-paille //===----------------------------------------------------------------------===//
8afa13ba1Sserge-sans-paille //
9afa13ba1Sserge-sans-paille // This pass moves instruction maked as auto-init closer to the basic block that
10afa13ba1Sserge-sans-paille // use it, eventually removing it from some control path of the function.
11afa13ba1Sserge-sans-paille //
12afa13ba1Sserge-sans-paille //===----------------------------------------------------------------------===//
13afa13ba1Sserge-sans-paille 
14afa13ba1Sserge-sans-paille #include "llvm/Transforms/Utils/MoveAutoInit.h"
15afa13ba1Sserge-sans-paille #include "llvm/ADT/STLExtras.h"
16afa13ba1Sserge-sans-paille #include "llvm/ADT/Statistic.h"
17afa13ba1Sserge-sans-paille #include "llvm/Analysis/MemorySSA.h"
18afa13ba1Sserge-sans-paille #include "llvm/Analysis/MemorySSAUpdater.h"
19afa13ba1Sserge-sans-paille #include "llvm/Analysis/ValueTracking.h"
20afa13ba1Sserge-sans-paille #include "llvm/IR/DebugInfo.h"
21afa13ba1Sserge-sans-paille #include "llvm/IR/Dominators.h"
22afa13ba1Sserge-sans-paille #include "llvm/IR/Instructions.h"
23afa13ba1Sserge-sans-paille #include "llvm/IR/IntrinsicInst.h"
24afa13ba1Sserge-sans-paille #include "llvm/Support/CommandLine.h"
25afa13ba1Sserge-sans-paille #include "llvm/Transforms/Utils/LoopUtils.h"
26afa13ba1Sserge-sans-paille 
27afa13ba1Sserge-sans-paille using namespace llvm;
28afa13ba1Sserge-sans-paille 
29afa13ba1Sserge-sans-paille #define DEBUG_TYPE "move-auto-init"
30afa13ba1Sserge-sans-paille 
31afa13ba1Sserge-sans-paille STATISTIC(NumMoved, "Number of instructions moved");
32afa13ba1Sserge-sans-paille 
33afa13ba1Sserge-sans-paille static cl::opt<unsigned> MoveAutoInitThreshold(
34afa13ba1Sserge-sans-paille     "move-auto-init-threshold", cl::Hidden, cl::init(128),
35afa13ba1Sserge-sans-paille     cl::desc("Maximum instructions to analyze per moved initialization"));
36afa13ba1Sserge-sans-paille 
37afa13ba1Sserge-sans-paille static bool hasAutoInitMetadata(const Instruction &I) {
38afa13ba1Sserge-sans-paille   return I.hasMetadata(LLVMContext::MD_annotation) &&
39afa13ba1Sserge-sans-paille          any_of(I.getMetadata(LLVMContext::MD_annotation)->operands(),
40d65c0527SZain Jaffal                 [](const MDOperand &Op) { return Op.equalsStr("auto-init"); });
41afa13ba1Sserge-sans-paille }
42afa13ba1Sserge-sans-paille 
43afa13ba1Sserge-sans-paille static std::optional<MemoryLocation> writeToAlloca(const Instruction &I) {
44afa13ba1Sserge-sans-paille   MemoryLocation ML;
45afa13ba1Sserge-sans-paille   if (auto *MI = dyn_cast<MemIntrinsic>(&I))
46afa13ba1Sserge-sans-paille     ML = MemoryLocation::getForDest(MI);
47afa13ba1Sserge-sans-paille   else if (auto *SI = dyn_cast<StoreInst>(&I))
48afa13ba1Sserge-sans-paille     ML = MemoryLocation::get(SI);
49afa13ba1Sserge-sans-paille   else
50fb0c50beSNikita Popov     return std::nullopt;
51afa13ba1Sserge-sans-paille 
52afa13ba1Sserge-sans-paille   if (isa<AllocaInst>(getUnderlyingObject(ML.Ptr)))
53afa13ba1Sserge-sans-paille     return ML;
54afa13ba1Sserge-sans-paille   else
55afa13ba1Sserge-sans-paille     return {};
56afa13ba1Sserge-sans-paille }
57afa13ba1Sserge-sans-paille 
58afa13ba1Sserge-sans-paille /// Finds a BasicBlock in the CFG where instruction `I` can be moved to while
59afa13ba1Sserge-sans-paille /// not changing the Memory SSA ordering and being guarded by at least one
60afa13ba1Sserge-sans-paille /// condition.
61afa13ba1Sserge-sans-paille static BasicBlock *usersDominator(const MemoryLocation &ML, Instruction *I,
62afa13ba1Sserge-sans-paille                                   DominatorTree &DT, MemorySSA &MSSA) {
63afa13ba1Sserge-sans-paille   BasicBlock *CurrentDominator = nullptr;
64afa13ba1Sserge-sans-paille   MemoryUseOrDef &IMA = *MSSA.getMemoryAccess(I);
65afa13ba1Sserge-sans-paille   BatchAAResults AA(MSSA.getAA());
66afa13ba1Sserge-sans-paille 
67afa13ba1Sserge-sans-paille   SmallPtrSet<MemoryAccess *, 8> Visited;
68afa13ba1Sserge-sans-paille 
69afa13ba1Sserge-sans-paille   auto AsMemoryAccess = [](User *U) { return cast<MemoryAccess>(U); };
70afa13ba1Sserge-sans-paille   SmallVector<MemoryAccess *> WorkList(map_range(IMA.users(), AsMemoryAccess));
71afa13ba1Sserge-sans-paille 
72afa13ba1Sserge-sans-paille   while (!WorkList.empty()) {
73afa13ba1Sserge-sans-paille     MemoryAccess *MA = WorkList.pop_back_val();
74afa13ba1Sserge-sans-paille     if (!Visited.insert(MA).second)
75afa13ba1Sserge-sans-paille       continue;
76afa13ba1Sserge-sans-paille 
77afa13ba1Sserge-sans-paille     if (Visited.size() > MoveAutoInitThreshold)
78afa13ba1Sserge-sans-paille       return nullptr;
79afa13ba1Sserge-sans-paille 
80afa13ba1Sserge-sans-paille     bool FoundClobberingUser = false;
81afa13ba1Sserge-sans-paille     if (auto *M = dyn_cast<MemoryUseOrDef>(MA)) {
82afa13ba1Sserge-sans-paille       Instruction *MI = M->getMemoryInst();
83afa13ba1Sserge-sans-paille 
84afa13ba1Sserge-sans-paille       // If this memory instruction may not clobber `I`, we can skip it.
85afa13ba1Sserge-sans-paille       // LifetimeEnd is a valid user, but we do not want it in the user
86afa13ba1Sserge-sans-paille       // dominator.
87afa13ba1Sserge-sans-paille       if (AA.getModRefInfo(MI, ML) != ModRefInfo::NoModRef &&
88afa13ba1Sserge-sans-paille           !MI->isLifetimeStartOrEnd() && MI != I) {
89afa13ba1Sserge-sans-paille         FoundClobberingUser = true;
90afa13ba1Sserge-sans-paille         CurrentDominator = CurrentDominator
91afa13ba1Sserge-sans-paille                                ? DT.findNearestCommonDominator(CurrentDominator,
92afa13ba1Sserge-sans-paille                                                                MI->getParent())
93afa13ba1Sserge-sans-paille                                : MI->getParent();
94afa13ba1Sserge-sans-paille       }
95afa13ba1Sserge-sans-paille     }
96afa13ba1Sserge-sans-paille     if (!FoundClobberingUser) {
97afa13ba1Sserge-sans-paille       auto UsersAsMemoryAccesses = map_range(MA->users(), AsMemoryAccess);
98afa13ba1Sserge-sans-paille       append_range(WorkList, UsersAsMemoryAccesses);
99afa13ba1Sserge-sans-paille     }
100afa13ba1Sserge-sans-paille   }
101afa13ba1Sserge-sans-paille   return CurrentDominator;
102afa13ba1Sserge-sans-paille }
103afa13ba1Sserge-sans-paille 
104afa13ba1Sserge-sans-paille static bool runMoveAutoInit(Function &F, DominatorTree &DT, MemorySSA &MSSA) {
105afa13ba1Sserge-sans-paille   BasicBlock &EntryBB = F.getEntryBlock();
106afa13ba1Sserge-sans-paille   SmallVector<std::pair<Instruction *, BasicBlock *>> JobList;
107afa13ba1Sserge-sans-paille 
108afa13ba1Sserge-sans-paille   //
109afa13ba1Sserge-sans-paille   // Compute movable instructions.
110afa13ba1Sserge-sans-paille   //
111afa13ba1Sserge-sans-paille   for (Instruction &I : EntryBB) {
112afa13ba1Sserge-sans-paille     if (!hasAutoInitMetadata(I))
113afa13ba1Sserge-sans-paille       continue;
114afa13ba1Sserge-sans-paille 
115afa13ba1Sserge-sans-paille     std::optional<MemoryLocation> ML = writeToAlloca(I);
116afa13ba1Sserge-sans-paille     if (!ML)
117afa13ba1Sserge-sans-paille       continue;
118afa13ba1Sserge-sans-paille 
119afa13ba1Sserge-sans-paille     if (I.isVolatile())
120afa13ba1Sserge-sans-paille       continue;
121afa13ba1Sserge-sans-paille 
122afa13ba1Sserge-sans-paille     BasicBlock *UsersDominator = usersDominator(ML.value(), &I, DT, MSSA);
123afa13ba1Sserge-sans-paille     if (!UsersDominator)
124afa13ba1Sserge-sans-paille       continue;
125afa13ba1Sserge-sans-paille 
126afa13ba1Sserge-sans-paille     if (UsersDominator == &EntryBB)
127afa13ba1Sserge-sans-paille       continue;
128afa13ba1Sserge-sans-paille 
129afa13ba1Sserge-sans-paille     // Traverse the CFG to detect cycles `UsersDominator` would be part of.
130afa13ba1Sserge-sans-paille     SmallPtrSet<BasicBlock *, 8> TransitiveSuccessors;
131afa13ba1Sserge-sans-paille     SmallVector<BasicBlock *> WorkList(successors(UsersDominator));
132afa13ba1Sserge-sans-paille     bool HasCycle = false;
133afa13ba1Sserge-sans-paille     while (!WorkList.empty()) {
134afa13ba1Sserge-sans-paille       BasicBlock *CurrBB = WorkList.pop_back_val();
135afa13ba1Sserge-sans-paille       if (CurrBB == UsersDominator)
136afa13ba1Sserge-sans-paille         // No early exit because we want to compute the full set of transitive
137afa13ba1Sserge-sans-paille         // successors.
138afa13ba1Sserge-sans-paille         HasCycle = true;
139afa13ba1Sserge-sans-paille       for (BasicBlock *Successor : successors(CurrBB)) {
140afa13ba1Sserge-sans-paille         if (!TransitiveSuccessors.insert(Successor).second)
141afa13ba1Sserge-sans-paille           continue;
142afa13ba1Sserge-sans-paille         WorkList.push_back(Successor);
143afa13ba1Sserge-sans-paille       }
144afa13ba1Sserge-sans-paille     }
145afa13ba1Sserge-sans-paille 
146afa13ba1Sserge-sans-paille     // Don't insert if that could create multiple execution of I,
147afa13ba1Sserge-sans-paille     // but we can insert it in the non back-edge predecessors, if it exists.
148afa13ba1Sserge-sans-paille     if (HasCycle) {
149afa13ba1Sserge-sans-paille       BasicBlock *UsersDominatorHead = UsersDominator;
150afa13ba1Sserge-sans-paille       while (BasicBlock *UniquePredecessor =
151afa13ba1Sserge-sans-paille                  UsersDominatorHead->getUniquePredecessor())
152afa13ba1Sserge-sans-paille         UsersDominatorHead = UniquePredecessor;
153afa13ba1Sserge-sans-paille 
154afa13ba1Sserge-sans-paille       if (UsersDominatorHead == &EntryBB)
155afa13ba1Sserge-sans-paille         continue;
156afa13ba1Sserge-sans-paille 
157afa13ba1Sserge-sans-paille       BasicBlock *DominatingPredecessor = nullptr;
158afa13ba1Sserge-sans-paille       for (BasicBlock *Pred : predecessors(UsersDominatorHead)) {
159afa13ba1Sserge-sans-paille         // If one of the predecessor of the dominator also transitively is a
160afa13ba1Sserge-sans-paille         // successor, moving to the dominator would do the inverse of loop
161afa13ba1Sserge-sans-paille         // hoisting, and we don't want that.
162afa13ba1Sserge-sans-paille         if (TransitiveSuccessors.count(Pred))
163afa13ba1Sserge-sans-paille           continue;
164afa13ba1Sserge-sans-paille 
16526d3cd1dSXChy         if (!DT.isReachableFromEntry(Pred))
16626d3cd1dSXChy           continue;
16726d3cd1dSXChy 
168afa13ba1Sserge-sans-paille         DominatingPredecessor =
169afa13ba1Sserge-sans-paille             DominatingPredecessor
170afa13ba1Sserge-sans-paille                 ? DT.findNearestCommonDominator(DominatingPredecessor, Pred)
171afa13ba1Sserge-sans-paille                 : Pred;
172afa13ba1Sserge-sans-paille       }
173afa13ba1Sserge-sans-paille 
174afa13ba1Sserge-sans-paille       if (!DominatingPredecessor || DominatingPredecessor == &EntryBB)
175afa13ba1Sserge-sans-paille         continue;
176afa13ba1Sserge-sans-paille 
177afa13ba1Sserge-sans-paille       UsersDominator = DominatingPredecessor;
178afa13ba1Sserge-sans-paille     }
179afa13ba1Sserge-sans-paille 
180afa13ba1Sserge-sans-paille     // CatchSwitchInst blocks can only have one instruction, so they are not
181afa13ba1Sserge-sans-paille     // good candidates for insertion.
182*6292a808SJeremy Morse     while (isa<CatchSwitchInst>(UsersDominator->getFirstNonPHIIt())) {
183afa13ba1Sserge-sans-paille       for (BasicBlock *Pred : predecessors(UsersDominator))
18426d3cd1dSXChy         if (DT.isReachableFromEntry(Pred))
185afa13ba1Sserge-sans-paille           UsersDominator = DT.findNearestCommonDominator(UsersDominator, Pred);
186afa13ba1Sserge-sans-paille     }
187afa13ba1Sserge-sans-paille 
188afa13ba1Sserge-sans-paille     // We finally found a place where I can be moved while not introducing extra
189afa13ba1Sserge-sans-paille     // execution, and guarded by at least one condition.
190afa13ba1Sserge-sans-paille     if (UsersDominator != &EntryBB)
191afa13ba1Sserge-sans-paille       JobList.emplace_back(&I, UsersDominator);
192afa13ba1Sserge-sans-paille   }
193afa13ba1Sserge-sans-paille 
194afa13ba1Sserge-sans-paille   //
195afa13ba1Sserge-sans-paille   // Perform the actual substitution.
196afa13ba1Sserge-sans-paille   //
197afa13ba1Sserge-sans-paille   if (JobList.empty())
198afa13ba1Sserge-sans-paille     return false;
199afa13ba1Sserge-sans-paille 
200afa13ba1Sserge-sans-paille   MemorySSAUpdater MSSAU(&MSSA);
201afa13ba1Sserge-sans-paille 
202afa13ba1Sserge-sans-paille   // Reverse insertion to respect relative order between instructions:
203afa13ba1Sserge-sans-paille   // if two instructions are moved from the same BB to the same BB, we insert
204afa13ba1Sserge-sans-paille   // the second one in the front, then the first on top of it.
205afa13ba1Sserge-sans-paille   for (auto &Job : reverse(JobList)) {
2066942c64eSJeremy Morse     Job.first->moveBefore(*Job.second, Job.second->getFirstInsertionPt());
207afa13ba1Sserge-sans-paille     MSSAU.moveToPlace(MSSA.getMemoryAccess(Job.first), Job.first->getParent(),
208afa13ba1Sserge-sans-paille                       MemorySSA::InsertionPlace::Beginning);
209afa13ba1Sserge-sans-paille   }
210afa13ba1Sserge-sans-paille 
211afa13ba1Sserge-sans-paille   if (VerifyMemorySSA)
212afa13ba1Sserge-sans-paille     MSSA.verifyMemorySSA();
213afa13ba1Sserge-sans-paille 
214afa13ba1Sserge-sans-paille   NumMoved += JobList.size();
215afa13ba1Sserge-sans-paille 
216afa13ba1Sserge-sans-paille   return true;
217afa13ba1Sserge-sans-paille }
218afa13ba1Sserge-sans-paille 
219afa13ba1Sserge-sans-paille PreservedAnalyses MoveAutoInitPass::run(Function &F,
220afa13ba1Sserge-sans-paille                                         FunctionAnalysisManager &AM) {
221afa13ba1Sserge-sans-paille 
222afa13ba1Sserge-sans-paille   auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
223afa13ba1Sserge-sans-paille   auto &MSSA = AM.getResult<MemorySSAAnalysis>(F).getMSSA();
224afa13ba1Sserge-sans-paille   if (!runMoveAutoInit(F, DT, MSSA))
225afa13ba1Sserge-sans-paille     return PreservedAnalyses::all();
226afa13ba1Sserge-sans-paille 
227afa13ba1Sserge-sans-paille   PreservedAnalyses PA;
228afa13ba1Sserge-sans-paille   PA.preserve<DominatorTreeAnalysis>();
229afa13ba1Sserge-sans-paille   PA.preserve<MemorySSAAnalysis>();
230afa13ba1Sserge-sans-paille   PA.preserveSet<CFGAnalyses>();
231afa13ba1Sserge-sans-paille   return PA;
232afa13ba1Sserge-sans-paille }
233