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)},
"",
583 for (ExtractElementInst *EEI : DynamicAccesses) {
585 ArrayTy, Alloca, {
Zero, EEI->getIndexOperand()},
"",
589 EEI->eraseFromParent();
597 for (
int I = 0,
E =
N;
I !=
E; ++
I)
602 for (
int I = 0,
E =
N;
I !=
E; ++
I)
608 if (OldResult != Intrin) {
616 [[nodiscard]]
bool lowerTypedBufferLoad(
Function &
F,
bool HasCheckBit) {
620 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
624 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
633 std::array<Value *, 3>
Args{Handle, Index0, Index1};
634 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
635 OpCode::BufferLoad, Args, CI->
getName(), NewRetTy);
638 if (
Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
648 static void collectInsertedElements(
Value *Vec,
651 assert(NumElts <=
Elements.size() &&
"Not enough room for the components");
663 while (!Chain.
empty()) {
666 if (IndexVal < NumElts)
674 static void extractElementsIntoArgs(
IRBuilder<> &IRB,
676 unsigned ArgIdx,
Value *Src,
677 unsigned MaxElements) {
684 unsigned Count = VecTy->getNumElements();
685 assert(
Count <= MaxElements &&
"Too many elements for the arg list");
688 collectInsertedElements(Src, Elements);
690 for (
unsigned I = 0;
I <
Count; ++
I)
691 Args[ArgIdx +
I] = Elements[
I]
693 : IRB.CreateExtractElement(
694 Src, ConstantInt::
get(IRB.getInt32Ty(),
I));
699 static void extractNonZeroOffsets(
IRBuilder<> &IRB,
701 unsigned ArgIdx,
Value *Offsets,
702 unsigned MaxElements) {
704 bool OffsetsAreZero = COff && COff->isNullValue();
706 extractElementsIntoArgs(IRB, Args, ArgIdx, Offsets, MaxElements);
709 [[nodiscard]]
bool lowerTextureLoad(
Function &
F) {
713 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
718 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
727 dxil::ResourceTypeInfo &RTI = DRTM[HandleTy];
729 if (RTI.
isUAV() && Kind != dxil::ResourceKind::Texture2DMS &&
730 Kind != dxil::ResourceKind::Texture2DMSArray)
741 extractElementsIntoArgs(IRB, Args, 2, Coords, 3);
742 extractNonZeroOffsets(IRB, Args, 5, Offsets, 3);
744 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
745 OpCode::TextureLoad, Args, CI->
getName(), NewRetTy);
748 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
751 eraseDeadInsertElementChains(VectorArgs);
760 [[nodiscard]]
bool lowerSampleOp(
763 SmallVectorImpl<Value *> &)> EmitExtraArgs) {
765 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
770 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
772 createTmpHandleCast(CI->
getArgOperand(1), OpBuilder.getHandleType());
783 UndefF, UndefI, UndefI, UndefI};
786 extractElementsIntoArgs(IRB, Args, 2, Coords, 4);
787 extractNonZeroOffsets(IRB, Args, 6, Offsets, 3);
790 EmitExtraArgs(IRB, CI, Args);
792 Expected<CallInst *> OpCall =
793 OpBuilder.tryCreateOp(
Op, Args, CI->
getName(), NewRetTy);
796 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
799 eraseDeadInsertElementChains(VectorArgs);
805 [[nodiscard]]
bool lowerSample(
Function &
F,
bool HasClamp) {
806 return lowerSampleOp(
F, OpCode::Sample, 2, 3,
808 SmallVectorImpl<Value *> &Args) {
816 [[nodiscard]]
bool lowerSampleBias(
Function &
F,
bool HasClamp) {
817 return lowerSampleOp(
818 F, OpCode::SampleBias, 2, 4,
820 SmallVectorImpl<Value *> &Args) {
829 [[nodiscard]]
bool lowerSampleLevel(
Function &
F) {
830 return lowerSampleOp(
831 F, OpCode::SampleLevel, 2, 4,
832 [](
IRBuilder<> &, CallInst *CI, SmallVectorImpl<Value *> &Args) {
838 [[nodiscard]]
bool lowerSampleGrad(
Function &
F,
bool HasClamp) {
839 return lowerSampleOp(
840 F, OpCode::SampleGrad, 2, 5,
842 SmallVectorImpl<Value *> &Args) {
847 size_t DDXStart =
Args.size();
848 Args.append(3, UndefF);
849 extractElementsIntoArgs(IRB, Args, DDXStart, DDX, 3);
851 size_t DDYStart =
Args.size();
852 Args.append(3, UndefF);
853 extractElementsIntoArgs(IRB, Args, DDYStart, DDY, 3);
859 [[nodiscard]]
bool lowerRawBufferLoad(
Function &
F) {
860 const DataLayout &
DL =
F.getDataLayout();
865 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
870 Type *NewRetTy = OpBuilder.getResRetType(ScalarTy);
873 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
877 DL.getTypeSizeInBits(OldTy) /
DL.getTypeSizeInBits(ScalarTy);
878 Value *
Mask = ConstantInt::get(Int8Ty, ~(~0U << NumElements));
880 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value());
887 Expected<CallInst *> OpCall =
888 MMDI.DXILVersion >= VersionTuple(1, 2)
889 ? OpBuilder.tryCreateOp(OpCode::RawBufferLoad,
892 : OpBuilder.tryCreateOp(OpCode::BufferLoad,
893 {Handle, Index0, Index1}, CI->
getName(),
897 if (
Error E = replaceResRetUses(CI, *OpCall,
true))
904 [[nodiscard]]
bool lowerCBufferLoad(
Function &
F) {
907 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
912 Type *NewRetTy = OpBuilder.getCBufRetType(ScalarTy);
915 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
918 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
919 OpCode::CBufferLoadLegacy, {Handle,
Index}, CI->
getName(), NewRetTy);
922 if (
Error E = replaceNamedStructUses(CI, *OpCall))
930 [[nodiscard]]
bool lowerUpdateCounter(
Function &
F) {
934 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
937 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
940 std::array<Value *, 2>
Args{Handle, Op1};
942 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
943 OpCode::UpdateCounter, Args, CI->
getName(), Int32Ty);
954 [[nodiscard]]
bool lowerGetDimensionsX(
Function &
F) {
958 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
961 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
964 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
965 OpCode::GetDimensions, {Handle,
Undef}, CI->
getName(), Int32Ty);
976 [[nodiscard]]
bool lowerGetPointer(
Function &
F) {
979 assert(
F.user_empty() &&
"getpointer operations should have been removed");
991 bool FillWithUndef) {
992 std::array<Value *, 4> DataElements{
nullptr,
nullptr,
nullptr,
nullptr};
993 extractElementsIntoArgs(IRB, DataElements, 0,
Data, 4);
999 if (DataElements[
I] ==
nullptr)
1004 return DataElements;
1009 static void eraseDeadInsertElementChain(
Value *
Data) {
1012 InsertElementInst *Tmp = IEI;
1018 [[nodiscard]]
bool lowerBufferStore(
Function &
F,
bool IsRaw) {
1019 const DataLayout &
DL =
F.getDataLayout();
1024 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1028 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1044 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1045 Value *
Mask = ConstantInt::get(Int8Ty, IsRaw ? ~(~0U << NumElements)
1049 if (NumElements > 4)
1051 "Buffer store data must have at most 4 elements",
1054 std::array<Value *, 4> DataElements =
1055 splitStoreData(IRB,
Data, NumElements, IsRaw);
1059 Handle, Index0, Index1, DataElements[0],
1060 DataElements[1], DataElements[2], DataElements[3],
Mask};
1061 if (IsRaw && MMDI.DXILVersion >= VersionTuple(1, 2)) {
1062 Op = OpCode::RawBufferStore;
1065 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value()));
1067 Expected<CallInst *> OpCall =
1068 OpBuilder.tryCreateOp(
Op, Args, CI->
getName());
1073 eraseDeadInsertElementChain(
Data);
1091 for (
const WeakTrackingVH &VH : Vectors)
1093 eraseDeadInsertElementChain(V);
1096 [[nodiscard]]
bool lowerTextureStore(
Function &
F) {
1097 const DataLayout &
DL =
F.getDataLayout();
1102 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1107 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1114 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1115 if (NumElements > 4)
1117 "Texture store data must have at most 4 elements",
1121 std::array<Value *, 4> DataElements =
1122 splitStoreData(IRB,
Data, NumElements,
false);
1125 std::array<Value *, 9>
Args{
1127 Undef, DataElements[0], DataElements[1],
1128 DataElements[2], DataElements[3],
Mask};
1131 extractElementsIntoArgs(IRB, Args, 1, Coords, 3);
1133 Expected<CallInst *> OpCall =
1134 OpBuilder.tryCreateOp(OpCode::TextureStore, Args, CI->
getName());
1139 eraseDeadInsertElementChains(VectorArgs);
1145 [[nodiscard]]
bool lowerResourceAtomicBinOp(
Function &
F) {
1148 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1154 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1161 std::array<Value *, 6>
Args{Handle, BinOp, Coord0,
1162 Coord1, Coord2, NewValue};
1163 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1168 std::string Message(
toString(std::move(
E)));
1182 [[nodiscard]]
bool lowerResourceAtomicCompareExchange(
Function &
F) {
1185 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1191 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1198 std::array<Value *, 6>
Args{Handle, Coord0, Coord1,
1199 Coord2, CompareValue, NewValue};
1200 Expected<CallInst *> OpCall =
1201 OpBuilder.tryCreateOp(dxil::OpCode::AtomicCompareExchange, Args,
1206 std::string Message(
toString(std::move(
E)));
1220 [[nodiscard]]
bool lowerCtpopToCountBits(
Function &
F) {
1224 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1229 Type *RetTy = Int32Ty;
1230 Type *FRT =
F.getReturnType();
1232 RetTy = VectorType::get(RetTy, VT);
1234 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1235 dxil::OpCode::CountBits, Args, CI->
getName(), RetTy);
1249 CastOp = Instruction::ZExt;
1250 CastOp2 = Instruction::SExt;
1253 "Currently only lowering 16, 32, or 64 bit ctpop to CountBits \
1255 CastOp = Instruction::Trunc;
1256 CastOp2 = Instruction::Trunc;
1261 bool NeedsCast =
false;
1264 if (
I && (
I->getOpcode() == CastOp ||
I->getOpcode() == CastOp2) &&
1265 I->getType() == RetTy) {
1266 I->replaceAllUsesWith(*OpCall);
1267 I->eraseFromParent();
1287 [[nodiscard]]
bool lowerLifetimeIntrinsic(
Function &
F) {
1289 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1293 "Expected operand of lifetime intrinsic to be a pointer");
1295 auto ZeroOrUndef = [&](
Type *Ty) {
1296 return MMDI.ValidatorVersion < VersionTuple(1, 6)
1298 : UndefValue::
get(Ty);
1301 Value *Val =
nullptr;
1303 if (GV->hasInitializer() || GV->isExternallyInitialized())
1305 Val = ZeroOrUndef(GV->getValueType());
1307 Val = ZeroOrUndef(AI->getAllocatedType());
1309 assert(Val &&
"Expected operand of lifetime intrinsic to be a global "
1310 "variable or alloca instruction");
1318 [[nodiscard]]
bool lowerIsFPClass(
Function &
F) {
1322 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1331 switch (TCI->getZExtValue()) {
1332 case FPClassTest::fcInf:
1333 OpCode = dxil::OpCode::IsInf;
1335 case FPClassTest::fcNan:
1336 OpCode = dxil::OpCode::IsNaN;
1338 case FPClassTest::fcNormal:
1339 OpCode = dxil::OpCode::IsNormal;
1341 case FPClassTest::fcFinite:
1342 OpCode = dxil::OpCode::IsFinite;
1345 SmallString<128>
Msg =
1346 formatv(
"Unsupported FPClassTest {0} for DXIL Op Lowering",
1347 TCI->getZExtValue());
1351 Expected<CallInst *> OpCall =
1362 bool lowerIntrinsics() {
1363 bool Updated =
false;
1364 bool HasErrors =
false;
1367 if (!
F.isDeclaration())
1373 case Intrinsic::dx_resource_casthandle:
1375 case Intrinsic::dbg_value:
1378 F.eraseFromParent();
1382 F.eraseFromParent();
1385 "Unsupported intrinsic {0} for DXIL lowering",
F.getName());
1386 M.getContext().emitError(
Msg);
1391#define DXIL_OP_INTRINSIC(OpCode, Intrin, ...) \
1393 HasErrors |= replaceFunctionWithOp( \
1394 F, OpCode, ArrayRef<IntrinArgSelect>{__VA_ARGS__}); \
1396#include "DXILOperation.inc"
1397 case Intrinsic::dx_resource_handlefrombinding:
1398 HasErrors |= lowerHandleFromBinding(
F);
1400 case Intrinsic::dx_resource_handlefromheap:
1401 HasErrors |= lowerHandleFromHeap(
F);
1403 case Intrinsic::dx_resource_getbasepointer:
1404 case Intrinsic::dx_resource_getpointer:
1405 HasErrors |= lowerGetPointer(
F);
1407 case Intrinsic::dx_resource_nonuniformindex:
1409 "overloaded llvm.dx.resource.nonuniformindex intrinsics?");
1412 case Intrinsic::dx_resource_load_typedbuffer:
1413 HasErrors |= lowerTypedBufferLoad(
F,
true);
1415 case Intrinsic::dx_resource_load_level:
1416 HasErrors |= lowerTextureLoad(
F);
1418 case Intrinsic::dx_resource_sample:
1419 HasErrors |= lowerSample(
F,
false);
1421 case Intrinsic::dx_resource_sample_clamp:
1422 HasErrors |= lowerSample(
F,
true);
1424 case Intrinsic::dx_resource_samplebias:
1425 HasErrors |= lowerSampleBias(
F,
false);
1427 case Intrinsic::dx_resource_samplebias_clamp:
1428 HasErrors |= lowerSampleBias(
F,
true);
1430 case Intrinsic::dx_resource_samplelevel:
1431 HasErrors |= lowerSampleLevel(
F);
1433 case Intrinsic::dx_resource_samplegrad:
1434 HasErrors |= lowerSampleGrad(
F,
false);
1436 case Intrinsic::dx_resource_samplegrad_clamp:
1437 HasErrors |= lowerSampleGrad(
F,
true);
1439 case Intrinsic::dx_resource_store_typedbuffer:
1440 HasErrors |= lowerBufferStore(
F,
false);
1442 case Intrinsic::dx_resource_store_texture:
1443 HasErrors |= lowerTextureStore(
F);
1445 case Intrinsic::dx_resource_load_rawbuffer:
1446 HasErrors |= lowerRawBufferLoad(
F);
1448 case Intrinsic::dx_resource_store_rawbuffer:
1449 HasErrors |= lowerBufferStore(
F,
true);
1451 case Intrinsic::dx_resource_load_cbufferrow_2:
1452 case Intrinsic::dx_resource_load_cbufferrow_4:
1453 case Intrinsic::dx_resource_load_cbufferrow_8:
1454 HasErrors |= lowerCBufferLoad(
F);
1456 case Intrinsic::dx_resource_updatecounter:
1457 HasErrors |= lowerUpdateCounter(
F);
1459 case Intrinsic::dx_resource_atomic_binop:
1460 HasErrors |= lowerResourceAtomicBinOp(
F);
1462 case Intrinsic::dx_resource_atomic_compare_exchange:
1463 HasErrors |= lowerResourceAtomicCompareExchange(
F);
1465 case Intrinsic::dx_resource_getdimensions_x:
1466 HasErrors |= lowerGetDimensionsX(
F);
1468 case Intrinsic::ctpop:
1469 HasErrors |= lowerCtpopToCountBits(
F);
1471 case Intrinsic::lifetime_start:
1472 case Intrinsic::lifetime_end:
1474 F.eraseFromParent();
1476 if (MMDI.DXILVersion < VersionTuple(1, 6))
1477 HasErrors |= lowerLifetimeIntrinsic(
F);
1482 case Intrinsic::is_fpclass:
1483 HasErrors |= lowerIsFPClass(
F);
1488 if (Updated && !HasErrors) {
1489 cleanupHandleCasts();
1490 cleanupNonUniformResourceIndexCalls();
1503 const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1515class DXILOpLoweringLegacy :
public ModulePass {
1517 bool runOnModule(
Module &M)
override {
1519 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
1521 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1523 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
1525 return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1527 StringRef getPassName()
const override {
return "DXIL Op Lowering"; }
1528 DXILOpLoweringLegacy() : ModulePass(
ID) {}
1531 void getAnalysisUsage(llvm::AnalysisUsage &AU)
const override {
1534 AU.
addRequired<DXILMetadataAnalysisWrapperPass>();
1541char DXILOpLoweringLegacy::ID = 0;
1552 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...
static GetElementPtrInst * CreateInBounds(Type *PointeeType, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
Create an "inbounds" getelementptr.
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="")
BasicBlock::iterator GetInsertPoint() const
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
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)
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
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.
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.