LLVM 24.0.0git
AMDGPULowerBufferFatPointers.cpp
Go to the documentation of this file.
1//===-- AMDGPULowerBufferFatPointers.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 operations on buffer fat pointers (addrspace 7) to
10// operations on buffer resources (addrspace 8) and is needed for correct
11// codegen.
12//
13// # Background
14//
15// Address space 7 (the buffer fat pointer) is a 160-bit pointer that consists
16// of a 128-bit buffer descriptor and a 32-bit offset into that descriptor.
17// The buffer resource part needs to be it needs to be a "raw" buffer resource
18// (it must have a stride of 0 and bounds checks must be in raw buffer mode
19// or disabled).
20//
21// When these requirements are met, a buffer resource can be treated as a
22// typical (though quite wide) pointer that follows typical LLVM pointer
23// semantics. This allows the frontend to reason about such buffers (which are
24// often encountered in the context of SPIR-V kernels).
25//
26// However, because of their non-power-of-2 size, these fat pointers cannot be
27// present during translation to MIR (though this restriction may be lifted
28// during the transition to GlobalISel). Therefore, this pass is needed in order
29// to correctly implement these fat pointers.
30//
31// The resource intrinsics take the resource part (the address space 8 pointer)
32// and the offset part (the 32-bit integer) as separate arguments. In addition,
33// many users of these buffers manipulate the offset while leaving the resource
34// part alone. For these reasons, we want to typically separate the resource
35// and offset parts into separate variables, but combine them together when
36// encountering cases where this is required, such as by inserting these values
37// into aggretates or moving them to memory.
38//
39// Therefore, at a high level, `ptr addrspace(7) %x` becomes `ptr addrspace(8)
40// %x.rsrc` and `i32 %x.off`, which will be combined into `{ptr addrspace(8),
41// i32} %x = {%x.rsrc, %x.off}` if needed. Similarly, `vector<Nxp7>` becomes
42// `{vector<Nxp8>, vector<Nxi32 >}` and its component parts.
43//
44// # Implementation
45//
46// This pass proceeds in three main phases:
47//
48// ## Rewriting loads and stores of p7 and memcpy()-like handling
49//
50// The first phase is to rewrite away all loads and stors of `ptr addrspace(7)`,
51// including aggregates containing such pointers, to ones that use `i160`. This
52// is handled by `StoreFatPtrsAsIntsAndExpandMemcpyVisitor` , which visits
53// loads, stores, and allocas and, if the loaded or stored type contains `ptr
54// addrspace(7)`, rewrites it to use i160, `ptrtoint`ing before stores and
55// `inttoptr`ing after loads. Vectors of pointers work the same way. Since i160
56// and p7 differ in size and alignment, aggregates are split into one access per
57// leaf, and allocas and GEPs use byte offsets and sizes from the original type.
58//
59// Such a transformation allows the later phases of the pass to not need
60// to handle buffer fat pointers moving to and from memory, where we load
61// have to handle the incompatibility between a `{Nxp8, Nxi32}` representation
62// and `Nxi60` directly. Instead, that transposing action (where the vectors
63// of resources and vectors of offsets are concatentated before being stored to
64// memory) are handled through implementing `inttoptr` and `ptrtoint` only.
65//
66// Atomics operations on `ptr addrspace(7)` values are not suppported, as the
67// hardware does not include a 160-bit atomic.
68//
69// In order to save on O(N) work and to ensure that the contents type
70// legalizer correctly splits up wide loads, also unconditionally lower
71// memcpy-like intrinsics into loops here.
72//
73// ## Buffer contents type legalization
74//
75// The underlying buffer intrinsics only support types up to 128 bits long,
76// and don't support complex types. If buffer operations were
77// standard pointer operations that could be represented as MIR-level loads,
78// this would be handled by the various legalization schemes in instruction
79// selection. However, because we have to do the conversion from `load` and
80// `store` to intrinsics at LLVM IR level, we must perform that legalization
81// ourselves.
82//
83// This involves a combination of
84// - Converting arrays to vectors where possible
85// - Otherwise, splitting loads and stores of aggregates into loads/stores of
86// each component.
87// - Zero-extending things to fill a whole number of bytes
88// - Casting values of types that don't neatly correspond to supported machine
89// value
90// (for example, an i96 or i256) into ones that would work (
91// like <3 x i32> and <8 x i32>, respectively)
92// - Splitting values that are too long (such as aforementioned <8 x i32>) into
93// multiple operations.
94//
95// ## Type remapping
96//
97// We use a `ValueMapper` to mangle uses of [vectors of] buffer fat pointers
98// to the corresponding struct type, which has a resource part and an offset
99// part.
100//
101// This uses a `BufferFatPtrToStructTypeMap` and a `FatPtrConstMaterializer`
102// to, usually by way of `setType`ing values. Constants are handled here
103// because there isn't a good way to fix them up later.
104//
105// This has the downside of leaving the IR in an invalid state (for example,
106// the instruction `getelementptr {ptr addrspace(8), i32} %p, ...` will exist),
107// but all such invalid states will be resolved by the third phase.
108//
109// Functions that don't take buffer fat pointers are modified in place. Those
110// that do take such pointers have their basic blocks moved to a new function
111// with arguments that are {ptr addrspace(8), i32} arguments and return values.
112// This phase also records intrinsics so that they can be remangled or deleted
113// later.
114//
115// ## Splitting pointer structs
116//
117// The meat of this pass consists of defining semantics for operations that
118// produce or consume [vectors of] buffer fat pointers in terms of their
119// resource and offset parts. This is accomplished throgh the `SplitPtrStructs`
120// visitor.
121//
122// In the first pass through each function that is being lowered, the splitter
123// inserts new instructions to implement the split-structures behavior, which is
124// needed for correctness and performance. It records a list of "split users",
125// instructions that are being replaced by operations on the resource and offset
126// parts.
127//
128// Split users do not necessarily need to produce parts themselves (
129// a `load float, ptr addrspace(7)` does not, for example), but, if they do not
130// generate fat buffer pointers, they must RAUW in their replacement
131// instructions during the initial visit.
132//
133// When these new instructions are created, they use the split parts recorded
134// for their initial arguments in order to generate their replacements, creating
135// a parallel set of instructions that does not refer to the original fat
136// pointer values but instead to their resource and offset components.
137//
138// Instructions, such as `extractvalue`, that produce buffer fat pointers from
139// sources that do not have split parts, have such parts generated using
140// `extractvalue`. This is also the initial handling of PHI nodes, which
141// are then cleaned up.
142//
143// ### Conditionals
144//
145// PHI nodes are initially given resource parts via `extractvalue`. However,
146// this is not an efficient rewrite of such nodes, as, in most cases, the
147// resource part in a conditional or loop remains constant throughout the loop
148// and only the offset varies. Failing to optimize away these constant resources
149// would cause additional registers to be sent around loops and might lead to
150// waterfall loops being generated for buffer operations due to the
151// "non-uniform" resource argument.
152//
153// Therefore, after all instructions have been visited, the pointer splitter
154// post-processes all encountered conditionals. Given a PHI node or select,
155// getPossibleRsrcRoots() collects all values that the resource parts of that
156// conditional's input could come from as well as collecting all conditional
157// instructions encountered during the search. If, after filtering out the
158// initial node itself, the set of encountered conditionals is a subset of the
159// potential roots and there is a single potential resource that isn't in the
160// conditional set, that value is the only possible value the resource argument
161// could have throughout the control flow.
162//
163// If that condition is met, then a PHI node can have its resource part changed
164// to the singleton value and then be replaced by a PHI on the offsets.
165// Otherwise, each PHI node is split into two, one for the resource part and one
166// for the offset part, which replace the temporary `extractvalue` instructions
167// that were added during the first pass.
168//
169// Similar logic applies to `select`, where
170// `%z = select i1 %cond, %cond, ptr addrspace(7) %x, ptr addrspace(7) %y`
171// can be split into `%z.rsrc = %x.rsrc` and
172// `%z.off = select i1 %cond, ptr i32 %x.off, i32 %y.off`
173// if both `%x` and `%y` have the same resource part, but two `select`
174// operations will be needed if they do not.
175//
176// ### Final processing
177//
178// After conditionals have been cleaned up, the IR for each function is
179// rewritten to remove all the old instructions that have been split up.
180//
181// Any instruction that used to produce a buffer fat pointer (and therefore now
182// produces a resource-and-offset struct after type remapping) is
183// replaced as follows:
184// 1. All debug value annotations are cloned to reflect that the resource part
185// and offset parts are computed separately and constitute different
186// fragments of the underlying source language variable.
187// 2. All uses that were themselves split are replaced by a `poison` of the
188// struct type, as they will themselves be erased soon. This rule, combined
189// with debug handling, should leave the use lists of split instructions
190// empty in almost all cases.
191// 3. If a user of the original struct-valued result remains, the structure
192// needed for the new types to work is constructed out of the newly-defined
193// parts, and the original instruction is replaced by this structure
194// before being erased. Instructions requiring this construction include
195// `ret` and `insertvalue`.
196//
197// # Consequences
198//
199// This pass does not alter the CFG.
200//
201// Alias analysis information will become coarser, as the LLVM alias analyzer
202// cannot handle the buffer intrinsics. Specifically, while we can determine
203// that the following two loads do not alias:
204// ```
205// %y = getelementptr i32, ptr addrspace(7) %x, i32 1
206// %a = load i32, ptr addrspace(7) %x
207// %b = load i32, ptr addrspace(7) %y
208// ```
209// we cannot (except through some code that runs during scheduling) determine
210// that the rewritten loads below do not alias.
211// ```
212// %y.off = add i32 %x.off, 1
213// %a = call @llvm.amdgcn.raw.ptr.buffer.load(ptr addrspace(8) %x.rsrc, i32
214// %x.off, ...)
215// %b = call @llvm.amdgcn.raw.ptr.buffer.load(ptr addrspace(8)
216// %x.rsrc, i32 %y.off, ...)
217// ```
218// However, existing alias information is preserved.
219//===----------------------------------------------------------------------===//
220
221#include "AMDGPU.h"
222#include "AMDGPUTargetMachine.h"
223#include "GCNSubtarget.h"
224#include "SIDefines.h"
226#include "llvm/ADT/SmallVector.h"
234#include "llvm/IR/Constants.h"
235#include "llvm/IR/DebugInfo.h"
236#include "llvm/IR/DerivedTypes.h"
237#include "llvm/IR/IRBuilder.h"
238#include "llvm/IR/InstIterator.h"
239#include "llvm/IR/InstVisitor.h"
240#include "llvm/IR/Instructions.h"
242#include "llvm/IR/Intrinsics.h"
243#include "llvm/IR/IntrinsicsAMDGPU.h"
244#include "llvm/IR/Metadata.h"
245#include "llvm/IR/Operator.h"
246#include "llvm/IR/PassManager.h"
247#include "llvm/IR/PatternMatch.h"
249#include "llvm/IR/ValueHandle.h"
251#include "llvm/Pass.h"
255#include "llvm/Support/Debug.h"
262
263#define DEBUG_TYPE "amdgpu-lower-buffer-fat-pointers"
264
265using namespace llvm;
266
269
270static constexpr unsigned BufferOffsetWidth = 32;
271
272namespace {
273/// Recursively replace instances of ptr addrspace(7) and vector<Nxptr
274/// addrspace(7)> with some other type as defined by the relevant subclass.
275class BufferFatPtrTypeLoweringBase : public ValueMapTypeRemapper {
277
278 Type *remapTypeImpl(Type *Ty);
279
280protected:
281 virtual Type *remapScalar(PointerType *PT) = 0;
282 virtual Type *remapVector(VectorType *VT) = 0;
283
284 const DataLayout &DL;
285
286public:
287 BufferFatPtrTypeLoweringBase(const DataLayout &DL) : DL(DL) {}
288 Type *remapType(Type *SrcTy) override;
289 void clear() { Map.clear(); }
290};
291
292/// Remap ptr addrspace(7) to i160 and vector<Nxptr addrspace(7)> to
293/// vector<Nxi60> in order to correctly handling loading/storing these values
294/// from memory.
295class BufferFatPtrToIntTypeMap : public BufferFatPtrTypeLoweringBase {
296 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
297
298protected:
299 Type *remapScalar(PointerType *PT) override { return DL.getIntPtrType(PT); }
300 Type *remapVector(VectorType *VT) override { return DL.getIntPtrType(VT); }
301};
302
303/// Remap ptr addrspace(7) to {ptr addrspace(8), i32} (the resource and offset
304/// parts of the pointer) so that we can easily rewrite operations on these
305/// values that aren't loading them from or storing them to memory.
306class BufferFatPtrToStructTypeMap : public BufferFatPtrTypeLoweringBase {
307 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
308
309protected:
310 Type *remapScalar(PointerType *PT) override;
311 Type *remapVector(VectorType *VT) override;
312};
313} // namespace
314
315// This code is adapted from the type remapper in lib/Linker/IRMover.cpp
316Type *BufferFatPtrTypeLoweringBase::remapTypeImpl(Type *Ty) {
317 Type **Entry = &Map[Ty];
318 if (*Entry)
319 return *Entry;
320 if (auto *PT = dyn_cast<PointerType>(Ty)) {
321 if (PT->getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER) {
322 return *Entry = remapScalar(PT);
323 }
324 }
325 if (auto *VT = dyn_cast<VectorType>(Ty)) {
326 auto *PT = dyn_cast<PointerType>(VT->getElementType());
327 if (PT && PT->getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER) {
328 return *Entry = remapVector(VT);
329 }
330 return *Entry = Ty;
331 }
332 // Whether the type is one that is structurally uniqued - that is, if it is
333 // not a named struct (the only kind of type where multiple structurally
334 // identical types that have a distinct `Type*`)
335 StructType *TyAsStruct = dyn_cast<StructType>(Ty);
336 bool IsUniqued = !TyAsStruct || TyAsStruct->isLiteral();
337 // Base case for ints, floats, opaque pointers, and so on, which don't
338 // require recursion.
339 if (Ty->getNumContainedTypes() == 0 && IsUniqued)
340 return *Entry = Ty;
341 bool Changed = false;
342 SmallVector<Type *> ElementTypes(Ty->getNumContainedTypes(), nullptr);
343 for (unsigned int I = 0, E = Ty->getNumContainedTypes(); I < E; ++I) {
344 Type *OldElem = Ty->getContainedType(I);
345 Type *NewElem = remapTypeImpl(OldElem);
346 ElementTypes[I] = NewElem;
347 Changed |= (OldElem != NewElem);
348 }
349 // Recursive calls to remapTypeImpl() may have invalidated pointer.
350 Entry = &Map[Ty];
351 if (!Changed) {
352 return *Entry = Ty;
353 }
354 if (auto *ArrTy = dyn_cast<ArrayType>(Ty))
355 return *Entry = ArrayType::get(ElementTypes[0], ArrTy->getNumElements());
356 if (auto *FnTy = dyn_cast<FunctionType>(Ty))
357 return *Entry = FunctionType::get(ElementTypes[0],
358 ArrayRef(ElementTypes).slice(1),
359 FnTy->isVarArg());
360 if (auto *STy = dyn_cast<StructType>(Ty)) {
361 // Genuine opaque types don't have a remapping.
362 if (STy->isOpaque())
363 return *Entry = Ty;
364 bool IsPacked = STy->isPacked();
365 if (IsUniqued)
366 return *Entry = StructType::get(Ty->getContext(), ElementTypes, IsPacked);
367 SmallString<16> Name(STy->getName());
368 STy->setName("");
369 return *Entry = StructType::create(Ty->getContext(), ElementTypes, Name,
370 IsPacked);
371 }
372 llvm_unreachable("Unknown type of type that contains elements");
373}
374
375Type *BufferFatPtrTypeLoweringBase::remapType(Type *SrcTy) {
376 return remapTypeImpl(SrcTy);
377}
378
379Type *BufferFatPtrToStructTypeMap::remapScalar(PointerType *PT) {
380 LLVMContext &Ctx = PT->getContext();
381 return StructType::get(PointerType::get(Ctx, AMDGPUAS::BUFFER_RESOURCE),
383}
384
385Type *BufferFatPtrToStructTypeMap::remapVector(VectorType *VT) {
386 ElementCount EC = VT->getElementCount();
387 LLVMContext &Ctx = VT->getContext();
388 Type *RsrcVec =
389 VectorType::get(PointerType::get(Ctx, AMDGPUAS::BUFFER_RESOURCE), EC);
390 Type *OffVec = VectorType::get(IntegerType::get(Ctx, BufferOffsetWidth), EC);
391 return StructType::get(RsrcVec, OffVec);
392}
393
394static bool isBufferFatPtrOrVector(Type *Ty) {
395 if (auto *PT = dyn_cast<PointerType>(Ty->getScalarType()))
396 return PT->getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER;
397 return false;
398}
399
400// True if the type is {ptr addrspace(8), i32} or a struct containing vectors of
401// those types. Used to quickly skip instructions we don't need to process.
402static bool isSplitFatPtr(Type *Ty) {
403 auto *ST = dyn_cast<StructType>(Ty);
404 if (!ST)
405 return false;
406 if (!ST->isLiteral() || ST->getNumElements() != 2)
407 return false;
408 auto *MaybeRsrc =
409 dyn_cast<PointerType>(ST->getElementType(0)->getScalarType());
410 auto *MaybeOff =
411 dyn_cast<IntegerType>(ST->getElementType(1)->getScalarType());
412 return MaybeRsrc && MaybeOff &&
413 MaybeRsrc->getAddressSpace() == AMDGPUAS::BUFFER_RESOURCE &&
414 MaybeOff->getBitWidth() == BufferOffsetWidth;
415}
416
417// True if the result type or any argument types are buffer fat pointers.
419 Type *T = C->getType();
420 return isBufferFatPtrOrVector(T) || any_of(C->operands(), [](const Use &U) {
421 return isBufferFatPtrOrVector(U.get()->getType());
422 });
423}
424
425namespace {
426/// Convert [vectors of] buffer fat pointers to integers when they are read from
427/// or stored to memory. This ensures that these pointers will have the same
428/// memory layout as before they are lowered, even though they will no longer
429/// have their previous layout in registers/in the program (they'll be broken
430/// down into resource and offset parts). This has the downside of imposing
431/// marshalling costs when reading or storing these values, but since placing
432/// such pointers into memory is an uncommon operation at best, we feel that
433/// this cost is acceptable for better performance in the common case.
434class StoreFatPtrsAsIntsAndExpandMemcpyVisitor
435 : public InstVisitor<StoreFatPtrsAsIntsAndExpandMemcpyVisitor, bool> {
436 BufferFatPtrToIntTypeMap *TypeMap;
437
439
440 const DataLayout &DL;
441
442 // Used for memcpy() lowering.
443 const TargetTransformInfo *TTI;
444 ScalarEvolution *SE;
445
446 Value *applyOffset(Value *Ptr, uint64_t Off);
447 // Visits each maximal subtree of `Ty` that is fat-ptr-free or is itself a
448 // [vector of] fat pointer(s), at its offset in `Ty`'s original layout.
449 void forEachAggLeaf(
450 Type *Ty, SmallVectorImpl<unsigned> &AggIdxs, uint64_t Off,
451 const Twine &Name,
452 function_ref<void(Type *LeafTy, Type *IntLeafTy, ArrayRef<unsigned> Idxs,
453 uint64_t Off, const Twine &Name)>
454 Visit);
455
456public:
457 StoreFatPtrsAsIntsAndExpandMemcpyVisitor(BufferFatPtrToIntTypeMap *TypeMap,
458 const DataLayout &DL,
459 LLVMContext &Ctx)
460 : TypeMap(TypeMap), IRB(Ctx, InstSimplifyFolder(DL)), DL(DL) {}
461 bool processFunction(Function &F, const TargetTransformInfo *TTI,
462 ScalarEvolution *SE);
463
464 bool visitInstruction(Instruction &I) { return false; }
465 bool visitAllocaInst(AllocaInst &I);
466 bool visitLoadInst(LoadInst &LI);
467 bool visitStoreInst(StoreInst &SI);
468 bool visitGetElementPtrInst(GetElementPtrInst &I);
469
470 bool visitMemCpyInst(MemCpyInst &MCI);
471 bool visitMemMoveInst(MemMoveInst &MMI);
472 bool visitMemSetInst(MemSetInst &MSI);
473 bool visitMemSetPatternInst(MemSetPatternInst &MSPI);
474};
475} // namespace
476
477Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::applyOffset(Value *Ptr,
478 uint64_t Off) {
479 // The InstSimplifyFolder gives back `Ptr` itself when `Off` is 0.
480 return IRB.CreatePtrAdd(
481 Ptr, ConstantInt::get(DL.getIndexType(Ptr->getType()), Off),
482 Ptr->getName() + ".off." + Twine(Off), GEPNoWrapFlags::noUnsignedWrap());
483}
484
485void StoreFatPtrsAsIntsAndExpandMemcpyVisitor::forEachAggLeaf(
486 Type *Ty, SmallVectorImpl<unsigned> &AggIdxs, uint64_t Off,
487 const Twine &Name,
488 function_ref<void(Type *LeafTy, Type *IntLeafTy, ArrayRef<unsigned> Idxs,
489 uint64_t Off, const Twine &Name)>
490 Visit) {
491 Type *IntTy = TypeMap->remapType(Ty);
492 if (isBufferFatPtrOrVector(Ty) || Ty == IntTy) {
493 // Zero-sized leaves ({} or [0 x T]) access no bytes; skip them.
494 if (DL.getTypeStoreSize(Ty) != 0)
495 Visit(Ty, IntTy, AggIdxs, Off, Name);
496 return;
497 }
498 auto Recurse = [&](unsigned I, Type *ElemTy, uint64_t ElemOff) {
499 AggIdxs.push_back(I);
500 forEachAggLeaf(ElemTy, AggIdxs, Off + ElemOff, Name + "." + Twine(I),
501 Visit);
502 AggIdxs.pop_back();
503 };
504 if (auto *ST = dyn_cast<StructType>(Ty)) {
505 const StructLayout *Layout = DL.getStructLayout(ST);
506 for (auto [I, ElemTy, ElemOff] :
507 enumerate(ST->elements(), Layout->getMemberOffsets()))
508 Recurse(I, ElemTy, ElemOff.getFixedValue());
509 return;
510 }
511 auto *AT = cast<ArrayType>(Ty);
512 Type *ElemTy = AT->getElementType();
513 uint64_t Stride = DL.getTypeAllocSize(ElemTy).getFixedValue();
514 for (unsigned I : seq<unsigned>(AT->getNumElements()))
515 Recurse(I, ElemTy, I * Stride);
516}
517
518bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::processFunction(
519 Function &F, const TargetTransformInfo *TTI, ScalarEvolution *SE) {
520 this->TTI = TTI;
521 this->SE = SE;
522 bool Changed = false;
523 // Process memcpy-like instructions after the main iteration because they can
524 // invalidate iterators.
525 SmallVector<WeakTrackingVH> CanBecomeLoops;
526 for (Instruction &I : make_early_inc_range(instructions(F))) {
528 CanBecomeLoops.push_back(&I);
529 else
530 Changed |= visit(I);
531 }
532 for (WeakTrackingVH VH : make_early_inc_range(CanBecomeLoops)) {
534 }
535 this->TTI = nullptr;
536 this->SE = nullptr;
537 return Changed;
538}
539
540bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitAllocaInst(AllocaInst &I) {
541 Type *Ty = I.getAllocatedType();
542 Type *NewTy = TypeMap->remapType(Ty);
543 if (Ty == NewTy)
544 return false;
545 // i160 is smaller than ptr addrspace(7) (24 bytes vs. 32); fall back to a
546 // byte array of the original size so sizes computed from Ty stay in bounds.
547 TypeSize AllocSize = DL.getTypeAllocSize(Ty);
548 if (AllocSize.isFixed() && DL.getTypeAllocSize(NewTy) != AllocSize)
549 NewTy = ArrayType::get(IRB.getInt8Ty(), AllocSize.getFixedValue());
550 I.setAllocatedType(NewTy);
551 return true;
552}
553
554bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitGetElementPtrInst(
555 GetElementPtrInst &I) {
556 Type *Ty = I.getSourceElementType();
557 if (Ty == TypeMap->remapType(Ty))
558 return false;
559 // Lower to a byte offset now, before remapping changes p7's layout (see file
560 // header).
561 IRB.SetInsertPoint(&I);
562 Value *Off = emitGEPOffset(&IRB, DL, &I);
563 Value *NewGEP = IRB.CreatePtrAdd(I.getPointerOperand(), Off, I.getName(),
564 I.getNoWrapFlags());
565 I.replaceAllUsesWith(NewGEP);
566 I.eraseFromParent();
567 return true;
568}
569
570bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitLoadInst(LoadInst &LI) {
571 Type *Ty = LI.getType();
572 Type *IntTy = TypeMap->remapType(Ty);
573 if (Ty == IntTy)
574 return false;
575
576 IRB.SetInsertPoint(&LI);
577 if (!isBufferFatPtrOrVector(Ty)) {
578 // i160 has the same 20-byte store size as p7, so loading each leaf at
579 // its original-layout offset accesses the same bytes as the unlowered load.
580 Value *Agg = PoisonValue::get(Ty);
581 AAMDNodes AATags = LI.getAAMetadata();
582 SmallVector<unsigned> AggIdxs;
583 forEachAggLeaf(
584 Ty, AggIdxs, 0, LI.getName(),
585 [&](Type *LeafTy, Type *IntLeafTy, ArrayRef<unsigned> Idxs,
586 uint64_t Off, const Twine &Name) {
587 Value *Ptr = applyOffset(LI.getPointerOperand(), Off);
588 LoadInst *NewLI = IRB.CreateAlignedLoad(
589 IntLeafTy, Ptr, commonAlignment(LI.getAlign(), Off), Name);
590 NewLI->setVolatile(LI.isVolatile());
591 copyMetadataForLoad(*NewLI, LI);
592 NewLI->setAAMetadata(AATags.adjustForAccess(Off, IntLeafTy, DL));
593 Value *V = NewLI;
594 if (LeafTy != IntLeafTy)
595 V = IRB.CreateIntToPtr(NewLI, LeafTy, Name + ".ptr");
596 Agg = IRB.CreateInsertValue(Agg, V, Idxs, Name + ".agg");
597 });
598 LI.replaceAllUsesWith(Agg);
599 LI.eraseFromParent();
600 return true;
601 }
602 auto *NLI = cast<LoadInst>(LI.clone());
603 NLI->mutateType(IntTy);
604 NLI = IRB.Insert(NLI);
605 NLI->takeName(&LI);
606
607 Value *CastBack = IRB.CreateIntToPtr(NLI, Ty, NLI->getName() + ".ptr");
608 LI.replaceAllUsesWith(CastBack);
609 LI.eraseFromParent();
610 return true;
611}
612
613bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitStoreInst(StoreInst &SI) {
614 Value *V = SI.getValueOperand();
615 Type *Ty = V->getType();
616 Type *IntTy = TypeMap->remapType(Ty);
617 if (Ty == IntTy)
618 return false;
619
620 IRB.SetInsertPoint(&SI);
621 if (!isBufferFatPtrOrVector(Ty)) {
622 // Store each leaf at its byte offset in the original layout; see
623 // visitLoadInst.
624 AAMDNodes AATags = SI.getAAMetadata();
625 SmallVector<unsigned> AggIdxs;
626 forEachAggLeaf(
627 Ty, AggIdxs, 0, V->getName(),
628 [&](Type *LeafTy, Type *IntLeafTy, ArrayRef<unsigned> Idxs,
629 uint64_t Off, const Twine &Name) {
630 Value *Leaf = IRB.CreateExtractValue(V, Idxs, Name);
631 if (LeafTy != IntLeafTy)
632 Leaf = IRB.CreatePtrToInt(Leaf, IntLeafTy, Name + ".int");
633 auto *NewSI = cast<StoreInst>(SI.clone());
634 NewSI->setAlignment(commonAlignment(SI.getAlign(), Off));
635 NewSI->setOperand(0, Leaf);
636 NewSI->setOperand(1, applyOffset(SI.getPointerOperand(), Off));
637 // Each leaf covers only part of the original assignment.
638 NewSI->setMetadata(LLVMContext::MD_DIAssignID, nullptr);
639 IRB.Insert(NewSI);
640 NewSI->setAAMetadata(AATags.adjustForAccess(Off, IntLeafTy, DL));
641 });
642 SI.eraseFromParent();
643 return true;
644 }
645 Value *IntV = IRB.CreatePtrToInt(V, IntTy, V->getName() + ".int");
646 for (auto *Dbg : at::getDVRAssignmentMarkers(&SI))
647 Dbg->setRawLocation(ValueAsMetadata::get(IntV));
648
649 SI.setOperand(0, IntV);
650 return true;
651}
652
653bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemCpyInst(
654 MemCpyInst &MCI) {
655 // TODO: Allow memcpy.p7.p3 as a synonym for the direct-to-LDS copy, which'll
656 // need loop expansion here.
659 return false;
660 llvm::expandMemCpyAsLoop(&MCI, *TTI, SE);
661 MCI.eraseFromParent();
662 return true;
663}
664
665bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemMoveInst(
666 MemMoveInst &MMI) {
669 return false;
671 "memmove() on buffer descriptors is not implemented because pointer "
672 "comparison on buffer descriptors isn't implemented\n");
673}
674
675bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetInst(
676 MemSetInst &MSI) {
678 return false;
680 MSI.eraseFromParent();
681 return true;
682}
683
684bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetPatternInst(
685 MemSetPatternInst &MSPI) {
687 return false;
689 MSPI.eraseFromParent();
690 return true;
691}
692
693namespace {
694/// Convert loads/stores of types that the buffer intrinsics can't handle into
695/// one ore more such loads/stores that consist of legal types.
696///
697/// Do this by
698/// 1. Recursing into structs (and arrays that don't share a memory layout with
699/// vectors) since the intrinsics can't handle complex types.
700/// 2. Converting arrays of non-aggregate, byte-sized types into their
701/// corresponding vectors
702/// 3. Bitcasting unsupported types, namely overly-long scalars and byte
703/// vectors, into vectors of supported types.
704/// 4. Splitting up excessively long reads/writes into multiple operations.
705///
706/// Note that this doesn't handle complex data strucures, but, in the future,
707/// the aggregate load splitter from SROA could be refactored to allow for that
708/// case.
709///
710/// Note that, if we can prove that the initial value of the pointer offset is 0
711/// and that the load/store won't wrap from the left or won't have bounds checks
712/// that straddle a word boundary, we can emit some of the strict bounds
713/// checking pessimizations even in strict OOB mode, and we attempt to do so.
714class LegalizeBufferContentTypesVisitor
715 : public InstVisitor<LegalizeBufferContentTypesVisitor, bool> {
716 friend class InstVisitor<LegalizeBufferContentTypesVisitor, bool>;
717
719
720 const DataLayout &DL;
721
722 ScalarEvolution *SE = nullptr;
723
724 // Map base (non-GEP'd) pointers to the number of records they have, if known.
725 // If a pointer is known to have a starting offset of 0 but it wasn't known to
726 // have a number of records (ex. it was `addrspacecast` from a buffer
727 // resource), it will be present in this map, but the key will be null.
728 // Otherwise, there will be no map entry.
729 ValueToValueMapTy ZeroBasePointerToNumRecords;
730
731 // Subtarget info, needed for determining what cache control bits to set.
732 const TargetMachine *TM;
733 const GCNSubtarget *ST = nullptr;
734
735 /// If T is [N x U], where U is a scalar type, return the vector type
736 /// <N x U>, otherwise, return T.
737 Type *scalarArrayTypeAsVector(Type *MaybeArrayType);
738 Value *arrayToVector(Value *V, Type *TargetType, const Twine &Name);
739 Value *vectorToArray(Value *V, Type *OrigType, const Twine &Name);
740
741 /// Analyze how a given buffer access could be out of bounds. Used to optimize
742 /// the strict splitting used in strict bounds checking mode.
743 struct OobProperties {
744 // Offset is far enough from all-1s that we won't get wrapping around to 0.
745 bool NoWrapFromMax = false;
746 // Offset is either entirely in-bounds or entirely out of bounds.
747 bool NoPartialOOB = false;
748
749 OobProperties() = delete;
750 // Needed for some Clangs.
751 OobProperties(bool NoWrapFromMax, bool NoPartialOOB)
752 : NoWrapFromMax(NoWrapFromMax), NoPartialOOB(NoPartialOOB) {}
753 };
754 OobProperties analyzeOobProperties(Value *Ptr, Type *Ty, uint64_t ByteOffset);
755
756 /// Break up the loads of a struct into the loads of its components
757
758 /// Return the maximum allowed load/store width for the given type and
759 /// alignment combination based on subtarget flags.
760 /// 1. If unaligned accesses are not enabled, then any load/store that is less
761 /// than word-aligned has to be handled one byte or ushort at a time.
762 /// 2. If relaxed OOB mode is not set, we must ensure that the in-bounds
763 /// part of a partially out of bounds read/write is performed correctly. This
764 /// means that any load that isn't naturally aligned has to be split into
765 /// parts that are naturally aligned, so that, after bitcasting, we don't have
766 /// unaligned loads that could discard valid data.
767 ///
768 /// For example, if we're loading a <8 x i8>, that's actually a load of a <2 x
769 /// i32>, and if we load from an align(2) address, that address might be 2
770 /// bytes from the end of the buffer. The hardware will, when performing the
771 /// <2 x i32> load, mask off the entire first word, causing the two in-bounds
772 /// bytes to be masked off. However,if we know the offset can't be too close
773 /// to the number of records in the buffer (if known), we can skip this
774 /// expansion.
775 ///
776 /// Unlike the complete disablement of unaligned accesses from point 1,
777 /// this does not apply to unaligned scalars, but will apply to cases like
778 /// `load <2 x i32>, align 4` since the left elemenvt might be out of bounds.
779 /// Note that if the we know that the base offset is known to be
780 /// less than `uint32_max - byte_size(Ty)`, we can skip these alignment
781 /// checks.
782 uint64_t maxIntrinsicWidth(Type *Ty, Align A, OobProperties OobProps);
783
784 /// Convert a vector or scalar type that can't be operated on by buffer
785 /// intrinsics to one that would be legal through bitcasts and/or truncation.
786 /// Uses the wider of i32, i16, or i8 where possible, clamping to the maximum
787 /// allowed width under the alignment rules and subtarget flags.
788 Type *legalNonAggregateForMemOp(Type *T, uint64_t MaxWidth);
789 Value *makeLegalNonAggregate(Value *V, Type *TargetType, const Twine &Name);
790 Value *makeIllegalNonAggregate(Value *V, Type *OrigType, const Twine &Name);
791
792 struct VecSlice {
793 uint64_t Index = 0;
794 uint64_t Length = 0;
795 VecSlice() = delete;
796 // Needed for some Clangs
797 VecSlice(uint64_t Index, uint64_t Length) : Index(Index), Length(Length) {}
798 };
799 /// Return the [index, length] pairs into which `T` needs to be cut to form
800 /// legal buffer load or store operations. Clears `Slices`. Creates an empty
801 /// `Slices` for non-vector inputs and creates one slice if no slicing will be
802 /// needed. No slice may be larger than `MaxWidth`.
803 void getVecSlices(Type *T, uint64_t MaxWidth,
804 SmallVectorImpl<VecSlice> &Slices);
805
806 Value *extractSlice(Value *Vec, VecSlice S, const Twine &Name);
807 Value *insertSlice(Value *Whole, Value *Part, VecSlice S, const Twine &Name);
808
809 /// In most cases, return `LegalType`. However, when given an input that would
810 /// normally be a legal type for the buffer intrinsics to return but that
811 /// isn't hooked up through SelectionDAG, return a type of the same width that
812 /// can be used with the relevant intrinsics. Specifically, handle the cases:
813 /// - <1 x T> => T for all T
814 /// - <N x i8> <=> i16, i32, 2xi32, 4xi32 (as needed)
815 /// - <N x T> where T is under 32 bits and the total size is 96 bits <=> <3 x
816 /// i32>
817 Type *intrinsicTypeFor(Type *LegalType);
818
819 bool visitLoadImpl(LoadInst &OrigLI, Type *PartType,
820 SmallVectorImpl<uint32_t> &AggIdxs, uint64_t AggByteOffset,
821 Value *&Result, const Twine &Name);
822 /// Return value is (Changed, ModifiedInPlace)
823 std::pair<bool, bool> visitStoreImpl(StoreInst &OrigSI, Type *PartType,
824 SmallVectorImpl<uint32_t> &AggIdxs,
825 uint64_t AggByteOffset,
826 const Twine &Name);
827
828 bool visitInstruction(Instruction &I) { return false; }
829 bool visitLoadInst(LoadInst &LI);
830 bool visitStoreInst(StoreInst &SI);
831
832 // Record base pointer data and num_records (if known).
833 bool visitIntrinsicInst(IntrinsicInst &II);
834 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASCI);
835
836public:
837 LegalizeBufferContentTypesVisitor(const DataLayout &DL, LLVMContext &Ctx,
838 const TargetMachine *TM)
839 : IRB(Ctx, InstSimplifyFolder(DL)), DL(DL), TM(TM) {}
840 bool processFunction(Function &F, ScalarEvolution *SE);
841};
842} // namespace
843
844Type *LegalizeBufferContentTypesVisitor::scalarArrayTypeAsVector(Type *T) {
846 if (!AT)
847 return T;
848 Type *ET = AT->getElementType();
849 if (!ET->isSingleValueType() || isa<VectorType>(ET))
850 reportFatalUsageError("loading non-scalar arrays from buffer fat pointers "
851 "should have recursed");
852 if (!DL.typeSizeEqualsStoreSize(AT))
854 "loading padded arrays from buffer fat pinters should have recursed");
855 return FixedVectorType::get(ET, AT->getNumElements());
856}
857
858Value *LegalizeBufferContentTypesVisitor::arrayToVector(Value *V,
859 Type *TargetType,
860 const Twine &Name) {
861 Value *VectorRes = PoisonValue::get(TargetType);
862 auto *VT = cast<FixedVectorType>(TargetType);
863 unsigned EC = VT->getNumElements();
864 for (auto I : iota_range<unsigned>(0, EC, /*Inclusive=*/false)) {
865 Value *Elem = IRB.CreateExtractValue(V, I, Name + ".elem." + Twine(I));
866 VectorRes = IRB.CreateInsertElement(VectorRes, Elem, I,
867 Name + ".as.vec." + Twine(I));
868 }
869 return VectorRes;
870}
871
872Value *LegalizeBufferContentTypesVisitor::vectorToArray(Value *V,
873 Type *OrigType,
874 const Twine &Name) {
875 Value *ArrayRes = PoisonValue::get(OrigType);
876 ArrayType *AT = cast<ArrayType>(OrigType);
877 unsigned EC = AT->getNumElements();
878 for (auto I : iota_range<unsigned>(0, EC, /*Inclusive=*/false)) {
879 Value *Elem = IRB.CreateExtractElement(V, I, Name + ".elem." + Twine(I));
880 ArrayRes = IRB.CreateInsertValue(ArrayRes, Elem, I,
881 Name + ".as.array." + Twine(I));
882 }
883 return ArrayRes;
884}
885
886LegalizeBufferContentTypesVisitor::OobProperties
887LegalizeBufferContentTypesVisitor::analyzeOobProperties(Value *Ptr, Type *Ty,
888 uint64_t ByteOffset) {
889 OobProperties Result(false, false);
890
891 if (ST->hasRelaxedBufferOOBMode())
892 return OobProperties(true, true);
893
894 if (!SE)
895 return Result;
896 if (!SE->isSCEVable(Ptr->getType()))
897 return Result;
898 const SCEV *PtrOp = SE->getSCEV(Ptr);
899 if (ByteOffset > 0)
900 PtrOp = SE->getAddExpr(PtrOp, SE->getConstant(IRB.getInt32(ByteOffset)));
901 const auto *PtrBase = dyn_cast<SCEVUnknown>(SE->getPointerBase(PtrOp));
902 if (!PtrBase)
903 return Result;
904 Value *PtrBaseVal = PtrBase->getValue();
905 // We don't know if the offset field started at 0, so there's no safe analysis
906 // we can do. If it weren't for the fact that nuw / inbounds / ... are
907 // properties of the pointer, we might be able to use hem, but loads where the
908 // address computation for sub-parts of the loaded type wraps the address
909 // space are explicitly in scope here so there's not much we can do inside
910 // functions that can't "see" the fat pointer creation.
911 auto NumRecordsIfKnown = ZeroBasePointerToNumRecords.find(PtrBaseVal);
912 if (NumRecordsIfKnown == ZeroBasePointerToNumRecords.end())
913 return Result;
914
915 unsigned TypeSize = DL.getTypeStoreSize(Ty).getKnownMinValue();
916 const SCEV *PtrDiff = SE->getMinusSCEV(PtrOp, PtrBase);
917 APInt MaxNoWrapOffset = APInt::getAllOnes(BufferOffsetWidth) - TypeSize;
918 if (SE->isKnownNonNegative(PtrDiff) ||
919 SE->getUnsignedRangeMax(PtrDiff).ule(MaxNoWrapOffset))
920 Result.NoWrapFromMax = true;
921
922 // If we know that the pointer is zero-based but not what its upper bound is,
923 // we'll need to split up underaligned loads of small types.
924 if (!NumRecordsIfKnown->second)
925 return Result;
926 const SCEV *NumRecords = SE->getSCEV(NumRecordsIfKnown->second);
927
928 // We'll normalize all bounds to the num_records width on the hardware.
929 std::optional<unsigned> MaybeNumRecordsWidth =
931 if (!MaybeNumRecordsWidth)
932 return Result;
933 unsigned NumRecordsWidth = *MaybeNumRecordsWidth;
934 Type *NumRecordsTy = IRB.getIntNTy(NumRecordsWidth);
935 // Compare in i64 so wraparound is visible as a negative.
936 Type *CompareTy = IRB.getInt64Ty();
937 const SCEV *Bound = SE->getNoopOrZeroExtend(
938 SE->getTruncateOrZeroExtend(NumRecords, NumRecordsTy), CompareTy);
939
940 // All-1s is (per ISA or as a consequence of the bounds check rules, depending
941 // on architecture) no bounds check.
942 if (Bound == SE->getConstant(APInt::getMaxValue(NumRecordsWidth)
943 .zext(CompareTy->getIntegerBitWidth())))
944 Result.NoPartialOOB = true;
945
946 const SCEV *BoundsDiff =
947 SE->getMinusSCEV(Bound, SE->getNoopOrZeroExtend(PtrDiff, CompareTy));
948
949 if (SE->getSignedRangeMin(BoundsDiff).sge(TypeSize) ||
950 SE->isKnownNonPositive(BoundsDiff))
951 Result.NoPartialOOB = true;
952 return Result;
953}
954
956LegalizeBufferContentTypesVisitor::maxIntrinsicWidth(Type *T, Align A,
957 OobProperties OobProps) {
958 Align Result(16);
959 if (!ST->hasUnalignedBufferAccessEnabled() && A < Align(4))
960 Result = A;
961 auto *VT = dyn_cast<VectorType>(T);
962 if (!ST->hasRelaxedBufferOOBMode() && VT) {
963 TypeSize ElemBits = DL.getTypeSizeInBits(VT->getElementType());
964 if (ElemBits.isKnownMultipleOf(32)) {
965 // Word-sized operations are bounds-checked per word. So, the only case we
966 // have to worry about is stores that start out of bounds and then go in,
967 // and those can only become in-bounds on a multiple of their alignment.
968 // Therefore, we can use the declared alignment of the operation as the
969 // maximum width, rounding up to 4.
970 if (!OobProps.NoWrapFromMax)
971 Result = std::min(Result, std::max(A, Align(4)));
972 } else if ((ElemBits.isKnownMultipleOf(8) ||
973 isPowerOf2_64(ElemBits.getKnownMinValue()))) {
974 // To ensure correct behavior for sub-word types, we must always scalarize
975 // unaligned loads of sub-word types. For example, if you load
976 // a <4 x i8> from offset 7 in an 8-byte buffer, expecting the vector
977 // to be padded out with 0s after that last byte, you'll get all 0s
978 // instead. To prevent this behavior when not requested, de-vectorize such
979 // loads.
980 //
981 // If we knew that the value that triggers bounds checks was a multiple of
982 // 4 along with the access being word-aligned, we could avoid the
983 // scalarization here, as the bitcast wouldn't change any check behavior,
984 // but we don't currently try to analyze this.
985 //
986 // Strict OOB checking isn't supported if the size of each element is a
987 // non-power-of-2 value less than 8, since there's no feasible way to
988 // apply such a strict bounds check.
989 if (!OobProps.NoPartialOOB)
990 Result =
991 commonAlignment(Result, divideCeil(ElemBits.getKnownMinValue(), 8));
992 }
993 }
994 return Result.value() * 8;
995}
996
997Type *LegalizeBufferContentTypesVisitor::legalNonAggregateForMemOp(
998 Type *T, uint64_t MaxWidth) {
999 TypeSize Size = DL.getTypeStoreSizeInBits(T);
1000 // Implicitly zero-extend to the next byte if needed.
1001 if (!DL.typeSizeEqualsStoreSize(T))
1002 T = IRB.getIntNTy(Size.getFixedValue());
1003 Type *ElemTy = T->getScalarType();
1005 // Pointers are always big enough, and we'll let scalable vectors through to
1006 // fail in codegen.
1007 return T;
1008 }
1009 unsigned ElemSize = DL.getTypeSizeInBits(ElemTy).getFixedValue();
1010 if (isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= MaxWidth) {
1011 // [vectors of] anything that's 16/32/64/128 bits can be cast and split into
1012 // legal buffer operations, except that we might need to cut them into
1013 // smaller values if we're not allowed to do unaligned vector loads.
1014 return T;
1015 }
1016 Type *BestVectorElemType = nullptr;
1017 if (Size.isKnownMultipleOf(32) && MaxWidth >= 32)
1018 BestVectorElemType = IRB.getInt32Ty();
1019 else if (Size.isKnownMultipleOf(16) && MaxWidth >= 16)
1020 BestVectorElemType = IRB.getInt16Ty();
1021 else
1022 BestVectorElemType = IRB.getInt8Ty();
1023 unsigned NumCastElems =
1024 Size.getFixedValue() / BestVectorElemType->getIntegerBitWidth();
1025 if (NumCastElems == 1)
1026 return BestVectorElemType;
1027 return FixedVectorType::get(BestVectorElemType, NumCastElems);
1028}
1029
1030Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
1031 Value *V, Type *TargetType, const Twine &Name) {
1032 Type *SourceType = V->getType();
1033 TypeSize SourceSize = DL.getTypeSizeInBits(SourceType);
1034 TypeSize TargetSize = DL.getTypeSizeInBits(TargetType);
1035 if (SourceSize != TargetSize) {
1036 Type *ShortScalarTy = IRB.getIntNTy(SourceSize.getFixedValue());
1037 Type *ByteScalarTy = IRB.getIntNTy(TargetSize.getFixedValue());
1038 Value *AsScalar = IRB.CreateBitCast(V, ShortScalarTy, Name + ".as.scalar");
1039 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name + ".zext");
1040 V = Zext;
1041 SourceType = ByteScalarTy;
1042 }
1043 return IRB.CreateBitCast(V, TargetType, Name + ".legal");
1044}
1045
1046Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
1047 Value *V, Type *OrigType, const Twine &Name) {
1048 Type *LegalType = V->getType();
1049 TypeSize LegalSize = DL.getTypeSizeInBits(LegalType);
1050 TypeSize OrigSize = DL.getTypeSizeInBits(OrigType);
1051 if (LegalSize != OrigSize) {
1052 Type *ShortScalarTy = IRB.getIntNTy(OrigSize.getFixedValue());
1053 Type *ByteScalarTy = IRB.getIntNTy(LegalSize.getFixedValue());
1054 Value *AsScalar = IRB.CreateBitCast(V, ByteScalarTy, Name + ".bytes.cast");
1055 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name + ".trunc");
1056 return IRB.CreateBitCast(Trunc, OrigType, Name + ".orig");
1057 }
1058 return IRB.CreateBitCast(V, OrigType, Name + ".real.ty");
1059}
1060
1061Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(Type *LegalType) {
1062 auto *VT = dyn_cast<FixedVectorType>(LegalType);
1063 if (!VT)
1064 return LegalType;
1065 Type *ET = VT->getElementType();
1066 // Explicitly return the element type of 1-element vectors because the
1067 // underlying intrinsics don't like <1 x T> even though it's a synonym for T.
1068 if (VT->getNumElements() == 1)
1069 return ET;
1070 if (DL.getTypeSizeInBits(LegalType) == 96 && DL.getTypeSizeInBits(ET) < 32)
1071 return FixedVectorType::get(IRB.getInt32Ty(), 3);
1072 if (ET->isIntegerTy(8)) {
1073 switch (VT->getNumElements()) {
1074 default:
1075 return LegalType; // Let it crash later
1076 case 1:
1077 return IRB.getInt8Ty();
1078 case 2:
1079 return IRB.getInt16Ty();
1080 case 4:
1081 return IRB.getInt32Ty();
1082 case 8:
1083 return FixedVectorType::get(IRB.getInt32Ty(), 2);
1084 case 16:
1085 return FixedVectorType::get(IRB.getInt32Ty(), 4);
1086 }
1087 }
1088 return LegalType;
1089}
1090
1091void LegalizeBufferContentTypesVisitor::getVecSlices(
1092 Type *T, uint64_t MaxWidth, SmallVectorImpl<VecSlice> &Slices) {
1093 Slices.clear();
1094 auto *VT = dyn_cast<FixedVectorType>(T);
1095 if (!VT)
1096 return;
1097
1098 uint64_t ElemBitWidth =
1099 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
1100
1101 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
1102 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
1103 uint64_t ElemsPerWord = ElemsPer2Words / 2;
1104 uint64_t ElemsPerShort = ElemsPerWord / 2;
1105 uint64_t ElemsPerByte = ElemsPerShort / 2;
1106 // If the elements evenly pack into 32-bit words, we can use 3-word stores,
1107 // such as for <6 x bfloat> or <3 x i32>, but we can't dot his for, for
1108 // example, <3 x i64>, since that's not slicing.
1109 uint64_t ElemsPer3Words = ElemsPerWord * 3;
1110
1111 uint64_t TotalElems = VT->getNumElements();
1112 uint64_t Index = 0;
1113 auto TrySlice = [&](unsigned MaybeLen, unsigned Width) {
1114 if (MaybeLen > 0 && Width <= MaxWidth && Index + MaybeLen <= TotalElems) {
1115 VecSlice Slice{/*Index=*/Index, /*Length=*/MaybeLen};
1116 Slices.push_back(Slice);
1117 Index += MaybeLen;
1118 return true;
1119 }
1120 return false;
1121 };
1122 while (Index < TotalElems) {
1123 TrySlice(ElemsPer4Words, 128) || TrySlice(ElemsPer3Words, 96) ||
1124 TrySlice(ElemsPer2Words, 64) || TrySlice(ElemsPerWord, 32) ||
1125 TrySlice(ElemsPerShort, 16) || TrySlice(ElemsPerByte, 8);
1126 }
1127}
1128
1129Value *LegalizeBufferContentTypesVisitor::extractSlice(Value *Vec, VecSlice S,
1130 const Twine &Name) {
1131 auto *VecVT = dyn_cast<FixedVectorType>(Vec->getType());
1132 if (!VecVT)
1133 return Vec;
1134 if (S.Length == VecVT->getNumElements() && S.Index == 0)
1135 return Vec;
1136 if (S.Length == 1)
1137 return IRB.CreateExtractElement(Vec, S.Index,
1138 Name + ".slice." + Twine(S.Index));
1139 SmallVector<int> Mask = llvm::to_vector(
1140 llvm::iota_range<int>(S.Index, S.Index + S.Length, /*Inclusive=*/false));
1141 return IRB.CreateShuffleVector(Vec, Mask, Name + ".slice." + Twine(S.Index));
1142}
1143
1144Value *LegalizeBufferContentTypesVisitor::insertSlice(Value *Whole, Value *Part,
1145 VecSlice S,
1146 const Twine &Name) {
1147 auto *WholeVT = dyn_cast<FixedVectorType>(Whole->getType());
1148 if (!WholeVT)
1149 return Part;
1150 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
1151 return Part;
1152 if (S.Length == 1) {
1153 return IRB.CreateInsertElement(Whole, Part, S.Index,
1154 Name + ".slice." + Twine(S.Index));
1155 }
1156 int NumElems = cast<FixedVectorType>(Whole->getType())->getNumElements();
1157
1158 // Extend the slice with poisons to make the main shufflevector happy.
1159 SmallVector<int> ExtPartMask(NumElems, -1);
1160 for (auto [I, E] : llvm::enumerate(
1161 MutableArrayRef<int>(ExtPartMask).take_front(S.Length))) {
1162 E = I;
1163 }
1164 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
1165 Name + ".ext." + Twine(S.Index));
1166
1167 SmallVector<int> Mask =
1168 llvm::to_vector(llvm::iota_range<int>(0, NumElems, /*Inclusive=*/false));
1169 for (auto [I, E] :
1170 llvm::enumerate(MutableArrayRef<int>(Mask).slice(S.Index, S.Length)))
1171 E = I + NumElems;
1172 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
1173 Name + ".parts." + Twine(S.Index));
1174}
1175
1176bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
1177 LoadInst &OrigLI, Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1178 uint64_t AggByteOff, Value *&Result, const Twine &Name) {
1179 if (auto *ST = dyn_cast<StructType>(PartType)) {
1180 const StructLayout *Layout = DL.getStructLayout(ST);
1181 bool Changed = false;
1182 for (auto [I, ElemTy, Offset] :
1183 llvm::enumerate(ST->elements(), Layout->getMemberOffsets())) {
1184 AggIdxs.push_back(I);
1185 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1186 AggByteOff + Offset.getFixedValue(), Result,
1187 Name + "." + Twine(I));
1188 AggIdxs.pop_back();
1189 }
1190 return Changed;
1191 }
1192 if (auto *AT = dyn_cast<ArrayType>(PartType)) {
1193 Type *ElemTy = AT->getElementType();
1194 if (!ElemTy->isSingleValueType() || !DL.typeSizeEqualsStoreSize(ElemTy) ||
1195 ElemTy->isVectorTy()) {
1196 TypeSize ElemAllocSize = DL.getTypeAllocSize(ElemTy);
1197 bool Changed = false;
1198 for (auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1199 /*Inclusive=*/false)) {
1200 AggIdxs.push_back(I);
1201 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1202 AggByteOff + I * ElemAllocSize.getFixedValue(),
1203 Result, Name + Twine(I));
1204 AggIdxs.pop_back();
1205 }
1206 return Changed;
1207 }
1208 }
1209
1210 // Typical case
1211
1212 Align PartAlign = commonAlignment(OrigLI.getAlign(), AggByteOff);
1213 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1214 OobProperties OobProps =
1215 analyzeOobProperties(OrigLI.getPointerOperand(), PartType, AggByteOff);
1216 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1217 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1218
1219 SmallVector<VecSlice> Slices;
1220 getVecSlices(LegalType, MaxWidth, Slices);
1221 bool HasSlices = Slices.size() > 1;
1222 bool IsAggPart = !AggIdxs.empty();
1223 Value *LoadsRes;
1224 if (!HasSlices && !IsAggPart) {
1225 Type *LoadableType = intrinsicTypeFor(LegalType);
1226 if (LoadableType == PartType)
1227 return false;
1228
1229 IRB.SetInsertPoint(&OrigLI);
1230 auto *NLI = cast<LoadInst>(OrigLI.clone());
1231 NLI->mutateType(LoadableType);
1232 NLI = IRB.Insert(NLI);
1233 NLI->setName(Name + ".loadable");
1234
1235 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name + ".from.loadable");
1236 } else {
1237 IRB.SetInsertPoint(&OrigLI);
1238 LoadsRes = PoisonValue::get(LegalType);
1239 Value *OrigPtr = OrigLI.getPointerOperand();
1240 // If we're needing to spill something into more than one load, its legal
1241 // type will be a vector (ex. an i256 load will have LegalType = <8 x i32>).
1242 // But if we're already a scalar (which can happen if we're splitting up a
1243 // struct), the element type will be the legal type itself.
1244 Type *ElemType = LegalType->getScalarType();
1245 unsigned ElemBytes = DL.getTypeStoreSize(ElemType);
1246 AAMDNodes AANodes = OrigLI.getAAMetadata();
1247 if (IsAggPart && Slices.empty())
1248 Slices.push_back(VecSlice{/*Index=*/0, /*Length=*/1});
1249 for (VecSlice S : Slices) {
1250 Type *SliceType =
1251 S.Length != 1 ? FixedVectorType::get(ElemType, S.Length) : ElemType;
1252 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1253 // You can't reasonably expect loads to wrap around the edge of memory.
1254 Value *NewPtr = IRB.CreateGEP(
1255 IRB.getInt8Ty(), OrigLI.getPointerOperand(), IRB.getInt32(ByteOffset),
1256 OrigPtr->getName() + ".off.ptr." + Twine(ByteOffset),
1259 Type *LoadableType = intrinsicTypeFor(SliceType);
1260 LoadInst *NewLI = IRB.CreateAlignedLoad(
1261 LoadableType, NewPtr, commonAlignment(OrigLI.getAlign(), ByteOffset),
1262 Name + ".off." + Twine(ByteOffset));
1263 copyMetadataForLoad(*NewLI, OrigLI);
1264 NewLI->setAAMetadata(
1265 AANodes.adjustForAccess(ByteOffset, LoadableType, DL));
1266 NewLI->setAtomic(OrigLI.getOrdering(), OrigLI.getSyncScopeID());
1267 NewLI->setVolatile(OrigLI.isVolatile());
1268 Value *Loaded = IRB.CreateBitCast(NewLI, SliceType,
1269 NewLI->getName() + ".from.loadable");
1270 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1271 }
1272 }
1273 if (LegalType != ArrayAsVecType)
1274 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1275 if (ArrayAsVecType != PartType)
1276 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1277
1278 if (IsAggPart)
1279 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1280 else
1281 Result = LoadsRes;
1282 return true;
1283}
1284
1285bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1287 return false;
1288
1289 SmallVector<uint32_t> AggIdxs;
1290 Type *OrigType = LI.getType();
1291 Value *Result = PoisonValue::get(OrigType);
1292 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.getName());
1293 if (!Changed)
1294 return false;
1295 Result->takeName(&LI);
1296 LI.replaceAllUsesWith(Result);
1297 LI.eraseFromParent();
1298 return Changed;
1299}
1300
1301std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1302 StoreInst &OrigSI, Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1303 uint64_t AggByteOff, const Twine &Name) {
1304 if (auto *ST = dyn_cast<StructType>(PartType)) {
1305 const StructLayout *Layout = DL.getStructLayout(ST);
1306 bool Changed = false;
1307 for (auto [I, ElemTy, Offset] :
1308 llvm::enumerate(ST->elements(), Layout->getMemberOffsets())) {
1309 AggIdxs.push_back(I);
1310 Changed |= std::get<0>(visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1311 AggByteOff + Offset.getFixedValue(),
1312 Name + "." + Twine(I)));
1313 AggIdxs.pop_back();
1314 }
1315 return std::make_pair(Changed, /*ModifiedInPlace=*/false);
1316 }
1317 if (auto *AT = dyn_cast<ArrayType>(PartType)) {
1318 Type *ElemTy = AT->getElementType();
1319 if (!ElemTy->isSingleValueType() || !DL.typeSizeEqualsStoreSize(ElemTy) ||
1320 ElemTy->isVectorTy()) {
1321 TypeSize ElemAllocSize = DL.getTypeAllocSize(ElemTy);
1322 bool Changed = false;
1323 for (auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1324 /*Inclusive=*/false)) {
1325 AggIdxs.push_back(I);
1326 Changed |= std::get<0>(visitStoreImpl(
1327 OrigSI, ElemTy, AggIdxs,
1328 AggByteOff + I * ElemAllocSize.getFixedValue(), Name + Twine(I)));
1329 AggIdxs.pop_back();
1330 }
1331 return std::make_pair(Changed, /*ModifiedInPlace=*/false);
1332 }
1333 }
1334
1335 Value *OrigData = OrigSI.getValueOperand();
1336 Value *NewData = OrigData;
1337
1338 bool IsAggPart = !AggIdxs.empty();
1339 if (IsAggPart)
1340 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1341
1342 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1343 if (ArrayAsVecType != PartType) {
1344 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1345 }
1346
1347 Align PartAlign = commonAlignment(OrigSI.getAlign(), AggByteOff);
1348 OobProperties OobProps =
1349 analyzeOobProperties(OrigSI.getPointerOperand(), PartType, AggByteOff);
1350 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1351 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1352 if (LegalType != ArrayAsVecType) {
1353 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1354 }
1355
1356 SmallVector<VecSlice> Slices;
1357 getVecSlices(LegalType, MaxWidth, Slices);
1358 bool NeedToSplit = Slices.size() > 1 || IsAggPart;
1359 if (!NeedToSplit) {
1360 Type *StorableType = intrinsicTypeFor(LegalType);
1361 if (StorableType == PartType)
1362 return std::make_pair(/*Changed=*/false, /*ModifiedInPlace=*/false);
1363 NewData = IRB.CreateBitCast(NewData, StorableType, Name + ".storable");
1364 OrigSI.setOperand(0, NewData);
1365 return std::make_pair(/*Changed=*/true, /*ModifiedInPlace=*/true);
1366 }
1367
1368 Value *OrigPtr = OrigSI.getPointerOperand();
1369 Type *ElemType = LegalType->getScalarType();
1370 if (IsAggPart && Slices.empty())
1371 Slices.push_back(VecSlice{/*Index=*/0, /*Length=*/1});
1372 unsigned ElemBytes = DL.getTypeStoreSize(ElemType);
1373 AAMDNodes AANodes = OrigSI.getAAMetadata();
1374 for (VecSlice S : Slices) {
1375 Type *SliceType =
1376 S.Length != 1 ? FixedVectorType::get(ElemType, S.Length) : ElemType;
1377 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1378 Value *NewPtr = IRB.CreateGEP(
1379 IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1380 OrigPtr->getName() + ".part." + Twine(S.Index),
1383 Value *DataSlice = extractSlice(NewData, S, Name);
1384 Type *StorableType = intrinsicTypeFor(SliceType);
1385 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1386 DataSlice->getName() + ".storable");
1387 auto *NewSI = cast<StoreInst>(OrigSI.clone());
1388 NewSI->setAlignment(commonAlignment(OrigSI.getAlign(), ByteOffset));
1389 IRB.Insert(NewSI);
1390 NewSI->setOperand(0, DataSlice);
1391 NewSI->setOperand(1, NewPtr);
1392 NewSI->setAAMetadata(AANodes.adjustForAccess(ByteOffset, StorableType, DL));
1393 }
1394 return std::make_pair(/*Changed=*/true, /*ModifiedInPlace=*/false);
1395}
1396
1397bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1398 if (SI.getPointerAddressSpace() != AMDGPUAS::BUFFER_FAT_POINTER)
1399 return false;
1400 IRB.SetInsertPoint(&SI);
1401 SmallVector<uint32_t> AggIdxs;
1402 Value *OrigData = SI.getValueOperand();
1403 auto [Changed, ModifiedInPlace] =
1404 visitStoreImpl(SI, OrigData->getType(), AggIdxs, 0, OrigData->getName());
1405 if (Changed && !ModifiedInPlace)
1406 SI.eraseFromParent();
1407 return Changed;
1408}
1409
1410bool LegalizeBufferContentTypesVisitor::visitAddrSpaceCastInst(
1411 AddrSpaceCastInst &AI) {
1414 return false;
1415 Value *Src = AI.getPointerOperand();
1416 auto Record = ZeroBasePointerToNumRecords.find(Src);
1417 if (Record != ZeroBasePointerToNumRecords.end())
1418 ZeroBasePointerToNumRecords.insert({&AI, Record->second});
1419 else
1420 ZeroBasePointerToNumRecords.insert({&AI, nullptr});
1421 return false;
1422}
1423
1424bool LegalizeBufferContentTypesVisitor::visitIntrinsicInst(IntrinsicInst &II) {
1425 if (II.getIntrinsicID() != Intrinsic::amdgcn_make_buffer_rsrc)
1426 return false;
1427 ZeroBasePointerToNumRecords.insert({&II, II.getOperand(2)});
1428 return false;
1429}
1430
1431bool LegalizeBufferContentTypesVisitor::processFunction(Function &F,
1432 ScalarEvolution *SE) {
1433 this->SE = SE;
1434 ST = &TM->getSubtarget<GCNSubtarget>(F);
1435 bool Changed = false;
1436 for (Instruction &I : make_early_inc_range(instructions(F))) {
1437 Changed |= visit(I);
1438 }
1439 ZeroBasePointerToNumRecords.clear();
1440 this->SE = nullptr;
1441 return Changed;
1442}
1443
1444/// Return the ptr addrspace(8) and i32 (resource and offset parts) in a lowered
1445/// buffer fat pointer constant.
1446static std::pair<Constant *, Constant *>
1448 assert(isSplitFatPtr(C->getType()) && "Not a split fat buffer pointer");
1449 return std::make_pair(C->getAggregateElement(0u), C->getAggregateElement(1u));
1450}
1451
1452namespace {
1453/// Handle the remapping of ptr addrspace(7) constants.
1454class FatPtrConstMaterializer final : public ValueMaterializer {
1455 BufferFatPtrToStructTypeMap *TypeMap;
1456 // An internal mapper that is used to recurse into the arguments of constants.
1457 // While the documentation for `ValueMapper` specifies not to use it
1458 // recursively, examination of the logic in mapValue() shows that it can
1459 // safely be used recursively when handling constants, like it does in its own
1460 // logic.
1461 ValueMapper InternalMapper;
1462
1463 Constant *materializeBufferFatPtrConst(Constant *C);
1464
1465public:
1466 // UnderlyingMap is the value map this materializer will be filling.
1467 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1468 ValueToValueMapTy &UnderlyingMap)
1469 : TypeMap(TypeMap),
1470 InternalMapper(UnderlyingMap, RF_None, TypeMap, this) {}
1471 ~FatPtrConstMaterializer() = default;
1472
1473 Value *materialize(Value *V) override;
1474};
1475} // namespace
1476
1477Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *C) {
1478 Type *SrcTy = C->getType();
1479 auto *NewTy = dyn_cast<StructType>(TypeMap->remapType(SrcTy));
1480 if (C->isNullValue())
1481 return ConstantAggregateZero::getNullValue(NewTy);
1482 if (isa<PoisonValue>(C)) {
1483 return ConstantStruct::get(NewTy,
1484 {PoisonValue::get(NewTy->getElementType(0)),
1485 PoisonValue::get(NewTy->getElementType(1))});
1486 }
1487 if (isa<UndefValue>(C)) {
1488 return ConstantStruct::get(NewTy,
1489 {UndefValue::get(NewTy->getElementType(0)),
1490 UndefValue::get(NewTy->getElementType(1))});
1491 }
1492
1493 if (auto *VC = dyn_cast<ConstantVector>(C)) {
1494 if (Constant *S = VC->getSplatValue()) {
1495 Constant *NewS = InternalMapper.mapConstant(*S);
1496 if (!NewS)
1497 return nullptr;
1498 auto [Rsrc, Off] = splitLoweredFatBufferConst(NewS);
1499 auto EC = VC->getType()->getElementCount();
1500 return ConstantStruct::get(NewTy, {ConstantVector::getSplat(EC, Rsrc),
1501 ConstantVector::getSplat(EC, Off)});
1502 }
1505 for (Value *Op : VC->operand_values()) {
1506 auto *NewOp = dyn_cast_or_null<Constant>(InternalMapper.mapValue(*Op));
1507 if (!NewOp)
1508 return nullptr;
1509 auto [Rsrc, Off] = splitLoweredFatBufferConst(NewOp);
1510 Rsrcs.push_back(Rsrc);
1511 Offs.push_back(Off);
1512 }
1513 Constant *RsrcVec = ConstantVector::get(Rsrcs);
1514 Constant *OffVec = ConstantVector::get(Offs);
1515 return ConstantStruct::get(NewTy, {RsrcVec, OffVec});
1516 }
1517
1518 if (isa<GlobalValue>(C))
1519 reportFatalUsageError("global values containing ptr addrspace(7) (buffer "
1520 "fat pointer) values are not supported");
1521
1522 if (isa<ConstantExpr>(C))
1524 "constant exprs containing ptr addrspace(7) (buffer "
1525 "fat pointer) values should have been expanded earlier");
1526
1527 return nullptr;
1528}
1529
1530Value *FatPtrConstMaterializer::materialize(Value *V) {
1532 if (!C)
1533 return nullptr;
1534 // Structs and other types that happen to contain fat pointers get remapped
1535 // by the mapValue() logic.
1536 if (!isBufferFatPtrConst(C))
1537 return nullptr;
1538 return materializeBufferFatPtrConst(C);
1539}
1540
1541using PtrParts = std::pair<Value *, Value *>;
1542namespace {
1543// The visitor returns the resource and offset parts for an instruction if they
1544// can be computed, or (nullptr, nullptr) for cases that don't have a meaningful
1545// value mapping.
1546class SplitPtrStructs : public InstVisitor<SplitPtrStructs, PtrParts> {
1547 ValueToValueMapTy RsrcParts;
1548 ValueToValueMapTy OffParts;
1549
1550 // Track instructions that have been rewritten into a user of the component
1551 // parts of their ptr addrspace(7) input. Instructions that produced
1552 // ptr addrspace(7) parts should **not** be RAUW'd before being added to this
1553 // set, as that replacement will be handled in a post-visit step. However,
1554 // instructions that yield values that aren't fat pointers (ex. ptrtoint)
1555 // should RAUW themselves with new instructions that use the split parts
1556 // of their arguments during processing.
1557 DenseSet<Instruction *> SplitUsers;
1558
1559 // Nodes that need a second look once we've computed the parts for all other
1560 // instructions to see if, for example, we really need to phi on the resource
1561 // part.
1562 SmallVector<Instruction *> Conditionals;
1563 // Temporary instructions produced while lowering conditionals that should be
1564 // killed.
1565 SmallVector<Instruction *> ConditionalTemps;
1566
1567 // Subtarget info, needed for determining what cache control bits to set.
1568 const TargetMachine *TM;
1569 const GCNSubtarget *ST = nullptr;
1570
1572
1573 // Copy metadata between instructions if applicable.
1574 void copyMetadata(Value *Dest, Value *Src);
1575
1576 // Get the resource and offset parts of the value V, inserting appropriate
1577 // extractvalue calls if needed.
1578 PtrParts getPtrParts(Value *V);
1579
1580 // Given an instruction that could produce multiple resource parts (a PHI or
1581 // select), collect the set of possible instructions that could have provided
1582 // its resource parts that it could have (the `Roots`) and the set of
1583 // conditional instructions visited during the search (`Seen`). If, after
1584 // removing the root of the search from `Seen` and `Roots`, `Seen` is a subset
1585 // of `Roots` and `Roots - Seen` contains one element, the resource part of
1586 // that element can replace the resource part of all other elements in `Seen`.
1587 void getPossibleRsrcRoots(Instruction *I, SmallPtrSetImpl<Value *> &Roots,
1589 void processConditionals();
1590
1591 // If an instruction hav been split into resource and offset parts,
1592 // delete that instruction. If any of its uses have not themselves been split
1593 // into parts (for example, an insertvalue), construct the structure
1594 // that the type rewrites declared should be produced by the dying instruction
1595 // and use that.
1596 // Also, kill the temporary extractvalue operations produced by the two-stage
1597 // lowering of PHIs and conditionals.
1598 void killAndReplaceSplitInstructions(SmallVectorImpl<Instruction *> &Origs);
1599
1600 void setAlign(CallInst *Intr, Align A, unsigned RsrcArgIdx);
1601 void insertPreMemOpFence(AtomicOrdering Order, SyncScope::ID SSID);
1602 void insertPostMemOpFence(AtomicOrdering Order, SyncScope::ID SSID);
1603 Value *handleMemoryInst(Instruction *I, Value *Arg, Value *Ptr, Type *Ty,
1604 Align Alignment, AtomicOrdering Order,
1605 bool IsVolatile, SyncScope::ID SSID);
1606
1607public:
1608 SplitPtrStructs(const DataLayout &DL, LLVMContext &Ctx,
1609 const TargetMachine *TM)
1610 : TM(TM), IRB(Ctx, InstSimplifyFolder(DL)) {}
1611
1612 void processFunction(Function &F);
1613
1614 PtrParts visitInstruction(Instruction &I);
1615 PtrParts visitLoadInst(LoadInst &LI);
1616 PtrParts visitStoreInst(StoreInst &SI);
1617 PtrParts visitAtomicRMWInst(AtomicRMWInst &AI);
1618 PtrParts visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI);
1619 PtrParts visitGetElementPtrInst(GetElementPtrInst &GEP);
1620
1621 PtrParts visitPtrToAddrInst(PtrToAddrInst &PA);
1622 PtrParts visitPtrToIntInst(PtrToIntInst &PI);
1623 PtrParts visitIntToPtrInst(IntToPtrInst &IP);
1624 PtrParts visitAddrSpaceCastInst(AddrSpaceCastInst &I);
1625 PtrParts visitICmpInst(ICmpInst &Cmp);
1626 PtrParts visitFreezeInst(FreezeInst &I);
1627
1628 PtrParts visitExtractElementInst(ExtractElementInst &I);
1629 PtrParts visitInsertElementInst(InsertElementInst &I);
1630 PtrParts visitShuffleVectorInst(ShuffleVectorInst &I);
1631
1632 PtrParts visitPHINode(PHINode &PHI);
1633 PtrParts visitSelectInst(SelectInst &SI);
1634
1635 PtrParts visitIntrinsicInst(IntrinsicInst &II);
1636};
1637} // namespace
1638
1639void SplitPtrStructs::copyMetadata(Value *Dest, Value *Src) {
1640 auto *DestI = dyn_cast<Instruction>(Dest);
1641 auto *SrcI = dyn_cast<Instruction>(Src);
1642
1643 if (!DestI || !SrcI)
1644 return;
1645
1646 DestI->copyMetadata(*SrcI);
1647}
1648
1649PtrParts SplitPtrStructs::getPtrParts(Value *V) {
1650 assert(isSplitFatPtr(V->getType()) && "it's not meaningful to get the parts "
1651 "of something that wasn't rewritten");
1652 auto *RsrcEntry = &RsrcParts[V];
1653 auto *OffEntry = &OffParts[V];
1654 if (*RsrcEntry && *OffEntry)
1655 return {*RsrcEntry, *OffEntry};
1656
1657 if (auto *C = dyn_cast<Constant>(V)) {
1658 auto [Rsrc, Off] = splitLoweredFatBufferConst(C);
1659 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1660 }
1661
1662 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1663 if (auto *I = dyn_cast<Instruction>(V)) {
1664 LLVM_DEBUG(dbgs() << "Recursing to split parts of " << *I << "\n");
1665 auto [Rsrc, Off] = visit(*I);
1666 if (Rsrc && Off)
1667 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1668 // We'll be creating the new values after the relevant instruction.
1669 // This instruction generates a value and so isn't a terminator.
1670 IRB.SetInsertPoint(*I->getInsertionPointAfterDef());
1671 IRB.SetCurrentDebugLocation(I->getDebugLoc());
1672 } else if (auto *A = dyn_cast<Argument>(V)) {
1673 IRB.SetInsertPointPastAllocas(A->getParent());
1674 IRB.SetCurrentDebugLocation(DebugLoc());
1675 }
1676 Value *Rsrc = IRB.CreateExtractValue(V, 0, V->getName() + ".rsrc");
1677 Value *Off = IRB.CreateExtractValue(V, 1, V->getName() + ".off");
1678 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1679}
1680
1681/// Returns the instruction that defines the resource part of the value V.
1682/// Note that this is not getUnderlyingObject(), since that looks through
1683/// operations like ptrmask which might modify the resource part.
1684///
1685/// We can limit ourselves to just looking through GEPs followed by looking
1686/// through addrspacecasts because only those two operations preserve the
1687/// resource part, and because operations on an `addrspace(8)` (which is the
1688/// legal input to this addrspacecast) would produce a different resource part.
1690 while (auto *GEP = dyn_cast<GEPOperator>(V))
1691 V = GEP->getPointerOperand();
1692 while (auto *ASC = dyn_cast<AddrSpaceCastOperator>(V))
1693 V = ASC->getPointerOperand();
1694 return V;
1695}
1696
1697void SplitPtrStructs::getPossibleRsrcRoots(Instruction *I,
1698 SmallPtrSetImpl<Value *> &Roots,
1699 SmallPtrSetImpl<Value *> &Seen) {
1700 if (auto *PHI = dyn_cast<PHINode>(I)) {
1701 if (!Seen.insert(I).second)
1702 return;
1703 for (Value *In : PHI->incoming_values()) {
1704 In = rsrcPartRoot(In);
1705 Roots.insert(In);
1707 getPossibleRsrcRoots(cast<Instruction>(In), Roots, Seen);
1708 }
1709 } else if (auto *SI = dyn_cast<SelectInst>(I)) {
1710 if (!Seen.insert(SI).second)
1711 return;
1712 Value *TrueVal = rsrcPartRoot(SI->getTrueValue());
1713 Value *FalseVal = rsrcPartRoot(SI->getFalseValue());
1714 Roots.insert(TrueVal);
1715 Roots.insert(FalseVal);
1716 if (isa<PHINode, SelectInst>(TrueVal))
1717 getPossibleRsrcRoots(cast<Instruction>(TrueVal), Roots, Seen);
1718 if (isa<PHINode, SelectInst>(FalseVal))
1719 getPossibleRsrcRoots(cast<Instruction>(FalseVal), Roots, Seen);
1720 } else {
1721 llvm_unreachable("getPossibleRsrcParts() only works on phi and select");
1722 }
1723}
1724
1725void SplitPtrStructs::processConditionals() {
1726 SmallDenseMap<Value *, Value *> FoundRsrcs;
1727 SmallPtrSet<Value *, 4> Roots;
1728 SmallPtrSet<Value *, 4> Seen;
1729 for (Instruction *I : Conditionals) {
1730 // These have to exist by now because we've visited these nodes.
1731 Value *Rsrc = RsrcParts[I];
1732 Value *Off = OffParts[I];
1733 assert(Rsrc && Off && "must have visited conditionals by now");
1734
1735 std::optional<Value *> MaybeRsrc;
1736 auto MaybeFoundRsrc = FoundRsrcs.find(I);
1737 if (MaybeFoundRsrc != FoundRsrcs.end()) {
1738 MaybeRsrc = MaybeFoundRsrc->second;
1739 } else {
1740 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1741 Roots.clear();
1742 Seen.clear();
1743 getPossibleRsrcRoots(I, Roots, Seen);
1744 LLVM_DEBUG(dbgs() << "Processing conditional: " << *I << "\n");
1745#ifndef NDEBUG
1746 for (Value *V : Roots)
1747 LLVM_DEBUG(dbgs() << "Root: " << *V << "\n");
1748 for (Value *V : Seen)
1749 LLVM_DEBUG(dbgs() << "Seen: " << *V << "\n");
1750#endif
1751 // If we are our own possible root, then we shouldn't block our
1752 // replacement with a valid incoming value.
1753 Roots.erase(I);
1754 // We don't want to block the optimization for conditionals that don't
1755 // refer to themselves but did see themselves during the traversal.
1756 Seen.erase(I);
1757
1758 if (set_is_subset(Seen, Roots)) {
1759 auto Diff = set_difference(Roots, Seen);
1760 if (Diff.size() == 1) {
1761 Value *RootVal = *Diff.begin();
1762 // Handle the case where previous loops already looked through
1763 // an addrspacecast.
1764 if (isSplitFatPtr(RootVal->getType()))
1765 MaybeRsrc = std::get<0>(getPtrParts(RootVal));
1766 else
1767 MaybeRsrc = RootVal;
1768 }
1769 }
1770 }
1771
1772 if (auto *PHI = dyn_cast<PHINode>(I)) {
1773 Value *NewRsrc;
1774 StructType *PHITy = cast<StructType>(PHI->getType());
1775 IRB.SetInsertPoint(*PHI->getInsertionPointAfterDef());
1776 IRB.SetCurrentDebugLocation(PHI->getDebugLoc());
1777 if (MaybeRsrc) {
1778 NewRsrc = *MaybeRsrc;
1779 } else {
1780 Type *RsrcTy = PHITy->getElementType(0);
1781 auto *RsrcPHI = IRB.CreatePHI(RsrcTy, PHI->getNumIncomingValues());
1782 RsrcPHI->takeName(Rsrc);
1783 for (auto [V, BB] : llvm::zip(PHI->incoming_values(), PHI->blocks())) {
1784 Value *VRsrc = std::get<0>(getPtrParts(V));
1785 RsrcPHI->addIncoming(VRsrc, BB);
1786 }
1787 copyMetadata(RsrcPHI, PHI);
1788 NewRsrc = RsrcPHI;
1789 }
1790
1791 Type *OffTy = PHITy->getElementType(1);
1792 auto *NewOff = IRB.CreatePHI(OffTy, PHI->getNumIncomingValues());
1793 NewOff->takeName(Off);
1794 for (auto [V, BB] : llvm::zip(PHI->incoming_values(), PHI->blocks())) {
1795 assert(OffParts.count(V) && "An offset part had to be created by now");
1796 Value *VOff = std::get<1>(getPtrParts(V));
1797 NewOff->addIncoming(VOff, BB);
1798 }
1799 copyMetadata(NewOff, PHI);
1800
1801 // Note: We don't eraseFromParent() the temporaries because we don't want
1802 // to put the corrections maps in an inconstent state. That'll be handed
1803 // during the rest of the killing. Also, `ValueToValueMapTy` guarantees
1804 // that references in that map will be updated as well.
1805 // Note that if the temporary instruction got `InstSimplify`'d away, it
1806 // might be something like a block argument.
1807 if (auto *RsrcInst = dyn_cast<Instruction>(Rsrc)) {
1808 ConditionalTemps.push_back(RsrcInst);
1809 RsrcInst->replaceAllUsesWith(NewRsrc);
1810 }
1811 if (auto *OffInst = dyn_cast<Instruction>(Off)) {
1812 ConditionalTemps.push_back(OffInst);
1813 OffInst->replaceAllUsesWith(NewOff);
1814 }
1815
1816 // Save on recomputing the cycle traversals in known-root cases.
1817 if (MaybeRsrc)
1818 for (Value *V : Seen)
1819 FoundRsrcs[V] = NewRsrc;
1820 } else if (isa<SelectInst>(I)) {
1821 if (MaybeRsrc) {
1822 if (auto *RsrcInst = dyn_cast<Instruction>(Rsrc)) {
1823 // Guard against conditionals that were already folded away.
1824 if (RsrcInst != *MaybeRsrc) {
1825 ConditionalTemps.push_back(RsrcInst);
1826 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1827 }
1828 }
1829 for (Value *V : Seen)
1830 FoundRsrcs[V] = *MaybeRsrc;
1831 }
1832 } else {
1833 llvm_unreachable("Only PHIs and selects go in the conditionals list");
1834 }
1835 }
1836}
1837
1838void SplitPtrStructs::killAndReplaceSplitInstructions(
1839 SmallVectorImpl<Instruction *> &Origs) {
1840 for (Instruction *I : ConditionalTemps)
1841 I->eraseFromParent();
1842
1843 for (Instruction *I : Origs) {
1844 if (!SplitUsers.contains(I))
1845 continue;
1846
1848 findDbgValues(I, Dbgs);
1849 for (DbgVariableRecord *Dbg : Dbgs) {
1850 auto &DL = I->getDataLayout();
1851 assert(isSplitFatPtr(I->getType()) &&
1852 "We should've RAUW'd away loads, stores, etc. at this point");
1853 DbgVariableRecord *OffDbg = Dbg->clone();
1854 auto [Rsrc, Off] = getPtrParts(I);
1855
1856 int64_t RsrcSz = DL.getTypeSizeInBits(Rsrc->getType());
1857 int64_t OffSz = DL.getTypeSizeInBits(Off->getType());
1858
1859 std::optional<DIExpression *> RsrcExpr =
1860 DIExpression::createFragmentExpression(Dbg->getExpression(), 0,
1861 RsrcSz);
1862 std::optional<DIExpression *> OffExpr =
1863 DIExpression::createFragmentExpression(Dbg->getExpression(), RsrcSz,
1864 OffSz);
1865 if (OffExpr) {
1866 OffDbg->setExpression(*OffExpr);
1867 OffDbg->replaceVariableLocationOp(I, Off);
1868 OffDbg->insertBefore(Dbg);
1869 } else {
1870 OffDbg->eraseFromParent();
1871 }
1872 if (RsrcExpr) {
1873 Dbg->setExpression(*RsrcExpr);
1874 Dbg->replaceVariableLocationOp(I, Rsrc);
1875 } else {
1876 Dbg->replaceVariableLocationOp(I, PoisonValue::get(I->getType()));
1877 }
1878 }
1879
1880 Value *Poison = PoisonValue::get(I->getType());
1881 I->replaceUsesWithIf(Poison, [&](const Use &U) -> bool {
1882 if (const auto *UI = dyn_cast<Instruction>(U.getUser()))
1883 return SplitUsers.contains(UI);
1884 return false;
1885 });
1886
1887 if (I->use_empty()) {
1888 I->eraseFromParent();
1889 continue;
1890 }
1891 IRB.SetInsertPoint(*I->getInsertionPointAfterDef());
1892 IRB.SetCurrentDebugLocation(I->getDebugLoc());
1893 auto [Rsrc, Off] = getPtrParts(I);
1894 Value *Struct = PoisonValue::get(I->getType());
1895 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1896 Struct = IRB.CreateInsertValue(Struct, Off, 1);
1897 copyMetadata(Struct, I);
1898 Struct->takeName(I);
1899 I->replaceAllUsesWith(Struct);
1900 I->eraseFromParent();
1901 }
1902}
1903
1904void SplitPtrStructs::setAlign(CallInst *Intr, Align A, unsigned RsrcArgIdx) {
1905 LLVMContext &Ctx = Intr->getContext();
1906 Intr->addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx, A));
1907}
1908
1909void SplitPtrStructs::insertPreMemOpFence(AtomicOrdering Order,
1910 SyncScope::ID SSID) {
1911 switch (Order) {
1912 case AtomicOrdering::Release:
1913 case AtomicOrdering::AcquireRelease:
1914 case AtomicOrdering::SequentiallyConsistent:
1915 IRB.CreateFence(AtomicOrdering::Release, SSID);
1916 break;
1917 default:
1918 break;
1919 }
1920}
1921
1922void SplitPtrStructs::insertPostMemOpFence(AtomicOrdering Order,
1923 SyncScope::ID SSID) {
1924 switch (Order) {
1925 case AtomicOrdering::Acquire:
1926 case AtomicOrdering::AcquireRelease:
1927 case AtomicOrdering::SequentiallyConsistent:
1928 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1929 break;
1930 default:
1931 break;
1932 }
1933}
1934
1935Value *SplitPtrStructs::handleMemoryInst(Instruction *I, Value *Arg, Value *Ptr,
1936 Type *Ty, Align Alignment,
1937 AtomicOrdering Order, bool IsVolatile,
1938 SyncScope::ID SSID) {
1939 IRB.SetInsertPoint(I);
1940
1941 auto [Rsrc, Off] = getPtrParts(Ptr);
1943 if (Arg)
1944 Args.push_back(Arg);
1945 Args.push_back(Rsrc);
1946 Args.push_back(Off);
1947 insertPreMemOpFence(Order, SSID);
1948 // soffset is always 0 for these cases, where we always want any offset to be
1949 // part of bounds checking and we don't know which parts of the GEPs is
1950 // uniform.
1951 Args.push_back(IRB.getInt32(0));
1952
1953 uint32_t Aux = 0;
1954 if (IsVolatile)
1956 Args.push_back(IRB.getInt32(Aux));
1957
1959 if (isa<LoadInst>(I))
1960 IID = Order == AtomicOrdering::NotAtomic
1961 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1962 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1963 else if (isa<StoreInst>(I))
1964 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1965 else if (auto *RMW = dyn_cast<AtomicRMWInst>(I)) {
1966 switch (RMW->getOperation()) {
1968 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1969 break;
1970 case AtomicRMWInst::Add:
1971 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1972 break;
1973 case AtomicRMWInst::Sub:
1974 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1975 break;
1976 case AtomicRMWInst::And:
1977 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1978 break;
1979 case AtomicRMWInst::Or:
1980 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1981 break;
1982 case AtomicRMWInst::Xor:
1983 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1984 break;
1985 case AtomicRMWInst::Max:
1986 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1987 break;
1988 case AtomicRMWInst::Min:
1989 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1990 break;
1992 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1993 break;
1995 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1996 break;
1998 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
1999 break;
2001 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
2002 break;
2004 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
2005 break;
2007 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
2008 break;
2010 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
2011 break;
2012 case AtomicRMWInst::FSub: {
2014 "atomic floating point subtraction not supported for "
2015 "buffer resources and should've been expanded away");
2016 break;
2017 }
2020 "atomic floating point fmaximum not supported for "
2021 "buffer resources and should've been expanded away");
2022 break;
2023 }
2026 "atomic floating point fminimum not supported for "
2027 "buffer resources and should've been expanded away");
2028 break;
2029 }
2032 "atomic floating point fmaximumnum not supported for "
2033 "buffer resources and should've been expanded away");
2034 break;
2035 }
2038 "atomic floating point fminimumnum not supported for "
2039 "buffer resources and should've been expanded away");
2040 break;
2041 }
2044 "atomic nand not supported for buffer resources and "
2045 "should've been expanded away");
2046 break;
2050 "wrapping increment/decrement not supported for "
2051 "buffer resources and should've been expanded away");
2052 break;
2054 llvm_unreachable("Not sure how we got a bad binop");
2055 }
2056 }
2057
2058 CallInst *Call = IRB.CreateIntrinsicWithoutFolding(IID, Ty, Args);
2059 copyMetadata(Call, I);
2060 setAlign(Call, Alignment, Arg ? 1 : 0);
2061 Call->takeName(I);
2062
2063 insertPostMemOpFence(Order, SSID);
2064 // The "no moving p7 directly" rewrites ensure that this load or store won't
2065 // itself need to be split into parts.
2066 SplitUsers.insert(I);
2067 I->replaceAllUsesWith(Call);
2068 return Call;
2069}
2070
2071PtrParts SplitPtrStructs::visitInstruction(Instruction &I) {
2072 return {nullptr, nullptr};
2073}
2074
2075PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
2077 return {nullptr, nullptr};
2078 handleMemoryInst(&LI, nullptr, LI.getPointerOperand(), LI.getType(),
2079 LI.getAlign(), LI.getOrdering(), LI.isVolatile(),
2080 LI.getSyncScopeID());
2081 return {nullptr, nullptr};
2082}
2083
2084PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
2085 if (!isSplitFatPtr(SI.getPointerOperandType()))
2086 return {nullptr, nullptr};
2087 Value *Arg = SI.getValueOperand();
2088 handleMemoryInst(&SI, Arg, SI.getPointerOperand(), Arg->getType(),
2089 SI.getAlign(), SI.getOrdering(), SI.isVolatile(),
2090 SI.getSyncScopeID());
2091 return {nullptr, nullptr};
2092}
2093
2094PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
2096 return {nullptr, nullptr};
2097 Value *Arg = AI.getValOperand();
2098 handleMemoryInst(&AI, Arg, AI.getPointerOperand(), Arg->getType(),
2099 AI.getAlign(), AI.getOrdering(), AI.isVolatile(),
2100 AI.getSyncScopeID());
2101 return {nullptr, nullptr};
2102}
2103
2104// Unlike load, store, and RMW, cmpxchg needs special handling to account
2105// for the boolean argument.
2106PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
2107 Value *Ptr = AI.getPointerOperand();
2108 if (!isSplitFatPtr(Ptr->getType()))
2109 return {nullptr, nullptr};
2110 IRB.SetInsertPoint(&AI);
2111
2112 Type *Ty = AI.getNewValOperand()->getType();
2113 AtomicOrdering Order = AI.getMergedOrdering();
2114 SyncScope::ID SSID = AI.getSyncScopeID();
2115 bool IsNonTemporal = AI.getMetadata(LLVMContext::MD_nontemporal);
2116
2117 auto [Rsrc, Off] = getPtrParts(Ptr);
2118 insertPreMemOpFence(Order, SSID);
2119
2120 uint32_t Aux = 0;
2121 if (IsNonTemporal)
2122 Aux |= AMDGPU::CPol::SLC;
2123 if (AI.isVolatile())
2125 CallInst *Call = IRB.CreateIntrinsicWithoutFolding(
2126 Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
2127 {AI.getNewValOperand(), AI.getCompareOperand(), Rsrc, Off,
2128 IRB.getInt32(0), IRB.getInt32(Aux)});
2129 copyMetadata(Call, &AI);
2130 setAlign(Call, AI.getAlign(), 2);
2131 Call->takeName(&AI);
2132 insertPostMemOpFence(Order, SSID);
2133
2134 Value *Res = PoisonValue::get(AI.getType());
2135 Res = IRB.CreateInsertValue(Res, Call, 0);
2136 Value *Succeeded = IRB.CreateICmpEQ(Call, AI.getCompareOperand());
2137 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
2138 SplitUsers.insert(&AI);
2139 AI.replaceAllUsesWith(Res);
2140 return {nullptr, nullptr};
2141}
2142
2143PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &GEP) {
2144 using namespace llvm::PatternMatch;
2145 Value *Ptr = GEP.getPointerOperand();
2146 if (!isSplitFatPtr(Ptr->getType()))
2147 return {nullptr, nullptr};
2148 IRB.SetInsertPoint(&GEP);
2149
2150 auto [Rsrc, Off] = getPtrParts(Ptr);
2151 const DataLayout &DL = GEP.getDataLayout();
2152 bool IsNUW = GEP.hasNoUnsignedWrap();
2153 bool IsNUSW = GEP.hasNoUnsignedSignedWrap();
2154
2155 StructType *ResTy = cast<StructType>(GEP.getType());
2156 Type *ResRsrcTy = ResTy->getElementType(0);
2157 VectorType *ResRsrcVecTy = dyn_cast<VectorType>(ResRsrcTy);
2158 bool BroadcastsPtr = ResRsrcVecTy && !isa<VectorType>(Off->getType());
2159
2160 // In order to call emitGEPOffset() and thus not have to reimplement it,
2161 // we need the GEP result to have ptr addrspace(7) type.
2162 Type *FatPtrTy =
2163 ResRsrcTy->getWithNewType(IRB.getPtrTy(AMDGPUAS::BUFFER_FAT_POINTER));
2164 GEP.mutateType(FatPtrTy);
2165 Value *OffAccum = emitGEPOffset(&IRB, DL, &GEP);
2166 GEP.mutateType(ResTy);
2167
2168 if (BroadcastsPtr) {
2169 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
2170 Rsrc->getName());
2171 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Off,
2172 Off->getName());
2173 }
2174 if (match(OffAccum, m_Zero())) { // Constant-zero offset
2175 SplitUsers.insert(&GEP);
2176 return {Rsrc, Off};
2177 }
2178
2179 bool HasNonNegativeOff = false;
2180 if (auto *CI = dyn_cast<ConstantInt>(OffAccum)) {
2181 HasNonNegativeOff = !CI->isNegative();
2182 }
2183 Value *NewOff;
2184 if (match(Off, m_Zero())) {
2185 NewOff = OffAccum;
2186 } else {
2187 NewOff = IRB.CreateAdd(Off, OffAccum, "",
2188 /*hasNUW=*/IsNUW || (IsNUSW && HasNonNegativeOff),
2189 /*hasNSW=*/false);
2190 }
2191 copyMetadata(NewOff, &GEP);
2192 NewOff->takeName(&GEP);
2193 SplitUsers.insert(&GEP);
2194 return {Rsrc, NewOff};
2195}
2196
2197PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
2198 Value *Ptr = PI.getPointerOperand();
2199 if (!isSplitFatPtr(Ptr->getType()))
2200 return {nullptr, nullptr};
2201 IRB.SetInsertPoint(&PI);
2202
2203 Type *ResTy = PI.getType();
2204 unsigned Width = ResTy->getScalarSizeInBits();
2205
2206 auto [Rsrc, Off] = getPtrParts(Ptr);
2207 const DataLayout &DL = PI.getDataLayout();
2208 unsigned FatPtrWidth = DL.getPointerSizeInBits(AMDGPUAS::BUFFER_FAT_POINTER);
2209
2210 Value *Res;
2211 if (Width <= BufferOffsetWidth) {
2212 Res = IRB.CreateIntCast(Off, ResTy, /*isSigned=*/false,
2213 PI.getName() + ".off");
2214 } else {
2215 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.getName() + ".rsrc");
2216 Value *Shl = IRB.CreateShl(
2217 RsrcInt,
2218 ConstantExpr::getIntegerValue(ResTy, APInt(Width, BufferOffsetWidth)),
2219 "", Width >= FatPtrWidth, Width > FatPtrWidth);
2220 Value *OffCast = IRB.CreateIntCast(Off, ResTy, /*isSigned=*/false,
2221 PI.getName() + ".off");
2222 Res = IRB.CreateOr(Shl, OffCast);
2223 }
2224
2225 copyMetadata(Res, &PI);
2226 Res->takeName(&PI);
2227 SplitUsers.insert(&PI);
2228 PI.replaceAllUsesWith(Res);
2229 return {nullptr, nullptr};
2230}
2231
2232PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
2233 Value *Ptr = PA.getPointerOperand();
2234 if (!isSplitFatPtr(Ptr->getType()))
2235 return {nullptr, nullptr};
2236 IRB.SetInsertPoint(&PA);
2237
2238 auto [Rsrc, Off] = getPtrParts(Ptr);
2239 Value *Res = IRB.CreateIntCast(Off, PA.getType(), /*isSigned=*/false);
2240 copyMetadata(Res, &PA);
2241 Res->takeName(&PA);
2242 SplitUsers.insert(&PA);
2243 PA.replaceAllUsesWith(Res);
2244 return {nullptr, nullptr};
2245}
2246
2247PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
2248 if (!isSplitFatPtr(IP.getType()))
2249 return {nullptr, nullptr};
2250 IRB.SetInsertPoint(&IP);
2251 const DataLayout &DL = IP.getDataLayout();
2252 unsigned RsrcPtrWidth = DL.getPointerSizeInBits(AMDGPUAS::BUFFER_RESOURCE);
2253 Value *Int = IP.getOperand(0);
2254 Type *IntTy = Int->getType();
2255 Type *RsrcIntTy = IntTy->getWithNewBitWidth(RsrcPtrWidth);
2256 unsigned Width = IntTy->getScalarSizeInBits();
2257
2258 auto *RetTy = cast<StructType>(IP.getType());
2259 Type *RsrcTy = RetTy->getElementType(0);
2260 Type *OffTy = RetTy->getElementType(1);
2261 // inttoptr zero-extends, so narrow inputs contribute nothing to the resource
2262 // part.
2263 Value *RsrcInt;
2264 if (Width <= BufferOffsetWidth) {
2265 RsrcInt = Constant::getNullValue(RsrcIntTy);
2266 } else {
2267 Value *RsrcPart =
2268 IRB.CreateLShr(Int, ConstantInt::get(IntTy, BufferOffsetWidth));
2269 RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy, /*isSigned=*/false);
2270 }
2271 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.getName() + ".rsrc");
2272 Value *Off =
2273 IRB.CreateIntCast(Int, OffTy, /*IsSigned=*/false, IP.getName() + ".off");
2274
2275 copyMetadata(Rsrc, &IP);
2276 SplitUsers.insert(&IP);
2277 return {Rsrc, Off};
2278}
2279
2280PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &I) {
2281 // TODO(krzysz00): handle casts from ptr addrspace(7) to global pointers
2282 // by computing the effective address.
2283 if (!isSplitFatPtr(I.getType()))
2284 return {nullptr, nullptr};
2285 IRB.SetInsertPoint(&I);
2286 Value *In = I.getPointerOperand();
2287 // No-op casts preserve parts
2288 if (In->getType() == I.getType()) {
2289 auto [Rsrc, Off] = getPtrParts(In);
2290 SplitUsers.insert(&I);
2291 return {Rsrc, Off};
2292 }
2293
2294 auto *ResTy = cast<StructType>(I.getType());
2295 Type *RsrcTy = ResTy->getElementType(0);
2296 Type *OffTy = ResTy->getElementType(1);
2297 Value *ZeroOff = Constant::getNullValue(OffTy);
2298
2299 // Special case for null pointers, undef, and poison, which can be created by
2300 // address space propagation.
2301 auto *InConst = dyn_cast<Constant>(In);
2302 if (InConst && InConst->isNullValue()) {
2303 Value *NullRsrc = Constant::getNullValue(RsrcTy);
2304 SplitUsers.insert(&I);
2305 return {NullRsrc, ZeroOff};
2306 }
2307 if (isa<PoisonValue>(In)) {
2308 Value *PoisonRsrc = PoisonValue::get(RsrcTy);
2309 Value *PoisonOff = PoisonValue::get(OffTy);
2310 SplitUsers.insert(&I);
2311 return {PoisonRsrc, PoisonOff};
2312 }
2313 if (isa<UndefValue>(In)) {
2314 Value *UndefRsrc = UndefValue::get(RsrcTy);
2315 Value *UndefOff = UndefValue::get(OffTy);
2316 SplitUsers.insert(&I);
2317 return {UndefRsrc, UndefOff};
2318 }
2319
2320 if (I.getSrcAddressSpace() != AMDGPUAS::BUFFER_RESOURCE)
2322 "only buffer resources (addrspace 8) and null/poison pointers can be "
2323 "cast to buffer fat pointers (addrspace 7)");
2324 SplitUsers.insert(&I);
2325 return {In, ZeroOff};
2326}
2327
2328PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2329 Value *Lhs = Cmp.getOperand(0);
2330 if (!isSplitFatPtr(Lhs->getType()))
2331 return {nullptr, nullptr};
2332 Value *Rhs = Cmp.getOperand(1);
2333 IRB.SetInsertPoint(&Cmp);
2334 ICmpInst::Predicate Pred = Cmp.getPredicate();
2335
2336 assert((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
2337 "Pointer comparison is only equal or unequal");
2338 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2339 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2340 Value *Res = IRB.CreateICmp(Pred, LhsOff, RhsOff);
2341 copyMetadata(Res, &Cmp);
2342 Res->takeName(&Cmp);
2343 SplitUsers.insert(&Cmp);
2344 Cmp.replaceAllUsesWith(Res);
2345 return {nullptr, nullptr};
2346}
2347
2348PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &I) {
2349 if (!isSplitFatPtr(I.getType()))
2350 return {nullptr, nullptr};
2351 IRB.SetInsertPoint(&I);
2352 auto [Rsrc, Off] = getPtrParts(I.getOperand(0));
2353
2354 Value *RsrcRes = IRB.CreateFreeze(Rsrc, I.getName() + ".rsrc");
2355 copyMetadata(RsrcRes, &I);
2356 Value *OffRes = IRB.CreateFreeze(Off, I.getName() + ".off");
2357 copyMetadata(OffRes, &I);
2358 SplitUsers.insert(&I);
2359 return {RsrcRes, OffRes};
2360}
2361
2362PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &I) {
2363 if (!isSplitFatPtr(I.getType()))
2364 return {nullptr, nullptr};
2365 IRB.SetInsertPoint(&I);
2366 Value *Vec = I.getVectorOperand();
2367 Value *Idx = I.getIndexOperand();
2368 auto [Rsrc, Off] = getPtrParts(Vec);
2369
2370 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx, I.getName() + ".rsrc");
2371 copyMetadata(RsrcRes, &I);
2372 Value *OffRes = IRB.CreateExtractElement(Off, Idx, I.getName() + ".off");
2373 copyMetadata(OffRes, &I);
2374 SplitUsers.insert(&I);
2375 return {RsrcRes, OffRes};
2376}
2377
2378PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &I) {
2379 // The mutated instructions temporarily don't return vectors, and so
2380 // we need the generic getType() here to avoid crashes.
2382 return {nullptr, nullptr};
2383 IRB.SetInsertPoint(&I);
2384 Value *Vec = I.getOperand(0);
2385 Value *Elem = I.getOperand(1);
2386 Value *Idx = I.getOperand(2);
2387 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2388 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2389
2390 Value *RsrcRes =
2391 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx, I.getName() + ".rsrc");
2392 copyMetadata(RsrcRes, &I);
2393 Value *OffRes =
2394 IRB.CreateInsertElement(VecOff, ElemOff, Idx, I.getName() + ".off");
2395 copyMetadata(OffRes, &I);
2396 SplitUsers.insert(&I);
2397 return {RsrcRes, OffRes};
2398}
2399
2400PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &I) {
2401 // Cast is needed for the same reason as insertelement's.
2403 return {nullptr, nullptr};
2404 IRB.SetInsertPoint(&I);
2405
2406 Value *V1 = I.getOperand(0);
2407 Value *V2 = I.getOperand(1);
2408 ArrayRef<int> Mask = I.getShuffleMask();
2409 auto [V1Rsrc, V1Off] = getPtrParts(V1);
2410 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2411
2412 Value *RsrcRes =
2413 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask, I.getName() + ".rsrc");
2414 copyMetadata(RsrcRes, &I);
2415 Value *OffRes =
2416 IRB.CreateShuffleVector(V1Off, V2Off, Mask, I.getName() + ".off");
2417 copyMetadata(OffRes, &I);
2418 SplitUsers.insert(&I);
2419 return {RsrcRes, OffRes};
2420}
2421
2422PtrParts SplitPtrStructs::visitPHINode(PHINode &PHI) {
2423 if (!isSplitFatPtr(PHI.getType()))
2424 return {nullptr, nullptr};
2425 IRB.SetInsertPoint(*PHI.getInsertionPointAfterDef());
2426 // Phi nodes will be handled in post-processing after we've visited every
2427 // instruction. However, instead of just returning {nullptr, nullptr},
2428 // we explicitly create the temporary extractvalue operations that are our
2429 // temporary results so that they end up at the beginning of the block with
2430 // the PHIs.
2431 Value *TmpRsrc = IRB.CreateExtractValue(&PHI, 0, PHI.getName() + ".rsrc");
2432 Value *TmpOff = IRB.CreateExtractValue(&PHI, 1, PHI.getName() + ".off");
2433 Conditionals.push_back(&PHI);
2434 SplitUsers.insert(&PHI);
2435 return {TmpRsrc, TmpOff};
2436}
2437
2438PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2439 if (!isSplitFatPtr(SI.getType()))
2440 return {nullptr, nullptr};
2441 IRB.SetInsertPoint(&SI);
2442
2443 Value *Cond = SI.getCondition();
2444 Value *True = SI.getTrueValue();
2445 Value *False = SI.getFalseValue();
2446 auto [TrueRsrc, TrueOff] = getPtrParts(True);
2447 auto [FalseRsrc, FalseOff] = getPtrParts(False);
2448
2449 Value *RsrcRes =
2450 IRB.CreateSelect(Cond, TrueRsrc, FalseRsrc, SI.getName() + ".rsrc", &SI);
2451 copyMetadata(RsrcRes, &SI);
2452 Conditionals.push_back(&SI);
2453 Value *OffRes =
2454 IRB.CreateSelect(Cond, TrueOff, FalseOff, SI.getName() + ".off", &SI);
2455 copyMetadata(OffRes, &SI);
2456 SplitUsers.insert(&SI);
2457 return {RsrcRes, OffRes};
2458}
2459
2460/// Returns true if this intrinsic needs to be removed when it is
2461/// applied to `ptr addrspace(7)` values. Calls to these intrinsics are
2462/// rewritten into calls to versions of that intrinsic on the resource
2463/// descriptor.
2465 switch (IID) {
2466 default:
2467 return false;
2468 case Intrinsic::amdgcn_make_buffer_rsrc:
2469 case Intrinsic::ptrmask:
2470 case Intrinsic::invariant_start:
2471 case Intrinsic::invariant_end:
2472 case Intrinsic::launder_invariant_group:
2473 case Intrinsic::strip_invariant_group:
2474 case Intrinsic::memcpy:
2475 case Intrinsic::memcpy_inline:
2476 case Intrinsic::memmove:
2477 case Intrinsic::memset:
2478 case Intrinsic::memset_inline:
2479 case Intrinsic::experimental_memset_pattern:
2480 case Intrinsic::amdgcn_load_to_lds:
2481 case Intrinsic::amdgcn_load_async_to_lds:
2482 return true;
2483 }
2484}
2485
2486PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &I) {
2487 Intrinsic::ID IID = I.getIntrinsicID();
2488 switch (IID) {
2489 default:
2490 break;
2491 case Intrinsic::amdgcn_make_buffer_rsrc: {
2492 if (!isSplitFatPtr(I.getType()))
2493 return {nullptr, nullptr};
2494 Value *Base = I.getArgOperand(0);
2495 Value *Stride = I.getArgOperand(1);
2496 Value *NumRecords = I.getArgOperand(2);
2497 Value *Flags = I.getArgOperand(3);
2498 auto *SplitType = cast<StructType>(I.getType());
2499 Type *RsrcType = SplitType->getElementType(0);
2500 Type *OffType = SplitType->getElementType(1);
2501 IRB.SetInsertPoint(&I);
2502 Value *Rsrc = IRB.CreateIntrinsic(
2503 IID, {RsrcType, Base->getType(), NumRecords->getType()},
2504 {Base, Stride, NumRecords, Flags});
2505 copyMetadata(Rsrc, &I);
2506 Rsrc->takeName(&I);
2507 Value *Zero = Constant::getNullValue(OffType);
2508 SplitUsers.insert(&I);
2509 return {Rsrc, Zero};
2510 }
2511 case Intrinsic::ptrmask: {
2512 Value *Ptr = I.getArgOperand(0);
2513 if (!isSplitFatPtr(Ptr->getType()))
2514 return {nullptr, nullptr};
2515 Value *Mask = I.getArgOperand(1);
2516 IRB.SetInsertPoint(&I);
2517 auto [Rsrc, Off] = getPtrParts(Ptr);
2518 if (Mask->getType() != Off->getType())
2519 reportFatalUsageError("offset width is not equal to index width of fat "
2520 "pointer (data layout not set up correctly?)");
2521 Value *OffRes = IRB.CreateAnd(Off, Mask, I.getName() + ".off");
2522 copyMetadata(OffRes, &I);
2523 SplitUsers.insert(&I);
2524 return {Rsrc, OffRes};
2525 }
2526 // Pointer annotation intrinsics that, given their object-wide nature
2527 // operate on the resource part.
2528 case Intrinsic::invariant_start: {
2529 Value *Ptr = I.getArgOperand(1);
2530 if (!isSplitFatPtr(Ptr->getType()))
2531 return {nullptr, nullptr};
2532 IRB.SetInsertPoint(&I);
2533 auto [Rsrc, Off] = getPtrParts(Ptr);
2534 Type *NewTy = PointerType::get(I.getContext(), AMDGPUAS::BUFFER_RESOURCE);
2535 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {I.getOperand(0), Rsrc});
2536 copyMetadata(NewRsrc, &I);
2537 NewRsrc->takeName(&I);
2538 SplitUsers.insert(&I);
2539 I.replaceAllUsesWith(NewRsrc);
2540 return {nullptr, nullptr};
2541 }
2542 case Intrinsic::invariant_end: {
2543 Value *RealPtr = I.getArgOperand(2);
2544 if (!isSplitFatPtr(RealPtr->getType()))
2545 return {nullptr, nullptr};
2546 IRB.SetInsertPoint(&I);
2547 Value *RealRsrc = getPtrParts(RealPtr).first;
2548 Value *InvPtr = I.getArgOperand(0);
2549 Value *Size = I.getArgOperand(1);
2550 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->getType()},
2551 {InvPtr, Size, RealRsrc});
2552 copyMetadata(NewRsrc, &I);
2553 NewRsrc->takeName(&I);
2554 SplitUsers.insert(&I);
2555 I.replaceAllUsesWith(NewRsrc);
2556 return {nullptr, nullptr};
2557 }
2558 case Intrinsic::launder_invariant_group:
2559 case Intrinsic::strip_invariant_group: {
2560 Value *Ptr = I.getArgOperand(0);
2561 if (!isSplitFatPtr(Ptr->getType()))
2562 return {nullptr, nullptr};
2563 IRB.SetInsertPoint(&I);
2564 auto [Rsrc, Off] = getPtrParts(Ptr);
2565 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->getType()}, {Rsrc});
2566 copyMetadata(NewRsrc, &I);
2567 NewRsrc->takeName(&I);
2568 SplitUsers.insert(&I);
2569 return {NewRsrc, Off};
2570 }
2571 case Intrinsic::amdgcn_load_to_lds:
2572 case Intrinsic::amdgcn_load_async_to_lds: {
2573 Value *Ptr = I.getArgOperand(0);
2574 if (!isSplitFatPtr(Ptr->getType()))
2575 return {nullptr, nullptr};
2576 IRB.SetInsertPoint(&I);
2577 auto [Rsrc, Off] = getPtrParts(Ptr);
2578 Value *LDSPtr = I.getArgOperand(1);
2579 Value *LoadSize = I.getArgOperand(2);
2580 Value *ImmOff = I.getArgOperand(3);
2581 Value *Aux = I.getArgOperand(4);
2582 Value *SOffset = IRB.getInt32(0);
2583 Intrinsic::ID NewIntr =
2584 IID == Intrinsic::amdgcn_load_to_lds
2585 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2586 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2587 Instruction *NewLoad = IRB.CreateIntrinsicWithoutFolding(
2588 NewIntr, {}, {Rsrc, LDSPtr, LoadSize, Off, SOffset, ImmOff, Aux});
2589 copyMetadata(NewLoad, &I);
2590 SplitUsers.insert(&I);
2591 I.replaceAllUsesWith(NewLoad);
2592 return {nullptr, nullptr};
2593 }
2594 }
2595 return {nullptr, nullptr};
2596}
2597
2598void SplitPtrStructs::processFunction(Function &F) {
2599 ST = &TM->getSubtarget<GCNSubtarget>(F);
2600 SmallVector<Instruction *, 0> Originals(
2602 LLVM_DEBUG(dbgs() << "Splitting pointer structs in function: " << F.getName()
2603 << "\n");
2604 for (Instruction *I : Originals) {
2605 // In some cases, instruction order doesn't reflect program order,
2606 // so the visit() call will have already visited coertain instructions
2607 // by the time this loop gets to them. Avoid re-visiting these so as to,
2608 // for example, avoid processing the same conditional twice.
2609 if (SplitUsers.contains(I))
2610 continue;
2611 auto [Rsrc, Off] = visit(I);
2612 assert(((Rsrc && Off) || (!Rsrc && !Off)) &&
2613 "Can't have a resource but no offset");
2614 if (Rsrc)
2615 RsrcParts[I] = Rsrc;
2616 if (Off)
2617 OffParts[I] = Off;
2618 }
2619 processConditionals();
2620 killAndReplaceSplitInstructions(Originals);
2621
2622 // Clean up after ourselves to save on memory.
2623 RsrcParts.clear();
2624 OffParts.clear();
2625 SplitUsers.clear();
2626 Conditionals.clear();
2627 ConditionalTemps.clear();
2628}
2629
2630namespace {
2631class AMDGPULowerBufferFatPointers : public ModulePass {
2632public:
2633 static char ID;
2634
2635 AMDGPULowerBufferFatPointers() : ModulePass(ID) {}
2636
2637 bool run(Module &M, const TargetMachine &TM, GetTTIFn GetTTI, GetSEFn GetSE);
2638 bool runOnModule(Module &M) override;
2639
2640 void getAnalysisUsage(AnalysisUsage &AU) const override;
2641};
2642} // namespace
2643
2644/// Returns true if there are values that have a buffer fat pointer in them,
2645/// which means we'll need to perform rewrites on this function. As a side
2646/// effect, this will populate the type remapping cache.
2648 BufferFatPtrToStructTypeMap *TypeMap) {
2649 bool HasFatPointers = false;
2650 for (const BasicBlock &BB : F)
2651 for (const Instruction &I : BB) {
2652 HasFatPointers |= (I.getType() != TypeMap->remapType(I.getType()));
2653 // Catch null pointer constants in loads, stores, etc.
2654 for (const Value *V : I.operand_values())
2655 HasFatPointers |= (V->getType() != TypeMap->remapType(V->getType()));
2656 }
2657 return HasFatPointers;
2658}
2659
2661 BufferFatPtrToStructTypeMap *TypeMap) {
2662 Type *Ty = F.getFunctionType();
2663 return Ty != TypeMap->remapType(Ty);
2664}
2665
2666/// Move the body of `OldF` into a new function, returning it.
2668 ValueToValueMapTy &CloneMap) {
2669 bool IsIntrinsic = OldF->isIntrinsic();
2670 Function *NewF =
2671 Function::Create(NewTy, OldF->getLinkage(), OldF->getAddressSpace());
2672 NewF->copyAttributesFrom(OldF);
2673 NewF->copyMetadata(OldF, 0);
2674 NewF->takeName(OldF);
2675 NewF->updateAfterNameChange();
2677 OldF->getParent()->getFunctionList().insertAfter(OldF->getIterator(), NewF);
2678
2679 while (!OldF->empty()) {
2680 BasicBlock *BB = &OldF->front();
2681 BB->removeFromParent();
2682 BB->insertInto(NewF);
2683 CloneMap[BB] = BB;
2684 for (Instruction &I : *BB) {
2685 CloneMap[&I] = &I;
2686 }
2687 }
2688
2690 AttributeList OldAttrs = OldF->getAttributes();
2691
2692 for (auto [I, OldArg, NewArg] : enumerate(OldF->args(), NewF->args())) {
2693 CloneMap[&NewArg] = &OldArg;
2694 NewArg.takeName(&OldArg);
2695 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2696 // Temporarily mutate type of `NewArg` to allow RAUW to work.
2697 NewArg.mutateType(OldArgTy);
2698 OldArg.replaceAllUsesWith(&NewArg);
2699 NewArg.mutateType(NewArgTy);
2700
2701 AttributeSet ArgAttr = OldAttrs.getParamAttrs(I);
2702 // Intrinsics get their attributes fixed later.
2703 if (OldArgTy != NewArgTy && !IsIntrinsic)
2704 ArgAttr = ArgAttr.removeAttributes(
2705 NewF->getContext(),
2706 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2707 ArgAttrs.push_back(ArgAttr);
2708 }
2709 AttributeSet RetAttrs = OldAttrs.getRetAttrs();
2710 if (OldF->getReturnType() != NewF->getReturnType() && !IsIntrinsic)
2711 RetAttrs = RetAttrs.removeAttributes(
2712 NewF->getContext(),
2713 AttributeFuncs::typeIncompatible(NewF->getReturnType(), RetAttrs));
2714 NewF->setAttributes(AttributeList::get(
2715 NewF->getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2716 return NewF;
2717}
2718
2720 for (Argument &A : F->args())
2721 CloneMap[&A] = &A;
2722 for (BasicBlock &BB : *F) {
2723 CloneMap[&BB] = &BB;
2724 for (Instruction &I : BB)
2725 CloneMap[&I] = &I;
2726 }
2727}
2728
2729bool AMDGPULowerBufferFatPointers::run(Module &M, const TargetMachine &TM,
2730 GetTTIFn GetTTI, GetSEFn GetSE) {
2731 bool Changed = false;
2732 const DataLayout &DL = M.getDataLayout();
2733 // Record the functions which need to be remapped.
2734 // The second element of the pair indicates whether the function has to have
2735 // its arguments or return types adjusted.
2737
2738 LLVMContext &Ctx = M.getContext();
2739
2740 BufferFatPtrToStructTypeMap StructTM(DL);
2741 BufferFatPtrToIntTypeMap IntTM(DL);
2742 for (GlobalVariable &GV : make_early_inc_range(M.globals())) {
2743 if (GV.getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER) {
2744 // FIXME: Use DiagnosticInfo unsupported but it requires a Function
2745 Ctx.emitError("global variables with a buffer fat pointer address "
2746 "space (7) are not supported");
2747 GV.replaceAllUsesWith(PoisonValue::get(GV.getType()));
2748 GV.eraseFromParent();
2749 Changed = true;
2750 continue;
2751 }
2752
2753 Type *VT = GV.getValueType();
2754 if (VT != StructTM.remapType(VT)) {
2755 // FIXME: Use DiagnosticInfo unsupported but it requires a Function
2756 Ctx.emitError("global variables that contain buffer fat pointers "
2757 "(address space 7 pointers) are unsupported. Use "
2758 "buffer resource pointers (address space 8) instead");
2759 GV.replaceAllUsesWith(PoisonValue::get(GV.getType()));
2760 GV.eraseFromParent();
2761 Changed = true;
2762 continue;
2763 }
2764 }
2765
2766 {
2767 // Collect all constant exprs and aggregates referenced by any function.
2769 for (Function &F : M.functions())
2770 for (Instruction &I : instructions(F))
2771 for (Value *Op : I.operands())
2773 Worklist.push_back(cast<Constant>(Op));
2774
2775 // Recursively look for any referenced buffer pointer constants.
2776 SmallPtrSet<Constant *, 8> Visited;
2777 SetVector<Constant *> BufferFatPtrConsts;
2778 while (!Worklist.empty()) {
2779 Constant *C = Worklist.pop_back_val();
2780 if (!Visited.insert(C).second)
2781 continue;
2782 if (isBufferFatPtrOrVector(C->getType()))
2783 BufferFatPtrConsts.insert(C);
2784 for (Value *Op : C->operands())
2786 Worklist.push_back(cast<Constant>(Op));
2787 }
2788
2789 // Expand all constant expressions using fat buffer pointers to
2790 // instructions.
2792 BufferFatPtrConsts.getArrayRef(), /*RestrictToFunc=*/nullptr,
2793 /*RemoveDeadConstants=*/false, /*IncludeSelf=*/true);
2794 }
2795
2796 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM, DL,
2797 M.getContext());
2798 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(
2799 DL, M.getContext(), &TM);
2800 for (Function &F : M.functions()) {
2801 bool InterfaceChange = hasFatPointerInterface(F, &StructTM);
2802 bool BodyChanges = containsBufferFatPointers(F, &StructTM);
2803 const TargetTransformInfo *TTI = GetTTI(F);
2804 ScalarEvolution *SE = GetSE(F);
2805 Changed |= MemOpsRewrite.processFunction(F, TTI, SE);
2806 if (InterfaceChange || BodyChanges) {
2807 NeedsRemap.push_back(std::make_pair(&F, InterfaceChange));
2808 Changed |= BufferContentsTypeRewrite.processFunction(F, SE);
2809 }
2810 }
2811 if (NeedsRemap.empty())
2812 return Changed;
2813
2814 SmallVector<Function *> NeedsPostProcess;
2815 SmallVector<Function *> Intrinsics;
2816 // Keep one big map so as to memoize constants across functions.
2817 ValueToValueMapTy CloneMap;
2818 FatPtrConstMaterializer Materializer(&StructTM, CloneMap);
2819
2820 ValueMapper LowerInFuncs(CloneMap, RF_None, &StructTM, &Materializer);
2821 for (auto [F, InterfaceChange] : NeedsRemap) {
2822 Function *NewF = F;
2823 if (InterfaceChange)
2825 F, cast<FunctionType>(StructTM.remapType(F->getFunctionType())),
2826 CloneMap);
2827 else
2828 makeCloneInPraceMap(F, CloneMap);
2829 LowerInFuncs.remapFunction(*NewF);
2830 if (NewF->isIntrinsic())
2831 Intrinsics.push_back(NewF);
2832 else
2833 NeedsPostProcess.push_back(NewF);
2834 if (InterfaceChange) {
2835 F->replaceAllUsesWith(NewF);
2836 F->eraseFromParent();
2837 }
2838 Changed = true;
2839 }
2840 StructTM.clear();
2841 IntTM.clear();
2842 CloneMap.clear();
2843
2844 SplitPtrStructs Splitter(DL, M.getContext(), &TM);
2845 for (Function *F : NeedsPostProcess)
2846 Splitter.processFunction(*F);
2847 for (Function *F : Intrinsics) {
2848 // use_empty() can also occur with cases like masked load, which will
2849 // have been rewritten out of the module by now but not erased.
2850 if (F->use_empty() || isRemovablePointerIntrinsic(F->getIntrinsicID())) {
2851 F->eraseFromParent();
2852 } else {
2853 std::optional<Function *> NewF = Intrinsic::remangleIntrinsicFunction(F);
2854 if (NewF)
2855 F->replaceAllUsesWith(*NewF);
2856 }
2857 }
2858 return Changed;
2859}
2860
2861bool AMDGPULowerBufferFatPointers::runOnModule(Module &M) {
2862 TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
2863 const TargetMachine &TM = TPC.getTM<TargetMachine>();
2864 auto GetTTI = [&](Function &F) -> const TargetTransformInfo * {
2865 if (F.isDeclaration())
2866 return nullptr;
2867 return &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
2868 };
2869 auto GetSE = [&](Function &F) -> ScalarEvolution * {
2870 if (F.isDeclaration())
2871 return nullptr;
2872 return &getAnalysis<ScalarEvolutionWrapperPass>(F).getSE();
2873 };
2874 return run(M, TM, GetTTI, GetSE);
2875}
2876
2877char AMDGPULowerBufferFatPointers::ID = 0;
2878
2879char &llvm::AMDGPULowerBufferFatPointersID = AMDGPULowerBufferFatPointers::ID;
2880
2881void AMDGPULowerBufferFatPointers::getAnalysisUsage(AnalysisUsage &AU) const {
2885}
2886
2887#define PASS_DESC "Lower buffer fat pointer operations to buffer resources"
2888INITIALIZE_PASS_BEGIN(AMDGPULowerBufferFatPointers, DEBUG_TYPE, PASS_DESC,
2889 false, false)
2893INITIALIZE_PASS_END(AMDGPULowerBufferFatPointers, DEBUG_TYPE, PASS_DESC, false,
2894 false)
2895#undef PASS_DESC
2896
2898 return new AMDGPULowerBufferFatPointers();
2899}
2900
2903 auto &FA = MA.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
2904 auto GetTTI = [&](Function &F) -> const TargetTransformInfo * {
2905 if (F.isDeclaration())
2906 return nullptr;
2907 return &FA.getResult<TargetIRAnalysis>(F);
2908 };
2909 auto GetSE = [&](Function &F) -> ScalarEvolution * {
2910 if (F.isDeclaration())
2911 return nullptr;
2912 return &FA.getResult<ScalarEvolutionAnalysis>(F);
2913 };
2914 return AMDGPULowerBufferFatPointers().run(M, TM, GetTTI, GetSE)
2917}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU address space definition.
unsigned uint64_t
function_ref< const TargetTransformInfo *(Function &)> GetTTIFn
static Function * moveFunctionAdaptingType(Function *OldF, FunctionType *NewTy, ValueToValueMapTy &CloneMap)
Move the body of OldF into a new function, returning it.
static void makeCloneInPraceMap(Function *F, ValueToValueMapTy &CloneMap)
static bool isBufferFatPtrOrVector(Type *Ty)
static bool isSplitFatPtr(Type *Ty)
std::pair< Value *, Value * > PtrParts
static bool hasFatPointerInterface(const Function &F, BufferFatPtrToStructTypeMap *TypeMap)
static bool isRemovablePointerIntrinsic(Intrinsic::ID IID)
Returns true if this intrinsic needs to be removed when it is applied to ptr addrspace(7) values.
static bool containsBufferFatPointers(const Function &F, BufferFatPtrToStructTypeMap *TypeMap)
Returns true if there are values that have a buffer fat pointer in them, which means we'll need to pe...
static Value * rsrcPartRoot(Value *V)
Returns the instruction that defines the resource part of the value V.
static constexpr unsigned BufferOffsetWidth
function_ref< ScalarEvolution *(Function &)> GetSEFn
static bool isBufferFatPtrConst(Constant *C)
static std::pair< Constant *, Constant * > splitLoweredFatBufferConst(Constant *C)
Return the ptr addrspace(8) and i32 (resource and offset parts) in a lowered buffer fat pointer const...
Rewrite undef for PHI
The AMDGPU TargetMachine interface definition for hw codegen targets.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
Expand Atomic instructions
Atomic ordering constants.
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
AMD GCN specific subclass of TargetSubtarget.
#define DEBUG_TYPE
Hexagon Common GEP
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
Machine Check Debug Module
This file contains the declarations for metadata subclasses.
#define T
static bool processFunction(Function &F, NVPTXTargetMachine &TM)
uint64_t IntrinsicInst * II
#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
const SmallVectorImpl< MachineOperand > & Cond
static void visit(BasicBlock &Start, std::function< bool(BasicBlock *)> op)
This file defines generic set operations that may be used on set's of different types,...
This file defines the SmallVector class.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static SymbolRef::Type getType(const Symbol *Sym)
Definition TapiFile.cpp:39
Target-Independent Code Generator Pass Configuration Options pass.
This pass exposes codegen information to IR-level passes.
static APInt getAllOnes(unsigned numBits)
Return an APInt of a specified width with all bits set.
Definition APInt.h:231
LLVM_ABI APInt zext(unsigned width) const
Zero extend to a new width.
Definition APInt.cpp:1056
static APInt getMaxValue(unsigned numBits)
Gets maximum unsigned value of APInt for specific bit width.
Definition APInt.h:203
bool ule(const APInt &RHS) const
Unsigned less or equal comparison.
Definition APInt.h:1155
bool sge(const APInt &RHS) const
Signed greater or equal comparison.
Definition APInt.h:1242
This class represents a conversion between pointers from one address space to another.
Value * getPointerOperand()
Gets the pointer operand.
unsigned getSrcAddressSpace() const
Returns the address space of the pointer operand.
unsigned getDestAddressSpace() const
Returns the address space of the result.
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 & addRequired()
This class represents an incoming formal argument to a Function.
Definition Argument.h:32
An instruction that atomically checks whether a specified value is in a memory location,...
AtomicOrdering getMergedOrdering() const
Returns a single ordering which is at least as strong as both the success and failure orderings for t...
bool isVolatile() const
Return true if this is a cmpxchg from a volatile memory location.
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this cmpxchg instruction.
an instruction that atomically reads a memory location, combines it with another value,...
Align getAlign() const
Return the alignment of the memory that is being allocated by the instruction.
bool isVolatile() const
Return true if this is a RMW on a volatile memory location.
@ Add
*p = old + v
@ FAdd
*p = old + v
@ USubCond
Subtract only if no unsigned overflow.
@ FMinimum
*p = minimum(old, v) minimum matches the behavior of llvm.minimum.
@ Min
*p = old <signed v ? old : v
@ Sub
*p = old - v
@ And
*p = old & v
@ Xor
*p = old ^ v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ FMaximum
*p = maximum(old, v) maximum matches the behavior of llvm.maximum.
@ FSub
*p = old - v
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ FMin
*p = minnum(old, v) minnum matches the behavior of llvm.minnum.
@ UMax
*p = old >unsigned v ? old : v
@ FMaximumNum
*p = maximumnum(old, v) maximumnum matches the behavior of llvm.maximumnum.
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
@ UDecWrap
Decrement one until a minimum value or zero.
@ FMinimumNum
*p = minimumnum(old, v) minimumnum matches the behavior of llvm.minimumnum.
@ Nand
*p = ~(old & v)
Value * getPointerOperand()
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this rmw instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this rmw instruction.
This class holds the attributes for a particular argument, parameter, function, or return value.
Definition Attributes.h:407
LLVM_ABI AttributeSet removeAttributes(LLVMContext &C, const AttributeMask &AttrsToRemove) const
Remove the specified attributes from this set.
LLVM Basic Block Representation.
Definition BasicBlock.h:62
LLVM_ABI void removeFromParent()
Unlink 'this' from the containing function, but do not delete it.
LLVM_ABI void insertInto(Function *Parent, BasicBlock *InsertBefore=nullptr)
Insert unlinked basic block into a function.
void addParamAttr(unsigned ArgNo, Attribute::AttrKind Kind)
Adds the attribute to the indicated argument.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI Constant * get(StructType *T, ArrayRef< Constant * > V)
static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
Definition Constant.h:43
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
static LLVM_ABI std::optional< DIExpression * > createFragmentExpression(const DIExpression *Expr, unsigned OffsetInBits, unsigned SizeInBits)
Create a DIExpression to describe one part of an aggregate variable that is fragmented across multipl...
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
LLVM_ABI void insertBefore(DbgRecord *InsertBefore)
LLVM_ABI void eraseFromParent()
LLVM_ABI void replaceVariableLocationOp(Value *OldValue, Value *NewValue, bool AllowEmpty=false)
void setExpression(DIExpression *NewExpr)
iterator find(const_arg_type_t< KeyT > Val)
Definition DenseMap.h:223
iterator end()
Definition DenseMap.h:141
Implements a dense probed hash-table based set.
Definition DenseSet.h:281
This instruction extracts a single (scalar) element from a VectorType value.
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Definition Type.cpp:867
This class represents a freeze function that returns random concrete value if an operand is either a ...
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
Definition Function.h:168
bool empty() const
Definition Function.h:843
const BasicBlock & front() const
Definition Function.h:844
iterator_range< arg_iterator > args()
Definition Function.h:876
AttributeList getAttributes() const
Return the attribute list for this Function.
Definition Function.h:328
bool isIntrinsic() const
isIntrinsic - Returns true if the function's name starts with "llvm.".
Definition Function.h:251
void setAttributes(AttributeList Attrs)
Set the attribute list for this Function.
Definition Function.h:331
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function.
Definition Function.cpp:353
void updateAfterNameChange()
Update internal caches that depend on the function name (such as the intrinsic ID and libcall cache).
Definition Function.cpp:921
Type * getReturnType() const
Returns the type of the ret val.
Definition Function.h:216
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
Definition Function.cpp:842
bool hasRelaxedBufferOOBMode() const
bool hasUnalignedBufferAccessEnabled() const
std::optional< unsigned > getBufferResourceNumRecordsWidth() const
Return the width, in bits, of the num_records field of a buffer resource (V#) on this subtarget,...
static GEPNoWrapFlags noUnsignedWrap()
static GEPNoWrapFlags none()
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
LLVM_ABI void copyMetadata(const GlobalObject *Src, unsigned Offset)
Copy metadata from Src, adjusting offsets by Offset.
LinkageTypes getLinkage() const
void setDLLStorageClass(DLLStorageClassTypes C)
unsigned getAddressSpace() const
Module * getParent()
Get the module that this global value is contained inside of...
DLLStorageClassTypes getDLLStorageClass() const
This instruction compares its operands according to the predicate given to the constructor.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition IRBuilder.h:2903
This instruction inserts a single (scalar) element into a VectorType value.
InstSimplifyFolder - Use InstructionSimplify to fold operations to existing values.
Base class for instruction visitors.
Definition InstVisitor.h:78
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
LLVM_ABI void setAAMetadata(const AAMDNodes &N)
Sets the AA metadata on this instruction from the AAMDNodes structure.
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
LLVM_ABI AAMDNodes getAAMetadata() const
Returns the AA metadata for this instruction.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
This class represents a cast from an integer to a pointer.
static LLVM_ABI IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition Type.cpp:348
A wrapper class for inspecting calls to intrinsic functions.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
LLVM_ABI void emitError(const Instruction *I, const Twine &ErrorStr)
emitError - Emit an error message to the currently installed error handler with optional location inf...
An instruction for reading from memory.
unsigned getPointerAddressSpace() const
Returns the address space of the pointer operand.
Value * getPointerOperand()
bool isVolatile() const
Return true if this is a load from a volatile memory location.
void setAtomic(AtomicOrdering Ordering, SyncScope::ID SSID=SyncScope::System)
Sets the ordering constraint and the synchronization scope ID of this load instruction.
AtomicOrdering getOrdering() const
Returns the ordering constraint of this load instruction.
Type * getPointerOperandType() const
void setVolatile(bool V)
Specify whether this is a volatile load or not.
SyncScope::ID getSyncScopeID() const
Returns the synchronization scope ID of this load instruction.
Align getAlign() const
Return the alignment of the access that is being performed.
unsigned getDestAddressSpace() const
unsigned getSourceAddressSpace() const
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
const FunctionListType & getFunctionList() const
Get the Module's list of functions (constant).
Definition Module.h:704
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 none()
Convenience factory function for the empty preserved set.
Definition Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
This class represents a cast from a pointer to an address (non-capturing ptrtoint).
Value * getPointerOperand()
Gets the pointer operand.
This class represents a cast from a pointer to an integer.
Value * getPointerOperand()
Gets the pointer operand.
Analysis pass that exposes the ScalarEvolution for a function.
The main scalar evolution driver.
LLVM_ABI bool isKnownNonNegative(const SCEV *S)
Test if the given expression is known to be non-negative.
LLVM_ABI bool isKnownNonPositive(const SCEV *S)
Test if the given expression is known to be non-positive.
LLVM_ABI const SCEV * getConstant(ConstantInt *V)
LLVM_ABI const SCEV * getSCEV(Value *V)
Return a SCEV expression for the full generality of the specified expression.
LLVM_ABI const SCEV * getMinusSCEV(SCEVUse LHS, SCEVUse RHS, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Return LHS-RHS.
LLVM_ABI bool isSCEVable(Type *Ty) const
Test if values of the given type are analyzable within the SCEV framework.
APInt getSignedRangeMin(const SCEV *S)
Determine the min of the signed range for a particular SCEV.
LLVM_ABI const SCEV * getNoopOrZeroExtend(const SCEV *V, Type *Ty)
Return a SCEV corresponding to a conversion of the input value to the specified type.
LLVM_ABI const SCEV * getPointerBase(const SCEV *V)
Transitively follow the chain of pointer-type operands until reaching a SCEV that does not have a sin...
APInt getUnsignedRangeMax(const SCEV *S)
Determine the max of the unsigned range for a particular SCEV.
LLVM_ABI const SCEV * getAddExpr(SmallVectorImpl< SCEVUse > &Ops, SCEV::NoWrapFlags Flags=SCEV::FlagAnyWrap, unsigned Depth=0)
Get a canonical add expression, or something simpler if possible.
LLVM_ABI const SCEV * getTruncateOrZeroExtend(const SCEV *V, Type *Ty, unsigned Depth=0)
Return a SCEV corresponding to a conversion of the input value to the specified type.
This class represents the LLVM 'select' instruction.
ArrayRef< value_type > getArrayRef() const
Definition SetVector.h:91
bool insert(const value_type &X)
Insert a new element into the SetVector.
Definition SetVector.h:157
This instruction constructs a fixed permutation of two input vectors.
A templated base class for SmallPtrSet which provides the typesafe interface that is common across al...
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
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.
Align getAlign() const
Value * getValueOperand()
Value * getPointerOperand()
MutableArrayRef< TypeSize > getMemberOffsets()
Definition DataLayout.h:766
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Definition Type.cpp:477
static LLVM_ABI StructType * create(LLVMContext &Context, StringRef Name)
This creates an identified struct.
Definition Type.cpp:683
bool isLiteral() const
Return true if this type is uniqued by structural equivalence, false if it is a struct definition.
Type * getElementType(unsigned N) const
Analysis pass providing the TargetTransformInfo.
Primary interface to the complete machine description for the target machine.
const STC & getSubtarget(const Function &F) const
This method returns a pointer to the specified type of TargetSubtargetInfo.
Target-Independent Code Generator Pass Configuration Options.
TMC & getTM() const
Get the right type of TargetMachine for this target.
Wrapper pass for TargetTransformInfo.
This pass provides access to the codegen interfaces that are needed for IR-level transformations.
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
LLVM_ABI unsigned getIntegerBitWidth() const
bool isVectorTy() const
True if this is an instance of VectorType.
Definition Type.h:288
bool isSingleValueType() const
Return true if the type is a valid type for a register in codegen.
Definition Type.h:311
unsigned getNumContainedTypes() const
Return the number of types in the derived type.
Definition Type.h:403
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition Type.h:368
LLVM_ABI Type * getWithNewBitWidth(unsigned NewBitWidth) const
Given an integer or vector type, change the lane bitwidth to NewBitwidth, whilst keeping the old numb...
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
LLVMContext & getContext() const
Return the LLVMContext in which this type was uniqued.
Definition Type.h:130
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
Definition Type.cpp:232
bool isIntegerTy() const
True if this is an instance of IntegerType.
Definition Type.h:257
Type * getContainedType(unsigned i) const
This method is used to implement the type iterator (defined at the end of the file).
Definition Type.h:397
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
void setOperand(unsigned i, Value *Val)
Definition User.h:212
Value * getOperand(unsigned i) const
Definition User.h:207
static LLVM_ABI ValueAsMetadata * get(Value *V)
Definition Metadata.cpp:510
This is a class that can be implemented by clients to remap types when cloning constants and instruct...
Definition ValueMapper.h:45
size_type count(const KeyT &Val) const
Return 1 if the specified key is in the map, 0 otherwise.
Definition ValueMap.h:156
iterator find(const KeyT &Val)
Definition ValueMap.h:160
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
Definition ValueMap.h:175
iterator end()
Definition ValueMap.h:139
LLVM_ABI Constant * mapConstant(const Constant &C)
LLVM_ABI Value * mapValue(const Value &V)
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
LLVMContext & getContext() const
All values hold a context through their type.
Definition Value.h:258
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
Definition Value.cpp:319
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Definition Value.cpp:400
std::pair< iterator, bool > insert(const ValueT &V)
Definition DenseSet.h:209
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition DenseSet.h:182
constexpr bool isKnownMultipleOf(ScalarTy RHS) const
This function tells the caller whether the element count is known at compile time to be a multiple of...
Definition TypeSize.h:180
constexpr ScalarTy getFixedValue() const
Definition TypeSize.h:200
constexpr bool isFixed() const
Returns true if the quantity is not scaled by vscale.
Definition TypeSize.h:171
constexpr ScalarTy getKnownMinValue() const
Returns the minimum value this quantity can represent.
Definition TypeSize.h:165
An efficient, type-erasing, non-owning reference to a callable.
self_iterator getIterator()
Definition ilist_node.h:123
iterator insertAfter(iterator where, pointer New)
Definition ilist.h:174
CallInst * Call
Changed
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BUFFER_FAT_POINTER
Address space for 160-bit buffer fat pointers.
@ BUFFER_RESOURCE
Address space for 128-bit buffer resources.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
@ Entry
Definition COFF.h:862
LLVM_ABI std::optional< Function * > remangleIntrinsicFunction(Function *F)
bool match(Val *V, const Pattern &P)
is_zero m_Zero()
Match any null constant or a vector with all elements equal to 0.
SmallVector< DbgVariableRecord * > getDVRAssignmentMarkers(const Instruction *Inst)
Return a range of dbg_assign records for which Inst performs the assignment they encode.
Definition DebugInfo.h:205
DXILDebugInfoMap run(Module &M)
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:578
@ Length
Definition DWP.cpp:578
detail::zippy< detail::zip_shortest, T, U, Args... > zip(T &&t, U &&u, Args &&...args)
zip iterator for two or more iteratable types.
Definition STLExtras.h:830
LLVM_ABI void findDbgValues(Value *V, SmallVectorImpl< DbgVariableRecord * > &DbgVariableRecords)
Finds the dbg.values describing a value.
ModulePass * createAMDGPULowerBufferFatPointersPass()
auto enumerate(FirstRange &&First, RestRanges &&...Rest)
Given two or more input ranges, returns a new range whose values are tuples (A, B,...
Definition STLExtras.h:2554
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI void copyMetadataForLoad(LoadInst &Dest, const LoadInst &Source)
Copy the metadata from the source instruction to the destination (the replacement for the source inst...
Definition Local.cpp:3125
bool set_is_subset(const S1Ty &S1, const S2Ty &S2)
set_is_subset(A, B) - Return true iff A in B
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.
constexpr bool isPowerOf2_64(uint64_t Value)
Return true if the argument is a power of two > 0 (64 bit edition.)
Definition MathExtras.h:285
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
LLVM_ABI bool convertUsersOfConstantsToInstructions(ArrayRef< Constant * > Consts, Function *RestrictToFunc=nullptr, bool RemoveDeadConstants=true, bool IncludeSelf=false)
Replace constant expressions users of the given constants with instructions.
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:1746
LLVM_ABI Value * emitGEPOffset(IRBuilderBase *Builder, const DataLayout &DL, User *GEP, bool NoAssumptions=false)
Given a getelementptr instruction/constantexpr, emit the code necessary to compute the offset from th...
Definition Local.cpp:22
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
@ RF_None
Definition ValueMapper.h:75
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
SmallVector< ValueTypeFromRangeType< R >, Size > to_vector(R &&Range)
Given a range of type R, iterate the entire range and return a SmallVector with elements of the vecto...
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
AtomicOrdering
Atomic ordering for LLVM's memory model.
constexpr T divideCeil(U Numerator, V Denominator)
Returns the integer ceil(Numerator / Denominator).
Definition MathExtras.h:389
TargetTransformInfo TTI
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
DWARFExpression::Operation Op
S1Ty set_difference(const S1Ty &S1, const S2Ty &S2)
set_difference(A, B) - Return A - B
ArrayRef(const T &OneElt) -> ArrayRef< T >
ValueMap< const Value *, WeakTrackingVH > ValueToValueMapTy
LLVM_ABI void expandMemSetAsLoop(MemSetInst *MemSet, const TargetTransformInfo *TTI=nullptr)
Expand MemSet as a loop.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
LLVM_ABI void expandMemSetPatternAsLoop(MemSetPatternInst *MemSet, const TargetTransformInfo *TTI=nullptr)
Expand MemSetPattern as a loop.
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Definition iterator.h:368
Align commonAlignment(Align A, uint64_t Offset)
Returns the alignment that satisfies both alignments.
Definition Alignment.h:201
LLVM_ABI void expandMemCpyAsLoop(MemCpyInst *MemCpy, const TargetTransformInfo &TTI, ScalarEvolution *SE=nullptr)
Expand MemCpy as a loop. MemCpy is not deleted.
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
LLVM_ABI AAMDNodes adjustForAccess(unsigned AccessSize)
Create a new AAMDNode for accessing AccessSize bytes of this AAMDNode.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39