25#include "llvm/IR/IntrinsicsDirectX.h"
40#define DEBUG_TYPE "dxil-resource-access"
44[[noreturn]]
static void
54 for (
auto *Handle : Handles) {
55 std::string HandleStr;
57 Handle->print(HandleOS);
62 "Resource access is not guaranteed to map to a unique global resource",
72 assert((
II->getIntrinsicID() == Intrinsic::dx_resource_getpointer ||
73 II->getIntrinsicID() == Intrinsic::dx_resource_getbasepointer) &&
74 "Resource access through unexpected intrinsic");
75 return Offset ?
Offset : ConstantInt::get(Builder.getInt32Ty(), 0);
79 assert(
GEP &&
"Resource access through unexpected instruction");
81 unsigned NumIndices =
GEP->getNumIndices();
82 uint64_t IndexScale =
DL.getTypeAllocSize(
GEP->getSourceElementType());
83 APInt ConstantOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
85 if (
GEP->accumulateConstantOffset(
DL, ConstantOffset)) {
88 ConstantInt::get(
DL.getIndexType(
GEP->getType()), ConstantOffset);
90 }
else if (NumIndices == 1) {
93 GEPOffset = *
GEP->idx_begin();
94 }
else if (NumIndices == 2) {
96 auto *IndexIt =
GEP->idx_begin();
98 "GEP is not indexing through pointer");
99 GEPOffset = *(++IndexIt);
104 if (!(IndexScale % ElemSize)) {
107 IndexScale /= ElemSize;
111 GEPOffset = Builder.CreateMul(
112 GEPOffset, ConstantInt::get(Builder.getInt32Ty(), IndexScale));
114 GEPOffset = Builder.CreateUDiv(
115 GEPOffset, ConstantInt::get(Builder.getInt32Ty(), ElemSize));
118 Ptr =
GEP->getPointerOperand();
132 Value *V =
SI->getValueOperand();
133 if (V->getType() == ContainedType) {
136 "Store of whole element has mismatched address to store to");
137 }
else if (V->getType() == ScalarType) {
140 auto *
Load = Builder.CreateIntrinsic(
141 LoadType, Intrinsic::dx_resource_load_typedbuffer,
142 {
II->getOperand(0),
II->getOperand(1)});
143 auto *Struct = Builder.CreateExtractValue(
Load, {0});
145 uint64_t AccessSize =
DL.getTypeSizeInBits(ScalarType) / 8;
148 V = Builder.CreateInsertElement(Struct, V,
Offset);
153 auto *Inst = Builder.CreateIntrinsic(
154 Builder.getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,
155 {II->getOperand(0), II->getOperand(1), V});
156 SI->replaceAllUsesWith(Inst);
179 Value *Handle =
II->getOperand(0);
180 Value *Coords =
II->getOperand(1);
182 Value *V =
SI->getValueOperand();
183 if (V->getType() == ContainedType) {
186 "Store of whole element has mismatched address to store to");
187 }
else if (V->getType() == ScalarType) {
191 Value *MipLevel = Builder.getInt32(0);
193 auto *
Load = Builder.CreateIntrinsic(ContainedType,
194 Intrinsic::dx_resource_load_level,
195 {Handle, Coords, MipLevel, Offsets});
197 uint64_t AccessSize =
DL.getTypeSizeInBits(ScalarType) / 8;
200 V = Builder.CreateInsertElement(
Load, V,
Offset);
205 auto *Inst = Builder.CreateIntrinsic(Builder.getVoidTy(),
206 Intrinsic::dx_resource_store_texture,
207 {Handle, Coords, V});
208 SI->replaceAllUsesWith(Inst);
217 if (!ConstantOffset || !ConstantOffset->isZero())
218 Index = Builder.CreateAdd(Index,
Offset);
222 Builder.CreateIntrinsic(Builder.getVoidTy(),
223 Intrinsic::dx_resource_store_rawbuffer,
224 {Buffer, Index, Offset, V});
232 Value *V =
SI->getValueOperand();
233 assert(!V->getType()->isAggregateType() &&
234 "Resource store should be scalar or vector type");
236 Value *Index =
II->getOperand(1);
243 if (VT && VT->getNumElements() > 4) {
245 Type *EltTy = VT->getElementType();
246 Value *Stride = ConstantInt::get(Builder.getInt32Ty(),
247 4 * (
DL.getTypeSizeInBits(EltTy) / 8));
250 for (
unsigned int I = 0,
N = VT->getNumElements();
I <
N;
I += 4) {
254 for (
unsigned int J =
I,
E = std::min(
N, J + 4); J <
E; ++J)
256 Value *Part = Builder.CreateShuffleVector(V, Indices);
286 "DXIL Store not implemented for this texture resource kind");
299static std::optional<dxil::AtomicBinOpCode>
344static std::pair<Value *, Value *>
348 Value *Index =
II->getOperand(1);
356 if (!ConstantOffset || !ConstantOffset->isZero())
357 Index = Builder.CreateAdd(Index,
Offset);
369 Value *Coords =
II->getOperand(1);
372 assert(VecTy->getNumElements() <= 3 &&
"Too many texture coordinates");
373 for (
unsigned I = 0,
E = VecTy->getNumElements();
I !=
E; ++
I)
374 CoordArgs.
push_back(Builder.CreateExtractElement(Coords,
I));
384 "Atomic operations take between one and three coordinates");
386 std::optional<dxil::AtomicBinOpCode> BinOpCode =
401 Val = Builder.CreateBitCast(Val,
OpTy);
405 Handle, Builder.getInt32(
static_cast<uint32_t>(*BinOpCode))};
414 Builder.CreateIntrinsic(
OpTy, Intrinsic::dx_resource_atomic_binop, Args);
417 Result = Builder.CreateBitCast(Result, ValTy);
440 "scalar element type");
454 "Atomic operations take between one and three coordinates");
462 Args.push_back(Compare);
463 Args.push_back(NewValue);
465 Value *Original = Builder.CreateIntrinsic(
466 NewValue->
getType(), Intrinsic::dx_resource_atomic_compare_exchange,
476 if (!EV || EV->getIndices()[0] != 0)
482 EV->replaceAllUsesWith(Original);
483 EV->eraseFromParent();
506 "scalar element type");
536 "DXIL atomicrmw not implemented for this texture resource kind");
542 "DXIL atomicrmw not implemented for this resource type");
573 "DXIL cmpxchg not implemented for this texture resource kind");
579 "DXIL cmpxchg not implemented for this resource type");
597 Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,
598 {
II->getOperand(0),
II->getOperand(1)});
599 V = Builder.CreateExtractValue(V, {0});
602 uint64_t AccessSize =
DL.getTypeSizeInBits(ScalarType) / 8;
606 if (!ConstantOffset || !ConstantOffset->isZero())
607 V = Builder.CreateExtractElement(V,
Offset);
614 Builder.getInt32(0));
625 Value *Handle =
II->getOperand(0);
626 Value *Coords =
II->getOperand(1);
629 Value *MipLevel = Builder.getInt32(0);
635 Builder.CreateIntrinsic(ContainedType, Intrinsic::dx_resource_load_level,
636 {Handle, Coords, MipLevel, Offsets});
639 uint64_t AccessSize =
DL.getTypeSizeInBits(ScalarType) / 8;
643 if (!ConstantOffset || !ConstantOffset->isZero())
644 V = Builder.CreateExtractElement(V,
Offset);
651 Builder.getInt32(0));
663 if (!ConstantOffset || !ConstantOffset->isZero())
664 Index = Builder.CreateAdd(Index,
Offset);
671 Value *V = Builder.CreateIntrinsic(TypeWithCheck,
672 Intrinsic::dx_resource_load_rawbuffer,
674 return Builder.CreateExtractValue(V, {0});
682 Value *Index =
II->getOperand(1);
692 "Resource load should be scalar or vector type");
697 Type *EltTy = VT->getElementType();
698 Value *Stride = ConstantInt::get(Builder.getInt32Ty(),
699 4 * (
DL.getTypeSizeInBits(EltTy) / 8));
702 for (
unsigned int I = 0,
N = VT->getNumElements();
I <
N;
I += 4) {
720struct CBufferRowIntrin {
723 unsigned int EltSize;
724 unsigned int NumElts;
726 CBufferRowIntrin(
const DataLayout &
DL,
Type *Ty) {
729 switch (
DL.getTypeSizeInBits(Ty)) {
731 IID = Intrinsic::dx_resource_load_cbufferrow_8;
737 IID = Intrinsic::dx_resource_load_cbufferrow_4;
743 IID = Intrinsic::dx_resource_load_cbufferrow_2;
756 const CBufferRowIntrin &Intrin,
758 Value *Window,
unsigned RowNumber,
761 RowNumber == 0 ? FirstRow
762 : Builder.CreateAdd(FirstRow, Builder.getInt32(RowNumber));
763 Value *RowLoad = Builder.CreateIntrinsic(
764 Intrin.RetTy, Intrin.IID, {Handle, RowIndex},
nullptr, Name +
".load");
765 for (
unsigned J = 0; J != Intrin.NumElts; ++J) {
766 Value *Element = Builder.CreateExtractValue(RowLoad, {J});
767 Window = Builder.CreateInsertElement(
768 Window, Element, Builder.getInt32(RowNumber * Intrin.NumElts + J));
774 const CBufferRowIntrin &Intrin,
780 unsigned NumElements = VT ? VT->getNumElements() : 1;
782 Value *Handle =
II->getOperand(0);
785 Builder.CreateAdd(BaseRow, Builder.CreateUDiv(ByteOffset, RowSize));
786 Value *Component = Builder.CreateUDiv(Builder.CreateURem(ByteOffset, RowSize),
787 Builder.getInt32(Intrin.EltSize));
788 unsigned MinComponent =
790 unsigned MaxComponent =
792 unsigned MinRows = 1 + (MinComponent + NumElements - 1) / Intrin.NumElts;
793 unsigned MaxRows = 1 + (MaxComponent + NumElements - 1) / Intrin.NumElts;
797 for (
unsigned I = 0;
I != MinRows; ++
I)
803 if (MaxRows != MinRows) {
805 Value *LastComponent =
806 Builder.CreateAdd(Component, Builder.getInt32(NumElements - 1));
807 Value *CrossesRow = Builder.CreateICmpUGE(
808 LastComponent, Builder.getInt32(MinRows * Intrin.NumElts));
812 Builder.SetInsertPoint(ThenTerm);
814 Builder, Intrin, Handle, FirstRow, Window, MinRows, Name);
815 Builder.SetInsertPoint(LI);
816 auto *Rows = Builder.CreatePHI(WindowTy, 2, Name +
".rows");
817 Rows->addIncoming(Window, Head);
818 Rows->addIncoming(NextWindow, ThenTerm->
getParent());
823 for (
unsigned I = 0;
I != NumElements; ++
I) {
825 I == 0 ? Component : Builder.CreateAdd(Component, Builder.getInt32(
I));
827 Builder.CreateExtractElement(Window, Index, Name +
".extract");
829 VT ? Builder.CreateInsertElement(Result, Element, Builder.getInt32(
I))
840 if (!Phi || Phi->getNumIncomingValues() == 0)
846 for (
unsigned I = 0;
I != Phi->getNumIncomingValues(); ++
I)
849 Phi->getIncomingBlock(
I)->getTerminator()));
850 return Known.unionWith(IncomingKnown);
859 CBufferRowIntrin Intrin(
DL, Ty->getScalarType());
862 Value *Handle =
II->getOperand(0);
867 II->getIntrinsicID() == Intrinsic::dx_resource_getbasepointer
868 ? ConstantInt::get(Builder.getInt32Ty(), 0)
870 assert(GlobalOffset &&
"CBuffer getpointer index must be constant");
873 Value *CurrentRow = ConstantInt::get(
875 unsigned int CurrentIndex =
885 "Unexpected indirect access to resource without GEP");
889 CurrentRow = Builder.CreateAdd(GEPOffset, CurrentRow);
891 APInt ConstantOffset(
DL.getIndexTypeSizeInBits(LastGEP->getType()), 0);
892 if (LastGEP->accumulateConstantOffset(
DL, ConstantOffset)) {
893 APInt Remainder(
DL.getIndexTypeSizeInBits(LastGEP->getType()),
895 APInt::udivrem(ConstantOffset, Remainder, ConstantOffset, Remainder);
896 CurrentRow = Builder.CreateAdd(
897 CurrentRow, ConstantInt::get(Builder.getInt32Ty(), ConstantOffset));
900 assert(LastGEP->getNumIndices() == 1 &&
901 "Last GEP of cbuffer access is not array or struct access");
904 Value *RowIndex = Builder.CreateSExtOrTrunc(*LastGEP->idx_begin(),
905 Builder.getInt32Ty());
907 DL.getTypeAllocSize(LastGEP->getSourceElementType());
910 "CBuffer GEP index is not row aligned");
914 : Builder.CreateMul(RowIndex, Builder.getInt32(IndexScale));
916 if (BaseWithinRow != 0)
918 Builder.CreateAdd(ByteOffset, Builder.getInt32(BaseWithinRow));
925 II, LI, Intrin, CurrentRow, ByteOffset, WithinRow));
928 RowIndex = Builder.CreateUDiv(ByteOffset, RowSize,
"",
933 "CBuffer GEP index is not row aligned");
934 RowIndex = Builder.CreateMul(
936 ConstantInt::get(Builder.getInt32Ty(),
940 BaseRow && BaseRow->isZero())
941 CurrentRow = RowIndex;
943 CurrentRow = Builder.CreateAdd(CurrentRow, RowIndex);
947 auto *CBufLoad = Builder.CreateIntrinsic(
948 Intrin.RetTy, Intrin.IID, {Handle, CurrentRow},
nullptr, Name +
".load");
950 Builder.CreateExtractValue(CBufLoad, {CurrentIndex++}, Name +
".extract");
954 unsigned int Remaining =
955 ((
DL.getTypeSizeInBits(Ty) / 8) / Intrin.EltSize) - 1;
956 if (Remaining == 0) {
962 assert(VT->getNumElements() == 1 &&
"Can't have multiple elements here");
964 Builder.getInt32(0), Name);
972 while (Remaining--) {
973 CurrentIndex %= Intrin.NumElts;
975 if (CurrentIndex == 0) {
976 CurrentRow = Builder.CreateAdd(CurrentRow,
977 ConstantInt::get(Builder.getInt32Ty(), 1));
978 CBufLoad = Builder.CreateIntrinsic(Intrin.RetTy, Intrin.IID,
979 {Handle, CurrentRow},
nullptr,
983 Extracts.
push_back(Builder.CreateExtractValue(CBufLoad, {CurrentIndex++},
989 for (
int I = 0,
E = Extracts.
size();
I <
E; ++
I)
990 Result = Builder.CreateInsertElement(
991 Result, Extracts[
I], Builder.getInt32(
I), Name +
formatv(
".upto{}",
I));
1039 if (
II->getIntrinsicID() == Intrinsic::dx_resource_updatecounter)
1056 Intrinsic::dx_resource_handlefrombinding,
1057 Intrinsic::dx_resource_handlefromimplicitbinding,
1065 while (!Worklist.
empty()) {
1068 if (!
X->getType()->isPointerTy() && !
X->getType()->isTargetExtTy())
1074 for (
Use &V : Phi->incoming_values())
1085 if (IID == Intrinsic::dx_resource_getpointer ||
1086 IID == Intrinsic::dx_resource_getbasepointer)
1100 "Only expects a Handle as determined from collectUsedHandles.");
1108 uint32_t UpperBound =
Size == UINT32_MAX ? UINT32_MAX : LowerBound +
Size - 1;
1110 return hlsl::Binding(Class, Space, LowerBound, UpperBound,
nullptr);
1115struct AccessIndices {
1120 bool hasGetPtrIdx() {
return GetPtrIdx !=
nullptr; }
1121 bool hasHandleIdx() {
return HandleIdx !=
nullptr; }
1122 bool hasOffsetIdx() {
return OffsetIdx !=
nullptr; }
1128struct TrackedAccessIndices {
1129 WeakTrackingVH GetPtrIdx;
1130 WeakTrackingVH HandleIdx;
1131 WeakTrackingVH OffsetIdx;
1133 TrackedAccessIndices() =
default;
1134 TrackedAccessIndices(
const AccessIndices &AI)
1135 : GetPtrIdx(AI.GetPtrIdx), HandleIdx(AI.HandleIdx),
1136 OffsetIdx(AI.OffsetIdx) {}
1137 operator AccessIndices()
const {
return {GetPtrIdx, HandleIdx, OffsetIdx}; }
1148 unsigned BitWidth =
DL.getIndexTypeSizeInBits(
GEP->getType());
1152 GEP->collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset);
1153 assert(
Success &&
"Unhandled GEP structure for resource access");
1158 for (
auto &[V, Scale] : VariableOffsets) {
1159 Value *Index = Builder.CreateSExtOrTrunc(V, I32);
1162 Builder.CreateMul(Index, ConstantInt::get(I32, Scale.getSExtValue()));
1176 PhiAccessIndicesMap &VisitedPhis) {
1180 return {
nullptr,
II->getArgOperand(3),
nullptr};
1184 if (IID == Intrinsic::dx_resource_getpointer ||
1185 IID == Intrinsic::dx_resource_getbasepointer) {
1188 assert(!AccessIdx.hasGetPtrIdx() &&
1189 "Encountered multiple dx.resource.getpointers in ptr chain?");
1191 AccessIdx.GetPtrIdx = ConstantInt::get(Builder.getInt32Ty(), 0);
1192 if (IID == Intrinsic::dx_resource_getpointer)
1193 AccessIdx.GetPtrIdx =
II->getArgOperand(1);
1206 AccessIdx.OffsetIdx =
1207 AccessIdx.hasOffsetIdx()
1208 ? Builder.CreateAdd(AccessIdx.OffsetIdx, GEPOffset)
1217 if (
auto It = VisitedPhis.find(Phi); It != VisitedPhis.end())
1220 unsigned NumEdges = Phi->getNumIncomingValues();
1221 assert(NumEdges != 0 &&
"Malformed Phi Node");
1224 std::unique_ptr<PHINode> GetPtrPhi(
1226 std::unique_ptr<PHINode> HandlePhi(
1228 std::unique_ptr<PHINode> OffsetPhi(
1230 bool HasOffset =
false;
1235 if (Phi->getType()->isTargetExtTy())
1236 VisitedPhis[Phi] = AccessIndices{
nullptr, HandlePhi.get(),
1238 else if (Phi->getType()->isPointerTy())
1240 AccessIndices{GetPtrPhi.get(), HandlePhi.get(), OffsetPhi.get()};
1242 for (
unsigned Idx = 0; Idx < NumEdges; Idx++) {
1243 auto *BB = Phi->getIncomingBlock(Idx);
1246 if (AccessIdx.hasGetPtrIdx())
1247 GetPtrPhi->addIncoming(AccessIdx.GetPtrIdx, BB);
1248 HandlePhi->addIncoming(AccessIdx.HandleIdx, BB);
1249 if (AccessIdx.hasOffsetIdx()) {
1250 OffsetPhi->addIncoming(AccessIdx.OffsetIdx, BB);
1253 OffsetPhi->addIncoming(ConstantInt::get(Builder.getInt32Ty(), 0), BB);
1258 if (GetPtrPhi->getNumIncomingValues() == 0) {
1259 GetPtrIdx =
nullptr;
1260 }
else if (
Value *ConstantGetPtr = GetPtrPhi->hasConstantValue()) {
1261 GetPtrIdx = ConstantGetPtr;
1264 GetPtrIdx = GetPtrPhi.release();
1265 Builder.Insert(GetPtrIdx);
1269 if (
Value *ConstantHandle = HandlePhi->hasConstantValue()) {
1270 HandleIdx = ConstantHandle;
1273 HandleIdx = HandlePhi.release();
1274 Builder.Insert(HandleIdx);
1277 Value *OffsetIdx =
nullptr;
1279 if (
Value *ConstantIdx = OffsetPhi->hasConstantValue()) {
1280 OffsetIdx = ConstantIdx;
1283 OffsetIdx = OffsetPhi.release();
1284 Builder.Insert(OffsetIdx);
1289 AccessIndices Result = {GetPtrIdx, HandleIdx, OffsetIdx};
1290 VisitedPhis[Phi] = Result;
1303 Value *GetPtrSelect =
nullptr;
1304 Value *OffsetSelect =
nullptr;
1306 if (TrueAccessIdx.hasGetPtrIdx() && FalseAccessIdx.hasGetPtrIdx())
1308 Builder.CreateSelect(
Select->getCondition(), TrueAccessIdx.GetPtrIdx,
1309 FalseAccessIdx.GetPtrIdx,
"",
Select);
1311 auto *HandleSelect =
1312 Builder.CreateSelect(
Select->getCondition(), TrueAccessIdx.HandleIdx,
1313 FalseAccessIdx.HandleIdx,
"",
Select);
1315 if (TrueAccessIdx.hasOffsetIdx() || FalseAccessIdx.hasOffsetIdx()) {
1316 Value *Zero = ConstantInt::get(Builder.getInt32Ty(), 0);
1318 TrueAccessIdx.hasOffsetIdx() ? TrueAccessIdx.OffsetIdx : Zero;
1319 Value *FalseOffset =
1320 FalseAccessIdx.hasOffsetIdx() ? FalseAccessIdx.OffsetIdx : Zero;
1321 OffsetSelect = Builder.CreateSelect(
Select->getCondition(), TrueOffset,
1322 FalseOffset,
"",
Select);
1326 return {GetPtrSelect, HandleSelect, OffsetSelect};
1335 PhiAccessIndicesMap &VisitedPhis) {
1337 assert(AccessIdx.hasHandleIdx() &&
1338 "Couldn't retrieve handle index. This is guaranteed by "
1339 "getAccessIndices");
1343 Builder.SetInsertPoint(Ptr->
getParent()->getFirstNonPHIIt());
1346 Builder.Insert(Handle);
1349 assert(AccessIdx.hasGetPtrIdx() &&
1350 "Couldn't retrieve getpointer index. This is guaranteed by "
1351 "getAccessIndices");
1352 auto *GetPtr = Builder.CreateIntrinsic(Ptr->
getType(),
1353 Intrinsic::dx_resource_getpointer,
1354 {Handle, AccessIdx.GetPtrIdx});
1358 Value *Result = GetPtr;
1359 if (AccessIdx.hasOffsetIdx())
1360 Result = Builder.CreatePtrAdd(GetPtr, AccessIdx.OffsetIdx);
1364 "Unexpected resource access operand type");
1383 PhiAccessIndicesMap VisitedPhis;
1389 unsigned NumHandles = Handles.
size();
1390 if (NumHandles <= 1)
1393 bool SameGlobalBinding =
true;
1395 for (
unsigned Idx = 1; Idx < NumHandles; Idx++)
1396 SameGlobalBinding &=
1399 if (!SameGlobalBinding)
1408 bool MadeChanges =
false;
1412 for (
const auto &HandleToIndex : VisitedPhis)
1413 ResourcePhis.
push_back(HandleToIndex.first);
1416 if (
I->hasNUses(0)) {
1417 I->eraseFromParent();
1432 for (
User *U :
II->users())
1436 while (!Worklist.
empty()) {
1446 assert(
SI->getValueOperand() !=
II &&
"Pointer escaped!");
1465 Dead->eraseFromParent();
1466 II->eraseFromParent();
1474 if (
II->getIntrinsicID() == Intrinsic::dx_resource_getpointer ||
1475 II->getIntrinsicID() == Intrinsic::dx_resource_getbasepointer) {
1478 (DRTM[HandleTy].isCBuffer() ||
1479 II->getIntrinsicID() != Intrinsic::dx_resource_getbasepointer) &&
1480 "dx_resource_getbasepointer should only be used by cbuffers");
1495 assert(DRTM &&
"DXILResourceTypeAnalysis must be available");
1499 if (!(MadeHandleChanges || MadeResourceChanges))
1512 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1515 return MadeHandleChanges || MadeResourceChanges;
1517 StringRef getPassName()
const override {
return "DXIL Resource Access"; }
1518 DXILResourceAccessLegacy() : FunctionPass(
ID) {}
1521 void getAnalysisUsage(llvm::AnalysisUsage &AU)
const override {
1525char DXILResourceAccessLegacy::ID = 0;
1529 "DXIL Resource Access",
false,
false)
1535 return new DXILResourceAccessLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
AMDGPU Register Bank Select
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
DXIL Remove Unused Resources
static void diagnoseNonUniqueResourceAccess(Instruction *I, ArrayRef< IntrinsicInst * > Handles)
static std::optional< dxil::AtomicBinOpCode > getAtomicBinOpCode(AtomicRMWInst::BinOp BinOp)
static void replaceHandleWithIndices(Instruction *Ptr, IntrinsicInst *OldHandle, SmallSetVector< Instruction *, 16 > &DeadInsts, PhiAccessIndicesMap &VisitedPhis)
static void createLoadIntrinsic(IntrinsicInst *II, LoadInst *LI, dxil::ResourceTypeInfo &RTI)
static void createTextureStore(IntrinsicInst *II, StoreInst *SI, dxil::ResourceTypeInfo &RTI)
static Value * emitRawLoad(IRBuilder<> &Builder, Type *Ty, Value *Buffer, Value *Index, Value *Offset, dxil::ResourceTypeInfo &RTI)
static void emitAtomicCompareExchange(IRBuilder<> &Builder, AtomicCmpXchgInst *AI, Value *Handle, ArrayRef< Value * > Coords)
static bool legalizeResourceHandles(Function &F, DXILResourceTypeMap &DRTM)
static void createTypedBufferLoad(IntrinsicInst *II, LoadInst *LI, dxil::ResourceTypeInfo &RTI)
static void createTypedBufferStore(IntrinsicInst *II, StoreInst *SI, dxil::ResourceTypeInfo &RTI)
static SmallVector< IntrinsicInst * > collectUsedHandles(Value *Ptr)
static const std::array< Intrinsic::ID, 2 > HandleIntrins
static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM)
static Value * createDynamicCBufferLoad(IntrinsicInst *II, LoadInst *LI, const CBufferRowIntrin &Intrin, Value *BaseRow, Value *ByteOffset, const KnownBits &WithinRow)
static void createTextureLoad(IntrinsicInst *II, LoadInst *LI, dxil::ResourceTypeInfo &RTI)
static void emitRawStore(IRBuilder<> &Builder, Value *Buffer, Value *Index, Value *Offset, Value *V, dxil::ResourceTypeInfo &RTI)
static Value * getNullOffsetsFor(IRBuilder<> &Builder, Value *Coords)
Build a zero-initialized offset operand matching the shape of the given coordinate operand.
static Instruction * getHandleRoot(Instruction *I)
static void createBufferAtomicCompareExchange(IntrinsicInst *II, AtomicCmpXchgInst *AI, dxil::ResourceTypeInfo &RTI)
static Value * traverseGEPOffsets(const DataLayout &DL, IRBuilder<> &Builder, Value *Ptr, uint64_t AccessSize)
static Value * loadCBufferRowIntoWindow(IRBuilder<> &Builder, const CBufferRowIntrin &Intrin, Value *Handle, Value *FirstRow, Value *Window, unsigned RowNumber, StringRef Name)
static void createBufferAtomicBinOp(IntrinsicInst *II, AtomicRMWInst *AI, dxil::ResourceTypeInfo &RTI)
static hlsl::Binding getHandleIntrinsicBinding(IntrinsicInst *Handle, DXILResourceTypeMap &DRTM)
static void createStoreIntrinsic(IntrinsicInst *II, StoreInst *SI, dxil::ResourceTypeInfo &RTI)
static void createCBufferLoad(IntrinsicInst *II, LoadInst *LI, dxil::ResourceTypeInfo &RTI)
static std::pair< Value *, Value * > getAtomicResourceCoords(IntrinsicInst *II, Value *PointerOperand, dxil::ResourceTypeInfo &RTI, IRBuilder<> &Builder, const DataLayout &DL)
static void createRawStores(IntrinsicInst *II, StoreInst *SI, dxil::ResourceTypeInfo &RTI)
static SmallVector< Value *, 3 > getTextureAtomicCoords(IntrinsicInst *II, IRBuilder<> &Builder)
static void createTextureAtomicBinOp(IntrinsicInst *II, AtomicRMWInst *AI, dxil::ResourceTypeInfo &RTI)
static KnownBits computeCBufferOffsetKnownBits(Value *Offset, const DataLayout &DL, const Instruction *CxtI)
static Value * accumulateGEPOffset(GetElementPtrInst *GEP, IRBuilder<> &Builder)
static void emitAtomicBinOp(IRBuilder<> &Builder, AtomicRMWInst *AI, Value *Handle, ArrayRef< Value * > Coords)
static AccessIndices getAccessIndices(Instruction *I, SmallSetVector< Instruction *, 16 > &DeadInsts, PhiAccessIndicesMap &VisitedPhis)
static void createRawLoads(IntrinsicInst *II, LoadInst *LI, dxil::ResourceTypeInfo &RTI)
static void createAtomicCompareExchangeIntrinsic(IntrinsicInst *II, AtomicCmpXchgInst *AI, dxil::ResourceTypeInfo &RTI)
static void createAtomicBinOpIntrinsic(IntrinsicInst *II, AtomicRMWInst *AI, dxil::ResourceTypeInfo &RTI)
static Instruction * getHandleOperand(Instruction *AI)
static void createTextureAtomicCompareExchange(IntrinsicInst *II, AtomicCmpXchgInst *AI, dxil::ResourceTypeInfo &RTI)
static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI)
This file defines the DenseMap class.
static bool runOnFunction(Function &F, bool PostInlining)
This file implements a map that provides insertion order iteration.
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 contains the declarations for profiling metadata utility functions.
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.
static LLVM_ABI void udivrem(const APInt &LHS, const APInt &RHS, APInt &Quotient, APInt &Remainder)
Dual division/remainder interface.
uint64_t getZExtValue() const
Get zero extended value.
bool isZero() const
Determine if this value is zero, i.e. all bits are clear.
int64_t getSExtValue() const
Get sign extended value.
AnalysisUsage & addRequired()
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
bool empty() const
Check if the array is empty.
An instruction that atomically checks whether a specified value is in a memory location,...
Value * getNewValOperand()
Value * getCompareOperand()
Value * getPointerOperand()
an instruction that atomically reads a memory location, combines it with another value,...
BinOp
This enumeration lists the possible modifications atomicrmw can make.
@ USubCond
Subtract only if no unsigned overflow.
@ FMinimum
*p = minimum(old, v) minimum matches the behavior of llvm.minimum.
@ Min
*p = old <signed v ? old : v
@ USubSat
*p = usub.sat(old, v) usub.sat matches the behavior of llvm.usub.sat.
@ FMaximum
*p = maximum(old, v) maximum matches the behavior of llvm.maximum.
@ UIncWrap
Increment one up to a maximum value.
@ Max
*p = old >signed v ? old : v
@ UMin
*p = old <unsigned v ? old : v
@ FMin
*p = minnum(old, v) minnum matches the behavior of llvm.minnum.
@ UMax
*p = old >unsigned v ? old : v
@ FMaximumNum
*p = maximumnum(old, v) maximumnum matches the behavior of llvm.maximumnum.
@ FMax
*p = maxnum(old, v) maxnum matches the behavior of llvm.maxnum.
@ UDecWrap
Decrement one until a minimum value or zero.
@ FMinimumNum
*p = minimumnum(old, v) minimumnum matches the behavior of llvm.minimumnum.
Value * getPointerOperand()
BinOp getOperation() const
LLVM Basic Block Representation.
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
This is the shared class of boolean and integer constants.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
A parsed version of the target data layout string in and methods for querying it.
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
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
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI Instruction * clone() const
Create a copy of 'this' instruction that is identical in all ways except the following:
iterator_range< user_iterator > users()
LLVM_ABI const DataLayout & getDataLayout() const
Get the data layout of the module this instruction belongs to.
A wrapper class for inspecting calls to intrinsic functions.
Intrinsic::ID getIntrinsicID() const
Return the intrinsic ID of this intrinsic.
This is an important class for using LLVM in a threaded context.
An instruction for reading from memory.
Value * getPointerOperand()
static PHINode * Create(Type *Ty, unsigned NumReservedValues, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Constructors - NumReservedValues is a hint for the number of incoming edges that this phi node will h...
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.
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.
bool contains(ConstPtrType Ptr) const
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
A SetVector that performs no allocations if smaller than a certain size.
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.
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
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 LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
bool isTargetExtTy() const
Return true if this is a target extension type.
bool isAggregateType() const
Return true if the type is an aggregate type.
static LLVM_ABI IntegerType * getInt1Ty(LLVMContext &C)
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
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 StringRef getName() const
Return a constant reference to the value's name.
Value handle that is nullable, but tries to track the Value.
TargetExtType * getHandleTy() const
LLVM_ABI bool isStruct() const
dxil::ResourceKind getResourceKind() const
const ParentTy * getParent() const
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ RTAccelerationStructure
const unsigned CBufferRowSizeInBytes
This is an optimization pass for GlobalISel generic memory operations.
@ Known
Known to have no common set bits.
LLVM_ABI void setExplicitlyUnknownBranchWeightsIfProfiled(Instruction &I, StringRef PassName, const Function *F=nullptr)
Like setExplicitlyUnknownBranchWeights(...), but only sets unknown branch weights in the new instruct...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
@ Load
The value being inserted comes from a load (InsertElement only).
OuterAnalysisManagerProxy< ModuleAnalysisManager, Function > ModuleAnalysisManagerFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
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...
LLVM_ABI void computeKnownBits(const Value *V, KnownBits &Known, const DataLayout &DL, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, bool UseInstrInfo=true, unsigned Depth=0)
Determine which bits of V are known to be either zero or one and return them in the KnownZero/KnownOn...
LLVM_ABI Value * concatenateVectors(IRBuilderBase &Builder, ArrayRef< Value * > Vecs)
Concatenate a list of vectors.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
auto reverse(ContainerTy &&C)
FunctionPass * createDXILResourceAccessLegacyPass()
Pass to update resource accesses to use load/store directly.
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
LLVM_ABI bool RecursivelyDeleteDeadPHINode(PHINode *PN, const TargetLibraryInfo *TLI=nullptr, MemorySSAUpdater *MSSAU=nullptr, SmallPtrSetImpl< PHINode * > *KnownNonDeadPHIs=nullptr)
If the specified value is an effectively dead PHI node, due to being a def-use chain of single-use no...
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...
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI Instruction * SplitBlockAndInsertIfThen(Value *Cond, BasicBlock::iterator SplitBefore, bool Unreachable, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr, BasicBlock *ThenBlock=nullptr)
Split the containing block at the specified instruction - everything before SplitBefore stays in the ...
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
static KnownBits makeConstant(const APInt &C)
Create known bits from a known constant.
void setAllConflict()
Make all bits known to be both zero and one.
bool isConstant() const
Returns true if we know the value of all bits.
KnownBits intersectWith(const KnownBits &RHS) const
Returns KnownBits information that is known to be true for both this and RHS.
APInt getMaxValue() const
Return the maximal unsigned value possible given these KnownBits.
APInt getMinValue() const
Return the minimal unsigned value possible given these KnownBits.
const APInt & getConstant() const
Returns the value when all bits have a known value.
A MapVector that performs no allocations if smaller than a certain size.