OSDN Git Service

2008-10-15 Vladimir Makarov <vmakarov@redhat.com>
authorvmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 16 Oct 2008 00:51:34 +0000 (00:51 +0000)
committervmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>
Thu, 16 Oct 2008 00:51:34 +0000 (00:51 +0000)
PR middle-end/37535
* ira-lives.c (mark_early_clobbers): Remove.
(make_pseudo_conflict, check_and_make_def_use_conflicts,
check_and_make_def_conflicts,
make_early_clobber_and_input_conflicts,
mark_hard_reg_early_clobbers): New functions.
(process_bb_node_lives): Call
make_early_clobber_and_input_conflicts and
mark_hard_reg_early_clobbers.  Make hard register inputs live
again.

* doc/rtl.texi (clobber): Change descriotion of RA behaviour for
early clobbers of pseudo-registers.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@141160 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/doc/rtl.texi
gcc/ira-lives.c

index 0cf0dec..68ae6ec 100644 (file)
@@ -1,5 +1,21 @@
 2008-10-15  Vladimir Makarov  <vmakarov@redhat.com>
 
+       PR middle-end/37535
+       * ira-lives.c (mark_early_clobbers): Remove.
+       (make_pseudo_conflict, check_and_make_def_use_conflicts,
+       check_and_make_def_conflicts,
+       make_early_clobber_and_input_conflicts,
+       mark_hard_reg_early_clobbers): New functions.
+       (process_bb_node_lives): Call
+       make_early_clobber_and_input_conflicts and
+       mark_hard_reg_early_clobbers.  Make hard register inputs live
+       again.
+
+       * doc/rtl.texi (clobber): Change descriotion of RA behaviour for
+       early clobbers of pseudo-registers.
+       
+2008-10-15  Vladimir Makarov  <vmakarov@redhat.com>
+
        PR middle-end/37674
        * ira-build.c (ira_flattening): Recalculate
        ALLOCNO_TOTAL_NO_STACK_REG_P and ALLOCNO_TOTAL_CONFLICT_HARD_REGS
index 701e490..1411f24 100644 (file)
@@ -2917,11 +2917,12 @@ constituent instructions might not.
 When a @code{clobber} expression for a register appears inside a
 @code{parallel} with other side effects, the register allocator
 guarantees that the register is unoccupied both before and after that
-insn if it is a hard register clobber or the @samp{&} constraint
-is specified for at least one alternative (@pxref{Modifiers}) of the
-clobber.  However, the reload phase may allocate a register used for
-one of the inputs unless the @samp{&} constraint is specified for the
-selected alternative.  You can clobber either a specific hard
+insn if it is a hard register clobber.  For pseudo-register clobber,
+the register allocator and the reload pass do not assign the same hard
+register to the clobber and the input operands if there is an insn
+alternative containing the @samp{&} constraint (@pxref{Modifiers}) for
+the clobber and the hard register is in register classes of the
+clobber in the alternative.  You can clobber either a specific hard
 register, a pseudo register, or a @code{scratch} expression; in the
 latter two cases, GCC will allocate a hard register that is available
 there for use as a temporary.
index 89343fe..f4b2d6d 100644 (file)
@@ -349,39 +349,169 @@ mark_ref_dead (df_ref def)
   mark_reg_dead (reg);
 }
 
-/* Mark early clobber registers of the current INSN as live (if
-   LIVE_P) or dead.  Return true if there are such registers.  */
+/* Make pseudo REG conflicting with pseudo DREG, if the 1st pseudo
+   class is intersected with class CL.  Advance the current program
+   point before making the conflict if ADVANCE_P.  Return TRUE if we
+   will need to advance the current program point.  */
 static bool
