]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR rtl-optimization/23478 (Miscompilation due to reloading of a var that is also...
authorJakub Jelinek <jakub@redhat.com>
Thu, 1 Sep 2005 20:51:09 +0000 (22:51 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 1 Sep 2005 20:51:09 +0000 (22:51 +0200)
PR rtl-optimization/23478
* regs.h (reg_info): Add throw_calls_crossed.
(REG_N_THROWING_CALLS_CROSSED): Define.
* flow.c (allocate_reg_life_data): Initialize
REG_N_THROWING_CALLS_CROSSED.
(propagate_one_insn, attempt_auto_inc): Update
REG_N_THROWING_CALLS_CROSSED.
* local-alloc.c (struct qty): Add n_throwing_calls_crossed field.
(alloc_qty): Initialize it.
(update_equiv_regs): Clear REG_N_THROWING_CALLS_CROSSED.
(combine_regs): Combine also n_throwing_calls_crossed fields.
(find_free_reg): Don't attempt to caller-save pseudos crossing
calls that might throw.
* global.c (struct allocno): Add throwing_calls_crossed field.
(global_alloc): Initialize throwing_calls_crossed.
(find_reg): Don't attempt to caller-save pseudos crossing calls that
might throw.

* g++.dg/opt/pr23478.C: New test.

From-SVN: r103745

gcc/ChangeLog
gcc/flow.c
gcc/global.c
gcc/local-alloc.c
gcc/regs.h
gcc/testsuite/ChangeLog

index f4cc5d6fceb7a15a39e230676c2c994f5a9e8520..e815b00a583d334e77bde9444ec499241003748f 100644 (file)
@@ -1,3 +1,23 @@
+2005-09-01  Jakub Jelinek  <jakub@redhat.com>
+
+       PR rtl-optimization/23478
+       * regs.h (reg_info): Add throw_calls_crossed.
+       (REG_N_THROWING_CALLS_CROSSED): Define.
+       * flow.c (allocate_reg_life_data): Initialize
+       REG_N_THROWING_CALLS_CROSSED.
+       (propagate_one_insn, attempt_auto_inc): Update
+       REG_N_THROWING_CALLS_CROSSED.
+       * local-alloc.c (struct qty): Add n_throwing_calls_crossed field.
+       (alloc_qty): Initialize it.
+       (update_equiv_regs): Clear REG_N_THROWING_CALLS_CROSSED.
+       (combine_regs): Combine also n_throwing_calls_crossed fields.
+       (find_free_reg): Don't attempt to caller-save pseudos crossing
+       calls that might throw.
+       * global.c (struct allocno): Add throwing_calls_crossed field.
+       (global_alloc): Initialize throwing_calls_crossed.
+       (find_reg): Don't attempt to caller-save pseudos crossing calls that
+       might throw.
+
 2005-09-01  Richard Earnshaw  <richard.earnshaw@arm.com>
 
        PR rtl-optimization/17810 target/15342
index fed908dc451f3c85cd7bf9adb9fadc6fde65ad07..9f1e1b79ad4e5ccba2157291c05cfb7c5d7fe067 100644 (file)
@@ -104,7 +104,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
    life_analysis fills in certain vectors containing information about
    register usage: REG_N_REFS, REG_N_DEATHS, REG_N_SETS, REG_LIVE_LENGTH,
-   REG_N_CALLS_CROSSED and REG_BASIC_BLOCK.
+   REG_N_CALLS_CROSSED, REG_N_THROWING_CALLS_CROSSED and REG_BASIC_BLOCK.
 
    life_analysis sets current_function_sp_is_unchanging if the function
    doesn't modify the stack pointer.  */
@@ -1470,6 +1470,7 @@ allocate_reg_life_data (void)
       REG_N_REFS (i) = 0;
       REG_N_DEATHS (i) = 0;
       REG_N_CALLS_CROSSED (i) = 0;
+      REG_N_THROWING_CALLS_CROSSED (i) = 0;
       REG_LIVE_LENGTH (i) = 0;
       REG_FREQ (i) = 0;
       REG_BASIC_BLOCK (i) = REG_BLOCK_UNKNOWN;
@@ -1688,8 +1689,13 @@ propagate_one_insn (struct propagate_block_info *pbi, rtx insn)
         record this for them.  */
 
       if (GET_CODE (insn) == CALL_INSN && (flags & PROP_REG_INFO))
-       EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
-                                  { REG_N_CALLS_CROSSED (i)++; });
+       {
+         EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
+                                    { REG_N_CALLS_CROSSED (i)++; });
+         if (can_throw_internal (insn))
+           EXECUTE_IF_SET_IN_REG_SET (pbi->reg_live, 0, i,
+                                    { REG_N_THROWING_CALLS_CROSSED (i)++; });
+       }
 
       /* Record sets.  Do this even for dead instructions, since they
         would have killed the values if they hadn't been deleted.  */
