re PR rtl-optimization/86939 (IRA incorrectly creates an interference between a pseud...
authorPeter Bergner <bergner@linux.ibm.com>
Sat, 6 Oct 2018 02:12:30 +0000 (02:12 +0000)
committerPeter Bergner <bergner@gcc.gnu.org>
Sat, 6 Oct 2018 02:12:30 +0000 (21:12 -0500)
gcc/
PR rtl-optimization/86939
PR rtl-optimization/87479
* ira.h (non_conflicting_reg_copy_p): New prototype.
* ira-lives.c (ignore_reg_for_conflicts): New static variable.
(make_hard_regno_dead): Don't add conflicts for register
ignore_reg_for_conflicts.
(make_object_dead): Likewise.
(non_conflicting_reg_copy_p): New function.
(process_bb_node_lives): Set ignore_reg_for_conflicts for copies.
Remove special conflict handling of REAL_PIC_OFFSET_TABLE_REGNUM.
* lra-lives.c (ignore_reg_for_conflicts): New static variable.
(make_hard_regno_dead): Don't add conflicts for register
ignore_reg_for_conflicts.  Remove special conflict handling of
REAL_PIC_OFFSET_TABLE_REGNUM.  Remove now unused argument
check_pic_pseudo_p and update callers.
(mark_pseudo_dead): Don't add conflicts for register
ignore_reg_for_conflicts.
(process_bb_lives): Set ignore_reg_for_conflicts for copies.

gcc/testsuite/
PR rtl-optimization/86939
PR rtl-optimization/87479
* gcc.target/powerpc/pr86939.c: New test.
* gcc/testsuite/gcc.target/i386/pr49095.c: Fix expected results.

From-SVN: r264897

gcc/ChangeLog
gcc/ira-lives.c
gcc/ira.h
gcc/lra-lives.c
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr49095.c
gcc/testsuite/gcc.target/powerpc/pr86939.c [new file with mode: 0644]

index 6d81f73a708e5deec15857f14a2f5335b0745c54..73f26a936ecbe19a1e189434bb3e8cacf39cabc8 100644 (file)
@@ -1,3 +1,24 @@
+2018-10-05  Peter Bergner  <bergner@linux.ibm.com>
+
+       PR rtl-optimization/86939
+       PR rtl-optimization/87479
+       * ira.h (non_conflicting_reg_copy_p): New prototype.
+       * ira-lives.c (ignore_reg_for_conflicts): New static variable.
+       (make_hard_regno_dead): Don't add conflicts for register
+       ignore_reg_for_conflicts.
+       (make_object_dead): Likewise.
+       (non_conflicting_reg_copy_p): New function.
+       (process_bb_node_lives): Set ignore_reg_for_conflicts for copies.
+       Remove special conflict handling of REAL_PIC_OFFSET_TABLE_REGNUM.
+       * lra-lives.c (ignore_reg_for_conflicts): New static variable.
+       (make_hard_regno_dead): Don't add conflicts for register
+       ignore_reg_for_conflicts.  Remove special conflict handling of
+       REAL_PIC_OFFSET_TABLE_REGNUM.  Remove now unused argument
+       check_pic_pseudo_p and update callers.
+       (mark_pseudo_dead): Don't add conflicts for register
+       ignore_reg_for_conflicts.
+       (process_bb_lives): Set ignore_reg_for_conflicts for copies.
+
 2018-10-05  Andrew Waterman  <andrew@sifive.com>
            Jim Wilson  <jimw@sifive.com>
 
index f1a7d2797b2eb20b38617f340928ce91cac72092..dd8b334d58ec4a5acfeeeb8f49af3137003fabdc 100644 (file)
@@ -84,6 +84,10 @@ static int *allocno_saved_at_call;
    supplemental to recog_data.  */
 static alternative_mask preferred_alternatives;
 
+/* If non-NULL, the source operand of a register to register copy for which
+   we should not add a conflict with the copy's destination operand.  */
+static rtx ignore_reg_for_conflicts;
+
 /* Record hard register REGNO as now being live.  */
 static void
 make_hard_regno_live (int regno)
@@ -101,6 +105,11 @@ make_hard_regno_dead (int regno)
     {
       ira_object_t obj = ira_object_id_map[i];
 
+      if (ignore_reg_for_conflicts != NULL_RTX
+         && REGNO (ignore_reg_for_conflicts)
+            == (unsigned int) ALLOCNO_REGNO (OBJECT_ALLOCNO (obj)))
+       continue;
+
       SET_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), regno);
       SET_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), regno);
     }
