LLVM 24.0.0git
AMDGPUSwLowerLDS.cpp
Go to the documentation of this file.
1//===-- AMDGPUSwLowerLDS.cpp -----------------------------------------===//
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 lowers the local data store, LDS, uses in kernel and non-kernel
10// functions in module to use dynamically allocated global memory.
11// Packed LDS Layout is emulated in the global memory.
12// The lowered memory instructions from LDS to global memory are then
13// instrumented for address sanitizer, to catch addressing errors.
14// This pass only work when address sanitizer has been enabled and has
15// instrumented the IR. It identifies that IR has been instrumented using
16// "nosanitize_address" module flag.
17//
18// Replacement of Kernel LDS accesses:
19// For a kernel, LDS access can be static or dynamic which are direct
20// (accessed within kernel) and indirect (accessed through non-kernels).
21// All these LDS accesses corresponding to kernel will be packed together,
22// where all static LDS accesses will be allocated first and then dynamic
23// LDS follows. The total size with alignment is calculated. A new LDS global
24// will be created for the kernel called "SW LDS" and it will have the
25// attribute "amdgpu-lds-size" attached with value of the size calculated.
26// All the LDS accesses in the module will be replaced by GEP with offset
27// into the "Sw LDS".
28// A new "llvm.amdgcn.<kernel>.dynlds" is created per kernel accessing
29// the dynamic LDS. This will be marked used by kernel and will have
30// MD_absolue_symbol metadata set to total static LDS size, Since dynamic
31// LDS allocation starts after all static LDS allocation.
32//
33// A device global memory equal to the total LDS size will be allocated.
34// At the prologue of the kernel, a single work-item from the
35// work-group, does a "malloc" and stores the pointer of the
36// allocation in "SW LDS".
37//
38// To store the offsets corresponding to all LDS accesses, another global
39// variable is created which will be called "SW LDS metadata" in this pass.
40// - SW LDS Global:
41// It is LDS global of ptr type with name
42// "llvm.amdgcn.sw.lds.<kernel-name>".
43// - Metadata Global:
44// It is of struct type, with n members. n equals the number of LDS
45// globals accessed by the kernel(direct and indirect). Each member of
46// struct is another struct of type {i32, i32, i32}. First member
47// corresponds to offset, second member corresponds to size of LDS global
48// being replaced and third represents the total aligned size. It will
49// have name "llvm.amdgcn.sw.lds.<kernel-name>.md". This global will have
50// an initializer with static LDS related offsets and sizes initialized.
51// But for dynamic LDS related entries, offsets will be initialized to
52// previous static LDS allocation end offset. Sizes for them will be zero
53// initially. These dynamic LDS offset and size values will be updated
54// within the kernel, since kernel can read the dynamic LDS size
55// allocation done at runtime with query to "hidden_dynamic_lds_size"
56// hidden kernel argument.
57//
58// At the epilogue of kernel, allocated memory would be made free by the same
59// single work-item.
60//
61// Replacement of non-kernel LDS accesses:
62// Multiple kernels can access the same non-kernel function.
63// All the kernels accessing LDS through non-kernels, or reaching
64// non-kernels with LDS instructions, are sorted and assigned a kernel-id.
65// All the LDS globals accessed by non-kernels are sorted. This
66// information is used to build two tables:
67// - Base table:
68// Base table will have single row, with elements of the row
69// placed as per kernel ID. Each element in the row corresponds
70// to ptr of "SW LDS" variable created for that kernel.
71// - Offset table:
72// Offset table will have multiple rows and columns.
73// Rows are assumed to be from 0 to (n-1). n is total number
74// of kernels accessing the LDS through non-kernels.
75// Each row will have m elements. m is the total number of
76// unique LDS globals accessed by all non-kernels.
77// Each element in the row correspond to the ptr of
78// the replacement of LDS global done by that particular kernel.
79// A LDS variable in non-kernel will be replaced based on the information
80// from base and offset tables. Based on kernel-id query, ptr of "SW
81// LDS" for that corresponding kernel is obtained from base table.
82// The Offset into the base "SW LDS" is obtained from
83// corresponding element in offset table. With this information, replacement
84// value is obtained.
85//===----------------------------------------------------------------------===//
86
87#include "AMDGPU.h"
89#include "AMDGPUMemoryUtils.h"
91#include "llvm/ADT/StringRef.h"
94#include "llvm/IR/Constants.h"
95#include "llvm/IR/DIBuilder.h"
96#include "llvm/IR/DebugInfo.h"
98#include "llvm/IR/IRBuilder.h"
100#include "llvm/IR/Instructions.h"
101#include "llvm/IR/MDBuilder.h"
103#include "llvm/Pass.h"
107
108#include <algorithm>
109
110#define DEBUG_TYPE "amdgpu-sw-lower-lds"
111#define COV5_HIDDEN_DYN_LDS_SIZE_ARG 15
112
113using namespace llvm;
114using namespace AMDGPU;
115
116namespace {
117
119 AsanInstrumentLDS("amdgpu-asan-instrument-lds",
120 cl::desc("Run asan instrumentation on LDS instructions "
121 "lowered to global memory"),
122 cl::init(true), cl::Hidden);
123
124using DomTreeCallback = function_ref<DominatorTree *(Function &F)>;
125
126struct LDSAccessTypeInfo {
127 SetVector<GlobalVariable *> StaticLDSGlobals;
128 SetVector<GlobalVariable *> DynamicLDSGlobals;
129};
130
131// Struct to hold all the Metadata required for a kernel
132// to replace a LDS global uses with corresponding offset
133// in to device global memory.
134struct KernelLDSParameters {
135 GlobalVariable *SwLDS = nullptr;
136 GlobalVariable *SwDynLDS = nullptr;
137 GlobalVariable *SwLDSMetadata = nullptr;
138 LDSAccessTypeInfo DirectAccess;
139 LDSAccessTypeInfo IndirectAccess;
141 LDSToReplacementIndicesMap;
142 uint32_t MallocSize = 0;
143 uint32_t LDSSize = 0;
144 SmallVector<std::pair<uint32_t, uint32_t>, 64> RedzoneOffsetAndSizeVector;
145};
146
147// Struct to store information for creation of offset table
148// for all the non-kernel LDS accesses.
149struct NonKernelLDSParameters {
150 GlobalVariable *LDSBaseTable = nullptr;
151 GlobalVariable *LDSOffsetTable = nullptr;
152 SetVector<Function *> OrderedKernels;
153 SetVector<GlobalVariable *> OrdereLDSGlobals;
154};
155
156struct AsanInstrumentInfo {
157 int Scale = 0;
158 uint32_t Offset = 0;
159 SetVector<Instruction *> Instructions;
160};
161
162struct FunctionsAndLDSAccess {
163 MapVector<Function *, KernelLDSParameters> KernelToLDSParametersMap;
164 SetVector<Function *> KernelsWithIndirectLDSAccess;
165 SetVector<Function *> NonKernelsWithLDSInstructions;
166 SetVector<GlobalVariable *> AllNonKernelLDSAccess;
167 FunctionVariableMap NonKernelToLDSAccessMap;
168};
169
170class AMDGPUSwLowerLDS {
171public:
172 AMDGPUSwLowerLDS(Module &Mod, DomTreeCallback Callback)
173 : M(Mod), IRB(M), DTCallback(Callback) {}
174 bool run();
175 void getUsesOfLDSByNonKernels();
176 void getNonKernelsWithLDSInstructions(const CallGraph &CG);
178 getOrderedIndirectLDSAccessingKernels(SetVector<Function *> &Kernels);
180 getOrderedNonKernelAllLDSGlobals(SetVector<GlobalVariable *> &Variables);
181 void buildSwLDSGlobal(Function *Func);
182 void buildSwDynLDSGlobal(Function *Func);
183 void populateSwMetadataGlobal(Function *Func);
184 void populateSwLDSAttributeAndMetadata(Function *Func);
185 void populateLDSToReplacementIndicesMap(Function *Func);
186 void getLDSMemoryInstructions(Function *Func,
187 SetVector<Instruction *> &LDSInstructions);
188 void replaceKernelLDSAccesses(Function *Func);
189 Value *getTranslatedGlobalMemoryPtrOfLDS(Value *LoadMallocPtr, Value *LDSPtr);
190 Value *getTranslatedLDSPtrOfFlat(Value *LoadMallocPtr, Value *FlatPtr,
191 Type *LDSPtrTy);
192 void translateLDSMemoryOperationsToGlobalMemory(
193 Function *Func, Value *LoadMallocPtr,
194 SetVector<Instruction *> &LDSInstructions);
195 void poisonRedzones(Function *Func, Value *MallocPtr);
196 void lowerKernelLDSAccesses(Function *Func, DomTreeUpdater &DTU);
197 void buildNonKernelLDSOffsetTable(NonKernelLDSParameters &NKLDSParams);
198 void buildNonKernelLDSBaseTable(NonKernelLDSParameters &NKLDSParams);
199 Constant *
200 getAddressesOfVariablesInKernel(Function *Func,
201 SetVector<GlobalVariable *> &Variables);
202 void lowerNonKernelLDSAccesses(Function *Func,
203 SetVector<GlobalVariable *> &LDSGlobals,
204 NonKernelLDSParameters &NKLDSParams);
205 void
206 updateMallocSizeForDynamicLDS(Function *Func, Value **CurrMallocSize,
207 Value *HiddenDynLDSSize,
208 SetVector<GlobalVariable *> &DynamicLDSGlobals);
209 void initAsanInfo();
210
211private:
212 Module &M;
213 IRBuilder<> IRB;
214 DomTreeCallback DTCallback;
215 FunctionsAndLDSAccess FuncLDSAccessInfo;
216 AsanInstrumentInfo AsanInfo;
217};
218
219template <typename T> SetVector<T> sortByName(std::vector<T> &&V) {
220 // Sort the vector of globals or Functions based on their name.
221 // Returns a SetVector of globals/Functions.
222 sort(V, [](const auto *L, const auto *R) {
223 return L->getName() < R->getName();
224 });
225 return {SetVector<T>(llvm::from_range, V)};
226}
227
228SetVector<GlobalVariable *> AMDGPUSwLowerLDS::getOrderedNonKernelAllLDSGlobals(
229 SetVector<GlobalVariable *> &Variables) {
230 // Sort all the non-kernel LDS accesses based on their name.
231 return sortByName(
232 std::vector<GlobalVariable *>(Variables.begin(), Variables.end()));
233}
234
235SetVector<Function *> AMDGPUSwLowerLDS::getOrderedIndirectLDSAccessingKernels(
236 SetVector<Function *> &Kernels) {
237 // Sort the non-kernels accessing LDS based on their name.
238 // Also assign a kernel ID metadata based on the sorted order.
239 LLVMContext &Ctx = M.getContext();
240 if (Kernels.size() > UINT32_MAX) {
241 report_fatal_error("Unimplemented SW LDS lowering for > 2**32 kernels");
242 }
243 SetVector<Function *> OrderedKernels =
244 sortByName(std::vector<Function *>(Kernels.begin(), Kernels.end()));
245 for (size_t i = 0; i < Kernels.size(); i++) {
246 Metadata *AttrMDArgs[1] = {
248 };
249 Function *Func = OrderedKernels[i];
250 Func->setMetadata("llvm.amdgcn.lds.kernel.id",
251 MDNode::get(Ctx, AttrMDArgs));
252 }
253 return OrderedKernels;
254}
255
256// LDS memory operations and casts between flat and LDS.
257static bool isLDSMemoryInstruction(const Instruction &Inst) {
258 if (auto *LI = dyn_cast<LoadInst>(&Inst))
259 return LI->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS;
260 if (auto *SI = dyn_cast<StoreInst>(&Inst))
261 return SI->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS;
262 if (auto *RMW = dyn_cast<AtomicRMWInst>(&Inst))
263 return RMW->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS;
264 if (auto *XCHG = dyn_cast<AtomicCmpXchgInst>(&Inst))
265 return XCHG->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS;
266 if (auto *ASC = dyn_cast<AddrSpaceCastInst>(&Inst)) {
267 unsigned SrcAS = ASC->getSrcAddressSpace();
268 unsigned DstAS = ASC->getDestAddressSpace();
269 return (SrcAS == AMDGPUAS::LOCAL_ADDRESS &&
270 DstAS == AMDGPUAS::FLAT_ADDRESS) ||
271 (SrcAS == AMDGPUAS::FLAT_ADDRESS &&
272 DstAS == AMDGPUAS::LOCAL_ADDRESS);
273 }
274 if (auto *MI = dyn_cast<AnyMemIntrinsic>(&Inst)) {
275 if (MI->getDestAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
276 return true;
277 auto *MTI = dyn_cast<AnyMemTransferInst>(MI);
278 return MTI && MTI->getSourceAddressSpace() == AMDGPUAS::LOCAL_ADDRESS;
279 }
280 return false;
281}
282
283void AMDGPUSwLowerLDS::getNonKernelsWithLDSInstructions(const CallGraph &CG) {
284 // Non-kernels with LDS instructions find the malloc buffer through the base
285 // table, so every kernel reaching them needs a kernel ID, even one without
286 // LDS.
287 DenseMap<Function *, bool> HasLDSInstructionsCache;
288 auto HasLDSInstructions = [&](Function *F) {
289 auto [It, Inserted] = HasLDSInstructionsCache.try_emplace(F, false);
290 if (Inserted) {
291 It->second = any_of(instructions(*F), isLDSMemoryInstruction);
292 if (It->second)
293 FuncLDSAccessInfo.NonKernelsWithLDSInstructions.insert(F);
294 }
295 return It->second;
296 };
297
298 // Indirect calls may reach any address taken non-kernel.
299 SmallVector<Function *> AddressTakenFuncs;
300 for (Function &F : M)
301 if (!F.isDeclaration() && !isKernel(F) &&
302 F.hasAddressTaken(nullptr, /*IgnoreCallbackUses=*/false,
303 /*IgnoreAssumeLikeCalls=*/false,
304 /*IgnoreLLVMUsed=*/true))
305 AddressTakenFuncs.push_back(&F);
306
307 for (Function &Kernel : M) {
308 if (Kernel.isDeclaration() || !isKernel(Kernel))
309 continue;
310
311 bool ReachesLDSInstructions = false;
312 bool SeenUnknownCall = false;
313 SmallVector<Function *> WorkList = {&Kernel};
315 auto Visit = [&](Function *Callee) {
316 if (Callee->isDeclaration() || isKernel(*Callee) ||
317 !Visited.insert(Callee).second)
318 return;
319 ReachesLDSInstructions |= HasLDSInstructions(Callee);
320 WorkList.push_back(Callee);
321 };
322
323 while (!WorkList.empty()) {
324 Function *F = WorkList.pop_back_val();
325 for (const CallGraphNode::CallRecord &CallRecord : *CG[F]) {
326 if (!CallRecord.second)
327 continue;
328 if (Function *Callee = CallRecord.second->getFunction()) {
329 Visit(Callee);
330 continue;
331 }
332 if (SeenUnknownCall)
333 continue;
334 SeenUnknownCall = true;
335 for (Function *PotentialCallee : AddressTakenFuncs)
336 Visit(PotentialCallee);
337 }
338 }
339
340 if (ReachesLDSInstructions)
341 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess.insert(&Kernel);
342 }
343}
344
345void AMDGPUSwLowerLDS::getUsesOfLDSByNonKernels() {
346 for (GlobalVariable *GV : FuncLDSAccessInfo.AllNonKernelLDSAccess) {
348 continue;
349
350 for (User *V : GV->users()) {
351 if (auto *I = dyn_cast<Instruction>(V)) {
352 Function *F = I->getFunction();
353 if (!isKernel(*F) && !F->isDeclaration())
354 FuncLDSAccessInfo.NonKernelToLDSAccessMap[F].insert(GV);
355 }
356 }
357 }
358}
359
360static void recordLDSAbsoluteAddress(Module &M, GlobalVariable *GV,
361 uint32_t Address) {
362 // Write the specified address into metadata where it can be retrieved by
363 // the assembler. Format is a half open range, [Address Address+1)
364 LLVMContext &Ctx = M.getContext();
365 auto *IntTy = M.getDataLayout().getIntPtrType(Ctx, AMDGPUAS::LOCAL_ADDRESS);
366 MDBuilder MDB(Ctx);
367 MDNode *MetadataNode = MDB.createRange(ConstantInt::get(IntTy, Address),
368 ConstantInt::get(IntTy, Address + 1));
369 GV->setMetadata(LLVMContext::MD_absolute_symbol, MetadataNode);
370}
371
372static void addLDSSizeAttribute(Function *Func, uint32_t Offset,
373 bool IsDynLDS) {
374 if (Offset != 0) {
375 std::string Buffer;
376 raw_string_ostream SS{Buffer};
377 SS << Offset;
378 if (IsDynLDS)
379 SS << "," << Offset;
380 Func->addFnAttr("amdgpu-lds-size", Buffer);
381 }
382}
383
384static void markUsedByKernel(Function *Func, GlobalVariable *SGV) {
385 BasicBlock *Entry = &Func->getEntryBlock();
386 IRBuilder<> Builder(Entry->getFirstNonPHIIt());
387
388 Function *Decl = Intrinsic::getOrInsertDeclaration(Func->getParent(),
389 Intrinsic::donothing, {});
390
391 Value *UseInstance[1] = {
392 Builder.CreateConstInBoundsGEP1_32(SGV->getValueType(), SGV, 0)};
393
394 Builder.CreateCall(Decl, {},
395 {OperandBundleDefT<Value *>("ExplicitUse", UseInstance)});
396}
397
398void AMDGPUSwLowerLDS::buildSwLDSGlobal(Function *Func) {
399 // Create new LDS global required for each kernel to store
400 // device global memory pointer.
401 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
402 // Create new global pointer variable
403 LDSParams.SwLDS = new GlobalVariable(
404 M, IRB.getPtrTy(), false, GlobalValue::InternalLinkage,
405 PoisonValue::get(IRB.getPtrTy()), "llvm.amdgcn.sw.lds." + Func->getName(),
408 MD.NoAddress = true;
409 LDSParams.SwLDS->setSanitizerMetadata(MD);
410}
411
412void AMDGPUSwLowerLDS::buildSwDynLDSGlobal(Function *Func) {
413 // Create new Dyn LDS global if kernel accesses dyn LDS.
414 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
415 if (LDSParams.DirectAccess.DynamicLDSGlobals.empty() &&
416 LDSParams.IndirectAccess.DynamicLDSGlobals.empty())
417 return;
418 // Create new global pointer variable
419 auto *emptyCharArray = ArrayType::get(IRB.getInt8Ty(), 0);
420 LDSParams.SwDynLDS = new GlobalVariable(
421 M, emptyCharArray, false, GlobalValue::ExternalLinkage, nullptr,
422 "llvm.amdgcn." + Func->getName() + ".dynlds", nullptr,
424 markUsedByKernel(Func, LDSParams.SwDynLDS);
426 MD.NoAddress = true;
427 LDSParams.SwDynLDS->setSanitizerMetadata(MD);
428}
429
430void AMDGPUSwLowerLDS::populateSwLDSAttributeAndMetadata(Function *Func) {
431 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
432 bool IsDynLDSUsed = LDSParams.SwDynLDS;
433 uint32_t Offset = LDSParams.LDSSize;
434 recordLDSAbsoluteAddress(M, LDSParams.SwLDS, 0);
435 addLDSSizeAttribute(Func, Offset, IsDynLDSUsed);
436 if (LDSParams.SwDynLDS)
437 recordLDSAbsoluteAddress(M, LDSParams.SwDynLDS, Offset);
438}
439
440void AMDGPUSwLowerLDS::populateSwMetadataGlobal(Function *Func) {
441 // Create new metadata global for every kernel and initialize the
442 // start offsets and sizes corresponding to each LDS accesses.
443 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
444 auto &Ctx = M.getContext();
445 auto &DL = M.getDataLayout();
446 std::vector<Type *> Items;
447 Type *Int32Ty = IRB.getInt32Ty();
448 std::vector<Constant *> Initializers;
449 Align MaxAlignment(1);
450 auto UpdateMaxAlignment = [&MaxAlignment, &DL](GlobalVariable *GV) {
451 Align GVAlign = AMDGPU::getAlign(DL, GV);
452 MaxAlignment = std::max(MaxAlignment, GVAlign);
453 };
454
455 for (GlobalVariable *GV : LDSParams.DirectAccess.StaticLDSGlobals)
456 UpdateMaxAlignment(GV);
457
458 for (GlobalVariable *GV : LDSParams.DirectAccess.DynamicLDSGlobals)
459 UpdateMaxAlignment(GV);
460
461 for (GlobalVariable *GV : LDSParams.IndirectAccess.StaticLDSGlobals)
462 UpdateMaxAlignment(GV);
463
464 for (GlobalVariable *GV : LDSParams.IndirectAccess.DynamicLDSGlobals)
465 UpdateMaxAlignment(GV);
466
467 //{StartOffset, AlignedSizeInBytes}
468 SmallString<128> MDItemStr;
469 raw_svector_ostream MDItemOS(MDItemStr);
470 MDItemOS << "llvm.amdgcn.sw.lds." << Func->getName() << ".md.item";
471
472 StructType *LDSItemTy =
473 StructType::create(Ctx, {Int32Ty, Int32Ty, Int32Ty}, MDItemOS.str());
474 uint32_t &MallocSize = LDSParams.MallocSize;
475 SetVector<GlobalVariable *> UniqueLDSGlobals;
476 int AsanScale = AsanInfo.Scale;
477 auto buildInitializerForSwLDSMD =
478 [&](SetVector<GlobalVariable *> &LDSGlobals) {
479 for (auto &GV : LDSGlobals) {
480 if (is_contained(UniqueLDSGlobals, GV))
481 continue;
482 UniqueLDSGlobals.insert(GV);
483
484 Type *Ty = GV->getValueType();
485 const uint64_t SizeInBytes = DL.getTypeAllocSize(Ty);
486 Items.push_back(LDSItemTy);
487 Constant *ItemStartOffset = ConstantInt::get(Int32Ty, MallocSize);
488 Constant *SizeInBytesConst = ConstantInt::get(Int32Ty, SizeInBytes);
489 // Get redzone size corresponding a size.
490 const uint64_t RightRedzoneSize =
491 AMDGPU::getRedzoneSizeForGlobal(AsanScale, SizeInBytes);
492 // Update MallocSize with current size and redzone size.
493 MallocSize += SizeInBytes;
494 if (!AMDGPU::isDynamicLDS(*GV))
495 LDSParams.RedzoneOffsetAndSizeVector.emplace_back(MallocSize,
496 RightRedzoneSize);
497 MallocSize += RightRedzoneSize;
498 // Align current size plus redzone.
499 uint64_t AlignedSize =
500 alignTo(SizeInBytes + RightRedzoneSize, MaxAlignment);
501 Constant *AlignedSizeInBytesConst =
502 ConstantInt::get(Int32Ty, AlignedSize);
503 // Align MallocSize
504 MallocSize = alignTo(MallocSize, MaxAlignment);
505 Constant *InitItem =
506 ConstantStruct::get(LDSItemTy, {ItemStartOffset, SizeInBytesConst,
507 AlignedSizeInBytesConst});
508 Initializers.push_back(InitItem);
509 }
510 };
511 SetVector<GlobalVariable *> SwLDSVector;
512 SwLDSVector.insert(LDSParams.SwLDS);
513 buildInitializerForSwLDSMD(SwLDSVector);
514 buildInitializerForSwLDSMD(LDSParams.DirectAccess.StaticLDSGlobals);
515 buildInitializerForSwLDSMD(LDSParams.IndirectAccess.StaticLDSGlobals);
516 buildInitializerForSwLDSMD(LDSParams.DirectAccess.DynamicLDSGlobals);
517 buildInitializerForSwLDSMD(LDSParams.IndirectAccess.DynamicLDSGlobals);
518
519 // Update the LDS size used by the kernel.
520 Type *Ty = LDSParams.SwLDS->getValueType();
521 const uint64_t SizeInBytes = DL.getTypeAllocSize(Ty);
522 uint64_t AlignedSize = alignTo(SizeInBytes, MaxAlignment);
523 LDSParams.LDSSize = AlignedSize;
524 SmallString<128> MDTypeStr;
525 raw_svector_ostream MDTypeOS(MDTypeStr);
526 MDTypeOS << "llvm.amdgcn.sw.lds." << Func->getName() << ".md.type";
527 StructType *MetadataStructType =
528 StructType::create(Ctx, Items, MDTypeOS.str());
529 SmallString<128> MDStr;
530 raw_svector_ostream MDOS(MDStr);
531 MDOS << "llvm.amdgcn.sw.lds." << Func->getName() << ".md";
532 LDSParams.SwLDSMetadata = new GlobalVariable(
533 M, MetadataStructType, false, GlobalValue::InternalLinkage,
534 PoisonValue::get(MetadataStructType), MDOS.str(), nullptr,
536 Constant *data = ConstantStruct::get(MetadataStructType, Initializers);
537 LDSParams.SwLDSMetadata->setInitializer(data);
538 assert(LDSParams.SwLDS);
539 // Set the alignment to MaxAlignment for SwLDS.
540 LDSParams.SwLDS->setAlignment(MaxAlignment);
541 if (LDSParams.SwDynLDS)
542 LDSParams.SwDynLDS->setAlignment(MaxAlignment);
544 MD.NoAddress = true;
545 LDSParams.SwLDSMetadata->setSanitizerMetadata(MD);
546}
547
548void AMDGPUSwLowerLDS::populateLDSToReplacementIndicesMap(Function *Func) {
549 // Fill the corresponding LDS replacement indices for each LDS access
550 // related to this kernel.
551 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
552 SetVector<GlobalVariable *> UniqueLDSGlobals;
553 auto PopulateIndices = [&](SetVector<GlobalVariable *> &LDSGlobals,
554 uint32_t &Idx) {
555 for (auto &GV : LDSGlobals) {
556 if (is_contained(UniqueLDSGlobals, GV))
557 continue;
558 UniqueLDSGlobals.insert(GV);
559 LDSParams.LDSToReplacementIndicesMap[GV] = {0, Idx, 0};
560 ++Idx;
561 }
562 };
563 uint32_t Idx = 0;
564 SetVector<GlobalVariable *> SwLDSVector;
565 SwLDSVector.insert(LDSParams.SwLDS);
566 PopulateIndices(SwLDSVector, Idx);
567 PopulateIndices(LDSParams.DirectAccess.StaticLDSGlobals, Idx);
568 PopulateIndices(LDSParams.IndirectAccess.StaticLDSGlobals, Idx);
569 PopulateIndices(LDSParams.DirectAccess.DynamicLDSGlobals, Idx);
570 PopulateIndices(LDSParams.IndirectAccess.DynamicLDSGlobals, Idx);
571}
572
573static void replacesUsesOfGlobalInFunction(Function *Func, GlobalVariable *GV,
574 Value *Replacement) {
575 // Replace all uses of LDS global in this Function with a Replacement.
576 auto ReplaceUsesLambda = [Func](const Use &U) -> bool {
577 auto *V = U.getUser();
578 if (auto *Inst = dyn_cast<Instruction>(V)) {
579 auto *Func1 = Inst->getFunction();
580 if (Func == Func1)
581 return true;
582 }
583 return false;
584 };
585 GV->replaceUsesWithIf(Replacement, ReplaceUsesLambda);
586}
587
588void AMDGPUSwLowerLDS::replaceKernelLDSAccesses(Function *Func) {
589 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
590 GlobalVariable *SwLDS = LDSParams.SwLDS;
591 assert(SwLDS);
592 GlobalVariable *SwLDSMetadata = LDSParams.SwLDSMetadata;
593 assert(SwLDSMetadata);
594 StructType *SwLDSMetadataStructType =
595 cast<StructType>(SwLDSMetadata->getValueType());
596 Type *Int32Ty = IRB.getInt32Ty();
597 auto &IndirectAccess = LDSParams.IndirectAccess;
598 auto &DirectAccess = LDSParams.DirectAccess;
599 // Replace all uses of LDS global in this Function with a Replacement.
600 SetVector<GlobalVariable *> UniqueLDSGlobals;
601 auto ReplaceLDSGlobalUses = [&](SetVector<GlobalVariable *> &LDSGlobals) {
602 for (auto &GV : LDSGlobals) {
603 // Do not generate instructions if LDS access is in non-kernel
604 // i.e indirect-access.
605 if ((IndirectAccess.StaticLDSGlobals.contains(GV) ||
606 IndirectAccess.DynamicLDSGlobals.contains(GV)) &&
607 (!DirectAccess.StaticLDSGlobals.contains(GV) &&
608 !DirectAccess.DynamicLDSGlobals.contains(GV)))
609 continue;
610 if (is_contained(UniqueLDSGlobals, GV))
611 continue;
612 UniqueLDSGlobals.insert(GV);
613 auto &Indices = LDSParams.LDSToReplacementIndicesMap[GV];
614 assert(Indices.size() == 3);
615 Constant *GEPIdx[] = {ConstantInt::get(Int32Ty, Indices[0]),
616 ConstantInt::get(Int32Ty, Indices[1]),
617 ConstantInt::get(Int32Ty, Indices[2])};
619 Func->getDataLayout(), SwLDSMetadataStructType, SwLDSMetadata, GEPIdx,
621 Value *Offset = IRB.CreateLoad(Int32Ty, GEP);
622 Value *BasePlusOffset =
623 IRB.CreateInBoundsGEP(IRB.getInt8Ty(), SwLDS, {Offset});
624 LLVM_DEBUG(GV->printAsOperand(dbgs() << "Sw LDS Lowering, Replacing LDS ",
625 false));
626 replacesUsesOfGlobalInFunction(Func, GV, BasePlusOffset);
627 }
628 };
629 ReplaceLDSGlobalUses(DirectAccess.StaticLDSGlobals);
630 ReplaceLDSGlobalUses(IndirectAccess.StaticLDSGlobals);
631 ReplaceLDSGlobalUses(DirectAccess.DynamicLDSGlobals);
632 ReplaceLDSGlobalUses(IndirectAccess.DynamicLDSGlobals);
633}
634
635void AMDGPUSwLowerLDS::updateMallocSizeForDynamicLDS(
636 Function *Func, Value **CurrMallocSize, Value *HiddenDynLDSSize,
637 SetVector<GlobalVariable *> &DynamicLDSGlobals) {
638 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
639 Type *Int32Ty = IRB.getInt32Ty();
640
641 GlobalVariable *SwLDS = LDSParams.SwLDS;
642 GlobalVariable *SwLDSMetadata = LDSParams.SwLDSMetadata;
643 assert(SwLDS && SwLDSMetadata);
644 StructType *MetadataStructType =
645 cast<StructType>(SwLDSMetadata->getValueType());
646 unsigned MaxAlignment = SwLDS->getAlign().valueOrOne().value();
647 Value *MaxAlignValue = IRB.getInt32(MaxAlignment);
648 Value *MaxAlignValueMinusOne = IRB.getInt32(MaxAlignment - 1);
649
650 for (GlobalVariable *DynGV : DynamicLDSGlobals) {
651 auto &Indices = LDSParams.LDSToReplacementIndicesMap[DynGV];
652 // Update the Offset metadata.
653 Constant *Index0 = ConstantInt::get(Int32Ty, 0);
654 Constant *Index1 = ConstantInt::get(Int32Ty, Indices[1]);
655
656 Constant *Index2Offset = ConstantInt::get(Int32Ty, 0);
657 auto *GEPForOffset = IRB.CreateInBoundsGEP(
658 MetadataStructType, SwLDSMetadata, {Index0, Index1, Index2Offset});
659
660 IRB.CreateStore(*CurrMallocSize, GEPForOffset);
661 // Update the size and Aligned Size metadata.
662 Constant *Index2Size = ConstantInt::get(Int32Ty, 1);
663 auto *GEPForSize = IRB.CreateInBoundsGEP(MetadataStructType, SwLDSMetadata,
664 {Index0, Index1, Index2Size});
665
666 Value *CurrDynLDSSize = IRB.CreateLoad(Int32Ty, HiddenDynLDSSize);
667 IRB.CreateStore(CurrDynLDSSize, GEPForSize);
668 Constant *Index2AlignedSize = ConstantInt::get(Int32Ty, 2);
669 auto *GEPForAlignedSize = IRB.CreateInBoundsGEP(
670 MetadataStructType, SwLDSMetadata, {Index0, Index1, Index2AlignedSize});
671
672 Value *AlignedDynLDSSize =
673 IRB.CreateAdd(CurrDynLDSSize, MaxAlignValueMinusOne);
674 AlignedDynLDSSize = IRB.CreateUDiv(AlignedDynLDSSize, MaxAlignValue);
675 AlignedDynLDSSize = IRB.CreateMul(AlignedDynLDSSize, MaxAlignValue);
676 IRB.CreateStore(AlignedDynLDSSize, GEPForAlignedSize);
677
678 // Update the Current Malloc Size
679 *CurrMallocSize = IRB.CreateAdd(*CurrMallocSize, AlignedDynLDSSize);
680 }
681}
682
683static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore,
684 DISubprogram *SP) {
685 assert(InsertBefore);
686 if (InsertBefore->getDebugLoc())
687 return InsertBefore->getDebugLoc();
688 if (SP)
689 return DILocation::get(SP->getContext(), SP->getLine(), 1, SP);
690 return DebugLoc();
691}
692
693void AMDGPUSwLowerLDS::getLDSMemoryInstructions(
694 Function *Func, SetVector<Instruction *> &LDSInstructions) {
695 for (Instruction &Inst : instructions(Func))
696 if (isLDSMemoryInstruction(Inst))
697 LDSInstructions.insert(&Inst);
698}
699
700Value *AMDGPUSwLowerLDS::getTranslatedGlobalMemoryPtrOfLDS(Value *LoadMallocPtr,
701 Value *LDSPtr) {
702 assert(LDSPtr && "Invalid LDS pointer operand");
703 Type *LDSPtrType = LDSPtr->getType();
704 LLVMContext &Ctx = M.getContext();
705 const DataLayout &DL = M.getDataLayout();
706 Type *IntTy = DL.getIntPtrType(Ctx, AMDGPUAS::LOCAL_ADDRESS);
707 if (auto *VecPtrTy = dyn_cast<VectorType>(LDSPtrType)) {
708 // Handle vector of pointers
709 ElementCount NumElements = VecPtrTy->getElementCount();
710 IntTy = VectorType::get(IntTy, NumElements);
711 }
712 Value *GepIndex = IRB.CreatePtrToInt(LDSPtr, IntTy);
713 return IRB.CreateInBoundsGEP(IRB.getInt8Ty(), LoadMallocPtr, {GepIndex});
714}
715
716// A flat pointer to lowered LDS holds a global address inside the malloc
717// buffer, but LDS values in this pass are offsets into that buffer.
718// Rebase it as inttoptr(trunc(ptrtoaddr(flat) - ptrtoaddr(buf))).
719Value *AMDGPUSwLowerLDS::getTranslatedLDSPtrOfFlat(Value *LoadMallocPtr,
720 Value *FlatPtr,
721 Type *LDSPtrTy) {
722 const DataLayout &DL = M.getDataLayout();
723 Value *FlatAddr = IRB.CreatePtrToAddr(FlatPtr);
724 Value *Base = IRB.CreatePtrToAddr(LoadMallocPtr);
725 if (auto *VecTy = dyn_cast<VectorType>(FlatAddr->getType()))
726 Base = IRB.CreateVectorSplat(VecTy->getElementCount(), Base);
727 Value *Diff = IRB.CreateSub(FlatAddr, Base);
728 Value *Offset = IRB.CreateTrunc(Diff, DL.getAddressType(LDSPtrTy));
729 Value *LDSPtr = IRB.CreateIntToPtr(Offset, LDSPtrTy);
730 // Flat null is 0 but LDS null is -1, which the rebased offset cannot keep.
732 Constant::getNullValue(FlatPtr->getType()), LDSPtrTy);
733 return IRB.CreateSelect(IRB.CreateIsNull(FlatPtr), LDSNull, LDSPtr);
734}
735
736void AMDGPUSwLowerLDS::translateLDSMemoryOperationsToGlobalMemory(
737 Function *Func, Value *LoadMallocPtr,
738 SetVector<Instruction *> &LDSInstructions) {
739 LLVM_DEBUG(dbgs() << "Translating LDS memory operations to global memory : "
740 << Func->getName());
741 for (Instruction *Inst : LDSInstructions) {
742 IRB.SetInsertPoint(Inst);
743 if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
744 Value *LIOperand = LI->getPointerOperand();
745 Value *Replacement =
746 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, LIOperand);
747 LoadInst *NewLI =
748 IRB.CreateLoad(LI->getType(), Replacement, LI->getProperties());
749 AsanInfo.Instructions.insert(NewLI);
750 LI->replaceAllUsesWith(NewLI);
751 LI->eraseFromParent();
752 } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
753 Value *SIOperand = SI->getPointerOperand();
754 Value *Replacement =
755 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, SIOperand);
756 StoreInst *NewSI = IRB.CreateStore(SI->getValueOperand(), Replacement,
757 SI->getProperties());
758 AsanInfo.Instructions.insert(NewSI);
759 SI->replaceAllUsesWith(NewSI);
760 SI->eraseFromParent();
761 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(Inst)) {
762 Value *RMWPtrOperand = RMW->getPointerOperand();
763 Value *RMWValOperand = RMW->getValOperand();
764 Value *Replacement =
765 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, RMWPtrOperand);
766 AtomicRMWInst *NewRMW = IRB.CreateAtomicRMW(
767 RMW->getOperation(), Replacement, RMWValOperand, RMW->getAlign(),
768 RMW->getOrdering(), RMW->getSyncScopeID());
769 NewRMW->setVolatile(RMW->isVolatile());
770 AsanInfo.Instructions.insert(NewRMW);
771 RMW->replaceAllUsesWith(NewRMW);
772 RMW->eraseFromParent();
773 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(Inst)) {
774 Value *XCHGPtrOperand = XCHG->getPointerOperand();
775 Value *Replacement =
776 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, XCHGPtrOperand);
778 Replacement, XCHG->getCompareOperand(), XCHG->getNewValOperand(),
779 XCHG->getAlign(), XCHG->getSuccessOrdering(),
780 XCHG->getFailureOrdering(), XCHG->getSyncScopeID());
781 NewXCHG->setVolatile(XCHG->isVolatile());
782 AsanInfo.Instructions.insert(NewXCHG);
783 XCHG->replaceAllUsesWith(NewXCHG);
784 XCHG->eraseFromParent();
785 } else if (AnyMemIntrinsic *MI = dyn_cast<AnyMemIntrinsic>(Inst)) {
786 Value *NewDest = MI->getRawDest();
787 if (MI->getDestAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
788 NewDest = getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, NewDest);
789 CallInst *NewMI = nullptr;
791 if (MI->isAtomic()) {
793 NewDest, MSI->getValue(), MSI->getLength(),
794 MSI->getDestAlign().valueOrOne(), MSI->getElementSizeInBytes());
795 } else {
796 NewMI = IRB.CreateMemSet(NewDest, MSI->getValue(), MSI->getLength(),
797 MSI->getDestAlign(),
798 cast<MemSetInst>(MI)->isVolatile());
799 }
801 Value *NewSrc = MTI->getRawSource();
802 if (MTI->getSourceAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
803 NewSrc = getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, NewSrc);
804 if (MI->isAtomic()) {
805 if (MI->getIntrinsicID() ==
806 Intrinsic::memmove_element_unordered_atomic) {
808 NewDest, MTI->getDestAlign().valueOrOne(), NewSrc,
809 MTI->getSourceAlign().valueOrOne(), MTI->getLength(),
810 MTI->getElementSizeInBytes());
811 } else {
813 NewDest, MTI->getDestAlign().valueOrOne(), NewSrc,
814 MTI->getSourceAlign().valueOrOne(), MTI->getLength(),
815 MTI->getElementSizeInBytes());
816 }
817 } else {
818 NewMI = IRB.CreateMemTransferInst(
819 MI->getIntrinsicID(), NewDest, MTI->getDestAlign(), NewSrc,
820 MTI->getSourceAlign(), MTI->getLength(),
821 cast<MemTransferInst>(MI)->isVolatile());
822 }
823 } else
824 reportFatalUsageError("Unimplemented LDS lowering memory intrinsic");
825 AsanInfo.Instructions.insert(NewMI);
826 MI->replaceAllUsesWith(NewMI);
827 MI->eraseFromParent();
828 } else if (AddrSpaceCastInst *ASC = dyn_cast<AddrSpaceCastInst>(Inst)) {
829 Value *AIOperand = ASC->getPointerOperand();
830 Value *NewAI = nullptr;
831 if (ASC->getDestAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
832 NewAI =
833 getTranslatedLDSPtrOfFlat(LoadMallocPtr, AIOperand, ASC->getType());
834 } else {
835 Value *Replacement =
836 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, AIOperand);
837 // Note: No need to add the instruction to AsanInfo instructions to be
838 // instrumented list. FLAT_ADDRESS ptr would have been already
839 // instrumented by asan pass prior to this pass.
840 NewAI = IRB.CreateAddrSpaceCast(Replacement, ASC->getType());
841 }
842 ASC->replaceAllUsesWith(NewAI);
843 ASC->eraseFromParent();
844 } else
845 report_fatal_error("Unimplemented LDS lowering instruction");
846 }
847}
848
849void AMDGPUSwLowerLDS::poisonRedzones(Function *Func, Value *MallocPtr) {
850 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
851 Type *Int64Ty = IRB.getInt64Ty();
852 Type *VoidTy = IRB.getVoidTy();
853 FunctionCallee AsanPoisonRegion = M.getOrInsertFunction(
854 "__asan_poison_region",
855 FunctionType::get(VoidTy, {Int64Ty, Int64Ty}, false));
856
857 auto RedzonesVec = LDSParams.RedzoneOffsetAndSizeVector;
858 size_t VecSize = RedzonesVec.size();
859 for (unsigned i = 0; i < VecSize; i++) {
860 auto &RedzonePair = RedzonesVec[i];
861 uint64_t RedzoneOffset = RedzonePair.first;
862 uint64_t RedzoneSize = RedzonePair.second;
863 Value *RedzoneAddrOffset = IRB.CreateInBoundsGEP(
864 IRB.getInt8Ty(), MallocPtr, {IRB.getInt64(RedzoneOffset)});
865 Value *RedzoneAddress = IRB.CreatePtrToInt(RedzoneAddrOffset, Int64Ty);
866 IRB.CreateCall(AsanPoisonRegion,
867 {RedzoneAddress, IRB.getInt64(RedzoneSize)});
868 }
869}
870
871void AMDGPUSwLowerLDS::lowerKernelLDSAccesses(Function *Func,
872 DomTreeUpdater &DTU) {
873 LLVM_DEBUG(dbgs() << "Sw Lowering Kernel LDS for : " << Func->getName());
874 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
875 auto &Ctx = M.getContext();
876 auto *PrevEntryBlock = &Func->getEntryBlock();
877 SetVector<Instruction *> LDSInstructions;
878 getLDSMemoryInstructions(Func, LDSInstructions);
879 const DataLayout &DL = M.getDataLayout();
880
881 // Create malloc block.
882 auto *MallocBlock = BasicBlock::Create(Ctx, "Malloc", Func, PrevEntryBlock);
883
884 // Create WIdBlock block which has instructions related to selection of
885 // {0,0,0} indiex work item in the work group.
886 auto *WIdBlock = BasicBlock::Create(Ctx, "WId", Func, MallocBlock);
887
888 // Move constant-size allocas from the original entry block to the new entry
889 // block (WIdBlock) so they remain static allocas. Splice the leading cluster
890 // in bulk, then move any stragglers that are interleaved with other
891 // instructions.
892 auto SplitIt = PrevEntryBlock->getFirstNonPHIOrAlloca();
893 WIdBlock->splice(WIdBlock->end(), PrevEntryBlock, PrevEntryBlock->begin(),
894 SplitIt);
895 for (Instruction &I : make_early_inc_range(*PrevEntryBlock))
896 if (auto *AI = dyn_cast<AllocaInst>(&I))
897 if (isa<ConstantInt>(AI->getArraySize()))
898 AI->moveBefore(*WIdBlock, WIdBlock->end());
899
900 IRB.SetInsertPoint(WIdBlock->end());
901 DebugLoc FirstDL =
902 getOrCreateDebugLoc(&*PrevEntryBlock->begin(), Func->getSubprogram());
903 IRB.SetCurrentDebugLocation(FirstDL);
904 Value *WIdx = IRB.CreateIntrinsic(Intrinsic::amdgcn_workitem_id_x, {});
905 Value *WIdy = IRB.CreateIntrinsic(Intrinsic::amdgcn_workitem_id_y, {});
906 Value *WIdz = IRB.CreateIntrinsic(Intrinsic::amdgcn_workitem_id_z, {});
907 Value *XYOr = IRB.CreateOr(WIdx, WIdy);
908 Value *XYZOr = IRB.CreateOr(XYOr, WIdz);
909 Value *WIdzCond = IRB.CreateICmpEQ(XYZOr, IRB.getInt32(0));
910
911 // All work items will branch to PrevEntryBlock except {0,0,0} index
912 // work item which will branch to malloc block.
913 IRB.CreateCondBr(WIdzCond, MallocBlock, PrevEntryBlock);
914
915 // Malloc block
916 IRB.SetInsertPoint(MallocBlock->begin());
917
918 // If Dynamic LDS globals are accessed by the kernel,
919 // Get the size of dyn lds from hidden dyn_lds_size kernel arg.
920 // Update the corresponding metadata global entries for this dyn lds global.
921 GlobalVariable *SwLDS = LDSParams.SwLDS;
922 GlobalVariable *SwLDSMetadata = LDSParams.SwLDSMetadata;
923 assert(SwLDS && SwLDSMetadata);
924 StructType *MetadataStructType =
925 cast<StructType>(SwLDSMetadata->getValueType());
926 Type *Int32Ty = IRB.getInt32Ty();
927 Type *Int64Ty = IRB.getInt64Ty();
928
929 SetVector<GlobalVariable *> UniqueLDSGlobals;
930 auto GetUniqueLDSGlobals = [&](SetVector<GlobalVariable *> &LDSGlobals) {
931 for (auto &GV : LDSGlobals) {
932 if (is_contained(UniqueLDSGlobals, GV))
933 continue;
934 UniqueLDSGlobals.insert(GV);
935 }
936 };
937
938 GetUniqueLDSGlobals(LDSParams.DirectAccess.StaticLDSGlobals);
939 GetUniqueLDSGlobals(LDSParams.IndirectAccess.StaticLDSGlobals);
940 // The metadata global always has an item for the SwLDS pointer itself, so
941 // there is at least one static item and the last one ends the static region.
942 unsigned LastStaticLDSIdx = UniqueLDSGlobals.size();
943 UniqueLDSGlobals.clear();
944
945 auto *GEPForEndStaticLDSOffset =
946 IRB.CreateInBoundsGEP(MetadataStructType, SwLDSMetadata,
947 {ConstantInt::get(Int32Ty, 0),
948 ConstantInt::get(Int32Ty, LastStaticLDSIdx),
949 ConstantInt::get(Int32Ty, 0)});
950
951 auto *GEPForEndStaticLDSSize =
952 IRB.CreateInBoundsGEP(MetadataStructType, SwLDSMetadata,
953 {ConstantInt::get(Int32Ty, 0),
954 ConstantInt::get(Int32Ty, LastStaticLDSIdx),
955 ConstantInt::get(Int32Ty, 2)});
956
957 Value *EndStaticLDSOffset = IRB.CreateLoad(Int32Ty, GEPForEndStaticLDSOffset);
958 Value *EndStaticLDSSize = IRB.CreateLoad(Int32Ty, GEPForEndStaticLDSSize);
959 Value *CurrMallocSize = IRB.CreateAdd(EndStaticLDSOffset, EndStaticLDSSize);
960
961 if (LDSParams.SwDynLDS) {
964 "Dynamic LDS size query is only supported for CO V5 and later.");
965 // Get size from hidden dyn_lds_size argument of kernel
967 IRB.CreateIntrinsic(Intrinsic::amdgcn_implicitarg_ptr, {});
968 Value *HiddenDynLDSSize = IRB.CreateInBoundsGEP(
969 ImplicitArg->getType(), ImplicitArg,
970 {ConstantInt::get(Int64Ty, COV5_HIDDEN_DYN_LDS_SIZE_ARG)});
971 UniqueLDSGlobals.clear();
972 GetUniqueLDSGlobals(LDSParams.DirectAccess.DynamicLDSGlobals);
973 GetUniqueLDSGlobals(LDSParams.IndirectAccess.DynamicLDSGlobals);
974 updateMallocSizeForDynamicLDS(Func, &CurrMallocSize, HiddenDynLDSSize,
975 UniqueLDSGlobals);
976 }
977
978 CurrMallocSize = IRB.CreateZExt(CurrMallocSize, Int64Ty);
979
980 // Create a call to malloc function which does device global memory allocation
981 // with size equals to all LDS global accesses size in this kernel.
982 Value *ReturnAddress = IRB.CreateIntrinsic(
983 Intrinsic::returnaddress, IRB.getPtrTy(DL.getProgramAddressSpace()),
984 {IRB.getInt32(0)});
985 FunctionCallee MallocFunc = M.getOrInsertFunction(
986 StringRef("__asan_malloc_impl"),
987 FunctionType::get(Int64Ty, {Int64Ty, Int64Ty}, false));
988 Value *RAPtrToInt = IRB.CreatePtrToInt(ReturnAddress, Int64Ty);
989 Value *MallocCall = IRB.CreateCall(MallocFunc, {CurrMallocSize, RAPtrToInt});
990
991 Value *MallocPtr =
993
994 // Create store of malloc to new global
995 IRB.CreateStore(MallocPtr, SwLDS);
996
997 // Create calls to __asan_poison_region to poison redzones.
998 poisonRedzones(Func, MallocPtr);
999
1000 // Create branch to PrevEntryBlock
1001 IRB.CreateBr(PrevEntryBlock);
1002
1003 // Create wave-group barrier at the starting of Previous entry block
1004 Type *Int1Ty = IRB.getInt1Ty();
1005 IRB.SetInsertPoint(PrevEntryBlock->begin());
1006 auto *XYZCondPhi = IRB.CreatePHI(Int1Ty, 2, "xyzCond");
1007 XYZCondPhi->addIncoming(IRB.getInt1(0), WIdBlock);
1008 XYZCondPhi->addIncoming(IRB.getInt1(1), MallocBlock);
1009
1010 IRB.CreateIntrinsic(Intrinsic::amdgcn_s_barrier, {});
1011
1012 // Load malloc pointer from Sw LDS.
1013 Value *LoadMallocPtr =
1015
1016 // Replace All uses of LDS globals with new LDS pointers.
1017 replaceKernelLDSAccesses(Func);
1018
1019 // Replace Memory Operations on LDS with corresponding
1020 // global memory pointers.
1021 translateLDSMemoryOperationsToGlobalMemory(Func, LoadMallocPtr,
1022 LDSInstructions);
1023
1024 auto *CondFreeBlock = BasicBlock::Create(Ctx, "CondFree", Func);
1025 auto *FreeBlock = BasicBlock::Create(Ctx, "Free", Func);
1026 auto *EndBlock = BasicBlock::Create(Ctx, "End", Func);
1027 for (BasicBlock &BB : *Func) {
1028 if (!BB.empty()) {
1029 if (ReturnInst *RI = dyn_cast<ReturnInst>(&BB.back())) {
1030 RI->eraseFromParent();
1031 IRB.SetInsertPoint(BB.end());
1032 IRB.CreateBr(CondFreeBlock);
1033 }
1034 }
1035 }
1036
1037 // Cond Free Block
1038 IRB.SetInsertPoint(CondFreeBlock->begin());
1039 IRB.CreateIntrinsic(Intrinsic::amdgcn_s_barrier, {});
1040 IRB.CreateCondBr(XYZCondPhi, FreeBlock, EndBlock);
1041
1042 // Free Block
1043 IRB.SetInsertPoint(FreeBlock->begin());
1044
1045 // Free the previously allocate device global memory.
1046 FunctionCallee AsanFreeFunc = M.getOrInsertFunction(
1047 StringRef("__asan_free_impl"),
1048 FunctionType::get(IRB.getVoidTy(), {Int64Ty, Int64Ty}, false));
1049 Value *ReturnAddr = IRB.CreateIntrinsic(
1050 Intrinsic::returnaddress, IRB.getPtrTy(DL.getProgramAddressSpace()),
1051 IRB.getInt32(0));
1052 Value *RAPToInt = IRB.CreatePtrToInt(ReturnAddr, Int64Ty);
1053 Value *MallocPtrToInt = IRB.CreatePtrToInt(LoadMallocPtr, Int64Ty);
1054 IRB.CreateCall(AsanFreeFunc, {MallocPtrToInt, RAPToInt});
1055
1056 IRB.CreateBr(EndBlock);
1057
1058 // End Block
1059 IRB.SetInsertPoint(EndBlock->begin());
1060 IRB.CreateRetVoid();
1061 // Update the DomTree with corresponding links to basic blocks.
1062 DTU.applyUpdates({{DominatorTree::Insert, WIdBlock, MallocBlock},
1063 {DominatorTree::Insert, MallocBlock, PrevEntryBlock},
1064 {DominatorTree::Insert, CondFreeBlock, FreeBlock},
1065 {DominatorTree::Insert, FreeBlock, EndBlock}});
1066}
1067
1068Constant *AMDGPUSwLowerLDS::getAddressesOfVariablesInKernel(
1069 Function *Func, SetVector<GlobalVariable *> &Variables) {
1070 Type *Int32Ty = IRB.getInt32Ty();
1071 ArrayType *KernelOffsetsType =
1073
1074 // Kernels with no direct or indirect LDS uses never read their offset row.
1075 auto KernelIt = FuncLDSAccessInfo.KernelToLDSParametersMap.find(Func);
1076 if (KernelIt == FuncLDSAccessInfo.KernelToLDSParametersMap.end() ||
1077 !KernelIt->second.SwLDSMetadata)
1078 return PoisonValue::get(KernelOffsetsType);
1079
1080 auto &LDSParams = KernelIt->second;
1081 GlobalVariable *SwLDSMetadata = LDSParams.SwLDSMetadata;
1082 auto *SwLDSMetadataStructType =
1083 cast<StructType>(SwLDSMetadata->getValueType());
1084
1085 SmallVector<Constant *> Elements;
1086 for (auto *GV : Variables) {
1087 auto It = LDSParams.LDSToReplacementIndicesMap.find(GV);
1088 if (It == LDSParams.LDSToReplacementIndicesMap.end()) {
1089 Elements.push_back(
1091 continue;
1092 }
1093 auto &Indices = It->second;
1094 Constant *GEPIdx[] = {ConstantInt::get(Int32Ty, Indices[0]),
1095 ConstantInt::get(Int32Ty, Indices[1]),
1096 ConstantInt::get(Int32Ty, Indices[2])};
1098 Func->getDataLayout(), SwLDSMetadataStructType, SwLDSMetadata, GEPIdx,
1100 Elements.push_back(GEP);
1101 }
1102 return ConstantArray::get(KernelOffsetsType, Elements);
1103}
1104
1105void AMDGPUSwLowerLDS::buildNonKernelLDSBaseTable(
1106 NonKernelLDSParameters &NKLDSParams) {
1107 // Base table will have single row, with elements of the row
1108 // placed as per kernel ID. Each element in the row corresponds
1109 // to addresss of "SW LDS" global of the kernel.
1110 auto &Kernels = NKLDSParams.OrderedKernels;
1111 if (Kernels.empty())
1112 return;
1113 const size_t NumberKernels = Kernels.size();
1115 ArrayType *AllKernelsOffsetsType = ArrayType::get(LDSPtrTy, NumberKernels);
1116 std::vector<Constant *> OverallConstantExprElts(NumberKernels);
1117 for (size_t i = 0; i < NumberKernels; i++) {
1118 // Null for kernels without LDS. Lowered functions still load this entry
1119 // on entry, but only use it on LDS paths these kernels never take.
1120 Constant *SwLDS = ConstantPointerNull::get(LDSPtrTy);
1121 auto It = FuncLDSAccessInfo.KernelToLDSParametersMap.find(Kernels[i]);
1122 if (It != FuncLDSAccessInfo.KernelToLDSParametersMap.end() &&
1123 It->second.SwLDS)
1124 SwLDS = It->second.SwLDS;
1125 OverallConstantExprElts[i] = SwLDS;
1126 }
1127 Constant *init =
1128 ConstantArray::get(AllKernelsOffsetsType, OverallConstantExprElts);
1129 NKLDSParams.LDSBaseTable = new GlobalVariable(
1130 M, AllKernelsOffsetsType, true, GlobalValue::InternalLinkage, init,
1131 "llvm.amdgcn.sw.lds.base.table", nullptr, GlobalValue::NotThreadLocal,
1134 MD.NoAddress = true;
1135 NKLDSParams.LDSBaseTable->setSanitizerMetadata(MD);
1136}
1137
1138void AMDGPUSwLowerLDS::buildNonKernelLDSOffsetTable(
1139 NonKernelLDSParameters &NKLDSParams) {
1140 // Offset table will have multiple rows and columns.
1141 // Rows are assumed to be from 0 to (n-1). n is total number
1142 // of kernels accessing the LDS through non-kernels.
1143 // Each row will have m elements. m is the total number of
1144 // unique LDS globals accessed by non-kernels.
1145 // Each element in the row correspond to the address of
1146 // the replacement of LDS global done by that particular kernel.
1147 auto &Variables = NKLDSParams.OrdereLDSGlobals;
1148 auto &Kernels = NKLDSParams.OrderedKernels;
1149 if (Variables.empty() || Kernels.empty())
1150 return;
1151 const size_t NumberVariables = Variables.size();
1152 const size_t NumberKernels = Kernels.size();
1153
1154 ArrayType *KernelOffsetsType =
1155 ArrayType::get(IRB.getPtrTy(AMDGPUAS::GLOBAL_ADDRESS), NumberVariables);
1156
1157 ArrayType *AllKernelsOffsetsType =
1158 ArrayType::get(KernelOffsetsType, NumberKernels);
1159 std::vector<Constant *> overallConstantExprElts(NumberKernels);
1160 for (size_t i = 0; i < NumberKernels; i++) {
1161 Function *Func = Kernels[i];
1162 overallConstantExprElts[i] =
1163 getAddressesOfVariablesInKernel(Func, Variables);
1164 }
1165 Constant *Init =
1166 ConstantArray::get(AllKernelsOffsetsType, overallConstantExprElts);
1167 NKLDSParams.LDSOffsetTable = new GlobalVariable(
1168 M, AllKernelsOffsetsType, true, GlobalValue::InternalLinkage, Init,
1169 "llvm.amdgcn.sw.lds.offset.table", nullptr, GlobalValue::NotThreadLocal,
1172 MD.NoAddress = true;
1173 NKLDSParams.LDSOffsetTable->setSanitizerMetadata(MD);
1174}
1175
1176void AMDGPUSwLowerLDS::lowerNonKernelLDSAccesses(
1177 Function *Func, SetVector<GlobalVariable *> &LDSGlobals,
1178 NonKernelLDSParameters &NKLDSParams) {
1179 // Replace LDS access in non-kernel with replacement queried from
1180 // Base table and offset from offset table.
1181 LLVM_DEBUG(dbgs() << "Sw LDS lowering, lower non-kernel access for : "
1182 << Func->getName());
1183 auto InsertAt = Func->getEntryBlock().getFirstNonPHIOrAlloca();
1184 IRB.SetInsertPoint(InsertAt);
1185
1186 // Get LDS memory instructions.
1187 SetVector<Instruction *> LDSInstructions;
1188 getLDSMemoryInstructions(Func, LDSInstructions);
1189
1190 auto *KernelId = IRB.CreateIntrinsic(Intrinsic::amdgcn_lds_kernel_id, {});
1191 GlobalVariable *LDSBaseTable = NKLDSParams.LDSBaseTable;
1192 GlobalVariable *LDSOffsetTable = NKLDSParams.LDSOffsetTable;
1193 auto &OrdereLDSGlobals = NKLDSParams.OrdereLDSGlobals;
1194 Value *BaseGEP = IRB.CreateInBoundsGEP(
1195 LDSBaseTable->getValueType(), LDSBaseTable, {IRB.getInt32(0), KernelId});
1196 Value *BaseLoad =
1197 IRB.CreateLoad(IRB.getPtrTy(AMDGPUAS::LOCAL_ADDRESS), BaseGEP);
1198 Value *LoadMallocPtr =
1199 IRB.CreateLoad(IRB.getPtrTy(AMDGPUAS::GLOBAL_ADDRESS), BaseLoad);
1200
1201 for (GlobalVariable *GV : LDSGlobals) {
1202 const auto *GVIt = llvm::find(OrdereLDSGlobals, GV);
1203 assert(GVIt != OrdereLDSGlobals.end());
1204 uint32_t GVOffset = std::distance(OrdereLDSGlobals.begin(), GVIt);
1205
1206 Value *OffsetGEP = IRB.CreateInBoundsGEP(
1207 LDSOffsetTable->getValueType(), LDSOffsetTable,
1208 {IRB.getInt32(0), KernelId, IRB.getInt32(GVOffset)});
1209 Value *OffsetLoad =
1210 IRB.CreateLoad(IRB.getPtrTy(AMDGPUAS::GLOBAL_ADDRESS), OffsetGEP);
1211 Value *Offset = IRB.CreateLoad(IRB.getInt32Ty(), OffsetLoad);
1212 Value *BasePlusOffset =
1213 IRB.CreateInBoundsGEP(IRB.getInt8Ty(), BaseLoad, {Offset});
1214 LLVM_DEBUG(dbgs() << "Sw LDS Lowering, Replace non-kernel LDS for "
1215 << GV->getName());
1216 replacesUsesOfGlobalInFunction(Func, GV, BasePlusOffset);
1217 }
1218 translateLDSMemoryOperationsToGlobalMemory(Func, LoadMallocPtr,
1219 LDSInstructions);
1220}
1221
1222static void reorderStaticDynamicIndirectLDSSet(KernelLDSParameters &LDSParams) {
1223 // Sort Static, dynamic LDS globals which are either
1224 // direct or indirect access on basis of name.
1225 auto &DirectAccess = LDSParams.DirectAccess;
1226 auto &IndirectAccess = LDSParams.IndirectAccess;
1227 LDSParams.DirectAccess.StaticLDSGlobals = sortByName(
1228 std::vector<GlobalVariable *>(DirectAccess.StaticLDSGlobals.begin(),
1229 DirectAccess.StaticLDSGlobals.end()));
1230 LDSParams.DirectAccess.DynamicLDSGlobals = sortByName(
1231 std::vector<GlobalVariable *>(DirectAccess.DynamicLDSGlobals.begin(),
1232 DirectAccess.DynamicLDSGlobals.end()));
1233 LDSParams.IndirectAccess.StaticLDSGlobals = sortByName(
1234 std::vector<GlobalVariable *>(IndirectAccess.StaticLDSGlobals.begin(),
1235 IndirectAccess.StaticLDSGlobals.end()));
1236 LDSParams.IndirectAccess.DynamicLDSGlobals = sortByName(
1237 std::vector<GlobalVariable *>(IndirectAccess.DynamicLDSGlobals.begin(),
1238 IndirectAccess.DynamicLDSGlobals.end()));
1239}
1240
1241void AMDGPUSwLowerLDS::initAsanInfo() {
1242 // Get Shadow mapping scale and offset.
1243 unsigned LongSize =
1244 M.getDataLayout().getPointerSizeInBits(AMDGPUAS::GLOBAL_ADDRESS);
1246 int Scale;
1247 bool OrShadowOffset;
1248 llvm::getAddressSanitizerParams(M.getContext(), M.getTargetTriple(), LongSize,
1249 false, &Offset, &Scale, &OrShadowOffset);
1250 AsanInfo.Scale = Scale;
1251 AsanInfo.Offset = Offset;
1252}
1253
1254static bool hasFnWithSanitizeAddressAttr(FunctionVariableMap &LDSAccesses) {
1255 for (auto &K : LDSAccesses) {
1256 Function *F = K.first;
1257 if (!F)
1258 continue;
1259 if (F->hasFnAttribute(Attribute::SanitizeAddress))
1260 return true;
1261 }
1262 return false;
1263}
1264
1265bool AMDGPUSwLowerLDS::run() {
1266 bool Changed = false;
1267
1268 CallGraph CG = CallGraph(M);
1269
1270 Changed |=
1272
1273 // Get all the direct and indirect access of LDS for all the kernels.
1275
1276 // Flag to decide whether to lower all the LDS accesses
1277 // based on sanitize_address attribute.
1278 bool LowerAllLDS = hasFnWithSanitizeAddressAttr(LDSUsesInfo.DirectAccess) ||
1279 hasFnWithSanitizeAddressAttr(LDSUsesInfo.IndirectAccess);
1280
1281 if (!LowerAllLDS)
1282 return Changed;
1283
1284 // Utility to group LDS access into direct, indirect, static and dynamic.
1285 auto PopulateKernelStaticDynamicLDS = [&](FunctionVariableMap &LDSAccesses,
1286 bool DirectAccess) {
1287 for (auto &K : LDSAccesses) {
1288 Function *F = K.first;
1289 if (!F || K.second.empty())
1290 continue;
1291
1292 assert(isKernel(*F));
1293
1294 // Only inserts if key isn't already in the map.
1295 FuncLDSAccessInfo.KernelToLDSParametersMap.insert(
1296 {F, KernelLDSParameters()});
1297
1298 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[F];
1299 if (!DirectAccess)
1300 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess.insert(F);
1301 for (GlobalVariable *GV : K.second) {
1302 if (!DirectAccess) {
1303 if (AMDGPU::isDynamicLDS(*GV))
1304 LDSParams.IndirectAccess.DynamicLDSGlobals.insert(GV);
1305 else
1306 LDSParams.IndirectAccess.StaticLDSGlobals.insert(GV);
1307 FuncLDSAccessInfo.AllNonKernelLDSAccess.insert(GV);
1308 } else {
1309 if (AMDGPU::isDynamicLDS(*GV))
1310 LDSParams.DirectAccess.DynamicLDSGlobals.insert(GV);
1311 else
1312 LDSParams.DirectAccess.StaticLDSGlobals.insert(GV);
1313 }
1314 }
1315 }
1316 };
1317
1318 PopulateKernelStaticDynamicLDS(LDSUsesInfo.DirectAccess, true);
1319 PopulateKernelStaticDynamicLDS(LDSUsesInfo.IndirectAccess, false);
1320
1321 // Get address sanitizer scale.
1322 initAsanInfo();
1323
1324 for (auto &K : FuncLDSAccessInfo.KernelToLDSParametersMap) {
1325 Function *Func = K.first;
1326 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
1327 if (LDSParams.DirectAccess.StaticLDSGlobals.empty() &&
1328 LDSParams.DirectAccess.DynamicLDSGlobals.empty() &&
1329 LDSParams.IndirectAccess.StaticLDSGlobals.empty() &&
1330 LDSParams.IndirectAccess.DynamicLDSGlobals.empty())
1331 continue;
1332
1334 CG, Func,
1335 {"amdgpu-no-workitem-id-x", "amdgpu-no-workitem-id-y",
1336 "amdgpu-no-workitem-id-z", "amdgpu-no-heap-ptr"});
1337 reorderStaticDynamicIndirectLDSSet(LDSParams);
1338 buildSwLDSGlobal(Func);
1339 buildSwDynLDSGlobal(Func);
1340 populateSwMetadataGlobal(Func);
1341 populateSwLDSAttributeAndMetadata(Func);
1342 populateLDSToReplacementIndicesMap(Func);
1343 DomTreeUpdater DTU(DTCallback(*Func), DomTreeUpdater::UpdateStrategy::Lazy);
1344 lowerKernelLDSAccesses(Func, DTU);
1345 Changed = true;
1346 }
1347
1348 // Get the Uses of LDS from non-kernels.
1349 getUsesOfLDSByNonKernels();
1350
1351 // Get non-kernels with LDS instructions and the kernels reaching them.
1352 getNonKernelsWithLDSInstructions(CG);
1353
1354 // TODO: removeFnAttrFromReachable does not visit callees of indirect call
1355 // targets.
1356 for (Function *Func : FuncLDSAccessInfo.KernelsWithIndirectLDSAccess)
1357 removeFnAttrFromReachable(CG, Func, {"amdgpu-no-lds-kernel-id"});
1358
1359 // Lower LDS accesses in non-kernels.
1360 if (!FuncLDSAccessInfo.NonKernelToLDSAccessMap.empty() ||
1361 !FuncLDSAccessInfo.NonKernelsWithLDSInstructions.empty()) {
1362 NonKernelLDSParameters NKLDSParams;
1363 NKLDSParams.OrderedKernels = getOrderedIndirectLDSAccessingKernels(
1364 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess);
1365 NKLDSParams.OrdereLDSGlobals = getOrderedNonKernelAllLDSGlobals(
1366 FuncLDSAccessInfo.AllNonKernelLDSAccess);
1367 buildNonKernelLDSBaseTable(NKLDSParams);
1368 buildNonKernelLDSOffsetTable(NKLDSParams);
1369 for (auto &K : FuncLDSAccessInfo.NonKernelToLDSAccessMap) {
1370 Function *Func = K.first;
1371 DenseSet<GlobalVariable *> &LDSGlobals = K.second;
1372 SetVector<GlobalVariable *> OrderedLDSGlobals = sortByName(
1373 std::vector<GlobalVariable *>(LDSGlobals.begin(), LDSGlobals.end()));
1374 lowerNonKernelLDSAccesses(Func, OrderedLDSGlobals, NKLDSParams);
1375 }
1376 for (Function *Func : FuncLDSAccessInfo.NonKernelsWithLDSInstructions) {
1377 if (FuncLDSAccessInfo.NonKernelToLDSAccessMap.contains(Func))
1378 continue;
1379 SetVector<GlobalVariable *> NoLDSGlobals;
1380 lowerNonKernelLDSAccesses(Func, NoLDSGlobals, NKLDSParams);
1381 }
1382 Changed = true;
1383 }
1384
1385 if (!Changed)
1386 return Changed;
1387
1388 for (auto &GV : make_early_inc_range(M.globals())) {
1390 // probably want to remove from used lists
1392 if (GV.use_empty())
1393 GV.eraseFromParent();
1394 }
1395 }
1396
1397 if (AsanInstrumentLDS) {
1398 SmallVector<InterestingMemoryOperand, 16> OperandsToInstrument;
1399 for (Instruction *Inst : AsanInfo.Instructions) {
1400 SmallVector<InterestingMemoryOperand, 1> InterestingOperands;
1401 getInterestingMemoryOperands(M, Inst, InterestingOperands);
1402 llvm::append_range(OperandsToInstrument, InterestingOperands);
1403 }
1404 for (auto &Operand : OperandsToInstrument) {
1405 Value *Addr = Operand.getPtr();
1406 instrumentAddress(M, IRB, Operand.getInsn(), Operand.getInsn(), Addr,
1407 Operand.Alignment.valueOrOne(), Operand.TypeStoreSize,
1408 Operand.IsWrite, nullptr, false, false, AsanInfo.Scale,
1409 AsanInfo.Offset);
1410 Changed = true;
1411 }
1412 }
1413
1414 return Changed;
1415}
1416
1417class AMDGPUSwLowerLDSLegacy : public ModulePass {
1418public:
1419 static char ID;
1420 AMDGPUSwLowerLDSLegacy() : ModulePass(ID) {}
1421 bool runOnModule(Module &M) override;
1422 void getAnalysisUsage(AnalysisUsage &AU) const override {
1424 }
1425};
1426} // namespace
1427
1428char AMDGPUSwLowerLDSLegacy::ID = 0;
1429char &llvm::AMDGPUSwLowerLDSLegacyPassID = AMDGPUSwLowerLDSLegacy::ID;
1430
1431INITIALIZE_PASS_BEGIN(AMDGPUSwLowerLDSLegacy, "amdgpu-sw-lower-lds",
1432 "AMDGPU Software lowering of LDS", false, false)
1434INITIALIZE_PASS_END(AMDGPUSwLowerLDSLegacy, "amdgpu-sw-lower-lds",
1435 "AMDGPU Software lowering of LDS", false, false)
1436
1437bool AMDGPUSwLowerLDSLegacy::runOnModule(Module &M) {
1438 // AddressSanitizer pass adds "nosanitize_address" module flag if it has
1439 // instrumented the IR. Return early if the flag is not present.
1440 if (!M.getModuleFlag("nosanitize_address"))
1441 return false;
1442 DominatorTreeWrapperPass *const DTW =
1443 getAnalysisIfAvailable<DominatorTreeWrapperPass>();
1444 auto DTCallback = [&DTW](Function &F) -> DominatorTree * {
1445 return DTW ? &DTW->getDomTree() : nullptr;
1446 };
1447
1448 AMDGPUSwLowerLDS SwLowerLDSImpl(M, DTCallback);
1449 bool IsChanged = SwLowerLDSImpl.run();
1450 return IsChanged;
1451}
1452
1454 return new AMDGPUSwLowerLDSLegacy();
1455}
1456
1459 // AddressSanitizer pass adds "nosanitize_address" module flag if it has
1460 // instrumented the IR. Return early if the flag is not present.
1461 if (!M.getModuleFlag("nosanitize_address"))
1462 return PreservedAnalyses::all();
1463 auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
1464 auto DTCallback = [&FAM](Function &F) -> DominatorTree * {
1465 return &FAM.getResult<DominatorTreeAnalysis>(F);
1466 };
1467 AMDGPUSwLowerLDS SwLowerLDSImpl(M, DTCallback);
1468 bool IsChanged = SwLowerLDSImpl.run();
1469 if (!IsChanged)
1470 return PreservedAnalyses::all();
1471
1474 return PA;
1475}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
This file provides interfaces used to build and manipulate a call graph, which is a very useful tool ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Hexagon Common GEP
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
if(auto Err=PB.parsePassPipeline(MPM, Passes)) return wrap(std MPM run * Mod
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition PassSupport.h:42
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition PassSupport.h:39
static Split data
This file contains some functions that are useful when dealing with strings.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore, DISubprogram *SP)
This class represents a conversion between pointers from one address space to another.
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represent the analysis usage information of a pass.
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
This class represents any memset intrinsic.
static LLVM_ABI ArrayType * get(Type *ElementType, uint64_t NumElements)
This static method is the primary way to construct an ArrayType.
An instruction that atomically checks whether a specified value is in a memory location,...
void setVolatile(bool V)
Specify whether this is a volatile cmpxchg.
an instruction that atomically reads a memory location, combines it with another value,...
void setVolatile(bool V)
Specify whether this is a volatile RMW or not.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition BasicBlock.h:206
std::pair< std::optional< WeakTrackingVH >, CallGraphNode * > CallRecord
A pair of the calling instruction (a call or invoke) and the call graph node being called.
Definition CallGraph.h:174
The basic data container for the call graph of a Module of IR.
Definition CallGraph.h:72
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI Constant * get(ArrayType *T, ArrayRef< Constant * > V)
static ConstantAsMetadata * get(Constant *C)
Definition Metadata.h:548
static LLVM_SUPPRESS_DEPRECATED_DECLARATIONS_PUSH Constant * getGetElementPtr(Type *Ty, Constant *C, ArrayRef< Constant * > IdxList, GEPNoWrapFlags NW=GEPNoWrapFlags::none(), std::optional< ConstantRange > InRange=std::nullopt, Type *OnlyIfReducedTy=nullptr)
Getelementptr form.
Definition Constants.h:1477
static LLVM_ABI Constant * getAddrSpaceCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
static LLVM_ABI ConstantPointerNull * get(PointerType *T)
Static factory methods - Return objects of the specified value.
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
Definition Constant.h:44
LLVM_ABI void removeDeadConstantUsers() const
If there are any dead constant users dangling off of this constant, remove them.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
Subprogram description. Uses SubclassData1.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
A debug info location.
Definition DebugLoc.h:126
std::pair< iterator, bool > try_emplace(KeyT &&Key, Ts &&...Args)
Definition DenseMap.h:856
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
Analysis pass which computes a DominatorTree.
Definition Dominators.h:241
Legacy analysis pass which computes a DominatorTree.
Definition Dominators.h:277
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
static GEPNoWrapFlags inBounds()
void applyUpdates(ArrayRef< UpdateT > Updates)
Submit updates to all available trees.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set a particular kind of metadata attachment.
LLVM_ABI bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
Definition Globals.cpp:408
LLVM_ABI void setSanitizerMetadata(SanitizerMetadata Meta)
Definition Globals.cpp:324
@ InternalLinkage
Rename collisions when linking (static functions).
Definition GlobalValue.h:60
@ ExternalLinkage
Externally visible function.
Definition GlobalValue.h:53
Type * getValueType() const
MaybeAlign getAlign() const
Returns the alignment of the given variable.
LLVM_ABI void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it.
Definition Globals.cpp:609
ConstantInt * getInt1(bool V)
Get a constant value representing either true or false.
Definition IRBuilder.h:440
Value * CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNull=false)
Definition IRBuilder.h:2248
AtomicCmpXchgInst * CreateAtomicCmpXchg(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SyncScope::ID SSID=SyncScope::System)
Definition IRBuilder.h:1968
IntegerType * getInt1Ty()
Fetch the type representing a single bit.
Definition IRBuilder.h:507
CondBrInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
Definition IRBuilder.h:1212
Value * CreatePtrToAddr(Value *V, const Twine &Name="")
Definition IRBuilder.h:2229
LLVM_ABI Value * CreateVectorSplat(unsigned NumElts, Value *V, const Twine &Name="")
Return a vector value that contains.
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2238
void SetCurrentDebugLocation(const DebugLoc &L)
Set location information used by debugging information.
Definition IRBuilder.h:228
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition IRBuilder.h:522
IntegerType * getInt64Ty()
Fetch the type representing a 64-bit integer.
Definition IRBuilder.h:527
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
Definition IRBuilder.h:2019
LLVM_ABI CallInst * CreateElementUnorderedAtomicMemMove(Value *Dst, Align DstAlign, Value *Src, Align SrcAlign, Value *Size, uint32_t ElementSize, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert an element unordered-atomic memmove between the specified pointers.
Value * CreateUDiv(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition IRBuilder.h:1469
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
Definition IRBuilder.h:470
UncondBrInst * CreateBr(BasicBlock *Dest)
Create an unconditional 'br label X' instruction.
Definition IRBuilder.h:1206
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition IRBuilder.h:465
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition IRBuilder.h:2547
Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:2382
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1435
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
Definition IRBuilder.h:1907
CallInst * CreateElementUnorderedAtomicMemSet(Value *Ptr, Value *Val, uint64_t Size, Align Alignment, uint32_t ElementSize, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert an element unordered-atomic memset of the region of memory starting at the given po...
Definition IRBuilder.h:617
CallInst * CreateMemSet(Value *Ptr, Value *Val, uint64_t Size, MaybeAlign Align, bool isVolatile=false, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert a memset to the specified pointer and the specified value.
Definition IRBuilder.h:596
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Definition IRBuilder.h:2121
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
Definition IRBuilder.h:1183
LLVM_ABI Value * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > OverloadTypes, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="", ArrayRef< OperandBundleDef > OpBundles={}, function_ref< void(CallInst *)> SetFn=[](CallInst *) {})
Variant to create a possibly constant-folded intrinsic.
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Definition IRBuilder.h:1925
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1418
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2233
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2561
Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)
Definition IRBuilder.h:2107
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Definition IRBuilder.h:565
Value * CreateIsNull(Value *Arg, const Twine &Name="")
Return a boolean value testing if Arg == 0.
Definition IRBuilder.h:2758
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:196
Type * getVoidTy()
Fetch the type representing void.
Definition IRBuilder.h:560
LLVM_ABI CallInst * CreateElementUnorderedAtomicMemCpy(Value *Dst, Align DstAlign, Value *Src, Align SrcAlign, Value *Size, uint32_t ElementSize, const AAMDNodes &AAInfo=AAMDNodes())
Create and insert an element unordered-atomic memcpy between the specified pointers.
LLVM_ABI CallInst * CreateMemTransferInst(Intrinsic::ID IntrID, Value *Dst, MaybeAlign DstAlign, Value *Src, MaybeAlign SrcAlign, Value *Size, bool isVolatile=false, const AAMDNodes &AAInfo=AAMDNodes())
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
Definition IRBuilder.h:1588
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
Definition IRBuilder.h:512
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1452
AtomicRMWInst * CreateAtomicRMW(AtomicRMWInst::BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System, bool Elementwise=false)
Definition IRBuilder.h:1981
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2909
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:76
An instruction for reading from memory.
LLVM_ABI MDNode * createRange(const APInt &Lo, const APInt &Hi)
Return metadata describing the range [Lo, Hi).
Definition MDBuilder.cpp:92
Metadata node.
Definition Metadata.h:1081
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1579
This class implements a map that also provides access to all stored values in a deterministic order.
Definition MapVector.h:38
bool empty() const
Definition MapVector.h:79
bool contains(const KeyT &Key) const
Definition MapVector.h:148
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition MapVector.h:126
Root of the metadata hierarchy.
Definition Metadata.h:64
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Definition Pass.h:253
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:68
A container for an operand bundle being viewed as a set of values rather than a set of uses.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
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 & preserve()
Mark an analysis as preserved.
Definition Analysis.h:132
Return a value (possibly void), from a function.
A vector that has set insertion semantics.
Definition SetVector.h:57
size_type size() const
Determine the number of elements in the SetVector.
Definition SetVector.h:103
iterator end()
Get an iterator to the end of the SetVector.
Definition SetVector.h:118
void clear()
Completely clear the SetVector.
Definition SetVector.h:273
bool empty() const
Determine if the SetVector is empty or not.
Definition SetVector.h:100
iterator begin()
Get an iterator to the beginning of the SetVector.
Definition SetVector.h:112
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
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.
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
Class to represent struct types.
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition Type.cpp:662
Target-Independent Code Generator Pass Configuration Options.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
LLVM Value Representation.
Definition Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition Value.h:257
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:549
iterator_range< user_iterator > users()
Definition Value.h:428
LLVM_ABI void printAsOperand(raw_ostream &O, bool PrintType=true, const Module *M=nullptr) const
Print the name of this Value out to the specified raw_ostream.
bool use_empty() const
Definition Value.h:348
LLVM_ABI bool replaceUsesWithIf(Value *New, llvm::function_ref< bool(Use &U)> ShouldReplace)
Go through the uses list for this definition and make each use point to "V" if the callback ShouldRep...
Definition Value.cpp:557
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:315
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
An efficient, type-erasing, non-owning reference to a callable.
A raw_ostream that writes to an std::string.
A raw_ostream that writes to an SmallVector or SmallString.
StringRef str() const
Return a StringRef for the vector contents.
Changed
@ LOCAL_ADDRESS
Address space for local memory.
@ FLAT_ADDRESS
Address space for flat memory.
@ GLOBAL_ADDRESS
Address space for global memory (RAT0, VTX0).
GVUsesInfoTy getTransitiveUsesOfLDSForLowering(const CallGraph &CG, Module &M)
Collects all uses of LDS Global Variables in M using getUsesOfGVByFunction, with isLDSVariableToLower...
void getInterestingMemoryOperands(Module &M, Instruction *I, SmallVectorImpl< InterestingMemoryOperand > &Interesting)
Get all the memory operands from the instruction that needs to be instrumented.
bool isDynamicLDS(const GlobalVariable &GV)
unsigned getAMDHSACodeObjectVersion(const Module &M)
void removeFnAttrFromReachable(CallGraph &CG, Function *KernelRoot, ArrayRef< StringRef > FnAttrs)
Strip FnAttr attribute from any functions where we may have introduced its use.
bool eliminateGVConstantExprUsesFromAllInstructions(Module &M, function_ref< bool(const GlobalVariable &)> Filter)
Iterates over all GlobalVariables in M, and whenever Filter returns true, replace all constant users ...
LLVM_READNONE constexpr bool isKernel(CallingConv::ID CC)
MapVector< Function *, DenseSet< GlobalVariable * > > FunctionVariableMap
bool isLDSVariableToLower(const GlobalVariable &GV)
Align getAlign(const DataLayout &DL, const GlobalVariable *GV)
void instrumentAddress(Module &M, IRBuilder<> &IRB, Instruction *OrigIns, Instruction *InsertBefore, Value *Addr, Align Alignment, TypeSize TypeStoreSize, bool IsWrite, Value *SizeArgument, bool UseCalls, bool Recover, int AsanScale, int AsanOffset)
Instrument the memory operand Addr.
uint64_t getRedzoneSizeForGlobal(int AsanScale, uint64_t SizeInBytes)
Given SizeInBytes of the Value to be instrunmented, Returns the redzone size corresponding to it.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
ModulePass * createAMDGPUSwLowerLDSLegacyPass()
@ Offset
Definition DWP.cpp:577
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1781
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
constexpr from_range_t from_range
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Definition STLExtras.h:2224
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
Definition STLExtras.h:649
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
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:1762
char & AMDGPUSwLowerLDSLegacyPassID
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1652
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:149
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
LLVM_ABI void getAddressSanitizerParams(const LLVMContext &Ctx, const Triple &TargetTriple, int LongSize, bool IsKasan, uint64_t *ShadowBase, int *MappingScale, bool *OrShadowOffset)
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1963
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
Definition MIRParser.h:39
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
FunctionVariableMap DirectAccess
FunctionVariableMap IndirectAccess
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
constexpr uint64_t value() const
This is a hole in the type system and should not be abused.
Definition Alignment.h:82
Align valueOrOne() const
For convenience, returns a valid alignment or 1 if undefined.
Definition Alignment.h:135