diff options
Diffstat (limited to 'gcc/rust/backend/rust-compile-base.cc')
-rw-r--r-- | gcc/rust/backend/rust-compile-base.cc | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/gcc/rust/backend/rust-compile-base.cc b/gcc/rust/backend/rust-compile-base.cc index 81598c4..85d85b9 100644 --- a/gcc/rust/backend/rust-compile-base.cc +++ b/gcc/rust/backend/rust-compile-base.cc @@ -17,6 +17,11 @@ // <http://www.gnu.org/licenses/>. #include "rust-compile-base.h" +#include "rust-compile-item.h" +#include "rust-compile-stmt.h" +#include "rust-compile-fnparam.h" +#include "rust-compile-var-decl.h" + #include "fold-const.h" #include "stringpool.h" @@ -169,5 +174,280 @@ HIRCompileBase::address_expression (tree expr, Location location) return build_fold_addr_expr_loc (location.gcc_location (), expr); } +std::vector<Bvariable *> +HIRCompileBase::compile_locals_for_block (Context *ctx, Resolver::Rib &rib, + tree fndecl) +{ + std::vector<Bvariable *> locals; + rib.iterate_decls ([&] (NodeId n, Location) mutable -> bool { + Resolver::Definition d; + bool ok = ctx->get_resolver ()->lookup_definition (n, &d); + rust_assert (ok); + + HIR::Stmt *decl = nullptr; + ok = ctx->get_mappings ()->resolve_nodeid_to_stmt (d.parent, &decl); + rust_assert (ok); + + // if its a function we extract this out side of this fn context + // and it is not a local to this function + bool is_item = ctx->get_mappings ()->lookup_hir_item ( + decl->get_mappings ().get_crate_num (), + decl->get_mappings ().get_hirid ()) + != nullptr; + if (is_item) + { + HIR::Item *item = static_cast<HIR::Item *> (decl); + CompileItem::compile (item, ctx); + return true; + } + + Bvariable *compiled = CompileVarDecl::compile (fndecl, decl, ctx); + locals.push_back (compiled); + + return true; + }); + + return locals; +} + +void +HIRCompileBase::compile_function_body (Context *ctx, tree fndecl, + HIR::BlockExpr &function_body, + bool has_return_type) +{ + for (auto &s : function_body.get_statements ()) + { + auto compiled_expr = CompileStmt::Compile (s.get (), ctx); + if (compiled_expr != nullptr) + { + tree compiled_stmt + = ctx->get_backend ()->expression_statement (fndecl, compiled_expr); + ctx->add_statement (compiled_stmt); + } + } + + if (function_body.has_expr ()) + { + // the previous passes will ensure this is a valid return + // or a valid trailing expression + tree compiled_expr + = CompileExpr::Compile (function_body.expr.get (), ctx); + + if (compiled_expr != nullptr) + { + if (has_return_type) + { + std::vector<tree> retstmts; + retstmts.push_back (compiled_expr); + + auto ret = ctx->get_backend ()->return_statement ( + fndecl, retstmts, + function_body.get_final_expr ()->get_locus ()); + ctx->add_statement (ret); + } + else + { + tree final_stmt + = ctx->get_backend ()->expression_statement (fndecl, + compiled_expr); + ctx->add_statement (final_stmt); + } + } + } +} + +tree +HIRCompileBase::compile_function ( + Context *ctx, const std::string &fn_name, HIR::SelfParam &self_param, + std::vector<HIR::FunctionParam> &function_params, + const HIR::FunctionQualifiers &qualifiers, HIR::Visibility &visibility, + AST::AttrVec &outer_attrs, Location locus, HIR::BlockExpr *function_body, + const Resolver::CanonicalPath *canonical_path, TyTy::FnType *fntype, + bool function_has_return) +{ + tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype); + std::string ir_symbol_name + = canonical_path->get () + fntype->subst_as_string (); + + // we don't mangle the main fn since we haven't implemented the main shim + bool is_main_fn = fn_name.compare ("main") == 0; + std::string asm_name = fn_name; + if (!is_main_fn) + asm_name = ctx->mangle_item (fntype, *canonical_path); + + unsigned int flags = 0; + tree fndecl = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, + asm_name, flags, locus); + setup_attributes_on_fndecl (fndecl, is_main_fn, !visibility.is_error (), + qualifiers, outer_attrs); + setup_abi_options (fndecl, fntype->get_abi ()); + + // insert into the context + ctx->insert_function_decl (fntype, fndecl); + + // setup the params + TyTy::BaseType *tyret = fntype->get_return_type (); + std::vector<Bvariable *> param_vars; + if (!self_param.is_error ()) + { + rust_assert (fntype->is_method ()); + TyTy::BaseType *self_tyty_lookup = fntype->get_self_type (); + + tree self_type = TyTyResolveCompile::compile (ctx, self_tyty_lookup); + Bvariable *compiled_self_param + = CompileSelfParam::compile (ctx, fndecl, self_param, self_type, + self_param.get_locus ()); + + param_vars.push_back (compiled_self_param); + ctx->insert_var_decl (self_param.get_mappings ().get_hirid (), + compiled_self_param); + } + + // offset from + 1 for the TyTy::FnType being used when this is a method to + // skip over Self on the FnType + bool is_method = !self_param.is_error (); + size_t i = is_method ? 1 : 0; + for (auto &referenced_param : function_params) + { + auto tyty_param = fntype->param_at (i++); + auto param_tyty = tyty_param.second; + auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty); + + Location param_locus = referenced_param.get_locus (); + Bvariable *compiled_param_var + = CompileFnParam::compile (ctx, fndecl, &referenced_param, + compiled_param_type, param_locus); + + param_vars.push_back (compiled_param_var); + ctx->insert_var_decl (referenced_param.get_mappings ().get_hirid (), + compiled_param_var); + } + + if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars)) + return error_mark_node; + + // lookup locals + auto body_mappings = function_body->get_mappings (); + Resolver::Rib *rib = nullptr; + bool ok + = ctx->get_resolver ()->find_name_rib (body_mappings.get_nodeid (), &rib); + rust_assert (ok); + + std::vector<Bvariable *> locals + = compile_locals_for_block (ctx, *rib, fndecl); + + tree enclosing_scope = NULL_TREE; + Location start_location = function_body->get_locus (); + Location end_location = function_body->get_end_locus (); + + tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, locals, + start_location, end_location); + ctx->push_block (code_block); + + Bvariable *return_address = nullptr; + if (function_has_return) + { + tree return_type = TyTyResolveCompile::compile (ctx, tyret); + + bool address_is_taken = false; + tree ret_var_stmt = NULL_TREE; + + return_address + = ctx->get_backend ()->temporary_variable (fndecl, code_block, + return_type, NULL, + address_is_taken, locus, + &ret_var_stmt); + + ctx->add_statement (ret_var_stmt); + } + + ctx->push_fn (fndecl, return_address); + compile_function_body (ctx, fndecl, *function_body, function_has_return); + tree bind_tree = ctx->pop_block (); + + gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR); + DECL_SAVED_TREE (fndecl) = bind_tree; + + ctx->pop_fn (); + ctx->push_function (fndecl); + + return fndecl; +} + +tree +HIRCompileBase::compile_constant_item ( + Context *ctx, TyTy::BaseType *resolved_type, + const Resolver::CanonicalPath *canonical_path, HIR::Expr *const_value_expr, + Location locus) +{ + const std::string &ident = canonical_path->get (); + tree type = TyTyResolveCompile::compile (ctx, resolved_type); + tree const_type = build_qualified_type (type, TYPE_QUAL_CONST); + + bool is_block_expr + = const_value_expr->get_expression_type () == HIR::Expr::ExprType::Block; + + // compile the expression + tree folded_expr = error_mark_node; + if (!is_block_expr) + { + tree value = CompileExpr::Compile (const_value_expr, ctx); + folded_expr = ConstCtx::fold (value); + } + else + { + // in order to compile a block expr we want to reuse as much existing + // machineary that we already have. This means the best approach is to + // make a _fake_ function with a block so it can hold onto temps then + // use our constexpr code to fold it completely or error_mark_node + Backend::typed_identifier receiver; + tree compiled_fn_type = ctx->get_backend ()->function_type ( + receiver, {}, {Backend::typed_identifier ("_", const_type, locus)}, + NULL, locus); + + tree fndecl + = ctx->get_backend ()->function (compiled_fn_type, ident, "", 0, locus); + TREE_READONLY (fndecl) = 1; + + tree enclosing_scope = NULL_TREE; + HIR::BlockExpr *function_body + = static_cast<HIR::BlockExpr *> (const_value_expr); + Location start_location = function_body->get_locus (); + Location end_location = function_body->get_end_locus (); + + tree code_block + = ctx->get_backend ()->block (fndecl, enclosing_scope, {}, + start_location, end_location); + ctx->push_block (code_block); + + bool address_is_taken = false; + tree ret_var_stmt = NULL_TREE; + Bvariable *return_address + = ctx->get_backend ()->temporary_variable (fndecl, code_block, + const_type, NULL, + address_is_taken, locus, + &ret_var_stmt); + + ctx->add_statement (ret_var_stmt); + ctx->push_fn (fndecl, return_address); + + compile_function_body (ctx, fndecl, *function_body, true); + tree bind_tree = ctx->pop_block (); + + gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR); + DECL_SAVED_TREE (fndecl) = bind_tree; + + ctx->pop_fn (); + + // lets fold it into a call expr + tree call = build_call_array_loc (locus.gcc_location (), const_type, + fndecl, 0, NULL); + folded_expr = ConstCtx::fold (call); + } + + return ctx->get_backend ()->named_constant_expression (const_type, ident, + folded_expr, locus); +} + } // namespace Compile } // namespace Rust |