Skip to content

Commit b57ddbf

Browse files
committed
HIR Const Eval - Handle different endiannesses
1 parent efeb47d commit b57ddbf

File tree

2 files changed

+112
-31
lines changed

2 files changed

+112
-31
lines changed

src/hir_conv/constant_evaluation.cpp

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,10 @@ namespace MIR { namespace eval {
141141
virtual void read_mask(uint8_t* dst, size_t dst_ofs, size_t ofs, size_t len) const = 0;
142142

143143
virtual bool is_writable() const = 0;
144-
virtual void write_bytes(size_t ofs, const void* data, size_t len) = 0;
144+
virtual uint8_t* ext_write_bytes(size_t ofs, size_t len) = 0;
145+
void write_bytes(size_t ofs, const void* data, size_t len) {
146+
memcpy(ext_write_bytes(ofs, len), data, len);
147+
}
145148
virtual void write_mask_from(size_t ofs, const IValue& src, size_t src_ofs, size_t len) = 0;
146149

147150
virtual RelocPtr get_reloc(size_t ofs) const = 0;
@@ -257,7 +260,7 @@ namespace MIR { namespace eval {
257260
}
258261

259262
bool is_writable() const override { return false; }
260-
void write_bytes(size_t ofs, const void* data, size_t len) override { abort(); }
263+
uint8_t* ext_write_bytes(size_t ofs, size_t len) override { abort(); }
261264
void write_mask_from(size_t ofs, const IValue& src, size_t src_ofs, size_t len) override { abort(); }
262265

263266
RelocPtr get_reloc(size_t ofs) const override { return RelocPtr(); }
@@ -374,7 +377,7 @@ namespace MIR { namespace eval {
374377
bool is_writable() const override {
375378
return !is_readonly;
376379
}
377-
void write_bytes(size_t ofs, const void* data, size_t len) override
380+
uint8_t* ext_write_bytes(size_t ofs, size_t len) override
378381
{
379382
assert(ofs <= length);
380383
assert(len <= length);
@@ -390,11 +393,10 @@ namespace MIR { namespace eval {
390393
for( ; ml % 8 != 0 && ml > 0; mo ++, ml --)
391394
m[mo/8] |= (1 << (mo % 8));
392395
}
393-
// Write data
394-
memcpy(this->data + ofs, data, len);
395396
// Clear impacted relocations
396397
auto it = std::remove_if(this->relocations.begin(), this->relocations.end(), [&](const Reloc& r){ return (ofs <= r.offset && r.offset < ofs+len); });
397398
this->relocations.resize( it - this->relocations.begin() );
399+
return this->data + ofs;
398400
}
399401
void write_mask_from(size_t ofs, const IValue& src, size_t src_ofs, size_t len) override {
400402
assert(ofs <= length);
@@ -499,7 +501,7 @@ namespace MIR { namespace eval {
499501
bool is_writable() const override {
500502
return false;
501503
}
502-
void write_bytes(size_t ofs, const void* data, size_t len) override {
504+
uint8_t* ext_write_bytes(size_t ofs, size_t len) override {
503505
abort();
504506
}
505507
void write_mask_from(size_t ofs, const IValue& src, size_t src_ofs, size_t len) override {
@@ -611,6 +613,17 @@ namespace MIR { namespace eval {
611613
storage.as_value().write_bytes(ofs, data, len);
612614
}
613615
}
616+
uint8_t* ext_write_bytes(const MIR::TypeResolve& state, size_t len) {
617+
MIR_ASSERT(state, storage, "Writing to invalid slot");
618+
MIR_ASSERT(state, storage.as_value().is_writable(), "Writing to read-only slot");
619+
if(len > 0) {
620+
return storage.as_value().ext_write_bytes(ofs, len);
621+
}
622+
else {
623+
static uint8_t empty_buf;
624+
return &empty_buf;
625+
}
626+
}
614627

615628
void write_byte(const MIR::TypeResolve& state, uint8_t v) {
616629
write_bytes(state, &v, 1);
@@ -629,12 +642,22 @@ namespace MIR { namespace eval {
629642
write_uint(state, bits, U128(v));
630643
}
631644
void write_uint(const MIR::TypeResolve& state, unsigned bits, U128 v) {
632-
if(Target_GetCurSpec().m_arch.m_big_endian) MIR_TODO(state, "Handle big endian in constant evaluate");
633-
write_bytes(state, &v, (bits+7)/8);
645+
auto n_bytes = (bits+7)/8;
646+
if(Target_GetCurSpec().m_arch.m_big_endian) {
647+
v.to_be_bytes(ext_write_bytes(state, n_bytes), n_bytes);
648+
}
649+
else {
650+
v.to_le_bytes(ext_write_bytes(state, n_bytes), n_bytes);
651+
}
634652
}
635653
void write_sint(const MIR::TypeResolve& state, unsigned bits, S128 v) {
636-
if(Target_GetCurSpec().m_arch.m_big_endian) MIR_TODO(state, "Handle big endian in constant evaluate");
637-
write_bytes(state, &v, (bits+7)/8);
654+
auto n_bytes = (bits+7)/8;
655+
if(Target_GetCurSpec().m_arch.m_big_endian) {
656+
v.get_inner().to_be_bytes(ext_write_bytes(state, n_bytes), n_bytes);
657+
}
658+
else {
659+
v.get_inner().to_le_bytes(ext_write_bytes(state, n_bytes), n_bytes);
660+
}
638661
}
639662
void write_ptr(const MIR::TypeResolve& state, uint64_t val, RelocPtr reloc) {
640663
write_uint(state, Target_GetPointerBits(), U128(val));
@@ -644,11 +667,16 @@ namespace MIR { namespace eval {
644667
storage.as_value().set_reloc(ofs, std::move(reloc));
645668
}
646669

647-
void read_bytes(const MIR::TypeResolve& state, void* data, size_t len) const {
670+
const uint8_t* ext_read_bytes(const MIR::TypeResolve& state, size_t len) const {
648671
MIR_ASSERT(state, storage, "");
649672
MIR_ASSERT(state, len >= 1, "");
650673
const auto* src = storage.as_value().get_bytes(ofs, len, /*check_mask*/true);
651674
MIR_ASSERT(state, src, "Invalid read: " << ofs << "+" << len << " (in " << *this << ")");
675+
return src;
676+
}
677+
void read_bytes(const MIR::TypeResolve& state, void* data, size_t len) const {
678+
const auto* src = ext_read_bytes(state, len);
679+
assert(src);
652680
memcpy(data, src, len);
653681
}
654682
double read_float(const ::MIR::TypeResolve& state, unsigned bits) const {
@@ -661,33 +689,27 @@ namespace MIR { namespace eval {
661689
}
662690
}
663691
U128 read_uint(const ::MIR::TypeResolve& state, unsigned bits) const {
664-
if(Target_GetCurSpec().m_arch.m_big_endian) MIR_TODO(state, "Handle big endian in constant evaluate");
665692
assert(bits <= 128);
666-
if(bits > 64) {
667-
uint64_t v[2] = {0,0};
668-
read_bytes(state, v, (bits+7)/8);
669-
return U128(v[0], v[1]);
693+
auto n_bytes = (bits+7)/8;
694+
U128 rv;
695+
if(Target_GetCurSpec().m_arch.m_big_endian) {
696+
rv.from_be_bytes(ext_read_bytes(state, n_bytes), n_bytes);
670697
}
671698
else {
672-
uint64_t rv = 0;
673-
read_bytes(state, &rv, (bits+7)/8);
674-
return U128(rv);
699+
rv.from_le_bytes(ext_read_bytes(state, n_bytes), n_bytes);
675700
}
701+
return rv;
676702
}
677703
S128 read_sint(const ::MIR::TypeResolve& state, unsigned bits) const {
678-
auto v = read_uint(state, bits);
679-
if( v.bit(bits-1) ) {
680-
// Apply sign extension
681-
if( bits <= 64 ) {
682-
auto v64 = v.truncate_u64();
683-
v64 |= UINT64_MAX << bits;
684-
v = U128(v64, UINT64_MAX);
685-
}
686-
else {
687-
assert(bits == 128);
688-
}
704+
auto n_bytes = (bits+7)/8;
705+
S128 rv;
706+
if(Target_GetCurSpec().m_arch.m_big_endian) {
707+
rv.from_be_bytes(ext_read_bytes(state, n_bytes), n_bytes);
689708
}
690-
return S128(v);
709+
else {
710+
rv.from_le_bytes(ext_read_bytes(state, n_bytes), n_bytes);
711+
}
712+
return rv;
691713
}
692714
uint64_t read_usize(const ::MIR::TypeResolve& state) const {
693715
return read_uint(state, Target_GetPointerBits()).truncate_u64();

src/include/int128.h

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,48 @@ class U128
6464
memcpy(&rv, &vi, sizeof(rv));
6565
return rv;
6666
}
67+
void to_le_bytes(uint8_t* dst, size_t max_len) {
68+
max_len = max_len > 16 ? 16 : max_len;
69+
#if __LITTLE_ENDIAN__
70+
memcpy(dst, this, max_len);
71+
#else
72+
for(size_t i = 0; i < max_len; i++) {
73+
dst[i] = static_cast<uint8_t>( (*this >> (i*8)).truncate_u64() );
74+
}
75+
#endif
76+
}
77+
void to_be_bytes(uint8_t* dst, size_t max_len) {
78+
max_len = max_len > 16 ? 16 : max_len;
79+
#if __BIG_ENDIAN__
80+
memcpy(dst, this, max_len);
81+
#else
82+
for(size_t i = 0; i < max_len; i++) {
83+
dst[max_len-1-i] = static_cast<uint8_t>( (*this >> (i*8)).truncate_u64() );
84+
}
85+
#endif
86+
}
87+
void from_le_bytes(const uint8_t* src, size_t max_len) {
88+
max_len = max_len > 16 ? 16 : max_len;
89+
*this = U128();
90+
#if __LITTLE_ENDIAN__
91+
memcpy(this, src, max_len);
92+
#else
93+
for(size_t i = 0; i < max_len; i++) {
94+
*this |= U128(src[i]) << (i*8);
95+
}
96+
#endif
97+
}
98+
void from_be_bytes(const uint8_t* src, size_t max_len) {
99+
max_len = max_len > 16 ? 16 : max_len;
100+
*this = U128();
101+
#if __BIG_ENDIAN__
102+
memcpy(this, src, max_len);
103+
#else
104+
for(size_t i = 0; i < max_len; i++) {
105+
*this |= U128(src[max_len-1-i]) << (i*8);
106+
}
107+
#endif
108+
}
67109

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

306+
private:
307+
void sign_extend(size_t n_bytes) {
308+
if( n_bytes < 16 && inner.bit(n_bytes*8-1) ) {
309+
// Apply sign extension mask - shift in nbits from an all-ones value
310+
inner |= U128::max() << (n_bytes*8);
311+
}
312+
}
313+
public:
314+
void from_le_bytes(const uint8_t* src, size_t max_len) {
315+
inner.from_le_bytes(src, max_len);
316+
sign_extend(max_len);
317+
}
318+
void from_be_bytes(const uint8_t* src, size_t max_len) {
319+
inner.from_be_bytes(src, max_len);
320+
sign_extend(max_len);
321+
}
322+
264323
S128 operator~() const { return S128(~inner); }
265324
S128 operator-() const { return S128(~inner) + S128(1); }
266325
S128 operator+(S128 x) const { return S128(inner + x.inner); }

0 commit comments

Comments
 (0)