summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2017-01-21 18:07:25 +0800
committerJohn Hodge <tpg@mutabah.net>2017-01-21 18:07:25 +0800
commita3d4dd65e0029f42c8cbc1869bb4d4357852cd81 (patch)
treeb3a2c6d23f20f9ec97da94fc2494b693e10f06d7
parent41c852259d814cccb9d172d365c9cfddbc44bdfe (diff)
downloadmrust-a3d4dd65e0029f42c8cbc1869bb4d4357852cd81.tar.gz
MIR Gen - Fix drop generation
-rw-r--r--src/mir/from_hir.hpp10
-rw-r--r--src/mir/mir_builder.cpp141
2 files changed, 105 insertions, 46 deletions
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp
index c33ba274..0dfc9e50 100644
--- a/src/mir/from_hir.hpp
+++ b/src/mir/from_hir.hpp
@@ -91,9 +91,11 @@ TAGGED_UNION(ScopeType, Variables,
::std::vector<SplitArm> arms;
}),
(Loop, struct {
- ::std::set<unsigned int> changed_vars;
- ::std::set<unsigned int> changed_tmps;
- ::std::vector<SplitArm> exit_states;
+ // 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;
+ bool exit_state_valid;
+ SplitEnd exit_state;
})
);
@@ -225,6 +227,8 @@ private:
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);
+ void terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_loop);
+
void drop_value_from_state(const Span& sp, const VarState& vs, ::MIR::LValue lv);
void drop_scope_values(const ScopeDef& sd);
void complete_scope(ScopeDef& sd);
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index 62f8e9c3..197d2518 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -625,6 +625,7 @@ void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cl
complete_scope(scope_def);
}
+
void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, bool loop_exit/*=false*/)
{
TRACE_FUNCTION_F("EARLY scope " << scope.idx);
@@ -647,17 +648,7 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope,
// If this is exiting a loop, save the state so the variable state after the loop is known.
if( loop_exit && scope_def.data.is_Loop() )
{
- auto& e = scope_def.data.as_Loop();
- SplitArm sa;
- for(const auto& i : e.changed_vars)
- {
- sa.var_states.insert( ::std::make_pair(i, get_variable_state(sp, i).clone()) );
- }
- for(const auto& i : e.changed_tmps)
- {
- sa.tmp_states.insert( ::std::make_pair(i, get_temp_state(sp, i).clone()) );
- }
- e.exit_states.push_back( mv$(sa) );
+ terminate_loop_early(sp, scope_def.data.as_Loop());
}
}
@@ -900,6 +891,48 @@ namespace
}
}
+void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_loop)
+{
+ if( sd_loop.exit_state_valid )
+ {
+ // 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)
+ {
+ 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() ));
+ }
+ 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));
+ }
+ }
+ else
+ {
+ // Obtain states of changed variables/temporaries
+ for(const auto& ent : sd_loop.changed_vars)
+ {
+ 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)
+ {
+ 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_valid = true;
+ }
+}
+
void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable)
{
ASSERT_BUG(sp, handle.idx < m_scopes.size(), "");
@@ -955,6 +988,10 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r
merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), out_state, src_state);
}
}
+ else
+ {
+ DEBUG("Unreachable, not merging");
+ }
}
else
{
@@ -986,14 +1023,17 @@ void MirBuilder::end_split_arm_early(const Span& sp)
complete_scope(scope_def);
}
- if( !m_scope_stack.empty() && m_scopes.at( m_scope_stack.back() ).data.is_Split() )
+ if( !m_scope_stack.empty() )
{
- DEBUG("Early terminate split scope " << m_scope_stack.back());
- auto& sd = m_scopes[ m_scope_stack.back() ];
- auto& sd_split = sd.data.as_Split();
- sd_split.arms.back().has_early_terminated = true;
+ if( m_scopes.at( m_scope_stack.back() ).data.is_Split() )
+ {
+ DEBUG("Early terminate split scope " << m_scope_stack.back());
+ auto& sd = m_scopes[ m_scope_stack.back() ];
+ auto& sd_split = sd.data.as_Split();
+ sd_split.arms.back().has_early_terminated = true;
- // TODO: Create drop flags if required?
+ // TODO: Create drop flags if required?
+ }
}
}
void MirBuilder::complete_scope(ScopeDef& sd)
@@ -1013,16 +1053,40 @@ void MirBuilder::complete_scope(ScopeDef& sd)
(Split,
)
)
+
+ struct H {
+ static void apply_end_state(const Span& sp, MirBuilder& builder, SplitEnd& end_state)
+ {
+ for(auto& ent : end_state.var_states)
+ {
+ auto& vs = builder.get_variable_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);
+ vs = ::std::move(ent.second);
+ }
+ }
+ }
+ };
+
// No macro for better debug output.
if( sd.data.is_Loop() )
{
- #if 0
auto& e = sd.data.as_Loop();
- TRACE_FUNCTION_F("Loop - " << e.exit_states.size() << " breaks");
-
- // Merge all exit states and apply to output
- H::apply_split_arms(*this, sd.span, e.exit_states);
- #endif
+ TRACE_FUNCTION_F("Loop");
+ if( e.exit_state_valid )
+ {
+ H::apply_end_state(sd.span, *this, e.exit_state);
+ }
}
else if( sd.data.is_Split() )
{
@@ -1030,24 +1094,7 @@ void MirBuilder::complete_scope(ScopeDef& sd)
TRACE_FUNCTION_F("Split - " << (e.arms.size() - 1) << " arms");
ASSERT_BUG(sd.span, e.end_state_valid, "");
- for(auto& ent : e.end_state.var_states)
- {
- auto& vs = get_variable_state_mut(sd.span, ent.first);
- if( vs != ent.second )
- {
- DEBUG(::MIR::LValue::make_Variable(ent.first) << " " << vs << " => " << ent.second);
- vs = ::std::move(ent.second);
- }
- }
- for(auto& ent : e.end_state.tmp_states)
- {
- auto& vs = get_temp_state_mut(sd.span, ent.first);
- if( vs != ent.second )
- {
- DEBUG(::MIR::LValue::make_Temporary({ent.first}) << " " << vs << " => " << ent.second);
- vs = ::std::move(ent.second);
- }
- }
+ H::apply_end_state(sd.span, *this, e.end_state);
}
}
@@ -1291,7 +1338,11 @@ VarState& MirBuilder::get_variable_state_mut(const Span& sp, unsigned int idx)
else if( scope_def.data.is_Loop() )
{
auto& e = scope_def.data.as_Loop();
- e.changed_vars.insert( idx );
+ if( e.changed_vars.count(idx) == 0 )
+ {
+ auto state = e.exit_state_valid ? get_variable_state(sp, idx).clone() : VarState::make_Valid({});
+ e.changed_vars.insert(::std::make_pair( idx, mv$(state) ));
+ }
}
else
{
@@ -1357,7 +1408,11 @@ VarState& MirBuilder::get_temp_state_mut(const Span& sp, unsigned int idx)
else if( scope_def.data.is_Loop() )
{
auto& e = scope_def.data.as_Loop();
- e.changed_tmps.insert( idx );
+ if( e.changed_tmps.count(idx) == 0 )
+ {
+ auto state = e.exit_state_valid ? get_temp_state(sp, idx).clone() : VarState::make_Valid({});
+ e.changed_tmps.insert(::std::make_pair( idx, mv$(state) ));
+ }
}
else
{