diff options
author | Ian Bolton <ian.bolton@arm.com> | 2012-06-18 17:30:41 +0000 |
---|---|---|
committer | Greta Yorsh <gretay@gcc.gnu.org> | 2012-06-18 18:30:41 +0100 |
commit | 4b2678f8864154a2339001a0ad588c7f611437c7 (patch) | |
tree | 2fbecb24dff9d18763579b4db54ee60e68c66f1e /gcc | |
parent | 3aee198212070736d6a42f3a53f943f61ddc9d4a (diff) | |
download | gcc-4b2678f8864154a2339001a0ad588c7f611437c7.zip gcc-4b2678f8864154a2339001a0ad588c7f611437c7.tar.gz gcc-4b2678f8864154a2339001a0ad588c7f611437c7.tar.bz2 |
New define insn pattern for epilogue with floating point registers (DFmode) and...
New define insn pattern for epilogue with floating point registers (DFmode)
and a new function that emits RTL for this pattern. This function is a
helper for epilogue extension. It is used by a later patch.
gcc/
2012-06-18 Ian Bolton <ian.bolton@arm.com>
Sameera Deshpande <sameera.deshpande@arm.com>
Greta Yorsh <greta.yorsh@arm.com>
* config/arm/arm.md (vfp_pop_multiple_with_writeback) New
define_insn.
* config/arm/predicates.md (pop_multiple_fp) New special predicate.
* config/arm/arm.c (arm_emit_vfp_multi_reg_pop): New function.
Co-Authored-By: Greta Yorsh <greta.yorsh@arm.com>
Co-Authored-By: Sameera Deshpande <sameera.deshpande@arm.com>
From-SVN: r188740
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 70 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 35 | ||||
-rw-r--r-- | gcc/config/arm/predicates.md | 8 |
4 files changed, 122 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b3d50d3..f9362b1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,15 @@ Sameera Deshpande <sameera.deshpande@arm.com> Greta Yorsh <greta.yorsh@arm.com> + * config/arm/arm.md (vfp_pop_multiple_with_writeback) New + define_insn. + * config/arm/predicates.md (pop_multiple_fp) New special predicate. + * config/arm/arm.c (arm_emit_vfp_multi_reg_pop): New function. + +2012-06-18 Ian Bolton <ian.bolton@arm.com> + Sameera Deshpande <sameera.deshpande@arm.com> + Greta Yorsh <greta.yorsh@arm.com> + * config/arm/arm.md (load_multiple_with_writeback) New define_insn. (load_multiple, pop_multiple_with_writeback_and_return) Likewise. (pop_multiple_with_return, ldr_with_return) Likewise. diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index 5b3e6f5..02f27d0 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -16544,6 +16544,76 @@ arm_emit_multi_reg_pop (unsigned long saved_regs_mask) REG_NOTES (par) = dwarf; } +/* Generate and emit an insn pattern that we will recognize as a pop_multi + of NUM_REGS consecutive VFP regs, starting at FIRST_REG. + + Unfortunately, since this insn does not reflect very well the actual + semantics of the operation, we need to annotate the insn for the benefit + of DWARF2 frame unwind information. */ +static void +arm_emit_vfp_multi_reg_pop (int first_reg, int num_regs, rtx base_reg) +{ + int i, j; + rtx par; + rtx dwarf = NULL_RTX; + rtx tmp, reg; + + gcc_assert (num_regs && num_regs <= 32); + + /* Workaround ARM10 VFPr1 bug. */ + if (num_regs == 2 && !arm_arch6) + { + if (first_reg == 15) + first_reg--; + + num_regs++; + } + + /* We can emit at most 16 D-registers in a single pop_multi instruction, and + there could be up to 32 D-registers to restore. + If there are more than 16 D-registers, make two recursive calls, + each of which emits one pop_multi instruction. */ + if (num_regs > 16) + { + arm_emit_vfp_multi_reg_pop (first_reg, 16, base_reg); + arm_emit_vfp_multi_reg_pop (first_reg + 16, num_regs - 16, base_reg); + return; + } + + /* The parallel needs to hold num_regs SETs + and one SET for the stack update. */ + par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs + 1)); + + /* Increment the stack pointer, based on there being + num_regs 8-byte registers to restore. */ + tmp = gen_rtx_SET (VOIDmode, + base_reg, + plus_constant (Pmode, base_reg, 8 * num_regs)); + RTX_FRAME_RELATED_P (tmp) = 1; + XVECEXP (par, 0, 0) = tmp; + + /* Now show every reg that will be restored, using a SET for each. */ + for (j = 0, i=first_reg; j < num_regs; i += 2) + { + reg = gen_rtx_REG (DFmode, i); + + tmp = gen_rtx_SET (VOIDmode, + reg, + gen_frame_mem + (DFmode, + plus_constant (Pmode, base_reg, 8 * j))); + RTX_FRAME_RELATED_P (tmp) = 1; + XVECEXP (par, 0, j + 1) = tmp; + + dwarf = alloc_reg_note (REG_CFA_RESTORE, reg, dwarf); + + j++; + } + + par = emit_insn (par); + REG_NOTES (par) = dwarf; +} + /* Calculate the size of the return value that is passed in registers. */ static unsigned arm_size_return_regs (void) diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 3fa207b..bde8580 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -10946,6 +10946,41 @@ [(set_attr "type" "load1") (set_attr "predicable" "yes")] ) +;; Pop for floating point registers (as used in epilogue RTL) +(define_insn "*vfp_pop_multiple_with_writeback" + [(match_parallel 0 "pop_multiple_fp" + [(set (match_operand:SI 1 "s_register_operand" "+rk") + (plus:SI (match_dup 1) + (match_operand:SI 2 "const_int_operand" "I"))) + (set (match_operand:DF 3 "arm_hard_register_operand" "") + (mem:DF (match_dup 1)))])] + "TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP" + "* + { + int num_regs = XVECLEN (operands[0], 0); + char pattern[100]; + rtx op_list[2]; + strcpy (pattern, \"fldmfdd\\t\"); + strcat (pattern, reg_names[REGNO (SET_DEST (XVECEXP (operands[0], 0, 0)))]); + strcat (pattern, \"!, {\"); + op_list[0] = XEXP (XVECEXP (operands[0], 0, 1), 0); + strcat (pattern, \"%P0\"); + if ((num_regs - 1) > 1) + { + strcat (pattern, \"-%P1\"); + op_list [1] = XEXP (XVECEXP (operands[0], 0, num_regs - 1), 0); + } + + strcat (pattern, \"}\"); + output_asm_insn (pattern, op_list); + return \"\"; + } + " + [(set_attr "type" "load4") + (set_attr "conds" "unconditional") + (set_attr "predicable" "no")] +) + ;; Special patterns for dealing with the constant pool (define_insn "align_4" diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md index 6eaab3d..9fd9ad2 100644 --- a/gcc/config/arm/predicates.md +++ b/gcc/config/arm/predicates.md @@ -376,6 +376,14 @@ /*return_pc=*/true); }) +(define_special_predicate "pop_multiple_fp" + (match_code "parallel") +{ + return ldm_stm_operation_p (op, /*load=*/true, DFmode, + /*consecutive=*/true, + /*return_pc=*/false); +}) + (define_special_predicate "multi_register_push" (match_code "parallel") { |