aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile-expr.cc
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2022-01-13 22:01:59 +0000
committerPhilip Herron <philip.herron@embecosm.com>2022-01-14 12:32:40 +0000
commit52780af6602763fac6297f7983878b38e0188bb9 (patch)
tree41a8d89d018f527b3f20159da1279f67aac71f40 /gcc/rust/backend/rust-compile-expr.cc
parent06c2a74f557ec98896c9f71ba666bd969c4735d2 (diff)
downloadgcc-52780af6602763fac6297f7983878b38e0188bb9.zip
gcc-52780af6602763fac6297f7983878b38e0188bb9.tar.gz
gcc-52780af6602763fac6297f7983878b38e0188bb9.tar.bz2
Redesign constant folding from the typechecking pass to the backend
In Rust the ArrayType has a constant capacity constraint, this 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 typechecking system which generated gcc tree's for the IR and enforced the constant checking along the way. Also after doing some testing GCC with optimizations turned on is capable of constant folding/propogating the compilation unit fully. Which meant we need a method of doing with regardless of optimization level to be able to be on par with what the Rust language expects we need a full proof method. Turns out the CPP front-end already does this via its constexpr mechanism to ensure that these _do_ fold correclty. 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. Addresses #799
Diffstat (limited to 'gcc/rust/backend/rust-compile-expr.cc')
-rw-r--r--gcc/rust/backend/rust-compile-expr.cc235
1 files changed, 232 insertions, 3 deletions
diff --git a/gcc/rust/backend/rust-compile-expr.cc b/gcc/rust/backend/rust-compile-expr.cc
index 9b04bbf..33237e5 100644
--- a/gcc/rust/backend/rust-compile-expr.cc
+++ b/gcc/rust/backend/rust-compile-expr.cc
@@ -25,10 +25,12 @@
#include "rust-hir-type-bounds.h"
#include "rust-hir-dot-operator.h"
#include "rust-compile-pattern.h"
+#include "rust-constexpr.h"
#include "fold-const.h"
#include "realmpfr.h"
#include "convert.h"
+#include "print-tree.h"
namespace Rust {
namespace Compile {
@@ -381,7 +383,11 @@ CompileExpr::visit (HIR::CallExpr &expr)
rust_assert (ok);
// coerce it if required
- rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
+ Location lvalue_locus
+ = ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
+ Location rvalue_locus = argument->get_locus ();
+ rvalue = coercion_site (rvalue, actual, expected, lvalue_locus,
+ rvalue_locus);
// add it to the list
arguments.push_back (rvalue);
@@ -477,7 +483,11 @@ CompileExpr::visit (HIR::CallExpr &expr)
rust_assert (ok);
// coerce it if required
- rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
+ Location lvalue_locus
+ = ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
+ Location rvalue_locus = argument->get_locus ();
+ rvalue
+ = coercion_site (rvalue, actual, expected, lvalue_locus, rvalue_locus);
// add it to the list
args.push_back (rvalue);
@@ -604,7 +614,11 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
rust_assert (ok);
// coerce it if required
- rvalue = coercion_site (rvalue, actual, expected, expr.get_locus ());
+ Location lvalue_locus
+ = ctx->get_mappings ()->lookup_location (expected->get_ty_ref ());
+ Location rvalue_locus = argument->get_locus ();
+ rvalue
+ = coercion_site (rvalue, actual, expected, lvalue_locus, rvalue_locus);
// add it to the list
args.push_back (rvalue);
@@ -1093,5 +1107,220 @@ CompileExpr::type_cast_expression (tree type_to_cast_to, tree expr_tree,
expr_tree);
}
+void
+CompileExpr::visit (HIR::ArrayExpr &expr)
+{
+ TyTy::BaseType *tyty = nullptr;
+ if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
+ &tyty))
+ {
+ rust_fatal_error (expr.get_locus (),
+ "did not resolve type for this array expr");
+ return;
+ }
+
+ tree array_type = TyTyResolveCompile::compile (ctx, tyty);
+ if (TREE_CODE (array_type) != ARRAY_TYPE)
+ {
+ translated = error_mark_node;
+ return;
+ }
+
+ rust_assert (tyty->get_kind () == TyTy::TypeKind::ARRAY);
+ const TyTy::ArrayType &array_tyty
+ = static_cast<const TyTy::ArrayType &> (*tyty);
+
+ HIR::ArrayElems &elements = *expr.get_internal_elements ();
+ switch (elements.get_array_expr_type ())
+ {
+ case HIR::ArrayElems::ArrayExprType::VALUES: {
+ HIR::ArrayElemsValues &elems
+ = static_cast<HIR::ArrayElemsValues &> (elements);
+ translated
+ = array_value_expr (expr.get_locus (), array_tyty, array_type, elems);
+ }
+ return;
+
+ case HIR::ArrayElems::ArrayExprType::COPIED:
+ HIR::ArrayElemsCopied &elems
+ = static_cast<HIR::ArrayElemsCopied &> (elements);
+ translated
+ = array_copied_expr (expr.get_locus (), array_tyty, array_type, elems);
+ }
+}
+
+tree
+CompileExpr::array_value_expr (Location expr_locus,
+ const TyTy::ArrayType &array_tyty,
+ tree array_type, HIR::ArrayElemsValues &elems)
+{
+ std::vector<unsigned long> indexes;
+ std::vector<tree> constructor;
+ size_t i = 0;
+ for (auto &elem : elems.get_values ())
+ {
+ tree translated_expr = CompileExpr::Compile (elem.get (), ctx);
+ constructor.push_back (translated_expr);
+ indexes.push_back (i++);
+ }
+
+ return ctx->get_backend ()->array_constructor_expression (array_type, indexes,
+ constructor,
+ expr_locus);
+}
+
+tree
+CompileExpr::array_copied_expr (Location expr_locus,
+ const TyTy::ArrayType &array_tyty,
+ tree array_type, HIR::ArrayElemsCopied &elems)
+{
+ // see gcc/cp/typeck2.c:1369-1401
+ gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
+ tree domain = TYPE_DOMAIN (array_type);
+ if (!domain)
+ return error_mark_node;
+
+ if (!TREE_CONSTANT (TYPE_MAX_VALUE (domain)))
+ {
+ rust_error_at (expr_locus, "non const capacity domain %qT", array_type);
+ return error_mark_node;
+ }
+
+ tree capacity_expr = CompileExpr::Compile (elems.get_num_copies_expr (), ctx);
+ if (!TREE_CONSTANT (capacity_expr))
+ {
+ rust_error_at (expr_locus, "non const num copies %qT", array_type);
+ return error_mark_node;
+ }
+
+ // get the compiled value
+ tree translated_expr = CompileExpr::Compile (elems.get_elem_to_copy (), ctx);
+
+ tree max_domain = TYPE_MAX_VALUE (domain);
+ tree min_domain = TYPE_MIN_VALUE (domain);
+
+ auto max = wi::to_offset (max_domain);
+ auto min = wi::to_offset (min_domain);
+ auto precision = TYPE_PRECISION (TREE_TYPE (domain));
+ auto sign = TYPE_SIGN (TREE_TYPE (domain));
+ unsigned HOST_WIDE_INT len
+ = wi::ext (max - min + 1, precision, sign).to_uhwi ();
+
+ // create the constructor
+ size_t idx = 0;
+ std::vector<unsigned long> indexes;
+ std::vector<tree> constructor;
+ for (unsigned HOST_WIDE_INT i = 0; i < len; i++)
+ {
+ constructor.push_back (translated_expr);
+ indexes.push_back (idx++);
+ }
+
+ return ctx->get_backend ()->array_constructor_expression (array_type, indexes,
+ constructor,
+ expr_locus);
+}
+
+// tree
+// CompileExpr::array_copied_expr (Location expr_locus, tree array_type,
+// HIR::ArrayElemsCopied &elems)
+// {
+// // create tmp for the result
+// fncontext fnctx = ctx->peek_fn ();
+// Location start_location = expr_locus;
+// Location end_location = expr_locus;
+// tree fndecl = fnctx.fndecl;
+// tree enclosing_scope = ctx->peek_enclosing_scope ();
+
+// bool is_address_taken = false;
+// tree result_var_stmt = nullptr;
+// Bvariable *result
+// = ctx->get_backend ()->temporary_variable (fnctx.fndecl,
+// enclosing_scope,
+// array_type, NULL,
+// is_address_taken, expr_locus,
+// &result_var_stmt);
+// ctx->add_statement (result_var_stmt);
+
+// // get the compiled value
+// tree translated_expr = CompileExpr::Compile (elems.get_elem_to_copy (),
+// ctx);
+
+// // lets assign each index in the array
+// TyTy::BaseType *capacity_tyty = nullptr;
+// HirId capacity_ty_id
+// = elems.get_num_copies_expr ()->get_mappings ().get_hirid ();
+// bool ok = ctx->get_tyctx ()->lookup_type (capacity_ty_id,
+// &capacity_tyty); rust_assert (ok); tree capacity_type =
+// TyTyResolveCompile::compile (ctx, capacity_tyty); tree capacity_expr =
+// CompileExpr::Compile (elems.get_num_copies_expr (), ctx);
+
+// // create a loop for this with assignments to array_index exprs
+// tree index_type = capacity_type;
+// Bvariable *idx
+// = ctx->get_backend ()->temporary_variable (fnctx.fndecl,
+// enclosing_scope,
+// index_type, NULL,
+// is_address_taken, expr_locus,
+// &result_var_stmt);
+// ctx->add_statement (result_var_stmt);
+
+// // set index to zero
+// tree index_lvalue = error_mark_node;
+// tree zero = build_int_cst (index_type, 0);
+// tree index_assignment
+// = ctx->get_backend ()->assignment_statement (fnctx.fndecl,
+// index_lvalue,
+// zero, expr_locus);
+// ctx->add_statement (index_assignment);
+
+// // BEGIN loop block
+// tree loop_body = ctx->get_backend ()->block (fndecl, enclosing_scope, {},
+// start_location, end_location);
+// ctx->push_block (loop_body);
+
+// // loop predicate
+// tree loop_predicate
+// = fold_build2_loc (expr_locus.gcc_location (), GE_EXPR,
+// boolean_type_node,
+// ctx->get_backend ()->var_expression (idx, expr_locus),
+// capacity_expr);
+// tree exit_expr = fold_build1_loc (expr_locus.gcc_location (), EXIT_EXPR,
+// void_type_node, loop_predicate);
+// tree break_stmt
+// = ctx->get_backend ()->expression_statement (fnctx.fndecl, exit_expr);
+// ctx->add_statement (break_stmt);
+
+// // increment index
+// tree increment
+// = fold_build2_loc (expr_locus.gcc_location (), POSTINCREMENT_EXPR,
+// index_type,
+// ctx->get_backend ()->var_expression (idx, expr_locus),
+// build_int_cst (index_type, 1));
+
+// // create index_assess
+// tree index_access = ctx->get_backend ()->array_index_expression (
+// ctx->get_backend ()->var_expression (result, expr_locus), increment,
+// expr_locus);
+
+// // create assignment to index_access
+// tree array_assignment
+// = ctx->get_backend ()->assignment_statement (fnctx.fndecl,
+// index_access,
+// translated_expr, expr_locus);
+// ctx->add_statement (array_assignment);
+
+// // END loop block
+// ctx->pop_block ();
+
+// tree loop_expr = ctx->get_backend ()->loop_expression (loop_body,
+// expr_locus); tree loop_stmt
+// = ctx->get_backend ()->expression_statement (fnctx.fndecl, loop_expr);
+// ctx->add_statement (loop_stmt);
+
+// // result is the tmp
+// return ctx->get_backend ()->var_expression (result, expr_locus);
+// }
+
} // namespace Compile
} // namespace Rust