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