Skip to content

Commit

Permalink
HIR Const Eval - Handle different endiannesses
Browse files Browse the repository at this point in the history
  • Loading branch information
thepowersgang committed Sep 28, 2023
1 parent efeb47d commit b57ddbf
Show file tree
Hide file tree
Showing 2 changed files with 112 additions and 31 deletions.
84 changes: 53 additions & 31 deletions src/hir_conv/constant_evaluation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,10 @@ namespace MIR { namespace eval {
virtual void read_mask(uint8_t* dst, size_t dst_ofs, size_t ofs, size_t len) const = 0;

virtual bool is_writable() const = 0;
virtual void write_bytes(size_t ofs, const void* data, size_t len) = 0;
virtual uint8_t* ext_write_bytes(size_t ofs, size_t len) = 0;
void write_bytes(size_t ofs, const void* data, size_t len) {
memcpy(ext_write_bytes(ofs, len), data, len);
}
virtual void write_mask_from(size_t ofs, const IValue& src, size_t src_ofs, size_t len) = 0;

virtual RelocPtr get_reloc(size_t ofs) const = 0;
Expand Down Expand Up @@ -257,7 +260,7 @@ namespace MIR { namespace eval {
}

bool is_writable() const override { return false; }
void write_bytes(size_t ofs, const void* data, size_t len) override { abort(); }
uint8_t* ext_write_bytes(size_t ofs, size_t len) override { abort(); }
void write_mask_from(size_t ofs, const IValue& src, size_t src_ofs, size_t len) override { abort(); }

RelocPtr get_reloc(size_t ofs) const override { return RelocPtr(); }
Expand Down Expand Up @@ -374,7 +377,7 @@ namespace MIR { namespace eval {
bool is_writable() const override {
return !is_readonly;
}
void write_bytes(size_t ofs, const void* data, size_t len) override
uint8_t* ext_write_bytes(size_t ofs, size_t len) override
{
assert(ofs <= length);
assert(len <= length);
Expand All @@ -390,11 +393,10 @@ namespace MIR { namespace eval {
for( ; ml % 8 != 0 && ml > 0; mo ++, ml --)
m[mo/8] |= (1 << (mo % 8));
}
// Write data
memcpy(this->data + ofs, data, len);
// Clear impacted relocations
auto it = std::remove_if(this->relocations.begin(), this->relocations.end(), [&](const Reloc& r){ return (ofs <= r.offset && r.offset < ofs+len); });
this->relocations.resize( it - this->relocations.begin() );
return this->data + ofs;
}
void write_mask_from(size_t ofs, const IValue& src, size_t src_ofs, size_t len) override {
assert(ofs <= length);
Expand Down Expand Up @@ -499,7 +501,7 @@ namespace MIR { namespace eval {
bool is_writable() const override {
return false;
}
void write_bytes(size_t ofs, const void* data, size_t len) override {
uint8_t* ext_write_bytes(size_t ofs, size_t len) override {
abort();
}
void write_mask_from(size_t ofs, const IValue& src, size_t src_ofs, size_t len) override {
Expand Down Expand Up @@ -611,6 +613,17 @@ namespace MIR { namespace eval {
storage.as_value().write_bytes(ofs, data, len);
}
}
uint8_t* ext_write_bytes(const MIR::TypeResolve& state, size_t len) {
MIR_ASSERT(state, storage, "Writing to invalid slot");
MIR_ASSERT(state, storage.as_value().is_writable(), "Writing to read-only slot");
if(len > 0) {
return storage.as_value().ext_write_bytes(ofs, len);
}
else {
static uint8_t empty_buf;
return &empty_buf;
}
}

void write_byte(const MIR::TypeResolve& state, uint8_t v) {
write_bytes(state, &v, 1);
Expand All @@ -629,12 +642,22 @@ namespace MIR { namespace eval {
write_uint(state, bits, U128(v));
}
void write_uint(const MIR::TypeResolve& state, unsigned bits, U128 v) {
if(Target_GetCurSpec().m_arch.m_big_endian) MIR_TODO(state, "Handle big endian in constant evaluate");
write_bytes(state, &v, (bits+7)/8);
auto n_bytes = (bits+7)/8;
if(Target_GetCurSpec().m_arch.m_big_endian) {
v.to_be_bytes(ext_write_bytes(state, n_bytes), n_bytes);
}
else {
v.to_le_bytes(ext_write_bytes(state, n_bytes), n_bytes);
}
}
void write_sint(const MIR::TypeResolve& state, unsigned bits, S128 v) {
if(Target_GetCurSpec().m_arch.m_big_endian) MIR_TODO(state, "Handle big endian in constant evaluate");
write_bytes(state, &v, (bits+7)/8);
auto n_bytes = (bits+7)/8;
if(Target_GetCurSpec().m_arch.m_big_endian) {
v.get_inner().to_be_bytes(ext_write_bytes(state, n_bytes), n_bytes);
}
else {
v.get_inner().to_le_bytes(ext_write_bytes(state, n_bytes), n_bytes);
}
}
void write_ptr(const MIR::TypeResolve& state, uint64_t val, RelocPtr reloc) {
write_uint(state, Target_GetPointerBits(), U128(val));
Expand All @@ -644,11 +667,16 @@ namespace MIR { namespace eval {
storage.as_value().set_reloc(ofs, std::move(reloc));
}

void read_bytes(const MIR::TypeResolve& state, void* data, size_t len) const {
const uint8_t* ext_read_bytes(const MIR::TypeResolve& state, size_t len) const {
MIR_ASSERT(state, storage, "");
MIR_ASSERT(state, len >= 1, "");
const auto* src = storage.as_value().get_bytes(ofs, len, /*check_mask*/true);
MIR_ASSERT(state, src, "Invalid read: " << ofs << "+" << len << " (in " << *this << ")");
return src;
}
void read_bytes(const MIR::TypeResolve& state, void* data, size_t len) const {
const auto* src = ext_read_bytes(state, len);
assert(src);
memcpy(data, src, len);
}
double read_float(const ::MIR::TypeResolve& state, unsigned bits) const {
Expand All @@ -661,33 +689,27 @@ namespace MIR { namespace eval {
}
}
U128 read_uint(const ::MIR::TypeResolve& state, unsigned bits) const {
if(Target_GetCurSpec().m_arch.m_big_endian) MIR_TODO(state, "Handle big endian in constant evaluate");
assert(bits <= 128);
if(bits > 64) {
uint64_t v[2] = {0,0};
read_bytes(state, v, (bits+7)/8);
return U128(v[0], v[1]);
auto n_bytes = (bits+7)/8;
U128 rv;
if(Target_GetCurSpec().m_arch.m_big_endian) {
rv.from_be_bytes(ext_read_bytes(state, n_bytes), n_bytes);
}
else {
uint64_t rv = 0;
read_bytes(state, &rv, (bits+7)/8);
return U128(rv);
rv.from_le_bytes(ext_read_bytes(state, n_bytes), n_bytes);
}
return rv;
}
S128 read_sint(const ::MIR::TypeResolve& state, unsigned bits) const {
auto v = read_uint(state, bits);
if( v.bit(bits-1) ) {
// Apply sign extension
if( bits <= 64 ) {
auto v64 = v.truncate_u64();
v64 |= UINT64_MAX << bits;
v = U128(v64, UINT64_MAX);
}
else {
assert(bits == 128);
}
auto n_bytes = (bits+7)/8;
S128 rv;
if(Target_GetCurSpec().m_arch.m_big_endian) {
rv.from_be_bytes(ext_read_bytes(state, n_bytes), n_bytes);
}
return S128(v);
else {
rv.from_le_bytes(ext_read_bytes(state, n_bytes), n_bytes);
}
return rv;
}
uint64_t read_usize(const ::MIR::TypeResolve& state) const {
return read_uint(state, Target_GetPointerBits()).truncate_u64();
Expand Down
59 changes: 59 additions & 0 deletions src/include/int128.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,48 @@ class U128
memcpy(&rv, &vi, sizeof(rv));
return rv;
}
void to_le_bytes(uint8_t* dst, size_t max_len) {
max_len = max_len > 16 ? 16 : max_len;
#if __LITTLE_ENDIAN__
memcpy(dst, this, max_len);
#else
for(size_t i = 0; i < max_len; i++) {
dst[i] = static_cast<uint8_t>( (*this >> (i*8)).truncate_u64() );
}
#endif
}
void to_be_bytes(uint8_t* dst, size_t max_len) {
max_len = max_len > 16 ? 16 : max_len;
#if __BIG_ENDIAN__
memcpy(dst, this, max_len);
#else
for(size_t i = 0; i < max_len; i++) {
dst[max_len-1-i] = static_cast<uint8_t>( (*this >> (i*8)).truncate_u64() );
}
#endif
}
void from_le_bytes(const uint8_t* src, size_t max_len) {
max_len = max_len > 16 ? 16 : max_len;
*this = U128();
#if __LITTLE_ENDIAN__
memcpy(this, src, max_len);
#else
for(size_t i = 0; i < max_len; i++) {
*this |= U128(src[i]) << (i*8);
}
#endif
}
void from_be_bytes(const uint8_t* src, size_t max_len) {
max_len = max_len > 16 ? 16 : max_len;
*this = U128();
#if __BIG_ENDIAN__
memcpy(this, src, max_len);
#else
for(size_t i = 0; i < max_len; i++) {
*this |= U128(src[max_len-1-i]) << (i*8);
}
#endif
}

U128 operator~() const { return U128(~lo, ~hi); }
U128 operator+(U128 x) const { U128 rv(0); add128_o(*this, x, &rv); return rv; }
Expand Down Expand Up @@ -261,6 +303,23 @@ class S128
float to_float() const { return (*this < 0 ? -1.0f : 1.0f) * this->u_abs().to_float(); }
U128 get_inner() const { return inner; }

private:
void sign_extend(size_t n_bytes) {
if( n_bytes < 16 && inner.bit(n_bytes*8-1) ) {
// Apply sign extension mask - shift in nbits from an all-ones value
inner |= U128::max() << (n_bytes*8);
}
}
public:
void from_le_bytes(const uint8_t* src, size_t max_len) {
inner.from_le_bytes(src, max_len);
sign_extend(max_len);
}
void from_be_bytes(const uint8_t* src, size_t max_len) {
inner.from_be_bytes(src, max_len);
sign_extend(max_len);
}

S128 operator~() const { return S128(~inner); }
S128 operator-() const { return S128(~inner) + S128(1); }
S128 operator+(S128 x) const { return S128(inner + x.inner); }
Expand Down

0 comments on commit b57ddbf

Please sign in to comment.