2012-04-30 Ian Bolton <ian.bolton at arm.com> Sameera Deshpande...
2012-04-30 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. Co-Authored-By: Greta Yorsh <greta.yorsh@arm.com> Co-Authored-By: Sameera Deshpande <sameera.deshpande@arm.com> From-SVN: r186980
This commit is contained in:
parent
d55d2c8490
commit
5991e1568c
|
@ -1,3 +1,12 @@
|
|||
2012-04-30 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.
|
||||
|
||||
2012-04-30 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* config/i386/i386.md (and<mode>3): Expand masking operations with
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -10166,6 +10166,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
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue