1bdd1243dSDimitry Andric //===--- ExpandLargeFpConvert.cpp - Expand large fp convert----------------===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric 
10bdd1243dSDimitry Andric // This pass expands ‘fptoui .. to’, ‘fptosi .. to’, ‘uitofp .. to’,
11bdd1243dSDimitry Andric // ‘sitofp .. to’ instructions with a bitwidth above a threshold into
12bdd1243dSDimitry Andric // auto-generated functions. This is useful for targets like x86_64 that cannot
13bdd1243dSDimitry Andric // lower fp convertions with more than 128 bits.
14bdd1243dSDimitry Andric //
15bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
16bdd1243dSDimitry Andric 
17*5f757f3fSDimitry Andric #include "llvm/CodeGen/ExpandLargeFpConvert.h"
18bdd1243dSDimitry Andric #include "llvm/ADT/SmallVector.h"
19bdd1243dSDimitry Andric #include "llvm/ADT/StringExtras.h"
20bdd1243dSDimitry Andric #include "llvm/Analysis/GlobalsModRef.h"
21bdd1243dSDimitry Andric #include "llvm/CodeGen/Passes.h"
22bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetLowering.h"
23bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetPassConfig.h"
24bdd1243dSDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
25bdd1243dSDimitry Andric #include "llvm/IR/IRBuilder.h"
26bdd1243dSDimitry Andric #include "llvm/IR/InstIterator.h"
27bdd1243dSDimitry Andric #include "llvm/IR/PassManager.h"
28bdd1243dSDimitry Andric #include "llvm/InitializePasses.h"
29bdd1243dSDimitry Andric #include "llvm/Pass.h"
30bdd1243dSDimitry Andric #include "llvm/Support/CommandLine.h"
31bdd1243dSDimitry Andric #include "llvm/Target/TargetMachine.h"
32bdd1243dSDimitry Andric 
33bdd1243dSDimitry Andric using namespace llvm;
34bdd1243dSDimitry Andric 
35bdd1243dSDimitry Andric static cl::opt<unsigned>
36bdd1243dSDimitry Andric     ExpandFpConvertBits("expand-fp-convert-bits", cl::Hidden,
37bdd1243dSDimitry Andric                      cl::init(llvm::IntegerType::MAX_INT_BITS),
38bdd1243dSDimitry Andric                      cl::desc("fp convert instructions on integers with "
39bdd1243dSDimitry Andric                               "more than <N> bits are expanded."));
40bdd1243dSDimitry Andric 
41bdd1243dSDimitry Andric /// Generate code to convert a fp number to integer, replacing FPToS(U)I with
42bdd1243dSDimitry Andric /// the generated code. This currently generates code similarly to compiler-rt's
43bdd1243dSDimitry Andric /// implementations.
44bdd1243dSDimitry Andric ///
45bdd1243dSDimitry Andric /// An example IR generated from compiler-rt/fixsfdi.c looks like below:
46bdd1243dSDimitry Andric /// define dso_local i64 @foo(float noundef %a) local_unnamed_addr #0 {
47bdd1243dSDimitry Andric /// entry:
48bdd1243dSDimitry Andric ///   %0 = bitcast float %a to i32
49bdd1243dSDimitry Andric ///   %conv.i = zext i32 %0 to i64
50bdd1243dSDimitry Andric ///   %tobool.not = icmp sgt i32 %0, -1
51bdd1243dSDimitry Andric ///   %conv = select i1 %tobool.not, i64 1, i64 -1
52bdd1243dSDimitry Andric ///   %and = lshr i64 %conv.i, 23
53bdd1243dSDimitry Andric ///   %shr = and i64 %and, 255
54bdd1243dSDimitry Andric ///   %and2 = and i64 %conv.i, 8388607
55bdd1243dSDimitry Andric ///   %or = or i64 %and2, 8388608
56bdd1243dSDimitry Andric ///   %cmp = icmp ult i64 %shr, 127
57bdd1243dSDimitry Andric ///   br i1 %cmp, label %cleanup, label %if.end
58bdd1243dSDimitry Andric ///
59bdd1243dSDimitry Andric /// if.end:                                           ; preds = %entry
60bdd1243dSDimitry Andric ///   %sub = add nuw nsw i64 %shr, 4294967169
61bdd1243dSDimitry Andric ///   %conv5 = and i64 %sub, 4294967232
62bdd1243dSDimitry Andric ///   %cmp6.not = icmp eq i64 %conv5, 0
63bdd1243dSDimitry Andric ///   br i1 %cmp6.not, label %if.end12, label %if.then8
64bdd1243dSDimitry Andric ///
65bdd1243dSDimitry Andric /// if.then8:                                         ; preds = %if.end
66bdd1243dSDimitry Andric ///   %cond11 = select i1 %tobool.not, i64 9223372036854775807, i64 -9223372036854775808
67bdd1243dSDimitry Andric ///   br label %cleanup
68bdd1243dSDimitry Andric ///
69bdd1243dSDimitry Andric /// if.end12:                                         ; preds = %if.end
70bdd1243dSDimitry Andric ///   %cmp13 = icmp ult i64 %shr, 150
71bdd1243dSDimitry Andric ///   br i1 %cmp13, label %if.then15, label %if.else
72bdd1243dSDimitry Andric ///
73bdd1243dSDimitry Andric /// if.then15:                                        ; preds = %if.end12
74bdd1243dSDimitry Andric ///   %sub16 = sub nuw nsw i64 150, %shr
75bdd1243dSDimitry Andric ///   %shr17 = lshr i64 %or, %sub16
76bdd1243dSDimitry Andric ///   %mul = mul nsw i64 %shr17, %conv
77bdd1243dSDimitry Andric ///   br label %cleanup
78bdd1243dSDimitry Andric ///
79bdd1243dSDimitry Andric /// if.else:                                          ; preds = %if.end12
80bdd1243dSDimitry Andric ///   %sub18 = add nsw i64 %shr, -150
81bdd1243dSDimitry Andric ///   %shl = shl i64 %or, %sub18
82bdd1243dSDimitry Andric ///   %mul19 = mul nsw i64 %shl, %conv
83bdd1243dSDimitry Andric ///   br label %cleanup
84bdd1243dSDimitry Andric ///
85bdd1243dSDimitry Andric /// cleanup:                                          ; preds = %entry, %if.else, %if.then15, %if.then8
86bdd1243dSDimitry Andric ///   %retval.0 = phi i64 [ %cond11, %if.then8 ], [ %mul, %if.then15 ], [ %mul19, %if.else ], [ 0, %entry ]
87bdd1243dSDimitry Andric ///   ret i64 %retval.0
88bdd1243dSDimitry Andric /// }
89bdd1243dSDimitry Andric ///
90bdd1243dSDimitry Andric /// Replace fp to integer with generated code.
expandFPToI(Instruction * FPToI)91bdd1243dSDimitry Andric static void expandFPToI(Instruction *FPToI) {
92bdd1243dSDimitry Andric   IRBuilder<> Builder(FPToI);
93bdd1243dSDimitry Andric   auto *FloatVal = FPToI->getOperand(0);
94bdd1243dSDimitry Andric   IntegerType *IntTy = cast<IntegerType>(FPToI->getType());
95bdd1243dSDimitry Andric 
96bdd1243dSDimitry Andric   unsigned BitWidth = FPToI->getType()->getIntegerBitWidth();
97bdd1243dSDimitry Andric   unsigned FPMantissaWidth = FloatVal->getType()->getFPMantissaWidth() - 1;
98bdd1243dSDimitry Andric 
99bdd1243dSDimitry Andric   // FIXME: fp16's range is covered by i32. So `fptoi half` can convert
100bdd1243dSDimitry Andric   // to i32 first following a sext/zext to target integer type.
101bdd1243dSDimitry Andric   Value *A1 = nullptr;
102bdd1243dSDimitry Andric   if (FloatVal->getType()->isHalfTy()) {
103bdd1243dSDimitry Andric     if (FPToI->getOpcode() == Instruction::FPToUI) {
104bdd1243dSDimitry Andric       Value *A0 = Builder.CreateFPToUI(FloatVal, Builder.getIntNTy(32));
105bdd1243dSDimitry Andric       A1 = Builder.CreateZExt(A0, IntTy);
106bdd1243dSDimitry Andric     } else { // FPToSI
107bdd1243dSDimitry Andric       Value *A0 = Builder.CreateFPToSI(FloatVal, Builder.getIntNTy(32));
108bdd1243dSDimitry Andric       A1 = Builder.CreateSExt(A0, IntTy);
109bdd1243dSDimitry Andric     }
110bdd1243dSDimitry Andric     FPToI->replaceAllUsesWith(A1);
111bdd1243dSDimitry Andric     FPToI->dropAllReferences();
112bdd1243dSDimitry Andric     FPToI->eraseFromParent();
113bdd1243dSDimitry Andric     return;
114bdd1243dSDimitry Andric   }
115bdd1243dSDimitry Andric 
116bdd1243dSDimitry Andric   // fp80 conversion is implemented by fpext to fp128 first then do the
117bdd1243dSDimitry Andric   // conversion.
118bdd1243dSDimitry Andric   FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth;
119bdd1243dSDimitry Andric   unsigned FloatWidth = PowerOf2Ceil(FPMantissaWidth);
120bdd1243dSDimitry Andric   unsigned ExponentWidth = FloatWidth - FPMantissaWidth - 1;
121bdd1243dSDimitry Andric   unsigned ExponentBias = (1 << (ExponentWidth - 1)) - 1;
122bdd1243dSDimitry Andric   Value *ImplicitBit = Builder.CreateShl(
123bdd1243dSDimitry Andric       Builder.getIntN(BitWidth, 1), Builder.getIntN(BitWidth, FPMantissaWidth));
124bdd1243dSDimitry Andric   Value *SignificandMask =
125bdd1243dSDimitry Andric       Builder.CreateSub(ImplicitBit, Builder.getIntN(BitWidth, 1));
126bdd1243dSDimitry Andric   Value *NegOne = Builder.CreateSExt(
127bdd1243dSDimitry Andric       ConstantInt::getSigned(Builder.getInt32Ty(), -1), IntTy);
128bdd1243dSDimitry Andric   Value *NegInf =
129bdd1243dSDimitry Andric       Builder.CreateShl(ConstantInt::getSigned(IntTy, 1),
130bdd1243dSDimitry Andric                         ConstantInt::getSigned(IntTy, BitWidth - 1));
131bdd1243dSDimitry Andric 
132bdd1243dSDimitry Andric   BasicBlock *Entry = Builder.GetInsertBlock();
133bdd1243dSDimitry Andric   Function *F = Entry->getParent();
134bdd1243dSDimitry Andric   Entry->setName(Twine(Entry->getName(), "fp-to-i-entry"));
135bdd1243dSDimitry Andric   BasicBlock *End =
136bdd1243dSDimitry Andric       Entry->splitBasicBlock(Builder.GetInsertPoint(), "fp-to-i-cleanup");
137bdd1243dSDimitry Andric   BasicBlock *IfEnd =
138bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-end", F, End);
139bdd1243dSDimitry Andric   BasicBlock *IfThen5 =
140bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-then5", F, End);
141bdd1243dSDimitry Andric   BasicBlock *IfEnd9 =
142bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-end9", F, End);
143bdd1243dSDimitry Andric   BasicBlock *IfThen12 =
144bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-then12", F, End);
145bdd1243dSDimitry Andric   BasicBlock *IfElse =
146bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "fp-to-i-if-else", F, End);
147bdd1243dSDimitry Andric 
148bdd1243dSDimitry Andric   Entry->getTerminator()->eraseFromParent();
149bdd1243dSDimitry Andric 
150bdd1243dSDimitry Andric   // entry:
151bdd1243dSDimitry Andric   Builder.SetInsertPoint(Entry);
152bdd1243dSDimitry Andric   Value *FloatVal0 = FloatVal;
153bdd1243dSDimitry Andric   // fp80 conversion is implemented by fpext to fp128 first then do the
154bdd1243dSDimitry Andric   // conversion.
155bdd1243dSDimitry Andric   if (FloatVal->getType()->isX86_FP80Ty())
156bdd1243dSDimitry Andric     FloatVal0 =
157bdd1243dSDimitry Andric         Builder.CreateFPExt(FloatVal, Type::getFP128Ty(Builder.getContext()));
158bdd1243dSDimitry Andric   Value *ARep0 =
159bdd1243dSDimitry Andric       Builder.CreateBitCast(FloatVal0, Builder.getIntNTy(FloatWidth));
160bdd1243dSDimitry Andric   Value *ARep = Builder.CreateZExt(ARep0, FPToI->getType());
161bdd1243dSDimitry Andric   Value *PosOrNeg = Builder.CreateICmpSGT(
162bdd1243dSDimitry Andric       ARep0, ConstantInt::getSigned(Builder.getIntNTy(FloatWidth), -1));
163bdd1243dSDimitry Andric   Value *Sign = Builder.CreateSelect(PosOrNeg, ConstantInt::getSigned(IntTy, 1),
164bdd1243dSDimitry Andric                                      ConstantInt::getSigned(IntTy, -1));
165bdd1243dSDimitry Andric   Value *And =
166bdd1243dSDimitry Andric       Builder.CreateLShr(ARep, Builder.getIntN(BitWidth, FPMantissaWidth));
167bdd1243dSDimitry Andric   Value *And2 = Builder.CreateAnd(
168bdd1243dSDimitry Andric       And, Builder.getIntN(BitWidth, (1 << ExponentWidth) - 1));
169bdd1243dSDimitry Andric   Value *Abs = Builder.CreateAnd(ARep, SignificandMask);
170bdd1243dSDimitry Andric   Value *Or = Builder.CreateOr(Abs, ImplicitBit);
171bdd1243dSDimitry Andric   Value *Cmp =
172bdd1243dSDimitry Andric       Builder.CreateICmpULT(And2, Builder.getIntN(BitWidth, ExponentBias));
173bdd1243dSDimitry Andric   Builder.CreateCondBr(Cmp, End, IfEnd);
174bdd1243dSDimitry Andric 
175bdd1243dSDimitry Andric   // if.end:
176bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfEnd);
177bdd1243dSDimitry Andric   Value *Add1 = Builder.CreateAdd(
178bdd1243dSDimitry Andric       And2, ConstantInt::getSigned(IntTy, -int64_t(ExponentBias + BitWidth)));
179bdd1243dSDimitry Andric   Value *Cmp3 =
180bdd1243dSDimitry Andric       Builder.CreateICmpULT(Add1, ConstantInt::getSigned(IntTy, -BitWidth));
181bdd1243dSDimitry Andric   Builder.CreateCondBr(Cmp3, IfThen5, IfEnd9);
182bdd1243dSDimitry Andric 
183bdd1243dSDimitry Andric   // if.then5:
184bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfThen5);
185bdd1243dSDimitry Andric   Value *PosInf = Builder.CreateXor(NegOne, NegInf);
186bdd1243dSDimitry Andric   Value *Cond8 = Builder.CreateSelect(PosOrNeg, PosInf, NegInf);
187bdd1243dSDimitry Andric   Builder.CreateBr(End);
188bdd1243dSDimitry Andric 
189bdd1243dSDimitry Andric   // if.end9:
190bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfEnd9);
191bdd1243dSDimitry Andric   Value *Cmp10 = Builder.CreateICmpULT(
192bdd1243dSDimitry Andric       And2, Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth));
193bdd1243dSDimitry Andric   Builder.CreateCondBr(Cmp10, IfThen12, IfElse);
194bdd1243dSDimitry Andric 
195bdd1243dSDimitry Andric   // if.then12:
196bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfThen12);
197bdd1243dSDimitry Andric   Value *Sub13 = Builder.CreateSub(
198bdd1243dSDimitry Andric       Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth), And2);
199bdd1243dSDimitry Andric   Value *Shr14 = Builder.CreateLShr(Or, Sub13);
200bdd1243dSDimitry Andric   Value *Mul = Builder.CreateMul(Shr14, Sign);
201bdd1243dSDimitry Andric   Builder.CreateBr(End);
202bdd1243dSDimitry Andric 
203bdd1243dSDimitry Andric   // if.else:
204bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfElse);
205bdd1243dSDimitry Andric   Value *Sub15 = Builder.CreateAdd(
206bdd1243dSDimitry Andric       And2,
207bdd1243dSDimitry Andric       ConstantInt::getSigned(IntTy, -(ExponentBias + FPMantissaWidth)));
208bdd1243dSDimitry Andric   Value *Shl = Builder.CreateShl(Or, Sub15);
209bdd1243dSDimitry Andric   Value *Mul16 = Builder.CreateMul(Shl, Sign);
210bdd1243dSDimitry Andric   Builder.CreateBr(End);
211bdd1243dSDimitry Andric 
212bdd1243dSDimitry Andric   // cleanup:
213bdd1243dSDimitry Andric   Builder.SetInsertPoint(End, End->begin());
214bdd1243dSDimitry Andric   PHINode *Retval0 = Builder.CreatePHI(FPToI->getType(), 4);
215bdd1243dSDimitry Andric 
216bdd1243dSDimitry Andric   Retval0->addIncoming(Cond8, IfThen5);
217bdd1243dSDimitry Andric   Retval0->addIncoming(Mul, IfThen12);
218bdd1243dSDimitry Andric   Retval0->addIncoming(Mul16, IfElse);
219bdd1243dSDimitry Andric   Retval0->addIncoming(Builder.getIntN(BitWidth, 0), Entry);
220bdd1243dSDimitry Andric 
221bdd1243dSDimitry Andric   FPToI->replaceAllUsesWith(Retval0);
222bdd1243dSDimitry Andric   FPToI->dropAllReferences();
223bdd1243dSDimitry Andric   FPToI->eraseFromParent();
224bdd1243dSDimitry Andric }
225bdd1243dSDimitry Andric 
226bdd1243dSDimitry Andric /// Generate code to convert a fp number to integer, replacing S(U)IToFP with
227bdd1243dSDimitry Andric /// the generated code. This currently generates code similarly to compiler-rt's
228bdd1243dSDimitry Andric /// implementations. This implementation has an implicit assumption that integer
229bdd1243dSDimitry Andric /// width is larger than fp.
230bdd1243dSDimitry Andric ///
231bdd1243dSDimitry Andric /// An example IR generated from compiler-rt/floatdisf.c looks like below:
232bdd1243dSDimitry Andric /// define dso_local float @__floatdisf(i64 noundef %a) local_unnamed_addr #0 {
233bdd1243dSDimitry Andric /// entry:
234bdd1243dSDimitry Andric ///   %cmp = icmp eq i64 %a, 0
235bdd1243dSDimitry Andric ///   br i1 %cmp, label %return, label %if.end
236bdd1243dSDimitry Andric ///
237bdd1243dSDimitry Andric /// if.end:                                           ; preds = %entry
238bdd1243dSDimitry Andric ///   %shr = ashr i64 %a, 63
239bdd1243dSDimitry Andric ///   %xor = xor i64 %shr, %a
240bdd1243dSDimitry Andric ///   %sub = sub nsw i64 %xor, %shr
241bdd1243dSDimitry Andric ///   %0 = tail call i64 @llvm.ctlz.i64(i64 %sub, i1 true), !range !5
242bdd1243dSDimitry Andric ///   %cast = trunc i64 %0 to i32
243bdd1243dSDimitry Andric ///   %sub1 = sub nuw nsw i32 64, %cast
244bdd1243dSDimitry Andric ///   %sub2 = xor i32 %cast, 63
245bdd1243dSDimitry Andric ///   %cmp3 = icmp ult i32 %cast, 40
246bdd1243dSDimitry Andric ///   br i1 %cmp3, label %if.then4, label %if.else
247bdd1243dSDimitry Andric ///
248bdd1243dSDimitry Andric /// if.then4:                                         ; preds = %if.end
249bdd1243dSDimitry Andric ///   switch i32 %sub1, label %sw.default [
250bdd1243dSDimitry Andric ///     i32 25, label %sw.bb
251bdd1243dSDimitry Andric ///     i32 26, label %sw.epilog
252bdd1243dSDimitry Andric ///   ]
253bdd1243dSDimitry Andric ///
254bdd1243dSDimitry Andric /// sw.bb:                                            ; preds = %if.then4
255bdd1243dSDimitry Andric ///   %shl = shl i64 %sub, 1
256bdd1243dSDimitry Andric ///   br label %sw.epilog
257bdd1243dSDimitry Andric ///
258bdd1243dSDimitry Andric /// sw.default:                                       ; preds = %if.then4
259bdd1243dSDimitry Andric ///   %sub5 = sub nsw i64 38, %0
260bdd1243dSDimitry Andric ///   %sh_prom = and i64 %sub5, 4294967295
261bdd1243dSDimitry Andric ///   %shr6 = lshr i64 %sub, %sh_prom
262bdd1243dSDimitry Andric ///   %shr9 = lshr i64 274877906943, %0
263bdd1243dSDimitry Andric ///   %and = and i64 %shr9, %sub
264bdd1243dSDimitry Andric ///   %cmp10 = icmp ne i64 %and, 0
265bdd1243dSDimitry Andric ///   %conv11 = zext i1 %cmp10 to i64
266bdd1243dSDimitry Andric ///   %or = or i64 %shr6, %conv11
267bdd1243dSDimitry Andric ///   br label %sw.epilog
268bdd1243dSDimitry Andric ///
269bdd1243dSDimitry Andric /// sw.epilog:                                        ; preds = %sw.default, %if.then4, %sw.bb
270bdd1243dSDimitry Andric ///   %a.addr.0 = phi i64 [ %or, %sw.default ], [ %sub, %if.then4 ], [ %shl, %sw.bb ]
271bdd1243dSDimitry Andric ///   %1 = lshr i64 %a.addr.0, 2
272bdd1243dSDimitry Andric ///   %2 = and i64 %1, 1
273bdd1243dSDimitry Andric ///   %or16 = or i64 %2, %a.addr.0
274bdd1243dSDimitry Andric ///   %inc = add nsw i64 %or16, 1
275bdd1243dSDimitry Andric ///   %3 = and i64 %inc, 67108864
276bdd1243dSDimitry Andric ///   %tobool.not = icmp eq i64 %3, 0
277bdd1243dSDimitry Andric ///   %spec.select.v = select i1 %tobool.not, i64 2, i64 3
278bdd1243dSDimitry Andric ///   %spec.select = ashr i64 %inc, %spec.select.v
279bdd1243dSDimitry Andric ///   %spec.select56 = select i1 %tobool.not, i32 %sub2, i32 %sub1
280bdd1243dSDimitry Andric ///   br label %if.end26
281bdd1243dSDimitry Andric ///
282bdd1243dSDimitry Andric /// if.else:                                          ; preds = %if.end
283bdd1243dSDimitry Andric ///   %sub23 = add nuw nsw i64 %0, 4294967256
284bdd1243dSDimitry Andric ///   %sh_prom24 = and i64 %sub23, 4294967295
285bdd1243dSDimitry Andric ///   %shl25 = shl i64 %sub, %sh_prom24
286bdd1243dSDimitry Andric ///   br label %if.end26
287bdd1243dSDimitry Andric ///
288bdd1243dSDimitry Andric /// if.end26:                                         ; preds = %sw.epilog, %if.else
289bdd1243dSDimitry Andric ///   %a.addr.1 = phi i64 [ %shl25, %if.else ], [ %spec.select, %sw.epilog ]
290bdd1243dSDimitry Andric ///   %e.0 = phi i32 [ %sub2, %if.else ], [ %spec.select56, %sw.epilog ]
291bdd1243dSDimitry Andric ///   %conv27 = trunc i64 %shr to i32
292bdd1243dSDimitry Andric ///   %and28 = and i32 %conv27, -2147483648
293bdd1243dSDimitry Andric ///   %add = shl nuw nsw i32 %e.0, 23
294bdd1243dSDimitry Andric ///   %shl29 = add nuw nsw i32 %add, 1065353216
295bdd1243dSDimitry Andric ///   %conv31 = trunc i64 %a.addr.1 to i32
296bdd1243dSDimitry Andric ///   %and32 = and i32 %conv31, 8388607
297bdd1243dSDimitry Andric ///   %or30 = or i32 %and32, %and28
298bdd1243dSDimitry Andric ///   %or33 = or i32 %or30, %shl29
299bdd1243dSDimitry Andric ///   %4 = bitcast i32 %or33 to float
300bdd1243dSDimitry Andric ///   br label %return
301bdd1243dSDimitry Andric ///
302bdd1243dSDimitry Andric /// return:                                           ; preds = %entry, %if.end26
303bdd1243dSDimitry Andric ///   %retval.0 = phi float [ %4, %if.end26 ], [ 0.000000e+00, %entry ]
304bdd1243dSDimitry Andric ///   ret float %retval.0
305bdd1243dSDimitry Andric /// }
306bdd1243dSDimitry Andric ///
307bdd1243dSDimitry Andric /// Replace integer to fp with generated code.
expandIToFP(Instruction * IToFP)308bdd1243dSDimitry Andric static void expandIToFP(Instruction *IToFP) {
309bdd1243dSDimitry Andric   IRBuilder<> Builder(IToFP);
310bdd1243dSDimitry Andric   auto *IntVal = IToFP->getOperand(0);
311bdd1243dSDimitry Andric   IntegerType *IntTy = cast<IntegerType>(IntVal->getType());
312bdd1243dSDimitry Andric 
313bdd1243dSDimitry Andric   unsigned BitWidth = IntVal->getType()->getIntegerBitWidth();
314bdd1243dSDimitry Andric   unsigned FPMantissaWidth = IToFP->getType()->getFPMantissaWidth() - 1;
315bdd1243dSDimitry Andric   // fp80 conversion is implemented by conversion tp fp128 first following
316bdd1243dSDimitry Andric   // a fptrunc to fp80.
317bdd1243dSDimitry Andric   FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth;
318bdd1243dSDimitry Andric   // FIXME: As there is no related builtins added in compliler-rt,
319bdd1243dSDimitry Andric   // here currently utilized the fp32 <-> fp16 lib calls to implement.
320bdd1243dSDimitry Andric   FPMantissaWidth = FPMantissaWidth == 10 ? 23 : FPMantissaWidth;
321bdd1243dSDimitry Andric   unsigned FloatWidth = PowerOf2Ceil(FPMantissaWidth);
322bdd1243dSDimitry Andric   bool IsSigned = IToFP->getOpcode() == Instruction::SIToFP;
323bdd1243dSDimitry Andric 
324bdd1243dSDimitry Andric   assert(BitWidth > FloatWidth && "Unexpected conversion. expandIToFP() "
325bdd1243dSDimitry Andric                                   "assumes integer width is larger than fp.");
326bdd1243dSDimitry Andric 
327bdd1243dSDimitry Andric   Value *Temp1 =
328bdd1243dSDimitry Andric       Builder.CreateShl(Builder.getIntN(BitWidth, 1),
329bdd1243dSDimitry Andric                         Builder.getIntN(BitWidth, FPMantissaWidth + 3));
330bdd1243dSDimitry Andric 
331bdd1243dSDimitry Andric   BasicBlock *Entry = Builder.GetInsertBlock();
332bdd1243dSDimitry Andric   Function *F = Entry->getParent();
333bdd1243dSDimitry Andric   Entry->setName(Twine(Entry->getName(), "itofp-entry"));
334bdd1243dSDimitry Andric   BasicBlock *End =
335bdd1243dSDimitry Andric       Entry->splitBasicBlock(Builder.GetInsertPoint(), "itofp-return");
336bdd1243dSDimitry Andric   BasicBlock *IfEnd =
337bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "itofp-if-end", F, End);
338bdd1243dSDimitry Andric   BasicBlock *IfThen4 =
339bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "itofp-if-then4", F, End);
340bdd1243dSDimitry Andric   BasicBlock *SwBB =
341bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "itofp-sw-bb", F, End);
342bdd1243dSDimitry Andric   BasicBlock *SwDefault =
343bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "itofp-sw-default", F, End);
344bdd1243dSDimitry Andric   BasicBlock *SwEpilog =
345bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "itofp-sw-epilog", F, End);
346bdd1243dSDimitry Andric   BasicBlock *IfThen20 =
347bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "itofp-if-then20", F, End);
348bdd1243dSDimitry Andric   BasicBlock *IfElse =
349bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "itofp-if-else", F, End);
350bdd1243dSDimitry Andric   BasicBlock *IfEnd26 =
351bdd1243dSDimitry Andric       BasicBlock::Create(Builder.getContext(), "itofp-if-end26", F, End);
352bdd1243dSDimitry Andric 
353bdd1243dSDimitry Andric   Entry->getTerminator()->eraseFromParent();
354bdd1243dSDimitry Andric 
355bdd1243dSDimitry Andric   Function *CTLZ =
356bdd1243dSDimitry Andric       Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz, IntTy);
357bdd1243dSDimitry Andric   ConstantInt *True = Builder.getTrue();
358bdd1243dSDimitry Andric 
359bdd1243dSDimitry Andric   // entry:
360bdd1243dSDimitry Andric   Builder.SetInsertPoint(Entry);
361bdd1243dSDimitry Andric   Value *Cmp = Builder.CreateICmpEQ(IntVal, ConstantInt::getSigned(IntTy, 0));
362bdd1243dSDimitry Andric   Builder.CreateCondBr(Cmp, End, IfEnd);
363bdd1243dSDimitry Andric 
364bdd1243dSDimitry Andric   // if.end:
365bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfEnd);
366bdd1243dSDimitry Andric   Value *Shr =
367bdd1243dSDimitry Andric       Builder.CreateAShr(IntVal, Builder.getIntN(BitWidth, BitWidth - 1));
368bdd1243dSDimitry Andric   Value *Xor = Builder.CreateXor(Shr, IntVal);
369bdd1243dSDimitry Andric   Value *Sub = Builder.CreateSub(Xor, Shr);
370bdd1243dSDimitry Andric   Value *Call = Builder.CreateCall(CTLZ, {IsSigned ? Sub : IntVal, True});
371bdd1243dSDimitry Andric   Value *Cast = Builder.CreateTrunc(Call, Builder.getInt32Ty());
372bdd1243dSDimitry Andric   int BitWidthNew = FloatWidth == 128 ? BitWidth : 32;
373bdd1243dSDimitry Andric   Value *Sub1 = Builder.CreateSub(Builder.getIntN(BitWidthNew, BitWidth),
374bdd1243dSDimitry Andric                                   FloatWidth == 128 ? Call : Cast);
375bdd1243dSDimitry Andric   Value *Sub2 = Builder.CreateSub(Builder.getIntN(BitWidthNew, BitWidth - 1),
376bdd1243dSDimitry Andric                                   FloatWidth == 128 ? Call : Cast);
377bdd1243dSDimitry Andric   Value *Cmp3 = Builder.CreateICmpSGT(
378bdd1243dSDimitry Andric       Sub2, Builder.getIntN(BitWidthNew, FPMantissaWidth + 1));
379bdd1243dSDimitry Andric   Builder.CreateCondBr(Cmp3, IfThen4, IfElse);
380bdd1243dSDimitry Andric 
381bdd1243dSDimitry Andric   // if.then4:
382bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfThen4);
383bdd1243dSDimitry Andric   llvm::SwitchInst *SI = Builder.CreateSwitch(Sub1, SwDefault);
384bdd1243dSDimitry Andric   SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 2), SwBB);
385bdd1243dSDimitry Andric   SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 3), SwEpilog);
386bdd1243dSDimitry Andric 
387bdd1243dSDimitry Andric   // sw.bb:
388bdd1243dSDimitry Andric   Builder.SetInsertPoint(SwBB);
389bdd1243dSDimitry Andric   Value *Shl =
390bdd1243dSDimitry Andric       Builder.CreateShl(IsSigned ? Sub : IntVal, Builder.getIntN(BitWidth, 1));
391bdd1243dSDimitry Andric   Builder.CreateBr(SwEpilog);
392bdd1243dSDimitry Andric 
393bdd1243dSDimitry Andric   // sw.default:
394bdd1243dSDimitry Andric   Builder.SetInsertPoint(SwDefault);
395bdd1243dSDimitry Andric   Value *Sub5 = Builder.CreateSub(
396bdd1243dSDimitry Andric       Builder.getIntN(BitWidthNew, BitWidth - FPMantissaWidth - 3),
397bdd1243dSDimitry Andric       FloatWidth == 128 ? Call : Cast);
398bdd1243dSDimitry Andric   Value *ShProm = Builder.CreateZExt(Sub5, IntTy);
399bdd1243dSDimitry Andric   Value *Shr6 = Builder.CreateLShr(IsSigned ? Sub : IntVal,
400bdd1243dSDimitry Andric                                    FloatWidth == 128 ? Sub5 : ShProm);
401bdd1243dSDimitry Andric   Value *Sub8 =
402bdd1243dSDimitry Andric       Builder.CreateAdd(FloatWidth == 128 ? Call : Cast,
403bdd1243dSDimitry Andric                         Builder.getIntN(BitWidthNew, FPMantissaWidth + 3));
404bdd1243dSDimitry Andric   Value *ShProm9 = Builder.CreateZExt(Sub8, IntTy);
405bdd1243dSDimitry Andric   Value *Shr9 = Builder.CreateLShr(ConstantInt::getSigned(IntTy, -1),
406bdd1243dSDimitry Andric                                    FloatWidth == 128 ? Sub8 : ShProm9);
407bdd1243dSDimitry Andric   Value *And = Builder.CreateAnd(Shr9, IsSigned ? Sub : IntVal);
408bdd1243dSDimitry Andric   Value *Cmp10 = Builder.CreateICmpNE(And, Builder.getIntN(BitWidth, 0));
409bdd1243dSDimitry Andric   Value *Conv11 = Builder.CreateZExt(Cmp10, IntTy);
410bdd1243dSDimitry Andric   Value *Or = Builder.CreateOr(Shr6, Conv11);
411bdd1243dSDimitry Andric   Builder.CreateBr(SwEpilog);
412bdd1243dSDimitry Andric 
413bdd1243dSDimitry Andric   // sw.epilog:
414bdd1243dSDimitry Andric   Builder.SetInsertPoint(SwEpilog);
415bdd1243dSDimitry Andric   PHINode *AAddr0 = Builder.CreatePHI(IntTy, 3);
416bdd1243dSDimitry Andric   AAddr0->addIncoming(Or, SwDefault);
417bdd1243dSDimitry Andric   AAddr0->addIncoming(IsSigned ? Sub : IntVal, IfThen4);
418bdd1243dSDimitry Andric   AAddr0->addIncoming(Shl, SwBB);
419bdd1243dSDimitry Andric   Value *A0 = Builder.CreateTrunc(AAddr0, Builder.getInt32Ty());
420bdd1243dSDimitry Andric   Value *A1 = Builder.CreateLShr(A0, Builder.getIntN(32, 2));
421bdd1243dSDimitry Andric   Value *A2 = Builder.CreateAnd(A1, Builder.getIntN(32, 1));
422bdd1243dSDimitry Andric   Value *Conv16 = Builder.CreateZExt(A2, IntTy);
423bdd1243dSDimitry Andric   Value *Or17 = Builder.CreateOr(AAddr0, Conv16);
424bdd1243dSDimitry Andric   Value *Inc = Builder.CreateAdd(Or17, Builder.getIntN(BitWidth, 1));
425bdd1243dSDimitry Andric   Value *Shr18 = nullptr;
426bdd1243dSDimitry Andric   if (IsSigned)
427bdd1243dSDimitry Andric     Shr18 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 2));
428bdd1243dSDimitry Andric   else
429bdd1243dSDimitry Andric     Shr18 = Builder.CreateLShr(Inc, Builder.getIntN(BitWidth, 2));
430bdd1243dSDimitry Andric   Value *A3 = Builder.CreateAnd(Inc, Temp1, "a3");
431bdd1243dSDimitry Andric   Value *PosOrNeg = Builder.CreateICmpEQ(A3, Builder.getIntN(BitWidth, 0));
432bdd1243dSDimitry Andric   Value *ExtractT60 = Builder.CreateTrunc(Shr18, Builder.getIntNTy(FloatWidth));
433bdd1243dSDimitry Andric   Value *Extract63 = Builder.CreateLShr(Shr18, Builder.getIntN(BitWidth, 32));
434bdd1243dSDimitry Andric   Value *ExtractT64 = nullptr;
435bdd1243dSDimitry Andric   if (FloatWidth > 80)
436bdd1243dSDimitry Andric     ExtractT64 = Builder.CreateTrunc(Sub2, Builder.getInt64Ty());
437bdd1243dSDimitry Andric   else
438bdd1243dSDimitry Andric     ExtractT64 = Builder.CreateTrunc(Extract63, Builder.getInt32Ty());
439bdd1243dSDimitry Andric   Builder.CreateCondBr(PosOrNeg, IfEnd26, IfThen20);
440bdd1243dSDimitry Andric 
441bdd1243dSDimitry Andric   // if.then20
442bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfThen20);
443bdd1243dSDimitry Andric   Value *Shr21 = nullptr;
444bdd1243dSDimitry Andric   if (IsSigned)
445bdd1243dSDimitry Andric     Shr21 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 3));
446bdd1243dSDimitry Andric   else
447bdd1243dSDimitry Andric     Shr21 = Builder.CreateLShr(Inc, Builder.getIntN(BitWidth, 3));
448bdd1243dSDimitry Andric   Value *ExtractT = Builder.CreateTrunc(Shr21, Builder.getIntNTy(FloatWidth));
449bdd1243dSDimitry Andric   Value *Extract = Builder.CreateLShr(Shr21, Builder.getIntN(BitWidth, 32));
450bdd1243dSDimitry Andric   Value *ExtractT62 = nullptr;
451bdd1243dSDimitry Andric   if (FloatWidth > 80)
452bdd1243dSDimitry Andric     ExtractT62 = Builder.CreateTrunc(Sub1, Builder.getIntNTy(64));
453bdd1243dSDimitry Andric   else
454bdd1243dSDimitry Andric     ExtractT62 = Builder.CreateTrunc(Extract, Builder.getIntNTy(32));
455bdd1243dSDimitry Andric   Builder.CreateBr(IfEnd26);
456bdd1243dSDimitry Andric 
457bdd1243dSDimitry Andric   // if.else:
458bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfElse);
459bdd1243dSDimitry Andric   Value *Sub24 = Builder.CreateAdd(
460bdd1243dSDimitry Andric       FloatWidth == 128 ? Call : Cast,
461bdd1243dSDimitry Andric       ConstantInt::getSigned(Builder.getIntNTy(BitWidthNew),
462bdd1243dSDimitry Andric                              -(BitWidth - FPMantissaWidth - 1)));
463bdd1243dSDimitry Andric   Value *ShProm25 = Builder.CreateZExt(Sub24, IntTy);
464bdd1243dSDimitry Andric   Value *Shl26 = Builder.CreateShl(IsSigned ? Sub : IntVal,
465bdd1243dSDimitry Andric                                    FloatWidth == 128 ? Sub24 : ShProm25);
466bdd1243dSDimitry Andric   Value *ExtractT61 = Builder.CreateTrunc(Shl26, Builder.getIntNTy(FloatWidth));
467bdd1243dSDimitry Andric   Value *Extract65 = Builder.CreateLShr(Shl26, Builder.getIntN(BitWidth, 32));
468bdd1243dSDimitry Andric   Value *ExtractT66 = nullptr;
469bdd1243dSDimitry Andric   if (FloatWidth > 80)
470bdd1243dSDimitry Andric     ExtractT66 = Builder.CreateTrunc(Sub2, Builder.getIntNTy(64));
471bdd1243dSDimitry Andric   else
472bdd1243dSDimitry Andric     ExtractT66 = Builder.CreateTrunc(Extract65, Builder.getInt32Ty());
473bdd1243dSDimitry Andric   Builder.CreateBr(IfEnd26);
474bdd1243dSDimitry Andric 
475bdd1243dSDimitry Andric   // if.end26:
476bdd1243dSDimitry Andric   Builder.SetInsertPoint(IfEnd26);
477bdd1243dSDimitry Andric   PHINode *AAddr1Off0 = Builder.CreatePHI(Builder.getIntNTy(FloatWidth), 3);
478bdd1243dSDimitry Andric   AAddr1Off0->addIncoming(ExtractT, IfThen20);
479bdd1243dSDimitry Andric   AAddr1Off0->addIncoming(ExtractT60, SwEpilog);
480bdd1243dSDimitry Andric   AAddr1Off0->addIncoming(ExtractT61, IfElse);
481bdd1243dSDimitry Andric   PHINode *AAddr1Off32 = nullptr;
482bdd1243dSDimitry Andric   if (FloatWidth > 32) {
483bdd1243dSDimitry Andric     AAddr1Off32 =
484bdd1243dSDimitry Andric         Builder.CreatePHI(Builder.getIntNTy(FloatWidth > 80 ? 64 : 32), 3);
485bdd1243dSDimitry Andric     AAddr1Off32->addIncoming(ExtractT62, IfThen20);
486bdd1243dSDimitry Andric     AAddr1Off32->addIncoming(ExtractT64, SwEpilog);
487bdd1243dSDimitry Andric     AAddr1Off32->addIncoming(ExtractT66, IfElse);
488bdd1243dSDimitry Andric   }
489bdd1243dSDimitry Andric   PHINode *E0 = nullptr;
490bdd1243dSDimitry Andric   if (FloatWidth <= 80) {
491bdd1243dSDimitry Andric     E0 = Builder.CreatePHI(Builder.getIntNTy(BitWidthNew), 3);
492bdd1243dSDimitry Andric     E0->addIncoming(Sub1, IfThen20);
493bdd1243dSDimitry Andric     E0->addIncoming(Sub2, SwEpilog);
494bdd1243dSDimitry Andric     E0->addIncoming(Sub2, IfElse);
495bdd1243dSDimitry Andric   }
496bdd1243dSDimitry Andric   Value *And29 = nullptr;
497bdd1243dSDimitry Andric   if (FloatWidth > 80) {
498bdd1243dSDimitry Andric     Value *Temp2 = Builder.CreateShl(Builder.getIntN(BitWidth, 1),
499bdd1243dSDimitry Andric                                      Builder.getIntN(BitWidth, 63));
500bdd1243dSDimitry Andric     And29 = Builder.CreateAnd(Shr, Temp2, "and29");
501bdd1243dSDimitry Andric   } else {
502bdd1243dSDimitry Andric     Value *Conv28 = Builder.CreateTrunc(Shr, Builder.getIntNTy(32));
503bdd1243dSDimitry Andric     And29 = Builder.CreateAnd(
504bdd1243dSDimitry Andric         Conv28, ConstantInt::getSigned(Builder.getIntNTy(32), 0x80000000));
505bdd1243dSDimitry Andric   }
506bdd1243dSDimitry Andric   unsigned TempMod = FPMantissaWidth % 32;
507bdd1243dSDimitry Andric   Value *And34 = nullptr;
508bdd1243dSDimitry Andric   Value *Shl30 = nullptr;
509bdd1243dSDimitry Andric   if (FloatWidth > 80) {
510bdd1243dSDimitry Andric     TempMod += 32;
511bdd1243dSDimitry Andric     Value *Add = Builder.CreateShl(AAddr1Off32, Builder.getIntN(64, TempMod));
512bdd1243dSDimitry Andric     Shl30 = Builder.CreateAdd(
513bdd1243dSDimitry Andric         Add,
514bdd1243dSDimitry Andric         Builder.getIntN(64, ((1ull << (62ull - TempMod)) - 1ull) << TempMod));
515bdd1243dSDimitry Andric     And34 = Builder.CreateZExt(Shl30, Builder.getIntNTy(128));
516bdd1243dSDimitry Andric   } else {
517bdd1243dSDimitry Andric     Value *Add = Builder.CreateShl(E0, Builder.getIntN(32, TempMod));
518bdd1243dSDimitry Andric     Shl30 = Builder.CreateAdd(
519bdd1243dSDimitry Andric         Add, Builder.getIntN(32, ((1 << (30 - TempMod)) - 1) << TempMod));
520bdd1243dSDimitry Andric     And34 = Builder.CreateAnd(FloatWidth > 32 ? AAddr1Off32 : AAddr1Off0,
521bdd1243dSDimitry Andric                               Builder.getIntN(32, (1 << TempMod) - 1));
522bdd1243dSDimitry Andric   }
523bdd1243dSDimitry Andric   Value *Or35 = nullptr;
524bdd1243dSDimitry Andric   if (FloatWidth > 80) {
525bdd1243dSDimitry Andric     Value *And29Trunc = Builder.CreateTrunc(And29, Builder.getIntNTy(128));
526bdd1243dSDimitry Andric     Value *Or31 = Builder.CreateOr(And29Trunc, And34);
527bdd1243dSDimitry Andric     Value *Or34 = Builder.CreateShl(Or31, Builder.getIntN(128, 64));
528bdd1243dSDimitry Andric     Value *Temp3 = Builder.CreateShl(Builder.getIntN(128, 1),
529bdd1243dSDimitry Andric                                      Builder.getIntN(128, FPMantissaWidth));
530bdd1243dSDimitry Andric     Value *Temp4 = Builder.CreateSub(Temp3, Builder.getIntN(128, 1));
531bdd1243dSDimitry Andric     Value *A6 = Builder.CreateAnd(AAddr1Off0, Temp4);
532bdd1243dSDimitry Andric     Or35 = Builder.CreateOr(Or34, A6);
533bdd1243dSDimitry Andric   } else {
534bdd1243dSDimitry Andric     Value *Or31 = Builder.CreateOr(And34, And29);
535bdd1243dSDimitry Andric     Or35 = Builder.CreateOr(IsSigned ? Or31 : And34, Shl30);
536bdd1243dSDimitry Andric   }
537bdd1243dSDimitry Andric   Value *A4 = nullptr;
538bdd1243dSDimitry Andric   if (IToFP->getType()->isDoubleTy()) {
539bdd1243dSDimitry Andric     Value *ZExt1 = Builder.CreateZExt(Or35, Builder.getIntNTy(FloatWidth));
540bdd1243dSDimitry Andric     Value *Shl1 = Builder.CreateShl(ZExt1, Builder.getIntN(FloatWidth, 32));
541bdd1243dSDimitry Andric     Value *And1 =
542bdd1243dSDimitry Andric         Builder.CreateAnd(AAddr1Off0, Builder.getIntN(FloatWidth, 0xFFFFFFFF));
543bdd1243dSDimitry Andric     Value *Or1 = Builder.CreateOr(Shl1, And1);
544bdd1243dSDimitry Andric     A4 = Builder.CreateBitCast(Or1, IToFP->getType());
545bdd1243dSDimitry Andric   } else if (IToFP->getType()->isX86_FP80Ty()) {
546bdd1243dSDimitry Andric     Value *A40 =
547bdd1243dSDimitry Andric         Builder.CreateBitCast(Or35, Type::getFP128Ty(Builder.getContext()));
548bdd1243dSDimitry Andric     A4 = Builder.CreateFPTrunc(A40, IToFP->getType());
549bdd1243dSDimitry Andric   } else if (IToFP->getType()->isHalfTy()) {
550bdd1243dSDimitry Andric     // Deal with "half" situation. This is a workaround since we don't have
551bdd1243dSDimitry Andric     // floattihf.c currently as referring.
552bdd1243dSDimitry Andric     Value *A40 =
553bdd1243dSDimitry Andric         Builder.CreateBitCast(Or35, Type::getFloatTy(Builder.getContext()));
554bdd1243dSDimitry Andric     A4 = Builder.CreateFPTrunc(A40, IToFP->getType());
555bdd1243dSDimitry Andric   } else // float type
556bdd1243dSDimitry Andric     A4 = Builder.CreateBitCast(Or35, IToFP->getType());
557bdd1243dSDimitry Andric   Builder.CreateBr(End);
558bdd1243dSDimitry Andric 
559bdd1243dSDimitry Andric   // return:
560bdd1243dSDimitry Andric   Builder.SetInsertPoint(End, End->begin());
561bdd1243dSDimitry Andric   PHINode *Retval0 = Builder.CreatePHI(IToFP->getType(), 2);
562bdd1243dSDimitry Andric   Retval0->addIncoming(A4, IfEnd26);
563bdd1243dSDimitry Andric   Retval0->addIncoming(ConstantFP::getZero(IToFP->getType(), false), Entry);
564bdd1243dSDimitry Andric 
565bdd1243dSDimitry Andric   IToFP->replaceAllUsesWith(Retval0);
566bdd1243dSDimitry Andric   IToFP->dropAllReferences();
567bdd1243dSDimitry Andric   IToFP->eraseFromParent();
568bdd1243dSDimitry Andric }
569bdd1243dSDimitry Andric 
runImpl(Function & F,const TargetLowering & TLI)570bdd1243dSDimitry Andric static bool runImpl(Function &F, const TargetLowering &TLI) {
571bdd1243dSDimitry Andric   SmallVector<Instruction *, 4> Replace;
572bdd1243dSDimitry Andric   bool Modified = false;
573bdd1243dSDimitry Andric 
574bdd1243dSDimitry Andric   unsigned MaxLegalFpConvertBitWidth =
575bdd1243dSDimitry Andric       TLI.getMaxLargeFPConvertBitWidthSupported();
576bdd1243dSDimitry Andric   if (ExpandFpConvertBits != llvm::IntegerType::MAX_INT_BITS)
577bdd1243dSDimitry Andric     MaxLegalFpConvertBitWidth = ExpandFpConvertBits;
578bdd1243dSDimitry Andric 
579bdd1243dSDimitry Andric   if (MaxLegalFpConvertBitWidth >= llvm::IntegerType::MAX_INT_BITS)
580bdd1243dSDimitry Andric     return false;
581bdd1243dSDimitry Andric 
582bdd1243dSDimitry Andric   for (auto &I : instructions(F)) {
583bdd1243dSDimitry Andric     switch (I.getOpcode()) {
584bdd1243dSDimitry Andric     case Instruction::FPToUI:
585bdd1243dSDimitry Andric     case Instruction::FPToSI: {
586bdd1243dSDimitry Andric       // TODO: This pass doesn't handle vectors.
587bdd1243dSDimitry Andric       if (I.getOperand(0)->getType()->isVectorTy())
588bdd1243dSDimitry Andric         continue;
589bdd1243dSDimitry Andric 
590bdd1243dSDimitry Andric       auto *IntTy = dyn_cast<IntegerType>(I.getType());
591bdd1243dSDimitry Andric       if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth)
592bdd1243dSDimitry Andric         continue;
593bdd1243dSDimitry Andric 
594bdd1243dSDimitry Andric       Replace.push_back(&I);
595bdd1243dSDimitry Andric       Modified = true;
596bdd1243dSDimitry Andric       break;
597bdd1243dSDimitry Andric     }
598bdd1243dSDimitry Andric     case Instruction::UIToFP:
599bdd1243dSDimitry Andric     case Instruction::SIToFP: {
600bdd1243dSDimitry Andric       // TODO: This pass doesn't handle vectors.
601bdd1243dSDimitry Andric       if (I.getOperand(0)->getType()->isVectorTy())
602bdd1243dSDimitry Andric         continue;
603bdd1243dSDimitry Andric 
604bdd1243dSDimitry Andric       auto *IntTy = dyn_cast<IntegerType>(I.getOperand(0)->getType());
605bdd1243dSDimitry Andric       if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth)
606bdd1243dSDimitry Andric         continue;
607bdd1243dSDimitry Andric 
608bdd1243dSDimitry Andric       Replace.push_back(&I);
609bdd1243dSDimitry Andric       Modified = true;
610bdd1243dSDimitry Andric       break;
611bdd1243dSDimitry Andric     }
612bdd1243dSDimitry Andric     default:
613bdd1243dSDimitry Andric       break;
614bdd1243dSDimitry Andric     }
615bdd1243dSDimitry Andric   }
616bdd1243dSDimitry Andric 
617bdd1243dSDimitry Andric   if (Replace.empty())
618bdd1243dSDimitry Andric     return false;
619bdd1243dSDimitry Andric 
620bdd1243dSDimitry Andric   while (!Replace.empty()) {
621bdd1243dSDimitry Andric     Instruction *I = Replace.pop_back_val();
622bdd1243dSDimitry Andric     if (I->getOpcode() == Instruction::FPToUI ||
623bdd1243dSDimitry Andric         I->getOpcode() == Instruction::FPToSI) {
624bdd1243dSDimitry Andric       expandFPToI(I);
625bdd1243dSDimitry Andric     } else {
626bdd1243dSDimitry Andric       expandIToFP(I);
627bdd1243dSDimitry Andric     }
628bdd1243dSDimitry Andric   }
629bdd1243dSDimitry Andric 
630bdd1243dSDimitry Andric   return Modified;
631bdd1243dSDimitry Andric }
632bdd1243dSDimitry Andric 
633bdd1243dSDimitry Andric namespace {
634bdd1243dSDimitry Andric class ExpandLargeFpConvertLegacyPass : public FunctionPass {
635bdd1243dSDimitry Andric public:
636bdd1243dSDimitry Andric   static char ID;
637bdd1243dSDimitry Andric 
ExpandLargeFpConvertLegacyPass()638bdd1243dSDimitry Andric   ExpandLargeFpConvertLegacyPass() : FunctionPass(ID) {
639bdd1243dSDimitry Andric     initializeExpandLargeFpConvertLegacyPassPass(
640bdd1243dSDimitry Andric         *PassRegistry::getPassRegistry());
641bdd1243dSDimitry Andric   }
642bdd1243dSDimitry Andric 
runOnFunction(Function & F)643bdd1243dSDimitry Andric   bool runOnFunction(Function &F) override {
644bdd1243dSDimitry Andric     auto *TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
645bdd1243dSDimitry Andric     auto *TLI = TM->getSubtargetImpl(F)->getTargetLowering();
646bdd1243dSDimitry Andric     return runImpl(F, *TLI);
647bdd1243dSDimitry Andric   }
648bdd1243dSDimitry Andric 
getAnalysisUsage(AnalysisUsage & AU) const649bdd1243dSDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override {
650bdd1243dSDimitry Andric     AU.addRequired<TargetPassConfig>();
651bdd1243dSDimitry Andric     AU.addPreserved<AAResultsWrapperPass>();
652bdd1243dSDimitry Andric     AU.addPreserved<GlobalsAAWrapperPass>();
653bdd1243dSDimitry Andric   }
654bdd1243dSDimitry Andric };
655bdd1243dSDimitry Andric } // namespace
656bdd1243dSDimitry Andric 
run(Function & F,FunctionAnalysisManager & FAM)657*5f757f3fSDimitry Andric PreservedAnalyses ExpandLargeFpConvertPass::run(Function &F,
658*5f757f3fSDimitry Andric                                                 FunctionAnalysisManager &FAM) {
659*5f757f3fSDimitry Andric   const TargetSubtargetInfo *STI = TM->getSubtargetImpl(F);
660*5f757f3fSDimitry Andric   return runImpl(F, *STI->getTargetLowering()) ? PreservedAnalyses::none()
661*5f757f3fSDimitry Andric                                                : PreservedAnalyses::all();
662*5f757f3fSDimitry Andric }
663*5f757f3fSDimitry Andric 
664bdd1243dSDimitry Andric char ExpandLargeFpConvertLegacyPass::ID = 0;
665bdd1243dSDimitry Andric INITIALIZE_PASS_BEGIN(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert",
666bdd1243dSDimitry Andric                       "Expand large fp convert", false, false)
667bdd1243dSDimitry Andric INITIALIZE_PASS_END(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert",
668bdd1243dSDimitry Andric                     "Expand large fp convert", false, false)
669bdd1243dSDimitry Andric 
createExpandLargeFpConvertPass()670bdd1243dSDimitry Andric FunctionPass *llvm::createExpandLargeFpConvertPass() {
671bdd1243dSDimitry Andric   return new ExpandLargeFpConvertLegacyPass();
672bdd1243dSDimitry Andric }
673