From f66975555fec57e55f3d72d06d8bc83472cd2c1e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 31 Mar 2022 16:06:46 +0200 Subject: [PATCH] [Float2Int] Extract calcRange() method (NFC) This avoids the awkward "Abort" flag, because we can simply early-return instead. --- llvm/include/llvm/Transforms/Scalar/Float2Int.h | 1 + llvm/lib/Transforms/Scalar/Float2Int.cpp | 200 ++++++++++++------------ 2 files changed, 100 insertions(+), 101 deletions(-) diff --git a/llvm/include/llvm/Transforms/Scalar/Float2Int.h b/llvm/include/llvm/Transforms/Scalar/Float2Int.h index d53c1f4..9def40e 100644 --- a/llvm/include/llvm/Transforms/Scalar/Float2Int.h +++ b/llvm/include/llvm/Transforms/Scalar/Float2Int.h @@ -41,6 +41,7 @@ private: ConstantRange badRange(); ConstantRange unknownRange(); ConstantRange validateRange(ConstantRange R); + ConstantRange calcRange(Instruction *I); void walkBackwards(); void walkForwards(); bool validateAndTransform(); diff --git a/llvm/lib/Transforms/Scalar/Float2Int.cpp b/llvm/lib/Transforms/Scalar/Float2Int.cpp index 4b6ff27..bf87311 100644 --- a/llvm/lib/Transforms/Scalar/Float2Int.cpp +++ b/llvm/lib/Transforms/Scalar/Float2Int.cpp @@ -235,116 +235,114 @@ void Float2IntPass::walkBackwards() { } } -// Walk forwards down the list of seen instructions, so we visit defs before -// uses. -void Float2IntPass::walkForwards() { - for (auto &It : reverse(SeenInsts)) { - if (It.second != unknownRange()) - continue; +// Calculate result range from operand ranges +ConstantRange Float2IntPass::calcRange(Instruction *I) { + std::function)> Op; + switch (I->getOpcode()) { + // FIXME: Handle select and phi nodes. + default: + case Instruction::UIToFP: + case Instruction::SIToFP: + llvm_unreachable("Should have been handled in walkForwards!"); - Instruction *I = It.first; - std::function)> Op; - switch (I->getOpcode()) { - // FIXME: Handle select and phi nodes. - default: - case Instruction::UIToFP: - case Instruction::SIToFP: - llvm_unreachable("Should have been handled in walkForwards!"); + case Instruction::FNeg: + Op = [](ArrayRef Ops) { + assert(Ops.size() == 1 && "FNeg is a unary operator!"); + unsigned Size = Ops[0].getBitWidth(); + auto Zero = ConstantRange(APInt::getZero(Size)); + return Zero.sub(Ops[0]); + }; + break; - case Instruction::FNeg: - Op = [](ArrayRef Ops) { - assert(Ops.size() == 1 && "FNeg is a unary operator!"); - unsigned Size = Ops[0].getBitWidth(); - auto Zero = ConstantRange(APInt::getZero(Size)); - return Zero.sub(Ops[0]); - }; - break; + case Instruction::FAdd: + case Instruction::FSub: + case Instruction::FMul: + Op = [I](ArrayRef Ops) { + assert(Ops.size() == 2 && "its a binary operator!"); + auto BinOp = (Instruction::BinaryOps) I->getOpcode(); + return Ops[0].binaryOp(BinOp, Ops[1]); + }; + break; - case Instruction::FAdd: - case Instruction::FSub: - case Instruction::FMul: - Op = [I](ArrayRef Ops) { - assert(Ops.size() == 2 && "its a binary operator!"); - auto BinOp = (Instruction::BinaryOps) I->getOpcode(); - return Ops[0].binaryOp(BinOp, Ops[1]); - }; - break; + // + // Root-only instructions - we'll only see these if they're the + // first node in a walk. + // + case Instruction::FPToUI: + case Instruction::FPToSI: + Op = [I](ArrayRef Ops) { + assert(Ops.size() == 1 && "FPTo[US]I is a unary operator!"); + // Note: We're ignoring the casts output size here as that's what the + // caller expects. + auto CastOp = (Instruction::CastOps)I->getOpcode(); + return Ops[0].castOp(CastOp, MaxIntegerBW+1); + }; + break; - // - // Root-only instructions - we'll only see these if they're the - // first node in a walk. - // - case Instruction::FPToUI: - case Instruction::FPToSI: - Op = [I](ArrayRef Ops) { - assert(Ops.size() == 1 && "FPTo[US]I is a unary operator!"); - // Note: We're ignoring the casts output size here as that's what the - // caller expects. - auto CastOp = (Instruction::CastOps)I->getOpcode(); - return Ops[0].castOp(CastOp, MaxIntegerBW+1); - }; - break; + case Instruction::FCmp: + Op = [](ArrayRef Ops) { + assert(Ops.size() == 2 && "FCmp is a binary operator!"); + return Ops[0].unionWith(Ops[1]); + }; + break; + } - case Instruction::FCmp: - Op = [](ArrayRef Ops) { - assert(Ops.size() == 2 && "FCmp is a binary operator!"); - return Ops[0].unionWith(Ops[1]); - }; - break; + SmallVector OpRanges; + for (Value *O : I->operands()) { + if (Instruction *OI = dyn_cast(O)) { + assert(SeenInsts.find(OI) != SeenInsts.end() && + "def not seen before use!"); + OpRanges.push_back(SeenInsts.find(OI)->second); + } else if (ConstantFP *CF = dyn_cast(O)) { + // Work out if the floating point number can be losslessly represented + // as an integer. + // APFloat::convertToInteger(&Exact) purports to do what we want, but + // the exactness can be too precise. For example, negative zero can + // never be exactly converted to an integer. + // + // Instead, we ask APFloat to round itself to an integral value - this + // preserves sign-of-zero - then compare the result with the original. + // + const APFloat &F = CF->getValueAPF(); + + // First, weed out obviously incorrect values. Non-finite numbers + // can't be represented and neither can negative zero, unless + // we're in fast math mode. + if (!F.isFinite() || + (F.isZero() && F.isNegative() && isa(I) && + !I->hasNoSignedZeros())) + return badRange(); + + APFloat NewF = F; + auto Res = NewF.roundToIntegral(APFloat::rmNearestTiesToEven); + if (Res != APFloat::opOK || NewF != F) + return badRange(); + + // OK, it's representable. Now get it. + APSInt Int(MaxIntegerBW+1, false); + bool Exact; + CF->getValueAPF().convertToInteger(Int, + APFloat::rmNearestTiesToEven, + &Exact); + OpRanges.push_back(ConstantRange(Int)); + } else { + llvm_unreachable("Should have already marked this as badRange!"); } + } - bool Abort = false; - SmallVector OpRanges; - for (Value *O : I->operands()) { - if (Instruction *OI = dyn_cast(O)) { - assert(SeenInsts.find(OI) != SeenInsts.end() && - "def not seen before use!"); - OpRanges.push_back(SeenInsts.find(OI)->second); - } else if (ConstantFP *CF = dyn_cast(O)) { - // Work out if the floating point number can be losslessly represented - // as an integer. - // APFloat::convertToInteger(&Exact) purports to do what we want, but - // the exactness can be too precise. For example, negative zero can - // never be exactly converted to an integer. - // - // Instead, we ask APFloat to round itself to an integral value - this - // preserves sign-of-zero - then compare the result with the original. - // - const APFloat &F = CF->getValueAPF(); - - // First, weed out obviously incorrect values. Non-finite numbers - // can't be represented and neither can negative zero, unless - // we're in fast math mode. - if (!F.isFinite() || - (F.isZero() && F.isNegative() && isa(I) && - !I->hasNoSignedZeros())) { - seen(I, badRange()); - Abort = true; - break; - } + // Reduce the operands' ranges to a single range. + return Op(OpRanges); +} - APFloat NewF = F; - auto Res = NewF.roundToIntegral(APFloat::rmNearestTiesToEven); - if (Res != APFloat::opOK || NewF != F) { - seen(I, badRange()); - Abort = true; - break; - } - // OK, it's representable. Now get it. - APSInt Int(MaxIntegerBW+1, false); - bool Exact; - CF->getValueAPF().convertToInteger(Int, - APFloat::rmNearestTiesToEven, - &Exact); - OpRanges.push_back(ConstantRange(Int)); - } else { - llvm_unreachable("Should have already marked this as badRange!"); - } - } +// Walk forwards down the list of seen instructions, so we visit defs before +// uses. +void Float2IntPass::walkForwards() { + for (auto &It : reverse(SeenInsts)) { + if (It.second != unknownRange()) + continue; - // Reduce the operands' ranges to a single range and return. - if (!Abort) - seen(I, Op(OpRanges)); + Instruction *I = It.first; + seen(I, calcRange(I)); } } -- 2.7.4