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 assert(
F.getIntrinsicID() == Intrinsic::dx_fdot &&
203 "Function is not a dx.fdot intrinsic");
205 return ParamTy->getNumElements() <= 4 ||
206 F.getParent()->getTargetTriple().getOSVersion() <
VersionTuple(6, 9);
210 switch (
F.getIntrinsicID()) {
211 case Intrinsic::assume:
213 case Intrinsic::atan2:
214 case Intrinsic::copysign:
215 case Intrinsic::fshl:
216 case Intrinsic::fshr:
218 case Intrinsic::is_fpclass:
220 case Intrinsic::log10:
222 case Intrinsic::powi:
223 case Intrinsic::dx_all:
224 case Intrinsic::dx_any:
225 case Intrinsic::dx_uclamp:
226 case Intrinsic::dx_sclamp:
227 case Intrinsic::dx_nclamp:
228 case Intrinsic::dx_isinf:
229 case Intrinsic::dx_isnan:
230 case Intrinsic::dx_normalize:
231 case Intrinsic::dx_sdot:
232 case Intrinsic::dx_udot:
233 case Intrinsic::dx_sign:
234 case Intrinsic::usub_sat:
235 case Intrinsic::vector_reduce_add:
236 case Intrinsic::vector_reduce_fadd:
237 case Intrinsic::matrix_multiply:
238 case Intrinsic::matrix_transpose:
239 case Intrinsic::umul_with_overflow:
240 case Intrinsic::smul_with_overflow:
241 case Intrinsic::dx_load_input:
242 case Intrinsic::dx_store_output:
244 case Intrinsic::dx_fdot:
246 case Intrinsic::dx_resource_load_rawbuffer:
248 F.getParent(),
F.getReturnType()->getStructElementType(0),
250 case Intrinsic::dx_resource_load_typedbuffer:
252 F.getParent(),
F.getReturnType()->getStructElementType(0),
254 case Intrinsic::dx_resource_store_rawbuffer:
256 F.getParent(),
F.getFunctionType()->getParamType(3),
true);
257 case Intrinsic::dx_resource_store_typedbuffer:
259 F.getParent(),
F.getFunctionType()->getParamType(2),
false);
267 Type *Ty =
A->getType();
271 Value *Cmp = Builder.CreateICmpULT(
A,
B,
"usub.cmp");
272 Value *
Sub = Builder.CreateSub(
A,
B,
"usub.sub");
273 Value *Zero = ConstantInt::get(Ty, 0);
274 return Builder.CreateSelect(Cmp, Zero,
Sub,
"usub.sat");
281 Type *Ty,
unsigned BW) {
282 assert(BW % 2 == 0 &&
"high-half split needs symmetric halves");
283 unsigned Half = BW / 2;
284 Value *HalfShift = ConstantInt::get(Ty, Half);
287 Value *U0 = Builder.CreateAnd(
A, LoMask);
288 Value *U1 = Builder.CreateLShr(
A, HalfShift);
289 Value *V0 = Builder.CreateAnd(
B, LoMask);
290 Value *
V1 = Builder.CreateLShr(
B, HalfShift);
292 Value *W0 = Builder.CreateMul(U0, V0);
293 Value *
T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
294 Builder.CreateLShr(W0, HalfShift));
295 Value *W1 = Builder.CreateAnd(
T, LoMask);
296 Value *W2 = Builder.CreateLShr(
T, HalfShift);
297 W1 = Builder.CreateAdd(Builder.CreateMul(U0,
V1), W1);
298 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1,
V1), W2),
299 Builder.CreateLShr(W1, HalfShift));
309 Type *Ty =
A->getType();
310 unsigned BW = Ty->getScalarSizeInBits();
320 Lo = Builder.CreateMul(
A,
B);
323 Signed ? Builder.CreateSExt(
A, WideTy) : Builder.CreateZExt(
A, WideTy);
325 Signed ? Builder.CreateSExt(
B, WideTy) : Builder.CreateZExt(
B, WideTy);
326 Value *Wide = Builder.CreateMul(WideA, WideB);
329 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(
Lo, WideTy));
331 Value *
Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
332 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(WideTy, 0));
334 }
else if (BW == 32) {
338 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
339 Value *
Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {
A,
B});
340 Value *
Hi = Builder.CreateExtractValue(
Mul, 0);
341 Lo = Builder.CreateExtractValue(
Mul, 1);
343 Ov = Builder.CreateICmpNE(
344 Hi, Builder.CreateAShr(
Lo, ConstantInt::get(Ty, BW - 1)));
346 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
348 Lo = Builder.CreateMul(
A,
B);
353 Value *SignShift = ConstantInt::get(Ty, BW - 1);
354 Value *ASign = Builder.CreateAShr(
A, SignShift);
355 Value *BSign = Builder.CreateAShr(
B, SignShift);
356 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(ASign,
B));
357 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(BSign,
A));
358 Ov = Builder.CreateICmpNE(
Hi, Builder.CreateAShr(
Lo, SignShift));
360 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
365 Agg = Builder.CreateInsertValue(Agg,
Lo, 0);
366 return Builder.CreateInsertValue(Agg, Ov, 1);
370 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
371 IntrinsicId == Intrinsic::vector_reduce_fadd);
374 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
377 Type *Ty =
X->getType();
379 unsigned XVecSize = XVec->getNumElements();
380 Value *Sum = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
386 Sum = Builder.CreateFAdd(Sum, StartValue);
390 for (
unsigned I = 1;
I < XVecSize;
I++) {
391 Value *Elt = Builder.CreateExtractElement(
X,
I);
393 Sum = Builder.CreateFAdd(Sum, Elt);
395 Sum = Builder.CreateAdd(Sum, Elt);
404 Type *Ty =
X->getType();
410 ConstantInt::get(EltTy, 0))
411 : ConstantInt::get(EltTy, 0);
412 auto *V = Builder.CreateSub(Zero,
X);
413 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {
X, V},
nullptr,
419 Type *ATy =
A->getType();
420 [[maybe_unused]]
Type *BTy =
B->getType();
429 unsigned NumElts = AVec->getNumElements();
433 DotIntrinsic = Intrinsic::dx_dot2;
436 DotIntrinsic = Intrinsic::dx_dot3;
439 DotIntrinsic = Intrinsic::dx_dot4;
443 "Invalid dot product input vector: length is outside 2-4");
447 for (
unsigned I = 0;
I < NumElts; ++
I)
448 Args.push_back(Builder.CreateExtractElement(
A, Builder.getInt32(
I)));
449 for (
unsigned I = 0;
I < NumElts; ++
I)
450 Args.push_back(Builder.CreateExtractElement(
B, Builder.getInt32(
I)));
451 return Builder.CreateIntrinsic(ATy->
getScalarType(), DotIntrinsic, Args,
468 "long fdot must not be expanded for shader model 6.9 or later");
471 Value *Result =
nullptr;
473 unsigned Remaining = NumElts -
Offset;
476 unsigned ChunkSize = Remaining == 5 ? 3 : std::min(Remaining, 4u);
478 for (
unsigned I = 0;
I < ChunkSize; ++
I)
480 Value *AChunk = Builder.CreateShuffleVector(
A, Mask);
481 Value *BChunk = Builder.CreateShuffleVector(
B, Mask);
483 Result = Result ? Builder.CreateFAdd(Result, Chunk,
"dot.add") : Chunk;
492 assert(DotIntrinsic == Intrinsic::dx_sdot ||
493 DotIntrinsic == Intrinsic::dx_udot);
496 Type *ATy =
A->getType();
497 [[maybe_unused]]
Type *BTy =
B->getType();
507 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
509 : Intrinsic::dx_umad;
512 Result = Builder.CreateMul(Elt0, Elt1);
513 for (
unsigned I = 1;
I < AVec->getNumElements();
I++) {
514 Elt0 = Builder.CreateExtractElement(
A,
I);
515 Elt1 = Builder.CreateExtractElement(
B,
I);
516 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
526 Type *Ty =
X->getType();
534 Value *NewX = Builder.CreateFMul(Log2eConst,
X);
535 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
536 Ty, Intrinsic::exp2, {NewX},
nullptr,
"dx.exp2");
548 switch (TCI->getZExtValue()) {
562 Type *FTy =
F->getType();
563 unsigned FNumElem = 0;
569 Type *ElemTy = FVecTy->getElementType();
570 FNumElem = FVecTy->getNumElements();
571 BitWidth = ElemTy->getPrimitiveSizeInBits();
578 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
579 switch (TCI->getZExtValue()) {
586 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
588 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
590 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
602 Type *Ty =
X->getType();
607 if (IntrinsicId == Intrinsic::dx_any)
608 return Builder.CreateOr(Result, Elt);
609 assert(IntrinsicId == Intrinsic::dx_all);
610 return Builder.CreateAnd(Result, Elt);
613 Value *Result =
nullptr;
614 if (!Ty->isVectorTy()) {
616 ? Builder.CreateFCmpUNE(
X, ConstantFP::get(EltTy, 0))
617 : Builder.CreateICmpNE(
X, ConstantInt::get(EltTy, 0));
622 ? Builder.CreateFCmpUNE(
625 ConstantFP::get(EltTy, 0)))
626 : Builder.CreateICmpNE(
629 ConstantInt::get(EltTy, 0)));
630 Result = Builder.CreateExtractElement(
Cond, (
uint64_t)0);
631 for (
unsigned I = 1;
I < XVec->getNumElements();
I++) {
632 Value *Elt = Builder.CreateExtractElement(
Cond,
I);
633 Result = ApplyOp(IntrinsicId, Result, Elt);
643 Type *Ty =
X->getType();
649 ConstantFP::get(EltTy, LogConstVal))
650 : ConstantFP::get(EltTy, LogConstVal);
651 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
652 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
655 return Builder.CreateFMul(Ln2Const, Log2Call);
672 const APFloat &fpVal = constantFP->getValueAPF();
676 return Builder.CreateFDiv(
X,
X);
684 const APFloat &fpVal = constantFP->getValueAPF();
689 Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
691 nullptr,
"dx.rsqrt");
693 Value *MultiplicandVec =
694 Builder.CreateVectorSplat(XVec->getNumElements(), Multiplicand);
695 return Builder.CreateFMul(
X, MultiplicandVec);
701 Type *Ty =
X->getType();
705 Value *Tan = Builder.CreateFDiv(
Y,
X);
707 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
708 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
716 Constant *Zero = ConstantFP::get(Ty, 0);
717 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
718 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
721 Value *Result = Atan;
722 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
723 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
724 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
725 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
728 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
729 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
732 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
733 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
736 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
737 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
740 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
741 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
746template <
bool LeftFunnel>
755 unsigned BitWidth = Ty->getScalarSizeInBits();
757 "Can't use Mask to compute modulo and inverse");
772 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
777 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
782 Value *NotShift = Builder.CreateNot(Shift);
783 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
785 Constant *One = ConstantInt::get(Ty, 1);
790 ShiftedA = Builder.CreateShl(
A, MaskedShift);
791 Value *ShiftB1 = Builder.CreateLShr(
B, One);
792 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
794 Value *ShiftA1 = Builder.CreateShl(
A, One);
795 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
796 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
799 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
807 Type *Ty =
X->getType();
810 if (IntrinsicId == Intrinsic::powi)
811 Y = Builder.CreateSIToFP(
Y, Ty);
814 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
815 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
816 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
817 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
830 "Only expand double or int64 scalars or vectors");
831 bool IsVector =
false;
832 unsigned ExtractNum = 2;
834 ExtractNum = 2 * VT->getNumElements();
836 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
845 while (ExtractNum > 0) {
846 unsigned LoadNum = std::min(ExtractNum, 4u);
850 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
853 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
854 Value *Tmp = Builder.getInt32(4 *
Base * 2);
855 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
858 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
862 Value *Extract = Builder.CreateExtractValue(
Load, {0});
865 for (
unsigned I = 0;
I < LoadNum; ++
I)
867 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
870 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
871 Value *Combined =
nullptr;
874 Combined = Builder.CreateIntrinsic(
875 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
876 {ExtractElements[I], ExtractElements[I + 1]});
881 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
883 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
885 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
887 Combined = Builder.CreateOr(
Lo, ShiftedHi);
891 Result = Builder.CreateInsertElement(Result, Combined,
892 Builder.getInt32((
I / 2) +
Base));
897 ExtractNum -= LoadNum;
901 Value *CheckBit =
nullptr;
912 if (Indices[0] == 0) {
914 EVI->replaceAllUsesWith(Result);
917 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
922 for (
Value *L : Loads)
923 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
924 CheckBit = Builder.CreateAnd(CheckBits);
926 EVI->replaceAllUsesWith(CheckBit);
928 EVI->eraseFromParent();
937 unsigned ValIndex = IsRaw ? 3 : 2;
942 "Only expand double or int64 scalars or vectors");
945 bool IsVector =
false;
946 unsigned ExtractNum = 2;
949 VecLen = VT->getNumElements();
950 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
951 ExtractNum = VecLen * 2;
960 Type *SplitElementTy = Int32Ty;
964 Value *LowBits =
nullptr;
965 Value *HighBits =
nullptr;
969 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
971 LowBits = Builder.CreateExtractValue(Split, 0);
972 HighBits = Builder.CreateExtractValue(Split, 1);
976 Constant *ShiftAmt = Builder.getInt64(32);
982 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
983 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
984 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
989 for (
unsigned I = 0;
I < VecLen; ++
I) {
991 Mask.push_back(
I + VecLen);
993 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
995 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
996 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
1003 while (ExtractNum > 0) {
1004 unsigned StoreNum = std::min(ExtractNum, 4u);
1006 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
1009 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
1010 Value *Tmp = Builder.getInt32(4 *
Base);
1011 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
1015 for (
unsigned I = 0;
I < StoreNum; ++
I) {
1016 Mask.push_back(
Base +
I);
1019 Value *SubVal = Val;
1021 SubVal = Builder.CreateShuffleVector(Val, Mask);
1023 Args.push_back(SubVal);
1025 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
1027 ExtractNum -= StoreNum;
1035 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1036 return Intrinsic::umax;
1037 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1038 return Intrinsic::smax;
1039 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1040 return Intrinsic::maxnum;
1044 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1045 return Intrinsic::umin;
1046 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1047 return Intrinsic::smin;
1048 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1049 return Intrinsic::minnum;
1057 Type *Ty =
X->getType();
1059 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1060 {
X, Min},
nullptr,
"dx.max");
1061 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1062 {MaxCall, Max},
nullptr,
"dx.min");
1067 Type *Ty =
X->getType();
1077 GT = Builder.CreateFCmpOLT(Zero,
X);
1078 LT = Builder.CreateFCmpOLT(
X, Zero);
1081 GT = Builder.CreateICmpSLT(Zero,
X);
1082 LT = Builder.CreateICmpSLT(
X, Zero);
1085 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1086 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1088 return Builder.CreateSub(ZextGT, ZextLT);
1100 bool IsDouble = Ty->getScalarType()->isDoubleTy();
1101 unsigned BitWidth = IsDouble ? 32 : Ty->getScalarSizeInBits();
1104 auto CopySignBit = [&](
Value *MagnitudeInt,
Value *SignInt) {
1107 Constant *SignMask = ConstantInt::get(IntTy, SignMaskVal);
1108 Constant *NotSignMask = ConstantInt::get(IntTy, ~SignMaskVal);
1110 Value *MagnitudeBits = Builder.CreateAnd(MagnitudeInt, NotSignMask);
1111 Value *SignBits = Builder.CreateAnd(SignInt, SignMask);
1112 return Builder.CreateOr(MagnitudeBits, SignBits);
1118 Value *MagnitudeHalves = Builder.CreateIntrinsic(
1119 SplitTy, Intrinsic::dx_splitdouble, {Magnitude});
1121 Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble, {Sign});
1122 Value *MagnitudeLow = Builder.CreateExtractValue(MagnitudeHalves, 0);
1123 Value *MagnitudeHigh = Builder.CreateExtractValue(MagnitudeHalves, 1);
1124 Value *SignHigh = Builder.CreateExtractValue(SignHalves, 1);
1126 Value *CombinedHigh = CopySignBit(MagnitudeHigh, SignHigh);
1127 return Builder.CreateIntrinsic(Ty, Intrinsic::dx_asdouble,
1128 {MagnitudeLow, CombinedHigh});
1131 Value *MagnitudeInt = Builder.CreateBitCast(Magnitude, IntTy);
1132 Value *SignInt = Builder.CreateBitCast(Sign, IntTy);
1133 Value *CombinedInt = CopySignBit(MagnitudeInt, SignInt);
1134 return Builder.CreateBitCast(CombinedInt, Ty);
1149 Type *EltTy = RetTy->getElementType();
1160 unsigned LHSSize = LHSRows * LHSCols;
1161 unsigned RHSSize = LHSCols * RHSCols;
1164 for (
unsigned I = 0;
I < LHSSize; ++
I)
1165 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1166 for (
unsigned I = 0;
I < RHSSize; ++
I)
1167 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1172 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1173 if (IsFP && !UseScalarFP) {
1176 FloatDotID = Intrinsic::dx_dot2;
1179 FloatDotID = Intrinsic::dx_dot3;
1182 FloatDotID = Intrinsic::dx_dot4;
1186 "Invalid matrix inner dimension for dot product: must be 2-4");
1191 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1192 for (
unsigned R = 0; R < LHSRows; ++R) {
1195 for (
unsigned K = 0; K < LHSCols; ++K) {
1196 RowElts.
push_back(LHSElts[K * LHSRows + R]);
1203 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1204 for (
unsigned K = 1; K < LHSCols; ++K)
1205 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1206 {RowElts[K], ColElts[K], Dot});
1210 Args.append(RowElts.
begin(), RowElts.
end());
1211 Args.append(ColElts.
begin(), ColElts.
end());
1212 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1215 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1216 for (
unsigned K = 1; K < LHSCols; ++K)
1217 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1218 {RowElts[K], ColElts[K], Dot});
1220 unsigned ResIdx =
C * LHSRows + R;
1221 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1235 unsigned NumElts = Rows * Cols;
1237 for (
unsigned I = 0;
I < NumElts; ++
I)
1238 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1241 return Builder.CreateShuffleVector(Mat, Mask);
1256 Type *ScalarTy = VT->getElementType();
1257 unsigned NumElems = VT->getNumElements();
1263 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1266 M, Intrinsic::dx_store_output, {ScalarTy});
1268 for (
unsigned I = 0;
I < NumElems; ++
I) {
1270 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1272 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1273 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1274 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
1292 Type *ScalarTy = VT->getElementType();
1293 unsigned NumElems = VT->getNumElements();
1299 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1302 M, Intrinsic::dx_load_input, {ScalarTy});
1305 for (
unsigned I = 0;
I < NumElems; ++
I) {
1307 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1308 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1309 Value *Scalar = Builder.CreateCall(
1310 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1312 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1319 Value *Result =
nullptr;
1321 switch (IntrinsicId) {
1322 case Intrinsic::abs:
1325 case Intrinsic::assume:
1328 case Intrinsic::atan2:
1331 case Intrinsic::copysign:
1334 case Intrinsic::fshl:
1337 case Intrinsic::fshr:
1340 case Intrinsic::exp:
1343 case Intrinsic::is_fpclass:
1346 case Intrinsic::log:
1349 case Intrinsic::log10:
1352 case Intrinsic::pow:
1353 case Intrinsic::powi:
1356 case Intrinsic::dx_all:
1357 case Intrinsic::dx_any:
1360 case Intrinsic::dx_uclamp:
1361 case Intrinsic::dx_sclamp:
1362 case Intrinsic::dx_nclamp:
1365 case Intrinsic::dx_isinf:
1368 case Intrinsic::dx_isnan:
1371 case Intrinsic::dx_normalize:
1374 case Intrinsic::dx_fdot:
1377 case Intrinsic::dx_sdot:
1378 case Intrinsic::dx_udot:
1381 case Intrinsic::dx_sign:
1384 case Intrinsic::dx_load_input:
1387 case Intrinsic::dx_store_output:
1391 case Intrinsic::dx_resource_load_rawbuffer:
1395 case Intrinsic::dx_resource_store_rawbuffer:
1399 case Intrinsic::dx_resource_load_typedbuffer:
1403 case Intrinsic::dx_resource_store_typedbuffer:
1407 case Intrinsic::usub_sat:
1410 case Intrinsic::umul_with_overflow:
1411 case Intrinsic::smul_with_overflow:
1413 Intrinsic::smul_with_overflow);
1415 case Intrinsic::vector_reduce_add:
1416 case Intrinsic::vector_reduce_fadd:
1419 case Intrinsic::matrix_multiply:
1422 case Intrinsic::matrix_transpose:
1438 bool IntrinsicExpanded =
false;
1445 if (
F.user_empty() && IntrinsicExpanded)
1446 F.eraseFromParent();
1465 "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 * expandCopySignIntrinsic(CallInst *Orig)
static Value * expand16BitIsFinite(CallInst *Orig)
static Value * expandLoadInput(CallInst *Orig)
static Value * expandUsubSat(CallInst *Orig)
static Value * expandAnyOrAllIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId)
static Value * expandFloatDotIntrinsic(CallInst *Orig)
static bool expandStoreOutput(CallInst *Orig)
static Value * expandMatrixTranspose(CallInst *Orig)
static Value * expandVecReduceAdd(CallInst *Orig, Intrinsic::ID IntrinsicId)
static Value * expandAtan2Intrinsic(CallInst *Orig)
static Value * expandLog10Intrinsic(CallInst *Orig)
static Intrinsic::ID getMinForClamp(Intrinsic::ID ClampIntrinsic)
static Value * expandIntegerDotIntrinsic(CallInst *Orig, Intrinsic::ID DotIntrinsic)
static bool expandBufferStoreIntrinsic(CallInst *Orig, bool IsRaw)
static Value * expandLogIntrinsic(CallInst *Orig, float LogConstVal=numbers::ln2f)
static Value * expandMulWithOverflow(CallInst *Orig, bool Signed)
static Value * expandPowIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId)
static bool resourceAccessNeeds64BitExpansion(Module *M, Type *OverloadTy, bool IsRaw)
static Value * expandExpIntrinsic(CallInst *Orig)
static Value * expand16BitIsNaN(CallInst *Orig)
static Value * expandSignIntrinsic(CallInst *Orig)
static Intrinsic::ID getMaxForClamp(Intrinsic::ID ClampIntrinsic)
static bool shouldExpandFloatDotIntrinsic(Function &F)
static Value * expandFloatDotChunk(CallInst *Orig, Value *A, Value *B)
static Value * expandAbs(CallInst *Orig)
static bool isIntrinsicExpansion(Function &F)
static bool expandBufferLoadIntrinsic(CallInst *Orig, bool IsRaw)
static Value * expandMatrixMultiply(CallInst *Orig)
static Value * expandIsFPClass(CallInst *Orig)
static Value * expandFunnelShiftIntrinsic(CallInst *Orig)
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
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()
Class for arbitrary precision integers.
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
void setAttributes(AttributeList A)
Set the attributes for this call.
Value * getArgOperand(unsigned i) const
FunctionType * getFunctionType() const
AttributeList getAttributes() const
Return the attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
void setTailCall(bool IsTc=true)
static LLVM_ABI Constant * getSplat(ElementCount EC, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
This is an important base class in LLVM.
bool isNullValue() const
Return true if this is the value that would be returned by getNullValue.
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
PreservedAnalyses run(Module &M, ModuleAnalysisManager &)
static constexpr ElementCount getFixed(ScalarTy MinVal)
static LLVM_ABI FixedVectorType * get(Type *ElementType, unsigned NumElts)
Type * getParamType(unsigned i) const
Parameter type accessors.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI const Module * getModule() const
Return the module owning the function this instruction belongs to or nullptr it the function does not...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI FastMathFlags getFastMathFlags() const LLVM_READONLY
Convenience function for getting all the fast-math flags, which must be an operator which supports th...
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
A Module instance is used to store all the information related to an LLVM module.
const Triple & getTargetTriple() const
Get the target triple which is a string describing the target host.
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
static LLVM_ABI StructType * get(LLVMContext &Context, ArrayRef< Type * > Elements, bool isPacked=false)
This static method is the primary way to create a literal StructType.
LLVM_ABI VersionTuple getOSVersion() const
Parse the version number from the OS name component of the triple, if present.
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM_ABI Type * getStructElementType(unsigned N) const
bool isVectorTy() const
True if this is an instance of VectorType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
static LLVM_ABI IntegerType * getInt8Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
LLVM_ABI Type * getWithNewBitWidth(unsigned NewBitWidth) const
Given an integer or vector type, change the lane bitwidth to NewBitwidth, whilst keeping the old numb...
static LLVM_ABI IntegerType * getInt16Ty(LLVMContext &C)
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
LLVM_ABI Type * getWithNewType(Type *EltTy) const
Given vector type, change the element type, whilst keeping the old number of elements.
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
bool isFloatingPointTy() const
Return true if this is one of the floating-point types.
bool isIntegerTy() const
True if this is an instance of IntegerType.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
Value * getOperand(unsigned i) const
LLVM Value Representation.
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
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.