15#include "llvm/IR/IntrinsicsDirectX.h"
21#define DEBUG_TYPE "dxil-cbuffer-access"
26struct CBufferRowIntrin {
33 assert(Ty == Ty->getScalarType() &&
"Expected scalar type");
35 switch (
DL.getTypeSizeInBits(Ty)) {
37 IID = Intrinsic::dx_resource_load_cbufferrow_8;
43 IID = Intrinsic::dx_resource_load_cbufferrow_4;
49 IID = Intrinsic::dx_resource_load_cbufferrow_2;
61struct CBufferResource {
70 : GVHandle(GVHandle), Member(Member), MemberOffset(MemberOffset) {}
75 return Member->users();
81 size_t getOffsetForCBufferGEP(
Value *Val) {
83 "Expected a pointer-typed value");
91 assert(
GEP->getPointerOperand() == Member &&
92 "Indirect access to resource handle");
95 APInt ConstantOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
96 bool Success =
GEP->accumulateConstantOffset(
DL, ConstantOffset);
98 assert(
Success &&
"Offsets into cbuffer globals must be constant");
113 void createAndSetCurrentHandle(
IRBuilder<> &Builder) {
114 Handle = Builder.CreateLoad(GVHandle->
getValueType(), GVHandle,
121 const Twine &Name =
"") {
123 "Expected a handle for this cbuffer global resource to be created "
124 "before loading a value from it");
127 size_t TargetOffset = MemberOffset +
Offset;
128 CBufferRowIntrin Intrin(
DL, Ty->getScalarType());
131 unsigned int CurrentIndex =
134 auto *CBufLoad = Builder.CreateIntrinsic(
135 Intrin.RetTy, Intrin.IID,
136 {Handle, ConstantInt::get(Builder.getInt32Ty(), CurrentRow)},
nullptr,
138 auto *Elt = Builder.CreateExtractValue(CBufLoad, {CurrentIndex++},
141 Value *Result =
nullptr;
142 unsigned int Remaining =
143 ((
DL.getTypeSizeInBits(Ty) / 8) / Intrin.EltSize) - 1;
145 if (Remaining == 0) {
151 assert(VT->getNumElements() == 1 &&
152 "Can't have multiple elements here");
154 Builder.getInt32(0), Name);
161 while (Remaining--) {
162 CurrentIndex %= Intrin.NumElts;
164 if (CurrentIndex == 0)
165 CBufLoad = Builder.CreateIntrinsic(
166 Intrin.RetTy, Intrin.IID,
167 {Handle, ConstantInt::get(Builder.getInt32Ty(), ++CurrentRow)},
168 nullptr, Name +
".load");
170 Extracts.
push_back(Builder.CreateExtractValue(CBufLoad, {CurrentIndex++},
176 for (
int I = 0,
E = Extracts.
size();
I <
E; ++
I)
178 Builder.CreateInsertElement(Result, Extracts[
I], Builder.getInt32(
I),
191 CBR.createAndSetCurrentHandle(Builder);
202 size_t ArrOffset,
size_t N,
203 const Twine &Name =
"") {
205 Type *ElemTy = ArrTy->getElementType();
206 size_t ElemTySize =
DL.getTypeAllocSize(ElemTy);
207 for (
unsigned I = 0;
I <
N; ++
I) {
208 size_t Offset = ArrOffset +
I * ElemTySize;
213 ElemArrTy->getNumElements(), Name);
218 APInt CBufArrayOffset(
223 CBR.loadValue(Builder, ElemTy, CBufArrayOffset.
getZExtValue(), Name);
225 Builder.CreateInBoundsGEP(Builder.getInt8Ty(), MCI->
getDest(),
226 {Builder.getInt32(Offset)}, Name +
".dest");
238 assert(ArrTy &&
"MemCpy lowering is only supported for array types");
243 "Expected MemCpy source to be a cbuffer global variable");
249 if (ByteLength == 0) {
256 Type *ElemTy = ArrTy->getElementType();
257 size_t ElemSize =
DL.getTypeAllocSize(ElemTy);
258 assert(ByteLength % ElemSize == 0 &&
259 "Length of bytes to MemCpy must be divisible by allocation size of "
260 "source/destination array elements");
261 size_t ElemsToCpy = ByteLength / ElemSize;
264 CBR.createAndSetCurrentHandle(Builder);
277 while (!ToProcess.
empty()) {
311 CBufferResource CBR(Mapping.Handle, Member.GV, Member.Offset);
313 Member.GV->removeFromParent();
316 CBufMD->eraseFromModule();
330class DXILCBufferAccessLegacy :
public ModulePass {
333 StringRef getPassName()
const override {
return "DXIL CBuffer Access"; }
334 DXILCBufferAccessLegacy() : ModulePass(
ID) {}
338char DXILCBufferAccessLegacy::ID = 0;
345 return new DXILCBufferAccessLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static bool replaceCBufferAccesses(Module &M)
static void copyArrayElemsForMemCpy(IRBuilder<> &Builder, MemCpyInst *MCI, CBufferResource &CBR, ArrayType *ArrTy, size_t ArrOffset, size_t N, const Twine &Name="")
This function recursively copies N array elements from the cbuffer resource CBR to the MemCpy Destina...
static void replaceLoad(LoadInst *LI, CBufferResource &CBR, SmallVectorImpl< WeakTrackingVH > &DeadInsts)
Replace load via cbuffer global with a load from the cbuffer handle itself.
static void replaceAccessesWithHandle(CBufferResource &CBR)
static void replaceMemCpy(MemCpyInst *MCI, CBufferResource &CBR)
Replace memcpy from a cbuffer global with a memcpy from the cbuffer handle itself.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static Type * getValueType(Value *V)
Returns the type of the given value/instruction V.
Class for arbitrary precision integers.
uint64_t getZExtValue() const
Get zero extended value.
This is the shared class of boolean and integer constants.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
A parsed version of the target data layout string in and methods for querying it.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this global belongs to.
Type * getValueType() const
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
An instruction for reading from memory.
Value * getPointerOperand()
This class wraps the llvm.memcpy intrinsic.
Value * getLength() const
Value * getDest() const
This is just like getRawDest, but it strips off any cast instructions (including addrspacecast) that ...
Value * getSource() const
This is just like getRawSource, but it strips off any cast instructions that feed it,...
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
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.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
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.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
A range adaptor for a pair of iterators.
#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.
const unsigned CBufferRowSizeInBytes
APInt translateCBufArrayOffset(const DataLayout &DL, APInt Offset, ArrayType *Ty)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool RecursivelyDeleteTriviallyDeadInstructions(Value *V, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, std::function< void(Value *)> AboutToDeleteCallback=std::function< void(Value *)>())
If the specified value is a trivially dead instruction, delete it.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
ModulePass * createDXILCBufferAccessLegacyPass()
Pass to translate loads in the cbuffer address space to intrinsics.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
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...
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.