aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile.cc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-01-14 15:49:07 +0000
committerGitHub <noreply@github.com>2022-01-14 15:49:07 +0000
commitb21caeb3af4313016afeb94a91956e8fc4c2656d (patch)
tree03b1cac2b3442af423cd565b0168682e6d4541b3 /gcc/rust/backend/rust-compile.cc
parent03e56b5181506a4e6cdb9fe86c543a57840e54c3 (diff)
parent93554f3bce5bd42d8671559a774818767979cdae (diff)
downloadgcc-b21caeb3af4313016afeb94a91956e8fc4c2656d.zip
gcc-b21caeb3af4313016afeb94a91956e8fc4c2656d.tar.gz
gcc-b21caeb3af4313016afeb94a91956e8fc4c2656d.tar.bz2
Merge #870
870: Add constant folding to const functions r=philberty a=philberty In Rust the ArrayType has a constant capacity constraint, which means it allows for bounds checking at compile time as no variable-length arrays are allowed. In order to typecheck this case we had a constant folding pass as part of the type checking system which generated gcc tree's for the IR and enforced the constant checking along the way. GCC with optimizations turned on is capable of constant folding/propogating the compilation unit fully, but we need a method that works regardless of middlle-end optimizations to fold constant expressions at the front-end, turns out the CPP front-end already does this via its constexpr mechanism to ensure that these _do_ fold correctly. Another major reason to do this change is that the original const fold pass was a striped down copy of what the backend is _already_ doing which is creating a duplication of the code generation pass. With this all unified into the code generation pass all we need to do is port over gcc/cp/constexpr.c to enforce the const rules fully but at the GCC tree level not at the typed HIR level. Now that we have unified the pass when we hit a const function we can simply emit a normal GCC function and outside of const expressions GCC will simply emit a normal CallExpr and depending on optimization level fully optimize this. If we are in a ConstDecl we will follow the rust-constexpr.cc and fold the values or error_mark_node with an apropriate error. By reusing the CPP constexpr code we _know_ it works so reusing it as much as possible is a good idea in general for this front-end. Fixes #799 Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc/rust/backend/rust-compile.cc')
-rw-r--r--gcc/rust/backend/rust-compile.cc90
1 files changed, 77 insertions, 13 deletions
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index 610e3aa..7208ed0 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -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)
@@ -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)
{
@@ -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
@@ -288,21 +288,33 @@ HIRCompileBase::compile_locals_for_block (Resolver::Rib &rib, tree fndecl,
}
tree
-HIRCompileBase::coercion_site (tree compiled_ref, TyTy::BaseType *actual,
- TyTy::BaseType *expected, Location locus)
+HIRCompileBase::coercion_site (tree rvalue, TyTy::BaseType *actual,
+ TyTy::BaseType *expected, Location lvalue_locus,
+ Location rvalue_locus)
{
auto root_actual_kind = actual->get_root ()->get_kind ();
auto root_expected_kind = expected->get_root ()->get_kind ();
- if (root_expected_kind == TyTy::TypeKind::DYNAMIC
- && root_actual_kind != TyTy::TypeKind::DYNAMIC)
+ if (root_expected_kind == TyTy::TypeKind::ARRAY
+ && root_actual_kind == TyTy::TypeKind::ARRAY)
+ {
+ tree tree_rval_type
+ = TyTyResolveCompile::compile (ctx, actual->get_root ());
+ tree tree_lval_type
+ = TyTyResolveCompile::compile (ctx, expected->get_root ());
+ if (!verify_array_capacities (tree_lval_type, tree_rval_type,
+ lvalue_locus, rvalue_locus))
+ return error_mark_node;
+ }
+ else if (root_expected_kind == TyTy::TypeKind::DYNAMIC
+ && root_actual_kind != TyTy::TypeKind::DYNAMIC)
{
const TyTy::DynamicObjectType *dyn
= static_cast<const TyTy::DynamicObjectType *> (expected->get_root ());
- return coerce_to_dyn_object (compiled_ref, actual, expected, dyn, locus);
+ return coerce_to_dyn_object (rvalue, actual, expected, dyn, rvalue_locus);
}
- return compiled_ref;
+ return rvalue;
}
tree
@@ -530,5 +542,57 @@ HIRCompileBase::compute_address_for_trait_item (
true, locus);
}
+bool
+HIRCompileBase::verify_array_capacities (tree ltype, tree rtype,
+ Location lvalue_locus,
+ Location rvalue_locus)
+{
+ rust_assert (ltype != NULL_TREE);
+ rust_assert (rtype != NULL_TREE);
+
+ // lets just return ok as other errors have already occurred
+ if (ltype == error_mark_node || rtype == error_mark_node)
+ return true;
+
+ tree ltype_domain = TYPE_DOMAIN (ltype);
+ if (!ltype_domain)
+ return false;
+
+ if (!TREE_CONSTANT (TYPE_MAX_VALUE (ltype_domain)))
+ return false;
+
+ auto ltype_length
+ = wi::ext (wi::to_offset (TYPE_MAX_VALUE (ltype_domain))
+ - wi::to_offset (TYPE_MIN_VALUE (ltype_domain)) + 1,
+ TYPE_PRECISION (TREE_TYPE (ltype_domain)),
+ TYPE_SIGN (TREE_TYPE (ltype_domain)))
+ .to_uhwi ();
+
+ tree rtype_domain = TYPE_DOMAIN (rtype);
+ if (!rtype_domain)
+ return false;
+
+ if (!TREE_CONSTANT (TYPE_MAX_VALUE (rtype_domain)))
+ return false;
+
+ auto rtype_length
+ = wi::ext (wi::to_offset (TYPE_MAX_VALUE (rtype_domain))
+ - wi::to_offset (TYPE_MIN_VALUE (rtype_domain)) + 1,
+ TYPE_PRECISION (TREE_TYPE (rtype_domain)),
+ TYPE_SIGN (TREE_TYPE (rtype_domain)))
+ .to_uhwi ();
+
+ if (ltype_length != rtype_length)
+ {
+ rust_error_at (rvalue_locus,
+ "expected an array with a fixed size of %lu "
+ "elements, found one with %lu elements",
+ ltype_length, rtype_length);
+ return false;
+ }
+
+ return true;
+}
+
} // namespace Compile
} // namespace Rust