On 24/04/12 17:26, Greta Yorsh wrote:
> Move the code of the special predicates load_multiple_operation and
> store_multiple_operation into a separate function. No change in
> functionality.
>
> 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 declaration.
> * config/arm/arm.c (ldm_stm_operation_p): New function.
> * config/arm/predicates.md (load_multiple_operation): Update
> predicate.
> (store_multiple_operation): Likewise.
>
Thanks, I've committed this.
R.
>
>
> 1-predicate.patch.txt
>
>
> diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
> index 900d09a..7da0e90 100644
> --- a/gcc/config/arm/arm-protos.h
> +++ b/gcc/config/arm/arm-protos.h
> @@ -62,6 +62,7 @@ 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 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 e5779ce..74f4abf 100644
> --- a/gcc/config/arm/arm.c
> +++ b/gcc/config/arm/arm.c
> @@ -10138,6 +10138,150 @@ adjacent_mem_locations (rtx a, rtx b)
> return 0;
> }
>
> +/* Return true if OP is a valid load or store multiple operation. LOAD is
> true
> + for load operations, false for store operations.
> + 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>))))
> + :
> + :
> + (SET (R_dn) (MEM (PLUS (addr) (offset + n * <reg_increment>))))
> + ]
> + where
> + 1. If offset is 0, first insn should be (SET (R_d0) (MEM (src_addr))).
> + 2. REGNO (R_d0) < REGNO (R_d1) < ... < REGNO (R_dn).
> + 3. If consecutive is TRUE, then for kth register being loaded,
> + REGNO (R_dk) = REGNO (R_d0) + k.
> + The pattern for store is similar. */
> +bool
> +ldm_stm_operation_p (rtx op, bool load)
> +{
> + HOST_WIDE_INT count = XVECLEN (op, 0);
> + rtx reg, mem, addr;
> + unsigned 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;
> +
> + reg_increment = 4;
> + offset_adj = 0;
> +
> + if (count <= 1
> + || GET_CODE (XVECEXP (op, 0, offset_adj)) != SET
> + || (load && !REG_P (SET_DEST (XVECEXP (op, 0, offset_adj)))))
> + return false;
> +
> + /* Check if this is a write-back. */
> + elt = XVECEXP (op, 0, offset_adj);
> + if (GET_CODE (SET_SRC (elt)) == PLUS)
> + {
> + i++;
> + base = 1;
> + update = true;
> +
> + /* The offset adjustment must be the number of registers being
> + popped times the size of a single register. */
> + if (!REG_P (SET_DEST (elt))
> + || !REG_P (XEXP (SET_SRC (elt), 0))
> + || (REGNO (SET_DEST (elt)) != REGNO (XEXP (SET_SRC (elt), 0)))
> + || !CONST_INT_P (XEXP (SET_SRC (elt), 1))
> + || INTVAL (XEXP (SET_SRC (elt), 1)) !=
> + ((count - 1 - offset_adj) * reg_increment))
> + return false;
> + }
> +
> + i = i + offset_adj;
> + base = base + offset_adj;
> + /* Perform a quick check so we don't blow up below. */
> + if (count <= i)
> + return false;
> +
> + elt = XVECEXP (op, 0, i - 1);
> + if (GET_CODE (elt) != SET)
> + return false;
> +
> + if (load)
> + {
> + reg = SET_DEST (elt);
> + mem = SET_SRC (elt);
> + }
> + else
> + {
> + reg = SET_SRC (elt);
> + mem = SET_DEST (elt);
> + }
> +
> + if (!REG_P (reg) || !MEM_P (mem))
> + return false;
> +
> + regno = REGNO (reg);
> + addr = XEXP (mem, 0);
> + if (GET_CODE (addr) == PLUS)
> + {
> + if (!CONST_INT_P (XEXP (addr, 1)))
> + return false;
> +
> + offset = INTVAL (XEXP (addr, 1));
> + addr = XEXP (addr, 0);
> + }
> +
> + if (!REG_P (addr))
> + return false;
> +
> + for (; i < count; i++)
> + {
> + elt = XVECEXP (op, 0, i);
> + if (GET_CODE (elt) != SET)
> + return false;
> +
> + if (load)
> + {
> + reg = SET_DEST (elt);
> + mem = SET_SRC (elt);
> + }
> + else
> + {
> + reg = SET_SRC (elt);
> + mem = SET_DEST (elt);
> + }
> +
> + if (!REG_P (reg)
> + || GET_MODE (reg) != SImode
> + || REGNO (reg) <= regno
> + || !MEM_P (mem)
> + || GET_MODE (mem) != SImode
> + || ((GET_CODE (XEXP (mem, 0)) != PLUS
> + || !rtx_equal_p (XEXP (XEXP (mem, 0), 0), addr)
> + || !CONST_INT_P (XEXP (XEXP (mem, 0), 1))
> + || (INTVAL (XEXP (XEXP (mem, 0), 1)) !=
> + offset + (i - base) * reg_increment))
> + && (!REG_P (XEXP (mem, 0))
> + || offset + (i - base) * reg_increment != 0)))
> + return false;
> +
> + regno = REGNO (reg);
> + if (regno == REGNO (addr))
> + addr_reg_in_reglist = true;
> + }
> +
> + if (load)
> + {
> + if (update && addr_reg_in_reglist)
> + return false;
> +
> + /* For Thumb-1, address register is always modified - either by
> write-back
> + or by explicit load. If the pattern does not describe an update,
> + then the address register must be in the list of loaded registers.
> */
> + if (TARGET_THUMB1)
> + return update || addr_reg_in_reglist;
> + }
> +
> + return true;
> +}
> +
> /* Return true iff it would be profitable to turn a sequence of NOPS loads
> or stores (depending on IS_STORE) into a load-multiple or store-multiple
> instruction. ADD_OFFSET is nonzero if the base address register needs
> diff --git a/gcc/config/arm/predicates.md b/gcc/config/arm/predicates.md
> index 9171d73..0c44f47 100644
> --- a/gcc/config/arm/predicates.md
> +++ b/gcc/config/arm/predicates.md
> @@ -380,154 +380,13 @@
> (define_special_predicate "load_multiple_operation"
> (match_code "parallel")
> {
> - HOST_WIDE_INT count = XVECLEN (op, 0);
> - unsigned dest_regno;
> - rtx src_addr;
> - HOST_WIDE_INT i = 1, base = 0;
> - HOST_WIDE_INT offset = 0;
> - rtx elt;
> - bool addr_reg_loaded = false;
> - bool update = false;
> -
> - if (count <= 1
> - || GET_CODE (XVECEXP (op, 0, 0)) != SET
> - || !REG_P (SET_DEST (XVECEXP (op, 0, 0))))
> - return false;
> -
> - /* Check to see if this might be a write-back. */
> - if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
> - {
> - i++;
> - base = 1;
> - update = true;
> -
> - /* Now check it more carefully. */
> - if (GET_CODE (SET_DEST (elt)) != REG
> - || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
> - || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
> - || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
> - return false;
> - }
> -
> - /* Perform a quick check so we don't blow up below. */
> - if (count <= i
> - || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
> - || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != REG
> - || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != MEM)
> - return false;
> -
> - dest_regno = REGNO (SET_DEST (XVECEXP (op, 0, i - 1)));
> - src_addr = XEXP (SET_SRC (XVECEXP (op, 0, i - 1)), 0);
> - if (GET_CODE (src_addr) == PLUS)
> - {
> - if (GET_CODE (XEXP (src_addr, 1)) != CONST_INT)
> - return false;
> - offset = INTVAL (XEXP (src_addr, 1));
> - src_addr = XEXP (src_addr, 0);
> - }
> - if (!REG_P (src_addr))
> - return false;
> -
> - for (; i < count; i++)
> - {
> - elt = XVECEXP (op, 0, i);
> -
> - if (GET_CODE (elt) != SET
> - || GET_CODE (SET_DEST (elt)) != REG
> - || GET_MODE (SET_DEST (elt)) != SImode
> - || REGNO (SET_DEST (elt)) <= dest_regno
> - || GET_CODE (SET_SRC (elt)) != MEM
> - || GET_MODE (SET_SRC (elt)) != SImode
> - || ((GET_CODE (XEXP (SET_SRC (elt), 0)) != PLUS
> - || !rtx_equal_p (XEXP (XEXP (SET_SRC (elt), 0), 0), src_addr)
> - || GET_CODE (XEXP (XEXP (SET_SRC (elt), 0), 1)) != CONST_INT
> - || INTVAL (XEXP (XEXP (SET_SRC (elt), 0), 1)) != offset + (i -
> base) * 4)
> - && (!REG_P (XEXP (SET_SRC (elt), 0))
> - || offset + (i - base) * 4 != 0)))
> - return false;
> - dest_regno = REGNO (SET_DEST (elt));
> - if (dest_regno == REGNO (src_addr))
> - addr_reg_loaded = true;
> - }
> - /* For Thumb, we only have updating instructions. If the pattern does
> - not describe an update, it must be because the address register is
> - in the list of loaded registers - on the hardware, this has the effect
> - of overriding the update. */
> - if (update && addr_reg_loaded)
> - return false;
> - if (TARGET_THUMB1)
> - return update || addr_reg_loaded;
> - return true;
> + return ldm_stm_operation_p (op, /*load=*/true);
> })
>
> (define_special_predicate "store_multiple_operation"
> (match_code "parallel")
> {
> - HOST_WIDE_INT count = XVECLEN (op, 0);
> - unsigned src_regno;
> - rtx dest_addr;
> - HOST_WIDE_INT i = 1, base = 0, offset = 0;
> - rtx elt;
> -
> - if (count <= 1
> - || GET_CODE (XVECEXP (op, 0, 0)) != SET)
> - return false;
> -
> - /* Check to see if this might be a write-back. */
> - if (GET_CODE (SET_SRC (elt = XVECEXP (op, 0, 0))) == PLUS)
> - {
> - i++;
> - base = 1;
> -
> - /* Now check it more carefully. */
> - if (GET_CODE (SET_DEST (elt)) != REG
> - || GET_CODE (XEXP (SET_SRC (elt), 0)) != REG
> - || GET_CODE (XEXP (SET_SRC (elt), 1)) != CONST_INT
> - || INTVAL (XEXP (SET_SRC (elt), 1)) != (count - 1) * 4)
> - return false;
> - }
> -
> - /* Perform a quick check so we don't blow up below. */
> - if (count <= i
> - || GET_CODE (XVECEXP (op, 0, i - 1)) != SET
> - || GET_CODE (SET_DEST (XVECEXP (op, 0, i - 1))) != MEM
> - || GET_CODE (SET_SRC (XVECEXP (op, 0, i - 1))) != REG)
> - return false;
> -
> - src_regno = REGNO (SET_SRC (XVECEXP (op, 0, i - 1)));
> - dest_addr = XEXP (SET_DEST (XVECEXP (op, 0, i - 1)), 0);
> -
> - if (GET_CODE (dest_addr) == PLUS)
> - {
> - if (GET_CODE (XEXP (dest_addr, 1)) != CONST_INT)
> - return false;
> - offset = INTVAL (XEXP (dest_addr, 1));
> - dest_addr = XEXP (dest_addr, 0);
> - }
> - if (!REG_P (dest_addr))
> - return false;
> -
> - for (; i < count; i++)
> - {
> - elt = XVECEXP (op, 0, i);
> -
> - if (GET_CODE (elt) != SET
> - || GET_CODE (SET_SRC (elt)) != REG
> - || GET_MODE (SET_SRC (elt)) != SImode
> - || REGNO (SET_SRC (elt)) <= src_regno
> - || GET_CODE (SET_DEST (elt)) != MEM
> - || GET_MODE (SET_DEST (elt)) != SImode
> - || ((GET_CODE (XEXP (SET_DEST (elt), 0)) != PLUS
> - || !rtx_equal_p (XEXP (XEXP (SET_DEST (elt), 0), 0), dest_addr)
> - || GET_CODE (XEXP (XEXP (SET_DEST (elt), 0), 1)) != CONST_INT
> - || INTVAL (XEXP (XEXP (SET_DEST (elt), 0), 1)) != offset + (i
> - base) * 4)
> - && (!REG_P (XEXP (SET_DEST (elt), 0))
> - || offset + (i - base) * 4 != 0)))
> - return false;
> - src_regno = REGNO (SET_SRC (elt));
> - }
> -
> - return true;
> + return ldm_stm_operation_p (op, /*load=*/false);
> })
>
> (define_special_predicate "multi_register_push"