[libc-commits] [libc] [libc] Add bigint casting between word types (PR #111914)
via libc-commits
libc-commits at lists.llvm.org
Thu Oct 10 19:39:31 PDT 2024
================
@@ -361,17 +361,90 @@ struct BigInt {
LIBC_INLINE constexpr BigInt(const BigInt &other) = default;
- template <size_t OtherBits, bool OtherSigned>
+ template <size_t OtherBits, bool OtherSigned, typename OtherWordType>
LIBC_INLINE constexpr BigInt(
- const BigInt<OtherBits, OtherSigned, WordType> &other) {
- if (OtherBits >= Bits) { // truncate
- for (size_t i = 0; i < WORD_COUNT; ++i)
- val[i] = other[i];
- } else { // zero or sign extend
- size_t i = 0;
- for (; i < OtherBits / WORD_SIZE; ++i)
- val[i] = other[i];
- extend(i, Signed && other.is_neg());
+ const BigInt<OtherBits, OtherSigned, OtherWordType> &other) {
+ using BigIntOther = BigInt<OtherBits, OtherSigned, OtherWordType>;
+ const bool should_sign_extend = Signed && other.is_neg();
+
+ if constexpr (BigIntOther::WORD_SIZE < WORD_SIZE) {
+ // OtherWordType is smaller
+ constexpr size_t WORD_SIZE_RATIO = WORD_SIZE / BigIntOther::WORD_SIZE;
+ static_assert(
+ (WORD_SIZE % BigIntOther::WORD_SIZE) == 0 &&
+ "Word types must be multiples of each other for correct conversion.");
+ if (OtherBits >= Bits) { // truncate
+ // for each big word
+ for (size_t i = 0; i < WORD_COUNT; ++i) {
+ WordType cur_word = 0;
+ // combine WORD_SIZE_RATIO small words into a big word
+ for (size_t j = 0; j < WORD_SIZE_RATIO; ++j)
+ cur_word |= static_cast<WordType>(other[(i * WORD_SIZE_RATIO) + j])
+ << (BigIntOther::WORD_SIZE * j);
+
+ val[i] = cur_word;
+ }
+ } else { // zero or sign extend
+ size_t i = 0;
+ WordType cur_word = 0;
+ // for each small word
+ for (; i < BigIntOther::WORD_COUNT; ++i) {
+ // combine WORD_SIZE_RATIO small words into a big word
+ cur_word |= static_cast<WordType>(other[i])
+ << (BigIntOther::WORD_SIZE * (i % WORD_SIZE_RATIO));
+ // if we've completed a big word, copy it into place and reset
+ if ((i % WORD_SIZE_RATIO) == WORD_SIZE_RATIO - 1) {
+ val[i / WORD_SIZE_RATIO] = cur_word;
+ cur_word = 0;
+ }
+ }
+ // Pretend there are extra words of the correct sign extension as needed
+
+ const WordType extension_bits =
+ should_sign_extend ? cpp::numeric_limits<WordType>::max()
+ : cpp::numeric_limits<WordType>::min();
+ if ((i % WORD_SIZE_RATIO) != 0) {
+ cur_word |= static_cast<WordType>(extension_bits)
+ << (BigIntOther::WORD_SIZE * (i % WORD_SIZE_RATIO));
+ }
+ // Copy the last word into place.
+ val[(i / WORD_SIZE_RATIO)] = cur_word;
+ extend((i / WORD_SIZE_RATIO) + 1, should_sign_extend);
+ }
+ } else if constexpr (BigIntOther::WORD_SIZE == WORD_SIZE) {
+ if (OtherBits >= Bits) { // truncate
----------------
lntue wrote:
also `if constexpr`
https://github.com/llvm/llvm-project/pull/111914
More information about the libc-commits
mailing list