diff --git a/libc/src/__support/FPUtil/FPBits.h b/libc/src/__support/FPUtil/FPBits.h index ce4925bae125..7028fd4f3895 100644 --- a/libc/src/__support/FPUtil/FPBits.h +++ b/libc/src/__support/FPUtil/FPBits.h @@ -798,7 +798,9 @@ template LIBC_INLINE static constexpr FPType get_fp_type() { return FPType::IEEE754_Binary64; else if constexpr (LDBL_MANT_DIG == 64) return FPType::X86_Binary80; - else if constexpr (LDBL_MANT_DIG == 113) + // TODO: properly treat double-double type. + // else if constexpr (LDBL_MANT_DIG == 113) + else return FPType::IEEE754_Binary128; } #if defined(LIBC_TYPES_HAS_FLOAT16) diff --git a/libc/src/__support/RPC/rpc_server.h b/libc/src/__support/RPC/rpc_server.h index 3dfd79c6ecd0..316e275f3cf6 100644 --- a/libc/src/__support/RPC/rpc_server.h +++ b/libc/src/__support/RPC/rpc_server.h @@ -43,8 +43,10 @@ #define LIBC_COPT_PRINTF_DISABLE_WIDE #endif +// TODO: Make printf and our internal tools able to force the long double types +// properly. // The 'long double' type is 8 bytes. -#define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64 +// #define LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64 #include "shared/rpc.h" #include "shared/rpc_opcodes.h" @@ -226,7 +228,7 @@ LIBC_INLINE static void handle_printf(rpc::Server::Port &port, writer.write(cur_section.raw_string); } } - buffer_size[lane] = writer.get_chars_written(); + buffer_size[lane] = static_cast(writer.get_chars_written()); } // Receive any strings from the client and push them into a buffer. diff --git a/libc/src/__support/float_to_string.h b/libc/src/__support/float_to_string.h index 44853059a8da..683fb75aeda3 100644 --- a/libc/src/__support/float_to_string.h +++ b/libc/src/__support/float_to_string.h @@ -606,6 +606,7 @@ public: }; #if !defined(LIBC_TYPES_LONG_DOUBLE_IS_FLOAT64) && \ + !defined(LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE) && \ !defined(LIBC_COPT_FLOAT_TO_STR_NO_SPECIALIZE_LD) // --------------------------- LONG DOUBLE FUNCTIONS --------------------------- diff --git a/libc/src/stdio/printf_core/float_dec_converter.h b/libc/src/stdio/printf_core/float_dec_converter.h index ed004f9a26a1..509b4e24ada3 100644 --- a/libc/src/stdio/printf_core/float_dec_converter.h +++ b/libc/src/stdio/printf_core/float_dec_converter.h @@ -29,7 +29,11 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { +#ifdef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE +using StorageType = UInt128; +#else using StorageType = fputil::FPBits::StorageType; +#endif // LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE using DecimalString = IntegerToString; using ExponentString = IntegerToString::WithSign>; @@ -243,7 +247,9 @@ template class FloatWriter { // -exponent will never overflow because all long double types we support // have at most 15 bits of mantissa and the C standard defines an int as // being at least 16 bits. +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE static_assert(fputil::FPBits::EXP_LEN < (sizeof(int) * 8)); +#endif // LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE public: LIBC_INLINE FloatWriter(Writer *init_writer, @@ -1127,6 +1133,7 @@ LIBC_INLINE int convert_float_dec_auto_typed(Writer *writer, template LIBC_INLINE int convert_float_decimal(Writer *writer, const FormatSection &to_conv) { +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE if (to_conv.length_modifier == LengthModifier::L) { fputil::FPBits::StorageType float_raw = to_conv.conv_val_raw; fputil::FPBits float_bits(float_raw); @@ -1134,7 +1141,9 @@ LIBC_INLINE int convert_float_decimal(Writer *writer, return convert_float_decimal_typed(writer, to_conv, float_bits); } - } else { + } else +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + { fputil::FPBits::StorageType float_raw = static_cast::StorageType>(to_conv.conv_val_raw); fputil::FPBits float_bits(float_raw); @@ -1149,6 +1158,7 @@ LIBC_INLINE int convert_float_decimal(Writer *writer, template LIBC_INLINE int convert_float_dec_exp(Writer *writer, const FormatSection &to_conv) { +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE if (to_conv.length_modifier == LengthModifier::L) { fputil::FPBits::StorageType float_raw = to_conv.conv_val_raw; fputil::FPBits float_bits(float_raw); @@ -1156,7 +1166,9 @@ LIBC_INLINE int convert_float_dec_exp(Writer *writer, return convert_float_dec_exp_typed(writer, to_conv, float_bits); } - } else { + } else +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + { fputil::FPBits::StorageType float_raw = static_cast::StorageType>(to_conv.conv_val_raw); fputil::FPBits float_bits(float_raw); @@ -1171,6 +1183,7 @@ LIBC_INLINE int convert_float_dec_exp(Writer *writer, template LIBC_INLINE int convert_float_dec_auto(Writer *writer, const FormatSection &to_conv) { +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE if (to_conv.length_modifier == LengthModifier::L) { fputil::FPBits::StorageType float_raw = to_conv.conv_val_raw; fputil::FPBits float_bits(float_raw); @@ -1178,7 +1191,9 @@ LIBC_INLINE int convert_float_dec_auto(Writer *writer, return convert_float_dec_auto_typed(writer, to_conv, float_bits); } - } else { + } else +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + { fputil::FPBits::StorageType float_raw = static_cast::StorageType>(to_conv.conv_val_raw); fputil::FPBits float_bits(float_raw); diff --git a/libc/src/stdio/printf_core/float_dec_converter_limited.h b/libc/src/stdio/printf_core/float_dec_converter_limited.h index 0f85d0a8d26b..6b0e37b987e9 100644 --- a/libc/src/stdio/printf_core/float_dec_converter_limited.h +++ b/libc/src/stdio/printf_core/float_dec_converter_limited.h @@ -59,7 +59,11 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { enum class ConversionType { E, F, G }; +#ifdef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE +using StorageType = UInt128; +#else using StorageType = fputil::FPBits::StorageType; +#endif // LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE constexpr unsigned MAX_DIGITS = 39; constexpr size_t DF_BITS = 320; @@ -633,14 +637,17 @@ template LIBC_INLINE int convert_float_outer(Writer *writer, const FormatSection &to_conv, ConversionType ctype) { +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE if (to_conv.length_modifier == LengthModifier::L) { - fputil::FPBits::StorageType float_raw = to_conv.conv_val_raw; + StorageType float_raw = to_conv.conv_val_raw; fputil::FPBits float_bits(float_raw); if (!float_bits.is_inf_or_nan()) { return convert_float_typed(writer, to_conv, float_bits, ctype); } - } else { + } else +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + { fputil::FPBits::StorageType float_raw = static_cast::StorageType>(to_conv.conv_val_raw); fputil::FPBits float_bits(float_raw); diff --git a/libc/src/stdio/printf_core/float_hex_converter.h b/libc/src/stdio/printf_core/float_hex_converter.h index 9b57f1d803e7..5c6899156ccb 100644 --- a/libc/src/stdio/printf_core/float_hex_converter.h +++ b/libc/src/stdio/printf_core/float_hex_converter.h @@ -28,14 +28,21 @@ namespace printf_core { template LIBC_INLINE int convert_float_hex_exp(Writer *writer, const FormatSection &to_conv) { +#ifdef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + using LDBits = fputil::FPBits; + using StorageType = LDBits::StorageType; +#else using LDBits = fputil::FPBits; using StorageType = LDBits::StorageType; +#endif // LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE bool is_negative; int exponent; StorageType mantissa; bool is_inf_or_nan; uint32_t fraction_bits; + +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE if (to_conv.length_modifier == LengthModifier::L) { fraction_bits = LDBits::FRACTION_LEN; LDBits::StorageType float_raw = to_conv.conv_val_raw; @@ -44,7 +51,9 @@ LIBC_INLINE int convert_float_hex_exp(Writer *writer, exponent = float_bits.get_explicit_exponent(); mantissa = float_bits.get_explicit_mantissa(); is_inf_or_nan = float_bits.is_inf_or_nan(); - } else { + } else +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + { using LBits = fputil::FPBits; fraction_bits = LBits::FRACTION_LEN; LBits::StorageType float_raw = diff --git a/libc/src/stdio/printf_core/float_inf_nan_converter.h b/libc/src/stdio/printf_core/float_inf_nan_converter.h index ce31d7ae5549..379b7c6d3dcd 100644 --- a/libc/src/stdio/printf_core/float_inf_nan_converter.h +++ b/libc/src/stdio/printf_core/float_inf_nan_converter.h @@ -22,7 +22,11 @@ namespace LIBC_NAMESPACE_DECL { namespace printf_core { +#ifdef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE +using StorageType = UInt128; +#else using StorageType = fputil::FPBits::StorageType; +#endif // LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE template LIBC_INLINE int convert_inf_nan(Writer *writer, @@ -31,12 +35,15 @@ LIBC_INLINE int convert_inf_nan(Writer *writer, // the appropriate case based on the case of the conversion. bool is_negative; StorageType mantissa; +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE if (to_conv.length_modifier == LengthModifier::L) { fputil::FPBits::StorageType float_raw = to_conv.conv_val_raw; fputil::FPBits float_bits(float_raw); is_negative = float_bits.is_neg(); mantissa = float_bits.get_mantissa(); - } else { + } else +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE + { fputil::FPBits::StorageType float_raw = static_cast::StorageType>(to_conv.conv_val_raw); fputil::FPBits float_bits(float_raw); diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h index 7f9dd7ae627a..ed2425049151 100644 --- a/libc/src/stdio/printf_core/parser.h +++ b/libc/src/stdio/printf_core/parser.h @@ -15,6 +15,7 @@ #include "src/__support/CPP/optional.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/macros/config.h" +#include "src/__support/macros/properties/types.h" #include "src/__support/str_to_integer.h" #include "src/stdio/printf_core/core_structs.h" #include "src/stdio/printf_core/printf_config.h" @@ -40,9 +41,11 @@ template struct int_type_of { template <> struct int_type_of { using type = fputil::FPBits::StorageType; }; +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE template <> struct int_type_of { using type = fputil::FPBits::StorageType; }; +#endif // LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT template @@ -254,7 +257,9 @@ public: if (lm != LengthModifier::L) { WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, double, conv_index); } else { +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, long double, conv_index); +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE } break; #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT @@ -493,8 +498,10 @@ private: // Floating point numbers are stored separately from the other arguments. else if (cur_type_desc == type_desc_from_type()) args_cur.template next_var(); +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE else if (cur_type_desc == type_desc_from_type()) args_cur.template next_var(); +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT // Floating point numbers may be stored separately from the other @@ -660,8 +667,10 @@ private: case ('G'): if (lm != LengthModifier::L) conv_size = type_desc_from_type(); +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE else conv_size = type_desc_from_type(); +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE break; #endif // LIBC_COPT_PRINTF_DISABLE_FLOAT #ifdef LIBC_INTERNAL_PRINTF_HAS_FIXED_POINT diff --git a/libc/src/stdio/scanf_core/converter_utils.h b/libc/src/stdio/scanf_core/converter_utils.h index 6f4d16cffb19..979d180b01a6 100644 --- a/libc/src/stdio/scanf_core/converter_utils.h +++ b/libc/src/stdio/scanf_core/converter_utils.h @@ -83,11 +83,13 @@ LIBC_INLINE void write_float_with_length(char *str, *reinterpret_cast(output_ptr) = value; break; } +#ifndef LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE case (LengthModifier::L): { auto value = internal::strtofloatingpoint(str); *reinterpret_cast(output_ptr) = value; break; } +#endif // !LIBC_TYPES_LONG_DOUBLE_IS_DOUBLE_DOUBLE default: { auto value = internal::strtofloatingpoint(str); *reinterpret_cast(output_ptr) = value; diff --git a/libc/test/shared/CMakeLists.txt b/libc/test/shared/CMakeLists.txt index 8710b0513d23..1b5c44b74e83 100644 --- a/libc/test/shared/CMakeLists.txt +++ b/libc/test/shared/CMakeLists.txt @@ -276,3 +276,29 @@ add_fp_unittest( libc.src.__support.math.ceill libc.src.__support.math.log ) + +add_fp_unittest( + shared_str_to_num_test + SUITE + libc-shared-tests + SRCS + shared_str_to_num_test.cpp + DEPENDS + libc.src.__support.str_to_float + libc.src.__support.str_to_integer +) + +if(NOT MSVC AND NOT LLVM_LIBC_FULL_BUILD) +add_fp_unittest( + shared_rpc_test + SUITE + libc-shared-tests + SRCS + shared_rpc_test.cpp + DEPENDS + libc.src.stdio.printf_core.converter + libc.src.stdio.printf_core.parser + libc.src.stdio.printf_core.writer + libc.src.__support.arg_list +) +endif() diff --git a/libc/test/shared/shared_rpc_test.cpp b/libc/test/shared/shared_rpc_test.cpp new file mode 100644 index 000000000000..69861dd10260 --- /dev/null +++ b/libc/test/shared/shared_rpc_test.cpp @@ -0,0 +1,69 @@ +//===-- Unittests for shared RPC server -----------------------------------===// +// +// 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 "shared/rpc.h" +#include "shared/rpc_server.h" +#include "test/UnitTest/Test.h" + +TEST(LlvmLibcSharedRpcTest, TestIncrement) { + constexpr uint32_t port_count = 8; + constexpr uint32_t lane_size = 4; + alignas(64) + uint8_t buffer[::rpc::Server::allocation_size(lane_size, port_count)] = { + 0}; + + using ProcAType = ::rpc::Process; + using ProcBType = ::rpc::Process; + + ProcAType ProcA(port_count, buffer); + ProcBType ProcB(port_count, buffer); + + uint32_t index = 0; // any < port_count + uint64_t lane_mask = 1; + + // Each process has its own local lock for index + EXPECT_TRUE(ProcA.try_lock(lane_mask, index)); + EXPECT_TRUE(ProcB.try_lock(lane_mask, index)); + + // All zero to begin with + EXPECT_EQ(ProcA.load_inbox(lane_mask, index), 0u); + EXPECT_EQ(ProcB.load_inbox(lane_mask, index), 0u); + EXPECT_EQ(ProcA.load_outbox(lane_mask, index), 0u); + EXPECT_EQ(ProcB.load_outbox(lane_mask, index), 0u); + + // Available for ProcA and not for ProcB + EXPECT_FALSE(ProcA.buffer_unavailable(ProcA.load_inbox(lane_mask, index), + ProcA.load_outbox(lane_mask, index))); + EXPECT_TRUE(ProcB.buffer_unavailable(ProcB.load_inbox(lane_mask, index), + ProcB.load_outbox(lane_mask, index))); + + // ProcA write to outbox + uint32_t ProcAOutbox = ProcA.load_outbox(lane_mask, index); + EXPECT_EQ(ProcAOutbox, 0u); + ProcAOutbox = ProcA.invert_outbox(lane_mask, index, ProcAOutbox); + EXPECT_EQ(ProcAOutbox, 1u); + + // No longer available for ProcA + EXPECT_TRUE(ProcA.buffer_unavailable(ProcA.load_inbox(lane_mask, index), + ProcAOutbox)); + + // Outbox is still zero, hasn't been written to + EXPECT_EQ(ProcB.load_outbox(lane_mask, index), 0u); + + // Wait for ownership will terminate because load_inbox returns 1 + EXPECT_EQ(ProcB.load_inbox(lane_mask, index), 1u); + ProcB.wait_for_ownership(lane_mask, index, 0u, 0u); + + // and B now has the buffer available + EXPECT_FALSE(ProcB.buffer_unavailable(ProcB.load_inbox(lane_mask, index), + ProcB.load_outbox(lane_mask, index))); + + // Enough checks for one test, close the locks + ProcA.unlock(lane_mask, index); + ProcB.unlock(lane_mask, index); +} diff --git a/libc/test/shared/shared_str_to_num_test.cpp b/libc/test/shared/shared_str_to_num_test.cpp new file mode 100644 index 000000000000..b2a5e386e7e5 --- /dev/null +++ b/libc/test/shared/shared_str_to_num_test.cpp @@ -0,0 +1,56 @@ +//===-- Unittests for shared string to number functions -------------------===// +// +// 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 "shared/str_to_float.h" +#include "shared/str_to_integer.h" +#include "test/UnitTest/Test.h" + +namespace LIBC_NAMESPACE_DECL { + +TEST(LlvmLibcSharedStrToNumTest, IntegerTests) { + { + auto result = shared::strtointeger("123", 10); + EXPECT_EQ(result.value, 123); + EXPECT_EQ(result.parsed_len, ptrdiff_t(3)); + EXPECT_EQ(result.error, 0); + } + { + auto result = shared::strtointeger(" -0x123", 0); + EXPECT_EQ(result.value, -0x123); + EXPECT_EQ(result.parsed_len, ptrdiff_t(8)); + EXPECT_EQ(result.error, 0); + } +} + +TEST(LlvmLibcSharedStrToNumTest, FloatTests) { + { + // 1.25 = 1.01b = 5 * 2^-2 + shared::ExpandedFloat input; + input.mantissa = 5; + input.exponent = -2; + auto result = shared::binary_exp_to_float( + input, false, shared::RoundDirection::Nearest); + EXPECT_EQ(result.num.mantissa, uint64_t(0x4000000000000)); + EXPECT_EQ(result.num.exponent, 1023); + EXPECT_EQ(result.error, 0); + } + { + // 1.25 = 125 * 10^-2 + shared::ExpandedFloat input; + input.mantissa = 125; + input.exponent = -2; + const char *str = "1.25"; + auto result = shared::decimal_exp_to_float( + input, false, shared::RoundDirection::Nearest, str); + EXPECT_EQ(result.num.mantissa, uint64_t(0x14000000000000)); + EXPECT_EQ(result.num.exponent, 1023); + EXPECT_EQ(result.error, 0); + } +} + +} // namespace LIBC_NAMESPACE_DECL