diff options
-rw-r--r-- | tools/standalone_miri/hir_sim.cpp | 4 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 96 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 50 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 30 |
4 files changed, 162 insertions, 18 deletions
diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 4ff3f191..ef6c4df1 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -5,6 +5,7 @@ #include "hir_sim.hpp" #include "module_tree.hpp" +#include "debug.hpp" //::HIR::Path::Path(::HIR::SimplePath sp) //{ @@ -21,9 +22,10 @@ size_t HIR::TypeRef::get_size(size_t ofs) const case RawType::Composite: return this->composite_type->size; case RawType::Unreachable: + LOG_BUG("Attempting to get size of an unreachable type, " << *this); case RawType::TraitObject: case RawType::Str: - throw "Invalid"; + LOG_BUG("Attempting to get size of an unsized type, " << *this); case RawType::U8: case RawType::I8: return 1; case RawType::U16: case RawType::I16: diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index eb571c64..1afb72a7 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -57,13 +57,6 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar } ::std::vector<bool> drop_flags = fcn.m_mir.drop_flags; - ::std::vector<Value> locals; locals.reserve( fcn.m_mir.locals.size() ); - - Value ret_val = Value(fcn.ret_ty); - for(const auto& ty : fcn.m_mir.locals) - { - locals.push_back(Value(ty)); - } struct State { @@ -82,7 +75,13 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar locals.reserve(fcn.m_mir.locals.size()); for(const auto& ty : fcn.m_mir.locals) { - locals.push_back(Value(ty)); + if( ty == RawType::Unreachable ) { + // HACK: Locals can be !, but they can NEVER be accessed + locals.push_back(Value()); + } + else { + locals.push_back(Value(ty)); + } } } @@ -584,13 +583,83 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar return state.ret; TU_ARM(bb.terminator, If, _te) LOG_TODO("Terminator::If"); - TU_ARM(bb.terminator, Switch, _te) - LOG_TODO("Terminator::Switch"); + TU_ARM(bb.terminator, Switch, te) { + ::HIR::TypeRef ty; + auto v = state.get_value_and_type(te.val, ty); + LOG_ASSERT(ty.wrappers.size() == 0, "" << ty); + LOG_ASSERT(ty.inner_type == RawType::Composite, "" << ty); + + // TODO: Convert the variant list into something that makes it easier to switch on. + size_t found_target = SIZE_MAX; + size_t default_target = SIZE_MAX; + 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 ) + { + // Save as the default, error for multiple defaults + if( default_target != SIZE_MAX ) + { + LOG_FATAL("Two variants with no tag in Switch"); + } + default_target = i; + } + else + { + // Get offset, read the value. + ::HIR::TypeRef tag_ty; + size_t tag_ofs = ty.get_field_ofs(var.base_field, var.field_path, tag_ty); + // Read the value bytes + ::std::vector<char> tmp( var.tag_data.size() ); + v.read_bytes(tag_ofs, const_cast<char*>(tmp.data()), tmp.size()); + if( ::std::memcmp(tmp.data(), var.tag_data.data(), tmp.size()) == 0 ) + { + found_target = i; + break ; + } + } + } + + if( found_target == SIZE_MAX ) + { + found_target = default_target; + } + if( found_target == SIZE_MAX ) + { + LOG_FATAL("Terminator::Switch on " << ty << " didn't find a variant"); + } + bb_idx = te.targets.at(found_target); + } continue; TU_ARM(bb.terminator, SwitchValue, _te) LOG_TODO("Terminator::SwitchValue"); TU_ARM(bb.terminator, Call, te) { - if( te.fcn.is_Intrinsic() ) { - LOG_TODO("Terminator::Call - intrinsic"); + if( te.fcn.is_Intrinsic() ) + { + const auto& fe = te.fcn.as_Intrinsic(); + if( fe.name == "atomic_store" ) + { + const auto& ptr_param = te.args.at(0); + const auto& val_param = te.args.at(1); + + ::HIR::TypeRef ptr_ty; + auto val = state.param_to_value(ptr_param, ptr_ty); + LOG_ASSERT(val.size() == POINTER_SIZE, "atomic_store of a value that isn't a pointer-sized value"); + + // There MUST be a relocation at this point with a valid allocation. + LOG_ASSERT(val.allocation, "Deref of a value with no allocation (hence no relocations)"); + LOG_TRACE("Deref " << val.allocation.alloc()); + auto alloc = val.allocation.alloc().get_relocation(0); + LOG_ASSERT(alloc, "Deref of a value with no relocation"); + + // TODO: Atomic side of this? + size_t ofs = val.read_usize(0); + auto ty = ptr_ty.get_inner(); + alloc.alloc().write_value(ofs, state.param_to_value(val_param)); + } + else + { + LOG_TODO("Terminator::Call - intrinsic \"" << fe.name << "\""); + } } else { const ::HIR::Path* fcn_p; @@ -618,7 +687,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar ::std::cout << "Call " << *fcn_p << ::std::endl; MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args)); } - } break; + bb_idx = te.ret_block; + } continue; } throw ""; } diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 44fd2d02..b0c5f757 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -189,8 +189,8 @@ void Allocation::write_value(size_t ofs, Value v) { size_t v_size = v.allocation.alloc().size(); const auto& src_alloc = v.allocation.alloc(); - // TODO: Just copy the validity from the source. - v.check_bytes_valid(0, v_size); + // Take a copy of the source mask + auto s_mask = src_alloc.mask; // Save relocations first, because `Foo = Foo` is valid. ::std::vector<Relocation> new_relocs = src_alloc.relocations; @@ -209,12 +209,42 @@ void Allocation::write_value(size_t ofs, Value v) this->relocations.push_back( ::std::move(r) ); } } + + // Set mask in destination + if( ofs % 8 != 0 || v_size % 8 != 0 ) + { + // Lazy way, sets/clears individual bits + for(size_t i = 0; i < v_size; i ++) + { + uint8_t dbit = 1 << ((ofs+i) % 8); + if( s_mask[i/8] & (1 << (i %8)) ) + this->mask[ (ofs+i) / 8 ] |= dbit; + else + this->mask[ (ofs+i) / 8 ] &= ~dbit; + } + } + else + { + // Copy the mask bytes directly + for(size_t i = 0; i < v_size / 8; i ++) + { + this->mask[ofs/8+i] = s_mask[i]; + } + } } else { - // TODO: Check validity of input, OR just copy the validity - v.check_bytes_valid(0, v.direct_data.size); this->write_bytes(ofs, v.direct_data.data, v.direct_data.size); + + // Lazy way, sets/clears individual bits + for(size_t i = 0; i < v.direct_data.size; i ++) + { + uint8_t dbit = 1 << ((ofs+i) % 8); + if( v.direct_data.mask[i/8] & (1 << (i %8)) ) + this->mask[ (ofs+i) / 8 ] |= dbit; + else + this->mask[ (ofs+i) / 8 ] &= ~dbit; + } } } void Allocation::write_bytes(size_t ofs, const void* src, size_t count) @@ -520,4 +550,16 @@ uint64_t ValueRef::read_usize(size_t ofs) const uint64_t v = 0; this->read_bytes(0, &v, POINTER_SIZE); return v; +} +uint64_t Value::read_usize(size_t ofs) const +{ + uint64_t v = 0; + this->read_bytes(0, &v, POINTER_SIZE); + return v; +} +uint64_t Allocation::read_usize(size_t ofs) const +{ + uint64_t v = 0; + this->read_bytes(0, &v, POINTER_SIZE); + return v; }
\ No newline at end of file diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 1971bb6d..32131ab1 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -134,6 +134,19 @@ public: void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); } void write_usize(size_t ofs, uint64_t v); void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); } + + uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; } + uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; } + uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; } + uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; } + int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); } + int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); } + int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); } + int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); } + float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; } + double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; } + uint64_t read_usize(size_t ofs) const; + int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); } }; extern ::std::ostream& operator<<(::std::ostream& os, const Allocation& x); @@ -176,6 +189,19 @@ struct Value void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); } void write_usize(size_t ofs, uint64_t v); void write_isize(size_t ofs, int64_t v) { write_usize(ofs, static_cast<uint64_t>(v)); } + + uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; } + uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; } + uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; } + uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; } + int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); } + int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); } + int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); } + int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); } + float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; } + double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; } + uint64_t read_usize(size_t ofs) const; + int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); } }; extern ::std::ostream& operator<<(::std::ostream& os, const Value& v); @@ -202,6 +228,8 @@ struct ValueRef } Value read_value(size_t ofs, size_t size) const { + if( size == 0 ) + return Value(); assert(ofs < m_size); assert(size <= m_size); assert(ofs+size <= m_size); @@ -213,6 +241,8 @@ struct ValueRef } } void read_bytes(size_t ofs, void* dst, size_t size) const { + if( size == 0 ) + return ; assert(ofs < m_size); assert(size <= m_size); assert(ofs+size <= m_size); |