Skip to content

Commit 1a8447d

Browse files
committed
gccrs: add {add,sub,mul}_with_overflow intrinsics
Fixes #1898 Signed-off-by: Philip Herron <[email protected]> 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.
1 parent 193c21c commit 1a8447d

File tree

2 files changed

+142
-0
lines changed

2 files changed

+142
-0
lines changed

gcc/rust/backend/rust-compile-intrinsic.cc

+104
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "rust-constexpr.h"
2626
#include "rust-tree.h"
2727
#include "tree-core.h"
28+
#include "rust-gcc.h"
2829
#include "print-tree.h"
2930
#include "fold-const.h"
3031
#include "langhooks.h"
@@ -78,6 +79,8 @@ static tree
7879
wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, tree_code op);
7980
static tree
8081
copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype);
82+
static tree
83+
op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op);
8184

8285
enum class Prefetch
8386
{
@@ -107,6 +110,14 @@ wrapping_op_handler (tree_code op)
107110
};
108111
}
109112

113+
const static std::function<tree (Context *, TyTy::FnType *)>
114+
op_with_overflow (tree_code op)
115+
{
116+
return [op] (Context *ctx, TyTy::FnType *fntype) {
117+
return op_with_overflow_inner (ctx, fntype, op);
118+
};
119+
}
120+
110121
static inline tree
111122
prefetch_read_data (Context *ctx, TyTy::FnType *fntype)
112123
{
@@ -170,6 +181,9 @@ static const std::map<std::string,
170181
{"wrapping_add", wrapping_op_handler (PLUS_EXPR)},
171182
{"wrapping_sub", wrapping_op_handler (MINUS_EXPR)},
172183
{"wrapping_mul", wrapping_op_handler (MULT_EXPR)},
184+
{"add_with_overflow", op_with_overflow (PLUS_EXPR)},
185+
{"sub_with_overflow", op_with_overflow (MINUS_EXPR)},
186+
{"mul_with_overflow", op_with_overflow (MULT_EXPR)},
173187
{"copy_nonoverlapping", copy_nonoverlapping_handler},
174188
{"prefetch_read_data", prefetch_read_data},
175189
{"prefetch_write_data", prefetch_write_data},
@@ -558,6 +572,96 @@ wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, tree_code op)
558572
return fndecl;
559573
}
560574

575+
/**
576+
* pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
577+
*/
578+
static tree
579+
op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op)
580+
{
581+
// wrapping_<op> intrinsics have two parameter
582+
rust_assert (fntype->get_params ().size () == 2);
583+
584+
tree lookup = NULL_TREE;
585+
if (check_for_cached_intrinsic (ctx, fntype, &lookup))
586+
return lookup;
587+
588+
auto fndecl = compile_intrinsic_function (ctx, fntype);
589+
590+
// setup the params
591+
std::vector<Bvariable *> param_vars;
592+
compile_fn_params (ctx, fntype, fndecl, &param_vars);
593+
594+
auto &x_param = param_vars.at (0);
595+
auto &y_param = param_vars.at (1);
596+
597+
if (!ctx->get_backend ()->function_set_parameters (fndecl, param_vars))
598+
return error_mark_node;
599+
600+
enter_intrinsic_block (ctx, fndecl);
601+
602+
// BUILTIN op_with_overflow FN BODY BEGIN
603+
auto x = ctx->get_backend ()->var_expression (x_param, Location ());
604+
auto y = ctx->get_backend ()->var_expression (y_param, Location ());
605+
606+
tree overflow_builtin = error_mark_node;
607+
switch (op)
608+
{
609+
case PLUS_EXPR:
610+
BuiltinsContext::get ().lookup_simple_builtin ("add_overflow",
611+
&overflow_builtin);
612+
break;
613+
614+
case MINUS_EXPR:
615+
BuiltinsContext::get ().lookup_simple_builtin ("sub_overflow",
616+
&overflow_builtin);
617+
break;
618+
619+
case MULT_EXPR:
620+
BuiltinsContext::get ().lookup_simple_builtin ("mul_overflow",
621+
&overflow_builtin);
622+
break;
623+
624+
default:
625+
gcc_unreachable ();
626+
break;
627+
}
628+
rust_assert (overflow_builtin != error_mark_node);
629+
630+
// this should match y as well or we can take it from the TyTy structure
631+
tree overflow_op_type = TREE_TYPE (x);
632+
tree tmp_stmt = error_mark_node;
633+
Bvariable *bvar
634+
= ctx->get_backend ()->temporary_variable (fndecl, NULL_TREE,
635+
overflow_op_type, NULL_TREE,
636+
true /*address_is_taken*/,
637+
Location (), &tmp_stmt);
638+
ctx->add_statement (tmp_stmt);
639+
640+
tree result_decl = bvar->get_tree (Location ());
641+
tree result_ref = build_fold_addr_expr_loc (BUILTINS_LOCATION, result_decl);
642+
643+
tree did_overflow_node
644+
= build_call_expr_loc (BUILTINS_LOCATION, overflow_builtin, 3, x, y,
645+
result_ref);
646+
647+
std::vector<tree> vals = {result_decl, did_overflow_node};
648+
tree tuple_type = TREE_TYPE (DECL_RESULT (fndecl));
649+
tree result_expr
650+
= ctx->get_backend ()->constructor_expression (tuple_type, false, vals, -1,
651+
Location ());
652+
653+
auto return_statement
654+
= ctx->get_backend ()->return_statement (fndecl, {result_expr},
655+
Location ());
656+
ctx->add_statement (return_statement);
657+
658+
// BUILTIN wrapping_<op> FN BODY END
659+
660+
finalize_intrinsic_block (ctx, fndecl);
661+
662+
return fndecl;
663+
}
664+
561665
/**
562666
* fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
563667
*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
mod intrinsics {
2+
extern "rust-intrinsic" {
3+
pub fn add_with_overflow<T>(x: T, y: T) -> (T, bool);
4+
pub fn sub_with_overflow<T>(x: T, y: T) -> (T, bool);
5+
pub fn mul_with_overflow<T>(x: T, y: T) -> (T, bool);
6+
}
7+
}
8+
9+
pub enum Option<T> {
10+
None,
11+
Some(T),
12+
}
13+
14+
impl i32 {
15+
pub fn checked_add(self, rhs: Self) -> Option<Self> {
16+
let (a, b) = self.overflowing_add(rhs);
17+
if b {
18+
Option::None
19+
} else {
20+
Option::Some(a)
21+
}
22+
}
23+
24+
pub fn overflowing_add(self, rhs: Self) -> (Self, bool) {
25+
let (a, b) = unsafe { intrinsics::add_with_overflow(self as i32, rhs as i32) };
26+
(a as Self, b)
27+
}
28+
29+
pub fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
30+
let (a, b) = unsafe { intrinsics::sub_with_overflow(self as i32, rhs as i32) };
31+
(a as Self, b)
32+
}
33+
34+
pub fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
35+
let (a, b) = unsafe { intrinsics::mul_with_overflow(self as i32, rhs as i32) };
36+
(a as Self, b)
37+
}
38+
}

0 commit comments

Comments
 (0)