diff options
Diffstat (limited to 'tools/standalone_miri/main.cpp')
-rw-r--r-- | tools/standalone_miri/main.cpp | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp new file mode 100644 index 00000000..a6a58a91 --- /dev/null +++ b/tools/standalone_miri/main.cpp @@ -0,0 +1,325 @@ +// +// +// +#include <iostream> +#include "module_tree.hpp" +#include "value.hpp" +#include <algorithm> +#include <iomanip> + +#pragma warning( error : 4061) + +struct ProgramOptions +{ + ::std::string infile; + + int parse(int argc, const char* argv[]); +}; + +Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args); + +int main(int argc, const char* argv[]) +{ + ProgramOptions opts; + + if( opts.parse(argc, argv) ) + { + return 1; + } + + auto tree = ModuleTree {}; + + tree.load_file(opts.infile); + + auto rv = MIRI_Invoke(tree, tree.find_lang_item("start"), {}); + ::std::cout << rv << ::std::endl; + + return 0; +} + +Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args) +{ + const auto& fcn = modtree.get_function(path); + + ::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 + { + const Function& fcn; + Value ret; + ::std::vector<Value> args; + ::std::vector<Value> locals; + + State(const Function& fcn, ::std::vector<Value> args): + fcn(fcn), + ret(fcn.ret_ty), + args(::std::move(args)) + { + locals.reserve(fcn.m_mir.locals.size()); + for(const auto& ty : fcn.m_mir.locals) + { + locals.push_back(Value(ty)); + } + } + + Value& get_value_type_and_ofs(const ::MIR::LValue& lv, size_t& ofs, ::HIR::TypeRef& ty) + { + switch(lv.tag()) + { + TU_ARM(lv, Return, _e) { + ofs = 0; + ty = fcn.ret_ty; + return ret; + } break; + TU_ARM(lv, Local, e) { + ofs = 0; + ty = fcn.m_mir.locals.at(e); + return locals.at(e); + } break; + TU_ARM(lv, Argument, e) { + ofs = 0; + ty = fcn.args.at(e.idx); + return args.at(e.idx); + } break; + TU_ARM(lv, Index, e) { + auto idx = read_lvalue(*e.idx).as_usize(); + ::HIR::TypeRef array_ty; + auto& base_val = get_value_type_and_ofs(*e.val, ofs, array_ty); + if( array_ty.wrappers.empty() ) + throw "ERROR"; + if( array_ty.wrappers.front().type == TypeWrapper::Ty::Array ) + { + ty = array_ty.get_inner(); + ofs += ty.get_size() * idx; + return base_val; + } + else if( array_ty.wrappers.front().type == TypeWrapper::Ty::Slice ) + { + throw "TODO"; + } + else + { + throw "ERROR"; + } + } break; + TU_ARM(lv, Field, e) { + ::HIR::TypeRef composite_ty; + auto& base_val = get_value_type_and_ofs(*e.val, ofs, composite_ty); + ::std::cout << "get_type_and_ofs: " << composite_ty << ::std::endl; + size_t inner_ofs; + ty = composite_ty.get_field(e.field_index, inner_ofs); + ofs += inner_ofs; + return base_val; + } + } + throw ""; + } + + ::HIR::TypeRef get_lvalue_ty(const ::MIR::LValue& lv) + { + ::HIR::TypeRef ty; + size_t ofs = 0; + get_value_type_and_ofs(lv, ofs, ty); + return ty; + } + + Value read_lvalue_with_ty(const ::MIR::LValue& lv, ::HIR::TypeRef& ty) + { + ::std::cout << "read_lvalue_with_ty: " << lv << ::std::endl; + size_t ofs = 0; + Value& base_value = get_value_type_and_ofs(lv, ofs, ty); + + ::std::cout << "> read_lvalue_with_ty: " << ty << ::std::endl; + + return base_value.read_value(ofs, ty.get_size()); + } + Value read_lvalue(const ::MIR::LValue& lv) + { + ::std::cout << "read_lvalue: " << lv << ::std::endl; + ::HIR::TypeRef ty; + return read_lvalue_with_ty(lv, ty); + } + void write_lvalue(const ::MIR::LValue& lv, Value val) + { + ::std::cout << "write_lvaue: " << lv << ::std::endl; + //::std::cout << "write_lvaue: " << lv << " = " << val << ::std::endl; + ::HIR::TypeRef ty; + size_t ofs = 0; + Value& base_value = get_value_type_and_ofs(lv, ofs, ty); + + base_value.write_value(ofs, val); + } + + Value const_to_value(const ::MIR::Constant& c, ::HIR::TypeRef& ty) + { + switch(c.tag()) + { + TU_ARM(c, Int, ce) { + ty = ::HIR::TypeRef(ce.t); + Value val = Value(ty); + val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian + // TODO: If the write was clipped, sign-extend + return val; + } break; + TU_ARM(c, Uint, ce) { + ty = ::HIR::TypeRef(ce.t); + Value val = Value(ty); + val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian + return val; + } break; + } + throw ""; + } + Value const_to_value(const ::MIR::Constant& c) + { + ::HIR::TypeRef ty; + return const_to_value(c, ty); + } + Value param_to_value(const ::MIR::Param& p, ::HIR::TypeRef& ty) + { + switch(p.tag()) + { + TU_ARM(p, Constant, pe) + return const_to_value(pe, ty); + TU_ARM(p, LValue, pe) + return read_lvalue_with_ty(pe, ty); + } + throw ""; + } + Value param_to_value(const ::MIR::Param& p) + { + ::HIR::TypeRef ty; + return param_to_value(p, ty); + } + } state { fcn, ::std::move(args) }; + + size_t bb_idx = 0; + for(;;) + { + const auto& bb = fcn.m_mir.blocks.at(bb_idx); + + for(const auto& stmt : bb.statements) + { + ::std::cout << "BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt << ::std::endl; + switch(stmt.tag()) + { + TU_ARM(stmt, Assign, se) { + Value val; + switch(se.src.tag()) + { + TU_ARM(se.src, Use, re) { + state.write_lvalue(se.dst, state.read_lvalue(re)); + } break; + TU_ARM(se.src, Constant, re) { + state.write_lvalue(se.dst, state.const_to_value(re)); + } break; + TU_ARM(se.src, SizedArray, re) { + throw "TODO"; + } break; + TU_ARM(se.src, Cast, re) { + throw "TODO"; + } break; + TU_ARM(se.src, BinOp, re) { + throw "TODO"; + } break; + TU_ARM(se.src, UniOp, re) { + throw "TODO"; + } break; + TU_ARM(se.src, DstMeta, re) { + throw "TODO"; + } break; + TU_ARM(se.src, DstPtr, re) { + throw "TODO"; + } break; + TU_ARM(se.src, MakeDst, re) { + throw "TODO"; + } break; + TU_ARM(se.src, Tuple, re) { + ::HIR::TypeRef dst_ty; + size_t ofs = 0; + Value& base_value = state.get_value_type_and_ofs(se.dst, ofs, dst_ty); + + for(size_t i = 0; i < re.vals.size(); i++) + { + auto fld_ofs = dst_ty.composite_type->fields.at(i).first; + base_value.write_value(ofs + fld_ofs, state.param_to_value(re.vals[i])); + } + } break; + TU_ARM(se.src, Array, re) { + throw "TODO"; + } break; + TU_ARM(se.src, Variant, re) { + throw "TODO"; + } break; + TU_ARM(se.src, Struct, re) { + throw "TODO"; + } break; + } + } break; + case ::MIR::Statement::TAG_Asm: + throw "TODO"; + break; + case ::MIR::Statement::TAG_Drop: + throw "TODO"; + break; + case ::MIR::Statement::TAG_SetDropFlag: + throw "TODO"; + break; + } + } + + ::std::cout << "BB" << bb_idx << "/TERM: " << bb.terminator << ::std::endl; + switch(bb.terminator.tag()) + { + TU_ARM(bb.terminator, Goto, te) + bb_idx = te; + continue; + TU_ARM(bb.terminator, Return, _te) + return state.ret; + } + throw ""; + } + + throw ""; +} + +int ProgramOptions::parse(int argc, const char* argv[]) +{ + bool all_free = false; + for(int argidx = 1; argidx < argc; argidx ++) + { + const char* arg = argv[argidx]; + if( arg[0] != '-' || all_free ) + { + // Free + if( this->infile == "" ) + { + this->infile = arg; + } + else + { + // TODO: Too many free arguments + } + } + else if( arg[1] != '-' ) + { + // Short + } + else if( arg[2] != '\0' ) + { + // Long + } + else + { + all_free = true; + } + } + return 0; +} |