summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/hir/deserialise.cpp3
-rw-r--r--src/hir/serialise.cpp1
-rw-r--r--src/mir/from_hir.hpp5
-rw-r--r--src/mir/mir.hpp3
-rw-r--r--src/mir/mir_builder.cpp46
-rw-r--r--src/trans/codegen_c.cpp7
6 files changed, 51 insertions, 14 deletions
diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp
index 18c58682..19786eb1 100644
--- a/src/hir/deserialise.cpp
+++ b/src/hir/deserialise.cpp
@@ -983,7 +983,8 @@ namespace {
case 3:
return ::MIR::Statement::make_SetDropFlag({
static_cast<unsigned int>(m_in.read_count()),
- m_in.read_bool()
+ m_in.read_bool(),
+ static_cast<unsigned int>(m_in.read_count())
});
default:
::std::cerr << "Bad tag for a MIR Statement" << ::std::endl;
diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp
index fc3aa002..dede23a4 100644
--- a/src/hir/serialise.cpp
+++ b/src/hir/serialise.cpp
@@ -494,6 +494,7 @@ namespace {
m_out.write_tag(3);
m_out.write_count(e.idx);
m_out.write_bool(e.new_val);
+ m_out.write_count(e.other);
)
)
}
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:
diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp
index 9af8875b..11a74b4f 100644
--- a/src/trans/codegen_c.cpp
+++ b/src/trans/codegen_c.cpp
@@ -1188,7 +1188,12 @@ namespace {
case ::MIR::Statement::TAGDEAD: throw "";
case ::MIR::Statement::TAG_SetDropFlag: {
const auto& e = stmt.as_SetDropFlag();
- m_of << "\tdf" << e.idx << " = " << e.new_val << ";\n";
+ m_of << "\tdf" << e.idx << " = ";
+ if( e.other == ~0u )
+ m_of << e.new_val;
+ else
+ m_of << (e.new_val ? "!" : "") << "df" << e.other;
+ m_of << ";\n";
break; }
case ::MIR::Statement::TAG_Drop: {
const auto& e = stmt.as_Drop();