diff options
-rw-r--r-- | src/trans/codegen_mmir.cpp | 274 | ||||
-rw-r--r-- | tools/standalone_miri/hir_sim.cpp | 26 | ||||
-rw-r--r-- | tools/standalone_miri/hir_sim.hpp | 1 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 156 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.cpp | 61 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.hpp | 9 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 183 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 72 | ||||
-rw-r--r-- | vsproject/mrustc.vcxproj.filters | 24 | ||||
-rw-r--r-- | vsproject/standalone_miri/standalone_miri.vcxproj | 5 |
10 files changed, 766 insertions, 45 deletions
diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 09167486..d4b9f799 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -97,6 +97,9 @@ namespace os << (sign ? "-" : "+") << "0x1." << ::std::setw(52/4) << ::std::setfill('0') << ::std::hex << frac << ::std::dec << "p" << (exp - 1023); os << " " << v.t; } break; + TU_ARM(e, ItemAddr, v) { + os << "ADDROF " << v; + } break; default: os << e; break; @@ -160,13 +163,13 @@ namespace { m_of << "\tlet m: fn();\n"; m_of << "\t0: {\n"; - m_of << "\t\tASSIGN m = &" << ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "mrustc-main")) << ";\n"; - m_of << "\t\tCALL RETURN = " << ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "start")) << "(m, arg1, arg2) goto 1 else 1\n"; + m_of << "\t\tASSIGN m = ADDROF " << ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "mrustc-main")) << ";\n"; + m_of << "\t\tCALL RETURN = " << ::HIR::GenericPath(m_resolve.m_crate.get_lang_item_path(Span(), "start")) << "(m, arg0, arg1) goto 1 else 1\n"; } else { m_of << "\t0: {\n"; - m_of << "\t\tCALL RETURN = " << ::HIR::GenericPath(c_start_path) << "(arg1, arg2) goto 1 else 1;\n"; + m_of << "\t\tCALL RETURN = " << ::HIR::GenericPath(c_start_path) << "(arg0, arg1) goto 1 else 1;\n"; } m_of << "\t}\n"; m_of << "\t1: {\n"; @@ -509,6 +512,271 @@ namespace #endif m_mir_res = nullptr; } + struct Reloc { + size_t ofs; + size_t len; + const ::HIR::Path* p; + ::std::string bytes; + }; + void emit_literal_as_bytes(const ::HIR::Literal& lit, const ::HIR::TypeRef& ty, ::std::vector<Reloc>& out_relocations, size_t base_ofs) + { + TRACE_FUNCTION_F(lit << ", " << ty); + auto putb = [&](uint8_t b) { + if( b == 0 ) { + m_of << "\\0"; + } + else if( b == '\\' ) { + m_of << "\\\\"; + } + else if( b == '"' ) { + m_of << "\\\""; + } + else if( ' ' <= b && b <= 'z' && b != '\\' ) { + m_of << b; + } + else if( b < 16 ) { + m_of << "\\x0" << ::std::hex << int(b) << ::std::dec; + } + else { + m_of << "\\x" << ::std::hex << int(b) << ::std::dec; + } + }; + auto putu32 = [&](uint32_t v) { + putb(v & 0xFF); + putb(v >> 8); + putb(v >> 16); + putb(v >> 24); + }; + auto putsize = [&](uint64_t v) { + if( true ) { + putu32(v ); + putu32(v >> 32); + } + else { + putu32(v ); + } + }; + switch(ty.m_data.tag()) + { + case ::HIR::TypeRef::Data::TAGDEAD: throw ""; + case ::HIR::TypeRef::Data::TAG_Generic: + case ::HIR::TypeRef::Data::TAG_ErasedType: + case ::HIR::TypeRef::Data::TAG_Diverge: + case ::HIR::TypeRef::Data::TAG_Infer: + case ::HIR::TypeRef::Data::TAG_TraitObject: + case ::HIR::TypeRef::Data::TAG_Slice: + case ::HIR::TypeRef::Data::TAG_Closure: + BUG(sp, "Unexpected " << ty << " in decoding literal"); + TU_ARM(ty.m_data, Primitive, te) { + switch(te) + { + case ::HIR::CoreType::U8: + case ::HIR::CoreType::I8: + case ::HIR::CoreType::Bool: + ASSERT_BUG(sp, lit.is_Integer(), ty << " not Literal::Integer - " << lit); + putb(lit.as_Integer()); + break; + case ::HIR::CoreType::U16: + case ::HIR::CoreType::I16: + ASSERT_BUG(sp, lit.is_Integer(), ty << " not Literal::Integer - " << lit); + putb(lit.as_Integer() & 0xFF); + putb(lit.as_Integer() >> 8); + break; + case ::HIR::CoreType::U32: + case ::HIR::CoreType::I32: + case ::HIR::CoreType::Char: + ASSERT_BUG(sp, lit.is_Integer(), ty << " not Literal::Integer - " << lit); + putu32(lit.as_Integer() ); + break; + case ::HIR::CoreType::U64: + case ::HIR::CoreType::I64: + ASSERT_BUG(sp, lit.is_Integer(), ty << " not Literal::Integer - " << lit); + putu32(lit.as_Integer() ); + putu32(lit.as_Integer() >> 32); + break; + case ::HIR::CoreType::U128: + case ::HIR::CoreType::I128: + ASSERT_BUG(sp, lit.is_Integer(), ty << " not Literal::Integer - " << lit); + putu32(lit.as_Integer() ); + putu32(lit.as_Integer() >> 32); + putu32(0); + putu32(0); + break; + case ::HIR::CoreType::Usize: + case ::HIR::CoreType::Isize: + ASSERT_BUG(sp, lit.is_Integer(), ty << " not Literal::Integer - " << lit); + putsize(lit.as_Integer()); + break; + case ::HIR::CoreType::F32: { + ASSERT_BUG(sp, lit.is_Float(), "not Literal::Float - " << lit); + uint32_t v; + memcpy(&v, &double(lit.as_Float()), 4); + putu32(v); + } break; + case ::HIR::CoreType::F64: { + ASSERT_BUG(sp, lit.is_Float(), "not Literal::Float - " << lit); + uint64_t v; + memcpy(&v, &lit.as_Float(), 8); + putu32(v); + } break; + case ::HIR::CoreType::Str: + BUG(sp, "Unexpected " << ty << " in decoding literal"); + } + } break; + case ::HIR::TypeRef::Data::TAG_Path: + case ::HIR::TypeRef::Data::TAG_Tuple: { + const auto* repr = Target_GetTypeRepr(sp, m_resolve, ty); + assert(repr); + size_t cur_ofs = 0; + if( lit.is_List() ) + { + const auto& le = lit.as_List(); + assert(le.size() == repr->fields.size()); + for(size_t i = 0; i < repr->fields.size(); i ++) + { + assert(cur_ofs <= repr->fields[i].offset); + while(cur_ofs < repr->fields[i].offset) + { + putb(0); + cur_ofs ++; + } + emit_literal_as_bytes(le[i], repr->fields[i].ty, out_relocations, base_ofs + cur_ofs); + size_t size; + assert(Target_GetSizeOf(sp, m_resolve, repr->fields[i].ty, size)); + cur_ofs += size; + } + while(cur_ofs < repr->size) + { + putb(0); + cur_ofs ++; + } + } + else if( lit.is_Variant() ) + { + const auto& le = lit.as_Variant(); + if( *le.val != ::HIR::Literal::make_List({}) ) + { + assert(le.idx < repr->fields.size()); + while(cur_ofs < repr->fields[le.idx].offset) + { + putb(0); + cur_ofs ++; + } + + emit_literal_as_bytes(*le.val, repr->fields[le.idx].ty, out_relocations, base_ofs + cur_ofs); + + size_t size; + assert(Target_GetSizeOf(sp, m_resolve, repr->fields[le.idx].ty, size)); + cur_ofs += size; + } + + if(const auto* ve = repr->variants.opt_Values()) + { + ASSERT_BUG(sp, cur_ofs <= repr->fields[ve->field.index].offset, "Bad offset before enum tag"); + while(cur_ofs < repr->fields[ve->field.index].offset) + { + putb(0); + cur_ofs ++; + } + auto v = ::HIR::Literal::make_Integer(le.idx); + emit_literal_as_bytes(v, repr->fields[ve->field.index].ty, out_relocations, base_ofs + cur_ofs); + } + // TODO: Nonzero? + while(cur_ofs < repr->size) + { + putb(0); + cur_ofs ++; + } + } + else + { + TODO(sp, "Composites - " << ty << " w/ " << lit); + } + } break; + case ::HIR::TypeRef::Data::TAG_Borrow: + if( *ty.m_data.as_Borrow().inner == ::HIR::CoreType::Str ) + { + ASSERT_BUG(sp, lit.is_String(), ty << " not Literal::String - " << lit); + const auto& s = lit.as_String(); + putsize(0); + putsize(s.size()); + out_relocations.push_back(Reloc { base_ofs, 8, nullptr, s }); + break; + } + // fall + case ::HIR::TypeRef::Data::TAG_Pointer: { + const auto& ity = (ty.m_data.is_Borrow() ? *ty.m_data.as_Borrow().inner : *ty.m_data.as_Pointer().inner); + size_t ity_size, ity_align; + Target_GetSizeAndAlignOf(sp, m_resolve, ity, ity_size, ity_align); + bool is_unsized = (ity_size == SIZE_MAX); + if( lit.is_BorrowPath() ) + { + putsize(0); + out_relocations.push_back(Reloc { base_ofs, 8, &lit.as_BorrowPath(), "" }); + if( is_unsized ) + { + // TODO: Get the size of the pointed-to array + // OR: Find out the source item type and the target trait. + putsize(0); + } + break; + } + else if( lit.is_Integer() ) + { + ASSERT_BUG(sp, lit.as_Integer() == 0, "Pointer from integer not 0"); + ASSERT_BUG(sp, ty.m_data.is_Pointer(), "Borrow from integer"); + putsize(0); + if( is_unsized ) + { + putsize(0); + } + break; + } + TODO(sp, "Pointers - " << ty << " w/ " << lit); + } break; + case ::HIR::TypeRef::Data::TAG_Function: + ASSERT_BUG(sp, lit.is_BorrowPath(), ty << " not Literal::BorrowPath - " << lit); + putsize(0); + out_relocations.push_back(Reloc { base_ofs, 8, &lit.as_BorrowPath(), "" }); + break; + TU_ARM(ty.m_data, Array, te) { + // What about byte strings? + // TODO: Assert size + ASSERT_BUG(sp, lit.is_List(), "not Literal::List - " << lit); + for(const auto& v : lit.as_List()) + { + emit_literal_as_bytes(v, *te.inner, out_relocations, base_ofs); + size_t size; + assert(Target_GetSizeOf(sp, m_resolve, *te.inner, size)); + base_ofs += size; + } + } break; + } + } + void emit_static_local(const ::HIR::Path& p, const ::HIR::Static& item, const Trans_Params& params) override + { + ::MIR::Function empty_fcn; + ::MIR::TypeResolve top_mir_res { sp, m_resolve, FMT_CB(ss, ss << "static " << p;), ::HIR::TypeRef(), {}, empty_fcn }; + m_mir_res = &top_mir_res; + + TRACE_FUNCTION_F(p); + + ::std::vector<Reloc> relocations; + + auto type = params.monomorph(m_resolve, item.m_type); + m_of << "static " << p << ": " << type << " = \""; + emit_literal_as_bytes(item.m_value_res, type, relocations, 0); + m_of << "\""; + m_of << "{"; + for(const auto& r : relocations) + { + // TODO. + } + m_of << "}"; + m_of << ";\n"; + + m_mir_res = nullptr; + } void emit_function_code(const ::HIR::Path& p, const ::HIR::Function& item, const Trans_Params& params, bool is_extern_def, const ::MIR::FunctionPointer& code) override { TRACE_FUNCTION_F(p); diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index 0010e202..7fccc806 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -6,6 +6,8 @@ #include "hir_sim.hpp" #include "module_tree.hpp" +const size_t POINTER_SIZE = 8; + //::HIR::Path::Path(::HIR::SimplePath sp) //{ //} @@ -22,6 +24,7 @@ size_t HIR::TypeRef::get_size(size_t ofs) const case RawType::Composite: return this->composite_type->size; case RawType::Unreachable: + case RawType::TraitObject: case RawType::Str: throw "Invalid"; case RawType::U8: case RawType::I8: @@ -35,6 +38,16 @@ size_t HIR::TypeRef::get_size(size_t ofs) const case RawType::U128: case RawType::I128: return 16; + case RawType::Bool: + return 1; + case RawType::Char: + return 4; + + case RawType::F32: + return 4; + case RawType::F64: + return 8; + case RawType::Function: // This should probably be invalid? case RawType::USize: case RawType::ISize: return POINTER_SIZE; @@ -52,7 +65,10 @@ size_t HIR::TypeRef::get_size(size_t ofs) const { // Need to look up the metadata type for the actual type if( this->inner_type == RawType::Composite ) - throw "TODO"; + { + ::std::cerr << "TODO: Check metadata type for pointer " << *this << ", assuming none" << ::std::endl; + return POINTER_SIZE; + } else if( this->inner_type == RawType::Str ) return POINTER_SIZE*2; else if( this->inner_type == RawType::TraitObject ) @@ -175,6 +191,12 @@ namespace HIR { case RawType::Unreachable: os << "!"; break; + case RawType::Function: + os << "function_?"; + break; + case RawType::TraitObject: + os << "traitobject_?"; + break; case RawType::Bool: os << "bool"; break; case RawType::Char: os << "char"; break; case RawType::Str: os << "str"; break; @@ -191,6 +213,8 @@ namespace HIR { case RawType::I128: os << "i128"; break; case RawType::USize: os << "usize"; break; case RawType::ISize: os << "isize"; break; + case RawType::F32: os << "f32"; break; + case RawType::F64: os << "f64"; break; } for(auto it = x.wrappers.rbegin(); it != x.wrappers.rend(); ++it) { diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 1303f077..96887536 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -82,6 +82,7 @@ namespace HIR { /// Definition of a type struct TypeRef { + // Top to bottom list of wrappers (first entry is the outermost wrapper) ::std::vector<TypeWrapper> wrappers; RawType inner_type = RawType::Unit; const DataType* composite_type = nullptr; diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index a6a58a91..c7069ed2 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -7,8 +7,6 @@ #include <algorithm> #include <iomanip> -#pragma warning( error : 4061) - struct ProgramOptions { ::std::string infile; @@ -16,7 +14,7 @@ struct ProgramOptions int parse(int argc, const char* argv[]); }; -Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args); +Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args); int main(int argc, const char* argv[]) { @@ -31,15 +29,32 @@ int main(int argc, const char* argv[]) tree.load_file(opts.infile); - auto rv = MIRI_Invoke(tree, tree.find_lang_item("start"), {}); + auto val_argc = Value( ::HIR::TypeRef{RawType::I32} ); + ::HIR::TypeRef argv_ty { RawType::I8 }; + argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 }); + argv_ty.wrappers.push_back(TypeWrapper { TypeWrapper::Ty::Pointer, 0 }); + auto val_argv = Value(argv_ty); + val_argc.write_bytes(0, "\0\0\0", 4); + val_argv.write_bytes(0, "\0\0\0\0\0\0\0", argv_ty.get_size()); + + ::std::vector<Value> args; + args.push_back(::std::move(val_argc)); + args.push_back(::std::move(val_argv)); + auto rv = MIRI_Invoke( tree, tree.find_lang_item("start"), ::std::move(args) ); ::std::cout << rv << ::std::endl; return 0; } -Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args) +Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args) { + //TRACE_FUNCTION_FR(path,path) const auto& fcn = modtree.get_function(path); + for(size_t i = 0; i < args.size(); i ++) + { + //DEBUG(a); + ::std::cout << "Argument(" << i << ") = " << args[i] << ::std::endl; + } ::std::vector<bool> drop_flags = fcn.m_mir.drop_flags; ::std::vector<Value> locals; locals.reserve( fcn.m_mir.locals.size() ); @@ -52,12 +67,14 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val struct State { + ModuleTree& modtree; const Function& fcn; Value ret; ::std::vector<Value> args; ::std::vector<Value> locals; - State(const Function& fcn, ::std::vector<Value> args): + State(ModuleTree& modtree, const Function& fcn, ::std::vector<Value> args): + modtree(modtree), fcn(fcn), ret(fcn.ret_ty), args(::std::move(args)) @@ -73,6 +90,7 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val { switch(lv.tag()) { + case ::MIR::LValue::TAGDEAD: throw ""; TU_ARM(lv, Return, _e) { ofs = 0; ty = fcn.ret_ty; @@ -88,6 +106,9 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val ty = fcn.args.at(e.idx); return args.at(e.idx); } break; + TU_ARM(lv, Static, e) { + return modtree.get_static(e); + } break; TU_ARM(lv, Index, e) { auto idx = read_lvalue(*e.idx).as_usize(); ::HIR::TypeRef array_ty; @@ -118,6 +139,23 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val ofs += inner_ofs; return base_val; } + TU_ARM(lv, Downcast, e) { + ::HIR::TypeRef composite_ty; + auto& base_val = get_value_type_and_ofs(*e.val, ofs, composite_ty); + + size_t inner_ofs; + ty = composite_ty.get_field(e.variant_index, inner_ofs); + ::std::cerr << "TODO: Read from Downcast - " << lv << ::std::endl; + throw "TODO"; + ofs += inner_ofs; + return base_val; + } + TU_ARM(lv, Deref, e) { + //auto addr = read_lvalue(*e.val); + + ::std::cerr << "TODO: Read from deref - " << lv << ::std::endl; + throw "TODO"; + } break; } throw ""; } @@ -161,6 +199,7 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val { switch(c.tag()) { + case ::MIR::Constant::TAGDEAD: throw ""; TU_ARM(c, Int, ce) { ty = ::HIR::TypeRef(ce.t); Value val = Value(ty); @@ -174,6 +213,42 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian return val; } break; + TU_ARM(c, Bool, ce) { + Value val = Value(::HIR::TypeRef { RawType::Bool }); + val.write_bytes(0, &ce.v, 1); + return val; + } break; + TU_ARM(c, Float, ce) { + ty = ::HIR::TypeRef(ce.t); + Value val = Value(ty); + if( ce.t.raw_type == RawType::F64 ) { + val.write_bytes(0, &ce.v, ::std::min(ty.get_size(), sizeof(ce.v))); // TODO: Endian/format? + } + else if( ce.t.raw_type == RawType::F32 ) { + float v = static_cast<float>(ce.v); + val.write_bytes(0, &v, ::std::min(ty.get_size(), sizeof(v))); // TODO: Endian/format? + } + else { + throw ::std::runtime_error("BUG: Invalid type in Constant::Float"); + } + return val; + } break; + TU_ARM(c, Const, ce) { + throw ::std::runtime_error("BUG: Constant::Const in mmir"); + } break; + TU_ARM(c, Bytes, ce) { + throw ::std::runtime_error("TODO: Constant::Bytes"); + } break; + TU_ARM(c, StaticString, ce) { + throw ::std::runtime_error("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"); + } break; } throw ""; } @@ -186,6 +261,7 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val { switch(p.tag()) { + case ::MIR::Param::TAGDEAD: throw ""; TU_ARM(p, Constant, pe) return const_to_value(pe, ty); TU_ARM(p, LValue, pe) @@ -198,7 +274,7 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val ::HIR::TypeRef ty; return param_to_value(p, ty); } - } state { fcn, ::std::move(args) }; + } state { modtree, fcn, ::std::move(args) }; size_t bb_idx = 0; for(;;) @@ -210,16 +286,38 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val ::std::cout << "BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt << ::std::endl; switch(stmt.tag()) { + case ::MIR::Statement::TAGDEAD: throw ""; TU_ARM(stmt, Assign, se) { Value val; switch(se.src.tag()) { + case ::MIR::RValue::TAGDEAD: throw ""; 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, Borrow, re) { + ::HIR::TypeRef src_ty; + size_t ofs = 0; + Value& base_value = state.get_value_type_and_ofs(re.val, ofs, src_ty); + if( !base_value.allocation ) + { + // TODO: Need to convert this value into an allocation version + ::std::cerr << "TODO: RValue::Borrow - " << se.src << " - convert to non-inline" << ::std::endl; + throw "TODO"; + //base_value.to_allocation(); + } + ofs += base_value.meta.indirect_meta.offset; + src_ty.wrappers.insert(src_ty.wrappers.begin(), TypeWrapper { TypeWrapper::Ty::Borrow, static_cast<size_t>(re.type) }); + Value new_val = Value(src_ty); + // ^ Pointer value + new_val.allocation.alloc().relocations.push_back(Relocation { 0, base_value.allocation }); + new_val.write_bytes(0, &ofs, src_ty.get_size()); + ::std::cerr << "TODO: RValue::Borrow - " << se.src << ::std::endl; + throw "TODO"; + } break; TU_ARM(se.src, SizedArray, re) { throw "TODO"; } break; @@ -272,17 +370,61 @@ Value MIRI_Invoke(const ModuleTree& modtree, ::HIR::Path path, ::std::vector<Val case ::MIR::Statement::TAG_SetDropFlag: throw "TODO"; break; + case ::MIR::Statement::TAG_ScopeEnd: + throw "TODO"; + break; } } ::std::cout << "BB" << bb_idx << "/TERM: " << bb.terminator << ::std::endl; switch(bb.terminator.tag()) { + case ::MIR::Terminator::TAGDEAD: throw ""; + TU_ARM(bb.terminator, Incomplete, _te) + throw ::std::runtime_error("BUG: Terminator::Incomplete hit"); + TU_ARM(bb.terminator, Diverge, _te) + throw ::std::runtime_error("BUG: Terminator::Diverge hit"); + TU_ARM(bb.terminator, Panic, _te) + throw ::std::runtime_error("TODO: Terminator::Panic"); TU_ARM(bb.terminator, Goto, te) bb_idx = te; continue; TU_ARM(bb.terminator, Return, _te) return state.ret; + TU_ARM(bb.terminator, If, _te) + throw ::std::runtime_error("TODO: Terminator::If"); + TU_ARM(bb.terminator, Switch, _te) + throw ::std::runtime_error("TODO: Terminator::Switch"); + TU_ARM(bb.terminator, SwitchValue, _te) + throw ::std::runtime_error("TODO: Terminator::SwitchValue"); + TU_ARM(bb.terminator, Call, te) { + if( te.fcn.is_Intrinsic() ) { + throw ::std::runtime_error("TODO: Terminator::Call - intrinsic"); + } + else { + const ::HIR::Path* fcn_p; + if( te.fcn.is_Path() ) { + fcn_p = &te.fcn.as_Path(); + } + else { + ::HIR::TypeRef ty; + auto v = state.read_lvalue_with_ty(te.fcn.as_Value(), ty); + // TODO: Assert type + // TODO: Assert offset/content. + assert(v.as_usize() == 0); + fcn_p = &v.allocation.alloc().relocations.at(0).backing_alloc.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) ); + } + ::std::cout << "TODO: Call " << *fcn_p << ::std::endl; + MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args)); + } + throw ::std::runtime_error("TODO: Terminator::Call"); + } break; } throw ""; } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index f056481b..90d599c8 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -3,6 +3,7 @@ // #include "module_tree.hpp" #include "lex.hpp" +#include "value.hpp" #include <iostream> ModuleTree::ModuleTree() @@ -73,7 +74,7 @@ bool Parser::parse_one() else if( lex.consume_if("fn") ) { auto p = parse_path(); - //::std::cout << "DEBUG:p arse_one - fn " << p << ::std::endl; + //::std::cout << "DEBUG: parse_one - fn " << p << ::std::endl; lex.check_consume('('); ::std::vector<::HIR::TypeRef> arg_tys; @@ -91,17 +92,33 @@ bool Parser::parse_one() } auto body = parse_body(); - tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(arg_tys), rv_ty, ::std::move(body) }) ); + auto p2 = p; + tree.functions.insert( ::std::make_pair(::std::move(p), Function { ::std::move(p2), ::std::move(arg_tys), rv_ty, ::std::move(body) }) ); } else if( lex.consume_if("static") ) { auto p = parse_path(); //::std::cout << "DEBUG: parse_one - static " << p << ::std::endl; + lex.check_consume(':'); + auto ty = parse_type(); + // TODO: externs? lex.check_consume('='); - // TODO: Body? Value? - //auto body = parse_body(); - //auto data = ::std::move(lex.consume().strval); - throw "TODO"; + lex.check(TokenClass::String); + auto data = ::std::move(lex.consume().strval); + if( lex.consume_if('{') ) + { + while( !lex.consume_if('}') ) + { + // TODO: Parse relocation entries + throw "TODO"; + } + } + lex.check_consume(';'); + + Value val = Value(ty); + val.write_bytes(0, data.data(), data.size()); + + tree.statics.insert(::std::make_pair( ::std::move(p), ::std::move(val) )); } else if( lex.consume_if("type") ) { @@ -354,7 +371,7 @@ bool Parser::parse_one() else if( p.lex.consume_if("false") ) { return ::MIR::Constant::make_Bool({ false }); } - else if( p.lex.consume_if("&") ) { + else if( p.lex.consume_if("ADDROF") ) { auto path = p.parse_path(); return ::MIR::Constant::make_ItemAddr({ ::std::move(path) }); @@ -371,6 +388,7 @@ bool Parser::parse_one() if( p.lex.next() == TokenClass::Integer || p.lex.next() == TokenClass::String || p.lex.next() == TokenClass::ByteString || p.lex.next() == '+' || p.lex.next() == '-' || p.lex.next() == '&' || p.lex.next() == "true" || p.lex.next() == "false" + || p.lex.next() == "ADDROF" ) { return parse_const(p); @@ -432,6 +450,7 @@ bool Parser::parse_one() if( lex.next() == TokenClass::Integer || lex.next() == TokenClass::String || lex.next() == TokenClass::ByteString || lex.next() == '+' || lex.next() == '-' || lex.next() == "true" || lex.next() == "false" + || lex.next() == "ADDROF" ) { src_rval = H::parse_const(*this); @@ -1203,4 +1222,32 @@ const Function& ModuleTree::get_function(const ::HIR::Path& p) const throw ""; } return it->second; +} +const Function* ModuleTree::get_function_opt(const ::HIR::Path& p) const +{ + auto it = functions.find(p); + if(it == functions.end()) + { + return nullptr; + } + return &it->second; +} +Value& ModuleTree::get_static(const ::HIR::Path& p) +{ + auto it = statics.find(p); + if(it == statics.end()) + { + ::std::cerr << "Unable to find static " << p << " for invoke" << ::std::endl; + throw ""; + } + return it->second; +} +Value* ModuleTree::get_static_opt(const ::HIR::Path& p) +{ + auto it = statics.find(p); + if(it == statics.end()) + { + return nullptr; + } + return &it->second; }
\ No newline at end of file diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp index ce831621..96a77718 100644 --- a/tools/standalone_miri/module_tree.hpp +++ b/tools/standalone_miri/module_tree.hpp @@ -10,8 +10,11 @@ #include "../../src/mir/mir.hpp" #include "hir_sim.hpp" +struct Value; + struct Function { + ::HIR::Path my_path; ::std::vector<::HIR::TypeRef> args; ::HIR::TypeRef ret_ty; ::MIR::Function m_mir; @@ -25,6 +28,9 @@ class ModuleTree ::std::set<::std::string> loaded_files; ::std::map<::HIR::Path, Function> functions; + ::std::map<::HIR::Path, Value> statics; + // TODO: statics + // Hack: Tuples are stored as `::""::<A,B,C,...>` ::std::map<::HIR::GenericPath, ::std::unique_ptr<DataType>> data_types; public: @@ -34,6 +40,9 @@ public: ::HIR::SimplePath find_lang_item(const char* name) const; const Function& get_function(const ::HIR::Path& p) const; + const Function* get_function_opt(const ::HIR::Path& p) const; + Value& get_static(const ::HIR::Path& p); + Value* get_static_opt(const ::HIR::Path& p); }; // struct/union/enum diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index e04154f6..59b68ea0 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -8,6 +8,54 @@ #include <iomanip> #include <algorithm> + +AllocationPtr Allocation::new_alloc(size_t size) +{ + Allocation* rv = new Allocation(); + rv->refcount = 1; + rv->data.resize( (size + 8-1) / 8 ); // QWORDS + rv->mask.resize( (size + 8-1) / 8 ); // bitmap bytes + return AllocationPtr(rv); +} +AllocationPtr AllocationPtr::new_fcn(::HIR::Path p) +{ + AllocationPtr rv; + auto* ptr = new ::HIR::Path(::std::move(p)); + rv.m_ptr = reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(ptr) + static_cast<uintptr_t>(Ty::Function) ); + return rv; +} +AllocationPtr::AllocationPtr(const AllocationPtr& x): + m_ptr(x.m_ptr) +{ + if( is_alloc() ) { + assert(alloc().refcount != SIZE_MAX); + alloc().refcount += 1; + } +} +AllocationPtr::~AllocationPtr() +{ + if( *this ) + { + switch(get_ty()) + { + case Ty::Allocation: { + auto* ptr = &alloc(); + ptr->refcount -= 1; + if(ptr->refcount == 0) + delete ptr; + } break; + case Ty::Function: { + auto* ptr = const_cast<::HIR::Path*>(&fcn()); + delete ptr; + } break; + case Ty::Unused1: { + } break; + case Ty::Unused2: { + } break; + } + } +} + Value::Value() { this->meta.direct_data.size = 0; @@ -18,6 +66,7 @@ Value::Value(::HIR::TypeRef ty) { size_t size = ty.get_size(); #if 1 + // Support inline data if the data will fit within the inline region (which is the size of the metadata) if( ty.get_size() <= sizeof(this->meta.direct_data.data) ) { struct H @@ -26,6 +75,11 @@ Value::Value(::HIR::TypeRef ty) { if( ty.wrappers.empty() || ::std::all_of(ty.wrappers.begin(), ty.wrappers.end(), [](const auto& x){ return x.type == TypeWrapper::Ty::Array; }) ) { + // TODO: Function pointers should be _pointers_ + if( ty.inner_type == RawType::Function ) + { + return true; + } // Check the inner type if( ty.inner_type != RawType::Composite ) { @@ -45,28 +99,69 @@ Value::Value(::HIR::TypeRef ty) if( ! H::has_pointer(ty) ) { // Will fit in a inline allocation, nice. + ::std::cout << "Value::Value(): No pointers in " << ty << ", storing inline" << ::std::endl; this->meta.direct_data.size = static_cast<uint8_t>(size); + this->meta.direct_data.mask[0] = 0; + this->meta.direct_data.mask[1] = 0; return ; } } #endif // Fallback: Make a new allocation - throw "TODO"; + ::std::cout << "Value::Value(): Creating allocation for " << ty << ::std::endl; + this->allocation = Allocation::new_alloc(size); + this->meta.indirect_meta.offset = 0; + this->meta.indirect_meta.size = size; +} +Value Value::new_fnptr(const ::HIR::Path& fn_path) +{ + Value rv( ::HIR::TypeRef(::HIR::CoreType { RawType::Function }) ); + assert(rv.allocation); + rv.allocation.alloc().relocations.push_back(Relocation { 0, AllocationPtr::new_fcn(fn_path) }); + rv.allocation.alloc().data.at(0) = 0; + rv.allocation.alloc().mask.at(0) = 0xFF; // TODO: Get pointer size and make that much valid instead of 8 bytes + return rv; } void Value::check_bytes_valid(size_t ofs, size_t size) const { if( this->allocation ) { - throw "TODO"; + const auto& alloc = this->allocation.alloc(); + if( ofs >= this->meta.indirect_meta.size || ofs+size > this->meta.indirect_meta.size ) { + ::std::cerr << "ERROR: OOB read" << ::std::endl; + throw "ERROR"; + } + ofs += this->meta.indirect_meta.offset; + //assert(ofs + size < alloc.size()); + for(size_t i = ofs; i < ofs + size; i++) + { + if( !(alloc.mask[i/8] & (1 << i%8)) ) + { + ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl; + throw "ERROR"; + } + } } else { - for(size_t i = 0; i < this->meta.direct_data.size; i++) + if( size == 0 && this->meta.direct_data.size > 0 ) { + return ; + } + if( ofs >= this->meta.direct_data.size ) { + ::std::cerr << "ERROR: OOB read" << ::std::endl; + throw "ERROR"; + } + if( ofs+size > this->meta.direct_data.size ) { + ::std::cerr << "ERROR: OOB read" << ::std::endl; + throw "ERROR"; + } + for(size_t i = ofs; i < ofs + size; i++) { if( !(this->meta.direct_data.mask[i/8] & (1 << i%8)) ) { + ::std::cerr << "ERROR: Invalid bytes in value" << ::std::endl; throw "ERROR"; } } @@ -76,7 +171,14 @@ void Value::mark_bytes_valid(size_t ofs, size_t size) { if( this->allocation ) { - throw "TODO"; + auto& alloc = this->allocation.alloc(); + // TODO: Assert range. + ofs += this->meta.indirect_meta.offset; + assert( (ofs+size+8-1) / 8 < alloc.mask.size() ); + for(size_t i = ofs; i < ofs + size; i++) + { + alloc.mask[i/8] |= (1 << i%8); + } } else { @@ -93,7 +195,29 @@ Value Value::read_value(size_t ofs, size_t size) const check_bytes_valid(ofs, size); if( this->allocation ) { - throw "TODO"; + const auto& alloc = this->allocation.alloc(); + // TODO: Determine if this can become an inline allocation. + bool has_reloc = false; + for(const auto& r : alloc.relocations) + { + if( this->meta.indirect_meta.offset+ofs <= r.slot_ofs && r.slot_ofs < this->meta.indirect_meta.offset + ofs + size ) + { + has_reloc = true; + } + } + Value rv; + if( has_reloc && size < sizeof(this->meta.direct_data.data) ) + { + rv.allocation = Allocation::new_alloc(size); + rv.meta.indirect_meta.offset = 0; + rv.meta.indirect_meta.size = size; + } + else + { + rv.meta.direct_data.size = static_cast<uint8_t>(size); + } + rv.write_bytes(0, this->data_ptr() + ofs, size); + return rv; } else { @@ -114,7 +238,12 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count) { if( this->allocation ) { - throw "TODO"; + if(ofs >= this->meta.indirect_meta.size ) + throw "ERROR"; + if(count > this->meta.indirect_meta.size ) + throw "ERROR"; + if(ofs+count > this->meta.indirect_meta.size ) + throw "ERROR"; } else { @@ -124,21 +253,36 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count) throw "ERROR"; if(ofs+count > this->meta.direct_data.size ) throw "ERROR"; - ::std::memcpy(this->meta.direct_data.data+ofs, src, count); - mark_bytes_valid(ofs, count); } + ::std::memcpy(this->data_ptr() + ofs, src, count); + mark_bytes_valid(ofs, count); } void Value::write_value(size_t ofs, Value v) { if( v.allocation ) { - throw "TODO"; + v.check_bytes_valid(0, v.meta.indirect_meta.size); + const auto& src_alloc = v.allocation.alloc(); + write_bytes(ofs, v.data_ptr(), v.meta.indirect_meta.size); + // Find any relocations that apply and copy those in. + // - Any relocations in the source within `v.meta.indirect_meta.offset` .. `v.meta.indirect_meta.offset + v.meta.indirect_meta.size` + for(const auto& r : src_alloc.relocations) + { + // TODO: Negative offsets in destination? + if( v.meta.indirect_meta.offset <= r.slot_ofs && r.slot_ofs < v.meta.indirect_meta.offset + v.meta.indirect_meta.size ) + { + // Applicable + if( !this->allocation ) { + throw ::std::runtime_error("TODO: Writing value with a relocation into a slot without a relocation"); + } + this->allocation.alloc().relocations.push_back( r ); + } + } } else { v.check_bytes_valid(0, v.meta.direct_data.size); write_bytes(ofs, v.meta.direct_data.data, v.meta.direct_data.size); - mark_bytes_valid(ofs, meta.direct_data.size); } } @@ -146,7 +290,7 @@ size_t Value::as_usize() const { uint64_t v; this->read_bytes(0, &v, 8); - // TODO: Handle endian + // TODO: Handle endian and different architectures return v; } ::std::ostream& operator<<(::std::ostream& os, const Value& v) @@ -155,7 +299,22 @@ size_t Value::as_usize() const os << ::std::hex; if( v.allocation ) { - throw "TODO"; + const auto& alloc = v.allocation.alloc(); + for(size_t i = 0; i < v.meta.indirect_meta.size; i++) + { + if( i != 0 ) + os << " "; + size_t j = i + v.meta.indirect_meta.offset; + + if( alloc.mask[j/8] & (1 << i%8) ) + { + os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[j]; + } + else + { + os << "--"; + } + } } else { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 65403a81..9f9e68f4 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -6,33 +6,95 @@ #include <vector> #include <memory> #include <cstdint> +#include <cassert> namespace HIR { struct TypeRef; + struct Path; } class Allocation; + class AllocationPtr { friend class Allocation; - Allocation* m_ptr; + void* m_ptr; +public: + + enum class Ty + { + Allocation, + Function, // m_ptr is a pointer to the function. + Unused1, + Unused2, + }; + +private: + AllocationPtr(Allocation* p): + m_ptr(p) + { + } public: AllocationPtr(): m_ptr(nullptr) {} + AllocationPtr(AllocationPtr&& x): m_ptr(x.m_ptr) { + x.m_ptr = nullptr; + } + AllocationPtr(const AllocationPtr& x); + ~AllocationPtr(); + static AllocationPtr new_fcn(::HIR::Path p); + + AllocationPtr& operator=(AllocationPtr&& x) { + this->~AllocationPtr(); + this->m_ptr = x.m_ptr; + x.m_ptr = nullptr; + return *this; + } operator bool() const { return m_ptr != 0; } - Allocation& operator*() { return *m_ptr; } - Allocation* operator->() { return m_ptr; } + bool is_alloc() { + return *this && get_ty() == Ty::Allocation; + } + Allocation& alloc() { + assert(get_ty() == Ty::Allocation); + return *static_cast<Allocation*>(get_ptr()); + } + const Allocation& alloc() const { + assert(get_ty() == Ty::Allocation); + return *static_cast<Allocation*>(get_ptr()); + } + const ::HIR::Path& fcn() const { + assert(get_ty() == Ty::Function); + return *static_cast<const ::HIR::Path*>(get_ptr()); + } + + Ty get_ty() const { + return static_cast<Ty>( reinterpret_cast<uintptr_t>(m_ptr) & 3 ); + } +private: + void* get_ptr() const { + return reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(m_ptr) & ~3 ); + } }; struct Relocation { + // Offset within parent allocation where this relocation is performed. + // TODO: Size? size_t slot_ofs; AllocationPtr backing_alloc; }; class Allocation { + friend class AllocationPtr; size_t refcount; + // TODO: Read-only flag? public: + static AllocationPtr new_alloc(size_t size); + + const uint8_t* data_ptr() const { return reinterpret_cast<const uint8_t*>(this->data.data()); } + uint8_t* data_ptr() { return reinterpret_cast< uint8_t*>(this->data.data()); } + ::std::vector<uint64_t> data; + ::std::vector<uint8_t> mask; ::std::vector<Relocation> relocations; }; @@ -54,6 +116,7 @@ struct Value Value(); Value(::HIR::TypeRef ty); + static Value new_fnptr(const ::HIR::Path& fn_path); void check_bytes_valid(size_t ofs, size_t size) const; void mark_bytes_valid(size_t ofs, size_t size); @@ -65,5 +128,8 @@ struct Value void write_bytes(size_t ofs, const void* src, size_t count); size_t as_usize() const; +private: + const uint8_t* data_ptr() const { return allocation ? allocation.alloc().data_ptr() + meta.indirect_meta.offset : meta.direct_data.data; } + uint8_t* data_ptr() { return allocation ? allocation.alloc().data_ptr() + meta.indirect_meta.offset : meta.direct_data.data; } }; extern ::std::ostream& operator<<(::std::ostream& os, const Value& v); diff --git a/vsproject/mrustc.vcxproj.filters b/vsproject/mrustc.vcxproj.filters index 6c0ba794..997e4849 100644 --- a/vsproject/mrustc.vcxproj.filters +++ b/vsproject/mrustc.vcxproj.filters @@ -412,9 +412,6 @@ <ClInclude Include="..\src\hir_expand\main_bindings.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\hir_typeck\main_bindings.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\include\cpp_unpack.h"> <Filter>Header Files</Filter> </ClInclude> @@ -460,18 +457,9 @@ <ClInclude Include="..\src\parse\lex.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\parse\parseerror.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\resolve\main_bindings.hpp"> <Filter>Header Files</Filter> </ClInclude> - <ClInclude Include="..\src\trans\main_bindings.hpp"> - <Filter>Header Files</Filter> - </ClInclude> - <ClInclude Include="..\src\trans\mangling.hpp"> - <Filter>Header Files</Filter> - </ClInclude> <ClInclude Include="..\src\ast\attrs.hpp"> <Filter>Header Files\ast</Filter> </ClInclude> @@ -601,6 +589,18 @@ <ClInclude Include="..\src\hir\hir.hpp"> <Filter>Header Files\hir</Filter> </ClInclude> + <ClInclude Include="..\src\hir_typeck\main_bindings.hpp"> + <Filter>Header Files\hir_typeck</Filter> + </ClInclude> + <ClInclude Include="..\src\trans\main_bindings.hpp"> + <Filter>Header Files\trans</Filter> + </ClInclude> + <ClInclude Include="..\src\trans\mangling.hpp"> + <Filter>Header Files\trans</Filter> + </ClInclude> + <ClInclude Include="..\src\parse\parseerror.hpp"> + <Filter>Header Files\parse</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <None Include="packages.config" /> diff --git a/vsproject/standalone_miri/standalone_miri.vcxproj b/vsproject/standalone_miri/standalone_miri.vcxproj index e992e3df..ed5dc733 100644 --- a/vsproject/standalone_miri/standalone_miri.vcxproj +++ b/vsproject/standalone_miri/standalone_miri.vcxproj @@ -90,6 +90,7 @@ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatSpecificWarningsAsErrors>4062;4061;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -105,6 +106,7 @@ <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatSpecificWarningsAsErrors>4062;4061;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -122,6 +124,7 @@ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatSpecificWarningsAsErrors>4062;4061;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -141,6 +144,7 @@ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> + <TreatSpecificWarningsAsErrors>4062;4061;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors> </ClCompile> <Link> <SubSystem>Console</SubSystem> @@ -153,6 +157,7 @@ <Text Include="ReadMe.txt" /> </ItemGroup> <ItemGroup> + <ClInclude Include="..\..\tools\standalone_miri\debug.h" /> <ClInclude Include="..\..\tools\standalone_miri\hir_sim.hpp" /> <ClInclude Include="..\..\tools\standalone_miri\lex.hpp" /> <ClInclude Include="..\..\tools\standalone_miri\module_tree.hpp" /> |