24#include "llvm/IR/IntrinsicsDirectX.h"
39#define DEBUG_TYPE "dxil-resource-access"
43[[noreturn]]
static void
53 for (
auto *Handle : Handles) {
54 std::string HandleStr;
56 Handle->print(HandleOS);
61 "Resource access is not guaranteed to map to a unique global resource",
71 assert((
II->getIntrinsicID() == Intrinsic::dx_resource_getpointer ||
72 II->getIntrinsicID() == Intrinsic::dx_resource_getbasepointer) &&
73 "Resource access through unexpected intrinsic");
74 return Offset ?
Offset : ConstantInt::get(Builder.getInt32Ty(), 0);
78 assert(
GEP &&
"Resource access through unexpected instruction");
80 unsigned NumIndices =
GEP->getNumIndices();
81 uint64_t IndexScale =
DL.getTypeAllocSize(
GEP->getSourceElementType());
82 APInt ConstantOffset(
DL.getIndexTypeSizeInBits(
GEP->getType()), 0);
84 if (
GEP->accumulateConstantOffset(
DL, ConstantOffset)) {
87 ConstantInt::get(
DL.getIndexType(
GEP->getType()), ConstantOffset);
89 }
else if (NumIndices == 1) {
92 GEPOffset = *
GEP->idx_begin();
93 }
else if (NumIndices == 2) {
95 auto *IndexIt =
GEP->idx_begin();
97 "GEP is not indexing through pointer");
98 GEPOffset = *(++IndexIt);
103 if (!(IndexScale % ElemSize)) {
106 IndexScale /= ElemSize;
110 GEPOffset = Builder.CreateMul(
111 GEPOffset, ConstantInt::get(Builder.getInt32Ty(), IndexScale));
113 GEPOffset = Builder.CreateUDiv(
114 GEPOffset, ConstantInt::get(Builder.getInt32Ty(), ElemSize));
117 Ptr =
GEP->getPointerOperand();
132 if (
V->getType() == ContainedType) {
135 "Store of whole element has mismatched address to store to");
136 }
else if (
V->getType() == ScalarType) {
139 auto *
Load = Builder.CreateIntrinsic(
140 LoadType, Intrinsic::dx_resource_load_typedbuffer,
141 {
II->getOperand(0),
II->getOperand(1)});
142 auto *Struct = Builder.CreateExtractValue(
Load, {0});
144 uint64_t AccessSize =
DL.getTypeSizeInBits(ScalarType) / 8;
147 V = Builder.CreateInsertElement(Struct,
V,
Offset);
152 auto *Inst = Builder.CreateIntrinsic(
153 Builder.getVoidTy(), Intrinsic::dx_resource_store_typedbuffer,
154 {II->getOperand(0), II->getOperand(1), V});
155 SI->replaceAllUsesWith(Inst);
178 Value *Handle =
II->getOperand(0);
179 Value *Coords =
II->getOperand(1);
182 if (
V->getType() == ContainedType) {
185 "Store of whole element has mismatched address to store to");
186 }
else if (
V->getType() == ScalarType) {
190 Value *MipLevel = Builder.getInt32(0);
192 auto *
Load = Builder.CreateIntrinsic(ContainedType,
193 Intrinsic::dx_resource_load_level,
194 {Handle, Coords, MipLevel, Offsets});
196 uint64_t AccessSize =
DL.getTypeSizeInBits(ScalarType) / 8;
204 auto *Inst = Builder.CreateIntrinsic(Builder.getVoidTy(),
205 Intrinsic::dx_resource_store_texture,
206 {Handle, Coords, V});
207 SI->replaceAllUsesWith(Inst);
216 if (!ConstantOffset || !ConstantOffset->isZero())
217 Index = Builder.CreateAdd(Index,
Offset);
221 Builder.CreateIntrinsic(Builder.getVoidTy(),
222 Intrinsic::dx_resource_store_rawbuffer,
223 {Buffer, Index, Offset, V});
232 assert(!
V->getType()->isAggregateType() &&
233 "Resource store should be scalar or vector type");
235 Value *Index =
II->getOperand(1);
242 if (VT && VT->getNumElements() > 4) {
244 Type *EltTy = VT->getElementType();
245 Value *Stride = ConstantInt::get(Builder.getInt32Ty(),
246 4 * (
DL.getTypeSizeInBits(EltTy) / 8));
249 for (
unsigned int I = 0,
N = VT->getNumElements();
I <
N;
I += 4) {
253 for (
unsigned int J =
I,
E = std::min(
N, J + 4); J <
E; ++J)
255 Value *Part = Builder.CreateShuffleVector(
V, Indices);
285 "DXIL Store not implemented for this texture resource kind");
298static std::optional<dxil::AtomicBinOpCode>
343static std::pair<Value *, Value *>
347 Value *Index =
II->getOperand(1);
355 if (!ConstantOffset || !ConstantOffset->isZero())
356 Index = Builder.CreateAdd(Index,
Offset);
368 Value *Coords =
II->getOperand(1);
371 assert(VecTy->getNumElements() <= 3 &&
"Too many texture coordinates");
372 for (
unsigned I = 0,
E = VecTy->getNumElements();
I !=
E; ++
I)
373 CoordArgs.
push_back(Builder.CreateExtractElement(Coords,
I));
383 "Atomic operations take between one and three coordinates");
385 std::optional<dxil::AtomicBinOpCode> BinOpCode =
400 Val = Builder.CreateBitCast(Val,
OpTy);
404 Handle, Builder.getInt32(
static_cast<uint32_t>(*BinOpCode))};
413 Builder.CreateIntrinsic(
OpTy, Intrinsic::dx_resource_atomic_binop, Args);
416 Result = Builder.CreateBitCast(Result, ValTy);
439 "scalar element type");
453 "Atomic operations take between one and three coordinates");
461 Args.push_back(Compare);
462 Args.push_back(NewValue);
464 Value *Original = Builder.CreateIntrinsic(
465 NewValue->
getType(), Intrinsic::dx_resource_atomic_compare_exchange,
475 if (!EV || EV->getIndices()[0] != 0)
481 EV->replaceAllUsesWith(Original);
482 EV->eraseFromParent();
505 "scalar element type");
535 "DXIL atomicrmw not implemented for this texture resource kind");
541 "DXIL atomicrmw not implemented for this resource type");
572 "DXIL cmpxchg not implemented for this texture resource kind");
578 "DXIL cmpxchg not implemented for this resource type");
596 Builder.CreateIntrinsic(LoadType, Intrinsic::dx_resource_load_typedbuffer,
597 {
II->getOperand(0),
II->getOperand(1)});
598 V = Builder.CreateExtractValue(
V, {0});
601 uint64_t AccessSize =
DL.getTypeSizeInBits(ScalarType) / 8;
605 if (!ConstantOffset || !ConstantOffset->isZero())
606 V = Builder.CreateExtractElement(
V,
Offset);
613 Builder.getInt32(0));
624 Value *Handle =
II->getOperand(0);
625 Value *Coords =
II->getOperand(1);
628 Value *MipLevel = Builder.getInt32(0);
634 Builder.CreateIntrinsic(ContainedType, Intrinsic::dx_resource_load_level,
635 {Handle, Coords, MipLevel, Offsets});
638 uint64_t AccessSize =
DL.getTypeSizeInBits(ScalarType) / 8;
642 if (!ConstantOffset || !ConstantOffset->isZero())
643 V = Builder.CreateExtractElement(
V,
Offset);
650 Builder.getInt32(0));
662 if (!ConstantOffset || !ConstantOffset->isZero())
663 Index = Builder.CreateAdd(Index,
Offset);
670 Value *
V = Builder.CreateIntrinsic(TypeWithCheck,
671 Intrinsic::dx_resource_load_rawbuffer,
673 return Builder.CreateExtractValue(
V, {0});
681 Value *Index =
II->getOperand(1);
691 "Resource load should be scalar or vector type");
696 Type *EltTy = VT->getElementType();
697 Value *Stride = ConstantInt::get(Builder.getInt32Ty(),
698 4 * (
DL.getTypeSizeInBits(EltTy) / 8));
701 for (
unsigned int I = 0,
N = VT->getNumElements();
I <
N;
I += 4) {
719struct CBufferRowIntrin {
722 unsigned int EltSize;
723 unsigned int NumElts;
725 CBufferRowIntrin(
const DataLayout &
DL,
Type *Ty) {
728 switch (
DL.getTypeSizeInBits(Ty)) {
730 IID = Intrinsic::dx_resource_load_cbufferrow_8;
736 IID = Intrinsic::dx_resource_load_cbufferrow_4;
742 IID = Intrinsic::dx_resource_load_cbufferrow_2;
755 const CBufferRowIntrin &Intrin,
757 Value *Window,
unsigned RowNumber,
760 RowNumber == 0 ? FirstRow
761 : Builder.CreateAdd(FirstRow, Builder.getInt32(RowNumber));
762 Value *RowLoad = Builder.CreateIntrinsic(
763 Intrin.RetTy, Intrin.IID, {Handle, RowIndex},
nullptr, Name +
".load");
764 for (
unsigned J = 0; J != Intrin.NumElts; ++J) {
765 Value *Element = Builder.CreateExtractValue(RowLoad, {J});
766 Window = Builder.CreateInsertElement(
767 Window, Element, Builder.getInt32(RowNumber * Intrin.NumElts + J));
773 const CBufferRowIntrin &Intrin,
779 unsigned NumElements = VT ? VT->getNumElements() : 1;
781 Value *Handle =
II->getOperand(0);
784 Builder.CreateAdd(BaseRow, Builder.CreateUDiv(ByteOffset, RowSize));
785 Value *Component = Builder.CreateUDiv(Builder.CreateURem(ByteOffset, RowSize),
786 Builder.getInt32(Intrin.EltSize));
787 unsigned MinComponent =
789 unsigned MaxComponent =
791 unsigned MinRows = 1 + (MinComponent + NumElements - 1) / Intrin.NumElts;
792 unsigned MaxRows = 1 + (MaxComponent + NumElements - 1) / Intrin.NumElts;
796 for (
unsigned I = 0;
I != MinRows; ++
I)
802 if (MaxRows != MinRows) {
804 Value *LastComponent =
805 Builder.CreateAdd(Component, Builder.getInt32(NumElements - 1));
806 Value *CrossesRow = Builder.CreateICmpUGE(
807 LastComponent, Builder.getInt32(MinRows * Intrin.NumElts));
811 Builder.SetInsertPoint(ThenTerm);
813 Builder, Intrin, Handle, FirstRow, Window, MinRows, Name);
814 Builder.SetInsertPoint(LI);
815 auto *Rows = Builder.CreatePHI(WindowTy, 2, Name +
".rows");
816 Rows->addIncoming(Window, Head);
817 Rows->addIncoming(NextWindow, ThenTerm->
getParent());
822 for (
unsigned I = 0;
I != NumElements; ++
I) {
824 I == 0 ? Component : Builder.CreateAdd(Component, Builder.getInt32(
I));
826 Builder.CreateExtractElement(Window, Index, Name +
".extract");
828 VT ? Builder.CreateInsertElement(Result, Element, Builder.getInt32(
I))
839 if (!Phi || Phi->getNumIncomingValues() == 0)
845 for (
unsigned I = 0;
I != Phi->getNumIncomingValues(); ++
I)
848 Phi->getIncomingBlock(
I)->getTerminator()));
849 return Known.unionWith(IncomingKnown);
858 CBufferRowIntrin Intrin(
DL, Ty->getScalarType());
861 Value *Handle =
II->getOperand(0);
866 II->getIntrinsicID() == Intrinsic::dx_resource_getbasepointer
867 ? ConstantInt::get(Builder.getInt32Ty(), 0)
869 assert(GlobalOffset &&
"CBuffer getpointer index must be constant");
872 Value *CurrentRow = ConstantInt::get(
874 unsigned int CurrentIndex =
884 "Unexpected indirect access to resource without GEP");
888 CurrentRow = Builder.CreateAdd(GEPOffset, CurrentRow);
890 APInt ConstantOffset(
DL.getIndexTypeSizeInBits(LastGEP->getType()), 0);
891 if (LastGEP->accumulateConstantOffset(
DL, ConstantOffset)) {
892 APInt Remainder(
DL.getIndexTypeSizeInBits(LastGEP->getType()),
894 APInt::udivrem(ConstantOffset, Remainder, ConstantOffset, Remainder);
895 CurrentRow = Builder.CreateAdd(
896 CurrentRow, ConstantInt::get(Builder.getInt32Ty(), ConstantOffset));
899 assert(LastGEP->getNumIndices() == 1 &&
900 "Last GEP of cbuffer access is not array or struct access");
903 Value *RowIndex = Builder.CreateSExtOrTrunc(*LastGEP->idx_begin(),
904 Builder.getInt32Ty());
906 DL.getTypeAllocSize(LastGEP->getSourceElementType());
909 "CBuffer GEP index is not row aligned");
913 : Builder.CreateMul(RowIndex, Builder.getInt32(IndexScale));
915 if (BaseWithinRow != 0)
917 Builder.CreateAdd(ByteOffset, Builder.getInt32(BaseWithinRow));
924 II, LI, Intrin, CurrentRow, ByteOffset, WithinRow));
927 RowIndex = Builder.CreateUDiv(ByteOffset, RowSize,
"",
932 "CBuffer GEP index is not row aligned");
933 RowIndex = Builder.CreateMul(
935 ConstantInt::get(Builder.getInt32Ty(),
939 BaseRow && BaseRow->isZero())
940 CurrentRow = RowIndex;
942 CurrentRow = Builder.CreateAdd(CurrentRow, RowIndex);
946 auto *CBufLoad = Builder.CreateIntrinsic(
947 Intrin.RetTy, Intrin.IID, {Handle, CurrentRow},
nullptr, Name +
".load");
949 Builder.CreateExtractValue(CBufLoad, {CurrentIndex++}, Name +
".extract");
953 unsigned int Remaining =
954 ((
DL.getTypeSizeInBits(Ty) / 8) / Intrin.EltSize) - 1;
955 if (Remaining == 0) {
961 assert(VT->getNumElements() == 1 &&
"Can't have multiple elements here");
963 Builder.getInt32(0), Name);
971 while (Remaining--) {
972 CurrentIndex %= Intrin.NumElts;
974 if (CurrentIndex == 0) {
975 CurrentRow = Builder.CreateAdd(CurrentRow,
976 ConstantInt::get(Builder.getInt32Ty(), 1));
977 CBufLoad = Builder.CreateIntrinsic(Intrin.RetTy, Intrin.IID,
978 {Handle, CurrentRow},
nullptr,
982 Extracts.
push_back(Builder.CreateExtractValue(CBufLoad, {CurrentIndex++},
988 for (
int I = 0,
E = Extracts.
size();
I <
E; ++
I)
989 Result = Builder.CreateInsertElement(
990 Result, Extracts[
I], Builder.getInt32(
I), Name +
formatv(
".upto{}",
I));
1038 if (
II->getIntrinsicID() == Intrinsic::dx_resource_updatecounter)
1055 Intrinsic::dx_resource_handlefrombinding,
1056 Intrinsic::dx_resource_handlefromimplicitbinding,
1064 while (!Worklist.
empty()) {
1067 if (!
X->getType()->isPointerTy() && !
X->getType()->isTargetExtTy())
1073 for (
Use &
V : Phi->incoming_values())
1084 if (IID == Intrinsic::dx_resource_getpointer ||
1085 IID == Intrinsic::dx_resource_getbasepointer)
1099 "Only expects a Handle as determined from collectUsedHandles.");
1107 uint32_t UpperBound =
Size == UINT32_MAX ? UINT32_MAX : LowerBound +
Size - 1;
1109 return hlsl::Binding(Class, Space, LowerBound, UpperBound,
nullptr);
1114struct AccessIndices {
1119 bool hasGetPtrIdx() {
return GetPtrIdx !=
nullptr; }
1120 bool hasHandleIdx() {
return HandleIdx !=
nullptr; }
1121 bool hasOffsetIdx() {
return OffsetIdx !=
nullptr; }
1127struct TrackedAccessIndices {
1128 WeakTrackingVH GetPtrIdx;
1129 WeakTrackingVH HandleIdx;
1130 WeakTrackingVH OffsetIdx;
1132 TrackedAccessIndices() =
default;
1133 TrackedAccessIndices(
const AccessIndices &AI)
1134 : GetPtrIdx(AI.GetPtrIdx), HandleIdx(AI.HandleIdx),
1135 OffsetIdx(AI.OffsetIdx) {}
1136 operator AccessIndices()
const {
return {GetPtrIdx, HandleIdx, OffsetIdx}; }
1147 unsigned BitWidth =
DL.getIndexTypeSizeInBits(
GEP->getType());
1151 GEP->collectOffset(
DL,
BitWidth, VariableOffsets, ConstantOffset);
1152 assert(
Success &&
"Unhandled GEP structure for resource access");
1157 for (
auto &[
V, Scale] : VariableOffsets) {
1158 Value *Index = Builder.CreateSExtOrTrunc(
V, I32);
1161 Builder.CreateMul(Index, ConstantInt::get(I32, Scale.getSExtValue()));
1175 PhiAccessIndicesMap &VisitedPhis) {
1179 return {
nullptr,
II->getArgOperand(3),
nullptr};
1183 if (IID == Intrinsic::dx_resource_getpointer ||
1184 IID == Intrinsic::dx_resource_getbasepointer) {
1187 assert(!AccessIdx.hasGetPtrIdx() &&
1188 "Encountered multiple dx.resource.getpointers in ptr chain?");
1190 AccessIdx.GetPtrIdx = ConstantInt::get(Builder.getInt32Ty(), 0);
1191 if (IID == Intrinsic::dx_resource_getpointer)
1192 AccessIdx.GetPtrIdx =
II->getArgOperand(1);
1205 AccessIdx.OffsetIdx =
1206 AccessIdx.hasOffsetIdx()
1207 ? Builder.CreateAdd(AccessIdx.OffsetIdx, GEPOffset)
1216 if (
auto It = VisitedPhis.find(Phi); It != VisitedPhis.end())
1219 unsigned NumEdges = Phi->getNumIncomingValues();
1220 assert(NumEdges != 0 &&
"Malformed Phi Node");
1223 std::unique_ptr<PHINode> GetPtrPhi(
1225 std::unique_ptr<PHINode> HandlePhi(
1227 std::unique_ptr<PHINode> OffsetPhi(
1229 bool HasOffset =
false;
1234 if (Phi->getType()->isTargetExtTy())
1235 VisitedPhis[Phi] = AccessIndices{
nullptr, HandlePhi.get(),
1237 else if (Phi->getType()->isPointerTy())
1239 AccessIndices{GetPtrPhi.get(), HandlePhi.get(), OffsetPhi.get()};
1241 for (
unsigned Idx = 0; Idx < NumEdges; Idx++) {
1242 auto *BB = Phi->getIncomingBlock(Idx);
1245 if (AccessIdx.hasGetPtrIdx())
1246 GetPtrPhi->addIncoming(AccessIdx.GetPtrIdx, BB);
1247 HandlePhi->addIncoming(AccessIdx.HandleIdx, BB);
1248 if (AccessIdx.hasOffsetIdx()) {
1249 OffsetPhi->addIncoming(AccessIdx.OffsetIdx, BB);
1252 OffsetPhi->addIncoming(ConstantInt::get(Builder.getInt32Ty(), 0), BB);
1257 if (GetPtrPhi->getNumIncomingValues() == 0) {
1258 GetPtrIdx =
nullptr;
1259 }
else if (
Value *ConstantGetPtr = GetPtrPhi->hasConstantValue()) {
1260 GetPtrIdx = ConstantGetPtr;
1263 GetPtrIdx = GetPtrPhi.release();
1264 Builder.Insert(GetPtrIdx);
1268 if (
Value *ConstantHandle = HandlePhi->hasConstantValue()) {
1269 HandleIdx = ConstantHandle;
1272 HandleIdx = HandlePhi.release();
1273 Builder.Insert(HandleIdx);
1276 Value *OffsetIdx =
nullptr;
1278 if (
Value *ConstantIdx = OffsetPhi->hasConstantValue()) {
1279 OffsetIdx = ConstantIdx;
1282 OffsetIdx = OffsetPhi.release();
1283 Builder.Insert(OffsetIdx);
1288 AccessIndices Result = {GetPtrIdx, HandleIdx, OffsetIdx};
1289 VisitedPhis[Phi] = Result;
1302 Value *GetPtrSelect =
nullptr;
1303 Value *OffsetSelect =
nullptr;
1305 if (TrueAccessIdx.hasGetPtrIdx() && FalseAccessIdx.hasGetPtrIdx())
1307 Builder.CreateSelect(
Select->getCondition(), TrueAccessIdx.GetPtrIdx,
1308 FalseAccessIdx.GetPtrIdx,
"",
Select);
1310 auto *HandleSelect =
1311 Builder.CreateSelect(
Select->getCondition(), TrueAccessIdx.HandleIdx,
1312 FalseAccessIdx.HandleIdx,
"",
Select);
1314 if (TrueAccessIdx.hasOffsetIdx() || FalseAccessIdx.hasOffsetIdx()) {
1315 Value *Zero = ConstantInt::get(Builder.getInt32Ty(), 0);
1317 TrueAccessIdx.hasOffsetIdx() ? TrueAccessIdx.OffsetIdx : Zero;
1318 Value *FalseOffset =
1319 FalseAccessIdx.hasOffsetIdx() ? FalseAccessIdx.OffsetIdx : Zero;
1320 OffsetSelect = Builder.CreateSelect(
Select->getCondition(), TrueOffset,
1321 FalseOffset,
"",
Select);
1325 return {GetPtrSelect, HandleSelect, OffsetSelect};
1334 PhiAccessIndicesMap &VisitedPhis) {
1336 assert(AccessIdx.hasHandleIdx() &&
1337 "Couldn't retrieve handle index. This is guaranteed by "
1338 "getAccessIndices");
1342 Builder.SetInsertPoint(Ptr->
getParent()->getFirstNonPHIIt());
1345 Builder.Insert(Handle);
1348 assert(AccessIdx.hasGetPtrIdx() &&
1349 "Couldn't retrieve getpointer index. This is guaranteed by "
1350 "getAccessIndices");
1351 auto *GetPtr = Builder.CreateIntrinsic(Ptr->
getType(),
1352 Intrinsic::dx_resource_getpointer,
1353 {Handle, AccessIdx.GetPtrIdx});
1357 Value *Result = GetPtr;
1358 if (AccessIdx.hasOffsetIdx())
1359 Result = Builder.CreatePtrAdd(GetPtr, AccessIdx.OffsetIdx);
1363 "Unexpected resource access operand type");
1382 PhiAccessIndicesMap VisitedPhis;
1388 unsigned NumHandles = Handles.
size();
1389 if (NumHandles <= 1)
1392 bool SameGlobalBinding =
true;
1394 for (
unsigned Idx = 1; Idx < NumHandles; Idx++)
1395 SameGlobalBinding &=
1398 if (!SameGlobalBinding)
1407 bool MadeChanges =
false;
1411 for (
const auto &HandleToIndex : VisitedPhis)
1412 ResourcePhis.
push_back(HandleToIndex.first);
1415 if (
I->hasNUses(0)) {
1416 I->eraseFromParent();
1431 for (
User *U :
II->users())
1435 while (!Worklist.
empty()) {
1445 assert(
SI->getValueOperand() !=
II &&
"Pointer escaped!");
1464 Dead->eraseFromParent();
1465 II->eraseFromParent();
1473 if (
II->getIntrinsicID() == Intrinsic::dx_resource_getpointer ||
1474 II->getIntrinsicID() == Intrinsic::dx_resource_getbasepointer) {
1477 (DRTM[HandleTy].isCBuffer() ||
1478 II->getIntrinsicID() != Intrinsic::dx_resource_getbasepointer) &&
1479 "dx_resource_getbasepointer should only be used by cbuffers");
1494 assert(DRTM &&
"DXILResourceTypeAnalysis must be available");
1498 if (!(MadeHandleChanges || MadeResourceChanges))
1511 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1514 return MadeHandleChanges || MadeResourceChanges;
1516 StringRef getPassName()
const override {
return "DXIL Resource Access"; }
1517 DXILResourceAccessLegacy() : FunctionPass(
ID) {}
1520 void getAnalysisUsage(llvm::AnalysisUsage &AU)
const override {
1524char DXILResourceAccessLegacy::ID = 0;
1528 "DXIL Resource Access",
false,
false)
1534 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()
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.