diff --git a/gcc/ChangeLog b/gcc/ChangeLog index fbf165210648..00420bee77c0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,30 @@ +2006-11-23 David Ung <davidu@mips.com> + + * config/mips/mips.h (ISA_HAS_FP4): Add MIPS32R2 + 64bit fpu + combination. + (ISA_HAS_MXHC1): True if ISA supports mfhc1 and mthc1 opcodes. + (ASM_SPEC): Pass along -mfp32 and -mfp64. + * config/mips/mips.c (mips_split_64bit_move): Use gen_mthc1 to set + high part of FP register when in 64-bit FP register mode. Similarly + use gen_mfhc1 to load high part of FP register. + (override_options): Allow -mgp32 and -mfp64 combination if + ISA_HAS_MXHC1 (currently for O32 only). + (mips_cannot_change_mode_class): If floating-point registers are + bigger than word size. disallow conversion of float register from a + large integer mode to a float mode smaller than the float register + size. + (mips_class_max_nregs): Handle float registers case seperately. + * config/mips/mips.md (define_constants): Add UNSPEC_MFHC1, + UNSPEC_MTHC1. + (movdi_32bit): Use !TARGET_FLOAT64 in condition pattern. + (movdf_hardfloat_32bit): Similarly. + (movdi_gp32_fp64): New DImode pattern for MIPS32R2 which optionally + support a full 64-bit fpu. + (mthc1): New pattern to generate MTHC1 instruction. + (mfhc1): New pattern to generate MFHC1 instruction. + * doc/invoke.texi (MIPS Options): Document the -mgp32 -mfp64 + option for the MIPS32R2 and mention its use under O32 ABI. + 2006-11-23 Bernd Schmidt <bernd.schmidt@analog.com> * var-tracking.c (emit_note_insn_var_location): Take care not to diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 52e2aabe1fe5..63c19ab99f1e 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -2846,15 +2846,35 @@ mips_split_64bit_move (rtx dest, rtx src) if (FP_REG_RTX_P (dest)) { /* Loading an FPR from memory or from GPRs. */ - 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))); + if (ISA_HAS_MXHC1) + { + dest = gen_lowpart (DFmode, dest); + 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)) { /* Storing an FPR into memory or GPRs. */ - emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0)); - emit_insn (gen_store_df_high (mips_subword (dest, 1), src)); + if (ISA_HAS_MXHC1) + { + src = gen_lowpart (DFmode, src); + emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0)); + emit_insn (gen_mfhc1 (mips_subword (dest, 1), src)); + } + else + { + emit_move_insn (mips_subword (dest, 0), mips_subword (src, 0)); + emit_insn (gen_store_df_high (mips_subword (dest, 1), src)); + } } else { @@ -4804,8 +4824,10 @@ override_options (void) only one right answer here. */ if (TARGET_64BIT && TARGET_DOUBLE_FLOAT && !TARGET_FLOAT64) error ("unsupported combination: %s", "-mgp64 -mfp32 -mdouble-float"); - else if (!TARGET_64BIT && TARGET_FLOAT64) - error ("unsupported combination: %s", "-mgp32 -mfp64"); + else if (!TARGET_64BIT && TARGET_FLOAT64 + && !(ISA_HAS_MXHC1 && mips_abi == ABI_32)) + error ("-mgp32 and -mfp64 can only be combined if the target" + " supports the mfhc1 and mthc1 instructions"); else if (TARGET_SINGLE_FLOAT && TARGET_FLOAT64) error ("unsupported combination: %s", "-mfp64 -msingle-float"); } @@ -7660,15 +7682,27 @@ mips_cannot_change_mode_class (enum machine_mode from, return true; } } + + /* gcc assumes that each word of a multiword register can be accessed + individually using SUBREGs. This is not true for floating-point + registers if they are bigger than a word. */ + if (UNITS_PER_FPREG > UNITS_PER_WORD + && GET_MODE_SIZE (from) > UNITS_PER_WORD + && GET_MODE_SIZE (to) < UNITS_PER_FPREG + && reg_classes_intersect_p (FP_REGS, class)) + return true; + /* Loading a 32-bit value into a 64-bit floating-point register will not sign-extend the value, despite what LOAD_EXTEND_OP says. We can't allow 64-bit float registers to change from SImode to to a wider mode. */ - if (TARGET_FLOAT64 + if (TARGET_64BIT + && TARGET_FLOAT64 && from == SImode && GET_MODE_SIZE (to) >= UNITS_PER_WORD && reg_classes_intersect_p (FP_REGS, class)) return true; + return false; } @@ -7830,14 +7864,17 @@ mips_secondary_reload_class (enum reg_class class, /* Implement CLASS_MAX_NREGS. - Usually all registers are word-sized. The only supported exception - is -mgp64 -msingle-float, which has 64-bit words but 32-bit float - registers. A word-based calculation is correct even in that case, - since -msingle-float disallows multi-FPR values. + - UNITS_PER_FPREG controls the number of registers needed by FP_REGS. - The FP status registers are an exception to this rule. They are always - 4 bytes wide as they only hold condition code modes, and CCmode is always - considered to be 4 bytes wide. */ + - ST_REGS are always hold CCmode values, and CCmode values are + considered to be 4 bytes wide. + + All other register classes are covered by UNITS_PER_WORD. Note that + this is true even for unions of integer and float registers when the + latter are smaller than the former. The only supported combination + in which case this occurs is -mgp64 -msingle-float, which has 64-bit + words but 32-bit float registers. A word-based calculation is correct + in that case since -msingle-float disallows multi-FPR values. */ int mips_class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED, @@ -7845,6 +7882,8 @@ mips_class_max_nregs (enum reg_class class ATTRIBUTE_UNUSED, { if (class == ST_REGS) return (GET_MODE_SIZE (mode) + 3) / 4; + else if (class == FP_REGS) + return (GET_MODE_SIZE (mode) + UNITS_PER_FPREG - 1) / UNITS_PER_FPREG; else return (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD; } diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index ddcc81b32774..00f7ca8f55ff 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -607,6 +607,7 @@ extern const struct mips_rtx_cost_data *mips_cost; FP madd and msub instructions, and the FP recip and recip sqrt instructions. */ #define ISA_HAS_FP4 ((ISA_MIPS4 \ + || (ISA_MIPS32R2 && TARGET_FLOAT64) \ || ISA_MIPS64) \ && !TARGET_MIPS16) @@ -703,6 +704,9 @@ extern const struct mips_rtx_cost_data *mips_cost; #define ISA_HAS_EXT_INS (ISA_MIPS32R2 \ && !TARGET_MIPS16) +/* ISA has instructions for accessing top part of 64 bit fp regs */ +#define ISA_HAS_MXHC1 (TARGET_FLOAT64 && ISA_MIPS32R2) + /* True if the result of a load is not available to the next instruction. A nop will then be needed between instructions like "lw $4,..." and "addiu $4,$4,1". */ @@ -821,6 +825,7 @@ extern const struct mips_rtx_cost_data *mips_cost; %(subtarget_asm_debugging_spec) \ %{mabi=*} %{!mabi*: %(asm_abi_default_spec)} \ %{mgp32} %{mgp64} %{march=*} %{mxgot:-xgot} \ +%{mfp32} %{mfp64} \ %{mshared} %{mno-shared} \ %{msym32} %{mno-sym32} \ %{mtune=*} %{v} \ diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index dfa82f159a75..b175fb343e8f 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -47,6 +47,8 @@ (UNSPEC_MFHILO 26) (UNSPEC_TLS_LDM 27) (UNSPEC_TLS_GET_TP 28) + (UNSPEC_MFHC1 31) + (UNSPEC_MTHC1 32) (UNSPEC_ADDRESS_FIRST 100) @@ -3255,7 +3257,7 @@ (define_insn "*movdi_32bit" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*B*C*D,*B*C*D,*d,*m") (match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))] - "!TARGET_64BIT && !TARGET_MIPS16 + "!TARGET_64BIT && !TARGET_FLOAT64 && !TARGET_MIPS16 && (register_operand (operands[0], DImode) || reg_or_0_operand (operands[1], DImode))" { return mips_output_move (operands[0], operands[1]); } @@ -3263,6 +3265,17 @@ (set_attr "mode" "DI") (set_attr "length" "8,16,*,*,8,8,8,*,8,*")]) +(define_insn "*movdi_gp32_fp64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*f,*f,*f,*d,*m") + (match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*f,*J*d,*m,*f,*f"))] + "!TARGET_64BIT && TARGET_FLOAT64 && !TARGET_MIPS16 + && (register_operand (operands[0], DImode) + || reg_or_0_operand (operands[1], DImode))" + { return mips_output_move (operands[0], operands[1]); } + [(set_attr "type" "arith,arith,load,store,mthilo,mfhilo,fmove,xfer,fpload,xfer,fpstore") + (set_attr "mode" "DI") + (set_attr "length" "8,16,*,*,8,8,4,8,*,8,*")]) + (define_insn "*movdi_32bit_mips16" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") (match_operand:DI 1 "move_operand" "d,d,y,K,N,m,d,*x"))] @@ -3804,6 +3817,7 @@ (set_attr "mode" "DF") (set_attr "length" "4,4,*,*,*,4,4,4,*,*")]) +;; This pattern applies to both !TARGET_FLOAT64 and TARGET_FLOAT64. (define_insn "*movdf_hardfloat_32bit" [(set (match_operand:DF 0 "nonimmediate_operand" "=f,f,f,m,m,*f,*d,*d,*d,*m") (match_operand:DF 1 "move_operand" "f,G,m,f,G,*d,*f,*d*G,*m,*d"))] @@ -3985,6 +3999,29 @@ [(set_attr "type" "xfer,fpstore") (set_attr "mode" "SF")]) +;; 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" + "mthc1\t%z1,%0" + [(set_attr "type" "xfer") + (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" + "mfhc1\t%0,%1" + [(set_attr "type" "xfer") + (set_attr "mode" "SF")]) + ;; Insn to initialize $gp for n32/n64 abicalls. Operand 0 is the offset ;; of _gp from the start of this function. Operand 1 is the incoming ;; function address. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 045c5fd25571..2cef7e6f1dd6 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -10657,6 +10657,19 @@ can use @option{-mgp32} to get 32-bit code instead. For information about the O64 ABI, see @w{@uref{http://gcc.gnu.org/projects/mipso64-abi.html}}. +GCC supports a variant of the o32 ABI in which floating-point registers +are 64 rather than 32 bits wide. You can select this combination with +@option{-mabi=32} @option{-mfp64}. This ABI relies on the @samp{mthc1} +and @samp{mfhc1} instructions and is therefore only supported for +MIPS32R2 processors. + +The register assignments for arguments and return values remain the +same, but each scalar value is passed in a single 64-bit register +rather than a pair of 32-bit registers. For example, scalar +floating-point values are returned in @samp{$f0} only, not a +@samp{$f0}/@samp{$f1} pair. The set of call-saved registers also +remains the same, but all 64 bits are saved. + @item -mabicalls @itemx -mno-abicalls @opindex mabicalls diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index f8dc647d4e0c..cec51b1d7961 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2006-11-23 David Ung <davidu@mips.com> + + * gcc.target/mips/mips.exp (dg-mips-options): Handle parsing of + -mfp64, allowable when ISA >= 33 and float is enabled. + * gcc.target/mips/mips32r2-mxhc1.c: New test for checking the use + of mthc1 and mfhc1 patterns. + 2006-11-23 Zdenek Dvorak <dvorakz@suse.cz> PR tree-optimization/29921 diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp index d88a867db1bf..af5b0fbdd5da 100644 --- a/gcc/testsuite/gcc.target/mips/mips.exp +++ b/gcc/testsuite/gcc.target/mips/mips.exp @@ -158,6 +158,10 @@ proc dg-mips-options {args} { if {$mips_mips16} { set matches 0 } + } elseif {$flag == "-mfp64"} { + if {$mips_isa < 33 || $mips_float != "hard"} { + set matches 0 + } } elseif {[regexp -- {^-march=(.*)} $flag dummy arch]} { if {$mips_mips16 || ($arch != $mips_arch && $mips_forced_isa)} { set matches 0 diff --git a/gcc/testsuite/gcc.target/mips/mips32r2-mxhc1.c b/gcc/testsuite/gcc.target/mips/mips32r2-mxhc1.c new file mode 100644 index 000000000000..7a3b12d55af6 --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/mips32r2-mxhc1.c @@ -0,0 +1,14 @@ +/* { dg-do compile } */ +/* { dg-mips-options "-O -march=mips32r2 -mabi=32 -mfp64" } */ +/* { dg-final { scan-assembler "mthc1" } } */ +/* { dg-final { scan-assembler "mfhc1" } } */ + +double func1 (long long a) +{ + return a; +} + +long long func2 (double b) +{ + return b; +}