summaryrefslogtreecommitdiff
path: root/src/mir
diff options
context:
space:
mode:
Diffstat (limited to 'src/mir')
-rw-r--r--src/mir/from_hir.hpp5
-rw-r--r--src/mir/mir.hpp3
-rw-r--r--src/mir/mir_builder.cpp46
3 files changed, 42 insertions, 12 deletions
diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp
index 494e0fa6..f4fa3074 100644
--- a/src/mir/from_hir.hpp
+++ b/src/mir/from_hir.hpp
@@ -173,8 +173,9 @@ public:
void push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val);
// Push an inline assembly statement (NOTE: inputs aren't marked as moved)
void push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data);
- // Pus
- void push_stmt_set_dropflag(const Span& sp, unsigned int index, bool value);
+ // Push a setting/clearing of a drop flag
+ void push_stmt_set_dropflag_val(const Span& sp, unsigned int index, bool value);
+ void push_stmt_set_dropflag_other(const Span& sp, unsigned int index, unsigned int other);
// - Block management
bool block_active() const {
diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp
index 565d159b..d897ad13 100644
--- a/src/mir/mir.hpp
+++ b/src/mir/mir.hpp
@@ -224,7 +224,8 @@ TAGGED_UNION(Statement, Assign,
// Update the state of a drop flag
(SetDropFlag, struct {
unsigned int idx;
- bool new_val;
+ bool new_val; // If `other` is populated, this indicates that the other value should be negated
+ unsigned int other = ~0u;
}),
// Drop a value
(Drop, struct {
diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp
index d1a44816..a76129d2 100644
--- a/src/mir/mir_builder.cpp
+++ b/src/mir/mir_builder.cpp
@@ -296,11 +296,16 @@ void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data)
// 2. Push
m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_Asm( mv$(data) ) );
}
-void MirBuilder::push_stmt_set_dropflag(const Span& sp, unsigned int idx, bool value)
+void MirBuilder::push_stmt_set_dropflag_val(const Span& sp, unsigned int idx, bool value)
{
ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_SetDropFlag({ idx, value }) );
}
+void MirBuilder::push_stmt_set_dropflag_other(const Span& sp, unsigned int idx, unsigned int other)
+{
+ ASSERT_BUG(sp, m_block_active, "Pushing statement with no active block");
+ m_output.blocks.at(m_current_block).statements.push_back( ::MIR::Statement::make_SetDropFlag({ idx, false, other }) );
+}
void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst)
{
@@ -567,7 +572,7 @@ unsigned int MirBuilder::new_drop_flag(bool default_state)
unsigned int MirBuilder::new_drop_flag_and_set(const Span& sp, bool set_state)
{
auto rv = new_drop_flag(!set_state);
- push_stmt_set_dropflag(sp, rv, set_state);
+ push_stmt_set_dropflag_val(sp, rv, set_state);
return rv;
}
bool MirBuilder::get_drop_flag_default(const Span& sp, unsigned int idx)
@@ -734,13 +739,32 @@ namespace
return ;
case VarState::TAG_Valid:
return ;
- case VarState::TAG_Optional:
+ case VarState::TAG_Optional: {
+ auto flag_idx = new_state.as_Optional();
// Was valid, now optional.
- if( builder.get_drop_flag_default( sp, new_state.as_Optional() ) != true ) {
- TODO(sp, "Drop flag default not true when going Valid->Optional");
+ if( builder.get_drop_flag_default(sp, flag_idx) != true ) {
+ // Allocate a new drop flag with a default state of `true` and set it to this flag?
+ #if 1
+ auto new_flag = builder.new_drop_flag(true);
+ builder.push_stmt_set_dropflag_other(sp, new_flag, flag_idx);
+ old_state = VarState::make_Optional( new_flag );
+ #else
+ // OR: Push an assign of this flag to every other completed arm
+ // - Cleaner generated code, but can't be used for Optional->Optional
+ for(unsigned int i = 0; i < sd_split.arms.size()-1; i ++)
+ {
+ if( sd_split.arms[i].end_block != 0 ) {
+ m_output.blocks.at( sd_split.arms[i].end_block )
+ .statements.push_back(::MIR::Statement::make_SetDropFlag({ flag_idx, true }));
+ }
+ }
+ #endif
+ }
+ else {
+ old_state = VarState::make_Optional( new_state.as_Optional() );
}
- old_state = VarState::make_Optional( new_state.as_Optional() );
return ;
+ }
case VarState::TAG_Partial:
TODO(sp, "Handle Valid->Partial in split scope");
}
@@ -750,14 +774,18 @@ namespace
{
case VarState::TAGDEAD: throw "";
case VarState::TAG_Invalid:
- builder.push_stmt_set_dropflag(sp, old_state.as_Optional(), false);
+ builder.push_stmt_set_dropflag_val(sp, old_state.as_Optional(), false);
return ;
case VarState::TAG_Valid:
- builder.push_stmt_set_dropflag(sp, old_state.as_Optional(), true);
+ builder.push_stmt_set_dropflag_val(sp, old_state.as_Optional(), true);
return ;
case VarState::TAG_Optional:
if( old_state.as_Optional() != new_state.as_Optional() ) {
- TODO(sp, "Handle Optional->Optional with mismatched flags");
+ #if 1
+ builder.push_stmt_set_dropflag_other(sp, old_state.as_Optional(), new_state.as_Optional());
+ #else
+ // TODO: Rewrite history replacing one flag with another (if they have the same default)
+ #endif
}
return ;
case VarState::TAG_Partial: