10 changes: 9 additions & 1 deletion libc/src/__support/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ add_header_library(
NormalFloat.h
PlatformDefs.h
UInt.h
XFloat.h
DEPENDS
libc.include.math
libc.include.errno
Expand All @@ -24,6 +23,15 @@ add_header_library(
libc.src.errno.errno
)

add_header_library(
xfloat
HDRS
XFloat.h
DEPENDS
.fputil #FPBits and NormalFloat
libc.src.__support.CPP.uint
)

add_header_library(
sqrt
HDRS
Expand Down
236 changes: 0 additions & 236 deletions libc/src/__support/FPUtil/UInt.h

This file was deleted.

2 changes: 1 addition & 1 deletion libc/src/__support/FPUtil/XFloat.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#include "FPBits.h"
#include "NormalFloat.h"
#include "UInt.h"
#include "src/__support/CPP/UInt.h"

#include <stdint.h>

Expand Down
4 changes: 3 additions & 1 deletion libc/src/math/generic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1091,7 +1091,9 @@ add_object_library(
HDRS
dp_trig.h
DEPENDS
libc.src.__support.FPUtil.fputil
libc.src.__support.FPUtil.fputil #FPBits and ManipulationFunction
libc.src.__support.FPUtil.xfloat
libc.src.__support.CPP.uint
COMPILE_OPTIONS
-O3
)
10 changes: 10 additions & 0 deletions libc/test/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ add_libc_unittest(
libc.src.__support.arg_list
)

add_libc_unittest(
uint128_test
SUITE
libc_support_unittests
SRCS
uint128_test.cpp
DEPENDS
libc.src.__support.CPP.uint
)

add_executable(
libc_str_to_float_comparison_test
str_to_float_comparison_test.cpp
Expand Down
163 changes: 163 additions & 0 deletions libc/test/src/__support/uint128_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
//===-- Unittests for the 128 bit integer class ---------------------------===//
//
// 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 "src/__support/CPP/UInt.h"

#include "utils/UnitTest/Test.h"

using UInt128 = __llvm_libc::cpp::UInt<128>;

TEST(LlvmLibcUInt128ClassTest, BasicInit) {
UInt128 empty;
UInt128 half_val(12345);
UInt128 full_val({12345, 67890});
ASSERT_TRUE(half_val != full_val);
}

TEST(LlvmLibcUInt128ClassTest, AdditionTests) {
UInt128 val1(12345);
UInt128 val2(54321);
UInt128 result1(66666);
EXPECT_EQ(val1 + val2, result1);
EXPECT_EQ((val1 + val2), (val2 + val1)); // addition is reciprocal

// Test overflow
UInt128 val3({0xf000000000000001, 0});
UInt128 val4({0x100000000000000f, 0});
UInt128 result2({0x10, 0x1});
EXPECT_EQ(val3 + val4, result2);
EXPECT_EQ(val3 + val4, val4 + val3);
}

TEST(LlvmLibcUInt128ClassTest, MultiplicationTests) {
UInt128 val1({5, 0});
UInt128 val2({10, 0});
UInt128 result1({50, 0});
EXPECT_EQ((val1 * val2), result1);
EXPECT_EQ((val1 * val2), (val2 * val1)); // multiplication is reciprocal

// Check that the multiplication works accross the whole number
UInt128 val3({0xf, 0});
UInt128 val4({0x1111111111111111, 0x1111111111111111});
UInt128 result2({0xffffffffffffffff, 0xffffffffffffffff});
EXPECT_EQ((val3 * val4), result2);
EXPECT_EQ((val3 * val4), (val4 * val3));

// Check that multiplication doesn't reorder the bits.
UInt128 val5({2, 0});
UInt128 val6({0x1357024675316420, 0x0123456776543210});
UInt128 result3({0x26ae048cea62c840, 0x02468aceeca86420});

EXPECT_EQ((val5 * val6), result3);
EXPECT_EQ((val5 * val6), (val6 * val5));

// Make sure that multiplication handles overflow correctly.
UInt128 val7(2);
UInt128 val8({0x8000800080008000, 0x8000800080008000});
UInt128 result4({0x0001000100010000, 0x0001000100010001});
EXPECT_EQ((val7 * val8), result4);
EXPECT_EQ((val7 * val8), (val8 * val7));

// val9 is the 128 bit mantissa of 1e60 as a float, val10 is the mantissa for
// 1e-60. They almost cancel on the high bits, but the result we're looking
// for is just the low bits. The full result would be
// 0x7fffffffffffffffffffffffffffffff3a4f32d17f40d08f917cf11d1e039c50
UInt128 val9({0x01D762422C946590, 0x9F4F2726179A2245});
UInt128 val10({0x3792F412CB06794D, 0xCDB02555653131B6});
UInt128 result5({0x917cf11d1e039c50, 0x3a4f32d17f40d08f});
EXPECT_EQ((val9 * val10), result5);
EXPECT_EQ((val9 * val10), (val10 * val9));
}

TEST(LlvmLibcUInt128ClassTest, ShiftLeftTests) {
UInt128 val1(0x0123456789abcdef);
UInt128 result1(0x123456789abcdef0);
EXPECT_EQ((val1 << 4), result1);

UInt128 val2({0x13579bdf02468ace, 0x123456789abcdef0});
UInt128 result2({0x02468ace00000000, 0x9abcdef013579bdf});
EXPECT_EQ((val2 << 32), result2);

UInt128 result3({0, 0x13579bdf02468ace});
EXPECT_EQ((val2 << 64), result3);

UInt128 result4({0, 0x02468ace00000000});
EXPECT_EQ((val2 << 96), result4);

UInt128 result5({0, 0x2468ace000000000});
EXPECT_EQ((val2 << 100), result5);

UInt128 result6({0, 0});
EXPECT_EQ((val2 << 128), result6);
EXPECT_EQ((val2 << 256), result6);
}

TEST(LlvmLibcUInt128ClassTest, ShiftRightTests) {
UInt128 val1(0x0123456789abcdef);
UInt128 result1(0x00123456789abcde);
EXPECT_EQ((val1 >> 4), result1);

UInt128 val2({0x13579bdf02468ace, 0x123456789abcdef0});
UInt128 result2({0x9abcdef013579bdf, 0x0000000012345678});
EXPECT_EQ((val2 >> 32), result2);

UInt128 result3({0x123456789abcdef0, 0});
EXPECT_EQ((val2 >> 64), result3);

UInt128 result4({0x0000000012345678, 0});
EXPECT_EQ((val2 >> 96), result4);

UInt128 result5({0x0000000001234567, 0});
EXPECT_EQ((val2 >> 100), result5);

UInt128 result6({0, 0});
EXPECT_EQ((val2 >> 128), result6);
EXPECT_EQ((val2 >> 256), result6);
}

TEST(LlvmLibcUInt128ClassTest, AndTests) {
UInt128 base({0xffff00000000ffff, 0xffffffff00000000});
UInt128 val128({0xf0f0f0f00f0f0f0f, 0xff00ff0000ff00ff});
uint64_t val64 = 0xf0f0f0f00f0f0f0f;
int val32 = 0x0f0f0f0f;
UInt128 result128({0xf0f0000000000f0f, 0xff00ff0000000000});
UInt128 result64(0xf0f0000000000f0f);
UInt128 result32(0x00000f0f);
EXPECT_EQ((base & val128), result128);
EXPECT_EQ((base & val64), result64);
EXPECT_EQ((base & val32), result32);
}

TEST(LlvmLibcUInt128ClassTest, OrTests) {
UInt128 base({0xffff00000000ffff, 0xffffffff00000000});
UInt128 val128({0xf0f0f0f00f0f0f0f, 0xff00ff0000ff00ff});
uint64_t val64 = 0xf0f0f0f00f0f0f0f;
int val32 = 0x0f0f0f0f;
UInt128 result128({0xfffff0f00f0fffff, 0xffffffff00ff00ff});
UInt128 result64({0xfffff0f00f0fffff, 0xffffffff00000000});
UInt128 result32({0xffff00000f0fffff, 0xffffffff00000000});
EXPECT_EQ((base | val128), result128);
EXPECT_EQ((base | val64), result64);
EXPECT_EQ((base | val32), result32);
}

TEST(LlvmLibcUInt128ClassTest, EqualsTests) {
UInt128 a1({0xffffffff00000000, 0xffff00000000ffff});
UInt128 a2({0xffffffff00000000, 0xffff00000000ffff});
UInt128 b({0xff00ff0000ff00ff, 0xf0f0f0f00f0f0f0f});
UInt128 a_reversed({0xffff00000000ffff, 0xffffffff00000000});
UInt128 a_upper(0xffff00000000ffff);
UInt128 a_lower(0xffffffff00000000);
ASSERT_TRUE(a1 == a1);
ASSERT_TRUE(a1 == a2);
ASSERT_FALSE(a1 == b);
ASSERT_FALSE(a1 == a_reversed);
ASSERT_FALSE(a1 == a_lower);
ASSERT_FALSE(a1 == a_upper);
ASSERT_TRUE(a_lower != a_upper);
}
20 changes: 19 additions & 1 deletion libc/utils/UnitTest/LibcTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "LibcTest.h"

#include "src/__support/CPP/UInt.h"
#include "utils/testutils/ExecuteFunction.h"
#include <cassert>
#include <iostream>
Expand Down Expand Up @@ -41,7 +42,6 @@ describeValue(ValType Value) {
}

std::string describeValue(std::string Value) { return std::string(Value); }

#ifdef __SIZEOF_INT128__
// When the value is __uint128_t, also show its hexadecimal digits.
// Using template to force exact match, prevent ambiguous promotion.
Expand All @@ -64,6 +64,20 @@ template <> std::string describeValue<__uint128_t>(__uint128_t Value) {
}
#endif

// When the value is UInt<128>, also show its hexadecimal digits.
template <>
std::string
describeValue<__llvm_libc::cpp::UInt<128>>(__llvm_libc::cpp::UInt<128> Value) {
std::string S(sizeof(__llvm_libc::cpp::UInt<128>) * 2, '0');

for (auto I = S.rbegin(), End = S.rend(); I != End; ++I, Value = Value >> 4) {
unsigned char Mod = static_cast<unsigned char>(Value) & 15;
*I = Mod < 10 ? '0' + Mod : 'a' + Mod - 10;
}

return "0x" + S;
}

template <typename ValType>
void explainDifference(ValType LHS, ValType RHS, const char *LHSStr,
const char *RHSStr, const char *File, unsigned long Line,
Expand Down Expand Up @@ -226,6 +240,10 @@ template bool test<__int128_t>(RunContext *Ctx, TestCondition Cond,
const char *LHSStr, const char *RHSStr,
const char *File, unsigned long Line);
#endif
template bool test<__llvm_libc::cpp::UInt<128>>(
RunContext *Ctx, TestCondition Cond, __llvm_libc::cpp::UInt<128> LHS,
__llvm_libc::cpp::UInt<128> RHS, const char *LHSStr, const char *RHSStr,
const char *File, unsigned long Line);

template bool test<unsigned char>(RunContext *Ctx, TestCondition Cond,
unsigned char LHS, unsigned char RHS,
Expand Down