aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile-base.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/backend/rust-compile-base.cc')
-rw-r--r--gcc/rust/backend/rust-compile-base.cc280
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