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