diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mir/dump.cpp | 329 | ||||
-rw-r--r-- | src/mir/operations.hpp | 2 | ||||
-rw-r--r-- | src/mir/optimise.cpp | 32 |
3 files changed, 209 insertions, 154 deletions
diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index 166f07ba..bbacbbf3 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -8,156 +8,19 @@ #include "main_bindings.hpp" #include <hir/visitor.hpp> #include "mir.hpp" +#include "operations.hpp" namespace { - class TreeVisitor: - public ::HIR::Visitor + class MirDumper { ::std::ostream& m_os; - unsigned int m_indent_level; - bool m_short_item_name = false; - + unsigned int m_indent_level; public: - TreeVisitor(::std::ostream& os): + MirDumper(::std::ostream& os, unsigned int il): m_os(os), - m_indent_level(0) - { - } - - void visit_type_impl(::HIR::TypeImpl& impl) override - { - m_short_item_name = true; - - m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << impl.m_type << "\n"; - if( ! impl.m_params.m_bounds.empty() ) - { - m_os << indent() << " " << impl.m_params.fmt_bounds() << "\n"; - } - m_os << indent() << "{\n"; - inc_indent(); - ::HIR::Visitor::visit_type_impl(impl); - dec_indent(); - m_os << indent() << "}\n"; - - m_short_item_name = false; - } - virtual void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override - { - m_short_item_name = true; - - m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << "\n"; - if( ! impl.m_params.m_bounds.empty() ) - { - m_os << indent() << " " << impl.m_params.fmt_bounds() << "\n"; - } - m_os << indent() << "{\n"; - inc_indent(); - ::HIR::Visitor::visit_trait_impl(trait_path, impl); - dec_indent(); - m_os << indent() << "}\n"; - - m_short_item_name = false; - } - void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override - { - m_short_item_name = true; - - m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << (impl.is_positive ? "" : "!") << trait_path << impl.m_trait_args << " for " << impl.m_type << "\n"; - if( ! impl.m_params.m_bounds.empty() ) - { - m_os << indent() << " " << impl.m_params.fmt_bounds() << "\n"; - } - m_os << indent() << "{ }\n"; - - m_short_item_name = false; - } - - // - Type Items - void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override - { - m_short_item_name = true; - - m_os << indent() << "trait " << p << item.m_params.fmt_args() << "\n"; - if( ! item.m_params.m_bounds.empty() ) - { - m_os << indent() << " " << item.m_params.fmt_bounds() << "\n"; - } - m_os << indent() << "{\n"; - inc_indent(); - ::HIR::Visitor::visit_trait(p, item); - dec_indent(); - m_os << indent() << "}\n"; - - m_short_item_name = false; - } - - void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override - { - m_os << indent(); - if( item.m_const ) - m_os << "const "; - if( item.m_unsafe ) - m_os << "unsafe "; - if( item.m_abi != ABI_RUST ) - m_os << "extern \"" << item.m_abi << "\" "; - m_os << "fn "; - if( m_short_item_name ) - m_os << p.get_name(); - else - m_os << p; - m_os << item.m_params.fmt_args() << "("; - for(unsigned int i = 0; i < item.m_args.size(); i ++) - { - if( i == 0 && item.m_args[i].first.m_binding.m_name == "self" ) { - m_os << "self="; - } - m_os << "arg$" << i << ": " << item.m_args[i].second << ", "; - } - m_os << ") -> " << item.m_return << "\n"; - if( ! item.m_params.m_bounds.empty() ) - { - m_os << indent() << " " << item.m_params.fmt_bounds() << "\n"; - } - - if( item.m_code ) - { - m_os << indent() << "{\n"; - inc_indent(); - this->dump_mir(*item.m_code.m_mir); - dec_indent(); - m_os << indent() << "}\n"; - } - else - { - m_os << indent() << " ;\n"; - } - } - void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override - { - m_os << indent(); - m_os << "static "; - if( m_short_item_name ) - m_os << p.get_name(); - else - m_os << p; - m_os << ": " << item.m_type; - if( item.m_value ) - { - inc_indent(); - m_os << "= {\n"; - inc_indent(); - this->dump_mir(*item.m_value.m_mir); - dec_indent(); - m_os << indent() << "} /* = " << item.m_value_res << "*/;\n"; - dec_indent(); - } - else - { - m_os << ";\n"; - } - } - + m_indent_level(il) + {} void dump_mir(const ::MIR::Function& fcn) { @@ -178,7 +41,7 @@ namespace { for(unsigned int i = 0; i < fcn.blocks.size(); i ++) { const auto& block = fcn.blocks[i]; - DEBUG("BB" << i); + //DEBUG("BB" << i); m_os << indent() << "bb" << i << ": {\n"; inc_indent(); @@ -188,11 +51,11 @@ namespace { TU_MATCHA( (stmt), (e), (Assign, - DEBUG("- Assign " << e.dst << " = " << e.src); + //DEBUG("- Assign " << e.dst << " = " << e.src); m_os << FMT_M(e.dst) << " = " << FMT_M(e.src) << ";\n"; ), (Asm, - DEBUG("- Asm"); + //DEBUG("- Asm"); m_os << "("; for(const auto& v : e.outputs) m_os << FMT_M(v.second) << ","; @@ -220,7 +83,7 @@ namespace { m_os << ";\n"; ), (Drop, - DEBUG("- DROP " << e.slot); + //DEBUG("- DROP " << e.slot); m_os << "drop(" << FMT_M(e.slot); switch( e.kind ) { @@ -477,6 +340,172 @@ namespace { ) ) } + + private: + RepeatLitStr indent() const { + return RepeatLitStr { " ", static_cast<int>(m_indent_level) }; + } + void inc_indent() { + m_indent_level ++; + } + void dec_indent() { + m_indent_level --; + } + }; + + void dump_mir(::std::ostream& os, unsigned int il, const ::MIR::Function& fcn) + { + MirDumper md { os, il }; + md.dump_mir(fcn); + } + + class TreeVisitor: + public ::HIR::Visitor + { + ::std::ostream& m_os; + unsigned int m_indent_level; + bool m_short_item_name = false; + + public: + TreeVisitor(::std::ostream& os): + m_os(os), + m_indent_level(0) + { + } + + void visit_type_impl(::HIR::TypeImpl& impl) override + { + m_short_item_name = true; + + m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << impl.m_type << "\n"; + if( ! impl.m_params.m_bounds.empty() ) + { + m_os << indent() << " " << impl.m_params.fmt_bounds() << "\n"; + } + m_os << indent() << "{\n"; + inc_indent(); + ::HIR::Visitor::visit_type_impl(impl); + dec_indent(); + m_os << indent() << "}\n"; + + m_short_item_name = false; + } + virtual void visit_trait_impl(const ::HIR::SimplePath& trait_path, ::HIR::TraitImpl& impl) override + { + m_short_item_name = true; + + m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << "\n"; + if( ! impl.m_params.m_bounds.empty() ) + { + m_os << indent() << " " << impl.m_params.fmt_bounds() << "\n"; + } + m_os << indent() << "{\n"; + inc_indent(); + ::HIR::Visitor::visit_trait_impl(trait_path, impl); + dec_indent(); + m_os << indent() << "}\n"; + + m_short_item_name = false; + } + void visit_marker_impl(const ::HIR::SimplePath& trait_path, ::HIR::MarkerImpl& impl) override + { + m_short_item_name = true; + + m_os << indent() << "impl" << impl.m_params.fmt_args() << " " << (impl.is_positive ? "" : "!") << trait_path << impl.m_trait_args << " for " << impl.m_type << "\n"; + if( ! impl.m_params.m_bounds.empty() ) + { + m_os << indent() << " " << impl.m_params.fmt_bounds() << "\n"; + } + m_os << indent() << "{ }\n"; + + m_short_item_name = false; + } + + // - Type Items + void visit_trait(::HIR::ItemPath p, ::HIR::Trait& item) override + { + m_short_item_name = true; + + m_os << indent() << "trait " << p << item.m_params.fmt_args() << "\n"; + if( ! item.m_params.m_bounds.empty() ) + { + m_os << indent() << " " << item.m_params.fmt_bounds() << "\n"; + } + m_os << indent() << "{\n"; + inc_indent(); + ::HIR::Visitor::visit_trait(p, item); + dec_indent(); + m_os << indent() << "}\n"; + + m_short_item_name = false; + } + + void visit_function(::HIR::ItemPath p, ::HIR::Function& item) override + { + m_os << indent(); + if( item.m_const ) + m_os << "const "; + if( item.m_unsafe ) + m_os << "unsafe "; + if( item.m_abi != ABI_RUST ) + m_os << "extern \"" << item.m_abi << "\" "; + m_os << "fn "; + if( m_short_item_name ) + m_os << p.get_name(); + else + m_os << p; + m_os << item.m_params.fmt_args() << "("; + for(unsigned int i = 0; i < item.m_args.size(); i ++) + { + if( i == 0 && item.m_args[i].first.m_binding.m_name == "self" ) { + m_os << "self="; + } + m_os << "arg$" << i << ": " << item.m_args[i].second << ", "; + } + m_os << ") -> " << item.m_return << "\n"; + if( ! item.m_params.m_bounds.empty() ) + { + m_os << indent() << " " << item.m_params.fmt_bounds() << "\n"; + } + + if( item.m_code ) + { + m_os << indent() << "{\n"; + inc_indent(); + dump_mir(m_os, m_indent_level, *item.m_code.m_mir); + dec_indent(); + m_os << indent() << "}\n"; + } + else + { + m_os << indent() << " ;\n"; + } + } + void visit_static(::HIR::ItemPath p, ::HIR::Static& item) override + { + m_os << indent(); + m_os << "static "; + if( m_short_item_name ) + m_os << p.get_name(); + else + m_os << p; + m_os << ": " << item.m_type; + if( item.m_value ) + { + inc_indent(); + m_os << "= {\n"; + inc_indent(); + dump_mir(m_os, m_indent_level, *item.m_value.m_mir); + dec_indent(); + m_os << indent() << "} /* = " << item.m_value_res << "*/;\n"; + dec_indent(); + } + else + { + m_os << ";\n"; + } + } + private: RepeatLitStr indent() const { return RepeatLitStr { " ", static_cast<int>(m_indent_level) }; @@ -497,3 +526,9 @@ void MIR_Dump(::std::ostream& sink, const ::HIR::Crate& crate) tv.visit_crate( const_cast< ::HIR::Crate&>(crate) ); } +void MIR_Dump_Fcn(::std::ostream& sink, const ::MIR::Function& fcn, unsigned int il) +{ + MirDumper md { sink, il }; + md.dump_mir(fcn); +} + diff --git a/src/mir/operations.hpp b/src/mir/operations.hpp index deef8830..cdc9c00b 100644 --- a/src/mir/operations.hpp +++ b/src/mir/operations.hpp @@ -14,3 +14,5 @@ extern void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPat extern void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type); // Optimise the MIR extern void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type); + +extern void MIR_Dump_Fcn(::std::ostream& sink, const ::MIR::Function& fcn, unsigned int il=0); diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 7868eb30..edaf0d5d 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -152,7 +152,7 @@ namespace { (SetDropFlag, ), (Drop, - rv |= visit_mir_lvalue_mut(e.slot, false, cb); + rv |= visit_mir_lvalue_mut(e.slot, true, cb); ) ) return rv; @@ -379,6 +379,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path { // Apply cleanup again (as monomorpisation in inlining may have exposed a vtable call) MIR_Cleanup(resolve, path, fcn, args, ret_type); + //MIR_Dump_Fcn(::std::cout, fcn); change_happened = true; } @@ -392,9 +393,19 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // >> Combine Duplicate Blocks change_happened |= MIR_Optimise_UnifyBlocks(state, fcn) || change_happened; + #if 0 + if( change_happened ) + { + MIR_Dump_Fcn(::std::cout, fcn); + MIR_Validate(resolve, path, fcn, args, ret_type); + } + #endif } while( change_happened ); + #if 0 + MIR_Dump_Fcn(::std::cout, fcn); + #endif // DEFENCE: Run validation _before_ GC (so validation errors refer to the pre-gc numbers) MIR_Validate(resolve, path, fcn, args, ret_type); // GC pass on blocks and variables @@ -503,7 +514,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) { struct H { - static bool can_inline(const ::MIR::Function& fcn) + static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn) { if( fcn.blocks.size() == 1 ) { @@ -511,12 +522,17 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) } else if( fcn.blocks.size() == 3 && fcn.blocks[0].terminator.is_Call() ) { + const auto& blk0_te = fcn.blocks[0].terminator.as_Call(); if( !(fcn.blocks[1].terminator.is_Diverge() || fcn.blocks[1].terminator.is_Return()) ) return false; if( !(fcn.blocks[2].terminator.is_Diverge() || fcn.blocks[2].terminator.is_Return()) ) return false; if( fcn.blocks[0].statements.size() + fcn.blocks[1].statements.size() + fcn.blocks[2].statements.size() > 10 ) return false; + // Detect and avoid simple recursion. + // - This won't detect mutual recursion - that also needs prevention. + if( blk0_te.fcn.is_Path() && blk0_te.fcn.as_Path() == path ) + return false; return true; } else @@ -816,9 +832,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) { if( ! te->fcn.is_Path() ) continue ; + const auto& path = te->fcn.as_Path(); Cloner cloner { state.sp, state.m_resolve, *te }; - const auto* called_mir = get_called_mir(state, te->fcn.as_Path(), cloner.params); + const auto* called_mir = get_called_mir(state, path, cloner.params); if( !called_mir ) continue ; @@ -826,9 +843,9 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) // Inline IF: // - First BB ends with a call and total count is 3 // - Statement count smaller than 10 - if( ! H::can_inline(*called_mir) ) + if( ! H::can_inline(path, *called_mir) ) continue ; - TRACE_FUNCTION_F("Inline " << te->fcn.as_Path()); + TRACE_FUNCTION_F("Inline " << path); // Monomorph values and append cloner.var_base = fcn.named_variables.size(); @@ -867,6 +884,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) // -------------------------------------------------------------------- bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn) { + TRACE_FUNCTION; ::std::vector<bool> replacable( fcn.temporaries.size() ); // 1. Enumerate which (if any) temporaries share the same type { @@ -1680,8 +1698,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F } // --- Eliminate `... = Use(tmp)` (propagate lvalues upwards) { - // TODO - //::std::map< ::MIR::LValue, ::MIR::RValue> replacements; + DEBUG("- Move upwards"); for(auto& block : fcn.blocks) { for(auto it = block.statements.begin(); it != block.statements.end(); ++it) @@ -1750,6 +1767,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F // > Ensure that the target of the above assignment isn't used in the intervening statements // > Replace function call result value with target of assignment { + DEBUG("- Returns"); for(auto& block : fcn.blocks) { if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD ) |