Patchwork patch to fix pr57046

login
register
mail settings
Submitter Vladimir Makarov
Date April 24, 2013, 8:27 p.m.
Message ID <5178404B.5090907@redhat.com>
Download mbox | patch
Permalink /patch/239312/
State New
Headers show

Comments

Vladimir Makarov - April 24, 2013, 8:27 p.m.
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  <vmakarov@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  <vmakarov@redhat.com>

         PR rtl-optimizations/57046
         * gcc.target/i386/pr57046.c: New test.

Patch

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