15#include "llvm/IR/IntrinsicsDirectX.h"
21#define DEBUG_TYPE "dxil-cbuffer-access"
26struct CBufferRowIntrin {
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");
88 if (
auto *
GEP = dyn_cast<GEPOperator>(Val)) {
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");
100 if (
auto *ATy = dyn_cast<ArrayType>(Member->getValueType()))
113 void createAndSetCurrentHandle(
IRBuilder<> &Builder) {
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;
131 unsigned int CurrentIndex =
135 Intrin.RetTy, Intrin.IID,
136 {Handle, ConstantInt::get(Builder.
getInt32Ty(), CurrentRow)},
nullptr,
141 Value *Result =
nullptr;
142 unsigned int Remaining =
143 ((
DL.getTypeSizeInBits(Ty) / 8) / Intrin.EltSize) - 1;
145 if (Remaining == 0) {
150 if (
auto *VT = dyn_cast<FixedVectorType>(Ty)) {
151 assert(VT->getNumElements() == 1 &&
152 "Can't have multiple elements here");
161 while (Remaining--) {
162 CurrentIndex %= Intrin.NumElts;
164 if (CurrentIndex == 0)
166 Intrin.RetTy, Intrin.IID,
167 {Handle, ConstantInt::get(Builder.getInt32Ty(), ++CurrentRow)},
168 nullptr,
Name +
".load");
176 for (
int I = 0, E = Extracts.size();
I < E; ++
I)
191 CBR.createAndSetCurrentHandle(Builder);
202 size_t ArrOffset,
size_t N,
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;
211 if (
ArrayType *ElemArrTy = dyn_cast<ArrayType>(ElemTy)) {
213 ElemArrTy->getNumElements(),
Name);
218 APInt CBufArrayOffset(
226 {Builder.getInt32(Offset)},
Name +
".dest");
237 ArrayType *ArrTy = dyn_cast<ArrayType>(CBR.getValueType());
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()) {
278 User *Cur = ToProcess.pop_back_val();
281 if (
auto *LI = dyn_cast<LoadInst>(Cur)) {
288 if (
auto *MCI = dyn_cast<MemCpyInst>(Cur)) {
294 if (isa<GetElementPtrInst>(Cur) || isa<GEPOperator>(Cur)) {
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"; }
338char DXILCBufferAccessLegacy::ID = 0;
345 return new DXILCBufferAccessLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
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.
A container for analyses that lazily runs them and caches their results.
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
Value * CreateInsertElement(Type *VecTy, Value *NewElt, 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.
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
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.
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
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 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.
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.
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.
ModulePass * createDXILCBufferAccessLegacyPass()
Pass to translate loads in the cbuffer address space to intrinsics.
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.