Hi!
When writing the PR127685 fix/workaround, I've noticed the comment
about RAW_DATA_CST and decided to implement it. WHen playing with
testcases, I've noticed it doesn't handle even more important case,
STRING_CST.
RAW_DATA_CST is less important because it usually appears only for
larger chunks, CPP_EMBED should usually appear for 64+ bytes in
the #embed directive and being turned into RAW_DATA_CST, similarly the
optimizations to turn large array initializers into RAW_DATA_CST usually
need 64+ bytes or more. Sure, e.g. C designated initializers then can
break it into smaller pieces, down to even 2 bytes in it, but
the vrp-cstload-limit param has 255 as the upper limit (why?) and
checks the whole size of the corresponding complete object, not even
its subobject, so to handle RAW_DATA_CST, one needs to bump the limit I
think.
On the other side, the C/C++ braced_list_to_string optimization can
turn initializers like {,un}signed char xyz[] = { 1, 2, 3 };
into = "\1\2\3", even for much smaller sizes.
Anyway, both of these IMHO need to be handled inside of
accumulate_range_from_array_ref, because that is where we know the
indexes, can check if a specific byte in those intersects the index range
and in that case, we don't need to build_int_cst just to throw it away
and can just create a wide_int and union that. In both of these cases
we can do this only for the end of the component path and have to verify
m_type is integral and with CHAR_BIT precision. It can be either
signed or unsigned, we need to either sign or zero extend the host byte
from STRING_CST or RAW_DATA_CST when creating the wide_int.
Or shall I instead of the intersects_p (idx_r, next, next) and
intersects_p (idx_r, lo, lo) checks call idx_r.contains_p (next)
and idx_r.contains (lo)? And/or change the intersects_p function to
optimize for the common case, so if (lo == hi) return r.contains (lo);
first before doing it the slower way?
Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
2026-10-15 Jakub Jelinek <[email protected]>
PR tree-optimization/127879
* gimple-range-fold.cc (ctor_ref_range::accumulate_range): Remove
comment about RAW_DATA_CST. Allow also STRING_CST, not just
CONSTRUCTOR.
(ctor_ref_range::accumulate_range_from_component_ref): Punt if
init is not a CONSTRUCTOR.
(ctor_ref_range::accumulate_range_from_array_ref): Handle
init being a STRING_CST. Handle RAW_DATA_CSTs inside of a
CONSTRUCTOR.
(fold_using_range::range_from_readonly_var): Allow ctor being
a STRING_CST, rather than only a CONSTRUCTOR.
* gcc.dg/tree-ssa/vrp-from-cst-agg-14.c: New test.
* gcc.dg/tree-ssa/vrp-from-cst-agg-15.c: New test.
* gcc.dg/tree-ssa/vrp-from-cst-agg-16.c: New test.
* gcc.dg/tree-ssa/vrp-from-cst-agg-17.c: New test.
* gcc.dg/tree-ssa/vrp-from-cst-agg-18.c: New test.
* gcc.dg/tree-ssa/vrp-from-cst-agg-19.c: New test.
--- a/gcc/gimple-range-fold.cc 2026-10-13 08:39:10.033278759 +0200
+++ b/gcc/gimple-range-fold.cc 2026-10-14 10:20:24.476947435 +0200
@@ -1041,8 +1041,7 @@ ctor_ref_range::accumulate_range (tree i
{
if (i == m_component_path.length ())
return accumulate_range_from_scalar (init);
- /* TODO: Perhaps handle RAW_DATA_CST too. */
- if (TREE_CODE (init) != CONSTRUCTOR)
+ if (TREE_CODE (init) != CONSTRUCTOR && TREE_CODE (init) != STRING_CST)
return false;
tree ref = m_component_path[i];
@@ -1112,6 +1111,8 @@ ctor_ref_range::accumulate_range_from_co
{
unsigned ix;
tree index, val;
+ if (TREE_CODE (init) != CONSTRUCTOR)
+ return false;
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), ix, index, val)
{
if (index != fld)
@@ -1182,6 +1183,29 @@ ctor_ref_range::accumulate_range_from_ar
unsigned ix;
tree index, val;
+ if (TREE_CODE (init) == STRING_CST)
+ {
+ if (i != m_component_path.length ()
+ || !INTEGRAL_TYPE_P (m_type)
+ || TYPE_PRECISION (m_type) != CHAR_BIT
+ || !useless_type_conversion_p (m_type, TREE_TYPE (TREE_TYPE (init)))
+ || wi::gtu_p (max + 1 - min, TREE_STRING_LENGTH (init)))
+ return false;
+ for (int n = 0; wi::leu_p (next, max); ++n, next = next + 1)
+ if (intersects_p (idx_r, next, next))
+ {
+ wide_int wi_cst;
+ if (TYPE_UNSIGNED (m_type))
+ wi_cst = wi::uhwi ((unsigned char) TREE_STRING_POINTER (init)[n],
+ CHAR_BIT);
+ else
+ wi_cst = wi::shwi ((signed char) TREE_STRING_POINTER (init)[n],
+ CHAR_BIT);
+ m_r.union_ (int_range<1> (m_type, wi_cst, wi_cst));
+ }
+ return true;
+ }
+
// Build a range with the entire domain, and take out any elements which are
// initialized. If there's anything left in that range, it means there are
// missing elements and we should add a [0, 0] to the final range.
@@ -1208,7 +1232,34 @@ ctor_ref_range::accumulate_range_from_ar
missing.intersect (int_range<2> (type, lo, hi, VR_ANTI_RANGE));
next = wi::add (hi, 1);
- if (intersects_p (idx_r, lo, hi) && !accumulate_range (val, i))
+ if (!intersects_p (idx_r, lo, hi))
+ continue;
+
+ if (TREE_CODE (val) == RAW_DATA_CST)
+ {
+ if (i != m_component_path.length ()
+ || !INTEGRAL_TYPE_P (m_type)
+ || TYPE_PRECISION (m_type) != CHAR_BIT
+ || !useless_type_conversion_p (m_type,
+ TREE_TYPE (val)))
+ return false;
+
+ for (int n = 0; wi::leu_p (lo, hi); ++n, lo = lo + 1)
+ if (intersects_p (idx_r, lo, lo))
+ {
+ wide_int wi_cst;
+ if (TYPE_UNSIGNED (m_type))
+ wi_cst = wi::uhwi (RAW_DATA_UCHAR_ELT (val, n),
+ CHAR_BIT);
+ else
+ wi_cst = wi::shwi (RAW_DATA_SCHAR_ELT (val, n),
+ CHAR_BIT);
+ m_r.union_ (int_range<1> (m_type, wi_cst, wi_cst));
+ }
+ continue;
+ }
+
+ if (!accumulate_range (val, i))
return false;
}
@@ -1278,7 +1329,8 @@ fold_using_range::range_from_readonly_va
the right part of the constructor then. */
tree ctor = ctor_for_folding (t);
if (!ctor
- || TREE_CODE (ctor) != CONSTRUCTOR)
+ || (TREE_CODE (ctor) != CONSTRUCTOR
+ && TREE_CODE (ctor) != STRING_CST))
return false;
value_range tmp (type);
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-14.c 2026-10-14
10:36:44.663663527 +0200
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-14.c 2026-10-14
10:43:14.877374484 +0200
@@ -0,0 +1,65 @@
+/* PR tree-optimization/127879 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized --param vrp-cstload-limit=255" } */
+/* { dg-final { scan-tree-dump-times "PHI <(?:-1\\\(\[0-9]*\\\),
1|1\\\(\[0-9]*\\\), -1)\\\(\[0-9]*\\\)>" 4 "optimized" } } */
+/* { dg-final { scan-tree-dump-not " = \[abc]\\\[" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " = d.b\\\[" "optimized" } } */
+
+const unsigned char a[] = { 100, 108, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
0, 24, 18, 35, 98 };
+const unsigned char b[] = { 100, 108, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 0, 24, 18, 35, 98 };
+const struct { int a; unsigned char b; } c[] = { { 0, 100 }, { 0, 108 }, { 0,
48 }, { 0, 49 }, { 0, 50 }, { 0, 51 },
+ { 0, 52 }, { 0, 53 }, { 0, 54
}, { 0, 55 }, { 0, 56 }, { 0, 57 },
+ { 0, 0 }, { 0, 24 }, { 0, 18
}, { 0, 35 }, { 0, 98 } };
+const struct { int a; unsigned char b[]; } d = { 0, { 100, 108, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57, 0, 24, 18, 35, 98 } };
+
+int
+foo (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (a[x] >= 48 && a[x] <= 57)
+ return 1;
+ return 0;
+}
+
+int
+bar (int x)
+{
+ if (x < 2 || x >= 220)
+ return -1;
+ if (b[x] >= 48 && b[x] <= 57)
+ return 1;
+ return 0;
+}
+
+int
+baz (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (c[x].b >= 48 && c[x].b <= 57)
+ return 1;
+ return 0;
+}
+
+int
+qux (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (d.b[x] >= 48 && d.b[x] <= 57)
+ return 1;
+ return 0;
+}
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-15.c 2026-10-14
10:44:04.801697802 +0200
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-15.c 2026-10-14
10:46:12.626965130 +0200
@@ -0,0 +1,29 @@
+/* PR tree-optimization/127879 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fexec-charset=UTF-8" } */
+/* { dg-final { scan-tree-dump-times "PHI <(?:-1\\\(\[0-9]*\\\),
1|1\\\(\[0-9]*\\\), -1)\\\(\[0-9]*\\\)>" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-not " = a\\\[" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " = b.b\\\[" "optimized" } } */
+
+const unsigned char a[] = " !0123456789\0{}~";
+const struct { int a; unsigned char b[]; } b = { 0, " !0123456789\0{}~" };
+
+int
+foo (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (a[x] >= '0' && a[x] <= '9')
+ return 1;
+ return 0;
+}
+
+int
+bar (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (b.b[x] >= '0' && b.b[x] <= '9')
+ return 1;
+ return 0;
+}
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-16.c 2026-10-14
10:58:17.356141325 +0200
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-16.c 2026-10-14
11:01:27.370565646 +0200
@@ -0,0 +1,29 @@
+/* PR tree-optimization/127879 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "PHI <(?:-1\\\(\[0-9]*\\\),
1|1\\\(\[0-9]*\\\), -1)\\\(\[0-9]*\\\)>" 2 "optimized" } } */
+/* { dg-final { scan-tree-dump-not " = a\\\[" "optimized" } } */
+/* { dg-final { scan-tree-dump-not " = b.b\\\[" "optimized" } } */
+
+const signed char a[] = { 28, -36, -2, -1, 2, 4, -3, -4, 1, 3, 0, 5, -37, 29 };
+const struct { int a; signed char b[]; } b = { 0, { 28, -36, -2, -1, 2, 4, -3,
-4, 1, 3, 0, 5, -37, 29 } };
+
+int
+foo (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (a[x] >= -4 && a[x] <= 5)
+ return 1;
+ return 0;
+}
+
+int
+bar (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (b.b[x] >= -4 && b.b[x] <= 5)
+ return 1;
+ return 0;
+}
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-17.c 2026-10-14
11:02:04.307065113 +0200
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-17.c 2026-10-14
11:03:26.765947833 +0200
@@ -0,0 +1,66 @@
+/* PR tree-optimization/127879 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized --param vrp-cstload-limit=255" } */
+/* { dg-final { scan-tree-dump " = a\\\[" "optimized" } } */
+/* { dg-final { scan-tree-dump " = b\\\[" "optimized" } } */
+/* { dg-final { scan-tree-dump " = c\\\[" "optimized" } } */
+/* { dg-final { scan-tree-dump " = d.b\\\[" "optimized" } } */
+
+const unsigned char a[] = { 100, 108, 48, 49, 50, 51, 52, 53, 58, 55, 56, 57,
0, 24, 18, 35, 98 };
+const unsigned char b[] = { 100, 108, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 47, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 49, 50,
51, 52, 53, 54, 55, 56, 57,
+ 0, 24, 18, 35, 98 };
+const struct { int a; unsigned char b; } c[] = { { 0, 100 }, { 0, 108 }, { 0,
48 }, { 0, 49 }, { 0, 50 }, { 0, 51 },
+ { 0, 52 }, { 0, 58 }, { 0, 54
}, { 0, 55 }, { 0, 56 }, { 0, 57 },
+ { 0, 0 }, { 0, 24 }, { 0, 18
}, { 0, 35 }, { 0, 98 } };
+const struct { int a; unsigned char b[]; } d = { 0, { 100, 108, 48, 49, 50,
51, 47, 53, 54, 55, 56, 57, 0, 24, 18, 35, 98 } };
+
+int
+foo (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (a[x] >= 48 && a[x] <= 57)
+ return 1;
+ return 0;
+}
+
+int
+bar (int x)
+{
+ if (x < 2 || x >= 220)
+ return -1;
+ if (b[x] >= 48 && b[x] <= 57)
+ return 1;
+ return 0;
+}
+
+int
+baz (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (c[x].b >= 48 && c[x].b <= 57)
+ return 1;
+ return 0;
+}
+
+int
+qux (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (d.b[x] >= 48 && d.b[x] <= 57)
+ return 1;
+ return 0;
+}
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-18.c 2026-10-14
11:03:46.323682837 +0200
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-18.c 2026-10-14
11:04:14.952294928 +0200
@@ -0,0 +1,28 @@
+/* PR tree-optimization/127879 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized -fexec-charset=UTF-8" } */
+/* { dg-final { scan-tree-dump " = a\\\[" "optimized" } } */
+/* { dg-final { scan-tree-dump " = b.b\\\[" "optimized" } } */
+
+const unsigned char a[] = " !012345+789\0{}~";
+const struct { int a; unsigned char b[]; } b = { 0, " !01234567+9\0{}~" };
+
+int
+foo (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (a[x] >= '0' && a[x] <= '9')
+ return 1;
+ return 0;
+}
+
+int
+bar (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (b.b[x] >= '0' && b.b[x] <= '9')
+ return 1;
+ return 0;
+}
--- a/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-19.c 2026-10-14
11:04:26.179142809 +0200
+++ b/gcc/testsuite/gcc.dg/tree-ssa/vrp-from-cst-agg-19.c 2026-10-14
11:04:45.909875465 +0200
@@ -0,0 +1,28 @@
+/* PR tree-optimization/127879 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump " = a\\\[" "optimized" } } */
+/* { dg-final { scan-tree-dump " = b.b\\\[" "optimized" } } */
+
+const signed char a[] = { 28, -36, -2, -1, 2, 4, -3, -4, 1, 3, 0, -5, -37, 29
};
+const struct { int a; signed char b[]; } b = { 0, { 28, -36, -2, -1, 2, 4, -3,
-4, 1, 3, 0, -5, -37, 29 } };
+
+int
+foo (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (a[x] >= -4 && a[x] <= 5)
+ return 1;
+ return 0;
+}
+
+int
+bar (int x)
+{
+ if (x < 2 || x >= 12)
+ return -1;
+ if (b.b[x] >= -4 && b.b[x] <= 5)
+ return 1;
+ return 0;
+}
Jakub