aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2022-03-09 14:37:47 +0000
committerPhilip Herron <philip.herron@embecosm.com>2022-03-10 11:40:02 +0000
commita08ac0c27aed0c6d390d03656b708eb71381a5e9 (patch)
tree2de46126aaff38e8ef503952f299f164d6788f75 /gcc/rust/backend
parent865b6090a8f8981cdfc050ea2ee44abbe92de141 (diff)
downloadgcc-a08ac0c27aed0c6d390d03656b708eb71381a5e9.zip
gcc-a08ac0c27aed0c6d390d03656b708eb71381a5e9.tar.gz
gcc-a08ac0c27aed0c6d390d03656b708eb71381a5e9.tar.bz2
Add support for the rust offset intrinsic
This patch adds the initial support for generic intrinsics these are do not map directly to GCC builtins and need to be substited with their specificed types. This patch allows for custom implementation body for these functions by specifying handler functions which will generate the applicable intrinsic when asked for. Addresses #658
Diffstat (limited to 'gcc/rust/backend')
-rw-r--r--gcc/rust/backend/rust-compile-fnparam.h8
-rw-r--r--gcc/rust/backend/rust-compile-intrinsic.cc124
-rw-r--r--gcc/rust/backend/rust-compile-resolve-path.cc8
-rw-r--r--gcc/rust/backend/rust-tree.cc18
-rw-r--r--gcc/rust/backend/rust-tree.h6
5 files changed, 163 insertions, 1 deletions
diff --git a/gcc/rust/backend/rust-compile-fnparam.h b/gcc/rust/backend/rust-compile-fnparam.h
index 74df725..5e3cfaa 100644
--- a/gcc/rust/backend/rust-compile-fnparam.h
+++ b/gcc/rust/backend/rust-compile-fnparam.h
@@ -36,6 +36,14 @@ public:
return compiler.compiled_param;
}
+ static Bvariable *compile (Context *ctx, tree fndecl, HIR::Pattern *param,
+ tree decl_type, Location locus)
+ {
+ CompileFnParam compiler (ctx, fndecl, decl_type, locus);
+ param->accept_vis (compiler);
+ return compiler.compiled_param;
+ }
+
void visit (HIR::IdentifierPattern &pattern) override
{
if (!pattern.is_mut ())
diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc
index 8c5b073..177c14e 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -15,10 +15,20 @@
// <http://www.gnu.org/licenses/>.
#include "rust-compile-intrinsic.h"
+#include "rust-compile-type.h"
+#include "rust-compile-fnparam.h"
+#include "rust-tree.h"
namespace Rust {
namespace Compile {
+static tree
+offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype);
+
+static const std::map<std::string,
+ std::function<tree (Context *, TyTy::BaseType *)>>
+ generic_intrinsics = {{"offset", &offset_intrinsic_handler}};
+
Intrinsics::Intrinsics (Context *ctx) : ctx (ctx) {}
tree
@@ -82,11 +92,123 @@ Intrinsics::compile (TyTy::FnType *fntype)
if (builtin != nullptr)
return builtin;
+ // is it an generic builtin?
+ auto it = generic_intrinsics.find (fntype->get_identifier ());
+ if (it != generic_intrinsics.end ())
+ return it->second (ctx, fntype);
+
Location locus = ctx->get_mappings ()->lookup_location (fntype->get_ref ());
- rust_error_at (locus, "unknown builtin");
+ rust_error_at (locus, "unknown builtin intrinsic: %s",
+ fntype->get_identifier ().c_str ());
return error_mark_node;
}
+static tree
+offset_intrinsic_handler (Context *ctx, TyTy::BaseType *fntype_tyty)
+{
+ rust_assert (fntype_tyty->get_kind () == TyTy::TypeKind::FNDEF);
+ TyTy::FnType *fntype = static_cast<TyTy::FnType *> (fntype_tyty);
+ const Resolver::CanonicalPath &canonical_path = fntype->get_ident ().path;
+
+ // items can be forward compiled which means we may not need to invoke this
+ // code. We might also have already compiled this generic function as well.
+ tree lookup = NULL_TREE;
+ if (ctx->lookup_function_decl (fntype->get_ty_ref (), &lookup,
+ fntype->get_id (), fntype))
+ {
+ // has this been added to the list then it must be finished
+ if (ctx->function_completed (lookup))
+ {
+ tree dummy = NULL_TREE;
+ if (!ctx->lookup_function_decl (fntype->get_ty_ref (), &dummy))
+ {
+ ctx->insert_function_decl (fntype, lookup);
+ }
+ return lookup;
+ }
+ }
+
+ if (fntype->has_subsititions_defined ())
+ {
+ // override the Hir Lookups for the substituions in this context
+ fntype->override_context ();
+ }
+
+ // offset intrinsic has two params dst pointer and offset isize
+ if (fntype->get_params ().size () != 2)
+ {
+ rust_error_at (fntype->get_ident ().locus,
+ "invalid number of parameters for offset intrinsic");
+ return error_mark_node;
+ }
+
+ tree compiled_fn_type = TyTyResolveCompile::compile (ctx, fntype);
+ std::string ir_symbol_name
+ = canonical_path.get () + fntype->subst_as_string ();
+ std::string asm_name = ctx->mangle_item (fntype, canonical_path);
+
+ unsigned int flags = 0;
+ tree fndecl
+ = ctx->get_backend ()->function (compiled_fn_type, ir_symbol_name, asm_name,
+ flags, fntype->get_ident ().locus);
+ TREE_PUBLIC (fndecl) = 0;
+ TREE_READONLY (fndecl) = 1;
+ DECL_ARTIFICIAL (fndecl) = 1;
+ DECL_EXTERNAL (fndecl) = 0;
+ DECL_DECLARED_INLINE_P (fndecl) = 1;
+
+ // setup the params
+ std::vector<Bvariable *> param_vars;
+ for (auto &parm : fntype->get_params ())
+ {
+ auto &referenced_param = parm.first;
+ auto &param_tyty = parm.second;
+ auto compiled_param_type = TyTyResolveCompile::compile (ctx, param_tyty);
+
+ Location param_locus = referenced_param->get_locus ();
+ Bvariable *compiled_param_var
+ = CompileFnParam::compile (ctx, fndecl, referenced_param,
+ compiled_param_type, param_locus);
+
+ param_vars.push_back (compiled_param_var);
+ }
+
+ auto &dst_param = param_vars.at (0);
+ auto &size_param = param_vars.at (1);
+ rust_assert (param_vars.size () == 2);
+ if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
+ return error_mark_node;
+
+ tree enclosing_scope = NULL_TREE;
+ Location start_location = Location ();
+ Location end_location = Location ();
+
+ tree code_block = ctx->get_backend ()->block (fndecl, enclosing_scope, {},
+ start_location, end_location);
+ ctx->push_block (code_block);
+
+ // BUILTIN offset FN BODY BEGIN
+ tree dst = ctx->get_backend ()->var_expression (dst_param, Location ());
+ tree size = ctx->get_backend ()->var_expression (size_param, Location ());
+ tree pointer_offset_expr
+ = pointer_offset_expression (dst, size, BUILTINS_LOCATION);
+ auto return_statement
+ = ctx->get_backend ()->return_statement (fndecl, {pointer_offset_expr},
+ Location ());
+ ctx->add_statement (return_statement);
+ // BUILTIN offset FN BODY END
+
+ tree bind_tree = ctx->pop_block ();
+
+ gcc_assert (TREE_CODE (bind_tree) == BIND_EXPR);
+ DECL_SAVED_TREE (fndecl) = bind_tree;
+
+ ctx->pop_fn ();
+ ctx->push_function (fndecl);
+
+ return fndecl;
+}
+
} // namespace Compile
} // namespace Rust
diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc
index 09f3860..2ad672d 100644
--- a/gcc/rust/backend/rust-compile-resolve-path.cc
+++ b/gcc/rust/backend/rust-compile-resolve-path.cc
@@ -17,6 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-compile-resolve-path.h"
+#include "rust-compile-intrinsic.h"
#include "rust-compile-item.h"
#include "rust-compile-implitem.h"
#include "rust-compile-expr.h"
@@ -142,6 +143,13 @@ ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
TREE_USED (fn) = 1;
return address_expression (fn, expr_locus);
}
+ else if (fntype->get_abi () == ABI::INTRINSIC)
+ {
+ Intrinsics compile (ctx);
+ fn = compile.compile (fntype);
+ TREE_USED (fn) = 1;
+ return address_expression (fn, expr_locus);
+ }
}
// let the query system figure it out
diff --git a/gcc/rust/backend/rust-tree.cc b/gcc/rust/backend/rust-tree.cc
index 8e39408..6f7614d 100644
--- a/gcc/rust/backend/rust-tree.cc
+++ b/gcc/rust/backend/rust-tree.cc
@@ -17,6 +17,7 @@
// <http://www.gnu.org/licenses/>.
#include "rust-tree.h"
+#include "fold-const.h"
#include "stringpool.h"
#include "attribs.h"
#include "escaped_string.h"
@@ -656,4 +657,21 @@ get_fndecl_from_callee (tree fn)
return NULL_TREE;
}
+tree
+pointer_offset_expression (tree base_tree, tree index_tree, location_t location)
+{
+ tree element_type_tree = TREE_TYPE (TREE_TYPE (base_tree));
+ if (base_tree == error_mark_node || TREE_TYPE (base_tree) == error_mark_node
+ || index_tree == error_mark_node || element_type_tree == error_mark_node)
+ return error_mark_node;
+
+ tree element_size = TYPE_SIZE_UNIT (element_type_tree);
+ index_tree = fold_convert_loc (location, sizetype, index_tree);
+ tree offset
+ = fold_build2_loc (location, MULT_EXPR, sizetype, index_tree, element_size);
+
+ return fold_build2_loc (location, POINTER_PLUS_EXPR, TREE_TYPE (base_tree),
+ base_tree, offset);
+}
+
} // namespace Rust
diff --git a/gcc/rust/backend/rust-tree.h b/gcc/rust/backend/rust-tree.h
index c21bf4b..c50e090 100644
--- a/gcc/rust/backend/rust-tree.h
+++ b/gcc/rust/backend/rust-tree.h
@@ -177,6 +177,12 @@ expr_loc_or_input_loc (const_tree t);
extern tree
get_fndecl_from_callee (tree fn);
+// FIXME some helpers from HIRCompileBase could probably be moved here over time
+
+// Return an expression for the address of BASE[INDEX], used in offset intrinsic
+extern tree
+pointer_offset_expression (tree base_tree, tree index_tree, location_t locus);
+
} // namespace Rust
#endif // RUST_TREE