summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2017-11-30 23:04:50 +0800
committerJohn Hodge <tpg@ucc.asn.au>2017-11-30 23:04:50 +0800
commit7bdf012eb9626ce3a226b00265bd7845a01581f2 (patch)
tree990424a6c55c88b94d9410f46b6527cdb01f9f6b
parent1a379700e5c5d9c248ec661f651a5a8e8c6d895a (diff)
downloadmrust-7bdf012eb9626ce3a226b00265bd7845a01581f2.tar.gz
Codegen C - Structured SwitchValue partial support, unify Switch handling
-rw-r--r--src/trans/codegen_c.cpp39
-rw-r--r--src/trans/codegen_c.hpp7
-rw-r--r--src/trans/codegen_c_structured.cpp54
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