[PATCH v1 1/2] Simplify shifts wider than the bitwidth of types

Philipp Tomsich philipp.tomsich@vrull.eu
Mon Nov 16 22:59:29 GMT 2020


On Mon, 16 Nov 2020 at 23:38, Jim Wilson <jimw@sifive.com> wrote:

> On Mon, Nov 16, 2020 at 10:57 AM Philipp Tomsich <philipp.tomsich@vrull.eu>
> wrote:
>
>> This adds simplify_using_ranges::simplify_lshift_using_ranges to
>> detect and rewrite such cases.  If the intersection of meaningful
>> shift amounts for the underlying type and the value-range computed
>> for the shift-amount (whether an integer constant or a variable) is
>> empty, the statement is replaced with the zero-constant of the same
>> precision as the result.
>>
>
> This has the risk of breaking some user code.  I've seen people write code
> for RISC-V knowing that the hardware truncates shift counts, and so not
> doing the full calculation to get the right value but just letting the
> compiler/hardware calculate it for them via truncation.  Of course this
> code has implemented defined result, but there is no reason to break it
> unnecessarily.
>

While undefined behavior (as per the C standard), GCC uses a predictable
behaviour for negative shift-amounts (and shifts that are wider than the
type):

int func(int a)
{
  return a << -1;
}

will raise the following warning:

shift-neg.c: In function 'func':
shift-neg.c:3:12: warning: left shift count is negative
[-Wshift-count-negative]
    3 |   return a << -1;
      |            ^~

and return 0:

func:
    li a0,0
    ret
    .size func, .-func


Having two different results generated here, depending on what parts of GCC
"see" the shift-amount, doesn't seem sensible and likely to cause breakage
in the long term.
I fully agree that this is undefined behavior (so no well-formed program
should rely on it), but I would prefer to have a common behavior
independent on when the constant is known.

Philipp.


More information about the Gcc-patches mailing list