10cbb2a86SJames Molloy //===- Float2Int.cpp - Demote floating point ops to work on integers ------===//
20cbb2a86SJames Molloy //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60cbb2a86SJames Molloy //
70cbb2a86SJames Molloy //===----------------------------------------------------------------------===//
80cbb2a86SJames Molloy //
90cbb2a86SJames Molloy // This file implements the Float2Int pass, which aims to demote floating
100cbb2a86SJames Molloy // point operations to work on integers, where that is losslessly possible.
110cbb2a86SJames Molloy //
120cbb2a86SJames Molloy //===----------------------------------------------------------------------===//
130cbb2a86SJames Molloy
1483b753d4SMichael Kuperstein #include "llvm/Transforms/Scalar/Float2Int.h"
150cbb2a86SJames Molloy #include "llvm/ADT/APInt.h"
160cbb2a86SJames Molloy #include "llvm/ADT/APSInt.h"
170cbb2a86SJames Molloy #include "llvm/ADT/SmallVector.h"
187b560d40SChandler Carruth #include "llvm/Analysis/GlobalsModRef.h"
190cbb2a86SJames Molloy #include "llvm/IR/Constants.h"
20ed98c1b3Sserge-sans-paille #include "llvm/IR/Dominators.h"
210cbb2a86SJames Molloy #include "llvm/IR/IRBuilder.h"
220cbb2a86SJames Molloy #include "llvm/IR/Module.h"
2359630917Sserge-sans-paille #include "llvm/InitializePasses.h"
240cbb2a86SJames Molloy #include "llvm/Pass.h"
2559630917Sserge-sans-paille #include "llvm/Support/CommandLine.h"
260cbb2a86SJames Molloy #include "llvm/Support/Debug.h"
270cbb2a86SJames Molloy #include "llvm/Support/raw_ostream.h"
280cbb2a86SJames Molloy #include "llvm/Transforms/Scalar.h"
290cbb2a86SJames Molloy #include <deque>
3071acce68SMindong Chen
3171acce68SMindong Chen #define DEBUG_TYPE "float2int"
3271acce68SMindong Chen
330cbb2a86SJames Molloy using namespace llvm;
340cbb2a86SJames Molloy
350cbb2a86SJames Molloy // The algorithm is simple. Start at instructions that convert from the
360cbb2a86SJames Molloy // float to the int domain: fptoui, fptosi and fcmp. Walk up the def-use
370cbb2a86SJames Molloy // graph, using an equivalence datastructure to unify graphs that interfere.
380cbb2a86SJames Molloy //
390cbb2a86SJames Molloy // Mappable instructions are those with an integer corrollary that, given
400cbb2a86SJames Molloy // integer domain inputs, produce an integer output; fadd, for example.
410cbb2a86SJames Molloy //
420cbb2a86SJames Molloy // If a non-mappable instruction is seen, this entire def-use graph is marked
430cbb2a86SJames Molloy // as non-transformable. If we see an instruction that converts from the
440cbb2a86SJames Molloy // integer domain to FP domain (uitofp,sitofp), we terminate our walk.
450cbb2a86SJames Molloy
460cbb2a86SJames Molloy /// The largest integer type worth dealing with.
470cbb2a86SJames Molloy static cl::opt<unsigned>
480cbb2a86SJames Molloy MaxIntegerBW("float2int-max-integer-bw", cl::init(64), cl::Hidden,
490cbb2a86SJames Molloy cl::desc("Max integer bitwidth to consider in float2int"
500cbb2a86SJames Molloy "(default=64)"));
510cbb2a86SJames Molloy
520cbb2a86SJames Molloy namespace {
5383b753d4SMichael Kuperstein struct Float2IntLegacyPass : public FunctionPass {
540cbb2a86SJames Molloy static char ID; // Pass identification, replacement for typeid
Float2IntLegacyPass__anon0ca239b60111::Float2IntLegacyPass5583b753d4SMichael Kuperstein Float2IntLegacyPass() : FunctionPass(ID) {
5683b753d4SMichael Kuperstein initializeFloat2IntLegacyPassPass(*PassRegistry::getPassRegistry());
570cbb2a86SJames Molloy }
580cbb2a86SJames Molloy
runOnFunction__anon0ca239b60111::Float2IntLegacyPass5983b753d4SMichael Kuperstein bool runOnFunction(Function &F) override {
6083b753d4SMichael Kuperstein if (skipFunction(F))
6183b753d4SMichael Kuperstein return false;
6283b753d4SMichael Kuperstein
6313e71ce6SSanjay Patel const DominatorTree &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree();
6413e71ce6SSanjay Patel return Impl.runImpl(F, DT);
6583b753d4SMichael Kuperstein }
6683b753d4SMichael Kuperstein
getAnalysisUsage__anon0ca239b60111::Float2IntLegacyPass670cbb2a86SJames Molloy void getAnalysisUsage(AnalysisUsage &AU) const override {
680cbb2a86SJames Molloy AU.setPreservesCFG();
6913e71ce6SSanjay Patel AU.addRequired<DominatorTreeWrapperPass>();
707b560d40SChandler Carruth AU.addPreserved<GlobalsAAWrapperPass>();
710cbb2a86SJames Molloy }
720cbb2a86SJames Molloy
7383b753d4SMichael Kuperstein private:
7483b753d4SMichael Kuperstein Float2IntPass Impl;
750cbb2a86SJames Molloy };
76f00654e3SAlexander Kornienko }
770cbb2a86SJames Molloy
7883b753d4SMichael Kuperstein char Float2IntLegacyPass::ID = 0;
7983b753d4SMichael Kuperstein INITIALIZE_PASS(Float2IntLegacyPass, "float2int", "Float to int", false, false)
800cbb2a86SJames Molloy
810cbb2a86SJames Molloy // Given a FCmp predicate, return a matching ICmp predicate if one
820cbb2a86SJames Molloy // exists, otherwise return BAD_ICMP_PREDICATE.
mapFCmpPred(CmpInst::Predicate P)830cbb2a86SJames Molloy static CmpInst::Predicate mapFCmpPred(CmpInst::Predicate P) {
840cbb2a86SJames Molloy switch (P) {
850cbb2a86SJames Molloy case CmpInst::FCMP_OEQ:
860cbb2a86SJames Molloy case CmpInst::FCMP_UEQ:
870cbb2a86SJames Molloy return CmpInst::ICMP_EQ;
880cbb2a86SJames Molloy case CmpInst::FCMP_OGT:
890cbb2a86SJames Molloy case CmpInst::FCMP_UGT:
900cbb2a86SJames Molloy return CmpInst::ICMP_SGT;
910cbb2a86SJames Molloy case CmpInst::FCMP_OGE:
920cbb2a86SJames Molloy case CmpInst::FCMP_UGE:
930cbb2a86SJames Molloy return CmpInst::ICMP_SGE;
940cbb2a86SJames Molloy case CmpInst::FCMP_OLT:
950cbb2a86SJames Molloy case CmpInst::FCMP_ULT:
960cbb2a86SJames Molloy return CmpInst::ICMP_SLT;
970cbb2a86SJames Molloy case CmpInst::FCMP_OLE:
980cbb2a86SJames Molloy case CmpInst::FCMP_ULE:
990cbb2a86SJames Molloy return CmpInst::ICMP_SLE;
1000cbb2a86SJames Molloy case CmpInst::FCMP_ONE:
1010cbb2a86SJames Molloy case CmpInst::FCMP_UNE:
1020cbb2a86SJames Molloy return CmpInst::ICMP_NE;
1030cbb2a86SJames Molloy default:
1040cbb2a86SJames Molloy return CmpInst::BAD_ICMP_PREDICATE;
1050cbb2a86SJames Molloy }
1060cbb2a86SJames Molloy }
1070cbb2a86SJames Molloy
1080cbb2a86SJames Molloy // Given a floating point binary operator, return the matching
1090cbb2a86SJames Molloy // integer version.
mapBinOpcode(unsigned Opcode)1100cbb2a86SJames Molloy static Instruction::BinaryOps mapBinOpcode(unsigned Opcode) {
1110cbb2a86SJames Molloy switch (Opcode) {
1120cbb2a86SJames Molloy default: llvm_unreachable("Unhandled opcode!");
1130cbb2a86SJames Molloy case Instruction::FAdd: return Instruction::Add;
1140cbb2a86SJames Molloy case Instruction::FSub: return Instruction::Sub;
1150cbb2a86SJames Molloy case Instruction::FMul: return Instruction::Mul;
1160cbb2a86SJames Molloy }
1170cbb2a86SJames Molloy }
1180cbb2a86SJames Molloy
1190cbb2a86SJames Molloy // Find the roots - instructions that convert from the FP domain to
1200cbb2a86SJames Molloy // integer domain.
findRoots(Function & F,const DominatorTree & DT)121fdf9bad5SBjorn Pettersson void Float2IntPass::findRoots(Function &F, const DominatorTree &DT) {
12213e71ce6SSanjay Patel for (BasicBlock &BB : F) {
12313e71ce6SSanjay Patel // Unreachable code can take on strange forms that we are not prepared to
12413e71ce6SSanjay Patel // handle. For example, an instruction may have itself as an operand.
12513e71ce6SSanjay Patel if (!DT.isReachableFromEntry(&BB))
12613e71ce6SSanjay Patel continue;
12713e71ce6SSanjay Patel
12813e71ce6SSanjay Patel for (Instruction &I : BB) {
12954ade235SReid Kleckner if (isa<VectorType>(I.getType()))
13054ade235SReid Kleckner continue;
1310cbb2a86SJames Molloy switch (I.getOpcode()) {
1320cbb2a86SJames Molloy default: break;
1330cbb2a86SJames Molloy case Instruction::FPToUI:
1340cbb2a86SJames Molloy case Instruction::FPToSI:
1350cbb2a86SJames Molloy Roots.insert(&I);
1360cbb2a86SJames Molloy break;
1370cbb2a86SJames Molloy case Instruction::FCmp:
1380cbb2a86SJames Molloy if (mapFCmpPred(cast<CmpInst>(&I)->getPredicate()) !=
1390cbb2a86SJames Molloy CmpInst::BAD_ICMP_PREDICATE)
1400cbb2a86SJames Molloy Roots.insert(&I);
1410cbb2a86SJames Molloy break;
1420cbb2a86SJames Molloy }
1430cbb2a86SJames Molloy }
1440cbb2a86SJames Molloy }
14513e71ce6SSanjay Patel }
1460cbb2a86SJames Molloy
1470cbb2a86SJames Molloy // Helper - mark I as having been traversed, having range R.
seen(Instruction * I,ConstantRange R)1485974dadcSCraig Topper void Float2IntPass::seen(Instruction *I, ConstantRange R) {
149d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "F2I: " << *I << ":" << R << "\n");
150fc481e5eSCraig Topper auto IT = SeenInsts.find(I);
151fc481e5eSCraig Topper if (IT != SeenInsts.end())
152fc481e5eSCraig Topper IT->second = std::move(R);
1530cbb2a86SJames Molloy else
154fc481e5eSCraig Topper SeenInsts.insert(std::make_pair(I, std::move(R)));
1550cbb2a86SJames Molloy }
1560cbb2a86SJames Molloy
1570cbb2a86SJames Molloy // Helper - get a range representing a poison value.
badRange()15883b753d4SMichael Kuperstein ConstantRange Float2IntPass::badRange() {
159977934f0SNikita Popov return ConstantRange::getFull(MaxIntegerBW + 1);
1600cbb2a86SJames Molloy }
unknownRange()16183b753d4SMichael Kuperstein ConstantRange Float2IntPass::unknownRange() {
162977934f0SNikita Popov return ConstantRange::getEmpty(MaxIntegerBW + 1);
1630cbb2a86SJames Molloy }
validateRange(ConstantRange R)16483b753d4SMichael Kuperstein ConstantRange Float2IntPass::validateRange(ConstantRange R) {
1650cbb2a86SJames Molloy if (R.getBitWidth() > MaxIntegerBW + 1)
1660cbb2a86SJames Molloy return badRange();
1670cbb2a86SJames Molloy return R;
1680cbb2a86SJames Molloy }
1690cbb2a86SJames Molloy
1700cbb2a86SJames Molloy // The most obvious way to structure the search is a depth-first, eager
1710cbb2a86SJames Molloy // search from each root. However, that require direct recursion and so
1720cbb2a86SJames Molloy // can only handle small instruction sequences. Instead, we split the search
1730cbb2a86SJames Molloy // up into two phases:
1740cbb2a86SJames Molloy // - walkBackwards: A breadth-first walk of the use-def graph starting from
1750cbb2a86SJames Molloy // the roots. Populate "SeenInsts" with interesting
1760cbb2a86SJames Molloy // instructions and poison values if they're obvious and
1770cbb2a86SJames Molloy // cheap to compute. Calculate the equivalance set structure
1780cbb2a86SJames Molloy // while we're here too.
1790cbb2a86SJames Molloy // - walkForwards: Iterate over SeenInsts in reverse order, so we visit
1800cbb2a86SJames Molloy // defs before their uses. Calculate the real range info.
1810cbb2a86SJames Molloy
1820cbb2a86SJames Molloy // Breadth-first walk of the use-def graph; determine the set of nodes
1830cbb2a86SJames Molloy // we care about and eagerly determine if some of them are poisonous.
walkBackwards()184fdf9bad5SBjorn Pettersson void Float2IntPass::walkBackwards() {
1850cbb2a86SJames Molloy std::deque<Instruction*> Worklist(Roots.begin(), Roots.end());
1860cbb2a86SJames Molloy while (!Worklist.empty()) {
1870cbb2a86SJames Molloy Instruction *I = Worklist.back();
1880cbb2a86SJames Molloy Worklist.pop_back();
1890cbb2a86SJames Molloy
1900cbb2a86SJames Molloy if (SeenInsts.find(I) != SeenInsts.end())
1910cbb2a86SJames Molloy // Seen already.
1920cbb2a86SJames Molloy continue;
1930cbb2a86SJames Molloy
1940cbb2a86SJames Molloy switch (I->getOpcode()) {
1950cbb2a86SJames Molloy // FIXME: Handle select and phi nodes.
1960cbb2a86SJames Molloy default:
1970cbb2a86SJames Molloy // Path terminated uncleanly.
1980cbb2a86SJames Molloy seen(I, badRange());
1990cbb2a86SJames Molloy break;
2000cbb2a86SJames Molloy
2014d00af1bSPhilip Reames case Instruction::UIToFP:
2020cbb2a86SJames Molloy case Instruction::SIToFP: {
2034d00af1bSPhilip Reames // Path terminated cleanly - use the type of the integer input to seed
2044d00af1bSPhilip Reames // the analysis.
2050cbb2a86SJames Molloy unsigned BW = I->getOperand(0)->getType()->getPrimitiveSizeInBits();
206977934f0SNikita Popov auto Input = ConstantRange::getFull(BW);
2074d00af1bSPhilip Reames auto CastOp = (Instruction::CastOps)I->getOpcode();
2084d00af1bSPhilip Reames seen(I, validateRange(Input.castOp(CastOp, MaxIntegerBW+1)));
2090cbb2a86SJames Molloy continue;
2100cbb2a86SJames Molloy }
2110cbb2a86SJames Molloy
212771769beSCameron McInally case Instruction::FNeg:
2130cbb2a86SJames Molloy case Instruction::FAdd:
2140cbb2a86SJames Molloy case Instruction::FSub:
2150cbb2a86SJames Molloy case Instruction::FMul:
2160cbb2a86SJames Molloy case Instruction::FPToUI:
2170cbb2a86SJames Molloy case Instruction::FPToSI:
2180cbb2a86SJames Molloy case Instruction::FCmp:
2190cbb2a86SJames Molloy seen(I, unknownRange());
2200cbb2a86SJames Molloy break;
2210cbb2a86SJames Molloy }
2220cbb2a86SJames Molloy
2230cbb2a86SJames Molloy for (Value *O : I->operands()) {
2240cbb2a86SJames Molloy if (Instruction *OI = dyn_cast<Instruction>(O)) {
2250cbb2a86SJames Molloy // Unify def-use chains if they interfere.
2260cbb2a86SJames Molloy ECs.unionSets(I, OI);
2270cbb2a86SJames Molloy if (SeenInsts.find(I)->second != badRange())
2280cbb2a86SJames Molloy Worklist.push_back(OI);
2290cbb2a86SJames Molloy } else if (!isa<ConstantFP>(O)) {
2300cbb2a86SJames Molloy // Not an instruction or ConstantFP? we can't do anything.
2310cbb2a86SJames Molloy seen(I, badRange());
2320cbb2a86SJames Molloy }
2330cbb2a86SJames Molloy }
2340cbb2a86SJames Molloy }
2350cbb2a86SJames Molloy }
2360cbb2a86SJames Molloy
237*c0cc9825SNikita Popov // Calculate result range from operand ranges.
238*c0cc9825SNikita Popov // Return None if the range cannot be calculated yet.
calcRange(Instruction * I)239*c0cc9825SNikita Popov Optional<ConstantRange> Float2IntPass::calcRange(Instruction *I) {
2400cbb2a86SJames Molloy SmallVector<ConstantRange, 4> OpRanges;
2410cbb2a86SJames Molloy for (Value *O : I->operands()) {
2420cbb2a86SJames Molloy if (Instruction *OI = dyn_cast<Instruction>(O)) {
243*c0cc9825SNikita Popov auto OpIt = SeenInsts.find(OI);
244*c0cc9825SNikita Popov assert(OpIt != SeenInsts.end() && "def not seen before use!");
245*c0cc9825SNikita Popov if (OpIt->second == unknownRange())
246*c0cc9825SNikita Popov return None; // Wait until operand range has been calculated.
247*c0cc9825SNikita Popov OpRanges.push_back(OpIt->second);
2480cbb2a86SJames Molloy } else if (ConstantFP *CF = dyn_cast<ConstantFP>(O)) {
2490cbb2a86SJames Molloy // Work out if the floating point number can be losslessly represented
2500cbb2a86SJames Molloy // as an integer.
2510cbb2a86SJames Molloy // APFloat::convertToInteger(&Exact) purports to do what we want, but
2520cbb2a86SJames Molloy // the exactness can be too precise. For example, negative zero can
2530cbb2a86SJames Molloy // never be exactly converted to an integer.
2540cbb2a86SJames Molloy //
2550cbb2a86SJames Molloy // Instead, we ask APFloat to round itself to an integral value - this
2560cbb2a86SJames Molloy // preserves sign-of-zero - then compare the result with the original.
2570cbb2a86SJames Molloy //
25846e38f36SBenjamin Kramer const APFloat &F = CF->getValueAPF();
2590cbb2a86SJames Molloy
2600cbb2a86SJames Molloy // First, weed out obviously incorrect values. Non-finite numbers
2610cbb2a86SJames Molloy // can't be represented and neither can negative zero, unless
2620cbb2a86SJames Molloy // we're in fast math mode.
2630cbb2a86SJames Molloy if (!F.isFinite() ||
2640cbb2a86SJames Molloy (F.isZero() && F.isNegative() && isa<FPMathOperator>(I) &&
265f6697555SNikita Popov !I->hasNoSignedZeros()))
266f6697555SNikita Popov return badRange();
2670cbb2a86SJames Molloy
2680cbb2a86SJames Molloy APFloat NewF = F;
2690cbb2a86SJames Molloy auto Res = NewF.roundToIntegral(APFloat::rmNearestTiesToEven);
270f6697555SNikita Popov if (Res != APFloat::opOK || NewF != F)
271f6697555SNikita Popov return badRange();
272f6697555SNikita Popov
2730cbb2a86SJames Molloy // OK, it's representable. Now get it.
2740cbb2a86SJames Molloy APSInt Int(MaxIntegerBW+1, false);
2750cbb2a86SJames Molloy bool Exact;
2760cbb2a86SJames Molloy CF->getValueAPF().convertToInteger(Int,
2770cbb2a86SJames Molloy APFloat::rmNearestTiesToEven,
2780cbb2a86SJames Molloy &Exact);
2790cbb2a86SJames Molloy OpRanges.push_back(ConstantRange(Int));
2800cbb2a86SJames Molloy } else {
2810cbb2a86SJames Molloy llvm_unreachable("Should have already marked this as badRange!");
2820cbb2a86SJames Molloy }
2830cbb2a86SJames Molloy }
2840cbb2a86SJames Molloy
28533ac23e7SNikita Popov switch (I->getOpcode()) {
28633ac23e7SNikita Popov // FIXME: Handle select and phi nodes.
28733ac23e7SNikita Popov default:
28833ac23e7SNikita Popov case Instruction::UIToFP:
28933ac23e7SNikita Popov case Instruction::SIToFP:
29033ac23e7SNikita Popov llvm_unreachable("Should have been handled in walkForwards!");
29133ac23e7SNikita Popov
29233ac23e7SNikita Popov case Instruction::FNeg: {
29333ac23e7SNikita Popov assert(OpRanges.size() == 1 && "FNeg is a unary operator!");
29433ac23e7SNikita Popov unsigned Size = OpRanges[0].getBitWidth();
29533ac23e7SNikita Popov auto Zero = ConstantRange(APInt::getZero(Size));
29633ac23e7SNikita Popov return Zero.sub(OpRanges[0]);
29733ac23e7SNikita Popov }
29833ac23e7SNikita Popov
29933ac23e7SNikita Popov case Instruction::FAdd:
30033ac23e7SNikita Popov case Instruction::FSub:
30133ac23e7SNikita Popov case Instruction::FMul: {
30233ac23e7SNikita Popov assert(OpRanges.size() == 2 && "its a binary operator!");
30333ac23e7SNikita Popov auto BinOp = (Instruction::BinaryOps) I->getOpcode();
30433ac23e7SNikita Popov return OpRanges[0].binaryOp(BinOp, OpRanges[1]);
30533ac23e7SNikita Popov }
30633ac23e7SNikita Popov
30733ac23e7SNikita Popov //
30833ac23e7SNikita Popov // Root-only instructions - we'll only see these if they're the
30933ac23e7SNikita Popov // first node in a walk.
31033ac23e7SNikita Popov //
31133ac23e7SNikita Popov case Instruction::FPToUI:
31233ac23e7SNikita Popov case Instruction::FPToSI: {
31333ac23e7SNikita Popov assert(OpRanges.size() == 1 && "FPTo[US]I is a unary operator!");
31433ac23e7SNikita Popov // Note: We're ignoring the casts output size here as that's what the
31533ac23e7SNikita Popov // caller expects.
31633ac23e7SNikita Popov auto CastOp = (Instruction::CastOps)I->getOpcode();
31733ac23e7SNikita Popov return OpRanges[0].castOp(CastOp, MaxIntegerBW+1);
31833ac23e7SNikita Popov }
31933ac23e7SNikita Popov
32033ac23e7SNikita Popov case Instruction::FCmp:
32133ac23e7SNikita Popov assert(OpRanges.size() == 2 && "FCmp is a binary operator!");
32233ac23e7SNikita Popov return OpRanges[0].unionWith(OpRanges[1]);
32333ac23e7SNikita Popov }
324f6697555SNikita Popov }
325f6697555SNikita Popov
326f6697555SNikita Popov // Walk forwards down the list of seen instructions, so we visit defs before
327f6697555SNikita Popov // uses.
walkForwards()328f6697555SNikita Popov void Float2IntPass::walkForwards() {
329*c0cc9825SNikita Popov std::deque<Instruction *> Worklist;
330*c0cc9825SNikita Popov for (const auto &Pair : SeenInsts)
331*c0cc9825SNikita Popov if (Pair.second == unknownRange())
332*c0cc9825SNikita Popov Worklist.push_back(Pair.first);
333f6697555SNikita Popov
334*c0cc9825SNikita Popov while (!Worklist.empty()) {
335*c0cc9825SNikita Popov Instruction *I = Worklist.back();
336*c0cc9825SNikita Popov Worklist.pop_back();
337*c0cc9825SNikita Popov
338*c0cc9825SNikita Popov if (Optional<ConstantRange> Range = calcRange(I))
339*c0cc9825SNikita Popov seen(I, *Range);
340*c0cc9825SNikita Popov else
341*c0cc9825SNikita Popov Worklist.push_front(I); // Reprocess later.
3420cbb2a86SJames Molloy }
3430cbb2a86SJames Molloy }
3440cbb2a86SJames Molloy
3450cbb2a86SJames Molloy // If there is a valid transform to be done, do it.
validateAndTransform()34683b753d4SMichael Kuperstein bool Float2IntPass::validateAndTransform() {
3470cbb2a86SJames Molloy bool MadeChange = false;
3480cbb2a86SJames Molloy
3490cbb2a86SJames Molloy // Iterate over every disjoint partition of the def-use graph.
3500cbb2a86SJames Molloy for (auto It = ECs.begin(), E = ECs.end(); It != E; ++It) {
3510cbb2a86SJames Molloy ConstantRange R(MaxIntegerBW + 1, false);
3520cbb2a86SJames Molloy bool Fail = false;
3530cbb2a86SJames Molloy Type *ConvertedToTy = nullptr;
3540cbb2a86SJames Molloy
3550cbb2a86SJames Molloy // For every member of the partition, union all the ranges together.
3560cbb2a86SJames Molloy for (auto MI = ECs.member_begin(It), ME = ECs.member_end();
3570cbb2a86SJames Molloy MI != ME; ++MI) {
3580cbb2a86SJames Molloy Instruction *I = *MI;
3590cbb2a86SJames Molloy auto SeenI = SeenInsts.find(I);
3600cbb2a86SJames Molloy if (SeenI == SeenInsts.end())
3610cbb2a86SJames Molloy continue;
3620cbb2a86SJames Molloy
3630cbb2a86SJames Molloy R = R.unionWith(SeenI->second);
3640cbb2a86SJames Molloy // We need to ensure I has no users that have not been seen.
3650cbb2a86SJames Molloy // If it does, transformation would be illegal.
3660cbb2a86SJames Molloy //
3670cbb2a86SJames Molloy // Don't count the roots, as they terminate the graphs.
368c714da2cSKazu Hirata if (!Roots.contains(I)) {
3690cbb2a86SJames Molloy // Set the type of the conversion while we're here.
3700cbb2a86SJames Molloy if (!ConvertedToTy)
3710cbb2a86SJames Molloy ConvertedToTy = I->getType();
3720cbb2a86SJames Molloy for (User *U : I->users()) {
3730cbb2a86SJames Molloy Instruction *UI = dyn_cast<Instruction>(U);
3740cbb2a86SJames Molloy if (!UI || SeenInsts.find(UI) == SeenInsts.end()) {
375d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "F2I: Failing because of " << *U << "\n");
3760cbb2a86SJames Molloy Fail = true;
3770cbb2a86SJames Molloy break;
3780cbb2a86SJames Molloy }
3790cbb2a86SJames Molloy }
3800cbb2a86SJames Molloy }
3810cbb2a86SJames Molloy if (Fail)
3820cbb2a86SJames Molloy break;
3830cbb2a86SJames Molloy }
3840cbb2a86SJames Molloy
3850cbb2a86SJames Molloy // If the set was empty, or we failed, or the range is poisonous,
3860cbb2a86SJames Molloy // bail out.
3870cbb2a86SJames Molloy if (ECs.member_begin(It) == ECs.member_end() || Fail ||
3880cbb2a86SJames Molloy R.isFullSet() || R.isSignWrappedSet())
3890cbb2a86SJames Molloy continue;
3900cbb2a86SJames Molloy assert(ConvertedToTy && "Must have set the convertedtoty by this point!");
3910cbb2a86SJames Molloy
3920cbb2a86SJames Molloy // The number of bits required is the maximum of the upper and
3930cbb2a86SJames Molloy // lower limits, plus one so it can be signed.
3940cbb2a86SJames Molloy unsigned MinBW = std::max(R.getLower().getMinSignedBits(),
3950cbb2a86SJames Molloy R.getUpper().getMinSignedBits()) + 1;
396d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "F2I: MinBitwidth=" << MinBW << ", R: " << R << "\n");
3970cbb2a86SJames Molloy
3980cbb2a86SJames Molloy // If we've run off the realms of the exactly representable integers,
3990cbb2a86SJames Molloy // the floating point result will differ from an integer approximation.
4000cbb2a86SJames Molloy
4010cbb2a86SJames Molloy // Do we need more bits than are in the mantissa of the type we converted
4020cbb2a86SJames Molloy // to? semanticsPrecision returns the number of mantissa bits plus one
4030cbb2a86SJames Molloy // for the sign bit.
4040cbb2a86SJames Molloy unsigned MaxRepresentableBits
4050cbb2a86SJames Molloy = APFloat::semanticsPrecision(ConvertedToTy->getFltSemantics()) - 1;
4060cbb2a86SJames Molloy if (MinBW > MaxRepresentableBits) {
407d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "F2I: Value not guaranteed to be representable!\n");
4080cbb2a86SJames Molloy continue;
4090cbb2a86SJames Molloy }
4100cbb2a86SJames Molloy if (MinBW > 64) {
411d34e60caSNicola Zaghen LLVM_DEBUG(
412d34e60caSNicola Zaghen dbgs() << "F2I: Value requires more than 64 bits to represent!\n");
4130cbb2a86SJames Molloy continue;
4140cbb2a86SJames Molloy }
4150cbb2a86SJames Molloy
4160cbb2a86SJames Molloy // OK, R is known to be representable. Now pick a type for it.
4170cbb2a86SJames Molloy // FIXME: Pick the smallest legal type that will fit.
4180cbb2a86SJames Molloy Type *Ty = (MinBW > 32) ? Type::getInt64Ty(*Ctx) : Type::getInt32Ty(*Ctx);
4190cbb2a86SJames Molloy
4200cbb2a86SJames Molloy for (auto MI = ECs.member_begin(It), ME = ECs.member_end();
4210cbb2a86SJames Molloy MI != ME; ++MI)
4220cbb2a86SJames Molloy convert(*MI, Ty);
4230cbb2a86SJames Molloy MadeChange = true;
4240cbb2a86SJames Molloy }
4250cbb2a86SJames Molloy
4260cbb2a86SJames Molloy return MadeChange;
4270cbb2a86SJames Molloy }
4280cbb2a86SJames Molloy
convert(Instruction * I,Type * ToTy)42983b753d4SMichael Kuperstein Value *Float2IntPass::convert(Instruction *I, Type *ToTy) {
4300cbb2a86SJames Molloy if (ConvertedInsts.find(I) != ConvertedInsts.end())
4310cbb2a86SJames Molloy // Already converted this instruction.
4320cbb2a86SJames Molloy return ConvertedInsts[I];
4330cbb2a86SJames Molloy
4340cbb2a86SJames Molloy SmallVector<Value*,4> NewOperands;
4350cbb2a86SJames Molloy for (Value *V : I->operands()) {
4360cbb2a86SJames Molloy // Don't recurse if we're an instruction that terminates the path.
4370cbb2a86SJames Molloy if (I->getOpcode() == Instruction::UIToFP ||
4380cbb2a86SJames Molloy I->getOpcode() == Instruction::SIToFP) {
4390cbb2a86SJames Molloy NewOperands.push_back(V);
4400cbb2a86SJames Molloy } else if (Instruction *VI = dyn_cast<Instruction>(V)) {
4410cbb2a86SJames Molloy NewOperands.push_back(convert(VI, ToTy));
4420cbb2a86SJames Molloy } else if (ConstantFP *CF = dyn_cast<ConstantFP>(V)) {
44349a3ad21SRui Ueyama APSInt Val(ToTy->getPrimitiveSizeInBits(), /*isUnsigned=*/false);
4440cbb2a86SJames Molloy bool Exact;
4450cbb2a86SJames Molloy CF->getValueAPF().convertToInteger(Val,
4460cbb2a86SJames Molloy APFloat::rmNearestTiesToEven,
4470cbb2a86SJames Molloy &Exact);
4480cbb2a86SJames Molloy NewOperands.push_back(ConstantInt::get(ToTy, Val));
4490cbb2a86SJames Molloy } else {
4500cbb2a86SJames Molloy llvm_unreachable("Unhandled operand type?");
4510cbb2a86SJames Molloy }
4520cbb2a86SJames Molloy }
4530cbb2a86SJames Molloy
4540cbb2a86SJames Molloy // Now create a new instruction.
4550cbb2a86SJames Molloy IRBuilder<> IRB(I);
4560cbb2a86SJames Molloy Value *NewV = nullptr;
4570cbb2a86SJames Molloy switch (I->getOpcode()) {
4580cbb2a86SJames Molloy default: llvm_unreachable("Unhandled instruction!");
4590cbb2a86SJames Molloy
4600cbb2a86SJames Molloy case Instruction::FPToUI:
4610cbb2a86SJames Molloy NewV = IRB.CreateZExtOrTrunc(NewOperands[0], I->getType());
4620cbb2a86SJames Molloy break;
4630cbb2a86SJames Molloy
4640cbb2a86SJames Molloy case Instruction::FPToSI:
4650cbb2a86SJames Molloy NewV = IRB.CreateSExtOrTrunc(NewOperands[0], I->getType());
4660cbb2a86SJames Molloy break;
4670cbb2a86SJames Molloy
4680cbb2a86SJames Molloy case Instruction::FCmp: {
4690cbb2a86SJames Molloy CmpInst::Predicate P = mapFCmpPred(cast<CmpInst>(I)->getPredicate());
4700cbb2a86SJames Molloy assert(P != CmpInst::BAD_ICMP_PREDICATE && "Unhandled predicate!");
4710cbb2a86SJames Molloy NewV = IRB.CreateICmp(P, NewOperands[0], NewOperands[1], I->getName());
4720cbb2a86SJames Molloy break;
4730cbb2a86SJames Molloy }
4740cbb2a86SJames Molloy
4750cbb2a86SJames Molloy case Instruction::UIToFP:
4760cbb2a86SJames Molloy NewV = IRB.CreateZExtOrTrunc(NewOperands[0], ToTy);
4770cbb2a86SJames Molloy break;
4780cbb2a86SJames Molloy
4790cbb2a86SJames Molloy case Instruction::SIToFP:
4800cbb2a86SJames Molloy NewV = IRB.CreateSExtOrTrunc(NewOperands[0], ToTy);
4810cbb2a86SJames Molloy break;
4820cbb2a86SJames Molloy
483771769beSCameron McInally case Instruction::FNeg:
484771769beSCameron McInally NewV = IRB.CreateNeg(NewOperands[0], I->getName());
485771769beSCameron McInally break;
486771769beSCameron McInally
4870cbb2a86SJames Molloy case Instruction::FAdd:
4880cbb2a86SJames Molloy case Instruction::FSub:
4890cbb2a86SJames Molloy case Instruction::FMul:
4900cbb2a86SJames Molloy NewV = IRB.CreateBinOp(mapBinOpcode(I->getOpcode()),
4910cbb2a86SJames Molloy NewOperands[0], NewOperands[1],
4920cbb2a86SJames Molloy I->getName());
4930cbb2a86SJames Molloy break;
4940cbb2a86SJames Molloy }
4950cbb2a86SJames Molloy
4960cbb2a86SJames Molloy // If we're a root instruction, RAUW.
4970cbb2a86SJames Molloy if (Roots.count(I))
4980cbb2a86SJames Molloy I->replaceAllUsesWith(NewV);
4990cbb2a86SJames Molloy
5000cbb2a86SJames Molloy ConvertedInsts[I] = NewV;
5010cbb2a86SJames Molloy return NewV;
5020cbb2a86SJames Molloy }
5030cbb2a86SJames Molloy
5040cbb2a86SJames Molloy // Perform dead code elimination on the instructions we just modified.
cleanup()50583b753d4SMichael Kuperstein void Float2IntPass::cleanup() {
506d7708773SDavid Majnemer for (auto &I : reverse(ConvertedInsts))
5077679afdaSPete Cooper I.first->eraseFromParent();
5080cbb2a86SJames Molloy }
5090cbb2a86SJames Molloy
runImpl(Function & F,const DominatorTree & DT)51013e71ce6SSanjay Patel bool Float2IntPass::runImpl(Function &F, const DominatorTree &DT) {
511d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "F2I: Looking at function " << F.getName() << "\n");
5120cbb2a86SJames Molloy // Clear out all state.
5130cbb2a86SJames Molloy ECs = EquivalenceClasses<Instruction*>();
5140cbb2a86SJames Molloy SeenInsts.clear();
5150cbb2a86SJames Molloy ConvertedInsts.clear();
5160cbb2a86SJames Molloy Roots.clear();
5170cbb2a86SJames Molloy
5180cbb2a86SJames Molloy Ctx = &F.getParent()->getContext();
5190cbb2a86SJames Molloy
520fdf9bad5SBjorn Pettersson findRoots(F, DT);
5210cbb2a86SJames Molloy
522fdf9bad5SBjorn Pettersson walkBackwards();
5230cbb2a86SJames Molloy walkForwards();
5240cbb2a86SJames Molloy
5250cbb2a86SJames Molloy bool Modified = validateAndTransform();
5260cbb2a86SJames Molloy if (Modified)
5270cbb2a86SJames Molloy cleanup();
5280cbb2a86SJames Molloy return Modified;
5290cbb2a86SJames Molloy }
5300cbb2a86SJames Molloy
53183b753d4SMichael Kuperstein namespace llvm {
createFloat2IntPass()53283b753d4SMichael Kuperstein FunctionPass *createFloat2IntPass() { return new Float2IntLegacyPass(); }
53383b753d4SMichael Kuperstein
run(Function & F,FunctionAnalysisManager & AM)53413e71ce6SSanjay Patel PreservedAnalyses Float2IntPass::run(Function &F, FunctionAnalysisManager &AM) {
53513e71ce6SSanjay Patel const DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
53613e71ce6SSanjay Patel if (!runImpl(F, DT))
53783b753d4SMichael Kuperstein return PreservedAnalyses::all();
538ca68a3ecSChandler Carruth
53983b753d4SMichael Kuperstein PreservedAnalyses PA;
540ca68a3ecSChandler Carruth PA.preserveSet<CFGAnalyses>();
54183b753d4SMichael Kuperstein return PA;
54283b753d4SMichael Kuperstein }
54383b753d4SMichael Kuperstein } // End namespace llvm
544