//===- llvm/Support/ScaledNumber.h - Support for scaled numbers -*- 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 // //===----------------------------------------------------------------------===// // // This file contains functions (and a class) useful for working with scaled // numbers -- in particular, pairs of integers where one represents digits and // another represents a scale. The functions are helpers and live in the // namespace ScaledNumbers. The class ScaledNumber is useful for modelling // certain cost metrics that need simple, integer-like semantics that are easy // to reason about. // // These might remind you of soft-floats. If you want one of those, you're in // the wrong place. Look at include/llvm/ADT/APFloat.h instead. // //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_SCALEDNUMBER_H #define LLVM_SUPPORT_SCALEDNUMBER_H #include "llvm/Support/MathExtras.h" #include <algorithm> #include <cstdint> #include <limits> #include <string> #include <tuple> #include <utility> namespace llvm { namespace ScaledNumbers { /// Maximum scale; same as APFloat for easy debug printing. const int32_t MaxScale = …; /// Maximum scale; same as APFloat for easy debug printing. const int32_t MinScale = …; /// Get the width of a number. template <class DigitsT> inline int getWidth() { … } /// Conditionally round up a scaled number. /// /// Given \c Digits and \c Scale, round up iff \c ShouldRound is \c true. /// Always returns \c Scale unless there's an overflow, in which case it /// returns \c 1+Scale. /// /// \pre adding 1 to \c Scale will not overflow INT16_MAX. template <class DigitsT> inline std::pair<DigitsT, int16_t> getRounded(DigitsT Digits, int16_t Scale, bool ShouldRound) { … } /// Convenience helper for 32-bit rounding. inline std::pair<uint32_t, int16_t> getRounded32(uint32_t Digits, int16_t Scale, bool ShouldRound) { … } /// Convenience helper for 64-bit rounding. inline std::pair<uint64_t, int16_t> getRounded64(uint64_t Digits, int16_t Scale, bool ShouldRound) { … } /// Adjust a 64-bit scaled number down to the appropriate width. /// /// \pre Adding 64 to \c Scale will not overflow INT16_MAX. template <class DigitsT> inline std::pair<DigitsT, int16_t> getAdjusted(uint64_t Digits, int16_t Scale = 0) { … } /// Convenience helper for adjusting to 32 bits. inline std::pair<uint32_t, int16_t> getAdjusted32(uint64_t Digits, int16_t Scale = 0) { … } /// Convenience helper for adjusting to 64 bits. inline std::pair<uint64_t, int16_t> getAdjusted64(uint64_t Digits, int16_t Scale = 0) { … } /// Multiply two 64-bit integers to create a 64-bit scaled number. /// /// Implemented with four 64-bit integer multiplies. std::pair<uint64_t, int16_t> multiply64(uint64_t LHS, uint64_t RHS); /// Multiply two 32-bit integers to create a 32-bit scaled number. /// /// Implemented with one 64-bit integer multiply. template <class DigitsT> inline std::pair<DigitsT, int16_t> getProduct(DigitsT LHS, DigitsT RHS) { … } /// Convenience helper for 32-bit product. inline std::pair<uint32_t, int16_t> getProduct32(uint32_t LHS, uint32_t RHS) { … } /// Convenience helper for 64-bit product. inline std::pair<uint64_t, int16_t> getProduct64(uint64_t LHS, uint64_t RHS) { … } /// Divide two 64-bit integers to create a 64-bit scaled number. /// /// Implemented with long division. /// /// \pre \c Dividend and \c Divisor are non-zero. std::pair<uint64_t, int16_t> divide64(uint64_t Dividend, uint64_t Divisor); /// Divide two 32-bit integers to create a 32-bit scaled number. /// /// Implemented with one 64-bit integer divide/remainder pair. /// /// \pre \c Dividend and \c Divisor are non-zero. std::pair<uint32_t, int16_t> divide32(uint32_t Dividend, uint32_t Divisor); /// Divide two 32-bit numbers to create a 32-bit scaled number. /// /// Implemented with one 64-bit integer divide/remainder pair. /// /// Returns \c (DigitsT_MAX, MaxScale) for divide-by-zero (0 for 0/0). template <class DigitsT> std::pair<DigitsT, int16_t> getQuotient(DigitsT Dividend, DigitsT Divisor) { … } /// Convenience helper for 32-bit quotient. inline std::pair<uint32_t, int16_t> getQuotient32(uint32_t Dividend, uint32_t Divisor) { … } /// Convenience helper for 64-bit quotient. inline std::pair<uint64_t, int16_t> getQuotient64(uint64_t Dividend, uint64_t Divisor) { … } /// Implementation of getLg() and friends. /// /// Returns the rounded lg of \c Digits*2^Scale and an int specifying whether /// this was rounded up (1), down (-1), or exact (0). /// /// Returns \c INT32_MIN when \c Digits is zero. template <class DigitsT> inline std::pair<int32_t, int> getLgImpl(DigitsT Digits, int16_t Scale) { … } /// Get the lg (rounded) of a scaled number. /// /// Get the lg of \c Digits*2^Scale. /// /// Returns \c INT32_MIN when \c Digits is zero. template <class DigitsT> int32_t getLg(DigitsT Digits, int16_t Scale) { … } /// Get the lg floor of a scaled number. /// /// Get the floor of the lg of \c Digits*2^Scale. /// /// Returns \c INT32_MIN when \c Digits is zero. template <class DigitsT> int32_t getLgFloor(DigitsT Digits, int16_t Scale) { … } /// Get the lg ceiling of a scaled number. /// /// Get the ceiling of the lg of \c Digits*2^Scale. /// /// Returns \c INT32_MIN when \c Digits is zero. template <class DigitsT> int32_t getLgCeiling(DigitsT Digits, int16_t Scale) { … } /// Implementation for comparing scaled numbers. /// /// Compare two 64-bit numbers with different scales. Given that the scale of /// \c L is higher than that of \c R by \c ScaleDiff, compare them. Return -1, /// 1, and 0 for less than, greater than, and equal, respectively. /// /// \pre 0 <= ScaleDiff < 64. int compareImpl(uint64_t L, uint64_t R, int ScaleDiff); /// Compare two scaled numbers. /// /// Compare two scaled numbers. Returns 0 for equal, -1 for less than, and 1 /// for greater than. template <class DigitsT> int compare(DigitsT LDigits, int16_t LScale, DigitsT RDigits, int16_t RScale) { … } /// Match scales of two numbers. /// /// Given two scaled numbers, match up their scales. Change the digits and /// scales in place. Shift the digits as necessary to form equivalent numbers, /// losing precision only when necessary. /// /// If the output value of \c LDigits (\c RDigits) is \c 0, the output value of /// \c LScale (\c RScale) is unspecified. /// /// As a convenience, returns the matching scale. If the output value of one /// number is zero, returns the scale of the other. If both are zero, which /// scale is returned is unspecified. template <class DigitsT> int16_t matchScales(DigitsT &LDigits, int16_t &LScale, DigitsT &RDigits, int16_t &RScale) { … } /// Get the sum of two scaled numbers. /// /// Get the sum of two scaled numbers with as much precision as possible. /// /// \pre Adding 1 to \c LScale (or \c RScale) will not overflow INT16_MAX. template <class DigitsT> std::pair<DigitsT, int16_t> getSum(DigitsT LDigits, int16_t LScale, DigitsT RDigits, int16_t RScale) { … } /// Convenience helper for 32-bit sum. inline std::pair<uint32_t, int16_t> getSum32(uint32_t LDigits, int16_t LScale, uint32_t RDigits, int16_t RScale) { … } /// Convenience helper for 64-bit sum. inline std::pair<uint64_t, int16_t> getSum64(uint64_t LDigits, int16_t LScale, uint64_t RDigits, int16_t RScale) { … } /// Get the difference of two scaled numbers. /// /// Get LHS minus RHS with as much precision as possible. /// /// Returns \c (0, 0) if the RHS is larger than the LHS. template <class DigitsT> std::pair<DigitsT, int16_t> getDifference(DigitsT LDigits, int16_t LScale, DigitsT RDigits, int16_t RScale) { … } /// Convenience helper for 32-bit difference. inline std::pair<uint32_t, int16_t> getDifference32(uint32_t LDigits, int16_t LScale, uint32_t RDigits, int16_t RScale) { … } /// Convenience helper for 64-bit difference. inline std::pair<uint64_t, int16_t> getDifference64(uint64_t LDigits, int16_t LScale, uint64_t RDigits, int16_t RScale) { … } } // end namespace ScaledNumbers } // end namespace llvm llvm // end namespace llvm #endif // LLVM_SUPPORT_SCALEDNUMBER_H