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_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;
568 Type *ElemTy = FVecTy->getElementType();
569 FNumElem = FVecTy->getNumElements();
570 BitWidth = ElemTy->getPrimitiveSizeInBits();
577 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
578 switch (TCI->getZExtValue()) {
585 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
587 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
589 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
601 Type *Ty =
X->getType();
606 if (IntrinsicId == Intrinsic::dx_any)
607 return Builder.CreateOr(Result, Elt);
608 assert(IntrinsicId == Intrinsic::dx_all);
609 return Builder.CreateAnd(Result, Elt);
612 Value *Result =
nullptr;
613 if (!Ty->isVectorTy()) {
615 ? Builder.CreateFCmpUNE(
X, ConstantFP::get(EltTy, 0))
616 : Builder.CreateICmpNE(
X, ConstantInt::get(EltTy, 0));
621 ? Builder.CreateFCmpUNE(
624 ConstantFP::get(EltTy, 0)))
625 : Builder.CreateICmpNE(
628 ConstantInt::get(EltTy, 0)));
629 Result = Builder.CreateExtractElement(
Cond, (
uint64_t)0);
630 for (
unsigned I = 1;
I < XVec->getNumElements();
I++) {
631 Value *Elt = Builder.CreateExtractElement(
Cond,
I);
632 Result = ApplyOp(IntrinsicId, Result, Elt);
642 Type *Ty =
X->getType();
648 ConstantFP::get(EltTy, LogConstVal))
649 : ConstantFP::get(EltTy, LogConstVal);
650 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
651 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
654 return Builder.CreateFMul(Ln2Const, Log2Call);
663 Type *Ty =
X->getType();
667 Value *Tan = Builder.CreateFDiv(
Y,
X);
669 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
670 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
678 Constant *Zero = ConstantFP::get(Ty, 0);
679 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
680 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
683 Value *Result = Atan;
684 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
685 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
686 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
687 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
690 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
691 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
694 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
695 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
698 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
699 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
702 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
703 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
708template <
bool LeftFunnel>
718 "Can't use Mask to compute modulo and inverse");
733 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
738 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
743 Value *NotShift = Builder.CreateNot(Shift);
744 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
746 Constant *One = ConstantInt::get(Ty, 1);
751 ShiftedA = Builder.CreateShl(
A, MaskedShift);
752 Value *ShiftB1 = Builder.CreateLShr(
B, One);
753 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
755 Value *ShiftA1 = Builder.CreateShl(
A, One);
756 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
757 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
760 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
768 Type *Ty =
X->getType();
771 if (IntrinsicId == Intrinsic::powi)
772 Y = Builder.CreateSIToFP(
Y, Ty);
775 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
776 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
777 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
778 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
791 "Only expand double or int64 scalars or vectors");
792 bool IsVector =
false;
793 unsigned ExtractNum = 2;
795 ExtractNum = 2 * VT->getNumElements();
797 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
806 while (ExtractNum > 0) {
807 unsigned LoadNum = std::min(ExtractNum, 4u);
811 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
814 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
815 Value *Tmp = Builder.getInt32(4 *
Base * 2);
816 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
819 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
823 Value *Extract = Builder.CreateExtractValue(
Load, {0});
826 for (
unsigned I = 0;
I < LoadNum; ++
I)
828 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
831 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
832 Value *Combined =
nullptr;
835 Combined = Builder.CreateIntrinsic(
836 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
837 {ExtractElements[I], ExtractElements[I + 1]});
842 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
844 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
846 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
848 Combined = Builder.CreateOr(
Lo, ShiftedHi);
852 Result = Builder.CreateInsertElement(Result, Combined,
853 Builder.getInt32((
I / 2) +
Base));
858 ExtractNum -= LoadNum;
862 Value *CheckBit =
nullptr;
873 if (Indices[0] == 0) {
875 EVI->replaceAllUsesWith(Result);
878 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
883 for (
Value *L : Loads)
884 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
885 CheckBit = Builder.CreateAnd(CheckBits);
887 EVI->replaceAllUsesWith(CheckBit);
889 EVI->eraseFromParent();
898 unsigned ValIndex = IsRaw ? 3 : 2;
903 "Only expand double or int64 scalars or vectors");
906 bool IsVector =
false;
907 unsigned ExtractNum = 2;
910 VecLen = VT->getNumElements();
911 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
912 ExtractNum = VecLen * 2;
921 Type *SplitElementTy = Int32Ty;
925 Value *LowBits =
nullptr;
926 Value *HighBits =
nullptr;
930 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
932 LowBits = Builder.CreateExtractValue(Split, 0);
933 HighBits = Builder.CreateExtractValue(Split, 1);
937 Constant *ShiftAmt = Builder.getInt64(32);
943 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
944 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
945 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
950 for (
unsigned I = 0;
I < VecLen; ++
I) {
952 Mask.push_back(
I + VecLen);
954 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
956 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
957 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
964 while (ExtractNum > 0) {
965 unsigned StoreNum = std::min(ExtractNum, 4u);
967 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
970 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
972 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
976 for (
unsigned I = 0;
I < StoreNum; ++
I) {
977 Mask.push_back(
Base +
I);
982 SubVal = Builder.CreateShuffleVector(Val, Mask);
984 Args.push_back(SubVal);
986 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
988 ExtractNum -= StoreNum;
996 if (ClampIntrinsic == Intrinsic::dx_uclamp)
997 return Intrinsic::umax;
998 if (ClampIntrinsic == Intrinsic::dx_sclamp)
999 return Intrinsic::smax;
1000 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1001 return Intrinsic::maxnum;
1005 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1006 return Intrinsic::umin;
1007 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1008 return Intrinsic::smin;
1009 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1010 return Intrinsic::minnum;
1018 Type *Ty =
X->getType();
1020 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1021 {
X, Min},
nullptr,
"dx.max");
1022 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1023 {MaxCall, Max},
nullptr,
"dx.min");
1028 Type *Ty =
X->getType();
1038 GT = Builder.CreateFCmpOLT(Zero,
X);
1039 LT = Builder.CreateFCmpOLT(
X, Zero);
1042 GT = Builder.CreateICmpSLT(Zero,
X);
1043 LT = Builder.CreateICmpSLT(
X, Zero);
1046 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1047 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1049 return Builder.CreateSub(ZextGT, ZextLT);
1061 bool IsDouble = Ty->getScalarType()->isDoubleTy();
1062 unsigned BitWidth = IsDouble ? 32 : Ty->getScalarSizeInBits();
1065 auto CopySignBit = [&](
Value *MagnitudeInt,
Value *SignInt) {
1068 Constant *SignMask = ConstantInt::get(IntTy, SignMaskVal);
1069 Constant *NotSignMask = ConstantInt::get(IntTy, ~SignMaskVal);
1071 Value *MagnitudeBits = Builder.CreateAnd(MagnitudeInt, NotSignMask);
1072 Value *SignBits = Builder.CreateAnd(SignInt, SignMask);
1073 return Builder.CreateOr(MagnitudeBits, SignBits);
1079 Value *MagnitudeHalves = Builder.CreateIntrinsic(
1080 SplitTy, Intrinsic::dx_splitdouble, {Magnitude});
1082 Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble, {Sign});
1083 Value *MagnitudeLow = Builder.CreateExtractValue(MagnitudeHalves, 0);
1084 Value *MagnitudeHigh = Builder.CreateExtractValue(MagnitudeHalves, 1);
1085 Value *SignHigh = Builder.CreateExtractValue(SignHalves, 1);
1087 Value *CombinedHigh = CopySignBit(MagnitudeHigh, SignHigh);
1088 return Builder.CreateIntrinsic(Ty, Intrinsic::dx_asdouble,
1089 {MagnitudeLow, CombinedHigh});
1092 Value *MagnitudeInt = Builder.CreateBitCast(Magnitude, IntTy);
1093 Value *SignInt = Builder.CreateBitCast(Sign, IntTy);
1094 Value *CombinedInt = CopySignBit(MagnitudeInt, SignInt);
1095 return Builder.CreateBitCast(CombinedInt, Ty);
1110 Type *EltTy = RetTy->getElementType();
1121 unsigned LHSSize = LHSRows * LHSCols;
1122 unsigned RHSSize = LHSCols * RHSCols;
1125 for (
unsigned I = 0;
I < LHSSize; ++
I)
1126 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1127 for (
unsigned I = 0;
I < RHSSize; ++
I)
1128 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1133 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1134 if (IsFP && !UseScalarFP) {
1137 FloatDotID = Intrinsic::dx_dot2;
1140 FloatDotID = Intrinsic::dx_dot3;
1143 FloatDotID = Intrinsic::dx_dot4;
1147 "Invalid matrix inner dimension for dot product: must be 2-4");
1152 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1153 for (
unsigned R = 0; R < LHSRows; ++R) {
1156 for (
unsigned K = 0; K < LHSCols; ++K) {
1157 RowElts.
push_back(LHSElts[K * LHSRows + R]);
1164 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1165 for (
unsigned K = 1; K < LHSCols; ++K)
1166 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1167 {RowElts[K], ColElts[K], Dot});
1171 Args.append(RowElts.
begin(), RowElts.
end());
1172 Args.append(ColElts.
begin(), ColElts.
end());
1173 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1176 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1177 for (
unsigned K = 1; K < LHSCols; ++K)
1178 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1179 {RowElts[K], ColElts[K], Dot});
1181 unsigned ResIdx =
C * LHSRows + R;
1182 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1196 unsigned NumElts = Rows * Cols;
1198 for (
unsigned I = 0;
I < NumElts; ++
I)
1199 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1202 return Builder.CreateShuffleVector(Mat, Mask);
1217 Type *ScalarTy = VT->getElementType();
1218 unsigned NumElems = VT->getNumElements();
1224 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1227 M, Intrinsic::dx_store_output, {ScalarTy});
1229 for (
unsigned I = 0;
I < NumElems; ++
I) {
1231 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1233 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1234 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1235 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
1253 Type *ScalarTy = VT->getElementType();
1254 unsigned NumElems = VT->getNumElements();
1260 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1263 M, Intrinsic::dx_load_input, {ScalarTy});
1266 for (
unsigned I = 0;
I < NumElems; ++
I) {
1268 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1269 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1270 Value *Scalar = Builder.CreateCall(
1271 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1273 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1280 Value *Result =
nullptr;
1282 switch (IntrinsicId) {
1283 case Intrinsic::abs:
1286 case Intrinsic::assume:
1289 case Intrinsic::atan2:
1292 case Intrinsic::copysign:
1295 case Intrinsic::fshl:
1298 case Intrinsic::fshr:
1301 case Intrinsic::exp:
1304 case Intrinsic::is_fpclass:
1307 case Intrinsic::log:
1310 case Intrinsic::log10:
1313 case Intrinsic::pow:
1314 case Intrinsic::powi:
1317 case Intrinsic::dx_all:
1318 case Intrinsic::dx_any:
1321 case Intrinsic::dx_uclamp:
1322 case Intrinsic::dx_sclamp:
1323 case Intrinsic::dx_nclamp:
1326 case Intrinsic::dx_isinf:
1329 case Intrinsic::dx_isnan:
1332 case Intrinsic::dx_fdot:
1335 case Intrinsic::dx_sdot:
1336 case Intrinsic::dx_udot:
1339 case Intrinsic::dx_sign:
1342 case Intrinsic::dx_load_input:
1345 case Intrinsic::dx_store_output:
1349 case Intrinsic::dx_resource_load_rawbuffer:
1353 case Intrinsic::dx_resource_store_rawbuffer:
1357 case Intrinsic::dx_resource_load_typedbuffer:
1361 case Intrinsic::dx_resource_store_typedbuffer:
1365 case Intrinsic::usub_sat:
1368 case Intrinsic::umul_with_overflow:
1369 case Intrinsic::smul_with_overflow:
1371 Intrinsic::smul_with_overflow);
1373 case Intrinsic::vector_reduce_add:
1374 case Intrinsic::vector_reduce_fadd:
1377 case Intrinsic::matrix_multiply:
1380 case Intrinsic::matrix_transpose:
1396 bool IntrinsicExpanded =
false;
1403 if (
F.user_empty() && IntrinsicExpanded)
1404 F.eraseFromParent();
1423 "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)
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.