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"