aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorAldy Hernandez <aldyh@redhat.com>2005-01-14 21:22:14 +0000
committerAldy Hernandez <aldyh@gcc.gnu.org>2005-01-14 21:22:14 +0000
commit54b695e729623a329250bf68894cbd7ae25020ac (patch)
tree44ec03ace9a33d611bf37e4c25c9c7ffad7a7728 /gcc
parentfd3395a50bf61702cce7c573f02caebbfd536fc2 (diff)
downloadgcc-54b695e729623a329250bf68894cbd7ae25020ac.zip
gcc-54b695e729623a329250bf68894cbd7ae25020ac.tar.gz
gcc-54b695e729623a329250bf68894cbd7ae25020ac.tar.bz2
rs6000.h (CLASS_MAX_NREGS): DF goes in 1 register on e500v2.
* 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. From-SVN: r93665
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog29
-rw-r--r--gcc/config/rs6000/rs6000.c87
-rw-r--r--gcc/config/rs6000/rs6000.h5
-rw-r--r--gcc/config/rs6000/rs6000.md2
-rw-r--r--gcc/config/rs6000/spe.md39
5 files changed, 137 insertions, 25 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2d0d11b..53e9844 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,34 @@
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
trunc_int_for_mode on scalar integers.
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index a6a8871..a8586a6 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -710,6 +710,7 @@ static rtx spe_expand_builtin (tree, rtx, bool *);
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 *);
@@ -3035,6 +3036,39 @@ input_operand (rtx op, enum machine_mode mode)
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. */
@@ -3248,6 +3282,14 @@ rs6000_legitimate_offset_address_p (enum machine_mode mode, rtx x, int strict)
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)
@@ -3326,7 +3368,8 @@ legitimate_lo_sum_address_p (enum machine_mode mode, rtx x, int strict)
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);
@@ -3403,7 +3446,8 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
&& 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)
{
@@ -3423,8 +3467,11 @@ rs6000_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
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)
@@ -3834,7 +3881,8 @@ rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
&& 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));
@@ -3942,7 +3990,8 @@ rs6000_legitimate_address (enum machine_mode mode, rtx x, int reg_ok_strict)
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;
@@ -5084,31 +5133,23 @@ function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
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;
}
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index 63c1b83..215fdcd 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -1429,6 +1429,8 @@ enum reg_class
#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))
@@ -1442,6 +1444,8 @@ enum reg_class
? 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)
@@ -2588,6 +2592,7 @@ extern char rs6000_reg_names[][8]; /* register names (0 vs. %r0). */
{"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}}, \
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index e3ba021..890088e 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -7709,7 +7709,7 @@
(set_attr "length" "4")])
(define_insn "*movsi_internal1"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h")
+ [(set (match_operand:SI 0 "rs6k_nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h")
(match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,r,0"))]
"gpc_reg_operand (operands[0], SImode)
|| gpc_reg_operand (operands[1], SImode)"
diff --git a/gcc/config/rs6000/spe.md b/gcc/config/rs6000/spe.md
index 6e40371..c43adcb 100644
--- a/gcc/config/rs6000/spe.md
+++ b/gcc/config/rs6000/spe.md
@@ -2192,8 +2192,45 @@
(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)