This is the mail archive of the gcc@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]

df.c and partial writes/REG_EQUAL notes


Hi,
yesterday I wanted to make myself familiar with the dataflow module and write
simple code to construct webs early and split each pseudo consisting of multiple
webs to assist CSE and other optimizations.  What I am shooting for is to replace
some of logic of unroll.c to make it more rewritable for CFG.  For instance code like
*a++=0;
*a++=0;
*a++=0;
*a++=0;
*a++=0;
Will currently use 5 increments, but if the various copies of A are split, the
CSE/combine takes care to construct multiple moves.

Problem 1
=========

I've run into problems with dataflow analyzis and partial writes.  For instance following
code:

1: (set (reg:DI x) (const_int 0))

2: (set (subreg:SI (reg:DI x) 0) (const_int 1))

3: (use somewhere reg:DI x)

As currently impleemnted in df.c, there will be no depdendancy between insn 1 and insn 3,
as the store in insn 2 is believed to kill whole value of X.
The semantic of insn 2 is to overwruite just first word of the value so the insn 3 uses
values of both instructions.

I am attaching an work-in-progress patch, that changes the behaviour to represent the
depdendancy between insn 1 and insn 2 and mark the definition in insn 2 as read/write,
as well as the use in insn 2, so my web code can realize the fact that the register
must be equal and I can merge webs for X in insns 1-2 and X in insns 2-3 otherwise
disjunct.

In same way I get read/write for strict_low_part

There are number of hacks around the code, as I understand designed to cooperate somehow
with register allocator, but I am not 100% sure how.  Would be the approach described good
enought?

Alternativly we may want to make dataflow more smart and realize that insn 2 does not
use value of insn 1, but insn 3 uses both, but I am not quite sure it is wortwhile,
as pass who wants to be aware of this should also know that insn 1 can't be placed
after insn 2, even when the insn 2 does not use the value nor does kill the value
defined by insn 1.

What do you think is the most suitable behaviour?

Problem 2
=========

Another problem I've run into are the REG_EQUAL/EQUIV notes.  Currently dataflow
ignores them, but attempts to update them when register is replaced, but this is quite
wrong, as the insn may not mention the register in the pattern, but still may contain
it in the REG_EQUIV note.  This is common in libcall sequences and similar stuff.

I've added an option to build dataflow with REG_EQUIV/EQUAL notes reprezented as
ordinally uses.

Does that sound sane?
With my new "flags" field I've introduced for the problem 1, I can even mark them,
so the eventual passes may ignore them in some cases - does that make sense for
register allocator (as it is probably only one who will do so).

I am attaching the patch as well as the webizer code, both kind of work-in-progress.

Honza
*** df.h	Wed Aug 29 01:43:20 2001
--- /home/hubicka/DF.H	Tue Sep 25 15:54:22 2001
*************** Software Foundation, 59 Temple Place - S
*** 31,36 ****
--- 31,37 ----
  #define DF_RU_CHAIN    128	/* Reg-use chain.  */
  #define DF_ALL	       255
  #define DF_HARD_REGS  1024
+ #define DF_EQUIV_NOTES 2048	/* Mark uses present in EQUIV/EQUAL notes.  */
  
  enum df_ref_type {DF_REF_REG_DEF, DF_REF_REG_USE, DF_REF_REG_MEM_LOAD,
  		  DF_REF_REG_MEM_STORE};
*************** struct df_link
*** 48,53 ****
--- 49,58 ----
    struct ref *ref;
  };
  
+ enum df_ref_flags
+   {
+     DF_REF_READ_WRITE = 1
+   };
  
  /* Define a register reference structure.  */
  struct ref
*************** struct ref
*** 59,64 ****
--- 64,70 ----
    struct df_link *chain;	/* Head of def-use or use-def chain.  */
    enum df_ref_type type;	/* Type of ref.  */
    int id;			/* Ref index.  */
+   enum df_ref_flags flags;	/* Various flags.  */
  };
  
  
*************** struct df_map
*** 174,179 ****
--- 180,186 ----
  #define DF_REF_TYPE(REF) ((REF)->type)
  #define DF_REF_CHAIN(REF) ((REF)->chain)
  #define DF_REF_ID(REF) ((REF)->id)
+ #define DF_REF_FLAGS(REF) ((REF)->flags)
  
  /* Macros to determine the reference type.  */
  
