diff options
-rw-r--r-- | src/trans/codegen_mmir.cpp | 4 | ||||
-rw-r--r-- | tools/standalone_miri/main.cpp | 128 | ||||
-rw-r--r-- | tools/standalone_miri/value.cpp | 50 |
3 files changed, 165 insertions, 17 deletions
diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 88c81568..cea409bf 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -348,6 +348,10 @@ namespace { m_of << "\t" << e.offset << " = " << e.ty << ";\n"; } + for(const auto& e : repr->fields) + { + m_of << "\t" << "#" << (&e - repr->fields.data()) << ";\n"; + } m_of << "}\n"; // TODO: Drop glue! diff --git a/tools/standalone_miri/main.cpp b/tools/standalone_miri/main.cpp index 8823cf44..3fc807c5 100644 --- a/tools/standalone_miri/main.cpp +++ b/tools/standalone_miri/main.cpp @@ -256,16 +256,17 @@ struct Ops { return 1; } } - static uint64_t do_unsigned(uint64_t l, uint64_t r, ::MIR::eBinOp op) { + template<typename T> + static T do_bitwise(T l, 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; + case ::MIR::eBinOp::BIT_AND: return l & r; + case ::MIR::eBinOp::BIT_OR: return l | r; + case ::MIR::eBinOp::BIT_XOR: return l ^ r; + case ::MIR::eBinOp::BIT_SHL: return l << r; + case ::MIR::eBinOp::BIT_SHR: return l >> r; default: - LOG_BUG("Unexpected operation in Ops::do_unsigned"); + LOG_BUG("Unexpected operation in Ops::do_bitwise"); } } }; @@ -859,13 +860,10 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar 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); + LOG_DEBUG(v_l << " (" << ty_l <<") ? " << v_r << " (" << ty_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: @@ -878,8 +876,8 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar const auto& alloc_l = v_l.m_value ? v_l.m_value->allocation : v_l.m_alloc; const auto& alloc_r = v_r.m_value ? v_r.m_value->allocation : v_r.m_alloc; - auto reloc_l = alloc_l ? alloc_l.alloc().get_relocation(0) : AllocationPtr(); - auto reloc_r = alloc_r ? alloc_r.alloc().get_relocation(0) : AllocationPtr(); + auto reloc_l = alloc_l ? alloc_l.alloc().get_relocation(v_l.m_offset) : AllocationPtr(); + auto reloc_r = alloc_r ? alloc_r.alloc().get_relocation(v_r.m_offset) : AllocationPtr(); if( reloc_l != reloc_r ) { @@ -949,6 +947,68 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar new_val = Value(::HIR::TypeRef(RawType::Bool)); new_val.write_u8(0, res_bool ? 1 : 0); } break; + case ::MIR::eBinOp::BIT_SHL: + case ::MIR::eBinOp::BIT_SHR: { + LOG_ASSERT(ty_l.wrappers.empty(), "Bitwise operator on non-primitive - " << ty_l); + LOG_ASSERT(ty_r.wrappers.empty(), "Bitwise operator with non-primitive - " << ty_r); + size_t max_bits = ty_r.get_size() * 8; + uint8_t shift; + auto check_cast = [&](auto v){ LOG_ASSERT(0 <= v && v <= max_bits, "Shift out of range - " << v); return static_cast<uint8_t>(v); }; + switch(ty_r.inner_type) + { + case RawType::U64: shift = check_cast(v_r.read_u64(0)); break; + case RawType::U32: shift = check_cast(v_r.read_u32(0)); break; + case RawType::U16: shift = check_cast(v_r.read_u16(0)); break; + case RawType::U8 : shift = check_cast(v_r.read_u8 (0)); break; + case RawType::I64: shift = check_cast(v_r.read_i64(0)); break; + case RawType::I32: shift = check_cast(v_r.read_i32(0)); break; + case RawType::I16: shift = check_cast(v_r.read_i16(0)); break; + case RawType::I8 : shift = check_cast(v_r.read_i8 (0)); break; + case RawType::USize: shift = check_cast(v_r.read_usize(0)); break; + case RawType::ISize: shift = check_cast(v_r.read_isize(0)); break; + default: + LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); + } + new_val = Value(ty_l); + switch(ty_l.inner_type) + { + case RawType::U64: new_val.write_u64(0, Ops::do_bitwise(v_l.read_u64(0), static_cast<uint64_t>(shift), re.op)); break; + case RawType::U32: new_val.write_u32(0, Ops::do_bitwise(v_l.read_u32(0), static_cast<uint32_t>(shift), re.op)); break; + case RawType::U16: new_val.write_u16(0, Ops::do_bitwise(v_l.read_u16(0), static_cast<uint16_t>(shift), re.op)); break; + case RawType::U8 : new_val.write_u8 (0, Ops::do_bitwise(v_l.read_u8 (0), static_cast<uint8_t >(shift), re.op)); break; + case RawType::USize: new_val.write_usize(0, Ops::do_bitwise(v_l.read_usize(0), static_cast<uint64_t>(shift), re.op)); break; + default: + LOG_TODO("BinOp shift rhs unknown type - " << se.src << " w/ " << ty_r); + } + } break; + case ::MIR::eBinOp::BIT_AND: + case ::MIR::eBinOp::BIT_OR: + case ::MIR::eBinOp::BIT_XOR: + LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r); + LOG_ASSERT(ty_l.wrappers.empty(), "Bitwise operator on non-primitive - " << ty_l); + new_val = Value(ty_l); + switch(ty_l.inner_type) + { + case RawType::U64: + new_val.write_u64( 0, Ops::do_bitwise(v_l.read_u64(0), v_r.read_u64(0), re.op) ); + break; + case RawType::U32: + new_val.write_u32( 0, static_cast<uint32_t>(Ops::do_bitwise(v_l.read_u32(0), v_r.read_u32(0), re.op)) ); + break; + case RawType::U16: + new_val.write_u16( 0, static_cast<uint16_t>(Ops::do_bitwise(v_l.read_u16(0), v_r.read_u16(0), re.op)) ); + break; + case RawType::U8: + new_val.write_u8 ( 0, static_cast<uint8_t >(Ops::do_bitwise(v_l.read_u8 (0), v_r.read_u8 (0), re.op)) ); + break; + case RawType::USize: + new_val.write_usize( 0, Ops::do_bitwise(v_l.read_usize(0), v_r.read_usize(0), re.op) ); + break; + default: + LOG_TODO("BinOp bitwise - " << se.src << " w/ " << ty_l); + } + + break; default: LOG_ASSERT(ty_l == ty_r, "BinOp type mismatch - " << ty_l << " != " << ty_r); auto val_l = PrimitiveValueVirt::from_value(ty_l, v_l); @@ -960,8 +1020,9 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar case ::MIR::eBinOp::MUL: val_l.get().multiply( val_r.get() ); break; case ::MIR::eBinOp::DIV: val_l.get().divide( val_r.get() ); break; case ::MIR::eBinOp::MOD: val_l.get().modulo( val_r.get() ); break; + default: - throw ""; + LOG_TODO("Unsupported binary operator?"); } new_val = Value(ty_l); val_l.get().write_to_value(new_val, 0); @@ -1204,6 +1265,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar bb_idx = te; continue; TU_ARM(bb.terminator, Return, _te) + LOG_DEBUG("RETURN " << state.ret); return state.ret; TU_ARM(bb.terminator, If, te) { uint8_t v = state.get_value_ref(te.cond).read_u8(0); @@ -1291,6 +1353,7 @@ Value MIRI_Invoke(ModuleTree& modtree, ::HIR::Path path, ::std::vector<Value> ar LOG_DEBUG("Call " << *fcn_p); state.write_lvalue(te.ret_val, MIRI_Invoke(modtree, *fcn_p, ::std::move(sub_args))); + LOG_DEBUG("resume " << path); } bb_idx = te.ret_block; } continue; @@ -1432,6 +1495,10 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name const auto& ty = ty_params.tys.at(0); alloc.alloc().write_value(ofs, ::std::move(data_val)); } + else if( name == "uninit" ) + { + return Value(ty_params.tys.at(0)); + } // ---------------------------------------------------------------- // Checked arithmatic else if( name == "add_with_overflow" ) @@ -1501,6 +1568,39 @@ Value MIRI_Invoke_Intrinsic(const ModuleTree& modtree, const ::std::string& name lhs.get().write_to_value(rv, 0); } // ---------------------------------------------------------------- + // memcpy + else if( name == "copy_nonoverlapping" ) + { + auto src_ofs = args.at(0).read_usize(0); + auto src_alloc = args.at(0).allocation.alloc().get_relocation(0); + auto dst_ofs = args.at(1).read_usize(0); + auto dst_alloc = args.at(1).allocation.alloc().get_relocation(0); + auto byte_count = args.at(2).read_usize(0); + + LOG_ASSERT(src_alloc, "Source of copy* must have an allocation"); + LOG_ASSERT(dst_alloc, "Destination of copy* must be a memory allocation"); + LOG_ASSERT(dst_alloc.is_alloc(), "Destination of copy* must be a memory allocation"); + + switch(src_alloc.get_ty()) + { + case AllocationPtr::Ty::Allocation: { + auto v = src_alloc.alloc().read_value(src_ofs, byte_count); + dst_alloc.alloc().write_value(dst_ofs, ::std::move(v)); + } break; + case AllocationPtr::Ty::StdString: + LOG_ASSERT(src_ofs <= src_alloc.str().size(), ""); + LOG_ASSERT(byte_count <= src_alloc.str().size(), ""); + LOG_ASSERT(src_ofs + byte_count <= src_alloc.str().size(), ""); + dst_alloc.alloc().write_bytes(dst_ofs, src_alloc.str().data() + src_ofs, byte_count); + break; + case AllocationPtr::Ty::Function: + LOG_FATAL("Attempt to copy* a function"); + break; + case AllocationPtr::Ty::Unused2: + LOG_BUG("Unused tag"); + break; + } + } else { LOG_TODO("Call intrinsic \"" << name << "\""); diff --git a/tools/standalone_miri/value.cpp b/tools/standalone_miri/value.cpp index 51bf6b94..745e9b1b 100644 --- a/tools/standalone_miri/value.cpp +++ b/tools/standalone_miri/value.cpp @@ -581,13 +581,57 @@ void Value::write_usize(size_t ofs, uint64_t v) } extern ::std::ostream& operator<<(::std::ostream& os, const ValueRef& v) { - if( v.m_alloc ) + if( v.m_alloc || v.m_value->allocation ) { - os << v.m_alloc.alloc(); + const auto& alloc_ptr = v.m_alloc ? v.m_alloc : v.m_value->allocation; + // TODO: What if alloc_ptr isn't a data allocation? + const auto& alloc = alloc_ptr.alloc(); + + for(size_t i = v.m_offset; i < ::std::min(alloc.size(), v.m_offset + v.m_size); i++) + { + if( i != 0 ) + os << " "; + + if( alloc.mask[i/8] & (1 << i%8) ) + { + os << ::std::setw(2) << ::std::setfill('0') << (int)alloc.data_ptr()[i]; + } + else + { + os << "--"; + } + } + + os << " {"; + for(const auto& r : alloc.relocations) + { + if( v.m_offset <= r.slot_ofs && r.slot_ofs < v.m_offset + v.m_size ) + { + os << " @" << (r.slot_ofs - v.m_offset) << "=" << r.backing_alloc; + } + } + os << " }"; } else { - os << *v.m_value; + const auto& direct = v.m_value->direct_data; + + auto flags = os.flags(); + os << ::std::hex; + for(size_t i = v.m_offset; i < ::std::min(static_cast<size_t>(direct.size), v.m_offset + v.m_size); i++) + { + if( i != 0 ) + os << " "; + if( direct.mask[i/8] & (1 << i%8) ) + { + os << ::std::setw(2) << ::std::setfill('0') << (int)direct.data[i]; + } + else + { + os << "--"; + } + } + os.setf(flags); } return os; } |