summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/mir/dump.cpp329
-rw-r--r--src/mir/operations.hpp2
-rw-r--r--src/mir/optimise.cpp32
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 )