LLVM: lib/Target/AMDGPU/AMDGPUMemoryUtils.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
19#include "llvm/IR/IntrinsicsAMDGPU.h"
21
22#define DEBUG_TYPE "amdgpu-memory-utils"
23
24using namespace llvm;
25
27
32
33
34
35
36
37
38
39
40
41
44 while (true) {
46 return TTy;
48 if (STy->getNumElements() != 1)
49 return nullptr;
50 Ty = STy->getElementType(0);
51 continue;
52 }
54 Ty = ATy->getElementType();
55 continue;
56 }
57 return nullptr;
58 }
59}
60
63 return Ty->getName() == "amdgcn.named.barrier" ? Ty : nullptr;
64 return nullptr;
65}
66
75
78 return false;
79 }
81 return true;
82 }
84
85
86
87 return false;
88 }
90
91
92 return false;
93 }
94 return true;
95}
96
98
99
100
101
102
103
104
105
106
107
108
109
110
112 for (auto &GV : M.globals())
116}
117
121
122
123 for (auto &GV : M.globals()) {
125 continue;
130 kernels[F].insert(&GV);
131 else
132 Functions[F].insert(&GV);
133 }
134 }
135 }
136}
137
139
143
144
146 for (Function &F : M.functions()) {
148 if (F.hasAddressTaken(nullptr,
149 false,
150 false,
151 true,
152 false)) {
153 AddressTakenFuncs.insert(&F);
154 }
155 }
156
157
159 for (Function *F : AddressTakenFuncs) {
160 set_union(VariablesReachableThroughFunctionPointer, DirectMapFunction[F]);
161 }
162
163 auto FunctionMakesUnknownCall = [&](const Function *F) -> bool {
164 assert(->isDeclaration());
166 if (!R.second->getFunction())
167 return true;
168 }
169 return false;
170 };
171
172
174
175
176
177 for (Function &F : M.functions()) {
178 if (.isDeclaration() && FunctionMakesUnknownCall(&F)) {
181 VariablesReachableThroughFunctionPointer);
182 }
183 }
184 }
185
186
187
188 for (Function &Func : M.functions()) {
189 if (Func.isDeclaration() || isKernel(Func))
190 continue;
191
194
195 while (!wip.empty()) {
197
198
199
200 set_union(TransitiveMapFunction[&Func], DirectMapFunction[F]);
201
203 Function *Ith = R.second->getFunction();
204 if (Ith) {
208 }
209 }
210 }
211 }
212 }
213
214
215
216 for (Function *F : AddressTakenFuncs) {
217 set_union(VariablesReachableThroughFunctionPointer,
218 TransitiveMapFunction[F]);
219 }
220
221
222
224
225 for (Function &Func : M.functions()) {
226 if (Func.isDeclaration() || (Func))
227 continue;
228
230 Function *Ith = R.second->getFunction();
231 if (Ith) {
232 set_union(IndirectMapKernel[&Func], TransitiveMapFunction[Ith]);
233 }
234 }
235
236
237
238 bool SeesUnknownCalls = [&]() {
241
242 while (!WorkList.empty()) {
244
246 if (!CallRecord.second)
247 continue;
248
249 Function *Callee = CallRecord.second->getFunction();
250 if (!Callee)
251 return true;
252
253 if (Visited.insert(Callee).second)
255 }
256 }
257 return false;
258 }();
259
260 if (SeesUnknownCalls) {
261 set_union(IndirectMapKernel[&Func],
262 VariablesReachableThroughFunctionPointer);
263 }
264 }
265
266
267
268
269
270
271
272
273
274 std::optional HasAbsoluteGVs;
275 bool HasSpecialGVs = false;
276 for (auto &Map : {DirectMapKernel, IndirectMapKernel}) {
277 for (auto &[Fn, GVs] : Map) {
278 for (auto *GV : GVs) {
279 bool IsAbsolute = GV->isAbsoluteSymbolRef();
280 bool IsDirectMapDynLDSGV =
282 if (IsDirectMapDynLDSGV)
283 continue;
285 if (IsAbsolute) {
286 DirectMapKernel[Fn].erase(GV);
287 IndirectMapKernel[Fn].erase(GV);
288 }
289 HasSpecialGVs = true;
290 continue;
291 }
292 if (HasAbsoluteGVs.has_value()) {
293 if (*HasAbsoluteGVs != IsAbsolute) {
295 "module cannot mix absolute and non-absolute LDS GVs");
296 }
297 } else
298 HasAbsoluteGVs = IsAbsolute;
299 }
300 }
301 }
302
303
304
305 if (HasAbsoluteGVs && *HasAbsoluteGVs)
307
308 return {std::move(DirectMapKernel), std::move(IndirectMapKernel),
309 HasSpecialGVs};
310}
311
316
319 bool SeenUnknownCall = false;
320
321 while (!WorkList.empty()) {
323
324 for (auto &CallRecord : *CG[F]) {
325 if (!CallRecord.second)
326 continue;
327
328 Function *Callee = CallRecord.second->getFunction();
329 if (!Callee) {
330 if (!SeenUnknownCall) {
331 SeenUnknownCall = true;
332
333
334
335
338 ExternalCallRecord.second->getFunction();
339 assert(PotentialCallee);
340 if ((*PotentialCallee)) {
343 }
344 }
345 }
346 } else {
348 Callee->removeFnAttr(Attr);
349 if (Visited.insert(Callee).second)
351 }
352 }
353 }
354}
355
357 Instruction *DefInst = Def->getMemoryInst();
358
360 return false;
361
363 switch (II->getIntrinsicID()) {
364 case Intrinsic::amdgcn_s_barrier:
365 case Intrinsic::amdgcn_s_cluster_barrier:
366 case Intrinsic::amdgcn_s_barrier_signal:
367 case Intrinsic::amdgcn_s_barrier_signal_var:
368 case Intrinsic::amdgcn_s_barrier_signal_isfirst:
369 case Intrinsic::amdgcn_s_barrier_init:
370 case Intrinsic::amdgcn_s_barrier_join:
371 case Intrinsic::amdgcn_s_barrier_wait:
372 case Intrinsic::amdgcn_s_barrier_leave:
373 case Intrinsic::amdgcn_s_get_barrier_state:
374 case Intrinsic::amdgcn_wave_barrier:
375 case Intrinsic::amdgcn_sched_barrier:
376 case Intrinsic::amdgcn_sched_group_barrier:
377 case Intrinsic::amdgcn_iglp_opt:
378 return false;
379 default:
380 break;
381 }
382 }
383
384
385
386 const auto checkNoAlias = [AA, Ptr](auto I) -> bool {
387 return I && AA->isNoAlias(I->getPointerOperand(), Ptr);
388 };
389
392 return false;
393
394 return true;
395}
396
403
404 LLVM_DEBUG(dbgs() << "Checking clobbering of: " << *Load << '\n');
405
406
407
408
409
410
411
412
413
414 while (!WorkList.empty()) {
416 if (!Visited.insert(MA).second)
417 continue;
418
420 continue;
421
423 LLVM_DEBUG(dbgs() << " Def: " << *Def->getMemoryInst() << '\n');
424
427 return true;
428 }
429
432 continue;
433 }
434
436 for (const auto &Use : Phi->incoming_values())
438 }
439
441 return false;
442}
443
444}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file exposes an interface to building/using memory SSA to walk memory instructions using a use/d...
uint64_t IntrinsicInst * II
This file defines generic set operations that may be used on set's of different types,...
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
std::pair< std::optional< WeakTrackingVH >, CallGraphNode * > CallRecord
A pair of the calling instruction (a call or invoke) and the call graph node being called.
The basic data container for the call graph of a Module of IR.
CallGraphNode * getExternalCallingNode() const
Returns the CallGraphNode which is used to represent undetermined calls into the callgraph.
A parsed version of the target data layout string in and methods for querying it.
Implements a dense probed hash-table based set.
const Function & getFunction() const
void removeFnAttr(Attribute::AttrKind Kind)
Remove function attributes from this function.
Module * getParent()
Get the module that this global value is contained inside of...
PointerType * getType() const
Global values are always pointers.
Type * getValueType() const
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
bool hasInitializer() const
Definitions have initializers, declarations don't.
bool isConstant() const
If the value is a global constant, its value is immutable throughout the runtime execution of the pro...
A wrapper class for inspecting calls to intrinsic functions.
An instruction for reading from memory.
Represents a read-write access to memory, whether it is a must-alias, or a may-alias.
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.
Represents phi nodes for memory accesses.
This is the generic walker interface for walkers of MemorySSA.
MemoryAccess * getClobberingMemoryAccess(const Instruction *I, BatchAAResults &AA)
Given a memory Mod/Ref/ModRef'ing instruction, calling this will give you the nearest dominating Memo...
Encapsulates MemorySSA, including all data associated with memory accesses.
LLVM_ABI MemorySSAWalker * getWalker()
bool isLiveOnEntryDef(const MemoryAccess *MA) const
Return true if MA represents the live on entry value.
A Module instance is used to store all the information related to an LLVM module.
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.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
StringRef - Represent a constant reference to a string, i.e.
Class to represent target extensions types, which are generally unintrospectable from target-independ...
StringRef getName() const
Return the name for this target extension type.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI unsigned getPointerAddressSpace() const
Get the address space of this pointer or pointer vector type.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
iterator_range< user_iterator > users()
LLVM_ABI Align getPointerAlignment(const DataLayout &DL) const
Returns an alignment of the pointer value.
std::pair< iterator, bool > insert(const ValueT &V)
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Abstract Attribute helper functions.
@ LOCAL_ADDRESS
Address space for local memory.
bool isDynamicLDS(const GlobalVariable &GV)
Definition AMDGPUMemoryUtils.cpp:67
void removeFnAttrFromReachable(CallGraph &CG, Function *KernelRoot, ArrayRef< StringRef > FnAttrs)
Strip FnAttr attribute from any functions where we may have introduced its use.
Definition AMDGPUMemoryUtils.cpp:312
LLVM_READNONE constexpr bool isKernel(CallingConv::ID CC)
void getUsesOfLDSByFunction(const CallGraph &CG, Module &M, FunctionVariableMap &kernels, FunctionVariableMap &Functions)
Definition AMDGPUMemoryUtils.cpp:118
bool isReallyAClobber(const Value *Ptr, MemoryDef *Def, AAResults *AA)
Given a Def clobbering a load from Ptr according to the MSSA check if this is actually a memory updat...
Definition AMDGPUMemoryUtils.cpp:356
LDSUsesInfoTy getTransitiveUsesOfLDS(const CallGraph &CG, Module &M)
Definition AMDGPUMemoryUtils.cpp:138
static TargetExtType * getTargetExtType(const GlobalVariable &GV)
Definition AMDGPUMemoryUtils.cpp:42
DenseMap< Function *, DenseSet< GlobalVariable * > > FunctionVariableMap
TargetExtType * isNamedBarrier(const GlobalVariable &GV)
Definition AMDGPUMemoryUtils.cpp:61
bool isLDSVariableToLower(const GlobalVariable &GV)
Definition AMDGPUMemoryUtils.cpp:76
bool eliminateConstantExprUsesOfLDSFromAllInstructions(Module &M)
Definition AMDGPUMemoryUtils.cpp:97
Align getAlign(const DataLayout &DL, const GlobalVariable *GV)
Definition AMDGPUMemoryUtils.cpp:28
bool isClobberedInFunction(const LoadInst *Load, MemorySSA *MSSA, AAResults *AA)
Check is a Load is clobbered in its function.
Definition AMDGPUMemoryUtils.cpp:397
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
LLVM_ABI bool convertUsersOfConstantsToInstructions(ArrayRef< Constant * > Consts, Function *RestrictToFunc=nullptr, bool RemoveDeadConstants=true, bool IncludeSelf=false)
Replace constant expressions users of the given constants with instructions.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool set_union(S1Ty &S1, const S2Ty &S2)
set_union(A, B) - Compute A := A u B, return whether A changed.
bool isa(const From &Val)
isa - Return true if the parameter to the template is an instance of one of the template type argu...
decltype(auto) cast(const From &Val)
cast - Return the argument parameter cast to the specified type.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
This struct is a compact representation of a valid (non-zero power of two) alignment.