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 switch (
F.getIntrinsicID()) {
203 case Intrinsic::assume:
205 case Intrinsic::atan2:
206 case Intrinsic::fshl:
207 case Intrinsic::fshr:
209 case Intrinsic::is_fpclass:
211 case Intrinsic::log10:
213 case Intrinsic::powi:
214 case Intrinsic::dx_all:
215 case Intrinsic::dx_any:
216 case Intrinsic::dx_cross:
217 case Intrinsic::dx_uclamp:
218 case Intrinsic::dx_sclamp:
219 case Intrinsic::dx_nclamp:
220 case Intrinsic::dx_degrees:
221 case Intrinsic::dx_isinf:
222 case Intrinsic::dx_isnan:
223 case Intrinsic::dx_lerp:
224 case Intrinsic::dx_normalize:
225 case Intrinsic::dx_fdot:
226 case Intrinsic::dx_sdot:
227 case Intrinsic::dx_udot:
228 case Intrinsic::dx_sign:
229 case Intrinsic::dx_step:
230 case Intrinsic::dx_radians:
231 case Intrinsic::dx_interlocked_add:
232 case Intrinsic::dx_interlocked_or:
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:
241 case Intrinsic::dx_resource_load_rawbuffer:
243 F.getParent(),
F.getReturnType()->getStructElementType(0),
245 case Intrinsic::dx_resource_load_typedbuffer:
247 F.getParent(),
F.getReturnType()->getStructElementType(0),
249 case Intrinsic::dx_resource_store_rawbuffer:
251 F.getParent(),
F.getFunctionType()->getParamType(3),
true);
252 case Intrinsic::dx_resource_store_typedbuffer:
254 F.getParent(),
F.getFunctionType()->getParamType(2),
false);
262 Type *Ty =
A->getType();
266 Value *Cmp = Builder.CreateICmpULT(
A,
B,
"usub.cmp");
267 Value *
Sub = Builder.CreateSub(
A,
B,
"usub.sub");
268 Value *Zero = ConstantInt::get(Ty, 0);
269 return Builder.CreateSelect(Cmp, Zero,
Sub,
"usub.sat");
276 Type *Ty,
unsigned BW) {
277 assert(BW % 2 == 0 &&
"high-half split needs symmetric halves");
278 unsigned Half = BW / 2;
279 Value *HalfShift = ConstantInt::get(Ty, Half);
282 Value *U0 = Builder.CreateAnd(
A, LoMask);
283 Value *U1 = Builder.CreateLShr(
A, HalfShift);
284 Value *V0 = Builder.CreateAnd(
B, LoMask);
285 Value *
V1 = Builder.CreateLShr(
B, HalfShift);
287 Value *W0 = Builder.CreateMul(U0, V0);
288 Value *
T = Builder.CreateAdd(Builder.CreateMul(U1, V0),
289 Builder.CreateLShr(W0, HalfShift));
290 Value *W1 = Builder.CreateAnd(
T, LoMask);
291 Value *W2 = Builder.CreateLShr(
T, HalfShift);
292 W1 = Builder.CreateAdd(Builder.CreateMul(U0,
V1), W1);
293 return Builder.CreateAdd(Builder.CreateAdd(Builder.CreateMul(U1,
V1), W2),
294 Builder.CreateLShr(W1, HalfShift));
304 Type *Ty =
A->getType();
305 unsigned BW = Ty->getScalarSizeInBits();
315 Lo = Builder.CreateMul(
A,
B);
318 Signed ? Builder.CreateSExt(
A, WideTy) : Builder.CreateZExt(
A, WideTy);
320 Signed ? Builder.CreateSExt(
B, WideTy) : Builder.CreateZExt(
B, WideTy);
321 Value *Wide = Builder.CreateMul(WideA, WideB);
324 Ov = Builder.CreateICmpNE(Wide, Builder.CreateSExt(
Lo, WideTy));
326 Value *
Hi = Builder.CreateLShr(Wide, ConstantInt::get(WideTy, BW));
327 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(WideTy, 0));
329 }
else if (BW == 32) {
333 Signed ? Intrinsic::dx_imul : Intrinsic::dx_umul;
334 Value *
Mul = Builder.CreateIntrinsic(ResTy, IntrinsicID, {
A,
B});
335 Value *
Hi = Builder.CreateExtractValue(
Mul, 0);
336 Lo = Builder.CreateExtractValue(
Mul, 1);
338 Ov = Builder.CreateICmpNE(
339 Hi, Builder.CreateAShr(
Lo, ConstantInt::get(Ty, BW - 1)));
341 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
343 Lo = Builder.CreateMul(
A,
B);
348 Value *SignShift = ConstantInt::get(Ty, BW - 1);
349 Value *ASign = Builder.CreateAShr(
A, SignShift);
350 Value *BSign = Builder.CreateAShr(
B, SignShift);
351 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(ASign,
B));
352 Hi = Builder.CreateSub(
Hi, Builder.CreateAnd(BSign,
A));
353 Ov = Builder.CreateICmpNE(
Hi, Builder.CreateAShr(
Lo, SignShift));
355 Ov = Builder.CreateICmpNE(
Hi, ConstantInt::get(Ty, 0));
360 Agg = Builder.CreateInsertValue(Agg,
Lo, 0);
361 return Builder.CreateInsertValue(Agg, Ov, 1);
365 assert(IntrinsicId == Intrinsic::vector_reduce_add ||
366 IntrinsicId == Intrinsic::vector_reduce_fadd);
369 bool IsFAdd = (IntrinsicId == Intrinsic::vector_reduce_fadd);
372 Type *Ty =
X->getType();
374 unsigned XVecSize = XVec->getNumElements();
375 Value *Sum = Builder.CreateExtractElement(
X,
static_cast<uint64_t>(0));
381 Sum = Builder.CreateFAdd(Sum, StartValue);
385 for (
unsigned I = 1;
I < XVecSize;
I++) {
386 Value *Elt = Builder.CreateExtractElement(
X,
I);
388 Sum = Builder.CreateFAdd(Sum, Elt);
390 Sum = Builder.CreateAdd(Sum, Elt);
399 Type *Ty =
X->getType();
405 ConstantInt::get(EltTy, 0))
406 : ConstantInt::get(EltTy, 0);
407 auto *V = Builder.CreateSub(Zero,
X);
408 return Builder.CreateIntrinsic(Ty, Intrinsic::smax, {
X, V},
nullptr,
422 Value *op0_x = Builder.CreateExtractElement(op0, (
uint64_t)0,
"x0");
423 Value *op0_y = Builder.CreateExtractElement(op0, 1,
"x1");
424 Value *op0_z = Builder.CreateExtractElement(op0, 2,
"x2");
426 Value *op1_x = Builder.CreateExtractElement(op1, (
uint64_t)0,
"y0");
427 Value *op1_y = Builder.CreateExtractElement(op1, 1,
"y1");
428 Value *op1_z = Builder.CreateExtractElement(op1, 2,
"y2");
431 Value *xy = Builder.CreateFMul(x0, y1);
432 Value *yx = Builder.CreateFMul(y0, x1);
433 return Builder.CreateFSub(xy, yx, Orig->
getName());
436 Value *yz_zy = MulSub(op0_y, op0_z, op1_y, op1_z);
437 Value *zx_xz = MulSub(op0_z, op0_x, op1_z, op1_x);
438 Value *xy_yx = MulSub(op0_x, op0_y, op1_x, op1_y);
441 cross = Builder.CreateInsertElement(cross, yz_zy, (
uint64_t)0);
442 cross = Builder.CreateInsertElement(cross, zx_xz, 1);
443 cross = Builder.CreateInsertElement(cross, xy_yx, 2);
451 Type *ATy =
A->getType();
452 [[maybe_unused]]
Type *BTy =
B->getType();
462 int NumElts = AVec->getNumElements();
465 DotIntrinsic = Intrinsic::dx_dot2;
468 DotIntrinsic = Intrinsic::dx_dot3;
471 DotIntrinsic = Intrinsic::dx_dot4;
475 "Invalid dot product input vector: length is outside 2-4");
480 for (
int I = 0;
I < NumElts; ++
I)
481 Args.push_back(Builder.CreateExtractElement(
A, Builder.getInt32(
I)));
482 for (
int I = 0;
I < NumElts; ++
I)
483 Args.push_back(Builder.CreateExtractElement(
B, Builder.getInt32(
I)));
484 return Builder.CreateIntrinsic(ATy->
getScalarType(), DotIntrinsic, Args,
499 assert(DotIntrinsic == Intrinsic::dx_sdot ||
500 DotIntrinsic == Intrinsic::dx_udot);
503 Type *ATy =
A->getType();
504 [[maybe_unused]]
Type *BTy =
B->getType();
514 Intrinsic::ID MadIntrinsic = DotIntrinsic == Intrinsic::dx_sdot
516 : Intrinsic::dx_umad;
519 Result = Builder.CreateMul(Elt0, Elt1);
520 for (
unsigned I = 1;
I < AVec->getNumElements();
I++) {
521 Elt0 = Builder.CreateExtractElement(
A,
I);
522 Elt1 = Builder.CreateExtractElement(
B,
I);
523 Result = Builder.CreateIntrinsic(Result->getType(), MadIntrinsic,
533 Type *Ty =
X->getType();
541 Value *NewX = Builder.CreateFMul(Log2eConst,
X);
542 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
543 Ty, Intrinsic::exp2, {NewX},
nullptr,
"dx.exp2");
555 switch (TCI->getZExtValue()) {
569 Type *FTy =
F->getType();
570 unsigned FNumElem = 0;
576 Type *ElemTy = FVecTy->getElementType();
577 FNumElem = FVecTy->getNumElements();
578 BitWidth = ElemTy->getPrimitiveSizeInBits();
585 Value *FBitCast = Builder.CreateBitCast(
F, BitCastTy);
586 switch (TCI->getZExtValue()) {
593 Value *NegZeroSplat = Builder.CreateVectorSplat(FNumElem, NegZero);
595 Builder.CreateICmpEQ(FBitCast, NegZeroSplat,
"is.fpclass.negzero");
597 RetVal = Builder.CreateICmpEQ(FBitCast, NegZero,
"is.fpclass.negzero");
609 Type *Ty =
X->getType();
614 if (IntrinsicId == Intrinsic::dx_any)
615 return Builder.CreateOr(Result, Elt);
616 assert(IntrinsicId == Intrinsic::dx_all);
617 return Builder.CreateAnd(Result, Elt);
620 Value *Result =
nullptr;
621 if (!Ty->isVectorTy()) {
623 ? Builder.CreateFCmpUNE(
X, ConstantFP::get(EltTy, 0))
624 : Builder.CreateICmpNE(
X, ConstantInt::get(EltTy, 0));
629 ? Builder.CreateFCmpUNE(
632 ConstantFP::get(EltTy, 0)))
633 : Builder.CreateICmpNE(
636 ConstantInt::get(EltTy, 0)));
637 Result = Builder.CreateExtractElement(
Cond, (
uint64_t)0);
638 for (
unsigned I = 1;
I < XVec->getNumElements();
I++) {
639 Value *Elt = Builder.CreateExtractElement(
Cond,
I);
640 Result = ApplyOp(IntrinsicId, Result, Elt);
651 auto *V = Builder.CreateFSub(
Y,
X);
652 V = Builder.CreateFMul(S, V);
653 return Builder.CreateFAdd(
X, V,
"dx.lerp");
660 Type *Ty =
X->getType();
666 ConstantFP::get(EltTy, LogConstVal))
667 : ConstantFP::get(EltTy, LogConstVal);
668 CallInst *Log2Call = Builder.CreateIntrinsicWithoutFolding(
669 Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
672 return Builder.CreateFMul(Ln2Const, Log2Call);
689 const APFloat &fpVal = constantFP->getValueAPF();
693 return Builder.CreateFDiv(
X,
X);
701 const APFloat &fpVal = constantFP->getValueAPF();
706 Value *Multiplicand = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_rsqrt,
708 nullptr,
"dx.rsqrt");
710 Value *MultiplicandVec =
711 Builder.CreateVectorSplat(XVec->getNumElements(), Multiplicand);
712 return Builder.CreateFMul(
X, MultiplicandVec);
718 Type *Ty =
X->getType();
722 Value *Tan = Builder.CreateFDiv(
Y,
X);
724 CallInst *Atan = Builder.CreateIntrinsicWithoutFolding(
725 Ty, Intrinsic::atan, {Tan},
nullptr,
"Elt.Atan");
733 Constant *Zero = ConstantFP::get(Ty, 0);
734 Value *AtanAddPi = Builder.CreateFAdd(Atan, Pi);
735 Value *AtanSubPi = Builder.CreateFSub(Atan, Pi);
738 Value *Result = Atan;
739 Value *XLt0 = Builder.CreateFCmpOLT(
X, Zero);
740 Value *XEq0 = Builder.CreateFCmpOEQ(
X, Zero);
741 Value *YGe0 = Builder.CreateFCmpOGE(
Y, Zero);
742 Value *YLt0 = Builder.CreateFCmpOLT(
Y, Zero);
745 Value *XLt0AndYGe0 = Builder.CreateAnd(XLt0, YGe0);
746 Result = Builder.CreateSelect(XLt0AndYGe0, AtanAddPi, Result);
749 Value *XLt0AndYLt0 = Builder.CreateAnd(XLt0, YLt0);
750 Result = Builder.CreateSelect(XLt0AndYLt0, AtanSubPi, Result);
753 Value *XEq0AndYLt0 = Builder.CreateAnd(XEq0, YLt0);
754 Result = Builder.CreateSelect(XEq0AndYLt0, NegHalfPi, Result);
757 Value *XEq0AndYGe0 = Builder.CreateAnd(XEq0, YGe0);
758 Result = Builder.CreateSelect(XEq0AndYGe0, HalfPi, Result);
763template <
bool LeftFunnel>
772 unsigned BitWidth = Ty->getScalarSizeInBits();
774 "Can't use Mask to compute modulo and inverse");
789 Constant *Mask = ConstantInt::get(Ty, Ty->getScalarSizeInBits() - 1);
794 Value *MaskedShift = Builder.CreateAnd(Shift, Mask);
799 Value *NotShift = Builder.CreateNot(Shift);
800 Value *InverseShift = Builder.CreateAnd(NotShift, Mask);
802 Constant *One = ConstantInt::get(Ty, 1);
807 ShiftedA = Builder.CreateShl(
A, MaskedShift);
808 Value *ShiftB1 = Builder.CreateLShr(
B, One);
809 ShiftedB = Builder.CreateLShr(ShiftB1, InverseShift);
811 Value *ShiftA1 = Builder.CreateShl(
A, One);
812 ShiftedA = Builder.CreateShl(ShiftA1, InverseShift);
813 ShiftedB = Builder.CreateLShr(
B, MaskedShift);
816 Value *Result = Builder.CreateOr(ShiftedA, ShiftedB);
824 Type *Ty =
X->getType();
827 if (IntrinsicId == Intrinsic::powi)
828 Y = Builder.CreateSIToFP(
Y, Ty);
831 Builder.CreateIntrinsic(Ty, Intrinsic::log2, {
X},
nullptr,
"elt.log2");
832 auto *
Mul = Builder.CreateFMul(Log2Call,
Y);
833 CallInst *Exp2Call = Builder.CreateIntrinsicWithoutFolding(
834 Ty, Intrinsic::exp2, {
Mul},
nullptr,
"elt.exp2");
844 Type *Ty =
X->getType();
847 Constant *One = ConstantFP::get(Ty->getScalarType(), 1.0);
848 Constant *Zero = ConstantFP::get(Ty->getScalarType(), 0.0);
851 if (Ty != Ty->getScalarType()) {
859 return Builder.CreateSelect(
Cond, Zero, One);
864 Type *Ty =
X->getType();
867 return Builder.CreateFMul(
X, PiOver180);
879 return Builder.CreateAtomicRMW(
Op, Ptr, Val,
MaybeAlign(),
890 "Only expand double or int64 scalars or vectors");
891 bool IsVector =
false;
892 unsigned ExtractNum = 2;
894 ExtractNum = 2 * VT->getNumElements();
896 assert(IsRaw || ExtractNum == 4 &&
"TypedBufferLoad vector must be size 2");
905 while (ExtractNum > 0) {
906 unsigned LoadNum = std::min(ExtractNum, 4u);
910 Intrinsic::ID LoadIntrinsic = Intrinsic::dx_resource_load_typedbuffer;
913 LoadIntrinsic = Intrinsic::dx_resource_load_rawbuffer;
914 Value *Tmp = Builder.getInt32(4 *
Base * 2);
915 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
918 Value *Load = Builder.CreateIntrinsic(LoadType, LoadIntrinsic, Args);
922 Value *Extract = Builder.CreateExtractValue(Load, {0});
925 for (
unsigned I = 0;
I < LoadNum; ++
I)
927 Builder.CreateExtractElement(Extract, Builder.getInt32(
I)));
930 for (
unsigned I = 0;
I < LoadNum;
I += 2) {
931 Value *Combined =
nullptr;
934 Combined = Builder.CreateIntrinsic(
935 Builder.getDoubleTy(), Intrinsic::dx_asdouble,
936 {ExtractElements[I], ExtractElements[I + 1]});
941 Builder.CreateZExt(ExtractElements[
I], Builder.getInt64Ty());
943 Builder.CreateZExt(ExtractElements[
I + 1], Builder.getInt64Ty());
945 Value *ShiftedHi = Builder.CreateShl(
Hi, Builder.getInt64(32));
947 Combined = Builder.CreateOr(
Lo, ShiftedHi);
951 Result = Builder.CreateInsertElement(Result, Combined,
952 Builder.getInt32((
I / 2) +
Base));
957 ExtractNum -= LoadNum;
961 Value *CheckBit =
nullptr;
972 if (Indices[0] == 0) {
974 EVI->replaceAllUsesWith(Result);
977 assert(Indices[0] == 1 &&
"Unexpected type for typedbufferload");
982 for (
Value *L : Loads)
983 CheckBits.
push_back(Builder.CreateExtractValue(L, {1}));
984 CheckBit = Builder.CreateAnd(CheckBits);
986 EVI->replaceAllUsesWith(CheckBit);
988 EVI->eraseFromParent();
997 unsigned ValIndex = IsRaw ? 3 : 2;
1002 "Only expand double or int64 scalars or vectors");
1005 bool IsVector =
false;
1006 unsigned ExtractNum = 2;
1007 unsigned VecLen = 0;
1009 VecLen = VT->getNumElements();
1010 assert(IsRaw || VecLen == 2 &&
"TypedBufferStore vector must be size 2");
1011 ExtractNum = VecLen * 2;
1020 Type *SplitElementTy = Int32Ty;
1024 Value *LowBits =
nullptr;
1025 Value *HighBits =
nullptr;
1029 Value *Split = Builder.CreateIntrinsic(SplitTy, Intrinsic::dx_splitdouble,
1031 LowBits = Builder.CreateExtractValue(Split, 0);
1032 HighBits = Builder.CreateExtractValue(Split, 1);
1036 Constant *ShiftAmt = Builder.getInt64(32);
1042 LowBits = Builder.CreateTrunc(InputVal, SplitElementTy);
1043 Value *ShiftedVal = Builder.CreateLShr(InputVal, ShiftAmt);
1044 HighBits = Builder.CreateTrunc(ShiftedVal, SplitElementTy);
1049 for (
unsigned I = 0;
I < VecLen; ++
I) {
1051 Mask.push_back(
I + VecLen);
1053 Val = Builder.CreateShuffleVector(LowBits, HighBits, Mask);
1055 Val = Builder.CreateInsertElement(Val, LowBits, Builder.getInt32(0));
1056 Val = Builder.CreateInsertElement(Val, HighBits, Builder.getInt32(1));
1063 while (ExtractNum > 0) {
1064 unsigned StoreNum = std::min(ExtractNum, 4u);
1066 Intrinsic::ID StoreIntrinsic = Intrinsic::dx_resource_store_typedbuffer;
1069 StoreIntrinsic = Intrinsic::dx_resource_store_rawbuffer;
1070 Value *Tmp = Builder.getInt32(4 *
Base);
1071 Args.push_back(Builder.CreateAdd(Orig->
getOperand(2), Tmp));
1075 for (
unsigned I = 0;
I < StoreNum; ++
I) {
1076 Mask.push_back(
Base +
I);
1079 Value *SubVal = Val;
1081 SubVal = Builder.CreateShuffleVector(Val, Mask);
1083 Args.push_back(SubVal);
1085 Builder.CreateIntrinsic(Builder.getVoidTy(), StoreIntrinsic, Args);
1087 ExtractNum -= StoreNum;
1095 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1096 return Intrinsic::umax;
1097 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1098 return Intrinsic::smax;
1099 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1100 return Intrinsic::maxnum;
1104 if (ClampIntrinsic == Intrinsic::dx_uclamp)
1105 return Intrinsic::umin;
1106 if (ClampIntrinsic == Intrinsic::dx_sclamp)
1107 return Intrinsic::smin;
1108 assert(ClampIntrinsic == Intrinsic::dx_nclamp);
1109 return Intrinsic::minnum;
1117 Type *Ty =
X->getType();
1119 auto *MaxCall = Builder.CreateIntrinsic(Ty,
getMaxForClamp(ClampIntrinsic),
1120 {
X, Min},
nullptr,
"dx.max");
1121 return Builder.CreateIntrinsic(Ty,
getMinForClamp(ClampIntrinsic),
1122 {MaxCall, Max},
nullptr,
"dx.min");
1127 Type *Ty =
X->getType();
1130 return Builder.CreateFMul(
X, DegreesRatio);
1135 Type *Ty =
X->getType();
1145 GT = Builder.CreateFCmpOLT(Zero,
X);
1146 LT = Builder.CreateFCmpOLT(
X, Zero);
1149 GT = Builder.CreateICmpSLT(Zero,
X);
1150 LT = Builder.CreateICmpSLT(
X, Zero);
1153 Value *ZextGT = Builder.CreateZExt(GT, RetTy);
1154 Value *ZextLT = Builder.CreateZExt(LT, RetTy);
1156 return Builder.CreateSub(ZextGT, ZextLT);
1171 Type *EltTy = RetTy->getElementType();
1182 unsigned LHSSize = LHSRows * LHSCols;
1183 unsigned RHSSize = LHSCols * RHSCols;
1186 for (
unsigned I = 0;
I < LHSSize; ++
I)
1187 LHSElts[
I] = Builder.CreateExtractElement(
LHS,
I);
1188 for (
unsigned I = 0;
I < RHSSize; ++
I)
1189 RHSElts[
I] = Builder.CreateExtractElement(
RHS,
I);
1194 bool UseScalarFP = IsFP && (EltTy->
isDoubleTy() || LHSCols == 1);
1195 if (IsFP && !UseScalarFP) {
1198 FloatDotID = Intrinsic::dx_dot2;
1201 FloatDotID = Intrinsic::dx_dot3;
1204 FloatDotID = Intrinsic::dx_dot4;
1208 "Invalid matrix inner dimension for dot product: must be 2-4");
1213 for (
unsigned C = 0;
C < RHSCols; ++
C) {
1214 for (
unsigned R = 0; R < LHSRows; ++R) {
1217 for (
unsigned K = 0; K < LHSCols; ++K) {
1218 RowElts.
push_back(LHSElts[K * LHSRows + R]);
1225 Dot = Builder.CreateFMul(RowElts[0], ColElts[0]);
1226 for (
unsigned K = 1; K < LHSCols; ++K)
1227 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::fmuladd,
1228 {RowElts[K], ColElts[K], Dot});
1232 Args.append(RowElts.
begin(), RowElts.
end());
1233 Args.append(ColElts.
begin(), ColElts.
end());
1234 Dot = Builder.CreateIntrinsic(EltTy, FloatDotID, Args);
1237 Dot = Builder.CreateMul(RowElts[0], ColElts[0]);
1238 for (
unsigned K = 1; K < LHSCols; ++K)
1239 Dot = Builder.CreateIntrinsic(EltTy, Intrinsic::dx_imad,
1240 {RowElts[K], ColElts[K], Dot});
1242 unsigned ResIdx =
C * LHSRows + R;
1243 Result = Builder.CreateInsertElement(Result, Dot, ResIdx);
1257 unsigned NumElts = Rows * Cols;
1259 for (
unsigned I = 0;
I < NumElts; ++
I)
1260 Mask[
I] = (
I % Cols) * Rows + (
I / Cols);
1263 return Builder.CreateShuffleVector(Mat, Mask);
1267 Value *Result =
nullptr;
1269 switch (IntrinsicId) {
1270 case Intrinsic::abs:
1273 case Intrinsic::assume:
1276 case Intrinsic::atan2:
1279 case Intrinsic::fshl:
1282 case Intrinsic::fshr:
1285 case Intrinsic::exp:
1288 case Intrinsic::is_fpclass:
1291 case Intrinsic::log:
1294 case Intrinsic::log10:
1297 case Intrinsic::pow:
1298 case Intrinsic::powi:
1301 case Intrinsic::dx_all:
1302 case Intrinsic::dx_any:
1305 case Intrinsic::dx_cross:
1308 case Intrinsic::dx_uclamp:
1309 case Intrinsic::dx_sclamp:
1310 case Intrinsic::dx_nclamp:
1313 case Intrinsic::dx_degrees:
1316 case Intrinsic::dx_isinf:
1319 case Intrinsic::dx_isnan:
1322 case Intrinsic::dx_lerp:
1325 case Intrinsic::dx_normalize:
1328 case Intrinsic::dx_fdot:
1331 case Intrinsic::dx_sdot:
1332 case Intrinsic::dx_udot:
1335 case Intrinsic::dx_sign:
1338 case Intrinsic::dx_step:
1341 case Intrinsic::dx_radians:
1344 case Intrinsic::dx_interlocked_add:
1347 case Intrinsic::dx_interlocked_or:
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< 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 * expandNormalizeIntrinsic(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 * expand16BitIsFinite(CallInst *Orig)
static Value * expandLerpIntrinsic(CallInst *Orig)
static Value * expandCrossIntrinsic(CallInst *Orig)
static Value * expandUsubSat(CallInst *Orig)
static Value * expandAnyOrAllIntrinsic(CallInst *Orig, Intrinsic::ID IntrinsicId)
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 * expandStepIntrinsic(CallInst *Orig)
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 * expandDegreesIntrinsic(CallInst *Orig)
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 Value * expandAbs(CallInst *Orig)
static Value * expandFloatDotIntrinsic(CallInst *Orig, Value *A, Value *B)
static Value * expandRadiansIntrinsic(CallInst *Orig)
static Value * expandInterlockedIntrinsic(CallInst *Orig, AtomicRMWInst::BinOp Op)
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()
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.
BinOp
This enumeration lists the possible modifications atomicrmw can make.
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.
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.
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)
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.
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()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
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.
@ C
The default llvm calling convention, compatible with C.
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.
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.
DWARFExpression::Operation Op
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.
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.