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_isinf:
220 case Intrinsic::dx_isnan:
221 case Intrinsic::dx_normalize:
222 case Intrinsic::dx_fdot:
223 case Intrinsic::dx_sdot:
224 case Intrinsic::dx_udot:
225 case Intrinsic::dx_sign:
226 case Intrinsic::usub_sat:
227 case Intrinsic::vector_reduce_add:
228 case Intrinsic::vector_reduce_fadd:
229 case Intrinsic::matrix_multiply:
230 case Intrinsic::matrix_transpose:
231 case Intrinsic::umul_with_overflow:
232 case Intrinsic::smul_with_overflow:
233 case Intrinsic::dx_load_input:
234 case Intrinsic::dx_store_output:
236 case Intrinsic::dx_resource_load_rawbuffer:
238 F.getParent(),
F.getReturnType()->getStructElementType(0),
240 case Intrinsic::dx_resource_load_typedbuffer:
242 F.getParent(),
F.getReturnType()->getStructElementType(0),
244 case Intrinsic::dx_resource_store_rawbuffer:
246 F.getParent(),
F.getFunctionType()->getParamType(3),
true);
247 case Intrinsic::dx_resource_store_typedbuffer:
249 F.getParent(),
F.getFunctionType()->getParamType(2),
false);
257 Type *Ty =
A->getType();
261 Value *Cmp = Builder.CreateICmpULT(
A,
B,
"usub.cmp");
262 Value *
Sub = Builder.CreateSub(
A,
B,
"usub.sub");
263 Value *Zero = ConstantInt::get(Ty, 0);
264 return Builder.CreateSelect(Cmp, Zero,
Sub,
"usub.sat");
271 Type *Ty,
unsigned BW) {
272 assert(BW % 2 == 0 &&
"high-half split needs symmetric halves");
273 unsigned Half = BW / 2;
274 Value *HalfShift = ConstantInt::get(Ty, Half);
277 Value *U0 = Builder.CreateAnd(
A, LoMask);
278 Value *U1 = Builder.CreateLShr(
A, HalfShift);
279 Value *V0 = Builder.CreateAnd(
B, LoMask);
280 Value *
V1 = Builder.CreateLShr(
B, HalfShift);
282 Value *W0 = Builder.CreateMul(U0, V0);
283 Value *
T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
284 Builder.CreateLShr(W0, HalfShift));
285 Value *W1 = Builder.CreateAnd(
T, LoMask);
286 Value *W2 = Builder.CreateLShr(
T, HalfShift);
287 W1 = Builder.CreateAdd(Builder.CreateMul(U0,
V1), W1);
288 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1,
V1), W2),
289 Builder.CreateLShr(W1, HalfShift));
299 Type *Ty =
A->getType();
300 unsigned BW = Ty->getScalarSizeInBits();
310 Lo = Builder.CreateMul(
A,
B);
313 Signed ? Builder.CreateSExt(
A, WideTy) : Builder.CreateZExt(
A, WideTy);
315 Signed ? Builder.CreateSExt(
B, WideTy) : Builder.CreateZExt(
B, WideTy);
316 Value *Wide = Builder.CreateMul(WideA, WideB);
319 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(
Lo, WideTy));
321 Value *
Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
322 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(WideTy, 0));
324 }
else if (BW == 32) {
328 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
329 Value *
Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {
A,
B});
330 Value *
Hi = Builder.CreateExtractValue(
Mul, 0);
331 Lo = Builder.CreateExtractValue(
Mul, 1);
333 Ov = Builder.CreateICmpNE(
334 Hi, Builder.CreateAShr(
Lo, ConstantInt::get(Ty, BW - 1)));
336 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
338 Lo = Builder.CreateMul(
A,
B);
343 Value *SignShift = ConstantInt::get(Ty, BW - 1);
344 Value *ASign = Builder.CreateAShr(
A, SignShift);
345 Value *BSign = Builder.CreateAShr(
B, SignShift);
346 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(ASign,
B));
347 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(BSign,
A));
348 Ov = Builder.CreateICmpNE(
Hi, Builder.CreateAShr(
Lo, SignShift));
350 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
355 Agg = Builder.CreateInsertValue(Agg,
Lo, 0);
356 return Builder.CreateInsertValue(Agg, Ov, 1);
360 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
361 IntrinsicId == Intrinsic::vector_reduce_fadd);
364 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
367 Type *Ty =
X->getType();
369 unsigned XVecSize = XVec->getNumElements();
370 Value *Sum = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
376 Sum = Builder.CreateFAdd(Sum, StartValue);
380 for (
unsigned I = 1;
I < XVecSize;
I++) {
381 Value *Elt = Builder.CreateExtractElement(
X,
I);
383 Sum = Builder.CreateFAdd(Sum, Elt);
385 Sum = Builder.CreateAdd(Sum, Elt);
394 Type *Ty =
X->getType();
400 ConstantInt::get(EltTy, 0))
401 : ConstantInt::get(EltTy, 0);
402 auto *V = Builder.CreateSub(Zero,
X);
403 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {
X, V},
nullptr,
411 Type *ATy =
A->getType();
412 [[maybe_unused]]
Type *BTy =
B->getType();
422 int NumElts = AVec->getNumElements();
425 DotIntrinsic = Intrinsic::dx_dot2;
428 DotIntrinsic = Intrinsic::dx_dot3;
431 DotIntrinsic = Intrinsic::dx_dot4;
435 "Invalid dot product input vector: length is outside 2-4");
440 for (
int I = 0;
I < NumElts; ++
I)
441 Args.push_back(Builder.CreateExtractElement(
A, Builder.getInt32(
I)));
442 for (
int I = 0;
I < NumElts; ++
I)
443 Args.push_back(Builder.CreateExtractElement(
B, Builder.getInt32(
I)));
444 return Builder.CreateIntrinsic(ATy->
getScalarType(), DotIntrinsic, Args,
459 assert(DotIntrinsic == Intrinsic::dx_sdot ||
460 DotIntrinsic == Intrinsic::dx_udot);
463 Type *ATy =
A->getType();
464 [[maybe_unused]]
Type *BTy =
B->getType();
474 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
476 : Intrinsic::dx_umad;
479 Result = Builder.CreateMul(Elt0, Elt1);
480 for (
unsigned I = 1;
I < AVec->getNumElements();
I++) {
481 Elt0 = Builder.CreateExtractElement(
A,
I);
482 Elt1 = Builder.CreateExtractElement(
B,
I);
483 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
493 Type *Ty =
X->getType();
501 Value *NewX = Builder.CreateFMul(Log2eConst,
X);
502 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
503 Ty, Intrinsic::exp2, {NewX},
nullptr,
"dx.exp2");
515 switch (TCI->getZExtValue()) {
529 Type *FTy =
F->getType();
530 unsigned FNumElem = 0;
536 Type *ElemTy = FVecTy->getElementType();
537 FNumElem = FVecTy->getNumElements();
538 BitWidth = ElemTy->getPrimitiveSizeInBits();
545 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
546 switch (TCI->getZExtValue()) {
553 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
555 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
557 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
569 Type *Ty =
X->getType();
574 if (IntrinsicId == Intrinsic::dx_any)
575 return Builder.CreateOr(Result, Elt);
576 assert(IntrinsicId == Intrinsic::dx_all);
577 return Builder.CreateAnd(Result, Elt);
580 Value *Result =
nullptr;
581 if (!Ty->isVectorTy()) {
583 ? Builder.CreateFCmpUNE(
X, ConstantFP::get(EltTy, 0))
584 : Builder.CreateICmpNE(
X, ConstantInt::get(EltTy, 0));
589 ? Builder.CreateFCmpUNE(
592 ConstantFP::get(EltTy, 0)))
593 : Builder.CreateICmpNE(
596 ConstantInt::get(EltTy, 0)));
597 Result = Builder.CreateExtractElement(
Cond, (
uint64_t)0);
598 for (
unsigned I = 1;
I < XVec->getNumElements();
I++) {
599 Value *Elt = Builder.CreateExtractElement(
Cond,
I);
600 Result = ApplyOp(IntrinsicId, Result, Elt);
610 Type *Ty =
X->getType();
616 ConstantFP::get(EltTy, LogConstVal))
617 : ConstantFP::get(EltTy, LogConstVal);
618 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
619 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
622 return Builder.CreateFMul(Ln2Const, Log2Call);
639 const APFloat &fpVal = constantFP->getValueAPF();
643 return Builder.CreateFDiv(
X,
X);
651 const APFloat &fpVal = constantFP->getValueAPF();
656 Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
658 nullptr,
"dx.rsqrt");
660 Value *MultiplicandVec =
661 Builder.CreateVectorSplat(XVec->getNumElements(), Multiplicand);
662 return Builder.CreateFMul(
X, MultiplicandVec);
668 Type *Ty =
X->getType();
672 Value *Tan = Builder.CreateFDiv(
Y,
X);
674 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
675 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
683 Constant *Zero = ConstantFP::get(Ty, 0);
684 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
685 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
688 Value *Result = Atan;
689 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
690 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
691 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
692 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
695 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
696 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
699 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
700 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
703 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
704 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
707 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
708 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
713template <
bool LeftFunnel>
722 unsigned BitWidth = Ty->getScalarSizeInBits();
724 "Can't use Mask to compute modulo and inverse");
739 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
744 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
749 Value *NotShift = Builder.CreateNot(Shift);
750 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
752 Constant *One = ConstantInt::get(Ty, 1);
757 ShiftedA = Builder.CreateShl(
A, MaskedShift);
758 Value *ShiftB1 = Builder.CreateLShr(
B, One);
759 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
761 Value *ShiftA1 = Builder.CreateShl(
A, One);
762 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
763 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
766 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
774 Type *Ty =
X->getType();
777 if (IntrinsicId == Intrinsic::powi)
778 Y = Builder.CreateSIToFP(
Y, Ty);
781 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
782 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
783 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
784 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
797 "Only expand double or int64 scalars or vectors");
798 bool IsVector =
false;
799 unsigned ExtractNum = 2;
801 ExtractNum = 2 * VT->getNumElements();
803 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
812 while (ExtractNum > 0) {
813 unsigned LoadNum = std::min(ExtractNum, 4u);
817 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
820 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
821 Value *Tmp = Builder.getInt32(4 *
Base * 2);
822 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
825 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
829 Value *Extract = Builder.CreateExtractValue(
Load, {0});
832 for (
unsigned I = 0;
I < LoadNum; ++
I)
834 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
837 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
838 Value *Combined =
nullptr;
841 Combined = Builder.CreateIntrinsic(
842 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
843 {ExtractElements[I], ExtractElements[I + 1]});
848 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
850 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
852 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
854 Combined = Builder.CreateOr(
Lo, ShiftedHi);
858 Result = Builder.CreateInsertElement(Result, Combined,
859 Builder.getInt32((
I / 2) +
Base));
864 ExtractNum -= LoadNum;
868 Value *CheckBit =
nullptr;
879 if (Indices[0] == 0) {
881 EVI->replaceAllUsesWith(Result);
884 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
889 for (
Value *L : Loads)
890 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
891 CheckBit = Builder.CreateAnd(CheckBits);
893 EVI->replaceAllUsesWith(CheckBit);
895 EVI->eraseFromParent();
904 unsigned ValIndex = IsRaw ? 3 : 2;
909 "Only expand double or int64 scalars or vectors");
912 bool IsVector =
false;
913 unsigned ExtractNum = 2;
916 VecLen = VT->getNumElements();
917 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
918 ExtractNum = VecLen * 2;
927 Type *SplitElementTy = Int32Ty;
931 Value *LowBits =
nullptr;
932 Value *HighBits =
nullptr;
936 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
938 LowBits = Builder.CreateExtractValue(Split, 0);
939 HighBits = Builder.CreateExtractValue(Split, 1);
943 Constant *ShiftAmt = Builder.getInt64(32);
949 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
950 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
951 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
956 for (
unsigned I = 0;
I < VecLen; ++
I) {
958 Mask.push_back(
I + VecLen);
960 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
962 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
963 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
970 while (ExtractNum > 0) {
971 unsigned StoreNum = std::min(ExtractNum, 4u);
973 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
976 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
978 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
982 for (
unsigned I = 0;
I < StoreNum; ++
I) {
983 Mask.push_back(
Base +
I);
988 SubVal = Builder.CreateShuffleVector(Val, Mask);
990 Args.push_back(SubVal);
992 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
994 ExtractNum -= StoreNum;
1002 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1003 return Intrinsic::umax;
1004 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1005 return Intrinsic::smax;
1006 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1007 return Intrinsic::maxnum;
1011 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1012 return Intrinsic::umin;
1013 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1014 return Intrinsic::smin;
1015 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1016 return Intrinsic::minnum;
1024 Type *Ty =
X->getType();
1026 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1027 {
X, Min},
nullptr,
"dx.max");
1028 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1029 {MaxCall, Max},
nullptr,
"dx.min");
1034 Type *Ty =
X->getType();
1044 GT = Builder.CreateFCmpOLT(Zero,
X);
1045 LT = Builder.CreateFCmpOLT(
X, Zero);
1048 GT = Builder.CreateICmpSLT(Zero,
X);
1049 LT = Builder.CreateICmpSLT(
X, Zero);
1052 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1053 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1055 return Builder.CreateSub(ZextGT, ZextLT);
1070 Type *EltTy = RetTy->getElementType();
1081 unsigned LHSSize = LHSRows * LHSCols;
1082 unsigned RHSSize = LHSCols * RHSCols;
1085 for (
unsigned I = 0;
I < LHSSize; ++
I)
1086 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1087 for (
unsigned I = 0;
I < RHSSize; ++
I)
1088 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1093 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1094 if (IsFP && !UseScalarFP) {
1097 FloatDotID = Intrinsic::dx_dot2;
1100 FloatDotID = Intrinsic::dx_dot3;
1103 FloatDotID = Intrinsic::dx_dot4;
1107 "Invalid matrix inner dimension for dot product: must be 2-4");
1112 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1113 for (
unsigned R = 0; R < LHSRows; ++R) {
1116 for (
unsigned K = 0; K < LHSCols; ++K) {
1117 RowElts.
push_back(LHSElts[K * LHSRows + R]);
1124 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1125 for (
unsigned K = 1; K < LHSCols; ++K)
1126 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1127 {RowElts[K], ColElts[K], Dot});
1131 Args.append(RowElts.
begin(), RowElts.
end());
1132 Args.append(ColElts.
begin(), ColElts.
end());
1133 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1136 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1137 for (
unsigned K = 1; K < LHSCols; ++K)
1138 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1139 {RowElts[K], ColElts[K], Dot});
1141 unsigned ResIdx =
C * LHSRows + R;
1142 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1156 unsigned NumElts = Rows * Cols;
1158 for (
unsigned I = 0;
I < NumElts; ++
I)
1159 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1162 return Builder.CreateShuffleVector(Mat, Mask);
1177 Type *ScalarTy = VT->getElementType();
1178 unsigned NumElems = VT->getNumElements();
1184 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1187 M, Intrinsic::dx_store_output, {ScalarTy});
1189 for (
unsigned I = 0;
I < NumElems; ++
I) {
1191 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1193 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1194 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1195 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
1213 Type *ScalarTy = VT->getElementType();
1214 unsigned NumElems = VT->getNumElements();
1220 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1223 M, Intrinsic::dx_load_input, {ScalarTy});
1226 for (
unsigned I = 0;
I < NumElems; ++
I) {
1228 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1229 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1230 Value *Scalar = Builder.CreateCall(
1231 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1233 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1240 Value *Result =
nullptr;
1242 switch (IntrinsicId) {
1243 case Intrinsic::abs:
1246 case Intrinsic::assume:
1249 case Intrinsic::atan2:
1252 case Intrinsic::fshl:
1255 case Intrinsic::fshr:
1258 case Intrinsic::exp:
1261 case Intrinsic::is_fpclass:
1264 case Intrinsic::log:
1267 case Intrinsic::log10:
1270 case Intrinsic::pow:
1271 case Intrinsic::powi:
1274 case Intrinsic::dx_all:
1275 case Intrinsic::dx_any:
1278 case Intrinsic::dx_uclamp:
1279 case Intrinsic::dx_sclamp:
1280 case Intrinsic::dx_nclamp:
1283 case Intrinsic::dx_isinf:
1286 case Intrinsic::dx_isnan:
1289 case Intrinsic::dx_normalize:
1292 case Intrinsic::dx_fdot:
1295 case Intrinsic::dx_sdot:
1296 case Intrinsic::dx_udot:
1299 case Intrinsic::dx_sign:
1302 case Intrinsic::dx_load_input:
1305 case Intrinsic::dx_store_output:
1309 case Intrinsic::dx_resource_load_rawbuffer:
1313 case Intrinsic::dx_resource_store_rawbuffer:
1317 case Intrinsic::dx_resource_load_typedbuffer:
1321 case Intrinsic::dx_resource_store_typedbuffer:
1325 case Intrinsic::usub_sat:
1328 case Intrinsic::umul_with_overflow:
1329 case Intrinsic::smul_with_overflow:
1331 Intrinsic::smul_with_overflow);
1333 case Intrinsic::vector_reduce_add:
1334 case Intrinsic::vector_reduce_fadd:
1337 case Intrinsic::matrix_multiply:
1340 case Intrinsic::matrix_transpose:
1356 bool IntrinsicExpanded =
false;
1363 if (
F.user_empty() && IntrinsicExpanded)
1364 F.eraseFromParent();
1383 "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 * 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 * expandIntegerDotIntrinsic(CallInst *Orig, Intrinsic::ID DotIntrinsic)
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 Value * expandAbs(CallInst *Orig)
static Value * expandFloatDotIntrinsic(CallInst *Orig, Value *A, Value *B)
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.