RFC: Avoid calling convert_to_mode with invalid rtl.
Nick Clifton
nickc@redhat.com
Fri Mar 13 11:33:00 GMT 2015
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. */
More information about the Gcc-patches
mailing list