summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir/deserialise.cpp31
-rw-r--r--src/hir/serialise.cpp7
-rw-r--r--src/hir/serialise_lowlevel.hpp6
-rw-r--r--src/hir_typeck/expr_cs.cpp3
-rw-r--r--src/mir/from_hir_match.cpp102
-rw-r--r--src/trans/codegen_c.cpp51
6 files changed, 149 insertions, 51 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index 968cf8d3..c5867542 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -325,6 +325,8 @@ namespace {
::MIR::BasicBlock deserialise_mir_basicblock();
::MIR::Statement deserialise_mir_statement();
::MIR::Terminator deserialise_mir_terminator();
+ ::MIR::Terminator deserialise_mir_terminator_();
+ ::MIR::SwitchValues deserialise_mir_switchvalues();
::MIR::CallTarget deserialise_mir_calltarget();
::MIR::Param deserialise_mir_param()
@@ -1070,8 +1072,13 @@ namespace {
}
::MIR::Terminator HirDeserialiser::deserialise_mir_terminator()
{
- TRACE_FUNCTION;
-
+ ::MIR::Terminator rv;
+ TRACE_FUNCTION_FR("", rv);
+ rv = this->deserialise_mir_terminator_();
+ return rv;
+ }
+ ::MIR::Terminator HirDeserialiser::deserialise_mir_terminator_()
+ {
switch( m_in.read_tag() )
{
#define _(x, ...) case ::MIR::Terminator::TAG_##x: return ::MIR::Terminator::make_##x( __VA_ARGS__ );
@@ -1089,6 +1096,12 @@ namespace {
deserialise_mir_lvalue(),
deserialise_vec_c<unsigned int>([&](){ return static_cast<unsigned int>(m_in.read_count()); })
})
+ _(SwitchValue, {
+ deserialise_mir_lvalue(),
+ static_cast<unsigned int>(m_in.read_count()),
+ deserialise_vec_c<unsigned int>([&](){ return static_cast<unsigned int>(m_in.read_count()); }),
+ deserialise_mir_switchvalues()
+ })
_(Call, {
static_cast<unsigned int>(m_in.read_count()),
static_cast<unsigned int>(m_in.read_count()),
@@ -1101,6 +1114,20 @@ namespace {
throw "";
}
}
+ ::MIR::SwitchValues HirDeserialiser::deserialise_mir_switchvalues()
+ {
+ TRACE_FUNCTION;
+ switch(m_in.read_tag())
+ {
+ #define _(x, ...) case ::MIR::SwitchValues::TAG_##x: return ::MIR::SwitchValues::make_##x( __VA_ARGS__ );
+ _(Unsigned, deserialise_vec_c<uint64_t>([&](){ return m_in.read_u64c(); }))
+ _(Signed , deserialise_vec_c< int64_t>([&](){ return m_in.read_i64c(); }))
+ _(String , deserialise_vec<::std::string>())
+ #undef _
+ default:
+ throw "";
+ }
+ }
::MIR::CallTarget HirDeserialiser::deserialise_mir_calltarget()
{
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index e200a39e..d80154ed 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -81,6 +81,11 @@ namespace {
// m_out.write_count(val);
//}
+ void serialise(bool v) { m_out.write_bool(v); };
+ void serialise(unsigned int v) { m_out.write_count(v); };
+ void serialise(uint64_t v) { m_out.write_u64c(v); };
+ void serialise(int64_t v) { m_out.write_i64c(v); };
+
void serialise_type(const ::HIR::TypeRef& ty)
{
m_out.write_tag( ty.m_data.tag() );
@@ -791,8 +796,6 @@ namespace {
)
}
- void serialise(unsigned int v) { m_out.write_count(v); };
-
void serialise(const ::HIR::Linkage& linkage)
{
//m_out.write_tag( static_cast<int>(linkage.type) );
diff --git a/src/hir/serialise_lowlevel.hpp b/src/hir/serialise_lowlevel.hpp
index de913432..6be8ff8c 100644
--- a/src/hir/serialise_lowlevel.hpp
+++ b/src/hir/serialise_lowlevel.hpp
@@ -49,6 +49,9 @@ public:
};
this->write(buf, 8);
}
+ void write_i64(int64_t v) {
+ write_u64(static_cast<uint64_t>(v));
+ }
// Variable-length encoded u64 (for array sizes)
void write_u64c(uint64_t v) {
if( v < (1<<7) ) {
@@ -184,6 +187,9 @@ public:
| (static_cast<uint64_t>(buf[7]) << 56)
;
}
+ int64_t read_i64() {
+ return static_cast<int64_t>(read_u64());
+ }
// Variable-length encoded u64 (for array sizes)
uint64_t read_u64c() {
auto v = read_u8();
diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp
index abca0507..d44645cb 100644
--- a/src/hir_typeck/expr_cs.cpp
+++ b/src/hir_typeck/expr_cs.cpp
@@ -4360,11 +4360,14 @@ namespace {
}
// Can't Unsize to a known-Sized type.
+ // BUT! Can do a Deref coercion to a Sized type.
+ #if 0
if( dst.m_data.is_Infer() && dst.m_data.as_Infer().index < context.m_ivars_sized.size() && context.m_ivars_sized.at( dst.m_data.as_Infer().index ) )
{
DEBUG("Can't unsize to known-Sized type");
return CoerceResult::Equality;
}
+ #endif
// Handle ivars specially
if(dst.m_data.is_Infer() && src.m_data.is_Infer())
diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp
index 61548fd2..275c0d10 100644
--- a/src/mir/from_hir_match.cpp
+++ b/src/mir/from_hir_match.cpp
@@ -2871,14 +2871,53 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
case ::HIR::CoreType::U128:
case ::HIR::CoreType::Usize:
+ case ::HIR::CoreType::Char:
+ if( rules.size() == 1 )
+ {
+ // Special case, single option, equality only
+ const auto& r = rules[0][0][ofs];
+ ASSERT_BUG(sp, r.is_Value(), "Matching without _Value pattern - " << r.tag_str());
+ const auto& re = r.as_Value();
+ auto test_val = ::MIR::Param(re.clone());
+ auto cmp_lval = m_builder.get_rval_in_if_cond(sp, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, mv$(test_val) }));
+ m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), arm_targets[0], def_blk }) );
+ }
+ else
+ {
+ // NOTE: Rules are currently sorted
+ // TODO: If there are Constant::Const values in the list, they need to come first! (with equality checks)
+
+ ::std::vector< uint64_t> values;
+ ::std::vector< ::MIR::BasicBlockId> targets;
+ size_t tgt_ofs = 0;
+ for(size_t i = 0; i < rules.size(); i++)
+ {
+ for(size_t j = 1; j < rules[i].size(); j ++)
+ ASSERT_BUG(sp, arm_targets[tgt_ofs] == arm_targets[tgt_ofs+j], "Mismatched target blocks for Value match");
+
+ const auto& r = rules[i][0][ofs];
+ ASSERT_BUG(sp, r.is_Value(), "Matching without _Value pattern - " << r.tag_str());
+ const auto& re = r.as_Value();
+ if(re.is_Const())
+ TODO(sp, "Handle Constant::Const in match");
+
+ values.push_back( re.as_Uint().v );
+ targets.push_back( arm_targets[tgt_ofs] );
+
+ tgt_ofs += rules[i].size();
+ }
+ m_builder.end_block( ::MIR::Terminator::make_SwitchValue({
+ mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values))
+ }) );
+ }
+ break;
+
case ::HIR::CoreType::I8:
case ::HIR::CoreType::I16:
case ::HIR::CoreType::I32:
case ::HIR::CoreType::I64:
case ::HIR::CoreType::I128:
case ::HIR::CoreType::Isize:
-
- case ::HIR::CoreType::Char:
if( rules.size() == 1 )
{
// Special case, single option, equality only
@@ -2891,12 +2930,11 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
}
else
{
- // TODO: Add a SwitchInt terminator for use with this. (Or just a SwitchVal terminator?)
-
// NOTE: Rules are currently sorted
// TODO: If there are Constant::Const values in the list, they need to come first! (with equality checks)
- // Does a sorted linear search. Binary search would be nicer but is harder to implement.
+ ::std::vector< int64_t> values;
+ ::std::vector< ::MIR::BasicBlockId> targets;
size_t tgt_ofs = 0;
for(size_t i = 0; i < rules.size(); i++)
{
@@ -2909,33 +2947,17 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
if(re.is_Const())
TODO(sp, "Handle Constant::Const in match");
- // IF v < tst : def_blk
- // Skip if the previous value was the imediat predecesor
- bool is_succ = i != 0 && (re.is_Uint()
- ? re.as_Uint().v == rules[i-1][0][ofs].as_Value().as_Uint().v + 1
- : re.as_Int().v == rules[i-1][0][ofs].as_Value().as_Int().v + 1
- );
- if( !is_succ )
- {
- auto cmp_eq_blk = m_builder.new_bb_unlinked();
- auto cmp_lval_lt = this->push_compare(val.clone(), ::MIR::eBinOp::LT, ::MIR::Param(re.clone()));
- m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_lt), def_blk, cmp_eq_blk }) );
- m_builder.set_cur_block(cmp_eq_blk);
- }
-
- // IF v == tst : target
- {
- auto next_cmp_blk = m_builder.new_bb_unlinked();
- auto cmp_lval_eq = this->push_compare( val.clone(), ::MIR::eBinOp::EQ, ::MIR::Param(re.clone()) );
- m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_eq), arm_targets[tgt_ofs], next_cmp_blk }) );
- m_builder.set_cur_block(next_cmp_blk);
- }
+ values.push_back( re.as_Int().v );
+ targets.push_back( arm_targets[tgt_ofs] );
tgt_ofs += rules[i].size();
}
- m_builder.end_block( ::MIR::Terminator::make_Goto(def_blk) );
+ m_builder.end_block( ::MIR::Terminator::make_SwitchValue({
+ mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values))
+ }) );
}
break;
+
case ::HIR::CoreType::F32:
case ::HIR::CoreType::F64: {
// NOTE: Rules are currently sorted
@@ -2976,8 +2998,9 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
// Remove the deref on the &str
auto oval = mv$(val);
auto val = mv$(*oval.as_Deref().val);
- // NOTE: Rules are currently sorted
- // TODO: If there are Constant::Const values in the list, they need to come first!
+
+ ::std::vector< ::MIR::BasicBlockId> targets;
+ ::std::vector< ::std::string> values;
size_t tgt_ofs = 0;
for(size_t i = 0; i < rules.size(); i++)
{
@@ -2990,25 +3013,14 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
if(re.is_Const())
TODO(sp, "Handle Constant::Const in match");
- // IF v < tst : def_blk
- {
- auto cmp_eq_blk = m_builder.new_bb_unlinked();
- auto cmp_lval_lt = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::LT, ::MIR::Param(re.clone()) }));
- m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_lt), def_blk, cmp_eq_blk }) );
- m_builder.set_cur_block(cmp_eq_blk);
- }
-
- // IF v == tst : target
- {
- auto next_cmp_blk = m_builder.new_bb_unlinked();
- auto cmp_lval_eq = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ val.clone(), ::MIR::eBinOp::EQ, ::MIR::Param(re.clone()) }));
- m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_eq), arm_targets[tgt_ofs], next_cmp_blk }) );
- m_builder.set_cur_block(next_cmp_blk);
- }
+ targets.push_back( arm_targets[tgt_ofs] );
+ values.push_back( re.as_StaticString() );
tgt_ofs += rules[i].size();
}
- m_builder.end_block( ::MIR::Terminator::make_Goto(def_blk) );
+ m_builder.end_block( ::MIR::Terminator::make_SwitchValue({
+ mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values))
+ }) );
break;
}
}
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 43a0c103..082d461d 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -1871,7 +1871,9 @@ namespace {
bb_use_counts[t] ++;
),
(SwitchValue,
- MIR_TODO(mir_res, "SwitchValue in C codegen");
+ for(const auto& t : te.targets)
+ bb_use_counts[t] ++;
+ bb_use_counts[te.def_target] ++;
),
(Call,
bb_use_counts[te.ret_block] ++;
@@ -2005,7 +2007,52 @@ namespace {
}
),
(SwitchValue,
- MIR_TODO(mir_res, "SwitchValue in C codegen");
+ if( const auto* ve = e.values.opt_String() ) {
+ assert(ve->size() == e.targets.size());
+ m_of << "\t{\n";
+ m_of << "\t\tint cmp;\n";
+ m_of << "\t\t";
+ for(size_t i = 0; i < e.targets.size(); i++)
+ {
+ const auto& v = (*ve)[i];
+ m_of << "if( (cmp = slice_cmp("; emit_lvalue(e.val); m_of << ", make_sliceptr("; this->print_escaped_string(v); m_of << "," << v.size() << "))) < 0)\n";
+ m_of << "\t\t\tgoto bb" << e.def_target << ";\n";
+ m_of << "\t\telse if( cmp == 0 )\n";
+ m_of << "\t\t\tgoto bb" << e.targets[i] << ";\n";
+ m_of << "\t\telse ";
+ }
+ m_of << "\n\t\t\tgoto bb" << e.def_target << ";\n";
+
+ m_of << "\t}\n";
+ }
+ else if( const auto* ve = e.values.opt_Unsigned() ) {
+ assert(ve->size() == e.targets.size());
+ m_of << "\tswitch("; emit_lvalue(e.val); m_of << ") {\n";
+ for(size_t i = 0; i < e.targets.size(); i++)
+ {
+ m_of << "\t\tcase " << (*ve)[i] << "ull: goto bb" << e.targets[i] << ";\n";
+ }
+ m_of << "\t\tdefault: goto bb" << e.def_target << ";\n";
+ m_of << "\t}\n";
+ }
+ else if( const auto* ve = e.values.opt_Signed() ) {
+ assert(ve->size() == e.targets.size());
+ m_of << "\tswitch("; emit_lvalue(e.val); m_of << ") {\n";
+ for(size_t i = 0; i < e.targets.size(); i++)
+ {
+ m_of << "\t\tcase ";
+ if( (*ve)[i] == INT64_MIN )
+ m_of << "INT64_MIN";
+ else
+ m_of << (*ve)[i] << "ull";
+ m_of << ": goto bb" << e.targets[i] << ";\n";
+ }
+ m_of << "\t\tdefault: goto bb" << e.def_target << ";\n";
+ m_of << "\t}\n";
+ }
+ else {
+ MIR_BUG(mir_res, "SwitchValue with unknown value type - " << e.values.tag_str());
+ }
),
(Call,
emit_term_call(mir_res, e, 1);