//===- FloatingPointMode.cpp ------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/ADT/FloatingPointMode.h" #include "llvm/ADT/StringExtras.h" using namespace llvm; FPClassTest llvm::fneg(FPClassTest Mask) { FPClassTest NewMask = Mask & fcNan; if (Mask & fcNegInf) NewMask |= fcPosInf; if (Mask & fcNegNormal) NewMask |= fcPosNormal; if (Mask & fcNegSubnormal) NewMask |= fcPosSubnormal; if (Mask & fcNegZero) NewMask |= fcPosZero; if (Mask & fcPosZero) NewMask |= fcNegZero; if (Mask & fcPosSubnormal) NewMask |= fcNegSubnormal; if (Mask & fcPosNormal) NewMask |= fcNegNormal; if (Mask & fcPosInf) NewMask |= fcNegInf; return NewMask; } FPClassTest llvm::inverse_fabs(FPClassTest Mask) { FPClassTest NewMask = Mask & fcNan; if (Mask & fcPosZero) NewMask |= fcZero; if (Mask & fcPosSubnormal) NewMask |= fcSubnormal; if (Mask & fcPosNormal) NewMask |= fcNormal; if (Mask & fcPosInf) NewMask |= fcInf; return NewMask; } FPClassTest llvm::unknown_sign(FPClassTest Mask) { FPClassTest NewMask = Mask & fcNan; if (Mask & fcZero) NewMask |= fcZero; if (Mask & fcSubnormal) NewMask |= fcSubnormal; if (Mask & fcNormal) NewMask |= fcNormal; if (Mask & fcInf) NewMask |= fcInf; return NewMask; } // Every bitfield has a unique name and one or more aliasing names that cover // multiple bits. Names should be listed in order of preference, with higher // popcounts listed first. // // Bits are consumed as printed. Each field should only be represented in one // printed field. static constexpr std::pair NoFPClassName[] = { {fcAllFlags, "all"}, {fcNan, "nan"}, {fcSNan, "snan"}, {fcQNan, "qnan"}, {fcInf, "inf"}, {fcNegInf, "ninf"}, {fcPosInf, "pinf"}, {fcZero, "zero"}, {fcNegZero, "nzero"}, {fcPosZero, "pzero"}, {fcSubnormal, "sub"}, {fcNegSubnormal, "nsub"}, {fcPosSubnormal, "psub"}, {fcNormal, "norm"}, {fcNegNormal, "nnorm"}, {fcPosNormal, "pnorm"} }; raw_ostream &llvm::operator<<(raw_ostream &OS, FPClassTest Mask) { OS << '('; if (Mask == fcNone) { OS << "none)"; return OS; } ListSeparator LS(" "); for (auto [BitTest, Name] : NoFPClassName) { if ((Mask & BitTest) == BitTest) { OS << LS << Name; // Clear the bits so we don't print any aliased names later. Mask &= ~BitTest; } } assert(Mask == 0 && "didn't print some mask bits"); OS << ')'; return OS; } void DenormalFPEnv::print(raw_ostream &OS, bool OmitIfSame) const { if (F32Mode == DefaultMode) { DefaultMode.print(OS, /*Legacy=*/false, OmitIfSame); return; } // Omit printing the base mode if only the f32 mode isn't the default. if (DefaultMode != DenormalMode::getDefault()) { DefaultMode.print(OS, /*Legacy=*/false, OmitIfSame); OS << ", "; } OS << "float: "; F32Mode.print(OS, /*Legacy=*/false, OmitIfSame); } static bool cannotOrderStrictlyGreaterImpl(FPClassTest LHS, FPClassTest RHS, bool OrEqual, bool OrderedZero) { LHS &= ~fcNan; RHS &= ~fcNan; if (LHS == fcNone || RHS == fcNone) return true; FPClassTest LowestBitRHS = static_cast(RHS & -RHS); FPClassTest HighestBitLHS = static_cast(1 << Log2_32(LHS)); if (!OrderedZero) { // Introduce conflict in zero bits if we're treating them as equal. if (LowestBitRHS == fcNegZero) LowestBitRHS = fcPosZero; if (HighestBitLHS == fcNegZero) HighestBitLHS = fcPosZero; } if (LowestBitRHS > HighestBitLHS) { assert((LHS & RHS) == fcNone && "no bits should intersect"); return true; } if (LowestBitRHS < HighestBitLHS) return false; constexpr FPClassTest ExactValuesMask = fcZero | fcInf; return !OrEqual && (LowestBitRHS & ExactValuesMask) != fcNone; } bool llvm::cannotOrderStrictlyGreater(FPClassTest LHS, FPClassTest RHS, bool OrderedZeroSign) { return cannotOrderStrictlyGreaterImpl(LHS, RHS, false, OrderedZeroSign); } bool llvm::cannotOrderStrictlyGreaterEq(FPClassTest LHS, FPClassTest RHS, bool OrderedZeroSign) { return cannotOrderStrictlyGreaterImpl(LHS, RHS, true, OrderedZeroSign); } bool llvm::cannotOrderStrictlyLess(FPClassTest LHS, FPClassTest RHS, bool OrderedZeroSign) { return cannotOrderStrictlyGreaterImpl(RHS, LHS, false, OrderedZeroSign); } bool llvm::cannotOrderStrictlyLessEq(FPClassTest LHS, FPClassTest RHS, bool OrderedZeroSign) { return cannotOrderStrictlyGreaterImpl(RHS, LHS, true, OrderedZeroSign); } FPClassTest llvm::orderedStrictlyLess(FPClassTest Mask, bool OrderedZeroSign) { // Ignores NaN Mask &= ~fcNan; // Since the classes are ordered bits, we can get all classes which are // smaller than all classes in Known by setting all trailing 0 bits to 1, // and setting the other bits to 0. // This is done by counting the number of trailing 0 bits and creating a // mask based on that. // For example: 0b1111000000 = fcPositive // -> 0b0000111111 = fcNegative | fcNan FPClassTest NewMask = static_cast( maskTrailingOnes(countr_zero(Mask)) & fcAllFlags); // Remove NaNs NewMask &= ~fcNan; // We cannot conclude that only one zero is smaller // if the zeroes are not ordered if (!OrderedZeroSign && ((NewMask & fcZero) != fcZero)) NewMask &= ~fcZero; return NewMask; } FPClassTest llvm::orderedStrictlyGreater(FPClassTest Mask, bool OrderedZeroSign) { // Counting the number of leading 0 bits and create a mask based on that, // removing the leading 1s that are outside the bitfield: // For example: 0b0000111100 = fcNegative // -> 0b1111000000 = fcPositive FPClassTest NewMask = static_cast( maskLeadingOnes(countl_zero(Mask)) & fcAllFlags); // Remove NaNs NewMask &= ~fcNan; // We cannot conclude that only one zero is greater // if the zeroes are not ordered if (!OrderedZeroSign && ((NewMask & fcZero) != fcZero)) NewMask &= ~fcZero; return NewMask; }