diff options
-rw-r--r-- | tools/standalone_miri/miri.cpp | 101 | ||||
-rw-r--r-- | tools/standalone_miri/u128.hpp | 155 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 2 |
3 files changed, 244 insertions, 14 deletions
diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index 97343714..55ac81bb 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -341,6 +341,7 @@ struct MirHelpers auto len = vr.m_metadata->read_usize(0); LOG_ASSERT(idx < len, "Slice index out of range"); vr.m_offset += ty.get_size() * idx; + vr.m_metadata.reset(); } else { @@ -433,8 +434,8 @@ struct MirHelpers LOG_DEBUG("sizeof(" << ty << ") = " << ty.get_size()); LOG_ASSERT(vr.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value (size=" << vr << ") - " << vr << ": " << ptr_ty); size = ty.get_size(); - if( !alloc ) { - LOG_ERROR("Deref of a value with no relocation - " << vr); + if( !alloc && size > 0 ) { + LOG_ERROR("Deref of a non-ZST pointer with no relocation - " << vr); } } @@ -502,7 +503,11 @@ struct MirHelpers ty = ::HIR::TypeRef(ce.t); Value val = Value(ty); val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian - // TODO: i128/u128 need the upper bytes cleared+valid + // i128/u128 need the upper bytes cleared+valid + if( ce.t.raw_type == RawType::U128 ) { + uint64_t zero = 0; + val.write_bytes(8, &zero, 8); + } return val; } break; TU_ARM(c, Bool, ce) { @@ -799,8 +804,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::Bool: throw "ERROR"; case RawType::F32: throw "BUG"; case RawType::F64: dst_val = static_cast<float>( src_value.read_f64(0) ); break; - case RawType::USize: throw "TODO";// /*dst_val = src_value.read_usize();*/ break; - case RawType::ISize: throw "TODO";// /*dst_val = src_value.read_isize();*/ break; + case RawType::USize: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_usize();*/ break; + case RawType::ISize: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_isize();*/ break; case RawType::U8: dst_val = static_cast<float>( src_value.read_u8 (0) ); break; case RawType::I8: dst_val = static_cast<float>( src_value.read_i8 (0) ); break; case RawType::U16: dst_val = static_cast<float>( src_value.read_u16(0) ); break; @@ -809,8 +814,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::I32: dst_val = static_cast<float>( src_value.read_i32(0) ); break; case RawType::U64: dst_val = static_cast<float>( src_value.read_u64(0) ); break; case RawType::I64: dst_val = static_cast<float>( src_value.read_i64(0) ); break; - case RawType::U128: throw "TODO";// /*dst_val = src_value.read_u128();*/ break; - case RawType::I128: throw "TODO";// /*dst_val = src_value.read_i128();*/ break; + case RawType::U128: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_u128();*/ break; + case RawType::I128: LOG_TODO("f32 from " << src_ty);// /*dst_val = src_value.read_i128();*/ break; } new_val.write_f32(0, dst_val); } break; @@ -990,6 +995,13 @@ bool InterpreterThread::step_one(Value& out_thread_result) if(0) case RawType::I64: dst_val = static_cast<uint64_t>( src_value.read_i64(0) ); + if(0) + case RawType::U128: + dst_val = static_cast<uint64_t>( src_value.read_u128(0) ); + if(0) + case RawType::I128: + LOG_TODO("Cast i128 to " << re.type); + //dst_val = static_cast<uint64_t>( src_value.read_i128(0) ); switch(re.type.inner_type) { @@ -1027,13 +1039,20 @@ bool InterpreterThread::step_one(Value& out_thread_result) throw ""; } break; - case RawType::U128: throw "TODO"; /*dst_val = src_value.read_u128();*/ break; - case RawType::I128: throw "TODO"; /*dst_val = src_value.read_i128();*/ break; } } break; case RawType::U128: - case RawType::I128: - LOG_TODO("Cast to " << re.type); + case RawType::I128: { + U128 dst_val; + switch(src_ty.inner_type) + { + case RawType::U8: dst_val = src_value.read_u8 (0); break; + case RawType::I8: dst_val = src_value.read_i8 (0); break; + default: + LOG_TODO("Cast " << src_ty << " to " << re.type); + } + new_val.write_u128(0, dst_val); + } break; } } } break; @@ -1150,6 +1169,8 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::ISize: res = res != 0 ? res : Ops::do_compare(v_l.read_isize(0), v_r.read_isize(0)); break; case RawType::Char: res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0)); break; case RawType::Bool: res = res != 0 ? res : Ops::do_compare(v_l.read_u8(0), v_r.read_u8(0)); break; // TODO: `read_bool` that checks for bool values? + case RawType::U128: res = res != 0 ? res : Ops::do_compare(v_l.read_u128(0), v_r.read_u128(0)); break; + case RawType::I128: res = res != 0 ? res : Ops::do_compare(v_l.read_i128(0), v_r.read_i128(0)); break; default: LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l); } @@ -1197,6 +1218,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) switch(ty_l.inner_type) { // TODO: U128 + case RawType::U128: new_val.write_u128(0, Ops::do_bitwise(v_l.read_u128(0), U128(shift), re.op)); break; case RawType::U64: new_val.write_u64(0, Ops::do_bitwise(v_l.read_u64(0), static_cast<uint64_t>(shift), re.op)); break; case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast<uint32_t>(shift), re.op)); break; case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast<uint16_t>(shift), re.op)); break; @@ -1217,7 +1239,10 @@ bool InterpreterThread::step_one(Value& out_thread_result) new_val = Value(ty_l); switch(ty_l.inner_type) { - // TODO: U128/I128 + case RawType::U128: + case RawType::I128: + new_val.write_u128( 0, Ops::do_bitwise(v_l.read_u128(0), v_r.read_u128(0), re.op) ); + break; case RawType::U64: case RawType::I64: new_val.write_u64( 0, Ops::do_bitwise(v_l.read_u64(0), v_r.read_u64(0), re.op) ); @@ -1621,6 +1646,7 @@ bool InterpreterThread::step_one(Value& out_thread_result) case RawType::U64: switch_val = v.read_u64(0); break; case RawType::U128: LOG_TODO("Terminator::SwitchValue::Unsigned with u128"); case RawType::USize: switch_val = v.read_usize(0); break; + case RawType::Char: switch_val = v.read_u32(0); break; default: LOG_ERROR("Terminator::SwitchValue::Unsigned with unexpected type - " << ty); } @@ -1913,7 +1939,7 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c return reinterpret_cast<const char*>(v.read_pointer_const(0, len + 1)); // Final read will trigger an error if the NUL isn't there } }; - if( link_name == "__rust_allocate" || link_name == "__rust_alloc" ) + if( link_name == "__rust_allocate" || link_name == "__rust_alloc" || link_name == "__rust_alloc_zeroed" ) { static unsigned s_alloc_count = 0; @@ -1921,11 +1947,16 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c auto alloc_name = FMT_STRING("__rust_alloc#" << alloc_idx); auto size = args.at(0).read_usize(0); auto align = args.at(1).read_usize(0); - LOG_DEBUG("__rust_allocate(size=" << size << ", align=" << align << "): name=" << alloc_name); + LOG_DEBUG(link_name << "(size=" << size << ", align=" << align << "): name=" << alloc_name); auto alloc = Allocation::new_alloc(size, ::std::move(alloc_name)); LOG_TRACE("- alloc=" << alloc << " (" << alloc->size() << " bytes)"); auto rty = ::HIR::TypeRef(RawType::Unit).wrap( TypeWrapper::Ty::Pointer, 0 ); + if( link_name == "__rust_alloc_zeroed" ) + { + alloc->mark_bytes_valid(0, size); + } + // TODO: Use the alignment when making an allocation? rv = Value::new_pointer(rty, Allocation::PTR_BASE, RelocationPtr::new_alloc(::std::move(alloc))); } @@ -2412,6 +2443,23 @@ bool InterpreterThread::call_extern(Value& rv, const ::std::string& link_name, c { rv = Value::new_i32(-1); } + else if( link_name == "memcmp" ) + { + auto n = args.at(2).read_usize(0); + int rv_i; + if( n > 0 ) + { + const void* ptr_b = args.at(1).read_pointer_const(0, n); + const void* ptr_a = args.at(0).read_pointer_const(0, n); + + rv_i = memcmp(ptr_a, ptr_b, n); + } + else + { + rv_i = 0; + } + rv = Value::new_i32(rv_i); + } // - `void *memchr(const void *s, int c, size_t n);` else if( link_name == "memchr" ) { @@ -2696,6 +2744,31 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: rv = ::std::move(args.at(0)); rv.write_ptr(0, Allocation::PTR_BASE + new_ofs, ptr_alloc); } + else if( name == "arith_offset" ) // Doesn't check validity, and allows wrapping + { + auto ptr_alloc = args.at(0).get_relocation(0); + auto ptr_ofs = args.at(0).read_usize(0); + //LOG_ASSERT(ptr_ofs >= Allocation::PTR_BASE, "`offset` with invalid pointer - " << args.at(0)); + //ptr_ofs -= Allocation::PTR_BASE; + auto& ofs_val = args.at(1); + + auto delta_counts = ofs_val.read_usize(0); + auto new_ofs = ptr_ofs + delta_counts * ty_params.tys.at(0).get_size(); + if(POINTER_SIZE != 8) { + new_ofs &= 0xFFFFFFFF; + } + //new_ofs += Allocation::PTR_BASE; + + rv = ::std::move(args.at(0)); + if( ptr_alloc ) + { + rv.write_ptr(0, new_ofs, ptr_alloc); + } + else + { + rv.write_usize(0, new_ofs); + } + } // effectively ptr::write else if( name == "move_val_init" ) { diff --git a/tools/standalone_miri/u128.hpp b/tools/standalone_miri/u128.hpp index 03c004d9..8403b94a 100644 --- a/tools/standalone_miri/u128.hpp +++ b/tools/standalone_miri/u128.hpp @@ -2,9 +2,126 @@ class U128 { + friend class I128; uint64_t lo, hi; public: U128(): lo(0), hi(0) {} + + U128(uint8_t v): lo(v), hi(0) {} + U128(int8_t v): lo(v), hi(v < 0 ? -1 : 0) {} + + void fmt(::std::ostream& os) const { os << hi << ":" << lo; } + + int cmp(U128 v) const { + if( hi != v.hi ) { + return (hi < v.hi ? -1 : 1); + } + if( lo != v.lo ) { + return (lo < v.lo ? -1 : 1); + } + return 0; + } + int cmp(unsigned v) const { + if(hi) + return 1; + if(lo < v) + return -1; + if(lo > v) + return 1; + return 0; + } + + template<typename T> bool operator< (const T& v) const { return this->cmp(v) < 0; } + template<typename T> bool operator<=(const T& v) const { return this->cmp(v) <= 0; } + template<typename T> bool operator> (const T& v) const { return this->cmp(v) > 0; } + template<typename T> bool operator>=(const T& v) const { return this->cmp(v) >= 0; } + template<typename T> bool operator==(const T& v) const { return this->cmp(v) == 0; } + template<typename T> bool operator!=(const T& v) const { return this->cmp(v) != 0; } + + operator uint8_t() const { return static_cast<uint8_t>(lo); } + + U128 operator&(U128 x) const { + U128 rv; + rv.lo = this->lo & x.lo; + rv.hi = this->hi & x.hi; + return rv; + } + U128 operator|(U128 x) const { + U128 rv; + rv.lo = this->lo | x.lo; + rv.hi = this->hi | x.hi; + return rv; + } + U128 operator^(U128 x) const { + U128 rv; + rv.lo = this->lo ^ x.lo; + rv.hi = this->hi ^ x.hi; + return rv; + } + + U128 operator<<(U128 n) const + { + if( n < 128 ) + { + return *this << static_cast<uint8_t>(n); + } + else + { + return U128(); + } + } + U128 operator<<(uint8_t n) const + { + if(n == 0) + { + return *this; + } + else if( n < 64 ) + { + U128 rv; + rv.lo = lo << n; + rv.hi = (hi << n) | (lo >> (64-n)); + return rv; + } + else if( n < 128 ) + { + U128 rv; + rv.lo = 0; + rv.hi = (lo << (n-64)); + return rv; + } + else + { + return U128(); + } + } + U128 operator>>(uint8_t n) const + { + if(n == 0) + { + return *this; + } + else if( n < 64 ) + { + U128 rv; + rv.lo = (lo >> n) | (hi << (64-n)); + rv.hi = (hi >> n); + return rv; + } + else if( n < 128 ) + { + U128 rv; + rv.lo = (hi >> (n-64)); + rv.hi = 0; + return rv; + } + else + { + return U128(); + } + } + + friend ::std::ostream& operator<<(::std::ostream& os, const U128& x) { x.fmt(os); return os; } }; class I128 @@ -12,4 +129,42 @@ class I128 U128 v; public: I128() {} + + int cmp(I128 x) const { + if(v.hi != x.v.hi) + return (static_cast<int64_t>(v.hi) < static_cast<int64_t>(x.v.hi) ? -1 : 1); + if(v.lo != x.v.lo) + { + if( static_cast<int64_t>(v.hi) < 0 ) + { + // Negative, so larger raw value is the smaller + return (v.lo > x.v.lo ? -1 : 1); + } + else + { + return (v.lo < x.v.lo ? -1 : 1); + } + } + return 0; + } + //int cmp(int v) const { + // if(hi) + // return 1; + // if(lo < v) + // return -1; + // if(lo > v) + // return 1; + // return 0; + //} + + template<typename T> bool operator< (const T& v) const { return this->cmp(v) < 0; } + template<typename T> bool operator<=(const T& v) const { return this->cmp(v) <= 0; } + template<typename T> bool operator> (const T& v) const { return this->cmp(v) > 0; } + template<typename T> bool operator>=(const T& v) const { return this->cmp(v) >= 0; } + template<typename T> bool operator==(const T& v) const { return this->cmp(v) == 0; } + template<typename T> bool operator!=(const T& v) const { return this->cmp(v) != 0; } + + void fmt(::std::ostream& os) const { os << v.hi << ":" << v.lo; } + + friend ::std::ostream& operator<<(::std::ostream& os, const I128& x) { x.fmt(os); return os; } }; diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 764df8fa..dea4c890 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -235,10 +235,12 @@ struct ValueCommonWrite: void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); } void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); } void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); } + void write_u128(size_t ofs, U128 v) { write_bytes(ofs, &v, 16); } void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); } void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); } void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); } void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); } + void write_i128(size_t ofs, I128 v) { write_bytes(ofs, &v, 16); } void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); } void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); } void write_usize(size_t ofs, uint64_t v); |