Hi Guys, A bug reported against the RL78 port has a uncovered a generic problem with expand_expr_real_1() function - part of the code their computes the offset of an address for an array reference, and if necessary makes sure that it is in the correct mode:
if (offset) { machine_mode address_mode; rtx offset_rtx = expand_expr (offset, NULL_RTX, VOIDmode, EXPAND_SUM); gcc_assert (MEM_P (op0)); address_mode = get_address_mode (op0); if (GET_MODE (offset_rtx) != address_mode) offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); The problem here is that convert_to_mode() may decide to offload offset_rtx into another reg and then extend the reg to address_mode, but it assumes that offset_rtx is a valid rtl expression for the target. Offset_rtx probably looks like this: (plus (mult (reg) (const_int)) (const_int)) For the RL78, and possibly other targets, this is valid as an address, but not as standalone expression. (The RL78 does not have a multiply-and-add instruction, but it does have register+offset indexed addressing). The end result then is an ICE like this: error: unrecognizable insn: (insn 10 9 11 2 (set (subreg:HI (reg:SI 48) 0) (plus:HI (mult:HI (reg:HI 44) (const_int 2)) (reg:HI 46)))) I don't think that convert_to_mode is at fault here however - it is written assuming that its input is valid. So instead I am asking for comments on the patch below. (I realise that the sources are in stage 4 and so this patch is not suitable for application at this time). The patch adds a second call to expand_expr(), giving the address mode as the suggested mode, and using a normal expansion, rather than EXPAND_SUM. This might work, but even if it does not the rtl in offset_rtx will be valid in a non-address context so that whatever convert_to_mode does will still remain valid. What do people think ? Is this the right approach ? I have tested the patch with an rl78-elf toolchain as well as an x86_64-pc-linux-gnu toolchain and there were no regressions in the gcc testsuite for either of these targets. Cheers Nick Index: gcc/expr.c =================================================================== --- gcc/expr.c (revision 221374) +++ gcc/expr.c (working copy) @@ -10257,6 +10257,15 @@ address_mode = get_address_mode (op0); + + if (GET_MODE (offset_rtx) != address_mode) + /* Before calling convert_to_mode, try expanding the offset as a + normal expression in the address mode. Even if this fails to + choose that mode, it has the benefit that any RTL generated + will be valid even outside of an address computation, a + result that is not achieved with EXPAND_SUM. */ + offset_rtx = expand_expr (offset, NULL_RTX, get_address_mode (op0), + EXPAND_NORMAL); + if (GET_MODE (offset_rtx) != address_mode) offset_rtx = convert_to_mode (address_mode, offset_rtx, 0); /* See the comment in expand_assignment for the rationale. */