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]

[RFC] Extend CSE to track const anchors


This is my attempt to fix PR/33699, which is a bug against MIPS.  The problem
is that for:

  typedef unsigned * ptr_t;
  void f (void) {
    ptr_t p = (ptr_t)0xFED0;
    p[0] = 0xDEAD;
    p[2] = 0xDEAD;
    p[4] = 0xDEAD;
    p[6] = 0xDEAD;
  }

the constant address is propagated into the address expressions so we load
four constants instead of using reg-offset addressing.

It's also somewhat related to this thread:

  http://gcc.gnu.org/ml/gcc/2009-02/threads.html#00114

Specifically, in

  f ()
  {
    g (0x12340001, 0x1233ffff);
  }

we synthesize the two constants indepedently.

The patch below changes CSE to insert anchor constants into the table of
available expressions along with the corresponding reg-offset expression.
Right now there is no prioritization or trimming of reg-offset expressions
that are equivalent to a constant anchor.  This is something I am planning to
look at later.

Also, the backend interface part of how anchor constants are specified is
completely missing; I just hard-coded reasonable MIPS values.

Since for some reason we don't CSE inside MEM expression I needed to make the
transformation from:

  (insn 8 7 9 2 /home/anemet/tmp/s.c:5 (set (reg/f:DI 195)
          (const_int 65240 [0xfed8])) 270 {*movdi_64bit} (nil))

to:

  // r193 holds 0xfed0
  (insn 8 7 9 2 /home/anemet/tmp/s.c:5 (set (reg/f:DI 195)
          (plus:DI (reg/f:DI 193)
              (const_int 8 [0x8]))) 11 {*adddi3} (expr_list:REG_EQUAL (const_int 65240 [0xfed8]) (nil)))

stick i.e. make its cost lower.  See the change and the comment in mips.c.
Later, it's combine (and not fwprop?!), who propagates the addition into the
MEM.

With this for the above tests we get:

        li      $2,65232                        # 0xfed0
        li      $3,57005                        # 0xdead
        sw      $3,24($2)
        sw      $3,0($2)
        sw      $3,8($2)
        j       $31
        sw      $3,16($2)

and

        li      $4,305397760                    # 0x12340000
        daddiu  $5,$4,-1
        j       g
        daddiu  $4,$4,1


Comments?  (Although this is technically a regression from 3.4, I am proposing
this for 4.5.)

Adam


	* cse.c (get_const_anchors): New function.
	(insert_const_anchors): New function.
	(cse_insn): Set src_related using anchor constants.  Insert
	constant anchors into the table of available expressions.

	* config/mips/mips.c (mips_rtx_costs): Make immediate-add even cheaper
	than loading a simple constant into a register.

Index: cse.c
===================================================================
--- cse.c	(revision 144568)
+++ cse.c	(working copy)
@@ -3961,6 +3961,50 @@ record_jump_cond (enum rtx_code code, en
 
   merge_equiv_classes (op0_elt, op1_elt);
 }
+
+#define TARGET_CONST_ANCHOR 0x8000
+
+/* Compute the upper and lower anchors for CST as base, offset pairs.  */
+
+static rtx
+get_const_anchors (rtx cst, rtx *upper_base, HOST_WIDE_INT *upper_offs,
+		   HOST_WIDE_INT *lower_offs)
+{
+  HOST_WIDE_INT n, upper, lower;
+
+  n = INTVAL (cst);
+  upper = (n + (TARGET_CONST_ANCHOR - 1)) & ~(TARGET_CONST_ANCHOR - 1);
+  lower = n & ~(TARGET_CONST_ANCHOR - 1);
+
+  *upper_base = GEN_INT (upper);
+  *upper_offs = n - upper;
+  *lower_offs = n - lower;
+  return GEN_INT (lower);
+}
+
+/* Create equivalences between the two anchors of a constant value and the
+   corresponding register-offset expressions.  Use the register REG, which is
+   equivalent to the constant value CLASSP->exp.  */
+
+static void
+insert_const_anchors (rtx reg, struct table_elt *classp,
+		      enum machine_mode mode)
+{
+  rtx lower_base, upper_base;
+  HOST_WIDE_INT lower_offs, upper_offs;
+  rtx lower_exp, upper_exp;
+  struct table_elt *celt;
+  rtx cst = classp->exp;
+
+  lower_base = get_const_anchors (cst, &upper_base, &upper_offs, &lower_offs);
+  lower_exp = plus_constant (reg, -lower_offs);
+  upper_exp = plus_constant (reg, -upper_offs);
+
+  celt = insert (lower_base, NULL, HASH (lower_base, mode), mode);
+  insert (lower_exp, celt, HASH (lower_exp, mode), mode);
+  celt = insert (upper_base, NULL, HASH (upper_base, mode), mode);
+  insert (upper_exp, celt, HASH (upper_exp, mode), mode);
+}
 
 /* CSE processing for one instruction.
    First simplify sources and addresses of all assignments
@@ -4594,6 +4638,64 @@ cse_insn (rtx insn)
 	}
 #endif /* LOAD_EXTEND_OP */
 
+      /* Try to express the constant using a register-offset expresion using
+	 anchor constants.  */
+
+      if (!src_related && src_const && GET_CODE (src_const) == CONST_INT)
+	{
+	  rtx lower_base, upper_base;
+	  struct table_elt *lower_elt, *upper_elt, *elt;
+	  HOST_WIDE_INT lower_offs, upper_offs, offs;
+
+	  lower_base = get_const_anchors (src_const, &upper_base, &upper_offs,
+					  &lower_offs);
+	  lower_elt = lookup (lower_base, HASH (lower_base, mode), mode);
+	  upper_elt = lookup (upper_base, HASH (upper_base, mode), mode);
+
+	  /* Loop over LOWER_ELTs and UPPER_ELTs to find a reg-offset pair
+	     that we can use to express SRC_CONST.  */
+	  elt = NULL;
+	  if (lower_elt)
+	    {
+	      elt = lower_elt->first_same_value;
+	      offs = lower_offs;
+	    }
+	  else if (upper_elt)
+	    {
+	      elt = upper_elt->first_same_value;
+	      upper_elt = NULL;
+	      offs = upper_offs;
+	    }
+	  while (elt)
+	    {
+	      if (REG_P (elt->exp)
+		  || (GET_CODE (elt->exp) == PLUS
+		      && REG_P (XEXP (elt->exp, 0))
+		      && GET_CODE (XEXP (elt->exp, 1)) == CONST_INT))
+		{
+		  rtx x = plus_constant (elt->exp, offs);
+		  if (REG_P (x)
+		      || (GET_CODE (x) == PLUS
+			  && IN_RANGE (INTVAL (XEXP (x, 1)),
+				       -TARGET_CONST_ANCHOR,
+				       TARGET_CONST_ANCHOR - 1)))
+		    {
+		      src_related = x;
+		      break;
+		    }
+		}	      
+
+	      if (!elt->next_same_value && upper_elt)
+		{
+		  elt = upper_elt->first_same_value;
+		  upper_elt = NULL;
+		  offs = upper_offs;
+		}
+	      else
+		elt = elt->next_same_value;
+	    }
+	}
+
       if (src == src_folded)
 	src_folded = 0;
 
@@ -5432,6 +5534,11 @@ cse_insn (rtx insn)
 	elt = insert (dest, sets[i].src_elt,
 		      sets[i].dest_hash, GET_MODE (dest));
 
+	/* If this is a constant, insert the constant anchors with the
+	   equivalent register-offset expressions using DEST.  */
+	if (GET_CODE (sets[i].src_elt->exp) == CONST_INT)
+	  insert_const_anchors (dest, sets[i].src_elt, GET_MODE (dest));
+
 	elt->in_memory = (MEM_P (sets[i].inner_dest)
 			  && !MEM_READONLY_P (sets[i].inner_dest));
 
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 144568)
+++ config/mips/mips.c	(working copy)
@@ -3573,6 +3573,17 @@ mips_rtx_costs (rtx x, int code, int out
 	  return false;
 	}
 
+      /* CSE creates these for loading a constant into a register.  In that
+	 case the first operand is a register used somewhere else holding a
+	 value that can be used to derive the constant value.  Prefer them
+	 even over simple constant sets as these can be propagated into MEM
+	 expressions.  */
+      if (mips_immediate_operand_p (PLUS, INTVAL (XEXP (x, 1))))
+	{
+	  *total = -1;
+	  return true;
+	}
+
       /* Double-word operations require three single-word operations and
 	 an SLTU.  The MIPS16 version then needs to move the result of
 	 the SLTU from $24 to a MIPS16 register.  */


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