diff options
author | John Hodge <tpg@mutabah.net> | 2017-01-30 20:26:31 +0800 |
---|---|---|
committer | John Hodge <tpg@mutabah.net> | 2017-01-30 20:26:31 +0800 |
commit | 77a56cc58e84335b6a25ee3330ad3c2e06ab5942 (patch) | |
tree | 4dfac802ce365b6a8ba09f03ad933d33025095d4 /src | |
parent | 9d6e35aea551d291a3b687908de35045e572c0a1 (diff) | |
download | mrust-77a56cc58e84335b6a25ee3330ad3c2e06ab5942.tar.gz |
MIR Optimise - Remove known branches
Diffstat (limited to 'src')
-rw-r--r-- | src/mir/optimise.cpp | 77 |
1 files changed, 74 insertions, 3 deletions
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index fd1c9921..28c33fef 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -356,6 +356,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn); void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type) @@ -373,6 +374,9 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // >> Simplify call graph MIR_Optimise_BlockSimplify(state, fcn); + // >> Apply known constants + change_happened |= MIR_Optimise_ConstPropagte(state, fcn); + // >> Inline short functions bool inline_happened = MIR_Optimise_Inlining(state, fcn); if( inline_happened ) @@ -383,16 +387,16 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path change_happened = true; } - // >> Propagate dead assignments + // >> Propagate/remove dead assignments while( MIR_Optimise_PropagateSingleAssignments(state, fcn) ) ; // >> Unify duplicate temporaries // If two temporaries don't overlap in lifetime (blocks in which they're valid), unify the two - change_happened |= MIR_Optimise_UnifyTemporaries(state, fcn) || change_happened; + change_happened |= MIR_Optimise_UnifyTemporaries(state, fcn); // >> Combine Duplicate Blocks - change_happened |= MIR_Optimise_UnifyBlocks(state, fcn) || change_happened; + change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); #if 0 if( change_happened ) { @@ -1392,6 +1396,72 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) } } + +// -------------------------------------------------------------------- +// Propagate constants and eliminate known paths +// -------------------------------------------------------------------- +bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) +{ + bool changed = false; + TRACE_FUNCTION_FR("", changed); + + // 1. Remove based on known booleans within a single block + // - Eliminates `if false`/`if true` branches + for(auto& bb : fcn.blocks) + { + auto bbidx = &bb - &fcn.blocks.front(); + if( ! bb.terminator.is_If() ) continue; + const auto& te = bb.terminator.as_If(); + + // Restrict condition to being a temporary/variable + if( te.cond.is_Temporary() ) + ; + else if( te.cond.is_Argument() ) + ; + else + continue; + + auto has_cond = [&](const auto& lv, bool is_write)->bool { + return lv == te.cond; + }; + bool val_known = false; + bool known_val; + for(unsigned int i = bb.statements.size(); i --; ) + { + if( bb.statements[i].is_Assign() ) + { + const auto& se = bb.statements[i].as_Assign(); + // If the condition was mentioned, don't assume it has the same value + // TODO: What if the condition is a field/index and something else is edited? + if( visit_mir_lvalues(se.src, has_cond) ) + break; + + if( se.dst != te.cond ) + continue; + if( !se.src.is_Constant() ) + continue; + if( !se.src.as_Constant().is_Bool() ) + continue; + val_known = true; + known_val = se.src.as_Constant().as_Bool(); + break; + } + else + { + if( visit_mir_lvalues(bb.statements[i], has_cond) ) + break; + } + } + if( val_known ) + { + DEBUG("bb" << bbidx << ": Condition known to be " << known_val); + bb.terminator = ::MIR::Terminator::make_Goto( known_val ? te.bb0 : te.bb1 ); + changed = true; + } + } + return changed; +} + // -------------------------------------------------------------------- // Replace `tmp = RValue::Use()` where the temp is only used once // -------------------------------------------------------------------- @@ -1489,6 +1559,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F { const auto& vu = val_uses.tmp_uses[e.dst.as_Temporary().idx]; DEBUG("VU " << e.dst << " R:" << vu.read << " W:" << vu.write); + // TODO: Allow write many? // > Where the temporary is written once and read once if( !( vu.read == 1 && vu.write == 1 ) ) continue ; |