[PATCH][RFC] Automatized pattern matching

Zdenek Dvorak rakdver@atrey.karlin.mff.cuni.cz
Sat Jun 7 11:09:00 GMT 2003


Hello.

Here is the patch after implementing some of your ideas

-- * for !{}
-- _match and _code variables are now local
-- / predicate / feature implemented a bit more generally, so
   you can use almost arbitrary expression as predicate. Not really sure
   whether it is a good idea;

   MATCH_RTX ("(* reg@0/!REGNO_QTY_VALID_P (REGNO (_loc))/)

   does look a bit confusing. On the other hand

   MATCH_RTX ("(subreg $op0/mode == GET_MODE/)", elt->exp)

   seems cool to me.

and cleaning up the coding style issues.

Zdenek

/* Pattern matching utilities.
   Copyright (C) 2003 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 = vexpression | vexpression / predicate /
			-- if predicate is supplied (any text that does not
			   contain a /), value matched by vexpression is bound
			   to _loc variable and predicate is requiered to be
			   true.  If predicate does not contain ( character,
			   the location is passed to it as argument instead
   pexpression = expression | expression @ var 
			-- matches with the expression; in the later case,
			   var is bound to the expression
			-- handled by translate_pattern
   expression = _ |
			-- matches anything
			-- anything that is not of 'e' type may currently be
			   matched only by _ without @ or / parts
		{ 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
			-- * means any code
			-- 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;
  char *predicate;
  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 (int, char **);
static void print_pattern_condition (FILE *, struct pattern *, int,
				     const char *);
static void print_code_condition (FILE *, int, char *, bitmap, int,
				  const char *);
static struct pattern *translate_whole_pattern (char *);
static struct pattern *translate_pattern (char **);
static struct pattern *translate_expr_pattern (char **);
static struct pattern *translate_var_pattern (char **);
static struct pattern *translate_alt_pattern (char **);
static struct pattern *translate_const_pattern (char **);
static void translate_alias (char **, struct pattern *);
static void translate_predicate (char **, struct pattern *);
static void translate_code_pattern (char **, int *, bitmap *, char **);
static struct pattern *create_pattern_any (char *);
static struct pattern *create_pattern_const (char *);
static struct pattern *create_pattern_expr (int, bitmap, char *);
static struct pattern *create_pattern_alt (void);
static void add_param (struct pattern *, struct pattern *);
static void add_alt (struct pattern *, struct pattern *);
static void add_code (char *, bitmap, char *);
static void skip_whites (char **);
static char *cut_var_name (char **);
static void doindent (FILE *, int);
static void release_pattern (struct pattern *);
static void generate_match_macros (FILE *, FILE *);
static void report_error (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 (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 *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;
    }

  if (pattern->predicate)
    {
      fprintf (file, " \\\n");
      doindent (file, indent);
      if (strchr (pattern->predicate, '('))
	{
	  fprintf (file, "&& ((_loc = %s) || 1) \\\n", position);
	  doindent (file, indent);
	  fprintf (file, "&& (%s)", pattern->predicate);
	}
      else
	fprintf (file, "&& %s (%s)", pattern->predicate, position);
    }
}

/* 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 *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 *file, int indent)
{
  while (indent--)
    fprintf (file, " ");
}

/* Parses the PATTERN and returns its internal representation.  */
static struct pattern *
translate_whole_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 (char **pattern)
{
  while (**pattern == ' ')
    (*pattern)++;
}

/* Translates pattern case of the grammar, moving the pointer to PATTERN behind
   it.  */
static struct pattern *
translate_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 '_':
      ret = create_pattern_any (NULL);
      break;

    case '$':
      ret = translate_var_pattern (pattern);
      break;

    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;
	  break;
	}
      return NULL;
    }
  
  skip_whites (pattern);
  if (**pattern == '@')
    {
      (*pattern)++;
      translate_alias (pattern, ret);
    }

  skip_whites (pattern);
  if (**pattern == '/')
    {
      (*pattern)++;
      translate_predicate (pattern, ret);
    }

  return ret;
}

/* Translates expression case of the grammar, moving the pointer to PATTERN behind
   it.  */
