This is a case where we had: (set (reg:HI foo) (plus:HI (reg:HI sp) (const_int X))) (clobber (reg:CC FLAGS_REG))
and the splitters decided to convert it to an LEA: (set (reg:SI foo) (plus:SI (subreg:SI (reg:HI sp) 0) (const_int X))) But this fails to match, because ix86_address_subreg_operand doesn't allow subregs of the stack pointer. This shows up an inconsistency in the way the generic code handles subregs of the stack pointer. Normally we refuse to fold them, even after reload, but the final_p case of alter_subreg folds them anyway. That's how we ended up with the rather odd 16-bit sp. However, even if the special alter_subreg case was removed (so that we continued to use stack_pointer_rtx itself), we'd have: (set (reg:HI foo) (plus:HI (subreg:HI (reg:DI sp) 0) (const_int X))) (clobber (reg:CC FLAGS_REG)) which would get converted to: (set (reg:SI foo) (plus:SI (subreg:SI (reg:DI sp) 0) (const_int X))) and we'd ICE in the same way. The reason x86 rejects subregs of the stack pointer is this same refusal to fold. ix86_print_operand_address tries to simplify a SUBREG to a REG and simplify_subreg wouldn't do anything for sp. simplify_subreg isn't a lot of help at the output stage though. If the insn stream contains a subreg that could be simplified but hasn't been, then IMO that's a bug. The cases we have to handle here are those that can't be simplified (unless we decide at some point that all registers must be simplifiable after reload, in which case we shouldn't need to handle SUBREGs at all). As things stand, I think we should be using true_regnum in this case instead. Tested on x86_64-linux-gnu. OK to install? Richard gcc/ PR target/55204 * config/i386/i386.c (ix86_address_subreg_operand): Remove stack pointer check. (print_reg): Use true_regnum rather than REGNO. (ix86_print_operand_address): Remove SUBREG handling. Index: gcc/config/i386/i386.c =================================================================== --- gcc/config/i386/i386.c 2012-11-04 21:53:46.000000000 +0000 +++ gcc/config/i386/i386.c 2012-11-04 21:53:46.821356709 +0000 @@ -11784,10 +11784,6 @@ ix86_address_subreg_operand (rtx op) if (GET_MODE_SIZE (mode) > UNITS_PER_WORD) return false; - /* simplify_subreg does not handle stack pointer. */ - if (REGNO (op) == STACK_POINTER_REGNUM) - return false; - /* Allow only SUBREGs of non-eliminable hard registers. */ return register_no_elim_operand (op, mode); } @@ -14084,13 +14080,6 @@ print_reg (rtx x, int code, FILE *file) const char *reg; bool duplicated = code == 'd' && TARGET_AVX; - gcc_assert (x == pc_rtx - || (REGNO (x) != ARG_POINTER_REGNUM - && REGNO (x) != FRAME_POINTER_REGNUM - && REGNO (x) != FLAGS_REG - && REGNO (x) != FPSR_REG - && REGNO (x) != FPCR_REG)); - if (ASSEMBLER_DIALECT == ASM_ATT) putc ('%', file); @@ -14101,6 +14090,13 @@ print_reg (rtx x, int code, FILE *file) return; } + unsigned int regno = true_regnum (x); + gcc_assert (regno != ARG_POINTER_REGNUM + && regno != FRAME_POINTER_REGNUM + && regno != FLAGS_REG + && regno != FPSR_REG + && regno != FPCR_REG); + if (code == 'w' || MMX_REG_P (x)) code = 2; else if (code == 'b') @@ -14126,7 +14122,7 @@ print_reg (rtx x, int code, FILE *file) { gcc_assert (TARGET_64BIT); putc ('r', file); - fprint_ul (file, REGNO (x) - FIRST_REX_INT_REG + 8); + fprint_ul (file, regno - FIRST_REX_INT_REG + 8); switch (code) { case 0: @@ -14170,24 +14166,24 @@ print_reg (rtx x, int code, FILE *file) case 16: case 2: normal: - reg = hi_reg_name[REGNO (x)]; + reg = hi_reg_name[regno]; break; case 1: - if (REGNO (x) >= ARRAY_SIZE (qi_reg_name)) + if (regno >= ARRAY_SIZE (qi_reg_name)) goto normal; - reg = qi_reg_name[REGNO (x)]; + reg = qi_reg_name[regno]; break; case 0: - if (REGNO (x) >= ARRAY_SIZE (qi_high_reg_name)) + if (regno >= ARRAY_SIZE (qi_high_reg_name)) goto normal; - reg = qi_high_reg_name[REGNO (x)]; + reg = qi_high_reg_name[regno]; break; case 32: if (SSE_REG_P (x)) { gcc_assert (!duplicated); putc ('y', file); - fputs (hi_reg_name[REGNO (x)] + 1, file); + fputs (hi_reg_name[regno] + 1, file); return; } break; @@ -14943,22 +14939,6 @@ ix86_print_operand_address (FILE *file, gcc_assert (ok); - if (parts.base && GET_CODE (parts.base) == SUBREG) - { - rtx tmp = SUBREG_REG (parts.base); - parts.base = simplify_subreg (GET_MODE (parts.base), - tmp, GET_MODE (tmp), 0); - gcc_assert (parts.base != NULL_RTX); - } - - if (parts.index && GET_CODE (parts.index) == SUBREG) - { - rtx tmp = SUBREG_REG (parts.index); - parts.index = simplify_subreg (GET_MODE (parts.index), - tmp, GET_MODE (tmp), 0); - gcc_assert (parts.index != NULL_RTX); - } - base = parts.base; index = parts.index; disp = parts.disp;