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] Crossjumping corrupts alias info


Hello,

as I've described in:

http://gcc.gnu.org/ml/gcc/2004-02/msg00090.html

the crossjumping step does not care about alias information coming with
memory expressions. Hence the alias information of one of
the merged insns is lost. Together with code duplication during basic block
reordering the scheduler produces wrong code code due to broken data
dependecies.

The attached patch introduces new versions of rtx_equal_p and rtx_renumbered_equal_p
in cfgcleanup.c which perform additional checks of the attributes for memory 
expressions. In order to do this correctly I've added mem_expr_equal_p to emit-rtl.c 
which returns true for equal tree nodes coming with memory expression.

Due to less crossjumping the size of e.g. libstd++.so.6.0.0 is increased  by 0.072% (2764 bytes).

For now I've fixed only the crossjumping analysis step, but it is surely necessary to
look into other places where rtx_equal_p is used.

Bootstrapped without regressions on s390-ibm-linux and s390x-ibm-linux.

OK?

Bye,

-Andreas-

2004-02-20  Andreas Krebbel  <krebbel1@de.ibm.com>

	* rtl.h (mem_expr_equal_p): Function prototype added.
	* cfgcleanup.c (MEM_ATTRIBUTES_EQUAL_P): New macro.
	(rtx_and_memattr_equal_p, rtx_and_memattr_renumbered_equal_p): New 
	functions.
	(insns_match_p): Use rtx_and_memattr_equal_p and
	rtx_and_memattr_renumbered_equal_p instead of rtx_equal_p and 
	rtx_renumbered_equal_p.
	* emit-rtl.c (mem_expr_equal_p): New function.


