26#include "llvm/IR/IntrinsicsDirectX.h"
36#define DEBUG_TYPE "dxil-op-lower"
60 : M(M), OpBuilder(M), DRM(DRM), DRTM(DRTM), MMDI(MMDI) {}
72 if (
Error E = ReplaceCall(CI)) {
73 std::string Message(
toString(std::move(
E)));
85 struct IntrinArgSelect {
87#define DXIL_OP_INTRINSIC_ARG_SELECT_TYPE(name) name,
88#include "DXILOperation.inc"
98 Error replaceNamedStructUses(CallInst *Intrin, CallInst *DXILOp) {
101 if (!IntrinTy->isLayoutIdentical(DXILOpTy))
103 "Type mismatch between intrinsic and DXIL op",
108 EVI->setOperand(0, DXILOp);
110 IVI->setOperand(0, DXILOp);
113 "be used by insert- and extractvalue",
118 bool isFast(FastMathFlags Flags) {
122 Flags.noSignedZeros() &&
Flags.allowReciprocal() &&
126 void setDxPrecise(CallInst *CI) {
127 const StringRef
Key =
"dx.precise";
141 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
142 OpBuilder.getIRB().SetInsertPoint(CI);
144 if (ArgSelects.
size()) {
145 for (
const IntrinArgSelect &
A : ArgSelects) {
147 case IntrinArgSelect::Type::Index:
150 case IntrinArgSelect::Type::I8:
151 Args.push_back(OpBuilder.getIRB().getInt8((uint8_t)
A.Value));
153 case IntrinArgSelect::Type::I32:
154 Args.push_back(OpBuilder.getIRB().getInt32(
A.Value));
162 Expected<CallInst *> OpCall =
163 OpBuilder.tryCreateOp(DXILOp, Args, CI->
getName(),
F.getReturnType());
169 setDxPrecise(*OpCall);
172 if (
Error E = replaceNamedStructUses(CI, *OpCall))
188 CallInst *Cast = OpBuilder.getIRB().CreateIntrinsicWithoutFolding(
189 Intrinsic::dx_resource_casthandle, {Ty,
V->getType()}, {
V});
190 CleanupCasts.push_back(Cast);
194 void cleanupHandleCasts() {
198 for (CallInst *Cast : CleanupCasts) {
207 if (Cast->
getType() != OpBuilder.getHandleType()) {
214 assert(
Def->getIntrinsicID() == Intrinsic::dx_resource_casthandle &&
215 "Unbalanced pair of temporary handle casts");
228 F->eraseFromParent();
230 CleanupCasts.clear();
233 void cleanupNonUniformResourceIndexCalls() {
244 CleanupNURI->eraseFromParent();
245 CleanupNURI =
nullptr;
253 void removeResourceGlobals(CallInst *CI) {
257 Store->eraseFromParent();
259 if (GV->use_empty()) {
260 GV->removeDeadConstantUsers();
261 GV->eraseFromParent();
267 void replaceHandleFromBindingCall(CallInst *CI,
Value *Replacement) {
269 Intrinsic::dx_resource_handlefrombinding);
271 removeResourceGlobals(CI);
278 if (NameGlobal && NameGlobal->use_empty())
279 NameGlobal->eraseFromParent();
282 bool hasNonUniformIndex(
Value *IndexOp) {
286 SmallVector<Value *, 16> Worklist;
287 SmallPtrSet<Value *, 16> Visited;
290 while (!Worklist.
empty()) {
296 if (!Visited.
insert(V).second)
300 if (CI->
getIntrinsicID() == Intrinsic::dx_resource_nonuniformindex)
306 for (
Value *Incoming :
Phi->incoming_values())
312 if (Inst->getNumOperands() > 0 && !Inst->isTerminator())
313 for (
Value *
Op : Inst->operands())
319 Error validateRawBufferElementIndex(
Value *Resource,
Value *ElementIndex) {
324 if (IsStructured && IsPoison)
326 "Element index of structured buffer may not be poison",
329 if (!IsStructured && !IsPoison)
331 "Element index of raw buffer must be poison",
337 [[nodiscard]]
bool lowerToCreateHandle(
Function &
F) {
343 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
346 auto *It = DRM.find(CI);
347 assert(It != DRM.end() &&
"Resource not in map?");
348 dxil::ResourceInfo &RI = *It;
356 ConstantInt::get(Int32Ty,
Binding.LowerBound));
358 bool HasNonUniformIndex =
359 (
Binding.Size == 1) ?
false : hasNonUniformIndex(IndexOp);
360 std::array<Value *, 4>
Args{
362 ConstantInt::get(Int32Ty,
Binding.BindingID), IndexOp,
363 ConstantInt::get(Int1Ty, HasNonUniformIndex)};
364 Expected<CallInst *> OpCall =
365 OpBuilder.tryCreateOp(OpCode::CreateHandle, Args, CI->
getName());
369 Value *Cast = createTmpHandleCast(*OpCall, CI->
getType());
370 replaceHandleFromBindingCall(CI, Cast);
375 [[nodiscard]]
bool lowerToBindAndAnnotateHandle(
Function &
F) {
380 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
383 auto *It = DRM.find(CI);
384 assert(It != DRM.end() &&
"Resource not in map?");
385 dxil::ResourceInfo &RI = *It;
388 dxil::ResourceTypeInfo &RTI = DRTM[RI.
getHandleTy()];
394 ConstantInt::get(Int32Ty,
Binding.LowerBound));
396 std::pair<uint32_t, uint32_t> Props =
401 uint32_t UpperBound =
Binding.Size == 0
402 ? std::numeric_limits<uint32_t>::max()
404 Constant *ResBind = OpBuilder.getResBind(
Binding.LowerBound, UpperBound,
406 bool NonUniformIndex =
407 (
Binding.Size == 1) ?
false : hasNonUniformIndex(IndexOp);
408 Constant *NonUniformOp = ConstantInt::get(Int1Ty, NonUniformIndex);
409 std::array<Value *, 3> BindArgs{ResBind, IndexOp, NonUniformOp};
410 Expected<CallInst *> OpBind = OpBuilder.tryCreateOp(
411 OpCode::CreateHandleFromBinding, BindArgs, CI->
getName());
415 std::array<Value *, 2> AnnotateArgs{
416 *OpBind, OpBuilder.getResProps(Props.first, Props.second)};
417 Expected<CallInst *> OpAnnotate = OpBuilder.tryCreateOp(
418 OpCode::AnnotateHandle, AnnotateArgs,
423 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->
getType());
424 replaceHandleFromBindingCall(CI, Cast);
432 bool lowerHandleFromBinding(
Function &
F) {
433 if (MMDI.DXILVersion < VersionTuple(1, 6))
434 return lowerToCreateHandle(
F);
435 return lowerToBindAndAnnotateHandle(
F);
441 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
444 auto *It = DRM.find(CI);
445 assert(It != DRM.end() &&
"Resource not in map?");
446 dxil::ResourceInfo &RI = *It;
447 dxil::ResourceTypeInfo &RTI = DRTM[RI.
getHandleTy()];
450 Value *IsSamplerHeap =
453 std::pair<uint32_t, uint32_t> Props =
456 bool NonUniformIndex = hasNonUniformIndex(IndexOp);
457 Value *NonUniformOp =
460 std::array<Value *, 3>
Args{IndexOp, IsSamplerHeap, NonUniformOp};
461 Expected<CallInst *> OpCreateHandle = OpBuilder.tryCreateOp(
462 OpCode::CreateHandleFromHeap, Args, CI->
getName());
466 std::array<Value *, 2> AnnotateArgs{
467 *OpCreateHandle, OpBuilder.getResProps(Props.first, Props.second)};
468 Expected<CallInst *> OpAnnotate = OpBuilder.tryCreateOp(
469 OpCode::AnnotateHandle, AnnotateArgs,
474 Value *Cast = createTmpHandleCast(*OpAnnotate, CI->
getType());
483 Error replaceResRetUses(CallInst *Intrin, CallInst *
Op,
bool HasCheckBit) {
492 Value *CheckOp =
nullptr;
496 ArrayRef<unsigned> Indices = EVI->getIndices();
503 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
504 OpCode::CheckAccessFullyMapped, {NewEVI},
512 EVI->replaceAllUsesWith(CheckOp);
513 EVI->eraseFromParent();
525 "Expected only use to be extract of first element");
527 OldTy =
ST->getElementType(0);
535 if (OldResult != Intrin) {
542 std::array<Value *, 4> Extracts = {};
550 size_t IndexVal = IndexOp->getZExtValue();
551 assert(IndexVal < 4 &&
"Index into buffer load out of range");
552 if (!Extracts[IndexVal])
555 EEI->eraseFromParent();
563 const unsigned N = VecTy->getNumElements();
567 if (!DynamicAccesses.
empty()) {
571 Type *ElTy = VecTy->getElementType();
572 Type *ArrayTy = ArrayType::get(ElTy,
N);
575 for (
int I = 0,
E =
N;
I !=
E; ++
I) {
579 ArrayTy, Alloca, {
Zero, ConstantInt::get(Int32Ty,
I)},
"",
584 for (ExtractElementInst *EEI : DynamicAccesses) {
586 ArrayTy, Alloca, {
Zero, EEI->getIndexOperand()},
"",
590 EEI->eraseFromParent();
598 for (
int I = 0,
E =
N;
I !=
E; ++
I)
603 for (
int I = 0,
E =
N;
I !=
E; ++
I)
609 if (OldResult != Intrin) {
617 [[nodiscard]]
bool lowerTypedBufferLoad(
Function &
F,
bool HasCheckBit) {
621 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
625 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
634 std::array<Value *, 3>
Args{Handle, Index0, Index1};
635 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
636 OpCode::BufferLoad, Args, CI->
getName(), NewRetTy);
639 if (
Error E = replaceResRetUses(CI, *OpCall, HasCheckBit))
649 static void collectInsertedElements(
Value *Vec,
652 assert(NumElts <=
Elements.size() &&
"Not enough room for the components");
664 while (!Chain.
empty()) {
667 if (IndexVal < NumElts)
675 static void extractElementsIntoArgs(
IRBuilder<> &IRB,
677 unsigned ArgIdx,
Value *Src,
678 unsigned MaxElements) {
685 unsigned Count = VecTy->getNumElements();
686 assert(
Count <= MaxElements &&
"Too many elements for the arg list");
689 collectInsertedElements(Src, Elements);
691 for (
unsigned I = 0;
I <
Count; ++
I)
692 Args[ArgIdx +
I] = Elements[
I]
694 : IRB.CreateExtractElement(
695 Src, ConstantInt::
get(IRB.getInt32Ty(),
I));
700 static void extractNonZeroOffsets(
IRBuilder<> &IRB,
702 unsigned ArgIdx,
Value *Offsets,
703 unsigned MaxElements) {
705 bool OffsetsAreZero = COff && COff->isNullValue();
707 extractElementsIntoArgs(IRB, Args, ArgIdx, Offsets, MaxElements);
710 [[nodiscard]]
bool lowerTextureLoad(
Function &
F) {
714 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
719 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
728 dxil::ResourceTypeInfo &RTI = DRTM[HandleTy];
730 if (RTI.
isUAV() && Kind != dxil::ResourceKind::Texture2DMS &&
731 Kind != dxil::ResourceKind::Texture2DMSArray)
742 extractElementsIntoArgs(IRB, Args, 2, Coords, 3);
743 extractNonZeroOffsets(IRB, Args, 5, Offsets, 3);
745 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
746 OpCode::TextureLoad, Args, CI->
getName(), NewRetTy);
749 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
752 eraseDeadInsertElementChains(VectorArgs);
761 [[nodiscard]]
bool lowerSampleOp(
764 SmallVectorImpl<Value *> &)> EmitExtraArgs) {
766 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
771 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
773 createTmpHandleCast(CI->
getArgOperand(1), OpBuilder.getHandleType());
784 UndefF, UndefI, UndefI, UndefI};
787 extractElementsIntoArgs(IRB, Args, 2, Coords, 4);
788 extractNonZeroOffsets(IRB, Args, 6, Offsets, 3);
791 EmitExtraArgs(IRB, CI, Args);
793 Expected<CallInst *> OpCall =
794 OpBuilder.tryCreateOp(
Op, Args, CI->
getName(), NewRetTy);
797 if (
Error E = replaceResRetUses(CI, *OpCall,
false))
800 eraseDeadInsertElementChains(VectorArgs);
806 [[nodiscard]]
bool lowerSample(
Function &
F,
bool HasClamp) {
807 return lowerSampleOp(
F, OpCode::Sample, 2, 3,
809 SmallVectorImpl<Value *> &Args) {
817 [[nodiscard]]
bool lowerSampleBias(
Function &
F,
bool HasClamp) {
818 return lowerSampleOp(
819 F, OpCode::SampleBias, 2, 4,
821 SmallVectorImpl<Value *> &Args) {
830 [[nodiscard]]
bool lowerSampleLevel(
Function &
F) {
831 return lowerSampleOp(
832 F, OpCode::SampleLevel, 2, 4,
833 [](
IRBuilder<> &, CallInst *CI, SmallVectorImpl<Value *> &Args) {
839 [[nodiscard]]
bool lowerSampleGrad(
Function &
F,
bool HasClamp) {
840 return lowerSampleOp(
841 F, OpCode::SampleGrad, 2, 5,
843 SmallVectorImpl<Value *> &Args) {
848 size_t DDXStart =
Args.size();
849 Args.append(3, UndefF);
850 extractElementsIntoArgs(IRB, Args, DDXStart, DDX, 3);
852 size_t DDYStart =
Args.size();
853 Args.append(3, UndefF);
854 extractElementsIntoArgs(IRB, Args, DDYStart, DDY, 3);
860 [[nodiscard]]
bool lowerRawBufferLoad(
Function &
F) {
861 const DataLayout &
DL =
F.getDataLayout();
866 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
871 Type *NewRetTy = OpBuilder.getResRetType(ScalarTy);
874 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
878 DL.getTypeSizeInBits(OldTy) /
DL.getTypeSizeInBits(ScalarTy);
879 Value *
Mask = ConstantInt::get(Int8Ty, ~(~0U << NumElements));
881 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value());
888 Expected<CallInst *> OpCall =
889 MMDI.DXILVersion >= VersionTuple(1, 2)
890 ? OpBuilder.tryCreateOp(OpCode::RawBufferLoad,
893 : OpBuilder.tryCreateOp(OpCode::BufferLoad,
894 {Handle, Index0, Index1}, CI->
getName(),
898 if (
Error E = replaceResRetUses(CI, *OpCall,
true))
905 [[nodiscard]]
bool lowerCBufferLoad(
Function &
F) {
908 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
913 Type *NewRetTy = OpBuilder.getCBufRetType(ScalarTy);
916 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
919 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
920 OpCode::CBufferLoadLegacy, {Handle,
Index}, CI->
getName(), NewRetTy);
923 if (
Error E = replaceNamedStructUses(CI, *OpCall))
931 [[nodiscard]]
bool lowerUpdateCounter(
Function &
F) {
935 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
938 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
941 std::array<Value *, 2>
Args{Handle, Op1};
943 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
944 OpCode::UpdateCounter, Args, CI->
getName(), Int32Ty);
955 [[nodiscard]]
bool lowerBarrierByMemoryHandle(
Function &
F) {
958 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
961 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
964 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
965 OpCode::BarrierByMemoryHandle, {Handle, SemanticFlags});
974 [[nodiscard]]
bool lowerGetDimensionsX(
Function &
F) {
978 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
981 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
984 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
985 OpCode::GetDimensions, {Handle,
Undef}, CI->
getName(), Int32Ty);
996 [[nodiscard]]
bool lowerGetPointer(
Function &
F) {
999 assert(
F.user_empty() &&
"getpointer operations should have been removed");
1000 F.eraseFromParent();
1011 bool FillWithUndef) {
1012 std::array<Value *, 4> DataElements{
nullptr,
nullptr,
nullptr,
nullptr};
1013 extractElementsIntoArgs(IRB, DataElements, 0,
Data, 4);
1019 if (DataElements[
I] ==
nullptr)
1024 return DataElements;
1029 static void eraseDeadInsertElementChain(
Value *
Data) {
1032 InsertElementInst *Tmp = IEI;
1038 [[nodiscard]]
bool lowerBufferStore(
Function &
F,
bool IsRaw) {
1039 const DataLayout &
DL =
F.getDataLayout();
1044 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1048 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1064 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1065 Value *
Mask = ConstantInt::get(Int8Ty, IsRaw ? ~(~0U << NumElements)
1069 if (NumElements > 4)
1071 "Buffer store data must have at most 4 elements",
1074 std::array<Value *, 4> DataElements =
1075 splitStoreData(IRB,
Data, NumElements, IsRaw);
1079 Handle, Index0, Index1, DataElements[0],
1080 DataElements[1], DataElements[2], DataElements[3],
Mask};
1081 if (IsRaw && MMDI.DXILVersion >= VersionTuple(1, 2)) {
1082 Op = OpCode::RawBufferStore;
1085 ConstantInt::get(Int32Ty,
DL.getPrefTypeAlign(ScalarTy).value()));
1087 Expected<CallInst *> OpCall =
1088 OpBuilder.tryCreateOp(
Op, Args, CI->
getName());
1093 eraseDeadInsertElementChain(
Data);
1111 for (
const WeakTrackingVH &VH : Vectors)
1113 eraseDeadInsertElementChain(V);
1116 [[nodiscard]]
bool lowerTextureStore(
Function &
F) {
1117 const DataLayout &
DL =
F.getDataLayout();
1122 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1127 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1134 DL.getTypeSizeInBits(DataTy) /
DL.getTypeSizeInBits(ScalarTy);
1135 if (NumElements > 4)
1137 "Texture store data must have at most 4 elements",
1141 std::array<Value *, 4> DataElements =
1142 splitStoreData(IRB,
Data, NumElements,
false);
1145 std::array<Value *, 9>
Args{
1147 Undef, DataElements[0], DataElements[1],
1148 DataElements[2], DataElements[3],
Mask};
1151 extractElementsIntoArgs(IRB, Args, 1, Coords, 3);
1153 Expected<CallInst *> OpCall =
1154 OpBuilder.tryCreateOp(OpCode::TextureStore, Args, CI->
getName());
1159 eraseDeadInsertElementChains(VectorArgs);
1165 [[nodiscard]]
bool lowerResourceAtomicBinOp(
Function &
F) {
1168 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1174 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1181 std::array<Value *, 6>
Args{Handle, BinOp, Coord0,
1182 Coord1, Coord2, NewValue};
1183 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1188 std::string Message(
toString(std::move(
E)));
1202 [[nodiscard]]
bool lowerResourceAtomicCompareExchange(
Function &
F) {
1205 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1211 createTmpHandleCast(CI->
getArgOperand(0), OpBuilder.getHandleType());
1218 std::array<Value *, 6>
Args{Handle, Coord0, Coord1,
1219 Coord2, CompareValue, NewValue};
1220 Expected<CallInst *> OpCall =
1221 OpBuilder.tryCreateOp(dxil::OpCode::AtomicCompareExchange, Args,
1226 std::string Message(
toString(std::move(
E)));
1240 [[nodiscard]]
bool lowerCtpopToCountBits(
Function &
F) {
1244 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1249 Type *RetTy = Int32Ty;
1250 Type *FRT =
F.getReturnType();
1252 RetTy = VectorType::get(RetTy, VT);
1254 Expected<CallInst *> OpCall = OpBuilder.tryCreateOp(
1255 dxil::OpCode::CountBits, Args, CI->
getName(), RetTy);
1269 CastOp = Instruction::ZExt;
1270 CastOp2 = Instruction::SExt;
1273 "Currently only lowering 16, 32, or 64 bit ctpop to CountBits \
1275 CastOp = Instruction::Trunc;
1276 CastOp2 = Instruction::Trunc;
1281 bool NeedsCast =
false;
1284 if (
I && (
I->getOpcode() == CastOp ||
I->getOpcode() == CastOp2) &&
1285 I->getType() == RetTy) {
1286 I->replaceAllUsesWith(*OpCall);
1287 I->eraseFromParent();
1307 [[nodiscard]]
bool lowerLifetimeIntrinsic(
Function &
F) {
1309 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1313 "Expected operand of lifetime intrinsic to be a pointer");
1315 auto ZeroOrUndef = [&](
Type *Ty) {
1316 return MMDI.ValidatorVersion < VersionTuple(1, 6)
1318 : UndefValue::
get(Ty);
1321 Value *Val =
nullptr;
1323 if (GV->hasInitializer() || GV->isExternallyInitialized())
1325 Val = ZeroOrUndef(GV->getValueType());
1327 Val = ZeroOrUndef(AI->getAllocatedType());
1329 assert(Val &&
"Expected operand of lifetime intrinsic to be a global "
1330 "variable or alloca instruction");
1338 [[nodiscard]]
bool lowerIsFPClass(
Function &
F) {
1342 return replaceFunction(
F, [&](CallInst *CI) ->
Error {
1351 switch (TCI->getZExtValue()) {
1352 case FPClassTest::fcInf:
1353 OpCode = dxil::OpCode::IsInf;
1355 case FPClassTest::fcNan:
1356 OpCode = dxil::OpCode::IsNaN;
1358 case FPClassTest::fcNormal:
1359 OpCode = dxil::OpCode::IsNormal;
1361 case FPClassTest::fcFinite:
1362 OpCode = dxil::OpCode::IsFinite;
1365 SmallString<128>
Msg =
1366 formatv(
"Unsupported FPClassTest {0} for DXIL Op Lowering",
1367 TCI->getZExtValue());
1371 Expected<CallInst *> OpCall =
1382 bool lowerIntrinsics() {
1383 bool Updated =
false;
1384 bool HasErrors =
false;
1387 if (!
F.isDeclaration())
1393 case Intrinsic::dx_resource_casthandle:
1395 case Intrinsic::dbg_value:
1398 F.eraseFromParent();
1402 F.eraseFromParent();
1405 "Unsupported intrinsic {0} for DXIL lowering",
F.getName());
1406 M.getContext().emitError(
Msg);
1411#define DXIL_OP_INTRINSIC(OpCode, Intrin, ...) \
1413 HasErrors |= replaceFunctionWithOp( \
1414 F, OpCode, ArrayRef<IntrinArgSelect>{__VA_ARGS__}); \
1416#include "DXILOperation.inc"
1417 case Intrinsic::dx_resource_handlefrombinding:
1418 HasErrors |= lowerHandleFromBinding(
F);
1420 case Intrinsic::dx_resource_handlefromheap:
1421 HasErrors |= lowerHandleFromHeap(
F);
1423 case Intrinsic::dx_resource_getbasepointer:
1424 case Intrinsic::dx_resource_getpointer:
1425 HasErrors |= lowerGetPointer(
F);
1427 case Intrinsic::dx_resource_nonuniformindex:
1429 "overloaded llvm.dx.resource.nonuniformindex intrinsics?");
1432 case Intrinsic::dx_resource_load_typedbuffer:
1433 HasErrors |= lowerTypedBufferLoad(
F,
true);
1435 case Intrinsic::dx_resource_load_level:
1436 HasErrors |= lowerTextureLoad(
F);
1438 case Intrinsic::dx_resource_sample:
1439 HasErrors |= lowerSample(
F,
false);
1441 case Intrinsic::dx_resource_sample_clamp:
1442 HasErrors |= lowerSample(
F,
true);
1444 case Intrinsic::dx_resource_samplebias:
1445 HasErrors |= lowerSampleBias(
F,
false);
1447 case Intrinsic::dx_resource_samplebias_clamp:
1448 HasErrors |= lowerSampleBias(
F,
true);
1450 case Intrinsic::dx_resource_samplelevel:
1451 HasErrors |= lowerSampleLevel(
F);
1453 case Intrinsic::dx_resource_samplegrad:
1454 HasErrors |= lowerSampleGrad(
F,
false);
1456 case Intrinsic::dx_resource_samplegrad_clamp:
1457 HasErrors |= lowerSampleGrad(
F,
true);
1459 case Intrinsic::dx_resource_store_typedbuffer:
1460 HasErrors |= lowerBufferStore(
F,
false);
1462 case Intrinsic::dx_resource_store_texture:
1463 HasErrors |= lowerTextureStore(
F);
1465 case Intrinsic::dx_resource_load_rawbuffer:
1466 HasErrors |= lowerRawBufferLoad(
F);
1468 case Intrinsic::dx_resource_store_rawbuffer:
1469 HasErrors |= lowerBufferStore(
F,
true);
1471 case Intrinsic::dx_resource_load_cbufferrow_2:
1472 case Intrinsic::dx_resource_load_cbufferrow_4:
1473 case Intrinsic::dx_resource_load_cbufferrow_8:
1474 HasErrors |= lowerCBufferLoad(
F);
1476 case Intrinsic::dx_resource_updatecounter:
1477 HasErrors |= lowerUpdateCounter(
F);
1479 case Intrinsic::dx_barrier_by_memory_handle:
1480 HasErrors |= lowerBarrierByMemoryHandle(
F);
1482 case Intrinsic::dx_resource_atomic_binop:
1483 HasErrors |= lowerResourceAtomicBinOp(
F);
1485 case Intrinsic::dx_resource_atomic_compare_exchange:
1486 HasErrors |= lowerResourceAtomicCompareExchange(
F);
1488 case Intrinsic::dx_resource_getdimensions_x:
1489 HasErrors |= lowerGetDimensionsX(
F);
1491 case Intrinsic::ctpop:
1492 HasErrors |= lowerCtpopToCountBits(
F);
1494 case Intrinsic::lifetime_start:
1495 case Intrinsic::lifetime_end:
1497 F.eraseFromParent();
1499 if (MMDI.DXILVersion < VersionTuple(1, 6))
1500 HasErrors |= lowerLifetimeIntrinsic(
F);
1505 case Intrinsic::is_fpclass:
1506 HasErrors |= lowerIsFPClass(
F);
1511 if (Updated && !HasErrors) {
1512 cleanupHandleCasts();
1513 cleanupNonUniformResourceIndexCalls();
1526 const bool MadeChanges = OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1539class DXILOpLoweringLegacy :
public ModulePass {
1541 bool runOnModule(
Module &M)
override {
1543 getAnalysis<DXILResourceWrapperPass>().getResourceMap();
1545 getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
1547 getAnalysis<DXILMetadataAnalysisWrapperPass>().getModuleMetadata();
1549 return OpLowerer(M, DRM, DRTM, MMDI).lowerIntrinsics();
1551 StringRef getPassName()
const override {
return "DXIL Op Lowering"; }
1552 DXILOpLoweringLegacy() : ModulePass(
ID) {}
1555 void getAnalysisUsage(llvm::AnalysisUsage &AU)
const override {
1558 AU.
addRequired<DXILMetadataAnalysisWrapperPass>();
1566char DXILOpLoweringLegacy::ID = 0;
1577 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.