Bernd Edlinger <bernd.edlin...@hotmail.de> writes:
> On 08/18/18 12:40, Richard Sandiford wrote:
>> Bernd Edlinger <bernd.edlin...@hotmail.de> writes:
>>> Hi everybody,
>>>
>>> On 08/16/18 08:36, Bernd Edlinger wrote:
>>>> Jeff Law wrote:
>>>>> I wonder if the change to how we set up the initializers is ultimately
>>>>> changing the section those go into and ultimately causing an overflow of
>>>>> the .sdata section.
>>>>
>>>>
>>>> Yes, that is definitely the case.
>>>> Due to the -fmerge-all-constants option used
>>>> named arrays with brace initializer look like string initializers
>>>> and can go into the merge section if there are no embedded nul chars.
>>>> But the string constants can now be huge.
>>>>
>>>> See my other patch about string merging:
>>>> [PATCH] Handle not explicitly zero terminated strings in merge sections
>>>> https://gcc.gnu.org/ml/gcc-patches/2018-08/msg00481.html
>>>>
>>>>
>>>> Can this section overflow?
>>>>
>>>
>>>
>>> could someone try out if this (untested) patch fixes the issue?
>>>
>>>
>>> Thanks,
>>> Bernd.
>>>
>>>
>>> 2018-08-18  Bernd Edlinger  <bernd.edlin...@hotmail.de>
>>>
>>>     * expmed.c (simple_mem_bitfield_p): Do shift right signed.
>>>     * config/alpha/alpha.h (CONSTANT_ADDRESS_P): Avoid signed
>>>     integer overflow.
>>>
>>> Index: gcc/config/alpha/alpha.h
>>> ===================================================================
>>> --- gcc/config/alpha/alpha.h        (revision 263611)
>>> +++ gcc/config/alpha/alpha.h        (working copy)
>>> @@ -678,7 +678,7 @@ enum reg_class {
>>>   
>>>   #define CONSTANT_ADDRESS_P(X)   \
>>>     (CONST_INT_P (X)                \
>>> -   && (unsigned HOST_WIDE_INT) (INTVAL (X) + 0x8000) < 0x10000)
>>> +   && (UINTVAL (X) + 0x8000) < 0x10000)
>>>   
>>>   /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
>>>      and check its validity for a certain class.
>>> Index: gcc/expmed.c
>>> ===================================================================
>>> --- gcc/expmed.c    (revision 263611)
>>> +++ gcc/expmed.c    (working copy)
>>> @@ -579,8 +579,12 @@ static bool
>>>   simple_mem_bitfield_p (rtx op0, poly_uint64 bitsize, poly_uint64 bitnum,
>>>                    machine_mode mode, poly_uint64 *bytenum)
>>>   {
>>> +  poly_int64 ibit = bitnum;
>>> +  poly_int64 ibyte;
>>> +  if (!multiple_p (ibit, BITS_PER_UNIT, &ibyte))
>>> +    return false;
>>> +  *bytenum = ibyte;
>>>     return (MEM_P (op0)
>>> -     && multiple_p (bitnum, BITS_PER_UNIT, bytenum)
>>>       && known_eq (bitsize, GET_MODE_BITSIZE (mode))
>>>       && (!targetm.slow_unaligned_access (mode, MEM_ALIGN (op0))
>>>           || (multiple_p (bitnum, GET_MODE_ALIGNMENT (mode))
>> 
>> Do we have a genuinely negative bit offset here?  Seems like the callers
>> would need to be updated if so, since the code is consistent in treating
>> the offset as unsigned.
>> 
>
> Aehm, yes.
>
> The test case plural.i contains this:
>
> static const yytype_int8 yypgoto[] =
> {
>       -10, -10, -1
> };
>
> static const yytype_uint8 yyr1[] =
> {
>         0, 16, 17, 18, 18, 18, 18, 18, 18, 18,
>        18, 18, 18, 18
> };
>
>    yyn = yyr1[yyn];
>
>    yystate = yypgoto[yyn - 16] + *yyssp;
>
>
> There will probably a reason why yyn can never be 0
> in yyn = yyr1[yyn]; but it is not really obvious.
>
> In plural.i.228t.optimized we have:
>
>   pretmp_400 = yypgoto[-16];
>    _385 = (int) pretmp_400;
>    goto <bb 69>; [100.00%]

Ah, ok.

[...]

> (gdb) frame 26
> #26 0x000000000082f828 in expand_expr_real_1 (exp=<optimized out>, 
> target=<optimized out>,
>      tmode=<optimized out>, modifier=EXPAND_NORMAL, alt_rtl=0x0, 
> inner_reference_p=<optimized out>)
>      at ../../gcc-trunk/gcc/expr.c:10801
> 10801                                      ext_mode, ext_mode, reversep, 
> alt_rtl);
> (gdb) list
> 10796               reversep = TYPE_REVERSE_STORAGE_ORDER (type);
> 10797 
> 10798             op0 = extract_bit_field (op0, bitsize, bitpos, unsignedp,
> 10799                                      (modifier == EXPAND_STACK_PARM
> 10800                                       ? NULL_RTX : target),
> 10801                                      ext_mode, ext_mode, reversep, 
> alt_rtl);
> 10802 
> 10803             /* If the result has a record type and the mode of OP0 is an
> 10804                integral mode then, if BITSIZE is narrower than this mode
> 10805                and this is for big-endian data, we must put the field
> (gdb) p bitpos
> $1 = {<poly_int_pod<1u, long>> = {coeffs = {-128}}, <No data fields>}

The get_inner_reference->store_field path in expand_assignment has:

      /* Make sure bitpos is not negative, it can wreak havoc later.  */
      if (maybe_lt (bitpos, 0))
        {
          gcc_assert (offset == NULL_TREE);
          offset = size_int (bits_to_bytes_round_down (bitpos));
          bitpos = num_trailing_bits (bitpos);
        }

So maybe this is what havoc looks like.

It's not my area, but I think we should be doing something similar for
the get_inner_reference->expand_bit_field path in expand_expr_real_1.
Haven't checked whether the offset == NULL_TREE assert would be
guaranteed there though.

> $5 = {<poly_int_pod<1u, unsigned long>> = {coeffs = {0x1ffffffffffffff0}}, 
> <No data fields>}
>
> The byte offset is completely wrong now, due to the bitnum was
> initially a negative integer and got converted to unsigned.  At the
> moment when that is converted to byte offsets it is done wrong.  I
> think it is too much to change everything to signed arithmetics, but
> at least when converting a bit pos to a byte pos, it should be done in
> signed arithmetics.

But then we'd mishandle a real 1ULL << 63 bitpos (say).  Realise it's
unlikely in real code, but it'd still probably be possible to construct
a variant of the original test case in which the bias was
+0x1000000000000000 rather than -16.

Thanks,
Richard

Reply via email to