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;
569 FNumElem = FVecTy->getNumElements();
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;
976 Args[AddressArg] = Builder.CreateAdd(Args[AddressArg], Tmp);
980 for (
unsigned I = 0;
I < StoreNum; ++
I) {
981 Mask.push_back(
Base +
I);
986 SubVal = Builder.CreateShuffleVector(Val, Mask);
988 Args.push_back(SubVal);
990 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
992 ExtractNum -= StoreNum;
1000 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1001 return Intrinsic::umax;
1002 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1003 return Intrinsic::smax;
1004 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1005 return Intrinsic::maxnum;
1009 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1010 return Intrinsic::umin;
1011 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1012 return Intrinsic::smin;
1013 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1014 return Intrinsic::minnum;
1022 Type *Ty =
X->getType();
1024 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1025 {
X, Min},
nullptr,
"dx.max");
1026 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1027 {MaxCall, Max},
nullptr,
"dx.min");
1032 Type *Ty =
X->getType();
1042 GT = Builder.CreateFCmpOLT(Zero,
X);
1043 LT = Builder.CreateFCmpOLT(
X, Zero);
1046 GT = Builder.CreateICmpSLT(Zero,
X);
1047 LT = Builder.CreateICmpSLT(
X, Zero);
1050 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1051 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1053 return Builder.CreateSub(ZextGT, ZextLT);
1065 bool IsDouble = Ty->getScalarType()->isDoubleTy();
1066 unsigned BitWidth = IsDouble ? 32 : Ty->getScalarSizeInBits();
1069 auto CopySignBit = [&](
Value *MagnitudeInt,
Value *SignInt) {
1072 Constant *SignMask = ConstantInt::get(IntTy, SignMaskVal);
1073 Constant *NotSignMask = ConstantInt::get(IntTy, ~SignMaskVal);
1075 Value *MagnitudeBits = Builder.CreateAnd(MagnitudeInt, NotSignMask);
1076 Value *SignBits = Builder.CreateAnd(SignInt, SignMask);
1077 return Builder.CreateOr(MagnitudeBits, SignBits);
1083 Value *MagnitudeHalves = Builder.CreateIntrinsic(
1084 SplitTy, Intrinsic::dx_splitdouble, {Magnitude});
1086 Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble, {Sign});
1087 Value *MagnitudeLow = Builder.CreateExtractValue(MagnitudeHalves, 0);
1088 Value *MagnitudeHigh = Builder.CreateExtractValue(MagnitudeHalves, 1);
1089 Value *SignHigh = Builder.CreateExtractValue(SignHalves, 1);
1091 Value *CombinedHigh = CopySignBit(MagnitudeHigh, SignHigh);
1092 return Builder.CreateIntrinsic(Ty, Intrinsic::dx_asdouble,
1093 {MagnitudeLow, CombinedHigh});
1096 Value *MagnitudeInt = Builder.CreateBitCast(Magnitude, IntTy);
1097 Value *SignInt = Builder.CreateBitCast(Sign, IntTy);
1098 Value *CombinedInt = CopySignBit(MagnitudeInt, SignInt);
1099 return Builder.CreateBitCast(CombinedInt, Ty);
1114 Type *EltTy = RetTy->getElementType();
1125 unsigned LHSSize = LHSRows * LHSCols;
1126 unsigned RHSSize = LHSCols * RHSCols;
1129 for (
unsigned I = 0;
I < LHSSize; ++
I)
1130 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1131 for (
unsigned I = 0;
I < RHSSize; ++
I)
1132 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1137 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1138 if (IsFP && !UseScalarFP) {
1141 FloatDotID = Intrinsic::dx_dot2;
1144 FloatDotID = Intrinsic::dx_dot3;
1147 FloatDotID = Intrinsic::dx_dot4;
1151 "Invalid matrix inner dimension for dot product: must be 2-4");
1156 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1157 for (
unsigned R = 0; R < LHSRows; ++R) {
1160 for (
unsigned K = 0;
K < LHSCols; ++
K) {
1168 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1169 for (
unsigned K = 1;
K < LHSCols; ++
K)
1170 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1171 {RowElts[K], ColElts[K], Dot});
1175 Args.append(RowElts.
begin(), RowElts.
end());
1176 Args.append(ColElts.
begin(), ColElts.
end());
1177 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1180 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1181 for (
unsigned K = 1;
K < LHSCols; ++
K)
1182 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1183 {RowElts[K], ColElts[K], Dot});
1185 unsigned ResIdx =
C * LHSRows + R;
1186 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1200 unsigned NumElts = Rows * Cols;
1202 for (
unsigned I = 0;
I < NumElts; ++
I)
1203 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1206 return Builder.CreateShuffleVector(Mat, Mask);
1221 Type *ScalarTy = VT->getElementType();
1222 unsigned NumElems = VT->getNumElements();
1228 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1231 M, Intrinsic::dx_store_output, {ScalarTy});
1233 for (
unsigned I = 0;
I < NumElems; ++
I) {
1235 Builder.CreateExtractElement(
Data, ConstantInt::get(Int32Ty,
I));
1237 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1238 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1239 Builder.CreateCall(ScalarFn, {SigElementId, RowIndex, ColI8, Scalar});
1257 Type *ScalarTy = VT->getElementType();
1258 unsigned NumElems = VT->getNumElements();
1264 Value *StartColI32 = Builder.CreateZExt(StartCol, Int32Ty);
1267 M, Intrinsic::dx_load_input, {ScalarTy});
1270 for (
unsigned I = 0;
I < NumElems; ++
I) {
1272 Builder.CreateAdd(StartColI32, ConstantInt::get(Int32Ty,
I));
1273 Value *ColI8 = Builder.CreateTrunc(ColIdx, Int8Ty);
1274 Value *Scalar = Builder.CreateCall(
1275 ScalarFn, {SigElementId, RowIndex, ColI8, GsVertexOrPrimIndex});
1277 Builder.CreateInsertElement(Vec, Scalar, ConstantInt::get(Int32Ty,
I));
1284 Value *Result =
nullptr;
1286 switch (IntrinsicId) {
1287 case Intrinsic::abs:
1290 case Intrinsic::assume:
1293 case Intrinsic::atan2:
1296 case Intrinsic::copysign:
1299 case Intrinsic::fshl:
1302 case Intrinsic::fshr:
1305 case Intrinsic::exp:
1308 case Intrinsic::is_fpclass:
1311 case Intrinsic::log:
1314 case Intrinsic::log10:
1317 case Intrinsic::pow:
1318 case Intrinsic::powi:
1321 case Intrinsic::dx_all:
1322 case Intrinsic::dx_any:
1325 case Intrinsic::dx_uclamp:
1326 case Intrinsic::dx_sclamp:
1327 case Intrinsic::dx_nclamp:
1330 case Intrinsic::dx_isinf:
1333 case Intrinsic::dx_isnan:
1336 case Intrinsic::dx_fdot:
1339 case Intrinsic::dx_sdot:
1340 case Intrinsic::dx_udot:
1343 case Intrinsic::dx_sign:
1346 case Intrinsic::dx_load_input:
1349 case Intrinsic::dx_store_output:
1353 case Intrinsic::dx_resource_load_rawbuffer:
1357 case Intrinsic::dx_resource_store_rawbuffer:
1361 case Intrinsic::dx_resource_load_typedbuffer:
1365 case Intrinsic::dx_resource_store_typedbuffer:
1369 case Intrinsic::usub_sat:
1372 case Intrinsic::umul_with_overflow:
1373 case Intrinsic::smul_with_overflow:
1375 Intrinsic::smul_with_overflow);
1377 case Intrinsic::vector_reduce_add:
1378 case Intrinsic::vector_reduce_fadd:
1381 case Intrinsic::matrix_multiply:
1384 case Intrinsic::matrix_transpose:
1400 bool IntrinsicExpanded =
false;
1407 if (
F.user_empty() && IntrinsicExpanded)
1408 F.eraseFromParent();
1427 "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.