https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121831

--- Comment #13 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
Untested fix for the ICE:

--- gcc/expr.cc.jj      2025-08-05 12:57:06.719031397 +0200
+++ gcc/expr.cc 2025-09-08 18:53:23.453223679 +0200
@@ -6533,6 +6533,31 @@ string_cst_read_str (void *data, void *,
   return c_readstr (TREE_STRING_POINTER (str) + offset, mode, false);
 }

+/* Helper function for store_expr storing of RAW_DATA_CST.  */
+
+static rtx
+raw_data_cst_read_str (void *data, void *, HOST_WIDE_INT offset,
+                      fixed_size_mode mode)
+{
+  tree cst = (tree) data;
+
+  gcc_assert (offset >= 0);
+  if (offset >= RAW_DATA_LENGTH (cst))
+    return const0_rtx;
+
+  if ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode)
+      > (unsigned HOST_WIDE_INT) RAW_DATA_LENGTH (cst))
+    {
+      char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode));
+      size_t l = RAW_DATA_LENGTH (cst) - offset;
+      memcpy (p, RAW_DATA_POINTER (cst) + offset, l);
+      memset (p + l, '\0', GET_MODE_SIZE (mode) - l);
+      return c_readstr (p, mode, false);
+    }
+
+  return c_readstr (RAW_DATA_POINTER (cst) + offset, mode, false);
+}
+
 /* Generate code for computing expression EXP,
    and storing the value into TARGET.

@@ -7630,7 +7655,7 @@ store_constructor (tree exp, rtx target,
     case ARRAY_TYPE:
       {
        tree value, index;
-       unsigned HOST_WIDE_INT i;
+       unsigned HOST_WIDE_INT i, j = 0;
        bool need_to_clear;
        tree domain;
        tree elttype = TREE_TYPE (type);
@@ -7692,6 +7717,8 @@ store_constructor (tree exp, rtx target,
                    this_node_count = (tree_to_uhwi (hi_index)
                                       - tree_to_uhwi (lo_index) + 1);
                  }
+               else if (TREE_CODE (value) == RAW_DATA_CST)
+                 this_node_count = RAW_DATA_LENGTH (value);
                else
                  this_node_count = 1;

@@ -7734,7 +7761,11 @@ store_constructor (tree exp, rtx target,
            rtx xtarget = target;

            if (cleared && initializer_zerop (value))
-             continue;
+             {
+               if (TREE_CODE (value) == RAW_DATA_CST)
+                 j += RAW_DATA_LENGTH (value) - 1;
+               continue;
+             }

            mode = TYPE_MODE (elttype);
            if (mode != BLKmode)
@@ -7750,6 +7781,8 @@ store_constructor (tree exp, rtx target,
                unsigned HOST_WIDE_INT lo, hi, count;
                tree offset;

+               gcc_assert (TREE_CODE (value) != RAW_DATA_CST);
+
                /* If the range is constant and "small", unroll the loop.  */
                if (const_bounds_p
                    && tree_fits_uhwi_p (lo_index)
@@ -7846,13 +7879,14 @@ store_constructor (tree exp, rtx target,
              {
                tree offset;

+               gcc_assert (TREE_CODE (value) != RAW_DATA_CST);
                if (index)
                  offset = fold_build2 (MINUS_EXPR,
                                        TREE_TYPE (index),
                                        index,
                                        TYPE_MIN_VALUE (domain));
                else
-                 offset = size_int (i);
+                 offset = size_int (i + j);

                offset = size_binop (MULT_EXPR,
                                     fold_convert (sizetype, offset),
@@ -7869,7 +7903,7 @@ store_constructor (tree exp, rtx target,
                  bitpos = ((tree_to_uhwi (index) - minelt)
                            * tree_to_uhwi (TYPE_SIZE (elttype)));
                else
-                 bitpos = (i * tree_to_uhwi (TYPE_SIZE (elttype)));
+                 bitpos = ((i + j) * tree_to_uhwi (TYPE_SIZE (elttype)));

                if (MEM_P (target) && !MEM_KEEP_ALIAS_SET_P (target)
                    && TREE_CODE (type) == ARRAY_TYPE
@@ -7878,10 +7912,50 @@ store_constructor (tree exp, rtx target,
                    target = copy_rtx (target);
                    MEM_KEEP_ALIAS_SET_P (target) = 1;
                  }
-               store_constructor_field (target, bitsize, bitpos, 0,
-                                        bitregion_end, mode, value,
-                                        cleared, get_alias_set (elttype),
-                                        reverse);
+               if (TREE_CODE (value) != RAW_DATA_CST)
+                 store_constructor_field (target, bitsize, bitpos, 0,
+                                          bitregion_end, mode, value,
+                                          cleared, get_alias_set (elttype),
+                                          reverse);
+               else
+                 {
+                   j += RAW_DATA_LENGTH (value) - 1;
+                   gcc_assert (known_eq (bitsize, BITS_PER_UNIT));
+                   rtx to_rtx = adjust_address (target, mode,
+                                                bitpos / BITS_PER_UNIT);
+
+                   if (to_rtx == target)
+                     to_rtx = copy_rtx (to_rtx);
+
+                   if (!MEM_KEEP_ALIAS_SET_P (to_rtx)
+                       && MEM_ALIAS_SET (to_rtx) != 0)
+                     set_mem_alias_set (to_rtx, get_alias_set (elttype));
+
+                   if (can_store_by_pieces (RAW_DATA_LENGTH (value),
+                                            raw_data_cst_read_str,
+                                            (void *) value,
+                                            MEM_ALIGN (target), false))
+                     {
+                       store_by_pieces (target, RAW_DATA_LENGTH (value),
+                                        raw_data_cst_read_str, (void *) value,
+                                        MEM_ALIGN (target), false,
+                                        RETURN_BEGIN);
+                       continue;
+                     }
+
+                   elttype
+                     = build_array_type_nelts (TREE_TYPE (value),
+                                               RAW_DATA_LENGTH (value));
+                   tree ctor = build_constructor_single (elttype, NULL_TREE,
+                                                         value);
+                   ctor = tree_output_constant_def (ctor);
+                   mode = TYPE_MODE (type);
+                   store_constructor_field (target,
+                                            bitsize * RAW_DATA_LENGTH (value),
+                                            bitpos, 0, bitregion_end, mode,
+                                            ctor, cleared,
+                                            get_alias_set (elttype), reverse);
+                 }
              }
          }
        break;

need to test it more tomorrow (both the store_by_pieces path and the other
one).
That said, besides the no limit case (or perhaps better adding extra
argument(s) to
expand_constructor/store_constructor/store_constructor_field to be able to use
larger CONSTRUCTOR parts from the existing variable instead of emitting it into
memory separately) I'm wondering about
                if (TREE_CODE (value) == CONSTRUCTOR)
                  {
                    /* If VALUE is a CONSTRUCTOR, this optimization is only
                       useful if this doesn't store the CONSTRUCTOR into
                       memory.  If it does, it is more efficient to just
                       load the data from the array directly.  */
                    rtx ret = expand_constructor (value, target,
                                                  modifier, true);
                    if (ret == NULL_RTX)
                      value = NULL_TREE;
                  }

                if (value)
                  return expand_expr (value, target, tmode, modifier);
and
                      if (TREE_CODE (value) == CONSTRUCTOR)
                        {
                          /* If VALUE is a CONSTRUCTOR, this
                             optimization is only useful if
                             this doesn't store the CONSTRUCTOR
                             into memory.  If it does, it is more
                             efficient to just load the data from
                             the array directly.  */
                          rtx ret = expand_constructor (value, target,
                                                        modifier, true);
                          if (ret == NULL_RTX)
                            break;
                        }

                      return expand_expr (fold (value), target, tmode,
                                          modifier);
In my understanding, if expand_constructor returns non-NULL, it has already
stored value into target, so the expand_expr after it stores it there the
second time.

Reply via email to