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. */