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)

Reply via email to