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/PassManager.h"
246#include "llvm/IR/PatternMatch.h"
249#include "llvm/Pass.h"
253#include "llvm/Support/Debug.h"
260
261#define DEBUG_TYPE "amdgpu-lower-buffer-fat-pointers"
262
263using namespace llvm;
264
267
268static constexpr unsigned BufferOffsetWidth = 32;
269
270namespace {
271/// Recursively replace instances of ptr addrspace(7) and vector<Nxptr
272/// addrspace(7)> with some other type as defined by the relevant subclass.
273class BufferFatPtrTypeLoweringBase : public ValueMapTypeRemapper {
275
276 Type *remapTypeImpl(Type *Ty);
277
278protected:
279 virtual Type *remapScalar(PointerType *PT) = 0;
280 virtual Type *remapVector(VectorType *VT) = 0;
281
282 const DataLayout &DL;
283
284public:
285 BufferFatPtrTypeLoweringBase(const DataLayout &DL) : DL(DL) {}
286 Type *remapType(Type *SrcTy) override;
287 void clear() { Map.clear(); }
288};
289
290/// Remap ptr addrspace(7) to i160 and vector<Nxptr addrspace(7)> to
291/// vector<Nxi60> in order to correctly handling loading/storing these values
292/// from memory.
293class BufferFatPtrToIntTypeMap : public BufferFatPtrTypeLoweringBase {
294 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
295
296protected:
297 Type *remapScalar(PointerType *PT) override { return DL.getIntPtrType(PT); }
298 Type *remapVector(VectorType *VT) override { return DL.getIntPtrType(VT); }
299};
300
301/// Remap ptr addrspace(7) to {ptr addrspace(8), i32} (the resource and offset
302/// parts of the pointer) so that we can easily rewrite operations on these
303/// values that aren't loading them from or storing them to memory.
304class BufferFatPtrToStructTypeMap : public BufferFatPtrTypeLoweringBase {
305 using BufferFatPtrTypeLoweringBase::BufferFatPtrTypeLoweringBase;
306
307protected:
308 Type *remapScalar(PointerType *PT) override;
309 Type *remapVector(VectorType *VT) override;
310};
311} // namespace
312
313// This code is adapted from the type remapper in lib/Linker/IRMover.cpp
314Type *BufferFatPtrTypeLoweringBase::remapTypeImpl(Type *Ty) {
315 Type **Entry = &Map[Ty];
316 if (*Entry)
317 return *Entry;
318 if (auto *PT = dyn_cast<PointerType>(Ty)) {
319 if (PT->getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER) {
320 return *Entry = remapScalar(PT);
321 }
322 }
323 if (auto *VT = dyn_cast<VectorType>(Ty)) {
324 auto *PT = dyn_cast<PointerType>(VT->getElementType());
325 if (PT && PT->getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER) {
326 return *Entry = remapVector(VT);
327 }
328 return *Entry = Ty;
329 }
330 // Whether the type is one that is structurally uniqued - that is, if it is
331 // not a named struct (the only kind of type where multiple structurally
332 // identical types that have a distinct `Type*`)
333 StructType *TyAsStruct = dyn_cast<StructType>(Ty);
334 bool IsUniqued = !TyAsStruct || TyAsStruct->isLiteral();
335 // Base case for ints, floats, opaque pointers, and so on, which don't
336 // require recursion.
337 if (Ty->getNumContainedTypes() == 0 && IsUniqued)
338 return *Entry = Ty;
339 bool Changed = false;
340 SmallVector<Type *> ElementTypes(Ty->getNumContainedTypes(), nullptr);
341 for (unsigned int I = 0, E = Ty->getNumContainedTypes(); I < E; ++I) {
342 Type *OldElem = Ty->getContainedType(I);
343 Type *NewElem = remapTypeImpl(OldElem);
344 ElementTypes[I] = NewElem;
345 Changed |= (OldElem != NewElem);
346 }
347 // Recursive calls to remapTypeImpl() may have invalidated pointer.
348 Entry = &Map[Ty];
349 if (!Changed) {
350 return *Entry = Ty;
351 }
352 if (auto *ArrTy = dyn_cast<ArrayType>(Ty))
353 return *Entry = ArrayType::get(ElementTypes[0], ArrTy->getNumElements());
354 if (auto *FnTy = dyn_cast<FunctionType>(Ty))
355 return *Entry = FunctionType::get(ElementTypes[0],
356 ArrayRef(ElementTypes).slice(1),
357 FnTy->isVarArg());
358 if (auto *STy = dyn_cast<StructType>(Ty)) {
359 // Genuine opaque types don't have a remapping.
360 if (STy->isOpaque())
361 return *Entry = Ty;
362 bool IsPacked = STy->isPacked();
363 if (IsUniqued)
364 return *Entry = StructType::get(Ty->getContext(), ElementTypes, IsPacked);
365 SmallString<16> Name(STy->getName());
366 STy->setName("");
367 return *Entry = StructType::create(Ty->getContext(), ElementTypes, Name,
368 IsPacked);
369 }
370 llvm_unreachable("Unknown type of type that contains elements");
371}
372
373Type *BufferFatPtrTypeLoweringBase::remapType(Type *SrcTy) {
374 return remapTypeImpl(SrcTy);
375}
376
377Type *BufferFatPtrToStructTypeMap::remapScalar(PointerType *PT) {
378 LLVMContext &Ctx = PT->getContext();
379 return StructType::get(PointerType::get(Ctx, AMDGPUAS::BUFFER_RESOURCE),
381}
382
383Type *BufferFatPtrToStructTypeMap::remapVector(VectorType *VT) {
384 ElementCount EC = VT->getElementCount();
385 LLVMContext &Ctx = VT->getContext();
386 Type *RsrcVec =
387 VectorType::get(PointerType::get(Ctx, AMDGPUAS::BUFFER_RESOURCE), EC);
388 Type *OffVec = VectorType::get(IntegerType::get(Ctx, BufferOffsetWidth), EC);
389 return StructType::get(RsrcVec, OffVec);
390}
391
392static bool isBufferFatPtrOrVector(Type *Ty) {
393 if (auto *PT = dyn_cast<PointerType>(Ty->getScalarType()))
394 return PT->getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER;
395 return false;
396}
397
398// True if the type is {ptr addrspace(8), i32} or a struct containing vectors of
399// those types. Used to quickly skip instructions we don't need to process.
400static bool isSplitFatPtr(Type *Ty) {
401 auto *ST = dyn_cast<StructType>(Ty);
402 if (!ST)
403 return false;
404 if (!ST->isLiteral() || ST->getNumElements() != 2)
405 return false;
406 auto *MaybeRsrc =
407 dyn_cast<PointerType>(ST->getElementType(0)->getScalarType());
408 auto *MaybeOff =
409 dyn_cast<IntegerType>(ST->getElementType(1)->getScalarType());
410 return MaybeRsrc && MaybeOff &&
411 MaybeRsrc->getAddressSpace() == AMDGPUAS::BUFFER_RESOURCE &&
412 MaybeOff->getBitWidth() == BufferOffsetWidth;
413}
414
415// True if the result type or any argument types are buffer fat pointers.
417 Type *T = C->getType();
418 return isBufferFatPtrOrVector(T) || any_of(C->operands(), [](const Use &U) {
419 return isBufferFatPtrOrVector(U.get()->getType());
420 });
421}
422
423namespace {
424/// Convert [vectors of] buffer fat pointers to integers when they are read from
425/// or stored to memory. This ensures that these pointers will have the same
426/// memory layout as before they are lowered, even though they will no longer
427/// have their previous layout in registers/in the program (they'll be broken
428/// down into resource and offset parts). This has the downside of imposing
429/// marshalling costs when reading or storing these values, but since placing
430/// such pointers into memory is an uncommon operation at best, we feel that
431/// this cost is acceptable for better performance in the common case.
432class StoreFatPtrsAsIntsAndExpandMemcpyVisitor
433 : public InstVisitor<StoreFatPtrsAsIntsAndExpandMemcpyVisitor, bool> {
434 BufferFatPtrToIntTypeMap *TypeMap;
435
437
438 const DataLayout &DL;
439
440 // Used for memcpy() lowering.
441 const TargetTransformInfo *TTI;
442 ScalarEvolution *SE;
443
444 Value *applyOffset(Value *Ptr, uint64_t Off);
445 // Visits each maximal subtree of `Ty` that is fat-ptr-free or is itself a
446 // [vector of] fat pointer(s), at its offset in `Ty`'s original layout.
447 void forEachAggLeaf(
448 Type *Ty, SmallVectorImpl<unsigned> &AggIdxs, uint64_t Off,
449 const Twine &Name,
450 function_ref<void(Type *LeafTy, Type *IntLeafTy, ArrayRef<unsigned> Idxs,
451 uint64_t Off, const Twine &Name)>
452 Visit);
453
454public:
455 StoreFatPtrsAsIntsAndExpandMemcpyVisitor(BufferFatPtrToIntTypeMap *TypeMap,
456 const DataLayout &DL,
457 LLVMContext &Ctx)
458 : TypeMap(TypeMap), IRB(Ctx, InstSimplifyFolder(DL)), DL(DL) {}
459 bool processFunction(Function &F, const TargetTransformInfo *TTI,
460 ScalarEvolution *SE);
461
462 bool visitInstruction(Instruction &I) { return false; }
463 bool visitAllocaInst(AllocaInst &I);
464 bool visitLoadInst(LoadInst &LI);
465 bool visitStoreInst(StoreInst &SI);
466 bool visitGetElementPtrInst(GetElementPtrInst &I);
467
468 bool visitMemCpyInst(MemCpyInst &MCI);
469 bool visitMemMoveInst(MemMoveInst &MMI);
470 bool visitMemSetInst(MemSetInst &MSI);
471 bool visitMemSetPatternInst(MemSetPatternInst &MSPI);
472};
473} // namespace
474
475Value *StoreFatPtrsAsIntsAndExpandMemcpyVisitor::applyOffset(Value *Ptr,
476 uint64_t Off) {
477 // The InstSimplifyFolder gives back `Ptr` itself when `Off` is 0.
478 return IRB.CreatePtrAdd(
479 Ptr, ConstantInt::get(DL.getIndexType(Ptr->getType()), Off),
480 Ptr->getName() + ".off." + Twine(Off), GEPNoWrapFlags::noUnsignedWrap());
481}
482
483void StoreFatPtrsAsIntsAndExpandMemcpyVisitor::forEachAggLeaf(
484 Type *Ty, SmallVectorImpl<unsigned> &AggIdxs, uint64_t Off,
485 const Twine &Name,
486 function_ref<void(Type *LeafTy, Type *IntLeafTy, ArrayRef<unsigned> Idxs,
487 uint64_t Off, const Twine &Name)>
488 Visit) {
489 Type *IntTy = TypeMap->remapType(Ty);
490 if (isBufferFatPtrOrVector(Ty) || Ty == IntTy) {
491 // Zero-sized leaves ({} or [0 x T]) access no bytes; skip them.
492 if (DL.getTypeStoreSize(Ty) != 0)
493 Visit(Ty, IntTy, AggIdxs, Off, Name);
494 return;
495 }
496 auto Recurse = [&](unsigned I, Type *ElemTy, uint64_t ElemOff) {
497 AggIdxs.push_back(I);
498 forEachAggLeaf(ElemTy, AggIdxs, Off + ElemOff, Name + "." + Twine(I),
499 Visit);
500 AggIdxs.pop_back();
501 };
502 if (auto *ST = dyn_cast<StructType>(Ty)) {
503 const StructLayout *Layout = DL.getStructLayout(ST);
504 for (auto [I, ElemTy, ElemOff] :
505 enumerate(ST->elements(), Layout->getMemberOffsets()))
506 Recurse(I, ElemTy, ElemOff.getFixedValue());
507 return;
508 }
509 auto *AT = cast<ArrayType>(Ty);
510 Type *ElemTy = AT->getElementType();
511 uint64_t Stride = DL.getTypeAllocSize(ElemTy).getFixedValue();
512 for (unsigned I : seq<unsigned>(AT->getNumElements()))
513 Recurse(I, ElemTy, I * Stride);
514}
515
516bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::processFunction(
517 Function &F, const TargetTransformInfo *TTI, ScalarEvolution *SE) {
518 this->TTI = TTI;
519 this->SE = SE;
520 bool Changed = false;
521 // Process memcpy-like instructions after the main iteration because they can
522 // invalidate iterators.
523 SmallVector<WeakTrackingVH> CanBecomeLoops;
524 for (Instruction &I : make_early_inc_range(instructions(F))) {
526 CanBecomeLoops.push_back(&I);
527 else
528 Changed |= visit(I);
529 }
530 for (WeakTrackingVH VH : make_early_inc_range(CanBecomeLoops)) {
532 }
533 this->TTI = nullptr;
534 this->SE = nullptr;
535 return Changed;
536}
537
538bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitAllocaInst(AllocaInst &I) {
539 Type *Ty = I.getAllocatedType();
540 Type *NewTy = TypeMap->remapType(Ty);
541 if (Ty == NewTy)
542 return false;
543 // i160 is smaller than ptr addrspace(7) (24 bytes vs. 32); fall back to a
544 // byte array of the original size so sizes computed from Ty stay in bounds.
545 TypeSize AllocSize = DL.getTypeAllocSize(Ty);
546 if (AllocSize.isFixed() && DL.getTypeAllocSize(NewTy) != AllocSize)
547 NewTy = ArrayType::get(IRB.getInt8Ty(), AllocSize.getFixedValue());
548 I.setAllocatedType(NewTy);
549 return true;
550}
551
552bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitGetElementPtrInst(
553 GetElementPtrInst &I) {
554 Type *Ty = I.getSourceElementType();
555 if (Ty == TypeMap->remapType(Ty))
556 return false;
557 // Lower to a byte offset now, before remapping changes p7's layout (see file
558 // header).
559 IRB.SetInsertPoint(&I);
560 Value *Off = emitGEPOffset(&IRB, DL, &I);
561 Value *NewGEP = IRB.CreatePtrAdd(I.getPointerOperand(), Off, I.getName(),
562 I.getNoWrapFlags());
563 I.replaceAllUsesWith(NewGEP);
564 I.eraseFromParent();
565 return true;
566}
567
568bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitLoadInst(LoadInst &LI) {
569 Type *Ty = LI.getType();
570 Type *IntTy = TypeMap->remapType(Ty);
571 if (Ty == IntTy)
572 return false;
573
574 IRB.SetInsertPoint(&LI);
575 if (!isBufferFatPtrOrVector(Ty)) {
576 // i160 has the same 20-byte store size as p7, so loading each leaf at
577 // its original-layout offset accesses the same bytes as the unlowered load.
578 Value *Agg = PoisonValue::get(Ty);
579 AAMDNodes AATags = LI.getAAMetadata();
580 SmallVector<unsigned> AggIdxs;
581 forEachAggLeaf(
582 Ty, AggIdxs, 0, LI.getName(),
583 [&](Type *LeafTy, Type *IntLeafTy, ArrayRef<unsigned> Idxs,
584 uint64_t Off, const Twine &Name) {
585 Value *Ptr = applyOffset(LI.getPointerOperand(), Off);
586 LoadInst *NewLI = IRB.CreateAlignedLoad(
587 IntLeafTy, Ptr, commonAlignment(LI.getAlign(), Off), Name);
588 NewLI->setVolatile(LI.isVolatile());
589 copyMetadataForLoad(*NewLI, LI);
590 NewLI->setAAMetadata(AATags.adjustForAccess(Off, IntLeafTy, DL));
591 Value *V = NewLI;
592 if (LeafTy != IntLeafTy)
593 V = IRB.CreateIntToPtr(NewLI, LeafTy, Name + ".ptr");
594 Agg = IRB.CreateInsertValue(Agg, V, Idxs, Name + ".agg");
595 });
596 LI.replaceAllUsesWith(Agg);
597 LI.eraseFromParent();
598 return true;
599 }
600 auto *NLI = cast<LoadInst>(LI.clone());
601 NLI->mutateType(IntTy);
602 NLI = IRB.Insert(NLI);
603 NLI->takeName(&LI);
604
605 Value *CastBack = IRB.CreateIntToPtr(NLI, Ty, NLI->getName() + ".ptr");
606 LI.replaceAllUsesWith(CastBack);
607 LI.eraseFromParent();
608 return true;
609}
610
611bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitStoreInst(StoreInst &SI) {
612 Value *V = SI.getValueOperand();
613 Type *Ty = V->getType();
614 Type *IntTy = TypeMap->remapType(Ty);
615 if (Ty == IntTy)
616 return false;
617
618 IRB.SetInsertPoint(&SI);
619 if (!isBufferFatPtrOrVector(Ty)) {
620 // Store each leaf at its byte offset in the original layout; see
621 // visitLoadInst.
622 AAMDNodes AATags = SI.getAAMetadata();
623 SmallVector<unsigned> AggIdxs;
624 forEachAggLeaf(
625 Ty, AggIdxs, 0, V->getName(),
626 [&](Type *LeafTy, Type *IntLeafTy, ArrayRef<unsigned> Idxs,
627 uint64_t Off, const Twine &Name) {
628 Value *Leaf = IRB.CreateExtractValue(V, Idxs, Name);
629 if (LeafTy != IntLeafTy)
630 Leaf = IRB.CreatePtrToInt(Leaf, IntLeafTy, Name + ".int");
631 auto *NewSI = cast<StoreInst>(SI.clone());
632 NewSI->setAlignment(commonAlignment(SI.getAlign(), Off));
633 NewSI->setOperand(0, Leaf);
634 NewSI->setOperand(1, applyOffset(SI.getPointerOperand(), Off));
635 // Each leaf covers only part of the original assignment.
636 NewSI->setMetadata(LLVMContext::MD_DIAssignID, nullptr);
637 IRB.Insert(NewSI);
638 NewSI->setAAMetadata(AATags.adjustForAccess(Off, IntLeafTy, DL));
639 });
640 SI.eraseFromParent();
641 return true;
642 }
643 Value *IntV = IRB.CreatePtrToInt(V, IntTy, V->getName() + ".int");
644 for (auto *Dbg : at::getDVRAssignmentMarkers(&SI))
645 Dbg->setRawLocation(ValueAsMetadata::get(IntV));
646
647 SI.setOperand(0, IntV);
648 return true;
649}
650
651bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemCpyInst(
652 MemCpyInst &MCI) {
653 // TODO: Allow memcpy.p7.p3 as a synonym for the direct-to-LDS copy, which'll
654 // need loop expansion here.
657 return false;
658 llvm::expandMemCpyAsLoop(&MCI, *TTI, SE);
659 MCI.eraseFromParent();
660 return true;
661}
662
663bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemMoveInst(
664 MemMoveInst &MMI) {
667 return false;
669 "memmove() on buffer descriptors is not implemented because pointer "
670 "comparison on buffer descriptors isn't implemented\n");
671}
672
673bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetInst(
674 MemSetInst &MSI) {
676 return false;
678 MSI.eraseFromParent();
679 return true;
680}
681
682bool StoreFatPtrsAsIntsAndExpandMemcpyVisitor::visitMemSetPatternInst(
683 MemSetPatternInst &MSPI) {
685 return false;
687 MSPI.eraseFromParent();
688 return true;
689}
690
691namespace {
692/// Convert loads/stores of types that the buffer intrinsics can't handle into
693/// one ore more such loads/stores that consist of legal types.
694///
695/// Do this by
696/// 1. Recursing into structs (and arrays that don't share a memory layout with
697/// vectors) since the intrinsics can't handle complex types.
698/// 2. Converting arrays of non-aggregate, byte-sized types into their
699/// corresponding vectors
700/// 3. Bitcasting unsupported types, namely overly-long scalars and byte
701/// vectors, into vectors of supported types.
702/// 4. Splitting up excessively long reads/writes into multiple operations.
703///
704/// Note that this doesn't handle complex data strucures, but, in the future,
705/// the aggregate load splitter from SROA could be refactored to allow for that
706/// case.
707///
708/// Note that, if we can prove that the initial value of the pointer offset is 0
709/// and that the load/store won't wrap from the left or won't have bounds checks
710/// that straddle a word boundary, we can emit some of the strict bounds
711/// checking pessimizations even in strict OOB mode, and we attempt to do so.
712class LegalizeBufferContentTypesVisitor
713 : public InstVisitor<LegalizeBufferContentTypesVisitor, bool> {
714 friend class InstVisitor<LegalizeBufferContentTypesVisitor, bool>;
715
717
718 const DataLayout &DL;
719
720 ScalarEvolution *SE = nullptr;
721
722 // Map base (non-GEP'd) pointers to the number of records they have, if known.
723 // If a pointer is known to have a starting offset of 0 but it wasn't known to
724 // have a number of records (ex. it was `addrspacecast` from a buffer
725 // resource), it will be present in this map, but the key will be null.
726 // Otherwise, there will be no map entry.
727 ValueToValueMapTy ZeroBasePointerToNumRecords;
728
729 // Subtarget info, needed for determining what cache control bits to set.
730 const TargetMachine *TM;
731 const GCNSubtarget *ST = nullptr;
732
733 /// If T is [N x U], where U is a scalar type, return the vector type
734 /// <N x U>, otherwise, return T.
735 Type *scalarArrayTypeAsVector(Type *MaybeArrayType);
736 Value *arrayToVector(Value *V, Type *TargetType, const Twine &Name);
737 Value *vectorToArray(Value *V, Type *OrigType, const Twine &Name);
738
739 /// Analyze how a given buffer access could be out of bounds. Used to optimize
740 /// the strict splitting used in strict bounds checking mode.
741 struct OobProperties {
742 // Offset is far enough from all-1s that we won't get wrapping around to 0.
743 bool NoWrapFromMax = false;
744 // Offset is either entirely in-bounds or entirely out of bounds.
745 bool NoPartialOOB = false;
746
747 OobProperties() = delete;
748 // Needed for some Clangs.
749 OobProperties(bool NoWrapFromMax, bool NoPartialOOB)
750 : NoWrapFromMax(NoWrapFromMax), NoPartialOOB(NoPartialOOB) {}
751 };
752 OobProperties analyzeOobProperties(Value *Ptr, Type *Ty, uint64_t ByteOffset);
753
754 /// Break up the loads of a struct into the loads of its components
755
756 /// Return the maximum allowed load/store width for the given type and
757 /// alignment combination based on subtarget flags.
758 /// 1. If unaligned accesses are not enabled, then any load/store that is less
759 /// than word-aligned has to be handled one byte or ushort at a time.
760 /// 2. If relaxed OOB mode is not set, we must ensure that the in-bounds
761 /// part of a partially out of bounds read/write is performed correctly. This
762 /// means that any load that isn't naturally aligned has to be split into
763 /// parts that are naturally aligned, so that, after bitcasting, we don't have
764 /// unaligned loads that could discard valid data.
765 ///
766 /// For example, if we're loading a <8 x i8>, that's actually a load of a <2 x
767 /// i32>, and if we load from an align(2) address, that address might be 2
768 /// bytes from the end of the buffer. The hardware will, when performing the
769 /// <2 x i32> load, mask off the entire first word, causing the two in-bounds
770 /// bytes to be masked off. However,if we know the offset can't be too close
771 /// to the number of records in the buffer (if known), we can skip this
772 /// expansion.
773 ///
774 /// Unlike the complete disablement of unaligned accesses from point 1,
775 /// this does not apply to unaligned scalars, but will apply to cases like
776 /// `load <2 x i32>, align 4` since the left elemenvt might be out of bounds.
777 /// Note that if the we know that the base offset is known to be
778 /// less than `uint32_max - byte_size(Ty)`, we can skip these alignment
779 /// checks.
780 uint64_t maxIntrinsicWidth(Type *Ty, Align A, OobProperties OobProps);
781
782 /// Convert a vector or scalar type that can't be operated on by buffer
783 /// intrinsics to one that would be legal through bitcasts and/or truncation.
784 /// Uses the wider of i32, i16, or i8 where possible, clamping to the maximum
785 /// allowed width under the alignment rules and subtarget flags.
786 Type *legalNonAggregateForMemOp(Type *T, uint64_t MaxWidth);
787 Value *makeLegalNonAggregate(Value *V, Type *TargetType, const Twine &Name);
788 Value *makeIllegalNonAggregate(Value *V, Type *OrigType, const Twine &Name);
789
790 struct VecSlice {
791 uint64_t Index = 0;
792 uint64_t Length = 0;
793 VecSlice() = delete;
794 // Needed for some Clangs
795 VecSlice(uint64_t Index, uint64_t Length) : Index(Index), Length(Length) {}
796 };
797 /// Return the [index, length] pairs into which `T` needs to be cut to form
798 /// legal buffer load or store operations. Clears `Slices`. Creates an empty
799 /// `Slices` for non-vector inputs and creates one slice if no slicing will be
800 /// needed. No slice may be larger than `MaxWidth`.
801 void getVecSlices(Type *T, uint64_t MaxWidth,
802 SmallVectorImpl<VecSlice> &Slices);
803
804 Value *extractSlice(Value *Vec, VecSlice S, const Twine &Name);
805 Value *insertSlice(Value *Whole, Value *Part, VecSlice S, const Twine &Name);
806
807 /// In most cases, return `LegalType`. However, when given an input that would
808 /// normally be a legal type for the buffer intrinsics to return but that
809 /// isn't hooked up through SelectionDAG, return a type of the same width that
810 /// can be used with the relevant intrinsics. Specifically, handle the cases:
811 /// - <1 x T> => T for all T
812 /// - <N x i8> <=> i16, i32, 2xi32, 4xi32 (as needed)
813 /// - <N x T> where T is under 32 bits and the total size is 96 bits <=> <3 x
814 /// i32>
815 Type *intrinsicTypeFor(Type *LegalType);
816
817 bool visitLoadImpl(LoadInst &OrigLI, Type *PartType,
818 SmallVectorImpl<uint32_t> &AggIdxs, uint64_t AggByteOffset,
819 Value *&Result, const Twine &Name);
820 /// Return value is (Changed, ModifiedInPlace)
821 std::pair<bool, bool> visitStoreImpl(StoreInst &OrigSI, Type *PartType,
822 SmallVectorImpl<uint32_t> &AggIdxs,
823 uint64_t AggByteOffset,
824 const Twine &Name);
825
826 bool visitInstruction(Instruction &I) { return false; }
827 bool visitLoadInst(LoadInst &LI);
828 bool visitStoreInst(StoreInst &SI);
829
830 // Record base pointer data and num_records (if known).
831 bool visitIntrinsicInst(IntrinsicInst &II);
832 bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASCI);
833
834public:
835 LegalizeBufferContentTypesVisitor(const DataLayout &DL, LLVMContext &Ctx,
836 const TargetMachine *TM)
837 : IRB(Ctx, InstSimplifyFolder(DL)), DL(DL), TM(TM) {}
838 bool processFunction(Function &F, ScalarEvolution *SE);
839};
840} // namespace
841
842Type *LegalizeBufferContentTypesVisitor::scalarArrayTypeAsVector(Type *T) {
844 if (!AT)
845 return T;
846 Type *ET = AT->getElementType();
847 if (!ET->isSingleValueType() || isa<VectorType>(ET))
848 reportFatalUsageError("loading non-scalar arrays from buffer fat pointers "
849 "should have recursed");
850 if (!DL.typeSizeEqualsStoreSize(AT))
852 "loading padded arrays from buffer fat pinters should have recursed");
853 return FixedVectorType::get(ET, AT->getNumElements());
854}
855
856Value *LegalizeBufferContentTypesVisitor::arrayToVector(Value *V,
857 Type *TargetType,
858 const Twine &Name) {
859 Value *VectorRes = PoisonValue::get(TargetType);
860 auto *VT = cast<FixedVectorType>(TargetType);
861 unsigned EC = VT->getNumElements();
862 for (auto I : iota_range<unsigned>(0, EC, /*Inclusive=*/false)) {
863 Value *Elem = IRB.CreateExtractValue(V, I, Name + ".elem." + Twine(I));
864 VectorRes = IRB.CreateInsertElement(VectorRes, Elem, I,
865 Name + ".as.vec." + Twine(I));
866 }
867 return VectorRes;
868}
869
870Value *LegalizeBufferContentTypesVisitor::vectorToArray(Value *V,
871 Type *OrigType,
872 const Twine &Name) {
873 Value *ArrayRes = PoisonValue::get(OrigType);
874 ArrayType *AT = cast<ArrayType>(OrigType);
875 unsigned EC = AT->getNumElements();
876 for (auto I : iota_range<unsigned>(0, EC, /*Inclusive=*/false)) {
877 Value *Elem = IRB.CreateExtractElement(V, I, Name + ".elem." + Twine(I));
878 ArrayRes = IRB.CreateInsertValue(ArrayRes, Elem, I,
879 Name + ".as.array." + Twine(I));
880 }
881 return ArrayRes;
882}
883
884LegalizeBufferContentTypesVisitor::OobProperties
885LegalizeBufferContentTypesVisitor::analyzeOobProperties(Value *Ptr, Type *Ty,
886 uint64_t ByteOffset) {
887 OobProperties Result(false, false);
888
889 if (ST->hasRelaxedBufferOOBMode())
890 return OobProperties(true, true);
891
892 if (!SE)
893 return Result;
894 if (!SE->isSCEVable(Ptr->getType()))
895 return Result;
896 const SCEV *PtrOp = SE->getSCEV(Ptr);
897 if (ByteOffset > 0)
898 PtrOp = SE->getAddExpr(PtrOp, SE->getConstant(IRB.getInt32(ByteOffset)));
899 const auto *PtrBase = dyn_cast<SCEVUnknown>(SE->getPointerBase(PtrOp));
900 if (!PtrBase)
901 return Result;
902 Value *PtrBaseVal = PtrBase->getValue();
903 // We don't know if the offset field started at 0, so there's no safe analysis
904 // we can do. If it weren't for the fact that nuw / inbounds / ... are
905 // properties of the pointer, we might be able to use hem, but loads where the
906 // address computation for sub-parts of the loaded type wraps the address
907 // space are explicitly in scope here so there's not much we can do inside
908 // functions that can't "see" the fat pointer creation.
909 auto NumRecordsIfKnown = ZeroBasePointerToNumRecords.find(PtrBaseVal);
910 if (NumRecordsIfKnown == ZeroBasePointerToNumRecords.end())
911 return Result;
912
913 unsigned TypeSize = DL.getTypeStoreSize(Ty).getKnownMinValue();
914 const SCEV *PtrDiff = SE->getMinusSCEV(PtrOp, PtrBase);
915 APInt MaxNoWrapOffset = APInt::getAllOnes(BufferOffsetWidth) - TypeSize;
916 if (SE->isKnownNonNegative(PtrDiff) ||
917 SE->getUnsignedRangeMax(PtrDiff).ule(MaxNoWrapOffset))
918 Result.NoWrapFromMax = true;
919
920 // If we know that the pointer is zero-based but not what its upper bound is,
921 // we'll need to split up underaligned loads of small types.
922 if (!NumRecordsIfKnown->second)
923 return Result;
924 const SCEV *NumRecords = SE->getSCEV(NumRecordsIfKnown->second);
925
926 // We'll normalize all bounds to the num_records width on the hardware.
927 std::optional<unsigned> MaybeNumRecordsWidth =
929 if (!MaybeNumRecordsWidth)
930 return Result;
931 unsigned NumRecordsWidth = *MaybeNumRecordsWidth;
932 Type *NumRecordsTy = IRB.getIntNTy(NumRecordsWidth);
933 // Compare in i64 so wraparound is visible as a negative.
934 Type *CompareTy = IRB.getInt64Ty();
935 const SCEV *Bound = SE->getNoopOrZeroExtend(
936 SE->getTruncateOrZeroExtend(NumRecords, NumRecordsTy), CompareTy);
937
938 // All-1s is (per ISA or as a consequence of the bounds check rules, depending
939 // on architecture) no bounds check.
940 if (Bound == SE->getConstant(APInt::getMaxValue(NumRecordsWidth)
941 .zext(CompareTy->getIntegerBitWidth())))
942 Result.NoPartialOOB = true;
943
944 const SCEV *BoundsDiff =
945 SE->getMinusSCEV(Bound, SE->getNoopOrZeroExtend(PtrDiff, CompareTy));
946
947 if (SE->getSignedRangeMin(BoundsDiff).sge(TypeSize) ||
948 SE->isKnownNonPositive(BoundsDiff))
949 Result.NoPartialOOB = true;
950 return Result;
951}
952
954LegalizeBufferContentTypesVisitor::maxIntrinsicWidth(Type *T, Align A,
955 OobProperties OobProps) {
956 Align Result(16);
957 if (!ST->hasUnalignedBufferAccessEnabled() && A < Align(4))
958 Result = A;
959 auto *VT = dyn_cast<VectorType>(T);
960 if (!ST->hasRelaxedBufferOOBMode() && VT) {
961 TypeSize ElemBits = DL.getTypeSizeInBits(VT->getElementType());
962 if (ElemBits.isKnownMultipleOf(32)) {
963 // Word-sized operations are bounds-checked per word. So, the only case we
964 // have to worry about is stores that start out of bounds and then go in,
965 // and those can only become in-bounds on a multiple of their alignment.
966 // Therefore, we can use the declared alignment of the operation as the
967 // maximum width, rounding up to 4.
968 if (!OobProps.NoWrapFromMax)
969 Result = std::min(Result, std::max(A, Align(4)));
970 } else if ((ElemBits.isKnownMultipleOf(8) ||
971 isPowerOf2_64(ElemBits.getKnownMinValue()))) {
972 // To ensure correct behavior for sub-word types, we must always scalarize
973 // unaligned loads of sub-word types. For example, if you load
974 // a <4 x i8> from offset 7 in an 8-byte buffer, expecting the vector
975 // to be padded out with 0s after that last byte, you'll get all 0s
976 // instead. To prevent this behavior when not requested, de-vectorize such
977 // loads.
978 //
979 // If we knew that the value that triggers bounds checks was a multiple of
980 // 4 along with the access being word-aligned, we could avoid the
981 // scalarization here, as the bitcast wouldn't change any check behavior,
982 // but we don't currently try to analyze this.
983 //
984 // Strict OOB checking isn't supported if the size of each element is a
985 // non-power-of-2 value less than 8, since there's no feasible way to
986 // apply such a strict bounds check.
987 if (!OobProps.NoPartialOOB)
988 Result =
989 commonAlignment(Result, divideCeil(ElemBits.getKnownMinValue(), 8));
990 }
991 }
992 return Result.value() * 8;
993}
994
995Type *LegalizeBufferContentTypesVisitor::legalNonAggregateForMemOp(
996 Type *T, uint64_t MaxWidth) {
997 TypeSize Size = DL.getTypeStoreSizeInBits(T);
998 // Implicitly zero-extend to the next byte if needed.
999 if (!DL.typeSizeEqualsStoreSize(T))
1000 T = IRB.getIntNTy(Size.getFixedValue());
1001 Type *ElemTy = T->getScalarType();
1003 // Pointers are always big enough, and we'll let scalable vectors through to
1004 // fail in codegen.
1005 return T;
1006 }
1007 unsigned ElemSize = DL.getTypeSizeInBits(ElemTy).getFixedValue();
1008 if (isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= MaxWidth) {
1009 // [vectors of] anything that's 16/32/64/128 bits can be cast and split into
1010 // legal buffer operations, except that we might need to cut them into
1011 // smaller values if we're not allowed to do unaligned vector loads.
1012 return T;
1013 }
1014 Type *BestVectorElemType = nullptr;
1015 if (Size.isKnownMultipleOf(32) && MaxWidth >= 32)
1016 BestVectorElemType = IRB.getInt32Ty();
1017 else if (Size.isKnownMultipleOf(16) && MaxWidth >= 16)
1018 BestVectorElemType = IRB.getInt16Ty();
1019 else
1020 BestVectorElemType = IRB.getInt8Ty();
1021 unsigned NumCastElems =
1022 Size.getFixedValue() / BestVectorElemType->getIntegerBitWidth();
1023 if (NumCastElems == 1)
1024 return BestVectorElemType;
1025 return FixedVectorType::get(BestVectorElemType, NumCastElems);
1026}
1027
1028Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
1029 Value *V, Type *TargetType, const Twine &Name) {
1030 Type *SourceType = V->getType();
1031 TypeSize SourceSize = DL.getTypeSizeInBits(SourceType);
1032 TypeSize TargetSize = DL.getTypeSizeInBits(TargetType);
1033 if (SourceSize != TargetSize) {
1034 Type *ShortScalarTy = IRB.getIntNTy(SourceSize.getFixedValue());
1035 Type *ByteScalarTy = IRB.getIntNTy(TargetSize.getFixedValue());
1036 Value *AsScalar = IRB.CreateBitCast(V, ShortScalarTy, Name + ".as.scalar");
1037 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name + ".zext");
1038 V = Zext;
1039 SourceType = ByteScalarTy;
1040 }
1041 return IRB.CreateBitCast(V, TargetType, Name + ".legal");
1042}
1043
1044Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
1045 Value *V, Type *OrigType, const Twine &Name) {
1046 Type *LegalType = V->getType();
1047 TypeSize LegalSize = DL.getTypeSizeInBits(LegalType);
1048 TypeSize OrigSize = DL.getTypeSizeInBits(OrigType);
1049 if (LegalSize != OrigSize) {
1050 Type *ShortScalarTy = IRB.getIntNTy(OrigSize.getFixedValue());
1051 Type *ByteScalarTy = IRB.getIntNTy(LegalSize.getFixedValue());
1052 Value *AsScalar = IRB.CreateBitCast(V, ByteScalarTy, Name + ".bytes.cast");
1053 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name + ".trunc");
1054 return IRB.CreateBitCast(Trunc, OrigType, Name + ".orig");
1055 }
1056 return IRB.CreateBitCast(V, OrigType, Name + ".real.ty");
1057}
1058
1059Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(Type *LegalType) {
1060 auto *VT = dyn_cast<FixedVectorType>(LegalType);
1061 if (!VT)
1062 return LegalType;
1063 Type *ET = VT->getElementType();
1064 // Explicitly return the element type of 1-element vectors because the
1065 // underlying intrinsics don't like <1 x T> even though it's a synonym for T.
1066 if (VT->getNumElements() == 1)
1067 return ET;
1068 if (DL.getTypeSizeInBits(LegalType) == 96 && DL.getTypeSizeInBits(ET) < 32)
1069 return FixedVectorType::get(IRB.getInt32Ty(), 3);
1070 if (ET->isIntegerTy(8)) {
1071 switch (VT->getNumElements()) {
1072 default:
1073 return LegalType; // Let it crash later
1074 case 1:
1075 return IRB.getInt8Ty();
1076 case 2:
1077 return IRB.getInt16Ty();
1078 case 4:
1079 return IRB.getInt32Ty();
1080 case 8:
1081 return FixedVectorType::get(IRB.getInt32Ty(), 2);
1082 case 16:
1083 return FixedVectorType::get(IRB.getInt32Ty(), 4);
1084 }
1085 }
1086 return LegalType;
1087}
1088
1089void LegalizeBufferContentTypesVisitor::getVecSlices(
1090 Type *T, uint64_t MaxWidth, SmallVectorImpl<VecSlice> &Slices) {
1091 Slices.clear();
1092 auto *VT = dyn_cast<FixedVectorType>(T);
1093 if (!VT)
1094 return;
1095
1096 uint64_t ElemBitWidth =
1097 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
1098
1099 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
1100 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
1101 uint64_t ElemsPerWord = ElemsPer2Words / 2;
1102 uint64_t ElemsPerShort = ElemsPerWord / 2;
1103 uint64_t ElemsPerByte = ElemsPerShort / 2;
1104 // If the elements evenly pack into 32-bit words, we can use 3-word stores,
1105 // such as for <6 x bfloat> or <3 x i32>, but we can't dot his for, for
1106 // example, <3 x i64>, since that's not slicing.
1107 uint64_t ElemsPer3Words = ElemsPerWord * 3;
1108
1109 uint64_t TotalElems = VT->getNumElements();
1110 uint64_t Index = 0;
1111 auto TrySlice = [&](unsigned MaybeLen, unsigned Width) {
1112 if (MaybeLen > 0 && Width <= MaxWidth && Index + MaybeLen <= TotalElems) {
1113 VecSlice Slice{/*Index=*/Index, /*Length=*/MaybeLen};
1114 Slices.push_back(Slice);
1115 Index += MaybeLen;
1116 return true;
1117 }
1118 return false;
1119 };
1120 while (Index < TotalElems) {
1121 TrySlice(ElemsPer4Words, 128) || TrySlice(ElemsPer3Words, 96) ||
1122 TrySlice(ElemsPer2Words, 64) || TrySlice(ElemsPerWord, 32) ||
1123 TrySlice(ElemsPerShort, 16) || TrySlice(ElemsPerByte, 8);
1124 }
1125}
1126
1127Value *LegalizeBufferContentTypesVisitor::extractSlice(Value *Vec, VecSlice S,
1128 const Twine &Name) {
1129 auto *VecVT = dyn_cast<FixedVectorType>(Vec->getType());
1130 if (!VecVT)
1131 return Vec;
1132 if (S.Length == VecVT->getNumElements() && S.Index == 0)
1133 return Vec;
1134 if (S.Length == 1)
1135 return IRB.CreateExtractElement(Vec, S.Index,
1136 Name + ".slice." + Twine(S.Index));
1137 SmallVector<int> Mask = llvm::to_vector(
1138 llvm::iota_range<int>(S.Index, S.Index + S.Length, /*Inclusive=*/false));
1139 return IRB.CreateShuffleVector(Vec, Mask, Name + ".slice." + Twine(S.Index));
1140}
1141
1142Value *LegalizeBufferContentTypesVisitor::insertSlice(Value *Whole, Value *Part,
1143 VecSlice S,
1144 const Twine &Name) {
1145 auto *WholeVT = dyn_cast<FixedVectorType>(Whole->getType());
1146 if (!WholeVT)
1147 return Part;
1148 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
1149 return Part;
1150 if (S.Length == 1) {
1151 return IRB.CreateInsertElement(Whole, Part, S.Index,
1152 Name + ".slice." + Twine(S.Index));
1153 }
1154 int NumElems = cast<FixedVectorType>(Whole->getType())->getNumElements();
1155
1156 // Extend the slice with poisons to make the main shufflevector happy.
1157 SmallVector<int> ExtPartMask(NumElems, -1);
1158 for (auto [I, E] : llvm::enumerate(
1159 MutableArrayRef<int>(ExtPartMask).take_front(S.Length))) {
1160 E = I;
1161 }
1162 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
1163 Name + ".ext." + Twine(S.Index));
1164
1165 SmallVector<int> Mask =
1166 llvm::to_vector(llvm::iota_range<int>(0, NumElems, /*Inclusive=*/false));
1167 for (auto [I, E] :
1168 llvm::enumerate(MutableArrayRef<int>(Mask).slice(S.Index, S.Length)))
1169 E = I + NumElems;
1170 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
1171 Name + ".parts." + Twine(S.Index));
1172}
1173
1174bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
1175 LoadInst &OrigLI, Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1176 uint64_t AggByteOff, Value *&Result, const Twine &Name) {
1177 if (auto *ST = dyn_cast<StructType>(PartType)) {
1178 const StructLayout *Layout = DL.getStructLayout(ST);
1179 bool Changed = false;
1180 for (auto [I, ElemTy, Offset] :
1181 llvm::enumerate(ST->elements(), Layout->getMemberOffsets())) {
1182 AggIdxs.push_back(I);
1183 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1184 AggByteOff + Offset.getFixedValue(), Result,
1185 Name + "." + Twine(I));
1186 AggIdxs.pop_back();
1187 }
1188 return Changed;
1189 }
1190 if (auto *AT = dyn_cast<ArrayType>(PartType)) {
1191 Type *ElemTy = AT->getElementType();
1192 if (!ElemTy->isSingleValueType() || !DL.typeSizeEqualsStoreSize(ElemTy) ||
1193 ElemTy->isVectorTy()) {
1194 TypeSize ElemAllocSize = DL.getTypeAllocSize(ElemTy);
1195 bool Changed = false;
1196 for (auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1197 /*Inclusive=*/false)) {
1198 AggIdxs.push_back(I);
1199 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1200 AggByteOff + I * ElemAllocSize.getFixedValue(),
1201 Result, Name + Twine(I));
1202 AggIdxs.pop_back();
1203 }
1204 return Changed;
1205 }
1206 }
1207
1208 // Typical case
1209
1210 Align PartAlign = commonAlignment(OrigLI.getAlign(), AggByteOff);
1211 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1212 OobProperties OobProps =
1213 analyzeOobProperties(OrigLI.getPointerOperand(), PartType, AggByteOff);
1214 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1215 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1216
1217 SmallVector<VecSlice> Slices;
1218 getVecSlices(LegalType, MaxWidth, Slices);
1219 bool HasSlices = Slices.size() > 1;
1220 bool IsAggPart = !AggIdxs.empty();
1221 Value *LoadsRes;
1222 if (!HasSlices && !IsAggPart) {
1223 Type *LoadableType = intrinsicTypeFor(LegalType);
1224 if (LoadableType == PartType)
1225 return false;
1226
1227 IRB.SetInsertPoint(&OrigLI);
1228 auto *NLI = cast<LoadInst>(OrigLI.clone());
1229 NLI->mutateType(LoadableType);
1230 NLI = IRB.Insert(NLI);
1231 NLI->setName(Name + ".loadable");
1232
1233 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name + ".from.loadable");
1234 } else {
1235 IRB.SetInsertPoint(&OrigLI);
1236 LoadsRes = PoisonValue::get(LegalType);
1237 Value *OrigPtr = OrigLI.getPointerOperand();
1238 // If we're needing to spill something into more than one load, its legal
1239 // type will be a vector (ex. an i256 load will have LegalType = <8 x i32>).
1240 // But if we're already a scalar (which can happen if we're splitting up a
1241 // struct), the element type will be the legal type itself.
1242 Type *ElemType = LegalType->getScalarType();
1243 unsigned ElemBytes = DL.getTypeStoreSize(ElemType);
1244 AAMDNodes AANodes = OrigLI.getAAMetadata();
1245 if (IsAggPart && Slices.empty())
1246 Slices.push_back(VecSlice{/*Index=*/0, /*Length=*/1});
1247 for (VecSlice S : Slices) {
1248 Type *SliceType =
1249 S.Length != 1 ? FixedVectorType::get(ElemType, S.Length) : ElemType;
1250 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1251 // You can't reasonably expect loads to wrap around the edge of memory.
1252 Value *NewPtr = IRB.CreateGEP(
1253 IRB.getInt8Ty(), OrigLI.getPointerOperand(), IRB.getInt32(ByteOffset),
1254 OrigPtr->getName() + ".off.ptr." + Twine(ByteOffset),
1257 Type *LoadableType = intrinsicTypeFor(SliceType);
1258 LoadInst *NewLI = IRB.CreateAlignedLoad(
1259 LoadableType, NewPtr, commonAlignment(OrigLI.getAlign(), ByteOffset),
1260 Name + ".off." + Twine(ByteOffset));
1261 copyMetadataForLoad(*NewLI, OrigLI);
1262 NewLI->setAAMetadata(
1263 AANodes.adjustForAccess(ByteOffset, LoadableType, DL));
1264 NewLI->setAtomic(OrigLI.getOrdering(), OrigLI.getSyncScopeID());
1265 NewLI->setVolatile(OrigLI.isVolatile());
1266 Value *Loaded = IRB.CreateBitCast(NewLI, SliceType,
1267 NewLI->getName() + ".from.loadable");
1268 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1269 }
1270 }
1271 if (LegalType != ArrayAsVecType)
1272 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1273 if (ArrayAsVecType != PartType)
1274 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1275
1276 if (IsAggPart)
1277 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1278 else
1279 Result = LoadsRes;
1280 return true;
1281}
1282
1283bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1285 return false;
1286
1287 SmallVector<uint32_t> AggIdxs;
1288 Type *OrigType = LI.getType();
1289 Value *Result = PoisonValue::get(OrigType);
1290 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.getName());
1291 if (!Changed)
1292 return false;
1293 Result->takeName(&LI);
1294 LI.replaceAllUsesWith(Result);
1295 LI.eraseFromParent();
1296 return Changed;
1297}
1298
1299std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1300 StoreInst &OrigSI, Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1301 uint64_t AggByteOff, const Twine &Name) {
1302 if (auto *ST = dyn_cast<StructType>(PartType)) {
1303 const StructLayout *Layout = DL.getStructLayout(ST);
1304 bool Changed = false;
1305 for (auto [I, ElemTy, Offset] :
1306 llvm::enumerate(ST->elements(), Layout->getMemberOffsets())) {
1307 AggIdxs.push_back(I);
1308 Changed |= std::get<0>(visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1309 AggByteOff + Offset.getFixedValue(),
1310 Name + "." + Twine(I)));
1311 AggIdxs.pop_back();
1312 }
1313 return std::make_pair(Changed, /*ModifiedInPlace=*/false);
1314 }
1315 if (auto *AT = dyn_cast<ArrayType>(PartType)) {
1316 Type *ElemTy = AT->getElementType();
1317 if (!ElemTy->isSingleValueType() || !DL.typeSizeEqualsStoreSize(ElemTy) ||
1318 ElemTy->isVectorTy()) {
1319 TypeSize ElemAllocSize = DL.getTypeAllocSize(ElemTy);
1320 bool Changed = false;
1321 for (auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1322 /*Inclusive=*/false)) {
1323 AggIdxs.push_back(I);
1324 Changed |= std::get<0>(visitStoreImpl(
1325 OrigSI, ElemTy, AggIdxs,
1326 AggByteOff + I * ElemAllocSize.getFixedValue(), Name + Twine(I)));
1327 AggIdxs.pop_back();
1328 }
1329 return std::make_pair(Changed, /*ModifiedInPlace=*/false);
1330 }
1331 }
1332
1333 Value *OrigData = OrigSI.getValueOperand();
1334 Value *NewData = OrigData;
1335
1336 bool IsAggPart = !AggIdxs.empty();
1337 if (IsAggPart)
1338 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1339
1340 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1341 if (ArrayAsVecType != PartType) {
1342 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1343 }
1344
1345 Align PartAlign = commonAlignment(OrigSI.getAlign(), AggByteOff);
1346 OobProperties OobProps =
1347 analyzeOobProperties(OrigSI.getPointerOperand(), PartType, AggByteOff);
1348 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1349 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1350 if (LegalType != ArrayAsVecType) {
1351 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1352 }
1353
1354 SmallVector<VecSlice> Slices;
1355 getVecSlices(LegalType, MaxWidth, Slices);
1356 bool NeedToSplit = Slices.size() > 1 || IsAggPart;
1357 if (!NeedToSplit) {
1358 Type *StorableType = intrinsicTypeFor(LegalType);
1359 if (StorableType == PartType)
1360 return std::make_pair(/*Changed=*/false, /*ModifiedInPlace=*/false);
1361 NewData = IRB.CreateBitCast(NewData, StorableType, Name + ".storable");
1362 OrigSI.setOperand(0, NewData);
1363 return std::make_pair(/*Changed=*/true, /*ModifiedInPlace=*/true);
1364 }
1365
1366 Value *OrigPtr = OrigSI.getPointerOperand();
1367 Type *ElemType = LegalType->getScalarType();
1368 if (IsAggPart && Slices.empty())
1369 Slices.push_back(VecSlice{/*Index=*/0, /*Length=*/1});
1370 unsigned ElemBytes = DL.getTypeStoreSize(ElemType);
1371 AAMDNodes AANodes = OrigSI.getAAMetadata();
1372 for (VecSlice S : Slices) {
1373 Type *SliceType =
1374 S.Length != 1 ? FixedVectorType::get(ElemType, S.Length) : ElemType;
1375 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1376 Value *NewPtr = IRB.CreateGEP(
1377 IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1378 OrigPtr->getName() + ".part." + Twine(S.Index),
1381 Value *DataSlice = extractSlice(NewData, S, Name);
1382 Type *StorableType = intrinsicTypeFor(SliceType);
1383 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1384 DataSlice->getName() + ".storable");
1385 auto *NewSI = cast<StoreInst>(OrigSI.clone());
1386 NewSI->setAlignment(commonAlignment(OrigSI.getAlign(), ByteOffset));
1387 IRB.Insert(NewSI);
1388 NewSI->setOperand(0, DataSlice);
1389 NewSI->setOperand(1, NewPtr);
1390 NewSI->setAAMetadata(AANodes.adjustForAccess(ByteOffset, StorableType, DL));
1391 }
1392 return std::make_pair(/*Changed=*/true, /*ModifiedInPlace=*/false);
1393}
1394
1395bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1396 if (SI.getPointerAddressSpace() != AMDGPUAS::BUFFER_FAT_POINTER)
1397 return false;
1398 IRB.SetInsertPoint(&SI);
1399 SmallVector<uint32_t> AggIdxs;
1400 Value *OrigData = SI.getValueOperand();
1401 auto [Changed, ModifiedInPlace] =
1402 visitStoreImpl(SI, OrigData->getType(), AggIdxs, 0, OrigData->getName());
1403 if (Changed && !ModifiedInPlace)
1404 SI.eraseFromParent();
1405 return Changed;
1406}
1407
1408bool LegalizeBufferContentTypesVisitor::visitAddrSpaceCastInst(
1409 AddrSpaceCastInst &AI) {
1412 return false;
1413 Value *Src = AI.getPointerOperand();
1414 auto Record = ZeroBasePointerToNumRecords.find(Src);
1415 if (Record != ZeroBasePointerToNumRecords.end())
1416 ZeroBasePointerToNumRecords.insert({&AI, Record->second});
1417 else
1418 ZeroBasePointerToNumRecords.insert({&AI, nullptr});
1419 return false;
1420}
1421
1422bool LegalizeBufferContentTypesVisitor::visitIntrinsicInst(IntrinsicInst &II) {
1423 if (II.getIntrinsicID() != Intrinsic::amdgcn_make_buffer_rsrc)
1424 return false;
1425 ZeroBasePointerToNumRecords.insert({&II, II.getOperand(2)});
1426 return false;
1427}
1428
1429bool LegalizeBufferContentTypesVisitor::processFunction(Function &F,
1430 ScalarEvolution *SE) {
1431 this->SE = SE;
1432 ST = &TM->getSubtarget<GCNSubtarget>(F);
1433 bool Changed = false;
1434 for (Instruction &I : make_early_inc_range(instructions(F))) {
1435 Changed |= visit(I);
1436 }
1437 ZeroBasePointerToNumRecords.clear();
1438 this->SE = nullptr;
1439 return Changed;
1440}
1441
1442/// Return the ptr addrspace(8) and i32 (resource and offset parts) in a lowered
1443/// buffer fat pointer constant.
1444static std::pair<Constant *, Constant *>
1446 assert(isSplitFatPtr(C->getType()) && "Not a split fat buffer pointer");
1447 return std::make_pair(C->getAggregateElement(0u), C->getAggregateElement(1u));
1448}
1449
1450namespace {
1451/// Handle the remapping of ptr addrspace(7) constants.
1452class FatPtrConstMaterializer final : public ValueMaterializer {
1453 BufferFatPtrToStructTypeMap *TypeMap;
1454 // An internal mapper that is used to recurse into the arguments of constants.
1455 // While the documentation for `ValueMapper` specifies not to use it
1456 // recursively, examination of the logic in mapValue() shows that it can
1457 // safely be used recursively when handling constants, like it does in its own
1458 // logic.
1459 ValueMapper InternalMapper;
1460
1461 Constant *materializeBufferFatPtrConst(Constant *C);
1462
1463public:
1464 // UnderlyingMap is the value map this materializer will be filling.
1465 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1466 ValueToValueMapTy &UnderlyingMap)
1467 : TypeMap(TypeMap),
1468 InternalMapper(UnderlyingMap, RF_None, TypeMap, this) {}
1469 ~FatPtrConstMaterializer() = default;
1470
1471 Value *materialize(Value *V) override;
1472};
1473} // namespace
1474
1475Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *C) {
1476 Type *SrcTy = C->getType();
1477 auto *NewTy = dyn_cast<StructType>(TypeMap->remapType(SrcTy));
1478 if (C->isNullValue())
1479 return ConstantAggregateZero::getNullValue(NewTy);
1480 if (isa<PoisonValue>(C)) {
1481 return ConstantStruct::get(NewTy,
1482 {PoisonValue::get(NewTy->getElementType(0)),
1483 PoisonValue::get(NewTy->getElementType(1))});
1484 }
1485 if (isa<UndefValue>(C)) {
1486 return ConstantStruct::get(NewTy,
1487 {UndefValue::get(NewTy->getElementType(0)),
1488 UndefValue::get(NewTy->getElementType(1))});
1489 }
1490
1491 if (auto *VC = dyn_cast<ConstantVector>(C)) {
1492 if (Constant *S = VC->getSplatValue()) {
1493 Constant *NewS = InternalMapper.mapConstant(*S);
1494 if (!NewS)
1495 return nullptr;
1496 auto [Rsrc, Off] = splitLoweredFatBufferConst(NewS);
1497 auto EC = VC->getType()->getElementCount();
1498 return ConstantStruct::get(NewTy, {ConstantVector::getSplat(EC, Rsrc),
1499 ConstantVector::getSplat(EC, Off)});
1500 }
1503 for (Value *Op : VC->operand_values()) {
1504 auto *NewOp = dyn_cast_or_null<Constant>(InternalMapper.mapValue(*Op));
1505 if (!NewOp)
1506 return nullptr;
1507 auto [Rsrc, Off] = splitLoweredFatBufferConst(NewOp);
1508 Rsrcs.push_back(Rsrc);
1509 Offs.push_back(Off);
1510 }
1511 Constant *RsrcVec = ConstantVector::get(Rsrcs);
1512 Constant *OffVec = ConstantVector::get(Offs);
1513 return ConstantStruct::get(NewTy, {RsrcVec, OffVec});
1514 }
1515
1516 if (isa<GlobalValue>(C))
1517 reportFatalUsageError("global values containing ptr addrspace(7) (buffer "
1518 "fat pointer) values are not supported");
1519
1520 if (isa<ConstantExpr>(C))
1522 "constant exprs containing ptr addrspace(7) (buffer "
1523 "fat pointer) values should have been expanded earlier");
1524
1525 return nullptr;
1526}
1527
1528Value *FatPtrConstMaterializer::materialize(Value *V) {
1530 if (!C)
1531 return nullptr;
1532 // Structs and other types that happen to contain fat pointers get remapped
1533 // by the mapValue() logic.
1534 if (!isBufferFatPtrConst(C))
1535 return nullptr;
1536 return materializeBufferFatPtrConst(C);
1537}
1538
1539using PtrParts = std::pair<Value *, Value *>;
1540namespace {
1541// The visitor returns the resource and offset parts for an instruction if they
1542// can be computed, or (nullptr, nullptr) for cases that don't have a meaningful
1543// value mapping.
1544class SplitPtrStructs : public InstVisitor<SplitPtrStructs, PtrParts> {
1545 ValueToValueMapTy RsrcParts;
1546 ValueToValueMapTy OffParts;
1547
1548 // Track instructions that have been rewritten into a user of the component
1549 // parts of their ptr addrspace(7) input. Instructions that produced
1550 // ptr addrspace(7) parts should **not** be RAUW'd before being added to this
1551 // set, as that replacement will be handled in a post-visit step. However,
1552 // instructions that yield values that aren't fat pointers (ex. ptrtoint)
1553 // should RAUW themselves with new instructions that use the split parts
1554 // of their arguments during processing.
1555 DenseSet<Instruction *> SplitUsers;
1556
1557 // Nodes that need a second look once we've computed the parts for all other
1558 // instructions to see if, for example, we really need to phi on the resource
1559 // part.
1560 SmallVector<Instruction *> Conditionals;
1561 // Temporary instructions produced while lowering conditionals that should be
1562 // killed.
1563 SmallVector<Instruction *> ConditionalTemps;
1564
1565 // Subtarget info, needed for determining what cache control bits to set.
1566 const TargetMachine *TM;
1567 const GCNSubtarget *ST = nullptr;
1568
1570
1571 // Copy metadata between instructions if applicable.
1572 void copyMetadata(Value *Dest, Value *Src);
1573
1574 // Get the resource and offset parts of the value V, inserting appropriate
1575 // extractvalue calls if needed.
1576 PtrParts getPtrParts(Value *V);
1577
1578 // Given an instruction that could produce multiple resource parts (a PHI or
1579 // select), collect the set of possible instructions that could have provided
1580 // its resource parts that it could have (the `Roots`) and the set of
1581 // conditional instructions visited during the search (`Seen`). If, after
1582 // removing the root of the search from `Seen` and `Roots`, `Seen` is a subset
1583 // of `Roots` and `Roots - Seen` contains one element, the resource part of
1584 // that element can replace the resource part of all other elements in `Seen`.
1585 void getPossibleRsrcRoots(Instruction *I, SmallPtrSetImpl<Value *> &Roots,
1587 void processConditionals();
1588
1589 // If an instruction hav been split into resource and offset parts,
1590 // delete that instruction. If any of its uses have not themselves been split
1591 // into parts (for example, an insertvalue), construct the structure
1592 // that the type rewrites declared should be produced by the dying instruction
1593 // and use that.
1594 // Also, kill the temporary extractvalue operations produced by the two-stage
1595 // lowering of PHIs and conditionals.
1596 void killAndReplaceSplitInstructions(SmallVectorImpl<Instruction *> &Origs);
1597
1598 void setAlign(CallInst *Intr, Align A, unsigned RsrcArgIdx);
1599 void insertPreMemOpFence(AtomicOrdering Order, SyncScope::ID SSID);
1600 void insertPostMemOpFence(AtomicOrdering Order, SyncScope::ID SSID);
1601 Value *handleMemoryInst(Instruction *I, Value *Arg, Value *Ptr, Type *Ty,
1602 Align Alignment, AtomicOrdering Order,
1603 bool IsVolatile, SyncScope::ID SSID);
1604
1605public:
1606 SplitPtrStructs(const DataLayout &DL, LLVMContext &Ctx,
1607 const TargetMachine *TM)
1608 : TM(TM), IRB(Ctx, InstSimplifyFolder(DL)) {}
1609
1610 void processFunction(Function &F);
1611
1612 PtrParts visitInstruction(Instruction &I);
1613 PtrParts visitLoadInst(LoadInst &LI);
1614 PtrParts visitStoreInst(StoreInst &SI);
1615 PtrParts visitAtomicRMWInst(AtomicRMWInst &AI);
1616 PtrParts visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI);
1617 PtrParts visitGetElementPtrInst(GetElementPtrInst &GEP);
1618
1619 PtrParts visitPtrToAddrInst(PtrToAddrInst &PA);
1620 PtrParts visitPtrToIntInst(PtrToIntInst &PI);
1621 PtrParts visitIntToPtrInst(IntToPtrInst &IP);
1622 PtrParts visitAddrSpaceCastInst(AddrSpaceCastInst &I);
1623 PtrParts visitICmpInst(ICmpInst &Cmp);
1624 PtrParts visitFreezeInst(FreezeInst &I);
1625
1626 PtrParts visitExtractElementInst(ExtractElementInst &I);
1627 PtrParts visitInsertElementInst(InsertElementInst &I);
1628 PtrParts visitShuffleVectorInst(ShuffleVectorInst &I);
1629
1630 PtrParts visitPHINode(PHINode &PHI);
1631 PtrParts visitSelectInst(SelectInst &SI);
1632
1633 PtrParts visitIntrinsicInst(IntrinsicInst &II);
1634};
1635} // namespace
1636
1637void SplitPtrStructs::copyMetadata(Value *Dest, Value *Src) {
1638 auto *DestI = dyn_cast<Instruction>(Dest);
1639 auto *SrcI = dyn_cast<Instruction>(Src);
1640
1641 if (!DestI || !SrcI)
1642 return;
1643
1644 DestI->copyMetadata(*SrcI);
1645}
1646
1647PtrParts SplitPtrStructs::getPtrParts(Value *V) {
1648 assert(isSplitFatPtr(V->getType()) && "it's not meaningful to get the parts "
1649 "of something that wasn't rewritten");
1650 auto *RsrcEntry = &RsrcParts[V];
1651 auto *OffEntry = &OffParts[V];
1652 if (*RsrcEntry && *OffEntry)
1653 return {*RsrcEntry, *OffEntry};
1654
1655 if (auto *C = dyn_cast<Constant>(V)) {
1656 auto [Rsrc, Off] = splitLoweredFatBufferConst(C);
1657 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1658 }
1659
1660 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1661 if (auto *I = dyn_cast<Instruction>(V)) {
1662 LLVM_DEBUG(dbgs() << "Recursing to split parts of " << *I << "\n");
1663 auto [Rsrc, Off] = visit(*I);
1664 if (Rsrc && Off)
1665 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1666 // We'll be creating the new values after the relevant instruction.
1667 // This instruction generates a value and so isn't a terminator.
1668 IRB.SetInsertPoint(*I->getInsertionPointAfterDef());
1669 IRB.SetCurrentDebugLocation(I->getDebugLoc());
1670 } else if (auto *A = dyn_cast<Argument>(V)) {
1671 IRB.SetInsertPointPastAllocas(A->getParent());
1672 IRB.SetCurrentDebugLocation(DebugLoc());
1673 }
1674 Value *Rsrc = IRB.CreateExtractValue(V, 0, V->getName() + ".rsrc");
1675 Value *Off = IRB.CreateExtractValue(V, 1, V->getName() + ".off");
1676 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1677}
1678
1679/// Returns the instruction that defines the resource part of the value V.
1680/// Note that this is not getUnderlyingObject(), since that looks through
1681/// operations like ptrmask which might modify the resource part.
1682///
1683/// We can limit ourselves to just looking through GEPs followed by looking
1684/// through addrspacecasts because only those two operations preserve the
1685/// resource part, and because operations on an `addrspace(8)` (which is the
1686/// legal input to this addrspacecast) would produce a different resource part.
1688 while (auto *GEP = dyn_cast<GEPOperator>(V))
1689 V = GEP->getPointerOperand();
1690 while (auto *ASC = dyn_cast<AddrSpaceCastOperator>(V))
1691 V = ASC->getPointerOperand();
1692 return V;
1693}
1694
1695void SplitPtrStructs::getPossibleRsrcRoots(Instruction *I,
1696 SmallPtrSetImpl<Value *> &Roots,
1697 SmallPtrSetImpl<Value *> &Seen) {
1698 if (auto *PHI = dyn_cast<PHINode>(I)) {
1699 if (!Seen.insert(I).second)
1700 return;
1701 for (Value *In : PHI->incoming_values()) {
1702 In = rsrcPartRoot(In);
1703 Roots.insert(In);
1705 getPossibleRsrcRoots(cast<Instruction>(In), Roots, Seen);
1706 }
1707 } else if (auto *SI = dyn_cast<SelectInst>(I)) {
1708 if (!Seen.insert(SI).second)
1709 return;
1710 Value *TrueVal = rsrcPartRoot(SI->getTrueValue());
1711 Value *FalseVal = rsrcPartRoot(SI->getFalseValue());
1712 Roots.insert(TrueVal);
1713 Roots.insert(FalseVal);
1714 if (isa<PHINode, SelectInst>(TrueVal))
1715 getPossibleRsrcRoots(cast<Instruction>(TrueVal), Roots, Seen);
1716 if (isa<PHINode, SelectInst>(FalseVal))
1717 getPossibleRsrcRoots(cast<Instruction>(FalseVal), Roots, Seen);
1718 } else {
1719 llvm_unreachable("getPossibleRsrcParts() only works on phi and select");
1720 }
1721}
1722
1723void SplitPtrStructs::processConditionals() {
1724 SmallDenseMap<Value *, Value *> FoundRsrcs;
1725 SmallPtrSet<Value *, 4> Roots;
1726 SmallPtrSet<Value *, 4> Seen;
1727 for (Instruction *I : Conditionals) {
1728 // These have to exist by now because we've visited these nodes.
1729 Value *Rsrc = RsrcParts[I];
1730 Value *Off = OffParts[I];
1731 assert(Rsrc && Off && "must have visited conditionals by now");
1732
1733 std::optional<Value *> MaybeRsrc;
1734 auto MaybeFoundRsrc = FoundRsrcs.find(I);
1735 if (MaybeFoundRsrc != FoundRsrcs.end()) {
1736 MaybeRsrc = MaybeFoundRsrc->second;
1737 } else {
1738 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1739 Roots.clear();
1740 Seen.clear();
1741 getPossibleRsrcRoots(I, Roots, Seen);
1742 LLVM_DEBUG(dbgs() << "Processing conditional: " << *I << "\n");
1743#ifndef NDEBUG
1744 for (Value *V : Roots)
1745 LLVM_DEBUG(dbgs() << "Root: " << *V << "\n");
1746 for (Value *V : Seen)
1747 LLVM_DEBUG(dbgs() << "Seen: " << *V << "\n");
1748#endif
1749 // If we are our own possible root, then we shouldn't block our
1750 // replacement with a valid incoming value.
1751 Roots.erase(I);
1752 // We don't want to block the optimization for conditionals that don't
1753 // refer to themselves but did see themselves during the traversal.
1754 Seen.erase(I);
1755
1756 if (set_is_subset(Seen, Roots)) {
1757 auto Diff = set_difference(Roots, Seen);
1758 if (Diff.size() == 1) {
1759 Value *RootVal = *Diff.begin();
1760 // Handle the case where previous loops already looked through
1761 // an addrspacecast.
1762 if (isSplitFatPtr(RootVal->getType()))
1763 MaybeRsrc = std::get<0>(getPtrParts(RootVal));
1764 else
1765 MaybeRsrc = RootVal;
1766 }
1767 }
1768 }
1769
1770 if (auto *PHI = dyn_cast<PHINode>(I)) {
1771 Value *NewRsrc;
1772 StructType *PHITy = cast<StructType>(PHI->getType());
1773 IRB.SetInsertPoint(*PHI->getInsertionPointAfterDef());
1774 IRB.SetCurrentDebugLocation(PHI->getDebugLoc());
1775 if (MaybeRsrc) {
1776 NewRsrc = *MaybeRsrc;
1777 } else {
1778 Type *RsrcTy = PHITy->getElementType(0);
1779 auto *RsrcPHI = IRB.CreatePHI(RsrcTy, PHI->getNumIncomingValues());
1780 RsrcPHI->takeName(Rsrc);
1781 for (auto [V, BB] : llvm::zip(PHI->incoming_values(), PHI->blocks())) {
1782 Value *VRsrc = std::get<0>(getPtrParts(V));
1783 RsrcPHI->addIncoming(VRsrc, BB);
1784 }
1785 copyMetadata(RsrcPHI, PHI);
1786 NewRsrc = RsrcPHI;
1787 }
1788
1789 Type *OffTy = PHITy->getElementType(1);
1790 auto *NewOff = IRB.CreatePHI(OffTy, PHI->getNumIncomingValues());
1791 NewOff->takeName(Off);
1792 for (auto [V, BB] : llvm::zip(PHI->incoming_values(), PHI->blocks())) {
1793 assert(OffParts.count(V) && "An offset part had to be created by now");
1794 Value *VOff = std::get<1>(getPtrParts(V));
1795 NewOff->addIncoming(VOff, BB);
1796 }
1797 copyMetadata(NewOff, PHI);
1798
1799 // Note: We don't eraseFromParent() the temporaries because we don't want
1800 // to put the corrections maps in an inconstent state. That'll be handed
1801 // during the rest of the killing. Also, `ValueToValueMapTy` guarantees
1802 // that references in that map will be updated as well.
1803 // Note that if the temporary instruction got `InstSimplify`'d away, it
1804 // might be something like a block argument.
1805 if (auto *RsrcInst = dyn_cast<Instruction>(Rsrc)) {
1806 ConditionalTemps.push_back(RsrcInst);
1807 RsrcInst->replaceAllUsesWith(NewRsrc);
1808 }
1809 if (auto *OffInst = dyn_cast<Instruction>(Off)) {
1810 ConditionalTemps.push_back(OffInst);
1811 OffInst->replaceAllUsesWith(NewOff);
1812 }
1813
1814 // Save on recomputing the cycle traversals in known-root cases.
1815 if (MaybeRsrc)
1816 for (Value *V : Seen)
1817 FoundRsrcs[V] = NewRsrc;
1818 } else if (isa<SelectInst>(I)) {
1819 if (MaybeRsrc) {
1820 if (auto *RsrcInst = dyn_cast<Instruction>(Rsrc)) {
1821 // Guard against conditionals that were already folded away.
1822 if (RsrcInst != *MaybeRsrc) {
1823 ConditionalTemps.push_back(RsrcInst);
1824 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1825 }
1826 }
1827 for (Value *V : Seen)
1828 FoundRsrcs[V] = *MaybeRsrc;
1829 }
1830 } else {
1831 llvm_unreachable("Only PHIs and selects go in the conditionals list");
1832 }
1833 }
1834}
1835
1836void SplitPtrStructs::killAndReplaceSplitInstructions(
1837 SmallVectorImpl<Instruction *> &Origs) {
1838 for (Instruction *I : ConditionalTemps)
1839 I->eraseFromParent();
1840
1841 for (Instruction *I : Origs) {
1842 if (!SplitUsers.contains(I))
1843 continue;
1844
1846 findDbgValues(I, Dbgs);
1847 for (DbgVariableRecord *Dbg : Dbgs) {
1848 auto &DL = I->getDataLayout();
1849 assert(isSplitFatPtr(I->getType()) &&
1850 "We should've RAUW'd away loads, stores, etc. at this point");
1851 DbgVariableRecord *OffDbg = Dbg->clone();
1852 auto [Rsrc, Off] = getPtrParts(I);
1853
1854 int64_t RsrcSz = DL.getTypeSizeInBits(Rsrc->getType());
1855 int64_t OffSz = DL.getTypeSizeInBits(Off->getType());
1856
1857 std::optional<DIExpression *> RsrcExpr =
1858 DIExpression::createFragmentExpression(Dbg->getExpression(), 0,
1859 RsrcSz);
1860 std::optional<DIExpression *> OffExpr =
1861 DIExpression::createFragmentExpression(Dbg->getExpression(), RsrcSz,
1862 OffSz);
1863 if (OffExpr) {
1864 OffDbg->setExpression(*OffExpr);
1865 OffDbg->replaceVariableLocationOp(I, Off);
1866 OffDbg->insertBefore(Dbg);
1867 } else {
1868 OffDbg->eraseFromParent();
1869 }
1870 if (RsrcExpr) {
1871 Dbg->setExpression(*RsrcExpr);
1872 Dbg->replaceVariableLocationOp(I, Rsrc);
1873 } else {
1874 Dbg->replaceVariableLocationOp(I, PoisonValue::get(I->getType()));
1875 }
1876 }
1877
1878 Value *Poison = PoisonValue::get(I->getType());
1879 I->replaceUsesWithIf(Poison, [&](const Use &U) -> bool {
1880 if (const auto *UI = dyn_cast<Instruction>(U.getUser()))
1881 return SplitUsers.contains(UI);
1882 return false;
1883 });
1884
1885 if (I->use_empty()) {
1886 I->eraseFromParent();
1887 continue;
1888 }
1889 IRB.SetInsertPoint(*I->getInsertionPointAfterDef());
1890 IRB.SetCurrentDebugLocation(I->getDebugLoc());
1891 auto [Rsrc, Off] = getPtrParts(I);
1892 Value *Struct = PoisonValue::get(I->getType());
1893 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1894 Struct = IRB.CreateInsertValue(Struct, Off, 1);
1895 copyMetadata(Struct, I);
1896 Struct->takeName(I);
1897 I->replaceAllUsesWith(Struct);
1898 I->eraseFromParent();
1899 }
1900}
1901
1902void SplitPtrStructs::setAlign(CallInst *Intr, Align A, unsigned RsrcArgIdx) {
1903 LLVMContext &Ctx = Intr->getContext();
1904 Intr->addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx, A));
1905}
1906
1907void SplitPtrStructs::insertPreMemOpFence(AtomicOrdering Order,
1908 SyncScope::ID SSID) {
1909 switch (Order) {
1910 case AtomicOrdering::Release:
1911 case AtomicOrdering::AcquireRelease:
1912 case AtomicOrdering::SequentiallyConsistent:
1913 IRB.CreateFence(AtomicOrdering::Release, SSID);
1914 break;
1915 default:
1916 break;
1917 }
1918}
1919
1920void SplitPtrStructs::insertPostMemOpFence(AtomicOrdering Order,
1921 SyncScope::ID SSID) {
1922 switch (Order) {
1923 case AtomicOrdering::Acquire:
1924 case AtomicOrdering::AcquireRelease:
1925 case AtomicOrdering::SequentiallyConsistent:
1926 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1927 break;
1928 default:
1929 break;
1930 }
1931}
1932
1933Value *SplitPtrStructs::handleMemoryInst(Instruction *I, Value *Arg, Value *Ptr,
1934 Type *Ty, Align Alignment,
1935 AtomicOrdering Order, bool IsVolatile,
1936 SyncScope::ID SSID) {
1937 IRB.SetInsertPoint(I);
1938
1939 auto [Rsrc, Off] = getPtrParts(Ptr);
1941 if (Arg)
1942 Args.push_back(Arg);
1943 Args.push_back(Rsrc);
1944 Args.push_back(Off);
1945 insertPreMemOpFence(Order, SSID);
1946 // soffset is always 0 for these cases, where we always want any offset to be
1947 // part of bounds checking and we don't know which parts of the GEPs is
1948 // uniform.
1949 Args.push_back(IRB.getInt32(0));
1950
1951 uint32_t Aux = 0;
1952 if (IsVolatile)
1954 Args.push_back(IRB.getInt32(Aux));
1955
1957 if (isa<LoadInst>(I))
1958 IID = Order == AtomicOrdering::NotAtomic
1959 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1960 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1961 else if (isa<StoreInst>(I))
1962 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1963 else if (auto *RMW = dyn_cast<AtomicRMWInst>(I)) {
1964 switch (RMW->getOperation()) {
1966 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1967 break;
1968 case AtomicRMWInst::Add:
1969 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1970 break;
1971 case AtomicRMWInst::Sub:
1972 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1973 break;
1974 case AtomicRMWInst::And:
1975 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1976 break;
1977 case AtomicRMWInst::Or:
1978 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1979 break;
1980 case AtomicRMWInst::Xor:
1981 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1982 break;
1983 case AtomicRMWInst::Max:
1984 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1985 break;
1986 case AtomicRMWInst::Min:
1987 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1988 break;
1990 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1991 break;
1993 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1994 break;
1996 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
1997 break;
1999 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
2000 break;
2002 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
2003 break;
2005 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
2006 break;
2008 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
2009 break;
2010 case AtomicRMWInst::FSub: {
2012 "atomic floating point subtraction not supported for "
2013 "buffer resources and should've been expanded away");
2014 break;
2015 }
2018 "atomic floating point fmaximum not supported for "
2019 "buffer resources and should've been expanded away");
2020 break;
2021 }
2024 "atomic floating point fminimum not supported for "
2025 "buffer resources and should've been expanded away");
2026 break;
2027 }
2030 "atomic floating point fmaximumnum not supported for "
2031 "buffer resources and should've been expanded away");
2032 break;
2033 }
2036 "atomic floating point fminimumnum not supported for "
2037 "buffer resources and should've been expanded away");
2038 break;
2039 }
2042 "atomic nand not supported for buffer resources and "
2043 "should've been expanded away");
2044 break;
2048 "wrapping increment/decrement not supported for "
2049 "buffer resources and should've been expanded away");
2050 break;
2052 llvm_unreachable("Not sure how we got a bad binop");
2053 }
2054 }
2055
2056 CallInst *Call = IRB.CreateIntrinsicWithoutFolding(IID, Ty, Args);
2057 copyMetadata(Call, I);
2058 setAlign(Call, Alignment, Arg ? 1 : 0);
2059 Call->takeName(I);
2060
2061 insertPostMemOpFence(Order, SSID);
2062 // The "no moving p7 directly" rewrites ensure that this load or store won't
2063 // itself need to be split into parts.
2064 SplitUsers.insert(I);
2065 I->replaceAllUsesWith(Call);
2066 return Call;
2067}
2068
2069PtrParts SplitPtrStructs::visitInstruction(Instruction &I) {
2070 return {nullptr, nullptr};
2071}
2072
2073PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
2075 return {nullptr, nullptr};
2076 handleMemoryInst(&LI, nullptr, LI.getPointerOperand(), LI.getType(),
2077 LI.getAlign(), LI.getOrdering(), LI.isVolatile(),
2078 LI.getSyncScopeID());
2079 return {nullptr, nullptr};
2080}
2081
2082PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
2083 if (!isSplitFatPtr(SI.getPointerOperandType()))
2084 return {nullptr, nullptr};
2085 Value *Arg = SI.getValueOperand();
2086 handleMemoryInst(&SI, Arg, SI.getPointerOperand(), Arg->getType(),
2087 SI.getAlign(), SI.getOrdering(), SI.isVolatile(),
2088 SI.getSyncScopeID());
2089 return {nullptr, nullptr};
2090}
2091
2092PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
2094 return {nullptr, nullptr};
2095 Value *Arg = AI.getValOperand();
2096 handleMemoryInst(&AI, Arg, AI.getPointerOperand(), Arg->getType(),
2097 AI.getAlign(), AI.getOrdering(), AI.isVolatile(),
2098 AI.getSyncScopeID());
2099 return {nullptr, nullptr};
2100}
2101
2102// Unlike load, store, and RMW, cmpxchg needs special handling to account
2103// for the boolean argument.
2104PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
2105 Value *Ptr = AI.getPointerOperand();
2106 if (!isSplitFatPtr(Ptr->getType()))
2107 return {nullptr, nullptr};
2108 IRB.SetInsertPoint(&AI);
2109
2110 Type *Ty = AI.getNewValOperand()->getType();
2111 AtomicOrdering Order = AI.getMergedOrdering();
2112 SyncScope::ID SSID = AI.getSyncScopeID();
2113 bool IsNonTemporal = AI.getMetadata(LLVMContext::MD_nontemporal);
2114
2115 auto [Rsrc, Off] = getPtrParts(Ptr);
2116 insertPreMemOpFence(Order, SSID);
2117
2118 uint32_t Aux = 0;
2119 if (IsNonTemporal)
2120 Aux |= AMDGPU::CPol::SLC;
2121 if (AI.isVolatile())
2123 CallInst *Call = IRB.CreateIntrinsicWithoutFolding(
2124 Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
2125 {AI.getNewValOperand(), AI.getCompareOperand(), Rsrc, Off,
2126 IRB.getInt32(0), IRB.getInt32(Aux)});
2127 copyMetadata(Call, &AI);
2128 setAlign(Call, AI.getAlign(), 2);
2129 Call->takeName(&AI);
2130 insertPostMemOpFence(Order, SSID);
2131
2132 Value *Res = PoisonValue::get(AI.getType());
2133 Res = IRB.CreateInsertValue(Res, Call, 0);
2134 Value *Succeeded = IRB.CreateICmpEQ(Call, AI.getCompareOperand());
2135 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
2136 SplitUsers.insert(&AI);
2137 AI.replaceAllUsesWith(Res);
2138 return {nullptr, nullptr};
2139}
2140
2141PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &GEP) {
2142 using namespace llvm::PatternMatch;
2143 Value *Ptr = GEP.getPointerOperand();
2144 if (!isSplitFatPtr(Ptr->getType()))
2145 return {nullptr, nullptr};
2146 IRB.SetInsertPoint(&GEP);
2147
2148 auto [Rsrc, Off] = getPtrParts(Ptr);
2149 const DataLayout &DL = GEP.getDataLayout();
2150 bool IsNUW = GEP.hasNoUnsignedWrap();
2151 bool IsNUSW = GEP.hasNoUnsignedSignedWrap();
2152
2153 StructType *ResTy = cast<StructType>(GEP.getType());
2154 Type *ResRsrcTy = ResTy->getElementType(0);
2155 VectorType *ResRsrcVecTy = dyn_cast<VectorType>(ResRsrcTy);
2156 bool BroadcastsPtr = ResRsrcVecTy && !isa<VectorType>(Off->getType());
2157
2158 // In order to call emitGEPOffset() and thus not have to reimplement it,
2159 // we need the GEP result to have ptr addrspace(7) type.
2160 Type *FatPtrTy =
2161 ResRsrcTy->getWithNewType(IRB.getPtrTy(AMDGPUAS::BUFFER_FAT_POINTER));
2162 GEP.mutateType(FatPtrTy);
2163 Value *OffAccum = emitGEPOffset(&IRB, DL, &GEP);
2164 GEP.mutateType(ResTy);
2165
2166 if (BroadcastsPtr) {
2167 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
2168 Rsrc->getName());
2169 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Off,
2170 Off->getName());
2171 }
2172 if (match(OffAccum, m_Zero())) { // Constant-zero offset
2173 SplitUsers.insert(&GEP);
2174 return {Rsrc, Off};
2175 }
2176
2177 bool HasNonNegativeOff = false;
2178 if (auto *CI = dyn_cast<ConstantInt>(OffAccum)) {
2179 HasNonNegativeOff = !CI->isNegative();
2180 }
2181 Value *NewOff;
2182 if (match(Off, m_Zero())) {
2183 NewOff = OffAccum;
2184 } else {
2185 NewOff = IRB.CreateAdd(Off, OffAccum, "",
2186 /*hasNUW=*/IsNUW || (IsNUSW && HasNonNegativeOff),
2187 /*hasNSW=*/false);
2188 }
2189 copyMetadata(NewOff, &GEP);
2190 NewOff->takeName(&GEP);
2191 SplitUsers.insert(&GEP);
2192 return {Rsrc, NewOff};
2193}
2194
2195PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
2196 Value *Ptr = PI.getPointerOperand();
2197 if (!isSplitFatPtr(Ptr->getType()))
2198 return {nullptr, nullptr};
2199 IRB.SetInsertPoint(&PI);
2200
2201 Type *ResTy = PI.getType();
2202 unsigned Width = ResTy->getScalarSizeInBits();
2203
2204 auto [Rsrc, Off] = getPtrParts(Ptr);
2205 const DataLayout &DL = PI.getDataLayout();
2206 unsigned FatPtrWidth = DL.getPointerSizeInBits(AMDGPUAS::BUFFER_FAT_POINTER);
2207
2208 Value *Res;
2209 if (Width <= BufferOffsetWidth) {
2210 Res = IRB.CreateIntCast(Off, ResTy, /*isSigned=*/false,
2211 PI.getName() + ".off");
2212 } else {
2213 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.getName() + ".rsrc");
2214 Value *Shl = IRB.CreateShl(
2215 RsrcInt,
2216 ConstantExpr::getIntegerValue(ResTy, APInt(Width, BufferOffsetWidth)),
2217 "", Width >= FatPtrWidth, Width > FatPtrWidth);
2218 Value *OffCast = IRB.CreateIntCast(Off, ResTy, /*isSigned=*/false,
2219 PI.getName() + ".off");
2220 Res = IRB.CreateOr(Shl, OffCast);
2221 }
2222
2223 copyMetadata(Res, &PI);
2224 Res->takeName(&PI);
2225 SplitUsers.insert(&PI);
2226 PI.replaceAllUsesWith(Res);
2227 return {nullptr, nullptr};
2228}
2229
2230PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
2231 Value *Ptr = PA.getPointerOperand();
2232 if (!isSplitFatPtr(Ptr->getType()))
2233 return {nullptr, nullptr};
2234 IRB.SetInsertPoint(&PA);
2235
2236 auto [Rsrc, Off] = getPtrParts(Ptr);
2237 Value *Res = IRB.CreateIntCast(Off, PA.getType(), /*isSigned=*/false);
2238 copyMetadata(Res, &PA);
2239 Res->takeName(&PA);
2240 SplitUsers.insert(&PA);
2241 PA.replaceAllUsesWith(Res);
2242 return {nullptr, nullptr};
2243}
2244
2245PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
2246 if (!isSplitFatPtr(IP.getType()))
2247 return {nullptr, nullptr};
2248 IRB.SetInsertPoint(&IP);
2249 const DataLayout &DL = IP.getDataLayout();
2250 unsigned RsrcPtrWidth = DL.getPointerSizeInBits(AMDGPUAS::BUFFER_RESOURCE);
2251 Value *Int = IP.getOperand(0);
2252 Type *IntTy = Int->getType();
2253 Type *RsrcIntTy = IntTy->getWithNewBitWidth(RsrcPtrWidth);
2254 unsigned Width = IntTy->getScalarSizeInBits();
2255
2256 auto *RetTy = cast<StructType>(IP.getType());
2257 Type *RsrcTy = RetTy->getElementType(0);
2258 Type *OffTy = RetTy->getElementType(1);
2259 // inttoptr zero-extends, so narrow inputs contribute nothing to the resource
2260 // part.
2261 Value *RsrcInt;
2262 if (Width <= BufferOffsetWidth) {
2263 RsrcInt = Constant::getNullValue(RsrcIntTy);
2264 } else {
2265 Value *RsrcPart =
2266 IRB.CreateLShr(Int, ConstantInt::get(IntTy, BufferOffsetWidth));
2267 RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy, /*isSigned=*/false);
2268 }
2269 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.getName() + ".rsrc");
2270 Value *Off =
2271 IRB.CreateIntCast(Int, OffTy, /*IsSigned=*/false, IP.getName() + ".off");
2272
2273 copyMetadata(Rsrc, &IP);
2274 SplitUsers.insert(&IP);
2275 return {Rsrc, Off};
2276}
2277
2278PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &I) {
2279 // TODO(krzysz00): handle casts from ptr addrspace(7) to global pointers
2280 // by computing the effective address.
2281 if (!isSplitFatPtr(I.getType()))
2282 return {nullptr, nullptr};
2283 IRB.SetInsertPoint(&I);
2284 Value *In = I.getPointerOperand();
2285 // No-op casts preserve parts
2286 if (In->getType() == I.getType()) {
2287 auto [Rsrc, Off] = getPtrParts(In);
2288 SplitUsers.insert(&I);
2289 return {Rsrc, Off};
2290 }
2291
2292 auto *ResTy = cast<StructType>(I.getType());
2293 Type *RsrcTy = ResTy->getElementType(0);
2294 Type *OffTy = ResTy->getElementType(1);
2295 Value *ZeroOff = Constant::getNullValue(OffTy);
2296
2297 // Special case for null pointers, undef, and poison, which can be created by
2298 // address space propagation.
2299 auto *InConst = dyn_cast<Constant>(In);
2300 if (InConst && InConst->isNullValue()) {
2301 Value *NullRsrc = Constant::getNullValue(RsrcTy);
2302 SplitUsers.insert(&I);
2303 return {NullRsrc, ZeroOff};
2304 }
2305 if (isa<PoisonValue>(In)) {
2306 Value *PoisonRsrc = PoisonValue::get(RsrcTy);
2307 Value *PoisonOff = PoisonValue::get(OffTy);
2308 SplitUsers.insert(&I);
2309 return {PoisonRsrc, PoisonOff};
2310 }
2311 if (isa<UndefValue>(In)) {
2312 Value *UndefRsrc = UndefValue::get(RsrcTy);
2313 Value *UndefOff = UndefValue::get(OffTy);
2314 SplitUsers.insert(&I);
2315 return {UndefRsrc, UndefOff};
2316 }
2317
2318 if (I.getSrcAddressSpace() != AMDGPUAS::BUFFER_RESOURCE)
2320 "only buffer resources (addrspace 8) and null/poison pointers can be "
2321 "cast to buffer fat pointers (addrspace 7)");
2322 SplitUsers.insert(&I);
2323 return {In, ZeroOff};
2324}
2325
2326PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2327 Value *Lhs = Cmp.getOperand(0);
2328 if (!isSplitFatPtr(Lhs->getType()))
2329 return {nullptr, nullptr};
2330 Value *Rhs = Cmp.getOperand(1);
2331 IRB.SetInsertPoint(&Cmp);
2332 ICmpInst::Predicate Pred = Cmp.getPredicate();
2333
2334 assert((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
2335 "Pointer comparison is only equal or unequal");
2336 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2337 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2338 Value *Res = IRB.CreateICmp(Pred, LhsOff, RhsOff);
2339 copyMetadata(Res, &Cmp);
2340 Res->takeName(&Cmp);
2341 SplitUsers.insert(&Cmp);
2342 Cmp.replaceAllUsesWith(Res);
2343 return {nullptr, nullptr};
2344}
2345
2346PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &I) {
2347 if (!isSplitFatPtr(I.getType()))
2348 return {nullptr, nullptr};
2349 IRB.SetInsertPoint(&I);
2350 auto [Rsrc, Off] = getPtrParts(I.getOperand(0));
2351
2352 Value *RsrcRes = IRB.CreateFreeze(Rsrc, I.getName() + ".rsrc");
2353 copyMetadata(RsrcRes, &I);
2354 Value *OffRes = IRB.CreateFreeze(Off, I.getName() + ".off");
2355 copyMetadata(OffRes, &I);
2356 SplitUsers.insert(&I);
2357 return {RsrcRes, OffRes};
2358}
2359
2360PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &I) {
2361 if (!isSplitFatPtr(I.getType()))
2362 return {nullptr, nullptr};
2363 IRB.SetInsertPoint(&I);
2364 Value *Vec = I.getVectorOperand();
2365 Value *Idx = I.getIndexOperand();
2366 auto [Rsrc, Off] = getPtrParts(Vec);
2367
2368 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx, I.getName() + ".rsrc");
2369 copyMetadata(RsrcRes, &I);
2370 Value *OffRes = IRB.CreateExtractElement(Off, Idx, I.getName() + ".off");
2371 copyMetadata(OffRes, &I);
2372 SplitUsers.insert(&I);
2373 return {RsrcRes, OffRes};
2374}
2375
2376PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &I) {
2377 // The mutated instructions temporarily don't return vectors, and so
2378 // we need the generic getType() here to avoid crashes.
2380 return {nullptr, nullptr};
2381 IRB.SetInsertPoint(&I);
2382 Value *Vec = I.getOperand(0);
2383 Value *Elem = I.getOperand(1);
2384 Value *Idx = I.getOperand(2);
2385 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2386 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2387
2388 Value *RsrcRes =
2389 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx, I.getName() + ".rsrc");
2390 copyMetadata(RsrcRes, &I);
2391 Value *OffRes =
2392 IRB.CreateInsertElement(VecOff, ElemOff, Idx, I.getName() + ".off");
2393 copyMetadata(OffRes, &I);
2394 SplitUsers.insert(&I);
2395 return {RsrcRes, OffRes};
2396}
2397
2398PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &I) {
2399 // Cast is needed for the same reason as insertelement's.
2401 return {nullptr, nullptr};
2402 IRB.SetInsertPoint(&I);
2403
2404 Value *V1 = I.getOperand(0);
2405 Value *V2 = I.getOperand(1);
2406 ArrayRef<int> Mask = I.getShuffleMask();
2407 auto [V1Rsrc, V1Off] = getPtrParts(V1);
2408 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2409
2410 Value *RsrcRes =
2411 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask, I.getName() + ".rsrc");
2412 copyMetadata(RsrcRes, &I);
2413 Value *OffRes =
2414 IRB.CreateShuffleVector(V1Off, V2Off, Mask, I.getName() + ".off");
2415 copyMetadata(OffRes, &I);
2416 SplitUsers.insert(&I);
2417 return {RsrcRes, OffRes};
2418}
2419
2420PtrParts SplitPtrStructs::visitPHINode(PHINode &PHI) {
2421 if (!isSplitFatPtr(PHI.getType()))
2422 return {nullptr, nullptr};
2423 IRB.SetInsertPoint(*PHI.getInsertionPointAfterDef());
2424 // Phi nodes will be handled in post-processing after we've visited every
2425 // instruction. However, instead of just returning {nullptr, nullptr},
2426 // we explicitly create the temporary extractvalue operations that are our
2427 // temporary results so that they end up at the beginning of the block with
2428 // the PHIs.
2429 Value *TmpRsrc = IRB.CreateExtractValue(&PHI, 0, PHI.getName() + ".rsrc");
2430 Value *TmpOff = IRB.CreateExtractValue(&PHI, 1, PHI.getName() + ".off");
2431 Conditionals.push_back(&PHI);
2432 SplitUsers.insert(&PHI);
2433 return {TmpRsrc, TmpOff};
2434}
2435
2436PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2437 if (!isSplitFatPtr(SI.getType()))
2438 return {nullptr, nullptr};
2439 IRB.SetInsertPoint(&SI);
2440
2441 Value *Cond = SI.getCondition();
2442 Value *True = SI.getTrueValue();
2443 Value *False = SI.getFalseValue();
2444 auto [TrueRsrc, TrueOff] = getPtrParts(True);
2445 auto [FalseRsrc, FalseOff] = getPtrParts(False);
2446
2447 Value *RsrcRes =
2448 IRB.CreateSelect(Cond, TrueRsrc, FalseRsrc, SI.getName() + ".rsrc", &SI);
2449 copyMetadata(RsrcRes, &SI);
2450 Conditionals.push_back(&SI);
2451 Value *OffRes =
2452 IRB.CreateSelect(Cond, TrueOff, FalseOff, SI.getName() + ".off", &SI);
2453 copyMetadata(OffRes, &SI);
2454 SplitUsers.insert(&SI);
2455 return {RsrcRes, OffRes};
2456}
2457
2458/// Returns true if this intrinsic needs to be removed when it is
2459/// applied to `ptr addrspace(7)` values. Calls to these intrinsics are
2460/// rewritten into calls to versions of that intrinsic on the resource
2461/// descriptor.
2463 switch (IID) {
2464 default:
2465 return false;
2466 case Intrinsic::amdgcn_make_buffer_rsrc:
2467 case Intrinsic::ptrmask:
2468 case Intrinsic::invariant_start:
2469 case Intrinsic::invariant_end:
2470 case Intrinsic::launder_invariant_group:
2471 case Intrinsic::strip_invariant_group:
2472 case Intrinsic::memcpy:
2473 case Intrinsic::memcpy_inline:
2474 case Intrinsic::memmove:
2475 case Intrinsic::memset:
2476 case Intrinsic::memset_inline:
2477 case Intrinsic::experimental_memset_pattern:
2478 case Intrinsic::amdgcn_load_to_lds:
2479 case Intrinsic::amdgcn_load_async_to_lds:
2480 return true;
2481 }
2482}
2483
2484PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &I) {
2485 Intrinsic::ID IID = I.getIntrinsicID();
2486 switch (IID) {
2487 default:
2488 break;
2489 case Intrinsic::amdgcn_make_buffer_rsrc: {
2490 if (!isSplitFatPtr(I.getType()))
2491 return {nullptr, nullptr};
2492 Value *Base = I.getArgOperand(0);
2493 Value *Stride = I.getArgOperand(1);
2494 Value *NumRecords = I.getArgOperand(2);
2495 Value *Flags = I.getArgOperand(3);
2496 auto *SplitType = cast<StructType>(I.getType());
2497 Type *RsrcType = SplitType->getElementType(0);
2498 Type *OffType = SplitType->getElementType(1);
2499 IRB.SetInsertPoint(&I);
2500 Value *Rsrc = IRB.CreateIntrinsic(
2501 IID, {RsrcType, Base->getType(), NumRecords->getType()},
2502 {Base, Stride, NumRecords, Flags});
2503 copyMetadata(Rsrc, &I);
2504 Rsrc->takeName(&I);
2505 Value *Zero = Constant::getNullValue(OffType);
2506 SplitUsers.insert(&I);
2507 return {Rsrc, Zero};
2508 }
2509 case Intrinsic::ptrmask: {
2510 Value *Ptr = I.getArgOperand(0);
2511 if (!isSplitFatPtr(Ptr->getType()))
2512 return {nullptr, nullptr};
2513 Value *Mask = I.getArgOperand(1);
2514 IRB.SetInsertPoint(&I);
2515 auto [Rsrc, Off] = getPtrParts(Ptr);
2516 if (Mask->getType() != Off->getType())
2517 reportFatalUsageError("offset width is not equal to index width of fat "
2518 "pointer (data layout not set up correctly?)");
2519 Value *OffRes = IRB.CreateAnd(Off, Mask, I.getName() + ".off");
2520 copyMetadata(OffRes, &I);
2521 SplitUsers.insert(&I);
2522 return {Rsrc, OffRes};
2523 }
2524 // Pointer annotation intrinsics that, given their object-wide nature
2525 // operate on the resource part.
2526 case Intrinsic::invariant_start: {
2527 Value *Ptr = I.getArgOperand(1);
2528 if (!isSplitFatPtr(Ptr->getType()))
2529 return {nullptr, nullptr};
2530 IRB.SetInsertPoint(&I);
2531 auto [Rsrc, Off] = getPtrParts(Ptr);
2532 Type *NewTy = PointerType::get(I.getContext(), AMDGPUAS::BUFFER_RESOURCE);
2533 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {I.getOperand(0), Rsrc});
2534 copyMetadata(NewRsrc, &I);
2535 NewRsrc->takeName(&I);
2536 SplitUsers.insert(&I);
2537 I.replaceAllUsesWith(NewRsrc);
2538 return {nullptr, nullptr};
2539 }
2540 case Intrinsic::invariant_end: {
2541 Value *RealPtr = I.getArgOperand(2);
2542 if (!isSplitFatPtr(RealPtr->getType()))
2543 return {nullptr, nullptr};
2544 IRB.SetInsertPoint(&I);
2545 Value *RealRsrc = getPtrParts(RealPtr).first;
2546 Value *InvPtr = I.getArgOperand(0);
2547 Value *Size = I.getArgOperand(1);
2548 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->getType()},
2549 {InvPtr, Size, RealRsrc});
2550 copyMetadata(NewRsrc, &I);
2551 NewRsrc->takeName(&I);
2552 SplitUsers.insert(&I);
2553 I.replaceAllUsesWith(NewRsrc);
2554 return {nullptr, nullptr};
2555 }
2556 case Intrinsic::launder_invariant_group:
2557 case Intrinsic::strip_invariant_group: {
2558 Value *Ptr = I.getArgOperand(0);
2559 if (!isSplitFatPtr(Ptr->getType()))
2560 return {nullptr, nullptr};
2561 IRB.SetInsertPoint(&I);
2562 auto [Rsrc, Off] = getPtrParts(Ptr);
2563 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->getType()}, {Rsrc});
2564 copyMetadata(NewRsrc, &I);
2565 NewRsrc->takeName(&I);
2566 SplitUsers.insert(&I);
2567 return {NewRsrc, Off};
2568 }
2569 case Intrinsic::amdgcn_load_to_lds:
2570 case Intrinsic::amdgcn_load_async_to_lds: {
2571 Value *Ptr = I.getArgOperand(0);
2572 if (!isSplitFatPtr(Ptr->getType()))
2573 return {nullptr, nullptr};
2574 IRB.SetInsertPoint(&I);
2575 auto [Rsrc, Off] = getPtrParts(Ptr);
2576 Value *LDSPtr = I.getArgOperand(1);
2577 Value *LoadSize = I.getArgOperand(2);
2578 Value *ImmOff = I.getArgOperand(3);
2579 Value *Aux = I.getArgOperand(4);
2580 Value *SOffset = IRB.getInt32(0);
2581 Intrinsic::ID NewIntr =
2582 IID == Intrinsic::amdgcn_load_to_lds
2583 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2584 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2585 Instruction *NewLoad = IRB.CreateIntrinsicWithoutFolding(
2586 NewIntr, {}, {Rsrc, LDSPtr, LoadSize, Off, SOffset, ImmOff, Aux});
2587 copyMetadata(NewLoad, &I);
2588 SplitUsers.insert(&I);
2589 I.replaceAllUsesWith(NewLoad);
2590 return {nullptr, nullptr};
2591 }
2592 }
2593 return {nullptr, nullptr};
2594}
2595
2596void SplitPtrStructs::processFunction(Function &F) {
2597 ST = &TM->getSubtarget<GCNSubtarget>(F);
2598 SmallVector<Instruction *, 0> Originals(
2600 LLVM_DEBUG(dbgs() << "Splitting pointer structs in function: " << F.getName()
2601 << "\n");
2602 for (Instruction *I : Originals) {
2603 // In some cases, instruction order doesn't reflect program order,
2604 // so the visit() call will have already visited coertain instructions
2605 // by the time this loop gets to them. Avoid re-visiting these so as to,
2606 // for example, avoid processing the same conditional twice.
2607 if (SplitUsers.contains(I))
2608 continue;
2609 auto [Rsrc, Off] = visit(I);
2610 assert(((Rsrc && Off) || (!Rsrc && !Off)) &&
2611 "Can't have a resource but no offset");
2612 if (Rsrc)
2613 RsrcParts[I] = Rsrc;
2614 if (Off)
2615 OffParts[I] = Off;
2616 }
2617 processConditionals();
2618 killAndReplaceSplitInstructions(Originals);
2619
2620 // Clean up after ourselves to save on memory.
2621 RsrcParts.clear();
2622 OffParts.clear();
2623 SplitUsers.clear();
2624 Conditionals.clear();
2625 ConditionalTemps.clear();
2626}
2627
2628namespace {
2629class AMDGPULowerBufferFatPointers : public ModulePass {
2630public:
2631 static char ID;
2632
2633 AMDGPULowerBufferFatPointers() : ModulePass(ID) {}
2634
2635 bool run(Module &M, const TargetMachine &TM, GetTTIFn GetTTI, GetSEFn GetSE);
2636 bool runOnModule(Module &M) override;
2637
2638 void getAnalysisUsage(AnalysisUsage &AU) const override;
2639};
2640} // namespace
2641
2642/// Returns true if there are values that have a buffer fat pointer in them,
2643/// which means we'll need to perform rewrites on this function. As a side
2644/// effect, this will populate the type remapping cache.
2646 BufferFatPtrToStructTypeMap *TypeMap) {
2647 bool HasFatPointers = false;
2648 for (const BasicBlock &BB : F)
2649 for (const Instruction &I : BB) {
2650 HasFatPointers |= (I.getType() != TypeMap->remapType(I.getType()));
2651 // Catch null pointer constants in loads, stores, etc.
2652 for (const Value *V : I.operand_values())
2653 HasFatPointers |= (V->getType() != TypeMap->remapType(V->getType()));
2654 }
2655 return HasFatPointers;
2656}
2657
2659 BufferFatPtrToStructTypeMap *TypeMap) {
2660 Type *Ty = F.getFunctionType();
2661 return Ty != TypeMap->remapType(Ty);
2662}
2663
2664/// Move the body of `OldF` into a new function, returning it.
2666 ValueToValueMapTy &CloneMap) {
2667 bool IsIntrinsic = OldF->isIntrinsic();
2668 Function *NewF =
2669 Function::Create(NewTy, OldF->getLinkage(), OldF->getAddressSpace());
2670 NewF->copyAttributesFrom(OldF);
2671 NewF->copyMetadata(OldF, 0);
2672 NewF->takeName(OldF);
2673 NewF->updateAfterNameChange();
2675 OldF->getParent()->getFunctionList().insertAfter(OldF->getIterator(), NewF);
2676
2677 while (!OldF->empty()) {
2678 BasicBlock *BB = &OldF->front();
2679 BB->removeFromParent();
2680 BB->insertInto(NewF);
2681 CloneMap[BB] = BB;
2682 for (Instruction &I : *BB) {
2683 CloneMap[&I] = &I;
2684 }
2685 }
2686
2688 AttributeList OldAttrs = OldF->getAttributes();
2689
2690 for (auto [I, OldArg, NewArg] : enumerate(OldF->args(), NewF->args())) {
2691 CloneMap[&NewArg] = &OldArg;
2692 NewArg.takeName(&OldArg);
2693 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2694 // Temporarily mutate type of `NewArg` to allow RAUW to work.
2695 NewArg.mutateType(OldArgTy);
2696 OldArg.replaceAllUsesWith(&NewArg);
2697 NewArg.mutateType(NewArgTy);
2698
2699 AttributeSet ArgAttr = OldAttrs.getParamAttrs(I);
2700 // Intrinsics get their attributes fixed later.
2701 if (OldArgTy != NewArgTy && !IsIntrinsic)
2702 ArgAttr = ArgAttr.removeAttributes(
2703 NewF->getContext(),
2704 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2705 ArgAttrs.push_back(ArgAttr);
2706 }
2707 AttributeSet RetAttrs = OldAttrs.getRetAttrs();
2708 if (OldF->getReturnType() != NewF->getReturnType() && !IsIntrinsic)
2709 RetAttrs = RetAttrs.removeAttributes(
2710 NewF->getContext(),
2711 AttributeFuncs::typeIncompatible(NewF->getReturnType(), RetAttrs));
2712 NewF->setAttributes(AttributeList::get(
2713 NewF->getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2714 return NewF;
2715}
2716
2718 for (Argument &A : F->args())
2719 CloneMap[&A] = &A;
2720 for (BasicBlock &BB : *F) {
2721 CloneMap[&BB] = &BB;
2722 for (Instruction &I : BB)
2723 CloneMap[&I] = &I;
2724 }
2725}
2726
2727bool AMDGPULowerBufferFatPointers::run(Module &M, const TargetMachine &TM,
2728 GetTTIFn GetTTI, GetSEFn GetSE) {
2729 bool Changed = false;
2730 const DataLayout &DL = M.getDataLayout();
2731 // Record the functions which need to be remapped.
2732 // The second element of the pair indicates whether the function has to have
2733 // its arguments or return types adjusted.
2735
2736 LLVMContext &Ctx = M.getContext();
2737
2738 BufferFatPtrToStructTypeMap StructTM(DL);
2739 BufferFatPtrToIntTypeMap IntTM(DL);
2740 for (GlobalVariable &GV : make_early_inc_range(M.globals())) {
2741 if (GV.getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER) {
2742 // FIXME: Use DiagnosticInfo unsupported but it requires a Function
2743 Ctx.emitError("global variables with a buffer fat pointer address "
2744 "space (7) are not supported");
2745 GV.replaceAllUsesWith(PoisonValue::get(GV.getType()));
2746 GV.eraseFromParent();
2747 Changed = true;
2748 continue;
2749 }
2750
2751 Type *VT = GV.getValueType();
2752 if (VT != StructTM.remapType(VT)) {
2753 // FIXME: Use DiagnosticInfo unsupported but it requires a Function
2754 Ctx.emitError("global variables that contain buffer fat pointers "
2755 "(address space 7 pointers) are unsupported. Use "
2756 "buffer resource pointers (address space 8) instead");
2757 GV.replaceAllUsesWith(PoisonValue::get(GV.getType()));
2758 GV.eraseFromParent();
2759 Changed = true;
2760 continue;
2761 }
2762 }
2763
2764 {
2765 // Collect all constant exprs and aggregates referenced by any function.
2767 for (Function &F : M.functions())
2768 for (Instruction &I : instructions(F))
2769 for (Value *Op : I.operands())
2771 Worklist.push_back(cast<Constant>(Op));
2772
2773 // Recursively look for any referenced buffer pointer constants.
2774 SmallPtrSet<Constant *, 8> Visited;
2775 SetVector<Constant *> BufferFatPtrConsts;
2776 while (!Worklist.empty()) {
2777 Constant *C = Worklist.pop_back_val();
2778 if (!Visited.insert(C).second)
2779 continue;
2780 if (isBufferFatPtrOrVector(C->getType()))
2781 BufferFatPtrConsts.insert(C);
2782 for (Value *Op : C->operands())
2784 Worklist.push_back(cast<Constant>(Op));
2785 }
2786
2787 // Expand all constant expressions using fat buffer pointers to
2788 // instructions.
2790 BufferFatPtrConsts.getArrayRef(), /*RestrictToFunc=*/nullptr,
2791 /*RemoveDeadConstants=*/false, /*IncludeSelf=*/true);
2792 }
2793
2794 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM, DL,
2795 M.getContext());
2796 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(
2797 DL, M.getContext(), &TM);
2798 for (Function &F : M.functions()) {
2799 bool InterfaceChange = hasFatPointerInterface(F, &StructTM);
2800 bool BodyChanges = containsBufferFatPointers(F, &StructTM);
2801 const TargetTransformInfo *TTI = GetTTI(F);
2802 ScalarEvolution *SE = GetSE(F);
2803 Changed |= MemOpsRewrite.processFunction(F, TTI, SE);
2804 if (InterfaceChange || BodyChanges) {
2805 NeedsRemap.push_back(std::make_pair(&F, InterfaceChange));
2806 Changed |= BufferContentsTypeRewrite.processFunction(F, SE);
2807 }
2808 }
2809 if (NeedsRemap.empty())
2810 return Changed;
2811
2812 SmallVector<Function *> NeedsPostProcess;
2813 SmallVector<Function *> Intrinsics;
2814 // Keep one big map so as to memoize constants across functions.
2815 ValueToValueMapTy CloneMap;
2816 FatPtrConstMaterializer Materializer(&StructTM, CloneMap);
2817
2818 ValueMapper LowerInFuncs(CloneMap, RF_None, &StructTM, &Materializer);
2819 for (auto [F, InterfaceChange] : NeedsRemap) {
2820 Function *NewF = F;
2821 if (InterfaceChange)
2823 F, cast<FunctionType>(StructTM.remapType(F->getFunctionType())),
2824 CloneMap);
2825 else
2826 makeCloneInPraceMap(F, CloneMap);
2827 LowerInFuncs.remapFunction(*NewF);
2828 if (NewF->isIntrinsic())
2829 Intrinsics.push_back(NewF);
2830 else
2831 NeedsPostProcess.push_back(NewF);
2832 if (InterfaceChange) {
2833 F->replaceAllUsesWith(NewF);
2834 F->eraseFromParent();
2835 }
2836 Changed = true;
2837 }
2838 StructTM.clear();
2839 IntTM.clear();
2840 CloneMap.clear();
2841
2842 SplitPtrStructs Splitter(DL, M.getContext(), &TM);
2843 for (Function *F : NeedsPostProcess)
2844 Splitter.processFunction(*F);
2845 for (Function *F : Intrinsics) {
2846 // use_empty() can also occur with cases like masked load, which will
2847 // have been rewritten out of the module by now but not erased.
2848 if (F->use_empty() || isRemovablePointerIntrinsic(F->getIntrinsicID())) {
2849 F->eraseFromParent();
2850 } else {
2851 std::optional<Function *> NewF = Intrinsic::remangleIntrinsicFunction(F);
2852 if (NewF)
2853 F->replaceAllUsesWith(*NewF);
2854 }
2855 }
2856 return Changed;
2857}
2858
2859bool AMDGPULowerBufferFatPointers::runOnModule(Module &M) {
2860 TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
2861 const TargetMachine &TM = TPC.getTM<TargetMachine>();
2862 auto GetTTI = [&](Function &F) -> const TargetTransformInfo * {
2863 if (F.isDeclaration())
2864 return nullptr;
2865 return &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
2866 };
2867 auto GetSE = [&](Function &F) -> ScalarEvolution * {
2868 if (F.isDeclaration())
2869 return nullptr;
2870 return &getAnalysis<ScalarEvolutionWrapperPass>(F).getSE();
2871 };
2872 return run(M, TM, GetTTI, GetSE);
2873}
2874
2875char AMDGPULowerBufferFatPointers::ID = 0;
2876
2877char &llvm::AMDGPULowerBufferFatPointersID = AMDGPULowerBufferFatPointers::ID;
2878
2879void AMDGPULowerBufferFatPointers::getAnalysisUsage(AnalysisUsage &AU) const {
2883}
2884
2885#define PASS_DESC "Lower buffer fat pointer operations to buffer resources"
2886INITIALIZE_PASS_BEGIN(AMDGPULowerBufferFatPointers, DEBUG_TYPE, PASS_DESC,
2887 false, false)
2891INITIALIZE_PASS_END(AMDGPULowerBufferFatPointers, DEBUG_TYPE, PASS_DESC, false,
2892 false)
2893#undef PASS_DESC
2894
2896 return new AMDGPULowerBufferFatPointers();
2897}
2898
2901 auto &FA = MA.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
2902 auto GetTTI = [&](Function &F) -> const TargetTransformInfo * {
2903 if (F.isDeclaration())
2904 return nullptr;
2905 return &FA.getResult<TargetIRAnalysis>(F);
2906 };
2907 auto GetSE = [&](Function &F) -> ScalarEvolution * {
2908 if (F.isDeclaration())
2909 return nullptr;
2910 return &FA.getResult<ScalarEvolutionAnalysis>(F);
2911 };
2912 return AMDGPULowerBufferFatPointers().run(M, TM, GetTTI, GetSE)
2915}
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:577
@ Length
Definition DWP.cpp:577
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