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:
237 case Intrinsic::dx_load_input:
238 case Intrinsic::dx_store_output:
240 case Intrinsic::dx_resource_load_rawbuffer:
242 F.getParent(),
F.getReturnType()->getStructElementType(0),
244 case Intrinsic::dx_resource_load_typedbuffer:
246 F.getParent(),
F.getReturnType()->getStructElementType(0),
248 case Intrinsic::dx_resource_store_rawbuffer:
250 F.getParent(),
F.getFunctionType()->getParamType(3),
true);
251 case Intrinsic::dx_resource_store_typedbuffer:
253 F.getParent(),
F.getFunctionType()->getParamType(2),
false);
261 Type *Ty =
A->getType();
265 Value *Cmp = Builder.CreateICmpULT(
A,
B,
"usub.cmp");
266 Value *
Sub = Builder.CreateSub(
A,
B,
"usub.sub");
267 Value *Zero = ConstantInt::get(Ty, 0);
268 return Builder.CreateSelect(Cmp, Zero,
Sub,
"usub.sat");
275 Type *Ty,
unsigned BW) {
276 assert(BW % 2 == 0 &&
"high-half split needs symmetric halves");
277 unsigned Half = BW / 2;
278 Value *HalfShift = ConstantInt::get(Ty, Half);
281 Value *U0 = Builder.CreateAnd(
A, LoMask);
282 Value *U1 = Builder.CreateLShr(
A, HalfShift);
283 Value *V0 = Builder.CreateAnd(
B, LoMask);
284 Value *
V1 = Builder.CreateLShr(
B, HalfShift);
286 Value *W0 = Builder.CreateMul(U0, V0);
287 Value *
T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
288 Builder.CreateLShr(W0, HalfShift));
289 Value *W1 = Builder.CreateAnd(
T, LoMask);
290 Value *W2 = Builder.CreateLShr(
T, HalfShift);
291 W1 = Builder.CreateAdd(Builder.CreateMul(U0,
V1), W1);
292 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1,
V1), W2),
293 Builder.CreateLShr(W1, HalfShift));
303 Type *Ty =
A->getType();
304 unsigned BW = Ty->getScalarSizeInBits();
314 Lo = Builder.CreateMul(
A,
B);
317 Signed ? Builder.CreateSExt(
A, WideTy) : Builder.CreateZExt(
A, WideTy);
319 Signed ? Builder.CreateSExt(
B, WideTy) : Builder.CreateZExt(
B, WideTy);
320 Value *Wide = Builder.CreateMul(WideA, WideB);
323 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(
Lo, WideTy));
325 Value *
Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
326 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(WideTy, 0));
328 }
else if (BW == 32) {
332 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
333 Value *
Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {
A,
B});
334 Value *
Hi = Builder.CreateExtractValue(
Mul, 0);
335 Lo = Builder.CreateExtractValue(
Mul, 1);
337 Ov = Builder.CreateICmpNE(
338 Hi, Builder.CreateAShr(
Lo, ConstantInt::get(Ty, BW - 1)));
340 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
342 Lo = Builder.CreateMul(
A,
B);
347 Value *SignShift = ConstantInt::get(Ty, BW - 1);
348 Value *ASign = Builder.CreateAShr(
A, SignShift);
349 Value *BSign = Builder.CreateAShr(
B, SignShift);
350 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(ASign,
B));
351 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(BSign,
A));
352 Ov = Builder.CreateICmpNE(
Hi, Builder.CreateAShr(
Lo, SignShift));
354 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
359 Agg = Builder.CreateInsertValue(Agg,
Lo, 0);
360 return Builder.CreateInsertValue(Agg, Ov, 1);
364 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
365 IntrinsicId == Intrinsic::vector_reduce_fadd);
368 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
371 Type *Ty =
X->getType();
373 unsigned XVecSize = XVec->getNumElements();
374 Value *Sum = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
380 Sum = Builder.CreateFAdd(Sum, StartValue);
384 for (
unsigned I = 1;
I < XVecSize;
I++) {
385 Value *Elt = Builder.CreateExtractElement(
X,
I);
387 Sum = Builder.CreateFAdd(Sum, Elt);
389 Sum = Builder.CreateAdd(Sum, Elt);
398 Type *Ty =
X->getType();
404 ConstantInt::get(EltTy, 0))
405 : ConstantInt::get(EltTy, 0);
406 auto *V = Builder.CreateSub(Zero,
X);
407 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {
X, V},
nullptr,
415 Type *ATy =
A->getType();
416 [[maybe_unused]]
Type *BTy =
B->getType();
426 int NumElts = AVec->getNumElements();
429 DotIntrinsic = Intrinsic::dx_dot2;
432 DotIntrinsic = Intrinsic::dx_dot3;
435 DotIntrinsic = Intrinsic::dx_dot4;
439 "Invalid dot product input vector: length is outside 2-4");
444 for (
int I = 0;
I < NumElts; ++
I)
445 Args.push_back(Builder.CreateExtractElement(
A, Builder.getInt32(
I)));
446 for (
int I = 0;
I < NumElts; ++
I)
447 Args.push_back(Builder.CreateExtractElement(
B, Builder.getInt32(
I)));
448 return Builder.CreateIntrinsic(ATy->
getScalarType(), DotIntrinsic, Args,
463 assert(DotIntrinsic == Intrinsic::dx_sdot ||
464 DotIntrinsic == Intrinsic::dx_udot);
467 Type *ATy =
A->getType();
468 [[maybe_unused]]
Type *BTy =
B->getType();
478 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
480 : Intrinsic::dx_umad;
483 Result = Builder.CreateMul(Elt0, Elt1);
484 for (
unsigned I = 1;
I < AVec->getNumElements();
I++) {
485 Elt0 = Builder.CreateExtractElement(
A,
I);
486 Elt1 = Builder.CreateExtractElement(
B,
I);
487 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
497 Type *Ty =
X->getType();
505 Value *NewX = Builder.CreateFMul(Log2eConst,
X);
506 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
507 Ty, Intrinsic::exp2, {NewX},
nullptr,
"dx.exp2");
519 switch (TCI->getZExtValue()) {
533 Type *FTy =
F->getType();
534 unsigned FNumElem = 0;
540 Type *ElemTy = FVecTy->getElementType();
541 FNumElem = FVecTy->getNumElements();
542 BitWidth = ElemTy->getPrimitiveSizeInBits();
549 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
550 switch (TCI->getZExtValue()) {
557 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
559 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
561 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
573 Type *Ty =
X->getType();
578 if (IntrinsicId == Intrinsic::dx_any)
579 return Builder.CreateOr(Result, Elt);
580 assert(IntrinsicId == Intrinsic::dx_all);
581 return Builder.CreateAnd(Result, Elt);
584 Value *Result =
nullptr;
585 if (!Ty->isVectorTy()) {
587 ? Builder.CreateFCmpUNE(
X, ConstantFP::get(EltTy, 0))
588 : Builder.CreateICmpNE(
X, ConstantInt::get(EltTy, 0));
593 ? Builder.CreateFCmpUNE(
596 ConstantFP::get(EltTy, 0)))
597 : Builder.CreateICmpNE(
600 ConstantInt::get(EltTy, 0)));
601 Result = Builder.CreateExtractElement(
Cond, (
uint64_t)0);
602 for (
unsigned I = 1;
I < XVec->getNumElements();
I++) {
603 Value *Elt = Builder.CreateExtractElement(
Cond,
I);
604 Result = ApplyOp(IntrinsicId, Result, Elt);
615 auto *V = Builder.CreateFSub(
Y,
X);
616 V = Builder.CreateFMul(S, V);
617 return Builder.CreateFAdd(
X, V,
"dx.lerp");
624 Type *Ty =
X->getType();
630 ConstantFP::get(EltTy, LogConstVal))
631 : ConstantFP::get(EltTy, LogConstVal);
632 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
633 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
636 return Builder.CreateFMul(Ln2Const, Log2Call);
653 const APFloat &fpVal = constantFP->getValueAPF();
657 return Builder.CreateFDiv(
X,
X);
665 const APFloat &fpVal = constantFP->getValueAPF();
670 Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
672 nullptr,
"dx.rsqrt");
674 Value *MultiplicandVec =
675 Builder.CreateVectorSplat(XVec->getNumElements(), Multiplicand);
676 return Builder.CreateFMul(
X, MultiplicandVec);
682 Type *Ty =
X->getType();
686 Value *Tan = Builder.CreateFDiv(
Y,
X);
688 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
689 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
697 Constant *Zero = ConstantFP::get(Ty, 0);
698 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
699 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
702 Value *Result = Atan;
703 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
704 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
705 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
706 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
709 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
710 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
713 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
714 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
717 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
718 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
721 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
722 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
727template <
bool LeftFunnel>
736 unsigned BitWidth = Ty->getScalarSizeInBits();
738 "Can't use Mask to compute modulo and inverse");
753 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
758 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
763 Value *NotShift = Builder.CreateNot(Shift);
764 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
766 Constant *One = ConstantInt::get(Ty, 1);
771 ShiftedA = Builder.CreateShl(
A, MaskedShift);
772 Value *ShiftB1 = Builder.CreateLShr(
B, One);
773 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
775 Value *ShiftA1 = Builder.CreateShl(
A, One);
776 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
777 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
780 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
788 Type *Ty =
X->getType();
791 if (IntrinsicId == Intrinsic::powi)
792 Y = Builder.CreateSIToFP(
Y, Ty);
795 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
796 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
797 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
798 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
808 Type *Ty =
X->getType();
811 Constant *One = ConstantFP::get(Ty->getScalarType(), 1.0);
812 Constant *Zero = ConstantFP::get(Ty->getScalarType(), 0.0);
815 if (Ty != Ty->getScalarType()) {
823 return Builder.CreateSelect(
Cond, Zero, One);
828 Type *Ty =
X->getType();
831 return Builder.CreateFMul(
X, PiOver180);
841 "Only expand double or int64 scalars or vectors");
842 bool IsVector =
false;
843 unsigned ExtractNum = 2;
845 ExtractNum = 2 * VT->getNumElements();
847 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
856 while (ExtractNum > 0) {
857 unsigned LoadNum = std::min(ExtractNum, 4u);
861 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
864 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
865 Value *Tmp = Builder.getInt32(4 *
Base * 2);
866 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
869 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
873 Value *Extract = Builder.CreateExtractValue(
Load, {0});
876 for (
unsigned I = 0;
I < LoadNum; ++
I)
878 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
881 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
882 Value *Combined =
nullptr;
885 Combined = Builder.CreateIntrinsic(
886 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
887 {ExtractElements[I], ExtractElements[I + 1]});
892 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
894 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
896 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
898 Combined = Builder.CreateOr(
Lo, ShiftedHi);
902 Result = Builder.CreateInsertElement(Result, Combined,
903 Builder.getInt32((
I / 2) +
Base));
908 ExtractNum -= LoadNum;
912 Value *CheckBit =
nullptr;
923 if (Indices[0] == 0) {
925 EVI->replaceAllUsesWith(Result);
928 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
933 for (
Value *L : Loads)
934 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
935 CheckBit = Builder.CreateAnd(CheckBits);
937 EVI->replaceAllUsesWith(CheckBit);
939 EVI->eraseFromParent();
948 unsigned ValIndex = IsRaw ? 3 : 2;
953 "Only expand double or int64 scalars or vectors");
956 bool IsVector =
false;
957 unsigned ExtractNum = 2;
960 VecLen = VT->getNumElements();
961 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
962 ExtractNum = VecLen * 2;
971 Type *SplitElementTy = Int32Ty;
975 Value *LowBits =
nullptr;
976 Value *HighBits =
nullptr;
980 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
982 LowBits = Builder.CreateExtractValue(Split, 0);
983 HighBits = Builder.CreateExtractValue(Split, 1);
987 Constant *ShiftAmt = Builder.getInt64(32);
993 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
994 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
995 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
1000 for (
unsigned I = 0;
I < VecLen; ++
I) {
1002 Mask.push_back(
I + VecLen);
1004 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
1006 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
1007 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
1014 while (ExtractNum > 0) {
1015 unsigned StoreNum = std::min(ExtractNum, 4u);
1017 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
1020 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
1021 Value *Tmp = Builder.getInt32(4 *
Base);
1022 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
1026 for (
unsigned I = 0;
I < StoreNum; ++
I) {
1027 Mask.push_back(
Base +
I);
1030 Value *SubVal = Val;
1032 SubVal = Builder.CreateShuffleVector(Val, Mask);
1034 Args.push_back(SubVal);
1036 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
1038 ExtractNum -= StoreNum;
1046 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1047 return Intrinsic::umax;
1048 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1049 return Intrinsic::smax;
1050 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1051 return Intrinsic::maxnum;
1055 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1056 return Intrinsic::umin;
1057 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1058 return Intrinsic::smin;
1059 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1060 return Intrinsic::minnum;
1068 Type *Ty =
X->getType();
1070 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1071 {
X, Min},
nullptr,
"dx.max");
1072 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1073 {MaxCall, Max},
nullptr,
"dx.min");
1078 Type *Ty =
X->getType();
1081 return Builder.CreateFMul(
X, DegreesRatio);
1086 Type *Ty =
X->getType();
1096 GT = Builder.CreateFCmpOLT(Zero,
X);
1097 LT = Builder.CreateFCmpOLT(
X, Zero);
1100 GT = Builder.CreateICmpSLT(Zero,
X);
1101 LT = Builder.CreateICmpSLT(
X, Zero);
1104 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1105 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1107 return Builder.CreateSub(ZextGT, ZextLT);
1122 Type *EltTy = RetTy->getElementType();
1133 unsigned LHSSize = LHSRows * LHSCols;
1134 unsigned RHSSize = LHSCols * RHSCols;
1137 for (
unsigned I = 0;
I < LHSSize; ++
I)
1138 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1139 for (
unsigned I = 0;
I < RHSSize; ++
I)
1140 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1145 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1146 if (IsFP && !UseScalarFP) {
1149 FloatDotID = Intrinsic::dx_dot2;
1152 FloatDotID = Intrinsic::dx_dot3;
1155 FloatDotID = Intrinsic::dx_dot4;
1159 "Invalid matrix inner dimension for dot product: must be 2-4");
1164 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1165 for (
unsigned R = 0; R < LHSRows; ++R) {
1168 for (
unsigned K = 0; K < LHSCols; ++K) {
1169 RowElts.
push_back(LHSElts[K * LHSRows + R]);
1176 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1177 for (
unsigned K = 1; K < LHSCols; ++K)
1178 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1179 {RowElts[K], ColElts[K], Dot});
1183 Args.append(RowElts.
begin(), RowElts.
end());
1184 Args.append(ColElts.
begin(), ColElts.
end());
1185 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1188 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1189 for (
unsigned K = 1; K < LHSCols; ++K)
1190 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1191 {RowElts[K], ColElts[K], Dot});
1193 unsigned ResIdx =
C * LHSRows + R;
1194 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1208 unsigned NumElts = Rows * Cols;
1210 for (
unsigned I = 0;
I < NumElts; ++
I)
1211 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1214 return Builder.CreateShuffleVector(Mat, Mask);
1229 Type *ScalarTy = VT->getElementType();
1230 unsigned NumElems = VT->getNumElements();
1237 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1240 M, Intrinsic::dx_store_output, {ScalarTy});
1242 for (
unsigned I = 0;
I < NumElems; ++
I) {
1244 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1246 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1247 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1248 Builder.CreateCall(ScalarFn,
1249 {SigpointId, SigElementId, RowIndex, ColI8, Scalar});
1267 Type *ScalarTy = VT->getElementType();
1268 unsigned NumElems = VT->getNumElements();
1275 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1278 M, Intrinsic::dx_load_input, {ScalarTy});
1281 for (
unsigned I = 0;
I < NumElems; ++
I) {
1283 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1284 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1286 Builder.CreateCall(ScalarFn, {SigpointId, SigElementId, RowIndex, ColI8,
1287 GsVertexOrPrimIndex});
1289 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1296 Value *Result =
nullptr;
1298 switch (IntrinsicId) {
1299 case Intrinsic::abs:
1302 case Intrinsic::assume:
1305 case Intrinsic::atan2:
1308 case Intrinsic::fshl:
1311 case Intrinsic::fshr:
1314 case Intrinsic::exp:
1317 case Intrinsic::is_fpclass:
1320 case Intrinsic::log:
1323 case Intrinsic::log10:
1326 case Intrinsic::pow:
1327 case Intrinsic::powi:
1330 case Intrinsic::dx_all:
1331 case Intrinsic::dx_any:
1334 case Intrinsic::dx_uclamp:
1335 case Intrinsic::dx_sclamp:
1336 case Intrinsic::dx_nclamp:
1339 case Intrinsic::dx_degrees:
1342 case Intrinsic::dx_isinf:
1345 case Intrinsic::dx_isnan:
1348 case Intrinsic::dx_lerp:
1351 case Intrinsic::dx_normalize:
1354 case Intrinsic::dx_fdot:
1357 case Intrinsic::dx_sdot:
1358 case Intrinsic::dx_udot:
1361 case Intrinsic::dx_sign:
1364 case Intrinsic::dx_step:
1367 case Intrinsic::dx_radians:
1370 case Intrinsic::dx_load_input:
1373 case Intrinsic::dx_store_output:
1377 case Intrinsic::dx_resource_load_rawbuffer:
1381 case Intrinsic::dx_resource_store_rawbuffer:
1385 case Intrinsic::dx_resource_load_typedbuffer:
1389 case Intrinsic::dx_resource_store_typedbuffer:
1393 case Intrinsic::usub_sat:
1396 case Intrinsic::umul_with_overflow:
1397 case Intrinsic::smul_with_overflow:
1399 Intrinsic::smul_with_overflow);
1401 case Intrinsic::vector_reduce_add:
1402 case Intrinsic::vector_reduce_fadd:
1405 case Intrinsic::matrix_multiply:
1408 case Intrinsic::matrix_transpose:
1424 bool IntrinsicExpanded =
false;
1431 if (
F.user_empty() && IntrinsicExpanded)
1432 F.eraseFromParent();
1451 "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 * expandLoadInput(CallInst *Orig)
static Value * expandLerpIntrinsic(CallInst *Orig)
static Value * expandUsubSat(CallInst *Orig)
static Value * expandAnyOrAllIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId)
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 * 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)
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.
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.
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()
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.