17#include "llvm/IR/IntrinsicsDirectX.h"
20#define DEBUG_TYPE "dxil-resource-access"
26 assert(!PrevOffset &&
"Non-constant GEP chains not handled yet");
36 ScalarSize =
DL.getTypeSizeInBits(ScalarType) / 8;
39 APInt ConstantOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
40 if (
GEP->accumulateConstantOffset(
DL, ConstantOffset)) {
45 auto IndexIt =
GEP->idx_begin();
46 assert(cast<ConstantInt>(IndexIt)->getZExtValue() == 0 &&
47 "GEP is not indexing through pointer");
50 assert(++IndexIt ==
GEP->idx_end() &&
"Too many indices in GEP");
60 Value *V = SI->getValueOperand();
61 if (V->getType() == ContainedType) {
68 LoadType, Intrinsic::dx_resource_load_typedbuffer,
69 {
II->getOperand(0),
II->getOperand(1)});
81 Builder.
getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,
82 {II->getOperand(0), II->getOperand(1), V});
83 SI->replaceAllUsesWith(Inst);
91 Value *V = SI->getValueOperand();
94 Builder.
getVoidTy(), Intrinsic::dx_resource_store_rawbuffer,
95 {II->getOperand(0), II->getOperand(1), Offset, V});
96 SI->replaceAllUsesWith(Inst);
102 case dxil::ResourceKind::TypedBuffer:
104 case dxil::ResourceKind::RawBuffer:
105 case dxil::ResourceKind::StructuredBuffer:
107 case dxil::ResourceKind::Texture1D:
108 case dxil::ResourceKind::Texture2D:
109 case dxil::ResourceKind::Texture2DMS:
110 case dxil::ResourceKind::Texture3D:
111 case dxil::ResourceKind::TextureCube:
112 case dxil::ResourceKind::Texture1DArray:
113 case dxil::ResourceKind::Texture2DArray:
114 case dxil::ResourceKind::Texture2DMSArray:
115 case dxil::ResourceKind::TextureCubeArray:
116 case dxil::ResourceKind::FeedbackTexture2D:
117 case dxil::ResourceKind::FeedbackTexture2DArray:
121 case dxil::ResourceKind::CBuffer:
122 case dxil::ResourceKind::Sampler:
123 case dxil::ResourceKind::TBuffer:
124 case dxil::ResourceKind::RTAccelerationStructure:
125 case dxil::ResourceKind::Invalid:
126 case dxil::ResourceKind::NumEntries:
139 Builder.
CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,
140 {
II->getOperand(0),
II->getOperand(1)});
156 Builder.
CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_rawbuffer,
157 {
II->getOperand(0),
II->getOperand(1),
Offset});
166 case dxil::ResourceKind::TypedBuffer:
168 case dxil::ResourceKind::RawBuffer:
169 case dxil::ResourceKind::StructuredBuffer:
171 case dxil::ResourceKind::Texture1D:
172 case dxil::ResourceKind::Texture2D:
173 case dxil::ResourceKind::Texture2DMS:
174 case dxil::ResourceKind::Texture3D:
175 case dxil::ResourceKind::TextureCube:
176 case dxil::ResourceKind::Texture1DArray:
177 case dxil::ResourceKind::Texture2DArray:
178 case dxil::ResourceKind::Texture2DMSArray:
179 case dxil::ResourceKind::TextureCubeArray:
180 case dxil::ResourceKind::FeedbackTexture2D:
181 case dxil::ResourceKind::FeedbackTexture2DArray:
182 case dxil::ResourceKind::CBuffer:
183 case dxil::ResourceKind::TBuffer:
186 case dxil::ResourceKind::Sampler:
187 case dxil::ResourceKind::RTAccelerationStructure:
188 case dxil::ResourceKind::Invalid:
189 case dxil::ResourceKind::NumEntries:
197 struct AccessAndOffset {
202 for (
User *U :
II->users())
206 while (!Worklist.
empty()) {
207 AccessAndOffset Current = Worklist.
back();
210 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(Current.Access)) {
218 }
else if (
auto *SI = dyn_cast<StoreInst>(Current.Access)) {
219 assert(SI->getValueOperand() !=
II &&
"Pointer escaped!");
223 }
else if (
auto *LI = dyn_cast<LoadInst>(Current.Access)) {
233 Dead->eraseFromParent();
234 II->eraseFromParent();
238 bool Changed =
false;
242 if (
auto *
II = dyn_cast<IntrinsicInst>(&
I))
243 if (
II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {
244 auto *HandleTy = cast<TargetExtType>(
II->getArgOperand(0)->getType());
248 for (
auto &[
II, RI] : Resources)
259 assert(DRTM &&
"DXILResourceTypeAnalysis must be available");
276 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
280 StringRef getPassName()
const override {
return "DXIL Resource Access"; }
289char DXILResourceAccessLegacy::ID = 0;
293 "DXIL Resource Access",
false,
false)
299 return new DXILResourceAccessLegacy();
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static Value * calculateGEPOffset(GetElementPtrInst *GEP, Value *PrevOffset, dxil::ResourceTypeInfo &RTI)
static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM)
static void createRawLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset)
static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void createTypedBufferLoad(IntrinsicInst *II, LoadInst *LI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void createTypedBufferStore(IntrinsicInst *II, StoreInst *SI, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI)
static void createRawStore(IntrinsicInst *II, StoreInst *SI, Value *Offset)
static bool runOnFunction(Function &F, bool PostInlining)
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Class for arbitrary precision integers.
APInt udiv(const APInt &RHS) const
Unsigned division operation.
A container for analyses that lazily runs them and caches their results.
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()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
A parsed version of the target data layout string in and methods for querying it.
Analysis pass which computes a DominatorTree.
Legacy analysis pass which computes a DominatorTree.
FunctionPass class - This class is used to implement most global optimizations.
an instruction for type-safe pointer arithmetic to access elements of arrays and structs
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
IntegerType * getInt1Ty()
Fetch the type representing a single bit.
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
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.
Type * getVoidTy()
Fetch the type representing void.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
A wrapper class for inspecting calls to intrinsic functions.
An instruction for reading from memory.
An analysis over an "inner" IR unit that provides access to an analysis manager over a "outer" IR uni...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void preserve()
Mark an analysis as preserved.
reference emplace_back(ArgTypes &&... Args)
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.
StringRef - Represent a constant reference to a string, i.e.
static StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
Type * getTypeParameter(unsigned i) const
The instances of the Type class are immutable: once they are created, they are never changed.
static IntegerType * getInt32Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
TargetExtType * getHandleTy() const
dxil::ResourceKind getResourceKind() const
#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.
This is an optimization pass for GlobalISel generic memory operations.
auto reverse(ContainerTy &&C)
FunctionPass * createDXILResourceAccessLegacyPass()
Pass to update resource accesses to use load/store directly.
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.