25#include "llvm/IR/IntrinsicsDirectX.h"
34#define DEBUG_TYPE "dxil-op-lower"
58 : M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM), MMDI(MMDI) {}
70 if (
Error E = ReplaceCall(CI)) {
71 std::string Message(
toString(std::move(
E)));
83 struct IntrinArgSelect {
85#define DXIL_OP_INTRINSIC_ARG_SELECT_TYPE(name) name,
86#include "DXILOperation.inc"
96 Error replaceNamedStructUses(CallInst *Intrin, CallInst *DXILOp) {
99 if (!IntrinTy->isLayoutIdentical(DXILOpTy))
101 "Type mismatch between intrinsic and DXIL op",
106 EVI->setOperand(0, DXILOp);
108 IVI->setOperand(0, DXILOp);
111 "be used by insert- and extractvalue",
116 bool isFast(FastMathFlags Flags) {
120 Flags.noSignedZeros() &&
Flags.allowReciprocal() &&
124 void setDxPrecise(CallInst *CI) {
125 const StringRef
Key =
"dx.precise";
139 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
140 OpBuilder.getIRB().SetInsertPoint(CI);
142 if (ArgSelects.
size()) {
143 for (
const IntrinArgSelect &
A : ArgSelects) {
145 case IntrinArgSelect::Type::Index:
148 case IntrinArgSelect::Type::I8:
149 Args.push_back(OpBuilder.getIRB().getInt8((uint8_t)
A.Value));
151 case IntrinArgSelect::Type::I32:
152 Args.push_back(OpBuilder.getIRB().getInt32(
A.Value));
160 Expected<CallInst *> OpCall =
161 OpBuilder.tryCreateOp(DXILOp, Args, CI->
getName(),
F.getReturnType());
167 setDxPrecise(*OpCall);
170 if (
Error E = replaceNamedStructUses(CI, *OpCall))
186 CallInst *Cast = OpBuilder.getIRB().CreateIntrinsicWithoutFolding(
187 Intrinsic::dx_resource_casthandle, {Ty,
V->getType()}, {
V});
188 CleanupCasts.push_back(Cast);
192 void cleanupHandleCasts() {
196 for (CallInst *Cast : CleanupCasts) {
205 if (Cast->
getType() != OpBuilder.getHandleType()) {
212 assert(
Def->getIntrinsicID() == Intrinsic::dx_resource_casthandle &&
213 "Unbalanced pair of temporary handle casts");
225 for (Function *
F : CastFns)
226 F->eraseFromParent();
228 CleanupCasts.clear();
231 void cleanupNonUniformResourceIndexCalls() {
242 CleanupNURI->eraseFromParent();
243 CleanupNURI =
nullptr;
251 void removeResourceGlobals(CallInst *CI) {
255 Store->eraseFromParent();
257 if (GV->use_empty()) {
258 GV->removeDeadConstantUsers();
259 GV->eraseFromParent();
265 void replaceHandleFromBindingCall(CallInst *CI,
Value *Replacement) {
267 Intrinsic::dx_resource_handlefrombinding);
269 removeResourceGlobals(CI);
276 if (NameGlobal && NameGlobal->use_empty())
277 NameGlobal->removeFromParent();
280 bool hasNonUniformIndex(
Value *IndexOp) {
284 SmallVector<Value *, 16> Worklist;
285 SmallPtrSet<Value *, 16> Visited;
288 while (!Worklist.
empty()) {
294 if (!Visited.
insert(V).second)
298 if (CI->
getIntrinsicID() == Intrinsic::dx_resource_nonuniformindex)
304 for (
Value *Incoming :
Phi->incoming_values())
310 if (Inst->getNumOperands() > 0 && !Inst->isTerminator())
311 for (
Value *
Op : Inst->operands())
317 Error validateRawBufferElementIndex(
Value *Resource,
Value *ElementIndex) {
322 if (IsStructured && IsPoison)
324 "Element index of structured buffer may not be poison",
327 if (!IsStructured && !IsPoison)
329 "Element index of raw buffer must be poison",
335 [[nodiscard]]
bool lowerToCreateHandle(Function &
F) {
341 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
344 auto *It = DRM.find(CI);
345 assert(It != DRM.end() &&
"Resource not in map?");
346 dxil::ResourceInfo &RI = *It;
354 ConstantInt::get(Int32Ty,
Binding.LowerBound));
356 bool HasNonUniformIndex =
357 (
Binding.Size == 1) ?
false : hasNonUniformIndex(IndexOp);
358 std::array<Value *, 4>
Args{
360 ConstantInt::get(Int32Ty,
Binding.RecordID), IndexOp,
361 ConstantInt::get(Int1Ty, HasNonUniformIndex)};
362 Expected<CallInst *> OpCall =
363 OpBuilder.tryCreateOp(OpCode::CreateHandle, Args, CI->
getName());
367 Value *Cast = createTmpHandleCast(*OpCall, CI->
getType());
368 replaceHandleFromBindingCall(CI, Cast);
373 [[nodiscard]]
bool lowerToBindAndAnnotateHandle(Function &
F) {
378 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
381 auto *It = DRM.find(CI);
382 assert(It != DRM.end() &&
"Resource not in map?");
383 dxil::ResourceInfo &RI = *It;
386 dxil::ResourceTypeInfo &RTI = DRTM[RI.
getHandleTy()];
392 ConstantInt::get(Int32Ty,
Binding.LowerBound));
394 std::pair<uint32_t, uint32_t> Props =
399 uint32_t UpperBound =
Binding.Size == 0
400 ? std::numeric_limits<uint32_t>::max()
402 Constant *ResBind = OpBuilder.getResBind(
Binding.LowerBound, UpperBound,
404 bool NonUniformIndex =
405 (
Binding.Size == 1) ?
false : hasNonUniformIndex(IndexOp);
406 Constant *NonUniformOp = ConstantInt::get(Int1Ty, NonUniformIndex);
407 std::array<Value *, 3> BindArgs{ResBind, IndexOp, NonUniformOp};
408 Expected<CallInst *> OpBind = OpBuilder.tryCreateOp(
409 OpCode::CreateHandleFromBinding, BindArgs, CI->
getName());
413 std::array<Value *, 2> AnnotateArgs{
414 *OpBind, OpBuilder.getResProps(Props.first, Props.second)};
415 Expected<CallInst *> OpAnnotate = OpBuilder.tryCreateOp(
416 OpCode::AnnotateHandle, AnnotateArgs,
421 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->
getType());
422 replaceHandleFromBindingCall(CI, Cast);
430 bool lowerHandleFromBinding(Function &
F) {
431 if (MMDI.DXILVersion < VersionTuple(1, 6))
432 return lowerToCreateHandle(
F);
433 return lowerToBindAndAnnotateHandle(
F);
438 Error replaceResRetUses(CallInst *Intrin, CallInst *
Op,
bool HasCheckBit) {
447 Value *CheckOp =
nullptr;
451 ArrayRef<unsigned> Indices = EVI->getIndices();
458 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
459 OpCode::CheckAccessFullyMapped, {NewEVI},
467 EVI->replaceAllUsesWith(CheckOp);
468 EVI->eraseFromParent();
480 "Expected only use to be extract of first element");
482 OldTy =
ST->getElementType(0);
490 if (OldResult != Intrin) {
497 std::array<Value *, 4> Extracts = {};
505 size_t IndexVal = IndexOp->getZExtValue();
506 assert(IndexVal < 4 &&
"Index into buffer load out of range");
507 if (!Extracts[IndexVal])
510 EEI->eraseFromParent();
518 const unsigned N = VecTy->getNumElements();
522 if (!DynamicAccesses.
empty()) {
526 Type *ElTy = VecTy->getElementType();
527 Type *ArrayTy = ArrayType::get(ElTy,
N);
530 for (
int I = 0,
E =
N;
I !=
E; ++
I) {
534 ArrayTy, Alloca, {
Zero, ConstantInt::get(Int32Ty,
I)});
538 for (ExtractElementInst *EEI : DynamicAccesses) {
540 {
Zero, EEI->getIndexOperand()});
543 EEI->eraseFromParent();
551 for (
int I = 0,
E =
N;
I !=
E; ++
I)
556 for (
int I = 0,
E =
N;
I !=
E; ++
I)
562 if (OldResult != Intrin) {
570 [[nodiscard]]
bool lowerTypedBufferLoad(Function &
F,
bool HasCheckBit) {
574 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
578 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
587 std::array<Value *, 3>
Args{Handle, Index0, Index1};
588 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
589 OpCode::BufferLoad, Args, CI->
getName(), NewRetTy);
592 if (
Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
602 static void extractElementsIntoArgs(
IRBuilder<> &IRB,
604 unsigned ArgIdx,
Value *Src,
605 unsigned MaxElements) {
606 Type *Ty = Src->getType();
608 unsigned Count = VecTy->getNumElements();
609 assert(
Count <= MaxElements &&
"Expected at most 3 elements in vector");
610 for (
unsigned I = 0;
I <
Count; ++
I)
619 static void extractNonZeroOffsets(
IRBuilder<> &IRB,
621 unsigned ArgIdx,
Value *Offsets,
622 unsigned MaxElements) {
624 bool OffsetsAreZero = COff && COff->isNullValue();
626 extractElementsIntoArgs(IRB, Args, ArgIdx, Offsets, MaxElements);
629 [[nodiscard]]
bool lowerTextureLoad(Function &
F) {
633 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
637 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
646 dxil::ResourceTypeInfo &RTI = DRTM[HandleTy];
648 if (RTI.
isUAV() && Kind != dxil::ResourceKind::Texture2DMS &&
649 Kind != dxil::ResourceKind::Texture2DMSArray)
660 extractElementsIntoArgs(IRB, Args, 2, Coords, 3);
661 extractNonZeroOffsets(IRB, Args, 5, Offsets, 3);
663 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
664 OpCode::TextureLoad, Args, CI->
getName(), NewRetTy);
667 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
677 [[nodiscard]]
bool lowerSampleOp(
678 Function &
F,
OpCode Op,
unsigned CoordsIdx,
unsigned OffsetsIdx,
680 SmallVectorImpl<Value *> &)> EmitExtraArgs) {
682 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
686 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
688 createTmpHandleCast(CI->
getArgOperand(1), OpBuilder.getHandleType());
699 UndefF, UndefI, UndefI, UndefI};
702 extractElementsIntoArgs(IRB, Args, 2, Coords, 4);
703 extractNonZeroOffsets(IRB, Args, 6, Offsets, 3);
706 EmitExtraArgs(IRB, CI, Args);
708 Expected<CallInst *> OpCall =
709 OpBuilder.tryCreateOp(
Op, Args, CI->
getName(), NewRetTy);
712 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
719 [[nodiscard]]
bool lowerSample(Function &
F,
bool HasClamp) {
720 return lowerSampleOp(
F, OpCode::Sample, 2, 3,
722 SmallVectorImpl<Value *> &Args) {
730 [[nodiscard]]
bool lowerSampleBias(Function &
F,
bool HasClamp) {
731 return lowerSampleOp(
732 F, OpCode::SampleBias, 2, 4,
734 SmallVectorImpl<Value *> &Args) {
743 [[nodiscard]]
bool lowerSampleLevel(Function &
F) {
744 return lowerSampleOp(
745 F, OpCode::SampleLevel, 2, 4,
746 [](
IRBuilder<> &, CallInst *CI, SmallVectorImpl<Value *> &Args) {
752 [[nodiscard]]
bool lowerSampleGrad(Function &
F,
bool HasClamp) {
753 return lowerSampleOp(
754 F, OpCode::SampleGrad, 2, 5,
756 SmallVectorImpl<Value *> &Args) {
761 size_t DDXStart =
Args.size();
762 Args.append(3, UndefF);
763 extractElementsIntoArgs(IRB, Args, DDXStart, DDX, 3);
765 size_t DDYStart =
Args.size();
766 Args.append(3, UndefF);
767 extractElementsIntoArgs(IRB, Args, DDYStart, DDY, 3);
773 [[nodiscard]]
bool lowerRawBufferLoad(Function &
F) {
774 const DataLayout &
DL =
F.getDataLayout();
779 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
784 Type *NewRetTy = OpBuilder.getResRetType(ScalarTy);
787 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
790 uint64_t NumElements =
791 DL.getTypeSizeInBits(OldTy) /
DL.getTypeSizeInBits(ScalarTy);
792 Value *
Mask = ConstantInt::get(Int8Ty, ~(~0U << NumElements));
794 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value());
801 Expected<CallInst *> OpCall =
802 MMDI.DXILVersion >= VersionTuple(1, 2)
803 ? OpBuilder.tryCreateOp(OpCode::RawBufferLoad,
806 : OpBuilder.tryCreateOp(OpCode::BufferLoad,
807 {Handle, Index0, Index1}, CI->
getName(),
811 if (
Error E = replaceResRetUses(CI, *OpCall,
true))
818 [[nodiscard]]
bool lowerCBufferLoad(Function &
F) {
821 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
826 Type *NewRetTy = OpBuilder.getCBufRetType(ScalarTy);
829 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
832 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
833 OpCode::CBufferLoadLegacy, {Handle,
Index}, CI->
getName(), NewRetTy);
836 if (
Error E = replaceNamedStructUses(CI, *OpCall))
844 [[nodiscard]]
bool lowerUpdateCounter(Function &
F) {
848 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
851 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
854 std::array<Value *, 2>
Args{Handle, Op1};
856 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
857 OpCode::UpdateCounter, Args, CI->
getName(), Int32Ty);
868 [[nodiscard]]
bool lowerGetDimensionsX(Function &
F) {
872 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
875 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
878 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
879 OpCode::GetDimensions, {Handle,
Undef}, CI->
getName(), Int32Ty);
890 [[nodiscard]]
bool lowerGetPointer(Function &
F) {
893 assert(
F.user_empty() &&
"getpointer operations should have been removed");
904 uint64_t NumElements,
905 bool FillWithUndef) {
909 std::array<Value *, 4> DataElements{
nullptr,
nullptr,
nullptr,
nullptr};
910 if (DataTy == ScalarTy)
911 DataElements[0] =
Data;
921 size_t IndexVal = IndexOp->getZExtValue();
922 assert(IndexVal < 4 &&
"Too many elements for resource store");
923 DataElements[IndexVal] = IEI->getOperand(1);
931 for (uint64_t
I = 0,
E = NumElements;
I <
E; ++
I)
932 if (DataElements[
I] ==
nullptr)
939 for (uint64_t
I = NumElements,
E = 4;
I <
E; ++
I)
940 if (DataElements[
I] ==
nullptr)
949 static void eraseDeadInsertElementChain(
Value *
Data) {
951 while (IEI && IEI->use_empty()) {
952 InsertElementInst *Tmp = IEI;
958 [[nodiscard]]
bool lowerBufferStore(Function &
F,
bool IsRaw) {
959 const DataLayout &
DL =
F.getDataLayout();
964 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
968 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
983 uint64_t NumElements =
984 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
985 Value *
Mask = ConstantInt::get(Int8Ty, IsRaw ? ~(~0U << NumElements)
991 "Buffer store data must have at most 4 elements",
994 std::array<Value *, 4> DataElements =
995 splitStoreData(IRB,
Data, NumElements, IsRaw);
999 Handle, Index0, Index1, DataElements[0],
1000 DataElements[1], DataElements[2], DataElements[3],
Mask};
1001 if (IsRaw && MMDI.DXILVersion >= VersionTuple(1, 2)) {
1002 Op = OpCode::RawBufferStore;
1005 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value()));
1007 Expected<CallInst *> OpCall =
1008 OpBuilder.tryCreateOp(
Op, Args, CI->
getName());
1013 eraseDeadInsertElementChain(
Data);
1019 [[nodiscard]]
bool lowerTextureStore(Function &
F) {
1020 const DataLayout &
DL =
F.getDataLayout();
1025 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1029 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1035 uint64_t NumElements =
1036 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1037 if (NumElements > 4)
1039 "Texture store data must have at most 4 elements",
1043 std::array<Value *, 4> DataElements =
1044 splitStoreData(IRB,
Data, NumElements,
false);
1047 std::array<Value *, 9>
Args{
1049 Undef, DataElements[0], DataElements[1],
1050 DataElements[2], DataElements[3],
Mask};
1053 extractElementsIntoArgs(IRB, Args, 1, Coords, 3);
1055 Expected<CallInst *> OpCall =
1056 OpBuilder.tryCreateOp(OpCode::TextureStore, Args, CI->
getName());
1061 eraseDeadInsertElementChain(
Data);
1067 [[nodiscard]]
bool lowerResourceAtomicBinOp(Function &
F) {
1070 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1076 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1082 std::array<Value *, 6>
Args{
1083 Handle, BinOp, Coord0, Coord1, ConstantInt::get(IRB.
getInt32Ty(), 0),
1085 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1090 std::string Message(
toString(std::move(
E)));
1104 [[nodiscard]]
bool lowerCtpopToCountBits(Function &
F) {
1108 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1113 Type *RetTy = Int32Ty;
1114 Type *FRT =
F.getReturnType();
1116 RetTy = VectorType::get(RetTy, VT);
1118 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1119 dxil::OpCode::CountBits, Args, CI->
getName(), RetTy);
1133 CastOp = Instruction::ZExt;
1134 CastOp2 = Instruction::SExt;
1137 "Currently only lowering 16, 32, or 64 bit ctpop to CountBits \
1139 CastOp = Instruction::Trunc;
1140 CastOp2 = Instruction::Trunc;
1145 bool NeedsCast =
false;
1148 if (
I && (
I->getOpcode() == CastOp ||
I->getOpcode() == CastOp2) &&
1149 I->getType() == RetTy) {
1150 I->replaceAllUsesWith(*OpCall);
1151 I->eraseFromParent();
1171 [[nodiscard]]
bool lowerLifetimeIntrinsic(Function &
F) {
1173 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1177 "Expected operand of lifetime intrinsic to be a pointer");
1179 auto ZeroOrUndef = [&](
Type *Ty) {
1180 return MMDI.ValidatorVersion < VersionTuple(1, 6)
1182 : UndefValue::
get(Ty);
1185 Value *Val =
nullptr;
1187 if (GV->hasInitializer() || GV->isExternallyInitialized())
1189 Val = ZeroOrUndef(GV->getValueType());
1191 Val = ZeroOrUndef(AI->getAllocatedType());
1193 assert(Val &&
"Expected operand of lifetime intrinsic to be a global "
1194 "variable or alloca instruction");
1202 [[nodiscard]]
bool lowerIsFPClass(Function &
F) {
1206 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1215 switch (TCI->getZExtValue()) {
1216 case FPClassTest::fcInf:
1217 OpCode = dxil::OpCode::IsInf;
1219 case FPClassTest::fcNan:
1220 OpCode = dxil::OpCode::IsNaN;
1222 case FPClassTest::fcNormal:
1223 OpCode = dxil::OpCode::IsNormal;
1225 case FPClassTest::fcFinite:
1226 OpCode = dxil::OpCode::IsFinite;
1229 SmallString<128>
Msg =
1230 formatv(
"Unsupported FPClassTest {0} for DXIL Op Lowering",
1231 TCI->getZExtValue());
1235 Expected<CallInst *> OpCall =
1246 bool lowerIntrinsics() {
1247 bool Updated =
false;
1248 bool HasErrors =
false;
1251 if (!
F.isDeclaration())
1257 case Intrinsic::dx_resource_casthandle:
1259 case Intrinsic::dbg_value:
1262 F.eraseFromParent();
1266 F.eraseFromParent();
1269 "Unsupported intrinsic {0} for DXIL lowering",
F.getName());
1270 M.getContext().emitError(
Msg);
1275#define DXIL_OP_INTRINSIC(OpCode, Intrin, ...) \
1277 HasErrors |= replaceFunctionWithOp( \
1278 F, OpCode, ArrayRef<IntrinArgSelect>{__VA_ARGS__}); \
1280#include "DXILOperation.inc"
1281 case Intrinsic::dx_resource_handlefrombinding:
1282 HasErrors |= lowerHandleFromBinding(
F);
1284 case Intrinsic::dx_resource_getbasepointer:
1285 case Intrinsic::dx_resource_getpointer:
1286 HasErrors |= lowerGetPointer(
F);
1288 case Intrinsic::dx_resource_nonuniformindex:
1290 "overloaded llvm.dx.resource.nonuniformindex intrinsics?");
1293 case Intrinsic::dx_resource_load_typedbuffer:
1294 HasErrors |= lowerTypedBufferLoad(
F,
true);
1296 case Intrinsic::dx_resource_load_level:
1297 HasErrors |= lowerTextureLoad(
F);
1299 case Intrinsic::dx_resource_sample:
1300 HasErrors |= lowerSample(
F,
false);
1302 case Intrinsic::dx_resource_sample_clamp:
1303 HasErrors |= lowerSample(
F,
true);
1305 case Intrinsic::dx_resource_samplebias:
1306 HasErrors |= lowerSampleBias(
F,
false);
1308 case Intrinsic::dx_resource_samplebias_clamp:
1309 HasErrors |= lowerSampleBias(
F,
true);
1311 case Intrinsic::dx_resource_samplelevel:
1312 HasErrors |= lowerSampleLevel(
F);
1314 case Intrinsic::dx_resource_samplegrad:
1315 HasErrors |= lowerSampleGrad(
F,
false);
1317 case Intrinsic::dx_resource_samplegrad_clamp:
1318 HasErrors |= lowerSampleGrad(
F,
true);
1320 case Intrinsic::dx_resource_store_typedbuffer:
1321 HasErrors |= lowerBufferStore(
F,
false);
1323 case Intrinsic::dx_resource_store_texture:
1324 HasErrors |= lowerTextureStore(
F);
1326 case Intrinsic::dx_resource_load_rawbuffer:
1327 HasErrors |= lowerRawBufferLoad(
F);
1329 case Intrinsic::dx_resource_store_rawbuffer:
1330 HasErrors |= lowerBufferStore(
F,
true);
1332 case Intrinsic::dx_resource_load_cbufferrow_2:
1333 case Intrinsic::dx_resource_load_cbufferrow_4:
1334 case Intrinsic::dx_resource_load_cbufferrow_8:
1335 HasErrors |= lowerCBufferLoad(
F);
1337 case Intrinsic::dx_resource_updatecounter:
1338 HasErrors |= lowerUpdateCounter(
F);
1340 case Intrinsic::dx_resource_atomic_binop:
1341 HasErrors |= lowerResourceAtomicBinOp(
F);
1343 case Intrinsic::dx_resource_getdimensions_x:
1344 HasErrors |= lowerGetDimensionsX(
F);
1346 case Intrinsic::ctpop:
1347 HasErrors |= lowerCtpopToCountBits(
F);
1349 case Intrinsic::lifetime_start:
1350 case Intrinsic::lifetime_end:
1352 F.eraseFromParent();
1354 if (MMDI.DXILVersion < VersionTuple(1, 6))
1355 HasErrors |= lowerLifetimeIntrinsic(
F);
1360 case Intrinsic::is_fpclass:
1361 HasErrors |= lowerIsFPClass(
F);
1366 if (Updated && !HasErrors) {
1367 cleanupHandleCasts();
1368 cleanupNonUniformResourceIndexCalls();
1381 const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1393class DXILOpLoweringLegacy :
public ModulePass {
1395 bool runOnModule(
Module &M)
override {
1397 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
1399 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1401 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
1403 return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1405 StringRef getPassName()
const override {
return "DXIL Op Lowering"; }
1406 DXILOpLoweringLegacy() : ModulePass(
ID) {}
1409 void getAnalysisUsage(llvm::AnalysisUsage &AU)
const override {
1412 AU.
addRequired<DXILMetadataAnalysisWrapperPass>();
1419char DXILOpLoweringLegacy::ID = 0;
1430 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.
Machine Check Debug Module
ModuleAnalysisManager MAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
static unsigned getFastMathFlags(const MachineInstr &I, const SPIRVSubtarget &ST)
This file defines the SmallVector class.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
size_t size() const
Get the array size.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
User::op_iterator arg_begin()
Return the iterator pointing to the beginning of the argument list.
Value * getArgOperand(unsigned i) const
User::op_iterator arg_end()
Return the iterator pointing to the end of the argument list.
LLVM_ABI Intrinsic::ID getIntrinsicID() const
Returns the intrinsic ID of the intrinsic called or Intrinsic::not_intrinsic if the called function i...
This class represents a function call, abstracting a target machine's calling convention.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM)
Diagnostic information for unsupported feature in backend.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Error takeError()
Take ownership of the stored error.
Intrinsic::ID getIntrinsicID() const LLVM_READONLY
getIntrinsicID - This method returns the ID number of the specified function, or Intrinsic::not_intri...
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
AllocaInst * CreateAlloca(Type *Ty, unsigned AddrSpace, Value *ArraySize=nullptr, const Twine &Name="")
IntegerType * getInt1Ty()
Fetch the type representing a single bit.
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Value * CreateZExtOrTrunc(Value *V, Type *DestTy, const Twine &Name="")
Create a ZExt or Trunc from the integer value V to DestTy.
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Value * CreateInBoundsGEP(Type *Ty, Value *Ptr, ArrayRef< Value * > IdxList, const Twine &Name="")
LoadInst * CreateLoad(Type *Ty, Value *Ptr, const char *Name)
Provided to resolve 'CreateLoad(Ty, Ptr, "...")' correctly, instead of converting the string to 'bool...
StoreInst * CreateStore(Value *Val, Value *Ptr, bool isVolatile=false)
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Type * getFloatTy()
Fetch the type representing a 32-bit floating point value.
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
IntegerType * getInt8Ty()
Fetch the type representing an 8-bit integer.
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
LLVM_ABI void diagnose(const DiagnosticInfo &DI)
Report a message to the currently installed diagnostic handler.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
LLVMContext & getContext() const
Get the global data context.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
PreservedAnalyses & preserve()
Mark an analysis as preserved.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
iterator erase(const_iterator CI)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
The instances of the Type class are immutable: once they are created, they are never changed.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isIntOrIntVectorTy() const
Return true if this is an integer type or a vector of integer types.
bool isPointerTy() const
True if this is an instance of PointerType.
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
static LLVM_ABI UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Value * getOperand(unsigned i) const
Type * getType() const
All values are typed, get the type of this value.
user_iterator user_begin()
bool hasOneUse() const
Return true if there is exactly one use of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
TargetExtType * getHandleTy() const
LLVM_ABI std::pair< uint32_t, uint32_t > getAnnotateProps(Module &M, dxil::ResourceTypeInfo &RTI) const
const ResourceBinding & getBinding() const
dxil::ResourceClass getResourceClass() const
LLVM_ABI bool isUAV() const
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.