From c7f4248191dce493cd43fecd808cf15015271408 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 22 Jun 2017 11:43:41 +0800 Subject: Codegen C - First pass at structured C output (generated, but not compiled) --- src/trans/codegen_c_structured.cpp | 290 +++++++++++++++++++++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 src/trans/codegen_c_structured.cpp (limited to 'src/trans/codegen_c_structured.cpp') diff --git a/src/trans/codegen_c_structured.cpp b/src/trans/codegen_c_structured.cpp new file mode 100644 index 00000000..e89d7589 --- /dev/null +++ b/src/trans/codegen_c_structured.cpp @@ -0,0 +1,290 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * trans/codegen_c_structured.cpp + * - Converts MIR into a semi-structured form + */ +#include +#include +#include +#include "codegen_c.hpp" + +NodeRef::NodeRef(Node node_data): + node(new Node(mv$(node_data))), + bb_idx(SIZE_MAX) +{ +} +bool NodeRef::has_target() const +{ + if( node ) { + TU_MATCHA( (*this->node), (e), + (Block, + return e.next_bb != SIZE_MAX; + ), + (If, + return e.next_bb != SIZE_MAX; + ), + (Switch, + return e.next_bb != SIZE_MAX; + ), + (Loop, + return e.next_bb != SIZE_MAX; + ) + ) + throw ""; + } + else { + return true; + } +} +size_t NodeRef::target() const +{ + if( node ) { + TU_MATCHA( (*this->node), (e), + (Block, + return e.next_bb; + ), + (If, + return e.next_bb; + ), + (Switch, + return e.next_bb; + ), + (Loop, + return e.next_bb; + ) + ) + throw ""; + } + else { + return bb_idx; + } +} + +class Converter +{ + const ::MIR::Function& m_fcn; +public: + ::std::vector m_block_ref_count; + ::std::vector m_blocks_used; + + Converter(const ::MIR::Function& fcn): + m_fcn(fcn) + { + + } + + // Returns true if the passed block is the start of a self-contained sequence of blocks + bool bb_is_opening(size_t bb_idx) + { + if( m_blocks_used[bb_idx] ) { + return false; + } + else if( m_block_ref_count[bb_idx] > 1 ) { + // TODO: Determine if these multiple references are from the block looping back on itself + return false; + } + else { + return true; + } + } + NodeRef process_node_ref(size_t bb_idx) + { + if( bb_is_opening(bb_idx) ) { + return NodeRef( process_node(bb_idx) ); + } + else { + return NodeRef(bb_idx); + } + } + + Node process_node(size_t bb_idx) + { + TRACE_FUNCTION_F(bb_idx); + ::std::vector refs; + for(;;) + { + DEBUG("bb_idx = " << bb_idx); + bool stop = false; + assert( !m_blocks_used[bb_idx] ); + m_blocks_used[bb_idx] = true; + + refs.push_back( NodeRef(bb_idx) ); + + const auto& blk = m_fcn.blocks.at(bb_idx); + DEBUG("> " << blk.terminator); + TU_MATCHA( (blk.terminator), (te), + (Incomplete, + stop = true; + ), + (Goto, + bb_idx = te; + ), + (Panic, + TODO(Span(), "Panic"); + ), + (Diverge, + stop = true; + ), + (Return, + stop = true; + ), + (If, + auto arm0 = process_node_ref(te.bb0); + auto arm1 = process_node_ref(te.bb1); + if( arm0.has_target() && arm1.has_target() ) { + if( arm0.target() == arm1.target() ) { + bb_idx = arm0.target(); + } + else { + stop = true; + } + } + else if( arm0.has_target() ) { + bb_idx = arm0.target(); + } + else if( arm1.has_target() ) { + bb_idx = arm1.target(); + } + else { + // No target from either arm + stop = false; + } + refs.push_back(Node::make_If({ bb_idx, &te.cond, mv$(arm0), mv$(arm1) })); + ), + (Switch, + ::std::vector arms; + ::std::vector next_blocks; + for(auto& tgt : te.targets) + { + arms.push_back( process_node_ref(tgt) ); + if( arms.back().has_target() ) + { + next_blocks.push_back( arms.back().target() ); + } + } + ::std::sort(next_blocks.begin(), next_blocks.end()); + size_t exit_bb = SIZE_MAX; + if(!next_blocks.empty()) + { + size_t cur = next_blocks[0]; + size_t cur_count = 0; + size_t max_count = 0; + for(auto b : next_blocks) + { + if(cur == b) { + cur_count ++; + } + else { + if( cur_count > max_count ) { + exit_bb = cur; + } + cur = b; + cur_count = 1; + } + } + if( cur_count > max_count ) { + exit_bb = cur; + } + } + refs.push_back(Node::make_Switch({ exit_bb, &te.val, mv$(arms) })); + stop = true; + ), + (Call, + // NOTE: Let the panic arm just be a goto + bb_idx = te.ret_block; + ) + ) + + if( stop ) + { + break; + } + + // If `bb_idx` is in `refs` as a NodeRef + auto it = ::std::find(refs.begin(), refs.end(), bb_idx); + if( it != refs.end() ) + { + // Wrap ibb_idxms from `it` to `refs.end()` in a `loop` block + ::std::vector loop_blocks; + loop_blocks.reserve(refs.end() - it); + for(auto it2 = it; it2 != refs.end(); ++it2) + loop_blocks.push_back( mv$(*it2) ); + auto loop_node = NodeRef( Node::make_Block({ SIZE_MAX, mv$(loop_blocks) }) ); + + refs.push_back( Node::make_Loop({ SIZE_MAX, mv$(loop_node) }) ); + // TODO: If there is only one `goto` in the above loop, assume it's the target + DEBUG("Loop"); + break; + } + else if( bb_is_opening(bb_idx) ) + { + DEBUG("Destination " << bb_idx << " is unreferenced+unvisited"); + } + else + { + break; + } + } + + return Node::make_Block({ bb_idx, mv$(refs) }); + } +}; + +::std::vector MIR_To_Structured(const ::MIR::Function& fcn) +{ + Converter conv(fcn); + conv.m_block_ref_count.resize( fcn.blocks.size() ); + conv.m_block_ref_count[0] += 1; + for(const auto& blk : fcn.blocks) + { + TU_MATCHA( (blk.terminator), (te), + (Incomplete, + ), + (Goto, + conv.m_block_ref_count[te] += 1; + ), + (Panic, + conv.m_block_ref_count[te.dst] += 1; + ), + (Diverge, + ), + (Return, + ), + (If, + conv.m_block_ref_count[te.bb0] += 1; + conv.m_block_ref_count[te.bb1] += 1; + ), + (Switch, + for(auto tgt : te.targets) + conv.m_block_ref_count[tgt] += 1; + ), + (Call, + conv.m_block_ref_count[te.ret_block] += 1; + conv.m_block_ref_count[te.panic_block] += 1; + ) + ) + } + + // First Block: Becomes a block in structured output + // - Terminator selects what the next block will be + // - + + // Find next unvisited block + conv.m_blocks_used.resize( fcn.blocks.size() ); + ::std::vector nodes; + for(size_t bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++) + { + if( conv.m_blocks_used[bb_idx] ) + continue; + + nodes.push_back( conv.process_node(bb_idx) ); + } + + + // Return. + return nodes; +} + + -- cgit v1.2.3 From c4e88b3c49736e71534c918a83956885c052beb8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 6 Jul 2017 16:29:30 +0800 Subject: MIR - Add (but don't use) a SwitchValue terminator --- src/hir/serialise.cpp | 24 ++++ src/hir_conv/bind.cpp | 3 + src/mir/check.cpp | 17 +++ src/mir/check_full.cpp | 8 ++ src/mir/cleanup.cpp | 3 + src/mir/dump.cpp | 18 +++ src/mir/helpers.cpp | 10 ++ src/mir/mir.cpp | 34 +++++ src/mir/mir.hpp | 14 ++ src/mir/optimise.cpp | 263 ++++++++++++++----------------------- src/trans/codegen_c.cpp | 9 +- src/trans/codegen_c_structured.cpp | 8 ++ src/trans/enumerate.cpp | 6 + src/trans/monomorphise.cpp | 8 ++ 14 files changed, 259 insertions(+), 166 deletions(-) (limited to 'src/trans/codegen_c_structured.cpp') diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index cddbf0b8..78efe261 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -77,6 +77,9 @@ namespace { m_out.write_count(e.first); serialise(e.second); } + //void serialise(::MIR::BasicBlockId val) { + // m_out.write_count(val); + //} void serialise_type(const ::HIR::TypeRef& ty) { @@ -531,6 +534,12 @@ namespace { for(auto t : e.targets) m_out.write_count(t); ), + (SwitchValue, + serialise(e.val); + m_out.write_count(e.def_target); + serialise_vec(e.targets); + serialise(e.values); + ), (Call, m_out.write_count(e.ret_block); m_out.write_count(e.panic_block); @@ -540,6 +549,21 @@ namespace { ) ) } + void serialise(const ::MIR::SwitchValues& sv) + { + m_out.write_tag( static_cast(sv.tag()) ); + TU_MATCHA( (sv), (e), + (Unsigned, + serialise_vec(e); + ), + (Signed, + serialise_vec(e); + ), + (String, + serialise_vec(e); + ) + ) + } void serialise(const ::MIR::CallTarget& ct) { m_out.write_tag( static_cast(ct.tag()) ); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 1b0f61b6..beac3b84 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -617,6 +617,9 @@ namespace { (Switch, H::visit_lvalue(*this, te.val); ), + (SwitchValue, + H::visit_lvalue(*this, te.val); + ), (Call, H::visit_lvalue(*this, te.ret_val); TU_MATCHA( (te.fcn), (e2), diff --git a/src/mir/check.cpp b/src/mir/check.cpp index 58bcaf55..7c0cd4d8 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -452,6 +452,14 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn add_to_visit( tgt, path, val_state ); } ), + (SwitchValue, + val_state.ensure_valid( state, e.val ); + for(const auto& tgt : e.targets) + { + add_to_visit( tgt, path, val_state ); + } + add_to_visit( e.def_target, path, val_state ); + ), (Call, if( e.fcn.is_Value() ) val_state.ensure_valid( state, e.fcn.as_Value() ); @@ -534,6 +542,12 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path PUSH_BB(e.targets[i], "Switch V" << i); } ), + (SwitchValue, + for(unsigned int i = 0; i < e.targets.size(); i++ ) { + PUSH_BB(e.targets[i], "SwitchValue " << i); + } + PUSH_BB(e.def_target, "SwitchValue def"); + ), (Call, PUSH_BB(e.ret_block, "Call ret"); PUSH_BB(e.panic_block, "Call panic"); @@ -829,6 +843,9 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path (Switch, // Check that the condition is an enum ), + (SwitchValue, + // Check that the condition's type matches the values + ), (Call, if( e.fcn.is_Value() ) { diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index a153aca7..1f86c40a 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -995,6 +995,14 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio todo_queue.push_back( ::std::make_pair(te.targets[i], i == te.targets.size()-1 ? mv$(state) : state.clone()) ); } ), + (SwitchValue, + state.ensure_lvalue_valid(mir_res, te.val); + for(size_t i = 0; i < te.targets.size(); i ++) + { + todo_queue.push_back( ::std::make_pair(te.targets[i], state.clone()) ); + } + todo_queue.push_back( ::std::make_pair(te.def_target, mv$(state)) ); + ), (Call, if(const auto* e = te.fcn.opt_Value()) { diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 3dda81dc..f26f2bdd 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -1103,6 +1103,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, (Switch, MIR_Cleanup_LValue(state, mutator, e.val); ), + (SwitchValue, + MIR_Cleanup_LValue(state, mutator, e.val); + ), (Call, MIR_Cleanup_LValue(state, mutator, e.ret_val); if( e.fcn.is_Value() ) { diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index 4e53cf5b..a029023a 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -131,6 +131,24 @@ namespace { m_os << j << " => bb" << e.targets[j] << ", "; m_os << "}\n"; ), + (SwitchValue, + m_os << "switch " << FMT_M(e.val) << " {"; + TU_MATCHA( (e.values), (ve), + (Unsigned, + for(unsigned int j = 0; j < e.targets.size(); j ++) + m_os << ve[j] << " => bb" << e.targets[j] << ", "; + ), + (Signed, + for(unsigned int j = 0; j < e.targets.size(); j ++) + m_os << (ve[j] >= 0 ? "+" : "") << ve[j] << " => bb" << e.targets[j] << ", "; + ), + (String, + for(unsigned int j = 0; j < e.targets.size(); j ++) + m_os << "\"" << ve[j] << "\" => bb" << e.targets[j] << ", "; + ) + ) + m_os << "_ => bb" << e.def_target << "}\n"; + ), (Call, m_os << FMT_M(e.ret_val) << " = "; TU_MATCHA( (e.fcn), (e2), diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index ea5709d1..e51c9180 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -481,6 +481,9 @@ namespace visit { (Switch, rv |= visit_mir_lvalue(e.val, ValUsage::Read, cb); ), + (SwitchValue, + rv |= visit_mir_lvalue(e.val, ValUsage::Read, cb); + ), (Call, if( e.fcn.is_Value() ) { rv |= visit_mir_lvalue(e.fcn.as_Value(), ValUsage::Read, cb); @@ -951,6 +954,13 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime( m_states_to_do.push_back( ::std::make_pair(te.targets[i], mv$(s)) ); } ), + (SwitchValue, + for(size_t i = 0; i < te.targets.size(); i ++) + { + m_states_to_do.push_back( ::std::make_pair(te.targets[i], state.clone()) ); + } + m_states_to_do.push_back( ::std::make_pair(te.def_target, mv$(state)) ); + ), (Call, if( te.ret_val == m_lv ) { diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 3f7057ff..09e978f9 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -419,6 +419,24 @@ namespace MIR { os << j << " => bb" << e.targets[j] << ", "; os << ")"; ), + (SwitchValue, + os << "SwitchValue( " << e.val << " : "; + TU_MATCHA( (e.values), (ve), + (Unsigned, + for(unsigned int j = 0; j < e.targets.size(); j ++) + os << ve[j] << " => bb" << e.targets[j] << ", "; + ), + (Signed, + for(unsigned int j = 0; j < e.targets.size(); j ++) + os << (ve[j] >= 0 ? "+" : "") << ve[j] << " => bb" << e.targets[j] << ", "; + ), + (String, + for(unsigned int j = 0; j < e.targets.size(); j ++) + os << "\"" << ve[j] << "\" => bb" << e.targets[j] << ", "; + ) + ) + os << "else bb" << e.def_target << ")"; + ), (Call, os << "Call( " << e.ret_val << " = "; TU_MATCHA( (e.fcn), (e2), @@ -604,3 +622,19 @@ namespace MIR { throw ""; } +::MIR::SwitchValues MIR::SwitchValues::clone() const +{ + TU_MATCHA( (*this), (ve), + (Unsigned, + return ve; + ), + (Signed, + return ve; + ), + (String, + return ve; + ) + ) + throw ""; +} + diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 6254bf42..987e0498 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -211,6 +211,14 @@ TAGGED_UNION(CallTarget, Intrinsic, ::HIR::PathParams params; }) ); +TAGGED_UNION_EX(SwitchValues, (), Unsigned, ( + (Unsigned, ::std::vector), + (Signed, ::std::vector), + (String, ::std::vector<::std::string>) + ), (),(), ( + SwitchValues clone() const; + ) + ); TAGGED_UNION(Terminator, Incomplete, (Incomplete, struct {}), // Block isn't complete (ERROR in output) @@ -227,6 +235,12 @@ TAGGED_UNION(Terminator, Incomplete, LValue val; ::std::vector targets; }), + (SwitchValue, struct { + LValue val; + BasicBlockId def_target; + ::std::vector targets; + SwitchValues values; + }), (Call, struct { BasicBlockId ret_block; BasicBlockId panic_block; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 3ef629b1..73cbaa04 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -222,6 +222,9 @@ namespace { (Switch, visit_mir_lvalue_mut(e.val, ValUsage::Read, cb); ), + (SwitchValue, + visit_mir_lvalue_mut(e.val, ValUsage::Read, cb); + ), (Call, if( e.fcn.is_Value() ) { visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, cb); @@ -392,6 +395,42 @@ namespace { } + void visit_terminator_target_mut(::MIR::Terminator& term, ::std::function cb) { + TU_MATCHA( (term), (e), + (Incomplete, + ), + (Return, + ), + (Diverge, + ), + (Goto, + cb(e); + ), + (Panic, + ), + (If, + cb(e.bb0); + cb(e.bb1); + ), + (Switch, + for(auto& target : e.targets) + cb(target); + ), + (SwitchValue, + for(auto& target : e.targets) + cb(target); + cb(e.def_target); + ), + (Call, + cb(e.ret_block); + cb(e.panic_block); + ) + ) + } + void visit_terminator_target(const ::MIR::Terminator& term, ::std::function cb) { + visit_terminator_target_mut(const_cast<::MIR::Terminator&>(term), cb); + } + void visit_blocks_mut(::MIR::TypeResolve& state, ::MIR::Function& fcn, ::std::function cb) { ::std::vector visited( fcn.blocks.size() ); @@ -406,44 +445,16 @@ namespace { cb(bb, block); - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target(block.terminator, [&](auto e){ if( !visited[e] ) to_visit.push_back(e); - ), - (Panic, - ), - (If, - if( !visited[e.bb0] ) - to_visit.push_back(e.bb0); - if( !visited[e.bb1] ) - to_visit.push_back(e.bb1); - ), - (Switch, - for(auto& target : e.targets) - if( !visited[target] ) - to_visit.push_back(target); - ), - (Call, - if( !visited[e.ret_block] ) - to_visit.push_back(e.ret_block); - if( !visited[e.panic_block] ) - to_visit.push_back(e.panic_block); - ) - ) + }); } } void visit_blocks(::MIR::TypeResolve& state, const ::MIR::Function& fcn, ::std::function cb) { visit_blocks_mut(state, const_cast<::MIR::Function&>(fcn), [cb](auto id, auto& blk){ cb(id, blk); }); } - bool statement_invalidates_lvalue(const ::MIR::Statement& stmt, const ::MIR::LValue& lv) { return visit_mir_lvalues(stmt, [&](const auto& v, auto vu) { @@ -651,32 +662,10 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn) } } - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target_mut(block.terminator, [&](auto& e) { if( &fcn.blocks[e] != &block ) e = get_new_target(state, e); - ), - (Panic, - ), - (If, - e.bb0 = get_new_target(state, e.bb0); - e.bb1 = get_new_target(state, e.bb1); - ), - (Switch, - for(auto& target : e.targets) - target = get_new_target(state, target); - ), - (Call, - e.ret_block = get_new_target(state, e.ret_block); - e.panic_block = get_new_target(state, e.panic_block); - ) - ) + }); } // >> Merge blocks where a block goto-s to a single-use block. @@ -694,40 +683,10 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn) visited[bb] = true; const auto& block = fcn.blocks[bb]; - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target(block.terminator, [&](const auto& e) { if( !visited[e] ) to_visit.push_back(e); uses[e] ++; - ), - (Panic, - ), - (If, - if( !visited[e.bb0] ) to_visit.push_back(e.bb0); - if( !visited[e.bb1] ) to_visit.push_back(e.bb1); - uses[e.bb0] ++; - uses[e.bb1] ++; - ), - (Switch, - for(auto& target : e.targets) - { - if( !visited[target] ) - to_visit.push_back(target); - uses[target] ++; - } - ), - (Call, - if( !visited[e.ret_block] ) to_visit.push_back(e.ret_block); - if( !visited[e.panic_block] ) to_visit.push_back(e.panic_block); - uses[e.ret_block] ++; - uses[e.panic_block] ++; - ) - ) + }); } unsigned int i = 0; @@ -970,6 +929,13 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool arms.push_back( bbi + this->bb_base ); return ::MIR::Terminator::make_Switch({ this->clone_lval(se.val), mv$(arms) }); ), + (SwitchValue, + ::std::vector<::MIR::BasicBlockId> arms; + arms.reserve(se.targets.size()); + for(const auto& bbi : se.targets) + arms.push_back( bbi + this->bb_base ); + return ::MIR::Terminator::make_SwitchValue({ this->clone_lval(se.val), se.def_target + this->bb_base, mv$(arms), se.values.clone() }); + ), (Call, ::MIR::CallTarget tgt; TU_MATCHA( (se.fcn), (ste), @@ -1412,6 +1378,30 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) if( ae.targets != be.targets ) return false; ), + (SwitchValue, + if( ae.val != be.val ) + return false; + if( ae.targets != be.targets ) + return false; + if( ae.def_target != be.def_target ) + return false; + if( ae.values.tag() != be.values.tag() ) + return false; + TU_MATCHA( (ae.values, be.values), (ae2, be2), + (Unsigned, + if( ae2 != be2 ) + return false; + ), + (Signed, + if( ae2 != be2 ) + return false; + ), + (String, + if( ae2 != be2 ) + return false; + ) + ) + ), (Call, if( ae.ret_block != be.ret_block ) return false; @@ -1483,32 +1473,9 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) { if( bb.terminator.tag() == ::MIR::Terminator::TAGDEAD ) continue ; - TU_MATCHA( (bb.terminator), (te), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target_mut(bb.terminator, [&](auto& te) { patch_tgt(te); - ), - (Panic, - patch_tgt(te.dst); - ), - (If, - patch_tgt(te.bb0); - patch_tgt(te.bb1); - ), - (Switch, - for(auto& tgt : te.targets) - patch_tgt(tgt); - ), - (Call, - patch_tgt(te.ret_block); - patch_tgt(te.panic_block); - ) - ) + }); //DEBUG("- " << bb.terminator); } @@ -1548,7 +1515,7 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio visited[bb] = true; const auto& block = fcn.blocks[bb]; - auto ref_block = [&](auto idx) { + visit_terminator_target(block.terminator, [&](const auto& idx) { if( !visited[idx] ) to_visit.push_back(idx); if(block_uses[idx] == 0) @@ -1556,34 +1523,7 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio else block_origins[idx] = SIZE_MAX; block_uses[idx] ++; - }; - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, - ref_block(e); - ), - (Panic, - ), - (If, - ref_block(e.bb0); - ref_block(e.bb1); - ), - (Switch, - for(auto& target : e.targets) - { - ref_block(target); - } - ), - (Call, - ref_block(e.ret_block); - ref_block(e.panic_block); - ) - ) + }); } } @@ -2293,6 +2233,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F found = true; stop = true; ), + (SwitchValue, + if( src_is_lvalue && visit_mir_lvalue(e.val, ValUsage::Read, is_lvalue_usage) ) + found = true; + stop = true; + ), (Call, if( e.fcn.is_Value() ) if( src_is_lvalue && visit_mir_lvalue(e.fcn.as_Value(), ValUsage::Read, is_lvalue_usage) ) @@ -2847,6 +2792,12 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn for(auto& target : e.targets) target = block_rewrite_table[target]; ), + (SwitchValue, + visit_mir_lvalue_mut(e.val, ValUsage::Read, lvalue_cb); + for(auto& target : e.targets) + target = block_rewrite_table[target]; + e.def_target = block_rewrite_table[e.def_target]; + ), (Call, if( e.fcn.is_Value() ) { visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, lvalue_cb); @@ -2939,6 +2890,11 @@ void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& pa for(auto dst : te.targets) todo.push_back(Todo { dst, ++branches, info.level + 1 }); ), + (SwitchValue, + for(auto dst : te.targets) + todo.push_back(Todo { dst, ++branches, info.level + 1 }); + todo.push_back(Todo { te.def_target, info.branch_count, info.level + 1 }); + ), (Call, todo.push_back(Todo { te.ret_block, info.branch_count, info.level + 1 }); todo.push_back(Todo { te.panic_block, ++branches, info.level + 1 }); @@ -2963,32 +2919,9 @@ void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& pa { auto fix_bb_idx = [&](auto idx){ return ::std::find(idxes.begin(), idxes.end(), idx) - idxes.begin(); }; new_block_list.push_back( mv$(fcn.blocks[idx]) ); - TU_MATCHA( (new_block_list.back().terminator), (te), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target_mut(new_block_list.back().terminator, [&](auto& te){ te = fix_bb_idx(te); - ), - (Panic, - te.dst = fix_bb_idx(te.dst); - ), - (If, - te.bb0 = fix_bb_idx(te.bb0); - te.bb1 = fix_bb_idx(te.bb1); - ), - (Switch, - for(auto& tgt : te.targets) - tgt = fix_bb_idx(tgt); - ), - (Call, - te.ret_block = fix_bb_idx(te.ret_block); - te.panic_block = fix_bb_idx(te.panic_block); - ) - ) + }); } fcn.blocks = mv$(new_block_list); } diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index be34e3db..c554d4ab 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1386,6 +1386,7 @@ namespace { m_of << "\tbool df" << i << " = " << code->drop_flags[i] << ";\n"; } + if( false ) { m_of << "#if 0\n"; auto nodes = MIR_To_Structured(*code); @@ -1445,7 +1446,7 @@ namespace { auto it = m_enum_repr_cache.find( ty.m_data.as_Path().path.m_data.as_Generic() ); if( it != m_enum_repr_cache.end() ) { - MIR_ASSERT(mir_res, e.targets.size() == 2, ""); + MIR_ASSERT(mir_res, e.targets.size() == 2, "Non-zero optimised type a variant count that isn't 2"); m_of << "\tif("; emit_lvalue(e.val); emit_nonzero_path(it->second); m_of << ")\n"; m_of << "\t\tgoto bb" << e.targets[1] << ";\n"; m_of << "\telse\n"; @@ -1470,6 +1471,9 @@ namespace { m_of << "\t}\n"; } ), + (SwitchValue, + MIR_TODO(mir_res, "SwitchValue in C codegen"); + ), (Call, emit_term_call(mir_res, e, 1); m_of << "\tgoto bb" << e.ret_block << ";\n"; @@ -1524,6 +1528,9 @@ namespace { emit_term_call(mir_res, te, indent_level); ), (Switch, + //assert(i == e.nodes.size()-1 && "Switch"); + ), + (SwitchValue, //assert(i == e.nodes.size()-1 && "Switch"); ) ) diff --git a/src/trans/codegen_c_structured.cpp b/src/trans/codegen_c_structured.cpp index e89d7589..888f9a26 100644 --- a/src/trans/codegen_c_structured.cpp +++ b/src/trans/codegen_c_structured.cpp @@ -191,6 +191,9 @@ public: refs.push_back(Node::make_Switch({ exit_bb, &te.val, mv$(arms) })); stop = true; ), + (SwitchValue, + TODO(Span(), "SwitchValue"); + ), (Call, // NOTE: Let the panic arm just be a goto bb_idx = te.ret_block; @@ -260,6 +263,11 @@ public: for(auto tgt : te.targets) conv.m_block_ref_count[tgt] += 1; ), + (SwitchValue, + for(auto tgt : te.targets) + conv.m_block_ref_count[tgt] += 1; + conv.m_block_ref_count[te.def_target] += 1; + ), (Call, conv.m_block_ref_count[te.ret_block] += 1; conv.m_block_ref_count[te.panic_block] += 1; diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index fb577959..41489e2b 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -935,6 +935,9 @@ void Trans_Enumerate_Types(EnumState& state) (Switch, H::visit_lvalue(tv,pp,fcn, te.val); ), + (SwitchValue, + H::visit_lvalue(tv,pp,fcn, te.val); + ), (Call, if( te.fcn.is_Value() ) H::visit_lvalue(tv,pp,fcn, te.fcn.as_Value()); @@ -1476,6 +1479,9 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, (Switch, Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); ), + (SwitchValue, + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + ), (Call, Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val, pp); TU_MATCHA( (e.fcn), (e2), diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index f708060d..b752a5bc 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -295,6 +295,14 @@ namespace { e.targets }); ), + (SwitchValue, + terminator = ::MIR::Terminator::make_SwitchValue({ + monomorph_LValue(resolve, params, e.val), + e.def_target, + e.targets, + e.values.clone() + }); + ), (Call, struct H { static ::MIR::CallTarget monomorph_calltarget(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::CallTarget& ct) { -- cgit v1.2.3