diff options
author | John Hodge <tpg@ucc.asn.au> | 2019-08-03 22:27:21 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2019-08-03 22:27:21 +0800 |
commit | 2612c15cc92a7b9331a2bf6970df506d92b9c48f (patch) | |
tree | 43361c58f92439dc69c1513ae1a323900a1783ec /tools | |
parent | 7f6d0fed8b2d713daa1668c66ffdcc5ac89d7874 (diff) | |
download | mrust-2612c15cc92a7b9331a2bf6970df506d92b9c48f.tar.gz |
Standalone MIRI - discriminant_value
Diffstat (limited to 'tools')
-rw-r--r-- | tools/standalone_miri/miri.cpp | 56 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 10 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 5 |
3 files changed, 60 insertions, 11 deletions
diff --git a/tools/standalone_miri/miri.cpp b/tools/standalone_miri/miri.cpp index c955ef3b..67023205 100644 --- a/tools/standalone_miri/miri.cpp +++ b/tools/standalone_miri/miri.cpp @@ -830,23 +830,26 @@ bool InterpreterThread::step_one(Value& out_thread_result) LOG_ASSERT(re.type.inner_type == RawType::USize, "Function pointers can only be casted to usize, instead " << re.type); new_val = src_value.read_value(0, re.type.get_size()); break; - case RawType::Char: + case RawType::Char: { + uint32_t v = src_value.read_u32(0); switch(re.type.inner_type) { - case RawType::U8: { - uint32_t v = src_value.read_u32(0); + case RawType::U8: if( v > 0xFF ) { LOG_NOTICE("Casting to u8 from char above 255"); } new_val.write_u8(0, v & 0xFF); - } break; + break; case RawType::U32: new_val = src_value.read_value(0, 4); break; + case RawType::USize: + new_val.write_usize(0, v); + break; default: LOG_ERROR("Char can only be casted to u32/u8, instead " << re.type); } - break; + } break; case RawType::Unit: LOG_FATAL("Cast of unit"); case RawType::Composite: { @@ -2093,10 +2096,49 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: { it = type_ids.insert(it, ty_T); } - + rv = Value::with_size(POINTER_SIZE, false); rv.write_usize(0, it - type_ids.begin()); } + else if( name == "discriminant_value" ) + { + const auto& ty = ty_params.tys.at(0); + ValueRef val = args.at(0).deref(0, ty); + + size_t fallback = SIZE_MAX; + size_t found_index = SIZE_MAX; + assert(ty.composite_type); + for(size_t i = 0; i < ty.composite_type->variants.size(); i ++) + { + const auto& var = ty.composite_type->variants[i]; + if( var.tag_data.size() == 0 ) + { + // Only seen in Option<NonNull> + assert(fallback == SIZE_MAX); + fallback = i; + } + else + { + // Get offset to the tag + ::HIR::TypeRef tag_ty; + size_t tag_ofs = ty.get_field_ofs(var.base_field, var.field_path, tag_ty); + // Compare + if( val.compare(tag_ofs, var.tag_data.data(), var.tag_data.size()) == 0 ) + { + found_index = i; + break ; + } + } + } + + if( found_index == SIZE_MAX ) + { + LOG_ASSERT(fallback != SIZE_MAX, "Can't find variant of " << ty << " for " << val); + found_index = fallback; + } + + rv = Value::new_usize(found_index); + } else if( name == "atomic_fence" || name == "atomic_fence_acq" ) { rv = Value(); @@ -2192,7 +2234,7 @@ bool InterpreterThread::call_intrinsic(Value& rv, const RcString& name, const :: rv = Value::with_size( ty_T.get_size() + 1, false ); rv.write_value(0, data_ref.read_value(0, old_v.size())); LOG_DEBUG("> *ptr = " << data_ref); - if( data_ref.compare(old_v.data_ptr(), old_v.size()) == true ) { + if( data_ref.compare(0, old_v.data_ptr(), old_v.size()) == true ) { data_ref.m_alloc.alloc().write_value( data_ref.m_offset, new_v ); rv.write_u8( old_v.size(), 1 ); } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 3fb4c238..363d980b 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -309,6 +309,10 @@ ValueRef ValueCommonRead::read_pointer_valref_mut(size_t rd_ofs, size_t size) return ValueRef(reloc, ofs, size); } } +ValueRef ValueCommonRead::deref(size_t ofs, const ::HIR::TypeRef& ty) +{ + return read_pointer_valref_mut(ofs, ty.get_size()); +} void Allocation::resize(size_t new_size) @@ -991,8 +995,8 @@ Value ValueRef::read_value(size_t ofs, size_t size) const return m_value->read_value(m_offset + ofs, size); } } -bool ValueRef::compare(const void* other, size_t other_len) const +bool ValueRef::compare(size_t offset, const void* other, size_t other_len) const { - check_bytes_valid(0, other_len); - return ::std::memcmp(data_ptr(), other, other_len) == 0; + check_bytes_valid(offset, other_len); + return ::std::memcmp(data_ptr() + offset, other, other_len) == 0; } diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index e8567d02..5e5ccc4f 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -201,6 +201,9 @@ struct ValueCommonRead uint64_t read_usize(size_t ofs) const; int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); } + /// De-reference a pointer (of target type `ty`) at the given offset, and return a reference to it + ValueRef deref(size_t ofs, const ::HIR::TypeRef& ty); + /// Read a pointer from the value, requiring at least `req_valid` valid bytes, saves avaliable space in `size` void* read_pointer_unsafe(size_t rd_ofs, size_t req_valid, size_t& size, bool& is_mut) const; /// Read a pointer, requiring `req_len` valid bytes @@ -515,6 +518,6 @@ struct ValueRef: } } - bool compare(const void* other, size_t other_len) const; + bool compare(size_t offset, const void* other, size_t other_len) const; }; extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v); |