24#include "llvm/IR/IntrinsicsDirectX.h"
34#define DEBUG_TYPE "dxil-intrinsic-expansion"
49 if (IsRaw && M->getTargetTriple().getDXILVersion() >
VersionTuple(1, 2))
58 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
73 ConstantInt::get(IType, 0x7c00))
74 : ConstantInt::get(IType, 0x7c00);
81 ConstantInt::get(IType, 0xfc00))
82 : ConstantInt::get(IType, 0xfc00);
84 Value *IVal = Builder.CreateBitCast(Val, PosInf->
getType());
85 Value *B1 = Builder.CreateICmpEQ(IVal, PosInf);
86 Value *B2 = Builder.CreateICmpEQ(IVal, NegInf);
87 Value *B3 = Builder.CreateOr(B1, B2);
93 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
109 ConstantInt::get(IType, 0x7c00))
110 : ConstantInt::get(IType, 0x7c00);
116 ConstantInt::get(IType, 0x3ff))
117 : ConstantInt::get(IType, 0x3ff);
124 ConstantInt::get(IType, 0))
125 : ConstantInt::get(IType, 0);
127 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
128 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
129 Value *B1 = Builder.CreateICmpEQ(Exp, ExpBitMask);
131 Value *Sig = Builder.CreateAnd(IVal, SigBitMask);
132 Value *B2 = Builder.CreateICmpNE(Sig,
Zero);
133 Value *B3 = Builder.CreateAnd(B1, B2);
139 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
155 ConstantInt::get(IType, 0x7c00))
156 : ConstantInt::get(IType, 0x7c00);
158 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
159 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
160 Value *B1 = Builder.CreateICmpNE(Exp, ExpBitMask);
166 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
182 ConstantInt::get(IType, 0x7c00))
183 : ConstantInt::get(IType, 0x7c00);
189 ConstantInt::get(IType, 0))
190 : ConstantInt::get(IType, 0);
192 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
193 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
194 Value *NotAllZeroes = Builder.CreateICmpNE(Exp,
Zero);
195 Value *NotAllOnes = Builder.CreateICmpNE(Exp, ExpBitMask);
196 Value *B1 = Builder.CreateAnd(NotAllZeroes, NotAllOnes);
201 assert(
F.getIntrinsicID() == Intrinsic::dx_fdot &&
202 "Function is not a dx.fdot intrinsic");
204 return ParamTy->getNumElements() <= 4 ||
205 F.getParent()->getTargetTriple().getOSVersion() <
VersionTuple(6, 9);
209 switch (
F.getIntrinsicID()) {
210 case Intrinsic::assume:
212 case Intrinsic::atan2:
213 case Intrinsic::copysign:
214 case Intrinsic::fshl:
215 case Intrinsic::fshr:
217 case Intrinsic::is_fpclass:
219 case Intrinsic::log10:
221 case Intrinsic::powi:
222 case Intrinsic::dx_uclamp:
223 case Intrinsic::dx_sclamp:
224 case Intrinsic::dx_nclamp:
225 case Intrinsic::dx_isfinite:
226 case Intrinsic::dx_isinf:
227 case Intrinsic::dx_isnan:
228 case Intrinsic::dx_sdot:
229 case Intrinsic::dx_udot:
230 case Intrinsic::dx_sign:
231 case Intrinsic::usub_sat:
232 case Intrinsic::vector_reduce_add:
233 case Intrinsic::vector_reduce_fadd:
234 case Intrinsic::matrix_multiply:
235 case Intrinsic::matrix_transpose:
236 case Intrinsic::umul_with_overflow:
237 case Intrinsic::smul_with_overflow:
238 case Intrinsic::dx_load_input:
239 case Intrinsic::dx_store_output:
241 case Intrinsic::vector_reduce_and:
242 case Intrinsic::vector_reduce_or:
243 return F.getParent()->getTargetTriple().getDXILVersion() <
245 case Intrinsic::dx_fdot:
247 case Intrinsic::dx_resource_load_rawbuffer:
249 F.getParent(),
F.getReturnType()->getStructElementType(0),
251 case Intrinsic::dx_resource_load_typedbuffer:
253 F.getParent(),
F.getReturnType()->getStructElementType(0),
255 case Intrinsic::dx_resource_store_rawbuffer:
257 F.getParent(),
F.getFunctionType()->getParamType(3),
true);
258 case Intrinsic::dx_resource_store_typedbuffer:
260 F.getParent(),
F.getFunctionType()->getParamType(2),
false);
268 Type *Ty =
A->getType();
272 Value *Cmp = Builder.CreateICmpULT(
A,
B,
"usub.cmp");
273 Value *
Sub = Builder.CreateSub(
A,
B,
"usub.sub");
275 return Builder.CreateSelect(Cmp,
Zero,
Sub,
"usub.sat");
282 Type *Ty,
unsigned BW) {
283 assert(BW % 2 == 0 &&
"high-half split needs symmetric halves");
284 unsigned Half = BW / 2;
285 Value *HalfShift = ConstantInt::get(Ty, Half);
288 Value *U0 = Builder.CreateAnd(
A, LoMask);
289 Value *U1 = Builder.CreateLShr(
A, HalfShift);
290 Value *V0 = Builder.CreateAnd(
B, LoMask);
291 Value *
V1 = Builder.CreateLShr(
B, HalfShift);
293 Value *W0 = Builder.CreateMul(U0, V0);
294 Value *
T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
295 Builder.CreateLShr(W0, HalfShift));
296 Value *W1 = Builder.CreateAnd(
T, LoMask);
297 Value *W2 = Builder.CreateLShr(
T, HalfShift);
298 W1 = Builder.CreateAdd(Builder.CreateMul(U0,
V1), W1);
299 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1,
V1), W2),
300 Builder.CreateLShr(W1, HalfShift));
310 Type *Ty =
A->getType();
311 unsigned BW = Ty->getScalarSizeInBits();
321 Lo = Builder.CreateMul(
A,
B);
324 Signed ? Builder.CreateSExt(
A, WideTy) : Builder.CreateZExt(
A, WideTy);
326 Signed ? Builder.CreateSExt(
B, WideTy) : Builder.CreateZExt(
B, WideTy);
327 Value *Wide = Builder.CreateMul(WideA, WideB);
330 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(
Lo, WideTy));
332 Value *
Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
333 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(WideTy, 0));
335 }
else if (BW == 32) {
339 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
340 Value *
Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {
A,
B});
341 Value *
Hi = Builder.CreateExtractValue(
Mul, 0);
342 Lo = Builder.CreateExtractValue(
Mul, 1);
344 Ov = Builder.CreateICmpNE(
345 Hi, Builder.CreateAShr(
Lo, ConstantInt::get(Ty, BW - 1)));
347 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
349 Lo = Builder.CreateMul(
A,
B);
354 Value *SignShift = ConstantInt::get(Ty, BW - 1);
355 Value *ASign = Builder.CreateAShr(
A, SignShift);
356 Value *BSign = Builder.CreateAShr(
B, SignShift);
357 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(ASign,
B));
358 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(BSign,
A));
359 Ov = Builder.CreateICmpNE(
Hi, Builder.CreateAShr(
Lo, SignShift));
361 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
366 Agg = Builder.CreateInsertValue(Agg,
Lo, 0);
367 return Builder.CreateInsertValue(Agg, Ov, 1);
371 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
372 IntrinsicId == Intrinsic::vector_reduce_fadd);
375 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
378 Type *Ty =
X->getType();
380 unsigned XVecSize = XVec->getNumElements();
381 Value *Sum = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
387 Sum = Builder.CreateFAdd(Sum, StartValue);
391 for (
unsigned I = 1;
I < XVecSize;
I++) {
392 Value *Elt = Builder.CreateExtractElement(
X,
I);
394 Sum = Builder.CreateFAdd(Sum, Elt);
396 Sum = Builder.CreateAdd(Sum, Elt);
403 assert(IntrinsicId == Intrinsic::vector_reduce_and ||
404 IntrinsicId == Intrinsic::vector_reduce_or);
409 Value *Result = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
410 for (
unsigned I = 1;
I < XVec->getNumElements(); ++
I) {
411 Value *Elt = Builder.CreateExtractElement(
X,
I);
412 Result = IntrinsicId == Intrinsic::vector_reduce_or
413 ? Builder.CreateOr(Result, Elt)
414 : Builder.CreateAnd(Result, Elt);
422 Type *Ty =
X->getType();
428 ConstantInt::get(EltTy, 0))
429 : ConstantInt::get(EltTy, 0);
430 auto *
V = Builder.CreateSub(
Zero,
X);
431 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {
X,
V},
nullptr,
437 Type *ATy =
A->getType();
438 [[maybe_unused]]
Type *BTy =
B->getType();
447 unsigned NumElts = AVec->getNumElements();
451 DotIntrinsic = Intrinsic::dx_dot2;
454 DotIntrinsic = Intrinsic::dx_dot3;
457 DotIntrinsic = Intrinsic::dx_dot4;
461 "Invalid dot product input vector: length is outside 2-4");
465 for (
unsigned I = 0;
I < NumElts; ++
I)
466 Args.push_back(Builder.CreateExtractElement(
A, Builder.getInt32(
I)));
467 for (
unsigned I = 0;
I < NumElts; ++
I)
468 Args.push_back(Builder.CreateExtractElement(
B, Builder.getInt32(
I)));
469 return Builder.CreateIntrinsic(ATy->
getScalarType(), DotIntrinsic, Args,
486 "long fdot must not be expanded for shader model 6.9 or later");
489 Value *Result =
nullptr;
491 unsigned Remaining = NumElts -
Offset;
494 unsigned ChunkSize = Remaining == 5 ? 3 : std::min(Remaining, 4u);
496 for (
unsigned I = 0;
I < ChunkSize; ++
I)
498 Value *AChunk = Builder.CreateShuffleVector(
A, Mask);
499 Value *BChunk = Builder.CreateShuffleVector(
B, Mask);
501 Result = Result ? Builder.CreateFAdd(Result, Chunk,
"dot.add") : Chunk;
510 assert(DotIntrinsic == Intrinsic::dx_sdot ||
511 DotIntrinsic == Intrinsic::dx_udot);
514 Type *ATy =
A->getType();
515 [[maybe_unused]]
Type *BTy =
B->getType();
525 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
527 : Intrinsic::dx_umad;
530 Result = Builder.CreateMul(Elt0, Elt1);
531 for (
unsigned I = 1;
I < AVec->getNumElements();
I++) {
532 Elt0 = Builder.CreateExtractElement(
A,
I);
533 Elt1 = Builder.CreateExtractElement(
B,
I);
534 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
544 Type *Ty =
X->getType();
552 Value *NewX = Builder.CreateFMul(Log2eConst,
X);
553 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
554 Ty, Intrinsic::exp2, {NewX},
nullptr,
"dx.exp2");
566 switch (TCI->getZExtValue()) {
580 Type *FTy =
F->getType();
581 unsigned FNumElem = 0;
588 FNumElem = FVecTy->getNumElements();
596 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
597 switch (TCI->getZExtValue()) {
599 Value *NegZero = ConstantInt::get(Builder.getIntNTy(
BitWidth),
603 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
605 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
607 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
619 Type *Ty =
X->getType();
625 ConstantFP::get(EltTy, LogConstVal))
626 : ConstantFP::get(EltTy, LogConstVal);
627 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
628 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
631 return Builder.CreateFMul(Ln2Const, Log2Call);
640 Type *Ty =
X->getType();
644 Value *Tan = Builder.CreateFDiv(
Y,
X);
646 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
647 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
656 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
657 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
660 Value *Result = Atan;
667 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
668 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
671 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
672 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
675 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
676 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
679 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
680 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
685template <
bool LeftFunnel>
695 "Can't use Mask to compute modulo and inverse");
710 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
715 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
720 Value *NotShift = Builder.CreateNot(Shift);
721 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
723 Constant *One = ConstantInt::get(Ty, 1);
728 ShiftedA = Builder.CreateShl(
A, MaskedShift);
729 Value *ShiftB1 = Builder.CreateLShr(
B, One);
730 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
732 Value *ShiftA1 = Builder.CreateShl(
A, One);
733 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
734 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
737 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
745 Type *Ty =
X->getType();
748 if (IntrinsicId == Intrinsic::powi)
749 Y = Builder.CreateSIToFP(
Y, Ty);
752 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
753 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
754 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
755 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
768 "Only expand double or int64 scalars or vectors");
769 bool IsVector =
false;
770 unsigned ExtractNum = 2;
772 ExtractNum = 2 * VT->getNumElements();
774 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
783 while (ExtractNum > 0) {
784 unsigned LoadNum = std::min(ExtractNum, 4u);
788 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
791 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
792 Value *Tmp = Builder.getInt32(4 *
Base * 2);
797 Args[AddressArg] = Builder.CreateAdd(Args[AddressArg], Tmp);
800 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
804 Value *Extract = Builder.CreateExtractValue(
Load, {0});
807 for (
unsigned I = 0;
I < LoadNum; ++
I)
809 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
812 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
813 Value *Combined =
nullptr;
816 Combined = Builder.CreateIntrinsic(
817 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
818 {ExtractElements[I], ExtractElements[I + 1]});
823 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
825 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
827 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
829 Combined = Builder.CreateOr(
Lo, ShiftedHi);
833 Result = Builder.CreateInsertElement(Result, Combined,
834 Builder.getInt32((
I / 2) +
Base));
839 ExtractNum -= LoadNum;
843 Value *CheckBit =
nullptr;
854 if (Indices[0] == 0) {
856 EVI->replaceAllUsesWith(Result);
859 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
864 for (
Value *L : Loads)
865 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
866 CheckBit = Builder.CreateAnd(CheckBits);
868 EVI->replaceAllUsesWith(CheckBit);
870 EVI->eraseFromParent();
879 unsigned ValIndex = IsRaw ? 3 : 2;
884 "Only expand double or int64 scalars or vectors");
887 bool IsVector =
false;
888 unsigned ExtractNum = 2;
891 VecLen = VT->getNumElements();
892 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
893 ExtractNum = VecLen * 2;
902 Type *SplitElementTy = Int32Ty;
906 Value *LowBits =
nullptr;
907 Value *HighBits =
nullptr;
911 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
913 LowBits = Builder.CreateExtractValue(Split, 0);
914 HighBits = Builder.CreateExtractValue(Split, 1);
918 Constant *ShiftAmt = Builder.getInt64(32);
924 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
925 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
926 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
931 for (
unsigned I = 0;
I < VecLen; ++
I) {
933 Mask.push_back(
I + VecLen);
935 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
937 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
938 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
945 while (ExtractNum > 0) {
946 unsigned StoreNum = std::min(ExtractNum, 4u);
948 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
951 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
957 Args[AddressArg] = Builder.CreateAdd(Args[AddressArg], Tmp);
961 for (
unsigned I = 0;
I < StoreNum; ++
I) {
962 Mask.push_back(
Base +
I);
967 SubVal = Builder.CreateShuffleVector(Val, Mask);
969 Args.push_back(SubVal);
971 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
973 ExtractNum -= StoreNum;
981 if (ClampIntrinsic == Intrinsic::dx_uclamp)
982 return Intrinsic::umax;
983 if (ClampIntrinsic == Intrinsic::dx_sclamp)
984 return Intrinsic::smax;
985 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
986 return Intrinsic::maxnum;
990 if (ClampIntrinsic == Intrinsic::dx_uclamp)
991 return Intrinsic::umin;
992 if (ClampIntrinsic == Intrinsic::dx_sclamp)
993 return Intrinsic::smin;
994 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
995 return Intrinsic::minnum;
1003 Type *Ty =
X->getType();
1005 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1006 {
X, Min},
nullptr,
"dx.max");
1007 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1008 {MaxCall, Max},
nullptr,
"dx.min");
1013 Type *Ty =
X->getType();
1023 GT = Builder.CreateFCmpOLT(
Zero,
X);
1024 LT = Builder.CreateFCmpOLT(
X,
Zero);
1027 GT = Builder.CreateICmpSLT(
Zero,
X);
1028 LT = Builder.CreateICmpSLT(
X,
Zero);
1031 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1032 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1034 return Builder.CreateSub(ZextGT, ZextLT);
1046 bool IsDouble = Ty->getScalarType()->isDoubleTy();
1047 unsigned BitWidth = IsDouble ? 32 : Ty->getScalarSizeInBits();
1050 auto CopySignBit = [&](
Value *MagnitudeInt,
Value *SignInt) {
1053 Constant *SignMask = ConstantInt::get(IntTy, SignMaskVal);
1054 Constant *NotSignMask = ConstantInt::get(IntTy, ~SignMaskVal);
1056 Value *MagnitudeBits = Builder.CreateAnd(MagnitudeInt, NotSignMask);
1057 Value *SignBits = Builder.CreateAnd(SignInt, SignMask);
1058 return Builder.CreateOr(MagnitudeBits, SignBits);
1064 Value *MagnitudeHalves = Builder.CreateIntrinsic(
1065 SplitTy, Intrinsic::dx_splitdouble, {Magnitude});
1067 Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble, {
Sign});
1068 Value *MagnitudeLow = Builder.CreateExtractValue(MagnitudeHalves, 0);
1069 Value *MagnitudeHigh = Builder.CreateExtractValue(MagnitudeHalves, 1);
1070 Value *SignHigh = Builder.CreateExtractValue(SignHalves, 1);
1072 Value *CombinedHigh = CopySignBit(MagnitudeHigh, SignHigh);
1073 return Builder.CreateIntrinsic(Ty, Intrinsic::dx_asdouble,
1074 {MagnitudeLow, CombinedHigh});
1077 Value *MagnitudeInt = Builder.CreateBitCast(Magnitude, IntTy);
1078 Value *SignInt = Builder.CreateBitCast(
Sign, IntTy);
1079 Value *CombinedInt = CopySignBit(MagnitudeInt, SignInt);
1080 return Builder.CreateBitCast(CombinedInt, Ty);
1095 Type *EltTy = RetTy->getElementType();
1106 unsigned LHSSize = LHSRows * LHSCols;
1107 unsigned RHSSize = LHSCols * RHSCols;
1110 for (
unsigned I = 0;
I < LHSSize; ++
I)
1111 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1112 for (
unsigned I = 0;
I < RHSSize; ++
I)
1113 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1118 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1119 if (IsFP && !UseScalarFP) {
1122 FloatDotID = Intrinsic::dx_dot2;
1125 FloatDotID = Intrinsic::dx_dot3;
1128 FloatDotID = Intrinsic::dx_dot4;
1132 "Invalid matrix inner dimension for dot product: must be 2-4");
1137 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1138 for (
unsigned R = 0; R < LHSRows; ++R) {
1141 for (
unsigned K = 0;
K < LHSCols; ++
K) {
1149 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1150 for (
unsigned K = 1;
K < LHSCols; ++
K)
1151 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1152 {RowElts[K], ColElts[K], Dot});
1156 Args.append(RowElts.
begin(), RowElts.
end());
1157 Args.append(ColElts.
begin(), ColElts.
end());
1158 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1161 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1162 for (
unsigned K = 1;
K < LHSCols; ++
K)
1163 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1164 {RowElts[K], ColElts[K], Dot});
1166 unsigned ResIdx =
C * LHSRows + R;
1167 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1181 unsigned NumElts = Rows * Cols;
1183 for (
unsigned I = 0;
I < NumElts; ++
I)
1184 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1187 return Builder.CreateShuffleVector(Mat, Mask);
1202 Type *ScalarTy = VT->getElementType();
1203 unsigned NumElems = VT->getNumElements();
1209 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1212 M, Intrinsic::dx_store_output, {ScalarTy});
1214 for (
unsigned I = 0;
I < NumElems; ++
I) {
1216 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1218 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1219 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1220 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8,
Scalar});
1238 Type *ScalarTy = VT->getElementType();
1239 unsigned NumElems = VT->getNumElements();
1245 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1248 M, Intrinsic::dx_load_input, {ScalarTy});
1251 for (
unsigned I = 0;
I < NumElems; ++
I) {
1253 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1254 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1256 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1258 Builder.CreateInsertElement(Vec,
Scalar, ConstantInt::get(Int32Ty,
I));
1265 Value *Result =
nullptr;
1267 switch (IntrinsicId) {
1268 case Intrinsic::abs:
1271 case Intrinsic::assume:
1274 case Intrinsic::atan2:
1277 case Intrinsic::copysign:
1280 case Intrinsic::fshl:
1283 case Intrinsic::fshr:
1286 case Intrinsic::exp:
1289 case Intrinsic::is_fpclass:
1292 case Intrinsic::log:
1295 case Intrinsic::log10:
1298 case Intrinsic::pow:
1299 case Intrinsic::powi:
1302 case Intrinsic::vector_reduce_and:
1303 case Intrinsic::vector_reduce_or:
1306 case Intrinsic::dx_uclamp:
1307 case Intrinsic::dx_sclamp:
1308 case Intrinsic::dx_nclamp:
1311 case Intrinsic::dx_isfinite:
1314 case Intrinsic::dx_isinf:
1317 case Intrinsic::dx_isnan:
1320 case Intrinsic::dx_fdot:
1323 case Intrinsic::dx_sdot:
1324 case Intrinsic::dx_udot:
1327 case Intrinsic::dx_sign:
1330 case Intrinsic::dx_load_input:
1333 case Intrinsic::dx_store_output:
1337 case Intrinsic::dx_resource_load_rawbuffer:
1341 case Intrinsic::dx_resource_store_rawbuffer:
1345 case Intrinsic::dx_resource_load_typedbuffer:
1349 case Intrinsic::dx_resource_store_typedbuffer:
1353 case Intrinsic::usub_sat:
1356 case Intrinsic::umul_with_overflow:
1357 case Intrinsic::smul_with_overflow:
1359 Intrinsic::smul_with_overflow);
1361 case Intrinsic::vector_reduce_add:
1362 case Intrinsic::vector_reduce_fadd:
1365 case Intrinsic::matrix_multiply:
1368 case Intrinsic::matrix_transpose:
1384 bool IntrinsicExpanded =
false;
1391 if (
F.user_empty() && IntrinsicExpanded)
1392 F.eraseFromParent();
1411 "DXIL Intrinsic Expansion",
false,
false)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static Value * expand16BitIsNormal(CallInst *Orig)
static Value * createMulHighUnsigned(IRBuilder<> &Builder, Value *A, Value *B, Type *Ty, unsigned BW)
static bool expandIntrinsic(Function &F, CallInst *Orig)
static Value * expandClampIntrinsic(CallInst *Orig, Intrinsic::ID ClampIntrinsic)
static Value * expand16BitIsInf(CallInst *Orig)
static bool expansionIntrinsics(Module &M)
static Value * expandCopySignIntrinsic(CallInst *Orig)
static Value * expand16BitIsFinite(CallInst *Orig)
static Value * expandLoadInput(CallInst *Orig)
static Value * expandUsubSat(CallInst *Orig)
static Value * expandFloatDotIntrinsic(CallInst *Orig)
static bool expandStoreOutput(CallInst *Orig)
static Value * expandMatrixTranspose(CallInst *Orig)
static Value * expandVecReduceAdd(CallInst *Orig, Intrinsic::ID IntrinsicId)
static Value * expandAtan2Intrinsic(CallInst *Orig)
static Value * expandLog10Intrinsic(CallInst *Orig)
static Intrinsic::ID getMinForClamp(Intrinsic::ID ClampIntrinsic)
static Value * expandIntegerDotIntrinsic(CallInst *Orig, Intrinsic::ID DotIntrinsic)
static Value * expandVecReduceAndOr(CallInst *Orig, Intrinsic::ID IntrinsicId)
static bool expandBufferStoreIntrinsic(CallInst *Orig, bool IsRaw)
static Value * expandLogIntrinsic(CallInst *Orig, float LogConstVal=numbers::ln2f)
static Value * expandMulWithOverflow(CallInst *Orig, bool Signed)
static Value * expandPowIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId)
static bool resourceAccessNeeds64BitExpansion(Module *M, Type *OverloadTy, bool IsRaw)
static Value * expandExpIntrinsic(CallInst *Orig)
static Value * expand16BitIsNaN(CallInst *Orig)
static Value * expandSignIntrinsic(CallInst *Orig)
static Intrinsic::ID getMaxForClamp(Intrinsic::ID ClampIntrinsic)
static bool shouldExpandFloatDotIntrinsic(Function &F)
static Value * expandFloatDotChunk(CallInst *Orig, Value *A, Value *B)
static Value * expandAbs(CallInst *Orig)
static bool isIntrinsicExpansion(Function &F)
static bool expandBufferLoadIntrinsic(CallInst *Orig, bool IsRaw)
static Value * expandMatrixMultiply(CallInst *Orig)
static Value * expandIsFPClass(CallInst *Orig)
static Value * expandFunnelShiftIntrinsic(CallInst *Orig)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file defines the SmallVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
bool runOnModule(Module &M) override
runOnModule - Virtual method overriden by subclasses to process the module being operated on.
DXILIntrinsicExpansionLegacy()
Class for arbitrary precision integers.
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
void setAttributes(AttributeList A)
Set the attributes for this call.
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
AttributeList getAttributes() const
Return the attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
void setTailCall(bool IsTc=true)
static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
This is an important base class in LLVM.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
static constexpr ElementCount getFixed(ScalarTy MinVal)
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Type * getParamType(unsigned i) const
Parameter type accessors.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
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.
iterator_range< user_iterator > users()
LLVM_ABI FastMathFlags getFastMathFlags() const LLVM_READONLY
Convenience function for getting all the fast-math flags, which must be an operator which supports th...
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.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
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 none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
LLVM_ABI VersionTuple getOSVersion() const
Parse the version number from the OS name component of the triple, if present.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI Type * getStructElementType(unsigned N) const
bool isVectorTy() const
True if this is an instance of VectorType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
LLVM_ABI Type * getWithNewBitWidth(unsigned NewBitWidth) const
Given an integer or vector type, change the lane bitwidth to NewBitwidth, whilst keeping the old numb...
static LLVM_ABI IntegerType * getInt16Ty(LLVMContext &C)
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
Represents a version number in the form major[.minor[.subminor[.build]]].
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
This is an optimization pass for GlobalISel generic memory operations.
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).
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...
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
ModulePass * createDXILIntrinsicExpansionLegacyPass()
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...
@ Sub
Subtraction of integers.
constexpr unsigned BitWidth
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.
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.