summaryrefslogtreecommitdiff
path: root/gcc/config/spu
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/spu')
-rw-r--r--gcc/config/spu/spu-protos.h1
-rw-r--r--gcc/config/spu/spu.c73
-rw-r--r--gcc/config/spu/spu.h11
3 files changed, 82 insertions, 3 deletions
diff --git a/gcc/config/spu/spu-protos.h b/gcc/config/spu/spu-protos.h
index cb5cc241539..9485f384f1f 100644
--- a/gcc/config/spu/spu-protos.h
+++ b/gcc/config/spu/spu-protos.h
@@ -76,6 +76,7 @@ extern void spu_builtin_insert (rtx ops[]);
extern void spu_builtin_promote (rtx ops[]);
extern void spu_expand_sign_extend (rtx ops[]);
extern void spu_expand_vector_init (rtx target, rtx vals);
+extern rtx spu_legitimize_reload_address (rtx, enum machine_mode, int, int);
#endif /* RTX_CODE */
extern void spu_init_expanders (void);
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
diff --git a/gcc/config/spu/spu.h b/gcc/config/spu/spu.h
index c69cf7efc4e..d89bf49f2d2 100644
--- a/gcc/config/spu/spu.h
+++ b/gcc/config/spu/spu.h
@@ -390,6 +390,17 @@ targetm.resolve_overloaded_builtin = spu_resolve_overloaded_builtin; \
#define MAX_REGS_PER_ADDRESS 2
+#define LEGITIMIZE_RELOAD_ADDRESS(AD, MODE, OPNUM, TYPE, IND, WIN) \
+do { \
+ rtx new_rtx = spu_legitimize_reload_address (AD, MODE, OPNUM, \
+ (int)(TYPE)); \
+ if (new_rtx) \
+ { \
+ (AD) = new_rtx; \
+ goto WIN; \
+ } \
+} while (0)
+
/* Costs */