xref: /llvm-project/llvm/lib/CodeGen/ExpandLargeFpConvert.cpp (revision 735ab61ac828bd61398e6847d60e308fdf2b54ec)
189f36dd8SFreddy Ye //===--- ExpandLargeFpConvert.cpp - Expand large fp convert----------------===//
289f36dd8SFreddy Ye //
389f36dd8SFreddy Ye // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
489f36dd8SFreddy Ye // See https://llvm.org/LICENSE.txt for license information.
589f36dd8SFreddy Ye // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
689f36dd8SFreddy Ye //
789f36dd8SFreddy Ye //===----------------------------------------------------------------------===//
889f36dd8SFreddy Ye //
989f36dd8SFreddy Ye 
1089f36dd8SFreddy Ye // This pass expands ‘fptoui .. to’, ‘fptosi .. to’, ‘uitofp .. to’,
1189f36dd8SFreddy Ye // ‘sitofp .. to’ instructions with a bitwidth above a threshold into
1289f36dd8SFreddy Ye // auto-generated functions. This is useful for targets like x86_64 that cannot
1389f36dd8SFreddy Ye // lower fp convertions with more than 128 bits.
1489f36dd8SFreddy Ye //
1589f36dd8SFreddy Ye //===----------------------------------------------------------------------===//
1689f36dd8SFreddy Ye 
173cef582aSMatt Arsenault #include "llvm/CodeGen/ExpandLargeFpConvert.h"
1889f36dd8SFreddy Ye #include "llvm/ADT/SmallVector.h"
1989f36dd8SFreddy Ye #include "llvm/Analysis/GlobalsModRef.h"
2089f36dd8SFreddy Ye #include "llvm/CodeGen/Passes.h"
2189f36dd8SFreddy Ye #include "llvm/CodeGen/TargetLowering.h"
2289f36dd8SFreddy Ye #include "llvm/CodeGen/TargetPassConfig.h"
2389f36dd8SFreddy Ye #include "llvm/CodeGen/TargetSubtargetInfo.h"
2489f36dd8SFreddy Ye #include "llvm/IR/IRBuilder.h"
2589f36dd8SFreddy Ye #include "llvm/IR/InstIterator.h"
2689f36dd8SFreddy Ye #include "llvm/IR/PassManager.h"
2789f36dd8SFreddy Ye #include "llvm/InitializePasses.h"
2889f36dd8SFreddy Ye #include "llvm/Pass.h"
2989f36dd8SFreddy Ye #include "llvm/Support/CommandLine.h"
3089f36dd8SFreddy Ye #include "llvm/Target/TargetMachine.h"
3189f36dd8SFreddy Ye 
3289f36dd8SFreddy Ye using namespace llvm;
3389f36dd8SFreddy Ye 
3489f36dd8SFreddy Ye static cl::opt<unsigned>
3589f36dd8SFreddy Ye     ExpandFpConvertBits("expand-fp-convert-bits", cl::Hidden,
3689f36dd8SFreddy Ye                      cl::init(llvm::IntegerType::MAX_INT_BITS),
3789f36dd8SFreddy Ye                      cl::desc("fp convert instructions on integers with "
3889f36dd8SFreddy Ye                               "more than <N> bits are expanded."));
3989f36dd8SFreddy Ye 
4089f36dd8SFreddy Ye /// Generate code to convert a fp number to integer, replacing FPToS(U)I with
4189f36dd8SFreddy Ye /// the generated code. This currently generates code similarly to compiler-rt's
4289f36dd8SFreddy Ye /// implementations.
4389f36dd8SFreddy Ye ///
4489f36dd8SFreddy Ye /// An example IR generated from compiler-rt/fixsfdi.c looks like below:
4589f36dd8SFreddy Ye /// define dso_local i64 @foo(float noundef %a) local_unnamed_addr #0 {
4689f36dd8SFreddy Ye /// entry:
4789f36dd8SFreddy Ye ///   %0 = bitcast float %a to i32
4889f36dd8SFreddy Ye ///   %conv.i = zext i32 %0 to i64
4989f36dd8SFreddy Ye ///   %tobool.not = icmp sgt i32 %0, -1
5089f36dd8SFreddy Ye ///   %conv = select i1 %tobool.not, i64 1, i64 -1
5189f36dd8SFreddy Ye ///   %and = lshr i64 %conv.i, 23
5289f36dd8SFreddy Ye ///   %shr = and i64 %and, 255
5389f36dd8SFreddy Ye ///   %and2 = and i64 %conv.i, 8388607
5489f36dd8SFreddy Ye ///   %or = or i64 %and2, 8388608
5589f36dd8SFreddy Ye ///   %cmp = icmp ult i64 %shr, 127
5689f36dd8SFreddy Ye ///   br i1 %cmp, label %cleanup, label %if.end
5789f36dd8SFreddy Ye ///
5889f36dd8SFreddy Ye /// if.end:                                           ; preds = %entry
5989f36dd8SFreddy Ye ///   %sub = add nuw nsw i64 %shr, 4294967169
6089f36dd8SFreddy Ye ///   %conv5 = and i64 %sub, 4294967232
6189f36dd8SFreddy Ye ///   %cmp6.not = icmp eq i64 %conv5, 0
6289f36dd8SFreddy Ye ///   br i1 %cmp6.not, label %if.end12, label %if.then8
6389f36dd8SFreddy Ye ///
6489f36dd8SFreddy Ye /// if.then8:                                         ; preds = %if.end
6589f36dd8SFreddy Ye ///   %cond11 = select i1 %tobool.not, i64 9223372036854775807, i64 -9223372036854775808
6689f36dd8SFreddy Ye ///   br label %cleanup
6789f36dd8SFreddy Ye ///
6889f36dd8SFreddy Ye /// if.end12:                                         ; preds = %if.end
6989f36dd8SFreddy Ye ///   %cmp13 = icmp ult i64 %shr, 150
7089f36dd8SFreddy Ye ///   br i1 %cmp13, label %if.then15, label %if.else
7189f36dd8SFreddy Ye ///
7289f36dd8SFreddy Ye /// if.then15:                                        ; preds = %if.end12
7389f36dd8SFreddy Ye ///   %sub16 = sub nuw nsw i64 150, %shr
7489f36dd8SFreddy Ye ///   %shr17 = lshr i64 %or, %sub16
7589f36dd8SFreddy Ye ///   %mul = mul nsw i64 %shr17, %conv
7689f36dd8SFreddy Ye ///   br label %cleanup
7789f36dd8SFreddy Ye ///
7889f36dd8SFreddy Ye /// if.else:                                          ; preds = %if.end12
7989f36dd8SFreddy Ye ///   %sub18 = add nsw i64 %shr, -150
8089f36dd8SFreddy Ye ///   %shl = shl i64 %or, %sub18
8189f36dd8SFreddy Ye ///   %mul19 = mul nsw i64 %shl, %conv
8289f36dd8SFreddy Ye ///   br label %cleanup
8389f36dd8SFreddy Ye ///
8489f36dd8SFreddy Ye /// cleanup:                                          ; preds = %entry, %if.else, %if.then15, %if.then8
8589f36dd8SFreddy Ye ///   %retval.0 = phi i64 [ %cond11, %if.then8 ], [ %mul, %if.then15 ], [ %mul19, %if.else ], [ 0, %entry ]
8689f36dd8SFreddy Ye ///   ret i64 %retval.0
8789f36dd8SFreddy Ye /// }
8889f36dd8SFreddy Ye ///
8989f36dd8SFreddy Ye /// Replace fp to integer with generated code.
9089f36dd8SFreddy Ye static void expandFPToI(Instruction *FPToI) {
9189f36dd8SFreddy Ye   IRBuilder<> Builder(FPToI);
9289f36dd8SFreddy Ye   auto *FloatVal = FPToI->getOperand(0);
9389f36dd8SFreddy Ye   IntegerType *IntTy = cast<IntegerType>(FPToI->getType());
9489f36dd8SFreddy Ye 
9589f36dd8SFreddy Ye   unsigned BitWidth = FPToI->getType()->getIntegerBitWidth();
9689f36dd8SFreddy Ye   unsigned FPMantissaWidth = FloatVal->getType()->getFPMantissaWidth() - 1;
9789f36dd8SFreddy Ye 
9889f36dd8SFreddy Ye   // FIXME: fp16's range is covered by i32. So `fptoi half` can convert
9989f36dd8SFreddy Ye   // to i32 first following a sext/zext to target integer type.
10089f36dd8SFreddy Ye   Value *A1 = nullptr;
10189f36dd8SFreddy Ye   if (FloatVal->getType()->isHalfTy()) {
10289f36dd8SFreddy Ye     if (FPToI->getOpcode() == Instruction::FPToUI) {
10389f36dd8SFreddy Ye       Value *A0 = Builder.CreateFPToUI(FloatVal, Builder.getIntNTy(32));
10489f36dd8SFreddy Ye       A1 = Builder.CreateZExt(A0, IntTy);
10589f36dd8SFreddy Ye     } else { // FPToSI
10689f36dd8SFreddy Ye       Value *A0 = Builder.CreateFPToSI(FloatVal, Builder.getIntNTy(32));
10789f36dd8SFreddy Ye       A1 = Builder.CreateSExt(A0, IntTy);
10889f36dd8SFreddy Ye     }
10989f36dd8SFreddy Ye     FPToI->replaceAllUsesWith(A1);
11089f36dd8SFreddy Ye     FPToI->dropAllReferences();
11189f36dd8SFreddy Ye     FPToI->eraseFromParent();
11289f36dd8SFreddy Ye     return;
11389f36dd8SFreddy Ye   }
11489f36dd8SFreddy Ye 
11589f36dd8SFreddy Ye   // fp80 conversion is implemented by fpext to fp128 first then do the
11689f36dd8SFreddy Ye   // conversion.
11789f36dd8SFreddy Ye   FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth;
118110c22feSBevin Hansson   unsigned FloatWidth =
119110c22feSBevin Hansson       PowerOf2Ceil(FloatVal->getType()->getScalarSizeInBits());
12089f36dd8SFreddy Ye   unsigned ExponentWidth = FloatWidth - FPMantissaWidth - 1;
12189f36dd8SFreddy Ye   unsigned ExponentBias = (1 << (ExponentWidth - 1)) - 1;
12289f36dd8SFreddy Ye   Value *ImplicitBit = Builder.CreateShl(
12389f36dd8SFreddy Ye       Builder.getIntN(BitWidth, 1), Builder.getIntN(BitWidth, FPMantissaWidth));
12489f36dd8SFreddy Ye   Value *SignificandMask =
12589f36dd8SFreddy Ye       Builder.CreateSub(ImplicitBit, Builder.getIntN(BitWidth, 1));
12689f36dd8SFreddy Ye   Value *NegOne = Builder.CreateSExt(
12789f36dd8SFreddy Ye       ConstantInt::getSigned(Builder.getInt32Ty(), -1), IntTy);
12889f36dd8SFreddy Ye   Value *NegInf =
12989f36dd8SFreddy Ye       Builder.CreateShl(ConstantInt::getSigned(IntTy, 1),
13089f36dd8SFreddy Ye                         ConstantInt::getSigned(IntTy, BitWidth - 1));
13189f36dd8SFreddy Ye 
13289f36dd8SFreddy Ye   BasicBlock *Entry = Builder.GetInsertBlock();
13389f36dd8SFreddy Ye   Function *F = Entry->getParent();
13489f36dd8SFreddy Ye   Entry->setName(Twine(Entry->getName(), "fp-to-i-entry"));
13589f36dd8SFreddy Ye   BasicBlock *End =
13689f36dd8SFreddy Ye       Entry->splitBasicBlock(Builder.GetInsertPoint(), "fp-to-i-cleanup");
13789f36dd8SFreddy Ye   BasicBlock *IfEnd =
13889f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-end", F, End);
13989f36dd8SFreddy Ye   BasicBlock *IfThen5 =
14089f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-then5", F, End);
14189f36dd8SFreddy Ye   BasicBlock *IfEnd9 =
14289f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-end9", F, End);
14389f36dd8SFreddy Ye   BasicBlock *IfThen12 =
14489f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-then12", F, End);
14589f36dd8SFreddy Ye   BasicBlock *IfElse =
14689f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-else", F, End);
14789f36dd8SFreddy Ye 
14889f36dd8SFreddy Ye   Entry->getTerminator()->eraseFromParent();
14989f36dd8SFreddy Ye 
15089f36dd8SFreddy Ye   // entry:
15189f36dd8SFreddy Ye   Builder.SetInsertPoint(Entry);
15289f36dd8SFreddy Ye   Value *FloatVal0 = FloatVal;
15389f36dd8SFreddy Ye   // fp80 conversion is implemented by fpext to fp128 first then do the
15489f36dd8SFreddy Ye   // conversion.
15589f36dd8SFreddy Ye   if (FloatVal->getType()->isX86_FP80Ty())
15689f36dd8SFreddy Ye     FloatVal0 =
15789f36dd8SFreddy Ye         Builder.CreateFPExt(FloatVal, Type::getFP128Ty(Builder.getContext()));
15889f36dd8SFreddy Ye   Value *ARep0 =
15989f36dd8SFreddy Ye       Builder.CreateBitCast(FloatVal0, Builder.getIntNTy(FloatWidth));
16089f36dd8SFreddy Ye   Value *ARep = Builder.CreateZExt(ARep0, FPToI->getType());
16189f36dd8SFreddy Ye   Value *PosOrNeg = Builder.CreateICmpSGT(
16289f36dd8SFreddy Ye       ARep0, ConstantInt::getSigned(Builder.getIntNTy(FloatWidth), -1));
16389f36dd8SFreddy Ye   Value *Sign = Builder.CreateSelect(PosOrNeg, ConstantInt::getSigned(IntTy, 1),
16489f36dd8SFreddy Ye                                      ConstantInt::getSigned(IntTy, -1));
16589f36dd8SFreddy Ye   Value *And =
16689f36dd8SFreddy Ye       Builder.CreateLShr(ARep, Builder.getIntN(BitWidth, FPMantissaWidth));
16789f36dd8SFreddy Ye   Value *And2 = Builder.CreateAnd(
16889f36dd8SFreddy Ye       And, Builder.getIntN(BitWidth, (1 << ExponentWidth) - 1));
16989f36dd8SFreddy Ye   Value *Abs = Builder.CreateAnd(ARep, SignificandMask);
17089f36dd8SFreddy Ye   Value *Or = Builder.CreateOr(Abs, ImplicitBit);
17189f36dd8SFreddy Ye   Value *Cmp =
17289f36dd8SFreddy Ye       Builder.CreateICmpULT(And2, Builder.getIntN(BitWidth, ExponentBias));
17389f36dd8SFreddy Ye   Builder.CreateCondBr(Cmp, End, IfEnd);
17489f36dd8SFreddy Ye 
17589f36dd8SFreddy Ye   // if.end:
17689f36dd8SFreddy Ye   Builder.SetInsertPoint(IfEnd);
17789f36dd8SFreddy Ye   Value *Add1 = Builder.CreateAdd(
17814c30189SBevin Hansson       And2, ConstantInt::getSigned(
17914c30189SBevin Hansson                 IntTy, -static_cast<int64_t>(ExponentBias + BitWidth)));
18014c30189SBevin Hansson   Value *Cmp3 = Builder.CreateICmpULT(
18114c30189SBevin Hansson       Add1, ConstantInt::getSigned(IntTy, -static_cast<int64_t>(BitWidth)));
18289f36dd8SFreddy Ye   Builder.CreateCondBr(Cmp3, IfThen5, IfEnd9);
18389f36dd8SFreddy Ye 
18489f36dd8SFreddy Ye   // if.then5:
18589f36dd8SFreddy Ye   Builder.SetInsertPoint(IfThen5);
18689f36dd8SFreddy Ye   Value *PosInf = Builder.CreateXor(NegOne, NegInf);
18789f36dd8SFreddy Ye   Value *Cond8 = Builder.CreateSelect(PosOrNeg, PosInf, NegInf);
18889f36dd8SFreddy Ye   Builder.CreateBr(End);
18989f36dd8SFreddy Ye 
19089f36dd8SFreddy Ye   // if.end9:
19189f36dd8SFreddy Ye   Builder.SetInsertPoint(IfEnd9);
19289f36dd8SFreddy Ye   Value *Cmp10 = Builder.CreateICmpULT(
19389f36dd8SFreddy Ye       And2, Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth));
19489f36dd8SFreddy Ye   Builder.CreateCondBr(Cmp10, IfThen12, IfElse);
19589f36dd8SFreddy Ye 
19689f36dd8SFreddy Ye   // if.then12:
19789f36dd8SFreddy Ye   Builder.SetInsertPoint(IfThen12);
19889f36dd8SFreddy Ye   Value *Sub13 = Builder.CreateSub(
19989f36dd8SFreddy Ye       Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth), And2);
20089f36dd8SFreddy Ye   Value *Shr14 = Builder.CreateLShr(Or, Sub13);
20189f36dd8SFreddy Ye   Value *Mul = Builder.CreateMul(Shr14, Sign);
20289f36dd8SFreddy Ye   Builder.CreateBr(End);
20389f36dd8SFreddy Ye 
20489f36dd8SFreddy Ye   // if.else:
20589f36dd8SFreddy Ye   Builder.SetInsertPoint(IfElse);
20689f36dd8SFreddy Ye   Value *Sub15 = Builder.CreateAdd(
20714c30189SBevin Hansson       And2, ConstantInt::getSigned(
20814c30189SBevin Hansson                 IntTy, -static_cast<int64_t>(ExponentBias + FPMantissaWidth)));
20989f36dd8SFreddy Ye   Value *Shl = Builder.CreateShl(Or, Sub15);
21089f36dd8SFreddy Ye   Value *Mul16 = Builder.CreateMul(Shl, Sign);
21189f36dd8SFreddy Ye   Builder.CreateBr(End);
21289f36dd8SFreddy Ye 
21389f36dd8SFreddy Ye   // cleanup:
214d75f9dd1SStephen Tozer   Builder.SetInsertPoint(End, End->begin());
21589f36dd8SFreddy Ye   PHINode *Retval0 = Builder.CreatePHI(FPToI->getType(), 4);
21689f36dd8SFreddy Ye 
21789f36dd8SFreddy Ye   Retval0->addIncoming(Cond8, IfThen5);
21889f36dd8SFreddy Ye   Retval0->addIncoming(Mul, IfThen12);
21989f36dd8SFreddy Ye   Retval0->addIncoming(Mul16, IfElse);
22089f36dd8SFreddy Ye   Retval0->addIncoming(Builder.getIntN(BitWidth, 0), Entry);
22189f36dd8SFreddy Ye 
22289f36dd8SFreddy Ye   FPToI->replaceAllUsesWith(Retval0);
22389f36dd8SFreddy Ye   FPToI->dropAllReferences();
22489f36dd8SFreddy Ye   FPToI->eraseFromParent();
22589f36dd8SFreddy Ye }
22689f36dd8SFreddy Ye 
22789f36dd8SFreddy Ye /// Generate code to convert a fp number to integer, replacing S(U)IToFP with
22889f36dd8SFreddy Ye /// the generated code. This currently generates code similarly to compiler-rt's
22989f36dd8SFreddy Ye /// implementations. This implementation has an implicit assumption that integer
23089f36dd8SFreddy Ye /// width is larger than fp.
23189f36dd8SFreddy Ye ///
23289f36dd8SFreddy Ye /// An example IR generated from compiler-rt/floatdisf.c looks like below:
23389f36dd8SFreddy Ye /// define dso_local float @__floatdisf(i64 noundef %a) local_unnamed_addr #0 {
23489f36dd8SFreddy Ye /// entry:
23589f36dd8SFreddy Ye ///   %cmp = icmp eq i64 %a, 0
23689f36dd8SFreddy Ye ///   br i1 %cmp, label %return, label %if.end
23789f36dd8SFreddy Ye ///
23889f36dd8SFreddy Ye /// if.end:                                           ; preds = %entry
23989f36dd8SFreddy Ye ///   %shr = ashr i64 %a, 63
24089f36dd8SFreddy Ye ///   %xor = xor i64 %shr, %a
24189f36dd8SFreddy Ye ///   %sub = sub nsw i64 %xor, %shr
24289f36dd8SFreddy Ye ///   %0 = tail call i64 @llvm.ctlz.i64(i64 %sub, i1 true), !range !5
24389f36dd8SFreddy Ye ///   %cast = trunc i64 %0 to i32
24489f36dd8SFreddy Ye ///   %sub1 = sub nuw nsw i32 64, %cast
24589f36dd8SFreddy Ye ///   %sub2 = xor i32 %cast, 63
24689f36dd8SFreddy Ye ///   %cmp3 = icmp ult i32 %cast, 40
24789f36dd8SFreddy Ye ///   br i1 %cmp3, label %if.then4, label %if.else
24889f36dd8SFreddy Ye ///
24989f36dd8SFreddy Ye /// if.then4:                                         ; preds = %if.end
25089f36dd8SFreddy Ye ///   switch i32 %sub1, label %sw.default [
25189f36dd8SFreddy Ye ///     i32 25, label %sw.bb
25289f36dd8SFreddy Ye ///     i32 26, label %sw.epilog
25389f36dd8SFreddy Ye ///   ]
25489f36dd8SFreddy Ye ///
25589f36dd8SFreddy Ye /// sw.bb:                                            ; preds = %if.then4
25689f36dd8SFreddy Ye ///   %shl = shl i64 %sub, 1
25789f36dd8SFreddy Ye ///   br label %sw.epilog
25889f36dd8SFreddy Ye ///
25989f36dd8SFreddy Ye /// sw.default:                                       ; preds = %if.then4
26089f36dd8SFreddy Ye ///   %sub5 = sub nsw i64 38, %0
26189f36dd8SFreddy Ye ///   %sh_prom = and i64 %sub5, 4294967295
26289f36dd8SFreddy Ye ///   %shr6 = lshr i64 %sub, %sh_prom
26389f36dd8SFreddy Ye ///   %shr9 = lshr i64 274877906943, %0
26489f36dd8SFreddy Ye ///   %and = and i64 %shr9, %sub
26589f36dd8SFreddy Ye ///   %cmp10 = icmp ne i64 %and, 0
26689f36dd8SFreddy Ye ///   %conv11 = zext i1 %cmp10 to i64
26789f36dd8SFreddy Ye ///   %or = or i64 %shr6, %conv11
26889f36dd8SFreddy Ye ///   br label %sw.epilog
26989f36dd8SFreddy Ye ///
27089f36dd8SFreddy Ye /// sw.epilog:                                        ; preds = %sw.default, %if.then4, %sw.bb
27189f36dd8SFreddy Ye ///   %a.addr.0 = phi i64 [ %or, %sw.default ], [ %sub, %if.then4 ], [ %shl, %sw.bb ]
27289f36dd8SFreddy Ye ///   %1 = lshr i64 %a.addr.0, 2
27389f36dd8SFreddy Ye ///   %2 = and i64 %1, 1
27489f36dd8SFreddy Ye ///   %or16 = or i64 %2, %a.addr.0
27589f36dd8SFreddy Ye ///   %inc = add nsw i64 %or16, 1
27689f36dd8SFreddy Ye ///   %3 = and i64 %inc, 67108864
27789f36dd8SFreddy Ye ///   %tobool.not = icmp eq i64 %3, 0
27889f36dd8SFreddy Ye ///   %spec.select.v = select i1 %tobool.not, i64 2, i64 3
27989f36dd8SFreddy Ye ///   %spec.select = ashr i64 %inc, %spec.select.v
28089f36dd8SFreddy Ye ///   %spec.select56 = select i1 %tobool.not, i32 %sub2, i32 %sub1
28189f36dd8SFreddy Ye ///   br label %if.end26
28289f36dd8SFreddy Ye ///
28389f36dd8SFreddy Ye /// if.else:                                          ; preds = %if.end
28489f36dd8SFreddy Ye ///   %sub23 = add nuw nsw i64 %0, 4294967256
28589f36dd8SFreddy Ye ///   %sh_prom24 = and i64 %sub23, 4294967295
28689f36dd8SFreddy Ye ///   %shl25 = shl i64 %sub, %sh_prom24
28789f36dd8SFreddy Ye ///   br label %if.end26
28889f36dd8SFreddy Ye ///
28989f36dd8SFreddy Ye /// if.end26:                                         ; preds = %sw.epilog, %if.else
29089f36dd8SFreddy Ye ///   %a.addr.1 = phi i64 [ %shl25, %if.else ], [ %spec.select, %sw.epilog ]
29189f36dd8SFreddy Ye ///   %e.0 = phi i32 [ %sub2, %if.else ], [ %spec.select56, %sw.epilog ]
29289f36dd8SFreddy Ye ///   %conv27 = trunc i64 %shr to i32
29389f36dd8SFreddy Ye ///   %and28 = and i32 %conv27, -2147483648
29489f36dd8SFreddy Ye ///   %add = shl nuw nsw i32 %e.0, 23
29589f36dd8SFreddy Ye ///   %shl29 = add nuw nsw i32 %add, 1065353216
29689f36dd8SFreddy Ye ///   %conv31 = trunc i64 %a.addr.1 to i32
29789f36dd8SFreddy Ye ///   %and32 = and i32 %conv31, 8388607
29889f36dd8SFreddy Ye ///   %or30 = or i32 %and32, %and28
29989f36dd8SFreddy Ye ///   %or33 = or i32 %or30, %shl29
30089f36dd8SFreddy Ye ///   %4 = bitcast i32 %or33 to float
30189f36dd8SFreddy Ye ///   br label %return
30289f36dd8SFreddy Ye ///
30389f36dd8SFreddy Ye /// return:                                           ; preds = %entry, %if.end26
30489f36dd8SFreddy Ye ///   %retval.0 = phi float [ %4, %if.end26 ], [ 0.000000e+00, %entry ]
30589f36dd8SFreddy Ye ///   ret float %retval.0
30689f36dd8SFreddy Ye /// }
30789f36dd8SFreddy Ye ///
30889f36dd8SFreddy Ye /// Replace integer to fp with generated code.
30989f36dd8SFreddy Ye static void expandIToFP(Instruction *IToFP) {
31089f36dd8SFreddy Ye   IRBuilder<> Builder(IToFP);
31189f36dd8SFreddy Ye   auto *IntVal = IToFP->getOperand(0);
31289f36dd8SFreddy Ye   IntegerType *IntTy = cast<IntegerType>(IntVal->getType());
31389f36dd8SFreddy Ye 
31489f36dd8SFreddy Ye   unsigned BitWidth = IntVal->getType()->getIntegerBitWidth();
31589f36dd8SFreddy Ye   unsigned FPMantissaWidth = IToFP->getType()->getFPMantissaWidth() - 1;
31689f36dd8SFreddy Ye   // fp80 conversion is implemented by conversion tp fp128 first following
31789f36dd8SFreddy Ye   // a fptrunc to fp80.
31889f36dd8SFreddy Ye   FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth;
31989f36dd8SFreddy Ye   // FIXME: As there is no related builtins added in compliler-rt,
32089f36dd8SFreddy Ye   // here currently utilized the fp32 <-> fp16 lib calls to implement.
32189f36dd8SFreddy Ye   FPMantissaWidth = FPMantissaWidth == 10 ? 23 : FPMantissaWidth;
322110c22feSBevin Hansson   FPMantissaWidth = FPMantissaWidth == 7 ? 23 : FPMantissaWidth;
32389f36dd8SFreddy Ye   unsigned FloatWidth = PowerOf2Ceil(FPMantissaWidth);
32489f36dd8SFreddy Ye   bool IsSigned = IToFP->getOpcode() == Instruction::SIToFP;
32589f36dd8SFreddy Ye 
32689f36dd8SFreddy Ye   assert(BitWidth > FloatWidth && "Unexpected conversion. expandIToFP() "
32789f36dd8SFreddy Ye                                   "assumes integer width is larger than fp.");
32889f36dd8SFreddy Ye 
32989f36dd8SFreddy Ye   Value *Temp1 =
33089f36dd8SFreddy Ye       Builder.CreateShl(Builder.getIntN(BitWidth, 1),
33189f36dd8SFreddy Ye                         Builder.getIntN(BitWidth, FPMantissaWidth + 3));
33289f36dd8SFreddy Ye 
33389f36dd8SFreddy Ye   BasicBlock *Entry = Builder.GetInsertBlock();
33489f36dd8SFreddy Ye   Function *F = Entry->getParent();
33589f36dd8SFreddy Ye   Entry->setName(Twine(Entry->getName(), "itofp-entry"));
33689f36dd8SFreddy Ye   BasicBlock *End =
33789f36dd8SFreddy Ye       Entry->splitBasicBlock(Builder.GetInsertPoint(), "itofp-return");
33889f36dd8SFreddy Ye   BasicBlock *IfEnd =
33989f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "itofp-if-end", F, End);
34089f36dd8SFreddy Ye   BasicBlock *IfThen4 =
34189f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "itofp-if-then4", F, End);
34289f36dd8SFreddy Ye   BasicBlock *SwBB =
34389f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "itofp-sw-bb", F, End);
34489f36dd8SFreddy Ye   BasicBlock *SwDefault =
34589f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "itofp-sw-default", F, End);
34689f36dd8SFreddy Ye   BasicBlock *SwEpilog =
34789f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "itofp-sw-epilog", F, End);
34889f36dd8SFreddy Ye   BasicBlock *IfThen20 =
34989f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "itofp-if-then20", F, End);
35089f36dd8SFreddy Ye   BasicBlock *IfElse =
35189f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "itofp-if-else", F, End);
35289f36dd8SFreddy Ye   BasicBlock *IfEnd26 =
35389f36dd8SFreddy Ye       BasicBlock::Create(Builder.getContext(), "itofp-if-end26", F, End);
35489f36dd8SFreddy Ye 
35589f36dd8SFreddy Ye   Entry->getTerminator()->eraseFromParent();
35689f36dd8SFreddy Ye 
35789f36dd8SFreddy Ye   Function *CTLZ =
358*fa789dffSRahul Joshi       Intrinsic::getOrInsertDeclaration(F->getParent(), Intrinsic::ctlz, IntTy);
35989f36dd8SFreddy Ye   ConstantInt *True = Builder.getTrue();
36089f36dd8SFreddy Ye 
36189f36dd8SFreddy Ye   // entry:
36289f36dd8SFreddy Ye   Builder.SetInsertPoint(Entry);
36389f36dd8SFreddy Ye   Value *Cmp = Builder.CreateICmpEQ(IntVal, ConstantInt::getSigned(IntTy, 0));
36489f36dd8SFreddy Ye   Builder.CreateCondBr(Cmp, End, IfEnd);
36589f36dd8SFreddy Ye 
36689f36dd8SFreddy Ye   // if.end:
36789f36dd8SFreddy Ye   Builder.SetInsertPoint(IfEnd);
36889f36dd8SFreddy Ye   Value *Shr =
36989f36dd8SFreddy Ye       Builder.CreateAShr(IntVal, Builder.getIntN(BitWidth, BitWidth - 1));
37089f36dd8SFreddy Ye   Value *Xor = Builder.CreateXor(Shr, IntVal);
37189f36dd8SFreddy Ye   Value *Sub = Builder.CreateSub(Xor, Shr);
37289f36dd8SFreddy Ye   Value *Call = Builder.CreateCall(CTLZ, {IsSigned ? Sub : IntVal, True});
37389f36dd8SFreddy Ye   Value *Cast = Builder.CreateTrunc(Call, Builder.getInt32Ty());
37489f36dd8SFreddy Ye   int BitWidthNew = FloatWidth == 128 ? BitWidth : 32;
37589f36dd8SFreddy Ye   Value *Sub1 = Builder.CreateSub(Builder.getIntN(BitWidthNew, BitWidth),
37689f36dd8SFreddy Ye                                   FloatWidth == 128 ? Call : Cast);
37789f36dd8SFreddy Ye   Value *Sub2 = Builder.CreateSub(Builder.getIntN(BitWidthNew, BitWidth - 1),
37889f36dd8SFreddy Ye                                   FloatWidth == 128 ? Call : Cast);
37989f36dd8SFreddy Ye   Value *Cmp3 = Builder.CreateICmpSGT(
380f623adbbSBevin Hansson       Sub1, Builder.getIntN(BitWidthNew, FPMantissaWidth + 1));
38189f36dd8SFreddy Ye   Builder.CreateCondBr(Cmp3, IfThen4, IfElse);
38289f36dd8SFreddy Ye 
38389f36dd8SFreddy Ye   // if.then4:
38489f36dd8SFreddy Ye   Builder.SetInsertPoint(IfThen4);
38589f36dd8SFreddy Ye   llvm::SwitchInst *SI = Builder.CreateSwitch(Sub1, SwDefault);
38689f36dd8SFreddy Ye   SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 2), SwBB);
38789f36dd8SFreddy Ye   SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 3), SwEpilog);
38889f36dd8SFreddy Ye 
38989f36dd8SFreddy Ye   // sw.bb:
39089f36dd8SFreddy Ye   Builder.SetInsertPoint(SwBB);
39189f36dd8SFreddy Ye   Value *Shl =
39289f36dd8SFreddy Ye       Builder.CreateShl(IsSigned ? Sub : IntVal, Builder.getIntN(BitWidth, 1));
39389f36dd8SFreddy Ye   Builder.CreateBr(SwEpilog);
39489f36dd8SFreddy Ye 
39589f36dd8SFreddy Ye   // sw.default:
39689f36dd8SFreddy Ye   Builder.SetInsertPoint(SwDefault);
39789f36dd8SFreddy Ye   Value *Sub5 = Builder.CreateSub(
39889f36dd8SFreddy Ye       Builder.getIntN(BitWidthNew, BitWidth - FPMantissaWidth - 3),
39989f36dd8SFreddy Ye       FloatWidth == 128 ? Call : Cast);
40089f36dd8SFreddy Ye   Value *ShProm = Builder.CreateZExt(Sub5, IntTy);
40189f36dd8SFreddy Ye   Value *Shr6 = Builder.CreateLShr(IsSigned ? Sub : IntVal,
40289f36dd8SFreddy Ye                                    FloatWidth == 128 ? Sub5 : ShProm);
40389f36dd8SFreddy Ye   Value *Sub8 =
40489f36dd8SFreddy Ye       Builder.CreateAdd(FloatWidth == 128 ? Call : Cast,
40589f36dd8SFreddy Ye                         Builder.getIntN(BitWidthNew, FPMantissaWidth + 3));
40689f36dd8SFreddy Ye   Value *ShProm9 = Builder.CreateZExt(Sub8, IntTy);
40789f36dd8SFreddy Ye   Value *Shr9 = Builder.CreateLShr(ConstantInt::getSigned(IntTy, -1),
40889f36dd8SFreddy Ye                                    FloatWidth == 128 ? Sub8 : ShProm9);
40989f36dd8SFreddy Ye   Value *And = Builder.CreateAnd(Shr9, IsSigned ? Sub : IntVal);
41089f36dd8SFreddy Ye   Value *Cmp10 = Builder.CreateICmpNE(And, Builder.getIntN(BitWidth, 0));
41189f36dd8SFreddy Ye   Value *Conv11 = Builder.CreateZExt(Cmp10, IntTy);
41289f36dd8SFreddy Ye   Value *Or = Builder.CreateOr(Shr6, Conv11);
41389f36dd8SFreddy Ye   Builder.CreateBr(SwEpilog);
41489f36dd8SFreddy Ye 
41589f36dd8SFreddy Ye   // sw.epilog:
41689f36dd8SFreddy Ye   Builder.SetInsertPoint(SwEpilog);
41789f36dd8SFreddy Ye   PHINode *AAddr0 = Builder.CreatePHI(IntTy, 3);
41889f36dd8SFreddy Ye   AAddr0->addIncoming(Or, SwDefault);
41989f36dd8SFreddy Ye   AAddr0->addIncoming(IsSigned ? Sub : IntVal, IfThen4);
42089f36dd8SFreddy Ye   AAddr0->addIncoming(Shl, SwBB);
42189f36dd8SFreddy Ye   Value *A0 = Builder.CreateTrunc(AAddr0, Builder.getInt32Ty());
42289f36dd8SFreddy Ye   Value *A1 = Builder.CreateLShr(A0, Builder.getIntN(32, 2));
42389f36dd8SFreddy Ye   Value *A2 = Builder.CreateAnd(A1, Builder.getIntN(32, 1));
42489f36dd8SFreddy Ye   Value *Conv16 = Builder.CreateZExt(A2, IntTy);
42589f36dd8SFreddy Ye   Value *Or17 = Builder.CreateOr(AAddr0, Conv16);
42689f36dd8SFreddy Ye   Value *Inc = Builder.CreateAdd(Or17, Builder.getIntN(BitWidth, 1));
42789f36dd8SFreddy Ye   Value *Shr18 = nullptr;
42889f36dd8SFreddy Ye   if (IsSigned)
42989f36dd8SFreddy Ye     Shr18 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 2));
43089f36dd8SFreddy Ye   else
43189f36dd8SFreddy Ye     Shr18 = Builder.CreateLShr(Inc, Builder.getIntN(BitWidth, 2));
43289f36dd8SFreddy Ye   Value *A3 = Builder.CreateAnd(Inc, Temp1, "a3");
43389f36dd8SFreddy Ye   Value *PosOrNeg = Builder.CreateICmpEQ(A3, Builder.getIntN(BitWidth, 0));
43489f36dd8SFreddy Ye   Value *ExtractT60 = Builder.CreateTrunc(Shr18, Builder.getIntNTy(FloatWidth));
43589f36dd8SFreddy Ye   Value *Extract63 = Builder.CreateLShr(Shr18, Builder.getIntN(BitWidth, 32));
43689f36dd8SFreddy Ye   Value *ExtractT64 = nullptr;
43789f36dd8SFreddy Ye   if (FloatWidth > 80)
43889f36dd8SFreddy Ye     ExtractT64 = Builder.CreateTrunc(Sub2, Builder.getInt64Ty());
43989f36dd8SFreddy Ye   else
44089f36dd8SFreddy Ye     ExtractT64 = Builder.CreateTrunc(Extract63, Builder.getInt32Ty());
44189f36dd8SFreddy Ye   Builder.CreateCondBr(PosOrNeg, IfEnd26, IfThen20);
44289f36dd8SFreddy Ye 
44389f36dd8SFreddy Ye   // if.then20
44489f36dd8SFreddy Ye   Builder.SetInsertPoint(IfThen20);
44589f36dd8SFreddy Ye   Value *Shr21 = nullptr;
44689f36dd8SFreddy Ye   if (IsSigned)
44789f36dd8SFreddy Ye     Shr21 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 3));
44889f36dd8SFreddy Ye   else
44989f36dd8SFreddy Ye     Shr21 = Builder.CreateLShr(Inc, Builder.getIntN(BitWidth, 3));
45089f36dd8SFreddy Ye   Value *ExtractT = Builder.CreateTrunc(Shr21, Builder.getIntNTy(FloatWidth));
45189f36dd8SFreddy Ye   Value *Extract = Builder.CreateLShr(Shr21, Builder.getIntN(BitWidth, 32));
45289f36dd8SFreddy Ye   Value *ExtractT62 = nullptr;
45389f36dd8SFreddy Ye   if (FloatWidth > 80)
45489f36dd8SFreddy Ye     ExtractT62 = Builder.CreateTrunc(Sub1, Builder.getIntNTy(64));
45589f36dd8SFreddy Ye   else
45689f36dd8SFreddy Ye     ExtractT62 = Builder.CreateTrunc(Extract, Builder.getIntNTy(32));
45789f36dd8SFreddy Ye   Builder.CreateBr(IfEnd26);
45889f36dd8SFreddy Ye 
45989f36dd8SFreddy Ye   // if.else:
46089f36dd8SFreddy Ye   Builder.SetInsertPoint(IfElse);
46189f36dd8SFreddy Ye   Value *Sub24 = Builder.CreateAdd(
46289f36dd8SFreddy Ye       FloatWidth == 128 ? Call : Cast,
46389f36dd8SFreddy Ye       ConstantInt::getSigned(Builder.getIntNTy(BitWidthNew),
46489f36dd8SFreddy Ye                              -(BitWidth - FPMantissaWidth - 1)));
46589f36dd8SFreddy Ye   Value *ShProm25 = Builder.CreateZExt(Sub24, IntTy);
46689f36dd8SFreddy Ye   Value *Shl26 = Builder.CreateShl(IsSigned ? Sub : IntVal,
46789f36dd8SFreddy Ye                                    FloatWidth == 128 ? Sub24 : ShProm25);
46889f36dd8SFreddy Ye   Value *ExtractT61 = Builder.CreateTrunc(Shl26, Builder.getIntNTy(FloatWidth));
46989f36dd8SFreddy Ye   Value *Extract65 = Builder.CreateLShr(Shl26, Builder.getIntN(BitWidth, 32));
47089f36dd8SFreddy Ye   Value *ExtractT66 = nullptr;
47189f36dd8SFreddy Ye   if (FloatWidth > 80)
47289f36dd8SFreddy Ye     ExtractT66 = Builder.CreateTrunc(Sub2, Builder.getIntNTy(64));
47389f36dd8SFreddy Ye   else
47489f36dd8SFreddy Ye     ExtractT66 = Builder.CreateTrunc(Extract65, Builder.getInt32Ty());
47589f36dd8SFreddy Ye   Builder.CreateBr(IfEnd26);
47689f36dd8SFreddy Ye 
47789f36dd8SFreddy Ye   // if.end26:
47889f36dd8SFreddy Ye   Builder.SetInsertPoint(IfEnd26);
47989f36dd8SFreddy Ye   PHINode *AAddr1Off0 = Builder.CreatePHI(Builder.getIntNTy(FloatWidth), 3);
48089f36dd8SFreddy Ye   AAddr1Off0->addIncoming(ExtractT, IfThen20);
48189f36dd8SFreddy Ye   AAddr1Off0->addIncoming(ExtractT60, SwEpilog);
48289f36dd8SFreddy Ye   AAddr1Off0->addIncoming(ExtractT61, IfElse);
48389f36dd8SFreddy Ye   PHINode *AAddr1Off32 = nullptr;
48489f36dd8SFreddy Ye   if (FloatWidth > 32) {
48589f36dd8SFreddy Ye     AAddr1Off32 =
48689f36dd8SFreddy Ye         Builder.CreatePHI(Builder.getIntNTy(FloatWidth > 80 ? 64 : 32), 3);
48789f36dd8SFreddy Ye     AAddr1Off32->addIncoming(ExtractT62, IfThen20);
48889f36dd8SFreddy Ye     AAddr1Off32->addIncoming(ExtractT64, SwEpilog);
48989f36dd8SFreddy Ye     AAddr1Off32->addIncoming(ExtractT66, IfElse);
49089f36dd8SFreddy Ye   }
49189f36dd8SFreddy Ye   PHINode *E0 = nullptr;
49289f36dd8SFreddy Ye   if (FloatWidth <= 80) {
49389f36dd8SFreddy Ye     E0 = Builder.CreatePHI(Builder.getIntNTy(BitWidthNew), 3);
49489f36dd8SFreddy Ye     E0->addIncoming(Sub1, IfThen20);
49589f36dd8SFreddy Ye     E0->addIncoming(Sub2, SwEpilog);
49689f36dd8SFreddy Ye     E0->addIncoming(Sub2, IfElse);
49789f36dd8SFreddy Ye   }
49889f36dd8SFreddy Ye   Value *And29 = nullptr;
49989f36dd8SFreddy Ye   if (FloatWidth > 80) {
50089f36dd8SFreddy Ye     Value *Temp2 = Builder.CreateShl(Builder.getIntN(BitWidth, 1),
50189f36dd8SFreddy Ye                                      Builder.getIntN(BitWidth, 63));
50289f36dd8SFreddy Ye     And29 = Builder.CreateAnd(Shr, Temp2, "and29");
50389f36dd8SFreddy Ye   } else {
50489f36dd8SFreddy Ye     Value *Conv28 = Builder.CreateTrunc(Shr, Builder.getIntNTy(32));
50589f36dd8SFreddy Ye     And29 = Builder.CreateAnd(
50689f36dd8SFreddy Ye         Conv28, ConstantInt::getSigned(Builder.getIntNTy(32), 0x80000000));
50789f36dd8SFreddy Ye   }
50889f36dd8SFreddy Ye   unsigned TempMod = FPMantissaWidth % 32;
50989f36dd8SFreddy Ye   Value *And34 = nullptr;
51089f36dd8SFreddy Ye   Value *Shl30 = nullptr;
51189f36dd8SFreddy Ye   if (FloatWidth > 80) {
51289f36dd8SFreddy Ye     TempMod += 32;
51389f36dd8SFreddy Ye     Value *Add = Builder.CreateShl(AAddr1Off32, Builder.getIntN(64, TempMod));
51489f36dd8SFreddy Ye     Shl30 = Builder.CreateAdd(
51589f36dd8SFreddy Ye         Add,
51689f36dd8SFreddy Ye         Builder.getIntN(64, ((1ull << (62ull - TempMod)) - 1ull) << TempMod));
51789f36dd8SFreddy Ye     And34 = Builder.CreateZExt(Shl30, Builder.getIntNTy(128));
51889f36dd8SFreddy Ye   } else {
51989f36dd8SFreddy Ye     Value *Add = Builder.CreateShl(E0, Builder.getIntN(32, TempMod));
52089f36dd8SFreddy Ye     Shl30 = Builder.CreateAdd(
52189f36dd8SFreddy Ye         Add, Builder.getIntN(32, ((1 << (30 - TempMod)) - 1) << TempMod));
52289f36dd8SFreddy Ye     And34 = Builder.CreateAnd(FloatWidth > 32 ? AAddr1Off32 : AAddr1Off0,
52389f36dd8SFreddy Ye                               Builder.getIntN(32, (1 << TempMod) - 1));
52489f36dd8SFreddy Ye   }
52589f36dd8SFreddy Ye   Value *Or35 = nullptr;
52689f36dd8SFreddy Ye   if (FloatWidth > 80) {
52789f36dd8SFreddy Ye     Value *And29Trunc = Builder.CreateTrunc(And29, Builder.getIntNTy(128));
52889f36dd8SFreddy Ye     Value *Or31 = Builder.CreateOr(And29Trunc, And34);
52989f36dd8SFreddy Ye     Value *Or34 = Builder.CreateShl(Or31, Builder.getIntN(128, 64));
53089f36dd8SFreddy Ye     Value *Temp3 = Builder.CreateShl(Builder.getIntN(128, 1),
53189f36dd8SFreddy Ye                                      Builder.getIntN(128, FPMantissaWidth));
53289f36dd8SFreddy Ye     Value *Temp4 = Builder.CreateSub(Temp3, Builder.getIntN(128, 1));
53389f36dd8SFreddy Ye     Value *A6 = Builder.CreateAnd(AAddr1Off0, Temp4);
53489f36dd8SFreddy Ye     Or35 = Builder.CreateOr(Or34, A6);
53589f36dd8SFreddy Ye   } else {
53689f36dd8SFreddy Ye     Value *Or31 = Builder.CreateOr(And34, And29);
53789f36dd8SFreddy Ye     Or35 = Builder.CreateOr(IsSigned ? Or31 : And34, Shl30);
53889f36dd8SFreddy Ye   }
53989f36dd8SFreddy Ye   Value *A4 = nullptr;
54089f36dd8SFreddy Ye   if (IToFP->getType()->isDoubleTy()) {
54189f36dd8SFreddy Ye     Value *ZExt1 = Builder.CreateZExt(Or35, Builder.getIntNTy(FloatWidth));
54289f36dd8SFreddy Ye     Value *Shl1 = Builder.CreateShl(ZExt1, Builder.getIntN(FloatWidth, 32));
54389f36dd8SFreddy Ye     Value *And1 =
54489f36dd8SFreddy Ye         Builder.CreateAnd(AAddr1Off0, Builder.getIntN(FloatWidth, 0xFFFFFFFF));
54589f36dd8SFreddy Ye     Value *Or1 = Builder.CreateOr(Shl1, And1);
54689f36dd8SFreddy Ye     A4 = Builder.CreateBitCast(Or1, IToFP->getType());
54789f36dd8SFreddy Ye   } else if (IToFP->getType()->isX86_FP80Ty()) {
54889f36dd8SFreddy Ye     Value *A40 =
54989f36dd8SFreddy Ye         Builder.CreateBitCast(Or35, Type::getFP128Ty(Builder.getContext()));
55089f36dd8SFreddy Ye     A4 = Builder.CreateFPTrunc(A40, IToFP->getType());
551110c22feSBevin Hansson   } else if (IToFP->getType()->isHalfTy() || IToFP->getType()->isBFloatTy()) {
55289f36dd8SFreddy Ye     // Deal with "half" situation. This is a workaround since we don't have
55389f36dd8SFreddy Ye     // floattihf.c currently as referring.
55489f36dd8SFreddy Ye     Value *A40 =
55589f36dd8SFreddy Ye         Builder.CreateBitCast(Or35, Type::getFloatTy(Builder.getContext()));
55689f36dd8SFreddy Ye     A4 = Builder.CreateFPTrunc(A40, IToFP->getType());
55789f36dd8SFreddy Ye   } else // float type
55889f36dd8SFreddy Ye     A4 = Builder.CreateBitCast(Or35, IToFP->getType());
55989f36dd8SFreddy Ye   Builder.CreateBr(End);
56089f36dd8SFreddy Ye 
56189f36dd8SFreddy Ye   // return:
562d75f9dd1SStephen Tozer   Builder.SetInsertPoint(End, End->begin());
56389f36dd8SFreddy Ye   PHINode *Retval0 = Builder.CreatePHI(IToFP->getType(), 2);
56489f36dd8SFreddy Ye   Retval0->addIncoming(A4, IfEnd26);
56589f36dd8SFreddy Ye   Retval0->addIncoming(ConstantFP::getZero(IToFP->getType(), false), Entry);
56689f36dd8SFreddy Ye 
56789f36dd8SFreddy Ye   IToFP->replaceAllUsesWith(Retval0);
56889f36dd8SFreddy Ye   IToFP->dropAllReferences();
56989f36dd8SFreddy Ye   IToFP->eraseFromParent();
57089f36dd8SFreddy Ye }
57189f36dd8SFreddy Ye 
5727edddee2SBevin Hansson static void scalarize(Instruction *I, SmallVectorImpl<Instruction *> &Replace) {
5737edddee2SBevin Hansson   VectorType *VTy = cast<FixedVectorType>(I->getType());
5747edddee2SBevin Hansson 
5757edddee2SBevin Hansson   IRBuilder<> Builder(I);
5767edddee2SBevin Hansson 
5777edddee2SBevin Hansson   unsigned NumElements = VTy->getElementCount().getFixedValue();
5787edddee2SBevin Hansson   Value *Result = PoisonValue::get(VTy);
5797edddee2SBevin Hansson   for (unsigned Idx = 0; Idx < NumElements; ++Idx) {
5807edddee2SBevin Hansson     Value *Ext = Builder.CreateExtractElement(I->getOperand(0), Idx);
5817edddee2SBevin Hansson     Value *Cast = Builder.CreateCast(cast<CastInst>(I)->getOpcode(), Ext,
5827edddee2SBevin Hansson                                      I->getType()->getScalarType());
5837edddee2SBevin Hansson     Result = Builder.CreateInsertElement(Result, Cast, Idx);
5847edddee2SBevin Hansson     if (isa<Instruction>(Cast))
5857edddee2SBevin Hansson       Replace.push_back(cast<Instruction>(Cast));
5867edddee2SBevin Hansson   }
5877edddee2SBevin Hansson   I->replaceAllUsesWith(Result);
5887edddee2SBevin Hansson   I->dropAllReferences();
5897edddee2SBevin Hansson   I->eraseFromParent();
5907edddee2SBevin Hansson }
5917edddee2SBevin Hansson 
59289f36dd8SFreddy Ye static bool runImpl(Function &F, const TargetLowering &TLI) {
59389f36dd8SFreddy Ye   SmallVector<Instruction *, 4> Replace;
5947edddee2SBevin Hansson   SmallVector<Instruction *, 4> ReplaceVector;
59589f36dd8SFreddy Ye   bool Modified = false;
59689f36dd8SFreddy Ye 
59789f36dd8SFreddy Ye   unsigned MaxLegalFpConvertBitWidth =
59889f36dd8SFreddy Ye       TLI.getMaxLargeFPConvertBitWidthSupported();
59989f36dd8SFreddy Ye   if (ExpandFpConvertBits != llvm::IntegerType::MAX_INT_BITS)
60089f36dd8SFreddy Ye     MaxLegalFpConvertBitWidth = ExpandFpConvertBits;
60189f36dd8SFreddy Ye 
60289f36dd8SFreddy Ye   if (MaxLegalFpConvertBitWidth >= llvm::IntegerType::MAX_INT_BITS)
60389f36dd8SFreddy Ye     return false;
60489f36dd8SFreddy Ye 
60589f36dd8SFreddy Ye   for (auto &I : instructions(F)) {
60689f36dd8SFreddy Ye     switch (I.getOpcode()) {
60789f36dd8SFreddy Ye     case Instruction::FPToUI:
60889f36dd8SFreddy Ye     case Instruction::FPToSI: {
6097edddee2SBevin Hansson       // TODO: This pass doesn't handle scalable vectors.
6107edddee2SBevin Hansson       if (I.getOperand(0)->getType()->isScalableTy())
61189f36dd8SFreddy Ye         continue;
61289f36dd8SFreddy Ye 
613f991a167SSimon Pilgrim       auto *IntTy = cast<IntegerType>(I.getType()->getScalarType());
61489f36dd8SFreddy Ye       if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth)
61589f36dd8SFreddy Ye         continue;
61689f36dd8SFreddy Ye 
6177edddee2SBevin Hansson       if (I.getOperand(0)->getType()->isVectorTy())
6187edddee2SBevin Hansson         ReplaceVector.push_back(&I);
6197edddee2SBevin Hansson       else
62089f36dd8SFreddy Ye         Replace.push_back(&I);
62189f36dd8SFreddy Ye       Modified = true;
62289f36dd8SFreddy Ye       break;
62389f36dd8SFreddy Ye     }
62489f36dd8SFreddy Ye     case Instruction::UIToFP:
62589f36dd8SFreddy Ye     case Instruction::SIToFP: {
6267edddee2SBevin Hansson       // TODO: This pass doesn't handle scalable vectors.
6277edddee2SBevin Hansson       if (I.getOperand(0)->getType()->isScalableTy())
62889f36dd8SFreddy Ye         continue;
62989f36dd8SFreddy Ye 
6307edddee2SBevin Hansson       auto *IntTy =
631f991a167SSimon Pilgrim           cast<IntegerType>(I.getOperand(0)->getType()->getScalarType());
63289f36dd8SFreddy Ye       if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth)
63389f36dd8SFreddy Ye         continue;
63489f36dd8SFreddy Ye 
6357edddee2SBevin Hansson       if (I.getOperand(0)->getType()->isVectorTy())
6367edddee2SBevin Hansson         ReplaceVector.push_back(&I);
6377edddee2SBevin Hansson       else
63889f36dd8SFreddy Ye         Replace.push_back(&I);
63989f36dd8SFreddy Ye       Modified = true;
64089f36dd8SFreddy Ye       break;
64189f36dd8SFreddy Ye     }
64289f36dd8SFreddy Ye     default:
64389f36dd8SFreddy Ye       break;
64489f36dd8SFreddy Ye     }
64589f36dd8SFreddy Ye   }
64689f36dd8SFreddy Ye 
6477edddee2SBevin Hansson   while (!ReplaceVector.empty()) {
6487edddee2SBevin Hansson     Instruction *I = ReplaceVector.pop_back_val();
6497edddee2SBevin Hansson     scalarize(I, Replace);
6507edddee2SBevin Hansson   }
6517edddee2SBevin Hansson 
65289f36dd8SFreddy Ye   if (Replace.empty())
65389f36dd8SFreddy Ye     return false;
65489f36dd8SFreddy Ye 
65589f36dd8SFreddy Ye   while (!Replace.empty()) {
65689f36dd8SFreddy Ye     Instruction *I = Replace.pop_back_val();
65789f36dd8SFreddy Ye     if (I->getOpcode() == Instruction::FPToUI ||
65889f36dd8SFreddy Ye         I->getOpcode() == Instruction::FPToSI) {
65989f36dd8SFreddy Ye       expandFPToI(I);
66089f36dd8SFreddy Ye     } else {
66189f36dd8SFreddy Ye       expandIToFP(I);
66289f36dd8SFreddy Ye     }
66389f36dd8SFreddy Ye   }
66489f36dd8SFreddy Ye 
66589f36dd8SFreddy Ye   return Modified;
66689f36dd8SFreddy Ye }
66789f36dd8SFreddy Ye 
668b6942a28SBenjamin Kramer namespace {
66989f36dd8SFreddy Ye class ExpandLargeFpConvertLegacyPass : public FunctionPass {
67089f36dd8SFreddy Ye public:
67189f36dd8SFreddy Ye   static char ID;
67289f36dd8SFreddy Ye 
67389f36dd8SFreddy Ye   ExpandLargeFpConvertLegacyPass() : FunctionPass(ID) {
67489f36dd8SFreddy Ye     initializeExpandLargeFpConvertLegacyPassPass(
67589f36dd8SFreddy Ye         *PassRegistry::getPassRegistry());
67689f36dd8SFreddy Ye   }
67789f36dd8SFreddy Ye 
67889f36dd8SFreddy Ye   bool runOnFunction(Function &F) override {
67989f36dd8SFreddy Ye     auto *TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
68089f36dd8SFreddy Ye     auto *TLI = TM->getSubtargetImpl(F)->getTargetLowering();
68189f36dd8SFreddy Ye     return runImpl(F, *TLI);
68289f36dd8SFreddy Ye   }
68389f36dd8SFreddy Ye 
68489f36dd8SFreddy Ye   void getAnalysisUsage(AnalysisUsage &AU) const override {
68589f36dd8SFreddy Ye     AU.addRequired<TargetPassConfig>();
68689f36dd8SFreddy Ye     AU.addPreserved<AAResultsWrapperPass>();
68789f36dd8SFreddy Ye     AU.addPreserved<GlobalsAAWrapperPass>();
68889f36dd8SFreddy Ye   }
68989f36dd8SFreddy Ye };
690b6942a28SBenjamin Kramer } // namespace
69189f36dd8SFreddy Ye 
6923cef582aSMatt Arsenault PreservedAnalyses ExpandLargeFpConvertPass::run(Function &F,
6933cef582aSMatt Arsenault                                                 FunctionAnalysisManager &FAM) {
6943cef582aSMatt Arsenault   const TargetSubtargetInfo *STI = TM->getSubtargetImpl(F);
6953cef582aSMatt Arsenault   return runImpl(F, *STI->getTargetLowering()) ? PreservedAnalyses::none()
6963cef582aSMatt Arsenault                                                : PreservedAnalyses::all();
6973cef582aSMatt Arsenault }
6983cef582aSMatt Arsenault 
69989f36dd8SFreddy Ye char ExpandLargeFpConvertLegacyPass::ID = 0;
70089f36dd8SFreddy Ye INITIALIZE_PASS_BEGIN(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert",
70189f36dd8SFreddy Ye                       "Expand large fp convert", false, false)
70289f36dd8SFreddy Ye INITIALIZE_PASS_END(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert",
70389f36dd8SFreddy Ye                     "Expand large fp convert", false, false)
70489f36dd8SFreddy Ye 
70589f36dd8SFreddy Ye FunctionPass *llvm::createExpandLargeFpConvertPass() {
70689f36dd8SFreddy Ye   return new ExpandLargeFpConvertLegacyPass();
70789f36dd8SFreddy Ye }
708