24#include "llvm/IR/IntrinsicsDirectX.h"
34#define DEBUG_TYPE "dxil-intrinsic-expansion"
49 if (IsRaw && M->getTargetTriple().getDXILVersion() >
VersionTuple(1, 2))
58 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
73 ConstantInt::get(IType, 0x7c00))
74 : ConstantInt::get(IType, 0x7c00);
81 ConstantInt::get(IType, 0xfc00))
82 : ConstantInt::get(IType, 0xfc00);
84 Value *IVal = Builder.CreateBitCast(Val, PosInf->
getType());
85 Value *B1 = Builder.CreateICmpEQ(IVal, PosInf);
86 Value *B2 = Builder.CreateICmpEQ(IVal, NegInf);
87 Value *B3 = Builder.CreateOr(B1, B2);
93 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
109 ConstantInt::get(IType, 0x7c00))
110 : ConstantInt::get(IType, 0x7c00);
116 ConstantInt::get(IType, 0x3ff))
117 : ConstantInt::get(IType, 0x3ff);
124 ConstantInt::get(IType, 0))
125 : ConstantInt::get(IType, 0);
127 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
128 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
129 Value *B1 = Builder.CreateICmpEQ(Exp, ExpBitMask);
131 Value *Sig = Builder.CreateAnd(IVal, SigBitMask);
132 Value *B2 = Builder.CreateICmpNE(Sig, Zero);
133 Value *B3 = Builder.CreateAnd(B1, B2);
139 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
155 ConstantInt::get(IType, 0x7c00))
156 : ConstantInt::get(IType, 0x7c00);
158 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
159 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
160 Value *B1 = Builder.CreateICmpNE(Exp, ExpBitMask);
166 if (M->getTargetTriple().getDXILVersion() >=
VersionTuple(1, 9))
182 ConstantInt::get(IType, 0x7c00))
183 : ConstantInt::get(IType, 0x7c00);
189 ConstantInt::get(IType, 0))
190 : ConstantInt::get(IType, 0);
192 Value *IVal = Builder.CreateBitCast(Val, ExpBitMask->
getType());
193 Value *Exp = Builder.CreateAnd(IVal, ExpBitMask);
194 Value *NotAllZeroes = Builder.CreateICmpNE(Exp, Zero);
195 Value *NotAllOnes = Builder.CreateICmpNE(Exp, ExpBitMask);
196 Value *B1 = Builder.CreateAnd(NotAllZeroes, NotAllOnes);
201 assert(
F.getIntrinsicID() == Intrinsic::dx_fdot &&
202 "Function is not a dx.fdot intrinsic");
204 return ParamTy->getNumElements() <= 4 ||
205 F.getParent()->getTargetTriple().getOSVersion() <
VersionTuple(6, 9);
209 switch (
F.getIntrinsicID()) {
210 case Intrinsic::assume:
212 case Intrinsic::atan2:
213 case Intrinsic::copysign:
214 case Intrinsic::fshl:
215 case Intrinsic::fshr:
217 case Intrinsic::is_fpclass:
219 case Intrinsic::log10:
221 case Intrinsic::powi:
222 case Intrinsic::dx_all:
223 case Intrinsic::dx_any:
224 case Intrinsic::dx_uclamp:
225 case Intrinsic::dx_sclamp:
226 case Intrinsic::dx_nclamp:
227 case Intrinsic::dx_isfinite:
228 case Intrinsic::dx_isinf:
229 case Intrinsic::dx_isnan:
230 case Intrinsic::dx_sdot:
231 case Intrinsic::dx_udot:
232 case Intrinsic::dx_sign:
233 case Intrinsic::usub_sat:
234 case Intrinsic::vector_reduce_add:
235 case Intrinsic::vector_reduce_fadd:
236 case Intrinsic::matrix_multiply:
237 case Intrinsic::matrix_transpose:
238 case Intrinsic::umul_with_overflow:
239 case Intrinsic::smul_with_overflow:
240 case Intrinsic::dx_load_input:
241 case Intrinsic::dx_store_output:
243 case Intrinsic::dx_fdot:
245 case Intrinsic::dx_resource_load_rawbuffer:
247 F.getParent(),
F.getReturnType()->getStructElementType(0),
249 case Intrinsic::dx_resource_load_typedbuffer:
251 F.getParent(),
F.getReturnType()->getStructElementType(0),
253 case Intrinsic::dx_resource_store_rawbuffer:
255 F.getParent(),
F.getFunctionType()->getParamType(3),
true);
256 case Intrinsic::dx_resource_store_typedbuffer:
258 F.getParent(),
F.getFunctionType()->getParamType(2),
false);
266 Type *Ty =
A->getType();
270 Value *Cmp = Builder.CreateICmpULT(
A,
B,
"usub.cmp");
271 Value *
Sub = Builder.CreateSub(
A,
B,
"usub.sub");
272 Value *Zero = ConstantInt::get(Ty, 0);
273 return Builder.CreateSelect(Cmp, Zero,
Sub,
"usub.sat");
280 Type *Ty,
unsigned BW) {
281 assert(BW % 2 == 0 &&
"high-half split needs symmetric halves");
282 unsigned Half = BW / 2;
283 Value *HalfShift = ConstantInt::get(Ty, Half);
286 Value *U0 = Builder.CreateAnd(
A, LoMask);
287 Value *U1 = Builder.CreateLShr(
A, HalfShift);
288 Value *V0 = Builder.CreateAnd(
B, LoMask);
289 Value *
V1 = Builder.CreateLShr(
B, HalfShift);
291 Value *W0 = Builder.CreateMul(U0, V0);
292 Value *
T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
293 Builder.CreateLShr(W0, HalfShift));
294 Value *W1 = Builder.CreateAnd(
T, LoMask);
295 Value *W2 = Builder.CreateLShr(
T, HalfShift);
296 W1 = Builder.CreateAdd(Builder.CreateMul(U0,
V1), W1);
297 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1,
V1), W2),
298 Builder.CreateLShr(W1, HalfShift));
308 Type *Ty =
A->getType();
309 unsigned BW = Ty->getScalarSizeInBits();
319 Lo = Builder.CreateMul(
A,
B);
322 Signed ? Builder.CreateSExt(
A, WideTy) : Builder.CreateZExt(
A, WideTy);
324 Signed ? Builder.CreateSExt(
B, WideTy) : Builder.CreateZExt(
B, WideTy);
325 Value *Wide = Builder.CreateMul(WideA, WideB);
328 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(
Lo, WideTy));
330 Value *
Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
331 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(WideTy, 0));
333 }
else if (BW == 32) {
337 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
338 Value *
Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {
A,
B});
339 Value *
Hi = Builder.CreateExtractValue(
Mul, 0);
340 Lo = Builder.CreateExtractValue(
Mul, 1);
342 Ov = Builder.CreateICmpNE(
343 Hi, Builder.CreateAShr(
Lo, ConstantInt::get(Ty, BW - 1)));
345 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
347 Lo = Builder.CreateMul(
A,
B);
352 Value *SignShift = ConstantInt::get(Ty, BW - 1);
353 Value *ASign = Builder.CreateAShr(
A, SignShift);
354 Value *BSign = Builder.CreateAShr(
B, SignShift);
355 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(ASign,
B));
356 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(BSign,
A));
357 Ov = Builder.CreateICmpNE(
Hi, Builder.CreateAShr(
Lo, SignShift));
359 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
364 Agg = Builder.CreateInsertValue(Agg,
Lo, 0);
365 return Builder.CreateInsertValue(Agg, Ov, 1);
369 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
370 IntrinsicId == Intrinsic::vector_reduce_fadd);
373 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
376 Type *Ty =
X->getType();
378 unsigned XVecSize = XVec->getNumElements();
379 Value *Sum = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
385 Sum = Builder.CreateFAdd(Sum, StartValue);
389 for (
unsigned I = 1;
I < XVecSize;
I++) {
390 Value *Elt = Builder.CreateExtractElement(
X,
I);
392 Sum = Builder.CreateFAdd(Sum, Elt);
394 Sum = Builder.CreateAdd(Sum, Elt);
403 Type *Ty =
X->getType();
409 ConstantInt::get(EltTy, 0))
410 : ConstantInt::get(EltTy, 0);
411 auto *
V = Builder.CreateSub(Zero,
X);
412 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {
X,
V},
nullptr,
418 Type *ATy =
A->getType();
419 [[maybe_unused]]
Type *BTy =
B->getType();
428 unsigned NumElts = AVec->getNumElements();
432 DotIntrinsic = Intrinsic::dx_dot2;
435 DotIntrinsic = Intrinsic::dx_dot3;
438 DotIntrinsic = Intrinsic::dx_dot4;
442 "Invalid dot product input vector: length is outside 2-4");
446 for (
unsigned I = 0;
I < NumElts; ++
I)
447 Args.push_back(Builder.CreateExtractElement(
A, Builder.getInt32(
I)));
448 for (
unsigned I = 0;
I < NumElts; ++
I)
449 Args.push_back(Builder.CreateExtractElement(
B, Builder.getInt32(
I)));
450 return Builder.CreateIntrinsic(ATy->
getScalarType(), DotIntrinsic, Args,
467 "long fdot must not be expanded for shader model 6.9 or later");
470 Value *Result =
nullptr;
472 unsigned Remaining = NumElts -
Offset;
475 unsigned ChunkSize = Remaining == 5 ? 3 : std::min(Remaining, 4u);
477 for (
unsigned I = 0;
I < ChunkSize; ++
I)
479 Value *AChunk = Builder.CreateShuffleVector(
A, Mask);
480 Value *BChunk = Builder.CreateShuffleVector(
B, Mask);
482 Result = Result ? Builder.CreateFAdd(Result, Chunk,
"dot.add") : Chunk;
491 assert(DotIntrinsic == Intrinsic::dx_sdot ||
492 DotIntrinsic == Intrinsic::dx_udot);
495 Type *ATy =
A->getType();
496 [[maybe_unused]]
Type *BTy =
B->getType();
506 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
508 : Intrinsic::dx_umad;
511 Result = Builder.CreateMul(Elt0, Elt1);
512 for (
unsigned I = 1;
I < AVec->getNumElements();
I++) {
513 Elt0 = Builder.CreateExtractElement(
A,
I);
514 Elt1 = Builder.CreateExtractElement(
B,
I);
515 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
525 Type *Ty =
X->getType();
533 Value *NewX = Builder.CreateFMul(Log2eConst,
X);
534 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
535 Ty, Intrinsic::exp2, {NewX},
nullptr,
"dx.exp2");
547 switch (TCI->getZExtValue()) {
561 Type *FTy =
F->getType();
562 unsigned FNumElem = 0;
569 FNumElem = FVecTy->getNumElements();
577 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
578 switch (TCI->getZExtValue()) {
580 Value *NegZero = ConstantInt::get(Builder.getIntNTy(
BitWidth),
584 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
586 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
588 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
600 Type *Ty =
X->getType();
605 if (IntrinsicId == Intrinsic::dx_any)
606 return Builder.CreateOr(Result, Elt);
607 assert(IntrinsicId == Intrinsic::dx_all);
608 return Builder.CreateAnd(Result, Elt);
611 Value *Result =
nullptr;
612 if (!Ty->isVectorTy()) {
614 ? Builder.CreateFCmpUNE(
X, ConstantFP::get(EltTy, 0))
615 : Builder.CreateICmpNE(
X, ConstantInt::get(EltTy, 0));
620 ? Builder.CreateFCmpUNE(
623 ConstantFP::get(EltTy, 0)))
624 : Builder.CreateICmpNE(
627 ConstantInt::get(EltTy, 0)));
628 Result = Builder.CreateExtractElement(
Cond, (
uint64_t)0);
629 for (
unsigned I = 1;
I < XVec->getNumElements();
I++) {
630 Value *Elt = Builder.CreateExtractElement(
Cond,
I);
631 Result = ApplyOp(IntrinsicId, Result, Elt);
641 Type *Ty =
X->getType();
647 ConstantFP::get(EltTy, LogConstVal))
648 : ConstantFP::get(EltTy, LogConstVal);
649 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
650 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
653 return Builder.CreateFMul(Ln2Const, Log2Call);
662 Type *Ty =
X->getType();
666 Value *Tan = Builder.CreateFDiv(
Y,
X);
668 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
669 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
677 Constant *Zero = ConstantFP::get(Ty, 0);
678 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
679 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
682 Value *Result = Atan;
683 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
684 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
685 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
686 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
689 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
690 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
693 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
694 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
697 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
698 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
701 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
702 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
707template <
bool LeftFunnel>
717 "Can't use Mask to compute modulo and inverse");
732 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
737 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
742 Value *NotShift = Builder.CreateNot(Shift);
743 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
745 Constant *One = ConstantInt::get(Ty, 1);
750 ShiftedA = Builder.CreateShl(
A, MaskedShift);
751 Value *ShiftB1 = Builder.CreateLShr(
B, One);
752 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
754 Value *ShiftA1 = Builder.CreateShl(
A, One);
755 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
756 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
759 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
767 Type *Ty =
X->getType();
770 if (IntrinsicId == Intrinsic::powi)
771 Y = Builder.CreateSIToFP(
Y, Ty);
774 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
775 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
776 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
777 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
790 "Only expand double or int64 scalars or vectors");
791 bool IsVector =
false;
792 unsigned ExtractNum = 2;
794 ExtractNum = 2 * VT->getNumElements();
796 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
805 while (ExtractNum > 0) {
806 unsigned LoadNum = std::min(ExtractNum, 4u);
810 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
813 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
814 Value *Tmp = Builder.getInt32(4 *
Base * 2);
819 Args[AddressArg] = Builder.CreateAdd(Args[AddressArg], Tmp);
822 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
826 Value *Extract = Builder.CreateExtractValue(
Load, {0});
829 for (
unsigned I = 0;
I < LoadNum; ++
I)
831 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
834 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
835 Value *Combined =
nullptr;
838 Combined = Builder.CreateIntrinsic(
839 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
840 {ExtractElements[I], ExtractElements[I + 1]});
845 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
847 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
849 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
851 Combined = Builder.CreateOr(
Lo, ShiftedHi);
855 Result = Builder.CreateInsertElement(Result, Combined,
856 Builder.getInt32((
I / 2) +
Base));
861 ExtractNum -= LoadNum;
865 Value *CheckBit =
nullptr;
876 if (Indices[0] == 0) {
878 EVI->replaceAllUsesWith(Result);
881 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
886 for (
Value *L : Loads)
887 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
888 CheckBit = Builder.CreateAnd(CheckBits);
890 EVI->replaceAllUsesWith(CheckBit);
892 EVI->eraseFromParent();
901 unsigned ValIndex = IsRaw ? 3 : 2;
906 "Only expand double or int64 scalars or vectors");
909 bool IsVector =
false;
910 unsigned ExtractNum = 2;
913 VecLen = VT->getNumElements();
914 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
915 ExtractNum = VecLen * 2;
924 Type *SplitElementTy = Int32Ty;
928 Value *LowBits =
nullptr;
929 Value *HighBits =
nullptr;
933 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
935 LowBits = Builder.CreateExtractValue(Split, 0);
936 HighBits = Builder.CreateExtractValue(Split, 1);
940 Constant *ShiftAmt = Builder.getInt64(32);
946 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
947 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
948 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
953 for (
unsigned I = 0;
I < VecLen; ++
I) {
955 Mask.push_back(
I + VecLen);
957 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
959 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
960 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
967 while (ExtractNum > 0) {
968 unsigned StoreNum = std::min(ExtractNum, 4u);
970 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
973 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
979 Args[AddressArg] = Builder.CreateAdd(Args[AddressArg], Tmp);
983 for (
unsigned I = 0;
I < StoreNum; ++
I) {
984 Mask.push_back(
Base +
I);
989 SubVal = Builder.CreateShuffleVector(Val, Mask);
991 Args.push_back(SubVal);
993 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
995 ExtractNum -= StoreNum;
1003 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1004 return Intrinsic::umax;
1005 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1006 return Intrinsic::smax;
1007 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1008 return Intrinsic::maxnum;
1012 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1013 return Intrinsic::umin;
1014 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1015 return Intrinsic::smin;
1016 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1017 return Intrinsic::minnum;
1025 Type *Ty =
X->getType();
1027 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1028 {
X, Min},
nullptr,
"dx.max");
1029 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1030 {MaxCall, Max},
nullptr,
"dx.min");
1035 Type *Ty =
X->getType();
1045 GT = Builder.CreateFCmpOLT(Zero,
X);
1046 LT = Builder.CreateFCmpOLT(
X, Zero);
1049 GT = Builder.CreateICmpSLT(Zero,
X);
1050 LT = Builder.CreateICmpSLT(
X, Zero);
1053 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1054 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1056 return Builder.CreateSub(ZextGT, ZextLT);
1068 bool IsDouble = Ty->getScalarType()->isDoubleTy();
1069 unsigned BitWidth = IsDouble ? 32 : Ty->getScalarSizeInBits();
1072 auto CopySignBit = [&](
Value *MagnitudeInt,
Value *SignInt) {
1075 Constant *SignMask = ConstantInt::get(IntTy, SignMaskVal);
1076 Constant *NotSignMask = ConstantInt::get(IntTy, ~SignMaskVal);
1078 Value *MagnitudeBits = Builder.CreateAnd(MagnitudeInt, NotSignMask);
1079 Value *SignBits = Builder.CreateAnd(SignInt, SignMask);
1080 return Builder.CreateOr(MagnitudeBits, SignBits);
1086 Value *MagnitudeHalves = Builder.CreateIntrinsic(
1087 SplitTy, Intrinsic::dx_splitdouble, {Magnitude});
1089 Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble, {Sign});
1090 Value *MagnitudeLow = Builder.CreateExtractValue(MagnitudeHalves, 0);
1091 Value *MagnitudeHigh = Builder.CreateExtractValue(MagnitudeHalves, 1);
1092 Value *SignHigh = Builder.CreateExtractValue(SignHalves, 1);
1094 Value *CombinedHigh = CopySignBit(MagnitudeHigh, SignHigh);
1095 return Builder.CreateIntrinsic(Ty, Intrinsic::dx_asdouble,
1096 {MagnitudeLow, CombinedHigh});
1099 Value *MagnitudeInt = Builder.CreateBitCast(Magnitude, IntTy);
1100 Value *SignInt = Builder.CreateBitCast(Sign, IntTy);
1101 Value *CombinedInt = CopySignBit(MagnitudeInt, SignInt);
1102 return Builder.CreateBitCast(CombinedInt, Ty);
1117 Type *EltTy = RetTy->getElementType();
1128 unsigned LHSSize = LHSRows * LHSCols;
1129 unsigned RHSSize = LHSCols * RHSCols;
1132 for (
unsigned I = 0;
I < LHSSize; ++
I)
1133 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1134 for (
unsigned I = 0;
I < RHSSize; ++
I)
1135 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1140 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1141 if (IsFP && !UseScalarFP) {
1144 FloatDotID = Intrinsic::dx_dot2;
1147 FloatDotID = Intrinsic::dx_dot3;
1150 FloatDotID = Intrinsic::dx_dot4;
1154 "Invalid matrix inner dimension for dot product: must be 2-4");
1159 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1160 for (
unsigned R = 0; R < LHSRows; ++R) {
1163 for (
unsigned K = 0;
K < LHSCols; ++
K) {
1171 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1172 for (
unsigned K = 1;
K < LHSCols; ++
K)
1173 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1174 {RowElts[K], ColElts[K], Dot});
1178 Args.append(RowElts.
begin(), RowElts.
end());
1179 Args.append(ColElts.
begin(), ColElts.
end());
1180 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1183 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1184 for (
unsigned K = 1;
K < LHSCols; ++
K)
1185 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1186 {RowElts[K], ColElts[K], Dot});
1188 unsigned ResIdx =
C * LHSRows + R;
1189 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1203 unsigned NumElts = Rows * Cols;
1205 for (
unsigned I = 0;
I < NumElts; ++
I)
1206 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1209 return Builder.CreateShuffleVector(Mat, Mask);
1224 Type *ScalarTy = VT->getElementType();
1225 unsigned NumElems = VT->getNumElements();
1231 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1234 M, Intrinsic::dx_store_output, {ScalarTy});
1236 for (
unsigned I = 0;
I < NumElems; ++
I) {
1238 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1240 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1241 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1242 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
1260 Type *ScalarTy = VT->getElementType();
1261 unsigned NumElems = VT->getNumElements();
1267 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1270 M, Intrinsic::dx_load_input, {ScalarTy});
1273 for (
unsigned I = 0;
I < NumElems; ++
I) {
1275 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1276 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1277 Value *Scalar = Builder.CreateCall(
1278 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1280 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1287 Value *Result =
nullptr;
1289 switch (IntrinsicId) {
1290 case Intrinsic::abs:
1293 case Intrinsic::assume:
1296 case Intrinsic::atan2:
1299 case Intrinsic::copysign:
1302 case Intrinsic::fshl:
1305 case Intrinsic::fshr:
1308 case Intrinsic::exp:
1311 case Intrinsic::is_fpclass:
1314 case Intrinsic::log:
1317 case Intrinsic::log10:
1320 case Intrinsic::pow:
1321 case Intrinsic::powi:
1324 case Intrinsic::dx_all:
1325 case Intrinsic::dx_any:
1328 case Intrinsic::dx_uclamp:
1329 case Intrinsic::dx_sclamp:
1330 case Intrinsic::dx_nclamp:
1333 case Intrinsic::dx_isfinite:
1336 case Intrinsic::dx_isinf:
1339 case Intrinsic::dx_isnan:
1342 case Intrinsic::dx_fdot:
1345 case Intrinsic::dx_sdot:
1346 case Intrinsic::dx_udot:
1349 case Intrinsic::dx_sign:
1352 case Intrinsic::dx_load_input:
1355 case Intrinsic::dx_store_output:
1359 case Intrinsic::dx_resource_load_rawbuffer:
1363 case Intrinsic::dx_resource_store_rawbuffer:
1367 case Intrinsic::dx_resource_load_typedbuffer:
1371 case Intrinsic::dx_resource_store_typedbuffer:
1375 case Intrinsic::usub_sat:
1378 case Intrinsic::umul_with_overflow:
1379 case Intrinsic::smul_with_overflow:
1381 Intrinsic::smul_with_overflow);
1383 case Intrinsic::vector_reduce_add:
1384 case Intrinsic::vector_reduce_fadd:
1387 case Intrinsic::matrix_multiply:
1390 case Intrinsic::matrix_transpose:
1406 bool IntrinsicExpanded =
false;
1413 if (
F.user_empty() && IntrinsicExpanded)
1414 F.eraseFromParent();
1433 "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 * 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)
SmallVector< MachineOperand, 4 > 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.
iterator_range< user_iterator > users()
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.
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()
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
@ 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.