summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Hodge <tpg@ucc.asn.au>2019-06-02 11:55:02 +0800
committerJohn Hodge <tpg@ucc.asn.au>2019-06-02 11:55:02 +0800
commitdab72ad78160ecd2a4d1759174cee837a5bedcbc (patch)
treed7b6f4a34435a163390150476e8fa532f9f2bdfb
parent599ed0a4cdaf7e05a1c8623c015a593106ea31ec (diff)
downloadmrust-dab72ad78160ecd2a4d1759174cee837a5bedcbc.tar.gz
MIR - Refactor LValue to reduce size and linked-list-ness (seems to have had a ~10% reduction in memory usage)
-rw-r--r--Notes/MIR-PackedLValue.txt65
-rw-r--r--src/hir/deserialise.cpp32
-rw-r--r--src/hir/serialise.cpp41
-rw-r--r--src/hir_conv/bind.cpp27
-rw-r--r--src/hir_conv/constant_evaluation.cpp112
-rw-r--r--src/include/tagged_union.hpp7
-rw-r--r--src/mir/check.cpp173
-rw-r--r--src/mir/check_full.cpp230
-rw-r--r--src/mir/cleanup.cpp82
-rw-r--r--src/mir/dump.cpp35
-rw-r--r--src/mir/from_hir.cpp76
-rw-r--r--src/mir/from_hir.hpp15
-rw-r--r--src/mir/from_hir_match.cpp112
-rw-r--r--src/mir/helpers.cpp135
-rw-r--r--src/mir/helpers.hpp11
-rw-r--r--src/mir/mir.cpp189
-rw-r--r--src/mir/mir.hpp402
-rw-r--r--src/mir/mir_builder.cpp597
-rw-r--r--src/mir/optimise.cpp587
-rw-r--r--src/trans/auto_impls.cpp20
-rw-r--r--src/trans/codegen_c.cpp287
-rw-r--r--src/trans/codegen_mmir.cpp103
-rw-r--r--src/trans/enumerate.cpp340
-rw-r--r--src/trans/monomorphise.cpp40
24 files changed, 1863 insertions, 1855 deletions
diff --git a/Notes/MIR-PackedLValue.txt b/Notes/MIR-PackedLValue.txt
new file mode 100644
index 00000000..ce889aee
--- /dev/null
+++ b/Notes/MIR-PackedLValue.txt
@@ -0,0 +1,65 @@
+Problem statement:
+- MIR LValues are very common, and suffer from excessive indirection when
+ dereferences and field accesses are present
+- Many MIR analysis passes care most about the inner values
+- Pointer chasing ruins cache locality
+
+Solution: Replace the tagged union tree with a flatteded structure
+
+Quirk: Indexing takes two LValues to produce one BUT one of those is of a
+lesser class, so doesn't need to be treated the same.
+
+
+
+Structure proposal:
+----
+A LValue is made up of:
+- A root value (referencing a local, argument, static, or the return value)
+- And a list of wrappers (dereference, field, downcast, index)
+
+Root values are encoded as a packed pointer/value and tag, with the tag stored in the low 2 bits of the pointer
+- This allows a 32-bit pointer to a word to be stored, using the alignment bits as tag
+- Arguments and locals are encoded with the argument/local index in the "data" bits
+- Return value is encoded as argument `-1` (all 1 bits in data)
+- Statics are encoded as a pointer to a `::HIR::Path`
+ - This adds a new pointer access and allocation vs the existing LValue structure
+ - HIR::Path already has a bunch of pointers in it, may not hurt that much (and may help by keeping the normal size
+ of the LValue down)
+
+Wrappers are stored as a vector of words, packed in a similar way to root values
+- Dereference is stored just as an entry (could pack multiple derefs into one, but that would make handling more
+ difficult)
+- Field/Downcast is stored with the field/variant index in the "data" bits
+- Indexing is stored as a pointer to a LValue
+ - ALTERNATIVE: Could require that indexing always uses a local, and just store the local index
+ - This would vastly reduce complexity in handling the Index wrapper, BUT would add a new statement in some cases
+ - A quick scan of the MMIR output of libstd crates, shows that the vast majority of indexing cases are with a local
+ directly.
+ - Doing so would simplify monomorph/clone/serialise (no need to clone the wrapper list, just copy it).
+ - Would also improve comparison times
+
+
+
+Usecase comparisons
+------
+(Using 32-bit architecture)
+
+NOTES:
+- Existing `LValue` structure is 3 words long (1 tag, plus 2 pointers for largest variant)
+ - WRONG. It's actually far larger due to the ::HIR::Path embedded in it (estimate at least 8 pointers, very likely
+ more). That should be fixed given the number of LValue-s that exist
+ - Fixed now, had a slight improvement in compile times (and memory usage?)
+- New structure is 4 words long (root value, plus len/cap/ptr for vector)
+
+- Field access via `&self`
+ - Old: Field(Deref(Argument(0)), 0)
+ - 12 + 12 + 12 = 36 bytes w/ 2 pointers
+ - New: LValue( Argument(0), { Deref, Field(0) } )
+ - 16 + 8 = 24 bytes w/ 1 pointer
+
+- Array stored in `&self` (common in librand)
+ - `(*arg0).2[var16].0`
+ - Old: Field( Index(Field(Deref(Argument(0)), 2), Local(16)), 0 )
+ - 12 * 5 + 12 = 72 bytes 2/ 5 pointers
+ - New: LValue( Argument(0), { Deref, Field(2), Index(16), Field(0) } )
+ - 16 + 16 = 32 bytes w/ 1 pointer
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index 56671a04..35aeacca 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -464,32 +464,15 @@
rv = deserialise_mir_lvalue_();
return rv;
}
+ ::MIR::LValue::Wrapper deserialise_mir_lvalue_wrapper()
+ {
+ return ::MIR::LValue::Wrapper::from_inner(m_in.read_count());
+ }
::MIR::LValue deserialise_mir_lvalue_()
{
- switch(auto tag = m_in.read_tag())
- {
- #define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ );
- _(Return, {})
- _(Argument, { static_cast<unsigned int>(m_in.read_count()) } )
- _(Local, static_cast<unsigned int>(m_in.read_count()) )
- _(Static, box$(deserialise_path()) )
- _(Field, {
- box$( deserialise_mir_lvalue() ),
- static_cast<unsigned int>(m_in.read_count())
- } )
- _(Deref, { box$( deserialise_mir_lvalue() ) })
- _(Index, {
- box$( deserialise_mir_lvalue() ),
- box$( deserialise_mir_lvalue() )
- } )
- _(Downcast, {
- box$( deserialise_mir_lvalue() ),
- static_cast<unsigned int>(m_in.read_count())
- } )
- #undef _
- default:
- BUG(Span(), "Bad tag for MIR::LValue - " << tag);
- }
+ auto root_v = m_in.read_count();
+ auto root = (root_v == 3 ? ::MIR::LValue::Storage::new_Static(deserialise_path()) : ::MIR::LValue::Storage::from_inner(root_v));
+ return ::MIR::LValue( mv$(root), deserialise_vec<::MIR::LValue::Wrapper>() );
}
::MIR::RValue deserialise_mir_rvalue()
{
@@ -827,6 +810,7 @@
template<> DEF_D( ::HIR::TraitValueItem, return d.deserialise_traitvalueitem(); )
template<> DEF_D( ::MIR::Param, return d.deserialise_mir_param(); )
+ template<> DEF_D( ::MIR::LValue::Wrapper, return d.deserialise_mir_lvalue_wrapper(); )
template<> DEF_D( ::MIR::LValue, return d.deserialise_mir_lvalue(); )
template<> DEF_D( ::MIR::Statement, return d.deserialise_mir_statement(); )
template<> DEF_D( ::MIR::BasicBlock, return d.deserialise_mir_basicblock(); )
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index c15630d9..fc53e245 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -722,35 +722,18 @@
void serialise(const ::MIR::LValue& lv)
{
TRACE_FUNCTION_F("LValue = "<<lv);
- m_out.write_tag( static_cast<int>(lv.tag()) );
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- m_out.write_count(e.idx);
- ),
- (Local,
- m_out.write_count(e);
- ),
- (Static,
- serialise_path(*e);
- ),
- (Field,
- serialise(e.val);
- m_out.write_count(e.field_index);
- ),
- (Deref,
- serialise(e.val);
- ),
- (Index,
- serialise(e.val);
- serialise(e.idx);
- ),
- (Downcast,
- serialise(e.val);
- m_out.write_count(e.variant_index);
- )
- )
+ if( lv.m_root.is_Static() ) {
+ m_out.write_count(3);
+ serialise_path(lv.m_root.as_Static());
+ }
+ else {
+ m_out.write_count( lv.m_root.get_inner() );
+ }
+ serialise_vec(lv.m_wrappers);
+ }
+ void serialise(const ::MIR::LValue::Wrapper& w)
+ {
+ m_out.write_count(w.get_inner());
}
void serialise(const ::MIR::RValue& val)
{
diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp
index 84854315..e3441157 100644
--- a/src/hir_conv/bind.cpp
+++ b/src/hir_conv/bind.cpp
@@ -704,30 +704,9 @@ namespace {
struct H {
static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Local,
- ),
- (Argument,
- ),
- (Static,
- upper_visitor.visit_path(*e, ::HIR::Visitor::PathContext::VALUE);
- ),
- (Field,
- H::visit_lvalue(upper_visitor, *e.val);
- ),
- (Deref,
- H::visit_lvalue(upper_visitor, *e.val);
- ),
- (Index,
- H::visit_lvalue(upper_visitor, *e.val);
- H::visit_lvalue(upper_visitor, *e.idx);
- ),
- (Downcast,
- H::visit_lvalue(upper_visitor, *e.val);
- )
- )
+ if( lv.m_root.is_Static() ) {
+ upper_visitor.visit_path(lv.m_root.as_Static(), ::HIR::Visitor::PathContext::VALUE);
+ }
}
static void visit_constant(Visitor& upper_visitor, ::MIR::Constant& e)
{
diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp
index b97a6ae0..500ac490 100644
--- a/src/hir_conv/constant_evaluation.cpp
+++ b/src/hir_conv/constant_evaluation.cpp
@@ -293,61 +293,66 @@ namespace HIR {
::HIR::Literal& get_lval(const ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
+ ::HIR::Literal* lit_ptr;
+ TRACE_FUNCTION_FR(lv, *lit_ptr);
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- return retval;
+ lit_ptr = &retval;
),
(Local,
- if( e >= locals.size() )
- MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size());
- return locals[e];
+ MIR_ASSERT(state, e < locals.size(), "Local index out of range - " << e << " >= " << locals.size());
+ lit_ptr = &locals[e];
),
(Argument,
- if( e.idx >= args.size() )
- MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size());
- return args[e.idx];
+ MIR_ASSERT(state, e < args.size(), "Argument index out of range - " << e << " >= " << args.size());
+ lit_ptr = &args[e];
),
(Static,
- MIR_TODO(state, "LValue::Static - " << *e);
- ),
- (Field,
- auto& val = get_lval(*e.val);
- MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv);
- auto& vals = val.as_List();
- MIR_ASSERT(state, e.field_index < vals.size(), "LValue::Field index out of range");
- return vals[ e.field_index ];
- ),
- (Deref,
- auto& val = get_lval(*e.val);
- TU_MATCH_DEF( ::HIR::Literal, (val), (ve),
- (
- MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }");
- ),
- (BorrowData,
- return *ve;
- ),
- (String,
- // Just clone the string (hack)
- // - TODO: Create a list?
- return val;
- )
- )
- ),
- (Index,
- auto& val = get_lval(*e.val);
- MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv);
- auto& idx = get_lval(*e.idx);
- MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv);
- auto& vals = val.as_List();
- auto idx_v = static_cast<size_t>( idx.as_Integer() );
- MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range");
- return vals[ idx_v ];
- ),
- (Downcast,
- MIR_TODO(state, "LValue::Downcast - " << lv);
+ MIR_TODO(state, "LValue::Static - " << e);
)
)
- throw "";
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& val = *lit_ptr;
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, e) {
+ MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv);
+ auto& vals = val.as_List();
+ MIR_ASSERT(state, e < vals.size(), "LValue::Field index out of range");
+ lit_ptr = &vals[ e ];
+ }
+ TU_ARMA(Deref, e) {
+ TU_MATCH_DEF( ::HIR::Literal, (val), (ve),
+ (
+ MIR_TODO(state, "LValue::Deref - " << lv << " { " << val << " }");
+ ),
+ (BorrowData,
+ lit_ptr = &*ve;
+ ),
+ (String,
+ // Just clone the string (hack)
+ // - TODO: Create a list?
+ lit_ptr = &val;
+ )
+ )
+ }
+ TU_ARMA(Index, e) {
+ MIR_ASSERT(state, val.is_List(), "LValue::Index on non-list literal - " << val.tag_str() << " - " << lv);
+ MIR_ASSERT(state, e < locals.size(), "LValue::Index index local out of range");
+ auto& idx = locals[e];
+ MIR_ASSERT(state, idx.is_Integer(), "LValue::Index with non-integer index literal - " << idx.tag_str() << " - " << lv);
+ auto& vals = val.as_List();
+ auto idx_v = static_cast<size_t>( idx.as_Integer() );
+ MIR_ASSERT(state, idx_v < vals.size(), "LValue::Index index out of range");
+ lit_ptr = &vals[ idx_v ];
+ }
+ TU_ARMA(Downcast, e) {
+ MIR_TODO(state, "LValue::Downcast - " << lv);
+ }
+ }
+ }
+ return *lit_ptr;
}
::HIR::Literal read_lval(const ::MIR::LValue& lv)
{
@@ -481,17 +486,14 @@ namespace HIR {
MIR_BUG(state, "Only shared borrows are allowed in constants");
}
- if( e.type != ::HIR::BorrowType::Shared ) {
- MIR_BUG(state, "Only shared borrows are allowed in constants");
- }
- if( const auto* p = e.val.opt_Deref() ) {
- if( p->val->is_Deref() )
- MIR_TODO(state, "Undo nested deref coercion - " << *p->val);
- val = local_state.read_lval(*p->val);
+ if( !e.val.m_wrappers.empty() && e.val.m_wrappers.back().is_Deref() ) {
+ //if( p->val->is_Deref() )
+ // MIR_TODO(state, "Undo nested deref coercion - " << *p->val);
+ val = local_state.read_lval(e.val.clone_unwrapped());
}
- else if( const auto* p = e.val.opt_Static() ) {
+ else if( e.val.m_wrappers.empty() && e.val.m_root.is_Static() ){
// Borrow of a static, emit BorrowPath with the same path
- val = ::HIR::Literal::make_BorrowPath( (*p)->clone() );
+ val = ::HIR::Literal::make_BorrowPath( e.val.m_root.as_Static().clone() );
}
else {
auto inner_val = local_state.read_lval(e.val);
diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp
index dab7f8ea..5a3359b8 100644
--- a/src/include/tagged_union.hpp
+++ b/src/include/tagged_union.hpp
@@ -28,7 +28,6 @@
#define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__)
#define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__)
-
// Argument iteration
#define TU_DISP0(n)
#define TU_DISP1(n, _1) n _1
@@ -105,7 +104,7 @@
*/ TU_MATCH_ARMS(CLASS, VAR, NAME, __VA_ARGS__)/*
*/ default: {TU_EXP DEF;} break;/*
*/}
-#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ auto& NAME = (VAR).as_##TAG(); (void)&NAME;
+#define TU_MATCH_BIND1(TAG, VAR, NAME) /*MATCH_BIND*/ decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)&NAME;
#define TU_MATCH_BIND2_(TAG, v1,v2, n1,n2) TU_MATCH_BIND1(TAG, v1, n1) TU_MATCH_BIND1(TAG, v2, n2)
#define TU_MATCH_BIND2(...) TU_EXP1( TU_MATCH_BIND2_(__VA_ARGS__) ) // << Exists to cause expansion of the vars
#define TU_MATCH_ARM(CLASS, VAR, NAME, TAG, ...) case CLASS::TAG_##TAG: {/*
@@ -119,12 +118,12 @@
#define TU_MATCH_HDR(VARS, brace) TU_MATCH_HDR_(::std::remove_reference<decltype(TU_FIRST VARS)>::type, VARS, brace)
#define TU_MATCH_HDR_(CLASS, VARS, brace) switch( (TU_FIRST VARS).tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used");
// Evil hack: two for loops, the inner stops the outer after it's done.
-#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference<decltype(VAR)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
+#define TU_ARM(VAR, TAG, NAME) break; case ::std::remove_reference<decltype(VAR)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype((VAR).as_##TAG()) NAME = (VAR).as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
#define TU_MATCH_HDRA(VARS, brace) TU_MATCH_HDRA_(::std::remove_reference<decltype(TU_FIRST VARS)>::type, VARS, brace)
#define TU_MATCH_HDRA_(CLASS, VARS, brace) auto& tu_match_hdr2_v = (TU_FIRST VARS); switch( tu_match_hdr2_v.tag() ) brace case CLASS::TAGDEAD: assert(!"ERROR: destructed tagged union used");
// Evil hack: two for loops, the inner stops the outer after it's done.
-#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference<decltype(tu_match_hdr2_v)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(auto& NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
+#define TU_ARMA(TAG, NAME) break; case ::std::remove_reference<decltype(tu_match_hdr2_v)>::type::TAG_##TAG: for(bool tu_lc = true; tu_lc; tu_lc=false) for(decltype(tu_match_hdr2_v.as_##TAG()) NAME = tu_match_hdr2_v.as_##TAG(); (void)NAME, tu_lc; tu_lc=false)
//#define TU_TEST(VAL, ...) (VAL.is_##TAG() && VAL.as_##TAG() TEST)
#define TU_TEST1(VAL, TAG1, TEST) (VAL.is_##TAG1() && VAL.as_##TAG1() TEST)
diff --git a/src/mir/check.cpp b/src/mir/check.cpp
index 0b032bbc..6ed34563 100644
--- a/src/mir/check.cpp
+++ b/src/mir/check.cpp
@@ -116,6 +116,11 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
{
}
+ explicit ValStates(const ValStates& v) = default;
+ ValStates(ValStates&& v) = default;
+ ValStates& operator=(const ValStates& v) = delete;
+ ValStates& operator=(ValStates&& v) = default;
+
void fmt(::std::ostream& os) {
os << "ValStates { ";
switch(ret_state)
@@ -159,12 +164,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
return locals.empty() && args.empty();
}
+ // NOTE: Moves if this state is empty
bool merge(unsigned bb_idx, ValStates& other)
{
DEBUG("bb" << bb_idx << " this=" << FMT_CB(ss,this->fmt(ss);) << ", other=" << FMT_CB(ss,other.fmt(ss);));
if( this->empty() )
{
- *this = other;
+ *this = ValStates(other);
return true;
}
else if( *this == other )
@@ -183,34 +189,38 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
void mark_validity(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv, bool is_valid)
{
- TU_MATCH_DEF( ::MIR::LValue, (lv), (e),
- (
- ),
+ if( !lv.m_wrappers.empty())
+ {
+ return ;
+ }
+ TU_MATCHA( (lv.m_root), (e),
(Return,
ret_state = is_valid ? State::Valid : State::Invalid;
),
(Argument,
- MIR_ASSERT(state, e.idx < this->args.size(), "Argument index out of range");
- DEBUG("arg$" << e.idx << " = " << (is_valid ? "Valid" : "Invalid"));
- this->args[e.idx] = is_valid ? State::Valid : State::Invalid;
+ MIR_ASSERT(state, e < this->args.size(), "Argument index out of range " << lv);
+ DEBUG("arg$" << e << " = " << (is_valid ? "Valid" : "Invalid"));
+ this->args[e] = is_valid ? State::Valid : State::Invalid;
),
(Local,
- MIR_ASSERT(state, e < this->locals.size(), "Local index out of range");
+ MIR_ASSERT(state, e < this->locals.size(), "Local index out of range - " << lv);
DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid"));
this->locals[e] = is_valid ? State::Valid : State::Invalid;
+ ),
+ (Static,
)
)
}
void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv)
{
- TU_MATCH( ::MIR::LValue, (lv), (e),
+ TU_MATCHA( (lv.m_root), (e),
(Return,
if( this->ret_state != State::Valid )
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Argument,
- MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range");
- if( this->args[e.idx] != State::Valid )
+ MIR_ASSERT(state, e < this->args.size(), "Arg index out of range");
+ if( this->args[e] != State::Valid )
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Local,
@@ -219,27 +229,22 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
MIR_BUG(state, "Use of non-valid lvalue - " << lv);
),
(Static,
- ),
- (Field,
- ensure_valid(state, *e.val);
- ),
- (Deref,
- ensure_valid(state, *e.val);
- ),
- (Index,
- ensure_valid(state, *e.val);
- ensure_valid(state, *e.idx);
- ),
- (Downcast,
- ensure_valid(state, *e.val);
)
)
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() )
+ {
+ if( this->locals[w.as_Index()] != State::Valid )
+ MIR_BUG(state, "Use of non-valid lvalue - " << ::MIR::LValue::new_Local(w.as_Index()));
+ }
+ }
}
void move_val(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv)
{
ensure_valid(state, lv);
- ::HIR::TypeRef tmp;
- if( ! state.m_resolve.type_is_copy( state.sp, state.get_lvalue_type(tmp, lv) ) )
+ if( ! state.lvalue_is_copy(lv) )
{
mark_validity(state, lv, false);
}
@@ -284,20 +289,29 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
::std::vector<unsigned int> path;
ValStates state;
};
+ // TODO: Remove this? The path is useful, but the cloned states are really expensive
+ // - Option: Keep the paths, but only ever use the pre-set entry state?
::std::vector<ToVisit> to_visit_blocks;
// TODO: Check that all used locals are also set (anywhere at all)
- auto add_to_visit = [&](unsigned int idx, ::std::vector<unsigned int> src_path, auto vs) {
+ auto add_to_visit = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates& vs, bool can_move) {
for(const auto& b : to_visit_blocks)
if( b.bb == idx && b.state == vs)
return ;
if( block_start_states.at(idx) == vs )
return ;
src_path.push_back(idx);
- to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } );
+ // TODO: Update the target block, and only visit if we've induced a change
+ to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), (can_move ? mv$(vs) : ValStates(vs)) } );
+ };
+ auto add_to_visit_move = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates vs) {
+ add_to_visit(idx, mv$(src_path), vs, true);
+ };
+ auto add_to_visit_copy = [&](unsigned int idx, ::std::vector<unsigned int> src_path, ValStates& vs) {
+ add_to_visit(idx, mv$(src_path), vs, false);
};
- add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } );
+ add_to_visit_move( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } );
while( to_visit_blocks.size() > 0 )
{
auto block = to_visit_blocks.back().bb;
@@ -311,7 +325,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
if( ! block_start_states.at(block).merge(block, val_state) ) {
continue ;
}
- DEBUG("BB" << block << " via [" << path << "]");
+ ASSERT_BUG(Span(), val_state.locals.size() == fcn.locals.size(), "");
+ DEBUG("BB" << block << " via [" << path << "] " << FMT_CB(ss,val_state.fmt(ss);));
// 2. Using the newly merged state, iterate statements checking the usage and updating state.
const auto& bb = fcn.blocks[block];
@@ -411,13 +426,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
// 3. Pass new state on to destination blocks
state.set_cur_stmt_term(block);
DEBUG(state << bb.terminator);
- TU_MATCH(::MIR::Terminator, (bb.terminator), (e),
- (Incomplete,
+ TU_MATCH_HDRA( (bb.terminator), { )
+ TU_ARMA(Incomplete, e) {
// Should be impossible here.
- ),
- (Return,
+ }
+ TU_ARMA(Return, e) {
// Check if the return value has been set
- val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) );
+ val_state.ensure_valid( state, ::MIR::LValue::new_Return() );
// Ensure that no other non-Copy values are valid
for(unsigned int i = 0; i < val_state.locals.size(); i ++)
{
@@ -432,51 +447,51 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn
// TODO: Error, becuase this has just been leaked
}
}
- ),
- (Diverge,
+ }
+ TU_ARMA(Diverge, e) {
// TODO: Ensure that cleanup has been performed.
- ),
- (Goto,
+ }
+ TU_ARMA(Goto, e) {
// Push block with the new state
- add_to_visit( e, mv$(path), mv$(val_state) );
- ),
- (Panic,
+ add_to_visit_move( e, mv$(path), mv$(val_state) );
+ }
+ TU_ARMA(Panic, e) {
// What should be done here?
- ),
- (If,
+ }
+ TU_ARMA(If, e) {
// Push blocks
val_state.ensure_valid( state, e.cond );
- add_to_visit( e.bb0, path, val_state );
- add_to_visit( e.bb1, mv$(path), mv$(val_state) );
- ),
- (Switch,
+ add_to_visit_copy( e.bb0, path, val_state );
+ add_to_visit_move( e.bb1, mv$(path), mv$(val_state) );
+ }
+ TU_ARMA(Switch, e) {
val_state.ensure_valid( state, e.val );
for(const auto& tgt : e.targets)
{
- add_to_visit( tgt, path, val_state );
+ add_to_visit( tgt, path, val_state, (&tgt == &e.targets.back()) );
}
- ),
- (SwitchValue,
+ }
+ TU_ARMA(SwitchValue, e) {
val_state.ensure_valid( state, e.val );
for(const auto& tgt : e.targets)
{
- add_to_visit( tgt, path, val_state );
+ add_to_visit_copy( tgt, path, val_state );
+ }
+ add_to_visit_move( e.def_target, path, mv$(val_state) );
}
- add_to_visit( e.def_target, path, val_state );
- ),
- (Call,
+ TU_ARMA(Call, e) {
if( e.fcn.is_Value() )
val_state.ensure_valid( state, e.fcn.as_Value() );
for(const auto& arg : e.args)
val_state.move_val( state, arg );
// Push blocks (with return valid only in one)
- add_to_visit(e.panic_block, path, val_state);
+ add_to_visit_copy(e.panic_block, path, val_state);
// TODO: If the function returns !, don't follow the ret_block
val_state.mark_validity( state, e.ret_val, true );
- add_to_visit(e.ret_block, mv$(path), mv$(val_state));
- )
- )
+ add_to_visit_move(e.ret_block, mv$(path), mv$(val_state));
+ }
+ }
}
}
@@ -838,33 +853,33 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
state.set_cur_stmt_term(bb_idx);
DEBUG(state << bb.terminator);
- TU_MATCH(::MIR::Terminator, (bb.terminator), (e),
- (Incomplete,
- ),
- (Return,
+ TU_MATCH_HDRA( (bb.terminator), {)
+ TU_ARMA(Incomplete, e) {
+ }
+ TU_ARMA(Return, e) {
// TODO: Check if the function can return (i.e. if its return type isn't an empty type)
- ),
- (Diverge,
- ),
- (Goto,
- ),
- (Panic,
- ),
- (If,
+ }
+ TU_ARMA(Diverge, e) {
+ }
+ TU_ARMA(Goto, e) {
+ }
+ TU_ARMA(Panic, e) {
+ }
+ TU_ARMA(If, e) {
// Check that condition lvalue is a bool
::HIR::TypeRef tmp;
const auto& ty = state.get_lvalue_type(tmp, e.cond);
if( ty != ::HIR::CoreType::Bool ) {
MIR_BUG(state, "Type mismatch in `If` - expected bool, got " << ty);
}
- ),
- (Switch,
+ }
+ TU_ARMA(Switch, e) {
// Check that the condition is an enum
- ),
- (SwitchValue,
+ }
+ TU_ARMA(SwitchValue, e) {
// Check that the condition's type matches the values
- ),
- (Call,
+ }
+ TU_ARMA(Call, e) {
if( e.fcn.is_Value() )
{
::HIR::TypeRef tmp;
@@ -875,8 +890,8 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path
}
}
// Typecheck arguments and return value
- )
- )
+ }
+ }
}
}
diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp
index 24a4930a..0cc83c6f 100644
--- a/src/mir/check_full.cpp
+++ b/src/mir/check_full.cpp
@@ -446,68 +446,54 @@ namespace
}
const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const
{
- TU_MATCHA( (lv), (e),
+ const State* state_p = nullptr;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- return return_value;
+ state_p = &return_value;
),
(Argument,
- return args.at(e.idx);
+ state_p = &args.at(e);
),
(Local,
- return locals.at(e);
+ state_p = &locals.at(e);
),
(Static,
static State state_of_static(true);
return state_of_static;
- ),
- (Field,
- const auto& vs = get_lvalue_state(mir_res, *e.val);
- if( vs.is_composite() )
- {
- const auto& states = this->get_composite(mir_res, vs);
- MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range");
- return states[e.field_index];
- }
- else
- {
- return vs;
+ )
+ )
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( state_p->is_composite() ) {
+ break;
}
- ),
- (Deref,
- const auto& vs = get_lvalue_state(mir_res, *e.val);
- if( vs.is_composite() )
- {
+ const auto& vs = *state_p;
+ state_p = nullptr;
+
+ TU_MATCHA( (w), (e),
+ (Field,
+ const auto& states = this->get_composite(mir_res, vs);
+ MIR_ASSERT(mir_res, e < states.size(), "Field index out of range");
+ state_p = &states[e];
+ ),
+ (Deref,
MIR_TODO(mir_res, "Deref with composite state");
- }
- else
- {
- return vs;
- }
- ),
- (Index,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- const auto& vs_i = get_lvalue_state(mir_res, *e.idx);
- MIR_ASSERT(mir_res, !vs_v.is_composite(), "");
- MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
- //return State(vs_v.is_valid() && vs_i.is_valid());
- MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value");
- return vs_v;
- ),
- (Downcast,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- if( vs_v.is_composite() )
- {
- const auto& states = this->get_composite(mir_res, vs_v);
- MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs_v));
- return states[0];
- }
- else
- {
- return vs_v;
- }
+ ),
+ (Index,
+ const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e));
+ MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value");
+ MIR_BUG(mir_res, "Indexing a composite state");
+ ),
+ (Downcast,
+ const auto& states = this->get_composite(mir_res, vs);
+ MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs));
+ state_p = &states[0];
+ )
)
- )
- throw "";
+ assert(state_p);
+ }
+ return *state_p;
}
void clear_state(const ::MIR::TypeResolve& mir_res, State& s) {
@@ -522,42 +508,47 @@ namespace
void set_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv, State new_vs)
{
TRACE_FUNCTION_F(lv << " = " << StateFmt(*this, new_vs) << " (from " << StateFmt(*this, get_lvalue_state(mir_res, lv)) << ")");
- TU_MATCHA( (lv), (e),
+ State* state_p = nullptr;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- this->clear_state(mir_res, return_value);
- return_value = mv$(new_vs);
+ state_p = &return_value;
),
(Argument,
- auto& slot = args.at(e.idx);
- this->clear_state(mir_res, slot);
- slot = mv$(new_vs);
+ state_p = &args.at(e);
),
(Local,
- auto& slot = locals.at(e);
- this->clear_state(mir_res, slot);
- slot = mv$(new_vs);
+ state_p = &locals.at(e);
),
(Static,
- // Ignore.
- ),
- (Field,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
+ return ;
+ )
+ )
+
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& cur_vs = *state_p;
+
+ // If this is not a composite, and it matches the new state
if( !cur_vs.is_composite() && cur_vs == new_vs )
{
- // Not a composite, and no state change
+ // Early return
+ return;
}
- else
- {
- ::std::vector<State>* states_p;
+
+ state_p = nullptr;
+ TU_MATCHA( (w), (e),
+ (Field,
+ // Current isn't a composite, we need to change that
if( !cur_vs.is_composite() )
{
::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, *e.val);
+ const auto& ty = mir_res.get_lvalue_type(tmp, lv, /*wrapper_skip_count=*/(&lv.m_wrappers.back() - &w));
unsigned int n_fields = 0;
if( const auto* e = ty.m_data.opt_Tuple() )
{
n_fields = e->size();
}
+ // TODO: Fixed-size arrays
else if( ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Struct() )
{
const auto& e = ty.m_data.as_Path().binding.as_Struct();
@@ -573,94 +564,59 @@ namespace
)
)
}
- else {
+ else
+ {
MIR_BUG(mir_res, "Unknown type being accessed with Field - " << ty);
}
- auto new_cur_vs = this->allocate_composite(n_fields, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
- }
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
+ cur_vs = State(this->allocate_composite(n_fields, cur_vs));
}
// Get composite state and assign into it
- auto& states = *states_p;
- MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range");
- this->clear_state(mir_res, states[e.field_index]);
- states[e.field_index] = mv$(new_vs);
- }
- ),
- (Deref,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
- if( !cur_vs.is_composite() && cur_vs == new_vs )
- {
- // Not a composite, and no state change
- }
- else
- {
- ::std::vector<State>* states_p;
+ auto& states = this->get_composite(mir_res, cur_vs);
+ MIR_ASSERT(mir_res, e< states.size(), "Field index out of range");
+ state_p = &states[e];
+ ),
+ (Deref,
if( !cur_vs.is_composite() )
{
+ // TODO: Should this check if the type is Box?
//::HIR::TypeRef tmp;
//const auto& ty = mir_res.get_lvalue_type(tmp, *e.val);
- // TODO: Should this check if the type is Box?
- auto new_cur_vs = this->allocate_composite(2, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
- }
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
+ cur_vs = State(this->allocate_composite(2, cur_vs));
}
// Get composite state and assign into it
- auto& states = *states_p;
+ auto& states = this->get_composite(mir_res, cur_vs);
MIR_ASSERT(mir_res, states.size() == 2, "Deref with invalid state list size");
- this->clear_state(mir_res, states[1]);
- states[1] = mv$(new_vs);
- }
- ),
- (Index,
- const auto& vs_v = get_lvalue_state(mir_res, *e.val);
- const auto& vs_i = get_lvalue_state(mir_res, *e.idx);
- MIR_ASSERT(mir_res, !vs_v.is_composite(), "");
- MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
+ state_p = &states[1];
+ ),
+ (Index,
+ const auto& vs_i = get_lvalue_state(mir_res, ::MIR::LValue::new_Local(e));
+ MIR_ASSERT(mir_res, !cur_vs.is_composite(), "");
+ MIR_ASSERT(mir_res, !vs_i.is_composite(), "");
- MIR_ASSERT(mir_res, vs_v.is_valid(), "Indexing an invalid value");
- MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index");
+ MIR_ASSERT(mir_res, cur_vs.is_valid(), "Indexing an invalid value");
+ MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalid index");
- // NOTE: Ignore
- ),
- (Downcast,
- const auto& cur_vs = get_lvalue_state(mir_res, *e.val);
- if( !cur_vs.is_composite() && cur_vs == new_vs )
- {
- // Not a composite, and no state change
- }
- else
- {
- ::std::vector<State>* states_p;
+ // NOTE: Ignore
+ return ;
+ ),
+ (Downcast,
if( !cur_vs.is_composite() )
{
- auto new_cur_vs = this->allocate_composite(1, cur_vs);
- set_lvalue_state(mir_res, *e.val, State(new_cur_vs));
- states_p = &this->get_composite(mir_res, new_cur_vs);
+ cur_vs = State(this->allocate_composite(1, cur_vs));
}
- else
- {
- states_p = &this->get_composite(mir_res, cur_vs);
- }
-
// Get composite state and assign into it
- auto& states = *states_p;
- MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << *e.val << " - " << this->fmt_state(mir_res, *e.val));
+ auto& states = this->get_composite(mir_res, cur_vs);
+ MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << lv << " - " << StateFmt(*this, cur_vs));
this->clear_state(mir_res, states[0]);
states[0] = mv$(new_vs);
- }
+ )
)
- )
+ assert(state_p);
+ }
+ this->clear_state(mir_res, *state_p);
+ *state_p = mv$(new_vs);
}
};
@@ -939,7 +895,7 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
(Incomplete,
),
(Return,
- state.ensure_lvalue_valid(mir_res, ::MIR::LValue::make_Return({}));
+ state.ensure_lvalue_valid(mir_res, ::MIR::LValue::new_Return());
if( ENABLE_LEAK_DETECTOR )
{
auto ensure_dropped = [&](const State& s, const ::MIR::LValue& lv) {
@@ -955,10 +911,10 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio
}
};
for(unsigned i = 0; i < state.locals.size(); i ++ ) {
- ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i));
+ ensure_dropped(state.locals[i], ::MIR::LValue::new_Local(i));
}
for(unsigned i = 0; i < state.args.size(); i ++ ) {
- ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i}));
+ ensure_dropped(state.args[i], ::MIR::LValue::new_Argument(i));
}
}
),
diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp
index 5d32d0c8..b535c7ce 100644
--- a/src/mir/cleanup.cpp
+++ b/src/mir/cleanup.cpp
@@ -33,7 +33,7 @@ struct MirMutator
::MIR::LValue new_temporary(::HIR::TypeRef ty)
{
- auto rv = ::MIR::LValue::make_Local( static_cast<unsigned int>(m_fcn.locals.size()) );
+ auto rv = ::MIR::LValue::new_Local( static_cast<unsigned int>(m_fcn.locals.size()) );
m_fcn.locals.push_back( mv$(ty) );
return rv;
}
@@ -493,12 +493,13 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con
// Allocate a temporary for the vtable pointer itself
auto vtable_lv = mutator.new_temporary( mv$(vtable_ty) );
// - Load the vtable and store it
- auto ptr_lv = ::MIR::LValue::make_Deref({ box$(receiver_lvp.clone()) });
+ auto ptr_lv = ::MIR::LValue::new_Deref( receiver_lvp.clone() );
MIR_Cleanup_LValue(state, mutator, ptr_lv);
- auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(*ptr_lv.as_Deref().val) });
+ ptr_lv.m_wrappers.pop_back();
+ auto vtable_rval = ::MIR::RValue::make_DstMeta({ mv$(ptr_lv) });
mutator.push_statement( ::MIR::Statement::make_Assign({ vtable_lv.clone(), mv$(vtable_rval) }) );
- auto fcn_lval = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(vtable_lv) })), vtable_idx });
+ auto fcn_lval = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref( mv$(vtable_lv) ), vtable_idx );
::HIR::TypeRef tmp;
const auto& ty = state.get_lvalue_type(tmp, fcn_lval);
@@ -526,23 +527,23 @@ const ::HIR::Literal* MIR_Cleanup_GetConstant(const MIR::TypeResolve& state, con
),
(Tuple,
for(unsigned int i = 0; i < se.size(); i ++ ) {
- auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone());
+ auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i );
if( i == str.m_struct_markings.coerce_unsized_index ) {
- vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), ::MIR::LValue::make_Field({ box$(val), i }) ) );
+ vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].ent), mv$(val)) );
}
else {
- vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) );
+ vals.push_back( mv$(val) );
}
}
),
(Named,
for(unsigned int i = 0; i < se.size(); i ++ ) {
- auto val = (i == se.size() - 1 ? mv$(lv) : lv.clone());
+ auto val = ::MIR::LValue::new_Field( (i == se.size() - 1 ? mv$(lv) : lv.clone()), i );
if( i == str.m_struct_markings.coerce_unsized_index ) {
- vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), ::MIR::LValue::make_Field({ box$(val), i }) ) );
+ vals.push_back( H::get_unit_ptr(state, mutator, monomorph(se[i].second.ent), mv$(val) ) );
}
else {
- vals.push_back( ::MIR::LValue::make_Field({ box$(val), i }) );
+ vals.push_back( mv$(val) );
}
}
)
@@ -777,7 +778,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
auto ty_d = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_d, false);
auto ty_s = monomorphise_type_with(state.sp, se[i].ent, monomorph_cb_s, false);
- auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i }));
+ auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i));
auto new_lval = mutator.in_temporary( mv$(ty_d), mv$(new_rval) );
ents.push_back( mv$(new_lval) );
@@ -793,7 +794,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
}
else
{
- ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) );
+ ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) );
}
}
),
@@ -806,7 +807,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
auto ty_d = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_d, false);
auto ty_s = monomorphise_type_with(state.sp, se[i].second.ent, monomorph_cb_s, false);
- auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::make_Field({ box$(value.clone()), i }));
+ auto new_rval = MIR_Cleanup_CoerceUnsized(state, mutator, ty_d, ty_s, ::MIR::LValue::new_Field(value.clone(), i));
auto new_lval = mutator.new_temporary( mv$(ty_d) );
mutator.push_statement( ::MIR::Statement::make_Assign({ new_lval.clone(), mv$(new_rval) }) );
@@ -823,7 +824,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
}
else
{
- ents.push_back( ::MIR::LValue::make_Field({ box$(value.clone()), i}) );
+ ents.push_back( ::MIR::LValue::new_Field(value.clone(), i) );
}
}
)
@@ -865,7 +866,7 @@ bool MIR_Cleanup_Unsize_GetMetadata(const ::MIR::TypeResolve& state, MirMutator&
void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::MIR::LValue& lval)
{
- TU_MATCHA( (lval), (le),
+ TU_MATCHA( (lval.m_root), (le),
(Return,
),
(Argument,
@@ -873,30 +874,22 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::
(Local,
),
(Static,
- ),
- (Field,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- ),
- (Deref,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- ),
- (Index,
- MIR_Cleanup_LValue(state, mutator, *le.val);
- MIR_Cleanup_LValue(state, mutator, *le.idx);
- ),
- (Downcast,
- MIR_Cleanup_LValue(state, mutator, *le.val);
)
)
- // If this is a deref of Box, unpack and deref the inner pointer
- if( lval.is_Deref() )
+ for(size_t i = 0; i < lval.m_wrappers.size(); i ++)
{
- auto& le = lval.as_Deref();
+ if( !lval.m_wrappers[i].is_Deref() ) {
+ continue ;
+ }
+
+ // If this is a deref of Box, unpack and deref the inner pointer
::HIR::TypeRef tmp;
- const auto& ty = state.get_lvalue_type(tmp, *le.val);
+ const auto& ty = state.get_lvalue_type(tmp, lval, lval.m_wrappers.size() - i);
if( state.m_resolve.is_type_owned_box(ty) )
{
+ unsigned num_injected_fld_zeros = 0;
+
// Handle Box by extracting it to its pointer.
// - Locate (or remember) which field in Box is the pointer, and replace the inner by that field
// > Dumb idea, assume it's always the first field. Keep accessing until located.
@@ -924,11 +917,16 @@ void MIR_Cleanup_LValue(const ::MIR::TypeResolve& state, MirMutator& mutator, ::
tmp = monomorphise_type(state.sp, str.m_params, te.path.m_data.as_Generic().m_params, *ty_tpl);
typ = &tmp;
- auto new_lval = ::MIR::LValue::make_Field({ mv$(le.val), 0 });
- le.val = box$(new_lval);
+ num_injected_fld_zeros ++;
}
MIR_ASSERT(state, typ->m_data.is_Pointer(), "First non-path field in Box wasn't a pointer - " << *typ);
// We have reached the pointer. Good.
+
+ // Inject all of the field zero accesses (before the deref)
+ while(num_injected_fld_zeros--)
+ {
+ lval.m_wrappers.insert( lval.m_wrappers.begin() + i, ::MIR::LValue::Wrapper::new_Field(0) );
+ }
}
}
}
@@ -1030,9 +1028,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
),
(DstMeta,
// HACK: Ensure that the box Deref conversion fires here.
- auto v = ::MIR::LValue::make_Deref({ box$(re.val) });
- MIR_Cleanup_LValue(state, mutator, v);
- re.val = mv$( *v.as_Deref().val );
+ re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() );
+ MIR_Cleanup_LValue(state, mutator, re.val);
+ re.val.m_wrappers.pop_back();
// If the type is an array (due to a monomorpised generic?) then replace.
::HIR::TypeRef tmp;
@@ -1053,9 +1051,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
),
(DstPtr,
// HACK: Ensure that the box Deref conversion fires here.
- auto v = ::MIR::LValue::make_Deref({ box$(re.val) });
- MIR_Cleanup_LValue(state, mutator, v);
- re.val = mv$( *v.as_Deref().val );
+ re.val.m_wrappers.push_back( ::MIR::LValue::Wrapper::new_Deref() );
+ MIR_Cleanup_LValue(state, mutator, re.val);
+ re.val.m_wrappers.pop_back();
),
(MakeDst,
MIR_Cleanup_Param(state, mutator, re.ptr_val);
@@ -1218,13 +1216,13 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path,
e.args.reserve( fcn_ty.m_arg_types.size() );
for(unsigned int i = 0; i < fcn_ty.m_arg_types.size(); i ++)
{
- e.args.push_back( ::MIR::LValue::make_Field({ box$(args_lvalue.clone()), i }) );
+ e.args.push_back( ::MIR::LValue::new_Field(args_lvalue.clone(), i) );
}
// If the trait is Fn/FnMut, dereference the input value.
if( pe.trait.m_path == resolve.m_lang_FnOnce )
e.fcn = mv$(fcn_lvalue);
else
- e.fcn = ::MIR::LValue::make_Deref({ box$(fcn_lvalue) });
+ e.fcn = ::MIR::LValue::new_Deref( mv$(fcn_lvalue) );
}
}
)
diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp
index b02c1e5b..69ffa850 100644
--- a/src/mir/dump.cpp
+++ b/src/mir/dump.cpp
@@ -176,40 +176,7 @@ namespace {
#undef FMT
}
void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) {
- TU_MATCHA( (lval), (e),
- (Return,
- os << "RETURN";
- ),
- (Argument,
- os << "arg$" << e.idx;
- ),
- (Local,
- os << "_$" << e;
- ),
- (Static,
- os << *e;
- ),
- (Field,
- os << "(";
- fmt_val(os, *e.val);
- os << ")." << e.field_index;
- ),
- (Deref,
- os << "*";
- fmt_val(os, *e.val);
- ),
- (Index,
- os << "(";
- fmt_val(os, *e.val);
- os << ")[";
- fmt_val(os, *e.idx);
- os << "]";
- ),
- (Downcast,
- fmt_val(os, *e.val);
- os << " as variant" << e.variant_index;
- )
- )
+ os << lval;
}
void fmt_val(::std::ostream& os, const ::MIR::Constant& e) {
TU_MATCHA( (e), (ce),
diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp
index 9e749811..d511a32a 100644
--- a/src/mir/from_hir.cpp
+++ b/src/mir/from_hir.cpp
@@ -177,7 +177,7 @@ namespace {
for(size_t i = 0; i < pat.m_binding.m_implicit_deref_count; i ++)
{
- lval = ::MIR::LValue::make_Deref({ box$(lval) });
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
}
switch( pat.m_binding.m_type )
@@ -215,35 +215,35 @@ namespace {
for(size_t i = 0; i < pat.m_implicit_deref_count; i ++)
{
- lval = ::MIR::LValue::make_Deref({ box$( mv$(lval) ) });
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
}
TU_MATCH_HDRA( (pat.m_data), {)
TU_ARMA(Any, e) {
}
TU_ARMA(Box, e) {
- destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable);
+ destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable);
}
TU_ARMA(Ref, e) {
- destructure_from_ex(sp, *e.sub, ::MIR::LValue::make_Deref({ box$( mv$(lval) ) }), allow_refutable);
+ destructure_from_ex(sp, *e.sub, ::MIR::LValue::new_Deref(mv$(lval)), allow_refutable);
}
TU_ARMA(Tuple, e) {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
}
TU_ARMA(SplitTuple, e) {
assert(e.total_size >= e.leading.size() + e.trailing.size());
for(unsigned int i = 0; i < e.leading.size(); i ++ )
{
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
// TODO: Is there a binding in the middle?
unsigned int ofs = e.total_size - e.trailing.size();
for(unsigned int i = 0; i < e.trailing.size(); i ++ )
{
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), ofs+i}), allow_refutable);
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), ofs+i), allow_refutable);
}
}
TU_ARMA(StructValue, e) {
@@ -252,7 +252,7 @@ namespace {
TU_ARMA(StructTuple, e) {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable);
}
}
TU_ARMA(Struct, e) {
@@ -264,7 +264,7 @@ namespace {
for(const auto& fld_pat : e.sub_patterns)
{
unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin();
- destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval.clone() ), idx}), allow_refutable);
+ destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable);
}
}
}
@@ -302,10 +302,10 @@ namespace {
ERROR(sp, E0000, "Variant " << variants[i].name << " not handled");
}
}
- auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx });
+ auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx);
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++ )
{
- destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::make_Field({ box$( lval_var.clone() ), i}), allow_refutable);
+ destructure_from_ex(sp, e.sub_patterns[i], ::MIR::LValue::new_Field(lval_var.clone(), i), allow_refutable);
}
}
TU_ARMA(EnumStruct, e) {
@@ -316,11 +316,11 @@ namespace {
const auto& str = *var.type.m_data.as_Path().binding.as_Struct();
ASSERT_BUG(sp, str.m_data.is_Named(), "Struct pattern on non-Named struct - " << e.path);
const auto& fields = str.m_data.as_Named();
- auto lval_var = ::MIR::LValue::make_Downcast({ box$(mv$(lval)), e.binding_idx });
+ auto lval_var = ::MIR::LValue::new_Downcast(mv$(lval), e.binding_idx);
for(const auto& fld_pat : e.sub_patterns)
{
unsigned idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto&x){ return x.first == fld_pat.first; } ) - fields.begin();
- destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::make_Field({ box$( lval_var.clone() ), idx}), allow_refutable);
+ destructure_from_ex(sp, fld_pat.second, ::MIR::LValue::new_Field(lval_var.clone(), idx), allow_refutable);
}
}
TU_ARMA(Slice, e) {
@@ -335,7 +335,7 @@ namespace {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++)
{
const auto& subpat = e.sub_patterns[i];
- destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable );
+ destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable );
}
}
else
@@ -346,7 +346,7 @@ namespace {
for(unsigned int i = 0; i < e.sub_patterns.size(); i ++)
{
const auto& subpat = e.sub_patterns[i];
- destructure_from_ex(sp, subpat, ::MIR::LValue::make_Field({ box$(lval.clone()), i }), allow_refutable );
+ destructure_from_ex(sp, subpat, ::MIR::LValue::new_Field(lval.clone(), i), allow_refutable );
}
}
}
@@ -374,7 +374,7 @@ namespace {
for(unsigned int i = 0; i < e.leading.size(); i ++)
{
unsigned int idx = 0 + i;
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
if( e.extra_bind.is_valid() )
{
@@ -383,7 +383,7 @@ namespace {
for(unsigned int i = 0; i < e.trailing.size(); i ++)
{
unsigned int idx = array_size - e.trailing.size() + i;
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
}
else
@@ -409,13 +409,13 @@ namespace {
::MIR::LValue len_lval;
if( e.extra_bind.is_valid() || e.trailing.size() > 0 )
{
- len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval).clone() }));
+ len_lval = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, lval) }));
}
for(unsigned int i = 0; i < e.leading.size(); i ++)
{
unsigned int idx = i;
- destructure_from_ex(sp, e.leading[i], ::MIR::LValue::make_Field({ box$(lval.clone()), idx }), allow_refutable );
+ destructure_from_ex(sp, e.leading[i], ::MIR::LValue::new_Field(lval.clone(), idx), allow_refutable );
}
if( e.extra_bind.is_valid() )
{
@@ -427,7 +427,7 @@ namespace {
::HIR::BorrowType bt = H::get_borrow_type(sp, e.extra_bind);
::MIR::LValue ptr_val = m_builder.lvalue_or_temp(sp,
::HIR::TypeRef::new_borrow( bt, inner_type.clone() ),
- ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::make_Field({ box$(lval.clone()), static_cast<unsigned int>(e.leading.size()) }) })
+ ::MIR::RValue::make_Borrow({ 0, bt, ::MIR::LValue::new_Field( lval.clone(), static_cast<unsigned int>(e.leading.size()) ) })
);
// TODO: Cast to raw pointer? Or keep as a borrow?
@@ -442,7 +442,7 @@ namespace {
auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ e.trailing.size() - i, ::HIR::CoreType::Usize }));
::MIR::LValue ofs_val = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ len_lval.clone(), ::MIR::eBinOp::SUB, mv$(sub_val) }) );
// Recurse with the indexed value
- destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::make_Index({ box$(lval.clone()), box$(ofs_val) }), allow_refutable);
+ destructure_from_ex(sp, e.trailing[i], ::MIR::LValue::new_Index( lval.clone(), ofs_val.m_root.as_Local() ), allow_refutable);
}
}
}
@@ -574,7 +574,7 @@ namespace {
TRACE_FUNCTION_F("_Return");
this->visit_node_ptr(node.m_value);
- m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Return({}), m_builder.get_result(node.span()) );
+ m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Return(), m_builder.get_result(node.span()) );
m_builder.terminate_scope_early( node.span(), m_builder.fcn_scope() );
m_builder.end_block( ::MIR::Terminator::make_Return({}) );
}
@@ -1474,7 +1474,7 @@ namespace {
limit_val = ::MIR::Constant::make_Uint({ e.size_val, ::HIR::CoreType::Usize });
),
(Slice,
- limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value).clone() });
+ limit_val = ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(node.m_value->span(), value) });
)
)
@@ -1508,7 +1508,13 @@ namespace {
m_builder.set_cur_block( arm_continue );
}
- m_builder.set_result( node.span(), ::MIR::LValue::make_Index({ box$(value), box$(index) }) );
+ if( !index.is_Local())
+ {
+ auto local_idx = m_builder.new_temporary(::HIR::CoreType::Usize);
+ m_builder.push_stmt_assign(node.span(), local_idx.clone(), mv$(index));
+ index = mv$(local_idx);
+ }
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Index( mv$(value), index.m_root.as_Local() ) );
}
void visit(::HIR::ExprNode_Deref& node) override
@@ -1591,7 +1597,7 @@ namespace {
}
}
- m_builder.set_result( node.span(), ::MIR::LValue::make_Deref({ box$(val) }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Deref( mv$(val) ) );
}
void visit(::HIR::ExprNode_Emplace& node) override
@@ -1702,7 +1708,7 @@ namespace {
// 3. Get the value and assign it into `place_raw`
node.m_value->visit(*this);
auto val = m_builder.get_result(node.span());
- m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Deref({ box$(place_raw.clone()) }), mv$(val) );
+ m_builder.push_stmt_assign( node.span(), ::MIR::LValue::new_Deref(place_raw.clone()), mv$(val), /*drop_destination=*/false );
// 3. Return a call to `finalize`
::HIR::Path finalize_path(::HIR::GenericPath {});
@@ -1806,9 +1812,7 @@ namespace {
auto place = m_builder.new_temporary( place_type );
m_builder.push_stmt_assign(node.span(), place.clone(), ::MIR::RValue::make_Cast({ mv$(place_raw), place_type.clone() }));
// 3. Do a non-dropping write into the target location (i.e. just a MIR assignment)
- // TODO: This should indicate that the destination shouldn't be dropped, but since drops don't happen on
- // reassign currently, that's not yet an issue.
- m_builder.push_stmt_assign(node.span(), ::MIR::LValue::make_Deref({box$(place.clone())}), mv$(val));
+ m_builder.push_stmt_assign(node.span(), ::MIR::LValue::new_Deref(place.clone()), mv$(val), /*drop_destination=*/false);
// 4. Convert the pointer into an `owned_box`
auto res_type = ::HIR::TypeRef::new_path(::HIR::GenericPath(lang_owned_box, mv$(trait_params_data)), &m_builder.crate().get_struct_by_path(node.span(), lang_owned_box));
auto res = m_builder.new_temporary(res_type);
@@ -2056,20 +2060,20 @@ namespace {
unsigned int idx;
if( ::std::isdigit(node.m_field.c_str()[0]) ) {
::std::stringstream(node.m_field.c_str()) >> idx;
- m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) );
}
else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Struct() ) {
const auto& str = **bep;
const auto& fields = str.m_data.as_Named();
idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin();
- m_builder.set_result( node.span(), ::MIR::LValue::make_Field({ box$(val), idx }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Field( mv$(val), idx ) );
}
else if( const auto* bep = val_ty.m_data.as_Path().binding.opt_Union() ) {
const auto& unm = **bep;
const auto& fields = unm.m_variants;
idx = ::std::find_if( fields.begin(), fields.end(), [&](const auto& x){ return x.first == node.m_field; } ) - fields.begin();
- m_builder.set_result( node.span(), ::MIR::LValue::make_Downcast({ box$(val), idx }) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Downcast( mv$(val), idx ) );
}
else {
BUG(node.span(), "Field access on non-union/struct - " << val_ty);
@@ -2202,7 +2206,7 @@ namespace {
m_builder.set_result( node.span(), mv$(tmp) );
),
(Static,
- m_builder.set_result( node.span(), ::MIR::LValue::make_Static(box$(node.m_path.clone())) );
+ m_builder.set_result( node.span(), ::MIR::LValue::new_Static(node.m_path.clone()) );
),
(StructConstant,
// TODO: Why is this still a PathValue?
@@ -2321,7 +2325,7 @@ namespace {
ASSERT_BUG(sp, str.m_data.is_Named(), "");
const ::HIR::t_struct_fields& fields = str.m_data.as_Named();
- ::MIR::LValue base_val;
+ auto base_val = ::MIR::LValue::new_Return();
if( node.m_base_value )
{
DEBUG("_StructLiteral - base");
@@ -2362,7 +2366,7 @@ namespace {
if( !node.m_base_value) {
ERROR(node.span(), E0000, "Field '" << fields[i].first << "' not specified");
}
- values[i] = ::MIR::LValue::make_Field({ box$( base_val.clone() ), i });
+ values[i] = ::MIR::LValue::new_Field( base_val.clone(), i );
}
else {
// Partial move support will handle dropping the rest?
@@ -2545,7 +2549,7 @@ namespace {
else
{
ev.define_vars_from(ptr->span(), arg.first);
- ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i}));
+ ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::new_Argument(i));
}
i ++;
}
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp
index 194fd0e0..a1f9a10f 100644
--- a/src/mir/from_hir.hpp
+++ b/src/mir/from_hir.hpp
@@ -188,13 +188,10 @@ public:
// - Values
::MIR::LValue get_variable(const Span& sp, unsigned idx) const {
- // DIASBLED: State tracking doesn't support arguments in loops/splits
-#if 1
auto it = m_var_arg_mappings.find(idx);
if(it != m_var_arg_mappings.end())
- return ::MIR::LValue::make_Argument({ it->second });
-#endif
- return ::MIR::LValue::make_Local( idx );
+ return ::MIR::LValue::new_Argument(it->second);
+ return ::MIR::LValue::new_Local(idx);
}
::MIR::LValue new_temporary(const ::HIR::TypeRef& ty);
::MIR::LValue lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val);
@@ -224,7 +221,7 @@ public:
// - Statements
// Push an assignment. NOTE: This also marks the rvalue as moved
- void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val);
+ void push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination=true);
// Push a drop (likely only used by scope cleanup)
void push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int drop_flag=~0u);
// Push a shallow drop (for Box)
@@ -296,7 +293,7 @@ private:
const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const;
VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type);
- const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0);
+ VarState* get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv);
VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv);
void terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_loop);
@@ -306,11 +303,11 @@ private:
void complete_scope(ScopeDef& sd);
public:
- void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const;
+ void with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb, const ::MIR::LValue::Wrapper* stop_wrapper=nullptr) const;
bool lvalue_is_copy(const Span& sp, const ::MIR::LValue& lv) const;
// Obtain the base fat poiner for a dst reference. Errors if it wasn't via a fat pointer
- const ::MIR::LValue& get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const;
+ ::MIR::LValue get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const;
};
class MirConverter:
diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp
index e3ddce30..2bfb1a27 100644
--- a/src/mir/from_hir_match.cpp
+++ b/src/mir/from_hir_match.cpp
@@ -1732,13 +1732,13 @@ namespace {
),
(Tuple,
ASSERT_BUG(sp, idx < e.size(), "Tuple index out of range");
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
cur_ty = &e[idx];
),
(Path,
if( idx == FIELD_DEREF ) {
// TODO: Check that the path is Box
- lval = ::MIR::LValue::make_Deref({ box$(lval) });
+ lval = ::MIR::LValue::new_Deref( mv$(lval) );
cur_ty = &e.path.m_data.as_Generic().m_params.m_types.at(0);
break;
}
@@ -1773,7 +1773,7 @@ namespace {
else {
cur_ty = &fld.ent;
}
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
),
(Named,
assert( idx < fields.size() );
@@ -1785,7 +1785,7 @@ namespace {
else {
cur_ty = &fld.ent;
}
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
)
)
),
@@ -1804,7 +1804,7 @@ namespace {
else {
cur_ty = &fld.second.ent;
}
- lval = ::MIR::LValue::make_Downcast({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Downcast(mv$(lval), idx);
),
(Enum,
auto monomorph_to_ptr = [&](const auto& ty)->const auto* {
@@ -1824,7 +1824,7 @@ namespace {
const auto& var = variants[idx];
cur_ty = monomorph_to_ptr(var.type);
- lval = ::MIR::LValue::make_Downcast({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Downcast(mv$(lval), idx);
)
)
),
@@ -1841,7 +1841,7 @@ namespace {
assert(idx < e.size_val);
cur_ty = &*e.inner;
if( idx < FIELD_INDEX_MAX )
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
else {
idx -= FIELD_INDEX_MAX;
idx = FIELD_INDEX_MAX - idx;
@@ -1851,16 +1851,16 @@ namespace {
(Slice,
cur_ty = &*e.inner;
if( idx < FIELD_INDEX_MAX )
- lval = ::MIR::LValue::make_Field({ box$(lval), idx });
+ lval = ::MIR::LValue::new_Field(mv$(lval), idx);
else {
idx -= FIELD_INDEX_MAX;
idx = FIELD_INDEX_MAX - idx;
// 1. Create an LValue containing the size of this slice subtract `idx`
- auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval).clone() }));
+ auto len_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, lval) }));
auto sub_val = ::MIR::Param(::MIR::Constant::make_Uint({ idx, ::HIR::CoreType::Usize }));
auto ofs_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_BinOp({ mv$(len_lval), ::MIR::eBinOp::SUB, mv$(sub_val) }) );
// 2. Return _Index with that value
- lval = ::MIR::LValue::make_Index({ box$(lval), box$(ofs_val) });
+ lval = ::MIR::LValue::new_Index(mv$(lval), ofs_val.as_Local());
}
),
(Borrow,
@@ -1874,7 +1874,7 @@ namespace {
cur_ty = &*e.inner;
}
DEBUG(i << " " << *cur_ty);
- lval = ::MIR::LValue::make_Deref({ box$(lval) });
+ lval = ::MIR::LValue::new_Deref(mv$(lval));
),
(Pointer,
ERROR(sp, E0000, "Attempting to match over a pointer");
@@ -1978,14 +1978,14 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
DEBUG("ty = " << ity << ", val = " << val);
const auto& ty = ity;
- TU_MATCHA( (ty.m_data), (te),
- (Infer,
+ TU_MATCH_HDRA( (ty.m_data), {)
+ TU_ARMA(Infer, _te) {
BUG(sp, "Hit _ in type - " << ty);
- ),
- (Diverge,
+ }
+ TU_ARMA(Diverge, _te) {
BUG(sp, "Matching over !");
- ),
- (Primitive,
+ }
+ TU_ARMA(Primitive, te) {
switch(te)
{
case ::HIR::CoreType::Bool: {
@@ -2152,17 +2152,20 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
case ::HIR::CoreType::Str: {
ASSERT_BUG(sp, rule.is_Value() && rule.as_Value().is_StaticString(), "");
const auto& v = rule.as_Value();
+ ASSERT_BUG(sp, val.is_Deref(), "");
+ val.m_wrappers.pop_back();
+ auto str_val = mv$(val);
auto succ_bb = builder.new_bb_unlinked();
auto test_val = ::MIR::Param(::MIR::Constant( v.as_StaticString() ));
- auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(*val.as_Deref().val), ::MIR::eBinOp::EQ, mv$(test_val) }));
+ auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(str_val), ::MIR::eBinOp::EQ, mv$(test_val) }));
builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval), succ_bb, fail_bb }) );
builder.set_cur_block(succ_bb);
} break;
}
- ),
- (Path,
+ }
+ TU_ARMA(Path, te) {
TU_MATCHA( (te.binding), (pbe),
(Unbound,
BUG(sp, "Encounterd unbound path - " << te.path);
@@ -2221,26 +2224,26 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Recurse with the new ruleset
MIR_LowerHIR_Match_Simple__GeneratePattern(builder, sp,
re.sub_rules.data(), re.sub_rules.size(),
- var_ty_m, ::MIR::LValue::make_Downcast({ box$(val.clone()), var_idx }), rule.field_path.size()+1,
+ var_ty_m, ::MIR::LValue::new_Downcast(val.clone(), var_idx), rule.field_path.size()+1,
fail_bb
);
}
) // TypePathBinding::Enum
)
- ), // Type::Data::Path
- (Generic,
+ } // Type::Data::Path
+ TU_ARMA(Generic, _te) {
BUG(sp, "Attempting to match a generic");
- ),
- (TraitObject,
+ }
+ TU_ARMA(TraitObject, te) {
BUG(sp, "Attempting to match a trait object");
- ),
- (ErasedType,
+ }
+ TU_ARMA(ErasedType, te) {
BUG(sp, "Attempting to match an erased type");
- ),
- (Array,
+ }
+ TU_ARMA(Array, te) {
TODO(sp, "Match directly on array?");
- ),
- (Slice,
+ }
+ TU_ARMA(Slice, te) {
ASSERT_BUG(sp, rule.is_Slice() || rule.is_SplitSlice() || (rule.is_Value() && rule.as_Value().is_Bytes()), "Can only match slice with Bytes or Slice rules - " << rule);
if( rule.is_Value() ) {
ASSERT_BUG(sp, *te.inner == ::HIR::CoreType::U8, "Bytes pattern on non-&[u8]");
@@ -2249,7 +2252,8 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
auto succ_bb = builder.new_bb_unlinked();
- auto inner_val = val.as_Deref().val->clone();
+ ASSERT_BUG(sp, val.is_Deref(), "Slice pattern on non-Deref - " << val);
+ auto inner_val = val.clone_unwrapped();
auto slice_rval = ::MIR::RValue::make_MakeDst({ mv$(cloned_val), mv$(size_val) });
auto test_lval = builder.lvalue_or_temp(sp, ::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, ty.clone()), mv$(slice_rval));
@@ -2262,7 +2266,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Compare length
auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.len, ::HIR::CoreType::Usize }) );
- auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() }));
+ auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) }));
auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::EQ, mv$(test_val) }));
auto len_succ_bb = builder.new_bb_unlinked();
@@ -2281,7 +2285,7 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
// Compare length
auto test_val = ::MIR::Param( ::MIR::Constant::make_Uint({ re.min_len, ::HIR::CoreType::Usize}) );
- auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val).clone() }));
+ auto len_val = builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ builder.get_ptr_to_dst(sp, val) }));
auto cmp_lval = builder.lvalue_or_temp(sp, ::HIR::CoreType::Bool, ::MIR::RValue::make_BinOp({ mv$(len_val), ::MIR::eBinOp::LT, mv$(test_val) }));
auto len_succ_bb = builder.new_bb_unlinked();
@@ -2302,23 +2306,23 @@ int MIR_LowerHIR_Match_Simple__GeneratePattern(MirBuilder& builder, const Span&
else {
BUG(sp, "Invalid rule type for slice - " << rule);
}
- ),
- (Tuple,
+ } // Type::Data::Array
+ TU_ARMA(Tuple, te) {
TODO(sp, "Match directly on tuple?");
- ),
- (Borrow,
+ }
+ TU_ARMA(Borrow, te) {
TODO(sp, "Match directly on borrow?");
- ), // Type::Data::Borrow
- (Pointer,
+ } // Type::Data::Borrow
+ TU_ARMA(Pointer, te) {
BUG(sp, "Attempting to match a pointer - " << rule << " against " << ty);
- ),
- (Function,
+ }
+ TU_ARMA(Function, te) {
BUG(sp, "Attempting to match a function pointer - " << rule << " against " << ty);
- ),
- (Closure,
+ }
+ TU_ARMA(Closure, te) {
BUG(sp, "Attempting to match a closure");
- )
- )
+ }
+ }
}
return 0;
}
@@ -3035,10 +3039,10 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
}
m_builder.end_block( ::MIR::Terminator::make_Goto(def_blk) );
} break;
- case ::HIR::CoreType::Str:
+ case ::HIR::CoreType::Str: {
// Remove the deref on the &str
- auto oval = mv$(val);
- auto val = mv$(*oval.as_Deref().val);
+ ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "&str match on non-Deref lvalue - " << val);
+ val.m_wrappers.pop_back();
::std::vector< ::MIR::BasicBlockId> targets;
::std::vector< ::std::string> values;
@@ -3062,7 +3066,7 @@ void MatchGenGrouped::gen_dispatch__primitive(::HIR::TypeRef ty, ::MIR::LValue v
m_builder.end_block( ::MIR::Terminator::make_SwitchValue({
mv$(val), def_blk, mv$(targets), ::MIR::SwitchValues(mv$(values))
}) );
- break;
+ } break;
}
}
@@ -3100,7 +3104,7 @@ void MatchGenGrouped::gen_dispatch__enum(::HIR::TypeRef ty, ::MIR::LValue val, c
void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val, const ::std::vector<t_rules_subset>& rules, size_t ofs, const ::std::vector<::MIR::BasicBlockId>& arm_targets, ::MIR::BasicBlockId def_blk)
{
- auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() }));
+ auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) }));
// TODO: Re-sort the rules list to interleve Constant::Bytes and Slice
@@ -3162,8 +3166,8 @@ void MatchGenGrouped::gen_dispatch__slice(::HIR::TypeRef ty, ::MIR::LValue val,
m_builder.set_cur_block(succ_blk);
// TODO: What if `val` isn't a Deref?
- ASSERT_BUG(sp, val.is_Deref(), "TODO: Handle non-Deref matches of byte strings");
- cmp_lval_eq = this->push_compare( val.as_Deref().val->clone(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) );
+ ASSERT_BUG(sp, !val.m_wrappers.empty() && val.m_wrappers.back().is_Deref(), "TODO: Handle non-Deref matches of byte strings - " << val);
+ cmp_lval_eq = this->push_compare( val.clone_unwrapped(), ::MIR::eBinOp::EQ, mv$(cmp_slice_val) );
m_builder.end_block( ::MIR::Terminator::make_If({ mv$(cmp_lval_eq), arm_targets[tgt_ofs], def_blk }) );
m_builder.set_cur_block(next_cmp_blk);
@@ -3273,7 +3277,7 @@ void MatchGenGrouped::gen_dispatch_splitslice(const field_path_t& field_path, co
ASSERT_BUG(sp, ty.m_data.is_Slice(), "SplitSlice pattern on non-slice - " << ty);
// Obtain slice length
- auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val).clone() }));
+ auto val_len = m_builder.lvalue_or_temp(sp, ::HIR::CoreType::Usize, ::MIR::RValue::make_DstMeta({ m_builder.get_ptr_to_dst(sp, val) }));
// 1. Check that length is sufficient for the pattern to be used
// `IF len < min_len : def_blk, next
diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp
index 1453acb3..6f0ef891 100644
--- a/src/mir/helpers.cpp
+++ b/src/mir/helpers.cpp
@@ -12,9 +12,12 @@
#include <mir/mir.hpp>
#include <algorithm> // ::std::find
-void ::MIR::TypeResolve::fmt_pos(::std::ostream& os) const
+void ::MIR::TypeResolve::fmt_pos(::std::ostream& os, bool include_path/*=false*/) const
{
- os << this->m_path << " BB" << this->bb_idx << "/";
+ if( include_path ) {
+ os << this->m_path << " ";
+ }
+ os << "BB" << this->bb_idx << "/";
if( this->stmt_idx == STMT_TERM ) {
os << "TERM";
}
@@ -27,7 +30,7 @@ void ::MIR::TypeResolve::print_msg(const char* tag, ::std::function<void(::std::
{
auto& os = ::std::cerr;
os << "MIR " << tag << ": ";
- fmt_pos(os);
+ fmt_pos(os, true);
cb(os);
os << ::std::endl;
abort();
@@ -67,25 +70,39 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_static_type(::HIR::TypeRef& tmp, c
)
throw "";
}
-const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const
+const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count/*=0*/) const
{
- TU_MATCH(::MIR::LValue, (val), (e),
+ const ::HIR::TypeRef* rv = nullptr;
+ TU_MATCHA( (val.m_root), (e),
(Return,
- return m_ret_type;
+ rv = &m_ret_type;
),
(Argument,
- MIR_ASSERT(*this, e.idx < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")");
- return m_args.at(e.idx).second;
+ MIR_ASSERT(*this, e < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")");
+ rv = &m_args.at(e).second;
),
(Local,
MIR_ASSERT(*this, e < m_fcn.locals.size(), "Local " << val << " out of range (" << m_fcn.locals.size() << ")");
- return m_fcn.locals.at(e);
+ rv = &m_fcn.locals.at(e);
),
(Static,
- return get_static_type(tmp, *e);
- ),
- (Field,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ rv = &get_static_type(tmp, e);
+ )
+ )
+ assert(wrapper_skip_count <= val.m_wrappers.size());
+ const auto* stop_wrapper = &val.m_wrappers[ val.m_wrappers.size() - wrapper_skip_count ];
+ for(const auto& w : val.m_wrappers)
+ {
+ if( &w == stop_wrapper )
+ break;
+ rv = &this->get_unwrapped_type(tmp, w, *rv);
+ }
+ return *rv;
+}
+const ::HIR::TypeRef& ::MIR::TypeResolve::get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const
+{
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, field_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Field access on unexpected type - " << ty);
@@ -98,14 +115,14 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
),
(Tuple,
- MIR_ASSERT(*this, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size());
- return te[e.field_index];
+ MIR_ASSERT(*this, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size());
+ return te[field_index];
),
(Path,
if( const auto* tep = te.binding.opt_Struct() )
{
const auto& str = **tep;
- auto monomorph = [&](const auto& ty)->const auto& {
+ auto maybe_monomorph = [&](const auto& ty)->const auto& {
if( monomorphise_type_needed(ty) ) {
tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty);
m_resolve.expand_associated_types(sp, tmp);
@@ -120,12 +137,12 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
MIR_BUG(*this, "Field on unit-like struct - " << ty);
),
(Tuple,
- MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in tuple-struct " << te.path);
- return monomorph(se[e.field_index].ent);
+ MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in tuple-struct " << te.path);
+ return maybe_monomorph(se[field_index].ent);
),
(Named,
- MIR_ASSERT(*this, e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se[e.field_index].second.ent);
+ MIR_ASSERT(*this, field_index < se.size(), "Field index out of range in struct " << te.path);
+ return maybe_monomorph(se[field_index].second.ent);
)
)
}
@@ -142,8 +159,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return t;
}
};
- MIR_ASSERT(*this, e.field_index < unm.m_variants.size(), "Field index out of range for union");
- return maybe_monomorph(unm.m_variants.at(e.field_index).second.ent);
+ MIR_ASSERT(*this, field_index < unm.m_variants.size(), "Field index out of range for union");
+ return maybe_monomorph(unm.m_variants.at(field_index).second.ent);
}
else
{
@@ -151,9 +168,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
}
)
)
- ),
- (Deref,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Deref, _e) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Deref on unexpected type - " << ty);
@@ -174,9 +190,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
)
)
- ),
- (Index,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Index, index_local) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Index on unexpected type - " << ty);
@@ -188,9 +203,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
return *te.inner;
)
)
- ),
- (Downcast,
- const auto& ty = this->get_lvalue_type(tmp, *e.val);
+ }
+ TU_ARMA(Downcast, variant_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
MIR_BUG(*this, "Downcast on unexpected type - " << ty);
@@ -202,8 +216,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
const auto& enm = *te.binding.as_Enum();
MIR_ASSERT(*this, enm.m_data.is_Data(), "Downcast on non-data enum - " << ty);
const auto& variants = enm.m_data.as_Data();
- MIR_ASSERT(*this, e.variant_index < variants.size(), "Variant index out of range for " << ty);
- const auto& variant = variants[e.variant_index];
+ MIR_ASSERT(*this, variant_index < variants.size(), "Variant index out of range for " << ty);
+ const auto& variant = variants[variant_index];
const auto& var_ty = variant.type;
if( monomorphise_type_needed(var_ty) ) {
@@ -218,12 +232,13 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
else
{
const auto& unm = *te.binding.as_Union();
- MIR_ASSERT(*this, e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants[e.variant_index];
+ MIR_ASSERT(*this, variant_index < unm.m_variants.size(), "Variant index out of range");
+ const auto& variant = unm.m_variants[variant_index];
const auto& var_ty = variant.second.ent;
+ //return m_resolve.maybe_monomorph(sp, tmp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty);
if( monomorphise_type_needed(var_ty) ) {
- tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent);
+ tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, var_ty);
m_resolve.expand_associated_types(sp, tmp);
return tmp;
}
@@ -233,8 +248,8 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c
}
)
)
- )
- )
+ }
+ }
throw "";
}
const ::HIR::TypeRef& MIR::TypeResolve::get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const
@@ -383,6 +398,15 @@ namespace visit {
{
if( cb(lv, u) )
return true;
+#if 1
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() )
+ {
+ cb(LValue::new_Local(w.as_Index()), ValUsage::Read);
+ }
+ }
+#else
TU_MATCHA( (lv), (e),
(Return,
),
@@ -408,6 +432,7 @@ namespace visit {
return visit_mir_lvalue(*e.val, u, cb);
)
)
+#endif
return false;
}
@@ -625,32 +650,15 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
{
auto assigned_lvalue = [&](size_t bb_idx, size_t stmt_idx, const ::MIR::LValue& lv) {
// NOTE: Fills the first statement after running, just to ensure that any assigned value has _a_ lifetime
- if( const auto* de = lv.opt_Local() )
+ if( lv.m_root.is_Local() )
{
- if( !mask || mask->at(*de) )
+ auto de = lv.m_root.as_Local();
+ if( !mask || mask->at(de) )
{
- MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]);
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
+ MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[de]);
+ slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
}
}
- else
- {
- // Not a direct assignment of a slot. But check if a slot is mutated as part of this.
- ::MIR::visit::visit_mir_lvalue(lv, ValUsage::Write, [&](const auto& ilv, ValUsage vu) {
- if( const auto* de = ilv.opt_Local() )
- {
- if( vu == ValUsage::Write )
- {
- if( !mask || mask->at(*de) )
- {
- MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]);
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx);
- }
- }
- }
- return false;
- });
- }
};
const auto& bb = fcn.blocks[bb_idx];
@@ -673,11 +681,12 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c
else if( const auto* se = stmt.opt_Drop() )
{
// HACK: Mark values as valid wherever there's a drop (prevents confusion by simple validator)
- if( const auto* de = se->slot.opt_Local() )
+ if( se->slot.m_wrappers.empty() && se->slot.m_root.is_Local() )
{
- if( !mask || mask->at(*de) )
+ auto de = se->slot.m_root.as_Local();
+ if( !mask || mask->at(de) )
{
- slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx);
+ slot_lifetimes[de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx);
}
}
}
diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp
index 58eee9b9..0296a1c4 100644
--- a/src/mir/helpers.hpp
+++ b/src/mir/helpers.hpp
@@ -104,7 +104,7 @@ public:
}
unsigned int get_cur_stmt_ofs() const;
- void fmt_pos(::std::ostream& os) const;
+ void fmt_pos(::std::ostream& os, bool include_path=false) const;
void print_bug(::std::function<void(::std::ostream& os)> cb) const {
print_msg("ERROR", cb);
}
@@ -116,7 +116,14 @@ public:
const ::MIR::BasicBlock& get_block(::MIR::BasicBlockId id) const;
const ::HIR::TypeRef& get_static_type(::HIR::TypeRef& tmp, const ::HIR::Path& path) const;
- const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const;
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val, unsigned wrapper_skip_count=0) const;
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::CRef& val) const {
+ return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count());
+ }
+ const ::HIR::TypeRef& get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue::MRef& val) const {
+ return get_lvalue_type(tmp, val.lv(), val.lv().m_wrappers.size() - val.wrapper_count());
+ }
+ const ::HIR::TypeRef& get_unwrapped_type(::HIR::TypeRef& tmp, const ::MIR::LValue::Wrapper& w, const ::HIR::TypeRef& ty) const;
const ::HIR::TypeRef& get_param_type(::HIR::TypeRef& tmp, const ::MIR::Param& val) const;
::HIR::TypeRef get_const_type(const ::MIR::Constant& c) const;
diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp
index 83f7e1f0..8e3045d6 100644
--- a/src/mir/mir.cpp
+++ b/src/mir/mir.cpp
@@ -91,119 +91,86 @@ namespace MIR {
throw "";
}
- ::std::ostream& operator<<(::std::ostream& os, const LValue& x)
+ void LValue::RefCommon::fmt(::std::ostream& os) const
{
- TU_MATCHA( (x), (e),
+ TU_MATCHA( (m_lv->m_root), (e),
(Return,
os << "retval";
),
(Argument,
- os << "a" << e.idx;
+ os << "a" << e;
),
(Local,
os << "_" << e;
),
(Static,
- os << "(" << *e << ")";
- ),
- (Field,
- os << *e.val << "." << e.field_index;
- ),
- (Deref,
- os << *e.val << "*";
- ),
- (Index,
- os << *e.val << "[" << *e.idx << "]";
- ),
- (Downcast,
- os << *e.val << "#" << e.variant_index;
+ os << "(" << e << ")";
)
)
+ for(size_t i = 0; i < m_wrapper_count; i ++)
+ {
+ const LValue::Wrapper& w = m_lv->m_wrappers.at(i);
+ TU_MATCHA( (w), (e),
+ (Field,
+ os << "." << e;
+ ),
+ (Deref,
+ os << "*";
+ ),
+ (Index,
+ os << "[_" << e << "]";
+ ),
+ (Downcast,
+ os << "#" << e;
+ )
+ )
+ }
+ }
+
+ ::std::ostream& operator<<(::std::ostream& os, const LValue& x)
+ {
+ LValue::CRef(x).fmt(os);
return os;
}
- bool operator<(const LValue& a, const LValue& b)
+
+ Ordering LValue::Storage::ord(const LValue::Storage& x) const
{
- if( a.tag() != b.tag() )
- return a.tag() < b.tag();
- TU_MATCHA( (a, b), (ea, eb),
- (Return,
- return false;
- ),
- (Argument,
- return ea.idx < eb.idx;
- ),
- (Local,
- return ea < eb;
- ),
- (Static,
- return ea < eb;
- ),
- (Field,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- if( ea.field_index != eb.field_index )
- return ea.field_index < eb.field_index;
- return true;
- ),
- (Deref,
- return *ea.val < *eb.val;
- ),
- (Index,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- return *ea.idx < *eb.idx;
- ),
- (Downcast,
- if( *ea.val != *eb.val )
- return *ea.val < *eb.val;
- return ea.variant_index < eb.variant_index;
- )
- )
- throw "";
+ if( x.is_Static() )
+ {
+ if( this->is_Static() )
+ return this->as_Static().ord( x.as_Static() );
+ else
+ return OrdLess;
+ }
+ else
+ {
+ if( this->is_Static() )
+ return OrdGreater;
+ }
+
+ return ::ord(this->val, x.val);
}
- bool operator==(const LValue& a, const LValue& b)
+ Ordering LValue::ord(const LValue& x) const
{
- if( a.tag() != b.tag() )
- return false;
- TU_MATCHA( (a, b), (ea, eb),
- (Return,
- return true;
- ),
- (Argument,
- return ea.idx == eb.idx;
- ),
- (Local,
- return ea == eb;
- ),
- (Static,
- return ea == eb;
- ),
- (Field,
- if( *ea.val != *eb.val )
- return false;
- if( ea.field_index != eb.field_index )
- return false;
- return true;
- ),
- (Deref,
- return *ea.val == *eb.val;
- ),
- (Index,
- if( *ea.val != *eb.val )
- return false;
- if( *ea.idx != *eb.idx )
- return false;
- return true;
- ),
- (Downcast,
- if( *ea.val != *eb.val )
- return false;
- if( ea.variant_index != eb.variant_index )
- return false;
- return true;
- )
- )
- throw "";
+ auto rv = m_root.ord(x.m_root);
+ if( rv != OrdEqual )
+ return rv;
+ return ::ord(m_wrappers, x.m_wrappers);
+ }
+ Ordering LValue::RefCommon::ord(const LValue::RefCommon& x) const
+ {
+ Ordering rv;
+ //TRACE_FUNCTION_FR(FMT_CB(ss, this->fmt(ss); ss << " ? "; x.fmt(ss);), rv);
+ rv = m_lv->m_root.ord(x.m_lv->m_root);
+ if( rv != OrdEqual )
+ return rv;
+ for(size_t i = 0; i < ::std::min(m_wrapper_count, x.m_wrapper_count); i ++)
+ {
+ rv = m_lv->m_wrappers[i].ord(x.m_lv->m_wrappers[i]);
+ if( rv != OrdEqual )
+ return rv;
+ }
+ return (rv = ::ord(m_wrapper_count, x.m_wrapper_count));
}
::std::ostream& operator<<(::std::ostream& os, const Param& x)
@@ -537,30 +504,14 @@ namespace MIR {
}
}
-::MIR::LValue MIR::LValue::clone() const
+::MIR::LValue::Storage MIR::LValue::Storage::clone() const
{
- TU_MATCHA( (*this), (e),
- (Return, return LValue(e); ),
- (Argument, return LValue(e); ),
- (Local, return LValue(e); ),
- (Static, return LValue(box$(e->clone())); ),
- (Field, return LValue::make_Field({
- box$( e.val->clone() ),
- e.field_index
- }); ),
- (Deref, return LValue::make_Deref({
- box$( e.val->clone() )
- }); ),
- (Index, return LValue::make_Index({
- box$( e.val->clone() ),
- box$( e.idx->clone() )
- }); ),
- (Downcast, return LValue::make_Downcast({
- box$( e.val->clone() ),
- e.variant_index
- }); )
- )
- throw "";
+ if( is_Static() ) {
+ return new_Static(as_Static().clone());
+ }
+ else {
+ return Storage(this->val);
+ }
}
::MIR::Constant MIR::Constant::clone() const
{
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index 63acf89d..f3d61dfa 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -12,21 +12,27 @@
#include <memory> // std::unique_ptr
#include <hir/type.hpp>
+class MonomorphState;
+
namespace MIR {
typedef unsigned int RegionId;
typedef unsigned int BasicBlockId;
-#if 0
-// TODO: Store LValues as:
+// Store LValues as:
// - A packed root value (one word, using the low bits as an enum descriminator)
// - A list of (inner to outer) wrappers
struct LValue
{
class Storage
{
+ public:
+ const static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits
+ private:
+
uintptr_t val;
- static uintptr_t MAX_ARG = (1 << 30) - 1; // max value of 30 bits
+
+ Storage(uintptr_t v): val(v) {}
public:
Storage(const Storage&) = delete;
Storage& operator=(const Storage&) = delete;
@@ -40,41 +46,89 @@ struct LValue
this->~Storage();
this->val = x.val;
x.val = 0;
+ return *this;
}
~Storage()
{
if( is_Static() ) {
- delete reinterpret_cast<::HIR::Path*>(val & ~3u);
+ delete reinterpret_cast<::HIR::Path*>(val & ~3ull);
val = 0;
}
}
- static Storage new_Return() { return Storage { MAX_ARG << 2 }; }
- static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage { idx << 2 }; )
- static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage { (idx << 2) | 1 } };
+ static Storage new_Return() { return Storage(0 << 2); }
+ static Storage new_Argument(unsigned idx) { assert(idx < MAX_ARG); return Storage((idx+1) << 2); }
+ static Storage new_Local(unsigned idx) { assert(idx <= MAX_ARG); return Storage((idx << 2) | 1); }
static Storage new_Static(::HIR::Path p) {
::HIR::Path* ptr = new ::HIR::Path(::std::move(p));
- return Storage { static_cast<uintptr_t>(ptr) | 2; }
+ return Storage(reinterpret_cast<uintptr_t>(ptr) | 2);
+ }
+
+ Storage clone() const;
+
+ uintptr_t get_inner() const {
+ assert(!is_Static());
+ return val;
+ }
+ static Storage from_inner(uintptr_t v) {
+ assert( (v & 3) < 2 );
+ return Storage(v);
+ }
+
+ enum Tag {
+ TAG_Argument,
+ TAG_Local,
+ TAG_Static,
+ TAG_Return,
+ TAGDEAD,
+ };
+ Tag tag() const {
+ if(val == 0)
+ return TAG_Return;
+ return static_cast<Tag>(val & 3);
}
- bool is_Return() const { return val == (MAX_ARG << 2) /*&& (val & 3) == 0*/; }
- bool is_Argument() const { return val != (MAX_ARG << 2) && (val & 3) == 0; }
+ bool is_Return() const { return val == 0; }
+ bool is_Argument() const { return val != 0 && (val & 3) == 0; }
bool is_Local() const { return (val & 3) == 1; }
bool is_Static() const { return (val & 3) == 2; }
- // No as_Return
- unsigned as_Argument() const { assert(is_Argument()); return val >> 2; }
- unsigned as_Local() const { assert(is_Local()); return val >> 2; }
- const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast<const ::HIR::Path*>(val & ~3u); }
+ const char as_Return () const { assert(is_Return()); return 0; }
+ const unsigned as_Argument() const { assert(is_Argument()); return (val >> 2) - 1; }
+ const unsigned as_Local () const { assert(is_Local()); return val >> 2; }
+
+ const ::HIR::Path& as_Static() const { assert(is_Static()); return *reinterpret_cast<const ::HIR::Path*>(val & ~3llu); }
+ ::HIR::Path& as_Static() { assert(is_Static()); return *reinterpret_cast< ::HIR::Path*>(val & ~3llu); }
+
+ Ordering ord(const Storage& x) const;
+ bool operator==(const Storage& x) const { return this->ord(x) == OrdEqual; }
+ bool operator!=(const Storage& x) const { return this->ord(x) != OrdEqual; }
};
class Wrapper
{
- uintptr_t val;
+ uint32_t val;
+ Wrapper(uint32_t v): val(v) {}
public:
- static Wrapper new_Deref() { return Wrapper { 0 }; }
- static Wrapepr new_Field (unsigned idx) { return Wrapper { (idx << 2) | 1 }; }
- static Wrapepr new_Downcast(unsigned idx) { return Wrapper { (idx << 2) | 2 }; }
- static Wrapepr new_Index (unsigned idx) { return Wrapper { (idx << 2) | 3 }; }
+ static Wrapper new_Deref() { return Wrapper( 0 ); }
+ static Wrapper new_Field (unsigned idx) { return Wrapper( (idx << 2) | 1 ); }
+ static Wrapper new_Downcast(unsigned idx) { return Wrapper( (idx << 2) | 2 ); }
+ static Wrapper new_Index (unsigned idx) { if(idx == ~0u) idx = Storage::MAX_ARG; return Wrapper( (idx << 2) | 3 ); }
+
+ uint32_t get_inner() const { return val; }
+ static Wrapper from_inner(uint32_t v) {
+ return Wrapper(v);
+ }
+
+ enum Tag {
+ TAG_Deref,
+ TAG_Field,
+ TAG_Downcast,
+ TAG_Index,
+ TAGDEAD,
+ };
+ Tag tag() const {
+ return static_cast<Tag>(val & 3);
+ }
bool is_Deref () const { return (val & 3) == 0; }
// Stores the field index
@@ -84,79 +138,269 @@ struct LValue
// Stores a Local index
bool is_Index () const { return (val & 3) == 3; }
- // no as_Deref()
- const unsigned as_Field() const { assert(is_Field()); return (val >> 2); }
+ const char as_Deref () const { assert(is_Deref()); return 0; }
+ const unsigned as_Field () const { assert(is_Field()); return (val >> 2); }
const unsigned as_Downcast() const { assert(is_Downcast()); return (val >> 2); }
// TODO: Should this return a LValue?
- const unsigned as_Index() const { assert(is_Index()); return (val >> 2); }
+ const unsigned as_Index () const { assert(is_Index()); unsigned rv = (val >> 2); return rv; }
+
+ void inc_Field () { assert(is_Field ()); *this = Wrapper::new_Field (as_Field () + 1); }
+ void inc_Downcast() { assert(is_Downcast()); *this = Wrapper::new_Downcast(as_Downcast() + 1); }
+
+ Ordering ord(const Wrapper& x) const { return ::ord(val, x.val); }
};
Storage m_root;
::std::vector<Wrapper> m_wrappers;
- static LValue new_Return() { return LValue { Storage::new_Return(), {} }; }
- static LValue new_Argument(unsigned idx) { return LValue { Storage::new_Argument(idx), {} }; }
- static LValue new_Local(unsigned idx) { return LValue { Storage::new_Local(idx), {} }; }
- static LValue new_Static(::HIR::Path p) { return LValue { Storage::new_Static(::std::move(p)), {} }; }
+ LValue()
+ :m_root( Storage::new_Return() )
+ {
+ }
+ LValue(Storage root, ::std::vector<Wrapper> wrappers)
+ :m_root( ::std::move(root) )
+ ,m_wrappers( ::std::move(wrappers) )
+ {
+ }
+
+ static LValue new_Return () { return LValue(Storage::new_Return(), {}); }
+ static LValue new_Argument(unsigned idx ) { return LValue(Storage::new_Argument(idx), {}); }
+ static LValue new_Local (unsigned idx ) { return LValue(Storage::new_Local(idx), {}); }
+ static LValue new_Static (::HIR::Path p) { return LValue(Storage::new_Static(::std::move(p)), {}); }
+
+ static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); return lv; }
+ static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); return lv; }
+ static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); return lv; }
+ static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); return lv; }
- static LValue new_Deref(LValue lv) { lv.m_wrappers.push_back(Wrapper::new_Deref()); }
- static LValue new_Field(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Field(idx)); }
- static LValue new_Downcast(LValue lv, unsigned idx) { lv.m_wrappers.push_back(Wrapper::new_Downcast(idx)); }
- static LValue new_Index(LValue lv, unsigned local_idx) { lv.m_wrappers.push_back(Wrapper::new_Index(local_idx)); }
+ bool is_Return() const { return m_wrappers.empty() && m_root.is_Return(); }
+ bool is_Local () const { return m_wrappers.empty() && m_root.is_Local(); }
+ const unsigned as_Local() const { assert(m_wrappers.empty()); return m_root.as_Local(); }
+
+ bool is_Deref () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Deref(); }
+ bool is_Field () const { return m_wrappers.size() > 0 && m_wrappers.back().is_Field(); }
+ bool is_Downcast() const { return m_wrappers.size() > 0 && m_wrappers.back().is_Downcast(); }
+ const unsigned as_Field() const { assert(!m_wrappers.empty()); return m_wrappers.back().as_Field(); }
+
+ void inc_Field () { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Field (); }
+ void inc_Downcast() { assert(m_wrappers.size() > 0); m_wrappers.back().inc_Downcast(); }
+
+ Ordering ord(const LValue& x) const;
LValue monomorphise(const MonomorphState& ms, unsigned local_offset=0);
//LValue monomorphise(const TransParams& ms, unsigned local_offset=0);
- LValue clone() const;
+ LValue clone() const {
+ return LValue(m_root.clone(), m_wrappers);
+ }
+ LValue clone_wrapped(::std::vector<Wrapper> wrappers) const {
+ if( this->m_wrappers.empty() ) {
+ return LValue(m_root.clone(), ::std::move(wrappers));
+ }
+ else {
+ return clone_wrapped(wrappers.begin(), wrappers.end());
+ }
+ }
+ template<typename It>
+ LValue clone_wrapped(It begin_it, It end_it) const {
+ ::std::vector<Wrapper> wrappers;
+ wrappers.reserve(m_wrappers.size() + ::std::distance(begin_it, end_it));
+ wrappers.insert(wrappers.end(), m_wrappers.begin(), m_wrappers.end());
+ wrappers.insert(wrappers.end(), begin_it, end_it);
+ return LValue(m_root.clone(), ::std::move(wrappers));
+ }
+
+ LValue clone_unwrapped(unsigned count=1) const {
+ assert(count > 0);
+ assert(count <= m_wrappers.size());
+ return LValue(m_root.clone(), ::std::vector<Wrapper>(m_wrappers.begin(), m_wrappers.end() - count));
+ }
+
+ /// Helper class that represents a LValue unwrapped to a certain degree
+ class RefCommon
+ {
+ protected:
+ const LValue* m_lv;
+ size_t m_wrapper_count;
+
+ RefCommon(const LValue& lv, size_t wrapper_count)
+ :m_lv(&lv)
+ ,m_wrapper_count(wrapper_count)
+ {
+ assert(wrapper_count <= lv.m_wrappers.size());
+ }
+
+ public:
+ LValue clone() const {
+ return ::MIR::LValue( m_lv->m_root.clone(), ::std::vector<Wrapper>(m_lv->m_wrappers.begin(), m_lv->m_wrappers.begin() + m_wrapper_count) );
+ }
+
+ const LValue& lv() const { return *m_lv; }
+ size_t wrapper_count() const { return m_wrapper_count; }
+
+ /// Unwrap one level, returning false if already at the root
+ bool try_unwrap() {
+ if( m_wrapper_count == 0 ) {
+ return false;
+ }
+ else {
+ m_wrapper_count --;
+ return true;
+ }
+ }
+
+ enum Tag {
+ TAGDEAD,
+ TAG_Return,
+ TAG_Argument,
+ TAG_Local,
+ TAG_Static,
+ TAG_Deref,
+ TAG_Field,
+ TAG_Downcast,
+ TAG_Index,
+ };
+ Tag tag() const {
+ if( m_wrapper_count == 0 )
+ {
+ switch(m_lv->m_root.tag())
+ {
+ case Storage::TAGDEAD: return TAGDEAD;
+ case Storage::TAG_Return: return TAG_Return;
+ case Storage::TAG_Argument: return TAG_Argument;
+ case Storage::TAG_Local: return TAG_Local;
+ case Storage::TAG_Static: return TAG_Static;
+ }
+ }
+ else
+ {
+ switch(m_lv->m_wrappers[m_wrapper_count-1].tag())
+ {
+ case Wrapper::TAGDEAD: return TAGDEAD;
+ case Wrapper::TAG_Deref: return TAG_Deref;
+ case Wrapper::TAG_Field: return TAG_Field;
+ case Wrapper::TAG_Downcast: return TAG_Downcast;
+ case Wrapper::TAG_Index: return TAG_Index;
+ }
+ }
+ return TAGDEAD;
+ }
+
+ bool is_Local () const { return m_wrapper_count == 0 && m_lv->m_root.is_Local (); }
+ bool is_Return () const { return m_wrapper_count == 0 && m_lv->m_root.is_Return (); }
+ bool is_Argument() const { return m_wrapper_count == 0 && m_lv->m_root.is_Argument(); }
+ bool is_Static () const { return m_wrapper_count == 0 && m_lv->m_root.is_Static (); }
+ bool is_Deref () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Deref (); }
+ bool is_Field () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Field (); }
+ bool is_Downcast() const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Downcast(); }
+ bool is_Index () const { return m_wrapper_count >= 1 && m_lv->m_wrappers[m_wrapper_count-1].is_Index (); }
+
+ const unsigned as_Local () const { assert(is_Local ()); return m_lv->m_root.as_Local (); }
+ const char as_Return () const { assert(is_Return ()); return m_lv->m_root.as_Return (); }
+ const unsigned as_Argument() const { assert(is_Argument()); return m_lv->m_root.as_Argument(); }
+ const HIR::Path& as_Static () const { assert(is_Static ()); return m_lv->m_root.as_Static (); }
+ const char as_Deref () const { assert(is_Deref ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Deref (); }
+ const unsigned as_Field () const { assert(is_Field ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Field (); }
+ const unsigned as_Downcast() const { assert(is_Downcast()); return m_lv->m_wrappers[m_wrapper_count-1].as_Downcast(); }
+ const unsigned as_Index () const { assert(is_Index ()); return m_lv->m_wrappers[m_wrapper_count-1].as_Index (); }
- class Ref
+ void fmt(::std::ostream& os) const;
+ Ordering ord(const RefCommon& b) const;
+ };
+
+ class CRef: public RefCommon
{
- LValue& r;
- size_t wrapper_idx;
- public::
- LValue clone() const;
- void replace(LValue x) const;
+ public:
+ CRef(const LValue& lv)
+ :RefCommon(lv, lv.m_wrappers.size())
+ {
+ }
+ CRef(const LValue& lv, size_t wc)
+ :RefCommon(lv, wc)
+ {
+ }
+
+ /// Unwrap one level
+ const CRef inner_ref() const {
+ assert(m_wrapper_count > 0);
+ auto rv = *this;
+ rv.m_wrapper_count--;
+ return rv;
+ }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const CRef& x) {
+ x.fmt(os);
+ return os;
+ }
+
+ bool operator<(const CRef& b) const {
+ return this->ord(b) == OrdLess;
+ }
+ bool operator==(const CRef& b) const {
+ return this->ord(b) == OrdEqual;
+ }
};
+ class MRef: public RefCommon
+ {
+ public:
+ MRef(LValue& lv)
+ :RefCommon(lv, lv.m_wrappers.size())
+ {
+ }
+
+ operator CRef() const {
+ return CRef(*m_lv, m_wrapper_count);
+ }
+
+ MRef inner_ref() {
+ assert(m_wrapper_count > 0);
+ auto rv = *this;
+ rv.m_wrapper_count--;
+ return rv;
+ }
+ void replace(LValue x) {
+ auto& mut_lv = const_cast<LValue&>(*m_lv);
+ // Shortcut: No wrappers on source/destination (just assign the slot/root)
+ if( m_wrapper_count == 0 && x.m_wrappers.empty() ) {
+ mut_lv.m_root = ::std::move(x.m_root);
+ return ;
+ }
+ // If there's wrappers on this value (assigning over inner portion)
+ if( m_wrapper_count < m_lv->m_wrappers.size() ) {
+ // Add those wrappers to the end of the new value
+ x.m_wrappers.insert(x.m_wrappers.end(), m_lv->m_wrappers.begin() + m_wrapper_count, m_lv->m_wrappers.end());
+ }
+ // Overwrite
+ mut_lv = ::std::move(x);
+ }
+
+ friend ::std::ostream& operator<<(::std::ostream& os, const MRef& x) {
+ x.fmt(os);
+ return os;
+ }
+ };
+
+ Ordering ord(const LValue::CRef& x) const;
+ Ordering ord(const LValue::MRef& x) const;
};
-#endif
-
-// "LVALUE" - Assignable values
-TAGGED_UNION_EX(LValue, (), Return, (
- // Function return
- (Return, struct{}),
- // Function argument (input)
- (Argument, struct { unsigned int idx; }),
- // Variable/Temporary
- (Local, unsigned int),
- // `static` or `static mut`
- (Static, ::std::unique_ptr<::HIR::Path>),
- // Field access (tuple, struct, tuple struct, enum field, ...)
- // NOTE: Also used to index an array/slice by a compile-time known index (e.g. in destructuring)
- (Field, struct {
- ::std::unique_ptr<LValue> val;
- unsigned int field_index;
- }),
- // Dereference a value
- (Deref, struct {
- ::std::unique_ptr<LValue> val;
- }),
- // Index an array or slice (typeof(val) == [T; n] or [T])
- // NOTE: This is not bounds checked!
- (Index, struct {
- ::std::unique_ptr<LValue> val;
- ::std::unique_ptr<LValue> idx;
- }),
- // Interpret an enum as a particular variant
- (Downcast, struct {
- ::std::unique_ptr<LValue> val;
- unsigned int variant_index;
- })
- ), (),(), (
- LValue clone() const;
- )
- );
extern ::std::ostream& operator<<(::std::ostream& os, const LValue& x);
-extern bool operator<(const LValue& a, const LValue& b);
-extern bool operator==(const LValue& a, const LValue& b);
+static inline bool operator<(const LValue& a, const LValue::CRef& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator<(const LValue& a, const LValue::MRef& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator<(const LValue::CRef& a, const LValue& b) {
+ return b.ord(a) == OrdGreater;
+}
+static inline bool operator<(const LValue::MRef& a, const LValue& b) {
+ return b.ord(a) == OrdGreater;
+}
+static inline bool operator<(const LValue& a, const LValue& b) {
+ return a.ord(b) == OrdLess;
+}
+static inline bool operator==(const LValue& a, const LValue& b) {
+ return a.ord(b) == OrdEqual;
+}
static inline bool operator!=(const LValue& a, const LValue& b) {
return !(a == b);
}
@@ -224,7 +468,7 @@ TAGGED_UNION_EX(Constant, (), Int, (
/// Parameter - A value used when a rvalue just reads (doesn't require a lvalue)
/// Can be either a lvalue (memory address), or a constant
-TAGGED_UNION_EX(Param, (), LValue, (
+TAGGED_UNION_EX(Param, (), Constant, (
(LValue, LValue),
(Constant, Constant)
), (), (), (
@@ -237,7 +481,7 @@ TAGGED_UNION_EX(Param, (), LValue, (
)
);
-TAGGED_UNION_EX(RValue, (), Use, (
+TAGGED_UNION_EX(RValue, (), Tuple, (
(Use, LValue),
(Constant, Constant),
(SizedArray, struct {
@@ -359,7 +603,7 @@ enum class eDropKind {
SHALLOW,
DEEP,
};
-TAGGED_UNION(Statement, Assign,
+TAGGED_UNION(Statement, Asm,
// Value assigment
(Assign, struct {
LValue dst;
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index 8d534314..a064b67d 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -68,7 +68,7 @@ MirBuilder::~MirBuilder()
{
if( has_result() )
{
- push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) );
+ push_stmt_assign( sp, ::MIR::LValue::new_Return(), get_result(sp) );
}
terminate_scope_early(sp, fcn_scope());
@@ -176,7 +176,7 @@ void MirBuilder::define_variable(unsigned int idx)
auto& tmp_scope = top_scope->data.as_Owning();
assert(tmp_scope.is_temporary);
tmp_scope.slots.push_back( rv );
- return ::MIR::LValue::make_Local(rv);
+ return ::MIR::LValue::new_Local(rv);
}
::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val)
{
@@ -258,12 +258,10 @@ void MirBuilder::set_result(const Span& sp, ::MIR::RValue val)
m_result_valid = true;
}
-void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val)
+void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RValue val, bool drop_destination/*=true*/)
{
DEBUG(dst << " = " << val);
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, dst.tag() != ::MIR::LValue::TAGDEAD, "");
- ASSERT_BUG(sp, val.tag() != ::MIR::RValue::TAGDEAD, "");
auto moved_param = [&](const ::MIR::Param& p) {
if(const auto* e = p.opt_LValue()) {
@@ -344,13 +342,15 @@ void MirBuilder::push_stmt_assign(const Span& sp, ::MIR::LValue dst, ::MIR::RVal
)
// Drop target if populated
- mark_value_assigned(sp, dst);
+ if( drop_destination )
+ {
+ mark_value_assigned(sp, dst);
+ }
this->push_stmt( sp, ::MIR::Statement::make_Assign({ mv$(dst), mv$(val) }) );
}
void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/)
{
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, "");
if( lvalue_is_copy(sp, val) ) {
// Don't emit a drop for Copy values
@@ -362,7 +362,6 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int
void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/)
{
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
- ASSERT_BUG(sp, val.tag() != ::MIR::LValue::TAGDEAD, "");
// TODO: Ensure that the type is a Box?
@@ -400,22 +399,12 @@ void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt)
void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
{
- VarState* state_p = nullptr;
- // TODO: Tracking of complex asignment states (e.g. assignment of a field)
- TU_MATCH_DEF(::MIR::LValue, (dst), (e),
- (
- ),
- (Return,
- // Don't drop.
- // No state tracking for the return value
- ),
- (Argument,
- state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument);
- ),
- (Local,
- state_p = &get_slot_state_mut(sp, e, SlotType::Local);
- )
- )
+ if( dst.m_root.is_Return() )
+ {
+ ASSERT_BUG(sp, dst.m_wrappers.empty(), "Assignment to a component of the return value should be impossible.");
+ return ;
+ }
+ VarState* state_p = get_val_state_mut_p(sp, dst);;
if( state_p )
{
@@ -425,42 +414,28 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
drop_value_from_state(sp, *state_p, dst.clone());
*state_p = VarState::make_Valid({});
}
- // TODO: What about assigning into non-tracked locations? Should still cause a drop
+ else
+ {
+ // Assigning into non-tracked locations still causes a drop
+ drop_value_from_state(sp, VarState::make_Valid({}), dst.clone());
+ }
}
void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/)
{
TRACE_FUNCTION_F(val);
- TU_MATCH_DEF(::MIR::LValue, (val), (e),
- (
+ for(const auto& w : val.m_wrappers)
+ {
+ if( w.is_Index() ) {
+ // Raise index temporary
+ raise_temporaries(sp, ::MIR::LValue::new_Local(w.as_Index()), scope, to_above);
+ }
+ }
+ if( !val.m_root.is_Local() ) {
// No raising of these source values?
return ;
- ),
- // TODO: This may not be correct, because it can change the drop points and ordering
- // HACK: Working around cases where values are dropped while the result is not yet used.
- (Index,
- raise_temporaries(sp, *e.val, scope, to_above);
- raise_temporaries(sp, *e.idx, scope, to_above);
- return ;
- ),
- (Deref,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- (Field,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- (Downcast,
- raise_temporaries(sp, *e.val, scope, to_above);
- return ;
- ),
- // Actual value types
- (Local,
- )
- )
- ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val);
- const auto idx = val.as_Local();
+ }
+ const auto idx = val.m_root.as_Local();
bool is_temp = (idx >= m_first_temp_idx);
/*
if( !is_temp ) {
@@ -833,13 +808,12 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
}
auto& src_scope_def = m_scopes.at(source.idx);
-#if 1
ASSERT_BUG(sp, src_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (source)");
ASSERT_BUG(sp, src_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (source)");
auto& src_list = src_scope_def.data.as_Owning().slots;
for(auto idx : src_list)
{
- DEBUG("> Raising " << ::MIR::LValue::make_Local(idx));
+ DEBUG("> Raising " << ::MIR::LValue::new_Local(idx));
assert(idx >= m_first_temp_idx);
}
@@ -910,13 +884,6 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle
// Move all defined variables from one to the other
auto& tgt_list = tgt_scope_def.data.as_Owning().slots;
tgt_list.insert( tgt_list.end(), src_list.begin(), src_list.end() );
-#else
- auto list = src_scope_def.data.as_Temporaries().temporaries;
- for(auto idx : list)
- {
- this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target);
- }
-#endif
// Scope completed
m_scope_stack.pop_back();
@@ -979,7 +946,7 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope,
for(size_t i = 0; i < m_arg_states.size(); i ++)
{
const auto& state = get_slot_state(sp, i, SlotType::Argument);
- this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast<unsigned>(i) }));
+ this->drop_value_from_state(sp, state, ::MIR::LValue::new_Argument(static_cast<unsigned>(i)));
}
}
}
@@ -1060,7 +1027,7 @@ namespace
});
if( is_box )
{
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
}
else
{
@@ -1086,13 +1053,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
} return;
@@ -1168,7 +1135,7 @@ namespace
});
if( is_box ) {
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
}
else {
BUG(sp, "MovedOut on non-Box");
@@ -1192,19 +1159,19 @@ namespace
}
auto& ose = old_state.as_Partial();
if( is_enum ) {
- auto ilv = ::MIR::LValue::make_Downcast({ box$(lv.clone()), 0 });
+ auto ilv = ::MIR::LValue::new_Downcast(lv.clone(), 0);
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]);
- ilv.as_Downcast().variant_index ++;
+ ilv.inc_Downcast();
}
}
else {
- auto ilv = ::MIR::LValue::make_Field({ box$(lv.clone()), 0 });
+ auto ilv = ::MIR::LValue::new_Field(lv.clone(), 0);
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
merge_state(sp, builder, ilv, ose.inner_states[i], nse.inner_states[i]);
- ilv.as_Field().field_index ++;
+ ilv.inc_Field();
}
}
} return;
@@ -1268,13 +1235,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
return; }
@@ -1309,7 +1276,7 @@ namespace
builder.push_stmt_set_dropflag_val(sp, ose.outer_flag, is_valid);
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state);
return ; }
case VarState::TAG_Optional: {
const auto& nse = new_state.as_Optional();
@@ -1334,7 +1301,7 @@ namespace
builder.push_stmt_set_dropflag_other(sp, ose.outer_flag, nse);
builder.push_stmt_set_dropflag_default(sp, nse);
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, new_state);
return; }
case VarState::TAG_MovedOut: {
const auto& nse = new_state.as_MovedOut();
@@ -1342,7 +1309,7 @@ namespace
{
TODO(sp, "Handle mismatched flags in MovedOut");
}
- merge_state(sp, builder, ::MIR::LValue::make_Deref({ box$(lv.clone()) }), *ose.inner_state, *nse.inner_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Deref(lv.clone()), *ose.inner_state, *nse.inner_state);
return; }
case VarState::TAG_Partial:
BUG(sp, "MovedOut->Partial not valid");
@@ -1366,13 +1333,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], new_state);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], new_state);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], new_state);
}
}
return ;
@@ -1384,13 +1351,13 @@ namespace
if( is_enum ) {
for(size_t i = 0; i < ose.inner_states.size(); i ++)
{
- merge_state(sp, builder, ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)), ose.inner_states[i], nse.inner_states[i]);
}
}
else {
for(unsigned int i = 0; i < ose.inner_states.size(); i ++ )
{
- merge_state(sp, builder, ::MIR::LValue::make_Field({ box$(lv.clone()), i }), ose.inner_states[i], nse.inner_states[i]);
+ merge_state(sp, builder, ::MIR::LValue::new_Field(lv.clone(), i), ose.inner_states[i], nse.inner_states[i]);
}
}
} return ;
@@ -1419,8 +1386,8 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l
merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type));
}
};
- merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local);
- merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument);
+ merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::new_Local, SlotType::Local);
+ merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::new_Argument(v); }, SlotType::Argument);
}
else
{
@@ -1475,7 +1442,7 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r
auto it = states.find(idx);
const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1));
- auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx}));
+ auto lv = (type == SlotType::Local ? ::MIR::LValue::new_Local(idx) : ::MIR::LValue::new_Argument(idx));
merge_state(sp, *this, mv$(lv), out_state, src_state);
}
};
@@ -1565,7 +1532,7 @@ void MirBuilder::complete_scope(ScopeDef& sd)
auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local);
if( vs != ent.second )
{
- DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second);
+ DEBUG(::MIR::LValue::new_Local(ent.first) << " " << vs << " => " << ent.second);
vs = ::std::move(ent.second);
}
}
@@ -1574,7 +1541,7 @@ void MirBuilder::complete_scope(ScopeDef& sd)
auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument);
if( vs != ent.second )
{
- DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second);
+ DEBUG(::MIR::LValue::new_Argument(ent.first) << " " << vs << " => " << ent.second);
vs = ::std::move(ent.second);
}
}
@@ -1612,7 +1579,7 @@ void MirBuilder::complete_scope(ScopeDef& sd)
for(auto& ent : e->changed_slots)
{
auto& vs = this->get_slot_state_mut(sd.span, ent.first, SlotType::Local);
- auto lv = ::MIR::LValue::make_Local(ent.first);
+ auto lv = ::MIR::LValue::new_Local(ent.first);
DEBUG(lv << " " << vs << " => " << ent.second);
if( vs != ent.second )
{
@@ -1630,97 +1597,96 @@ void MirBuilder::complete_scope(ScopeDef& sd)
}
}
-void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb) const
+void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function<void(const ::HIR::TypeRef&)> cb, const ::MIR::LValue::Wrapper* stop_wrapper/*=nullptr*/) const
{
- TU_MATCH(::MIR::LValue, (val), (e),
+ ::HIR::TypeRef tmp;
+ const ::HIR::TypeRef* ty_p = nullptr;
+ TU_MATCHA( (val.m_root), (e),
(Return,
TODO(sp, "Return");
),
(Argument,
- cb( m_args.at(e.idx).second );
+ ty_p = &m_args.at(e).second;
),
(Local,
- cb( m_output.locals.at(e) );
+ ty_p = &m_output.locals.at(e);
),
(Static,
- TU_MATCHA( (e->m_data), (pe),
+ TU_MATCHA( (e.m_data), (pe),
(Generic,
ASSERT_BUG(sp, pe.m_params.m_types.empty(), "Path params on static");
const auto& s = m_resolve.m_crate.get_static_by_path(sp, pe.m_path);
- cb( s.m_type );
+ ty_p = &s.m_type;
),
(UfcsKnown,
- TODO(sp, "Static - UfcsKnown - " << *e);
+ TODO(sp, "Static - UfcsKnown - " << e);
),
(UfcsUnknown,
- BUG(sp, "Encountered UfcsUnknown in Static - " << *e);
+ BUG(sp, "Encountered UfcsUnknown in Static - " << e);
),
(UfcsInherent,
- TODO(sp, "Static - UfcsInherent - " << *e);
+ TODO(sp, "Static - UfcsInherent - " << e);
)
)
- ),
- (Field,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ )
+ )
+ assert(ty_p);
+ for(const auto& w : val.m_wrappers)
+ {
+ if( &w == stop_wrapper )
+ {
+ stop_wrapper = nullptr; // Reset so the below bugcheck can work
+ break;
+ }
+ const auto& ty = *ty_p;
+ ty_p = nullptr;
+ auto maybe_monomorph = [&](const ::HIR::GenericParams& params_def, const ::HIR::Path& p, const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
+ if( monomorphise_type_needed(t) ) {
+ tmp = monomorphise_type(sp, params_def, p.m_data.as_Generic().m_params, t);
+ m_resolve.expand_associated_types(sp, tmp);
+ return tmp;
+ }
+ else {
+ return t;
+ }
+ };
+ TU_MATCH_HDRA( (w), {)
+ TU_ARMA(Field, field_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Field access on unexpected type - " << ty);
),
(Array,
- cb( *te.inner );
+ ty_p = &*te.inner;
),
(Slice,
- cb( *te.inner );
+ ty_p = &*te.inner;
),
(Path,
- ::HIR::TypeRef tmp;
if( const auto* tep = te.binding.opt_Struct() )
{
const auto& str = **tep;
- auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
- if( monomorphise_type_needed(t) ) {
- tmp = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, t);
- m_resolve.expand_associated_types(sp, tmp);
- return tmp;
- }
- else {
- return t;
- }
- };
TU_MATCHA( (str.m_data), (se),
(Unit,
BUG(sp, "Field on unit-like struct - " << ty);
),
(Tuple,
- ASSERT_BUG(sp, e.field_index < se.size(),
- "Field index out of range in tuple-struct " << ty << " - " << e.field_index << " > " << se.size());
- const auto& fld = se[e.field_index];
- cb( maybe_monomorph(fld.ent) );
+ ASSERT_BUG(sp, field_index < se.size(),
+ "Field index out of range in tuple-struct " << ty << " - " << field_index << " > " << se.size());
+ const auto& fld = se[field_index];
+ ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent);
),
(Named,
- ASSERT_BUG(sp, e.field_index < se.size(),
- "Field index out of range in struct " << ty << " - " << e.field_index << " > " << se.size());
- const auto& fld = se[e.field_index].second;
- cb( maybe_monomorph(fld.ent) );
+ ASSERT_BUG(sp, field_index < se.size(),
+ "Field index out of range in struct " << ty << " - " << field_index << " > " << se.size());
+ const auto& fld = se[field_index].second;
+ ty_p = &maybe_monomorph(str.m_params, te.path, fld.ent);
)
)
}
- else if( const auto* tep = te.binding.opt_Union() )
+ else if( /*const auto* tep =*/ te.binding.opt_Union() )
{
BUG(sp, "Field access on a union isn't valid, use Downcast instead - " << ty);
- const auto& unm = **tep;
- auto maybe_monomorph = [&](const ::HIR::TypeRef& t)->const ::HIR::TypeRef& {
- if( monomorphise_type_needed(t) ) {
- tmp = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, t);
- m_resolve.expand_associated_types(sp, tmp);
- return tmp;
- }
- else {
- return t;
- }
- };
- ASSERT_BUG(sp, e.field_index < unm.m_variants.size(), "Field index out of range for union");
- cb( maybe_monomorph(unm.m_variants.at(e.field_index).second.ent) );
}
else
{
@@ -1728,14 +1694,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
}
),
(Tuple,
- ASSERT_BUG(sp, e.field_index < te.size(), "Field index out of range in tuple " << e.field_index << " >= " << te.size());
- cb( te[e.field_index] );
+ ASSERT_BUG(sp, field_index < te.size(), "Field index out of range in tuple " << field_index << " >= " << te.size());
+ ty_p = &te[field_index];
)
)
- });
- ),
- (Deref,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Deref, _e) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Deref on unexpected type - " << ty);
@@ -1743,38 +1707,34 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
(Path,
if( const auto* inner_ptr = this->is_type_owned_box(ty) )
{
- cb( *inner_ptr );
+ ty_p = &*inner_ptr;
}
else {
BUG(sp, "Deref on unexpected type - " << ty);
}
),
(Pointer,
- cb(*te.inner);
+ ty_p = &*te.inner;
),
(Borrow,
- cb(*te.inner);
+ ty_p = &*te.inner;
)
)
- });
- ),
- (Index,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Index, _index_val) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Index on unexpected type - " << ty);
),
(Slice,
- cb(*te.inner);
+ ty_p = &*te.inner;
),
(Array,
- cb(*te.inner);
+ ty_p = &*te.inner;
)
)
- });
- ),
- (Downcast,
- with_val_type(sp, *e.val, [&](const auto& ty){
+ }
+ TU_ARMA(Downcast, variant_index) {
TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te),
(
BUG(sp, "Downcast on unexpected type - " << ty);
@@ -1785,33 +1745,19 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
const auto& enm = **pbe;
ASSERT_BUG(sp, enm.m_data.is_Data(), "Downcast on non-data enum");
const auto& variants = enm.m_data.as_Data();
- ASSERT_BUG(sp, e.variant_index < variants.size(), "Variant index out of range");
- const auto& variant = variants[e.variant_index];
+ ASSERT_BUG(sp, variant_index < variants.size(), "Variant index out of range");
+ const auto& variant = variants[variant_index];
- if( monomorphise_type_needed(variant.type) ) {
- auto tmp = monomorphise_type(sp, enm.m_params, te.path.m_data.as_Generic().m_params, variant.type);
- m_resolve.expand_associated_types(sp, tmp);
- cb(tmp);
- }
- else {
- cb(variant.type);
- }
+ ty_p = &maybe_monomorph(enm.m_params, te.path, variant.type);
}
else if( const auto* pbe = te.binding.opt_Union() )
{
const auto& unm = **pbe;
- ASSERT_BUG(sp, e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants.at(e.variant_index);
+ ASSERT_BUG(sp, variant_index < unm.m_variants.size(), "Variant index out of range");
+ const auto& variant = unm.m_variants.at(variant_index);
const auto& fld = variant.second;
- if( monomorphise_type_needed(fld.ent) ) {
- auto sty = monomorphise_type(sp, unm.m_params, te.path.m_data.as_Generic().m_params, fld.ent);
- m_resolve.expand_associated_types(sp, sty);
- cb(sty);
- }
- else {
- cb(fld.ent);
- }
+ ty_p = &maybe_monomorph(unm.m_params, te.path, fld.ent);
}
else
{
@@ -1819,9 +1765,12 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::
}
)
)
- });
- )
- )
+ }
+ }
+ assert(ty_p);
+ }
+ ASSERT_BUG(sp, !stop_wrapper, "A stop wrapper was passed, but not found");
+ cb(*ty_p);
}
bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const
@@ -1998,165 +1947,177 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT
}
}
-const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count)
-{
- TODO(sp, "");
-}
-VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv)
+VarState* MirBuilder::get_val_state_mut_p(const Span& sp, const ::MIR::LValue& lv)
{
TRACE_FUNCTION_F(lv);
- TU_MATCHA( (lv), (e),
+ VarState* vs;
+ TU_MATCHA( (lv.m_root), (e),
(Return,
BUG(sp, "Move of return value");
- return get_slot_state_mut(sp, ~0u, SlotType::Local);
+ vs = &get_slot_state_mut(sp, ~0u, SlotType::Local);
),
(Argument,
- return get_slot_state_mut(sp, e.idx, SlotType::Argument);
+ vs = &get_slot_state_mut(sp, e, SlotType::Argument);
),
(Local,
- return get_slot_state_mut(sp, e, SlotType::Local);
+ vs = &get_slot_state_mut(sp, e, SlotType::Local);
),
(Static,
- BUG(sp, "Attempting to mutate state of a static");
- ),
- (Field,
- auto& ivs = get_val_state_mut(sp, *e.val);
- VarState tpl;
- TU_MATCHA( (ivs), (ivse),
- (Invalid,
- //BUG(sp, "Mutating inner state of an invalidated composite - " << lv);
- tpl = VarState::make_Valid({});
- ),
- (MovedOut,
- BUG(sp, "Field on value with MovedOut state - " << lv);
- ),
- (Partial,
- ),
- (Optional,
- tpl = ivs.clone();
- ),
- (Valid,
- tpl = VarState::make_Valid({});
- )
+ return nullptr;
+ //BUG(sp, "Attempting to mutate state of a static");
)
- if( !ivs.is_Partial() )
- {
- size_t n_flds = 0;
- with_val_type(sp, *e.val, [&](const auto& ty) {
- DEBUG("ty = " << ty);
- if(const auto* e = ty.m_data.opt_Path()) {
- ASSERT_BUG(sp, e->binding.is_Struct(), "");
- const auto& str = *e->binding.as_Struct();
- TU_MATCHA( (str.m_data), (se),
- (Unit,
- BUG(sp, "Field access of unit-like struct");
- ),
- (Tuple,
- n_flds = se.size();
- ),
- (Named,
- n_flds = se.size();
- )
- )
- }
- else if(const auto* e = ty.m_data.opt_Tuple()) {
- n_flds = e->size();
- }
- else if(const auto* e = ty.m_data.opt_Array()) {
- n_flds = e->size_val;
- }
- else {
- TODO(sp, "Determine field count for " << ty);
- }
- });
- ::std::vector<VarState> inner_vs; inner_vs.reserve(n_flds);
- for(size_t i = 0; i < n_flds; i++)
- inner_vs.push_back( tpl.clone() );
- ivs = VarState::make_Partial({ mv$(inner_vs) });
- }
- return ivs.as_Partial().inner_states.at(e.field_index);
- ),
- (Deref,
- // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop
- bool is_box = false;
- if( this->m_lang_Box )
- {
- with_val_type(sp, *e.val, [&](const auto& ty){
- DEBUG("ty = " << ty);
- is_box = this->is_type_owned_box(ty);
- });
- }
-
+ )
- if( is_box )
- {
- auto& ivs = get_val_state_mut(sp, *e.val);
- if( ! ivs.is_MovedOut() )
+ for(const auto& w : lv.m_wrappers)
+ {
+ auto& ivs = *vs;
+ vs = nullptr;
+ TU_MATCH_HDRA( (w), { )
+ TU_ARMA(Field, field_index) {
+ VarState tpl;
+ TU_MATCHA( (ivs), (ivse),
+ (Invalid,
+ //BUG(sp, "Mutating inner state of an invalidated composite - " << lv);
+ tpl = VarState::make_Valid({});
+ ),
+ (MovedOut,
+ BUG(sp, "Field on value with MovedOut state - " << lv);
+ ),
+ (Partial,
+ ),
+ (Optional,
+ tpl = ivs.clone();
+ ),
+ (Valid,
+ tpl = VarState::make_Valid({});
+ )
+ )
+ if( !ivs.is_Partial() )
{
- ::std::vector<VarState> inner;
- inner.push_back(VarState::make_Valid({}));
- unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u);
- ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag });
+ size_t n_flds = 0;
+ with_val_type(sp, lv, [&](const auto& ty) {
+ DEBUG("ty = " << ty);
+ if(const auto* e = ty.m_data.opt_Path()) {
+ ASSERT_BUG(sp, e->binding.is_Struct(), "");
+ const auto& str = *e->binding.as_Struct();
+ TU_MATCHA( (str.m_data), (se),
+ (Unit,
+ BUG(sp, "Field access of unit-like struct");
+ ),
+ (Tuple,
+ n_flds = se.size();
+ ),
+ (Named,
+ n_flds = se.size();
+ )
+ )
+ }
+ else if(const auto* e = ty.m_data.opt_Tuple()) {
+ n_flds = e->size();
+ }
+ else if(const auto* e = ty.m_data.opt_Array()) {
+ n_flds = e->size_val;
+ }
+ else {
+ TODO(sp, "Determine field count for " << ty);
+ }
+ }, &w);
+ ::std::vector<VarState> inner_vs; inner_vs.reserve(n_flds);
+ for(size_t i = 0; i < n_flds; i++)
+ inner_vs.push_back( tpl.clone() );
+ ivs = VarState::make_Partial({ mv$(inner_vs) });
+ }
+ vs = &ivs.as_Partial().inner_states.at(field_index);
+ }
+ TU_ARMA(Deref, _e) {
+ // HACK: If the dereferenced type is a Box ("owned_box") then hack in move and shallow drop
+ bool is_box = false;
+ if( this->m_lang_Box )
+ {
+ with_val_type(sp, lv, [&](const auto& ty){
+ DEBUG("ty = " << ty);
+ is_box = this->is_type_owned_box(ty);
+ }, &w);
}
- return *ivs.as_MovedOut().inner_state;
- }
- else
- {
- BUG(sp, "Move out of deref with non-Copy values - &move? - " << lv << " : " << FMT_CB(ss, this->with_val_type(sp, lv, [&](const auto& ty){ss<<ty;});) );
- }
- ),
- (Index,
- BUG(sp, "Move out of index with non-Copy values - Partial move?");
- ),
- (Downcast,
- // TODO: What if the inner is Copy? What if the inner is a hidden pointer?
- auto& ivs = get_val_state_mut(sp, *e.val);
- //static VarState ivs; ivs = VarState::make_Valid({});
- if( !ivs.is_Partial() )
- {
- ASSERT_BUG(sp, !ivs.is_MovedOut(), "Downcast of a MovedOut value");
-
- size_t var_count = 0;
- with_val_type(sp, *e.val, [&](const auto& ty){
- DEBUG("ty = " << ty);
- ASSERT_BUG(sp, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
- const auto& pb = ty.m_data.as_Path().binding;
- // TODO: What about unions?
- // - Iirc, you can't move out of them so they will never have state mutated
- if( pb.is_Enum() )
- {
- const auto& enm = *pb.as_Enum();
- var_count = enm.num_variants();
- }
- else if( const auto* pbe = pb.opt_Union() )
+
+ if( is_box )
+ {
+ if( ! ivs.is_MovedOut() )
{
- const auto& unm = **pbe;
- var_count = unm.m_variants.size();
+ ::std::vector<VarState> inner;
+ inner.push_back(VarState::make_Valid({}));
+ unsigned int drop_flag = (ivs.is_Optional() ? ivs.as_Optional() : ~0u);
+ ivs = VarState::make_MovedOut({ box$(VarState::make_Valid({})), drop_flag });
}
- else
+ vs = &*ivs.as_MovedOut().inner_state;
+ }
+ else
+ {
+ return nullptr;
+ }
+ }
+ TU_ARMA(Index, e) {
+ return nullptr;
+ }
+ TU_ARMA(Downcast, variant_index) {
+ if( !ivs.is_Partial() )
+ {
+ ASSERT_BUG(sp, !ivs.is_MovedOut(), "Downcast of a MovedOut value");
+
+ size_t var_count = 0;
+ with_val_type(sp, lv, [&](const auto& ty){
+ DEBUG("ty = " << ty);
+ ASSERT_BUG(sp, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
+ const auto& pb = ty.m_data.as_Path().binding;
+ // TODO: What about unions?
+ // - Iirc, you can't move out of them so they will never have state mutated
+ if( pb.is_Enum() )
+ {
+ const auto& enm = *pb.as_Enum();
+ var_count = enm.num_variants();
+ }
+ else if( const auto* pbe = pb.opt_Union() )
+ {
+ const auto& unm = **pbe;
+ var_count = unm.m_variants.size();
+ }
+ else
+ {
+ BUG(sp, "Downcast on non-Enum/Union - " << ty);
+ }
+ }, &w);
+
+ ::std::vector<VarState> inner;
+ for(size_t i = 0; i < var_count; i ++)
{
- BUG(sp, "Downcast on non-Enum/Union - " << ty);
+ inner.push_back( VarState::make_Invalid(InvalidType::Uninit) );
}
- });
+ inner[variant_index] = mv$(ivs);
+ ivs = VarState::make_Partial({ mv$(inner) });
+ }
- ::std::vector<VarState> inner;
- for(size_t i = 0; i < var_count; i ++)
- {
- inner.push_back( VarState::make_Invalid(InvalidType::Uninit) );
+ vs = &ivs.as_Partial().inner_states.at(variant_index);
}
- inner[e.variant_index] = mv$(ivs);
- ivs = VarState::make_Partial({ mv$(inner) });
}
-
- return ivs.as_Partial().inner_states.at(e.variant_index);
- )
- )
- BUG(sp, "Fell off send of get_val_state_mut");
+ assert(vs);
+ }
+ return vs;
+}
+VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv)
+{
+ auto rv_p = this->get_val_state_mut_p(sp, lv);
+ if( !rv_p )
+ {
+ //BUG(sp, "Move out of index with non-Copy values - Partial move?");
+ BUG(sp, "Move out of deref with non-Copy values - &move? - " << lv << " : " << FMT_CB(ss, this->with_val_type(sp, lv, [&](const auto& ty){ss<<ty;});) );
+ }
+ return *rv_p;
}
void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR::LValue lv)
{
+ TRACE_FUNCTION_F(lv << " " << vs);
TU_MATCHA( (vs), (vse),
(Invalid,
),
@@ -2170,7 +2131,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
});
if( is_box )
{
- drop_value_from_state(sp, *vse.inner_state, ::MIR::LValue::make_Deref({ box$(lv.clone()) }));
+ drop_value_from_state(sp, *vse.inner_state, ::MIR::LValue::new_Deref(lv.clone()));
push_stmt_drop_shallow(sp, mv$(lv), vse.outer_flag);
}
else
@@ -2190,7 +2151,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
DEBUG("TODO: Switch based on enum value");
//for(size_t i = 0; i < vse.inner_states.size(); i ++)
//{
- // drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::make_Downcast({ box$(lv.clone()), static_cast<unsigned int>(i) }));
+ // drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::new_Downcast(lv.clone(), static_cast<unsigned int>(i)));
//}
}
else if( is_union )
@@ -2201,7 +2162,7 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR
{
for(size_t i = 0; i < vse.inner_states.size(); i ++)
{
- drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::make_Field({ box$(lv.clone()), static_cast<unsigned int>(i) }));
+ drop_value_from_state(sp, vse.inner_states[i], ::MIR::LValue::new_Field(lv.clone(), static_cast<unsigned int>(i)));
}
}
),
@@ -2219,7 +2180,7 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd)
{
const auto& vs = get_slot_state(sd.span, idx, SlotType::Local);
DEBUG("slot" << idx << " - " << vs);
- drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Local(idx) );
+ drop_value_from_state( sd.span, vs, ::MIR::LValue::new_Local(idx) );
}
),
(Split,
@@ -2243,18 +2204,18 @@ void MirBuilder::moved_lvalue(const Span& sp, const ::MIR::LValue& lv)
}
}
-const ::MIR::LValue& MirBuilder::get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const
+::MIR::LValue MirBuilder::get_ptr_to_dst(const Span& sp, const ::MIR::LValue& lv) const
{
// Undo field accesses
- const auto* lvp = &lv;
- while(lvp->is_Field())
- lvp = &*lvp->as_Field().val;
+ size_t count = 0;
+ while( count < lv.m_wrappers.size() && lv.m_wrappers[ lv.m_wrappers.size()-1 - count ].is_Field() )
+ count ++;
// TODO: Enum variants?
- ASSERT_BUG(sp, lvp->is_Deref(), "Access of an unsized field without a dereference - " << lv);
+ ASSERT_BUG(sp, count < lv.m_wrappers.size() && lv.m_wrappers[ lv.m_wrappers.size()-1 - count ].is_Deref(), "Access of an unsized field without a dereference - " << lv);
- return *lvp->as_Deref().val;
+ return lv.clone_unwrapped(count+1);
}
// --------------------------------------------------------------------
diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp
index 440f65db..a08aa055 100644
--- a/src/mir/optimise.cpp
+++ b/src/mir/optimise.cpp
@@ -305,49 +305,72 @@ namespace {
Borrow, // Any borrow
};
- bool visit_mir_lvalue_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalues_inner(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
{
- //TRACE_FUNCTION_F(lv);
- if( cb(lv, u) )
- return true;
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- ),
- (Static,
- ),
- (Field,
- // HACK: If "moving", use a "Read" value usage (covers some quirks)
- return visit_mir_lvalue_mut(*e.val, u == ValUsage::Move ? ValUsage::Read : u, cb);
- ),
- (Deref,
- return visit_mir_lvalue_mut(*e.val, u == ValUsage::Borrow ? u : ValUsage::Read, cb);
- ),
- (Index,
- bool rv = false;
- rv |= visit_mir_lvalue_mut(*e.val, u, cb);
- rv |= visit_mir_lvalue_mut(*e.idx, ValUsage::Read, cb);
- return rv;
- ),
- (Downcast,
- return visit_mir_lvalue_mut(*e.val, u, cb);
- )
- )
+ for(const auto& w : lv.m_wrappers)
+ {
+ if(w.is_Index())
+ if( cb(::MIR::LValue::new_Local(w.as_Index()), ValUsage::Read) )
+ return true;
+ }
+ return cb(lv, u);
+ }
+ bool visit_mir_lvalue_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue::MRef& , ValUsage)> cb)
+ {
+ auto lvr = ::MIR::LValue::MRef(lv);
+ do
+ {
+ if( cb(lvr, u) )
+ return true;
+ // TODO: Use a TU_MATCH?
+ if( lvr.is_Index() )
+ {
+ auto ilv = ::MIR::LValue::new_Local(lvr.as_Index());
+ auto ilv_r = ::MIR::LValue::MRef(ilv);
+ bool rv = cb(ilv_r, ValUsage::Read);
+ assert(ilv.is_Local() && ilv.as_Local() == lvr.as_Index());
+ if( rv )
+ return true;
+ }
+ else if( lvr.is_Field() )
+ {
+ // HACK: If "moving", use a "Read" value usage (covers some quirks)
+ if( u == ValUsage::Move ) {
+ u = ValUsage::Read;
+ }
+ }
+ else if( lvr.is_Deref() )
+ {
+ // TODO: Is this right?
+ if( u == ValUsage::Borrow ) {
+ u = ValUsage::Read;
+ }
+ }
+ else
+ {
+ // No change
+ }
+ } while( lvr.try_unwrap() );
return false;
}
- bool visit_mir_lvalue(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
+ bool visit_mir_lvalue(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue::CRef& , ValUsage)> cb)
{
return visit_mir_lvalue_mut( const_cast<::MIR::LValue&>(lv), u, [&](auto& v, auto u) { return cb(v,u); } );
}
+ bool visit_mir_lvalue_raw_mut(::MIR::LValue& lv, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
+ {
+ return cb(lv, u);
+ }
+ bool visit_mir_lvalue_raw(const ::MIR::LValue& lv, ValUsage u, ::std::function<bool(const ::MIR::LValue& , ValUsage)> cb)
+ {
+ return cb(lv, u);
+ }
bool visit_mir_lvalue_mut(::MIR::Param& p, ValUsage u, ::std::function<bool(::MIR::LValue& , ValUsage)> cb)
{
if( auto* e = p.opt_LValue() )
{
- return visit_mir_lvalue_mut(*e, u, cb);
+ return visit_mir_lvalue_raw_mut(*e, u, cb);
}
else
{
@@ -358,7 +381,7 @@ namespace {
{
if( const auto* e = p.opt_LValue() )
{
- return visit_mir_lvalue(*e, u, cb);
+ return visit_mir_lvalue_raw(*e, u, cb);
}
else
{
@@ -371,7 +394,7 @@ namespace {
bool rv = false;
TU_MATCHA( (rval), (se),
(Use,
- rv |= visit_mir_lvalue_mut(se, ValUsage::Move, cb); // Can move
+ rv |= visit_mir_lvalue_raw_mut(se, ValUsage::Move, cb); // Can move
),
(Constant,
),
@@ -379,23 +402,23 @@ namespace {
rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Has to be Read
),
(Borrow,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Borrow, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Borrow, cb);
),
(Cast,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Also has to be read
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb); // Also has to be read
),
(BinOp,
rv |= visit_mir_lvalue_mut(se.val_l, ValUsage::Read, cb); // Same
rv |= visit_mir_lvalue_mut(se.val_r, ValUsage::Read, cb);
),
(UniOp,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb);
),
(DstMeta,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb); // Reads
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb); // Reads
),
(DstPtr,
- rv |= visit_mir_lvalue_mut(se.val, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(se.val, ValUsage::Read, cb);
),
(MakeDst,
rv |= visit_mir_lvalue_mut(se.ptr_val, ValUsage::Move, cb);
@@ -430,19 +453,19 @@ namespace {
TU_MATCHA( (stmt), (e),
(Assign,
rv |= visit_mir_lvalues_mut(e.src, cb);
- rv |= visit_mir_lvalue_mut(e.dst, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.dst, ValUsage::Write, cb);
),
(Asm,
for(auto& v : e.inputs)
- rv |= visit_mir_lvalue_mut(v.second, ValUsage::Read, cb);
+ rv |= visit_mir_lvalue_raw_mut(v.second, ValUsage::Read, cb);
for(auto& v : e.outputs)
- rv |= visit_mir_lvalue_mut(v.second, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(v.second, ValUsage::Write, cb);
),
(SetDropFlag,
),
(Drop,
// Well, it mutates...
- rv |= visit_mir_lvalue_mut(e.slot, ValUsage::Write, cb);
+ rv |= visit_mir_lvalue_raw_mut(e.slot, ValUsage::Write, cb);
),
(ScopeEnd,
)
@@ -468,21 +491,21 @@ namespace {
(Panic,
),
(If,
- visit_mir_lvalue_mut(e.cond, ValUsage::Read, cb);
+ visit_mir_lvalue_raw_mut(e.cond, ValUsage::Read, cb);
),
(Switch,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, cb);
+ visit_mir_lvalue_raw_mut(e.val, ValUsage::Read, cb);
),
(SwitchValue,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, cb);
+ visit_mir_lvalue_raw_mut(e.val, ValUsage::Read, cb);
),
(Call,
if( e.fcn.is_Value() ) {
- visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, cb);
+ visit_mir_lvalue_raw_mut(e.fcn.as_Value(), ValUsage::Read, cb);
}
for(auto& v : e.args)
visit_mir_lvalue_mut(v, ValUsage::Move, cb);
- visit_mir_lvalue_mut(e.ret_val, ValUsage::Write, cb);
+ visit_mir_lvalue_raw_mut(e.ret_val, ValUsage::Write, cb);
)
)
}
@@ -747,12 +770,7 @@ namespace {
{
if( const auto* e = term.opt_Call() )
{
- return visit_mir_lvalue(e->ret_val, ValUsage::Write, [&](const auto& v, auto vu) {
- if( v == lv ) {
- return vu != ValUsage::Read;
- }
- return false;
- });
+ return (e->ret_val.m_root == lv.m_root);
}
else
{
@@ -1163,42 +1181,34 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
::MIR::LValue clone_lval(const ::MIR::LValue& src) const
{
- TU_MATCHA( (src), (se),
+ auto wrappers = src.m_wrappers;
+ for(auto& w : wrappers)
+ {
+ if( w.is_Index() ) {
+ w = ::MIR::LValue::Wrapper::new_Index( this->var_base + w.as_Index() );
+ }
+ }
+ TU_MATCHA( (src.m_root), (se),
(Return,
- return this->retval.clone();
+ return this->retval.clone_wrapped( mv$(wrappers) );
),
(Argument,
- const auto& arg = this->te.args.at(se.idx);
- if( this->copy_args[se.idx] != ~0u )
+ const auto& arg = this->te.args.at(se);
+ if( this->copy_args[se] != ~0u )
{
- return ::MIR::LValue::make_Local(this->copy_args[se.idx]);
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Local(this->copy_args[se]), mv$(wrappers) );
}
else
{
assert( !arg.is_Constant() ); // Should have been handled in the above
- return arg.as_LValue().clone();
+ return arg.as_LValue().clone_wrapped( mv$(wrappers) );
}
),
(Local,
- return ::MIR::LValue::make_Local(this->var_base + se);
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Local(this->var_base + se), mv$(wrappers) );
),
(Static,
- return box$(this->monomorph( *se ));
- ),
- (Deref,
- return ::MIR::LValue::make_Deref({ box$(this->clone_lval(*se.val)) });
- ),
- (Field,
- return ::MIR::LValue::make_Field({ box$(this->clone_lval(*se.val)), se.field_index });
- ),
- (Index,
- return ::MIR::LValue::make_Index({
- box$(this->clone_lval(*se.val)),
- box$(this->clone_lval(*se.idx))
- });
- ),
- (Downcast,
- return ::MIR::LValue::make_Downcast({ box$(this->clone_lval(*se.val)), se.variant_index });
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Static(this->monomorph(se)), mv$(wrappers) );
)
)
throw "";
@@ -1329,7 +1339,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
// Allocate a temporary for the return value
{
- cloner.retval = ::MIR::LValue::make_Local( fcn.locals.size() );
+ cloner.retval = ::MIR::LValue::new_Local( fcn.locals.size() );
DEBUG("- Storing return value in " << cloner.retval);
::HIR::TypeRef tmp_ty;
fcn.locals.push_back( state.get_lvalue_type(tmp_ty, te->ret_val).clone() );
@@ -1373,7 +1383,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool
{
::HIR::TypeRef tmp;
auto ty = val.is_Constant() ? state.get_const_type(val.as_Constant()) : state.get_lvalue_type(tmp, val.as_LValue()).clone();
- auto lv = ::MIR::LValue::make_Local( static_cast<unsigned>(fcn.locals.size()) );
+ auto lv = ::MIR::LValue::new_Local( static_cast<unsigned>(fcn.locals.size()) );
fcn.locals.push_back( mv$(ty) );
auto rval = val.is_Constant() ? ::MIR::RValue(mv$(val.as_Constant())) : ::MIR::RValue( mv$(val.as_LValue()) );
auto stmt = ::MIR::Statement::make_Assign({ mv$(lv), mv$(rval) });
@@ -1442,7 +1452,7 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
const auto& src_rvalue = bb.statements[it->second].as_Assign().src;
// Destination invalidated?
- if( lv.is_Local() && it->first == lv.as_Local() )
+ if( lv.m_root.is_Local() && it->first == lv.m_root.as_Local() )
{
switch(vu)
{
@@ -1463,9 +1473,9 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
case ValUsage::Borrow: // Borrows are annoying, assume they invalidate anything used
case ValUsage::Write: // Mutated? It's invalidated
case ValUsage::Move: // Moved? Now invalid
- visit_mir_lvalues(src_rvalue, [&](const auto& s_lv, auto /*s_vu*/) {
+ visit_mir_lvalues(src_rvalue, [&](const ::MIR::LValue& s_lv, auto s_vu) {
//DEBUG(" " << s_lv << " ?= " << lv);
- if( s_lv == lv )
+ if( s_lv.m_root == lv.m_root )
{
DEBUG(state << "> Invalidates source of Local(" << it->first << ") - " << src_rvalue);
invalidated = true;
@@ -1499,39 +1509,37 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// > For now, don't do the replacement if it would delete the assignment UNLESS it's directly being used)
// 2. Search for replacements
- bool top_level = true;
- visit_mir_lvalue_mut(top_lv, top_usage, [&](auto& ilv, auto /*i_usage*/) {
- if( ilv.is_Local() )
+ if( top_lv.m_root.is_Local() )
+ {
+ bool top_level = top_lv.m_wrappers.empty();
+ auto ilv = ::MIR::LValue::new_Local(top_lv.m_root.as_Local());
+ auto it = local_assignments.find(top_lv.m_root.as_Local());
+ if( it != local_assignments.end() )
{
- auto it = local_assignments.find(ilv.as_Local());
- if( it != local_assignments.end() )
+ const auto& new_val = bb.statements[it->second].as_Assign().src.as_Use();
+ // - Copy? All is good.
+ if( state.lvalue_is_copy(ilv) )
{
- // - Copy? All is good.
- if( state.lvalue_is_copy(ilv) )
- {
- ilv = bb.statements[it->second].as_Assign().src.as_Use().clone();
- DEBUG(state << "> Replace (and keep) Local(" << it->first << ") with " << ilv);
- }
- // - Top-level (directly used) also good.
- else if( top_level && top_usage == ValUsage::Move )
- {
- // TODO: DstMeta/DstPtr _doesn't_ move, so shouldn't trigger this.
- ilv = bb.statements[it->second].as_Assign().src.as_Use().clone();
- DEBUG(state << "> Replace (and remove) Local(" << it->first << ") with " << ilv);
- statements_to_remove.push_back( it->second );
- local_assignments.erase(it);
- }
- // - Otherwise, remove the record.
- else
- {
- DEBUG(state << "> Non-copy value used within a LValue, remove record of Local(" << it->first << ")");
- local_assignments.erase(it);
- }
+ top_lv = new_val.clone_wrapped(top_lv.m_wrappers.begin(), top_lv.m_wrappers.end());
+ DEBUG(state << "> Replace (and keep) Local(" << it->first << ") with " << new_val);
+ }
+ // - Top-level (directly used) also good.
+ else if( top_level && top_usage == ValUsage::Move )
+ {
+ // TODO: DstMeta/DstPtr _doesn't_ move, so shouldn't trigger this.
+ top_lv = new_val.clone();
+ DEBUG(state << "> Replace (and remove) Local(" << it->first << ") with " << new_val);
+ statements_to_remove.push_back( it->second );
+ local_assignments.erase(it);
+ }
+ // - Otherwise, remove the record.
+ else
+ {
+ DEBUG(state << "> Non-copy value used within a LValue, remove record of Local(" << it->first << ")");
+ local_assignments.erase(it);
}
}
- top_level = false;
- return false;
- });
+ }
// Return true to prevent recursion
return true;
};
@@ -1558,15 +1566,13 @@ bool MIR_Optimise_DeTemporary(::MIR::TypeResolve& state, ::MIR::Function& fcn)
// - Check if this is a new assignment
if( stmt.is_Assign() && stmt.as_Assign().dst.is_Local() && stmt.as_Assign().src.is_Use() )
{
- if( visit_mir_lvalue(stmt.as_Assign().src.as_Use(), ValUsage::Read, [&](const auto& lv, auto /*vu*/) {
- return lv == stmt.as_Assign().dst;
- }) )
+ const auto& dst_lv = stmt.as_Assign().dst;
+ const auto& src_lv = stmt.as_Assign().src.as_Use();
+ if( visit_mir_lvalues_inner(src_lv, ValUsage::Read, [&](const auto& lv, auto) { return lv.m_root == dst_lv.m_root; }) )
{
DEBUG(state << "> Don't record, self-referrential");
}
- else if( visit_mir_lvalue(stmt.as_Assign().src.as_Use(), ValUsage::Read, [&](const auto& lv, auto /*vu*/) {
- return lv.is_Deref();
- }) )
+ else if( ::std::any_of(src_lv.m_wrappers.begin(), src_lv.m_wrappers.end(), [](const auto& w){ return w.is_Deref(); }) )
{
DEBUG(state << "> Don't record, dereference");
}
@@ -1741,12 +1747,13 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f
{
DEBUG("Replacing temporaries using {" << replacements << "}");
visit_mir_lvalues_mut(state, fcn, [&](auto& lv, auto ) {
- if( auto* ve = lv.opt_Local() ) {
- auto it = replacements.find(*ve);
+ if( lv.m_root.is_Local() )
+ {
+ auto it = replacements.find(lv.m_root.as_Local());
if( it != replacements.end() )
{
MIR_DEBUG(state, lv << " => Local(" << it->second << ")");
- *ve = it->second;
+ lv.m_root = ::MIR::LValue::Storage::new_Local(it->second);
return true;
}
}
@@ -2082,33 +2089,34 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio
state.set_cur_stmt(bb_idx, i);
DEBUG(state << block.statements[i]);
visit_mir_lvalues_mut(block.statements[i], [&](::MIR::LValue& lv, auto vu) {
- if(const auto* e = lv.opt_Field())
+ if(vu == ValUsage::Read && lv.m_wrappers.size() > 1 && lv.m_wrappers.front().is_Field() && lv.m_root.is_Local())
{
- if(vu == ValUsage::Read && e->val->is_Local() ) {
- // TODO: This value _must_ be Copy for this optimisation to work.
- // - OR, it has to somehow invalidate the original tuple
- DEBUG(state << "Locating origin of " << lv);
- ::HIR::TypeRef tmp;
- if( !state.m_resolve.type_is_copy(state.sp, state.get_lvalue_type(tmp, *e->val)) )
+ auto field_index = lv.m_wrappers.front().as_Field();
+ auto inner_lv = ::MIR::LValue::new_Local(lv.m_root.as_Local());
+ auto outer_lv = ::MIR::LValue::new_Field(inner_lv.clone(), field_index);
+ // TODO: This value _must_ be Copy for this optimisation to work.
+ // - OR, it has to somehow invalidate the original tuple
+ DEBUG(state << "Locating origin of " << lv);
+ ::HIR::TypeRef tmp;
+ if( !state.m_resolve.type_is_copy(state.sp, state.get_lvalue_type(tmp, inner_lv)) )
+ {
+ DEBUG(state << "- not Copy, can't optimise");
+ return false;
+ }
+ const auto* source_lvalue = get_field(inner_lv, field_index, bb_idx, i);
+ if( source_lvalue )
+ {
+ if( outer_lv != *source_lvalue )
{
- DEBUG(state << "- not Copy, can't optimise");
- return false;
+ DEBUG(state << "Source is " << *source_lvalue);
+ lv = source_lvalue->clone_wrapped( lv.m_wrappers.begin() + 1, lv.m_wrappers.end() );
+ change_happend = true;
}
- const auto* source_lvalue = get_field(*e->val, e->field_index, bb_idx, i);
- if( source_lvalue )
+ else
{
- if( lv != *source_lvalue )
- {
- DEBUG(state << "Source is " << *source_lvalue);
- lv = source_lvalue->clone();
- change_happend = true;
- }
- else
- {
- DEBUG(state << "No change");
- }
- return false;
+ DEBUG(state << "No change");
}
+ return false;
}
}
return false;
@@ -2760,15 +2768,17 @@ bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fc
for(auto& blk : fcn.blocks)
{
auto cb = [&](auto& lv, auto _vu) {
- if(lv.is_Field() && lv.as_Field().val->is_Local())
+ if( !lv.m_wrappers.empty() && lv.m_wrappers.front().is_Field() && lv.m_root.is_Local() )
{
- auto fld_idx = lv.as_Field().field_index;
- auto it = replacements.find( lv.as_Field().val->as_Local() );
+ auto fld_idx = lv.m_wrappers.front().as_Field();
+ auto it = replacements.find( lv.m_root.as_Local() );
if( it != replacements.end() )
{
MIR_ASSERT(state, fld_idx < it->second.size(), "Tuple field index out of range");
DEBUG(state << "Replace " << lv << " with Local(" << it->second.at(fld_idx) << ")");
- lv = ::MIR::LValue::make_Local(it->second.at(fld_idx));
+
+ lv.m_wrappers.erase( lv.m_wrappers.begin() );
+ lv.m_root = ::MIR::LValue::Storage::new_Local(it->second.at(fld_idx));
}
}
return false;
@@ -2790,7 +2800,7 @@ bool MIR_Optimise_SplitAggregates(::MIR::TypeResolve& state, ::MIR::Function& fc
for(size_t i = 0; i < vals.size(); i ++)
{
- auto lv = ::MIR::LValue::make_Local(rit->second[i]);
+ auto lv = ::MIR::LValue::new_Local(rit->second[i]);
auto rv = vals[i].is_LValue()
? ::MIR::RValue(::std::move( vals[i].as_LValue() ))
: ::MIR::RValue(::std::move( vals[i].as_Constant() ))
@@ -2835,13 +2845,16 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
::std::vector<ValUse> local_uses;
void use_lvalue(const ::MIR::LValue& lv, ValUsage ut) {
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- auto& vu = local_uses[e];
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index() ){
+ //local_uses[w.as_Index()].read += 1;
+ local_uses[w.as_Index()].borrow += 1;
+ }
+ }
+ if( lv.m_root.is_Local() )
+ {
+ auto& vu = local_uses[lv.m_root.as_Local()];
switch(ut)
{
case ValUsage::Move:
@@ -2849,23 +2862,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
case ValUsage::Write: vu.write += 1; break;
case ValUsage::Borrow: vu.borrow += 1; break;
}
- ),
- (Static,
- ),
- (Field,
- use_lvalue(*e.val, ut);
- ),
- (Deref,
- use_lvalue(*e.val, ut);
- ),
- (Index,
- use_lvalue(*e.val, ut);
- use_lvalue(*e.idx, ValUsage::Read);
- ),
- (Downcast,
- use_lvalue(*e.val, ut);
- )
- )
+ }
}
} val_uses = {
::std::vector<ValUse>(fcn.locals.size())
@@ -2881,7 +2878,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// > Replace usage with the inner of the original `Use`
{
// 1. Assignments (forward propagate)
- ::std::map< ::MIR::LValue, ::MIR::RValue> replacements;
+ //::std::map< ::MIR::LValue::CRef, ::MIR::RValue> replacements;
+ ::std::vector< ::std::pair<::MIR::LValue, ::MIR::RValue> > replacements;
+ auto replacements_find = [&replacements](const ::MIR::LValue::CRef& lv) {
+ return ::std::find_if(replacements.begin(), replacements.end(), [&](const auto& e) { return lv == e.first; });
+ };
for(const auto& block : fcn.blocks)
{
if( block.terminator.tag() == ::MIR::Terminator::TAGDEAD )
@@ -2889,16 +2890,18 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
for(unsigned int stmt_idx = 0; stmt_idx < block.statements.size(); stmt_idx ++)
{
+ state.set_cur_stmt(&block - &fcn.blocks.front(), stmt_idx);
const auto& stmt = block.statements[stmt_idx];
+ DEBUG(state << stmt);
// > Assignment
if( ! stmt.is_Assign() )
continue ;
const auto& e = stmt.as_Assign();
// > Of a temporary from with a RValue::Use
- if( const auto* de = e.dst.opt_Local() )
+ if( e.dst.is_Local() )
{
- const auto& vu = val_uses.local_uses[*de];
- DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write << " B:" << vu.borrow);
+ const auto& vu = val_uses.local_uses[e.dst.as_Local()];
+ DEBUG(" - VU " << e.dst << " R:" << vu.read << " W:" << vu.write << " B:" << vu.borrow);
// TODO: Allow write many?
// > Where the variable is written once and read once
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
@@ -2908,17 +2911,16 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
continue ;
}
- DEBUG(e.dst << " = " << e.src);
if( e.src.is_Use() )
{
// Keep the complexity down
const auto* srcp = &e.src.as_Use();
- while( srcp->is_Field() )
- srcp = &*srcp->as_Field().val;
- if( !srcp->is_Local() )
+ if( ::std::any_of(srcp->m_wrappers.begin(), srcp->m_wrappers.end(), [](auto& w) { return !w.is_Field(); }) )
+ continue ;
+ if( !srcp->m_root.is_Local() )
continue ;
- if( replacements.find(*srcp) != replacements.end() )
+ if( replacements_find(*srcp) != replacements.end() )
{
DEBUG("> Can't replace, source has pending replacement");
continue;
@@ -2933,12 +2935,19 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
continue ;
}
bool src_is_lvalue = e.src.is_Use();
+ DEBUG("- Locate usage");
- auto is_lvalue_usage = [&](const auto& lv, auto ){ return lv == e.dst; };
+ auto is_lvalue_usage = [&](const auto& lv, auto ){
+ return lv.m_root == e.dst.m_root;
+ //return lv == e.dst;
+ };
// Returns `true` if the passed lvalue is used as a part of the source
auto is_lvalue_in_val = [&](const auto& lv) {
- return visit_mir_lvalues(e.src, [&](const auto& slv, auto ) { return lv == slv; });
+ return visit_mir_lvalues(e.src, [&](const auto& slv, auto ) {
+ return lv.m_root == slv.m_root;
+ //return lv == slv;
+ });
};
// Eligable for replacement
// Find where this value is used
@@ -2948,8 +2957,9 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
bool found = false;
for(unsigned int si2 = stmt_idx+1; si2 < block.statements.size(); si2 ++)
{
+ state.set_cur_stmt(&block - &fcn.blocks.front(), si2);
const auto& stmt2 = block.statements[si2];
- DEBUG("[find usage] " << stmt2);
+ DEBUG(state << "[find usage] " << stmt2);
// Usage found.
if( visit_mir_lvalues(stmt2, is_lvalue_usage) )
@@ -2981,7 +2991,15 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
}
if( !stop )
{
- DEBUG("[find usage] " << block.terminator);
+ state.set_cur_stmt_term(&block - &fcn.blocks.front());
+ DEBUG(state << "[find usage] " << block.terminator);
+ if( src_is_lvalue )
+ {
+ visit_mir_lvalues(block.terminator, [&](const auto& lv, auto vu) {
+ found |= is_lvalue_usage(lv, vu);
+ return found;
+ });
+ }
TU_MATCHA( (block.terminator), (e),
(Incomplete,
),
@@ -2995,29 +3013,15 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
(Panic,
),
(If,
- if( src_is_lvalue && visit_mir_lvalue(e.cond, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(Switch,
- if( src_is_lvalue && visit_mir_lvalue(e.val, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(SwitchValue,
- if( src_is_lvalue && visit_mir_lvalue(e.val, ValUsage::Read, is_lvalue_usage) )
- found = true;
stop = true;
),
(Call,
- if( e.fcn.is_Value() )
- if( src_is_lvalue && visit_mir_lvalue(e.fcn.as_Value(), ValUsage::Read, is_lvalue_usage) )
- found = true;
- for(const auto& v : e.args)
- {
- if( src_is_lvalue && visit_mir_lvalue(v, ValUsage::Read, is_lvalue_usage) )
- found = true;
- }
stop = true;
)
)
@@ -3025,8 +3029,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// Schedule a replacement in a future pass
if( found )
{
- DEBUG("> Replace " << e.dst << " with " << e.src.as_Use());
- replacements.insert( ::std::make_pair(e.dst.clone(), e.src.clone()) );
+ DEBUG("> Schedule replace " << e.dst << " with " << e.src.as_Use());
+ replacements.push_back( ::std::make_pair(e.dst.clone(), e.src.clone()) );
}
else
{
@@ -3035,21 +3039,26 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
} // for(stmt : block.statements)
}
+ DEBUG("replacements = " << replacements);
+
// Apply replacements within replacements
for(;;)
{
unsigned int inner_replaced_count = 0;
for(auto& r : replacements)
{
- visit_mir_lvalues_mut(r.second, [&](auto& lv, auto vu) {
+ visit_mir_lvalues_mut(r.second, [&](::MIR::LValue& lv, auto vu) {
if( vu == ValUsage::Read || vu == ValUsage::Move )
{
- auto it = replacements.find(lv);
- if( it != replacements.end() && it->second.is_Use() )
- {
- lv = it->second.as_Use().clone();
- inner_replaced_count ++;
- }
+ visit_mir_lvalue_mut(lv, vu, [&](::MIR::LValue::MRef& lvr, auto vu) {
+ auto it = replacements_find(lvr);
+ if( it != replacements.end() && it->second.is_Use() )
+ {
+ lvr.replace( it->second.as_Use().clone() );
+ inner_replaced_count ++;
+ }
+ return false;
+ });
}
return false;
});
@@ -3057,26 +3066,30 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
if( inner_replaced_count == 0 )
break;
}
+ DEBUG("replacements = " << replacements);
// Apply replacements
unsigned int replaced = 0;
while( replaced < replacements.size() )
{
auto old_replaced = replaced;
- auto cb = [&](auto& lv, auto vu){
- if( vu == ValUsage::Read || vu == ValUsage::Move )
- {
- auto it = replacements.find(lv);
- if( it != replacements.end() )
+ auto cb = [&](::MIR::LValue& lv, auto vu){
+ return visit_mir_lvalue_mut(lv, vu, [&](::MIR::LValue::MRef& lv, auto vu) {
+ if( vu == ValUsage::Read || vu == ValUsage::Move )
{
- 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 - " << lv << " with " << it->second);
- auto rval = ::std::move(it->second);
- lv = ::std::move(rval.as_Use());
- replaced += 1;
+ auto it = replacements_find(lv);
+ if( it != replacements.end() )
+ {
+ 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 - " << lv << " with " << it->second);
+ auto rval = ::std::move(it->second);
+ DEBUG("> Do replace " << lv << " => " << rval);
+ lv.replace( ::std::move(rval.as_Use()) );
+ replaced += 1;
+ }
}
- }
- return false;
+ return false;
+ });
};
for(unsigned int block_idx = 0; block_idx < fcn.blocks.size(); block_idx ++)
{
@@ -3086,10 +3099,12 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
for(auto& stmt : block.statements)
{
state.set_cur_stmt(block_idx, (&stmt - &block.statements.front()));
+ DEBUG(state << stmt);
+#if 0
if( stmt.is_Assign() && stmt.as_Assign().src.is_Use() )
{
auto& e = stmt.as_Assign();
- auto it = replacements.find(e.src.as_Use());
+ 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");
@@ -3098,6 +3113,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
}
}
else
+#endif
{
visit_mir_lvalues_mut(stmt, cb);
}
@@ -3114,8 +3130,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
state.set_cur_stmt(&block - &fcn.blocks.front(), (it - block.statements.begin()));
// If the statement was an assign of a replaced temporary, remove it.
- if( it->is_Assign() && replacements.count( it->as_Assign().dst ) > 0 )
+ auto it2 = replacements.end();
+ if( it->is_Assign() && (it2 = replacements_find(it->as_Assign().dst)) != replacements.end() ) {
+ DEBUG(state << "Delete " << *it);
it = block.statements.erase(it);
+ }
else {
MIR_ASSERT(state, !( it->is_Assign() && it->as_Assign().src.tag() == ::MIR::RValue::TAGDEAD ), "");
++it;
@@ -3137,8 +3156,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
if( it->as_Assign().src.tag() == ::MIR::RValue::TAGDEAD )
continue ;
auto& to_replace_lval = it->as_Assign().dst;
- if( const auto* e = to_replace_lval.opt_Local() ) {
- const auto& vu = val_uses.local_uses[*e];
+ if( to_replace_lval.is_Local() ){
+ const auto& vu = val_uses.local_uses[to_replace_lval.as_Local()];
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
continue ;
}
@@ -3162,8 +3181,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// `... = Use(to_replace_lval)`
// TODO: Ensure that the target isn't borrowed.
- if( const auto* e = new_dst_lval.opt_Local() ) {
- const auto& vu = val_uses.local_uses[*e];
+ if( new_dst_lval.is_Local() ) {
+ const auto& vu = val_uses.local_uses[new_dst_lval.as_Local()];
if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) )
break ;
}
@@ -3180,7 +3199,8 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
// Closure returns `true` if the passed lvalue is a component of `new_dst_lval`
auto is_lvalue_in_val = [&](const auto& lv) {
- return visit_mir_lvalue(new_dst_lval, ValUsage::Write, [&](const auto& slv, auto ) { return lv == slv; });
+ // Don't care about indexing?
+ return lv.m_root == new_dst_lval.m_root;
};
if( visit_mir_lvalues(*it3, [&](const auto& lv, auto ){ return is_lvalue_in_val(lv); }) )
{
@@ -3241,8 +3261,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
// 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, ValUsage::Write, [&](const auto& slv, auto ) { return lv == slv; });
+ auto lvalue_impacts_dst = [&](const ::MIR::LValue& lv)->bool {
+ // Returns true if the two lvalues share a common root
+ // TODO: Could restrict based on the presence of
+ // deref/field accesses?
+ return lv.m_root == new_dst->m_root;
};
for(auto it = blk2.statements.begin(); it != blk2.statements.end(); ++ it)
{
@@ -3251,11 +3274,12 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
{
DEBUG("- Replace function return " << e.ret_val << " with " << *new_dst);
e.ret_val = new_dst->clone();
+ // TODO: Invalidate the entry, instead of deleting?
it = blk2.statements.erase(it);
replacement_happend = true;
break;
}
- if( visit_mir_lvalues(stmt, [&](const auto& lv, ValUsage vu){ return lv == *new_dst || (vu == ValUsage::Write && lvalue_impacts_dst(lv)); }) )
+ if( visit_mir_lvalues(stmt, [&](const MIR::LValue& lv, ValUsage vu){ return lv == *new_dst || (vu == ValUsage::Write && lvalue_impacts_dst(lv)); }) )
{
break;
}
@@ -3289,17 +3313,14 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F
}
// Remove assignments of locals that are never read
- TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de),
- (
- ),
- (Local,
- const auto& vu = val_uses.local_uses[de];
+ if( se->dst.is_Local() )
+ {
+ const auto& vu = val_uses.local_uses[se->dst.as_Local()];
if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) {
DEBUG(state << se->dst << " only written, removing write");
it = block.statements.erase(it)-1;
}
- )
- )
+ }
}
}
// NOTE: Calls can write values, but they also have side-effects
@@ -3427,9 +3448,12 @@ bool MIR_Optimise_DeadAssignments(::MIR::TypeResolve& state, ::MIR::Function& fc
for(const auto& bb : fcn.blocks)
{
auto cb = [&](const ::MIR::LValue& lv, ValUsage vu) {
- if( lv.is_Local() ) {
- read_locals[lv.as_Local()] = true;
+ if( lv.m_root.is_Local() ) {
+ read_locals[lv.m_root.as_Local()] = true;
}
+ for(const auto& w : lv.m_wrappers)
+ if(w.is_Index())
+ read_locals[w.as_Index()] = true;
return false;
};
for(const auto& stmt : bb.statements)
@@ -3496,7 +3520,7 @@ bool MIR_Optimise_NoopRemoval(::MIR::TypeResolve& state, ::MIR::Function& fcn)
if( it->is_Assign()
&& it->as_Assign().src.is_Borrow()
&& it->as_Assign().src.as_Borrow().val.is_Deref()
- && *it->as_Assign().src.as_Borrow().val.as_Deref().val == it->as_Assign().dst
+ && it->as_Assign().src.as_Borrow().val.clone_unwrapped() == it->as_Assign().dst
)
{
DEBUG(state << "Useless assignment (v = &*v), remove - " << *it);
@@ -3520,7 +3544,7 @@ bool MIR_Optimise_NoopRemoval(::MIR::TypeResolve& state, ::MIR::Function& fcn)
bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn)
{
::std::vector<bool> visited( fcn.blocks.size() );
- visit_blocks(state, fcn, [&visited](auto bb, const auto& _blokc) {
+ visit_blocks(state, fcn, [&visited](auto bb, const auto& /*block*/) {
assert( !visited[bb] );
visited[bb] = true;
});
@@ -3550,12 +3574,19 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
visited[bb] = true;
auto assigned_lval = [&](const ::MIR::LValue& lv) {
- const auto* lvp = &lv;
// TODO: Consume through indexing/field accesses
- while(lvp->is_Field())
- lvp = &*lvp->as_Field().val;
- if(const auto* le = lvp->opt_Local() )
- used_locals[*le] = true;
+ for(const auto& w : lv.m_wrappers)
+ {
+ if( w.is_Field() ) {
+ }
+ else {
+ return ;
+ }
+ }
+ if( lv.m_root.is_Local() )
+ {
+ used_locals[lv.m_root.as_Local()] = true;
+ }
};
for(const auto& stmt : block.statements)
@@ -3629,20 +3660,23 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
auto it = fcn.blocks.begin();
for(unsigned int i = 0; i < visited.size(); i ++)
{
- if( !visited[i] )
- {
- // Delete
- DEBUG("GC bb" << i);
- it = fcn.blocks.erase(it);
- }
- else
+ if( visited[i] )
{
- auto lvalue_cb = [&](auto& lv, auto ) {
- if(auto* e = lv.opt_Local() ) {
- MIR_ASSERT(state, *e < local_rewrite_table.size(), "Variable out of range - " << lv);
+ auto lvalue_cb = [&](::MIR::LValue& lv, auto ) {
+ if( lv.m_root.is_Local() )
+ {
+ auto e = lv.m_root.as_Local();
+ MIR_ASSERT(state, e < local_rewrite_table.size(), "Variable out of range - " << lv);
// If the table entry for this variable is !0, it wasn't marked as used
- MIR_ASSERT(state, local_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused");
- *e = local_rewrite_table.at(*e);
+ MIR_ASSERT(state, local_rewrite_table.at(e) != ~0u, "LValue " << lv << " incorrectly marked as unused");
+ lv.m_root = ::MIR::LValue::Storage::new_Local(local_rewrite_table.at(e) );
+ }
+ for(auto& w : lv.m_wrappers)
+ {
+ if( w.is_Index())
+ {
+ w = ::MIR::LValue::Wrapper::new_Index(local_rewrite_table.at( w.as_Index() ));
+ }
}
return false;
};
@@ -3716,6 +3750,7 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
}
state.set_cur_stmt_term(i);
// Rewrite and advance
+ visit_mir_lvalues_mut(it->terminator, lvalue_cb);
TU_MATCHA( (it->terminator), (e),
(Incomplete,
),
@@ -3729,49 +3764,45 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn
(Panic,
),
(If,
- visit_mir_lvalue_mut(e.cond, ValUsage::Read, lvalue_cb);
e.bb0 = block_rewrite_table[e.bb0];
e.bb1 = block_rewrite_table[e.bb1];
),
(Switch,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, lvalue_cb);
for(auto& target : e.targets)
target = block_rewrite_table[target];
),
(SwitchValue,
- visit_mir_lvalue_mut(e.val, ValUsage::Read, lvalue_cb);
for(auto& target : e.targets)
target = block_rewrite_table[target];
e.def_target = block_rewrite_table[e.def_target];
),
(Call,
- if( e.fcn.is_Value() ) {
- visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, lvalue_cb);
- }
- for(auto& v : e.args)
- visit_mir_lvalue_mut(v, ValUsage::Read, lvalue_cb);
- visit_mir_lvalue_mut(e.ret_val, ValUsage::Write, lvalue_cb);
e.ret_block = block_rewrite_table[e.ret_block];
e.panic_block = block_rewrite_table[e.panic_block];
)
)
// Delete all statements flagged in a bitmap for deletion
- auto stmt_it = it->statements.begin();
- for(auto flag : to_remove_statements)
- {
- if(flag) {
- stmt_it = it->statements.erase(stmt_it);
- }
- else {
- ++ stmt_it;
- }
- }
-
- ++it;
+ assert(it->statements.size() == to_remove_statements.size());
+ auto new_end = ::std::remove_if(it->statements.begin(), it->statements.end(), [&](const auto& s){
+ size_t stmt_idx = (&s - &it->statements.front());
+ return to_remove_statements[stmt_idx];
+ });
+ it->statements.erase(new_end, it->statements.end());
}
+ ++it;
}
+ auto new_blocks_end = ::std::remove_if(fcn.blocks.begin(), fcn.blocks.end(), [&](const auto& bb) {
+ size_t i = &bb - &fcn.blocks.front();
+ if( !visited[i] ) {
+ DEBUG("GC bb" << i);
+ }
+ return !visited[i];
+ });
+ fcn.blocks.erase(new_blocks_end, fcn.blocks.end());
+
+ // NOTE: Drop flags are bool, so can't use the above hack
for(unsigned int i = 0, j = 0; i < n_df; i ++)
{
if( !used_dfs[i] )
diff --git a/src/trans/auto_impls.cpp b/src/trans/auto_impls.cpp
index 07a52857..ea10c8e2 100644
--- a/src/trans/auto_impls.cpp
+++ b/src/trans/auto_impls.cpp
@@ -55,9 +55,9 @@ namespace {
{
const auto& lang_Clone = state.resolve.m_crate.get_lang_item_path(sp, "clone");
// Allocate to locals (one for the `&T`, the other for the cloned `T`)
- auto borrow_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() );
+ auto borrow_lv = ::MIR::LValue::new_Local( mir_fcn.locals.size() );
mir_fcn.locals.push_back(::HIR::TypeRef::new_borrow(::HIR::BorrowType::Shared, subty.clone()));
- auto res_lv = ::MIR::LValue::make_Local( mir_fcn.locals.size() );
+ auto res_lv = ::MIR::LValue::new_Local( mir_fcn.locals.size() );
mir_fcn.locals.push_back(subty.clone());
// Call `<T as Clone>::clone`, passing a borrow of the field
@@ -97,8 +97,8 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
{
::MIR::BasicBlock bb;
bb.statements.push_back(::MIR::Statement::make_Assign({
- ::MIR::LValue::make_Return({}),
- ::MIR::RValue::make_Use( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) }) )
+ ::MIR::LValue::new_Return(),
+ ::MIR::RValue::make_Use( ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) ) )
}));
bb.terminator = ::MIR::Terminator::make_Return({});
mir_fcn.blocks.push_back(::std::move( bb ));
@@ -121,13 +121,13 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
{
::HIR::TypeRef tmp;
const auto& ty_m = monomorphise_type_needed(fld.ent) ? (tmp = p.monomorph(state.resolve, fld.ent)) : fld.ent;
- auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast<unsigned>(values.size()) });
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
values.push_back( clone_field(state, sp, mir_fcn, ty_m, mv$(fld_lvalue)) );
}
// Construct the result value
::MIR::BasicBlock bb;
bb.statements.push_back(::MIR::Statement::make_Assign({
- ::MIR::LValue::make_Return({}),
+ ::MIR::LValue::new_Return(),
::MIR::RValue::make_Struct({ gp.clone(), mv$(values) })
}));
bb.terminator = ::MIR::Terminator::make_Return({});
@@ -142,13 +142,13 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
::std::vector< ::MIR::Param> values; values.reserve(te.size_val);
for(size_t i = 0; i < te.size_val; i ++)
{
- auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast<unsigned>(i) });
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
values.push_back( clone_field(state, sp, mir_fcn, *te.inner, mv$(fld_lvalue)) );
}
// Construct the result
::MIR::BasicBlock bb;
bb.statements.push_back(::MIR::Statement::make_Assign({
- ::MIR::LValue::make_Return({}),
+ ::MIR::LValue::new_Return(),
::MIR::RValue::make_Array({ mv$(values) })
}));
bb.terminator = ::MIR::Terminator::make_Return({});
@@ -161,14 +161,14 @@ void Trans_AutoImpl_Clone(State& state, ::HIR::TypeRef ty)
// For each field of the tuple, create a clone (either using Copy if posible, or calling Clone::clone)
for(const auto& subty : te)
{
- auto fld_lvalue = ::MIR::LValue::make_Field({ box$(::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({ 0 })) })), static_cast<unsigned>(values.size()) });
+ auto fld_lvalue = ::MIR::LValue::new_Field( ::MIR::LValue::new_Deref(::MIR::LValue::new_Argument(0)), static_cast<unsigned>(values.size()) );
values.push_back( clone_field(state, sp, mir_fcn, subty, mv$(fld_lvalue)) );
}
// Construct the result tuple
::MIR::BasicBlock bb;
bb.statements.push_back(::MIR::Statement::make_Assign({
- ::MIR::LValue::make_Return({}),
+ ::MIR::LValue::new_Return(),
::MIR::RValue::make_Tuple({ mv$(values) })
}));
bb.terminator = ::MIR::Terminator::make_Return({});
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 09b63f44..bd447191 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -945,7 +945,7 @@ namespace {
{
auto inner_ptr = ::HIR::TypeRef::new_pointer( ::HIR::BorrowType::Unique, inner_type.clone() );
m_of << indent; emit_ctype(inner_ptr, FMT_CB(ss, ss << "i"; )); m_of << " = "; emit_lvalue(slot); m_of << "._0._0._0;\n";
- emit_destructor_call( ::MIR::LValue::make_Local(~0u), inner_type, true, indent_level );
+ emit_destructor_call( ::MIR::LValue::new_Local(::MIR::LValue::Storage::MAX_ARG), inner_type, true, indent_level );
}
// TODO: This is specific to the official liballoc's owned_box
::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { inner_type.clone() } };
@@ -976,7 +976,7 @@ namespace {
m_mir_res = &mir_res;
m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n";
- emit_box_drop(1, *ity, ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }), /*run_destructor=*/true);
+ emit_box_drop(1, *ity, ::MIR::LValue::new_Deref(::MIR::LValue::new_Return()), /*run_destructor=*/true);
m_of << "}\n";
m_mir_res = nullptr;
@@ -1122,13 +1122,13 @@ namespace {
m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {\n";
if( m_resolve.type_needs_drop_glue(sp, ty) )
{
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(const auto& ity : te)
{
// TODO: What if it's a ZST?
emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1);
- fld_lv.as_Field().field_index ++;
+ fld_lv.inc_Field();
}
}
m_of << "}\n";
@@ -1329,13 +1329,12 @@ namespace {
m_of << "\t" << Trans_Mangle( ::HIR::Path(struct_ty.clone(), m_resolve.m_lang_Drop, "drop") ) << "(rv);\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(size_t i = 0; i < repr->fields.size(); i++)
{
- fld_lv.as_Field().field_index = i;
-
emit_destructor_call(fld_lv, repr->fields[i].ty, /*unsized_valid=*/true, /*indent=*/1);
+ fld_lv.inc_Field();
}
}
m_of << "}\n";
@@ -1573,14 +1572,14 @@ namespace {
{
m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
+ auto self = ::MIR::LValue::new_Deref(::MIR::LValue::new_Return());
if( const auto* e = repr->variants.opt_NonZero() )
{
unsigned idx = 1 - e->zero_variant;
// TODO: Fat pointers?
m_of << "\tif( (*rv)"; emit_enum_path(repr, e->field); m_of << " != 0 ) {\n";
- emit_destructor_call( ::MIR::LValue::make_Downcast({ box$(self), idx }), repr->fields[idx].ty, false, 2 );
+ emit_destructor_call( ::MIR::LValue::new_Downcast(mv$(self), idx), repr->fields[idx].ty, false, 2 );
m_of << "\t}\n";
}
else if( repr->fields.size() <= 1 )
@@ -1590,15 +1589,15 @@ namespace {
}
else if( const auto* e = repr->variants.opt_Values() )
{
- auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 });
+ auto var_lv =::MIR::LValue::new_Downcast(mv$(self), 0);
m_of << "\tswitch(rv->TAG) {\n";
for(unsigned int var_idx = 0; var_idx < e->values.size(); var_idx ++)
{
- var_lv.as_Downcast().variant_index = var_idx;
m_of << "\tcase " << e->values[var_idx] << ":\n";
emit_destructor_call(var_lv, repr->fields[var_idx].ty, /*unsized_valid=*/false, /*indent=*/2);
m_of << "\t\tbreak;\n";
+ var_lv.inc_Downcast();
}
m_of << "\t}\n";
}
@@ -2874,8 +2873,8 @@ namespace {
break;
}
- TU_MATCHA( (e.src), (ve),
- (Use,
+ TU_MATCH_HDRA( (e.src), {)
+ TU_ARMA(Use, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, ve);
if( ty == ::HIR::TypeRef::new_diverge() ) {
@@ -2892,13 +2891,13 @@ namespace {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve);
- ),
- (Constant,
+ }
+ TU_ARMA(Constant, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_constant(ve, &e.dst);
- ),
- (SizedArray,
+ }
+ TU_ARMA(SizedArray, ve) {
if( ve.count == 0 ) {
}
else if( ve.count == 1 ) {
@@ -2917,34 +2916,35 @@ namespace {
m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n";
m_of << indent << "\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val);
}
- ),
- (Borrow,
+ }
+ TU_ARMA(Borrow, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, ve.val);
bool special = false;
// If the inner value was a deref, just copy the pointer verbatim
- TU_IFLET(::MIR::LValue, ve.val, Deref, le,
+ if( ve.val.is_Deref() )
+ {
emit_lvalue(e.dst);
m_of << " = ";
- emit_lvalue(*le.val);
+ emit_lvalue( ::MIR::LValue::CRef(ve.val).inner_ref() );
special = true;
- )
+ }
// Magic for taking a &-ptr to unsized field of a struct.
// - Needs to get metadata from bottom-level pointer.
- else TU_IFLET(::MIR::LValue, ve.val, Field, le,
+ else if( ve.val.is_Field() ) {
if( metadata_type(ty) != MetadataType::None ) {
- const ::MIR::LValue* base_val = &*le.val;
- while(base_val->is_Field())
- base_val = &*base_val->as_Field().val;
- MIR_ASSERT(mir_res, base_val->is_Deref(), "DST access must be via a deref");
- const ::MIR::LValue& base_ptr = *base_val->as_Deref().val;
+ auto base_val = ::MIR::LValue::CRef(ve.val).inner_ref();
+ while(base_val.is_Field())
+ base_val.try_unwrap();
+ MIR_ASSERT(mir_res, base_val.is_Deref(), "DST access must be via a deref");
+ const auto base_ptr = base_val.inner_ref();
// Construct the new DST
emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n" << indent;
emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val);
special = true;
}
- )
+ }
else {
}
@@ -2953,50 +2953,55 @@ namespace {
if( !special && m_options.disallow_empty_structs && ve.val.is_Field() && this->type_is_bad_zst(ty) )
{
// Work backwards to the first non-ZST field
- const auto* val_fp = &ve.val.as_Field();
- while( val_fp->val->is_Field() )
+ auto val_fp = ::MIR::LValue::CRef(ve.val);
+ assert(val_fp.is_Field());
+ while( val_fp.inner_ref().is_Field() )
{
::HIR::TypeRef tmp;
- const auto& ty = mir_res.get_lvalue_type(tmp, *val_fp->val);
+ const auto& ty = mir_res.get_lvalue_type(tmp, val_fp.inner_ref());
if( !this->type_is_bad_zst(ty) )
break;
+ val_fp.try_unwrap();
}
+ assert(val_fp.is_Field());
// Here, we have `val_fp` be a LValue::Field that refers to a ZST, but the inner of the field points to a non-ZST or a local
emit_lvalue(e.dst);
m_of << " = ";
// If the index is zero, then the best option is to borrow the source
- if( val_fp->val->is_Downcast() )
+ auto field_inner = val_fp.inner_ref();
+ if( field_inner.is_Downcast() )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val->as_Downcast().val);
+ m_of << "(void*)& "; emit_lvalue(field_inner.inner_ref());
}
- else if( val_fp->field_index == 0 )
+ else if( val_fp.as_Field() == 0 )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val);
+ m_of << "(void*)& "; emit_lvalue(field_inner);
}
else
{
::HIR::TypeRef tmp;
- auto tmp_lv = ::MIR::LValue::make_Field({ box$(val_fp->val->clone()), val_fp->field_index - 1 });
+ auto tmp_lv = ::MIR::LValue::new_Field( field_inner.clone(), val_fp.as_Field() - 1 );
bool use_parent = false;
for(;;)
{
const auto& ty = mir_res.get_lvalue_type(tmp, tmp_lv);
if( !this->type_is_bad_zst(ty) )
break;
- if( tmp_lv.as_Field().field_index == 0 )
+ auto idx = tmp_lv.as_Field();
+ if( idx == 0 )
{
use_parent = true;
break;
}
- tmp_lv.as_Field().field_index -= 1;
+ tmp_lv.m_wrappers.back() = ::MIR::LValue::Wrapper::new_Field(idx - 1);
}
// Reached index zero, with still ZST
if( use_parent )
{
- m_of << "(void*)& "; emit_lvalue(*val_fp->val);
+ m_of << "(void*)& "; emit_lvalue(field_inner);
}
// Use the address after the previous item
else
@@ -3013,11 +3018,11 @@ namespace {
m_of << " = ";
m_of << "& "; emit_lvalue(ve.val);
}
- ),
- (Cast,
+ }
+ TU_ARMA(Cast, ve) {
emit_rvalue_cast(mir_res, e.dst, ve);
- ),
- (BinOp,
+ }
+ TU_ARMA(BinOp, ve) {
emit_lvalue(e.dst);
m_of << " = ";
::HIR::TypeRef tmp, tmp_r;
@@ -3168,8 +3173,8 @@ namespace {
{
m_of << ".lo";
}
- ),
- (UniOp,
+ }
+ TU_ARMA(UniOp, ve) {
::HIR::TypeRef tmp;
const auto& ty = mir_res.get_lvalue_type(tmp, e.dst);
@@ -3204,24 +3209,24 @@ namespace {
break;
}
emit_lvalue(ve.val);
- ),
- (DstMeta,
+ }
+ TU_ARMA(DstMeta, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve.val);
m_of << ".META";
- ),
- (DstPtr,
+ }
+ TU_ARMA(DstPtr, ve) {
emit_lvalue(e.dst);
m_of << " = ";
emit_lvalue(ve.val);
m_of << ".PTR";
- ),
- (MakeDst,
+ }
+ TU_ARMA(MakeDst, ve) {
emit_lvalue(e.dst); m_of << ".PTR = "; emit_param(ve.ptr_val); m_of << ";\n" << indent;
emit_lvalue(e.dst); m_of << ".META = "; emit_param(ve.meta_val);
- ),
- (Tuple,
+ }
+ TU_ARMA(Tuple, ve) {
bool has_emitted = false;
for(unsigned int j = 0; j < ve.vals.size(); j ++)
{
@@ -3245,15 +3250,15 @@ namespace {
m_of << "._" << j << " = ";
emit_param(ve.vals[j]);
}
- ),
- (Array,
+ }
+ TU_ARMA(Array, ve) {
for(unsigned int j = 0; j < ve.vals.size(); j ++) {
if( j != 0 ) m_of << ";\n" << indent;
emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = ";
emit_param(ve.vals[j]);
}
- ),
- (Variant,
+ }
+ TU_ARMA(Variant, ve) {
const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path);
if( tyi.is_Union() )
{
@@ -3310,8 +3315,8 @@ namespace {
{
BUG(mir_res.sp, "Unexpected type in Variant");
}
- ),
- (Struct,
+ }
+ TU_ARMA(Struct, ve) {
if( ve.vals.empty() )
{
if( m_options.disallow_empty_structs )
@@ -3349,8 +3354,8 @@ namespace {
emit_param(ve.vals[j]);
}
}
- )
- )
+ }
+ }
m_of << ";";
m_of << "\t// " << e.dst << " = " << e.src;
m_of << "\n";
@@ -4432,7 +4437,7 @@ namespace {
// Nothing needs to be done, this just stops the destructor from running.
}
else if( name == "drop_in_place" ) {
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(e.args.at(0).as_LValue().clone()) }), params.m_types.at(0), true, 1 /* TODO: get from caller */ );
+ emit_destructor_call( ::MIR::LValue::new_Deref(e.args.at(0).as_LValue().clone()), params.m_types.at(0), true, /*indent_level=*/1 /* TODO: get from caller */ );
}
else if( name == "needs_drop" ) {
// Returns `true` if the actual type given as `T` requires drop glue;
@@ -5186,7 +5191,7 @@ namespace {
if( te.type == ::HIR::BorrowType::Owned )
{
// Call drop glue on inner.
- emit_destructor_call( ::MIR::LValue::make_Deref({ box$(slot.clone()) }), *te.inner, true, indent_level );
+ emit_destructor_call( ::MIR::LValue::new_Deref(slot.clone()), *te.inner, true, indent_level );
}
),
(Path,
@@ -5201,10 +5206,7 @@ namespace {
if( this->type_is_bad_zst(ty) && (slot.is_Field() || slot.is_Downcast()) )
{
m_of << indent << Trans_Mangle(p) << "((void*)&";
- if( slot.is_Field() )
- emit_lvalue(*slot.as_Field().val);
- else
- emit_lvalue(*slot.as_Downcast().val);
+ emit_lvalue(::MIR::LValue::CRef(slot).inner_ref());
m_of << ");\n";
}
else
@@ -5219,7 +5221,7 @@ namespace {
m_of << indent << Trans_Mangle(p) << "( " << make_fcn << "(";
if( slot.is_Deref() )
{
- emit_lvalue(*slot.as_Deref().val);
+ emit_lvalue( ::MIR::LValue::CRef(slot).inner_ref() );
m_of << ".PTR";
}
else
@@ -5227,10 +5229,10 @@ namespace {
m_of << "&"; emit_lvalue(slot);
}
m_of << ", ";
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
- emit_lvalue(*lvp->as_Deref().val); m_of << ".META";
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
+ emit_lvalue(lvr.inner_ref()); m_of << ".META";
m_of << ") );\n";
break;
}
@@ -5240,7 +5242,7 @@ namespace {
if( te.size_val > 0 )
{
m_of << indent << "for(unsigned i = 0; i < " << te.size_val << "; i++) {\n";
- emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false, indent_level+1);
+ emit_destructor_call(::MIR::LValue::new_Index(slot.clone(), ::MIR::LValue::Storage::MAX_ARG), *te.inner, false, indent_level+1);
m_of << "\n" << indent << "}";
}
),
@@ -5248,24 +5250,24 @@ namespace {
// Emit destructors for all entries
if( te.size() > 0 )
{
- ::MIR::LValue lv = ::MIR::LValue::make_Field({ box$(slot.clone()), 0 });
+ ::MIR::LValue lv = ::MIR::LValue::new_Field(slot.clone(), 0);
for(unsigned int i = 0; i < te.size(); i ++)
{
- lv.as_Field().field_index = i;
emit_destructor_call(lv, te[i], unsized_valid && (i == te.size()-1), indent_level);
+ lv.inc_Field();
}
}
),
(TraitObject,
MIR_ASSERT(*m_mir_res, unsized_valid, "Dropping TraitObject without a pointer");
// Call destructor in vtable
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
- m_of << indent << "((VTABLE_HDR*)"; emit_lvalue(*lvp->as_Deref().val); m_of << ".META)->drop(";
- if( const auto* ve = slot.opt_Deref() )
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
+ m_of << indent << "((VTABLE_HDR*)"; emit_lvalue(lvr.inner_ref()); m_of << ".META)->drop(";
+ if( slot.is_Deref() )
{
- emit_lvalue(*ve->val); m_of << ".PTR";
+ emit_lvalue(::MIR::LValue::CRef(slot).inner_ref()); m_of << ".PTR";
}
else
{
@@ -5275,12 +5277,12 @@ namespace {
),
(Slice,
MIR_ASSERT(*m_mir_res, unsized_valid, "Dropping Slice without a pointer");
- const auto* lvp = &slot;
- while(const auto* le = lvp->opt_Field()) lvp = &*le->val;
- MIR_ASSERT(*m_mir_res, lvp->is_Deref(), "Access to unized type without a deref - " << *lvp << " (part of " << slot << ")");
+ auto lvr = ::MIR::LValue::CRef(slot);
+ while(lvr.is_Field()) lvr.try_unwrap();
+ MIR_ASSERT(*m_mir_res, lvr.is_Deref(), "Access to unized type without a deref - " << lvr << " (part of " << slot << ")");
// Call destructor on all entries
- m_of << indent << "for(unsigned i = 0; i < "; emit_lvalue(*lvp->as_Deref().val); m_of << ".META; i++) {\n";
- emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false, indent_level+1);
+ m_of << indent << "for(unsigned i = 0; i < "; emit_lvalue(lvr.inner_ref()); m_of << ".META; i++) {\n";
+ emit_destructor_call(::MIR::LValue::new_Index(slot.clone(), ::MIR::LValue::Storage::MAX_ARG), *te.inner, false, indent_level+1);
m_of << "\n" << indent << "}";
)
)
@@ -5525,116 +5527,125 @@ namespace {
)
}
- void emit_lvalue(const ::MIR::LValue& val) {
- TU_MATCHA( (val), (e),
- (Return,
+ void emit_lvalue(const ::MIR::LValue::CRef& val)
+ {
+ TU_MATCH_HDRA( (val), {)
+ TU_ARMA(Return, _e) {
m_of << "rv";
- ),
- (Argument,
- m_of << "arg" << e.idx;
- ),
- (Local,
- if( e == ~0u )
+ }
+ TU_ARMA(Argument, e) {
+ m_of << "arg" << e;
+ }
+ TU_ARMA(Local, e) {
+ if( e == ::MIR::LValue::Storage::MAX_ARG )
m_of << "i";
else
m_of << "var" << e;
- ),
- (Static,
- m_of << Trans_Mangle(*e);
- ),
- (Field,
+ }
+ TU_ARMA(Static, e) {
+ m_of << Trans_Mangle(e);
+ }
+ TU_ARMA(Field, field_index) {
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
- if( ty.m_data.is_Slice() ) {
- if( e.val->is_Deref() )
+ auto inner = val.inner_ref();
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
+ if( ty.m_data.is_Slice() )
+ {
+ if( inner.is_Deref() )
{
m_of << "(("; emit_ctype(*ty.m_data.as_Slice().inner); m_of << "*)";
- emit_lvalue(*e.val->as_Deref().val);
+ emit_lvalue(inner.inner_ref());
m_of << ".PTR)";
}
else
{
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
- m_of << "[" << e.field_index << "]";
+ m_of << "[" << field_index << "]";
}
else if( ty.m_data.is_Array() ) {
- emit_lvalue(*e.val);
- m_of << ".DATA[" << e.field_index << "]";
+ emit_lvalue(inner);
+ m_of << ".DATA[" << field_index << "]";
}
- else if( e.val->is_Deref() ) {
+ else if( inner.is_Deref() ) {
auto dst_type = metadata_type(ty);
if( dst_type != MetadataType::None )
{
- m_of << "(("; emit_ctype(ty); m_of << "*)"; emit_lvalue(*e.val->as_Deref().val); m_of << ".PTR)->_" << e.field_index;
+ m_of << "(("; emit_ctype(ty); m_of << "*)"; emit_lvalue(inner.inner_ref()); m_of << ".PTR)->_" << field_index;
}
else
{
- emit_lvalue(*e.val->as_Deref().val);
- m_of << "->_" << e.field_index;
+ emit_lvalue(inner.inner_ref());
+ m_of << "->_" << field_index;
}
}
else {
- emit_lvalue(*e.val);
- m_of << "._" << e.field_index;
+ emit_lvalue(inner);
+ m_of << "._" << field_index;
}
- ),
- (Deref,
- // TODO: If the type is unsized, then this pointer is a fat pointer, so we need to cast the data pointer.
+ }
+ TU_ARMA(Deref, _e) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
const auto& ty = m_mir_res->get_lvalue_type(tmp, val);
auto dst_type = metadata_type(ty);
+ // If the type is unsized, then this pointer is a fat pointer, so we need to cast the data pointer.
if( dst_type != MetadataType::None )
{
m_of << "(*("; emit_ctype(ty); m_of << "*)";
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ".PTR)";
}
else
{
m_of << "(*";
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ")";
}
- ),
- (Index,
+ }
+ TU_ARMA(Index, index_local) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
m_of << "(";
if( ty.m_data.is_Slice() ) {
- if( e.val->is_Deref() )
+ if( inner.is_Deref() )
{
m_of << "("; emit_ctype(*ty.m_data.as_Slice().inner); m_of << "*)";
- emit_lvalue(*e.val->as_Deref().val);
+ emit_lvalue(inner.inner_ref());
m_of << ".PTR";
}
else {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
}
else if( ty.m_data.is_Array() ) {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
m_of << ".DATA";
}
else {
- emit_lvalue(*e.val);
+ emit_lvalue(inner);
}
m_of << ")[";
- emit_lvalue(*e.idx);
+ emit_lvalue(::MIR::LValue::new_Local(index_local));
m_of << "]";
- ),
- (Downcast,
+ }
+ TU_ARMA(Downcast, variant_index) {
+ auto inner = val.inner_ref();
::HIR::TypeRef tmp;
- const auto& ty = m_mir_res->get_lvalue_type(tmp, *e.val);
- emit_lvalue(*e.val);
+ const auto& ty = m_mir_res->get_lvalue_type(tmp, inner);
+ emit_lvalue(inner);
MIR_ASSERT(*m_mir_res, ty.m_data.is_Path(), "Downcast on non-Path type - " << ty);
if( ty.m_data.as_Path().binding.is_Enum() )
{
m_of << ".DATA";
}
- m_of << ".var_" << e.variant_index;
- )
- )
+ m_of << ".var_" << variant_index;
+ }
+ }
+ }
+ void emit_lvalue(const ::MIR::LValue& val) {
+ emit_lvalue( ::MIR::LValue::CRef(val) );
}
void emit_constant(const ::MIR::Constant& ve, const ::MIR::LValue* dst_ptr=nullptr)
{
diff --git a/src/trans/codegen_mmir.cpp b/src/trans/codegen_mmir.cpp
index 50d36a8a..23f333fd 100644
--- a/src/trans/codegen_mmir.cpp
+++ b/src/trans/codegen_mmir.cpp
@@ -31,47 +31,44 @@ namespace
::std::ostream& operator<<(::std::ostream& os, const Fmt<::MIR::LValue>& x)
{
- auto fmt_lhs = [](::std::ostream& os, const ::MIR::LValue& lv) {
- if( lv.is_Deref() ) {
- os << "(" << fmt(lv) << ")";
- }
- else {
- os << fmt(lv);
- }
- };
- switch(x.e.tag())
- {
- case ::MIR::LValue::TAGDEAD: throw "";
- TU_ARM(x.e, Return, _e) (void)_e;
+ TU_MATCHA( (x.e.m_root), (e),
+ (Return,
os << "RETURN";
- break;
- TU_ARM(x.e, Local, e)
+ ),
+ (Local,
os << "var" << e;
- break;
- TU_ARM(x.e, Argument, e)
- os << "arg" << e.idx;
- break;
- TU_ARM(x.e, Static, e)
- os << *e;
- break;
- TU_ARM(x.e, Deref, e)
- os << "*" << fmt(*e.val);
- break;
- TU_ARM(x.e, Field, e) {
- fmt_lhs(os, *e.val);
- // Avoid `0.` existing in the output
- if( e.val->is_Field() || e.val->is_Downcast() )
- os << " ";
- os << "." << e.field_index;
- } break;
- TU_ARM(x.e, Index, e) {
- fmt_lhs(os, *e.val);
- os << "[" << fmt(*e.idx) << "]";
- } break;
- TU_ARM(x.e, Downcast, e) {
- fmt_lhs(os, *e.val);
- os << "@" << e.variant_index;
- } break;
+ ),
+ (Argument,
+ os << "arg" << e;
+ ),
+ (Static,
+ os << e;
+ )
+ )
+ bool was_num = false;
+ for(const auto& w : x.e.m_wrappers)
+ {
+ bool prev_was_num = was_num; was_num = false;
+ switch(w.tag())
+ {
+ TU_ARM(w, Deref, e)
+ os << "*";
+ break;
+ TU_ARM(w, Field, field_index) {
+ // Add a space to prevent accidental float literals
+ if( prev_was_num )
+ os << " ";
+ os << "." << field_index;
+ was_num = true;
+ } break;
+ TU_ARM(w, Index, e) {
+ os << "[var" << fmt(::MIR::LValue::new_Local(e)) << "]";
+ } break;
+ TU_ARM(w, Downcast, variant_index) {
+ os << "@" << variant_index;
+ was_num = true;
+ } break;
+ }
}
return os;
}
@@ -225,14 +222,14 @@ namespace
m_of << "\t0: {\n";
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_lv = ::MIR::LValue::new_Field(mv$(self), 0);
for(const auto& e : repr->fields)
{
if( m_resolve.type_needs_drop_glue(sp, e.ty) ) {
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
- fld_lv.as_Field().field_index += 1;
+ fld_lv.inc_Field();
}
m_of << "\t\t""RETURN\n";
m_of << "\t}\n";
@@ -388,13 +385,13 @@ namespace
//ASSERT_BUG(sp, !item.m_markings.has_drop_impl, "Box shouldn't have a Drop impl");
// TODO: This is very specific to the structure of the official liballoc's Box.
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_p_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
- fld_p_lv = ::MIR::LValue::make_Field({ box$(fld_p_lv), 0 });
- fld_p_lv = ::MIR::LValue::make_Field({ box$(fld_p_lv), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_p_lv = ::MIR::LValue::new_Field( mv$(self), 0 );
+ fld_p_lv = ::MIR::LValue::new_Field( mv$(fld_p_lv), 0 );
+ fld_p_lv = ::MIR::LValue::new_Field( mv$(fld_p_lv), 0 );
if( m_resolve.type_needs_drop_glue(sp, *ity) ) {
- auto fld_lv = ::MIR::LValue::make_Deref({ box$(fld_p_lv.clone()) });
+ auto fld_lv = ::MIR::LValue::new_Deref( fld_p_lv.clone() );
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
@@ -424,14 +421,14 @@ namespace
m_of << "\t2: {\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) });
- auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Argument(0) );
+ auto fld_lv = ::MIR::LValue::new_Field( mv$(self), 0 );
for(const auto& e : repr->fields)
{
if( m_resolve.type_needs_drop_glue(sp, e.ty) ) {
m_of << "\t\t""DROP " << fmt(fld_lv) << ";\n";
}
- fld_lv.as_Field().field_index += 1;
+ fld_lv.inc_Field();
}
}
m_of << "\t\t""RETURN\n";
@@ -606,18 +603,18 @@ namespace
{
m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n";
}
- auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) });
+ auto self = ::MIR::LValue::new_Deref( ::MIR::LValue::new_Return() );
if( nonzero_path.size() > 0 )
{
// TODO: Fat pointers?
m_of << "\tif( (*rv)._1"; emit_nonzero_path(nonzero_path); m_of << " ) {\n";
- emit_destructor_call( ::MIR::LValue::make_Field({ box$(self), 1 }), monomorph(item.m_data.as_Data()[1].type), false, 2 );
+ emit_destructor_call( ::MIR::LValue::new_Field( box$(self), 1 ), monomorph(item.m_data.as_Data()[1].type), false, 2 );
m_of << "\t}\n";
}
else if( const auto* e = item.m_data.opt_Data() )
{
- auto var_lv =::MIR::LValue::make_Downcast({ box$(self), 0 });
+ auto var_lv =::MIR::LValue::new_Downcast( mv$(self), 0 );
m_of << "\tswitch(rv->TAG) {\n";
for(unsigned int var_idx = 0; var_idx < e->size(); var_idx ++)
diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp
index a2ecb408..dfc566c0 100644
--- a/src/trans/enumerate.cpp
+++ b/src/trans/enumerate.cpp
@@ -11,6 +11,7 @@
#include "trans_list.hpp"
#include <hir/hir.hpp>
#include <mir/mir.hpp>
+#include <mir/helpers.hpp>
#include <hir_typeck/common.hpp> // monomorph
#include <hir_typeck/static.hpp> // StaticTraitResolve
#include <hir/item_path.hpp>
@@ -659,8 +660,9 @@ void Trans_Enumerate_Types(EnumState& state)
// Visit all functions that haven't been type-visited yet
for(unsigned int i = 0; i < state.fcns_to_type_visit.size(); i++)
{
- auto p = state.fcns_to_type_visit[i];
- TRACE_FUNCTION_F("Function " << ::std::find_if(state.rv.m_functions.begin(), state.rv.m_functions.end(), [&](const auto&x){ return x.second.get() == p; })->first);
+ auto* p = state.fcns_to_type_visit[i];
+ auto& fcn_path = ::std::find_if(state.rv.m_functions.begin(), state.rv.m_functions.end(), [&](const auto&x){ return x.second.get() == p; })->first;
+ TRACE_FUNCTION_F("Function " << fcn_path);
assert(p->ptr);
const auto& fcn = *p->ptr;
const auto& pp = p->pp;
@@ -701,290 +703,170 @@ void Trans_Enumerate_Types(EnumState& state)
for(const auto& ty : mir.locals)
tv.visit_type(monomorph(ty));
- // TODO: Find all LValue::Deref instances and get the result type
+ // Find all LValue::Deref instances and get the result type
+ ::MIR::TypeResolve::args_t empty_args;
+ ::HIR::TypeRef empty_ty;
+ ::MIR::TypeResolve mir_res(sp, tv.m_resolve, FMT_CB(fcn_path), /*ret_ty=*/empty_ty, empty_args, mir);
for(const auto& block : mir.blocks)
{
- struct H {
- static const ::HIR::TypeRef& visit_lvalue(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::LValue& lv, ::HIR::TypeRef* tmp_ty_ptr = nullptr) {
- static ::HIR::TypeRef blank;
- TRACE_FUNCTION_F(lv << (tmp_ty_ptr ? " [type]" : ""));
+ struct MirVisitor
+ //:public ::MIR::Visitor
+ {
+ TypeVisitor& tv;
+ const Trans_Params& pp;
+ const ::HIR::Function& fcn;
+ const ::MIR::TypeResolve& mir_res;
+
+ MirVisitor(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::TypeResolve& mir_res)
+ :tv(tv)
+ ,pp(pp)
+ ,fcn(fcn)
+ ,mir_res(mir_res)
+ {
+ }
+
+ void visit_lvalue(const ::MIR::LValue& lv) //override
+ {
+ TRACE_FUNCTION_F(lv);
+ if( ::std::none_of(lv.m_wrappers.begin(), lv.m_wrappers.end(), [](const auto& w){ return w.is_Deref(); }) )
+ {
+ return ;
+ }
+ ::HIR::TypeRef tmp;
auto monomorph_outer = [&](const auto& tpl)->const auto& {
- assert(tmp_ty_ptr);
if( monomorphise_type_needed(tpl) ) {
- return *tmp_ty_ptr = pp.monomorph(tv.m_resolve, tpl);
+ return tmp = pp.monomorph(tv.m_resolve, tpl);
}
else {
return tpl;
}
};
+ const ::HIR::TypeRef* ty_p = nullptr;;
// Recurse, if Deref get the type and add it to the visitor
- TU_MATCHA( (lv), (e),
+ TU_MATCHA( (lv.m_root), (e),
(Return,
- if( tmp_ty_ptr ) {
- TODO(Span(), "Get return type for MIR type enumeration");
- }
+ MIR_TODO(mir_res, "Get return type for MIR type enumeration");
),
(Argument,
- if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_args[e.idx].second);
- }
+ ty_p = &monomorph_outer(fcn.m_args[e].second);
),
(Local,
- if( tmp_ty_ptr ) {
- return monomorph_outer(fcn.m_code.m_mir->locals[e]);
- }
+ ty_p = &monomorph_outer(fcn.m_code.m_mir->locals[e]);
),
(Static,
- if( tmp_ty_ptr ) {
- const auto& path = *e;
- TU_MATCHA( (path.m_data), (pe),
- (Generic,
- ASSERT_BUG(Span(), pe.m_params.m_types.empty(), "Path params on static - " << path);
- const auto& s = tv.m_resolve.m_crate.get_static_by_path(Span(), pe.m_path);
- return s.m_type;
- ),
- (UfcsKnown,
- TODO(Span(), "LValue::Static - UfcsKnown - " << path);
- ),
- (UfcsUnknown,
- BUG(Span(), "Encountered UfcsUnknown in LValue::Static - " << path);
- ),
- (UfcsInherent,
- TODO(Span(), "LValue::Static - UfcsInherent - " << path);
- )
- )
- }
- ),
- (Field,
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Field access of unexpected type - " << ity);
- ),
- (Tuple,
- return te[e.field_index];
- ),
- (Array,
- return *te.inner;
- ),
- (Slice,
- return *te.inner;
- ),
- (Path,
- ASSERT_BUG(Span(), te.binding.is_Struct(), "Field on non-Struct - " << ity);
- const auto& str = *te.binding.as_Struct();
- auto monomorph = [&](const auto& ty)->const auto& {
- if( monomorphise_type_needed(ty) ) {
- *tmp_ty_ptr = monomorphise_type(sp, str.m_params, te.path.m_data.as_Generic().m_params, ty);
- tv.m_resolve.expand_associated_types(sp, *tmp_ty_ptr);
- return *tmp_ty_ptr;
- }
- else {
- return ty;
- }
- };
- TU_MATCHA( (str.m_data), (se),
- (Unit,
- BUG(Span(), "Field on unit-like struct - " << ity);
- ),
- (Tuple,
- ASSERT_BUG(Span(), e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se.at(e.field_index).ent);
- ),
- (Named,
- ASSERT_BUG(Span(), e.field_index < se.size(), "Field index out of range in struct " << te.path);
- return monomorph(se.at(e.field_index).second.ent);
- )
- )
- )
- )
- }
- ),
- (Deref,
- ::HIR::TypeRef tmp;
- if( !tmp_ty_ptr ) tmp_ty_ptr = &tmp;
-
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Deref of unexpected type - " << ity);
+ // TODO: Monomorphise the path then hand to MIR::TypeResolve?
+ const auto& path = e;
+ TU_MATCHA( (path.m_data), (pe),
+ (Generic,
+ MIR_ASSERT(mir_res, pe.m_params.m_types.empty(), "Path params on static - " << path);
+ const auto& s = tv.m_resolve.m_crate.get_static_by_path(mir_res.sp, pe.m_path);
+ ty_p = &s.m_type;
),
- (Path,
- if( const auto* inner_ptr = tv.m_resolve.is_type_owned_box(ity) )
- {
- DEBUG("- Add type " << ity);
- tv.visit_type(*inner_ptr);
- return *inner_ptr;
- }
- else {
- BUG(Span(), "Deref on unexpected type - " << ity);
- }
+ (UfcsKnown,
+ MIR_TODO(mir_res, "LValue::Static - UfcsKnown - " << path);
),
- (Borrow,
- DEBUG("- Add type " << ity);
- tv.visit_type(*te.inner);
- return *te.inner;
+ (UfcsUnknown,
+ MIR_BUG(mir_res, "Encountered UfcsUnknown in LValue::Static - " << path);
),
- (Pointer,
- DEBUG("- Add type " << ity);
- tv.visit_type(*te.inner);
- return *te.inner;
+ (UfcsInherent,
+ MIR_TODO(mir_res, "LValue::Static - UfcsInherent - " << path);
)
)
- ),
- (Index,
- visit_lvalue(tv,pp,fcn, *e.idx, tmp_ty_ptr);
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF(::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Index of unexpected type - " << ity);
- ),
- (Array,
- return *te.inner;
- ),
- (Slice,
- return *te.inner;
- )
- )
- }
- ),
- (Downcast,
- const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr);
- if( tmp_ty_ptr )
- {
- TU_MATCH_DEF( ::HIR::TypeRef::Data, (ity.m_data), (te),
- (
- BUG(Span(), "Downcast on unexpected type - " << ity);
- ),
- (Path,
- if( te.binding.is_Enum() )
- {
- const auto& enm = *te.binding.as_Enum();
- auto monomorph = [&](const auto& ty)->auto {
- ::HIR::TypeRef rv = monomorphise_type(pp.sp, enm.m_params, te.path.m_data.as_Generic().m_params, ty);
- tv.m_resolve.expand_associated_types(sp, rv);
- return rv;
- };
- ASSERT_BUG(Span(), enm.m_data.is_Data(), "");
- const auto& variants = enm.m_data.as_Data();
- ASSERT_BUG(Span(), e.variant_index < variants.size(), "Variant index out of range");
- const auto& raw_ty = variants[e.variant_index].type;
- if( monomorphise_type_needed(raw_ty) ) {
- return *tmp_ty_ptr = monomorph(raw_ty);
- }
- else {
- return raw_ty;
- }
- }
- else
- {
- const auto& unm = *te.binding.as_Union();
- ASSERT_BUG(Span(), e.variant_index < unm.m_variants.size(), "Variant index out of range");
- const auto& variant = unm.m_variants[e.variant_index];
- const auto& var_ty = variant.second.ent;
-
- if( monomorphise_type_needed(var_ty) ) {
- *tmp_ty_ptr = monomorphise_type(pp.sp, unm.m_params, te.path.m_data.as_Generic().m_params, variant.second.ent);
- tv.m_resolve.expand_associated_types(pp.sp, *tmp_ty_ptr);
- return *tmp_ty_ptr;
- }
- else {
- return var_ty;
- }
- }
- )
- )
- }
)
)
- return blank;
+ assert(ty_p);
+ for(const auto& w : lv.m_wrappers)
+ {
+ ty_p = &mir_res.get_unwrapped_type(tmp, w, *ty_p);
+ if( w.is_Deref() )
+ {
+ tv.visit_type(*ty_p);
+ }
+ }
}
- static void visit_const(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::Constant& p)
+ void visit_const(const ::MIR::Constant& p)
{
}
- static void visit_param(TypeVisitor& tv, const Trans_Params& pp, const ::HIR::Function& fcn, const ::MIR::Param& p)
+ void visit_param(const ::MIR::Param& p)
{
TU_MATCHA( (p), (e),
(LValue,
- H::visit_lvalue(tv, pp, fcn, e);
+ this->visit_lvalue(e);
),
(Constant,
- H::visit_const(tv, pp, fcn, e);
+ this->visit_const(e);
)
)
}
};
+ MirVisitor mir_visit(tv, pp, fcn, mir_res);
for(const auto& stmt : block.statements)
{
TU_MATCHA( (stmt), (se),
(Drop,
- H::visit_lvalue(tv,pp,fcn, se.slot);
+ mir_visit.visit_lvalue(se.slot);
),
(SetDropFlag,
),
(Asm,
for(const auto& v : se.outputs)
- H::visit_lvalue(tv,pp,fcn, v.second);
+ mir_visit.visit_lvalue(v.second);
for(const auto& v : se.inputs)
- H::visit_lvalue(tv,pp,fcn, v.second);
+ mir_visit.visit_lvalue(v.second);
),
(ScopeEnd,
),
(Assign,
- H::visit_lvalue(tv,pp,fcn, se.dst);
+ mir_visit.visit_lvalue(se.dst);
TU_MATCHA( (se.src), (re),
(Use,
- H::visit_lvalue(tv,pp,fcn, re);
+ mir_visit.visit_lvalue(re);
),
(Constant,
- H::visit_const(tv,pp,fcn, re);
+ mir_visit.visit_const(re);
),
(SizedArray,
- H::visit_param(tv,pp,fcn, re.val);
+ mir_visit.visit_param(re.val);
),
(Borrow,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(Cast,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(BinOp,
- H::visit_param(tv,pp,fcn, re.val_l);
- H::visit_param(tv,pp,fcn, re.val_l);
+ mir_visit.visit_param(re.val_l);
+ mir_visit.visit_param(re.val_r);
),
(UniOp,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(DstMeta,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(DstPtr,
- H::visit_lvalue(tv,pp,fcn, re.val);
+ mir_visit.visit_lvalue(re.val);
),
(MakeDst,
- H::visit_param(tv,pp,fcn, re.ptr_val);
- H::visit_param(tv,pp,fcn, re.meta_val);
+ mir_visit.visit_param(re.ptr_val);
+ mir_visit.visit_param(re.meta_val);
),
(Tuple,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
),
(Array,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
),
(Variant,
- H::visit_param(tv,pp,fcn, re.val);
+ mir_visit.visit_param(re.val);
),
(Struct,
for(const auto& v : re.vals)
- H::visit_param(tv,pp,fcn, v);
+ mir_visit.visit_param(v);
)
)
)
@@ -997,25 +879,31 @@ void Trans_Enumerate_Types(EnumState& state)
(Goto, ),
(Panic, ),
(If,
- H::visit_lvalue(tv,pp,fcn, te.cond);
+ mir_visit.visit_lvalue(te.cond);
),
(Switch,
- H::visit_lvalue(tv,pp,fcn, te.val);
+ mir_visit.visit_lvalue(te.val);
),
(SwitchValue,
- H::visit_lvalue(tv,pp,fcn, te.val);
+ mir_visit.visit_lvalue(te.val);
),
(Call,
- if( te.fcn.is_Value() )
- H::visit_lvalue(tv,pp,fcn, te.fcn.as_Value());
- else if( te.fcn.is_Intrinsic() )
+ if(const auto* e = te.fcn.opt_Value() )
{
- for(const auto& ty : te.fcn.as_Intrinsic().params.m_types)
+ mir_visit.visit_lvalue(*e);
+ }
+ else if(const auto* e = te.fcn.opt_Intrinsic())
+ {
+ for(const auto& ty : e->params.m_types)
tv.visit_type(monomorph(ty));
}
- H::visit_lvalue(tv,pp,fcn, te.ret_val);
+ else
+ {
+ // Paths don't need visiting?
+ }
+ mir_visit.visit_lvalue(te.ret_val);
for(const auto& arg : te.args)
- H::visit_param(tv,pp,fcn, arg);
+ mir_visit.visit_param(arg);
)
)
}
@@ -1550,30 +1438,10 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co
void Trans_Enumerate_FillFrom_MIR_LValue(MIR::EnumCache& state, const ::MIR::LValue& lv)
{
- TU_MATCHA( (lv), (e),
- (Return,
- ),
- (Argument,
- ),
- (Local,
- ),
- (Static,
- state.insert_path(*e);
- ),
- (Field,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val);
- ),
- (Deref,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val);
- ),
- (Index,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val);
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.idx);
- ),
- (Downcast,
- Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val);
- )
- )
+ if( lv.m_root.is_Static() )
+ {
+ state.insert_path(lv.m_root.as_Static());
+ }
}
void Trans_Enumerate_FillFrom_MIR_Constant(MIR::EnumCache& state, const ::MIR::Constant& c)
{
diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp
index 6c331d9c..b5099918 100644
--- a/src/trans/monomorphise.cpp
+++ b/src/trans/monomorphise.cpp
@@ -15,38 +15,14 @@
namespace {
::MIR::LValue monomorph_LValue(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::LValue& tpl)
{
- TU_MATCHA( (tpl), (e),
- (Return, return e; ),
- (Argument, return e; ),
- (Local, return e; ),
- (Static,
- return box$(params.monomorph(resolve, *e));
- ),
- (Field,
- return ::MIR::LValue::make_Field({
- box$(monomorph_LValue(resolve, params, *e.val)),
- e.field_index
- });
- ),
- (Deref,
- return ::MIR::LValue::make_Deref({
- box$(monomorph_LValue(resolve, params, *e.val))
- });
- ),
- (Index,
- return ::MIR::LValue::make_Index({
- box$(monomorph_LValue(resolve, params, *e.val)),
- box$(monomorph_LValue(resolve, params, *e.idx))
- });
- ),
- (Downcast,
- return ::MIR::LValue::make_Downcast({
- box$(monomorph_LValue(resolve, params, *e.val)),
- e.variant_index
- });
- )
- )
- throw "";
+ if( tpl.m_root.is_Static() )
+ {
+ return ::MIR::LValue( ::MIR::LValue::Storage::new_Static(params.monomorph(resolve, tpl.m_root.as_Static())), tpl.m_wrappers );
+ }
+ else
+ {
+ return tpl.clone();
+ }
}
::MIR::Constant monomorph_Constant(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::Constant& tpl)
{