25#include "llvm/IR/IntrinsicsDirectX.h"
35#define DEBUG_TYPE "dxil-op-lower"
59 : M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM), MMDI(MMDI) {}
71 if (
Error E = ReplaceCall(CI)) {
72 std::string Message(
toString(std::move(
E)));
84 struct IntrinArgSelect {
86#define DXIL_OP_INTRINSIC_ARG_SELECT_TYPE(name) name,
87#include "DXILOperation.inc"
97 Error replaceNamedStructUses(CallInst *Intrin, CallInst *DXILOp) {
100 if (!IntrinTy->isLayoutIdentical(DXILOpTy))
102 "Type mismatch between intrinsic and DXIL op",
107 EVI->setOperand(0, DXILOp);
109 IVI->setOperand(0, DXILOp);
112 "be used by insert- and extractvalue",
117 bool isFast(FastMathFlags Flags) {
121 Flags.noSignedZeros() &&
Flags.allowReciprocal() &&
125 void setDxPrecise(CallInst *CI) {
126 const StringRef
Key =
"dx.precise";
140 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
141 OpBuilder.getIRB().SetInsertPoint(CI);
143 if (ArgSelects.
size()) {
144 for (
const IntrinArgSelect &
A : ArgSelects) {
146 case IntrinArgSelect::Type::Index:
149 case IntrinArgSelect::Type::I8:
150 Args.push_back(OpBuilder.getIRB().getInt8((uint8_t)
A.Value));
152 case IntrinArgSelect::Type::I32:
153 Args.push_back(OpBuilder.getIRB().getInt32(
A.Value));
161 Expected<CallInst *> OpCall =
162 OpBuilder.tryCreateOp(DXILOp, Args, CI->
getName(),
F.getReturnType());
168 setDxPrecise(*OpCall);
171 if (
Error E = replaceNamedStructUses(CI, *OpCall))
187 CallInst *Cast = OpBuilder.getIRB().CreateIntrinsicWithoutFolding(
188 Intrinsic::dx_resource_casthandle, {Ty,
V->getType()}, {
V});
189 CleanupCasts.push_back(Cast);
193 void cleanupHandleCasts() {
197 for (CallInst *Cast : CleanupCasts) {
206 if (Cast->
getType() != OpBuilder.getHandleType()) {
213 assert(
Def->getIntrinsicID() == Intrinsic::dx_resource_casthandle &&
214 "Unbalanced pair of temporary handle casts");
227 F->eraseFromParent();
229 CleanupCasts.clear();
232 void cleanupNonUniformResourceIndexCalls() {
243 CleanupNURI->eraseFromParent();
244 CleanupNURI =
nullptr;
252 void removeResourceGlobals(CallInst *CI) {
256 Store->eraseFromParent();
258 if (GV->use_empty()) {
259 GV->removeDeadConstantUsers();
260 GV->eraseFromParent();
266 void replaceHandleFromBindingCall(CallInst *CI,
Value *Replacement) {
268 Intrinsic::dx_resource_handlefrombinding);
270 removeResourceGlobals(CI);
277 if (NameGlobal && NameGlobal->use_empty())
278 NameGlobal->eraseFromParent();
281 bool hasNonUniformIndex(
Value *IndexOp) {
285 SmallVector<Value *, 16> Worklist;
286 SmallPtrSet<Value *, 16> Visited;
289 while (!Worklist.
empty()) {
295 if (!Visited.
insert(V).second)
299 if (CI->
getIntrinsicID() == Intrinsic::dx_resource_nonuniformindex)
305 for (
Value *Incoming :
Phi->incoming_values())
311 if (Inst->getNumOperands() > 0 && !Inst->isTerminator())
312 for (
Value *
Op : Inst->operands())
318 Error validateRawBufferElementIndex(
Value *Resource,
Value *ElementIndex) {
323 if (IsStructured && IsPoison)
325 "Element index of structured buffer may not be poison",
328 if (!IsStructured && !IsPoison)
330 "Element index of raw buffer must be poison",
336 [[nodiscard]]
bool lowerToCreateHandle(
Function &
F) {
342 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
345 auto *It = DRM.find(CI);
346 assert(It != DRM.end() &&
"Resource not in map?");
347 dxil::ResourceInfo &RI = *It;
355 ConstantInt::get(Int32Ty,
Binding.LowerBound));
357 bool HasNonUniformIndex =
358 (
Binding.Size == 1) ?
false : hasNonUniformIndex(IndexOp);
359 std::array<Value *, 4>
Args{
361 ConstantInt::get(Int32Ty,
Binding.BindingID), IndexOp,
362 ConstantInt::get(Int1Ty, HasNonUniformIndex)};
363 Expected<CallInst *> OpCall =
364 OpBuilder.tryCreateOp(OpCode::CreateHandle, Args, CI->
getName());
368 Value *Cast = createTmpHandleCast(*OpCall, CI->
getType());
369 replaceHandleFromBindingCall(CI, Cast);
374 [[nodiscard]]
bool lowerToBindAndAnnotateHandle(
Function &
F) {
379 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
382 auto *It = DRM.find(CI);
383 assert(It != DRM.end() &&
"Resource not in map?");
384 dxil::ResourceInfo &RI = *It;
387 dxil::ResourceTypeInfo &RTI = DRTM[RI.
getHandleTy()];
393 ConstantInt::get(Int32Ty,
Binding.LowerBound));
395 std::pair<uint32_t, uint32_t> Props =
400 uint32_t UpperBound =
Binding.Size == 0
401 ? std::numeric_limits<uint32_t>::max()
403 Constant *ResBind = OpBuilder.getResBind(
Binding.LowerBound, UpperBound,
405 bool NonUniformIndex =
406 (
Binding.Size == 1) ?
false : hasNonUniformIndex(IndexOp);
407 Constant *NonUniformOp = ConstantInt::get(Int1Ty, NonUniformIndex);
408 std::array<Value *, 3> BindArgs{ResBind, IndexOp, NonUniformOp};
409 Expected<CallInst *> OpBind = OpBuilder.tryCreateOp(
410 OpCode::CreateHandleFromBinding, BindArgs, CI->
getName());
414 std::array<Value *, 2> AnnotateArgs{
415 *OpBind, OpBuilder.getResProps(Props.first, Props.second)};
416 Expected<CallInst *> OpAnnotate = OpBuilder.tryCreateOp(
417 OpCode::AnnotateHandle, AnnotateArgs,
422 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->
getType());
423 replaceHandleFromBindingCall(CI, Cast);
431 bool lowerHandleFromBinding(
Function &
F) {
432 if (MMDI.DXILVersion < VersionTuple(1, 6))
433 return lowerToCreateHandle(
F);
434 return lowerToBindAndAnnotateHandle(
F);
440 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
443 auto *It = DRM.find(CI);
444 assert(It != DRM.end() &&
"Resource not in map?");
445 dxil::ResourceInfo &RI = *It;
446 dxil::ResourceTypeInfo &RTI = DRTM[RI.
getHandleTy()];
449 Value *IsSamplerHeap =
452 std::pair<uint32_t, uint32_t> Props =
455 bool NonUniformIndex = hasNonUniformIndex(IndexOp);
456 Value *NonUniformOp =
459 std::array<Value *, 3>
Args{IndexOp, IsSamplerHeap, NonUniformOp};
460 Expected<CallInst *> OpCreateHandle = OpBuilder.tryCreateOp(
461 OpCode::CreateHandleFromHeap, Args, CI->
getName());
465 std::array<Value *, 2> AnnotateArgs{
466 *OpCreateHandle, OpBuilder.getResProps(Props.first, Props.second)};
467 Expected<CallInst *> OpAnnotate = OpBuilder.tryCreateOp(
468 OpCode::AnnotateHandle, AnnotateArgs,
473 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->
getType());
482 Error replaceResRetUses(CallInst *Intrin, CallInst *
Op,
bool HasCheckBit) {
491 Value *CheckOp =
nullptr;
495 ArrayRef<unsigned> Indices = EVI->getIndices();
502 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
503 OpCode::CheckAccessFullyMapped, {NewEVI},
511 EVI->replaceAllUsesWith(CheckOp);
512 EVI->eraseFromParent();
524 "Expected only use to be extract of first element");
526 OldTy =
ST->getElementType(0);
534 if (OldResult != Intrin) {
541 std::array<Value *, 4> Extracts = {};
549 size_t IndexVal = IndexOp->getZExtValue();
550 assert(IndexVal < 4 &&
"Index into buffer load out of range");
551 if (!Extracts[IndexVal])
554 EEI->eraseFromParent();
562 const unsigned N = VecTy->getNumElements();
566 if (!DynamicAccesses.
empty()) {
570 Type *ElTy = VecTy->getElementType();
571 Type *ArrayTy = ArrayType::get(ElTy,
N);
574 for (
int I = 0,
E =
N;
I !=
E; ++
I) {
578 ArrayTy, Alloca, {
Zero, ConstantInt::get(Int32Ty,
I)});
582 for (ExtractElementInst *EEI : DynamicAccesses) {
584 {
Zero, EEI->getIndexOperand()});
587 EEI->eraseFromParent();
595 for (
int I = 0,
E =
N;
I !=
E; ++
I)
600 for (
int I = 0,
E =
N;
I !=
E; ++
I)
606 if (OldResult != Intrin) {
614 [[nodiscard]]
bool lowerTypedBufferLoad(
Function &
F,
bool HasCheckBit) {
618 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
622 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
631 std::array<Value *, 3>
Args{Handle, Index0, Index1};
632 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
633 OpCode::BufferLoad, Args, CI->
getName(), NewRetTy);
636 if (
Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
646 static void collectInsertedElements(
Value *Vec,
649 assert(NumElts <=
Elements.size() &&
"Not enough room for the components");
661 while (!Chain.
empty()) {
664 if (IndexVal < NumElts)
672 static void extractElementsIntoArgs(
IRBuilder<> &IRB,
674 unsigned ArgIdx,
Value *Src,
675 unsigned MaxElements) {
682 unsigned Count = VecTy->getNumElements();
683 assert(
Count <= MaxElements &&
"Too many elements for the arg list");
686 collectInsertedElements(Src, Elements);
688 for (
unsigned I = 0;
I <
Count; ++
I)
689 Args[ArgIdx +
I] = Elements[
I]
691 : IRB.CreateExtractElement(
692 Src, ConstantInt::
get(IRB.getInt32Ty(),
I));
697 static void extractNonZeroOffsets(
IRBuilder<> &IRB,
699 unsigned ArgIdx,
Value *Offsets,
700 unsigned MaxElements) {
702 bool OffsetsAreZero = COff && COff->isNullValue();
704 extractElementsIntoArgs(IRB, Args, ArgIdx, Offsets, MaxElements);
707 [[nodiscard]]
bool lowerTextureLoad(
Function &
F) {
711 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
716 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
725 dxil::ResourceTypeInfo &RTI = DRTM[HandleTy];
727 if (RTI.
isUAV() && Kind != dxil::ResourceKind::Texture2DMS &&
728 Kind != dxil::ResourceKind::Texture2DMSArray)
739 extractElementsIntoArgs(IRB, Args, 2, Coords, 3);
740 extractNonZeroOffsets(IRB, Args, 5, Offsets, 3);
742 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
743 OpCode::TextureLoad, Args, CI->
getName(), NewRetTy);
746 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
749 eraseDeadInsertElementChains(VectorArgs);
758 [[nodiscard]]
bool lowerSampleOp(
761 SmallVectorImpl<Value *> &)> EmitExtraArgs) {
763 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
768 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
770 createTmpHandleCast(CI->
getArgOperand(1), OpBuilder.getHandleType());
781 UndefF, UndefI, UndefI, UndefI};
784 extractElementsIntoArgs(IRB, Args, 2, Coords, 4);
785 extractNonZeroOffsets(IRB, Args, 6, Offsets, 3);
788 EmitExtraArgs(IRB, CI, Args);
790 Expected<CallInst *> OpCall =
791 OpBuilder.tryCreateOp(
Op, Args, CI->
getName(), NewRetTy);
794 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
797 eraseDeadInsertElementChains(VectorArgs);
803 [[nodiscard]]
bool lowerSample(
Function &
F,
bool HasClamp) {
804 return lowerSampleOp(
F, OpCode::Sample, 2, 3,
806 SmallVectorImpl<Value *> &Args) {
814 [[nodiscard]]
bool lowerSampleBias(
Function &
F,
bool HasClamp) {
815 return lowerSampleOp(
816 F, OpCode::SampleBias, 2, 4,
818 SmallVectorImpl<Value *> &Args) {
827 [[nodiscard]]
bool lowerSampleLevel(
Function &
F) {
828 return lowerSampleOp(
829 F, OpCode::SampleLevel, 2, 4,
830 [](
IRBuilder<> &, CallInst *CI, SmallVectorImpl<Value *> &Args) {
836 [[nodiscard]]
bool lowerSampleGrad(
Function &
F,
bool HasClamp) {
837 return lowerSampleOp(
838 F, OpCode::SampleGrad, 2, 5,
840 SmallVectorImpl<Value *> &Args) {
845 size_t DDXStart =
Args.size();
846 Args.append(3, UndefF);
847 extractElementsIntoArgs(IRB, Args, DDXStart, DDX, 3);
849 size_t DDYStart =
Args.size();
850 Args.append(3, UndefF);
851 extractElementsIntoArgs(IRB, Args, DDYStart, DDY, 3);
857 [[nodiscard]]
bool lowerRawBufferLoad(
Function &
F) {
858 const DataLayout &
DL =
F.getDataLayout();
863 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
868 Type *NewRetTy = OpBuilder.getResRetType(ScalarTy);
871 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
875 DL.getTypeSizeInBits(OldTy) /
DL.getTypeSizeInBits(ScalarTy);
876 Value *
Mask = ConstantInt::get(Int8Ty, ~(~0U << NumElements));
878 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value());
885 Expected<CallInst *> OpCall =
886 MMDI.DXILVersion >= VersionTuple(1, 2)
887 ? OpBuilder.tryCreateOp(OpCode::RawBufferLoad,
890 : OpBuilder.tryCreateOp(OpCode::BufferLoad,
891 {Handle, Index0, Index1}, CI->
getName(),
895 if (
Error E = replaceResRetUses(CI, *OpCall,
true))
902 [[nodiscard]]
bool lowerCBufferLoad(
Function &
F) {
905 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
910 Type *NewRetTy = OpBuilder.getCBufRetType(ScalarTy);
913 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
916 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
917 OpCode::CBufferLoadLegacy, {Handle,
Index}, CI->
getName(), NewRetTy);
920 if (
Error E = replaceNamedStructUses(CI, *OpCall))
928 [[nodiscard]]
bool lowerUpdateCounter(
Function &
F) {
932 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
935 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
938 std::array<Value *, 2>
Args{Handle, Op1};
940 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
941 OpCode::UpdateCounter, Args, CI->
getName(), Int32Ty);
952 [[nodiscard]]
bool lowerGetDimensionsX(
Function &
F) {
956 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
959 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
962 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
963 OpCode::GetDimensions, {Handle,
Undef}, CI->
getName(), Int32Ty);
974 [[nodiscard]]
bool lowerGetPointer(
Function &
F) {
977 assert(
F.user_empty() &&
"getpointer operations should have been removed");
989 bool FillWithUndef) {
990 std::array<Value *, 4> DataElements{
nullptr,
nullptr,
nullptr,
nullptr};
991 extractElementsIntoArgs(IRB, DataElements, 0,
Data, 4);
997 if (DataElements[
I] ==
nullptr)
1002 return DataElements;
1007 static void eraseDeadInsertElementChain(
Value *
Data) {
1010 InsertElementInst *Tmp = IEI;
1016 [[nodiscard]]
bool lowerBufferStore(
Function &
F,
bool IsRaw) {
1017 const DataLayout &
DL =
F.getDataLayout();
1022 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1026 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1042 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1043 Value *
Mask = ConstantInt::get(Int8Ty, IsRaw ? ~(~0U << NumElements)
1047 if (NumElements > 4)
1049 "Buffer store data must have at most 4 elements",
1052 std::array<Value *, 4> DataElements =
1053 splitStoreData(IRB,
Data, NumElements, IsRaw);
1057 Handle, Index0, Index1, DataElements[0],
1058 DataElements[1], DataElements[2], DataElements[3],
Mask};
1059 if (IsRaw && MMDI.DXILVersion >= VersionTuple(1, 2)) {
1060 Op = OpCode::RawBufferStore;
1063 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value()));
1065 Expected<CallInst *> OpCall =
1066 OpBuilder.tryCreateOp(
Op, Args, CI->
getName());
1071 eraseDeadInsertElementChain(
Data);
1089 for (
const WeakTrackingVH &VH : Vectors)
1091 eraseDeadInsertElementChain(V);
1094 [[nodiscard]]
bool lowerTextureStore(
Function &
F) {
1095 const DataLayout &
DL =
F.getDataLayout();
1100 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1105 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1112 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1113 if (NumElements > 4)
1115 "Texture store data must have at most 4 elements",
1119 std::array<Value *, 4> DataElements =
1120 splitStoreData(IRB,
Data, NumElements,
false);
1123 std::array<Value *, 9>
Args{
1125 Undef, DataElements[0], DataElements[1],
1126 DataElements[2], DataElements[3],
Mask};
1129 extractElementsIntoArgs(IRB, Args, 1, Coords, 3);
1131 Expected<CallInst *> OpCall =
1132 OpBuilder.tryCreateOp(OpCode::TextureStore, Args, CI->
getName());
1137 eraseDeadInsertElementChains(VectorArgs);
1143 [[nodiscard]]
bool lowerResourceAtomicBinOp(
Function &
F) {
1146 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1152 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1159 std::array<Value *, 6>
Args{Handle, BinOp, Coord0,
1160 Coord1, Coord2, NewValue};
1161 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1166 std::string Message(
toString(std::move(
E)));
1180 [[nodiscard]]
bool lowerResourceAtomicCompareExchange(
Function &
F) {
1183 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1189 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1196 std::array<Value *, 6>
Args{Handle, Coord0, Coord1,
1197 Coord2, CompareValue, NewValue};
1198 Expected<CallInst *> OpCall =
1199 OpBuilder.tryCreateOp(dxil::OpCode::AtomicCompareExchange, Args,
1204 std::string Message(
toString(std::move(
E)));
1218 [[nodiscard]]
bool lowerCtpopToCountBits(
Function &
F) {
1222 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1227 Type *RetTy = Int32Ty;
1228 Type *FRT =
F.getReturnType();
1230 RetTy = VectorType::get(RetTy, VT);
1232 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1233 dxil::OpCode::CountBits, Args, CI->
getName(), RetTy);
1247 CastOp = Instruction::ZExt;
1248 CastOp2 = Instruction::SExt;
1251 "Currently only lowering 16, 32, or 64 bit ctpop to CountBits \
1253 CastOp = Instruction::Trunc;
1254 CastOp2 = Instruction::Trunc;
1259 bool NeedsCast =
false;
1262 if (
I && (
I->getOpcode() == CastOp ||
I->getOpcode() == CastOp2) &&
1263 I->getType() == RetTy) {
1264 I->replaceAllUsesWith(*OpCall);
1265 I->eraseFromParent();
1285 [[nodiscard]]
bool lowerLifetimeIntrinsic(
Function &
F) {
1287 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1291 "Expected operand of lifetime intrinsic to be a pointer");
1293 auto ZeroOrUndef = [&](
Type *Ty) {
1294 return MMDI.ValidatorVersion < VersionTuple(1, 6)
1296 : UndefValue::
get(Ty);
1299 Value *Val =
nullptr;
1301 if (GV->hasInitializer() || GV->isExternallyInitialized())
1303 Val = ZeroOrUndef(GV->getValueType());
1305 Val = ZeroOrUndef(AI->getAllocatedType());
1307 assert(Val &&
"Expected operand of lifetime intrinsic to be a global "
1308 "variable or alloca instruction");
1316 [[nodiscard]]
bool lowerIsFPClass(
Function &
F) {
1320 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1329 switch (TCI->getZExtValue()) {
1330 case FPClassTest::fcInf:
1331 OpCode = dxil::OpCode::IsInf;
1333 case FPClassTest::fcNan:
1334 OpCode = dxil::OpCode::IsNaN;
1336 case FPClassTest::fcNormal:
1337 OpCode = dxil::OpCode::IsNormal;
1339 case FPClassTest::fcFinite:
1340 OpCode = dxil::OpCode::IsFinite;
1343 SmallString<128>
Msg =
1344 formatv(
"Unsupported FPClassTest {0} for DXIL Op Lowering",
1345 TCI->getZExtValue());
1349 Expected<CallInst *> OpCall =
1360 bool lowerIntrinsics() {
1361 bool Updated =
false;
1362 bool HasErrors =
false;
1365 if (!
F.isDeclaration())
1371 case Intrinsic::dx_resource_casthandle:
1373 case Intrinsic::dbg_value:
1376 F.eraseFromParent();
1380 F.eraseFromParent();
1383 "Unsupported intrinsic {0} for DXIL lowering",
F.getName());
1384 M.getContext().emitError(
Msg);
1389#define DXIL_OP_INTRINSIC(OpCode, Intrin, ...) \
1391 HasErrors |= replaceFunctionWithOp( \
1392 F, OpCode, ArrayRef<IntrinArgSelect>{__VA_ARGS__}); \
1394#include "DXILOperation.inc"
1395 case Intrinsic::dx_resource_handlefrombinding:
1396 HasErrors |= lowerHandleFromBinding(
F);
1398 case Intrinsic::dx_resource_handlefromheap:
1399 HasErrors |= lowerHandleFromHeap(
F);
1401 case Intrinsic::dx_resource_getbasepointer:
1402 case Intrinsic::dx_resource_getpointer:
1403 HasErrors |= lowerGetPointer(
F);
1405 case Intrinsic::dx_resource_nonuniformindex:
1407 "overloaded llvm.dx.resource.nonuniformindex intrinsics?");
1410 case Intrinsic::dx_resource_load_typedbuffer:
1411 HasErrors |= lowerTypedBufferLoad(
F,
true);
1413 case Intrinsic::dx_resource_load_level:
1414 HasErrors |= lowerTextureLoad(
F);
1416 case Intrinsic::dx_resource_sample:
1417 HasErrors |= lowerSample(
F,
false);
1419 case Intrinsic::dx_resource_sample_clamp:
1420 HasErrors |= lowerSample(
F,
true);
1422 case Intrinsic::dx_resource_samplebias:
1423 HasErrors |= lowerSampleBias(
F,
false);
1425 case Intrinsic::dx_resource_samplebias_clamp:
1426 HasErrors |= lowerSampleBias(
F,
true);
1428 case Intrinsic::dx_resource_samplelevel:
1429 HasErrors |= lowerSampleLevel(
F);
1431 case Intrinsic::dx_resource_samplegrad:
1432 HasErrors |= lowerSampleGrad(
F,
false);
1434 case Intrinsic::dx_resource_samplegrad_clamp:
1435 HasErrors |= lowerSampleGrad(
F,
true);
1437 case Intrinsic::dx_resource_store_typedbuffer:
1438 HasErrors |= lowerBufferStore(
F,
false);
1440 case Intrinsic::dx_resource_store_texture:
1441 HasErrors |= lowerTextureStore(
F);
1443 case Intrinsic::dx_resource_load_rawbuffer:
1444 HasErrors |= lowerRawBufferLoad(
F);
1446 case Intrinsic::dx_resource_store_rawbuffer:
1447 HasErrors |= lowerBufferStore(
F,
true);
1449 case Intrinsic::dx_resource_load_cbufferrow_2:
1450 case Intrinsic::dx_resource_load_cbufferrow_4:
1451 case Intrinsic::dx_resource_load_cbufferrow_8:
1452 HasErrors |= lowerCBufferLoad(
F);
1454 case Intrinsic::dx_resource_updatecounter:
1455 HasErrors |= lowerUpdateCounter(
F);
1457 case Intrinsic::dx_resource_atomic_binop:
1458 HasErrors |= lowerResourceAtomicBinOp(
F);
1460 case Intrinsic::dx_resource_atomic_compare_exchange:
1461 HasErrors |= lowerResourceAtomicCompareExchange(
F);
1463 case Intrinsic::dx_resource_getdimensions_x:
1464 HasErrors |= lowerGetDimensionsX(
F);
1466 case Intrinsic::ctpop:
1467 HasErrors |= lowerCtpopToCountBits(
F);
1469 case Intrinsic::lifetime_start:
1470 case Intrinsic::lifetime_end:
1472 F.eraseFromParent();
1474 if (MMDI.DXILVersion < VersionTuple(1, 6))
1475 HasErrors |= lowerLifetimeIntrinsic(
F);
1480 case Intrinsic::is_fpclass:
1481 HasErrors |= lowerIsFPClass(
F);
1486 if (Updated && !HasErrors) {
1487 cleanupHandleCasts();
1488 cleanupNonUniformResourceIndexCalls();
1501 const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1513class DXILOpLoweringLegacy :
public ModulePass {
1515 bool runOnModule(
Module &M)
override {
1517 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
1519 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1521 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
1523 return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1525 StringRef getPassName()
const override {
return "DXIL Op Lowering"; }
1526 DXILOpLoweringLegacy() : ModulePass(
ID) {}
1529 void getAnalysisUsage(llvm::AnalysisUsage &AU)
const override {
1532 AU.
addRequired<DXILMetadataAnalysisWrapperPass>();
1539char DXILOpLoweringLegacy::ID = 0;
1550 return new DXILOpLoweringLegacy();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
ReachingDefInfo InstSet & ToRemove
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static constexpr uint8_t TypedUAVStoreWriteMask
Write mask covering all four components of a UAV element.
DXIL Resource Implicit Binding
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
This defines the Use class.
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)
static unsigned getFastMathFlags(const MachineInstr &I, const SPIRVSubtarget &ST)
This file defines the SmallVector class.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
size_t size() const
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.
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
iterator_range< User::op_iterator > args()
Iteration adapter for range-for loops.
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI ConstantInt * getBool(LLVMContext &Context, bool V)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Diagnostic information for unsupported feature in backend.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Error takeError()
Take ownership of the stored error.
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
IntegerType * getInt1Ty()
Fetch the type representing a single bit.
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="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
LLVMContext & getContext() const
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Type * getFloatTy()
Fetch the type representing a 32-bit floating point value.
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.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
iterator_range< user_iterator > users()
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
user_iterator user_begin()
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
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.
LLVMContext & getContext() const
Get the global data context.
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.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
reference emplace_back(ArgTypes &&... Args)
iterator erase(const_iterator CI)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isIntOrIntVectorTy() const
Return true if this is an integer type or a vector of integer types.
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'.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Value * getOperand(unsigned i) const
Type * getType() const
All values are typed, get the type of this value.
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
TargetExtType * getHandleTy() const
LLVM_ABI std::pair< uint32_t, uint32_t > getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const
const ResourceBinding & getBinding() const
dxil::ResourceClass getResourceClass() const
LLVM_ABI bool isUAV() const
LLVM_ABI bool isSampler() const
dxil::ResourceKind getResourceKind() const
An efficient, type-erasing, non-owning reference to a callable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
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.
ResourceKind
The kind of resource for an SRV or UAV resource.
NodeAddr< DefNode * > Def
NodeAddr< PhiNode * > Phi
NodeAddr< UseNode * > Use
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
@ Undef
Value of the register doesn't matter.
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).
@ Store
The extracted value is stored (ExtractElement only).
LLVM_ABI 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)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto formatv(bool Validate, const char *Fmt, Ts &&...Vals)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
void sort(IteratorTy Start, IteratorTy End)
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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...
LLVM_ATTRIBUTE_VISIBILITY_DEFAULT AnalysisKey InnerAnalysisManagerProxy< AnalysisManagerT, IRUnitT, ExtraArgTs... >::Key
MutableArrayRef(T &OneElt) -> MutableArrayRef< T >
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Count
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
std::string toString(const APInt &I, unsigned Radix, bool Signed, bool formatAsCLiteral=false, bool UpperCase=true, bool InsertSeparators=false)
ModulePass * createDXILOpLoweringLegacyPass()
Pass to lowering LLVM intrinsic call to DXIL op function call.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.