summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/standalone_miri/hir_sim.cpp19
-rw-r--r--tools/standalone_miri/hir_sim.hpp1
-rw-r--r--tools/standalone_miri/main.cpp416
-rw-r--r--tools/standalone_miri/value.cpp42
-rw-r--r--tools/standalone_miri/value.hpp9
5 files changed, 379 insertions, 108 deletions
diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp
index ef6c4df1..d549fa1d 100644
--- a/tools/standalone_miri/hir_sim.cpp
+++ b/tools/standalone_miri/hir_sim.cpp
@@ -90,6 +90,25 @@ size_t HIR::TypeRef::get_size(size_t ofs) const
}
throw "";
}
+bool HIR::TypeRef::has_slice_meta() const
+{
+ if( this->wrappers.size() == 0 )
+ {
+ if(this->inner_type == RawType::Composite)
+ {
+ // TODO: Handle metadata better
+ return false;
+ }
+ else
+ {
+ return (this->inner_type == RawType::Str);
+ }
+ }
+ else
+ {
+ return (this->wrappers[0].type == TypeWrapper::Ty::Slice);
+ }
+}
HIR::TypeRef HIR::TypeRef::get_inner() const
{
diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp
index a81a3f9d..93d5569c 100644
--- a/tools/standalone_miri/hir_sim.hpp
+++ b/tools/standalone_miri/hir_sim.hpp
@@ -118,6 +118,7 @@ namespace HIR {
}
size_t get_size(size_t ofs=0) const;
+ bool has_slice_meta() const; // The attached metadata is a count
TypeRef get_inner() const;
TypeRef get_field(size_t idx, size_t& ofs) const;
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp
index 026fba05..f060fef0 100644
--- a/tools/standalone_miri/main.cpp
+++ b/tools/standalone_miri/main.cpp
@@ -17,6 +17,7 @@ struct ProgramOptions
Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args);
Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& abi, ::std::vector<Value> args);
+Value MIRI_Invoke_Intrinsic(const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector<Value> args);
int main(int argc, const char* argv[])
{
@@ -50,18 +51,19 @@ int main(int argc, const char* argv[])
struct Ops {
template<typename T>
- static bool do_compare(T l, T r, ::MIR::eBinOp op) {
- switch(op)
- {
- case ::MIR::eBinOp::EQ: return l == r;
- case ::MIR::eBinOp::NE: return l != r;
- case ::MIR::eBinOp::GT: return l > r;
- case ::MIR::eBinOp::GE: return l >= r;
- case ::MIR::eBinOp::LT: return l < r;
- case ::MIR::eBinOp::LE: return l <= r;
- break;
- default:
- LOG_BUG("Unexpected operation in Ops::do_compare");
+ static int do_compare(T l, T r) {
+ if( l == r ) {
+ return 0;
+ }
+ else if( !(l != r) ) {
+ // Special return value for NaN w/ NaN
+ return 2;
+ }
+ else if( l < r ) {
+ return -1;
+ }
+ else {
+ return 1;
}
}
static uint64_t do_unsigned(uint64_t l, uint64_t r, ::MIR::eBinOp op) {
@@ -188,16 +190,34 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
TU_ARM(lv, Deref, e) {
::HIR::TypeRef ptr_ty;
auto val = get_value_and_type(*e.val, ptr_ty);
- LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value");
- // There MUST be a relocation at this point with a valid allocation.
- auto& val_alloc = val.m_alloc ? val.m_alloc : val.m_value->allocation;
- LOG_ASSERT(val_alloc, "Deref of a value with no allocation (hence no relocations)");
- LOG_TRACE("Deref " << val_alloc.alloc());
- auto alloc = val_alloc.alloc().get_relocation(val.m_offset);
- LOG_ASSERT(alloc, "Deref of a value with no relocation");
- size_t ofs = val.read_usize(0);
ty = ptr_ty.get_inner();
- return ValueRef(::std::move(alloc), ofs, ty.get_size());
+ // TODO: Slices and slice-like types have the same logic.
+ if( ty == RawType::Str )
+ {
+ LOG_ASSERT(val.m_size == 2*POINTER_SIZE, "Deref of a &str that isn't a fat-pointer sized value");
+ // There MUST be a relocation at this point with a valid allocation.
+ auto& val_alloc = val.m_alloc ? val.m_alloc : val.m_value->allocation;
+ LOG_ASSERT(val_alloc, "Deref of a value with no allocation (hence no relocations)");
+ LOG_TRACE("Deref " << val_alloc.alloc());
+ auto alloc = val_alloc.alloc().get_relocation(val.m_offset);
+ LOG_ASSERT(alloc, "Deref of a value with no relocation");
+ size_t ofs = val.read_usize(0);
+ size_t size = val.read_usize(POINTER_SIZE);
+ return ValueRef(::std::move(alloc), ofs, size);
+ }
+ // TODO: Trait objects and trait-object likes
+ else
+ {
+ LOG_ASSERT(val.m_size == POINTER_SIZE, "Deref of a value that isn't a pointer-sized value");
+ // There MUST be a relocation at this point with a valid allocation.
+ auto& val_alloc = val.m_alloc ? val.m_alloc : val.m_value->allocation;
+ LOG_ASSERT(val_alloc, "Deref of a value with no allocation (hence no relocations)");
+ LOG_TRACE("Deref " << val_alloc.alloc());
+ auto alloc = val_alloc.alloc().get_relocation(val.m_offset);
+ LOG_ASSERT(alloc, "Deref of a value with no relocation");
+ size_t ofs = val.read_usize(0);
+ return ValueRef(::std::move(alloc), ofs, ty.get_size());
+ }
} break;
}
throw "";
@@ -285,7 +305,15 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
LOG_TODO("Constant::Bytes");
} break;
TU_ARM(c, StaticString, ce) {
- LOG_TODO("Constant::StaticString");
+ ty = ::HIR::TypeRef(RawType::Str);
+ ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Borrow, 0 });
+ Value val = Value(ty);
+ val.write_usize(0, 0);
+ val.write_usize(POINTER_SIZE, ce.size());
+ val.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_string(&ce) });
+ LOG_DEBUG(c << " = " << val);
+ //return Value::new_dataptr(ce.data());
+ return val;
} break;
TU_ARM(c, ItemAddr, ce) {
// Create a value with a special backing allocation of zero size that references the specified item.
@@ -369,13 +397,21 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
}
alloc = AllocationPtr(src_base_value.m_value->allocation);
}
- LOG_DEBUG("- alloc=" << alloc << " (" << alloc.alloc() << ")");
+ if( alloc.is_alloc() )
+ LOG_DEBUG("- alloc=" << alloc << " (" << alloc.alloc() << ")");
+ else
+ LOG_DEBUG("- alloc=" << alloc);
size_t ofs = src_base_value.m_offset;
+ bool is_slice_like = src_ty.has_slice_meta();
src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast<size_t>(re.type) });
new_val = Value(src_ty);
// ^ Pointer value
new_val.write_usize(0, ofs);
+ if( is_slice_like )
+ {
+ new_val.write_usize(POINTER_SIZE, src_base_value.m_size);
+ }
// - Add the relocation after writing the value (writing clears the relocations)
new_val.allocation.alloc().relocations.push_back(Relocation { 0, ::std::move(alloc) });
} break;
@@ -410,7 +446,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
if( src_ty.get_size() > re.type.get_size() ) {
// TODO: How to casting fat to thin?
- throw "TODO";
+ //LOG_TODO("Handle casting fat to thin, " << src_ty << " -> " << re.type);
+ new_val = src_value.read_value(0, re.type.get_size());
}
else
{
@@ -440,7 +477,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
&& src_ty.wrappers.at(0).type != TypeWrapper::Ty::Borrow ) {
throw "ERROR";
}
- // TODO: MUST be a thin pointer
+ // TODO: MUST be a thin pointer?
// TODO: MUST be an integer (usize only?)
if( re.type != RawType::USize ) {
@@ -525,15 +562,105 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
case RawType::Char:
LOG_TODO("Cast to " << re.type);
case RawType::USize:
- case RawType::ISize:
case RawType::U8:
- case RawType::I8:
case RawType::U16:
- case RawType::I16:
case RawType::U32:
- case RawType::I32:
case RawType::U64:
+ case RawType::ISize:
+ case RawType::I8:
+ case RawType::I16:
+ case RawType::I32:
case RawType::I64:
+ {
+ uint64_t dst_val = 0.0;
+ // Can be an integer, or F32 (pointer is impossible atm)
+ switch(src_ty.inner_type)
+ {
+ case RawType::Unreachable: throw "BUG";
+ case RawType::Composite: throw "ERROR";
+ case RawType::TraitObject: throw "ERROR";
+ case RawType::Function:
+ LOG_ASSERT(re.type.inner_type == RawType::USize, "");
+ new_val = src_value.read_value(0, re.type.get_size());
+ break;
+ case RawType::Char: LOG_TODO("Cast char to integer (only u32)");
+ case RawType::Str: throw "ERROR";
+ case RawType::Unit: throw "ERROR";
+ case RawType::Bool: throw "ERROR";
+ case RawType::F64: throw "BUG";
+ case RawType::F32:
+ dst_val = static_cast<uint64_t>( src_value.read_f32(0) );
+ if(0)
+ case RawType::USize:
+ dst_val = static_cast<uint64_t>( src_value.read_usize(0) );
+ if(0)
+ case RawType::ISize:
+ dst_val = static_cast<uint64_t>( src_value.read_isize(0) );
+ if(0)
+ case RawType::U8:
+ dst_val = static_cast<uint64_t>( src_value.read_u8 (0) );
+ if(0)
+ case RawType::I8:
+ dst_val = static_cast<uint64_t>( src_value.read_i8 (0) );
+ if(0)
+ case RawType::U16:
+ dst_val = static_cast<uint64_t>( src_value.read_u16(0) );
+ if(0)
+ case RawType::I16:
+ dst_val = static_cast<uint64_t>( src_value.read_i16(0) );
+ if(0)
+ case RawType::U32:
+ dst_val = static_cast<uint64_t>( src_value.read_u32(0) );
+ if(0)
+ case RawType::I32:
+ dst_val = static_cast<uint64_t>( src_value.read_i32(0) );
+ if(0)
+ case RawType::U64:
+ dst_val = static_cast<uint64_t>( src_value.read_u64(0) );
+ if(0)
+ case RawType::I64:
+ dst_val = static_cast<uint64_t>( src_value.read_i64(0) );
+
+ switch(re.type.inner_type)
+ {
+ case RawType::USize:
+ new_val.write_usize(0, dst_val);
+ break;
+ case RawType::U8:
+ new_val.write_u8(0, static_cast<uint8_t>(dst_val));
+ break;
+ case RawType::U16:
+ new_val.write_u16(0, static_cast<uint16_t>(dst_val));
+ break;
+ case RawType::U32:
+ new_val.write_u32(0, dst_val);
+ break;
+ case RawType::U64:
+ new_val.write_u64(0, dst_val);
+ break;
+ case RawType::ISize:
+ new_val.write_usize(0, static_cast<int64_t>(dst_val));
+ break;
+ case RawType::I8:
+ new_val.write_i8(0, static_cast<int8_t>(dst_val));
+ break;
+ case RawType::I16:
+ new_val.write_i16(0, static_cast<int16_t>(dst_val));
+ break;
+ case RawType::I32:
+ new_val.write_i32(0, static_cast<int32_t>(dst_val));
+ break;
+ case RawType::I64:
+ new_val.write_i64(0, static_cast<int64_t>(dst_val));
+ break;
+ default:
+ 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);
@@ -559,25 +686,38 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
case ::MIR::eBinOp::LT:
case ::MIR::eBinOp::LE: {
LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
- bool res;
+ int res = 0;
+ // TODO: Handle comparison of the relocations too
+
+ const auto& alloc_l = v_l.m_value ? v_l.m_value->allocation : v_l.m_alloc;
+ const auto& alloc_r = v_r.m_value ? v_r.m_value->allocation : v_r.m_alloc;
+ auto reloc_l = alloc_l ? alloc_l.alloc().get_relocation(0) : AllocationPtr();
+ auto reloc_r = alloc_r ? alloc_r.alloc().get_relocation(0) : AllocationPtr();
+
+ if( reloc_l != reloc_r )
+ {
+ res = (reloc_l < reloc_r ? -1 : 1);
+ }
+ LOG_DEBUG("res=" << res << ", " << reloc_l << " ? " << reloc_r);
+
if( ty_l.wrappers.empty() )
{
switch(ty_l.inner_type)
{
case RawType::U64:
- res = Ops::do_compare(v_l.read_u64(0), v_r.read_u64(0), re.op);
+ res = res != 0 ? res : Ops::do_compare(v_l.read_u64(0), v_r.read_u64(0));
break;
case RawType::U32:
- res = Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0), re.op);
+ res = res != 0 ? res : Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0));
break;
case RawType::U16:
- res = Ops::do_compare(v_l.read_u16(0), v_r.read_u16(0), re.op);
+ res = res != 0 ? res : Ops::do_compare(v_l.read_u16(0), v_r.read_u16(0));
break;
case RawType::U8:
- res = Ops::do_compare(v_l.read_u8(0), v_r.read_u8(0), re.op);
+ res = res != 0 ? res : Ops::do_compare(v_l.read_u8(0), v_r.read_u8(0));
break;
case RawType::USize:
- res = Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0), re.op);
+ res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0));
break;
default:
LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
@@ -586,19 +726,41 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
else if( ty_l.wrappers.front().type == TypeWrapper::Ty::Pointer )
{
// TODO: Technically only EQ/NE are valid.
- res = Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0), re.op);
- // TODO: Compare fat metadata.
- if( v_l.m_size > POINTER_SIZE )
+
+ res = res != 0 ? res : Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0));
+
+ // Compare fat metadata.
+ if( res == 0 && v_l.m_size > POINTER_SIZE )
{
- LOG_TODO("Compare fat pointers (metadata)");
+ reloc_l = v_l.m_alloc ? v_l.m_alloc.alloc().get_relocation(POINTER_SIZE) : AllocationPtr();
+ reloc_r = v_r.m_alloc ? v_r.m_alloc.alloc().get_relocation(POINTER_SIZE) : AllocationPtr();
+
+ if( res == 0 && reloc_l != reloc_r )
+ {
+ res = (reloc_l < reloc_r ? -1 : 1);
+ }
+ res = res != 0 ? res : Ops::do_compare(v_l.read_usize(POINTER_SIZE), v_r.read_usize(POINTER_SIZE));
}
}
else
{
LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
}
+ bool res_bool;
+ switch(re.op)
+ {
+ case ::MIR::eBinOp::EQ: res_bool = (res == 0); break;
+ case ::MIR::eBinOp::NE: res_bool = (res != 0); break;
+ case ::MIR::eBinOp::GT: res_bool = (res == 1); break;
+ case ::MIR::eBinOp::GE: res_bool = (res == 1 || res == 0); break;
+ case ::MIR::eBinOp::LT: res_bool = (res == -1); break;
+ case ::MIR::eBinOp::LE: res_bool = (res == -1 || res == 0); break;
+ break;
+ default:
+ LOG_BUG("Unknown comparison");
+ }
new_val = Value(::HIR::TypeRef(RawType::Bool));
- new_val.write_u8(0, res ? 1 : 0);
+ new_val.write_u8(0, res_bool ? 1 : 0);
} break;
default:
LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
@@ -633,7 +795,64 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
}
} break;
TU_ARM(se.src, UniOp, re) {
- throw "TODO";
+ ::HIR::TypeRef ty;
+ auto v = state.get_value_and_type(re.val, ty);
+ LOG_ASSERT(ty.wrappers.empty(), "UniOp on wrapped type - " << ty);
+ new_val = Value(ty);
+ switch(re.op)
+ {
+ case ::MIR::eUniOp::INV:
+ switch(ty.inner_type)
+ {
+ case RawType::U128:
+ LOG_TODO("UniOp::INV U128");
+ case RawType::U64:
+ new_val.write_u64( 0, ~v.read_u64(0) );
+ break;
+ case RawType::U32:
+ new_val.write_u32( 0, ~v.read_u32(0) );
+ break;
+ case RawType::U16:
+ new_val.write_u16( 0, ~v.read_u16(0) );
+ break;
+ case RawType::U8:
+ new_val.write_u8 ( 0, ~v.read_u8 (0) );
+ break;
+ case RawType::USize:
+ new_val.write_usize( 0, ~v.read_usize(0) );
+ break;
+ case RawType::Bool:
+ new_val.write_u8 ( 0, v.read_u8 (0) == 0 );
+ break;
+ default:
+ LOG_TODO("UniOp::INV - w/ type " << ty);
+ }
+ break;
+ case ::MIR::eUniOp::NEG:
+ switch(ty.inner_type)
+ {
+ case RawType::I128:
+ LOG_TODO("UniOp::NEG I128");
+ case RawType::I64:
+ new_val.write_i64( 0, -v.read_i64(0) );
+ break;
+ case RawType::I32:
+ new_val.write_i32( 0, -v.read_i32(0) );
+ break;
+ case RawType::I16:
+ new_val.write_i16( 0, -v.read_i16(0) );
+ break;
+ case RawType::I8:
+ new_val.write_i8 ( 0, -v.read_i8 (0) );
+ break;
+ case RawType::ISize:
+ new_val.write_isize( 0, -v.read_isize(0) );
+ break;
+ default:
+ LOG_TODO("UniOp::INV - w/ type " << ty);
+ }
+ break;
+ }
} break;
TU_ARM(se.src, DstMeta, re) {
throw "TODO";
@@ -694,16 +913,16 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
state.write_lvalue(se.dst, ::std::move(new_val));
} break;
case ::MIR::Statement::TAG_Asm:
- throw "TODO";
+ LOG_TODO(stmt);
break;
case ::MIR::Statement::TAG_Drop:
- throw "TODO";
+ LOG_TODO(stmt);
break;
case ::MIR::Statement::TAG_SetDropFlag:
- throw "TODO";
+ LOG_TODO(stmt);
break;
case ::MIR::Statement::TAG_ScopeEnd:
- throw "TODO";
+ LOG_TODO(stmt);
break;
}
}
@@ -778,52 +997,15 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
TU_ARM(bb.terminator, SwitchValue, _te)
LOG_TODO("Terminator::SwitchValue");
TU_ARM(bb.terminator, Call, te) {
+ ::std::vector<Value> sub_args; sub_args.reserve(te.args.size());
+ for(const auto& a : te.args)
+ {
+ sub_args.push_back( state.param_to_value(a) );
+ }
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 if( fe.name == "atomic_load" )
- {
- const auto& ptr_param = te.args.at(0);
-
- ::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();
- state.write_lvalue( te.ret_val, alloc.alloc().read_value(ofs, fe.params.tys.at(0).get_size()) );
- }
- else
- {
- LOG_TODO("Terminator::Call - intrinsic \"" << fe.name << "\"");
- }
+ state.write_lvalue(te.ret_val, MIRI_Invoke_Intrinsic(fe.name, fe.params, ::std::move(sub_args)));
}
else
{
@@ -844,11 +1026,6 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
fcn_p = &fcn_alloc_ptr.fcn();
}
- ::std::vector<Value> sub_args; sub_args.reserve(te.args.size());
- for(const auto& a : te.args)
- {
- sub_args.push_back( state.param_to_value(a) );
- }
LOG_DEBUG("Call " << *fcn_p);
state.write_lvalue(te.ret_val, MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args)));
}
@@ -874,6 +1051,59 @@ Value MIRI_Invoke_Extern(const ::std::string& link_name, const ::std::string& ab
LOG_TODO("Call external function " << link_name);
}
}
+Value MIRI_Invoke_Intrinsic(const ::std::string& name, const ::HIR::PathParams& ty_params, ::std::vector<Value> args)
+{
+ Value rv;
+ TRACE_FUNCTION_R(name, rv);
+ if( name == "atomic_store" )
+ {
+ auto& ptr_val = args.at(0);
+ auto& data_val = args.at(1);
+
+ LOG_ASSERT(ptr_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(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)");
+ LOG_TRACE("Deref " << ptr_val.allocation.alloc());
+ auto alloc = ptr_val.allocation.alloc().get_relocation(0);
+ LOG_ASSERT(alloc, "Deref of a value with no relocation");
+
+ // TODO: Atomic side of this?
+ size_t ofs = ptr_val.read_usize(0);
+ const auto& ty = ty_params.tys.at(0);
+ alloc.alloc().write_value(ofs, ::std::move(data_val));
+ }
+ else if( name == "atomic_load" )
+ {
+ auto& ptr_val = args.at(0);
+ LOG_ASSERT(ptr_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(ptr_val.allocation, "Deref of a value with no allocation (hence no relocations)");
+ LOG_TRACE("Deref " << ptr_val.allocation.alloc());
+ auto alloc = ptr_val.allocation.alloc().get_relocation(0);
+ LOG_ASSERT(alloc, "Deref of a value with no relocation");
+
+ // TODO: Atomic side of this?
+ size_t ofs = ptr_val.read_usize(0);
+ const auto& ty = ty_params.tys.at(0);
+ rv = alloc.alloc().read_value(ofs, ty.get_size());
+ }
+ else if( name == "transmute" )
+ {
+ // Transmute requires the same size, so just copying the value works
+ rv = ::std::move(args.at(0));
+ }
+ else if( name == "assume" )
+ {
+ // Assume is a no-op which returns unit
+ }
+ else
+ {
+ LOG_TODO("Call itrinsic \"" << name << "\"");
+ }
+ return rv;
+}
int ProgramOptions::parse(int argc, const char* argv[])
{
diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp
index b0c5f757..522e40dd 100644
--- a/tools/standalone_miri/value.cpp
+++ b/tools/standalone_miri/value.cpp
@@ -25,6 +25,12 @@ AllocationPtr AllocationPtr::new_fcn(::HIR::Path p)
rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::Function) );
return rv;
}
+AllocationPtr AllocationPtr::new_string(const ::std::string* ptr)
+{
+ AllocationPtr rv;
+ rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::StdString) );
+ return rv;
+}
AllocationPtr::AllocationPtr(const AllocationPtr& x):
m_ptr(nullptr)
{
@@ -45,8 +51,10 @@ AllocationPtr::AllocationPtr(const AllocationPtr& x):
m_ptr = reinterpret_cast<void*>( ptr_i + static_cast<uintptr_t>(Ty::Function) );
assert(get_ty() == Ty::Function);
} break;
- case Ty::Unused1:
- throw "BUG";
+ case Ty::StdString:
+ // No ownership semantics, just clone the pointer
+ m_ptr = x.m_ptr;
+ break;
case Ty::Unused2:
throw "BUG";
}
@@ -75,7 +83,8 @@ AllocationPtr::~AllocationPtr()
auto* ptr = const_cast<::HIR::Path*>(&fcn());
delete ptr;
} break;
- case Ty::Unused1: {
+ case Ty::StdString: {
+ // No ownership semantics
} break;
case Ty::Unused2: {
} break;
@@ -93,9 +102,10 @@ AllocationPtr::~AllocationPtr()
os << &x.alloc();
break;
case AllocationPtr::Ty::Function:
- os << *const_cast<::HIR::Path*>(&x.fcn());
+ os << x.fcn();
break;
- case AllocationPtr::Ty::Unused1:
+ case AllocationPtr::Ty::StdString:
+ os << "\"" << x.str() << "\"";
break;
case AllocationPtr::Ty::Unused2:
break;
@@ -283,7 +293,7 @@ void Allocation::write_bytes(size_t ofs, const void* src, size_t count)
}
void Allocation::write_usize(size_t ofs, uint64_t v)
{
- this->write_bytes(0, &v, POINTER_SIZE);
+ this->write_bytes(ofs, &v, POINTER_SIZE);
}
::std::ostream& operator<<(::std::ostream& os, const Allocation& x)
{
@@ -438,7 +448,6 @@ Value Value::read_value(size_t ofs, size_t size) const
{
Value rv;
LOG_DEBUG("(" << ofs << ", " << size << ") - " << *this);
- check_bytes_valid(ofs, size);
if( this->allocation )
{
rv = this->allocation.alloc().read_value(ofs, size);
@@ -448,6 +457,8 @@ Value Value::read_value(size_t ofs, size_t size) const
// Inline can become inline.
rv.direct_data.size = static_cast<uint8_t>(size);
rv.write_bytes(0, this->direct_data.data+ofs, size);
+ rv.direct_data.mask[0] = this->direct_data.mask[0];
+ rv.direct_data.mask[1] = this->direct_data.mask[1];
}
LOG_DEBUG("RETURN " << rv);
return rv;
@@ -482,12 +493,15 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count)
}
else
{
- if(ofs >= this->direct_data.size )
- throw "ERROR";
- if(count > this->direct_data.size )
- throw "ERROR";
- if(ofs+count > this->direct_data.size )
- throw "ERROR";
+ if(ofs >= this->direct_data.size ) {
+ LOG_BUG("Write to offset outside value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")");
+ }
+ if(count > this->direct_data.size ){
+ LOG_BUG("Write larger than value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")");
+ }
+ if(ofs+count > this->direct_data.size ) {
+ LOG_BUG("Write extends outside value size (" << ofs << "+" << count << " >= " << (int)this->direct_data.size << ")");
+ }
::std::memcpy(this->direct_data.data + ofs, src, count);
mark_bytes_valid(ofs, count);
}
@@ -514,7 +528,7 @@ void Value::write_value(size_t ofs, Value v)
}
void Value::write_usize(size_t ofs, uint64_t v)
{
- this->write_bytes(0, &v, POINTER_SIZE);
+ this->write_bytes(ofs, &v, POINTER_SIZE);
}
::std::ostream& operator<<(::std::ostream& os, const Value& v)
diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp
index 32131ab1..baa47e3f 100644
--- a/tools/standalone_miri/value.hpp
+++ b/tools/standalone_miri/value.hpp
@@ -25,7 +25,7 @@ public:
{
Allocation,
Function, // m_ptr is a pointer to the function.
- Unused1,
+ StdString,
Unused2,
};
@@ -42,6 +42,8 @@ public:
AllocationPtr(const AllocationPtr& x);
~AllocationPtr();
static AllocationPtr new_fcn(::HIR::Path p);
+ //static AllocationPtr new_rawdata(const void* buf, size_t len);
+ static AllocationPtr new_string(const ::std::string* s); // NOTE: The string must have a stable pointer
AllocationPtr& operator=(const AllocationPtr& x) = delete;
AllocationPtr& operator=(AllocationPtr&& x) {
@@ -70,6 +72,11 @@ public:
assert(get_ty() == Ty::Function);
return *static_cast<const ::HIR::Path*>(get_ptr());
}
+ const ::std::string& str() const {
+ assert(*this);
+ assert(get_ty() == Ty::StdString);
+ return *static_cast<const ::std::string*>(get_ptr());
+ }
Ty get_ty() const {
return static_cast<Ty>( reinterpret_cast<uintptr_t>(m_ptr) & 3 );