summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/mir/mir.cpp73
-rw-r--r--src/mir/mir.hpp5
-rw-r--r--src/mir/optimise.cpp104
3 files changed, 146 insertions, 36 deletions
diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp
index d5aae815..b696a7f0 100644
--- a/src/mir/mir.cpp
+++ b/src/mir/mir.cpp
@@ -328,4 +328,77 @@ namespace MIR {
throw "";
}
+::MIR::RValue MIR::RValue::clone() const
+{
+ TU_MATCHA( (*this), (e),
+ (Use,
+ return ::MIR::RValue(e.clone());
+ ),
+ (Constant,
+ TU_MATCHA( (e), (e2),
+ (Int, return ::MIR::Constant(e2); ),
+ (Uint, return ::MIR::Constant(e2); ),
+ (Float, return ::MIR::Constant(e2); ),
+ (Bool, return ::MIR::Constant(e2); ),
+ (Bytes, return ::MIR::Constant(e2); ),
+ (StaticString, return ::MIR::Constant(e2); ),
+ (Const, return ::MIR::Constant::make_Const({e2.p.clone()}); ),
+ (ItemAddr, return ::MIR::Constant(e2.clone()); )
+ )
+ ),
+ (SizedArray,
+ return ::MIR::RValue::make_SizedArray({ e.val.clone(), e.count });
+ ),
+ (Borrow,
+ return ::MIR::RValue::make_Borrow({ e.region, e.type, e.val.clone() });
+ ),
+ (Cast,
+ return ::MIR::RValue::make_Cast({ e.val.clone(), e.type.clone() });
+ ),
+ (BinOp,
+ return ::MIR::RValue::make_BinOp({ e.val_l.clone(), e.op, e.val_r.clone() });
+ ),
+ (UniOp,
+ return ::MIR::RValue::make_UniOp({ e.val.clone(), e.op });
+ ),
+ (DstMeta,
+ return ::MIR::RValue::make_DstMeta({ e.val.clone() });
+ ),
+ (DstPtr,
+ return ::MIR::RValue::make_DstPtr({ e.val.clone() });
+ ),
+ // Construct a DST pointer from a thin pointer and metadata
+ (MakeDst,
+ return ::MIR::RValue::make_MakeDst({ e.ptr_val.clone(), e.meta_val.clone() });
+ ),
+ (Tuple,
+ ::std::vector<::MIR::LValue> ret;
+ ret.reserve(e.vals.size());
+ for(const auto& v : e.vals)
+ ret.push_back( v.clone() );
+ return ::MIR::RValue::make_Tuple({ mv$(ret) });
+ ),
+ // Array literal
+ (Array,
+ ::std::vector<::MIR::LValue> ret;
+ ret.reserve(e.vals.size());
+ for(const auto& v : e.vals)
+ ret.push_back( v.clone() );
+ return ::MIR::RValue::make_Array({ mv$(ret) });
+ ),
+ // Create a new instance of a union (and eventually enum)
+ (Variant,
+ return ::MIR::RValue::make_Variant({ e.path.clone(), e.index, e.val.clone() });
+ ),
+ // Create a new instance of a struct (or enum)
+ (Struct,
+ ::std::vector<::MIR::LValue> ret;
+ ret.reserve(e.vals.size());
+ for(const auto& v : e.vals)
+ ret.push_back( v.clone() );
+ return ::MIR::RValue::make_Struct({ e.path.clone(), e.variant_idx, mv$(ret) });
+ )
+ )
+ throw "";
+}
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index cacaea99..fb69c7d9 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -102,7 +102,7 @@ TAGGED_UNION(Constant, Int,
);
extern ::std::ostream& operator<<(::std::ostream& os, const Constant& v);
-TAGGED_UNION(RValue, Use,
+TAGGED_UNION_EX(RValue, (), Use, (
(Use, LValue),
(Constant, Constant),
(SizedArray, struct {
@@ -163,6 +163,9 @@ TAGGED_UNION(RValue, Use,
unsigned int variant_idx; // if ~0, it's a struct
::std::vector<LValue> vals;
})
+ ), (),(), (
+ RValue clone() const;
+ )
);
extern ::std::ostream& operator<<(::std::ostream& os, const RValue& x);
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp
index 4a976662..a349c5fb 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -159,6 +159,36 @@ namespace {
return visit_mir_lvalues_mut(const_cast<::MIR::Statement&>(stmt), [&](auto& lv, bool im){ return cb(lv, im); });
}
+ void visit_mir_lvalues_mut(::MIR::Terminator& term, ::std::function<bool(::MIR::LValue& , bool)> cb)
+ {
+ TU_MATCHA( (term), (e),
+ (Incomplete,
+ ),
+ (Return,
+ ),
+ (Diverge,
+ ),
+ (Goto,
+ ),
+ (Panic,
+ ),
+ (If,
+ visit_mir_lvalue_mut(e.cond, false, cb);
+ ),
+ (Switch,
+ visit_mir_lvalue_mut(e.val, false, cb);
+ ),
+ (Call,
+ if( e.fcn.is_Value() ) {
+ visit_mir_lvalue_mut(e.fcn.as_Value(), false, cb);
+ }
+ for(auto& v : e.args)
+ visit_mir_lvalue_mut(v, false, cb);
+ visit_mir_lvalue_mut(e.ret_val, true, cb);
+ )
+ )
+ }
+
void visit_mir_lvalues_mut(::MIR::TypeResolve& state, ::MIR::Function& fcn, ::std::function<bool(::MIR::LValue& , bool)> cb)
{
for(unsigned int block_idx = 0; block_idx < fcn.blocks.size(); block_idx ++)
@@ -172,32 +202,7 @@ namespace {
visit_mir_lvalues_mut(stmt, cb);
}
state.set_cur_stmt_term(block_idx);
- TU_MATCHA( (block.terminator), (e),
- (Incomplete,
- ),
- (Return,
- ),
- (Diverge,
- ),
- (Goto,
- ),
- (Panic,
- ),
- (If,
- visit_mir_lvalue_mut(e.cond, false, cb);
- ),
- (Switch,
- visit_mir_lvalue_mut(e.val, false, cb);
- ),
- (Call,
- if( e.fcn.is_Value() ) {
- visit_mir_lvalue_mut(e.fcn.as_Value(), false, cb);
- }
- for(auto& v : e.args)
- visit_mir_lvalue_mut(v, false, cb);
- visit_mir_lvalue_mut(e.ret_val, true, cb);
- )
- )
+ visit_mir_lvalues_mut(block.terminator, cb);
}
}
void visit_mir_lvalues(::MIR::TypeResolve& state, const ::MIR::Function& fcn, ::std::function<bool(const ::MIR::LValue& , bool)> cb)
@@ -369,7 +374,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
// > This includes mutation, borrowing, or moving.
{
// 1. Assignments (forward propagate)
- ::std::map< ::MIR::LValue, ::MIR::LValue> replacements;
+ ::std::map< ::MIR::LValue, ::MIR::RValue> replacements;
for(const auto& block : fcn.blocks)
{
if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD )
@@ -489,7 +494,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
if( found )
{
DEBUG("> Replace " << e.dst << " with " << e.src.as_Use());
- replacements.insert( ::std::make_pair(e.dst.clone(), e.src.as_Use().clone()) );
+ replacements.insert( ::std::make_pair(e.dst.clone(), e.src.clone()) );
}
else
{
@@ -503,13 +508,13 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
unsigned int inner_replaced_count = 0;
for(auto& r : replacements)
{
- visit_mir_lvalue_mut(r.second, false, [&](auto& lv, bool is_write) {
+ visit_mir_lvalues_mut(r.second, [&](auto& lv, bool is_write) {
if( !is_write )
{
auto it = replacements.find(lv);
- if( it != replacements.end() )
+ if( it != replacements.end() && it->second.is_Use() )
{
- lv = it->second.clone();
+ lv = it->second.as_Use().clone();
inner_replaced_count ++;
}
}
@@ -525,19 +530,48 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
while( replaced < replacements.size() )
{
auto old_replaced = replaced;
- visit_mir_lvalues_mut(state, fcn, [&](auto& lv, bool is_write){
+ auto cb = [&](auto& lv, bool is_write){
if( !is_write )
{
auto it = replacements.find(lv);
if( it != replacements.end() )
{
- MIR_ASSERT(state, it->second.tag() != ::MIR::LValue::TAGDEAD, "Replacement of " << lv << " fired twice");
- lv = ::std::move(it->second);
+ MIR_ASSERT(state, it->second.tag() != ::MIR::RValue::TAGDEAD, "Replacement of " << lv << " fired twice");
+ MIR_ASSERT(state, it->second.is_Use(), "Replacing a lvalue with a rvalue");
+ auto rval = ::std::move(it->second);
+ lv = ::std::move(rval.as_Use());
replaced += 1;
}
}
return false;
- });
+ };
+ for(unsigned int block_idx = 0; block_idx < fcn.blocks.size(); block_idx ++)
+ {
+ auto& block = fcn.blocks[block_idx];
+ if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD )
+ continue ;
+ for(auto& stmt : block.statements)
+ {
+ state.set_cur_stmt(block_idx, (&stmt - &block.statements.front()));
+ if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() )
+ {
+ auto& e = stmt.as_Assign();
+ auto it = replacements.find(e.src.as_Use());
+ if( it != replacements.end() )
+ {
+ MIR_ASSERT(state, it->second.tag() != ::MIR::RValue::TAGDEAD, "Replacement of " << it->first << " fired twice");
+ e.src = mv$(it->second);
+ replaced += 1;
+ }
+ }
+ else
+ {
+ visit_mir_lvalues_mut(stmt, cb);
+ }
+ }
+ state.set_cur_stmt_term(block_idx);
+ visit_mir_lvalues_mut(block.terminator, cb);
+ }
MIR_ASSERT(state, replaced > old_replaced, "Temporary eliminations didn't advance");
}
// Remove assignments of replaced values