diff options
author | Richard Sandiford <rsandifo@nildram.co.uk> | 2007-10-03 18:39:30 +0000 |
---|---|---|
committer | Richard Sandiford <rsandifo@gcc.gnu.org> | 2007-10-03 18:39:30 +0000 |
commit | 0064fbe9b6d395c794fc021d6dc97b40f9d7ac92 (patch) | |
tree | facac44939a51a8591e7804d091bfb66aeb0c6f6 /gcc/config | |
parent | f5783e34f97cd9012ae3ee4118a5e3bf642d8aed (diff) | |
download | gcc-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.h | 2 | ||||
-rw-r--r-- | gcc/config/mips/mips.c | 90 | ||||
-rw-r--r-- | gcc/config/mips/mips.md | 170 |
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" |