The following patch fixes http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57046
The patch was successfully bootstrapped and tested on x86/x86-64. Committed as rev. 198263. 2013-04-24 Vladimir Makarov <vmaka...@redhat.com> PR rtl-optimizations/57046 * lra-constraints (split_reg): Set up lra_risky_transformations_p for multi-reg splits. 2013-04-24 Vladimir Makarov <vmaka...@redhat.com> PR rtl-optimizations/57046 * gcc.target/i386/pr57046.c: New test.
Index: lra-constraints.c =================================================================== --- lra-constraints.c (revision 198252) +++ lra-constraints.c (working copy) @@ -4198,7 +4198,7 @@ split_reg (bool before_p, int original_r { enum reg_class rclass; rtx original_reg; - int hard_regno; + int hard_regno, nregs; rtx new_reg, save, restore, usage_insn; bool after_p; bool call_save_p; @@ -4208,10 +4208,12 @@ split_reg (bool before_p, int original_r rclass = ira_allocno_class_translate[REGNO_REG_CLASS (original_regno)]; hard_regno = original_regno; call_save_p = false; + nregs = 1; } else { hard_regno = reg_renumber[original_regno]; + nregs = hard_regno_nregs[hard_regno][PSEUDO_REGNO_MODE (original_regno)]; rclass = lra_get_allocno_class (original_regno); original_reg = regno_reg_rtx[original_regno]; call_save_p = need_for_call_save_p (original_regno); @@ -4324,6 +4326,13 @@ split_reg (bool before_p, int original_r before_p ? NULL_RTX : save, call_save_p ? "Add save<-reg" : "Add split<-reg"); + if (nregs > 1) + /* If we are trying to split multi-register. We should check + conflicts on the next assignment sub-pass. IRA can allocate on + sub-register levels, LRA do this on pseudos level right now and + this discrepancy may create allocation conflicts after + splitting. */ + lra_risky_transformations_p = true; if (lra_dump_file != NULL) fprintf (lra_dump_file, " ))))))))))))))))))))))))))))))))))))))))))))))))\n"); Index: testsuite/gcc.target/i386/pr57046.c =================================================================== --- testsuite/gcc.target/i386/pr57046.c (revision 0) +++ testsuite/gcc.target/i386/pr57046.c (working copy) @@ -0,0 +1,77 @@ +/* { dg-do run } */ +/* { dg-options "-O2" } */ + +struct emac { + unsigned reg[23]; +}; + +struct mop { + unsigned long long addr; + unsigned int size; +}; + +unsigned int __attribute__((__noinline__)) +level(const struct emac *obj) +{ + return 0; +} + +void __attribute__((__noinline__)) +info(struct emac *dev, unsigned long long addr) +{ + asm("" : : : "memory"); +} + +unsigned long long __attribute__((__noinline__)) +get_value(const struct mop *mop) +{ + return 0x1234567890abcdefull; +} + +int __attribute__((__noinline__)) +emac_operation(struct emac *obj, struct mop *mop) +{ + unsigned long long addr = mop->addr; + int index = addr >> 2; + unsigned int value, old_value; + + if (mop->size != 4) + return 0; + + if (index >= 23) { + if (level(obj) >= 1) + info(obj, addr); + return 0; + } + + value = get_value(mop); + old_value = obj->reg[index]; + + info(obj, 0); + + switch (index) { + case 0: + obj->reg[0] = old_value; + break; + case 7: + case 8: + obj->reg[index] = value; + break; + } + + return 0; +} + +int main(void) +{ + struct emac e = { { 0 } }; + struct mop mop = { 32, 4 }; + + e.reg[8] = 0xdeadbeef; + emac_operation(&e, &mop); + + if (e.reg[8] != 0x90abcdef) + __builtin_abort(); + + return 0; +}