From 0681baae19283e52f3343e1362e49d9d933a753c Mon Sep 17 00:00:00 2001 From: Merry Date: Sat, 9 Dec 2023 14:37:53 +0000 Subject: [PATCH] cxxrtl: Extract divmod algorithm into value --- backends/cxxrtl/runtime/cxxrtl/cxxrtl.h | 65 ++++++++++++++++--------- 1 file changed, 42 insertions(+), 23 deletions(-) diff --git a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h index bc171717f..bd4affc30 100644 --- a/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/runtime/cxxrtl/cxxrtl.h @@ -576,6 +576,37 @@ struct value : public expr_base> { result.data[result.chunks - 1] &= result.msb_mask; return result; } + + std::pair, value> udivmod(value divisor) const { + value quotient; + value dividend = *this; + if (dividend.ucmp(divisor)) + return {/*quotient=*/value{0u}, /*remainder=*/dividend}; + uint32_t divisor_shift = dividend.ctlz() - divisor.ctlz(); + divisor = divisor.shl(value{divisor_shift}); + for (size_t step = 0; step <= divisor_shift; step++) { + quotient = quotient.shl(value{1u}); + if (!dividend.ucmp(divisor)) { + dividend = dividend.sub(divisor); + quotient.set_bit(0, true); + } + divisor = divisor.shr(value{1u}); + } + return {quotient, /*remainder=*/dividend}; + } + + std::pair, value> sdivmod(const value &other) const { + value quotient; + value remainder; + value dividend = sext(); + value divisor = other.template sext(); + if (dividend.is_neg()) dividend = dividend.neg(); + if (divisor.is_neg()) divisor = divisor.neg(); + std::tie(quotient, remainder) = dividend.udivmod(divisor); + if (dividend.is_neg() != divisor.is_neg()) quotient = quotient.neg(); + if (dividend.is_neg()) remainder = remainder.neg(); + return {quotient.template trunc(), remainder.template trunc()}; + } }; // Expression template for a slice, usable as lvalue or rvalue, and composable with other expression templates here. @@ -764,7 +795,7 @@ std::ostream &operator<<(std::ostream &os, const value_formatted &vf) buf += '0'; while (!val.is_zero()) { value quotient, remainder; - std::tie(quotient, remainder) = val.template divmod_uu(value{10u}); + std::tie(quotient, remainder) = val.udivmod(value{10u}); buf += '0' + remainder.template trunc<(Bits > 4 ? 4 : Bits)>().val().template get(); val = quotient; } @@ -1649,35 +1680,23 @@ CXXRTL_ALWAYS_INLINE std::pair, value> divmod_uu(const value &a, const value &b) { constexpr size_t Bits = max(BitsY, max(BitsA, BitsB)); value quotient; + value remainder; value dividend = a.template zext(); value divisor = b.template zext(); - if (dividend.ucmp(divisor)) - return {/*quotient=*/value { 0u }, /*remainder=*/dividend.template trunc()}; - uint32_t divisor_shift = dividend.ctlz() - divisor.ctlz(); - divisor = divisor.shl(value<32> { divisor_shift }); - for (size_t step = 0; step <= divisor_shift; step++) { - quotient = quotient.shl(value<1> { 1u }); - if (!dividend.ucmp(divisor)) { - dividend = dividend.sub(divisor); - quotient.set_bit(0, true); - } - divisor = divisor.shr(value<1> { 1u }); - } - return {quotient.template trunc(), /*remainder=*/dividend.template trunc()}; + std::tie(quotient, remainder) = dividend.udivmod(divisor); + return {quotient.template trunc(), remainder.template trunc()}; } template CXXRTL_ALWAYS_INLINE std::pair, value> divmod_ss(const value &a, const value &b) { - value ua = a.template sext(); - value ub = b.template sext(); - if (ua.is_neg()) ua = ua.neg(); - if (ub.is_neg()) ub = ub.neg(); - value y, r; - std::tie(y, r) = divmod_uu(ua, ub); - if (a.is_neg() != b.is_neg()) y = y.neg(); - if (a.is_neg()) r = r.neg(); - return {y, r}; + constexpr size_t Bits = max(BitsY, max(BitsA, BitsB)); + value quotient; + value remainder; + value dividend = a.template sext(); + value divisor = b.template sext(); + std::tie(quotient, remainder) = dividend.sdivmod(divisor); + return {quotient.template trunc(), remainder.template trunc()}; } template