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_radians:
229 case Intrinsic::usub_sat:
230 case Intrinsic::vector_reduce_add:
231 case Intrinsic::vector_reduce_fadd:
232 case Intrinsic::matrix_multiply:
233 case Intrinsic::matrix_transpose:
234 case Intrinsic::umul_with_overflow:
235 case Intrinsic::smul_with_overflow:
236 case Intrinsic::dx_load_input:
237 case Intrinsic::dx_store_output:
239 case Intrinsic::dx_resource_load_rawbuffer:
241 F.getParent(),
F.getReturnType()->getStructElementType(0),
243 case Intrinsic::dx_resource_load_typedbuffer:
245 F.getParent(),
F.getReturnType()->getStructElementType(0),
247 case Intrinsic::dx_resource_store_rawbuffer:
249 F.getParent(),
F.getFunctionType()->getParamType(3),
true);
250 case Intrinsic::dx_resource_store_typedbuffer:
252 F.getParent(),
F.getFunctionType()->getParamType(2),
false);
260 Type *Ty =
A->getType();
264 Value *Cmp = Builder.CreateICmpULT(
A,
B,
"usub.cmp");
265 Value *
Sub = Builder.CreateSub(
A,
B,
"usub.sub");
266 Value *Zero = ConstantInt::get(Ty, 0);
267 return Builder.CreateSelect(Cmp, Zero,
Sub,
"usub.sat");
274 Type *Ty,
unsigned BW) {
275 assert(BW % 2 == 0 &&
"high-half split needs symmetric halves");
276 unsigned Half = BW / 2;
277 Value *HalfShift = ConstantInt::get(Ty, Half);
280 Value *U0 = Builder.CreateAnd(
A, LoMask);
281 Value *U1 = Builder.CreateLShr(
A, HalfShift);
282 Value *V0 = Builder.CreateAnd(
B, LoMask);
283 Value *
V1 = Builder.CreateLShr(
B, HalfShift);
285 Value *W0 = Builder.CreateMul(U0, V0);
286 Value *
T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
287 Builder.CreateLShr(W0, HalfShift));
288 Value *W1 = Builder.CreateAnd(
T, LoMask);
289 Value *W2 = Builder.CreateLShr(
T, HalfShift);
290 W1 = Builder.CreateAdd(Builder.CreateMul(U0,
V1), W1);
291 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1,
V1), W2),
292 Builder.CreateLShr(W1, HalfShift));
302 Type *Ty =
A->getType();
303 unsigned BW = Ty->getScalarSizeInBits();
313 Lo = Builder.CreateMul(
A,
B);
316 Signed ? Builder.CreateSExt(
A, WideTy) : Builder.CreateZExt(
A, WideTy);
318 Signed ? Builder.CreateSExt(
B, WideTy) : Builder.CreateZExt(
B, WideTy);
319 Value *Wide = Builder.CreateMul(WideA, WideB);
322 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(
Lo, WideTy));
324 Value *
Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
325 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(WideTy, 0));
327 }
else if (BW == 32) {
331 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
332 Value *
Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {
A,
B});
333 Value *
Hi = Builder.CreateExtractValue(
Mul, 0);
334 Lo = Builder.CreateExtractValue(
Mul, 1);
336 Ov = Builder.CreateICmpNE(
337 Hi, Builder.CreateAShr(
Lo, ConstantInt::get(Ty, BW - 1)));
339 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
341 Lo = Builder.CreateMul(
A,
B);
346 Value *SignShift = ConstantInt::get(Ty, BW - 1);
347 Value *ASign = Builder.CreateAShr(
A, SignShift);
348 Value *BSign = Builder.CreateAShr(
B, SignShift);
349 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(ASign,
B));
350 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(BSign,
A));
351 Ov = Builder.CreateICmpNE(
Hi, Builder.CreateAShr(
Lo, SignShift));
353 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
358 Agg = Builder.CreateInsertValue(Agg,
Lo, 0);
359 return Builder.CreateInsertValue(Agg, Ov, 1);
363 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
364 IntrinsicId == Intrinsic::vector_reduce_fadd);
367 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
370 Type *Ty =
X->getType();
372 unsigned XVecSize = XVec->getNumElements();
373 Value *Sum = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
379 Sum = Builder.CreateFAdd(Sum, StartValue);
383 for (
unsigned I = 1;
I < XVecSize;
I++) {
384 Value *Elt = Builder.CreateExtractElement(
X,
I);
386 Sum = Builder.CreateFAdd(Sum, Elt);
388 Sum = Builder.CreateAdd(Sum, Elt);
397 Type *Ty =
X->getType();
403 ConstantInt::get(EltTy, 0))
404 : ConstantInt::get(EltTy, 0);
405 auto *V = Builder.CreateSub(Zero,
X);
406 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {
X, V},
nullptr,
414 Type *ATy =
A->getType();
415 [[maybe_unused]]
Type *BTy =
B->getType();
425 int NumElts = AVec->getNumElements();
428 DotIntrinsic = Intrinsic::dx_dot2;
431 DotIntrinsic = Intrinsic::dx_dot3;
434 DotIntrinsic = Intrinsic::dx_dot4;
438 "Invalid dot product input vector: length is outside 2-4");
443 for (
int I = 0;
I < NumElts; ++
I)
444 Args.push_back(Builder.CreateExtractElement(
A, Builder.getInt32(
I)));
445 for (
int I = 0;
I < NumElts; ++
I)
446 Args.push_back(Builder.CreateExtractElement(
B, Builder.getInt32(
I)));
447 return Builder.CreateIntrinsic(ATy->
getScalarType(), DotIntrinsic, Args,
462 assert(DotIntrinsic == Intrinsic::dx_sdot ||
463 DotIntrinsic == Intrinsic::dx_udot);
466 Type *ATy =
A->getType();
467 [[maybe_unused]]
Type *BTy =
B->getType();
477 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
479 : Intrinsic::dx_umad;
482 Result = Builder.CreateMul(Elt0, Elt1);
483 for (
unsigned I = 1;
I < AVec->getNumElements();
I++) {
484 Elt0 = Builder.CreateExtractElement(
A,
I);
485 Elt1 = Builder.CreateExtractElement(
B,
I);
486 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
496 Type *Ty =
X->getType();
504 Value *NewX = Builder.CreateFMul(Log2eConst,
X);
505 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
506 Ty, Intrinsic::exp2, {NewX},
nullptr,
"dx.exp2");
518 switch (TCI->getZExtValue()) {
532 Type *FTy =
F->getType();
533 unsigned FNumElem = 0;
539 Type *ElemTy = FVecTy->getElementType();
540 FNumElem = FVecTy->getNumElements();
541 BitWidth = ElemTy->getPrimitiveSizeInBits();
548 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
549 switch (TCI->getZExtValue()) {
556 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
558 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
560 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
572 Type *Ty =
X->getType();
577 if (IntrinsicId == Intrinsic::dx_any)
578 return Builder.CreateOr(Result, Elt);
579 assert(IntrinsicId == Intrinsic::dx_all);
580 return Builder.CreateAnd(Result, Elt);
583 Value *Result =
nullptr;
584 if (!Ty->isVectorTy()) {
586 ? Builder.CreateFCmpUNE(
X, ConstantFP::get(EltTy, 0))
587 : Builder.CreateICmpNE(
X, ConstantInt::get(EltTy, 0));
592 ? Builder.CreateFCmpUNE(
595 ConstantFP::get(EltTy, 0)))
596 : Builder.CreateICmpNE(
599 ConstantInt::get(EltTy, 0)));
600 Result = Builder.CreateExtractElement(
Cond, (
uint64_t)0);
601 for (
unsigned I = 1;
I < XVec->getNumElements();
I++) {
602 Value *Elt = Builder.CreateExtractElement(
Cond,
I);
603 Result = ApplyOp(IntrinsicId, Result, Elt);
614 auto *V = Builder.CreateFSub(
Y,
X);
615 V = Builder.CreateFMul(S, V);
616 return Builder.CreateFAdd(
X, V,
"dx.lerp");
623 Type *Ty =
X->getType();
629 ConstantFP::get(EltTy, LogConstVal))
630 : ConstantFP::get(EltTy, LogConstVal);
631 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
632 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
635 return Builder.CreateFMul(Ln2Const, Log2Call);
652 const APFloat &fpVal = constantFP->getValueAPF();
656 return Builder.CreateFDiv(
X,
X);
664 const APFloat &fpVal = constantFP->getValueAPF();
669 Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
671 nullptr,
"dx.rsqrt");
673 Value *MultiplicandVec =
674 Builder.CreateVectorSplat(XVec->getNumElements(), Multiplicand);
675 return Builder.CreateFMul(
X, MultiplicandVec);
681 Type *Ty =
X->getType();
685 Value *Tan = Builder.CreateFDiv(
Y,
X);
687 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
688 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
696 Constant *Zero = ConstantFP::get(Ty, 0);
697 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
698 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
701 Value *Result = Atan;
702 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
703 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
704 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
705 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
708 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
709 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
712 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
713 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
716 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
717 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
720 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
721 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
726template <
bool LeftFunnel>
735 unsigned BitWidth = Ty->getScalarSizeInBits();
737 "Can't use Mask to compute modulo and inverse");
752 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
757 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
762 Value *NotShift = Builder.CreateNot(Shift);
763 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
765 Constant *One = ConstantInt::get(Ty, 1);
770 ShiftedA = Builder.CreateShl(
A, MaskedShift);
771 Value *ShiftB1 = Builder.CreateLShr(
B, One);
772 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
774 Value *ShiftA1 = Builder.CreateShl(
A, One);
775 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
776 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
779 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
787 Type *Ty =
X->getType();
790 if (IntrinsicId == Intrinsic::powi)
791 Y = Builder.CreateSIToFP(
Y, Ty);
794 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
795 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
796 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
797 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
805 Type *Ty =
X->getType();
808 return Builder.CreateFMul(
X, PiOver180);
818 "Only expand double or int64 scalars or vectors");
819 bool IsVector =
false;
820 unsigned ExtractNum = 2;
822 ExtractNum = 2 * VT->getNumElements();
824 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
833 while (ExtractNum > 0) {
834 unsigned LoadNum = std::min(ExtractNum, 4u);
838 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
841 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
842 Value *Tmp = Builder.getInt32(4 *
Base * 2);
843 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
846 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
850 Value *Extract = Builder.CreateExtractValue(
Load, {0});
853 for (
unsigned I = 0;
I < LoadNum; ++
I)
855 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
858 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
859 Value *Combined =
nullptr;
862 Combined = Builder.CreateIntrinsic(
863 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
864 {ExtractElements[I], ExtractElements[I + 1]});
869 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
871 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
873 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
875 Combined = Builder.CreateOr(
Lo, ShiftedHi);
879 Result = Builder.CreateInsertElement(Result, Combined,
880 Builder.getInt32((
I / 2) +
Base));
885 ExtractNum -= LoadNum;
889 Value *CheckBit =
nullptr;
900 if (Indices[0] == 0) {
902 EVI->replaceAllUsesWith(Result);
905 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
910 for (
Value *L : Loads)
911 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
912 CheckBit = Builder.CreateAnd(CheckBits);
914 EVI->replaceAllUsesWith(CheckBit);
916 EVI->eraseFromParent();
925 unsigned ValIndex = IsRaw ? 3 : 2;
930 "Only expand double or int64 scalars or vectors");
933 bool IsVector =
false;
934 unsigned ExtractNum = 2;
937 VecLen = VT->getNumElements();
938 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
939 ExtractNum = VecLen * 2;
948 Type *SplitElementTy = Int32Ty;
952 Value *LowBits =
nullptr;
953 Value *HighBits =
nullptr;
957 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
959 LowBits = Builder.CreateExtractValue(Split, 0);
960 HighBits = Builder.CreateExtractValue(Split, 1);
964 Constant *ShiftAmt = Builder.getInt64(32);
970 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
971 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
972 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
977 for (
unsigned I = 0;
I < VecLen; ++
I) {
979 Mask.push_back(
I + VecLen);
981 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
983 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
984 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
991 while (ExtractNum > 0) {
992 unsigned StoreNum = std::min(ExtractNum, 4u);
994 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
997 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
999 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
1003 for (
unsigned I = 0;
I < StoreNum; ++
I) {
1004 Mask.push_back(
Base +
I);
1007 Value *SubVal = Val;
1009 SubVal = Builder.CreateShuffleVector(Val, Mask);
1011 Args.push_back(SubVal);
1013 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
1015 ExtractNum -= StoreNum;
1023 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1024 return Intrinsic::umax;
1025 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1026 return Intrinsic::smax;
1027 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1028 return Intrinsic::maxnum;
1032 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1033 return Intrinsic::umin;
1034 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1035 return Intrinsic::smin;
1036 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1037 return Intrinsic::minnum;
1045 Type *Ty =
X->getType();
1047 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1048 {
X, Min},
nullptr,
"dx.max");
1049 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1050 {MaxCall, Max},
nullptr,
"dx.min");
1055 Type *Ty =
X->getType();
1058 return Builder.CreateFMul(
X, DegreesRatio);
1063 Type *Ty =
X->getType();
1073 GT = Builder.CreateFCmpOLT(Zero,
X);
1074 LT = Builder.CreateFCmpOLT(
X, Zero);
1077 GT = Builder.CreateICmpSLT(Zero,
X);
1078 LT = Builder.CreateICmpSLT(
X, Zero);
1081 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1082 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1084 return Builder.CreateSub(ZextGT, ZextLT);
1099 Type *EltTy = RetTy->getElementType();
1110 unsigned LHSSize = LHSRows * LHSCols;
1111 unsigned RHSSize = LHSCols * RHSCols;
1114 for (
unsigned I = 0;
I < LHSSize; ++
I)
1115 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1116 for (
unsigned I = 0;
I < RHSSize; ++
I)
1117 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1122 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1123 if (IsFP && !UseScalarFP) {
1126 FloatDotID = Intrinsic::dx_dot2;
1129 FloatDotID = Intrinsic::dx_dot3;
1132 FloatDotID = Intrinsic::dx_dot4;
1136 "Invalid matrix inner dimension for dot product: must be 2-4");
1141 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1142 for (
unsigned R = 0; R < LHSRows; ++R) {
1145 for (
unsigned K = 0; K < LHSCols; ++K) {
1146 RowElts.
push_back(LHSElts[K * LHSRows + R]);
1153 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1154 for (
unsigned K = 1; K < LHSCols; ++K)
1155 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1156 {RowElts[K], ColElts[K], Dot});
1160 Args.append(RowElts.
begin(), RowElts.
end());
1161 Args.append(ColElts.
begin(), ColElts.
end());
1162 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1165 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1166 for (
unsigned K = 1; K < LHSCols; ++K)
1167 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1168 {RowElts[K], ColElts[K], Dot});
1170 unsigned ResIdx =
C * LHSRows + R;
1171 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1185 unsigned NumElts = Rows * Cols;
1187 for (
unsigned I = 0;
I < NumElts; ++
I)
1188 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1191 return Builder.CreateShuffleVector(Mat, Mask);
1206 Type *ScalarTy = VT->getElementType();
1207 unsigned NumElems = VT->getNumElements();
1214 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1217 M, Intrinsic::dx_store_output, {ScalarTy});
1219 for (
unsigned I = 0;
I < NumElems; ++
I) {
1221 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1223 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1224 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1225 Builder.CreateCall(ScalarFn,
1226 {SigpointId, SigElementId, RowIndex, ColI8, Scalar});
1244 Type *ScalarTy = VT->getElementType();
1245 unsigned NumElems = VT->getNumElements();
1252 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1255 M, Intrinsic::dx_load_input, {ScalarTy});
1258 for (
unsigned I = 0;
I < NumElems; ++
I) {
1260 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1261 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1263 Builder.CreateCall(ScalarFn, {SigpointId, SigElementId, RowIndex, ColI8,
1264 GsVertexOrPrimIndex});
1266 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1273 Value *Result =
nullptr;
1275 switch (IntrinsicId) {
1276 case Intrinsic::abs:
1279 case Intrinsic::assume:
1282 case Intrinsic::atan2:
1285 case Intrinsic::fshl:
1288 case Intrinsic::fshr:
1291 case Intrinsic::exp:
1294 case Intrinsic::is_fpclass:
1297 case Intrinsic::log:
1300 case Intrinsic::log10:
1303 case Intrinsic::pow:
1304 case Intrinsic::powi:
1307 case Intrinsic::dx_all:
1308 case Intrinsic::dx_any:
1311 case Intrinsic::dx_uclamp:
1312 case Intrinsic::dx_sclamp:
1313 case Intrinsic::dx_nclamp:
1316 case Intrinsic::dx_degrees:
1319 case Intrinsic::dx_isinf:
1322 case Intrinsic::dx_isnan:
1325 case Intrinsic::dx_lerp:
1328 case Intrinsic::dx_normalize:
1331 case Intrinsic::dx_fdot:
1334 case Intrinsic::dx_sdot:
1335 case Intrinsic::dx_udot:
1338 case Intrinsic::dx_sign:
1341 case Intrinsic::dx_radians:
1344 case Intrinsic::dx_load_input:
1347 case Intrinsic::dx_store_output:
1351 case Intrinsic::dx_resource_load_rawbuffer:
1355 case Intrinsic::dx_resource_store_rawbuffer:
1359 case Intrinsic::dx_resource_load_typedbuffer:
1363 case Intrinsic::dx_resource_store_typedbuffer:
1367 case Intrinsic::usub_sat:
1370 case Intrinsic::umul_with_overflow:
1371 case Intrinsic::smul_with_overflow:
1373 Intrinsic::smul_with_overflow);
1375 case Intrinsic::vector_reduce_add:
1376 case Intrinsic::vector_reduce_fadd:
1379 case Intrinsic::matrix_multiply:
1382 case Intrinsic::matrix_transpose:
1398 bool IntrinsicExpanded =
false;
1405 if (
F.user_empty() && IntrinsicExpanded)
1406 F.eraseFromParent();
1425 "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 * 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.