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, &param_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).