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.