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_isfinite:
229 case Intrinsic::dx_isinf:
230 case Intrinsic::dx_isnan:
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;
570 FNumElem = FVecTy->getNumElements();
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);
664 Type *Ty =
X->getType();
668 Value *Tan = Builder.CreateFDiv(
Y,
X);
670 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
671 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
679 Constant *Zero = ConstantFP::get(Ty, 0);
680 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
681 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
684 Value *Result = Atan;
685 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
686 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
687 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
688 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
691 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
692 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
695 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
696 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
699 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
700 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
703 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
704 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
709template <
bool LeftFunnel>
719 "Can't use Mask to compute modulo and inverse");
734 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
739 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
744 Value *NotShift = Builder.CreateNot(Shift);
745 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
747 Constant *One = ConstantInt::get(Ty, 1);
752 ShiftedA = Builder.CreateShl(
A, MaskedShift);
753 Value *ShiftB1 = Builder.CreateLShr(
B, One);
754 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
756 Value *ShiftA1 = Builder.CreateShl(
A, One);
757 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
758 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
761 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
769 Type *Ty =
X->getType();
772 if (IntrinsicId == Intrinsic::powi)
773 Y = Builder.CreateSIToFP(
Y, Ty);
776 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
777 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
778 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
779 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
792 "Only expand double or int64 scalars or vectors");
793 bool IsVector =
false;
794 unsigned ExtractNum = 2;
796 ExtractNum = 2 * VT->getNumElements();
798 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
807 while (ExtractNum > 0) {
808 unsigned LoadNum = std::min(ExtractNum, 4u);
812 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
815 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
816 Value *Tmp = Builder.getInt32(4 *
Base * 2);
821 Args[AddressArg] = Builder.CreateAdd(Args[AddressArg], Tmp);
824 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
828 Value *Extract = Builder.CreateExtractValue(
Load, {0});
831 for (
unsigned I = 0;
I < LoadNum; ++
I)
833 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
836 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
837 Value *Combined =
nullptr;
840 Combined = Builder.CreateIntrinsic(
841 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
842 {ExtractElements[I], ExtractElements[I + 1]});
847 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
849 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
851 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
853 Combined = Builder.CreateOr(
Lo, ShiftedHi);
857 Result = Builder.CreateInsertElement(Result, Combined,
858 Builder.getInt32((
I / 2) +
Base));
863 ExtractNum -= LoadNum;
867 Value *CheckBit =
nullptr;
878 if (Indices[0] == 0) {
880 EVI->replaceAllUsesWith(Result);
883 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
888 for (
Value *L : Loads)
889 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
890 CheckBit = Builder.CreateAnd(CheckBits);
892 EVI->replaceAllUsesWith(CheckBit);
894 EVI->eraseFromParent();
903 unsigned ValIndex = IsRaw ? 3 : 2;
908 "Only expand double or int64 scalars or vectors");
911 bool IsVector =
false;
912 unsigned ExtractNum = 2;
915 VecLen = VT->getNumElements();
916 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
917 ExtractNum = VecLen * 2;
926 Type *SplitElementTy = Int32Ty;
930 Value *LowBits =
nullptr;
931 Value *HighBits =
nullptr;
935 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
937 LowBits = Builder.CreateExtractValue(Split, 0);
938 HighBits = Builder.CreateExtractValue(Split, 1);
942 Constant *ShiftAmt = Builder.getInt64(32);
948 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
949 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
950 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
955 for (
unsigned I = 0;
I < VecLen; ++
I) {
957 Mask.push_back(
I + VecLen);
959 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
961 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
962 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
969 while (ExtractNum > 0) {
970 unsigned StoreNum = std::min(ExtractNum, 4u);
972 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
975 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
981 Args[AddressArg] = Builder.CreateAdd(Args[AddressArg], Tmp);
985 for (
unsigned I = 0;
I < StoreNum; ++
I) {
986 Mask.push_back(
Base +
I);
991 SubVal = Builder.CreateShuffleVector(Val, Mask);
993 Args.push_back(SubVal);
995 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
997 ExtractNum -= StoreNum;
1005 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1006 return Intrinsic::umax;
1007 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1008 return Intrinsic::smax;
1009 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1010 return Intrinsic::maxnum;
1014 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1015 return Intrinsic::umin;
1016 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1017 return Intrinsic::smin;
1018 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1019 return Intrinsic::minnum;
1027 Type *Ty =
X->getType();
1029 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1030 {
X, Min},
nullptr,
"dx.max");
1031 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1032 {MaxCall, Max},
nullptr,
"dx.min");
1037 Type *Ty =
X->getType();
1047 GT = Builder.CreateFCmpOLT(Zero,
X);
1048 LT = Builder.CreateFCmpOLT(
X, Zero);
1051 GT = Builder.CreateICmpSLT(Zero,
X);
1052 LT = Builder.CreateICmpSLT(
X, Zero);
1055 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1056 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1058 return Builder.CreateSub(ZextGT, ZextLT);
1070 bool IsDouble = Ty->getScalarType()->isDoubleTy();
1071 unsigned BitWidth = IsDouble ? 32 : Ty->getScalarSizeInBits();
1074 auto CopySignBit = [&](
Value *MagnitudeInt,
Value *SignInt) {
1077 Constant *SignMask = ConstantInt::get(IntTy, SignMaskVal);
1078 Constant *NotSignMask = ConstantInt::get(IntTy, ~SignMaskVal);
1080 Value *MagnitudeBits = Builder.CreateAnd(MagnitudeInt, NotSignMask);
1081 Value *SignBits = Builder.CreateAnd(SignInt, SignMask);
1082 return Builder.CreateOr(MagnitudeBits, SignBits);
1088 Value *MagnitudeHalves = Builder.CreateIntrinsic(
1089 SplitTy, Intrinsic::dx_splitdouble, {Magnitude});
1091 Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble, {Sign});
1092 Value *MagnitudeLow = Builder.CreateExtractValue(MagnitudeHalves, 0);
1093 Value *MagnitudeHigh = Builder.CreateExtractValue(MagnitudeHalves, 1);
1094 Value *SignHigh = Builder.CreateExtractValue(SignHalves, 1);
1096 Value *CombinedHigh = CopySignBit(MagnitudeHigh, SignHigh);
1097 return Builder.CreateIntrinsic(Ty, Intrinsic::dx_asdouble,
1098 {MagnitudeLow, CombinedHigh});
1101 Value *MagnitudeInt = Builder.CreateBitCast(Magnitude, IntTy);
1102 Value *SignInt = Builder.CreateBitCast(Sign, IntTy);
1103 Value *CombinedInt = CopySignBit(MagnitudeInt, SignInt);
1104 return Builder.CreateBitCast(CombinedInt, Ty);
1119 Type *EltTy = RetTy->getElementType();
1130 unsigned LHSSize = LHSRows * LHSCols;
1131 unsigned RHSSize = LHSCols * RHSCols;
1134 for (
unsigned I = 0;
I < LHSSize; ++
I)
1135 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1136 for (
unsigned I = 0;
I < RHSSize; ++
I)
1137 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1142 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1143 if (IsFP && !UseScalarFP) {
1146 FloatDotID = Intrinsic::dx_dot2;
1149 FloatDotID = Intrinsic::dx_dot3;
1152 FloatDotID = Intrinsic::dx_dot4;
1156 "Invalid matrix inner dimension for dot product: must be 2-4");
1161 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1162 for (
unsigned R = 0; R < LHSRows; ++R) {
1165 for (
unsigned K = 0;
K < LHSCols; ++
K) {
1173 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1174 for (
unsigned K = 1;
K < LHSCols; ++
K)
1175 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1176 {RowElts[K], ColElts[K], Dot});
1180 Args.append(RowElts.
begin(), RowElts.
end());
1181 Args.append(ColElts.
begin(), ColElts.
end());
1182 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1185 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1186 for (
unsigned K = 1;
K < LHSCols; ++
K)
1187 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1188 {RowElts[K], ColElts[K], Dot});
1190 unsigned ResIdx =
C * LHSRows + R;
1191 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1205 unsigned NumElts = Rows * Cols;
1207 for (
unsigned I = 0;
I < NumElts; ++
I)
1208 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1211 return Builder.CreateShuffleVector(Mat, Mask);
1226 Type *ScalarTy = VT->getElementType();
1227 unsigned NumElems = VT->getNumElements();
1233 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1236 M, Intrinsic::dx_store_output, {ScalarTy});
1238 for (
unsigned I = 0;
I < NumElems; ++
I) {
1240 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1242 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1243 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1244 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
1262 Type *ScalarTy = VT->getElementType();
1263 unsigned NumElems = VT->getNumElements();
1269 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1272 M, Intrinsic::dx_load_input, {ScalarTy});
1275 for (
unsigned I = 0;
I < NumElems; ++
I) {
1277 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1278 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1279 Value *Scalar = Builder.CreateCall(
1280 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1282 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1289 Value *Result =
nullptr;
1291 switch (IntrinsicId) {
1292 case Intrinsic::abs:
1295 case Intrinsic::assume:
1298 case Intrinsic::atan2:
1301 case Intrinsic::copysign:
1304 case Intrinsic::fshl:
1307 case Intrinsic::fshr:
1310 case Intrinsic::exp:
1313 case Intrinsic::is_fpclass:
1316 case Intrinsic::log:
1319 case Intrinsic::log10:
1322 case Intrinsic::pow:
1323 case Intrinsic::powi:
1326 case Intrinsic::dx_all:
1327 case Intrinsic::dx_any:
1330 case Intrinsic::dx_uclamp:
1331 case Intrinsic::dx_sclamp:
1332 case Intrinsic::dx_nclamp:
1335 case Intrinsic::dx_isfinite:
1338 case Intrinsic::dx_isinf:
1341 case Intrinsic::dx_isnan:
1344 case Intrinsic::dx_fdot:
1347 case Intrinsic::dx_sdot:
1348 case Intrinsic::dx_udot:
1351 case Intrinsic::dx_sign:
1354 case Intrinsic::dx_load_input:
1357 case Intrinsic::dx_store_output:
1361 case Intrinsic::dx_resource_load_rawbuffer:
1365 case Intrinsic::dx_resource_store_rawbuffer:
1369 case Intrinsic::dx_resource_load_typedbuffer:
1373 case Intrinsic::dx_resource_store_typedbuffer:
1377 case Intrinsic::usub_sat:
1380 case Intrinsic::umul_with_overflow:
1381 case Intrinsic::smul_with_overflow:
1383 Intrinsic::smul_with_overflow);
1385 case Intrinsic::vector_reduce_add:
1386 case Intrinsic::vector_reduce_fadd:
1389 case Intrinsic::matrix_multiply:
1392 case Intrinsic::matrix_transpose:
1408 bool IntrinsicExpanded =
false;
1415 if (
F.user_empty() && IntrinsicExpanded)
1416 F.eraseFromParent();
1435 "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.
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()
Pass to expand intrinsic operations that lack DXIL opCodes.
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.