LLVM 24.0.0git
Float2Int.cpp
Go to the documentation of this file.
1//===- Float2Int.cpp - Demote floating point ops to work on integers ------===//
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// This file implements the Float2Int pass, which aims to demote floating
10// point operations to work on integers, where that is losslessly possible.
11//
12//===----------------------------------------------------------------------===//
13
15#include "ScalarOptions.h"
16#include "llvm/ADT/APInt.h"
17#include "llvm/ADT/APSInt.h"
20#include "llvm/IR/Constants.h"
21#include "llvm/IR/Dominators.h"
22#include "llvm/IR/IRBuilder.h"
23#include "llvm/IR/Module.h"
24#include "llvm/Support/Debug.h"
26#include <deque>
27
28#define DEBUG_TYPE "float2int"
29
30using namespace llvm;
31
32// The algorithm is simple. Start at instructions that convert from the
33// float to the int domain: fptoui, fptosi and fcmp. Walk up the def-use
34// graph, using an equivalence datastructure to unify graphs that interfere.
35//
36// Mappable instructions are those with an integer corrollary that, given
37// integer domain inputs, produce an integer output; fadd, for example.
38//
39// If a non-mappable instruction is seen, this entire def-use graph is marked
40// as non-transformable. If we see an instruction that converts from the
41// integer domain to FP domain (uitofp,sitofp), we terminate our walk.
42
43// Given a FCmp predicate, return a matching ICmp predicate if one
44// exists, otherwise return BAD_ICMP_PREDICATE.
69
70// Given a floating point binary operator, return the matching
71// integer version.
72static Instruction::BinaryOps mapBinOpcode(unsigned Opcode) {
73 switch (Opcode) {
74 default: llvm_unreachable("Unhandled opcode!");
75 case Instruction::FAdd: return Instruction::Add;
76 case Instruction::FSub: return Instruction::Sub;
77 case Instruction::FMul: return Instruction::Mul;
78 }
79}
80
81// Find the roots - instructions that convert from the FP domain to
82// integer domain.
83void Float2IntPass::findRoots(Function &F, const DominatorTree &DT) {
84 for (BasicBlock &BB : F) {
85 // Unreachable code can take on strange forms that we are not prepared to
86 // handle. For example, an instruction may have itself as an operand.
87 if (!DT.isReachableFromEntry(&BB))
88 continue;
89
90 for (Instruction &I : BB) {
91 if (isa<VectorType>(I.getType()))
92 continue;
93 switch (I.getOpcode()) {
94 default: break;
95 case Instruction::FPToUI:
96 case Instruction::FPToSI:
97 Roots.insert(&I);
98 break;
99 case Instruction::FCmp:
102 Roots.insert(&I);
103 break;
104 }
105 }
106 }
107}
108
109// Helper - mark I as having been traversed, having range R.
110void Float2IntPass::seen(Instruction *I, ConstantRange R) {
111 LLVM_DEBUG(dbgs() << "F2I: " << *I << ":" << R << "\n");
112 SeenInsts.insert_or_assign(I, std::move(R));
113}
114
115// Helper - get a range representing a poison value.
116ConstantRange Float2IntPass::badRange() {
117 return ConstantRange::getFull(MaxIntegerBW + 1);
118}
119ConstantRange Float2IntPass::unknownRange() {
120 return ConstantRange::getEmpty(MaxIntegerBW + 1);
121}
122ConstantRange Float2IntPass::validateRange(ConstantRange R) {
123 if (R.getBitWidth() > MaxIntegerBW + 1)
124 return badRange();
125 return R;
126}
127
128// The most obvious way to structure the search is a depth-first, eager
129// search from each root. However, that require direct recursion and so
130// can only handle small instruction sequences. Instead, we split the search
131// up into two phases:
132// - walkBackwards: A breadth-first walk of the use-def graph starting from
133// the roots. Populate "SeenInsts" with interesting
134// instructions and poison values if they're obvious and
135// cheap to compute. Calculate the equivalance set structure
136// while we're here too.
137// - walkForwards: Iterate over SeenInsts in reverse order, so we visit
138// defs before their uses. Calculate the real range info.
139
140// Breadth-first walk of the use-def graph; determine the set of nodes
141// we care about and eagerly determine if some of them are poisonous.
142void Float2IntPass::walkBackwards() {
143 std::deque<Instruction*> Worklist(Roots.begin(), Roots.end());
144 while (!Worklist.empty()) {
145 Instruction *I = Worklist.back();
146 Worklist.pop_back();
147
148 if (SeenInsts.contains(I))
149 // Seen already.
150 continue;
151
152 switch (I->getOpcode()) {
153 // FIXME: Handle select and phi nodes.
154 default:
155 // Path terminated uncleanly.
156 seen(I, badRange());
157 break;
158
159 case Instruction::UIToFP:
160 case Instruction::SIToFP: {
161 // Path terminated cleanly - use the type of the integer input to seed
162 // the analysis.
163 unsigned BW = I->getOperand(0)->getType()->getPrimitiveSizeInBits();
164 auto Input = ConstantRange::getFull(BW);
165 auto CastOp = (Instruction::CastOps)I->getOpcode();
166 seen(I, validateRange(Input.castOp(CastOp, MaxIntegerBW+1)));
167 continue;
168 }
169
170 case Instruction::FNeg:
171 case Instruction::FAdd:
172 case Instruction::FSub:
173 case Instruction::FMul:
174 case Instruction::FPToUI:
175 case Instruction::FPToSI:
176 case Instruction::FCmp:
177 seen(I, unknownRange());
178 break;
179 }
180
181 for (Value *O : I->operands()) {
182 if (Instruction *OI = dyn_cast<Instruction>(O)) {
183 // Unify def-use chains if they interfere.
184 ECs.unionSets(I, OI);
185 if (SeenInsts.find(I)->second != badRange())
186 Worklist.push_back(OI);
187 } else if (!isa<ConstantFP>(O)) {
188 // Not an instruction or ConstantFP? we can't do anything.
189 seen(I, badRange());
190 }
191 }
192 }
193}
194
195// Calculate result range from operand ranges.
196// Return std::nullopt if the range cannot be calculated yet.
197std::optional<ConstantRange> Float2IntPass::calcRange(Instruction *I) {
199 for (Value *O : I->operands()) {
200 if (Instruction *OI = dyn_cast<Instruction>(O)) {
201 auto OpIt = SeenInsts.find(OI);
202 assert(OpIt != SeenInsts.end() && "def not seen before use!");
203 if (OpIt->second == unknownRange())
204 return std::nullopt; // Wait until operand range has been calculated.
205 OpRanges.push_back(OpIt->second);
206 } else if (ConstantFP *CF = dyn_cast<ConstantFP>(O)) {
207 // Work out if the floating point number can be losslessly represented
208 // as an integer.
209 // APFloat::convertToInteger(&Exact) purports to do what we want, but
210 // the exactness can be too precise. For example, negative zero can
211 // never be exactly converted to an integer.
212 //
213 // Instead, we ask APFloat to round itself to an integral value - this
214 // preserves sign-of-zero - then compare the result with the original.
215 //
216 const APFloat &F = CF->getValueAPF();
217
218 // First, weed out obviously incorrect values. Non-finite numbers
219 // can't be represented and neither can negative zero, unless
220 // we're in fast math mode.
221 if (!F.isFinite() ||
222 (F.isZero() && F.isNegative() && isa<FPMathOperator>(I) &&
223 !I->hasNoSignedZeros()))
224 return badRange();
225
226 APFloat NewF = F;
228 if (Res != APFloat::opOK || NewF != F)
229 return badRange();
230
231 // OK, it's representable. Now get it.
232 APSInt Int(MaxIntegerBW+1, false);
233 bool Exact;
234 APFloat::opStatus Status = CF->getValueAPF().convertToInteger(
236 // Although the round above is loseless, we still need to check if the
237 // floating-point value can be represented in the integer type.
238 if (Status == APFloat::opOK || Status == APFloat::opInexact)
239 OpRanges.push_back(ConstantRange(Int));
240 else
241 return badRange();
242 } else {
243 llvm_unreachable("Should have already marked this as badRange!");
244 }
245 }
246
247 switch (I->getOpcode()) {
248 // FIXME: Handle select and phi nodes.
249 default:
250 case Instruction::UIToFP:
251 case Instruction::SIToFP:
252 llvm_unreachable("Should have been handled in walkForwards!");
253
254 case Instruction::FNeg: {
255 assert(OpRanges.size() == 1 && "FNeg is a unary operator!");
256 unsigned Size = OpRanges[0].getBitWidth();
257 auto Zero = ConstantRange(APInt::getZero(Size));
258 return Zero.sub(OpRanges[0]);
259 }
260
261 case Instruction::FAdd:
262 case Instruction::FSub:
263 case Instruction::FMul: {
264 assert(OpRanges.size() == 2 && "its a binary operator!");
265 auto BinOp = (Instruction::BinaryOps) I->getOpcode();
266 return OpRanges[0].binaryOp(BinOp, OpRanges[1]);
267 }
268
269 //
270 // Root-only instructions - we'll only see these if they're the
271 // first node in a walk.
272 //
273 case Instruction::FPToUI:
274 case Instruction::FPToSI: {
275 assert(OpRanges.size() == 1 && "FPTo[US]I is a unary operator!");
276 // Note: We're ignoring the casts output size here as that's what the
277 // caller expects.
278 auto CastOp = (Instruction::CastOps)I->getOpcode();
279 return OpRanges[0].castOp(CastOp, MaxIntegerBW+1);
280 }
281
282 case Instruction::FCmp:
283 assert(OpRanges.size() == 2 && "FCmp is a binary operator!");
284 return OpRanges[0].unionWith(OpRanges[1]);
285 }
286}
287
288// Walk forwards down the list of seen instructions, so we visit defs before
289// uses.
290void Float2IntPass::walkForwards() {
291 std::deque<Instruction *> Worklist;
292 for (const auto &Pair : SeenInsts)
293 if (Pair.second == unknownRange())
294 Worklist.push_back(Pair.first);
295
296 while (!Worklist.empty()) {
297 Instruction *I = Worklist.back();
298 Worklist.pop_back();
299
300 if (std::optional<ConstantRange> Range = calcRange(I))
301 seen(I, *Range);
302 else
303 Worklist.push_front(I); // Reprocess later.
304 }
305}
306
307// If there is a valid transform to be done, do it.
308bool Float2IntPass::validateAndTransform(const DataLayout &DL) {
309 bool MadeChange = false;
310
311 // Iterate over every disjoint partition of the def-use graph.
312 for (const auto &E : ECs) {
313 if (!E->isLeader())
314 continue;
315
316 ConstantRange R(MaxIntegerBW + 1, false);
317 bool Fail = false;
318 Type *ConvertedToTy = nullptr;
319
320 // For every member of the partition, union all the ranges together.
321 for (Instruction *I : ECs.members(*E)) {
322 auto *SeenI = SeenInsts.find(I);
323 if (SeenI == SeenInsts.end())
324 continue;
325
326 R = R.unionWith(SeenI->second);
327 // We need to ensure I has no users that have not been seen.
328 // If it does, transformation would be illegal.
329 //
330 // Don't count the roots, as they terminate the graphs.
331 if (!Roots.contains(I)) {
332 // Set the type of the conversion while we're here.
333 if (!ConvertedToTy)
334 ConvertedToTy = I->getType();
335 for (User *U : I->users()) {
337 if (!UI || !SeenInsts.contains(UI)) {
338 LLVM_DEBUG(dbgs() << "F2I: Failing because of " << *U << "\n");
339 Fail = true;
340 break;
341 }
342 }
343 }
344 if (Fail)
345 break;
346 }
347
348 // If the set was empty, or we failed, or the range is poisonous,
349 // bail out.
350 if (ECs.member_begin(*E) == ECs.member_end() || Fail || R.isFullSet() ||
351 R.isSignWrappedSet())
352 continue;
353 assert(ConvertedToTy && "Must have set the convertedtoty by this point!");
354
355 // The number of bits required is the maximum of the upper and
356 // lower limits, plus one so it can be signed.
357 unsigned MinBW = R.getMinSignedBits() + 1;
358 LLVM_DEBUG(dbgs() << "F2I: MinBitwidth=" << MinBW << ", R: " << R << "\n");
359
360 // If we've run off the realms of the exactly representable integers,
361 // the floating point result will differ from an integer approximation.
362
363 // Do we need more bits than are in the mantissa of the type we converted
364 // to? semanticsPrecision returns the number of mantissa bits plus one
365 // for the sign bit.
366 unsigned MaxRepresentableBits
367 = APFloat::semanticsPrecision(ConvertedToTy->getFltSemantics()) - 1;
368 if (MinBW > MaxRepresentableBits) {
369 LLVM_DEBUG(dbgs() << "F2I: Value not guaranteed to be representable!\n");
370 continue;
371 }
372
373 // OK, R is known to be representable.
374 // Pick the smallest legal type that will fit.
375 Type *Ty = DL.getSmallestLegalIntType(*Ctx, MinBW);
376 if (!Ty) {
377 // Every supported target supports 64-bit and 32-bit integers,
378 // so fallback to a 32 or 64-bit integer if the value fits.
379 if (MinBW <= 32) {
380 Ty = Type::getInt32Ty(*Ctx);
381 } else if (MinBW <= 64) {
382 Ty = Type::getInt64Ty(*Ctx);
383 } else {
384 LLVM_DEBUG(dbgs() << "F2I: Value requires more bits to represent than "
385 "the target supports!\n");
386 continue;
387 }
388 }
389
390 for (Instruction *I : ECs.members(*E))
391 convert(I, Ty);
392 MadeChange = true;
393 }
394
395 return MadeChange;
396}
397
398Value *Float2IntPass::convert(Instruction *I, Type *ToTy) {
399 if (auto It = ConvertedInsts.find(I); It != ConvertedInsts.end())
400 // Already converted this instruction.
401 return It->second;
402
403 SmallVector<Value*,4> NewOperands;
404 for (Value *V : I->operands()) {
405 // Don't recurse if we're an instruction that terminates the path.
406 if (I->getOpcode() == Instruction::UIToFP ||
407 I->getOpcode() == Instruction::SIToFP) {
408 NewOperands.push_back(V);
409 } else if (Instruction *VI = dyn_cast<Instruction>(V)) {
410 NewOperands.push_back(convert(VI, ToTy));
411 } else if (ConstantFP *CF = dyn_cast<ConstantFP>(V)) {
412 APSInt Val(ToTy->getPrimitiveSizeInBits(), /*isUnsigned=*/false);
413 bool Exact;
414 CF->getValueAPF().convertToInteger(Val,
416 &Exact);
417 NewOperands.push_back(ConstantInt::get(ToTy, Val));
418 } else {
419 llvm_unreachable("Unhandled operand type?");
420 }
421 }
422
423 // Now create a new instruction.
424 IRBuilder<> IRB(I);
425 Value *NewV = nullptr;
426 switch (I->getOpcode()) {
427 default: llvm_unreachable("Unhandled instruction!");
428
429 case Instruction::FPToUI:
430 NewV = IRB.CreateZExtOrTrunc(NewOperands[0], I->getType());
431 break;
432
433 case Instruction::FPToSI:
434 NewV = IRB.CreateSExtOrTrunc(NewOperands[0], I->getType());
435 break;
436
437 case Instruction::FCmp: {
439 assert(P != CmpInst::BAD_ICMP_PREDICATE && "Unhandled predicate!");
440 NewV = IRB.CreateICmp(P, NewOperands[0], NewOperands[1], I->getName());
441 break;
442 }
443
444 case Instruction::UIToFP:
445 NewV = IRB.CreateZExtOrTrunc(NewOperands[0], ToTy);
446 break;
447
448 case Instruction::SIToFP:
449 NewV = IRB.CreateSExtOrTrunc(NewOperands[0], ToTy);
450 break;
451
452 case Instruction::FNeg:
453 NewV = IRB.CreateNeg(NewOperands[0], I->getName());
454 break;
455
456 case Instruction::FAdd:
457 case Instruction::FSub:
458 case Instruction::FMul:
459 NewV = IRB.CreateBinOp(mapBinOpcode(I->getOpcode()),
460 NewOperands[0], NewOperands[1],
461 I->getName());
462 break;
463 }
464
465 // If we're a root instruction, RAUW.
466 if (Roots.count(I))
467 I->replaceAllUsesWith(NewV);
468
469 ConvertedInsts[I] = NewV;
470 return NewV;
471}
472
473// Perform dead code elimination on the instructions we just modified.
474void Float2IntPass::cleanup() {
475 for (auto &I : reverse(ConvertedInsts))
476 I.first->eraseFromParent();
477}
478
480 LLVM_DEBUG(dbgs() << "F2I: Looking at function " << F.getName() << "\n");
481 // Clear out all state.
483 SeenInsts.clear();
484 ConvertedInsts.clear();
485 Roots.clear();
486
487 MaxIntegerBW = ScalarOptions::Global.float2int_max_integer_bw;
488 Ctx = &F.getParent()->getContext();
489
490 findRoots(F, DT);
491
492 walkBackwards();
493 walkForwards();
494
495 const DataLayout &DL = F.getDataLayout();
496 bool Modified = validateAndTransform(DL);
497 if (Modified)
498 cleanup();
499 return Modified;
500}
501
#define Fail
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
This file implements the APSInt class, which is a simple class that represents an arbitrary sized int...
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static CmpInst::Predicate mapFCmpPred(CmpInst::Predicate P)
Definition Float2Int.cpp:45
static Instruction::BinaryOps mapBinOpcode(unsigned Opcode)
Definition Float2Int.cpp:72
This is the interface for a simple mod/ref and alias analysis over globals.
Module.h This file contains the declarations for the Module class.
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
#define P(N)
This file defines the SmallVector class.
#define LLVM_DEBUG(...)
Definition Debug.h:119
static constexpr roundingMode rmNearestTiesToEven
Definition APFloat.h:361
static LLVM_ABI unsigned int semanticsPrecision(const fltSemantics &)
Definition APFloat.cpp:329
opStatus
IEEE-754R 7: Default exception handling.
Definition APFloat.h:377
opStatus roundToIntegral(roundingMode RM)
Definition APFloat.h:1352
static APInt getZero(unsigned numBits)
Get the '0' value for the specified bit-width.
Definition APInt.h:196
PassT::Result & getResult(IRUnitT &IR, ExtraArgTs... ExtraArgs)
Get the result of an analysis pass for a given IR unit.
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
Predicate
This enumeration lists the possible predicates for CmpInst subclasses.
Definition InstrTypes.h:740
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
Definition InstrTypes.h:743
@ ICMP_SLT
signed less than
Definition InstrTypes.h:769
@ ICMP_SLE
signed less or equal
Definition InstrTypes.h:770
@ FCMP_OLT
0 1 0 0 True if ordered and less than
Definition InstrTypes.h:746
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
Definition InstrTypes.h:755
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
Definition InstrTypes.h:744
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
Definition InstrTypes.h:745
@ ICMP_SGT
signed greater than
Definition InstrTypes.h:767
@ FCMP_ULT
1 1 0 0 True if unordered or less than
Definition InstrTypes.h:754
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
Definition InstrTypes.h:748
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
Definition InstrTypes.h:751
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
Definition InstrTypes.h:752
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
Definition InstrTypes.h:747
@ ICMP_NE
not equal
Definition InstrTypes.h:762
@ ICMP_SGE
signed greater or equal
Definition InstrTypes.h:768
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
Definition InstrTypes.h:756
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
Definition InstrTypes.h:753
This class represents a range of values.
A parsed version of the target data layout string in and methods for querying it.
Definition DataLayout.h:64
Analysis pass which computes a DominatorTree.
Definition Dominators.h:241
Concrete subclass of DominatorTreeBase that is used to compute a normal dominator tree.
Definition Dominators.h:122
LLVM_ABI bool isReachableFromEntry(const Use &U) const
Provide an overload for a Use.
This represents a collection of equivalence classes and supports three efficient operations: insert a...
LLVM_ABI bool runImpl(Function &F, const DominatorTree &DT)
LLVM_ABI PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM)
A set of analyses that are preserved following a run of a transformation pass.
Definition Analysis.h:112
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
void push_back(const T &Elt)
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
static LLVM_ABI IntegerType * getInt64Ty(LLVMContext &C)
Definition Type.cpp:300
static LLVM_ABI IntegerType * getInt32Ty(LLVMContext &C)
Definition Type.cpp:299
LLVM_ABI TypeSize getPrimitiveSizeInBits() const LLVM_READONLY
Return the basic size of this type if it is a primitive type.
Definition Type.cpp:187
LLVM_ABI const fltSemantics & getFltSemantics() const
Definition Type.cpp:96
LLVM Value Representation.
Definition Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Predicate getPredicate(unsigned Condition, unsigned Hint)
Return predicate consisting of specified condition and hint bits.
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
auto reverse(ContainerTy &&C)
Definition STLExtras.h:408
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
IRBuilder(LLVMContext &, FolderTy, InserterTy) -> IRBuilder< FolderTy, InserterTy >
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
AnalysisManager< Function > FunctionAnalysisManager
Convenience typedef for the Function analysis manager.