On Mon, 16 Nov 2020 at 23:38, Jim Wilson <j...@sifive.com> wrote: > On Mon, Nov 16, 2020 at 10:57 AM Philipp Tomsich <philipp.toms...@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.