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