Some platforms don't support proper 128 bit integers, but some
algorithms use them, such as any that use long doubles. This patch
modifies the existing UInt class to support the necessary operators.
This does not put this new class into use, that will be in followup
patches.
Details
- Reviewers
sivachandra lntue - Commits
- rG1170951c7377: [libc] add uint128 implementation
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
libc/src/__support/UInt128.h | ||
---|---|---|
42 | other should either be UInt128 or const UInt128&. You can also add const after the declaration: | |
81 | Drop the const for amount and add const at the end: | |
88 | BITS_IN_UINT64 is unsigned, mixing with signed amount might trigger UB / warnings. | |
libc/test/src/__support/uint128_test.cpp | ||
14 | You should be able to add specialization for UInt128 in LibcTest.cpp and use ASSERT_EQ, EXPECT_EQ as usual. Also disable the __uint128_t variant over there when it's not defined. |
make every UInt128 function constexpr and const.
libc/src/__support/UInt128.h | ||
---|---|---|
88 | it theoretically could, although the bigger problem was the algorithm being wrong for numbers above 64. I've fixed both shifts. | |
libc/test/src/__support/uint128_test.cpp | ||
14 | I could make ASSERT_EQ support my custom UInt128, but that would add a dependency for effectively no gain, since UInt128 shouldn't be called by name in any other test file. Also, the __uint128_t code is already disabled for LibcTest.cpp |
We already have a more generic UInt class here: https://github.com/llvm/llvm-project/blob/main/libc/src/__support/FPUtil/UInt.h
It does not have all the operations exactly as you want, but I could add straightforward extensions and the tests you have in this patch all pass. I strongly suggest adding such extensions to the existing class instead of re-implementing a new class.
I'm not sure that extending UInt.h is a good idea, since it adds a lot of complexity for not a lot of benefit. If we had actual uses for integers larger than 128 bits, then I would agree, but right now the UInt class is not used in any entrypoint. There is a use of 192 bit integers in src/__support/FPUtil/XFloat.h which is included in src/math/generic/dp_trig.cpp, but that's never actually used. To move these functions to UInt would involve rewriting all of these functions to support arbitrary sized integers when in reality there's only one size used. This would be easy for most things, but would be very difficult for multiplying two 128 bit integers. Finally, The designs of these classes are different, my UInt128 class is intended to be an immutable number, acting similar to a primitive. The UInt class acts more like a proper class, its functions take an argument and modify the object instead of creating a new object to be returned. These are both valid designs, but mine is closer to what's expected when using __uint128_t, which is I think what's most important.
If you are starting out, and need only 128 bit integers, I agree with this. The point I am making is, a much general class is already present.
If we had actual uses for integers larger than 128 bits, then I would agree, but right now the UInt class is not used in any entrypoint.
I agree its not used in an entrypoint. But, that doesn't mean its incorrect or totally unused. It is actually tested in one range reduction function.
To move these functions to UInt would involve rewriting all of these functions to support arbitrary sized integers when in reality there's only one size used.
My point is to not move any of the complex pieces. Those complex parts are already implemented in very a general fashion.
Finally, The designs of these classes are different, my UInt128 class is intended to be an immutable number, acting similar to a primitive.
That is why I said that all you need is to add a few straightforward methods. Before I actually made the comment, I tried it out to actually convince myself that I was talking sense. With just a few additional but straightforward methods, all your tests work as is. For example, for addition, all I had to add was this:
UInt<Bits> operator+(const UInt<Bits> &other) const { UInt<Bits> result(*this); result.add(other); return result; }
Similarly, I added straightforward methods for multiplication, shift and bitwise operators also.
changed to use the existing uint class, much of this change was contributed by sivachandra
libc/src/__support/CMakeLists.txt | ||
---|---|---|
63 | Is this still needed? | |
libc/src/__support/FPUtil/UInt.h | ||
20 ↗ | (On Diff #428444) | Add suffix -u/-U to the constant. |
20 ↗ | (On Diff #428444) | can this be all caps MASK32? |
40 ↗ | (On Diff #428444) | Move this out of the class. |
52 ↗ | (On Diff #428444) | Move this out of the class. You can keep them in a separate namespace of use different function name so that it won't clash with the usual strlen. |
60 ↗ | (On Diff #428444) | If you remove trivial implementations of the default and copy constructors, does it still work correctly? |
91 ↗ | (On Diff #428444) | init method is only used here, why don't we just leave its implementation here and remove the private init method? |
93 ↗ | (On Diff #428444) | Remove this if it's not needed. |
199 ↗ | (On Diff #428444) | This line is not needed. result was 0-initialized, and multiply by other[0] would should still be 0. |
libc/src/__support/FPUtil/UInt.h | ||
---|---|---|
20 ↗ | (On Diff #428444) | Why have these been moved out of the class? They are supposed to be internal conveniences and should not be made available from a "public" namespace. If you moved them out for use in the operator* specialization, then if you make them them static, they can still live as private members. |
40 ↗ | (On Diff #428444) | The hexval and strlen methods should be removed along with the commented out constructor. Even the InvalidHexDigit member. |
libc/test/src/__support/uint128_test.cpp | ||
14 | By "disabled" do you mean the conditional on __SIZEOF_INT128__? If yes, you should add the else branches for it with this specialization. To keep everything more logically organized, you should probably move the UInt.h header file to src/__support/CPP. |
move UInt to CPP
add UInt comparison to LibcTest
Move tests to use default comparison
Is this still needed?