static struct pattern *
translate_expr_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 (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 (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 (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 (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", beg);
      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 (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 (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 and storing var name in TGT.  */
static void
translate_alias (char **pattern, struct pattern *tgt)
{
  char *name = cut_var_name (pattern);
  tgt->variable = name;
}

/* Translates / predicate / part of pattern case of the grammar, moving
   the pointer to PATTERN behind it and storing the predicate in TGT.  */
static void
translate_predicate (char **pattern, struct pattern *tgt)
{
  int l;
  char *beg = *pattern;
  char *end = beg;
  char *predicate;

  while (*end != '/')
    {
      if (!*end)
	report_error ("unclosed predicate", beg);
      end++;
    }

  l = end - beg + 1;
  predicate = xmalloc (l);
  memcpy (predicate, beg, l - 1);
  predicate[l - 1] = 0;

  tgt->predicate = predicate;
  *pattern = end + 1;
}

/* Adds a CODE parsed from PATTERN at the actual position to codeset TO.  */
static void
add_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 (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 if (**pattern == '*')
    {
      *negate_alts = !*negate_alts;
      (*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 (char *var)
{
  struct pattern *ret = xmalloc (sizeof (struct pattern));

  ret->type = PATTERN_ANY;
  ret->variable = var;
  ret->predicate = NULL;

  return ret;
}

/* Create pattern expression matching anything rtx_equal_p to VALUE.  */
static struct pattern *
create_pattern_const (char *value)
{
  struct pattern *ret = xmalloc (sizeof (struct pattern));

  ret->type = PATTERN_CONST;
  ret->variable = NULL;
  ret->predicate = 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 (int negate_alts, bitmap code_alts, char *code_var)
{
  struct pattern *ret = xmalloc (sizeof (struct pattern));

  ret->type = PATTERN_EXPR;
  ret->variable = NULL;
  ret->predicate = 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->predicate = 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 (struct pattern *pattern)
{
  int i;

  if (pattern->variable)
    free (pattern->variable);
  if (pattern->predicate)
    free (pattern->predicate);

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

  fprintf (macro, "#define USES_PATTERN_MATCHING \\\n");
  for (i = 0; i < 10; i++)
    {
      fprintf (macro, "  rtx %s ATTRIBUTE_UNUSED; \\\n", matchvars[i]);
      fprintf (macro, "  enum rtx_code %s ATTRIBUTE_UNUSED; \\\n", codevars[i]);
    }
  fprintf (macro, "\\\n");
  fprintf (macro, "  rtx _loc ATTRIBUTE_UNUSED; \\\n");
  fprintf (macro, "  /* We let this produce warning in case pattern matching is never used.  */ \\\n");
  fprintf (macro, "  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: cse.c
===================================================================
RCS file: /cvs/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	7 Jun 2003 11:00:29 -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
*************** static bool
*** 667,672 ****
--- 668,675 ----
  fixed_base_plus_p (x)
       rtx x;
  {
+   USES_PATTERN_MATCHING;
+ 
    switch (GET_CODE (x))
      {
      case REG:
*************** 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;
--- 683,689 ----
        return false;
  
      case PLUS:
!       return MATCH_RTX ("(plus _/fixed_base_plus_p/ const_int)", x);
  
      case ADDRESSOF:
        return true;
*************** address_cost (x, mode)
*** 897,908 ****
       rtx x;
       enum machine_mode mode;
  {
    /* The address_cost target hook does not deal with ADDRESSOF nodes.  But,
       during CSE, such nodes are present.  Using an ADDRESSOF node which
       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
--- 898,910 ----
       rtx x;
       enum machine_mode mode;
  {
+   USES_PATTERN_MATCHING;
    /* The address_cost target hook does not deal with ADDRESSOF nodes.  But,
       during CSE, such nodes are present.  Using an ADDRESSOF node which
       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 _/REG_P/)", x))
      return -1;
  
    /* We may be asked for cost of various unusual addresses, such as operands
*************** static int
*** 1164,1169 ****
--- 1166,1172 ----
  mention_regs (x)
       rtx x;
  {
+   USES_PATTERN_MATCHING;
    enum rtx_code code;
    int i, j;
    const char *fmt;
*************** 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;
  	  }
      }
--- 1235,1251 ----
  
    if (code == COMPARE || GET_RTX_CLASS (code) == '<')
      {
!       if (MATCH_RTX ("(* reg@0/!REGNO_QTY_VALID_P (REGNO (_loc))/)", x))
! 	if (insert_regs (_match0, NULL, 0))
  	  {
! 	    rehash_using_reg (_match0);
  	    changed = 1;
  	  }
  
!       if (MATCH_RTX ("(* _ reg@1/!REGNO_QTY_VALID_P (REGNO (_loc))/)", x))
! 	if (insert_regs (_match1, NULL, 0))
  	  {
! 	    rehash_using_reg (_match1);
  	    changed = 1;
  	  }
      }
*************** canon_hash (x, mode)
*** 2237,2242 ****
--- 2238,2244 ----
       rtx x;
       enum machine_mode mode;
  {
+   USES_PATTERN_MATCHING;
    int i, j;
    unsigned hash = 0;
    enum rtx_code code;
*************** 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;
--- 2380,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/!MEM_VOLATILE_P/)", x))
  	{
  	  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)
*** 2714,2719 ****
--- 2715,2721 ----
       rtx x;
       int from_alias;
  {
+   USES_PATTERN_MATCHING;
    /* We need not check for X and the equivalence class being of the same
       mode because if X is equivalent to a constant in some mode, it
       doesn't vary in any mode.  */
*************** 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;
      }
--- 2731,2742 ----
  	return 0;
      }
  
!   if (MATCH_RTX ("(plus reg@0/REGNO_QTY_VALID_P (REGNO (_loc))/ const_int)", x))
      {
!       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)
*** 2884,2891 ****
       rtx *loc;
       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;
--- 2881,2889 ----
       rtx *loc;
       enum machine_mode mode;
  {
+   USES_PATTERN_MATCHING;
    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;
  
--- 2901,2911 ----
       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;
  
--- 3001,3014 ----
    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
*** 3100,3105 ****
--- 3090,3096 ----
       rtx *parg1, *parg2;
       enum machine_mode *pmode1, *pmode2;
  {
+   USES_PATTERN_MATCHING;
    rtx arg1, arg2;
  
    arg1 = *parg1, arg2 = *parg2;
*************** 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
--- 3259,3265 ----
  	}
        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)
*** 3297,3302 ****
--- 3288,3294 ----
       rtx x;
       rtx insn;
  {
+   USES_PATTERN_MATCHING;
    enum rtx_code code;
    enum machine_mode mode;
    const char *fmt;
*************** 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
--- 3439,3462 ----
  	  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);
--- 3470,3477 ----
  				== 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;
--- 3511,3521 ----
  						     op0, op1);
  		}
  
! 	      else if (MATCH_RTX ("(subreg $op0/mode == GET_MODE/)", elt->exp)
  		       && (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
--- 3544,3550 ----
  	/* 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.  */
--- 3559,3574 ----
  	  }
  
  	/* 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
--- 3611,3618 ----
  
  	/* 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.  */
--- 4080,4096 ----
  		= 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
--- 4100,4116 ----
  		= 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);
--- 4155,4161 ----
  	  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;
  
--- 4274,4280 ----
      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)
*** 4731,4736 ****
--- 4713,4719 ----
       rtx insn;
       rtx libcall_insn;
  {
+   USES_PATTERN_MATCHING;
    rtx x = PATTERN (insn);
    int i;
    rtx tem;
*************** 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);
  	}
      }
--- 4744,4751 ----
      {
        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));
  	    }
  	}
  
--- 4807,4816 ----
  	    {
  	      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
--- 4839,4846 ----
  	      /* 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.  */
--- 4858,4865 ----
      }
    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
--- 4915,4926 ----
        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);
--- 4986,4993 ----
        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;
--- 5131,5137 ----
  	      /* 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)
--- 5222,5238 ----
  	 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))
--- 5546,5553 ----
  		   /* 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))
--- 5633,5640 ----
  	 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;
  	}
  
--- 5811,5818 ----
  	      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.  */
--- 5973,5980 ----
  	    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))
  	    {
--- 6094,6103 ----
  	/* 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
--- 6107,6113 ----
  	      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
*************** static int
*** 6391,6399 ****
  addr_affects_sp_p (addr)
       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)
  	{
--- 6359,6368 ----
  addr_affects_sp_p (addr)
       rtx addr;
  {
+   USES_PATTERN_MATCHING;
+ 
    if (GET_RTX_CLASS (GET_CODE (addr)) == 'a'
!       && MATCH_RTX ("(* reg/STACK_POINTER_REGNUM == REGNO/)", addr))
      {
        if (REG_TICK (STACK_POINTER_REGNUM) >= 0)
  	{
*************** static void
*** 6423,6439 ****
  invalidate_from_clobbers (x)
       rtx x;
  {
    if (GET_CODE (x) == CLOBBER)
      {
        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)
--- 6392,6408 ----
  invalidate_from_clobbers (x)
       rtx x;
  {
+   USES_PATTERN_MATCHING;
+ 
    if (GET_CODE (x) == CLOBBER)
      {
        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));
  	    }
  	}
      }
--- 6414,6423 ----
  	  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));
  	    }
  	}
      }
*************** static void
*** 6563,6568 ****
--- 6530,6536 ----
  cse_around_loop (loop_start)
       rtx loop_start;
  {
+   USES_PATTERN_MATCHING;
    rtx insn;
    int i;
    struct table_elt *p;
*************** 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
--- 6555,6564 ----
      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
*************** cse_around_loop (loop_start)
*** 6616,6628 ****
         insn = NEXT_INSN (insn))
      {
        if (INSN_P (insn)
! 	  && (GET_CODE (PATTERN (insn)) == SET
! 	      || GET_CODE (PATTERN (insn)) == CLOBBER))
  	cse_set_around_loop (PATTERN (insn), insn, loop_start);
        else if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == PARALLEL)
  	for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
! 	  if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET
! 	      || GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == CLOBBER)
  	    cse_set_around_loop (XVECEXP (PATTERN (insn), 0, i), insn,
  				 loop_start);
      }
--- 6581,6591 ----
         insn = NEXT_INSN (insn))
      {
        if (INSN_P (insn)
! 	  && MATCH_RTX ("({set|clobber})", PATTERN (insn)))
  	cse_set_around_loop (PATTERN (insn), insn, loop_start);
        else if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == PARALLEL)
  	for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
! 	  if (MATCH_RTX ("({set|clobber})", XVECEXP (PATTERN (insn), 0, i)))
  	    cse_set_around_loop (XVECEXP (PATTERN (insn), 0, i), insn,
  				 loop_start);
      }
*************** invalidate_skipped_set (dest, set, data)
*** 6637,6642 ****
--- 6600,6606 ----
       rtx dest;
       void *data ATTRIBUTE_UNUSED;
  {
+   USES_PATTERN_MATCHING;
    enum rtx_code code = GET_CODE (dest);
  
    if (code == MEM
*************** 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
--- 6622,6631 ----
        || 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
*** 6736,6741 ****
--- 6700,6706 ----
       rtx insn;
       rtx loop_start;
  {
+   USES_PATTERN_MATCHING;
    struct table_elt *src_elt;
  
    /* If this is a SET, see if we can replace SET_SRC, but ignore SETs that
*************** 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,
--- 6783,6792 ----
  
    /* 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)
*** 7433,7449 ****
       rtx *rtl;
       void *data;
  {
    rtx insn = (rtx) data;
  
    /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it,
       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.
--- 7396,7413 ----
       rtx *rtl;
       void *data;
  {
+   USES_PATTERN_MATCHING;
    rtx insn = (rtx) data;
  
    /* If this insn uses a LABEL_REF and there isn't a REG_LABEL note for it,
       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)
*** 7461,7466 ****
--- 7425,7431 ----
       rtx dest;
       int incr;
  {
+   USES_PATTERN_MATCHING;
    enum rtx_code code;
    rtx note;
    const char *fmt;
*************** 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:
--- 7454,7461 ----
      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:



More information about the Gcc-patches mailing list