This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH][RFC] Automatized pattern matching
- From: Zdenek Dvorak <rakdver at atrey dot karlin dot mff dot cuni dot cz>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sat, 7 Jun 2003 00:03:26 +0200
- Subject: [PATCH][RFC] Automatized pattern matching
Hello,
as someone mentioned on gcc summit, quite a lot of big conditions in gcc
is in fact a pattern matching on rtl expressions, that probably cannot
be expressed in a more clear way in c directly.
What we could however do is to use a language more suited to this task
to describe the patterns and to translate them into c automatically.
The patch below shows a simple implementation of this idea (for
technical details see comments in pattern.c); it for example allows you
to write
if (MATCH_RTX ("(const (plus $base const_int@1))", addr))
offset = INTVAL (_match1);
instead of (real piece of code from cse.c)
if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
&& GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
{
base = XEXP (XEXP (addr, 0), 0);
offset = INTVAL (XEXP (XEXP (addr, 0), 1));
}
which seems somewhat more readable to me. I have rewritten the
conditions in cse.c that seemed to be suitable for this (55 in total,
but there are some more that could be also done after simple extension
to pattern definition) to demonstrate the possibilities of usage.
Everything seems to work, gcc bootstraps happily. Of course there are
some technical details to be considered (some straightforward, like more
reasonable connection to build system and enabling patterns to be split
over several lines, some basically unsolvable like interaction with
other macros).
Comments?
Zdenek
* pattern.c: New.
* Makefile.in (STAGESTUFF): Add genpattern and match-*.h files.
(genpattern, match-cse.h): Add rules.
(cse.o): Add match-cse.h dependency.
(pattern.o): New.
* cse.c: Include match-cse.h.
(fixed_base_plus_p, address_cost, mention_regs, canon_hash,
cse_rtx_varies_p, find_best_addr, find_comparison_args, fold_rtx,
cse_insn, addr_affects_sp_p, invalidate_from_clobbers,
cse_around_loop, invalidate_skipped_set, cse_set_around_loop,
check_for_label_ref, count_reg_usage): Use generated patterns.
pattern.c:
/* Pattern matching utilities.
Copyright (C) 2002 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "tm.h"
#include "rtl.h"
#include "bitmap.h"
/* This program is used to generate conditions for pattern matching of rtl
expressions. Usage:
The source file foo.c where you want to use the feature must include
match-foo.h. The file is generated by this program; to ensure it, you must
add it to Makefile.in. Then whenever you need to do a pattern matching,
just use MATCH_RTX (pattern, expression); this macro expands to a condition
that performs the pattern matching, binds the defined variables and returns
whether match succeeded (if it does not, contents of used variables is
undefined; otherwise it is set according to the leftmost succesful match).
Whole usage of MATCH_RTX must fit to one line and at most one
MATCH_RTX per line is supported. '"' character may not occur inside pattern.
Exact (almost; for easier reading some conditions on it are only mentioned
in comments) grammar of pattern expressions is
pattern = expression | expression @ var
-- matches with the expression; in the later case,
var is bound to the
expression
-- handled by translate_pattern
expression = _ |
-- matches anything; @ var binding cannot be applied
in this case
-- anything that is not of 'e' type may currently be
matched only by _
{ alternatives } |
-- matches if any of alternatives does
[ string ] |
-- expression given by string is compared with the
matched expression using rtx_equal_p; in a special
cases [0], [1], ..., [9], temporary variables
_match[0-9] are used. ['s and ]'s in the string
must be balanced.
-- handled by translate_const_pattern
$var |
-- matches anything, var is bound to the expression
-- handled by translate_var_pattern
( rtx_match ) |
-- matches rtx expression
code
-- a shortcut for ( code )
alternatives = pattern | pattern '|' alternatives
-- handled by translate_alt_pattern
var = [0-9] | string
-- variables 0 - 9 are temporaries, they may be accessed
as _match[0-9]
-- string must be a valid c identifier and it is
interpreted as a variable name
rtx_match = code_match parameters
-- matches code of expression with code_match and
arguments with parameters; if there are less
parameters than appropriate for a code, the other
ones may have any values
-- handled by translate_expr_pattern
parameters = pattern | pattern parameters
code_match = [var] |
-- code must be equal to value of var. Temporary
variables are of course disjoint with rtx temporary
variables and are named _code[0-9]
codeset |
codeset @ var
-- code must belong to a codeset, in the later case
it is assigned to var
codeset = !code | code | { codes } | ! { codes } | {} | ! {}
codes = code | code codes
-- a code or list of codes in set, by their names
(in lowercase)
-- with !, complement of the set is taken
-- handled by translate_code_pattern
The technical realization is a bit tricky; we emit the macro
MATCH##line number for every occurence of MATCH_RTX that contains the
condition performing the pattern match. MATCH_RTX (P, X) itself expands to
MATCH ## __LINE__ (X) and further to the requiered condition.
*/
/* Characters that define a temporary variable. */
#define ANON_CHAR(X) ('0' <= (X) && (X) <= '9')
/* Valid characters in the variable names. */
#define IDENT_CHAR(X) (('a' <= (X) && (X) <= 'z') \
|| ('A' <= (X) && (X) <= 'Z') \
|| ('0' <= (X) && (X) <= '9') \
|| (X) == '_')
/* Names of the temporary rtx and rtx_code variables. */
const char *matchvars[10] =
{
"_match0", "_match1", "_match2", "_match3", "_match4",
"_match5", "_match6", "_match7", "_match8", "_match9"
};
const char *codevars[10] =
{
"_code0", "_code1", "_code2", "_code3", "_code4",
"_code5", "_code6", "_code7", "_code8", "_code9"
};
/* Expands names of temporary variables. */
#define MATCH_VAR_NAME(X) ANON_CHAR (*(X)) ? matchvars[*(X) - '0'] : (X)
#define CODE_VAR_NAME(X) ANON_CHAR (*(X)) ? codevars[*(X) - '0'] : (X)
/* The data structure to represent the pattern. The meaning of the fields
should be obvious (see description of grammar above). */
struct pattern
{
enum pattern_type
{
PATTERN_ANY,
PATTERN_CONST,
PATTERN_EXPR,
PATTERN_OR
} type;
char *variable;
union
{
struct data_const
{
char *cnst;
} data_const;
struct data_expr
{
int negate_code_alts;
char *code_variable;
bitmap code_alts;
int n_params;
struct pattern **params;
} data_expr;
struct data_or
{
int n_alts;
struct pattern **alts;
} data_or;
} data;
};
int main PARAMS ((int, char **));
static void print_pattern_condition PARAMS ((FILE *,
struct pattern *,
int, const char *));
static void print_code_condition PARAMS ((FILE *, int, char *,
bitmap, int,
const char *));
static struct pattern *translate_whole_pattern PARAMS ((char *));
static struct pattern *translate_pattern PARAMS ((char **));
static struct pattern *translate_expr_pattern PARAMS ((char **));
static struct pattern *translate_var_pattern PARAMS ((char **));
static struct pattern *translate_alt_pattern PARAMS ((char **));
static struct pattern *translate_const_pattern PARAMS ((char **));
static void translate_alias PARAMS ((char **,
struct pattern *));
static void translate_code_pattern PARAMS ((char **, int *,
bitmap *, char **));
static struct pattern *create_pattern_any PARAMS ((char *));
static struct pattern *create_pattern_const PARAMS ((char *));
static struct pattern *create_pattern_expr PARAMS ((int, bitmap, char *));
static struct pattern *create_pattern_alt PARAMS ((void));
static void add_param PARAMS ((struct pattern *,
struct pattern *));
static void add_alt PARAMS ((struct pattern *,
struct pattern *));
static void add_code PARAMS ((char *, bitmap, char *));
static void skip_whites PARAMS ((char **));
static char *cut_var_name PARAMS ((char **));
static void doindent PARAMS ((FILE *, int));
static void release_pattern PARAMS ((struct pattern *));
static void generate_match_macros PARAMS ((FILE *, FILE *));
static void report_error PARAMS ((const char *, char *));
/* Variables that define current position in the processed file (for error
messages. */
static char *file_name;
static char *macro_file;
static int line_number;
static char *line_start;
/* Reports an error described by MSG occuring at point WHERE on the current
line. */
static void
report_error (msg, where)
const char *msg;
char *where;
{
fprintf (stderr, "Error (%s) at %s:%d char %d (%s of expression %s)",
msg, file_name, line_number, where - line_start,
where, line_start);
unlink (macro_file);
abort ();
}
/* Generates a condition to match PATTERN with expression POSITION.
The condition is written to FILE indented by INDENT spaces. */
static void
print_pattern_condition (file, pattern, indent, position)
FILE *file;
struct pattern *pattern;
int indent;
const char *position;
{
int i;
if (pattern->variable)
{
fprintf (file, "((%s = %s) || 1) && ",
MATCH_VAR_NAME (pattern->variable), position);
position = MATCH_VAR_NAME (pattern->variable);
}
switch (pattern->type)
{
case PATTERN_ANY:
fprintf (file, "1");
break;
case PATTERN_CONST:
fprintf (file, "rtx_equal_p (%s, %s)",
MATCH_VAR_NAME (pattern->data.data_const.cnst), position);
break;
case PATTERN_OR:
fprintf (file, "(0");
for (i = 0; i < pattern->data.data_or.n_alts; i++)
{
fprintf (file, " \\\n");
doindent (file, indent + 5);
fprintf (file, "|| (");
print_pattern_condition (file,
pattern->data.data_or.alts[i],
indent + 8,
position);
fprintf (file, ")");
}
fprintf (file, " \\\n");
doindent (file, indent);
fprintf (file, ")");
break;
case PATTERN_EXPR:
print_code_condition (file,
pattern->data.data_expr.negate_code_alts,
pattern->data.data_expr.code_variable,
pattern->data.data_expr.code_alts,
indent, position);
for (i = 0; i < pattern->data.data_expr.n_params; i++)
{
char *new_position;
fprintf (file, " \\\n");
doindent (file, indent + 5);
fprintf (file, "&& ");
new_position = xmalloc (strlen (position) + 100);
sprintf (new_position, "XEXP (%s, %d)", position, i);
print_pattern_condition (file,
pattern->data.data_expr.params[i],
indent + 8,
new_position);
free (new_position);
}
break;
}
return;
}
/* Generates a condition to match set of codes ALTS (its complement if NEGATED)
against rtx code of expression POSITION. The result is stored into VARIABLE
if it is not NULL. The condition is written to FILE indented by INDENT
spaces. */
static void
print_code_condition (file, negated, variable, alts, indent, position)
FILE *file;
int negated;
char *variable;
bitmap alts;
int indent;
const char *position;
{
int code;
if (!alts)
{
fprintf (file, "%s == GET_CODE (%s)",
CODE_VAR_NAME (variable), position);
return;
}
if (variable)
fprintf (file, "((%s = GET_CODE (%s)) || 1) &&",
CODE_VAR_NAME (variable), position);
fprintf (file, negated ? "(1" : "(0");
EXECUTE_IF_SET_IN_BITMAP (alts, 0, code,
{
fprintf (file, " \\\n");
doindent (file, indent + 5);
fprintf (file, negated ? "&& " : "|| ");
fprintf (file, "GET_CODE (%s) %s %d /* %s */",
position, negated ? "!=" : "==",
code, GET_RTX_NAME (code));
});
fprintf (file, " \\\n");
doindent (file, indent);
fprintf (file, ")");
}
/* Outputs INDENT spaces to FILE. */
static void
doindent (file, indent)
FILE *file;
int indent;
{
while (indent--)
fprintf (file, " ");
}
/* Parses the PATTERN and returns its internal representation. */
static struct pattern *
translate_whole_pattern (pattern)
char *pattern;
{
struct pattern *ret = translate_pattern (&pattern);
skip_whites (&pattern);
if (*pattern)
report_error ("extra characters after end of pattern", pattern);
return ret;
}
/* Moves pointer to PATTERN over any spaces. */
static void
skip_whites (pattern)
char **pattern;
{
while (**pattern == ' ')
(*pattern)++;
}
/* Translates pattern case of the grammar, moving the pointer to PATTERN behind
it. */
static struct pattern *
translate_pattern (pattern)
char **pattern;
{
char *pos;
struct pattern *ret;
skip_whites (pattern);
pos = *pattern;
*pattern = pos + 1;
switch (*pos)
{
case '(':
ret = translate_expr_pattern (pattern);
break;
case '{':
ret = translate_alt_pattern (pattern);
break;
case '[':
ret = translate_const_pattern (pattern);
break;
case '_':
return create_pattern_any (NULL);
case '$':
return translate_var_pattern (pattern);
default:
*pattern = pos;
/* A special case for code being shortcut for (code) */
if (IDENT_CHAR (*pos))
{
int negate_alts; /* Of course always zero. */
bitmap code_alts;
char *variable; /* It will get detected as code variable if present.
Does not matter, we interpret it as match variable
instead. */
translate_code_pattern (pattern, &negate_alts, &code_alts, &variable);
ret = create_pattern_expr (negate_alts, code_alts, NULL);
ret->variable = variable;
return ret;
}
return NULL;
}
skip_whites (pattern);
if (**pattern == '@')
{
(*pattern)++;
translate_alias (pattern, ret);
}
return ret;
}
/* Translates expression case of the grammar, moving the pointer to PATTERN behind
it. */
static struct pattern *
translate_expr_pattern (pattern)
char **pattern;
{
int negate_alts;
bitmap code_alts;
char *code_variable;
struct pattern *ret, *param;
translate_code_pattern (pattern, &negate_alts, &code_alts, &code_variable);
ret = create_pattern_expr (negate_alts, code_alts, code_variable);
while ((param = translate_pattern (pattern)))
add_param (ret, param);
if (**pattern != ')')
report_error ("expecting end of pattern", *pattern);
(*pattern)++;
return ret;
}
/* Adds a pattern matching single parameter PARAM to the list of parameters
of rtl_match pattern TO. */
static void
add_param (to, param)
struct pattern *to;
struct pattern *param;
{
struct data_expr *tto = &to->data.data_expr;
tto->params = xrealloc (tto->params, sizeof (struct pattern *) * ++tto->n_params);
tto->params[tto->n_params - 1] = param;
}
/* Translates alt case of the grammar, moving the pointer to PATTERN behind
it. */
static struct pattern *
translate_alt_pattern (pattern)
char **pattern;
{
struct pattern *ret, *alt;
ret = create_pattern_alt ();
while (1)
{
alt = translate_pattern (pattern);
add_alt (ret, alt);
skip_whites (pattern);
if (**pattern == '}')
break;
if (**pattern != '|')
report_error ("expecting alternative", *pattern);
(*pattern)++;
}
(*pattern)++;
return ret;
}
/* Adds a pattern ALT to the list of alternatives of pattern TO. */
static void
add_alt (to, alt)
struct pattern *to;
struct pattern *alt;
{
struct data_or *tto = &to->data.data_or;
tto->alts = xrealloc (tto->alts, sizeof (struct pattern *) * ++tto->n_alts);
tto->alts[tto->n_alts - 1] = alt;
}
/* Translates const case of the grammar, moving the pointer to PATTERN behind
it. */
static struct pattern *
translate_const_pattern (pattern)
char **pattern;
{
int level = 1, l;
char *beg = *pattern;
char *end = beg;
char *ret;
while (level)
{
if (*end == '[')
level++;
if (*end == ']')
level--;
if (!*end)
report_error ("unclosed const pattern", *pattern);
end++;
}
l = end - beg;
ret = xmalloc (l);
memcpy (ret, beg, l - 1);
ret[l - 1] = 0;
*pattern = end;
return create_pattern_const (ret);
}
/* Cuts a variable name from pattern and moves pointer to PATTERN behind it.
The variable name is returned. */
static char *
cut_var_name (pattern)
char **pattern;
{
int l;
char *beg = *pattern;
char *end = beg;
char *ret;
if (ANON_CHAR (*beg))
end = beg + 1;
else if (IDENT_CHAR (*beg))
{
while (IDENT_CHAR (*end))
end++;
}
else report_error ("wrong variable name", *pattern);
l = end - beg;
ret = xmalloc (l + 1);
memcpy (ret, beg, l);
ret[l] = 0;
*pattern = end;
return ret;
}
/* Translates var case of the grammar, moving the pointer to PATTERN behind
it. */
static struct pattern *
translate_var_pattern (pattern)
char **pattern;
{
return create_pattern_any (cut_var_name (pattern));
}
/* Translates @ var part of pattern case of the grammar, moving the pointer
to PATTERN behind it. */
static void
translate_alias (pattern, tgt)
char **pattern;
struct pattern *tgt;
{
char *name = cut_var_name (pattern);
tgt->variable = name;
}
/* Adds a CODE parsed from PATTERN at the actual position to codeset TO. */
static void
add_code (pattern, to, code)
char *pattern;
bitmap to;
char *code;
{
int i;
for (i = 0; i < NUM_RTX_CODE; i++)
if (! strcmp (code, GET_RTX_NAME (i)))
break;
if (i == NUM_RTX_CODE)
report_error ("wrong rtl code", pattern);
bitmap_set_bit (to, i);
}
/* Translates code_match case of the grammar, moving the pointer
to PATTERN behind it. It returns set of alternatives for code in CODE_ALTS,
variable to that store it in VARIABLE (or NULL if none) and whether to
consider a complement of the set in NEGATE_ALTS.
If the code match is a comparison with code variable, NULL is returned in
CODE_ALTS and name of the variable in VARIABLE. */
static void
translate_code_pattern (pattern, negate_alts, code_alts, variable)
char **pattern;
int *negate_alts;
bitmap *code_alts;
char **variable;
{
bitmap ret;
char *code, *tmp;
skip_whites (pattern);
if (**pattern == '[')
{
(*pattern)++;
skip_whites (pattern);
*variable = cut_var_name (pattern);
skip_whites (pattern);
if (**pattern != ']')
report_error ("unclosed variable reference", *pattern);
(*pattern)++;
*code_alts = NULL;
return;
}
if (**pattern == '!')
{
(*pattern)++;
skip_whites (pattern);
*negate_alts = true;
}
else
*negate_alts = false;
ret = BITMAP_XMALLOC ();
if (**pattern == '{')
{
(*pattern)++;
skip_whites (pattern);
if (**pattern != '}')
{
while (1)
{
tmp = *pattern;
code = cut_var_name (pattern);
add_code (tmp, ret, code);
free (code);
skip_whites (pattern);
if (**pattern == '}')
break;
if (**pattern != '|')
report_error ("expecting alternative", *pattern);
(*pattern)++;
skip_whites (pattern);
}
}
(*pattern)++;
}
else
{
tmp = *pattern;
skip_whites (pattern);
code = cut_var_name (pattern);
add_code (tmp, ret, code);
free (code);
}
*code_alts = ret;
skip_whites (pattern);
if (**pattern == '@')
{
(*pattern)++;
skip_whites (pattern);
*variable = cut_var_name (pattern);
}
else
*variable = NULL;
}
/* Create pattern expression matching anything and storing it to VAR (if VAR is
not NULL. */
static struct pattern *
create_pattern_any (var)
char *var;
{
struct pattern *ret = xmalloc (sizeof (struct pattern));
ret->type = PATTERN_ANY;
ret->variable = var;
return ret;
}
/* Create pattern expression matching anything rtx_equal_p to VALUE. */
static struct pattern *
create_pattern_const (value)
char *value;
{
struct pattern *ret = xmalloc (sizeof (struct pattern));
ret->type = PATTERN_CONST;
ret->variable = NULL;
ret->data.data_const.cnst = value;
return ret;
}
/* Create pattern expression matching rtx with code matched by CODE_ALTS,
storing this code to CODE_VAR if not NULL. If NEGATE_ALTS is set,
a pattern for complement of the CODE_ALTS is taken. */
static struct pattern *
create_pattern_expr (negate_alts, code_alts, code_var)
int negate_alts;
bitmap code_alts;
char *code_var;
{
struct pattern *ret = xmalloc (sizeof (struct pattern));
ret->type = PATTERN_EXPR;
ret->variable = NULL;
ret->data.data_expr.negate_code_alts = negate_alts;
ret->data.data_expr.code_variable = code_var;
ret->data.data_expr.code_alts = code_alts;
ret->data.data_expr.n_params = 0;
ret->data.data_expr.params = NULL;
return ret;
}
/* Create pattern expression matching alternatives (that will be added
later). */
static struct pattern *
create_pattern_alt ()
{
struct pattern *ret = xmalloc (sizeof (struct pattern));
ret->type = PATTERN_OR;
ret->variable = NULL;
ret->data.data_or.n_alts = 0;
ret->data.data_or.alts = NULL;
return ret;
}
/* Releases a memory occupied by PATTERN. */
static void
release_pattern (pattern)
struct pattern *pattern;
{
int i;
if (pattern->variable)
free (pattern->variable);
switch (pattern->type)
{
case PATTERN_ANY:
break;
case PATTERN_CONST:
free (pattern->data.data_const.cnst);
break;
case PATTERN_EXPR:
if (pattern->data.data_expr.code_variable)
free (pattern->data.data_expr.code_variable);
if (pattern->data.data_expr.code_alts)
BITMAP_FREE (pattern->data.data_expr.code_alts);
for (i = 0; i < pattern->data.data_expr.n_params; i++)
release_pattern (pattern->data.data_expr.params[i]);
free (pattern->data.data_expr.params);
break;
case PATTERN_OR:
for (i = 0; i < pattern->data.data_or.n_alts; i++)
release_pattern (pattern->data.data_or.alts[i]);
free (pattern->data.data_or.alts);
break;
}
free (pattern);
}
/* Generate MATCH... macros for file SOURCE, storing them at MACROFILE. */
static void
generate_match_macros (source, macrofile)
FILE *source;
FILE *macrofile;
{
char *line = NULL, *match, *tmp;
int nl = 0;
size_t ll;
struct pattern *pattern;
for (; getline (&line, &ll, source) >= 0; free (line), line = NULL)
{
nl++;
match = strstr (line, "MATCH_RTX");
if (!match)
continue;
while (*match && *match != '\"')
match++;
if (*match != '\"')
continue;
match++;
tmp = match;
while (*tmp && *tmp != '\"')
tmp++;
if (*tmp != '\"')
continue;
*tmp = 0;
line_start = match;
line_number = nl;
pattern = translate_whole_pattern (match);
fprintf (macrofile, "#define MATCH%d(X) (_last_match = \\\n ", nl);
print_pattern_condition (macrofile, pattern, 4, "(X)");
release_pattern (pattern);
fprintf (macrofile, ")\n\n");
}
}
/* Processes the file ARGV[1], storing the result in file ARGV[2]. */
int
main (argc, argv)
int argc;
char **argv;
{
FILE *source, *macro;
int i;
if (argc != 3)
abort ();
file_name = argv[1];
source = fopen (argv[1], "r");
macro = fopen (argv[2], "w");
fprintf (macro, "/* Generated automatically by the program `genpattern'\n");
fprintf (macro, " from file `%s' */\n\n", file_name);
for (i = 0; i < 10; i++)
{
fprintf (macro, "static rtx %s ATTRIBUTE_UNUSED;\n", matchvars[i]);
fprintf (macro, "static enum rtx_code %s ATTRIBUTE_UNUSED;\n", codevars[i]);
}
fprintf (macro, "\n");
fprintf (macro, "/* We let this produce warning in case pattern matching is never used. */\n");
fprintf (macro, "static int _last_match;\n\n");
fprintf (macro, "#define CONCATX(A, B) A ## B\n");
fprintf (macro, "#define CONCAT(A, B) CONCATX (A, B) /* A trick to get __LINE__ expanded. */\n\n");
fprintf (macro, "#define MATCH_RTX(P, X) CONCAT (MATCH, __LINE__) (X)\n\n");
generate_match_macros (source, macro);
fclose (source);
fclose (macro);
return 0;
}
Index: Makefile.in
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/Makefile.in,v
retrieving revision 1.1070
diff -c -3 -p -r1.1070 Makefile.in
*** Makefile.in 6 Jun 2003 09:24:21 -0000 1.1070
--- Makefile.in 6 Jun 2003 21:27:49 -0000
*************** STAGESTUFF = *$(objext) insn-flags.h ins
*** 842,848 ****
genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c \
xgcc$(exeext) cpp$(exeext) cc1$(exeext) $(EXTRA_PASSES) \
$(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) cc1obj$(exeext) \
! protoize$(exeext) unprotoize$(exeext) \
$(SPECS) collect2$(exeext) $(USE_COLLECT2) \
gcov-iov$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \
*.[0-9][0-9].* *.[si] libcpp.a libbackend.a libgcc.mk \
--- 842,848 ----
genrtl.c genrtl.h gt-*.h gtype-*.h gtype-desc.c \
xgcc$(exeext) cpp$(exeext) cc1$(exeext) $(EXTRA_PASSES) \
$(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) cc1obj$(exeext) \
! protoize$(exeext) unprotoize$(exeext) match-*.h genpattern$(exeext) \
$(SPECS) collect2$(exeext) $(USE_COLLECT2) \
gcov-iov$(build_exeext) gcov$(exeext) gcov-dump$(exeext) \
*.[0-9][0-9].* *.[si] libcpp.a libbackend.a libgcc.mk \
*************** s-check : gencheck$(build_exeext) $(srcd
*** 1387,1392 ****
--- 1387,1400 ----
$(SHELL) $(srcdir)/move-if-change tmp-check.h tree-check.h
$(STAMP) s-check
+ genpattern$(build_exeext) : pattern.o $(BUILD_RTL) $(BUILD_SUPPORT) \
+ $(BUILD_ERRORS) $(BUILD_LIBDEPS)
+ $(BUILD_CC) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \
+ pattern.o $(BUILD_RTL) $(BUILD_SUPPORT) \
+ $(BUILD_ERRORS) $(BUILD_LIBS)
+ match-cse.h : cse.c genpattern$(build_exeext)
+ $(RUN_GEN) ./genpattern$(build_exeext) cse.c match-cse.h
+
gencheck$(build_exeext) : gencheck.o $(BUILD_LIBDEPS)
$(BUILD_CC) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \
gencheck.o $(BUILD_LIBS)
*************** cselib.o : cselib.c $(CONFIG_H) $(SYSTEM
*** 1604,1610 ****
cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \
output.h function.h $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \
! except.h $(TARGET_H) $(PARAMS_H)
gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
hard-reg-set.h flags.h real.h insn-config.h ggc.h $(RECOG_H) $(EXPR_H) \
$(BASIC_BLOCK_H) function.h output.h toplev.h $(TM_P_H) $(PARAMS_H) except.h gt-gcse.h
--- 1612,1618 ----
cse.o : cse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
hard-reg-set.h flags.h real.h insn-config.h $(RECOG_H) $(EXPR_H) toplev.h \
output.h function.h $(BASIC_BLOCK_H) $(GGC_H) $(TM_P_H) $(TIMEVAR_H) \
! except.h $(TARGET_H) $(PARAMS_H) match-cse.h
gcse.o : gcse.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
hard-reg-set.h flags.h real.h insn-config.h ggc.h $(RECOG_H) $(EXPR_H) \
$(BASIC_BLOCK_H) function.h output.h toplev.h $(TM_P_H) $(PARAMS_H) except.h gt-gcse.h
*************** df.o : df.c $(CONFIG_H) $(SYSTEM_H) core
*** 1629,1634 ****
--- 1637,1643 ----
$(BASIC_BLOCK_H) df.h $(FIBHEAP_H)
conflict.o : conflict.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(OBSTACK_H) \
$(HASHTAB_H) $(RTL_H) hard-reg-set.h $(BASIC_BLOCK_H)
+ pattern.o: pattern.c
profile.o : profile.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \
$(TREE_H) flags.h output.h $(REGS_H) $(EXPR_H) function.h \
toplev.h $(BASIC_BLOCK_H) $(COVERAGE_H)
Index: cse.c
===================================================================
RCS file: /cvsroot/gcc/gcc/gcc/cse.c,v
retrieving revision 1.264
diff -c -3 -p -r1.264 cse.c
*** cse.c 4 Jun 2003 21:05:20 -0000 1.264
--- cse.c 6 Jun 2003 21:27:50 -0000
*************** Software Foundation, 59 Temple Place - S
*** 43,48 ****
--- 43,49 ----
#include "except.h"
#include "target.h"
#include "params.h"
+ #include "match-cse.h"
/* The basic idea of common subexpression elimination is to go
through the code, keeping a record of expressions that would
*************** fixed_base_plus_p (x)
*** 680,688 ****
return false;
case PLUS:
! if (GET_CODE (XEXP (x, 1)) != CONST_INT)
return false;
! return fixed_base_plus_p (XEXP (x, 0));
case ADDRESSOF:
return true;
--- 681,689 ----
return false;
case PLUS:
! if (!MATCH_RTX ("(plus $0 const_int)", x))
return false;
! return fixed_base_plus_p (_match0);
case ADDRESSOF:
return true;
*************** address_cost (x, mode)
*** 902,908 ****
refers to the address of a REG is a good thing because we can then
turn (MEM (ADDRESSSOF (REG))) into just plain REG. */
! if (GET_CODE (x) == ADDRESSOF && REG_P (XEXP ((x), 0)))
return -1;
/* We may be asked for cost of various unusual addresses, such as operands
--- 903,909 ----
refers to the address of a REG is a good thing because we can then
turn (MEM (ADDRESSSOF (REG))) into just plain REG. */
! if (MATCH_RTX ("(addressof $0)", x) && REG_P (_match0))
return -1;
/* We may be asked for cost of various unusual addresses, such as operands
*************** mention_regs (x)
*** 1232,1250 ****
if (code == COMPARE || GET_RTX_CLASS (code) == '<')
{
! if (GET_CODE (XEXP (x, 0)) == REG
! && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
! if (insert_regs (XEXP (x, 0), NULL, 0))
{
! rehash_using_reg (XEXP (x, 0));
changed = 1;
}
! if (GET_CODE (XEXP (x, 1)) == REG
! && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
! if (insert_regs (XEXP (x, 1), NULL, 0))
{
! rehash_using_reg (XEXP (x, 1));
changed = 1;
}
}
--- 1233,1251 ----
if (code == COMPARE || GET_RTX_CLASS (code) == '<')
{
! if (MATCH_RTX ("(!{} reg@0)", x)
! && ! REGNO_QTY_VALID_P (REGNO (_match0)))
! if (insert_regs (_match0, NULL, 0))
{
! rehash_using_reg (_match0);
changed = 1;
}
! if (MATCH_RTX ("(!{} _ reg@1)", x)
! && ! REGNO_QTY_VALID_P (REGNO (_match1)))
! if (insert_regs (_match1, NULL, 0))
{
! rehash_using_reg (_match1);
changed = 1;
}
}
*************** canon_hash (x, mode)
*** 2378,2388 ****
handling since the MEM may be BLKmode which normally
prevents an entry from being made. Pure calls are
marked by a USE which mentions BLKmode memory. */
! if (GET_CODE (XEXP (x, 0)) == MEM
! && ! MEM_VOLATILE_P (XEXP (x, 0)))
{
hash += (unsigned) USE;
! x = XEXP (x, 0);
if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
hash_arg_in_memory = 1;
--- 2379,2389 ----
handling since the MEM may be BLKmode which normally
prevents an entry from being made. Pure calls are
marked by a USE which mentions BLKmode memory. */
! if (MATCH_RTX ("(use mem@0)", x)
! && ! MEM_VOLATILE_P (_match0))
{
hash += (unsigned) USE;
! x = _match0;
if (! RTX_UNCHANGING_P (x) || fixed_base_plus_p (XEXP (x, 0)))
hash_arg_in_memory = 1;
*************** cse_rtx_varies_p (x, from_alias)
*** 2729,2743 ****
return 0;
}
! if (GET_CODE (x) == PLUS
! && GET_CODE (XEXP (x, 1)) == CONST_INT
! && GET_CODE (XEXP (x, 0)) == REG
! && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
{
! int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
struct qty_table_elem *x0_ent = &qty_table[x0_q];
! if ((GET_MODE (XEXP (x, 0)) == x0_ent->mode)
&& x0_ent->const_rtx != NULL_RTX)
return 0;
}
--- 2730,2742 ----
return 0;
}
! if (MATCH_RTX ("(plus reg@0 const_int)", x)
! && REGNO_QTY_VALID_P (REGNO (_match0)))
{
! int x0_q = REG_QTY (REGNO (_match0));
struct qty_table_elem *x0_ent = &qty_table[x0_q];
! if ((GET_MODE (_match0) == x0_ent->mode)
&& x0_ent->const_rtx != NULL_RTX)
return 0;
}
*************** cse_rtx_varies_p (x, from_alias)
*** 2747,2766 ****
us a three instruction sequence, load large offset into a register,
load fp minus a constant into a register, then a MEM which is the
sum of the two `constant' registers. */
! if (GET_CODE (x) == PLUS
! && GET_CODE (XEXP (x, 0)) == REG
! && GET_CODE (XEXP (x, 1)) == REG
! && REGNO_QTY_VALID_P (REGNO (XEXP (x, 0)))
! && REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
{
! int x0_q = REG_QTY (REGNO (XEXP (x, 0)));
! int x1_q = REG_QTY (REGNO (XEXP (x, 1)));
struct qty_table_elem *x0_ent = &qty_table[x0_q];
struct qty_table_elem *x1_ent = &qty_table[x1_q];
! if ((GET_MODE (XEXP (x, 0)) == x0_ent->mode)
&& x0_ent->const_rtx != NULL_RTX
! && (GET_MODE (XEXP (x, 1)) == x1_ent->mode)
&& x1_ent->const_rtx != NULL_RTX)
return 0;
}
--- 2746,2763 ----
us a three instruction sequence, load large offset into a register,
load fp minus a constant into a register, then a MEM which is the
sum of the two `constant' registers. */
! if (MATCH_RTX ("(plus reg@0 reg@1)", x)
! && REGNO_QTY_VALID_P (REGNO (_match0))
! && REGNO_QTY_VALID_P (REGNO (_match1)))
{
! int x0_q = REG_QTY (REGNO (_match0));
! int x1_q = REG_QTY (REGNO (_match1));
struct qty_table_elem *x0_ent = &qty_table[x0_q];
struct qty_table_elem *x1_ent = &qty_table[x1_q];
! if ((GET_MODE (_match0) == x0_ent->mode)
&& x0_ent->const_rtx != NULL_RTX
! && (GET_MODE (_match1) == x1_ent->mode)
&& x1_ent->const_rtx != NULL_RTX)
return 0;
}
*************** find_best_addr (insn, loc, mode)
*** 2885,2891 ****
enum machine_mode mode;
{
struct table_elt *elt;
! rtx addr = *loc;
struct table_elt *p;
int found_better = 1;
int save_do_not_record = do_not_record;
--- 2882,2888 ----
enum machine_mode mode;
{
struct table_elt *elt;
! rtx addr = *loc, op1 = NULL_RTX;
struct table_elt *p;
int found_better = 1;
int save_do_not_record = do_not_record;
*************** find_best_addr (insn, loc, mode)
*** 2903,2919 ****
for some reason, but we cannot take advantage of that because we have
no easy way to unshare the MEM. In addition, looking up all stack
addresses is costly. */
! if ((GET_CODE (addr) == PLUS
! && GET_CODE (XEXP (addr, 0)) == REG
! && GET_CODE (XEXP (addr, 1)) == CONST_INT
! && (regno = REGNO (XEXP (addr, 0)),
! regno == FRAME_POINTER_REGNUM || regno == HARD_FRAME_POINTER_REGNUM
! || regno == ARG_POINTER_REGNUM))
! || (GET_CODE (addr) == REG
! && (regno = REGNO (addr), regno == FRAME_POINTER_REGNUM
|| regno == HARD_FRAME_POINTER_REGNUM
|| regno == ARG_POINTER_REGNUM))
! || GET_CODE (addr) == ADDRESSOF
|| CONSTANT_ADDRESS_P (addr))
return;
--- 2900,2910 ----
for some reason, but we cannot take advantage of that because we have
no easy way to unshare the MEM. In addition, looking up all stack
addresses is costly. */
! if ((MATCH_RTX ("{(plus reg@0 const_int) | reg@0}", addr)
! && (regno = REGNO (_match0), regno == FRAME_POINTER_REGNUM
|| regno == HARD_FRAME_POINTER_REGNUM
|| regno == ARG_POINTER_REGNUM))
! || MATCH_RTX ("addressof", addr)
|| CONSTANT_ADDRESS_P (addr))
return;
*************** find_best_addr (insn, loc, mode)
*** 3009,3024 ****
if (flag_expensive_optimizations
&& (GET_RTX_CLASS (GET_CODE (*loc)) == '2'
|| GET_RTX_CLASS (GET_CODE (*loc)) == 'c')
! && GET_CODE (XEXP (*loc, 0)) == REG)
{
- rtx op1 = XEXP (*loc, 1);
-
do_not_record = 0;
! hash = HASH (XEXP (*loc, 0), Pmode);
do_not_record = save_do_not_record;
hash_arg_in_memory = save_hash_arg_in_memory;
! elt = lookup (XEXP (*loc, 0), hash, Pmode);
if (elt == 0)
return;
--- 3000,3013 ----
if (flag_expensive_optimizations
&& (GET_RTX_CLASS (GET_CODE (*loc)) == '2'
|| GET_RTX_CLASS (GET_CODE (*loc)) == 'c')
! && MATCH_RTX ("(!{} reg@0 $op1)", *loc))
{
do_not_record = 0;
! hash = HASH (_match0, Pmode);
do_not_record = save_do_not_record;
hash_arg_in_memory = save_hash_arg_in_memory;
! elt = lookup (_match0, hash, Pmode);
if (elt == 0)
return;
*************** find_comparison_args (code, parg1, parg2
*** 3268,3274 ****
}
else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
code = GET_CODE (x);
! arg1 = XEXP (x, 0), arg2 = XEXP (x, 1);
}
/* Return our results. Return the modes from before fold_rtx
--- 3257,3263 ----
}
else if (GET_RTX_CLASS (GET_CODE (x)) == '<')
code = GET_CODE (x);
! MATCH_RTX ("(!{} $arg1 $arg2)", x);
}
/* Return our results. Return the modes from before fold_rtx
*************** fold_rtx (x, insn)
*** 3447,3474 ****
for (; elt; elt = elt->next_same_value)
{
enum rtx_code eltcode = GET_CODE (elt->exp);
/* Just check for unary and binary operations. */
! if (GET_RTX_CLASS (GET_CODE (elt->exp)) == '1'
! && GET_CODE (elt->exp) != SIGN_EXTEND
! && GET_CODE (elt->exp) != ZERO_EXTEND
! && GET_CODE (XEXP (elt->exp, 0)) == SUBREG
! && GET_MODE (SUBREG_REG (XEXP (elt->exp, 0))) == mode
&& (GET_MODE_CLASS (mode)
! == GET_MODE_CLASS (GET_MODE (XEXP (elt->exp, 0)))))
{
- rtx op0 = SUBREG_REG (XEXP (elt->exp, 0));
-
if (GET_CODE (op0) != REG && ! CONSTANT_P (op0))
op0 = fold_rtx (op0, NULL_RTX);
op0 = equiv_constant (op0);
if (op0)
! new = simplify_unary_operation (GET_CODE (elt->exp), mode,
! op0, mode);
}
! else if ((GET_RTX_CLASS (GET_CODE (elt->exp)) == '2'
! || GET_RTX_CLASS (GET_CODE (elt->exp)) == 'c')
&& eltcode != DIV && eltcode != MOD
&& eltcode != UDIV && eltcode != UMOD
&& eltcode != ASHIFTRT && eltcode != LSHIFTRT
--- 3436,3459 ----
for (; elt; elt = elt->next_same_value)
{
enum rtx_code eltcode = GET_CODE (elt->exp);
+ rtx op0 = NULL_RTX, op1;
/* Just check for unary and binary operations. */
! if (GET_RTX_CLASS (eltcode) == '1'
! && MATCH_RTX ("(!{zero_extend | sign_extend} (subreg $op0)@1)", elt->exp)
! && GET_MODE (op0) == mode
&& (GET_MODE_CLASS (mode)
! == GET_MODE_CLASS (GET_MODE (_match1))))
{
if (GET_CODE (op0) != REG && ! CONSTANT_P (op0))
op0 = fold_rtx (op0, NULL_RTX);
op0 = equiv_constant (op0);
if (op0)
! new = simplify_unary_operation (eltcode, mode, op0, mode);
}
! else if ((GET_RTX_CLASS (eltcode) == '2'
! || GET_RTX_CLASS (eltcode) == 'c')
&& eltcode != DIV && eltcode != MOD
&& eltcode != UDIV && eltcode != UMOD
&& eltcode != ASHIFTRT && eltcode != LSHIFTRT
*************** fold_rtx (x, insn)
*** 3482,3489 ****
== mode))
|| CONSTANT_P (XEXP (elt->exp, 1))))
{
! rtx op0 = gen_lowpart_common (mode, XEXP (elt->exp, 0));
! rtx op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1));
if (op0 && GET_CODE (op0) != REG && ! CONSTANT_P (op0))
op0 = fold_rtx (op0, NULL_RTX);
--- 3467,3474 ----
== mode))
|| CONSTANT_P (XEXP (elt->exp, 1))))
{
! op0 = gen_lowpart_common (mode, XEXP (elt->exp, 0));
! op1 = gen_lowpart_common (mode, XEXP (elt->exp, 1));
if (op0 && GET_CODE (op0) != REG && ! CONSTANT_P (op0))
op0 = fold_rtx (op0, NULL_RTX);
*************** fold_rtx (x, insn)
*** 3523,3534 ****
op0, op1);
}
! else if (GET_CODE (elt->exp) == SUBREG
! && GET_MODE (SUBREG_REG (elt->exp)) == mode
&& (GET_MODE_SIZE (GET_MODE (folded_arg0))
<= UNITS_PER_WORD)
&& exp_equiv_p (elt->exp, elt->exp, 1, 0))
! new = copy_rtx (SUBREG_REG (elt->exp));
if (new)
return new;
--- 3508,3519 ----
op0, op1);
}
! else if (MATCH_RTX ("(subreg $op0)", elt->exp)
! && GET_MODE (op0) == mode
&& (GET_MODE_SIZE (GET_MODE (folded_arg0))
<= UNITS_PER_WORD)
&& exp_equiv_p (elt->exp, elt->exp, 1, 0))
! new = copy_rtx (op0);
if (new)
return new;
*************** fold_rtx (x, insn)
*** 3557,3563 ****
/* Even if we don't fold in the insn itself,
we can safely do so here, in hopes of getting a constant. */
rtx addr = fold_rtx (XEXP (x, 0), NULL_RTX);
! rtx base = 0;
HOST_WIDE_INT offset = 0;
if (GET_CODE (addr) == REG
--- 3542,3548 ----
/* Even if we don't fold in the insn itself,
we can safely do so here, in hopes of getting a constant. */
rtx addr = fold_rtx (XEXP (x, 0), NULL_RTX);
! rtx base = NULL_RTX, label = NULL_RTX;
HOST_WIDE_INT offset = 0;
if (GET_CODE (addr) == REG
*************** fold_rtx (x, insn)
*** 3572,3590 ****
}
/* If address is constant, split it into a base and integer offset. */
! if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
base = addr;
! else if (GET_CODE (addr) == CONST && GET_CODE (XEXP (addr, 0)) == PLUS
! && GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
! {
! base = XEXP (XEXP (addr, 0), 0);
! offset = INTVAL (XEXP (XEXP (addr, 0), 1));
! }
! else if (GET_CODE (addr) == LO_SUM
! && GET_CODE (XEXP (addr, 1)) == SYMBOL_REF)
! base = XEXP (addr, 1);
! else if (GET_CODE (addr) == ADDRESSOF)
return change_address (x, VOIDmode, addr);
/* If this is a constant pool reference, we can fold it into its
constant to allow better value tracking. */
--- 3557,3572 ----
}
/* If address is constant, split it into a base and integer offset. */
! if (MATCH_RTX ("({symbol_ref | label_ref})", addr))
base = addr;
! else if (MATCH_RTX ("(const (plus $base const_int@1))", addr))
! offset = INTVAL (_match1);
! else if (MATCH_RTX ("(lo_sum _ symbol_ref@base)", addr))
! ;
! else if (MATCH_RTX ("addressof", addr))
return change_address (x, VOIDmode, addr);
+ else
+ base = NULL_RTX;
/* If this is a constant pool reference, we can fold it into its
constant to allow better value tracking. */
*************** fold_rtx (x, insn)
*** 3627,3635 ****
/* If this is a reference to a label at a known position in a jump
table, we also know its value. */
! if (base && GET_CODE (base) == LABEL_REF)
{
- rtx label = XEXP (base, 0);
rtx table_insn = NEXT_INSN (label);
if (table_insn && GET_CODE (table_insn) == JUMP_INSN
--- 3609,3616 ----
/* If this is a reference to a label at a known position in a jump
table, we also know its value. */
! if (base && MATCH_RTX ("(label_ref $label)", base))
{
rtx table_insn = NEXT_INSN (label);
if (table_insn && GET_CODE (table_insn) == JUMP_INSN
*************** fold_rtx (x, insn)
*** 4097,4113 ****
= GET_CODE (folded_arg0) == MINUS ? folded_arg0
: lookup_as_function (folded_arg0, MINUS);
! if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
! && XEXP (XEXP (y, 1), 0) == XEXP (const_arg1, 0))
! return XEXP (y, 0);
/* Now try for a CONST of a MINUS like the above. */
if ((y = (GET_CODE (folded_arg0) == CONST ? folded_arg0
: lookup_as_function (folded_arg0, CONST))) != 0
! && GET_CODE (XEXP (y, 0)) == MINUS
! && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
! && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg1, 0))
! return XEXP (XEXP (y, 0), 0);
}
/* Likewise if the operands are in the other order. */
--- 4078,4094 ----
= GET_CODE (folded_arg0) == MINUS ? folded_arg0
: lookup_as_function (folded_arg0, MINUS);
! if (y != 0
! && MATCH_RTX ("(!{} $0 (label_ref $1))", y)
! && _match1 == XEXP (const_arg1, 0))
! return _match0;
/* Now try for a CONST of a MINUS like the above. */
if ((y = (GET_CODE (folded_arg0) == CONST ? folded_arg0
: lookup_as_function (folded_arg0, CONST))) != 0
! && MATCH_RTX ("(!{} (minus $0 (label_ref $1)))", y)
! && _match1 == XEXP (const_arg1, 0))
! return _match0;
}
/* Likewise if the operands are in the other order. */
*************** fold_rtx (x, insn)
*** 4117,4133 ****
= GET_CODE (folded_arg1) == MINUS ? folded_arg1
: lookup_as_function (folded_arg1, MINUS);
! if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
! && XEXP (XEXP (y, 1), 0) == XEXP (const_arg0, 0))
! return XEXP (y, 0);
/* Now try for a CONST of a MINUS like the above. */
if ((y = (GET_CODE (folded_arg1) == CONST ? folded_arg1
: lookup_as_function (folded_arg1, CONST))) != 0
! && GET_CODE (XEXP (y, 0)) == MINUS
! && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
! && XEXP (XEXP (XEXP (y, 0), 1), 0) == XEXP (const_arg0, 0))
! return XEXP (XEXP (y, 0), 0);
}
/* If second operand is a register equivalent to a negative
--- 4098,4114 ----
= GET_CODE (folded_arg1) == MINUS ? folded_arg1
: lookup_as_function (folded_arg1, MINUS);
! if (y != 0
! && MATCH_RTX ("(!{} $0 (label_ref $1))", y)
! && _match1 == XEXP (const_arg0, 0))
! return _match0;
/* Now try for a CONST of a MINUS like the above. */
if ((y = (GET_CODE (folded_arg1) == CONST ? folded_arg1
: lookup_as_function (folded_arg1, CONST))) != 0
! && MATCH_RTX ("(!{} (minus $0 (label_ref $1)))", y)
! && _match1 == XEXP (const_arg0, 0))
! return _match0;
}
/* If second operand is a register equivalent to a negative
*************** fold_rtx (x, insn)
*** 4172,4178 ****
if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT)
{
rtx y = lookup_as_function (XEXP (x, 0), PLUS);
! if (y && GET_CODE (XEXP (y, 1)) == CONST_INT)
return fold_rtx (plus_constant (copy_rtx (y),
-INTVAL (const_arg1)),
NULL_RTX);
--- 4153,4159 ----
if (const_arg1 != 0 && GET_CODE (const_arg1) == CONST_INT)
{
rtx y = lookup_as_function (XEXP (x, 0), PLUS);
! if (y && MATCH_RTX ("(!{} _ const_int)", y))
return fold_rtx (plus_constant (copy_rtx (y),
-INTVAL (const_arg1)),
NULL_RTX);
*************** fold_rtx (x, insn)
*** 4291,4298 ****
case 'o':
/* (lo_sum (high X) X) is simply X. */
if (code == LO_SUM && const_arg0 != 0
! && GET_CODE (const_arg0) == HIGH
! && rtx_equal_p (XEXP (const_arg0, 0), const_arg1))
return const_arg1;
break;
--- 4272,4278 ----
case 'o':
/* (lo_sum (high X) X) is simply X. */
if (code == LO_SUM && const_arg0 != 0
! && MATCH_RTX ("(high [const_arg1])", const_arg0))
return const_arg1;
break;
*************** cse_insn (insn, libcall_insn)
*** 4761,4768 ****
{
for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
{
! if (GET_CODE (XEXP (tem, 0)) == CLOBBER)
! invalidate (SET_DEST (XEXP (tem, 0)), VOIDmode);
XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
}
}
--- 4741,4748 ----
{
for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
{
! if (MATCH_RTX ("(!{} clobber@0)", tem))
! invalidate (SET_DEST (_match0), VOIDmode);
XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
}
}
*************** cse_insn (insn, libcall_insn)
*** 4824,4835 ****
{
rtx clobbered = XEXP (y, 0);
! if (GET_CODE (clobbered) == REG
! || GET_CODE (clobbered) == SUBREG)
invalidate (clobbered, VOIDmode);
! else if (GET_CODE (clobbered) == STRICT_LOW_PART
! || GET_CODE (clobbered) == ZERO_EXTRACT)
! invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
}
}
--- 4804,4813 ----
{
rtx clobbered = XEXP (y, 0);
! if (MATCH_RTX ("({reg | subreg})", clobbered))
invalidate (clobbered, VOIDmode);
! else if (MATCH_RTX ("({strict_low_part | zero_extract} $0)", clobbered))
! invalidate (_match0, GET_MODE (clobbered));
}
}
*************** cse_insn (insn, libcall_insn)
*** 4858,4865 ****
/* If we clobber memory, canon the address.
This does nothing when a register is clobbered
because we have already invalidated the reg. */
! if (GET_CODE (XEXP (y, 0)) == MEM)
! canon_reg (XEXP (y, 0), NULL_RTX);
}
else if (GET_CODE (y) == USE
&& ! (GET_CODE (XEXP (y, 0)) == REG
--- 4836,4843 ----
/* If we clobber memory, canon the address.
This does nothing when a register is clobbered
because we have already invalidated the reg. */
! if (MATCH_RTX ("(clobber mem@0)", y))
! canon_reg (_match0, NULL_RTX);
}
else if (GET_CODE (y) == USE
&& ! (GET_CODE (XEXP (y, 0)) == REG
*************** cse_insn (insn, libcall_insn)
*** 4877,4884 ****
}
else if (GET_CODE (x) == CLOBBER)
{
! if (GET_CODE (XEXP (x, 0)) == MEM)
! canon_reg (XEXP (x, 0), NULL_RTX);
}
/* Canonicalize a USE of a pseudo register or memory location. */
--- 4855,4862 ----
}
else if (GET_CODE (x) == CLOBBER)
{
! if (MATCH_RTX ("(clobber mem@0)", x))
! canon_reg (_match0, NULL_RTX);
}
/* Canonicalize a USE of a pseudo register or memory location. */
*************** cse_insn (insn, libcall_insn)
*** 4934,4945 ****
else
SET_SRC (sets[i].rtl) = new;
! if (GET_CODE (dest) == ZERO_EXTRACT || GET_CODE (dest) == SIGN_EXTRACT)
{
validate_change (insn, &XEXP (dest, 1),
! canon_reg (XEXP (dest, 1), insn), 1);
validate_change (insn, &XEXP (dest, 2),
! canon_reg (XEXP (dest, 2), insn), 1);
}
while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
--- 4912,4923 ----
else
SET_SRC (sets[i].rtl) = new;
! if (MATCH_RTX ("({zero_extract | sign_extract} _ $1 $2)", dest))
{
validate_change (insn, &XEXP (dest, 1),
! canon_reg (_match1, insn), 1);
validate_change (insn, &XEXP (dest, 2),
! canon_reg (_match2, insn), 1);
}
while (GET_CODE (dest) == SUBREG || GET_CODE (dest) == STRICT_LOW_PART
*************** cse_insn (insn, libcall_insn)
*** 5005,5012 ****
if (src_eqv)
{
enum machine_mode eqvmode = mode;
! if (GET_CODE (dest) == STRICT_LOW_PART)
! eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
do_not_record = 0;
hash_arg_in_memory = 0;
src_eqv_hash = HASH (src_eqv, eqvmode);
--- 4983,4990 ----
if (src_eqv)
{
enum machine_mode eqvmode = mode;
! if (MATCH_RTX ("(strict_low_part (subreg $0))", dest))
! eqvmode = GET_MODE (_match0);
do_not_record = 0;
hash_arg_in_memory = 0;
src_eqv_hash = HASH (src_eqv, eqvmode);
*************** cse_insn (insn, libcall_insn)
*** 5150,5158 ****
/* Consider (minus (label_ref L1) (label_ref L2)) as
"constant" here so we will record it. This allows us
to fold switch statements when an ADDR_DIFF_VEC is used. */
! || (GET_CODE (src_folded) == MINUS
! && GET_CODE (XEXP (src_folded, 0)) == LABEL_REF
! && GET_CODE (XEXP (src_folded, 1)) == LABEL_REF)))
src_const = src_folded, src_const_elt = elt;
else if (src_const == 0 && src_eqv_here && CONSTANT_P (src_eqv_here))
src_const = src_eqv_here, src_const_elt = src_eqv_elt;
--- 5128,5134 ----
/* Consider (minus (label_ref L1) (label_ref L2)) as
"constant" here so we will record it. This allows us
to fold switch statements when an ADDR_DIFF_VEC is used. */
! || MATCH_RTX ("(minus label_ref label_ref)", src_folded)))
src_const = src_folded, src_const_elt = elt;
else if (src_const == 0 && src_eqv_here && CONSTANT_P (src_eqv_here))
src_const = src_eqv_here, src_const_elt = src_eqv_elt;
*************** cse_insn (insn, libcall_insn)
*** 5243,5259 ****
value. */
if (flag_expensive_optimizations && ! src_related
! && GET_CODE (src) == AND && GET_CODE (XEXP (src, 1)) == CONST_INT
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
{
enum machine_mode tmode;
! rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
for (tmode = GET_MODE_WIDER_MODE (mode);
GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
tmode = GET_MODE_WIDER_MODE (tmode))
{
! rtx inner = gen_lowpart_if_possible (tmode, XEXP (src, 0));
struct table_elt *larger_elt;
if (inner)
--- 5219,5235 ----
value. */
if (flag_expensive_optimizations && ! src_related
! && MATCH_RTX ("(and $0 const_int@1)", src)
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
{
enum machine_mode tmode;
! rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, _match1);
for (tmode = GET_MODE_WIDER_MODE (mode);
GET_MODE_SIZE (tmode) <= UNITS_PER_WORD;
tmode = GET_MODE_WIDER_MODE (tmode))
{
! rtx inner = gen_lowpart_if_possible (tmode, _match0);
struct table_elt *larger_elt;
if (inner)
*************** cse_insn (insn, libcall_insn)
*** 5567,5579 ****
/* Reject cases that will abort in decode_rtx_const.
On the alpha when simplifying a switch, we get
(const (truncate (minus (label_ref) (label_ref)))). */
! && ! (GET_CODE (trial) == CONST
! && GET_CODE (XEXP (trial, 0)) == TRUNCATE)
! /* Likewise on IA-64, except without the truncate. */
! && ! (GET_CODE (trial) == CONST
! && GET_CODE (XEXP (trial, 0)) == MINUS
! && GET_CODE (XEXP (XEXP (trial, 0), 0)) == LABEL_REF
! && GET_CODE (XEXP (XEXP (trial, 0), 1)) == LABEL_REF)
&& (src_folded == 0
|| (GET_CODE (src_folded) != MEM
&& ! src_folded_force_flag))
--- 5543,5550 ----
/* Reject cases that will abort in decode_rtx_const.
On the alpha when simplifying a switch, we get
(const (truncate (minus (label_ref) (label_ref)))). */
! && !MATCH_RTX ("(const truncate)", trial)
! && !MATCH_RTX ("(const (minus label_ref label_ref))", trial)
&& (src_folded == 0
|| (GET_CODE (src_folded) != MEM
&& ! src_folded_force_flag))
*************** cse_insn (insn, libcall_insn)
*** 5659,5669 ****
entry in a jump table. */
if (n_sets == 1 && src_const && GET_CODE (dest) == REG
! && GET_CODE (src_const) != REG
! && ! (GET_CODE (src_const) == CONST
! && GET_CODE (XEXP (src_const, 0)) == MINUS
! && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
! && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF))
{
/* We only want a REG_EQUAL note if src_const != src. */
if (! rtx_equal_p (src, src_const))
--- 5630,5637 ----
entry in a jump table. */
if (n_sets == 1 && src_const && GET_CODE (dest) == REG
! && ! MATCH_RTX ("reg", src_const)
! && ! MATCH_RTX ("(const (minus label_ref label_ref))", src_const))
{
/* We only want a REG_EQUAL note if src_const != src. */
if (! rtx_equal_p (src, src_const))
*************** cse_insn (insn, libcall_insn)
*** 5840,5848 ****
if (! libcall_insn || insn == libcall_insn)
invalidate (dest, VOIDmode);
}
! else if (GET_CODE (dest) == STRICT_LOW_PART
! || GET_CODE (dest) == ZERO_EXTRACT)
! invalidate (XEXP (dest, 0), GET_MODE (dest));
sets[i].rtl = 0;
}
--- 5808,5815 ----
if (! libcall_insn || insn == libcall_insn)
invalidate (dest, VOIDmode);
}
! else if (MATCH_RTX ("({strict_low_part | zero_extract} $0)", dest))
! invalidate (_match0, GET_MODE (dest));
sets[i].rtl = 0;
}
*************** cse_insn (insn, libcall_insn)
*** 6003,6011 ****
if (! libcall_insn || insn == libcall_insn)
invalidate (dest, VOIDmode);
}
! else if (GET_CODE (dest) == STRICT_LOW_PART
! || GET_CODE (dest) == ZERO_EXTRACT)
! invalidate (XEXP (dest, 0), GET_MODE (dest));
}
/* A volatile ASM invalidates everything. */
--- 5970,5977 ----
if (! libcall_insn || insn == libcall_insn)
invalidate (dest, VOIDmode);
}
! else if (MATCH_RTX ("({strict_low_part | zero_extract} $0)", dest))
! invalidate (_match0, GET_MODE (dest));
}
/* A volatile ASM invalidates everything. */
*************** cse_insn (insn, libcall_insn)
*** 6125,6134 ****
/* STRICT_LOW_PART isn't part of the value BEING set,
and neither is the SUBREG inside it.
Note that in this case SETS[I].SRC_ELT is really SRC_EQV_ELT. */
! if (GET_CODE (dest) == STRICT_LOW_PART)
! dest = SUBREG_REG (XEXP (dest, 0));
! if (GET_CODE (dest) == REG || GET_CODE (dest) == SUBREG)
/* Registers must also be inserted into chains for quantities. */
if (insert_regs (dest, sets[i].src_elt, 1))
{
--- 6091,6100 ----
/* STRICT_LOW_PART isn't part of the value BEING set,
and neither is the SUBREG inside it.
Note that in this case SETS[I].SRC_ELT is really SRC_EQV_ELT. */
! if (MATCH_RTX ("(strict_low_part (subreg $0))", dest))
! dest = _match0;
! if (MATCH_RTX ("({reg | subreg})", dest))
/* Registers must also be inserted into chains for quantities. */
if (insert_regs (dest, sets[i].src_elt, 1))
{
*************** cse_insn (insn, libcall_insn)
*** 6138,6145 ****
sets[i].dest_hash = HASH (dest, GET_MODE (dest));
}
! if (GET_CODE (inner_dest) == MEM
! && GET_CODE (XEXP (inner_dest, 0)) == ADDRESSOF)
/* Given (SET (MEM (ADDRESSOF (X))) Y) we don't want to say
that (MEM (ADDRESSOF (X))) is equivalent to Y.
Consider the case in which the address of the MEM is
--- 6104,6110 ----
sets[i].dest_hash = HASH (dest, GET_MODE (dest));
}
! if (MATCH_RTX ("(mem addressof)", inner_dest))
/* Given (SET (MEM (ADDRESSOF (X))) Y) we don't want to say
that (MEM (ADDRESSOF (X))) is equivalent to Y.
Consider the case in which the address of the MEM is
*************** addr_affects_sp_p (addr)
*** 6392,6399 ****
rtx addr;
{
if (GET_RTX_CLASS (GET_CODE (addr)) == 'a'
! && GET_CODE (XEXP (addr, 0)) == REG
! && REGNO (XEXP (addr, 0)) == STACK_POINTER_REGNUM)
{
if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
{
--- 6357,6364 ----
rtx addr;
{
if (GET_RTX_CLASS (GET_CODE (addr)) == 'a'
! && MATCH_RTX ("(!{} reg@0)", addr)
! && REGNO (_match0) == STACK_POINTER_REGNUM)
{
if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
{
*************** invalidate_from_clobbers (x)
*** 6428,6439 ****
rtx ref = XEXP (x, 0);
if (ref)
{
! if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
! || GET_CODE (ref) == MEM)
invalidate (ref, VOIDmode);
! else if (GET_CODE (ref) == STRICT_LOW_PART
! || GET_CODE (ref) == ZERO_EXTRACT)
! invalidate (XEXP (ref, 0), GET_MODE (ref));
}
}
else if (GET_CODE (x) == PARALLEL)
--- 6393,6402 ----
rtx ref = XEXP (x, 0);
if (ref)
{
! if (MATCH_RTX ("({reg | subreg | mem})", ref))
invalidate (ref, VOIDmode);
! else if (MATCH_RTX ("({strict_low_part | zero_extract} $0)", ref))
! invalidate (_match0, GET_MODE (ref));
}
}
else if (GET_CODE (x) == PARALLEL)
*************** invalidate_from_clobbers (x)
*** 6445,6456 ****
if (GET_CODE (y) == CLOBBER)
{
rtx ref = XEXP (y, 0);
! if (GET_CODE (ref) == REG || GET_CODE (ref) == SUBREG
! || GET_CODE (ref) == MEM)
invalidate (ref, VOIDmode);
! else if (GET_CODE (ref) == STRICT_LOW_PART
! || GET_CODE (ref) == ZERO_EXTRACT)
! invalidate (XEXP (ref, 0), GET_MODE (ref));
}
}
}
--- 6408,6417 ----
if (GET_CODE (y) == CLOBBER)
{
rtx ref = XEXP (y, 0);
! if (MATCH_RTX ("({reg | subreg | mem})", ref))
invalidate (ref, VOIDmode);
! else if (MATCH_RTX ("({strict_low_part | zero_extract} $0)", ref))
! invalidate (_match0, GET_MODE (ref));
}
}
}
*************** cse_around_loop (loop_start)
*** 6587,6599 ****
for (p = last_jump_equiv_class->first_same_value; p;
p = p->next_same_value)
{
! if (GET_CODE (p->exp) == MEM || GET_CODE (p->exp) == REG
! || (GET_CODE (p->exp) == SUBREG
! && GET_CODE (SUBREG_REG (p->exp)) == REG))
invalidate (p->exp, VOIDmode);
! else if (GET_CODE (p->exp) == STRICT_LOW_PART
! || GET_CODE (p->exp) == ZERO_EXTRACT)
! invalidate (XEXP (p->exp, 0), GET_MODE (p->exp));
}
/* Process insns starting after LOOP_START until we hit a CALL_INSN or
--- 6548,6557 ----
for (p = last_jump_equiv_class->first_same_value; p;
p = p->next_same_value)
{
! if (MATCH_RTX ("{({reg | mem}) | (subreg reg)}", p->exp))
invalidate (p->exp, VOIDmode);
! else if (MATCH_RTX ("({strict_low_part | zero_extract} $0)", p->exp))
! invalidate (_match0, GET_MODE (p->exp));
}
/* Process insns starting after LOOP_START until we hit a CALL_INSN or
*************** invalidate_skipped_set (dest, set, data)
*** 6658,6667 ****
|| dest == pc_rtx)
return;
! if (code == STRICT_LOW_PART || code == ZERO_EXTRACT)
! invalidate (XEXP (dest, 0), GET_MODE (dest));
! else if (code == REG || code == SUBREG || code == MEM)
invalidate (dest, VOIDmode);
}
/* Invalidate all insns from START up to the end of the function or the
--- 6616,6625 ----
|| dest == pc_rtx)
return;
! if (MATCH_RTX ("({reg | subreg | mem})", dest))
invalidate (dest, VOIDmode);
+ else if (MATCH_RTX ("({strict_low_part | zero_extract} $0)", dest))
+ invalidate (_match0, GET_MODE (dest));
}
/* Invalidate all insns from START up to the end of the function or the
*************** cse_set_around_loop (x, insn, loop_start
*** 6818,6829 ****
/* See comment on similar code in cse_insn for explanation of these
tests. */
! if (GET_CODE (SET_DEST (x)) == REG || GET_CODE (SET_DEST (x)) == SUBREG
! || GET_CODE (SET_DEST (x)) == MEM)
invalidate (SET_DEST (x), VOIDmode);
! else if (GET_CODE (SET_DEST (x)) == STRICT_LOW_PART
! || GET_CODE (SET_DEST (x)) == ZERO_EXTRACT)
! invalidate (XEXP (SET_DEST (x), 0), GET_MODE (SET_DEST (x)));
}
/* Find the end of INSN's basic block and return its range,
--- 6776,6785 ----
/* See comment on similar code in cse_insn for explanation of these
tests. */
! if (MATCH_RTX ("({reg | subreg | mem})", SET_DEST (x)))
invalidate (SET_DEST (x), VOIDmode);
! else if (MATCH_RTX ("({strict_low_part | zero_extract} $0)", SET_DEST (x)))
! invalidate (_match0, GET_MODE (SET_DEST (x)));
}
/* Find the end of INSN's basic block and return its range,
*************** check_for_label_ref (rtl, data)
*** 7439,7449 ****
we must rerun jump since it needs to place the note. If this is a
LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
since no REG_LABEL will be added. */
! return (GET_CODE (*rtl) == LABEL_REF
&& ! LABEL_REF_NONLOCAL_P (*rtl)
! && LABEL_P (XEXP (*rtl, 0))
! && INSN_UID (XEXP (*rtl, 0)) != 0
! && ! find_reg_note (insn, REG_LABEL, XEXP (*rtl, 0)));
}
/* Count the number of times registers are used (not set) in X.
--- 7395,7405 ----
we must rerun jump since it needs to place the note. If this is a
LABEL_REF for a CODE_LABEL that isn't in the insn chain, don't do this
since no REG_LABEL will be added. */
! return (MATCH_RTX ("(label_ref $0)", *rtl)
&& ! LABEL_REF_NONLOCAL_P (*rtl)
! && LABEL_P (_match0)
! && INSN_UID (_match0) != 0
! && ! find_reg_note (insn, REG_LABEL, _match0));
}
/* Count the number of times registers are used (not set) in X.
*************** count_reg_usage (x, counts, dest, incr)
*** 7489,7496 ****
case CLOBBER:
/* If we are clobbering a MEM, mark any registers inside the address
as being used. */
! if (GET_CODE (XEXP (x, 0)) == MEM)
! count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
return;
case SET:
--- 7445,7452 ----
case CLOBBER:
/* If we are clobbering a MEM, mark any registers inside the address
as being used. */
! if (MATCH_RTX ("(clobber (mem $0))", x))
! count_reg_usage (_match0, counts, NULL_RTX, incr);
return;
case SET: