public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/vendors/riscv/heads/ext-dce)] Add more comments. Fix various formatting problems. Add extensions as safe to propagate through.
@ 2023-11-15 19:01 Jeff Law
  0 siblings, 0 replies; only message in thread
From: Jeff Law @ 2023-11-15 19:01 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:c3fda9f9af9749c46f7d60e62b598427ae05a77f

commit c3fda9f9af9749c46f7d60e62b598427ae05a77f
Author: Jeff Law <jlaw@ventanamicro.com>
Date:   Wed Nov 15 11:58:09 2023 -0700

    Add more comments.  Fix various formatting problems.  Add extensions as safe to propagate through.

Diff:
---
 gcc/ext-dce.cc | 450 ++++++++++++++++++++++++++++++---------------------------
 1 file changed, 234 insertions(+), 216 deletions(-)

diff --git a/gcc/ext-dce.cc b/gcc/ext-dce.cc
index 8a91f1ebbfc..9cf0a3c2ae3 100644
--- a/gcc/ext-dce.cc
+++ b/gcc/ext-dce.cc
@@ -60,6 +60,8 @@ safe_for_live_propagation (rtx_code code)
     case NOT:
     case PLUS:
     case MULT:
+    case ZERO_EXTEND:
+    case SIGN_EXTEND:
 
     /* ?!? These should be double-checked.  */
     case MINUS:
@@ -265,7 +267,7 @@ ext_dce_try_optimize_insn (rtx_insn *insn, rtx set, bitmap changed_pseudos)
 /* Some operators imply that their second operand is fully live,
    regardless of how many bits in the output are live.  An example
    would be the shift count on a target without SHIFT_COUNT_TRUCATED
-   defined. 
+   defined.
 
    Return TRUE if CODE is such an operator.  FALSE otherwise.  */
 
@@ -307,250 +309,266 @@ ext_dce_process_uses (rtx_insn *insn, bitmap livenow, bitmap live_tmp,
 	bitmap_set_range (livenow, HARD_FRAME_POINTER_REGNUM * 4, 4);
     }
 
