25#include "llvm/IR/IntrinsicsDirectX.h"
34#define DEBUG_TYPE "dxil-op-lower"
58 : M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM), MMDI(MMDI) {}
70 if (
Error E = ReplaceCall(CI)) {
71 std::string Message(
toString(std::move(
E)));
83 struct IntrinArgSelect {
85#define DXIL_OP_INTRINSIC_ARG_SELECT_TYPE(name) name,
86#include "DXILOperation.inc"
96 Error replaceNamedStructUses(CallInst *Intrin, CallInst *DXILOp) {
99 if (!IntrinTy->isLayoutIdentical(DXILOpTy))
101 "Type mismatch between intrinsic and DXIL op",
106 EVI->setOperand(0, DXILOp);
108 IVI->setOperand(0, DXILOp);
111 "be used by insert- and extractvalue",
116 bool isFast(FastMathFlags Flags) {
120 Flags.noSignedZeros() &&
Flags.allowReciprocal() &&
124 void setDxPrecise(CallInst *CI) {
125 const StringRef
Key =
"dx.precise";
139 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
140 OpBuilder.getIRB().SetInsertPoint(CI);
142 if (ArgSelects.
size()) {
143 for (
const IntrinArgSelect &
A : ArgSelects) {
145 case IntrinArgSelect::Type::Index:
148 case IntrinArgSelect::Type::I8:
149 Args.push_back(OpBuilder.getIRB().getInt8((uint8_t)
A.Value));
151 case IntrinArgSelect::Type::I32:
152 Args.push_back(OpBuilder.getIRB().getInt32(
A.Value));
160 Expected<CallInst *> OpCall =
161 OpBuilder.tryCreateOp(DXILOp, Args, CI->
getName(),
F.getReturnType());
167 setDxPrecise(*OpCall);
170 if (
Error E = replaceNamedStructUses(CI, *OpCall))
186 CallInst *Cast = OpBuilder.getIRB().CreateIntrinsicWithoutFolding(
187 Intrinsic::dx_resource_casthandle, {Ty,
V->getType()}, {
V});
188 CleanupCasts.push_back(Cast);
192 void cleanupHandleCasts() {
196 for (CallInst *Cast : CleanupCasts) {
205 if (Cast->
getType() != OpBuilder.getHandleType()) {
212 assert(
Def->getIntrinsicID() == Intrinsic::dx_resource_casthandle &&
213 "Unbalanced pair of temporary handle casts");
226 F->eraseFromParent();
228 CleanupCasts.clear();
231 void cleanupNonUniformResourceIndexCalls() {
242 CleanupNURI->eraseFromParent();
243 CleanupNURI =
nullptr;
251 void removeResourceGlobals(CallInst *CI) {
255 Store->eraseFromParent();
257 if (GV->use_empty()) {
258 GV->removeDeadConstantUsers();
259 GV->eraseFromParent();
265 void replaceHandleFromBindingCall(CallInst *CI,
Value *Replacement) {
267 Intrinsic::dx_resource_handlefrombinding);
269 removeResourceGlobals(CI);
276 if (NameGlobal && NameGlobal->use_empty())
277 NameGlobal->removeFromParent();
280 bool hasNonUniformIndex(
Value *IndexOp) {
284 SmallVector<Value *, 16> Worklist;
285 SmallPtrSet<Value *, 16> Visited;
288 while (!Worklist.
empty()) {
294 if (!Visited.
insert(V).second)
298 if (CI->
getIntrinsicID() == Intrinsic::dx_resource_nonuniformindex)
304 for (
Value *Incoming :
Phi->incoming_values())
310 if (Inst->getNumOperands() > 0 && !Inst->isTerminator())
311 for (
Value *
Op : Inst->operands())
317 Error validateRawBufferElementIndex(
Value *Resource,
Value *ElementIndex) {
322 if (IsStructured && IsPoison)
324 "Element index of structured buffer may not be poison",
327 if (!IsStructured && !IsPoison)
329 "Element index of raw buffer must be poison",
335 [[nodiscard]]
bool lowerToCreateHandle(
Function &
F) {
341 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
344 auto *It = DRM.find(CI);
345 assert(It != DRM.end() &&
"Resource not in map?");
346 dxil::ResourceInfo &RI = *It;
354 ConstantInt::get(Int32Ty,
Binding.LowerBound));
356 bool HasNonUniformIndex =
357 (
Binding.Size == 1) ?
false : hasNonUniformIndex(IndexOp);
358 std::array<Value *, 4>
Args{
360 ConstantInt::get(Int32Ty,
Binding.BindingID), IndexOp,
361 ConstantInt::get(Int1Ty, HasNonUniformIndex)};
362 Expected<CallInst *> OpCall =
363 OpBuilder.tryCreateOp(OpCode::CreateHandle, Args, CI->
getName());
367 Value *Cast = createTmpHandleCast(*OpCall, CI->
getType());
368 replaceHandleFromBindingCall(CI, Cast);
373 [[nodiscard]]
bool lowerToBindAndAnnotateHandle(
Function &
F) {
378 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
381 auto *It = DRM.find(CI);
382 assert(It != DRM.end() &&
"Resource not in map?");
383 dxil::ResourceInfo &RI = *It;
386 dxil::ResourceTypeInfo &RTI = DRTM[RI.
getHandleTy()];
392 ConstantInt::get(Int32Ty,
Binding.LowerBound));
394 std::pair<uint32_t, uint32_t> Props =
399 uint32_t UpperBound =
Binding.Size == 0
400 ? std::numeric_limits<uint32_t>::max()
402 Constant *ResBind = OpBuilder.getResBind(
Binding.LowerBound, UpperBound,
404 bool NonUniformIndex =
405 (
Binding.Size == 1) ?
false : hasNonUniformIndex(IndexOp);
406 Constant *NonUniformOp = ConstantInt::get(Int1Ty, NonUniformIndex);
407 std::array<Value *, 3> BindArgs{ResBind, IndexOp, NonUniformOp};
408 Expected<CallInst *> OpBind = OpBuilder.tryCreateOp(
409 OpCode::CreateHandleFromBinding, BindArgs, CI->
getName());
413 std::array<Value *, 2> AnnotateArgs{
414 *OpBind, OpBuilder.getResProps(Props.first, Props.second)};
415 Expected<CallInst *> OpAnnotate = OpBuilder.tryCreateOp(
416 OpCode::AnnotateHandle, AnnotateArgs,
421 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->
getType());
422 replaceHandleFromBindingCall(CI, Cast);
430 bool lowerHandleFromBinding(
Function &
F) {
431 if (MMDI.DXILVersion < VersionTuple(1, 6))
432 return lowerToCreateHandle(
F);
433 return lowerToBindAndAnnotateHandle(
F);
439 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
442 auto *It = DRM.find(CI);
443 assert(It != DRM.end() &&
"Resource not in map?");
444 dxil::ResourceInfo &RI = *It;
445 dxil::ResourceTypeInfo &RTI = DRTM[RI.
getHandleTy()];
448 Value *IsSamplerHeap =
451 std::pair<uint32_t, uint32_t> Props =
454 bool NonUniformIndex = hasNonUniformIndex(IndexOp);
455 Value *NonUniformOp =
458 std::array<Value *, 3>
Args{IndexOp, IsSamplerHeap, NonUniformOp};
459 Expected<CallInst *> OpCreateHandle = OpBuilder.tryCreateOp(
460 OpCode::CreateHandleFromHeap, Args, CI->
getName());
464 std::array<Value *, 2> AnnotateArgs{
465 *OpCreateHandle, OpBuilder.getResProps(Props.first, Props.second)};
466 Expected<CallInst *> OpAnnotate = OpBuilder.tryCreateOp(
467 OpCode::AnnotateHandle, AnnotateArgs,
472 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->
getType());
481 Error replaceResRetUses(CallInst *Intrin, CallInst *
Op,
bool HasCheckBit) {
490 Value *CheckOp =
nullptr;
494 ArrayRef<unsigned> Indices = EVI->getIndices();
501 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
502 OpCode::CheckAccessFullyMapped, {NewEVI},
510 EVI->replaceAllUsesWith(CheckOp);
511 EVI->eraseFromParent();
523 "Expected only use to be extract of first element");
525 OldTy =
ST->getElementType(0);
533 if (OldResult != Intrin) {
540 std::array<Value *, 4> Extracts = {};
548 size_t IndexVal = IndexOp->getZExtValue();
549 assert(IndexVal < 4 &&
"Index into buffer load out of range");
550 if (!Extracts[IndexVal])
553 EEI->eraseFromParent();
561 const unsigned N = VecTy->getNumElements();
565 if (!DynamicAccesses.
empty()) {
569 Type *ElTy = VecTy->getElementType();
570 Type *ArrayTy = ArrayType::get(ElTy,
N);
573 for (
int I = 0,
E =
N;
I !=
E; ++
I) {
577 ArrayTy, Alloca, {
Zero, ConstantInt::get(Int32Ty,
I)});
581 for (ExtractElementInst *EEI : DynamicAccesses) {
583 {
Zero, EEI->getIndexOperand()});
586 EEI->eraseFromParent();
594 for (
int I = 0,
E =
N;
I !=
E; ++
I)
599 for (
int I = 0,
E =
N;
I !=
E; ++
I)
605 if (OldResult != Intrin) {
613 [[nodiscard]]
bool lowerTypedBufferLoad(
Function &
F,
bool HasCheckBit) {
617 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
621 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
630 std::array<Value *, 3>
Args{Handle, Index0, Index1};
631 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
632 OpCode::BufferLoad, Args, CI->
getName(), NewRetTy);
635 if (
Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
645 static void extractElementsIntoArgs(
IRBuilder<> &IRB,
647 unsigned ArgIdx,
Value *Src,
648 unsigned MaxElements) {
649 Type *Ty = Src->getType();
651 unsigned Count = VecTy->getNumElements();
652 assert(
Count <= MaxElements &&
"Expected at most 3 elements in vector");
653 for (
unsigned I = 0;
I <
Count; ++
I)
662 static void extractNonZeroOffsets(
IRBuilder<> &IRB,
664 unsigned ArgIdx,
Value *Offsets,
665 unsigned MaxElements) {
667 bool OffsetsAreZero = COff && COff->isNullValue();
669 extractElementsIntoArgs(IRB, Args, ArgIdx, Offsets, MaxElements);
672 [[nodiscard]]
bool lowerTextureLoad(
Function &
F) {
676 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
680 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
689 dxil::ResourceTypeInfo &RTI = DRTM[HandleTy];
691 if (RTI.
isUAV() && Kind != dxil::ResourceKind::Texture2DMS &&
692 Kind != dxil::ResourceKind::Texture2DMSArray)
703 extractElementsIntoArgs(IRB, Args, 2, Coords, 3);
704 extractNonZeroOffsets(IRB, Args, 5, Offsets, 3);
706 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
707 OpCode::TextureLoad, Args, CI->
getName(), NewRetTy);
710 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
720 [[nodiscard]]
bool lowerSampleOp(
723 SmallVectorImpl<Value *> &)> EmitExtraArgs) {
725 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
729 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
731 createTmpHandleCast(CI->
getArgOperand(1), OpBuilder.getHandleType());
742 UndefF, UndefI, UndefI, UndefI};
745 extractElementsIntoArgs(IRB, Args, 2, Coords, 4);
746 extractNonZeroOffsets(IRB, Args, 6, Offsets, 3);
749 EmitExtraArgs(IRB, CI, Args);
751 Expected<CallInst *> OpCall =
752 OpBuilder.tryCreateOp(
Op, Args, CI->
getName(), NewRetTy);
755 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
762 [[nodiscard]]
bool lowerSample(
Function &
F,
bool HasClamp) {
763 return lowerSampleOp(
F, OpCode::Sample, 2, 3,
765 SmallVectorImpl<Value *> &Args) {
773 [[nodiscard]]
bool lowerSampleBias(
Function &
F,
bool HasClamp) {
774 return lowerSampleOp(
775 F, OpCode::SampleBias, 2, 4,
777 SmallVectorImpl<Value *> &Args) {
786 [[nodiscard]]
bool lowerSampleLevel(
Function &
F) {
787 return lowerSampleOp(
788 F, OpCode::SampleLevel, 2, 4,
789 [](
IRBuilder<> &, CallInst *CI, SmallVectorImpl<Value *> &Args) {
795 [[nodiscard]]
bool lowerSampleGrad(
Function &
F,
bool HasClamp) {
796 return lowerSampleOp(
797 F, OpCode::SampleGrad, 2, 5,
799 SmallVectorImpl<Value *> &Args) {
804 size_t DDXStart =
Args.size();
805 Args.append(3, UndefF);
806 extractElementsIntoArgs(IRB, Args, DDXStart, DDX, 3);
808 size_t DDYStart =
Args.size();
809 Args.append(3, UndefF);
810 extractElementsIntoArgs(IRB, Args, DDYStart, DDY, 3);
816 [[nodiscard]]
bool lowerRawBufferLoad(
Function &
F) {
817 const DataLayout &
DL =
F.getDataLayout();
822 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
827 Type *NewRetTy = OpBuilder.getResRetType(ScalarTy);
830 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
834 DL.getTypeSizeInBits(OldTy) /
DL.getTypeSizeInBits(ScalarTy);
835 Value *
Mask = ConstantInt::get(Int8Ty, ~(~0U << NumElements));
837 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value());
844 Expected<CallInst *> OpCall =
845 MMDI.DXILVersion >= VersionTuple(1, 2)
846 ? OpBuilder.tryCreateOp(OpCode::RawBufferLoad,
849 : OpBuilder.tryCreateOp(OpCode::BufferLoad,
850 {Handle, Index0, Index1}, CI->
getName(),
854 if (
Error E = replaceResRetUses(CI, *OpCall,
true))
861 [[nodiscard]]
bool lowerCBufferLoad(
Function &
F) {
864 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
869 Type *NewRetTy = OpBuilder.getCBufRetType(ScalarTy);
872 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
875 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
876 OpCode::CBufferLoadLegacy, {Handle,
Index}, CI->
getName(), NewRetTy);
879 if (
Error E = replaceNamedStructUses(CI, *OpCall))
887 [[nodiscard]]
bool lowerUpdateCounter(
Function &
F) {
891 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
894 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
897 std::array<Value *, 2>
Args{Handle, Op1};
899 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
900 OpCode::UpdateCounter, Args, CI->
getName(), Int32Ty);
911 [[nodiscard]]
bool lowerGetDimensionsX(
Function &
F) {
915 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
918 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
921 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
922 OpCode::GetDimensions, {Handle,
Undef}, CI->
getName(), Int32Ty);
933 [[nodiscard]]
bool lowerGetPointer(
Function &
F) {
936 assert(
F.user_empty() &&
"getpointer operations should have been removed");
948 bool FillWithUndef) {
952 std::array<Value *, 4> DataElements{
nullptr,
nullptr,
nullptr,
nullptr};
953 if (DataTy == ScalarTy)
954 DataElements[0] =
Data;
964 size_t IndexVal = IndexOp->getZExtValue();
965 assert(IndexVal < 4 &&
"Too many elements for resource store");
966 DataElements[IndexVal] = IEI->getOperand(1);
975 if (DataElements[
I] ==
nullptr)
983 if (DataElements[
I] ==
nullptr)
992 static void eraseDeadInsertElementChain(
Value *
Data) {
994 while (IEI && IEI->use_empty()) {
995 InsertElementInst *Tmp = IEI;
1001 [[nodiscard]]
bool lowerBufferStore(
Function &
F,
bool IsRaw) {
1002 const DataLayout &
DL =
F.getDataLayout();
1007 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1011 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1027 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1028 Value *
Mask = ConstantInt::get(Int8Ty, IsRaw ? ~(~0U << NumElements)
1032 if (NumElements > 4)
1034 "Buffer store data must have at most 4 elements",
1037 std::array<Value *, 4> DataElements =
1038 splitStoreData(IRB,
Data, NumElements, IsRaw);
1042 Handle, Index0, Index1, DataElements[0],
1043 DataElements[1], DataElements[2], DataElements[3],
Mask};
1044 if (IsRaw && MMDI.DXILVersion >= VersionTuple(1, 2)) {
1045 Op = OpCode::RawBufferStore;
1048 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value()));
1050 Expected<CallInst *> OpCall =
1051 OpBuilder.tryCreateOp(
Op, Args, CI->
getName());
1056 eraseDeadInsertElementChain(
Data);
1062 [[nodiscard]]
bool lowerTextureStore(
Function &
F) {
1063 const DataLayout &
DL =
F.getDataLayout();
1068 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1072 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1079 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1080 if (NumElements > 4)
1082 "Texture store data must have at most 4 elements",
1086 std::array<Value *, 4> DataElements =
1087 splitStoreData(IRB,
Data, NumElements,
false);
1090 std::array<Value *, 9>
Args{
1092 Undef, DataElements[0], DataElements[1],
1093 DataElements[2], DataElements[3],
Mask};
1096 extractElementsIntoArgs(IRB, Args, 1, Coords, 3);
1098 Expected<CallInst *> OpCall =
1099 OpBuilder.tryCreateOp(OpCode::TextureStore, Args, CI->
getName());
1104 eraseDeadInsertElementChain(
Data);
1110 [[nodiscard]]
bool lowerResourceAtomicBinOp(
Function &
F) {
1113 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1119 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1125 std::array<Value *, 6>
Args{
1126 Handle, BinOp, Coord0, Coord1, ConstantInt::get(IRB.
getInt32Ty(), 0),
1128 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1133 std::string Message(
toString(std::move(
E)));
1147 [[nodiscard]]
bool lowerCtpopToCountBits(
Function &
F) {
1151 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1156 Type *RetTy = Int32Ty;
1157 Type *FRT =
F.getReturnType();
1159 RetTy = VectorType::get(RetTy, VT);
1161 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1162 dxil::OpCode::CountBits, Args, CI->
getName(), RetTy);
1176 CastOp = Instruction::ZExt;
1177 CastOp2 = Instruction::SExt;
1180 "Currently only lowering 16, 32, or 64 bit ctpop to CountBits \
1182 CastOp = Instruction::Trunc;
1183 CastOp2 = Instruction::Trunc;
1188 bool NeedsCast =
false;
1191 if (
I && (
I->getOpcode() == CastOp ||
I->getOpcode() == CastOp2) &&
1192 I->getType() == RetTy) {
1193 I->replaceAllUsesWith(*OpCall);
1194 I->eraseFromParent();
1214 [[nodiscard]]
bool lowerLifetimeIntrinsic(
Function &
F) {
1216 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1220 "Expected operand of lifetime intrinsic to be a pointer");
1222 auto ZeroOrUndef = [&](
Type *Ty) {
1223 return MMDI.ValidatorVersion < VersionTuple(1, 6)
1225 : UndefValue::
get(Ty);
1228 Value *Val =
nullptr;
1230 if (GV->hasInitializer() || GV->isExternallyInitialized())
1232 Val = ZeroOrUndef(GV->getValueType());
1234 Val = ZeroOrUndef(AI->getAllocatedType());
1236 assert(Val &&
"Expected operand of lifetime intrinsic to be a global "
1237 "variable or alloca instruction");
1245 [[nodiscard]]
bool lowerIsFPClass(
Function &
F) {
1249 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1258 switch (TCI->getZExtValue()) {
1259 case FPClassTest::fcInf:
1260 OpCode = dxil::OpCode::IsInf;
1262 case FPClassTest::fcNan:
1263 OpCode = dxil::OpCode::IsNaN;
1265 case FPClassTest::fcNormal:
1266 OpCode = dxil::OpCode::IsNormal;
1268 case FPClassTest::fcFinite:
1269 OpCode = dxil::OpCode::IsFinite;
1272 SmallString<128>
Msg =
1273 formatv(
"Unsupported FPClassTest {0} for DXIL Op Lowering",
1274 TCI->getZExtValue());
1278 Expected<CallInst *> OpCall =
1289 bool lowerIntrinsics() {
1290 bool Updated =
false;
1291 bool HasErrors =
false;
1294 if (!
F.isDeclaration())
1300 case Intrinsic::dx_resource_casthandle:
1302 case Intrinsic::dbg_value:
1305 F.eraseFromParent();
1309 F.eraseFromParent();
1312 "Unsupported intrinsic {0} for DXIL lowering",
F.getName());
1313 M.getContext().emitError(
Msg);
1318#define DXIL_OP_INTRINSIC(OpCode, Intrin, ...) \
1320 HasErrors |= replaceFunctionWithOp( \
1321 F, OpCode, ArrayRef<IntrinArgSelect>{__VA_ARGS__}); \
1323#include "DXILOperation.inc"
1324 case Intrinsic::dx_resource_handlefrombinding:
1325 HasErrors |= lowerHandleFromBinding(
F);
1327 case Intrinsic::dx_resource_handlefromheap:
1328 HasErrors |= lowerHandleFromHeap(
F);
1330 case Intrinsic::dx_resource_getbasepointer:
1331 case Intrinsic::dx_resource_getpointer:
1332 HasErrors |= lowerGetPointer(
F);
1334 case Intrinsic::dx_resource_nonuniformindex:
1336 "overloaded llvm.dx.resource.nonuniformindex intrinsics?");
1339 case Intrinsic::dx_resource_load_typedbuffer:
1340 HasErrors |= lowerTypedBufferLoad(
F,
true);
1342 case Intrinsic::dx_resource_load_level:
1343 HasErrors |= lowerTextureLoad(
F);
1345 case Intrinsic::dx_resource_sample:
1346 HasErrors |= lowerSample(
F,
false);
1348 case Intrinsic::dx_resource_sample_clamp:
1349 HasErrors |= lowerSample(
F,
true);
1351 case Intrinsic::dx_resource_samplebias:
1352 HasErrors |= lowerSampleBias(
F,
false);
1354 case Intrinsic::dx_resource_samplebias_clamp:
1355 HasErrors |= lowerSampleBias(
F,
true);
1357 case Intrinsic::dx_resource_samplelevel:
1358 HasErrors |= lowerSampleLevel(
F);
1360 case Intrinsic::dx_resource_samplegrad:
1361 HasErrors |= lowerSampleGrad(
F,
false);
1363 case Intrinsic::dx_resource_samplegrad_clamp:
1364 HasErrors |= lowerSampleGrad(
F,
true);
1366 case Intrinsic::dx_resource_store_typedbuffer:
1367 HasErrors |= lowerBufferStore(
F,
false);
1369 case Intrinsic::dx_resource_store_texture:
1370 HasErrors |= lowerTextureStore(
F);
1372 case Intrinsic::dx_resource_load_rawbuffer:
1373 HasErrors |= lowerRawBufferLoad(
F);
1375 case Intrinsic::dx_resource_store_rawbuffer:
1376 HasErrors |= lowerBufferStore(
F,
true);
1378 case Intrinsic::dx_resource_load_cbufferrow_2:
1379 case Intrinsic::dx_resource_load_cbufferrow_4:
1380 case Intrinsic::dx_resource_load_cbufferrow_8:
1381 HasErrors |= lowerCBufferLoad(
F);
1383 case Intrinsic::dx_resource_updatecounter:
1384 HasErrors |= lowerUpdateCounter(
F);
1386 case Intrinsic::dx_resource_atomic_binop:
1387 HasErrors |= lowerResourceAtomicBinOp(
F);
1389 case Intrinsic::dx_resource_getdimensions_x:
1390 HasErrors |= lowerGetDimensionsX(
F);
1392 case Intrinsic::ctpop:
1393 HasErrors |= lowerCtpopToCountBits(
F);
1395 case Intrinsic::lifetime_start:
1396 case Intrinsic::lifetime_end:
1398 F.eraseFromParent();
1400 if (MMDI.DXILVersion < VersionTuple(1, 6))
1401 HasErrors |= lowerLifetimeIntrinsic(
F);
1406 case Intrinsic::is_fpclass:
1407 HasErrors |= lowerIsFPClass(
F);
1412 if (Updated && !HasErrors) {
1413 cleanupHandleCasts();
1414 cleanupNonUniformResourceIndexCalls();
1427 const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1439class DXILOpLoweringLegacy :
public ModulePass {
1441 bool runOnModule(
Module &M)
override {
1443 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
1445 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1447 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
1449 return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1451 StringRef getPassName()
const override {
return "DXIL Op Lowering"; }
1452 DXILOpLoweringLegacy() : ModulePass(
ID) {}
1455 void getAnalysisUsage(llvm::AnalysisUsage &AU)
const override {
1458 AU.
addRequired<DXILMetadataAnalysisWrapperPass>();
1465char DXILOpLoweringLegacy::ID = 0;
1476 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...
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 * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
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.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
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.
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.
user_iterator user_begin()
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< user_iterator > users()
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.