From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1643) id 48F013858D28; Sun, 5 Mar 2023 11:41:19 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 48F013858D28 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1678016479; bh=P3aor2r30qxZWALsrFhanAMGgDKaJEJpZZboI6hRU88=; h=From:To:Subject:Date:From; b=lUey80AwiApPAvcb+uQq+C2rqca5+BIeL6XP6Ggn/ad6Pq9XkHKjtkSHjmMu0geKS bZX9RpCA7WL7t19GxmE3/2OH9ISsA6BGRR9FsiwMkZeUNTrFGUqbTYpehqxuiTtzQp GYaeC7MfXUqQm3FRXNZJ62i9AIc+kegNIXDNXttQ= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Thomas Schwinge To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/rust/master] gccrs: add {add, sub, mul}_with_overflow intrinsics X-Act-Checkin: gcc X-Git-Author: Philip Herron X-Git-Refname: refs/heads/devel/rust/master X-Git-Oldrev: 7394a6893dd9fc2bc34822e002b53eb200ff51d5 X-Git-Newrev: 23befb042f90f5c84a59c0901b147c24a704847b Message-Id: <20230305114119.48F013858D28@sourceware.org> Date: Sun, 5 Mar 2023 11:41:19 +0000 (GMT) List-Id: https://gcc.gnu.org/g:23befb042f90f5c84a59c0901b147c24a704847b commit 23befb042f90f5c84a59c0901b147c24a704847b Author: Philip Herron Date: Wed Mar 1 11:42:36 2023 +0000 gccrs: add {add,sub,mul}_with_overflow intrinsics Fixes #1898 Signed-off-by: Philip Herron gcc/rust/ChangeLog: * backend/rust-compile-intrinsic.cc (op_with_overflow_inner): wraps op_with_overflow (std::function +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(x: T, y: T) -> (T, bool); + */ +static tree +op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op) +{ + // wrapping_ 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 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 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_ FN BODY END + + finalize_intrinsic_block (ctx, fndecl); + + return fndecl; +} + /** * fn copy_nonoverlapping(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(x: T, y: T) -> (T, bool); + pub fn sub_with_overflow(x: T, y: T) -> (T, bool); + pub fn mul_with_overflow(x: T, y: T) -> (T, bool); + } +} + +pub enum Option { + None, + Some(T), +} + +impl i32 { + pub fn checked_add(self, rhs: Self) -> Option { + 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) + } +}