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.