25#include "llvm/IR/IntrinsicsDirectX.h"
35#define DEBUG_TYPE "dxil-intrinsic-expansion"
50 if (IsRaw && M->getTargetTriple().getDXILVersion() >
VersionTuple(1, 2))
59 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
74 ConstantInt::get(IType, 0x7c00))
75 : ConstantInt::get(IType, 0x7c00);
82 ConstantInt::get(IType, 0xfc00))
83 : ConstantInt::get(IType, 0xfc00);
85 Value *IVal = Builder.CreateBitCast(Val, PosInf->
getType());
86 Value *B1 = Builder.CreateICmpEQ(IVal, PosInf);
87 Value *B2 = Builder.CreateICmpEQ(IVal, NegInf);
88 Value *B3 = Builder.CreateOr(B1, B2);
94 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
110 ConstantInt::get(IType, 0x7c00))
111 : ConstantInt::get(IType, 0x7c00);
117 ConstantInt::get(IType, 0x3ff))
118 : ConstantInt::get(IType, 0x3ff);
125 ConstantInt::get(IType, 0))
126 : ConstantInt::get(IType, 0);
128 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
129 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
130 Value *B1 = Builder.CreateICmpEQ(Exp, ExpBitMask);
132 Value *Sig = Builder.CreateAnd(IVal, SigBitMask);
133 Value *B2 = Builder.CreateICmpNE(Sig, Zero);
134 Value *B3 = Builder.CreateAnd(B1, B2);
140 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
156 ConstantInt::get(IType, 0x7c00))
157 : ConstantInt::get(IType, 0x7c00);
159 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
160 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
161 Value *B1 = Builder.CreateICmpNE(Exp, ExpBitMask);
167 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
183 ConstantInt::get(IType, 0x7c00))
184 : ConstantInt::get(IType, 0x7c00);
190 ConstantInt::get(IType, 0))
191 : ConstantInt::get(IType, 0);
193 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
194 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
195 Value *NotAllZeroes = Builder.CreateICmpNE(Exp, Zero);
196 Value *NotAllOnes = Builder.CreateICmpNE(Exp, ExpBitMask);
197 Value *B1 = Builder.CreateAnd(NotAllZeroes, NotAllOnes);
202 switch (
F.getIntrinsicID()) {
203 case Intrinsic::assume:
205 case Intrinsic::atan2:
206 case Intrinsic::fshl:
207 case Intrinsic::fshr:
209 case Intrinsic::is_fpclass:
211 case Intrinsic::log10:
213 case Intrinsic::powi:
214 case Intrinsic::dx_all:
215 case Intrinsic::dx_any:
216 case Intrinsic::dx_uclamp:
217 case Intrinsic::dx_sclamp:
218 case Intrinsic::dx_nclamp:
219 case Intrinsic::dx_degrees:
220 case Intrinsic::dx_isinf:
221 case Intrinsic::dx_isnan:
222 case Intrinsic::dx_lerp:
223 case Intrinsic::dx_normalize:
224 case Intrinsic::dx_fdot:
225 case Intrinsic::dx_sdot:
226 case Intrinsic::dx_udot:
227 case Intrinsic::dx_sign:
228 case Intrinsic::dx_step:
229 case Intrinsic::dx_radians:
230 case Intrinsic::usub_sat:
231 case Intrinsic::vector_reduce_add:
232 case Intrinsic::vector_reduce_fadd:
233 case Intrinsic::matrix_multiply:
234 case Intrinsic::matrix_transpose:
235 case Intrinsic::umul_with_overflow:
236 case Intrinsic::smul_with_overflow:
238 case Intrinsic::dx_resource_load_rawbuffer:
240 F.getParent(),
F.getReturnType()->getStructElementType(0),
242 case Intrinsic::dx_resource_load_typedbuffer:
244 F.getParent(),
F.getReturnType()->getStructElementType(0),
246 case Intrinsic::dx_resource_store_rawbuffer:
248 F.getParent(),
F.getFunctionType()->getParamType(3),
true);
249 case Intrinsic::dx_resource_store_typedbuffer:
251 F.getParent(),
F.getFunctionType()->getParamType(2),
false);
259 Type *Ty =
A->getType();
263 Value *Cmp = Builder.CreateICmpULT(
A,
B,
"usub.cmp");
264 Value *
Sub = Builder.CreateSub(
A,
B,
"usub.sub");
265 Value *Zero = ConstantInt::get(Ty, 0);
266 return Builder.CreateSelect(Cmp, Zero,
Sub,
"usub.sat");
273 Type *Ty,
unsigned BW) {
274 assert(BW % 2 == 0 &&
"high-half split needs symmetric halves");
275 unsigned Half = BW / 2;
276 Value *HalfShift = ConstantInt::get(Ty, Half);
279 Value *U0 = Builder.CreateAnd(
A, LoMask);
280 Value *U1 = Builder.CreateLShr(
A, HalfShift);
281 Value *V0 = Builder.CreateAnd(
B, LoMask);
282 Value *
V1 = Builder.CreateLShr(
B, HalfShift);
284 Value *W0 = Builder.CreateMul(U0, V0);
285 Value *
T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
286 Builder.CreateLShr(W0, HalfShift));
287 Value *W1 = Builder.CreateAnd(
T, LoMask);
288 Value *W2 = Builder.CreateLShr(
T, HalfShift);
289 W1 = Builder.CreateAdd(Builder.CreateMul(U0,
V1), W1);
290 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1,
V1), W2),
291 Builder.CreateLShr(W1, HalfShift));
301 Type *Ty =
A->getType();
302 unsigned BW = Ty->getScalarSizeInBits();
312 Lo = Builder.CreateMul(
A,
B);
315 Signed ? Builder.CreateSExt(
A, WideTy) : Builder.CreateZExt(
A, WideTy);
317 Signed ? Builder.CreateSExt(
B, WideTy) : Builder.CreateZExt(
B, WideTy);
318 Value *Wide = Builder.CreateMul(WideA, WideB);
321 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(
Lo, WideTy));
323 Value *
Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
324 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(WideTy, 0));
326 }
else if (BW == 32) {
330 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
331 Value *
Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {
A,
B});
332 Value *
Hi = Builder.CreateExtractValue(
Mul, 0);
333 Lo = Builder.CreateExtractValue(
Mul, 1);
335 Ov = Builder.CreateICmpNE(
336 Hi, Builder.CreateAShr(
Lo, ConstantInt::get(Ty, BW - 1)));
338 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
340 Lo = Builder.CreateMul(
A,
B);
345 Value *SignShift = ConstantInt::get(Ty, BW - 1);
346 Value *ASign = Builder.CreateAShr(
A, SignShift);
347 Value *BSign = Builder.CreateAShr(
B, SignShift);
348 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(ASign,
B));
349 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(BSign,
A));
350 Ov = Builder.CreateICmpNE(
Hi, Builder.CreateAShr(
Lo, SignShift));
352 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
357 Agg = Builder.CreateInsertValue(Agg,
Lo, 0);
358 return Builder.CreateInsertValue(Agg, Ov, 1);
362 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
363 IntrinsicId == Intrinsic::vector_reduce_fadd);
366 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
369 Type *Ty =
X->getType();
371 unsigned XVecSize = XVec->getNumElements();
372 Value *Sum = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
378 Sum = Builder.CreateFAdd(Sum, StartValue);
382 for (
unsigned I = 1;
I < XVecSize;
I++) {
383 Value *Elt = Builder.CreateExtractElement(
X,
I);
385 Sum = Builder.CreateFAdd(Sum, Elt);
387 Sum = Builder.CreateAdd(Sum, Elt);
396 Type *Ty =
X->getType();
402 ConstantInt::get(EltTy, 0))
403 : ConstantInt::get(EltTy, 0);
404 auto *V = Builder.CreateSub(Zero,
X);
405 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {
X, V},
nullptr,
413 Type *ATy =
A->getType();
414 [[maybe_unused]]
Type *BTy =
B->getType();
424 int NumElts = AVec->getNumElements();
427 DotIntrinsic = Intrinsic::dx_dot2;
430 DotIntrinsic = Intrinsic::dx_dot3;
433 DotIntrinsic = Intrinsic::dx_dot4;
437 "Invalid dot product input vector: length is outside 2-4");
442 for (
int I = 0;
I < NumElts; ++
I)
443 Args.push_back(Builder.CreateExtractElement(
A, Builder.getInt32(
I)));
444 for (
int I = 0;
I < NumElts; ++
I)
445 Args.push_back(Builder.CreateExtractElement(
B, Builder.getInt32(
I)));
446 return Builder.CreateIntrinsic(ATy->
getScalarType(), DotIntrinsic, Args,
461 assert(DotIntrinsic == Intrinsic::dx_sdot ||
462 DotIntrinsic == Intrinsic::dx_udot);
465 Type *ATy =
A->getType();
466 [[maybe_unused]]
Type *BTy =
B->getType();
476 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
478 : Intrinsic::dx_umad;
481 Result = Builder.CreateMul(Elt0, Elt1);
482 for (
unsigned I = 1;
I < AVec->getNumElements();
I++) {
483 Elt0 = Builder.CreateExtractElement(
A,
I);
484 Elt1 = Builder.CreateExtractElement(
B,
I);
485 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
495 Type *Ty =
X->getType();
503 Value *NewX = Builder.CreateFMul(Log2eConst,
X);
504 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
505 Ty, Intrinsic::exp2, {NewX},
nullptr,
"dx.exp2");
517 switch (TCI->getZExtValue()) {
531 Type *FTy =
F->getType();
532 unsigned FNumElem = 0;
538 Type *ElemTy = FVecTy->getElementType();
539 FNumElem = FVecTy->getNumElements();
540 BitWidth = ElemTy->getPrimitiveSizeInBits();
547 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
548 switch (TCI->getZExtValue()) {
555 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
557 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
559 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
571 Type *Ty =
X->getType();
576 if (IntrinsicId == Intrinsic::dx_any)
577 return Builder.CreateOr(Result, Elt);
578 assert(IntrinsicId == Intrinsic::dx_all);
579 return Builder.CreateAnd(Result, Elt);
582 Value *Result =
nullptr;
583 if (!Ty->isVectorTy()) {
585 ? Builder.CreateFCmpUNE(
X, ConstantFP::get(EltTy, 0))
586 : Builder.CreateICmpNE(
X, ConstantInt::get(EltTy, 0));
591 ? Builder.CreateFCmpUNE(
594 ConstantFP::get(EltTy, 0)))
595 : Builder.CreateICmpNE(
598 ConstantInt::get(EltTy, 0)));
599 Result = Builder.CreateExtractElement(
Cond, (
uint64_t)0);
600 for (
unsigned I = 1;
I < XVec->getNumElements();
I++) {
601 Value *Elt = Builder.CreateExtractElement(
Cond,
I);
602 Result = ApplyOp(IntrinsicId, Result, Elt);
613 auto *V = Builder.CreateFSub(
Y,
X);
614 V = Builder.CreateFMul(S, V);
615 return Builder.CreateFAdd(
X, V,
"dx.lerp");
622 Type *Ty =
X->getType();
628 ConstantFP::get(EltTy, LogConstVal))
629 : ConstantFP::get(EltTy, LogConstVal);
630 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
631 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
634 return Builder.CreateFMul(Ln2Const, Log2Call);
651 const APFloat &fpVal = constantFP->getValueAPF();
655 return Builder.CreateFDiv(
X,
X);
663 const APFloat &fpVal = constantFP->getValueAPF();
668 Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
670 nullptr,
"dx.rsqrt");
672 Value *MultiplicandVec =
673 Builder.CreateVectorSplat(XVec->getNumElements(), Multiplicand);
674 return Builder.CreateFMul(
X, MultiplicandVec);
680 Type *Ty =
X->getType();
684 Value *Tan = Builder.CreateFDiv(
Y,
X);
686 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
687 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
695 Constant *Zero = ConstantFP::get(Ty, 0);
696 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
697 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
700 Value *Result = Atan;
701 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
702 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
703 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
704 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
707 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
708 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
711 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
712 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
715 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
716 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
719 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
720 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
725template <
bool LeftFunnel>
734 unsigned BitWidth = Ty->getScalarSizeInBits();
736 "Can't use Mask to compute modulo and inverse");
751 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
756 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
761 Value *NotShift = Builder.CreateNot(Shift);
762 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
764 Constant *One = ConstantInt::get(Ty, 1);
769 ShiftedA = Builder.CreateShl(
A, MaskedShift);
770 Value *ShiftB1 = Builder.CreateLShr(
B, One);
771 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
773 Value *ShiftA1 = Builder.CreateShl(
A, One);
774 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
775 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
778 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
786 Type *Ty =
X->getType();
789 if (IntrinsicId == Intrinsic::powi)
790 Y = Builder.CreateSIToFP(
Y, Ty);
793 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
794 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
795 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
796 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
806 Type *Ty =
X->getType();
809 Constant *One = ConstantFP::get(Ty->getScalarType(), 1.0);
810 Constant *Zero = ConstantFP::get(Ty->getScalarType(), 0.0);
813 if (Ty != Ty->getScalarType()) {
821 return Builder.CreateSelect(
Cond, Zero, One);
826 Type *Ty =
X->getType();
829 return Builder.CreateFMul(
X, PiOver180);
839 "Only expand double or int64 scalars or vectors");
840 bool IsVector =
false;
841 unsigned ExtractNum = 2;
843 ExtractNum = 2 * VT->getNumElements();
845 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
854 while (ExtractNum > 0) {
855 unsigned LoadNum = std::min(ExtractNum, 4u);
859 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
862 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
863 Value *Tmp = Builder.getInt32(4 *
Base * 2);
864 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
867 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
871 Value *Extract = Builder.CreateExtractValue(
Load, {0});
874 for (
unsigned I = 0;
I < LoadNum; ++
I)
876 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
879 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
880 Value *Combined =
nullptr;
883 Combined = Builder.CreateIntrinsic(
884 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
885 {ExtractElements[I], ExtractElements[I + 1]});
890 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
892 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
894 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
896 Combined = Builder.CreateOr(
Lo, ShiftedHi);
900 Result = Builder.CreateInsertElement(Result, Combined,
901 Builder.getInt32((
I / 2) +
Base));
906 ExtractNum -= LoadNum;
910 Value *CheckBit =
nullptr;
921 if (Indices[0] == 0) {
923 EVI->replaceAllUsesWith(Result);
926 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
931 for (
Value *L : Loads)
932 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
933 CheckBit = Builder.CreateAnd(CheckBits);
935 EVI->replaceAllUsesWith(CheckBit);
937 EVI->eraseFromParent();
946 unsigned ValIndex = IsRaw ? 3 : 2;
951 "Only expand double or int64 scalars or vectors");
954 bool IsVector =
false;
955 unsigned ExtractNum = 2;
958 VecLen = VT->getNumElements();
959 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
960 ExtractNum = VecLen * 2;
969 Type *SplitElementTy = Int32Ty;
973 Value *LowBits =
nullptr;
974 Value *HighBits =
nullptr;
978 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
980 LowBits = Builder.CreateExtractValue(Split, 0);
981 HighBits = Builder.CreateExtractValue(Split, 1);
985 Constant *ShiftAmt = Builder.getInt64(32);
991 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
992 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
993 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
998 for (
unsigned I = 0;
I < VecLen; ++
I) {
1000 Mask.push_back(
I + VecLen);
1002 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
1004 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
1005 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
1012 while (ExtractNum > 0) {
1013 unsigned StoreNum = std::min(ExtractNum, 4u);
1015 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
1018 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
1019 Value *Tmp = Builder.getInt32(4 *
Base);
1020 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
1024 for (
unsigned I = 0;
I < StoreNum; ++
I) {
1025 Mask.push_back(
Base +
I);
1028 Value *SubVal = Val;
1030 SubVal = Builder.CreateShuffleVector(Val, Mask);
1032 Args.push_back(SubVal);
1034 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
1036 ExtractNum -= StoreNum;
1044 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1045 return Intrinsic::umax;
1046 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1047 return Intrinsic::smax;
1048 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1049 return Intrinsic::maxnum;
1053 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1054 return Intrinsic::umin;
1055 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1056 return Intrinsic::smin;
1057 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1058 return Intrinsic::minnum;
1066 Type *Ty =
X->getType();
1068 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1069 {
X, Min},
nullptr,
"dx.max");
1070 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1071 {MaxCall, Max},
nullptr,
"dx.min");
1076 Type *Ty =
X->getType();
1079 return Builder.CreateFMul(
X, DegreesRatio);
1084 Type *Ty =
X->getType();
1094 GT = Builder.CreateFCmpOLT(Zero,
X);
1095 LT = Builder.CreateFCmpOLT(
X, Zero);
1098 GT = Builder.CreateICmpSLT(Zero,
X);
1099 LT = Builder.CreateICmpSLT(
X, Zero);
1102 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1103 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1105 return Builder.CreateSub(ZextGT, ZextLT);
1120 Type *EltTy = RetTy->getElementType();
1131 unsigned LHSSize = LHSRows * LHSCols;
1132 unsigned RHSSize = LHSCols * RHSCols;
1135 for (
unsigned I = 0;
I < LHSSize; ++
I)
1136 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1137 for (
unsigned I = 0;
I < RHSSize; ++
I)
1138 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1143 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1144 if (IsFP && !UseScalarFP) {
1147 FloatDotID = Intrinsic::dx_dot2;
1150 FloatDotID = Intrinsic::dx_dot3;
1153 FloatDotID = Intrinsic::dx_dot4;
1157 "Invalid matrix inner dimension for dot product: must be 2-4");
1162 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1163 for (
unsigned R = 0; R < LHSRows; ++R) {
1166 for (
unsigned K = 0; K < LHSCols; ++K) {
1167 RowElts.
push_back(LHSElts[K * LHSRows + R]);
1174 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1175 for (
unsigned K = 1; K < LHSCols; ++K)
1176 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1177 {RowElts[K], ColElts[K], Dot});
1181 Args.append(RowElts.
begin(), RowElts.
end());
1182 Args.append(ColElts.
begin(), ColElts.
end());
1183 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1186 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1187 for (
unsigned K = 1; K < LHSCols; ++K)
1188 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1189 {RowElts[K], ColElts[K], Dot});
1191 unsigned ResIdx =
C * LHSRows + R;
1192 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1206 unsigned NumElts = Rows * Cols;
1208 for (
unsigned I = 0;
I < NumElts; ++
I)
1209 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1212 return Builder.CreateShuffleVector(Mat, Mask);
1216 Value *Result =
nullptr;
1218 switch (IntrinsicId) {
1219 case Intrinsic::abs:
1222 case Intrinsic::assume:
1225 case Intrinsic::atan2:
1228 case Intrinsic::fshl:
1231 case Intrinsic::fshr:
1234 case Intrinsic::exp:
1237 case Intrinsic::is_fpclass:
1240 case Intrinsic::log:
1243 case Intrinsic::log10:
1246 case Intrinsic::pow:
1247 case Intrinsic::powi:
1250 case Intrinsic::dx_all:
1251 case Intrinsic::dx_any:
1254 case Intrinsic::dx_uclamp:
1255 case Intrinsic::dx_sclamp:
1256 case Intrinsic::dx_nclamp:
1259 case Intrinsic::dx_degrees:
1262 case Intrinsic::dx_isinf:
1265 case Intrinsic::dx_isnan:
1268 case Intrinsic::dx_lerp:
1271 case Intrinsic::dx_normalize:
1274 case Intrinsic::dx_fdot:
1277 case Intrinsic::dx_sdot:
1278 case Intrinsic::dx_udot:
1281 case Intrinsic::dx_sign:
1284 case Intrinsic::dx_step:
1287 case Intrinsic::dx_radians:
1290 case Intrinsic::dx_resource_load_rawbuffer:
1294 case Intrinsic::dx_resource_store_rawbuffer:
1298 case Intrinsic::dx_resource_load_typedbuffer:
1302 case Intrinsic::dx_resource_store_typedbuffer:
1306 case Intrinsic::usub_sat:
1309 case Intrinsic::umul_with_overflow:
1310 case Intrinsic::smul_with_overflow:
1312 Intrinsic::smul_with_overflow);
1314 case Intrinsic::vector_reduce_add:
1315 case Intrinsic::vector_reduce_fadd:
1318 case Intrinsic::matrix_multiply:
1321 case Intrinsic::matrix_transpose:
1337 bool IntrinsicExpanded =
false;
1344 if (
F.user_empty() && IntrinsicExpanded)
1345 F.eraseFromParent();
1364 "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 * expandNormalizeIntrinsic(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 * expand16BitIsFinite(CallInst *Orig)
static Value * expandLerpIntrinsic(CallInst *Orig)
static Value * expandUsubSat(CallInst *Orig)
static Value * expandAnyOrAllIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId)
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 * expandStepIntrinsic(CallInst *Orig)
static Value * expandIntegerDotIntrinsic(CallInst *Orig, Intrinsic::ID DotIntrinsic)
static bool expandBufferStoreIntrinsic(CallInst *Orig, bool IsRaw)
static Value * expandLogIntrinsic(CallInst *Orig, float LogConstVal=numbers::ln2f)
static Value * expandDegreesIntrinsic(CallInst *Orig)
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 Value * expandAbs(CallInst *Orig)
static Value * expandFloatDotIntrinsic(CallInst *Orig, Value *A, Value *B)
static Value * expandRadiansIntrinsic(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)
const SmallVectorImpl< MachineOperand > & Cond
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()
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.
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.
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.
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)
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.
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.
iterator_range< user_iterator > users()
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.
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()
Pass to expand intrinsic operations that lack DXIL opCodes.
@ 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.