From c2af54e57545b55be1a5c32cfe4ffbc4b6e114a4 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 30 Dec 2018 10:35:38 +0800 Subject: MIR Optimise - constant evaluation: addition --- src/mir/optimise.cpp | 128 +++++++++++++++++++++++++++------------------------ 1 file changed, 69 insertions(+), 59 deletions(-) (limited to 'src/mir/optimise.cpp') diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 80bca08d..67a5d4a4 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -2219,75 +2219,85 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) const auto& val_l = se.val_l.as_Constant(); const auto& val_r = se.val_r.as_Constant(); - ::MIR::Constant new_value; - bool replace = false; - switch(se.op) + if( val_l.is_Const() || val_r.is_Const() ) { - case ::MIR::eBinOp::EQ: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else + } + else + { + struct H { + static int64_t truncate_s(::HIR::CoreType ct, int64_t v) { + return v; + } + static uint64_t truncate_u(::HIR::CoreType ct, uint64_t v) { + switch(ct) + { + case ::HIR::CoreType::U8: return v & 0xFF; + case ::HIR::CoreType::U16: return v & 0xFFFF; + case ::HIR::CoreType::U32: return v & 0xFFFFFFFF; + case ::HIR::CoreType::U64: return v; + case ::HIR::CoreType::U128: return v; + case ::HIR::CoreType::Usize: return v; + case ::HIR::CoreType::Char: + //MIR_BUG(state, "Invalid use of operator on char"); + break; + default: + // Invalid type for Uint literal + break; + } + return v; + } + }; + ::MIR::Constant new_value; + switch(se.op) { - replace = true; + case ::MIR::eBinOp::EQ: new_value = ::MIR::Constant::make_Bool({val_l == val_r}); - } - break; - case ::MIR::eBinOp::NE: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::NE: new_value = ::MIR::Constant::make_Bool({val_l != val_r}); - } - break; - case ::MIR::eBinOp::LT: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::LT: new_value = ::MIR::Constant::make_Bool({val_l < val_r}); - } - break; - case ::MIR::eBinOp::LE: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::LE: new_value = ::MIR::Constant::make_Bool({val_l <= val_r}); - } - break; - case ::MIR::eBinOp::GT: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::GT: new_value = ::MIR::Constant::make_Bool({val_l > val_r}); - } - break; - case ::MIR::eBinOp::GE: - if( val_l.is_Const() || val_r.is_Const() ) - ; - else - { - replace = true; + break; + case ::MIR::eBinOp::GE: new_value = ::MIR::Constant::make_Bool({val_l >= val_r}); + break; + + case ::MIR::eBinOp::ADD: + MIR_ASSERT(state, val_l.tag() == val_r.tag(), "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r); + //{TU_MATCH_HDRA( (val_l, val_r), {) + {TU_MATCH_HDRA( (val_l), {) + default: + break; + // TU_ARMav(Int, (le, re)) { + TU_ARMA(Int, le) { const auto& re = val_r.as_Int(); + MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r); + new_value = ::MIR::Constant::make_Int({ H::truncate_s(le.t, le.v + re.v) }); + } + TU_ARMA(Uint, le) { const auto& re = val_r.as_Uint(); + MIR_ASSERT(state, le.t == re.t, "Mismatched types for eBinOp::ADD - " << val_l << " + " << val_r); + new_value = ::MIR::Constant::make_Uint({ H::truncate_u(le.t, le.v + re.v) }); + } + }} + break; + // TODO: Other binary operations + // Could emit a TODO? + default: + break; } - break; - // TODO: Other binary operations - // Could emit a TODO? - default: - break; - } - if( replace ) - { - DEBUG(state << " " << e->src << " = " << new_value); - e->src = mv$(new_value); - changed = true; + if( new_value != ::MIR::Constant() ) + { + DEBUG(state << " " << e->src << " = " << new_value); + e->src = mv$(new_value); + changed = true; + } } } ), -- cgit v1.2.3 From 967a76859749ecb602cd2c343e28888514f827bd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 25 Apr 2019 13:56:11 +0800 Subject: MIR - Reduce size of LValue::Static by putting the HIR::Path behind a pointer --- src/hir/deserialise.cpp | 2 +- src/hir/serialise.cpp | 2 +- src/hir_conv/bind.cpp | 2 +- src/hir_conv/constant_evaluation.cpp | 4 +-- src/mir/dump.cpp | 2 +- src/mir/from_hir.cpp | 2 +- src/mir/helpers.cpp | 2 +- src/mir/mir.cpp | 4 +-- src/mir/mir.hpp | 58 +++++++++++++++++++++++++++++++++++- src/mir/mir_builder.cpp | 8 ++--- src/mir/optimise.cpp | 2 +- src/trans/codegen_c.cpp | 2 +- src/trans/codegen_mmir.cpp | 2 +- src/trans/enumerate.cpp | 4 +-- src/trans/monomorphise.cpp | 2 +- 15 files changed, 77 insertions(+), 21 deletions(-) (limited to 'src/mir/optimise.cpp') diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 9933255f..cd25a3cb 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -423,7 +423,7 @@ _(Return, {}) _(Argument, { static_cast(m_in.read_count()) } ) _(Local, static_cast(m_in.read_count()) ) - _(Static, deserialise_path() ) + _(Static, box$(deserialise_path()) ) _(Field, { box$( deserialise_mir_lvalue() ), static_cast(m_in.read_count()) diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index dd81596f..e90cf995 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -689,7 +689,7 @@ m_out.write_count(e); ), (Static, - serialise_path(e); + serialise_path(*e); ), (Field, serialise(e.val); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index a3b0041b..940b2cab 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -712,7 +712,7 @@ namespace { (Argument, ), (Static, - upper_visitor.visit_path(e, ::HIR::Visitor::PathContext::VALUE); + upper_visitor.visit_path(*e, ::HIR::Visitor::PathContext::VALUE); ), (Field, H::visit_lvalue(upper_visitor, *e.val); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 6049056c..6838e186 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -319,7 +319,7 @@ namespace { return args[e.idx]; ), (Static, - MIR_TODO(state, "LValue::Static - " << e); + MIR_TODO(state, "LValue::Static - " << *e); ), (Field, auto& val = get_lval(*e.val); @@ -495,7 +495,7 @@ namespace { } else if( const auto* p = e.val.opt_Static() ) { // Borrow of a static, emit BorrowPath with the same path - val = ::HIR::Literal::make_BorrowPath( p->clone() ); + val = ::HIR::Literal::make_BorrowPath( (*p)->clone() ); } else { auto inner_val = local_state.read_lval(e.val); diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index 90b81d5d..ffce8abb 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -187,7 +187,7 @@ namespace { os << "_$" << e; ), (Static, - os << e; + os << *e; ), (Field, os << "("; diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index a2d0c790..912b8c78 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2195,7 +2195,7 @@ namespace { m_builder.set_result( node.span(), mv$(tmp) ); ), (Static, - m_builder.set_result( node.span(), ::MIR::LValue::make_Static(node.m_path.clone()) ); + m_builder.set_result( node.span(), ::MIR::LValue::make_Static(box$(node.m_path.clone())) ); ), (StructConstant, // TODO: Why is this still a PathValue? diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 38380fed..38388aed 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -82,7 +82,7 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return m_fcn.locals.at(e); ), (Static, - return get_static_type(tmp, e); + return get_static_type(tmp, *e); ), (Field, const auto& ty = this->get_lvalue_type(tmp, *e.val); diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index ee6c1a6c..657e695d 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -104,7 +104,7 @@ namespace MIR { os << "Local(" << e << ")"; ), (Static, - os << "Static(" << e << ")"; + os << "Static(" << *e << ")"; ), (Field, os << "Field(" << e.field_index << ", " << *e.val << ")"; @@ -543,7 +543,7 @@ namespace MIR { (Return, return LValue(e); ), (Argument, return LValue(e); ), (Local, return LValue(e); ), - (Static, return LValue(e.clone()); ), + (Static, return LValue(box$(e->clone())); ), (Field, return LValue::make_Field({ box$( e.val->clone() ), e.field_index diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 31eb9cd7..6969225d 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -17,6 +17,62 @@ namespace MIR { typedef unsigned int RegionId; typedef unsigned int BasicBlockId; +#if 0 +// TODO: Store LValues as: +// - A packed root value (one word, using the low bits as an enum descriminator) +// - A list of (inner to outer) wrappers +struct LValue +{ + class Storage + { + uintptr_t val; + public: + ~Storage() + { + if( is_Static() ) { + delete reinterpret_cast<::HIR::Path*>(val & ~3u); + val = 0; + } + } + bool is_Argument() const { return val != (MAX_ARG << 2) && (val & 3) == 0; } + bool is_Return() const { return val == (MAX_ARG << 2); } + bool is_Local() const { return (val & 3) == 1; } + bool is_Static() const { return (val & 3) == 2; } + + const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3u); } + }; + class Wrapper + { + uintptr_t val; + public: + bool is_Deref() const { return (val & 3) == 0; } + // Stores the field index + bool is_Field() const { return (val & 3) == 1; } + // Stores the variant index + bool is_Downcast() const { return (val & 3) == 2; } + // Stores a Local index + bool is_Index() const { return (val & 3) == 3; } + + const unsigned as_Field() const { assert(is_Field()); return (val >> 2); } + const unsigned as_Index() const { assert(is_Index()); return (val >> 2); } + }; + + Storage m_root; + ::std::vector m_wrappers; + + LValue clone() const; + + class Ref + { + LValue& r; + size_t wrapper_idx; + public:: + LValue clone() const; + void replace(LValue x) const; + }; +}; +#endif + // "LVALUE" - Assignable values TAGGED_UNION_EX(LValue, (), Return, ( // Function return @@ -26,7 +82,7 @@ TAGGED_UNION_EX(LValue, (), Return, ( // Variable/Temporary (Local, unsigned int), // `static` or `static mut` - (Static, ::HIR::Path), + (Static, ::std::unique_ptr<::HIR::Path>), // Field access (tuple, struct, tuple struct, enum field, ...) // NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring) (Field, struct { diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index ac1b7650..81816535 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -1622,20 +1622,20 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: cb( m_output.locals.at(e) ); ), (Static, - TU_MATCHA( (e.m_data), (pe), + TU_MATCHA( (e->m_data), (pe), (Generic, ASSERT_BUG(sp, pe.m_params.m_types.empty(), "Path params on static"); const auto& s = m_resolve.m_crate.get_static_by_path(sp, pe.m_path); cb( s.m_type ); ), (UfcsKnown, - TODO(sp, "Static - UfcsKnown - " << e); + TODO(sp, "Static - UfcsKnown - " << *e); ), (UfcsUnknown, - BUG(sp, "Encountered UfcsUnknown in Static - " << e); + BUG(sp, "Encountered UfcsUnknown in Static - " << *e); ), (UfcsInherent, - TODO(sp, "Static - UfcsInherent - " << e); + TODO(sp, "Static - UfcsInherent - " << *e); ) ) ), diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 67a5d4a4..b7e63deb 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1159,7 +1159,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool return ::MIR::LValue::make_Local(this->var_base + se); ), (Static, - return this->monomorph( se ); + return box$(this->monomorph( *se )); ), (Deref, return ::MIR::LValue::make_Deref({ box$(this->clone_lval(*se.val)) }); diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 98d0d3de..373a36a8 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -5522,7 +5522,7 @@ namespace { m_of << "var" << e; ), (Static, - m_of << Trans_Mangle(e); + m_of << Trans_Mangle(*e); ), (Field, ::HIR::TypeRef tmp; diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index b2c5282a..4867cf6f 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -52,7 +52,7 @@ namespace os << "arg" << e.idx; break; TU_ARM(x.e, Static, e) - os << e; + os << *e; break; TU_ARM(x.e, Deref, e) os << "*" << fmt(*e.val); diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index afdbd626..da11386c 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -735,7 +735,7 @@ void Trans_Enumerate_Types(EnumState& state) ), (Static, if( tmp_ty_ptr ) { - const auto& path = e; + const auto& path = *e; TU_MATCHA( (path.m_data), (pe), (Generic, ASSERT_BUG(Span(), pe.m_params.m_types.empty(), "Path params on static - " << path); @@ -1495,7 +1495,7 @@ void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& (Local, ), (Static, - Trans_Enumerate_FillFrom_Path(state, e, pp); + Trans_Enumerate_FillFrom_Path(state, *e, pp); ), (Field, Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index 3b958fec..0a0b43b5 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -19,7 +19,7 @@ namespace { (Argument, return e; ), (Local, return e; ), (Static, - return params.monomorph(resolve, e); + return box$(params.monomorph(resolve, *e)); ), (Field, return ::MIR::LValue::make_Field({ -- cgit v1.2.3 From 9e5d8a66034e95217e00702647fdc6621862c9ae Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 28 Apr 2019 11:03:42 +0800 Subject: MIR Optimise - Fix (and detect) a recursive inline, remove drops of GC'd locals, disable a really expensive pass --- src/mir/optimise.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) (limited to 'src/mir/optimise.cpp') diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index b7e63deb..7c284546 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -191,7 +191,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path #endif // >> Move common statements (assignments) across gotos. - change_happened |= MIR_Optimise_CommonStatements(state, fcn); + //change_happened |= MIR_Optimise_CommonStatements(state, fcn); // >> Combine Duplicate Blocks change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); @@ -859,12 +859,31 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool { bool inline_happened = false; TRACE_FUNCTION_FR("", inline_happened); + struct InlineEvent { + ::HIR::Path path; + ::std::vector bb_list; + InlineEvent(::HIR::Path p) + :path(::std::move(p)) + { + } + bool has_bb(size_t i) const { + return ::std::find(this->bb_list.begin(), this->bb_list.end(), i) != this->bb_list.end(); + } + void add_range(size_t start, size_t count) { + for(size_t j = 0; j < count; j++) + { + this->bb_list.push_back(start + j); + } + } + }; + ::std::vector inlined_functions; struct H { static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn, bool minimal) { // TODO: If the function is marked as `inline(always)`, then inline it regardless of the contents + // TODO: Take a monomorph helper so recursion can be detected if( minimal ) { return false; @@ -888,6 +907,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool return false; // Detect and avoid simple recursion. // - This won't detect mutual recursion - that also needs prevention. + // TODO: This is the pre-monomorph path, but we're comparing with the post-monomorph path if( blk0_te.fcn.is_Path() && blk0_te.fcn.as_Path() == path ) return false; return true; @@ -907,6 +927,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool // Recursion, don't inline. if( te.fcn.is_Path() && te.fcn.as_Path() == path ) return false; + // HACK: Only allow if the wrapped function is an intrinsic + // - Works around the TODO about monomorphed paths above + if(!te.fcn.is_Intrinsic()) + return false; } } return true; @@ -1272,6 +1296,15 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool if( ! te->fcn.is_Path() ) continue ; const auto& path = te->fcn.as_Path(); + DEBUG(state << fcn.blocks[i].terminator); + + for(const auto& e : inlined_functions) + { + if( path == e.path && e.has_bb(i) ) + { + MIR_BUG(state, "Recursive inline of " << path); + } + } Cloner cloner { state.sp, state.m_resolve, *te }; const auto* called_mir = get_called_mir(state, list, path, cloner.params); @@ -1292,7 +1325,6 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool DEBUG("Can't inline " << path); continue ; } - DEBUG(state << fcn.blocks[i].terminator); TRACE_FUNCTION_F("Inline " << path); // Allocate a temporary for the return value @@ -1350,6 +1382,17 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool } cloner.const_assignments.clear(); + // Record the inline event + for(auto& e : inlined_functions) + { + if( e.has_bb(i) ) + { + e.add_range(cloner.bb_base, new_blocks.size()); + } + } + inlined_functions.push_back(InlineEvent(path.clone())); + inlined_functions.back().add_range(cloner.bb_base, new_blocks.size()); + // Apply DEBUG("- Append new blocks"); fcn.blocks.reserve( fcn.blocks.size() + new_blocks.size() ); @@ -1359,6 +1402,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool } fcn.blocks[i].terminator = ::MIR::Terminator::make_Goto( cloner.bb_base ); inline_happened = true; + + // TODO: Store the inlined path along with the start and end BBs, and then use that to detect recursive + // inlining + // - Recursive inlining should be an immediate panic. } } return inline_happened; @@ -3605,6 +3652,14 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn continue ; } } + + // HACK: Remove drop if it's of an unused value (TODO: only if it's conditional?) + if( se->slot.is_Local() && local_rewrite_table[se->slot.as_Local()] == ~0u ) + { + DEBUG(state << "Remove " << stmt << " - Dropping non-set value"); + to_remove_statements[stmt_idx] = true; + continue ; + } } visit_mir_lvalues_mut(stmt, lvalue_cb); -- cgit v1.2.3 From 4c4a7b88914861b644ec56738ced8cfc179f93f9 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 5 May 2019 12:42:57 +0800 Subject: MIR - Wrap HIR::Path-s in MIR::Constant in unique_ptr --- src/hir/deserialise.cpp | 4 +-- src/hir/expr_ptr.cpp | 13 ++++--- src/hir/serialise.cpp | 4 +-- src/hir_conv/bind.cpp | 47 ++++++++++--------------- src/hir_conv/constant_evaluation.cpp | 6 ++-- src/mir/cleanup.cpp | 18 +++++----- src/mir/dump.cpp | 4 +-- src/mir/from_hir.cpp | 20 ++++++----- src/mir/helpers.cpp | 10 +++--- src/mir/mir.cpp | 12 +++---- src/mir/mir.hpp | 67 ++++++++++++++++++++++++++++++------ src/mir/optimise.cpp | 4 +-- src/trans/codegen_c.cpp | 8 ++--- src/trans/codegen_mmir.cpp | 2 +- src/trans/enumerate.cpp | 4 +-- src/trans/monomorphise.cpp | 6 ++-- 16 files changed, 135 insertions(+), 94 deletions(-) (limited to 'src/mir/optimise.cpp') diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index cd25a3cb..c5350b55 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -532,8 +532,8 @@ return ::MIR::Constant::make_Bytes( mv$(bytes) ); } _(StaticString, m_in.read_string() ) - _(Const, { deserialise_path() } ) - _(ItemAddr, deserialise_path() ) + _(Const, { box$(deserialise_path()) } ) + _(ItemAddr, box$(deserialise_path()) ) #undef _ default: BUG(Span(), "Bad tag for MIR::Const - " << tag); diff --git a/src/hir/expr_ptr.cpp b/src/hir/expr_ptr.cpp index 0c219e0f..7f493a0d 100644 --- a/src/hir/expr_ptr.cpp +++ b/src/hir/expr_ptr.cpp @@ -91,11 +91,14 @@ void HIR::ExprPtr::set_mir(::MIR::FunctionPointer mir) assert( !this->m_mir ); m_mir = ::std::move(mir); // Reset the HIR tree to be a placeholder node (thus freeing the backing memory) - //if( node ) - //{ - // auto sp = node->span(); - // node = ExprPtrInner(::std::unique_ptr(new ::HIR::ExprNode_Tuple(sp, {}))); - //} + if( false && node ) + { + auto sp = node->span(); + node = ExprPtrInner(::std::unique_ptr(new ::HIR::ExprNode_Loop( + sp, "", + ::std::unique_ptr(new ::HIR::ExprNode_Tuple(sp, {})) + ))); + } } diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index e90cf995..2c72c801 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -795,10 +795,10 @@ m_out.write_string(e); ), (Const, - serialise_path(e.p); + serialise_path(*e.p); ), (ItemAddr, - serialise_path(e); + serialise_path(*e); ) ) } diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 940b2cab..84854315 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -729,25 +729,29 @@ namespace { ) ) } + static void visit_constant(Visitor& upper_visitor, ::MIR::Constant& e) + { + TU_MATCHA( (e), (ce), + (Int, ), + (Uint,), + (Float, ), + (Bool, ), + (Bytes, ), + (StaticString, ), // String + (Const, + upper_visitor.visit_path(*ce.p, ::HIR::Visitor::PathContext::VALUE); + ), + (ItemAddr, + upper_visitor.visit_path(*ce, ::HIR::Visitor::PathContext::VALUE); + ) + ) + } static void visit_param(Visitor& upper_visitor, ::MIR::Param& p) { TU_MATCHA( (p), (e), (LValue, H::visit_lvalue(upper_visitor, e);), (Constant, - TU_MATCHA( (e), (ce), - (Int, ), - (Uint,), - (Float, ), - (Bool, ), - (Bytes, ), - (StaticString, ), // String - (Const, - upper_visitor.visit_path(ce.p, ::HIR::Visitor::PathContext::VALUE); - ), - (ItemAddr, - upper_visitor.visit_path(ce, ::HIR::Visitor::PathContext::VALUE); - ) - ) + H::visit_constant(upper_visitor, e); ) ) } @@ -765,20 +769,7 @@ namespace { H::visit_lvalue(*this, e); ), (Constant, - TU_MATCHA( (e), (ce), - (Int, ), - (Uint,), - (Float, ), - (Bool, ), - (Bytes, ), - (StaticString, ), // String - (Const, - this->visit_path(ce.p, ::HIR::Visitor::PathContext::VALUE); - ), - (ItemAddr, - this->visit_path(ce, ::HIR::Visitor::PathContext::VALUE); - ) - ) + H::visit_constant(*this, e); ), (SizedArray, H::visit_param(*this, e.val); diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index 6067b32f..0ccb6e6f 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -390,11 +390,11 @@ namespace HIR { TU_ARM(c, StaticString, e2) return ::HIR::Literal(e2); TU_ARM(c, Const, e2) { - auto p = ms.monomorph(state.sp, e2.p); + auto p = ms.monomorph(state.sp, *e2.p); // If there's any mention of generics in this path, then return Literal::Defer if( visit_path_tys_with(p, [&](const auto& ty)->bool { return ty.m_data.is_Generic(); }) ) { - DEBUG("Return Literal::Defer for constant " << e2.p << " which references a generic parameter"); + DEBUG("Return Literal::Defer for constant " << *e2.p << " which references a generic parameter"); return ::HIR::Literal::make_Defer({}); } MonomorphState const_ms; @@ -417,7 +417,7 @@ namespace HIR { return clone_literal( c.m_value_res ); } TU_ARM(c, ItemAddr, e2) - return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, e2) ); + return ::HIR::Literal::make_BorrowPath( ms.monomorph(state.sp, *e2) ); } throw ""; }; diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index fdc0f3d4..dd5332b6 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -216,7 +216,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con if( path == ::HIR::GenericPath() ) MIR_TODO(state, "Literal of type " << ty << " - " << lit); DEBUG("Unknown type " << ty << ", but a path was provided - Return ItemAddr " << path); - return ::MIR::Constant( mv$(path) ); + return ::MIR::Constant::make_ItemAddr( box$(path) ); ), (Tuple, MIR_ASSERT(state, lit.is_List(), "Non-list literal for Tuple - " << lit); @@ -378,7 +378,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con if( const auto* pp = lit.opt_BorrowPath() ) { const auto& path = *pp; - auto ptr_val = ::MIR::Constant::make_ItemAddr(path.clone()); + auto ptr_val = ::MIR::Constant::make_ItemAddr(box$(path.clone())); // TODO: Get the metadata type (for !Sized wrapper types) if( te.inner->m_data.is_Slice() ) { @@ -397,7 +397,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con auto vtable_path = ::HIR::Path(&ty == &tmp ? mv$(tmp) : ty.clone(), tep->m_trait.m_path.clone(), "vtable#"); - auto vtable_val = ::MIR::Param( ::MIR::Constant::make_ItemAddr(mv$(vtable_path)) ); + auto vtable_val = ::MIR::Param( ::MIR::Constant::make_ItemAddr(box$(vtable_path)) ); return ::MIR::RValue::make_MakeDst({ ::MIR::Param(mv$(ptr_val)), mv$(vtable_val) }); } @@ -458,7 +458,7 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con (Function, //MIR_TODO(state, "Const function pointer " << lit << " w/ type " << ty); MIR_ASSERT(state, lit.is_BorrowPath(), ""); - return ::MIR::Constant::make_ItemAddr( lit.as_BorrowPath().clone() ); + return ::MIR::Constant::make_ItemAddr( box$( lit.as_BorrowPath().clone() ) ); ) ) } @@ -703,7 +703,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& MIR_ASSERT(state, state.m_resolve.type_is_sized(state.sp, src_ty), "Attempting to get vtable for unsized type - " << src_ty); ::HIR::Path vtable { src_ty.clone(), trait_path.m_path.clone(), "vtable#" }; - out_meta_val = ::MIR::Constant::make_ItemAddr(mv$(vtable)); + out_meta_val = ::MIR::Constant::make_ItemAddr(box$(vtable)); } } return true; @@ -1092,18 +1092,18 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, TU_IFLET( ::MIR::Constant, e, Const, ce, // 1. Find the constant ::HIR::TypeRef ty; - const auto* lit_ptr = MIR_Cleanup_GetConstant(state, ce.p, ty); + const auto* lit_ptr = MIR_Cleanup_GetConstant(state, *ce.p, ty); if( lit_ptr && !lit_ptr->is_Defer() ) { - DEBUG("Replace constant " << ce.p << " with " << *lit_ptr); - se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(ce.p)); + DEBUG("Replace constant " << *ce.p << " with " << *lit_ptr); + se.src = MIR_Cleanup_LiteralToRValue(state, mutator, *lit_ptr, mv$(ty), mv$(*ce.p)); if( auto* p = se.src.opt_Constant() ) { MIR_Cleanup_Constant(state, mutator, *p); } } else { - DEBUG("No replacement for constant " << ce.p); + DEBUG("No replacement for constant " << *ce.p); } ) ) diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index ffce8abb..b02c1e5b 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -244,10 +244,10 @@ namespace { os << "\"" << ce << "\""; ), (Const, - os << ce.p; + os << *ce.p; ), (ItemAddr, - os << "addr " << ce; + os << "addr " << *ce; ) ) } diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 8d51bf55..b8549f8a 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -162,6 +162,7 @@ namespace { void destructure_from_ex(const Span& sp, const ::HIR::Pattern& pat, ::MIR::LValue lval, int allow_refutable=0) // 1 : yes, 2 : disallow binding { + TRACE_FUNCTION_F(pat << ", allow_refutable=" << allow_refutable); if( allow_refutable != 3 && pat.m_binding.is_valid() ) { if( allow_refutable == 2 ) { BUG(sp, "Binding when not expected"); @@ -425,9 +426,10 @@ namespace { // 2. Obtain pointer to element ::HIR::BorrowType bt = H::get_borrow_type(sp, e.extra_bind); ::MIR::LValue ptr_val = m_builder.lvalue_or_temp(sp, - ::HIR::TypeRef::new_pointer( bt, inner_type.clone() ), + ::HIR::TypeRef::new_borrow( bt, inner_type.clone() ), ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::make_Field({ box$(lval.clone()), static_cast(e.leading.size()) }) }) ); + // TODO: Cast to raw pointer? Or keep as a borrow? // Construct fat pointer m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) ); @@ -2185,7 +2187,7 @@ namespace { // TODO: Ideally, the creation of the wrapper function would happen somewhere before trans? auto tmp = m_builder.new_temporary( node.m_res_type ); - m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); m_builder.set_result( sp, mv$(tmp) ); return ; } @@ -2196,7 +2198,7 @@ namespace { ), (Constant, auto tmp = m_builder.new_temporary( e.m_type ); - m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_Const({node.m_path.clone()}) ); + m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_Const({box$(node.m_path.clone())}) ); m_builder.set_result( node.span(), mv$(tmp) ); ), (Static, @@ -2245,13 +2247,13 @@ namespace { fcn_ty_data.m_arg_types.push_back( monomorphise_type_with(sp, arg.second, monomorph_cb) ); } auto tmp = m_builder.new_temporary( ::HIR::TypeRef( mv$(fcn_ty_data) ) ); - m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); m_builder.set_result( sp, mv$(tmp) ); ), (StructConstructor, // TODO: Ideally, the creation of the wrapper function would happen somewhere before this? auto tmp = m_builder.new_temporary( node.m_res_type ); - m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.push_stmt_assign( sp, tmp.clone(), ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); m_builder.set_result( sp, mv$(tmp) ); ) ) @@ -2263,13 +2265,13 @@ namespace { ASSERT_BUG(sp, it != tr.m_values.end(), "Cannot find trait item for " << node.m_path); TU_MATCHA( (it->second), (e), (Constant, - m_builder.set_result( sp, ::MIR::Constant::make_Const({node.m_path.clone()}) ); + m_builder.set_result( sp, ::MIR::Constant::make_Const({box$(node.m_path.clone())}) ); ), (Static, TODO(sp, "Associated statics (non-rustc) - " << node.m_path); ), (Function, - m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); ) ) ), @@ -2285,7 +2287,7 @@ namespace { { auto it = impl.m_methods.find(pe.item); if( it != impl.m_methods.end() ) { - m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(node.m_path.clone()) ); + m_builder.set_result( sp, ::MIR::Constant::make_ItemAddr(box$(node.m_path.clone())) ); return true; } } @@ -2293,7 +2295,7 @@ namespace { { auto it = impl.m_constants.find(pe.item); if( it != impl.m_constants.end() ) { - m_builder.set_result( sp, ::MIR::Constant::make_Const({node.m_path.clone()}) ); + m_builder.set_result( sp, ::MIR::Constant::make_Const({box$(node.m_path.clone())}) ); return true; } } diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 38388aed..1453acb3 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -270,7 +270,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons ), (Const, MonomorphState p; - auto v = m_resolve.get_value(this->sp, e.p, p, /*signature_only=*/true); + auto v = m_resolve.get_value(this->sp, *e.p, p, /*signature_only=*/true); if( const auto* ve = v.opt_Constant() ) { const auto& ty = (*ve)->m_type; if( monomorphise_type_needed(ty) ) { @@ -282,12 +282,12 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons return ty.clone(); } else { - MIR_BUG(*this, "get_const_type - Not a constant " << e.p); + MIR_BUG(*this, "get_const_type - Not a constant " << *e.p); } ), (ItemAddr, MonomorphState p; - auto v = m_resolve.get_value(this->sp, e, p, /*signature_only=*/true); + auto v = m_resolve.get_value(this->sp, *e, p, /*signature_only=*/true); TU_MATCHA( (v), (ve), (NotFound, MIR_BUG(*this, "get_const_type - ItemAddr points to unknown value - " << c); @@ -325,7 +325,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons ::HIR::FunctionType ft; ft.is_unsafe = false; ft.m_abi = ABI_RUST; - auto enum_path = e.clone(); + auto enum_path = e->clone(); enum_path.m_data.as_Generic().m_path.m_components.pop_back(); ft.m_rettype = box$( ::HIR::TypeRef::new_path(mv$(enum_path), ve.e) ); ft.m_arg_types.reserve(str_data.size()); @@ -348,7 +348,7 @@ const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, cons ::HIR::FunctionType ft; ft.is_unsafe = false; ft.m_abi = ABI_RUST; - ft.m_rettype = box$( ::HIR::TypeRef::new_path( ::HIR::GenericPath(*ve.p, e.m_data.as_Generic().m_params.clone()), &str) ); + ft.m_rettype = box$( ::HIR::TypeRef::new_path( ::HIR::GenericPath(*ve.p, e->m_data.as_Generic().m_params.clone()), &str) ); ft.m_arg_types.reserve(str_data.size()); for(const auto& fld : str_data) ft.m_arg_types.push_back( p.monomorph(this->sp, fld.ent) ); diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 657e695d..638b8e46 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -44,10 +44,10 @@ namespace MIR { os << "\"" << FmtEscaped(e) << "\""; ), (Const, - os << e.p; + os << *e.p; ), (ItemAddr, - os << "&" << e; + os << "&" << *e; ) ) return os; @@ -82,10 +82,10 @@ namespace MIR { return ::ord(ae, be); ), (Const, - return ::ord(ae.p, be.p); + return ::ord(*ae.p, *be.p); ), (ItemAddr, - return ::ord(ae, be); + return ::ord(*ae, *be); ) ) throw ""; @@ -571,8 +571,8 @@ namespace MIR { (Bool, return ::MIR::Constant(e2); ), (Bytes, return ::MIR::Constant(e2); ), (StaticString, return ::MIR::Constant(e2); ), - (Const, return ::MIR::Constant::make_Const({e2.p.clone()}); ), - (ItemAddr, return ::MIR::Constant(e2.clone()); ) + (Const, return ::MIR::Constant::make_Const({box$(e2.p->clone())}); ), + (ItemAddr, return ::MIR::Constant(box$(e2->clone())); ) ) throw ""; } diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 7100d4aa..c24aac51 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -26,7 +26,21 @@ struct LValue class Storage { uintptr_t val; + static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits public: + Storage(const Storage&) = delete; + Storage& operator=(const Storage&) = delete; + Storage(Storage&& x) + :val(x.val) + { + x.val = 0; + } + Storage& operator=(Storage&& x) + { + this->~Storage(); + this->val = x.val; + x.val = 0; + } ~Storage() { if( is_Static() ) { @@ -34,32 +48,64 @@ struct LValue val = 0; } } + + static Storage new_Return() { return Storage { MAX_ARG << 2 }; } + static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage { idx << 2 }; ) + static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage { (idx << 2) | 1 } }; + static Storage new_Static(::HIR::Path p) { + ::HIR::Path* ptr = new ::HIR::Path(::std::move(p)); + return Storage { static_cast(ptr) | 2; } + } + + bool is_Return() const { return val == (MAX_ARG << 2) /*&& (val & 3) == 0*/; } bool is_Argument() const { return val != (MAX_ARG << 2) && (val & 3) == 0; } - bool is_Return() const { return val == (MAX_ARG << 2); } - bool is_Local() const { return (val & 3) == 1; } - bool is_Static() const { return (val & 3) == 2; } + bool is_Local() const { return (val & 3) == 1; } + bool is_Static() const { return (val & 3) == 2; } + // No as_Return + unsigned as_Argument() const { assert(is_Argument()); return val >> 2; } + unsigned as_Local() const { assert(is_Local()); return val >> 2; } const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3u); } }; class Wrapper { uintptr_t val; public: - bool is_Deref() const { return (val & 3) == 0; } + static Wrapper new_Deref() { return Wrapper { 0 }; } + static Wrapepr new_Field (unsigned idx) { return Wrapper { (idx << 2) | 1 }; } + static Wrapepr new_Downcast(unsigned idx) { return Wrapper { (idx << 2) | 2 }; } + static Wrapepr new_Index (unsigned idx) { return Wrapper { (idx << 2) | 3 }; } + + bool is_Deref () const { return (val & 3) == 0; } // Stores the field index - bool is_Field() const { return (val & 3) == 1; } + bool is_Field () const { return (val & 3) == 1; } // Stores the variant index bool is_Downcast() const { return (val & 3) == 2; } // Stores a Local index - bool is_Index() const { return (val & 3) == 3; } + bool is_Index () const { return (val & 3) == 3; } + // no as_Deref() const unsigned as_Field() const { assert(is_Field()); return (val >> 2); } + const unsigned as_Downcast() const { assert(is_Downcast()); return (val >> 2); } + // TODO: Should this return a LValue? const unsigned as_Index() const { assert(is_Index()); return (val >> 2); } }; Storage m_root; ::std::vector m_wrappers; + static LValue new_Return() { return LValue { Storage::new_Return(), {} }; } + static LValue new_Argument(unsigned idx) { return LValue { Storage::new_Argument(idx), {} }; } + static LValue new_Local(unsigned idx) { return LValue { Storage::new_Local(idx), {} }; } + static LValue new_Static(::HIR::Path p) { return LValue { Storage::new_Static(::std::move(p)), {} }; } + + static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); } + static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); } + static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); } + static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); } + + LValue monomorphise(const MonomorphState& ms, unsigned local_offset=0); + //LValue monomorphise(const TransParams& ms, unsigned local_offset=0); LValue clone() const; class Ref @@ -159,11 +205,10 @@ TAGGED_UNION_EX(Constant, (), Int, ( }), (Bytes, ::std::vector< ::std::uint8_t>), // Byte string (StaticString, ::std::string), // String - // TODO: Should these ::HIR::Path structures be behind pointers? - // - HIR::Path is ~11 words long, without it MIR::Constant is 4 instead of 12 - // - MIR::Param is quite common, potential large space saving. - (Const, struct { ::HIR::Path p; }), // `const` - (ItemAddr, ::HIR::Path) // address of a value + // NOTE: These are behind pointers to save inline space (HIR::Path is ~11 + // words, compared to 4 for MIR::Constant without it) + (Const, struct { ::std::unique_ptr<::HIR::Path> p; }), // `const` + (ItemAddr, ::std::unique_ptr<::HIR::Path>) // address of a value ), (), (), ( friend ::std::ostream& operator<<(::std::ostream& os, const Constant& v); ::Ordering ord(const Constant& b) const; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 7c284546..a45b1c05 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1213,10 +1213,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool (Bytes, return ::MIR::Constant(ce);), (StaticString, return ::MIR::Constant(ce);), (Const, - return ::MIR::Constant::make_Const({ this->monomorph(ce.p) }); + return ::MIR::Constant::make_Const({ box$(this->monomorph(*ce.p)) }); ), (ItemAddr, - return ::MIR::Constant::make_ItemAddr(this->monomorph(ce)); + return ::MIR::Constant::make_ItemAddr(box$(this->monomorph(*ce))); ) ) throw ""; diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 08b4f2de..d238a523 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -5743,7 +5743,7 @@ namespace { (Const, // TODO: This should have been eliminated? ("MIR Cleanup" should have removed all inline Const references) ::HIR::TypeRef ty; - const auto& lit = get_literal_for_const(c.p, ty); + const auto& lit = get_literal_for_const(*c.p, ty); if(lit.is_Integer() || lit.is_Float()) { emit_literal(ty, lit, {}); @@ -5764,7 +5764,7 @@ namespace { } ), (ItemAddr, - TU_MATCHA( (c.m_data), (pe), + TU_MATCHA( (c->m_data), (pe), (Generic, if( pe.m_path.m_components.size() > 1 && m_crate.get_typeitem_by_path(sp, pe.m_path, false, true).is_Enum() ) ; @@ -5781,7 +5781,7 @@ namespace { } ), (UfcsUnknown, - MIR_BUG(*m_mir_res, "UfcsUnknown in trans " << c); + MIR_BUG(*m_mir_res, "UfcsUnknown in trans " << *c); ), (UfcsInherent, // TODO: If the target is a function, don't emit the & @@ -5792,7 +5792,7 @@ namespace { m_of << "&"; ) ) - m_of << Trans_Mangle(c); + m_of << Trans_Mangle(*c); ) ) } diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp index 4867cf6f..51b8aac3 100644 --- a/src/trans/codegen_mmir.cpp +++ b/src/trans/codegen_mmir.cpp @@ -104,7 +104,7 @@ namespace os << " " << v.t; } break; TU_ARM(e, ItemAddr, v) { - os << "ADDROF " << v; + os << "ADDROF " << *v; } break; default: os << e; diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 00b938ff..934f40a2 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -1541,10 +1541,10 @@ void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Consta (StaticString, ), // String (Const, // - Check if this constant has a value of Defer - Trans_Enumerate_FillFrom_Path(state, ce.p, pp); + Trans_Enumerate_FillFrom_Path(state, *ce.p, pp); ), (ItemAddr, - Trans_Enumerate_FillFrom_Path(state, ce, pp); + Trans_Enumerate_FillFrom_Path(state, *ce, pp); ) ) } diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index cf101443..50924e2f 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -71,15 +71,15 @@ namespace { ), (Const, return ::MIR::Constant::make_Const({ - params.monomorph(resolve, ce.p) + box$(params.monomorph(resolve, *ce.p)) }); ), (ItemAddr, - auto p = params.monomorph(resolve, ce); + auto p = params.monomorph(resolve, *ce); // TODO: If this is a pointer to a function on a trait object, replace with the address loaded from the vtable. // - Requires creating a new temporary for the vtable pointer. // - Also requires knowing what the receiver is. - return ::MIR::Constant( mv$(p) ); + return ::MIR::Constant( box$(p) ); ) ) throw ""; -- cgit v1.2.3 From 4c4dd6e0120877b6a535cef62ee06795b07456d2 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 9 May 2019 22:57:28 +0800 Subject: MIR Optimise - Work around De-Temporary bug that was mis-optimising Vec::retain --- src/mir/optimise.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'src/mir/optimise.cpp') diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index a45b1c05..b1be20a4 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -1411,6 +1411,12 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool return inline_happened; } +// TODO: New pass that removes useless borrows +// ``` +// _$1 = & _$0; +// (*_$1).1 = 0x0; +// ``` + // -------------------------------------------------------------------- // Replaces uses of stack slots with what they were assigned with (when // possible) @@ -1424,6 +1430,7 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn) { auto& bb = fcn.blocks[bb_idx]; ::std::map local_assignments; // Local number -> statement index + // TODO: Keep track of what variables would invalidate a local (and compound on assignment) ::std::vector statements_to_remove; // List of statements that have to be removed // ----- Helper closures ----- @@ -1457,6 +1464,7 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn) case ValUsage::Write: // Mutated? It's invalidated case ValUsage::Move: // Moved? Now invalid visit_mir_lvalues(src_rvalue, [&](const auto& s_lv, auto /*s_vu*/) { + //DEBUG(" " << s_lv << " ?= " << lv); if( s_lv == lv ) { DEBUG(state << "> Invalidates source of Local(" << it->first << ") - " << src_rvalue); @@ -1556,6 +1564,12 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn) { DEBUG(state << "> Don't record, self-referrential"); } + else if( visit_mir_lvalue(stmt.as_Assign().src.as_Use(), ValUsage::Read, [&](const auto& lv, auto /*vu*/) { + return lv.is_Deref(); + }) ) + { + DEBUG(state << "> Don't record, dereference"); + } else { local_assignments.insert(::std::make_pair( stmt.as_Assign().dst.as_Local(), stmt_idx )); -- cgit v1.2.3 From cee20b8f3ab7fd6eca9fddff712b899064d0536b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Tue, 14 May 2019 20:49:40 +0800 Subject: Trans Enumerate - Cache paths used by function --- src/mir/mir.hpp | 16 ++++++ src/mir/optimise.cpp | 4 +- src/trans/enumerate.cpp | 145 +++++++++++++++++++++++++++++++++--------------- 3 files changed, 119 insertions(+), 46 deletions(-) (limited to 'src/mir/optimise.cpp') diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index c24aac51..ebef039a 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -402,6 +402,19 @@ struct BasicBlock }; +struct EnumCache; // Defined in trans/enumerate.cpp +class EnumCachePtr +{ + const EnumCache* p; +public: + EnumCachePtr(const EnumCache* p=nullptr): p(p) {} + ~EnumCachePtr(); + EnumCachePtr(EnumCachePtr&& x): p(x.p) { x.p = nullptr; } + EnumCachePtr& operator=(EnumCachePtr&& x) { this->~EnumCachePtr(); p = x.p; x.p = nullptr; return *this; } + operator bool() { return p; } + const EnumCache& operator*() const { return *p; } + const EnumCache* operator->() const { return p; } +}; class Function { public: @@ -410,6 +423,9 @@ public: ::std::vector drop_flags; ::std::vector blocks; + + // Cache filled/used by enumerate + mutable EnumCachePtr trans_enum_state; }; }; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index b1be20a4..440f65db 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -3921,7 +3921,9 @@ void MIR_OptimiseCrate_Inlining(const ::HIR::Crate& crate, TransList& list) else if( hir_fcn.m_code ) { auto& mir = hir_fcn.m_code.get_mir_or_error_mut(Span()); - did_inline_on_pass |= MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list); + bool did_opt = MIR_OptimiseInline(resolve, ip, mir, hir_fcn.m_args, hir_fcn.m_return, list); + mir.trans_enum_state = ::MIR::EnumCachePtr(); // Clear MIR enum cache + did_inline_on_pass |= did_opt; } else { diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 934f40a2..4567c0e7 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -51,7 +51,7 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Function& function, void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Static& stat, TransList_Static& stat_out, Trans_Params pp={}); void Trans_Enumerate_FillFrom_VTable (EnumState& state, ::HIR::Path vtable_path, const Trans_Params& pp); void Trans_Enumerate_FillFrom_Literal(EnumState& state, const ::HIR::Literal& lit, const Trans_Params& pp); -void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, const Trans_Params& pp); +void Trans_Enumerate_FillFrom_MIR(MIR::EnumCache& state, const ::MIR::Function& code); /// Enumerate trans items starting from `::main` (binary crate) TransList Trans_Enumerate_Main(const ::HIR::Crate& crate) @@ -336,6 +336,7 @@ TransList Trans_Enumerate_Public(::HIR::Crate& crate) return rv; } +#if 0 void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list) { EnumState state { crate }; @@ -381,6 +382,7 @@ void Trans_Enumerate_Cleanup(const ::HIR::Crate& crate, TransList& list) ASSERT_BUG(Span(), it != list.m_functions.end(), "Enumerate Error - New function appeared after monomorphisation - " << e.first); } } +#endif /// Common post-processing void Trans_Enumerate_CommonPost_Run(EnumState& state) @@ -1346,6 +1348,48 @@ namespace { } } +namespace MIR { + struct EnumCache + { + ::std::vector paths; + ::std::vector typeids; + EnumCache() + { + } + void insert_path(const ::HIR::Path& new_path) + { + for(const auto* p : this->paths) + if( *p == new_path ) + return ; + this->paths.push_back(&new_path); + } + void insert_typeid(const ::HIR::TypeRef& new_ty) + { + for(const auto* p : this->typeids) + if( *p == new_ty ) + return ; + this->typeids.push_back(&new_ty); + } + + void apply(EnumState& state, const Trans_Params& pp) const + { + for(const auto* ty_p : this->typeids) + { + state.rv.m_typeids.insert( pp.monomorph(state.crate, *ty_p) ); + } + for(const auto& path : this->paths) + { + Trans_Enumerate_FillFrom_Path(state, *path, pp); + } + } + }; + EnumCachePtr::~EnumCachePtr() + { + delete this->p; + this->p = nullptr; + } +} + void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, const Trans_Params& pp) { TRACE_FUNCTION_F(path); @@ -1491,7 +1535,9 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co { if( auto* slot = state.rv.add_const(mv$(path_mono)) ) { - Trans_Enumerate_FillFrom_MIR(state, *e->m_value.m_mir, sub_pp); + MIR::EnumCache es; + Trans_Enumerate_FillFrom_MIR(es, *e->m_value.m_mir); + es.apply(state, sub_pp); slot->ptr = e; slot->pp = ::std::move(sub_pp); } @@ -1503,7 +1549,8 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co } } } -void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& lv, const Trans_Params& pp) + +void Trans_Enumerate_FillFrom_MIR_LValue(MIR::EnumCache& state, const ::MIR::LValue& lv) { TU_MATCHA( (lv), (e), (Return, @@ -1513,24 +1560,24 @@ void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& (Local, ), (Static, - Trans_Enumerate_FillFrom_Path(state, *e, pp); + state.insert_path(*e); ), (Field, - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val); ), (Deref, - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val); ), (Index, - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.idx, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.idx); ), (Downcast, - Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val); ) ) } -void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Constant& c, const Trans_Params& pp) +void Trans_Enumerate_FillFrom_MIR_Constant(MIR::EnumCache& state, const ::MIR::Constant& c) { TU_MATCHA( (c), (ce), (Int, ), @@ -1541,21 +1588,21 @@ void Trans_Enumerate_FillFrom_MIR_Constant(EnumState& state, const ::MIR::Consta (StaticString, ), // String (Const, // - Check if this constant has a value of Defer - Trans_Enumerate_FillFrom_Path(state, *ce.p, pp); + state.insert_path(*ce.p); ), (ItemAddr, - Trans_Enumerate_FillFrom_Path(state, *ce, pp); + state.insert_path(*ce); ) ) } -void Trans_Enumerate_FillFrom_MIR_Param(EnumState& state, const ::MIR::Param& p, const Trans_Params& pp) +void Trans_Enumerate_FillFrom_MIR_Param(MIR::EnumCache& state, const ::MIR::Param& p) { TU_MATCHA( (p), (e), - (LValue, Trans_Enumerate_FillFrom_MIR_LValue(state, e, pp); ), - (Constant, Trans_Enumerate_FillFrom_MIR_Constant(state, e, pp); ) + (LValue, Trans_Enumerate_FillFrom_MIR_LValue(state, e); ), + (Constant, Trans_Enumerate_FillFrom_MIR_Constant(state, e); ) ) } -void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, const Trans_Params& pp) +void Trans_Enumerate_FillFrom_MIR(MIR::EnumCache& state, const ::MIR::Function& code) { for(const auto& bb : code.blocks) { @@ -1564,63 +1611,63 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, TU_MATCHA((stmt), (se), (Assign, DEBUG("- " << se.dst << " = " << se.src); - Trans_Enumerate_FillFrom_MIR_LValue(state, se.dst, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, se.dst); TU_MATCHA( (se.src), (e), (Use, - Trans_Enumerate_FillFrom_MIR_LValue(state, e, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e); ), (Constant, - Trans_Enumerate_FillFrom_MIR_Constant(state, e, pp); + Trans_Enumerate_FillFrom_MIR_Constant(state, e); ), (SizedArray, - Trans_Enumerate_FillFrom_MIR_Param(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, e.val); ), (Borrow, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (Cast, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (BinOp, - Trans_Enumerate_FillFrom_MIR_Param(state, e.val_l, pp); - Trans_Enumerate_FillFrom_MIR_Param(state, e.val_r, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, e.val_l); + Trans_Enumerate_FillFrom_MIR_Param(state, e.val_r); ), (UniOp, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (DstMeta, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (DstPtr, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (MakeDst, - Trans_Enumerate_FillFrom_MIR_Param(state, e.ptr_val, pp); - Trans_Enumerate_FillFrom_MIR_Param(state, e.meta_val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, e.ptr_val); + Trans_Enumerate_FillFrom_MIR_Param(state, e.meta_val); ), (Tuple, for(const auto& val : e.vals) - Trans_Enumerate_FillFrom_MIR_Param(state, val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, val); ), (Array, for(const auto& val : e.vals) - Trans_Enumerate_FillFrom_MIR_Param(state, val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, val); ), (Variant, - Trans_Enumerate_FillFrom_MIR_Param(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, e.val); ), (Struct, for(const auto& val : e.vals) - Trans_Enumerate_FillFrom_MIR_Param(state, val, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, val); ) ) ), (Asm, DEBUG("- asm! ..."); for(const auto& v : se.inputs) - Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, v.second); for(const auto& v : se.outputs) - Trans_Enumerate_FillFrom_MIR_LValue(state, v.second, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, v.second); ), (SetDropFlag, ), @@ -1628,7 +1675,7 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, ), (Drop, DEBUG("- DROP " << se.slot); - Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, se.slot); // TODO: Ensure that the drop glue for this type is generated ) ) @@ -1641,32 +1688,32 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, (Goto, ), (Panic, ), (If, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.cond, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.cond); ), (Switch, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (SwitchValue, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val); ), (Call, - Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val); TU_MATCHA( (e.fcn), (e2), (Value, - Trans_Enumerate_FillFrom_MIR_LValue(state, e2, pp); + Trans_Enumerate_FillFrom_MIR_LValue(state, e2); ), (Path, - Trans_Enumerate_FillFrom_Path(state, e2, pp); + state.insert_path(e2); ), (Intrinsic, if( e2.name == "type_id" ) { // Add ::#type_id to the enumerate list - state.rv.m_typeids.insert( pp.monomorph(state.crate, e2.params.m_types.at(0)) ); + state.insert_typeid(e2.params.m_types.at(0)); } ) ) for(const auto& arg : e.args) - Trans_Enumerate_FillFrom_MIR_Param(state, arg, pp); + Trans_Enumerate_FillFrom_MIR_Param(state, arg); ) ) } @@ -1765,7 +1812,15 @@ void Trans_Enumerate_FillFrom(EnumState& state, const ::HIR::Function& function, TRACE_FUNCTION_F("Function pp=" << pp.pp_method<<"+"<apply(state, pp); } else { -- cgit v1.2.3 From dab72ad78160ecd2a4d1759174cee837a5bedcbc Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jun 2019 11:55:02 +0800 Subject: MIR - Refactor LValue to reduce size and linked-list-ness (seems to have had a ~10% reduction in memory usage) --- Notes/MIR-PackedLValue.txt | 65 ++++ src/hir/deserialise.cpp | 32 +- src/hir/serialise.cpp | 41 +-- src/hir_conv/bind.cpp | 27 +- src/hir_conv/constant_evaluation.cpp | 112 +++---- src/include/tagged_union.hpp | 7 +- src/mir/check.cpp | 173 +++++----- src/mir/check_full.cpp | 230 ++++++-------- src/mir/cleanup.cpp | 82 +++-- src/mir/dump.cpp | 35 +- src/mir/from_hir.cpp | 76 ++--- src/mir/from_hir.hpp | 15 +- src/mir/from_hir_match.cpp | 112 +++---- src/mir/helpers.cpp | 135 ++++---- src/mir/helpers.hpp | 11 +- src/mir/mir.cpp | 189 ++++------- src/mir/mir.hpp | 402 ++++++++++++++++++----- src/mir/mir_builder.cpp | 597 ++++++++++++++++------------------- src/mir/optimise.cpp | 587 ++++++++++++++++++---------------- src/trans/auto_impls.cpp | 20 +- src/trans/codegen_c.cpp | 287 +++++++++-------- src/trans/codegen_mmir.cpp | 103 +++--- src/trans/enumerate.cpp | 340 ++++++-------------- src/trans/monomorphise.cpp | 40 +-- 24 files changed, 1863 insertions(+), 1855 deletions(-) create mode 100644 Notes/MIR-PackedLValue.txt (limited to 'src/mir/optimise.cpp') diff --git a/Notes/MIR-PackedLValue.txt b/Notes/MIR-PackedLValue.txt new file mode 100644 index 00000000..ce889aee --- /dev/null +++ b/Notes/MIR-PackedLValue.txt @@ -0,0 +1,65 @@ +Problem statement: +- MIR LValues are very common, and suffer from excessive indirection when + dereferences and field accesses are present +- Many MIR analysis passes care most about the inner values +- Pointer chasing ruins cache locality + +Solution: Replace the tagged union tree with a flatteded structure + +Quirk: Indexing takes two LValues to produce one BUT one of those is of a +lesser class, so doesn't need to be treated the same. + + + +Structure proposal: +---- +A LValue is made up of: +- A root value (referencing a local, argument, static, or the return value) +- And a list of wrappers (dereference, field, downcast, index) + +Root values are encoded as a packed pointer/value and tag, with the tag stored in the low 2 bits of the pointer +- This allows a 32-bit pointer to a word to be stored, using the alignment bits as tag +- Arguments and locals are encoded with the argument/local index in the "data" bits +- Return value is encoded as argument `-1` (all 1 bits in data) +- Statics are encoded as a pointer to a `::HIR::Path` + - This adds a new pointer access and allocation vs the existing LValue structure + - HIR::Path already has a bunch of pointers in it, may not hurt that much (and may help by keeping the normal size + of the LValue down) + +Wrappers are stored as a vector of words, packed in a similar way to root values +- Dereference is stored just as an entry (could pack multiple derefs into one, but that would make handling more + difficult) +- Field/Downcast is stored with the field/variant index in the "data" bits +- Indexing is stored as a pointer to a LValue + - ALTERNATIVE: Could require that indexing always uses a local, and just store the local index + - This would vastly reduce complexity in handling the Index wrapper, BUT would add a new statement in some cases + - A quick scan of the MMIR output of libstd crates, shows that the vast majority of indexing cases are with a local + directly. + - Doing so would simplify monomorph/clone/serialise (no need to clone the wrapper list, just copy it). + - Would also improve comparison times + + + +Usecase comparisons +------ +(Using 32-bit architecture) + +NOTES: +- Existing `LValue` structure is 3 words long (1 tag, plus 2 pointers for largest variant) + - WRONG. It's actually far larger due to the ::HIR::Path embedded in it (estimate at least 8 pointers, very likely + more). That should be fixed given the number of LValue-s that exist + - Fixed now, had a slight improvement in compile times (and memory usage?) +- New structure is 4 words long (root value, plus len/cap/ptr for vector) + +- Field access via `&self` + - Old: Field(Deref(Argument(0)), 0) + - 12 + 12 + 12 = 36 bytes w/ 2 pointers + - New: LValue( Argument(0), { Deref, Field(0) } ) + - 16 + 8 = 24 bytes w/ 1 pointer + +- Array stored in `&self` (common in librand) + - `(*arg0).2[var16].0` + - Old: Field( Index(Field(Deref(Argument(0)), 2), Local(16)), 0 ) + - 12 * 5 + 12 = 72 bytes 2/ 5 pointers + - New: LValue( Argument(0), { Deref, Field(2), Index(16), Field(0) } ) + - 16 + 16 = 32 bytes w/ 1 pointer diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 56671a04..35aeacca 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -464,32 +464,15 @@ rv = deserialise_mir_lvalue_(); return rv; } + ::MIR::LValue::Wrapper deserialise_mir_lvalue_wrapper() + { + return ::MIR::LValue::Wrapper::from_inner(m_in.read_count()); + } ::MIR::LValue deserialise_mir_lvalue_() { - switch(auto tag = m_in.read_tag()) - { - #define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ ); - _(Return, {}) - _(Argument, { static_cast(m_in.read_count()) } ) - _(Local, static_cast(m_in.read_count()) ) - _(Static, box$(deserialise_path()) ) - _(Field, { - box$( deserialise_mir_lvalue() ), - static_cast(m_in.read_count()) - } ) - _(Deref, { box$( deserialise_mir_lvalue() ) }) - _(Index, { - box$( deserialise_mir_lvalue() ), - box$( deserialise_mir_lvalue() ) - } ) - _(Downcast, { - box$( deserialise_mir_lvalue() ), - static_cast(m_in.read_count()) - } ) - #undef _ - default: - BUG(Span(), "Bad tag for MIR::LValue - " << tag); - } + auto root_v = m_in.read_count(); + auto root = (root_v == 3 ? ::MIR::LValue::Storage::new_Static(deserialise_path()) : ::MIR::LValue::Storage::from_inner(root_v)); + return ::MIR::LValue( mv$(root), deserialise_vec<::MIR::LValue::Wrapper>() ); } ::MIR::RValue deserialise_mir_rvalue() { @@ -827,6 +810,7 @@ template<> DEF_D( ::HIR::TraitValueItem, return d.deserialise_traitvalueitem(); ) template<> DEF_D( ::MIR::Param, return d.deserialise_mir_param(); ) + template<> DEF_D( ::MIR::LValue::Wrapper, return d.deserialise_mir_lvalue_wrapper(); ) template<> DEF_D( ::MIR::LValue, return d.deserialise_mir_lvalue(); ) template<> DEF_D( ::MIR::Statement, return d.deserialise_mir_statement(); ) template<> DEF_D( ::MIR::BasicBlock, return d.deserialise_mir_basicblock(); ) diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index c15630d9..fc53e245 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -722,35 +722,18 @@ void serialise(const ::MIR::LValue& lv) { TRACE_FUNCTION_F("LValue = "<(lv.tag()) ); - TU_MATCHA( (lv), (e), - (Return, - ), - (Argument, - m_out.write_count(e.idx); - ), - (Local, - m_out.write_count(e); - ), - (Static, - serialise_path(*e); - ), - (Field, - serialise(e.val); - m_out.write_count(e.field_index); - ), - (Deref, - serialise(e.val); - ), - (Index, - serialise(e.val); - serialise(e.idx); - ), - (Downcast, - serialise(e.val); - m_out.write_count(e.variant_index); - ) - ) + if( lv.m_root.is_Static() ) { + m_out.write_count(3); + serialise_path(lv.m_root.as_Static()); + } + else { + m_out.write_count( lv.m_root.get_inner() ); + } + serialise_vec(lv.m_wrappers); + } + void serialise(const ::MIR::LValue::Wrapper& w) + { + m_out.write_count(w.get_inner()); } void serialise(const ::MIR::RValue& val) { diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 84854315..e3441157 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -704,30 +704,9 @@ namespace { struct H { static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv) { - TU_MATCHA( (lv), (e), - (Return, - ), - (Local, - ), - (Argument, - ), - (Static, - upper_visitor.visit_path(*e, ::HIR::Visitor::PathContext::VALUE); - ), - (Field, - H::visit_lvalue(upper_visitor, *e.val); - ), - (Deref, - H::visit_lvalue(upper_visitor, *e.val); - ), - (Index, - H::visit_lvalue(upper_visitor, *e.val); - H::visit_lvalue(upper_visitor, *e.idx); - ), - (Downcast, - H::visit_lvalue(upper_visitor, *e.val); - ) - ) + if( lv.m_root.is_Static() ) { + upper_visitor.visit_path(lv.m_root.as_Static(), ::HIR::Visitor::PathContext::VALUE); + } } static void visit_constant(Visitor& upper_visitor, ::MIR::Constant& e) { diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index b97a6ae0..500ac490 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -293,61 +293,66 @@ namespace HIR { ::HIR::Literal& get_lval(const ::MIR::LValue& lv) { - TU_MATCHA( (lv), (e), + ::HIR::Literal* lit_ptr; + TRACE_FUNCTION_FR(lv, *lit_ptr); + TU_MATCHA( (lv.m_root), (e), (Return, - return retval; + lit_ptr = &retval; ), (Local, - if( e >= locals.size() ) - MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size()); - return locals[e]; + MIR_ASSERT(state, e < locals.size(), "Local index out of range - " << e << " >= " << locals.size()); + lit_ptr = &locals[e]; ), (Argument, - if( e.idx >= args.size() ) - MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size()); - return args[e.idx]; + MIR_ASSERT(state, e < args.size(), "Argument index out of range - " << e << " >= " << args.size()); + lit_ptr = &args[e]; ), (Static, - MIR_TODO(state, "LValue::Static - " << *e); - ), - (Field, - auto& val = get_lval(*e.val); - MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv); - auto& vals = val.as_List(); - MIR_ASSERT(state, e.field_index < vals.size(), "LValue::Field index out of range"); - return vals[ e.field_index ]; - ), - (Deref, - auto& val = get_lval(*e.val); - TU_MATCH_DEF( ::HIR::Literal, (val), (ve), - ( - MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }"); - ), - (BorrowData, - return *ve; - ), - (String, - // Just clone the string (hack) - // - TODO: Create a list? - return val; - ) - ) - ), - (Index, - auto& val = get_lval(*e.val); - MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv); - auto& idx = get_lval(*e.idx); - MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv); - auto& vals = val.as_List(); - auto idx_v = static_cast( idx.as_Integer() ); - MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range"); - return vals[ idx_v ]; - ), - (Downcast, - MIR_TODO(state, "LValue::Downcast - " << lv); + MIR_TODO(state, "LValue::Static - " << e); ) ) - throw ""; + + for(const auto& w : lv.m_wrappers) + { + auto& val = *lit_ptr; + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, e) { + MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv); + auto& vals = val.as_List(); + MIR_ASSERT(state, e < vals.size(), "LValue::Field index out of range"); + lit_ptr = &vals[ e ]; + } + TU_ARMA(Deref, e) { + TU_MATCH_DEF( ::HIR::Literal, (val), (ve), + ( + MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }"); + ), + (BorrowData, + lit_ptr = &*ve; + ), + (String, + // Just clone the string (hack) + // - TODO: Create a list? + lit_ptr = &val; + ) + ) + } + TU_ARMA(Index, e) { + MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv); + MIR_ASSERT(state, e < locals.size(), "LValue::Index index local out of range"); + auto& idx = locals[e]; + MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv); + auto& vals = val.as_List(); + auto idx_v = static_cast( idx.as_Integer() ); + MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range"); + lit_ptr = &vals[ idx_v ]; + } + TU_ARMA(Downcast, e) { + MIR_TODO(state, "LValue::Downcast - " << lv); + } + } + } + return *lit_ptr; } ::HIR::Literal read_lval(const ::MIR::LValue& lv) { @@ -481,17 +486,14 @@ namespace HIR { MIR_BUG(state, "Only shared borrows are allowed in constants"); } - if( e.type != ::HIR::BorrowType::Shared ) { - MIR_BUG(state, "Only shared borrows are allowed in constants"); - } - if( const auto* p = e.val.opt_Deref() ) { - if( p->val->is_Deref() ) - MIR_TODO(state, "Undo nested deref coercion - " << *p->val); - val = local_state.read_lval(*p->val); + if( !e.val.m_wrappers.empty() && e.val.m_wrappers.back().is_Deref() ) { + //if( p->val->is_Deref() ) + // MIR_TODO(state, "Undo nested deref coercion - " << *p->val); + val = local_state.read_lval(e.val.clone_unwrapped()); } - else if( const auto* p = e.val.opt_Static() ) { + else if( e.val.m_wrappers.empty() && e.val.m_root.is_Static() ){ // Borrow of a static, emit BorrowPath with the same path - val = ::HIR::Literal::make_BorrowPath( (*p)->clone() ); + val = ::HIR::Literal::make_BorrowPath( e.val.m_root.as_Static().clone() ); } else { auto inner_val = local_state.read_lval(e.val); diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index dab7f8ea..5a3359b8 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -28,7 +28,6 @@ #define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__) #define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__) - // Argument iteration #define TU_DISP0(n) #define TU_DISP1(n, _1) n _1 @@ -105,7 +104,7 @@ */ TU_MATCH_ARMS(CLASS, VAR, NAME, __VA_ARGS__)/* */ default: {TU_EXP DEF;} break;/* */} -#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ auto& NAME = (VAR).as_##TAG(); (void)&NAME; +#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)&NAME; #define TU_MATCH_BIND2_(TAG, v1,v2, n1,n2) TU_MATCH_BIND1(TAG, v1, n1) TU_MATCH_BIND1(TAG, v2, n2) #define TU_MATCH_BIND2(...) TU_EXP1( TU_MATCH_BIND2_(__VA_ARGS__) ) // << Exists to cause expansion of the vars #define TU_MATCH_ARM(CLASS, VAR, NAME, TAG, ...) case CLASS::TAG_##TAG: {/* @@ -119,12 +118,12 @@ #define TU_MATCH_HDR(VARS, brace) TU_MATCH_HDR_(::std::remove_reference::type, VARS, brace) #define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false) #define TU_MATCH_HDRA(VARS, brace) TU_MATCH_HDRA_(::std::remove_reference::type, VARS, brace) #define TU_MATCH_HDRA_(CLASS, VARS, brace) auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used"); // Evil hack: two for loops, the inner stops the outer after it's done. -#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) +#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype(tu_match_hdr2_v.as_##TAG()) NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false) //#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST) #define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST) diff --git a/src/mir/check.cpp b/src/mir/check.cpp index 0b032bbc..6ed34563 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -116,6 +116,11 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn { } + explicit ValStates(const ValStates& v) = default; + ValStates(ValStates&& v) = default; + ValStates& operator=(const ValStates& v) = delete; + ValStates& operator=(ValStates&& v) = default; + void fmt(::std::ostream& os) { os << "ValStates { "; switch(ret_state) @@ -159,12 +164,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn return locals.empty() && args.empty(); } + // NOTE: Moves if this state is empty bool merge(unsigned bb_idx, ValStates& other) { DEBUG("bb" << bb_idx << " this=" << FMT_CB(ss,this->fmt(ss);) << ", other=" << FMT_CB(ss,other.fmt(ss);)); if( this->empty() ) { - *this = other; + *this = ValStates(other); return true; } else if( *this == other ) @@ -183,34 +189,38 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn void mark_validity(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv, bool is_valid) { - TU_MATCH_DEF( ::MIR::LValue, (lv), (e), - ( - ), + if( !lv.m_wrappers.empty()) + { + return ; + } + TU_MATCHA( (lv.m_root), (e), (Return, ret_state = is_valid ? State::Valid : State::Invalid; ), (Argument, - MIR_ASSERT(state, e.idx < this->args.size(), "Argument index out of range"); - DEBUG("arg$" << e.idx << " = " << (is_valid ? "Valid" : "Invalid")); - this->args[e.idx] = is_valid ? State::Valid : State::Invalid; + MIR_ASSERT(state, e < this->args.size(), "Argument index out of range " << lv); + DEBUG("arg$" << e << " = " << (is_valid ? "Valid" : "Invalid")); + this->args[e] = is_valid ? State::Valid : State::Invalid; ), (Local, - MIR_ASSERT(state, e < this->locals.size(), "Local index out of range"); + MIR_ASSERT(state, e < this->locals.size(), "Local index out of range - " << lv); DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid")); this->locals[e] = is_valid ? State::Valid : State::Invalid; + ), + (Static, ) ) } void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv) { - TU_MATCH( ::MIR::LValue, (lv), (e), + TU_MATCHA( (lv.m_root), (e), (Return, if( this->ret_state != State::Valid ) MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Argument, - MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range"); - if( this->args[e.idx] != State::Valid ) + MIR_ASSERT(state, e < this->args.size(), "Arg index out of range"); + if( this->args[e] != State::Valid ) MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Local, @@ -219,27 +229,22 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Static, - ), - (Field, - ensure_valid(state, *e.val); - ), - (Deref, - ensure_valid(state, *e.val); - ), - (Index, - ensure_valid(state, *e.val); - ensure_valid(state, *e.idx); - ), - (Downcast, - ensure_valid(state, *e.val); ) ) + + for(const auto& w : lv.m_wrappers) + { + if( w.is_Index() ) + { + if( this->locals[w.as_Index()] != State::Valid ) + MIR_BUG(state, "Use of non-valid lvalue - " << ::MIR::LValue::new_Local(w.as_Index())); + } + } } void move_val(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv) { ensure_valid(state, lv); - ::HIR::TypeRef tmp; - if( ! state.m_resolve.type_is_copy( state.sp, state.get_lvalue_type(tmp, lv) ) ) + if( ! state.lvalue_is_copy(lv) ) { mark_validity(state, lv, false); } @@ -284,20 +289,29 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn ::std::vector path; ValStates state; }; + // TODO: Remove this? The path is useful, but the cloned states are really expensive + // - Option: Keep the paths, but only ever use the pre-set entry state? ::std::vector to_visit_blocks; // TODO: Check that all used locals are also set (anywhere at all) - auto add_to_visit = [&](unsigned int idx, ::std::vector src_path, auto vs) { + auto add_to_visit = [&](unsigned int idx, ::std::vector src_path, ValStates& vs, bool can_move) { for(const auto& b : to_visit_blocks) if( b.bb == idx && b.state == vs) return ; if( block_start_states.at(idx) == vs ) return ; src_path.push_back(idx); - to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } ); + // TODO: Update the target block, and only visit if we've induced a change + to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), (can_move ? mv$(vs) : ValStates(vs)) } ); + }; + auto add_to_visit_move = [&](unsigned int idx, ::std::vector src_path, ValStates vs) { + add_to_visit(idx, mv$(src_path), vs, true); + }; + auto add_to_visit_copy = [&](unsigned int idx, ::std::vector src_path, ValStates& vs) { + add_to_visit(idx, mv$(src_path), vs, false); }; - add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } ); + add_to_visit_move( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } ); while( to_visit_blocks.size() > 0 ) { auto block = to_visit_blocks.back().bb; @@ -311,7 +325,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn if( ! block_start_states.at(block).merge(block, val_state) ) { continue ; } - DEBUG("BB" << block << " via [" << path << "]"); + ASSERT_BUG(Span(), val_state.locals.size() == fcn.locals.size(), ""); + DEBUG("BB" << block << " via [" << path << "] " << FMT_CB(ss,val_state.fmt(ss);)); // 2. Using the newly merged state, iterate statements checking the usage and updating state. const auto& bb = fcn.blocks[block]; @@ -411,13 +426,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn // 3. Pass new state on to destination blocks state.set_cur_stmt_term(block); DEBUG(state << bb.terminator); - TU_MATCH(::MIR::Terminator, (bb.terminator), (e), - (Incomplete, + TU_MATCH_HDRA( (bb.terminator), { ) + TU_ARMA(Incomplete, e) { // Should be impossible here. - ), - (Return, + } + TU_ARMA(Return, e) { // Check if the return value has been set - val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) ); + val_state.ensure_valid( state, ::MIR::LValue::new_Return() ); // Ensure that no other non-Copy values are valid for(unsigned int i = 0; i < val_state.locals.size(); i ++) { @@ -432,51 +447,51 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn // TODO: Error, becuase this has just been leaked } } - ), - (Diverge, + } + TU_ARMA(Diverge, e) { // TODO: Ensure that cleanup has been performed. - ), - (Goto, + } + TU_ARMA(Goto, e) { // Push block with the new state - add_to_visit( e, mv$(path), mv$(val_state) ); - ), - (Panic, + add_to_visit_move( e, mv$(path), mv$(val_state) ); + } + TU_ARMA(Panic, e) { // What should be done here? - ), - (If, + } + TU_ARMA(If, e) { // Push blocks val_state.ensure_valid( state, e.cond ); - add_to_visit( e.bb0, path, val_state ); - add_to_visit( e.bb1, mv$(path), mv$(val_state) ); - ), - (Switch, + add_to_visit_copy( e.bb0, path, val_state ); + add_to_visit_move( e.bb1, mv$(path), mv$(val_state) ); + } + TU_ARMA(Switch, e) { val_state.ensure_valid( state, e.val ); for(const auto& tgt : e.targets) { - add_to_visit( tgt, path, val_state ); + add_to_visit( tgt, path, val_state, (&tgt == &e.targets.back()) ); } - ), - (SwitchValue, + } + TU_ARMA(SwitchValue, e) { val_state.ensure_valid( state, e.val ); for(const auto& tgt : e.targets) { - add_to_visit( tgt, path, val_state ); + add_to_visit_copy( tgt, path, val_state ); + } + add_to_visit_move( e.def_target, path, mv$(val_state) ); } - add_to_visit( e.def_target, path, val_state ); - ), - (Call, + TU_ARMA(Call, e) { if( e.fcn.is_Value() ) val_state.ensure_valid( state, e.fcn.as_Value() ); for(const auto& arg : e.args) val_state.move_val( state, arg ); // Push blocks (with return valid only in one) - add_to_visit(e.panic_block, path, val_state); + add_to_visit_copy(e.panic_block, path, val_state); // TODO: If the function returns !, don't follow the ret_block val_state.mark_validity( state, e.ret_val, true ); - add_to_visit(e.ret_block, mv$(path), mv$(val_state)); - ) - ) + add_to_visit_move(e.ret_block, mv$(path), mv$(val_state)); + } + } } } @@ -838,33 +853,33 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path state.set_cur_stmt_term(bb_idx); DEBUG(state << bb.terminator); - TU_MATCH(::MIR::Terminator, (bb.terminator), (e), - (Incomplete, - ), - (Return, + TU_MATCH_HDRA( (bb.terminator), {) + TU_ARMA(Incomplete, e) { + } + TU_ARMA(Return, e) { // TODO: Check if the function can return (i.e. if its return type isn't an empty type) - ), - (Diverge, - ), - (Goto, - ), - (Panic, - ), - (If, + } + TU_ARMA(Diverge, e) { + } + TU_ARMA(Goto, e) { + } + TU_ARMA(Panic, e) { + } + TU_ARMA(If, e) { // Check that condition lvalue is a bool ::HIR::TypeRef tmp; const auto& ty = state.get_lvalue_type(tmp, e.cond); if( ty != ::HIR::CoreType::Bool ) { MIR_BUG(state, "Type mismatch in `If` - expected bool, got " << ty); } - ), - (Switch, + } + TU_ARMA(Switch, e) { // Check that the condition is an enum - ), - (SwitchValue, + } + TU_ARMA(SwitchValue, e) { // Check that the condition's type matches the values - ), - (Call, + } + TU_ARMA(Call, e) { if( e.fcn.is_Value() ) { ::HIR::TypeRef tmp; @@ -875,8 +890,8 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path } } // Typecheck arguments and return value - ) - ) + } + } } } diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index 24a4930a..0cc83c6f 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -446,68 +446,54 @@ namespace } const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const { - TU_MATCHA( (lv), (e), + const State* state_p = nullptr; + TU_MATCHA( (lv.m_root), (e), (Return, - return return_value; + state_p = &return_value; ), (Argument, - return args.at(e.idx); + state_p = &args.at(e); ), (Local, - return locals.at(e); + state_p = &locals.at(e); ), (Static, static State state_of_static(true); return state_of_static; - ), - (Field, - const auto& vs = get_lvalue_state(mir_res, *e.val); - if( vs.is_composite() ) - { - const auto& states = this->get_composite(mir_res, vs); - MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range"); - return states[e.field_index]; - } - else - { - return vs; + ) + ) + + for(const auto& w : lv.m_wrappers) + { + if( state_p->is_composite() ) { + break; } - ), - (Deref, - const auto& vs = get_lvalue_state(mir_res, *e.val); - if( vs.is_composite() ) - { + const auto& vs = *state_p; + state_p = nullptr; + + TU_MATCHA( (w), (e), + (Field, + const auto& states = this->get_composite(mir_res, vs); + MIR_ASSERT(mir_res, e < states.size(), "Field index out of range"); + state_p = &states[e]; + ), + (Deref, MIR_TODO(mir_res, "Deref with composite state"); - } - else - { - return vs; - } - ), - (Index, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - const auto& vs_i = get_lvalue_state(mir_res, *e.idx); - MIR_ASSERT(mir_res, !vs_v.is_composite(), ""); - MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); - //return State(vs_v.is_valid() && vs_i.is_valid()); - MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value"); - return vs_v; - ), - (Downcast, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - if( vs_v.is_composite() ) - { - const auto& states = this->get_composite(mir_res, vs_v); - MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs_v)); - return states[0]; - } - else - { - return vs_v; - } + ), + (Index, + const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e)); + MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value"); + MIR_BUG(mir_res, "Indexing a composite state"); + ), + (Downcast, + const auto& states = this->get_composite(mir_res, vs); + MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs)); + state_p = &states[0]; + ) ) - ) - throw ""; + assert(state_p); + } + return *state_p; } void clear_state(const ::MIR::TypeResolve& mir_res, State& s) { @@ -522,42 +508,47 @@ namespace void set_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv, State new_vs) { TRACE_FUNCTION_F(lv << " = " << StateFmt(*this, new_vs) << " (from " << StateFmt(*this, get_lvalue_state(mir_res, lv)) << ")"); - TU_MATCHA( (lv), (e), + State* state_p = nullptr; + TU_MATCHA( (lv.m_root), (e), (Return, - this->clear_state(mir_res, return_value); - return_value = mv$(new_vs); + state_p = &return_value; ), (Argument, - auto& slot = args.at(e.idx); - this->clear_state(mir_res, slot); - slot = mv$(new_vs); + state_p = &args.at(e); ), (Local, - auto& slot = locals.at(e); - this->clear_state(mir_res, slot); - slot = mv$(new_vs); + state_p = &locals.at(e); ), (Static, - // Ignore. - ), - (Field, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); + return ; + ) + ) + + for(const auto& w : lv.m_wrappers) + { + auto& cur_vs = *state_p; + + // If this is not a composite, and it matches the new state if( !cur_vs.is_composite() && cur_vs == new_vs ) { - // Not a composite, and no state change + // Early return + return; } - else - { - ::std::vector* states_p; + + state_p = nullptr; + TU_MATCHA( (w), (e), + (Field, + // Current isn't a composite, we need to change that if( !cur_vs.is_composite() ) { ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, *e.val); + const auto& ty = mir_res.get_lvalue_type(tmp, lv, /*wrapper_skip_count=*/(&lv.m_wrappers.back() - &w)); unsigned int n_fields = 0; if( const auto* e = ty.m_data.opt_Tuple() ) { n_fields = e->size(); } + // TODO: Fixed-size arrays else if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Struct() ) { const auto& e = ty.m_data.as_Path().binding.as_Struct(); @@ -573,94 +564,59 @@ namespace ) ) } - else { + else + { MIR_BUG(mir_res, "Unknown type being accessed with Field - " << ty); } - auto new_cur_vs = this->allocate_composite(n_fields, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); - } - else - { - states_p = &this->get_composite(mir_res, cur_vs); + cur_vs = State(this->allocate_composite(n_fields, cur_vs)); } // Get composite state and assign into it - auto& states = *states_p; - MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range"); - this->clear_state(mir_res, states[e.field_index]); - states[e.field_index] = mv$(new_vs); - } - ), - (Deref, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); - if( !cur_vs.is_composite() && cur_vs == new_vs ) - { - // Not a composite, and no state change - } - else - { - ::std::vector* states_p; + auto& states = this->get_composite(mir_res, cur_vs); + MIR_ASSERT(mir_res, e< states.size(), "Field index out of range"); + state_p = &states[e]; + ), + (Deref, if( !cur_vs.is_composite() ) { + // TODO: Should this check if the type is Box? //::HIR::TypeRef tmp; //const auto& ty = mir_res.get_lvalue_type(tmp, *e.val); - // TODO: Should this check if the type is Box? - auto new_cur_vs = this->allocate_composite(2, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); - } - else - { - states_p = &this->get_composite(mir_res, cur_vs); + cur_vs = State(this->allocate_composite(2, cur_vs)); } // Get composite state and assign into it - auto& states = *states_p; + auto& states = this->get_composite(mir_res, cur_vs); MIR_ASSERT(mir_res, states.size() == 2, "Deref with invalid state list size"); - this->clear_state(mir_res, states[1]); - states[1] = mv$(new_vs); - } - ), - (Index, - const auto& vs_v = get_lvalue_state(mir_res, *e.val); - const auto& vs_i = get_lvalue_state(mir_res, *e.idx); - MIR_ASSERT(mir_res, !vs_v.is_composite(), ""); - MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); + state_p = &states[1]; + ), + (Index, + const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e)); + MIR_ASSERT(mir_res, !cur_vs.is_composite(), ""); + MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); - MIR_ASSERT(mir_res, vs_v.is_valid(), "Indexing an invalid value"); - MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index"); + MIR_ASSERT(mir_res, cur_vs.is_valid(), "Indexing an invalid value"); + MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index"); - // NOTE: Ignore - ), - (Downcast, - const auto& cur_vs = get_lvalue_state(mir_res, *e.val); - if( !cur_vs.is_composite() && cur_vs == new_vs ) - { - // Not a composite, and no state change - } - else - { - ::std::vector* states_p; + // NOTE: Ignore + return ; + ), + (Downcast, if( !cur_vs.is_composite() ) { - auto new_cur_vs = this->allocate_composite(1, cur_vs); - set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); - states_p = &this->get_composite(mir_res, new_cur_vs); + cur_vs = State(this->allocate_composite(1, cur_vs)); } - else - { - states_p = &this->get_composite(mir_res, cur_vs); - } - // Get composite state and assign into it - auto& states = *states_p; - MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << *e.val << " - " << this->fmt_state(mir_res, *e.val)); + auto& states = this->get_composite(mir_res, cur_vs); + MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << lv << " - " << StateFmt(*this, cur_vs)); this->clear_state(mir_res, states[0]); states[0] = mv$(new_vs); - } + ) ) - ) + assert(state_p); + } + this->clear_state(mir_res, *state_p); + *state_p = mv$(new_vs); } }; @@ -939,7 +895,7 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio (Incomplete, ), (Return, - state.ensure_lvalue_valid(mir_res, ::MIR::LValue::make_Return({})); + state.ensure_lvalue_valid(mir_res, ::MIR::LValue::new_Return()); if( ENABLE_LEAK_DETECTOR ) { auto ensure_dropped = [&](const State& s, const ::MIR::LValue& lv) { @@ -955,10 +911,10 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio } }; for(unsigned i = 0; i < state.locals.size(); i ++ ) { - ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i)); + ensure_dropped(state.locals[i], ::MIR::LValue::new_Local(i)); } for(unsigned i = 0; i < state.args.size(); i ++ ) { - ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i})); + ensure_dropped(state.args[i], ::MIR::LValue::new_Argument(i)); } } ), diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 5d32d0c8..b535c7ce 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -33,7 +33,7 @@ struct MirMutator ::MIR::LValue new_temporary(::HIR::TypeRef ty) { - auto rv = ::MIR::LValue::make_Local( static_cast(m_fcn.locals.size()) ); + auto rv = ::MIR::LValue::new_Local( static_cast(m_fcn.locals.size()) ); m_fcn.locals.push_back( mv$(ty) ); return rv; } @@ -493,12 +493,13 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con // Allocate a temporary for the vtable pointer itself auto vtable_lv = mutator.new_temporary( mv$(vtable_ty) ); // - Load the vtable and store it - auto ptr_lv = ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) }); + auto ptr_lv = ::MIR::LValue::new_Deref( receiver_lvp.clone() ); MIR_Cleanup_LValue(state, mutator, ptr_lv); - auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(*ptr_lv.as_Deref().val) }); + ptr_lv.m_wrappers.pop_back(); + auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(ptr_lv) }); mutator.push_statement( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) ); - auto fcn_lval = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx }); + auto fcn_lval = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref( mv$(vtable_lv) ), vtable_idx ); ::HIR::TypeRef tmp; const auto& ty = state.get_lvalue_type(tmp, fcn_lval); @@ -526,23 +527,23 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con ), (Tuple, for(unsigned int i = 0; i < se.size(); i ++ ) { - auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone()); + auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i ); if( i == str.m_struct_markings.coerce_unsized_index ) { - vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), ::MIR::LValue::make_Field({ box$(val), i }) ) ); + vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), mv$(val)) ); } else { - vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) ); + vals.push_back( mv$(val) ); } } ), (Named, for(unsigned int i = 0; i < se.size(); i ++ ) { - auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone()); + auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i ); if( i == str.m_struct_markings.coerce_unsized_index ) { - vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), ::MIR::LValue::make_Field({ box$(val), i }) ) ); + vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), mv$(val) ) ); } else { - vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) ); + vals.push_back( mv$(val) ); } } ) @@ -777,7 +778,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false); auto ty_s = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_s, false); - auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i })); + auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i)); auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) ); ents.push_back( mv$(new_lval) ); @@ -793,7 +794,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } else { - ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) ); + ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) ); } } ), @@ -806,7 +807,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false); auto ty_s = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_s, false); - auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i })); + auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i)); auto new_lval = mutator.new_temporary( mv$(ty_d) ); mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) ); @@ -823,7 +824,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& } else { - ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) ); + ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) ); } } ) @@ -865,7 +866,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator& void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::MIR::LValue& lval) { - TU_MATCHA( (lval), (le), + TU_MATCHA( (lval.m_root), (le), (Return, ), (Argument, @@ -873,30 +874,22 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, :: (Local, ), (Static, - ), - (Field, - MIR_Cleanup_LValue(state, mutator, *le.val); - ), - (Deref, - MIR_Cleanup_LValue(state, mutator, *le.val); - ), - (Index, - MIR_Cleanup_LValue(state, mutator, *le.val); - MIR_Cleanup_LValue(state, mutator, *le.idx); - ), - (Downcast, - MIR_Cleanup_LValue(state, mutator, *le.val); ) ) - // If this is a deref of Box, unpack and deref the inner pointer - if( lval.is_Deref() ) + for(size_t i = 0; i < lval.m_wrappers.size(); i ++) { - auto& le = lval.as_Deref(); + if( !lval.m_wrappers[i].is_Deref() ) { + continue ; + } + + // If this is a deref of Box, unpack and deref the inner pointer ::HIR::TypeRef tmp; - const auto& ty = state.get_lvalue_type(tmp, *le.val); + const auto& ty = state.get_lvalue_type(tmp, lval, lval.m_wrappers.size() - i); if( state.m_resolve.is_type_owned_box(ty) ) { + unsigned num_injected_fld_zeros = 0; + // Handle Box by extracting it to its pointer. // - Locate (or remember) which field in Box is the pointer, and replace the inner by that field // > Dumb idea, assume it's always the first field. Keep accessing until located. @@ -924,11 +917,16 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, :: tmp = monomorphise_type(state.sp, str.m_params, te.path.m_data.as_Generic().m_params, *ty_tpl); typ = &tmp; - auto new_lval = ::MIR::LValue::make_Field({ mv$(le.val), 0 }); - le.val = box$(new_lval); + num_injected_fld_zeros ++; } MIR_ASSERT(state, typ->m_data.is_Pointer(), "First non-path field in Box wasn't a pointer - " << *typ); // We have reached the pointer. Good. + + // Inject all of the field zero accesses (before the deref) + while(num_injected_fld_zeros--) + { + lval.m_wrappers.insert( lval.m_wrappers.begin() + i, ::MIR::LValue::Wrapper::new_Field(0) ); + } } } } @@ -1030,9 +1028,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ), (DstMeta, // HACK: Ensure that the box Deref conversion fires here. - auto v = ::MIR::LValue::make_Deref({ box$(re.val) }); - MIR_Cleanup_LValue(state, mutator, v); - re.val = mv$( *v.as_Deref().val ); + re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() ); + MIR_Cleanup_LValue(state, mutator, re.val); + re.val.m_wrappers.pop_back(); // If the type is an array (due to a monomorpised generic?) then replace. ::HIR::TypeRef tmp; @@ -1053,9 +1051,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ), (DstPtr, // HACK: Ensure that the box Deref conversion fires here. - auto v = ::MIR::LValue::make_Deref({ box$(re.val) }); - MIR_Cleanup_LValue(state, mutator, v); - re.val = mv$( *v.as_Deref().val ); + re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() ); + MIR_Cleanup_LValue(state, mutator, re.val); + re.val.m_wrappers.pop_back(); ), (MakeDst, MIR_Cleanup_Param(state, mutator, re.ptr_val); @@ -1218,13 +1216,13 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, e.args.reserve( fcn_ty.m_arg_types.size() ); for(unsigned int i = 0; i < fcn_ty.m_arg_types.size(); i ++) { - e.args.push_back( ::MIR::LValue::make_Field({ box$(args_lvalue.clone()), i }) ); + e.args.push_back( ::MIR::LValue::new_Field(args_lvalue.clone(), i) ); } // If the trait is Fn/FnMut, dereference the input value. if( pe.trait.m_path == resolve.m_lang_FnOnce ) e.fcn = mv$(fcn_lvalue); else - e.fcn = ::MIR::LValue::make_Deref({ box$(fcn_lvalue) }); + e.fcn = ::MIR::LValue::new_Deref( mv$(fcn_lvalue) ); } } ) diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index b02c1e5b..69ffa850 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -176,40 +176,7 @@ namespace { #undef FMT } void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) { - TU_MATCHA( (lval), (e), - (Return, - os << "RETURN"; - ), - (Argument, - os << "arg$" << e.idx; - ), - (Local, - os << "_$" << e; - ), - (Static, - os << *e; - ), - (Field, - os << "("; - fmt_val(os, *e.val); - os << ")." << e.field_index; - ), - (Deref, - os << "*"; - fmt_val(os, *e.val); - ), - (Index, - os << "("; - fmt_val(os, *e.val); - os << ")["; - fmt_val(os, *e.idx); - os << "]"; - ), - (Downcast, - fmt_val(os, *e.val); - os << " as variant" << e.variant_index; - ) - ) + os << lval; } void fmt_val(::std::ostream& os, const ::MIR::Constant& e) { TU_MATCHA( (e), (ce), diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 9e749811..d511a32a 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -177,7 +177,7 @@ namespace { for(size_t i = 0; i < pat.m_binding.m_implicit_deref_count; i ++) { - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); } switch( pat.m_binding.m_type ) @@ -215,35 +215,35 @@ namespace { for(size_t i = 0; i < pat.m_implicit_deref_count; i ++) { - lval = ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); } TU_MATCH_HDRA( (pat.m_data), {) TU_ARMA(Any, e) { } TU_ARMA(Box, e) { - destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable); + destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable); } TU_ARMA(Ref, e) { - destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable); + destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable); } TU_ARMA(Tuple, e) { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } } TU_ARMA(SplitTuple, e) { assert(e.total_size >= e.leading.size() + e.trailing.size()); for(unsigned int i = 0; i < e.leading.size(); i ++ ) { - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } // TODO: Is there a binding in the middle? unsigned int ofs = e.total_size - e.trailing.size(); for(unsigned int i = 0; i < e.trailing.size(); i ++ ) { - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), ofs+i}), allow_refutable); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), ofs+i), allow_refutable); } } TU_ARMA(StructValue, e) { @@ -252,7 +252,7 @@ namespace { TU_ARMA(StructTuple, e) { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable); } } TU_ARMA(Struct, e) { @@ -264,7 +264,7 @@ namespace { for(const auto& fld_pat : e.sub_patterns) { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); - destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable); + destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable); } } } @@ -302,10 +302,10 @@ namespace { ERROR(sp, E0000, "Variant " << variants[i].name << " not handled"); } } - auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); + auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx); for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ ) { - destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval_var.clone() ), i}), allow_refutable); + destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval_var.clone(), i), allow_refutable); } } TU_ARMA(EnumStruct, e) { @@ -316,11 +316,11 @@ namespace { const auto& str = *var.type.m_data.as_Path().binding.as_Struct(); ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path); const auto& fields = str.m_data.as_Named(); - auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx }); + auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx); for(const auto& fld_pat : e.sub_patterns) { unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin(); - destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval_var.clone() ), idx}), allow_refutable); + destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval_var.clone(), idx), allow_refutable); } } TU_ARMA(Slice, e) { @@ -335,7 +335,7 @@ namespace { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++) { const auto& subpat = e.sub_patterns[i]; - destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable ); + destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable ); } } else @@ -346,7 +346,7 @@ namespace { for(unsigned int i = 0; i < e.sub_patterns.size(); i ++) { const auto& subpat = e.sub_patterns[i]; - destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable ); + destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable ); } } } @@ -374,7 +374,7 @@ namespace { for(unsigned int i = 0; i < e.leading.size(); i ++) { unsigned int idx = 0 + i; - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } if( e.extra_bind.is_valid() ) { @@ -383,7 +383,7 @@ namespace { for(unsigned int i = 0; i < e.trailing.size(); i ++) { unsigned int idx = array_size - e.trailing.size() + i; - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } } else @@ -409,13 +409,13 @@ namespace { ::MIR::LValue len_lval; if( e.extra_bind.is_valid() || e.trailing.size() > 0 ) { - len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval).clone() })); + len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval) })); } for(unsigned int i = 0; i < e.leading.size(); i ++) { unsigned int idx = i; - destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable ); + destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable ); } if( e.extra_bind.is_valid() ) { @@ -427,7 +427,7 @@ namespace { ::HIR::BorrowType bt = H::get_borrow_type(sp, e.extra_bind); ::MIR::LValue ptr_val = m_builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow( bt, inner_type.clone() ), - ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::make_Field({ box$(lval.clone()), static_cast(e.leading.size()) }) }) + ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::new_Field( lval.clone(), static_cast(e.leading.size()) ) }) ); // TODO: Cast to raw pointer? Or keep as a borrow? @@ -442,7 +442,7 @@ namespace { auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ e.trailing.size() - i, ::HIR::CoreType::Usize })); ::MIR::LValue ofs_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ len_lval.clone(), ::MIR::eBinOp::SUB, mv$(sub_val) }) ); // Recurse with the indexed value - destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Index({ box$(lval.clone()), box$(ofs_val) }), allow_refutable); + destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Index( lval.clone(), ofs_val.m_root.as_Local() ), allow_refutable); } } } @@ -574,7 +574,7 @@ namespace { TRACE_FUNCTION_F("_Return"); this->visit_node_ptr(node.m_value); - m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Return({}), m_builder.get_result(node.span()) ); + m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Return(), m_builder.get_result(node.span()) ); m_builder.terminate_scope_early( node.span(), m_builder.fcn_scope() ); m_builder.end_block( ::MIR::Terminator::make_Return({}) ); } @@ -1474,7 +1474,7 @@ namespace { limit_val = ::MIR::Constant::make_Uint({ e.size_val, ::HIR::CoreType::Usize }); ), (Slice, - limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value).clone() }); + limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value) }); ) ) @@ -1508,7 +1508,13 @@ namespace { m_builder.set_cur_block( arm_continue ); } - m_builder.set_result( node.span(), ::MIR::LValue::make_Index({ box$(value), box$(index) }) ); + if( !index.is_Local()) + { + auto local_idx = m_builder.new_temporary(::HIR::CoreType::Usize); + m_builder.push_stmt_assign(node.span(), local_idx.clone(), mv$(index)); + index = mv$(local_idx); + } + m_builder.set_result( node.span(), ::MIR::LValue::new_Index( mv$(value), index.m_root.as_Local() ) ); } void visit(::HIR::ExprNode_Deref& node) override @@ -1591,7 +1597,7 @@ namespace { } } - m_builder.set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Deref( mv$(val) ) ); } void visit(::HIR::ExprNode_Emplace& node) override @@ -1702,7 +1708,7 @@ namespace { // 3. Get the value and assign it into `place_raw` node.m_value->visit(*this); auto val = m_builder.get_result(node.span()); - m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Deref({ box$(place_raw.clone()) }), mv$(val) ); + m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Deref(place_raw.clone()), mv$(val), /*drop_destination=*/false ); // 3. Return a call to `finalize` ::HIR::Path finalize_path(::HIR::GenericPath {}); @@ -1806,9 +1812,7 @@ namespace { auto place = m_builder.new_temporary( place_type ); m_builder.push_stmt_assign(node.span(), place.clone(), ::MIR::RValue::make_Cast({ mv$(place_raw), place_type.clone() })); // 3. Do a non-dropping write into the target location (i.e. just a MIR assignment) - // TODO: This should indicate that the destination shouldn't be dropped, but since drops don't happen on - // reassign currently, that's not yet an issue. - m_builder.push_stmt_assign(node.span(), ::MIR::LValue::make_Deref({box$(place.clone())}), mv$(val)); + m_builder.push_stmt_assign(node.span(), ::MIR::LValue::new_Deref(place.clone()), mv$(val), /*drop_destination=*/false); // 4. Convert the pointer into an `owned_box` auto res_type = ::HIR::TypeRef::new_path(::HIR::GenericPath(lang_owned_box, mv$(trait_params_data)), &m_builder.crate().get_struct_by_path(node.span(), lang_owned_box)); auto res = m_builder.new_temporary(res_type); @@ -2056,20 +2060,20 @@ namespace { unsigned int idx; if( ::std::isdigit(node.m_field.c_str()[0]) ) { ::std::stringstream(node.m_field.c_str()) >> idx; - m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) ); } else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Struct() ) { const auto& str = **bep; const auto& fields = str.m_data.as_Named(); idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); - m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) ); } else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Union() ) { const auto& unm = **bep; const auto& fields = unm.m_variants; idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin(); - m_builder.set_result( node.span(), ::MIR::LValue::make_Downcast({ box$(val), idx }) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Downcast( mv$(val), idx ) ); } else { BUG(node.span(), "Field access on non-union/struct - " << val_ty); @@ -2202,7 +2206,7 @@ namespace { m_builder.set_result( node.span(), mv$(tmp) ); ), (Static, - m_builder.set_result( node.span(), ::MIR::LValue::make_Static(box$(node.m_path.clone())) ); + m_builder.set_result( node.span(), ::MIR::LValue::new_Static(node.m_path.clone()) ); ), (StructConstant, // TODO: Why is this still a PathValue? @@ -2321,7 +2325,7 @@ namespace { ASSERT_BUG(sp, str.m_data.is_Named(), ""); const ::HIR::t_struct_fields& fields = str.m_data.as_Named(); - ::MIR::LValue base_val; + auto base_val = ::MIR::LValue::new_Return(); if( node.m_base_value ) { DEBUG("_StructLiteral - base"); @@ -2362,7 +2366,7 @@ namespace { if( !node.m_base_value) { ERROR(node.span(), E0000, "Field '" << fields[i].first << "' not specified"); } - values[i] = ::MIR::LValue::make_Field({ box$( base_val.clone() ), i }); + values[i] = ::MIR::LValue::new_Field( base_val.clone(), i ); } else { // Partial move support will handle dropping the rest? @@ -2545,7 +2549,7 @@ namespace { else { ev.define_vars_from(ptr->span(), arg.first); - ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::new_Argument(i)); } i ++; } diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 194fd0e0..a1f9a10f 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -188,13 +188,10 @@ public: // - Values ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { - // DIASBLED: State tracking doesn't support arguments in loops/splits -#if 1 auto it = m_var_arg_mappings.find(idx); if(it != m_var_arg_mappings.end()) - return ::MIR::LValue::make_Argument({ it->second }); -#endif - return ::MIR::LValue::make_Local( idx ); + return ::MIR::LValue::new_Argument(it->second); + return ::MIR::LValue::new_Local(idx); } ::MIR::LValue new_temporary(const ::HIR::TypeRef& ty); ::MIR::LValue lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val); @@ -224,7 +221,7 @@ public: // - Statements // Push an assignment. NOTE: This also marks the rvalue as moved - void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val); + void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination=true); // Push a drop (likely only used by scope cleanup) void push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u); // Push a shallow drop (for Box) @@ -296,7 +293,7 @@ private: const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const; VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type); - const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0); + VarState* get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv); VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv); void terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_loop); @@ -306,11 +303,11 @@ private: void complete_scope(ScopeDef& sd); public: - void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb) const; + void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb, const ::MIR::LValue::Wrapper* stop_wrapper=nullptr) const; bool lvalue_is_copy(const Span& sp, const ::MIR::LValue& lv) const; // Obtain the base fat poiner for a dst reference. Errors if it wasn't via a fat pointer - const ::MIR::LValue& get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const; + ::MIR::LValue get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const; }; class MirConverter: diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index e3ddce30..2bfb1a27 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -1732,13 +1732,13 @@ namespace { ), (Tuple, ASSERT_BUG(sp, idx < e.size(), "Tuple index out of range"); - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); cur_ty = &e[idx]; ), (Path, if( idx == FIELD_DEREF ) { // TODO: Check that the path is Box - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref( mv$(lval) ); cur_ty = &e.path.m_data.as_Generic().m_params.m_types.at(0); break; } @@ -1773,7 +1773,7 @@ namespace { else { cur_ty = &fld.ent; } - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); ), (Named, assert( idx < fields.size() ); @@ -1785,7 +1785,7 @@ namespace { else { cur_ty = &fld.ent; } - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); ) ) ), @@ -1804,7 +1804,7 @@ namespace { else { cur_ty = &fld.second.ent; } - lval = ::MIR::LValue::make_Downcast({ box$(lval), idx }); + lval = ::MIR::LValue::new_Downcast(mv$(lval), idx); ), (Enum, auto monomorph_to_ptr = [&](const auto& ty)->const auto* { @@ -1824,7 +1824,7 @@ namespace { const auto& var = variants[idx]; cur_ty = monomorph_to_ptr(var.type); - lval = ::MIR::LValue::make_Downcast({ box$(lval), idx }); + lval = ::MIR::LValue::new_Downcast(mv$(lval), idx); ) ) ), @@ -1841,7 +1841,7 @@ namespace { assert(idx < e.size_val); cur_ty = &*e.inner; if( idx < FIELD_INDEX_MAX ) - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); else { idx -= FIELD_INDEX_MAX; idx = FIELD_INDEX_MAX - idx; @@ -1851,16 +1851,16 @@ namespace { (Slice, cur_ty = &*e.inner; if( idx < FIELD_INDEX_MAX ) - lval = ::MIR::LValue::make_Field({ box$(lval), idx }); + lval = ::MIR::LValue::new_Field(mv$(lval), idx); else { idx -= FIELD_INDEX_MAX; idx = FIELD_INDEX_MAX - idx; // 1. Create an LValue containing the size of this slice subtract `idx` - auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval).clone() })); + auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval) })); auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ idx, ::HIR::CoreType::Usize })); auto ofs_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ mv$(len_lval), ::MIR::eBinOp::SUB, mv$(sub_val) }) ); // 2. Return _Index with that value - lval = ::MIR::LValue::make_Index({ box$(lval), box$(ofs_val) }); + lval = ::MIR::LValue::new_Index(mv$(lval), ofs_val.as_Local()); } ), (Borrow, @@ -1874,7 +1874,7 @@ namespace { cur_ty = &*e.inner; } DEBUG(i << " " << *cur_ty); - lval = ::MIR::LValue::make_Deref({ box$(lval) }); + lval = ::MIR::LValue::new_Deref(mv$(lval)); ), (Pointer, ERROR(sp, E0000, "Attempting to match over a pointer"); @@ -1978,14 +1978,14 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& DEBUG("ty = " << ity << ", val = " << val); const auto& ty = ity; - TU_MATCHA( (ty.m_data), (te), - (Infer, + TU_MATCH_HDRA( (ty.m_data), {) + TU_ARMA(Infer, _te) { BUG(sp, "Hit _ in type - " << ty); - ), - (Diverge, + } + TU_ARMA(Diverge, _te) { BUG(sp, "Matching over !"); - ), - (Primitive, + } + TU_ARMA(Primitive, te) { switch(te) { case ::HIR::CoreType::Bool: { @@ -2152,17 +2152,20 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& case ::HIR::CoreType::Str: { ASSERT_BUG(sp, rule.is_Value() && rule.as_Value().is_StaticString(), ""); const auto& v = rule.as_Value(); + ASSERT_BUG(sp, val.is_Deref(), ""); + val.m_wrappers.pop_back(); + auto str_val = mv$(val); auto succ_bb = builder.new_bb_unlinked(); auto test_val = ::MIR::Param(::MIR::Constant( v.as_StaticString() )); - auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(*val.as_Deref().val), ::MIR::eBinOp::EQ, mv$(test_val) })); + auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(str_val), ::MIR::eBinOp::EQ, mv$(test_val) })); builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) ); builder.set_cur_block(succ_bb); } break; } - ), - (Path, + } + TU_ARMA(Path, te) { TU_MATCHA( (te.binding), (pbe), (Unbound, BUG(sp, "Encounterd unbound path - " << te.path); @@ -2221,26 +2224,26 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Recurse with the new ruleset MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp, re.sub_rules.data(), re.sub_rules.size(), - var_ty_m, ::MIR::LValue::make_Downcast({ box$(val.clone()), var_idx }), rule.field_path.size()+1, + var_ty_m, ::MIR::LValue::new_Downcast(val.clone(), var_idx), rule.field_path.size()+1, fail_bb ); } ) // TypePathBinding::Enum ) - ), // Type::Data::Path - (Generic, + } // Type::Data::Path + TU_ARMA(Generic, _te) { BUG(sp, "Attempting to match a generic"); - ), - (TraitObject, + } + TU_ARMA(TraitObject, te) { BUG(sp, "Attempting to match a trait object"); - ), - (ErasedType, + } + TU_ARMA(ErasedType, te) { BUG(sp, "Attempting to match an erased type"); - ), - (Array, + } + TU_ARMA(Array, te) { TODO(sp, "Match directly on array?"); - ), - (Slice, + } + TU_ARMA(Slice, te) { ASSERT_BUG(sp, rule.is_Slice() || rule.is_SplitSlice() || (rule.is_Value() && rule.as_Value().is_Bytes()), "Can only match slice with Bytes or Slice rules - " << rule); if( rule.is_Value() ) { ASSERT_BUG(sp, *te.inner == ::HIR::CoreType::U8, "Bytes pattern on non-&[u8]"); @@ -2249,7 +2252,8 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& auto succ_bb = builder.new_bb_unlinked(); - auto inner_val = val.as_Deref().val->clone(); + ASSERT_BUG(sp, val.is_Deref(), "Slice pattern on non-Deref - " << val); + auto inner_val = val.clone_unwrapped(); auto slice_rval = ::MIR::RValue::make_MakeDst({ mv$(cloned_val), mv$(size_val) }); auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), mv$(slice_rval)); @@ -2262,7 +2266,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Compare length auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.len, ::HIR::CoreType::Usize }) ); - auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() })); + auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::EQ, mv$(test_val) })); auto len_succ_bb = builder.new_bb_unlinked(); @@ -2281,7 +2285,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& // Compare length auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.min_len, ::HIR::CoreType::Usize}) ); - auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() })); + auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) })); auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::LT, mv$(test_val) })); auto len_succ_bb = builder.new_bb_unlinked(); @@ -2302,23 +2306,23 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span& else { BUG(sp, "Invalid rule type for slice - " << rule); } - ), - (Tuple, + } // Type::Data::Array + TU_ARMA(Tuple, te) { TODO(sp, "Match directly on tuple?"); - ), - (Borrow, + } + TU_ARMA(Borrow, te) { TODO(sp, "Match directly on borrow?"); - ), // Type::Data::Borrow - (Pointer, + } // Type::Data::Borrow + TU_ARMA(Pointer, te) { BUG(sp, "Attempting to match a pointer - " << rule << " against " << ty); - ), - (Function, + } + TU_ARMA(Function, te) { BUG(sp, "Attempting to match a function pointer - " << rule << " against " << ty); - ), - (Closure, + } + TU_ARMA(Closure, te) { BUG(sp, "Attempting to match a closure"); - ) - ) + } + } } return 0; } @@ -3035,10 +3039,10 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v } m_builder.end_block( ::MIR::Terminator::make_Goto(def_blk) ); } break; - case ::HIR::CoreType::Str: + case ::HIR::CoreType::Str: { // Remove the deref on the &str - auto oval = mv$(val); - auto val = mv$(*oval.as_Deref().val); + ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "&str match on non-Deref lvalue - " << val); + val.m_wrappers.pop_back(); ::std::vector< ::MIR::BasicBlockId> targets; ::std::vector< ::std::string> values; @@ -3062,7 +3066,7 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v m_builder.end_block( ::MIR::Terminator::make_SwitchValue({ mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values)) }) ); - break; + } break; } } @@ -3100,7 +3104,7 @@ void MatchGenGrouped::gen_dispatch__enum(::HIR::TypeRef ty, ::MIR::LValue val, c void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, const ::std::vector& rules, size_t ofs, const ::std::vector<::MIR::BasicBlockId>& arm_targets, ::MIR::BasicBlockId def_blk) { - auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() })); + auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) })); // TODO: Re-sort the rules list to interleve Constant::Bytes and Slice @@ -3162,8 +3166,8 @@ void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, m_builder.set_cur_block(succ_blk); // TODO: What if `val` isn't a Deref? - ASSERT_BUG(sp, val.is_Deref(), "TODO: Handle non-Deref matches of byte strings"); - cmp_lval_eq = this->push_compare( val.as_Deref().val->clone(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) ); + ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "TODO: Handle non-Deref matches of byte strings - " << val); + cmp_lval_eq = this->push_compare( val.clone_unwrapped(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) ); m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_eq), arm_targets[tgt_ofs], def_blk }) ); m_builder.set_cur_block(next_cmp_blk); @@ -3273,7 +3277,7 @@ void MatchGenGrouped::gen_dispatch_splitslice(const field_path_t& field_path, co ASSERT_BUG(sp, ty.m_data.is_Slice(), "SplitSlice pattern on non-slice - " << ty); // Obtain slice length - auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() })); + auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) })); // 1. Check that length is sufficient for the pattern to be used // `IF len < min_len : def_blk, next diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 1453acb3..6f0ef891 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -12,9 +12,12 @@ #include #include // ::std::find -void ::MIR::TypeResolve::fmt_pos(::std::ostream& os) const +void ::MIR::TypeResolve::fmt_pos(::std::ostream& os, bool include_path/*=false*/) const { - os << this->m_path << " BB" << this->bb_idx << "/"; + if( include_path ) { + os << this->m_path << " "; + } + os << "BB" << this->bb_idx << "/"; if( this->stmt_idx == STMT_TERM ) { os << "TERM"; } @@ -27,7 +30,7 @@ void ::MIR::TypeResolve::print_msg(const char* tag, ::std::functionget_lvalue_type(tmp, *e.val); + rv = &get_static_type(tmp, e); + ) + ) + assert(wrapper_skip_count <= val.m_wrappers.size()); + const auto* stop_wrapper = &val.m_wrappers[ val.m_wrappers.size() - wrapper_skip_count ]; + for(const auto& w : val.m_wrappers) + { + if( &w == stop_wrapper ) + break; + rv = &this->get_unwrapped_type(tmp, w, *rv); + } + return *rv; +} +const ::HIR::TypeRef& ::MIR::TypeResolve::get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const +{ + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, field_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Field access on unexpected type - " << ty); @@ -98,14 +115,14 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ), (Tuple, - MIR_ASSERT(*this, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size()); - return te[e.field_index]; + MIR_ASSERT(*this, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size()); + return te[field_index]; ), (Path, if( const auto* tep = te.binding.opt_Struct() ) { const auto& str = **tep; - auto monomorph = [&](const auto& ty)->const auto& { + auto maybe_monomorph = [&](const auto& ty)->const auto& { if( monomorphise_type_needed(ty) ) { tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty); m_resolve.expand_associated_types(sp, tmp); @@ -120,12 +137,12 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c MIR_BUG(*this, "Field on unit-like struct - " << ty); ), (Tuple, - MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in tuple-struct " << te.path); - return monomorph(se[e.field_index].ent); + MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in tuple-struct " << te.path); + return maybe_monomorph(se[field_index].ent); ), (Named, - MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in struct " << te.path); - return monomorph(se[e.field_index].second.ent); + MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in struct " << te.path); + return maybe_monomorph(se[field_index].second.ent); ) ) } @@ -142,8 +159,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return t; } }; - MIR_ASSERT(*this, e.field_index < unm.m_variants.size(), "Field index out of range for union"); - return maybe_monomorph(unm.m_variants.at(e.field_index).second.ent); + MIR_ASSERT(*this, field_index < unm.m_variants.size(), "Field index out of range for union"); + return maybe_monomorph(unm.m_variants.at(field_index).second.ent); } else { @@ -151,9 +168,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c } ) ) - ), - (Deref, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Deref, _e) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Deref on unexpected type - " << ty); @@ -174,9 +190,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ) ) - ), - (Index, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Index, index_local) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Index on unexpected type - " << ty); @@ -188,9 +203,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c return *te.inner; ) ) - ), - (Downcast, - const auto& ty = this->get_lvalue_type(tmp, *e.val); + } + TU_ARMA(Downcast, variant_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( MIR_BUG(*this, "Downcast on unexpected type - " << ty); @@ -202,8 +216,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c const auto& enm = *te.binding.as_Enum(); MIR_ASSERT(*this, enm.m_data.is_Data(), "Downcast on non-data enum - " << ty); const auto& variants = enm.m_data.as_Data(); - MIR_ASSERT(*this, e.variant_index < variants.size(), "Variant index out of range for " << ty); - const auto& variant = variants[e.variant_index]; + MIR_ASSERT(*this, variant_index < variants.size(), "Variant index out of range for " << ty); + const auto& variant = variants[variant_index]; const auto& var_ty = variant.type; if( monomorphise_type_needed(var_ty) ) { @@ -218,12 +232,13 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c else { const auto& unm = *te.binding.as_Union(); - MIR_ASSERT(*this, e.variant_index < unm.m_variants.size(), "Variant index out of range"); - const auto& variant = unm.m_variants[e.variant_index]; + MIR_ASSERT(*this, variant_index < unm.m_variants.size(), "Variant index out of range"); + const auto& variant = unm.m_variants[variant_index]; const auto& var_ty = variant.second.ent; + //return m_resolve.maybe_monomorph(sp, tmp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty); if( monomorphise_type_needed(var_ty) ) { - tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent); + tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty); m_resolve.expand_associated_types(sp, tmp); return tmp; } @@ -233,8 +248,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c } ) ) - ) - ) + } + } throw ""; } const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const @@ -383,6 +398,15 @@ namespace visit { { if( cb(lv, u) ) return true; +#if 1 + for(const auto& w : lv.m_wrappers) + { + if( w.is_Index() ) + { + cb(LValue::new_Local(w.as_Index()), ValUsage::Read); + } + } +#else TU_MATCHA( (lv), (e), (Return, ), @@ -408,6 +432,7 @@ namespace visit { return visit_mir_lvalue(*e.val, u, cb); ) ) +#endif return false; } @@ -625,32 +650,15 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c { auto assigned_lvalue = [&](size_t bb_idx, size_t stmt_idx, const ::MIR::LValue& lv) { // NOTE: Fills the first statement after running, just to ensure that any assigned value has _a_ lifetime - if( const auto* de = lv.opt_Local() ) + if( lv.m_root.is_Local() ) { - if( !mask || mask->at(*de) ) + auto de = lv.m_root.as_Local(); + if( !mask || mask->at(de) ) { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]); - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); + MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[de]); + slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); } } - else - { - // Not a direct assignment of a slot. But check if a slot is mutated as part of this. - ::MIR::visit::visit_mir_lvalue(lv, ValUsage::Write, [&](const auto& ilv, ValUsage vu) { - if( const auto* de = ilv.opt_Local() ) - { - if( vu == ValUsage::Write ) - { - if( !mask || mask->at(*de) ) - { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]); - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); - } - } - } - return false; - }); - } }; const auto& bb = fcn.blocks[bb_idx]; @@ -673,11 +681,12 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c else if( const auto* se = stmt.opt_Drop() ) { // HACK: Mark values as valid wherever there's a drop (prevents confusion by simple validator) - if( const auto* de = se->slot.opt_Local() ) + if( se->slot.m_wrappers.empty() && se->slot.m_root.is_Local() ) { - if( !mask || mask->at(*de) ) + auto de = se->slot.m_root.as_Local(); + if( !mask || mask->at(de) ) { - slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx); + slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx); } } } diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp index 58eee9b9..0296a1c4 100644 --- a/src/mir/helpers.hpp +++ b/src/mir/helpers.hpp @@ -104,7 +104,7 @@ public: } unsigned int get_cur_stmt_ofs() const; - void fmt_pos(::std::ostream& os) const; + void fmt_pos(::std::ostream& os, bool include_path=false) const; void print_bug(::std::function cb) const { print_msg("ERROR", cb); } @@ -116,7 +116,14 @@ public: const ::MIR::BasicBlock& get_block(::MIR::BasicBlockId id) const; const ::HIR::TypeRef& get_static_type(::HIR::TypeRef& tmp, const ::HIR::Path& path) const; - const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const; + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count=0) const; + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::CRef& val) const { + return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count()); + } + const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::MRef& val) const { + return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count()); + } + const ::HIR::TypeRef& get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const; const ::HIR::TypeRef& get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const; ::HIR::TypeRef get_const_type(const ::MIR::Constant& c) const; diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 83f7e1f0..8e3045d6 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -91,119 +91,86 @@ namespace MIR { throw ""; } - ::std::ostream& operator<<(::std::ostream& os, const LValue& x) + void LValue::RefCommon::fmt(::std::ostream& os) const { - TU_MATCHA( (x), (e), + TU_MATCHA( (m_lv->m_root), (e), (Return, os << "retval"; ), (Argument, - os << "a" << e.idx; + os << "a" << e; ), (Local, os << "_" << e; ), (Static, - os << "(" << *e << ")"; - ), - (Field, - os << *e.val << "." << e.field_index; - ), - (Deref, - os << *e.val << "*"; - ), - (Index, - os << *e.val << "[" << *e.idx << "]"; - ), - (Downcast, - os << *e.val << "#" << e.variant_index; + os << "(" << e << ")"; ) ) + for(size_t i = 0; i < m_wrapper_count; i ++) + { + const LValue::Wrapper& w = m_lv->m_wrappers.at(i); + TU_MATCHA( (w), (e), + (Field, + os << "." << e; + ), + (Deref, + os << "*"; + ), + (Index, + os << "[_" << e << "]"; + ), + (Downcast, + os << "#" << e; + ) + ) + } + } + + ::std::ostream& operator<<(::std::ostream& os, const LValue& x) + { + LValue::CRef(x).fmt(os); return os; } - bool operator<(const LValue& a, const LValue& b) + + Ordering LValue::Storage::ord(const LValue::Storage& x) const { - if( a.tag() != b.tag() ) - return a.tag() < b.tag(); - TU_MATCHA( (a, b), (ea, eb), - (Return, - return false; - ), - (Argument, - return ea.idx < eb.idx; - ), - (Local, - return ea < eb; - ), - (Static, - return ea < eb; - ), - (Field, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - if( ea.field_index != eb.field_index ) - return ea.field_index < eb.field_index; - return true; - ), - (Deref, - return *ea.val < *eb.val; - ), - (Index, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - return *ea.idx < *eb.idx; - ), - (Downcast, - if( *ea.val != *eb.val ) - return *ea.val < *eb.val; - return ea.variant_index < eb.variant_index; - ) - ) - throw ""; + if( x.is_Static() ) + { + if( this->is_Static() ) + return this->as_Static().ord( x.as_Static() ); + else + return OrdLess; + } + else + { + if( this->is_Static() ) + return OrdGreater; + } + + return ::ord(this->val, x.val); } - bool operator==(const LValue& a, const LValue& b) + Ordering LValue::ord(const LValue& x) const { - if( a.tag() != b.tag() ) - return false; - TU_MATCHA( (a, b), (ea, eb), - (Return, - return true; - ), - (Argument, - return ea.idx == eb.idx; - ), - (Local, - return ea == eb; - ), - (Static, - return ea == eb; - ), - (Field, - if( *ea.val != *eb.val ) - return false; - if( ea.field_index != eb.field_index ) - return false; - return true; - ), - (Deref, - return *ea.val == *eb.val; - ), - (Index, - if( *ea.val != *eb.val ) - return false; - if( *ea.idx != *eb.idx ) - return false; - return true; - ), - (Downcast, - if( *ea.val != *eb.val ) - return false; - if( ea.variant_index != eb.variant_index ) - return false; - return true; - ) - ) - throw ""; + auto rv = m_root.ord(x.m_root); + if( rv != OrdEqual ) + return rv; + return ::ord(m_wrappers, x.m_wrappers); + } + Ordering LValue::RefCommon::ord(const LValue::RefCommon& x) const + { + Ordering rv; + //TRACE_FUNCTION_FR(FMT_CB(ss, this->fmt(ss); ss << " ? "; x.fmt(ss);), rv); + rv = m_lv->m_root.ord(x.m_lv->m_root); + if( rv != OrdEqual ) + return rv; + for(size_t i = 0; i < ::std::min(m_wrapper_count, x.m_wrapper_count); i ++) + { + rv = m_lv->m_wrappers[i].ord(x.m_lv->m_wrappers[i]); + if( rv != OrdEqual ) + return rv; + } + return (rv = ::ord(m_wrapper_count, x.m_wrapper_count)); } ::std::ostream& operator<<(::std::ostream& os, const Param& x) @@ -537,30 +504,14 @@ namespace MIR { } } -::MIR::LValue MIR::LValue::clone() const +::MIR::LValue::Storage MIR::LValue::Storage::clone() const { - TU_MATCHA( (*this), (e), - (Return, return LValue(e); ), - (Argument, return LValue(e); ), - (Local, return LValue(e); ), - (Static, return LValue(box$(e->clone())); ), - (Field, return LValue::make_Field({ - box$( e.val->clone() ), - e.field_index - }); ), - (Deref, return LValue::make_Deref({ - box$( e.val->clone() ) - }); ), - (Index, return LValue::make_Index({ - box$( e.val->clone() ), - box$( e.idx->clone() ) - }); ), - (Downcast, return LValue::make_Downcast({ - box$( e.val->clone() ), - e.variant_index - }); ) - ) - throw ""; + if( is_Static() ) { + return new_Static(as_Static().clone()); + } + else { + return Storage(this->val); + } } ::MIR::Constant MIR::Constant::clone() const { diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 63acf89d..f3d61dfa 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -12,21 +12,27 @@ #include // std::unique_ptr #include +class MonomorphState; + namespace MIR { typedef unsigned int RegionId; typedef unsigned int BasicBlockId; -#if 0 -// TODO: Store LValues as: +// Store LValues as: // - A packed root value (one word, using the low bits as an enum descriminator) // - A list of (inner to outer) wrappers struct LValue { class Storage { + public: + const static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits + private: + uintptr_t val; - static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits + + Storage(uintptr_t v): val(v) {} public: Storage(const Storage&) = delete; Storage& operator=(const Storage&) = delete; @@ -40,41 +46,89 @@ struct LValue this->~Storage(); this->val = x.val; x.val = 0; + return *this; } ~Storage() { if( is_Static() ) { - delete reinterpret_cast<::HIR::Path*>(val & ~3u); + delete reinterpret_cast<::HIR::Path*>(val & ~3ull); val = 0; } } - static Storage new_Return() { return Storage { MAX_ARG << 2 }; } - static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage { idx << 2 }; ) - static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage { (idx << 2) | 1 } }; + static Storage new_Return() { return Storage(0 << 2); } + static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage((idx+1) << 2); } + static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage((idx << 2) | 1); } static Storage new_Static(::HIR::Path p) { ::HIR::Path* ptr = new ::HIR::Path(::std::move(p)); - return Storage { static_cast(ptr) | 2; } + return Storage(reinterpret_cast(ptr) | 2); + } + + Storage clone() const; + + uintptr_t get_inner() const { + assert(!is_Static()); + return val; + } + static Storage from_inner(uintptr_t v) { + assert( (v & 3) < 2 ); + return Storage(v); + } + + enum Tag { + TAG_Argument, + TAG_Local, + TAG_Static, + TAG_Return, + TAGDEAD, + }; + Tag tag() const { + if(val == 0) + return TAG_Return; + return static_cast(val & 3); } - bool is_Return() const { return val == (MAX_ARG << 2) /*&& (val & 3) == 0*/; } - bool is_Argument() const { return val != (MAX_ARG << 2) && (val & 3) == 0; } + bool is_Return() const { return val == 0; } + bool is_Argument() const { return val != 0 && (val & 3) == 0; } bool is_Local() const { return (val & 3) == 1; } bool is_Static() const { return (val & 3) == 2; } - // No as_Return - unsigned as_Argument() const { assert(is_Argument()); return val >> 2; } - unsigned as_Local() const { assert(is_Local()); return val >> 2; } - const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3u); } + const char as_Return () const { assert(is_Return()); return 0; } + const unsigned as_Argument() const { assert(is_Argument()); return (val >> 2) - 1; } + const unsigned as_Local () const { assert(is_Local()); return val >> 2; } + + const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast(val & ~3llu); } + ::HIR::Path& as_Static() { assert(is_Static()); return *reinterpret_cast< ::HIR::Path*>(val & ~3llu); } + + Ordering ord(const Storage& x) const; + bool operator==(const Storage& x) const { return this->ord(x) == OrdEqual; } + bool operator!=(const Storage& x) const { return this->ord(x) != OrdEqual; } }; class Wrapper { - uintptr_t val; + uint32_t val; + Wrapper(uint32_t v): val(v) {} public: - static Wrapper new_Deref() { return Wrapper { 0 }; } - static Wrapepr new_Field (unsigned idx) { return Wrapper { (idx << 2) | 1 }; } - static Wrapepr new_Downcast(unsigned idx) { return Wrapper { (idx << 2) | 2 }; } - static Wrapepr new_Index (unsigned idx) { return Wrapper { (idx << 2) | 3 }; } + static Wrapper new_Deref() { return Wrapper( 0 ); } + static Wrapper new_Field (unsigned idx) { return Wrapper( (idx << 2) | 1 ); } + static Wrapper new_Downcast(unsigned idx) { return Wrapper( (idx << 2) | 2 ); } + static Wrapper new_Index (unsigned idx) { if(idx == ~0u) idx = Storage::MAX_ARG; return Wrapper( (idx << 2) | 3 ); } + + uint32_t get_inner() const { return val; } + static Wrapper from_inner(uint32_t v) { + return Wrapper(v); + } + + enum Tag { + TAG_Deref, + TAG_Field, + TAG_Downcast, + TAG_Index, + TAGDEAD, + }; + Tag tag() const { + return static_cast(val & 3); + } bool is_Deref () const { return (val & 3) == 0; } // Stores the field index @@ -84,79 +138,269 @@ struct LValue // Stores a Local index bool is_Index () const { return (val & 3) == 3; } - // no as_Deref() - const unsigned as_Field() const { assert(is_Field()); return (val >> 2); } + const char as_Deref () const { assert(is_Deref()); return 0; } + const unsigned as_Field () const { assert(is_Field()); return (val >> 2); } const unsigned as_Downcast() const { assert(is_Downcast()); return (val >> 2); } // TODO: Should this return a LValue? - const unsigned as_Index() const { assert(is_Index()); return (val >> 2); } + const unsigned as_Index () const { assert(is_Index()); unsigned rv = (val >> 2); return rv; } + + void inc_Field () { assert(is_Field ()); *this = Wrapper::new_Field (as_Field () + 1); } + void inc_Downcast() { assert(is_Downcast()); *this = Wrapper::new_Downcast(as_Downcast() + 1); } + + Ordering ord(const Wrapper& x) const { return ::ord(val, x.val); } }; Storage m_root; ::std::vector m_wrappers; - static LValue new_Return() { return LValue { Storage::new_Return(), {} }; } - static LValue new_Argument(unsigned idx) { return LValue { Storage::new_Argument(idx), {} }; } - static LValue new_Local(unsigned idx) { return LValue { Storage::new_Local(idx), {} }; } - static LValue new_Static(::HIR::Path p) { return LValue { Storage::new_Static(::std::move(p)), {} }; } + LValue() + :m_root( Storage::new_Return() ) + { + } + LValue(Storage root, ::std::vector wrappers) + :m_root( ::std::move(root) ) + ,m_wrappers( ::std::move(wrappers) ) + { + } + + static LValue new_Return () { return LValue(Storage::new_Return(), {}); } + static LValue new_Argument(unsigned idx ) { return LValue(Storage::new_Argument(idx), {}); } + static LValue new_Local (unsigned idx ) { return LValue(Storage::new_Local(idx), {}); } + static LValue new_Static (::HIR::Path p) { return LValue(Storage::new_Static(::std::move(p)), {}); } + + static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); return lv; } + static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); return lv; } + static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); return lv; } + static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); return lv; } - static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); } - static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); } - static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); } - static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); } + bool is_Return() const { return m_wrappers.empty() && m_root.is_Return(); } + bool is_Local () const { return m_wrappers.empty() && m_root.is_Local(); } + const unsigned as_Local() const { assert(m_wrappers.empty()); return m_root.as_Local(); } + + bool is_Deref () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Deref(); } + bool is_Field () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Field(); } + bool is_Downcast() const { return m_wrappers.size() > 0 && m_wrappers.back().is_Downcast(); } + const unsigned as_Field() const { assert(!m_wrappers.empty()); return m_wrappers.back().as_Field(); } + + void inc_Field () { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Field (); } + void inc_Downcast() { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Downcast(); } + + Ordering ord(const LValue& x) const; LValue monomorphise(const MonomorphState& ms, unsigned local_offset=0); //LValue monomorphise(const TransParams& ms, unsigned local_offset=0); - LValue clone() const; + LValue clone() const { + return LValue(m_root.clone(), m_wrappers); + } + LValue clone_wrapped(::std::vector wrappers) const { + if( this->m_wrappers.empty() ) { + return LValue(m_root.clone(), ::std::move(wrappers)); + } + else { + return clone_wrapped(wrappers.begin(), wrappers.end()); + } + } + template + LValue clone_wrapped(It begin_it, It end_it) const { + ::std::vector wrappers; + wrappers.reserve(m_wrappers.size() + ::std::distance(begin_it, end_it)); + wrappers.insert(wrappers.end(), m_wrappers.begin(), m_wrappers.end()); + wrappers.insert(wrappers.end(), begin_it, end_it); + return LValue(m_root.clone(), ::std::move(wrappers)); + } + + LValue clone_unwrapped(unsigned count=1) const { + assert(count > 0); + assert(count <= m_wrappers.size()); + return LValue(m_root.clone(), ::std::vector(m_wrappers.begin(), m_wrappers.end() - count)); + } + + /// Helper class that represents a LValue unwrapped to a certain degree + class RefCommon + { + protected: + const LValue* m_lv; + size_t m_wrapper_count; + + RefCommon(const LValue& lv, size_t wrapper_count) + :m_lv(&lv) + ,m_wrapper_count(wrapper_count) + { + assert(wrapper_count <= lv.m_wrappers.size()); + } + + public: + LValue clone() const { + return ::MIR::LValue( m_lv->m_root.clone(), ::std::vector(m_lv->m_wrappers.begin(), m_lv->m_wrappers.begin() + m_wrapper_count) ); + } + + const LValue& lv() const { return *m_lv; } + size_t wrapper_count() const { return m_wrapper_count; } + + /// Unwrap one level, returning false if already at the root + bool try_unwrap() { + if( m_wrapper_count == 0 ) { + return false; + } + else { + m_wrapper_count --; + return true; + } + } + + enum Tag { + TAGDEAD, + TAG_Return, + TAG_Argument, + TAG_Local, + TAG_Static, + TAG_Deref, + TAG_Field, + TAG_Downcast, + TAG_Index, + }; + Tag tag() const { + if( m_wrapper_count == 0 ) + { + switch(m_lv->m_root.tag()) + { + case Storage::TAGDEAD: return TAGDEAD; + case Storage::TAG_Return: return TAG_Return; + case Storage::TAG_Argument: return TAG_Argument; + case Storage::TAG_Local: return TAG_Local; + case Storage::TAG_Static: return TAG_Static; + } + } + else + { + switch(m_lv->m_wrappers[m_wrapper_count-1].tag()) + { + case Wrapper::TAGDEAD: return TAGDEAD; + case Wrapper::TAG_Deref: return TAG_Deref; + case Wrapper::TAG_Field: return TAG_Field; + case Wrapper::TAG_Downcast: return TAG_Downcast; + case Wrapper::TAG_Index: return TAG_Index; + } + } + return TAGDEAD; + } + + bool is_Local () const { return m_wrapper_count == 0 && m_lv->m_root.is_Local (); } + bool is_Return () const { return m_wrapper_count == 0 && m_lv->m_root.is_Return (); } + bool is_Argument() const { return m_wrapper_count == 0 && m_lv->m_root.is_Argument(); } + bool is_Static () const { return m_wrapper_count == 0 && m_lv->m_root.is_Static (); } + bool is_Deref () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Deref (); } + bool is_Field () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Field (); } + bool is_Downcast() const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Downcast(); } + bool is_Index () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Index (); } + + const unsigned as_Local () const { assert(is_Local ()); return m_lv->m_root.as_Local (); } + const char as_Return () const { assert(is_Return ()); return m_lv->m_root.as_Return (); } + const unsigned as_Argument() const { assert(is_Argument()); return m_lv->m_root.as_Argument(); } + const HIR::Path& as_Static () const { assert(is_Static ()); return m_lv->m_root.as_Static (); } + const char as_Deref () const { assert(is_Deref ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Deref (); } + const unsigned as_Field () const { assert(is_Field ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Field (); } + const unsigned as_Downcast() const { assert(is_Downcast()); return m_lv->m_wrappers[m_wrapper_count-1].as_Downcast(); } + const unsigned as_Index () const { assert(is_Index ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Index (); } - class Ref + void fmt(::std::ostream& os) const; + Ordering ord(const RefCommon& b) const; + }; + + class CRef: public RefCommon { - LValue& r; - size_t wrapper_idx; - public:: - LValue clone() const; - void replace(LValue x) const; + public: + CRef(const LValue& lv) + :RefCommon(lv, lv.m_wrappers.size()) + { + } + CRef(const LValue& lv, size_t wc) + :RefCommon(lv, wc) + { + } + + /// Unwrap one level + const CRef inner_ref() const { + assert(m_wrapper_count > 0); + auto rv = *this; + rv.m_wrapper_count--; + return rv; + } + + friend ::std::ostream& operator<<(::std::ostream& os, const CRef& x) { + x.fmt(os); + return os; + } + + bool operator<(const CRef& b) const { + return this->ord(b) == OrdLess; + } + bool operator==(const CRef& b) const { + return this->ord(b) == OrdEqual; + } }; + class MRef: public RefCommon + { + public: + MRef(LValue& lv) + :RefCommon(lv, lv.m_wrappers.size()) + { + } + + operator CRef() const { + return CRef(*m_lv, m_wrapper_count); + } + + MRef inner_ref() { + assert(m_wrapper_count > 0); + auto rv = *this; + rv.m_wrapper_count--; + return rv; + } + void replace(LValue x) { + auto& mut_lv = const_cast(*m_lv); + // Shortcut: No wrappers on source/destination (just assign the slot/root) + if( m_wrapper_count == 0 && x.m_wrappers.empty() ) { + mut_lv.m_root = ::std::move(x.m_root); + return ; + } + // If there's wrappers on this value (assigning over inner portion) + if( m_wrapper_count < m_lv->m_wrappers.size() ) { + // Add those wrappers to the end of the new value + x.m_wrappers.insert(x.m_wrappers.end(), m_lv->m_wrappers.begin() + m_wrapper_count, m_lv->m_wrappers.end()); + } + // Overwrite + mut_lv = ::std::move(x); + } + + friend ::std::ostream& operator<<(::std::ostream& os, const MRef& x) { + x.fmt(os); + return os; + } + }; + + Ordering ord(const LValue::CRef& x) const; + Ordering ord(const LValue::MRef& x) const; }; -#endif - -// "LVALUE" - Assignable values -TAGGED_UNION_EX(LValue, (), Return, ( - // Function return - (Return, struct{}), - // Function argument (input) - (Argument, struct { unsigned int idx; }), - // Variable/Temporary - (Local, unsigned int), - // `static` or `static mut` - (Static, ::std::unique_ptr<::HIR::Path>), - // Field access (tuple, struct, tuple struct, enum field, ...) - // NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring) - (Field, struct { - ::std::unique_ptr val; - unsigned int field_index; - }), - // Dereference a value - (Deref, struct { - ::std::unique_ptr val; - }), - // Index an array or slice (typeof(val) == [T; n] or [T]) - // NOTE: This is not bounds checked! - (Index, struct { - ::std::unique_ptr val; - ::std::unique_ptr idx; - }), - // Interpret an enum as a particular variant - (Downcast, struct { - ::std::unique_ptr val; - unsigned int variant_index; - }) - ), (),(), ( - LValue clone() const; - ) - ); extern ::std::ostream& operator<<(::std::ostream& os, const LValue& x); -extern bool operator<(const LValue& a, const LValue& b); -extern bool operator==(const LValue& a, const LValue& b); +static inline bool operator<(const LValue& a, const LValue::CRef& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator<(const LValue& a, const LValue::MRef& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator<(const LValue::CRef& a, const LValue& b) { + return b.ord(a) == OrdGreater; +} +static inline bool operator<(const LValue::MRef& a, const LValue& b) { + return b.ord(a) == OrdGreater; +} +static inline bool operator<(const LValue& a, const LValue& b) { + return a.ord(b) == OrdLess; +} +static inline bool operator==(const LValue& a, const LValue& b) { + return a.ord(b) == OrdEqual; +} static inline bool operator!=(const LValue& a, const LValue& b) { return !(a == b); } @@ -224,7 +468,7 @@ TAGGED_UNION_EX(Constant, (), Int, ( /// Parameter - A value used when a rvalue just reads (doesn't require a lvalue) /// Can be either a lvalue (memory address), or a constant -TAGGED_UNION_EX(Param, (), LValue, ( +TAGGED_UNION_EX(Param, (), Constant, ( (LValue, LValue), (Constant, Constant) ), (), (), ( @@ -237,7 +481,7 @@ TAGGED_UNION_EX(Param, (), LValue, ( ) ); -TAGGED_UNION_EX(RValue, (), Use, ( +TAGGED_UNION_EX(RValue, (), Tuple, ( (Use, LValue), (Constant, Constant), (SizedArray, struct { @@ -359,7 +603,7 @@ enum class eDropKind { SHALLOW, DEEP, }; -TAGGED_UNION(Statement, Assign, +TAGGED_UNION(Statement, Asm, // Value assigment (Assign, struct { LValue dst; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 8d534314..a064b67d 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -68,7 +68,7 @@ MirBuilder::~MirBuilder() { if( has_result() ) { - push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) ); + push_stmt_assign( sp, ::MIR::LValue::new_Return(), get_result(sp) ); } terminate_scope_early(sp, fcn_scope()); @@ -176,7 +176,7 @@ void MirBuilder::define_variable(unsigned int idx) auto& tmp_scope = top_scope->data.as_Owning(); assert(tmp_scope.is_temporary); tmp_scope.slots.push_back( rv ); - return ::MIR::LValue::make_Local(rv); + return ::MIR::LValue::new_Local(rv); } ::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val) { @@ -258,12 +258,10 @@ void MirBuilder::set_result(const Span& sp, ::MIR::RValue val) m_result_valid = true; } -void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val) +void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination/*=true*/) { DEBUG(dst << " = " << val); ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, dst.tag() != ::MIR::LValue::TAGDEAD, ""); - ASSERT_BUG(sp, val.tag() != ::MIR::RValue::TAGDEAD, ""); auto moved_param = [&](const ::MIR::Param& p) { if(const auto* e = p.opt_LValue()) { @@ -344,13 +342,15 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal ) // Drop target if populated - mark_value_assigned(sp, dst); + if( drop_destination ) + { + mark_value_assigned(sp, dst); + } this->push_stmt( sp, ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) ); } void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/) { ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, ""); if( lvalue_is_copy(sp, val) ) { // Don't emit a drop for Copy values @@ -362,7 +362,6 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/) { ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, ""); // TODO: Ensure that the type is a Box? @@ -400,22 +399,12 @@ void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt) void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) { - VarState* state_p = nullptr; - // TODO: Tracking of complex asignment states (e.g. assignment of a field) - TU_MATCH_DEF(::MIR::LValue, (dst), (e), - ( - ), - (Return, - // Don't drop. - // No state tracking for the return value - ), - (Argument, - state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument); - ), - (Local, - state_p = &get_slot_state_mut(sp, e, SlotType::Local); - ) - ) + if( dst.m_root.is_Return() ) + { + ASSERT_BUG(sp, dst.m_wrappers.empty(), "Assignment to a component of the return value should be impossible."); + return ; + } + VarState* state_p = get_val_state_mut_p(sp, dst);; if( state_p ) { @@ -425,42 +414,28 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) drop_value_from_state(sp, *state_p, dst.clone()); *state_p = VarState::make_Valid({}); } - // TODO: What about assigning into non-tracked locations? Should still cause a drop + else + { + // Assigning into non-tracked locations still causes a drop + drop_value_from_state(sp, VarState::make_Valid({}), dst.clone()); + } } void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/) { TRACE_FUNCTION_F(val); - TU_MATCH_DEF(::MIR::LValue, (val), (e), - ( + for(const auto& w : val.m_wrappers) + { + if( w.is_Index() ) { + // Raise index temporary + raise_temporaries(sp, ::MIR::LValue::new_Local(w.as_Index()), scope, to_above); + } + } + if( !val.m_root.is_Local() ) { // No raising of these source values? return ; - ), - // TODO: This may not be correct, because it can change the drop points and ordering - // HACK: Working around cases where values are dropped while the result is not yet used. - (Index, - raise_temporaries(sp, *e.val, scope, to_above); - raise_temporaries(sp, *e.idx, scope, to_above); - return ; - ), - (Deref, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - (Field, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - (Downcast, - raise_temporaries(sp, *e.val, scope, to_above); - return ; - ), - // Actual value types - (Local, - ) - ) - ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val); - const auto idx = val.as_Local(); + } + const auto idx = val.m_root.as_Local(); bool is_temp = (idx >= m_first_temp_idx); /* if( !is_temp ) { @@ -833,13 +808,12 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle } auto& src_scope_def = m_scopes.at(source.idx); -#if 1 ASSERT_BUG(sp, src_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (source)"); ASSERT_BUG(sp, src_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (source)"); auto& src_list = src_scope_def.data.as_Owning().slots; for(auto idx : src_list) { - DEBUG("> Raising " << ::MIR::LValue::make_Local(idx)); + DEBUG("> Raising " << ::MIR::LValue::new_Local(idx)); assert(idx >= m_first_temp_idx); } @@ -910,13 +884,6 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle // Move all defined variables from one to the other auto& tgt_list = tgt_scope_def.data.as_Owning().slots; tgt_list.insert( tgt_list.end(), src_list.begin(), src_list.end() ); -#else - auto list = src_scope_def.data.as_Temporaries().temporaries; - for(auto idx : list) - { - this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target); - } -#endif // Scope completed m_scope_stack.pop_back(); @@ -979,7 +946,7 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, for(size_t i = 0; i < m_arg_states.size(); i ++) { const auto& state = get_slot_state(sp, i, SlotType::Argument); - this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast(i) })); + this->drop_value_from_state(sp, state, ::MIR::LValue::new_Argument(static_cast(i))); } } } @@ -1060,7 +1027,7 @@ namespace }); if( is_box ) { - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); } else { @@ -1086,13 +1053,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } } return; @@ -1168,7 +1135,7 @@ namespace }); if( is_box ) { - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); } else { BUG(sp, "MovedOut on non-Box"); @@ -1192,19 +1159,19 @@ namespace } auto& ose = old_state.as_Partial(); if( is_enum ) { - auto ilv = ::MIR::LValue::make_Downcast({ box$(lv.clone()), 0 }); + auto ilv = ::MIR::LValue::new_Downcast(lv.clone(), 0); for(size_t i = 0; i < ose.inner_states.size(); i ++) { merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]); - ilv.as_Downcast().variant_index ++; + ilv.inc_Downcast(); } } else { - auto ilv = ::MIR::LValue::make_Field({ box$(lv.clone()), 0 }); + auto ilv = ::MIR::LValue::new_Field(lv.clone(), 0); for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]); - ilv.as_Field().field_index ++; + ilv.inc_Field(); } } } return; @@ -1268,13 +1235,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } return; } @@ -1309,7 +1276,7 @@ namespace builder.push_stmt_set_dropflag_val(sp, ose.outer_flag, is_valid); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state); return ; } case VarState::TAG_Optional: { const auto& nse = new_state.as_Optional(); @@ -1334,7 +1301,7 @@ namespace builder.push_stmt_set_dropflag_other(sp, ose.outer_flag, nse); builder.push_stmt_set_dropflag_default(sp, nse); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state); return; } case VarState::TAG_MovedOut: { const auto& nse = new_state.as_MovedOut(); @@ -1342,7 +1309,7 @@ namespace { TODO(sp, "Handle mismatched flags in MovedOut"); } - merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state); + merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state); return; } case VarState::TAG_Partial: BUG(sp, "MovedOut->Partial not valid"); @@ -1366,13 +1333,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], new_state); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], new_state); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], new_state); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], new_state); } } return ; @@ -1384,13 +1351,13 @@ namespace if( is_enum ) { for(size_t i = 0; i < ose.inner_states.size(); i ++) { - merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast(i) }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast(i)), ose.inner_states[i], nse.inner_states[i]); } } else { for(unsigned int i = 0; i < ose.inner_states.size(); i ++ ) { - merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]); + merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]); } } } return ; @@ -1419,8 +1386,8 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type)); } }; - merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local); - merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument); + merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::new_Local, SlotType::Local); + merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::new_Argument(v); }, SlotType::Argument); } else { @@ -1475,7 +1442,7 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r auto it = states.find(idx); const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1)); - auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx})); + auto lv = (type == SlotType::Local ? ::MIR::LValue::new_Local(idx) : ::MIR::LValue::new_Argument(idx)); merge_state(sp, *this, mv$(lv), out_state, src_state); } }; @@ -1565,7 +1532,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local); if( vs != ent.second ) { - DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second); + DEBUG(::MIR::LValue::new_Local(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } @@ -1574,7 +1541,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument); if( vs != ent.second ) { - DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second); + DEBUG(::MIR::LValue::new_Argument(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } @@ -1612,7 +1579,7 @@ void MirBuilder::complete_scope(ScopeDef& sd) for(auto& ent : e->changed_slots) { auto& vs = this->get_slot_state_mut(sd.span, ent.first, SlotType::Local); - auto lv = ::MIR::LValue::make_Local(ent.first); + auto lv = ::MIR::LValue::new_Local(ent.first); DEBUG(lv << " " << vs << " => " << ent.second); if( vs != ent.second ) { @@ -1630,97 +1597,96 @@ void MirBuilder::complete_scope(ScopeDef& sd) } } -void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb) const +void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb, const ::MIR::LValue::Wrapper* stop_wrapper/*=nullptr*/) const { - TU_MATCH(::MIR::LValue, (val), (e), + ::HIR::TypeRef tmp; + const ::HIR::TypeRef* ty_p = nullptr; + TU_MATCHA( (val.m_root), (e), (Return, TODO(sp, "Return"); ), (Argument, - cb( m_args.at(e.idx).second ); + ty_p = &m_args.at(e).second; ), (Local, - cb( m_output.locals.at(e) ); + ty_p = &m_output.locals.at(e); ), (Static, - TU_MATCHA( (e->m_data), (pe), + TU_MATCHA( (e.m_data), (pe), (Generic, ASSERT_BUG(sp, pe.m_params.m_types.empty(), "Path params on static"); const auto& s = m_resolve.m_crate.get_static_by_path(sp, pe.m_path); - cb( s.m_type ); + ty_p = &s.m_type; ), (UfcsKnown, - TODO(sp, "Static - UfcsKnown - " << *e); + TODO(sp, "Static - UfcsKnown - " << e); ), (UfcsUnknown, - BUG(sp, "Encountered UfcsUnknown in Static - " << *e); + BUG(sp, "Encountered UfcsUnknown in Static - " << e); ), (UfcsInherent, - TODO(sp, "Static - UfcsInherent - " << *e); + TODO(sp, "Static - UfcsInherent - " << e); ) ) - ), - (Field, - with_val_type(sp, *e.val, [&](const auto& ty){ + ) + ) + assert(ty_p); + for(const auto& w : val.m_wrappers) + { + if( &w == stop_wrapper ) + { + stop_wrapper = nullptr; // Reset so the below bugcheck can work + break; + } + const auto& ty = *ty_p; + ty_p = nullptr; + auto maybe_monomorph = [&](const ::HIR::GenericParams& params_def, const ::HIR::Path& p, const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { + if( monomorphise_type_needed(t) ) { + tmp = monomorphise_type(sp, params_def, p.m_data.as_Generic().m_params, t); + m_resolve.expand_associated_types(sp, tmp); + return tmp; + } + else { + return t; + } + }; + TU_MATCH_HDRA( (w), {) + TU_ARMA(Field, field_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Field access on unexpected type - " << ty); ), (Array, - cb( *te.inner ); + ty_p = &*te.inner; ), (Slice, - cb( *te.inner ); + ty_p = &*te.inner; ), (Path, - ::HIR::TypeRef tmp; if( const auto* tep = te.binding.opt_Struct() ) { const auto& str = **tep; - auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { - if( monomorphise_type_needed(t) ) { - tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, t); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return t; - } - }; TU_MATCHA( (str.m_data), (se), (Unit, BUG(sp, "Field on unit-like struct - " << ty); ), (Tuple, - ASSERT_BUG(sp, e.field_index < se.size(), - "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size()); - const auto& fld = se[e.field_index]; - cb( maybe_monomorph(fld.ent) ); + ASSERT_BUG(sp, field_index < se.size(), + "Field index out of range in tuple-struct " << ty << " - " << field_index << " > " << se.size()); + const auto& fld = se[field_index]; + ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent); ), (Named, - ASSERT_BUG(sp, e.field_index < se.size(), - "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size()); - const auto& fld = se[e.field_index].second; - cb( maybe_monomorph(fld.ent) ); + ASSERT_BUG(sp, field_index < se.size(), + "Field index out of range in struct " << ty << " - " << field_index << " > " << se.size()); + const auto& fld = se[field_index].second; + ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent); ) ) } - else if( const auto* tep = te.binding.opt_Union() ) + else if( /*const auto* tep =*/ te.binding.opt_Union() ) { BUG(sp, "Field access on a union isn't valid, use Downcast instead - " << ty); - const auto& unm = **tep; - auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& { - if( monomorphise_type_needed(t) ) { - tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, t); - m_resolve.expand_associated_types(sp, tmp); - return tmp; - } - else { - return t; - } - }; - ASSERT_BUG(sp, e.field_index < unm.m_variants.size(), "Field index out of range for union"); - cb( maybe_monomorph(unm.m_variants.at(e.field_index).second.ent) ); } else { @@ -1728,14 +1694,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: } ), (Tuple, - ASSERT_BUG(sp, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size()); - cb( te[e.field_index] ); + ASSERT_BUG(sp, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size()); + ty_p = &te[field_index]; ) ) - }); - ), - (Deref, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Deref, _e) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Deref on unexpected type - " << ty); @@ -1743,38 +1707,34 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: (Path, if( const auto* inner_ptr = this->is_type_owned_box(ty) ) { - cb( *inner_ptr ); + ty_p = &*inner_ptr; } else { BUG(sp, "Deref on unexpected type - " << ty); } ), (Pointer, - cb(*te.inner); + ty_p = &*te.inner; ), (Borrow, - cb(*te.inner); + ty_p = &*te.inner; ) ) - }); - ), - (Index, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Index, _index_val) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Index on unexpected type - " << ty); ), (Slice, - cb(*te.inner); + ty_p = &*te.inner; ), (Array, - cb(*te.inner); + ty_p = &*te.inner; ) ) - }); - ), - (Downcast, - with_val_type(sp, *e.val, [&](const auto& ty){ + } + TU_ARMA(Downcast, variant_index) { TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), ( BUG(sp, "Downcast on unexpected type - " << ty); @@ -1785,33 +1745,19 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: const auto& enm = **pbe; ASSERT_BUG(sp, enm.m_data.is_Data(), "Downcast on non-data enum"); const auto& variants = enm.m_data.as_Data(); - ASSERT_BUG(sp, e.variant_index < variants.size(), "Variant index out of range"); - const auto& variant = variants[e.variant_index]; + ASSERT_BUG(sp, variant_index < variants.size(), "Variant index out of range"); + const auto& variant = variants[variant_index]; - if( monomorphise_type_needed(variant.type) ) { - auto tmp = monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, variant.type); - m_resolve.expand_associated_types(sp, tmp); - cb(tmp); - } - else { - cb(variant.type); - } + ty_p = &maybe_monomorph(enm.m_params, te.path, variant.type); } else if( const auto* pbe = te.binding.opt_Union() ) { const auto& unm = **pbe; - ASSERT_BUG(sp, e.variant_index < unm.m_variants.size(), "Variant index out of range"); - const auto& variant = unm.m_variants.at(e.variant_index); + ASSERT_BUG(sp, variant_index < unm.m_variants.size(), "Variant index out of range"); + const auto& variant = unm.m_variants.at(variant_index); const auto& fld = variant.second; - if( monomorphise_type_needed(fld.ent) ) { - auto sty = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, fld.ent); - m_resolve.expand_associated_types(sp, sty); - cb(sty); - } - else { - cb(fld.ent); - } + ty_p = &maybe_monomorph(unm.m_params, te.path, fld.ent); } else { @@ -1819,9 +1765,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: } ) ) - }); - ) - ) + } + } + assert(ty_p); + } + ASSERT_BUG(sp, !stop_wrapper, "A stop wrapper was passed, but not found"); + cb(*ty_p); } bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const @@ -1998,165 +1947,177 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT } } -const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count) -{ - TODO(sp, ""); -} -VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) +VarState* MirBuilder::get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv) { TRACE_FUNCTION_F(lv); - TU_MATCHA( (lv), (e), + VarState* vs; + TU_MATCHA( (lv.m_root), (e), (Return, BUG(sp, "Move of return value"); - return get_slot_state_mut(sp, ~0u, SlotType::Local); + vs = &get_slot_state_mut(sp, ~0u, SlotType::Local); ), (Argument, - return get_slot_state_mut(sp, e.idx, SlotType::Argument); + vs = &get_slot_state_mut(sp, e, SlotType::Argument); ), (Local, - return get_slot_state_mut(sp, e, SlotType::Local); + vs = &get_slot_state_mut(sp, e, SlotType::Local); ), (Static, - BUG(sp, "Attempting to mutate state of a static"); - ), - (Field, - auto& ivs = get_val_state_mut(sp, *e.val); - VarState tpl; - TU_MATCHA( (ivs), (ivse), - (Invalid, - //BUG(sp, "Mutating inner state of an invalidated composite - " << lv); - tpl = VarState::make_Valid({}); - ), - (MovedOut, - BUG(sp, "Field on value with MovedOut state - " << lv); - ), - (Partial, - ), - (Optional, - tpl = ivs.clone(); - ), - (Valid, - tpl = VarState::make_Valid({}); - ) + return nullptr; + //BUG(sp, "Attempting to mutate state of a static"); ) - if( !ivs.is_Partial() ) - { - size_t n_flds = 0; - with_val_type(sp, *e.val, [&](const auto& ty) { - DEBUG("ty = " << ty); - if(const auto* e = ty.m_data.opt_Path()) { - ASSERT_BUG(sp, e->binding.is_Struct(), ""); - const auto& str = *e->binding.as_Struct(); - TU_MATCHA( (str.m_data), (se), - (Unit, - BUG(sp, "Field access of unit-like struct"); - ), - (Tuple, - n_flds = se.size(); - ), - (Named, - n_flds = se.size(); - ) - ) - } - else if(const auto* e = ty.m_data.opt_Tuple()) { - n_flds = e->size(); - } - else if(const auto* e = ty.m_data.opt_Array()) { - n_flds = e->size_val; - } - else { - TODO(sp, "Determine field count for " << ty); - } - }); - ::std::vector inner_vs; inner_vs.reserve(n_flds); - for(size_t i = 0; i < n_flds; i++) - inner_vs.push_back( tpl.clone() ); - ivs = VarState::make_Partial({ mv$(inner_vs) }); - } - return ivs.as_Partial().inner_states.at(e.field_index); - ), - (Deref, - // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop - bool is_box = false; - if( this->m_lang_Box ) - { - with_val_type(sp, *e.val, [&](const auto& ty){ - DEBUG("ty = " << ty); - is_box = this->is_type_owned_box(ty); - }); - } - + ) - if( is_box ) - { - auto& ivs = get_val_state_mut(sp, *e.val); - if( ! ivs.is_MovedOut() ) + for(const auto& w : lv.m_wrappers) + { + auto& ivs = *vs; + vs = nullptr; + TU_MATCH_HDRA( (w), { ) + TU_ARMA(Field, field_index) { + VarState tpl; + TU_MATCHA( (ivs), (ivse), + (Invalid, + //BUG(sp, "Mutating inner state of an invalidated composite - " << lv); + tpl = VarState::make_Valid({}); + ), + (MovedOut, + BUG(sp, "Field on value with MovedOut state - " << lv); + ), + (Partial, + ), + (Optional, + tpl = ivs.clone(); + ), + (Valid, + tpl = VarState::make_Valid({}); + ) + ) + if( !ivs.is_Partial() ) { - ::std::vector inner; - inner.push_back(VarState::make_Valid({})); - unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u); - ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag }); + size_t n_flds = 0; + with_val_type(sp, lv, [&](const auto& ty) { + DEBUG("ty = " << ty); + if(const auto* e = ty.m_data.opt_Path()) { + ASSERT_BUG(sp, e->binding.is_Struct(), ""); + const auto& str = *e->binding.as_Struct(); + TU_MATCHA( (str.m_data), (se), + (Unit, + BUG(sp, "Field access of unit-like struct"); + ), + (Tuple, + n_flds = se.size(); + ), + (Named, + n_flds = se.size(); + ) + ) + } + else if(const auto* e = ty.m_data.opt_Tuple()) { + n_flds = e->size(); + } + else if(const auto* e = ty.m_data.opt_Array()) { + n_flds = e->size_val; + } + else { + TODO(sp, "Determine field count for " << ty); + } + }, &w); + ::std::vector inner_vs; inner_vs.reserve(n_flds); + for(size_t i = 0; i < n_flds; i++) + inner_vs.push_back( tpl.clone() ); + ivs = VarState::make_Partial({ mv$(inner_vs) }); + } + vs = &ivs.as_Partial().inner_states.at(field_index); + } + TU_ARMA(Deref, _e) { + // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop + bool is_box = false; + if( this->m_lang_Box ) + { + with_val_type(sp, lv, [&](const auto& ty){ + DEBUG("ty = " << ty); + is_box = this->is_type_owned_box(ty); + }, &w); } - return *ivs.as_MovedOut().inner_state; - } - else - { - BUG(sp, "Move out of deref with non-Copy values - &move? - " << lv << " : " << FMT_CB(ss, this->with_val_type(sp, lv, [&](const auto& ty){ss<