diff options
-rw-r--r-- | src/hir/deserialise.cpp | 3 | ||||
-rw-r--r-- | src/hir/serialise.cpp | 1 | ||||
-rw-r--r-- | src/mir/from_hir.hpp | 5 | ||||
-rw-r--r-- | src/mir/mir.hpp | 3 | ||||
-rw-r--r-- | src/mir/mir_builder.cpp | 46 | ||||
-rw-r--r-- | src/trans/codegen_c.cpp | 7 |
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(); |