summaryrefslogtreecommitdiff
path: root/src/mir/optimise.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mir/optimise.cpp')
-rw-r--r--src/mir/optimise.cpp193
1 files changed, 135 insertions, 58 deletions
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp
index d483869c..f5a4236f 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -75,60 +75,71 @@ namespace {
return visit_mir_lvalue_mut( const_cast<::MIR::LValue&>(lv), is_write, [&](auto& v, bool im) { return cb(v,im); } );
}
+ bool visit_mir_lvalues_mut(::MIR::RValue& rval, ::std::function<bool(::MIR::LValue& , bool)> cb)
+ {
+ bool rv = false;
+ TU_MATCHA( (rval), (se),
+ (Use,
+ rv |= visit_mir_lvalue_mut(se, false, cb);
+ ),
+ (Constant,
+ ),
+ (SizedArray,
+ rv |= visit_mir_lvalue_mut(se.val, false, cb);
+ ),
+ (Borrow,
+ rv |= visit_mir_lvalue_mut(se.val, (se.type != ::HIR::BorrowType::Shared), cb);
+ ),
+ (Cast,
+ rv |= visit_mir_lvalue_mut(se.val, false, cb);
+ ),
+ (BinOp,
+ rv |= visit_mir_lvalue_mut(se.val_l, false, cb);
+ rv |= visit_mir_lvalue_mut(se.val_r, false, cb);
+ ),
+ (UniOp,
+ rv |= visit_mir_lvalue_mut(se.val, false, cb);
+ ),
+ (DstMeta,
+ rv |= visit_mir_lvalue_mut(se.val, false, cb);
+ ),
+ (DstPtr,
+ rv |= visit_mir_lvalue_mut(se.val, false, cb);
+ ),
+ (MakeDst,
+ // TODO: Would prefer a flag to indicate "move"
+ rv |= visit_mir_lvalue_mut(se.ptr_val, false, cb);
+ rv |= visit_mir_lvalue_mut(se.meta_val, false, cb);
+ ),
+ (Tuple,
+ for(auto& v : se.vals)
+ rv |= visit_mir_lvalue_mut(v, false, cb);
+ ),
+ (Array,
+ for(auto& v : se.vals)
+ rv |= visit_mir_lvalue_mut(v, false, cb);
+ ),
+ (Variant,
+ rv |= visit_mir_lvalue_mut(se.val, false, cb);
+ ),
+ (Struct,
+ for(auto& v : se.vals)
+ rv |= visit_mir_lvalue_mut(v, false, cb);
+ )
+ )
+ return rv;
+ }
+ //bool visit_mir_lvalues(const ::MIR::RValue& rval, ::std::function<bool(const ::MIR::LValue& , bool)> cb)
+ //{
+ // return visit_mir_lvalues_mut(const_cast<::MIR::RValue&>(rval), [&](auto& lv, bool im){ return cb(lv, im); });
+ //}
+
bool visit_mir_lvalues_mut(::MIR::Statement& stmt, ::std::function<bool(::MIR::LValue& , bool)> cb)
{
bool rv = false;
TU_MATCHA( (stmt), (e),
(Assign,
- TU_MATCHA( (e.src), (se),
- (Use,
- rv |= visit_mir_lvalue_mut(se, false, cb);
- ),
- (Constant,
- ),
- (SizedArray,
- rv |= visit_mir_lvalue_mut(se.val, false, cb);
- ),
- (Borrow,
- rv |= visit_mir_lvalue_mut(se.val, (se.type != ::HIR::BorrowType::Shared), cb);
- ),
- (Cast,
- rv |= visit_mir_lvalue_mut(se.val, false, cb);
- ),
- (BinOp,
- rv |= visit_mir_lvalue_mut(se.val_l, false, cb);
- rv |= visit_mir_lvalue_mut(se.val_r, false, cb);
- ),
- (UniOp,
- rv |= visit_mir_lvalue_mut(se.val, false, cb);
- ),
- (DstMeta,
- rv |= visit_mir_lvalue_mut(se.val, false, cb);
- ),
- (DstPtr,
- rv |= visit_mir_lvalue_mut(se.val, false, cb);
- ),
- (MakeDst,
- // TODO: Would prefer a flag to indicate "move"
- rv |= visit_mir_lvalue_mut(se.ptr_val, false, cb);
- rv |= visit_mir_lvalue_mut(se.meta_val, false, cb);
- ),
- (Tuple,
- for(auto& v : se.vals)
- rv |= visit_mir_lvalue_mut(v, false, cb);
- ),
- (Array,
- for(auto& v : se.vals)
- rv |= visit_mir_lvalue_mut(v, false, cb);
- ),
- (Variant,
- rv |= visit_mir_lvalue_mut(se.val, false, cb);
- ),
- (Struct,
- for(auto& v : se.vals)
- rv |= visit_mir_lvalue_mut(v, false, cb);
- )
- )
+ rv |= visit_mir_lvalues_mut(e.src, cb);
rv |= visit_mir_lvalue_mut(e.dst, true, cb);
),
(Asm,
@@ -358,7 +369,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// > This includes mutation, borrowing, or moving.
{
::std::map< unsigned int, ::MIR::LValue> replacements;
- for(const auto& block : fcn.blocks)
+ for(auto& block : fcn.blocks)
{
if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD )
continue ;
@@ -371,6 +382,8 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
continue ;
const auto& e = stmt.as_Assign();
// > Of a temporary from with a RValue::Use
+ // TODO: Variables too.
+ // TODO: Allow any rvalue type (if the usage is a RValue::Use)
if( !( e.dst.is_Temporary() && e.src.is_Use() ) )
continue ;
auto idx = e.dst.as_Temporary().idx;
@@ -378,15 +391,19 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// > Where the temporary is written once and read once
if( !( vu.read == 1 && vu.write == 1 ) )
continue ;
- // Get the root value(s) of the source
- const auto& src = e.src.as_Use();
+ // Get the root value(s) of the source
// TODO: Handle more complex values. (but don't bother for really complex values?)
+ const auto& src = e.src.as_Use();
if( !( src.is_Temporary() || src.is_Variable() ) )
continue ;
+ bool src_is_lvalue = true;
auto is_lvalue_usage = [&](const auto& lv, bool ){ return lv == e.dst; };
+ auto is_lvalue_in_val = [&](const auto& lv) {
+ return visit_mir_lvalue(src, true, [&](const auto& slv, bool ) { return lv == slv; });
+ };
// Eligable for replacement
// Find where this value is used
// - Stop on a conditional block terminator
@@ -395,9 +412,23 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
bool found = false;
for(unsigned int si2 = stmt_idx+1; si2 < block.statements.size(); si2 ++)
{
+ const auto& stmt2 = block.statements[si2];
+
// Usage found.
- if( visit_mir_lvalues(block.statements[si2], is_lvalue_usage) )
+ if( visit_mir_lvalues(stmt2, is_lvalue_usage) )
{
+ // TODO: If the source isn't a Use, ensure that this is a Use
+ if( !src_is_lvalue )
+ {
+ if( stmt2.is_Assign() && stmt2.as_Assign().src.is_Use() ) {
+ // Good
+ }
+ else {
+ // Bad, this has to stay a temporary
+ stop = true;
+ break;
+ }
+ }
found = true;
stop = true;
break;
@@ -405,7 +436,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// Determine if source is mutated.
// > Assume that any mutating access of the root value counts (over-cautious)
- if( visit_mir_lvalues(block.statements[si2], [&](const auto& lv, bool is_write){ return lv == src && is_write; }) )
+ if( visit_mir_lvalues(block.statements[si2], [&](const auto& lv, bool is_write){ return is_write && is_lvalue_in_val(lv); }) )
{
stop = true;
break;
@@ -426,21 +457,21 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
(Panic,
),
(If,
- if( visit_mir_lvalue(e.cond, false, is_lvalue_usage) )
+ if( src_is_lvalue && visit_mir_lvalue(e.cond, false, is_lvalue_usage) )
found = true;
stop = true;
),
(Switch,
- if( visit_mir_lvalue(e.val, false, is_lvalue_usage) )
+ if( src_is_lvalue && visit_mir_lvalue(e.val, false, is_lvalue_usage) )
found = true;
stop = true;
),
(Call,
if( e.fcn.is_Value() )
- if( visit_mir_lvalue(e.fcn.as_Value(), false, is_lvalue_usage) )
+ if( src_is_lvalue && visit_mir_lvalue(e.fcn.as_Value(), false, is_lvalue_usage) )
found = true;
for(const auto& v : e.args)
- if( visit_mir_lvalue(v, false, is_lvalue_usage) )
+ if( src_is_lvalue && visit_mir_lvalue(v, false, is_lvalue_usage) )
found = true;
stop = true;
)
@@ -456,6 +487,52 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
{
DEBUG("- Single-write/read " << e.dst << " not replaced - couldn't find usage");
}
+ } // for(stmt : block.statements)
+
+ // 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() )
+ {
+ 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;
+ }
+ }
+ }
}
}