diff options
author | John Hodge <tpg@mutabah.net> | 2018-02-18 18:53:55 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-02-18 18:53:55 +0800 |
commit | 99ae4eb88c2861c74a8a3ab6da53b505024cf2c6 (patch) | |
tree | dee6dfa6e5a2d0d49e7e4f824987699348a4c8af | |
parent | 4539eed0e165b3a6ca9a9e6b935e13a2b680e735 (diff) | |
download | mrust-99ae4eb88c2861c74a8a3ab6da53b505024cf2c6.tar.gz |
Standalone MIRI - Implement BinOp comparisons and Terminator::If
-rw-r--r-- | src/mir/mir.hpp | 4 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 185 | ||||
-rw-r--r-- | vsproject/standalone_miri/standalone_miri.vcxproj | 4 |
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> |