Jean Christophe Beyler writes:
> I set up your patch and I get an internal error on this test program:

You're right.  I haven't handled the case properly when the constant itself
was an anchor constant (e.g. 0).  Try this version.

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: gcc/cse.c
===================================================================
--- gcc.orig/cse.c      2009-03-08 12:16:56.000000000 -0700
+++ gcc/cse.c   2009-03-16 23:07:40.000000000 -0700
@@ -3961,6 +3961,55 @@ 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.  Return
+   NULL_RTX if CST is equal to an anchor.  */
+
+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);
+  lower = n & ~(TARGET_CONST_ANCHOR - 1);
+  if (n == lower)
+    return NULL_RTX;
+  upper = (n + (TARGET_CONST_ANCHOR - 1)) & ~(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);
+  if (!lower_base)
+    return;
+  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
@@ -4595,6 +4644,67 @@ cse_insn (rtx insn)
        }
 #endif /* LOAD_EXTEND_OP */
 
+      /* Try to express the constant using a register-offset expression 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);
+         if (lower_base)
+           {
+             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;
 
@@ -5433,6 +5543,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: gcc/config/mips/mips.c
===================================================================
--- gcc.orig/config/mips/mips.c 2009-03-08 10:13:18.000000000 -0700
+++ gcc/config/mips/mips.c      2009-03-15 11:37:48.000000000 -0700
@@ -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.  */

Reply via email to