summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mir/from_hir.cpp11
-rw-r--r--src/mir/from_hir.hpp15
-rw-r--r--src/mir/from_hir_match.cpp25
-rw-r--r--src/mir/mir_builder.cpp225
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) );
}