https://gcc.gnu.org/g:18cdf562ea2ae6b43df502e5ebb043f40d531884
commit 18cdf562ea2ae6b43df502e5ebb043f40d531884 Author: Alexandre Oliva <ol...@adacore.com> Date: Mon Jul 1 22:17:45 2024 -0300 UI_To_gnu: cope with per-target precision limits Avoid exceeding the maximum precision for wide ints, and for available int modes, when selecting a type to represent very wide constants, falling back to 0/0 for unrepresentable fractions. for gcc/ada/ChangeLog * gcc-interface/cuintp.cc (UI_To_gnu): Don't exceed available integral mode widths. Fail if the constant exceeds the representable numbers. * gcc-interface/decl.cc (gnat_to_gnu_entity): Recognize the failure mode and fall back to an indeterminate fraction. Diff: --- gcc/ada/gcc-interface/cuintp.cc | 40 ++++++++++++++++++++++++++++------------ gcc/ada/gcc-interface/decl.cc | 4 ++++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/gcc/ada/gcc-interface/cuintp.cc b/gcc/ada/gcc-interface/cuintp.cc index ad345096282..6a03131144b 100644 --- a/gcc/ada/gcc-interface/cuintp.cc +++ b/gcc/ada/gcc-interface/cuintp.cc @@ -69,7 +69,8 @@ build_cst_from_int (tree type, HOST_WIDE_INT low) depending on whether TYPE is an integral or real type. Overflow is tested by the constant-folding used to build the node. TYPE is the GCC type of the resulting node. If TYPE is NULL, an unsigned integer type wide enough - to hold the entire constant is selected. */ + to hold the entire constant is selected, and if no such type exists, + return NULL_TREE. */ tree UI_To_gnu (Uint Input, tree type) @@ -79,7 +80,7 @@ UI_To_gnu (Uint Input, tree type) any such possible value for intermediate computations and then rely on a conversion back to TYPE to perform the bias adjustment when need be. */ tree comp_type - = (!type ? gnat_type_for_size (32, 0) + = (!type ? gnat_type_for_size (32, 1) : (TREE_CODE (type) == INTEGER_TYPE && TYPE_BIASED_REPRESENTATION_P (type)) ? get_base_type (type) : type); @@ -96,6 +97,10 @@ UI_To_gnu (Uint Input, tree type) tree gnu_base; gcc_assert (Length > 0); + /* The extension of unsigned types we use to try to fit the + constant only works if we're dealing with nonnegative + constants, but that's what we expect when !TYPE. */ + gcc_assert (type || First >= 0); /* The computations we perform below always require a type at least as large as an integer not to overflow. FP types are always fine, but @@ -104,9 +109,6 @@ UI_To_gnu (Uint Input, tree type) convert the final result back to the incoming type later on. */ if (!SCALAR_FLOAT_TYPE_P (comp_type) && TYPE_PRECISION (comp_type) < 32) comp_type = gnat_type_for_size (32, 0); - else if (!type && TYPE_UNSIGNED (comp_type)) - /* Choose a signed type, so that we can detect overflow. */ - comp_type = make_signed_type (TYPE_PRECISION (comp_type)); gnu_base = build_cst_from_int (comp_type, Base); @@ -114,24 +116,38 @@ UI_To_gnu (Uint Input, tree type) for (Idx++, Length--; Length; Idx++, Length--) for (;;) { - tree next_ret = fold_build2 (code, comp_type, - fold_build2 (MULT_EXPR, comp_type, - gnu_ret, gnu_base), - build_cst_from_int - (comp_type, (*Udigits_Ptr)[Idx])); + tree elt, scaled, next_ret; + elt = build_cst_from_int (comp_type, (*Udigits_Ptr)[Idx]); + if (!type) + { + scaled = int_const_binop (MULT_EXPR, gnu_ret, gnu_base, -1); + next_ret = int_const_binop (code, scaled, elt, -1); + } + else + { + scaled = fold_build2 (MULT_EXPR, comp_type, gnu_ret, gnu_base); + next_ret = fold_build2 (code, comp_type, scaled, elt); + } if (!TREE_OVERFLOW (next_ret) || type) { gnu_ret = next_ret; break; } - comp_type = make_signed_type (TYPE_PRECISION (comp_type) * 2); + opt_scalar_int_mode wider_mode + = GET_MODE_WIDER_MODE (SCALAR_INT_TYPE_MODE + (comp_type)).require (); + if (!wider_mode.exists ()) + /* Signal that we couldn't represent the value. */ + return NULL_TREE; + comp_type = make_unsigned_type (GET_MODE_BITSIZE + (wider_mode.require ())); gnu_base = convert (comp_type, gnu_base); gnu_ret = convert (comp_type, gnu_ret); } } if (!type) - type = make_unsigned_type (TYPE_PRECISION (comp_type)); + type = comp_type; gnu_ret = convert (type, gnu_ret); /* We don't need any NOP_EXPR or NON_LVALUE_EXPR on GNU_RET. */ diff --git a/gcc/ada/gcc-interface/decl.cc b/gcc/ada/gcc-interface/decl.cc index 80dd6034a01..d7c17238bbc 100644 --- a/gcc/ada/gcc-interface/decl.cc +++ b/gcc/ada/gcc-interface/decl.cc @@ -1774,6 +1774,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition) const Uint gnat_den = Norm_Den (gnat_small_value); tree gnu_num = UI_To_gnu (gnat_num, NULL_TREE); tree gnu_den = UI_To_gnu (gnat_den, NULL_TREE); + + if (!gnu_num || !gnu_den) + gnu_num = gnu_den = integer_zero_node; + tree gnu_num_type = TREE_TYPE (gnu_num); tree gnu_den_type = TREE_TYPE (gnu_den); tree gnu_small_type = (TYPE_PRECISION (gnu_num_type)