aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile-item.h
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2022-01-13 21:04:57 +0000
committerPhilip Herron <philip.herron@embecosm.com>2022-01-14 12:32:49 +0000
commit93554f3bce5bd42d8671559a774818767979cdae (patch)
tree03b1cac2b3442af423cd565b0168682e6d4541b3 /gcc/rust/backend/rust-compile-item.h
parente9ffd4308d70da55b4c698b07b484063bcda0b01 (diff)
downloadgcc-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.h84
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 ();