LLVM 22.0.0git
ExpandFp.cpp
Go to the documentation of this file.
1//===--- ExpandFp.cpp - Expand fp instructions ----------------------------===//
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// This pass expands certain floating point instructions at the IR level.
9//
10// It expands ‘fptoui .. to’, ‘fptosi .. to’, ‘uitofp .. to’, ‘sitofp
11// .. to’ instructions with a bitwidth above a threshold. This is
12// useful for targets like x86_64 that cannot lower fp convertions
13// 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// clang-format off: preserve formatting of the following example
41
42/// Generate code to convert a fp number to integer, replacing FPToS(U)I with
43/// the generated code. This currently generates code similarly to compiler-rt's
44/// implementations.
45///
46/// An example IR generated from compiler-rt/fixsfdi.c looks like below:
47/// define dso_local i64 @foo(float noundef %a) local_unnamed_addr #0 {
48/// entry:
49/// %0 = bitcast float %a to i32
50/// %conv.i = zext i32 %0 to i64
51/// %tobool.not = icmp sgt i32 %0, -1
52/// %conv = select i1 %tobool.not, i64 1, i64 -1
53/// %and = lshr i64 %conv.i, 23
54/// %shr = and i64 %and, 255
55/// %and2 = and i64 %conv.i, 8388607
56/// %or = or i64 %and2, 8388608
57/// %cmp = icmp ult i64 %shr, 127
58/// br i1 %cmp, label %cleanup, label %if.end
59///
60/// if.end: ; preds = %entry
61/// %sub = add nuw nsw i64 %shr, 4294967169
62/// %conv5 = and i64 %sub, 4294967232
63/// %cmp6.not = icmp eq i64 %conv5, 0
64/// br i1 %cmp6.not, label %if.end12, label %if.then8
65///
66/// if.then8: ; preds = %if.end
67/// %cond11 = select i1 %tobool.not, i64 9223372036854775807, i64 -9223372036854775808
68/// br label %cleanup
69///
70/// if.end12: ; preds = %if.end
71/// %cmp13 = icmp ult i64 %shr, 150
72/// br i1 %cmp13, label %if.then15, label %if.else
73///
74/// if.then15: ; preds = %if.end12
75/// %sub16 = sub nuw nsw i64 150, %shr
76/// %shr17 = lshr i64 %or, %sub16
77/// %mul = mul nsw i64 %shr17, %conv
78/// br label %cleanup
79///
80/// if.else: ; preds = %if.end12
81/// %sub18 = add nsw i64 %shr, -150
82/// %shl = shl i64 %or, %sub18
83/// %mul19 = mul nsw i64 %shl, %conv
84/// br label %cleanup
85///
86/// cleanup: ; preds = %entry, %if.else, %if.then15, %if.then8
87/// %retval.0 = phi i64 [ %cond11, %if.then8 ], [ %mul, %if.then15 ], [ %mul19, %if.else ], [ 0, %entry ]
88/// ret i64 %retval.0
89/// }
90///
91/// Replace fp to integer with generated code.
92static void expandFPToI(Instruction *FPToI) {
93 // clang-format on
94 IRBuilder<> Builder(FPToI);
95 auto *FloatVal = FPToI->getOperand(0);
96 IntegerType *IntTy = cast<IntegerType>(FPToI->getType());
97
98 unsigned BitWidth = FPToI->getType()->getIntegerBitWidth();
99 unsigned FPMantissaWidth = FloatVal->getType()->getFPMantissaWidth() - 1;
100
101 // FIXME: fp16's range is covered by i32. So `fptoi half` can convert
102 // to i32 first following a sext/zext to target integer type.
103 Value *A1 = nullptr;
104 if (FloatVal->getType()->isHalfTy()) {
105 if (FPToI->getOpcode() == Instruction::FPToUI) {
106 Value *A0 = Builder.CreateFPToUI(FloatVal, Builder.getInt32Ty());
107 A1 = Builder.CreateZExt(A0, IntTy);
108 } else { // FPToSI
109 Value *A0 = Builder.CreateFPToSI(FloatVal, Builder.getInt32Ty());
110 A1 = Builder.CreateSExt(A0, IntTy);
111 }
112 FPToI->replaceAllUsesWith(A1);
113 FPToI->dropAllReferences();
114 FPToI->eraseFromParent();
115 return;
116 }
117
118 // fp80 conversion is implemented by fpext to fp128 first then do the
119 // conversion.
120 FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth;
121 unsigned FloatWidth =
122 PowerOf2Ceil(FloatVal->getType()->getScalarSizeInBits());
123 unsigned ExponentWidth = FloatWidth - FPMantissaWidth - 1;
124 unsigned ExponentBias = (1 << (ExponentWidth - 1)) - 1;
125 Value *ImplicitBit = Builder.CreateShl(
126 Builder.getIntN(BitWidth, 1), Builder.getIntN(BitWidth, FPMantissaWidth));
127 Value *SignificandMask =
128 Builder.CreateSub(ImplicitBit, Builder.getIntN(BitWidth, 1));
129 Value *NegOne = Builder.CreateSExt(
130 ConstantInt::getSigned(Builder.getInt32Ty(), -1), IntTy);
131 Value *NegInf =
132 Builder.CreateShl(ConstantInt::getSigned(IntTy, 1),
133 ConstantInt::getSigned(IntTy, BitWidth - 1));
134
135 BasicBlock *Entry = Builder.GetInsertBlock();
136 Function *F = Entry->getParent();
137 Entry->setName(Twine(Entry->getName(), "fp-to-i-entry"));
138 BasicBlock *End =
139 Entry->splitBasicBlock(Builder.GetInsertPoint(), "fp-to-i-cleanup");
140 BasicBlock *IfEnd =
141 BasicBlock::Create(Builder.getContext(), "fp-to-i-if-end", F, End);
142 BasicBlock *IfThen5 =
143 BasicBlock::Create(Builder.getContext(), "fp-to-i-if-then5", F, End);
144 BasicBlock *IfEnd9 =
145 BasicBlock::Create(Builder.getContext(), "fp-to-i-if-end9", F, End);
146 BasicBlock *IfThen12 =
147 BasicBlock::Create(Builder.getContext(), "fp-to-i-if-then12", F, End);
148 BasicBlock *IfElse =
149 BasicBlock::Create(Builder.getContext(), "fp-to-i-if-else", F, End);
150
151 Entry->getTerminator()->eraseFromParent();
152
153 // entry:
154 Builder.SetInsertPoint(Entry);
155 Value *FloatVal0 = FloatVal;
156 // fp80 conversion is implemented by fpext to fp128 first then do the
157 // conversion.
158 if (FloatVal->getType()->isX86_FP80Ty())
159 FloatVal0 =
160 Builder.CreateFPExt(FloatVal, Type::getFP128Ty(Builder.getContext()));
161 Value *ARep0 =
162 Builder.CreateBitCast(FloatVal0, Builder.getIntNTy(FloatWidth));
163 Value *ARep = Builder.CreateZExt(ARep0, FPToI->getType());
164 Value *PosOrNeg = Builder.CreateICmpSGT(
165 ARep0, ConstantInt::getSigned(Builder.getIntNTy(FloatWidth), -1));
166 Value *Sign = Builder.CreateSelect(PosOrNeg, ConstantInt::getSigned(IntTy, 1),
167 ConstantInt::getSigned(IntTy, -1));
168 Value *And =
169 Builder.CreateLShr(ARep, Builder.getIntN(BitWidth, FPMantissaWidth));
170 Value *And2 = Builder.CreateAnd(
171 And, Builder.getIntN(BitWidth, (1 << ExponentWidth) - 1));
172 Value *Abs = Builder.CreateAnd(ARep, SignificandMask);
173 Value *Or = Builder.CreateOr(Abs, ImplicitBit);
174 Value *Cmp =
175 Builder.CreateICmpULT(And2, Builder.getIntN(BitWidth, ExponentBias));
176 Builder.CreateCondBr(Cmp, End, IfEnd);
177
178 // if.end:
179 Builder.SetInsertPoint(IfEnd);
180 Value *Add1 = Builder.CreateAdd(
182 IntTy, -static_cast<int64_t>(ExponentBias + BitWidth)));
183 Value *Cmp3 = Builder.CreateICmpULT(
184 Add1, ConstantInt::getSigned(IntTy, -static_cast<int64_t>(BitWidth)));
185 Builder.CreateCondBr(Cmp3, IfThen5, IfEnd9);
186
187 // if.then5:
188 Builder.SetInsertPoint(IfThen5);
189 Value *PosInf = Builder.CreateXor(NegOne, NegInf);
190 Value *Cond8 = Builder.CreateSelect(PosOrNeg, PosInf, NegInf);
191 Builder.CreateBr(End);
192
193 // if.end9:
194 Builder.SetInsertPoint(IfEnd9);
195 Value *Cmp10 = Builder.CreateICmpULT(
196 And2, Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth));
197 Builder.CreateCondBr(Cmp10, IfThen12, IfElse);
198
199 // if.then12:
200 Builder.SetInsertPoint(IfThen12);
201 Value *Sub13 = Builder.CreateSub(
202 Builder.getIntN(BitWidth, ExponentBias + FPMantissaWidth), And2);
203 Value *Shr14 = Builder.CreateLShr(Or, Sub13);
204 Value *Mul = Builder.CreateMul(Shr14, Sign);
205 Builder.CreateBr(End);
206
207 // if.else:
208 Builder.SetInsertPoint(IfElse);
209 Value *Sub15 = Builder.CreateAdd(
211 IntTy, -static_cast<int64_t>(ExponentBias + FPMantissaWidth)));
212 Value *Shl = Builder.CreateShl(Or, Sub15);
213 Value *Mul16 = Builder.CreateMul(Shl, Sign);
214 Builder.CreateBr(End);
215
216 // cleanup:
217 Builder.SetInsertPoint(End, End->begin());
218 PHINode *Retval0 = Builder.CreatePHI(FPToI->getType(), 4);
219
220 Retval0->addIncoming(Cond8, IfThen5);
221 Retval0->addIncoming(Mul, IfThen12);
222 Retval0->addIncoming(Mul16, IfElse);
223 Retval0->addIncoming(Builder.getIntN(BitWidth, 0), Entry);
224
225 FPToI->replaceAllUsesWith(Retval0);
226 FPToI->dropAllReferences();
227 FPToI->eraseFromParent();
228}
229
230// clang-format off: preserve formatting of the following example
231
232/// Generate code to convert a fp number to integer, replacing S(U)IToFP with
233/// the generated code. This currently generates code similarly to compiler-rt's
234/// implementations. This implementation has an implicit assumption that integer
235/// width is larger than fp.
236///
237/// An example IR generated from compiler-rt/floatdisf.c looks like below:
238/// define dso_local float @__floatdisf(i64 noundef %a) local_unnamed_addr #0 {
239/// entry:
240/// %cmp = icmp eq i64 %a, 0
241/// br i1 %cmp, label %return, label %if.end
242///
243/// if.end: ; preds = %entry
244/// %shr = ashr i64 %a, 63
245/// %xor = xor i64 %shr, %a
246/// %sub = sub nsw i64 %xor, %shr
247/// %0 = tail call i64 @llvm.ctlz.i64(i64 %sub, i1 true), !range !5
248/// %cast = trunc i64 %0 to i32
249/// %sub1 = sub nuw nsw i32 64, %cast
250/// %sub2 = xor i32 %cast, 63
251/// %cmp3 = icmp ult i32 %cast, 40
252/// br i1 %cmp3, label %if.then4, label %if.else
253///
254/// if.then4: ; preds = %if.end
255/// switch i32 %sub1, label %sw.default [
256/// i32 25, label %sw.bb
257/// i32 26, label %sw.epilog
258/// ]
259///
260/// sw.bb: ; preds = %if.then4
261/// %shl = shl i64 %sub, 1
262/// br label %sw.epilog
263///
264/// sw.default: ; preds = %if.then4
265/// %sub5 = sub nsw i64 38, %0
266/// %sh_prom = and i64 %sub5, 4294967295
267/// %shr6 = lshr i64 %sub, %sh_prom
268/// %shr9 = lshr i64 274877906943, %0
269/// %and = and i64 %shr9, %sub
270/// %cmp10 = icmp ne i64 %and, 0
271/// %conv11 = zext i1 %cmp10 to i64
272/// %or = or i64 %shr6, %conv11
273/// br label %sw.epilog
274///
275/// sw.epilog: ; preds = %sw.default, %if.then4, %sw.bb
276/// %a.addr.0 = phi i64 [ %or, %sw.default ], [ %sub, %if.then4 ], [ %shl, %sw.bb ]
277/// %1 = lshr i64 %a.addr.0, 2
278/// %2 = and i64 %1, 1
279/// %or16 = or i64 %2, %a.addr.0
280/// %inc = add nsw i64 %or16, 1
281/// %3 = and i64 %inc, 67108864
282/// %tobool.not = icmp eq i64 %3, 0
283/// %spec.select.v = select i1 %tobool.not, i64 2, i64 3
284/// %spec.select = ashr i64 %inc, %spec.select.v
285/// %spec.select56 = select i1 %tobool.not, i32 %sub2, i32 %sub1
286/// br label %if.end26
287///
288/// if.else: ; preds = %if.end
289/// %sub23 = add nuw nsw i64 %0, 4294967256
290/// %sh_prom24 = and i64 %sub23, 4294967295
291/// %shl25 = shl i64 %sub, %sh_prom24
292/// br label %if.end26
293///
294/// if.end26: ; preds = %sw.epilog, %if.else
295/// %a.addr.1 = phi i64 [ %shl25, %if.else ], [ %spec.select, %sw.epilog ]
296/// %e.0 = phi i32 [ %sub2, %if.else ], [ %spec.select56, %sw.epilog ]
297/// %conv27 = trunc i64 %shr to i32
298/// %and28 = and i32 %conv27, -2147483648
299/// %add = shl nuw nsw i32 %e.0, 23
300/// %shl29 = add nuw nsw i32 %add, 1065353216
301/// %conv31 = trunc i64 %a.addr.1 to i32
302/// %and32 = and i32 %conv31, 8388607
303/// %or30 = or i32 %and32, %and28
304/// %or33 = or i32 %or30, %shl29
305/// %4 = bitcast i32 %or33 to float
306/// br label %return
307///
308/// return: ; preds = %entry, %if.end26
309/// %retval.0 = phi float [ %4, %if.end26 ], [ 0.000000e+00, %entry ]
310/// ret float %retval.0
311/// }
312///
313/// Replace integer to fp with generated code.
314static void expandIToFP(Instruction *IToFP) {
315 // clang-format on
316 IRBuilder<> Builder(IToFP);
317 auto *IntVal = IToFP->getOperand(0);
318 IntegerType *IntTy = cast<IntegerType>(IntVal->getType());
319
320 unsigned BitWidth = IntVal->getType()->getIntegerBitWidth();
321 unsigned FPMantissaWidth = IToFP->getType()->getFPMantissaWidth() - 1;
322 // fp80 conversion is implemented by conversion tp fp128 first following
323 // a fptrunc to fp80.
324 FPMantissaWidth = FPMantissaWidth == 63 ? 112 : FPMantissaWidth;
325 // FIXME: As there is no related builtins added in compliler-rt,
326 // here currently utilized the fp32 <-> fp16 lib calls to implement.
327 FPMantissaWidth = FPMantissaWidth == 10 ? 23 : FPMantissaWidth;
328 FPMantissaWidth = FPMantissaWidth == 7 ? 23 : FPMantissaWidth;
329 unsigned FloatWidth = PowerOf2Ceil(FPMantissaWidth);
330 bool IsSigned = IToFP->getOpcode() == Instruction::SIToFP;
331
332 assert(BitWidth > FloatWidth && "Unexpected conversion. expandIToFP() "
333 "assumes integer width is larger than fp.");
334
335 Value *Temp1 =
336 Builder.CreateShl(Builder.getIntN(BitWidth, 1),
337 Builder.getIntN(BitWidth, FPMantissaWidth + 3));
338
339 BasicBlock *Entry = Builder.GetInsertBlock();
340 Function *F = Entry->getParent();
341 Entry->setName(Twine(Entry->getName(), "itofp-entry"));
342 BasicBlock *End =
343 Entry->splitBasicBlock(Builder.GetInsertPoint(), "itofp-return");
344 BasicBlock *IfEnd =
345 BasicBlock::Create(Builder.getContext(), "itofp-if-end", F, End);
346 BasicBlock *IfThen4 =
347 BasicBlock::Create(Builder.getContext(), "itofp-if-then4", F, End);
348 BasicBlock *SwBB =
349 BasicBlock::Create(Builder.getContext(), "itofp-sw-bb", F, End);
350 BasicBlock *SwDefault =
351 BasicBlock::Create(Builder.getContext(), "itofp-sw-default", F, End);
352 BasicBlock *SwEpilog =
353 BasicBlock::Create(Builder.getContext(), "itofp-sw-epilog", F, End);
354 BasicBlock *IfThen20 =
355 BasicBlock::Create(Builder.getContext(), "itofp-if-then20", F, End);
356 BasicBlock *IfElse =
357 BasicBlock::Create(Builder.getContext(), "itofp-if-else", F, End);
358 BasicBlock *IfEnd26 =
359 BasicBlock::Create(Builder.getContext(), "itofp-if-end26", F, End);
360
361 Entry->getTerminator()->eraseFromParent();
362
363 Function *CTLZ =
364 Intrinsic::getOrInsertDeclaration(F->getParent(), Intrinsic::ctlz, IntTy);
365 ConstantInt *True = Builder.getTrue();
366
367 // entry:
368 Builder.SetInsertPoint(Entry);
369 Value *Cmp = Builder.CreateICmpEQ(IntVal, ConstantInt::getSigned(IntTy, 0));
370 Builder.CreateCondBr(Cmp, End, IfEnd);
371
372 // if.end:
373 Builder.SetInsertPoint(IfEnd);
374 Value *Shr =
375 Builder.CreateAShr(IntVal, Builder.getIntN(BitWidth, BitWidth - 1));
376 Value *Xor = Builder.CreateXor(Shr, IntVal);
377 Value *Sub = Builder.CreateSub(Xor, Shr);
378 Value *Call = Builder.CreateCall(CTLZ, {IsSigned ? Sub : IntVal, True});
379 Value *Cast = Builder.CreateTrunc(Call, Builder.getInt32Ty());
380 int BitWidthNew = FloatWidth == 128 ? BitWidth : 32;
381 Value *Sub1 = Builder.CreateSub(Builder.getIntN(BitWidthNew, BitWidth),
382 FloatWidth == 128 ? Call : Cast);
383 Value *Sub2 = Builder.CreateSub(Builder.getIntN(BitWidthNew, BitWidth - 1),
384 FloatWidth == 128 ? Call : Cast);
385 Value *Cmp3 = Builder.CreateICmpSGT(
386 Sub1, Builder.getIntN(BitWidthNew, FPMantissaWidth + 1));
387 Builder.CreateCondBr(Cmp3, IfThen4, IfElse);
388
389 // if.then4:
390 Builder.SetInsertPoint(IfThen4);
391 llvm::SwitchInst *SI = Builder.CreateSwitch(Sub1, SwDefault);
392 SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 2), SwBB);
393 SI->addCase(Builder.getIntN(BitWidthNew, FPMantissaWidth + 3), SwEpilog);
394
395 // sw.bb:
396 Builder.SetInsertPoint(SwBB);
397 Value *Shl =
398 Builder.CreateShl(IsSigned ? Sub : IntVal, Builder.getIntN(BitWidth, 1));
399 Builder.CreateBr(SwEpilog);
400
401 // sw.default:
402 Builder.SetInsertPoint(SwDefault);
403 Value *Sub5 = Builder.CreateSub(
404 Builder.getIntN(BitWidthNew, BitWidth - FPMantissaWidth - 3),
405 FloatWidth == 128 ? Call : Cast);
406 Value *ShProm = Builder.CreateZExt(Sub5, IntTy);
407 Value *Shr6 = Builder.CreateLShr(IsSigned ? Sub : IntVal,
408 FloatWidth == 128 ? Sub5 : ShProm);
409 Value *Sub8 =
410 Builder.CreateAdd(FloatWidth == 128 ? Call : Cast,
411 Builder.getIntN(BitWidthNew, FPMantissaWidth + 3));
412 Value *ShProm9 = Builder.CreateZExt(Sub8, IntTy);
413 Value *Shr9 = Builder.CreateLShr(ConstantInt::getSigned(IntTy, -1),
414 FloatWidth == 128 ? Sub8 : ShProm9);
415 Value *And = Builder.CreateAnd(Shr9, IsSigned ? Sub : IntVal);
416 Value *Cmp10 = Builder.CreateICmpNE(And, Builder.getIntN(BitWidth, 0));
417 Value *Conv11 = Builder.CreateZExt(Cmp10, IntTy);
418 Value *Or = Builder.CreateOr(Shr6, Conv11);
419 Builder.CreateBr(SwEpilog);
420
421 // sw.epilog:
422 Builder.SetInsertPoint(SwEpilog);
423 PHINode *AAddr0 = Builder.CreatePHI(IntTy, 3);
424 AAddr0->addIncoming(Or, SwDefault);
425 AAddr0->addIncoming(IsSigned ? Sub : IntVal, IfThen4);
426 AAddr0->addIncoming(Shl, SwBB);
427 Value *A0 = Builder.CreateTrunc(AAddr0, Builder.getInt32Ty());
428 Value *A1 = Builder.CreateLShr(A0, Builder.getInt32(2));
429 Value *A2 = Builder.CreateAnd(A1, Builder.getInt32(1));
430 Value *Conv16 = Builder.CreateZExt(A2, IntTy);
431 Value *Or17 = Builder.CreateOr(AAddr0, Conv16);
432 Value *Inc = Builder.CreateAdd(Or17, Builder.getIntN(BitWidth, 1));
433 Value *Shr18 = nullptr;
434 if (IsSigned)
435 Shr18 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 2));
436 else
437 Shr18 = Builder.CreateLShr(Inc, Builder.getIntN(BitWidth, 2));
438 Value *A3 = Builder.CreateAnd(Inc, Temp1, "a3");
439 Value *PosOrNeg = Builder.CreateICmpEQ(A3, Builder.getIntN(BitWidth, 0));
440 Value *ExtractT60 = Builder.CreateTrunc(Shr18, Builder.getIntNTy(FloatWidth));
441 Value *Extract63 = Builder.CreateLShr(Shr18, Builder.getIntN(BitWidth, 32));
442 Value *ExtractT64 = nullptr;
443 if (FloatWidth > 80)
444 ExtractT64 = Builder.CreateTrunc(Sub2, Builder.getInt64Ty());
445 else
446 ExtractT64 = Builder.CreateTrunc(Extract63, Builder.getInt32Ty());
447 Builder.CreateCondBr(PosOrNeg, IfEnd26, IfThen20);
448
449 // if.then20
450 Builder.SetInsertPoint(IfThen20);
451 Value *Shr21 = nullptr;
452 if (IsSigned)
453 Shr21 = Builder.CreateAShr(Inc, Builder.getIntN(BitWidth, 3));
454 else
455 Shr21 = Builder.CreateLShr(Inc, Builder.getIntN(BitWidth, 3));
456 Value *ExtractT = Builder.CreateTrunc(Shr21, Builder.getIntNTy(FloatWidth));
457 Value *Extract = Builder.CreateLShr(Shr21, Builder.getIntN(BitWidth, 32));
458 Value *ExtractT62 = nullptr;
459 if (FloatWidth > 80)
460 ExtractT62 = Builder.CreateTrunc(Sub1, Builder.getInt64Ty());
461 else
462 ExtractT62 = Builder.CreateTrunc(Extract, Builder.getInt32Ty());
463 Builder.CreateBr(IfEnd26);
464
465 // if.else:
466 Builder.SetInsertPoint(IfElse);
467 Value *Sub24 = Builder.CreateAdd(
468 FloatWidth == 128 ? Call : Cast,
469 ConstantInt::getSigned(Builder.getIntNTy(BitWidthNew),
470 -(BitWidth - FPMantissaWidth - 1)));
471 Value *ShProm25 = Builder.CreateZExt(Sub24, IntTy);
472 Value *Shl26 = Builder.CreateShl(IsSigned ? Sub : IntVal,
473 FloatWidth == 128 ? Sub24 : ShProm25);
474 Value *ExtractT61 = Builder.CreateTrunc(Shl26, Builder.getIntNTy(FloatWidth));
475 Value *Extract65 = Builder.CreateLShr(Shl26, Builder.getIntN(BitWidth, 32));
476 Value *ExtractT66 = nullptr;
477 if (FloatWidth > 80)
478 ExtractT66 = Builder.CreateTrunc(Sub2, Builder.getInt64Ty());
479 else
480 ExtractT66 = Builder.CreateTrunc(Extract65, Builder.getInt32Ty());
481 Builder.CreateBr(IfEnd26);
482
483 // if.end26:
484 Builder.SetInsertPoint(IfEnd26);
485 PHINode *AAddr1Off0 = Builder.CreatePHI(Builder.getIntNTy(FloatWidth), 3);
486 AAddr1Off0->addIncoming(ExtractT, IfThen20);
487 AAddr1Off0->addIncoming(ExtractT60, SwEpilog);
488 AAddr1Off0->addIncoming(ExtractT61, IfElse);
489 PHINode *AAddr1Off32 = nullptr;
490 if (FloatWidth > 32) {
491 AAddr1Off32 =
492 Builder.CreatePHI(Builder.getIntNTy(FloatWidth > 80 ? 64 : 32), 3);
493 AAddr1Off32->addIncoming(ExtractT62, IfThen20);
494 AAddr1Off32->addIncoming(ExtractT64, SwEpilog);
495 AAddr1Off32->addIncoming(ExtractT66, IfElse);
496 }
497 PHINode *E0 = nullptr;
498 if (FloatWidth <= 80) {
499 E0 = Builder.CreatePHI(Builder.getIntNTy(BitWidthNew), 3);
500 E0->addIncoming(Sub1, IfThen20);
501 E0->addIncoming(Sub2, SwEpilog);
502 E0->addIncoming(Sub2, IfElse);
503 }
504 Value *And29 = nullptr;
505 if (FloatWidth > 80) {
506 Value *Temp2 = Builder.CreateShl(Builder.getIntN(BitWidth, 1),
507 Builder.getIntN(BitWidth, 63));
508 And29 = Builder.CreateAnd(Shr, Temp2, "and29");
509 } else {
510 Value *Conv28 = Builder.CreateTrunc(Shr, Builder.getInt32Ty());
511 And29 = Builder.CreateAnd(
512 Conv28, ConstantInt::getSigned(Builder.getInt32Ty(), 0x80000000));
513 }
514 unsigned TempMod = FPMantissaWidth % 32;
515 Value *And34 = nullptr;
516 Value *Shl30 = nullptr;
517 if (FloatWidth > 80) {
518 TempMod += 32;
519 Value *Add = Builder.CreateShl(AAddr1Off32, Builder.getInt64(TempMod));
520 Shl30 = Builder.CreateAdd(
521 Add, Builder.getInt64(((1ull << (62ull - TempMod)) - 1ull) << TempMod));
522 And34 = Builder.CreateZExt(Shl30, Builder.getInt128Ty());
523 } else {
524 Value *Add = Builder.CreateShl(E0, Builder.getInt32(TempMod));
525 Shl30 = Builder.CreateAdd(
526 Add, Builder.getInt32(((1 << (30 - TempMod)) - 1) << TempMod));
527 And34 = Builder.CreateAnd(FloatWidth > 32 ? AAddr1Off32 : AAddr1Off0,
528 Builder.getInt32((1 << TempMod) - 1));
529 }
530 Value *Or35 = nullptr;
531 if (FloatWidth > 80) {
532 Value *And29Trunc = Builder.CreateTrunc(And29, Builder.getInt128Ty());
533 Value *Or31 = Builder.CreateOr(And29Trunc, And34);
534 Value *Or34 = Builder.CreateShl(Or31, Builder.getIntN(128, 64));
535 Value *Temp3 = Builder.CreateShl(Builder.getIntN(128, 1),
536 Builder.getIntN(128, FPMantissaWidth));
537 Value *Temp4 = Builder.CreateSub(Temp3, Builder.getIntN(128, 1));
538 Value *A6 = Builder.CreateAnd(AAddr1Off0, Temp4);
539 Or35 = Builder.CreateOr(Or34, A6);
540 } else {
541 Value *Or31 = Builder.CreateOr(And34, And29);
542 Or35 = Builder.CreateOr(IsSigned ? Or31 : And34, Shl30);
543 }
544 Value *A4 = nullptr;
545 if (IToFP->getType()->isDoubleTy()) {
546 Value *ZExt1 = Builder.CreateZExt(Or35, Builder.getIntNTy(FloatWidth));
547 Value *Shl1 = Builder.CreateShl(ZExt1, Builder.getIntN(FloatWidth, 32));
548 Value *And1 =
549 Builder.CreateAnd(AAddr1Off0, Builder.getIntN(FloatWidth, 0xFFFFFFFF));
550 Value *Or1 = Builder.CreateOr(Shl1, And1);
551 A4 = Builder.CreateBitCast(Or1, IToFP->getType());
552 } else if (IToFP->getType()->isX86_FP80Ty()) {
553 Value *A40 =
554 Builder.CreateBitCast(Or35, Type::getFP128Ty(Builder.getContext()));
555 A4 = Builder.CreateFPTrunc(A40, IToFP->getType());
556 } else if (IToFP->getType()->isHalfTy() || IToFP->getType()->isBFloatTy()) {
557 // Deal with "half" situation. This is a workaround since we don't have
558 // floattihf.c currently as referring.
559 Value *A40 =
560 Builder.CreateBitCast(Or35, Type::getFloatTy(Builder.getContext()));
561 A4 = Builder.CreateFPTrunc(A40, IToFP->getType());
562 } else // float type
563 A4 = Builder.CreateBitCast(Or35, IToFP->getType());
564 Builder.CreateBr(End);
565
566 // return:
567 Builder.SetInsertPoint(End, End->begin());
568 PHINode *Retval0 = Builder.CreatePHI(IToFP->getType(), 2);
569 Retval0->addIncoming(A4, IfEnd26);
570 Retval0->addIncoming(ConstantFP::getZero(IToFP->getType(), false), Entry);
571
572 IToFP->replaceAllUsesWith(Retval0);
573 IToFP->dropAllReferences();
574 IToFP->eraseFromParent();
575}
576
578 VectorType *VTy = cast<FixedVectorType>(I->getType());
579
580 IRBuilder<> Builder(I);
581
582 unsigned NumElements = VTy->getElementCount().getFixedValue();
583 Value *Result = PoisonValue::get(VTy);
584 for (unsigned Idx = 0; Idx < NumElements; ++Idx) {
585 Value *Ext = Builder.CreateExtractElement(I->getOperand(0), Idx);
586 Value *Cast = Builder.CreateCast(cast<CastInst>(I)->getOpcode(), Ext,
587 I->getType()->getScalarType());
588 Result = Builder.CreateInsertElement(Result, Cast, Idx);
589 if (isa<Instruction>(Cast))
590 Replace.push_back(cast<Instruction>(Cast));
591 }
592 I->replaceAllUsesWith(Result);
593 I->dropAllReferences();
594 I->eraseFromParent();
595}
596
597static bool runImpl(Function &F, const TargetLowering &TLI) {
599 SmallVector<Instruction *, 4> ReplaceVector;
600 bool Modified = false;
601
602 unsigned MaxLegalFpConvertBitWidth =
605 MaxLegalFpConvertBitWidth = ExpandFpConvertBits;
606
607 if (MaxLegalFpConvertBitWidth >= llvm::IntegerType::MAX_INT_BITS)
608 return false;
609
610 for (auto &I : instructions(F)) {
611 switch (I.getOpcode()) {
612 case Instruction::FPToUI:
613 case Instruction::FPToSI: {
614 // TODO: This pass doesn't handle scalable vectors.
615 if (I.getOperand(0)->getType()->isScalableTy())
616 continue;
617
618 auto *IntTy = cast<IntegerType>(I.getType()->getScalarType());
619 if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth)
620 continue;
621
622 if (I.getOperand(0)->getType()->isVectorTy())
623 ReplaceVector.push_back(&I);
624 else
625 Replace.push_back(&I);
626 Modified = true;
627 break;
628 }
629 case Instruction::UIToFP:
630 case Instruction::SIToFP: {
631 // TODO: This pass doesn't handle scalable vectors.
632 if (I.getOperand(0)->getType()->isScalableTy())
633 continue;
634
635 auto *IntTy =
636 cast<IntegerType>(I.getOperand(0)->getType()->getScalarType());
637 if (IntTy->getIntegerBitWidth() <= MaxLegalFpConvertBitWidth)
638 continue;
639
640 if (I.getOperand(0)->getType()->isVectorTy())
641 ReplaceVector.push_back(&I);
642 else
643 Replace.push_back(&I);
644 Modified = true;
645 break;
646 }
647 default:
648 break;
649 }
650 }
651
652 while (!ReplaceVector.empty()) {
653 Instruction *I = ReplaceVector.pop_back_val();
654 scalarize(I, Replace);
655 }
656
657 if (Replace.empty())
658 return false;
659
660 while (!Replace.empty()) {
661 Instruction *I = Replace.pop_back_val();
662 if (I->getOpcode() == Instruction::FPToUI ||
663 I->getOpcode() == Instruction::FPToSI) {
664 expandFPToI(I);
665 } else {
666 expandIToFP(I);
667 }
668 }
669
670 return Modified;
671}
672
673namespace {
674class ExpandFpLegacyPass : public FunctionPass {
675public:
676 static char ID;
677
678 ExpandFpLegacyPass() : FunctionPass(ID) {
680 }
681
682 bool runOnFunction(Function &F) override {
683 auto *TM = &getAnalysis<TargetPassConfig>().getTM<TargetMachine>();
684 auto *TLI = TM->getSubtargetImpl(F)->getTargetLowering();
685 return runImpl(F, *TLI);
686 }
687
688 void getAnalysisUsage(AnalysisUsage &AU) const override {
692 }
693};
694} // namespace
695
697 const TargetSubtargetInfo *STI = TM->getSubtargetImpl(F);
700}
701
702char ExpandFpLegacyPass::ID = 0;
703INITIALIZE_PASS_BEGIN(ExpandFpLegacyPass, "expand-fp",
704 "Expand certain fp instructions", false, false)
705INITIALIZE_PASS_END(ExpandFpLegacyPass, "expand-fp", "Expand fp", false, false)
706
707FunctionPass *llvm::createExpandFpPass() { return new ExpandFpLegacyPass(); }
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Expand Atomic instructions
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
bool End
Definition: ELF_riscv.cpp:480
static void expandIToFP(Instruction *IToFP)
Generate code to convert a fp number to integer, replacing S(U)IToFP with the generated code.
Definition: ExpandFp.cpp:314
static void expandFPToI(Instruction *FPToI)
Generate code to convert a fp number to integer, replacing FPToS(U)I with the generated code.
Definition: ExpandFp.cpp:92
static void scalarize(Instruction *I, SmallVectorImpl< Instruction * > &Replace)
Definition: ExpandFp.cpp:577
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)
Definition: ExpandFp.cpp:597
static Expected< BitVector > expand(StringRef S, StringRef Original)
Definition: GlobPattern.cpp:21
This is the interface for a simple mod/ref and alias analysis over globals.
This header defines various interfaces for pass management in LLVM.
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
FunctionAnalysisManager FAM
#define INITIALIZE_PASS_END(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:44
#define INITIALIZE_PASS_BEGIN(passName, arg, name, cfg, analysis)
Definition: PassSupport.h:39
This file defines the SmallVector class.
This file describes how to lower LLVM code to machine code.
Target-Independent Code Generator Pass Configuration Options pass.
static std::optional< unsigned > getOpcode(ArrayRef< VPValue * > Values)
Returns the opcode of Values or ~0 if they do not all agree.
Definition: VPlanSLP.cpp:247
BinaryOperator * Mul
A wrapper pass to provide the legacy pass manager access to a suitably prepared AAResults object.
A container for analyses that lazily runs them and caches their results.
Definition: PassManager.h:255
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:62
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
Definition: BasicBlock.h:206
static LLVM_ABI Constant * getZero(Type *Ty, bool Negative=false)
Definition: Constants.cpp:1059
This is the shared class of boolean and integer constants.
Definition: Constants.h:87
static ConstantInt * getSigned(IntegerType *Ty, int64_t V)
Return a ConstantInt with the specified value for the specified type.
Definition: Constants.h:131
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
Definition: ExpandFp.cpp:696
FunctionPass class - This class is used to implement most global optimizations.
Definition: Pass.h:314
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.
Value * CreateICmpULT(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:2345
Value * CreateInsertElement(Type *VecTy, Value *NewElt, Value *Idx, const Twine &Name="")
Definition: IRBuilder.h:2571
Value * CreateExtractElement(Value *Vec, Value *Idx, const Twine &Name="")
Definition: IRBuilder.h:2559
IntegerType * getIntNTy(unsigned N)
Fetch the type representing an N-bit integer.
Definition: IRBuilder.h:575
Value * CreateICmpSGT(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:2353
Value * CreateFPTrunc(Value *V, Type *DestTy, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:2162
ConstantInt * getTrue()
Get the constant value for i1 true.
Definition: IRBuilder.h:502
LLVM_ABI Value * CreateSelect(Value *C, Value *True, Value *False, const Twine &Name="", Instruction *MDFrom=nullptr)
Definition: IRBuilder.cpp:1005
Value * CreateFPToUI(Value *V, Type *DestTy, const Twine &Name="")
Definition: IRBuilder.h:2128
BasicBlock::iterator GetInsertPoint() const
Definition: IRBuilder.h:202
Value * CreateSExt(Value *V, Type *DestTy, const Twine &Name="")
Definition: IRBuilder.h:2094
Value * CreateLShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition: IRBuilder.h:1513
IntegerType * getInt32Ty()
Fetch the type representing a 32-bit integer.
Definition: IRBuilder.h:562
Value * CreateCast(Instruction::CastOps Op, Value *V, Type *DestTy, const Twine &Name="", MDNode *FPMathTag=nullptr, FMFSource FMFSource={})
Definition: IRBuilder.h:2238
BasicBlock * GetInsertBlock() const
Definition: IRBuilder.h:201
IntegerType * getInt64Ty()
Fetch the type representing a 64-bit integer.
Definition: IRBuilder.h:567
Value * CreateICmpNE(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:2333
ConstantInt * getInt64(uint64_t C)
Get a constant 64-bit value.
Definition: IRBuilder.h:527
ConstantInt * getInt32(uint32_t C)
Get a constant 32-bit value.
Definition: IRBuilder.h:522
PHINode * CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name="")
Definition: IRBuilder.h:2494
SwitchInst * CreateSwitch(Value *V, BasicBlock *Dest, unsigned NumCases=10, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a switch instruction with the specified value, default dest, and with a hint for the number of...
Definition: IRBuilder.h:1220
Value * CreateICmpEQ(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:2329
IntegerType * getInt128Ty()
Fetch the type representing a 128-bit integer.
Definition: IRBuilder.h:572
Value * CreateSub(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1420
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Definition: IRBuilder.h:2204
ConstantInt * getIntN(unsigned N, uint64_t C)
Get a constant N-bit value, zero extended or truncated from a 64-bit value.
Definition: IRBuilder.h:533
BranchInst * CreateCondBr(Value *Cond, BasicBlock *True, BasicBlock *False, MDNode *BranchWeights=nullptr, MDNode *Unpredictable=nullptr)
Create a conditional 'br Cond, TrueDest, FalseDest' instruction.
Definition: IRBuilder.h:1197
Value * CreateShl(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1492
Value * CreateZExt(Value *V, Type *DestTy, const Twine &Name="", bool IsNonNeg=false)
Definition: IRBuilder.h:2082
LLVMContext & getContext() const
Definition: IRBuilder.h:203
Value * CreateAnd(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:1551
Value * CreateAdd(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1403
CallInst * CreateCall(FunctionType *FTy, Value *Callee, ArrayRef< Value * > Args={}, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:2508
Value * CreateTrunc(Value *V, Type *DestTy, const Twine &Name="", bool IsNUW=false, bool IsNSW=false)
Definition: IRBuilder.h:2068
BranchInst * CreateBr(BasicBlock *Dest)
Create an unconditional 'br label X' instruction.
Definition: IRBuilder.h:1191
void SetInsertPoint(BasicBlock *TheBB)
This specifies that created instructions should be appended to the end of the specified block.
Definition: IRBuilder.h:207
Value * CreateFPExt(Value *V, Type *DestTy, const Twine &Name="", MDNode *FPMathTag=nullptr)
Definition: IRBuilder.h:2177
Value * CreateAShr(Value *LHS, Value *RHS, const Twine &Name="", bool isExact=false)
Definition: IRBuilder.h:1532
Value * CreateXor(Value *LHS, Value *RHS, const Twine &Name="")
Definition: IRBuilder.h:1599
Value * CreateOr(Value *LHS, Value *RHS, const Twine &Name="", bool IsDisjoint=false)
Definition: IRBuilder.h:1573
Value * CreateMul(Value *LHS, Value *RHS, const Twine &Name="", bool HasNUW=false, bool HasNSW=false)
Definition: IRBuilder.h:1437
Value * CreateFPToSI(Value *V, Type *DestTy, const Twine &Name="")
Definition: IRBuilder.h:2135
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Definition: IRBuilder.h:2780
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
unsigned getOpcode() const
Returns a member of one of the enums like Instruction::Add.
Definition: Instruction.h:312
Class to represent integer types.
Definition: DerivedTypes.h:42
@ MAX_INT_BITS
Maximum number of bits that can be specified.
Definition: DerivedTypes.h:54
void addIncoming(Value *V, BasicBlock *BB)
Add an incoming value to the end of the PHI list.
static LLVM_ABI 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:112
static LLVM_ABI PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
Definition: Constants.cpp:1885
A set of analyses that are preserved following a run of a transformation pass.
Definition: Analysis.h:112
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
Definition: Analysis.h:115
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition: Analysis.h:118
bool empty() const
Definition: SmallVector.h:82
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: SmallVector.h:574
void push_back(const T &Elt)
Definition: SmallVector.h:414
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1197
Multiway switch.
unsigned getMaxLargeFPConvertBitWidthSupported() const
Returns the size in bits of the maximum fp to/from int conversion 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:83
virtual const TargetSubtargetInfo * getSubtargetImpl(const Function &) const
Virtual method implemented by subclasses that returns a reference to that target's TargetSubtargetInf...
Target-Independent Code Generator Pass Configuration Options.
TargetSubtargetInfo - Generic base class for all target subtargets.
virtual const TargetLowering * getTargetLowering() const
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:82
static LLVM_ABI Type * getFloatTy(LLVMContext &C)
static LLVM_ABI Type * getFP128Ty(LLVMContext &C)
bool isX86_FP80Ty() const
Return true if this is x86 long double.
Definition: Type.h:159
LLVM_ABI int getFPMantissaWidth() const
Return the width of the mantissa of this type.
bool isBFloatTy() const
Return true if this is 'bfloat', a 16-bit bfloat type.
Definition: Type.h:145
bool isHalfTy() const
Return true if this is 'half', a 16-bit IEEE fp type.
Definition: Type.h:142
bool isDoubleTy() const
Return true if this is 'double', a 64-bit IEEE fp type.
Definition: Type.h:156
LLVM_ABI unsigned getIntegerBitWidth() const
void dropAllReferences()
Drop all references to operands.
Definition: User.h:349
Value * getOperand(unsigned i) const
Definition: User.h:232
LLVM Value Representation.
Definition: Value.h:75
Type * getType() const
All values are typed, get the type of this value.
Definition: Value.h:256
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
Definition: Value.cpp:546
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition: CallingConv.h:24
LLVM_ABI Function * getOrInsertDeclaration(Module *M, ID id, ArrayRef< Type * > Tys={})
Look up the Function declaration of the intrinsic id in the Module M.
Definition: Intrinsics.cpp:751
initializer< Ty > init(const Ty &Val)
Definition: CommandLine.h:444
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:390
LLVM_ABI void initializeExpandFpLegacyPassPass(PassRegistry &)
@ Xor
Bitwise or logical XOR of integers.
@ Sub
Subtraction of integers.
@ Add
Sum of integers.
constexpr unsigned BitWidth
Definition: BitmaskEnum.h:223
LLVM_ABI FunctionPass * createExpandFpPass()
Matching combinators.