LLVM 20.0.0git
DXILResourceAccess.cpp
Go to the documentation of this file.
1//===- DXILResourceAccess.cpp - Resource access via load/store ------------===//
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
10#include "DirectX.h"
12#include "llvm/IR/Dominators.h"
13#include "llvm/IR/IRBuilder.h"
16#include "llvm/IR/Intrinsics.h"
17#include "llvm/IR/IntrinsicsDirectX.h"
19
20#define DEBUG_TYPE "dxil-resource-access"
21
22using namespace llvm;
23
26 const DataLayout &DL = II->getDataLayout();
27
28 auto *HandleType = cast<TargetExtType>(II->getOperand(0)->getType());
29 assert(HandleType->getName() == "dx.TypedBuffer" &&
30 "Unexpected typed buffer type");
31 Type *ContainedType = HandleType->getTypeParameter(0);
32
33 Type *LoadType =
34 StructType::get(ContainedType, Type::getInt1Ty(II->getContext()));
35
36 // We need the size of an element in bytes so that we can calculate the offset
37 // in elements given a total offset in bytes later.
38 Type *ScalarType = ContainedType->getScalarType();
39 uint64_t ScalarSize = DL.getTypeSizeInBits(ScalarType) / 8;
40
41 // Process users keeping track of indexing accumulated from GEPs.
42 struct AccessAndIndex {
43 User *Access;
44 Value *Index;
45 };
47 for (User *U : II->users())
48 Worklist.push_back({U, nullptr});
49
51 while (!Worklist.empty()) {
52 AccessAndIndex Current = Worklist.back();
53 Worklist.pop_back();
54
55 if (auto *GEP = dyn_cast<GetElementPtrInst>(Current.Access)) {
56 IRBuilder<> Builder(GEP);
57
58 Value *Index;
59 APInt ConstantOffset(DL.getIndexTypeSizeInBits(GEP->getType()), 0);
60 if (GEP->accumulateConstantOffset(DL, ConstantOffset)) {
61 APInt Scaled = ConstantOffset.udiv(ScalarSize);
62 Index = ConstantInt::get(Builder.getInt32Ty(), Scaled);
63 } else {
64 auto IndexIt = GEP->idx_begin();
65 assert(cast<ConstantInt>(IndexIt)->getZExtValue() == 0 &&
66 "GEP is not indexing through pointer");
67 ++IndexIt;
68 Index = *IndexIt;
69 assert(++IndexIt == GEP->idx_end() && "Too many indices in GEP");
70 }
71
72 for (User *U : GEP->users())
73 Worklist.push_back({U, Index});
74 DeadInsts.push_back(GEP);
75
76 } else if (auto *SI = dyn_cast<StoreInst>(Current.Access)) {
77 assert(SI->getValueOperand() != II && "Pointer escaped!");
78 IRBuilder<> Builder(SI);
79
80 Value *V = SI->getValueOperand();
81 if (V->getType() == ContainedType) {
82 // V is already the right type.
83 } else if (V->getType() == ScalarType) {
84 // We're storing a scalar, so we need to load the current value and only
85 // replace the relevant part.
86 auto *Load = Builder.CreateIntrinsic(
87 LoadType, Intrinsic::dx_resource_load_typedbuffer,
88 {II->getOperand(0), II->getOperand(1)});
89 auto *Struct = Builder.CreateExtractValue(Load, {0});
90
91 // If we have an offset from seeing a GEP earlier, use it.
92 Value *IndexOp = Current.Index
93 ? Current.Index
94 : ConstantInt::get(Builder.getInt32Ty(), 0);
95 V = Builder.CreateInsertElement(Struct, V, IndexOp);
96 } else {
97 llvm_unreachable("Store to typed resource has invalid type");
98 }
99
100 auto *Inst = Builder.CreateIntrinsic(
101 Builder.getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,
102 {II->getOperand(0), II->getOperand(1), V});
103 SI->replaceAllUsesWith(Inst);
104 DeadInsts.push_back(SI);
105
106 } else if (auto *LI = dyn_cast<LoadInst>(Current.Access)) {
107 IRBuilder<> Builder(LI);
108 Value *V = Builder.CreateIntrinsic(
109 LoadType, Intrinsic::dx_resource_load_typedbuffer,
110 {II->getOperand(0), II->getOperand(1)});
111 V = Builder.CreateExtractValue(V, {0});
112
113 if (Current.Index)
114 V = Builder.CreateExtractElement(V, Current.Index);
115
116 LI->replaceAllUsesWith(V);
117 DeadInsts.push_back(LI);
118
119 } else
120 llvm_unreachable("Unhandled instruction - pointer escaped?");
121 }
122
123 // Traverse the now-dead instructions in RPO and remove them.
124 for (Instruction *Dead : llvm::reverse(DeadInsts))
125 Dead->eraseFromParent();
126 II->eraseFromParent();
127}
128
130 bool Changed = false;
132 for (BasicBlock &BB : F)
133 for (Instruction &I : BB)
134 if (auto *II = dyn_cast<IntrinsicInst>(&I))
135 if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {
136 auto *HandleTy = cast<TargetExtType>(II->getArgOperand(0)->getType());
137 Resources.emplace_back(II, DRTM[HandleTy]);
138 }
139
140 for (auto &[II, RI] : Resources) {
141 if (RI.isTyped()) {
142 Changed = true;
144 }
145
146 // TODO: handle other resource types. We should probably have an
147 // `unreachable` here once we've added support for all of them.
148 }
149
150 return Changed;
151}
152
156 DXILResourceTypeMap *DRTM =
157 MAMProxy.getCachedResult<DXILResourceTypeAnalysis>(*F.getParent());
158 assert(DRTM && "DXILResourceTypeAnalysis must be available");
159
160 bool MadeChanges = transformResourcePointers(F, *DRTM);
161 if (!MadeChanges)
162 return PreservedAnalyses::all();
163
167 return PA;
168}
169
170namespace {
171class DXILResourceAccessLegacy : public FunctionPass {
172public:
173 bool runOnFunction(Function &F) override {
174 DXILResourceTypeMap &DRTM =
175 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
176
177 return transformResourcePointers(F, DRTM);
178 }
179 StringRef getPassName() const override { return "DXIL Resource Access"; }
180 DXILResourceAccessLegacy() : FunctionPass(ID) {}
181
182 static char ID; // Pass identification.
183 void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
186 }
187};
188char DXILResourceAccessLegacy::ID = 0;
189} // end anonymous namespace
190
191INITIALIZE_PASS_BEGIN(DXILResourceAccessLegacy, DEBUG_TYPE,
192 "DXIL Resource Access", false, false)
194INITIALIZE_PASS_END(DXILResourceAccessLegacy, DEBUG_TYPE,
195 "DXIL Resource Access", false, false)
196
198 return new DXILResourceAccessLegacy();
199}
@ Scaled
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static void replaceTypedBufferAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI)
static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM)
DXIL Resource Access
uint32_t Index
static bool runOnFunction(Function &F, bool PostInlining)
#define DEBUG_TYPE
Hexagon Common GEP
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
Definition: PassSupport.h:55
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:57
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:52
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
@ Struct
Class for arbitrary precision integers.
Definition: APInt.h:78
APInt udiv(const APInt &RHS) const
Unsigned division operation.
Definition: APInt.cpp:1547
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:253
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Definition: PassManager.h:410
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
Definition: BasicBlock.h:61
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
A parsed version of the target data layout string in and methods for querying it.
Definition: DataLayout.h:63
Analysis pass which computes a DominatorTree.
Definition: Dominators.h:279
Legacy analysis pass which computes a DominatorTree.
Definition: Dominators.h:317
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:310
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Definition: IRBuilder.h:2510
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Definition: IRBuilder.h:2498
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
Definition: IRBuilder.h:2554
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition: IRBuilder.h:545
CallInst * CreateIntrinsic(Intrinsic::ID ID, ArrayRef< Type * > Types, ArrayRef< Value * > Args, FMFSource FMFSource={}, const Twine &Name="")
Create a call to intrinsic ID with Args, mangled using Types.
Definition: IRBuilder.cpp:890
Type * getVoidTy()
Fetch the type representing void.
Definition: IRBuilder.h:583
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2704
A wrapper class for inspecting calls to intrinsic functions.
Definition: IntrinsicInst.h:48
An analysis over an "inner" IR unit that provides access to an analysis manager over a "outer" IR uni...
Definition: PassManager.h:692
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:111
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:117
void preserve()
Mark an analysis as preserved.
Definition: Analysis.h:131
bool empty() const
Definition: SmallVector.h:81
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:937
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:51
static 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:406
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static IntegerType * getInt1Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
Definition: Type.h:355
LLVM Value Representation.
Definition: Value.h:74
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:534
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto reverse(ContainerTy &&C)
Definition: STLExtras.h:420
FunctionPass * createDXILResourceAccessLegacyPass()
Pass to update resource accesses to use load/store directly.