Skip to content

Commit

Permalink
[libc] Add a str() method to FPBits which returns a string representa…
Browse files Browse the repository at this point in the history
…tion.

Unit tests for the str() method have also been added.

Previously, a separate test only helper function was being used by the
test matchers which has regressed over many cleanups. Moreover, being a
test only utility, it was not tested separately (and hence the
regression).

Reviewed By: michaelrj

Differential Revision: https://reviews.llvm.org/D150906
  • Loading branch information
Siva Chandra Reddy committed May 19, 2023
1 parent 9615d48 commit 00bd8e9
Show file tree
Hide file tree
Showing 7 changed files with 396 additions and 64 deletions.
2 changes: 2 additions & 0 deletions libc/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ add_header_library(
.platform_defs
.float_properties
libc.src.__support.builtin_wrappers
libc.src.__support.integer_to_string
libc.src.__support.CPP.bit
libc.src.__support.CPP.string
libc.src.__support.CPP.type_traits
libc.src.__support.common
)
Expand Down
43 changes: 43 additions & 0 deletions libc/src/__support/FPUtil/FPBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
#include "PlatformDefs.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/string.h"
#include "src/__support/CPP/type_traits.h"
#include "src/__support/builtin_wrappers.h"
#include "src/__support/common.h"
#include "src/__support/integer_to_string.h"

#include "FloatProperties.h"
#include <stdint.h>
Expand Down Expand Up @@ -213,6 +215,47 @@ template <typename T> struct FPBits {
result.set_mantissa(mantissa);
return result;
}

// Converts the bits to a string in the following format:
// "0x<NNN...N> = S: N, E: 0xNNNN, M:0xNNN...N"
// 1. N is a hexadecimal digit.
// 2. The hexadecimal number on the LHS is the raw numerical representation
// of the bits.
// 3. The exponent is always 16 bits wide irrespective of the type of the
// floating encoding.
LIBC_INLINE cpp::string str() const {
if (is_nan())
return "(NaN)";
if (is_inf())
return get_sign() ? "(-Infinity)" : "(+Infinity)";

auto zerofill = [](char *arr, size_t n) {
for (size_t i = 0; i < n; ++i)
arr[i] = '0';
};

cpp::string s("0x");
char bitsbuf[IntegerToString::hex_bufsize<UIntType>()];
zerofill(bitsbuf, sizeof(bitsbuf));
IntegerToString::hex(bits, bitsbuf, false);
s += cpp::string(bitsbuf, sizeof(bitsbuf));

s += " = (";
s += cpp::string("S: ") + (get_sign() ? "1" : "0");

char expbuf[IntegerToString::hex_bufsize<uint16_t>()];
zerofill(expbuf, sizeof(expbuf));
IntegerToString::hex(get_unbiased_exponent(), expbuf, false);
s += cpp::string(", E: 0x") + cpp::string(expbuf, sizeof(expbuf));

char mantbuf[IntegerToString::hex_bufsize<UIntType>()] = {'0'};
zerofill(mantbuf, sizeof(mantbuf));
IntegerToString::hex(get_mantissa(), mantbuf, false);
s += cpp::string(", M: 0x") + cpp::string(mantbuf, sizeof(mantbuf));

s += ")";
return s;
}
};

} // namespace fputil
Expand Down
46 changes: 46 additions & 0 deletions libc/src/__support/FPUtil/x86_64/LongDoubleBits.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@
#define LLVM_LIBC_SRC_SUPPORT_FPUTIL_X86_64_LONG_DOUBLE_BITS_H

#include "src/__support/CPP/bit.h"
#include "src/__support/CPP/string.h"
#include "src/__support/UInt128.h"
#include "src/__support/common.h"
#include "src/__support/integer_to_string.h"
#include "src/__support/macros/properties/architectures.h"

#if !defined(LIBC_TARGET_ARCH_IS_X86)
Expand Down Expand Up @@ -207,6 +209,50 @@ template <> struct FPBits<long double> {
result.set_mantissa(mantissa);
return result;
}

