diff options
author | John Hodge <tpg@mutabah.net> | 2016-08-21 16:51:40 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2016-08-21 16:51:40 +0800 |
commit | 18be0631d249ed11a1ee433cfb39583dcc342687 (patch) | |
tree | bdb7e97cc0b2f631d3aabe8c6880056ca2a67381 /src/mir/from_hir.cpp | |
parent | aa2ad69f635eeb57f58775ca907cac11b6cf48a4 (diff) | |
download | mrust-18be0631d249ed11a1ee433cfb39583dcc342687.tar.gz |
MIR Gen - Move `MirBuilder` class to its own file
Diffstat (limited to 'src/mir/from_hir.cpp')
-rw-r--r-- | src/mir/from_hir.cpp | 652 |
1 files changed, 0 insertions, 652 deletions
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 57e25b9c..01eda781 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -1404,658 +1404,6 @@ namespace { } // -------------------------------------------------------------------- -// MirBuilder -// -------------------------------------------------------------------- -MirBuilder::MirBuilder(::MIR::Function& output): - m_output(output), - m_block_active(false), - m_result_valid(false), - m_fcn_scope(*this, 0) -{ - set_cur_block( new_bb_unlinked() ); - m_scopes.push_back( ScopeDef {} ); - m_scope_stack.push_back( 0 ); - - m_scopes.push_back( ScopeDef { false, ScopeType::make_Temporaries({}) } ); - m_scope_stack.push_back( 1 ); -} -MirBuilder::~MirBuilder() -{ - if( has_result() ) - { - push_stmt_assign( ::MIR::LValue::make_Return({}), get_result(Span()) ); - } - if( block_active() ) - { - terminate_scope( Span(), ScopeHandle { *this, 1 } ); - terminate_scope( Span(), mv$(m_fcn_scope) ); - end_block( ::MIR::Terminator::make_Return({}) ); - } -} - -void MirBuilder::define_variable(unsigned int idx) -{ - DEBUG("DEFINE var" << idx /* << ": " << m_output.named_variables.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 ); - e.var_states.push_back( VarState::Uninit ); - return ; - ), - (Split, - BUG(Span(), "Variable " << idx << " introduced within a Split"); - ) - ) - } - BUG(Span(), "Variable " << idx << " introduced with no Variable scope"); -} -::MIR::LValue MirBuilder::new_temporary(const ::HIR::TypeRef& ty) -{ - unsigned int rv = m_output.temporaries.size(); - DEBUG("DEFINE tmp" << rv << ": " << ty); - - m_output.temporaries.push_back( ty.clone() ); - temporaries_valid.push_back(false); - - 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 ; - } - } - assert( top_scope ); - auto& tmp_scope = top_scope->data.as_Temporaries(); - tmp_scope.temporaries.push_back( rv ); - tmp_scope.states.push_back( VarState::Uninit ); - return ::MIR::LValue::make_Temporary({rv}); -} -::MIR::LValue MirBuilder::lvalue_or_temp(const ::HIR::TypeRef& ty, ::MIR::RValue val) -{ - TU_IFLET(::MIR::RValue, val, Use, e, - return mv$(e); - ) - else { - auto temp = new_temporary(ty); - push_stmt_assign( ::MIR::LValue(temp.as_Temporary()), mv$(val) ); - return temp; - } -} - -::MIR::RValue MirBuilder::get_result(const Span& sp) -{ - if(!m_result_valid) { - BUG(sp, "No value avaliable"); - } - auto rv = mv$(m_result); - m_result_valid = false; - return rv; -} - -::MIR::LValue MirBuilder::get_result_lvalue(const Span& sp) -{ - auto rv = get_result(sp); - TU_IFLET(::MIR::RValue, rv, Use, e, - return mv$(e); - ) - else { - BUG(sp, "LValue expected, got RValue"); - } -} -void MirBuilder::set_result(const Span& sp, ::MIR::RValue val) -{ - if(m_result_valid) { - BUG(sp, "Pushing a result over an existing result"); - } - m_result = mv$(val); - m_result_valid = true; -} - -void MirBuilder::push_stmt_assign(::MIR::LValue dst, ::MIR::RValue val) -{ - ASSERT_BUG(Span(), m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(Span(), dst.tag() != ::MIR::LValue::TAGDEAD, ""); - ASSERT_BUG(Span(), val.tag() != ::MIR::RValue::TAGDEAD, ""); - - TU_MATCHA( (val), (e), - (Use, - this->moved_lvalue(e); - ), - (Constant, - ), - (SizedArray, - this->moved_lvalue(e.val); - ), - (Borrow, - if( e.type == ::HIR::BorrowType::Owned ) { - TODO(Span(), "Move using &move"); - // Likely would require a marker that ensures that the memory isn't reused. - this->moved_lvalue(e.val); - } - else { - // Doesn't move - } - ), - (Cast, - this->moved_lvalue(e.val); - ), - (BinOp, - switch(e.op) - { - case ::MIR::eBinOp::EQ: - case ::MIR::eBinOp::NE: - case ::MIR::eBinOp::GT: - case ::MIR::eBinOp::GE: - case ::MIR::eBinOp::LT: - case ::MIR::eBinOp::LE: - // Takes an implicit borrow... and only works on copy, so why is this block here? - break; - default: - this->moved_lvalue(e.val_l); - this->moved_lvalue(e.val_r); - break; - } - ), - (UniOp, - this->moved_lvalue(e.val); - ), - (DstMeta, - // Doesn't move - ), - (MakeDst, - // Doesn't move ptr_val - this->moved_lvalue(e.meta_val); - ), - (Tuple, - for(const auto& val : e.vals) - this->moved_lvalue(val); - ), - (Array, - for(const auto& val : e.vals) - this->moved_lvalue(val); - ), - (Struct, - for(const auto& val : e.vals) - this->moved_lvalue(val); - ) - ) - - // Drop target if populated - TU_MATCH_DEF(::MIR::LValue, (dst), (e), - ( - ), - (Temporary, - switch(get_temp_state(e.idx)) - { - case VarState::Uninit: - break; - case VarState::Dropped: - // ERROR? - break; - case VarState::Moved: - case VarState::MaybeMoved: - // ERROR? - break; - case VarState::Init: - // ERROR. - break; - } - set_temp_state(e.idx, VarState::Init); - ), - (Return, - // Don't drop. - //m_return_valid = true; - ), - (Variable, - switch( get_variable_state(e) ) - { - case VarState::Uninit: - case VarState::Moved: - break; - case VarState::Dropped: - // TODO: Is this an error? - break; - case VarState::Init: - // 1. Must be mut - // 2. Drop - push_stmt_drop( dst.clone() ); - break; - case VarState::MaybeMoved: - // TODO: Conditional drop - break; - } - set_variable_state(e, VarState::Init); - ) - ) - m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) ); -} -void MirBuilder::push_stmt_drop(::MIR::LValue val) -{ - ASSERT_BUG(Span(), m_block_active, "Pushing statement with no active block"); - ASSERT_BUG(Span(), val.tag() != ::MIR::LValue::TAGDEAD, ""); - m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Drop({ ::MIR::eDropKind::DEEP, mv$(val) }) ); -} - -void MirBuilder::set_cur_block(unsigned int new_block) -{ - if( m_block_active ) { - BUG(Span(), "Updating block when previous is active"); - } - DEBUG("BB" << new_block << " START"); - m_current_block = new_block; - m_block_active = true; -} -void MirBuilder::end_block(::MIR::Terminator term) -{ - if( !m_block_active ) { - BUG(Span(), "Terminating block when none active"); - } - DEBUG("BB" << m_current_block << " END -> " << term); - m_output.blocks.at(m_current_block).terminator = mv$(term); - m_block_active = false; - m_current_block = 0; -} -void MirBuilder::pause_cur_block() -{ - if( !m_block_active ) { - BUG(Span(), "Pausing block when none active"); - } - DEBUG("BB" << m_current_block << " PAUSE"); - m_block_active = false; - m_current_block = 0; -} -::MIR::BasicBlockId MirBuilder::new_bb_linked() -{ - auto rv = new_bb_unlinked(); - DEBUG("BB" << rv); - end_block( ::MIR::Terminator::make_Goto(rv) ); - set_cur_block(rv); - return rv; -} -::MIR::BasicBlockId MirBuilder::new_bb_unlinked() -{ - auto rv = m_output.blocks.size(); - DEBUG("BB" << rv); - m_output.blocks.push_back({}); - return rv; -} - -ScopeHandle MirBuilder::new_scope_var(const Span& sp) -{ - unsigned int idx = m_scopes.size(); - m_scopes.push_back( {false, ScopeType::make_Variables({})} ); - m_scope_stack.push_back( idx ); - DEBUG("START (var) scope " << idx); - return ScopeHandle { *this, idx }; -} -ScopeHandle MirBuilder::new_scope_temp(const Span& sp) -{ - unsigned int idx = m_scopes.size(); - m_scopes.push_back( {false, ScopeType::make_Temporaries({})} ); - m_scope_stack.push_back( idx ); - DEBUG("START (temp) scope " << idx); - return ScopeHandle { *this, idx }; -} -ScopeHandle MirBuilder::new_scope_split(const Span& sp) -{ - unsigned int idx = m_scopes.size(); - m_scopes.push_back( {false, ScopeType::make_Split({})} ); - m_scopes.back().data.as_Split().arms.push_back( {} ); - m_scope_stack.push_back( idx ); - DEBUG("START (split) scope " << idx); - return ScopeHandle { *this, idx }; -} -ScopeHandle MirBuilder::new_scope_loop(const Span& sp) -{ - unsigned int idx = m_scopes.size(); - m_scopes.push_back( {false, ScopeType::make_Loop({})} ); - m_scope_stack.push_back( idx ); - DEBUG("START (loop) scope " << idx); - return ScopeHandle { *this, idx }; -} -void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope) -{ - DEBUG("DONE scope " << scope.idx); - // 1. Check that this is the current scope (at the top of the stack) - if( m_scope_stack.back() != scope.idx ) - { - DEBUG("m_scope_stack = " << m_scope_stack); - auto it = ::std::find( m_scope_stack.begin(), m_scope_stack.end(), scope.idx ); - if( it == m_scope_stack.end() ) - BUG(sp, "Terminating scope not on the stack - scope " << scope.idx); - BUG(sp, "Terminating scope " << scope.idx << " when not at top of stack, " << (m_scope_stack.end() - it - 1) << " scopes in the way"); - } - - auto& scope_def = m_scopes.at(scope.idx); - ASSERT_BUG( sp, scope_def.complete == false, "Terminating scope which is already terminated" ); - - complete_scope(scope_def); - - // 2. Emit drops for all non-moved variables (share with below) - drop_scope_values(scope_def); - - // 3. Pop scope (last because `drop_scope_values` uses the stack) - m_scope_stack.pop_back(); -} -void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope) -{ - DEBUG("EARLY scope " << scope.idx); - - // 1. Ensure that this block is in the stack - auto it = ::std::find( m_scope_stack.begin(), m_scope_stack.end(), scope.idx ); - if( it == m_scope_stack.end() ) { - BUG(sp, "Early-terminating scope not on the stack"); - } - unsigned int slot = it - m_scope_stack.begin(); - - bool is_conditional = false; - for(unsigned int i = m_scope_stack.size(); i-- > slot; ) - { - auto idx = m_scope_stack[i]; - auto& scope_def = m_scopes.at( idx ); - - // If a conditional block is hit, prevent full termination of the rest - if( scope_def.data.is_Split() ) - is_conditional = true; - - if( !is_conditional ) { - DEBUG("Complete scope " << idx); - complete_scope(scope_def); - drop_scope_values(scope_def); - m_scope_stack.pop_back(); - } - else { - // Mark patial within this scope? - DEBUG("Drop part of scope " << idx); - - // Emit drops for dropped values within this scope - drop_scope_values(scope_def); - // Inform the scope that it's been early-exited - TU_IFLET( ScopeType, scope_def.data, Split, e, - e.arms.back().has_early_terminated = true; - ) - } - } -} -void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable) -{ - ASSERT_BUG(sp, handle.idx < m_scopes.size(), ""); - auto& sd = m_scopes.at( handle.idx ); - ASSERT_BUG(sp, sd.data.is_Split(), ""); - auto& sd_split = sd.data.as_Split(); - ASSERT_BUG(sp, !sd_split.arms.empty(), ""); - - sd_split.arms.back().always_early_terminated = /*sd_split.arms.back().has_early_terminated &&*/ !reachable; - - // TODO: Undo moves from within the other scope - sd_split.arms.push_back( {} ); -} -void MirBuilder::complete_scope(ScopeDef& sd) -{ - sd.complete = true; - TU_MATCHA( (sd.data), (e), - (Temporaries, - DEBUG("Temporaries " << e.temporaries); - ), - (Variables, - DEBUG("Variables " << e.vars); - ), - (Loop, - DEBUG("Loop"); - ), - (Split, - assert( e.arms.size() > 1 ); - DEBUG("Split - " << (e.arms.size() - 1) << " arms"); - e.arms.pop_back(); - - // Merge all arms and apply upwards - size_t var_count = 0; - for(const auto& arm : e.arms) - { - var_count = ::std::max(var_count, arm.var_states.size()); - } - for(const auto& arm : e.arms) - { - DEBUG("><"); - assert( arm.changed_var_states.size() == arm.var_states.size() ); - for(unsigned int i = 0; i < arm.var_states.size(); i ++ ) - { - if( arm.changed_var_states[i] ) - { - auto new_state = arm.var_states[i]; - // - NOTE: This scope should be off the stack now, so this call will get the original state - auto old_state = get_variable_state(i); - DEBUG("old_state = " << old_state << ", new_state = " << new_state); - // TODO: Need to build up a merged copy of the states? Or just apply upwards directly? - } - } - } - ) - ) -} - - -VarState MirBuilder::get_variable_state(unsigned int idx) const -{ - for( auto scope_idx : ::reverse(m_scope_stack) ) - { - const 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); - if( it != e.vars.end() ) { - unsigned int sub_idx = it - e.vars.begin(); - assert(sub_idx < e.var_states.size()); - return e.var_states[sub_idx]; - } - ), - (Split, - const auto& cur_arm = e.arms.back(); - if( idx < cur_arm.changed_var_states.size() && cur_arm.changed_var_states[idx] ) - { - assert( idx < cur_arm.var_states.size() ); - return cur_arm.var_states[idx]; - } - ) - ) - } - - BUG(Span(), "Variable " << idx << " not found in stack"); -} -void MirBuilder::set_variable_state(unsigned int idx, VarState state) -{ - 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); - if( it != e.vars.end() ) { - unsigned int sub_idx = it - e.vars.begin(); - assert(sub_idx < e.var_states.size()); - e.var_states[sub_idx] = state; - return ; - } - ), - (Split, - auto& cur_arm = e.arms.back(); - if( idx < cur_arm.changed_var_states.size() ) - { - assert( idx < cur_arm.var_states.size() ); - cur_arm.changed_var_states[idx] = true; - cur_arm.var_states[idx] = state; - return ; - } - ) - ) - } - - BUG(Span(), "Variable " << idx << " not found in stack"); -} -VarState MirBuilder::get_temp_state(unsigned int idx) const -{ - for( auto scope_idx : ::reverse(m_scope_stack) ) - { - const auto& scope_def = m_scopes.at(scope_idx); - TU_MATCH_DEF( ScopeType, (scope_def.data), (e), - ( - ), - (Temporaries, - auto it = ::std::find(e.temporaries.begin(), e.temporaries.end(), idx); - if( it != e.temporaries.end() ) { - unsigned int sub_idx = it - e.temporaries.begin(); - ASSERT_BUG(Span(), sub_idx < e.states.size(), "Temporary list sizes invalid - " << sub_idx << " >= " << e.states.size()); - return e.states[sub_idx]; - } - ), - (Split, - // TODO: Does split account for temps? It should. - ) - ) - } - - BUG(Span(), "Temporary " << idx << " not found in stack"); -} -void MirBuilder::set_temp_state(unsigned int idx, VarState state) -{ - for( auto scope_idx : ::reverse(m_scope_stack) ) - { - auto& scope_def = m_scopes.at(scope_idx); - TU_MATCH_DEF( ScopeType, (scope_def.data), (e), - ( - ), - (Temporaries, - auto it = ::std::find(e.temporaries.begin(), e.temporaries.end(), idx); - if( it != e.temporaries.end() ) { - unsigned int sub_idx = it - e.temporaries.begin(); - assert(sub_idx < e.states.size()); - e.states[sub_idx] = state; - return ; - } - ), - (Split, - // TODO: Does split account for temps? It should. - ) - ) - } -} - -void MirBuilder::drop_scope_values(const ScopeDef& sd) -{ - TU_MATCHA( (sd.data), (e), - (Temporaries, - for(auto tmp_idx : e.temporaries) - { - if( get_temp_state(tmp_idx) == VarState::Init ) { - push_stmt_drop( ::MIR::LValue::make_Temporary({ tmp_idx }) ); - set_temp_state(tmp_idx, VarState::Dropped); - } - } - ), - (Variables, - for(auto var_idx : e.vars) - { - switch( get_variable_state(var_idx) ) - { - case VarState::Uninit: - case VarState::Dropped: - case VarState::Moved: - break; - case VarState::Init: - push_stmt_drop( ::MIR::LValue::make_Variable(var_idx) ); - break; - case VarState::MaybeMoved: - // TODO: Drop flags - break; - } - } - ), - (Split, - // No values, controls parent - ), - (Loop, - // No values - ) - ) -} - -void MirBuilder::moved_lvalue(const ::MIR::LValue& lv) -{ - TU_MATCHA( (lv), (e), - (Variable, - set_variable_state(e, VarState::Moved); - ), - (Temporary, - //TODO(Span(), "Mark temp as moved"); - ), - (Argument, - //TODO(Span(), "Mark argument as moved"); - ), - (Static, - //TODO(Span(), "Static - Assert that type is Copy"); - ), - (Return, - BUG(Span(), "Read of return value"); - ), - (Field, - //TODO(Span(), "Mark field of an lvalue as moved (if not Copy) - Partially moved structs?"); - //moved_lvalue(*e.val); - ), - (Deref, - //TODO(Span(), "Mark deref of an lvalue as moved (if not Copy) - Req. DerefMove/&move otherwise"); - //moved_lvalue(*e.val); - ), - (Index, - //TODO(Span(), "Mark index of an lvalue as moved (if not Copy) - Req. IndexGet/IndexMove"); - //moved_lvalue(*e.val); - - moved_lvalue(*e.idx); - ), - (Downcast, - // TODO: What if the inner is Copy? What if the inner is a hidden pointer? - moved_lvalue(*e.val); - ) - ) -} - -ScopeHandle::~ScopeHandle() -{ - if( idx != ~0u ) - { - ASSERT_BUG(Span(), m_builder.m_scopes.size() > idx, "Scope invalid"); - ASSERT_BUG(Span(), m_builder.m_scopes.at(idx).complete, "Scope " << idx << " not completed"); - } -} - -::std::ostream& operator<<(::std::ostream& os, VarState x) -{ - switch(x) - { - #define _(V) case VarState::V: os << #V; break; - _(Uninit) - _(Init) - _(MaybeMoved) - _(Moved) - _(Dropped) - #undef _ - } - return os; -} - -// -------------------------------------------------------------------- void HIR_GenerateMIR(::HIR::Crate& crate) { |