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;
+}

Reply via email to