@@ -154,12 +163,38 @@ static void
 make_object_dead (ira_object_t obj)
 {
   live_range_t lr;
+  int ignore_regno = -1;
+  int end_regno = -1;
 
   sparseset_clear_bit (objects_live, OBJECT_CONFLICT_ID (obj));
 
+  /* Check whether any part of IGNORE_REG_FOR_CONFLICTS already conflicts
+     with OBJ.  */
+  if (ignore_reg_for_conflicts != NULL_RTX
+      && REGNO (ignore_reg_for_conflicts) < FIRST_PSEUDO_REGISTER)
+    {
+      end_regno = END_REGNO (ignore_reg_for_conflicts);
+      int src_regno = ignore_regno = REGNO (ignore_reg_for_conflicts);
+
+      while (src_regno < end_regno)
+       {
+         if (TEST_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), src_regno))
+           {
+             ignore_regno = end_regno = -1;
+             break;
+           }
+         src_regno++;
+       }
+    }
+
   IOR_HARD_REG_SET (OBJECT_CONFLICT_HARD_REGS (obj), hard_regs_live);
   IOR_HARD_REG_SET (OBJECT_TOTAL_CONFLICT_HARD_REGS (obj), hard_regs_live);
 
+  /* If IGNORE_REG_FOR_CONFLICTS did not already conflict with OBJ, make
+     sure it still doesn't.  */
+  for (; ignore_regno < end_regno; ignore_regno++)
+    CLEAR_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (obj), ignore_regno);
+
   lr = OBJECT_LIVE_RANGES (obj);
   ira_assert (lr != NULL);
   lr->finish = curr_point;
@@ -1022,6 +1057,38 @@ find_call_crossed_cheap_reg (rtx_insn *insn)
   return cheap_reg;
 }  
 
