diff options
author | Philip Herron <philip.herron@embecosm.com> | 2022-01-13 21:04:57 +0000 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2022-01-14 12:32:49 +0000 |
commit | 93554f3bce5bd42d8671559a774818767979cdae (patch) | |
tree | 03b1cac2b3442af423cd565b0168682e6d4541b3 /gcc/rust/backend/rust-compile-item.h | |
parent | e9ffd4308d70da55b4c698b07b484063bcda0b01 (diff) | |
download | gcc-93554f3bce5bd42d8671559a774818767979cdae.zip gcc-93554f3bce5bd42d8671559a774818767979cdae.tar.gz gcc-93554f3bce5bd42d8671559a774818767979cdae.tar.bz2 |
Add initial constant evaluation to blocks
BlockExpressions are usually evaluated by create a temporary variable to
hold the result of the tail expression in the correctly. Const expressions
do not have a context of a block so we must fold the value to store it
correctly without the need for temporary variables or a stack. To do this
we can leverage the fact that our constexpr code can fold simple CallExpr's
so in this patch we actually generate an implicit artifical function for
the block but do not add it to the translation unit and we then generate
an artifical CallExpr and pass it to the constant folder system, and then
assign the ConstDecl to this folded value thus reusing all of our existing
BlockExpression code instead of a seperate system.
Fixes #799
Diffstat (limited to 'gcc/rust/backend/rust-compile-item.h')
-rw-r--r-- | gcc/rust/backend/rust-compile-item.h | 84 |
1 files changed, 76 insertions, 8 deletions
diff --git a/gcc/rust/backend/rust-compile-item.h b/gcc/rust/backend/rust-compile-item.h index 6174950..208a2a5 100644 --- a/gcc/rust/backend/rust-compile-item.h +++ b/gcc/rust/backend/rust-compile-item.h @@ -91,25 +91,93 @@ public: void visit (HIR::ConstantItem &constant) override { + // resolve the type TyTy::BaseType *resolved_type = nullptr; bool ok = ctx->get_tyctx ()->lookup_type (constant.get_mappings ().get_hirid (), &resolved_type); rust_assert (ok); - tree type = TyTyResolveCompile::compile (ctx, resolved_type); - tree const_type = build_qualified_type (type, TYPE_QUAL_CONST); - - tree value = CompileExpr::Compile (constant.get_expr (), ctx); - tree folded_expr = ConstCtx::fold (value); - + // canonical path const Resolver::CanonicalPath *canonical_path = nullptr; ok = ctx->get_mappings ()->lookup_canonical_path ( constant.get_mappings ().get_crate_num (), constant.get_mappings ().get_nodeid (), &canonical_path); rust_assert (ok); - std::string ident = canonical_path->get (); + + // types + tree type = TyTyResolveCompile::compile (ctx, resolved_type); + tree const_type = build_qualified_type (type, TYPE_QUAL_CONST); + + HIR::Expr *const_value_expr = constant.get_expr (); + 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 (constant.get_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, constant.get_locus ())}, + NULL, constant.get_locus ()); + + tree fndecl + = ctx->get_backend ()->function (compiled_fn_type, ident, "", + Backend::function_read_only, + constant.get_locus ()); + + tree enclosing_scope = NULL_TREE; + HIR::BlockExpr *function_body + = static_cast<HIR::BlockExpr *> (constant.get_expr ()); + Location start_location = function_body->get_locus (); + Location end_location = function_body->get_closing_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, + constant.get_locus (), &ret_var_stmt); + + ctx->add_statement (ret_var_stmt); + ctx->push_fn (fndecl, return_address); + + compile_function_body (fndecl, *function_body, true); + + ctx->pop_block (); + + auto body = ctx->get_backend ()->block_statement (code_block); + if (!ctx->get_backend ()->function_set_body (fndecl, body)) + { + rust_error_at (constant.get_locus (), + "failed to set body to constant function"); + return; + } + + ctx->pop_fn (); + + // lets fold it into a call expr + tree call = build_call_array_loc (constant.get_locus ().gcc_location (), + const_type, fndecl, 0, NULL); + folded_expr = ConstCtx::fold (call); + } + tree const_expr = ctx->get_backend ()->named_constant_expression (const_type, ident, folded_expr, @@ -297,7 +365,7 @@ public: ctx->push_fn (fndecl, return_address); - compile_function_body (fndecl, function.get_definition (), + compile_function_body (fndecl, *function.get_definition ().get (), function.has_function_return_type ()); ctx->pop_block (); |