|
25 | 25 | #include "rust-constexpr.h"
|
26 | 26 | #include "rust-tree.h"
|
27 | 27 | #include "tree-core.h"
|
| 28 | +#include "rust-gcc.h" |
28 | 29 | #include "print-tree.h"
|
29 | 30 | #include "fold-const.h"
|
30 | 31 | #include "langhooks.h"
|
@@ -78,6 +79,8 @@ static tree
|
78 | 79 | wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, tree_code op);
|
79 | 80 | static tree
|
80 | 81 | copy_nonoverlapping_handler (Context *ctx, TyTy::FnType *fntype);
|
| 82 | +static tree |
| 83 | +op_with_overflow_inner (Context *ctx, TyTy::FnType *fntype, tree_code op); |
81 | 84 |
|
82 | 85 | enum class Prefetch
|
83 | 86 | {
|
@@ -107,6 +110,14 @@ wrapping_op_handler (tree_code op)
|
107 | 110 | };
|
108 | 111 | }
|
109 | 112 |
|
| 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 | + |
110 | 121 | static inline tree
|
111 | 122 | prefetch_read_data (Context *ctx, TyTy::FnType *fntype)
|
112 | 123 | {
|
@@ -170,6 +181,9 @@ static const std::map<std::string,
|
170 | 181 | {"wrapping_add", wrapping_op_handler (PLUS_EXPR)},
|
171 | 182 | {"wrapping_sub", wrapping_op_handler (MINUS_EXPR)},
|
172 | 183 | {"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)}, |
173 | 187 | {"copy_nonoverlapping", copy_nonoverlapping_handler},
|
174 | 188 | {"prefetch_read_data", prefetch_read_data},
|
175 | 189 | {"prefetch_write_data", prefetch_write_data},
|
@@ -558,6 +572,96 @@ wrapping_op_handler_inner (Context *ctx, TyTy::FnType *fntype, tree_code op)
|
558 | 572 | return fndecl;
|
559 | 573 | }
|
560 | 574 |
|
| 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, ¶m_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 | + |
561 | 665 | /**
|
562 | 666 | * fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
|
563 | 667 | */
|
|
0 commit comments