aboutsummaryrefslogtreecommitdiff
path: root/boot/result.cc
diff options
context:
space:
mode:
Diffstat (limited to 'boot/result.cc')
-rw-r--r--boot/result.cc86
1 files changed, 64 insertions, 22 deletions
diff --git a/boot/result.cc b/boot/result.cc
index 30b4576..15fe8b4 100644
--- a/boot/result.cc
+++ b/boot/result.cc
@@ -226,7 +226,7 @@ namespace elna::boot
std::optional<integer_literal> integer_literal::neg() const
{
- if (!is_signed() || is_negative_minimum())
+ if (!is_signed() || is_negative_minimum(bits()))
{
return std::nullopt;
}
@@ -237,32 +237,44 @@ namespace elna::boot
return result;
}
+ std::optional<integer_literal> integer_literal::negate() const
+ {
+ integer_literal result{ true, this->m_size };
+
+ mpz_set(result.raw, this->raw);
+ mpz_neg(result.raw, result.raw);
+
+ return std::move(result).check();
+ }
+
std::optional<integer_literal> integer_literal::shl(const integer_literal& that) const
{
if (that >= bits())
{
return std::nullopt;
}
- integer_literal result = *this;
-
- mpz_mul_2exp(result.raw, this->raw, static_cast<mp_bitcnt_t>(mpz_get_ui(that.raw)));
+ else
+ {
+ integer_literal result = *this;
- return std::move(result).check();
+ mpz_mul_2exp(result.raw, this->raw, static_cast<mp_bitcnt_t>(mpz_get_ui(that.raw)));
+ return std::make_optional(std::move(result).cast_to(is_signed(), size()));
+ }
}
std::optional<integer_literal> integer_literal::shr(const integer_literal& that) const
{
- integer_literal result = *this;
-
if (that >= bits())
{
- mpz_set_si(result.raw, *this > 0 ? 0 : -1);
+ return std::nullopt;
}
else
{
+ integer_literal result = *this;
+
mpz_fdiv_q_2exp(result.raw, this->raw, static_cast<mp_bitcnt_t>(mpz_get_ui(that.raw)));
+ return std::make_optional(std::move(result));
}
- return std::make_optional(std::move(result));
}
integer_literal integer_literal::operator|(const integer_literal& that) const
@@ -298,7 +310,7 @@ namespace elna::boot
mpz_com(result.raw, this->raw);
- return result;
+ return std::move(result).cast_to(is_signed(), size());
}
bool integer_literal::operator==(const integer_literal& that) const
@@ -328,16 +340,49 @@ namespace elna::boot
return *this;
}
- bool integer_literal::fit_into(const std::size_t target_size)
+ bool integer_literal::fit_into(bool target_signed, const std::size_t target_size)
{
- if (fits_in(target_size * CHAR_BIT))
+ if (fits_in(target_signed, target_size * CHAR_BIT))
{
+ this->m_signed = target_signed;
this->m_size = target_size;
return true;
}
return false;
}
+ bool integer_literal::fit_into(const std::size_t target_size)
+ {
+ return fit_into(is_signed(), target_size);
+ }
+
+ integer_literal integer_literal::cast_to(bool target_signed, std::size_t target_size) const
+ {
+ integer_literal result{ target_signed, target_size };
+ const std::size_t bits = target_size * CHAR_BIT;
+
+ // Reduce to the unsigned residue in [0, 2^bits). This is the bit pattern
+ // resulting from truncating or zero-extending in two's complement,
+ // regardless of the source's sign.
+ mpz_fdiv_r_2exp(result.raw, this->raw, bits);
+
+ // Since GMP doesn't store the value as 2's complement, if the value is
+ // signed it should be converted manually.
+ if (target_signed && mpz_tstbit(result.raw, bits - 1))
+ {
+ mpz_t modulus;
+
+ mpz_init(modulus);
+ mpz_set_ui(modulus, 1);
+ mpz_mul_2exp(modulus, modulus, bits);
+
+ mpz_sub(result.raw, result.raw, modulus);
+
+ mpz_clear(modulus);
+ }
+ return result;
+ }
+
bool integer_literal::is_signed() const
{
return this->m_signed;
@@ -367,30 +412,27 @@ namespace elna::boot
std::swap(lhs.m_size, rhs.m_size);
}
- bool integer_literal::fits_in(const std::size_t bits) const
+ bool integer_literal::fits_in(bool target_signed, const std::size_t bits) const
{
std::size_t required_bits = mpz_sizeinbase(this->raw, 2);
- if (!is_negative() || !is_negative_minimum(bits))
+ if (target_signed && !is_negative_minimum(bits))
{
++required_bits; // Add one bit for the sign.
}
- return required_bits <= bits && (!is_negative() || is_signed());
+ return required_bits <= bits && (!is_negative() || target_signed);
}
std::optional<integer_literal> integer_literal::check() &&
{
- return fits_in(bits()) ? std::make_optional(std::move(*this)) : std::nullopt;
+ return fits_in(is_signed(), bits())
+ ? std::make_optional(std::move(*this))
+ : std::nullopt;
}
bool integer_literal::is_negative_minimum(const std::size_t bits) const
{
- return mpz_scan1(this->raw, 0) == bits - 1;
- }
-
- bool integer_literal::is_negative_minimum() const
- {
- return is_negative() && is_negative_minimum(bits());
+ return is_negative() && mpz_scan1(this->raw, 0) == bits - 1;
}
std::size_t integer_literal::bits() const