[ARM] length pop* pattern in epilogue correctly
authorJiong Wang <jiong.wang@arm.com>
Sat, 11 Jun 2016 20:42:26 +0000 (20:42 +0000)
committerJiong Wang <jiwang@gcc.gnu.org>
Sat, 11 Jun 2016 20:42:26 +0000 (20:42 +0000)
PR target/71061
* config/arm/arm-protos.h (arm_attr_length_pop_multi): New declaration.
* config/arm/arm.c (arm_attr_length_pop_multi): New function to return
length for pop patterns.
(arm_attr_length_push_multi): Update comments.
* config/arm/arm.md (*load_multiple_with_writeback): Set "length"
attribute.
(*pop_multiple_with_writeback_and_return): Likewise.
(*pop_multiple_with_return): Likewise.

From-SVN: r237331

gcc/ChangeLog
gcc/config/arm/arm-protos.h
gcc/config/arm/arm.c
gcc/config/arm/arm.md

index e463219cdf0fa3a02f74d5d38f4d70cc3f1c4aa8..6266fb35712368ed9764512a93c60fa131c83504 100644 (file)
@@ -1,3 +1,15 @@
+2016-06-11  Jiong Wang  <jiong.wang@arm.com>
+
+       PR target/71061
+       * config/arm/arm-protos.h (arm_attr_length_pop_multi): New declaration.
+       * config/arm/arm.c (arm_attr_length_pop_multi): New function to return
+       length for pop patterns.
+       (arm_attr_length_push_multi): Update comments.
+       * config/arm/arm.md (*load_multiple_with_writeback): Set "length"
+       attribute.
+       (*pop_multiple_with_writeback_and_return): Likewise.
+       (*pop_multiple_with_return): Likewise.
+
 2016-06-11  Segher Boessenkool  <segher@kernel.crashing.org>
 
        PR middle-end/71310
index aaaabb761cfdad943ac895b511a0514cd4ee8471..1ba2ebb630ea109fec35c3883561c13816478801 100644 (file)
@@ -163,6 +163,7 @@ extern const char *arm_output_iwmmxt_shift_immediate (const char *, rtx *, bool)
 extern const char *arm_output_iwmmxt_tinsr (rtx *);
 extern unsigned int arm_sync_loop_insns (rtx , rtx *);
 extern int arm_attr_length_push_multi(rtx, rtx);
+extern int arm_attr_length_pop_multi(rtx *, bool, bool);
 extern void arm_expand_compare_and_swap (rtx op[]);
 extern void arm_split_compare_and_swap (rtx op[]);
 extern void arm_split_atomic_op (enum rtx_code, rtx, rtx, rtx, rtx, rtx, rtx);
index 47d2447ed34c4a1be46dff489ef8b4d0c30d4cde..3503c15420ede88761a870c9ad5b8968cadb2d0e 100644 (file)
@@ -27793,7 +27793,7 @@ arm_preferred_rename_class (reg_class_t rclass)
     return NO_REGS;
 }
 
-/* Compute the atrribute "length" of insn "*push_multi".
+/* Compute the attribute "length" of insn "*push_multi".
    So this function MUST be kept in sync with that insn pattern.  */
 int
 arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
@@ -27810,6 +27810,11 @@ arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
 
   /* Thumb2 mode.  */
   regno = REGNO (first_op);
+  /* For PUSH/STM under Thumb2 mode, we can use 16-bit encodings if the register
+     list is 8-bit.  Normally this means all registers in the list must be
+     LO_REGS, that is (R0 -R7).  If any HI_REGS used, then we must use 32-bit
+     encodings.  There is one exception for PUSH that LR in HI_REGS can be used
+     with 16-bit encoding.  */
   hi_reg = (REGNO_REG_CLASS (regno) == HI_REGS) && (regno != LR_REGNUM);
   for (i = 1; i < num_saves && !hi_reg; i++)
     {
@@ -27822,6 +27827,56 @@ arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
   return 4;
 }
 
+/* Compute the attribute "length" of insn.  Currently, this function is used
+   for "*load_multiple_with_writeback", "*pop_multiple_with_return" and
+   "*pop_multiple_with_writeback_and_return".  OPERANDS is the toplevel PARALLEL
+   rtx, RETURN_PC is true if OPERANDS contains return insn.  WRITE_BACK_P is
+   true if OPERANDS contains insn which explicit updates base register.  */
+
+int
+arm_attr_length_pop_multi (rtx *operands, bool return_pc, bool write_back_p)
+{
+  /* ARM mode.  */
+  if (TARGET_ARM)
+    return 4;
+  /* Thumb1 mode.  */
+  if (TARGET_THUMB1)
+    return 2;
+
+  rtx parallel_op = operands[0];
+  /* Initialize to elements number of PARALLEL.  */
+  unsigned indx = XVECLEN (parallel_op, 0) - 1;
+  /* Initialize the value to base register.  */
+  unsigned regno = REGNO (operands[1]);
+  /* Skip return and write back pattern.
+     We only need register pop pattern for later analysis.  */
+  unsigned first_indx = 0;
+  first_indx += return_pc ? 1 : 0;
+  first_indx += write_back_p ? 1 : 0;
+
+  /* A pop operation can be done through LDM or POP.  If the base register is SP
+     and if it's with write back, then a LDM will be alias of POP.  */
+  bool pop_p = (regno == SP_REGNUM && write_back_p);
+  bool ldm_p = !pop_p;
+
+  /* Check base register for LDM.  */
+  if (ldm_p && REGNO_REG_CLASS (regno) == HI_REGS)
+    return 4;
+
+  /* Check each register in the list.  */
+  for (; indx >= first_indx; indx--)
+    {
+      regno = REGNO (XEXP (XVECEXP (parallel_op, 0, indx), 0));
+      /* For POP, PC in HI_REGS can be used with 16-bit encoding.  See similar
+        comment in arm_attr_length_push_multi.  */
+      if (REGNO_REG_CLASS (regno) == HI_REGS
+         && (regno != PC_REGNUM || ldm_p))
+       return 4;
+    }
+
+  return 2;
+}
+
 /* Compute the number of instructions emitted by output_move_double.  */
 int
 arm_count_output_move_double_insns (rtx *operands)
index 04714a1335e5915e1237f430c9561bc6ef52e976..16498316bee9f19baff414885efe1e78191da047 100644 (file)
   }
   "
   [(set_attr "type" "load4")
-   (set_attr "predicable" "yes")]
+   (set_attr "predicable" "yes")
+   (set (attr "length")
+       (symbol_ref "arm_attr_length_pop_multi (operands,
+                                               /*return_pc=*/false,
+                                               /*write_back_p=*/true)"))]
 )
 
 ;; Pop with return (as used in epilogue RTL)
   }
   "
   [(set_attr "type" "load4")
-   (set_attr "predicable" "yes")]
+   (set_attr "predicable" "yes")
+   (set (attr "length")
+       (symbol_ref "arm_attr_length_pop_multi (operands, /*return_pc=*/true,
+                                               /*write_back_p=*/true)"))]
 )
 
 (define_insn "*pop_multiple_with_return"
   }
   "
   [(set_attr "type" "load4")
-   (set_attr "predicable" "yes")]
+   (set_attr "predicable" "yes")
+   (set (attr "length")
+       (symbol_ref "arm_attr_length_pop_multi (operands, /*return_pc=*/true,
+                                               /*write_back_p=*/false)"))]
 )
 
 ;; Load into PC and return