[backport gcc-4.8/trunk r195595 ] gcc/ 2013-03-11 Richard Earnshaw 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. --- gcc-4.7.2/gcc/config/arm/arm.c.~1~ 2012-09-07 11:31:54.000000000 +0200 +++ gcc-4.7.2/gcc/config/arm/arm.c 2013-03-15 08:59:10.118042609 +0100 @@ -14860,71 +14860,87 @@ shift_op (rtx op, HOST_WIDE_INT *amountp const char * mnem; enum rtx_code code = GET_CODE (op); - switch (GET_CODE (XEXP (op, 1))) - { - case REG: - case SUBREG: - *amountp = -1; - break; - - case CONST_INT: - *amountp = INTVAL (XEXP (op, 1)); - break; - - default: - gcc_unreachable (); - } - switch (code) { case ROTATE: - gcc_assert (*amountp != -1); - *amountp = 32 - *amountp; - code = ROTATERT; + if (!CONST_INT_P (XEXP (op, 1))) + { + output_operand_lossage ("invalid shift operand"); + return NULL; + } - /* Fall through. */ + code = ROTATERT; + *amountp = 32 - INTVAL (XEXP (op, 1)); + mnem = "ror"; + break; case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATERT: mnem = arm_shift_nmem(code); + if (CONST_INT_P (XEXP (op, 1))) + { + *amountp = INTVAL (XEXP (op, 1)); + } + else if (REG_P (XEXP (op, 1))) + { + *amountp = -1; + return mnem; + } + else + { + output_operand_lossage ("invalid shift operand"); + return NULL; + } break; case MULT: /* We never have to worry about the amount being other than a power of 2, since this case can never be reloaded from a reg. */ - gcc_assert (*amountp != -1); + if (!CONST_INT_P (XEXP (op, 1))) + { + output_operand_lossage ("invalid shift operand"); + return NULL; + } + + *amountp = INTVAL (XEXP (op, 1)) & 0xFFFFFFFF; + + /* Amount must be a power of two. */ + if (*amountp & (*amountp - 1)) + { + output_operand_lossage ("invalid shift operand"); + return NULL; + } + *amountp = int_log2 (*amountp); return ARM_LSL_NAME; default: - gcc_unreachable (); + output_operand_lossage ("invalid shift operand"); + return NULL; } - if (*amountp != -1) - { - /* This is not 100% correct, but follows from the desire to merge - multiplication by a power of 2 with the recognizer for a - shift. >=32 is not a valid shift for "lsl", so we must try and - output a shift that produces the correct arithmetical result. - Using lsr #32 is identical except for the fact that the carry bit - is not set correctly if we set the flags; but we never use the - carry bit from such an operation, so we can ignore that. */ - if (code == ROTATERT) - /* Rotate is just modulo 32. */ - *amountp &= 31; - else if (*amountp != (*amountp & 31)) - { - if (code == ASHIFT) - mnem = "lsr"; - *amountp = 32; - } - - /* Shifts of 0 are no-ops. */ - if (*amountp == 0) - return NULL; - } + /* This is not 100% correct, but follows from the desire to merge + multiplication by a power of 2 with the recognizer for a + shift. >=32 is not a valid shift for "lsl", so we must try and + output a shift that produces the correct arithmetical result. + Using lsr #32 is identical except for the fact that the carry bit + is not set correctly if we set the flags; but we never use the + carry bit from such an operation, so we can ignore that. */ + if (code == ROTATERT) + /* Rotate is just modulo 32. */ + *amountp &= 31; + else if (*amountp != (*amountp & 31)) + { + if (code == ASHIFT) + mnem = "lsr"; + *amountp = 32; + } + + /* Shifts of 0 are no-ops. */ + if (*amountp == 0) + return NULL; return mnem; } @@ -17300,12 +17316,6 @@ arm_print_operand (FILE *stream, rtx x, HOST_WIDE_INT val; const char *shift; - if (!shift_operator (x, SImode)) - { - output_operand_lossage ("invalid shift operand"); - break; - } - shift = shift_op (x, &val); if (shift)