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 are sorted and
64// assigned a kernel-id. All the LDS globals accessed by non-kernels
65// are sorted. This information is used to build two tables:
66// - Base table:
67// Base table will have single row, with elements of the row
68// placed as per kernel ID. Each element in the row corresponds
69// to ptr of "SW LDS" variable created for that kernel.
70// - Offset table:
71// Offset table will have multiple rows and columns.
72// Rows are assumed to be from 0 to (n-1). n is total number
73// of kernels accessing the LDS through non-kernels.
74// Each row will have m elements. m is the total number of
75// unique LDS globals accessed by all non-kernels.
76// Each element in the row correspond to the ptr of
77// the replacement of LDS global done by that particular kernel.
78// A LDS variable in non-kernel will be replaced based on the information
79// from base and offset tables. Based on kernel-id query, ptr of "SW
80// LDS" for that corresponding kernel is obtained from base table.
81// The Offset into the base "SW LDS" is obtained from
82// corresponding element in offset table. With this information, replacement
83// value is obtained.
84//===----------------------------------------------------------------------===//
85
86#include "AMDGPU.h"
88#include "AMDGPUMemoryUtils.h"
90#include "llvm/ADT/StringRef.h"
93#include "llvm/IR/Constants.h"
94#include "llvm/IR/DIBuilder.h"
95#include "llvm/IR/DebugInfo.h"
97#include "llvm/IR/IRBuilder.h"
99#include "llvm/IR/MDBuilder.h"
101#include "llvm/Pass.h"
105
106#include <algorithm>
107
108#define DEBUG_TYPE "amdgpu-sw-lower-lds"
109#define COV5_HIDDEN_DYN_LDS_SIZE_ARG 15
110
111using namespace llvm;
112using namespace AMDGPU;
113
114namespace {
115
117 AsanInstrumentLDS("amdgpu-asan-instrument-lds",
118 cl::desc("Run asan instrumentation on LDS instructions "
119 "lowered to global memory"),
120 cl::init(true), cl::Hidden);
121
122using DomTreeCallback = function_ref<DominatorTree *(Function &F)>;
123
124struct LDSAccessTypeInfo {
125 SetVector<GlobalVariable *> StaticLDSGlobals;
126 SetVector<GlobalVariable *> DynamicLDSGlobals;
127};
128
129// Struct to hold all the Metadata required for a kernel
130// to replace a LDS global uses with corresponding offset
131// in to device global memory.
132struct KernelLDSParameters {
133 GlobalVariable *SwLDS = nullptr;
134 GlobalVariable *SwDynLDS = nullptr;
135 GlobalVariable *SwLDSMetadata = nullptr;
136 LDSAccessTypeInfo DirectAccess;
137 LDSAccessTypeInfo IndirectAccess;
139 LDSToReplacementIndicesMap;
140 uint32_t MallocSize = 0;
141 uint32_t LDSSize = 0;
142 SmallVector<std::pair<uint32_t, uint32_t>, 64> RedzoneOffsetAndSizeVector;
143};
144
145// Struct to store information for creation of offset table
146// for all the non-kernel LDS accesses.
147struct NonKernelLDSParameters {
148 GlobalVariable *LDSBaseTable = nullptr;
149 GlobalVariable *LDSOffsetTable = nullptr;
150 SetVector<Function *> OrderedKernels;
151 SetVector<GlobalVariable *> OrdereLDSGlobals;
152};
153
154struct AsanInstrumentInfo {
155 int Scale = 0;
156 uint32_t Offset = 0;
157 SetVector<Instruction *> Instructions;
158};
159
160struct FunctionsAndLDSAccess {
161 DenseMap<Function *, KernelLDSParameters> KernelToLDSParametersMap;
162 SetVector<Function *> KernelsWithIndirectLDSAccess;
163 SetVector<Function *> NonKernelsWithLDSArgument;
164 SetVector<GlobalVariable *> AllNonKernelLDSAccess;
165 FunctionVariableMap NonKernelToLDSAccessMap;
166};
167
168class AMDGPUSwLowerLDS {
169public:
170 AMDGPUSwLowerLDS(Module &Mod, DomTreeCallback Callback)
171 : M(Mod), IRB(M.getContext()), DTCallback(Callback) {}
172 bool run();
173 void getUsesOfLDSByNonKernels();
174 void getNonKernelsWithLDSArguments(const CallGraph &CG);
176 getOrderedIndirectLDSAccessingKernels(SetVector<Function *> &Kernels);
178 getOrderedNonKernelAllLDSGlobals(SetVector<GlobalVariable *> &Variables);
179 void buildSwLDSGlobal(Function *Func);
180 void buildSwDynLDSGlobal(Function *Func);
181 void populateSwMetadataGlobal(Function *Func);
182 void populateSwLDSAttributeAndMetadata(Function *Func);
183 void populateLDSToReplacementIndicesMap(Function *Func);
184 void getLDSMemoryInstructions(Function *Func,
185 SetVector<Instruction *> &LDSInstructions);
186 void replaceKernelLDSAccesses(Function *Func);
187 Value *getTranslatedGlobalMemoryPtrOfLDS(Value *LoadMallocPtr, Value *LDSPtr);
188 void translateLDSMemoryOperationsToGlobalMemory(
189 Function *Func, Value *LoadMallocPtr,
190 SetVector<Instruction *> &LDSInstructions);
191 void poisonRedzones(Function *Func, Value *MallocPtr);
192 void lowerKernelLDSAccesses(Function *Func, DomTreeUpdater &DTU);
193 void buildNonKernelLDSOffsetTable(NonKernelLDSParameters &NKLDSParams);
194 void buildNonKernelLDSBaseTable(NonKernelLDSParameters &NKLDSParams);
195 Constant *
196 getAddressesOfVariablesInKernel(Function *Func,
197 SetVector<GlobalVariable *> &Variables);
198 void lowerNonKernelLDSAccesses(Function *Func,
199 SetVector<GlobalVariable *> &LDSGlobals,
200 NonKernelLDSParameters &NKLDSParams);
201 void
202 updateMallocSizeForDynamicLDS(Function *Func, Value **CurrMallocSize,
203 Value *HiddenDynLDSSize,
204 SetVector<GlobalVariable *> &DynamicLDSGlobals);
205 void initAsanInfo();
206
207private:
208 Module &M;
209 IRBuilder<> IRB;
210 DomTreeCallback DTCallback;
211 FunctionsAndLDSAccess FuncLDSAccessInfo;
212 AsanInstrumentInfo AsanInfo;
213};
214
215template <typename T> SetVector<T> sortByName(std::vector<T> &&V) {
216 // Sort the vector of globals or Functions based on their name.
217 // Returns a SetVector of globals/Functions.
218 sort(V, [](const auto *L, const auto *R) {
219 return L->getName() < R->getName();
220 });
221 return {SetVector<T>(llvm::from_range, V)};
222}
223
224SetVector<GlobalVariable *> AMDGPUSwLowerLDS::getOrderedNonKernelAllLDSGlobals(
225 SetVector<GlobalVariable *> &Variables) {
226 // Sort all the non-kernel LDS accesses based on their name.
227 return sortByName(
228 std::vector<GlobalVariable *>(Variables.begin(), Variables.end()));
229}
230
231SetVector<Function *> AMDGPUSwLowerLDS::getOrderedIndirectLDSAccessingKernels(
232 SetVector<Function *> &Kernels) {
233 // Sort the non-kernels accessing LDS based on their name.
234 // Also assign a kernel ID metadata based on the sorted order.
235 LLVMContext &Ctx = M.getContext();
236 if (Kernels.size() > UINT32_MAX) {
237 report_fatal_error("Unimplemented SW LDS lowering for > 2**32 kernels");
238 }
239 SetVector<Function *> OrderedKernels =
240 sortByName(std::vector<Function *>(Kernels.begin(), Kernels.end()));
241 for (size_t i = 0; i < Kernels.size(); i++) {
242 Metadata *AttrMDArgs[1] = {
244 };
245 Function *Func = OrderedKernels[i];
246 Func->setMetadata("llvm.amdgcn.lds.kernel.id",
247 MDNode::get(Ctx, AttrMDArgs));
248 }
249 return OrderedKernels;
250}
251
252void AMDGPUSwLowerLDS::getNonKernelsWithLDSArguments(const CallGraph &CG) {
253 // Among the kernels accessing LDS, get list of
254 // Non-kernels to which a call is made and a ptr
255 // to addrspace(3) is passed as argument.
256 for (auto &K : FuncLDSAccessInfo.KernelToLDSParametersMap) {
257 Function *Func = K.first;
258 const CallGraphNode *CGN = CG[Func];
259 if (!CGN)
260 continue;
261 for (auto &I : *CGN) {
262 CallGraphNode *CallerCGN = I.second;
263 Function *CalledFunc = CallerCGN->getFunction();
264 if (!CalledFunc || CalledFunc->isDeclaration())
265 continue;
266 if (AMDGPU::isKernel(*CalledFunc))
267 continue;
268 for (auto AI = CalledFunc->arg_begin(), E = CalledFunc->arg_end();
269 AI != E; ++AI) {
270 Type *ArgTy = (*AI).getType();
271 if (!ArgTy->isPointerTy())
272 continue;
274 continue;
275 FuncLDSAccessInfo.NonKernelsWithLDSArgument.insert(CalledFunc);
276 // Also add the Calling function to KernelsWithIndirectLDSAccess list
277 // so that base table of LDS is generated.
278 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess.insert(Func);
279 }
280 }
281 }
282}
283
284void AMDGPUSwLowerLDS::getUsesOfLDSByNonKernels() {
285 for (GlobalVariable *GV : FuncLDSAccessInfo.AllNonKernelLDSAccess) {
287 continue;
288
289 for (User *V : GV->users()) {
290 if (auto *I = dyn_cast<Instruction>(V)) {
291 Function *F = I->getFunction();
292 if (!isKernel(*F) && !F->isDeclaration())
293 FuncLDSAccessInfo.NonKernelToLDSAccessMap[F].insert(GV);
294 }
295 }
296 }
297}
298
299static void recordLDSAbsoluteAddress(Module &M, GlobalVariable *GV,
300 uint32_t Address) {
301 // Write the specified address into metadata where it can be retrieved by
302 // the assembler. Format is a half open range, [Address Address+1)
303 LLVMContext &Ctx = M.getContext();
304 auto *IntTy = M.getDataLayout().getIntPtrType(Ctx, AMDGPUAS::LOCAL_ADDRESS);
305 MDBuilder MDB(Ctx);
306 MDNode *MetadataNode = MDB.createRange(ConstantInt::get(IntTy, Address),
307 ConstantInt::get(IntTy, Address + 1));
308 GV->setMetadata(LLVMContext::MD_absolute_symbol, MetadataNode);
309}
310
311static void addLDSSizeAttribute(Function *Func, uint32_t Offset,
312 bool IsDynLDS) {
313 if (Offset != 0) {
314 std::string Buffer;
315 raw_string_ostream SS{Buffer};
316 SS << Offset;
317 if (IsDynLDS)
318 SS << "," << Offset;
319 Func->addFnAttr("amdgpu-lds-size", Buffer);
320 }
321}
322
323static void markUsedByKernel(Function *Func, GlobalVariable *SGV) {
324 BasicBlock *Entry = &Func->getEntryBlock();
325 IRBuilder<> Builder(Entry, Entry->getFirstNonPHIIt());
326
327 Function *Decl = Intrinsic::getOrInsertDeclaration(Func->getParent(),
328 Intrinsic::donothing, {});
329
330 Value *UseInstance[1] = {
331 Builder.CreateConstInBoundsGEP1_32(SGV->getValueType(), SGV, 0)};
332
333 Builder.CreateCall(Decl, {},
334 {OperandBundleDefT<Value *>("ExplicitUse", UseInstance)});
335}
336
337void AMDGPUSwLowerLDS::buildSwLDSGlobal(Function *Func) {
338 // Create new LDS global required for each kernel to store
339 // device global memory pointer.
340 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
341 // Create new global pointer variable
342 LDSParams.SwLDS = new GlobalVariable(
343 M, IRB.getPtrTy(), false, GlobalValue::InternalLinkage,
344 PoisonValue::get(IRB.getPtrTy()), "llvm.amdgcn.sw.lds." + Func->getName(),
347 MD.NoAddress = true;
348 LDSParams.SwLDS->setSanitizerMetadata(MD);
349}
350
351void AMDGPUSwLowerLDS::buildSwDynLDSGlobal(Function *Func) {
352 // Create new Dyn LDS global if kernel accesses dyn LDS.
353 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
354 if (LDSParams.DirectAccess.DynamicLDSGlobals.empty() &&
355 LDSParams.IndirectAccess.DynamicLDSGlobals.empty())
356 return;
357 // Create new global pointer variable
358 auto *emptyCharArray = ArrayType::get(IRB.getInt8Ty(), 0);
359 LDSParams.SwDynLDS = new GlobalVariable(
360 M, emptyCharArray, false, GlobalValue::ExternalLinkage, nullptr,
361 "llvm.amdgcn." + Func->getName() + ".dynlds", nullptr,
363 markUsedByKernel(Func, LDSParams.SwDynLDS);
365 MD.NoAddress = true;
366 LDSParams.SwDynLDS->setSanitizerMetadata(MD);
367}
368
369void AMDGPUSwLowerLDS::populateSwLDSAttributeAndMetadata(Function *Func) {
370 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
371 bool IsDynLDSUsed = LDSParams.SwDynLDS;
372 uint32_t Offset = LDSParams.LDSSize;
373 recordLDSAbsoluteAddress(M, LDSParams.SwLDS, 0);
374 addLDSSizeAttribute(Func, Offset, IsDynLDSUsed);
375 if (LDSParams.SwDynLDS)
376 recordLDSAbsoluteAddress(M, LDSParams.SwDynLDS, Offset);
377}
378
379void AMDGPUSwLowerLDS::populateSwMetadataGlobal(Function *Func) {
380 // Create new metadata global for every kernel and initialize the
381 // start offsets and sizes corresponding to each LDS accesses.
382 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
383 auto &Ctx = M.getContext();
384 auto &DL = M.getDataLayout();
385 std::vector<Type *> Items;
386 Type *Int32Ty = IRB.getInt32Ty();
387 std::vector<Constant *> Initializers;
388 Align MaxAlignment(1);
389 auto UpdateMaxAlignment = [&MaxAlignment, &DL](GlobalVariable *GV) {
390 Align GVAlign = AMDGPU::getAlign(DL, GV);
391 MaxAlignment = std::max(MaxAlignment, GVAlign);
392 };
393
394 for (GlobalVariable *GV : LDSParams.DirectAccess.StaticLDSGlobals)
395 UpdateMaxAlignment(GV);
396
397 for (GlobalVariable *GV : LDSParams.DirectAccess.DynamicLDSGlobals)
398 UpdateMaxAlignment(GV);
399
400 for (GlobalVariable *GV : LDSParams.IndirectAccess.StaticLDSGlobals)
401 UpdateMaxAlignment(GV);
402
403 for (GlobalVariable *GV : LDSParams.IndirectAccess.DynamicLDSGlobals)
404 UpdateMaxAlignment(GV);
405
406 //{StartOffset, AlignedSizeInBytes}
407 SmallString<128> MDItemStr;
408 raw_svector_ostream MDItemOS(MDItemStr);
409 MDItemOS << "llvm.amdgcn.sw.lds." << Func->getName() << ".md.item";
410
411 StructType *LDSItemTy =
412 StructType::create(Ctx, {Int32Ty, Int32Ty, Int32Ty}, MDItemOS.str());
413 uint32_t &MallocSize = LDSParams.MallocSize;
414 SetVector<GlobalVariable *> UniqueLDSGlobals;
415 int AsanScale = AsanInfo.Scale;
416 auto buildInitializerForSwLDSMD =
417 [&](SetVector<GlobalVariable *> &LDSGlobals) {
418 for (auto &GV : LDSGlobals) {
419 if (is_contained(UniqueLDSGlobals, GV))
420 continue;
421 UniqueLDSGlobals.insert(GV);
422
423 Type *Ty = GV->getValueType();
424 const uint64_t SizeInBytes = DL.getTypeAllocSize(Ty);
425 Items.push_back(LDSItemTy);
426 Constant *ItemStartOffset = ConstantInt::get(Int32Ty, MallocSize);
427 Constant *SizeInBytesConst = ConstantInt::get(Int32Ty, SizeInBytes);
428 // Get redzone size corresponding a size.
429 const uint64_t RightRedzoneSize =
430 AMDGPU::getRedzoneSizeForGlobal(AsanScale, SizeInBytes);
431 // Update MallocSize with current size and redzone size.
432 MallocSize += SizeInBytes;
433 if (!AMDGPU::isDynamicLDS(*GV))
434 LDSParams.RedzoneOffsetAndSizeVector.emplace_back(MallocSize,
435 RightRedzoneSize);
436 MallocSize += RightRedzoneSize;
437 // Align current size plus redzone.
438 uint64_t AlignedSize =
439 alignTo(SizeInBytes + RightRedzoneSize, MaxAlignment);
440 Constant *AlignedSizeInBytesConst =
441 ConstantInt::get(Int32Ty, AlignedSize);
442 // Align MallocSize
443 MallocSize = alignTo(MallocSize, MaxAlignment);
444 Constant *InitItem =
445 ConstantStruct::get(LDSItemTy, {ItemStartOffset, SizeInBytesConst,
446 AlignedSizeInBytesConst});
447 Initializers.push_back(InitItem);
448 }
449 };
450 SetVector<GlobalVariable *> SwLDSVector;
451 SwLDSVector.insert(LDSParams.SwLDS);
452 buildInitializerForSwLDSMD(SwLDSVector);
453 buildInitializerForSwLDSMD(LDSParams.DirectAccess.StaticLDSGlobals);
454 buildInitializerForSwLDSMD(LDSParams.IndirectAccess.StaticLDSGlobals);
455 buildInitializerForSwLDSMD(LDSParams.DirectAccess.DynamicLDSGlobals);
456 buildInitializerForSwLDSMD(LDSParams.IndirectAccess.DynamicLDSGlobals);
457
458 // Update the LDS size used by the kernel.
459 Type *Ty = LDSParams.SwLDS->getValueType();
460 const uint64_t SizeInBytes = DL.getTypeAllocSize(Ty);
461 uint64_t AlignedSize = alignTo(SizeInBytes, MaxAlignment);
462 LDSParams.LDSSize = AlignedSize;
463 SmallString<128> MDTypeStr;
464 raw_svector_ostream MDTypeOS(MDTypeStr);
465 MDTypeOS << "llvm.amdgcn.sw.lds." << Func->getName() << ".md.type";
466 StructType *MetadataStructType =
467 StructType::create(Ctx, Items, MDTypeOS.str());
468 SmallString<128> MDStr;
469 raw_svector_ostream MDOS(MDStr);
470 MDOS << "llvm.amdgcn.sw.lds." << Func->getName() << ".md";
471 LDSParams.SwLDSMetadata = new GlobalVariable(
472 M, MetadataStructType, false, GlobalValue::InternalLinkage,
473 PoisonValue::get(MetadataStructType), MDOS.str(), nullptr,
475 Constant *data = ConstantStruct::get(MetadataStructType, Initializers);
476 LDSParams.SwLDSMetadata->setInitializer(data);
477 assert(LDSParams.SwLDS);
478 // Set the alignment to MaxAlignment for SwLDS.
479 LDSParams.SwLDS->setAlignment(MaxAlignment);
480 if (LDSParams.SwDynLDS)
481 LDSParams.SwDynLDS->setAlignment(MaxAlignment);
483 MD.NoAddress = true;
484 LDSParams.SwLDSMetadata->setSanitizerMetadata(MD);
485}
486
487void AMDGPUSwLowerLDS::populateLDSToReplacementIndicesMap(Function *Func) {
488 // Fill the corresponding LDS replacement indices for each LDS access
489 // related to this kernel.
490 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
491 SetVector<GlobalVariable *> UniqueLDSGlobals;
492 auto PopulateIndices = [&](SetVector<GlobalVariable *> &LDSGlobals,
493 uint32_t &Idx) {
494 for (auto &GV : LDSGlobals) {
495 if (is_contained(UniqueLDSGlobals, GV))
496 continue;
497 UniqueLDSGlobals.insert(GV);
498 LDSParams.LDSToReplacementIndicesMap[GV] = {0, Idx, 0};
499 ++Idx;
500 }
501 };
502 uint32_t Idx = 0;
503 SetVector<GlobalVariable *> SwLDSVector;
504 SwLDSVector.insert(LDSParams.SwLDS);
505 PopulateIndices(SwLDSVector, Idx);
506 PopulateIndices(LDSParams.DirectAccess.StaticLDSGlobals, Idx);
507 PopulateIndices(LDSParams.IndirectAccess.StaticLDSGlobals, Idx);
508 PopulateIndices(LDSParams.DirectAccess.DynamicLDSGlobals, Idx);
509 PopulateIndices(LDSParams.IndirectAccess.DynamicLDSGlobals, Idx);
510}
511
512static void replacesUsesOfGlobalInFunction(Function *Func, GlobalVariable *GV,
513 Value *Replacement) {
514 // Replace all uses of LDS global in this Function with a Replacement.
515 auto ReplaceUsesLambda = [Func](const Use &U) -> bool {
516 auto *V = U.getUser();
517 if (auto *Inst = dyn_cast<Instruction>(V)) {
518 auto *Func1 = Inst->getFunction();
519 if (Func == Func1)
520 return true;
521 }
522 return false;
523 };
524 GV->replaceUsesWithIf(Replacement, ReplaceUsesLambda);
525}
526
527void AMDGPUSwLowerLDS::replaceKernelLDSAccesses(Function *Func) {
528 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
529 GlobalVariable *SwLDS = LDSParams.SwLDS;
530 assert(SwLDS);
531 GlobalVariable *SwLDSMetadata = LDSParams.SwLDSMetadata;
532 assert(SwLDSMetadata);
533 StructType *SwLDSMetadataStructType =
534 cast<StructType>(SwLDSMetadata->getValueType());
535 Type *Int32Ty = IRB.getInt32Ty();
536 auto &IndirectAccess = LDSParams.IndirectAccess;
537 auto &DirectAccess = LDSParams.DirectAccess;
538 // Replace all uses of LDS global in this Function with a Replacement.
539 SetVector<GlobalVariable *> UniqueLDSGlobals;
540 auto ReplaceLDSGlobalUses = [&](SetVector<GlobalVariable *> &LDSGlobals) {
541 for (auto &GV : LDSGlobals) {
542 // Do not generate instructions if LDS access is in non-kernel
543 // i.e indirect-access.
544 if ((IndirectAccess.StaticLDSGlobals.contains(GV) ||
545 IndirectAccess.DynamicLDSGlobals.contains(GV)) &&
546 (!DirectAccess.StaticLDSGlobals.contains(GV) &&
547 !DirectAccess.DynamicLDSGlobals.contains(GV)))
548 continue;
549 if (is_contained(UniqueLDSGlobals, GV))
550 continue;
551 UniqueLDSGlobals.insert(GV);
552 auto &Indices = LDSParams.LDSToReplacementIndicesMap[GV];
553 assert(Indices.size() == 3);
554 Constant *GEPIdx[] = {ConstantInt::get(Int32Ty, Indices[0]),
555 ConstantInt::get(Int32Ty, Indices[1]),
556 ConstantInt::get(Int32Ty, Indices[2])};
558 SwLDSMetadataStructType, SwLDSMetadata, GEPIdx, true);
559 Value *Offset = IRB.CreateLoad(Int32Ty, GEP);
560 Value *BasePlusOffset =
561 IRB.CreateInBoundsGEP(IRB.getInt8Ty(), SwLDS, {Offset});
562 LLVM_DEBUG(GV->printAsOperand(dbgs() << "Sw LDS Lowering, Replacing LDS ",
563 false));
564 replacesUsesOfGlobalInFunction(Func, GV, BasePlusOffset);
565 }
566 };
567 ReplaceLDSGlobalUses(DirectAccess.StaticLDSGlobals);
568 ReplaceLDSGlobalUses(IndirectAccess.StaticLDSGlobals);
569 ReplaceLDSGlobalUses(DirectAccess.DynamicLDSGlobals);
570 ReplaceLDSGlobalUses(IndirectAccess.DynamicLDSGlobals);
571}
572
573void AMDGPUSwLowerLDS::updateMallocSizeForDynamicLDS(
574 Function *Func, Value **CurrMallocSize, Value *HiddenDynLDSSize,
575 SetVector<GlobalVariable *> &DynamicLDSGlobals) {
576 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
577 Type *Int32Ty = IRB.getInt32Ty();
578
579 GlobalVariable *SwLDS = LDSParams.SwLDS;
580 GlobalVariable *SwLDSMetadata = LDSParams.SwLDSMetadata;
581 assert(SwLDS && SwLDSMetadata);
582 StructType *MetadataStructType =
583 cast<StructType>(SwLDSMetadata->getValueType());
584 unsigned MaxAlignment = SwLDS->getAlign().valueOrOne().value();
585 Value *MaxAlignValue = IRB.getInt32(MaxAlignment);
586 Value *MaxAlignValueMinusOne = IRB.getInt32(MaxAlignment - 1);
587
588 for (GlobalVariable *DynGV : DynamicLDSGlobals) {
589 auto &Indices = LDSParams.LDSToReplacementIndicesMap[DynGV];
590 // Update the Offset metadata.
591 Constant *Index0 = ConstantInt::get(Int32Ty, 0);
592 Constant *Index1 = ConstantInt::get(Int32Ty, Indices[1]);
593
594 Constant *Index2Offset = ConstantInt::get(Int32Ty, 0);
595 auto *GEPForOffset = IRB.CreateInBoundsGEP(
596 MetadataStructType, SwLDSMetadata, {Index0, Index1, Index2Offset});
597
598 IRB.CreateStore(*CurrMallocSize, GEPForOffset);
599 // Update the size and Aligned Size metadata.
600 Constant *Index2Size = ConstantInt::get(Int32Ty, 1);
601 auto *GEPForSize = IRB.CreateInBoundsGEP(MetadataStructType, SwLDSMetadata,
602 {Index0, Index1, Index2Size});
603
604 Value *CurrDynLDSSize = IRB.CreateLoad(Int32Ty, HiddenDynLDSSize);
605 IRB.CreateStore(CurrDynLDSSize, GEPForSize);
606 Constant *Index2AlignedSize = ConstantInt::get(Int32Ty, 2);
607 auto *GEPForAlignedSize = IRB.CreateInBoundsGEP(
608 MetadataStructType, SwLDSMetadata, {Index0, Index1, Index2AlignedSize});
609
610 Value *AlignedDynLDSSize =
611 IRB.CreateAdd(CurrDynLDSSize, MaxAlignValueMinusOne);
612 AlignedDynLDSSize = IRB.CreateUDiv(AlignedDynLDSSize, MaxAlignValue);
613 AlignedDynLDSSize = IRB.CreateMul(AlignedDynLDSSize, MaxAlignValue);
614 IRB.CreateStore(AlignedDynLDSSize, GEPForAlignedSize);
615
616 // Update the Current Malloc Size
617 *CurrMallocSize = IRB.CreateAdd(*CurrMallocSize, AlignedDynLDSSize);
618 }
619}
620
621static DebugLoc getOrCreateDebugLoc(const Instruction *InsertBefore,
622 DISubprogram *SP) {
623 assert(InsertBefore);
624 if (InsertBefore->getDebugLoc())
625 return InsertBefore->getDebugLoc();
626 if (SP)
627 return DILocation::get(SP->getContext(), SP->getLine(), 1, SP);
628 return DebugLoc();
629}
630
631void AMDGPUSwLowerLDS::getLDSMemoryInstructions(
632 Function *Func, SetVector<Instruction *> &LDSInstructions) {
633 for (BasicBlock &BB : *Func) {
634 for (Instruction &Inst : BB) {
635 if (LoadInst *LI = dyn_cast<LoadInst>(&Inst)) {
636 if (LI->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
637 LDSInstructions.insert(&Inst);
638 } else if (StoreInst *SI = dyn_cast<StoreInst>(&Inst)) {
639 if (SI->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
640 LDSInstructions.insert(&Inst);
641 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(&Inst)) {
642 if (RMW->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
643 LDSInstructions.insert(&Inst);
644 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(&Inst)) {
645 if (XCHG->getPointerAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
646 LDSInstructions.insert(&Inst);
647 } else if (AddrSpaceCastInst *ASC = dyn_cast<AddrSpaceCastInst>(&Inst)) {
648 if (ASC->getSrcAddressSpace() == AMDGPUAS::LOCAL_ADDRESS &&
649 ASC->getDestAddressSpace() == AMDGPUAS::FLAT_ADDRESS)
650 LDSInstructions.insert(&Inst);
651 } else if (AnyMemIntrinsic *MI = dyn_cast<AnyMemIntrinsic>(&Inst)) {
652 if (MI->getDestAddressSpace() == AMDGPUAS::LOCAL_ADDRESS) {
653 LDSInstructions.insert(&Inst);
654 } else if (auto *MTI = dyn_cast<AnyMemTransferInst>(MI)) {
655 if (MTI->getSourceAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
656 LDSInstructions.insert(&Inst);
657 }
658 } else
659 continue;
660 }
661 }
662}
663
664Value *AMDGPUSwLowerLDS::getTranslatedGlobalMemoryPtrOfLDS(Value *LoadMallocPtr,
665 Value *LDSPtr) {
666 assert(LDSPtr && "Invalid LDS pointer operand");
667 Type *LDSPtrType = LDSPtr->getType();
668 LLVMContext &Ctx = M.getContext();
669 const DataLayout &DL = M.getDataLayout();
670 Type *IntTy = DL.getIntPtrType(Ctx, AMDGPUAS::LOCAL_ADDRESS);
671 if (auto *VecPtrTy = dyn_cast<VectorType>(LDSPtrType)) {
672 // Handle vector of pointers
673 ElementCount NumElements = VecPtrTy->getElementCount();
674 IntTy = VectorType::get(IntTy, NumElements);
675 }
676 Value *GepIndex = IRB.CreatePtrToInt(LDSPtr, IntTy);
677 return IRB.CreateInBoundsGEP(IRB.getInt8Ty(), LoadMallocPtr, {GepIndex});
678}
679
680void AMDGPUSwLowerLDS::translateLDSMemoryOperationsToGlobalMemory(
681 Function *Func, Value *LoadMallocPtr,
682 SetVector<Instruction *> &LDSInstructions) {
683 LLVM_DEBUG(dbgs() << "Translating LDS memory operations to global memory : "
684 << Func->getName());
685 for (Instruction *Inst : LDSInstructions) {
686 IRB.SetInsertPoint(Inst);
687 if (LoadInst *LI = dyn_cast<LoadInst>(Inst)) {
688 Value *LIOperand = LI->getPointerOperand();
689 Value *Replacement =
690 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, LIOperand);
691 LoadInst *NewLI =
692 IRB.CreateLoad(LI->getType(), Replacement, LI->getProperties());
693 AsanInfo.Instructions.insert(NewLI);
694 LI->replaceAllUsesWith(NewLI);
695 LI->eraseFromParent();
696 } else if (StoreInst *SI = dyn_cast<StoreInst>(Inst)) {
697 Value *SIOperand = SI->getPointerOperand();
698 Value *Replacement =
699 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, SIOperand);
700 StoreInst *NewSI = IRB.CreateStore(SI->getValueOperand(), Replacement,
701 SI->getProperties());
702 AsanInfo.Instructions.insert(NewSI);
703 SI->replaceAllUsesWith(NewSI);
704 SI->eraseFromParent();
705 } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(Inst)) {
706 Value *RMWPtrOperand = RMW->getPointerOperand();
707 Value *RMWValOperand = RMW->getValOperand();
708 Value *Replacement =
709 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, RMWPtrOperand);
710 AtomicRMWInst *NewRMW = IRB.CreateAtomicRMW(
711 RMW->getOperation(), Replacement, RMWValOperand, RMW->getAlign(),
712 RMW->getOrdering(), RMW->getSyncScopeID());
713 NewRMW->setVolatile(RMW->isVolatile());
714 AsanInfo.Instructions.insert(NewRMW);
715 RMW->replaceAllUsesWith(NewRMW);
716 RMW->eraseFromParent();
717 } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(Inst)) {
718 Value *XCHGPtrOperand = XCHG->getPointerOperand();
719 Value *Replacement =
720 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, XCHGPtrOperand);
722 Replacement, XCHG->getCompareOperand(), XCHG->getNewValOperand(),
723 XCHG->getAlign(), XCHG->getSuccessOrdering(),
724 XCHG->getFailureOrdering(), XCHG->getSyncScopeID());
725 NewXCHG->setVolatile(XCHG->isVolatile());
726 AsanInfo.Instructions.insert(NewXCHG);
727 XCHG->replaceAllUsesWith(NewXCHG);
728 XCHG->eraseFromParent();
729 } else if (AnyMemIntrinsic *MI = dyn_cast<AnyMemIntrinsic>(Inst)) {
730 Value *NewDest = MI->getRawDest();
731 if (MI->getDestAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
732 NewDest = getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, NewDest);
733 CallInst *NewMI = nullptr;
735 if (MI->isAtomic()) {
737 NewDest, MSI->getValue(), MSI->getLength(),
738 MSI->getDestAlign().valueOrOne(), MSI->getElementSizeInBytes());
739 } else {
740 NewMI = IRB.CreateMemSet(NewDest, MSI->getValue(), MSI->getLength(),
741 MSI->getDestAlign(),
742 cast<MemSetInst>(MI)->isVolatile());
743 }
745 Value *NewSrc = MTI->getRawSource();
746 if (MTI->getSourceAddressSpace() == AMDGPUAS::LOCAL_ADDRESS)
747 NewSrc = getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, NewSrc);
748 if (MI->isAtomic()) {
749 if (MI->getIntrinsicID() ==
750 Intrinsic::memmove_element_unordered_atomic) {
752 NewDest, MTI->getDestAlign().valueOrOne(), NewSrc,
753 MTI->getSourceAlign().valueOrOne(), MTI->getLength(),
754 MTI->getElementSizeInBytes());
755 } else {
757 NewDest, MTI->getDestAlign().valueOrOne(), NewSrc,
758 MTI->getSourceAlign().valueOrOne(), MTI->getLength(),
759 MTI->getElementSizeInBytes());
760 }
761 } else {
762 NewMI = IRB.CreateMemTransferInst(
763 MI->getIntrinsicID(), NewDest, MTI->getDestAlign(), NewSrc,
764 MTI->getSourceAlign(), MTI->getLength(),
765 cast<MemTransferInst>(MI)->isVolatile());
766 }
767 } else
768 reportFatalUsageError("Unimplemented LDS lowering memory intrinsic");
769 AsanInfo.Instructions.insert(NewMI);
770 MI->replaceAllUsesWith(NewMI);
771 MI->eraseFromParent();
772 } else if (AddrSpaceCastInst *ASC = dyn_cast<AddrSpaceCastInst>(Inst)) {
773 Value *AIOperand = ASC->getPointerOperand();
774 Value *Replacement =
775 getTranslatedGlobalMemoryPtrOfLDS(LoadMallocPtr, AIOperand);
776 Value *NewAI = IRB.CreateAddrSpaceCast(Replacement, ASC->getType());
777 // Note: No need to add the instruction to AsanInfo instructions to be
778 // instrumented list. FLAT_ADDRESS ptr would have been already
779 // instrumented by asan pass prior to this pass.
780 ASC->replaceAllUsesWith(NewAI);
781 ASC->eraseFromParent();
782 } else
783 report_fatal_error("Unimplemented LDS lowering instruction");
784 }
785}
786
787void AMDGPUSwLowerLDS::poisonRedzones(Function *Func, Value *MallocPtr) {
788 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
789 Type *Int64Ty = IRB.getInt64Ty();
790 Type *VoidTy = IRB.getVoidTy();
791 FunctionCallee AsanPoisonRegion = M.getOrInsertFunction(
792 "__asan_poison_region",
793 FunctionType::get(VoidTy, {Int64Ty, Int64Ty}, false));
794
795 auto RedzonesVec = LDSParams.RedzoneOffsetAndSizeVector;
796 size_t VecSize = RedzonesVec.size();
797 for (unsigned i = 0; i < VecSize; i++) {
798 auto &RedzonePair = RedzonesVec[i];
799 uint64_t RedzoneOffset = RedzonePair.first;
800 uint64_t RedzoneSize = RedzonePair.second;
801 Value *RedzoneAddrOffset = IRB.CreateInBoundsGEP(
802 IRB.getInt8Ty(), MallocPtr, {IRB.getInt64(RedzoneOffset)});
803 Value *RedzoneAddress = IRB.CreatePtrToInt(RedzoneAddrOffset, Int64Ty);
804 IRB.CreateCall(AsanPoisonRegion,
805 {RedzoneAddress, IRB.getInt64(RedzoneSize)});
806 }
807}
808
809void AMDGPUSwLowerLDS::lowerKernelLDSAccesses(Function *Func,
810 DomTreeUpdater &DTU) {
811 LLVM_DEBUG(dbgs() << "Sw Lowering Kernel LDS for : " << Func->getName());
812 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
813 auto &Ctx = M.getContext();
814 auto *PrevEntryBlock = &Func->getEntryBlock();
815 SetVector<Instruction *> LDSInstructions;
816 getLDSMemoryInstructions(Func, LDSInstructions);
817 const DataLayout &DL = M.getDataLayout();
818
819 // Create malloc block.
820 auto *MallocBlock = BasicBlock::Create(Ctx, "Malloc", Func, PrevEntryBlock);
821
822 // Create WIdBlock block which has instructions related to selection of
823 // {0,0,0} indiex work item in the work group.
824 auto *WIdBlock = BasicBlock::Create(Ctx, "WId", Func, MallocBlock);
825
826 // Move constant-size allocas from the original entry block to the new entry
827 // block (WIdBlock) so they remain static allocas. Splice the leading cluster
828 // in bulk, then move any stragglers that are interleaved with other
829 // instructions.
830 auto SplitIt = PrevEntryBlock->getFirstNonPHIOrDbgOrAlloca();
831 WIdBlock->splice(WIdBlock->end(), PrevEntryBlock, PrevEntryBlock->begin(),
832 SplitIt);
833 for (Instruction &I : make_early_inc_range(*PrevEntryBlock))
834 if (auto *AI = dyn_cast<AllocaInst>(&I))
835 if (isa<ConstantInt>(AI->getArraySize()))
836 AI->moveBefore(*WIdBlock, WIdBlock->end());
837
838 IRB.SetInsertPoint(WIdBlock, WIdBlock->end());
839 DebugLoc FirstDL =
840 getOrCreateDebugLoc(&*PrevEntryBlock->begin(), Func->getSubprogram());
841 IRB.SetCurrentDebugLocation(FirstDL);
842 Value *WIdx = IRB.CreateIntrinsic(Intrinsic::amdgcn_workitem_id_x, {});
843 Value *WIdy = IRB.CreateIntrinsic(Intrinsic::amdgcn_workitem_id_y, {});
844 Value *WIdz = IRB.CreateIntrinsic(Intrinsic::amdgcn_workitem_id_z, {});
845 Value *XYOr = IRB.CreateOr(WIdx, WIdy);
846 Value *XYZOr = IRB.CreateOr(XYOr, WIdz);
847 Value *WIdzCond = IRB.CreateICmpEQ(XYZOr, IRB.getInt32(0));
848
849 // All work items will branch to PrevEntryBlock except {0,0,0} index
850 // work item which will branch to malloc block.
851 IRB.CreateCondBr(WIdzCond, MallocBlock, PrevEntryBlock);
852
853 // Malloc block
854 IRB.SetInsertPoint(MallocBlock, MallocBlock->begin());
855
856 // If Dynamic LDS globals are accessed by the kernel,
857 // Get the size of dyn lds from hidden dyn_lds_size kernel arg.
858 // Update the corresponding metadata global entries for this dyn lds global.
859 GlobalVariable *SwLDS = LDSParams.SwLDS;
860 GlobalVariable *SwLDSMetadata = LDSParams.SwLDSMetadata;
861 assert(SwLDS && SwLDSMetadata);
862 StructType *MetadataStructType =
863 cast<StructType>(SwLDSMetadata->getValueType());
864 uint32_t MallocSize = 0;
865 Value *CurrMallocSize;
866 Type *Int32Ty = IRB.getInt32Ty();
867 Type *Int64Ty = IRB.getInt64Ty();
868
869 SetVector<GlobalVariable *> UniqueLDSGlobals;
870 auto GetUniqueLDSGlobals = [&](SetVector<GlobalVariable *> &LDSGlobals) {
871 for (auto &GV : LDSGlobals) {
872 if (is_contained(UniqueLDSGlobals, GV))
873 continue;
874 UniqueLDSGlobals.insert(GV);
875 }
876 };
877
878 GetUniqueLDSGlobals(LDSParams.DirectAccess.StaticLDSGlobals);
879 GetUniqueLDSGlobals(LDSParams.IndirectAccess.StaticLDSGlobals);
880 unsigned NumStaticLDS = 1 + UniqueLDSGlobals.size();
881 UniqueLDSGlobals.clear();
882
883 if (NumStaticLDS) {
884 auto *GEPForEndStaticLDSOffset =
885 IRB.CreateInBoundsGEP(MetadataStructType, SwLDSMetadata,
886 {ConstantInt::get(Int32Ty, 0),
887 ConstantInt::get(Int32Ty, NumStaticLDS - 1),
888 ConstantInt::get(Int32Ty, 0)});
889
890 auto *GEPForEndStaticLDSSize =
891 IRB.CreateInBoundsGEP(MetadataStructType, SwLDSMetadata,
892 {ConstantInt::get(Int32Ty, 0),
893 ConstantInt::get(Int32Ty, NumStaticLDS - 1),
894 ConstantInt::get(Int32Ty, 2)});
895
896 Value *EndStaticLDSOffset =
897 IRB.CreateLoad(Int32Ty, GEPForEndStaticLDSOffset);
898 Value *EndStaticLDSSize = IRB.CreateLoad(Int32Ty, GEPForEndStaticLDSSize);
899 CurrMallocSize = IRB.CreateAdd(EndStaticLDSOffset, EndStaticLDSSize);
900 } else
901 CurrMallocSize = IRB.getInt32(MallocSize);
902
903 if (LDSParams.SwDynLDS) {
906 "Dynamic LDS size query is only supported for CO V5 and later.");
907 // Get size from hidden dyn_lds_size argument of kernel
909 IRB.CreateIntrinsic(Intrinsic::amdgcn_implicitarg_ptr, {});
910 Value *HiddenDynLDSSize = IRB.CreateInBoundsGEP(
911 ImplicitArg->getType(), ImplicitArg,
912 {ConstantInt::get(Int64Ty, COV5_HIDDEN_DYN_LDS_SIZE_ARG)});
913 UniqueLDSGlobals.clear();
914 GetUniqueLDSGlobals(LDSParams.DirectAccess.DynamicLDSGlobals);
915 GetUniqueLDSGlobals(LDSParams.IndirectAccess.DynamicLDSGlobals);
916 updateMallocSizeForDynamicLDS(Func, &CurrMallocSize, HiddenDynLDSSize,
917 UniqueLDSGlobals);
918 }
919
920 CurrMallocSize = IRB.CreateZExt(CurrMallocSize, Int64Ty);
921
922 // Create a call to malloc function which does device global memory allocation
923 // with size equals to all LDS global accesses size in this kernel.
924 Value *ReturnAddress = IRB.CreateIntrinsic(
925 Intrinsic::returnaddress, IRB.getPtrTy(DL.getProgramAddressSpace()),
926 {IRB.getInt32(0)});
927 FunctionCallee MallocFunc = M.getOrInsertFunction(
928 StringRef("__asan_malloc_impl"),
929 FunctionType::get(Int64Ty, {Int64Ty, Int64Ty}, false));
930 Value *RAPtrToInt = IRB.CreatePtrToInt(ReturnAddress, Int64Ty);
931 Value *MallocCall = IRB.CreateCall(MallocFunc, {CurrMallocSize, RAPtrToInt});
932
933 Value *MallocPtr =
935
936 // Create store of malloc to new global
937 IRB.CreateStore(MallocPtr, SwLDS);
938
939 // Create calls to __asan_poison_region to poison redzones.
940 poisonRedzones(Func, MallocPtr);
941
942 // Create branch to PrevEntryBlock
943 IRB.CreateBr(PrevEntryBlock);
944
945 // Create wave-group barrier at the starting of Previous entry block
946 Type *Int1Ty = IRB.getInt1Ty();
947 IRB.SetInsertPoint(PrevEntryBlock, PrevEntryBlock->begin());
948 auto *XYZCondPhi = IRB.CreatePHI(Int1Ty, 2, "xyzCond");
949 XYZCondPhi->addIncoming(IRB.getInt1(0), WIdBlock);
950 XYZCondPhi->addIncoming(IRB.getInt1(1), MallocBlock);
951
952 IRB.CreateIntrinsic(Intrinsic::amdgcn_s_barrier, {});
953
954 // Load malloc pointer from Sw LDS.
955 Value *LoadMallocPtr =
957
958 // Replace All uses of LDS globals with new LDS pointers.
959 replaceKernelLDSAccesses(Func);
960
961 // Replace Memory Operations on LDS with corresponding
962 // global memory pointers.
963 translateLDSMemoryOperationsToGlobalMemory(Func, LoadMallocPtr,
964 LDSInstructions);
965
966 auto *CondFreeBlock = BasicBlock::Create(Ctx, "CondFree", Func);
967 auto *FreeBlock = BasicBlock::Create(Ctx, "Free", Func);
968 auto *EndBlock = BasicBlock::Create(Ctx, "End", Func);
969 for (BasicBlock &BB : *Func) {
970 if (!BB.empty()) {
971 if (ReturnInst *RI = dyn_cast<ReturnInst>(&BB.back())) {
972 RI->eraseFromParent();
973 IRB.SetInsertPoint(&BB, BB.end());
974 IRB.CreateBr(CondFreeBlock);
975 }
976 }
977 }
978
979 // Cond Free Block
980 IRB.SetInsertPoint(CondFreeBlock, CondFreeBlock->begin());
981 IRB.CreateIntrinsic(Intrinsic::amdgcn_s_barrier, {});
982 IRB.CreateCondBr(XYZCondPhi, FreeBlock, EndBlock);
983
984 // Free Block
985 IRB.SetInsertPoint(FreeBlock, FreeBlock->begin());
986
987 // Free the previously allocate device global memory.
988 FunctionCallee AsanFreeFunc = M.getOrInsertFunction(
989 StringRef("__asan_free_impl"),
990 FunctionType::get(IRB.getVoidTy(), {Int64Ty, Int64Ty}, false));
991 Value *ReturnAddr = IRB.CreateIntrinsic(
992 Intrinsic::returnaddress, IRB.getPtrTy(DL.getProgramAddressSpace()),
993 IRB.getInt32(0));
994 Value *RAPToInt = IRB.CreatePtrToInt(ReturnAddr, Int64Ty);
995 Value *MallocPtrToInt = IRB.CreatePtrToInt(LoadMallocPtr, Int64Ty);
996 IRB.CreateCall(AsanFreeFunc, {MallocPtrToInt, RAPToInt});
997
998 IRB.CreateBr(EndBlock);
999
1000 // End Block
1001 IRB.SetInsertPoint(EndBlock, EndBlock->begin());
1002 IRB.CreateRetVoid();
1003 // Update the DomTree with corresponding links to basic blocks.
1004 DTU.applyUpdates({{DominatorTree::Insert, WIdBlock, MallocBlock},
1005 {DominatorTree::Insert, MallocBlock, PrevEntryBlock},
1006 {DominatorTree::Insert, CondFreeBlock, FreeBlock},
1007 {DominatorTree::Insert, FreeBlock, EndBlock}});
1008}
1009
1010Constant *AMDGPUSwLowerLDS::getAddressesOfVariablesInKernel(
1011 Function *Func, SetVector<GlobalVariable *> &Variables) {
1012 Type *Int32Ty = IRB.getInt32Ty();
1013 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
1014
1015 GlobalVariable *SwLDSMetadata = LDSParams.SwLDSMetadata;
1016 assert(SwLDSMetadata);
1017 auto *SwLDSMetadataStructType =
1018 cast<StructType>(SwLDSMetadata->getValueType());
1019 ArrayType *KernelOffsetsType =
1021
1022 SmallVector<Constant *> Elements;
1023 for (auto *GV : Variables) {
1024 auto It = LDSParams.LDSToReplacementIndicesMap.find(GV);
1025 if (It == LDSParams.LDSToReplacementIndicesMap.end()) {
1026 Elements.push_back(
1028 continue;
1029 }
1030 auto &Indices = It->second;
1031 Constant *GEPIdx[] = {ConstantInt::get(Int32Ty, Indices[0]),
1032 ConstantInt::get(Int32Ty, Indices[1]),
1033 ConstantInt::get(Int32Ty, Indices[2])};
1034 Constant *GEP = ConstantExpr::getGetElementPtr(SwLDSMetadataStructType,
1035 SwLDSMetadata, GEPIdx, true);
1036 Elements.push_back(GEP);
1037 }
1038 return ConstantArray::get(KernelOffsetsType, Elements);
1039}
1040
1041void AMDGPUSwLowerLDS::buildNonKernelLDSBaseTable(
1042 NonKernelLDSParameters &NKLDSParams) {
1043 // Base table will have single row, with elements of the row
1044 // placed as per kernel ID. Each element in the row corresponds
1045 // to addresss of "SW LDS" global of the kernel.
1046 auto &Kernels = NKLDSParams.OrderedKernels;
1047 if (Kernels.empty())
1048 return;
1049 const size_t NumberKernels = Kernels.size();
1050 ArrayType *AllKernelsOffsetsType =
1051 ArrayType::get(IRB.getPtrTy(AMDGPUAS::LOCAL_ADDRESS), NumberKernels);
1052 std::vector<Constant *> OverallConstantExprElts(NumberKernels);
1053 for (size_t i = 0; i < NumberKernels; i++) {
1054 Function *Func = Kernels[i];
1055 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
1056 OverallConstantExprElts[i] = LDSParams.SwLDS;
1057 }
1058 Constant *init =
1059 ConstantArray::get(AllKernelsOffsetsType, OverallConstantExprElts);
1060 NKLDSParams.LDSBaseTable = new GlobalVariable(
1061 M, AllKernelsOffsetsType, true, GlobalValue::InternalLinkage, init,
1062 "llvm.amdgcn.sw.lds.base.table", nullptr, GlobalValue::NotThreadLocal,
1065 MD.NoAddress = true;
1066 NKLDSParams.LDSBaseTable->setSanitizerMetadata(MD);
1067}
1068
1069void AMDGPUSwLowerLDS::buildNonKernelLDSOffsetTable(
1070 NonKernelLDSParameters &NKLDSParams) {
1071 // Offset table will have multiple rows and columns.
1072 // Rows are assumed to be from 0 to (n-1). n is total number
1073 // of kernels accessing the LDS through non-kernels.
1074 // Each row will have m elements. m is the total number of
1075 // unique LDS globals accessed by non-kernels.
1076 // Each element in the row correspond to the address of
1077 // the replacement of LDS global done by that particular kernel.
1078 auto &Variables = NKLDSParams.OrdereLDSGlobals;
1079 auto &Kernels = NKLDSParams.OrderedKernels;
1080 if (Variables.empty() || Kernels.empty())
1081 return;
1082 const size_t NumberVariables = Variables.size();
1083 const size_t NumberKernels = Kernels.size();
1084
1085 ArrayType *KernelOffsetsType =
1086 ArrayType::get(IRB.getPtrTy(AMDGPUAS::GLOBAL_ADDRESS), NumberVariables);
1087
1088 ArrayType *AllKernelsOffsetsType =
1089 ArrayType::get(KernelOffsetsType, NumberKernels);
1090 std::vector<Constant *> overallConstantExprElts(NumberKernels);
1091 for (size_t i = 0; i < NumberKernels; i++) {
1092 Function *Func = Kernels[i];
1093 overallConstantExprElts[i] =
1094 getAddressesOfVariablesInKernel(Func, Variables);
1095 }
1096 Constant *Init =
1097 ConstantArray::get(AllKernelsOffsetsType, overallConstantExprElts);
1098 NKLDSParams.LDSOffsetTable = new GlobalVariable(
1099 M, AllKernelsOffsetsType, true, GlobalValue::InternalLinkage, Init,
1100 "llvm.amdgcn.sw.lds.offset.table", nullptr, GlobalValue::NotThreadLocal,
1103 MD.NoAddress = true;
1104 NKLDSParams.LDSOffsetTable->setSanitizerMetadata(MD);
1105}
1106
1107void AMDGPUSwLowerLDS::lowerNonKernelLDSAccesses(
1108 Function *Func, SetVector<GlobalVariable *> &LDSGlobals,
1109 NonKernelLDSParameters &NKLDSParams) {
1110 // Replace LDS access in non-kernel with replacement queried from
1111 // Base table and offset from offset table.
1112 LLVM_DEBUG(dbgs() << "Sw LDS lowering, lower non-kernel access for : "
1113 << Func->getName());
1114 auto InsertAt = Func->getEntryBlock().getFirstNonPHIOrDbgOrAlloca();
1115 IRB.SetInsertPoint(InsertAt);
1116
1117 // Get LDS memory instructions.
1118 SetVector<Instruction *> LDSInstructions;
1119 getLDSMemoryInstructions(Func, LDSInstructions);
1120
1121 auto *KernelId = IRB.CreateIntrinsic(Intrinsic::amdgcn_lds_kernel_id, {});
1122 GlobalVariable *LDSBaseTable = NKLDSParams.LDSBaseTable;
1123 GlobalVariable *LDSOffsetTable = NKLDSParams.LDSOffsetTable;
1124 auto &OrdereLDSGlobals = NKLDSParams.OrdereLDSGlobals;
1125 Value *BaseGEP = IRB.CreateInBoundsGEP(
1126 LDSBaseTable->getValueType(), LDSBaseTable, {IRB.getInt32(0), KernelId});
1127 Value *BaseLoad =
1128 IRB.CreateLoad(IRB.getPtrTy(AMDGPUAS::LOCAL_ADDRESS), BaseGEP);
1129 Value *LoadMallocPtr =
1130 IRB.CreateLoad(IRB.getPtrTy(AMDGPUAS::GLOBAL_ADDRESS), BaseLoad);
1131
1132 for (GlobalVariable *GV : LDSGlobals) {
1133 const auto *GVIt = llvm::find(OrdereLDSGlobals, GV);
1134 assert(GVIt != OrdereLDSGlobals.end());
1135 uint32_t GVOffset = std::distance(OrdereLDSGlobals.begin(), GVIt);
1136
1137 Value *OffsetGEP = IRB.CreateInBoundsGEP(
1138 LDSOffsetTable->getValueType(), LDSOffsetTable,
1139 {IRB.getInt32(0), KernelId, IRB.getInt32(GVOffset)});
1140 Value *OffsetLoad =
1141 IRB.CreateLoad(IRB.getPtrTy(AMDGPUAS::GLOBAL_ADDRESS), OffsetGEP);
1142 Value *Offset = IRB.CreateLoad(IRB.getInt32Ty(), OffsetLoad);
1143 Value *BasePlusOffset =
1144 IRB.CreateInBoundsGEP(IRB.getInt8Ty(), BaseLoad, {Offset});
1145 LLVM_DEBUG(dbgs() << "Sw LDS Lowering, Replace non-kernel LDS for "
1146 << GV->getName());
1147 replacesUsesOfGlobalInFunction(Func, GV, BasePlusOffset);
1148 }
1149 translateLDSMemoryOperationsToGlobalMemory(Func, LoadMallocPtr,
1150 LDSInstructions);
1151}
1152
1153static void reorderStaticDynamicIndirectLDSSet(KernelLDSParameters &LDSParams) {
1154 // Sort Static, dynamic LDS globals which are either
1155 // direct or indirect access on basis of name.
1156 auto &DirectAccess = LDSParams.DirectAccess;
1157 auto &IndirectAccess = LDSParams.IndirectAccess;
1158 LDSParams.DirectAccess.StaticLDSGlobals = sortByName(
1159 std::vector<GlobalVariable *>(DirectAccess.StaticLDSGlobals.begin(),
1160 DirectAccess.StaticLDSGlobals.end()));
1161 LDSParams.DirectAccess.DynamicLDSGlobals = sortByName(
1162 std::vector<GlobalVariable *>(DirectAccess.DynamicLDSGlobals.begin(),
1163 DirectAccess.DynamicLDSGlobals.end()));
1164 LDSParams.IndirectAccess.StaticLDSGlobals = sortByName(
1165 std::vector<GlobalVariable *>(IndirectAccess.StaticLDSGlobals.begin(),
1166 IndirectAccess.StaticLDSGlobals.end()));
1167 LDSParams.IndirectAccess.DynamicLDSGlobals = sortByName(
1168 std::vector<GlobalVariable *>(IndirectAccess.DynamicLDSGlobals.begin(),
1169 IndirectAccess.DynamicLDSGlobals.end()));
1170}
1171
1172void AMDGPUSwLowerLDS::initAsanInfo() {
1173 // Get Shadow mapping scale and offset.
1174 unsigned LongSize =
1175 M.getDataLayout().getPointerSizeInBits(AMDGPUAS::GLOBAL_ADDRESS);
1177 int Scale;
1178 bool OrShadowOffset;
1179 llvm::getAddressSanitizerParams(M.getTargetTriple(), LongSize, false, &Offset,
1180 &Scale, &OrShadowOffset);
1181 AsanInfo.Scale = Scale;
1182 AsanInfo.Offset = Offset;
1183}
1184
1185static bool hasFnWithSanitizeAddressAttr(FunctionVariableMap &LDSAccesses) {
1186 for (auto &K : LDSAccesses) {
1187 Function *F = K.first;
1188 if (!F)
1189 continue;
1190 if (F->hasFnAttribute(Attribute::SanitizeAddress))
1191 return true;
1192 }
1193 return false;
1194}
1195
1196bool AMDGPUSwLowerLDS::run() {
1197 bool Changed = false;
1198
1199 CallGraph CG = CallGraph(M);
1200
1201 Changed |=
1203
1204 // Get all the direct and indirect access of LDS for all the kernels.
1206
1207 // Flag to decide whether to lower all the LDS accesses
1208 // based on sanitize_address attribute.
1209 bool LowerAllLDS = hasFnWithSanitizeAddressAttr(LDSUsesInfo.DirectAccess) ||
1210 hasFnWithSanitizeAddressAttr(LDSUsesInfo.IndirectAccess);
1211
1212 if (!LowerAllLDS)
1213 return Changed;
1214
1215 // Utility to group LDS access into direct, indirect, static and dynamic.
1216 auto PopulateKernelStaticDynamicLDS = [&](FunctionVariableMap &LDSAccesses,
1217 bool DirectAccess) {
1218 for (auto &K : LDSAccesses) {
1219 Function *F = K.first;
1220 if (!F || K.second.empty())
1221 continue;
1222
1223 assert(isKernel(*F));
1224
1225 // Only inserts if key isn't already in the map.
1226 FuncLDSAccessInfo.KernelToLDSParametersMap.insert(
1227 {F, KernelLDSParameters()});
1228
1229 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[F];
1230 if (!DirectAccess)
1231 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess.insert(F);
1232 for (GlobalVariable *GV : K.second) {
1233 if (!DirectAccess) {
1234 if (AMDGPU::isDynamicLDS(*GV))
1235 LDSParams.IndirectAccess.DynamicLDSGlobals.insert(GV);
1236 else
1237 LDSParams.IndirectAccess.StaticLDSGlobals.insert(GV);
1238 FuncLDSAccessInfo.AllNonKernelLDSAccess.insert(GV);
1239 } else {
1240 if (AMDGPU::isDynamicLDS(*GV))
1241 LDSParams.DirectAccess.DynamicLDSGlobals.insert(GV);
1242 else
1243 LDSParams.DirectAccess.StaticLDSGlobals.insert(GV);
1244 }
1245 }
1246 }
1247 };
1248
1249 PopulateKernelStaticDynamicLDS(LDSUsesInfo.DirectAccess, true);
1250 PopulateKernelStaticDynamicLDS(LDSUsesInfo.IndirectAccess, false);
1251
1252 // Get address sanitizer scale.
1253 initAsanInfo();
1254
1255 for (auto &K : FuncLDSAccessInfo.KernelToLDSParametersMap) {
1256 Function *Func = K.first;
1257 auto &LDSParams = FuncLDSAccessInfo.KernelToLDSParametersMap[Func];
1258 if (LDSParams.DirectAccess.StaticLDSGlobals.empty() &&
1259 LDSParams.DirectAccess.DynamicLDSGlobals.empty() &&
1260 LDSParams.IndirectAccess.StaticLDSGlobals.empty() &&
1261 LDSParams.IndirectAccess.DynamicLDSGlobals.empty()) {
1262 Changed = false;
1263 } else {
1265 CG, Func,
1266 {"amdgpu-no-workitem-id-x", "amdgpu-no-workitem-id-y",
1267 "amdgpu-no-workitem-id-z", "amdgpu-no-heap-ptr"});
1268 if (!LDSParams.IndirectAccess.StaticLDSGlobals.empty() ||
1269 !LDSParams.IndirectAccess.DynamicLDSGlobals.empty())
1270 removeFnAttrFromReachable(CG, Func, {"amdgpu-no-lds-kernel-id"});
1271 reorderStaticDynamicIndirectLDSSet(LDSParams);
1272 buildSwLDSGlobal(Func);
1273 buildSwDynLDSGlobal(Func);
1274 populateSwMetadataGlobal(Func);
1275 populateSwLDSAttributeAndMetadata(Func);
1276 populateLDSToReplacementIndicesMap(Func);
1277 DomTreeUpdater DTU(DTCallback(*Func),
1278 DomTreeUpdater::UpdateStrategy::Lazy);
1279 lowerKernelLDSAccesses(Func, DTU);
1280 Changed = true;
1281 }
1282 }
1283
1284 // Get the Uses of LDS from non-kernels.
1285 getUsesOfLDSByNonKernels();
1286
1287 // Get non-kernels with LDS ptr as argument and called by kernels.
1288 getNonKernelsWithLDSArguments(CG);
1289
1290 // Lower LDS accesses in non-kernels.
1291 if (!FuncLDSAccessInfo.NonKernelToLDSAccessMap.empty() ||
1292 !FuncLDSAccessInfo.NonKernelsWithLDSArgument.empty()) {
1293 NonKernelLDSParameters NKLDSParams;
1294 NKLDSParams.OrderedKernels = getOrderedIndirectLDSAccessingKernels(
1295 FuncLDSAccessInfo.KernelsWithIndirectLDSAccess);
1296 NKLDSParams.OrdereLDSGlobals = getOrderedNonKernelAllLDSGlobals(
1297 FuncLDSAccessInfo.AllNonKernelLDSAccess);
1298 buildNonKernelLDSBaseTable(NKLDSParams);
1299 buildNonKernelLDSOffsetTable(NKLDSParams);
1300 for (auto &K : FuncLDSAccessInfo.NonKernelToLDSAccessMap) {
1301 Function *Func = K.first;
1302 DenseSet<GlobalVariable *> &LDSGlobals = K.second;
1303 SetVector<GlobalVariable *> OrderedLDSGlobals = sortByName(
1304 std::vector<GlobalVariable *>(LDSGlobals.begin(), LDSGlobals.end()));
1305 lowerNonKernelLDSAccesses(Func, OrderedLDSGlobals, NKLDSParams);
1306 }
1307 for (Function *Func : FuncLDSAccessInfo.NonKernelsWithLDSArgument) {
1308 auto &K = FuncLDSAccessInfo.NonKernelToLDSAccessMap;
1309 if (K.contains(Func))
1310 continue;
1312 lowerNonKernelLDSAccesses(Func, Vec, NKLDSParams);
1313 }
1314 Changed = true;
1315 }
1316
1317 if (!Changed)
1318 return Changed;
1319
1320 for (auto &GV : make_early_inc_range(M.globals())) {
1322 // probably want to remove from used lists
1324 if (GV.use_empty())
1325 GV.eraseFromParent();
1326 }
1327 }
1328
1329 if (AsanInstrumentLDS) {
1330 SmallVector<InterestingMemoryOperand, 16> OperandsToInstrument;
1331 for (Instruction *Inst : AsanInfo.Instructions) {
1332 SmallVector<InterestingMemoryOperand, 1> InterestingOperands;
1333 getInterestingMemoryOperands(M, Inst, InterestingOperands);
1334 llvm::append_range(OperandsToInstrument, InterestingOperands);
1335 }
1336 for (auto &Operand : OperandsToInstrument) {
1337 Value *Addr = Operand.getPtr();
1338 instrumentAddress(M, IRB, Operand.getInsn(), Operand.getInsn(), Addr,
1339 Operand.Alignment.valueOrOne(), Operand.TypeStoreSize,
1340 Operand.IsWrite, nullptr, false, false, AsanInfo.Scale,
1341 AsanInfo.Offset);
1342 Changed = true;
1343 }
1344 }
1345
1346 return Changed;
1347}
1348
1349class AMDGPUSwLowerLDSLegacy : public ModulePass {
1350public:
1351 static char ID;
1352 AMDGPUSwLowerLDSLegacy() : ModulePass(ID) {}
1353 bool runOnModule(Module &M) override;
1354 void getAnalysisUsage(AnalysisUsage &AU) const override {
1356 }
1357};
1358} // namespace
1359
1360char AMDGPUSwLowerLDSLegacy::ID = 0;
1361char &llvm::AMDGPUSwLowerLDSLegacyPassID = AMDGPUSwLowerLDSLegacy::ID;
1362
1363INITIALIZE_PASS_BEGIN(AMDGPUSwLowerLDSLegacy, "amdgpu-sw-lower-lds",
1364 "AMDGPU Software lowering of LDS", false, false)
1366INITIALIZE_PASS_END(AMDGPUSwLowerLDSLegacy, "amdgpu-sw-lower-lds",
1367 "AMDGPU Software lowering of LDS", false, false)
1368
1369bool AMDGPUSwLowerLDSLegacy::runOnModule(Module &M) {
1370 // AddressSanitizer pass adds "nosanitize_address" module flag if it has
1371 // instrumented the IR. Return early if the flag is not present.
1372 if (!M.getModuleFlag("nosanitize_address"))
1373 return false;
1374 DominatorTreeWrapperPass *const DTW =
1375 getAnalysisIfAvailable<DominatorTreeWrapperPass>();
1376 auto DTCallback = [&DTW](Function &F) -> DominatorTree * {
1377 return DTW ? &DTW->getDomTree() : nullptr;
1378 };
1379
1380 AMDGPUSwLowerLDS SwLowerLDSImpl(M, DTCallback);
1381 bool IsChanged = SwLowerLDSImpl.run();
1382 return IsChanged;
1383}
1384
1386 return new AMDGPUSwLowerLDSLegacy();
1387}
1388
1391 // AddressSanitizer pass adds "nosanitize_address" module flag if it has
1392 // instrumented the IR. Return early if the flag is not present.
1393 if (!M.getModuleFlag("nosanitize_address"))
1394 return PreservedAnalyses::all();
1395 auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
1396 auto DTCallback = [&FAM](Function &F) -> DominatorTree * {
1397 return &FAM.getResult<DominatorTreeAnalysis>(F);
1398 };
1399 AMDGPUSwLowerLDS SwLowerLDSImpl(M, DTCallback);
1400 bool IsChanged = SwLowerLDSImpl.run();
1401 if (!IsChanged)
1402 return PreservedAnalyses::all();
1403
1406 return PA;
1407}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
unsigned uint64_t
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
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
A node in the call graph for a module.
Definition CallGraph.h:162
Function * getFunction() const
Returns the function that this call graph node represents.
Definition CallGraph.h:193
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:537
static 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:1470
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
This is an important base class in LLVM.
Definition Constant.h:43
LLVM_ABI void removeDeadConstantUsers() const
If there are any dead constant users dangling off of this constant, remove them.
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
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.
arg_iterator arg_end()
Definition Function.h:862
arg_iterator arg_begin()
Definition Function.h:853
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:452
AtomicCmpXchgInst * CreateAtomicCmpXchg(Value *Ptr, Value *Cmp, Value *New, MaybeAlign Align, AtomicOrdering SuccessOrdering, AtomicOrdering FailureOrdering, SyncScope::ID SSID=SyncScope::System)
Definition IRBuilder.h:1978
IntegerType * getInt1Ty()
Fetch the type representing a single bit.
Definition IRBuilder.h:519
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:1226
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2248
void SetCurrentDebugLocation(const DebugLoc &L)
Set location information used by debugging information.
Definition IRBuilder.h:221
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition IRBuilder.h:534
IntegerType * getInt64Ty()
Fetch the type representing a 64-bit integer.
Definition IRBuilder.h:539
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
Definition IRBuilder.h:2029
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:1483
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
Definition IRBuilder.h:482
UncondBrInst * CreateBr(BasicBlock *Dest)
Create an unconditional 'br label X' instruction.
Definition IRBuilder.h:1220
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition IRBuilder.h:477
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition IRBuilder.h:2550
Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")
Definition IRBuilder.h:2385
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:1916
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:629
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:608
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Definition IRBuilder.h:2131
ReturnInst * CreateRetVoid()
Create a 'ret void' instruction.
Definition IRBuilder.h:1197
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:1935
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1432
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2243
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition IRBuilder.h:2564
PointerType * getPtrTy(unsigned AddrSpace=0)
Fetch the type representing a pointer.
Definition IRBuilder.h:577
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition IRBuilder.h:181
Type * getVoidTy()
Fetch the type representing void.
Definition IRBuilder.h:572
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:1602
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
Definition IRBuilder.h:524
Value * CreateAddrSpaceCast(Value *V, Type *DestTy, const Twine &Name="")
Definition IRBuilder.h:2258
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition IRBuilder.h:1466
AtomicRMWInst * CreateAtomicRMW(AtomicRMWInst::BinOp Op, Value *Ptr, Value *Val, MaybeAlign Align, AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System, bool Elementwise=false)
Definition IRBuilder.h:1991
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2903
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
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:96
Metadata node.
Definition Metadata.h:1069
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
Definition Metadata.h:1567
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:255
A Module instance is used to store all the information related to an LLVM module.
Definition Module.h:67
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
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
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:683
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
bool isPointerTy() const
True if this is an instance of PointerType.
Definition Type.h:282
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.
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:255
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition Value.cpp:553
iterator_range< user_iterator > users()
Definition Value.h:426
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:346
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:561
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
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)
DenseMap< 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:1765
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:2208
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:633
InnerAnalysisManagerProxy< FunctionAnalysisManager, Module > FunctionAnalysisManagerModuleProxy
Provide the FunctionAnalysisManager to Module proxy.
char & AMDGPUSwLowerLDSLegacyPassID
void sort(IteratorTy Start, IteratorTy End)
Definition STLExtras.h:1636
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:144
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
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:1947
LLVM_ABI void getAddressSanitizerParams(const Triple &TargetTriple, int LongSize, bool IsKasan, uint64_t *ShadowBase, int *MappingScale, bool *OrShadowOffset)
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:77
Align valueOrOne() const
For convenience, returns a valid alignment or 1 if undefined.
Definition Alignment.h:130