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