Index: gcc/rtl.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/rtl.h,v
retrieving revision 1.448.4.2
diff -p -c -r1.448.4.2 rtl.h
*** gcc/rtl.h	12 Feb 2004 15:30:45 -0000	1.448.4.2
--- gcc/rtl.h	20 Feb 2004 12:20:45 -0000
*************** extern rtx emit_copy_of_insn_after (rtx,
*** 1452,1457 ****
--- 1452,1458 ----
  extern void set_reg_attrs_from_mem (rtx, rtx);
  extern void set_mem_attrs_from_reg (rtx, rtx);
  extern void set_reg_attrs_for_parm (rtx, rtx);
+ extern int mem_expr_equal_p (tree, tree);
  
  /* In rtl.c */
  extern rtx rtx_alloc (RTX_CODE);
Index: gcc/cfgcleanup.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cfgcleanup.c,v
retrieving revision 1.99.2.4
diff -p -c -r1.99.2.4 cfgcleanup.c
*** gcc/cfgcleanup.c	30 Jan 2004 11:07:49 -0000	1.99.2.4
--- gcc/cfgcleanup.c	20 Feb 2004 12:20:45 -0000
*************** Software Foundation, 59 Temple Place - S
*** 48,53 ****
--- 48,54 ----
  #include "params.h"
  #include "tm_p.h"
  #include "target.h"
+ #include "regs.h"
  
  /* cleanup_cfg maintains following flags for each basic block.  */
  
*************** enum bb_flags
*** 67,72 ****
--- 68,81 ----
  
  #define FORWARDER_BLOCK_P(BB) (BB_FLAGS (BB) & BB_FORWARDER_BLOCK)
  
+ /* Compare the attributes of two MEM rtx.  */
+ #define MEM_ATTRIBUTES_EQUAL_P(RTX1, RTX2)                         \
+ ((MEM_ALIAS_SET (RTX1) == MEM_ALIAS_SET (RTX2)                     \
+   && MEM_OFFSET (RTX1) == MEM_OFFSET (RTX2)                        \
+   && MEM_SIZE (RTX1) == MEM_SIZE (RTX2)                            \
+   && MEM_ALIGN (RTX1) == MEM_ALIGN (RTX2)                          \
+   && mem_expr_equal_p (MEM_EXPR (RTX1), MEM_EXPR (RTX2))) ? 1 : 0)
+ 
  static bool try_crossjump_to_edge (int, edge, edge);
  static bool try_crossjump_bb (int, basic_block);
  static bool outgoing_edges_match (int, basic_block, basic_block);
*************** static bool mark_effect (rtx, bitmap);
*** 84,90 ****
  static void notice_new_block (basic_block);
  static void update_forwarder_flag (basic_block);
  static int mentions_nonequal_regs (rtx *, void *);
!  
  /* Set flags for newly created block.  */
  
  static void
--- 93,101 ----
  static void notice_new_block (basic_block);
  static void update_forwarder_flag (basic_block);
  static int mentions_nonequal_regs (rtx *, void *);
! static int rtx_and_memattr_equal_p (rtx, rtx);
! static int rtx_and_memattr_renumbered_equal_p (rtx, rtx);
! 
  /* Set flags for newly created block.  */
  
  static void
*************** merge_blocks_move (edge e, basic_block b
*** 857,862 ****
--- 868,1195 ----
  }
   
  
+ /* Return 1 if X and Y are identical-looking rtx's. This
+    version was copied from rtl.c and got an additional check
+    for memory attributes.
+    This is the Lisp function EQUAL for rtx arguments.  */
+ 
+ int
+ rtx_and_memattr_equal_p (rtx x, rtx y)
+ {
+   int i;
+   int j;
+   enum rtx_code code;
+   const char *fmt;
+ 
+   if (x == y)
+     return 1;
+   if (x == 0 || y == 0)
+     return 0;
+ 
+   code = GET_CODE (x);
+   /* Rtx's of different codes cannot be equal.  */
+   if (code != GET_CODE (y))
+     return 0;
+ 
+   /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.
+      (REG:SI x) and (REG:HI x) are NOT equivalent.  */
+ 
+   if (GET_MODE (x) != GET_MODE (y))
+     return 0;
+ 
+   /* Some RTL can be compared nonrecursively.  */
+   switch (code)
+     {
+     case REG:
+       /* Until rtl generation is complete, don't consider a reference
+ 	 to the return register of the current function the same as
+ 	 the return from a called function.  This eases the job of
+ 	 function integration.  Once the distinction is no longer
+ 	 needed, they can be considered equivalent.  */
+       return (REGNO (x) == REGNO (y)
+ 	      && (! rtx_equal_function_value_matters
+ 		  || REG_FUNCTION_VALUE_P (x) == REG_FUNCTION_VALUE_P (y)));
+ 
+     case LABEL_REF:
+       return XEXP (x, 0) == XEXP (y, 0);
+ 
+     case SYMBOL_REF:
+       return XSTR (x, 0) == XSTR (y, 0);
+ 
+     case SCRATCH:
+     case CONST_DOUBLE:
+     case CONST_INT:
+     case CONST_VECTOR:
+       return 0;
+ 
+     default:
+       break;
+     }
+ 
+   /* Compare the elements.  If any pair of corresponding elements
+      fail to match, return 0 for the whole thing.  */
+ 
+   fmt = GET_RTX_FORMAT (code);
+   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+     {
+       switch (fmt[i])
+ 	{
+ 	case 'w':
+ 	  if (XWINT (x, i) != XWINT (y, i))
+ 	    return 0;
+ 	  break;
+ 
+ 	case 'n':
+ 	case 'i':
+ 	  if (XINT (x, i) != XINT (y, i))
+ 	    return 0;
+ 	  break;
+ 
+ 	case 'V':
+ 	case 'E':
+ 	  /* Two vectors must have the same length.  */
+ 	  if (XVECLEN (x, i) != XVECLEN (y, i))
+ 	    return 0;
+ 
+ 	  /* And the corresponding elements must match.  */
+ 	  for (j = 0; j < XVECLEN (x, i); j++)
+ 	    if (rtx_and_memattr_equal_p (XVECEXP (x, i, j), XVECEXP (y, i, j)) == 0)
+ 	      return 0;
+ 	  break;
+ 
+ 	case 'e':
+  	  if (GET_CODE(x) == MEM && ! MEM_ATTRIBUTES_EQUAL_P (x, y))
+  	    return 0;
+ 
+ 	  if (rtx_and_memattr_equal_p (XEXP (x, i), XEXP (y, i)) == 0)
+ 	    return 0;
+ 	  break;
+ 
+ 	case 'S':
+ 	case 's':
+ 	  if ((XSTR (x, i) || XSTR (y, i))
+ 	      && (! XSTR (x, i) || ! XSTR (y, i)
+ 		  || strcmp (XSTR (x, i), XSTR (y, i))))
+ 	    return 0;
+ 	  break;
+ 
+ 	case 'u':
+ 	  /* These are just backpointers, so they don't matter.  */
+ 	  break;
+ 
+ 	case '0':
+ 	case 't':
+ 	  break;
+ 
+ 	  /* It is believed that rtx's at this level will never
+ 	     contain anything but integers and other rtx's,
+ 	     except for within LABEL_REFs and SYMBOL_REFs.  */
+ 	default:
+ 	  abort ();
+ 	}
+     }
+   return 1;
+ }
+ 
+ /* Like rtx_and_memattr_equal_p except that it considers two REGs as equal
+    if they renumber to the same value and considers two commutative
+    operations to be the same if the order of the operands has been
+    reversed.
+ 
+    ??? Addition is not commutative on the PA due to the weird implicit
+    space register selection rules for memory addresses.  Therefore, we
+    don't consider a + b == b + a.
+ 
+    We could/should make this test a little tighter.  Possibly only
+    disabling it on the PA via some backend macro or only disabling this
+    case when the PLUS is inside a MEM.  */
+ 
+ int
+ rtx_and_memattr_renumbered_equal_p (rtx x, rtx y)
+ {
+   int i;
+   RTX_CODE code = GET_CODE (x);
+   const char *fmt;
+ 
+   if (x == y)
+     return 1;
+ 
+   if ((code == REG || (code == SUBREG && GET_CODE (SUBREG_REG (x)) == REG))
+       && (GET_CODE (y) == REG || (GET_CODE (y) == SUBREG
+ 				  && GET_CODE (SUBREG_REG (y)) == REG)))
+     {
+       int reg_x = -1, reg_y = -1;
+       int byte_x = 0, byte_y = 0;
+ 
+       if (GET_MODE (x) != GET_MODE (y))
+ 	return 0;
+ 
+       /* If we haven't done any renumbering, don't
+ 	 make any assumptions.  */
+       if (reg_renumber == 0)
+ 	return rtx_and_memattr_equal_p (x, y);
+ 
+       if (code == SUBREG)
+ 	{
+ 	  reg_x = REGNO (SUBREG_REG (x));
+ 	  byte_x = SUBREG_BYTE (x);
+ 
+ 	  if (reg_renumber[reg_x] >= 0)
+ 	    {
+ 	      reg_x = subreg_regno_offset (reg_renumber[reg_x],
+ 					   GET_MODE (SUBREG_REG (x)),
+ 					   byte_x,
+ 					   GET_MODE (x));
+ 	      byte_x = 0;
+ 	    }
+ 	}
+       else
+ 	{
+ 	  reg_x = REGNO (x);
+ 	  if (reg_renumber[reg_x] >= 0)
+ 	    reg_x = reg_renumber[reg_x];
+ 	}
+ 
+       if (GET_CODE (y) == SUBREG)
+ 	{
+ 	  reg_y = REGNO (SUBREG_REG (y));
+ 	  byte_y = SUBREG_BYTE (y);
+ 
+ 	  if (reg_renumber[reg_y] >= 0)
+ 	    {
+ 	      reg_y = subreg_regno_offset (reg_renumber[reg_y],
+ 					   GET_MODE (SUBREG_REG (y)),
+ 					   byte_y,
+ 					   GET_MODE (y));
+ 	      byte_y = 0;
+ 	    }
+ 	}
+       else
+ 	{
+ 	  reg_y = REGNO (y);
+ 	  if (reg_renumber[reg_y] >= 0)
+ 	    reg_y = reg_renumber[reg_y];
+ 	}
+ 
+       return reg_x >= 0 && reg_x == reg_y && byte_x == byte_y;
+     }
+ 
+   /* Now we have disposed of all the cases
+      in which different rtx codes can match.  */
+   if (code != GET_CODE (y))
+     return 0;
+ 
+   switch (code)
+     {
+     case PC:
+     case CC0:
+     case ADDR_VEC:
+     case ADDR_DIFF_VEC:
+     case CONST_INT:
+       return 0;
+ 
+     case LABEL_REF:
+       /* We can't assume nonlocal labels have their following insns yet.  */
+       if (LABEL_REF_NONLOCAL_P (x) || LABEL_REF_NONLOCAL_P (y))
+ 	return XEXP (x, 0) == XEXP (y, 0);
+ 
+       /* Two label-refs are equivalent if they point at labels
+ 	 in the same position in the instruction stream.  */
+       return (next_real_insn (XEXP (x, 0))
+ 	      == next_real_insn (XEXP (y, 0)));
+ 
+     case SYMBOL_REF:
+       return XSTR (x, 0) == XSTR (y, 0);
+ 
+     case CODE_LABEL:
+       /* If we didn't match EQ equality above, they aren't the same.  */
+       return 0;
+ 
+     default:
+       break;
+     }
+ 
+   /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent.  */
+ 
+   if (GET_MODE (x) != GET_MODE (y))
+     return 0;
+ 
+   /* For commutative operations, the RTX match if the operand match in any
+      order.  Also handle the simple binary and unary cases without a loop.
+ 
+      ??? Don't consider PLUS a commutative operator; see comments above.  */
+   if ((code == EQ || code == NE || GET_RTX_CLASS (code) == 'c')
+       && code != PLUS)
+     return ((rtx_and_memattr_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0))
+ 	     && rtx_and_memattr_renumbered_equal_p (XEXP (x, 1), XEXP (y, 1)))
+ 	    || (rtx_and_memattr_renumbered_equal_p (XEXP (x, 0), XEXP (y, 1))
+ 		&& rtx_and_memattr_renumbered_equal_p (XEXP (x, 1), XEXP (y, 0))));
+   else if (GET_RTX_CLASS (code) == '<' || GET_RTX_CLASS (code) == '2')
+     return (rtx_and_memattr_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0))
+ 	    && rtx_and_memattr_renumbered_equal_p (XEXP (x, 1), XEXP (y, 1)));
+   else if (GET_RTX_CLASS (code) == '1')
+     return rtx_and_memattr_renumbered_equal_p (XEXP (x, 0), XEXP (y, 0));
+ 
+   /* Compare the elements.  If any pair of corresponding elements
+      fail to match, return 0 for the whole things.  */
+ 
+   fmt = GET_RTX_FORMAT (code);
+   for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+     {
+       int j;
+       switch (fmt[i])
+ 	{
+ 	case 'w':
+ 	  if (XWINT (x, i) != XWINT (y, i))
+ 	    return 0;
+ 	  break;
+ 
+ 	case 'i':
+ 	  if (XINT (x, i) != XINT (y, i))
+ 	    return 0;
+ 	  break;
+ 
+ 	case 't':
+ 	  if (XTREE (x, i) != XTREE (y, i))
+ 	    return 0;
+ 	  break;
+ 
+ 	case 's':
+ 	  if (strcmp (XSTR (x, i), XSTR (y, i)))
+ 	    return 0;
+ 	  break;
+ 
+ 	case 'e':
+  	  if (GET_CODE(x) == MEM && ! MEM_ATTRIBUTES_EQUAL_P (x, y))
+ 	      return 0;
+  	  
+ 	  if (! rtx_and_memattr_renumbered_equal_p (XEXP (x, i), XEXP (y, i)))
+ 	    return 0;
+ 	  break;
+ 
+ 	case 'u':
+ 	  if (XEXP (x, i) != XEXP (y, i))
+ 	    return 0;
+ 	  /* Fall through.  */
+ 	case '0':
+ 	  break;
+ 
+ 	case 'E':
+ 	  if (XVECLEN (x, i) != XVECLEN (y, i))
+ 	    return 0;
+ 	  for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+ 	    if (!rtx_and_memattr_renumbered_equal_p (XVECEXP (x, i, j), 
+ 						     XVECEXP (y, i, j)))
+ 	      return 0;
+ 	  break;
+ 
+ 	default:
+ 	  abort ();
+ 	}
+     }
+   return 1;
+ }
+ 
  /* Return true if I1 and I2 are equivalent and thus can be crossjumped.  */
  
  static bool
