From 3d30741b2b9156e49531879fdb2154fde2019129 Mon Sep 17 00:00:00 2001 From: Richard Sandiford Date: Sun, 30 Sep 2007 22:50:02 +0000 Subject: [PATCH] mips.c (mips_split_64bit_move): Use gen_rtx_REG_offset rather than gen_lowpart to change a register from DImode... gcc/ * config/mips/mips.c (mips_split_64bit_move): Use gen_rtx_REG_offset rather than gen_lowpart to change a register from DImode to DFmode. (mips_cannot_change_mode_class): Only allow FPRs to change mode if both FROM and TO are integer modes that are no bigger than 4 bytes. (mips_mode_ok_for_mov_fmt_p): New function. (mips_preferred_reload_class): Use it instead of FLOAT_MODE_P. (mips_secondary_reload_class): Tweak formatting and comments. Use reg_class_subset_p instead of direct comparisons with classes. Only allow direct FPR<->FPR moves for modes that satisfy mips_mode_ok_for_mov_fmt_p. Only allow loads and stores for 4- and 8-byte types. Handle reloads in which X is an FPR. * config/mips/mips.md (*movdi_gp32_fp64): Remove f<-f alternative. (*movdi_64bit): Likewise. (*movsi_internal): Likewise. (*movhi_internal): Likewise. (*movqi_internal): Likewise. From-SVN: r128894 --- gcc/ChangeLog | 19 ++++ gcc/config/mips/mips.c | 217 +++++++++++++++++++--------------------- gcc/config/mips/mips.md | 42 ++++---- 3 files changed, 141 insertions(+), 137 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index eef9e94799b..5c1fdc0566c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,22 @@ +2007-09-30 Richard Sandiford + + * config/mips/mips.c (mips_split_64bit_move): Use gen_rtx_REG_offset + rather than gen_lowpart to change a register from DImode to DFmode. + (mips_cannot_change_mode_class): Only allow FPRs to change mode if + both FROM and TO are integer modes that are no bigger than 4 bytes. + (mips_mode_ok_for_mov_fmt_p): New function. + (mips_preferred_reload_class): Use it instead of FLOAT_MODE_P. + (mips_secondary_reload_class): Tweak formatting and comments. + Use reg_class_subset_p instead of direct comparisons with + classes. Only allow direct FPR<->FPR moves for modes that + satisfy mips_mode_ok_for_mov_fmt_p. Only allow loads and stores + for 4- and 8-byte types. Handle reloads in which X is an FPR. + * config/mips/mips.md (*movdi_gp32_fp64): Remove f<-f alternative. + (*movdi_64bit): Likewise. + (*movsi_internal): Likewise. + (*movhi_internal): Likewise. + (*movqi_internal): Likewise. + 2007-09-30 Diego Novillo PR 33593 diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index dbb7149b86e..6ac976abe6e 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -3547,7 +3547,8 @@ mips_split_64bit_move (rtx dest, rtx src) /* Loading an FPR from memory or from GPRs. */ if (ISA_HAS_MXHC1) { - dest = gen_lowpart (DFmode, dest); + 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))); @@ -3565,7 +3566,8 @@ mips_split_64bit_move (rtx dest, rtx src) /* Storing an FPR into memory or GPRs. */ if (ISA_HAS_MXHC1) { - src = gen_lowpart (DFmode, src); + 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)); } @@ -9314,44 +9316,38 @@ mips_callee_copies (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED, to mode TO. */ bool -mips_cannot_change_mode_class (enum machine_mode from, - enum machine_mode to, enum reg_class class) +mips_cannot_change_mode_class (enum machine_mode from ATTRIBUTE_UNUSED, + enum machine_mode to ATTRIBUTE_UNUSED, + enum reg_class class) { - if (MIN (GET_MODE_SIZE (from), GET_MODE_SIZE (to)) <= UNITS_PER_WORD - && MAX (GET_MODE_SIZE (from), GET_MODE_SIZE (to)) > UNITS_PER_WORD) - { - if (TARGET_BIG_ENDIAN) - { - /* When a multi-word value is stored in paired floating-point - registers, the first register always holds the low word. - We therefore can't allow FPRs to change between single-word - and multi-word modes. */ - if (MAX_FPRS_PER_FMT > 1 && reg_classes_intersect_p (FP_REGS, class)) - return true; - } - } + /* There are several problems with changing the modes of values + in floating-point registers: - /* 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; + - When a multi-word value is stored in paired floating-point + registers, the first register always holds the low word. + We therefore can't allow FPRs to change between single-word + and multi-word modes on big-endian targets. - /* 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_64BIT - && TARGET_FLOAT64 - && from == SImode - && GET_MODE_SIZE (to) >= UNITS_PER_WORD - && reg_classes_intersect_p (FP_REGS, class)) - 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. - return false; + - 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 FPRs to change from SImode to to a wider mode on + 64-bit targets. + + - If the FPU has already interpreted a value in one format, we must + not ask it to treat the value as having a different format. + + We therefore only allow changes between 4-byte and smaller integer + values, all of which have the "W" format as far as the FPU is + concerned. */ + return (reg_classes_intersect_p (FP_REGS, class) + && (GET_MODE_CLASS (from) != MODE_INT + || GET_MODE_CLASS (to) != MODE_INT + || GET_MODE_SIZE (from) > 4 + || GET_MODE_SIZE (to) > 4)); } /* Return true if X should not be moved directly into register $25. @@ -9367,6 +9363,27 @@ mips_dangerous_for_la25_p (rtx x) && mips_global_symbol_p (x)); } +/* Return true if moves in mode MODE can use the FPU's mov.fmt instruction. */ + +static bool +mips_mode_ok_for_mov_fmt_p (enum machine_mode mode) +{ + switch (mode) + { + case SFmode: + return TARGET_HARD_FLOAT; + + case DFmode: + return TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT; + + case V2SFmode: + return TARGET_HARD_FLOAT && TARGET_PAIRED_SINGLE_FLOAT; + + default: + return false; + } +} + /* Implement PREFERRED_RELOAD_CLASS. */ enum reg_class @@ -9375,9 +9392,8 @@ mips_preferred_reload_class (rtx x, enum reg_class class) if (mips_dangerous_for_la25_p (x) && reg_class_subset_p (LEA_REGS, class)) return LEA_REGS; - if (TARGET_HARD_FLOAT - && FLOAT_MODE_P (GET_MODE (x)) - && reg_class_subset_p (FP_REGS, class)) + if (reg_class_subset_p (FP_REGS, class) + && mips_mode_ok_for_mov_fmt_p (GET_MODE (x))) return FP_REGS; if (reg_class_subset_p (GR_REGS, class)) @@ -9399,110 +9415,81 @@ enum reg_class mips_secondary_reload_class (enum reg_class class, enum machine_mode mode, rtx x, int in_p) { - enum reg_class gr_regs = TARGET_MIPS16 ? M16_REGS : GR_REGS; - int regno = -1; - int gp_reg_p; - - if (REG_P (x)|| GET_CODE (x) == SUBREG) - regno = true_regnum (x); - - gp_reg_p = TARGET_MIPS16 ? M16_REG_P (regno) : GP_REG_P (regno); + int regno; + /* If X is a constant that cannot be loaded into $25, it must be loaded + into some other GPR. No other register class allows a direct move. */ if (mips_dangerous_for_la25_p (x)) + return reg_class_subset_p (class, LEA_REGS) ? NO_REGS : LEA_REGS; + + regno = true_regnum (x); + if (TARGET_MIPS16) { - gr_regs = LEA_REGS; - if (TEST_HARD_REG_BIT (reg_class_contents[(int) class], 25)) - return gr_regs; + /* In MIPS16 mode, every move must involve a member of M16_REGS. */ + if (!reg_class_subset_p (class, M16_REGS) && !M16_REG_P (regno)) + return M16_REGS; + + /* We can't really copy to HI or LO at all in MIPS16 mode. */ + if (in_p ? reg_classes_intersect_p (class, ACC_REGS) : ACC_REG_P (regno)) + return M16_REGS; + + return NO_REGS; } - /* Copying from HI or LO to anywhere other than a general register - requires a general register. - This rule applies to both the original HI/LO pair and the new - DSP accumulators. */ + /* Copying from accumulator registers to anywhere other than a general + register requires a temporary general register. */ if (reg_class_subset_p (class, ACC_REGS)) - { - if (TARGET_MIPS16 && in_p) - { - /* We can't really copy to HI or LO at all in mips16 mode. */ - return M16_REGS; - } - return gp_reg_p ? NO_REGS : gr_regs; - } + return GP_REG_P (regno) ? NO_REGS : GR_REGS; if (ACC_REG_P (regno)) - { - if (TARGET_MIPS16 && ! in_p) - { - /* We can't really copy to HI or LO at all in mips16 mode. */ - return M16_REGS; - } - return class == gr_regs ? NO_REGS : gr_regs; - } + return reg_class_subset_p (class, GR_REGS) ? NO_REGS : GR_REGS; /* We can only copy a value to a condition code register from a floating point register, and even then we require a scratch floating point register. We can only copy a value out of a condition code register into a general register. */ - if (class == ST_REGS) + if (reg_class_subset_p (class, ST_REGS)) { if (in_p) return FP_REGS; - return gp_reg_p ? NO_REGS : gr_regs; + return GP_REG_P (regno) ? NO_REGS : GR_REGS; } if (ST_REG_P (regno)) { - if (! in_p) + if (!in_p) return FP_REGS; - return class == gr_regs ? NO_REGS : gr_regs; + return reg_class_subset_p (class, GR_REGS) ? NO_REGS : GR_REGS; } - if (class == FP_REGS) + if (reg_class_subset_p (class, FP_REGS)) { - if (MEM_P (x)) - { - /* In this case we can use lwc1, swc1, ldc1 or sdc1. */ - return NO_REGS; - } - else if (CONSTANT_P (x) && GET_MODE_CLASS (mode) == MODE_FLOAT) - { - /* We can use the l.s and l.d macros to load floating-point - constants. ??? For l.s, we could probably get better - code by returning GR_REGS here. */ - return NO_REGS; - } - else if (gp_reg_p || x == CONST0_RTX (mode)) - { - /* In this case we can use mtc1, mfc1, dmtc1 or dmfc1. */ - return NO_REGS; - } - else if (FP_REG_P (regno)) - { - /* In this case we can use mov.s or mov.d. */ - return NO_REGS; - } - else - { - /* Otherwise, we need to reload through an integer register. */ - return gr_regs; - } - } + if (MEM_P (x) + && (GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8)) + /* In this case we can use lwc1, swc1, ldc1 or sdc1. We'll use + pairs of lwc1s and swc1s if ldc1 and sdc1 are not supported. */ + return NO_REGS; - /* In mips16 mode, going between memory and anything but M16_REGS - requires an M16_REG. */ - if (TARGET_MIPS16) - { - if (class != M16_REGS && class != M16_NA_REGS) + if (GP_REG_P (regno) || x == CONST0_RTX (mode)) + /* In this case we can use mtc1, mfc1, dmtc1 or dmfc1. */ + return NO_REGS; + + if (mips_mode_ok_for_mov_fmt_p (mode)) { - if (gp_reg_p) + 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; - return M16_REGS; - } - if (! gp_reg_p) - { - if (class == M16_REGS || class == M16_NA_REGS) + + if (FP_REG_P (regno)) + /* In this case we can use mov.fmt. */ return NO_REGS; - return M16_REGS; } + + /* Otherwise, we need to reload through an integer register. */ + return GR_REGS; } + if (FP_REG_P (regno)) + return reg_class_subset_p (class, GR_REGS) ? NO_REGS : GR_REGS; return NO_REGS; } diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md index d687223c382..890cc706590 100644 --- a/gcc/config/mips/mips.md +++ b/gcc/config/mips/mips.md @@ -3399,15 +3399,15 @@ (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"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*f,*f,*d,*m") + (match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*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" "multi,multi,load,store,mthilo,mfhilo,fmove,mtc,fpload,mfc,fpstore") + [(set_attr "type" "multi,multi,load,store,mthilo,mfhilo,mtc,fpload,mfc,fpstore") (set_attr "mode" "DI") - (set_attr "length" "8,16,*,*,8,8,4,8,*,8,*")]) + (set_attr "length" "8,16,*,*,8,8,8,*,8,*")]) (define_insn "*movdi_32bit_mips16" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") @@ -3421,15 +3421,15 @@ (set_attr "length" "8,8,8,8,12,*,*,8")]) (define_insn "*movdi_64bit" - [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*f,*d,*m,*x,*B*C*D,*B*C*D,*d,*m") - (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*f,*d*J,*m,*f,*f,*J*d,*d,*m,*B*C*D,*B*C*D"))] + [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*x,*B*C*D,*B*C*D,*d,*m") + (match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*d,*m,*B*C*D,*B*C*D"))] "TARGET_64BIT && !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" "move,const,const,load,store,fmove,mtc,fpload,mfc,fpstore,mthilo,mtc,load,mfc,store") + [(set_attr "type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mthilo,mtc,load,mfc,store") (set_attr "mode" "DI") - (set_attr "length" "4,*,*,*,*,4,4,*,4,*,4,8,*,8,*")]) + (set_attr "length" "4,*,*,*,*,4,*,4,*,4,8,*,8,*")]) (define_insn "*movdi_64bit_mips16" [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m") @@ -3518,15 +3518,15 @@ ;; in FP registers (off by default, use -mdebugh to enable). (define_insn "*movsi_internal" - [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m") - (match_operand:SI 1 "move_operand" "d,U,T,m,dJ,*f,*d*J,*m,*f,*f,*z,*d,*J*d,*A,*d,*m,*B*C*D,*B*C*D"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m") + (match_operand:SI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*A,*d,*m,*B*C*D,*B*C*D"))] "!TARGET_MIPS16 && (register_operand (operands[0], SImode) || reg_or_0_operand (operands[1], SImode))" { return mips_output_move (operands[0], operands[1]); } - [(set_attr "type" "move,const,const,load,store,fmove,mtc,fpload,mfc,fpstore,mfc,mtc,mthilo,mfhilo,mtc,load,mfc,store") + [(set_attr "type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mthilo,mfhilo,mtc,load,mfc,store") (set_attr "mode" "SI") - (set_attr "length" "4,*,*,*,*,4,4,*,4,*,4,4,4,4,4,*,4,*")]) + (set_attr "length" "4,*,*,*,*,4,*,4,*,4,4,4,4,4,*,4,*")]) (define_insn "*movsi_mips16" [(set (match_operand:SI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m") @@ -3727,8 +3727,8 @@ }) (define_insn "*movhi_internal" - [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x") - (match_operand:HI 1 "move_operand" "d,I,m,dJ,*f,*d,*f,*d"))] + [(set (match_operand:HI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*x") + (match_operand:HI 1 "move_operand" "d,I,m,dJ,*f,*d,*d"))] "!TARGET_MIPS16 && (register_operand (operands[0], HImode) || reg_or_0_operand (operands[1], HImode))" @@ -3739,11 +3739,10 @@ sh\t%z1,%0 mfc1\t%0,%1 mtc1\t%1,%0 - mov.s\t%0,%1 mt%0\t%1" - [(set_attr "type" "move,arith,load,store,mfc,mtc,fmove,mthilo") + [(set_attr "type" "move,arith,load,store,mfc,mtc,mthilo") (set_attr "mode" "HI") - (set_attr "length" "4,4,*,*,4,4,4,4")]) + (set_attr "length" "4,4,*,*,4,4,4")]) (define_insn "*movhi_mips16" [(set (match_operand:HI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m") @@ -3834,8 +3833,8 @@ }) (define_insn "*movqi_internal" - [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*f,*x") - (match_operand:QI 1 "move_operand" "d,I,m,dJ,*f,*d,*f,*d"))] + [(set (match_operand:QI 0 "nonimmediate_operand" "=d,d,d,m,*d,*f,*x") + (match_operand:QI 1 "move_operand" "d,I,m,dJ,*f,*d,*d"))] "!TARGET_MIPS16 && (register_operand (operands[0], QImode) || reg_or_0_operand (operands[1], QImode))" @@ -3846,11 +3845,10 @@ sb\t%z1,%0 mfc1\t%0,%1 mtc1\t%1,%0 - mov.s\t%0,%1 mt%0\t%1" - [(set_attr "type" "move,arith,load,store,mfc,mtc,fmove,mthilo") + [(set_attr "type" "move,arith,load,store,mfc,mtc,mthilo") (set_attr "mode" "QI") - (set_attr "length" "4,4,*,*,4,4,4,4")]) + (set_attr "length" "4,4,*,*,4,4,4")]) (define_insn "*movqi_mips16" [(set (match_operand:QI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m")