@@ -3365,7 +3371,11 @@ attempt_auto_inc (struct propagate_block_info *pbi, rtx inc, rtx insn,
         that REGNO now crosses them.  */
       for (temp = insn; temp != incr; temp = NEXT_INSN (temp))
        if (GET_CODE (temp) == CALL_INSN)
-         REG_N_CALLS_CROSSED (regno)++;
+         {
+           REG_N_CALLS_CROSSED (regno)++;
+           if (can_throw_internal (temp))
+             REG_N_THROWING_CALLS_CROSSED (regno)++;
+         }
 
       /* Invalidate alias info for Q since we just changed its value.  */
       clear_reg_alias_info (q);
index de765b36731e24a0d4a59c52b21e01f17f0b58d2..13e41cbb55045f5c59c696c8b3475359173c939d 100644 (file)
@@ -96,6 +96,9 @@ struct allocno
   /* Number of calls crossed by each allocno.  */
   int calls_crossed;
 
+  /* Number of calls that might throw crossed by each allocno.  */
+  int throwing_calls_crossed;
+
   /* Number of refs to each allocno.  */
   int n_refs;
 
@@ -469,6 +472,8 @@ global_alloc (FILE *file)
        allocno[num].reg = i;
        allocno[num].size = PSEUDO_REGNO_SIZE (i);
        allocno[num].calls_crossed += REG_N_CALLS_CROSSED (i);
+       allocno[num].throwing_calls_crossed
+         += REG_N_THROWING_CALLS_CROSSED (i);
        allocno[num].n_refs += REG_N_REFS (i);
        allocno[num].freq += REG_FREQ (i);
        if (allocno[num].live_length < REG_LIVE_LENGTH (i))
@@ -1187,9 +1192,11 @@ find_reg (int num, HARD_REG_SET losers, int alt_regs_p, int accept_call_clobbere
     {
       /* Did not find a register.  If it would be profitable to
         allocate a call-clobbered register and save and restore it
-        around calls, do that.  */
+        around calls, do that.  Don't do this if it crosses any calls
+        that might throw.  */
       if (! accept_call_clobbered
          && allocno[num].calls_crossed != 0
+         && allocno[num].throwing_calls_crossed == 0
          && CALLER_SAVE_PROFITABLE (allocno[num].n_refs,
                                     allocno[num].calls_crossed))
        {
index 61ff7fbc6b2b039b6ba1c55618e28a2fa1fb5732..6b1203d15afad03b4f2de1167b12113307121bf9 100644 (file)
@@ -120,6 +120,11 @@ struct qty
 
   int n_calls_crossed;
 
+  /* Number of times a reg tied to given qty lives across a CALL_INSN
+     that might throw.  */
+
+  int n_throwing_calls_crossed;
+
   /* The register number of one pseudo register whose reg_qty value is Q.
      This register should be the head of the chain
      maintained in reg_next_in_qty.  */
@@ -317,6 +322,7 @@ alloc_qty (int regno, enum machine_mode mode, int size, int birth)
   qty[qtyno].mode = mode;
   qty[qtyno].birth = birth;
   qty[qtyno].n_calls_crossed = REG_N_CALLS_CROSSED (regno);
+  qty[qtyno].n_throwing_calls_crossed = REG_N_THROWING_CALLS_CROSSED (regno);
   qty[qtyno].min_class = reg_preferred_class (regno);
   qty[qtyno].alternate_class = reg_alternate_class (regno);
   qty[qtyno].n_refs = REG_N_REFS (regno);
@@ -1119,6 +1125,7 @@ update_equiv_regs (void)
 
                      REG_BASIC_BLOCK (regno) = bb->index;
                      REG_N_CALLS_CROSSED (regno) = 0;
+                     REG_N_THROWING_CALLS_CROSSED (regno) = 0;
                      REG_LIVE_LENGTH (regno) = 2;
 
                      if (insn == BB_HEAD (bb))
@@ -1946,6 +1953,8 @@ combine_regs (rtx usedreg, rtx setreg, int may_save_copy, int insn_number,
 
       /* Update info about quantity SQTY.  */
       qty[sqty].n_calls_crossed += REG_N_CALLS_CROSSED (sreg);
+      qty[sqty].n_throwing_calls_crossed
+       += REG_N_THROWING_CALLS_CROSSED (sreg);
       qty[sqty].n_refs += REG_N_REFS (sreg);
       qty[sqty].freq += REG_FREQ (sreg);
       if (usize < ssize)
@@ -2251,12 +2260,14 @@ find_free_reg (enum reg_class class, enum machine_mode mode, int qtyno,
 
   /* We need not check to see if the current function has nonlocal
      labels because we don't put any pseudos that are live over calls in
-     registers in that case.  */
+     registers in that case.  Avoid putting pseudos crossing calls that
+     might throw into call used registers.  */
 
   if (! accept_call_clobbered
       && flag_caller_saves
       && ! just_try_suggested
       && qty[qtyno].n_calls_crossed != 0
+      && qty[qtyno].n_throwing_calls_crossed == 0
       && CALLER_SAVE_PROFITABLE (qty[qtyno].n_refs,
                                 qty[qtyno].n_calls_crossed))
     {
index bb1f43d0deddfb2c45b27d7fe779336df57df59d..e9ab2d808643e7ec7f1af44095b31e92349a138c 100644 (file)
@@ -59,6 +59,7 @@ typedef struct reg_info_def
   int deaths;                  /* # of times (REG n) dies */
   int live_length;             /* # of instructions (REG n) is live */
   int calls_crossed;           /* # of calls (REG n) is live across */
+  int throw_calls_crossed;     /* # of calls that may throw (REG n) is live across */
   int basic_block;             /* # of basic blocks (REG n) is used in */
   char changes_mode;           /* whether (SUBREG (REG n)) exists and
                                   is illegal.  */
@@ -125,6 +126,12 @@ extern varray_type reg_n_info;
 
 #define REG_N_CALLS_CROSSED(N) (VARRAY_REG (reg_n_info, N)->calls_crossed)
 
+/* Indexed by N, gives number of CALL_INSNS that may throw, across which
+   (REG n) is live.  */
+
+#define REG_N_THROWING_CALLS_CROSSED(N) \
+  (VARRAY_REG (reg_n_info, N)->throw_calls_crossed)
+
 /* Total number of instructions at which (REG n) is live.
    The larger this is, the less priority (REG n) gets for
    allocation in a hard register (in global-alloc).
index f77f197046655f2c4fd68aae756bb7dedb809b36..b533b210b332ccdd952a155fc1a3cf010fbd856f 100644 (file)
@@ -1,3 +1,8 @@
+2005-09-01  Jakub Jelinek  <jakub@redhat.com>
+
+       PR rtl-optimization/23478
+       * g++.dg/opt/pr23478.C: New test.
+
 2005-09-01  Volker Reichelt  <reichelt@igpm.rwth-aachen.de>
 
        Backport: