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>
717 unsigned BitWidth = Ty->getScalarSizeInBits();
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);
817 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
820 Value *
Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
824 Value *Extract = Builder.CreateExtractValue(
Load, {0});
827 for (
unsigned I = 0;
I < LoadNum; ++
I)
829 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
832 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
833 Value *Combined =
nullptr;
836 Combined = Builder.CreateIntrinsic(
837 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
838 {ExtractElements[I], ExtractElements[I + 1]});
843 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
845 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
847 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
849 Combined = Builder.CreateOr(
Lo, ShiftedHi);
853 Result = Builder.CreateInsertElement(Result, Combined,
854 Builder.getInt32((
I / 2) +
Base));
859 ExtractNum -= LoadNum;
863 Value *CheckBit =
nullptr;
874 if (Indices[0] == 0) {
876 EVI->replaceAllUsesWith(Result);
879 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
884 for (
Value *L : Loads)
885 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
886 CheckBit = Builder.CreateAnd(CheckBits);
888 EVI->replaceAllUsesWith(CheckBit);
890 EVI->eraseFromParent();
899 unsigned ValIndex = IsRaw ? 3 : 2;
904 "Only expand double or int64 scalars or vectors");
907 bool IsVector =
false;
908 unsigned ExtractNum = 2;
911 VecLen = VT->getNumElements();
912 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
913 ExtractNum = VecLen * 2;
922 Type *SplitElementTy = Int32Ty;
926 Value *LowBits =
nullptr;
927 Value *HighBits =
nullptr;
931 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
933 LowBits = Builder.CreateExtractValue(Split, 0);
934 HighBits = Builder.CreateExtractValue(Split, 1);
938 Constant *ShiftAmt = Builder.getInt64(32);
944 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
945 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
946 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
951 for (
unsigned I = 0;
I < VecLen; ++
I) {
953 Mask.push_back(
I + VecLen);
955 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
957 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
958 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
965 while (ExtractNum > 0) {
966 unsigned StoreNum = std::min(ExtractNum, 4u);
968 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
971 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
973 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
977 for (
unsigned I = 0;
I < StoreNum; ++
I) {
978 Mask.push_back(
Base +
I);
983 SubVal = Builder.CreateShuffleVector(Val, Mask);
985 Args.push_back(SubVal);
987 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
989 ExtractNum -= StoreNum;
997 if (ClampIntrinsic == Intrinsic::dx_uclamp)
998 return Intrinsic::umax;
999 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1000 return Intrinsic::smax;
1001 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1002 return Intrinsic::maxnum;
1006 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1007 return Intrinsic::umin;
1008 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1009 return Intrinsic::smin;
1010 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1011 return Intrinsic::minnum;
1019 Type *Ty =
X->getType();
1021 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1022 {
X, Min},
nullptr,
"dx.max");
1023 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1024 {MaxCall, Max},
nullptr,
"dx.min");
1029 Type *Ty =
X->getType();
1039 GT = Builder.CreateFCmpOLT(Zero,
X);
1040 LT = Builder.CreateFCmpOLT(
X, Zero);
1043 GT = Builder.CreateICmpSLT(Zero,
X);
1044 LT = Builder.CreateICmpSLT(
X, Zero);
1047 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1048 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1050 return Builder.CreateSub(ZextGT, ZextLT);
1062 bool IsDouble = Ty->getScalarType()->isDoubleTy();
1063 unsigned BitWidth = IsDouble ? 32 : Ty->getScalarSizeInBits();
1066 auto CopySignBit = [&](
Value *MagnitudeInt,
Value *SignInt) {
1069 Constant *SignMask = ConstantInt::get(IntTy, SignMaskVal);
1070 Constant *NotSignMask = ConstantInt::get(IntTy, ~SignMaskVal);
1072 Value *MagnitudeBits = Builder.CreateAnd(MagnitudeInt, NotSignMask);
1073 Value *SignBits = Builder.CreateAnd(SignInt, SignMask);
1074 return Builder.CreateOr(MagnitudeBits, SignBits);
1080 Value *MagnitudeHalves = Builder.CreateIntrinsic(
1081 SplitTy, Intrinsic::dx_splitdouble, {Magnitude});
1083 Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble, {Sign});
1084 Value *MagnitudeLow = Builder.CreateExtractValue(MagnitudeHalves, 0);
1085 Value *MagnitudeHigh = Builder.CreateExtractValue(MagnitudeHalves, 1);
1086 Value *SignHigh = Builder.CreateExtractValue(SignHalves, 1);
1088 Value *CombinedHigh = CopySignBit(MagnitudeHigh, SignHigh);
1089 return Builder.CreateIntrinsic(Ty, Intrinsic::dx_asdouble,
1090 {MagnitudeLow, CombinedHigh});
1093 Value *MagnitudeInt = Builder.CreateBitCast(Magnitude, IntTy);
1094 Value *SignInt = Builder.CreateBitCast(Sign, IntTy);
1095 Value *CombinedInt = CopySignBit(MagnitudeInt, SignInt);
1096 return Builder.CreateBitCast(CombinedInt, Ty);
1111 Type *EltTy = RetTy->getElementType();
1122 unsigned LHSSize = LHSRows * LHSCols;
1123 unsigned RHSSize = LHSCols * RHSCols;
1126 for (
unsigned I = 0;
I < LHSSize; ++
I)
1127 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1128 for (
unsigned I = 0;
I < RHSSize; ++
I)
1129 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1134 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1135 if (IsFP && !UseScalarFP) {
1138 FloatDotID = Intrinsic::dx_dot2;
1141 FloatDotID = Intrinsic::dx_dot3;
1144 FloatDotID = Intrinsic::dx_dot4;
1148 "Invalid matrix inner dimension for dot product: must be 2-4");
1153 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1154 for (
unsigned R = 0; R < LHSRows; ++R) {
1157 for (
unsigned K = 0; K < LHSCols; ++K) {
1158 RowElts.
push_back(LHSElts[K * LHSRows + R]);
1165 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1166 for (
unsigned K = 1; K < LHSCols; ++K)
1167 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1168 {RowElts[K], ColElts[K], Dot});
1172 Args.append(RowElts.
begin(), RowElts.
end());
1173 Args.append(ColElts.
begin(), ColElts.
end());
1174 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1177 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1178 for (
unsigned K = 1; K < LHSCols; ++K)
1179 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1180 {RowElts[K], ColElts[K], Dot});
1182 unsigned ResIdx =
C * LHSRows + R;
1183 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1197 unsigned NumElts = Rows * Cols;
1199 for (
unsigned I = 0;
I < NumElts; ++
I)
1200 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1203 return Builder.CreateShuffleVector(Mat, Mask);
1218 Type *ScalarTy = VT->getElementType();
1219 unsigned NumElems = VT->getNumElements();
1225 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1228 M, Intrinsic::dx_store_output, {ScalarTy});
1230 for (
unsigned I = 0;
I < NumElems; ++
I) {
1232 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1234 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1235 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1236 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
1254 Type *ScalarTy = VT->getElementType();
1255 unsigned NumElems = VT->getNumElements();
1261 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1264 M, Intrinsic::dx_load_input, {ScalarTy});
1267 for (
unsigned I = 0;
I < NumElems; ++
I) {
1269 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1270 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1271 Value *Scalar = Builder.CreateCall(
1272 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1274 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1281 Value *Result =
nullptr;
1283 switch (IntrinsicId) {
1284 case Intrinsic::abs:
1287 case Intrinsic::assume:
1290 case Intrinsic::atan2:
1293 case Intrinsic::copysign:
1296 case Intrinsic::fshl:
1299 case Intrinsic::fshr:
1302 case Intrinsic::exp:
1305 case Intrinsic::is_fpclass:
1308 case Intrinsic::log:
1311 case Intrinsic::log10:
1314 case Intrinsic::pow:
1315 case Intrinsic::powi:
1318 case Intrinsic::dx_all:
1319 case Intrinsic::dx_any:
1322 case Intrinsic::dx_uclamp:
1323 case Intrinsic::dx_sclamp:
1324 case Intrinsic::dx_nclamp:
1327 case Intrinsic::dx_isinf:
1330 case Intrinsic::dx_isnan:
1333 case Intrinsic::dx_fdot:
1336 case Intrinsic::dx_sdot:
1337 case Intrinsic::dx_udot:
1340 case Intrinsic::dx_sign:
1343 case Intrinsic::dx_load_input:
1346 case Intrinsic::dx_store_output:
1350 case Intrinsic::dx_resource_load_rawbuffer:
1354 case Intrinsic::dx_resource_store_rawbuffer:
1358 case Intrinsic::dx_resource_load_typedbuffer:
1362 case Intrinsic::dx_resource_store_typedbuffer:
1366 case Intrinsic::usub_sat:
1369 case Intrinsic::umul_with_overflow:
1370 case Intrinsic::smul_with_overflow:
1372 Intrinsic::smul_with_overflow);
1374 case Intrinsic::vector_reduce_add:
1375 case Intrinsic::vector_reduce_fadd:
1378 case Intrinsic::matrix_multiply:
1381 case Intrinsic::matrix_transpose:
1397 bool IntrinsicExpanded =
false;
1404 if (
F.user_empty() && IntrinsicExpanded)
1405 F.eraseFromParent();
1424 "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.