aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYvan Roux <yvan.roux@linaro.org>2016-09-02 09:56:59 +0200
committerYvan Roux <yvan.roux@linaro.org>2016-09-07 22:08:22 +0200
commitdc7ea65bae8a93c6bb20038e8bf47832be9a8114 (patch)
treefd76febc0e0f0662b26b92dcd19ba25f8f5fcd27
parent9e254fb6f6861b5a7bfc51bc9c475d855efc6bc7 (diff)
gcc/
Backport from trunk r237331. 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. Change-Id: I19b35183be89cdcab6e40b6c727334342873e9ea
-rw-r--r--gcc/config/arm/arm-protos.h1
-rw-r--r--gcc/config/arm/arm.c57
-rw-r--r--gcc/config/arm/arm.md16
3 files changed, 70 insertions, 4 deletions
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index aaaabb761cf..1ba2ebb630e 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -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);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 394af7f52ee..19057a894c4 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -27800,7 +27800,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)
@@ -27817,6 +27817,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++)
{
@@ -27829,6 +27834,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)
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index c1477ad6228..59efdecefa5 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -10562,7 +10562,11 @@
}
"
[(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)
@@ -10591,7 +10595,10 @@
}
"
[(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"
@@ -10611,7 +10618,10 @@
}
"
[(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