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