public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Kenneth Zadeck <zadeck@naturalbridge.com>
To: Kenneth Zadeck <zadeck@naturalbridge.com>
Cc: gcc-patches <gcc-patches@gcc.gnu.org>,
	  Ian Lance Taylor <iant@google.com>,
	 "Park, Seongbae" <seongbae.park@gmail.com>,
	  "Bonzini, Paolo" <bonzini@gnu.org>,
	 Steven Bosscher <stevenb.gcc@gmail.com>,
	  Richard Sandiford <rsandifo@nildram.co.uk>
Subject: Re: [trunk] first of three patches to get rid of no conflict blocks.
Date: Tue, 04 Mar 2008 20:57:00 -0000	[thread overview]
Message-ID: <47CDB78B.1020100@naturalbridge.com> (raw)
In-Reply-To: <47CDB6AF.9090707@naturalbridge.com>

[-- Attachment #1: Type: text/plain, Size: 3387 bytes --]

enopatch

Kenneth Zadeck wrote:
> This is the first of either two or three patches to get rid of no
> conflict blocks. 
> The problem with using the current implementation of df for this is that
> the current implementation does not keep the parameters for ZERO_EXTRACT
> or SIGN_EXTRACT if one of these wraps a subreg.  So in order to recover
> this info, you would of had to rescan the insn.
>
> Most of this patch deals with df-scan.  The idea here is there that if a
> ZERO_EXTRACT or SIGN_EXTRACT wraps a subreg, then new flags are added to
> the df_ref and two new fields are added to the df_ref to support the
> width and the offset information in these wrappers. 
>
> To do this without blowing a lot of space, i simply use an extension of
> the df_ref called df_ref_extract to support the two fields when they are
> necessary. 
>
> I would like at least one of the rtl experts to review this patch more
> carefully than a normal review.  Scanning rtl is not my forte, i fell
> kind of like the person in those old airplane movies that is called to
> cockpit after both pilots have been killed.   I know that pulling the
> stick back makes the plane go up, but there sure are a lot of buttons
> and switches there. 
>
> The next patch will use the information in ra-conflict to properly
> account for partial register use and hopefully make the noconflict
> blocks unnecessary.   It will utilize the offset and width fields from
> the extract wrappers.
>
> I have tested this patch on several platforms and it causes no problems,
> but since nothing is using this information, this is a pretty weak test.  
>
> Thanks,
>
> Kenny
>
>
> 2008-03-04  Kenneth Zadeck <zadeck@naturalbridge.com>
>
>     * fwprop.c (update_df): Support width and offset parameters of
>     df_ref_create.
>     * ra-conflict.c (mark_reg_store, clear_reg_in_live,
>     global_conflicts): Change DF_REF_EXTRACT to either
>     DF_REF_ZERO_EXTRACT or DF_REF_SIGN_EXTRACT.  Change
>     DF_REF_STRICT_LOWER_PART to DF_REF_STRICT_LOW_PART.
>     * df-scan.c (df_ref_record, df_defs_record,
>     df_ref_create_structure, df_def_record_1, df_uses_record,
>     df_get_conditional_uses, df_get_call_refs, df_insn_refs_collect,
>     df_bb_refs_collect, df_entry_block_defs_collect,
>     df_exit_block_uses_collect): Support new width and offset fields.
>     (ref_extract_pool): New storage pool.
>     (df_free_ref): New function.
>     (df_reg_chain_unlink, df_free_collection_rec,
>     df_sort_and_compress_refs): Call df_free_ref.
>     (df_ref_equal_p, df_ref_compare): Compare offset and width fields
>     of df_ref_extract.
>     (df_ref_create_structure): Allocate df_ref_extract if offset and
>     width fields are used.
>     (df_def_record_1): Get offset and width from ZERO_EXTRACT.
>     (df_uses_record): Get offset and width from ZERO_EXTRACT
>     and SIGN_EXTRACT.
>     * global.c (build_insn_chain): Change DF_REF_EXTRACT to either
>     DF_REF_ZERO_EXTRACT or DF_REF_SIGN_EXTRACT.  Change
>     DF_REF_STRICT_LOWER_PART to DF_REF_STRICT_LOW_PART.
>     * df.h (df_ref_flags): Change DF_REF_EXTRACT to either
>     DF_REF_ZERO_EXTRACT or DF_REF_SIGN_EXTRACT.  Change
>     DF_REF_STRICT_LOWER_PART to DF_REF_STRICT_LOW_PART.
>     (df_ref_extract): New structure.
>     (DF_REF_WIDTH, DF_REF_OFFSET): New macros.
>     (df_ref_create): Add width and offset parameters.
>     
>
>
>   


[-- Attachment #2: extract1.diff --]
[-- Type: text/x-patch, Size: 33618 bytes --]

Index: fwprop.c
===================================================================
--- fwprop.c	(revision 132860)
+++ fwprop.c	(working copy)
@@ -642,17 +642,25 @@ update_df (rtx insn, rtx *loc, struct df
     {
       struct df_ref *use = *use_rec;
       struct df_ref *orig_use = use, *new_use;
+      int width = -1;
+      int offset = -1;
       rtx *new_loc = find_occurrence (loc, DF_REF_REG (orig_use));
       use_rec++;
 
       if (!new_loc)
 	continue;
 
+      if (DF_REF_FLAGS_IS_SET (orig_use, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
+	{
+	  width = DF_REF_WIDTH (orig_use);
+	  offset = DF_REF_OFFSET (orig_use);
+	}
+
       /* Add a new insn use.  Use the original type, because it says if the
          use was within a MEM.  */
       new_use = df_ref_create (DF_REF_REG (orig_use), new_loc,
 			       insn, BLOCK_FOR_INSN (insn),
-			       type, DF_REF_FLAGS (orig_use) | new_flags);
+			       type, DF_REF_FLAGS (orig_use) | new_flags, width, offset);
 
       /* Set up the use-def chain.  */
       df_chain_copy (new_use, DF_REF_CHAIN (orig_use));
Index: ra-conflict.c
===================================================================
--- ra-conflict.c	(revision 132860)
+++ ra-conflict.c	(working copy)
@@ -297,7 +297,7 @@ mark_reg_store (sparseset allocnos_live,
     {
       unsigned int start = regno;
       unsigned int last = end_hard_regno (mode, regno);
-      if ((GET_CODE (reg) == SUBREG) && !DF_REF_FLAGS_IS_SET (ref, DF_REF_EXTRACT))
+      if ((GET_CODE (reg) == SUBREG) && !DF_REF_FLAGS_IS_SET (ref, DF_REF_ZERO_EXTRACT))
 	{
 	  start += subreg_regno_offset (regno, GET_MODE (SUBREG_REG (reg)),
 					SUBREG_BYTE (reg), GET_MODE (reg));
@@ -457,7 +457,7 @@ clear_reg_in_live (sparseset allocnos_li
   if (allocnum >= 0)
     {
       if (GET_CODE (reg) == SUBREG
-	  && !DF_REF_FLAGS_IS_SET (def, DF_REF_EXTRACT))
+	  && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
 	{
 	  unsigned int start = SUBREG_BYTE (reg);
 	  unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
@@ -465,7 +465,7 @@ clear_reg_in_live (sparseset allocnos_li
 	  ra_init_live_subregs (sparseset_bit_p (allocnos_live, allocnum), 
 				live_subregs, live_subregs_used, allocnum, reg);
 
-	  if (!DF_REF_FLAGS_IS_SET (def, DF_REF_STRICT_LOWER_PART))
+	  if (!DF_REF_FLAGS_IS_SET (def, DF_REF_STRICT_LOW_PART))
 	    {
 	      /* Expand the range to cover entire words.
 		 Bytes added here are "don't care".  */
@@ -511,7 +511,7 @@ clear_reg_in_live (sparseset allocnos_li
     {
       unsigned int start = regno;
       if (GET_CODE (reg) == SUBREG
-	  && !DF_REF_FLAGS_IS_SET (def, DF_REF_EXTRACT))
+	  && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
 	{
 	  unsigned int last;
 	  start += SUBREG_BYTE (reg);
@@ -864,7 +864,7 @@ global_conflicts (void)
 		  rtx reg = DF_REF_REG (def);
 		  set_reg_in_live (allocnos_live, live_subregs, live_subregs_used, 
 				   &hard_regs_live, reg, 
-				   DF_REF_FLAGS_IS_SET (def, DF_REF_EXTRACT));
+				   DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT));
 		  if (dump_file)
 		    dump_ref (dump_file, "  adding def", "\n",
 			      reg, DF_REF_REGNO (def), live_subregs, live_subregs_used);
@@ -946,7 +946,7 @@ global_conflicts (void)
 		 use unless that set also happens to wrapped in a
 		 ZERO_EXTRACT. */
 	      if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE) 
-		  && (!DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT)) 
+		  && (!DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT)) 
 		  && DF_REF_FLAGS_IS_SET (use, DF_REF_SUBREG))
 		continue;
 	      
@@ -957,7 +957,7 @@ global_conflicts (void)
 	      if (allocnum >= 0)
 		{
 		  if (GET_CODE (reg) == SUBREG
-		      && !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT)) 
+		      && !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT)) 
 		    {
 		      unsigned int start = SUBREG_BYTE (reg);
 		      unsigned int last = start + GET_MODE_SIZE (GET_MODE (reg));
Index: df-scan.c
===================================================================
--- df-scan.c	(revision 132860)
+++ df-scan.c	(working copy)
@@ -95,7 +95,7 @@ static struct df_mw_hardreg * df_null_mw
 static void df_ref_record (struct df_collection_rec *,
 			   rtx, rtx *, 
 			   basic_block, rtx, enum df_ref_type, 
-			   enum df_ref_flags);
+			   enum df_ref_flags, int, int);
 static void df_def_record_1 (struct df_collection_rec *,
 			     rtx, basic_block, rtx,
 			     enum df_ref_flags);
@@ -104,11 +104,11 @@ static void df_defs_record (struct df_co
 			    enum df_ref_flags);
 static void df_uses_record (struct df_collection_rec *,
 			    rtx *, enum df_ref_type,
-			    basic_block, rtx, enum df_ref_flags);
+			    basic_block, rtx, enum df_ref_flags, int, int);
 
 static struct df_ref *df_ref_create_structure (struct df_collection_rec *, rtx, rtx *, 
 					       basic_block, rtx, enum df_ref_type, 
-					       enum df_ref_flags);
+					       enum df_ref_flags, int, int);
 
 static void df_insn_refs_collect (struct df_collection_rec*, 
 				  basic_block, rtx); 
@@ -160,6 +160,7 @@ static bool regs_ever_live[FIRST_PSEUDO_
 struct df_scan_problem_data
 {
   alloc_pool ref_pool;
+  alloc_pool ref_extract_pool;
   alloc_pool insn_pool;
   alloc_pool reg_pool;
   alloc_pool mw_reg_pool;
@@ -214,6 +215,7 @@ df_scan_free_internal (void)
 
   free_alloc_pool (df_scan->block_pool);
   free_alloc_pool (problem_data->ref_pool);
+  free_alloc_pool (problem_data->ref_extract_pool);
   free_alloc_pool (problem_data->insn_pool);
   free_alloc_pool (problem_data->reg_pool);
   free_alloc_pool (problem_data->mw_reg_pool);
@@ -296,6 +298,9 @@ df_scan_alloc (bitmap all_blocks ATTRIBU
   problem_data->ref_pool 
     = create_alloc_pool ("df_scan_ref pool", 
 			 sizeof (struct df_ref), block_size);
+  problem_data->ref_extract_pool 
+    = create_alloc_pool ("df_scan_ref extract pool", 
+			 sizeof (struct df_ref_extract), block_size);
   problem_data->insn_pool 
     = create_alloc_pool ("df_scan_insn pool", 
 			 sizeof (struct df_insn_info), block_size);
@@ -608,13 +613,19 @@ df_scan_blocks (void)
 
 
 /* Create a new ref of type DF_REF_TYPE for register REG at address
-   LOC within INSN of BB.  */
+   LOC within INSN of BB.  This function is only used externally. 
+
+   If the REF_FLAGS field contain DF_REF_SIGN_EXTRACT or
+   DF_REF_ZERO_EXTRACT.  WIDTH and OFFSET are used to access the fields
+   if they were constants.  Otherwise they should be -1 if those flags
+   were set.  */
 
 struct df_ref *
 df_ref_create (rtx reg, rtx *loc, rtx insn, 
 	       basic_block bb,
 	       enum df_ref_type ref_type, 
-	       enum df_ref_flags ref_flags)
+	       enum df_ref_flags ref_flags,
+	       int width, int offset)
 {
   struct df_ref *ref;
   struct df_reg_info **reg_info;
@@ -629,7 +640,7 @@ df_ref_create (rtx reg, rtx *loc, rtx in
   /* You cannot hack artificial refs.  */
   gcc_assert (insn);
   ref = df_ref_create_structure (NULL, reg, loc, bb, insn,
-                                 ref_type, ref_flags);
+                                 ref_type, ref_flags, width, offset);
 
   if (DF_REF_TYPE (ref) == DF_REF_REG_DEF)
     {
@@ -727,6 +738,18 @@ df_ref_create (rtx reg, rtx *loc, rtx in
    UTILITIES TO CREATE AND DESTROY REFS AND CHAINS.
 ----------------------------------------------------------------------------*/
 
+static void
+df_free_ref (struct df_ref *ref)
+{
+  struct df_scan_problem_data *problem_data
+    = (struct df_scan_problem_data *) df_scan->problem_data;
+
+  if (DF_REF_FLAGS_IS_SET (ref, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
+    pool_free (problem_data->ref_extract_pool, (struct df_ref_extract *)ref);
+  else
+    pool_free (problem_data->ref_pool, ref);
+}
+
 
 /* Unlink and delete REF at the reg_use, reg_eq_use or reg_def chain.
    Also delete the def-use or use-def chain if it exists.  */
@@ -736,8 +759,6 @@ df_reg_chain_unlink (struct df_ref *ref)
 {
   struct df_ref *next = DF_REF_NEXT_REG (ref);  
   struct df_ref *prev = DF_REF_PREV_REG (ref);
-  struct df_scan_problem_data *problem_data
-    = (struct df_scan_problem_data *) df_scan->problem_data;
   int id = DF_REF_ID (ref);
   struct df_reg_info *reg_info;
   struct df_ref **refs = NULL;
@@ -808,7 +829,7 @@ df_reg_chain_unlink (struct df_ref *ref)
   if (next)
     DF_REF_PREV_REG (next) = prev;
 
-  pool_free (problem_data->ref_pool, ref);
+  df_free_ref (ref);
 }
 
 
@@ -1058,13 +1079,13 @@ df_free_collection_rec (struct df_collec
 
   if (collection_rec->def_vec)
     for (ref = collection_rec->def_vec; *ref; ref++)
-      pool_free (problem_data->ref_pool, *ref);
+      df_free_ref (*ref);
   if (collection_rec->use_vec)
     for (ref = collection_rec->use_vec; *ref; ref++)
-      pool_free (problem_data->ref_pool, *ref);
+      df_free_ref (*ref);
   if (collection_rec->eq_use_vec)
     for (ref = collection_rec->eq_use_vec; *ref; ref++)
-      pool_free (problem_data->ref_pool, *ref);
+      df_free_ref (*ref);
   if (collection_rec->mw_vec)
     for (mw = collection_rec->mw_vec; *mw; mw++)
       pool_free (problem_data->mw_reg_pool, *mw);
@@ -2045,7 +2066,7 @@ df_notes_rescan (rtx insn)
 	    case REG_EQUAL:
 	      df_uses_record (&collection_rec,
 			      &XEXP (note, 0), DF_REF_REG_USE,
-			      bb, insn, DF_REF_IN_NOTE);
+			      bb, insn, DF_REF_IN_NOTE, -1, -1);
 	    default:
 	      break;
 	    }
@@ -2115,6 +2136,13 @@ df_ref_equal_p (struct df_ref *ref1, str
 {
   if (!ref2)
     return false;
+
+  if ((DF_REF_FLAGS_IS_SET (ref1, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
+      && (DF_REF_FLAGS_IS_SET (ref2, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
+      && ((DF_REF_OFFSET (ref1) != DF_REF_OFFSET (ref2))
+	  || (DF_REF_WIDTH (ref1) != DF_REF_WIDTH (ref2))))
+    return false;
+
   return (ref1 == ref2) ||
     (DF_REF_REG (ref1) == DF_REF_REG (ref2)
      && DF_REF_REGNO (ref1) == DF_REF_REGNO (ref2)
@@ -2163,6 +2191,16 @@ df_ref_compare (const void *r1, const vo
       else
 	return 1;
     }
+
+  /* The flags are the same at this point so it is safe to only look
+     at ref1.  */
+  if (DF_REF_FLAGS_IS_SET (ref1, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
+    {
+      if (DF_REF_OFFSET (ref1) != DF_REF_OFFSET (ref2))
+	return DF_REF_OFFSET (ref1) - DF_REF_OFFSET (ref2);
+      if (DF_REF_WIDTH (ref1) != DF_REF_WIDTH (ref2))
+	return DF_REF_WIDTH (ref1) - DF_REF_WIDTH (ref2);
+    }
   return 0;
 }
 
@@ -2179,8 +2217,6 @@ df_swap_refs (struct df_ref **ref_vec, i
 static unsigned int
 df_sort_and_compress_refs (struct df_ref **ref_vec, unsigned int count)
 {
-  struct df_scan_problem_data *problem_data 
-    = (struct df_scan_problem_data *) df_scan->problem_data;
   unsigned int i;
   unsigned int dist = 0;
 
@@ -2215,7 +2251,7 @@ df_sort_and_compress_refs (struct df_ref
       /* Find the next ref that is not equal to the current ref.  */
       while (df_ref_equal_p (ref_vec[i], ref_vec[i + dist + 1]))
 	{
-	  pool_free (problem_data->ref_pool, ref_vec[i + dist + 1]);
+	  df_free_ref (ref_vec[i + dist + 1]);
 	  dist++;
 	}
       /* Copy it down to the next position.  */
@@ -2541,21 +2577,34 @@ df_refs_add_to_chains (struct df_collect
 }
 
 
-/* Allocate a ref and initialize its fields. */
+/* Allocate a ref and initialize its fields. 
+
+   If the REF_FLAGS field contain DF_REF_SIGN_EXTRACT or
+   DF_REF_ZERO_EXTRACT.  WIDTH and OFFSET are used to access the fields
+   if they were constants.  Otherwise they should be -1 if those flags
+   were set.  */
 
 static struct df_ref *
 df_ref_create_structure (struct df_collection_rec *collection_rec,
 			 rtx reg, rtx *loc, 
 			 basic_block bb, rtx insn, 
 			 enum df_ref_type ref_type, 
-			 enum df_ref_flags ref_flags)
+			 enum df_ref_flags ref_flags,
+			 int width, int offset)
 {
   struct df_ref *this_ref;
   int regno = REGNO (GET_CODE (reg) == SUBREG ? SUBREG_REG (reg) : reg);
   struct df_scan_problem_data *problem_data
     = (struct df_scan_problem_data *) df_scan->problem_data;
 
-  this_ref = pool_alloc (problem_data->ref_pool);
+  if (ref_flags & (DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
+    {
+      this_ref = pool_alloc (problem_data->ref_extract_pool);
+      DF_REF_WIDTH (this_ref) = width;
+      DF_REF_OFFSET (this_ref) = offset;
+    }
+  else
+    this_ref = pool_alloc (problem_data->ref_pool);
   DF_REF_ID (this_ref) = -1;
   DF_REF_REG (this_ref) = reg;
   DF_REF_REGNO (this_ref) =  regno;
@@ -2604,14 +2653,21 @@ df_ref_create_structure (struct df_colle
 
 
 /* Create new references of type DF_REF_TYPE for each part of register REG
-   at address LOC within INSN of BB.  */
+   at address LOC within INSN of BB. 
+
+   If the REF_FLAGS field contain DF_REF_SIGN_EXTRACT or
+   DF_REF_ZERO_EXTRACT.  WIDTH and OFFSET are used to access the fields
+   if they were constants.  Otherwise they should be -1 if those flags
+   were set.  */
+
 
 static void
 df_ref_record (struct df_collection_rec *collection_rec,
                rtx reg, rtx *loc, 
 	       basic_block bb, rtx insn, 
 	       enum df_ref_type ref_type, 
-	       enum df_ref_flags ref_flags) 
+	       enum df_ref_flags ref_flags,
+	       int width, int offset) 
 {
   unsigned int regno;
 
@@ -2660,7 +2716,7 @@ df_ref_record (struct df_collection_rec 
       for (i = regno; i < endregno; i++)
 	{
 	  ref = df_ref_create_structure (collection_rec, regno_reg_rtx[i], loc, 
-					 bb, insn, ref_type, ref_flags);
+					 bb, insn, ref_type, ref_flags, width, offset);
 
           gcc_assert (ORIGINAL_REGNO (DF_REF_REG (ref)) == i);
 	}
@@ -2669,7 +2725,7 @@ df_ref_record (struct df_collection_rec 
     {
       struct df_ref *ref;
       ref = df_ref_create_structure (collection_rec, reg, loc, bb, insn, 
-                                     ref_type, ref_flags);
+                                     ref_type, ref_flags, width, offset);
     }
 }
 
@@ -2703,6 +2759,8 @@ df_def_record_1 (struct df_collection_re
 {
   rtx *loc;
   rtx dst;
+  int offset = -1;
+  int width = -1;
 
  /* We may recursively call ourselves on EXPR_LIST when dealing with PARALLEL
      construct.  */
@@ -2730,16 +2788,24 @@ df_def_record_1 (struct df_collection_re
       return;
     }
 
-  /* Maybe, we should flag the use of STRICT_LOW_PART somehow.  It might
-     be handy for the reg allocator.  */
-  while (GET_CODE (dst) == STRICT_LOW_PART
-	 || GET_CODE (dst) == ZERO_EXTRACT)
-    {
-      flags |= DF_REF_READ_WRITE | DF_REF_PARTIAL;
-      if (GET_CODE (dst) == ZERO_EXTRACT)
-	flags |= DF_REF_EXTRACT;
-      else
-	flags |= DF_REF_STRICT_LOWER_PART;
+  if (GET_CODE (dst) == STRICT_LOW_PART)
+    {
+      flags |= DF_REF_READ_WRITE | DF_REF_PARTIAL | DF_REF_STRICT_LOW_PART;
+
+      loc = &XEXP (dst, 0);
+      dst = *loc;
+    }
+
+  if (GET_CODE (dst) == ZERO_EXTRACT)
+    {
+      flags |= DF_REF_READ_WRITE | DF_REF_PARTIAL | DF_REF_ZERO_EXTRACT;
+      
+      if (GET_CODE (XEXP (dst, 1)) == CONST_INT
+	  && GET_CODE (XEXP (dst, 2)) == CONST_INT)
+	{
+	  width = INTVAL (XEXP (dst, 1));
+	  offset = INTVAL (XEXP (dst, 2));
+	}
 
       loc = &XEXP (dst, 0);
       dst = *loc;
@@ -2749,13 +2815,13 @@ df_def_record_1 (struct df_collection_re
   if (REG_P (dst))
     {
       df_ref_record (collection_rec, 
-		     dst, loc, bb, insn, DF_REF_REG_DEF, flags);
+		     dst, loc, bb, insn, DF_REF_REG_DEF, flags, width, offset);
 
       /* We want to keep sp alive everywhere - by making all
 	 writes to sp also use of sp. */
       if (REGNO (dst) == STACK_POINTER_REGNUM)
 	df_ref_record (collection_rec,
-		       dst, NULL, bb, insn, DF_REF_REG_USE, flags);
+		       dst, NULL, bb, insn, DF_REF_REG_USE, flags, width, offset);
     }
   else if (GET_CODE (dst) == SUBREG && REG_P (SUBREG_REG (dst)))
     {
@@ -2765,7 +2831,7 @@ df_def_record_1 (struct df_collection_re
       flags |= DF_REF_SUBREG;
 
       df_ref_record (collection_rec, 
-		     dst, loc, bb, insn, DF_REF_REG_DEF, flags);
+		     dst, loc, bb, insn, DF_REF_REG_DEF, flags, width, offset);
     }
 }
 
@@ -2801,12 +2867,18 @@ df_defs_record (struct df_collection_rec
 }
 
 
-/* Process all the registers used in the rtx at address LOC.  */
+/* Process all the registers used in the rtx at address LOC.  
+
+   If the REF_FLAGS field contain DF_REF_SIGN_EXTRACT or
+   DF_REF_ZERO_EXTRACT.  WIDTH and LOWER are used to access the fields
+   if they were constants.  Otherwise they should be -1 if those flags
+   were set.  */
 
 static void
 df_uses_record (struct df_collection_rec *collection_rec,
                 rtx *loc, enum df_ref_type ref_type,
-		basic_block bb, rtx insn, enum df_ref_flags flags)
+		basic_block bb, rtx insn, enum df_ref_flags flags,
+		int width, int offset)
 {
   RTX_CODE code;
   rtx x;
@@ -2837,7 +2909,7 @@ df_uses_record (struct df_collection_rec
       if (MEM_P (XEXP (x, 0)))
 	df_uses_record (collection_rec,
 			&XEXP (XEXP (x, 0), 0),
-			DF_REF_REG_MEM_STORE, bb, insn, flags);
+			DF_REF_REG_MEM_STORE, bb, insn, flags, width, offset);
 
       /* If we're clobbering a REG then we have a def so ignore.  */
       return;
@@ -2845,7 +2917,7 @@ df_uses_record (struct df_collection_rec
     case MEM:
       df_uses_record (collection_rec,
 		      &XEXP (x, 0), DF_REF_REG_MEM_LOAD, 
-		      bb, insn, flags & DF_REF_IN_NOTE);
+		      bb, insn, flags & DF_REF_IN_NOTE, width, offset);
       return;
 
     case SUBREG:
@@ -2855,22 +2927,46 @@ df_uses_record (struct df_collection_rec
       if (!REG_P (SUBREG_REG (x)))
 	{
 	  loc = &SUBREG_REG (x);
-	  df_uses_record (collection_rec, loc, ref_type, bb, insn, flags);
+	  df_uses_record (collection_rec, loc, ref_type, bb, insn, flags, width, offset);
 	  return;
 	}
       /* ... Fall through ...  */
 
     case REG:
       df_ref_record (collection_rec, 
-		     x, loc, bb, insn, ref_type, flags);
+		     x, loc, bb, insn, ref_type, flags, width, offset);
       return;
 
+    case SIGN_EXTRACT:
+    case ZERO_EXTRACT:
+      {
+	/* If the parameters to the zero or sign extract are
+	   constants, strip them off and recurse, otherwise there is
+	   no information that we can gain from this operation.  */
+	if (GET_CODE (XEXP (x, 1)) == CONST_INT
+	    && GET_CODE (XEXP (x, 2)) == CONST_INT)
+	  {
+	    width = INTVAL (XEXP (x, 1));
+	    offset = INTVAL (XEXP (x, 2));
+
+	    if (code == ZERO_EXTRACT)
+	      flags |= DF_REF_ZERO_EXTRACT;
+	    else
+	      flags |= DF_REF_SIGN_EXTRACT;
+
+	    df_uses_record (collection_rec,
+			    &XEXP (x, 0), ref_type, bb, insn, flags, width, offset);
+	    return;
+	  }
+      }
+      break;
+
     case SET:
       {
 	rtx dst = SET_DEST (x);
 	gcc_assert (!(flags & DF_REF_IN_NOTE));
 	df_uses_record (collection_rec,
-			&SET_SRC (x), DF_REF_REG_USE, bb, insn, flags);
+			&SET_SRC (x), DF_REF_REG_USE, bb, insn, flags, width, offset);
 
 	switch (GET_CODE (dst))
 	  {
@@ -2879,7 +2975,7 @@ df_uses_record (struct df_collection_rec
 		{
 		  df_uses_record (collection_rec, &SUBREG_REG (dst), 
 				  DF_REF_REG_USE, bb, insn, 
-				  flags | DF_REF_READ_WRITE | DF_REF_SUBREG);
+				  flags | DF_REF_READ_WRITE | DF_REF_SUBREG, width, offset);
 		  break;
 		}
 	      /* Fall through.  */
@@ -2891,7 +2987,7 @@ df_uses_record (struct df_collection_rec
 		break;
 	    case MEM:
 	      df_uses_record (collection_rec, &XEXP (dst, 0),
-			      DF_REF_REG_MEM_STORE, bb, insn, flags);
+			      DF_REF_REG_MEM_STORE, bb, insn, flags, width, offset);
 	      break;
 	    case STRICT_LOW_PART:
 	      {
@@ -2902,20 +2998,31 @@ df_uses_record (struct df_collection_rec
 		df_uses_record (collection_rec, 
 				(GET_CODE (dst) == SUBREG) ? &SUBREG_REG (dst) : temp, 
 				DF_REF_REG_USE, bb, insn, 
-				DF_REF_READ_WRITE | DF_REF_STRICT_LOWER_PART);
+				DF_REF_READ_WRITE | DF_REF_STRICT_LOW_PART, width, offset);
 	      }
 	      break;
 	    case ZERO_EXTRACT:
-	    case SIGN_EXTRACT:
-	      df_uses_record (collection_rec, &XEXP (dst, 0), 
-			      DF_REF_REG_USE, bb, insn, 
-			      DF_REF_READ_WRITE | DF_REF_EXTRACT);
-	      df_uses_record (collection_rec, &XEXP (dst, 1), 
-			      DF_REF_REG_USE, bb, insn, flags);
-	      df_uses_record (collection_rec, &XEXP (dst, 2), 
-			      DF_REF_REG_USE, bb, insn, flags);
-	      dst = XEXP (dst, 0);
+	      {
+		if (GET_CODE (XEXP (dst, 1)) == CONST_INT
+		    && GET_CODE (XEXP (dst, 2)) == CONST_INT)
+		  {
+		    width = INTVAL (XEXP (dst, 1));
+		    offset = INTVAL (XEXP (dst, 2));
+		  }
+		else 
+		  {
+		    df_uses_record (collection_rec, &XEXP (dst, 1), 
+				    DF_REF_REG_USE, bb, insn, flags, width, offset);
+		    df_uses_record (collection_rec, &XEXP (dst, 2), 
+				    DF_REF_REG_USE, bb, insn, flags, width, offset);
+		  }
+
+		df_uses_record (collection_rec, &XEXP (dst, 0), 
+				DF_REF_REG_USE, bb, insn, 
+				DF_REF_READ_WRITE | DF_REF_ZERO_EXTRACT, width, offset);
+	      }
 	      break;
+
 	    default:
 	      gcc_unreachable ();
 	  }
@@ -2962,7 +3069,7 @@ df_uses_record (struct df_collection_rec
 
 	    for (j = 0; j < ASM_OPERANDS_INPUT_LENGTH (x); j++)
 	      df_uses_record (collection_rec, &ASM_OPERANDS_INPUT (x, j),
-			      DF_REF_REG_USE, bb, insn, flags);
+			      DF_REF_REG_USE, bb, insn, flags, width, offset);
 	    return;
 	  }
 	break;
@@ -2977,7 +3084,7 @@ df_uses_record (struct df_collection_rec
       /* Catch the def of the register being modified.  */
       df_ref_record (collection_rec, XEXP (x, 0), &XEXP (x, 0), bb, insn, 
 		     DF_REF_REG_DEF,
-                     flags | DF_REF_READ_WRITE | DF_REF_PRE_POST_MODIFY);
+                     flags | DF_REF_READ_WRITE | DF_REF_PRE_POST_MODIFY, width, offset);
 
       /* ... Fall through to handle uses ...  */
 
@@ -3000,14 +3107,16 @@ df_uses_record (struct df_collection_rec
 		loc = &XEXP (x, 0);
 		goto retry;
 	      }
-	    df_uses_record (collection_rec, &XEXP (x, i), ref_type, bb, insn, flags);
+	    df_uses_record (collection_rec, &XEXP (x, i), ref_type, 
+			    bb, insn, flags, width, offset);
 	  }
 	else if (fmt[i] == 'E')
 	  {
 	    int j;
 	    for (j = 0; j < XVECLEN (x, i); j++)
 	      df_uses_record (collection_rec,
-			      &XVECEXP (x, i, j), ref_type, bb, insn, flags);
+			      &XVECEXP (x, i, j), ref_type, 
+			      bb, insn, flags, width, offset);
 	  }
       }
   }
@@ -3027,11 +3136,21 @@ df_get_conditional_uses (struct df_colle
       struct df_ref *ref = collection_rec->def_vec[i];
       if (DF_REF_FLAGS_IS_SET (ref, DF_REF_CONDITIONAL))
         {
-          struct df_ref *use 
-	    = df_ref_create_structure (collection_rec, DF_REF_REG (ref),
-				       DF_REF_LOC (ref), DF_REF_BB (ref),
-				       DF_REF_INSN (ref), DF_REF_REG_USE,
-				       DF_REF_FLAGS (ref) & ~DF_REF_CONDITIONAL);
+	  int width = -1;
+	  int offset = -1;
+          struct df_ref *use;
+
+	  if (DF_REF_FLAGS_IS_SET (ref, DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT))
+	    {
+	      width = DF_REF_WIDTH (ref);
+	      offset = DF_REF_OFFSET (ref);
+	    }
+
+          use = df_ref_create_structure (collection_rec, DF_REF_REG (ref),
+					 DF_REF_LOC (ref), DF_REF_BB (ref),
+					 DF_REF_INSN (ref), DF_REF_REG_USE,
+					 DF_REF_FLAGS (ref) & ~DF_REF_CONDITIONAL,
+					 width, offset);
           DF_REF_REGNO (use) = DF_REF_REGNO (ref);
         }
     }
@@ -3069,7 +3188,7 @@ df_get_call_refs (struct df_collection_r
     {
       if (GET_CODE (XEXP (note, 0)) == USE)
         df_uses_record (collection_rec, &XEXP (XEXP (note, 0), 0),
-			DF_REF_REG_USE, bb, insn, flags);
+			DF_REF_REG_USE, bb, insn, flags, -1, -1);
       else if (GET_CODE (XEXP (note, 0)) == CLOBBER)
 	{
 	  if (REG_P (XEXP (XEXP (note, 0), 0)))
@@ -3081,13 +3200,13 @@ df_get_call_refs (struct df_collection_r
 	    }
 	  else
 	    df_uses_record (collection_rec, &XEXP (note, 0),
-		            DF_REF_REG_USE, bb, insn, flags);
+		            DF_REF_REG_USE, bb, insn, flags, -1, -1);
 	}
     }
 
   /* The stack ptr is used (honorarily) by a CALL insn.  */
   df_ref_record (collection_rec, regno_reg_rtx[STACK_POINTER_REGNUM],
-		 NULL, bb, insn, DF_REF_REG_USE, DF_REF_CALL_STACK_USAGE | flags);
+		 NULL, bb, insn, DF_REF_REG_USE, DF_REF_CALL_STACK_USAGE | flags, -1, -1);
 
   /* Calls may also reference any of the global registers,
      so they are recorded as used.  */
@@ -3095,9 +3214,9 @@ df_get_call_refs (struct df_collection_r
     if (global_regs[i])
       {
 	df_ref_record (collection_rec, regno_reg_rtx[i],
-		       NULL, bb, insn, DF_REF_REG_USE, flags);
+		       NULL, bb, insn, DF_REF_REG_USE, flags, -1, -1);
 	df_ref_record (collection_rec, regno_reg_rtx[i],
-		       NULL, bb, insn, DF_REF_REG_DEF, flags);
+		       NULL, bb, insn, DF_REF_REG_DEF, flags, -1, -1);
       }
 
   is_sibling_call = SIBLING_CALL_P (insn);
@@ -3110,7 +3229,7 @@ df_get_call_refs (struct df_collection_r
 	      || refers_to_regno_p (ui, ui+1, 
 				    current_function_return_rtx, NULL)))
         df_ref_record (collection_rec, regno_reg_rtx[ui], 
-		       NULL, bb, insn, DF_REF_REG_DEF, DF_REF_MAY_CLOBBER | flags);
+		       NULL, bb, insn, DF_REF_REG_DEF, DF_REF_MAY_CLOBBER | flags, -1, -1);
     }
 
   BITMAP_FREE (defs_generated);
@@ -3148,7 +3267,7 @@ df_insn_refs_collect (struct df_collecti
         case REG_EQUAL:
           df_uses_record (collection_rec,
                           &XEXP (note, 0), DF_REF_REG_USE,
-                          bb, insn, DF_REF_IN_NOTE);
+                          bb, insn, DF_REF_IN_NOTE, -1, -1);
           break;
         case REG_NON_LOCAL_GOTO:
           /* The frame ptr is used by a non-local goto.  */
@@ -3156,13 +3275,13 @@ df_insn_refs_collect (struct df_collecti
                          regno_reg_rtx[FRAME_POINTER_REGNUM],
                          NULL,
                          bb, insn, 
-                         DF_REF_REG_USE, 0);
+                         DF_REF_REG_USE, 0, -1, -1);
 #if FRAME_POINTER_REGNUM != HARD_FRAME_POINTER_REGNUM
           df_ref_record (collection_rec,
                          regno_reg_rtx[HARD_FRAME_POINTER_REGNUM],
                          NULL,
                          bb, insn, 
-                         DF_REF_REG_USE, 0);
+                         DF_REF_REG_USE, 0, -1, -1);
 #endif
           break;
         default:
@@ -3176,7 +3295,7 @@ df_insn_refs_collect (struct df_collecti
 
   /* Record the register uses.  */
   df_uses_record (collection_rec,
-		  &PATTERN (insn), DF_REF_REG_USE, bb, insn, 0);
+		  &PATTERN (insn), DF_REF_REG_USE, bb, insn, 0, -1, -1);
 
   /* DF_REF_CONDITIONAL needs corresponding USES. */
   if (is_cond_exec)
@@ -3259,7 +3378,7 @@ df_bb_refs_collect (struct df_collection
 	  if (regno == INVALID_REGNUM)
 	    break;
 	  df_ref_record (collection_rec, regno_reg_rtx[regno], NULL,
-			 bb, NULL, DF_REF_REG_DEF, DF_REF_AT_TOP);
+			 bb, NULL, DF_REF_REG_DEF, DF_REF_AT_TOP, -1, -1);
 	}
     }
 #endif
@@ -3283,7 +3402,7 @@ df_bb_refs_collect (struct df_collection
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	if (EH_USES (i))
 	  df_ref_record (collection_rec, regno_reg_rtx[i], NULL,
-			 bb, NULL, DF_REF_REG_USE, DF_REF_AT_TOP);
+			 bb, NULL, DF_REF_REG_USE, DF_REF_AT_TOP, -1, -1);
     }
 #endif
 
@@ -3291,7 +3410,7 @@ df_bb_refs_collect (struct df_collection
      non-local goto.  */
   if (bb->flags & BB_NON_LOCAL_GOTO_TARGET)
     df_ref_record (collection_rec, hard_frame_pointer_rtx, NULL,
-		   bb, NULL, DF_REF_REG_DEF, DF_REF_AT_TOP);
+		   bb, NULL, DF_REF_REG_DEF, DF_REF_AT_TOP, -1, -1);
  
   /* Add the artificial uses.  */
   if (bb->index >= NUM_FIXED_BLOCKS)
@@ -3305,7 +3424,7 @@ df_bb_refs_collect (struct df_collection
       EXECUTE_IF_SET_IN_BITMAP (au, 0, regno, bi)
 	{
 	  df_ref_record (collection_rec, regno_reg_rtx[regno], NULL,
-			 bb, NULL, DF_REF_REG_USE, 0);
+			 bb, NULL, DF_REF_REG_USE, 0, -1, -1);
 	}
     }
 
@@ -3598,7 +3717,7 @@ df_entry_block_defs_collect (struct df_c
   EXECUTE_IF_SET_IN_BITMAP (entry_block_defs, 0, i, bi)
     {
       df_ref_record (collection_rec, regno_reg_rtx[i], NULL, 
-		     ENTRY_BLOCK_PTR, NULL, DF_REF_REG_DEF, 0);
+		     ENTRY_BLOCK_PTR, NULL, DF_REF_REG_DEF, 0, -1, -1);
     }
 
   df_canonize_collection_rec (collection_rec);
@@ -3759,7 +3878,7 @@ df_exit_block_uses_collect (struct df_co
 
   EXECUTE_IF_SET_IN_BITMAP (exit_block_uses, 0, i, bi)
     df_ref_record (collection_rec, regno_reg_rtx[i], NULL,
-		   EXIT_BLOCK_PTR, NULL, DF_REF_REG_USE, 0);
+		   EXIT_BLOCK_PTR, NULL, DF_REF_REG_USE, 0, -1, -1);
 
 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM
   /* It is deliberate that this is not put in the exit block uses but
@@ -3769,7 +3888,7 @@ df_exit_block_uses_collect (struct df_co
       && bb_has_eh_pred (EXIT_BLOCK_PTR)
       && fixed_regs[ARG_POINTER_REGNUM])
     df_ref_record (collection_rec, regno_reg_rtx[ARG_POINTER_REGNUM], NULL,
-		   EXIT_BLOCK_PTR, NULL, DF_REF_REG_USE, 0);
+		   EXIT_BLOCK_PTR, NULL, DF_REF_REG_USE, 0, -1, -1);
 #endif
 
   df_canonize_collection_rec (collection_rec);
Index: global.c
===================================================================
--- global.c	(revision 132860)
+++ global.c	(working copy)
@@ -1490,7 +1490,7 @@ build_insn_chain (void)
 			/* We can model subregs, but not if they are
 			   wrapped in ZERO_EXTRACTS.  */
 			if (GET_CODE (reg) == SUBREG
-			    && !DF_REF_FLAGS_IS_SET (def, DF_REF_EXTRACT))
+			    && !DF_REF_FLAGS_IS_SET (def, DF_REF_ZERO_EXTRACT))
 			  {
 			    unsigned int start = SUBREG_BYTE (reg);
 			    unsigned int last = start 
@@ -1503,7 +1503,7 @@ build_insn_chain (void)
 						  regno, reg);
 
 			    if (!DF_REF_FLAGS_IS_SET
-				(def, DF_REF_STRICT_LOWER_PART))
+				(def, DF_REF_STRICT_LOW_PART))
 			      {
 				/* Expand the range to cover entire words.
 				   Bytes added here are "don't care".  */
@@ -1566,7 +1566,7 @@ build_insn_chain (void)
 		       precisely so we do not need to look at the
 		       fabricated use. */
 		    if (DF_REF_FLAGS_IS_SET (use, DF_REF_READ_WRITE) 
-			&& !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT) 
+			&& !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT) 
 			&& DF_REF_FLAGS_IS_SET (use, DF_REF_SUBREG))
 		      continue;
 		    
@@ -1585,7 +1585,7 @@ build_insn_chain (void)
 		    if (regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0)
 		      {
 			if (GET_CODE (reg) == SUBREG
-			    && !DF_REF_FLAGS_IS_SET (use, DF_REF_EXTRACT)) 
+			    && !DF_REF_FLAGS_IS_SET (use, DF_REF_ZERO_EXTRACT)) 
 			  {
 			    unsigned int start = SUBREG_BYTE (reg);
 			    unsigned int last = start 
Index: df.h
===================================================================
--- df.h	(revision 132860)
+++ df.h	(working copy)
@@ -117,14 +117,18 @@ enum df_ref_flags
     DF_REF_MUST_CLOBBER = 1 << 7,
 
 
-    /* This flag is set if this ref is inside a pre/post modify.  */
-    DF_REF_PRE_POST_MODIFY = 1 << 8,
+    /* If the ref has one of the following two flags set, then the
+       struct df_ref can be cast to struct df_ref_extract to access
+       the width and offset fields.  */
+ 
+    /* This flag is set if the ref contains a SIGN_EXTRACT.  */
+    DF_REF_SIGN_EXTRACT = 1 << 8,
 
-    /* This flag is set if the ref contains a ZERO_EXTRACT or SIGN_EXTRACT.  */
-    DF_REF_EXTRACT = 1 << 9,
+    /* This flag is set if the ref contains a ZERO_EXTRACT.  */
+    DF_REF_ZERO_EXTRACT = 1 << 9,
 
-    /* This flag is set if the ref contains a STRICT_LOWER_PART.  */
-    DF_REF_STRICT_LOWER_PART = 1 << 10,
+    /* This flag is set if the ref contains a STRICT_LOW_PART.  */
+    DF_REF_STRICT_LOW_PART = 1 << 10,
 
     /* This flag is set if the ref contains a SUBREG.  */
     DF_REF_SUBREG = 1 << 11,
@@ -138,7 +142,11 @@ enum df_ref_flags
     DF_REF_CALL_STACK_USAGE = 1 << 13,
 
     /* This flag is used for verification of existing refs. */
-    DF_REF_REG_MARKER = 1 << 14
+    DF_REF_REG_MARKER = 1 << 14,
+
+    /* This flag is set if this ref is inside a pre/post modify.  */
+    DF_REF_PRE_POST_MODIFY = 1 << 15
+
   };
 
 /* The possible ordering of refs within the df_ref_info.  */
@@ -381,6 +389,17 @@ struct df_ref
   struct df_ref *prev_reg;     /* Prev ref with same regno and type.  */
 };
 
+/* A df_ref_extract is just a df_ref with a width and offset field at
+   the end of it.  It is used to hold this information if the ref was
+   wrapped by a SIGN_EXTRACT or a ZERO_EXTRACT and to pass this info
+   to passes that wish to process partial regs precisely.  */
+struct df_ref_extract
+{
+  struct df_ref ref;
+  int width;
+  int offset;
+};
+
 /* These links are used for two purposes:
    1) def-use or use-def chains. 
    2) Multiword hard registers that underly a single hardware register.  */
@@ -598,7 +617,10 @@ struct df
 #define DF_REF_IS_REG_MARKED(REF) (DF_REF_FLAGS_IS_SET ((REF),DF_REF_REG_MARKER))
 #define DF_REF_NEXT_REG(REF) ((REF)->next_reg)
 #define DF_REF_PREV_REG(REF) ((REF)->prev_reg)
-
+/* The following two macros may only be applied if one of 
+   DF_REF_SIGN_EXTRACT | DF_REF_ZERO_EXTRACT is true. */ 
+#define DF_REF_WIDTH(REF) (((struct df_ref_extract *)(REF))->width)
+#define DF_REF_OFFSET(REF) (((struct df_ref_extract *)(REF))->offset)
 /* Macros to determine the reference type.  */
 
 #define DF_REF_REG_DEF_P(REF) (DF_REF_TYPE (REF) == DF_REF_REG_DEF)
@@ -862,7 +884,8 @@ extern void df_grow_reg_info (void);
 extern void df_grow_insn_info (void);
 extern void df_scan_blocks (void);
 extern struct df_ref *df_ref_create (rtx, rtx *, rtx,basic_block, 
-				     enum df_ref_type, enum df_ref_flags);
+				     enum df_ref_type, enum df_ref_flags,
+				     int, int);
 extern void df_ref_remove (struct df_ref *);
 extern struct df_insn_info * df_insn_create_insn_record (rtx);
 extern void df_insn_delete (basic_block, unsigned int);

  reply	other threads:[~2008-03-04 20:57 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-03-04 20:53 Kenneth Zadeck
2008-03-04 20:57 ` Kenneth Zadeck [this message]
2008-03-05 21:24   ` Ian Lance Taylor
2008-03-06  0:31     ` Kenneth Zadeck

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=47CDB78B.1020100@naturalbridge.com \
    --to=zadeck@naturalbridge.com \
    --cc=bonzini@gnu.org \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=iant@google.com \
    --cc=rsandifo@nildram.co.uk \
    --cc=seongbae.park@gmail.com \
    --cc=stevenb.gcc@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).