This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR target/12900


Hi,

This is again a consequence of the reg-stack edge purging patch.  The patch 
uses purge_dead_edges to try to purge edges associated with insns that have 
been deleted.  purge_dead_edges requires the CFG to be valid to do properly 
its work.  Now the reg-stack pass may temporarily damage the CFG, in that it 
may add 'move' insns past an abnormal call (this is the reason why the pass 
calls fixup_abnormal_edges later).  So purge_dead_edges may be fooled into 
thinking that valid edges are dead, which subsequently disables 
fixup_abnormal_edges and causes verify_flow_info to abort afterwards.

The proposed fix is to make sure that the control flow insn of the block 
being processed has been deleted before calling purge_dead_edges.  I think 
this is enough to guarantee that the compiler won't delete valid edges.

Bootstrapped/regtested on i586-redhat-linux-gnu (mainline except Ada).
The testcase doesn't fail on the 3.3 branch but the regression is latent so I 
think it would be wise to put it there too.


2003-11-06  Eric Botcazou  <ebotcazou@libertysurf.fr>

	PR target/12900
	* reg-stack (move_for_stack_reg): New prototype.  Return
	whether a control flow insn was deleted.
	(subst_stack_regs_pat): Likewise, using the information provided
	by move_for_stack_reg.
	(subst_stack_regs): Likewise, using the information provided
	by subst_stack_regs_pat.
	(convert_regs_1): Record whether a control flow insn was deleted,
	using the information provided by subst_stack_regs.  Purge dead
	edges only if a control flow insn was deleted.


2003-11-06  Eric Botcazou  <ebotcazou@libertysurf.fr>

	* g++.dg/opt/reg-stack4.C: New test.


-- 
Eric Botcazou
Index: reg-stack.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/reg-stack.c,v
retrieving revision 1.137
diff -c -p -r1.137 reg-stack.c
*** reg-stack.c	30 Oct 2003 21:01:14 -0000	1.137
--- reg-stack.c	5 Nov 2003 13:39:20 -0000
*************** static void remove_regno_note (rtx, enum
*** 249,261 ****
  static int get_hard_regnum (stack, rtx);
  static rtx emit_pop_insn (rtx, stack, rtx, enum emit_where);
  static void emit_swap_insn (rtx, stack, rtx);
! static void move_for_stack_reg (rtx, stack, rtx);
  static int swap_rtx_condition_1 (rtx);
  static int swap_rtx_condition (rtx);
  static void compare_for_stack_reg (rtx, stack, rtx);
! static void subst_stack_regs_pat (rtx, stack, rtx);
  static void subst_asm_stack_regs (rtx, stack);
! static void subst_stack_regs (rtx, stack);
  static void change_stack (rtx, stack, stack, enum emit_where);
  static int convert_regs_entry (void);
  static void convert_regs_exit (void);
--- 249,261 ----
  static int get_hard_regnum (stack, rtx);
  static rtx emit_pop_insn (rtx, stack, rtx, enum emit_where);
  static void emit_swap_insn (rtx, stack, rtx);
! static bool move_for_stack_reg (rtx, stack, rtx);
  static int swap_rtx_condition_1 (rtx);
  static int swap_rtx_condition (rtx);
  static void compare_for_stack_reg (rtx, stack, rtx);
! static bool subst_stack_regs_pat (rtx, stack, rtx);
  static void subst_asm_stack_regs (rtx, stack);
! static bool subst_stack_regs (rtx, stack);
  static void change_stack (rtx, stack, stack, enum emit_where);
  static int convert_regs_entry (void);
  static void convert_regs_exit (void);
*************** emit_swap_insn (rtx insn, stack regstack
*** 1028,1042 ****
  }
  
  /* Handle a move to or from a stack register in PAT, which is in INSN.
!    REGSTACK is the current stack.  */
  
! static void
  move_for_stack_reg (rtx insn, stack regstack, rtx pat)
  {
    rtx *psrc =  get_true_reg (&SET_SRC (pat));
    rtx *pdest = get_true_reg (&SET_DEST (pat));
    rtx src, dest;
    rtx note;
  
    src = *psrc; dest = *pdest;
  
--- 1028,1044 ----
  }
  
  /* Handle a move to or from a stack register in PAT, which is in INSN.
!    REGSTACK is the current stack.  Return whether a control flow insn
!    was deleted in the process.  */
  
! static bool
  move_for_stack_reg (rtx insn, stack regstack, rtx pat)
  {
    rtx *psrc =  get_true_reg (&SET_SRC (pat));
    rtx *pdest = get_true_reg (&SET_DEST (pat));
    rtx src, dest;
    rtx note;
+   bool control_flow_insn_deleted = false;
  
    src = *psrc; dest = *pdest;
  
*************** move_for_stack_reg (rtx insn, stack regs
*** 1066,1086 ****
  	     If so, just pop the src.  */
  
  	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
  	    {
! 	      emit_pop_insn (insn, regstack, src, EMIT_AFTER);
! 
! 	      delete_insn (insn);
! 	      return;
  	    }
  
! 	  regstack->reg[i] = REGNO (dest);
! 
! 	  SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
! 	  CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
! 
  	  delete_insn (insn);
! 
! 	  return;
  	}
  
        /* The source reg does not die.  */
--- 1068,1084 ----
  	     If so, just pop the src.  */
  
  	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
+ 	    emit_pop_insn (insn, regstack, src, EMIT_AFTER);
+ 	  else
  	    {
! 	      regstack->reg[i] = REGNO (dest);
! 	      SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
! 	      CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
  	    }
  
! 	  control_flow_insn_deleted |= control_flow_insn_p (insn);
  	  delete_insn (insn);
! 	  return control_flow_insn_deleted;
  	}
  
        /* The source reg does not die.  */
*************** move_for_stack_reg (rtx insn, stack regs
*** 1095,1102 ****
  	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
  	    emit_pop_insn (insn, regstack, dest, EMIT_AFTER);
  
  	  delete_insn (insn);
! 	  return;
  	}
  
        /* The destination ought to be dead.  */
--- 1093,1101 ----
  	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
  	    emit_pop_insn (insn, regstack, dest, EMIT_AFTER);
  
+ 	  control_flow_insn_deleted |= control_flow_insn_p (insn);
  	  delete_insn (insn);
! 	  return control_flow_insn_deleted;
  	}
  
        /* The destination ought to be dead.  */
