diff options
-rw-r--r-- | src/hir/deserialise.cpp | 31 | ||||
-rw-r--r-- | src/hir/serialise.cpp | 7 | ||||
-rw-r--r-- | src/hir/serialise_lowlevel.hpp | 6 | ||||
-rw-r--r-- | src/hir_typeck/expr_cs.cpp | 3 | ||||
-rw-r--r-- | src/mir/from_hir_match.cpp | 102 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 51 |
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); |