@@ -162,7 +162,7 @@ extern const char *arm_output_shift(rtx *, int);
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_pp_multi(rtx, rtx, int);
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);
@@ -27729,14 +27729,15 @@ arm_preferred_rename_class (reg_class_t rclass)
return NO_REGS;
}
-/* Compute the atrribute "length" of insn "*push_multi".
- So this function MUST be kept in sync with that insn pattern. */
+/* Compute the attribute "length" of an insn which performs a push/pop on
+ multiple registers. So this function MUST be kept in sync with that insn
+ pattern. PARALLEL_OP is the toplevel PARALLEL rtx, FIRST_OP is the first
+ push/pop register. FIRST_INDEX is the element index inside PARALLEL_OP for
+ the first register push/pop rtx. */
+
int
-arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
+arm_attr_length_pp_multi(rtx parallel_op, rtx first_op, int first_index)
{
- int i, regno, hi_reg;
- int num_saves = XVECLEN (parallel_op, 0);
-
/* ARM mode. */
if (TARGET_ARM)
return 4;
@@ -27744,18 +27745,31 @@ arm_attr_length_push_multi(rtx parallel_op, rtx first_op)
if (TARGET_THUMB1)
return 2;
- /* Thumb2 mode. */
- regno = REGNO (first_op);
- hi_reg = (REGNO_REG_CLASS (regno) == HI_REGS) && (regno != LR_REGNUM);
- for (i = 1; i < num_saves && !hi_reg; i++)
+ /* Thumb2 mode.
+ For the pattern "*push_multi", the register for the first push is kept in
+ the first UNSPEC rtx inside parallel, all other registers are kept in the
+ later USE rtxes. For pop* pattern, each register pop is cleanly
+ represented by an (set (reg) (mem)).
+
+ So we can't always use REGNO (XEXP (input, 0)) to fetch the first register,
+ thus it's passed as argument. Then we iterate the register list from the
+ last to the first, as the high register is usually at the end so we can
+ return earlier. */
+
+ unsigned int regno = REGNO (first_op);
+ if ((REGNO_REG_CLASS (regno) == HI_REGS) && (regno != LR_REGNUM))
+ return 4;
+
+ int i = XVECLEN (parallel_op, 0) - 1;
+ gcc_assert (first_index >= 0 && first_index <= i);
+ for (; i > first_index; i--)
{
regno = REGNO (XEXP (XVECEXP (parallel_op, 0, i), 0));
- hi_reg |= (REGNO_REG_CLASS (regno) == HI_REGS) && (regno != LR_REGNUM);
+ if (REGNO_REG_CLASS (regno) == HI_REGS && (regno != LR_REGNUM))
+ return 4;
}
- if (!hi_reg)
- return 2;
- return 4;
+ return 2;
}
/* Compute the number of instructions emitted by output_move_double. */
@@ -10488,7 +10488,7 @@
;; expressions. For simplicity, the first register is also in the unspec
;; part.
;; To avoid the usage of GNU extension, the length attribute is computed
-;; in a C function arm_attr_length_push_multi.
+;; in a C function arm_attr_length_pp_multi.
(define_insn "*push_multi"
[(match_parallel 2 "multi_register_push"
[(set (match_operand:BLK 0 "push_mult_memory_operand" "")
@@ -10530,7 +10530,7 @@
}"
[(set_attr "type" "store4")
(set (attr "length")
- (symbol_ref "arm_attr_length_push_multi (operands[2], operands[1])"))]
+ (symbol_ref "arm_attr_length_pp_multi (operands[2], operands[1], 0)"))]
)
(define_insn "stack_tie"
@@ -10565,7 +10565,9 @@
}
"
[(set_attr "type" "load4")
- (set_attr "predicable" "yes")]
+ (set_attr "predicable" "yes")
+ (set (attr "length")
+ (symbol_ref "arm_attr_length_pp_multi (operands[0], operands[3], 1)"))]
)
;; Pop with return (as used in epilogue RTL)
@@ -10594,7 +10596,9 @@
}
"
[(set_attr "type" "load4")
- (set_attr "predicable" "yes")]
+ (set_attr "predicable" "yes")
+ (set (attr "length")
+ (symbol_ref "arm_attr_length_pp_multi (operands[0], operands[3], 2)"))]
)
(define_insn "*pop_multiple_with_return"
@@ -10614,7 +10618,9 @@
}
"
[(set_attr "type" "load4")
- (set_attr "predicable" "yes")]
+ (set_attr "predicable" "yes")
+ (set (attr "length")
+ (symbol_ref "arm_attr_length_pp_multi (operands[0], operands[2], 1)"))]
)
;; Load into PC and return