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:
Ian Bolton 2012-04-30 13:40:14 +00:00 committed by Richard Earnshaw
parent d55d2c8490
commit 5991e1568c
4 changed files with 156 additions and 143 deletions

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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"