+/* Determine whether INSN is a register to register copy of the type where
+   we do not need to make the source and destiniation registers conflict.
+   If this is a copy instruction, then return the source reg.  Otherwise,
+   return NULL_RTX.  */
+rtx
+non_conflicting_reg_copy_p (rtx_insn *insn)
+{
+  rtx set = single_set (insn);
+
+  /* Disallow anything other than a simple register to register copy
+     that has no side effects.  */
+  if (set == NULL_RTX
+      || !REG_P (SET_DEST (set))
+      || !REG_P (SET_SRC (set))
+      || side_effects_p (set))
+    return NULL_RTX;
+
+  int dst_regno = REGNO (SET_DEST (set));
+  int src_regno = REGNO (SET_SRC (set));
+  machine_mode mode = GET_MODE (SET_DEST (set));
+
+  /* Computing conflicts for register pairs is difficult to get right, so
+     for now, disallow it.  */
+  if ((dst_regno < FIRST_PSEUDO_REGISTER
+       && hard_regno_nregs (dst_regno, mode) != 1)
+      || (src_regno < FIRST_PSEUDO_REGISTER
+         && hard_regno_nregs (src_regno, mode) != 1))
+    return NULL_RTX;
+
+  return SET_SRC (set);
+}
+
 /* Process insns of the basic block given by its LOOP_TREE_NODE to
    update allocno live ranges, allocno hard register conflicts,
    intersected calls, and register pressure info for allocnos for the
@@ -1107,22 +1174,7 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
                     curr_point);
 
          call_p = CALL_P (insn);
-#ifdef REAL_PIC_OFFSET_TABLE_REGNUM
-         int regno;
-         bool clear_pic_use_conflict_p = false;
-         /* Processing insn usage in call insn can create conflict
-            with pic pseudo and pic hard reg and that is wrong.
-            Check this situation and fix it at the end of the insn
-            processing.  */
-         if (call_p && pic_offset_table_rtx != NULL_RTX
-             && (regno = REGNO (pic_offset_table_rtx)) >= FIRST_PSEUDO_REGISTER
-             && (a = ira_curr_regno_allocno_map[regno]) != NULL)
-           clear_pic_use_conflict_p
-               = (find_regno_fusage (insn, USE, REAL_PIC_OFFSET_TABLE_REGNUM)
-                  && ! TEST_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS
-                                          (ALLOCNO_OBJECT (a, 0)),
-                                          REAL_PIC_OFFSET_TABLE_REGNUM));
-#endif
+         ignore_reg_for_conflicts = non_conflicting_reg_copy_p (insn);
 
          /* Mark each defined value as live.  We need to do this for
             unused values because they still conflict with quantities
@@ -1276,20 +1328,9 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
                }
            }
 
-#ifdef REAL_PIC_OFFSET_TABLE_REGNUM
-         if (clear_pic_use_conflict_p)
-           {
-             regno = REGNO (pic_offset_table_rtx);
-             a = ira_curr_regno_allocno_map[regno];
-             CLEAR_HARD_REG_BIT (OBJECT_CONFLICT_HARD_REGS (ALLOCNO_OBJECT (a, 0)),
-                                 REAL_PIC_OFFSET_TABLE_REGNUM);
-             CLEAR_HARD_REG_BIT (OBJECT_TOTAL_CONFLICT_HARD_REGS
-                                 (ALLOCNO_OBJECT (a, 0)),
-                                 REAL_PIC_OFFSET_TABLE_REGNUM);
-           }
-#endif
          curr_point++;
        }
+      ignore_reg_for_conflicts = NULL_RTX;
 
       if (bb_has_eh_pred (bb))
        for (j = 0; ; ++j)
index 9df983c8a9672022eaac86406c88beed0f6c9403..8a8e4605032daa8b0b7f9a36e79789bdfa8c803b 100644 (file)
--- a/gcc/ira.h
+++ b/gcc/ira.h
@@ -210,6 +210,9 @@ extern void ira_adjust_equiv_reg_cost (unsigned, int);
 /* ira-costs.c */
 extern void ira_costs_c_finalize (void);
 
+/* ira-lives.c */
+extern rtx non_conflicting_reg_copy_p (rtx_insn *);
+
 /* Spilling static chain pseudo may result in generation of wrong
    non-local goto code using frame-pointer to address saved stack
    pointer value after restoring old frame pointer value.  The
index a3bc29c033db200313b669c55a7cec3fac7d8dcc..0bf8cd06a302c8a6fcb914b94f953cdaa86597a2 100644 (file)
@@ -96,6 +96,10 @@ static bitmap_head temp_bitmap;
 /* Pool for pseudo live ranges.         */
 static object_allocator<lra_live_range> lra_live_range_pool ("live ranges");
 
+/* If non-NULL, the source operand of a register to register copy for which
+   we should not add a conflict with the copy's destination operand.  */
+static rtx ignore_reg_for_conflicts;
+
 /* Free live range list LR.  */
 static void
 free_live_range_list (lra_live_range_t lr)
@@ -239,11 +243,9 @@ make_hard_regno_live (int regno)
 
 /* Process the definition of hard register REGNO.  This updates
    hard_regs_live, START_DYING and conflict hard regs for living
-   pseudos.  Conflict hard regs for the pic pseudo is not updated if
-   REGNO is REAL_PIC_OFFSET_TABLE_REGNUM and CHECK_PIC_PSEUDO_P is
-   true.  */
+   pseudos.  */
 static void
