Skip to content

Commit

Permalink
Add initial constant evaluation to blocks
Browse files Browse the repository at this point in the history
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
  • Loading branch information
philberty committed Jan 14, 2022
1 parent e9ffd43 commit 93554f3
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 19 deletions.
3 changes: 1 addition & 2 deletions gcc/rust/backend/rust-compile-base.h
Expand Up @@ -37,8 +37,7 @@ class HIRCompileBase : public HIR::HIRFullVisitorBase

Context *get_context () { return ctx; }

void compile_function_body (tree fndecl,
std::unique_ptr<HIR::BlockExpr> &function_body,
void compile_function_body (tree fndecl, HIR::BlockExpr &function_body,
bool has_return_type);

bool compile_locals_for_block (Resolver::Rib &rib, tree fndecl,
Expand Down
4 changes: 2 additions & 2 deletions gcc/rust/backend/rust-compile-implitem.h
Expand Up @@ -288,7 +288,7 @@ class CompileInherentImplItem : public HIRCompileBase

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 ();
Expand Down Expand Up @@ -548,7 +548,7 @@ class CompileTraitItem : public HIRCompileBase

ctx->push_fn (fndecl, return_address);

compile_function_body (fndecl, func.get_block_expr (),
compile_function_body (fndecl, *func.get_block_expr ().get (),
function.has_return_type ());

ctx->pop_block ();
Expand Down
84 changes: 76 additions & 8 deletions gcc/rust/backend/rust-compile-item.h
Expand Up @@ -91,25 +91,93 @@ class CompileItem : public HIRCompileBase

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,
Expand Down Expand Up @@ -297,7 +365,7 @@ class CompileItem : public HIRCompileBase

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 ();
Expand Down
14 changes: 7 additions & 7 deletions gcc/rust/backend/rust-compile.cc
Expand Up @@ -207,11 +207,11 @@ CompileStructExprField::visit (HIR::StructExprFieldIdentifier &field)
// Shared methods in compilation

void
HIRCompileBase::compile_function_body (
tree fndecl, std::unique_ptr<HIR::BlockExpr> &function_body,
bool has_return_type)
HIRCompileBase::compile_function_body (tree fndecl,
HIR::BlockExpr &function_body,
bool has_return_type)
{
for (auto &s : function_body->get_statements ())
for (auto &s : function_body.get_statements ())
{
auto compiled_expr = CompileStmt::Compile (s.get (), ctx);
if (compiled_expr != nullptr)
Expand All @@ -222,12 +222,12 @@ HIRCompileBase::compile_function_body (
}
}

if (function_body->has_expr ())
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);
= CompileExpr::Compile (function_body.expr.get (), ctx);

if (compiled_expr != nullptr)
{
Expand All @@ -238,7 +238,7 @@ HIRCompileBase::compile_function_body (

auto ret = ctx->get_backend ()->return_statement (
fndecl, retstmts,
function_body->get_final_expr ()->get_locus ());
function_body.get_final_expr ()->get_locus ());
ctx->add_statement (ret);
}
else
Expand Down
16 changes: 16 additions & 0 deletions gcc/testsuite/rust/execute/torture/const_fold2.rs
@@ -0,0 +1,16 @@
// { dg-additional-options "-w" }
const A: i32 = 1;
const B: i32 = { A + 2 };

const fn test() -> i32 {
B
}

const C: i32 = {
const a: i32 = 4;
test() + a
};

fn main() -> i32 {
C - 7
}

0 comments on commit 93554f3

Please sign in to comment.