61#define DEBUG_TYPE "expand-ir-insts"
72 cl::desc(
"fp convert instructions on integers with "
73 "more than <N> bits are expanded."));
78 cl::desc(
"div and rem instructions on integers with "
79 "more than <N> bits are expanded."));
93 return Opcode == Instruction::SDiv || Opcode == Instruction::SRem;
106 "ShiftAmt out of range; callers should handle ShiftAmt == 0");
108 Value *Bias = Builder.CreateLShr(Sign,
BitWidth - ShiftAmt,
"bias");
109 return Builder.CreateAdd(
X, Bias,
"adjusted");
125 bool IsDiv = (Opcode == Instruction::UDiv || Opcode == Instruction::SDiv);
128 bool IsExact = IsDiv && BO->
isExact();
131 "Expected power-of-2 constant divisor");
136 unsigned BitWidth = Ty->getIntegerBitWidth();
138 APInt DivisorVal =
C->getValue();
139 bool IsNegativeDivisor = IsSigned && DivisorVal.
isNegative();
152 Result = IsNegativeDivisor ? Builder.CreateNeg(
X) :
X;
154 Result = ConstantInt::get(Ty, 0);
155 }
else if (IsSigned) {
161 X = Builder.CreateFreeze(
X,
X->getName() +
".fr");
165 Value *Quotient = Builder.CreateAShr(
166 Dividend, ShiftAmt, IsDiv && IsNegativeDivisor ?
"pre.neg" :
"shifted",
169 Result = IsNegativeDivisor ? Builder.CreateNeg(Quotient) : Quotient;
173 Value *Truncated = Builder.CreateShl(Quotient, ShiftAmt,
"truncated");
174 Result = Builder.CreateSub(
X, Truncated);
178 Result = Builder.CreateLShr(
X, ShiftAmt,
"", IsExact);
181 Result = Builder.CreateAnd(
X, ConstantInt::get(Ty, Mask));
222 static constexpr std::array<MVT, 3> ExpandableTypes{MVT::f16, MVT::f32,
226 static bool canExpandType(
Type *Ty) {
233 static bool shouldExpandFremType(
const TargetLowering &TLI,
234 const LibcallLoweringInfo &Libcalls,
236 assert(!VT.
isVector() &&
"Cannot handle vector type; must scalarize first");
238 case TargetLowering::LegalizeAction::Expand:
240 case TargetLowering::LegalizeAction::LibCall:
250 static bool shouldExpandFremType(
const TargetLowering &TLI,
251 const LibcallLoweringInfo &Libcalls,
256 return shouldExpandFremType(TLI, Libcalls,
262 static bool shouldExpandAnyFremType(
const TargetLowering &TLI,
263 const LibcallLoweringInfo &Libcalls) {
264 return any_of(ExpandableTypes, [&](MVT V) {
265 return shouldExpandFremType(TLI, Libcalls, EVT(V));
270 assert(canExpandType(Ty) &&
"Expected supported floating point type");
274 Type *ComputeTy = Ty;
278 unsigned MaxIter = 2;
286 unsigned Precision = APFloat::semanticsPrecision(Ty->
getFltSemantics());
287 return FRemExpander{B, Ty, Precision / MaxIter, ComputeTy};
303 : B(B), FremTy(FremTy), ComputeFpTy(ComputeFpTy), ExTy(B.getInt32Ty()),
304 Bits(ConstantInt::
get(ExTy, Bits)), One(ConstantInt::
get(ExTy, 1)) {}
306 Value *createRcp(
Value *V,
const Twine &Name)
const {
309 return B.CreateFDiv(ConstantFP::get(ComputeFpTy, 1.0), V, Name);
321 Value *Q = B.CreateUnaryIntrinsic(Intrinsic::rint, B.CreateFMul(Ax, Ayinv),
323 Value *AxUpdate = B.CreateFMA(B.CreateFNeg(Q), Ay, Ax, {},
"ax");
326 Value *Axp = B.CreateFAdd(AxUpdate, Ay,
"axp");
327 return B.CreateSelect(Clt, Axp, AxUpdate,
"ax");
333 std::pair<Value *, Value *> buildExpAndPower(
Value *Src,
Value *NewExp,
335 const Twine &PowName)
const {
339 Type *Ty = Src->getType();
340 Type *ExTy = B.getInt32Ty();
341 Value *Frexp = B.CreateIntrinsic(Intrinsic::frexp, {Ty, ExTy}, Src);
342 Value *Mant = B.CreateExtractValue(Frexp, {0});
343 Value *
Exp = B.CreateExtractValue(Frexp, {1});
345 Exp = B.CreateSub(Exp, One, ExName);
346 Value *
Pow = B.CreateLdexp(Mant, NewExp, {}, PowName);
355 void buildRemainderComputation(
Value *AxInitial,
Value *AyInitial,
Value *
X,
356 PHINode *RetPhi, FastMathFlags FMF)
const {
357 IRBuilder<>::FastMathFlagGuard Guard(B);
358 B.setFastMathFlags(FMF);
365 auto [Ax, Ex] = buildExpAndPower(AxInitial, Bits,
"ex",
"ax");
366 auto [Ay, Ey] = buildExpAndPower(AyInitial, One,
"ey",
"ay");
371 Value *Nb = B.CreateSub(Ex, Ey,
"nb");
372 Value *Ayinv = createRcp(Ay,
"ayinv");
388 B.SetInsertPoint(LoopBB);
389 PHINode *NbIv = B.CreatePHI(Nb->
getType(), 2,
"nb_iv");
392 auto *AxPhi = B.CreatePHI(ComputeFpTy, 2,
"ax_loop_phi");
393 AxPhi->addIncoming(Ax, PreheaderBB);
395 Value *AxPhiUpdate = buildUpdateAx(AxPhi, Ay, Ayinv);
396 AxPhiUpdate = B.CreateLdexp(AxPhiUpdate, Bits, {},
"ax_update");
397 AxPhi->addIncoming(AxPhiUpdate, LoopBB);
398 NbIv->
addIncoming(B.CreateSub(NbIv, Bits,
"nb_update"), LoopBB);
405 B.SetInsertPoint(ExitBB);
407 auto *AxPhiExit = B.CreatePHI(ComputeFpTy, 2,
"ax_exit_phi");
408 AxPhiExit->addIncoming(Ax, PreheaderBB);
409 AxPhiExit->addIncoming(AxPhi, LoopBB);
410 auto *NbExitPhi = B.CreatePHI(Nb->
getType(), 2,
"nb_exit_phi");
411 NbExitPhi->addIncoming(NbIv, LoopBB);
412 NbExitPhi->addIncoming(Nb, PreheaderBB);
414 Value *AxFinal = B.CreateLdexp(
415 AxPhiExit, B.CreateAdd(B.CreateSub(NbExitPhi, Bits), One), {},
"ax");
416 AxFinal = buildUpdateAx(AxFinal, Ay, Ayinv);
421 AxFinal = B.CreateLdexp(AxFinal, Ey, {},
"ax");
422 if (ComputeFpTy != FremTy)
423 AxFinal = B.CreateFPTrunc(AxFinal, FremTy);
424 Value *Ret = B.CreateCopySign(AxFinal,
X);
433 void buildElseBranch(
Value *Ax,
Value *Ay,
Value *
X, PHINode *RetPhi)
const {
437 Value *Ret = B.CreateSelect(B.CreateFCmpOEQ(Ax, Ay), ZeroWithXSign,
X);
445 std::optional<SimplifyQuery> &SQ,
457 Ret = B.CreateSelect(XFinite, Ret, Nan);
465 IRBuilder<>::FastMathFlagGuard Guard(
B);
470 B.clearFastMathFlags();
473 Value *Trunc =
B.CreateUnaryIntrinsic(Intrinsic::trunc, Quot, {});
474 Value *Neg =
B.CreateFNeg(Trunc);
476 return B.CreateFMA(Neg,
Y,
X);
480 std::optional<SimplifyQuery> &SQ)
const {
481 assert(
X->getType() == FremTy &&
Y->getType() == FremTy);
483 FastMathFlags FMF =
B.getFastMathFlags();
492 Value *Ax =
B.CreateFAbs(
X, {},
"ax");
493 Value *Ay =
B.CreateFAbs(
Y, {},
"ay");
494 if (ComputeFpTy !=
X->getType()) {
495 Ax =
B.CreateFPExt(Ax, ComputeFpTy,
"ax");
496 Ay =
B.CreateFPExt(Ay, ComputeFpTy,
"ay");
498 Value *AxAyCmp =
B.CreateFCmpOGT(Ax, Ay);
500 PHINode *RetPhi =
B.CreatePHI(FremTy, 2,
"ret");
506 Ret = handleInputCornerCases(Ret,
X,
Y, SQ, FMF.
noInfs());
513 auto SavedInsertPt =
B.GetInsertPoint();
521 FastMathFlags ComputeFMF = FMF;
525 B.SetInsertPoint(ThenBB);
526 buildRemainderComputation(Ax, Ay,
X, RetPhi, FMF);
530 B.SetInsertPoint(ElseBB);
531 buildElseBranch(Ax, Ay,
X, RetPhi);
534 B.SetInsertPoint(SavedInsertPt);
542 Type *Ty =
I.getType();
543 assert(FRemExpander::canExpandType(Ty) &&
544 "Expected supported floating point type");
552 B.setFastMathFlags(FMF);
553 B.SetCurrentDebugLocation(
I.getDebugLoc());
555 const FRemExpander Expander = FRemExpander::create(
B, Ty);
557 ? Expander.buildApproxFRem(
I.getOperand(0),
I.getOperand(1))
558 : Expander.buildFRem(
I.getOperand(0),
I.getOperand(1), SQ);
560 I.replaceAllUsesWith(Ret);
626 unsigned FPMantissaWidth = FloatVal->getType()->getFPMantissaWidth() - 1;
631 if (FloatVal->getType()->isHalfTy() &&
BitWidth >= 32) {
632 if (FPToI->
getOpcode() == Instruction::FPToUI) {
633 Value *A0 = Builder.CreateFPToUI(FloatVal, Builder.getInt32Ty());
634 A1 = Builder.CreateZExt(A0, IntTy);
636 Value *A0 = Builder.CreateFPToSI(FloatVal, Builder.getInt32Ty());
637 A1 = Builder.CreateSExt(A0, IntTy);
647 FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth;
648 unsigned FloatWidth =
649 PowerOf2Ceil(FloatVal->getType()->getScalarSizeInBits());
650 unsigned ExponentWidth = FloatWidth - FPMantissaWidth - 1;
651 unsigned ExponentBias = (1 << (ExponentWidth - 1)) - 1;
653 Value *ImplicitBit = ConstantInt::get(
655 Value *SignificandMask = ConstantInt::get(
660 Entry->setName(
Twine(Entry->getName(),
"fp-to-i-entry"));
666 "fp-to-i-if-check.saturate",
F, End);
671 Builder.getContext(),
"fp-to-i-if-check.exp.size",
F, End);
677 Entry->getTerminator()->eraseFromParent();
680 Builder.SetInsertPoint(Entry);
683 FloatVal = Builder.CreateFreeze(FloatVal);
686 if (FloatVal->getType()->isX86_FP80Ty())
689 Value *ARep = Builder.CreateBitCast(FloatVal, FloatIntTy);
690 Value *PosOrNeg, *Sign;
694 Sign = Builder.CreateSelectWithUnknownProfile(
699 Builder.CreateLShr(ARep, Builder.getIntN(FloatWidth, FPMantissaWidth));
700 Value *BiasedExp = Builder.CreateAnd(
701 And, Builder.getIntN(FloatWidth, (1 << ExponentWidth) - 1),
"biased.exp");
702 Value *Abs = Builder.CreateAnd(ARep, SignificandMask);
703 Value *Significand = Builder.CreateOr(Abs, ImplicitBit,
"significand");
704 Value *ZeroResultCond = Builder.CreateICmpULT(
705 BiasedExp, Builder.getIntN(FloatWidth, ExponentBias),
"exp.is.negative");
707 Value *IsNaN = Builder.CreateFCmpUNO(FloatVal, FloatVal,
"is.nan");
708 ZeroResultCond = Builder.CreateOr(ZeroResultCond, IsNaN);
710 Value *IsNeg = Builder.CreateIsNeg(ARep);
711 ZeroResultCond = Builder.CreateOr(ZeroResultCond, IsNeg);
715 ZeroResultCond, End, IsSaturating ? CheckSaturateBB : CheckExpSizeBB);
723 Builder.SetInsertPoint(CheckSaturateBB);
729 uint64_t MaxBiasedExp = (1ULL << ExponentWidth) - 1;
730 if (SaturatingBiasedExp > MaxBiasedExp)
731 SaturatingBiasedExp = MaxBiasedExp;
732 Value *Cmp3 = Builder.CreateICmpUGE(
733 BiasedExp, ConstantInt::get(FloatIntTy, SaturatingBiasedExp));
734 Value *CondBrSat = Builder.CreateCondBr(Cmp3, SaturateBB, CheckExpSizeBB);
738 LLVMContext::MD_prof,
743 Builder.SetInsertPoint(SaturateBB);
750 Saturated = Builder.CreateSelectWithUnknownProfile(
751 PosOrNeg, SignedMax, SignedMin,
"saturated");
755 Builder.CreateBr(End);
759 Builder.SetInsertPoint(CheckExpSizeBB);
760 Value *ExpSmallerMantissaWidth = Builder.CreateICmpULT(
761 BiasedExp, Builder.getIntN(FloatWidth, ExponentBias + FPMantissaWidth),
762 "exp.smaller.mantissa.width");
766 Builder.CreateCondBr(ExpSmallerMantissaWidth, ExpSmallBB, ExpLargeBB);
772 Builder.SetInsertPoint(ExpSmallBB);
773 Value *Sub13 = Builder.CreateSub(
774 Builder.getIntN(FloatWidth, ExponentBias + FPMantissaWidth), BiasedExp);
776 Builder.CreateZExtOrTrunc(Builder.CreateLShr(Significand, Sub13), IntTy);
778 ExpSmallRes = Builder.CreateMul(ExpSmallRes, Sign);
779 Builder.CreateBr(End);
782 Builder.SetInsertPoint(ExpLargeBB);
783 Value *Sub15 = Builder.CreateAdd(
786 FloatIntTy, -
static_cast<int64_t
>(ExponentBias + FPMantissaWidth)));
787 Value *SignificandCast = Builder.CreateZExtOrTrunc(Significand, IntTy);
788 Value *ExpLargeRes = Builder.CreateShl(
789 SignificandCast, Builder.CreateZExtOrTrunc(Sub15, IntTy));
791 ExpLargeRes = Builder.CreateMul(ExpLargeRes, Sign);
792 Builder.CreateBr(End);
795 Builder.SetInsertPoint(End, End->
begin());
796 PHINode *Retval0 = Builder.CreatePHI(FPToI->
getType(), 3 + IsSaturating);
899 unsigned BitWidth = IntVal->getType()->getIntegerBitWidth();
903 FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth;
906 FPMantissaWidth = FPMantissaWidth == 10 ? 23 : FPMantissaWidth;
907 FPMantissaWidth = FPMantissaWidth == 7 ? 23 : FPMantissaWidth;
909 bool IsSigned = IToFP->
getOpcode() == Instruction::SIToFP;
913 IntVal = Builder.CreateFreeze(IntVal);
919 IntTy = Builder.getIntNTy(
BitWidth);
920 IntVal = Builder.CreateIntCast(IntVal, IntTy, IsSigned);
924 Builder.CreateShl(Builder.getIntN(
BitWidth, 1),
925 Builder.getIntN(
BitWidth, FPMantissaWidth + 3));
929 Entry->setName(
Twine(Entry->getName(),
"itofp-entry"));
949 Entry->getTerminator()->eraseFromParent();
956 Builder.SetInsertPoint(Entry);
960 Value *CondBrEntry = Builder.CreateCondBr(Cmp, End, IfEnd);
963 LLVMContext::MD_prof,
968 Builder.SetInsertPoint(IfEnd);
971 Value *
Xor = Builder.CreateXor(Shr, IntVal);
973 Value *
Call = Builder.CreateCall(CTLZ, {IsSigned ?
Sub : IntVal, True});
974 Value *Cast = Builder.CreateTrunc(
Call, Builder.getInt32Ty());
975 int BitWidthNew = FloatWidth == 128 ?
BitWidth : 32;
976 Value *Sub1 = Builder.CreateSub(Builder.getIntN(BitWidthNew,
BitWidth),
977 FloatWidth == 128 ?
Call : Cast);
978 Value *Sub2 = Builder.CreateSub(Builder.getIntN(BitWidthNew,
BitWidth - 1),
979 FloatWidth == 128 ?
Call : Cast);
980 Value *Cmp3 = Builder.CreateICmpSGT(
981 Sub1, Builder.getIntN(BitWidthNew, FPMantissaWidth + 1));
985 Value *CondBrIfEnd = Builder.CreateCondBr(Cmp3, IfThen4, IfElse);
988 LLVMContext::MD_prof,
993 Builder.SetInsertPoint(IfThen4);
995 SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 2), SwBB);
996 SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 3), SwEpilog);
1003 LLVMContext::MD_prof,
1006 llvm::MDBuilder::kUnlikelyBranchWeight,
1007 llvm::MDBuilder::kUnlikelyBranchWeight}));
1011 Builder.SetInsertPoint(SwBB);
1013 Builder.CreateShl(IsSigned ?
Sub : IntVal, Builder.getIntN(
BitWidth, 1));
1014 Builder.CreateBr(SwEpilog);
1017 Builder.SetInsertPoint(SwDefault);
1018 Value *Sub5 = Builder.CreateSub(
1019 Builder.getIntN(BitWidthNew,
BitWidth - FPMantissaWidth - 3),
1020 FloatWidth == 128 ?
Call : Cast);
1021 Value *ShProm = Builder.CreateZExt(Sub5, IntTy);
1022 Value *Shr6 = Builder.CreateLShr(IsSigned ?
Sub : IntVal,
1023 FloatWidth == 128 ? Sub5 : ShProm);
1025 Builder.CreateAdd(FloatWidth == 128 ?
Call : Cast,
1026 Builder.getIntN(BitWidthNew, FPMantissaWidth + 3));
1027 Value *ShProm9 = Builder.CreateZExt(Sub8, IntTy);
1029 FloatWidth == 128 ? Sub8 : ShProm9);
1030 Value *
And = Builder.CreateAnd(Shr9, IsSigned ?
Sub : IntVal);
1032 Value *Conv11 = Builder.CreateZExt(Cmp10, IntTy);
1033 Value *
Or = Builder.CreateOr(Shr6, Conv11);
1034 Builder.CreateBr(SwEpilog);
1037 Builder.SetInsertPoint(SwEpilog);
1038 PHINode *AAddr0 = Builder.CreatePHI(IntTy, 3);
1042 Value *A0 = Builder.CreateTrunc(AAddr0, Builder.getInt32Ty());
1043 Value *A1 = Builder.CreateLShr(A0, Builder.getInt32(2));
1044 Value *A2 = Builder.CreateAnd(A1, Builder.getInt32(1));
1045 Value *Conv16 = Builder.CreateZExt(A2, IntTy);
1046 Value *Or17 = Builder.CreateOr(AAddr0, Conv16);
1047 Value *Inc = Builder.CreateAdd(Or17, Builder.getIntN(
BitWidth, 1));
1048 Value *Shr18 =
nullptr;
1050 Shr18 = Builder.CreateAShr(Inc, Builder.getIntN(
BitWidth, 2));
1052 Shr18 = Builder.CreateLShr(Inc, Builder.getIntN(
BitWidth, 2));
1053 Value *A3 = Builder.CreateAnd(Inc, Temp1,
"a3");
1054 Value *PosOrNeg = Builder.CreateICmpEQ(A3, Builder.getIntN(
BitWidth, 0));
1055 Value *ExtractT60 = Builder.CreateTrunc(Shr18, Builder.getIntNTy(FloatWidth));
1056 Value *Extract63 = Builder.CreateLShr(Shr18, Builder.getIntN(
BitWidth, 32));
1057 Value *ExtractT64 =
nullptr;
1058 if (FloatWidth > 80)
1059 ExtractT64 = Builder.CreateTrunc(Sub2, Builder.getInt64Ty());
1061 ExtractT64 = Builder.CreateTrunc(Extract63, Builder.getInt32Ty());
1064 Value *CondBrSwEpilog = Builder.CreateCondBr(PosOrNeg, IfEnd26, IfThen20);
1067 LLVMContext::MD_prof,
1072 Builder.SetInsertPoint(IfThen20);
1073 Value *Shr21 =
nullptr;
1075 Shr21 = Builder.CreateAShr(Inc, Builder.getIntN(
BitWidth, 3));
1077 Shr21 = Builder.CreateLShr(Inc, Builder.getIntN(
BitWidth, 3));
1078 Value *ExtractT = Builder.CreateTrunc(Shr21, Builder.getIntNTy(FloatWidth));
1079 Value *Extract = Builder.CreateLShr(Shr21, Builder.getIntN(
BitWidth, 32));
1080 Value *ExtractT62 =
nullptr;
1081 if (FloatWidth > 80)
1082 ExtractT62 = Builder.CreateTrunc(Sub1, Builder.getInt64Ty());
1084 ExtractT62 = Builder.CreateTrunc(Extract, Builder.getInt32Ty());
1085 Builder.CreateBr(IfEnd26);
1088 Builder.SetInsertPoint(IfElse);
1089 Value *Sub24 = Builder.CreateAdd(
1090 FloatWidth == 128 ?
Call : Cast,
1092 -(
int)(
BitWidth - FPMantissaWidth - 1)));
1093 Value *ShProm25 = Builder.CreateZExt(Sub24, IntTy);
1094 Value *Shl26 = Builder.CreateShl(IsSigned ?
Sub : IntVal,
1095 FloatWidth == 128 ? Sub24 : ShProm25);
1096 Value *ExtractT61 = Builder.CreateTrunc(Shl26, Builder.getIntNTy(FloatWidth));
1097 Value *Extract65 = Builder.CreateLShr(Shl26, Builder.getIntN(
BitWidth, 32));
1098 Value *ExtractT66 =
nullptr;
1099 if (FloatWidth > 80)
1100 ExtractT66 = Builder.CreateTrunc(Sub2, Builder.getInt64Ty());
1102 ExtractT66 = Builder.CreateTrunc(Extract65, Builder.getInt32Ty());
1103 Builder.CreateBr(IfEnd26);
1106 Builder.SetInsertPoint(IfEnd26);
1107 PHINode *AAddr1Off0 = Builder.CreatePHI(Builder.getIntNTy(FloatWidth), 3);
1111 PHINode *AAddr1Off32 =
nullptr;
1112 if (FloatWidth > 32) {
1114 Builder.CreatePHI(Builder.getIntNTy(FloatWidth > 80 ? 64 : 32), 3);
1120 if (FloatWidth <= 80) {
1121 E0 = Builder.CreatePHI(Builder.getIntNTy(BitWidthNew), 3);
1122 E0->addIncoming(Sub1, IfThen20);
1123 E0->addIncoming(Sub2, SwEpilog);
1124 E0->addIncoming(Sub2, IfElse);
1126 Value *And29 =
nullptr;
1127 if (FloatWidth > 80) {
1128 Value *Temp2 = Builder.CreateShl(Builder.getIntN(
BitWidth, 1),
1130 And29 = Builder.CreateAnd(Shr, Temp2,
"and29");
1132 Value *Conv28 = Builder.CreateTrunc(Shr, Builder.getInt32Ty());
1133 And29 = Builder.CreateAnd(
1136 unsigned TempMod = FPMantissaWidth % 32;
1137 Value *And34 =
nullptr;
1138 Value *Shl30 =
nullptr;
1139 if (FloatWidth > 80) {
1141 Value *
Add = Builder.CreateShl(AAddr1Off32, Builder.getInt64(TempMod));
1142 Shl30 = Builder.CreateAdd(
1143 Add, Builder.getInt64(((1ull << (62ull - TempMod)) - 1ull) << TempMod));
1144 And34 = Builder.CreateZExt(Shl30, Builder.getInt128Ty());
1146 Value *
Add = Builder.CreateShl(E0, Builder.getInt32(TempMod));
1147 Shl30 = Builder.CreateAdd(
1148 Add, Builder.getInt32(((1 << (30 - TempMod)) - 1) << TempMod));
1149 And34 = Builder.CreateAnd(FloatWidth > 32 ? AAddr1Off32 : AAddr1Off0,
1150 Builder.getInt32((1 << TempMod) - 1));
1152 Value *Or35 =
nullptr;
1153 if (FloatWidth > 80) {
1154 Value *And29Trunc = Builder.CreateTrunc(And29, Builder.getInt128Ty());
1155 Value *Or31 = Builder.CreateOr(And29Trunc, And34);
1156 Value *Or34 = Builder.CreateShl(Or31, Builder.getIntN(128, 64));
1157 Value *Temp3 = Builder.CreateShl(Builder.getIntN(128, 1),
1158 Builder.getIntN(128, FPMantissaWidth));
1159 Value *Temp4 = Builder.CreateSub(Temp3, Builder.getIntN(128, 1));
1160 Value *A6 = Builder.CreateAnd(AAddr1Off0, Temp4);
1161 Or35 = Builder.CreateOr(Or34, A6);
1163 Value *Or31 = Builder.CreateOr(And34, And29);
1164 Or35 = Builder.CreateOr(IsSigned ? Or31 : And34, Shl30);
1166 Value *A4 =
nullptr;
1168 Value *ZExt1 = Builder.CreateZExt(Or35, Builder.getIntNTy(FloatWidth));
1169 Value *Shl1 = Builder.CreateShl(ZExt1, Builder.getIntN(FloatWidth, 32));
1171 Builder.CreateAnd(AAddr1Off0, Builder.getIntN(FloatWidth, 0xFFFFFFFF));
1172 Value *Or1 = Builder.CreateOr(Shl1, And1);
1173 A4 = Builder.CreateBitCast(Or1, IToFP->
getType());
1177 A4 = Builder.CreateFPTrunc(A40, IToFP->
getType());
1183 A4 = Builder.CreateFPTrunc(A40, IToFP->
getType());
1185 A4 = Builder.CreateBitCast(Or35, IToFP->
getType());
1195 unsigned ExponentWidth = FloatWidth - FPMantissaWidth - 1;
1196 uint64_t MinInfExp = 1ULL << (ExponentWidth - 1);
1198 Value *MinInfExpVal = Builder.getIntN(BitWidthNew, MinInfExp);
1199 Value *Overflow = Builder.CreateICmpUGE(Sub2, MinInfExpVal);
1206 Inf = Builder.CreateSelectWithUnknownProfile(IsNeg, NegInf, Inf,
1209 A4 = Builder.CreateSelect(Overflow, Inf, A4);
1213 LLVMContext::MD_prof,
1217 Builder.CreateBr(End);
1220 Builder.SetInsertPoint(End, End->
begin());
1236 unsigned NumElements = VTy->getElementCount().getFixedValue();
1238 for (
unsigned Idx = 0; Idx < NumElements; ++Idx) {
1239 Value *Ext = Builder.CreateExtractElement(
I->getOperand(0), Idx);
1241 Value *NewOp =
nullptr;
1243 NewOp = Builder.CreateBinOp(
1244 BinOp->getOpcode(), Ext,
1245 Builder.CreateExtractElement(
I->getOperand(1), Idx));
1247 NewOp = Builder.CreateCast(CastI->getOpcode(), Ext,
1248 I->getType()->getScalarType());
1250 assert(
II->getIntrinsicID() == Intrinsic::fptoui_sat ||
1251 II->getIntrinsicID() == Intrinsic::fptosi_sat);
1252 NewOp = Builder.CreateIntrinsic(
I->getType()->getScalarType(),
1253 II->getIntrinsicID(), {Ext});
1257 Result = Builder.CreateInsertElement(Result, NewOp, Idx);
1259 ScalarizedI->copyIRFlags(
I,
true);
1264 I->replaceAllUsesWith(Result);
1265 I->dropAllReferences();
1266 I->eraseFromParent();
1271 if (
I.getOperand(0)->getType()->isVectorTy())
1281 unsigned MaxLegalFpConvertBitWidth =
1290 bool DisableExpandLargeFp =
1292 bool DisableExpandLargeDivRem =
1294 bool DisableFrem = !FRemExpander::shouldExpandAnyFremType(TLI, Libcalls);
1296 if (DisableExpandLargeFp && DisableFrem && DisableExpandLargeDivRem)
1300 Type *Ty =
I.getType();
1302 if (Ty->isScalableTy())
1305 switch (
I.getOpcode()) {
1306 case Instruction::FRem:
1307 return !DisableFrem &&
1308 FRemExpander::shouldExpandFremType(TLI, Libcalls, Ty);
1309 case Instruction::FPToUI:
1310 case Instruction::FPToSI:
1311 return !DisableExpandLargeFp &&
1313 MaxLegalFpConvertBitWidth;
1314 case Instruction::UIToFP:
1315 case Instruction::SIToFP:
1316 return !DisableExpandLargeFp &&
1318 ->getIntegerBitWidth() > MaxLegalFpConvertBitWidth;
1319 case Instruction::UDiv:
1320 case Instruction::SDiv:
1321 case Instruction::URem:
1322 case Instruction::SRem:
1327 return !DisableExpandLargeDivRem &&
1329 MaxLegalDivRemBitWidth;
1330 case Instruction::Call: {
1332 if (
II && (
II->getIntrinsicID() == Intrinsic::fptoui_sat ||
1333 II->getIntrinsicID() == Intrinsic::fptosi_sat)) {
1334 return !DisableExpandLargeFp &&
1336 MaxLegalFpConvertBitWidth;
1348 if (!ShouldHandleInst(
I))
1355 while (!Worklist.
empty()) {
1358 switch (
I->getOpcode()) {
1359 case Instruction::FRem: {
1360 auto SQ = [&]() -> std::optional<SimplifyQuery> {
1362 auto Res = std::make_optional<SimplifyQuery>(
1363 I->getModule()->getDataLayout(),
I);
1374 case Instruction::FPToUI:
1377 case Instruction::FPToSI:
1381 case Instruction::UIToFP:
1382 case Instruction::SIToFP:
1386 case Instruction::UDiv:
1387 case Instruction::SDiv:
1388 case Instruction::URem:
1389 case Instruction::SRem: {
1396 unsigned Opc = BO->getOpcode();
1397 if (
Opc == Instruction::UDiv ||
Opc == Instruction::SDiv)
1404 case Instruction::Call: {
1406 assert(
II->getIntrinsicID() == Intrinsic::fptoui_sat ||
1407 II->getIntrinsicID() == Intrinsic::fptosi_sat);
1409 II->getIntrinsicID() == Intrinsic::fptosi_sat);
1419class ExpandIRInstsLegacyPass :
public FunctionPass {
1426 : FunctionPass(
ID), OptLevel(OptLevel) {}
1431 auto *TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
1432 const TargetSubtargetInfo *Subtarget = TM->getSubtargetImpl(
F);
1433 auto *TLI = Subtarget->getTargetLowering();
1434 AssumptionCache *AC =
nullptr;
1436 const LibcallLoweringInfo &Libcalls =
1437 getAnalysis<LibcallLoweringInfoWrapper>().getLibcallLowering(
1438 *
F.getParent(), *Subtarget);
1440 if (OptLevel != CodeGenOptLevel::None && !
F.hasOptNone())
1441 AC = &getAnalysis<AssumptionCacheTracker>().getAssumptionCache(
F);
1442 return runImpl(
F, *TLI, Libcalls, AC);
1445 void getAnalysisUsage(AnalysisUsage &AU)
const override {
1448 if (OptLevel != CodeGenOptLevel::None)
1459 : TM(&TM), OptLevel(OptLevel) {}
1464 OS, MapClassName2PassName);
1466 OS <<
"O" << (int)OptLevel;
1483 if (!LibcallLowering) {
1485 "' analysis required");
1496char ExpandIRInstsLegacyPass::ID = 0;
1498 "Expand certain fp instructions",
false,
false)
1504 return new ExpandIRInstsLegacyPass(OptLevel);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool runImpl(MachineFunction &MF)
static bool runOnFunction(Function &F, bool PostInlining)
static bool expandFRem(BinaryOperator &I, std::optional< SimplifyQuery > &SQ)
static void expandIToFP(Instruction *IToFP)
Generate code to convert a fp number to integer, replacing S(U)IToFP with the generated code.
static cl::opt< unsigned > ExpandDivRemBits("expand-div-rem-bits", cl::Hidden, cl::init(IntegerType::MAX_INT_BITS), cl::desc("div and rem instructions on integers with " "more than <N> bits are expanded."))
static void expandPow2DivRem(BinaryOperator *BO)
Expand division or remainder by a power-of-2 constant.
static bool isSigned(unsigned Opcode)
static void addToWorklist(Instruction &I, SmallVector< Instruction *, 4 > &Worklist)
static Value * addSignedBias(IRBuilder<> &Builder, Value *X, unsigned BitWidth, unsigned ShiftAmt)
For signed div/rem by a power of 2, compute the bias-adjusted dividend: Sign = ashr X,...
static cl::opt< unsigned > ExpandFpConvertBits("expand-fp-convert-bits", cl::Hidden, cl::init(IntegerType::MAX_INT_BITS), cl::desc("fp convert instructions on integers with " "more than <N> bits are expanded."))
static void expandFPToI(Instruction *FPToI, bool IsSaturating, bool IsSigned)
Generate code to convert a fp number to integer, replacing FPToS(U)I with the generated code.
static bool isConstantPowerOfTwo(Value *V, bool SignedOp)
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Worklist)
This is the interface for a simple mod/ref and alias analysis over globals.
Module.h This file contains the declarations for the Module class.
This header defines various interfaces for pass management in LLVM.
uint64_t IntrinsicInst * II
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_DEPENDENCY(depName)
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
This file contains the declarations for profiling metadata utility functions.
This file defines the SmallVector class.
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This file describes how to lower LLVM code to machine code.
Target-Independent Code Generator Pass Configuration Options pass.
Class for arbitrary precision integers.
static APInt getSignMask(unsigned BitWidth)
Get the SignMask for a specific bit width.
static APInt getSignedMaxValue(unsigned numBits)
Gets maximum signed value of APInt for a specific bit width.
bool isNegative() const
Determine sign of this APInt.
unsigned countr_zero() const
Count the number of trailing zero bits.
static APInt getSignedMinValue(unsigned numBits)
Gets minimum signed value of APInt for a specific bit width.
bool isPowerOf2() const
Check if this APInt's value is a power of two greater than zero.
static APInt getLowBitsSet(unsigned numBits, unsigned loBitsSet)
Constructs an APInt value that has the bottom loBitsSet bits set.
static APInt getOneBitSet(unsigned numBits, unsigned BitNo)
Return an APInt with exactly one bit set in the result.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
A function analysis which provides an AssumptionCache.
A cache of @llvm.assume calls within a function.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
LLVM_ABI BasicBlock * splitBasicBlock(iterator I, const Twine &BBName="")
Split the basic block into two basic blocks at the specified instruction.
const Function * getParent() const
Return the enclosing method, or null if none.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
BinaryOps getOpcode() const
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ ICMP_SGT
signed greater than
static LLVM_ABI ConstantFP * getZero(Type *Ty, bool Negative=false)
static LLVM_ABI ConstantFP * getQNaN(Type *Ty, bool Negative=false, APInt *Payload=nullptr)
static LLVM_ABI ConstantFP * getInfinity(Type *Ty, bool Negative=false)
This is the shared class of boolean and integer constants.
static LLVM_ABI ConstantInt * getTrue(LLVMContext &Context)
static ConstantInt * getSigned(IntegerType *Ty, int64_t V, bool ImplicitTrunc=false)
Return a ConstantInt with the specified value for the specified type.
static LLVM_ABI Constant * getAllOnesValue(Type *Ty)
static LLVM_ABI Constant * getNullValue(Type *Ty)
Constructor to create a '0' constant of arbitrary type.
LLVM_ABI ExpandIRInstsPass(const TargetMachine &TM, CodeGenOptLevel OptLevel)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
LLVM_ABI void printPipeline(raw_ostream &OS, function_ref< StringRef(StringRef)> MapClassName2PassName)
Convenience struct for specifying and reasoning about fast-math flags.
void setAllowContract(bool B=true)
void setAllowReciprocal(bool B=true)
void setNoNaNs(bool B=true)
void setNoInfs(bool B=true)
FunctionPass class - This class is used to implement most global optimizations.
Module * getParent()
Get the module that this global value is contained inside of...
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI bool isExact() const LLVM_READONLY
Determine whether the exact flag is set.
LLVM_ABI void setMetadata(unsigned KindID, MDNode *Node)
Set the metadata of the specified kind to the specified node.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
Class to represent integer types.
@ MAX_INT_BITS
Maximum number of bits that can be specified.
Tracks which library functions to use for a particular subtarget or function.
RTLIB::LibcallImpl getLibcallImpl(RTLIB::Libcall Call) const
Return the lowering's selection of implementation call for Call.
LLVM_ABI MDNode * createBranchWeights(uint32_t TrueWeight, uint32_t FalseWeight, bool IsExpected=false)
Return metadata containing two branch weights.
LLVM_ABI MDNode * createLikelyBranchWeights()
Return metadata containing two branch weights, with significant bias towards true destination.
LLVM_ABI MDNode * createUnlikelyBranchWeights()
Return metadata containing two branch weights, with significant bias towards false destination.
Records a mapping from an opaque lowering context to its LibcallLoweringInfo.
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
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.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
unsigned getMaxDivRemBitWidthSupported() const
Returns the size in bits of the maximum div/rem the backend supports.
unsigned getMaxLargeFPConvertBitWidthSupported() const
Returns the size in bits of the maximum fp to/from int conversion the backend supports.
LegalizeAction getOperationAction(unsigned Op, EVT VT) const
Return how this operation should be treated: either it is legal, needs to be promoted to a larger siz...
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
Primary interface to the complete machine description for the target machine.
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetLowering * getTargetLowering() const
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.
LLVM_ABI unsigned getIntegerBitWidth() const
bool isX86_FP80Ty() const
Return true if this is x86 long double.
bool isBFloatTy() const
Return true if this is 'bfloat', a 16-bit bfloat type.
static LLVM_ABI Type * getFP128Ty(LLVMContext &C)
Type * getScalarType() const
If this is a vector type, return the element type, otherwise return 'this'.
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.
static LLVM_ABI IntegerType * getIntNTy(LLVMContext &C, unsigned N)
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
LLVM_ABI int getFPMantissaWidth() const
Return the width of the mantissa of this type.
LLVM_ABI const fltSemantics & getFltSemantics() const
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.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
An efficient, type-erasing, non-owning reference to a callable.
const ParentTy * getParent() const
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ BasicBlock
Various leaf nodes.
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > OverloadTys={})
Look up the Function declaration of the intrinsic id in the Module M.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI bool expandDivision(BinaryOperator *Div)
Generate code to divide two integers, replacing Div with the generated code.
LLVM_ABI cl::opt< bool > ProfcheckDisableMetadataFixes
LLVM_ABI bool isKnownNeverInfinity(const Value *V, const SimplifyQuery &SQ, unsigned Depth=0)
Return true if the floating-point scalar value is not an infinity or if the floating-point vector val...
LLVM_ABI void setExplicitlyUnknownBranchWeightsIfProfiled(Instruction &I, StringRef PassName, const Function *F=nullptr)
Like setExplicitlyUnknownBranchWeights(...), but only sets unknown branch weights in the new instruct...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
OuterAnalysisManagerProxy< ModuleAnalysisManager, Function > ModuleAnalysisManagerFunctionProxy
Provide the ModuleAnalysisManager to Function proxy.
LLVM_ABI void applyProfMetadataIfEnabled(Value *V, llvm::function_ref< void(Instruction *)> setMetadataCallback)
inst_iterator inst_begin(Function *F)
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
LLVM_ABI FunctionPass * createExpandIRInstsPass(CodeGenOptLevel)
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI const LibcallLoweringInfo & getLibcallLowering(const ModuleLibcallLoweringInfo &ModuleInfo, const TargetSubtargetInfo &Subtarget)
Resolve the LibcallLoweringInfo for Subtarget from the module-level ModuleInfo, applying the subtarge...
decltype(auto) get(const PointerIntPair< PointerTy, IntBits, IntType, PtrTraits, Info > &Pair)
LLVM_ABI void SplitBlockAndInsertIfThenElse(Value *Cond, BasicBlock::iterator SplitBefore, Instruction **ThenTerm, Instruction **ElseTerm, MDNode *BranchWeights=nullptr, DomTreeUpdater *DTU=nullptr, LoopInfo *LI=nullptr)
SplitBlockAndInsertIfThenElse is similar to SplitBlockAndInsertIfThen, but also creates the ElseBlock...
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
CodeGenOptLevel
Code generation optimization level.
inst_iterator inst_end(Function *F)
IRBuilder(LLVMContext &, FolderTy, InserterTy, MDNode *, ArrayRef< OperandBundleDef >) -> IRBuilder< FolderTy, InserterTy >
@ Xor
Bitwise or logical XOR of integers.
@ Sub
Subtraction of integers.
LLVM_ABI bool isGuaranteedNotToBeUndefOrPoison(const Value *V, AssumptionCache *AC=nullptr, const Instruction *CtxI=nullptr, const DominatorTree *DT=nullptr, unsigned Depth=0)
Return true if this function can prove that V does not have undef bits and is never poison.
constexpr unsigned BitWidth
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
LLVM_ABI bool expandRemainder(BinaryOperator *Rem)
Generate code to calculate the remainder of two integers, replacing Rem with the generated code.
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.
bool isSimple() const
Test if the given EVT is simple (as opposed to being extended).
static LLVM_ABI EVT getEVT(Type *Ty, bool HandleUnknown=false)
Return the value type corresponding to the specified type.
MVT getSimpleVT() const
Return the SimpleValueType held in the specified simple EVT.
bool isVector() const
Return true if this is a vector value type.
A CRTP mix-in to automatically provide informational APIs needed for passes.