aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorRichard Sandiford <rsandifo@nildram.co.uk>2007-10-03 18:39:30 +0000
committerRichard Sandiford <rsandifo@gcc.gnu.org>2007-10-03 18:39:30 +0000
commit0064fbe9b6d395c794fc021d6dc97b40f9d7ac92 (patch)
treefacac44939a51a8591e7804d091bfb66aeb0c6f6 /gcc/config
parentf5783e34f97cd9012ae3ee4118a5e3bf642d8aed (diff)
downloadgcc-0064fbe9b6d395c794fc021d6dc97b40f9d7ac92.zip
gcc-0064fbe9b6d395c794fc021d6dc97b40f9d7ac92.tar.gz
gcc-0064fbe9b6d395c794fc021d6dc97b40f9d7ac92.tar.bz2
re PR target/33635 (Bootstrap broken on mips-sgi-irix6.5)
gcc/ PR target/33635 * config/mips/mips-protos.h (mips_split_64bit_move): Rename to... (mips_split_doubleword_move): ...this. * config/mips/mips.c (mips_subword): Extend to handle 64-bit words; use natural endianness for multi-format FPR values. (mips_split_64bit_move): Rename to... (mips_split_doubleword_move): ...this and extend to 64-bit words. Use move_doubleword_fpr* patterns for moves involving FPRs. (mips_save_reg): Update the call to mips_split_64bit_move. (mips_secondary_reload_class): Return NO_REGS for any reload of a nonzero constant into an FPR if the constant can be forced to memory. * config/mips/mips.md: Update the splitter calls to mips_split_64bit_move. (UNSPEC_LOAD_DF_LOW): Rename to... (UNSPEC_LOAD_LOW): ...this. (UNSPEC_LOAD_DF_HIGH): Rename to... (UNSPEC_LOAD_HIGH): ...this. (UNSPEC_STORE_DF_HIGH): Rename to... (UNSPEC_STORE_WORD): ...this. (SPLITF): New mode iterator. (HALFMODE): New mode attribute. (movtf): New expander. (*movtf_internal): New define_insn_and_split. (move_doubleword_fpr<mode>): New expander. (load_df_low, load_df_high, store_df_high, mthc1, mfhc1): Replace with... (load_low<mode>, load_high<mode>, store_word<mode>, mthc1<mode>) (mfhc1<mode>): ...these more general patterns. gcc/testsuite/ PR target/33635 * gcc.target/mips/mips.exp (setup_mips_tests): Set mips_isa_rev and mips_forced_be. (dg-mips-options): Handle -EL and -mel. Make -mfp64 imply -mhard-float and a suitable ISA. Improve handling of -mipsXrY options. * gcc.target/mips/fpr-moves-1.c: New test. * gcc.target/mips/fpr-moves-2.c: Likewise. * gcc.target/mips/fpr-moves-3.c: Likewise. * gcc.target/mips/fpr-moves-4.c: Likewise. * gcc.target/mips/fpr-moves-5.c: Likewise. * gcc.target/mips/fpr-moves-6.c: Likewise. * gcc.target/mips/mips32r2-mxhc1.c: Remove -march=mips32r2 From-SVN: r128991
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/mips/mips-protos.h2
-rw-r--r--gcc/config/mips/mips.c90
-rw-r--r--gcc/config/mips/mips.md170
3 files changed, 147 insertions, 115 deletions
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 6237749..371fd93 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -201,7 +201,7 @@ extern int m16_nsimm8_8 (rtx, enum machine_mode);
extern rtx mips_subword (rtx, int);
extern bool mips_split_64bit_move_p (rtx, rtx);
-extern void mips_split_64bit_move (rtx, rtx);
+extern void mips_split_doubleword_move (rtx, rtx);
extern const char *mips_output_move (rtx, rtx);
extern void mips_restore_gp (void);
#ifdef RTX_CODE
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 6ac976a..64377b5 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -3477,7 +3477,7 @@ mips_address_cost (rtx addr)
rtx
mips_subword (rtx op, int high_p)
{
- unsigned int byte;
+ unsigned int byte, offset;
enum machine_mode mode;
mode = GET_MODE (op);
@@ -3490,7 +3490,11 @@ mips_subword (rtx op, int high_p)
byte = 0;
if (FP_REG_RTX_P (op))
- return gen_rtx_REG (word_mode, high_p ? REGNO (op) + 1 : REGNO (op));
+ {
+ /* Paired FPRs are always ordered little-endian. */
+ offset = (UNITS_PER_WORD < UNITS_PER_HWFPVALUE ? high_p : byte != 0);
+ return gen_rtx_REG (word_mode, REGNO (op) + offset);
+ }
if (MEM_P (op))
return mips_rewrite_small_data (adjust_address (op, word_mode, byte));
@@ -3524,58 +3528,23 @@ mips_split_64bit_move_p (rtx dest, rtx src)
}
-/* Split a 64-bit move from SRC to DEST assuming that
- mips_split_64bit_move_p holds.
-
- Moves into and out of FPRs cause some difficulty here. Such moves
- will always be DFmode, since paired FPRs are not allowed to store
- DImode values. The most natural representation would be two separate
- 32-bit moves, such as:
-
- (set (reg:SI $f0) (mem:SI ...))
- (set (reg:SI $f1) (mem:SI ...))
-
- However, the second insn is invalid because odd-numbered FPRs are
- not allowed to store independent values. Use the patterns load_df_low,
- load_df_high and store_df_high instead. */
+/* Split a doubleword move from SRC to DEST. On 32-bit targets,
+ this function handles 64-bit moves for which mips_split_64bit_move_p
+ holds. For 64-bit targets, this function handles 128-bit moves. */
void
-mips_split_64bit_move (rtx dest, rtx src)
+mips_split_doubleword_move (rtx dest, rtx src)
{
- if (FP_REG_RTX_P (dest))
- {
- /* Loading an FPR from memory or from GPRs. */
- if (ISA_HAS_MXHC1)
- {
- if (GET_MODE (dest) != DFmode)
- dest = gen_rtx_REG_offset (dest, DFmode, REGNO (dest), 0);
- emit_insn (gen_load_df_low (dest, mips_subword (src, 0)));
- emit_insn (gen_mthc1 (dest, mips_subword (src, 1),
- copy_rtx (dest)));
- }
- else
- {
- emit_insn (gen_load_df_low (copy_rtx (dest),
- mips_subword (src, 0)));
- emit_insn (gen_load_df_high (dest, mips_subword (src, 1),
- copy_rtx (dest)));
- }
- }
- else if (FP_REG_RTX_P (src))
+ if (FP_REG_RTX_P (dest) || FP_REG_RTX_P (src))
{
- /* Storing an FPR into memory or GPRs. */
- if (ISA_HAS_MXHC1)
- {
- if (GET_MODE (src) != DFmode)
- src = gen_rtx_REG_offset (src, DFmode, REGNO (src), 0);
- mips_emit_move (mips_subword (dest, 0), mips_subword (src, 0));
- emit_insn (gen_mfhc1 (mips_subword (dest, 1), src));
- }
+ if (!TARGET_64BIT && GET_MODE (dest) == DImode)
+ emit_insn (gen_move_doubleword_fprdi (dest, src));
+ else if (!TARGET_64BIT && GET_MODE (dest) == DFmode)
+ emit_insn (gen_move_doubleword_fprdf (dest, src));
+ else if (TARGET_64BIT && GET_MODE (dest) == TFmode)
+ emit_insn (gen_move_doubleword_fprtf (dest, src));
else
- {
- mips_emit_move (mips_subword (dest, 0), mips_subword (src, 0));
- emit_insn (gen_store_df_high (mips_subword (dest, 1), src));
- }
+ gcc_unreachable ();
}
else
{
@@ -8042,7 +8011,7 @@ mips_save_reg (rtx reg, rtx mem)
rtx x1, x2;
if (mips_split_64bit_move_p (mem, reg))
- mips_split_64bit_move (mem, reg);
+ mips_split_doubleword_move (mem, reg);
else
mips_emit_move (mem, reg);
@@ -9472,18 +9441,15 @@ mips_secondary_reload_class (enum reg_class class,
/* In this case we can use mtc1, mfc1, dmtc1 or dmfc1. */
return NO_REGS;
- if (mips_mode_ok_for_mov_fmt_p (mode))
- {
- if (CONSTANT_P (x))
- /* We can force the constants to memory and use lwc1
- and ldc1. As above, we will use pairs of lwc1s if
- ldc1 is not supported. */
- return NO_REGS;
-
- if (FP_REG_P (regno))
- /* In this case we can use mov.fmt. */
- return NO_REGS;
- }
+ if (CONSTANT_P (x) && !targetm.cannot_force_const_mem (x))
+ /* We can force the constant to memory and use lwc1
+ and ldc1. As above, we will use pairs of lwc1s if
+ ldc1 is not supported. */
+ return NO_REGS;
+
+ if (FP_REG_P (regno) && mips_mode_ok_for_mov_fmt_p (mode))
+ /* In this case we can use mov.fmt. */
+ return NO_REGS;
/* Otherwise, we need to reload through an integer register. */
return GR_REGS;
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index 38800ed..f4b90eb 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -24,9 +24,9 @@
;; <http://www.gnu.org/licenses/>.
(define_constants
- [(UNSPEC_LOAD_DF_LOW 0)
- (UNSPEC_LOAD_DF_HIGH 1)
- (UNSPEC_STORE_DF_HIGH 2)
+ [(UNSPEC_LOAD_LOW 0)
+ (UNSPEC_LOAD_HIGH 1)
+ (UNSPEC_STORE_WORD 2)
(UNSPEC_GET_FNADDR 3)
(UNSPEC_BLOCKAGE 4)
(UNSPEC_CPRESTORE 5)
@@ -498,6 +498,11 @@
(define_mode_iterator SCALARF [(SF "TARGET_HARD_FLOAT")
(DF "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT")])
+;; A floating-point mode for which moves involving FPRs may need to be split.
+(define_mode_iterator SPLITF [(DF "!TARGET_64BIT")
+ (DI "!TARGET_64BIT")
+ (TF "TARGET_64BIT")])
+
;; In GPR templates, a string like "<d>subu" will expand to "subu" in the
;; 32-bit version and "dsubu" in the 64-bit version.
(define_mode_attr d [(SI "") (DI "d")
@@ -546,6 +551,10 @@
(V4UQQ "SI") (V2UHQ "SI") (V2UHA "SI")
(V2HQ "SI") (V2HA "SI")])
+;; This attribute gives the integer mode that has half the size of
+;; the controlling mode.
+(define_mode_attr HALFMODE [(DF "SI") (DI "SI") (TF "DI")])
+
;; This attribute works around the early SB-1 rev2 core "F2" erratum:
;;
;; In certain cases, div.s and div.ps may have a rounding error
@@ -3999,6 +4008,32 @@
(set_attr "mode" "DF")
(set_attr "length" "8,8,8,*,*")])
+;; 128-bit floating point moves
+
+(define_expand "movtf"
+ [(set (match_operand:TF 0 "")
+ (match_operand:TF 1 ""))]
+ ""
+{
+ if (mips_legitimize_move (TFmode, operands[0], operands[1]))
+ DONE;
+})
+
+;; This pattern handles both hard- and soft-float cases.
+(define_insn_and_split "*movtf_internal"
+ [(set (match_operand:TF 0 "nonimmediate_operand" "=d,R,f,dR")
+ (match_operand:TF 1 "move_operand" "dGR,dG,dGR,f"))]
+ ""
+ "#"
+ "&& reload_completed"
+ [(const_int 0)]
+{
+ mips_split_doubleword_move (operands[0], operands[1]);
+ DONE;
+}
+ [(set_attr "type" "multi")
+ (set_attr "length" "16")])
+
(define_split
[(set (match_operand:DI 0 "nonimmediate_operand")
(match_operand:DI 1 "move_operand"))]
@@ -4006,7 +4041,7 @@
&& mips_split_64bit_move_p (operands[0], operands[1])"
[(const_int 0)]
{
- mips_split_64bit_move (operands[0], operands[1]);
+ mips_split_doubleword_move (operands[0], operands[1]);
DONE;
})
@@ -4017,7 +4052,7 @@
&& mips_split_64bit_move_p (operands[0], operands[1])"
[(const_int 0)]
{
- mips_split_64bit_move (operands[0], operands[1]);
+ mips_split_doubleword_move (operands[0], operands[1]);
DONE;
})
@@ -4099,74 +4134,105 @@
[(set_attr "type" "mfhilo")
(set_attr "mode" "<MODE>")])
-;; Patterns for loading or storing part of a paired floating point
-;; register. We need them because odd-numbered floating-point registers
-;; are not fully independent: see mips_split_64bit_move.
+;; Emit a doubleword move in which exactly one of the operands is
+;; a floating-point register. We can't just emit two normal moves
+;; because of the constraints imposed by the FPU register model;
+;; see mips_cannot_change_mode_class for details. Instead, we keep
+;; the FPR whole and use special patterns to refer to each word of
+;; the other operand.
+
+(define_expand "move_doubleword_fpr<mode>"
+ [(set (match_operand:SPLITF 0)
+ (match_operand:SPLITF 1))]
+ ""
+{
+ if (FP_REG_RTX_P (operands[0]))
+ {
+ rtx low = mips_subword (operands[1], 0);
+ rtx high = mips_subword (operands[1], 1);
+ emit_insn (gen_load_low<mode> (operands[0], low));
+ if (ISA_HAS_MXHC1)
+ emit_insn (gen_mthc1<mode> (operands[0], high, operands[0]));
+ else
+ emit_insn (gen_load_high<mode> (operands[0], high, operands[0]));
+ }
+ else
+ {
+ rtx low = mips_subword (operands[0], 0);
+ rtx high = mips_subword (operands[0], 1);
+ emit_insn (gen_store_word<mode> (low, operands[1], const0_rtx));
+ if (ISA_HAS_MXHC1)
+ emit_insn (gen_mfhc1<mode> (high, operands[1]));
+ else
+ emit_insn (gen_store_word<mode> (high, operands[1], const1_rtx));
+ }
+ DONE;
+})
;; Load the low word of operand 0 with operand 1.
-(define_insn "load_df_low"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (unspec:DF [(match_operand:SI 1 "general_operand" "dJ,m")]
- UNSPEC_LOAD_DF_LOW))]
- "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+(define_insn "load_low<mode>"
+ [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
+ (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "dJ,m")]
+ UNSPEC_LOAD_LOW))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
{
operands[0] = mips_subword (operands[0], 0);
return mips_output_move (operands[0], operands[1]);
}
- [(set_attr "type" "mtc,fpload")
- (set_attr "mode" "SF")])
+ [(set_attr "type" "mtc,fpload")
+ (set_attr "mode" "<HALFMODE>")])
;; Load the high word of operand 0 from operand 1, preserving the value
;; in the low word.
-(define_insn "load_df_high"
- [(set (match_operand:DF 0 "register_operand" "=f,f")
- (unspec:DF [(match_operand:SI 1 "general_operand" "dJ,m")
- (match_operand:DF 2 "register_operand" "0,0")]
- UNSPEC_LOAD_DF_HIGH))]
- "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+(define_insn "load_high<mode>"
+ [(set (match_operand:SPLITF 0 "register_operand" "=f,f")
+ (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "dJ,m")
+ (match_operand:SPLITF 2 "register_operand" "0,0")]
+ UNSPEC_LOAD_HIGH))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
{
operands[0] = mips_subword (operands[0], 1);
return mips_output_move (operands[0], operands[1]);
}
- [(set_attr "type" "mtc,fpload")
- (set_attr "mode" "SF")])
-
-;; Store the high word of operand 1 in operand 0. The corresponding
-;; low-word move is done in the normal way.
-(define_insn "store_df_high"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=d,m")
- (unspec:SI [(match_operand:DF 1 "register_operand" "f,f")]
- UNSPEC_STORE_DF_HIGH))]
- "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && !TARGET_64BIT"
+ [(set_attr "type" "mtc,fpload")
+ (set_attr "mode" "<HALFMODE>")])
+
+;; Store one word of operand 1 in operand 0. Operand 2 is 1 to store the
+;; high word and 0 to store the low word.
+(define_insn "store_word<mode>"
+ [(set (match_operand:<HALFMODE> 0 "nonimmediate_operand" "=d,m")
+ (unspec:<HALFMODE> [(match_operand:SPLITF 1 "register_operand" "f,f")
+ (match_operand 2 "const_int_operand")]
+ UNSPEC_STORE_WORD))]
+ "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT"
{
- operands[1] = mips_subword (operands[1], 1);
+ operands[1] = mips_subword (operands[1], INTVAL (operands[2]));
return mips_output_move (operands[0], operands[1]);
}
- [(set_attr "type" "mfc,fpstore")
- (set_attr "mode" "SF")])
+ [(set_attr "type" "mfc,fpstore")
+ (set_attr "mode" "<HALFMODE>")])
;; Move operand 1 to the high word of operand 0 using mthc1, preserving the
;; value in the low word.
-(define_insn "mthc1"
- [(set (match_operand:DF 0 "register_operand" "=f")
- (unspec:DF [(match_operand:SI 1 "general_operand" "dJ")
- (match_operand:DF 2 "register_operand" "0")]
- UNSPEC_MTHC1))]
- "TARGET_HARD_FLOAT && !TARGET_64BIT && ISA_HAS_MXHC1"
+(define_insn "mthc1<mode>"
+ [(set (match_operand:SPLITF 0 "register_operand" "=f")
+ (unspec:SPLITF [(match_operand:<HALFMODE> 1 "general_operand" "dJ")
+ (match_operand:SPLITF 2 "register_operand" "0")]
+ UNSPEC_MTHC1))]
+ "TARGET_HARD_FLOAT && ISA_HAS_MXHC1"
"mthc1\t%z1,%0"
- [(set_attr "type" "mtc")
- (set_attr "mode" "SF")])
-
-;; Move high word of operand 1 to operand 0 using mfhc1. The corresponding
-;; low-word move is done in the normal way.
-(define_insn "mfhc1"
- [(set (match_operand:SI 0 "register_operand" "=d")
- (unspec:SI [(match_operand:DF 1 "register_operand" "f")]
- UNSPEC_MFHC1))]
- "TARGET_HARD_FLOAT && !TARGET_64BIT && ISA_HAS_MXHC1"
+ [(set_attr "type" "mtc")
+ (set_attr "mode" "<HALFMODE>")])
+
+;; Move high word of operand 1 to operand 0 using mfhc1.
+(define_insn "mfhc1<mode>"
+ [(set (match_operand:<HALFMODE> 0 "register_operand" "=d")
+ (unspec:<HALFMODE> [(match_operand:SPLITF 1 "register_operand" "f")]
+ UNSPEC_MFHC1))]
+ "TARGET_HARD_FLOAT && ISA_HAS_MXHC1"
"mfhc1\t%0,%1"
- [(set_attr "type" "mfc")
- (set_attr "mode" "SF")])
+ [(set_attr "type" "mfc")
+ (set_attr "mode" "<HALFMODE>")])
;; Move a constant that satisfies CONST_GP_P into operand 0.
(define_expand "load_const_gp"