-mark_early_clobbers (rtx insn, bool live_p)
+make_pseudo_conflict (rtx reg, enum reg_class cl, rtx dreg, bool advance_p)
 {
-  int alt;
-  int def;
-  df_ref *def_rec;
-  bool set_p = false;
+  ira_allocno_t a;
 
-  for (def = 0; def < recog_data.n_operands; def++)
-    {
-      rtx dreg = recog_data.operand[def];
-      
-      if (GET_CODE (dreg) == SUBREG)
-       dreg = SUBREG_REG (dreg);
-      if (! REG_P (dreg))
-       continue;
+  if (GET_CODE (reg) == SUBREG)
+    reg = SUBREG_REG (reg);
+  
+  if (! REG_P (reg) || REGNO (reg) < FIRST_PSEUDO_REGISTER)
+    return advance_p;
+  
+  a = ira_curr_regno_allocno_map[REGNO (reg)];
+  if (! reg_classes_intersect_p (cl, ALLOCNO_COVER_CLASS (a)))
+    return advance_p;
 
-      for (alt = 0; alt < recog_data.n_alternatives; alt++)
-       if ((recog_op_alt[def][alt].earlyclobber)
-           && (recog_op_alt[def][alt].cl != NO_REGS))
-         break;
+  if (advance_p)
+    curr_point++;
 
-      if (alt >= recog_data.n_alternatives)
-       continue;
+  mark_reg_live (reg);
+  mark_reg_live (dreg);
+  mark_reg_dead (reg);
+  mark_reg_dead (dreg);
+
+  return false;
+}
 
-      if (live_p)
-       mark_reg_live (dreg);
+/* Check and make if necessary conflicts for pseudo DREG of class
+   DEF_CL of the current insn with input operand USE of class USE_CL.
+   Advance the current program point before making the conflict if
+   ADVANCE_P.  Return TRUE if we will need to advance the current
+   program point.  */
+static bool
+check_and_make_def_use_conflict (rtx dreg, enum reg_class def_cl,
+                                int use, enum reg_class use_cl,
+                                bool advance_p)
+{
+  if (! reg_classes_intersect_p (def_cl, use_cl))
+    return advance_p;
+  
+  advance_p = make_pseudo_conflict (recog_data.operand[use],
+                                   use_cl, dreg, advance_p);
+  /* Reload may end up swapping commutative operands, so you
+     have to take both orderings into account.  The
+     constraints for the two operands can be completely
+     different.  (Indeed, if the constraints for the two
+     operands are the same for all alternatives, there's no
+     point marking them as commutative.)  */
+  if (use < recog_data.n_operands + 1
+      && recog_data.constraints[use][0] == '%')
+    advance_p
+      = make_pseudo_conflict (recog_data.operand[use + 1],
+                             use_cl, dreg, advance_p);
+  if (use >= 1
+      && recog_data.constraints[use - 1][0] == '%')
+    advance_p
+      = make_pseudo_conflict (recog_data.operand[use - 1],
+                             use_cl, dreg, advance_p);
+  return advance_p;
+}
+
+/* Check and make if necessary conflicts for definition DEF of class
+   DEF_CL of the current insn with input operands.  Process only
+   constraints of alternative ALT.  */
+static void
+check_and_make_def_conflict (int alt, int def, enum reg_class def_cl)
+{
+  int use, use_match;
+  ira_allocno_t a;
+  enum reg_class use_cl, acl;
+  bool advance_p;
+  rtx dreg = recog_data.operand[def];
+       
+  if (def_cl == NO_REGS)
+    return;
+  
+  if (GET_CODE (dreg) == SUBREG)
+    dreg = SUBREG_REG (dreg);
+  
+  if (! REG_P (dreg) || REGNO (dreg) < FIRST_PSEUDO_REGISTER)
+    return;
+  
+  a = ira_curr_regno_allocno_map[REGNO (dreg)];
+  acl = ALLOCNO_COVER_CLASS (a);
+  if (! reg_classes_intersect_p (acl, def_cl))
+    return;
+  
+  advance_p = true;
+  
+  for (use = 0; use < recog_data.n_operands; use++)
+    {
+      if (use == def || recog_data.operand_type[use] == OP_OUT)
+       return;
+      
+      if (recog_op_alt[use][alt].anything_ok)
+       use_cl = ALL_REGS;
       else
-       mark_reg_dead (dreg);
-      set_p = true;
+       use_cl = recog_op_alt[use][alt].cl;
+      
+      advance_p = check_and_make_def_use_conflict (dreg, def_cl, use,
+                                                  use_cl, advance_p);
+      
+      if ((use_match = recog_op_alt[use][alt].matches) >= 0)
+       {
+         if (use_match == def)
+           return;
+         
+         if (recog_op_alt[use_match][alt].anything_ok)
+           use_cl = ALL_REGS;
+         else
+           use_cl = recog_op_alt[use_match][alt].cl;
+         advance_p = check_and_make_def_use_conflict (dreg, def_cl, use,
+                                                      use_cl, advance_p);
+       }
     }
+}
+
+/* Make conflicts of early clobber pseudo registers of the current
+   insn with its inputs.  Avoid introducing unnecessary conflicts by
+   checking classes of the constraints and pseudos because otherwise
+   significant code degradation is possible for some targets.  */
+static void
+make_early_clobber_and_input_conflicts (void)
+{
+  int alt;
+  int def, def_match;
+  enum reg_class def_cl;
+
+  for (alt = 0; alt < recog_data.n_alternatives; alt++)
+    for (def = 0; def < recog_data.n_operands; def++)
+      {
+       def_cl = NO_REGS;
+       if (recog_op_alt[def][alt].earlyclobber)
+         {
+           if (recog_op_alt[def][alt].anything_ok)
+             def_cl = ALL_REGS;
+           else
+             def_cl = recog_op_alt[def][alt].cl;
+           check_and_make_def_conflict (alt, def, def_cl);
+         }
+       if ((def_match = recog_op_alt[def][alt].matches) >= 0
+           && (recog_op_alt[def_match][alt].earlyclobber
+               || recog_op_alt[def][alt].earlyclobber))
+         {
+           if (recog_op_alt[def_match][alt].anything_ok)
+             def_cl = ALL_REGS;
+           else
+             def_cl = recog_op_alt[def_match][alt].cl;
+           check_and_make_def_conflict (alt, def, def_cl);
+         }
+      }
+}
+
+/* Mark early clobber hard registers of the current INSN as live (if
+   LIVE_P) or dead.  Return true if there are such registers.  */
+static bool
+mark_hard_reg_early_clobbers (rtx insn, bool live_p)
+{
+  df_ref *def_rec;
+  bool set_p = false;
 
   for (def_rec = DF_INSN_DEFS (insn); *def_rec; def_rec++)
     if (DF_REF_FLAGS_IS_SET (*def_rec, DF_REF_MUST_CLOBBER))
@@ -792,25 +922,36 @@ process_bb_node_lives (ira_loop_tree_node_t loop_tree_node)
                }
            }
          
+         make_early_clobber_and_input_conflicts ();
+
          curr_point++;
 
          /* Mark each used value as live.  */
          for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
            mark_ref_live (*use_rec);
 
-         set_p = mark_early_clobbers (insn, true);
-
          process_single_reg_class_operands (true, freq);
          
+         set_p = mark_hard_reg_early_clobbers (insn, true);
+
          if (set_p)
            {
-             mark_early_clobbers (insn, false);
+             mark_hard_reg_early_clobbers (insn, false);
 
-             /* Mark each used value as live again.  For example, a
+             /* Mark each hard reg as live again.  For example, a
                 hard register can be in clobber and in an insn
                 input.  */
              for (use_rec = DF_INSN_USES (insn); *use_rec; use_rec++)
-               mark_ref_live (*use_rec);
+               {
+                 rtx ureg = DF_REF_REG (*use_rec);
+                 
+                 if (GET_CODE (ureg) == SUBREG)
+                   ureg = SUBREG_REG (ureg);
+                 if (! REG_P (ureg) || REGNO (ureg) >= FIRST_PSEUDO_REGISTER)
+                   continue;
+                 
+                 mark_ref_live (*use_rec);
+               }
            }
 
          curr_point++;