From: Eric Botcazou <ebotca...@adacore.com> The implementation is essentially mirrored from the one for signed types.
gcc/ada/ChangeLog: * gcc-interface/gigi.h (standard_datatypes): Add ADT_uns_mulv64_decl and ADT_uns_mulv128_decl. (uns_mulv64_decl): New macro. (uns_mulv128_decl): Likewise. * gcc-interface/trans.cc (gigi): Create the uns_mulv64_decl and uns_mulv128_decl declarations. (gnat_to_gnu) <N_Op_Add>: Perform an overflow check for unsigned integer addition, subtraction and multiplication if required. <N_Op_Minus>: Perform an overflow check for unsigned integer negation if required. (build_unary_op_trapv): Add support for unsigned types. (build_binary_op_trapv): Likewise. <MINUS_EXPR>: Perform the check if the LHS is zero in the signed case as well. Tested on x86_64-pc-linux-gnu, committed on master. --- gcc/ada/gcc-interface/gigi.h | 8 ++- gcc/ada/gcc-interface/trans.cc | 103 +++++++++++++++++++++++---------- 2 files changed, 79 insertions(+), 32 deletions(-) diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h index 0345111fb85f..45b1bfd23e3a 100644 --- a/gcc/ada/gcc-interface/gigi.h +++ b/gcc/ada/gcc-interface/gigi.h @@ -388,11 +388,13 @@ enum standard_datatypes /* Function declaration node for run-time reallocation function. */ ADT_realloc_decl, - /* Function decl node for 64-bit multiplication with overflow checking. */ + /* Function decl nodes for 64-bit multiplication with overflow checking. */ ADT_mulv64_decl, + ADT_uns_mulv64_decl, - /* Function decl node for 128-bit multiplication with overflow checking. */ + /* Function decl nodes for 128-bit multiplication with overflow checking. */ ADT_mulv128_decl, + ADT_uns_mulv128_decl, /* Identifier for the name of the _Parent field in tagged record types. */ ADT_parent_name_id, @@ -455,7 +457,9 @@ extern GTY(()) tree gnat_raise_decls_ext[(int) LAST_REASON_CODE + 1]; #define free_decl gnat_std_decls[(int) ADT_free_decl] #define realloc_decl gnat_std_decls[(int) ADT_realloc_decl] #define mulv64_decl gnat_std_decls[(int) ADT_mulv64_decl] +#define uns_mulv64_decl gnat_std_decls[(int) ADT_uns_mulv64_decl] #define mulv128_decl gnat_std_decls[(int) ADT_mulv128_decl] +#define uns_mulv128_decl gnat_std_decls[(int) ADT_uns_mulv128_decl] #define parent_name_id gnat_std_decls[(int) ADT_parent_name_id] #define not_handled_by_others_name_id \ gnat_std_decls[(int) ADT_not_handled_by_others_name_id] diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc index fd1d39cd0f55..3c6e87e52c0a 100644 --- a/gcc/ada/gcc-interface/trans.cc +++ b/gcc/ada/gcc-interface/trans.cc @@ -319,7 +319,7 @@ gigi (Node_Id gnat_root, { Node_Id gnat_iter; Entity_Id gnat_literal; - tree t, ftype, int64_type; + tree t, ftype; struct elab_info *info; int i; @@ -466,7 +466,7 @@ gigi (Node_Id gnat_root, false, NULL, Empty); /* This is used for 64-bit multiplication with overflow checking. */ - int64_type = gnat_type_for_size (64, 0); + tree int64_type = gnat_type_for_size (64, 0); mulv64_decl = create_subprog_decl (get_identifier ("__gnat_mulv64"), NULL_TREE, build_function_type_list (int64_type, int64_type, @@ -475,6 +475,15 @@ gigi (Node_Id gnat_root, false, NULL, Empty); strub_make_callable (mulv64_decl); + tree uint64_type = gnat_type_for_size (64, 1); + uns_mulv64_decl + = create_subprog_decl (get_identifier ("__gnat_uns_mulv64"), NULL_TREE, + build_function_type_list (uint64_type, uint64_type, + uint64_type, NULL_TREE), + NULL_TREE, is_default, true, true, true, false, + false, NULL, Empty); + strub_make_callable (uns_mulv64_decl); + if (Enable_128bit_Types) { tree int128_type = gnat_type_for_size (128, 0); @@ -487,6 +496,17 @@ gigi (Node_Id gnat_root, NULL_TREE, is_default, true, true, true, false, false, NULL, Empty); strub_make_callable (mulv128_decl); + + tree uint128_type = gnat_type_for_size (128, 1); + uns_mulv128_decl + = create_subprog_decl (get_identifier ("__gnat_uns_mulv128"), NULL_TREE, + build_function_type_list (uint128_type, + uint128_type, + uint128_type, + NULL_TREE), + NULL_TREE, is_default, true, true, true, false, + false, NULL, Empty); + strub_make_callable (uns_mulv128_decl); } /* Name of the _Parent field in tagged record types. */ @@ -7504,12 +7524,11 @@ gnat_to_gnu (Node_Id gnat_node) gnu_max_shift = convert (gnu_type, gnu_max_shift); } - /* For signed integer addition, subtraction and multiplication, do an + /* For integer addition, subtraction and multiplication, perform an overflow check if required. */ - if (Do_Overflow_Check (gnat_node) - && (code == PLUS_EXPR || code == MINUS_EXPR || code == MULT_EXPR) - && !TYPE_UNSIGNED (gnu_type) - && !FLOAT_TYPE_P (gnu_type)) + if ((code == PLUS_EXPR || code == MINUS_EXPR || code == MULT_EXPR) + && !FLOAT_TYPE_P (gnu_type) + && Do_Overflow_Check (gnat_node)) gnu_result = build_binary_op_trapv (code, gnu_type, gnu_lhs, gnu_rhs, gnat_node); @@ -7590,11 +7609,11 @@ gnat_to_gnu (Node_Id gnat_node) gnu_expr = gnat_to_gnu (Right_Opnd (gnat_node)); gnu_result_type = get_unpadded_type (Etype (gnat_node)); - /* For signed integer negation and absolute value, do an overflow check + /* For integer negation and absolute value, perform an overflow check if required. */ - if (Do_Overflow_Check (gnat_node) - && !TYPE_UNSIGNED (gnu_result_type) - && !FLOAT_TYPE_P (gnu_result_type)) + if ((gnu_codes[kind] == NEGATE_EXPR || gnu_codes[kind] == ABS_EXPR) + && !FLOAT_TYPE_P (gnu_result_type) + && Do_Overflow_Check (gnat_node)) gnu_result = build_unary_op_trapv (gnu_codes[kind], gnu_result_type, gnu_expr, gnat_node); @@ -9959,12 +9978,25 @@ build_unary_op_trapv (enum tree_code code, tree gnu_type, tree operand, { gcc_assert (code == NEGATE_EXPR || code == ABS_EXPR); + tree gnu_expr, check; + operand = gnat_protect_expr (operand); - return emit_check (build_binary_op (EQ_EXPR, boolean_type_node, - operand, TYPE_MIN_VALUE (gnu_type)), - build_unary_op (code, gnu_type, operand), - CE_Overflow_Check_Failed, gnat_node); + gnu_expr = build_unary_op (code, gnu_type, operand); + + if (TYPE_UNSIGNED (gnu_type)) + { + if (code == ABS_EXPR) + return gnu_expr; + else + check = build_binary_op (NE_EXPR, boolean_type_node, + operand, TYPE_MIN_VALUE (gnu_type)); + } + else + check = build_binary_op (EQ_EXPR, boolean_type_node, + operand, TYPE_MIN_VALUE (gnu_type)); + + return emit_check (check, gnu_expr, CE_Overflow_Check_Failed, gnat_node); } /* Make a binary operation of kind CODE using build_binary_op, but guard @@ -10017,21 +10049,29 @@ build_binary_op_trapv (enum tree_code code, tree gnu_type, tree left, /* Never inline a 64-bit mult for a 32-bit target, it's way too long. */ if (code == MULT_EXPR && precision == 64 && BITS_PER_WORD < 64) { - tree int64 = gnat_type_for_size (64, 0); + tree int64 = gnat_type_for_size (64, TYPE_UNSIGNED (gnu_type)); Check_Restriction_No_Dependence_On_System (Name_Arith_64, gnat_node); - return convert (gnu_type, build_call_n_expr (mulv64_decl, 2, - convert (int64, lhs), - convert (int64, rhs))); + return + convert (gnu_type, build_call_n_expr (TYPE_UNSIGNED (gnu_type) + ? uns_mulv64_decl + : mulv64_decl, + 2, + convert (int64, lhs), + convert (int64, rhs))); } /* Likewise for a 128-bit mult and a 64-bit target. */ else if (code == MULT_EXPR && precision == 128 && BITS_PER_WORD < 128) { - tree int128 = gnat_type_for_size (128, 0); + tree int128 = gnat_type_for_size (128, TYPE_UNSIGNED (gnu_type)); Check_Restriction_No_Dependence_On_System (Name_Arith_128, gnat_node); - return convert (gnu_type, build_call_n_expr (mulv128_decl, 2, - convert (int128, lhs), - convert (int128, rhs))); + return + convert (gnu_type, build_call_n_expr (TYPE_UNSIGNED (gnu_type) + ? uns_mulv128_decl + : mulv128_decl, + 2, + convert (int128, lhs), + convert (int128, rhs))); } enum internal_fn icode; @@ -10065,7 +10105,7 @@ build_binary_op_trapv (enum tree_code code, tree gnu_type, tree left, } /* If one operand is a constant, we expose the overflow condition to enable - a subsequent simplication or even elimination. */ + a subsequent simplification or even elimination. */ switch (code) { case PLUS_EXPR: @@ -10085,21 +10125,24 @@ build_binary_op_trapv (enum tree_code code, tree gnu_type, tree left, break; case MINUS_EXPR: - if (TREE_CODE (lhs) == INTEGER_CST) + if (TREE_CODE (lhs) == INTEGER_CST && TYPE_UNSIGNED (gnu_type)) + /* In the unsigned case, overflow when rhs > lhs - type_min. */ + check = build_binary_op (GT_EXPR, boolean_type_node, rhs, + build_binary_op (MINUS_EXPR, gnu_type, + lhs, type_min)); + else if (TREE_CODE (lhs) == INTEGER_CST) { sgn = tree_int_cst_sgn (lhs); - if (sgn > 0) - /* When lhs > 0, overflow when rhs < lhs - type_max. */ + if (sgn >= 0) + /* When lhs >= 0, overflow when rhs < lhs - type_max. */ check = build_binary_op (LT_EXPR, boolean_type_node, rhs, build_binary_op (MINUS_EXPR, gnu_type, lhs, type_max)); - else if (sgn < 0) + else /* When lhs < 0, overflow when rhs > lhs - type_min. */ check = build_binary_op (GT_EXPR, boolean_type_node, rhs, build_binary_op (MINUS_EXPR, gnu_type, lhs, type_min)); - else - return gnu_expr; } else { -- 2.43.0