diff options
author | David S. Miller <davem@davemloft.net> | 2011-10-24 03:51:47 +0000 |
---|---|---|
committer | David S. Miller <davem@gcc.gnu.org> | 2011-10-23 20:51:47 -0700 |
commit | bb12a72a480421a89e860414cf69065fd4607443 (patch) | |
tree | 5bd9c991eaa0a8e9b848234a50274bca511fcf1f /gcc/config/sparc/sparc.c | |
parent | ec8ab7c4e438c4da643d03b1f0c47e5dd7e860b1 (diff) | |
download | gcc-bb12a72a480421a89e860414cf69065fd4607443.zip gcc-bb12a72a480421a89e860414cf69065fd4607443.tar.gz gcc-bb12a72a480421a89e860414cf69065fd4607443.tar.bz2 |
Add support for sparc VIS3 fp<-->int moves.
* config/sparc/sparc.h (SECONDARY_MEMORY_NEEDED): We can move
between float and non-float regs when VIS3.
* config/sparc/sparc.c (eligible_for_restore_insn): We can't
use a restore when the source is a float register.
(sparc_split_regreg_legitimate): When VIS3 allow moves between
float and integer regs.
(sparc_register_move_cost): Adjust to account for VIS3 moves.
(sparc_preferred_reload_class): On 32-bit with VIS3 when moving an
integer reg to a class containing EXTRA_FP_REGS, constrain to
FP_REGS.
(sparc_secondary_reload): On 32-bit with VIS3 when moving between
float and integer regs we sometimes need a FP_REGS class
intermediate move to satisfy the reload. When this happens
specify an extra cost of 2.
(*movsi_insn): Rename to have "_novis3" suffix and add !VIS3
guard.
(*movdi_insn_sp32_v9): Likewise.
(*movdi_insn_sp64): Likewise.
(*movsf_insn): Likewise.
(*movdf_insn_sp32_v9): Likewise.
(*movdf_insn_sp64): Likewise.
(*zero_extendsidi2_insn_sp64): Likewise.
(*sign_extendsidi2_insn): Likewise.
(*movsi_insn_vis3): New insn.
(*movdi_insn_sp32_v9_vis3): New insn.
(*movdi_insn_sp64_vis3): New insn.
(*movsf_insn_vis3): New insn.
(*movdf_insn_sp32_v9_vis3): New insn.
(*movdf_insn_sp64_vis3): New insn.
(*zero_extendsidi2_insn_sp64_vis3): New insn.
(*sign_extendsidi2_insn_vis3): New insn.
(TFmode reg/reg split): Make sure both REG operands are float.
(*mov<VM32:mode>_insn): Add "_novis3" suffix and !VIS3 guard. Remove
easy constant to integer reg alternatives.
(*mov<VM64:mode>_insn_sp64): Likewise.
(*mov<VM64:mode>_insn_sp32_novis3): Likewise.
(*mov<VM32:mode>_insn_vis3): New insn.
(*mov<VM64:mode>_insn_sp64_vis3): New insn.
(*mov<VM64:mode>_insn_sp32_vis3): New insn.
(VM64 reg<-->reg split): New spliiter for 32-bit.
From-SVN: r180360
Diffstat (limited to 'gcc/config/sparc/sparc.c')
-rw-r--r-- | gcc/config/sparc/sparc.c | 85 |
1 files changed, 79 insertions, 6 deletions
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c index 29d2847..79bb821 100644 --- a/gcc/config/sparc/sparc.c +++ b/gcc/config/sparc/sparc.c @@ -2996,10 +2996,23 @@ eligible_for_restore_insn (rtx trial, bool return_p) { rtx pat = PATTERN (trial); rtx src = SET_SRC (pat); + bool src_is_freg = false; + rtx src_reg; + + /* Since we now can do moves between float and integer registers when + VIS3 is enabled, we have to catch this case. We can allow such + moves when doing a 'return' however. */ + src_reg = src; + if (GET_CODE (src_reg) == SUBREG) + src_reg = SUBREG_REG (src_reg); + if (GET_CODE (src_reg) == REG + && SPARC_FP_REG_P (REGNO (src_reg))) + src_is_freg = true; /* The 'restore src,%g0,dest' pattern for word mode and below. */ if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT - && arith_operand (src, GET_MODE (src))) + && arith_operand (src, GET_MODE (src)) + && ! src_is_freg) { if (TARGET_ARCH64) return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); @@ -3009,7 +3022,8 @@ eligible_for_restore_insn (rtx trial, bool return_p) /* The 'restore src,%g0,dest' pattern for double-word mode. */ else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT - && arith_double_operand (src, GET_MODE (src))) + && arith_double_operand (src, GET_MODE (src)) + && ! src_is_freg) return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode); /* The 'restore src,%g0,dest' pattern for float if no FPU. */ @@ -7784,6 +7798,13 @@ sparc_split_regreg_legitimate (rtx reg1, rtx reg2) if (SPARC_INT_REG_P (regno1) && SPARC_INT_REG_P (regno2)) return 1; + if (TARGET_VIS3) + { + if ((SPARC_INT_REG_P (regno1) && SPARC_FP_REG_P (regno2)) + || (SPARC_FP_REG_P (regno1) && SPARC_INT_REG_P (regno2))) + return 1; + } + return 0; } @@ -10302,10 +10323,28 @@ static int sparc_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, reg_class_t from, reg_class_t to) { - if ((FP_REG_CLASS_P (from) && general_or_i64_p (to)) - || (general_or_i64_p (from) && FP_REG_CLASS_P (to)) - || from == FPCC_REGS - || to == FPCC_REGS) + bool need_memory = false; + + if (from == FPCC_REGS || to == FPCC_REGS) + need_memory = true; + else if ((FP_REG_CLASS_P (from) && general_or_i64_p (to)) + || (general_or_i64_p (from) && FP_REG_CLASS_P (to))) + { + if (TARGET_VIS3) + { + int size = GET_MODE_SIZE (mode); + if (size == 8 || size == 4) + { + if (! TARGET_ARCH32 || size == 4) + return 4; + else + return 6; + } + } + need_memory = true; + } + + if (need_memory) { if (sparc_cpu == PROCESSOR_ULTRASPARC || sparc_cpu == PROCESSOR_ULTRASPARC3 @@ -11163,6 +11202,18 @@ sparc_preferred_reload_class (rtx x, reg_class_t rclass) } } + if (TARGET_VIS3 + && ! TARGET_ARCH64 + && (rclass == EXTRA_FP_REGS + || rclass == GENERAL_OR_EXTRA_FP_REGS)) + { + int regno = true_regnum (x); + + if (SPARC_INT_REG_P (regno)) + return (rclass == EXTRA_FP_REGS + ? FP_REGS : GENERAL_OR_FP_REGS); + } + return rclass; } @@ -11275,6 +11326,9 @@ sparc_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, { enum reg_class rclass = (enum reg_class) rclass_i; + sri->icode = CODE_FOR_nothing; + sri->extra_cost = 0; + /* We need a temporary when loading/storing a HImode/QImode value between memory and the FPU registers. This can happen when combine puts a paradoxical subreg in a float/fix conversion insn. */ @@ -11307,6 +11361,25 @@ sparc_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, return NO_REGS; } + if (TARGET_VIS3 && TARGET_ARCH32) + { + int regno = true_regnum (x); + + /* When using VIS3 fp<-->int register moves, on 32-bit we have + to move 8-byte values in 4-byte pieces. This only works via + FP_REGS, and not via EXTRA_FP_REGS. Therefore if we try to + move between EXTRA_FP_REGS and GENERAL_REGS, we will need + an FP_REGS intermediate move. */ + if ((rclass == EXTRA_FP_REGS && SPARC_INT_REG_P (regno)) + || ((general_or_i64_p (rclass) + || rclass == GENERAL_OR_FP_REGS) + && SPARC_FP_REG_P (regno))) + { + sri->extra_cost = 2; + return FP_REGS; + } + } + return NO_REGS; } |