]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
Fix assertion failure on small array constructor
authorEric Botcazou <ebotcazou@adacore.com>
Fri, 6 Jun 2025 09:32:51 +0000 (11:32 +0200)
committerEric Botcazou <ebotcazou@adacore.com>
Fri, 6 Jun 2025 09:39:40 +0000 (11:39 +0200)
The Ada testcase triggers an assertion failure in size_binop_loc:

+===========================GNAT BUG DETECTED==============================+
| 16.0.0 20250605 (experimental) (x86_64-suse-linux) GCC error:            |
| in size_binop_loc, at fold-const.cc:2091                                 |
| Error detected around aggr7.ads:9:36

  gcc_assert (int_binop_types_match_p (code, TREE_TYPE (arg0),
                                       TREE_TYPE (arg1)));

because the very old code for ARRAY_TYPE in store_constructor is confused in
the case where it cannot perform static host-based arithmetics on offsets.

But the root cause is that it performs all the calculations in signed
sizetype while TYPE_DOMAIN is supposed to be a subtype of (unsigned)
sizetype, even for signed index types in Ada like in the testcase,
so the code takes the dynamic path instead of the static one for
negative indices.

gcc/
* expr.cc (store_constructor) <ARRAY_TYPE>: Perform the arithmetics
on offsets in (unsigned) sizetype.

gcc/testsuite/
* gnat.dg/specs/aggr7.ads: New test.

gcc/expr.cc
gcc/testsuite/gnat.dg/specs/aggr7.ads [new file with mode: 0644]

index 1eeefa1cadc08896c0d8d925a74e081c7cfae918..b3b46a266268e79567855442eaa8c8e1ce319fe1 100644 (file)
@@ -7631,8 +7631,8 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
        tree domain;
        tree elttype = TREE_TYPE (type);
        bool const_bounds_p;
-       HOST_WIDE_INT minelt = 0;
-       HOST_WIDE_INT maxelt = 0;
+       unsigned HOST_WIDE_INT minelt = 0;
+       unsigned HOST_WIDE_INT maxelt = 0;
 
        /* The storage order is specified for every aggregate type.  */
        reverse = TYPE_REVERSE_STORAGE_ORDER (type);
