27#define DEBUG_TYPE "amdgpu-simplifylib"
33 cl::desc(
"Comma separated list of functions to replace with native, or all"),
37#define MATH_PI numbers::pi
38#define MATH_E numbers::e
39#define MATH_SQRT2 numbers::sqrt2
40#define MATH_SQRT1_2 numbers::inv_sqrt2
48 const AMDGPUOptions &CLOpts;
54 bool AllNative =
false;
75 bool parseFunctionName(
const StringRef &FMangledName, FuncInfo &FInfo);
77 bool TDOFold(
CallInst *CI,
const FuncInfo &FInfo);
88 const FuncInfo &FInfo);
94 bool sincosUseNative(
CallInst *aCI,
const FuncInfo &FInfo);
97 bool evaluateScalarMathFunc(
const FuncInfo &FInfo,
APFloat &Res0,
99 bool evaluateCall(
CallInst *aCI,
const FuncInfo &FInfo);
103 std::tuple<Value *, Value *, Value *> insertSinCos(
Value *Arg,
113 const FuncInfo &FInfo);
117 bool shouldReplaceLibcallWithIntrinsic(
const CallInst *CI,
118 bool AllowMinSizeF32 =
false,
119 bool AllowF64 =
false,
120 bool AllowStrictFP =
false);
126 bool AllowMinSizeF32 =
false,
127 bool AllowF64 =
false,
128 bool AllowStrictFP =
false);
136 I->replaceAllUsesWith(With);
137 I->eraseFromParent();
157template <
typename IRB>
159 const Twine &Name =
"") {
160 CallInst *R =
B.CreateCall(Callee, Arg, Name);
162 R->setCallingConv(
F->getCallingConv());
166template <
typename IRB>
169 CallInst *R =
B.CreateCall(Callee, {Arg1, Arg2}, Name);
171 R->setCallingConv(
F->getCallingConv());
181 {FT->getParamType(0), PowNExpTy},
false);
419 : AMDGPULibFunc::getFunction(
M, fInfo);
423 Module *M,
const FuncInfo &fInfo, FuncInfo &newInfo,
425 assert(NewFunc != FastVariant);
429 newInfo = AMDGPULibFunc(FastVariant, fInfo);
430 if (FunctionCallee NewCallee = getFunction(M, newInfo))
434 newInfo = AMDGPULibFunc(NewFunc, fInfo);
435 return getFunction(M, newInfo);
438bool AMDGPULibCalls::parseFunctionName(
const StringRef &FMangledName,
454 : CLOpts(
F.
getContext().getLibraryOptions().
get<AMDGPUOptions>()),
459bool AMDGPULibCalls::useNativeFunc(
const StringRef F)
const {
464 AllNative = useNativeFunc(
"all") ||
469bool AMDGPULibCalls::sincosUseNative(
CallInst *aCI,
const FuncInfo &FInfo) {
470 bool native_sin = useNativeFunc(
"sin");
471 bool native_cos = useNativeFunc(
"cos");
473 if (native_sin && native_cos) {
488 if (sinExpr && cosExpr) {
496 <<
" with native version of sin/cos");
511 if (!parseFunctionName(Callee->getName(), FInfo) || !FInfo.
isMangled() ||
514 !(AllNative || useNativeFunc(FInfo.
getName()))) {
519 return sincosUseNative(aCI, FInfo);
528 <<
" with native version");
540 const FuncInfo &FInfo) {
542 if (!Callee->isDeclaration())
545 assert(Callee->hasName() &&
"Invalid read_pipe/write_pipe function");
546 auto *M = Callee->getParent();
547 std::string Name = std::string(Callee->getName());
549 if (NumArg != 4 && NumArg != 6)
555 if (!PacketSize || !PacketAlign)
560 if (Alignment !=
Size)
563 unsigned PtrArgLoc = CI->
arg_size() - 3;
568 for (
unsigned I = 0;
I != PtrArgLoc; ++
I)
572 Name = Name +
"_" + std::to_string(
Size);
581 for (
unsigned I = 0;
I != PtrArgLoc; ++
I)
583 Args.push_back(PtrArg);
585 auto *NCI =
B.CreateCall(
F, Args);
598 if (!Callee || Callee->isIntrinsic() || CI->
isNoBuiltin())
602 if (!parseFunctionName(Callee->getName(), FInfo))
612 if (TDOFold(CI, FInfo))
617 B.setIsFPConstrained(
true);
628 B.setFastMathFlags(FMF);
633 switch (FInfo.
getId()) {
637 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::exp,
642 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::exp2,
647 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::log,
652 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::log2,
657 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::log10,
660 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::minnum,
663 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::maxnum,
666 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::fma,
true,
669 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::fmuladd,
672 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::fabs,
true,
675 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::copysign,
678 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::floor,
true,
681 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::ceil,
true,
684 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::trunc,
true,
687 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::rint,
true,
690 return tryReplaceLibcallWithSimpleIntrinsic(
B, CI, Intrinsic::round,
true,
693 if (!shouldReplaceLibcallWithIntrinsic(CI,
true,
true))
699 Value *SplatArg1 =
B.CreateVectorSplat(VecTy->getElementCount(), Arg1);
705 {CI->getType(), CI->getArgOperand(1)->getType()}));
711 return tryOptimizePow(FPOp,
B, FInfo);
714 if (fold_pow(FPOp,
B, FInfo))
721 Module *M = Callee->getParent();
729 if (!shouldReplaceLibcallWithIntrinsic(CI))
735 if (fold_pow(FPOp,
B, FInfo))
742 Module *M = Callee->getParent();
750 if (!shouldReplaceLibcallWithIntrinsic(CI))
756 if (fold_rootn(FPOp,
B, FInfo))
762 Module *M = Callee->getParent();
764 if (
FunctionCallee RootnFastFunc = getFunction(M, RootnFastInfo)) {
774 return tryReplaceLibcallWithSimpleIntrinsic(
775 B, CI, Intrinsic::sqrt,
true,
true,
false);
778 return fold_sincos(FPOp,
B, FInfo);
784 switch (FInfo.
getId()) {
789 return fold_read_write_pipe(CI,
B, FInfo);
801 assert(Ty->isSingleValueType() &&
802 "Type must either be a scalar or a vector.");
803 assert((!Ty->isVectorTy() || Ty->isScalableTy() ||
805 "Unexpected number of constant values.");
807 "Expected exactly one constant value");
823bool AMDGPULibCalls::TDOFold(
CallInst *CI,
const FuncInfo &FInfo) {
829 int const sz = (int)tr.
size();
839 for (
int eltNo = 0; eltNo < vecSize; ++eltNo) {
846 auto MatchingRow =
llvm::find_if(tr, [eltval](
const TableEntry &entry) {
849 if (MatchingRow == tr.
end())
854 LLVM_DEBUG(
errs() <<
"AMDIC: " << *CI <<
" ---> " << *NewValues <<
"\n");
861 for (
int i = 0; i < sz; ++i) {
862 if (CF->isExactlyValue(tr[i].input)) {
863 Value *nval = ConstantFP::get(CF->getType(), tr[i].result);
864 LLVM_DEBUG(
errs() <<
"AMDIC: " << *CI <<
" ---> " << *nval <<
"\n");
877#if _XOPEN_SOURCE >= 600 || defined(_ISOC99_SOURCE) || _POSIX_C_SOURCE >= 200112L
886 const FuncInfo &FInfo) {
893 "fold_pow: encounter a wrong function call");
901 const APInt *CINT =
nullptr;
906 int ci_opr1 = (CINT ? (int)CINT->
getSExtValue() : 0x1111111);
913 bool SkipConstantFolds =
931 if (FunctionCallee FPExpr =
935 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> " << FInfo.getName()
936 <<
'(' << *opr0 <<
")\n");
938 issqrt ?
"__pow2sqrt" :
"__pow2rsqrt");
945 if (!SkipConstantFolds) {
946 if ((CF && CF->
isZero()) || (CINT && ci_opr1 == 0)) {
949 Constant *cnval = ConstantFP::get(eltType, 1.0);
956 if ((CF && CF->
isOne()) || (CINT && ci_opr1 == 1)) {
958 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> " << *opr0 <<
"\n");
964 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> " << *opr0 <<
" * "
966 Value *nval =
B.CreateFMul(opr0, opr0,
"__pow2");
970 if ((CF && CF->
isMinusOne()) || (CINT && ci_opr1 == -1)) {
972 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> 1 / " << *opr0 <<
"\n");
973 Constant *cnval = ConstantFP::get(eltType, 1.0);
977 Value *nval =
B.CreateFDiv(cnval, opr0,
"__powrecip");
993 int ival = (int)dval;
994 if ((
double)ival == dval) {
997 ci_opr1 = 0x11111111;
1002 unsigned abs_opr1 = (ci_opr1 < 0) ? -ci_opr1 : ci_opr1;
1003 if (abs_opr1 <= 12) {
1006 if (abs_opr1 == 0) {
1007 cnval = ConstantFP::get(eltType, 1.0);
1013 Value *valx2 =
nullptr;
1015 while (abs_opr1 > 0) {
1016 valx2 = valx2 ?
B.CreateFMul(valx2, valx2,
"__powx2") : opr0;
1018 nval = nval ?
B.CreateFMul(nval, valx2,
"__powprod") : valx2;
1025 cnval = ConstantFP::get(eltType, 1.0);
1029 nval =
B.CreateFDiv(cnval, nval,
"__1powprod");
1032 << ((ci_opr1 < 0) ?
"1/prod(" :
"prod(") << *opr0
1043 FunctionCallee ExpExpr;
1044 if (ShouldUseIntrinsic)
1053 bool needlog =
false;
1054 bool needabs =
false;
1055 bool needcopysign =
false;
1067 cnval = ConstantFP::get(eltType,
V);
1085 "Wrong vector size detected");
1090 if (
V < 0.0) needcopysign =
true;
1096 for (
double D : DVal)
1118 nval =
B.CreateFAbs(opr0,
nullptr,
"__fabs");
1120 nval = cnval ? cnval : opr0;
1123 FunctionCallee LogExpr;
1124 if (ShouldUseIntrinsic) {
1139 opr1 =
B.CreateSIToFP(opr1, nval->
getType(),
"pownI2F");
1141 nval =
B.CreateFMul(opr1, nval,
"__ylogx");
1143 CallInst *Exp2Call =
CreateCallEx(
B, ExpExpr, nval,
"__exp2");
1160 opr_n =
B.CreateZExtOrTrunc(opr_n, nTy,
"__ytou");
1162 opr_n =
B.CreateFPToSI(opr1, nTy,
"__ytou");
1165 Value *sign =
B.CreateShl(opr_n,
size-1,
"__yeven");
1166 sign =
B.CreateAnd(
B.CreateBitCast(opr0, nTy), sign,
"__pow_sign");
1168 nval =
B.CreateCopySign(nval,
B.CreateBitCast(sign, nval->
getType()),
1169 nullptr,
"__pow_sign");
1173 <<
"exp2(" << *opr1 <<
" * log2(" << *opr0 <<
"))\n");
1180 const FuncInfo &FInfo) {
1184 const APInt *CINT =
nullptr;
1188 Function *Parent =
B.GetInsertBlock()->getParent();
1191 if (ci_opr1 == 1 && !Parent->
hasFnAttribute(Attribute::StrictFP)) {
1195 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> " << *opr0 <<
'\n');
1208 if (ci_opr1 == 2 && FMFOkForSqrt &&
1209 shouldReplaceLibcallWithIntrinsic(CI,
1213 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> sqrt(" << *opr0 <<
")\n");
1215 Value *NewCall =
B.CreateUnaryIntrinsic(Intrinsic::sqrt, opr0, CI);
1220 MDBuilder MDHelper(
M->getContext());
1221 MDNode *FPMD = MDHelper.createFPMath(std::max(FPOp->
getFPAccuracy(), 2.0f));
1223 NewCallI->setMetadata(LLVMContext::MD_fpmath, FPMD);
1230 if (FunctionCallee FPExpr =
1232 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> cbrt(" << *opr0
1238 }
else if (ci_opr1 == -1) {
1239 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> 1.0 / " << *opr0 <<
"\n");
1240 Value *nval =
B.CreateFDiv(ConstantFP::get(opr0->
getType(), 1.0),
1247 if (ci_opr1 == -2 && FMFOkForSqrt &&
1248 shouldReplaceLibcallWithIntrinsic(CI,
1255 MDBuilder MDHelper(
M->getContext());
1256 MDNode *FPMD = MDHelper.createFPMath(std::max(FPOp->
getFPAccuracy(), 2.0f));
1262 Value *Sqrt =
B.CreateUnaryIntrinsic(Intrinsic::sqrt, opr0, CI);
1264 B.CreateFDiv(ConstantFP::get(opr0->
getType(), 1.0), Sqrt));
1266 SqrtI->setFastMathFlags(FMF);
1270 LLVM_DEBUG(
errs() <<
"AMDIC: " << *FPOp <<
" ---> rsqrt(" << *opr0
1281 Value *TruncY =
B.CreateUnaryIntrinsic(Intrinsic::trunc,
Y);
1282 return B.CreateFCmpOEQ(TruncY,
Y);
1287 auto *HalfY =
B.CreateFMul(
Y, ConstantFP::get(
Y->getType(), 0.5));
1295 Value *NotEvenY =
B.CreateNot(IsEvenY);
1296 return B.CreateAnd(IsIntY, NotEvenY);
1301 auto *fabsVal =
B.CreateFAbs(val);
1307 Value *AbsX =
B.CreateFAbs(
X);
1308 Value *LogAbsX =
B.CreateUnaryIntrinsic(Intrinsic::log2, AbsX);
1309 Value *YTimesLogX =
B.CreateFMul(
Y, LogAbsX);
1310 return B.CreateUnaryIntrinsic(Intrinsic::exp2, YTimesLogX);
1320 Constant *One = ConstantFP::get(
X->getType(), 1.0);
1330 Value *SelSign =
B.CreateSelect(IsOddY,
X, One);
1331 Value *Ret =
B.CreateCopySign(ExpYLnX, SelSign);
1336 Value *condNotIntY =
B.CreateNot(IsIntY);
1337 Value *condNaN =
B.CreateAnd(condNegX, condNotIntY);
1338 Ret =
B.CreateSelect(condNaN, QNaN, Ret);
1347 Value *YIsNegInf =
B.CreateFCmpUNE(
Y, AY);
1350 Value *AxEqOne =
B.CreateFCmpOEQ(AX, One);
1351 Value *AxLtOne =
B.CreateFCmpOLT(AX, One);
1352 Value *XorCond =
B.CreateXor(AxLtOne, YIsNegInf);
1354 B.CreateSelect(AxEqOne, AX,
B.CreateSelect(XorCond,
Zero, AY));
1355 Ret =
B.CreateSelect(YIsInf, SelInf, Ret);
1360 Value *AxInfOrZero =
B.CreateOr(XIsInf, XEqZero);
1362 Value *XorZeroInf =
B.CreateXor(XEqZero, YLtZero);
1363 Value *SelVal =
B.CreateSelect(XorZeroInf,
Zero, PInf);
1364 Value *SelSign2 =
B.CreateSelect(IsOddY,
X,
Zero);
1365 Value *Copysign =
B.CreateCopySign(SelVal, SelSign2);
1366 Ret =
B.CreateSelect(AxInfOrZero, Copysign, Ret);
1369 Value *isUnordered =
B.CreateFCmpUNO(
X,
Y);
1370 return B.CreateSelect(isUnordered, QNaN, Ret);
1374 Value *IZ =
B.CreateSelect(YIsNeg, PInf,
Zero);
1375 Value *ZI =
B.CreateSelect(YIsNeg,
Zero, PInf);
1378 Value *SelZeroCase =
B.CreateSelect(YEqZero, QNaN, IZ);
1380 Value *Ret =
B.CreateSelect(XEqZero, SelZeroCase, ExpYLnX);
1382 Value *XEqInf =
B.CreateFCmpOEQ(
X, PInf);
1384 Value *CondInfCase =
B.CreateAnd(XEqInf, YNeZero);
1385 Ret =
B.CreateSelect(CondInfCase, ZI, Ret);
1388 Value *XNeOne =
B.CreateFCmpUNE(
X, One);
1389 Value *CondInfY =
B.CreateAnd(IsInfY, XNeOne);
1390 Value *XLtOne =
B.CreateFCmpOLT(
X, One);
1391 Value *SelInfYCase =
B.CreateSelect(XLtOne, IZ, ZI);
1392 Ret =
B.CreateSelect(CondInfY, SelInfYCase, Ret);
1394 Value *IsUnordered =
B.CreateFCmpUNO(
X,
Y);
1395 return B.CreateSelect(IsUnordered, QNaN, Ret);
1398 Constant *ZeroI = ConstantInt::get(
Y->getType(), 0);
1401 Value *OneI = ConstantInt::get(
Y->getType(), 1);
1402 Value *YAnd1 =
B.CreateAnd(
Y, OneI);
1403 Value *IsOddY =
B.CreateICmpNE(YAnd1, ZeroI);
1406 Value *SelSign =
B.CreateSelect(IsOddY,
X, One);
1407 Value *Ret =
B.CreateCopySign(ExpYLnX, SelSign);
1410 Value *FabsX =
B.CreateFAbs(
X);
1411 Value *XIsInf =
B.CreateFCmpOEQ(FabsX, PInf);
1413 Value *InfOrZero =
B.CreateOr(XIsInf, XEqZero);
1416 Value *YLtZero =
B.CreateICmpSLT(
Y, ZeroI);
1417 Value *XorZeroInf =
B.CreateXor(XEqZero, YLtZero);
1418 Value *SelVal =
B.CreateSelect(XorZeroInf,
Zero, PInf);
1421 Value *SelSign2 =
B.CreateSelect(IsOddY,
X,
Zero);
1422 Value *Copysign =
B.CreateCopySign(SelVal, SelSign2);
1424 return B.CreateSelect(InfOrZero, Copysign, Ret);
1427 Constant *ZeroI = ConstantInt::get(
Y->getType(), 0);
1430 Value *YAnd1 =
B.CreateAnd(
Y, ConstantInt::get(
Y->getType(), 1));
1431 Value *IsOddY =
B.CreateICmpNE(YAnd1, ZeroI);
1434 Value *SelSign =
B.CreateSelect(IsOddY,
X, One);
1435 Value *Ret =
B.CreateCopySign(ExpYLnX, SelSign);
1438 Value *FabsX =
B.CreateFAbs(
X);
1439 Value *IsInfX =
B.CreateFCmpOEQ(FabsX, PInf);
1441 Value *CondInfOrZero =
B.CreateOr(IsInfX, XEqZero);
1444 Value *YLtZero =
B.CreateICmpSLT(
Y, ZeroI);
1445 Value *XorZeroInf =
B.CreateXor(XEqZero, YLtZero);
1446 Value *SelVal =
B.CreateSelect(XorZeroInf,
Zero, PInf);
1449 Value *SelSign2 =
B.CreateSelect(IsOddY,
X,
Zero);
1450 Value *Copysign =
B.CreateCopySign(SelVal, SelSign2);
1452 Ret =
B.CreateSelect(CondInfOrZero, Copysign, Ret);
1456 Value *NotOddY =
B.CreateNot(IsOddY);
1457 Value *CondNegAndNotOdd =
B.CreateAnd(XIsNeg, NotOddY);
1458 Value *YEqZero =
B.CreateICmpEQ(
Y, ZeroI);
1459 Value *CondBad =
B.CreateOr(CondNegAndNotOdd, YEqZero);
1460 return B.CreateSelect(CondBad, QNaN, Ret);
1485 Constant *One = ConstantFP::get(
X->getType(), 1.0);
1488 Value *XEqOne =
B.CreateFCmpOEQ(
X, One);
1489 Y =
B.CreateSelect(XEqOne, One,
Y);
1493 X =
B.CreateSelect(YEqZero, One,
X);
1511 Value *YEqZero =
B.CreateICmpEQ(
Y, ConstantInt::get(
Y->getType(), 0));
1514 X =
B.CreateSelect(YEqZero, ConstantFP::get(
X->getType(), 1.0),
X);
1516 Value *CastY =
B.CreateSIToFP(
Y,
X->getType());
1523 Value *CastY =
B.CreateSIToFP(
Y,
X->getType());
1526 Value *RcpY =
B.CreateFDiv(ConstantFP::get(
X->getType(), 1.0), CastY);
1538 const FuncInfo &FInfo) {
1548 FunctionCallee PowrFunc = getFloatFastVariant(
1556 SQ.getWithInstruction(
Call))) {
1558 return fold_pow(FPOp,
B, PowrInfo) ||
true;
1571 FunctionCallee PownFunc = getFloatFastVariant(
1579 B.CreateFPToSI(FPOp->
getOperand(1), PownType->getParamType(1));
1582 1, AttributeFuncs::typeIncompatible(CastedArg->
getType(),
1586 return fold_pow(FPOp,
B, PownInfo) ||
true;
1590 if (fold_pow(FPOp,
B, FInfo))
1599 if (FunctionCallee PowFastFunc = getFunction(M, PowFastInfo)) {
1601 return fold_pow(FPOp,
B, PowFastInfo) ||
true;
1611bool AMDGPULibCalls::shouldReplaceLibcallWithIntrinsic(
const CallInst *CI,
1612 bool AllowMinSizeF32,
1614 bool AllowStrictFP) {
1629 if (!AllowStrictFP && ParentF->
hasFnAttribute(Attribute::StrictFP))
1632 if (IsF32 && !AllowMinSizeF32 && ParentF->
hasMinSize())
1637void AMDGPULibCalls::replaceLibCallWithSimpleIntrinsic(
IRBuilder<> &
B,
1645 if (Arg0VecTy && !Arg1VecTy) {
1646 Value *SplatRHS =
B.CreateVectorSplat(Arg0VecTy->getElementCount(), Arg1);
1648 }
else if (!Arg0VecTy && Arg1VecTy) {
1649 Value *SplatLHS =
B.CreateVectorSplat(Arg1VecTy->getElementCount(), Arg0);
1655 CI->
getModule(), IntrID, {CI->getType()}));
1659bool AMDGPULibCalls::tryReplaceLibcallWithSimpleIntrinsic(
1661 bool AllowF64,
bool AllowStrictFP) {
1662 if (!shouldReplaceLibcallWithIntrinsic(CI, AllowMinSizeF32, AllowF64,
1665 replaceLibCallWithSimpleIntrinsic(
B, CI, IntrID);
1669std::tuple<Value *, Value *, Value *>
1674 B.SetInsertPointPastAllocas(
F);
1676 AllocaInst *
Alloc =
B.CreateAlloca(Arg->
getType(),
nullptr,
"__sincos_");
1683 B.SetInsertPoint(*ArgInst->getInsertionPointAfterDef());
1686 B.SetCurrentDebugLocation(
DL);
1694 Value *CastAlloc =
B.CreateAddrSpaceCast(
Alloc, CosPtrTy);
1702 return {SinCos, LoadCos, SinCos};
1707 const FuncInfo &fInfo) {
1726 Function *
F =
B.GetInsertBlock()->getParent();
1732 SinCosLibFuncPrivate.getLeads()[0].PtrKind =
1736 SinCosLibFuncGeneric.getLeads()[0].PtrKind =
1739 FunctionCallee FSinCosPrivate = getFunction(M, SinCosLibFuncPrivate);
1740 FunctionCallee FSinCosGeneric = getFunction(M, SinCosLibFuncGeneric);
1741 FunctionCallee FSinCos = FSinCosPrivate ? FSinCosPrivate : FSinCosGeneric;
1750 const std::string PairName = PartnerInfo.mangle(CLOpts);
1754 const std::string SinCosPrivateName = SinCosLibFuncPrivate.mangle(CLOpts);
1755 const std::string SinCosGenericName = SinCosLibFuncGeneric.mangle(CLOpts);
1759 MDNode *FPMath = CI->
getMetadata(LLVMContext::MD_fpmath);
1763 for (User* U : CArgVal->
users()) {
1772 bool Handled =
true;
1774 if (UCallee->
getName() == SinName)
1776 else if (UCallee->
getName() == CosName)
1778 else if (UCallee->
getName() == SinCosPrivateName ||
1779 UCallee->
getName() == SinCosGenericName)
1787 FMF &= OtherOp->getFastMathFlags();
1798 ArgInst && !ArgInst->getInsertionPointAfterDef())
1801 B.setFastMathFlags(FMF);
1802 B.setDefaultFPMathTag(FPMath);
1804 B.SetCurrentDebugLocation(DbgLoc);
1806 auto [Sin, Cos, SinCos] = insertSinCos(CArgVal, FMF,
B, FSinCos);
1809 for (CallInst *
C : Calls)
1810 C->replaceAllUsesWith(Res);
1815 replaceTrigInsts(SinCalls, Sin);
1816 replaceTrigInsts(CosCalls, Cos);
1817 replaceTrigInsts(SinCosCalls, SinCos);
1824bool AMDGPULibCalls::evaluateScalarMathFunc(
const FuncInfo &FInfo,
1838 switch (FInfo.getId()) {
1848 Res0 =
APFloat{log(opr0 + sqrt(opr0 * opr0 - 1.0))};
1861 Res0 =
APFloat{log(opr0 + sqrt(opr0 * opr0 + 1.0))};
1874 Res0 =
APFloat{(log(opr0 + 1.0) - log(opr0 - 1.0)) / 2.0};
1883 APFloat{(opr0 < 0.0) ? -
pow(-opr0, 1.0 / 3.0) :
pow(opr0, 1.0 / 3.0)};
1899 Res0 =
APFloat{std::exp(opr0)};
1915 Res0 =
APFloat{log(opr0) / log(2.0)};
1919 Res0 =
APFloat{log(opr0) / log(10.0)};
1923 Res0 =
APFloat{1.0 / sqrt(opr0)};
1965 double val = (double)iopr1->getSExtValue();
1974 double val = (double)iopr1->getSExtValue();
1991bool AMDGPULibCalls::evaluateCall(
CallInst *aCI,
const FuncInfo &FInfo) {
1992 int numArgs = (int)aCI->
arg_size();
2015 if (FuncVecSize == 1) {
2016 if (!evaluateScalarMathFunc(FInfo, Val0.
emplace_back(0.0),
2026 for (
int i = 0; i < FuncVecSize; ++i) {
2029 if (!evaluateScalarMathFunc(FInfo, Val0.
emplace_back(0.0),
2051 Simplifier.initNativeFuncs();
2056 F.printAsOperand(
dbgs(),
false,
F.getParent());
dbgs() <<
'\n';);
2058 for (
auto &BB :
F) {
2065 if (Simplifier.fold(CI))
2079 Simplifier.initNativeFuncs();
2082 for (
auto &BB :
F) {
2087 if (CI && Simplifier.useNative(CI))
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static const TableEntry tbl_log[]
static const TableEntry tbl_tgamma[]
static AMDGPULibFunc::EType getArgType(const AMDGPULibFunc &FInfo)
static const TableEntry tbl_expm1[]
static const TableEntry tbl_asinpi[]
static const TableEntry tbl_cos[]
static const TableEntry tbl_exp10[]
static CallInst * CreateCallEx(IRB &B, FunctionCallee Callee, Value *Arg, const Twine &Name="")
static CallInst * CreateCallEx2(IRB &B, FunctionCallee Callee, Value *Arg1, Value *Arg2, const Twine &Name="")
static const TableEntry tbl_rsqrt[]
static const TableEntry tbl_atanh[]
static const TableEntry tbl_cosh[]
static const TableEntry tbl_asin[]
static const TableEntry tbl_sinh[]
static const TableEntry tbl_acos[]
static const TableEntry tbl_tan[]
static const TableEntry tbl_cospi[]
static const TableEntry tbl_tanpi[]
static bool HasNative(AMDGPULibFunc::EFuncId id)
static Value * emitIsInf(IRBuilder<> &B, Value *val)
ArrayRef< TableEntry > TableRef
static int getVecSize(const AMDGPULibFunc &FInfo)
static Value * emitFastExpYLnx(IRBuilder<> &B, Value *X, Value *Y)
static Value * emitIsInteger(IRBuilder<> &B, Value *Y)
static Value * emitIsEvenInteger(IRBuilder<> &B, Value *Y)
static const TableEntry tbl_sin[]
static const TableEntry tbl_atan[]
static const TableEntry tbl_log2[]
static Constant * getConstantFloat(const ArrayRef< APFloat > Values, const Type *Ty)
static const TableEntry tbl_acospi[]
static Value * emitPowFixup(IRBuilder<> &B, Value *X, Value *Y, Value *ExpYLnX, PowKind Kind)
Emit special case management epilog code for fast pow, powr, pown, and rootn expansions.
static const TableEntry tbl_sqrt[]
static const TableEntry tbl_asinh[]
static TableRef getOptTable(AMDGPULibFunc::EFuncId id)
static const TableEntry tbl_acosh[]
static const TableEntry tbl_exp[]
static const TableEntry tbl_cbrt[]
static const TableEntry tbl_sinpi[]
static const TableEntry tbl_atanpi[]
static FunctionType * getPownType(FunctionType *FT)
static const TableEntry tbl_erf[]
static const TableEntry tbl_log10[]
static const TableEntry tbl_erfc[]
static cl::list< std::string > UseNative("amdgpu-use-native", cl::desc("Comma separated list of functions to replace with native, or all"), cl::CommaSeparated, cl::ValueOptional, cl::Hidden)
static const TableEntry tbl_tanh[]
static Value * emitIsOddInteger(IRBuilder<> &B, Value *Y)
static const TableEntry tbl_exp2[]
Base class for AMDGPU specific classes of TargetSubtarget.
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
FunctionAnalysisManager FAM
Func getContext().diagnose(DiagnosticInfoUnsupported(Func
#define DEBUG_WITH_TYPE(TYPE,...)
DEBUG_WITH_TYPE macro - This macro should be used by passes to emit debug information.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static Function * getFunction(FunctionType *Ty, const Twine &Name, Module *M)
static void replaceCall(FPMathOperator *I, Value *With)
bool isUnsafeFiniteOnlyMath(const FPMathOperator *FPOp) const
bool canIncreasePrecisionOfConstantFold(const FPMathOperator *FPOp) const
static void replaceCall(Instruction *I, Value *With)
AMDGPULibCalls(Function &F, FunctionAnalysisManager &FAM)
bool useNative(CallInst *CI)
static unsigned char getEPtrKindFromAddrSpace(unsigned AS)
Wrapper class for AMDGPULIbFuncImpl.
static bool parse(StringRef MangledName, AMDGPULibFunc &Ptr)
std::string getName() const
Get unmangled name for mangled library function and name for unmangled library function.
static FunctionCallee getOrInsertFunction(llvm::Module *M, const AMDGPULibFunc &fInfo)
void setPrefix(ENamePrefix PFX)
bool isCompatibleSignature(const Module &M, const FunctionType *FuncTy) const
Param * getLeads()
Get leading parameters for mangled lib functions.
ENamePrefix getPrefix() const
static constexpr roundingMode rmNearestTiesToEven
LLVM_ABI double convertToDouble() const
Converts this APFloat to host double value.
bool isExactlyValue(double V) const
We don't rely on operator== working on double values, as it returns true for things that are clearly ...
LLVM_ABI float convertToFloat() const
Converts this APFloat to host float value.
LLVM_READONLY bool isOne() const
LLVM_READONLY bool isMinusOne() const
int64_t getSExtValue() const
Get sign extended value.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
bool empty() const
Check if the array is empty.
A function analysis which provides an AssumptionCache.
static LLVM_ABI Attribute getWithNoFPClass(LLVMContext &Context, FPClassTest Mask)
InstListType::iterator iterator
Instruction iterators...
void setCallingConv(CallingConv::ID CC)
void removeParamAttrs(unsigned ArgNo, const AttributeMask &AttrsToRemove)
Removes the attributes from the given argument.
bool isNoBuiltin() const
Return true if the call should not be treated as a call to a builtin.
Function * getCalledFunction() const
Returns the function called, or null if this is an indirect function invocation or the function signa...
bool isStrictFP() const
Determine if the call requires strict floating point semantics.
AttributeSet getParamAttributes(unsigned ArgNo) const
Return the param attributes for this call.
bool isNoInline() const
Return true if the call should not be inlined.
void addRetAttr(Attribute::AttrKind Kind)
Adds the attribute to the return value.
Value * getArgOperand(unsigned i) const
void setArgOperand(unsigned i, Value *v)
FunctionType * getFunctionType() const
unsigned arg_size() const
AttributeList getAttributes() const
Return the attributes for this call.
void setCalledFunction(Function *Fn)
Sets the function called, including updating the function type.
This class represents a function call, abstracting a target machine's calling convention.
static CallInst * Create(FunctionType *Ty, Value *F, const Twine &NameStr="", InsertPosition InsertBefore=nullptr)
LLVM_ABI APFloat getElementAsAPFloat(uint64_t i) const
If this is a sequential container of floating point type, return the specified element as an APFloat.
LLVM_ABI uint64_t getNumElements() const
Return the number of elements in the array or vector.
static LLVM_ABI Constant * getSplat(unsigned NumElts, Constant *Elt)
Return a ConstantVector with the specified constant in each element.
static LLVM_ABI Constant * get(LLVMContext &Context, ArrayRef< uint8_t > Elts)
get() constructors - Return a constant with vector type with an element count and element type matchi...
const APFloat & getValueAPF() const
static LLVM_ABI ConstantFP * getZero(Type *Ty, bool Negative=false)
static LLVM_ABI ConstantFP * getQNaN(Type *Ty, bool Negative=false, APInt *Payload=nullptr)
LLVM_ABI bool isExactlyValue(const APFloat &V) const
We don't rely on operator== working on double values, as it returns true for things that are clearly ...
static LLVM_ABI ConstantFP * getInfinity(Type *Ty, bool Negative=false)
This is the shared class of boolean and integer constants.
uint64_t getZExtValue() const
Return the constant as a 64-bit unsigned integer value after it has been zero extended as appropriate...
Align getAlignValue() const
Return the constant as an llvm::Align, interpreting 0 as Align(1).
static LLVM_ABI Constant * get(ArrayRef< Constant * > V)
This is an important base class in LLVM.
LLVM_ABI Constant * getAggregateElement(unsigned Elt) const
For aggregates (struct/array/vector) return the constant that corresponds to the specified element if...
static LLVM_ABI DILocation * getMergedLocations(ArrayRef< DILocation * > Locs)
Try to combine the vector of locations passed as input in a single one.
Analysis pass which computes a DominatorTree.
Utility class for floating point operations which can have information about relaxed accuracy require...
bool isFast() const
Test if this operation allows all non-strict floating-point transforms.
bool hasNoNaNs() const
Test if this operation's arguments and results are assumed not-NaN.
FastMathFlags getFastMathFlags() const
Convenience function for getting all the fast-math flags.
bool hasNoSignedZeros() const
Test if this operation can ignore the sign of zero.
bool hasNoInfs() const
Test if this operation's arguments and results are assumed not-infinite.
bool hasApproxFunc() const
Test if this operation allows approximations of math library functions or intrinsics.
LLVM_ABI float getFPAccuracy() const
Get the maximum error permitted by this operation in ULPs.
Convenience struct for specifying and reasoning about fast-math flags.
void setAllowContract(bool B=true)
A handy container for a FunctionType+Callee-pointer pair, which can be passed around as a single enti...
FunctionType * getFunctionType()
Type * getParamType(unsigned i) const
Parameter type accessors.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
bool hasMinSize() const
Optimize this function for minimum size (-Oz).
bool hasFnAttribute(Attribute::AttrKind Kind) const
Return true if the function has the attribute.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
const DebugLoc & getDebugLoc() const
Return the debug location for this node as a DebugLoc.
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 void setFastMathFlags(FastMathFlags FMF)
Convenience function for setting multiple fast-math flags on this instruction, which must be an opera...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this Instruction.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
static LLVM_ABI MDNode * getMostGenericFPMath(MDNode *A, MDNode *B)
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
A Module instance is used to store all the information related to an LLVM module.
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.
reference emplace_back(ArgTypes &&... Args)
void reserve(size_type N)
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
Analysis pass providing the TargetLibraryInfo.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
bool isVectorTy() const
True if this is an instance of VectorType.
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
bool isFloatTy() const
Return true if this is 'float', a 32-bit IEEE fp type.
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.
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.
LLVM_ABI unsigned getScalarSizeInBits() const LLVM_READONLY
If this is a vector type, return the getPrimitiveSizeInBits value for the element type.
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
bool isIntegerTy() const
True if this is an instance of IntegerType.
void dropAllReferences()
Drop all references to operands.
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.
LLVMContext & getContext() const
All values hold a context through their type.
iterator_range< user_iterator > users()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Base class of all SIMD vector types.
static LLVM_ABI VectorType * get(Type *ElementType, ElementCount EC)
This static method is the primary way to construct an VectorType.
self_iterator getIterator()
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ FLAT_ADDRESS
Address space for flat memory.
@ PRIVATE_ADDRESS
Address space for private memory.
LLVM_ABI APInt pow(const APInt &X, int64_t N)
Compute X^N for N>=0.
@ C
The default llvm calling convention, compatible with C.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
ap_match< APInt > m_APIntAllowPoison(const APInt *&Res)
Match APInt while allowing poison in splat vector constants.
bool match(Val *V, const Pattern &P)
ap_match< APFloat > m_APFloatAllowPoison(const APFloat *&Res)
Match APFloat while allowing poison in splat vector constants.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
This is an optimization pass for GlobalISel generic memory operations.
static double log2(double V)
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
RelativeUniformCounterPtr Values
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
FPClassTest
Floating-point class tests, supported by 'is_fpclass' intrinsic.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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...
LLVM_ABI raw_fd_ostream & errs()
This returns a reference to a raw_ostream for standard error.
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
auto find_if(R &&Range, UnaryPredicate P)
Provide wrappers to std::find_if which take ranges instead of having to pass begin/end explicitly.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI bool isKnownIntegral(const Value *V, const SimplifyQuery &SQ, FastMathFlags FMF)
Return true if the floating-point value V is known to be an integer value.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
LLVM_ABI bool cannotBeOrderedLessThanZero(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Return true if we can prove that the specified FP value is either NaN or never less than -0....
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
This struct is a compact representation of a valid (non-zero power of two) alignment.