1//===- DXILResourceAccess.cpp - Resource access via load/store ------------===// 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 7//===----------------------------------------------------------------------===// 17#include "llvm/IR/IntrinsicsDirectX.h" 20#define DEBUG_TYPE "dxil-resource-access" 26assert(!PrevOffset &&
"Non-constant GEP chains not handled yet");
33// We need the size of an element in bytes so that we can calculate the 34// offset in elements given a total offset in bytes. 36 ScalarSize =
DL.getTypeSizeInBits(ScalarType) / 8;
39APInt ConstantOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
40if (
GEP->accumulateConstantOffset(
DL, ConstantOffset)) {
45auto IndexIt =
GEP->idx_begin();
46assert(cast<ConstantInt>(IndexIt)->getZExtValue() == 0 &&
47"GEP is not indexing through pointer");
50assert(++IndexIt ==
GEP->idx_end() &&
"Too many indices in GEP");
60Value *V = SI->getValueOperand();
61if (V->getType() == ContainedType) {
62// V is already the right type. 65// We're storing a scalar, so we need to load the current value and only 66// replace the relevant part. 68 LoadType, Intrinsic::dx_resource_load_typedbuffer,
69 {
II->getOperand(0),
II->getOperand(1)});
72// If we have an offset from seeing a GEP earlier, use that. Otherwise, 0. 81 Builder.
getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,
82 {II->getOperand(0), II->getOperand(1), V});
83 SI->replaceAllUsesWith(Inst);
91Value *V = SI->getValueOperand();
92// TODO: break up larger types 94 Builder.
getVoidTy(), Intrinsic::dx_resource_store_rawbuffer,
95 {II->getOperand(0), II->getOperand(1), Offset, V});
96 SI->replaceAllUsesWith(Inst);
102case dxil::ResourceKind::TypedBuffer:
104case dxil::ResourceKind::RawBuffer:
105case dxil::ResourceKind::StructuredBuffer:
107case dxil::ResourceKind::Texture1D:
108case dxil::ResourceKind::Texture2D:
109case dxil::ResourceKind::Texture2DMS:
110case dxil::ResourceKind::Texture3D:
111case dxil::ResourceKind::TextureCube:
112case dxil::ResourceKind::Texture1DArray:
113case dxil::ResourceKind::Texture2DArray:
114case dxil::ResourceKind::Texture2DMSArray:
115case dxil::ResourceKind::TextureCubeArray:
116case dxil::ResourceKind::FeedbackTexture2D:
117case dxil::ResourceKind::FeedbackTexture2DArray:
119/*gen_crash_diag=*/false);
121case dxil::ResourceKind::CBuffer:
122case dxil::ResourceKind::Sampler:
123case dxil::ResourceKind::TBuffer:
124case dxil::ResourceKind::RTAccelerationStructure:
125case dxil::ResourceKind::Invalid:
126case dxil::ResourceKind::NumEntries:
139 Builder.
CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,
140 {
II->getOperand(0),
II->getOperand(1)});
151// TODO: break up larger types 156 Builder.
CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_rawbuffer,
157 {
II->getOperand(0),
II->getOperand(1),
Offset});
166case dxil::ResourceKind::TypedBuffer:
168case dxil::ResourceKind::RawBuffer:
169case dxil::ResourceKind::StructuredBuffer:
171case dxil::ResourceKind::Texture1D:
172case dxil::ResourceKind::Texture2D:
173case dxil::ResourceKind::Texture2DMS:
174case dxil::ResourceKind::Texture3D:
175case dxil::ResourceKind::TextureCube:
176case dxil::ResourceKind::Texture1DArray:
177case dxil::ResourceKind::Texture2DArray:
178case dxil::ResourceKind::Texture2DMSArray:
179case dxil::ResourceKind::TextureCubeArray:
180case dxil::ResourceKind::FeedbackTexture2D:
181case dxil::ResourceKind::FeedbackTexture2DArray:
182case dxil::ResourceKind::CBuffer:
183case dxil::ResourceKind::TBuffer:
186case dxil::ResourceKind::Sampler:
187case dxil::ResourceKind::RTAccelerationStructure:
188case dxil::ResourceKind::Invalid:
189case dxil::ResourceKind::NumEntries:
196// Process users keeping track of indexing accumulated from GEPs. 197structAccessAndOffset {
206while (!Worklist.
empty()) {
207 AccessAndOffset Current = Worklist.
back();
210if (
auto *
GEP = dyn_cast<GetElementPtrInst>(Current.Access)) {
218 }
elseif (
auto *SI = dyn_cast<StoreInst>(Current.Access)) {
219assert(SI->getValueOperand() !=
II &&
"Pointer escaped!");
223 }
elseif (
auto *LI = dyn_cast<LoadInst>(Current.Access)) {
231// Traverse the now-dead instructions in RPO and remove them. 233 Dead->eraseFromParent();
234II->eraseFromParent();
242if (
auto *
II = dyn_cast<IntrinsicInst>(&
I))
243if (
II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {
244auto *HandleTy = cast<TargetExtType>(
II->getArgOperand(0)->getType());
248for (
auto &[
II, RI] : Resources)
259assert(DRTM &&
"DXILResourceTypeAnalysis must be available");
276 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
280StringRef getPassName()
const override{
return"DXIL Resource Access"; }
283staticcharID;
// Pass identification. 289char DXILResourceAccessLegacy::ID = 0;
290}
// end anonymous namespace 293"DXIL Resource Access",
false,
false)
299returnnew 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.