*** df.c	Fri Sep 21 14:04:31 2001
--- /home/hubicka/DF.C	Tue Sep 25 15:54:13 2001
*************** when optimising a loop, only certain reg
*** 153,160 ****
  Perhaps there should be a bitmap argument to df_analyse to specify
   which registers should be analysed?   */
  
- #define HANDLE_SUBREG
- 
  #include "config.h"
  #include "system.h"
  #include "rtl.h" 
--- 153,158 ----
*************** static void df_refs_unlink PARAMS ((stru
*** 225,239 ****
  
  static struct ref *df_ref_create PARAMS((struct df *, 
  					 rtx, rtx *, basic_block, rtx,
! 					 enum df_ref_type));
  static void df_ref_record_1 PARAMS((struct df *, rtx, rtx *, 
! 				    basic_block, rtx, enum df_ref_type));
  static void df_ref_record PARAMS((struct df *, rtx, rtx *, 
! 				  basic_block bb, rtx, enum df_ref_type));
  static void df_def_record_1 PARAMS((struct df *, rtx, basic_block, rtx));
  static void df_defs_record PARAMS((struct df *, rtx, basic_block, rtx));
  static void df_uses_record PARAMS((struct df *, rtx *,
! 				   enum df_ref_type, basic_block, rtx));
  static void df_insn_refs_record PARAMS((struct df *, basic_block, rtx));
  static void df_bb_refs_record PARAMS((struct df *, basic_block));
  static void df_refs_record PARAMS((struct df *, bitmap));
--- 223,240 ----
  
  static struct ref *df_ref_create PARAMS((struct df *, 
  					 rtx, rtx *, basic_block, rtx,
! 					 enum df_ref_type, enum df_ref_flags));
  static void df_ref_record_1 PARAMS((struct df *, rtx, rtx *, 
! 				    basic_block, rtx, enum df_ref_type,
! 				    enum df_ref_flags));
  static void df_ref_record PARAMS((struct df *, rtx, rtx *, 
! 				  basic_block bb, rtx, enum df_ref_type,
! 				  enum df_ref_flags));
  static void df_def_record_1 PARAMS((struct df *, rtx, basic_block, rtx));
  static void df_defs_record PARAMS((struct df *, rtx, basic_block, rtx));
  static void df_uses_record PARAMS((struct df *, rtx *,
! 				   enum df_ref_type, basic_block, rtx,
! 				   enum df_ref_flags));
  static void df_insn_refs_record PARAMS((struct df *, basic_block, rtx));
  static void df_bb_refs_record PARAMS((struct df *, basic_block));
  static void df_refs_record PARAMS((struct df *, bitmap));
*************** static void df_chain_dump PARAMS((struct
*** 295,300 ****
--- 296,302 ----
  static void df_chain_dump_regno PARAMS((struct df_link *, FILE *file));
  static void df_regno_debug PARAMS ((struct df *, unsigned int, FILE *));
  static void df_ref_debug PARAMS ((struct df *, struct ref *, FILE *));
+ static inline bool read_modify_subreg_p PARAMS ((rtx));
  
  
  /* Local memory allocation/deallocation routines.  */
*************** df_use_unlink (df, use)
*** 777,789 ****
  /* Create a new ref of type DF_REF_TYPE for register REG at address
     LOC within INSN of BB.  */
  static struct ref *
! df_ref_create (df, reg, loc, bb, insn, ref_type)
       struct df *df;     
       rtx reg;
       rtx *loc;
       basic_block bb;
       rtx insn;
       enum df_ref_type ref_type;
  {
    struct ref *this_ref;
    unsigned int uid;
--- 779,792 ----
  /* Create a new ref of type DF_REF_TYPE for register REG at address
     LOC within INSN of BB.  */
  static struct ref *
! df_ref_create (df, reg, loc, bb, insn, ref_type, ref_flags)
       struct df *df;     
       rtx reg;
       rtx *loc;
       basic_block bb;
       rtx insn;
       enum df_ref_type ref_type;
+      enum df_ref_flags ref_flags;
  {
    struct ref *this_ref;
    unsigned int uid;
*************** df_ref_create (df, reg, loc, bb, insn, r
*** 796,801 ****
--- 799,805 ----
    DF_REF_INSN (this_ref) = insn;
    DF_REF_CHAIN (this_ref) = 0;
    DF_REF_TYPE (this_ref) = ref_type;
+   DF_REF_FLAGS (this_ref) = ref_flags;
    uid = INSN_UID (insn);
  
    if (ref_type == DF_REF_REG_DEF)
*************** df_ref_create (df, reg, loc, bb, insn, r
*** 829,856 ****
  /* Create a new reference of type DF_REF_TYPE for a single register REG,
     used inside the LOC rtx of INSN.  */
  static void
! df_ref_record_1 (df, reg, loc, bb, insn, ref_type)
       struct df *df;
       rtx reg;
       rtx *loc;
       basic_block bb;
       rtx insn;
       enum df_ref_type ref_type;
  {
!   df_ref_create (df, reg, loc, bb, insn, ref_type);
  }
  
  
  /* Create new references of type DF_REF_TYPE for each part of register REG
     at address LOC within INSN of BB.  */
  static void
! df_ref_record (df, reg, loc, bb, insn, ref_type)
       struct df *df;
       rtx reg;
       rtx *loc;
       basic_block bb;
       rtx insn;
       enum df_ref_type ref_type;
  {
    unsigned int regno;
  
--- 833,862 ----
  /* Create a new reference of type DF_REF_TYPE for a single register REG,
     used inside the LOC rtx of INSN.  */
  static void
! df_ref_record_1 (df, reg, loc, bb, insn, ref_type, ref_flags)
       struct df *df;
       rtx reg;
       rtx *loc;
       basic_block bb;
       rtx insn;
       enum df_ref_type ref_type;
+      enum df_ref_flags ref_flags;
  {
!   df_ref_create (df, reg, loc, bb, insn, ref_type, ref_flags);
  }
  
  
  /* Create new references of type DF_REF_TYPE for each part of register REG
     at address LOC within INSN of BB.  */
  static void
! df_ref_record (df, reg, loc, bb, insn, ref_type, ref_flags)
       struct df *df;
       rtx reg;
       rtx *loc;
       basic_block bb;
       rtx insn;
       enum df_ref_type ref_type;
+      enum df_ref_flags ref_flags;
  {
    unsigned int regno;
  
*************** df_ref_record (df, reg, loc, bb, insn, r
*** 889,902 ****
  
        for (i = regno; i < endregno; i++)
  	df_ref_record_1 (df, gen_rtx_REG (reg_raw_mode[i], i),
! 			 loc, bb, insn, ref_type);
      }
    else
      {
!       df_ref_record_1 (df, reg, loc, bb, insn, ref_type);
      }
  }
  
  
  /* Process all the registers defined in the rtx, X.  */
  static void
--- 895,922 ----
  
        for (i = regno; i < endregno; i++)
  	df_ref_record_1 (df, gen_rtx_REG (reg_raw_mode[i], i),
! 			 loc, bb, insn, ref_type, ref_flags);
      }
    else
      {
!       df_ref_record_1 (df, reg, loc, bb, insn, ref_type, ref_flags);
      }
  }
  
+ /* Writes to SUBREG of inndermode wider than word and outermode shorter than
+    word are read-modify-write.  */
+ static inline bool
+ read_modify_subreg_p (x)
+      rtx x;
+ {
+   if (GET_CODE (x) != SUBREG)
+     return false;
+   if (GET_MODE_SIZE (GET_MODE (SUBREG_REG (x))) <= UNITS_PER_WORD)
+     return false;
+   if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
+     return false;
+   return true;
+ }
  
  /* Process all the registers defined in the rtx, X.  */
  static void
*************** df_def_record_1 (df, x, bb, insn)
*** 908,913 ****
--- 928,934 ----
  {
    rtx *loc = &SET_DEST (x);
    rtx dst = *loc;
+   enum df_ref_flags flags = 0;
  
    /* Some targets place small structures in registers for
       return values of functions.  */
*************** df_def_record_1 (df, x, bb, insn)
*** 922,959 ****
  
    /* May be, we should flag the use of strict_low_part somehow.  Might be
       handy for the reg allocator.  */
- #ifdef HANDLE_SUBREG
    while (GET_CODE (dst) == STRICT_LOW_PART
           || GET_CODE (dst) == ZERO_EXTRACT
- 	 || GET_CODE (dst) == SIGN_EXTRACT)
-     {
-       loc = &XEXP (dst, 0);
-       dst = *loc;
-     }
-   /* For the reg allocator we are interested in exact register references.
-      This means, we want to know, if only a part of a register is
-      used/defd.  */
- /*
-   if (GET_CODE (dst) == SUBREG)
-     {
-       loc = &XEXP (dst, 0);
-       dst = *loc;
-     } */
- #else
- 
-   while (GET_CODE (dst) == SUBREG
- 	 || GET_CODE (dst) == ZERO_EXTRACT
  	 || GET_CODE (dst) == SIGN_EXTRACT
! 	 || GET_CODE (dst) == STRICT_LOW_PART)
      {
        loc = &XEXP (dst, 0);
        dst = *loc;
      }
- #endif
  
    if (GET_CODE (dst) == REG
        || (GET_CODE (dst) == SUBREG && GET_CODE (SUBREG_REG (dst)) == REG))
!       df_ref_record (df, dst, loc, bb, insn, DF_REF_REG_DEF);
  }
  
  
--- 943,968 ----
  
    /* May be, we should flag the use of strict_low_part somehow.  Might be
       handy for the reg allocator.  */
    while (GET_CODE (dst) == STRICT_LOW_PART
           || GET_CODE (dst) == ZERO_EXTRACT
  	 || GET_CODE (dst) == SIGN_EXTRACT
! 	 || read_modify_subreg_p (dst))
      {
+       /* Strict low part allways contains SUBREG, but we don't want to make
+ 	 it appear outside, as whole register is allways considered.  */
+       if (GET_CODE (dst) == STRICT_LOW_PART)
+ 	{
+ 	  loc = &XEXP (dst, 0);
+ 	  dst = *loc;
+ 	}
        loc = &XEXP (dst, 0);
        dst = *loc;
+       flags |= DF_REF_READ_WRITE;
      }
  
    if (GET_CODE (dst) == REG
        || (GET_CODE (dst) == SUBREG && GET_CODE (SUBREG_REG (dst)) == REG))
!       df_ref_record (df, dst, loc, bb, insn, DF_REF_REG_DEF, flags);
  }
  
  
*************** df_defs_record (df, x, bb, insn)
*** 989,1006 ****
  
  /* Process all the registers used in the rtx at address LOC.  */
  static void
! df_uses_record (df, loc, ref_type, bb, insn)
       struct df *df;
       rtx *loc;
       enum df_ref_type ref_type;
       basic_block bb;
       rtx insn;
  {
    RTX_CODE code;
    rtx x;
  
   retry:
    x = *loc;
    code = GET_CODE (x);
    switch (code)
      {
--- 998,1018 ----
  
  /* Process all the registers used in the rtx at address LOC.  */
  static void
! df_uses_record (df, loc, ref_type, bb, insn, flags)
       struct df *df;
       rtx *loc;
       enum df_ref_type ref_type;
       basic_block bb;
       rtx insn;
+      enum df_ref_flags flags;
  {
    RTX_CODE code;
    rtx x;
  
   retry:
    x = *loc;
+   if (!x)
+     return;
    code = GET_CODE (x);
    switch (code)
      {
*************** df_uses_record (df, loc, ref_type, bb, i
*** 1019,1136 ****
  	 as being used.  */
        if (GET_CODE (XEXP (x, 0)) == MEM)
  	df_uses_record (df, &XEXP (XEXP (x, 0), 0), 
! 			DF_REF_REG_MEM_STORE, bb, insn);
  
        /* If we're clobbering a REG then we have a def so ignore.  */
        return;
  
      case MEM:
!       df_uses_record (df, &XEXP (x, 0), DF_REF_REG_MEM_LOAD, bb, insn);
        return;
  
      case SUBREG:
        /* While we're here, optimize this case.  */
- #if defined(HANDLE_SUBREG)
  
        /* In case the SUBREG is not of a register, don't optimize.  */
        if (GET_CODE (SUBREG_REG (x)) != REG)
  	{
  	  loc = &SUBREG_REG (x);
! 	  df_uses_record (df, loc, ref_type, bb, insn);
! 	  return;
! 	}
! #else
!       loc = &SUBREG_REG (x);
!       x = *loc;
!       if (GET_CODE (x) != REG)
! 	{
! 	  df_uses_record (df, loc, ref_type, bb, insn);
  	  return;
  	}
- #endif
  
        /* ... Fall through ...  */
  
      case REG:
        /* See a register (or subreg) other than being set.  */
!       df_ref_record (df, x, loc, bb, insn, ref_type);
        return;
  
      case SET:
        {
  	rtx dst = SET_DEST (x);
- 	int use_dst = 0;
  
! 	/* If storing into MEM, don't show it as being used.  But do
! 	   show the address as being used.  */
! 	if (GET_CODE (dst) == MEM)
! 	  {
! 	    df_uses_record (df, &XEXP (dst, 0), 
! 			    DF_REF_REG_MEM_STORE,
! 			    bb, insn);
! 	    df_uses_record (df, &SET_SRC (x), DF_REF_REG_USE, bb, insn);
! 	    return;
! 	  }
  	    
- #if 1 && defined(HANDLE_SUBREG)
  	/* Look for sets that perform a read-modify-write.  */
! 	while (GET_CODE (dst) == STRICT_LOW_PART
! 	       || GET_CODE (dst) == ZERO_EXTRACT
! 	       || GET_CODE (dst) == SIGN_EXTRACT)
! 	  {
! 	    if (GET_CODE (dst) == STRICT_LOW_PART)
! 	      {
! 		dst = XEXP (dst, 0);
! 		if (GET_CODE (dst) != SUBREG)
! 		  abort ();
! 		/* A strict_low_part uses the whole reg not only the subreg.  */
! 		df_uses_record (df, &SUBREG_REG (dst), DF_REF_REG_USE, bb, insn);
! 	      }
! 	    else
! 	      {
! 	        df_uses_record (df, &XEXP (dst, 0), DF_REF_REG_USE, bb, insn);
! 		dst = XEXP (dst, 0);
! 	      }
! 	  }
! 	if (GET_CODE (dst) == SUBREG)
! 	  {
! 	    /* Paradoxical or too small subreg's are read-mod-write.  */
!             if (GET_MODE_SIZE (GET_MODE (dst)) < GET_MODE_SIZE (word_mode)
!                 || GET_MODE_SIZE (GET_MODE (dst))
! 	           >= GET_MODE_SIZE (GET_MODE (SUBREG_REG (dst))))
! 	      use_dst = 1;
! 	  }
! 	/* In the original code also some SUBREG rtx's were considered
! 	   read-modify-write (those with
! 	     REG_SIZE(SUBREG_REG(dst)) > REG_SIZE(dst) )
! 	   e.g. a (subreg:QI (reg:SI A) 0).  I can't see this.  The only
! 	   reason for a read cycle for reg A would be to somehow preserve
! 	   the bits outside of the subreg:QI.  But for this a strict_low_part
! 	   was necessary anyway, and this we handled already.  */
! #else
! 	while (GET_CODE (dst) == STRICT_LOW_PART
! 	       || GET_CODE (dst) == ZERO_EXTRACT
! 	       || GET_CODE (dst) == SIGN_EXTRACT
! 	       || GET_CODE (dst) == SUBREG)
! 	  {
! 	    /* A SUBREG of a smaller size does not use the old value.  */
! 	    if (GET_CODE (dst) != SUBREG
! 		|| (REG_SIZE (SUBREG_REG (dst)) > REG_SIZE (dst)))
! 	      use_dst = 1;
! 	    dst = XEXP (dst, 0);
! 	  }
! #endif
! 
! 	if ((GET_CODE (dst) == PARALLEL && GET_MODE (dst) == BLKmode)
! 	    || GET_CODE (dst) == REG || GET_CODE (dst) == SUBREG)
  	  {
! #if 1 || !defined(HANDLE_SUBREG)
!             if (use_dst)
! 	      df_uses_record (df, &SET_DEST (x), DF_REF_REG_USE, bb, insn);
! #endif
! 	    df_uses_record (df, &SET_SRC (x), DF_REF_REG_USE, bb, insn);
! 	    return;
  	  }
        }
        break;
  
--- 1031,1108 ----
  	 as being used.  */
        if (GET_CODE (XEXP (x, 0)) == MEM)
  	df_uses_record (df, &XEXP (XEXP (x, 0), 0), 
! 			DF_REF_REG_MEM_STORE, bb, insn, 0);
  
        /* If we're clobbering a REG then we have a def so ignore.  */
        return;
  
      case MEM:
!       df_uses_record (df, &XEXP (x, 0), DF_REF_REG_MEM_LOAD, bb, insn, flags);
        return;
  
      case SUBREG:
        /* While we're here, optimize this case.  */
  
        /* In case the SUBREG is not of a register, don't optimize.  */
        if (GET_CODE (SUBREG_REG (x)) != REG)
  	{
  	  loc = &SUBREG_REG (x);
! 	  df_uses_record (df, loc, ref_type, bb, insn, flags);
  	  return;
  	}
  
        /* ... Fall through ...  */
  
      case REG:
        /* See a register (or subreg) other than being set.  */
!       df_ref_record (df, x, loc, bb, insn, ref_type, flags);
        return;
  
      case SET:
        {
  	rtx dst = SET_DEST (x);
  
! 	df_uses_record (df, &SET_SRC (x), DF_REF_REG_USE, bb, insn, 0);
  	    
  	/* Look for sets that perform a read-modify-write.  */
! 	switch (GET_CODE (dst))
  	  {
! 	    case SUBREG:
! 	      if (read_modify_subreg_p (dst))
! 		{
! 		  df_uses_record (df, &SUBREG_REG (dst), DF_REF_REG_USE, bb,
! 				  insn, DF_REF_READ_WRITE);
! 		  break;
! 		}
! 	      /* ... FALLTHRU ... */
! 	    case REG:
! 	    case PC:
! 	      break;
! 	    case MEM:
! 	      df_uses_record (df, &XEXP (dst, 0), 
! 			      DF_REF_REG_MEM_STORE,
! 			      bb, insn, 0);
! 	      break;
! 	    case STRICT_LOW_PART:
! 	      /* A strict_low_part uses the whole reg not only the subreg.  */
! 	      dst = XEXP (dst, 0);
! 	      if (GET_CODE (dst) != SUBREG)
! 		abort ();
! 	      df_uses_record (df, &SUBREG_REG (dst), DF_REF_REG_USE, bb,
! 			     insn, DF_REF_READ_WRITE);
! 	      break;
! 	    case ZERO_EXTRACT:
! 	    case SIGN_EXTRACT:
! 	      df_uses_record (df, &XEXP (dst, 0), DF_REF_REG_USE, bb, insn,
! 			      DF_REF_READ_WRITE);
! 	      df_uses_record (df, &XEXP (dst, 1), DF_REF_REG_USE, bb, insn, 0);
! 	      df_uses_record (df, &XEXP (dst, 2), DF_REF_REG_USE, bb, insn, 0);
! 	      dst = XEXP (dst, 0);
! 	      break;
! 	    default:
! 	      abort ();
  	  }
+ 	return;
        }
        break;
  
*************** df_uses_record (df, loc, ref_type, bb, i
*** 1163,1169 ****
  
  	    for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
  	      df_uses_record (df, &ASM_OPERANDS_INPUT (x, j), 
! 			      DF_REF_REG_USE, bb, insn);
  	    return;
  	  }
  	break;
--- 1135,1141 ----
  
  	    for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
  	      df_uses_record (df, &ASM_OPERANDS_INPUT (x, j), 
! 			      DF_REF_REG_USE, bb, insn, 0);
  	    return;
  	  }
  	break;
*************** df_uses_record (df, loc, ref_type, bb, i
*** 1176,1182 ****
      case PRE_MODIFY:
      case POST_MODIFY:
        /* Catch the def of the register being modified.  */
!       df_ref_record (df, XEXP (x, 0), &XEXP (x, 0), bb, insn, DF_REF_REG_DEF);
  
        /* ... Fall through to handle uses ...  */
  
--- 1148,1154 ----
      case PRE_MODIFY:
      case POST_MODIFY:
        /* Catch the def of the register being modified.  */
!       df_ref_record (df, XEXP (x, 0), &XEXP (x, 0), bb, insn, DF_REF_REG_DEF, DF_REF_READ_WRITE);
  
        /* ... Fall through to handle uses ...  */
  
*************** df_uses_record (df, loc, ref_type, bb, i
*** 1199,1212 ****
  		loc = &XEXP (x, 0);
  		goto retry;
  	      }
! 	    df_uses_record (df, &XEXP (x, i), ref_type, bb, insn);
  	  }
  	else if (fmt[i] == 'E')
  	  {
  	    int j;
  	    for (j = 0; j < XVECLEN (x, i); j++)
  	      df_uses_record (df, &XVECEXP (x, i, j), ref_type,
! 			      bb, insn);
  	  }
        }
    }
--- 1171,1184 ----
  		loc = &XEXP (x, 0);
  		goto retry;
  	      }
! 	    df_uses_record (df, &XEXP (x, i), ref_type, bb, insn, flags);
  	  }
  	else if (fmt[i] == 'E')
  	  {
  	    int j;
  	    for (j = 0; j < XVECLEN (x, i); j++)
  	      df_uses_record (df, &XVECEXP (x, i, j), ref_type,
! 			      bb, insn, flags);
  	  }
        }
    }
*************** df_insn_refs_record (df, bb, insn)
*** 1224,1231 ****
--- 1196,1220 ----
  
    if (INSN_P (insn))
      {
+       rtx note;
+ 
        /* Record register defs */
        df_defs_record (df, PATTERN (insn), bb, insn);
+ 
+       if (df->flags & DF_EQUIV_NOTES)
+ 	for (note = REG_NOTES (insn); note;
+ 	     note = XEXP (note, 1))
+ 	  {
+ 	    switch (REG_NOTE_KIND (note))
+ 	      {
+ 		case REG_EQUIV:
+ 		case REG_EQUAL:
+ 		  df_uses_record (df, &XEXP (note, 0), DF_REF_REG_USE,
+ 				  bb, insn, 0);
+ 		default:
+ 		  break;
+ 	      }
+ 	  }
        
        if (GET_CODE (insn) == CALL_INSN)
  	{
*************** df_insn_refs_record (df, bb, insn)
*** 1238,1249 ****
  	    {
  	      if (GET_CODE (XEXP (note, 0)) == USE)
  		df_uses_record (df, &SET_DEST (XEXP (note, 0)), DF_REF_REG_USE,
! 				bb, insn);
  	    }
  
  	  /* The stack ptr is used (honorarily) by a CALL insn.  */
  	  x = df_reg_use_gen (STACK_POINTER_REGNUM);
! 	  df_uses_record (df, &SET_DEST (x), DF_REF_REG_USE, bb, insn);
  	  
  	  if (df->flags & DF_HARD_REGS)
  	    {
--- 1227,1238 ----
  	    {
  	      if (GET_CODE (XEXP (note, 0)) == USE)
  		df_uses_record (df, &SET_DEST (XEXP (note, 0)), DF_REF_REG_USE,
! 				bb, insn, 0);
  	    }
  
  	  /* The stack ptr is used (honorarily) by a CALL insn.  */
  	  x = df_reg_use_gen (STACK_POINTER_REGNUM);
! 	  df_uses_record (df, &SET_DEST (x), DF_REF_REG_USE, bb, insn, 0);
  	  
  	  if (df->flags & DF_HARD_REGS)
  	    {
*************** df_insn_refs_record (df, bb, insn)
*** 1254,1267 ****
  		  {
  		    x = df_reg_use_gen (i);
  		    df_uses_record (df, &SET_DEST (x),
! 				    DF_REF_REG_USE, bb, insn);
  		  }
  	    }
  	}
        
        /* Record the register uses.  */
        df_uses_record (df, &PATTERN (insn), 
! 		      DF_REF_REG_USE, bb, insn);
        
  
        if (GET_CODE (insn) == CALL_INSN)
--- 1243,1256 ----
  		  {
  		    x = df_reg_use_gen (i);
  		    df_uses_record (df, &SET_DEST (x),
! 				    DF_REF_REG_USE, bb, insn, 0);
  		  }
  	    }
  	}
        
        /* Record the register uses.  */
        df_uses_record (df, &PATTERN (insn), 
! 		      DF_REF_REG_USE, bb, insn, 0);
        
  
        if (GET_CODE (insn) == CALL_INSN)
*************** df_insn_modify (df, bb, insn)
*** 2623,2636 ****
    bitmap_set_bit (df->bbs_modified, bb->index);
    bitmap_set_bit (df->insns_modified, uid);
  
- #if 0
    /* For incremental updating on the fly, perhaps we could make a copy
       of all the refs of the original insn and turn them into
       anti-refs.  When df_refs_update finds these anti-refs, it annihilates
       the original refs.  If validate_change fails then these anti-refs
       will just get ignored.  */
-   */
- #endif
  }
  
  
--- 2612,2622 ----
*************** df_dump (df, flags, file)
*** 3482,3487 ****
--- 3468,3475 ----
  		       DF_INSN_LUID (df, DF_REF_INSN (df->defs[j])),
  		       DF_REF_INSN_UID (df->defs[j]),
  		       DF_REF_REGNO (df->defs[j]));
+ 	      if (df->defs[j]->flags & DF_REF_READ_WRITE)
+ 		fprintf (file, "read/write ");
  	      df_chain_dump (DF_REF_CHAIN (df->defs[j]), file);
  	      fprintf (file, "\n");
  	    }
*************** df_dump (df, flags, file)
*** 3522,3527 ****
--- 3510,3517 ----
  		       DF_INSN_LUID (df, DF_REF_INSN (df->uses[j])),
  		       DF_REF_INSN_UID (df->uses[j]),
  		       DF_REF_REGNO (df->uses[j]));