-  for (rtx pat = PATTERN (insn);;)
+ restart:
+  subrtx_var_iterator::array_type array_var;
+  rtx pat = PATTERN (insn);
+  FOR_EACH_SUBRTX_VAR (iter, array_var, pat, NONCONST)
     {
-      subrtx_var_iterator::array_type array_var;
-      FOR_EACH_SUBRTX_VAR (iter, array_var, pat, NONCONST)
+      /* An EXPR_LIST (from call fusage) ends in NULL_RTX.  */
+      rtx x = *iter;
+      if (x == NULL_RTX)
+	continue;
+
+      /* So the basic idea in this FOR_EACH_SUBRTX_VAR loop is to
+	 handle SETs explicitly, possibly propagating live information
+	 into the uses.
+
+	 We may continue the loop at various points which will cause
+	 iteration into the next level of RTL.  Breaking from the loop
+	 is never safe as it can lead us to fail to process some of the
+	 RTL and thus not make objects live when necessary.  */
+      enum rtx_code xcode = GET_CODE (x);
+      if (GET_CODE (x) == SET)
 	{
-	  rtx x = *iter;
-	  /* An EXPR_LIST (from call fusage) ends in NULL_RTX.  */
-	  if (x == NULL_RTX)
-	    continue;
-	  enum rtx_code xcode = GET_CODE (x);
+	  const_rtx dst = SET_DEST (x);
+	  rtx src = SET_SRC (x);
+	  const_rtx y;
+	  unsigned HOST_WIDE_INT bit = 0;
+
+	  /* The code of the RHS of a SET.  */
+	  enum rtx_code code = GET_CODE (src);
 
-	  if (GET_CODE (x) == SET)
+	  /* ?!? How much of this should mirror SET handling, potentially
+	     being shared?  */
+	  if (SUBREG_P (dst))
 	    {
-	      const_rtx dst = SET_DEST (x);
-	      rtx src = SET_SRC (x);
-	      const_rtx y;
-	      unsigned HOST_WIDE_INT bit = 0;
-	      enum rtx_code code = GET_CODE (src);
-
-	      /* ?!? How much of this should mirror SET handling, potentially
-		 being shared?  */
-	      if (SUBREG_P (dst))
-		{
-		  bit = SUBREG_BYTE (dst).to_constant () * BITS_PER_UNIT;
-		  if (WORDS_BIG_ENDIAN)
-		    bit = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (dst))).to_constant ()
-			   - GET_MODE_BITSIZE (GET_MODE (dst)).to_constant () - bit);
-		  if (bit >= HOST_BITS_PER_WIDE_INT)
-		    bit = HOST_BITS_PER_WIDE_INT - 1;
-		  dst = SUBREG_REG (dst);
-		}
-	      else if (GET_CODE (dst) == ZERO_EXTRACT
-		       || GET_CODE (dst) == STRICT_LOW_PART)
-		dst = XEXP (dst, 0);
-
-	      /* Main processing of the uses.  Two major goals here.
-
-		 First, we want to try and propagate liveness (or the lack
-		 thereof) from the destination register to the source
-		 register(s).
-
-		 Second, if the source is an extension, try to optimize
-		 it into a SUBREG.  The SUBREG form indicates we don't
-		 care about the upper bits and will usually be copy
-		 propagated away.  */
-	      /* ?!? What to do with SUBREGs that aren't REGS?  */
-	      if (REG_P (dst) && safe_for_live_propagation (code))
-		{
-		  /* Create a mask representing the bits of this output
-		     operand that are live after this insn.  We can use
-		     this information to refine the live in state of
-		     inputs to this insn.
-
-		     We have to do this on a per SET basis, we might have
-		     an INSN with multiple SETS, some of which can narrow
-		     the source operand liveness, some of which may not.  */
-		  unsigned HOST_WIDE_INT dst_mask = 0;
-		  HOST_WIDE_INT rn = REGNO (dst);
-		  unsigned HOST_WIDE_INT mask_array[]
-		    = { 0xff, 0xff00, 0xffff0000ULL, -0x100000000ULL };
-		  for (int i = 0; i < 4; i++)
-		    if (bitmap_bit_p (live_tmp, 4 * rn + i))
-		      dst_mask |= mask_array[i];
-		  dst_mask >>= bit;
-
-		  /* ??? Could also handle ZERO_EXTRACT / SIGN_EXTRACT
-		     of the source specially to improve optimization.  */
-		  if (code == SIGN_EXTEND || code == ZERO_EXTEND)
-		    {
-		      rtx inner = XEXP (src, 0);
-		      unsigned HOST_WIDE_INT src_mask
-			= GET_MODE_MASK (GET_MODE (inner));
+	      bit = SUBREG_BYTE (dst).to_constant () * BITS_PER_UNIT;
+	      if (WORDS_BIG_ENDIAN)
+		bit = (GET_MODE_BITSIZE (GET_MODE (SUBREG_REG (dst))).to_constant ()
+		       - GET_MODE_BITSIZE (GET_MODE (dst)).to_constant () - bit);
+	      if (bit >= HOST_BITS_PER_WIDE_INT)
+		bit = HOST_BITS_PER_WIDE_INT - 1;
+	      dst = SUBREG_REG (dst);
+	    }
+	  else if (GET_CODE (dst) == ZERO_EXTRACT
+		   || GET_CODE (dst) == STRICT_LOW_PART)
+	    dst = XEXP (dst, 0);
 
-#if 0
-		      /* ?!? This seems like it shouldn't be necessary.  */
-		      /* Pretend there is one additional higher bit set in
-			 MASK2 to account for the sign bit propagation from the
-			 input value into the output value.  */
-		      if (code == SIGN_EXTEND)
-			{
-			  src_mask <<= 1;
-			  src_mask |= 1;
-			}
-#endif
+	  /* Main processing of the uses.  Two major goals here.
 
-		      /* (subreg (mem)) is technically valid RTL, but is
-			 severely discouraged.  So give up if we're about to
-			 create one.
+	     First, we want to try and propagate liveness (or the lack
+	     thereof) from the destination register to the source
+	     register(s).
 
-			 If this were to be loosened, then we'd still need to
-			 reject mode dependent addresses and volatile memory
-			 accesses.  */
-		      if (!REG_P (inner))
-			continue;
+	     Second, if the source is an extension, try to optimize
+	     it into a SUBREG.  The SUBREG form indicates we don't
+	     care about the upper bits and will usually be copy
+	     propagated away.
 
-		      /* DST_MASK could be zero if we had something in the SET
-			 that we couldn't handle.  */
-		      if (modify && dst_mask && (dst_mask & ~src_mask) == 0)
-			ext_dce_try_optimize_insn (insn, x, changed_pseudos);
+	     If we fail to handle something in here, the expectation
+	     is the iterator will dive into the sub-components and
+	     mark all the chunks in any found REGs as live.  */
+	  if (REG_P (dst) && safe_for_live_propagation (code))
+	    {
+	      /* Create a mask representing the bits of this output
+		 operand that are live after this insn.  We can use
+		 this information to refine the live in state of
+		 inputs to this insn in many cases.
+
+		 We have to do this on a per SET basis, we might have
+		 an INSN with multiple SETS, some of which can narrow
+		 the source operand liveness, some of which may not.  */
+	      unsigned HOST_WIDE_INT dst_mask = 0;
+	      HOST_WIDE_INT rn = REGNO (dst);
+	      unsigned HOST_WIDE_INT mask_array[]
+		= { 0xff, 0xff00, 0xffff0000ULL, -0x100000000ULL };
+	      for (int i = 0; i < 4; i++)
+		if (bitmap_bit_p (live_tmp, 4 * rn + i))
+		  dst_mask |= mask_array[i];
+	      dst_mask >>= bit;
+
+	      /* ??? Could also handle ZERO_EXTRACT / SIGN_EXTRACT
+		 of the source specially to improve optimization.  */
+	      if (code == SIGN_EXTEND || code == ZERO_EXTEND)
+		{
+		  rtx inner = XEXP (src, 0);
+		  unsigned HOST_WIDE_INT src_mask
+		    = GET_MODE_MASK (GET_MODE (inner));
 
-		      dst_mask &= src_mask;
-		      src = XEXP (src, 0);
-		      code = GET_CODE (src);
+#if 0
+		  /* ?!? This seems like it shouldn't be necessary.  */
+		  /* Pretend there is one additional higher bit set in
+		     MASK2 to account for the sign bit propagation from the
+		     input value into the output value.  */
+		  if (code == SIGN_EXTEND)
+		    {
+		      src_mask <<= 1;
+		      src_mask |= 1;
 		    }
+#endif
 
+		  /* (subreg (mem)) is technically valid RTL, but is
+		     severely discouraged.  So give up if we're about to
+		     create one.
 
-		  /* ?!? What is the point of this adjustment to DST_MASK?  */
-		  if (code == PLUS || code == MINUS || code == MULT
-		      || code == ASHIFT)
-		    dst_mask
-		      = dst_mask ? ((2ULL << floor_log2 (dst_mask)) - 1) : 0;
+		     If this were to be loosened, then we'd still need to
+		     reject mode dependent addresses and volatile memory
+		     accesses.  */
+		  if (MEM_P (inner))
+		    continue;
 
-		  /* We will handle the other operand of a binary operator
-		     at the bottom of the loop by resetting Y.  */
-		  if (BINARY_P (src))
-		    y = XEXP (src, 0);
-		  else
-		    y = src;
+		  /* DST_MASK could be zero if we had something in the SET
+		     that we couldn't handle.  */
+		  if (modify && dst_mask && (dst_mask & ~src_mask) == 0)
+		    ext_dce_try_optimize_insn (insn, x, changed_pseudos);
 
-		  for (;;)
-		    {
-		      if (paradoxical_subreg_p (y))
-			y = SUBREG_REG (y);
-		      else if (SUBREG_P (y))
-			{
-			  bit = (SUBREG_BYTE (y).to_constant ()
-				 * BITS_PER_UNIT);
-			  if (WORDS_BIG_ENDIAN)
-			    bit = (GET_MODE_BITSIZE
-				   (GET_MODE (SUBREG_REG (y))).to_constant ()
-				    - GET_MODE_BITSIZE (GET_MODE (y)).to_constant () - bit);
-			  if (dst_mask)
-			    {
-			      dst_mask <<= bit;
-			      if (!dst_mask)
-				dst_mask = -0x100000000ULL;
-			    }
-			  y = SUBREG_REG (y);
-			}
+		  dst_mask &= src_mask;
+		  src = XEXP (src, 0);
+		  code = GET_CODE (src);
+		}
 
-		      if (REG_P (y))
-			{
-			  rn = 4 * REGNO (y);
-			  unsigned HOST_WIDE_INT tmp_mask = dst_mask;
-
-			  if (!safe_for_live_propagation (code))
-			    tmp_mask = GET_MODE_MASK (GET_MODE (y));
-
-			  if (tmp_mask & 0xff)
-			    bitmap_set_bit (livenow, rn);
-			  if (tmp_mask & 0xff00)
-			    bitmap_set_bit (livenow, rn + 1);
-			  if (tmp_mask & 0xffff0000ULL)
-			    bitmap_set_bit (livenow, rn + 2);
-			  if (tmp_mask & -0x100000000ULL)
-			    bitmap_set_bit (livenow, rn + 3);
-
-
-			  /* Some operators imply their second operand
-			     is fully live.  */
-			  if (binop_implies_op2_fully_live (code))
-			    {
-			      rtx x = XEXP (src, 1);
-			      if (GET_CODE (x) == SUBREG)
-				x = SUBREG_REG (x);
-			      if (REG_P (x))
-				{
-				  bitmap_set_range (livenow, REGNO (x) * 4, 4);
-				  break;
-				}
-			    }
-			}
-		      /* !?! This looks wrong.  Y does not have to be a leaf
-			 here.  Consider a shift-add as an example or a PLUS
-			 where one or both operands are sign/zero extended. 
-			 Breaking out of the loop would cause us to fail to
-			 set liveness correctly.  */
-		      else if (!CONSTANT_P (y))
+	      /* Optimization is done at this point.  We just want to make
+		 sure everything that should get marked as live is marked
+		 from here onward.  */
+
+	      /* ?!? What is the point of this adjustment to DST_MASK?  */
+	      if (code == PLUS || code == MINUS
+		  || code == MULT || code == ASHIFT)
+		dst_mask
+		  = dst_mask ? ((2ULL << floor_log2 (dst_mask)) - 1) : 0;
+
+	      /* We will handle the other operand of a binary operator
+		 at the bottom of the loop by resetting Y.  */
+	      if (BINARY_P (src))
+		y = XEXP (src, 0);
+	      else
+		y = src;
+
+	      /* We're inside a SET and want to process the source operands
+		 making things live.  Breaking from this loop will cause
+		 the iterator to work on sub-rtxs, so it is safe to break
+		 if we see something we don't know how to handle.  */
+	      for (;;)
+		{
+		  if (paradoxical_subreg_p (y))
+		    y = SUBREG_REG (y);
+		  else if (SUBREG_P (y))
+		    {
+		      /* For anything but (subreg (reg)), break the inner loop
+			 and process normally (conservatively).  */
+		      if (!REG_P (SUBREG_REG (y)))
 			break;
-		      /* We might have (ashift (const_int 1) (reg...)) */
-		      else if (CONSTANT_P (y) 
-			       && binop_implies_op2_fully_live (GET_CODE (src)))
+		      bit = (SUBREG_BYTE (y).to_constant () * BITS_PER_UNIT);
+		      if (WORDS_BIG_ENDIAN)
+			bit = (GET_MODE_BITSIZE
+			       (GET_MODE (SUBREG_REG (y))).to_constant ()
+				- GET_MODE_BITSIZE (GET_MODE (y)).to_constant () - bit);
+		      if (dst_mask)
 			{
-			  rtx x = XEXP (src, 1);
-			  if (GET_CODE (x) == SUBREG)
-			    x = SUBREG_REG (x);
-
-			  if (REG_P (x))
-			    {
-			      bitmap_set_range (livenow, REGNO (x) * 4, 4);
-			      break;
-			    }
+			  dst_mask <<= bit;
+			  if (!dst_mask)
+			    dst_mask = -0x100000000ULL;
 			}
-		      /* This looks wrong for ternary operators.  */
-		      if (!BINARY_P (src))
-			break;
-		      y = XEXP (src, 1), src = pc_rtx;
+		      y = SUBREG_REG (y);
 		    }
 
-		  if (REG_P (y) || CONSTANT_P (y))
-		    iter.skip_subrtxes ();
+		  if (REG_P (y))
+		    {
+		      rn = 4 * REGNO (y);
+		      unsigned HOST_WIDE_INT tmp_mask = dst_mask;
+
+		      /* If the RTX code for the SET_SRC is not one we can
+			 propagate destination liveness through, then just
+			 set the mask to the mode's mask.  */
+		      if (!safe_for_live_propagation (code))
+			tmp_mask = GET_MODE_MASK (GET_MODE (y));
+
+		      if (tmp_mask & 0xff)
+			bitmap_set_bit (livenow, rn);
+		      if (tmp_mask & 0xff00)
+			bitmap_set_bit (livenow, rn + 1);
+		      if (tmp_mask & 0xffff0000ULL)
+			bitmap_set_bit (livenow, rn + 2);
+		      if (tmp_mask & -0x100000000ULL)
+			bitmap_set_bit (livenow, rn + 3);
+
+		      /* Some operators imply their second operand
+			 is fully live, break this inner loop which
+			 will cause the iterator to descent into the
+			 sub-rtxs which should be safe.  */
+		      if (binop_implies_op2_fully_live (code))
+			break;
+		    }
+		  else if (!CONSTANT_P (y))
+		    break;
+		  /* We might have (ashift (const_int 1) (reg...)) */
+		  else if (CONSTANT_P (y)
+			   && binop_implies_op2_fully_live (GET_CODE (src)))
+		    break;
+
+		  /* If this was anything but a binary operand, break the inner
+		     loop.  This is conservatively correct as it will cause the
+		     iterator to look at the sub-rtxs.  */
+		  if (!BINARY_P (src))
+		    break;
+
+		  /* We processed the first operand of a binary operator.  Now
+		     handle the second.  */
+		  y = XEXP (src, 1), src = pc_rtx;
 		}
-	      else if (REG_P (dst))
-		iter.substitute (src);
-	    }
-	  /* If we are reading the low part of a SUBREG, then we can
-	     refine liveness of the input register, otherwise let the
-	     iterator continue into SUBREG_REG.  */
-	  else if (xcode == SUBREG
-		   && REG_P (SUBREG_REG (x))
-		   && subreg_lowpart_p (x)
-		   && GET_MODE_BITSIZE (GET_MODE  (x)).to_constant () <= 32)
-	    {
-	      HOST_WIDE_INT size
-		= GET_MODE_BITSIZE (GET_MODE  (x)).to_constant ();
-
-	      HOST_WIDE_INT rn = 4 * REGNO (SUBREG_REG (x));
-
-	      bitmap_set_bit (livenow, rn);
-	      if (size > 8)
-		bitmap_set_bit (livenow, rn+1);
-	      if (size > 16)
-		bitmap_set_bit (livenow, rn+2);
-	      if (size > 32)
-		bitmap_set_bit (livenow, rn+3);
-	      iter.skip_subrtxes ();
+
+	      if (REG_P (y) || CONSTANT_P (y))
+		iter.skip_subrtxes ();
 	    }
-	  else if (REG_P (x))
-	    bitmap_set_range (livenow, REGNO (x) * 4, 4);
-	  else if (GET_CODE (x) == CLOBBER)
-	    continue;
+	  else if (REG_P (dst))
+	    iter.substitute (src);
 	}
-      if (GET_CODE (insn) != CALL_INSN || seen_fusage)
-	break;
-      pat = CALL_INSN_FUNCTION_USAGE (insn);
+      /* If we are reading the low part of a SUBREG, then we can
+	 refine liveness of the input register, otherwise let the
+	 iterator continue into SUBREG_REG.  */
+      else if (xcode == SUBREG
+	       && REG_P (SUBREG_REG (x))
+	       && subreg_lowpart_p (x)
+	       && GET_MODE_BITSIZE (GET_MODE  (x)).to_constant () <= 32)
+	{
+	  HOST_WIDE_INT size = GET_MODE_BITSIZE (GET_MODE  (x)).to_constant ();
+	  HOST_WIDE_INT rn = 4 * REGNO (SUBREG_REG (x));
+
+	  bitmap_set_bit (livenow, rn);
+	  if (size > 8)
+	    bitmap_set_bit (livenow, rn + 1);
+	  if (size > 16)
+	    bitmap_set_bit (livenow, rn + 2);
+	  if (size > 32)
+	    bitmap_set_bit (livenow, rn + 3);
+	  iter.skip_subrtxes ();
+	}
+      /* If we have a register reference that is not otherwise handled,
+	 just assume all the chunks are live.  */
+      else if (REG_P (x))
+	bitmap_set_range (livenow, REGNO (x) * 4, 4);
+    }
+
+  /* A bit of special handling for CALL_INSNs.  We need to look
+     at their fusage as well as set some implicit references.  */
+  if (GET_CODE (insn) == CALL_INSN && !seen_fusage)
+    {
+      /* We only need to do this processing once per call.  */
       seen_fusage = true;
+
       if (!FAKE_CALL_P (insn))
 	bitmap_set_range (livenow, STACK_POINTER_REGNUM * 4, 4);
-      /* Unless this is a call to a const function, it can read any
-	 global register.  */
-      if (RTL_CONST_CALL_P (insn))
+
+      /* If this is not a call to a const fucntion, then assume it
+	 can read any global register.  */
+      if (!RTL_CONST_CALL_P (insn))
 	for (unsigned i = 0; i < FIRST_PSEUDO_REGISTER; i++)
 	  if (global_regs[i])
 	    bitmap_set_range (livenow, i * 4, 4);
+
+      /* Process CALL_INSN_USAGE.  */
+      pat = CALL_INSN_FUNCTION_USAGE (insn);
+      goto restart;
     }
 }

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2023-11-15 19:01 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-11-15 19:01 [gcc(refs/vendors/riscv/heads/ext-dce)] Add more comments. Fix various formatting problems. Add extensions as safe to propagate through Jeff Law

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).