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

--- Comment #4 from Tom de Vries <vries at gcc dot gnu.org> ---
Looking at the x86_64 example, the difference between the signed and unsigned
case happens here in split_constant_offset_1:
...
    CASE_CONVERT:
      {
        /* We must not introduce undefined overflow, and we must not change the
           value.
           Hence we're okay if the inner type doesn't overflow to start with    
           (pointer or signed), the outer type also is an integer or pointer    
           and the outer precision is at least as large as the inner.  */
        tree itype = TREE_TYPE (op0);
        if ((POINTER_TYPE_P (itype)
             || (INTEGRAL_TYPE_P (itype) && TYPE_OVERFLOW_UNDEFINED (itype)))
            && TYPE_PRECISION (type) >= TYPE_PRECISION (itype)
            && (POINTER_TYPE_P (type) || INTEGRAL_TYPE_P (type)))
          {
            split_constant_offset (op0, &var0, off);
            *var = fold_convert (type, var0);
            return true;
          }
        return false;
      }
...

For the unsigned case, we're handling:
...
(gdb) call debug_generic_expr (exp)
(sizetype) _1
...

more in detail:
...
(gdb) call debug_tree (exp)
 <nop_expr 0x7ffff66fae60
    type <integer_type 0x7ffff65c8000 sizetype public unsigned DI
        size <integer_cst 0x7ffff65b0cd8 constant 64>
        unit size <integer_cst 0x7ffff65b0cf0 constant 8>
        align 64 symtab 0 alias set -1 canonical type 0x7ffff65c8000
        precision 64 min <integer_cst 0x7ffff65b0d08 0>
        max <integer_cst 0x7ffff65b24c0 18446744073709551615>>

    arg 0 <ssa_name 0x7ffff65bb948
        type <integer_type 0x7ffff65c8690 unsigned int sizes-gimplified
            public unsigned SI
            size <integer_cst 0x7ffff65b0f18 constant 32>
            unit size <integer_cst 0x7ffff65b0f30 constant 4>
            align 32 symtab 0 alias set -1 canonical type 0x7ffff65c8690
            precision 32 min <integer_cst 0x7ffff65b0f48 0>
            max <integer_cst 0x7ffff65b0f00 4294967295>
            pointer_to_this <pointer_type 0x7ffff65d5dc8>>
        visited
        def_stmt _1 = i_13 + 1;
        version 1
        ptr-info 0x7ffff66fa300>>
...

Since itype is unsigned int, '(POINTER_TYPE_P (itype) || (INTEGRAL_TYPE_P
(itype) && TYPE_OVERFLOW_UNDEFINED (itype)' evaluates to false.

For the signed case itype is signed int, and the same clause evaluates to true.

I wonder if we could improve split_constant_offset by using range info. For
this example, that would boil down to: 
- you check that _1 has a range such that the cast doesn't change the value
- you check that i_13 has a range such that i_13 + 1 doesn't overflow.

Reply via email to