*************** move_for_stack_reg (rtx insn, stack regs
*** 1165,1170 ****
--- 1164,1171 ----
      }
    else
      abort ();
+ 
+   return control_flow_insn_deleted;
  }
  
  /* Swap the condition on a branch, if there is one.  Return true if we
*************** compare_for_stack_reg (rtx insn, stack r
*** 1376,1387 ****
  }
  
  /* Substitute new registers in PAT, which is part of INSN.  REGSTACK
!    is the current register layout.  */
  
! static void
  subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
  {
    rtx *dest, *src;
  
    switch (GET_CODE (pat))
      {
--- 1377,1390 ----
  }
  
  /* Substitute new registers in PAT, which is part of INSN.  REGSTACK
!    is the current register layout.  Return whether a control flow insn
!    was deleted in the process.  */
  
! static bool
  subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
  {
    rtx *dest, *src;
+   bool control_flow_insn_deleted = false;
  
    switch (GET_CODE (pat))
      {
*************** subst_stack_regs_pat (rtx insn, stack re
*** 1393,1399 ****
  	  && find_regno_note (insn, REG_DEAD, REGNO (*src)))
  	{
  	  emit_pop_insn (insn, regstack, *src, EMIT_AFTER);
! 	  return;
  	}
        /* ??? Uninitialized USE should not happen.  */
        else if (get_hard_regnum (regstack, *src) == -1)
--- 1396,1402 ----
  	  && find_regno_note (insn, REG_DEAD, REGNO (*src)))
  	{
  	  emit_pop_insn (insn, regstack, *src, EMIT_AFTER);
! 	  return control_flow_insn_deleted;
  	}
        /* ??? Uninitialized USE should not happen.  */
        else if (get_hard_regnum (regstack, *src) == -1)
*************** subst_stack_regs_pat (rtx insn, stack re
*** 1443,1449 ****
  				       FP_MODE_REG (REGNO (*dest), SFmode),
  				       nan);
  		    PATTERN (insn) = pat;
! 		    move_for_stack_reg (insn, regstack, pat);
  		  }
  		if (! note && COMPLEX_MODE_P (GET_MODE (*dest))
  		    && get_hard_regnum (regstack, FP_MODE_REG (REGNO (*dest), DFmode)) == -1)
--- 1446,1452 ----
  				       FP_MODE_REG (REGNO (*dest), SFmode),
  				       nan);
  		    PATTERN (insn) = pat;
