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