-make_hard_regno_dead (int regno, bool check_pic_pseudo_p ATTRIBUTE_UNUSED)
+make_hard_regno_dead (int regno)
 {
   lra_assert (regno < FIRST_PSEUDO_REGISTER);
   if (! TEST_HARD_REG_BIT (hard_regs_live, regno))
@@ -251,13 +253,12 @@ make_hard_regno_dead (int regno, bool check_pic_pseudo_p ATTRIBUTE_UNUSED)
   sparseset_set_bit (start_dying, regno);
   unsigned int i;
   EXECUTE_IF_SET_IN_SPARSESET (pseudos_live, i)
-#ifdef REAL_PIC_OFFSET_TABLE_REGNUM
-    if (! check_pic_pseudo_p
-       || regno != REAL_PIC_OFFSET_TABLE_REGNUM
-       || pic_offset_table_rtx == NULL
-       || i != REGNO (pic_offset_table_rtx))
-#endif
+    {
+      if (ignore_reg_for_conflicts != NULL_RTX
+         && REGNO (ignore_reg_for_conflicts) == i)
+       continue;
       SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno);
+    }
   CLEAR_HARD_REG_BIT (hard_regs_live, regno);
   if (fixed_regs[regno] || TEST_HARD_REG_BIT (hard_regs_spilled_into, regno))
     {
@@ -294,14 +295,41 @@ static void
 mark_pseudo_dead (int regno, int point)
 {
   lra_live_range_t p;
+  int ignore_regno = -1;
+  int end_regno = -1;
 
   lra_assert (regno >= FIRST_PSEUDO_REGISTER);
   lra_assert (sparseset_bit_p (pseudos_live, regno));
   sparseset_clear_bit (pseudos_live, regno);
   sparseset_set_bit (start_dying, regno);
 
+  /* Check whether any part of IGNORE_REG_FOR_CONFLICTS already conflicts
+     with REGNO.  */
+  if (ignore_reg_for_conflicts != NULL_RTX
+      && REGNO (ignore_reg_for_conflicts) < FIRST_PSEUDO_REGISTER)
+    {
+      end_regno = END_REGNO (ignore_reg_for_conflicts);
+      int src_regno = ignore_regno = REGNO (ignore_reg_for_conflicts);
+
+      while (src_regno < end_regno)
+       {
+         if (TEST_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs,
+                                src_regno))
+           {
+             ignore_regno = end_regno = -1;
+             break;
+           }
+         src_regno++;
+       }
+    }
+
   IOR_HARD_REG_SET (lra_reg_info[regno].conflict_hard_regs, hard_regs_live);
 
+  /* If IGNORE_REG_FOR_CONFLICTS did not already conflict with REGNO, make
+     sure it still doesn't.  */
+  for (; ignore_regno < end_regno; ignore_regno++)
+    CLEAR_HARD_REG_BIT (lra_reg_info[regno].conflict_hard_regs, ignore_regno);
+
   if (complete_info_p || lra_get_regno_hard_regno (regno) < 0)
     {
       p = lra_reg_info[regno].live_ranges;
@@ -350,7 +378,7 @@ mark_regno_dead (int regno, machine_mode mode, int point)
   if (regno < FIRST_PSEUDO_REGISTER)
     {
       for (last = end_hard_regno (mode, regno); regno < last; regno++)
-       make_hard_regno_dead (regno, false);
+       make_hard_regno_dead (regno);
     }
   else
     {
@@ -747,6 +775,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
        }
 
       call_p = CALL_P (curr_insn);
+      ignore_reg_for_conflicts = non_conflicting_reg_copy_p (curr_insn);
       src_regno = (set != NULL_RTX && REG_P (SET_SRC (set))
                   ? REGNO (SET_SRC (set)) : -1);
       dst_regno = (set != NULL_RTX && REG_P (SET_DEST (set))
@@ -858,14 +887,13 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       for (reg = curr_static_id->hard_regs; reg != NULL; reg = reg->next)
        if (reg->type == OP_OUT
            && ! reg_early_clobber_p (reg, n_alt) && ! reg->subreg_p)
-         make_hard_regno_dead (reg->regno, false);
+         make_hard_regno_dead (reg->regno);
 
       if (curr_id->arg_hard_regs != NULL)
        for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
          if (regno >= FIRST_PSEUDO_REGISTER)
-           /* It is a clobber.  Don't create conflict of used
-              REAL_PIC_OFFSET_TABLE_REGNUM and the pic pseudo.  */
-           make_hard_regno_dead (regno - FIRST_PSEUDO_REGISTER, true);
+           /* It is a clobber.  */
+           make_hard_regno_dead (regno - FIRST_PSEUDO_REGISTER);
 
       if (call_p)
        {
@@ -926,8 +954,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
          make_hard_regno_live (reg->regno);
 
       if (curr_id->arg_hard_regs != NULL)
-       /* Make argument hard registers live.  Don't create conflict
-          of used REAL_PIC_OFFSET_TABLE_REGNUM and the pic pseudo.  */
+       /* Make argument hard registers live.  */
        for (i = 0; (regno = curr_id->arg_hard_regs[i]) >= 0; i++)
          if (regno < FIRST_PSEUDO_REGISTER)
            make_hard_regno_live (regno);
@@ -955,7 +982,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
              if (reg2->type != OP_OUT && reg2->regno == reg->regno)
                break;
            if (reg2 == NULL)
-             make_hard_regno_dead (reg->regno, false);
+             make_hard_regno_dead (reg->regno);
          }
 
       if (need_curr_point_incr)
@@ -990,6 +1017,7 @@ process_bb_lives (basic_block bb, int &curr_point, bool dead_insn_p)
       EXECUTE_IF_SET_IN_SPARSESET (unused_set, j)
        add_reg_note (curr_insn, REG_UNUSED, regno_reg_rtx[j]);
     }
+  ignore_reg_for_conflicts = NULL_RTX;
 
   if (bb_has_eh_pred (bb))
     for (j = 0; ; ++j)
index 818f6ea250a3c73e022b16d26351523ce700ad3f..f34b1670a9388d352a8070ce25ba8d43b534076c 100644 (file)
@@ -1,3 +1,10 @@
+2018-10-05  Peter Bergner  <bergner@linux.ibm.com>
+
+       PR rtl-optimization/86939
+       PR rtl-optimization/87479
+       * gcc.target/powerpc/pr86939.c: New test.
+       * gcc/testsuite/gcc.target/i386/pr49095.c: Fix expected results.
+
 2018-10-05  Bernd Edlinger  <bernd.edlinger@hotmail.de>
 
        * gnat.dg/string_merge1.adb: Fix test expectations.
index 078071910638b076a749b847552e260d8c45ab04..20175e73f14aea9944ec8acfe5eb43112e7a1b82 100644 (file)
@@ -73,4 +73,5 @@ G (long)
 /* { dg-final { scan-assembler-not "test\[lq\]" } } */
 /* The {f,h}{char,short,int,long}xor functions aren't optimized into
    a RMW instruction, so need load, modify and store.  FIXME eventually.  */
-/* { dg-final { scan-assembler-times "\\), %" 8 } } */
+/* { dg-final { scan-assembler-times "\\), %" 57 { target { ia32 } } } } */
+/* { dg-final { scan-assembler-times "\\), %" 45 { target { ! ia32 } } } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr86939.c b/gcc/testsuite/gcc.target/powerpc/pr86939.c
new file mode 100644 (file)
index 0000000..4bc9793
--- /dev/null
@@ -0,0 +1,12 @@
+/* { dg-do compile { target { powerpc*-*-* } } } */
+/* { dg-options "-O2" } */
+
+typedef long (*fptr_t) (void);
+long
+func (fptr_t *p)
+{
+  if (p)
+    return (*p) ();
+  return 0;
+}
+/* { dg-final { scan-assembler-not {mr %?r?12,} } } */