[ARM, AArch64] Make aarch-common.c files more robust.
gcc/ * config/arm/aarch-common.c (search_term): New typedef. (shift_rtx_costs): New array. (arm_rtx_shift_left_p): New. (arm_find_sub_rtx_with_search_term): Likewise. (arm_find_sub_rtx_with_code): Likewise. (arm_early_load_addr_dep): Add sanity checking. (arm_no_early_alu_shift_dep): Likewise. (arm_no_early_alu_shift_value_dep): Likewise. (arm_no_early_mul_dep): Likewise. (arm_no_early_store_addr_dep): Likewise. From-SVN: r204575
This commit is contained in:
parent
34d1ff06bf
commit
df023e0f3e
@ -1,3 +1,17 @@
|
||||
2013-11-08 James Greenhalgh <james.greenhalgh@arm.com>
|
||||
|
||||
* config/arm/aarch-common.c
|
||||
(search_term): New typedef.
|
||||
(shift_rtx_costs): New array.
|
||||
(arm_rtx_shift_left_p): New.
|
||||
(arm_find_sub_rtx_with_search_term): Likewise.
|
||||
(arm_find_sub_rtx_with_code): Likewise.
|
||||
(arm_early_load_addr_dep): Add sanity checking.
|
||||
(arm_no_early_alu_shift_dep): Likewise.
|
||||
(arm_no_early_alu_shift_value_dep): Likewise.
|
||||
(arm_no_early_mul_dep): Likewise.
|
||||
(arm_no_early_store_addr_dep): Likewise.
|
||||
|
||||
2013-11-08 Richard Biener <rguenther@suse.de>
|
||||
|
||||
PR tree-optimization/59047
|
||||
|
@ -31,30 +31,139 @@
|
||||
#include "c-family/c-common.h"
|
||||
#include "rtl.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
rtx_code search_code;
|
||||
rtx search_result;
|
||||
bool find_any_shift;
|
||||
} search_term;
|
||||
|
||||
/* Return TRUE if X is either an arithmetic shift left, or
|
||||
is a multiplication by a power of two. */
|
||||
static bool
|
||||
arm_rtx_shift_left_p (rtx x)
|
||||
{
|
||||
enum rtx_code code = GET_CODE (x);
|
||||
|
||||
if (code == MULT && CONST_INT_P (XEXP (x, 1))
|
||||
&& exact_log2 (INTVAL (XEXP (x, 1))) > 0)
|
||||
return true;
|
||||
|
||||
if (code == ASHIFT)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static rtx_code shift_rtx_codes[] =
|
||||
{ ASHIFT, ROTATE, ASHIFTRT, LSHIFTRT,
|
||||
ROTATERT, ZERO_EXTEND, SIGN_EXTEND };
|
||||
|
||||
/* Callback function for arm_find_sub_rtx_with_code.
|
||||
DATA is safe to treat as a SEARCH_TERM, ST. This will
|
||||
hold a SEARCH_CODE. PATTERN is checked to see if it is an
|
||||
RTX with that code. If it is, write SEARCH_RESULT in ST
|
||||
and return 1. Otherwise, or if we have been passed a NULL_RTX
|
||||
return 0. If ST.FIND_ANY_SHIFT then we are interested in
|
||||
anything which can reasonably be described as a SHIFT RTX. */
|
||||
static int
|
||||
arm_find_sub_rtx_with_search_term (rtx *pattern, void *data)
|
||||
{
|
||||
search_term *st = (search_term *) data;
|
||||
rtx_code pattern_code;
|
||||
int found = 0;
|
||||
|
||||
gcc_assert (pattern);
|
||||
gcc_assert (st);
|
||||
|
||||
/* Poorly formed patterns can really ruin our day. */
|
||||
if (*pattern == NULL_RTX)
|
||||
return 0;
|
||||
|
||||
pattern_code = GET_CODE (*pattern);
|
||||
|
||||
if (st->find_any_shift)
|
||||
{
|
||||
unsigned i = 0;
|
||||
|
||||
/* Left shifts might have been canonicalized to a MULT of some
|
||||
power of two. Make sure we catch them. */
|
||||
if (arm_rtx_shift_left_p (*pattern))
|
||||
found = 1;
|
||||
else
|
||||
for (i = 0; i < ARRAY_SIZE (shift_rtx_codes); i++)
|
||||
if (pattern_code == shift_rtx_codes[i])
|
||||
found = 1;
|
||||
}
|
||||
|
||||
if (pattern_code == st->search_code)
|
||||
found = 1;
|
||||
|
||||
if (found)
|
||||
st->search_result = *pattern;
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/* Traverse PATTERN looking for a sub-rtx with RTX_CODE CODE. */
|
||||
static rtx
|
||||
arm_find_sub_rtx_with_code (rtx pattern, rtx_code code, bool find_any_shift)
|
||||
{
|
||||
search_term st;
|
||||
int result = 0;
|
||||
|
||||
gcc_assert (pattern != NULL_RTX);
|
||||
st.search_code = code;
|
||||
st.search_result = NULL_RTX;
|
||||
st.find_any_shift = find_any_shift;
|
||||
result = for_each_rtx (&pattern, arm_find_sub_rtx_with_search_term, &st);
|
||||
if (result)
|
||||
return st.search_result;
|
||||
else
|
||||
return NULL_RTX;
|
||||
}
|
||||
|
||||
/* Traverse PATTERN looking for any sub-rtx which looks like a shift. */
|
||||
static rtx
|
||||
arm_find_shift_sub_rtx (rtx pattern)
|
||||
{
|
||||
return arm_find_sub_rtx_with_code (pattern, ASHIFT, true);
|
||||
}
|
||||
|
||||
/* PRODUCER and CONSUMER are two potentially dependant RTX. PRODUCER
|
||||
(possibly) contains a SET which will provide a result we can access
|
||||
using the SET_DEST macro. We will place the RTX which would be
|
||||
written by PRODUCER in SET_SOURCE.
|
||||
Similarly, CONSUMER (possibly) contains a SET which has an operand
|
||||
we can access using SET_SRC. We place this operand in
|
||||
SET_DESTINATION.
|
||||
|
||||
Return nonzero if we found the SET RTX we expected. */
|
||||
static int
|
||||
arm_get_set_operands (rtx producer, rtx consumer,
|
||||
rtx *set_source, rtx *set_destination)
|
||||
{
|
||||
rtx set_producer = arm_find_sub_rtx_with_code (producer, SET, false);
|
||||
rtx set_consumer = arm_find_sub_rtx_with_code (consumer, SET, false);
|
||||
|
||||
if (set_producer && set_consumer)
|
||||
{
|
||||
*set_source = SET_DEST (set_producer);
|
||||
*set_destination = SET_SRC (set_consumer);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if the CONSUMER instruction (a load) does need
|
||||
PRODUCER's value to calculate the address. */
|
||||
|
||||
int
|
||||
arm_early_load_addr_dep (rtx producer, rtx consumer)
|
||||
{
|
||||
rtx value = PATTERN (producer);
|
||||
rtx addr = PATTERN (consumer);
|
||||
rtx value, addr;
|
||||
|
||||
if (GET_CODE (value) == COND_EXEC)
|
||||
value = COND_EXEC_CODE (value);
|
||||
if (GET_CODE (value) == PARALLEL)
|
||||
value = XVECEXP (value, 0, 0);
|
||||
value = XEXP (value, 0);
|
||||
if (GET_CODE (addr) == COND_EXEC)
|
||||
addr = COND_EXEC_CODE (addr);
|
||||
if (GET_CODE (addr) == PARALLEL)
|
||||
{
|
||||
if (GET_CODE (XVECEXP (addr, 0, 0)) == RETURN)
|
||||
addr = XVECEXP (addr, 0, 1);
|
||||
else
|
||||
addr = XVECEXP (addr, 0, 0);
|
||||
}
|
||||
addr = XEXP (addr, 1);
|
||||
if (!arm_get_set_operands (producer, consumer, &value, &addr))
|
||||
return 0;
|
||||
|
||||
return reg_overlap_mentioned_p (value, addr);
|
||||
}
|
||||
@ -62,88 +171,56 @@ arm_early_load_addr_dep (rtx producer, rtx consumer)
|
||||
/* Return nonzero if the CONSUMER instruction (an ALU op) does not
|
||||
have an early register shift value or amount dependency on the
|
||||
result of PRODUCER. */
|
||||
|
||||
int
|
||||
arm_no_early_alu_shift_dep (rtx producer, rtx consumer)
|
||||
{
|
||||
rtx value = PATTERN (producer);
|
||||
rtx op = PATTERN (consumer);
|
||||
rtx value, op;
|
||||
rtx early_op;
|
||||
|
||||
if (GET_CODE (value) == COND_EXEC)
|
||||
value = COND_EXEC_CODE (value);
|
||||
if (GET_CODE (value) == PARALLEL)
|
||||
value = XVECEXP (value, 0, 0);
|
||||
value = XEXP (value, 0);
|
||||
if (GET_CODE (op) == COND_EXEC)
|
||||
op = COND_EXEC_CODE (op);
|
||||
if (GET_CODE (op) == PARALLEL)
|
||||
op = XVECEXP (op, 0, 0);
|
||||
op = XEXP (op, 1);
|
||||
if (!arm_get_set_operands (producer, consumer, &value, &op))
|
||||
return 0;
|
||||
|
||||
early_op = XEXP (op, 0);
|
||||
/* This is either an actual independent shift, or a shift applied to
|
||||
the first operand of another operation. We want the whole shift
|
||||
operation. */
|
||||
if (REG_P (early_op))
|
||||
early_op = op;
|
||||
if ((early_op = arm_find_shift_sub_rtx (op)))
|
||||
{
|
||||
if (REG_P (early_op))
|
||||
early_op = op;
|
||||
|
||||
return !reg_overlap_mentioned_p (value, early_op);
|
||||
return !reg_overlap_mentioned_p (value, early_op);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if the CONSUMER instruction (an ALU op) does not
|
||||
have an early register shift value dependency on the result of
|
||||
PRODUCER. */
|
||||
|
||||
int
|
||||
arm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
|
||||
{
|
||||
rtx value = PATTERN (producer);
|
||||
rtx op = PATTERN (consumer);
|
||||
rtx value, op;
|
||||
rtx early_op;
|
||||
|
||||
if (GET_CODE (value) == COND_EXEC)
|
||||
value = COND_EXEC_CODE (value);
|
||||
if (GET_CODE (value) == PARALLEL)
|
||||
value = XVECEXP (value, 0, 0);
|
||||
value = XEXP (value, 0);
|
||||
if (GET_CODE (op) == COND_EXEC)
|
||||
op = COND_EXEC_CODE (op);
|
||||
if (GET_CODE (op) == PARALLEL)
|
||||
op = XVECEXP (op, 0, 0);
|
||||
op = XEXP (op, 1);
|
||||
if (!arm_get_set_operands (producer, consumer, &value, &op))
|
||||
return 0;
|
||||
|
||||
early_op = XEXP (op, 0);
|
||||
if ((early_op = arm_find_shift_sub_rtx (op)))
|
||||
/* We want to check the value being shifted. */
|
||||
if (!reg_overlap_mentioned_p (value, XEXP (early_op, 0)))
|
||||
return 1;
|
||||
|
||||
/* This is either an actual independent shift, or a shift applied to
|
||||
the first operand of another operation. We want the value being
|
||||
shifted, in either case. */
|
||||
if (!REG_P (early_op))
|
||||
early_op = XEXP (early_op, 0);
|
||||
|
||||
return !reg_overlap_mentioned_p (value, early_op);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return nonzero if the CONSUMER (a mul or mac op) does not
|
||||
have an early register mult dependency on the result of
|
||||
PRODUCER. */
|
||||
|
||||
int
|
||||
arm_no_early_mul_dep (rtx producer, rtx consumer)
|
||||
{
|
||||
rtx value = PATTERN (producer);
|
||||
rtx op = PATTERN (consumer);
|
||||
rtx value, op;
|
||||
|
||||
if (GET_CODE (value) == COND_EXEC)
|
||||
value = COND_EXEC_CODE (value);
|
||||
if (GET_CODE (value) == PARALLEL)
|
||||
value = XVECEXP (value, 0, 0);
|
||||
value = XEXP (value, 0);
|
||||
if (GET_CODE (op) == COND_EXEC)
|
||||
op = COND_EXEC_CODE (op);
|
||||
if (GET_CODE (op) == PARALLEL)
|
||||
op = XVECEXP (op, 0, 0);
|
||||
op = XEXP (op, 1);
|
||||
if (!arm_get_set_operands (producer, consumer, &value, &op))
|
||||
return 0;
|
||||
|
||||
if (GET_CODE (op) == PLUS || GET_CODE (op) == MINUS)
|
||||
{
|
||||
@ -162,19 +239,17 @@ arm_no_early_mul_dep (rtx producer, rtx consumer)
|
||||
int
|
||||
arm_no_early_store_addr_dep (rtx producer, rtx consumer)
|
||||
{
|
||||
rtx value = PATTERN (producer);
|
||||
rtx addr = PATTERN (consumer);
|
||||
rtx value = arm_find_sub_rtx_with_code (producer, SET, false);
|
||||
rtx addr = arm_find_sub_rtx_with_code (consumer, SET, false);
|
||||
|
||||
if (GET_CODE (value) == COND_EXEC)
|
||||
value = COND_EXEC_CODE (value);
|
||||
if (GET_CODE (value) == PARALLEL)
|
||||
value = XVECEXP (value, 0, 0);
|
||||
value = XEXP (value, 0);
|
||||
if (GET_CODE (addr) == COND_EXEC)
|
||||
addr = COND_EXEC_CODE (addr);
|
||||
if (GET_CODE (addr) == PARALLEL)
|
||||
addr = XVECEXP (addr, 0, 0);
|
||||
addr = XEXP (addr, 0);
|
||||
if (value)
|
||||
value = SET_DEST (value);
|
||||
|
||||
if (addr)
|
||||
addr = SET_DEST (addr);
|
||||
|
||||
if (!value || !addr)
|
||||
return 0;
|
||||
|
||||
return !reg_overlap_mentioned_p (value, addr);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user