summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2017-03-04 15:16:13 +0800
committerJohn Hodge <tpg@ucc.asn.au>2017-03-04 15:16:13 +0800
commitf308909f51252996a8d9bfbbfb5b1cb30e10e7ff (patch)
tree8da6bc3ab18a1fe8ab3762dfda85d88bd720aab0
parentb00e904995edd4415a2dbae0a5407269772e818a (diff)
downloadmrust-f308909f51252996a8d9bfbbfb5b1cb30e10e7ff.tar.gz
MIR Optimise - Constant propagation using Param
-rw-r--r--src/mir/optimise.cpp188
1 files changed, 186 insertions, 2 deletions
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp
index cb96cba0..65896ded 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -1567,6 +1567,12 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bb.terminator = ::MIR::Terminator::make_Goto(te.ret_block);
changed = true;
}
+ //else if( tef.name == "get_dst_meta_slice" )
+ //{
+ // MIR_ASSERT(state, te.args.at(0).is_LValue(), "Argument to `get_dst_meta` must be a lvalue");
+ // auto& e = te.args.at(0).as_LValue();
+ // bb.statements.push_back(::MIR::Statement::make_Assign({ mv$(te.ret_val), ::MIR::RValue::make_DstMeta({ mv$(*e) }) }));
+ //}
else
{
// Ignore any other intrinsics
@@ -1579,8 +1585,186 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// > NOTE: No need to locally stitch blocks, next pass will do that
// TODO: Use ValState to do full constant propagation across blocks
- // 1. Remove based on known booleans within a single block
- // - Eliminates `if false`/`if true` branches
+ // Remove redundant temporaries and evaluate known binops
+ for(auto& bb : fcn.blocks)
+ {
+ auto bbidx = &bb - &fcn.blocks.front();
+
+ ::std::map< ::MIR::LValue, ::MIR::Constant > known_values;
+
+ auto check_param = [&](::MIR::Param& p) {
+ if(const auto* pe = p.opt_LValue()) {
+ auto it = known_values.find(*pe);
+ if( it != known_values.end() )
+ {
+ p = it->second.clone();
+ }
+ }
+ };
+
+ for(auto& stmt : bb.statements)
+ {
+ auto stmtidx = &stmt - &bb.statements.front();
+ state.set_cur_stmt(bbidx, stmtidx);
+ // Scan statements forwards:
+ // - If a known temporary is used as Param::LValue, replace LValue with the value
+ // - If a UniOp has its input known, evaluate
+ // - If a BinOp has both values known, evaluate
+ if( auto* e = stmt.opt_Assign() )
+ {
+ TU_MATCHA( (e->src), (se),
+ (Use,
+ auto it = known_values.find(se);
+ if( it != known_values.end() )
+ {
+ e->src = it->second.clone();
+ }
+ ),
+ (Constant,
+ // Ignore (knowledge done below)
+ ),
+ (SizedArray,
+ check_param(se.val);
+ ),
+ (Borrow,
+ ),
+ (Cast,
+ ),
+ (BinOp,
+ check_param(se.val_l);
+ check_param(se.val_r);
+
+ if( se.val_l.is_Constant() && se.val_r.is_Constant() )
+ {
+ // TODO: Evaluate BinOp
+ }
+ ),
+ (UniOp,
+ auto it = known_values.find(se.val);
+ if( it != known_values.end() )
+ {
+ const auto& val = it->second;
+ // TODO: Evaluate UniOp
+ switch( se.op )
+ {
+ case ::MIR::eUniOp::INV:
+ TU_MATCHA( (val), (ve),
+ (Uint,
+ auto val = ve.v;
+ switch(ve.t)
+ {
+ case ::HIR::CoreType::U8: val = (~val) & 0xFF; break;
+ case ::HIR::CoreType::U16: val = (~val) & 0xFFFF; break;
+ case ::HIR::CoreType::U32: val = (~val) & 0xFFFFFFFF; break;
+ case ::HIR::CoreType::Usize:
+ case ::HIR::CoreType::U64:
+ val = ~val;
+ break;
+ case ::HIR::CoreType::U128:
+ val = ~val;
+ break;
+ case ::HIR::CoreType::Char:
+ MIR_BUG(state, "Invalid use of ! on char");
+ break;
+ default:
+ // Invalid type for Uint literal
+ break;
+ }
+ e->src = ::MIR::Constant::make_Uint({ val, ve.t });
+ ),
+ (Int,
+ // Is ! valid on Int?
+ ),
+ (Float,
+ // Not valid?
+ ),
+ (Bool,
+ e->src = ::MIR::Constant::make_Bool({ !ve.v });
+ ),
+ (Bytes, ),
+ (StaticString, ),
+ (Const,
+ // TODO:
+ ),
+ (ItemAddr,
+ )
+ )
+ break;
+ case ::MIR::eUniOp::NEG:
+ TU_MATCHA( (val), (ve),
+ (Uint,
+ // Not valid?
+ ),
+ (Int,
+ e->src = ::MIR::Constant::make_Int({ -ve.v, ve.t });
+ ),
+ (Float,
+ e->src = ::MIR::Constant::make_Float({ -ve.v, ve.t });
+ ),
+ (Bool,
+ // Not valid?
+ ),
+ (Bytes, ),
+ (StaticString, ),
+ (Const,
+ // TODO:
+ ),
+ (ItemAddr,
+ )
+ )
+ break;
+ }
+ }
+ ),
+ (DstMeta,
+ ),
+ (DstPtr,
+ ),
+ (MakeDst,
+ check_param(se.ptr_val);
+ check_param(se.meta_val);
+ ),
+ (Tuple,
+ for(auto& p : se.vals)
+ check_param(p);
+ ),
+ (Array,
+ for(auto& p : se.vals)
+ check_param(p);
+ ),
+ (Variant,
+ check_param(se.val);
+ ),
+ (Struct,
+ for(auto& p : se.vals)
+ check_param(p);
+ )
+ )
+ }
+ // - If a known temporary is borrowed mutably or mutated somehow, clear its knowledge
+ visit_mir_lvalues(stmt, [&known_values](const ::MIR::LValue& lv, ValUsage vu)->bool {
+ if( vu == ValUsage::Write ) {
+ auto it = known_values.find(lv);
+ if(it != known_values.end())
+ known_values.erase(it);
+ }
+ return false;
+ });
+ // - Locate `temp = SOME_CONST` and record value
+ if( const auto* e = stmt.opt_Assign() )
+ {
+ if( e->dst.is_Temporary() && e->src.is_Constant() )
+ {
+ known_values.insert(::std::make_pair( e->dst.clone(), e->src.as_Constant().clone() ));
+ }
+ }
+ }
+
+ state.set_cur_stmt_term(bbidx);
+ }
+
+ // - 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();