mirror of git://gcc.gnu.org/git/gcc.git
genattrtab.c (attr_rtx_cost): Move earlier, start with cost being 1.
* genattrtab.c (attr_rtx_cost): Move earlier, start with cost being 1. (simplify_test_exp): Handle one more case of distributive law, decrease cost threshold. (tests_attr_p, get_attr_order): New functions. (optimize_attrs): Use topological order, inline only cheap values. (write_attr_set): Reset our_known_true after some time. From-SVN: r187714
This commit is contained in:
parent
30ee9dbf3d
commit
fb639843e4
|
@ -1,3 +1,12 @@
|
||||||
|
2012-05-21 Michael Matz <matz@suse.de>
|
||||||
|
|
||||||
|
* genattrtab.c (attr_rtx_cost): Move earlier, start with cost being 1.
|
||||||
|
(simplify_test_exp): Handle one more case of distributive law,
|
||||||
|
decrease cost threshold.
|
||||||
|
(tests_attr_p, get_attr_order): New functions.
|
||||||
|
(optimize_attrs): Use topological order, inline only cheap values.
|
||||||
|
(write_attr_set): Reset our_known_true after some time.
|
||||||
|
|
||||||
2012-05-21 H.J. Lu <hongjiu.lu@intel.com>
|
2012-05-21 H.J. Lu <hongjiu.lu@intel.com>
|
||||||
|
|
||||||
PR target/53425
|
PR target/53425
|
||||||
|
|
296
gcc/genattrtab.c
296
gcc/genattrtab.c
|
@ -116,6 +116,8 @@ along with GCC; see the file COPYING3. If not see
|
||||||
#include "vecprim.h"
|
#include "vecprim.h"
|
||||||
#include "fnmatch.h"
|
#include "fnmatch.h"
|
||||||
|
|
||||||
|
#define DEBUG 0
|
||||||
|
|
||||||
/* Flags for make_internal_attr's `special' parameter. */
|
/* Flags for make_internal_attr's `special' parameter. */
|
||||||
#define ATTR_NONE 0
|
#define ATTR_NONE 0
|
||||||
#define ATTR_SPECIAL (1 << 0)
|
#define ATTR_SPECIAL (1 << 0)
|
||||||
|
@ -1654,6 +1656,57 @@ write_length_unit_log (FILE *outf)
|
||||||
fprintf (outf, "EXPORTED_CONST int length_unit_log = %u;\n", length_unit_log);
|
fprintf (outf, "EXPORTED_CONST int length_unit_log = %u;\n", length_unit_log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Compute approximate cost of the expression. Used to decide whether
|
||||||
|
expression is cheap enough for inline. */
|
||||||
|
static int
|
||||||
|
attr_rtx_cost (rtx x)
|
||||||
|
{
|
||||||
|
int cost = 1;
|
||||||
|
enum rtx_code code;
|
||||||
|
if (!x)
|
||||||
|
return 0;
|
||||||
|
code = GET_CODE (x);
|
||||||
|
switch (code)
|
||||||
|
{
|
||||||
|
case MATCH_OPERAND:
|
||||||
|
if (XSTR (x, 1)[0])
|
||||||
|
return 10;
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case EQ_ATTR_ALT:
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
case EQ_ATTR:
|
||||||
|
/* Alternatives don't result into function call. */
|
||||||
|
if (!strcmp_check (XSTR (x, 0), alternative_name))
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 5;
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
const char *fmt = GET_RTX_FORMAT (code);
|
||||||
|
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
switch (fmt[i])
|
||||||
|
{
|
||||||
|
case 'V':
|
||||||
|
case 'E':
|
||||||
|
for (j = 0; j < XVECLEN (x, i); j++)
|
||||||
|
cost += attr_rtx_cost (XVECEXP (x, i, j));
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
cost += attr_rtx_cost (XEXP (x, i));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
/* Take a COND expression and see if any of the conditions in it can be
|
/* Take a COND expression and see if any of the conditions in it can be
|
||||||
simplified. If any are known true or known false for the particular insn
|
simplified. If any are known true or known false for the particular insn
|
||||||
code, the COND can be further simplified.
|
code, the COND can be further simplified.
|
||||||
|
@ -2280,57 +2333,6 @@ simplify_or_tree (rtx exp, rtx *pterm, int insn_code, int insn_index)
|
||||||
return exp;
|
return exp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute approximate cost of the expression. Used to decide whether
|
|
||||||
expression is cheap enough for inline. */
|
|
||||||
static int
|
|
||||||
attr_rtx_cost (rtx x)
|
|
||||||
{
|
|
||||||
int cost = 0;
|
|
||||||
enum rtx_code code;
|
|
||||||
if (!x)
|
|
||||||
return 0;
|
|
||||||
code = GET_CODE (x);
|
|
||||||
switch (code)
|
|
||||||
{
|
|
||||||
case MATCH_OPERAND:
|
|
||||||
if (XSTR (x, 1)[0])
|
|
||||||
return 10;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case EQ_ATTR_ALT:
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case EQ_ATTR:
|
|
||||||
/* Alternatives don't result into function call. */
|
|
||||||
if (!strcmp_check (XSTR (x, 0), alternative_name))
|
|
||||||
return 0;
|
|
||||||
else
|
|
||||||
return 5;
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
int i, j;
|
|
||||||
const char *fmt = GET_RTX_FORMAT (code);
|
|
||||||
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
switch (fmt[i])
|
|
||||||
{
|
|
||||||
case 'V':
|
|
||||||
case 'E':
|
|
||||||
for (j = 0; j < XVECLEN (x, i); j++)
|
|
||||||
cost += attr_rtx_cost (XVECEXP (x, i, j));
|
|
||||||
break;
|
|
||||||
case 'e':
|
|
||||||
cost += attr_rtx_cost (XEXP (x, i));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return cost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Simplify test expression and use temporary obstack in order to avoid
|
/* Simplify test expression and use temporary obstack in order to avoid
|
||||||
memory bloat. Use ATTR_IND_SIMPLIFIED to avoid unnecessary simplifications
|
memory bloat. Use ATTR_IND_SIMPLIFIED to avoid unnecessary simplifications
|
||||||
and avoid unnecessary copying if possible. */
|
and avoid unnecessary copying if possible. */
|
||||||
|
@ -2663,6 +2665,25 @@ simplify_test_exp (rtx exp, int insn_code, int insn_index)
|
||||||
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
|
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Similarly,
|
||||||
|
convert (ior (and (y) (x))
|
||||||
|
(and (z) (x)))
|
||||||
|
to (and (ior (y) (z))
|
||||||
|
(x))
|
||||||
|
Note that we want the common term to stay at the end.
|
||||||
|
*/
|
||||||
|
|
||||||
|
else if (GET_CODE (left) == AND && GET_CODE (right) == AND
|
||||||
|
&& attr_equal_p (XEXP (left, 1), XEXP (right, 1)))
|
||||||
|
{
|
||||||
|
newexp = attr_rtx (IOR, XEXP (left, 0), XEXP (right, 0));
|
||||||
|
|
||||||
|
left = newexp;
|
||||||
|
right = XEXP (right, 1);
|
||||||
|
newexp = attr_rtx (AND, left, right);
|
||||||
|
return SIMPLIFY_TEST_EXP (newexp, insn_code, insn_index);
|
||||||
|
}
|
||||||
|
|
||||||
/* See if all or all but one of the insn's alternatives are specified
|
/* See if all or all but one of the insn's alternatives are specified
|
||||||
in this tree. Optimize if so. */
|
in this tree. Optimize if so. */
|
||||||
|
|
||||||
|
@ -2798,7 +2819,7 @@ simplify_test_exp (rtx exp, int insn_code, int insn_index)
|
||||||
x = evaluate_eq_attr (exp, attr, av->value,
|
x = evaluate_eq_attr (exp, attr, av->value,
|
||||||
insn_code, insn_index);
|
insn_code, insn_index);
|
||||||
x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
|
x = SIMPLIFY_TEST_EXP (x, insn_code, insn_index);
|
||||||
if (attr_rtx_cost(x) < 20)
|
if (attr_rtx_cost(x) < 7)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2818,6 +2839,133 @@ simplify_test_exp (rtx exp, int insn_code, int insn_index)
|
||||||
return newexp;
|
return newexp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return 1 if any EQ_ATTR subexpression of P refers to ATTR,
|
||||||
|
otherwise return 0. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
tests_attr_p (rtx p, struct attr_desc *attr)
|
||||||
|
{
|
||||||
|
const char *fmt;
|
||||||
|
int i, ie, j, je;
|
||||||
|
|
||||||
|
if (GET_CODE (p) == EQ_ATTR)
|
||||||
|
{
|
||||||
|
if (XSTR (p, 0) != attr->name)
|
||||||
|
return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt = GET_RTX_FORMAT (GET_CODE (p));
|
||||||
|
ie = GET_RTX_LENGTH (GET_CODE (p));
|
||||||
|
for (i = 0; i < ie; i++)
|
||||||
|
{
|
||||||
|
switch (*fmt++)
|
||||||
|
{
|
||||||
|
case 'e':
|
||||||
|
if (tests_attr_p (XEXP (p, i), attr))
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
je = XVECLEN (p, i);
|
||||||
|
for (j = 0; j < je; ++j)
|
||||||
|
if (tests_attr_p (XVECEXP (p, i, j), attr))
|
||||||
|
return 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate a topological sorting of all attributes so that
|
||||||
|
all attributes only depend on attributes in front of it.
|
||||||
|
Place the result in *RET (which is a pointer to an array of
|
||||||
|
attr_desc pointers), and return the size of that array. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_attr_order (struct attr_desc ***ret)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
int num = 0;
|
||||||
|
struct attr_desc *attr;
|
||||||
|
struct attr_desc **all, **sorted;
|
||||||
|
char *handled;
|
||||||
|
for (i = 0; i < MAX_ATTRS_INDEX; i++)
|
||||||
|
for (attr = attrs[i]; attr; attr = attr->next)
|
||||||
|
num++;
|
||||||
|
all = XNEWVEC (struct attr_desc *, num);
|
||||||
|
sorted = XNEWVEC (struct attr_desc *, num);
|
||||||
|
handled = XCNEWVEC (char, num);
|
||||||
|
num = 0;
|
||||||
|
for (i = 0; i < MAX_ATTRS_INDEX; i++)
|
||||||
|
for (attr = attrs[i]; attr; attr = attr->next)
|
||||||
|
all[num++] = attr;
|
||||||
|
|
||||||
|
j = 0;
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
if (all[i]->is_const)
|
||||||
|
handled[i] = 1, sorted[j++] = all[i];
|
||||||
|
|
||||||
|
/* We have only few attributes hence we can live with the inner
|
||||||
|
loop being O(n^2), unlike the normal fast variants of topological
|
||||||
|
sorting. */
|
||||||
|
while (j < num)
|
||||||
|
{
|
||||||
|
for (i = 0; i < num; i++)
|
||||||
|
if (!handled[i])
|
||||||
|
{
|
||||||
|
/* Let's see if I depends on anything interesting. */
|
||||||
|
int k;
|
||||||
|
for (k = 0; k < num; k++)
|
||||||
|
if (!handled[k])
|
||||||
|
{
|
||||||
|
struct attr_value *av;
|
||||||
|
for (av = all[i]->first_value; av; av = av->next)
|
||||||
|
if (av->num_insns != 0)
|
||||||
|
if (tests_attr_p (av->value, all[k]))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (av)
|
||||||
|
/* Something in I depends on K. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (k == num)
|
||||||
|
{
|
||||||
|
/* Nothing in I depended on anything intersting, so
|
||||||
|
it's done. */
|
||||||
|
handled[i] = 1;
|
||||||
|
sorted[j++] = all[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (DEBUG)
|
||||||
|
for (j = 0; j < num; j++)
|
||||||
|
{
|
||||||
|
struct attr_desc *attr2;
|
||||||
|
struct attr_value *av;
|
||||||
|
|
||||||
|
attr = sorted[j];
|
||||||
|
fprintf (stderr, "%s depends on: ", attr->name);
|
||||||
|
for (i = 0; i < MAX_ATTRS_INDEX; ++i)
|
||||||
|
for (attr2 = attrs[i]; attr2; attr2 = attr2->next)
|
||||||
|
if (!attr2->is_const)
|
||||||
|
for (av = attr->first_value; av; av = av->next)
|
||||||
|
if (av->num_insns != 0)
|
||||||
|
if (tests_attr_p (av->value, attr2))
|
||||||
|
{
|
||||||
|
fprintf (stderr, "%s, ", attr2->name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fprintf (stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
free (all);
|
||||||
|
*ret = sorted;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
/* Optimize the attribute lists by seeing if we can determine conditional
|
/* Optimize the attribute lists by seeing if we can determine conditional
|
||||||
values from the known values of other attributes. This will save subroutine
|
values from the known values of other attributes. This will save subroutine
|
||||||
calls during the compilation. */
|
calls during the compilation. */
|
||||||
|
@ -2832,6 +2980,8 @@ optimize_attrs (void)
|
||||||
int i;
|
int i;
|
||||||
struct attr_value_list *ivbuf;
|
struct attr_value_list *ivbuf;
|
||||||
struct attr_value_list *iv;
|
struct attr_value_list *iv;
|
||||||
|
struct attr_desc **topsort;
|
||||||
|
int topnum;
|
||||||
|
|
||||||
/* For each insn code, make a list of all the insn_ent's for it,
|
/* For each insn code, make a list of all the insn_ent's for it,
|
||||||
for all values for all attributes. */
|
for all values for all attributes. */
|
||||||
|
@ -2847,18 +2997,22 @@ optimize_attrs (void)
|
||||||
|
|
||||||
iv = ivbuf = XNEWVEC (struct attr_value_list, num_insn_ents);
|
iv = ivbuf = XNEWVEC (struct attr_value_list, num_insn_ents);
|
||||||
|
|
||||||
for (i = 0; i < MAX_ATTRS_INDEX; i++)
|
/* Create the chain of insn*attr values such that we see dependend
|
||||||
for (attr = attrs[i]; attr; attr = attr->next)
|
attributes after their dependencies. As we use a stack via the
|
||||||
for (av = attr->first_value; av; av = av->next)
|
next pointers start from the end of the topological order. */
|
||||||
for (ie = av->first_insn; ie; ie = ie->next)
|
topnum = get_attr_order (&topsort);
|
||||||
{
|
for (i = topnum - 1; i >= 0; i--)
|
||||||
iv->attr = attr;
|
for (av = topsort[i]->first_value; av; av = av->next)
|
||||||
iv->av = av;
|
for (ie = av->first_insn; ie; ie = ie->next)
|
||||||
iv->ie = ie;
|
{
|
||||||
iv->next = insn_code_values[ie->def->insn_code];
|
iv->attr = topsort[i];
|
||||||
insn_code_values[ie->def->insn_code] = iv;
|
iv->av = av;
|
||||||
iv++;
|
iv->ie = ie;
|
||||||
}
|
iv->next = insn_code_values[ie->def->insn_code];
|
||||||
|
insn_code_values[ie->def->insn_code] = iv;
|
||||||
|
iv++;
|
||||||
|
}
|
||||||
|
free (topsort);
|
||||||
|
|
||||||
/* Sanity check on num_insn_ents. */
|
/* Sanity check on num_insn_ents. */
|
||||||
gcc_assert (iv == ivbuf + num_insn_ents);
|
gcc_assert (iv == ivbuf + num_insn_ents);
|
||||||
|
@ -2893,7 +3047,15 @@ optimize_attrs (void)
|
||||||
}
|
}
|
||||||
|
|
||||||
rtl_obstack = old;
|
rtl_obstack = old;
|
||||||
if (newexp != av->value)
|
/* If we created a new value for this instruction, and it's
|
||||||
|
cheaper than the old value, and overall cheap, use that
|
||||||
|
one as specific value for the current instruction.
|
||||||
|
The last test is to avoid exploding the get_attr_ function
|
||||||
|
sizes for no much gain. */
|
||||||
|
if (newexp != av->value
|
||||||
|
&& attr_rtx_cost (newexp) < attr_rtx_cost (av->value)
|
||||||
|
&& attr_rtx_cost (newexp) < 26
|
||||||
|
)
|
||||||
{
|
{
|
||||||
newexp = attr_copy_rtx (newexp);
|
newexp = attr_copy_rtx (newexp);
|
||||||
remove_insn_ent (av, ie);
|
remove_insn_ent (av, ie);
|
||||||
|
@ -3998,6 +4160,10 @@ write_attr_set (FILE *outf, struct attr_desc *attr, int indent, rtx value,
|
||||||
rtx testexp;
|
rtx testexp;
|
||||||
rtx inner_true;
|
rtx inner_true;
|
||||||
|
|
||||||
|
/* Reset our_known_true after some time to not accumulate
|
||||||
|
too much cruft (slowing down genattrtab). */
|
||||||
|
if ((i & 31) == 0)
|
||||||
|
our_known_true = known_true;
|
||||||
testexp = eliminate_known_true (our_known_true,
|
testexp = eliminate_known_true (our_known_true,
|
||||||
XVECEXP (value, 0, i),
|
XVECEXP (value, 0, i),
|
||||||
insn_code, insn_index);
|
insn_code, insn_index);
|
||||||
|
|
Loading…
Reference in New Issue