LLVM 17.0.0git
ExpandLargeFpConvert.cpp
Go to the documentation of this file.
1//===--- ExpandLargeFpConvert.cpp - Expand large fp convert----------------===//
2//
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
6//
7//===----------------------------------------------------------------------===//
8//
9
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.
14//
15//===----------------------------------------------------------------------===//
16
20#include "llvm/CodeGen/Passes.h"
24#include "llvm/IR/IRBuilder.h"
26#include "llvm/IR/PassManager.h"
28#include "llvm/Pass.h"
31
32using namespace llvm;
33
35 ExpandFpConvertBits("expand-fp-convert-bits", cl::Hidden,
37 cl::desc("fp convert instructions on integers with "
38 "more than <N> bits are expanded."));
39
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
42/// implementations.
43///
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 {
46/// entry:
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
57///
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
63///
64/// if.then8: ; preds = %if.end
65/// %cond11 = select i1 %tobool.not, i64 9223372036854775807, i64 -9223372036854775808
66/// br label %cleanup
67///
68/// if.end12: ; preds = %if.end
69/// %cmp13 = icmp ult i64 %shr, 150
70/// br i1 %cmp13, label %if.then15, label %if.else
71///
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
76/// br label %cleanup
77///
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
82/// br label %cleanup
83///
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 ]
86/// ret i64 %retval.0
87/// }
88///
89/// Replace fp to integer with generated code.
90static void expandFPToI(Instruction *FPToI) {
91 IRBuilder<> Builder(FPToI);
92 auto *FloatVal = FPToI->getOperand(0);
93 IntegerType *IntTy = cast<IntegerType>(FPToI->getType());
94
95 unsigned BitWidth = FPToI->getType()->getIntegerBitWidth();
96 unsigned FPMantissaWidth = FloatVal->getType()->getFPMantissaWidth() - 1;
97
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.
100 Value *A1 = nullptr;
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);
105 } else { // FPToSI
106 Value *A0 = Builder.CreateFPToSI(FloatVal, Builder.getIntNTy(32));
107 A1 = Builder.CreateSExt(A0, IntTy);
108 }
109 FPToI->replaceAllUsesWith(A1);
110 FPToI->dropAllReferences();
111 FPToI->eraseFromParent();
112 return;
113 }
114
115 // fp80 conversion is implemented by fpext to fp128 first then do the
116 // conversion.
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);
127 Value *NegInf =
128 Builder.CreateShl(ConstantInt::getSigned(IntTy, 1),
129 ConstantInt::getSigned(IntTy, BitWidth - 1));
130
131 BasicBlock *Entry = Builder.GetInsertBlock();
132 Function *F = Entry->getParent();
133 Entry->setName(Twine(Entry->getName(), "fp-to-i-entry"));
134 BasicBlock *End =
135 Entry->splitBasicBlock(Builder.GetInsertPoint(), "fp-to-i-cleanup");
136 BasicBlock *IfEnd =
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);
140 BasicBlock *IfEnd9 =
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);
144 BasicBlock *IfElse =
145 BasicBlock::Create(Builder.getContext(), "fp-to-i-if-else", F, End);
146
147 Entry->getTerminator()->eraseFromParent();
148
149 // entry:
150 Builder.SetInsertPoint(Entry);
151 Value *FloatVal0 = FloatVal;
152 // fp80 conversion is implemented by fpext to fp128 first then do the
153 // conversion.
154 if (FloatVal->getType()->isX86_FP80Ty())
155 FloatVal0 =
156 Builder.CreateFPExt(FloatVal, Type::getFP128Ty(Builder.getContext()));
157 Value *ARep0 =
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));
164 Value *And =
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);
170 Value *Cmp =
171 Builder.CreateICmpULT(And2, Builder.getIntN(BitWidth, ExponentBias));
172 Builder.CreateCondBr(Cmp, End, IfEnd);
173
174 // if.end:
175 Builder.SetInsertPoint(IfEnd);
176 Value *Add1 = Builder.CreateAdd(
177 And2, ConstantInt::getSigned(IntTy, -int64_t(ExponentBias + BitWidth)));
178 Value *Cmp3 =
179 Builder.CreateICmpULT(Add1, ConstantInt::getSigned(IntTy, -BitWidth));
180 Builder.CreateCondBr(Cmp3, IfThen5, IfEnd9);
181
182 // if.then5:
183 Builder.SetInsertPoint(IfThen5);
184 Value *PosInf = Builder.CreateXor(NegOne, NegInf);
185 Value *Cond8 = Builder.CreateSelect(PosOrNeg, PosInf, NegInf);
186 Builder.CreateBr(End);
187
188 // if.end9:
189 Builder.SetInsertPoint(IfEnd9);
190 Value *Cmp10 = Builder.CreateICmpULT(
191 And2, Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth));
192 Builder.CreateCondBr(Cmp10, IfThen12, IfElse);
193
194 // if.then12:
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);
201
202 // if.else:
203 Builder.SetInsertPoint(IfElse);
204 Value *Sub15 = Builder.CreateAdd(
205 And2,
206 ConstantInt::getSigned(IntTy, -(ExponentBias + FPMantissaWidth)));
207 Value *Shl = Builder.CreateShl(Or, Sub15);
208 Value *Mul16 = Builder.CreateMul(Shl, Sign);
209 Builder.CreateBr(End);
210
211 // cleanup:
212 Builder.SetInsertPoint(End, End->begin());
213 PHINode *Retval0 = Builder.CreatePHI(FPToI->getType(), 4);
214
215 Retval0->addIncoming(Cond8, IfThen5);
216 Retval0->addIncoming(Mul, IfThen12);
217 Retval0->addIncoming(Mul16, IfElse);
218 Retval0->addIncoming(Builder.getIntN(BitWidth, 0), Entry);
219
220 FPToI->replaceAllUsesWith(Retval0);
221 FPToI->dropAllReferences();
222 FPToI->eraseFromParent();
223}
224
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.
229///
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 {
232/// entry:
233/// %cmp = icmp eq i64 %a, 0
234/// br i1 %cmp, label %return, label %if.end
235///
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
246///
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
251/// ]
252///
253/// sw.bb: ; preds = %if.then4
254/// %shl = shl i64 %sub, 1
255/// br label %sw.epilog
256///
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
267///
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
280///
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
286///
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
299/// br label %return
300///
301/// return: ; preds = %entry, %if.end26
302/// %retval.0 = phi float [ %4, %if.end26 ], [ 0.000000e+00, %entry ]
303/// ret float %retval.0
304/// }
305///
306/// Replace integer to fp with generated code.
307static void expandIToFP(Instruction *IToFP) {
308 IRBuilder<> Builder(IToFP);
309 auto *IntVal = IToFP->getOperand(0);
310 IntegerType *IntTy = cast<IntegerType>(IntVal->getType());
311
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;
322
323 assert(BitWidth > FloatWidth && "Unexpected conversion. expandIToFP() "
324 "assumes integer width is larger than fp.");
325
326 Value *Temp1 =
327 Builder.CreateShl(Builder.getIntN(BitWidth, 1),
328 Builder.getIntN(BitWidth, FPMantissaWidth + 3));
329
330 BasicBlock *Entry = Builder.GetInsertBlock();
331 Function *F = Entry->getParent();
332 Entry->setName(Twine(Entry->getName(), "itofp-entry"));
333 BasicBlock *End =
334 Entry->splitBasicBlock(Builder.GetInsertPoint(), "itofp-return");
335 BasicBlock *IfEnd =
336 BasicBlock::Create(Builder.getContext(), "itofp-if-end", F, End);
337 BasicBlock *IfThen4 =
338 BasicBlock::Create(Builder.getContext(), "itofp-if-then4", F, End);
339 BasicBlock *SwBB =
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);
347 BasicBlock *IfElse =
348 BasicBlock::Create(Builder.getContext(), "itofp-if-else", F, End);
349 BasicBlock *IfEnd26 =
350 BasicBlock::Create(Builder.getContext(), "itofp-if-end26", F, End);
351
352 Entry->getTerminator()->eraseFromParent();
353
354 Function *CTLZ =
355 Intrinsic::getDeclaration(F->getParent(), Intrinsic::ctlz, IntTy);
356 ConstantInt *True = Builder.getTrue();
357
358 // entry:
359 Builder.SetInsertPoint(Entry);
360 Value *Cmp = Builder.CreateICmpEQ(IntVal, ConstantInt::getSigned(IntTy, 0));
361 Builder.CreateCondBr(Cmp, End, IfEnd);
362
363 // if.end:
364 Builder.SetInsertPoint(IfEnd);
365 Value *Shr =
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);
379
380 // if.then4:
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);
385
386 // sw.bb:
387 Builder.SetInsertPoint(SwBB);
388 Value *Shl =
389 Builder.CreateShl(IsSigned ? Sub : IntVal, Builder.getIntN(BitWidth, 1));
390 Builder.CreateBr(SwEpilog);
391
392 // sw.default:
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);
400 Value *Sub8 =
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);
411
412 // sw.epilog:
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;
425 if (IsSigned)
426 Shr18 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 2));
427 else
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;
434 if (FloatWidth > 80)
435 ExtractT64 = Builder.CreateTrunc(Sub2, Builder.getInt64Ty());
436 else
437 ExtractT64 = Builder.CreateTrunc(Extract63, Builder.getInt32Ty());
438 Builder.CreateCondBr(PosOrNeg, IfEnd26, IfThen20);
439
440 // if.then20
441 Builder.SetInsertPoint(IfThen20);
442 Value *Shr21 = nullptr;
443 if (IsSigned)
444 Shr21 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 3));
445 else
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;
450 if (FloatWidth > 80)
451 ExtractT62 = Builder.CreateTrunc(Sub1, Builder.getIntNTy(64));
452 else
453 ExtractT62 = Builder.CreateTrunc(Extract, Builder.getIntNTy(32));
454 Builder.CreateBr(IfEnd26);
455
456 // if.else:
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;
468 if (FloatWidth > 80)
469 ExtractT66 = Builder.CreateTrunc(Sub2, Builder.getIntNTy(64));
470 else
471 ExtractT66 = Builder.CreateTrunc(Extract65, Builder.getInt32Ty());
472 Builder.CreateBr(IfEnd26);
473
474 // if.end26:
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) {
482 AAddr1Off32 =
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);
487 }
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);
494 }
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");
500 } else {
501 Value *Conv28 = Builder.CreateTrunc(Shr, Builder.getIntNTy(32));
502 And29 = Builder.CreateAnd(
503 Conv28, ConstantInt::getSigned(Builder.getIntNTy(32), 0x80000000));
504 }
505 unsigned TempMod = FPMantissaWidth % 32;
506 Value *And34 = nullptr;
507 Value *Shl30 = nullptr;
508 if (FloatWidth > 80) {
509 TempMod += 32;
510 Value *Add = Builder.CreateShl(AAddr1Off32, Builder.getIntN(64, TempMod));
511 Shl30 = Builder.CreateAdd(
512 Add,
513 Builder.getIntN(64, ((1ull << (62ull - TempMod)) - 1ull) << TempMod));
514 And34 = Builder.CreateZExt(Shl30, Builder.getIntNTy(128));
515 } else {
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));
521 }
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);
532 } else {
533 Value *Or31 = Builder.CreateOr(And34, And29);
534 Or35 = Builder.CreateOr(IsSigned ? Or31 : And34, Shl30);
535 }
536 Value *A4 = nullptr;
537 if (IToFP->getType()->isDoubleTy()) {
538 Value *ZExt1 = Builder.CreateZExt(Or35, Builder.getIntNTy(FloatWidth));
539 Value *Shl1 = Builder.CreateShl(ZExt1, Builder.getIntN(FloatWidth, 32));
540 Value *And1 =
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()) {
545 Value *A40 =
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.
551 Value *A40 =
552 Builder.CreateBitCast(Or35, Type::getFloatTy(Builder.getContext()));
553 A4 = Builder.CreateFPTrunc(A40, IToFP->getType());
554 } else // float type
555 A4 = Builder.CreateBitCast(Or35, IToFP->getType());
556 Builder.CreateBr(End);
557
558 // return:
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);
563
564 IToFP->replaceAllUsesWith(Retval0);
565 IToFP->dropAllReferences();
566 IToFP->eraseFromParent();
567}
568
569static bool runImpl(Function &F, const TargetLowering &TLI) {
571 bool Modified = false;
572
573 unsigned MaxLegalFpConvertBitWidth =
576 MaxLegalFpConvertBitWidth = ExpandFpConvertBits;
577
578 if (MaxLegalFpConvertBitWidth >= llvm::IntegerType::MAX_INT_BITS)
579 return false;
580
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())
587 continue;
588
589 auto *IntTy = dyn_cast<IntegerType>(I.getType());
590 if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth)
591 continue;
592
593 Replace.push_back(&I);
594 Modified = true;
595 break;
596 }
597 case Instruction::UIToFP:
598 case Instruction::SIToFP: {
599 // TODO: This pass doesn't handle vectors.
600 if (I.getOperand(0)->getType()->isVectorTy())
601 continue;
602
603 auto *IntTy = dyn_cast<IntegerType>(I.getOperand(0)->getType());
604 if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth)
605 continue;
606
607 Replace.push_back(&I);
608 Modified = true;
609 break;
610 }
611 default:
612 break;
613 }
614 }
615
616 if (Replace.empty())
617 return false;
618
619 while (!Replace.empty()) {
620 Instruction *I = Replace.pop_back_val();
621 if (I->getOpcode() == Instruction::FPToUI ||
622 I->getOpcode() == Instruction::FPToSI) {
623 expandFPToI(I);
624 } else {
625 expandIToFP(I);
626 }
627 }
628
629 return Modified;
630}
631
632namespace {
633class ExpandLargeFpConvertLegacyPass : public FunctionPass {
634public:
635 static char ID;
636
637 ExpandLargeFpConvertLegacyPass() : FunctionPass(ID) {
640 }
641
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);
646 }
647
648 void getAnalysisUsage(AnalysisUsage &AU) const override {
652 }
653};
654} // namespace
655
656char ExpandLargeFpConvertLegacyPass::ID = 0;
657INITIALIZE_PASS_BEGIN(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert",
658 "Expand large fp convert", false, false)
659INITIALIZE_PASS_END(ExpandLargeFpConvertLegacyPass, "expand-large-fp-convert",
660 "Expand large fp convert", false, false)
661
663 return new ExpandLargeFpConvertLegacyPass();
664}
assume Assume Builder
static bool runImpl(Function &F, const TargetLowering &TLI)
static void expandIToFP(Instruction *IToFP)
Generate code to convert a fp number to integer, replacing S(U)IToFP with the generated code.
static void expandFPToI(Instruction *FPToI)
Generate code to convert a fp number to integer, replacing FPToS(U)I with the generated code.
expand large fp convert
static cl::opt< unsigned > ExpandFpConvertBits("expand-fp-convert-bits", cl::Hidden, cl::init(llvm::IntegerType::MAX_INT_BITS), cl::desc("fp convert instructions on integers with " "more than <N> bits are expanded."))
static bool runImpl(Function &F, const TargetLowering &TLI)
static Expected< BitVector > expand(StringRef S, StringRef Original)
Definition: GlobPattern.cpp:26
This is the interface for a simple mod/ref and alias analysis over globals.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
print must be executed print the must be executed context for all instructions
const char LLVMTargetMachineRef TM
This header defines various interfaces for pass management in LLVM.
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:59
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:52
@ SI
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
This file describes how to lower LLVM code to machine code.
Target-Independent Code Generator Pass Configuration Options pass.
BinaryOperator * Mul
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
Represent the analysis usage information of a pass.
AnalysisUsage & addRequired()
AnalysisUsage & addPreserved()
Add the specified Pass class to the set of analyses preserved by this pass.
LLVM Basic Block Representation.
Definition: BasicBlock.h:56
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:105
static Constant * getZero(Type *Ty, bool Negative=false)
Definition: Constants.cpp:1008
This is the shared class of boolean and integer constants.
Definition: Constants.h:78
static ConstantInt * getSigned(IntegerType *Ty, int64_t V)
Return a ConstantInt with the specified value for the specified type.
Definition: Constants.cpp:901
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:308
virtual bool runOnFunction(Function &F)=0
runOnFunction - Virtual method overriden by subclasses to do the per-function processing of the pass.
Legacy wrapper pass to provide the GlobalsAAResult object.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2550
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
Definition: Instruction.h:168
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
Definition: Instruction.cpp:82
Class to represent integer types.
Definition: DerivedTypes.h:40
@ MAX_INT_BITS
Maximum number of bits that can be specified.
Definition: DerivedTypes.h:52
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
Definition: Pass.cpp:98
bool empty() const
Definition: SmallVector.h:94
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
Multiway switch.
unsigned getMaxLargeFPConvertBitWidthSupported() const
Returns the size in bits of the maximum larget fp convert the backend supports.
This class defines information used to lower LLVM code to legal SelectionDAG operators that the targe...
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:78
Target-Independent Code Generator Pass Configuration Options.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
unsigned getIntegerBitWidth() const
bool isX86_FP80Ty() const
Return true if this is x86 long double.
Definition: Type.h:160
static Type * getFP128Ty(LLVMContext &C)
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
Definition: Type.h:143
int getFPMantissaWidth() const
Return the width of the mantissa of this type.
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition: Type.h:157
static Type * getFloatTy(LLVMContext &C)
void dropAllReferences()
Drop all references to operands.
Definition: User.h:299
Value * getOperand(unsigned i) const
Definition: User.h:169
LLVM Value Representation.
Definition: Value.h:74
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:255
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:532
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
Function * getDeclaration(Module *M, ID id, ArrayRef< Type * > Tys=std::nullopt)
Create or insert an LLVM Function declaration for an intrinsic, and return it.
Definition: Function.cpp:1502
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:445
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
Definition: MathExtras.h:455
FunctionPass * createExpandLargeFpConvertPass()
void initializeExpandLargeFpConvertLegacyPassPass(PassRegistry &)
@ Or
Bitwise or logical OR of integers.
@ Xor
Bitwise or logical XOR of integers.
@ And
Bitwise or logical AND of integers.
@ Add
Sum of integers.
constexpr unsigned BitWidth
Definition: BitmaskEnum.h:147