LLVM 23.0.0git
MoveAutoInit.cpp
Go to the documentation of this file.
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.
11//
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/Statistic.h"
20#include "llvm/IR/DebugInfo.h"
21#include "llvm/IR/Dominators.h"
26
27using namespace llvm;
28
29#define DEBUG_TYPE "move-auto-init"
30
31STATISTIC(NumMoved, "Number of instructions moved");
32
34 "move-auto-init-threshold", cl::Hidden, cl::init(128),
35 cl::desc("Maximum instructions to analyze per moved initialization"));
36
37static 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"); });
41}
42
43static std::optional<MemoryLocation> writeToAlloca(const Instruction &I) {
45 if (auto *MI = dyn_cast<MemIntrinsic>(&I))
47 else if (auto *SI = dyn_cast<StoreInst>(&I))
49 else
50 return std::nullopt;
51
53 return ML;
54 else
55 return {};
56}
57
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.
62 DominatorTree &DT, MemorySSA &MSSA) {
63 BasicBlock *CurrentDominator = nullptr;
64 MemoryUseOrDef &IMA = *MSSA.getMemoryAccess(I);
65 BatchAAResults AA(MSSA.getAA());
66
68
69 auto AsMemoryAccess = [](User *U) { return cast<MemoryAccess>(U); };
70 SmallVector<MemoryAccess *> WorkList(map_range(IMA.users(), AsMemoryAccess));
71
72 while (!WorkList.empty()) {
73 MemoryAccess *MA = WorkList.pop_back_val();
74 if (!Visited.insert(MA).second)
75 continue;
76
77 if (Visited.size() > MoveAutoInitThreshold)
78 return nullptr;
79
80 bool FoundClobberingUser = false;
81 if (auto *M = dyn_cast<MemoryUseOrDef>(MA)) {
82 Instruction *MI = M->getMemoryInst();
83
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();
94 }
95 }
96 if (!FoundClobberingUser) {
97 auto UsersAsMemoryAccesses = map_range(MA->users(), AsMemoryAccess);
98 append_range(WorkList, UsersAsMemoryAccesses);
99 }
100 }
101 return CurrentDominator;
102}
103
105 BasicBlock &EntryBB = F.getEntryBlock();
107
108 //
109 // Compute movable instructions.
110 //
111 for (Instruction &I : EntryBB) {
113 continue;
114
115 std::optional<MemoryLocation> ML = writeToAlloca(I);
116 if (!ML)
117 continue;
118
119 if (I.isVolatile())
120 continue;
121
122 BasicBlock *UsersDominator = usersDominator(ML.value(), &I, DT, MSSA);
123 if (!UsersDominator)
124 continue;
125
126 if (UsersDominator == &EntryBB)
127 continue;
128
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);
143 }
144 }
145
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;
153
154 if (UsersDominatorHead == &EntryBB)
155 continue;
156
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;
164
165 if (!DT.isReachableFromEntry(Pred))
166 continue;
167 if (!DT.dominates(Pred, UsersDominatorHead))
168 continue;
169 DominatingPredecessor =
170 DominatingPredecessor
171 ? DT.findNearestCommonDominator(DominatingPredecessor, Pred)
172 : Pred;
173 }
174
175 if (!DominatingPredecessor || DominatingPredecessor == &EntryBB)
176 continue;
177
178 UsersDominator = DominatingPredecessor;
179 }
180
181 // CatchSwitchInst blocks can only have one instruction, so they are not
182 // good candidates for insertion.
183 while (isa<CatchSwitchInst>(UsersDominator->getFirstNonPHIIt())) {
184 for (BasicBlock *Pred : predecessors(UsersDominator))
185 if (DT.isReachableFromEntry(Pred))
186 UsersDominator = DT.findNearestCommonDominator(UsersDominator, Pred);
187 }
188
189 // We finally found a place where I can be moved while not introducing extra
190 // execution, and guarded by at least one condition.
191 if (UsersDominator != &EntryBB)
192 JobList.emplace_back(&I, UsersDominator);
193 }
194
195 //
196 // Perform the actual substitution.
197 //
198 if (JobList.empty())
199 return false;
200
201 MemorySSAUpdater MSSAU(&MSSA);
202
203 // Reverse insertion to respect relative order between instructions:
204 // if two instructions are moved from the same BB to the same BB, we insert
205 // the second one in the front, then the first on top of it.
206 for (auto &Job : reverse(JobList)) {
207 Job.first->moveBefore(*Job.second, Job.second->getFirstInsertionPt());
208 MSSAU.moveToPlace(MSSA.getMemoryAccess(Job.first), Job.first->getParent(),
210 }
211
212 if (VerifyMemorySSA)
213 MSSA.verifyMemorySSA();
214
215 NumMoved += JobList.size();
216
217 return true;
218}
219
222
223 auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
224 auto &MSSA = AM.getResult<MemorySSAAnalysis>(F).getMSSA();
225 if (!runMoveAutoInit(F, DT, MSSA))
226 return PreservedAnalyses::all();
227
232 return PA;
233}
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
This file exposes an interface to building/using memory SSA to walk memory instructions using a use/d...
static cl::opt< unsigned > MoveAutoInitThreshold("move-auto-init-threshold", cl::Hidden, cl::init(128), cl::desc("Maximum instructions to analyze per moved initialization"))
static bool runMoveAutoInit(Function &F, DominatorTree &DT, MemorySSA &MSSA)
static BasicBlock * usersDominator(const MemoryLocation &ML, Instruction *I, DominatorTree &DT, MemorySSA &MSSA)
Finds a BasicBlock in the CFG where instruction I can be moved to while not changing the Memory SSA o...
static bool hasAutoInitMetadata(const Instruction &I)
static std::optional< MemoryLocation > writeToAlloca(const Instruction &I)
This file contains some templates that are useful if you are working with the STL at all.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
LLVM_ABI InstListType::const_iterator getFirstNonPHIIt() const
Returns an iterator to the first instruction in this block that is not a PHINode instruction.
LLVM_ABI const BasicBlock * getUniquePredecessor() const
Return the predecessor of this block if it has a unique predecessor block.
This class is a wrapper over an AAResults, and it is intended to be used only when there are no IR ch...
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
Analysis pass which computes a DominatorTree.
Definition Dominators.h:283
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:164
LLVM_ABI bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
LLVM_ABI Instruction * findNearestCommonDominator(Instruction *I1, Instruction *I2) const
Find the nearest instruction I that dominates both I1 and I2, in the sense that a result produced bef...
LLVM_ABI bool dominates(const BasicBlock *BB, const Use &U) const
Return true if the (end of the) basic block BB dominates the use U.
Tracking metadata reference owned by Metadata.
Definition Metadata.h:902
Representation for a specific memory location.
static LLVM_ABI MemoryLocation get(const LoadInst *LI)
Return a location with information about the memory reference by the given instruction.
static LLVM_ABI MemoryLocation getForDest(const MemIntrinsic *MI)
Return a location representing the destination of a memory set or transfer.
An analysis that produces MemorySSA for a function.
Definition MemorySSA.h:936
LLVM_ABI void moveToPlace(MemoryUseOrDef *What, BasicBlock *BB, MemorySSA::InsertionPlace Where)
Encapsulates MemorySSA, including all data associated with memory accesses.
Definition MemorySSA.h:702
AliasAnalysis & getAA()
Definition MemorySSA.h:802
LLVM_ABI void verifyMemorySSA(VerificationLevel=VerificationLevel::Fast) const
Verify that MemorySSA is self consistent (IE definitions dominate all uses, uses appear in the right ...
MemoryUseOrDef * getMemoryAccess(const Instruction *I) const
Given a memory Mod/Ref'ing instruction, get the MemorySSA access associated with it.
Definition MemorySSA.h:720
Class that has the common methods + fields of memory uses/defs.
Definition MemorySSA.h:250
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
size_type size() const
Definition SmallPtrSet.h:99
size_type count(ConstPtrType Ptr) const
count - Return 1 if the specified pointer is in the set, 0 otherwise.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
iterator_range< user_iterator > users()
Definition Value.h:426
const ParentTy * getParent() const
Definition ilist_node.h:34
Abstract Attribute helper functions.
Definition Attributor.h:165
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
auto successors(const MachineBasicBlock *BB)
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2198
auto map_range(ContainerTy &&C, FuncTy F)
Definition STLExtras.h:364
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1744
auto reverse(ContainerTy &&C)
Definition STLExtras.h:406
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...
Definition Casting.h:547
@ NoModRef
The access neither references nor modifies the value stored in memory.
Definition ModRef.h:30
LLVM_ABI bool VerifyMemorySSA
Enables verification of MemorySSA.
Definition MemorySSA.cpp:84
DWARFExpression::Operation Op
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
auto predecessors(const MachineBasicBlock *BB)
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI const Value * getUnderlyingObject(const Value *V, unsigned MaxLookup=MaxLookupSearchDepth)
This method strips off any GEP address adjustments, pointer casts or llvm.threadlocal....