We ran across problems with the regrename pass introducing invalid insns
while working on support for new load/store multiple instructions on
nios2. We're using an implementation similar to what ARM already does,
with a match_parallel predicate testing for restrictions on the
underlying machine instructions that can't be expressed using GCC
register constraints. (E.g., the register numbers do not have to be
sequential, but they do have to be ascending/descending and a
combination that can be encoded in the machine instruction.)
The attached patch teaches regrename to validate insns affected by each
register renaming before making the change. I can see at least two
other ways to handle this -- earlier, by rejecting renamings that result
in invalid instructions when it's searching for the best renaming; or
later, by validating the entire set of renamings as a group instead of
incrementally for each one -- but doing it all in regname_do_replace
seems least disruptive and risky in terms of the existing code.
There are a couple of old bugzilla tickets for
instruction-doesn't-satisfy-its-constraints ICEs in regrename that might
or might not be related to this. The symptom we saw was not an ICE,
just bad code being emitted that resulted in assembler errors.
I've bootstrapped and regression-tested this on x86_64-linux-gnu in
addition to our testing with the pending nios2 patch set. OK to commit?
-Sandra
2015-06-17 Chung-Lin Tang <clt...@codesourcery.com>
Sandra Loosemore <san...@codesourcery.com>
gcc/
* regrename.c (regrename_do_replace): Re-validate the modified
insns.
Index: gcc/regrename.c
===================================================================
--- gcc/regrename.c (revision 224532)
+++ gcc/regrename.c (working copy)
@@ -942,19 +942,22 @@ regrename_do_replace (struct du_head *he
int reg_ptr = REG_POINTER (*chain->loc);
if (DEBUG_INSN_P (chain->insn) && REGNO (*chain->loc) != base_regno)
- INSN_VAR_LOCATION_LOC (chain->insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+ validate_change (chain->insn, &(INSN_VAR_LOCATION_LOC (chain->insn)),
+ gen_rtx_UNKNOWN_VAR_LOC (), true);
else
{
- *chain->loc = gen_raw_REG (GET_MODE (*chain->loc), reg);
+ validate_change (chain->insn, chain->loc,
+ gen_raw_REG (GET_MODE (*chain->loc), reg), true);
if (regno >= FIRST_PSEUDO_REGISTER)
ORIGINAL_REGNO (*chain->loc) = regno;
REG_ATTRS (*chain->loc) = attr;
REG_POINTER (*chain->loc) = reg_ptr;
}
-
- df_insn_rescan (chain->insn);
}
+ if (!apply_change_group ())
+ return;
+
mode = GET_MODE (*head->first->loc);
head->regno = reg;
head->nregs = hard_regno_nregs[reg][mode];