public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc/devel/rust/master] gccrs: add {add, sub, mul}_with_overflow intrinsics
@ 2023-03-05 11:41 Thomas Schwinge
0 siblings, 0 replies; only message in thread
From: Thomas Schwinge @ 2023-03-05 11:41 UTC (permalink / raw)
To: gcc-cvs
https://gcc.gnu.org/g:23befb042f90f5c84a59c0901b147c24a704847b
commit 23befb042f90f5c84a59c0901b147c24a704847b
Author: Philip Herron <herron.philip@googlemail.com>
Date: Wed Mar 1 11:42:36 2023 +0000
gccrs: add {add,sub,mul}_with_overflow intrinsics
Fixes #1898
Signed-off-by: Philip Herron <herron.philip@googlemail.com>
gcc/rust/ChangeLog:
* backend/rust-compile-intrinsic.cc (op_with_overflow_inner): wraps op_with_overflow
(std::function<tree): likewise
(op_with_overflow): generate the intrinsic based on the tree_code op
gcc/testsuite/ChangeLog:
* rust/compile/torture/intrinsics-8.rs: New test.
Diff:
---
gcc/rust/backend/rust-compile-intrinsic.cc | 104 +++++++++++++++++++++
gcc/testsuite/rust/compile/torture/intrinsics-8.rs | 38 ++++++++
2 files changed, 142 insertions(+)
diff --git a/gcc/rust/backend/rust-compile-intrinsic.cc b/gcc/rust/backend/rust-compile-intrinsic.cc
index 55222116366..04b0d3a2611 100644
--- a/gcc/rust/backend/rust-compile-intrinsic.cc
+++ b/gcc/rust/backend/rust-compile-intrinsic.cc
@@ -25,6 +25,7 @@
#include "rust-constexpr.h"
#include "rust-tree.h"
#include "tree-core.h"
+#include "rust-gcc.h"
#include "print-tree.h"
#include "fold-const.h"
#include "langhooks.h"
@@ -78,6 +79,8 @@ static tree
wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, tree_code op);
static tree
copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype);
+static tree
+op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op);
enum class Prefetch
{
@@ -107,6 +110,14 @@ wrapping_op_handler (tree_code op)
};
}
+const static std::function<tree (Context *, TyTy::FnType *)>
+op_with_overflow (tree_code op)
+{
+ return [op] (Context *ctx, TyTy::FnType *fntype) {
+ return op_with_overflow_inner (ctx, fntype, op);
+ };
+}
+
static inline tree
prefetch_read_data (Context *ctx, TyTy::FnType *fntype)
{
@@ -170,6 +181,9 @@ static const std::map<std::string,
{"wrapping_add", wrapping_op_handler (PLUS_EXPR)},
{"wrapping_sub", wrapping_op_handler (MINUS_EXPR)},
{"wrapping_mul", wrapping_op_handler (MULT_EXPR)},
+ {"add_with_overflow", op_with_overflow (PLUS_EXPR)},
+ {"sub_with_overflow", op_with_overflow (MINUS_EXPR)},
+ {"mul_with_overflow", op_with_overflow (MULT_EXPR)},
{"copy_nonoverlapping", copy_nonoverlapping_handler},
{"prefetch_read_data", prefetch_read_data},
{"prefetch_write_data", prefetch_write_data},
@@ -558,6 +572,96 @@ wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, tree_code op)
return fndecl;
}
+/**
+ * pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
+ */
+static tree
+op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op)
+{
+ // wrapping_<op> intrinsics have two parameter
+ rust_assert (fntype->get_params ().size () == 2);
+
+ tree lookup = NULL_TREE;
+ if (check_for_cached_intrinsic (ctx, fntype, &lookup))
+ return lookup;
+
+ auto fndecl = compile_intrinsic_function (ctx, fntype);
+
+ // setup the params
+ std::vector<Bvariable *> param_vars;
+ compile_fn_params (ctx, fntype, fndecl, ¶m_vars);
+
+ auto &x_param = param_vars.at (0);
+ auto &y_param = param_vars.at (1);
+
+ if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
+ return error_mark_node;
+
+ enter_intrinsic_block (ctx, fndecl);
+
+ // BUILTIN op_with_overflow FN BODY BEGIN
+ auto x = ctx->get_backend ()->var_expression (x_param, Location ());
+ auto y = ctx->get_backend ()->var_expression (y_param, Location ());
+
+ tree overflow_builtin = error_mark_node;
+ switch (op)
+ {
+ case PLUS_EXPR:
+ BuiltinsContext::get ().lookup_simple_builtin ("add_overflow",
+ &overflow_builtin);
+ break;
+
+ case MINUS_EXPR:
+ BuiltinsContext::get ().lookup_simple_builtin ("sub_overflow",
+ &overflow_builtin);
+ break;
+
+ case MULT_EXPR:
+ BuiltinsContext::get ().lookup_simple_builtin ("mul_overflow",
+ &overflow_builtin);
+ break;
+
+ default:
+ gcc_unreachable ();
+ break;
+ }
+ rust_assert (overflow_builtin != error_mark_node);
+
+ // this should match y as well or we can take it from the TyTy structure
+ tree overflow_op_type = TREE_TYPE (x);
+ tree tmp_stmt = error_mark_node;
+ Bvariable *bvar
+ = ctx->get_backend ()->temporary_variable (fndecl, NULL_TREE,
+ overflow_op_type, NULL_TREE,
+ true /*address_is_taken*/,
+ Location (), &tmp_stmt);
+ ctx->add_statement (tmp_stmt);
+
+ tree result_decl = bvar->get_tree (Location ());
+ tree result_ref = build_fold_addr_expr_loc (BUILTINS_LOCATION, result_decl);
+
+ tree did_overflow_node
+ = build_call_expr_loc (BUILTINS_LOCATION, overflow_builtin, 3, x, y,
+ result_ref);
+
+ std::vector<tree> vals = {result_decl, did_overflow_node};
+ tree tuple_type = TREE_TYPE (DECL_RESULT (fndecl));
+ tree result_expr
+ = ctx->get_backend ()->constructor_expression (tuple_type, false, vals, -1,
+ Location ());
+
+ auto return_statement
+ = ctx->get_backend ()->return_statement (fndecl, {result_expr},
+ Location ());
+ ctx->add_statement (return_statement);
+
+ // BUILTIN wrapping_<op> FN BODY END
+
+ finalize_intrinsic_block (ctx, fndecl);
+
+ return fndecl;
+}
+
/**
* fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
*/
diff --git a/gcc/testsuite/rust/compile/torture/intrinsics-8.rs b/gcc/testsuite/rust/compile/torture/intrinsics-8.rs
new file mode 100644
index 00000000000..8788da5c7fc
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/intrinsics-8.rs
@@ -0,0 +1,38 @@
+mod intrinsics {
+ extern "rust-intrinsic" {
+ pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
+ pub fn sub_with_overflow<T>(x: T, y: T) -> (T, bool);
+ pub fn mul_with_overflow<T>(x: T, y: T) -> (T, bool);
+ }
+}
+
+pub enum Option<T> {
+ None,
+ Some(T),
+}
+
+impl i32 {
+ pub fn checked_add(self, rhs: Self) -> Option<Self> {
+ let (a, b) = self.overflowing_add(rhs);
+ if b {
+ Option::None
+ } else {
+ Option::Some(a)
+ }
+ }
+
+ pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe { intrinsics::add_with_overflow(self as i32, rhs as i32) };
+ (a as Self, b)
+ }
+
+ pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe { intrinsics::sub_with_overflow(self as i32, rhs as i32) };
+ (a as Self, b)
+ }
+
+ pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
+ let (a, b) = unsafe { intrinsics::mul_with_overflow(self as i32, rhs as i32) };
+ (a as Self, b)
+ }
+}
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2023-03-05 11:41 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-03-05 11:41 [gcc/devel/rust/master] gccrs: add {add, sub, mul}_with_overflow intrinsics Thomas Schwinge
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).