diff options
author | John Hodge <tpg@ucc.asn.au> | 2017-11-30 23:04:50 +0800 |
---|---|---|
committer | John Hodge <tpg@ucc.asn.au> | 2017-11-30 23:04:50 +0800 |
commit | 7bdf012eb9626ce3a226b00265bd7845a01581f2 (patch) | |
tree | 990424a6c55c88b94d9410f46b6527cdb01f9f6b | |
parent | 1a379700e5c5d9c248ec661f651a5a8e8c6d895a (diff) | |
download | mrust-7bdf012eb9626ce3a226b00265bd7845a01581f2.tar.gz |
Codegen C - Structured SwitchValue partial support, unify Switch handling
-rw-r--r-- | src/trans/codegen_c.cpp | 39 | ||||
-rw-r--r-- | src/trans/codegen_c.hpp | 7 | ||||
-rw-r--r-- | src/trans/codegen_c_structured.cpp | 54 |
3 files changed, 66 insertions, 34 deletions
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index c42b4b1f..4b0f0fc6 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2058,38 +2058,9 @@ namespace { m_of << "\tif("; emit_lvalue(e.cond); m_of << ") goto bb" << e.bb0 << "; else goto bb" << e.bb1 << ";\n"; ), (Switch, - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, e.val); - MIR_ASSERT(mir_res, ty.m_data.is_Path(), "Switch of a non-enum - " << ty); - MIR_ASSERT(mir_res, ty.m_data.as_Path().binding.is_Enum(), "Switch of a non-enum - " << ty); - const auto* enm = ty.m_data.as_Path().binding.as_Enum(); - 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, "Non-zero optimised type a variant count that isn't 2"); - m_of << "\tif("; emit_lvalue(e.val); m_of << "._1"; emit_nonzero_path(it->second); m_of << ")\n"; - m_of << "\t\tgoto bb" << e.targets[1] << ";\n"; - m_of << "\telse\n"; - m_of << "\t\tgoto bb" << e.targets[0] << ";\n"; - } - else if( enm->is_value() ) - { - m_of << "\tswitch("; emit_lvalue(e.val); m_of << ".TAG) {\n"; - for(unsigned int j = 0; j < e.targets.size(); j ++) - { - m_of << "\t\tcase " << enm->get_value(j) << ": goto bb" << e.targets[j] << ";\n"; - } - m_of << "\t\tdefault: abort();\n"; - m_of << "\t}\n"; - } - else - { - m_of << "\tswitch("; emit_lvalue(e.val); m_of << ".TAG) {\n"; - for(unsigned int j = 0; j < e.targets.size(); j ++) - m_of << "\t\tcase " << j << ": goto bb" << e.targets[j] << ";\n"; - m_of << "\t\tdefault: abort();\n"; - m_of << "\t}\n"; - } + emit_term_switch(mir_res, e.val, e.targets.size(), 1, [&](size_t idx) { + m_of << "goto bb" << e.targets[idx] << ";"; + }); ), (SwitchValue, ::HIR::TypeRef tmp; @@ -2203,7 +2174,6 @@ namespace { //assert(i == e.nodes.size()-1 && "If"); ), (Call, - // TODO: Emit call emit_term_call(mir_res, te, indent_level); ), (Switch, @@ -2253,6 +2223,9 @@ namespace { } }); ), + (SwitchValue, + MIR_TODO(mir_res, "SwitchValue"); + ), (Loop, m_of << indent << "for(;;) {\n"; assert(e.code.node); diff --git a/src/trans/codegen_c.hpp b/src/trans/codegen_c.hpp index 72d0c796..5c9afe12 100644 --- a/src/trans/codegen_c.hpp +++ b/src/trans/codegen_c.hpp @@ -38,6 +38,13 @@ TAGGED_UNION(Node, Block, const ::MIR::LValue* val; ::std::vector<NodeRef> arms; }), +(SwitchValue, struct { + size_t next_bb; + const ::MIR::LValue* val; + NodeRef def_arm; + ::std::vector<NodeRef> arms; + const ::MIR::SwitchValues* vals; + }), (Loop, struct { size_t next_bb; NodeRef code; diff --git a/src/trans/codegen_c_structured.cpp b/src/trans/codegen_c_structured.cpp index 888f9a26..f35de9f8 100644 --- a/src/trans/codegen_c_structured.cpp +++ b/src/trans/codegen_c_structured.cpp @@ -28,6 +28,9 @@ bool NodeRef::has_target() const (Switch, return e.next_bb != SIZE_MAX; ), + (SwitchValue, + return e.next_bb != SIZE_MAX; + ), (Loop, return e.next_bb != SIZE_MAX; ) @@ -51,6 +54,9 @@ size_t NodeRef::target() const (Switch, return e.next_bb; ), + (SwitchValue, + return e.next_bb; + ), (Loop, return e.next_bb; ) @@ -164,6 +170,7 @@ public: next_blocks.push_back( arms.back().target() ); } } + // TODO: Make the next block common ::std::sort(next_blocks.begin(), next_blocks.end()); size_t exit_bb = SIZE_MAX; if(!next_blocks.empty()) @@ -189,10 +196,55 @@ public: } } refs.push_back(Node::make_Switch({ exit_bb, &te.val, mv$(arms) })); + // TODO: Continue with the exit bb? stop = true; ), (SwitchValue, - TODO(Span(), "SwitchValue"); + ::std::vector<NodeRef> arms; + ::std::vector<size_t> 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() ); + } + } + auto def_arm = process_node_ref(te.def_target); + if(def_arm.has_target()) + { + next_blocks.push_back(def_arm.target()); + } + + // TODO: Make the next block common + ::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_SwitchValue({ exit_bb, &te.val, mv$(def_arm), mv$(arms), &te.values })); + stop = true; + ), (Call, // NOTE: Let the panic arm just be a goto |