diff options
author | John Hodge <tpg@mutabah.net> | 2018-02-16 20:51:04 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2018-02-16 20:51:04 +0800 |
commit | 75413b30fcf5dd97ddf44daa90fe1e361098d9e0 (patch) | |
tree | 18dbe1eb09bf0491194255813134b33814d82ac3 | |
parent | 97156f41a6831d0bfb8870a3757a2b19cd4d2495 (diff) | |
download | mrust-75413b30fcf5dd97ddf44daa90fe1e361098d9e0.tar.gz |
Standalone MIRI - Hacking along, hit a blocker that will need some refactor.
-rw-r--r-- | src/trans/codegen_mmir.cpp | 23 | ||||
-rw-r--r-- | tools/standalone_miri/debug.cpp | 42 | ||||
-rw-r--r-- | tools/standalone_miri/debug.hpp | 38 | ||||
-rw-r--r-- | tools/standalone_miri/hir_sim.cpp | 16 | ||||
-rw-r--r-- | tools/standalone_miri/hir_sim.hpp | 10 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 229 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.cpp | 126 | ||||
-rw-r--r-- | tools/standalone_miri/module_tree.hpp | 9 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 165 | ||||
-rw-r--r-- | tools/standalone_miri/value.hpp | 27 | ||||
-rw-r--r-- | vsproject/standalone_miri/standalone_miri.vcxproj | 7 | ||||
-rw-r--r-- | vsproject/standalone_miri/standalone_miri.vcxproj.filters | 6 |
12 files changed, 605 insertions, 93 deletions
diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 3f947b46..345a5703 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -424,15 +424,20 @@ namespace TU_ARM(repr->variants, None, _e) (void)_e; break; TU_ARM(repr->variants, Values, e) - for(auto v : e.values) + for(const auto& v : e.values) { - m_of << "\t[" << e.field.index << ", " << e.field.sub_fields << "] = \""; + // Variants require: + m_of << "\t#" << (&v - e.values.data()); + // - Data field number (optional) + if( !item.is_value() ) + { + m_of << " =" << (&v - e.values.data()); + } + // - Tag offsetr + m_of << " @[" << e.field.index << ", " << e.field.sub_fields << "] = \""; for(size_t i = 0; i < e.field.size; i ++) { int val = (v >> (i*8)) & 0xFF; - //if( val == 0 ) - // m_of << "\\0"; - //else if(val < 16) m_of << ::std::hex << "\\x0" << val << ::std::dec; else @@ -442,12 +447,13 @@ namespace } break; TU_ARM(repr->variants, NonZero, e) { - m_of << "\t[" << e.field.index << ", " << e.field.sub_fields << "] = \""; + m_of << "\t#" << int(e.zero_variant) << " @[" << e.field.index << ", " << e.field.sub_fields << "] = \""; for(size_t i = 0; i < e.field.size; i ++) { m_of << "\\0"; } m_of << "\";\n"; + m_of << "\t#" << int(1 - e.zero_variant) << ";\n"; } break; } m_of << "}\n"; @@ -805,6 +811,11 @@ namespace m_mir_res = &mir_res; m_of << "fn " << p << "("; + for(unsigned int i = 0; i < item.m_args.size(); i ++) + { + if( i != 0 ) m_of << ", "; + m_of << params.monomorph(m_resolve, item.m_args[i].second); + } m_of << "): " << ret_type << " {\n"; for(unsigned int i = 0; i < code->locals.size(); i ++) { DEBUG("var" << i << " : " << code->locals[i]); diff --git a/tools/standalone_miri/debug.cpp b/tools/standalone_miri/debug.cpp new file mode 100644 index 00000000..503d775a --- /dev/null +++ b/tools/standalone_miri/debug.cpp @@ -0,0 +1,42 @@ +#include "debug.hpp" + +DebugSink::DebugSink(::std::ostream& inner): + m_inner(inner) +{ +} +DebugSink::~DebugSink() +{ + m_inner << "\n"; +} +bool DebugSink::enabled(const char* fcn_name) +{ + return true; +} +DebugSink DebugSink::get(const char* fcn_name, const char* file, unsigned line, DebugLevel lvl) +{ + switch(lvl) + { + case DebugLevel::Trace: + ::std::cout << "Trace: " << file << ":" << line << ": "; + break; + case DebugLevel::Debug: + ::std::cout << "DEBUG: " << fcn_name << ": "; + break; + case DebugLevel::Notice: + ::std::cout << "NOTE: "; + break; + case DebugLevel::Warn: + ::std::cout << "WARN: "; + break; + case DebugLevel::Error: + ::std::cout << "ERROR: "; + break; + case DebugLevel::Fatal: + ::std::cout << "FATAL: "; + break; + case DebugLevel::Bug: + ::std::cout << "BUG: " << fcn_name << ": "; + break; + } + return DebugSink(::std::cout); +}
\ No newline at end of file diff --git a/tools/standalone_miri/debug.hpp b/tools/standalone_miri/debug.hpp new file mode 100644 index 00000000..77295aa2 --- /dev/null +++ b/tools/standalone_miri/debug.hpp @@ -0,0 +1,38 @@ +// +// +// +#pragma once + +#include <iostream> + +enum class DebugLevel { + Trace, + Debug, + Notice, + Warn, + Error, + Fatal, + Bug, +}; + +class DebugSink +{ + ::std::ostream& m_inner; + DebugSink(::std::ostream& inner); +public: + ~DebugSink(); + + template<typename T> + ::std::ostream& operator<<(const T& v) { return m_inner << v; } + + static bool enabled(const char* fcn_name); + static DebugSink get(const char* fcn_name, const char* file, unsigned line, DebugLevel lvl); +}; + +#define LOG_TRACE(strm) do { if(DebugSink::enabled(__FUNCTION__)) DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Trace) << strm; } while(0) +#define LOG_DEBUG(strm) do { if(DebugSink::enabled(__FUNCTION__)) DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Debug) << strm; } while(0) +#define LOG_ERROR(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Error) << strm; exit(1); } while(0) +#define LOG_FATAL(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Fatal) << strm; exit(1); } while(0) +#define LOG_TODO(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "TODO: " << strm; abort(); } while(0) +#define LOG_BUG(strm) do { DebugSink::get(__FUNCTION__,__FILE__,__LINE__,DebugLevel::Bug) << "BUG: " << strm; abort(); } while(0) +#define LOG_ASSERT(cnd) do { if( !(cnd) ) { LOG_BUG("Assertion failure: " #cnd); } } while(0) diff --git a/tools/standalone_miri/hir_sim.cpp b/tools/standalone_miri/hir_sim.cpp index c4232343..d3ccddc7 100644 --- a/tools/standalone_miri/hir_sim.cpp +++ b/tools/standalone_miri/hir_sim.cpp @@ -133,6 +133,22 @@ HIR::TypeRef HIR::TypeRef::get_field(size_t idx, size_t& ofs) const throw "ERROR"; } } +size_t HIR::TypeRef::get_field_ofs(size_t base_idx, const ::std::vector<size_t>& other_idx, TypeRef& ty) const +{ + assert(this->wrappers.size() == 0); + assert(this->inner_type == RawType::Composite); + size_t ofs = this->composite_type->fields.at(base_idx).first; + const auto* ty_p = &this->composite_type->fields.at(base_idx).second; + for(auto idx : other_idx) + { + assert(ty_p->wrappers.size() == 0); + assert(ty_p->inner_type == RawType::Composite); + ofs += ty_p->composite_type->fields.at(idx).first; + ty_p = &ty_p->composite_type->fields.at(idx).second; + } + ty = *ty_p; + return ofs; +} namespace HIR { ::std::ostream& operator<<(::std::ostream& os, const ::HIR::BorrowType& x) diff --git a/tools/standalone_miri/hir_sim.hpp b/tools/standalone_miri/hir_sim.hpp index 96887536..d0f04578 100644 --- a/tools/standalone_miri/hir_sim.hpp +++ b/tools/standalone_miri/hir_sim.hpp @@ -119,6 +119,14 @@ namespace HIR { TypeRef get_inner() const; TypeRef get_field(size_t idx, size_t& ofs) const; + bool operator==(const RawType& x) const { + if( this->wrappers.size() != 0 ) + return false; + return this->inner_type == x; + } + bool operator!=(const RawType& x) const { + return !(*this == x); + } bool operator==(const TypeRef& x) const { return !(*this != x); } @@ -135,6 +143,8 @@ namespace HIR { return false; } + size_t get_field_ofs(size_t idx, const ::std::vector<size_t>& other_idx, TypeRef& ty) const; + friend ::std::ostream& operator<<(::std::ostream& os, const TypeRef& x); }; diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 8a54c321..d1163c14 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -6,6 +6,7 @@ #include "value.hpp" #include <algorithm> #include <iomanip> +#include "debug.hpp" struct ProgramOptions { @@ -48,12 +49,11 @@ int main(int argc, const char* argv[]) Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> args) { - //TRACE_FUNCTION_FR(path,path) + LOG_DEBUG(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; + LOG_DEBUG("- Argument(" << i << ") = " << args[i]); } ::std::vector<bool> drop_flags = fcn.m_mir.drop_flags; @@ -134,7 +134,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar 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; + LOG_DEBUG("Field - " << composite_ty); size_t inner_ofs; ty = composite_ty.get_field(e.field_index, inner_ofs); ofs += inner_ofs; @@ -146,16 +146,23 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar 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"; + LOG_TODO("Read from Downcast - " << lv); ofs += inner_ofs; return base_val; } TU_ARM(lv, Deref, e) { - //auto addr = read_lvalue(*e.val); + ::HIR::TypeRef ptr_ty; + auto addr = read_lvalue_with_ty(*e.val, ptr_ty); + // There MUST be a relocation at this point with a valid allocation. + auto& reloc = addr.allocation.alloc().relocations.at(0); + assert(reloc.slot_ofs == 0); + ofs = addr.read_usize(0); + // Need to make a new Value to return as the base value. + // - This value needs to be stored somewhere. + // - Shoudl the value directly reference into the pointer? + //auto rv = Value(ptr_ty.get_inner(), reloc.backing_alloc, ofs); + LOG_TODO("Read from deref - " << lv << " - " << addr); - ::std::cerr << "TODO: Read from deref - " << lv << ::std::endl; - throw "TODO"; } break; } throw ""; @@ -171,24 +178,19 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar 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; + //LOG_DEBUG(lv << " = " << val); ::HIR::TypeRef ty; size_t ofs = 0; Value& base_value = get_value_type_and_ofs(lv, ofs, ty); @@ -284,7 +286,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar for(const auto& stmt : bb.statements) { - ::std::cout << "BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt << ::std::endl; + LOG_DEBUG("BB" << bb_idx << "/" << (&stmt - bb.statements.data()) << ": " << stmt); switch(stmt.tag()) { case ::MIR::Statement::TAGDEAD: throw ""; @@ -316,18 +318,180 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar // ^ Pointer value new_val.allocation.alloc().relocations.push_back(Relocation { 0, src_base_value.allocation }); new_val.write_bytes(0, &ofs, src_ty.get_size()); + LOG_DEBUG("- " << new_val); ::HIR::TypeRef dst_ty; // TODO: Check type equality size_t dst_ofs = 0; Value& dst_base_value = state.get_value_type_and_ofs(se.dst, dst_ofs, dst_ty); dst_base_value.write_value(dst_ofs, ::std::move(new_val)); + LOG_DEBUG("- " << dst_base_value); } break; TU_ARM(se.src, SizedArray, re) { throw "TODO"; } break; TU_ARM(se.src, Cast, re) { - throw "TODO"; + // Determine the type of cast, is it a reinterpret or is it a value transform? + // - Float <-> integer is a transform, anything else should be a reinterpret. + ::HIR::TypeRef src_ty; + Value src_value = state.read_lvalue_with_ty(re.val, src_ty); + + ::HIR::TypeRef dst_ty; + size_t dst_ofs = 0; + Value& dst_base_value = state.get_value_type_and_ofs(se.dst, dst_ofs, dst_ty); + + Value new_val = Value(re.type); + if( re.type == src_ty ) + { + // No-op cast + new_val = ::std::move(src_value); + } + else if( !re.type.wrappers.empty() ) + { + // Destination can only be a raw pointer + if( re.type.wrappers.at(0).type != TypeWrapper::Ty::Pointer ) { + throw "ERROR"; + } + if( !src_ty.wrappers.empty() ) + { + // Source can be either + if( src_ty.wrappers.at(0).type != TypeWrapper::Ty::Pointer + && src_ty.wrappers.at(0).type != TypeWrapper::Ty::Borrow ) { + throw "ERROR"; + } + + if( src_ty.get_size() > re.type.get_size() ) { + // TODO: How to casting fat to thin? + throw "TODO"; + } + else + { + new_val = ::std::move(src_value); + } + } + else + { + if( src_ty == RawType::Function ) + { + } + else if( src_ty == RawType::USize ) + { + } + else + { + ::std::cerr << "ERROR: Trying to pointer (" << re.type <<" ) from invalid type (" << src_ty << ")\n"; + throw "ERROR"; + } + new_val = ::std::move(src_value); + } + } + else if( !src_ty.wrappers.empty() ) + { + // TODO: top wrapper MUST be a pointer + if( src_ty.wrappers.at(0).type != TypeWrapper::Ty::Pointer + && src_ty.wrappers.at(0).type != TypeWrapper::Ty::Borrow ) { + throw "ERROR"; + } + // TODO: MUST be a thin pointer + + // TODO: MUST be an integer (usize only?) + if( src_ty != RawType::USize ) { + throw "ERROR"; + } + new_val = ::std::move(src_value); + } + else + { + // TODO: What happens if there'a cast of something with a relocation? + switch(re.type.inner_type) + { + case RawType::Unreachable: throw "BUG"; + case RawType::Composite: throw "ERROR"; + case RawType::TraitObject: throw "ERROR"; + case RawType::Function: throw "ERROR"; + case RawType::Str: throw "ERROR"; + case RawType::Unit: throw "ERROR"; + case RawType::F32: { + float dst_val = 0.0; + // Can be an integer, or F64 (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: throw "ERROR"; + case RawType::Char: throw "ERROR"; + case RawType::Str: throw "ERROR"; + case RawType::Unit: throw "ERROR"; + case RawType::Bool: throw "ERROR"; + case RawType::F32: throw "BUG"; + case RawType::F64: dst_val = static_cast<float>( src_value.read_f64(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::U8: dst_val = static_cast<float>( src_value.read_u8 (0) ); break; + case RawType::I8: dst_val = static_cast<float>( src_value.read_i8 (0) ); break; + case RawType::U16: dst_val = static_cast<float>( src_value.read_u16(0) ); break; + case RawType::I16: dst_val = static_cast<float>( src_value.read_i16(0) ); break; + case RawType::U32: dst_val = static_cast<float>( src_value.read_u32(0) ); break; + case RawType::I32: dst_val = static_cast<float>( src_value.read_i32(0) ); break; + case RawType::U64: dst_val = static_cast<float>( src_value.read_u64(0) ); break; + case RawType::I64: dst_val = static_cast<float>( src_value.read_i64(0) ); 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; + } + new_val.write_f32(0, dst_val); + } break; + case RawType::F64: { + double 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: throw "ERROR"; + case RawType::Char: throw "ERROR"; + 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<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::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; + case RawType::I16: dst_val = static_cast<double>( src_value.read_i16(0) ); break; + case RawType::U32: dst_val = static_cast<double>( src_value.read_u32(0) ); break; + case RawType::I32: dst_val = static_cast<double>( src_value.read_i32(0) ); break; + case RawType::U64: dst_val = static_cast<double>( src_value.read_u64(0) ); break; + case RawType::I64: dst_val = static_cast<double>( src_value.read_i64(0) ); 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; + } + new_val.write_f64(0, dst_val); + } break; + case RawType::Bool: + throw "TODO"; + case RawType::Char: + throw "TODO"; + 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::I64: + case RawType::U128: + case RawType::I128: + throw "TODO"; + } + } + + dst_base_value.write_value(dst_ofs, ::std::move(new_val)); } break; TU_ARM(se.src, BinOp, re) { throw "TODO"; @@ -359,7 +523,34 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar throw "TODO"; } break; TU_ARM(se.src, Variant, re) { - throw "TODO"; + ::HIR::TypeRef dst_ty; + size_t dst_ofs = 0; + Value& dst_base_value = state.get_value_type_and_ofs(se.dst, dst_ofs, dst_ty); + + // 1. Get the composite by path. + const auto& ty = state.modtree.get_composite(re.path); + // Three cases: + // - Unions (no tag) + // - Data enums (tag and data) + // - Value enums (no data) + const auto& var = ty.variants.at(re.index); + if( var.data_field != SIZE_MAX ) + { + const auto& fld = ty.fields.at(re.index); + + dst_base_value.write_value(dst_ofs + fld.first, state.param_to_value(re.val)); + } + if( var.base_field != SIZE_MAX ) + { + ::HIR::TypeRef tag_ty; + size_t tag_ofs = dst_ty.get_field_ofs(var.base_field, var.field_path, tag_ty); + LOG_ASSERT(tag_ty.get_size() == var.tag_data.size()); + dst_base_value.write_bytes(dst_ofs + tag_ofs, var.tag_data.data(), var.tag_data.size()); + } + else + { + // Union, no tag + } } break; TU_ARM(se.src, Struct, re) { throw "TODO"; @@ -416,7 +607,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar auto v = state.read_lvalue_with_ty(te.fcn.as_Value(), ty); // TODO: Assert type // TODO: Assert offset/content. - assert(v.as_usize() == 0); + assert(v.read_usize(0) == 0); fcn_p = &v.allocation.alloc().relocations.at(0).backing_alloc.fcn(); } diff --git a/tools/standalone_miri/module_tree.cpp b/tools/standalone_miri/module_tree.cpp index 90d599c8..321eaad9 100644 --- a/tools/standalone_miri/module_tree.cpp +++ b/tools/standalone_miri/module_tree.cpp @@ -5,6 +5,7 @@ #include "lex.hpp" #include "value.hpp" #include <iostream> +#include "debug.hpp" ModuleTree::ModuleTree() { @@ -109,8 +110,31 @@ bool Parser::parse_one() { while( !lex.consume_if('}') ) { - // TODO: Parse relocation entries - throw "TODO"; + lex.check_consume('@'); + lex.check(TokenClass::Integer); + auto ofs = lex.consume().integer(); + lex.check_consume('+'); + lex.check(TokenClass::Integer); + auto size = lex.consume().integer(); + lex.check_consume('='); + if( lex.next() == TokenClass::String ) + { + auto reloc_str = ::std::move(lex.consume().strval); + // TODO: Add relocation + } + else if( lex.next() == "::" ) + { + auto reloc_path = parse_path(); + // TODO: Add relocation + } + else + { + throw "ERROR"; + } + if( ! lex.consume_if(',') ) { + lex.check_consume('}'); + break ; + } } } lex.check_consume(';'); @@ -147,50 +171,76 @@ bool Parser::parse_one() //rv->dst_meta = ::HIR::TypeRef::diverge(); } - // Data - while(lex.next() == TokenClass::Integer) + while( lex.next() != '}' ) { - size_t ofs = lex.consume().integer(); - lex.check_consume('='); - auto ty = parse_type(); - lex.check_consume(';'); - //::std::cout << ofs << " " << ty << ::std::endl; + // Data + if(lex.next() == TokenClass::Integer) + { + size_t ofs = lex.consume().integer(); + lex.check_consume('='); + auto ty = parse_type(); + lex.check_consume(';'); + //::std::cout << ofs << " " << ty << ::std::endl; - rv.fields.push_back(::std::make_pair(ofs, ::std::move(ty))); - } - // Variants - while(lex.next() == '[') - { - lex.consume(); - size_t base_idx = lex.consume().integer(); - ::std::vector<size_t> other_idx; - if( lex.consume_if(',') ) + rv.fields.push_back(::std::make_pair(ofs, ::std::move(ty))); + } + // Variants + else if(lex.next() == TokenClass::Ident && lex.next().strval[0] == '#' ) { - while(lex.next() != ']') + size_t var_idx = ::std::stoi(lex.consume().strval.substr(1)); + + size_t data_fld = SIZE_MAX; + if( lex.consume_if('=') ) { - lex.check(TokenClass::Integer); - other_idx.push_back( lex.consume().integer() ); - if( !lex.consume_if(',') ) - break; + data_fld = lex.consume().integer(); } - } - lex.check_consume(']'); - lex.check_consume('='); - lex.check(TokenClass::String); - uint64_t v = 0; - int pos = 0; - for(auto ch : lex.next().strval) - { - if(pos < 64) + + size_t tag_ofs = SIZE_MAX; + + size_t base_idx = SIZE_MAX; + ::std::vector<size_t> other_idx; + ::std::string tag_value; + if( lex.consume_if('@') ) + { + lex.check_consume('['); + base_idx = lex.consume().integer(); + if( lex.consume_if(',') ) + { + while(lex.next() != ']') + { + lex.check(TokenClass::Integer); + other_idx.push_back( lex.consume().integer() ); + if( !lex.consume_if(',') ) + break; + } + } + lex.check_consume(']'); + + lex.check_consume('='); + lex.check(TokenClass::String); + tag_value = ::std::move(lex.consume().strval); + + //tag_ofs = rv.fields.at(base_idx).first; + //const auto* tag_ty = &rv.fields.at(base_idx).second; + //for(auto idx : other_idx) + //{ + // assert(tag_ty->wrappers.size() == 0); + // assert(tag_ty->inner_type == RawType::Composite); + // LOG_TODO(lex << "Calculate tag offset with nested tag - " << idx << " ty=" << *tag_ty); + //} + } + lex.check_consume(';'); + + if( rv.variants.size() <= var_idx ) { - v |= static_cast<uint64_t>(ch) << pos; + rv.variants.resize(var_idx+1); } - pos += 8; + rv.variants[var_idx] = { data_fld, base_idx, other_idx, tag_value }; + } + else + { + LOG_BUG(""); } - lex.consume(); - lex.check_consume(';'); - - rv.variants.push_back({ base_idx, other_idx, v }); } lex.check_consume('}'); diff --git a/tools/standalone_miri/module_tree.hpp b/tools/standalone_miri/module_tree.hpp index 96a77718..dd302367 100644 --- a/tools/standalone_miri/module_tree.hpp +++ b/tools/standalone_miri/module_tree.hpp @@ -43,6 +43,10 @@ public: 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); + + const DataType& get_composite(const ::HIR::GenericPath& p) const { + return *data_types.at(p); + } }; // struct/union/enum @@ -57,9 +61,12 @@ struct DataType ::std::vector<::std::pair<size_t, ::HIR::TypeRef>> fields; // Values for variants struct VariantValue { + size_t data_field; size_t base_field; ::std::vector<size_t> field_path; - uint64_t value; // TODO: This should be arbitary data? what size? + + //size_t tag_offset; // Cached. + ::std::string tag_data; }; ::std::vector<VariantValue> variants; }; diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index db8ec085..e4a19196 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -7,7 +7,7 @@ #include <iostream> #include <iomanip> #include <algorithm> - +#include "debug.hpp" AllocationPtr Allocation::new_alloc(size_t size) { @@ -15,6 +15,7 @@ AllocationPtr Allocation::new_alloc(size_t size) rv->refcount = 1; rv->data.resize( (size + 8-1) / 8 ); // QWORDS rv->mask.resize( (size + 8-1) / 8 ); // bitmap bytes + //LOG_DEBUG(rv << " ALLOC"); return AllocationPtr(rv); } AllocationPtr AllocationPtr::new_fcn(::HIR::Path p) @@ -25,11 +26,34 @@ AllocationPtr AllocationPtr::new_fcn(::HIR::Path p) return rv; } AllocationPtr::AllocationPtr(const AllocationPtr& x): - m_ptr(x.m_ptr) + m_ptr(nullptr) { - if( is_alloc() ) { - assert(alloc().refcount != SIZE_MAX); - alloc().refcount += 1; + if( x ) + { + switch(x.get_ty()) + { + case Ty::Allocation: + m_ptr = x.m_ptr; + assert(alloc().refcount != 0); + assert(alloc().refcount != SIZE_MAX); + alloc().refcount += 1; + //LOG_DEBUG(&alloc() << " REF++ " << alloc().refcount); + break; + case Ty::Function: { + auto ptr_i = reinterpret_cast<uintptr_t>(new ::HIR::Path(x.fcn())); + assert( (ptr_i & 3) == 0 ); + 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::Unused2: + throw "BUG"; + } + } + else + { + m_ptr = nullptr; } } AllocationPtr::~AllocationPtr() @@ -41,8 +65,11 @@ AllocationPtr::~AllocationPtr() case Ty::Allocation: { auto* ptr = &alloc(); ptr->refcount -= 1; + //LOG_DEBUG(&alloc() << " REF-- " << ptr->refcount); if(ptr->refcount == 0) + { delete ptr; + } } break; case Ty::Function: { auto* ptr = const_cast<::HIR::Path*>(&fcn()); @@ -56,6 +83,31 @@ AllocationPtr::~AllocationPtr() } } +::std::ostream& operator<<(::std::ostream& os, const AllocationPtr& x) +{ + if( x ) + { + switch(x.get_ty()) + { + case AllocationPtr::Ty::Allocation: + os << &x.alloc(); + break; + case AllocationPtr::Ty::Function: + os << *const_cast<::HIR::Path*>(&x.fcn()); + break; + case AllocationPtr::Ty::Unused1: + break; + case AllocationPtr::Ty::Unused2: + break; + } + } + else + { + os << "null"; + } + return os; +} + Value::Value() { this->meta.direct_data.size = 0; @@ -99,7 +151,7 @@ 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; + //LOG_TRACE("No pointers in " << ty << ", storing inline"); this->meta.direct_data.size = static_cast<uint8_t>(size); this->meta.direct_data.mask[0] = 0; this->meta.direct_data.mask[1] = 0; @@ -109,7 +161,7 @@ Value::Value(::HIR::TypeRef ty) #endif // Fallback: Make a new allocation - ::std::cout << "Value::Value(): Creating allocation for " << ty << ::std::endl; + //LOG_TRACE(" Creating allocation for " << ty); this->allocation = Allocation::new_alloc(size); this->meta.indirect_meta.offset = 0; this->meta.indirect_meta.size = size; @@ -174,7 +226,7 @@ void Value::mark_bytes_valid(size_t ofs, size_t size) auto& alloc = this->allocation.alloc(); // TODO: Assert range. ofs += this->meta.indirect_meta.offset; - assert( (ofs+size+8-1) / 8 < alloc.mask.size() ); + assert( ofs+size <= alloc.mask.size() * 8 ); for(size_t i = ofs; i < ofs + size; i++) { alloc.mask[i/8] |= (1 << i%8); @@ -191,7 +243,8 @@ void Value::mark_bytes_valid(size_t ofs, size_t size) Value Value::read_value(size_t ofs, size_t size) const { - ::std::cout << "Value::read_value(" << ofs << ", " << size << ")" << ::std::endl; + Value rv; + LOG_DEBUG("(" << ofs << ", " << size << ") - " << *this); check_bytes_valid(ofs, size); if( this->allocation ) { @@ -205,28 +258,34 @@ Value Value::read_value(size_t ofs, size_t size) const has_reloc = true; } } - Value rv; - if( has_reloc && size < sizeof(this->meta.direct_data.data) ) + 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; + + 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 ) + { + rv.allocation.alloc().relocations.push_back({ r.slot_ofs - (this->meta.indirect_meta.offset+ofs), r.backing_alloc }); + } + } } else { rv.meta.direct_data.size = static_cast<uint8_t>(size); } rv.write_bytes(0, this->data_ptr() + ofs, size); - return rv; } else { // Inline can become inline. - Value rv; rv.meta.direct_data.size = static_cast<uint8_t>(size); rv.write_bytes(0, this->meta.direct_data.data+ofs, size); - return rv; } + LOG_DEBUG("RETURN " << rv); + return rv; } void Value::read_bytes(size_t ofs, void* dst, size_t count) const { @@ -250,6 +309,23 @@ void Value::write_bytes(size_t ofs, const void* src, size_t count) ::std::cerr << "Value::write_bytes - Out of bounds write, " << ofs << "+" << count << " > size " << this->meta.indirect_meta.size << ::std::endl; throw "ERROR"; } + + + // - Remove any relocations already within this region + auto& this_relocs = this->allocation.alloc().relocations; + for(auto it = this_relocs.begin(); it != this_relocs.end(); ) + { + if( this->meta.indirect_meta.offset + ofs <= it->slot_ofs && it->slot_ofs < this->meta.indirect_meta.offset + ofs + count) + { + LOG_TRACE("Delete " << it->backing_alloc); + it = this_relocs.erase(it); + } + else + { + ++it; + } + } + } else { @@ -267,21 +343,49 @@ void Value::write_value(size_t ofs, Value v) { if( v.allocation ) { - v.check_bytes_valid(0, v.meta.indirect_meta.size); + size_t v_size = v.meta.indirect_meta.size; + v.check_bytes_valid(0, v_size); const auto& src_alloc = v.allocation.alloc(); - write_bytes(ofs, v.data_ptr(), v.meta.indirect_meta.size); + write_bytes(ofs, v.data_ptr(), v_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` + // - Any relocations in the source within `v.meta.indirect_meta.offset` .. `v.meta.indirect_meta.offset + v_size` + ::std::vector<Relocation> new_relocs; 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 ) + if( v.meta.indirect_meta.offset <= r.slot_ofs && r.slot_ofs < v.meta.indirect_meta.offset + v_size ) + { + LOG_TRACE("Copy " << r.backing_alloc); + // Applicable, save for later + new_relocs.push_back( r ); + } + } + if( !new_relocs.empty() ) + { + if( !this->allocation ) { + throw ::std::runtime_error("TODO: Writing value with a relocation into a slot without a relocation"); + } + // 1. Remove any relocations already within this region + auto& this_relocs = this->allocation.alloc().relocations; + for(auto it = this_relocs.begin(); it != this_relocs.end(); ) { - // Applicable - if( !this->allocation ) { - throw ::std::runtime_error("TODO: Writing value with a relocation into a slot without a relocation"); + if( this->meta.indirect_meta.offset + ofs <= it->slot_ofs && it->slot_ofs < this->meta.indirect_meta.offset + ofs + v_size) + { + LOG_TRACE("Delete " << it->backing_alloc); + it = this_relocs.erase(it); + } + else + { + ++it; } - this->allocation.alloc().relocations.push_back( r ); + } + // 2. Move the new relocations into this allocation + for(auto& r : new_relocs) + { + LOG_TRACE("Insert " << r.backing_alloc); + r.slot_ofs -= v.meta.indirect_meta.offset; + r.slot_ofs += this->meta.indirect_meta.offset + ofs; + this_relocs.push_back( ::std::move(r) ); } } } @@ -292,13 +396,14 @@ void Value::write_value(size_t ofs, Value v) } } -size_t Value::as_usize() const +uint64_t Value::read_usize(size_t ofs) const { - uint64_t v; + uint64_t v = 0; + // TODO: Handle different pointer sizes this->read_bytes(0, &v, 8); - // TODO: Handle endian and different architectures return v; } + ::std::ostream& operator<<(::std::ostream& os, const Value& v) { auto flags = os.flags(); @@ -321,6 +426,16 @@ size_t Value::as_usize() const os << "--"; } } + + os << " {"; + for(const auto& r : alloc.relocations) + { + if( v.meta.indirect_meta.offset <= r.slot_ofs && r.slot_ofs < v.meta.indirect_meta.offset + v.meta.indirect_meta.size ) + { + os << " @" << (r.slot_ofs - v.meta.indirect_meta.offset) << "=" << r.backing_alloc; + } + } + os << " }"; } else { diff --git a/tools/standalone_miri/value.hpp b/tools/standalone_miri/value.hpp index 9f9e68f4..b0c649fc 100644 --- a/tools/standalone_miri/value.hpp +++ b/tools/standalone_miri/value.hpp @@ -43,6 +43,7 @@ public: ~AllocationPtr(); static AllocationPtr new_fcn(::HIR::Path p); + AllocationPtr& operator=(const AllocationPtr& x) = delete; AllocationPtr& operator=(AllocationPtr&& x) { this->~AllocationPtr(); this->m_ptr = x.m_ptr; @@ -70,6 +71,8 @@ public: Ty get_ty() const { return static_cast<Ty>( reinterpret_cast<uintptr_t>(m_ptr) & 3 ); } + + friend ::std::ostream& operator<<(::std::ostream& os, const AllocationPtr& x); private: void* get_ptr() const { return reinterpret_cast<void*>( reinterpret_cast<uintptr_t>(m_ptr) & ~3 ); @@ -127,7 +130,29 @@ struct Value void write_value(size_t ofs, Value v); void write_bytes(size_t ofs, const void* src, size_t count); - size_t as_usize() const; + uint8_t read_u8(size_t ofs) const { uint8_t rv; read_bytes(ofs, &rv, 1); return rv; } + int8_t read_i8(size_t ofs) const { return static_cast<int8_t>(read_u8(ofs)); } + uint16_t read_u16(size_t ofs) const { uint16_t rv; read_bytes(ofs, &rv, 2); return rv; } + int16_t read_i16(size_t ofs) const { return static_cast<int16_t>(read_u16(ofs)); } + uint32_t read_u32(size_t ofs) const { uint32_t rv; read_bytes(ofs, &rv, 4); return rv; } + int32_t read_i32(size_t ofs) const { return static_cast<int32_t>(read_u32(ofs)); } + uint64_t read_u64(size_t ofs) const { uint64_t rv; read_bytes(ofs, &rv, 8); return rv; } + int64_t read_i64(size_t ofs) const { return static_cast<int64_t>(read_u64(ofs)); } + float read_f32(size_t ofs) const { float rv; read_bytes(ofs, &rv, 4); return rv; } + double read_f64(size_t ofs) const { double rv; read_bytes(ofs, &rv, 8); return rv; } + uint64_t read_usize(size_t ofs) const; + int64_t read_isize(size_t ofs) const { return static_cast<int64_t>(read_usize(ofs)); } + + void write_u8 (size_t ofs, uint8_t v) { write_bytes(ofs, &v, 1); } + void write_u16(size_t ofs, uint16_t v) { write_bytes(ofs, &v, 2); } + void write_u32(size_t ofs, uint32_t v) { write_bytes(ofs, &v, 4); } + void write_u64(size_t ofs, uint64_t v) { write_bytes(ofs, &v, 8); } + void write_i8 (size_t ofs, int8_t v) { write_u8 (ofs, static_cast<uint8_t >(v)); } + void write_i16(size_t ofs, int16_t v) { write_u16(ofs, static_cast<uint16_t>(v)); } + void write_i32(size_t ofs, int32_t v) { write_u32(ofs, static_cast<uint32_t>(v)); } + void write_i64(size_t ofs, int64_t v) { write_u64(ofs, static_cast<uint64_t>(v)); } + void write_f32(size_t ofs, float v) { write_bytes(ofs, &v, 4); } + void write_f64(size_t ofs, double v) { write_bytes(ofs, &v, 8); } 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; } diff --git a/vsproject/standalone_miri/standalone_miri.vcxproj b/vsproject/standalone_miri/standalone_miri.vcxproj index ed5dc733..4209e566 100644 --- a/vsproject/standalone_miri/standalone_miri.vcxproj +++ b/vsproject/standalone_miri/standalone_miri.vcxproj @@ -121,7 +121,7 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>WIN32;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <TreatSpecificWarningsAsErrors>4062;4061;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors> @@ -141,7 +141,7 @@ <Optimization>MaxSpeed</Optimization> <FunctionLevelLinking>true</FunctionLevelLinking> <IntrinsicFunctions>true</IntrinsicFunctions> - <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <PreprocessorDefinitions>_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <SDLCheck>true</SDLCheck> <AdditionalIncludeDirectories>$(SolutionDir)..\src\include;$(SolutionDir)..\tools\standalone_miri;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> <TreatSpecificWarningsAsErrors>4062;4061;%(TreatSpecificWarningsAsErrors)</TreatSpecificWarningsAsErrors> @@ -157,7 +157,7 @@ <Text Include="ReadMe.txt" /> </ItemGroup> <ItemGroup> - <ClInclude Include="..\..\tools\standalone_miri\debug.h" /> + <ClInclude Include="..\..\tools\standalone_miri\debug.hpp" /> <ClInclude Include="..\..\tools\standalone_miri\hir_sim.hpp" /> <ClInclude Include="..\..\tools\standalone_miri\lex.hpp" /> <ClInclude Include="..\..\tools\standalone_miri\module_tree.hpp" /> @@ -165,6 +165,7 @@ <ClInclude Include="targetver.h" /> </ItemGroup> <ItemGroup> + <ClCompile Include="..\..\tools\standalone_miri\debug.cpp" /> <ClCompile Include="..\..\tools\standalone_miri\hir_sim.cpp" /> <ClCompile Include="..\..\tools\standalone_miri\lex.cpp" /> <ClCompile Include="..\..\tools\standalone_miri\main.cpp" /> diff --git a/vsproject/standalone_miri/standalone_miri.vcxproj.filters b/vsproject/standalone_miri/standalone_miri.vcxproj.filters index 3010940e..e26bbee5 100644 --- a/vsproject/standalone_miri/standalone_miri.vcxproj.filters +++ b/vsproject/standalone_miri/standalone_miri.vcxproj.filters @@ -33,6 +33,9 @@ <ClInclude Include="..\..\tools\standalone_miri\lex.hpp"> <Filter>Header Files</Filter> </ClInclude> + <ClInclude Include="..\..\tools\standalone_miri\debug.hpp"> + <Filter>Header Files</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="..\..\tools\standalone_miri\main.cpp"> @@ -53,5 +56,8 @@ <ClCompile Include="..\..\tools\standalone_miri\value.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="..\..\tools\standalone_miri\debug.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> </Project>
\ No newline at end of file |