summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Hodge <tpg@mutabah.net>2016-12-31 18:47:32 +0800
committerJohn Hodge <tpg@mutabah.net>2016-12-31 18:47:32 +0800
commit936db1595619a25fb4a7ccf902e9e8af5852484e (patch)
treefb1f5db17bb880d437a88c2ad68c2a48c11db0d9 /src
parentad264bcc69545a2695115b72fdd286c09df062bd (diff)
downloadmrust-936db1595619a25fb4a7ccf902e9e8af5852484e.tar.gz
MIR Optimise - Move call output to after assignment propagation
Diffstat (limited to 'src')
-rw-r--r--src/mir/optimise.cpp109
1 files changed, 55 insertions, 54 deletions
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp
index dac45de5..4a976662 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -368,60 +368,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// - Any lvalues in the source lvalue must not be mutated between the source assignment and the usage.
// > This includes mutation, borrowing, or moving.
{
- // 1. Function returns (reverse propagate)
- for(auto& block : fcn.blocks)
- {
- if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD )
- continue ;
-
- // If the terminator is a call that writes to a 1:1 value, replace the destination value with the eventual destination (if that value isn't used in the meantime)
- if( block.terminator.is_Call() )
- {
- // TODO: What if the destination located here is a 1:1 and its usage is listed to be replaced by the return value.
- auto& e = block.terminator.as_Call();
- // TODO: Support variables too?
- if( !e.ret_val.is_Temporary() )
- continue ;
- const auto& vu = val_uses.tmp_uses[e.ret_val.as_Temporary().idx];
- if( !( vu.read == 1 && vu.write == 1 ) )
- continue ;
-
- // Iterate the target block, looking for where this value is used.
- const ::MIR::LValue* new_dst = nullptr;
- auto& blk2 = fcn.blocks.at(e.ret_block);
- for(const auto& stmt : blk2.statements)
- {
- if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() && stmt.as_Assign().src.as_Use() == e.ret_val ) {
- new_dst = &stmt.as_Assign().dst;
- break;
- }
- }
-
- // Ensure that the new destination value isn't used before assignment
- if( new_dst )
- {
- auto lvalue_impacts_dst = [&](const ::MIR::LValue& lv) {
- return visit_mir_lvalue(*new_dst, true, [&](const auto& slv, bool ) { return lv == slv; });
- };
- for(auto it = blk2.statements.begin(); it != blk2.statements.end(); ++ it)
- {
- const auto& stmt = *it;
- if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() && stmt.as_Assign().src.as_Use() == e.ret_val )
- {
- DEBUG("- Replace function return " << e.ret_val << " with " << *new_dst);
- e.ret_val = new_dst->clone();
- it = blk2.statements.erase(it);
- break;
- }
- if( visit_mir_lvalues(stmt, [&](const auto& lv, bool is_write){ return lv == *new_dst || (is_write && lvalue_impacts_dst(lv)); }) )
- {
- break;
- }
- }
- }
- }
- }
- // 2. Assignments (forward propagate)
+ // 1. Assignments (forward propagate)
::std::map< ::MIR::LValue, ::MIR::LValue> replacements;
for(const auto& block : fcn.blocks)
{
@@ -605,6 +552,60 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
++it;
}
}
+
+ // 2. Function returns (reverse propagate)
+ for(auto& block : fcn.blocks)
+ {
+ if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD )
+ continue ;
+
+ // If the terminator is a call that writes to a 1:1 value, replace the destination value with the eventual destination (if that value isn't used in the meantime)
+ if( block.terminator.is_Call() )
+ {
+ // TODO: What if the destination located here is a 1:1 and its usage is listed to be replaced by the return value.
+ auto& e = block.terminator.as_Call();
+ // TODO: Support variables too?
+ if( !e.ret_val.is_Temporary() )
+ continue ;
+ const auto& vu = val_uses.tmp_uses[e.ret_val.as_Temporary().idx];
+ if( !( vu.read == 1 && vu.write == 1 ) )
+ continue ;
+
+ // Iterate the target block, looking for where this value is used.
+ const ::MIR::LValue* new_dst = nullptr;
+ auto& blk2 = fcn.blocks.at(e.ret_block);
+ for(const auto& stmt : blk2.statements)
+ {
+ if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() && stmt.as_Assign().src.as_Use() == e.ret_val ) {
+ new_dst = &stmt.as_Assign().dst;
+ break;
+ }
+ }
+
+ // Ensure that the new destination value isn't used before assignment
+ if( new_dst )
+ {
+ auto lvalue_impacts_dst = [&](const ::MIR::LValue& lv) {
+ return visit_mir_lvalue(*new_dst, true, [&](const auto& slv, bool ) { return lv == slv; });
+ };
+ for(auto it = blk2.statements.begin(); it != blk2.statements.end(); ++ it)
+ {
+ const auto& stmt = *it;
+ if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() && stmt.as_Assign().src.as_Use() == e.ret_val )
+ {
+ DEBUG("- Replace function return " << e.ret_val << " with " << *new_dst);
+ e.ret_val = new_dst->clone();
+ it = blk2.statements.erase(it);
+ break;
+ }
+ if( visit_mir_lvalues(stmt, [&](const auto& lv, bool is_write){ return lv == *new_dst || (is_write && lvalue_impacts_dst(lv)); }) )
+ {
+ break;
+ }
+ }
+ }
+ }
+ }
}
// GC pass on blocks and variables