// Converts the bits to a string in the following format:
// "0x<NNN...N> = S: N, E: 0xNNNN, I: N, M:0xNNN...N"
// 1. N is a hexadecimal digit.
// 2. "I" denotes the implicit bit.
// 3. The hexadecimal number on the LHS is the raw numerical representation
// of the bits.
// 4. The exponent is always 16 bits wide irrespective of the type of the
// floating encoding.
LIBC_INLINE cpp::string str() const {
if (is_nan())
return "(NaN)";
if (is_inf())
return get_sign() ? "(-Infinity)" : "(+Infinity)";

auto zerofill = [](char *arr, size_t n) {
for (size_t i = 0; i < n; ++i)
arr[i] = '0';
};

cpp::string s("0x");
char bitsbuf[IntegerToString::hex_bufsize<UIntType>()] = {'0'};
zerofill(bitsbuf, sizeof(bitsbuf));
IntegerToString::hex(bits, bitsbuf, false);
s += cpp::string(bitsbuf, sizeof(bitsbuf));

s += " = (";
s += cpp::string("S: ") + (get_sign() ? "1" : "0");

char expbuf[IntegerToString::hex_bufsize<uint16_t>()] = {'0'};
zerofill(expbuf, sizeof(expbuf));
IntegerToString::hex(get_unbiased_exponent(), expbuf, false);
s += cpp::string(", E: 0x") + cpp::string(expbuf, sizeof(expbuf));

s += cpp::string(", I: ") + (get_implicit_bit() ? "1" : "0");

char mantbuf[IntegerToString::hex_bufsize<UIntType>()] = {'0'};
zerofill(mantbuf, sizeof(mantbuf));
IntegerToString::hex(get_mantissa(), mantbuf, false);
s += cpp::string(", M: 0x") + cpp::string(mantbuf, sizeof(mantbuf));

s += ")";
return s;
}
};

static_assert(
Expand Down
44 changes: 5 additions & 39 deletions libc/test/UnitTest/FPMatcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,43 +21,6 @@ namespace __llvm_libc {
namespace fputil {
namespace testing {

template <typename ValType>
cpp::enable_if_t<cpp::is_floating_point_v<ValType>, void>
describeValue(const char *label, ValType value) {
__llvm_libc::testing::tlog << label;

FPBits<ValType> bits(value);
if (bits.is_nan()) {
__llvm_libc::testing::tlog << "(NaN)";
} else if (bits.is_inf()) {
if (bits.get_sign())
__llvm_libc::testing::tlog << "(-Infinity)";
else
__llvm_libc::testing::tlog << "(+Infinity)";
} else {
constexpr int exponentWidthInHex =
(fputil::ExponentWidth<ValType>::VALUE - 1) / 4 + 1;
constexpr int mantissaWidthInHex =
(fputil::MantissaWidth<ValType>::VALUE - 1) / 4 + 1;
constexpr int bitsWidthInHex =
sizeof(typename fputil::FPBits<ValType>::UIntType) * 2;

__llvm_libc::testing::tlog
<< "0x"
<< int_to_hex<typename fputil::FPBits<ValType>::UIntType>(
bits.uintval(), bitsWidthInHex)
<< ", (S | E | M) = (" << (bits.get_sign() ? '1' : '0') << " | 0x"
<< int_to_hex<uint16_t>(bits.get_unbiased_exponent(),
exponentWidthInHex)
<< " | 0x"
<< int_to_hex<typename fputil::FPBits<ValType>::UIntType>(
bits.get_mantissa(), mantissaWidthInHex)
<< ")";
}

__llvm_libc::testing::tlog << '\n';
}

template <typename T, __llvm_libc::testing::TestCondition Condition>
class FPMatcher : public __llvm_libc::testing::Matcher<T> {
static_assert(__llvm_libc::cpp::is_floating_point_v<T>,
Expand Down Expand Up @@ -87,8 +50,11 @@ class FPMatcher : public __llvm_libc::testing::Matcher<T> {
}

void explainError() override {
describeValue("Expected floating point value: ", expected);
describeValue(" Actual floating point value: ", actual);
__llvm_libc::testing::tlog
<< "Expected floating point value: " << FPBits<T>(expected).str()
<< '\n';
__llvm_libc::testing::tlog
<< "Actual floating point value: " << FPBits<T>(actual).str() << '\n';
}
};

Expand Down
10 changes: 10 additions & 0 deletions libc/test/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,13 @@ add_fp_unittest(
DEPENDS
libc.src.__support.FPUtil.dyadic_float
)

add_libc_test(
fpbits_test
SUITE
libc-fputil-tests
SRCS
fpbits_test.cpp
DEPENDS
libc.src.__support.FPUtil.fp_bits
)
Loading

0 comments on commit 00bd8e9

Please sign in to comment.