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 lowerBarrierByMemoryHandle(
Function &
F) {
957 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
960 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
963 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
964 OpCode::BarrierByMemoryHandle, {Handle, SemanticFlags});
973 [[nodiscard]]
bool lowerGetDimensionsX(
Function &
F) {
977 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
980 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
983 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
984 OpCode::GetDimensions, {Handle,
Undef}, CI->
getName(), Int32Ty);
995 [[nodiscard]]
bool lowerGetPointer(
Function &
F) {
998 assert(
F.user_empty() &&
"getpointer operations should have been removed");
1010 bool FillWithUndef) {
1011 std::array<Value *, 4> DataElements{
nullptr,
nullptr,
nullptr,
nullptr};
1012 extractElementsIntoArgs(IRB, DataElements, 0,
Data, 4);
1018 if (DataElements[
I] ==
nullptr)
1023 return DataElements;
1028 static void eraseDeadInsertElementChain(
Value *
Data) {
1031 InsertElementInst *Tmp = IEI;
1037 [[nodiscard]]
bool lowerBufferStore(
Function &
F,
bool IsRaw) {
1038 const DataLayout &
DL =
F.getDataLayout();
1043 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1047 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1063 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1064 Value *
Mask = ConstantInt::get(Int8Ty, IsRaw ? ~(~0U << NumElements)
1068 if (NumElements > 4)
1070 "Buffer store data must have at most 4 elements",
1073 std::array<Value *, 4> DataElements =
1074 splitStoreData(IRB,
Data, NumElements, IsRaw);
1078 Handle, Index0, Index1, DataElements[0],
1079 DataElements[1], DataElements[2], DataElements[3],
Mask};
1080 if (IsRaw && MMDI.DXILVersion >= VersionTuple(1, 2)) {
1081 Op = OpCode::RawBufferStore;
1084 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value()));
1086 Expected<CallInst *> OpCall =
1087 OpBuilder.tryCreateOp(
Op, Args, CI->
getName());
1092 eraseDeadInsertElementChain(
Data);
1110 for (
const WeakTrackingVH &VH : Vectors)
1112 eraseDeadInsertElementChain(V);
1115 [[nodiscard]]
bool lowerTextureStore(
Function &
F) {
1116 const DataLayout &
DL =
F.getDataLayout();
1121 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1126 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1133 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1134 if (NumElements > 4)
1136 "Texture store data must have at most 4 elements",
1140 std::array<Value *, 4> DataElements =
1141 splitStoreData(IRB,
Data, NumElements,
false);
1144 std::array<Value *, 9>
Args{
1146 Undef, DataElements[0], DataElements[1],
1147 DataElements[2], DataElements[3],
Mask};
1150 extractElementsIntoArgs(IRB, Args, 1, Coords, 3);
1152 Expected<CallInst *> OpCall =
1153 OpBuilder.tryCreateOp(OpCode::TextureStore, Args, CI->
getName());
1158 eraseDeadInsertElementChains(VectorArgs);
1164 [[nodiscard]]
bool lowerResourceAtomicBinOp(
Function &
F) {
1167 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1173 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1180 std::array<Value *, 6>
Args{Handle, BinOp, Coord0,
1181 Coord1, Coord2, NewValue};
1182 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1187 std::string Message(
toString(std::move(
E)));
1201 [[nodiscard]]
bool lowerResourceAtomicCompareExchange(
Function &
F) {
1204 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1210 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1217 std::array<Value *, 6>
Args{Handle, Coord0, Coord1,
1218 Coord2, CompareValue, NewValue};
1219 Expected<CallInst *> OpCall =
1220 OpBuilder.tryCreateOp(dxil::OpCode::AtomicCompareExchange, Args,
1225 std::string Message(
toString(std::move(
E)));
1239 [[nodiscard]]
bool lowerCtpopToCountBits(
Function &
F) {
1243 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1248 Type *RetTy = Int32Ty;
1249 Type *FRT =
F.getReturnType();
1251 RetTy = VectorType::get(RetTy, VT);
1253 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1254 dxil::OpCode::CountBits, Args, CI->
getName(), RetTy);
1268 CastOp = Instruction::ZExt;
1269 CastOp2 = Instruction::SExt;
1272 "Currently only lowering 16, 32, or 64 bit ctpop to CountBits \
1274 CastOp = Instruction::Trunc;
1275 CastOp2 = Instruction::Trunc;
1280 bool NeedsCast =
false;
1283 if (
I && (
I->getOpcode() == CastOp ||
I->getOpcode() == CastOp2) &&
1284 I->getType() == RetTy) {
1285 I->replaceAllUsesWith(*OpCall);
1286 I->eraseFromParent();
1306 [[nodiscard]]
bool lowerLifetimeIntrinsic(
Function &
F) {
1308 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1312 "Expected operand of lifetime intrinsic to be a pointer");
1314 auto ZeroOrUndef = [&](
Type *Ty) {
1315 return MMDI.ValidatorVersion < VersionTuple(1, 6)
1317 : UndefValue::
get(Ty);
1320 Value *Val =
nullptr;
1322 if (GV->hasInitializer() || GV->isExternallyInitialized())
1324 Val = ZeroOrUndef(GV->getValueType());
1326 Val = ZeroOrUndef(AI->getAllocatedType());
1328 assert(Val &&
"Expected operand of lifetime intrinsic to be a global "
1329 "variable or alloca instruction");
1337 [[nodiscard]]
bool lowerIsFPClass(
Function &
F) {
1341 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1350 switch (TCI->getZExtValue()) {
1351 case FPClassTest::fcInf:
1352 OpCode = dxil::OpCode::IsInf;
1354 case FPClassTest::fcNan:
1355 OpCode = dxil::OpCode::IsNaN;
1357 case FPClassTest::fcNormal:
1358 OpCode = dxil::OpCode::IsNormal;
1360 case FPClassTest::fcFinite:
1361 OpCode = dxil::OpCode::IsFinite;
1364 SmallString<128>
Msg =
1365 formatv(
"Unsupported FPClassTest {0} for DXIL Op Lowering",
1366 TCI->getZExtValue());
1370 Expected<CallInst *> OpCall =
1381 bool lowerIntrinsics() {
1382 bool Updated =
false;
1383 bool HasErrors =
false;
1386 if (!
F.isDeclaration())
1392 case Intrinsic::dx_resource_casthandle:
1394 case Intrinsic::dbg_value:
1397 F.eraseFromParent();
1401 F.eraseFromParent();
1404 "Unsupported intrinsic {0} for DXIL lowering",
F.getName());
1405 M.getContext().emitError(
Msg);
1410#define DXIL_OP_INTRINSIC(OpCode, Intrin, ...) \
1412 HasErrors |= replaceFunctionWithOp( \
1413 F, OpCode, ArrayRef<IntrinArgSelect>{__VA_ARGS__}); \
1415#include "DXILOperation.inc"
1416 case Intrinsic::dx_resource_handlefrombinding:
1417 HasErrors |= lowerHandleFromBinding(
F);
1419 case Intrinsic::dx_resource_handlefromheap:
1420 HasErrors |= lowerHandleFromHeap(
F);
1422 case Intrinsic::dx_resource_getbasepointer:
1423 case Intrinsic::dx_resource_getpointer:
1424 HasErrors |= lowerGetPointer(
F);
1426 case Intrinsic::dx_resource_nonuniformindex:
1428 "overloaded llvm.dx.resource.nonuniformindex intrinsics?");
1431 case Intrinsic::dx_resource_load_typedbuffer:
1432 HasErrors |= lowerTypedBufferLoad(
F,
true);
1434 case Intrinsic::dx_resource_load_level:
1435 HasErrors |= lowerTextureLoad(
F);
1437 case Intrinsic::dx_resource_sample:
1438 HasErrors |= lowerSample(
F,
false);
1440 case Intrinsic::dx_resource_sample_clamp:
1441 HasErrors |= lowerSample(
F,
true);
1443 case Intrinsic::dx_resource_samplebias:
1444 HasErrors |= lowerSampleBias(
F,
false);
1446 case Intrinsic::dx_resource_samplebias_clamp:
1447 HasErrors |= lowerSampleBias(
F,
true);
1449 case Intrinsic::dx_resource_samplelevel:
1450 HasErrors |= lowerSampleLevel(
F);
1452 case Intrinsic::dx_resource_samplegrad:
1453 HasErrors |= lowerSampleGrad(
F,
false);
1455 case Intrinsic::dx_resource_samplegrad_clamp:
1456 HasErrors |= lowerSampleGrad(
F,
true);
1458 case Intrinsic::dx_resource_store_typedbuffer:
1459 HasErrors |= lowerBufferStore(
F,
false);
1461 case Intrinsic::dx_resource_store_texture:
1462 HasErrors |= lowerTextureStore(
F);
1464 case Intrinsic::dx_resource_load_rawbuffer:
1465 HasErrors |= lowerRawBufferLoad(
F);
1467 case Intrinsic::dx_resource_store_rawbuffer:
1468 HasErrors |= lowerBufferStore(
F,
true);
1470 case Intrinsic::dx_resource_load_cbufferrow_2:
1471 case Intrinsic::dx_resource_load_cbufferrow_4:
1472 case Intrinsic::dx_resource_load_cbufferrow_8:
1473 HasErrors |= lowerCBufferLoad(
F);
1475 case Intrinsic::dx_resource_updatecounter:
1476 HasErrors |= lowerUpdateCounter(
F);
1478 case Intrinsic::dx_barrier_by_memory_handle:
1479 HasErrors |= lowerBarrierByMemoryHandle(
F);
1481 case Intrinsic::dx_resource_atomic_binop:
1482 HasErrors |= lowerResourceAtomicBinOp(
F);
1484 case Intrinsic::dx_resource_atomic_compare_exchange:
1485 HasErrors |= lowerResourceAtomicCompareExchange(
F);
1487 case Intrinsic::dx_resource_getdimensions_x:
1488 HasErrors |= lowerGetDimensionsX(
F);
1490 case Intrinsic::ctpop:
1491 HasErrors |= lowerCtpopToCountBits(
F);
1493 case Intrinsic::lifetime_start:
1494 case Intrinsic::lifetime_end:
1496 F.eraseFromParent();
1498 if (MMDI.DXILVersion < VersionTuple(1, 6))
1499 HasErrors |= lowerLifetimeIntrinsic(
F);
1504 case Intrinsic::is_fpclass:
1505 HasErrors |= lowerIsFPClass(
F);
1510 if (Updated && !HasErrors) {
1511 cleanupHandleCasts();
1512 cleanupNonUniformResourceIndexCalls();
1525 const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1537class DXILOpLoweringLegacy :
public ModulePass {
1539 bool runOnModule(
Module &M)
override {
1541 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
1543 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1545 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
1547 return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1549 StringRef getPassName()
const override {
return "DXIL Op Lowering"; }
1550 DXILOpLoweringLegacy() : ModulePass(
ID) {}
1553 void getAnalysisUsage(llvm::AnalysisUsage &AU)
const override {
1556 AU.
addRequired<DXILMetadataAnalysisWrapperPass>();
1563char DXILOpLoweringLegacy::ID = 0;
1574 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.