lra_in_progress check in simplify_subreg_regno
Richard Sandiford
rdsandiford@googlemail.com
Wed Dec 18 22:03:00 GMT 2013
Hi Vlad,
The initial LRA merge added the lra_in_progress check to this code
in simplify_subreg_regno:
/* Give the backend a chance to disallow the mode change. */
if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT
&& REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode)
/* We can use mode change in LRA for some transformations. */
&& ! lra_in_progress)
return -1;
I realise that LRA internally uses subregs that wouldn't normally be valid
(e.g. to handle matching constraints) but I think it's really dangerous
to ignore REG_CANNOT_CHANGE_MODE_P and reduce a subreg to a specific
hard reg anyway. CLASS_CANNOT_CHANGE_MODE says that all bets are off in
terms of the normal subreg rules. E.g. the register class might have the
opposite endianness to GENERAL_REGS or something extreme like that.
It wasn't obvious from the comment exactly what case this !lra_in_progress
was handling, but I tried reverting it and saw a failure in gcc.dg/pr49948.c.
The problem there was with a subreg of the form:
(subreg:DI (reg:V2DI X) 0)
We were trying to reload this subreg in GENERAL_REGS and X had been
allocated an SSE reg. We then hit this code in curr_insn_transform,
which was deciding whether to reload the reg or the subreg:
if (REG_P (reg)
/* Strict_low_part requires reload the register not
the sub-register. */
&& (curr_static_id->operand[i].strict_low
|| (GET_MODE_SIZE (mode)
<= GET_MODE_SIZE (GET_MODE (reg))
&& (hard_regno
= get_try_hard_regno (REGNO (reg))) >= 0
&& (simplify_subreg_regno
(hard_regno,
GET_MODE (reg), byte, mode) < 0)
&& (goal_alt[i] == NO_REGS
|| (simplify_subreg_regno
(ira_class_hard_regs[goal_alt[i]][0],
GET_MODE (reg), byte, mode) >= 0)))))
{
loc = &SUBREG_REG (*loc);
mode = GET_MODE (*loc);
}
The first simplify_subreg_regno (on the SSE reg) used to return >= 0
thanks to the !lra_in_progress, even though the change is usually supposed
to be disallowed. With the !lra_in_progress removed simplify_subreg_regno
rejects the simplification instead. Then the second simplify_subreg_regno
(on the first allocatable GENERAL_REGS) succeeds and we go on to reload
the inner reg.
But the key in this case is that GENERAL_REGS isn't allowed to hold V2DImode,
so the simplification performed by the second simplify_subreg_regno
doesn't really have any meaning. I think we should check that
ira_class_hard_regs[goal_alt[i]][0] can hold GET_MODE (reg) before
trying to simplify a subreg of it.
Tested on x86_64-linux-gnu ({,-m32}, all languages including Go and Ada).
Does it look OK? Or, if the check was originally added for a different
situation, are you still able to reproduce it?
FWIW, this is all part of an attempt to fix the vec_select thing for x86_64.
I also want to get rid of the GET_MODE_CLASS checks seen in the first hunk,
but that's an entirely separate issue.
Thanks,
Richard
gcc/
* rtlanal.c (simplify_subreg_regno): Remove lra_in_progress check.
* lra-constraints.c (curr_insn_transform): Before trying to simplify
a subreg, check whether the original reg is valid.
Index: gcc/rtlanal.c
===================================================================
--- gcc/rtlanal.c 2013-12-09 08:03:31.931201686 +0000
+++ gcc/rtlanal.c 2013-12-18 21:22:10.605987652 +0000
@@ -3533,9 +3533,7 @@ simplify_subreg_regno (unsigned int xreg
/* Give the backend a chance to disallow the mode change. */
if (GET_MODE_CLASS (xmode) != MODE_COMPLEX_INT
&& GET_MODE_CLASS (xmode) != MODE_COMPLEX_FLOAT
- && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode)
- /* We can use mode change in LRA for some transformations. */
- && ! lra_in_progress)
+ && REG_CANNOT_CHANGE_MODE_P (xregno, xmode, ymode))
return -1;
#endif
Index: gcc/lra-constraints.c
===================================================================
--- gcc/lra-constraints.c 2013-12-09 21:35:05.589588280 +0000
+++ gcc/lra-constraints.c 2013-12-18 21:22:10.585987483 +0000
@@ -3493,9 +3493,12 @@ curr_insn_transform (void)
(hard_regno,
GET_MODE (reg), byte, mode) < 0)
&& (goal_alt[i] == NO_REGS
- || (simplify_subreg_regno
+ || (HARD_REGNO_MODE_OK
(ira_class_hard_regs[goal_alt[i]][0],
- GET_MODE (reg), byte, mode) >= 0)))))
+ GET_MODE (reg))
+ && (simplify_subreg_regno
+ (ira_class_hard_regs[goal_alt[i]][0],
+ GET_MODE (reg), byte, mode) >= 0))))))
{
loc = &SUBREG_REG (*loc);
mode = GET_MODE (*loc);
More information about the Gcc-patches
mailing list