diff options
author | John Hodge <tpg@ucc.asn.au> | 2017-06-16 10:35:30 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2017-06-16 10:35:30 +0800 |
commit | bbb7023bee036f87b45ba0555e60ce33837460b0 (patch) | |
tree | a1e1210bee4a1da459a3be90fb67dc586e400bb5 /src | |
parent | 94015a6835ae0d050a83dee1622e1d1b6851f556 (diff) | |
download | mrust-bbb7023bee036f87b45ba0555e60ce33837460b0.tar.gz |
MIR - Unify temporaries and variables
Diffstat (limited to 'src')
-rw-r--r-- | src/hir/deserialise.cpp | 12 | ||||
-rw-r--r-- | src/hir/serialise.cpp | 18 | ||||
-rw-r--r-- | src/hir_conv/bind.cpp | 10 | ||||
-rw-r--r-- | src/hir_conv/constant_evaluation.cpp | 25 | ||||
-rw-r--r-- | src/hir_expand/const_eval_full.cpp | 32 | ||||
-rw-r--r-- | src/mir/check.cpp | 81 | ||||
-rw-r--r-- | src/mir/check_full.cpp | 130 | ||||
-rw-r--r-- | src/mir/cleanup.cpp | 12 | ||||
-rw-r--r-- | src/mir/dump.cpp | 27 | ||||
-rw-r--r-- | src/mir/from_hir.cpp | 26 | ||||
-rw-r--r-- | src/mir/from_hir.hpp | 41 | ||||
-rw-r--r-- | src/mir/from_hir_match.cpp | 2 | ||||
-rw-r--r-- | src/mir/helpers.cpp | 65 | ||||
-rw-r--r-- | src/mir/helpers.hpp | 10 | ||||
-rw-r--r-- | src/mir/mir.cpp | 50 | ||||
-rw-r--r-- | src/mir/mir.hpp | 28 | ||||
-rw-r--r-- | src/mir/mir_builder.cpp | 543 | ||||
-rw-r--r-- | src/mir/optimise.cpp | 272 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 33 | ||||
-rw-r--r-- | src/trans/enumerate.cpp | 29 | ||||
-rw-r--r-- | src/trans/monomorphise.cpp | 19 |
21 files changed, 521 insertions, 944 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index f4dfdf19..3cb58a2e 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -338,11 +338,10 @@ namespace { switch(auto tag = m_in.read_tag()) { #define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ ); - _(Variable, static_cast<unsigned int>(m_in.read_count()) ) - _(Temporary, { static_cast<unsigned int>(m_in.read_count()) } ) - _(Argument, { static_cast<unsigned int>(m_in.read_count()) } ) - _(Static, deserialise_path() ) _(Return, {}) + _(Argument, { static_cast<unsigned int>(m_in.read_count()) } ) + _(Local, static_cast<unsigned int>(m_in.read_count()) ) + _(Static, deserialise_path() ) _(Field, { box$( deserialise_mir_lvalue() ), static_cast<unsigned int>(m_in.read_count()) @@ -962,8 +961,8 @@ namespace { ::MIR::Function rv; - rv.named_variables = deserialise_vec< ::HIR::TypeRef>( ); - rv.temporaries = deserialise_vec< ::HIR::TypeRef>( ); + rv.locals = deserialise_vec< ::HIR::TypeRef>( ); + //rv.local_names = deserialise_vec< ::std::string>( ); rv.drop_flags = deserialise_vec<bool>(); rv.blocks = deserialise_vec< ::MIR::BasicBlock>( ); @@ -1012,7 +1011,6 @@ namespace { } case 4: return ::MIR::Statement::make_ScopeEnd({ - deserialise_vec<unsigned int>(), deserialise_vec<unsigned int>() }); default: diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index 77e17dba..cddbf0b8 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -457,8 +457,8 @@ namespace { void serialise(const ::MIR::Function& mir) { // Write out MIR. - serialise_vec( mir.named_variables ); - serialise_vec( mir.temporaries ); + serialise_vec( mir.locals ); + //serialise_vec( mir.slot_names ); serialise_vec( mir.drop_flags ); serialise_vec( mir.blocks ); } @@ -498,8 +498,7 @@ namespace { ), (ScopeEnd, m_out.write_tag(4); - serialise_vec(e.vars); - serialise_vec(e.tmps); + serialise_vec(e.slots); ) ) } @@ -571,20 +570,17 @@ namespace { TRACE_FUNCTION_F("LValue = "<<lv); m_out.write_tag( static_cast<int>(lv.tag()) ); TU_MATCHA( (lv), (e), - (Variable, - m_out.write_count(e); - ), - (Temporary, - m_out.write_count(e.idx); + (Return, ), (Argument, m_out.write_count(e.idx); ), + (Local, + m_out.write_count(e); + ), (Static, serialise_path(e); ), - (Return, - ), (Field, serialise(e.val); m_out.write_count(e.field_index); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index cf443eb6..1b0f61b6 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -480,14 +480,12 @@ namespace { static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv) { TU_MATCHA( (lv), (e), - (Variable, + (Return, ), - (Temporary, + (Local, ), (Argument, ), - (Return, - ), (Static, upper_visitor.visit_path(e, ::HIR::Visitor::PathContext::VALUE); ), @@ -529,9 +527,7 @@ namespace { ) } }; - for(auto& ty : expr.m_mir->named_variables) - this->visit_type(ty); - for(auto& ty : expr.m_mir->temporaries) + for(auto& ty : expr.m_mir->locals) this->visit_type(ty); for(auto& block : expr.m_mir->blocks) { diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index a950a3dd..e8138169 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -1026,32 +1026,25 @@ namespace { ::MIR::TypeResolve state { sp, resolve, FMT_CB(,), exp, {}, fcn }; ::HIR::Literal retval; - ::std::vector< ::HIR::Literal> locals; - ::std::vector< ::HIR::Literal> temps; - locals.resize( fcn.named_variables.size() ); - temps.resize( fcn.temporaries.size() ); + ::std::vector< ::HIR::Literal> locals( fcn.locals.size() ); auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { TU_MATCHA( (lv), (e), - (Variable, - if( e >= locals.size() ) - BUG(sp, "Local index out of range - " << e << " >= " << locals.size()); - return locals[e]; - ), - (Temporary, - if( e.idx >= temps.size() ) - BUG(sp, "Temp index out of range - " << e.idx << " >= " << temps.size()); - return temps[e.idx]; + (Return, + return retval; ), (Argument, + ASSERT_BUG(sp, e.idx < args.size(), "Argument index out of range - " << e.idx << " >= " << args.size()); return args[e.idx]; ), + (Local, + if( e >= locals.size() ) + BUG(sp, "Local index out of range - " << e << " >= " << locals.size()); + return locals[e]; + ), (Static, TODO(sp, "LValue::Static"); ), - (Return, - return retval; - ), (Field, TODO(sp, "LValue::Field"); ), diff --git a/src/hir_expand/const_eval_full.cpp b/src/hir_expand/const_eval_full.cpp index 538693f4..04575a6e 100644 --- a/src/hir_expand/const_eval_full.cpp +++ b/src/hir_expand/const_eval_full.cpp @@ -292,49 +292,41 @@ namespace { ::MIR::TypeResolve state { sp, resolve, name, ::HIR::TypeRef(), {}, fcn }; ::HIR::Literal retval; - ::std::vector< ::HIR::Literal> locals; - ::std::vector< ::HIR::Literal> temps; - locals.resize( fcn.named_variables.size() ); - temps.resize( fcn.temporaries.size() ); + ::std::vector< ::HIR::Literal> locals( fcn.locals.size() ); struct LocalState { typedef ::std::vector< ::HIR::Literal> t_vec_lit; ::MIR::TypeResolve& state; ::HIR::Literal& retval; - ::std::vector< ::HIR::Literal>& locals; - ::std::vector< ::HIR::Literal>& temps; ::std::vector< ::HIR::Literal>& args; + ::std::vector< ::HIR::Literal>& locals; - LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& locals, t_vec_lit& temps, t_vec_lit& args): + LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& args, t_vec_lit& locals): state(state), retval(retval), - locals(locals), - temps(temps), - args(args) + args(args), + locals(locals) {} ::HIR::Literal& get_lval(const ::MIR::LValue& lv) { TU_MATCHA( (lv), (e), - (Variable, + (Return, + return retval; + ), + (Local, if( e >= locals.size() ) MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size()); return locals[e]; ), - (Temporary, - if( e.idx >= temps.size() ) - MIR_BUG(state, "Temp index out of range - " << e.idx << " >= " << temps.size()); - return temps[e.idx]; - ), (Argument, + if( e.idx >= args.size() ) + MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size()); return args[e.idx]; ), (Static, MIR_TODO(state, "LValue::Static - " << e); ), - (Return, - return retval; - ), (Field, auto& val = get_lval(*e.val); MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv); @@ -362,7 +354,7 @@ namespace { throw ""; } }; - LocalState local_state( state, retval, locals, temps, args ); + LocalState local_state( state, retval, args, locals ); auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { return local_state.get_lval(lv); }; auto read_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal { diff --git a/src/mir/check.cpp b/src/mir/check.cpp index f669623a..58bcaf55 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -105,15 +105,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn Valid, }; State ret_state = State::Invalid; - ::std::vector<State> arguments; - ::std::vector<State> temporaries; - ::std::vector<State> variables; + ::std::vector<State> args; + ::std::vector<State> locals; ValStates() {} - ValStates(size_t n_args, size_t n_temps, size_t n_vars): - arguments(n_args, State::Valid), - temporaries(n_temps), - variables(n_vars) + ValStates(size_t n_args, size_t n_locals): + args(n_args, State::Valid), + locals(n_locals) { } @@ -144,22 +142,20 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn } } }; - fmt_val_range("arg", this->arguments); - fmt_val_range("tmp", this->temporaries); - fmt_val_range("var", this->variables); + fmt_val_range("arg", this->args); + fmt_val_range("_", this->locals); os << "}"; } bool operator==(const ValStates& x) const { - if( ret_state != x.ret_state ) return false; - if( arguments != x.arguments ) return false; - if( temporaries != x.temporaries ) return false; - if( variables != x.variables ) return false; + if( ret_state != x.ret_state ) return false; + if( args != x.args ) return false; + if( locals != x.locals ) return false; return true; } bool empty() const { - return arguments.empty() && temporaries.empty() && variables.empty(); + return locals.empty() && args.empty(); } bool merge(unsigned bb_idx, ValStates& other) @@ -178,9 +174,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn { bool rv = false; rv |= ValStates::merge_state(this->ret_state, other.ret_state); - rv |= ValStates::merge_lists(this->arguments , other.arguments); - rv |= ValStates::merge_lists(this->temporaries, other.temporaries); - rv |= ValStates::merge_lists(this->variables , other.variables); + rv |= ValStates::merge_lists(this->args , other.args ); + rv |= ValStates::merge_lists(this->locals, other.locals); return rv; } } @@ -194,42 +189,32 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn ret_state = is_valid ? State::Valid : State::Invalid; ), (Argument, - MIR_ASSERT(state, e.idx < this->arguments.size(), ""); - DEBUG("arg" << e.idx << " = " << (is_valid ? "Valid" : "Invalid")); - this->arguments[e.idx] = is_valid ? State::Valid : State::Invalid; + 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; ), - (Variable, - MIR_ASSERT(state, e < this->variables.size(), ""); - DEBUG("var" << e << " = " << (is_valid ? "Valid" : "Invalid")); - this->variables[e] = is_valid ? State::Valid : State::Invalid; - ), - (Temporary, - MIR_ASSERT(state, e.idx < this->temporaries.size(), ""); - DEBUG("tmp" << e.idx << " = " << (is_valid ? "Valid" : "Invalid")); - this->temporaries[e.idx] = is_valid ? State::Valid : State::Invalid; + (Local, + MIR_ASSERT(state, e < this->locals.size(), "Local index out of range"); + DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid")); + this->locals[e] = is_valid ? State::Valid : State::Invalid; ) ) } void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv) { TU_MATCH( ::MIR::LValue, (lv), (e), - (Variable, - MIR_ASSERT(state, e < this->variables.size(), ""); - if( this->variables[e] != State::Valid ) - MIR_BUG(state, "Use of non-valid variable - " << lv); - ), - (Temporary, - MIR_ASSERT(state, e.idx < this->temporaries.size(), ""); - if( this->temporaries[e.idx] != State::Valid ) - MIR_BUG(state, "Use of non-valid temporary - " << lv); + (Return, + if( this->ret_state != State::Valid ) + MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Argument, - MIR_ASSERT(state, e.idx < this->arguments.size(), ""); - if( this->arguments[e.idx] != State::Valid ) - MIR_BUG(state, "Use of non-valid argument - " << lv); + MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range"); + if( this->args[e.idx] != State::Valid ) + MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), - (Return, - if( this->ret_state != State::Valid ) + (Local, + MIR_ASSERT(state, e < this->locals.size(), "Local index out of range"); + if( this->locals[e] != State::Valid ) MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Static, @@ -309,7 +294,7 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn src_path.push_back(idx); to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } ); }; - add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.temporaries.size(), fcn.named_variables.size() } ); + add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } ); while( to_visit_blocks.size() > 0 ) { auto block = to_visit_blocks.back().bb; @@ -430,12 +415,12 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn // Check if the return value has been set val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) ); // Ensure that no other non-Copy values are valid - for(unsigned int i = 0; i < val_state.variables.size(); i ++) + for(unsigned int i = 0; i < val_state.locals.size(); i ++) { - if( val_state.variables[i] == ValStates::State::Invalid ) + if( val_state.locals[i] == ValStates::State::Invalid ) { } - else if( state.m_resolve.type_is_copy(state.sp, fcn.named_variables[i]) ) + else if( state.m_resolve.type_is_copy(state.sp, fcn.locals[i]) ) { } else diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index f49598da..a153aca7 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -67,10 +67,9 @@ namespace { struct ValueStates { - ::std::vector<State> vars; - ::std::vector<State> temporaries; - ::std::vector<State> arguments; State return_value; + ::std::vector<State> args; + ::std::vector<State> locals; ::std::vector<bool> drop_flags; ::std::vector< ::std::vector<State> > inner_states; @@ -89,10 +88,9 @@ namespace } }; ValueStates rv; - rv.vars = H::clone_state_list(this->vars); - rv.temporaries = H::clone_state_list(this->temporaries); - rv.arguments = H::clone_state_list(this->arguments); rv.return_value = State(this->return_value); + rv.args = H::clone_state_list(this->args); + rv.locals = H::clone_state_list(this->locals); rv.drop_flags = this->drop_flags; rv.inner_states.reserve( this->inner_states.size() ); for(const auto& isl : this->inner_states) @@ -139,22 +137,18 @@ namespace return false; if( ! H::equal(*this, return_value, x, x.return_value) ) return false; - assert(vars.size() == x.vars.size()); - for(size_t i = 0; i < vars.size(); i ++) - { - if( ! H::equal(*this, vars[i], x, x.vars[i]) ) - return false; - } - assert(temporaries.size() == x.temporaries.size()); - for(size_t i = 0; i < temporaries.size(); i ++) + + assert(args.size() == x.args.size()); + for(size_t i = 0; i < args.size(); i ++) { - if( ! H::equal(*this, temporaries[i], x, x.temporaries[i]) ) + if( ! H::equal(*this, args[i], x, x.args[i]) ) return false; } - assert(arguments.size() == x.arguments.size()); - for(size_t i = 0; i < arguments.size(); i ++) + + assert(locals.size() == x.locals.size()); + for(size_t i = 0; i < locals.size(); i ++) { - if( ! H::equal(*this, arguments[i], x, x.arguments[i]) ) + if( ! H::equal(*this, locals[i], x, x.locals[i]) ) return false; } return true; @@ -397,13 +391,11 @@ namespace Marker m; m.used.resize(this->inner_states.size(), false); - for(const auto& s : this->vars) - m.mark_from_state(*this, s); - for(const auto& s : this->temporaries) + m.mark_from_state(*this, this->return_value); + for(const auto& s : this->args) m.mark_from_state(*this, s); - for(const auto& s : this->arguments) + for(const auto& s : this->locals) m.mark_from_state(*this, s); - m.mark_from_state(*this, this->return_value); } private: ::std::vector<State>& allocate_composite_int(State& out_state) @@ -455,22 +447,19 @@ namespace const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const { TU_MATCHA( (lv), (e), - (Variable, - return vars.at(e); - ), - (Temporary, - return temporaries.at(e.idx); + (Return, + return return_value; ), (Argument, - return arguments.at(e.idx); + return args.at(e.idx); + ), + (Local, + return locals.at(e); ), (Static, static State state_of_static(true); return state_of_static; ), - (Return, - return return_value; - ), (Field, const auto& vs = get_lvalue_state(mir_res, *e.val); if( vs.is_composite() ) @@ -520,7 +509,7 @@ namespace ) throw ""; } - + void clear_state(const ::MIR::TypeResolve& mir_res, State& s) { if(s.is_composite()) { auto& sub_states = this->get_composite(mir_res, s); @@ -529,33 +518,28 @@ namespace sub_states.clear(); } } - + 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), - (Variable, - auto& slot = vars.at(e); - this->clear_state(mir_res, slot); - slot = mv$(new_vs); + (Return, + this->clear_state(mir_res, return_value); + return_value = mv$(new_vs); ), - (Temporary, - auto& slot = temporaries.at(e.idx); + (Argument, + auto& slot = args.at(e.idx); this->clear_state(mir_res, slot); slot = mv$(new_vs); ), - (Argument, - auto& slot = arguments.at(e.idx); + (Local, + auto& slot = locals.at(e); this->clear_state(mir_res, slot); slot = mv$(new_vs); ), (Static, // Ignore. ), - (Return, - this->clear_state(mir_res, return_value); - return_value = mv$(new_vs); - ), (Field, const auto& cur_vs = get_lvalue_state(mir_res, *e.val); if( !cur_vs.is_composite() && cur_vs == new_vs ) @@ -736,12 +720,10 @@ namespace std { os << "ValueStates(path=[" << x.bb_path << "]"; print_val(",rv", x.return_value); - for(unsigned int i = 0; i < x.arguments.size(); i ++) - print_val(FMT_CB(ss, ss << ",a" << i;), x.arguments[i]); - for(unsigned int i = 0; i < x.vars.size(); i ++) - print_val(FMT_CB(ss, ss << ",_" << i;), x.vars[i]); - for(unsigned int i = 0; i < x.temporaries.size(); i ++) - print_val(FMT_CB(ss, ss << ",t" << i;), x.temporaries[i]); + for(unsigned int i = 0; i < x.args.size(); i ++) + print_val(FMT_CB(ss, ss << ",a" << i;), x.args[i]); + for(unsigned int i = 0; i < x.locals.size(); i ++) + print_val(FMT_CB(ss, ss << ",_" << i;), x.locals[i]); for(unsigned int i = 0; i < x.drop_flags.size(); i++) if(x.drop_flags[i]) os << ",df" << i; @@ -774,9 +756,8 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio return rv; } }; - state.arguments = H::make_list(mir_res.m_args.size(), true); - state.vars = H::make_list(fcn.named_variables.size(), false); - state.temporaries = H::make_list(fcn.temporaries.size(), false); + state.args = H::make_list(mir_res.m_args.size(), true); + state.locals = H::make_list(fcn.locals.size(), false); state.drop_flags = fcn.drop_flags; ::std::vector< ::std::pair<unsigned int, ValueStates> > todo_queue; @@ -789,46 +770,25 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio // Mask off any values which aren't valid in the first statement of this block { - for(unsigned i = 0; i < state.vars.size(); i ++) - { - /*if( !variables_copy[i] ) - { - // Not Copy, don't apply masking - } - else*/ if( ! state.vars[i].is_valid() ) - { - // Already invalid - } - else if( lifetimes.var_valid(i, cur_block, 0) ) - { - // Expected to be valid in this block, leave as-is - } - else - { - // Copy value not used at/after this block, mask to false - DEBUG("BB" << cur_block << " - var$" << i << " - Outside lifetime, discard"); - state.vars[i] = State(false); - } - } - for(unsigned i = 0; i < state.temporaries.size(); i ++) + for(unsigned i = 0; i < state.locals.size(); i ++) { /*if( !variables_copy[i] ) { // Not Copy, don't apply masking } - else*/ if( ! state.temporaries[i].is_valid() ) + else*/ if( ! state.locals[i].is_valid() ) { // Already invalid } - else if( lifetimes.tmp_valid(i, cur_block, 0) ) + else if( lifetimes.slot_valid(i, cur_block, 0) ) { // Expected to be valid in this block, leave as-is } else { // Copy value not used at/after this block, mask to false - DEBUG("BB" << cur_block << " - tmp$" << i << " - Outside lifetime, discard"); - state.temporaries[i] = State(false); + DEBUG("BB" << cur_block << " - _" << i << " - Outside lifetime, discard"); + state.locals[i] = State(false); } } } @@ -1007,11 +967,11 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio } } }; - for(unsigned i = 0; i < state.arguments.size(); i ++ ) { - ensure_dropped(state.arguments[i], ::MIR::LValue::make_Argument({i})); + for(unsigned i = 0; i < state.locals.size(); i ++ ) { + ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i)); } - for(unsigned i = 0; i < state.vars.size(); i ++ ) { - ensure_dropped(state.vars[i], ::MIR::LValue::make_Variable(i)); + for(unsigned i = 0; i < state.args.size(); i ++ ) { + ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i})); } } ), diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 17dca948..3dda81dc 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -32,8 +32,8 @@ struct MirMutator ::MIR::LValue new_temporary(::HIR::TypeRef ty) { - auto rv = ::MIR::LValue::make_Temporary({ static_cast<unsigned int>(m_fcn.temporaries.size()) }); - m_fcn.temporaries.push_back( mv$(ty) ); + auto rv = ::MIR::LValue::make_Local( static_cast<unsigned int>(m_fcn.locals.size()) ); + m_fcn.locals.push_back( mv$(ty) ); return rv; } @@ -831,15 +831,13 @@ 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), - (Variable, - ), - (Temporary, + (Return, ), (Argument, ), - (Static, + (Local, ), - (Return, + (Static, ), (Field, MIR_Cleanup_LValue(state, mutator, *le.val); diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index b4177295..4e53cf5b 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -25,13 +25,9 @@ namespace { void dump_mir(const ::MIR::Function& fcn) { - for(unsigned int i = 0; i < fcn.named_variables.size(); i ++) + for(size_t i = 0; i < fcn.locals.size(); i ++) { - m_os << indent() << "let _#" << i << ": " << fcn.named_variables[i] << ";\n"; - } - for(unsigned int i = 0; i < fcn.temporaries.size(); i ++) - { - m_os << indent() << "let tmp$" << i << ": " << fcn.temporaries[i] << ";\n"; + m_os << indent() << "let _$" << i << ": " << fcn.locals[i] << ";\n"; } for(unsigned int i = 0; i < fcn.drop_flags.size(); i ++) { @@ -102,10 +98,8 @@ namespace { ), (ScopeEnd, m_os << "// Scope End: "; - for(auto idx : e.vars) - m_os << "var$" << idx << ","; - for(auto idx : e.tmps) - m_os << "tmp$" << idx << ","; + for(auto idx : e.slots) + m_os << "_$" << idx << ","; m_os << "\n"; ) ) @@ -165,21 +159,18 @@ namespace { } void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) { TU_MATCHA( (lval), (e), - (Variable, - os << "_#" << e; - ), - (Temporary, - os << "tmp$" << e.idx; + (Return, + os << "RETURN"; ), (Argument, os << "arg$" << e.idx; ), + (Local, + os << "_$" << e; + ), (Static, os << e; ), - (Return, - os << "RETURN"; - ), (Field, os << "("; fmt_val(os, *e.val); diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index d9796aed..149d53ea 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -175,16 +175,16 @@ namespace { switch( pat.m_binding.m_type ) { case ::HIR::PatternBinding::Type::Move: - m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), mv$(lval) ); + m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), mv$(lval) ); break; case ::HIR::PatternBinding::Type::Ref: if(m_borrow_raise_target) { DEBUG("- Raising destructure borrow of " << lval << " to scope " << *m_borrow_raise_target); - m_builder.raise_variables(sp, lval, *m_borrow_raise_target); + m_builder.raise_temporaries(sp, lval, *m_borrow_raise_target); } - m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({ + m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(lval) }) ); break; @@ -192,9 +192,9 @@ namespace { if(m_borrow_raise_target) { DEBUG("- Raising destructure borrow of " << lval << " to scope " << *m_borrow_raise_target); - m_builder.raise_variables(sp, lval, *m_borrow_raise_target); + m_builder.raise_temporaries(sp, lval, *m_borrow_raise_target); } - m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({ + m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Unique, mv$(lval) }) ); break; @@ -390,7 +390,7 @@ namespace { ); // Construct fat pointer - m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) ); + 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) }) ); } if( e.trailing.size() > 0 ) { @@ -536,7 +536,7 @@ namespace { if( node.m_pattern.m_binding.is_valid() && node.m_pattern.m_data.is_Any() && node.m_pattern.m_binding.m_type == ::HIR::PatternBinding::Type::Move ) { - m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Variable(node.m_pattern.m_binding.m_slot), mv$(res) ); + m_builder.push_stmt_assign( node.span(), m_builder.get_variable(node.span(), node.m_pattern.m_binding.m_slot), mv$(res) ); } else { @@ -663,7 +663,7 @@ namespace { if( m_builder.block_active() ) { auto res = m_builder.get_result(arm.m_code->span()); - m_builder.raise_variables( arm.m_code->span(), res, scope, /*to_above=*/true); + m_builder.raise_temporaries( arm.m_code->span(), res, scope, /*to_above=*/true); m_builder.set_result(arm.m_code->span(), mv$(res)); m_builder.terminate_scope( node.span(), mv$(tmp_scope) ); @@ -1157,7 +1157,7 @@ namespace { if( m_borrow_raise_target ) { DEBUG("- Raising borrow to scope " << *m_borrow_raise_target); - m_builder.raise_variables(node.span(), val, *m_borrow_raise_target); + m_builder.raise_temporaries(node.span(), val, *m_borrow_raise_target); } m_builder.set_result( node.span(), ::MIR::RValue::make_Borrow({ 0, node.m_type, mv$(val) }) ); @@ -1438,7 +1438,7 @@ namespace { if( m_borrow_raise_target && m_in_borrow ) { DEBUG("- Raising deref in borrow to scope " << *m_borrow_raise_target); - m_builder.raise_variables(node.span(), val, *m_borrow_raise_target); + m_builder.raise_temporaries(node.span(), val, *m_borrow_raise_target); } @@ -2057,7 +2057,7 @@ namespace { void visit(::HIR::ExprNode_Variable& node) override { TRACE_FUNCTION_F("_Variable - " << node.m_name << " #" << node.m_slot); - m_builder.set_result( node.span(), ::MIR::LValue::make_Variable(node.m_slot) ); + m_builder.set_result( node.span(), m_builder.get_variable(node.span(), node.m_slot) ); } void visit(::HIR::ExprNode_StructLiteral& node) override @@ -2239,9 +2239,9 @@ namespace { TRACE_FUNCTION; ::MIR::Function fcn; - fcn.named_variables.reserve(ptr.m_bindings.size()); + fcn.locals.reserve(ptr.m_bindings.size()); for(const auto& t : ptr.m_bindings) - fcn.named_variables.push_back( t.clone() ); + fcn.locals.push_back( t.clone() ); // Scope ensures that builder cleanup happens before `fcn` is moved { diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 6b10d5bd..2730631f 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -79,20 +79,16 @@ extern ::std::ostream& operator<<(::std::ostream& os, const VarState& x); struct SplitArm { bool has_early_terminated = false; bool always_early_terminated = false; // Populated on completion - ::std::map<unsigned int, VarState> var_states; - ::std::map<unsigned int, VarState> tmp_states; + ::std::map<unsigned int, VarState> states; }; struct SplitEnd { - ::std::map<unsigned int, VarState> var_states; - ::std::map<unsigned int, VarState> tmp_states; + ::std::map<unsigned int, VarState> states; }; -TAGGED_UNION(ScopeType, Variables, - (Variables, struct { - ::std::vector<unsigned int> vars; // List of owned variables - }), - (Temporaries, struct { - ::std::vector<unsigned int> temporaries; // Controlled temporaries +TAGGED_UNION(ScopeType, Owning, + (Owning, struct { + bool is_temporary; + ::std::vector<unsigned int> slots; // List of owned variables }), (Split, struct { bool end_state_valid = false; @@ -101,8 +97,7 @@ TAGGED_UNION(ScopeType, Variables, }), (Loop, struct { // NOTE: This contains the original state for variables changed after `exit_state_valid` is true - ::std::map<unsigned int,VarState> changed_vars; - ::std::map<unsigned int,VarState> changed_tmps; + ::std::map<unsigned int,VarState> changed_slots; bool exit_state_valid; SplitEnd exit_state; }) @@ -134,11 +129,11 @@ class MirBuilder ::MIR::RValue m_result; bool m_result_valid; - // TODO: Extra information. + // TODO: Extra information (e.g. mutability) VarState m_return_state; ::std::vector<VarState> m_arg_states; - ::std::vector<VarState> m_variable_states; - ::std::vector<VarState> m_temporary_states; + ::std::vector<VarState> m_slot_states; + size_t m_first_temp_idx; struct ScopeDef { @@ -177,6 +172,9 @@ public: const ::HIR::TypeRef* is_type_owned_box(const ::HIR::TypeRef& ty) const; // - Values + ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { + return ::MIR::LValue::make_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); @@ -228,8 +226,8 @@ public: void mark_value_assigned(const Span& sp, const ::MIR::LValue& val); // Moves control of temporaries up to the specified scope (or to above it) - void raise_variables(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above=false); - void raise_variables(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above=false); + void raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above=false); + void raise_temporaries(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above=false); void set_cur_block(unsigned int new_block); ::MIR::BasicBlockId pause_cur_block(); @@ -269,13 +267,8 @@ public: // Helper - Marks a variable/... as moved (and checks if the move is valid) void moved_lvalue(const Span& sp, const ::MIR::LValue& lv); private: - const VarState& get_slot_state(const Span& sp, VarGroup ty, unsigned int idx, unsigned int skip_count=0) const; - VarState& get_slot_state_mut(const Span& sp, VarGroup ty, unsigned int idx); - - const VarState& get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const; - VarState& get_variable_state_mut(const Span& sp, unsigned int idx); - const VarState& get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const; - VarState& get_temp_state_mut(const Span& sp, unsigned int idx); + const VarState& get_slot_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const; + VarState& get_slot_state_mut(const Span& sp, unsigned int idx); const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0); VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index a68fd1bf..6e00e2e4 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -219,7 +219,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod { if( pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move) return false; - return !builder.lvalue_is_copy( sp, ::MIR::LValue::make_Variable( pat.m_binding.m_slot) ); + return !builder.lvalue_is_copy( sp, builder.get_variable(sp, pat.m_binding.m_slot) ); } TU_MATCHA( (pat.m_data), (e), (Any, diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index c38e73e9..31b50246 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -70,24 +70,20 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_static_type(::HIR::TypeRef& tmp, c const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const { TU_MATCH(::MIR::LValue, (val), (e), - (Variable, - MIR_ASSERT(*this, e < m_fcn.named_variables.size(), val << " out of range (" << m_fcn.named_variables.size() << ")"); - return m_fcn.named_variables.at(e); - ), - (Temporary, - MIR_ASSERT(*this, e.idx < m_fcn.temporaries.size(), val << " out of range (" << m_fcn.temporaries.size() << ")"); - return m_fcn.temporaries.at(e.idx); + (Return, + return m_ret_type; ), (Argument, - MIR_ASSERT(*this, e.idx < m_args.size(), val << " out of range (" << m_args.size() << ")"); + MIR_ASSERT(*this, e.idx < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")"); return m_args.at(e.idx).second; ), + (Local, + MIR_ASSERT(*this, e < m_fcn.locals.size(), "Local " << val << " out of range (" << m_fcn.locals.size() << ")"); + return m_fcn.locals.at(e); + ), (Static, return get_static_type(tmp, e); ), - (Return, - return m_ret_type; - ), (Field, const auto& ty = this->get_lvalue_type(tmp, *e.val); TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), @@ -314,16 +310,14 @@ namespace visit { if( cb(lv, u) ) return true; TU_MATCHA( (lv), (e), - (Variable, + (Return, ), (Argument, ), - (Temporary, + (Local, ), (Static, ), - (Return, - ), (Field, return visit_mir_lvalue(*e.val, u, cb); ), @@ -547,27 +541,21 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c } block_offsets.push_back(statement_count); // Store the final limit for later code to use. - ::std::vector<ValueLifetime> temporary_lifetimes( fcn.temporaries.size(), ValueLifetime(statement_count) ); - ::std::vector<ValueLifetime> variable_lifetimes( fcn.named_variables.size(), ValueLifetime(statement_count) ); - + ::std::vector<ValueLifetime> slot_lifetimes( fcn.locals.size(), ValueLifetime(statement_count) ); // Enumerate direct assignments of variables (linear iteration of BB list) for(size_t bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++) { 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_Variable() ) - { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, variable_lifetimes[*de]); - variable_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); - } - else if( const auto* de = lv.opt_Temporary() ) + if( const auto* de = lv.opt_Local() ) { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, temporary_lifetimes[de->idx]); - temporary_lifetimes[de->idx].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 { + // TODO: Can Argument(_) be assigned? // Not a direct assignment of a slot } }; @@ -589,6 +577,14 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c assigned_lvalue(bb_idx, stmt_idx+1, e.second); } } + 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() ) + { + slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx); + } + } } state.set_cur_stmt_term(bb_idx); @@ -601,25 +597,18 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c // Dump out variable lifetimes. if( dump_debug ) { - for(unsigned int i = 0; i < temporary_lifetimes.size(); i ++) + for(size_t i = 0; i < slot_lifetimes.size(); i ++) { - temporary_lifetimes[i].dump_debug("tmp", i, block_offsets); - } - for(unsigned int i = 0; i < variable_lifetimes.size(); i ++) - { - variable_lifetimes[i].dump_debug("var", i, block_offsets); + slot_lifetimes[i].dump_debug("_", i, block_offsets); } } ::MIR::ValueLifetimes rv; rv.m_block_offsets = mv$(block_offsets); - rv.m_temporaries.reserve( temporary_lifetimes.size() ); - for(auto& lft : temporary_lifetimes) - rv.m_temporaries.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) ); - rv.m_variables.reserve( variable_lifetimes.size() ); - for(auto& lft : variable_lifetimes) - rv.m_variables.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) ); + rv.m_slots.reserve( slot_lifetimes.size() ); + for(auto& lft : slot_lifetimes) + rv.m_slots.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) ); return rv; } void MIR_Helper_GetLifetimes_DetermineValueLifetime( diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp index 802ce88f..091a669f 100644 --- a/src/mir/helpers.hpp +++ b/src/mir/helpers.hpp @@ -158,14 +158,10 @@ public: struct ValueLifetimes { ::std::vector<size_t> m_block_offsets; - ::std::vector<ValueLifetime> m_temporaries; - ::std::vector<ValueLifetime> m_variables; + ::std::vector<ValueLifetime> m_slots; - bool var_valid(unsigned var_idx, unsigned bb_idx, unsigned stmt_idx) const { - return m_variables.at(var_idx).valid_at( m_block_offsets[bb_idx] + stmt_idx ); - } - bool tmp_valid(unsigned tmp_idx, unsigned bb_idx, unsigned stmt_idx) const { - return m_temporaries.at(tmp_idx).valid_at( m_block_offsets[bb_idx] + stmt_idx ); + bool slot_valid(unsigned idx, unsigned bb_idx, unsigned stmt_idx) const { + return m_slots.at(idx).valid_at( m_block_offsets[bb_idx] + stmt_idx ); } }; diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 9edc925b..3f7057ff 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -92,21 +92,18 @@ namespace MIR { ::std::ostream& operator<<(::std::ostream& os, const LValue& x) { TU_MATCHA( (x), (e), - (Variable, - os << "Variable(" << e << ")"; - ), - (Temporary, - os << "Temporary(" << e.idx << ")"; + (Return, + os << "Return"; ), (Argument, os << "Argument(" << e.idx << ")"; ), + (Local, + os << "Local(" << e << ")"; + ), (Static, os << "Static(" << e << ")"; ), - (Return, - os << "Return"; - ), (Field, os << "Field(" << e.field_index << ", " << *e.val << ")"; ), @@ -127,20 +124,17 @@ namespace MIR { if( a.tag() != b.tag() ) return a.tag() < b.tag(); TU_MATCHA( (a, b), (ea, eb), - (Variable, - return ea < eb; - ), - (Temporary, - return ea.idx < eb.idx; + (Return, + return false; ), (Argument, return ea.idx < eb.idx; ), - (Static, + (Local, return ea < eb; ), - (Return, - return false; + (Static, + return ea < eb; ), (Field, if( *ea.val != *eb.val ) @@ -170,20 +164,17 @@ namespace MIR { if( a.tag() != b.tag() ) return false; TU_MATCHA( (a, b), (ea, eb), - (Variable, - return ea == eb; - ), - (Temporary, - return ea.idx == eb.idx; + (Return, + return true; ), (Argument, return ea.idx == eb.idx; ), - (Static, + (Local, return ea == eb; ), - (Return, - return true; + (Static, + return ea == eb; ), (Field, if( *ea.val != *eb.val ) @@ -486,10 +477,8 @@ namespace MIR { ), (ScopeEnd, os << "ScopeEnd("; - for(auto idx : e.vars) - os << "var$" << idx << ","; - for(auto idx : e.tmps) - os << "tmp$" << idx << ","; + for(auto idx : e.slots) + os << "_$" << idx << ","; os << ")"; ) ) @@ -500,11 +489,10 @@ namespace MIR { ::MIR::LValue MIR::LValue::clone() const { TU_MATCHA( (*this), (e), - (Variable, return LValue(e); ), - (Temporary, return LValue(e); ), + (Return, return LValue(e); ), (Argument, return LValue(e); ), + (Local, return LValue(e); ), (Static, return LValue(e.clone()); ), - (Return, return LValue(e); ), (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 c22f8d5d..6254bf42 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -17,21 +17,15 @@ typedef unsigned int RegionId; typedef unsigned int BasicBlockId; // "LVALUE" - Assignable values -TAGGED_UNION_EX(LValue, (), Variable, ( - // User-named variable - (Variable, unsigned int), - // Temporary with no user-defined name - (Temporary, struct { - unsigned int idx; - }), - // Function argument (matters for destructuring) - (Argument, struct { - unsigned int idx; - }), - // `static` or `static mut` - (Static, ::HIR::Path), +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, ::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 { @@ -274,8 +268,7 @@ TAGGED_UNION(Statement, Assign, unsigned int flag_idx; // Valid if != ~0u }), (ScopeEnd, struct { - ::std::vector<unsigned> vars; - ::std::vector<unsigned> tmps; + ::std::vector<unsigned> slots; }) ); extern ::std::ostream& operator<<(::std::ostream& os, const Statement& x); @@ -290,9 +283,8 @@ struct BasicBlock class Function { public: - // TODO: Unify Variables, Temporaries, and Arguments - ::std::vector< ::HIR::TypeRef> named_variables; - ::std::vector< ::HIR::TypeRef> temporaries; + ::std::vector< ::HIR::TypeRef> locals; + //::std::vector< ::std::string> local_names; ::std::vector<bool> drop_flags; ::std::vector<BasicBlock> blocks; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index f03dc40f..5ace0bb0 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -26,21 +26,20 @@ MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const } set_cur_block( new_bb_unlinked() ); - m_scopes.push_back( ScopeDef { sp } ); + m_scopes.push_back( ScopeDef { sp, ScopeType::make_Owning({ false, {} }) } ); m_scope_stack.push_back( 0 ); - m_scopes.push_back( ScopeDef { sp, ScopeType::make_Temporaries({}) } ); + m_scopes.push_back( ScopeDef { sp, ScopeType::make_Owning({ true, {} }) } ); m_scope_stack.push_back( 1 ); - - m_if_cond_lval = this->new_temporary(::HIR::CoreType::Bool); - m_arg_states.reserve( args.size() ); - for(size_t i = 0; i < args.size(); i ++ ) + for(size_t i = 0; i < args.size(); i ++) m_arg_states.push_back( VarState::make_Valid({}) ); - m_variable_states.reserve( output.named_variables.size() ); - for(size_t i = 0; i < output.named_variables.size(); i ++ ) - m_variable_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); + m_slot_states.resize( output.locals.size() ); + m_first_temp_idx = output.locals.size(); + DEBUG("First temporary will be " << m_first_temp_idx); + + m_if_cond_lval = this->new_temporary(::HIR::CoreType::Bool); } MirBuilder::~MirBuilder() { @@ -85,18 +84,21 @@ const ::HIR::TypeRef* MirBuilder::is_type_owned_box(const ::HIR::TypeRef& ty) co void MirBuilder::define_variable(unsigned int idx) { - DEBUG("DEFINE var" << idx << ": " << m_output.named_variables.at(idx)); + DEBUG("DEFINE (var) _" << idx << ": " << m_output.locals.at(idx)); for( auto scope_idx : ::reverse(m_scope_stack) ) { auto& scope_def = m_scopes.at(scope_idx); TU_MATCH_DEF( ScopeType, (scope_def.data), (e), ( ), - (Variables, - auto it = ::std::find(e.vars.begin(), e.vars.end(), idx); - assert(it == e.vars.end()); - e.vars.push_back( idx ); - return ; + (Owning, + if( !e.is_temporary ) + { + auto it = ::std::find(e.slots.begin(), e.slots.end(), idx); + assert(it == e.slots.end()); + e.slots.push_back( idx ); + return ; + } ), (Split, BUG(Span(), "Variable " << idx << " introduced within a Split"); @@ -107,20 +109,24 @@ void MirBuilder::define_variable(unsigned int idx) } ::MIR::LValue MirBuilder::new_temporary(const ::HIR::TypeRef& ty) { - unsigned int rv = m_output.temporaries.size(); - DEBUG("DEFINE tmp" << rv << ": " << ty); + unsigned int rv = m_output.locals.size(); + DEBUG("DEFINE (temp) _" << rv << ": " << ty); - m_output.temporaries.push_back( ty.clone() ); - m_temporary_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); - assert(m_output.temporaries.size() == m_temporary_states.size()); + assert(m_output.locals.size() == m_slot_states.size()); + m_output.locals.push_back( ty.clone() ); + m_slot_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); + assert(m_output.locals.size() == m_slot_states.size()); ScopeDef* top_scope = nullptr; for(unsigned int i = m_scope_stack.size(); i --; ) { auto idx = m_scope_stack[i]; - if( m_scopes.at( idx ).data.is_Temporaries() ) { - top_scope = &m_scopes.at(idx); - break ; + if( const auto* e = m_scopes.at( idx ).data.opt_Owning() ) { + if( e->is_temporary ) + { + top_scope = &m_scopes.at(idx); + break ; + } } else if( m_scopes.at(idx).data.is_Loop() ) { @@ -140,9 +146,10 @@ void MirBuilder::define_variable(unsigned int idx) } } assert( top_scope ); - auto& tmp_scope = top_scope->data.as_Temporaries(); - tmp_scope.temporaries.push_back( rv ); - return ::MIR::LValue::make_Temporary({rv}); + 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); } ::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val) { @@ -151,7 +158,7 @@ void MirBuilder::define_variable(unsigned int idx) ) else { auto temp = new_temporary(ty); - push_stmt_assign( sp, ::MIR::LValue(temp.as_Temporary()), mv$(val) ); + push_stmt_assign( sp, temp.clone(), mv$(val) ); return temp; } } @@ -378,26 +385,12 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) TU_MATCH_DEF(::MIR::LValue, (dst), (e), ( ), - (Temporary, - state_p = &get_temp_state_mut(sp, e.idx); - if( const auto* se = state_p->opt_Invalid() ) - { - if( *se != InvalidType::Uninit ) { - BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p); - } - } - else { - // TODO: This should be a bug, but some of the match code ends up reassigning so.. - //BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p); - } - ), (Return, // Don't drop. // No state tracking for the return value ), - (Variable, - // TODO: Ensure that slot is mutable (information is lost, assume true) - state_p = &get_variable_state_mut(sp, e); + (Local, + state_p = &get_slot_state_mut(sp, e); ) ) @@ -411,7 +404,7 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) } } -void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/) +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), @@ -422,29 +415,32 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const // 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_variables(sp, *e.val, scope, to_above); - raise_variables(sp, *e.idx, scope, to_above); + raise_temporaries(sp, *e.val, scope, to_above); + raise_temporaries(sp, *e.idx, scope, to_above); return ; ), (Deref, - raise_variables(sp, *e.val, scope, to_above); + raise_temporaries(sp, *e.val, scope, to_above); return ; ), (Field, - raise_variables(sp, *e.val, scope, to_above); + raise_temporaries(sp, *e.val, scope, to_above); return ; ), (Downcast, - raise_variables(sp, *e.val, scope, to_above); + raise_temporaries(sp, *e.val, scope, to_above); return ; ), // Actual value types - (Variable, - ), - (Temporary, + (Local, ) ) - ASSERT_BUG(sp, val.is_Variable() || val.is_Temporary(), "Hit value raising code with non-variable value - " << val); + ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val); + const auto idx = val.as_Local(); + bool is_temp = (idx < m_first_temp_idx); + if( idx < m_first_temp_idx ) { + return ; + } // Find controlling scope auto scope_it = m_scope_stack.rbegin(); @@ -457,30 +453,20 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const DEBUG(val << " defined in or above target (scope " << scope << ")"); } - TU_IFLET( ScopeType, scope_def.data, Variables, e, - if( const auto* ve = val.opt_Variable() ) + TU_IFLET( ScopeType, scope_def.data, Owning, e, + if( e.is_temporary == is_temp ) { - auto idx = *ve; - auto tmp_it = ::std::find( e.vars.begin(), e.vars.end(), idx ); - if( tmp_it != e.vars.end() ) + auto tmp_it = ::std::find(e.slots.begin(), e.slots.end(), idx); + if( tmp_it != e.slots.end() ) { - e.vars.erase( tmp_it ); - DEBUG("Raise variable " << idx << " from " << *scope_it); + e.slots.erase( tmp_it ); + DEBUG("Raise slot " << idx << " from " << *scope_it); break ; } } - ) - else TU_IFLET( ScopeType, scope_def.data, Temporaries, e, - if( const auto* ve = val.opt_Temporary() ) + else { - auto idx = ve->idx; - auto tmp_it = ::std::find( e.temporaries.begin(), e.temporaries.end(), idx ); - if( tmp_it != e.temporaries.end() ) - { - e.temporaries.erase( tmp_it ); - DEBUG("Raise temporary " << idx << " from " << *scope_it); - break ; - } + // TODO: Should this care about variables? } ) else @@ -536,26 +522,12 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const target_seen = true; } - TU_IFLET( ScopeType, scope_def.data, Variables, e, - if( target_seen ) - { - if( const auto* ve = val.opt_Variable() ) - { - e.vars.push_back( *ve ); - DEBUG("- to " << *scope_it); - return ; - } - } - ) - else TU_IFLET( ScopeType, scope_def.data, Temporaries, e, - if( target_seen ) + TU_IFLET( ScopeType, scope_def.data, Owning, e, + if( target_seen && e.is_temporary == is_temp ) { - if( const auto* ve = val.opt_Temporary() ) - { - e.temporaries.push_back( ve->idx ); - DEBUG("- to " << *scope_it); - return ; - } + e.slots.push_back( idx ); + DEBUG("- to " << *scope_it); + return ; } ) else if( auto* sd_loop = scope_def.data.opt_Loop() ) @@ -566,19 +538,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const if( sd_loop->exit_state_valid ) { DEBUG("Adding " << val << " as unset to loop exit state"); - if( const auto* ve = val.opt_Variable() ) - { - auto v = sd_loop->exit_state.var_states.insert( ::std::make_pair(*ve, VarState(InvalidType::Uninit)) ); - ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); - } - else if( const auto* ve = val.opt_Temporary() ) - { - auto v = sd_loop->exit_state.tmp_states.insert( ::std::make_pair(ve->idx, VarState(InvalidType::Uninit)) ); - ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); - } - else { - BUG(sp, "Impossible raise value"); - } + auto v = sd_loop->exit_state.states.insert( ::std::make_pair(idx, VarState(InvalidType::Uninit)) ); + ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); } else { @@ -592,19 +553,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const if( sd_split->end_state_valid ) { DEBUG("Adding " << val << " as unset to loop exit state"); - if( const auto* ve = val.opt_Variable() ) - { - auto v = sd_split->end_state.var_states.insert( ::std::make_pair(*ve, VarState(InvalidType::Uninit)) ); - ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); - } - else if( const auto* ve = val.opt_Temporary() ) - { - auto v = sd_split->end_state.tmp_states.insert( ::std::make_pair(ve->idx, VarState(InvalidType::Uninit)) ); - ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); - } - else { - BUG(sp, "Impossible raise value"); - } + auto v = sd_split->end_state.states.insert( ::std::make_pair(idx, VarState(InvalidType::Uninit)) ); + ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); } else { @@ -613,20 +563,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const // TODO: This should update the outer state to unset. auto& arm = sd_split->arms.back(); - if( const auto* ve = val.opt_Variable() ) - { - arm.var_states.insert(::std::make_pair( *ve, get_variable_state(sp, *ve).clone() )); - m_variable_states.at(*ve) = VarState(InvalidType::Uninit); - } - else if( const auto* ve = val.opt_Temporary() ) - { - arm.tmp_states.insert(::std::make_pair( ve->idx, get_temp_state(sp, ve->idx).clone() )); - m_temporary_states.at(ve->idx) = VarState(InvalidType::Uninit); - } - else - { - BUG(sp, "Impossible raise value"); - } + arm.states.insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )); + m_slot_states.at(idx) = VarState(InvalidType::Uninit); } else { @@ -635,15 +573,15 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const } BUG(sp, "Couldn't find a scope to raise " << val << " into"); } -void MirBuilder::raise_variables(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above/*=false*/) +void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above/*=false*/) { auto raise_vars = [&](const ::MIR::Param& p) { if( const auto* e = p.opt_LValue() ) - this->raise_variables(sp, *e, scope, to_above); + this->raise_temporaries(sp, *e, scope, to_above); }; TU_MATCHA( (rval), (e), (Use, - this->raise_variables(sp, e, scope, to_above); + this->raise_temporaries(sp, e, scope, to_above); ), (Constant, ), @@ -652,23 +590,23 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::RValue& rval, cons ), (Borrow, // TODO: Wait, is this valid? - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (Cast, - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (BinOp, raise_vars(e.val_l); raise_vars(e.val_r); ), (UniOp, - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (DstMeta, - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (DstPtr, - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (MakeDst, raise_vars(e.ptr_val); @@ -760,7 +698,7 @@ bool MirBuilder::get_drop_flag_default(const Span& sp, unsigned int idx) ScopeHandle MirBuilder::new_scope_var(const Span& sp) { unsigned int idx = m_scopes.size(); - m_scopes.push_back( ScopeDef {sp, ScopeType::make_Variables({})} ); + m_scopes.push_back( ScopeDef {sp, ScopeType::make_Owning({ false, {} })} ); m_scope_stack.push_back( idx ); DEBUG("START (var) scope " << idx); return ScopeHandle { *this, idx }; @@ -768,7 +706,8 @@ ScopeHandle MirBuilder::new_scope_var(const Span& sp) ScopeHandle MirBuilder::new_scope_temp(const Span& sp) { unsigned int idx = m_scopes.size(); - m_scopes.push_back( ScopeDef {sp, ScopeType::make_Temporaries({})} ); + + m_scopes.push_back( ScopeDef {sp, ScopeType::make_Owning({ true, {} })} ); m_scope_stack.push_back( idx ); DEBUG("START (temp) scope " << idx); return ScopeHandle { *this, idx }; @@ -852,11 +791,13 @@ 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_Temporaries(), "Rasising scopes can only be done on temporaries (source)"); - auto& src_list = src_scope_def.data.as_Temporaries().temporaries; + 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_Temporary({ idx })); + DEBUG("> Raising " << ::MIR::LValue::make_Local(idx)); + assert(idx >= m_first_temp_idx); } // Seek up stack until the target scope is seen @@ -873,7 +814,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle // Insert these values as Invalid, both in the existing exit state, and in the changed list for(auto idx : src_list) { - auto v = sd_loop->exit_state.tmp_states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); + auto v = sd_loop->exit_state.states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); ASSERT_BUG(sp, v.second, ""); } } @@ -884,7 +825,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle for(auto idx : src_list) { - auto v2 = sd_loop->changed_tmps.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); + auto v2 = sd_loop->changed_slots.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); ASSERT_BUG(sp, v2.second, ""); } } @@ -896,7 +837,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle // Insert these indexes as Invalid for(auto idx : src_list) { - auto v = sd_split->end_state.tmp_states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); + auto v = sd_split->end_state.states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); ASSERT_BUG(sp, v.second, ""); } } @@ -910,8 +851,8 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle auto& arm = sd_split->arms.back(); for(auto idx : src_list) { - arm.tmp_states.insert(::std::make_pair( idx, mv$(m_temporary_states.at(idx)) )); - m_temporary_states.at(idx) = VarState(InvalidType::Uninit); + arm.states.insert(::std::make_pair( idx, mv$(m_slot_states.at(idx)) )); + m_slot_states.at(idx) = VarState(InvalidType::Uninit); } } } @@ -920,16 +861,17 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle BUG(sp, "Moving values to a scope not on the stack - scope " << target.idx); } auto& tgt_scope_def = m_scopes.at(target.idx); - ASSERT_BUG(sp, tgt_scope_def.data.is_Temporaries(), "Rasising scopes can only be done on temporaries (target)"); + ASSERT_BUG(sp, tgt_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (target)"); + ASSERT_BUG(sp, tgt_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (target)"); // Move all defined variables from one to the other - auto& tgt_list = tgt_scope_def.data.as_Temporaries().temporaries; + 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_variables(sp, ::MIR::LValue::make_Temporary({ idx }), target); + this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target); } #endif @@ -1388,39 +1330,24 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l { // Insert copies of parent state for newly changed values // and Merge all changed values - for(const auto& ent : sd_loop.changed_vars) - { - auto idx = ent.first; - if( sd_loop.exit_state.var_states.count(idx) == 0 ) { - sd_loop.exit_state.var_states.insert(::std::make_pair( idx, ent.second.clone() )); - } - auto& old_state = sd_loop.exit_state.var_states.at(idx); - merge_state(sp, *this, ::MIR::LValue::make_Variable(idx), old_state, get_variable_state(sp, idx)); - } - for(const auto& ent : sd_loop.changed_tmps) + for(const auto& ent : sd_loop.changed_slots) { auto idx = ent.first; - if( sd_loop.exit_state.tmp_states.count(idx) == 0 ) { - sd_loop.exit_state.tmp_states.insert(::std::make_pair( idx, ent.second.clone() )); + if( sd_loop.exit_state.states.count(idx) == 0 ) { + sd_loop.exit_state.states.insert(::std::make_pair( idx, ent.second.clone() )); } - auto& old_state = sd_loop.exit_state.tmp_states.at(idx); - merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), old_state, get_temp_state(sp, idx)); + auto& old_state = sd_loop.exit_state.states.at(idx); + merge_state(sp, *this, ::MIR::LValue::make_Local(idx), old_state, get_slot_state(sp, idx)); } } else { // Obtain states of changed variables/temporaries - for(const auto& ent : sd_loop.changed_vars) + for(const auto& ent : sd_loop.changed_slots) { - DEBUG("Variable(" << ent.first << ") = " << ent.second); + DEBUG("Slot(" << ent.first << ") = " << ent.second); auto idx = ent.first; - sd_loop.exit_state.var_states.insert(::std::make_pair( idx, get_variable_state(sp, idx).clone() )); - } - for(const auto& ent : sd_loop.changed_tmps) - { - DEBUG("Temporary(" << ent.first << ") = " << ent.second); - auto idx = ent.first; - sd_loop.exit_state.tmp_states.insert(::std::make_pair( idx, get_temp_state(sp, idx).clone() )); + sd_loop.exit_state.states.insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )); } sd_loop.exit_state_valid = true; } @@ -1446,39 +1373,23 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r if( reachable ) { // Insert copies of the parent state - for(const auto& ent : this_arm_state.var_states) { - if( sd_split.end_state.var_states.count(ent.first) == 0 ) { - sd_split.end_state.var_states.insert(::std::make_pair( ent.first, get_variable_state(sp, ent.first, 1).clone() )); - } - } - for(const auto& ent : this_arm_state.tmp_states) { - if( sd_split.end_state.tmp_states.count(ent.first) == 0 ) { - sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, get_temp_state(sp, ent.first, 1).clone() )); + for(const auto& ent : this_arm_state.states) { + if( sd_split.end_state.states.count(ent.first) == 0 ) { + sd_split.end_state.states.insert(::std::make_pair( ent.first, get_slot_state(sp, ent.first, 1).clone() )); } } // Merge state - for(auto& ent : sd_split.end_state.var_states) - { - auto idx = ent.first; - auto& out_state = ent.second; - - // Merge the states - auto it = this_arm_state.var_states.find(idx); - const auto& src_state = (it != this_arm_state.var_states.end() ? it->second : get_variable_state(sp, idx, 1)); - - merge_state(sp, *this, ::MIR::LValue::make_Variable(idx), out_state, src_state); - } - for(auto& ent : sd_split.end_state.tmp_states) + for(auto& ent : sd_split.end_state.states) { auto idx = ent.first; auto& out_state = ent.second; // Merge the states - auto it = this_arm_state.tmp_states.find(idx); - const auto& src_state = (it != this_arm_state.tmp_states.end() ? it->second : get_temp_state(sp, idx, 1)); + auto it = this_arm_state.states.find(idx); + const auto& src_state = (it != this_arm_state.states.end() ? it->second : get_slot_state(sp, idx, 1)); - merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), out_state, src_state); + merge_state(sp, *this, ::MIR::LValue::make_Local(idx), out_state, src_state); } } else @@ -1489,15 +1400,10 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r else { // Clone this arm's state - for(auto& ent : this_arm_state.var_states) - { - DEBUG("Variable(" << ent.first << ") = " << ent.second); - sd_split.end_state.var_states.insert(::std::make_pair( ent.first, ent.second.clone() )); - } - for(auto& ent : this_arm_state.tmp_states) + for(auto& ent : this_arm_state.states) { - DEBUG("Temporary(" << ent.first << ") = " << ent.second); - sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, ent.second.clone() )); + DEBUG("Slot(" << ent.first << ") = " << ent.second); + sd_split.end_state.states.insert(::std::make_pair( ent.first, ent.second.clone() )); } sd_split.end_state_valid = true; } @@ -1536,11 +1442,8 @@ void MirBuilder::complete_scope(ScopeDef& sd) sd.complete = true; TU_MATCHA( (sd.data), (e), - (Temporaries, - DEBUG("Temporaries - " << e.temporaries); - ), - (Variables, - DEBUG("Variables - " << e.vars); + (Owning, + DEBUG("Owning (" << (e.is_temporary ? "temps" : "vars") << ") - " << e.slots); ), (Loop, DEBUG("Loop"); @@ -1552,21 +1455,12 @@ void MirBuilder::complete_scope(ScopeDef& sd) struct H { static void apply_end_state(const Span& sp, MirBuilder& builder, SplitEnd& end_state) { - for(auto& ent : end_state.var_states) + for(auto& ent : end_state.states) { - auto& vs = builder.get_variable_state_mut(sp, ent.first); + auto& vs = builder.get_slot_state_mut(sp, ent.first); if( vs != ent.second ) { - DEBUG(::MIR::LValue::make_Variable(ent.first) << " " << vs << " => " << ent.second); - vs = ::std::move(ent.second); - } - } - for(auto& ent : end_state.tmp_states) - { - auto& vs = builder.get_temp_state_mut(sp, ent.first); - if( vs != ent.second ) - { - DEBUG(::MIR::LValue::make_Temporary({ent.first}) << " " << vs << " => " << ent.second); + DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } @@ -1596,16 +1490,15 @@ void MirBuilder::complete_scope(ScopeDef& sd) void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const { TU_MATCH(::MIR::LValue, (val), (e), - (Variable, - cb( m_output.named_variables.at(e) ); - ), - (Temporary, - cb( m_output.temporaries.at(e.idx) ); + (Return, + TODO(sp, "Return"); ), (Argument, - ASSERT_BUG(sp, e.idx < m_args.size(), "Argument number out of range"); cb( m_args.at(e.idx).second ); ), + (Local, + cb( m_output.locals.at(e) ); + ), (Static, TU_MATCHA( (e.m_data), (pe), (Generic, @@ -1624,9 +1517,6 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: ) ) ), - (Return, - TODO(sp, "Return"); - ), (Field, with_val_type(sp, *e.val, [&](const auto& ty){ TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), @@ -1821,7 +1711,7 @@ bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const return rv == 2; } -const VarState& MirBuilder::get_slot_state(const Span& sp, VarGroup ty, unsigned int idx, unsigned int skip_count/*=0*/) const +const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, unsigned int skip_count/*=0*/) const { // 1. Find an applicable Split scope for( auto scope_idx : ::reverse(m_scope_stack) ) @@ -1830,92 +1720,46 @@ const VarState& MirBuilder::get_slot_state(const Span& sp, VarGroup ty, unsigned TU_MATCH_DEF( ScopeType, (scope_def.data), (e), ( ), - (Temporaries, - if( ty == VarGroup::Temporary ) - { - auto it = ::std::find(e.temporaries.begin(), e.temporaries.end(), idx); - if( it != e.temporaries.end() ) { - break ; - } - } - ), - (Variables, - if( ty == VarGroup::Variable ) - { - auto it = ::std::find(e.vars.begin(), e.vars.end(), idx); - if( it != e.vars.end() ) { - // If controlled by this block, exit early (won't find it elsewhere) - break ; - } + (Owning, + auto it = ::std::find(e.slots.begin(), e.slots.end(), idx); + if( it != e.slots.end() ) { + break ; } ), (Split, const auto& cur_arm = e.arms.back(); - if( ty == VarGroup::Variable ) - { - auto it = cur_arm.var_states.find(idx); - if( it != cur_arm.var_states.end() ) - { - if( ! skip_count -- ) - { - return it->second; - } - } - } - else if( ty == VarGroup::Temporary ) + auto it = cur_arm.states.find(idx); + if( it != cur_arm.states.end() ) { - auto it = cur_arm.tmp_states.find(idx); - if( it != cur_arm.tmp_states.end() ) + if( ! skip_count -- ) { - if( ! skip_count -- ) - { - return it->second; - } + return it->second; } } ) ) } - switch(ty) + if( idx == ~0u ) { - case VarGroup::Return: return m_return_state; - case VarGroup::Argument: - ASSERT_BUG(sp, idx < m_arg_states.size(), "Argument " << idx << " out of range for state table"); - return m_arg_states.at(idx); - case VarGroup::Variable: - ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); - return m_variable_states[idx]; - case VarGroup::Temporary: - ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); - return m_temporary_states[idx]; } - BUG(sp, "Fell off the end of get_slot_state"); + else + { + ASSERT_BUG(sp, idx < m_slot_states.size(), "Slot " << idx << " out of range for state table"); + return m_slot_states.at(idx); + } } -VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned int idx) +VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) { VarState* ret = nullptr; for( auto scope_idx : ::reverse(m_scope_stack) ) { auto& scope_def = m_scopes.at(scope_idx); - if( const auto* e = scope_def.data.opt_Variables() ) - { - if( ty == VarGroup::Variable ) - { - auto it = ::std::find(e->vars.begin(), e->vars.end(), idx); - if( it != e->vars.end() ) { - break ; - } - } - } - else if( const auto* e = scope_def.data.opt_Temporaries() ) + if( const auto* e = scope_def.data.opt_Owning() ) { - if( ty == VarGroup::Temporary ) - { - auto it = ::std::find(e->temporaries.begin(), e->temporaries.end(), idx); - if( it != e->temporaries.end() ) { - break ; - } + auto it = ::std::find(e->slots.begin(), e->slots.end(), idx); + if( it != e->slots.end() ) { + break ; } } else if( scope_def.data.is_Split() ) @@ -1924,28 +1768,21 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned i auto& cur_arm = e.arms.back(); if( ! ret ) { - ::std::map<unsigned int, VarState>* states; - switch(ty) - { - case VarGroup::Return: states = nullptr; break; - case VarGroup::Argument: BUG(sp, "Mutating state of argument"); break; - case VarGroup::Variable: states = &cur_arm.var_states; break; - case VarGroup::Temporary: states = &cur_arm.tmp_states; break; + if( idx == ~0u ) { } - - if( states ) - { + else { + auto* states = &cur_arm.states; auto it = states->find(idx); if( it == states->end() ) { DEBUG("Split new (scope " << scope_idx << ")"); - ret = &( (*states)[idx] = get_slot_state(sp, ty, idx).clone() ); + it = states->insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )).first; } else { DEBUG("Split existing (scope " << scope_idx << ")"); - ret = &it->second; } + ret = &it->second; } } } @@ -1953,19 +1790,15 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned i { auto& e = scope_def.data.as_Loop(); ::std::map<unsigned int, VarState>* states = nullptr; - switch(ty) + if( idx == ~0u ) { - case VarGroup::Return: states = nullptr; break; - case VarGroup::Argument: BUG(sp, "Mutating state of argument"); break; - case VarGroup::Variable: states = &e.changed_vars; break; - case VarGroup::Temporary: states = &e.changed_tmps; break; } - - if( states ) + else { + states = &e.changed_slots; if( states->count(idx) == 0 ) { - auto state = e.exit_state_valid ? get_slot_state(sp, ty, idx).clone() : VarState::make_Valid({}); + auto state = e.exit_state_valid ? get_slot_state(sp, idx).clone() : VarState::make_Valid({}); states->insert(::std::make_pair( idx, mv$(state) )); } } @@ -1980,39 +1813,16 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned i } else { - switch(ty) + if( idx == ~0u ) { - case VarGroup::Return: return m_return_state; - case VarGroup::Argument: - ASSERT_BUG(sp, idx < m_arg_states.size(), "Argument " << idx << " out of range for state table"); - return m_arg_states.at(idx); - case VarGroup::Variable: - ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); - return m_variable_states[idx]; - case VarGroup::Temporary: - ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); - return m_temporary_states[idx]; } - BUG(sp, "Fell off the end of get_slot_state_mut"); + else + { + return m_slot_states.at(idx); + } } } -const VarState& MirBuilder::get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count) const -{ - return get_slot_state(sp, VarGroup::Variable, idx, skip_count); -} -VarState& MirBuilder::get_variable_state_mut(const Span& sp, unsigned int idx) -{ - return get_slot_state_mut(sp, VarGroup::Variable, idx); -} -const VarState& MirBuilder::get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count) const -{ - return get_slot_state(sp, VarGroup::Temporary, idx, skip_count); -} -VarState& MirBuilder::get_temp_state_mut(const Span& sp, unsigned int idx) -{ - return get_slot_state_mut(sp, VarGroup::Temporary, idx); -} const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count) { @@ -2022,22 +1832,20 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) { TRACE_FUNCTION_F(lv); TU_MATCHA( (lv), (e), - (Variable, - return get_slot_state_mut(sp, VarGroup::Variable, e); - ), - (Temporary, - return get_slot_state_mut(sp, VarGroup::Temporary, e.idx); + (Return, + BUG(sp, "Move of return value"); + return get_slot_state_mut(sp, ~0u); ), (Argument, - return get_slot_state_mut(sp, VarGroup::Argument, e.idx); + // NOTE: Only valid outside of split scopes (should only happen at the start) + return m_arg_states.at(e.idx); + ), + (Local, + return get_slot_state_mut(sp, e); ), (Static, BUG(sp, "Attempting to mutate state of a static"); ), - (Return, - BUG(sp, "Move of return value"); - return get_slot_state_mut(sp, VarGroup::Return, 0); - ), (Field, auto& ivs = get_val_state_mut(sp, *e.val); VarState tpl; @@ -2117,13 +1925,10 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) this->push_stmt_assign(sp, inner_lv.clone(), ::MIR::RValue( mv$(*e.val) )); *e.val = inner_lv.clone(); ), - (Variable, + (Argument, inner_lv = ::MIR::LValue(ei); ), - (Temporary, - inner_lv = ::MIR::LValue(ei); - ), - (Argument, + (Local, inner_lv = ::MIR::LValue(ei); ) ) @@ -2252,20 +2057,12 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR void MirBuilder::drop_scope_values(const ScopeDef& sd) { TU_MATCHA( (sd.data), (e), - (Temporaries, - for(auto tmp_idx : ::reverse(e.temporaries)) - { - const auto& vs = get_temp_state(sd.span, tmp_idx); - DEBUG("tmp" << tmp_idx << " - " << vs); - drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Temporary({ tmp_idx }) ); - } - ), - (Variables, - for(auto var_idx : ::reverse(e.vars)) + (Owning, + for(auto idx : ::reverse(e.slots)) { - const auto& vs = get_variable_state(sd.span, var_idx); - DEBUG("var" << var_idx << " - " << vs); - drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Variable(var_idx) ); + const auto& vs = get_slot_state(sd.span, idx); + DEBUG("slot" << idx << " - " << vs); + drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Local(idx) ); } ), (Split, diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 8e350c45..6837eab6 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -20,6 +20,7 @@ #define DUMP_BEFORE_ALL 0 #define DUMP_BEFORE_CONSTPROPAGATE 0 #define CHECK_AFTER_PASS 0 +#define CHECK_AFTER_ALL 0 #define DUMP_AFTER_DONE 0 #define CHECK_AFTER_DONE 1 @@ -59,16 +60,14 @@ namespace { if( cb(lv, u) ) return true; TU_MATCHA( (lv), (e), - (Variable, + (Return, ), (Argument, ), - (Temporary, + (Local, ), (Static, ), - (Return, - ), (Field, return visit_mir_lvalue_mut(*e.val, u, cb); ), @@ -473,6 +472,9 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // >> Apply known constants change_happened |= MIR_Optimise_ConstPropagte(state, fcn); + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif // >> Inline short functions bool inline_happened = MIR_Optimise_Inlining(state, fcn); @@ -483,18 +485,27 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path //MIR_Dump_Fcn(::std::cout, fcn); change_happened = true; } + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif // TODO: Convert `&mut *mut_foo` into `mut_foo` if the source is movable and not used afterwards // >> Propagate/remove dead assignments while( MIR_Optimise_PropagateSingleAssignments(state, fcn) ) change_happened = true; + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); // >> Unify duplicate temporaries // If two temporaries don't overlap in lifetime (blocks in which they're valid), unify the two change_happened |= MIR_Optimise_UnifyTemporaries(state, fcn); + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif // >> Combine Duplicate Blocks change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); @@ -553,12 +564,9 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn) auto& dst = (it-1)->as_ScopeEnd(); const auto& src = it->as_ScopeEnd(); DEBUG("Unify " << *(it-1) << " and " << *it); - for(auto v : src.vars) - dst.vars.push_back(v); - for(auto v : src.tmps) - dst.tmps.push_back(v); - ::std::sort(dst.vars.begin(), dst.vars.end()); - ::std::sort(dst.tmps.begin(), dst.tmps.end()); + for(auto v : src.slots) + dst.slots.push_back(v); + ::std::sort(dst.slots.begin(), dst.slots.end()); it = block.statements.erase(it); } else @@ -824,12 +832,9 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) ), (ScopeEnd, ::MIR::Statement::Data_ScopeEnd new_se; - new_se.vars.reserve(se.vars.size()); - for(auto idx : se.vars) - new_se.vars.push_back(this->var_base + idx); - new_se.tmps.reserve(se.tmps.size()); - for(auto idx : se.tmps) - new_se.tmps.push_back(this->tmp_base + idx); + new_se.slots.reserve(se.slots.size()); + for(auto idx : se.slots) + new_se.slots.push_back(this->var_base + idx); rv.statements.push_back(::MIR::Statement( mv$(new_se) )); ) ) @@ -922,23 +927,24 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) ::MIR::LValue clone_lval(const ::MIR::LValue& src) const { TU_MATCHA( (src), (se), - (Variable, - return ::MIR::LValue::make_Variable(se + this->var_base); - ), - (Temporary, - return ::MIR::LValue::make_Temporary({se.idx + this->tmp_base}); + (Return, + return this->te.ret_val.clone(); ), (Argument, const auto& arg = this->te.args.at(se.idx); - if( const auto* e = arg.opt_Constant() ) { - auto tmp = ::MIR::LValue::make_Temporary({ static_cast<unsigned>(this->tmp_end + this->const_assignments.size()) }); + if( const auto* e = arg.opt_Constant() ) + { + auto tmp = ::MIR::LValue::make_Local( static_cast<unsigned>(this->tmp_end + this->const_assignments.size()) ); this->const_assignments.push_back( e->clone() ); return tmp; } - return arg.as_LValue().clone(); + else + { + return arg.as_LValue().clone(); + } ), - (Return, - return this->te.ret_val.clone(); + (Local, + return ::MIR::LValue::make_Local(this->var_base + se); ), (Static, return this->monomorph( se ); @@ -983,8 +989,8 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) { TU_MATCHA( (src), (se), (LValue, - if( se.is_Argument() ) - return this->te.args.at(se.as_Argument().idx).clone(); + if( const auto* ae = se.opt_Argument() ) + return this->te.args.at(ae->idx).clone(); return clone_lval(se); ), (Constant, return clone_constant(se); ) @@ -995,8 +1001,8 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) { TU_MATCHA( (src), (se), (Use, - if( se.is_Argument() ) - if( const auto* e = this->te.args.at(se.as_Argument().idx).opt_Constant() ) + if( const auto* ae = se.opt_Argument() ) + if( const auto* e = this->te.args.at(ae->idx).opt_Constant() ) return e->clone(); return ::MIR::RValue( this->clone_lval(se) ); ), @@ -1072,13 +1078,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) TRACE_FUNCTION_F("Inline " << path); // Monomorph values and append - cloner.var_base = fcn.named_variables.size(); - for(const auto& ty : called_mir->named_variables) - fcn.named_variables.push_back( cloner.monomorph(ty) ); - cloner.tmp_base = fcn.temporaries.size(); - for(const auto& ty : called_mir->temporaries) - fcn.temporaries.push_back( cloner.monomorph(ty) ); - cloner.tmp_end = fcn.temporaries.size(); + cloner.var_base = fcn.locals.size(); + for(const auto& ty : called_mir->locals) + fcn.locals.push_back( cloner.monomorph(ty) ); + cloner.tmp_end = fcn.locals.size(); cloner.df_base = fcn.drop_flags.size(); fcn.drop_flags.insert( fcn.drop_flags.end(), called_mir->drop_flags.begin(), called_mir->drop_flags.end() ); cloner.bb_base = fcn.blocks.size(); @@ -1094,8 +1097,8 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) for(auto& val : cloner.const_assignments) { auto ty = state.get_const_type(val); - auto lv = ::MIR::LValue::make_Temporary({ static_cast<unsigned>(fcn.temporaries.size()) }); - fcn.temporaries.push_back( mv$(ty) ); + auto lv = ::MIR::LValue::make_Local( static_cast<unsigned>(fcn.locals.size()) ); + fcn.locals.push_back( mv$(ty) ); new_blocks[0].statements.insert( new_blocks[0].statements.begin(), ::MIR::Statement::make_Assign({ mv$(lv), mv$(val) }) ); } cloner.const_assignments.clear(); @@ -1120,19 +1123,19 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn) { TRACE_FUNCTION; - ::std::vector<bool> replacable( fcn.temporaries.size() ); + ::std::vector<bool> replacable( fcn.locals.size() ); // 1. Enumerate which (if any) temporaries share the same type { unsigned int n_found = 0; - for(unsigned int tmpidx = 0; tmpidx < fcn.temporaries.size(); tmpidx ++) + for(unsigned int tmpidx = 0; tmpidx < fcn.locals.size(); tmpidx ++) { if( replacable[tmpidx] ) continue ; - for(unsigned int i = tmpidx+1; i < fcn.temporaries.size(); i ++ ) + for(unsigned int i = tmpidx+1; i < fcn.locals.size(); i ++ ) { if( replacable[i] ) continue ; - if( fcn.temporaries[i] == fcn.temporaries[tmpidx] ) + if( fcn.locals[i] == fcn.locals[tmpidx] ) { replacable[i] = true; replacable[tmpidx] = true; @@ -1145,34 +1148,33 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f } auto lifetimes = MIR_Helper_GetLifetimes(state, fcn, /*dump_debug=*/true); - //::std::vector<::MIR::ValueLifetime> var_lifetimes = mv$(lifetimes.m_variables); - ::std::vector<::MIR::ValueLifetime> tmp_lifetimes = mv$(lifetimes.m_temporaries); + ::std::vector<::MIR::ValueLifetime> slot_lifetimes = mv$(lifetimes.m_slots); // 2. Unify variables of the same type with distinct non-overlapping lifetimes ::std::map<unsigned int, unsigned int> replacements; - ::std::vector<bool> visited( fcn.temporaries.size() ); + ::std::vector<bool> visited( fcn.locals.size() ); bool replacement_needed = false; - for(unsigned int tmpidx = 0; tmpidx < fcn.temporaries.size(); tmpidx ++) + for(unsigned int local_idx = 0; local_idx < fcn.locals.size(); local_idx ++) { - if( ! replacable[tmpidx] ) continue ; - if( visited[tmpidx] ) continue ; - if( ! tmp_lifetimes[tmpidx].is_used() ) continue ; - visited[tmpidx] = true; + if( ! replacable[local_idx] ) continue ; + if( visited[local_idx] ) continue ; + if( ! slot_lifetimes[local_idx].is_used() ) continue ; + visited[local_idx] = true; - for(unsigned int i = tmpidx+1; i < fcn.temporaries.size(); i ++) + for(unsigned int i = local_idx+1; i < fcn.locals.size(); i ++) { if( !replacable[i] ) continue ; - if( fcn.temporaries[i] != fcn.temporaries[tmpidx] ) + if( fcn.locals[i] != fcn.locals[local_idx] ) continue ; - if( ! tmp_lifetimes[i].is_used() ) + if( ! slot_lifetimes[i].is_used() ) continue ; // Variables are of the same type, check if they overlap - if( tmp_lifetimes[tmpidx].overlaps( tmp_lifetimes[i] ) ) + if( slot_lifetimes[local_idx].overlaps( slot_lifetimes[i] ) ) continue ; // They don't overlap, unify - tmp_lifetimes[tmpidx].unify( tmp_lifetimes[i] ); - replacements[i] = tmpidx; + slot_lifetimes[local_idx].unify( slot_lifetimes[i] ); + replacements[i] = local_idx; replacement_needed = true; visited[i] = true; } @@ -1182,12 +1184,12 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f { DEBUG("Replacing temporaries using {" << replacements << "}"); visit_mir_lvalues_mut(state, fcn, [&](auto& lv, auto ) { - if( auto* ve = lv.opt_Temporary() ) { - auto it = replacements.find(ve->idx); + if( auto* ve = lv.opt_Local() ) { + auto it = replacements.find(*ve); if( it != replacements.end() ) { - MIR_DEBUG(state, lv << " => Temporary(" << it->second << ")"); - ve->idx = it->second; + MIR_DEBUG(state, lv << " => Local(" << it->second << ")"); + *ve = it->second; return true; } } @@ -1249,9 +1251,7 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) return false; ), (ScopeEnd, - if( ae.vars != be.vars ) - return false; - if( ae.tmps == be.tmps ) + if( ae.slots != be.slots ) return false; ) ) @@ -1721,7 +1721,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) // - Locate `temp = SOME_CONST` and record value if( const auto* e = stmt.opt_Assign() ) { - if( e->dst.is_Temporary() || e->dst.is_Variable() ) + if( e->dst.is_Local() ) { if( const auto* ce = e->src.opt_Constant() ) { @@ -1743,9 +1743,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) const auto& te = bb.terminator.as_If(); // Restrict condition to being a temporary/variable - if( te.cond.is_Temporary() ) - ; - else if( te.cond.is_Argument() ) + if( te.cond.is_Local() ) ; else continue; @@ -1813,24 +1811,16 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F unsigned int borrow = 0; }; struct { - ::std::vector<ValUse> var_uses; - ::std::vector<ValUse> tmp_uses; + ::std::vector<ValUse> local_uses; void use_lvalue(const ::MIR::LValue& lv, ValUsage ut) { TU_MATCHA( (lv), (e), - (Variable, - auto& vu = var_uses[e]; - switch(ut) - { - case ValUsage::Read: vu.read += 1; break; - case ValUsage::Write: vu.write += 1; break; - case ValUsage::Borrow: vu.borrow += 1; break; - } + (Return, ), (Argument, ), - (Temporary, - auto& vu = tmp_uses[e.idx]; + (Local, + auto& vu = local_uses[e]; switch(ut) { case ValUsage::Read: vu.read += 1; break; @@ -1840,8 +1830,6 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F ), (Static, ), - (Return, - ), (Field, use_lvalue(*e.val, ut); ), @@ -1858,8 +1846,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F ) } } val_uses = { - ::std::vector<ValUse>(fcn.named_variables.size()), - ::std::vector<ValUse>(fcn.temporaries.size()) + ::std::vector<ValUse>(fcn.locals.size()) }; visit_mir_lvalues(state, fcn, [&](const auto& lv, auto ut){ val_uses.use_lvalue(lv, ut); return false; }); @@ -1886,19 +1873,10 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F continue ; const auto& e = stmt.as_Assign(); // > Of a temporary from with a RValue::Use - if( const auto* de = e.dst.opt_Temporary() ) + if( const auto* de = e.dst.opt_Local() ) { - const auto& vu = val_uses.tmp_uses[de->idx]; - DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write); - // TODO: Allow write many? - // > Where the temporary is written once and read once - if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) ) - continue ; - } - else if( const auto* de = e.dst.opt_Variable() ) - { - const auto& vu = val_uses.var_uses[*de]; - DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write); + const auto& vu = val_uses.local_uses[*de]; + DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write << " B:" << vu.borrow); // TODO: Allow write many? // > Where the variable is written once and read once if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) ) @@ -1915,7 +1893,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F const auto* srcp = &e.src.as_Use(); while( srcp->is_Field() ) srcp = &*srcp->as_Field().val; - if( !( srcp->is_Temporary() || srcp->is_Variable() || srcp->is_Argument() ) ) + if( !srcp->is_Local() ) continue ; if( replacements.find(*srcp) != replacements.end() ) @@ -2030,6 +2008,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F } // for(stmt : block.statements) } + // Apply replacements within replacements for(;;) { unsigned int inner_replaced_count = 0; @@ -2131,9 +2110,9 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F if( it->as_Assign().src.tag() == ::MIR::RValue::TAGDEAD ) continue ; auto& to_replace_lval = it->as_Assign().dst; - if( const auto* e = to_replace_lval.opt_Temporary() ) { - const auto& vu = val_uses.tmp_uses[e->idx]; - if( !( vu.read == 1 && vu.write == 1 ) ) + if( const auto* e = to_replace_lval.opt_Local() ) { + const auto& vu = val_uses.local_uses[*e]; + if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) ) continue ; } else { @@ -2201,10 +2180,9 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F { // TODO: What if the destination located here is a 1:1 and its usage is listed to be replaced by the return value. auto& e = block.terminator.as_Call(); - // TODO: Support variables too? - if( !e.ret_val.is_Temporary() ) + if( !e.ret_val.is_Local() ) continue ; - const auto& vu = val_uses.tmp_uses[e.ret_val.as_Temporary().idx]; + const auto& vu = val_uses.local_uses[e.ret_val.as_Local()]; if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) ) continue ; @@ -2261,19 +2239,12 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de), ( ), - (Variable, - const auto& vu = val_uses.var_uses[de]; + (Local, + const auto& vu = val_uses.local_uses[de]; if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) { DEBUG(se->dst << " only written, removing write"); it = block.statements.erase(it)-1; } - ), - (Temporary, - const auto& vu = val_uses.tmp_uses[de.idx]; - if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) { - DEBUG(se->dst << " only written, removing write with " << se->src); - it = block.statements.erase(it)-1; - } ) ) } @@ -2355,8 +2326,7 @@ bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Funct // -------------------------------------------------------------------- bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn) { - ::std::vector<bool> used_temps( fcn.temporaries.size() ); - ::std::vector<bool> used_vars( fcn.named_variables.size() ); + ::std::vector<bool> used_locals( fcn.locals.size() ); ::std::vector<bool> used_dfs( fcn.drop_flags.size() ); ::std::vector<bool> visited( fcn.blocks.size() ); @@ -2364,10 +2334,8 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn visited[bb] = true; auto assigned_lval = [&](const ::MIR::LValue& lv) { - if(const auto* le = lv.opt_Temporary() ) - used_temps[le->idx] = true; - if(const auto* le = lv.opt_Variable() ) - used_vars[*le] = true; + if(const auto* le = lv.opt_Local() ) + used_locals[*le] = true; }; for(const auto& stmt : block.statements) @@ -2404,42 +2372,28 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn { block_rewrite_table.push_back( visited[i] ? j ++ : ~0u ); } - ::std::vector<unsigned int> temp_rewrite_table; - unsigned int n_temp = fcn.temporaries.size(); - for(unsigned int i = 0, j = 0; i < n_temp; i ++) + ::std::vector<unsigned int> local_rewrite_table; + unsigned int n_locals = fcn.locals.size(); + for(unsigned int i = 0, j = 0; i < n_locals; i ++) { - if( !used_temps[i] ) + if( !used_locals[i] ) { - fcn.temporaries.erase(fcn.temporaries.begin() + j); + fcn.locals.erase(fcn.locals.begin() + j); } else { - DEBUG("tmp$" << i << " => tmp$" << j); + DEBUG("_" << i << " => _" << j); } - temp_rewrite_table.push_back( used_temps[i] ? j ++ : ~0u ); + local_rewrite_table.push_back( used_locals[i] ? j ++ : ~0u ); } - DEBUG("Deleted Temporaries:" << FMT_CB(ss, - for(auto run : runs(used_temps)) - if( !used_temps[run.first] ) + DEBUG("Deleted Locals:" << FMT_CB(ss, + for(auto run : runs(used_locals)) + if( !used_locals[run.first] ) { ss << " " << run.first; if(run.second != run.first) ss << "-" << run.second; } )); - ::std::vector<unsigned int> var_rewrite_table; - unsigned int n_var = fcn.named_variables.size(); - for(unsigned int i = 0, j = 0; i < n_var; i ++) - { - if( !used_vars[i] ) - { - DEBUG("GC Variable(" << i << ")"); - fcn.named_variables.erase(fcn.named_variables.begin() + j); - } - else { - DEBUG("var$" << i << " => var$" << j); - } - var_rewrite_table.push_back( used_vars[i] ? j ++ : ~0u ); - } ::std::vector<unsigned int> df_rewrite_table; unsigned int n_df = fcn.drop_flags.size(); for(unsigned int i = 0, j = 0; i < n_df; i ++) @@ -2464,17 +2418,11 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn else { auto lvalue_cb = [&](auto& lv, auto ) { - if(auto* e = lv.opt_Temporary() ) { - MIR_ASSERT(state, e->idx < temp_rewrite_table.size(), "Temporary out of range - " << lv); - // If the table entry for this temporary is !0, it wasn't marked as used - MIR_ASSERT(state, temp_rewrite_table.at(e->idx) != ~0u, "LValue " << lv << " incorrectly marked as unused"); - e->idx = temp_rewrite_table.at(e->idx); - } - if(auto* e = lv.opt_Variable() ) { - MIR_ASSERT(state, *e < var_rewrite_table.size(), "Variable out of range - " << lv); + if(auto* e = lv.opt_Local() ) { + MIR_ASSERT(state, *e < local_rewrite_table.size(), "Variable out of range - " << lv); // If the table entry for this variable is !0, it wasn't marked as used - MIR_ASSERT(state, var_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused"); - *e = var_rewrite_table.at(*e); + MIR_ASSERT(state, local_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused"); + *e = local_rewrite_table.at(*e); } return false; }; @@ -2520,28 +2468,18 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn } else if( auto* se = stmt.opt_ScopeEnd() ) { - for(auto it = se->vars.begin(); it != se->vars.end(); ) - { - if( var_rewrite_table.at(*it) == ~0u ) { - it = se->vars.erase(it); - } - else { - *it = var_rewrite_table.at(*it); - ++ it; - } - } - for(auto it = se->tmps.begin(); it != se->tmps.end(); ) + for(auto it = se->slots.begin(); it != se->slots.end(); ) { - if( temp_rewrite_table.at(*it) == ~0u ) { - it = se->tmps.erase(it); + if( local_rewrite_table.at(*it) == ~0u ) { + it = se->slots.erase(it); } else { - *it = temp_rewrite_table.at(*it); + *it = local_rewrite_table.at(*it); ++ it; } } - if( se->vars.empty() && se->tmps.empty() ) { + if( se->slots.empty() ) { DEBUG(state << "Delete ScopeEnd (now empty)"); to_remove_statements[stmt_idx] = true; continue ; diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 878a55d4..2841db10 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1303,16 +1303,10 @@ namespace { m_of << "{\n"; // Variables m_of << "\t"; emit_ctype(ret_type, FMT_CB(ss, ss << "rv";)); m_of << ";\n"; - for(unsigned int i = 0; i < code->named_variables.size(); i ++) { - DEBUG("var" << i << " : " << code->named_variables[i]); - m_of << "\t"; emit_ctype(code->named_variables[i], FMT_CB(ss, ss << "var" << i;)); m_of << ";"; - m_of << "\t// " << code->named_variables[i]; - m_of << "\n"; - } - for(unsigned int i = 0; i < code->temporaries.size(); i ++) { - DEBUG("tmp" << i << " : " << code->temporaries[i]); - m_of << "\t"; emit_ctype(code->temporaries[i], FMT_CB(ss, ss << " tmp" << i;)); m_of << ";"; - m_of << "\t// " << code->temporaries[i]; + for(unsigned int i = 0; i < code->locals.size(); i ++) { + DEBUG("var" << i << " : " << code->locals[i]); + m_of << "\t"; emit_ctype(code->locals[i], FMT_CB(ss, ss << "var" << i;)); m_of << ";"; + m_of << "\t// " << code->locals[i]; m_of << "\n"; } for(unsigned int i = 0; i < code->drop_flags.size(); i ++) { @@ -2612,7 +2606,7 @@ namespace { // Call destructor on all entries m_of << "for(unsigned i = 0; i < "; emit_lvalue(*lvp->as_Deref().val); m_of << ".META; i++) {"; m_of << "\t\t"; - emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Temporary({~0u})) }), *te.inner, false); + emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false); m_of << "\n\t}"; ) ) @@ -2814,20 +2808,17 @@ namespace { void emit_lvalue(const ::MIR::LValue& val) { TU_MATCHA( (val), (e), - (Variable, - m_of << "var" << e; - ), - (Temporary, - if( e.idx == ~0u ) - m_of << "i"; - else - m_of << "tmp" << e.idx; + (Return, + m_of << "rv"; ), (Argument, m_of << "arg" << e.idx; ), - (Return, - m_of << "rv"; + (Local, + if( e == ~0u ) + m_of << "i"; + else + m_of << "var" << e; ), (Static, m_of << Trans_Mangle(e); diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 02116d18..fb577959 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -623,9 +623,7 @@ void Trans_Enumerate_Types(EnumState& state) if( fcn.m_code.m_mir ) { const auto& mir = *fcn.m_code.m_mir; - for(const auto& ty : mir.named_variables) - tv.visit_type(monomorph(ty)); - for(const auto& ty : mir.temporaries) + for(const auto& ty : mir.locals) tv.visit_type(monomorph(ty)); // TODO: Find all LValue::Deref instances and get the result type @@ -646,19 +644,19 @@ void Trans_Enumerate_Types(EnumState& state) }; // Recurse, if Deref get the type and add it to the visitor TU_MATCHA( (lv), (e), - (Variable, + (Return, if( tmp_ty_ptr ) { - return monomorph_outer(fcn.m_code.m_mir->named_variables[e]); + TODO(Span(), "Get return type for MIR type enumeration"); } ), - (Temporary, + (Argument, if( tmp_ty_ptr ) { - return monomorph_outer(fcn.m_code.m_mir->temporaries[e.idx]); + return monomorph_outer(fcn.m_args[e.idx].second); } ), - (Argument, + (Local, if( tmp_ty_ptr ) { - return monomorph_outer(fcn.m_args[e.idx].second); + return monomorph_outer(fcn.m_code.m_mir->locals[e]); } ), (Static, @@ -682,11 +680,6 @@ void Trans_Enumerate_Types(EnumState& state) ) } ), - (Return, - if( tmp_ty_ptr ) { - TODO(Span(), "Get return type for MIR type enumeration"); - } - ), (Field, const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr); if( tmp_ty_ptr ) @@ -1344,17 +1337,15 @@ 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) { TU_MATCHA( (lv), (e), - (Variable, - ), - (Temporary, + (Return, ), (Argument, ), + (Local, + ), (Static, Trans_Enumerate_FillFrom_Path(state, e, pp); ), - (Return, - ), (Field, Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); ), diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index 3ac2ee09..f708060d 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -13,10 +13,9 @@ namespace { ::MIR::LValue monomorph_LValue(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::LValue& tpl) { TU_MATCHA( (tpl), (e), - (Variable, return e; ), - (Temporary, return e; ), - (Argument, return e; ), (Return, return e; ), + (Argument, return e; ), + (Local, return e; ), (Static, return params.monomorph(resolve, e); ), @@ -120,17 +119,11 @@ namespace { ::MIR::Function output; // 1. Monomorphise locals and temporaries - output.named_variables.reserve( tpl->named_variables.size() ); - for(const auto& var : tpl->named_variables) - { - DEBUG("- var" << output.named_variables.size()); - output.named_variables.push_back( params.monomorph(resolve, var) ); - } - output.temporaries.reserve( tpl->temporaries.size() ); - for(const auto& ty : tpl->temporaries) + output.locals.reserve( tpl->locals.size() ); + for(const auto& var : tpl->locals) { - DEBUG("- tmp" << output.temporaries.size()); - output.temporaries.push_back( params.monomorph(resolve, ty) ); + DEBUG("- _" << output.locals.size()); + output.locals.push_back( params.monomorph(resolve, var) ); } output.drop_flags = tpl->drop_flags; |