+ 	      if (df->uses[j]->flags & DF_REF_READ_WRITE)
+ 		fprintf (file, "read/write ");
  	      df_chain_dump (DF_REF_CHAIN (df->uses[j]), file);
  	      fprintf (file, "\n");
  	    }

struct web_entry
{
  struct web_entry *pred;
  rtx reg;
};
struct web_entry *
unionfind_root (struct web_entry *element)
{
  struct web_entry *element1 = element, *element2;

  while (element->pred)
    element = element->pred;
  while (element1->pred)
    {
      element2 = element1->pred;
      element1->pred = element;
      element1 = element2;
    }
  return element;
}

void
unionfind_merge (struct web_entry *first, struct web_entry *second)
{
  first = unionfind_root (first);
  second = unionfind_root (second);
  if (first == second)
    return;
  second->pred = first;
}

void
construct_webs ()
{
  struct df *df;
  struct web_entry *def_entry;
  struct web_entry *use_entry;
  unsigned int i;
  int max = max_reg_num ();
  char *used;

  df = df_init ();
  df_analyse (df, 0, DF_ALL | DF_UD_CHAIN | DF_DU_CHAIN | DF_EQUIV_NOTES);
  def_entry =
    (struct web_entry *) xcalloc (df->n_defs, sizeof (struct web_entry));
  use_entry =
    (struct web_entry *) xcalloc (df->n_uses, sizeof (struct web_entry));
  used = (char *) xcalloc (max, sizeof (char));

  if (rtl_dump_file)
    df_dump (df, DF_UD_CHAIN | DF_DU_CHAIN, rtl_dump_file);

  /* Now crossmerge the chains.  */
  for (i = 0; i < df->n_uses; i++)
    {
      struct df_link *link = df->uses[i]->chain;
      while (link)
	{
	  unionfind_merge (use_entry + i, def_entry + link->ref->id);
	  //fprintf(stderr, "u%i d%i\n",i, link->ref->id);
	  link = link->next;
	}
      /* In case we are seeing REF_READ_WRITE, we need to find
         the corresponding use and union them.  */
      if (df->uses[i]->flags & DF_REF_READ_WRITE)
	{
	  struct df_link *link = DF_INSN_DEFS (df, df->uses[i]->insn);

	  while (link->ref->reg != df->uses[i]->reg)
	    {
	      link = link->next;
	    }
	  
	  unionfind_merge (use_entry + i, def_entry + link->ref->id);
	  //fprintf(stderr, "a: u%i d%i\n",i, link->ref->id);
	  if (link->ref->chain)
	    {
	      unionfind_merge (use_entry + i, use_entry + link->ref->chain->ref->id);
	  //fprintf(stderr, "b: u%i u%i\n",i, link->ref->chain->ref->id);
	    }
	}
    }
  for (i = 0; i < df->n_defs + df->n_uses; i++)
    {
      struct web_entry *root;
      struct web_entry *entry;
      struct ref *ref;
      rtx reg, newreg;

      if (i < df->n_defs)
	{
	  entry = def_entry + i;
	  ref = df->defs[i];
	}
      else
	{
	  entry = use_entry + i - df->n_defs;
	  ref = df->uses[i - df->n_defs];
	}

      root = unionfind_root (entry);
      reg = ref->reg;
      if (GET_CODE (reg) == SUBREG)
	reg = SUBREG_REG (reg);

      if (root->reg)
	newreg = root->reg;
      else if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
	newreg = reg;
      else if (used[REGNO (reg)])
	{
	  newreg = gen_reg_rtx (GET_MODE (reg));
	  if (rtl_dump_file)
	    fprintf (rtl_dump_file, "Web oldreg=%i newreg=%i\n", REGNO (reg),
		     REGNO (newreg));
	}
      else
	newreg = reg, used[REGNO (reg)] = 1;

      root->reg = newreg;
      entry->reg = newreg;
      if (newreg != reg)
	{
	  if (GET_CODE (ref->reg) == SUBREG)
	    SUBREG_REG (ref->reg) = newreg;
	  else
	    *ref->loc = newreg;
	  if (rtl_dump_file)
	    fprintf (rtl_dump_file, "Insn %i updated. %s (%i->%i)\n",
		     INSN_UID (ref->insn),
		     DF_REF_REG_DEF_P (ref) ? "dest" : "use",
		     REGNO (reg), REGNO (newreg));
	}
    }
  free (def_entry);
  free (use_entry);
  free (used);
  df_finish (df);
}

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