@@ -7640,14 +7640,14 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
        domain = TYPE_DOMAIN (type);
        const_bounds_p = (TYPE_MIN_VALUE (domain)
                          && TYPE_MAX_VALUE (domain)
-                         && tree_fits_shwi_p (TYPE_MIN_VALUE (domain))
-                         && tree_fits_shwi_p (TYPE_MAX_VALUE (domain)));
+                         && tree_fits_uhwi_p (TYPE_MIN_VALUE (domain))
+                         && tree_fits_uhwi_p (TYPE_MAX_VALUE (domain)));
 
        /* If we have constant bounds for the range of the type, get them.  */
        if (const_bounds_p)
          {
-           minelt = tree_to_shwi (TYPE_MIN_VALUE (domain));
-           maxelt = tree_to_shwi (TYPE_MAX_VALUE (domain));
+           minelt = tree_to_uhwi (TYPE_MIN_VALUE (domain));
+           maxelt = tree_to_uhwi (TYPE_MAX_VALUE (domain));
          }
 
        /* If the constructor has fewer elements than the array, clear
@@ -7660,7 +7660,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
        else
          {
            unsigned HOST_WIDE_INT idx;
-           HOST_WIDE_INT count = 0, zero_count = 0;
+           unsigned HOST_WIDE_INT count = 0, zero_count = 0;
            need_to_clear = ! const_bounds_p;
 
            /* This loop is a more accurate version of the loop in
@@ -7668,7 +7668,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
               is also needed to check for missing elements.  */
            FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (exp), idx, index, value)
              {
-               HOST_WIDE_INT this_node_count;
+               unsigned HOST_WIDE_INT this_node_count;
 
                if (need_to_clear)
                  break;
@@ -7742,16 +7742,16 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
              {
                tree lo_index = TREE_OPERAND (index, 0);
                tree hi_index = TREE_OPERAND (index, 1);
-               rtx index_r, pos_rtx;
-               HOST_WIDE_INT lo, hi, count;
-               tree position;
+               rtx index_r;
+               unsigned HOST_WIDE_INT lo, hi, count;
+               tree offset;
 
                /* If the range is constant and "small", unroll the loop.  */
                if (const_bounds_p
-                   && tree_fits_shwi_p (lo_index)
-                   && tree_fits_shwi_p (hi_index)
-                   && (lo = tree_to_shwi (lo_index),
-                       hi = tree_to_shwi (hi_index),
+                   && tree_fits_uhwi_p (lo_index)
+                   && tree_fits_uhwi_p (hi_index)
+                   && (lo = tree_to_uhwi (lo_index),
+                       hi = tree_to_uhwi (hi_index),
                        count = hi - lo + 1,
                        (!MEM_P (target)
                         || count <= 2
@@ -7762,7 +7762,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
                    lo -= minelt;  hi -= minelt;
                    for (; lo <= hi; lo++)
                      {
-                       bitpos = lo * tree_to_shwi (TYPE_SIZE (elttype));
+                       bitpos = lo * tree_to_uhwi (TYPE_SIZE (elttype));
 
                        if (MEM_P (target)
                            && !MEM_KEEP_ALIAS_SET_P (target)
@@ -7798,21 +7798,18 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
                    emit_label (loop_start);
 
                    /* Assign value to element index.  */
-                   position =
-                     fold_convert (ssizetype,
-                                   fold_build2 (MINUS_EXPR,
-                                                TREE_TYPE (index),
-                                                index,
-                                                TYPE_MIN_VALUE (domain)));
-
-                   position =
-                       size_binop (MULT_EXPR, position,
-                                   fold_convert (ssizetype,
-                                                 TYPE_SIZE_UNIT (elttype)));
-
-                   pos_rtx = expand_normal (position);
-                   xtarget = offset_address (target, pos_rtx,
-                                             highest_pow2_factor (position));
+                   offset = fold_build2 (MINUS_EXPR,
+                                         TREE_TYPE (index),
+                                         index,
+                                         TYPE_MIN_VALUE (domain));
+
+                   offset = size_binop (MULT_EXPR,
+                                        fold_convert (sizetype, offset),
+                                        TYPE_SIZE_UNIT (elttype));
+
+                   xtarget = offset_address (target,
+                                             expand_normal (offset),
+                                             highest_pow2_factor (offset));
                    xtarget = adjust_address (xtarget, mode, 0);
                    if (TREE_CODE (value) == CONSTRUCTOR)
                      store_constructor (value, xtarget, cleared,
@@ -7840,35 +7837,32 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
                    emit_label (loop_end);
                  }
              }
-           else if ((index != 0 && ! tree_fits_shwi_p (index))
-                    || ! tree_fits_uhwi_p (TYPE_SIZE (elttype)))
+           else if ((index && !tree_fits_uhwi_p (index))
+                    || !tree_fits_uhwi_p (TYPE_SIZE (elttype)))
              {
-               tree position;
-
-               if (index == 0)
-                 index = ssize_int (1);
-
-               if (minelt)
-                 index = fold_convert (ssizetype,
-                                       fold_build2 (MINUS_EXPR,
-                                                    TREE_TYPE (index),
-                                                    index,
-                                                    TYPE_MIN_VALUE (domain)));
-
-               position =
-                 size_binop (MULT_EXPR, index,
-                             fold_convert (ssizetype,
-                                           TYPE_SIZE_UNIT (elttype)));
+               tree offset;
+
+               if (index)
+                 offset = fold_build2 (MINUS_EXPR,
+                                       TREE_TYPE (index),
+                                       index,
+                                       TYPE_MIN_VALUE (domain));
+               else
+                 offset = size_int (i);
+
+               offset = size_binop (MULT_EXPR,
+                                    fold_convert (sizetype, offset),
+                                    TYPE_SIZE_UNIT (elttype));
                xtarget = offset_address (target,
-                                         expand_normal (position),
-                                         highest_pow2_factor (position));
+                                         expand_normal (offset),
+                                         highest_pow2_factor (offset));
                xtarget = adjust_address (xtarget, mode, 0);
                store_expr (value, xtarget, 0, false, reverse);
              }
            else
              {
-               if (index != 0)
-                 bitpos = ((tree_to_shwi (index) - minelt)
+               if (index)
+                 bitpos = ((tree_to_uhwi (index) - minelt)
                            * tree_to_uhwi (TYPE_SIZE (elttype)));
                else
                  bitpos = (i * tree_to_uhwi (TYPE_SIZE (elttype)));
diff --git a/gcc/testsuite/gnat.dg/specs/aggr7.ads b/gcc/testsuite/gnat.dg/specs/aggr7.ads
new file mode 100644 (file)
index 0000000..06980b3
--- /dev/null
@@ -0,0 +1,11 @@
+-- { dg-do compile }
+
+package Aggr7 is
+
+  type Arr is array (Integer range <>) of Boolean;
+
+  Data : constant Arr := (False, True);
+
+  function Get_Data return Arr is (Data);
+
+end Aggr7;