Generalize ldm_stm_operation_p with additional parameters that will be used
by epilogue patterns:
* machine mode to support both SImode and DFmode registers
* flag to request consecutive registers in the register list
* flag to indicate whether PC in the register list
gcc/ChangeLog
2012-04-24 Ian Bolton <ian.bolton at arm.com>
Sameera Deshpande <sameera.deshpande at arm.com>
Greta Yorsh <greta.yorsh at arm.com>
* config/arm/arm-protos.h (ldm_stm_operation_p): New parameters.
* config/arm/arm.c (ldm_stm_operation_p): New parameters.
* config/arm/predicates.md (load_multiple_operation): Add arguments.
(store_multiple_operation): Likewise.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 753e109..efb5b9f 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -62,7 +62,8 @@ extern bool arm_legitimize_reload_address (rtx *, enum
machine_mode, int, int,
extern rtx thumb_legitimize_reload_address (rtx *, enum machine_mode, int, int,
int);
extern int thumb1_legitimate_address_p (enum machine_mode, rtx, int);
-extern bool ldm_stm_operation_p (rtx, bool);
+extern bool ldm_stm_operation_p (rtx, bool, enum machine_mode mode,
+ bool, bool);
extern int arm_const_double_rtx (rtx);
extern int neg_const_double_rtx_ok_for_fpa (rtx);
extern int vfp3_const_double_rtx (rtx);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 4216d05..5477de2 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -10139,7 +10139,9 @@ adjacent_mem_locations (rtx a, rtx b)
}
/* Return true if OP is a valid load or store multiple operation. LOAD is true
- for load operations, false for store operations.
+ for load operations, false for store operations. CONSECUTIVE is true
+ if the register numbers in the operation must be consecutive in the register
+ bank. RETURN_PC is true if value is to be loaded in PC.
The pattern we are trying to match for load is:
[(SET (R_d0) (MEM (PLUS (addr) (offset))))
(SET (R_d1) (MEM (PLUS (addr) (offset + <reg_increment>))))
@@ -10154,20 +10156,31 @@ adjacent_mem_locations (rtx a, rtx b)
REGNO (R_dk) = REGNO (R_d0) + k.
The pattern for store is similar. */
bool
-ldm_stm_operation_p (rtx op, bool load)
+ldm_stm_operation_p (rtx op, bool load, enum machine_mode mode,
+ bool consecutive, bool return_pc)
{
HOST_WIDE_INT count = XVECLEN (op, 0);
rtx reg, mem, addr;
unsigned regno;
+ unsigned first_regno;
HOST_WIDE_INT i = 1, base = 0, offset = 0;
rtx elt;
bool addr_reg_in_reglist = false;
bool update = false;
int reg_increment;
int offset_adj;
+ int regs_per_val;
- reg_increment = 4;
- offset_adj = 0;
+ /* If not in SImode, then registers must be consecutive
+ (e.g., VLDM instructions for DFmode). */
+ gcc_assert ((mode == SImode) || consecutive);
+ /* Setting return_pc for stores is illegal. */
+ gcc_assert (!return_pc || load);
+
+ /* Set up the increments and the regs per val based on the mode. */
+ reg_increment = GET_MODE_SIZE (mode);
+ regs_per_val = reg_increment / 4;
+ offset_adj = return_pc ? 1 : 0;
if (count <= 1
|| GET_CODE (XVECEXP (op, 0, offset_adj)) != SET
@@ -10195,9 +10208,11 @@ ldm_stm_operation_p (rtx op, bool load)
i = i + offset_adj;
base = base + offset_adj;
- /* Perform a quick check so we don't blow up below. */
- if (count <= i)
- return false;
+ /* Perform a quick check so we don't blow up below. If only one reg is
loaded,
+ success depends on the type: VLDM can do just one reg,
+ LDM must do at least two. */
+ if ((count <= i) && (mode == SImode))
+ return false;
elt = XVECEXP (op, 0, i - 1);
if (GET_CODE (elt) != SET)
@@ -10218,6 +10233,7 @@ ldm_stm_operation_p (rtx op, bool load)
return false;
regno = REGNO (reg);
+ first_regno = regno;
addr = XEXP (mem, 0);
if (GET_CODE (addr) == PLUS)
{
@@ -10249,10 +10265,13 @@ ldm_stm_operation_p (rtx op, bool load)
}
if (!REG_P (reg)
- || GET_MODE (reg) != SImode
+ || GET_MODE (reg) != mode
|| REGNO (reg) <= regno
+ || (consecutive
+ && (REGNO (reg) !=
+ (unsigned int) (first_regno + regs_per_val * (i - base))))
|| !MEM_P (mem)
- || GET_MODE (mem) != SImode
+ || GET_MODE (mem) != mode
|| ((GET_CODE (XEXP (mem, 0)) != PLUS
|| !rtx_equal_p (XEXP (XEXP (mem, 0), 0), addr)
|| !CONST_INT_P (XEXP (XEXP (mem, 0), 1))
diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
index 20a64ec..428f9e0 100644
--- a/gcc/config/arm/predicates.md
+++ b/gcc/config/arm/predicates.md
@@ -380,13 +380,17 @@
(define_special_predicate "load_multiple_operation"
(match_code "parallel")
{
- return ldm_stm_operation_p (op, /*load=*/true);
+ return ldm_stm_operation_p (op, /*load=*/true, SImode,
+ /*consecutive=*/false,
+ /*return_pc=*/false);
})
(define_special_predicate "store_multiple_operation"
(match_code "parallel")
{
- return ldm_stm_operation_p (op, /*load=*/false);
+ return ldm_stm_operation_p (op, /*load=*/false, SImode,
+ /*consecutive=*/false,
+ /*return_pc=*/false);
})
(define_special_predicate "multi_register_push"