Merge pull request #4067 from povik/cxxrtl-udivmod-fix

cxxrtl: Fix `ctlz`, `udivmod`
This commit is contained in:
Martin Povišer 2023-12-12 21:22:25 +01:00 committed by GitHub
commit 5837fe8c91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 13 additions and 8 deletions

View File

@ -508,12 +508,13 @@ struct value : public expr_base<value<Bits>> {
size_t count = 0; size_t count = 0;
for (size_t n = 0; n < chunks; n++) { for (size_t n = 0; n < chunks; n++) {
chunk::type x = data[chunks - 1 - n]; chunk::type x = data[chunks - 1 - n];
if (x == 0) { // First add to `count` as if the chunk is zero
count += (n == 0 ? Bits % chunk::bits : chunk::bits); count += (n == 0 ? Bits % chunk::bits : chunk::bits);
} else { // If the chunk isn't zero, correct the `count` value and return
// This loop implements the find first set idiom as recognized by LLVM. if (x != 0) {
for (; x != 0; count++) for (; x != 0; count--)
x >>= 1; x >>= 1;
break;
} }
} }
return count; return count;
@ -582,8 +583,9 @@ struct value : public expr_base<value<Bits>> {
value<Bits> dividend = *this; value<Bits> dividend = *this;
if (dividend.ucmp(divisor)) if (dividend.ucmp(divisor))
return {/*quotient=*/value<Bits>{0u}, /*remainder=*/dividend}; return {/*quotient=*/value<Bits>{0u}, /*remainder=*/dividend};
uint32_t divisor_shift = dividend.ctlz() - divisor.ctlz(); int64_t divisor_shift = divisor.ctlz() - dividend.ctlz();
divisor = divisor.shl(value<Bits>{divisor_shift}); assert(divisor_shift >= 0);
divisor = divisor.shl(value<Bits>{(chunk::type) divisor_shift});
for (size_t step = 0; step <= divisor_shift; step++) { for (size_t step = 0; step <= divisor_shift; step++) {
quotient = quotient.shl(value<Bits>{1u}); quotient = quotient.shl(value<Bits>{1u});
if (!dividend.ucmp(divisor)) { if (!dividend.ucmp(divisor)) {
@ -795,7 +797,10 @@ std::ostream &operator<<(std::ostream &os, const value_formatted<Bits> &vf)
buf += '0'; buf += '0';
while (!val.is_zero()) { while (!val.is_zero()) {
value<Bits> quotient, remainder; value<Bits> quotient, remainder;
std::tie(quotient, remainder) = val.udivmod(value<Bits>{10u}); if (Bits >= 4)
std::tie(quotient, remainder) = val.udivmod(value<Bits>{10u});
else
std::tie(quotient, remainder) = std::make_pair(value<Bits>{0u}, val);
buf += '0' + remainder.template trunc<(Bits > 4 ? 4 : Bits)>().val().template get<uint8_t>(); buf += '0' + remainder.template trunc<(Bits > 4 ? 4 : Bits)>().val().template get<uint8_t>();
val = quotient; val = quotient;
} }