+2005-01-14 Aldy Hernandez <aldyh@redhat.com>
+
+ * config/rs6000/rs6000.h (CLASS_MAX_NREGS): DF goes in 1 register
+ on e500v2.
+ (CANNOT_CHANGE_MODE_CLASS): Restrict DI mode changes on e500v2.
+ (PREDICATE_CODES): Add rs6k_nonimmediate_operand.
+
+ * config/rs6000/rs6000.c (invalid_e500_subreg): New.
+ (rs6k_nonimmediate_operand): New.
+ (rs6000_legitimate_offset_address_p): Handle DI modes on e500v2
+ correctly.
+ (legitimate_lo_sum_address_p): Same.
+ (rs6000_legitimize_address): Same.
+ (rs6000_legitimize_reload_address): Same.
+ (rs6000_legitimate_address): Same.
+ (spe_build_register_parallel): Pass DF and DC modes in a DI
+ register.
+
+ * config/rs6000/rs6000.md ("*movsi_internal1"): Change predicate
+ to rs6k_nonimmediate_operand.
+
+ * config/rs6000/spe.md ("*frob_df_di"): New.
+ ("*frob_di_df"): New.
+ ("*frob_di_df_2"): New.
+ ("*mov_sidf_e500_subreg0"): New.
+ ("*mov_sidf_e500_subreg4"): New.
+ ("*movdf_e500_double"): Change predicate to
+ rs6k_nonimmediate_operand.
+
2005-01-14 Aldy Hernandez <aldyh@redhat.com>
* postreload.c (move2add_note_store): Only call
static rtx spe_expand_stv_builtin (enum insn_code, tree);
static rtx spe_expand_predicate_builtin (enum insn_code, tree, rtx);
static rtx spe_expand_evsel_builtin (enum insn_code, tree, rtx);
+static bool invalid_e500_subreg (rtx, enum machine_mode);
static int rs6000_emit_int_cmove (rtx, rtx, rtx, rtx);
static rs6000_stack_t *rs6000_stack_info (void);
static void debug_stack_info (rs6000_stack_t *);
return 0;
}
+/* Return TRUE if OP is an invalid SUBREG operation on the e500. */
+static bool
+invalid_e500_subreg (rtx op, enum machine_mode mode)
+{
+ /* Reject (subreg:SI (reg:DF)). */
+ if (GET_CODE (op) == SUBREG
+ && mode == SImode
+ && REG_P (SUBREG_REG (op))
+ && GET_MODE (SUBREG_REG (op)) == DFmode)
+ return true;
+
+ /* Reject (subreg:DF (reg:DI)). */
+ if (GET_CODE (op) == SUBREG
+ && mode == DFmode
+ && REG_P (SUBREG_REG (op))
+ && GET_MODE (SUBREG_REG (op)) == DImode)
+ return true;
+
+ return false;
+}
+
+/* Just like nonimmediate_operand, but return 0 for invalid SUBREG's
+ on the e500. */
+int
+rs6k_nonimmediate_operand (rtx op, enum machine_mode mode)
+{
+ if (TARGET_E500_DOUBLE
+ && GET_CODE (op) == SUBREG
+ && invalid_e500_subreg (op, mode))
+ return 0;
+
+ return nonimmediate_operand (op, mode);
+}
/* Darwin, AIX increases natural record alignment to doubleword if the first
field is an FP double while the FP fields remain word aligned. */
return SPE_CONST_OFFSET_OK (offset);
case DImode:
+ /* On e500v2, we may have:
+
+ (subreg:DF (mem:DI (plus (reg) (const_int))) 0).
+
+ Which gets addressed with evldd instructions. */
+ if (TARGET_E500_DOUBLE)
+ return SPE_CONST_OFFSET_OK (offset);
+
if (mode == DFmode || !TARGET_POWERPC64)
extra = 4;
else if (offset & 3)
return false;
if (!INT_REG_OK_FOR_BASE_P (XEXP (x, 0), strict))
return false;
- if (TARGET_E500_DOUBLE && mode == DFmode)
+ /* Restrict addressing for DI because of our SUBREG hackery. */
+ if (TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
return false;
x = XEXP (x, 1);
&& GET_MODE_NUNITS (mode) == 1
&& ((TARGET_HARD_FLOAT && TARGET_FPRS)
|| TARGET_POWERPC64
- || ((mode != DFmode || TARGET_E500_DOUBLE) && mode != TFmode))
+ || (((mode != DImode && mode != DFmode) || TARGET_E500_DOUBLE)
+ && mode != TFmode))
&& (TARGET_POWERPC64 || mode != DImode)
&& mode != TImode)
{
return reg;
}
else if (SPE_VECTOR_MODE (mode)
- || (TARGET_E500_DOUBLE && mode == DFmode))
+ || (TARGET_E500_DOUBLE && (mode == DFmode
+ || mode == DImode)))
{
+ if (mode == DImode)
+ return NULL_RTX;
/* We accept [reg + reg] and [reg + OFFSET]. */
if (GET_CODE (x) == PLUS)
&& REG_MODE_OK_FOR_BASE_P (XEXP (x, 0), mode)
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& !SPE_VECTOR_MODE (mode)
- && !(TARGET_E500_DOUBLE && mode == DFmode)
+ && !(TARGET_E500_DOUBLE && (mode == DFmode
+ || mode == DImode))
&& !ALTIVEC_VECTOR_MODE (mode))
{
HOST_WIDE_INT val = INTVAL (XEXP (x, 1));
if ((GET_CODE (x) == PRE_INC || GET_CODE (x) == PRE_DEC)
&& !ALTIVEC_VECTOR_MODE (mode)
&& !SPE_VECTOR_MODE (mode)
- && !(TARGET_E500_DOUBLE && mode == DFmode)
+ /* Restrict addressing for DI because of our SUBREG hackery. */
+ && !(TARGET_E500_DOUBLE && (mode == DFmode || mode == DImode))
&& TARGET_UPDATE
&& legitimate_indirect_address_p (XEXP (x, 0), reg_ok_strict))
return 1;
static rtx
spe_build_register_parallel (enum machine_mode mode, int gregno)
{
- rtx r1, r2, r3, r4;
- enum machine_mode inner = SImode;
+ rtx r1, r3;
if (mode == DFmode)
{
- r1 = gen_rtx_REG (inner, gregno);
- r1 = gen_rtx_EXPR_LIST (SImode, r1, const0_rtx);
- r2 = gen_rtx_REG (inner, gregno + 1);
- r2 = gen_rtx_EXPR_LIST (SImode, r2, GEN_INT (4));
- return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2));
+ r1 = gen_rtx_REG (DImode, gregno);
+ r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
+ return gen_rtx_PARALLEL (mode, gen_rtvec (1, r1));
}
else if (mode == DCmode)
{
- r1 = gen_rtx_REG (inner, gregno);
- r1 = gen_rtx_EXPR_LIST (SImode, r1, const0_rtx);
- r2 = gen_rtx_REG (inner, gregno + 1);
- r2 = gen_rtx_EXPR_LIST (SImode, r2, GEN_INT (4));
- r3 = gen_rtx_REG (inner, gregno + 2);
- r3 = gen_rtx_EXPR_LIST (SImode, r3, GEN_INT (8));
- r4 = gen_rtx_REG (inner, gregno + 3);
- r4 = gen_rtx_EXPR_LIST (SImode, r4, GEN_INT (12));
- return gen_rtx_PARALLEL (mode, gen_rtvec (4, r1, r2, r3, r4));
+ r1 = gen_rtx_REG (DImode, gregno);
+ r1 = gen_rtx_EXPR_LIST (VOIDmode, r1, const0_rtx);
+ r3 = gen_rtx_REG (DImode, gregno + 2);
+ r3 = gen_rtx_EXPR_LIST (VOIDmode, r3, GEN_INT (8));
+ return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r3));
}
-
- abort ();
+ abort();
return NULL_RTX;
}
#define CLASS_MAX_NREGS(CLASS, MODE) \
(((CLASS) == FLOAT_REGS) \
? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \
+ : (TARGET_E500_DOUBLE && (CLASS) == GENERAL_REGS && (MODE) == DFmode) \
+ ? 1 \
: ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
? reg_classes_intersect_p (FLOAT_REGS, CLASS) \
: (TARGET_E500_DOUBLE && (((TO) == DFmode) + ((FROM) == DFmode)) == 1) \
? reg_classes_intersect_p (GENERAL_REGS, CLASS) \
+ : (TARGET_E500_DOUBLE && (((TO) == DImode) + ((FROM) == DImode)) == 1) \
+ ? reg_classes_intersect_p (GENERAL_REGS, CLASS) \
: (TARGET_SPE && (SPE_VECTOR_MODE (FROM) + SPE_VECTOR_MODE (TO)) == 1) \
? reg_classes_intersect_p (GENERAL_REGS, CLASS) \
: 0)
{"current_file_function_operand", {SYMBOL_REF}}, \
{"input_operand", {SUBREG, MEM, REG, CONST_INT, \
CONST_DOUBLE, SYMBOL_REF}}, \
+ {"rs6k_nonimmediate_operand", {SUBREG, MEM, REG}}, \
{"load_multiple_operation", {PARALLEL}}, \
{"store_multiple_operation", {PARALLEL}}, \
{"lmw_operation", {PARALLEL}}, \
(set_attr "length" "4")])
;; Double-precision floating point instructions.
+
+;; FIXME: Add o=r option.
+(define_insn "*frob_df_di"
+ [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r")
+ (subreg:DF (match_operand:DI 1 "input_operand" "r,m") 0))]
+ "TARGET_E500_DOUBLE"
+ "@
+ evmergelo %0,%H1,%L1
+ evldd%X1 %0,%y1")
+
+(define_insn "*frob_di_df"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "=&r")
+ (subreg:DI (match_operand:DF 1 "input_operand" "r") 0))]
+ "TARGET_E500_DOUBLE" /*one of these can be an mr */
+ "evmergehi %H0,%1,%1\;evmergelo %L0,%1,%1"
+ [(set_attr "length" "8")])
+
+(define_insn "*frob_di_df_2"
+ [(set (subreg:DF (match_operand:DI 0 "register_operand" "=&r") 0)
+ (match_operand:DF 1 "register_operand" "r"))]
+ "TARGET_E500_DOUBLE"
+ "evmergehi %H0,%1,%1\;evmergelo %L0,%1,%1"
+ [(set_attr "length" "8")])
+
+(define_insn "*mov_sidf_e500_subreg0"
+ [(set (subreg:SI (match_operand:DF 0 "register_operand" "+r") 0)
+ (match_operand:SI 1 "register_operand" "r"))]
+ "TARGET_E500_DOUBLE"
+ "evmergelo %0,%1,%0")
+
+(define_insn "*mov_sidf_e500_subreg4"
+ [(set (subreg:SI (match_operand:DF 0 "register_operand" "+r") 4)
+ (match_operand:SI 1 "register_operand" "r"))]
+ "TARGET_E500_DOUBLE"
+ "mr %0,%1")
+
+;; FIXME: Allow r=CONST0.
(define_insn "*movdf_e500_double"
- [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m")
+ [(set (match_operand:DF 0 "rs6k_nonimmediate_operand" "=r,r,m")
(match_operand:DF 1 "input_operand" "r,m,r"))]
"TARGET_HARD_FLOAT && TARGET_E500_DOUBLE
&& (gpc_reg_operand (operands[0], DFmode)