! 		    control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
  		  }
  		if (! note && COMPLEX_MODE_P (GET_MODE (*dest))
  		    && get_hard_regnum (regstack, FP_MODE_REG (REGNO (*dest), DFmode)) == -1)
*************** subst_stack_regs_pat (rtx insn, stack re
*** 1452,1458 ****
  				       FP_MODE_REG (REGNO (*dest) + 1, SFmode),
  				       nan);
  		    PATTERN (insn) = pat;
! 		    move_for_stack_reg (insn, regstack, pat);
  		  }
  	      }
  	  }
--- 1455,1461 ----
  				       FP_MODE_REG (REGNO (*dest) + 1, SFmode),
  				       nan);
  		    PATTERN (insn) = pat;
! 		    control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
  		  }
  	      }
  	  }
*************** subst_stack_regs_pat (rtx insn, stack re
*** 1475,1481 ****
  		&& (GET_CODE (*src) == REG || GET_CODE (*src) == MEM
  		    || GET_CODE (*src) == CONST_DOUBLE)))
  	  {
! 	    move_for_stack_reg (insn, regstack, pat);
  	    break;
  	  }
  
--- 1478,1484 ----
  		&& (GET_CODE (*src) == REG || GET_CODE (*src) == MEM
  		    || GET_CODE (*src) == CONST_DOUBLE)))
  	  {
! 	    control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
  	    break;
  	  }
  
*************** subst_stack_regs_pat (rtx insn, stack re
*** 1879,1884 ****
--- 1882,1889 ----
      default:
        break;
      }
+ 
+   return control_flow_insn_deleted;
  }
  
  /* Substitute hard regnums for any stack regs in INSN, which has
*************** subst_asm_stack_regs (rtx insn, stack re
*** 2176,2187 ****
  /* Substitute stack hard reg numbers for stack virtual registers in
     INSN.  Non-stack register numbers are not changed.  REGSTACK is the
     current stack content.  Insns may be emitted as needed to arrange the
!    stack for the 387 based on the contents of the insn.  */
  
! static void
  subst_stack_regs (rtx insn, stack regstack)
  {
    rtx *note_link, note;
    int i;
  
    if (GET_CODE (insn) == CALL_INSN)
--- 2181,2194 ----
  /* Substitute stack hard reg numbers for stack virtual registers in
     INSN.  Non-stack register numbers are not changed.  REGSTACK is the
     current stack content.  Insns may be emitted as needed to arrange the
!    stack for the 387 based on the contents of the insn.  Return whether
!    a control flow insn was deleted in the process.  */
  
! static bool
  subst_stack_regs (rtx insn, stack regstack)
  {
    rtx *note_link, note;
+   bool control_flow_insn_deleted = false;
    int i;
  
    if (GET_CODE (insn) == CALL_INSN)
*************** subst_stack_regs (rtx insn, stack regsta
*** 2222,2246 ****
  	     Any REG_UNUSED notes will be handled by subst_asm_stack_regs.  */
  
  	  subst_asm_stack_regs (insn, regstack);
! 	  return;
  	}
  
        if (GET_CODE (PATTERN (insn)) == PARALLEL)
  	for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
  	  {
  	    if (stack_regs_mentioned_p (XVECEXP (PATTERN (insn), 0, i)))
! 	      subst_stack_regs_pat (insn, regstack,
! 				    XVECEXP (PATTERN (insn), 0, i));
  	  }
        else
! 	subst_stack_regs_pat (insn, regstack, PATTERN (insn));
      }
  
    /* subst_stack_regs_pat may have deleted a no-op insn.  If so, any
       REG_UNUSED will already have been dealt with, so just return.  */
  
    if (GET_CODE (insn) == NOTE || INSN_DELETED_P (insn))
!     return;
  
    /* If there is a REG_UNUSED note on a stack register on this insn,
       the indicated reg must be popped.  The REG_UNUSED note is removed,
--- 2229,2255 ----
  	     Any REG_UNUSED notes will be handled by subst_asm_stack_regs.  */
  
  	  subst_asm_stack_regs (insn, regstack);
! 	  return control_flow_insn_deleted;
  	}
  
        if (GET_CODE (PATTERN (insn)) == PARALLEL)
  	for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
  	  {
  	    if (stack_regs_mentioned_p (XVECEXP (PATTERN (insn), 0, i)))
! 	      control_flow_insn_deleted
! 		|= subst_stack_regs_pat (insn, regstack,
! 					 XVECEXP (PATTERN (insn), 0, i));
  	  }
        else
