arm-eabi-gcc -Os -mthumb produces wrong code for the following testcase: void __attribute__((noinline)) foo (int *p, int d1, int d2, int d3, short count, int s1, int s2, int s3, int s4, int s5) { int n = count; while (n--) { *p++ = s1; *p++ = s2; *p++ = s3; *p++ = s4; *p++ = s5; } }
The important things about the testcase are: (a) There must be a subword stack parameter P1 that we do not assume is already promoted. This is "count" in the testcase above. (b) There must be later stack parameters whose pseudos do not get allocated a hard register. Because Thumb doesn't have subword stack loads, the sequence to set up P1's pseudo register must first load the argument pointer into a pseudo (let's call it PA). The gcse local-prop pass then replaces the argument pointer with PA in the instructions related to later stack parameters. The problem is that gcse does this in both the instruction bodies _and_ their REG_EQUIV notes, so we get things like: (set (reg P2) (mem (plus (reg PA) (const_int 4)))) REG_EQUIV: (mem (plus (reg PA) (const_int 4))) The change to the insn body is almost immediately undone by CSE (that was worthwhile, wasn't it?) but the REG_EQUIV note remains. The change to the note is bogus though. A REG_EQUIV note is supposed to say that all occurences of the register could be replaced with the equivalent expression without affecting semantics. However, when gcse.c:try_replace_reg replaces FROM with TO in INSN, the equivalence between FROM and TO is a local rather than a global property. I'm not sure the replacement would be valid even if the equivalence were global though. Nothing ensures (or is supposed to ensure) that PA's lifetime is extended to cover the lifetime of P2. I'm testing a patch now. Richard -- Summary: invalid gcse manipulation of REG_EQUIV notes Product: gcc Version: 4.2.0 Status: UNCONFIRMED Keywords: wrong-code Severity: normal Priority: P3 Component: rtl-optimization AssignedTo: unassigned at gcc dot gnu dot org ReportedBy: rsandifo at gcc dot gnu dot org GCC target triplet: arm-eabi http://gcc.gnu.org/bugzilla/show_bug.cgi?id=27073