From 9f8d9fa81be1c11b50bc5ced608a3bd18a53de21 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 9 Jun 2017 10:26:29 +0800 Subject: Fix build broken by MSVC port --- src/ast/path.cpp | 4 ++-- src/hir_expand/erased_types.cpp | 2 ++ src/hir_typeck/expr_cs.cpp | 4 +--- src/include/span.hpp | 1 + src/include/synext_decorator.hpp | 4 ++-- src/include/synext_macro.hpp | 4 ++-- 6 files changed, 10 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/ast/path.cpp b/src/ast/path.cpp index ebec5d5a..9976cae5 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -198,10 +198,10 @@ void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std unsigned int idx = it - ent.variants().begin(); DEBUG("Bound to enum variant '" << name << "' (#" << idx << ")"); - ::AST::PathBinding::Data_EnumVar tmp; + ::AST::PathBinding::Data_EnumVar tmp = {}; tmp.enum_ = &ent; tmp.idx = idx; - m_binding = PathBinding::make_EnumVar(tmp); + m_binding = PathBinding::make_EnumVar( mv$(tmp) ); } Path& Path::operator+=(const Path& other) diff --git a/src/hir_expand/erased_types.cpp b/src/hir_expand/erased_types.cpp index aca58207..f5fbe27a 100644 --- a/src/hir_expand/erased_types.cpp +++ b/src/hir_expand/erased_types.cpp @@ -16,6 +16,8 @@ const ::HIR::Function& HIR_Expand_ErasedType_GetFunction(const Span& sp, const S const ::HIR::Function* fcn_ptr = nullptr; switch(origin_path.m_data.tag()) { + case ::HIR::Path::Data::TAGDEAD: + BUG(Span(), "DEAD in ErasedType - " << origin_path); case ::HIR::Path::Data::TAG_UfcsUnknown: BUG(Span(), "UfcsUnknown in ErasedType - " << origin_path); case ::HIR::Path::Data::TAG_Generic: { diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index eb922414..9b5e4f5d 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -1643,9 +1643,7 @@ namespace { (Function, fix_param_count(sp, this->context, *e.type, false, node.m_path, ie.m_params, e.params); - const auto& fcn_params = e.params; - const auto& trait_params = e.trait.m_params; - auto monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &e.trait.m_params, &e.params); + auto monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &e.trait.m_params, &e.params); ::HIR::FunctionType ft { ie.m_unsafe, ie.m_abi, box$( monomorphise_type_with(sp, ie.m_return, monomorph_cb) ), diff --git a/src/include/span.hpp b/src/include/span.hpp index 11ffc005..ddb08ae3 100644 --- a/src/include/span.hpp +++ b/src/include/span.hpp @@ -30,6 +30,7 @@ struct ProtoSpan }; struct Span { + //::std::unique_ptr outer_span; // Expansion target for macros RcString filename; unsigned int start_line; diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp index 4988c624..3374fc88 100644 --- a/src/include/synext_decorator.hpp +++ b/src/include/synext_decorator.hpp @@ -67,9 +67,9 @@ struct DecoratorDef ::std::string name; ::std::unique_ptr def; DecoratorDef(::std::string name, ::std::unique_ptr def): + prev(nullptr), name(::std::move(name)), - def(::std::move(def)), - prev(nullptr) + def(::std::move(def)) { Register_Synext_Decorator_Static(this); } diff --git a/src/include/synext_macro.hpp b/src/include/synext_macro.hpp index c109b56e..0abaf0fe 100644 --- a/src/include/synext_macro.hpp +++ b/src/include/synext_macro.hpp @@ -35,9 +35,9 @@ struct MacroDef ::std::string name; ::std::unique_ptr def; MacroDef(::std::string name, ::std::unique_ptr def) : + prev(nullptr), name(::std::move(name)), - def(::std::move(def)), - prev(nullptr) + def(::std::move(def)) { Register_Synext_Macro_Static(this); } -- cgit v1.2.3 From 374a42466ee4e9d0a25ef65f73b84e3c870d6f79 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 9 Jun 2017 10:58:34 +0800 Subject: Fix use of hard tabs --- src/ast/path.cpp | 18 +-- src/common.hpp | 4 +- src/expand/mod.cpp | 38 ++--- src/hir/deserialise.cpp | 20 +-- src/hir/dump.cpp | 16 +-- src/hir/from_ast.cpp | 2 +- src/hir/type.cpp | 2 +- src/hir/type.hpp | 10 +- src/hir_expand/erased_types.cpp | 42 +++--- src/hir_expand/ufcs_everything.cpp | 6 +- src/hir_typeck/expr_check.cpp | 4 +- src/hir_typeck/expr_cs.cpp | 284 ++++++++++++++++++------------------- src/hir_typeck/helpers.cpp | 4 +- src/hir_typeck/static.cpp | 116 +++++++-------- src/include/debug.hpp | 12 +- src/include/synext_decorator.hpp | 22 +-- src/include/synext_macro.hpp | 22 +-- src/include/tagged_union.hpp | 18 +-- src/main.cpp | 58 ++++---- src/mir/check.cpp | 8 +- src/mir/check_full.cpp | 6 +- src/parse/lex.cpp | 8 +- 22 files changed, 360 insertions(+), 360 deletions(-) (limited to 'src') diff --git a/src/ast/path.cpp b/src/ast/path.cpp index 9976cae5..37428b1a 100644 --- a/src/ast/path.cpp +++ b/src/ast/path.cpp @@ -190,17 +190,17 @@ void Path::bind_variable(unsigned int slot) } void Path::bind_enum_var(const Enum& ent, const ::std::string& name, const ::std::vector& /*args*/) { - auto it = ::std::find_if(ent.variants().begin(), ent.variants().end(), [&](const auto& x) { return x.m_name == name; }); - if( it == ent.variants().end() ) - { - throw ParseError::Generic("Enum variant not found"); - } - unsigned int idx = it - ent.variants().begin(); + auto it = ::std::find_if(ent.variants().begin(), ent.variants().end(), [&](const auto& x) { return x.m_name == name; }); + if( it == ent.variants().end() ) + { + throw ParseError::Generic("Enum variant not found"); + } + unsigned int idx = it - ent.variants().begin(); DEBUG("Bound to enum variant '" << name << "' (#" << idx << ")"); - ::AST::PathBinding::Data_EnumVar tmp = {}; - tmp.enum_ = &ent; - tmp.idx = idx; + ::AST::PathBinding::Data_EnumVar tmp = {}; + tmp.enum_ = &ent; + tmp.idx = idx; m_binding = PathBinding::make_EnumVar( mv$(tmp) ); } diff --git a/src/common.hpp b/src/common.hpp index 55e0f833..dec40191 100644 --- a/src/common.hpp +++ b/src/common.hpp @@ -12,7 +12,7 @@ #include #ifdef _MSC_VER -#define __attribute__(x) +#define __attribute__(x) /* no-op */ #endif #define FMT(ss) (dynamic_cast< ::std::stringstream&>(::std::stringstream() << ss).str()) @@ -22,7 +22,7 @@ #define rc_new$(...) ::make_shared_ptr(::std::move(__VA_ARGS__)) #include "include/debug.hpp" -#include "include/rustic.hpp" // slice and option +#include "include/rustic.hpp" // slice and option #include "include/compile_error.hpp" template diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 01786284..1a534c0b 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -15,8 +15,8 @@ #include #include "cfg.hpp" -DecoratorDef* g_decorators_list = nullptr; -MacroDef* g_macros_list = nullptr; +DecoratorDef* g_decorators_list = nullptr; +MacroDef* g_macros_list = nullptr; ::std::map< ::std::string, ::std::unique_ptr > g_decorators; ::std::map< ::std::string, ::std::unique_ptr > g_macros; @@ -26,18 +26,18 @@ void Expand_Expr(::AST::Crate& crate, LList modstack, AST::E void Expand_Expr(::AST::Crate& crate, LList modstack, ::std::shared_ptr& node); void Register_Synext_Decorator(::std::string name, ::std::unique_ptr handler) { - g_decorators.insert(::std::make_pair( mv$(name), mv$(handler) )); + g_decorators.insert(::std::make_pair( mv$(name), mv$(handler) )); } void Register_Synext_Macro(::std::string name, ::std::unique_ptr handler) { - g_macros.insert(::std::make_pair( mv$(name), mv$(handler) )); + g_macros.insert(::std::make_pair( mv$(name), mv$(handler) )); } void Register_Synext_Decorator_Static(DecoratorDef* def) { - def->prev = g_decorators_list; - g_decorators_list = def; + def->prev = g_decorators_list; + g_decorators_list = def; } void Register_Synext_Macro_Static(MacroDef* def) { - def->prev = g_macros_list; - g_macros_list = def; + def->prev = g_macros_list; + g_macros_list = def; } @@ -1074,17 +1074,17 @@ void Expand_Mod_IndexAnon(::AST::Crate& crate, ::AST::Module& mod) } void Expand(::AST::Crate& crate) { - // Fill macro/decorator map from init list - while(g_decorators_list) - { - g_decorators.insert(::std::make_pair( mv$(g_decorators_list->name), mv$(g_decorators_list->def) )); - g_decorators_list = g_decorators_list->prev; - } - while (g_macros_list) - { - g_macros.insert(::std::make_pair(mv$(g_macros_list->name), mv$(g_macros_list->def))); - g_macros_list = g_macros_list->prev; - } + // Fill macro/decorator map from init list + while(g_decorators_list) + { + g_decorators.insert(::std::make_pair( mv$(g_decorators_list->name), mv$(g_decorators_list->def) )); + g_decorators_list = g_decorators_list->prev; + } + while (g_macros_list) + { + g_macros.insert(::std::make_pair(mv$(g_macros_list->name), mv$(g_macros_list->def))); + g_macros_list = g_macros_list->prev; + } auto modstack = LList(nullptr, &crate.m_root_module); diff --git a/src/hir/deserialise.cpp b/src/hir/deserialise.cpp index 0ff4d63b..f4dfdf19 100644 --- a/src/hir/deserialise.cpp +++ b/src/hir/deserialise.cpp @@ -505,10 +505,10 @@ namespace { ::HIR::Linkage deserialise_linkage() { - ::HIR::Linkage l; - l.type = ::HIR::Linkage::Type::Auto; - l.name = m_in.read_string(); - return l; + ::HIR::Linkage l; + l.type = ::HIR::Linkage::Type::Auto; + l.name = m_in.read_string(); + return l; } // - Value items @@ -1004,12 +1004,12 @@ namespace { deserialise_vec< ::std::string>() }); case 3: { - ::MIR::Statement::Data_SetDropFlag sdf; - sdf.idx = static_cast(m_in.read_count()); - sdf.new_val = m_in.read_bool(); - sdf.other = static_cast(m_in.read_count()); - return ::MIR::Statement::make_SetDropFlag(sdf); - } + ::MIR::Statement::Data_SetDropFlag sdf; + sdf.idx = static_cast(m_in.read_count()); + sdf.new_val = m_in.read_bool(); + sdf.other = static_cast(m_in.read_count()); + return ::MIR::Statement::make_SetDropFlag(sdf); + } case 4: return ::MIR::Statement::make_ScopeEnd({ deserialise_vec(), diff --git a/src/hir/dump.cpp b/src/hir/dump.cpp index 649116e0..75dde59f 100644 --- a/src/hir/dump.cpp +++ b/src/hir/dump.cpp @@ -262,13 +262,13 @@ namespace { void visit_constant(::HIR::ItemPath p, ::HIR::Constant& item) override { m_os << indent() << "const " << p.get_name() << ": " << item.m_type << " = " << item.m_value_res; - if( item.m_value ) - { - m_os << " /*= "; - item.m_value->visit(*this); - m_os << "*/"; - } - m_os << ";\n"; + if( item.m_value ) + { + m_os << " /*= "; + item.m_value->visit(*this); + m_os << "*/"; + } + m_os << ";\n"; } // - Misc @@ -530,7 +530,7 @@ namespace { m_os << ", "; } m_os << ")"; - m_os << "/* : " << node.m_res_type << " */"; + m_os << "/* : " << node.m_res_type << " */"; } void visit(::HIR::ExprNode_CallValue& node) override { diff --git a/src/hir/from_ast.cpp b/src/hir/from_ast.cpp index c0a3151e..e0429aca 100644 --- a/src/hir/from_ast.cpp +++ b/src/hir/from_ast.cpp @@ -702,7 +702,7 @@ { if( ptr->m_datatype == CORETYPE_UINT || ptr->m_datatype == CORETYPE_ANY ) { - // TODO: Limit check. + // TODO: Limit check. auto size_val = static_cast( ptr->m_value ); return ::HIR::TypeRef::new_array( mv$(inner), size_val ); } diff --git a/src/hir/type.cpp b/src/hir/type.cpp index 7dd8dc80..c672b3bd 100644 --- a/src/hir/type.cpp +++ b/src/hir/type.cpp @@ -781,7 +781,7 @@ bool ::HIR::TypeRef::match_test_generics(const Span& sp, const ::HIR::TypeRef& x (Enum , return ::HIR::TypeRef::TypePathBinding(e); ) ) assert(!"Fell off end of clone_binding"); - throw ""; + throw ""; } diff --git a/src/hir/type.hpp b/src/hir/type.hpp index a832e8e9..cc0894d2 100644 --- a/src/hir/type.hpp +++ b/src/hir/type.hpp @@ -178,8 +178,8 @@ public: Data m_data; TypeRef(): - m_data(Data::make_Infer({ ~0u, InferClass::None })) - {} + m_data(Data::make_Infer({ ~0u, InferClass::None })) + {} TypeRef(TypeRef&& ) = default; TypeRef(const TypeRef& ) = delete; TypeRef& operator=(TypeRef&& ) = default; @@ -212,9 +212,9 @@ public: static TypeRef new_diverge() { return TypeRef(Data::make_Diverge({})); } - static TypeRef new_infer(unsigned int idx = ~0u, InferClass ty_class = InferClass::None) { - return TypeRef(Data::make_Infer({idx, ty_class})); - } + static TypeRef new_infer(unsigned int idx = ~0u, InferClass ty_class = InferClass::None) { + return TypeRef(Data::make_Infer({idx, ty_class})); + } static TypeRef new_borrow(BorrowType bt, TypeRef inner) { return TypeRef(Data::make_Borrow({bt, box$(mv$(inner))})); } diff --git a/src/hir_expand/erased_types.cpp b/src/hir_expand/erased_types.cpp index f5fbe27a..caf42a79 100644 --- a/src/hir_expand/erased_types.cpp +++ b/src/hir_expand/erased_types.cpp @@ -14,23 +14,23 @@ const ::HIR::Function& HIR_Expand_ErasedType_GetFunction(const Span& sp, const StaticTraitResolve& resolve, const ::HIR::Path& origin_path, t_cb_generic& monomorph_cb, ::HIR::PathParams& impl_params) { const ::HIR::Function* fcn_ptr = nullptr; - switch(origin_path.m_data.tag()) - { + switch(origin_path.m_data.tag()) + { case ::HIR::Path::Data::TAGDEAD: BUG(Span(), "DEAD in ErasedType - " << origin_path); - case ::HIR::Path::Data::TAG_UfcsUnknown: - BUG(Span(), "UfcsUnknown in ErasedType - " << origin_path); - case ::HIR::Path::Data::TAG_Generic: { - const auto& pe = origin_path.m_data.as_Generic(); - monomorph_cb = monomorphise_type_get_cb(sp, nullptr, nullptr, &pe.m_params); - fcn_ptr = &resolve.m_crate.get_function_by_path(sp, pe.m_path); - } break; - case ::HIR::Path::Data::TAG_UfcsKnown: - // NOTE: This isn't possible yet (will it be? or will it expand to an associated type?) - TODO(sp, "Replace ErasedType - " << origin_path << " with source (UfcsKnown)"); - break; - case ::HIR::Path::Data::TAG_UfcsInherent: { - const auto& pe = origin_path.m_data.as_UfcsInherent(); + case ::HIR::Path::Data::TAG_UfcsUnknown: + BUG(Span(), "UfcsUnknown in ErasedType - " << origin_path); + case ::HIR::Path::Data::TAG_Generic: { + const auto& pe = origin_path.m_data.as_Generic(); + monomorph_cb = monomorphise_type_get_cb(sp, nullptr, nullptr, &pe.m_params); + fcn_ptr = &resolve.m_crate.get_function_by_path(sp, pe.m_path); + } break; + case ::HIR::Path::Data::TAG_UfcsKnown: + // NOTE: This isn't possible yet (will it be? or will it expand to an associated type?) + TODO(sp, "Replace ErasedType - " << origin_path << " with source (UfcsKnown)"); + break; + case ::HIR::Path::Data::TAG_UfcsInherent: { + const auto& pe = origin_path.m_data.as_UfcsInherent(); // 1. Find correct impl block for the path const ::HIR::TypeImpl* impl_ptr = nullptr; resolve.m_crate.find_type_impls(*pe.type, [&](const auto& ty)->const auto& { return ty; }, @@ -54,16 +54,16 @@ const ::HIR::Function& HIR_Expand_ErasedType_GetFunction(const Span& sp, const S return ::HIR::Compare::Equal; }); for(const auto& t : impl_params.m_types) - { + { if( t == ::HIR::TypeRef() ) - { + { TODO(sp, "Handle ErasedType where an impl parameter comes from a bound - " << origin_path); - } - } + } + } monomorph_cb = monomorphise_type_get_cb(sp, &*pe.type, &impl_params, &pe.params); - } break; - } + } break; + } assert(fcn_ptr); return *fcn_ptr; } diff --git a/src/hir_expand/ufcs_everything.cpp b/src/hir_expand/ufcs_everything.cpp index 44921105..adae855c 100644 --- a/src/hir_expand/ufcs_everything.cpp +++ b/src/hir_expand/ufcs_everything.cpp @@ -289,7 +289,7 @@ namespace { ASSERT_BUG(sp, ty_slot == ty_val, "Types must equal for non-operator assignment, " << ty_slot << " != " << ty_val); return ; _(Shr): {langitem = "shr_assign"; opname = "shr_assign"; } if(0) - _(Shl): {langitem = "shl_assign"; opname = "shl_assign"; } + _(Shl): {langitem = "shl_assign"; opname = "shl_assign"; } if( is_op_valid_shift(ty_slot, ty_val) ) { return ; } @@ -385,8 +385,8 @@ namespace { auto ty_r_ref = ::HIR::TypeRef::new_borrow( ::HIR::BorrowType::Shared, ty_r.clone() ); ::std::vector< ::HIR::ExprNodeP> args; - auto sp_left = node.m_left ->span(); - auto sp_right = node.m_right->span(); + auto sp_left = node.m_left ->span(); + auto sp_right = node.m_right->span(); args.push_back(NEWNODE(ty_l_ref.clone(), Borrow, sp_left , ::HIR::BorrowType::Shared, mv$(node.m_left ) )); args.push_back(NEWNODE(ty_r_ref.clone(), Borrow, sp_right, ::HIR::BorrowType::Shared, mv$(node.m_right) )); diff --git a/src/hir_typeck/expr_check.cpp b/src/hir_typeck/expr_check.cpp index fe67865f..a5d34186 100644 --- a/src/hir_typeck/expr_check.cpp +++ b/src/hir_typeck/expr_check.cpp @@ -640,7 +640,7 @@ namespace { fcn_ptr = &fcn; - monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &trait_params, &path_params); + monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &trait_params, &path_params); ), (UfcsUnknown, TODO(sp, "Hit a UfcsUnknown (" << path << ") - Is this an error?"); @@ -672,7 +672,7 @@ namespace { // Create monomorphise callback const auto& fcn_params = e.params; - monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &impl_params, &fcn_params); + monomorph_cb = monomorphise_type_get_cb(sp, &*e.type, &impl_params, &fcn_params); ) ) diff --git a/src/hir_typeck/expr_cs.cpp b/src/hir_typeck/expr_cs.cpp index 9b5e4f5d..de7f05ec 100644 --- a/src/hir_typeck/expr_cs.cpp +++ b/src/hir_typeck/expr_cs.cpp @@ -2366,148 +2366,148 @@ namespace { const auto& ty = *ty_p; DEBUG("- ty = " << ty); - if( const auto* e = ty.m_data.opt_Closure() ) - { - for( const auto& arg : e->m_arg_types ) - node.m_arg_types.push_back(arg.clone()); - node.m_arg_types.push_back(e->m_rettype->clone()); - node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Unknown; - } - else if( const auto* e = ty.m_data.opt_Function() ) - { - for( const auto& arg : e->m_arg_types ) - node.m_arg_types.push_back(arg.clone()); - node.m_arg_types.push_back(e->m_rettype->clone()); - node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn; - } - else if( ty.m_data.is_Infer() ) - { - // No idea yet - return ; - } - else - { - ::HIR::TypeRef fcn_args_tup; - ::HIR::TypeRef fcn_ret; - - // TODO: Use `find_trait_impls` instead of two different calls - // - This will get the TraitObject impl search too - - // Locate an impl of FnOnce (exists for all other Fn* traits) - unsigned int count = 0; - this->context.m_resolve.find_trait_impls(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool { - count++; - - auto tup = impl.get_trait_ty_param(0); - if (!tup.m_data.is_Tuple()) - ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); - fcn_args_tup = mv$(tup); - - fcn_ret = impl.get_type("Output"); - DEBUG("[visit:_CallValue] fcn_args_tup=" << fcn_args_tup << ", fcn_ret=" << fcn_ret); - return cmp == ::HIR::Compare::Equal; - }); - DEBUG("Found " << count << " impls of FnOnce"); - if(count > 1) { - return; - } - if(count == 1) - { - - // 3. Locate the most permissive implemented Fn* trait (Fn first, then FnMut, then assume just FnOnce) - // NOTE: Borrowing is added by the expansion to CallPath - if( this->context.m_resolve.find_trait_impls(node.span(), lang_Fn, trait_pp, ty, [&](auto impl, auto cmp) { - // TODO: Take the value of `cmp` into account - fcn_ret = impl.get_type("Output"); - return true; - //return cmp == ::HIR::Compare::Equal; - }) ) - { - DEBUG("-- Using Fn"); - node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn; - - this->context.equate_types_assoc(node.span(), node.m_res_type, lang_Fn, ::make_vec1(fcn_args_tup.clone()), ty, "Output"); - } - else if( this->context.m_resolve.find_trait_impls(node.span(), lang_FnMut, trait_pp, ty, [&](auto impl, auto cmp) { - // TODO: Take the value of `cmp` into account - fcn_ret = impl.get_type("Output"); - return true; - //return cmp == ::HIR::Compare::Equal; - }) ) - { - DEBUG("-- Using FnMut"); - node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnMut; - - this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnMut, ::make_vec1(fcn_args_tup.clone()), ty, "Output"); - } - else - { - DEBUG("-- Using FnOnce (default)"); - node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnOnce; - - this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnOnce, ::make_vec1(fcn_args_tup.clone()), ty, "Output"); - } - - // If the return type wasn't found in the impls, emit it as a UFCS - if(fcn_ret == ::HIR::TypeRef()) - { - fcn_ret = ::HIR::TypeRef(::HIR::Path(::HIR::Path::Data::make_UfcsKnown({ - box$(ty.clone()), - // - Clone argument tuple, as it's stolen into cache below - ::HIR::GenericPath(lang_FnOnce, ::HIR::PathParams(fcn_args_tup.clone())), - "Output", - {} - }))); - } - } - else if( const auto* e = ty.m_data.opt_Borrow() ) - { - deref_count++; - ty_p = &this->context.get_type(*e->inner); - DEBUG("Deref " << ty << " -> " << *ty_p); - keep_looping = true; - continue; - } - else - { - if( !ty.m_data.is_Generic() ) - { - bool found = this->context.m_resolve.find_trait_impls_crate(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool { - if (cmp == ::HIR::Compare::Fuzzy) - TODO(node.span(), "Handle fuzzy match - " << impl); - - auto tup = impl.get_trait_ty_param(0); - if (!tup.m_data.is_Tuple()) - ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); - fcn_args_tup = mv$(tup); - fcn_ret = impl.get_type("Output"); - ASSERT_BUG(node.span(), fcn_ret != ::HIR::TypeRef(), "Impl didn't have a type for Output - " << impl); - return true; - }); - if (found) { - // Fill cache and leave the TU_MATCH - node.m_arg_types = mv$(fcn_args_tup.m_data.as_Tuple()); - node.m_arg_types.push_back(mv$(fcn_ret)); - node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Unknown; - break; // leaves TU_MATCH - } - } - if( const auto* next_ty_p = this->context.m_resolve.autoderef(node.span(), ty, tmp_type) ) - { - DEBUG("Deref (autoderef) " << ty << " -> " << *next_ty_p); - deref_count++; - ty_p = next_ty_p; - keep_looping = true; - continue; - } - - // Didn't find anything. Error? - ERROR(node.span(), E0000, "Unable to find an implementation of Fn*" << trait_pp << " for " << this->context.m_ivars.fmt_type(ty)); - } - - node.m_arg_types = mv$(fcn_args_tup.m_data.as_Tuple()); - node.m_arg_types.push_back(mv$(fcn_ret)); - } + if( const auto* e = ty.m_data.opt_Closure() ) + { + for( const auto& arg : e->m_arg_types ) + node.m_arg_types.push_back(arg.clone()); + node.m_arg_types.push_back(e->m_rettype->clone()); + node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Unknown; + } + else if( const auto* e = ty.m_data.opt_Function() ) + { + for( const auto& arg : e->m_arg_types ) + node.m_arg_types.push_back(arg.clone()); + node.m_arg_types.push_back(e->m_rettype->clone()); + node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn; + } + else if( ty.m_data.is_Infer() ) + { + // No idea yet + return ; + } + else + { + ::HIR::TypeRef fcn_args_tup; + ::HIR::TypeRef fcn_ret; + + // TODO: Use `find_trait_impls` instead of two different calls + // - This will get the TraitObject impl search too + + // Locate an impl of FnOnce (exists for all other Fn* traits) + unsigned int count = 0; + this->context.m_resolve.find_trait_impls(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool { + count++; + + auto tup = impl.get_trait_ty_param(0); + if (!tup.m_data.is_Tuple()) + ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); + fcn_args_tup = mv$(tup); + + fcn_ret = impl.get_type("Output"); + DEBUG("[visit:_CallValue] fcn_args_tup=" << fcn_args_tup << ", fcn_ret=" << fcn_ret); + return cmp == ::HIR::Compare::Equal; + }); + DEBUG("Found " << count << " impls of FnOnce"); + if(count > 1) { + return; + } + if(count == 1) + { + + // 3. Locate the most permissive implemented Fn* trait (Fn first, then FnMut, then assume just FnOnce) + // NOTE: Borrowing is added by the expansion to CallPath + if( this->context.m_resolve.find_trait_impls(node.span(), lang_Fn, trait_pp, ty, [&](auto impl, auto cmp) { + // TODO: Take the value of `cmp` into account + fcn_ret = impl.get_type("Output"); + return true; + //return cmp == ::HIR::Compare::Equal; + }) ) + { + DEBUG("-- Using Fn"); + node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Fn; + + this->context.equate_types_assoc(node.span(), node.m_res_type, lang_Fn, ::make_vec1(fcn_args_tup.clone()), ty, "Output"); + } + else if( this->context.m_resolve.find_trait_impls(node.span(), lang_FnMut, trait_pp, ty, [&](auto impl, auto cmp) { + // TODO: Take the value of `cmp` into account + fcn_ret = impl.get_type("Output"); + return true; + //return cmp == ::HIR::Compare::Equal; + }) ) + { + DEBUG("-- Using FnMut"); + node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnMut; + + this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnMut, ::make_vec1(fcn_args_tup.clone()), ty, "Output"); + } + else + { + DEBUG("-- Using FnOnce (default)"); + node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::FnOnce; + + this->context.equate_types_assoc(node.span(), node.m_res_type, lang_FnOnce, ::make_vec1(fcn_args_tup.clone()), ty, "Output"); + } + + // If the return type wasn't found in the impls, emit it as a UFCS + if(fcn_ret == ::HIR::TypeRef()) + { + fcn_ret = ::HIR::TypeRef(::HIR::Path(::HIR::Path::Data::make_UfcsKnown({ + box$(ty.clone()), + // - Clone argument tuple, as it's stolen into cache below + ::HIR::GenericPath(lang_FnOnce, ::HIR::PathParams(fcn_args_tup.clone())), + "Output", + {} + }))); + } + } + else if( const auto* e = ty.m_data.opt_Borrow() ) + { + deref_count++; + ty_p = &this->context.get_type(*e->inner); + DEBUG("Deref " << ty << " -> " << *ty_p); + keep_looping = true; + continue; + } + else + { + if( !ty.m_data.is_Generic() ) + { + bool found = this->context.m_resolve.find_trait_impls_crate(node.span(), lang_FnOnce, trait_pp, ty, [&](auto impl, auto cmp)->bool { + if (cmp == ::HIR::Compare::Fuzzy) + TODO(node.span(), "Handle fuzzy match - " << impl); + + auto tup = impl.get_trait_ty_param(0); + if (!tup.m_data.is_Tuple()) + ERROR(node.span(), E0000, "FnOnce expects a tuple argument, got " << tup); + fcn_args_tup = mv$(tup); + fcn_ret = impl.get_type("Output"); + ASSERT_BUG(node.span(), fcn_ret != ::HIR::TypeRef(), "Impl didn't have a type for Output - " << impl); + return true; + }); + if (found) { + // Fill cache and leave the TU_MATCH + node.m_arg_types = mv$(fcn_args_tup.m_data.as_Tuple()); + node.m_arg_types.push_back(mv$(fcn_ret)); + node.m_trait_used = ::HIR::ExprNode_CallValue::TraitUsed::Unknown; + break; // leaves TU_MATCH + } + } + if( const auto* next_ty_p = this->context.m_resolve.autoderef(node.span(), ty, tmp_type) ) + { + DEBUG("Deref (autoderef) " << ty << " -> " << *next_ty_p); + deref_count++; + ty_p = next_ty_p; + keep_looping = true; + continue; + } + + // Didn't find anything. Error? + ERROR(node.span(), E0000, "Unable to find an implementation of Fn*" << trait_pp << " for " << this->context.m_ivars.fmt_type(ty)); + } + + node.m_arg_types = mv$(fcn_args_tup.m_data.as_Tuple()); + node.m_arg_types.push_back(mv$(fcn_ret)); + } } while( keep_looping ); if( deref_count > 0 ) diff --git a/src/hir_typeck/helpers.cpp b/src/hir_typeck/helpers.cpp index a3fe9b1c..c860c6ce 100644 --- a/src/hir_typeck/helpers.cpp +++ b/src/hir_typeck/helpers.cpp @@ -436,7 +436,7 @@ void HMTypeInferrence::add_ivars(::HIR::TypeRef& type) e.index = this->new_ivar(); this->get_type(type).m_data.as_Infer().ty_class = e.ty_class; this->mark_change(); - DEBUG("New ivar " << type); + DEBUG("New ivar " << type); } ), (Diverge, @@ -2020,7 +2020,7 @@ void TraitResolution::expand_associated_types_inplace__UfcsKnown(const Span& sp, ERROR(sp, E0000, "Couldn't find assocated type " << pe.item << " in " << pe.trait); if( impl.has_magic_params() ) { - } + } // TODO: What if there's multiple impls? DEBUG("Converted UfcsKnown - " << e.path << " = " << ty); diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index d8b692c9..8a4dba50 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -331,39 +331,39 @@ bool StaticTraitResolve::find_impl( if( m_crate.get_trait_by_path(sp, trait_path).m_is_marker ) { - struct H { - static bool find_impl__auto_trait_check(const StaticTraitResolve& self, - const Span& sp, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams* trait_params, const ::HIR::TypeRef& type, - t_cb_find_impl found_cb, - const ::HIR::MarkerImpl& impl, bool& out_rv - ) - { - DEBUG("- Auto " << (impl.is_positive ? "Pos" : "Neg") - << " impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " " << impl.m_params.fmt_bounds()); - if (impl.is_positive) - { - return self.find_impl__check_crate_raw(sp, trait_path, trait_params, type, impl.m_params, impl.m_trait_args, impl.m_type, - [&](auto impl_params, auto placeholders, auto cmp)->bool { - //rv = found_cb( ImplRef(impl_params, trait_path, impl, mv$(placeholders)), (cmp == ::HIR::Compare::Fuzzy) ); - out_rv = found_cb(ImplRef(&type, trait_params, &null_assoc), cmp == ::HIR::Compare::Fuzzy); - return out_rv; - }); - } - else - { - return self.find_impl__check_crate_raw(sp, trait_path, trait_params, type, impl.m_params, impl.m_trait_args, impl.m_type, - [&](auto impl_params, auto placeholders, auto cmp)->bool { - out_rv = false; - return true; - }); - } - } - }; + struct H { + static bool find_impl__auto_trait_check(const StaticTraitResolve& self, + const Span& sp, const ::HIR::SimplePath& trait_path, const ::HIR::PathParams* trait_params, const ::HIR::TypeRef& type, + t_cb_find_impl found_cb, + const ::HIR::MarkerImpl& impl, bool& out_rv + ) + { + DEBUG("- Auto " << (impl.is_positive ? "Pos" : "Neg") + << " impl" << impl.m_params.fmt_args() << " " << trait_path << impl.m_trait_args << " for " << impl.m_type << " " << impl.m_params.fmt_bounds()); + if (impl.is_positive) + { + return self.find_impl__check_crate_raw(sp, trait_path, trait_params, type, impl.m_params, impl.m_trait_args, impl.m_type, + [&](auto impl_params, auto placeholders, auto cmp)->bool { + //rv = found_cb( ImplRef(impl_params, trait_path, impl, mv$(placeholders)), (cmp == ::HIR::Compare::Fuzzy) ); + out_rv = found_cb(ImplRef(&type, trait_params, &null_assoc), cmp == ::HIR::Compare::Fuzzy); + return out_rv; + }); + } + else + { + return self.find_impl__check_crate_raw(sp, trait_path, trait_params, type, impl.m_params, impl.m_trait_args, impl.m_type, + [&](auto impl_params, auto placeholders, auto cmp)->bool { + out_rv = false; + return true; + }); + } + } + }; // Positive/negative impls bool rv = false; ret = this->m_crate.find_auto_trait_impls(trait_path, type, cb_ident, [&](const auto& impl)->bool { - return H::find_impl__auto_trait_check(*this, sp, trait_path, trait_params, type, found_cb, impl, rv); + return H::find_impl__auto_trait_check(*this, sp, trait_path, trait_params, type, found_cb, impl, rv); }); if(ret) return rv; @@ -592,9 +592,9 @@ bool StaticTraitResolve::find_impl__check_crate_raw( // Bounds for(const auto& bound : impl_params_def.m_bounds) { - if( const auto* ep = bound.opt_TraitBound() ) - { - const auto& e = *ep; + if( const auto* ep = bound.opt_TraitBound() ) + { + const auto& e = *ep; DEBUG("Trait bound " << e.type << " : " << e.trait); auto b_ty_mono = monomorphise_type_with(sp, e.type, cb_monomorph); @@ -665,11 +665,11 @@ bool StaticTraitResolve::find_impl__check_crate_raw( return false; } } - } - else // bound.opt_TraitBound() - { - // Ignore - } + } + else // bound.opt_TraitBound() + { + // Ignore + } } return found_cb( mv$(impl_params), mv$(placeholders), match ); @@ -705,9 +705,9 @@ bool StaticTraitResolve::find_impl__check_crate( }; // - If the type is a path (struct/enum/...), search for impls for all contained types. - if( const auto* ep = type.m_data.opt_Path() ) - { - const auto& e = *ep; + if( const auto* ep = type.m_data.opt_Path() ) + { + const auto& e = *ep; ::HIR::Compare res = ::HIR::Compare::Equal; TU_MATCH( ::HIR::Path::Data, (e.path.m_data), (pe), (Generic, @@ -828,9 +828,9 @@ bool StaticTraitResolve::find_impl__check_crate( ) ) return res; - } - else if( const auto* ep = type.m_data.opt_Tuple() ) - { + } + else if( const auto* ep = type.m_data.opt_Tuple() ) + { ::HIR::Compare res = ::HIR::Compare::Equal; for(const auto& sty : *ep) { @@ -839,11 +839,11 @@ bool StaticTraitResolve::find_impl__check_crate( return ::HIR::Compare::Unequal; } return res; - } + } else if( const auto* e = type.m_data.opt_Array() ) - { + { return type_impls_trait(*e->inner); - } + } // Otherwise, there's no negative so it must be positive else { return ::HIR::Compare::Equal; @@ -986,9 +986,9 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI bool rv; bool assume_opaque = true; rv = this->iterate_bounds([&](const auto& b)->bool { - if( const auto* bep = b.opt_TraitBound() ) - { - const auto& be = *bep; + if( const auto* bep = b.opt_TraitBound() ) + { + const auto& be = *bep; DEBUG("Trait bound - " << be.type << " : " << be.trait); // 1. Check if the type matches // - TODO: This should be a fuzzier match? @@ -1040,20 +1040,20 @@ void StaticTraitResolve::expand_associated_types__UfcsKnown(const Span& sp, ::HI } // - Didn't match - } - else if( const auto* bep = b.opt_TypeEquality() ) - { - const auto& be = *bep; + } + else if( const auto* bep = b.opt_TypeEquality() ) + { + const auto& be = *bep; DEBUG("Equality - " << be.type << " = " << be.other_type); if( input == be.type ) { input = be.other_type.clone(); return true; } - } - else - { - // Nothing. - } + } + else + { + // Nothing. + } return false; }); if( rv ) { diff --git a/src/include/debug.hpp b/src/include/debug.hpp index 2bbecb39..2f593cfb 100644 --- a/src/include/debug.hpp +++ b/src/include/debug.hpp @@ -42,10 +42,10 @@ class NullSink { public: NullSink() - {} + {} - template - const NullSink& operator<<(const T&) const { return *this; } + template + const NullSink& operator<<(const T&) const { return *this; } }; class TraceLog @@ -62,9 +62,9 @@ public: struct FmtLambda { ::std::function m_cb; - FmtLambda(::std::function cb): - m_cb(cb) - { } + FmtLambda(::std::function cb): + m_cb(cb) + { } friend ::std::ostream& operator<<(::std::ostream& os, const FmtLambda& x) { x.m_cb(os); return os; diff --git a/src/include/synext_decorator.hpp b/src/include/synext_decorator.hpp index 3374fc88..77b55710 100644 --- a/src/include/synext_decorator.hpp +++ b/src/include/synext_decorator.hpp @@ -63,19 +63,19 @@ extern void Register_Synext_Decorator_Static(DecoratorDef* def); struct DecoratorDef { - DecoratorDef* prev; - ::std::string name; - ::std::unique_ptr def; - DecoratorDef(::std::string name, ::std::unique_ptr def): - prev(nullptr), - name(::std::move(name)), - def(::std::move(def)) - { - Register_Synext_Decorator_Static(this); - } + DecoratorDef* prev; + ::std::string name; + ::std::unique_ptr def; + DecoratorDef(::std::string name, ::std::unique_ptr def): + prev(nullptr), + name(::std::move(name)), + def(::std::move(def)) + { + Register_Synext_Decorator_Static(this); + } }; -#define STATIC_DECORATOR(ident, _handler_class) static DecoratorDef s_register_##_handler_class ( ident, ::std::unique_ptr(new _handler_class()) ); +#define STATIC_DECORATOR(ident, _handler_class) static DecoratorDef s_register_##_handler_class ( ident, ::std::unique_ptr(new _handler_class()) ); #endif diff --git a/src/include/synext_macro.hpp b/src/include/synext_macro.hpp index 0abaf0fe..0359d508 100644 --- a/src/include/synext_macro.hpp +++ b/src/include/synext_macro.hpp @@ -31,19 +31,19 @@ extern void Register_Synext_Macro_Static(MacroDef* def); struct MacroDef { - MacroDef* prev; - ::std::string name; - ::std::unique_ptr def; - MacroDef(::std::string name, ::std::unique_ptr def) : - prev(nullptr), - name(::std::move(name)), - def(::std::move(def)) - { - Register_Synext_Macro_Static(this); - } + MacroDef* prev; + ::std::string name; + ::std::unique_ptr def; + MacroDef(::std::string name, ::std::unique_ptr def) : + prev(nullptr), + name(::std::move(name)), + def(::std::move(def)) + { + Register_Synext_Macro_Static(this); + } }; -#define STATIC_MACRO(ident, _handler_class) static MacroDef s_register_##_handler_class(ident, ::std::unique_ptr(new _handler_class())); +#define STATIC_MACRO(ident, _handler_class) static MacroDef s_register_##_handler_class(ident, ::std::unique_ptr(new _handler_class())); #endif diff --git a/src/include/tagged_union.hpp b/src/include/tagged_union.hpp index fbd42a77..f30cb7f2 100644 --- a/src/include/tagged_union.hpp +++ b/src/include/tagged_union.hpp @@ -13,13 +13,13 @@ #include #define TU_FIRST(a, ...) a -#define TU_EXP1(x) x +#define TU_EXP1(x) x #define TU_EXP(...) __VA_ARGS__ -#define TU_CASE_ITEM(src, mod, var, name) mod auto& name = src.as_##var(); (void)&name; -#define TU_CASE_BODY(class,var, ...) case class::var: { __VA_ARGS__ } break; -#define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__) -#define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__) +#define TU_CASE_ITEM(src, mod, var, name) mod auto& name = src.as_##var(); (void)&name; +#define TU_CASE_BODY(class,var, ...) case class::var: { __VA_ARGS__ } break; +#define TU_CASE(mod, class, var, name,src, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(src,mod,var,name) __VA_ARGS__) +#define TU_CASE2(mod, class, var, n1,s1, n2,s2, ...) TU_CASE_BODY(mod,class,var, TU_CASE_ITEM(s1,mod,var,n1) TU_CASE_ITEM(s2,mod,var,n2) __VA_ARGS__) // Argument iteration @@ -31,7 +31,7 @@ #define TU_DISP5(n, a1,a2,a3, b1,b2 ) TU_DISP3(n, a1,a2,a3) TU_DISP2(n, b1,b2) #define TU_DISP6(n, a1,a2,a3, b1,b2,b3) TU_DISP3(n, a1,a2,a3) TU_DISP3(n, b1,b2,b3) #define TU_DISP7(n, a1,a2,a3,a4, b1,b2,b3 ) TU_DISP4(n, a1,a2,a3,a4) TU_DISP3(n, b1,b2,b3) -#define TU_DISP8(n, a1,a2,a3,a4, b1,b2,b3,b4) TU_DISP4(n, a1,a2,a3,a4) TU_DISP4(n, b1,b2,b3,b4) +#define TU_DISP8(n, a1,a2,a3,a4, b1,b2,b3,b4) TU_DISP4(n, a1,a2,a3,a4) TU_DISP4(n, b1,b2,b3,b4) #define TU_DISP9(n, a1,a2,a3,a4, b1,b2,b3,b4, c1 ) TU_DISP4(n, a1,a2,a3,a4) TU_DISP3(n, b1,b2,b3 ) TU_DISP2(n, b4,c1) #define TU_DISP10(n, a1,a2,a3,a4, b1,b2,b3,b4, c1,c2 ) TU_DISP4(n, a1,a2,a3,a4) TU_DISP4(n, b1,b2,b3,b4) TU_DISP2(n, c1,c2) #define TU_DISP11(n, a1,a2,a3,a4, b1,b2,b3,b4, c1,c2,c3 ) TU_DISP4(n, a1,a2,a3,a4) TU_DISP4(n, b1,b2,b3,b4) TU_DISP3(n, c1,c2,c3) @@ -48,7 +48,7 @@ #define TU_DISPO4(n, v, v2, v3, v4) n(v) n(v2) n(v3) n(v4) #define TU_DISPO5(n, a1,a2,a3, b1,b2 ) TU_DISPO3(n, a1,a2,a3) TU_DISPO2(n, b1,b2) #define TU_DISPO6(n, a1,a2,a3, b1,b2,b3) TU_DISPO3(n, a1,a2,a3) TU_DISPO3(n, b1,b2,b3) -#define TU_DISPO7(n, a1,a2,a3,a4, b1,b2,b3 ) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO3(n, b1,b2,b3) +#define TU_DISPO7(n, a1,a2,a3,a4, b1,b2,b3 ) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO3(n, b1,b2,b3) #define TU_DISPO8(n, a1,a2,a3,a4, b1,b2,b3,b4) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO4(n, b1,b2,b3,b4) #define TU_DISPO9(n, a1,a2,a3,a4, b1,b2,b3,b4, c1) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO3(n, b1,b2,b3) TU_DISPO2(n, b4,c1) #define TU_DISPO10(n, a1,a2,a3,a4, b1,b2,b3,b4, c1,c2) TU_DISPO4(n, a1,a2,a3,a4) TU_DISPO4(n, b1,b2,b3,b4) TU_DISPO2(n, c1,c2) @@ -61,8 +61,8 @@ #define TU_DISPA(n, a) n a #define TU_DISPA1(n, a, _1) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) -#define TU_DISPA2(n, a, _1, _2) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) TU_DISPA(n, (TU_EXP a, TU_EXP _2)) -#define TU_DISPA3(n, a, _1, _2, _3) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) TU_DISPA(n, (TU_EXP a, TU_EXP _2)) TU_DISPA(n, (TU_EXP a, TU_EXP _3)) +#define TU_DISPA2(n, a, _1, _2) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) TU_DISPA(n, (TU_EXP a, TU_EXP _2)) +#define TU_DISPA3(n, a, _1, _2, _3) TU_DISPA(n, (TU_EXP a, TU_EXP _1)) TU_DISPA(n, (TU_EXP a, TU_EXP _2)) TU_DISPA(n, (TU_EXP a, TU_EXP _3)) #define TU_DISPA4(n, a, a1,a2, b1,b2) TU_DISPA2(n,a, a1,a2) TU_DISPA2(n,a, b1,b2) #define TU_DISPA5(n, a, a1,a2,a3, b1,b2) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA2(n,a, b1,b2) #define TU_DISPA6(n, a, a1,a2,a3, b1,b2,b3) TU_DISPA3(n,a, a1,a2,a3) TU_DISPA3(n,a, b1,b2,b3) diff --git a/src/main.cpp b/src/main.cpp index ec4e9f38..1b09b79b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -258,18 +258,18 @@ int main(int argc, char *argv[]) crate_name = ::std::string(params.infile.begin() + s, params.infile.begin() + e); for(auto& b : crate_name) { - if ('0' <= b && b <= '9') { - } - else if ('A' <= b && b <= 'Z') { - } - else if (b == '_') { - } - else if (b == '-') { - b = '_'; - } - else { - // TODO: Error? - } + if ('0' <= b && b <= '9') { + } + else if ('A' <= b && b <= 'Z') { + } + else if (b == '_') { + } + else if (b == '-') { + b = '_'; + } + else { + // TODO: Error? + } } } crate.m_crate_name = crate_name; @@ -571,14 +571,14 @@ ProgramParams::ProgramParams(int argc, char *argv[]) if( arg[0] != '-' ) { - if (this->infile == "") - { - this->infile = arg; - } - else - { - // TODO: Error - } + if (this->infile == "") + { + this->infile = arg; + } + else + { + // TODO: Error + } } else if( arg[1] != '-' ) { @@ -647,15 +647,15 @@ ProgramParams::ProgramParams(int argc, char *argv[]) } this->crate_path = argv[++i]; } - else if (strcmp(arg, "--out-dir") == 0) { - if (i == argc - 1) { - ::std::cerr << "Flag " << arg << " requires an argument" << ::std::endl; - exit(1); - } - this->output_dir = argv[++i]; - if (this->output_dir == "") { - // TODO: Error? - } + else if (strcmp(arg, "--out-dir") == 0) { + if (i == argc - 1) { + ::std::cerr << "Flag " << arg << " requires an argument" << ::std::endl; + exit(1); + } + this->output_dir = argv[++i]; + if (this->output_dir == "") { + // TODO: Error? + } if( this->output_dir.back() != '/' ) this->output_dir += '/'; } diff --git a/src/mir/check.cpp b/src/mir/check.cpp index 4b9dfd8b..f669623a 100644 --- a/src/mir/check.cpp +++ b/src/mir/check.cpp @@ -689,7 +689,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // TODO: Check suitability of source type (COMPLEX) ), (BinOp, - /* + /* ::HIR::TypeRef tmp_l, tmp_r; const auto& ty_l = state.get_lvalue_type(tmp_l, e.val_l); const auto& ty_r = state.get_lvalue_type(tmp_r, e.val_r); @@ -723,7 +723,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path ity_p = &*ty.m_data.as_Pointer().inner; else { MIR_BUG(state, "DstMeta requires a &-ptr as input, got " << ty); - } + } const auto& ity = *ity_p; if( ity.m_data.is_Generic() ) ; @@ -757,7 +757,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path ity_p = &*ty.m_data.as_Pointer().inner; else { MIR_BUG(state, "DstPtr requires a &-ptr as input, got " << ty); - } + } const auto& ity = *ity_p; if( ity.m_data.is_Slice() ) ; @@ -785,7 +785,7 @@ void MIR_Validate(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path ity_p = &*te->inner; else { MIR_BUG(state, "DstMeta requires a pointer as output, got " << ty); - } + } assert(ity_p); auto meta = get_metadata_type(state, *ity_p); if( meta == ::HIR::TypeRef() ) diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index cacd9bef..9f32d7ec 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -755,9 +755,9 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio TU_MATCHA( (blk.statements[i]), (se), (Assign, if( ENABLE_LEAK_DETECTOR ) - { - // TODO: Check if the target isn't valid. Allow if either invaid, or too complex to know. - } + { + // TODO: Check if the target isn't valid. Allow if either invaid, or too complex to know. + } TU_MATCHA( (se.src), (ve), (Use, state.move_lvalue(mir_res, ve); diff --git a/src/parse/lex.cpp b/src/parse/lex.cpp index 0587e443..9388fca4 100644 --- a/src/parse/lex.cpp +++ b/src/parse/lex.cpp @@ -223,8 +223,8 @@ signed int Lexer::getSymbol() bool issym(Codepoint ch) { - if('0' <= ch.v && ch.v <= '9') - return true; + if('0' <= ch.v && ch.v <= '9') + return true; if( ::std::isalpha(ch.v) ) return true; if( ch == '_' ) @@ -668,7 +668,7 @@ Token Lexer::getTokenInt() { return Token(TOK_EOF); } - throw "Fell off the end of getTokenInt"; + throw "Fell off the end of getTokenInt"; } Token Lexer::getTokenInt_RawString(bool is_byte) @@ -983,7 +983,7 @@ bool Codepoint::isspace() const { case ' ': case 0xC: // ^L case 0x85: - case 0x200E: case 0x200F: // LTR / RTL markers + case 0x200E: case 0x200F: // LTR / RTL markers case 0x2028: // Line Separator case 0x2029: // Paragrah Separator return true; -- cgit v1.2.3 From e205ae4024312fe6ddd437ae0ac12990d103bb45 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 10 Jun 2017 10:48:34 +0800 Subject: MIR Gen - Fix incorrect codegen due to defaulting to 0 not ~0 --- src/main.cpp | 3 ++- src/mir/mir_builder.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 1b09b79b..af999dae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -63,6 +63,7 @@ void init_debug_list() g_debug_disable_map.insert( "Dump HIR" ); g_debug_disable_map.insert( "Lower MIR" ); g_debug_disable_map.insert( "MIR Validate" ); + g_debug_disable_map.insert( "MIR Validate Full Early" ); g_debug_disable_map.insert( "Dump MIR" ); g_debug_disable_map.insert( "Constant Evaluate Full" ); g_debug_disable_map.insert( "MIR Cleanup" ); @@ -450,7 +451,7 @@ int main(int argc, char *argv[]) }); if( getenv("MRUSTC_FULL_VALIDATE_PREOPT") ) { - CompilePhaseV("MIR Validate Full", [&]() { + CompilePhaseV("MIR Validate Full Early", [&]() { MIR_CheckCrate_Full(*hir_crate); }); } diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 478146e8..f03dc40f 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -355,7 +355,7 @@ void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data) } void MirBuilder::push_stmt_set_dropflag_val(const Span& sp, unsigned int idx, bool value) { - this->push_stmt(sp, ::MIR::Statement::make_SetDropFlag({ idx, value })); + this->push_stmt(sp, ::MIR::Statement::make_SetDropFlag({ idx, value, ~0u })); } void MirBuilder::push_stmt_set_dropflag_other(const Span& sp, unsigned int idx, unsigned int other) { @@ -363,7 +363,7 @@ void MirBuilder::push_stmt_set_dropflag_other(const Span& sp, unsigned int idx, } void MirBuilder::push_stmt_set_dropflag_default(const Span& sp, unsigned int idx) { - this->push_stmt(sp, ::MIR::Statement::make_SetDropFlag({ idx, this->get_drop_flag_default(sp, idx) })); + this->push_stmt(sp, ::MIR::Statement::make_SetDropFlag({ idx, this->get_drop_flag_default(sp, idx), ~0u })); } void MirBuilder::push_stmt(const Span& sp, ::MIR::Statement stmt) { -- cgit v1.2.3 From c211c01437ce248d654b0d6ba9b739d1633cce68 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 10 Jun 2017 13:24:31 +0800 Subject: MIR Validate Full - Remove need for garbage collection of states --- src/mir/check_full.cpp | 187 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 142 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/mir/check_full.cpp b/src/mir/check_full.cpp index 9f32d7ec..f49598da 100644 --- a/src/mir/check_full.cpp +++ b/src/mir/check_full.cpp @@ -24,6 +24,11 @@ namespace // other = 1-based index into `inner_states` unsigned int index; + explicit State(const State&) = default; + State(State&& x) = default; + State& operator=(const State&) = delete; + State& operator=(State&& ) = default; + State(): index(0) {} State(bool valid): index(valid ? ~0u : 0) {} State(size_t idx): @@ -51,11 +56,12 @@ namespace struct StateFmt { const ValueStates& vss; - State s; - StateFmt( const ValueStates& vss, State s ): + const State& s; + StateFmt( const ValueStates& vss, const State& s ): vss(vss), s(s) {} }; +::std::ostream& operator<<(::std::ostream& os, const StateFmt& x); namespace { @@ -73,8 +79,28 @@ namespace ValueStates clone() const { + struct H { + static ::std::vector clone_state_list(const ::std::vector& l) { + ::std::vector rv; + rv.reserve(l.size()); + for(const auto& s : l) + rv.push_back( State(s) ); + return rv; + } + }; + 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.drop_flags = this->drop_flags; + rv.inner_states.reserve( this->inner_states.size() ); + for(const auto& isl : this->inner_states) + rv.inner_states.push_back( H::clone_state_list(isl) ); + rv.bb_path = this->bb_path; return *this; } + bool is_equivalent_to(const ValueStates& x) const { struct H { @@ -147,7 +173,7 @@ namespace } void ensure_lvalue_valid(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const { - auto vs = get_lvalue_state(mir_res, lv); + const auto& vs = get_lvalue_state(mir_res, lv); ::std::vector path; ensure_valid(mir_res, lv, vs, path); } @@ -380,20 +406,39 @@ namespace m.mark_from_state(*this, this->return_value); } private: - State allocate_composite(unsigned int n_fields, State basis) + ::std::vector& allocate_composite_int(State& out_state) { - assert(n_fields > 0); + // 1. Search for an unused (empty) slot for(size_t i = 0; i < this->inner_states.size(); i ++) { if( this->inner_states[i].size() == 0 ) { - inner_states[i] = ::std::vector(n_fields, basis); - return State(i); + out_state = State(i); + return inner_states[i]; } } + // 2. If none avaliable, allocate a new slot auto idx = inner_states.size(); - inner_states.push_back( ::std::vector(n_fields, basis) ); - return State(idx); + inner_states.push_back({}); + out_state = State(idx); + return inner_states.back(); + } + State allocate_composite(unsigned int n_fields, const State& basis) + { + assert(n_fields > 0); + assert(!basis.is_composite()); + + State rv; + auto& sub_states = allocate_composite_int(rv); + assert(sub_states.size() == 0); + + sub_states.reserve(n_fields); + while(n_fields--) + { + sub_states.push_back( State(basis) ); + } + + return rv; } public: @@ -407,7 +452,7 @@ namespace MIR_ASSERT(mir_res, vs.index-1 < this->inner_states.size(), ""); return this->inner_states.at( vs.index - 1 ); } - State get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const + const State& get_lvalue_state(const ::MIR::TypeResolve& mir_res, const ::MIR::LValue& lv) const { TU_MATCHA( (lv), (e), (Variable, @@ -420,13 +465,14 @@ namespace return arguments.at(e.idx); ), (Static, - return State(true); + static State state_of_static(true); + return state_of_static; ), (Return, return return_value; ), (Field, - auto vs = get_lvalue_state(mir_res, *e.val); + const auto& vs = get_lvalue_state(mir_res, *e.val); if( vs.is_composite() ) { const auto& states = this->get_composite(mir_res, vs); @@ -439,7 +485,7 @@ namespace } ), (Deref, - auto vs = get_lvalue_state(mir_res, *e.val); + const auto& vs = get_lvalue_state(mir_res, *e.val); if( vs.is_composite() ) { MIR_TODO(mir_res, "Deref with composite state"); @@ -450,18 +496,20 @@ namespace } ), (Index, - auto vs_v = get_lvalue_state(mir_res, *e.val); - auto vs_i = get_lvalue_state(mir_res, *e.idx); + const auto& vs_v = get_lvalue_state(mir_res, *e.val); + const auto& vs_i = get_lvalue_state(mir_res, *e.idx); MIR_ASSERT(mir_res, !vs_v.is_composite(), ""); MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); - return State(vs_v.is_valid() && vs_i.is_valid()); + //return State(vs_v.is_valid() && vs_i.is_valid()); + MIR_ASSERT(mir_res, vs_i.is_valid(), "Indexing with an invalidated value"); + return vs_v; ), (Downcast, - auto vs_v = get_lvalue_state(mir_res, *e.val); + const auto& vs_v = get_lvalue_state(mir_res, *e.val); if( vs_v.is_composite() ) { const auto& states = this->get_composite(mir_res, vs_v); - MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size"); + MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << StateFmt(*this, vs_v)); return states[0]; } else @@ -472,33 +520,51 @@ 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); + for(auto& ss : sub_states) + this->clear_state(mir_res, ss); + 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, - vars.at(e) = new_vs; + auto& slot = vars.at(e); + this->clear_state(mir_res, slot); + slot = mv$(new_vs); ), (Temporary, - temporaries.at(e.idx) = new_vs; + auto& slot = temporaries.at(e.idx); + this->clear_state(mir_res, slot); + slot = mv$(new_vs); ), (Argument, - arguments.at(e.idx) = new_vs; + auto& slot = arguments.at(e.idx); + this->clear_state(mir_res, slot); + slot = mv$(new_vs); ), (Static, // Ignore. ), (Return, - return_value = new_vs; + this->clear_state(mir_res, return_value); + return_value = mv$(new_vs); ), (Field, - auto cur_vs = get_lvalue_state(mir_res, *e.val); + const auto& cur_vs = get_lvalue_state(mir_res, *e.val); if( !cur_vs.is_composite() && cur_vs == new_vs ) { // Not a composite, and no state change } else { + ::std::vector* states_p; if( !cur_vs.is_composite() ) { ::HIR::TypeRef tmp; @@ -526,41 +592,55 @@ namespace else { MIR_BUG(mir_res, "Unknown type being accessed with Field - " << ty); } - cur_vs = this->allocate_composite(n_fields, cur_vs); - set_lvalue_state(mir_res, *e.val, cur_vs); + + auto new_cur_vs = this->allocate_composite(n_fields, cur_vs); + set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); + states_p = &this->get_composite(mir_res, new_cur_vs); + } + else + { + states_p = &this->get_composite(mir_res, cur_vs); } // Get composite state and assign into it - auto& states = this->get_composite(mir_res, cur_vs); + auto& states = *states_p; MIR_ASSERT(mir_res, e.field_index < states.size(), "Field index out of range"); - states[e.field_index] = new_vs; + this->clear_state(mir_res, states[e.field_index]); + states[e.field_index] = mv$(new_vs); } ), (Deref, - auto cur_vs = get_lvalue_state(mir_res, *e.val); + const auto& cur_vs = get_lvalue_state(mir_res, *e.val); if( !cur_vs.is_composite() && cur_vs == new_vs ) { // Not a composite, and no state change } else { + ::std::vector* states_p; if( !cur_vs.is_composite() ) { //::HIR::TypeRef tmp; //const auto& ty = mir_res.get_lvalue_type(tmp, *e.val); // TODO: Should this check if the type is Box? - cur_vs = this->allocate_composite(2, cur_vs); - set_lvalue_state(mir_res, *e.val, cur_vs); + auto new_cur_vs = this->allocate_composite(2, cur_vs); + set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); + states_p = &this->get_composite(mir_res, new_cur_vs); + } + else + { + states_p = &this->get_composite(mir_res, cur_vs); } // Get composite state and assign into it - auto& states = this->get_composite(mir_res, cur_vs); + auto& states = *states_p; MIR_ASSERT(mir_res, states.size() == 2, "Deref with invalid state list size"); - states[1] = new_vs; + this->clear_state(mir_res, states[1]); + states[1] = mv$(new_vs); } ), (Index, - auto vs_v = get_lvalue_state(mir_res, *e.val); - auto vs_i = get_lvalue_state(mir_res, *e.idx); + const auto& vs_v = get_lvalue_state(mir_res, *e.val); + const auto& vs_i = get_lvalue_state(mir_res, *e.idx); MIR_ASSERT(mir_res, !vs_v.is_composite(), ""); MIR_ASSERT(mir_res, !vs_i.is_composite(), ""); @@ -570,22 +650,30 @@ namespace // NOTE: Ignore ), (Downcast, - auto cur_vs = get_lvalue_state(mir_res, *e.val); + const auto& cur_vs = get_lvalue_state(mir_res, *e.val); if( !cur_vs.is_composite() && cur_vs == new_vs ) { // Not a composite, and no state change } else { + ::std::vector* states_p; if( !cur_vs.is_composite() ) { - cur_vs = this->allocate_composite(1, cur_vs); - set_lvalue_state(mir_res, *e.val, cur_vs); + auto new_cur_vs = this->allocate_composite(1, cur_vs); + set_lvalue_state(mir_res, *e.val, State(new_cur_vs)); + states_p = &this->get_composite(mir_res, new_cur_vs); + } + else + { + states_p = &this->get_composite(mir_res, cur_vs); } + // Get composite state and assign into it - auto& states = this->get_composite(mir_res, cur_vs); - MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size"); - states[0] = new_vs; + auto& states = *states_p; + MIR_ASSERT(mir_res, states.size() == 1, "Downcast on composite of invalid size - " << *e.val << " - " << this->fmt_state(mir_res, *e.val)); + this->clear_state(mir_res, states[0]); + states[0] = mv$(new_vs); } ) ) @@ -677,9 +765,18 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio DEBUG(lifetimes.m_block_offsets); ValueStates state; - state.arguments.resize( mir_res.m_args.size(), State(true) ); - state.vars.resize( fcn.named_variables.size() ); - state.temporaries.resize( fcn.temporaries.size() ); + struct H { + static ::std::vector make_list(size_t n, bool pop) { + ::std::vector rv; + rv.reserve(n); + while(n--) + rv.push_back(State(pop)); + 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.drop_flags = fcn.drop_flags; ::std::vector< ::std::pair > todo_queue; @@ -845,7 +942,7 @@ void MIR_Validate_FullValState(::MIR::TypeResolve& mir_res, const ::MIR::Functio { // HACK: A move out of a Box generates the following pattern: `[[[[X_]]X]]` // - Ensure that that is the pattern we're seeing here. - auto vs = state.get_lvalue_state(mir_res, se.slot); + const auto& vs = state.get_lvalue_state(mir_res, se.slot); MIR_ASSERT(mir_res, vs.index != ~0u, "Shallow drop on fully-valid value - " << se.slot); -- cgit v1.2.3 From 52d872b36d7fda733273d70100d21b16506f1647 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 11 Jun 2017 11:34:16 +0800 Subject: Parse - Support chaining of spans (for macro expansions) --- src/ast/expr.cpp | 8 ++++---- src/ast/expr.hpp | 7 +++---- src/expand/mod.cpp | 8 ++++---- src/hir/from_ast_expr.cpp | 46 +++++++++++++++++++++++----------------------- src/include/span.hpp | 3 ++- src/macro_rules/eval.cpp | 10 +++++----- src/macro_rules/parse.cpp | 6 +++--- src/parse/expr.cpp | 16 +++++++++------- src/parse/parseerror.cpp | 20 ++++++++++---------- src/parse/pattern.cpp | 6 +++--- src/parse/root.cpp | 26 +++++++++++++------------- src/parse/tokenstream.cpp | 14 +++++++++----- src/parse/tokenstream.hpp | 4 +++- src/parse/types.cpp | 2 +- src/resolve/absolute.cpp | 12 ++++++------ src/span.cpp | 3 +++ 16 files changed, 101 insertions(+), 90 deletions(-) (limited to 'src') diff --git a/src/ast/expr.cpp b/src/ast/expr.cpp index dd586683..c1baf9b4 100644 --- a/src/ast/expr.cpp +++ b/src/ast/expr.cpp @@ -69,11 +69,11 @@ ExprNode::~ExprNode() { #define OPT_CLONE(node) (node.get() ? node->clone() : ::AST::ExprNodeP()) namespace { - static inline ExprNodeP mk_exprnodep(const Position& pos, AST::ExprNode* en) { - en->set_pos(pos); + static inline ExprNodeP mk_exprnodep(const Span& pos, AST::ExprNode* en) { + en->set_span(pos); return ExprNodeP(en); } - #define NEWNODE(type, ...) mk_exprnodep(get_pos(), new type(__VA_ARGS__)) + #define NEWNODE(type, ...) mk_exprnodep(span(), new type(__VA_ARGS__)) } NODE(ExprNode_Block, { @@ -453,7 +453,7 @@ NV(ExprNode_Block, { }) NV(ExprNode_Macro, { - BUG(node.get_pos(), "Hit unexpanded macro in expression - " << node); + BUG(node.span(), "Hit unexpanded macro in expression - " << node); }) NV(ExprNode_Asm, { diff --git a/src/ast/expr.hpp b/src/ast/expr.hpp index ee1da656..a6b58e03 100644 --- a/src/ast/expr.hpp +++ b/src/ast/expr.hpp @@ -26,7 +26,7 @@ class NodeVisitor; class ExprNode { MetaItems m_attrs; - Position m_pos; + Span m_span; public: virtual ~ExprNode() = 0; @@ -34,9 +34,8 @@ public: virtual void print(::std::ostream& os) const = 0; virtual ::std::unique_ptr clone() const = 0; - void set_pos(Position p) { m_pos = ::std::move(p); } - const Position& get_pos() const { return m_pos; } - Span span() const { return m_pos; } + void set_span(Span s) { m_span = ::std::move(s); } + const Span& span() const { return m_span; } void set_attrs(MetaItems&& mi) { m_attrs = mv$(mi); diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 1a534c0b..38e40347 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -317,7 +317,7 @@ struct CExpandExpr: { this->visit(cnode); if(cnode.get() == nullptr) - ERROR(parent.get_pos(), E0000, "#[cfg] not allowed in this position"); + ERROR(parent.span(), E0000, "#[cfg] not allowed in this position"); } assert( ! this->replacement ); } @@ -343,7 +343,7 @@ struct CExpandExpr: ::AST::ExprNodeP rv; auto& mod = this->cur_mod(); - auto ttl = Expand_Macro( crate, modstack, mod, Span(node.get_pos()), node.m_name, node.m_ident, node.m_tokens ); + auto ttl = Expand_Macro( crate, modstack, mod, node.span(), node.m_name, node.m_ident, node.m_tokens ); if( !ttl.get() ) { // No expansion @@ -362,7 +362,7 @@ struct CExpandExpr: auto newexpr = Parse_ExprBlockLine_WithItems(*ttl, local_mod_ptr, add_silence_if_end); if( tmp_local_mod ) - TODO(node.get_pos(), "Handle edge case where a macro expansion outside of a _Block creates an item"); + TODO(node.span(), "Handle edge case where a macro expansion outside of a _Block creates an item"); if( newexpr ) { @@ -382,7 +382,7 @@ struct CExpandExpr: if( ttl->lookahead(0) != TOK_EOF ) { if( !nodes_out ) { - ERROR(node.get_pos(), E0000, "Unused tokens at the end of macro expansion - " << ttl->getToken()); + ERROR(node.span(), E0000, "Unused tokens at the end of macro expansion - " << ttl->getToken()); } } } diff --git a/src/hir/from_ast_expr.cpp b/src/hir/from_ast_expr.cpp index 9085bd3b..296bdce1 100644 --- a/src/hir/from_ast_expr.cpp +++ b/src/hir/from_ast_expr.cpp @@ -30,7 +30,7 @@ struct LowerHIR_ExprNode_Visitor: auto rv = new ::HIR::ExprNode_Block(v.span()); for(const auto& n : v.m_nodes) { - ASSERT_BUG(v.get_pos(), n, "NULL node encountered in block"); + ASSERT_BUG(v.span(), n, "NULL node encountered in block"); rv->m_nodes.push_back( LowerHIR_ExprNode_Inner( *n ) ); } if( v.m_yields_final_value && ! rv->m_nodes.empty() ) @@ -48,7 +48,7 @@ struct LowerHIR_ExprNode_Visitor: m_rv.reset( static_cast< ::HIR::ExprNode*>(rv) ); } virtual void visit(::AST::ExprNode_Macro& v) override { - BUG(v.get_pos(), "Hit ExprNode_Macro"); + BUG(v.span(), "Hit ExprNode_Macro"); } virtual void visit(::AST::ExprNode_Asm& v) override { ::std::vector< ::HIR::ExprNode_Asm::ValRef> outputs; @@ -72,7 +72,7 @@ struct LowerHIR_ExprNode_Visitor: case ::AST::ExprNode_Flow::CONTINUE: case ::AST::ExprNode_Flow::BREAK: if( v.m_value ) - TODO(v.get_pos(), "Handle break/continue values in HIR"); + TODO(v.span(), "Handle break/continue values in HIR"); m_rv.reset( new ::HIR::ExprNode_LoopControl( v.span(), v.m_target, (v.m_type == ::AST::ExprNode_Flow::CONTINUE) ) ); break; } @@ -167,7 +167,7 @@ struct LowerHIR_ExprNode_Visitor: } break; } case ::AST::ExprNode_BinOp::PLACE_IN: - TODO(v.get_pos(), "Desugar placement syntax"); + TODO(v.span(), "Desugar placement syntax"); break; case ::AST::ExprNode_BinOp::CMPEQU : op = ::HIR::ExprNode_BinOp::Op::CmpEqu ; if(0) @@ -213,7 +213,7 @@ struct LowerHIR_ExprNode_Visitor: )); } break; case ::AST::ExprNode_UniOp::QMARK: - BUG(v.get_pos(), "Encounterd question mark operator (should have been expanded in AST)"); + BUG(v.span(), "Encounterd question mark operator (should have been expanded in AST)"); break; case ::AST::ExprNode_UniOp::REF: @@ -262,7 +262,7 @@ struct LowerHIR_ExprNode_Visitor: TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e), ( m_rv.reset( new ::HIR::ExprNode_CallPath( v.span(), - LowerHIR_Path(Span(v.get_pos()), v.m_path), + LowerHIR_Path(v.span(), v.m_path), mv$( args ) ) ); ), @@ -361,7 +361,7 @@ struct LowerHIR_ExprNode_Visitor: break; } case ::AST::ExprNode_Loop::FOR: // NOTE: This should already be desugared (as a pass before resolve) - BUG(v.get_pos(), "Encountered still-sugared for loop"); + BUG(v.span(), "Encountered still-sugared for loop"); break; } @@ -507,7 +507,7 @@ struct LowerHIR_ExprNode_Visitor: } m_rv.reset( new ::HIR::ExprNode_Literal( v.span(), ::HIR::ExprNode_Literal::Data::make_Integer({ - H::get_type( Span(v.get_pos()), v.m_datatype ), + H::get_type( v.span(), v.m_datatype ), v.m_value }) ) ); @@ -520,7 +520,7 @@ struct LowerHIR_ExprNode_Visitor: case CORETYPE_F32: ct = ::HIR::CoreType::F32; break; case CORETYPE_F64: ct = ::HIR::CoreType::F64; break; default: - BUG(v.get_pos(), "Unknown type for float literal"); + BUG(v.span(), "Unknown type for float literal"); } m_rv.reset( new ::HIR::ExprNode_Literal( v.span(), ::HIR::ExprNode_Literal::Data::make_Float({ ct, v.m_value }) @@ -560,7 +560,7 @@ struct LowerHIR_ExprNode_Visitor: ERROR(v.span(), E0000, "Union constructors can't take a base value"); m_rv.reset( new ::HIR::ExprNode_UnionLiteral( v.span(), - LowerHIR_GenericPath(v.get_pos(), v.m_path), + LowerHIR_GenericPath(v.span(), v.m_path), v.m_values[0].first, LowerHIR_ExprNode_Inner(*v.m_values[0].second) ) ); @@ -571,7 +571,7 @@ struct LowerHIR_ExprNode_Visitor: for(const auto& val : v.m_values) values.push_back( ::std::make_pair(val.first, LowerHIR_ExprNode_Inner(*val.second)) ); m_rv.reset( new ::HIR::ExprNode_StructLiteral( v.span(), - LowerHIR_GenericPath(v.get_pos(), v.m_path), + LowerHIR_GenericPath(v.span(), v.m_path), ! v.m_path.binding().is_EnumVar(), LowerHIR_ExprNode_Inner_Opt(v.m_base_value.get()), mv$(values) @@ -604,7 +604,7 @@ struct LowerHIR_ExprNode_Visitor: virtual void visit(::AST::ExprNode_NamedValue& v) override { TU_IFLET(::AST::Path::Class, v.m_path.m_class, Local, e, if( !v.m_path.binding().is_Variable() ) { - BUG(v.get_pos(), "Named value was a local, but wasn't bound - " << v.m_path); + BUG(v.span(), "Named value was a local, but wasn't bound - " << v.m_path); } auto slot = v.m_path.binding().as_Variable().slot; m_rv.reset( new ::HIR::ExprNode_Variable( v.span(), e.name, slot ) ); @@ -612,7 +612,7 @@ struct LowerHIR_ExprNode_Visitor: else { TU_MATCH_DEF(::AST::PathBinding, (v.m_path.binding()), (e), ( - auto p = LowerHIR_Path(Span(v.get_pos()), v.m_path); + auto p = LowerHIR_Path(v.span(), v.m_path); if( p.m_data.is_Generic() ) { BUG(v.span(), "Unknown binding for PathValue but path is generic - " << v.m_path); } @@ -643,10 +643,10 @@ struct LowerHIR_ExprNode_Visitor: } } if( is_tuple_constructor ) { - m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::STRUCT_CONSTR ) ); + m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STRUCT_CONSTR ) ); } else { - m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(Span(v.get_pos()), v.m_path), true ) ); + m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), true ) ); } ), (EnumVar, @@ -680,33 +680,33 @@ struct LowerHIR_ExprNode_Visitor: } (void)var_idx; // TODO: Save time later by saving this. if( is_tuple_constructor ) { - m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::ENUM_VAR_CONSTR ) ); + m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::ENUM_VAR_CONSTR ) ); } else { - m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(Span(v.get_pos()), v.m_path), false ) ); + m_rv.reset( new ::HIR::ExprNode_UnitVariant( v.span(), LowerHIR_GenericPath(v.span(), v.m_path), false ) ); } ), (Function, - m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::FUNCTION ) ); + m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::FUNCTION ) ); ), (Static, if( e.static_ ) { if( e.static_->s_class() != ::AST::Static::CONST ) { - m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::STATIC ) ); + m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STATIC ) ); } else { - m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) ); + m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) ); } } else if( e.hir ) { - m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::STATIC ) ); + m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::STATIC ) ); } // HACK: If the HIR pointer is nullptr, then it refers to a `const else { - m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(Span(v.get_pos()), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) ); + m_rv.reset( new ::HIR::ExprNode_PathValue( v.span(), LowerHIR_Path(v.span(), v.m_path), ::HIR::ExprNode_PathValue::CONSTANT ) ); } ) ) @@ -739,7 +739,7 @@ struct LowerHIR_ExprNode_Visitor: const_cast<::AST::ExprNode*>(&e)->visit( v ); if( ! v.m_rv ) { - BUG(e.get_pos(), typeid(e).name() << " - Yielded a nullptr HIR node"); + BUG(e.span(), typeid(e).name() << " - Yielded a nullptr HIR node"); } return mv$( v.m_rv ); } diff --git a/src/include/span.hpp b/src/include/span.hpp index ddb08ae3..59c960fc 100644 --- a/src/include/span.hpp +++ b/src/include/span.hpp @@ -9,6 +9,7 @@ #include #include +#include enum ErrorType { @@ -30,7 +31,7 @@ struct ProtoSpan }; struct Span { - //::std::unique_ptr outer_span; // Expansion target for macros + ::std::shared_ptr outer_span; // Expansion target for macros RcString filename; unsigned int start_line; diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index 18ef563e..1bac45ee 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -618,9 +618,9 @@ bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type) switch(type) { case MacroPatEnt::PAT_TOKEN: - BUG(lex.getPosition(), ""); + BUG(lex.point_span(), ""); case MacroPatEnt::PAT_LOOP: - BUG(lex.getPosition(), ""); + BUG(lex.point_span(), ""); case MacroPatEnt::PAT_BLOCK: return LOOK_AHEAD(lex) == TOK_BRACE_OPEN || LOOK_AHEAD(lex) == TOK_INTERPOLATED_BLOCK; case MacroPatEnt::PAT_IDENT: @@ -651,7 +651,7 @@ bool Macro_TryPatternCap(TokenStream& lex, MacroPatEnt::Type type) case MacroPatEnt::PAT_ITEM: return is_token_item( LOOK_AHEAD(lex) ); } - BUG(lex.getPosition(), ""); + BUG(lex.point_span(), "Fell through"); } bool Macro_TryPattern(TokenStream& lex, const MacroPatEnt& pat) { @@ -680,9 +680,9 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type switch(type) { case MacroPatEnt::PAT_TOKEN: - BUG(lex.getPosition(), "Encountered PAT_TOKEN when handling capture"); + BUG(lex.point_span(), "Encountered PAT_TOKEN when handling capture"); case MacroPatEnt::PAT_LOOP: - BUG(lex.getPosition(), "Encountered PAT_LOOP when handling capture"); + BUG(lex.point_span(), "Encountered PAT_LOOP when handling capture"); case MacroPatEnt::PAT_TT: if( GET_TOK(tok, lex) == TOK_EOF ) diff --git a/src/macro_rules/parse.cpp b/src/macro_rules/parse.cpp index 8264180f..1b7509fd 100644 --- a/src/macro_rules/parse.cpp +++ b/src/macro_rules/parse.cpp @@ -82,7 +82,7 @@ public: else if( type == "item" ) ret.push_back( MacroPatEnt(name, idx, MacroPatEnt::PAT_ITEM) ); else - ERROR(lex.getPosition(), E0000, "Unknown fragment type '" << type << "'"); + ERROR(lex.point_span(), E0000, "Unknown fragment type '" << type << "'"); break; } case TOK_PAREN_OPEN: { auto subpat = Parse_MacroRules_Pat(lex, TOK_PAREN_OPEN, TOK_PAREN_CLOSE, names); @@ -155,7 +155,7 @@ public: { DEBUG("depth--"); if(depth == 0) - ERROR(lex.getPosition(), E0000, "Unmatched " << Token(close) << " in macro content"); + ERROR(lex.point_span(), E0000, "Unmatched " << Token(close) << " in macro content"); depth --; } @@ -206,7 +206,7 @@ public: auto name = tok.type() == TOK_IDENT ? tok.str() : FMT(tok); unsigned int idx = ::std::find(var_names.begin(), var_names.end(), name) - var_names.begin(); if( idx == var_names.size() ) - ERROR(lex.getPosition(), E0000, "Macro variable $" << name << " not found"); + ERROR(lex.point_span(), E0000, "Macro variable $" << name << " not found"); if( var_set_ptr ) { var_set_ptr->insert( ::std::make_pair(idx,true) ); } diff --git a/src/parse/expr.cpp b/src/parse/expr.cpp index 28729b93..547e38e0 100644 --- a/src/parse/expr.cpp +++ b/src/parse/expr.cpp @@ -20,7 +20,8 @@ using AST::ExprNode; using AST::ExprNodeP; -static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_pos(lex.getPosition()); return ExprNodeP(en); } +// TODO: Use a ProtoSpan +static inline ExprNodeP mk_exprnodep(const TokenStream& lex, AST::ExprNode* en){en->set_span(lex.point_span()); return ExprNodeP(en); } #define NEWNODE(type, ...) mk_exprnodep(lex, new type(__VA_ARGS__)) //ExprNodeP Parse_ExprBlockNode(TokenStream& lex, bool is_unsafe=false); // common.hpp @@ -552,7 +553,7 @@ ExprNodeP Parse_Stmt_Let(TokenStream& lex) { Token tok; AST::Pattern pat = Parse_Pattern(lex, false); // irrefutable - TypeRef type { lex.getPosition() }; + TypeRef type { lex.point_span() }; if( GET_TOK(tok, lex) == TOK_COLON ) { type = Parse_Type(lex); GET_TOK(tok, lex); @@ -969,7 +970,7 @@ ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path) GET_CHECK_TOK(tok, lex, TOK_COLON); ExprNodeP val = Parse_Stmt(lex); if( ! nodes.insert( ::std::make_pair(ofs, mv$(val)) ).second ) { - ERROR(lex.getPosition(), E0000, "Duplicate index"); + ERROR(lex.point_span(), E0000, "Duplicate index"); } if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE ) @@ -983,7 +984,7 @@ ExprNodeP Parse_ExprVal_StructLiteral(TokenStream& lex, AST::Path path) for(auto& p : nodes) { if( p.first != i ) { - ERROR(lex.getPosition(), E0000, "Missing index " << i); + ERROR(lex.point_span(), E0000, "Missing index " << i); } items.push_back( mv$(p.second) ); i ++; @@ -1041,7 +1042,7 @@ ExprNodeP Parse_ExprVal_Closure(TokenStream& lex, bool is_move) // Irrefutable pattern AST::Pattern pat = Parse_Pattern(lex, false); - TypeRef type { lex.getPosition() }; + TypeRef type { lex.point_span() }; if( GET_TOK(tok, lex) == TOK_COLON ) type = Parse_Type(lex); else @@ -1054,7 +1055,7 @@ ExprNodeP Parse_ExprVal_Closure(TokenStream& lex, bool is_move) } CHECK_TOK(tok, TOK_PIPE); - auto rt = TypeRef(lex.getPosition()); + auto rt = TypeRef(lex.point_span()); if( GET_TOK(tok, lex) == TOK_THINARROW ) { if( GET_TOK(tok, lex) == TOK_EXCLAM ) { @@ -1264,8 +1265,9 @@ ExprNodeP Parse_ExprVal(TokenStream& lex) } ExprNodeP Parse_ExprMacro(TokenStream& lex, AST::Path path) { + ASSERT_BUG(lex.point_span(), path.is_trivial(), "TODO: Support path macros - " << path); + Token tok; - ASSERT_BUG(lex.getPosition(), path.is_trivial(), "TODO: Support path macros - " << path); ::std::string name = path.m_class.is_Local() ? path.m_class.as_Local().name : path.nodes()[0].name(); ::std::string ident; if( GET_TOK(tok, lex) == TOK_IDENT ) { diff --git a/src/parse/parseerror.cpp b/src/parse/parseerror.cpp index 3c5d41fe..1bb30985 100644 --- a/src/parse/parseerror.cpp +++ b/src/parse/parseerror.cpp @@ -19,13 +19,13 @@ CompileError::Generic::Generic(::std::string message): } CompileError::Generic::Generic(const TokenStream& lex, ::std::string message) { - ::std::cout << lex.getPosition() << ": Generic(" << message << ")" << ::std::endl; + ::std::cout << lex.point_span() << ": Generic(" << message << ")" << ::std::endl; } CompileError::BugCheck::BugCheck(const TokenStream& lex, ::std::string message): m_message(message) { - ::std::cout << lex.getPosition() << "BugCheck(" << message << ")" << ::std::endl; + ::std::cout << lex.point_span() << "BugCheck(" << message << ")" << ::std::endl; } CompileError::BugCheck::BugCheck(::std::string message): m_message(message) @@ -41,7 +41,7 @@ CompileError::Todo::Todo(::std::string message): CompileError::Todo::Todo(const TokenStream& lex, ::std::string message): m_message(message) { - ::std::cout << lex.getPosition() << ": Todo(" << message << ")" << ::std::endl; + ::std::cout << lex.point_span() << ": Todo(" << message << ")" << ::std::endl; } CompileError::Todo::~Todo() throw() { @@ -49,7 +49,7 @@ CompileError::Todo::~Todo() throw() ParseError::BadChar::BadChar(const TokenStream& lex, char character) { - ::std::cout << lex.getPosition() << ": BadChar(" << character << ")" << ::std::endl; + ::std::cout << lex.point_span() << ": BadChar(" << character << ")" << ::std::endl; } ParseError::BadChar::~BadChar() throw() { @@ -58,24 +58,24 @@ ParseError::BadChar::~BadChar() throw() ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok)//: // m_tok( mv$(tok) ) { - auto pos = tok.get_pos(); + Span pos = tok.get_pos(); if(pos.filename == "") - pos = lex.getPosition(); + pos = lex.point_span(); ::std::cout << pos << ": Unexpected(" << tok << ")" << ::std::endl; } ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, Token exp)//: // m_tok( mv$(tok) ) { - auto pos = tok.get_pos(); + Span pos = tok.get_pos(); if(pos.filename == "") - pos = lex.getPosition(); + pos = lex.point_span(); ::std::cout << pos << ": Unexpected(" << tok << ", " << exp << ")" << ::std::endl; } ParseError::Unexpected::Unexpected(const TokenStream& lex, const Token& tok, ::std::vector exp) { - auto pos = tok.get_pos(); + Span pos = tok.get_pos(); if(pos.filename == "") - pos = lex.getPosition(); + pos = lex.point_span(); ::std::cout << pos << ": Unexpected " << tok << ", expected "; bool f = true; for(auto v: exp) { diff --git a/src/parse/pattern.cpp b/src/parse/pattern.cpp index e9d086f9..974ff5fb 100644 --- a/src/parse/pattern.cpp +++ b/src/parse/pattern.cpp @@ -258,7 +258,7 @@ AST::Pattern Parse_PatternReal1(TokenStream& lex, bool is_refutable) return AST::Pattern( AST::Pattern::TagValue(), AST::Pattern::Value::make_Float({n->m_datatype, n->m_value}) ); } else { - TODO(lex.getPosition(), "Convert :expr into a pattern value - " << *e); + TODO(lex.point_span(), "Convert :expr into a pattern value - " << *e); } } break; @@ -414,7 +414,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut GET_CHECK_TOK(tok, lex, TOK_COLON); auto val = Parse_Pattern(lex, is_refutable); if( ! pats.insert( ::std::make_pair(ofs, mv$(val)) ).second ) { - ERROR(lex.getPosition(), E0000, "Duplicate index"); + ERROR(lex.point_span(), E0000, "Duplicate index"); } if( GET_TOK(tok,lex) == TOK_BRACE_CLOSE ) @@ -435,7 +435,7 @@ AST::Pattern Parse_PatternStruct(TokenStream& lex, AST::Path path, bool is_refut { if( p.first != i ) { if( has_split || !split_allowed ) { - ERROR(lex.getPosition(), E0000, "Missing index " << i); + ERROR(lex.point_span(), E0000, "Missing index " << i); } has_split = true; i = p.first; diff --git a/src/parse/root.cpp b/src/parse/root.cpp index 5f8ed0a3..0790f05b 100644 --- a/src/parse/root.cpp +++ b/src/parse/root.cpp @@ -196,7 +196,7 @@ AST::GenericParams Parse_GenericParams(TokenStream& lex) ::std::string param_name = mv$(tok.str()); ret.add_ty_param( AST::TypeParam( param_name ) ); - auto param_ty = TypeRef(lex.getPosition(), param_name); + auto param_ty = TypeRef(lex.point_span(), param_name); if( GET_TOK(tok, lex) == TOK_COLON ) { Parse_TypeBound(lex, ret, mv$(param_ty)); @@ -382,7 +382,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_ GET_TOK(tok, lex); if( allow_self == false ) throw ParseError::Generic(lex, "Self binding not expected"); - TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF ); + TypeRef ty = TypeRef( lex.point_span(), "Self", 0xFFFF ); if( GET_TOK(tok, lex) == TOK_COLON ) { // Typed mut self ty = Parse_Type(lex); @@ -399,7 +399,7 @@ AST::Function Parse_FunctionDef(TokenStream& lex, ::std::string abi, bool allow_ // By-value method if( allow_self == false ) throw ParseError::Generic(lex, "Self binding not expected"); - TypeRef ty = TypeRef( lex.getPosition(), "Self", 0xFFFF ); + TypeRef ty = TypeRef( lex.point_span(), "Self", 0xFFFF ); if( GET_TOK(tok, lex) == TOK_COLON ) { // Typed mut self ty = Parse_Type(lex); @@ -723,14 +723,14 @@ AST::Trait Parse_TraitDef(TokenStream& lex, const AST::MetaItems& meta_items) if( GET_TOK(tok, lex) == TOK_COLON ) { // Bounded associated type - Parse_TypeBound(lex, atype_params, TypeRef(lex.getPosition(), "Self", 0xFFFF)); + Parse_TypeBound(lex, atype_params, TypeRef(lex.point_span(), "Self", 0xFFFF)); GET_TOK(tok, lex); } if( tok.type() == TOK_RWORD_WHERE ) { throw ParseError::Todo(lex, "Where clause on associated type"); } - TypeRef default_type = TypeRef( lex.getPosition() ); + TypeRef default_type = TypeRef( lex.point_span() ); if( tok.type() == TOK_EQUAL ) { default_type = Parse_Type(lex); GET_TOK(tok, lex); @@ -1049,7 +1049,7 @@ AST::MetaItem Parse_MetaItem(TokenStream& lex) if( GET_TOK(tok, lex) == TOK_DOUBLE_DOT ) { // Default impl - impl_type = TypeRef(TypeRef::TagInvalid(), lex.getPosition()); + impl_type = TypeRef(TypeRef::TagInvalid(), lex.point_span()); } else { @@ -1390,7 +1390,7 @@ void Parse_Use(TokenStream& lex, ::std::function 0, "`use` with no path"); + ASSERT_BUG(lex.point_span(), path.nodes().size() > 0, "`use` with no path"); name = path.nodes().back().name(); } @@ -1490,7 +1490,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) Parse_Use(lex, [&](AST::UseStmt p, std::string s) { DEBUG(mod_path << " - use " << p << " as '" << s << "'"); if( !item_data.is_None() ) - TODO(lex.getPosition(), "Encode multi-item use statements as a single Item"); + TODO(lex.point_span(), "Encode multi-item use statements as a single Item"); item_data = ::AST::Item(mv$(p)); item_name = mv$(s); }); @@ -1735,7 +1735,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) bool sub_file_controls_dir = true; if( mod_fileinfo.path == "-" ) { if( path_attr.size() ) { - ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin"); + ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin"); } sub_path = "-"; } @@ -1779,11 +1779,11 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) break; case TOK_SEMICOLON: if( sub_path == "-" ) { - ERROR(lex.getPosition(), E0000, "Cannot load module from file when reading stdin"); + ERROR(lex.point_span(), E0000, "Cannot load module from file when reading stdin"); } else if( path_attr.size() == 0 && ! mod_fileinfo.controls_dir ) { - ERROR(lex.getPosition(), E0000, "Can't load from files outside of mod.rs or crate root"); + ERROR(lex.point_span(), E0000, "Can't load from files outside of mod.rs or crate root"); } else if( !H::check_item_cfg(meta_items) ) { // Ignore - emit Item::None @@ -1801,7 +1801,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) if( ifs_dir.is_open() && ifs_file.is_open() ) { // Collision - ERROR(lex.getPosition(), E0000, "Both modname.rs and modname/mod.rs exist"); + ERROR(lex.point_span(), E0000, "Both modname.rs and modname/mod.rs exist"); } else if( ifs_dir.is_open() ) { @@ -1815,7 +1815,7 @@ bool Parse_MacroInvocation_Opt(TokenStream& lex, AST::MacroInvocation& out_inv) else { // Can't find file - ERROR(lex.getPosition(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'"); + ERROR(lex.point_span(), E0000, "Can't find file for '" << name << "' in '" << mod_fileinfo.path << "'"); } DEBUG("- path = " << submod.m_file_info.path); Lexer sub_lex(submod.m_file_info.path); diff --git a/src/parse/tokenstream.cpp b/src/parse/tokenstream.cpp index 8cb9a910..2975a523 100644 --- a/src/parse/tokenstream.cpp +++ b/src/parse/tokenstream.cpp @@ -116,11 +116,15 @@ ProtoSpan TokenStream::start_span() const Span TokenStream::end_span(ProtoSpan ps) const { auto p = this->getPosition(); - return Span( - ps.filename, - ps.start_line, ps.start_ofs, - p.line, p.ofs - ); + auto rv = Span( ps.filename, ps.start_line, ps.start_ofs, p.line, p.ofs ); + rv.outer_span = this->outerSpan(); + return rv; +} +Span TokenStream::point_span() const +{ + Span rv = this->getPosition(); + rv.outer_span = this->outerSpan(); + return rv; } Ident TokenStream::get_ident(Token tok) const { diff --git a/src/parse/tokenstream.hpp b/src/parse/tokenstream.hpp index 85fc62e2..5f2e0733 100644 --- a/src/parse/tokenstream.hpp +++ b/src/parse/tokenstream.hpp @@ -60,17 +60,19 @@ public: void putback(Token tok); eTokenType lookahead(unsigned int count); - virtual Position getPosition() const = 0; Ident::Hygiene getHygiene() const; ParseState& parse_state() { return m_parse_state; } ProtoSpan start_span() const; Span end_span(ProtoSpan ps) const; + Span point_span() const; Ident get_ident(Token tok) const; protected: + virtual Position getPosition() const = 0; + virtual ::std::shared_ptr outerSpan() const { return ::std::shared_ptr(0); } virtual Token realGetToken() = 0; virtual Ident::Hygiene realGetHygiene() const = 0; private: diff --git a/src/parse/types.cpp b/src/parse/types.cpp index 905bd935..ff993693 100644 --- a/src/parse/types.cpp +++ b/src/parse/types.cpp @@ -218,7 +218,7 @@ TypeRef Parse_Type_Fn(TokenStream& lex, ::std::vector<::std::string> hrls) if( GET_TOK(tok, lex) == TOK_STRING ) { abi = tok.str(); if( abi == "" ) - ERROR(lex.getPosition(), E0000, "Empty ABI"); + ERROR(lex.point_span(), E0000, "Empty ABI"); GET_TOK(tok, lex); } else { diff --git a/src/resolve/absolute.cpp b/src/resolve/absolute.cpp index 26a45a1e..1e197769 100644 --- a/src/resolve/absolute.cpp +++ b/src/resolve/absolute.cpp @@ -1601,7 +1601,7 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) Resolve_Absolute_Pattern(this->context, true, node.m_pattern); break; case ::AST::ExprNode_Loop::FOR: - BUG(node.get_pos(), "`for` should be desugared"); + BUG(node.span(), "`for` should be desugared"); } node.m_code->visit( *this ); this->context.pop_block(); @@ -1629,22 +1629,22 @@ void Resolve_Absolute_ExprNode(Context& context, ::AST::ExprNode& node) } void visit(AST::ExprNode_StructLiteral& node) override { DEBUG("ExprNode_StructLiteral"); - Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Type, node.m_path); + Resolve_Absolute_Path(this->context, node.span(), Context::LookupMode::Type, node.m_path); AST::NodeVisitorDef::visit(node); } void visit(AST::ExprNode_CallPath& node) override { DEBUG("ExprNode_CallPath"); - Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Variable, node.m_path); + Resolve_Absolute_Path(this->context, node.span(), Context::LookupMode::Variable, node.m_path); AST::NodeVisitorDef::visit(node); } void visit(AST::ExprNode_CallMethod& node) override { DEBUG("ExprNode_CallMethod"); - Resolve_Absolute_PathParams(this->context, Span(node.get_pos()), node.m_method.args()); + Resolve_Absolute_PathParams(this->context, node.span(), node.m_method.args()); AST::NodeVisitorDef::visit(node); } void visit(AST::ExprNode_NamedValue& node) override { - DEBUG("(" << node.get_pos() << ") ExprNode_NamedValue - " << node.m_path); - Resolve_Absolute_Path(this->context, Span(node.get_pos()), Context::LookupMode::Variable, node.m_path); + DEBUG("(" << node.span() << ") ExprNode_NamedValue - " << node.m_path); + Resolve_Absolute_Path(this->context, node.span(), Context::LookupMode::Variable, node.m_path); } void visit(AST::ExprNode_Cast& node) override { DEBUG("ExprNode_Cast"); diff --git a/src/span.cpp b/src/span.cpp index 29d7201b..8d176671 100644 --- a/src/span.cpp +++ b/src/span.cpp @@ -12,6 +12,7 @@ #include Span::Span(const Span& x): + outer_span(x.outer_span), filename(x.filename), start_line(x.start_line), start_ofs(x.start_ofs), @@ -20,6 +21,7 @@ Span::Span(const Span& x): { } Span::Span(const Position& pos): + outer_span(), filename(pos.filename), start_line(pos.line), start_ofs(pos.ofs), @@ -28,6 +30,7 @@ Span::Span(const Position& pos): { } Span::Span(): + outer_span(), filename("")/*, start_line(0), start_ofs(0), end_line(0), end_ofs(0) // */ -- cgit v1.2.3 From b3af24cd9e3715097997c8215f82f1184586f542 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 11 Jun 2017 21:03:45 +0800 Subject: Expand - Make file!/line! get the invocation location of a macro --- src/expand/file_line.cpp | 17 ++++++++++++++--- src/expand/macro_rules.cpp | 5 ----- src/expand/macro_rules.hpp | 2 -- src/expand/mod.cpp | 5 +++-- src/macro_rules/eval.cpp | 15 +++++++++++---- src/macro_rules/macro_rules.hpp | 2 +- 6 files changed, 29 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/expand/file_line.cpp b/src/expand/file_line.cpp index 8dfb7e6d..7e117993 100644 --- a/src/expand/file_line.cpp +++ b/src/expand/file_line.cpp @@ -9,12 +9,23 @@ #include "../parse/common.hpp" #include "../parse/ttstream.hpp" +namespace { + const Span& get_top_span(const Span& sp) { + if( sp.outer_span ) { + return get_top_span(*sp.outer_span); + } + else { + return sp; + } + } +} + class CExpanderFile: public ExpandProcMacro { ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override { - return box$( TTStreamO(TokenTree(Token(TOK_STRING, sp.filename.c_str()))) ); + return box$( TTStreamO(TokenTree(Token(TOK_STRING, get_top_span(sp).filename.c_str()))) ); } }; @@ -23,7 +34,7 @@ class CExpanderLine: { ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override { - return box$( TTStreamO(TokenTree(Token((uint64_t)sp.start_line, CORETYPE_U32))) ); + return box$( TTStreamO(TokenTree(Token((uint64_t)get_top_span(sp).start_line, CORETYPE_U32))) ); } }; @@ -32,7 +43,7 @@ class CExpanderColumn: { ::std::unique_ptr expand(const Span& sp, const AST::Crate& crate, const ::std::string& ident, const TokenTree& tt, AST::Module& mod) override { - return box$( TTStreamO(TokenTree(Token((uint64_t)sp.start_ofs, CORETYPE_U32))) ); + return box$( TTStreamO(TokenTree(Token((uint64_t)get_top_span(sp).start_ofs, CORETYPE_U32))) ); } }; diff --git a/src/expand/macro_rules.cpp b/src/expand/macro_rules.cpp index 338edd12..0375f430 100644 --- a/src/expand/macro_rules.cpp +++ b/src/expand/macro_rules.cpp @@ -169,11 +169,6 @@ class CMacroReexportHandler: } }; -::std::unique_ptr Macro_Invoke(const char* name, const MacroRules& rules, TokenTree tt, AST::Module& mod) -{ - return Macro_InvokeRules(name, rules, mv$(tt), mod); -} - STATIC_MACRO("macro_rules", CMacroRulesExpander); STATIC_DECORATOR("macro_use", CMacroUseHandler); diff --git a/src/expand/macro_rules.hpp b/src/expand/macro_rules.hpp index b5f09f1c..00332dd5 100644 --- a/src/expand/macro_rules.hpp +++ b/src/expand/macro_rules.hpp @@ -12,5 +12,3 @@ namespace AST { class TokenTree; class TokenStream; class MacroRules; - -extern ::std::unique_ptr Macro_Invoke(const char* name, const MacroRules& rules, TokenTree tt, AST::Module& mod); diff --git a/src/expand/mod.cpp b/src/expand/mod.cpp index 38e40347..5c3be722 100644 --- a/src/expand/mod.cpp +++ b/src/expand/mod.cpp @@ -11,6 +11,7 @@ #include #include #include "macro_rules.hpp" +#include "../macro_rules/macro_rules.hpp" #include "../parse/common.hpp" // For reparse from macros #include #include "cfg.hpp" @@ -115,7 +116,7 @@ void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate if( input_ident != "" ) ERROR(mi_span, E0000, "macro_rules! macros can't take an ident"); - auto e = Macro_Invoke(name.c_str(), *mr.data, mv$(input_tt), mod); + auto e = Macro_InvokeRules(name.c_str(), *mr.data, mi_span, mv$(input_tt), mod); return e; } } @@ -134,7 +135,7 @@ void Expand_Attrs(::AST::MetaItems& attrs, AttrStage stage, ::AST::Crate& crate } if( last_mac ) { - auto e = Macro_Invoke(name.c_str(), *last_mac, mv$(input_tt), mod); + auto e = Macro_InvokeRules(name.c_str(), *last_mac, mi_span, mv$(input_tt), mod); return e; } } diff --git a/src/macro_rules/eval.cpp b/src/macro_rules/eval.cpp index 1bac45ee..fffe9b68 100644 --- a/src/macro_rules/eval.cpp +++ b/src/macro_rules/eval.cpp @@ -577,6 +577,7 @@ class MacroExpander: const RcString m_macro_filename; const ::std::string m_crate_name; + ::std::shared_ptr m_invocation_span; ParameterMappings m_mappings; MacroExpandState m_state; @@ -588,9 +589,10 @@ class MacroExpander: public: MacroExpander(const MacroExpander& x) = delete; - MacroExpander(const ::std::string& macro_name, const Ident::Hygiene& parent_hygiene, const ::std::vector& contents, ParameterMappings mappings, ::std::string crate_name): + MacroExpander(const ::std::string& macro_name, const Span& sp, const Ident::Hygiene& parent_hygiene, const ::std::vector& contents, ParameterMappings mappings, ::std::string crate_name): m_macro_filename( FMT("Macro:" << macro_name) ), m_crate_name( mv$(crate_name) ), + m_invocation_span( new Span(sp) ), m_mappings( mv$(mappings) ), m_state( contents, m_mappings ), m_hygiene( Ident::Hygiene::new_scope_chained(parent_hygiene) ) @@ -598,6 +600,7 @@ public: } Position getPosition() const override; + ::std::shared_ptr outerSpan() const override; Ident::Hygiene realGetHygiene() const override; Token realGetToken() override; }; @@ -722,7 +725,7 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type } /// Parse the input TokenTree according to the `macro_rules!` patterns and return a token stream of the replacement -::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input, AST::Module& mod) +::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod) { TRACE_FUNCTION_F("'" << name << "', " << input); @@ -741,7 +744,7 @@ InterpolatedFragment Macro_HandlePatternCap(TokenStream& lex, MacroPatEnt::Type // Run through the expansion counting the number of times each fragment is used Macro_InvokeRules_CountSubstUses(bound_tts, rule.m_contents); - TokenStream* ret_ptr = new MacroExpander(name, rules.m_hygiene, rule.m_contents, mv$(bound_tts), rules.m_source_crate); + TokenStream* ret_ptr = new MacroExpander(name, sp, rules.m_hygiene, rule.m_contents, mv$(bound_tts), rules.m_source_crate); return ::std::unique_ptr( ret_ptr ); } @@ -1065,9 +1068,13 @@ void Macro_InvokeRules_CountSubstUses(ParameterMappings& bound_tts, const ::std: Position MacroExpander::getPosition() const { - // TODO: Return a far better span - invocaion location? + // TODO: Return the attached position of the last fetched token return Position(m_macro_filename, 0, m_state.top_pos()); } +::std::shared_ptr MacroExpander::outerSpan() const +{ + return m_invocation_span; +} Ident::Hygiene MacroExpander::realGetHygiene() const { if( m_ttstream ) diff --git a/src/macro_rules/macro_rules.hpp b/src/macro_rules/macro_rules.hpp index aed0e8ce..2a588a78 100644 --- a/src/macro_rules/macro_rules.hpp +++ b/src/macro_rules/macro_rules.hpp @@ -156,7 +156,7 @@ public: SERIALISABLE_PROTOTYPES(); }; -extern ::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, TokenTree input, AST::Module& mod); +extern ::std::unique_ptr Macro_InvokeRules(const char *name, const MacroRules& rules, const Span& sp, TokenTree input, AST::Module& mod); extern MacroRulesPtr Parse_MacroRules(TokenStream& lex); #endif // MACROS_HPP_INCLUDED -- cgit v1.2.3 From b653b8c5d25b0626d51f0d85c139d47f649db37b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 11 Jun 2017 21:47:30 +0800 Subject: Typecheck Static - Fix bug in needs_drop_glue --- src/hir_typeck/static.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/hir_typeck/static.cpp b/src/hir_typeck/static.cpp index 8a4dba50..0067eb7f 100644 --- a/src/hir_typeck/static.cpp +++ b/src/hir_typeck/static.cpp @@ -1670,6 +1670,7 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR TU_MATCH(::HIR::TypeRef::Data, (ty.m_data), (e), (Generic, + // TODO: Is this an error? return true; ), (Path, @@ -1797,7 +1798,7 @@ bool StaticTraitResolve::type_needs_drop_glue(const Span& sp, const ::HIR::TypeR (Tuple, for(const auto& ty : e) { - if( !type_needs_drop_glue(sp, ty) ) + if( type_needs_drop_glue(sp, ty) ) return true; } return false; -- cgit v1.2.3 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') 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') 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') 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') 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 8b082ee7d1ebf4488dd8d416431c08fdefffb639 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 16 Jun 2017 23:47:52 +0800 Subject: MIR optimise - Fix a few little bugs --- src/mir/helpers.cpp | 14 +++++++-- src/mir/mir_builder.cpp | 6 ++-- src/mir/optimise.cpp | 82 ++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 80 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 31b50246..02facac0 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -555,8 +555,18 @@ void MIR_Helper_GetLifetimes_DetermineValueLifetime(::MIR::TypeResolve& state, c } else { - // TODO: Can Argument(_) be assigned? - // Not a direct assignment of a slot + // Not a direct assignment of a slot. But check if a slot is mutated as part of this. + ::MIR::visit::visit_mir_lvalue(lv, ValUsage::Write, [&](const auto& ilv, ValUsage vu) { + if( const auto* de = ilv.opt_Local() ) + { + if( vu == ValUsage::Write ) + { + MIR_Helper_GetLifetimes_DetermineValueLifetime(state, fcn, bb_idx, stmt_idx, lv, block_offsets, slot_lifetimes[*de]); + slot_lifetimes[*de].fill(block_offsets, bb_idx, stmt_idx, stmt_idx); + } + } + return false; + }); } }; diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 5ace0bb0..7dee2003 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -437,10 +437,12 @@ void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, con ) 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 ) { + bool is_temp = (idx >= m_first_temp_idx); + /* + if( !is_temp ) { return ; } + */ // Find controlling scope auto scope_it = m_scope_stack.rbegin(); diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 6837eab6..39681596 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -17,7 +17,7 @@ #include #include -#define DUMP_BEFORE_ALL 0 +#define DUMP_BEFORE_ALL 1 #define DUMP_BEFORE_CONSTPROPAGATE 0 #define CHECK_AFTER_PASS 0 #define CHECK_AFTER_ALL 0 @@ -476,21 +476,11 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path MIR_Validate(resolve, path, fcn, args, ret_type); #endif - // >> Inline short functions - bool inline_happened = MIR_Optimise_Inlining(state, fcn); - if( inline_happened ) - { - // Apply cleanup again (as monomorpisation in inlining may have exposed a vtable call) - MIR_Cleanup(resolve, path, fcn, args, ret_type); - //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 +#if DUMP_BEFORE_ALL || DUMP_BEFORE_PSA + if( debug_enabled() ) MIR_Dump_Fcn(::std::cout, fcn); +#endif // >> Propagate/remove dead assignments while( MIR_Optimise_PropagateSingleAssignments(state, fcn) ) change_happened = true; @@ -512,6 +502,26 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // >> Remove assignments of unsed drop flags change_happened |= MIR_Optimise_DeadDropFlags(state, fcn); + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + + // >> Inline short functions + if( !change_happened ) + { + bool inline_happened = MIR_Optimise_Inlining(state, fcn); + if( inline_happened ) + { + // Apply cleanup again (as monomorpisation in inlining may have exposed a vtable call) + MIR_Cleanup(resolve, path, fcn, args, ret_type); + //MIR_Dump_Fcn(::std::cout, fcn); + change_happened = true; + } + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + } + if( change_happened ) { #if DUMP_AFTER_PASS @@ -704,7 +714,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) // TODO: Allow functions that are just a switch on an input. if( fcn.blocks.size() == 1 ) { - return fcn.blocks[0].statements.size() < 5 && ! fcn.blocks[0].terminator.is_Goto(); + return fcn.blocks[0].statements.size() < 10 && ! fcn.blocks[0].terminator.is_Goto(); } else if( fcn.blocks.size() == 3 && fcn.blocks[0].terminator.is_Call() ) { @@ -741,6 +751,8 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) size_t tmp_end = 0; mutable ::std::vector< ::MIR::Constant > const_assignments; + ::MIR::LValue retval; + Cloner(const Span& sp, const ::StaticTraitResolve& resolve, ::MIR::Terminator::Data_Call& te): sp(sp), resolve(resolve), @@ -838,8 +850,14 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) rv.statements.push_back(::MIR::Statement( mv$(new_se) )); ) ) + DEBUG("-> " << rv.statements.back()); } DEBUG("BB" << src_idx << "->BB" << new_idx << "/" << rv.statements.size() << ": " << src.terminator); + if(src.terminator.is_Return()) + { + rv.statements.push_back(::MIR::Statement::make_Assign({ this->te.ret_val.clone(), this->retval.clone() })); + DEBUG("++ " << rv.statements.back()); + } rv.terminator = this->clone_term(src.terminator); DEBUG("-> " << rv.terminator); return rv; @@ -924,11 +942,12 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) rv.push_back( this->clone_param(lv) ); return rv; } + ::MIR::LValue clone_lval(const ::MIR::LValue& src) const { TU_MATCHA( (src), (se), (Return, - return this->te.ret_val.clone(); + return this->retval.clone(); ), (Argument, const auto& arg = this->te.args.at(se.idx); @@ -1075,16 +1094,28 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) DEBUG("Can't inline " << path); continue ; } + DEBUG(state << fcn.blocks[i].terminator); TRACE_FUNCTION_F("Inline " << path); - // Monomorph values and append + // Allocate a temporary for the return value + { + cloner.retval = ::MIR::LValue::make_Local( fcn.locals.size() ); + DEBUG("- Storing return value in " << cloner.retval); + ::HIR::TypeRef tmp_ty; + fcn.locals.push_back( state.get_lvalue_type(tmp_ty, te->ret_val).clone() ); + //fcn.local_names.push_back( "" ); + } + + // Monomorph locals and append 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(); + // Append monomorphised copy of all blocks. // > Arguments replaced by input lvalues ::std::vector<::MIR::BasicBlock> new_blocks; @@ -1093,6 +1124,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) { new_blocks.push_back( cloner.clone_bb(bb, (&bb - called_mir->blocks.data()), fcn.blocks.size() + new_blocks.size()) ); } + // > Append new temporaries for(auto& val : cloner.const_assignments) { @@ -2134,6 +2166,19 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F const auto& new_dst_lval = it2->as_Assign().dst; // `... = Use(to_replace_lval)` + // TODO: Ensure that the target isn't borrowed. + if( const auto* e = new_dst_lval.opt_Local() ) { + const auto& vu = val_uses.local_uses[*e]; + if( !( vu.read == 1 && vu.write == 1 && vu.borrow == 0 ) ) + break ; + } + else if( new_dst_lval.is_Return() ) { + // Return, can't be borrowed? + } + else { + break; + } + // Ensure that the target doesn't change in the intervening time. bool was_invalidated = false; for(auto it3 = it+1; it3 != it2; it3++) @@ -2234,6 +2279,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F { for(auto it = block.statements.begin(); it != block.statements.end(); ++it) { + state.set_cur_stmt(&block - &fcn.blocks.front(), it - block.statements.begin()); if( const auto& se = it->opt_Assign() ) { TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de), @@ -2242,7 +2288,7 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F (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"); + DEBUG(state << se->dst << " only written, removing write"); it = block.statements.erase(it)-1; } ) -- cgit v1.2.3 From d524780a187a69e2c840359d9958ec16b41d1e68 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 17 Jun 2017 12:42:51 +0800 Subject: MIR Optimise - Sort BBs into approximate program flow --- src/mir/operations.hpp | 1 + src/mir/optimise.cpp | 117 ++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mir/operations.hpp b/src/mir/operations.hpp index 1c06bc8c..d8769dc4 100644 --- a/src/mir/operations.hpp +++ b/src/mir/operations.hpp @@ -16,5 +16,6 @@ extern void MIR_Validate_Full(const StaticTraitResolve& resolve, const ::HIR::It extern void MIR_Cleanup(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type); // Optimise the MIR extern void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type); +extern void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn); extern void MIR_Dump_Fcn(::std::ostream& sink, const ::MIR::Function& fcn, unsigned int il=0); diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 39681596..4760d3d5 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -552,8 +552,9 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // - Find unused blocks, then delete and rewrite all references. MIR_Optimise_GarbageCollect(state, fcn); - //MIR_Validate(resolve, path, fcn, args, ret_type); //MIR_Validate_Full(resolve, path, fcn, args, ret_type); + + MIR_SortBlocks(resolve, path, fcn); } // -------------------------------------------------------------------- @@ -2282,6 +2283,18 @@ bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::F state.set_cur_stmt(&block - &fcn.blocks.front(), it - block.statements.begin()); if( const auto& se = it->opt_Assign() ) { + // Remove No-op assignments (assignment from a lvalue to itself) + if( const auto* src_e = se->src.opt_Use() ) + { + if( se->dst == *src_e ) + { + DEBUG(state << se->dst << " set to itself, removing write"); + it = block.statements.erase(it)-1; + continue ; + } + } + + // Remove assignments of locals that are never read TU_MATCH_DEF( ::MIR::LValue, (se->dst), (de), ( ), @@ -2600,6 +2613,108 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn return false; } + +void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn) +{ + ::std::vector visited( fcn.blocks.size() ); + ::std::vector<::std::pair> depths( fcn.blocks.size() ); + + struct Todo { + size_t bb_idx; + unsigned branch_count; + unsigned level; + }; + unsigned int branches = 0; + ::std::vector todo; + todo.push_back( Todo { 0, 0, 0 } ); + + while(!todo.empty()) + { + auto info = todo.back(); + todo.pop_back(); + if( visited[info.bb_idx] ) + continue ; + + visited[info.bb_idx] = true; + depths[info.bb_idx] = ::std::make_pair( info.branch_count, info.level ); + const auto& bb = fcn.blocks[info.bb_idx]; + + TU_MATCHA( (bb.terminator), (te), + (Incomplete, + ), + (Return, + ), + (Diverge, + ), + (Goto, + todo.push_back(Todo { te, info.branch_count, info.level + 1 }); + ), + (Panic, + todo.push_back(Todo { te.dst, info.branch_count, info.level + 1 }); + ), + (If, + todo.push_back(Todo { te.bb0, ++branches, info.level + 1 }); + todo.push_back(Todo { te.bb1, ++branches, info.level + 1 }); + ), + (Switch, + for(auto dst : te.targets) + todo.push_back(Todo { dst, ++branches, 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 }); + ) + ) + } + + // Sort a list of block indexes by `depths` + ::std::vector idxes; + idxes.reserve(fcn.blocks.size()); + for(size_t i = 0; i < fcn.blocks.size(); i++) + idxes.push_back(i); + ::std::sort( idxes.begin(), idxes.end(), [&](auto a, auto b){ + return depths.at(a) < depths.at(b); + }); + + DEBUG(idxes); + + decltype(fcn.blocks) new_block_list; + new_block_list.reserve( fcn.blocks.size() ); + for(auto idx : idxes) + { + 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, + 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); +} + + void MIR_OptimiseCrate(::HIR::Crate& crate) { ::MIR::OuterVisitor ov { crate, [](const auto& res, const auto& p, auto& expr, const auto& args, const auto& ty) -- cgit v1.2.3 From 0a3acb319e9daebdb448af2995757cf5fb58bb4d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 18 Jun 2017 09:53:01 +0800 Subject: MIR Optimise - (minor) Comment on sort --- src/mir/optimise.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 4760d3d5..630ac584 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -2614,6 +2614,7 @@ bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn } +/// Sort basic blocks to approximate program flow (helps when reading MIR) void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn) { ::std::vector visited( fcn.blocks.size() ); -- 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') 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') 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 239b7826470dab3effc703b33d4d7a2a761c461e Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 22 Jun 2017 12:05:13 +0800 Subject: MIR Gen - Remove arguments that are just assigned from arguments --- src/mir/from_hir.hpp | 5 +++++ src/mir/mir_builder.cpp | 10 ++++++++++ 2 files changed, 15 insertions(+) (limited to 'src') diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 2730631f..ce310945 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -135,6 +135,8 @@ class MirBuilder ::std::vector m_slot_states; size_t m_first_temp_idx; + ::std::map m_var_arg_mappings; + struct ScopeDef { const Span& span; @@ -173,6 +175,9 @@ public: // - Values ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { + auto it = m_var_arg_mappings.find(idx); + if(it != m_var_arg_mappings.end()) + return ::MIR::LValue::make_Argument({ it->second }); return ::MIR::LValue::make_Local( idx ); } ::MIR::LValue new_temporary(const ::HIR::TypeRef& ty); diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 7dee2003..1549d39a 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -40,6 +40,16 @@ MirBuilder::MirBuilder(const Span& sp, const StaticTraitResolve& resolve, const DEBUG("First temporary will be " << m_first_temp_idx); m_if_cond_lval = this->new_temporary(::HIR::CoreType::Bool); + + // Determine which variables can be replaced by arguents + for(size_t i = 0; i < args.size(); i ++) + { + const auto& pat = args[i].first; + if( pat.m_binding.is_valid() && pat.m_binding.m_type == ::HIR::PatternBinding::Type::Move ) + { + m_var_arg_mappings[pat.m_binding.m_slot] = i; + } + } } MirBuilder::~MirBuilder() { -- cgit v1.2.3 From d514aee4850933e3d3d5529453aa2c8af250d4ce Mon Sep 17 00:00:00 2001 From: John Hodge Date: Fri, 23 Jun 2017 11:32:46 +0800 Subject: MIR Gen - Disable argument replacement until argument states are tracked fully --- src/mir/from_hir.hpp | 3 +++ src/mir/mir_builder.cpp | 18 +++++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index ce310945..f8834d98 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -175,9 +175,12 @@ public: // - Values ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { + // DIASBLED: State tracking doesn't support arguments in loops/splits +#if 0 auto it = m_var_arg_mappings.find(idx); if(it != m_var_arg_mappings.end()) return ::MIR::LValue::make_Argument({ it->second }); +#endif return ::MIR::LValue::make_Local( idx ); } ::MIR::LValue new_temporary(const ::HIR::TypeRef& ty); diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 1549d39a..0d5641ff 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -60,8 +60,9 @@ MirBuilder::~MirBuilder() { push_stmt_assign( sp, ::MIR::LValue::make_Return({}), get_result(sp) ); } - terminate_scope( sp, ScopeHandle { *this, 1 } ); - terminate_scope( sp, mv$(m_fcn_scope) ); + + terminate_scope_early(sp, fcn_scope()); + end_block( ::MIR::Terminator::make_Return({}) ); } } @@ -83,7 +84,7 @@ const ::HIR::TypeRef* MirBuilder::is_type_owned_box(const ::HIR::TypeRef& ty) co if( pe.m_path != *m_lang_Box ) { return nullptr; } - // TODO: Properly assert? + // TODO: Properly assert the size? return &pe.m_params.m_types.at(0); } else @@ -939,6 +940,17 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, ) } } + + + // Index 0 is the function scope, this only happens when about to return/panic + if( scope.idx == 0 ) + { + // Ensure that all arguments are dropped if they were not moved + for(size_t i = 0; i < m_arg_states.size(); i ++) + { + this->drop_value_from_state(sp, m_arg_states[i], ::MIR::LValue::make_Argument({ static_cast(i) })); + } + } } namespace -- cgit v1.2.3 From beeda64094e707764db29eabc83ddfee6f5e9c03 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 25 Jun 2017 12:04:10 +0800 Subject: MIR Optimise - Support minimal optimisiations --- src/main.cpp | 39 +++++- src/mir/main_bindings.hpp | 2 +- src/mir/optimise.cpp | 323 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 342 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index 27721cb0..ce5a3f48 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -144,6 +144,13 @@ struct ProgramParams ::std::set< ::std::string> features; + + struct { + bool disable_mir_optimisations = false; + bool full_validate = false; + bool full_validate_early = false; + } debug; + ProgramParams(int argc, char *argv[]); }; @@ -434,7 +441,7 @@ int main(int argc, char *argv[]) CompilePhaseV("MIR Cleanup", [&]() { MIR_CleanupCrate(*hir_crate); }); - if( getenv("MRUSTC_FULL_VALIDATE_PREOPT") ) + if( params.debug.full_validate_early || getenv("MRUSTC_FULL_VALIDATE_PREOPT") ) { CompilePhaseV("MIR Validate Full Early", [&]() { MIR_CheckCrate_Full(*hir_crate); @@ -443,7 +450,7 @@ int main(int argc, char *argv[]) // Optimise the MIR CompilePhaseV("MIR Optimise", [&]() { - MIR_OptimiseCrate(*hir_crate); + MIR_OptimiseCrate(*hir_crate, params.debug.disable_mir_optimisations); }); CompilePhaseV("Dump MIR", [&]() { @@ -456,7 +463,7 @@ int main(int argc, char *argv[]) // - Exhaustive MIR validation (follows every code path and checks variable validity) // > DEBUGGING ONLY CompilePhaseV("MIR Validate Full", [&]() { - if( getenv("MRUSTC_FULL_VALIDATE") ) + if( params.debug.full_validate || getenv("MRUSTC_FULL_VALIDATE") ) MIR_CheckCrate_Full(*hir_crate); }); @@ -596,6 +603,32 @@ ProgramParams::ProgramParams(int argc, char *argv[]) this->libraries.push_back( arg+1 ); } continue ; + case 'Z': { + ::std::string optname; + if( arg[1] == '\0' ) { + if( i == argc - 1) { + exit(1); + } + optname = argv[++i]; + } + else { + optname = arg+1; + } + + if( optname == "disable_mir_opt" ) { + this->debug.disable_mir_optimisations = true; + } + else if( optname == "full-validate" ) { + this->debug.full_validate = true; + } + else if( optname == "full-validate-early" ) { + this->debug.full_validate_early = true; + } + else { + ::std::cerr << "Unknown debug option: '" << optname << "'" << ::std::endl; + exit(1); + } + } continue; default: break; diff --git a/src/mir/main_bindings.hpp b/src/mir/main_bindings.hpp index 0d6074cb..4e7e3b78 100644 --- a/src/mir/main_bindings.hpp +++ b/src/mir/main_bindings.hpp @@ -18,4 +18,4 @@ extern void MIR_CheckCrate(/*const*/ ::HIR::Crate& crate); extern void MIR_CheckCrate_Full(/*const*/ ::HIR::Crate& crate); extern void MIR_CleanupCrate(::HIR::Crate& crate); -extern void MIR_OptimiseCrate(::HIR::Crate& crate); +extern void MIR_OptimiseCrate(::HIR::Crate& crate, bool minimal_optimisations); diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index 630ac584..cc06ab0c 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -19,8 +19,8 @@ #define DUMP_BEFORE_ALL 1 #define DUMP_BEFORE_CONSTPROPAGATE 0 -#define CHECK_AFTER_PASS 0 -#define CHECK_AFTER_ALL 0 +#define CHECK_AFTER_PASS 1 +#define CHECK_AFTER_ALL 1 #define DUMP_AFTER_DONE 0 #define CHECK_AFTER_DONE 1 @@ -441,11 +441,39 @@ namespace { 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) { + if( v == lv ) { + return vu != ValUsage::Read; + } + return false; + }); + } + bool terminator_invalidates_lvalue(const ::MIR::Terminator& term, const ::MIR::LValue& lv) + { + if( const auto* e = term.opt_Call() ) + { + return visit_mir_lvalue(e->ret_val, ValUsage::Write, [&](const auto& v, auto vu) { + if( v == lv ) { + return vu != ValUsage::Read; + } + return false; + }); + } + else + { + return false; + } + } } bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn); -bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool minimal); bool MIR_Optimise_PropagateSingleAssignments(::MIR::TypeResolve& state, ::MIR::Function& fcn); +bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_ConstPropagte(::MIR::TypeResolve& state, ::MIR::Function& fcn); @@ -453,12 +481,40 @@ bool MIR_Optimise_DeadDropFlags(::MIR::TypeResolve& state, ::MIR::Function& fcn) bool MIR_Optimise_GarbageCollect_Partial(::MIR::TypeResolve& state, ::MIR::Function& fcn); bool MIR_Optimise_GarbageCollect(::MIR::TypeResolve& state, ::MIR::Function& fcn); -void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type) +/// A minimum set of optimisations: +/// - Inlines `#[inline(always)]` functions +/// - Simplifies the call graph (by removing chained gotos) +/// - Sorts blocks into a rough flow order +void MIR_OptimiseMin(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type) { static Span sp; TRACE_FUNCTION_F(path); ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; + while( MIR_Optimise_Inlining(state, fcn, true) ) + { + MIR_Cleanup(resolve, path, fcn, args, ret_type); + //MIR_Dump_Fcn(::std::cout, fcn); + #if CHECK_AFTER_ALL + MIR_Validate(resolve, path, fcn, args, ret_type); + #endif + } + + MIR_Optimise_BlockSimplify(state, fcn); + MIR_Optimise_UnifyBlocks(state, fcn); + + //MIR_Optimise_GarbageCollect_Partial(state, fcn); + + MIR_Optimise_GarbageCollect(state, fcn); + //MIR_Validate_Full(resolve, path, fcn, args, ret_type); + MIR_SortBlocks(resolve, path, fcn); + return ; +} +void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path, ::MIR::Function& fcn, const ::HIR::Function::args_t& args, const ::HIR::TypeRef& ret_type) +{ + static Span sp; + TRACE_FUNCTION_F(path); + ::MIR::TypeResolve state { sp, resolve, FMT_CB(ss, ss << path;), ret_type, args, fcn }; bool change_happened; unsigned int pass_num = 0; @@ -467,7 +523,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path change_happened = false; TRACE_FUNCTION_FR("Pass " << pass_num, change_happened); - // >> Simplify call graph + // >> Simplify call graph (removes gotos to blocks with a single use) MIR_Optimise_BlockSimplify(state, fcn); // >> Apply known constants @@ -476,6 +532,13 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path MIR_Validate(resolve, path, fcn, args, ret_type); #endif + // >> Replace values from composites if they're known + // - Undoes the inefficiencies from the `match (a, b) { ... }` pattern + change_happened |= MIR_Optimise_PropagateKnownValues(state, fcn); +#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 #if DUMP_BEFORE_ALL || DUMP_BEFORE_PSA @@ -509,7 +572,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path // >> Inline short functions if( !change_happened ) { - bool inline_happened = MIR_Optimise_Inlining(state, fcn); + bool inline_happened = MIR_Optimise_Inlining(state, fcn, false); if( inline_happened ) { // Apply cleanup again (as monomorpisation in inlining may have exposed a vtable call) @@ -529,7 +592,7 @@ void MIR_Optimise(const StaticTraitResolve& resolve, const ::HIR::ItemPath& path MIR_Dump_Fcn(::std::cout, fcn); } #endif - #if CHECK_AFTER_PASS + #if CHECK_AFTER_PASS && !CHECK_AFTER_ALL MIR_Validate(resolve, path, fcn, args, ret_type); #endif } @@ -704,14 +767,22 @@ bool MIR_Optimise_BlockSimplify(::MIR::TypeResolve& state, ::MIR::Function& fcn) // -------------------------------------------------------------------- // If two temporaries don't overlap in lifetime (blocks in which they're valid), unify the two // -------------------------------------------------------------------- -bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) +bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool minimal) { TRACE_FUNCTION; struct H { - static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn) + static bool can_inline(const ::HIR::Path& path, const ::MIR::Function& fcn, bool minimal) { + // TODO: If the function is marked as `inline(always)`, then inline it regardless of the contents + + if( minimal ) { + return false; + } + + // TODO: If the function is marked as `inline(never)`, then don't inline + // TODO: Allow functions that are just a switch on an input. if( fcn.blocks.size() == 1 ) { @@ -743,6 +814,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) const Span& sp; const ::StaticTraitResolve& resolve; const ::MIR::Terminator::Data_Call& te; + ::std::vector copy_args; // Local indexes containing copies of Copy args ParamsSet params; unsigned int bb_base = ~0u; unsigned int tmp_base = ~0u; @@ -750,15 +822,17 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) unsigned int df_base = ~0u; size_t tmp_end = 0; - mutable ::std::vector< ::MIR::Constant > const_assignments; + mutable ::std::vector< ::MIR::Param > const_assignments; ::MIR::LValue retval; Cloner(const Span& sp, const ::StaticTraitResolve& resolve, ::MIR::Terminator::Data_Call& te): sp(sp), resolve(resolve), - te(te) - {} + te(te), + copy_args(te.args.size(), ~0u) + { + } ::HIR::TypeRef monomorph(const ::HIR::TypeRef& ty) const { auto rv = monomorphise_type_with(sp, ty, params.get_cb(sp)); @@ -958,6 +1032,10 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) this->const_assignments.push_back( e->clone() ); return tmp; } + else if( this->copy_args[se.idx] != ~0u ) + { + return ::MIR::LValue::make_Local(this->copy_args[se.idx]); + } else { return arg.as_LValue().clone(); @@ -1009,6 +1087,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) { TU_MATCHA( (src), (se), (LValue, + // NOTE: No need to use `copy_args` here as all uses of Param are copies/moves if( const auto* ae = se.opt_Argument() ) return this->te.args.at(ae->idx).clone(); return clone_lval(se); @@ -1090,7 +1169,7 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) // Inline IF: // - First BB ends with a call and total count is 3 // - Statement count smaller than 10 - if( ! H::can_inline(path, *called_mir) ) + if( ! H::can_inline(path, *called_mir, minimal) ) { DEBUG("Can't inline " << path); continue ; @@ -1117,6 +1196,20 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) fcn.drop_flags.insert( fcn.drop_flags.end(), called_mir->drop_flags.begin(), called_mir->drop_flags.end() ); cloner.bb_base = fcn.blocks.size(); + // Take a copy of all Copy arguments (!Copy doesn't matter, as they're unusable after the call) + for(size_t i = 0; i < te->args.size(); i++) + { + if(const auto* e = te->args[i].opt_LValue()) + { + if( state.lvalue_is_copy(*e) ) + { + cloner.copy_args[i] = cloner.tmp_end + cloner.const_assignments.size(); + cloner.const_assignments.push_back( e->clone() ); + DEBUG("- Taking a copy of arg " << i << " (" << *e << ") in Local(" << cloner.copy_args[i] << ")"); + } + } + } + // Append monomorphised copy of all blocks. // > Arguments replaced by input lvalues ::std::vector<::MIR::BasicBlock> new_blocks; @@ -1129,10 +1222,12 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn) // > Append new temporaries for(auto& val : cloner.const_assignments) { - auto ty = state.get_const_type(val); + ::HIR::TypeRef tmp; + auto ty = val.is_Constant() ? state.get_const_type(val.as_Constant()) : state.get_lvalue_type(tmp, val.as_LValue()).clone(); auto lv = ::MIR::LValue::make_Local( static_cast(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) }) ); + auto rval = val.is_Constant() ? ::MIR::RValue(mv$(val.as_Constant())) : ::MIR::RValue( mv$(val.as_LValue()) ); + new_blocks[0].statements.insert( new_blocks[0].statements.begin(), ::MIR::Statement::make_Assign({ mv$(lv), mv$(rval) }) ); } cloner.const_assignments.clear(); @@ -1236,6 +1331,7 @@ bool MIR_Optimise_UnifyTemporaries(::MIR::TypeResolve& state, ::MIR::Function& f } // -------------------------------------------------------------------- +// Combine identical blocks // -------------------------------------------------------------------- bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) { @@ -1434,6 +1530,192 @@ bool MIR_Optimise_UnifyBlocks(::MIR::TypeResolve& state, ::MIR::Function& fcn) } } +// -------------------------------------------------------------------- +// Propagate source values when a composite (tuple) is read +// -------------------------------------------------------------------- +bool MIR_Optimise_PropagateKnownValues(::MIR::TypeResolve& state, ::MIR::Function& fcn) +{ + TRACE_FUNCTION; + // 1. Determine reference counts for blocks (allows reversing up BB tree) + ::std::vector block_origins( fcn.blocks.size(), SIZE_MAX ); + { + ::std::vector block_uses( fcn.blocks.size() ); + ::std::vector visited( fcn.blocks.size() ); + ::std::vector< ::MIR::BasicBlockId> to_visit; + to_visit.push_back( 0 ); + block_uses[0] ++; + while( to_visit.size() > 0 ) + { + auto bb = to_visit.back(); to_visit.pop_back(); + if( visited[bb] ) + continue ; + visited[bb] = true; + const auto& block = fcn.blocks[bb]; + + auto ref_block = [&](auto idx) { + if( !visited[idx] ) + to_visit.push_back(idx); + if(block_uses[idx] == 0) + block_origins[idx] = bb; + 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); + ) + ) + } + } + + // 2. Find any assignments (or function uses?) of the form FIELD(LOCAL, _) + // > Restricted to simplify logic (and because that's the inefficient pattern observed) + // 3. Search backwards from that point until the referenced local is assigned + bool change_happend = false; + auto get_field = [&](const ::MIR::LValue& slot_lvalue, unsigned field, size_t start_bb_idx, size_t start_stmt_idx)->const ::MIR::LValue* { + TRACE_FUNCTION_F(slot_lvalue << "." << field << " BB" << start_bb_idx << "/" << start_stmt_idx); + // NOTE: An infinite loop is (theoretically) impossible. + auto bb_idx = start_bb_idx; + auto stmt_idx = start_stmt_idx; + for(;;) + { + const auto& bb = fcn.blocks[bb_idx]; + while(stmt_idx --) + { + if( stmt_idx == bb.statements.size() ) + { + DEBUG("BB" << bb_idx << "/TERM - " << bb.terminator); + if( terminator_invalidates_lvalue(bb.terminator, slot_lvalue) ) { + return nullptr; + } + continue ; + } + const auto& stmt = bb.statements[stmt_idx]; + DEBUG("BB" << bb_idx << "/" << stmt_idx << " - " << stmt); + if( const auto* se = stmt.opt_Assign() ) + { + if( se->dst == slot_lvalue ) + { + if( !se->src.is_Tuple() ) + return nullptr; + const auto& src_param = se->src.as_Tuple().vals.at(field); + DEBUG("> Found a source " << src_param); + // TODO: Support returning a Param + if( !src_param.is_LValue() ) + return nullptr; + const auto& src_lval = src_param.as_LValue(); + // Visit all statements between the start and here, checking for mutation of this value. + auto end_bb_idx = bb_idx; + auto end_stmt_idx = stmt_idx; + bb_idx = start_bb_idx; + stmt_idx = start_stmt_idx; + for(;;) + { + const auto& bb = fcn.blocks[bb_idx]; + while(stmt_idx--) + { + if(bb_idx == end_bb_idx && stmt_idx == end_stmt_idx) + return &src_lval; + if(stmt_idx == bb.statements.size()) + { + DEBUG("BB" << bb_idx << "/TERM - " << bb.terminator); + if( terminator_invalidates_lvalue(bb.terminator, src_lval) ) { + // Invalidated: Return. + return nullptr; + } + continue ; + } + if( statement_invalidates_lvalue(bb.statements[stmt_idx], src_lval) ) { + // Invalidated: Return. + return nullptr; + } + } + assert( block_origins[bb_idx] != SIZE_MAX ); + bb_idx = block_origins[bb_idx]; + stmt_idx = fcn.blocks[bb_idx].statements.size() + 1; + } + throw ""; + } + } + + // Check if the slot is invalidated (mutated) + if( statement_invalidates_lvalue(stmt, slot_lvalue) ) { + return nullptr; + } + } + if( block_origins[bb_idx] == SIZE_MAX ) + break; + bb_idx = block_origins[bb_idx]; + stmt_idx = fcn.blocks[bb_idx].statements.size() + 1; + } + return nullptr; + }; + for(auto& block : fcn.blocks) + { + size_t bb_idx = &block - &fcn.blocks.front(); + for(size_t i = 0; i < block.statements.size(); i++) + { + state.set_cur_stmt(bb_idx, i); + DEBUG(state << block.statements[i]); + visit_mir_lvalues_mut(block.statements[i], [&](::MIR::LValue& lv, auto vu) { + if(const auto* e = lv.opt_Field()) + { + if(vu == ValUsage::Read && e->val->is_Local() ) { + // TODO: This value _must_ be Copy for this optimisation to work. + // - OR, it has to somehow invalidate the original tuple + DEBUG(state << "Locating origin of " << lv); + ::HIR::TypeRef tmp; + if( !state.m_resolve.type_is_copy(state.sp, state.get_lvalue_type(tmp, *e->val)) ) + { + DEBUG(state << "- not Copy, can't optimise"); + return false; + } + const auto* source_lvalue = get_field(*e->val, e->field_index, bb_idx, i); + if( source_lvalue ) + { + if( lv != *source_lvalue ) + { + DEBUG(state << "Source is " << *source_lvalue); + lv = source_lvalue->clone(); + change_happend = true; + } + else + { + DEBUG(state << "No change"); + } + return false; + } + } + } + return false; + }); + } + } + return change_happend; +} // -------------------------------------------------------------------- // Propagate constants and eliminate known paths @@ -2716,11 +2998,16 @@ void MIR_SortBlocks(const StaticTraitResolve& resolve, const ::HIR::ItemPath& pa } -void MIR_OptimiseCrate(::HIR::Crate& crate) +void MIR_OptimiseCrate(::HIR::Crate& crate, bool do_minimal_optimisation) { - ::MIR::OuterVisitor ov { crate, [](const auto& res, const auto& p, auto& expr, const auto& args, const auto& ty) + ::MIR::OuterVisitor ov { crate, [do_minimal_optimisation](const auto& res, const auto& p, auto& expr, const auto& args, const auto& ty) { - MIR_Optimise(res, p, *expr.m_mir, args, ty); + if( do_minimal_optimisation ) { + MIR_OptimiseMin(res, p, *expr.m_mir, args, ty); + } + else { + MIR_Optimise(res, p, *expr.m_mir, args, ty); + } } }; ov.visit_crate(crate); -- cgit v1.2.3 From a6e215ef782b7cc7351989697d9ba189f76b119b Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 25 Jun 2017 12:32:52 +0800 Subject: MIR Helpers - Add a shortcut to check if a LValue is Copy --- src/mir/helpers.cpp | 5 +++++ src/mir/helpers.hpp | 1 + 2 files changed, 6 insertions(+) (limited to 'src') diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 02facac0..7b2fabd5 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -293,6 +293,11 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c ) throw ""; } +bool ::MIR::TypeResolve::lvalue_is_copy(const ::MIR::LValue& val) const +{ + ::HIR::TypeRef tmp; + return m_resolve.type_is_copy( this->sp, get_lvalue_type(tmp, val) ); +} const ::HIR::TypeRef* ::MIR::TypeResolve::is_type_owned_box(const ::HIR::TypeRef& ty) const { return m_resolve.is_type_owned_box(ty); diff --git a/src/mir/helpers.hpp b/src/mir/helpers.hpp index 091a669f..f241753e 100644 --- a/src/mir/helpers.hpp +++ b/src/mir/helpers.hpp @@ -104,6 +104,7 @@ public: ::HIR::TypeRef get_const_type(const ::MIR::Constant& c) const; + bool lvalue_is_copy(const ::MIR::LValue& val) const; const ::HIR::TypeRef* is_type_owned_box(const ::HIR::TypeRef& ty) const; friend ::std::ostream& operator<<(::std::ostream& os, const TypeResolve& x) { -- cgit v1.2.3 From 115c56651d5cb352162b45269c3e09832c2fff40 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jul 2017 10:06:59 +0800 Subject: MIR Gen - Track states for arguments (and directly use arguments where possible) --- src/mir/from_hir.cpp | 11 ++- src/mir/from_hir.hpp | 15 ++- src/mir/from_hir_match.cpp | 25 +++-- src/mir/mir_builder.cpp | 225 +++++++++++++++++++++++++++++---------------- 4 files changed, 181 insertions(+), 95 deletions(-) (limited to 'src') diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index 149d53ea..bc9b04a7 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -2252,8 +2252,15 @@ namespace { unsigned int i = 0; for( const auto& arg : args ) { - ev.define_vars_from(ptr->span(), arg.first); - ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + const auto& pat = arg.first; + if( pat.m_binding.is_valid() && pat.m_binding.m_type == ::HIR::PatternBinding::Type::Move ) + { + } + else + { + ev.define_vars_from(ptr->span(), arg.first); + ev.destructure_from(ptr->span(), arg.first, ::MIR::LValue::make_Argument({i})); + } i ++; } diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index f8834d98..11a18a6d 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -80,9 +80,11 @@ struct SplitArm { bool has_early_terminated = false; bool always_early_terminated = false; // Populated on completion ::std::map states; + ::std::map arg_states; }; struct SplitEnd { ::std::map states; + ::std::map arg_states; }; TAGGED_UNION(ScopeType, Owning, @@ -98,6 +100,7 @@ TAGGED_UNION(ScopeType, Owning, (Loop, struct { // NOTE: This contains the original state for variables changed after `exit_state_valid` is true ::std::map changed_slots; + ::std::map changed_args; bool exit_state_valid; SplitEnd exit_state; }) @@ -176,7 +179,7 @@ public: // - Values ::MIR::LValue get_variable(const Span& sp, unsigned idx) const { // DIASBLED: State tracking doesn't support arguments in loops/splits -#if 0 +#if 1 auto it = m_var_arg_mappings.find(idx); if(it != m_var_arg_mappings.end()) return ::MIR::LValue::make_Argument({ it->second }); @@ -262,7 +265,7 @@ public: /// Terminates a scope early (e.g. via return/break/...) void terminate_scope_early(const Span& sp, const ScopeHandle& , bool loop_exit=false); /// Marks the end of a split arm (end match arm, if body, ...) - void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable); + void end_split_arm(const Span& sp, const ScopeHandle& , bool reachable, bool early=false); /// Terminates the current split early (TODO: What does this mean?) void end_split_arm_early(const Span& sp); @@ -275,8 +278,12 @@ 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, unsigned int idx, unsigned int skip_count=0) const; - VarState& get_slot_state_mut(const Span& sp, unsigned int idx); + enum class SlotType { + Local, // Local ~0u is return + Argument + }; + const VarState& get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count=0) const; + VarState& get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type); const VarState& get_val_state(const Span& sp, const ::MIR::LValue& lv, unsigned int skip_count=0); VarState& get_val_state_mut(const Span& sp, const ::MIR::LValue& lv); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index 6e00e2e4..cbb39b34 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -82,8 +82,7 @@ struct ArmCode { ::MIR::BasicBlockId code = 0; bool has_condition = false; ::MIR::BasicBlockId cond_start; - ::MIR::BasicBlockId cond_end; - ::MIR::LValue cond_lval; + ::MIR::BasicBlockId cond_false; ::std::vector< ::MIR::BasicBlockId> destructures; // NOTE: Incomplete mutable ::MIR::BasicBlockId cond_fail_tgt = 0; @@ -355,9 +354,12 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod } builder.terminate_scope( sp, mv$(pat_scope) ); + ac.code = builder.new_bb_unlinked(); + // Condition // NOTE: Lack of drop due to early exit from this arm isn't an issue. All captures must be Copy // - The above is rustc E0008 "cannot bind by-move into a pattern guard" + // TODO: Create a special wrapping scope for the conditions that forces any moves to use a drop flag if(arm.m_cond) { if( H::is_pattern_move(sp, builder, arm.m_patterns[0]) ) @@ -372,9 +374,15 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod auto tmp_scope = builder.new_scope_temp(arm.m_cond->span()); conv.visit_node_ptr( arm.m_cond ); - ac.cond_lval = builder.get_result_in_if_cond(arm.m_cond->span()); + auto cond_lval = builder.get_result_in_if_cond(arm.m_cond->span()); builder.terminate_scope( arm.m_code->span(), mv$(tmp_scope) ); - ac.cond_end = builder.pause_cur_block(); + ac.cond_false = builder.new_bb_unlinked(); + builder.end_block(::MIR::Terminator::make_If({ mv$(cond_lval), ac.code, ac.cond_false })); + // TODO: Emit the `if` (to new blocks) and insert an early termination of the this split arm + + builder.set_cur_block(ac.cond_false); + builder.end_split_arm(arm.m_cond->span(), match_scope, true, true); + builder.pause_cur_block(); // NOTE: Paused so that later code (which knows what the false branch will be) can end it correctly @@ -390,7 +398,6 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod // Code DEBUG("-- Body Code"); - ac.code = builder.new_bb_unlinked(); auto tmp_scope = builder.new_scope_temp(arm.m_code->span()); builder.set_cur_block( ac.code ); conv.visit_node_ptr( arm.m_code ); @@ -1923,8 +1930,8 @@ void MIR_LowerHIR_Match_Simple( MirBuilder& builder, MirConverter& conv, ::HIR:: } if( arm_code.has_condition ) { - builder.set_cur_block( arm_code.cond_end ); - builder.end_block( ::MIR::Terminator::make_If({ mv$(arm_code.cond_lval), arm_code.code, next_arm_bb }) ); + builder.set_cur_block( arm_code.cond_false ); + builder.end_block( ::MIR::Terminator::make_Goto(next_arm_bb) ); } builder.set_cur_block( next_arm_bb ); } @@ -2625,8 +2632,8 @@ void MatchGenGrouped::gen_for_slice(t_rules_subset arm_rules, size_t ofs, ::MIR: { ac.cond_fail_tgt = next; - m_builder.set_cur_block( ac.cond_end ); - m_builder.end_block( ::MIR::Terminator::make_If({ ac.cond_lval.clone(), ac.code, next }) ); + m_builder.set_cur_block( ac.cond_false ); + m_builder.end_block( ::MIR::Terminator::make_Goto(next) ); } } diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 0d5641ff..54269144 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -400,8 +400,11 @@ void MirBuilder::mark_value_assigned(const Span& sp, const ::MIR::LValue& dst) // Don't drop. // No state tracking for the return value ), + (Argument, + state_p = &get_slot_state_mut(sp, e.idx, SlotType::Argument); + ), (Local, - state_p = &get_slot_state_mut(sp, e); + state_p = &get_slot_state_mut(sp, e, SlotType::Local); ) ) @@ -576,7 +579,7 @@ void MirBuilder::raise_temporaries(const Span& sp, const ::MIR::LValue& val, con // TODO: This should update the outer state to unset. auto& arm = sd_split->arms.back(); - arm.states.insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )); + arm.states.insert(::std::make_pair( idx, get_slot_state(sp, idx, SlotType::Local).clone() )); m_slot_states.at(idx) = VarState(InvalidType::Uninit); } else @@ -948,7 +951,8 @@ void MirBuilder::terminate_scope_early(const Span& sp, const ScopeHandle& scope, // Ensure that all arguments are dropped if they were not moved for(size_t i = 0; i < m_arg_states.size(); i ++) { - this->drop_value_from_state(sp, m_arg_states[i], ::MIR::LValue::make_Argument({ static_cast(i) })); + const auto& state = get_slot_state(sp, i, SlotType::Argument); + this->drop_value_from_state(sp, state, ::MIR::LValue::make_Argument({ static_cast(i) })); } } } @@ -983,6 +987,9 @@ namespace old_state = VarState::make_Optional( new_flag ); #else // TODO: Rewrite history. I.e. visit all previous branches and set this drop flag to `false` in all of them + for(auto pos : other_arms) { + builder.push_df_set_at(pos, flag_idx, false); + } TODO(sp, "Drop flag default not false when going Invalid->Optional"); #endif } @@ -1007,6 +1014,10 @@ namespace builder.push_stmt_set_dropflag_other(sp, new_flag, nse.outer_flag); builder.push_stmt_set_dropflag_default(sp, nse.outer_flag); ose.outer_flag = new_flag; +#if 0 + for(auto pos : other_arms) { + } +#endif } } else @@ -1354,30 +1365,39 @@ 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_slots) - { - auto idx = ent.first; - if( sd_loop.exit_state.states.count(idx) == 0 ) { - sd_loop.exit_state.states.insert(::std::make_pair( idx, ent.second.clone() )); + auto merge_list = [sp,this](const auto& changed, auto& exit_states, ::std::function<::MIR::LValue(unsigned)> val_cb, auto type) { + for(const auto& ent : changed) + { + auto idx = ent.first; + auto it = exit_states.find(idx); + if( it == exit_states.end() ) { + it = exit_states.insert(::std::make_pair( idx, ent.second.clone() )).first; + } + auto& old_state = it->second; + merge_state(sp, *this, val_cb(idx), old_state, get_slot_state(sp, idx, type)); } - 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)); - } + }; + merge_list(sd_loop.changed_slots, sd_loop.exit_state.states, ::MIR::LValue::make_Local, SlotType::Local); + merge_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, [](auto v){ return ::MIR::LValue::make_Argument({v}); }, SlotType::Argument); } else { + auto init_list = [sp,this](const auto& changed, auto& exit_states, auto type) { + for(const auto& ent : changed) + { + DEBUG("Slot(" << ent.first << ") = " << ent.second); + auto idx = ent.first; + exit_states.insert(::std::make_pair( idx, get_slot_state(sp, idx, type).clone() )); + } + }; // Obtain states of changed variables/temporaries - for(const auto& ent : sd_loop.changed_slots) - { - DEBUG("Slot(" << ent.first << ") = " << ent.second); - auto idx = ent.first; - sd_loop.exit_state.states.insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )); - } + init_list(sd_loop.changed_slots, sd_loop.exit_state.states, SlotType::Local); + init_list(sd_loop.changed_args, sd_loop.exit_state.arg_states, SlotType::Argument); sd_loop.exit_state_valid = true; } } -void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable) +void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool reachable, bool early/*=false*/) { ASSERT_BUG(sp, handle.idx < m_scopes.size(), "Handle passed to end_split_arm is invalid"); auto& sd = m_scopes.at( handle.idx ); @@ -1396,25 +1416,29 @@ 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.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() )); + auto merge_list = [sp,this](const auto& states, auto& end_states, auto type) { + // Insert copies of the parent state + for(const auto& ent : states) { + if( end_states.count(ent.first) == 0 ) { + end_states.insert(::std::make_pair( ent.first, get_slot_state(sp, ent.first, type, 1).clone() )); + } } - } - - // Merge state - for(auto& ent : sd_split.end_state.states) - { - auto idx = ent.first; - auto& out_state = ent.second; + // Merge state + for(auto& ent : end_states) + { + auto idx = ent.first; + auto& out_state = ent.second; - // Merge the states - 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 the states + auto it = states.find(idx); + const auto& src_state = (it != states.end() ? it->second : get_slot_state(sp, idx, type, 1)); - merge_state(sp, *this, ::MIR::LValue::make_Local(idx), out_state, src_state); - } + auto lv = (type == SlotType::Local ? ::MIR::LValue::make_Local(idx) : ::MIR::LValue::make_Argument({idx})); + merge_state(sp, *this, mv$(lv), out_state, src_state); + } + }; + merge_list(this_arm_state.states, sd_split.end_state.states, SlotType::Local); + merge_list(this_arm_state.arg_states, sd_split.end_state.arg_states, SlotType::Argument); } else { @@ -1429,17 +1453,29 @@ void MirBuilder::end_split_arm(const Span& sp, const ScopeHandle& handle, bool r DEBUG("Slot(" << ent.first << ") = " << ent.second); sd_split.end_state.states.insert(::std::make_pair( ent.first, ent.second.clone() )); } + for(auto& ent : this_arm_state.arg_states) + { + DEBUG("Argument(" << ent.first << ") = " << ent.second); + sd_split.end_state.arg_states.insert(::std::make_pair( ent.first, ent.second.clone() )); + } sd_split.end_state_valid = true; } - sd_split.arms.push_back( {} ); + if( reachable ) + { + assert(m_block_active); + } + if( !early ) + { + sd_split.arms.push_back( {} ); + } } void MirBuilder::end_split_arm_early(const Span& sp) { TRACE_FUNCTION_F(""); size_t i = m_scope_stack.size(); - // Terminate all scopes until a split is found. - while( i -- && ! (m_scopes.at(m_scope_stack[i]).data.is_Split() || m_scopes.at(m_scope_stack[i]).data.is_Loop()) ) + // Terminate every sequence of owning scopes + while( i -- && m_scopes.at(m_scope_stack[i]).data.is_Owning() ) { auto& scope_def = m_scopes[m_scope_stack[i]]; // Fully drop the scope @@ -1459,6 +1495,7 @@ void MirBuilder::end_split_arm_early(const Span& sp) // TODO: Create drop flags if required? } + // TODO: What if this is a loop? } } void MirBuilder::complete_scope(ScopeDef& sd) @@ -1481,13 +1518,22 @@ void MirBuilder::complete_scope(ScopeDef& sd) { for(auto& ent : end_state.states) { - auto& vs = builder.get_slot_state_mut(sp, ent.first); + auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Local); if( vs != ent.second ) { DEBUG(::MIR::LValue::make_Local(ent.first) << " " << vs << " => " << ent.second); vs = ::std::move(ent.second); } } + for(auto& ent : end_state.arg_states) + { + auto& vs = builder.get_slot_state_mut(sp, ent.first, SlotType::Argument); + if( vs != ent.second ) + { + DEBUG(::MIR::LValue::make_Argument({ent.first}) << " " << vs << " => " << ent.second); + vs = ::std::move(ent.second); + } + } } }; @@ -1735,7 +1781,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, unsigned int idx, unsigned int skip_count/*=0*/) const +const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, SlotType type, unsigned int skip_count/*=0*/) const { // 1. Find an applicable Split scope for( auto scope_idx : ::reverse(m_scope_stack) ) @@ -1745,15 +1791,19 @@ const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, uns ( ), (Owning, - auto it = ::std::find(e.slots.begin(), e.slots.end(), idx); - if( it != e.slots.end() ) { - break ; + if( type == SlotType::Local ) + { + 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(); - auto it = cur_arm.states.find(idx); - if( it != cur_arm.states.end() ) + const auto& list = (type == SlotType::Local ? cur_arm.states : cur_arm.arg_states); + auto it = list.find(idx); + if( it != list.end() ) { if( ! skip_count -- ) { @@ -1763,17 +1813,26 @@ const VarState& MirBuilder::get_slot_state(const Span& sp, unsigned int idx, uns ) ) } - if( idx == ~0u ) - { - return m_return_state; - } - else + switch(type) { - ASSERT_BUG(sp, idx < m_slot_states.size(), "Slot " << idx << " out of range for state table"); - return m_slot_states.at(idx); + case SlotType::Local: + if( idx == ~0u ) + { + return m_return_state; + } + else + { + ASSERT_BUG(sp, idx < m_slot_states.size(), "Slot " << idx << " out of range for state table"); + return m_slot_states.at(idx); + } + break; + case SlotType::Argument: + ASSERT_BUG(sp, idx < m_arg_states.size(), "Argument " << idx << " out of range for state table"); + return m_arg_states.at(idx); } + throw ""; } -VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) +VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotType type) { VarState* ret = nullptr; for( auto scope_idx : ::reverse(m_scope_stack) ) @@ -1781,26 +1840,28 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) auto& scope_def = m_scopes.at(scope_idx); if( const auto* e = scope_def.data.opt_Owning() ) { - auto it = ::std::find(e->slots.begin(), e->slots.end(), idx); - if( it != e->slots.end() ) { - break ; + if( type == SlotType::Local ) + { + auto it = ::std::find(e->slots.begin(), e->slots.end(), idx); + if( it != e->slots.end() ) { + break ; + } } } - else if( scope_def.data.is_Split() ) + else if( auto* e = scope_def.data.opt_Split() ) { - auto& e = scope_def.data.as_Split(); - auto& cur_arm = e.arms.back(); + auto& cur_arm = e->arms.back(); if( ! ret ) { if( idx == ~0u ) { } else { - auto* states = &cur_arm.states; - auto it = states->find(idx); - if( it == states->end() ) + auto& states = (type == SlotType::Local ? cur_arm.states : cur_arm.arg_states); + auto it = states.find(idx); + if( it == states.end() ) { DEBUG("Split new (scope " << scope_idx << ")"); - it = states->insert(::std::make_pair( idx, get_slot_state(sp, idx).clone() )).first; + it = states.insert(::std::make_pair( idx, get_slot_state(sp, idx, type).clone() )).first; } else { @@ -1810,20 +1871,18 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) } } } - else if( scope_def.data.is_Loop() ) + else if( auto* e = scope_def.data.opt_Loop() ) { - auto& e = scope_def.data.as_Loop(); - ::std::map* states = nullptr; if( idx == ~0u ) { } else { - states = &e.changed_slots; - if( states->count(idx) == 0 ) + auto& states = (type == SlotType::Local ? e->changed_slots : e->changed_args); + if( states.count(idx) == 0 ) { - auto state = e.exit_state_valid ? get_slot_state(sp, idx).clone() : VarState::make_Valid({}); - states->insert(::std::make_pair( idx, mv$(state) )); + auto state = e->exit_state_valid ? get_slot_state(sp, idx, type).clone() : VarState::make_Valid({}); + states.insert(::std::make_pair( idx, mv$(state) )); } } } @@ -1837,14 +1896,21 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx) } else { - if( idx == ~0u ) + switch(type) { - return m_return_state; - } - else - { - return m_slot_states.at(idx); + case SlotType::Local: + if( idx == ~0u ) + { + return m_return_state; + } + else + { + return m_slot_states.at(idx); + } + case SlotType::Argument: + return m_arg_states.at(idx); } + throw ""; } } @@ -1858,14 +1924,13 @@ VarState& MirBuilder::get_val_state_mut(const Span& sp, const ::MIR::LValue& lv) TU_MATCHA( (lv), (e), (Return, BUG(sp, "Move of return value"); - return get_slot_state_mut(sp, ~0u); + return get_slot_state_mut(sp, ~0u, SlotType::Local); ), (Argument, - // NOTE: Only valid outside of split scopes (should only happen at the start) - return m_arg_states.at(e.idx); + return get_slot_state_mut(sp, e.idx, SlotType::Argument); ), (Local, - return get_slot_state_mut(sp, e); + return get_slot_state_mut(sp, e, SlotType::Local); ), (Static, BUG(sp, "Attempting to mutate state of a static"); @@ -2084,7 +2149,7 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd) (Owning, for(auto idx : ::reverse(e.slots)) { - const auto& vs = get_slot_state(sd.span, idx); + const auto& vs = get_slot_state(sd.span, idx, SlotType::Local); DEBUG("slot" << idx << " - " << vs); drop_value_from_state( sd.span, vs, ::MIR::LValue::make_Local(idx) ); } -- cgit v1.2.3 From 57d622ef83220774ce21a18881efd7461ed5e73a Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jul 2017 16:59:15 +0800 Subject: MIR Optimise - Store params and Copy args early --- src/mir/helpers.cpp | 24 +++++++++++++++++++++++- src/mir/optimise.cpp | 38 +++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index 7b2fabd5..f2c0e39e 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -288,7 +288,29 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c } ), (ItemAddr, - MIR_TODO(*this, "get_const_type - Get type for constant `" << c << "`"); + MonomorphState p; + auto v = m_resolve.get_value(this->sp, e, p, /*signature_only=*/true); + TU_MATCHA( (v), (ve), + (NotFound, + MIR_BUG(*this, "get_const_type - ItemAddr points to unknown value - " << c); + ), + (Constant, + MIR_TODO(*this, "get_const_type - Get type for constant borrow `" << c << "`"); + ), + (Static, + MIR_TODO(*this, "get_const_type - Get type for static borrow `" << c << "`"); + ), + (Function, + ::HIR::FunctionType ft; + ft.is_unsafe = ve->m_unsafe; + ft.m_abi = ve->m_abi; + ft.m_rettype = box$( p.monomorph(this->sp, ve->m_return) ); + ft.m_arg_types.reserve(ve->m_args.size()); + for(const auto& arg : ve->m_args) + ft.m_arg_types.push_back( p.monomorph(this->sp, arg.second) ); + return ::HIR::TypeRef( mv$(ft) ); + ) + ) ) ) throw ""; diff --git a/src/mir/optimise.cpp b/src/mir/optimise.cpp index cc06ab0c..3ef629b1 100644 --- a/src/mir/optimise.cpp +++ b/src/mir/optimise.cpp @@ -21,6 +21,7 @@ #define DUMP_BEFORE_CONSTPROPAGATE 0 #define CHECK_AFTER_PASS 1 #define CHECK_AFTER_ALL 1 +#define DUMP_AFTER_PASS 1 #define DUMP_AFTER_DONE 0 #define CHECK_AFTER_DONE 1 @@ -1026,18 +1027,13 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool ), (Argument, const auto& arg = this->te.args.at(se.idx); - 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; - } - else if( this->copy_args[se.idx] != ~0u ) + if( this->copy_args[se.idx] != ~0u ) { return ::MIR::LValue::make_Local(this->copy_args[se.idx]); } else { + assert( !arg.is_Constant() ); // Should have been handled in the above return arg.as_LValue().clone(); } ), @@ -1088,8 +1084,8 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool TU_MATCHA( (src), (se), (LValue, // NOTE: No need to use `copy_args` here as all uses of Param are copies/moves - if( const auto* ae = se.opt_Argument() ) - return this->te.args.at(ae->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); ) @@ -1100,9 +1096,9 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool { TU_MATCHA( (src), (se), (Use, - if( const auto* ae = se.opt_Argument() ) - if( const auto* e = this->te.args.at(ae->idx).opt_Constant() ) - return e->clone(); + //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) ); ), (Constant, @@ -1196,17 +1192,15 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool fcn.drop_flags.insert( fcn.drop_flags.end(), called_mir->drop_flags.begin(), called_mir->drop_flags.end() ); cloner.bb_base = fcn.blocks.size(); - // Take a copy of all Copy arguments (!Copy doesn't matter, as they're unusable after the call) + // Store all Copy lvalue arguments and Constants in variables for(size_t i = 0; i < te->args.size(); i++) { - if(const auto* e = te->args[i].opt_LValue()) + const auto& a = te->args[i]; + if( !a.is_LValue() || state.lvalue_is_copy(a.as_LValue()) ) { - if( state.lvalue_is_copy(*e) ) - { - cloner.copy_args[i] = cloner.tmp_end + cloner.const_assignments.size(); - cloner.const_assignments.push_back( e->clone() ); - DEBUG("- Taking a copy of arg " << i << " (" << *e << ") in Local(" << cloner.copy_args[i] << ")"); - } + cloner.copy_args[i] = cloner.tmp_end + cloner.const_assignments.size(); + cloner.const_assignments.push_back( a.clone() ); + DEBUG("- Taking a copy of arg " << i << " (" << a << ") in Local(" << cloner.copy_args[i] << ")"); } } @@ -1227,7 +1221,9 @@ bool MIR_Optimise_Inlining(::MIR::TypeResolve& state, ::MIR::Function& fcn, bool auto lv = ::MIR::LValue::make_Local( static_cast(fcn.locals.size()) ); fcn.locals.push_back( mv$(ty) ); auto rval = val.is_Constant() ? ::MIR::RValue(mv$(val.as_Constant())) : ::MIR::RValue( mv$(val.as_LValue()) ); - new_blocks[0].statements.insert( new_blocks[0].statements.begin(), ::MIR::Statement::make_Assign({ mv$(lv), mv$(rval) }) ); + auto stmt = ::MIR::Statement::make_Assign({ mv$(lv), mv$(rval) }); + DEBUG("++ " << stmt); + new_blocks[0].statements.insert( new_blocks[0].statements.begin(), mv$(stmt) ); } cloner.const_assignments.clear(); -- cgit v1.2.3 From 656ae04aa0fd50a6f818d021da94a5915d13751c Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jul 2017 17:20:42 +0800 Subject: main - Use skewer case, not snake --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/main.cpp b/src/main.cpp index ce5a3f48..c442fd94 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -615,7 +615,7 @@ ProgramParams::ProgramParams(int argc, char *argv[]) optname = arg+1; } - if( optname == "disable_mir_opt" ) { + if( optname == "disable-mir-opt" ) { this->debug.disable_mir_optimisations = true; } else if( optname == "full-validate" ) { -- 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') 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 b7bb1f4f9c918e128f7ad83476790830c3f98c4d Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 2 Jul 2017 18:34:34 +0800 Subject: MIR Gen - Make mutating state (other than the if condition) within a match guard an error --- src/mir/from_hir.hpp | 6 ++++++ src/mir/from_hir_match.cpp | 3 ++- src/mir/mir_builder.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index 11a18a6d..b11a380a 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -103,6 +103,11 @@ TAGGED_UNION(ScopeType, Owning, ::std::map changed_args; bool exit_state_valid; SplitEnd exit_state; + }), + // State which should end up with no mutation of variable states + (Freeze, struct { + //::std::map changed_slots; + //::std::map changed_args; }) ); @@ -257,6 +262,7 @@ public: ScopeHandle new_scope_temp(const Span& sp); ScopeHandle new_scope_split(const Span& sp); ScopeHandle new_scope_loop(const Span& sp); + ScopeHandle new_scope_freeze(const Span& sp); /// Raises every variable defined in the source scope into the target scope void raise_all(const Span& sp, ScopeHandle src, const ScopeHandle& target); diff --git a/src/mir/from_hir_match.cpp b/src/mir/from_hir_match.cpp index cbb39b34..c10f170b 100644 --- a/src/mir/from_hir_match.cpp +++ b/src/mir/from_hir_match.cpp @@ -372,17 +372,18 @@ void MIR_LowerHIR_Match( MirBuilder& builder, MirConverter& conv, ::HIR::ExprNod ac.cond_start = builder.new_bb_unlinked(); builder.set_cur_block( ac.cond_start ); + auto freeze_scope = builder.new_scope_freeze(arm.m_cond->span()); auto tmp_scope = builder.new_scope_temp(arm.m_cond->span()); conv.visit_node_ptr( arm.m_cond ); auto cond_lval = builder.get_result_in_if_cond(arm.m_cond->span()); builder.terminate_scope( arm.m_code->span(), mv$(tmp_scope) ); ac.cond_false = builder.new_bb_unlinked(); builder.end_block(::MIR::Terminator::make_If({ mv$(cond_lval), ac.code, ac.cond_false })); - // TODO: Emit the `if` (to new blocks) and insert an early termination of the this split arm builder.set_cur_block(ac.cond_false); builder.end_split_arm(arm.m_cond->span(), match_scope, true, true); builder.pause_cur_block(); + builder.terminate_scope( arm.m_code->span(), mv$(freeze_scope) ); // NOTE: Paused so that later code (which knows what the false branch will be) can end it correctly diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 54269144..5dcb2ed2 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -745,6 +745,14 @@ ScopeHandle MirBuilder::new_scope_loop(const Span& sp) DEBUG("START (loop) scope " << idx); return ScopeHandle { *this, idx }; } +ScopeHandle MirBuilder::new_scope_freeze(const Span& sp) +{ + unsigned int idx = m_scopes.size(); + m_scopes.push_back( ScopeDef {sp, ScopeType::make_Freeze({})} ); + m_scope_stack.push_back( idx ); + DEBUG("START (freeze) scope " << idx); + return ScopeHandle { *this, idx }; +} void MirBuilder::terminate_scope(const Span& sp, ScopeHandle scope, bool emit_cleanup/*=true*/) { TRACE_FUNCTION_F("DONE scope " << scope.idx << " - " << (emit_cleanup ? "CLEANUP" : "NO CLEANUP")); @@ -1510,6 +1518,9 @@ void MirBuilder::complete_scope(ScopeDef& sd) DEBUG("Loop"); ), (Split, + ), + (Freeze, + //DEBUG("Freeze"); ) ) @@ -1886,6 +1897,18 @@ VarState& MirBuilder::get_slot_state_mut(const Span& sp, unsigned int idx, SlotT } } } + else if( scope_def.data.is_Freeze() ) + { + if( type == SlotType::Local && idx == m_if_cond_lval.as_Local() ) + { + } + else + { + // NOTE: This is only used in match conditions + DEBUG("Mutating state of ?" << idx); + ERROR(sp, E0000, "Attempting to move/initialise a value where not allowed"); + } + } else { } @@ -2159,6 +2182,8 @@ void MirBuilder::drop_scope_values(const ScopeDef& sd) ), (Loop, // No values + ), + (Freeze, ) ) } -- 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') 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 e16ccbcb9c836cb92699bfd387504ec2694a4141 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 6 Jul 2017 12:25:37 +0800 Subject: MIR Gen - Reset drop flags on entry to a loop (instead of after use) --- src/mir/from_hir.cpp | 8 +++++++- src/mir/from_hir.hpp | 3 +++ src/mir/mir_builder.cpp | 36 ++++++++++++++++++++---------------- 3 files changed, 30 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/mir/from_hir.cpp b/src/mir/from_hir.cpp index bc9b04a7..786c2243 100644 --- a/src/mir/from_hir.cpp +++ b/src/mir/from_hir.cpp @@ -548,8 +548,8 @@ namespace { void visit(::HIR::ExprNode_Loop& node) override { TRACE_FUNCTION_FR("_Loop", "_Loop"); - auto loop_body_scope = m_builder.new_scope_loop(node.span()); auto loop_block = m_builder.new_bb_linked(); + auto loop_body_scope = m_builder.new_scope_loop(node.span()); auto loop_next = m_builder.new_bb_unlinked(); auto loop_tmp_scope = m_builder.new_scope_temp(node.span()); @@ -2269,8 +2269,14 @@ namespace { root_node.visit( ev ); } + // NOTE: Can't clean up yet, as consteval isn't done + //MIR_Cleanup(resolve, path, fcn, args, ptr->m_res_type); MIR_Validate(resolve, path, fcn, args, ptr->m_res_type); + if( getenv("MRUSTC_VALIDATE_FULL_EARLY") ) { + MIR_Validate_Full(resolve, path, fcn, args, ptr->m_res_type); + } + return ::MIR::FunctionPointer(new ::MIR::Function(mv$(fcn))); } diff --git a/src/mir/from_hir.hpp b/src/mir/from_hir.hpp index b11a380a..c4be91a2 100644 --- a/src/mir/from_hir.hpp +++ b/src/mir/from_hir.hpp @@ -103,6 +103,9 @@ TAGGED_UNION(ScopeType, Owning, ::std::map changed_args; bool exit_state_valid; SplitEnd exit_state; + // TODO: Any drop flags allocated in the loop must be re-initialised at the start of the loop (or before a loopback) + ::MIR::BasicBlockId entry_bb; + ::std::vector drop_flags; }), // State which should end up with no mutation of variable states (Freeze, struct { diff --git a/src/mir/mir_builder.cpp b/src/mir/mir_builder.cpp index 5dcb2ed2..97942ba2 100644 --- a/src/mir/mir_builder.cpp +++ b/src/mir/mir_builder.cpp @@ -338,12 +338,6 @@ void MirBuilder::push_stmt_drop(const Span& sp, ::MIR::LValue val, unsigned int } this->push_stmt(sp, ::MIR::Statement::make_Drop({ ::MIR::eDropKind::DEEP, mv$(val), flag })); - - if( flag != ~0u ) - { - // Reset flag value back to default. - push_stmt_set_dropflag_val(sp, flag, m_output.drop_flags.at(flag)); - } } void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsigned int flag/*=~0u*/) { @@ -353,12 +347,6 @@ void MirBuilder::push_stmt_drop_shallow(const Span& sp, ::MIR::LValue val, unsig // TODO: Ensure that the type is a Box? this->push_stmt(sp, ::MIR::Statement::make_Drop({ ::MIR::eDropKind::SHALLOW, mv$(val), flag })); - - if( flag != ~0u ) - { - // Reset flag value back to default. - push_stmt_set_dropflag_val(sp, flag, m_output.drop_flags.at(flag)); - } } void MirBuilder::push_stmt_asm(const Span& sp, ::MIR::Statement::Data_Asm data) { @@ -697,6 +685,14 @@ unsigned int MirBuilder::new_drop_flag(bool default_state) { auto rv = m_output.drop_flags.size(); m_output.drop_flags.push_back(default_state); + for(size_t i = m_scope_stack.size(); i --;) + { + if( auto* e = m_scopes.at(m_scope_stack[i]).data.opt_Loop() ) + { + e->drop_flags.push_back(rv); + break; + } + } DEBUG("(" << default_state << ") = " << rv); return rv; } @@ -741,6 +737,7 @@ ScopeHandle MirBuilder::new_scope_loop(const Span& sp) { unsigned int idx = m_scopes.size(); m_scopes.push_back( ScopeDef {sp, ScopeType::make_Loop({})} ); + m_scopes.back().data.as_Loop().entry_bb = m_current_block; m_scope_stack.push_back( idx ); DEBUG("START (loop) scope " << idx); return ScopeHandle { *this, idx }; @@ -1549,13 +1546,20 @@ void MirBuilder::complete_scope(ScopeDef& sd) }; // No macro for better debug output. - if( sd.data.is_Loop() ) + if( auto* e = sd.data.opt_Loop() ) { - auto& e = sd.data.as_Loop(); TRACE_FUNCTION_F("Loop"); - if( e.exit_state_valid ) + if( e->exit_state_valid ) + { + H::apply_end_state(sd.span, *this, e->exit_state); + } + + // Insert sets of drop flags to the first block (at the start of that block) + auto& stmts = m_output.blocks.at(e->entry_bb).statements; + for(auto idx : e->drop_flags) { - H::apply_end_state(sd.span, *this, e.exit_state); + DEBUG("Reset df$" << idx); + stmts.insert( stmts.begin(), ::MIR::Statement::make_SetDropFlag({ idx, m_output.drop_flags.at(idx), ~0u }) ); } } else if( sd.data.is_Split() ) -- cgit v1.2.3 From 7cf78affadac44ea1918d0f576e6f337e8ffc653 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Thu, 6 Jul 2017 12:27:37 +0800 Subject: MIR Helpers - Expand associated types in monomorpised function types --- src/mir/helpers.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/mir/helpers.cpp b/src/mir/helpers.cpp index f2c0e39e..ea5709d1 100644 --- a/src/mir/helpers.cpp +++ b/src/mir/helpers.cpp @@ -308,7 +308,9 @@ const ::HIR::TypeRef& ::MIR::TypeResolve::get_lvalue_type(::HIR::TypeRef& tmp, c ft.m_arg_types.reserve(ve->m_args.size()); for(const auto& arg : ve->m_args) ft.m_arg_types.push_back( p.monomorph(this->sp, arg.second) ); - return ::HIR::TypeRef( mv$(ft) ); + auto rv = ::HIR::TypeRef( mv$(ft) ); + m_resolve.expand_associated_types(this->sp, rv); + return rv; ) ) ) -- 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') 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