diff options
author | John Hodge <tpg@ucc.asn.au> | 2017-07-02 10:06:59 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2017-07-02 10:06:59 +0800 |
commit | 115c56651d5cb352162b45269c3e09832c2fff40 (patch) | |
tree | 9b819272df0116948da197891ec567d0de635d0e | |
parent | a6e215ef782b7cc7351989697d9ba189f76b119b (diff) | |
download | mrust-115c56651d5cb352162b45269c3e09832c2fff40.tar.gz |
MIR Gen - Track states for arguments (and directly use arguments where possible)
-rw-r--r-- | src/mir/from_hir.cpp | 11 | ||||
-rw-r--r-- | src/mir/from_hir.hpp | 15 | ||||
-rw-r--r-- | src/mir/from_hir_match.cpp | 25 | ||||
-rw-r--r-- | src/mir/mir_builder.cpp | 225 |
4 files changed, 181 insertions, 95 deletions
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 149d53ea..bc9b04a7 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2252,8 +2252,15 @@ namespace { unsigned int i = 0; for( const auto& arg : args ) { - ev.define_vars_from(ptr->span(), arg.first); - ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + const auto& pat = arg.first; + if( pat.m_binding.is_valid() && pat.m_binding.m_type == ::HIR::PatternBinding::Type::Move ) + { + } + else + { + ev.define_vars_from(ptr->span(), arg.first); + ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + } i ++; } diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index f8834d98..11a18a6d 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -80,9 +80,11 @@ struct SplitArm { bool has_early_terminated = false; bool always_early_terminated = false; // Populated on completion ::std::map<unsigned int, VarState> states; + ::std::map<unsigned int, VarState> arg_states; }; struct SplitEnd { ::std::map<unsigned int, VarState> states; + ::std::map<unsigned int, VarState> arg_states; }; TAGGED_UNION(ScopeType, Owning, @@ -98,6 +100,7 @@ TAGGED_UNION(ScopeType, Owning, (Loop, struct { // NOTE: This contains the original state for variables changed after `exit_state_valid` is true ::std::map<unsigned int,VarState> changed_slots; + ::std::map<unsigned int,VarState> changed_args; bool exit_state_valid; SplitEnd exit_state; }) @@ -176,7 +179,7 @@ public: // - Values ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { // DIASBLED: State tracking doesn't support arguments in loops/splits -#if 0 +#if 1 auto it = m_var_arg_mappings.find(idx); if(it != m_var_arg_mappings.end()) return ::MIR::LValue::make_Argument({ it->second }); @@ -262,7 +265,7 @@ public: /// Terminates a scope early (e.g. via return/break/...) void terminate_scope_early(const Span& sp, const ScopeHandle& , bool loop_exit=false); /// Marks the end of a split arm (end match arm, if body, ...) - void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable); + void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable, bool early=false); /// Terminates the current split early (TODO: What does this mean?) void end_split_arm_early(const Span& sp); @@ -275,8 +278,12 @@ 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, unsigned int idx, unsigned int skip_count=0) const; - VarState& get_slot_state_mut(const Span& sp, unsigned int idx); + enum class SlotType { + Local, // Local ~0u is return + Argument + }; + const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const; + VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type); const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0); VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 6e00e2e4..cbb39b34 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -82,8 +82,7 @@ struct ArmCode { ::MIR::BasicBlockId code = 0; bool has_condition = false; ::MIR::BasicBlockId cond_start; - ::MIR::BasicBlockId cond_end; - ::MIR::LValue cond_lval; + ::MIR::BasicBlockId cond_false; ::std::vector< ::MIR::BasicBlockId> destructures; // NOTE: Incomplete mutable ::MIR::BasicBlockId cond_fail_tgt = 0; @@ -355,9 +354,12 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod } builder.terminate_scope( sp, mv$(pat_scope) ); + ac.code = builder.new_bb_unlinked(); + // Condition // NOTE: Lack of drop due to early exit from this arm isn't an issue. All captures must be Copy // - The above is rustc E0008 "cannot bind by-move into a pattern guard" + // TODO: Create a special wrapping scope for the conditions that forces any moves to use a drop flag if(arm.m_cond) { if( H::is_pattern_move(sp, builder, arm.m_patterns[0]) ) @@ -372,9 +374,15 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod auto tmp_scope = builder.new_scope_temp(arm.m_cond->span()); conv.visit_node_ptr( arm.m_cond ); - ac.cond_lval = builder.get_result_in_if_cond(arm.m_cond->span()); + auto cond_lval = builder.get_result_in_if_cond(arm.m_cond->span()); builder.terminate_scope( arm.m_code->span(), mv$(tmp_scope) ); - ac.cond_end = builder.pause_cur_block(); + ac.cond_false = builder.new_bb_unlinked(); + builder.end_block(::MIR::Terminator::make_If({ mv$(cond_lval), ac.code, ac.cond_false })); + // TODO: Emit the `if` (to new blocks) and insert an early termination of the this split arm + + builder.set_cur_block(ac.cond_false); + builder.end_split_arm(arm.m_cond->span(), match_scope, true, true); + builder.pause_cur_block(); // NOTE: Paused so that later code (which knows what the false branch will be) can end it correctly @@ -390,7 +398,6 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod // Code DEBUG("-- Body Code"); - ac.code = builder.new_bb_unlinked(); auto tmp_scope = builder.new_scope_temp(arm.m_code->span()); builder.set_cur_block( ac.code ); conv.visit_node_ptr( arm.m_code ); @@ -1923,8 +1930,8 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR:: } if( arm_code.has_condition ) { - builder.set_cur_block( arm_code.cond_end ); - builder.end_block( ::MIR::Terminator::make_If({ mv$(arm_code.cond_lval), arm_code.code, next_arm_bb }) ); + builder.set_cur_block( arm_code.cond_false ); + builder.end_block( ::MIR::Terminator::make_Goto(next_arm_bb) ); } builder.set_cur_block( next_arm_bb ); } @@ -2625,8 +2632,8 @@ void MatchGenGrouped::gen_for_slice(t_rules_subset arm_rules, size_t ofs, ::MIR: { ac.cond_fail_tgt = next; - m_builder.set_cur_block( ac.cond_end ); - m_builder.end_block( ::MIR::Terminator::make_If({ ac.cond_lval.clone(), ac.code, next }) ); + m_builder.set_cur_block( ac.cond_false ); + m_builder.end_block( ::MIR::Terminator::make_Goto(next) ); } } diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 0d5641ff..54269144 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -400,8 +400,11 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) // Don't drop. // No state tracking for the return value ), + (Argument, + state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument); + ), (Local, - state_p = &get_slot_state_mut(sp, e); + state_p = &get_slot_state_mut(sp, e, SlotType::Local); ) ) @@ -576,7 +579,7 @@ void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, con // TODO: This should update the outer state to unset. auto& arm = sd_split->arms.back(); - arm.states.insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )); + arm.states.insert(::std::make_pair( idx, get_slot_state(sp, idx, SlotType::Local).clone() )); m_slot_states.at(idx) = VarState(InvalidType::Uninit); } else @@ -948,7 +951,8 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, // Ensure that all arguments are dropped if they were not moved for(size_t i = 0; i < m_arg_states.size(); i ++) { - this->drop_value_from_state(sp, m_arg_states[i], ::MIR::LValue::make_Argument({ static_cast<unsigned>(i) })); + const auto& state = get_slot_state(sp, i, SlotType::Argument); + this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast<unsigned>(i) })); } } } @@ -983,6 +987,9 @@ namespace old_state = VarState::make_Optional( new_flag ); #else // TODO: Rewrite history. I.e. visit all previous branches and set this drop flag to `false` in all of them + for(auto pos : other_arms) { + builder.push_df_set_at(pos, flag_idx, false); + } TODO(sp, "Drop flag default not false when going Invalid->Optional"); #endif } @@ -1007,6 +1014,10 @@ namespace builder.push_stmt_set_dropflag_other(sp, new_flag, nse.outer_flag); builder.push_stmt_set_dropflag_default(sp, nse.outer_flag); ose.outer_flag = new_flag; +#if 0 + for(auto pos : other_arms) { + } +#endif } } else @@ -1354,30 +1365,39 @@ 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_slots) - { - auto idx = ent.first; - if( sd_loop.exit_state.states.count(idx) == 0 ) { - sd_loop.exit_state.states.insert(::std::make_pair( idx, ent.second.clone() )); + auto merge_list = [sp,this](const auto& changed, auto& exit_states, ::std::function<::MIR::LValue(unsigned)> val_cb, auto type) { + for(const auto& ent : changed) + { + auto idx = ent.first; + auto it = exit_states.find(idx); + if( it == exit_states.end() ) { + it = exit_states.insert(::std::make_pair( idx, ent.second.clone() )).first; + } + auto& old_state = it->second; + merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type)); } - 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)); - } + }; + merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local); + merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument); } else { + auto init_list = [sp,this](const auto& changed, auto& exit_states, auto type) { + for(const auto& ent : changed) + { + DEBUG("Slot(" << ent.first << ") = " << ent.second); + auto idx = ent.first; + exit_states.insert(::std::make_pair( idx, get_slot_state(sp, idx, type).clone() )); + } + }; // Obtain states of changed variables/temporaries - for(const auto& ent : sd_loop.changed_slots) - { - DEBUG("Slot(" << ent.first << ") = " << ent.second); - auto idx = ent.first; - sd_loop.exit_state.states.insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )); - } + init_list(sd_loop.changed_slots, sd_loop.exit_state.states, SlotType::Local); + init_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, SlotType::Argument); sd_loop.exit_state_valid = true; } } -void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable) +void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable, bool early/*=false*/) { ASSERT_BUG(sp, handle.idx < m_scopes.size(), "Handle passed to end_split_arm is invalid"); auto& sd = m_scopes.at( handle.idx ); @@ -1396,25 +1416,29 @@ 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.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() )); + auto merge_list = [sp,this](const auto& states, auto& end_states, auto type) { + // Insert copies of the parent state + for(const auto& ent : states) { + if( end_states.count(ent.first) == 0 ) { + end_states.insert(::std::make_pair( ent.first, get_slot_state(sp, ent.first, type, 1).clone() )); + } } - } - - // Merge state - for(auto& ent : sd_split.end_state.states) - { - auto idx = ent.first; - auto& out_state = ent.second; + // Merge state + for(auto& ent : end_states) + { + auto idx = ent.first; + auto& out_state = ent.second; - // Merge the states - 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 the states + auto it = states.find(idx); + const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1)); - merge_state(sp, *this, ::MIR::LValue::make_Local(idx), out_state, src_state); - } + auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx})); + merge_state(sp, *this, mv$(lv), out_state, src_state); + } + }; + merge_list(this_arm_state.states, sd_split.end_state.states, SlotType::Local); + merge_list(this_arm_state.arg_states, sd_split.end_state.arg_states, SlotType::Argument); } else { @@ -1429,17 +1453,29 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r DEBUG("Slot(" << ent.first << ") = " << ent.second); sd_split.end_state.states.insert(::std::make_pair( ent.first, ent.second.clone() )); } + for(auto& ent : this_arm_state.arg_states) + { + DEBUG("Argument(" << ent.first << ") = " << ent.second); + sd_split.end_state.arg_states.insert(::std::make_pair( ent.first, ent.second.clone() )); + } sd_split.end_state_valid = true; } - sd_split.arms.push_back( {} ); + if( reachable ) + { + assert(m_block_active); + } + if( !early ) + { + sd_split.arms.push_back( {} ); + } } void MirBuilder::end_split_arm_early(const Span& sp) { TRACE_FUNCTION_F(""); size_t i = m_scope_stack.size(); - // Terminate all scopes until a split is found. - while( i -- && ! (m_scopes.at(m_scope_stack[i]).data.is_Split() || m_scopes.at(m_scope_stack[i]).data.is_Loop()) ) + // Terminate every sequence of owning scopes + while( i -- && m_scopes.at(m_scope_stack[i]).data.is_Owning() ) { auto& scope_def = m_scopes[m_scope_stack[i]]; // Fully drop the scope @@ -1459,6 +1495,7 @@ void MirBuilder::end_split_arm_early(const Span& sp) // TODO: Create drop flags if required? } + // TODO: What if this is a loop? } } void MirBuilder::complete_scope(ScopeDef& sd) @@ -1481,13 +1518,22 @@ void MirBuilder::complete_scope(ScopeDef& sd) { for(auto& ent : end_state.states) { - auto& vs = builder.get_slot_state_mut(sp, ent.first); + auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local); if( vs != ent.second ) { DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } + for(auto& ent : end_state.arg_states) + { + auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument); + if( vs != ent.second ) + { + DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second); + vs = ::std::move(ent.second); + } + } } }; @@ -1735,7 +1781,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, unsigned int idx, unsigned int skip_count/*=0*/) const +const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count/*=0*/) const { // 1. Find an applicable Split scope for( auto scope_idx : ::reverse(m_scope_stack) ) @@ -1745,15 +1791,19 @@ const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, uns ( ), (Owning, - auto it = ::std::find(e.slots.begin(), e.slots.end(), idx); - if( it != e.slots.end() ) { - break ; + if( type == SlotType::Local ) + { + 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(); - auto it = cur_arm.states.find(idx); - if( it != cur_arm.states.end() ) + const auto& list = (type == SlotType::Local ? cur_arm.states : cur_arm.arg_states); + auto it = list.find(idx); + if( it != list.end() ) { if( ! skip_count -- ) { @@ -1763,17 +1813,26 @@ const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, uns ) ) } - if( idx == ~0u ) - { - return m_return_state; - } - else + switch(type) { - ASSERT_BUG(sp, idx < m_slot_states.size(), "Slot " << idx << " out of range for state table"); - return m_slot_states.at(idx); + case SlotType::Local: + if( idx == ~0u ) + { + return m_return_state; + } + else + { + ASSERT_BUG(sp, idx < m_slot_states.size(), "Slot " << idx << " out of range for state table"); + return m_slot_states.at(idx); + } + break; + case SlotType::Argument: + ASSERT_BUG(sp, idx < m_arg_states.size(), "Argument " << idx << " out of range for state table"); + return m_arg_states.at(idx); } + throw ""; } -VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) +VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type) { VarState* ret = nullptr; for( auto scope_idx : ::reverse(m_scope_stack) ) @@ -1781,26 +1840,28 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) auto& scope_def = m_scopes.at(scope_idx); if( const auto* e = scope_def.data.opt_Owning() ) { - auto it = ::std::find(e->slots.begin(), e->slots.end(), idx); - if( it != e->slots.end() ) { - break ; + if( type == SlotType::Local ) + { + auto it = ::std::find(e->slots.begin(), e->slots.end(), idx); + if( it != e->slots.end() ) { + break ; + } } } - else if( scope_def.data.is_Split() ) + else if( auto* e = scope_def.data.opt_Split() ) { - auto& e = scope_def.data.as_Split(); - auto& cur_arm = e.arms.back(); + auto& cur_arm = e->arms.back(); if( ! ret ) { if( idx == ~0u ) { } else { - auto* states = &cur_arm.states; - auto it = states->find(idx); - if( it == states->end() ) + auto& states = (type == SlotType::Local ? cur_arm.states : cur_arm.arg_states); + auto it = states.find(idx); + if( it == states.end() ) { DEBUG("Split new (scope " << scope_idx << ")"); - it = states->insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )).first; + it = states.insert(::std::make_pair( idx, get_slot_state(sp, idx, type).clone() )).first; } else { @@ -1810,20 +1871,18 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) } } } - else if( scope_def.data.is_Loop() ) + else if( auto* e = scope_def.data.opt_Loop() ) { - auto& e = scope_def.data.as_Loop(); - ::std::map<unsigned int, VarState>* states = nullptr; if( idx == ~0u ) { } else { - states = &e.changed_slots; - if( states->count(idx) == 0 ) + auto& states = (type == SlotType::Local ? e->changed_slots : e->changed_args); + if( states.count(idx) == 0 ) { - auto state = e.exit_state_valid ? get_slot_state(sp, idx).clone() : VarState::make_Valid({}); - states->insert(::std::make_pair( idx, mv$(state) )); + auto state = e->exit_state_valid ? get_slot_state(sp, idx, type).clone() : VarState::make_Valid({}); + states.insert(::std::make_pair( idx, mv$(state) )); } } } @@ -1837,14 +1896,21 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) } else { - if( idx == ~0u ) + switch(type) { - return m_return_state; - } - else - { - return m_slot_states.at(idx); + case SlotType::Local: + if( idx == ~0u ) + { + return m_return_state; + } + else + { + return m_slot_states.at(idx); + } + case SlotType::Argument: + return m_arg_states.at(idx); } + throw ""; } } @@ -1858,14 +1924,13 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) TU_MATCHA( (lv), (e), (Return, BUG(sp, "Move of return value"); - return get_slot_state_mut(sp, ~0u); + return get_slot_state_mut(sp, ~0u, SlotType::Local); ), (Argument, - // NOTE: Only valid outside of split scopes (should only happen at the start) - return m_arg_states.at(e.idx); + return get_slot_state_mut(sp, e.idx, SlotType::Argument); ), (Local, - return get_slot_state_mut(sp, e); + return get_slot_state_mut(sp, e, SlotType::Local); ), (Static, BUG(sp, "Attempting to mutate state of a static"); @@ -2084,7 +2149,7 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd) (Owning, for(auto idx : ::reverse(e.slots)) { - const auto& vs = get_slot_state(sd.span, idx); + const auto& vs = get_slot_state(sd.span, idx, SlotType::Local); DEBUG("slot" << idx << " - " << vs); drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Local(idx) ); } |