summaryrefslogtreecommitdiff
path: root/gcc/config/spu/spu.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/spu/spu.c')
-rw-r--r--gcc/config/spu/spu.c73
1 files changed, 70 insertions, 3 deletions
diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
index c6db6c3b3b0..b8e3fb35da3 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -982,6 +982,27 @@ spu_emit_branch_or_set (int is_set, rtx cmp, rtx operands[])
}
}
+ /* However, if we generate an integer result, performing a reverse test
+ would require an extra negation, so avoid that where possible. */
+ if (GET_CODE (op1) == CONST_INT && is_set == 1)
+ {
+ HOST_WIDE_INT val = INTVAL (op1) + 1;
+ if (trunc_int_for_mode (val, GET_MODE (op0)) == val)
+ switch (code)
+ {
+ case LE:
+ op1 = GEN_INT (val);
+ code = LT;
+ break;
+ case LEU:
+ op1 = GEN_INT (val);
+ code = LTU;
+ break;
+ default:
+ break;
+ }
+ }
+
comp_mode = SImode;
op_mode = GET_MODE (op0);
@@ -1113,7 +1134,8 @@ spu_emit_branch_or_set (int is_set, rtx cmp, rtx operands[])
if (is_set == 0 && op1 == const0_rtx
&& (GET_MODE (op0) == SImode
- || GET_MODE (op0) == HImode) && scode == SPU_EQ)
+ || GET_MODE (op0) == HImode
+ || GET_MODE (op0) == QImode) && scode == SPU_EQ)
{
/* Don't need to set a register with the result when we are
comparing against zero and branching. */
@@ -3803,8 +3825,14 @@ spu_legitimate_address_p (enum machine_mode mode,
if (GET_CODE (op0) == REG
&& INT_REG_OK_FOR_BASE_P (op0, reg_ok_strict)
&& GET_CODE (op1) == CONST_INT
- && INTVAL (op1) >= -0x2000
- && INTVAL (op1) <= 0x1fff
+ && ((INTVAL (op1) >= -0x2000 && INTVAL (op1) <= 0x1fff)
+ /* If virtual registers are involved, the displacement will
+ change later on anyway, so checking would be premature.
+ Reload will make sure the final displacement after
+ register elimination is OK. */
+ || op0 == arg_pointer_rtx
+ || op0 == frame_pointer_rtx
+ || op0 == virtual_stack_vars_rtx)
&& (!aligned || (INTVAL (op1) & 15) == 0))
return TRUE;
if (GET_CODE (op0) == REG
@@ -3877,6 +3905,45 @@ spu_addr_space_legitimize_address (rtx x, rtx oldx, enum machine_mode mode,
return spu_legitimize_address (x, oldx, mode);
}
+/* Reload reg + const_int for out-of-range displacements. */
+rtx
+spu_legitimize_reload_address (rtx ad, enum machine_mode mode ATTRIBUTE_UNUSED,
+ int opnum, int type)
+{
+ bool removed_and = false;
+
+ if (GET_CODE (ad) == AND
+ && CONST_INT_P (XEXP (ad, 1))
+ && INTVAL (XEXP (ad, 1)) == (HOST_WIDE_INT) - 16)
+ {
+ ad = XEXP (ad, 0);
+ removed_and = true;
+ }
+
+ if (GET_CODE (ad) == PLUS
+ && REG_P (XEXP (ad, 0))
+ && CONST_INT_P (XEXP (ad, 1))
+ && !(INTVAL (XEXP (ad, 1)) >= -0x2000
+ && INTVAL (XEXP (ad, 1)) <= 0x1fff))
+ {
+ /* Unshare the sum. */
+ ad = copy_rtx (ad);
+
+ /* Reload the displacement. */
+ push_reload (XEXP (ad, 1), NULL_RTX, &XEXP (ad, 1), NULL,
+ BASE_REG_CLASS, GET_MODE (ad), VOIDmode, 0, 0,
+ opnum, (enum reload_type) type);
+
+ /* Add back AND for alignment if we stripped it. */
+ if (removed_and)
+ ad = gen_rtx_AND (GET_MODE (ad), ad, GEN_INT (-16));
+
+ return ad;
+ }
+
+ return NULL_RTX;
+}
+
/* Handle an attribute requiring a FUNCTION_DECL; arguments as in
struct attribute_spec.handler. */
static tree