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

Richard Biener <rguenth at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
   Last reconfirmed|2025-05-19 00:00:00         |2025-07-07
     Ever confirmed|0                           |1
             Status|UNCONFIRMED                 |ASSIGNED
           Assignee|unassigned at gcc dot gnu.org      |rguenth at gcc dot 
gnu.org

--- Comment #31 from Richard Biener <rguenth at gcc dot gnu.org> ---
(In reply to Alexander Monakov from comment #28)
> Created attachment 61811 [details]
> standalone testcase
> 
> A standalone variant of the comment #22 testcase, preprocessed and with
> enough noipa stubs added to avoid linking with QtBase.

Thanks, this produces with -O2 -std=gnu++20

> ./a.out 
test2: 1 2 3 

while -O3 -std=gnu++20

> ./a.out 
test2: 1 2 3 18446744073709551615 

it also reproduces with -O3 -fno-tree-vectorize, the main difference seems
to be IPA and inline differences.  -fno-tree-pta fixes it.

There are exactly two(!) comparisons eliminated with the added path, the
2nd triggers the issue in VRP1:

Folding statement: if (e_137 != n_142)
 Registering value_relation (e_137 != n_142) on (33->35)
 Registering value_relation (e_137 == n_142) on (33->34)

Visiting conditional with predicate: if (e_137 != n_142)

With known ranges
        e_137: [prange] const char16_t * [1, +INF]      n_142: [prange] const
char16_t * VARYING

Predicate evaluates to: DON'T KNOW
***dbgcnt: lower limit 2 reached for prefetch.***
***dbgcnt: upper limit 2 reached for prefetch.***
gimple_simplified to if (1 != 0)
Folded into: if (1 != 0)


We have

  # PT = null
  e_137 = _130 + _136;
...
  # PT = nonlocal escaped null const-pool { D.189684 } (escaped)
  # USE = nonlocal escaped null const-pool { D.189684 } (escaped)
  n_142 = QtPrivate::qustrchr (D.206385, 46);
  D.206385 ={v} {CLOBBER(eos)};
  if (e_137 != n_142)

the interesting thing is that VRP computes

e_137  : [prange] const char16_t * [1, +INF]


VRP clears PT = null on the pointer and thus makes the compare compare
'nothing' with 'something'.  points-to computes

  # PT = null
  _130 = str.m_data;

the last initilizer is

  <bb 27> [local count: 1034442871]:
  _104 = state$start_100 + state$extra_101;
  MEM[(struct QChar *)&D.206374 clique 15 base 1] ={v} {CLOBBER(bob)};
  MEM[(struct QChar *)&D.206374 clique 15 base 1].ucs = 46;
  str = MEM[(const struct QStringView &)&tok2 + 32];

PTA has

tok2.128+192 = __old_val_8
tok2.128+192 = &NONLOCAL
tok2.128+192 = &NONLOCAL
tok2.128+192 = __old_val_8
str.0+64 = tok2.128+192
_130 = str.64+64

for some reason the

  str = MEM[(const struct QStringView &)&tok2 + 32];

assignment does not generate a

str.64+64 = tok2.192+64

constraint, that is, the source and dest varinfos do not seem to overlap.

We end up with

(gdb) p lhsc
$3 = {<vec<constraint_expr, va_heap, vl_ptr>> = {m_vec = 0x5219080 = {{
        type = SCALAR, var = 145, offset = 0}, {type = SCALAR, var = 146, 
        offset = 0}}}, <No data fields>}
(gdb) p rhsc
$6 = {<vec<constraint_expr, va_heap, vl_ptr>> = {m_vec = 0x5824f60 = {{
        type = SCALAR, var = 29, offset = 0}}}, <No data fields>}

where for the RHS that's the third var from 'tok2'.  Having the copy
offset by 32 is a bit odd sice that puts us inside the third subobject
that we have not sub-setted.

In any case the issue seems to be that do_structure_copy applies
the offset "twice" here, it does

      if (!get_ref_base_and_extent_hwi (lhsop, &lhsoffset, &lhssize, &reverse)
          || !get_ref_base_and_extent_hwi (rhsop, &rhsoffset, &rhssize,
                                           &reverse))
        {
          process_all_all_constraints (lhsc, rhsc);
          return;

computing 256 for rhsoffset (from the MEM_REF offset of 32 bytes) and
then checking overlap of two varinfos with

                  || ranges_overlap_p (lhsv->offset + rhsoffset, lhsv->size,
                                       rhsv->offset + lhsoffset, rhsv->size)))

the 2nd var of the LHS does not satisfy overlap.

I think the logic might only work when the offset computed by
get_ref_base_and_extent_hwi aligns with any of the fields offsets.

Reply via email to