LLVM: lib/Target/DirectX/DXILOpLowering.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
25#include "llvm/IR/IntrinsicsDirectX.h"
31
32#define DEBUG_TYPE "dxil-op-lower"
33
34using namespace llvm;
36
38 switch (F.getIntrinsicID()) {
39 case Intrinsic::dx_dot2:
40 case Intrinsic::dx_dot3:
41 case Intrinsic::dx_dot4:
42 return true;
43 }
44 return false;
45}
46
49 auto *VecArg = dyn_cast(Arg->getType());
50 for (unsigned I = 0; I < VecArg->getNumElements(); ++I) {
53 ExtractedElements.push_back(ExtractedElement);
54 }
55 return ExtractedElements;
56}
57
60
62 assert(NumOperands > 0);
64 [[maybe_unused]] auto *VecArg0 = dyn_cast(Arg0->getType());
67 for (unsigned I = 1; I < NumOperands; ++I) {
69 [[maybe_unused]] auto *VecArg = dyn_cast(Arg->getType());
71 assert(VecArg0->getElementType() == VecArg->getElementType());
72 assert(VecArg0->getNumElements() == VecArg->getNumElements());
74 NewOperands.append(NextOperandList.begin(), NextOperandList.end());
75 }
76 return NewOperands;
77}
78
79namespace {
80class OpLowerer {
86
87public:
89 : M(M), OpBuilder(M), DBM(DBM), DRTM(DRTM) {}
90
91
92
93 [[nodiscard]] bool
97 CallInst *CI = dyn_cast(U);
98 if (!CI)
99 continue;
100
101 if (Error E = ReplaceCall(CI)) {
102 std::string Message(toString(std::move(E)));
105 M.getContext().diagnose(Diag);
106 return true;
107 }
108 }
109 if (F.user_empty())
110 F.eraseFromParent();
111 return false;
112 }
113
114 struct IntrinArgSelect {
115 enum class Type {
116#define DXIL_OP_INTRINSIC_ARG_SELECT_TYPE(name) name,
117#include "DXILOperation.inc"
118 };
121 };
122
123 [[nodiscard]] bool
127 assert(!(IsVectorArgExpansion && ArgSelects.size()) &&
128 "Cann't do vector arg expansion when using arg selects.");
129 return replaceFunction(F, [&](CallInst *CI) -> Error {
130 OpBuilder.getIRB().SetInsertPoint(CI);
132 if (ArgSelects.size()) {
133 for (const IntrinArgSelect &A : ArgSelects) {
134 switch (A.Type) {
135 case IntrinArgSelect::Type::Index:
136 Args.push_back(CI->getArgOperand(A.Value));
137 break;
138 case IntrinArgSelect::Type::I8:
139 Args.push_back(OpBuilder.getIRB().getInt8((uint8_t)A.Value));
140 break;
141 case IntrinArgSelect::Type::I32:
142 Args.push_back(OpBuilder.getIRB().getInt32(A.Value));
143 break;
144 }
145 }
146 } else if (IsVectorArgExpansion) {
148 } else {
150 }
151
155 return E;
156
160 });
161 }
162
163 [[nodiscard]] bool replaceFunctionWithNamedStructOp(
167 return replaceFunction(F, [&](CallInst *CI) -> Error {
169 OpBuilder.getIRB().SetInsertPoint(CI);
170 if (IsVectorArgExpansion) {
173 } else
175
179 return E;
180 if (Error E = ReplaceUses(CI, *OpCall))
181 return E;
182
184 });
185 }
186
187
188
189
190
191
194 Intrinsic::dx_resource_casthandle, {Ty, V->getType()}, {V});
196 return Cast;
197 }
198
199 void cleanupHandleCasts() {
202
203 for (CallInst *Cast : CleanupCasts) {
204
205
206
207
209
210
211
214 continue;
215 }
216
217
219 assert(Def->getIntrinsicID() == Intrinsic::dx_resource_casthandle &&
220 "Unbalanced pair of temporary handle casts");
223 }
225 assert(Cast->user_empty() && "Temporary handle cast still has users");
227 }
228
229
233 F->eraseFromParent();
234
235 CleanupCasts.clear();
236 }
237
238
239
240
241
242
243 void removeResourceGlobals(CallInst *CI) {
245 if (StoreInst *Store = dyn_cast(User)) {
247 Store->eraseFromParent();
248 if (GlobalVariable *GV = dyn_cast(V))
249 if (GV->use_empty()) {
250 GV->removeDeadConstantUsers();
251 GV->eraseFromParent();
252 }
253 }
254 }
255 }
256
257 [[nodiscard]] bool lowerToCreateHandle(Function &F) {
261
262 return replaceFunction(F, [&](CallInst *CI) -> Error {
264
265 auto *It = DBM.find(CI);
266 assert(It != DBM.end() && "Resource not in map?");
268
269 const auto &Binding = RI.getBinding();
271
273 if (Binding.LowerBound != 0)
275 ConstantInt::get(Int32Ty, Binding.LowerBound));
276
277 std::array<Value *, 4> Args{
279 ConstantInt::get(Int32Ty, Binding.RecordID), IndexOp,
284 return E;
285
286 Value *Cast = createTmpHandleCast(*OpCall, CI->getType());
287
288 removeResourceGlobals(CI);
289
293 });
294 }
295
296 [[nodiscard]] bool lowerToBindAndAnnotateHandle(Function &F) {
299
300 return replaceFunction(F, [&](CallInst *CI) -> Error {
302
303 auto *It = DBM.find(CI);
304 assert(It != DBM.end() && "Resource not in map?");
306
307 const auto &Binding = RI.getBinding();
310
312 if (Binding.LowerBound != 0)
314 ConstantInt::get(Int32Ty, Binding.LowerBound));
315
316 std::pair<uint32_t, uint32_t> Props =
318
319
320
321 uint32_t Unbounded = std::numeric_limits<uint32_t>::max();
322 uint32_t UpperBound = Binding.Size == Unbounded
323 ? Unbounded
324 : Binding.LowerBound + Binding.Size - 1;
325 Constant *ResBind = OpBuilder.getResBind(Binding.LowerBound, UpperBound,
326 Binding.Space, RC);
327 std::array<Value *, 3> BindArgs{ResBind, IndexOp, CI->getArgOperand(4)};
329 OpCode::CreateHandleFromBinding, BindArgs, CI->getName());
331 return E;
332
333 std::array<Value *, 2> AnnotateArgs{
334 *OpBind, OpBuilder.getResProps(Props.first, Props.second)};
336 OpCode::AnnotateHandle, AnnotateArgs,
339 return E;
340
341 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->getType());
342
343 removeResourceGlobals(CI);
344
347
349 });
350 }
351
352
353
354
355 bool lowerHandleFromBinding(Function &F) {
358 return lowerToCreateHandle(F);
359 return lowerToBindAndAnnotateHandle(F);
360 }
361
364 if (auto *EVI = dyn_cast(U.getUser())) {
365
366 if (EVI->getNumIndices() != 1)
368 "Splitdouble has only 2 elements");
369 EVI->setOperand(0, Op);
370 } else {
371 return make_error(
372 "Splitdouble use is not ExtractValueInst",
374 }
375 }
376
378
380 }
381
382
383
386
389
390 if (HasCheckBit) {
391 auto *ST = cast(OldTy);
392
393 Value *CheckOp = nullptr;
396 if (auto *EVI = dyn_cast(U.getUser())) {
399
400 if (Indices[0] != 1)
401 continue;
402 if (!CheckOp) {
405 OpCode::CheckAccessFullyMapped, {NewEVI},
406 OldResult->hasName() ? OldResult->getName() + "_check"
408 Int32Ty);
410 return E;
411 CheckOp = *OpCall;
412 }
413 EVI->replaceAllUsesWith(CheckOp);
414 EVI->eraseFromParent();
415 }
416 }
417
419
422 }
423
425 isa(*OldResult->user_begin()) &&
426 "Expected only use to be extract of first element");
427 OldResult = cast(*OldResult->user_begin());
428 OldTy = ST->getElementType(0);
429 }
430
431
432 if (!isa(OldTy)) {
436 if (OldResult != Intrin) {
437 assert(Intrin->use_empty() && "Intrinsic still has uses?");
439 }
441 }
442
443 std::array<Value *, 4> Extracts = {};
445
446
447
449 if (auto *EEI = dyn_cast(U.getUser())) {
450 if (auto *IndexOp = dyn_cast(EEI->getIndexOperand())) {
451 size_t IndexVal = IndexOp->getZExtValue();
452 assert(IndexVal < 4 && "Index into buffer load out of range");
453 if (!Extracts[IndexVal])
456 EEI->eraseFromParent();
457 } else {
459 }
460 }
461 }
462
463 const auto *VecTy = cast(OldTy);
464 const unsigned N = VecTy->getNumElements();
465
466
467
468 if (!DynamicAccesses.empty()) {
470 Constant *Zero = ConstantInt::get(Int32Ty, 0);
471
472 Type *ElTy = VecTy->getElementType();
473 Type *ArrayTy = ArrayType::get(ElTy, N);
475
476 for (int I = 0, E = N; I != E; ++I) {
477 if (!Extracts[I])
480 ArrayTy, Alloca, {Zero, ConstantInt::get(Int32Ty, I)});
482 }
483
486 {Zero, EEI->getIndexOperand()});
489 EEI->eraseFromParent();
490 }
491 }
492
493
494
495
497 for (int I = 0, E = N; I != E; ++I)
498 if (!Extracts[I])
500
502 for (int I = 0, E = N; I != E; ++I)
505 }
506
508 if (OldResult != Intrin) {
509 assert(Intrin->use_empty() && "Intrinsic still has uses?");
511 }
512
514 }
515
516 [[nodiscard]] bool lowerTypedBufferLoad(Function &F, bool HasCheckBit) {
519
520 return replaceFunction(F, [&](CallInst *CI) -> Error {
522
527
529 if (HasCheckBit)
530 OldTy = cast(OldTy)->getElementType(0);
532
533 std::array<Value *, 3> Args{Handle, Index0, Index1};
535 OpCode::BufferLoad, Args, CI->getName(), NewRetTy);
537 return E;
538 if (Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
539 return E;
540
542 });
543 }
544
545 [[nodiscard]] bool lowerRawBufferLoad(Function &F) {
552
553 return replaceFunction(F, [&](CallInst *CI) -> Error {
555
556 Type *OldTy = cast(CI->getType())->getElementType(0);
559
565 DL.getTypeSizeInBits(OldTy) / DL.getTypeSizeInBits(ScalarTy);
566 Value *Mask = ConstantInt::get(Int8Ty, ~(~0U << NumElements));
568 ConstantInt::get(Int32Ty, DL.getPrefTypeAlign(ScalarTy).value());
569
572 ? OpBuilder.tryCreateOp(OpCode::RawBufferLoad,
573 {Handle, Index0, Index1, Mask, Align},
575 : OpBuilder.tryCreateOp(OpCode::BufferLoad,
576 {Handle, Index0, Index1}, CI->getName(),
577 NewRetTy);
579 return E;
580 if (Error E = replaceResRetUses(CI, *OpCall, true))
581 return E;
582
584 });
585 }
586
587 [[nodiscard]] bool lowerUpdateCounter(Function &F) {
590
591 return replaceFunction(F, [&](CallInst *CI) -> Error {
596
597 std::array<Value *, 2> Args{Handle, Op1};
598
600 OpCode::UpdateCounter, Args, CI->getName(), Int32Ty);
601
603 return E;
604
608 });
609 }
610
611 [[nodiscard]] bool lowerGetPointer(Function &F) {
612
613
614 assert(F.user_empty() && "getpointer operations should have been removed");
615 F.eraseFromParent();
616 return false;
617 }
618
619 [[nodiscard]] bool lowerBufferStore(Function &F, bool IsRaw) {
626
627 return replaceFunction(F, [&](CallInst *CI) -> Error {
629
634
636 Type *DataTy = Data->getType();
638
640 DL.getTypeSizeInBits(DataTy) / DL.getTypeSizeInBits(ScalarTy);
641 Value *Mask = ConstantInt::get(Int8Ty, ~(~0U << NumElements));
642
643
644 if (!IsRaw && NumElements != 4)
645 return make_error(
646 "typedBufferStore data must be a vector of 4 elements",
648 else if (NumElements > 4)
649 return make_error(
650 "rawBufferStore data must have at most 4 elements",
652
653 std::array<Value *, 4> DataElements{nullptr, nullptr, nullptr, nullptr};
654 if (DataTy == ScalarTy)
655 DataElements[0] = Data;
656 else {
657
658
659
660 auto *IEI = dyn_cast(Data);
661 while (IEI) {
662 auto *IndexOp = dyn_cast(IEI->getOperand(2));
663 if (!IndexOp)
664 break;
665 size_t IndexVal = IndexOp->getZExtValue();
666 assert(IndexVal < 4 && "Too many elements for buffer store");
667 DataElements[IndexVal] = IEI->getOperand(1);
668 IEI = dyn_cast(IEI->getOperand(0));
669 }
670 }
671
672
673
674
675 for (int I = 0, E = NumElements; I < E; ++I)
676 if (DataElements[I] == nullptr)
677 DataElements[I] =
679
680 for (int I = NumElements, E = 4; I < E; ++I)
681 if (DataElements[I] == nullptr)
683
686 Handle, Index0, Index1, DataElements[0],
687 DataElements[1], DataElements[2], DataElements[3], Mask};
688 if (IsRaw && DXILVersion >= VersionTuple(1, 2)) {
689 Op = OpCode::RawBufferStore;
690
691 Args.push_back(
692 ConstantInt::get(Int32Ty, DL.getPrefTypeAlign(ScalarTy).value()));
693 }
697 return E;
698
700
701 auto *IEI = dyn_cast(Data);
702 while (IEI && IEI->use_empty()) {
704 IEI = dyn_cast(IEI->getOperand(0));
706 }
707
709 });
710 }
711
712 [[nodiscard]] bool lowerCtpopToCountBits(Function &F) {
715
716 return replaceFunction(F, [&](CallInst *CI) -> Error {
720
722 Type *FRT = F.getReturnType();
723 if (const auto *VT = dyn_cast(FRT))
725
727 dxil::OpCode::CountBits, Args, CI->getName(), RetTy);
729 return E;
730
731
732 if (FRT->isIntOrIntVectorTy(32)) {
733 CI->replaceAllUsesWith(*OpCall);
734 CI->eraseFromParent();
735 return Error::success();
736 }
737
738 unsigned CastOp;
739 unsigned CastOp2;
740 if (FRT->isIntOrIntVectorTy(16)) {
741 CastOp = Instruction::ZExt;
742 CastOp2 = Instruction::SExt;
743 } else {
744 assert(FRT->isIntOrIntVectorTy(64) &&
745 "Currently only lowering 16, 32, or 64 bit ctpop to CountBits \
746 is supported.");
747 CastOp = Instruction::Trunc;
748 CastOp2 = Instruction::Trunc;
749 }
750
751
752
753 bool NeedsCast = false;
755 Instruction *I = dyn_cast(User);
756 if (I && (I->getOpcode() == CastOp || I->getOpcode() == CastOp2) &&
757 I->getType() == RetTy) {
758 I->replaceAllUsesWith(*OpCall);
759 I->eraseFromParent();
760 } else
761 NeedsCast = true;
762 }
763
764
765
766
767
768 if (NeedsCast) {
772 }
773
776 });
777 }
778
779 bool lowerIntrinsics() {
780 bool Updated = false;
781 bool HasErrors = false;
782
784 if (.isDeclaration())
785 continue;
787 switch (ID) {
788 default:
789 continue;
790#define DXIL_OP_INTRINSIC(OpCode, Intrin, ...) \
791 case Intrin: \
792 HasErrors |= replaceFunctionWithOp( \
793 F, OpCode, ArrayRef{__VA_ARGS__}); \
794 break;
795#include "DXILOperation.inc"
796 case Intrinsic::dx_resource_handlefrombinding:
797 HasErrors |= lowerHandleFromBinding(F);
798 break;
799 case Intrinsic::dx_resource_getpointer:
800 HasErrors |= lowerGetPointer(F);
801 break;
802 case Intrinsic::dx_resource_load_typedbuffer:
803 HasErrors |= lowerTypedBufferLoad(F, true);
804 break;
805 case Intrinsic::dx_resource_store_typedbuffer:
806 HasErrors |= lowerBufferStore(F, false);
807 break;
808 case Intrinsic::dx_resource_load_rawbuffer:
809 HasErrors |= lowerRawBufferLoad(F);
810 break;
811 case Intrinsic::dx_resource_store_rawbuffer:
812 HasErrors |= lowerBufferStore(F, true);
813 break;
814 case Intrinsic::dx_resource_updatecounter:
815 HasErrors |= lowerUpdateCounter(F);
816 break;
817
818
819 case Intrinsic::dx_splitdouble:
820 HasErrors |= replaceFunctionWithNamedStructOp(
821 F, OpCode::SplitDouble,
824 return replaceSplitDoubleCallUsages(CI, Op);
825 });
826 break;
827 case Intrinsic::ctpop:
828 HasErrors |= lowerCtpopToCountBits(F);
829 break;
830 }
831 Updated = true;
832 }
833 if (Updated && !HasErrors)
834 cleanupHandleCasts();
835
836 return Updated;
837 }
838};
839}
840
844
845 bool MadeChanges = OpLowerer(M, DBM, DRTM).lowerIntrinsics();
846 if (!MadeChanges)
852 return PA;
853}
854
855namespace {
856class DXILOpLoweringLegacy : public ModulePass {
857public:
858 bool runOnModule(Module &M) override {
860 getAnalysis().getBindingMap();
862 getAnalysis().getResourceTypeMap();
863
864 return OpLowerer(M, DBM, DRTM).lowerIntrinsics();
865 }
866 StringRef getPassName() const override { return "DXIL Op Lowering"; }
868
869 static char ID;
877 }
878};
879char DXILOpLoweringLegacy::ID = 0;
880}
881
883 false, false)
888
890 return new DXILOpLoweringLegacy();
891}
for(const MachineOperand &MO :llvm::drop_begin(OldMI.operands(), Desc.getNumOperands()))
ReachingDefAnalysis InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static bool isVectorArgExpansion(Function &F)
static SmallVector< Value * > argVectorFlatten(CallInst *Orig, IRBuilder<> &Builder)
static SmallVector< Value * > populateOperands(Value *Arg, IRBuilder<> &Builder)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
ModuleAnalysisManager MAM
#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())
This file defines the SmallVector class.
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.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Value * getArgOperand(unsigned i) const
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
This class represents a function call, abstracting a target machine's calling convention.
This is an important base class in LLVM.
This class represents an Operation in the Expression.
iterator find(const CallInst *Key)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
The legacy pass manager's analysis pass to compute DXIL resource information.
A parsed version of the target data layout string in and methods for querying it.
Diagnostic information for unsupported feature in backend.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
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="")
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.
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)
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
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...
This instruction inserts a single (scalar) element into a VectorType value.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
const Function * getFunction() const
Return the function this instruction belongs to.
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.
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.
iterator erase(const_iterator CI)
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.
An instruction for storing to memory.
StringRef - Represent a constant reference to a string, i.e.
Triple - Helper class for working with autoconf configuration names.
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.
static IntegerType * getInt32Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
A Use represents the edge between a Value definition and its users.
Value * getOperand(unsigned i) const
unsigned getNumOperands() const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
bool hasOneUse() const
Return true if there is exactly one use of this value.
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
iterator_range< user_iterator > users()
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< use_iterator > uses()
StringRef getName() const
Return a constant reference to the value's name.
Represents a version number in the form major[.minor[.subminor[.build]]].
StructType * getResRetType(Type *ElementTy)
Get a dx.types.ResRet type with the given element type.
StructType * getSplitDoubleType(LLVMContext &Context)
Get the dx.types.splitdouble type.
Expected< CallInst * > tryCreateOp(dxil::OpCode Op, ArrayRef< Value * > Args, const Twine &Name="", Type *RetTy=nullptr)
Try to create a call instruction for the given DXIL op.
Constant * getResBind(uint32_t LowerBound, uint32_t UpperBound, uint32_t SpaceID, dxil::ResourceClass RC)
Get a constant dx.types.ResBind value.
Constant * getResProps(uint32_t Word0, uint32_t Word1)
Get a constant dx.types.ResourceProperties value.
StructType * getHandleType()
Get the dx.types.Handle type.
std::pair< uint32_t, uint32_t > getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const
TargetExtType * getHandleTy() const
const ResourceBinding & getBinding() const
dxil::ResourceClass getResourceClass() const
Wrapper pass for the legacy pass manager.
An efficient, type-erasing, non-owning reference to a callable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
constexpr std::underlying_type_t< E > Mask()
Get a bitmask with 1s in all places up to the high-order bit of E's largest value.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
NodeAddr< DefNode * > Def
This is an optimization pass for GlobalISel generic memory operations.
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
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 unique(Range &&R, Predicate P)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
void sort(IteratorTy Start, IteratorTy End)
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
ModulePass * createDXILOpLoweringLegacyPass()
Pass to lowering LLVM intrinsic call to DXIL op function call.
const char * toString(DWARFSectionKind Kind)
This struct is a compact representation of a valid (non-zero power of two) alignment.