New define insn pattern for epilogue with floating point registers (DFmode) and...
authorIan Bolton <ian.bolton@arm.com>
Mon, 18 Jun 2012 17:30:41 +0000 (17:30 +0000)
committerGreta Yorsh <gretay@gcc.gnu.org>
Mon, 18 Jun 2012 17:30:41 +0000 (18:30 +0100)
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

gcc/ChangeLog
gcc/config/arm/arm.c
gcc/config/arm/arm.md
gcc/config/arm/predicates.md

index b3d50d3aba5a95c05655b5ae87044f6d26544195..f9362b1da165aa08df20dcf3b00c2ed96643777b 100644 (file)
@@ -1,3 +1,12 @@
+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.
+
 2012-06-18  Ian Bolton  <ian.bolton@arm.com>
             Sameera Deshpande  <sameera.deshpande@arm.com>
             Greta Yorsh  <greta.yorsh@arm.com>
index 5b3e6f5add3f84acd0de9d5f61ec2c2885acf3f3..02f27d0cb913e6105a8f6a75fa83c943a2411d55 100644 (file)
@@ -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)
index 3fa207bab834bd78885476a40ba19c5ee16079f3..bde8580d81d233b2a323912c8ed87e6d8c68386e 100644 (file)
   [(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"
index 6eaab3d49e9923ba8f79003ea1181bb1ea32afb7..9fd9ad216fc06e56fb5d44b4b6a01033023d59f4 100644 (file)
                                  /*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")
 {