From 23befb042f90f5c84a59c0901b147c24a704847b Mon Sep 17 00:00:00 2001 From: Philip Herron Date: Wed, 1 Mar 2023 11:42:36 +0000 Subject: 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); */ static tree 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 0000000..8788da5 --- /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) + } +} -- cgit v1.1