*************** insns_match_p (int mode ATTRIBUTE_UNUSED
*** 885,892 ****
       equal, they were constructed identically.  */
  
    if (GET_CODE (i1) == CALL_INSN
!       && (!rtx_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
! 		        CALL_INSN_FUNCTION_USAGE (i2))
  	  || SIBLING_CALL_P (i1) != SIBLING_CALL_P (i2)))
      return false;
  
--- 1218,1225 ----
       equal, they were constructed identically.  */
  
    if (GET_CODE (i1) == CALL_INSN
!       && (!rtx_and_memattr_equal_p (CALL_INSN_FUNCTION_USAGE (i1),
! 				    CALL_INSN_FUNCTION_USAGE (i2))
  	  || SIBLING_CALL_P (i1) != SIBLING_CALL_P (i2)))
      return false;
  
*************** insns_match_p (int mode ATTRIBUTE_UNUSED
*** 925,931 ****
  #endif
  
    if (reload_completed
!       ? rtx_renumbered_equal_p (p1, p2) : rtx_equal_p (p1, p2))
      return true;
  
    /* Do not do EQUIV substitution after reload.  First, we're undoing the
--- 1258,1265 ----
  #endif
  
    if (reload_completed
!       ? rtx_and_memattr_renumbered_equal_p (p1, p2) 
!       : rtx_and_memattr_equal_p (p1, p2))
      return true;
  
    /* Do not do EQUIV substitution after reload.  First, we're undoing the
*************** insns_match_p (int mode ATTRIBUTE_UNUSED
*** 945,960 ****
  	     use them.  */
  	  && (! reload_completed
  	      || (CONSTANT_P (XEXP (equiv1, 0))
! 		  && rtx_equal_p (XEXP (equiv1, 0), XEXP (equiv2, 0)))))
  	{
  	  rtx s1 = single_set (i1);
  	  rtx s2 = single_set (i2);
  	  if (s1 != 0 && s2 != 0
! 	      && rtx_renumbered_equal_p (SET_DEST (s1), SET_DEST (s2)))
  	    {
  	      validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1);
  	      validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1);
