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

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

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Assignee|unassigned at gcc dot gnu.org      |rguenth at gcc dot 
gnu.org
             Status|NEW                         |ASSIGNED
                 CC|                            |jakub at gcc dot gnu.org,
                   |                            |jwakely at redhat dot com

--- Comment #10 from Richard Biener <rguenth at gcc dot gnu.org> ---
ISTR seeing this before.  We are quite confused by the standard library code
comparing the address of a string literal with the local buffer:

MEM[(char_type &)&D.42061 + 17] = 32;
if (&D.42061.D.33506._M_local_buf >= &MEM <const char[2]> [(void *)"_" + 1B])
  goto <bb 6>; [50.00%]
else
  goto <bb 7>; [50.00%]

if (&D.42061.D.33506._M_local_buf <= "_")
  goto <bb 8>; [50.00%]
else
  goto <bb 9>; [50.00%]

<bb 9> [local count: 21728216]:
_97 = &D.42061.D.33506._M_local_buf - "_";
if (_97 == 1)
  goto <bb 6>; [34.00%]
else
  goto <bb 10>; [66.00%]

and we are afraid of optimizing relational compares of distinct objects
(well, that's simply undefined and good QOI is to DWIM, simply leave the
broken code around if there's no good way to choose true or false).

This is all preceeded by an "overlap condition" working on integers
(so not undefined), so what might work is to aggressively simplify
relational compares of known distinct objects to __builtin_unreachable ()
(aka isolate the errorneous path).

<bb 2> [local count: 1073741824]:
MEM[(struct basic_string *)&D.42061] ={v} {CLOBBER};
MEM[(struct _Alloc_hider *)&D.42061] ={v} {CLOBBER};
MEM[(struct _Alloc_hider *)&D.42061]._M_p = &D.42061.D.33506._M_local_buf;
MEM[(char_type &)&D.42061 + 16] = 32;
D.42061._M_string_length = 1;
__x.25_69 = (long unsigned int) "_";
__y.26_70 = (long unsigned int) &D.42061.D.33506._M_local_buf;
if (__x.25_69 < __y.26_70)
  goto <bb 4>; [50.00%]
else
  goto <bb 3>; [50.00%]

<bb 3> [local count: 347651448]:
__x.25_72 = (long unsigned int) &MEM <char[16]> [(void *)&D.42061 + 17B];
if (__x.25_69 > __x.25_72)
  goto <bb 4>; [50.00%]
else
  goto <bb 5>; [50.00%]

Alternatively somehow re-combine the above overlap test and simplify
it statically.  We are getting into

Breakpoint 5, maybe_fold_and_comparisons (type=<boolean_type 0x7ffff68e2b28
bool>, code1=GE_EXPR, op1a=<ssa_name 0x7ffff4a88cf0 72>, op1b=<ssa_name
0x7ffff4a88c18 69>, code2=GE_EXPR, op2a=<ssa_name 0x7ffff4a88c18 69>,
op2b=<ssa_name 0x7ffff4a88c60 70>, outer_cond_bb=<basic_block 0x7ffff4d69548
(2)>)

we do have a patterns optimizing an overlap test (but not statically folding)
with

/* For pointers @0 and @2 and nonnegative constant offset @1, look for
   expressions like:

   A: (@0 + @1 < @2) | (@2 + @1 < @0)
   B: (@0 + @1 <= @2) | (@2 + @1 <= @0)
...

unfortunately simple matching in match.pd falls foul of the PR105142 fix
given _72 is computed in the inner block and thus
maybe_fold_comparisons_from_match_pd is not going to pick that up.
Without that fix

(for cmp1 (lt le le lt)
     cmp2 (lt le lt le)
(simplify
 (bit_and (cmp1:c (convert@4 @0) (convert @1)) (cmp2:c (convert@5 @2) (convert
@3)))
 (if (TREE_CODE (@0) == ADDR_EXPR
      && TREE_CODE (@1) == ADDR_EXPR
      && TREE_CODE (@2) == ADDR_EXPR
      && TREE_CODE (@3) == ADDR_EXPR
      && INTEGRAL_TYPE_P (TREE_TYPE (@4))
      && types_match (TREE_TYPE (@4), TREE_TYPE (@5)))
  (with { poly_int64 diff0, diff1; }
   (if (ptr_difference_const (@0, @3, &diff0)
        && ptr_difference_const (@1, @2, &diff1)
        && !ptr_derefs_may_alias_p (@0, @1))
    { constant_boolean_node (false, type); })))))

works to detect this for the case of invariant addresses which have the
offset included.  It would need to be extended for cases where the
increments are variable or the base address is not invariant (but common).

I'm going to improve the PR105142 fix.

Reply via email to