From 8e1b979158c9d7065efa7c68a406271439168ee0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 11 Jun 2017 21:47:51 +0800 Subject: Codegen C - Make all drop glue static --- src/trans/codegen_c.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 946c7fac..72f2ad8a 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -219,7 +219,7 @@ namespace { ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, args, *(::MIR::Function*)nullptr }; m_mir_res = &mir_res; - m_of << "void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n"; + m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct s_" << Trans_Mangle(p) << "* rv) {\n"; // Obtain inner pointer // TODO: This is very specific to the structure of the official liballoc's Box. @@ -321,7 +321,7 @@ namespace { auto ty_ptr = ::HIR::TypeRef::new_pointer(::HIR::BorrowType::Owned, ty.clone()); ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), ty_ptr, args, *(::MIR::Function*)nullptr }; m_mir_res = &mir_res; - m_of << "void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {"; + m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(ty); m_of << "* rv) {"; auto self = ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Return({})) }); auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); for(const auto& ity : te) @@ -433,13 +433,13 @@ namespace { else if( m_resolve.is_type_owned_box(struct_ty) ) { m_box_glue_todo.push_back( ::std::make_pair( mv$(struct_ty.m_data.as_Path().path.m_data.as_Generic()), &item ) ); - m_of << "void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n"; + m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ");\n"; return ; } ::MIR::TypeResolve mir_res { sp, m_resolve, FMT_CB(ss, ss << drop_glue_path;), struct_ty_ptr, args, *(::MIR::Function*)nullptr }; m_mir_res = &mir_res; - m_of << "void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ") {\n"; + m_of << "static void " << Trans_Mangle(drop_glue_path) << "("; emit_ctype(struct_ty_ptr, FMT_CB(ss, ss << "rv";)); m_of << ") {\n"; // If this type has an impl of Drop, call that impl if( item.m_markings.has_drop_impl ) { @@ -511,7 +511,7 @@ namespace { m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(union u_" << Trans_Mangle(p) << "*rv);\n"; } - m_of << "void " << Trans_Mangle(drop_glue_path) << "(union u_" << Trans_Mangle(p) << "* rv) {\n"; + m_of << "static void " << Trans_Mangle(drop_glue_path) << "(union u_" << Trans_Mangle(p) << "* rv) {\n"; if( item.m_markings.has_drop_impl ) { m_of << "\t" << Trans_Mangle(drop_impl_path) << "(rv);\n"; @@ -685,7 +685,7 @@ namespace { m_of << "tUNIT " << Trans_Mangle(drop_impl_path) << "(struct e_" << Trans_Mangle(p) << "*rv);\n"; } - m_of << "void " << Trans_Mangle(drop_glue_path) << "(struct e_" << Trans_Mangle(p) << "* rv) {\n"; + m_of << "static void " << Trans_Mangle(drop_glue_path) << "(struct e_" << Trans_Mangle(p) << "* rv) {\n"; // If this type has an impl of Drop, call that impl if( item.m_markings.has_drop_impl ) -- cgit v1.2.3 From 194543a45e5a456a78746912e3dc561f096579f5 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 11 Jun 2017 22:26:27 +0800 Subject: Codegen C - Fix -INFINITY --- src/trans/codegen_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 72f2ad8a..68af508a 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -2988,7 +2988,7 @@ namespace { m_of << "NAN"; } else if( ::std::isinf(c.v) ) { - m_of << "INFINITY"; + m_of << (c.v < 0 ? "-" : "") << "INFINITY"; } else { m_of << c.v; -- cgit v1.2.3 From 94015a6835ae0d050a83dee1622e1d1b6851f556 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 15 Jun 2017 14:19:29 +0800 Subject: Codegen C - Fix float precision, disable test broken by fixed precision --- Makefile | 1 + src/trans/codegen_c.cpp | 32 ++++++++++++++------------------ 2 files changed, 15 insertions(+), 18 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/Makefile b/Makefile index 51f2b3be..0e836cdd 100644 --- a/Makefile +++ b/Makefile @@ -779,6 +779,7 @@ DISABLED_TESTS += run-pass/deriving-copyclone # - BUG: Unknown DISABLED_TESTS += run-pass/process-spawn-with-unicode-params # Bad path for process spawn DISABLED_TESTS += run-pass/u128 # u128 not very good, unknown where error is +DISABLED_TESTS += run-pass/issue-32805 # Possible f32 literal rounding isue DEF_RUST_TESTS = $(sort $(patsubst $(RUST_TESTS_DIR)%.rs,output/rust/%_out.txt,$(wildcard $(RUST_TESTS_DIR)$1/*.rs))) rust_tests-run-pass: $(filter-out $(patsubst %,output/rust/%_out.txt,$(DISABLED_TESTS)), $(call DEF_RUST_TESTS,run-pass) $(call DEF_RUST_TESTS,run-pass/union)) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 68af508a..878a55d4 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -894,6 +894,18 @@ namespace { m_mir_res = nullptr; } + void emit_float(double v) { + if( ::std::isnan(v) ) { + m_of << "NAN"; + } + else if( ::std::isinf(v) ) { + m_of << (v < 0 ? "-" : "") << "INFINITY"; + } + else { + m_of.precision(::std::numeric_limits::max_digits10 + 1); + m_of << ::std::scientific << v; + } + } void emit_literal(const ::HIR::TypeRef& ty, const ::HIR::Literal& lit, const Trans_Params& params) { TRACE_FUNCTION_F("ty=" << ty << ", lit=" << lit); ::HIR::TypeRef tmp; @@ -1065,15 +1077,7 @@ namespace { } ), (Float, - if( ::std::isnan(e) ) { - m_of << "NAN"; - } - else if( ::std::isinf(e) ) { - m_of << "INFINITY"; - } - else { - m_of << e; - } + this->emit_float(e); ), (BorrowOf, TU_MATCHA( (e.m_data), (pe), @@ -2984,15 +2988,7 @@ namespace { } ), (Float, - if( ::std::isnan(c.v) ) { - m_of << "NAN"; - } - else if( ::std::isinf(c.v) ) { - m_of << (c.v < 0 ? "-" : "") << "INFINITY"; - } - else { - m_of << c.v; - } + this->emit_float(c.v); ), (Bool, m_of << (c.v ? "true" : "false"); -- cgit v1.2.3 From bbb7023bee036f87b45ba0555e60ce33837460b0 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 16 Jun 2017 10:35:30 +0800 Subject: MIR - Unify temporaries and variables --- src/hir/deserialise.cpp | 12 +- src/hir/serialise.cpp | 18 +- src/hir_conv/bind.cpp | 10 +- src/hir_conv/constant_evaluation.cpp | 25 +- src/hir_expand/const_eval_full.cpp | 32 +-- src/mir/check.cpp | 81 +++--- src/mir/check_full.cpp | 130 +++------ src/mir/cleanup.cpp | 12 +- src/mir/dump.cpp | 27 +- src/mir/from_hir.cpp | 26 +- src/mir/from_hir.hpp | 41 ++- src/mir/from_hir_match.cpp | 2 +- src/mir/helpers.cpp | 65 ++--- src/mir/helpers.hpp | 10 +- src/mir/mir.cpp | 50 ++-- src/mir/mir.hpp | 28 +- src/mir/mir_builder.cpp | 543 +++++++++++------------------------ src/mir/optimise.cpp | 272 +++++++----------- src/trans/codegen_c.cpp | 33 +-- src/trans/enumerate.cpp | 29 +- src/trans/monomorphise.cpp | 19 +- 21 files changed, 521 insertions(+), 944 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index f4dfdf19..3cb58a2e 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -338,11 +338,10 @@ namespace { switch(auto tag = m_in.read_tag()) { #define _(x, ...) case ::MIR::LValue::TAG_##x: return ::MIR::LValue::make_##x( __VA_ARGS__ ); - _(Variable, static_cast(m_in.read_count()) ) - _(Temporary, { static_cast(m_in.read_count()) } ) - _(Argument, { static_cast(m_in.read_count()) } ) - _(Static, deserialise_path() ) _(Return, {}) + _(Argument, { static_cast(m_in.read_count()) } ) + _(Local, static_cast(m_in.read_count()) ) + _(Static, deserialise_path() ) _(Field, { box$( deserialise_mir_lvalue() ), static_cast(m_in.read_count()) @@ -962,8 +961,8 @@ namespace { ::MIR::Function rv; - rv.named_variables = deserialise_vec< ::HIR::TypeRef>( ); - rv.temporaries = deserialise_vec< ::HIR::TypeRef>( ); + rv.locals = deserialise_vec< ::HIR::TypeRef>( ); + //rv.local_names = deserialise_vec< ::std::string>( ); rv.drop_flags = deserialise_vec(); rv.blocks = deserialise_vec< ::MIR::BasicBlock>( ); @@ -1012,7 +1011,6 @@ namespace { } case 4: return ::MIR::Statement::make_ScopeEnd({ - deserialise_vec(), deserialise_vec() }); default: diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index 77e17dba..cddbf0b8 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -457,8 +457,8 @@ namespace { void serialise(const ::MIR::Function& mir) { // Write out MIR. - serialise_vec( mir.named_variables ); - serialise_vec( mir.temporaries ); + serialise_vec( mir.locals ); + //serialise_vec( mir.slot_names ); serialise_vec( mir.drop_flags ); serialise_vec( mir.blocks ); } @@ -498,8 +498,7 @@ namespace { ), (ScopeEnd, m_out.write_tag(4); - serialise_vec(e.vars); - serialise_vec(e.tmps); + serialise_vec(e.slots); ) ) } @@ -571,20 +570,17 @@ namespace { TRACE_FUNCTION_F("LValue = "<(lv.tag()) ); TU_MATCHA( (lv), (e), - (Variable, - m_out.write_count(e); - ), - (Temporary, - m_out.write_count(e.idx); + (Return, ), (Argument, m_out.write_count(e.idx); ), + (Local, + m_out.write_count(e); + ), (Static, serialise_path(e); ), - (Return, - ), (Field, serialise(e.val); m_out.write_count(e.field_index); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index cf443eb6..1b0f61b6 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -480,14 +480,12 @@ namespace { static void visit_lvalue(Visitor& upper_visitor, ::MIR::LValue& lv) { TU_MATCHA( (lv), (e), - (Variable, + (Return, ), - (Temporary, + (Local, ), (Argument, ), - (Return, - ), (Static, upper_visitor.visit_path(e, ::HIR::Visitor::PathContext::VALUE); ), @@ -529,9 +527,7 @@ namespace { ) } }; - for(auto& ty : expr.m_mir->named_variables) - this->visit_type(ty); - for(auto& ty : expr.m_mir->temporaries) + for(auto& ty : expr.m_mir->locals) this->visit_type(ty); for(auto& block : expr.m_mir->blocks) { diff --git a/src/hir_conv/constant_evaluation.cpp b/src/hir_conv/constant_evaluation.cpp index a950a3dd..e8138169 100644 --- a/src/hir_conv/constant_evaluation.cpp +++ b/src/hir_conv/constant_evaluation.cpp @@ -1026,32 +1026,25 @@ namespace { ::MIR::TypeResolve state { sp, resolve, FMT_CB(,), exp, {}, fcn }; ::HIR::Literal retval; - ::std::vector< ::HIR::Literal> locals; - ::std::vector< ::HIR::Literal> temps; - locals.resize( fcn.named_variables.size() ); - temps.resize( fcn.temporaries.size() ); + ::std::vector< ::HIR::Literal> locals( fcn.locals.size() ); auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { TU_MATCHA( (lv), (e), - (Variable, - if( e >= locals.size() ) - BUG(sp, "Local index out of range - " << e << " >= " << locals.size()); - return locals[e]; - ), - (Temporary, - if( e.idx >= temps.size() ) - BUG(sp, "Temp index out of range - " << e.idx << " >= " << temps.size()); - return temps[e.idx]; + (Return, + return retval; ), (Argument, + ASSERT_BUG(sp, e.idx < args.size(), "Argument index out of range - " << e.idx << " >= " << args.size()); return args[e.idx]; ), + (Local, + if( e >= locals.size() ) + BUG(sp, "Local index out of range - " << e << " >= " << locals.size()); + return locals[e]; + ), (Static, TODO(sp, "LValue::Static"); ), - (Return, - return retval; - ), (Field, TODO(sp, "LValue::Field"); ), diff --git a/src/hir_expand/const_eval_full.cpp b/src/hir_expand/const_eval_full.cpp index 538693f4..04575a6e 100644 --- a/src/hir_expand/const_eval_full.cpp +++ b/src/hir_expand/const_eval_full.cpp @@ -292,49 +292,41 @@ namespace { ::MIR::TypeResolve state { sp, resolve, name, ::HIR::TypeRef(), {}, fcn }; ::HIR::Literal retval; - ::std::vector< ::HIR::Literal> locals; - ::std::vector< ::HIR::Literal> temps; - locals.resize( fcn.named_variables.size() ); - temps.resize( fcn.temporaries.size() ); + ::std::vector< ::HIR::Literal> locals( fcn.locals.size() ); struct LocalState { typedef ::std::vector< ::HIR::Literal> t_vec_lit; ::MIR::TypeResolve& state; ::HIR::Literal& retval; - ::std::vector< ::HIR::Literal>& locals; - ::std::vector< ::HIR::Literal>& temps; ::std::vector< ::HIR::Literal>& args; + ::std::vector< ::HIR::Literal>& locals; - LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& locals, t_vec_lit& temps, t_vec_lit& args): + LocalState(::MIR::TypeResolve& state, ::HIR::Literal& retval, t_vec_lit& args, t_vec_lit& locals): state(state), retval(retval), - locals(locals), - temps(temps), - args(args) + args(args), + locals(locals) {} ::HIR::Literal& get_lval(const ::MIR::LValue& lv) { TU_MATCHA( (lv), (e), - (Variable, + (Return, + return retval; + ), + (Local, if( e >= locals.size() ) MIR_BUG(state, "Local index out of range - " << e << " >= " << locals.size()); return locals[e]; ), - (Temporary, - if( e.idx >= temps.size() ) - MIR_BUG(state, "Temp index out of range - " << e.idx << " >= " << temps.size()); - return temps[e.idx]; - ), (Argument, + if( e.idx >= args.size() ) + MIR_BUG(state, "Local index out of range - " << e.idx << " >= " << args.size()); return args[e.idx]; ), (Static, MIR_TODO(state, "LValue::Static - " << e); ), - (Return, - return retval; - ), (Field, auto& val = get_lval(*e.val); MIR_ASSERT(state, val.is_List(), "LValue::Field on non-list literal - " << val.tag_str() << " - " << lv); @@ -362,7 +354,7 @@ namespace { throw ""; } }; - LocalState local_state( state, retval, locals, temps, args ); + LocalState local_state( state, retval, args, locals ); auto get_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal& { return local_state.get_lval(lv); }; auto read_lval = [&](const ::MIR::LValue& lv) -> ::HIR::Literal { diff --git a/src/mir/check.cpp b/src/mir/check.cpp index f669623a..58bcaf55 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -105,15 +105,13 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn Valid, }; State ret_state = State::Invalid; - ::std::vector arguments; - ::std::vector temporaries; - ::std::vector variables; + ::std::vector args; + ::std::vector locals; ValStates() {} - ValStates(size_t n_args, size_t n_temps, size_t n_vars): - arguments(n_args, State::Valid), - temporaries(n_temps), - variables(n_vars) + ValStates(size_t n_args, size_t n_locals): + args(n_args, State::Valid), + locals(n_locals) { } @@ -144,22 +142,20 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn } } }; - fmt_val_range("arg", this->arguments); - fmt_val_range("tmp", this->temporaries); - fmt_val_range("var", this->variables); + fmt_val_range("arg", this->args); + fmt_val_range("_", this->locals); os << "}"; } bool operator==(const ValStates& x) const { - if( ret_state != x.ret_state ) return false; - if( arguments != x.arguments ) return false; - if( temporaries != x.temporaries ) return false; - if( variables != x.variables ) return false; + if( ret_state != x.ret_state ) return false; + if( args != x.args ) return false; + if( locals != x.locals ) return false; return true; } bool empty() const { - return arguments.empty() && temporaries.empty() && variables.empty(); + return locals.empty() && args.empty(); } bool merge(unsigned bb_idx, ValStates& other) @@ -178,9 +174,8 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn { bool rv = false; rv |= ValStates::merge_state(this->ret_state, other.ret_state); - rv |= ValStates::merge_lists(this->arguments , other.arguments); - rv |= ValStates::merge_lists(this->temporaries, other.temporaries); - rv |= ValStates::merge_lists(this->variables , other.variables); + rv |= ValStates::merge_lists(this->args , other.args ); + rv |= ValStates::merge_lists(this->locals, other.locals); return rv; } } @@ -194,42 +189,32 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn ret_state = is_valid ? State::Valid : State::Invalid; ), (Argument, - MIR_ASSERT(state, e.idx < this->arguments.size(), ""); - DEBUG("arg" << e.idx << " = " << (is_valid ? "Valid" : "Invalid")); - this->arguments[e.idx] = is_valid ? State::Valid : State::Invalid; + 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; ), - (Variable, - MIR_ASSERT(state, e < this->variables.size(), ""); - DEBUG("var" << e << " = " << (is_valid ? "Valid" : "Invalid")); - this->variables[e] = is_valid ? State::Valid : State::Invalid; - ), - (Temporary, - MIR_ASSERT(state, e.idx < this->temporaries.size(), ""); - DEBUG("tmp" << e.idx << " = " << (is_valid ? "Valid" : "Invalid")); - this->temporaries[e.idx] = is_valid ? State::Valid : State::Invalid; + (Local, + MIR_ASSERT(state, e < this->locals.size(), "Local index out of range"); + DEBUG("_" << e << " = " << (is_valid ? "Valid" : "Invalid")); + this->locals[e] = is_valid ? State::Valid : State::Invalid; ) ) } void ensure_valid(const ::MIR::TypeResolve& state, const ::MIR::LValue& lv) { TU_MATCH( ::MIR::LValue, (lv), (e), - (Variable, - MIR_ASSERT(state, e < this->variables.size(), ""); - if( this->variables[e] != State::Valid ) - MIR_BUG(state, "Use of non-valid variable - " << lv); - ), - (Temporary, - MIR_ASSERT(state, e.idx < this->temporaries.size(), ""); - if( this->temporaries[e.idx] != State::Valid ) - MIR_BUG(state, "Use of non-valid temporary - " << lv); + (Return, + if( this->ret_state != State::Valid ) + MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Argument, - MIR_ASSERT(state, e.idx < this->arguments.size(), ""); - if( this->arguments[e.idx] != State::Valid ) - MIR_BUG(state, "Use of non-valid argument - " << lv); + MIR_ASSERT(state, e.idx < this->args.size(), "Arg index out of range"); + if( this->args[e.idx] != State::Valid ) + MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), - (Return, - if( this->ret_state != State::Valid ) + (Local, + MIR_ASSERT(state, e < this->locals.size(), "Local index out of range"); + if( this->locals[e] != State::Valid ) MIR_BUG(state, "Use of non-valid lvalue - " << lv); ), (Static, @@ -309,7 +294,7 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn src_path.push_back(idx); to_visit_blocks.push_back( ToVisit { idx, mv$(src_path), mv$(vs) } ); }; - add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.temporaries.size(), fcn.named_variables.size() } ); + add_to_visit( 0, {}, ValStates { state.m_args.size(), fcn.locals.size() } ); while( to_visit_blocks.size() > 0 ) { auto block = to_visit_blocks.back().bb; @@ -430,12 +415,12 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn // Check if the return value has been set val_state.ensure_valid( state, ::MIR::LValue::make_Return({}) ); // Ensure that no other non-Copy values are valid - for(unsigned int i = 0; i < val_state.variables.size(); i ++) + for(unsigned int i = 0; i < val_state.locals.size(); i ++) { - if( val_state.variables[i] == ValStates::State::Invalid ) + if( val_state.locals[i] == ValStates::State::Invalid ) { } - else if( state.m_resolve.type_is_copy(state.sp, fcn.named_variables[i]) ) + else if( state.m_resolve.type_is_copy(state.sp, fcn.locals[i]) ) { } else diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index f49598da..a153aca7 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -67,10 +67,9 @@ namespace { struct ValueStates { - ::std::vector vars; - ::std::vector temporaries; - ::std::vector arguments; State return_value; + ::std::vector args; + ::std::vector locals; ::std::vector drop_flags; ::std::vector< ::std::vector > inner_states; @@ -89,10 +88,9 @@ namespace } }; ValueStates rv; - rv.vars = H::clone_state_list(this->vars); - rv.temporaries = H::clone_state_list(this->temporaries); - rv.arguments = H::clone_state_list(this->arguments); rv.return_value = State(this->return_value); + rv.args = H::clone_state_list(this->args); + rv.locals = H::clone_state_list(this->locals); rv.drop_flags = this->drop_flags; rv.inner_states.reserve( this->inner_states.size() ); for(const auto& isl : this->inner_states) @@ -139,22 +137,18 @@ namespace return false; if( ! H::equal(*this, return_value, x, x.return_value) ) return false; - assert(vars.size() == x.vars.size()); - for(size_t i = 0; i < vars.size(); i ++) - { - if( ! H::equal(*this, vars[i], x, x.vars[i]) ) - return false; - } - assert(temporaries.size() == x.temporaries.size()); - for(size_t i = 0; i < temporaries.size(); i ++) + + assert(args.size() == x.args.size()); + for(size_t i = 0; i < args.size(); i ++) { - if( ! H::equal(*this, temporaries[i], x, x.temporaries[i]) ) + if( ! H::equal(*this, args[i], x, x.args[i]) ) return false; } - assert(arguments.size() == x.arguments.size()); - for(size_t i = 0; i < arguments.size(); i ++) + + assert(locals.size() == x.locals.size()); + for(size_t i = 0; i < locals.size(); i ++) { - if( ! H::equal(*this, arguments[i], x, x.arguments[i]) ) + if( ! H::equal(*this, locals[i], x, x.locals[i]) ) return false; } return true; @@ -397,13 +391,11 @@ namespace Marker m; m.used.resize(this->inner_states.size(), false); - for(const auto& s : this->vars) - m.mark_from_state(*this, s); - for(const auto& s : this->temporaries) + m.mark_from_state(*this, this->return_value); + for(const auto& s : this->args) m.mark_from_state(*this, s); - for(const auto& s : this->arguments) + for(const auto& s : this->locals) m.mark_from_state(*this, s); - m.mark_from_state(*this, this->return_value); } private: ::std::vector& allocate_composite_int(State& out_state) @@ -455,22 +447,19 @@ namespace const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const { TU_MATCHA( (lv), (e), - (Variable, - return vars.at(e); - ), - (Temporary, - return temporaries.at(e.idx); + (Return, + return return_value; ), (Argument, - return arguments.at(e.idx); + return args.at(e.idx); + ), + (Local, + return locals.at(e); ), (Static, static State state_of_static(true); return state_of_static; ), - (Return, - return return_value; - ), (Field, const auto& vs = get_lvalue_state(mir_res, *e.val); if( vs.is_composite() ) @@ -520,7 +509,7 @@ namespace ) throw ""; } - + void clear_state(const ::MIR::TypeResolve& mir_res, State& s) { if(s.is_composite()) { auto& sub_states = this->get_composite(mir_res, s); @@ -529,33 +518,28 @@ namespace sub_states.clear(); } } - + 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), - (Variable, - auto& slot = vars.at(e); - this->clear_state(mir_res, slot); - slot = mv$(new_vs); + (Return, + this->clear_state(mir_res, return_value); + return_value = mv$(new_vs); ), - (Temporary, - auto& slot = temporaries.at(e.idx); + (Argument, + auto& slot = args.at(e.idx); this->clear_state(mir_res, slot); slot = mv$(new_vs); ), - (Argument, - auto& slot = arguments.at(e.idx); + (Local, + auto& slot = locals.at(e); this->clear_state(mir_res, slot); slot = mv$(new_vs); ), (Static, // Ignore. ), - (Return, - this->clear_state(mir_res, return_value); - return_value = mv$(new_vs); - ), (Field, const auto& cur_vs = get_lvalue_state(mir_res, *e.val); if( !cur_vs.is_composite() && cur_vs == new_vs ) @@ -736,12 +720,10 @@ namespace std { os << "ValueStates(path=[" << x.bb_path << "]"; print_val(",rv", x.return_value); - for(unsigned int i = 0; i < x.arguments.size(); i ++) - print_val(FMT_CB(ss, ss << ",a" << i;), x.arguments[i]); - for(unsigned int i = 0; i < x.vars.size(); i ++) - print_val(FMT_CB(ss, ss << ",_" << i;), x.vars[i]); - for(unsigned int i = 0; i < x.temporaries.size(); i ++) - print_val(FMT_CB(ss, ss << ",t" << i;), x.temporaries[i]); + for(unsigned int i = 0; i < x.args.size(); i ++) + print_val(FMT_CB(ss, ss << ",a" << i;), x.args[i]); + for(unsigned int i = 0; i < x.locals.size(); i ++) + print_val(FMT_CB(ss, ss << ",_" << i;), x.locals[i]); for(unsigned int i = 0; i < x.drop_flags.size(); i++) if(x.drop_flags[i]) os << ",df" << i; @@ -774,9 +756,8 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio return rv; } }; - state.arguments = H::make_list(mir_res.m_args.size(), true); - state.vars = H::make_list(fcn.named_variables.size(), false); - state.temporaries = H::make_list(fcn.temporaries.size(), false); + state.args = H::make_list(mir_res.m_args.size(), true); + state.locals = H::make_list(fcn.locals.size(), false); state.drop_flags = fcn.drop_flags; ::std::vector< ::std::pair > todo_queue; @@ -789,46 +770,25 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio // Mask off any values which aren't valid in the first statement of this block { - for(unsigned i = 0; i < state.vars.size(); i ++) - { - /*if( !variables_copy[i] ) - { - // Not Copy, don't apply masking - } - else*/ if( ! state.vars[i].is_valid() ) - { - // Already invalid - } - else if( lifetimes.var_valid(i, cur_block, 0) ) - { - // Expected to be valid in this block, leave as-is - } - else - { - // Copy value not used at/after this block, mask to false - DEBUG("BB" << cur_block << " - var$" << i << " - Outside lifetime, discard"); - state.vars[i] = State(false); - } - } - for(unsigned i = 0; i < state.temporaries.size(); i ++) + for(unsigned i = 0; i < state.locals.size(); i ++) { /*if( !variables_copy[i] ) { // Not Copy, don't apply masking } - else*/ if( ! state.temporaries[i].is_valid() ) + else*/ if( ! state.locals[i].is_valid() ) { // Already invalid } - else if( lifetimes.tmp_valid(i, cur_block, 0) ) + else if( lifetimes.slot_valid(i, cur_block, 0) ) { // Expected to be valid in this block, leave as-is } else { // Copy value not used at/after this block, mask to false - DEBUG("BB" << cur_block << " - tmp$" << i << " - Outside lifetime, discard"); - state.temporaries[i] = State(false); + DEBUG("BB" << cur_block << " - _" << i << " - Outside lifetime, discard"); + state.locals[i] = State(false); } } } @@ -1007,11 +967,11 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio } } }; - for(unsigned i = 0; i < state.arguments.size(); i ++ ) { - ensure_dropped(state.arguments[i], ::MIR::LValue::make_Argument({i})); + for(unsigned i = 0; i < state.locals.size(); i ++ ) { + ensure_dropped(state.locals[i], ::MIR::LValue::make_Local(i)); } - for(unsigned i = 0; i < state.vars.size(); i ++ ) { - ensure_dropped(state.vars[i], ::MIR::LValue::make_Variable(i)); + for(unsigned i = 0; i < state.args.size(); i ++ ) { + ensure_dropped(state.args[i], ::MIR::LValue::make_Argument({i})); } } ), diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 17dca948..3dda81dc 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -32,8 +32,8 @@ struct MirMutator ::MIR::LValue new_temporary(::HIR::TypeRef ty) { - auto rv = ::MIR::LValue::make_Temporary({ static_cast(m_fcn.temporaries.size()) }); - m_fcn.temporaries.push_back( mv$(ty) ); + auto rv = ::MIR::LValue::make_Local( static_cast(m_fcn.locals.size()) ); + m_fcn.locals.push_back( mv$(ty) ); return rv; } @@ -831,15 +831,13 @@ 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), - (Variable, - ), - (Temporary, + (Return, ), (Argument, ), - (Static, + (Local, ), - (Return, + (Static, ), (Field, MIR_Cleanup_LValue(state, mutator, *le.val); diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index b4177295..4e53cf5b 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -25,13 +25,9 @@ namespace { void dump_mir(const ::MIR::Function& fcn) { - for(unsigned int i = 0; i < fcn.named_variables.size(); i ++) + for(size_t i = 0; i < fcn.locals.size(); i ++) { - m_os << indent() << "let _#" << i << ": " << fcn.named_variables[i] << ";\n"; - } - for(unsigned int i = 0; i < fcn.temporaries.size(); i ++) - { - m_os << indent() << "let tmp$" << i << ": " << fcn.temporaries[i] << ";\n"; + m_os << indent() << "let _$" << i << ": " << fcn.locals[i] << ";\n"; } for(unsigned int i = 0; i < fcn.drop_flags.size(); i ++) { @@ -102,10 +98,8 @@ namespace { ), (ScopeEnd, m_os << "// Scope End: "; - for(auto idx : e.vars) - m_os << "var$" << idx << ","; - for(auto idx : e.tmps) - m_os << "tmp$" << idx << ","; + for(auto idx : e.slots) + m_os << "_$" << idx << ","; m_os << "\n"; ) ) @@ -165,21 +159,18 @@ namespace { } void fmt_val(::std::ostream& os, const ::MIR::LValue& lval) { TU_MATCHA( (lval), (e), - (Variable, - os << "_#" << e; - ), - (Temporary, - os << "tmp$" << e.idx; + (Return, + os << "RETURN"; ), (Argument, os << "arg$" << e.idx; ), + (Local, + os << "_$" << e; + ), (Static, os << e; ), - (Return, - os << "RETURN"; - ), (Field, os << "("; fmt_val(os, *e.val); diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index d9796aed..149d53ea 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -175,16 +175,16 @@ namespace { switch( pat.m_binding.m_type ) { case ::HIR::PatternBinding::Type::Move: - m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), mv$(lval) ); + m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), mv$(lval) ); break; case ::HIR::PatternBinding::Type::Ref: if(m_borrow_raise_target) { DEBUG("- Raising destructure borrow of " << lval << " to scope " << *m_borrow_raise_target); - m_builder.raise_variables(sp, lval, *m_borrow_raise_target); + m_builder.raise_temporaries(sp, lval, *m_borrow_raise_target); } - m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({ + m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Shared, mv$(lval) }) ); break; @@ -192,9 +192,9 @@ namespace { if(m_borrow_raise_target) { DEBUG("- Raising destructure borrow of " << lval << " to scope " << *m_borrow_raise_target); - m_builder.raise_variables(sp, lval, *m_borrow_raise_target); + m_builder.raise_temporaries(sp, lval, *m_borrow_raise_target); } - m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({ + m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, pat.m_binding.m_slot), ::MIR::RValue::make_Borrow({ 0, ::HIR::BorrowType::Unique, mv$(lval) }) ); break; @@ -390,7 +390,7 @@ namespace { ); // Construct fat pointer - m_builder.push_stmt_assign( sp, ::MIR::LValue::make_Variable(e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) ); + m_builder.push_stmt_assign( sp, m_builder.get_variable(sp, e.extra_bind.m_slot), ::MIR::RValue::make_MakeDst({ mv$(ptr_val), mv$(len_val) }) ); } if( e.trailing.size() > 0 ) { @@ -536,7 +536,7 @@ namespace { if( node.m_pattern.m_binding.is_valid() && node.m_pattern.m_data.is_Any() && node.m_pattern.m_binding.m_type == ::HIR::PatternBinding::Type::Move ) { - m_builder.push_stmt_assign( node.span(), ::MIR::LValue::make_Variable(node.m_pattern.m_binding.m_slot), mv$(res) ); + m_builder.push_stmt_assign( node.span(), m_builder.get_variable(node.span(), node.m_pattern.m_binding.m_slot), mv$(res) ); } else { @@ -663,7 +663,7 @@ namespace { if( m_builder.block_active() ) { auto res = m_builder.get_result(arm.m_code->span()); - m_builder.raise_variables( arm.m_code->span(), res, scope, /*to_above=*/true); + m_builder.raise_temporaries( arm.m_code->span(), res, scope, /*to_above=*/true); m_builder.set_result(arm.m_code->span(), mv$(res)); m_builder.terminate_scope( node.span(), mv$(tmp_scope) ); @@ -1157,7 +1157,7 @@ namespace { if( m_borrow_raise_target ) { DEBUG("- Raising borrow to scope " << *m_borrow_raise_target); - m_builder.raise_variables(node.span(), val, *m_borrow_raise_target); + m_builder.raise_temporaries(node.span(), val, *m_borrow_raise_target); } m_builder.set_result( node.span(), ::MIR::RValue::make_Borrow({ 0, node.m_type, mv$(val) }) ); @@ -1438,7 +1438,7 @@ namespace { if( m_borrow_raise_target && m_in_borrow ) { DEBUG("- Raising deref in borrow to scope " << *m_borrow_raise_target); - m_builder.raise_variables(node.span(), val, *m_borrow_raise_target); + m_builder.raise_temporaries(node.span(), val, *m_borrow_raise_target); } @@ -2057,7 +2057,7 @@ namespace { void visit(::HIR::ExprNode_Variable& node) override { TRACE_FUNCTION_F("_Variable - " << node.m_name << " #" << node.m_slot); - m_builder.set_result( node.span(), ::MIR::LValue::make_Variable(node.m_slot) ); + m_builder.set_result( node.span(), m_builder.get_variable(node.span(), node.m_slot) ); } void visit(::HIR::ExprNode_StructLiteral& node) override @@ -2239,9 +2239,9 @@ namespace { TRACE_FUNCTION; ::MIR::Function fcn; - fcn.named_variables.reserve(ptr.m_bindings.size()); + fcn.locals.reserve(ptr.m_bindings.size()); for(const auto& t : ptr.m_bindings) - fcn.named_variables.push_back( t.clone() ); + fcn.locals.push_back( t.clone() ); // Scope ensures that builder cleanup happens before `fcn` is moved { diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 6b10d5bd..2730631f 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -79,20 +79,16 @@ extern ::std::ostream& operator<<(::std::ostream& os, const VarState& x); struct SplitArm { bool has_early_terminated = false; bool always_early_terminated = false; // Populated on completion - ::std::map var_states; - ::std::map tmp_states; + ::std::map states; }; struct SplitEnd { - ::std::map var_states; - ::std::map tmp_states; + ::std::map states; }; -TAGGED_UNION(ScopeType, Variables, - (Variables, struct { - ::std::vector vars; // List of owned variables - }), - (Temporaries, struct { - ::std::vector temporaries; // Controlled temporaries +TAGGED_UNION(ScopeType, Owning, + (Owning, struct { + bool is_temporary; + ::std::vector slots; // List of owned variables }), (Split, struct { bool end_state_valid = false; @@ -101,8 +97,7 @@ TAGGED_UNION(ScopeType, Variables, }), (Loop, struct { // NOTE: This contains the original state for variables changed after `exit_state_valid` is true - ::std::map changed_vars; - ::std::map changed_tmps; + ::std::map changed_slots; bool exit_state_valid; SplitEnd exit_state; }) @@ -134,11 +129,11 @@ class MirBuilder ::MIR::RValue m_result; bool m_result_valid; - // TODO: Extra information. + // TODO: Extra information (e.g. mutability) VarState m_return_state; ::std::vector m_arg_states; - ::std::vector m_variable_states; - ::std::vector m_temporary_states; + ::std::vector m_slot_states; + size_t m_first_temp_idx; struct ScopeDef { @@ -177,6 +172,9 @@ public: const ::HIR::TypeRef* is_type_owned_box(const ::HIR::TypeRef& ty) const; // - Values + ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { + return ::MIR::LValue::make_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); @@ -228,8 +226,8 @@ public: void mark_value_assigned(const Span& sp, const ::MIR::LValue& val); // Moves control of temporaries up to the specified scope (or to above it) - void raise_variables(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above=false); - void raise_variables(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above=false); + void raise_temporaries(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above=false); + void raise_temporaries(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above=false); void set_cur_block(unsigned int new_block); ::MIR::BasicBlockId pause_cur_block(); @@ -269,13 +267,8 @@ public: // Helper - Marks a variable/... as moved (and checks if the move is valid) void moved_lvalue(const Span& sp, const ::MIR::LValue& lv); private: - const VarState& get_slot_state(const Span& sp, VarGroup ty, unsigned int idx, unsigned int skip_count=0) const; - VarState& get_slot_state_mut(const Span& sp, VarGroup ty, unsigned int idx); - - const VarState& get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const; - VarState& get_variable_state_mut(const Span& sp, unsigned int idx); - const VarState& get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const; - VarState& get_temp_state_mut(const Span& sp, unsigned int idx); + const VarState& get_slot_state(const Span& sp, unsigned int idx, unsigned int skip_count=0) const; + VarState& get_slot_state_mut(const Span& sp, unsigned int idx); const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0); VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index a68fd1bf..6e00e2e4 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -219,7 +219,7 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod { if( pat.m_binding.m_type != ::HIR::PatternBinding::Type::Move) return false; - return !builder.lvalue_is_copy( sp, ::MIR::LValue::make_Variable( pat.m_binding.m_slot) ); + return !builder.lvalue_is_copy( sp, builder.get_variable(sp, pat.m_binding.m_slot) ); } TU_MATCHA( (pat.m_data), (e), (Any, diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index c38e73e9..31b50246 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -70,24 +70,20 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_static_type(::HIR::TypeRef& tmp, c const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, const ::MIR::LValue& val) const { TU_MATCH(::MIR::LValue, (val), (e), - (Variable, - MIR_ASSERT(*this, e < m_fcn.named_variables.size(), val << " out of range (" << m_fcn.named_variables.size() << ")"); - return m_fcn.named_variables.at(e); - ), - (Temporary, - MIR_ASSERT(*this, e.idx < m_fcn.temporaries.size(), val << " out of range (" << m_fcn.temporaries.size() << ")"); - return m_fcn.temporaries.at(e.idx); + (Return, + return m_ret_type; ), (Argument, - MIR_ASSERT(*this, e.idx < m_args.size(), val << " out of range (" << m_args.size() << ")"); + MIR_ASSERT(*this, e.idx < m_args.size(), "Argument " << val << " out of range (" << m_args.size() << ")"); return m_args.at(e.idx).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); + ), (Static, return get_static_type(tmp, e); ), - (Return, - return m_ret_type; - ), (Field, const auto& ty = this->get_lvalue_type(tmp, *e.val); TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), @@ -314,16 +310,14 @@ namespace visit { if( cb(lv, u) ) return true; TU_MATCHA( (lv), (e), - (Variable, + (Return, ), (Argument, ), - (Temporary, + (Local, ), (Static, ), - (Return, - ), (Field, return visit_mir_lvalue(*e.val, u, cb); ), @@ -547,27 +541,21 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c } block_offsets.push_back(statement_count); // Store the final limit for later code to use. - ::std::vector temporary_lifetimes( fcn.temporaries.size(), ValueLifetime(statement_count) ); - ::std::vector variable_lifetimes( fcn.named_variables.size(), ValueLifetime(statement_count) ); - + ::std::vector slot_lifetimes( fcn.locals.size(), ValueLifetime(statement_count) ); // Enumerate direct assignments of variables (linear iteration of BB list) for(size_t bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++) { 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_Variable() ) - { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, variable_lifetimes[*de]); - variable_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); - } - else if( const auto* de = lv.opt_Temporary() ) + if( const auto* de = lv.opt_Local() ) { - MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, temporary_lifetimes[de->idx]); - temporary_lifetimes[de->idx].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 { + // TODO: Can Argument(_) be assigned? // Not a direct assignment of a slot } }; @@ -589,6 +577,14 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c assigned_lvalue(bb_idx, stmt_idx+1, e.second); } } + 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() ) + { + slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx,stmt_idx); + } + } } state.set_cur_stmt_term(bb_idx); @@ -601,25 +597,18 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c // Dump out variable lifetimes. if( dump_debug ) { - for(unsigned int i = 0; i < temporary_lifetimes.size(); i ++) + for(size_t i = 0; i < slot_lifetimes.size(); i ++) { - temporary_lifetimes[i].dump_debug("tmp", i, block_offsets); - } - for(unsigned int i = 0; i < variable_lifetimes.size(); i ++) - { - variable_lifetimes[i].dump_debug("var", i, block_offsets); + slot_lifetimes[i].dump_debug("_", i, block_offsets); } } ::MIR::ValueLifetimes rv; rv.m_block_offsets = mv$(block_offsets); - rv.m_temporaries.reserve( temporary_lifetimes.size() ); - for(auto& lft : temporary_lifetimes) - rv.m_temporaries.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) ); - rv.m_variables.reserve( variable_lifetimes.size() ); - for(auto& lft : variable_lifetimes) - rv.m_variables.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) ); + rv.m_slots.reserve( slot_lifetimes.size() ); + for(auto& lft : slot_lifetimes) + rv.m_slots.push_back( ::MIR::ValueLifetime(mv$(lft.stmt_bitmap)) ); return rv; } void MIR_Helper_GetLifetimes_DetermineValueLifetime( diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp index 802ce88f..091a669f 100644 --- a/src/mir/helpers.hpp +++ b/src/mir/helpers.hpp @@ -158,14 +158,10 @@ public: struct ValueLifetimes { ::std::vector m_block_offsets; - ::std::vector m_temporaries; - ::std::vector m_variables; + ::std::vector m_slots; - bool var_valid(unsigned var_idx, unsigned bb_idx, unsigned stmt_idx) const { - return m_variables.at(var_idx).valid_at( m_block_offsets[bb_idx] + stmt_idx ); - } - bool tmp_valid(unsigned tmp_idx, unsigned bb_idx, unsigned stmt_idx) const { - return m_temporaries.at(tmp_idx).valid_at( m_block_offsets[bb_idx] + stmt_idx ); + bool slot_valid(unsigned idx, unsigned bb_idx, unsigned stmt_idx) const { + return m_slots.at(idx).valid_at( m_block_offsets[bb_idx] + stmt_idx ); } }; diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 9edc925b..3f7057ff 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -92,21 +92,18 @@ namespace MIR { ::std::ostream& operator<<(::std::ostream& os, const LValue& x) { TU_MATCHA( (x), (e), - (Variable, - os << "Variable(" << e << ")"; - ), - (Temporary, - os << "Temporary(" << e.idx << ")"; + (Return, + os << "Return"; ), (Argument, os << "Argument(" << e.idx << ")"; ), + (Local, + os << "Local(" << e << ")"; + ), (Static, os << "Static(" << e << ")"; ), - (Return, - os << "Return"; - ), (Field, os << "Field(" << e.field_index << ", " << *e.val << ")"; ), @@ -127,20 +124,17 @@ namespace MIR { if( a.tag() != b.tag() ) return a.tag() < b.tag(); TU_MATCHA( (a, b), (ea, eb), - (Variable, - return ea < eb; - ), - (Temporary, - return ea.idx < eb.idx; + (Return, + return false; ), (Argument, return ea.idx < eb.idx; ), - (Static, + (Local, return ea < eb; ), - (Return, - return false; + (Static, + return ea < eb; ), (Field, if( *ea.val != *eb.val ) @@ -170,20 +164,17 @@ namespace MIR { if( a.tag() != b.tag() ) return false; TU_MATCHA( (a, b), (ea, eb), - (Variable, - return ea == eb; - ), - (Temporary, - return ea.idx == eb.idx; + (Return, + return true; ), (Argument, return ea.idx == eb.idx; ), - (Static, + (Local, return ea == eb; ), - (Return, - return true; + (Static, + return ea == eb; ), (Field, if( *ea.val != *eb.val ) @@ -486,10 +477,8 @@ namespace MIR { ), (ScopeEnd, os << "ScopeEnd("; - for(auto idx : e.vars) - os << "var$" << idx << ","; - for(auto idx : e.tmps) - os << "tmp$" << idx << ","; + for(auto idx : e.slots) + os << "_$" << idx << ","; os << ")"; ) ) @@ -500,11 +489,10 @@ namespace MIR { ::MIR::LValue MIR::LValue::clone() const { TU_MATCHA( (*this), (e), - (Variable, return LValue(e); ), - (Temporary, return LValue(e); ), + (Return, return LValue(e); ), (Argument, return LValue(e); ), + (Local, return LValue(e); ), (Static, return LValue(e.clone()); ), - (Return, return LValue(e); ), (Field, return LValue::make_Field({ box$( e.val->clone() ), e.field_index diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index c22f8d5d..6254bf42 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -17,21 +17,15 @@ typedef unsigned int RegionId; typedef unsigned int BasicBlockId; // "LVALUE" - Assignable values -TAGGED_UNION_EX(LValue, (), Variable, ( - // User-named variable - (Variable, unsigned int), - // Temporary with no user-defined name - (Temporary, struct { - unsigned int idx; - }), - // Function argument (matters for destructuring) - (Argument, struct { - unsigned int idx; - }), - // `static` or `static mut` - (Static, ::HIR::Path), +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, ::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 { @@ -274,8 +268,7 @@ TAGGED_UNION(Statement, Assign, unsigned int flag_idx; // Valid if != ~0u }), (ScopeEnd, struct { - ::std::vector vars; - ::std::vector tmps; + ::std::vector slots; }) ); extern ::std::ostream& operator<<(::std::ostream& os, const Statement& x); @@ -290,9 +283,8 @@ struct BasicBlock class Function { public: - // TODO: Unify Variables, Temporaries, and Arguments - ::std::vector< ::HIR::TypeRef> named_variables; - ::std::vector< ::HIR::TypeRef> temporaries; + ::std::vector< ::HIR::TypeRef> locals; + //::std::vector< ::std::string> local_names; ::std::vector drop_flags; ::std::vector blocks; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index f03dc40f..5ace0bb0 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -26,21 +26,20 @@ MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const } set_cur_block( new_bb_unlinked() ); - m_scopes.push_back( ScopeDef { sp } ); + m_scopes.push_back( ScopeDef { sp, ScopeType::make_Owning({ false, {} }) } ); m_scope_stack.push_back( 0 ); - m_scopes.push_back( ScopeDef { sp, ScopeType::make_Temporaries({}) } ); + m_scopes.push_back( ScopeDef { sp, ScopeType::make_Owning({ true, {} }) } ); m_scope_stack.push_back( 1 ); - - m_if_cond_lval = this->new_temporary(::HIR::CoreType::Bool); - m_arg_states.reserve( args.size() ); - for(size_t i = 0; i < args.size(); i ++ ) + for(size_t i = 0; i < args.size(); i ++) m_arg_states.push_back( VarState::make_Valid({}) ); - m_variable_states.reserve( output.named_variables.size() ); - for(size_t i = 0; i < output.named_variables.size(); i ++ ) - m_variable_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); + m_slot_states.resize( output.locals.size() ); + m_first_temp_idx = output.locals.size(); + DEBUG("First temporary will be " << m_first_temp_idx); + + m_if_cond_lval = this->new_temporary(::HIR::CoreType::Bool); } MirBuilder::~MirBuilder() { @@ -85,18 +84,21 @@ const ::HIR::TypeRef* MirBuilder::is_type_owned_box(const ::HIR::TypeRef& ty) co void MirBuilder::define_variable(unsigned int idx) { - DEBUG("DEFINE var" << idx << ": " << m_output.named_variables.at(idx)); + DEBUG("DEFINE (var) _" << idx << ": " << m_output.locals.at(idx)); for( auto scope_idx : ::reverse(m_scope_stack) ) { auto& scope_def = m_scopes.at(scope_idx); TU_MATCH_DEF( ScopeType, (scope_def.data), (e), ( ), - (Variables, - auto it = ::std::find(e.vars.begin(), e.vars.end(), idx); - assert(it == e.vars.end()); - e.vars.push_back( idx ); - return ; + (Owning, + if( !e.is_temporary ) + { + auto it = ::std::find(e.slots.begin(), e.slots.end(), idx); + assert(it == e.slots.end()); + e.slots.push_back( idx ); + return ; + } ), (Split, BUG(Span(), "Variable " << idx << " introduced within a Split"); @@ -107,20 +109,24 @@ void MirBuilder::define_variable(unsigned int idx) } ::MIR::LValue MirBuilder::new_temporary(const ::HIR::TypeRef& ty) { - unsigned int rv = m_output.temporaries.size(); - DEBUG("DEFINE tmp" << rv << ": " << ty); + unsigned int rv = m_output.locals.size(); + DEBUG("DEFINE (temp) _" << rv << ": " << ty); - m_output.temporaries.push_back( ty.clone() ); - m_temporary_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); - assert(m_output.temporaries.size() == m_temporary_states.size()); + assert(m_output.locals.size() == m_slot_states.size()); + m_output.locals.push_back( ty.clone() ); + m_slot_states.push_back( VarState::make_Invalid(InvalidType::Uninit) ); + assert(m_output.locals.size() == m_slot_states.size()); ScopeDef* top_scope = nullptr; for(unsigned int i = m_scope_stack.size(); i --; ) { auto idx = m_scope_stack[i]; - if( m_scopes.at( idx ).data.is_Temporaries() ) { - top_scope = &m_scopes.at(idx); - break ; + if( const auto* e = m_scopes.at( idx ).data.opt_Owning() ) { + if( e->is_temporary ) + { + top_scope = &m_scopes.at(idx); + break ; + } } else if( m_scopes.at(idx).data.is_Loop() ) { @@ -140,9 +146,10 @@ void MirBuilder::define_variable(unsigned int idx) } } assert( top_scope ); - auto& tmp_scope = top_scope->data.as_Temporaries(); - tmp_scope.temporaries.push_back( rv ); - return ::MIR::LValue::make_Temporary({rv}); + 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); } ::MIR::LValue MirBuilder::lvalue_or_temp(const Span& sp, const ::HIR::TypeRef& ty, ::MIR::RValue val) { @@ -151,7 +158,7 @@ void MirBuilder::define_variable(unsigned int idx) ) else { auto temp = new_temporary(ty); - push_stmt_assign( sp, ::MIR::LValue(temp.as_Temporary()), mv$(val) ); + push_stmt_assign( sp, temp.clone(), mv$(val) ); return temp; } } @@ -378,26 +385,12 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) TU_MATCH_DEF(::MIR::LValue, (dst), (e), ( ), - (Temporary, - state_p = &get_temp_state_mut(sp, e.idx); - if( const auto* se = state_p->opt_Invalid() ) - { - if( *se != InvalidType::Uninit ) { - BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p); - } - } - else { - // TODO: This should be a bug, but some of the match code ends up reassigning so.. - //BUG(sp, "Reassigning temporary " << e.idx << " - " << *state_p); - } - ), (Return, // Don't drop. // No state tracking for the return value ), - (Variable, - // TODO: Ensure that slot is mutable (information is lost, assume true) - state_p = &get_variable_state_mut(sp, e); + (Local, + state_p = &get_slot_state_mut(sp, e); ) ) @@ -411,7 +404,7 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) } } -void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const ScopeHandle& scope, bool to_above/*=false*/) +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), @@ -422,29 +415,32 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const // 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_variables(sp, *e.val, scope, to_above); - raise_variables(sp, *e.idx, scope, to_above); + raise_temporaries(sp, *e.val, scope, to_above); + raise_temporaries(sp, *e.idx, scope, to_above); return ; ), (Deref, - raise_variables(sp, *e.val, scope, to_above); + raise_temporaries(sp, *e.val, scope, to_above); return ; ), (Field, - raise_variables(sp, *e.val, scope, to_above); + raise_temporaries(sp, *e.val, scope, to_above); return ; ), (Downcast, - raise_variables(sp, *e.val, scope, to_above); + raise_temporaries(sp, *e.val, scope, to_above); return ; ), // Actual value types - (Variable, - ), - (Temporary, + (Local, ) ) - ASSERT_BUG(sp, val.is_Variable() || val.is_Temporary(), "Hit value raising code with non-variable value - " << val); + ASSERT_BUG(sp, val.is_Local(), "Hit value raising code with non-variable value - " << val); + const auto idx = val.as_Local(); + bool is_temp = (idx < m_first_temp_idx); + if( idx < m_first_temp_idx ) { + return ; + } // Find controlling scope auto scope_it = m_scope_stack.rbegin(); @@ -457,30 +453,20 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const DEBUG(val << " defined in or above target (scope " << scope << ")"); } - TU_IFLET( ScopeType, scope_def.data, Variables, e, - if( const auto* ve = val.opt_Variable() ) + TU_IFLET( ScopeType, scope_def.data, Owning, e, + if( e.is_temporary == is_temp ) { - auto idx = *ve; - auto tmp_it = ::std::find( e.vars.begin(), e.vars.end(), idx ); - if( tmp_it != e.vars.end() ) + auto tmp_it = ::std::find(e.slots.begin(), e.slots.end(), idx); + if( tmp_it != e.slots.end() ) { - e.vars.erase( tmp_it ); - DEBUG("Raise variable " << idx << " from " << *scope_it); + e.slots.erase( tmp_it ); + DEBUG("Raise slot " << idx << " from " << *scope_it); break ; } } - ) - else TU_IFLET( ScopeType, scope_def.data, Temporaries, e, - if( const auto* ve = val.opt_Temporary() ) + else { - auto idx = ve->idx; - auto tmp_it = ::std::find( e.temporaries.begin(), e.temporaries.end(), idx ); - if( tmp_it != e.temporaries.end() ) - { - e.temporaries.erase( tmp_it ); - DEBUG("Raise temporary " << idx << " from " << *scope_it); - break ; - } + // TODO: Should this care about variables? } ) else @@ -536,26 +522,12 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const target_seen = true; } - TU_IFLET( ScopeType, scope_def.data, Variables, e, - if( target_seen ) - { - if( const auto* ve = val.opt_Variable() ) - { - e.vars.push_back( *ve ); - DEBUG("- to " << *scope_it); - return ; - } - } - ) - else TU_IFLET( ScopeType, scope_def.data, Temporaries, e, - if( target_seen ) + TU_IFLET( ScopeType, scope_def.data, Owning, e, + if( target_seen && e.is_temporary == is_temp ) { - if( const auto* ve = val.opt_Temporary() ) - { - e.temporaries.push_back( ve->idx ); - DEBUG("- to " << *scope_it); - return ; - } + e.slots.push_back( idx ); + DEBUG("- to " << *scope_it); + return ; } ) else if( auto* sd_loop = scope_def.data.opt_Loop() ) @@ -566,19 +538,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const if( sd_loop->exit_state_valid ) { DEBUG("Adding " << val << " as unset to loop exit state"); - if( const auto* ve = val.opt_Variable() ) - { - auto v = sd_loop->exit_state.var_states.insert( ::std::make_pair(*ve, VarState(InvalidType::Uninit)) ); - ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); - } - else if( const auto* ve = val.opt_Temporary() ) - { - auto v = sd_loop->exit_state.tmp_states.insert( ::std::make_pair(ve->idx, VarState(InvalidType::Uninit)) ); - ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); - } - else { - BUG(sp, "Impossible raise value"); - } + auto v = sd_loop->exit_state.states.insert( ::std::make_pair(idx, VarState(InvalidType::Uninit)) ); + ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); } else { @@ -592,19 +553,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const if( sd_split->end_state_valid ) { DEBUG("Adding " << val << " as unset to loop exit state"); - if( const auto* ve = val.opt_Variable() ) - { - auto v = sd_split->end_state.var_states.insert( ::std::make_pair(*ve, VarState(InvalidType::Uninit)) ); - ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); - } - else if( const auto* ve = val.opt_Temporary() ) - { - auto v = sd_split->end_state.tmp_states.insert( ::std::make_pair(ve->idx, VarState(InvalidType::Uninit)) ); - ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); - } - else { - BUG(sp, "Impossible raise value"); - } + auto v = sd_split->end_state.states.insert( ::std::make_pair(idx, VarState(InvalidType::Uninit)) ); + ASSERT_BUG(sp, v.second, "Raising " << val << " which already had a state entry"); } else { @@ -613,20 +563,8 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const // TODO: This should update the outer state to unset. auto& arm = sd_split->arms.back(); - if( const auto* ve = val.opt_Variable() ) - { - arm.var_states.insert(::std::make_pair( *ve, get_variable_state(sp, *ve).clone() )); - m_variable_states.at(*ve) = VarState(InvalidType::Uninit); - } - else if( const auto* ve = val.opt_Temporary() ) - { - arm.tmp_states.insert(::std::make_pair( ve->idx, get_temp_state(sp, ve->idx).clone() )); - m_temporary_states.at(ve->idx) = VarState(InvalidType::Uninit); - } - else - { - BUG(sp, "Impossible raise value"); - } + arm.states.insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )); + m_slot_states.at(idx) = VarState(InvalidType::Uninit); } else { @@ -635,15 +573,15 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::LValue& val, const } BUG(sp, "Couldn't find a scope to raise " << val << " into"); } -void MirBuilder::raise_variables(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above/*=false*/) +void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::RValue& rval, const ScopeHandle& scope, bool to_above/*=false*/) { auto raise_vars = [&](const ::MIR::Param& p) { if( const auto* e = p.opt_LValue() ) - this->raise_variables(sp, *e, scope, to_above); + this->raise_temporaries(sp, *e, scope, to_above); }; TU_MATCHA( (rval), (e), (Use, - this->raise_variables(sp, e, scope, to_above); + this->raise_temporaries(sp, e, scope, to_above); ), (Constant, ), @@ -652,23 +590,23 @@ void MirBuilder::raise_variables(const Span& sp, const ::MIR::RValue& rval, cons ), (Borrow, // TODO: Wait, is this valid? - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (Cast, - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (BinOp, raise_vars(e.val_l); raise_vars(e.val_r); ), (UniOp, - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (DstMeta, - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (DstPtr, - this->raise_variables(sp, e.val, scope, to_above); + this->raise_temporaries(sp, e.val, scope, to_above); ), (MakeDst, raise_vars(e.ptr_val); @@ -760,7 +698,7 @@ bool MirBuilder::get_drop_flag_default(const Span& sp, unsigned int idx) ScopeHandle MirBuilder::new_scope_var(const Span& sp) { unsigned int idx = m_scopes.size(); - m_scopes.push_back( ScopeDef {sp, ScopeType::make_Variables({})} ); + m_scopes.push_back( ScopeDef {sp, ScopeType::make_Owning({ false, {} })} ); m_scope_stack.push_back( idx ); DEBUG("START (var) scope " << idx); return ScopeHandle { *this, idx }; @@ -768,7 +706,8 @@ ScopeHandle MirBuilder::new_scope_var(const Span& sp) ScopeHandle MirBuilder::new_scope_temp(const Span& sp) { unsigned int idx = m_scopes.size(); - m_scopes.push_back( ScopeDef {sp, ScopeType::make_Temporaries({})} ); + + m_scopes.push_back( ScopeDef {sp, ScopeType::make_Owning({ true, {} })} ); m_scope_stack.push_back( idx ); DEBUG("START (temp) scope " << idx); return ScopeHandle { *this, idx }; @@ -852,11 +791,13 @@ 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_Temporaries(), "Rasising scopes can only be done on temporaries (source)"); - auto& src_list = src_scope_def.data.as_Temporaries().temporaries; + 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_Temporary({ idx })); + DEBUG("> Raising " << ::MIR::LValue::make_Local(idx)); + assert(idx >= m_first_temp_idx); } // Seek up stack until the target scope is seen @@ -873,7 +814,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle // Insert these values as Invalid, both in the existing exit state, and in the changed list for(auto idx : src_list) { - auto v = sd_loop->exit_state.tmp_states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); + auto v = sd_loop->exit_state.states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); ASSERT_BUG(sp, v.second, ""); } } @@ -884,7 +825,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle for(auto idx : src_list) { - auto v2 = sd_loop->changed_tmps.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); + auto v2 = sd_loop->changed_slots.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); ASSERT_BUG(sp, v2.second, ""); } } @@ -896,7 +837,7 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle // Insert these indexes as Invalid for(auto idx : src_list) { - auto v = sd_split->end_state.tmp_states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); + auto v = sd_split->end_state.states.insert(::std::make_pair( idx, VarState(InvalidType::Uninit) )); ASSERT_BUG(sp, v.second, ""); } } @@ -910,8 +851,8 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle auto& arm = sd_split->arms.back(); for(auto idx : src_list) { - arm.tmp_states.insert(::std::make_pair( idx, mv$(m_temporary_states.at(idx)) )); - m_temporary_states.at(idx) = VarState(InvalidType::Uninit); + arm.states.insert(::std::make_pair( idx, mv$(m_slot_states.at(idx)) )); + m_slot_states.at(idx) = VarState(InvalidType::Uninit); } } } @@ -920,16 +861,17 @@ void MirBuilder::raise_all(const Span& sp, ScopeHandle source, const ScopeHandle BUG(sp, "Moving values to a scope not on the stack - scope " << target.idx); } auto& tgt_scope_def = m_scopes.at(target.idx); - ASSERT_BUG(sp, tgt_scope_def.data.is_Temporaries(), "Rasising scopes can only be done on temporaries (target)"); + ASSERT_BUG(sp, tgt_scope_def.data.is_Owning(), "Rasising scopes can only be done on temporaries (target)"); + ASSERT_BUG(sp, tgt_scope_def.data.as_Owning().is_temporary, "Rasising scopes can only be done on temporaries (target)"); // Move all defined variables from one to the other - auto& tgt_list = tgt_scope_def.data.as_Temporaries().temporaries; + 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_variables(sp, ::MIR::LValue::make_Temporary({ idx }), target); + this->raise_temporaries(sp, ::MIR::LValue::make_Temporary({ idx }), target); } #endif @@ -1388,39 +1330,24 @@ void MirBuilder::terminate_loop_early(const Span& sp, ScopeType::Data_Loop& sd_l { // Insert copies of parent state for newly changed values // and Merge all changed values - for(const auto& ent : sd_loop.changed_vars) - { - auto idx = ent.first; - if( sd_loop.exit_state.var_states.count(idx) == 0 ) { - sd_loop.exit_state.var_states.insert(::std::make_pair( idx, ent.second.clone() )); - } - auto& old_state = sd_loop.exit_state.var_states.at(idx); - merge_state(sp, *this, ::MIR::LValue::make_Variable(idx), old_state, get_variable_state(sp, idx)); - } - for(const auto& ent : sd_loop.changed_tmps) + for(const auto& ent : sd_loop.changed_slots) { auto idx = ent.first; - if( sd_loop.exit_state.tmp_states.count(idx) == 0 ) { - sd_loop.exit_state.tmp_states.insert(::std::make_pair( idx, ent.second.clone() )); + if( sd_loop.exit_state.states.count(idx) == 0 ) { + sd_loop.exit_state.states.insert(::std::make_pair( idx, ent.second.clone() )); } - auto& old_state = sd_loop.exit_state.tmp_states.at(idx); - merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), old_state, get_temp_state(sp, idx)); + auto& old_state = sd_loop.exit_state.states.at(idx); + merge_state(sp, *this, ::MIR::LValue::make_Local(idx), old_state, get_slot_state(sp, idx)); } } else { // Obtain states of changed variables/temporaries - for(const auto& ent : sd_loop.changed_vars) + for(const auto& ent : sd_loop.changed_slots) { - DEBUG("Variable(" << ent.first << ") = " << ent.second); + DEBUG("Slot(" << ent.first << ") = " << ent.second); auto idx = ent.first; - sd_loop.exit_state.var_states.insert(::std::make_pair( idx, get_variable_state(sp, idx).clone() )); - } - for(const auto& ent : sd_loop.changed_tmps) - { - DEBUG("Temporary(" << ent.first << ") = " << ent.second); - auto idx = ent.first; - sd_loop.exit_state.tmp_states.insert(::std::make_pair( idx, get_temp_state(sp, idx).clone() )); + sd_loop.exit_state.states.insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )); } sd_loop.exit_state_valid = true; } @@ -1446,39 +1373,23 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r if( reachable ) { // Insert copies of the parent state - for(const auto& ent : this_arm_state.var_states) { - if( sd_split.end_state.var_states.count(ent.first) == 0 ) { - sd_split.end_state.var_states.insert(::std::make_pair( ent.first, get_variable_state(sp, ent.first, 1).clone() )); - } - } - for(const auto& ent : this_arm_state.tmp_states) { - if( sd_split.end_state.tmp_states.count(ent.first) == 0 ) { - sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, get_temp_state(sp, ent.first, 1).clone() )); + for(const auto& ent : this_arm_state.states) { + if( sd_split.end_state.states.count(ent.first) == 0 ) { + sd_split.end_state.states.insert(::std::make_pair( ent.first, get_slot_state(sp, ent.first, 1).clone() )); } } // Merge state - for(auto& ent : sd_split.end_state.var_states) - { - auto idx = ent.first; - auto& out_state = ent.second; - - // Merge the states - auto it = this_arm_state.var_states.find(idx); - const auto& src_state = (it != this_arm_state.var_states.end() ? it->second : get_variable_state(sp, idx, 1)); - - merge_state(sp, *this, ::MIR::LValue::make_Variable(idx), out_state, src_state); - } - for(auto& ent : sd_split.end_state.tmp_states) + for(auto& ent : sd_split.end_state.states) { auto idx = ent.first; auto& out_state = ent.second; // Merge the states - auto it = this_arm_state.tmp_states.find(idx); - const auto& src_state = (it != this_arm_state.tmp_states.end() ? it->second : get_temp_state(sp, idx, 1)); + auto it = this_arm_state.states.find(idx); + const auto& src_state = (it != this_arm_state.states.end() ? it->second : get_slot_state(sp, idx, 1)); - merge_state(sp, *this, ::MIR::LValue::make_Temporary({idx}), out_state, src_state); + merge_state(sp, *this, ::MIR::LValue::make_Local(idx), out_state, src_state); } } else @@ -1489,15 +1400,10 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r else { // Clone this arm's state - for(auto& ent : this_arm_state.var_states) - { - DEBUG("Variable(" << ent.first << ") = " << ent.second); - sd_split.end_state.var_states.insert(::std::make_pair( ent.first, ent.second.clone() )); - } - for(auto& ent : this_arm_state.tmp_states) + for(auto& ent : this_arm_state.states) { - DEBUG("Temporary(" << ent.first << ") = " << ent.second); - sd_split.end_state.tmp_states.insert(::std::make_pair( ent.first, ent.second.clone() )); + DEBUG("Slot(" << ent.first << ") = " << ent.second); + sd_split.end_state.states.insert(::std::make_pair( ent.first, ent.second.clone() )); } sd_split.end_state_valid = true; } @@ -1536,11 +1442,8 @@ void MirBuilder::complete_scope(ScopeDef& sd) sd.complete = true; TU_MATCHA( (sd.data), (e), - (Temporaries, - DEBUG("Temporaries - " << e.temporaries); - ), - (Variables, - DEBUG("Variables - " << e.vars); + (Owning, + DEBUG("Owning (" << (e.is_temporary ? "temps" : "vars") << ") - " << e.slots); ), (Loop, DEBUG("Loop"); @@ -1552,21 +1455,12 @@ void MirBuilder::complete_scope(ScopeDef& sd) struct H { static void apply_end_state(const Span& sp, MirBuilder& builder, SplitEnd& end_state) { - for(auto& ent : end_state.var_states) + for(auto& ent : end_state.states) { - auto& vs = builder.get_variable_state_mut(sp, ent.first); + auto& vs = builder.get_slot_state_mut(sp, ent.first); if( vs != ent.second ) { - DEBUG(::MIR::LValue::make_Variable(ent.first) << " " << vs << " => " << ent.second); - vs = ::std::move(ent.second); - } - } - for(auto& ent : end_state.tmp_states) - { - auto& vs = builder.get_temp_state_mut(sp, ent.first); - if( vs != ent.second ) - { - DEBUG(::MIR::LValue::make_Temporary({ent.first}) << " " << vs << " => " << ent.second); + DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } @@ -1596,16 +1490,15 @@ void MirBuilder::complete_scope(ScopeDef& sd) void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std::function cb) const { TU_MATCH(::MIR::LValue, (val), (e), - (Variable, - cb( m_output.named_variables.at(e) ); - ), - (Temporary, - cb( m_output.temporaries.at(e.idx) ); + (Return, + TODO(sp, "Return"); ), (Argument, - ASSERT_BUG(sp, e.idx < m_args.size(), "Argument number out of range"); cb( m_args.at(e.idx).second ); ), + (Local, + cb( m_output.locals.at(e) ); + ), (Static, TU_MATCHA( (e.m_data), (pe), (Generic, @@ -1624,9 +1517,6 @@ void MirBuilder::with_val_type(const Span& sp, const ::MIR::LValue& val, ::std:: ) ) ), - (Return, - TODO(sp, "Return"); - ), (Field, with_val_type(sp, *e.val, [&](const auto& ty){ TU_MATCH_DEF( ::HIR::TypeRef::Data, (ty.m_data), (te), @@ -1821,7 +1711,7 @@ bool MirBuilder::lvalue_is_copy(const Span& sp, const ::MIR::LValue& val) const return rv == 2; } -const VarState& MirBuilder::get_slot_state(const Span& sp, VarGroup ty, unsigned int idx, unsigned int skip_count/*=0*/) const +const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, unsigned int skip_count/*=0*/) const { // 1. Find an applicable Split scope for( auto scope_idx : ::reverse(m_scope_stack) ) @@ -1830,92 +1720,46 @@ const VarState& MirBuilder::get_slot_state(const Span& sp, VarGroup ty, unsigned TU_MATCH_DEF( ScopeType, (scope_def.data), (e), ( ), - (Temporaries, - if( ty == VarGroup::Temporary ) - { - auto it = ::std::find(e.temporaries.begin(), e.temporaries.end(), idx); - if( it != e.temporaries.end() ) { - break ; - } - } - ), - (Variables, - if( ty == VarGroup::Variable ) - { - auto it = ::std::find(e.vars.begin(), e.vars.end(), idx); - if( it != e.vars.end() ) { - // If controlled by this block, exit early (won't find it elsewhere) - break ; - } + (Owning, + auto it = ::std::find(e.slots.begin(), e.slots.end(), idx); + if( it != e.slots.end() ) { + break ; } ), (Split, const auto& cur_arm = e.arms.back(); - if( ty == VarGroup::Variable ) - { - auto it = cur_arm.var_states.find(idx); - if( it != cur_arm.var_states.end() ) - { - if( ! skip_count -- ) - { - return it->second; - } - } - } - else if( ty == VarGroup::Temporary ) + auto it = cur_arm.states.find(idx); + if( it != cur_arm.states.end() ) { - auto it = cur_arm.tmp_states.find(idx); - if( it != cur_arm.tmp_states.end() ) + if( ! skip_count -- ) { - if( ! skip_count -- ) - { - return it->second; - } + return it->second; } } ) ) } - switch(ty) + if( idx == ~0u ) { - case VarGroup::Return: return m_return_state; - case VarGroup::Argument: - ASSERT_BUG(sp, idx < m_arg_states.size(), "Argument " << idx << " out of range for state table"); - return m_arg_states.at(idx); - case VarGroup::Variable: - ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); - return m_variable_states[idx]; - case VarGroup::Temporary: - ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); - return m_temporary_states[idx]; } - BUG(sp, "Fell off the end of get_slot_state"); + else + { + ASSERT_BUG(sp, idx < m_slot_states.size(), "Slot " << idx << " out of range for state table"); + return m_slot_states.at(idx); + } } -VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned int idx) +VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) { VarState* ret = nullptr; for( auto scope_idx : ::reverse(m_scope_stack) ) { auto& scope_def = m_scopes.at(scope_idx); - if( const auto* e = scope_def.data.opt_Variables() ) - { - if( ty == VarGroup::Variable ) - { - auto it = ::std::find(e->vars.begin(), e->vars.end(), idx); - if( it != e->vars.end() ) { - break ; - } - } - } - else if( const auto* e = scope_def.data.opt_Temporaries() ) + if( const auto* e = scope_def.data.opt_Owning() ) { - if( ty == VarGroup::Temporary ) - { - auto it = ::std::find(e->temporaries.begin(), e->temporaries.end(), idx); - if( it != e->temporaries.end() ) { - break ; - } + auto it = ::std::find(e->slots.begin(), e->slots.end(), idx); + if( it != e->slots.end() ) { + break ; } } else if( scope_def.data.is_Split() ) @@ -1924,28 +1768,21 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned i auto& cur_arm = e.arms.back(); if( ! ret ) { - ::std::map* states; - switch(ty) - { - case VarGroup::Return: states = nullptr; break; - case VarGroup::Argument: BUG(sp, "Mutating state of argument"); break; - case VarGroup::Variable: states = &cur_arm.var_states; break; - case VarGroup::Temporary: states = &cur_arm.tmp_states; break; + if( idx == ~0u ) { } - - if( states ) - { + else { + auto* states = &cur_arm.states; auto it = states->find(idx); if( it == states->end() ) { DEBUG("Split new (scope " << scope_idx << ")"); - ret = &( (*states)[idx] = get_slot_state(sp, ty, idx).clone() ); + it = states->insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )).first; } else { DEBUG("Split existing (scope " << scope_idx << ")"); - ret = &it->second; } + ret = &it->second; } } } @@ -1953,19 +1790,15 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned i { auto& e = scope_def.data.as_Loop(); ::std::map* states = nullptr; - switch(ty) + if( idx == ~0u ) { - case VarGroup::Return: states = nullptr; break; - case VarGroup::Argument: BUG(sp, "Mutating state of argument"); break; - case VarGroup::Variable: states = &e.changed_vars; break; - case VarGroup::Temporary: states = &e.changed_tmps; break; } - - if( states ) + else { + states = &e.changed_slots; if( states->count(idx) == 0 ) { - auto state = e.exit_state_valid ? get_slot_state(sp, ty, idx).clone() : VarState::make_Valid({}); + auto state = e.exit_state_valid ? get_slot_state(sp, idx).clone() : VarState::make_Valid({}); states->insert(::std::make_pair( idx, mv$(state) )); } } @@ -1980,39 +1813,16 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, VarGroup ty, unsigned i } else { - switch(ty) + if( idx == ~0u ) { - case VarGroup::Return: return m_return_state; - case VarGroup::Argument: - ASSERT_BUG(sp, idx < m_arg_states.size(), "Argument " << idx << " out of range for state table"); - return m_arg_states.at(idx); - case VarGroup::Variable: - ASSERT_BUG(sp, idx < m_variable_states.size(), "Variable " << idx << " out of range for state table"); - return m_variable_states[idx]; - case VarGroup::Temporary: - ASSERT_BUG(sp, idx < m_temporary_states.size(), "Temporary " << idx << " out of range for state table"); - return m_temporary_states[idx]; } - BUG(sp, "Fell off the end of get_slot_state_mut"); + else + { + return m_slot_states.at(idx); + } } } -const VarState& MirBuilder::get_variable_state(const Span& sp, unsigned int idx, unsigned int skip_count) const -{ - return get_slot_state(sp, VarGroup::Variable, idx, skip_count); -} -VarState& MirBuilder::get_variable_state_mut(const Span& sp, unsigned int idx) -{ - return get_slot_state_mut(sp, VarGroup::Variable, idx); -} -const VarState& MirBuilder::get_temp_state(const Span& sp, unsigned int idx, unsigned int skip_count) const -{ - return get_slot_state(sp, VarGroup::Temporary, idx, skip_count); -} -VarState& MirBuilder::get_temp_state_mut(const Span& sp, unsigned int idx) -{ - return get_slot_state_mut(sp, VarGroup::Temporary, idx); -} const VarState& MirBuilder::get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count) { @@ -2022,22 +1832,20 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) { TRACE_FUNCTION_F(lv); TU_MATCHA( (lv), (e), - (Variable, - return get_slot_state_mut(sp, VarGroup::Variable, e); - ), - (Temporary, - return get_slot_state_mut(sp, VarGroup::Temporary, e.idx); + (Return, + BUG(sp, "Move of return value"); + return get_slot_state_mut(sp, ~0u); ), (Argument, - return get_slot_state_mut(sp, VarGroup::Argument, e.idx); + // NOTE: Only valid outside of split scopes (should only happen at the start) + return m_arg_states.at(e.idx); + ), + (Local, + return get_slot_state_mut(sp, e); ), (Static, BUG(sp, "Attempting to mutate state of a static"); ), - (Return, - BUG(sp, "Move of return value"); - return get_slot_state_mut(sp, VarGroup::Return, 0); - ), (Field, auto& ivs = get_val_state_mut(sp, *e.val); VarState tpl; @@ -2117,13 +1925,10 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) this->push_stmt_assign(sp, inner_lv.clone(), ::MIR::RValue( mv$(*e.val) )); *e.val = inner_lv.clone(); ), - (Variable, + (Argument, inner_lv = ::MIR::LValue(ei); ), - (Temporary, - inner_lv = ::MIR::LValue(ei); - ), - (Argument, + (Local, inner_lv = ::MIR::LValue(ei); ) ) @@ -2252,20 +2057,12 @@ void MirBuilder::drop_value_from_state(const Span& sp, const VarState& vs, ::MIR void MirBuilder::drop_scope_values(const ScopeDef& sd) { TU_MATCHA( (sd.data), (e), - (Temporaries, - for(auto tmp_idx : ::reverse(e.temporaries)) - { - const auto& vs = get_temp_state(sd.span, tmp_idx); - DEBUG("tmp" << tmp_idx << " - " << vs); - drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Temporary({ tmp_idx }) ); - } - ), - (Variables, - for(auto var_idx : ::reverse(e.vars)) + (Owning, + for(auto idx : ::reverse(e.slots)) { - const auto& vs = get_variable_state(sd.span, var_idx); - DEBUG("var" << var_idx << " - " << vs); - drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Variable(var_idx) ); + const auto& vs = get_slot_state(sd.span, idx); + DEBUG("slot" << idx << " - " << vs); + drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Local(idx) ); } ), (Split, diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 8e350c45..6837eab6 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -20,6 +20,7 @@ #define DUMP_BEFORE_ALL 0 #define DUMP_BEFORE_CONSTPROPAGATE 0 #define CHECK_AFTER_PASS 0 +#define CHECK_AFTER_ALL 0 #define DUMP_AFTER_DONE 0 #define CHECK_AFTER_DONE 1 @@ -59,16 +60,14 @@ namespace { if( cb(lv, u) ) return true; TU_MATCHA( (lv), (e), - (Variable, + (Return, ), (Argument, ), - (Temporary, + (Local, ), (Static, ), - (Return, - ), (Field, return visit_mir_lvalue_mut(*e.val, u, cb); ), @@ -473,6 +472,9 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // >> Apply known constants change_happened |= MIR_Optimise_ConstPropagte(state, fcn); + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif // >> Inline short functions bool inline_happened = MIR_Optimise_Inlining(state, fcn); @@ -483,18 +485,27 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path //MIR_Dump_Fcn(::std::cout, fcn); change_happened = true; } + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif // TODO: Convert `&mut *mut_foo` into `mut_foo` if the source is movable and not used afterwards // >> Propagate/remove dead assignments while( MIR_Optimise_PropagateSingleAssignments(state, fcn) ) change_happened = true; + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); // >> Unify duplicate temporaries // If two temporaries don't overlap in lifetime (blocks in which they're valid), unify the two change_happened |= MIR_Optimise_UnifyTemporaries(state, fcn); + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif // >> Combine Duplicate Blocks change_happened |= MIR_Optimise_UnifyBlocks(state, fcn); @@ -553,12 +564,9 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn) auto& dst = (it-1)->as_ScopeEnd(); const auto& src = it->as_ScopeEnd(); DEBUG("Unify " << *(it-1) << " and " << *it); - for(auto v : src.vars) - dst.vars.push_back(v); - for(auto v : src.tmps) - dst.tmps.push_back(v); - ::std::sort(dst.vars.begin(), dst.vars.end()); - ::std::sort(dst.tmps.begin(), dst.tmps.end()); + for(auto v : src.slots) + dst.slots.push_back(v); + ::std::sort(dst.slots.begin(), dst.slots.end()); it = block.statements.erase(it); } else @@ -824,12 +832,9 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) ), (ScopeEnd, ::MIR::Statement::Data_ScopeEnd new_se; - new_se.vars.reserve(se.vars.size()); - for(auto idx : se.vars) - new_se.vars.push_back(this->var_base + idx); - new_se.tmps.reserve(se.tmps.size()); - for(auto idx : se.tmps) - new_se.tmps.push_back(this->tmp_base + idx); + new_se.slots.reserve(se.slots.size()); + for(auto idx : se.slots) + new_se.slots.push_back(this->var_base + idx); rv.statements.push_back(::MIR::Statement( mv$(new_se) )); ) ) @@ -922,23 +927,24 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) ::MIR::LValue clone_lval(const ::MIR::LValue& src) const { TU_MATCHA( (src), (se), - (Variable, - return ::MIR::LValue::make_Variable(se + this->var_base); - ), - (Temporary, - return ::MIR::LValue::make_Temporary({se.idx + this->tmp_base}); + (Return, + return this->te.ret_val.clone(); ), (Argument, const auto& arg = this->te.args.at(se.idx); - if( const auto* e = arg.opt_Constant() ) { - auto tmp = ::MIR::LValue::make_Temporary({ static_cast(this->tmp_end + this->const_assignments.size()) }); + if( const auto* e = arg.opt_Constant() ) + { + auto tmp = ::MIR::LValue::make_Local( static_cast(this->tmp_end + this->const_assignments.size()) ); this->const_assignments.push_back( e->clone() ); return tmp; } - return arg.as_LValue().clone(); + else + { + return arg.as_LValue().clone(); + } ), - (Return, - return this->te.ret_val.clone(); + (Local, + return ::MIR::LValue::make_Local(this->var_base + se); ), (Static, return this->monomorph( se ); @@ -983,8 +989,8 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) { TU_MATCHA( (src), (se), (LValue, - if( se.is_Argument() ) - return this->te.args.at(se.as_Argument().idx).clone(); + if( const auto* ae = se.opt_Argument() ) + return this->te.args.at(ae->idx).clone(); return clone_lval(se); ), (Constant, return clone_constant(se); ) @@ -995,8 +1001,8 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) { TU_MATCHA( (src), (se), (Use, - if( se.is_Argument() ) - if( const auto* e = this->te.args.at(se.as_Argument().idx).opt_Constant() ) + if( const auto* ae = se.opt_Argument() ) + if( const auto* e = this->te.args.at(ae->idx).opt_Constant() ) return e->clone(); return ::MIR::RValue( this->clone_lval(se) ); ), @@ -1072,13 +1078,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) TRACE_FUNCTION_F("Inline " << path); // Monomorph values and append - cloner.var_base = fcn.named_variables.size(); - for(const auto& ty : called_mir->named_variables) - fcn.named_variables.push_back( cloner.monomorph(ty) ); - cloner.tmp_base = fcn.temporaries.size(); - for(const auto& ty : called_mir->temporaries) - fcn.temporaries.push_back( cloner.monomorph(ty) ); - cloner.tmp_end = fcn.temporaries.size(); + cloner.var_base = fcn.locals.size(); + for(const auto& ty : called_mir->locals) + fcn.locals.push_back( cloner.monomorph(ty) ); + cloner.tmp_end = fcn.locals.size(); cloner.df_base = fcn.drop_flags.size(); fcn.drop_flags.insert( fcn.drop_flags.end(), called_mir->drop_flags.begin(), called_mir->drop_flags.end() ); cloner.bb_base = fcn.blocks.size(); @@ -1094,8 +1097,8 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) for(auto& val : cloner.const_assignments) { auto ty = state.get_const_type(val); - auto lv = ::MIR::LValue::make_Temporary({ static_cast(fcn.temporaries.size()) }); - fcn.temporaries.push_back( mv$(ty) ); + auto lv = ::MIR::LValue::make_Local( static_cast(fcn.locals.size()) ); + fcn.locals.push_back( mv$(ty) ); new_blocks[0].statements.insert( new_blocks[0].statements.begin(), ::MIR::Statement::make_Assign({ mv$(lv), mv$(val) }) ); } cloner.const_assignments.clear(); @@ -1120,19 +1123,19 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn) { TRACE_FUNCTION; - ::std::vector replacable( fcn.temporaries.size() ); + ::std::vector replacable( fcn.locals.size() ); // 1. Enumerate which (if any) temporaries share the same type { unsigned int n_found = 0; - for(unsigned int tmpidx = 0; tmpidx < fcn.temporaries.size(); tmpidx ++) + for(unsigned int tmpidx = 0; tmpidx < fcn.locals.size(); tmpidx ++) { if( replacable[tmpidx] ) continue ; - for(unsigned int i = tmpidx+1; i < fcn.temporaries.size(); i ++ ) + for(unsigned int i = tmpidx+1; i < fcn.locals.size(); i ++ ) { if( replacable[i] ) continue ; - if( fcn.temporaries[i] == fcn.temporaries[tmpidx] ) + if( fcn.locals[i] == fcn.locals[tmpidx] ) { replacable[i] = true; replacable[tmpidx] = true; @@ -1145,34 +1148,33 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f } auto lifetimes = MIR_Helper_GetLifetimes(state, fcn, /*dump_debug=*/true); - //::std::vector<::MIR::ValueLifetime> var_lifetimes = mv$(lifetimes.m_variables); - ::std::vector<::MIR::ValueLifetime> tmp_lifetimes = mv$(lifetimes.m_temporaries); + ::std::vector<::MIR::ValueLifetime> slot_lifetimes = mv$(lifetimes.m_slots); // 2. Unify variables of the same type with distinct non-overlapping lifetimes ::std::map replacements; - ::std::vector visited( fcn.temporaries.size() ); + ::std::vector visited( fcn.locals.size() ); bool replacement_needed = false; - for(unsigned int tmpidx = 0; tmpidx < fcn.temporaries.size(); tmpidx ++) + for(unsigned int local_idx = 0; local_idx < fcn.locals.size(); local_idx ++) { - if( ! replacable[tmpidx] ) continue ; - if( visited[tmpidx] ) continue ; - if( ! tmp_lifetimes[tmpidx].is_used() ) continue ; - visited[tmpidx] = true; + if( ! replacable[local_idx] ) continue ; + if( visited[local_idx] ) continue ; + if( ! slot_lifetimes[local_idx].is_used() ) continue ; + visited[local_idx] = true; - for(unsigned int i = tmpidx+1; i < fcn.temporaries.size(); i ++) + for(unsigned int i = local_idx+1; i < fcn.locals.size(); i ++) { if( !replacable[i] ) continue ; - if( fcn.temporaries[i] != fcn.temporaries[tmpidx] ) + if( fcn.locals[i] != fcn.locals[local_idx] ) continue ; - if( ! tmp_lifetimes[i].is_used() ) + if( ! slot_lifetimes[i].is_used() ) continue ; // Variables are of the same type, check if they overlap - if( tmp_lifetimes[tmpidx].overlaps( tmp_lifetimes[i] ) ) + if( slot_lifetimes[local_idx].overlaps( slot_lifetimes[i] ) ) continue ; // They don't overlap, unify - tmp_lifetimes[tmpidx].unify( tmp_lifetimes[i] ); - replacements[i] = tmpidx; + slot_lifetimes[local_idx].unify( slot_lifetimes[i] ); + replacements[i] = local_idx; replacement_needed = true; visited[i] = true; } @@ -1182,12 +1184,12 @@ 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_Temporary() ) { - auto it = replacements.find(ve->idx); + if( auto* ve = lv.opt_Local() ) { + auto it = replacements.find(*ve); if( it != replacements.end() ) { - MIR_DEBUG(state, lv << " => Temporary(" << it->second << ")"); - ve->idx = it->second; + MIR_DEBUG(state, lv << " => Local(" << it->second << ")"); + *ve = it->second; return true; } } @@ -1249,9 +1251,7 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) return false; ), (ScopeEnd, - if( ae.vars != be.vars ) - return false; - if( ae.tmps == be.tmps ) + if( ae.slots != be.slots ) return false; ) ) @@ -1721,7 +1721,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) // - Locate `temp = SOME_CONST` and record value if( const auto* e = stmt.opt_Assign() ) { - if( e->dst.is_Temporary() || e->dst.is_Variable() ) + if( e->dst.is_Local() ) { if( const auto* ce = e->src.opt_Constant() ) { @@ -1743,9 +1743,7 @@ bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn) const auto& te = bb.terminator.as_If(); // Restrict condition to being a temporary/variable - if( te.cond.is_Temporary() ) - ; - else if( te.cond.is_Argument() ) + if( te.cond.is_Local() ) ; else continue; @@ -1813,24 +1811,16 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F unsigned int borrow = 0; }; struct { - ::std::vector var_uses; - ::std::vector tmp_uses; + ::std::vector local_uses; void use_lvalue(const ::MIR::LValue& lv, ValUsage ut) { TU_MATCHA( (lv), (e), - (Variable, - auto& vu = var_uses[e]; - switch(ut) - { - case ValUsage::Read: vu.read += 1; break; - case ValUsage::Write: vu.write += 1; break; - case ValUsage::Borrow: vu.borrow += 1; break; - } + (Return, ), (Argument, ), - (Temporary, - auto& vu = tmp_uses[e.idx]; + (Local, + auto& vu = local_uses[e]; switch(ut) { case ValUsage::Read: vu.read += 1; break; @@ -1840,8 +1830,6 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F ), (Static, ), - (Return, - ), (Field, use_lvalue(*e.val, ut); ), @@ -1858,8 +1846,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F ) } } val_uses = { - ::std::vector(fcn.named_variables.size()), - ::std::vector(fcn.temporaries.size()) + ::std::vector(fcn.locals.size()) }; visit_mir_lvalues(state, fcn, [&](const auto& lv, auto ut){ val_uses.use_lvalue(lv, ut); return false; }); @@ -1886,19 +1873,10 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F continue ; const auto& e = stmt.as_Assign(); // > Of a temporary from with a RValue::Use - if( const auto* de = e.dst.opt_Temporary() ) + if( const auto* de = e.dst.opt_Local() ) { - const auto& vu = val_uses.tmp_uses[de->idx]; - DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write); - // TODO: Allow write many? - // > Where the temporary is written once and read once - if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) ) - continue ; - } - else if( const auto* de = e.dst.opt_Variable() ) - { - const auto& vu = val_uses.var_uses[*de]; - DEBUG(e.dst << " - VU " << e.dst << " R:" << vu.read << " W:" << vu.write); + const auto& vu = val_uses.local_uses[*de]; + DEBUG(e.dst << " - 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 ) ) @@ -1915,7 +1893,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F const auto* srcp = &e.src.as_Use(); while( srcp->is_Field() ) srcp = &*srcp->as_Field().val; - if( !( srcp->is_Temporary() || srcp->is_Variable() || srcp->is_Argument() ) ) + if( !srcp->is_Local() ) continue ; if( replacements.find(*srcp) != replacements.end() ) @@ -2030,6 +2008,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F } // for(stmt : block.statements) } + // Apply replacements within replacements for(;;) { unsigned int inner_replaced_count = 0; @@ -2131,9 +2110,9 @@ 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_Temporary() ) { - const auto& vu = val_uses.tmp_uses[e->idx]; - if( !( vu.read == 1 && vu.write == 1 ) ) + if( const auto* e = to_replace_lval.opt_Local() ) { + const auto& vu = val_uses.local_uses[*e]; + if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) ) continue ; } else { @@ -2201,10 +2180,9 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F { // TODO: What if the destination located here is a 1:1 and its usage is listed to be replaced by the return value. auto& e = block.terminator.as_Call(); - // TODO: Support variables too? - if( !e.ret_val.is_Temporary() ) + if( !e.ret_val.is_Local() ) continue ; - const auto& vu = val_uses.tmp_uses[e.ret_val.as_Temporary().idx]; + const auto& vu = val_uses.local_uses[e.ret_val.as_Local()]; if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) ) continue ; @@ -2261,19 +2239,12 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de), ( ), - (Variable, - const auto& vu = val_uses.var_uses[de]; + (Local, + const auto& vu = val_uses.local_uses[de]; if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) { DEBUG(se->dst << " only written, removing write"); it = block.statements.erase(it)-1; } - ), - (Temporary, - const auto& vu = val_uses.tmp_uses[de.idx]; - if( vu.write == 1 && vu.read == 0 && vu.borrow == 0 ) { - DEBUG(se->dst << " only written, removing write with " << se->src); - it = block.statements.erase(it)-1; - } ) ) } @@ -2355,8 +2326,7 @@ bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Funct // -------------------------------------------------------------------- bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn) { - ::std::vector used_temps( fcn.temporaries.size() ); - ::std::vector used_vars( fcn.named_variables.size() ); + ::std::vector used_locals( fcn.locals.size() ); ::std::vector used_dfs( fcn.drop_flags.size() ); ::std::vector visited( fcn.blocks.size() ); @@ -2364,10 +2334,8 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn visited[bb] = true; auto assigned_lval = [&](const ::MIR::LValue& lv) { - if(const auto* le = lv.opt_Temporary() ) - used_temps[le->idx] = true; - if(const auto* le = lv.opt_Variable() ) - used_vars[*le] = true; + if(const auto* le = lv.opt_Local() ) + used_locals[*le] = true; }; for(const auto& stmt : block.statements) @@ -2404,42 +2372,28 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn { block_rewrite_table.push_back( visited[i] ? j ++ : ~0u ); } - ::std::vector temp_rewrite_table; - unsigned int n_temp = fcn.temporaries.size(); - for(unsigned int i = 0, j = 0; i < n_temp; i ++) + ::std::vector local_rewrite_table; + unsigned int n_locals = fcn.locals.size(); + for(unsigned int i = 0, j = 0; i < n_locals; i ++) { - if( !used_temps[i] ) + if( !used_locals[i] ) { - fcn.temporaries.erase(fcn.temporaries.begin() + j); + fcn.locals.erase(fcn.locals.begin() + j); } else { - DEBUG("tmp$" << i << " => tmp$" << j); + DEBUG("_" << i << " => _" << j); } - temp_rewrite_table.push_back( used_temps[i] ? j ++ : ~0u ); + local_rewrite_table.push_back( used_locals[i] ? j ++ : ~0u ); } - DEBUG("Deleted Temporaries:" << FMT_CB(ss, - for(auto run : runs(used_temps)) - if( !used_temps[run.first] ) + DEBUG("Deleted Locals:" << FMT_CB(ss, + for(auto run : runs(used_locals)) + if( !used_locals[run.first] ) { ss << " " << run.first; if(run.second != run.first) ss << "-" << run.second; } )); - ::std::vector var_rewrite_table; - unsigned int n_var = fcn.named_variables.size(); - for(unsigned int i = 0, j = 0; i < n_var; i ++) - { - if( !used_vars[i] ) - { - DEBUG("GC Variable(" << i << ")"); - fcn.named_variables.erase(fcn.named_variables.begin() + j); - } - else { - DEBUG("var$" << i << " => var$" << j); - } - var_rewrite_table.push_back( used_vars[i] ? j ++ : ~0u ); - } ::std::vector df_rewrite_table; unsigned int n_df = fcn.drop_flags.size(); for(unsigned int i = 0, j = 0; i < n_df; i ++) @@ -2464,17 +2418,11 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn else { auto lvalue_cb = [&](auto& lv, auto ) { - if(auto* e = lv.opt_Temporary() ) { - MIR_ASSERT(state, e->idx < temp_rewrite_table.size(), "Temporary out of range - " << lv); - // If the table entry for this temporary is !0, it wasn't marked as used - MIR_ASSERT(state, temp_rewrite_table.at(e->idx) != ~0u, "LValue " << lv << " incorrectly marked as unused"); - e->idx = temp_rewrite_table.at(e->idx); - } - if(auto* e = lv.opt_Variable() ) { - MIR_ASSERT(state, *e < var_rewrite_table.size(), "Variable out of range - " << lv); + if(auto* e = lv.opt_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, var_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused"); - *e = var_rewrite_table.at(*e); + MIR_ASSERT(state, local_rewrite_table.at(*e) != ~0u, "LValue " << lv << " incorrectly marked as unused"); + *e = local_rewrite_table.at(*e); } return false; }; @@ -2520,28 +2468,18 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn } else if( auto* se = stmt.opt_ScopeEnd() ) { - for(auto it = se->vars.begin(); it != se->vars.end(); ) - { - if( var_rewrite_table.at(*it) == ~0u ) { - it = se->vars.erase(it); - } - else { - *it = var_rewrite_table.at(*it); - ++ it; - } - } - for(auto it = se->tmps.begin(); it != se->tmps.end(); ) + for(auto it = se->slots.begin(); it != se->slots.end(); ) { - if( temp_rewrite_table.at(*it) == ~0u ) { - it = se->tmps.erase(it); + if( local_rewrite_table.at(*it) == ~0u ) { + it = se->slots.erase(it); } else { - *it = temp_rewrite_table.at(*it); + *it = local_rewrite_table.at(*it); ++ it; } } - if( se->vars.empty() && se->tmps.empty() ) { + if( se->slots.empty() ) { DEBUG(state << "Delete ScopeEnd (now empty)"); to_remove_statements[stmt_idx] = true; continue ; diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 878a55d4..2841db10 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1303,16 +1303,10 @@ namespace { m_of << "{\n"; // Variables m_of << "\t"; emit_ctype(ret_type, FMT_CB(ss, ss << "rv";)); m_of << ";\n"; - for(unsigned int i = 0; i < code->named_variables.size(); i ++) { - DEBUG("var" << i << " : " << code->named_variables[i]); - m_of << "\t"; emit_ctype(code->named_variables[i], FMT_CB(ss, ss << "var" << i;)); m_of << ";"; - m_of << "\t// " << code->named_variables[i]; - m_of << "\n"; - } - for(unsigned int i = 0; i < code->temporaries.size(); i ++) { - DEBUG("tmp" << i << " : " << code->temporaries[i]); - m_of << "\t"; emit_ctype(code->temporaries[i], FMT_CB(ss, ss << " tmp" << i;)); m_of << ";"; - m_of << "\t// " << code->temporaries[i]; + for(unsigned int i = 0; i < code->locals.size(); i ++) { + DEBUG("var" << i << " : " << code->locals[i]); + m_of << "\t"; emit_ctype(code->locals[i], FMT_CB(ss, ss << "var" << i;)); m_of << ";"; + m_of << "\t// " << code->locals[i]; m_of << "\n"; } for(unsigned int i = 0; i < code->drop_flags.size(); i ++) { @@ -2612,7 +2606,7 @@ namespace { // Call destructor on all entries m_of << "for(unsigned i = 0; i < "; emit_lvalue(*lvp->as_Deref().val); m_of << ".META; i++) {"; m_of << "\t\t"; - emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Temporary({~0u})) }), *te.inner, false); + emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false); m_of << "\n\t}"; ) ) @@ -2814,20 +2808,17 @@ namespace { void emit_lvalue(const ::MIR::LValue& val) { TU_MATCHA( (val), (e), - (Variable, - m_of << "var" << e; - ), - (Temporary, - if( e.idx == ~0u ) - m_of << "i"; - else - m_of << "tmp" << e.idx; + (Return, + m_of << "rv"; ), (Argument, m_of << "arg" << e.idx; ), - (Return, - m_of << "rv"; + (Local, + if( e == ~0u ) + m_of << "i"; + else + m_of << "var" << e; ), (Static, m_of << Trans_Mangle(e); diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index 02116d18..fb577959 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -623,9 +623,7 @@ void Trans_Enumerate_Types(EnumState& state) if( fcn.m_code.m_mir ) { const auto& mir = *fcn.m_code.m_mir; - for(const auto& ty : mir.named_variables) - tv.visit_type(monomorph(ty)); - for(const auto& ty : mir.temporaries) + for(const auto& ty : mir.locals) tv.visit_type(monomorph(ty)); // TODO: Find all LValue::Deref instances and get the result type @@ -646,19 +644,19 @@ void Trans_Enumerate_Types(EnumState& state) }; // Recurse, if Deref get the type and add it to the visitor TU_MATCHA( (lv), (e), - (Variable, + (Return, if( tmp_ty_ptr ) { - return monomorph_outer(fcn.m_code.m_mir->named_variables[e]); + TODO(Span(), "Get return type for MIR type enumeration"); } ), - (Temporary, + (Argument, if( tmp_ty_ptr ) { - return monomorph_outer(fcn.m_code.m_mir->temporaries[e.idx]); + return monomorph_outer(fcn.m_args[e.idx].second); } ), - (Argument, + (Local, if( tmp_ty_ptr ) { - return monomorph_outer(fcn.m_args[e.idx].second); + return monomorph_outer(fcn.m_code.m_mir->locals[e]); } ), (Static, @@ -682,11 +680,6 @@ void Trans_Enumerate_Types(EnumState& state) ) } ), - (Return, - if( tmp_ty_ptr ) { - TODO(Span(), "Get return type for MIR type enumeration"); - } - ), (Field, const auto& ity = visit_lvalue(tv,pp,fcn, *e.val, tmp_ty_ptr); if( tmp_ty_ptr ) @@ -1344,17 +1337,15 @@ void Trans_Enumerate_FillFrom_Path(EnumState& state, const ::HIR::Path& path, co void Trans_Enumerate_FillFrom_MIR_LValue(EnumState& state, const ::MIR::LValue& lv, const Trans_Params& pp) { TU_MATCHA( (lv), (e), - (Variable, - ), - (Temporary, + (Return, ), (Argument, ), + (Local, + ), (Static, Trans_Enumerate_FillFrom_Path(state, e, pp); ), - (Return, - ), (Field, Trans_Enumerate_FillFrom_MIR_LValue(state, *e.val, pp); ), diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index 3ac2ee09..f708060d 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -13,10 +13,9 @@ namespace { ::MIR::LValue monomorph_LValue(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::LValue& tpl) { TU_MATCHA( (tpl), (e), - (Variable, return e; ), - (Temporary, return e; ), - (Argument, return e; ), (Return, return e; ), + (Argument, return e; ), + (Local, return e; ), (Static, return params.monomorph(resolve, e); ), @@ -120,17 +119,11 @@ namespace { ::MIR::Function output; // 1. Monomorphise locals and temporaries - output.named_variables.reserve( tpl->named_variables.size() ); - for(const auto& var : tpl->named_variables) - { - DEBUG("- var" << output.named_variables.size()); - output.named_variables.push_back( params.monomorph(resolve, var) ); - } - output.temporaries.reserve( tpl->temporaries.size() ); - for(const auto& ty : tpl->temporaries) + output.locals.reserve( tpl->locals.size() ); + for(const auto& var : tpl->locals) { - DEBUG("- tmp" << output.temporaries.size()); - output.temporaries.push_back( params.monomorph(resolve, ty) ); + DEBUG("- _" << output.locals.size()); + output.locals.push_back( params.monomorph(resolve, var) ); } output.drop_flags = tpl->drop_flags; -- cgit v1.2.3 From 60f74bdb41ae552caf734a799713591a6eea9fa1 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 18 Jun 2017 20:49:45 +0800 Subject: Trans - Starting work on multiple targets --- src/expand/cfg.hpp | 2 + src/main.cpp | 19 +- src/trans/codegen_c.cpp | 1060 +++++++++++++++++++++++++---------------------- src/trans/target.cpp | 55 ++- src/trans/target.hpp | 32 ++ 5 files changed, 657 insertions(+), 511 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/expand/cfg.hpp b/src/expand/cfg.hpp index 8e5fce42..edf17851 100644 --- a/src/expand/cfg.hpp +++ b/src/expand/cfg.hpp @@ -1,6 +1,8 @@ #pragma once +#include + extern void Cfg_SetFlag(::std::string name); extern void Cfg_SetValue(::std::string name, ::std::string val); extern void Cfg_SetValueCb(::std::string name, ::std::function cb); diff --git a/src/main.cpp b/src/main.cpp index af999dae..27721cb0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,6 +23,7 @@ #include "hir_expand/main_bindings.hpp" #include "mir/main_bindings.hpp" #include "trans/main_bindings.hpp" +#include "trans/target.hpp" #include "expand/cfg.hpp" @@ -175,26 +176,10 @@ int main(int argc, char *argv[]) // Set up cfg values Cfg_SetValue("rust_compiler", "mrustc"); - // TODO: Target spec - Cfg_SetFlag("unix"); - Cfg_SetFlag("linux"); - Cfg_SetValue("target_os", "linux"); - Cfg_SetValue("target_family", "unix"); - Cfg_SetValue("target_pointer_width", "64"); - Cfg_SetValue("target_endian", "little"); - Cfg_SetValue("target_arch", "x86_64"); - Cfg_SetValue("target_env", "gnu"); - Cfg_SetValueCb("target_has_atomic", [](const ::std::string& s) { - if(s == "8") return true; // Has an atomic byte - if(s == "ptr") return true; // Has an atomic pointer-sized value - return false; - }); - Cfg_SetValueCb("target_feature", [](const ::std::string& s) { - return false; - }); Cfg_SetValueCb("feature", [¶ms](const ::std::string& s) { return params.features.count(s) != 0; }); + Target_SetCfg(); if( params.test_harness ) diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 2841db10..7e0405d1 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -26,6 +26,11 @@ namespace { TraitObject, }; + enum class Compiler { + Gcc, + Msvc + }; + static Span sp; const ::HIR::Crate& m_crate; @@ -37,6 +42,8 @@ namespace { ::std::ofstream m_of; const ::MIR::TypeResolve* m_mir_res; + Compiler m_compiler = Compiler::Gcc; + ::std::map<::HIR::GenericPath, ::std::vector> m_enum_repr_cache; ::std::vector< ::std::pair< ::HIR::GenericPath, const ::HIR::Struct*> > m_box_glue_todo; @@ -55,10 +62,14 @@ namespace { << "#include \n" << "#include \n" << "#include \n" - << "#include \n" // atomic_* << "#include \n" // abort << "#include \n" // mem* << "#include \n" // round, ... + ; + m_of + << "#include \n" // atomic_* + ; + m_of << "typedef uint32_t CHAR;\n" << "typedef struct { } tUNIT;\n" << "typedef struct { } tBANG;\n" @@ -80,12 +91,20 @@ namespace { << "static inline TRAITOBJ_PTR make_traitobjptr(void* ptr, void* vt) { TRAITOBJ_PTR rv = { ptr, vt }; return rv; }\n" << "\n" << "static inline size_t max(size_t a, size_t b) { return a < b ? b : a; }\n" + << "static inline void noop_drop(void *p) {}\n" + << "\n" + ; + // 64-bit bit ops + m_of << "static inline uint64_t __builtin_clz64(uint64_t v) {\n" << "\treturn (v >> 32 != 0 ? __builtin_clz(v>>32) : 32 + __builtin_clz(v));\n" << "}\n" << "static inline uint64_t __builtin_ctz64(uint64_t v) {\n" << "\treturn ((v&0xFFFFFFFF) == 0 ? __builtin_ctz(v>>32) + 32 : __builtin_ctz(v));\n" << "}\n" + ; + // u128/i128 ops + m_of << "static inline unsigned __int128 __builtin_bswap128(unsigned __int128 v) {\n" << "\tuint64_t lo = __builtin_bswap64((uint64_t)v);\n" << "\tuint64_t hi = __builtin_bswap64((uint64_t)(v>>64));\n" @@ -98,8 +117,6 @@ namespace { << "\treturn ((v&0xFFFFFFFFFFFFFFFF) == 0 ? __builtin_ctz64(v>>64) + 64 : __builtin_ctz64(v));\n" << "}\n" << "\n" - << "static inline void noop_drop(void *p) {}\n" - << "\n" ; } @@ -134,59 +151,113 @@ namespace { // Execute $CC with the required libraries ::std::vector<::std::string> tmp; + auto cache_str = [&](::std::string s){ tmp.push_back(::std::move(s)); return tmp.back().c_str(); }; ::std::vector args; - args.push_back( getenv("CC") ? getenv("CC") : "gcc" ); - args.push_back("-ffunction-sections"); - args.push_back("-pthread"); - switch(opt.opt_level) - { - case 0: break; - case 1: - args.push_back("-O1"); - break; - case 2: - args.push_back("-O2"); - break; - } - if( opt.emit_debug_info ) - { - args.push_back("-g"); - } - args.push_back("-o"); - args.push_back(m_outfile_path.c_str()); - args.push_back(m_outfile_path_c.c_str()); - if( is_executable ) + switch( m_compiler ) { - for( const auto& crate : m_crate.m_ext_crates ) + case Compiler::Gcc: + args.push_back( getenv("CC") ? getenv("CC") : "gcc" ); + args.push_back("-ffunction-sections"); + args.push_back("-pthread"); + switch(opt.opt_level) { - tmp.push_back(crate.second.m_filename + ".o"); - args.push_back(tmp.back().c_str()); + case 0: break; + case 1: + args.push_back("-O1"); + break; + case 2: + args.push_back("-O2"); + break; } - for(const auto& path : opt.library_search_dirs ) + if( opt.emit_debug_info ) { - args.push_back("-L"); args.push_back(path.c_str()); - } - for(const auto& lib : m_crate.m_ext_libs) { - ASSERT_BUG(Span(), lib.name != "", ""); - args.push_back("-l"); args.push_back(lib.name.c_str()); + args.push_back("-g"); } - for( const auto& crate : m_crate.m_ext_crates ) + args.push_back("-o"); + args.push_back(m_outfile_path.c_str()); + args.push_back(m_outfile_path_c.c_str()); + if( is_executable ) { - for(const auto& lib : crate.second.m_data->m_ext_libs) { - ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first); + for( const auto& crate : m_crate.m_ext_crates ) + { + args.push_back(cache_str( crate.second.m_filename + ".o" )); + } + for(const auto& path : opt.library_search_dirs ) + { + args.push_back("-L"); args.push_back(path.c_str()); + } + for(const auto& lib : m_crate.m_ext_libs) { + ASSERT_BUG(Span(), lib.name != "", ""); args.push_back("-l"); args.push_back(lib.name.c_str()); } + for( const auto& crate : m_crate.m_ext_crates ) + { + for(const auto& lib : crate.second.m_data->m_ext_libs) { + ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first); + args.push_back("-l"); args.push_back(lib.name.c_str()); + } + } + for(const auto& path : opt.libraries ) + { + args.push_back("-l"); args.push_back(path.c_str()); + } + args.push_back("-z"); args.push_back("muldefs"); + args.push_back("-Wl,--gc-sections"); } - for(const auto& path : opt.libraries ) + else { - args.push_back("-l"); args.push_back(path.c_str()); + args.push_back("-c"); } - args.push_back("-z"); args.push_back("muldefs"); - args.push_back("-Wl,--gc-sections"); - } - else - { - args.push_back("-c"); + break; + case Compiler::Msvc: + args.push_back( "cl.exe" ); + args.push_back(m_outfile_path_c.c_str()); + switch(opt.opt_level) + { + case 0: break; + case 1: + args.push_back("/O1"); + break; + case 2: + args.push_back("/O2"); + break; + } + if(is_executable) + { + for( const auto& crate : m_crate.m_ext_crates ) + { + args.push_back(cache_str( crate.second.m_filename + ".o" )); + } + // Command-line specified linker search directories + for(const auto& path : opt.library_search_dirs ) + { + args.push_back("/link"); + args.push_back("/LIBPATH"); + args.push_back(path.c_str()); + } + // Crate-specified libraries + for(const auto& lib : m_crate.m_ext_libs) { + ASSERT_BUG(Span(), lib.name != "", ""); + args.push_back(lib.name.c_str()); + } + for( const auto& crate : m_crate.m_ext_crates ) + { + for(const auto& lib : crate.second.m_data->m_ext_libs) { + ASSERT_BUG(Span(), lib.name != "", "Empty lib from " << crate.first); + args.push_back(lib.name.c_str()); + } + } + for(const auto& path : opt.libraries ) + { + args.push_back(path.c_str()); + } + } + else + { + args.push_back("/c"); + args.push_back(cache_str( FMT("/Fo" + m_outfile_path) )); + } + break; } ::std::stringstream cmd_ss; @@ -1316,6 +1387,7 @@ namespace { { TRACE_FUNCTION_F(p << " bb" << i); + // HACK: Ignore any blocks that only contain `diverge;` if( code->blocks[i].statements.size() == 0 && code->blocks[i].terminator.is_Diverge() ) { DEBUG("- Diverge only, omitting"); m_of << "bb" << i << ": _Unwind_Resume(); // Diverge\n"; @@ -1327,454 +1399,7 @@ namespace { for(const auto& stmt : code->blocks[i].statements) { mir_res.set_cur_stmt(i, (&stmt - &code->blocks[i].statements.front())); - switch( stmt.tag() ) - { - case ::MIR::Statement::TAGDEAD: throw ""; - case ::MIR::Statement::TAG_ScopeEnd: - m_of << "// " << stmt << "\n"; - break; - case ::MIR::Statement::TAG_SetDropFlag: { - const auto& e = stmt.as_SetDropFlag(); - 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(); - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, e.slot); - - if( e.flag_idx != ~0u ) - m_of << "\tif( df" << e.flag_idx << " ) {\n"; - - switch( e.kind ) - { - case ::MIR::eDropKind::SHALLOW: - // Shallow drops are only valid on owned_box - if( const auto* ity = m_resolve.is_type_owned_box(ty) ) - { - // Emit a call to box_free for the type - ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } }; - // TODO: This is specific to the official liballoc's owned_box - m_of << "\t" << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n"; - } - else - { - MIR_BUG(mir_res, "Shallow drop on non-Box - " << ty); - } - break; - case ::MIR::eDropKind::DEEP: - emit_destructor_call(e.slot, ty, false); - break; - } - if( e.flag_idx != ~0u ) - m_of << "\t}\n"; - break; } - case ::MIR::Statement::TAG_Asm: { - const auto& e = stmt.as_Asm(); - - struct H { - static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) { - return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x){return x==des;}) != flags.end(); - } - static const char* convert_reg(const char* r) { - if( ::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0 ) { - return "a"; - } - else { - return r; - } - } - }; - bool is_volatile = H::has_flag(e.flags, "volatile"); - bool is_intel = H::has_flag(e.flags, "intel"); - - m_of << "\t__asm__ "; - if(is_volatile) m_of << "__volatile__"; - // TODO: Convert format string? - // TODO: Use a C-specific escaper here. - m_of << "(\"" << (is_intel ? ".syntax intel; " : "") << FmtEscaped(e.tpl) << (is_intel ? ".syntax att; " : "") << "\""; - m_of << ": "; - for(unsigned int i = 0; i < e.outputs.size(); i ++ ) - { - const auto& v = e.outputs[i]; - if( i != 0 ) m_of << ", "; - m_of << "\""; - switch(v.first[0]) - { - case '=': m_of << "="; break; - case '+': m_of << "+"; break; - default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); - } - m_of << H::convert_reg(v.first.c_str()+1); - m_of << "\"("; emit_lvalue(v.second); m_of << ")"; - } - m_of << ": "; - for(unsigned int i = 0; i < e.inputs.size(); i ++ ) - { - const auto& v = e.inputs[i]; - if( i != 0 ) m_of << ", "; - m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; - } - m_of << ": "; - for(unsigned int i = 0; i < e.clobbers.size(); i ++ ) - { - if( i != 0 ) m_of << ", "; - m_of << "\"" << e.clobbers[i] << "\""; - } - m_of << ");\n"; - break; } - case ::MIR::Statement::TAG_Assign: { - const auto& e = stmt.as_Assign(); - DEBUG("- " << e.dst << " = " << e.src); - m_of << "\t"; - TU_MATCHA( (e.src), (ve), - (Use, - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, ve); - if( ty == ::HIR::TypeRef::new_diverge() ) { - m_of << "abort()"; - break; - } - emit_lvalue(e.dst); - m_of << " = "; - emit_lvalue(ve); - ), - (Constant, - emit_lvalue(e.dst); - m_of << " = "; - emit_constant(ve, &e.dst); - ), - (SizedArray, - if( ve.count == 0 ) { - } - else if( ve.count == 1 ) { - emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); - } - else if( ve.count == 2 ) { - emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); - } - else if( ve.count == 3 ) { - emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); m_of << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA[2] = "; emit_param(ve.val); - } - else { - m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n"; - m_of << "\t\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val); - } - ), - (Borrow, - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); - bool special = false; - // If the inner value has type [T] or str, create DST based on inner pointer and existing metadata - TU_IFLET(::MIR::LValue, ve.val, Deref, le, - if( metadata_type(ty) != MetadataType::None ) { - emit_lvalue(e.dst); - m_of << " = "; - emit_lvalue(*le.val); - 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, - 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; - - // Construct the new DST - emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n\t"; - emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val); - special = true; - } - ) - if( !special ) - { - emit_lvalue(e.dst); - m_of << " = "; - m_of << "& "; emit_lvalue(ve.val); - } - ), - (Cast, - if( m_resolve.is_type_phantom_data(ve.type) ) { - m_of << "/* PhandomData cast */\n"; - continue ; - } - - emit_lvalue(e.dst); - m_of << " = "; - m_of << "("; emit_ctype(ve.type); m_of << ")"; - // TODO: If the source is an unsized borrow, then extract the pointer - bool special = false; - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); - // If the destination is a thin pointer - if( ve.type.m_data.is_Pointer() && !is_dst( *ve.type.m_data.as_Pointer().inner ) ) - { - // NOTE: Checks the result of the deref - if( (ty.m_data.is_Borrow() && is_dst(*ty.m_data.as_Borrow().inner)) - || (ty.m_data.is_Pointer() && is_dst(*ty.m_data.as_Pointer().inner)) - ) - { - emit_lvalue(ve.val); - m_of << ".PTR"; - special = true; - } - } - if( ve.type.m_data.is_Primitive() && ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum() ) - { - emit_lvalue(ve.val); - m_of << ".TAG"; - special = true; - } - if( !special ) - { - emit_lvalue(ve.val); - } - ), - (BinOp, - emit_lvalue(e.dst); - m_of << " = "; - ::HIR::TypeRef tmp; - const auto& ty = ve.val_l.is_LValue() ? mir_res.get_lvalue_type(tmp, ve.val_l.as_LValue()) : tmp = mir_res.get_const_type(ve.val_l.as_Constant()); - if( ty.m_data.is_Borrow() ) { - m_of << "(slice_cmp("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")"; - switch(ve.op) - { - case ::MIR::eBinOp::EQ: m_of << " == 0"; break; - case ::MIR::eBinOp::NE: m_of << " != 0"; break; - case ::MIR::eBinOp::GT: m_of << " > 0"; break; - case ::MIR::eBinOp::GE: m_of << " >= 0"; break; - case ::MIR::eBinOp::LT: m_of << " < 0"; break; - case ::MIR::eBinOp::LE: m_of << " <= 0"; break; - default: - MIR_BUG(mir_res, "Unknown comparison of a &-ptr - " << e.src << " with " << ty); - } - m_of << ")"; - break; - } - else if( const auto* te = ty.m_data.opt_Pointer() ) { - if( metadata_type(*te->inner) != MetadataType::None ) - { - switch(ve.op) - { - case ::MIR::eBinOp::EQ: - emit_param(ve.val_l); m_of << ".PTR == "; emit_param(ve.val_r); m_of << ".PTR && "; - emit_param(ve.val_l); m_of << ".META == "; emit_param(ve.val_r); m_of << ".META"; - break; - case ::MIR::eBinOp::NE: - emit_param(ve.val_l); m_of << ".PTR != "; emit_param(ve.val_r); m_of << ".PTR || "; - emit_param(ve.val_l); m_of << ".META != "; emit_param(ve.val_r); m_of << ".META"; - break; - default: - MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty); - } - } - else - { - emit_param(ve.val_l); - switch(ve.op) - { - case ::MIR::eBinOp::EQ: m_of << " == "; break; - case ::MIR::eBinOp::NE: m_of << " != "; break; - case ::MIR::eBinOp::GT: m_of << " > " ; break; - case ::MIR::eBinOp::GE: m_of << " >= "; break; - case ::MIR::eBinOp::LT: m_of << " < " ; break; - case ::MIR::eBinOp::LE: m_of << " <= "; break; - default: - MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty); - } - emit_param(ve.val_r); - } - break; - } - else if( ve.op == ::MIR::eBinOp::MOD && (ty == ::HIR::CoreType::F32 || ty == ::HIR::CoreType::F64) ) { - if( ty == ::HIR::CoreType::F32 ) - m_of << "remainderf"; - else - m_of << "remainder"; - m_of << "("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")"; - break; - } - else { - } - - emit_param(ve.val_l); - switch(ve.op) - { - case ::MIR::eBinOp::ADD: m_of << " + "; break; - case ::MIR::eBinOp::SUB: m_of << " - "; break; - case ::MIR::eBinOp::MUL: m_of << " * "; break; - case ::MIR::eBinOp::DIV: m_of << " / "; break; - case ::MIR::eBinOp::MOD: m_of << " % "; break; - - case ::MIR::eBinOp::BIT_OR: m_of << " | "; break; - case ::MIR::eBinOp::BIT_AND: m_of << " & "; break; - case ::MIR::eBinOp::BIT_XOR: m_of << " ^ "; break; - case ::MIR::eBinOp::BIT_SHR: m_of << " >> "; break; - case ::MIR::eBinOp::BIT_SHL: m_of << " << "; break; - case ::MIR::eBinOp::EQ: m_of << " == "; break; - case ::MIR::eBinOp::NE: m_of << " != "; break; - case ::MIR::eBinOp::GT: m_of << " > " ; break; - case ::MIR::eBinOp::GE: m_of << " >= "; break; - case ::MIR::eBinOp::LT: m_of << " < " ; break; - case ::MIR::eBinOp::LE: m_of << " <= "; break; - - case ::MIR::eBinOp::ADD_OV: - case ::MIR::eBinOp::SUB_OV: - case ::MIR::eBinOp::MUL_OV: - case ::MIR::eBinOp::DIV_OV: - MIR_TODO(mir_res, "Overflow"); - break; - } - emit_param(ve.val_r); - ), - (UniOp, - ::HIR::TypeRef tmp; - emit_lvalue(e.dst); - m_of << " = "; - switch(ve.op) - { - case ::MIR::eUniOp::NEG: m_of << "-"; break; - case ::MIR::eUniOp::INV: - if( mir_res.get_lvalue_type(tmp, e.dst) == ::HIR::CoreType::Bool ) - m_of << "!"; - else - m_of << "~"; - break; - } - emit_lvalue(ve.val); - ), - (DstMeta, - emit_lvalue(e.dst); - m_of << " = "; - emit_lvalue(ve.val); - m_of << ".META"; - ), - (DstPtr, - emit_lvalue(e.dst); - m_of << " = "; - emit_lvalue(ve.val); - m_of << ".PTR"; - ), - (MakeDst, - emit_lvalue(e.dst); - m_of << ".PTR = "; - emit_param(ve.ptr_val); - m_of << ";\n\t"; - emit_lvalue(e.dst); - m_of << ".META = "; - emit_param(ve.meta_val); - ), - (Tuple, - for(unsigned int j = 0; j < ve.vals.size(); j ++) { - if( j != 0 ) m_of << ";\n\t"; - emit_lvalue(e.dst); - m_of << "._" << j << " = "; - emit_param(ve.vals[j]); - } - ), - (Array, - for(unsigned int j = 0; j < ve.vals.size(); j ++) { - if( j != 0 ) m_of << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = "; - emit_param(ve.vals[j]); - } - ), - (Variant, - const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path); - if( tyi.is_Union() ) - { - emit_lvalue(e.dst); - m_of << ".var_" << ve.index << " = "; emit_param(ve.val); - } - else if( const auto* enm_p = tyi.opt_Enum() ) - { - MIR_TODO(mir_res, "Construct enum with RValue::Variant"); - if( enm_p->is_value() ) - { - emit_lvalue(e.dst); m_of << ".TAG = " << enm_p->get_value(ve.index) << ""; - } - else - { - emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA"; - m_of << ".var_" << ve.index << " = "; emit_param(ve.val); - } - } - else - { - BUG(mir_res.sp, "Unexpected type in Variant"); - } - ), - (Struct, - if(ve.variant_idx != ~0u) - { - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); - const auto* enm_p = ty.m_data.as_Path().binding.as_Enum(); - - auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); - if( it != m_enum_repr_cache.end() ) - { - if( ve.variant_idx == 0 ) { - // TODO: Use nonzero_path - m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))"; - } - else if( ve.variant_idx == 1 ) { - emit_lvalue(e.dst); - m_of << "._0 = "; - emit_param(ve.vals[0]); - } - else { - } - break; - } - else if( enm_p->is_value() ) - { - emit_lvalue(e.dst); - m_of << ".TAG = " << enm_p->get_value(ve.variant_idx); - assert(ve.vals.size() == 0); - } - else - { - emit_lvalue(e.dst); - m_of << ".TAG = " << ve.variant_idx; - } - if(ve.vals.size() > 0) - m_of << ";\n\t"; - } - - for(unsigned int j = 0; j < ve.vals.size(); j ++) - { - // HACK: Don't emit assignment of PhantomData - ::HIR::TypeRef tmp; - if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) ) - continue ; - - if( j != 0 ) m_of << ";\n\t"; - emit_lvalue(e.dst); - if(ve.variant_idx != ~0u) - m_of << ".DATA.var_" << ve.variant_idx; - m_of << "._" << j << " = "; - emit_param(ve.vals[j]); - } - ) - ) - m_of << ";"; - m_of << "\t// " << e.dst << " = " << e.src; - m_of << "\n"; - break; } - } + emit_statement(mir_res, stmt); } mir_res.set_cur_stmt_term(i); @@ -1912,6 +1537,457 @@ namespace { m_of.flush(); m_mir_res = nullptr; } + void emit_statement(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement& stmt) + { + switch( stmt.tag() ) + { + case ::MIR::Statement::TAGDEAD: throw ""; + case ::MIR::Statement::TAG_ScopeEnd: + m_of << "// " << stmt << "\n"; + break; + case ::MIR::Statement::TAG_SetDropFlag: { + const auto& e = stmt.as_SetDropFlag(); + 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(); + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, e.slot); + + if( e.flag_idx != ~0u ) + m_of << "\tif( df" << e.flag_idx << " ) {\n"; + + switch( e.kind ) + { + case ::MIR::eDropKind::SHALLOW: + // Shallow drops are only valid on owned_box + if( const auto* ity = m_resolve.is_type_owned_box(ty) ) + { + // Emit a call to box_free for the type + ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } }; + // TODO: This is specific to the official liballoc's owned_box + m_of << "\t" << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n"; + } + else + { + MIR_BUG(mir_res, "Shallow drop on non-Box - " << ty); + } + break; + case ::MIR::eDropKind::DEEP: + emit_destructor_call(e.slot, ty, false); + break; + } + if( e.flag_idx != ~0u ) + m_of << "\t}\n"; + break; } + case ::MIR::Statement::TAG_Asm: { + const auto& e = stmt.as_Asm(); + + struct H { + static bool has_flag(const ::std::vector<::std::string>& flags, const char* des) { + return ::std::find_if(flags.begin(), flags.end(), [des](const auto&x){return x==des;}) != flags.end(); + } + static const char* convert_reg(const char* r) { + if( ::std::strcmp(r, "{eax}") == 0 || ::std::strcmp(r, "{rax}") == 0 ) { + return "a"; + } + else { + return r; + } + } + }; + bool is_volatile = H::has_flag(e.flags, "volatile"); + bool is_intel = H::has_flag(e.flags, "intel"); + + m_of << "\t__asm__ "; + if(is_volatile) m_of << "__volatile__"; + // TODO: Convert format string? + // TODO: Use a C-specific escaper here. + m_of << "(\"" << (is_intel ? ".syntax intel; " : "") << FmtEscaped(e.tpl) << (is_intel ? ".syntax att; " : "") << "\""; + m_of << ": "; + for(unsigned int i = 0; i < e.outputs.size(); i ++ ) + { + const auto& v = e.outputs[i]; + if( i != 0 ) m_of << ", "; + m_of << "\""; + switch(v.first[0]) + { + case '=': m_of << "="; break; + case '+': m_of << "+"; break; + default: MIR_TODO(mir_res, "Handle asm! output leader '" << v.first[0] << "'"); + } + m_of << H::convert_reg(v.first.c_str()+1); + m_of << "\"("; emit_lvalue(v.second); m_of << ")"; + } + m_of << ": "; + for(unsigned int i = 0; i < e.inputs.size(); i ++ ) + { + const auto& v = e.inputs[i]; + if( i != 0 ) m_of << ", "; + m_of << "\"" << v.first << "\"("; emit_lvalue(v.second); m_of << ")"; + } + m_of << ": "; + for(unsigned int i = 0; i < e.clobbers.size(); i ++ ) + { + if( i != 0 ) m_of << ", "; + m_of << "\"" << e.clobbers[i] << "\""; + } + m_of << ");\n"; + break; } + case ::MIR::Statement::TAG_Assign: { + const auto& e = stmt.as_Assign(); + DEBUG("- " << e.dst << " = " << e.src); + m_of << "\t"; + TU_MATCHA( (e.src), (ve), + (Use, + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, ve); + if( ty == ::HIR::TypeRef::new_diverge() ) { + m_of << "abort()"; + break; + } + emit_lvalue(e.dst); + m_of << " = "; + emit_lvalue(ve); + ), + (Constant, + emit_lvalue(e.dst); + m_of << " = "; + emit_constant(ve, &e.dst); + ), + (SizedArray, + if( ve.count == 0 ) { + } + else if( ve.count == 1 ) { + emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); + } + else if( ve.count == 2 ) { + emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); + } + else if( ve.count == 3 ) { + emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[2] = "; emit_param(ve.val); + } + else { + m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n"; + m_of << "\t\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val); + } + ), + (Borrow, + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); + bool special = false; + // If the inner value has type [T] or str, create DST based on inner pointer and existing metadata + TU_IFLET(::MIR::LValue, ve.val, Deref, le, + if( metadata_type(ty) != MetadataType::None ) { + emit_lvalue(e.dst); + m_of << " = "; + emit_lvalue(*le.val); + 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, + 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; + + // Construct the new DST + emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n\t"; + emit_lvalue(e.dst); m_of << ".PTR = &"; emit_lvalue(ve.val); + special = true; + } + ) + if( !special ) + { + emit_lvalue(e.dst); + m_of << " = "; + m_of << "& "; emit_lvalue(ve.val); + } + ), + (Cast, + if( m_resolve.is_type_phantom_data(ve.type) ) { + m_of << "/* PhandomData cast */\n"; + return ; + } + + emit_lvalue(e.dst); + m_of << " = "; + m_of << "("; emit_ctype(ve.type); m_of << ")"; + // TODO: If the source is an unsized borrow, then extract the pointer + bool special = false; + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, ve.val); + // If the destination is a thin pointer + if( ve.type.m_data.is_Pointer() && !is_dst( *ve.type.m_data.as_Pointer().inner ) ) + { + // NOTE: Checks the result of the deref + if( (ty.m_data.is_Borrow() && is_dst(*ty.m_data.as_Borrow().inner)) + || (ty.m_data.is_Pointer() && is_dst(*ty.m_data.as_Pointer().inner)) + ) + { + emit_lvalue(ve.val); + m_of << ".PTR"; + special = true; + } + } + if( ve.type.m_data.is_Primitive() && ty.m_data.is_Path() && ty.m_data.as_Path().binding.is_Enum() ) + { + emit_lvalue(ve.val); + m_of << ".TAG"; + special = true; + } + if( !special ) + { + emit_lvalue(ve.val); + } + ), + (BinOp, + emit_lvalue(e.dst); + m_of << " = "; + ::HIR::TypeRef tmp; + const auto& ty = ve.val_l.is_LValue() ? mir_res.get_lvalue_type(tmp, ve.val_l.as_LValue()) : tmp = mir_res.get_const_type(ve.val_l.as_Constant()); + if( ty.m_data.is_Borrow() ) { + m_of << "(slice_cmp("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")"; + switch(ve.op) + { + case ::MIR::eBinOp::EQ: m_of << " == 0"; break; + case ::MIR::eBinOp::NE: m_of << " != 0"; break; + case ::MIR::eBinOp::GT: m_of << " > 0"; break; + case ::MIR::eBinOp::GE: m_of << " >= 0"; break; + case ::MIR::eBinOp::LT: m_of << " < 0"; break; + case ::MIR::eBinOp::LE: m_of << " <= 0"; break; + default: + MIR_BUG(mir_res, "Unknown comparison of a &-ptr - " << e.src << " with " << ty); + } + m_of << ")"; + break; + } + else if( const auto* te = ty.m_data.opt_Pointer() ) { + if( metadata_type(*te->inner) != MetadataType::None ) + { + switch(ve.op) + { + case ::MIR::eBinOp::EQ: + emit_param(ve.val_l); m_of << ".PTR == "; emit_param(ve.val_r); m_of << ".PTR && "; + emit_param(ve.val_l); m_of << ".META == "; emit_param(ve.val_r); m_of << ".META"; + break; + case ::MIR::eBinOp::NE: + emit_param(ve.val_l); m_of << ".PTR != "; emit_param(ve.val_r); m_of << ".PTR || "; + emit_param(ve.val_l); m_of << ".META != "; emit_param(ve.val_r); m_of << ".META"; + break; + default: + MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty); + } + } + else + { + emit_param(ve.val_l); + switch(ve.op) + { + case ::MIR::eBinOp::EQ: m_of << " == "; break; + case ::MIR::eBinOp::NE: m_of << " != "; break; + case ::MIR::eBinOp::GT: m_of << " > " ; break; + case ::MIR::eBinOp::GE: m_of << " >= "; break; + case ::MIR::eBinOp::LT: m_of << " < " ; break; + case ::MIR::eBinOp::LE: m_of << " <= "; break; + default: + MIR_BUG(mir_res, "Unknown comparison of a *-ptr - " << e.src << " with " << ty); + } + emit_param(ve.val_r); + } + break; + } + else if( ve.op == ::MIR::eBinOp::MOD && (ty == ::HIR::CoreType::F32 || ty == ::HIR::CoreType::F64) ) { + if( ty == ::HIR::CoreType::F32 ) + m_of << "remainderf"; + else + m_of << "remainder"; + m_of << "("; emit_param(ve.val_l); m_of << ", "; emit_param(ve.val_r); m_of << ")"; + break; + } + else { + } + + emit_param(ve.val_l); + switch(ve.op) + { + case ::MIR::eBinOp::ADD: m_of << " + "; break; + case ::MIR::eBinOp::SUB: m_of << " - "; break; + case ::MIR::eBinOp::MUL: m_of << " * "; break; + case ::MIR::eBinOp::DIV: m_of << " / "; break; + case ::MIR::eBinOp::MOD: m_of << " % "; break; + + case ::MIR::eBinOp::BIT_OR: m_of << " | "; break; + case ::MIR::eBinOp::BIT_AND: m_of << " & "; break; + case ::MIR::eBinOp::BIT_XOR: m_of << " ^ "; break; + case ::MIR::eBinOp::BIT_SHR: m_of << " >> "; break; + case ::MIR::eBinOp::BIT_SHL: m_of << " << "; break; + case ::MIR::eBinOp::EQ: m_of << " == "; break; + case ::MIR::eBinOp::NE: m_of << " != "; break; + case ::MIR::eBinOp::GT: m_of << " > " ; break; + case ::MIR::eBinOp::GE: m_of << " >= "; break; + case ::MIR::eBinOp::LT: m_of << " < " ; break; + case ::MIR::eBinOp::LE: m_of << " <= "; break; + + case ::MIR::eBinOp::ADD_OV: + case ::MIR::eBinOp::SUB_OV: + case ::MIR::eBinOp::MUL_OV: + case ::MIR::eBinOp::DIV_OV: + MIR_TODO(mir_res, "Overflow"); + break; + } + emit_param(ve.val_r); + ), + (UniOp, + ::HIR::TypeRef tmp; + emit_lvalue(e.dst); + m_of << " = "; + switch(ve.op) + { + case ::MIR::eUniOp::NEG: m_of << "-"; break; + case ::MIR::eUniOp::INV: + if( mir_res.get_lvalue_type(tmp, e.dst) == ::HIR::CoreType::Bool ) + m_of << "!"; + else + m_of << "~"; + break; + } + emit_lvalue(ve.val); + ), + (DstMeta, + emit_lvalue(e.dst); + m_of << " = "; + emit_lvalue(ve.val); + m_of << ".META"; + ), + (DstPtr, + emit_lvalue(e.dst); + m_of << " = "; + emit_lvalue(ve.val); + m_of << ".PTR"; + ), + (MakeDst, + emit_lvalue(e.dst); + m_of << ".PTR = "; + emit_param(ve.ptr_val); + m_of << ";\n\t"; + emit_lvalue(e.dst); + m_of << ".META = "; + emit_param(ve.meta_val); + ), + (Tuple, + for(unsigned int j = 0; j < ve.vals.size(); j ++) { + if( j != 0 ) m_of << ";\n\t"; + emit_lvalue(e.dst); + m_of << "._" << j << " = "; + emit_param(ve.vals[j]); + } + ), + (Array, + for(unsigned int j = 0; j < ve.vals.size(); j ++) { + if( j != 0 ) m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = "; + emit_param(ve.vals[j]); + } + ), + (Variant, + const auto& tyi = m_crate.get_typeitem_by_path(sp, ve.path.m_path); + if( tyi.is_Union() ) + { + emit_lvalue(e.dst); + m_of << ".var_" << ve.index << " = "; emit_param(ve.val); + } + else if( const auto* enm_p = tyi.opt_Enum() ) + { + MIR_TODO(mir_res, "Construct enum with RValue::Variant"); + if( enm_p->is_value() ) + { + emit_lvalue(e.dst); m_of << ".TAG = " << enm_p->get_value(ve.index) << ""; + } + else + { + emit_lvalue(e.dst); m_of << ".TAG = " << ve.index << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA"; + m_of << ".var_" << ve.index << " = "; emit_param(ve.val); + } + } + else + { + BUG(mir_res.sp, "Unexpected type in Variant"); + } + ), + (Struct, + if(ve.variant_idx != ~0u) + { + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, e.dst); + const auto* enm_p = ty.m_data.as_Path().binding.as_Enum(); + + auto it = m_enum_repr_cache.find(ty.m_data.as_Path().path.m_data.as_Generic()); + if( it != m_enum_repr_cache.end() ) + { + if( ve.variant_idx == 0 ) { + // TODO: Use nonzero_path + m_of << "memset(&"; emit_lvalue(e.dst); m_of << ", 0, sizeof("; emit_ctype(ty); m_of << "))"; + } + else if( ve.variant_idx == 1 ) { + emit_lvalue(e.dst); + m_of << "._0 = "; + emit_param(ve.vals[0]); + } + else { + } + break; + } + else if( enm_p->is_value() ) + { + emit_lvalue(e.dst); + m_of << ".TAG = " << enm_p->get_value(ve.variant_idx); + assert(ve.vals.size() == 0); + } + else + { + emit_lvalue(e.dst); + m_of << ".TAG = " << ve.variant_idx; + } + if(ve.vals.size() > 0) + m_of << ";\n\t"; + } + + for(unsigned int j = 0; j < ve.vals.size(); j ++) + { + // HACK: Don't emit assignment of PhantomData + ::HIR::TypeRef tmp; + if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) ) + continue ; + + if( j != 0 ) m_of << ";\n\t"; + emit_lvalue(e.dst); + if(ve.variant_idx != ~0u) + m_of << ".DATA.var_" << ve.variant_idx; + m_of << "._" << j << " = "; + emit_param(ve.vals[j]); + } + ) + ) + m_of << ";"; + m_of << "\t// " << e.dst << " = " << e.src; + m_of << "\n"; + break; } + } + } private: const ::HIR::TypeRef& monomorphise_fcn_return(::HIR::TypeRef& tmp, const ::HIR::Function& item, const Trans_Params& params) { diff --git a/src/trans/target.cpp b/src/trans/target.cpp index a85ab12a..d9b3486e 100644 --- a/src/trans/target.cpp +++ b/src/trans/target.cpp @@ -7,10 +7,53 @@ */ #include "target.hpp" #include +#include "../expand/cfg.hpp" // TODO: Replace with target selection #define POINTER_SIZE_BYTES 8 +TargetSpec g_target = { + "unix", + "linux", + "gnu", + CodegenMode::Gnu11, + TargetArch { + "x86_64", + 64, false, + { true, false, true, true, true } + } + }; + +void Target_SetCfg() +{ + if(g_target.m_family == "unix") { + Cfg_SetFlag("unix"); + } + else if( g_target.m_family == "windows") { + Cfg_SetFlag("windows"); + } + Cfg_SetValue("target_family", g_target.m_family); + + if( g_target.m_os_name == "linux" ) + { + Cfg_SetFlag("linux"); + } + Cfg_SetValue("target_env", g_target.m_env_name); + + Cfg_SetValue("target_os", g_target.m_os_name); + Cfg_SetValue("target_pointer_width", FMT(g_target.m_arch.m_pointer_bits)); + Cfg_SetValue("target_endian", g_target.m_arch.m_big_endian ? "big" : "little"); + Cfg_SetValue("target_arch", g_target.m_arch.m_name); + Cfg_SetValueCb("target_has_atomic", [&](const ::std::string& s) { + if(s == "8") return g_target.m_arch.m_atomics.u8; // Has an atomic byte + if(s == "ptr") return g_target.m_arch.m_atomics.ptr; // Has an atomic pointer-sized value + return false; + }); + Cfg_SetValueCb("target_feature", [](const ::std::string& s) { + return false; + }); +} + bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size, size_t& out_align) { TU_MATCHA( (ty.m_data), (te), @@ -55,8 +98,8 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& return true; case ::HIR::CoreType::Usize: case ::HIR::CoreType::Isize: - out_size = POINTER_SIZE_BYTES; - out_align = POINTER_SIZE_BYTES; + out_size = g_target.m_arch.m_pointer_bits / 8; + out_align = g_target.m_arch.m_pointer_bits / 8; return true; case ::HIR::CoreType::F32: out_size = 4; @@ -104,6 +147,11 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& size_t size, align; if( !Target_GetSizeAndAlignOf(sp, t, size,align) ) return false; + if( out_size % align != 0 ) + { + out_size += align; + out_size %= align; + } out_size += size; out_align = ::std::max(out_align, align); } @@ -116,6 +164,9 @@ bool Target_GetSizeAndAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& ), (Function, // Pointer size + out_size = g_target.m_arch.m_pointer_bits / 8; + out_align = g_target.m_arch.m_pointer_bits / 8; + return true; ), (Closure, // TODO. diff --git a/src/trans/target.hpp b/src/trans/target.hpp index 1c081b54..80ba0bf2 100644 --- a/src/trans/target.hpp +++ b/src/trans/target.hpp @@ -10,6 +10,38 @@ #include #include +enum class CodegenMode +{ + Gnu11, + Msvc, +}; + +struct TargetArch +{ + ::std::string m_name; + unsigned m_pointer_bits; + bool m_big_endian; + + struct { + bool u8; + bool u16; + bool u32; + bool u64; + bool ptr; + } m_atomics; +}; +struct TargetSpec +{ + ::std::string m_family; + ::std::string m_os_name; + ::std::string m_env_name; + + CodegenMode m_codegen_mode; + TargetArch m_arch; +}; + + +extern void Target_SetCfg(); extern bool Target_GetSizeOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_size); extern bool Target_GetAlignOf(const Span& sp, const ::HIR::TypeRef& ty, size_t& out_align); -- cgit v1.2.3 From c7f4248191dce493cd43fecd808cf15015271408 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 22 Jun 2017 11:43:41 +0800 Subject: Codegen C - First pass at structured C output (generated, but not compiled) --- Makefile | 3 +- src/trans/codegen_c.cpp | 341 +++++++++++++++++++++++++++---------- src/trans/codegen_c.hpp | 47 +++++ src/trans/codegen_c_structured.cpp | 290 +++++++++++++++++++++++++++++++ 4 files changed, 586 insertions(+), 95 deletions(-) create mode 100644 src/trans/codegen_c.hpp create mode 100644 src/trans/codegen_c_structured.cpp (limited to 'src/trans/codegen_c.cpp') diff --git a/Makefile b/Makefile index 778c59a8..e63b0d0d 100644 --- a/Makefile +++ b/Makefile @@ -110,7 +110,8 @@ OBJ += mir/check.o mir/cleanup.o mir/optimise.o OBJ += mir/check_full.o OBJ += hir/serialise.o hir/deserialise.o hir/serialise_lowlevel.o OBJ += trans/trans_list.o trans/mangling.o -OBJ += trans/enumerate.o trans/monomorphise.o trans/codegen.o trans/codegen_c.o +OBJ += trans/enumerate.o trans/monomorphise.o trans/codegen.o +OBJ += trans/codegen_c.o trans/codegen_c_structured.o OBJ += trans/target.o PCHS := ast/ast.hpp diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 7e0405d1..2612f577 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -14,6 +14,7 @@ #include #include #include +#include "codegen_c.hpp" namespace { @@ -1383,6 +1384,17 @@ namespace { for(unsigned int i = 0; i < code->drop_flags.size(); i ++) { m_of << "\tbool df" << i << " = " << code->drop_flags[i] << ";\n"; } + + { + m_of << "#if 0\n"; + auto nodes = MIR_To_Structured(*code); + for(const auto& node : nodes) + { + emit_fcn_node(mir_res, node, 1); + } + m_of << "#endif\n"; + } + for(unsigned int i = 0; i < code->blocks.size(); i ++) { TRACE_FUNCTION_F(p << " bb" << i); @@ -1458,76 +1470,7 @@ namespace { } ), (Call, - m_of << "\t"; - if( e.fcn.is_Intrinsic() ) - { - const auto& name = e.fcn.as_Intrinsic().name; - const auto& params = e.fcn.as_Intrinsic().params; - emit_intrinsic_call(name, params, e); - m_of << "\tgoto bb" << e.ret_block << ";\n"; - break ; - } - - TU_MATCHA( (e.fcn), (e2), - (Value, - { - ::HIR::TypeRef tmp; - const auto& ty = mir_res.get_lvalue_type(tmp, e2); - MIR_ASSERT(mir_res, ty.m_data.is_Function(), "Call::Value on non-function - " << ty); - if( !ty.m_data.as_Function().m_rettype->m_data.is_Diverge() ) - { - emit_lvalue(e.ret_val); m_of << " = "; - } - } - m_of << "("; emit_lvalue(e2); m_of << ")"; - ), - (Path, - { - bool is_diverge = false; - TU_MATCHA( (e2.m_data), (pe), - (Generic, - const auto& fcn = m_crate.get_function_by_path(sp, pe.m_path); - is_diverge |= fcn.m_return.m_data.is_Diverge(); - // TODO: Monomorph. - ), - (UfcsUnknown, - ), - (UfcsInherent, - // TODO: Check if the return type is ! - is_diverge |= m_resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; }, - [&](const auto& impl) { - // Associated functions - { - auto it = impl.m_methods.find(pe.item); - if( it != impl.m_methods.end() ) { - return it->second.data.m_return.m_data.is_Diverge(); - } - } - // Associated static (undef) - return false; - }); - ), - (UfcsKnown, - // TODO: Check if the return type is ! - ) - ) - if(!is_diverge) - { - emit_lvalue(e.ret_val); m_of << " = "; - } - } - m_of << Trans_Mangle(e2); - ), - (Intrinsic, - MIR_BUG(mir_res, "Intrinsic not expected, should be handled above"); - ) - ) - m_of << "("; - for(unsigned int j = 0; j < e.args.size(); j ++) { - if(j != 0) m_of << ","; - m_of << " "; emit_param(e.args[j]); - } - m_of << " );\n"; + emit_term_call(mir_res, e, 1); m_of << "\tgoto bb" << e.ret_block << ";\n"; ) ) @@ -1537,17 +1480,114 @@ namespace { m_of.flush(); m_mir_res = nullptr; } - void emit_statement(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement& stmt) + + void emit_fcn_node(::MIR::TypeResolve& mir_res, const Node& node, unsigned indent_level) { + auto indent = RepeatLitStr { "\t", static_cast(indent_level) }; + TU_MATCHA( (node), (e), + (Block, + for(size_t i = 0; i < e.nodes.size(); i ++) + { + const auto& snr = e.nodes[i]; + if( snr.node ) { + emit_fcn_node(mir_res, *snr.node, indent_level); + } + else { + DEBUG(mir_res << "BB" << snr.bb_idx); + m_of << indent << "bb" << snr.bb_idx << ":\n"; + const auto& bb = mir_res.m_fcn.blocks.at(snr.bb_idx); + for(const auto& stmt : bb.statements) + { + mir_res.set_cur_stmt(snr.bb_idx, (&stmt - &bb.statements.front())); + this->emit_statement(mir_res, stmt, indent_level); + } + + TU_MATCHA( (bb.terminator), (te), + (Incomplete, ), + (Return, + assert(i == e.nodes.size()-1 && "Return"); + m_of << indent << "return;\n"; + ), + (Goto, + // Ignore (handled by caller) + ), + (Diverge, + ), + (Panic, + ), + (If, + //assert(i == e.nodes.size()-1 && "If"); + ), + (Call, + // TODO: Emit call + emit_term_call(mir_res, te, indent_level); + ), + (Switch, + //assert(i == e.nodes.size()-1 && "Switch"); + ) + ) + } + } + ), + (If, + m_of << indent << "if("; emit_lvalue(*e.val); m_of << ") {\n"; + if( e.arm_true.node ) { + emit_fcn_node(mir_res, *e.arm_true.node, indent_level+1); + } + else { + m_of << indent << "\tgoto bb" << e.arm_true.bb_idx << ";\n"; + } + m_of << indent << "}\n"; + m_of << indent << "else {\n"; + if( e.arm_false.node ) { + emit_fcn_node(mir_res, *e.arm_false.node, indent_level+1); + } + else { + m_of << indent << "\tgoto bb" << e.arm_false.bb_idx << ";\n"; + } + m_of << indent << "}\n"; + ), + (Switch, + this->emit_term_switch(mir_res, *e.val, e.arms.size(), indent_level, [&](auto idx) { + const auto& arm = e.arms.at(idx); + if( arm.node ) { + m_of << "{\n"; + this->emit_fcn_node(mir_res, *arm.node, indent_level+1); + m_of << indent << "\t} "; + if( arm.has_target() && arm.target() != e.next_bb ) { + m_of << "goto bb" << arm.target() << ";"; + } + else { + m_of << "break;"; + } + } + else { + m_of << "goto bb" << arm.bb_idx << ";"; + } + }); + ), + (Loop, + m_of << indent << "for(;;) {\n"; + assert(e.code.node); + assert(e.code.node->is_Block()); + this->emit_fcn_node(mir_res, *e.code.node, indent_level+1); + m_of << indent << "}\n"; + ) + ) + } + + void emit_statement(const ::MIR::TypeResolve& mir_res, const ::MIR::Statement& stmt, unsigned indent_level=1) + { + auto indent = RepeatLitStr { "\t", static_cast(indent_level) }; switch( stmt.tag() ) { case ::MIR::Statement::TAGDEAD: throw ""; case ::MIR::Statement::TAG_ScopeEnd: - m_of << "// " << stmt << "\n"; + m_of << indent << "// " << stmt << "\n"; break; case ::MIR::Statement::TAG_SetDropFlag: { const auto& e = stmt.as_SetDropFlag(); - m_of << "\tdf" << e.idx << " = "; + m_of << indent << "df" << e.idx << " = "; if( e.other == ~0u ) m_of << e.new_val; else @@ -1560,7 +1600,7 @@ namespace { const auto& ty = mir_res.get_lvalue_type(tmp, e.slot); if( e.flag_idx != ~0u ) - m_of << "\tif( df" << e.flag_idx << " ) {\n"; + m_of << indent << "if( df" << e.flag_idx << " ) {\n"; switch( e.kind ) { @@ -1571,7 +1611,7 @@ namespace { // Emit a call to box_free for the type ::HIR::GenericPath box_free { m_crate.get_lang_item_path(sp, "box_free"), { ity->clone() } }; // TODO: This is specific to the official liballoc's owned_box - m_of << "\t" << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n"; + m_of << indent << Trans_Mangle(box_free) << "("; emit_lvalue(e.slot); m_of << "._0._0._0);\n"; } else { @@ -1583,7 +1623,7 @@ namespace { break; } if( e.flag_idx != ~0u ) - m_of << "\t}\n"; + m_of << indent << "}\n"; break; } case ::MIR::Statement::TAG_Asm: { const auto& e = stmt.as_Asm(); @@ -1604,7 +1644,7 @@ namespace { bool is_volatile = H::has_flag(e.flags, "volatile"); bool is_intel = H::has_flag(e.flags, "intel"); - m_of << "\t__asm__ "; + m_of << indent << "__asm__ "; if(is_volatile) m_of << "__volatile__"; // TODO: Convert format string? // TODO: Use a C-specific escaper here. @@ -1642,7 +1682,7 @@ namespace { case ::MIR::Statement::TAG_Assign: { const auto& e = stmt.as_Assign(); DEBUG("- " << e.dst << " = " << e.src); - m_of << "\t"; + m_of << indent; TU_MATCHA( (e.src), (ve), (Use, ::HIR::TypeRef tmp; @@ -1667,17 +1707,17 @@ namespace { emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); } else if( ve.count == 2 ) { - emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n" << indent; emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); } else if( ve.count == 3 ) { - emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n\t"; - emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); m_of << ";\n\t"; + emit_lvalue(e.dst); m_of << ".DATA[0] = "; emit_param(ve.val); m_of << ";\n" << indent; + emit_lvalue(e.dst); m_of << ".DATA[1] = "; emit_param(ve.val); m_of << ";\n" << indent; emit_lvalue(e.dst); m_of << ".DATA[2] = "; emit_param(ve.val); } else { m_of << "for(unsigned int i = 0; i < " << ve.count << "; i ++)\n"; - m_of << "\t\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val); + m_of << indent << "\t"; emit_lvalue(e.dst); m_of << ".DATA[i] = "; emit_param(ve.val); } ), (Borrow, @@ -1704,7 +1744,7 @@ namespace { const ::MIR::LValue& base_ptr = *base_val->as_Deref().val; // Construct the new DST - emit_lvalue(e.dst); m_of << ".META = "; emit_lvalue(base_ptr); m_of << ".META;\n\t"; + 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; } @@ -1879,17 +1919,12 @@ namespace { m_of << ".PTR"; ), (MakeDst, - emit_lvalue(e.dst); - m_of << ".PTR = "; - emit_param(ve.ptr_val); - m_of << ";\n\t"; - emit_lvalue(e.dst); - m_of << ".META = "; - emit_param(ve.meta_val); + 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, for(unsigned int j = 0; j < ve.vals.size(); j ++) { - if( j != 0 ) m_of << ";\n\t"; + if( j != 0 ) m_of << ";\n" << indent; emit_lvalue(e.dst); m_of << "._" << j << " = "; emit_param(ve.vals[j]); @@ -1897,7 +1932,7 @@ namespace { ), (Array, for(unsigned int j = 0; j < ve.vals.size(); j ++) { - if( j != 0 ) m_of << ";\n\t"; + if( j != 0 ) m_of << ";\n" << indent; emit_lvalue(e.dst); m_of << ".DATA[" << j << "] = "; emit_param(ve.vals[j]); } @@ -1963,7 +1998,7 @@ namespace { m_of << ".TAG = " << ve.variant_idx; } if(ve.vals.size() > 0) - m_of << ";\n\t"; + m_of << ";\n" << indent; } for(unsigned int j = 0; j < ve.vals.size(); j ++) @@ -1973,7 +2008,7 @@ namespace { if( ve.vals[j].is_LValue() && m_resolve.is_type_phantom_data( mir_res.get_lvalue_type(tmp, ve.vals[j].as_LValue())) ) continue ; - if( j != 0 ) m_of << ";\n\t"; + if( j != 0 ) m_of << ";\n" << indent; emit_lvalue(e.dst); if(ve.variant_idx != ~0u) m_of << ".DATA.var_" << ve.variant_idx; @@ -1988,6 +2023,124 @@ namespace { break; } } } + void emit_term_switch(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& val, size_t n_arms, unsigned indent_level, ::std::function cb) + { + auto indent = RepeatLitStr { "\t", static_cast(indent_level) }; + + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, val); + MIR_ASSERT(mir_res, ty.m_data.is_Path(), "Switch over non-Path type"); + MIR_ASSERT(mir_res, ty.m_data.as_Path().binding.is_Enum(), "Switch over non-enum"); + const auto* enm = ty.m_data.as_Path().binding.as_Enum(); + + auto it = m_enum_repr_cache.find( ty.m_data.as_Path().path.m_data.as_Generic() ); + if( it != m_enum_repr_cache.end() ) + { + //MIR_ASSERT(mir_res, e.targets.size() == 2, "NonZero optimised representation for an enum without two variants"); + MIR_ASSERT(mir_res, n_arms == 2, "NonZero optimised switch without two arms"); + m_of << indent << "if("; emit_lvalue(val); emit_nonzero_path(it->second); m_of << ")\n"; + m_of << indent; + cb(1); + m_of << "\n"; + m_of << indent << "else\n"; + m_of << indent; + cb(0); + m_of << "\n"; + } + else if( enm->is_value() ) + { + m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n"; + for(size_t j = 0; j < n_arms; j ++) + { + m_of << indent << "case " << enm->get_value(j) << ": "; + cb(j); + m_of << "\n"; + } + m_of << indent << "default: abort();\n"; + m_of << indent << "}\n"; + } + else + { + m_of << indent << "switch("; emit_lvalue(val); m_of << ".TAG) {\n"; + for(size_t j = 0; j < n_arms; j ++) + { + m_of << indent << "case " << j << ": "; + cb(j); + m_of << "\n"; + } + m_of << indent << "default: abort();\n"; + m_of << indent << "}\n"; + } + } + void emit_term_call(const ::MIR::TypeResolve& mir_res, const ::MIR::Terminator::Data_Call& e, unsigned indent_level) + { + auto indent = RepeatLitStr { "\t", static_cast(indent_level) }; + m_of << indent; + + TU_MATCHA( (e.fcn), (e2), + (Value, + { + ::HIR::TypeRef tmp; + const auto& ty = mir_res.get_lvalue_type(tmp, e2); + MIR_ASSERT(mir_res, ty.m_data.is_Function(), "Call::Value on non-function - " << ty); + if( !ty.m_data.as_Function().m_rettype->m_data.is_Diverge() ) + { + emit_lvalue(e.ret_val); m_of << " = "; + } + } + m_of << "("; emit_lvalue(e2); m_of << ")"; + ), + (Path, + { + bool is_diverge = false; + TU_MATCHA( (e2.m_data), (pe), + (Generic, + const auto& fcn = m_crate.get_function_by_path(sp, pe.m_path); + is_diverge |= fcn.m_return.m_data.is_Diverge(); + // TODO: Monomorph. + ), + (UfcsUnknown, + ), + (UfcsInherent, + // TODO: Check if the return type is ! + is_diverge |= m_resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; }, + [&](const auto& impl) { + // Associated functions + { + auto it = impl.m_methods.find(pe.item); + if( it != impl.m_methods.end() ) { + return it->second.data.m_return.m_data.is_Diverge(); + } + } + // Associated static (undef) + return false; + }); + ), + (UfcsKnown, + // TODO: Check if the return type is ! + ) + ) + if(!is_diverge) + { + emit_lvalue(e.ret_val); m_of << " = "; + } + } + m_of << Trans_Mangle(e2); + ), + (Intrinsic, + const auto& name = e.fcn.as_Intrinsic().name; + const auto& params = e.fcn.as_Intrinsic().params; + emit_intrinsic_call(name, params, e); + return ; + ) + ) + m_of << "("; + for(unsigned int j = 0; j < e.args.size(); j ++) { + if(j != 0) m_of << ","; + m_of << " "; emit_param(e.args[j]); + } + m_of << " );\n"; + } private: const ::HIR::TypeRef& monomorphise_fcn_return(::HIR::TypeRef& tmp, const ::HIR::Function& item, const Trans_Params& params) { diff --git a/src/trans/codegen_c.hpp b/src/trans/codegen_c.hpp new file mode 100644 index 00000000..72d0c796 --- /dev/null +++ b/src/trans/codegen_c.hpp @@ -0,0 +1,47 @@ +/* + */ +#pragma once +#include +#include + +class Node; + +struct NodeRef +{ + ::std::unique_ptr node; + size_t bb_idx; + + NodeRef(size_t idx): bb_idx(idx) {} + NodeRef(Node node); + + bool has_target() const; + size_t target() const; + + bool operator==(size_t idx) const { + return !node && bb_idx == idx; + } +}; + +TAGGED_UNION(Node, Block, +(Block, struct { + size_t next_bb; + ::std::vector nodes; + }), +(If, struct { + size_t next_bb; + const ::MIR::LValue* val; + NodeRef arm_false; + NodeRef arm_true; + }), +(Switch, struct { + size_t next_bb; + const ::MIR::LValue* val; + ::std::vector arms; + }), +(Loop, struct { + size_t next_bb; + NodeRef code; + }) +); + +extern ::std::vector MIR_To_Structured(const ::MIR::Function& fcn); diff --git a/src/trans/codegen_c_structured.cpp b/src/trans/codegen_c_structured.cpp new file mode 100644 index 00000000..e89d7589 --- /dev/null +++ b/src/trans/codegen_c_structured.cpp @@ -0,0 +1,290 @@ +/* + * MRustC - Rust Compiler + * - By John Hodge (Mutabah/thePowersGang) + * + * trans/codegen_c_structured.cpp + * - Converts MIR into a semi-structured form + */ +#include +#include +#include +#include "codegen_c.hpp" + +NodeRef::NodeRef(Node node_data): + node(new Node(mv$(node_data))), + bb_idx(SIZE_MAX) +{ +} +bool NodeRef::has_target() const +{ + if( node ) { + TU_MATCHA( (*this->node), (e), + (Block, + return e.next_bb != SIZE_MAX; + ), + (If, + return e.next_bb != SIZE_MAX; + ), + (Switch, + return e.next_bb != SIZE_MAX; + ), + (Loop, + return e.next_bb != SIZE_MAX; + ) + ) + throw ""; + } + else { + return true; + } +} +size_t NodeRef::target() const +{ + if( node ) { + TU_MATCHA( (*this->node), (e), + (Block, + return e.next_bb; + ), + (If, + return e.next_bb; + ), + (Switch, + return e.next_bb; + ), + (Loop, + return e.next_bb; + ) + ) + throw ""; + } + else { + return bb_idx; + } +} + +class Converter +{ + const ::MIR::Function& m_fcn; +public: + ::std::vector m_block_ref_count; + ::std::vector m_blocks_used; + + Converter(const ::MIR::Function& fcn): + m_fcn(fcn) + { + + } + + // Returns true if the passed block is the start of a self-contained sequence of blocks + bool bb_is_opening(size_t bb_idx) + { + if( m_blocks_used[bb_idx] ) { + return false; + } + else if( m_block_ref_count[bb_idx] > 1 ) { + // TODO: Determine if these multiple references are from the block looping back on itself + return false; + } + else { + return true; + } + } + NodeRef process_node_ref(size_t bb_idx) + { + if( bb_is_opening(bb_idx) ) { + return NodeRef( process_node(bb_idx) ); + } + else { + return NodeRef(bb_idx); + } + } + + Node process_node(size_t bb_idx) + { + TRACE_FUNCTION_F(bb_idx); + ::std::vector refs; + for(;;) + { + DEBUG("bb_idx = " << bb_idx); + bool stop = false; + assert( !m_blocks_used[bb_idx] ); + m_blocks_used[bb_idx] = true; + + refs.push_back( NodeRef(bb_idx) ); + + const auto& blk = m_fcn.blocks.at(bb_idx); + DEBUG("> " << blk.terminator); + TU_MATCHA( (blk.terminator), (te), + (Incomplete, + stop = true; + ), + (Goto, + bb_idx = te; + ), + (Panic, + TODO(Span(), "Panic"); + ), + (Diverge, + stop = true; + ), + (Return, + stop = true; + ), + (If, + auto arm0 = process_node_ref(te.bb0); + auto arm1 = process_node_ref(te.bb1); + if( arm0.has_target() && arm1.has_target() ) { + if( arm0.target() == arm1.target() ) { + bb_idx = arm0.target(); + } + else { + stop = true; + } + } + else if( arm0.has_target() ) { + bb_idx = arm0.target(); + } + else if( arm1.has_target() ) { + bb_idx = arm1.target(); + } + else { + // No target from either arm + stop = false; + } + refs.push_back(Node::make_If({ bb_idx, &te.cond, mv$(arm0), mv$(arm1) })); + ), + (Switch, + ::std::vector arms; + ::std::vector next_blocks; + for(auto& tgt : te.targets) + { + arms.push_back( process_node_ref(tgt) ); + if( arms.back().has_target() ) + { + next_blocks.push_back( arms.back().target() ); + } + } + ::std::sort(next_blocks.begin(), next_blocks.end()); + size_t exit_bb = SIZE_MAX; + if(!next_blocks.empty()) + { + size_t cur = next_blocks[0]; + size_t cur_count = 0; + size_t max_count = 0; + for(auto b : next_blocks) + { + if(cur == b) { + cur_count ++; + } + else { + if( cur_count > max_count ) { + exit_bb = cur; + } + cur = b; + cur_count = 1; + } + } + if( cur_count > max_count ) { + exit_bb = cur; + } + } + refs.push_back(Node::make_Switch({ exit_bb, &te.val, mv$(arms) })); + stop = true; + ), + (Call, + // NOTE: Let the panic arm just be a goto + bb_idx = te.ret_block; + ) + ) + + if( stop ) + { + break; + } + + // If `bb_idx` is in `refs` as a NodeRef + auto it = ::std::find(refs.begin(), refs.end(), bb_idx); + if( it != refs.end() ) + { + // Wrap ibb_idxms from `it` to `refs.end()` in a `loop` block + ::std::vector loop_blocks; + loop_blocks.reserve(refs.end() - it); + for(auto it2 = it; it2 != refs.end(); ++it2) + loop_blocks.push_back( mv$(*it2) ); + auto loop_node = NodeRef( Node::make_Block({ SIZE_MAX, mv$(loop_blocks) }) ); + + refs.push_back( Node::make_Loop({ SIZE_MAX, mv$(loop_node) }) ); + // TODO: If there is only one `goto` in the above loop, assume it's the target + DEBUG("Loop"); + break; + } + else if( bb_is_opening(bb_idx) ) + { + DEBUG("Destination " << bb_idx << " is unreferenced+unvisited"); + } + else + { + break; + } + } + + return Node::make_Block({ bb_idx, mv$(refs) }); + } +}; + +::std::vector MIR_To_Structured(const ::MIR::Function& fcn) +{ + Converter conv(fcn); + conv.m_block_ref_count.resize( fcn.blocks.size() ); + conv.m_block_ref_count[0] += 1; + for(const auto& blk : fcn.blocks) + { + TU_MATCHA( (blk.terminator), (te), + (Incomplete, + ), + (Goto, + conv.m_block_ref_count[te] += 1; + ), + (Panic, + conv.m_block_ref_count[te.dst] += 1; + ), + (Diverge, + ), + (Return, + ), + (If, + conv.m_block_ref_count[te.bb0] += 1; + conv.m_block_ref_count[te.bb1] += 1; + ), + (Switch, + for(auto tgt : te.targets) + conv.m_block_ref_count[tgt] += 1; + ), + (Call, + conv.m_block_ref_count[te.ret_block] += 1; + conv.m_block_ref_count[te.panic_block] += 1; + ) + ) + } + + // First Block: Becomes a block in structured output + // - Terminator selects what the next block will be + // - + + // Find next unvisited block + conv.m_blocks_used.resize( fcn.blocks.size() ); + ::std::vector nodes; + for(size_t bb_idx = 0; bb_idx < fcn.blocks.size(); bb_idx ++) + { + if( conv.m_blocks_used[bb_idx] ) + continue; + + nodes.push_back( conv.process_node(bb_idx) ); + } + + + // Return. + return nodes; +} + + -- cgit v1.2.3 From 11d2a7732c5d1c53aee384b2ca4fdc672c2cc1ae Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jul 2017 17:20:53 +0800 Subject: Codegen C - (minor) Comment before enum definitions --- src/trans/codegen_c.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 2612f577..5d87517d 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -666,6 +666,7 @@ namespace { } } + m_of << "// enum " << p << "\n"; if( nonzero_path.size() > 0 ) { MIR_ASSERT(*m_mir_res, nonzero_path[0] == 0, ""); -- cgit v1.2.3 From 0a79b158cee37a880b77c640f874fbf5a0493dc3 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jul 2017 18:36:01 +0800 Subject: Codegen C - Fix indenting in destructors --- src/trans/codegen_c.cpp | 47 ++++++++++++++++++++++------------------------- 1 file changed, 22 insertions(+), 25 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index 5d87517d..be34e3db 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -297,7 +297,7 @@ namespace { // TODO: This is very specific to the structure of the official liballoc's Box. m_of << "\t"; emit_ctype(args[0].second, FMT_CB(ss, ss << "arg0"; )); m_of << " = rv->_0._0._0;\n"; // Call destructor of inner data - emit_destructor_call( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) }), *ity, true); + emit_destructor_call( ::MIR::LValue::make_Deref({ box$(::MIR::LValue::make_Argument({0})) }), *ity, true, 1); // Emit a call to box_free for the type m_of << "\t" << Trans_Mangle(box_free) << "(arg0);\n"; @@ -398,7 +398,7 @@ namespace { auto fld_lv = ::MIR::LValue::make_Field({ box$(self), 0 }); for(const auto& ity : te) { - emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false); + emit_destructor_call(fld_lv, ity, /*unsized_valid=*/false, 1); fld_lv.as_Field().field_index ++; } m_of << "}\n"; @@ -529,7 +529,7 @@ namespace { const auto& fld = e[i]; fld_lv.as_Field().field_index = i; - emit_destructor_call(fld_lv, monomorph(fld.ent), true); + emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1); } ), (Named, @@ -538,7 +538,7 @@ namespace { const auto& fld = e[i].second; fld_lv.as_Field().field_index = i; - emit_destructor_call(fld_lv, monomorph(fld.ent), true); + emit_destructor_call(fld_lv, monomorph(fld.ent), true, 1); } ) ) @@ -774,7 +774,7 @@ namespace { m_of << "\tif( ! (*rv)"; emit_nonzero_path(nonzero_path); m_of << " ) {\n"; for(const auto& fld : item.m_variants[1].second.as_Tuple()) { - emit_destructor_call(fld_lv, monomorph(fld.ent), false); + emit_destructor_call(fld_lv, monomorph(fld.ent), false, 2); fld_lv.as_Field().field_index ++; } m_of << "\t}\n"; @@ -805,7 +805,7 @@ namespace { fld_lv.as_Field().field_index = i; const auto& fld = e[i]; - emit_destructor_call(fld_lv, monomorph(fld.ent), false); + emit_destructor_call(fld_lv, monomorph(fld.ent), false, 2); } m_of << "\tbreak;\n"; ), @@ -815,7 +815,7 @@ namespace { { fld_lv.as_Field().field_index = i; const auto& fld = e[i]; - emit_destructor_call(fld_lv, monomorph(fld.second.ent), false); + emit_destructor_call(fld_lv, monomorph(fld.second.ent), false, 2); } m_of << "\tbreak;\n"; ) @@ -1620,7 +1620,7 @@ namespace { } break; case ::MIR::eDropKind::DEEP: - emit_destructor_call(e.slot, ty, false); + emit_destructor_call(e.slot, ty, false, indent_level + (e.flag_idx != ~0u ? 1 : 0)); break; } if( e.flag_idx != ~0u ) @@ -2389,7 +2389,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 ); + 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 */ ); } else if( name == "needs_drop" ) { // Returns `true` if the actual type given as `T` requires drop glue; @@ -2729,8 +2729,9 @@ namespace { m_of << ";\n"; } - void emit_destructor_call(const ::MIR::LValue& slot, const ::HIR::TypeRef& ty, bool unsized_valid) + void emit_destructor_call(const ::MIR::LValue& slot, const ::HIR::TypeRef& ty, bool unsized_valid, unsigned indent_level) { + auto indent = RepeatLitStr { "\t", static_cast(indent_level) }; TU_MATCHA( (ty.m_data), (te), // Impossible (Diverge, ), @@ -2751,7 +2752,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 ); + emit_destructor_call( ::MIR::LValue::make_Deref({ box$(slot.clone()) }), *te.inner, true, indent_level ); } ), (Path, @@ -2762,13 +2763,13 @@ namespace { switch( metadata_type(ty) ) { case MetadataType::None: - m_of << "\t" << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n"; + m_of << indent << Trans_Mangle(p) << "(&"; emit_lvalue(slot); m_of << ");\n"; break; case MetadataType::Slice: make_fcn = "make_sliceptr"; if(0) case MetadataType::TraitObject: make_fcn = "make_traitobjptr"; - m_of << "\t" << Trans_Mangle(p) << "( " << make_fcn << "("; + m_of << indent << Trans_Mangle(p) << "( " << make_fcn << "("; if( slot.is_Deref() ) { emit_lvalue(*slot.as_Deref().val); @@ -2791,12 +2792,9 @@ namespace { // Emit destructors for all entries if( te.size_val > 0 ) { - ::MIR::LValue lv = ::MIR::LValue::make_Field({ box$(slot.clone()), 0 }); - for(unsigned int i = 0; i < te.size_val; i ++) - { - lv.as_Field().field_index = i; - emit_destructor_call(lv, *te.inner, false); - } + 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); + m_of << "\n" << indent << "}"; } ), (Tuple, @@ -2807,7 +2805,7 @@ namespace { 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)); + emit_destructor_call(lv, te[i], unsized_valid && (i == te.size()-1), indent_level); } } ), @@ -2817,7 +2815,7 @@ namespace { 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 << "((VTABLE_HDR*)"; emit_lvalue(*lvp->as_Deref().val); m_of << ".META)->drop("; + m_of << indent << "((VTABLE_HDR*)"; emit_lvalue(*lvp->as_Deref().val); m_of << ".META)->drop("; if( const auto* ve = slot.opt_Deref() ) { emit_lvalue(*ve->val); m_of << ".PTR"; @@ -2834,10 +2832,9 @@ namespace { 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 << ")"); // Call destructor on all entries - m_of << "for(unsigned i = 0; i < "; emit_lvalue(*lvp->as_Deref().val); m_of << ".META; i++) {"; - m_of << "\t\t"; - emit_destructor_call(::MIR::LValue::make_Index({ box$(slot.clone()), box$(::MIR::LValue::make_Local(~0u)) }), *te.inner, false); - m_of << "\n\t}"; + 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 << "\n" << indent << "}"; ) ) } -- cgit v1.2.3 From c4e88b3c49736e71534c918a83956885c052beb8 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 6 Jul 2017 16:29:30 +0800 Subject: MIR - Add (but don't use) a SwitchValue terminator --- src/hir/serialise.cpp | 24 ++++ src/hir_conv/bind.cpp | 3 + src/mir/check.cpp | 17 +++ src/mir/check_full.cpp | 8 ++ src/mir/cleanup.cpp | 3 + src/mir/dump.cpp | 18 +++ src/mir/helpers.cpp | 10 ++ src/mir/mir.cpp | 34 +++++ src/mir/mir.hpp | 14 ++ src/mir/optimise.cpp | 263 ++++++++++++++----------------------- src/trans/codegen_c.cpp | 9 +- src/trans/codegen_c_structured.cpp | 8 ++ src/trans/enumerate.cpp | 6 + src/trans/monomorphise.cpp | 8 ++ 14 files changed, 259 insertions(+), 166 deletions(-) (limited to 'src/trans/codegen_c.cpp') diff --git a/src/hir/serialise.cpp b/src/hir/serialise.cpp index cddbf0b8..78efe261 100644 --- a/src/hir/serialise.cpp +++ b/src/hir/serialise.cpp @@ -77,6 +77,9 @@ namespace { m_out.write_count(e.first); serialise(e.second); } + //void serialise(::MIR::BasicBlockId val) { + // m_out.write_count(val); + //} void serialise_type(const ::HIR::TypeRef& ty) { @@ -531,6 +534,12 @@ namespace { for(auto t : e.targets) m_out.write_count(t); ), + (SwitchValue, + serialise(e.val); + m_out.write_count(e.def_target); + serialise_vec(e.targets); + serialise(e.values); + ), (Call, m_out.write_count(e.ret_block); m_out.write_count(e.panic_block); @@ -540,6 +549,21 @@ namespace { ) ) } + void serialise(const ::MIR::SwitchValues& sv) + { + m_out.write_tag( static_cast(sv.tag()) ); + TU_MATCHA( (sv), (e), + (Unsigned, + serialise_vec(e); + ), + (Signed, + serialise_vec(e); + ), + (String, + serialise_vec(e); + ) + ) + } void serialise(const ::MIR::CallTarget& ct) { m_out.write_tag( static_cast(ct.tag()) ); diff --git a/src/hir_conv/bind.cpp b/src/hir_conv/bind.cpp index 1b0f61b6..beac3b84 100644 --- a/src/hir_conv/bind.cpp +++ b/src/hir_conv/bind.cpp @@ -617,6 +617,9 @@ namespace { (Switch, H::visit_lvalue(*this, te.val); ), + (SwitchValue, + H::visit_lvalue(*this, te.val); + ), (Call, H::visit_lvalue(*this, te.ret_val); TU_MATCHA( (te.fcn), (e2), diff --git a/src/mir/check.cpp b/src/mir/check.cpp index 58bcaf55..7c0cd4d8 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -452,6 +452,14 @@ void MIR_Validate_ValState(::MIR::TypeResolve& state, const ::MIR::Function& fcn add_to_visit( tgt, path, val_state ); } ), + (SwitchValue, + val_state.ensure_valid( state, e.val ); + for(const auto& tgt : e.targets) + { + add_to_visit( tgt, path, val_state ); + } + add_to_visit( e.def_target, path, val_state ); + ), (Call, if( e.fcn.is_Value() ) val_state.ensure_valid( state, e.fcn.as_Value() ); @@ -534,6 +542,12 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path PUSH_BB(e.targets[i], "Switch V" << i); } ), + (SwitchValue, + for(unsigned int i = 0; i < e.targets.size(); i++ ) { + PUSH_BB(e.targets[i], "SwitchValue " << i); + } + PUSH_BB(e.def_target, "SwitchValue def"); + ), (Call, PUSH_BB(e.ret_block, "Call ret"); PUSH_BB(e.panic_block, "Call panic"); @@ -829,6 +843,9 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path (Switch, // Check that the condition is an enum ), + (SwitchValue, + // Check that the condition's type matches the values + ), (Call, if( e.fcn.is_Value() ) { diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index a153aca7..1f86c40a 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -995,6 +995,14 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio todo_queue.push_back( ::std::make_pair(te.targets[i], i == te.targets.size()-1 ? mv$(state) : state.clone()) ); } ), + (SwitchValue, + state.ensure_lvalue_valid(mir_res, te.val); + for(size_t i = 0; i < te.targets.size(); i ++) + { + todo_queue.push_back( ::std::make_pair(te.targets[i], state.clone()) ); + } + todo_queue.push_back( ::std::make_pair(te.def_target, mv$(state)) ); + ), (Call, if(const auto* e = te.fcn.opt_Value()) { diff --git a/src/mir/cleanup.cpp b/src/mir/cleanup.cpp index 3dda81dc..f26f2bdd 100644 --- a/src/mir/cleanup.cpp +++ b/src/mir/cleanup.cpp @@ -1103,6 +1103,9 @@ void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, (Switch, MIR_Cleanup_LValue(state, mutator, e.val); ), + (SwitchValue, + MIR_Cleanup_LValue(state, mutator, e.val); + ), (Call, MIR_Cleanup_LValue(state, mutator, e.ret_val); if( e.fcn.is_Value() ) { diff --git a/src/mir/dump.cpp b/src/mir/dump.cpp index 4e53cf5b..a029023a 100644 --- a/src/mir/dump.cpp +++ b/src/mir/dump.cpp @@ -131,6 +131,24 @@ namespace { m_os << j << " => bb" << e.targets[j] << ", "; m_os << "}\n"; ), + (SwitchValue, + m_os << "switch " << FMT_M(e.val) << " {"; + TU_MATCHA( (e.values), (ve), + (Unsigned, + for(unsigned int j = 0; j < e.targets.size(); j ++) + m_os << ve[j] << " => bb" << e.targets[j] << ", "; + ), + (Signed, + for(unsigned int j = 0; j < e.targets.size(); j ++) + m_os << (ve[j] >= 0 ? "+" : "") << ve[j] << " => bb" << e.targets[j] << ", "; + ), + (String, + for(unsigned int j = 0; j < e.targets.size(); j ++) + m_os << "\"" << ve[j] << "\" => bb" << e.targets[j] << ", "; + ) + ) + m_os << "_ => bb" << e.def_target << "}\n"; + ), (Call, m_os << FMT_M(e.ret_val) << " = "; TU_MATCHA( (e.fcn), (e2), diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index ea5709d1..e51c9180 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -481,6 +481,9 @@ namespace visit { (Switch, rv |= visit_mir_lvalue(e.val, ValUsage::Read, cb); ), + (SwitchValue, + rv |= visit_mir_lvalue(e.val, ValUsage::Read, cb); + ), (Call, if( e.fcn.is_Value() ) { rv |= visit_mir_lvalue(e.fcn.as_Value(), ValUsage::Read, cb); @@ -951,6 +954,13 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime( m_states_to_do.push_back( ::std::make_pair(te.targets[i], mv$(s)) ); } ), + (SwitchValue, + for(size_t i = 0; i < te.targets.size(); i ++) + { + m_states_to_do.push_back( ::std::make_pair(te.targets[i], state.clone()) ); + } + m_states_to_do.push_back( ::std::make_pair(te.def_target, mv$(state)) ); + ), (Call, if( te.ret_val == m_lv ) { diff --git a/src/mir/mir.cpp b/src/mir/mir.cpp index 3f7057ff..09e978f9 100644 --- a/src/mir/mir.cpp +++ b/src/mir/mir.cpp @@ -419,6 +419,24 @@ namespace MIR { os << j << " => bb" << e.targets[j] << ", "; os << ")"; ), + (SwitchValue, + os << "SwitchValue( " << e.val << " : "; + TU_MATCHA( (e.values), (ve), + (Unsigned, + for(unsigned int j = 0; j < e.targets.size(); j ++) + os << ve[j] << " => bb" << e.targets[j] << ", "; + ), + (Signed, + for(unsigned int j = 0; j < e.targets.size(); j ++) + os << (ve[j] >= 0 ? "+" : "") << ve[j] << " => bb" << e.targets[j] << ", "; + ), + (String, + for(unsigned int j = 0; j < e.targets.size(); j ++) + os << "\"" << ve[j] << "\" => bb" << e.targets[j] << ", "; + ) + ) + os << "else bb" << e.def_target << ")"; + ), (Call, os << "Call( " << e.ret_val << " = "; TU_MATCHA( (e.fcn), (e2), @@ -604,3 +622,19 @@ namespace MIR { throw ""; } +::MIR::SwitchValues MIR::SwitchValues::clone() const +{ + TU_MATCHA( (*this), (ve), + (Unsigned, + return ve; + ), + (Signed, + return ve; + ), + (String, + return ve; + ) + ) + throw ""; +} + diff --git a/src/mir/mir.hpp b/src/mir/mir.hpp index 6254bf42..987e0498 100644 --- a/src/mir/mir.hpp +++ b/src/mir/mir.hpp @@ -211,6 +211,14 @@ TAGGED_UNION(CallTarget, Intrinsic, ::HIR::PathParams params; }) ); +TAGGED_UNION_EX(SwitchValues, (), Unsigned, ( + (Unsigned, ::std::vector), + (Signed, ::std::vector), + (String, ::std::vector<::std::string>) + ), (),(), ( + SwitchValues clone() const; + ) + ); TAGGED_UNION(Terminator, Incomplete, (Incomplete, struct {}), // Block isn't complete (ERROR in output) @@ -227,6 +235,12 @@ TAGGED_UNION(Terminator, Incomplete, LValue val; ::std::vector targets; }), + (SwitchValue, struct { + LValue val; + BasicBlockId def_target; + ::std::vector targets; + SwitchValues values; + }), (Call, struct { BasicBlockId ret_block; BasicBlockId panic_block; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 3ef629b1..73cbaa04 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -222,6 +222,9 @@ namespace { (Switch, visit_mir_lvalue_mut(e.val, ValUsage::Read, cb); ), + (SwitchValue, + visit_mir_lvalue_mut(e.val, ValUsage::Read, cb); + ), (Call, if( e.fcn.is_Value() ) { visit_mir_lvalue_mut(e.fcn.as_Value(), ValUsage::Read, cb); @@ -392,6 +395,42 @@ namespace { } + void visit_terminator_target_mut(::MIR::Terminator& term, ::std::function cb) { + TU_MATCHA( (term), (e), + (Incomplete, + ), + (Return, + ), + (Diverge, + ), + (Goto, + cb(e); + ), + (Panic, + ), + (If, + cb(e.bb0); + cb(e.bb1); + ), + (Switch, + for(auto& target : e.targets) + cb(target); + ), + (SwitchValue, + for(auto& target : e.targets) + cb(target); + cb(e.def_target); + ), + (Call, + cb(e.ret_block); + cb(e.panic_block); + ) + ) + } + void visit_terminator_target(const ::MIR::Terminator& term, ::std::function cb) { + visit_terminator_target_mut(const_cast<::MIR::Terminator&>(term), cb); + } + void visit_blocks_mut(::MIR::TypeResolve& state, ::MIR::Function& fcn, ::std::function cb) { ::std::vector visited( fcn.blocks.size() ); @@ -406,44 +445,16 @@ namespace { cb(bb, block); - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target(block.terminator, [&](auto e){ if( !visited[e] ) to_visit.push_back(e); - ), - (Panic, - ), - (If, - if( !visited[e.bb0] ) - to_visit.push_back(e.bb0); - if( !visited[e.bb1] ) - to_visit.push_back(e.bb1); - ), - (Switch, - for(auto& target : e.targets) - if( !visited[target] ) - to_visit.push_back(target); - ), - (Call, - if( !visited[e.ret_block] ) - to_visit.push_back(e.ret_block); - if( !visited[e.panic_block] ) - to_visit.push_back(e.panic_block); - ) - ) + }); } } void visit_blocks(::MIR::TypeResolve& state, const ::MIR::Function& fcn, ::std::function cb) { visit_blocks_mut(state, const_cast<::MIR::Function&>(fcn), [cb](auto id, auto& blk){ cb(id, blk); }); } - bool statement_invalidates_lvalue(const ::MIR::Statement& stmt, const ::MIR::LValue& lv) { return visit_mir_lvalues(stmt, [&](const auto& v, auto vu) { @@ -651,32 +662,10 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn) } } - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target_mut(block.terminator, [&](auto& e) { if( &fcn.blocks[e] != &block ) e = get_new_target(state, e); - ), - (Panic, - ), - (If, - e.bb0 = get_new_target(state, e.bb0); - e.bb1 = get_new_target(state, e.bb1); - ), - (Switch, - for(auto& target : e.targets) - target = get_new_target(state, target); - ), - (Call, - e.ret_block = get_new_target(state, e.ret_block); - e.panic_block = get_new_target(state, e.panic_block); - ) - ) + }); } // >> Merge blocks where a block goto-s to a single-use block. @@ -694,40 +683,10 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn) visited[bb] = true; const auto& block = fcn.blocks[bb]; - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target(block.terminator, [&](const auto& e) { if( !visited[e] ) to_visit.push_back(e); uses[e] ++; - ), - (Panic, - ), - (If, - if( !visited[e.bb0] ) to_visit.push_back(e.bb0); - if( !visited[e.bb1] ) to_visit.push_back(e.bb1); - uses[e.bb0] ++; - uses[e.bb1] ++; - ), - (Switch, - for(auto& target : e.targets) - { - if( !visited[target] ) - to_visit.push_back(target); - uses[target] ++; - } - ), - (Call, - if( !visited[e.ret_block] ) to_visit.push_back(e.ret_block); - if( !visited[e.panic_block] ) to_visit.push_back(e.panic_block); - uses[e.ret_block] ++; - uses[e.panic_block] ++; - ) - ) + }); } unsigned int i = 0; @@ -970,6 +929,13 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool arms.push_back( bbi + this->bb_base ); return ::MIR::Terminator::make_Switch({ this->clone_lval(se.val), mv$(arms) }); ), + (SwitchValue, + ::std::vector<::MIR::BasicBlockId> arms; + arms.reserve(se.targets.size()); + for(const auto& bbi : se.targets) + arms.push_back( bbi + this->bb_base ); + return ::MIR::Terminator::make_SwitchValue({ this->clone_lval(se.val), se.def_target + this->bb_base, mv$(arms), se.values.clone() }); + ), (Call, ::MIR::CallTarget tgt; TU_MATCHA( (se.fcn), (ste), @@ -1412,6 +1378,30 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) if( ae.targets != be.targets ) return false; ), + (SwitchValue, + if( ae.val != be.val ) + return false; + if( ae.targets != be.targets ) + return false; + if( ae.def_target != be.def_target ) + return false; + if( ae.values.tag() != be.values.tag() ) + return false; + TU_MATCHA( (ae.values, be.values), (ae2, be2), + (Unsigned, + if( ae2 != be2 ) + return false; + ), + (Signed, + if( ae2 != be2 ) + return false; + ), + (String, + if( ae2 != be2 ) + return false; + ) + ) + ), (Call, if( ae.ret_block != be.ret_block ) return false; @@ -1483,32 +1473,9 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) { if( bb.terminator.tag() == ::MIR::Terminator::TAGDEAD ) continue ; - TU_MATCHA( (bb.terminator), (te), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target_mut(bb.terminator, [&](auto& te) { patch_tgt(te); - ), - (Panic, - patch_tgt(te.dst); - ), - (If, - patch_tgt(te.bb0); - patch_tgt(te.bb1); - ), - (Switch, - for(auto& tgt : te.targets) - patch_tgt(tgt); - ), - (Call, - patch_tgt(te.ret_block); - patch_tgt(te.panic_block); - ) - ) + }); //DEBUG("- " << bb.terminator); } @@ -1548,7 +1515,7 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio visited[bb] = true; const auto& block = fcn.blocks[bb]; - auto ref_block = [&](auto idx) { + visit_terminator_target(block.terminator, [&](const auto& idx) { if( !visited[idx] ) to_visit.push_back(idx); if(block_uses[idx] == 0) @@ -1556,34 +1523,7 @@ bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Functio else block_origins[idx] = SIZE_MAX; block_uses[idx] ++; - }; - TU_MATCHA( (block.terminator), (e), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, - ref_block(e); - ), - (Panic, - ), - (If, - ref_block(e.bb0); - ref_block(e.bb1); - ), - (Switch, - for(auto& target : e.targets) - { - ref_block(target); - } - ), - (Call, - ref_block(e.ret_block); - ref_block(e.panic_block); - ) - ) + }); } } @@ -2293,6 +2233,11 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F 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) ) @@ -2847,6 +2792,12 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn 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); @@ -2939,6 +2890,11 @@ void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& pa for(auto dst : te.targets) todo.push_back(Todo { dst, ++branches, info.level + 1 }); ), + (SwitchValue, + for(auto dst : te.targets) + todo.push_back(Todo { dst, ++branches, info.level + 1 }); + todo.push_back(Todo { te.def_target, info.branch_count, info.level + 1 }); + ), (Call, todo.push_back(Todo { te.ret_block, info.branch_count, info.level + 1 }); todo.push_back(Todo { te.panic_block, ++branches, info.level + 1 }); @@ -2963,32 +2919,9 @@ void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& pa { auto fix_bb_idx = [&](auto idx){ return ::std::find(idxes.begin(), idxes.end(), idx) - idxes.begin(); }; new_block_list.push_back( mv$(fcn.blocks[idx]) ); - TU_MATCHA( (new_block_list.back().terminator), (te), - (Incomplete, - ), - (Return, - ), - (Diverge, - ), - (Goto, + visit_terminator_target_mut(new_block_list.back().terminator, [&](auto& te){ te = fix_bb_idx(te); - ), - (Panic, - te.dst = fix_bb_idx(te.dst); - ), - (If, - te.bb0 = fix_bb_idx(te.bb0); - te.bb1 = fix_bb_idx(te.bb1); - ), - (Switch, - for(auto& tgt : te.targets) - tgt = fix_bb_idx(tgt); - ), - (Call, - te.ret_block = fix_bb_idx(te.ret_block); - te.panic_block = fix_bb_idx(te.panic_block); - ) - ) + }); } fcn.blocks = mv$(new_block_list); } diff --git a/src/trans/codegen_c.cpp b/src/trans/codegen_c.cpp index be34e3db..c554d4ab 100644 --- a/src/trans/codegen_c.cpp +++ b/src/trans/codegen_c.cpp @@ -1386,6 +1386,7 @@ namespace { m_of << "\tbool df" << i << " = " << code->drop_flags[i] << ";\n"; } + if( false ) { m_of << "#if 0\n"; auto nodes = MIR_To_Structured(*code); @@ -1445,7 +1446,7 @@ namespace { auto it = m_enum_repr_cache.find( ty.m_data.as_Path().path.m_data.as_Generic() ); if( it != m_enum_repr_cache.end() ) { - MIR_ASSERT(mir_res, e.targets.size() == 2, ""); + MIR_ASSERT(mir_res, e.targets.size() == 2, "Non-zero optimised type a variant count that isn't 2"); m_of << "\tif("; emit_lvalue(e.val); emit_nonzero_path(it->second); m_of << ")\n"; m_of << "\t\tgoto bb" << e.targets[1] << ";\n"; m_of << "\telse\n"; @@ -1470,6 +1471,9 @@ namespace { m_of << "\t}\n"; } ), + (SwitchValue, + MIR_TODO(mir_res, "SwitchValue in C codegen"); + ), (Call, emit_term_call(mir_res, e, 1); m_of << "\tgoto bb" << e.ret_block << ";\n"; @@ -1524,6 +1528,9 @@ namespace { emit_term_call(mir_res, te, indent_level); ), (Switch, + //assert(i == e.nodes.size()-1 && "Switch"); + ), + (SwitchValue, //assert(i == e.nodes.size()-1 && "Switch"); ) ) diff --git a/src/trans/codegen_c_structured.cpp b/src/trans/codegen_c_structured.cpp index e89d7589..888f9a26 100644 --- a/src/trans/codegen_c_structured.cpp +++ b/src/trans/codegen_c_structured.cpp @@ -191,6 +191,9 @@ public: refs.push_back(Node::make_Switch({ exit_bb, &te.val, mv$(arms) })); stop = true; ), + (SwitchValue, + TODO(Span(), "SwitchValue"); + ), (Call, // NOTE: Let the panic arm just be a goto bb_idx = te.ret_block; @@ -260,6 +263,11 @@ public: for(auto tgt : te.targets) conv.m_block_ref_count[tgt] += 1; ), + (SwitchValue, + for(auto tgt : te.targets) + conv.m_block_ref_count[tgt] += 1; + conv.m_block_ref_count[te.def_target] += 1; + ), (Call, conv.m_block_ref_count[te.ret_block] += 1; conv.m_block_ref_count[te.panic_block] += 1; diff --git a/src/trans/enumerate.cpp b/src/trans/enumerate.cpp index fb577959..41489e2b 100644 --- a/src/trans/enumerate.cpp +++ b/src/trans/enumerate.cpp @@ -935,6 +935,9 @@ void Trans_Enumerate_Types(EnumState& state) (Switch, H::visit_lvalue(tv,pp,fcn, te.val); ), + (SwitchValue, + H::visit_lvalue(tv,pp,fcn, te.val); + ), (Call, if( te.fcn.is_Value() ) H::visit_lvalue(tv,pp,fcn, te.fcn.as_Value()); @@ -1476,6 +1479,9 @@ void Trans_Enumerate_FillFrom_MIR(EnumState& state, const ::MIR::Function& code, (Switch, Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); ), + (SwitchValue, + Trans_Enumerate_FillFrom_MIR_LValue(state, e.val, pp); + ), (Call, Trans_Enumerate_FillFrom_MIR_LValue(state, e.ret_val, pp); TU_MATCHA( (e.fcn), (e2), diff --git a/src/trans/monomorphise.cpp b/src/trans/monomorphise.cpp index f708060d..b752a5bc 100644 --- a/src/trans/monomorphise.cpp +++ b/src/trans/monomorphise.cpp @@ -295,6 +295,14 @@ namespace { e.targets }); ), + (SwitchValue, + terminator = ::MIR::Terminator::make_SwitchValue({ + monomorph_LValue(resolve, params, e.val), + e.def_target, + e.targets, + e.values.clone() + }); + ), (Call, struct H { static ::MIR::CallTarget monomorph_calltarget(const ::StaticTraitResolve& resolve, const Trans_Params& params, const ::MIR::CallTarget& ct) { -- cgit v1.2.3