diff options
author | Jiong Wang <jiong.wang@arm.com> | 2016-06-11 20:42:26 +0000 |
---|---|---|
committer | Jiong Wang <jiwang@gcc.gnu.org> | 2016-06-11 20:42:26 +0000 |
commit | 5775d58c066fe26e8d7de607a725743705cfd08d (patch) | |
tree | 13f9f0b62c517609fd6e7c120f28c37f6e02ec48 | |
parent | a0d66002539dcc75618868d902a44e11059b286a (diff) | |
download | gcc-5775d58c066fe26e8d7de607a725743705cfd08d.zip gcc-5775d58c066fe26e8d7de607a725743705cfd08d.tar.gz gcc-5775d58c066fe26e8d7de607a725743705cfd08d.tar.bz2 |
[ARM] length pop* pattern in epilogue correctly
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
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/config/arm/arm-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 57 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 16 |
4 files changed, 82 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e463219..6266fb3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index aaaabb7..1ba2ebb 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 47d2447..3503c15 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -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) diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md index 04714a1..1649831 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 |