summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/standalone_miri/hir_sim.cpp4
-rw-r--r--tools/standalone_miri/main.cpp96
-rw-r--r--tools/standalone_miri/value.cpp50
-rw-r--r--tools/standalone_miri/value.hpp30
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);