int w[5]; void foo (int x, unsigned y) { long long r = 0; long long s; int i; switch (x) { case 1: for (i = 0; i < 4; i++) { if (!y) s = (w[9] << (10 - 2 * i)) >> (32 - 5 * i + 5 * i); r |= (s & 0xffffffff) << (i * 5); } break; case 3: r = w[x] >> y; } w[x] = r; } ICEs at -O2 on arm-linux-gnuabi. This reduced testcase ICEs also in 4.7, but the unreduced one at https://bugzilla.redhat.com/show_bug.cgi?id=915830#c1 only ICEs in 4.8 and not in 4.7. I wonder why arm backend uses constraints (N) to enfore the shift count in the range, rather than e.g. masking the operand & 31 if CONST_INT before printing. Shift counts >= 32 for SImode are of course undefined behavior, so it really doesn't matter what gets emitted, but we shouldn't ICE on it.
Confirmed. I'm a bit wary of just truncating the value. Shifts by 32 may be valid in the ARM back-end in some circumstances where we're using the shift as part of setting up the flags. Fixing this fully would require getting rid of "shift_operator" and replacing it with iterators. But that's a pretty radical overhaul. Long term that might well be worthwhile, but not this close to a release.
In any case, this looks like a clear backend bug, as it allows const_int 32 in the operand (through the use of M constraint), but then doesn't handle it at all in arm_output_shift (it forces use of %S3 on it and that requires 0 .. 31 constant, not 0 .. 32). And while the code has undefined behavior, if you never invoke it, you should still be able to have it in a valid program.
Definitely a back-end bug. I'm not disputing that. My surprise is that this hasn't bitten us long before now, since the code has been this way for well over ten years.
If the folder or GIMPLE passes see it is a shift by 32, they fold it away (with or without a warning), so the fact that it is a constant larger than bitsize of the shifted operand has to be seen only during RTL optimizations.
Working on a fix.
According to reporter also broken on the 4.7 branch.
Author: rearnsha Date: Mon Mar 11 11:48:34 2013 New Revision: 196595 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=196595 Log: PR target/56470 * arm.c (shift_op): Validate RTL pattern on the fly. (arm_print_operand, case 'S'): Don't use shift_operator to validate the RTL. Modified: trunk/gcc/ChangeLog trunk/gcc/config/arm/arm.c
Fixed on trunk. Testing back-port to 4.7.
Author: rearnsha Date: Mon Mar 18 11:52:08 2013 New Revision: 196780 URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=196780 Log: PR target/56470 * arm.c (shift_op): Validate RTL pattern on the fly. (arm_print_operand, case 'S'): Don't use shift_operator to validate the RTL. Modified: branches/gcc-4_7-branch/gcc/ChangeLog branches/gcc-4_7-branch/gcc/config/arm/arm.c
Fixed