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 // All-1s is (per ISA or as a consequence of the bonud)check rules, depending
890 // on arcihtecture) no bounds check.
891 if (NumRecords->isAllOnesValue())
892 Result.NoPartialOOB = true;
893
894 const SCEV *BoundsDiff;
895 if (ST->has45BitNumRecordsBufferResource()) {
896 const SCEV *PtrDiffExt =
897 SE->getNoopOrZeroExtend(PtrDiff, NumRecords->getType());
898 BoundsDiff = SE->getMinusSCEV(NumRecords, PtrDiffExt);
899 } else {
900 const SCEV *NumRecordsI32 =
901 SE->getTruncateOrNoop(NumRecords, IRB.getInt32Ty());
902 BoundsDiff = SE->getMinusSCEV(NumRecordsI32, PtrDiff);
903 }
904
905 if (SE->getSignedRangeMin(BoundsDiff).sge(TypeSize) ||
906 SE->isKnownNonPositive(BoundsDiff))
907 Result.NoPartialOOB = true;
908 return Result;
909}
910
912LegalizeBufferContentTypesVisitor::maxIntrinsicWidth(Type *T, Align A,
913 OobProperties OobProps) {
914 Align Result(16);
915 if (!ST->hasUnalignedBufferAccessEnabled() && A < Align(4))
916 Result = A;
917 auto *VT = dyn_cast<VectorType>(T);
918 if (!ST->hasRelaxedBufferOOBMode() && VT) {
919 TypeSize ElemBits = DL.getTypeSizeInBits(VT->getElementType());
920 if (ElemBits.isKnownMultipleOf(32)) {
921 // Word-sized operations are bounds-checked per word. So, the only case we
922 // have to worry about is stores that start out of bounds and then go in,
923 // and those can only become in-bounds on a multiple of their alignment.
924 // Therefore, we can use the declared alignment of the operation as the
925 // maximum width, rounding up to 4.
926 if (!OobProps.NoWrapFromMax)
927 Result = std::min(Result, std::max(A, Align(4)));
928 } else if ((ElemBits.isKnownMultipleOf(8) ||
929 isPowerOf2_64(ElemBits.getKnownMinValue()))) {
930 // To ensure correct behavior for sub-word types, we must always scalarize
931 // unaligned loads of sub-word types. For example, if you load
932 // a <4 x i8> from offset 7 in an 8-byte buffer, expecting the vector
933 // to be padded out with 0s after that last byte, you'll get all 0s
934 // instead. To prevent this behavior when not requested, de-vectorize such
935 // loads.
936 //
937 // If we knew that the value that triggers bounds checks was a multiple of
938 // 4 along with the access being word-aligned, we could avoid the
939 // scalarization here, as the bitcast wouldn't change any check behavior,
940 // but we don't currently try to analyze this.
941 //
942 // Strict OOB checking isn't supported if the size of each element is a
943 // non-power-of-2 value less than 8, since there's no feasible way to
944 // apply such a strict bounds check.
945 if (!OobProps.NoPartialOOB)
946 Result =
947 commonAlignment(Result, divideCeil(ElemBits.getKnownMinValue(), 8));
948 }
949 }
950 return Result.value() * 8;
951}
952
953Type *LegalizeBufferContentTypesVisitor::legalNonAggregateForMemOp(
954 Type *T, uint64_t MaxWidth) {
955 TypeSize Size = DL.getTypeStoreSizeInBits(T);
956 // Implicitly zero-extend to the next byte if needed.
957 if (!DL.typeSizeEqualsStoreSize(T))
958 T = IRB.getIntNTy(Size.getFixedValue());
959 Type *ElemTy = T->getScalarType();
961 // Pointers are always big enough, and we'll let scalable vectors through to
962 // fail in codegen.
963 return T;
964 }
965 unsigned ElemSize = DL.getTypeSizeInBits(ElemTy).getFixedValue();
966 if (isPowerOf2_32(ElemSize) && ElemSize >= 16 && ElemSize <= MaxWidth) {
967 // [vectors of] anything that's 16/32/64/128 bits can be cast and split into
968 // legal buffer operations, except that we might need to cut them into
969 // smaller values if we're not allowed to do unaligned vector loads.
970 return T;
971 }
972 Type *BestVectorElemType = nullptr;
973 if (Size.isKnownMultipleOf(32) && MaxWidth >= 32)
974 BestVectorElemType = IRB.getInt32Ty();
975 else if (Size.isKnownMultipleOf(16) && MaxWidth >= 16)
976 BestVectorElemType = IRB.getInt16Ty();
977 else
978 BestVectorElemType = IRB.getInt8Ty();
979 unsigned NumCastElems =
980 Size.getFixedValue() / BestVectorElemType->getIntegerBitWidth();
981 if (NumCastElems == 1)
982 return BestVectorElemType;
983 return FixedVectorType::get(BestVectorElemType, NumCastElems);
984}
985
986Value *LegalizeBufferContentTypesVisitor::makeLegalNonAggregate(
987 Value *V, Type *TargetType, const Twine &Name) {
988 Type *SourceType = V->getType();
989 TypeSize SourceSize = DL.getTypeSizeInBits(SourceType);
990 TypeSize TargetSize = DL.getTypeSizeInBits(TargetType);
991 if (SourceSize != TargetSize) {
992 Type *ShortScalarTy = IRB.getIntNTy(SourceSize.getFixedValue());
993 Type *ByteScalarTy = IRB.getIntNTy(TargetSize.getFixedValue());
994 Value *AsScalar = IRB.CreateBitCast(V, ShortScalarTy, Name + ".as.scalar");
995 Value *Zext = IRB.CreateZExt(AsScalar, ByteScalarTy, Name + ".zext");
996 V = Zext;
997 SourceType = ByteScalarTy;
998 }
999 return IRB.CreateBitCast(V, TargetType, Name + ".legal");
1000}
1001
1002Value *LegalizeBufferContentTypesVisitor::makeIllegalNonAggregate(
1003 Value *V, Type *OrigType, const Twine &Name) {
1004 Type *LegalType = V->getType();
1005 TypeSize LegalSize = DL.getTypeSizeInBits(LegalType);
1006 TypeSize OrigSize = DL.getTypeSizeInBits(OrigType);
1007 if (LegalSize != OrigSize) {
1008 Type *ShortScalarTy = IRB.getIntNTy(OrigSize.getFixedValue());
1009 Type *ByteScalarTy = IRB.getIntNTy(LegalSize.getFixedValue());
1010 Value *AsScalar = IRB.CreateBitCast(V, ByteScalarTy, Name + ".bytes.cast");
1011 Value *Trunc = IRB.CreateTrunc(AsScalar, ShortScalarTy, Name + ".trunc");
1012 return IRB.CreateBitCast(Trunc, OrigType, Name + ".orig");
1013 }
1014 return IRB.CreateBitCast(V, OrigType, Name + ".real.ty");
1015}
1016
1017Type *LegalizeBufferContentTypesVisitor::intrinsicTypeFor(Type *LegalType) {
1018 auto *VT = dyn_cast<FixedVectorType>(LegalType);
1019 if (!VT)
1020 return LegalType;
1021 Type *ET = VT->getElementType();
1022 // Explicitly return the element type of 1-element vectors because the
1023 // underlying intrinsics don't like <1 x T> even though it's a synonym for T.
1024 if (VT->getNumElements() == 1)
1025 return ET;
1026 if (DL.getTypeSizeInBits(LegalType) == 96 && DL.getTypeSizeInBits(ET) < 32)
1027 return FixedVectorType::get(IRB.getInt32Ty(), 3);
1028 if (ET->isIntegerTy(8)) {
1029 switch (VT->getNumElements()) {
1030 default:
1031 return LegalType; // Let it crash later
1032 case 1:
1033 return IRB.getInt8Ty();
1034 case 2:
1035 return IRB.getInt16Ty();
1036 case 4:
1037 return IRB.getInt32Ty();
1038 case 8:
1039 return FixedVectorType::get(IRB.getInt32Ty(), 2);
1040 case 16:
1041 return FixedVectorType::get(IRB.getInt32Ty(), 4);
1042 }
1043 }
1044 return LegalType;
1045}
1046
1047void LegalizeBufferContentTypesVisitor::getVecSlices(
1048 Type *T, uint64_t MaxWidth, SmallVectorImpl<VecSlice> &Slices) {
1049 Slices.clear();
1050 auto *VT = dyn_cast<FixedVectorType>(T);
1051 if (!VT)
1052 return;
1053
1054 uint64_t ElemBitWidth =
1055 DL.getTypeSizeInBits(VT->getElementType()).getFixedValue();
1056
1057 uint64_t ElemsPer4Words = 128 / ElemBitWidth;
1058 uint64_t ElemsPer2Words = ElemsPer4Words / 2;
1059 uint64_t ElemsPerWord = ElemsPer2Words / 2;
1060 uint64_t ElemsPerShort = ElemsPerWord / 2;
1061 uint64_t ElemsPerByte = ElemsPerShort / 2;
1062 // If the elements evenly pack into 32-bit words, we can use 3-word stores,
1063 // such as for <6 x bfloat> or <3 x i32>, but we can't dot his for, for
1064 // example, <3 x i64>, since that's not slicing.
1065 uint64_t ElemsPer3Words = ElemsPerWord * 3;
1066
1067 uint64_t TotalElems = VT->getNumElements();
1068 uint64_t Index = 0;
1069 auto TrySlice = [&](unsigned MaybeLen, unsigned Width) {
1070 if (MaybeLen > 0 && Width <= MaxWidth && Index + MaybeLen <= TotalElems) {
1071 VecSlice Slice{/*Index=*/Index, /*Length=*/MaybeLen};
1072 Slices.push_back(Slice);
1073 Index += MaybeLen;
1074 return true;
1075 }
1076 return false;
1077 };
1078 while (Index < TotalElems) {
1079 TrySlice(ElemsPer4Words, 128) || TrySlice(ElemsPer3Words, 96) ||
1080 TrySlice(ElemsPer2Words, 64) || TrySlice(ElemsPerWord, 32) ||
1081 TrySlice(ElemsPerShort, 16) || TrySlice(ElemsPerByte, 8);
1082 }
1083}
1084
1085Value *LegalizeBufferContentTypesVisitor::extractSlice(Value *Vec, VecSlice S,
1086 const Twine &Name) {
1087 auto *VecVT = dyn_cast<FixedVectorType>(Vec->getType());
1088 if (!VecVT)
1089 return Vec;
1090 if (S.Length == VecVT->getNumElements() && S.Index == 0)
1091 return Vec;
1092 if (S.Length == 1)
1093 return IRB.CreateExtractElement(Vec, S.Index,
1094 Name + ".slice." + Twine(S.Index));
1095 SmallVector<int> Mask = llvm::to_vector(
1096 llvm::iota_range<int>(S.Index, S.Index + S.Length, /*Inclusive=*/false));
1097 return IRB.CreateShuffleVector(Vec, Mask, Name + ".slice." + Twine(S.Index));
1098}
1099
1100Value *LegalizeBufferContentTypesVisitor::insertSlice(Value *Whole, Value *Part,
1101 VecSlice S,
1102 const Twine &Name) {
1103 auto *WholeVT = dyn_cast<FixedVectorType>(Whole->getType());
1104 if (!WholeVT)
1105 return Part;
1106 if (S.Length == WholeVT->getNumElements() && S.Index == 0)
1107 return Part;
1108 if (S.Length == 1) {
1109 return IRB.CreateInsertElement(Whole, Part, S.Index,
1110 Name + ".slice." + Twine(S.Index));
1111 }
1112 int NumElems = cast<FixedVectorType>(Whole->getType())->getNumElements();
1113
1114 // Extend the slice with poisons to make the main shufflevector happy.
1115 SmallVector<int> ExtPartMask(NumElems, -1);
1116 for (auto [I, E] : llvm::enumerate(
1117 MutableArrayRef<int>(ExtPartMask).take_front(S.Length))) {
1118 E = I;
1119 }
1120 Value *ExtPart = IRB.CreateShuffleVector(Part, ExtPartMask,
1121 Name + ".ext." + Twine(S.Index));
1122
1123 SmallVector<int> Mask =
1124 llvm::to_vector(llvm::iota_range<int>(0, NumElems, /*Inclusive=*/false));
1125 for (auto [I, E] :
1126 llvm::enumerate(MutableArrayRef<int>(Mask).slice(S.Index, S.Length)))
1127 E = I + NumElems;
1128 return IRB.CreateShuffleVector(Whole, ExtPart, Mask,
1129 Name + ".parts." + Twine(S.Index));
1130}
1131
1132bool LegalizeBufferContentTypesVisitor::visitLoadImpl(
1133 LoadInst &OrigLI, Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1134 uint64_t AggByteOff, Value *&Result, const Twine &Name) {
1135 if (auto *ST = dyn_cast<StructType>(PartType)) {
1136 const StructLayout *Layout = DL.getStructLayout(ST);
1137 bool Changed = false;
1138 for (auto [I, ElemTy, Offset] :
1139 llvm::enumerate(ST->elements(), Layout->getMemberOffsets())) {
1140 AggIdxs.push_back(I);
1141 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1142 AggByteOff + Offset.getFixedValue(), Result,
1143 Name + "." + Twine(I));
1144 AggIdxs.pop_back();
1145 }
1146 return Changed;
1147 }
1148 if (auto *AT = dyn_cast<ArrayType>(PartType)) {
1149 Type *ElemTy = AT->getElementType();
1150 if (!ElemTy->isSingleValueType() || !DL.typeSizeEqualsStoreSize(ElemTy) ||
1151 ElemTy->isVectorTy()) {
1152 TypeSize ElemAllocSize = DL.getTypeAllocSize(ElemTy);
1153 bool Changed = false;
1154 for (auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1155 /*Inclusive=*/false)) {
1156 AggIdxs.push_back(I);
1157 Changed |= visitLoadImpl(OrigLI, ElemTy, AggIdxs,
1158 AggByteOff + I * ElemAllocSize.getFixedValue(),
1159 Result, Name + Twine(I));
1160 AggIdxs.pop_back();
1161 }
1162 return Changed;
1163 }
1164 }
1165
1166 // Typical case
1167
1168 Align PartAlign = commonAlignment(OrigLI.getAlign(), AggByteOff);
1169 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1170 OobProperties OobProps =
1171 analyzeOobProperties(OrigLI.getPointerOperand(), PartType, AggByteOff);
1172 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1173 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1174
1175 SmallVector<VecSlice> Slices;
1176 getVecSlices(LegalType, MaxWidth, Slices);
1177 bool HasSlices = Slices.size() > 1;
1178 bool IsAggPart = !AggIdxs.empty();
1179 Value *LoadsRes;
1180 if (!HasSlices && !IsAggPart) {
1181 Type *LoadableType = intrinsicTypeFor(LegalType);
1182 if (LoadableType == PartType)
1183 return false;
1184
1185 IRB.SetInsertPoint(&OrigLI);
1186 auto *NLI = cast<LoadInst>(OrigLI.clone());
1187 NLI->mutateType(LoadableType);
1188 NLI = IRB.Insert(NLI);
1189 NLI->setName(Name + ".loadable");
1190
1191 LoadsRes = IRB.CreateBitCast(NLI, LegalType, Name + ".from.loadable");
1192 } else {
1193 IRB.SetInsertPoint(&OrigLI);
1194 LoadsRes = PoisonValue::get(LegalType);
1195 Value *OrigPtr = OrigLI.getPointerOperand();
1196 // If we're needing to spill something into more than one load, its legal
1197 // type will be a vector (ex. an i256 load will have LegalType = <8 x i32>).
1198 // But if we're already a scalar (which can happen if we're splitting up a
1199 // struct), the element type will be the legal type itself.
1200 Type *ElemType = LegalType->getScalarType();
1201 unsigned ElemBytes = DL.getTypeStoreSize(ElemType);
1202 AAMDNodes AANodes = OrigLI.getAAMetadata();
1203 if (IsAggPart && Slices.empty())
1204 Slices.push_back(VecSlice{/*Index=*/0, /*Length=*/1});
1205 for (VecSlice S : Slices) {
1206 Type *SliceType =
1207 S.Length != 1 ? FixedVectorType::get(ElemType, S.Length) : ElemType;
1208 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1209 // You can't reasonably expect loads to wrap around the edge of memory.
1210 Value *NewPtr = IRB.CreateGEP(
1211 IRB.getInt8Ty(), OrigLI.getPointerOperand(), IRB.getInt32(ByteOffset),
1212 OrigPtr->getName() + ".off.ptr." + Twine(ByteOffset),
1215 Type *LoadableType = intrinsicTypeFor(SliceType);
1216 LoadInst *NewLI = IRB.CreateAlignedLoad(
1217 LoadableType, NewPtr, commonAlignment(OrigLI.getAlign(), ByteOffset),
1218 Name + ".off." + Twine(ByteOffset));
1219 copyMetadataForLoad(*NewLI, OrigLI);
1220 NewLI->setAAMetadata(
1221 AANodes.adjustForAccess(ByteOffset, LoadableType, DL));
1222 NewLI->setAtomic(OrigLI.getOrdering(), OrigLI.getSyncScopeID());
1223 NewLI->setVolatile(OrigLI.isVolatile());
1224 Value *Loaded = IRB.CreateBitCast(NewLI, SliceType,
1225 NewLI->getName() + ".from.loadable");
1226 LoadsRes = insertSlice(LoadsRes, Loaded, S, Name);
1227 }
1228 }
1229 if (LegalType != ArrayAsVecType)
1230 LoadsRes = makeIllegalNonAggregate(LoadsRes, ArrayAsVecType, Name);
1231 if (ArrayAsVecType != PartType)
1232 LoadsRes = vectorToArray(LoadsRes, PartType, Name);
1233
1234 if (IsAggPart)
1235 Result = IRB.CreateInsertValue(Result, LoadsRes, AggIdxs, Name);
1236 else
1237 Result = LoadsRes;
1238 return true;
1239}
1240
1241bool LegalizeBufferContentTypesVisitor::visitLoadInst(LoadInst &LI) {
1243 return false;
1244
1245 SmallVector<uint32_t> AggIdxs;
1246 Type *OrigType = LI.getType();
1247 Value *Result = PoisonValue::get(OrigType);
1248 bool Changed = visitLoadImpl(LI, OrigType, AggIdxs, 0, Result, LI.getName());
1249 if (!Changed)
1250 return false;
1251 Result->takeName(&LI);
1252 LI.replaceAllUsesWith(Result);
1253 LI.eraseFromParent();
1254 return Changed;
1255}
1256
1257std::pair<bool, bool> LegalizeBufferContentTypesVisitor::visitStoreImpl(
1258 StoreInst &OrigSI, Type *PartType, SmallVectorImpl<uint32_t> &AggIdxs,
1259 uint64_t AggByteOff, const Twine &Name) {
1260 if (auto *ST = dyn_cast<StructType>(PartType)) {
1261 const StructLayout *Layout = DL.getStructLayout(ST);
1262 bool Changed = false;
1263 for (auto [I, ElemTy, Offset] :
1264 llvm::enumerate(ST->elements(), Layout->getMemberOffsets())) {
1265 AggIdxs.push_back(I);
1266 Changed |= std::get<0>(visitStoreImpl(OrigSI, ElemTy, AggIdxs,
1267 AggByteOff + Offset.getFixedValue(),
1268 Name + "." + Twine(I)));
1269 AggIdxs.pop_back();
1270 }
1271 return std::make_pair(Changed, /*ModifiedInPlace=*/false);
1272 }
1273 if (auto *AT = dyn_cast<ArrayType>(PartType)) {
1274 Type *ElemTy = AT->getElementType();
1275 if (!ElemTy->isSingleValueType() || !DL.typeSizeEqualsStoreSize(ElemTy) ||
1276 ElemTy->isVectorTy()) {
1277 TypeSize ElemAllocSize = DL.getTypeAllocSize(ElemTy);
1278 bool Changed = false;
1279 for (auto I : llvm::iota_range<uint32_t>(0, AT->getNumElements(),
1280 /*Inclusive=*/false)) {
1281 AggIdxs.push_back(I);
1282 Changed |= std::get<0>(visitStoreImpl(
1283 OrigSI, ElemTy, AggIdxs,
1284 AggByteOff + I * ElemAllocSize.getFixedValue(), Name + Twine(I)));
1285 AggIdxs.pop_back();
1286 }
1287 return std::make_pair(Changed, /*ModifiedInPlace=*/false);
1288 }
1289 }
1290
1291 Value *OrigData = OrigSI.getValueOperand();
1292 Value *NewData = OrigData;
1293
1294 bool IsAggPart = !AggIdxs.empty();
1295 if (IsAggPart)
1296 NewData = IRB.CreateExtractValue(NewData, AggIdxs, Name);
1297
1298 Type *ArrayAsVecType = scalarArrayTypeAsVector(PartType);
1299 if (ArrayAsVecType != PartType) {
1300 NewData = arrayToVector(NewData, ArrayAsVecType, Name);
1301 }
1302
1303 Align PartAlign = commonAlignment(OrigSI.getAlign(), AggByteOff);
1304 OobProperties OobProps =
1305 analyzeOobProperties(OrigSI.getPointerOperand(), PartType, AggByteOff);
1306 uint64_t MaxWidth = maxIntrinsicWidth(ArrayAsVecType, PartAlign, OobProps);
1307 Type *LegalType = legalNonAggregateForMemOp(ArrayAsVecType, MaxWidth);
1308 if (LegalType != ArrayAsVecType) {
1309 NewData = makeLegalNonAggregate(NewData, LegalType, Name);
1310 }
1311
1312 SmallVector<VecSlice> Slices;
1313 getVecSlices(LegalType, MaxWidth, Slices);
1314 bool NeedToSplit = Slices.size() > 1 || IsAggPart;
1315 if (!NeedToSplit) {
1316 Type *StorableType = intrinsicTypeFor(LegalType);
1317 if (StorableType == PartType)
1318 return std::make_pair(/*Changed=*/false, /*ModifiedInPlace=*/false);
1319 NewData = IRB.CreateBitCast(NewData, StorableType, Name + ".storable");
1320 OrigSI.setOperand(0, NewData);
1321 return std::make_pair(/*Changed=*/true, /*ModifiedInPlace=*/true);
1322 }
1323
1324 Value *OrigPtr = OrigSI.getPointerOperand();
1325 Type *ElemType = LegalType->getScalarType();
1326 if (IsAggPart && Slices.empty())
1327 Slices.push_back(VecSlice{/*Index=*/0, /*Length=*/1});
1328 unsigned ElemBytes = DL.getTypeStoreSize(ElemType);
1329 AAMDNodes AANodes = OrigSI.getAAMetadata();
1330 for (VecSlice S : Slices) {
1331 Type *SliceType =
1332 S.Length != 1 ? FixedVectorType::get(ElemType, S.Length) : ElemType;
1333 int64_t ByteOffset = AggByteOff + S.Index * ElemBytes;
1334 Value *NewPtr = IRB.CreateGEP(
1335 IRB.getInt8Ty(), OrigPtr, IRB.getInt32(ByteOffset),
1336 OrigPtr->getName() + ".part." + Twine(S.Index),
1339 Value *DataSlice = extractSlice(NewData, S, Name);
1340 Type *StorableType = intrinsicTypeFor(SliceType);
1341 DataSlice = IRB.CreateBitCast(DataSlice, StorableType,
1342 DataSlice->getName() + ".storable");
1343 auto *NewSI = cast<StoreInst>(OrigSI.clone());
1344 NewSI->setAlignment(commonAlignment(OrigSI.getAlign(), ByteOffset));
1345 IRB.Insert(NewSI);
1346 NewSI->setOperand(0, DataSlice);
1347 NewSI->setOperand(1, NewPtr);
1348 NewSI->setAAMetadata(AANodes.adjustForAccess(ByteOffset, StorableType, DL));
1349 }
1350 return std::make_pair(/*Changed=*/true, /*ModifiedInPlace=*/false);
1351}
1352
1353bool LegalizeBufferContentTypesVisitor::visitStoreInst(StoreInst &SI) {
1354 if (SI.getPointerAddressSpace() != AMDGPUAS::BUFFER_FAT_POINTER)
1355 return false;
1356 IRB.SetInsertPoint(&SI);
1357 SmallVector<uint32_t> AggIdxs;
1358 Value *OrigData = SI.getValueOperand();
1359 auto [Changed, ModifiedInPlace] =
1360 visitStoreImpl(SI, OrigData->getType(), AggIdxs, 0, OrigData->getName());
1361 if (Changed && !ModifiedInPlace)
1362 SI.eraseFromParent();
1363 return Changed;
1364}
1365
1366bool LegalizeBufferContentTypesVisitor::visitAddrSpaceCastInst(
1367 AddrSpaceCastInst &AI) {
1370 return false;
1371 Value *Src = AI.getPointerOperand();
1372 auto Record = ZeroBasePointerToNumRecords.find(Src);
1373 if (Record != ZeroBasePointerToNumRecords.end())
1374 ZeroBasePointerToNumRecords.insert({&AI, Record->second});
1375 else
1376 ZeroBasePointerToNumRecords.insert({&AI, nullptr});
1377 return false;
1378}
1379
1380bool LegalizeBufferContentTypesVisitor::visitIntrinsicInst(IntrinsicInst &II) {
1381 if (II.getIntrinsicID() != Intrinsic::amdgcn_make_buffer_rsrc)
1382 return false;
1383 ZeroBasePointerToNumRecords.insert({&II, II.getOperand(2)});
1384 return false;
1385}
1386
1387bool LegalizeBufferContentTypesVisitor::processFunction(Function &F,
1388 ScalarEvolution *SE) {
1389 this->SE = SE;
1390 ST = &TM->getSubtarget<GCNSubtarget>(F);
1391 bool Changed = false;
1392 for (Instruction &I : make_early_inc_range(instructions(F))) {
1393 Changed |= visit(I);
1394 }
1395 ZeroBasePointerToNumRecords.clear();
1396 this->SE = nullptr;
1397 return Changed;
1398}
1399
1400/// Return the ptr addrspace(8) and i32 (resource and offset parts) in a lowered
1401/// buffer fat pointer constant.
1402static std::pair<Constant *, Constant *>
1404 assert(isSplitFatPtr(C->getType()) && "Not a split fat buffer pointer");
1405 return std::make_pair(C->getAggregateElement(0u), C->getAggregateElement(1u));
1406}
1407
1408namespace {
1409/// Handle the remapping of ptr addrspace(7) constants.
1410class FatPtrConstMaterializer final : public ValueMaterializer {
1411 BufferFatPtrToStructTypeMap *TypeMap;
1412 // An internal mapper that is used to recurse into the arguments of constants.
1413 // While the documentation for `ValueMapper` specifies not to use it
1414 // recursively, examination of the logic in mapValue() shows that it can
1415 // safely be used recursively when handling constants, like it does in its own
1416 // logic.
1417 ValueMapper InternalMapper;
1418
1419 Constant *materializeBufferFatPtrConst(Constant *C);
1420
1421public:
1422 // UnderlyingMap is the value map this materializer will be filling.
1423 FatPtrConstMaterializer(BufferFatPtrToStructTypeMap *TypeMap,
1424 ValueToValueMapTy &UnderlyingMap)
1425 : TypeMap(TypeMap),
1426 InternalMapper(UnderlyingMap, RF_None, TypeMap, this) {}
1427 ~FatPtrConstMaterializer() = default;
1428
1429 Value *materialize(Value *V) override;
1430};
1431} // namespace
1432
1433Constant *FatPtrConstMaterializer::materializeBufferFatPtrConst(Constant *C) {
1434 Type *SrcTy = C->getType();
1435 auto *NewTy = dyn_cast<StructType>(TypeMap->remapType(SrcTy));
1436 if (C->isNullValue())
1437 return ConstantAggregateZero::getNullValue(NewTy);
1438 if (isa<PoisonValue>(C)) {
1439 return ConstantStruct::get(NewTy,
1440 {PoisonValue::get(NewTy->getElementType(0)),
1441 PoisonValue::get(NewTy->getElementType(1))});
1442 }
1443 if (isa<UndefValue>(C)) {
1444 return ConstantStruct::get(NewTy,
1445 {UndefValue::get(NewTy->getElementType(0)),
1446 UndefValue::get(NewTy->getElementType(1))});
1447 }
1448
1449 if (auto *VC = dyn_cast<ConstantVector>(C)) {
1450 if (Constant *S = VC->getSplatValue()) {
1451 Constant *NewS = InternalMapper.mapConstant(*S);
1452 if (!NewS)
1453 return nullptr;
1454 auto [Rsrc, Off] = splitLoweredFatBufferConst(NewS);
1455 auto EC = VC->getType()->getElementCount();
1456 return ConstantStruct::get(NewTy, {ConstantVector::getSplat(EC, Rsrc),
1457 ConstantVector::getSplat(EC, Off)});
1458 }
1461 for (Value *Op : VC->operand_values()) {
1462 auto *NewOp = dyn_cast_or_null<Constant>(InternalMapper.mapValue(*Op));
1463 if (!NewOp)
1464 return nullptr;
1465 auto [Rsrc, Off] = splitLoweredFatBufferConst(NewOp);
1466 Rsrcs.push_back(Rsrc);
1467 Offs.push_back(Off);
1468 }
1469 Constant *RsrcVec = ConstantVector::get(Rsrcs);
1470 Constant *OffVec = ConstantVector::get(Offs);
1471 return ConstantStruct::get(NewTy, {RsrcVec, OffVec});
1472 }
1473
1474 if (isa<GlobalValue>(C))
1475 reportFatalUsageError("global values containing ptr addrspace(7) (buffer "
1476 "fat pointer) values are not supported");
1477
1478 if (isa<ConstantExpr>(C))
1480 "constant exprs containing ptr addrspace(7) (buffer "
1481 "fat pointer) values should have been expanded earlier");
1482
1483 return nullptr;
1484}
1485
1486Value *FatPtrConstMaterializer::materialize(Value *V) {
1488 if (!C)
1489 return nullptr;
1490 // Structs and other types that happen to contain fat pointers get remapped
1491 // by the mapValue() logic.
1492 if (!isBufferFatPtrConst(C))
1493 return nullptr;
1494 return materializeBufferFatPtrConst(C);
1495}
1496
1497using PtrParts = std::pair<Value *, Value *>;
1498namespace {
1499// The visitor returns the resource and offset parts for an instruction if they
1500// can be computed, or (nullptr, nullptr) for cases that don't have a meaningful
1501// value mapping.
1502class SplitPtrStructs : public InstVisitor<SplitPtrStructs, PtrParts> {
1503 ValueToValueMapTy RsrcParts;
1504 ValueToValueMapTy OffParts;
1505
1506 // Track instructions that have been rewritten into a user of the component
1507 // parts of their ptr addrspace(7) input. Instructions that produced
1508 // ptr addrspace(7) parts should **not** be RAUW'd before being added to this
1509 // set, as that replacement will be handled in a post-visit step. However,
1510 // instructions that yield values that aren't fat pointers (ex. ptrtoint)
1511 // should RAUW themselves with new instructions that use the split parts
1512 // of their arguments during processing.
1513 DenseSet<Instruction *> SplitUsers;
1514
1515 // Nodes that need a second look once we've computed the parts for all other
1516 // instructions to see if, for example, we really need to phi on the resource
1517 // part.
1518 SmallVector<Instruction *> Conditionals;
1519 // Temporary instructions produced while lowering conditionals that should be
1520 // killed.
1521 SmallVector<Instruction *> ConditionalTemps;
1522
1523 // Subtarget info, needed for determining what cache control bits to set.
1524 const TargetMachine *TM;
1525 const GCNSubtarget *ST = nullptr;
1526
1528
1529 // Copy metadata between instructions if applicable.
1530 void copyMetadata(Value *Dest, Value *Src);
1531
1532 // Get the resource and offset parts of the value V, inserting appropriate
1533 // extractvalue calls if needed.
1534 PtrParts getPtrParts(Value *V);
1535
1536 // Given an instruction that could produce multiple resource parts (a PHI or
1537 // select), collect the set of possible instructions that could have provided
1538 // its resource parts that it could have (the `Roots`) and the set of
1539 // conditional instructions visited during the search (`Seen`). If, after
1540 // removing the root of the search from `Seen` and `Roots`, `Seen` is a subset
1541 // of `Roots` and `Roots - Seen` contains one element, the resource part of
1542 // that element can replace the resource part of all other elements in `Seen`.
1543 void getPossibleRsrcRoots(Instruction *I, SmallPtrSetImpl<Value *> &Roots,
1545 void processConditionals();
1546
1547 // If an instruction hav been split into resource and offset parts,
1548 // delete that instruction. If any of its uses have not themselves been split
1549 // into parts (for example, an insertvalue), construct the structure
1550 // that the type rewrites declared should be produced by the dying instruction
1551 // and use that.
1552 // Also, kill the temporary extractvalue operations produced by the two-stage
1553 // lowering of PHIs and conditionals.
1554 void killAndReplaceSplitInstructions(SmallVectorImpl<Instruction *> &Origs);
1555
1556 void setAlign(CallInst *Intr, Align A, unsigned RsrcArgIdx);
1557 void insertPreMemOpFence(AtomicOrdering Order, SyncScope::ID SSID);
1558 void insertPostMemOpFence(AtomicOrdering Order, SyncScope::ID SSID);
1559 Value *handleMemoryInst(Instruction *I, Value *Arg, Value *Ptr, Type *Ty,
1560 Align Alignment, AtomicOrdering Order,
1561 bool IsVolatile, SyncScope::ID SSID);
1562
1563public:
1564 SplitPtrStructs(const DataLayout &DL, LLVMContext &Ctx,
1565 const TargetMachine *TM)
1566 : TM(TM), IRB(Ctx, InstSimplifyFolder(DL)) {}
1567
1568 void processFunction(Function &F);
1569
1570 PtrParts visitInstruction(Instruction &I);
1571 PtrParts visitLoadInst(LoadInst &LI);
1572 PtrParts visitStoreInst(StoreInst &SI);
1573 PtrParts visitAtomicRMWInst(AtomicRMWInst &AI);
1574 PtrParts visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI);
1575 PtrParts visitGetElementPtrInst(GetElementPtrInst &GEP);
1576
1577 PtrParts visitPtrToAddrInst(PtrToAddrInst &PA);
1578 PtrParts visitPtrToIntInst(PtrToIntInst &PI);
1579 PtrParts visitIntToPtrInst(IntToPtrInst &IP);
1580 PtrParts visitAddrSpaceCastInst(AddrSpaceCastInst &I);
1581 PtrParts visitICmpInst(ICmpInst &Cmp);
1582 PtrParts visitFreezeInst(FreezeInst &I);
1583
1584 PtrParts visitExtractElementInst(ExtractElementInst &I);
1585 PtrParts visitInsertElementInst(InsertElementInst &I);
1586 PtrParts visitShuffleVectorInst(ShuffleVectorInst &I);
1587
1588 PtrParts visitPHINode(PHINode &PHI);
1589 PtrParts visitSelectInst(SelectInst &SI);
1590
1591 PtrParts visitIntrinsicInst(IntrinsicInst &II);
1592};
1593} // namespace
1594
1595void SplitPtrStructs::copyMetadata(Value *Dest, Value *Src) {
1596 auto *DestI = dyn_cast<Instruction>(Dest);
1597 auto *SrcI = dyn_cast<Instruction>(Src);
1598
1599 if (!DestI || !SrcI)
1600 return;
1601
1602 DestI->copyMetadata(*SrcI);
1603}
1604
1605PtrParts SplitPtrStructs::getPtrParts(Value *V) {
1606 assert(isSplitFatPtr(V->getType()) && "it's not meaningful to get the parts "
1607 "of something that wasn't rewritten");
1608 auto *RsrcEntry = &RsrcParts[V];
1609 auto *OffEntry = &OffParts[V];
1610 if (*RsrcEntry && *OffEntry)
1611 return {*RsrcEntry, *OffEntry};
1612
1613 if (auto *C = dyn_cast<Constant>(V)) {
1614 auto [Rsrc, Off] = splitLoweredFatBufferConst(C);
1615 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1616 }
1617
1618 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1619 if (auto *I = dyn_cast<Instruction>(V)) {
1620 LLVM_DEBUG(dbgs() << "Recursing to split parts of " << *I << "\n");
1621 auto [Rsrc, Off] = visit(*I);
1622 if (Rsrc && Off)
1623 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1624 // We'll be creating the new values after the relevant instruction.
1625 // This instruction generates a value and so isn't a terminator.
1626 IRB.SetInsertPoint(*I->getInsertionPointAfterDef());
1627 IRB.SetCurrentDebugLocation(I->getDebugLoc());
1628 } else if (auto *A = dyn_cast<Argument>(V)) {
1629 IRB.SetInsertPointPastAllocas(A->getParent());
1630 IRB.SetCurrentDebugLocation(DebugLoc());
1631 }
1632 Value *Rsrc = IRB.CreateExtractValue(V, 0, V->getName() + ".rsrc");
1633 Value *Off = IRB.CreateExtractValue(V, 1, V->getName() + ".off");
1634 return {*RsrcEntry = Rsrc, *OffEntry = Off};
1635}
1636
1637/// Returns the instruction that defines the resource part of the value V.
1638/// Note that this is not getUnderlyingObject(), since that looks through
1639/// operations like ptrmask which might modify the resource part.
1640///
1641/// We can limit ourselves to just looking through GEPs followed by looking
1642/// through addrspacecasts because only those two operations preserve the
1643/// resource part, and because operations on an `addrspace(8)` (which is the
1644/// legal input to this addrspacecast) would produce a different resource part.
1646 while (auto *GEP = dyn_cast<GEPOperator>(V))
1647 V = GEP->getPointerOperand();
1648 while (auto *ASC = dyn_cast<AddrSpaceCastOperator>(V))
1649 V = ASC->getPointerOperand();
1650 return V;
1651}
1652
1653void SplitPtrStructs::getPossibleRsrcRoots(Instruction *I,
1654 SmallPtrSetImpl<Value *> &Roots,
1655 SmallPtrSetImpl<Value *> &Seen) {
1656 if (auto *PHI = dyn_cast<PHINode>(I)) {
1657 if (!Seen.insert(I).second)
1658 return;
1659 for (Value *In : PHI->incoming_values()) {
1660 In = rsrcPartRoot(In);
1661 Roots.insert(In);
1663 getPossibleRsrcRoots(cast<Instruction>(In), Roots, Seen);
1664 }
1665 } else if (auto *SI = dyn_cast<SelectInst>(I)) {
1666 if (!Seen.insert(SI).second)
1667 return;
1668 Value *TrueVal = rsrcPartRoot(SI->getTrueValue());
1669 Value *FalseVal = rsrcPartRoot(SI->getFalseValue());
1670 Roots.insert(TrueVal);
1671 Roots.insert(FalseVal);
1672 if (isa<PHINode, SelectInst>(TrueVal))
1673 getPossibleRsrcRoots(cast<Instruction>(TrueVal), Roots, Seen);
1674 if (isa<PHINode, SelectInst>(FalseVal))
1675 getPossibleRsrcRoots(cast<Instruction>(FalseVal), Roots, Seen);
1676 } else {
1677 llvm_unreachable("getPossibleRsrcParts() only works on phi and select");
1678 }
1679}
1680
1681void SplitPtrStructs::processConditionals() {
1682 SmallDenseMap<Value *, Value *> FoundRsrcs;
1683 SmallPtrSet<Value *, 4> Roots;
1684 SmallPtrSet<Value *, 4> Seen;
1685 for (Instruction *I : Conditionals) {
1686 // These have to exist by now because we've visited these nodes.
1687 Value *Rsrc = RsrcParts[I];
1688 Value *Off = OffParts[I];
1689 assert(Rsrc && Off && "must have visited conditionals by now");
1690
1691 std::optional<Value *> MaybeRsrc;
1692 auto MaybeFoundRsrc = FoundRsrcs.find(I);
1693 if (MaybeFoundRsrc != FoundRsrcs.end()) {
1694 MaybeRsrc = MaybeFoundRsrc->second;
1695 } else {
1696 IRBuilder<InstSimplifyFolder>::InsertPointGuard Guard(IRB);
1697 Roots.clear();
1698 Seen.clear();
1699 getPossibleRsrcRoots(I, Roots, Seen);
1700 LLVM_DEBUG(dbgs() << "Processing conditional: " << *I << "\n");
1701#ifndef NDEBUG
1702 for (Value *V : Roots)
1703 LLVM_DEBUG(dbgs() << "Root: " << *V << "\n");
1704 for (Value *V : Seen)
1705 LLVM_DEBUG(dbgs() << "Seen: " << *V << "\n");
1706#endif
1707 // If we are our own possible root, then we shouldn't block our
1708 // replacement with a valid incoming value.
1709 Roots.erase(I);
1710 // We don't want to block the optimization for conditionals that don't
1711 // refer to themselves but did see themselves during the traversal.
1712 Seen.erase(I);
1713
1714 if (set_is_subset(Seen, Roots)) {
1715 auto Diff = set_difference(Roots, Seen);
1716 if (Diff.size() == 1) {
1717 Value *RootVal = *Diff.begin();
1718 // Handle the case where previous loops already looked through
1719 // an addrspacecast.
1720 if (isSplitFatPtr(RootVal->getType()))
1721 MaybeRsrc = std::get<0>(getPtrParts(RootVal));
1722 else
1723 MaybeRsrc = RootVal;
1724 }
1725 }
1726 }
1727
1728 if (auto *PHI = dyn_cast<PHINode>(I)) {
1729 Value *NewRsrc;
1730 StructType *PHITy = cast<StructType>(PHI->getType());
1731 IRB.SetInsertPoint(*PHI->getInsertionPointAfterDef());
1732 IRB.SetCurrentDebugLocation(PHI->getDebugLoc());
1733 if (MaybeRsrc) {
1734 NewRsrc = *MaybeRsrc;
1735 } else {
1736 Type *RsrcTy = PHITy->getElementType(0);
1737 auto *RsrcPHI = IRB.CreatePHI(RsrcTy, PHI->getNumIncomingValues());
1738 RsrcPHI->takeName(Rsrc);
1739 for (auto [V, BB] : llvm::zip(PHI->incoming_values(), PHI->blocks())) {
1740 Value *VRsrc = std::get<0>(getPtrParts(V));
1741 RsrcPHI->addIncoming(VRsrc, BB);
1742 }
1743 copyMetadata(RsrcPHI, PHI);
1744 NewRsrc = RsrcPHI;
1745 }
1746
1747 Type *OffTy = PHITy->getElementType(1);
1748 auto *NewOff = IRB.CreatePHI(OffTy, PHI->getNumIncomingValues());
1749 NewOff->takeName(Off);
1750 for (auto [V, BB] : llvm::zip(PHI->incoming_values(), PHI->blocks())) {
1751 assert(OffParts.count(V) && "An offset part had to be created by now");
1752 Value *VOff = std::get<1>(getPtrParts(V));
1753 NewOff->addIncoming(VOff, BB);
1754 }
1755 copyMetadata(NewOff, PHI);
1756
1757 // Note: We don't eraseFromParent() the temporaries because we don't want
1758 // to put the corrections maps in an inconstent state. That'll be handed
1759 // during the rest of the killing. Also, `ValueToValueMapTy` guarantees
1760 // that references in that map will be updated as well.
1761 // Note that if the temporary instruction got `InstSimplify`'d away, it
1762 // might be something like a block argument.
1763 if (auto *RsrcInst = dyn_cast<Instruction>(Rsrc)) {
1764 ConditionalTemps.push_back(RsrcInst);
1765 RsrcInst->replaceAllUsesWith(NewRsrc);
1766 }
1767 if (auto *OffInst = dyn_cast<Instruction>(Off)) {
1768 ConditionalTemps.push_back(OffInst);
1769 OffInst->replaceAllUsesWith(NewOff);
1770 }
1771
1772 // Save on recomputing the cycle traversals in known-root cases.
1773 if (MaybeRsrc)
1774 for (Value *V : Seen)
1775 FoundRsrcs[V] = NewRsrc;
1776 } else if (isa<SelectInst>(I)) {
1777 if (MaybeRsrc) {
1778 if (auto *RsrcInst = dyn_cast<Instruction>(Rsrc)) {
1779 // Guard against conditionals that were already folded away.
1780 if (RsrcInst != *MaybeRsrc) {
1781 ConditionalTemps.push_back(RsrcInst);
1782 RsrcInst->replaceAllUsesWith(*MaybeRsrc);
1783 }
1784 }
1785 for (Value *V : Seen)
1786 FoundRsrcs[V] = *MaybeRsrc;
1787 }
1788 } else {
1789 llvm_unreachable("Only PHIs and selects go in the conditionals list");
1790 }
1791 }
1792}
1793
1794void SplitPtrStructs::killAndReplaceSplitInstructions(
1795 SmallVectorImpl<Instruction *> &Origs) {
1796 for (Instruction *I : ConditionalTemps)
1797 I->eraseFromParent();
1798
1799 for (Instruction *I : Origs) {
1800 if (!SplitUsers.contains(I))
1801 continue;
1802
1804 findDbgValues(I, Dbgs);
1805 for (DbgVariableRecord *Dbg : Dbgs) {
1806 auto &DL = I->getDataLayout();
1807 assert(isSplitFatPtr(I->getType()) &&
1808 "We should've RAUW'd away loads, stores, etc. at this point");
1809 DbgVariableRecord *OffDbg = Dbg->clone();
1810 auto [Rsrc, Off] = getPtrParts(I);
1811
1812 int64_t RsrcSz = DL.getTypeSizeInBits(Rsrc->getType());
1813 int64_t OffSz = DL.getTypeSizeInBits(Off->getType());
1814
1815 std::optional<DIExpression *> RsrcExpr =
1816 DIExpression::createFragmentExpression(Dbg->getExpression(), 0,
1817 RsrcSz);
1818 std::optional<DIExpression *> OffExpr =
1819 DIExpression::createFragmentExpression(Dbg->getExpression(), RsrcSz,
1820 OffSz);
1821 if (OffExpr) {
1822 OffDbg->setExpression(*OffExpr);
1823 OffDbg->replaceVariableLocationOp(I, Off);
1824 OffDbg->insertBefore(Dbg);
1825 } else {
1826 OffDbg->eraseFromParent();
1827 }
1828 if (RsrcExpr) {
1829 Dbg->setExpression(*RsrcExpr);
1830 Dbg->replaceVariableLocationOp(I, Rsrc);
1831 } else {
1832 Dbg->replaceVariableLocationOp(I, PoisonValue::get(I->getType()));
1833 }
1834 }
1835
1836 Value *Poison = PoisonValue::get(I->getType());
1837 I->replaceUsesWithIf(Poison, [&](const Use &U) -> bool {
1838 if (const auto *UI = dyn_cast<Instruction>(U.getUser()))
1839 return SplitUsers.contains(UI);
1840 return false;
1841 });
1842
1843 if (I->use_empty()) {
1844 I->eraseFromParent();
1845 continue;
1846 }
1847 IRB.SetInsertPoint(*I->getInsertionPointAfterDef());
1848 IRB.SetCurrentDebugLocation(I->getDebugLoc());
1849 auto [Rsrc, Off] = getPtrParts(I);
1850 Value *Struct = PoisonValue::get(I->getType());
1851 Struct = IRB.CreateInsertValue(Struct, Rsrc, 0);
1852 Struct = IRB.CreateInsertValue(Struct, Off, 1);
1853 copyMetadata(Struct, I);
1854 Struct->takeName(I);
1855 I->replaceAllUsesWith(Struct);
1856 I->eraseFromParent();
1857 }
1858}
1859
1860void SplitPtrStructs::setAlign(CallInst *Intr, Align A, unsigned RsrcArgIdx) {
1861 LLVMContext &Ctx = Intr->getContext();
1862 Intr->addParamAttr(RsrcArgIdx, Attribute::getWithAlignment(Ctx, A));
1863}
1864
1865void SplitPtrStructs::insertPreMemOpFence(AtomicOrdering Order,
1866 SyncScope::ID SSID) {
1867 switch (Order) {
1868 case AtomicOrdering::Release:
1869 case AtomicOrdering::AcquireRelease:
1870 case AtomicOrdering::SequentiallyConsistent:
1871 IRB.CreateFence(AtomicOrdering::Release, SSID);
1872 break;
1873 default:
1874 break;
1875 }
1876}
1877
1878void SplitPtrStructs::insertPostMemOpFence(AtomicOrdering Order,
1879 SyncScope::ID SSID) {
1880 switch (Order) {
1881 case AtomicOrdering::Acquire:
1882 case AtomicOrdering::AcquireRelease:
1883 case AtomicOrdering::SequentiallyConsistent:
1884 IRB.CreateFence(AtomicOrdering::Acquire, SSID);
1885 break;
1886 default:
1887 break;
1888 }
1889}
1890
1891Value *SplitPtrStructs::handleMemoryInst(Instruction *I, Value *Arg, Value *Ptr,
1892 Type *Ty, Align Alignment,
1893 AtomicOrdering Order, bool IsVolatile,
1894 SyncScope::ID SSID) {
1895 IRB.SetInsertPoint(I);
1896
1897 auto [Rsrc, Off] = getPtrParts(Ptr);
1899 if (Arg)
1900 Args.push_back(Arg);
1901 Args.push_back(Rsrc);
1902 Args.push_back(Off);
1903 insertPreMemOpFence(Order, SSID);
1904 // soffset is always 0 for these cases, where we always want any offset to be
1905 // part of bounds checking and we don't know which parts of the GEPs is
1906 // uniform.
1907 Args.push_back(IRB.getInt32(0));
1908
1909 uint32_t Aux = 0;
1910 if (IsVolatile)
1912 Args.push_back(IRB.getInt32(Aux));
1913
1915 if (isa<LoadInst>(I))
1916 IID = Order == AtomicOrdering::NotAtomic
1917 ? Intrinsic::amdgcn_raw_ptr_buffer_load
1918 : Intrinsic::amdgcn_raw_ptr_atomic_buffer_load;
1919 else if (isa<StoreInst>(I))
1920 IID = Intrinsic::amdgcn_raw_ptr_buffer_store;
1921 else if (auto *RMW = dyn_cast<AtomicRMWInst>(I)) {
1922 switch (RMW->getOperation()) {
1924 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_swap;
1925 break;
1926 case AtomicRMWInst::Add:
1927 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_add;
1928 break;
1929 case AtomicRMWInst::Sub:
1930 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub;
1931 break;
1932 case AtomicRMWInst::And:
1933 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_and;
1934 break;
1935 case AtomicRMWInst::Or:
1936 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_or;
1937 break;
1938 case AtomicRMWInst::Xor:
1939 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_xor;
1940 break;
1941 case AtomicRMWInst::Max:
1942 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smax;
1943 break;
1944 case AtomicRMWInst::Min:
1945 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_smin;
1946 break;
1948 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umax;
1949 break;
1951 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_umin;
1952 break;
1954 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fadd;
1955 break;
1957 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmax;
1958 break;
1960 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_fmin;
1961 break;
1963 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_cond_sub_u32;
1964 break;
1966 IID = Intrinsic::amdgcn_raw_ptr_buffer_atomic_sub_clamp_u32;
1967 break;
1968 case AtomicRMWInst::FSub: {
1970 "atomic floating point subtraction not supported for "
1971 "buffer resources and should've been expanded away");
1972 break;
1973 }
1976 "atomic floating point fmaximum not supported for "
1977 "buffer resources and should've been expanded away");
1978 break;
1979 }
1982 "atomic floating point fminimum not supported for "
1983 "buffer resources and should've been expanded away");
1984 break;
1985 }
1988 "atomic floating point fmaximumnum not supported for "
1989 "buffer resources and should've been expanded away");
1990 break;
1991 }
1994 "atomic floating point fminimumnum not supported for "
1995 "buffer resources and should've been expanded away");
1996 break;
1997 }
2000 "atomic nand not supported for buffer resources and "
2001 "should've been expanded away");
2002 break;
2006 "wrapping increment/decrement not supported for "
2007 "buffer resources and should've been expanded away");
2008 break;
2010 llvm_unreachable("Not sure how we got a bad binop");
2011 }
2012 }
2013
2014 CallInst *Call = IRB.CreateIntrinsicWithoutFolding(IID, Ty, Args);
2015 copyMetadata(Call, I);
2016 setAlign(Call, Alignment, Arg ? 1 : 0);
2017 Call->takeName(I);
2018
2019 insertPostMemOpFence(Order, SSID);
2020 // The "no moving p7 directly" rewrites ensure that this load or store won't
2021 // itself need to be split into parts.
2022 SplitUsers.insert(I);
2023 I->replaceAllUsesWith(Call);
2024 return Call;
2025}
2026
2027PtrParts SplitPtrStructs::visitInstruction(Instruction &I) {
2028 return {nullptr, nullptr};
2029}
2030
2031PtrParts SplitPtrStructs::visitLoadInst(LoadInst &LI) {
2033 return {nullptr, nullptr};
2034 handleMemoryInst(&LI, nullptr, LI.getPointerOperand(), LI.getType(),
2035 LI.getAlign(), LI.getOrdering(), LI.isVolatile(),
2036 LI.getSyncScopeID());
2037 return {nullptr, nullptr};
2038}
2039
2040PtrParts SplitPtrStructs::visitStoreInst(StoreInst &SI) {
2041 if (!isSplitFatPtr(SI.getPointerOperandType()))
2042 return {nullptr, nullptr};
2043 Value *Arg = SI.getValueOperand();
2044 handleMemoryInst(&SI, Arg, SI.getPointerOperand(), Arg->getType(),
2045 SI.getAlign(), SI.getOrdering(), SI.isVolatile(),
2046 SI.getSyncScopeID());
2047 return {nullptr, nullptr};
2048}
2049
2050PtrParts SplitPtrStructs::visitAtomicRMWInst(AtomicRMWInst &AI) {
2052 return {nullptr, nullptr};
2053 Value *Arg = AI.getValOperand();
2054 handleMemoryInst(&AI, Arg, AI.getPointerOperand(), Arg->getType(),
2055 AI.getAlign(), AI.getOrdering(), AI.isVolatile(),
2056 AI.getSyncScopeID());
2057 return {nullptr, nullptr};
2058}
2059
2060// Unlike load, store, and RMW, cmpxchg needs special handling to account
2061// for the boolean argument.
2062PtrParts SplitPtrStructs::visitAtomicCmpXchgInst(AtomicCmpXchgInst &AI) {
2063 Value *Ptr = AI.getPointerOperand();
2064 if (!isSplitFatPtr(Ptr->getType()))
2065 return {nullptr, nullptr};
2066 IRB.SetInsertPoint(&AI);
2067
2068 Type *Ty = AI.getNewValOperand()->getType();
2069 AtomicOrdering Order = AI.getMergedOrdering();
2070 SyncScope::ID SSID = AI.getSyncScopeID();
2071 bool IsNonTemporal = AI.getMetadata(LLVMContext::MD_nontemporal);
2072
2073 auto [Rsrc, Off] = getPtrParts(Ptr);
2074 insertPreMemOpFence(Order, SSID);
2075
2076 uint32_t Aux = 0;
2077 if (IsNonTemporal)
2078 Aux |= AMDGPU::CPol::SLC;
2079 if (AI.isVolatile())
2081 CallInst *Call = IRB.CreateIntrinsicWithoutFolding(
2082 Intrinsic::amdgcn_raw_ptr_buffer_atomic_cmpswap, Ty,
2083 {AI.getNewValOperand(), AI.getCompareOperand(), Rsrc, Off,
2084 IRB.getInt32(0), IRB.getInt32(Aux)});
2085 copyMetadata(Call, &AI);
2086 setAlign(Call, AI.getAlign(), 2);
2087 Call->takeName(&AI);
2088 insertPostMemOpFence(Order, SSID);
2089
2090 Value *Res = PoisonValue::get(AI.getType());
2091 Res = IRB.CreateInsertValue(Res, Call, 0);
2092 Value *Succeeded = IRB.CreateICmpEQ(Call, AI.getCompareOperand());
2093 Res = IRB.CreateInsertValue(Res, Succeeded, 1);
2094 SplitUsers.insert(&AI);
2095 AI.replaceAllUsesWith(Res);
2096 return {nullptr, nullptr};
2097}
2098
2099PtrParts SplitPtrStructs::visitGetElementPtrInst(GetElementPtrInst &GEP) {
2100 using namespace llvm::PatternMatch;
2101 Value *Ptr = GEP.getPointerOperand();
2102 if (!isSplitFatPtr(Ptr->getType()))
2103 return {nullptr, nullptr};
2104 IRB.SetInsertPoint(&GEP);
2105
2106 auto [Rsrc, Off] = getPtrParts(Ptr);
2107 const DataLayout &DL = GEP.getDataLayout();
2108 bool IsNUW = GEP.hasNoUnsignedWrap();
2109 bool IsNUSW = GEP.hasNoUnsignedSignedWrap();
2110
2111 StructType *ResTy = cast<StructType>(GEP.getType());
2112 Type *ResRsrcTy = ResTy->getElementType(0);
2113 VectorType *ResRsrcVecTy = dyn_cast<VectorType>(ResRsrcTy);
2114 bool BroadcastsPtr = ResRsrcVecTy && !isa<VectorType>(Off->getType());
2115
2116 // In order to call emitGEPOffset() and thus not have to reimplement it,
2117 // we need the GEP result to have ptr addrspace(7) type.
2118 Type *FatPtrTy =
2119 ResRsrcTy->getWithNewType(IRB.getPtrTy(AMDGPUAS::BUFFER_FAT_POINTER));
2120 GEP.mutateType(FatPtrTy);
2121 Value *OffAccum = emitGEPOffset(&IRB, DL, &GEP);
2122 GEP.mutateType(ResTy);
2123
2124 if (BroadcastsPtr) {
2125 Rsrc = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Rsrc,
2126 Rsrc->getName());
2127 Off = IRB.CreateVectorSplat(ResRsrcVecTy->getElementCount(), Off,
2128 Off->getName());
2129 }
2130 if (match(OffAccum, m_Zero())) { // Constant-zero offset
2131 SplitUsers.insert(&GEP);
2132 return {Rsrc, Off};
2133 }
2134
2135 bool HasNonNegativeOff = false;
2136 if (auto *CI = dyn_cast<ConstantInt>(OffAccum)) {
2137 HasNonNegativeOff = !CI->isNegative();
2138 }
2139 Value *NewOff;
2140 if (match(Off, m_Zero())) {
2141 NewOff = OffAccum;
2142 } else {
2143 NewOff = IRB.CreateAdd(Off, OffAccum, "",
2144 /*hasNUW=*/IsNUW || (IsNUSW && HasNonNegativeOff),
2145 /*hasNSW=*/false);
2146 }
2147 copyMetadata(NewOff, &GEP);
2148 NewOff->takeName(&GEP);
2149 SplitUsers.insert(&GEP);
2150 return {Rsrc, NewOff};
2151}
2152
2153PtrParts SplitPtrStructs::visitPtrToIntInst(PtrToIntInst &PI) {
2154 Value *Ptr = PI.getPointerOperand();
2155 if (!isSplitFatPtr(Ptr->getType()))
2156 return {nullptr, nullptr};
2157 IRB.SetInsertPoint(&PI);
2158
2159 Type *ResTy = PI.getType();
2160 unsigned Width = ResTy->getScalarSizeInBits();
2161
2162 auto [Rsrc, Off] = getPtrParts(Ptr);
2163 const DataLayout &DL = PI.getDataLayout();
2164 unsigned FatPtrWidth = DL.getPointerSizeInBits(AMDGPUAS::BUFFER_FAT_POINTER);
2165
2166 Value *Res;
2167 if (Width <= BufferOffsetWidth) {
2168 Res = IRB.CreateIntCast(Off, ResTy, /*isSigned=*/false,
2169 PI.getName() + ".off");
2170 } else {
2171 Value *RsrcInt = IRB.CreatePtrToInt(Rsrc, ResTy, PI.getName() + ".rsrc");
2172 Value *Shl = IRB.CreateShl(
2173 RsrcInt,
2174 ConstantExpr::getIntegerValue(ResTy, APInt(Width, BufferOffsetWidth)),
2175 "", Width >= FatPtrWidth, Width > FatPtrWidth);
2176 Value *OffCast = IRB.CreateIntCast(Off, ResTy, /*isSigned=*/false,
2177 PI.getName() + ".off");
2178 Res = IRB.CreateOr(Shl, OffCast);
2179 }
2180
2181 copyMetadata(Res, &PI);
2182 Res->takeName(&PI);
2183 SplitUsers.insert(&PI);
2184 PI.replaceAllUsesWith(Res);
2185 return {nullptr, nullptr};
2186}
2187
2188PtrParts SplitPtrStructs::visitPtrToAddrInst(PtrToAddrInst &PA) {
2189 Value *Ptr = PA.getPointerOperand();
2190 if (!isSplitFatPtr(Ptr->getType()))
2191 return {nullptr, nullptr};
2192 IRB.SetInsertPoint(&PA);
2193
2194 auto [Rsrc, Off] = getPtrParts(Ptr);
2195 Value *Res = IRB.CreateIntCast(Off, PA.getType(), /*isSigned=*/false);
2196 copyMetadata(Res, &PA);
2197 Res->takeName(&PA);
2198 SplitUsers.insert(&PA);
2199 PA.replaceAllUsesWith(Res);
2200 return {nullptr, nullptr};
2201}
2202
2203PtrParts SplitPtrStructs::visitIntToPtrInst(IntToPtrInst &IP) {
2204 if (!isSplitFatPtr(IP.getType()))
2205 return {nullptr, nullptr};
2206 IRB.SetInsertPoint(&IP);
2207 const DataLayout &DL = IP.getDataLayout();
2208 unsigned RsrcPtrWidth = DL.getPointerSizeInBits(AMDGPUAS::BUFFER_RESOURCE);
2209 Value *Int = IP.getOperand(0);
2210 Type *IntTy = Int->getType();
2211 Type *RsrcIntTy = IntTy->getWithNewBitWidth(RsrcPtrWidth);
2212 unsigned Width = IntTy->getScalarSizeInBits();
2213
2214 auto *RetTy = cast<StructType>(IP.getType());
2215 Type *RsrcTy = RetTy->getElementType(0);
2216 Type *OffTy = RetTy->getElementType(1);
2217 // inttoptr zero-extends, so narrow inputs contribute nothing to the resource
2218 // part.
2219 Value *RsrcInt;
2220 if (Width <= BufferOffsetWidth) {
2221 RsrcInt = Constant::getNullValue(RsrcIntTy);
2222 } else {
2223 Value *RsrcPart =
2224 IRB.CreateLShr(Int, ConstantInt::get(IntTy, BufferOffsetWidth));
2225 RsrcInt = IRB.CreateIntCast(RsrcPart, RsrcIntTy, /*isSigned=*/false);
2226 }
2227 Value *Rsrc = IRB.CreateIntToPtr(RsrcInt, RsrcTy, IP.getName() + ".rsrc");
2228 Value *Off =
2229 IRB.CreateIntCast(Int, OffTy, /*IsSigned=*/false, IP.getName() + ".off");
2230
2231 copyMetadata(Rsrc, &IP);
2232 SplitUsers.insert(&IP);
2233 return {Rsrc, Off};
2234}
2235
2236PtrParts SplitPtrStructs::visitAddrSpaceCastInst(AddrSpaceCastInst &I) {
2237 // TODO(krzysz00): handle casts from ptr addrspace(7) to global pointers
2238 // by computing the effective address.
2239 if (!isSplitFatPtr(I.getType()))
2240 return {nullptr, nullptr};
2241 IRB.SetInsertPoint(&I);
2242 Value *In = I.getPointerOperand();
2243 // No-op casts preserve parts
2244 if (In->getType() == I.getType()) {
2245 auto [Rsrc, Off] = getPtrParts(In);
2246 SplitUsers.insert(&I);
2247 return {Rsrc, Off};
2248 }
2249
2250 auto *ResTy = cast<StructType>(I.getType());
2251 Type *RsrcTy = ResTy->getElementType(0);
2252 Type *OffTy = ResTy->getElementType(1);
2253 Value *ZeroOff = Constant::getNullValue(OffTy);
2254
2255 // Special case for null pointers, undef, and poison, which can be created by
2256 // address space propagation.
2257 auto *InConst = dyn_cast<Constant>(In);
2258 if (InConst && InConst->isNullValue()) {
2259 Value *NullRsrc = Constant::getNullValue(RsrcTy);
2260 SplitUsers.insert(&I);
2261 return {NullRsrc, ZeroOff};
2262 }
2263 if (isa<PoisonValue>(In)) {
2264 Value *PoisonRsrc = PoisonValue::get(RsrcTy);
2265 Value *PoisonOff = PoisonValue::get(OffTy);
2266 SplitUsers.insert(&I);
2267 return {PoisonRsrc, PoisonOff};
2268 }
2269 if (isa<UndefValue>(In)) {
2270 Value *UndefRsrc = UndefValue::get(RsrcTy);
2271 Value *UndefOff = UndefValue::get(OffTy);
2272 SplitUsers.insert(&I);
2273 return {UndefRsrc, UndefOff};
2274 }
2275
2276 if (I.getSrcAddressSpace() != AMDGPUAS::BUFFER_RESOURCE)
2278 "only buffer resources (addrspace 8) and null/poison pointers can be "
2279 "cast to buffer fat pointers (addrspace 7)");
2280 SplitUsers.insert(&I);
2281 return {In, ZeroOff};
2282}
2283
2284PtrParts SplitPtrStructs::visitICmpInst(ICmpInst &Cmp) {
2285 Value *Lhs = Cmp.getOperand(0);
2286 if (!isSplitFatPtr(Lhs->getType()))
2287 return {nullptr, nullptr};
2288 Value *Rhs = Cmp.getOperand(1);
2289 IRB.SetInsertPoint(&Cmp);
2290 ICmpInst::Predicate Pred = Cmp.getPredicate();
2291
2292 assert((Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE) &&
2293 "Pointer comparison is only equal or unequal");
2294 auto [LhsRsrc, LhsOff] = getPtrParts(Lhs);
2295 auto [RhsRsrc, RhsOff] = getPtrParts(Rhs);
2296 Value *Res = IRB.CreateICmp(Pred, LhsOff, RhsOff);
2297 copyMetadata(Res, &Cmp);
2298 Res->takeName(&Cmp);
2299 SplitUsers.insert(&Cmp);
2300 Cmp.replaceAllUsesWith(Res);
2301 return {nullptr, nullptr};
2302}
2303
2304PtrParts SplitPtrStructs::visitFreezeInst(FreezeInst &I) {
2305 if (!isSplitFatPtr(I.getType()))
2306 return {nullptr, nullptr};
2307 IRB.SetInsertPoint(&I);
2308 auto [Rsrc, Off] = getPtrParts(I.getOperand(0));
2309
2310 Value *RsrcRes = IRB.CreateFreeze(Rsrc, I.getName() + ".rsrc");
2311 copyMetadata(RsrcRes, &I);
2312 Value *OffRes = IRB.CreateFreeze(Off, I.getName() + ".off");
2313 copyMetadata(OffRes, &I);
2314 SplitUsers.insert(&I);
2315 return {RsrcRes, OffRes};
2316}
2317
2318PtrParts SplitPtrStructs::visitExtractElementInst(ExtractElementInst &I) {
2319 if (!isSplitFatPtr(I.getType()))
2320 return {nullptr, nullptr};
2321 IRB.SetInsertPoint(&I);
2322 Value *Vec = I.getVectorOperand();
2323 Value *Idx = I.getIndexOperand();
2324 auto [Rsrc, Off] = getPtrParts(Vec);
2325
2326 Value *RsrcRes = IRB.CreateExtractElement(Rsrc, Idx, I.getName() + ".rsrc");
2327 copyMetadata(RsrcRes, &I);
2328 Value *OffRes = IRB.CreateExtractElement(Off, Idx, I.getName() + ".off");
2329 copyMetadata(OffRes, &I);
2330 SplitUsers.insert(&I);
2331 return {RsrcRes, OffRes};
2332}
2333
2334PtrParts SplitPtrStructs::visitInsertElementInst(InsertElementInst &I) {
2335 // The mutated instructions temporarily don't return vectors, and so
2336 // we need the generic getType() here to avoid crashes.
2338 return {nullptr, nullptr};
2339 IRB.SetInsertPoint(&I);
2340 Value *Vec = I.getOperand(0);
2341 Value *Elem = I.getOperand(1);
2342 Value *Idx = I.getOperand(2);
2343 auto [VecRsrc, VecOff] = getPtrParts(Vec);
2344 auto [ElemRsrc, ElemOff] = getPtrParts(Elem);
2345
2346 Value *RsrcRes =
2347 IRB.CreateInsertElement(VecRsrc, ElemRsrc, Idx, I.getName() + ".rsrc");
2348 copyMetadata(RsrcRes, &I);
2349 Value *OffRes =
2350 IRB.CreateInsertElement(VecOff, ElemOff, Idx, I.getName() + ".off");
2351 copyMetadata(OffRes, &I);
2352 SplitUsers.insert(&I);
2353 return {RsrcRes, OffRes};
2354}
2355
2356PtrParts SplitPtrStructs::visitShuffleVectorInst(ShuffleVectorInst &I) {
2357 // Cast is needed for the same reason as insertelement's.
2359 return {nullptr, nullptr};
2360 IRB.SetInsertPoint(&I);
2361
2362 Value *V1 = I.getOperand(0);
2363 Value *V2 = I.getOperand(1);
2364 ArrayRef<int> Mask = I.getShuffleMask();
2365 auto [V1Rsrc, V1Off] = getPtrParts(V1);
2366 auto [V2Rsrc, V2Off] = getPtrParts(V2);
2367
2368 Value *RsrcRes =
2369 IRB.CreateShuffleVector(V1Rsrc, V2Rsrc, Mask, I.getName() + ".rsrc");
2370 copyMetadata(RsrcRes, &I);
2371 Value *OffRes =
2372 IRB.CreateShuffleVector(V1Off, V2Off, Mask, I.getName() + ".off");
2373 copyMetadata(OffRes, &I);
2374 SplitUsers.insert(&I);
2375 return {RsrcRes, OffRes};
2376}
2377
2378PtrParts SplitPtrStructs::visitPHINode(PHINode &PHI) {
2379 if (!isSplitFatPtr(PHI.getType()))
2380 return {nullptr, nullptr};
2381 IRB.SetInsertPoint(*PHI.getInsertionPointAfterDef());
2382 // Phi nodes will be handled in post-processing after we've visited every
2383 // instruction. However, instead of just returning {nullptr, nullptr},
2384 // we explicitly create the temporary extractvalue operations that are our
2385 // temporary results so that they end up at the beginning of the block with
2386 // the PHIs.
2387 Value *TmpRsrc = IRB.CreateExtractValue(&PHI, 0, PHI.getName() + ".rsrc");
2388 Value *TmpOff = IRB.CreateExtractValue(&PHI, 1, PHI.getName() + ".off");
2389 Conditionals.push_back(&PHI);
2390 SplitUsers.insert(&PHI);
2391 return {TmpRsrc, TmpOff};
2392}
2393
2394PtrParts SplitPtrStructs::visitSelectInst(SelectInst &SI) {
2395 if (!isSplitFatPtr(SI.getType()))
2396 return {nullptr, nullptr};
2397 IRB.SetInsertPoint(&SI);
2398
2399 Value *Cond = SI.getCondition();
2400 Value *True = SI.getTrueValue();
2401 Value *False = SI.getFalseValue();
2402 auto [TrueRsrc, TrueOff] = getPtrParts(True);
2403 auto [FalseRsrc, FalseOff] = getPtrParts(False);
2404
2405 Value *RsrcRes =
2406 IRB.CreateSelect(Cond, TrueRsrc, FalseRsrc, SI.getName() + ".rsrc", &SI);
2407 copyMetadata(RsrcRes, &SI);
2408 Conditionals.push_back(&SI);
2409 Value *OffRes =
2410 IRB.CreateSelect(Cond, TrueOff, FalseOff, SI.getName() + ".off", &SI);
2411 copyMetadata(OffRes, &SI);
2412 SplitUsers.insert(&SI);
2413 return {RsrcRes, OffRes};
2414}
2415
2416/// Returns true if this intrinsic needs to be removed when it is
2417/// applied to `ptr addrspace(7)` values. Calls to these intrinsics are
2418/// rewritten into calls to versions of that intrinsic on the resource
2419/// descriptor.
2421 switch (IID) {
2422 default:
2423 return false;
2424 case Intrinsic::amdgcn_make_buffer_rsrc:
2425 case Intrinsic::ptrmask:
2426 case Intrinsic::invariant_start:
2427 case Intrinsic::invariant_end:
2428 case Intrinsic::launder_invariant_group:
2429 case Intrinsic::strip_invariant_group:
2430 case Intrinsic::memcpy:
2431 case Intrinsic::memcpy_inline:
2432 case Intrinsic::memmove:
2433 case Intrinsic::memset:
2434 case Intrinsic::memset_inline:
2435 case Intrinsic::experimental_memset_pattern:
2436 case Intrinsic::amdgcn_load_to_lds:
2437 case Intrinsic::amdgcn_load_async_to_lds:
2438 return true;
2439 }
2440}
2441
2442PtrParts SplitPtrStructs::visitIntrinsicInst(IntrinsicInst &I) {
2443 Intrinsic::ID IID = I.getIntrinsicID();
2444 switch (IID) {
2445 default:
2446 break;
2447 case Intrinsic::amdgcn_make_buffer_rsrc: {
2448 if (!isSplitFatPtr(I.getType()))
2449 return {nullptr, nullptr};
2450 Value *Base = I.getArgOperand(0);
2451 Value *Stride = I.getArgOperand(1);
2452 Value *NumRecords = I.getArgOperand(2);
2453 Value *Flags = I.getArgOperand(3);
2454 auto *SplitType = cast<StructType>(I.getType());
2455 Type *RsrcType = SplitType->getElementType(0);
2456 Type *OffType = SplitType->getElementType(1);
2457 IRB.SetInsertPoint(&I);
2458 Value *Rsrc = IRB.CreateIntrinsic(
2459 IID, {RsrcType, Base->getType(), NumRecords->getType()},
2460 {Base, Stride, NumRecords, Flags});
2461 copyMetadata(Rsrc, &I);
2462 Rsrc->takeName(&I);
2463 Value *Zero = Constant::getNullValue(OffType);
2464 SplitUsers.insert(&I);
2465 return {Rsrc, Zero};
2466 }
2467 case Intrinsic::ptrmask: {
2468 Value *Ptr = I.getArgOperand(0);
2469 if (!isSplitFatPtr(Ptr->getType()))
2470 return {nullptr, nullptr};
2471 Value *Mask = I.getArgOperand(1);
2472 IRB.SetInsertPoint(&I);
2473 auto [Rsrc, Off] = getPtrParts(Ptr);
2474 if (Mask->getType() != Off->getType())
2475 reportFatalUsageError("offset width is not equal to index width of fat "
2476 "pointer (data layout not set up correctly?)");
2477 Value *OffRes = IRB.CreateAnd(Off, Mask, I.getName() + ".off");
2478 copyMetadata(OffRes, &I);
2479 SplitUsers.insert(&I);
2480 return {Rsrc, OffRes};
2481 }
2482 // Pointer annotation intrinsics that, given their object-wide nature
2483 // operate on the resource part.
2484 case Intrinsic::invariant_start: {
2485 Value *Ptr = I.getArgOperand(1);
2486 if (!isSplitFatPtr(Ptr->getType()))
2487 return {nullptr, nullptr};
2488 IRB.SetInsertPoint(&I);
2489 auto [Rsrc, Off] = getPtrParts(Ptr);
2490 Type *NewTy = PointerType::get(I.getContext(), AMDGPUAS::BUFFER_RESOURCE);
2491 auto *NewRsrc = IRB.CreateIntrinsic(IID, {NewTy}, {I.getOperand(0), Rsrc});
2492 copyMetadata(NewRsrc, &I);
2493 NewRsrc->takeName(&I);
2494 SplitUsers.insert(&I);
2495 I.replaceAllUsesWith(NewRsrc);
2496 return {nullptr, nullptr};
2497 }
2498 case Intrinsic::invariant_end: {
2499 Value *RealPtr = I.getArgOperand(2);
2500 if (!isSplitFatPtr(RealPtr->getType()))
2501 return {nullptr, nullptr};
2502 IRB.SetInsertPoint(&I);
2503 Value *RealRsrc = getPtrParts(RealPtr).first;
2504 Value *InvPtr = I.getArgOperand(0);
2505 Value *Size = I.getArgOperand(1);
2506 Value *NewRsrc = IRB.CreateIntrinsic(IID, {RealRsrc->getType()},
2507 {InvPtr, Size, RealRsrc});
2508 copyMetadata(NewRsrc, &I);
2509 NewRsrc->takeName(&I);
2510 SplitUsers.insert(&I);
2511 I.replaceAllUsesWith(NewRsrc);
2512 return {nullptr, nullptr};
2513 }
2514 case Intrinsic::launder_invariant_group:
2515 case Intrinsic::strip_invariant_group: {
2516 Value *Ptr = I.getArgOperand(0);
2517 if (!isSplitFatPtr(Ptr->getType()))
2518 return {nullptr, nullptr};
2519 IRB.SetInsertPoint(&I);
2520 auto [Rsrc, Off] = getPtrParts(Ptr);
2521 Value *NewRsrc = IRB.CreateIntrinsic(IID, {Rsrc->getType()}, {Rsrc});
2522 copyMetadata(NewRsrc, &I);
2523 NewRsrc->takeName(&I);
2524 SplitUsers.insert(&I);
2525 return {NewRsrc, Off};
2526 }
2527 case Intrinsic::amdgcn_load_to_lds:
2528 case Intrinsic::amdgcn_load_async_to_lds: {
2529 Value *Ptr = I.getArgOperand(0);
2530 if (!isSplitFatPtr(Ptr->getType()))
2531 return {nullptr, nullptr};
2532 IRB.SetInsertPoint(&I);
2533 auto [Rsrc, Off] = getPtrParts(Ptr);
2534 Value *LDSPtr = I.getArgOperand(1);
2535 Value *LoadSize = I.getArgOperand(2);
2536 Value *ImmOff = I.getArgOperand(3);
2537 Value *Aux = I.getArgOperand(4);
2538 Value *SOffset = IRB.getInt32(0);
2539 Intrinsic::ID NewIntr =
2540 IID == Intrinsic::amdgcn_load_to_lds
2541 ? Intrinsic::amdgcn_raw_ptr_buffer_load_lds
2542 : Intrinsic::amdgcn_raw_ptr_buffer_load_async_lds;
2543 Instruction *NewLoad = IRB.CreateIntrinsicWithoutFolding(
2544 NewIntr, {}, {Rsrc, LDSPtr, LoadSize, Off, SOffset, ImmOff, Aux});
2545 copyMetadata(NewLoad, &I);
2546 SplitUsers.insert(&I);
2547 I.replaceAllUsesWith(NewLoad);
2548 return {nullptr, nullptr};
2549 }
2550 }
2551 return {nullptr, nullptr};
2552}
2553
2554void SplitPtrStructs::processFunction(Function &F) {
2555 ST = &TM->getSubtarget<GCNSubtarget>(F);
2556 SmallVector<Instruction *, 0> Originals(
2558 LLVM_DEBUG(dbgs() << "Splitting pointer structs in function: " << F.getName()
2559 << "\n");
2560 for (Instruction *I : Originals) {
2561 // In some cases, instruction order doesn't reflect program order,
2562 // so the visit() call will have already visited coertain instructions
2563 // by the time this loop gets to them. Avoid re-visiting these so as to,
2564 // for example, avoid processing the same conditional twice.
2565 if (SplitUsers.contains(I))
2566 continue;
2567 auto [Rsrc, Off] = visit(I);
2568 assert(((Rsrc && Off) || (!Rsrc && !Off)) &&
2569 "Can't have a resource but no offset");
2570 if (Rsrc)
2571 RsrcParts[I] = Rsrc;
2572 if (Off)
2573 OffParts[I] = Off;
2574 }
2575 processConditionals();
2576 killAndReplaceSplitInstructions(Originals);
2577
2578 // Clean up after ourselves to save on memory.
2579 RsrcParts.clear();
2580 OffParts.clear();
2581 SplitUsers.clear();
2582 Conditionals.clear();
2583 ConditionalTemps.clear();
2584}
2585
2586namespace {
2587class AMDGPULowerBufferFatPointers : public ModulePass {
2588public:
2589 static char ID;
2590
2591 AMDGPULowerBufferFatPointers() : ModulePass(ID) {}
2592
2593 bool run(Module &M, const TargetMachine &TM, GetTTIFn GetTTI, GetSEFn GetSE);
2594 bool runOnModule(Module &M) override;
2595
2596 void getAnalysisUsage(AnalysisUsage &AU) const override;
2597};
2598} // namespace
2599
2600/// Returns true if there are values that have a buffer fat pointer in them,
2601/// which means we'll need to perform rewrites on this function. As a side
2602/// effect, this will populate the type remapping cache.
2604 BufferFatPtrToStructTypeMap *TypeMap) {
2605 bool HasFatPointers = false;
2606 for (const BasicBlock &BB : F)
2607 for (const Instruction &I : BB) {
2608 HasFatPointers |= (I.getType() != TypeMap->remapType(I.getType()));
2609 // Catch null pointer constants in loads, stores, etc.
2610 for (const Value *V : I.operand_values())
2611 HasFatPointers |= (V->getType() != TypeMap->remapType(V->getType()));
2612 }
2613 return HasFatPointers;
2614}
2615
2617 BufferFatPtrToStructTypeMap *TypeMap) {
2618 Type *Ty = F.getFunctionType();
2619 return Ty != TypeMap->remapType(Ty);
2620}
2621
2622/// Move the body of `OldF` into a new function, returning it.
2624 ValueToValueMapTy &CloneMap) {
2625 bool IsIntrinsic = OldF->isIntrinsic();
2626 Function *NewF =
2627 Function::Create(NewTy, OldF->getLinkage(), OldF->getAddressSpace());
2628 NewF->copyAttributesFrom(OldF);
2629 NewF->copyMetadata(OldF, 0);
2630 NewF->takeName(OldF);
2631 NewF->updateAfterNameChange();
2633 OldF->getParent()->getFunctionList().insertAfter(OldF->getIterator(), NewF);
2634
2635 while (!OldF->empty()) {
2636 BasicBlock *BB = &OldF->front();
2637 BB->removeFromParent();
2638 BB->insertInto(NewF);
2639 CloneMap[BB] = BB;
2640 for (Instruction &I : *BB) {
2641 CloneMap[&I] = &I;
2642 }
2643 }
2644
2646 AttributeList OldAttrs = OldF->getAttributes();
2647
2648 for (auto [I, OldArg, NewArg] : enumerate(OldF->args(), NewF->args())) {
2649 CloneMap[&NewArg] = &OldArg;
2650 NewArg.takeName(&OldArg);
2651 Type *OldArgTy = OldArg.getType(), *NewArgTy = NewArg.getType();
2652 // Temporarily mutate type of `NewArg` to allow RAUW to work.
2653 NewArg.mutateType(OldArgTy);
2654 OldArg.replaceAllUsesWith(&NewArg);
2655 NewArg.mutateType(NewArgTy);
2656
2657 AttributeSet ArgAttr = OldAttrs.getParamAttrs(I);
2658 // Intrinsics get their attributes fixed later.
2659 if (OldArgTy != NewArgTy && !IsIntrinsic)
2660 ArgAttr = ArgAttr.removeAttributes(
2661 NewF->getContext(),
2662 AttributeFuncs::typeIncompatible(NewArgTy, ArgAttr));
2663 ArgAttrs.push_back(ArgAttr);
2664 }
2665 AttributeSet RetAttrs = OldAttrs.getRetAttrs();
2666 if (OldF->getReturnType() != NewF->getReturnType() && !IsIntrinsic)
2667 RetAttrs = RetAttrs.removeAttributes(
2668 NewF->getContext(),
2669 AttributeFuncs::typeIncompatible(NewF->getReturnType(), RetAttrs));
2670 NewF->setAttributes(AttributeList::get(
2671 NewF->getContext(), OldAttrs.getFnAttrs(), RetAttrs, ArgAttrs));
2672 return NewF;
2673}
2674
2676 for (Argument &A : F->args())
2677 CloneMap[&A] = &A;
2678 for (BasicBlock &BB : *F) {
2679 CloneMap[&BB] = &BB;
2680 for (Instruction &I : BB)
2681 CloneMap[&I] = &I;
2682 }
2683}
2684
2685bool AMDGPULowerBufferFatPointers::run(Module &M, const TargetMachine &TM,
2686 GetTTIFn GetTTI, GetSEFn GetSE) {
2687 bool Changed = false;
2688 const DataLayout &DL = M.getDataLayout();
2689 // Record the functions which need to be remapped.
2690 // The second element of the pair indicates whether the function has to have
2691 // its arguments or return types adjusted.
2693
2694 LLVMContext &Ctx = M.getContext();
2695
2696 BufferFatPtrToStructTypeMap StructTM(DL);
2697 BufferFatPtrToIntTypeMap IntTM(DL);
2698 for (GlobalVariable &GV : make_early_inc_range(M.globals())) {
2699 if (GV.getAddressSpace() == AMDGPUAS::BUFFER_FAT_POINTER) {
2700 // FIXME: Use DiagnosticInfo unsupported but it requires a Function
2701 Ctx.emitError("global variables with a buffer fat pointer address "
2702 "space (7) are not supported");
2703 GV.replaceAllUsesWith(PoisonValue::get(GV.getType()));
2704 GV.eraseFromParent();
2705 Changed = true;
2706 continue;
2707 }
2708
2709 Type *VT = GV.getValueType();
2710 if (VT != StructTM.remapType(VT)) {
2711 // FIXME: Use DiagnosticInfo unsupported but it requires a Function
2712 Ctx.emitError("global variables that contain buffer fat pointers "
2713 "(address space 7 pointers) are unsupported. Use "
2714 "buffer resource pointers (address space 8) instead");
2715 GV.replaceAllUsesWith(PoisonValue::get(GV.getType()));
2716 GV.eraseFromParent();
2717 Changed = true;
2718 continue;
2719 }
2720 }
2721
2722 {
2723 // Collect all constant exprs and aggregates referenced by any function.
2725 for (Function &F : M.functions())
2726 for (Instruction &I : instructions(F))
2727 for (Value *Op : I.operands())
2729 Worklist.push_back(cast<Constant>(Op));
2730
2731 // Recursively look for any referenced buffer pointer constants.
2732 SmallPtrSet<Constant *, 8> Visited;
2733 SetVector<Constant *> BufferFatPtrConsts;
2734 while (!Worklist.empty()) {
2735 Constant *C = Worklist.pop_back_val();
2736 if (!Visited.insert(C).second)
2737 continue;
2738 if (isBufferFatPtrOrVector(C->getType()))
2739 BufferFatPtrConsts.insert(C);
2740 for (Value *Op : C->operands())
2742 Worklist.push_back(cast<Constant>(Op));
2743 }
2744
2745 // Expand all constant expressions using fat buffer pointers to
2746 // instructions.
2748 BufferFatPtrConsts.getArrayRef(), /*RestrictToFunc=*/nullptr,
2749 /*RemoveDeadConstants=*/false, /*IncludeSelf=*/true);
2750 }
2751
2752 StoreFatPtrsAsIntsAndExpandMemcpyVisitor MemOpsRewrite(&IntTM, DL,
2753 M.getContext());
2754 LegalizeBufferContentTypesVisitor BufferContentsTypeRewrite(
2755 DL, M.getContext(), &TM);
2756 for (Function &F : M.functions()) {
2757 bool InterfaceChange = hasFatPointerInterface(F, &StructTM);
2758 bool BodyChanges = containsBufferFatPointers(F, &StructTM);
2759 const TargetTransformInfo *TTI = GetTTI(F);
2760 ScalarEvolution *SE = GetSE(F);
2761 Changed |= MemOpsRewrite.processFunction(F, TTI, SE);
2762 if (InterfaceChange || BodyChanges) {
2763 NeedsRemap.push_back(std::make_pair(&F, InterfaceChange));
2764 Changed |= BufferContentsTypeRewrite.processFunction(F, SE);
2765 }
2766 }
2767 if (NeedsRemap.empty())
2768 return Changed;
2769
2770 SmallVector<Function *> NeedsPostProcess;
2771 SmallVector<Function *> Intrinsics;
2772 // Keep one big map so as to memoize constants across functions.
2773 ValueToValueMapTy CloneMap;
2774 FatPtrConstMaterializer Materializer(&StructTM, CloneMap);
2775
2776 ValueMapper LowerInFuncs(CloneMap, RF_None, &StructTM, &Materializer);
2777 for (auto [F, InterfaceChange] : NeedsRemap) {
2778 Function *NewF = F;
2779 if (InterfaceChange)
2781 F, cast<FunctionType>(StructTM.remapType(F->getFunctionType())),
2782 CloneMap);
2783 else
2784 makeCloneInPraceMap(F, CloneMap);
2785 LowerInFuncs.remapFunction(*NewF);
2786 if (NewF->isIntrinsic())
2787 Intrinsics.push_back(NewF);
2788 else
2789 NeedsPostProcess.push_back(NewF);
2790 if (InterfaceChange) {
2791 F->replaceAllUsesWith(NewF);
2792 F->eraseFromParent();
2793 }
2794 Changed = true;
2795 }
2796 StructTM.clear();
2797 IntTM.clear();
2798 CloneMap.clear();
2799
2800 SplitPtrStructs Splitter(DL, M.getContext(), &TM);
2801 for (Function *F : NeedsPostProcess)
2802 Splitter.processFunction(*F);
2803 for (Function *F : Intrinsics) {
2804 // use_empty() can also occur with cases like masked load, which will
2805 // have been rewritten out of the module by now but not erased.
2806 if (F->use_empty() || isRemovablePointerIntrinsic(F->getIntrinsicID())) {
2807 F->eraseFromParent();
2808 } else {
2809 std::optional<Function *> NewF = Intrinsic::remangleIntrinsicFunction(F);
2810 if (NewF)
2811 F->replaceAllUsesWith(*NewF);
2812 }
2813 }
2814 return Changed;
2815}
2816
2817bool AMDGPULowerBufferFatPointers::runOnModule(Module &M) {
2818 TargetPassConfig &TPC = getAnalysis<TargetPassConfig>();
2819 const TargetMachine &TM = TPC.getTM<TargetMachine>();
2820 auto GetTTI = [&](Function &F) -> const TargetTransformInfo * {
2821 if (F.isDeclaration())
2822 return nullptr;
2823 return &getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F);
2824 };
2825 auto GetSE = [&](Function &F) -> ScalarEvolution * {
2826 if (F.isDeclaration())
2827 return nullptr;
2828 return &getAnalysis<ScalarEvolutionWrapperPass>(F).getSE();
2829 };
2830 return run(M, TM, GetTTI, GetSE);
2831}
2832
2833char AMDGPULowerBufferFatPointers::ID = 0;
2834
2835char &llvm::AMDGPULowerBufferFatPointersID = AMDGPULowerBufferFatPointers::ID;
2836
2837void AMDGPULowerBufferFatPointers::getAnalysisUsage(AnalysisUsage &AU) const {
2841}
2842
2843#define PASS_DESC "Lower buffer fat pointer operations to buffer resources"
2844INITIALIZE_PASS_BEGIN(AMDGPULowerBufferFatPointers, DEBUG_TYPE, PASS_DESC,
2845 false, false)
2849INITIALIZE_PASS_END(AMDGPULowerBufferFatPointers, DEBUG_TYPE, PASS_DESC, false,
2850 false)
2851#undef PASS_DESC
2852
2854 return new AMDGPULowerBufferFatPointers();
2855}
2856
2859 auto &FA = MA.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
2860 auto GetTTI = [&](Function &F) -> const TargetTransformInfo * {
2861 if (F.isDeclaration())
2862 return nullptr;
2863 return &FA.getResult<TargetIRAnalysis>(F);
2864 };
2865 auto GetSE = [&](Function &F) -> ScalarEvolution * {
2866 if (F.isDeclaration())
2867 return nullptr;
2868 return &FA.getResult<ScalarEvolutionAnalysis>(F);
2869 };
2870 return AMDGPULowerBufferFatPointers().run(M, TM, GetTTI, GetSE)
2873}
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
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
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:2893
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.
LLVM_ABI bool isAllOnesValue() const
Return true if the expression is a constant all-ones value.
Type * getType() const
Return the LLVM type of this SCEV expression.
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 const SCEV * getTruncateOrNoop(const SCEV *V, Type *Ty)
Return a SCEV corresponding to a conversion of the input value to the specified type.
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.
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:3139
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:395
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