20#include "llvm/IR/IntrinsicsDirectX.h"
25#define DEBUG_TYPE "dxil-resource-access"
31 assert(!PrevOffset &&
"Non-constant GEP chains not handled yet");
41 ScalarSize =
DL.getTypeSizeInBits(ScalarType) / 8;
44 APInt ConstantOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
45 if (
GEP->accumulateConstantOffset(
DL, ConstantOffset)) {
50 auto IndexIt =
GEP->idx_begin();
51 assert(cast<ConstantInt>(IndexIt)->getZExtValue() == 0 &&
52 "GEP is not indexing through pointer");
55 assert(++IndexIt ==
GEP->idx_end() &&
"Too many indices in GEP");
65 Value *V = SI->getValueOperand();
66 if (V->getType() == ContainedType) {
73 LoadType, Intrinsic::dx_resource_load_typedbuffer,
74 {
II->getOperand(0),
II->getOperand(1)});
86 Builder.
getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,
87 {II->getOperand(0), II->getOperand(1), V});
88 SI->replaceAllUsesWith(Inst);
96 Value *V = SI->getValueOperand();
99 Builder.
getVoidTy(), Intrinsic::dx_resource_store_rawbuffer,
100 {II->getOperand(0), II->getOperand(1), Offset, V});
101 SI->replaceAllUsesWith(Inst);
107 case dxil::ResourceKind::TypedBuffer:
109 case dxil::ResourceKind::RawBuffer:
110 case dxil::ResourceKind::StructuredBuffer:
112 case dxil::ResourceKind::Texture1D:
113 case dxil::ResourceKind::Texture2D:
114 case dxil::ResourceKind::Texture2DMS:
115 case dxil::ResourceKind::Texture3D:
116 case dxil::ResourceKind::TextureCube:
117 case dxil::ResourceKind::Texture1DArray:
118 case dxil::ResourceKind::Texture2DArray:
119 case dxil::ResourceKind::Texture2DMSArray:
120 case dxil::ResourceKind::TextureCubeArray:
121 case dxil::ResourceKind::FeedbackTexture2D:
122 case dxil::ResourceKind::FeedbackTexture2DArray:
125 case dxil::ResourceKind::CBuffer:
126 case dxil::ResourceKind::Sampler:
127 case dxil::ResourceKind::TBuffer:
128 case dxil::ResourceKind::RTAccelerationStructure:
129 case dxil::ResourceKind::Invalid:
130 case dxil::ResourceKind::NumEntries:
143 Builder.
CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,
144 {
II->getOperand(0),
II->getOperand(1)});
152 if (
auto *VT = dyn_cast<FixedVectorType>(LI->
getType()))
153 if (VT->getNumElements() == 1 && !isa<FixedVectorType>(V->getType()))
167 Builder.
CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_rawbuffer,
168 {
II->getOperand(0),
II->getOperand(1),
Offset});
177 case dxil::ResourceKind::TypedBuffer:
179 case dxil::ResourceKind::RawBuffer:
180 case dxil::ResourceKind::StructuredBuffer:
182 case dxil::ResourceKind::Texture1D:
183 case dxil::ResourceKind::Texture2D:
184 case dxil::ResourceKind::Texture2DMS:
185 case dxil::ResourceKind::Texture3D:
186 case dxil::ResourceKind::TextureCube:
187 case dxil::ResourceKind::Texture1DArray:
188 case dxil::ResourceKind::Texture2DArray:
189 case dxil::ResourceKind::Texture2DMSArray:
190 case dxil::ResourceKind::TextureCubeArray:
191 case dxil::ResourceKind::FeedbackTexture2D:
192 case dxil::ResourceKind::FeedbackTexture2DArray:
193 case dxil::ResourceKind::CBuffer:
194 case dxil::ResourceKind::TBuffer:
197 case dxil::ResourceKind::Sampler:
198 case dxil::ResourceKind::RTAccelerationStructure:
199 case dxil::ResourceKind::Invalid:
200 case dxil::ResourceKind::NumEntries:
210 auto *BB = Start->getParent();
213 for (
User *U : Start->users()) {
214 if (
auto *
I = dyn_cast<Instruction>(U)) {
215 if (
I->getParent() == BB)
221 while (!Worklist.
empty()) {
227 for (
User *U :
I->users()) {
228 if (
auto *J = dyn_cast<Instruction>(U)) {
229 if (J->getParent() == BB)
233 for (
Use &V :
I->operands()) {
234 if (
auto *J = dyn_cast<Instruction>(V)) {
235 if (J->getParent() == BB && V != Start)
259 Value *Val = Phi->getIncomingValueForBlock(BB);
264 if (
auto *PhiNested = dyn_cast<PHINode>(
I)) {
265 VMap[PhiNested] = PhiNested->getIncomingValueForBlock(BB);
280 for (
User *U :
II->users()) {
281 auto *Phi = dyn_cast<PHINode>(U);
287 bool HasReturnUse = isa<ReturnInst>(UsesInBlock.
back());
289 for (
unsigned I = 0, E = Phi->getNumIncomingValues();
I < E;
I++) {
290 auto *CurrIncomingBB = Phi->getIncomingBlock(
I);
293 PrevBBDeadInsts.
push_back(&CurrIncomingBB->back());
308 Dead->eraseFromParent();
309 CurrBBDeadInsts.
clear();
314 struct AccessAndOffset {
319 for (
User *U :
II->users())
323 while (!Worklist.
empty()) {
324 AccessAndOffset Current = Worklist.
back();
327 if (
auto *
GEP = dyn_cast<GetElementPtrInst>(Current.Access)) {
335 }
else if (
auto *SI = dyn_cast<StoreInst>(Current.Access)) {
336 assert(SI->getValueOperand() !=
II &&
"Pointer escaped!");
340 }
else if (
auto *LI = dyn_cast<LoadInst>(Current.Access)) {
349 Dead->eraseFromParent();
350 II->eraseFromParent();
359 if (
auto *
II = dyn_cast<IntrinsicInst>(&
I))
360 if (
II->getIntrinsicID() == Intrinsic::dx_resource_getpointer)
364 if (
auto *
II = dyn_cast<IntrinsicInst>(&
I))
365 if (
II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {
366 auto *HandleTy = cast<TargetExtType>(
II->getArgOperand(0)->getType());
370 for (
auto *Dead : PrevBBDeadInsts)
371 Dead->eraseFromParent();
372 PrevBBDeadInsts.
clear();
373 for (
auto *Dead : DeadBB)
374 Dead->eraseFromParent();
377 for (
auto &[
II, RI] : Resources)
380 return !Resources.
empty();
388 assert(DRTM &&
"DXILResourceTypeAnalysis must be available");
405 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
408 StringRef getPassName()
const override {
return "DXIL Resource Access"; }
417char DXILResourceAccessLegacy::ID = 0;
421 "DXIL Resource Access",
false,
false)
427 return new DXILResourceAccessLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB, IRBuilder<> &Builder, SmallVector< Instruction * > &UsesInBlock)
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 SmallVector< Instruction * > collectBlockUseDef(Instruction *Start)
static void phiNodeReplacement(IntrinsicInst *II, SmallVectorImpl< Instruction * > &PrevBBDeadInsts, SetVector< BasicBlock * > &DeadBB)
static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI)
static void createRawStore(IntrinsicInst *II, StoreInst *SI, Value *Offset)
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
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)
This file implements a set that has insertion order iteration characteristics.
Class for arbitrary precision integers.
LLVM_ABI 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.
const Instruction & back() const
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
A parsed version of the target data layout string in and methods for querying it.
ValueT lookup(const_arg_type_t< KeyT > Val) const
lookup - Return the entry for the specified key, or a default constructed value if no such entry exis...
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.
LLVM_ABI 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.
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
InstTy * Insert(InstTy *I, const Twine &Name="") const
Insert and return the specified instruction.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
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...
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.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
A vector that has set insertion semantics.
void clear()
Completely clear the SetVector.
bool insert(const value_type &X)
Insert a new element into the SetVector.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
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 LLVM_ABI 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 LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI bool isTyped() const
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.
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...
auto reverse(ContainerTy &&C)
FunctionPass * createDXILResourceAccessLegacyPass()
Pass to update resource accesses to use load/store directly.
void sort(IteratorTy Start, IteratorTy End)
@ RF_IgnoreMissingLocals
If this flag is set, the remapper ignores missing function-local entries (Argument,...
@ RF_NoModuleLevelChanges
If this flag is set, the remapper knows that only local values within a function (such as an instruct...
void RemapInstruction(Instruction *I, ValueToValueMapTy &VM, RemapFlags Flags=RF_None, ValueMapTypeRemapper *TypeMapper=nullptr, ValueMaterializer *Materializer=nullptr, const MetadataPredicate *IdentityMD=nullptr)
Convert the instruction operands from referencing the current values into those specified by VM.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.