summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2018-02-18 18:53:55 +0800
committerJohn Hodge <tpg@mutabah.net>2018-02-18 18:53:55 +0800
commit99ae4eb88c2861c74a8a3ab6da53b505024cf2c6 (patch)
treedee6dfa6e5a2d0d49e7e4f824987699348a4c8af
parent4539eed0e165b3a6ca9a9e6b935e13a2b680e735 (diff)
downloadmrust-99ae4eb88c2861c74a8a3ab6da53b505024cf2c6.tar.gz
Standalone MIRI - Implement BinOp comparisons and Terminator::If
-rw-r--r--src/mir/mir.hpp4
-rw-r--r--tools/standalone_miri/main.cpp185
-rw-r--r--vsproject/standalone_miri/standalone_miri.vcxproj4
3 files changed, 174 insertions, 19 deletions
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index d4b797ea..31eb9cd7 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -228,8 +228,8 @@ TAGGED_UNION(Terminator, Incomplete,
(Panic, struct { BasicBlockId dst; }), // ?
(If, struct {
LValue cond;
- BasicBlockId bb0;
- BasicBlockId bb1;
+ BasicBlockId bb0; // true
+ BasicBlockId bb1; // false
}),
(Switch, struct {
LValue val;
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp
index be9f6e05..026fba05 100644
--- a/tools/standalone_miri/main.cpp
+++ b/tools/standalone_miri/main.cpp
@@ -48,6 +48,36 @@ int main(int argc, const char* argv[])
return 0;
}
+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 uint64_t do_unsigned(uint64_t l, uint64_t r, ::MIR::eBinOp op) {
+ switch(op)
+ {
+ case ::MIR::eBinOp::ADD: return l + r;
+ case ::MIR::eBinOp::SUB: return l - r;
+ case ::MIR::eBinOp::MUL: return l * r;
+ case ::MIR::eBinOp::DIV: return l / r;
+ case ::MIR::eBinOp::MOD: return l % r;
+ default:
+ LOG_BUG("Unexpected operation in Ops::do_unsigned");
+ }
+ }
+};
+
Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args)
{
TRACE_FUNCTION_R(path, "");
@@ -249,20 +279,20 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
return val;
} break;
TU_ARM(c, Const, ce) {
- throw ::std::runtime_error("BUG: Constant::Const in mmir");
+ LOG_BUG("Constant::Const in mmir");
} break;
TU_ARM(c, Bytes, ce) {
- throw ::std::runtime_error("TODO: Constant::Bytes");
+ LOG_TODO("Constant::Bytes");
} break;
TU_ARM(c, StaticString, ce) {
- throw ::std::runtime_error("TODO: Constant::StaticString");
+ LOG_TODO("Constant::StaticString");
} break;
TU_ARM(c, ItemAddr, ce) {
// Create a value with a special backing allocation of zero size that references the specified item.
if( const auto* fn = modtree.get_function_opt(ce) ) {
return Value::new_fnptr(ce);
}
- throw ::std::runtime_error("TODO: Constant::ItemAddr");
+ LOG_TODO("Constant::ItemAddr - statics?");
} break;
}
throw "";
@@ -289,6 +319,20 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
::HIR::TypeRef ty;
return param_to_value(p, ty);
}
+
+ ValueRef get_value_ref_param(const ::MIR::Param& p, Value& tmp, ::HIR::TypeRef& ty)
+ {
+ switch(p.tag())
+ {
+ case ::MIR::Param::TAGDEAD: throw "";
+ TU_ARM(p, Constant, pe)
+ tmp = const_to_value(pe, ty);
+ return ValueRef(tmp, 0, ty.get_size());
+ TU_ARM(p, LValue, pe)
+ return get_value_and_type(pe, ty);
+ }
+ throw "";
+ }
} state { modtree, fcn, ::std::move(args) };
size_t bb_idx = 0;
@@ -461,8 +505,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
case RawType::Bool: throw "ERROR";
case RawType::F64: throw "BUG";
case RawType::F32: dst_val = static_cast<double>( src_value.read_f32(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: dst_val = static_cast<double>( src_value.read_usize(0) ); break;
+ case RawType::ISize: dst_val = static_cast<double>( src_value.read_isize(0) ); break;
case RawType::U8: dst_val = static_cast<double>( src_value.read_u8 (0) ); break;
case RawType::I8: dst_val = static_cast<double>( src_value.read_i8 (0) ); break;
case RawType::U16: dst_val = static_cast<double>( src_value.read_u16(0) ); break;
@@ -477,9 +521,9 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
new_val.write_f64(0, dst_val);
} break;
case RawType::Bool:
- throw "TODO";
+ LOG_TODO("Cast to " << re.type);
case RawType::Char:
- throw "TODO";
+ LOG_TODO("Cast to " << re.type);
case RawType::USize:
case RawType::ISize:
case RawType::U8:
@@ -492,12 +536,101 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
case RawType::I64:
case RawType::U128:
case RawType::I128:
- throw "TODO";
+ LOG_TODO("Cast to " << re.type);
}
}
} break;
TU_ARM(se.src, BinOp, re) {
- LOG_TODO("Handle BinOp - " << se.src);
+ ::HIR::TypeRef ty_l, ty_r;
+ Value tmp_l, tmp_r;
+ auto v_l = state.get_value_ref_param(re.val_l, tmp_l, ty_l);
+ auto v_r = state.get_value_ref_param(re.val_r, tmp_r, ty_r);
+ //LOG_DEBUG(v_l << " ? " << v_r);
+
+ switch(re.op)
+ {
+ case ::MIR::eBinOp::BIT_SHL:
+ case ::MIR::eBinOp::BIT_SHR:
+ LOG_TODO("BinOp SHL/SHR - can have mismatched types - " << se.src);
+ case ::MIR::eBinOp::EQ:
+ case ::MIR::eBinOp::NE:
+ case ::MIR::eBinOp::GT:
+ case ::MIR::eBinOp::GE:
+ case ::MIR::eBinOp::LT:
+ case ::MIR::eBinOp::LE: {
+ LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
+ bool res;
+ 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);
+ break;
+ case RawType::U32:
+ res = Ops::do_compare(v_l.read_u32(0), v_r.read_u32(0), re.op);
+ break;
+ case RawType::U16:
+ res = Ops::do_compare(v_l.read_u16(0), v_r.read_u16(0), re.op);
+ break;
+ case RawType::U8:
+ res = Ops::do_compare(v_l.read_u8(0), v_r.read_u8(0), re.op);
+ break;
+ case RawType::USize:
+ res = Ops::do_compare(v_l.read_usize(0), v_r.read_usize(0), re.op);
+ break;
+ default:
+ LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
+ }
+ }
+ 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 )
+ {
+ LOG_TODO("Compare fat pointers (metadata)");
+ }
+ }
+ else
+ {
+ LOG_TODO("BinOp comparisons - " << se.src << " w/ " << ty_l);
+ }
+ new_val = Value(::HIR::TypeRef(RawType::Bool));
+ new_val.write_u8(0, res ? 1 : 0);
+ } break;
+ default:
+ LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r);
+ new_val = Value(ty_l);
+ switch(ty_l.inner_type)
+ {
+ case RawType::U128:
+ LOG_TODO("BinOp U128");
+ case RawType::U64:
+ new_val.write_u64( 0, Ops::do_unsigned(v_l.read_u64(0), v_r.read_u64(0), re.op) );
+ break;
+ case RawType::U32:
+ new_val = Value(ty_l);
+ new_val.write_u32( 0, Ops::do_unsigned(v_l.read_u32(0), v_r.read_u32(0), re.op) );
+ break;
+ case RawType::U16:
+ new_val = Value(ty_l);
+ new_val.write_u16( 0, Ops::do_unsigned(v_l.read_u16(0), v_r.read_u16(0), re.op) );
+ break;
+ case RawType::U8:
+ new_val = Value(ty_l);
+ new_val.write_u8 ( 0, Ops::do_unsigned(v_l.read_u8 (0), v_r.read_u8 (0), re.op) );
+ break;
+ case RawType::USize:
+ new_val = Value(ty_l);
+ new_val.write_usize( 0, Ops::do_unsigned(v_l.read_usize(0), v_r.read_usize(0), re.op) );
+ break;
+ default:
+ LOG_TODO("Handle BinOp - w/ type " << ty_l);
+ }
+ break;
+ }
} break;
TU_ARM(se.src, UniOp, re) {
throw "TODO";
@@ -590,8 +723,11 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
continue;
TU_ARM(bb.terminator, Return, _te)
return state.ret;
- TU_ARM(bb.terminator, If, _te)
- LOG_TODO("Terminator::If");
+ TU_ARM(bb.terminator, If, te) {
+ uint8_t v = state.get_value_ref(te.cond).read_u8(0);
+ LOG_ASSERT(v == 0 || v == 1, "");
+ bb_idx = v ? te.bb0 : te.bb1;
+ } continue;
TU_ARM(bb.terminator, Switch, te) {
::HIR::TypeRef ty;
auto v = state.get_value_and_type(te.val, ty);
@@ -665,7 +801,26 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
auto ty = ptr_ty.get_inner();
alloc.alloc().write_value(ofs, state.param_to_value(val_param));
}
- else
+ 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 << "\"");
}
@@ -694,8 +849,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar
{
sub_args.push_back( state.param_to_value(a) );
}
- ::std::cout << "Call " << *fcn_p << ::std::endl;
- MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args));
+ LOG_DEBUG("Call " << *fcn_p);
+ state.write_lvalue(te.ret_val, MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args)));
}
bb_idx = te.ret_block;
} continue;
diff --git a/vsproject/standalone_miri/standalone_miri.vcxproj b/vsproject/standalone_miri/standalone_miri.vcxproj
index 4209e566..66f33ebd 100644
--- a/vsproject/standalone_miri/standalone_miri.vcxproj
+++ b/vsproject/standalone_miri/standalone_miri.vcxproj
@@ -124,7 +124,7 @@
<PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <TreatSpecificWarningsAsErrors>4062;4061;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
+ <TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -144,7 +144,7 @@
<PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
- <TreatSpecificWarningsAsErrors>4062;4061;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
+ <TreatSpecificWarningsAsErrors>4062;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>