diff options
Diffstat (limited to 'gcc/config/spu')
-rw-r--r-- | gcc/config/spu/spu-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/spu/spu.c | 73 | ||||
-rw-r--r-- | gcc/config/spu/spu.h | 11 |
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 */ |