summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-08-10 16:42:09 +0800
committerJohn Hodge <tpg@mutabah.net>2016-08-10 16:42:09 +0800
commitfd82195a241a49debb19d7a44442c66ab37d29bb (patch)
tree4c6e9ee757fd7fbe351d8014e8335b773286e886 /src
parent9744f22c07c28d1577de9ee7034e337c1cfc46de (diff)
downloadmrust-fd82195a241a49debb19d7a44442c66ab37d29bb.tar.gz
MIR - Start of match codegen
Diffstat (limited to 'src')
-rw-r--r--src/mir/from_hir.cpp107
1 files changed, 89 insertions, 18 deletions
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp
index 04dfff3f..4b663879 100644
--- a/src/mir/from_hir.cpp
+++ b/src/mir/from_hir.cpp
@@ -258,12 +258,57 @@ namespace {
// Build up a sorted vector of MIR pattern rules
TAGGED_UNION(PatternRule, Any,
(Any, struct {}),
- (Variant, unsigned int),
- (Value, ::MIR::Constant),
- (Optional, ::std::vector< PatternRule>)
+ (Variant, struct { unsigned int idx; ::std::vector<PatternRule> sub_rules; }),
+ (Value, ::MIR::Constant)
);
struct PatternRuleset {
::std::vector<PatternRule> m_rules;
+
+ static ::Ordering rule_is_before(const PatternRule& l, const PatternRule& r)
+ {
+ if( l.tag() != r.tag() ) {
+ // Any comes last, don't care about rest
+ if( l.tag() < r.tag() )
+ return ::OrdGreater;
+ else
+ return ::OrdLess;
+ }
+
+ TU_MATCHA( (l,r), (le,re),
+ (Any,
+ return ::OrdEqual;
+ ),
+ (Variant,
+ if( le.idx != re.idx )
+ return ::ord(le.idx, re.idx);
+ assert( le.sub_rules.size() == re.sub_rules.size() );
+ for(unsigned int i = 0; i < le.sub_rules.size(); i ++)
+ {
+ auto cmp = rule_is_before(le.sub_rules[i], re.sub_rules[i]);
+ if( cmp != ::OrdEqual )
+ return cmp;
+ }
+ return ::OrdEqual;
+ ),
+ (Value,
+ TODO(Span(), "Order PatternRule::Value");
+ )
+ )
+ throw "";
+ }
+ bool is_before(const PatternRuleset& other) const
+ {
+ assert( m_rules.size() == other.m_rules.size() );
+ for(unsigned int i = 0; i < m_rules.size(); i ++)
+ {
+ const auto& l = m_rules[i];
+ const auto& r = other.m_rules[i];
+ auto cmp = rule_is_before(l, r);
+ if( cmp != ::OrdEqual )
+ return cmp == ::OrdLess;
+ }
+ return false;
+ }
};
struct PatternRulesetBuilder {
::std::vector<PatternRule> m_rules;
@@ -347,14 +392,11 @@ namespace {
( BUG(sp, "Match not allowed, " << ty << " with " << pat); ),
(Any,
m_rules.push_back( PatternRule::make_Any({}) );
- m_rules.push_back( PatternRule::make_Optional({}) );
),
- (Value,
- ASSERT_BUG(sp, pe.val.is_Named(), "Value pattern for enum isn't _Named");
- TODO(sp, "Enum Value");
+ (EnumValue,
+ m_rules.push_back( PatternRule::make_Variant( {pe.binding_idx, {} } ) );
),
(EnumTuple,
- m_rules.push_back( PatternRule::make_Variant(pe.binding_idx) );
const auto& fields_def = pe.binding_ptr->m_variants[pe.binding_idx].second.as_Tuple();
PatternRulesetBuilder sub_builder;
for( unsigned int i = 0; i < pe.sub_patterns.size(); i ++ )
@@ -363,17 +405,15 @@ namespace {
auto subty = monomorphise_type(sp, pe.binding_ptr->m_params, e.path.m_data.as_Generic().m_params, fields_def[i].ent);
sub_builder.append_from( sp, subpat, subty );
}
- m_rules.push_back( PatternRule::make_Optional( mv$(sub_builder.m_rules) ) );
+ m_rules.push_back( PatternRule::make_Variant({ pe.binding_idx, mv$(sub_builder.m_rules) }) );
),
(EnumTupleWildcard,
- m_rules.push_back( PatternRule::make_Variant(pe.binding_idx) );
- m_rules.push_back( PatternRule::make_Optional({}) );
+ m_rules.push_back( PatternRule::make_Variant({ pe.binding_idx, {} }) );
),
(EnumStruct,
- m_rules.push_back( PatternRule::make_Variant(pe.binding_idx) );
PatternRulesetBuilder sub_builder;
TODO(sp, "Convert EnumStruct patterns");
- m_rules.push_back( PatternRule::make_Optional( mv$(sub_builder.m_rules) ) );
+ m_rules.push_back( PatternRule::make_Variant({ pe.binding_idx, mv$(sub_builder.m_rules) }) );
)
)
)
@@ -426,14 +466,14 @@ namespace {
};
// Map of arm index to ruleset
- ::std::vector< ::std::pair< unsigned int, PatternRuleset > > m_arm_rules;
+ ::std::vector< ::std::pair< unsigned int, PatternRuleset > > arm_rules;
for(const auto& arm : node.m_arms) {
auto idx = m_arm_rules.size();
for( const auto& pat : arm.m_patterns )
{
auto builder = PatternRulesetBuilder {};
builder.append_from(node.span(), pat, node.m_value->m_res_type);
- m_arm_rules.push_back( ::std::make_pair(idx, builder.into_ruleset()) );
+ arm_rules.push_back( ::std::make_pair(idx, builder.into_ruleset()) );
}
if( arm.m_cond ) {
@@ -442,11 +482,42 @@ namespace {
}
}
- // TODO: Sort ruleset such that wildcards go last (if there's no conditionals)
+ // Sort ruleset such that wildcards go last (if there's no conditionals)
+ // NOTE: Conditionals will break this, as you can have `x if x.is_foo() => {}, Enum::Foo ...`
+ ::std::sort( arm_rules.begin(), arm_rules.end(), [](const auto& l, const auto& r){ return l.second.is_before( r.second ); });
+
+ // Generate arm code
+ // - End the current block with a jump to the descision code (TODO: Can this be avoided while still being defensive?)
+ auto descision_block = this->new_bb_unlinked();
+ this->end_block( ::MIR::Terminator::Goto(descision_block) );
+
+ // - Create a result and next block
+ auto result_val = this->new_temporary(node.m_res_type);
+ auto next_block = this->new_bb_unlinked();
+
+ // - Generate code for arms.
+ ::std::vector< ::MIR::BasicBlockId> arm_blocks;
+ arm_blocks.reserve( arm_rules.size() );
+ for(unsigned int i = 0; i < arm_rules.size(); i ++)
+ {
+ const auto& arm = node.m_arms[i];
+ arm_blocks.push_back( this->new_bb_unlinked() );
+ this->set_cur_block(arm_blocks.back());
+
+ this->visit_node_ptr(arm.m_code);
+
+ this->push_stmt_assign( result_val.clone(), this->get_result(arm.m_code->span()) );
+ // TODO: Drop unused bindings introduced by this arm.
+ this->end_block( ::MIR::Terminator::Goto(next_block) );
+ }
- // TODO: Generate decision tree based on ruleset
+ // Generate decision code based on ruleset and type
+ this->set_cur_block(descision_block);
TODO(node.span(), "Convert match into MIR using ruleset");
+
+ this->set_cur_block(next_block);
+ this->set_result( mv$(result_val) );
}
} // ExprNode_Match
@@ -478,7 +549,7 @@ namespace {
}
else
{
- // TODO: Assign `()` to the result
+ // Assign `()` to the result
this->push_stmt_assign( result_val.clone(), ::MIR::RValue::make_Tuple({}) );
this->end_block( ::MIR::Terminator::make_Goto(next_block) );
}