! 	      if (! rtx_renumbered_equal_p (p1, p2))
  		cancel_changes (0);
  	      else if (apply_change_group ())
  		return true;
--- 1279,1296 ----
  	     use them.  */
  	  && (! reload_completed
  	      || (CONSTANT_P (XEXP (equiv1, 0))
! 		  && rtx_and_memattr_equal_p (XEXP (equiv1, 0), 
! 					      XEXP (equiv2, 0)))))
  	{
  	  rtx s1 = single_set (i1);
  	  rtx s2 = single_set (i2);
  	  if (s1 != 0 && s2 != 0
! 	      && rtx_and_memattr_renumbered_equal_p (SET_DEST (s1), 
! 						     SET_DEST (s2)))
  	    {
  	      validate_change (i1, &SET_SRC (s1), XEXP (equiv1, 0), 1);
  	      validate_change (i2, &SET_SRC (s2), XEXP (equiv2, 0), 1);
! 	      if (! rtx_and_memattr_renumbered_equal_p (p1, p2))
  		cancel_changes (0);
  	      else if (apply_change_group ())
  		return true;
Index: gcc/emit-rtl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/emit-rtl.c,v
retrieving revision 1.365.4.3
diff -p -c -r1.365.4.3 emit-rtl.c
*** gcc/emit-rtl.c	11 Feb 2004 08:07:48 -0000	1.365.4.3
--- gcc/emit-rtl.c	20 Feb 2004 12:20:46 -0000
*************** component_ref_for_mem_expr (tree ref)
*** 1520,1525 ****
--- 1520,1551 ----
  		  TREE_OPERAND (ref, 1));
  }
  
+ /* Returns 1 if both MEM_EXPR can be considered equal
+    and 0 otherwise.  */
+ 
+ int
+ mem_expr_equal_p (tree expr1, tree expr2)
+ {
+   if (expr1 == expr2)
+     return 1;
+ 
+   if (! expr1 || ! expr2)
+     return 0;
+ 
+   if (TREE_CODE (expr1) != TREE_CODE (expr2))
+     return 0;
+ 
+   if (TREE_CODE (expr1) == COMPONENT_REF)
+     {
+       /* COMPONENT_REF of something variable. The pointers to the 
+ 	 component refs maybe unequal but the operands have to match.  */
+       if (! TREE_OPERAND (expr1, 0) && ! TREE_OPERAND (expr2, 0))
+ 	return TREE_OPERAND (expr1, 1) == TREE_OPERAND (expr2, 1);
+     }
+ 
+   return 0;
+ }
+ 
  /* Given REF, a MEM, and T, either the type of X or the expression
     corresponding to REF, set the memory attributes.  OBJECTP is nonzero
     if we are making a new object of this type.  BITPOS is nonzero if


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