! 	control_flow_insn_deleted
! 	  |= subst_stack_regs_pat (insn, regstack, PATTERN (insn));
      }
  
    /* subst_stack_regs_pat may have deleted a no-op insn.  If so, any
       REG_UNUSED will already have been dealt with, so just return.  */
  
    if (GET_CODE (insn) == NOTE || INSN_DELETED_P (insn))
!     return control_flow_insn_deleted;
  
    /* If there is a REG_UNUSED note on a stack register on this insn,
       the indicated reg must be popped.  The REG_UNUSED note is removed,
*************** subst_stack_regs (rtx insn, stack regsta
*** 2256,2261 ****
--- 2265,2272 ----
        }
      else
        note_link = &XEXP (note, 1);
+ 
+   return control_flow_insn_deleted;
  }
  
  /* Change the organization of the stack so that it fits a new basic
*************** convert_regs_1 (FILE *file, basic_block 
*** 2638,2643 ****
--- 2649,2655 ----
    int deleted, inserted, reg;
    rtx insn, next;
    edge e, beste = NULL;
+   bool control_flow_insn_deleted = false;
  
    inserted = 0;
    deleted = 0;
*************** convert_regs_1 (FILE *file, basic_block 
*** 2726,2733 ****
  		       INSN_UID (insn));
  	      print_stack (file, &regstack);
  	    }
! 	  subst_stack_regs (insn, &regstack);
! 	  deleted |= (GET_CODE (insn) == NOTE || INSN_DELETED_P (insn));
  	}
      }
    while (next);
--- 2738,2744 ----
  		       INSN_UID (insn));
  	      print_stack (file, &regstack);
  	    }
! 	  control_flow_insn_deleted |= subst_stack_regs (insn, &regstack);
  	}
      }
    while (next);
*************** convert_regs_1 (FILE *file, basic_block 
*** 2766,2773 ****
  	  set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode),
  			     nan);
  	  insn = emit_insn_after (set, insn);
! 	  subst_stack_regs (insn, &regstack);
! 	  deleted |= (GET_CODE (insn) == NOTE || INSN_DELETED_P (insn));
  	}
      }
    
--- 2777,2783 ----
  	  set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode),
  			     nan);
  	  insn = emit_insn_after (set, insn);
! 	  control_flow_insn_deleted |= subst_stack_regs (insn, &regstack);
  	}
      }
    
*************** convert_regs_1 (FILE *file, basic_block 
*** 2777,2788 ****
       called at the end of convert_regs.  The order in which we process the
       blocks ensures that we never delete an already processed edge.
  
       ??? We are normally supposed not to delete trapping insns, so we pretend
       that the insns deleted above don't actually trap.  It would have been
       better to detect this earlier and avoid creating the EH edge in the first
       place, still, but we don't have enough information at that time.  */
  
!   if (deleted)
      purge_dead_edges (block);
  
    /* Something failed if the stack lives don't match.  If we had malformed
--- 2787,2804 ----
       called at the end of convert_regs.  The order in which we process the
       blocks ensures that we never delete an already processed edge.
  
+      Note that, at this point, the CFG may have been damaged by the emission
+      of instructions after an abnormal call, which moves the basic block end
+      (and is the reason why we call fixup_abnormal_edges later).  So we must
+      be sure that the trapping insn has been deleted before trying to purge
+      dead edges, otherwise we risk purging valid edges.
+ 
       ??? We are normally supposed not to delete trapping insns, so we pretend
       that the insns deleted above don't actually trap.  It would have been
       better to detect this earlier and avoid creating the EH edge in the first
       place, still, but we don't have enough information at that time.  */
  
!   if (control_flow_insn_deleted)
      purge_dead_edges (block);
  
    /* Something failed if the stack lives don't match.  If we had malformed

// PR target/12900
// Origin: <snyder@fnal.gov>

// This used to fail on x86 because the reg-stack pass
// deleted a valid edge.

// { dg-do compile }
// { dg-options "-mtune=i586 -O2" { target i?86-*-* } }

struct array {
  double data;
  virtual ~array();
};

double glob;
double ext1(double);
int nmuons;

void track_match()
{
  array vecdca;
  if (glob < 10) return;
  double p = glob*5;
  double phi = vecdca.data;
  ext1 (vecdca.data-glob);
  ext1 (phi*2);
  if (1 < p)
    ++nmuons; 
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]