public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* RFC: define_predicate
@ 2004-07-25  2:48 Zack Weinberg
  2004-07-30  9:45 ` Mark Mitchell
  2004-08-02 14:33 ` Paolo Bonzini
  0 siblings, 2 replies; 11+ messages in thread
From: Zack Weinberg @ 2004-07-25  2:48 UTC (permalink / raw)
  To: gcc-patches


So, while messing around with the ia64 operand predicates for floating
point, I got annoyed with the way information about the predicates is
communicated to genrecog.  There are two macros, PREDICATE_CODES and
SPECIAL_MODE_PREDICATES, defined in CPU.h and looked at only by
genrecog and genpreds.  Being in CPU.h, if you change them the entire
compiler gets rebuilt, which is tedious.  Also, this is a big reason
why you can't apply genrecog to an arbitrary machine description, you
have to use the one built for that machine description.  (Another
reason is of course insn-conditions.o, but that's a thornier problem.)

Anyway, I decided it made sense to move the predicate definitions into
the machine description, where we could easily annotate them with the
information genrecog needs.  This patch does just that.  There are two
new RTL patterns, DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE -
the only difference is that using DEFINE_SPECIAL_PREDICATE is like
listing the predicate in SPECIAL_MODE_PREDICATES.  They look like
this:

(define_predicate "call_operand" "subreg,reg,symbol_ref"
{
  if (mode != GET_MODE (op) && mode != VOIDmode)
    return 0;

  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG
          || (GET_CODE (op) == SUBREG && GET_CODE (XEXP (op, 0)) == REG));
})

You can also write the name of another predicate for the second
argument, which means "the same as that one" -- this could be used
extensively in ia64.md but I haven't done that, mainly because it's
shorter to write the lists explicitly in most cases.  I did use it for
destination_operand.

I only converted the ia64 back end to this new notation.  It's not
quite possible to automate.  However, ia64 has lots of predicates, so
you can easily see what it's like.  The old PREDICATE_CODES stuff
still works.  If people get into this change and update their ports,
though, we could get rid of quite a bit of goo and reduce the
dependencies of the build programs.

I haven't written any documentation yet, mainly because I had to run
out the door.  If people like this approach I'll do that.  I am
testing it on ia64-hpux (converted) and amd64-linux (not converted).

Some notes on apparently-tangential changes:  genpreds now takes an
option to indicate which of its two possible outputs it should
produce; thus the new gensupport feature.  It's necessary to stop
including tm-p.h in print-rtl.c to break a circular dependency.  As
far as I can tell it wasn't needed.  It *does* need flags.h and wasn't
properly dependent on it; the patch changed the build order to expose
that.  enum tls_model had to move to coretypes.h because the ia64
insn-preds.c needs it but doesn't include tree.h (nor should it,
IMO).  And the ia64 predicates I deleted had become identical to
machine-independent predicates, with the removal of ADDRESSOF.

Thoughts?

zw

        * rtl.def (DEFINE_PREDICATE, DEFINE_SPECIAL_PREDICATE): New codes.
        * genpreds.c: Scan the machine description for predicate
        definitions.  Add capability to generate a file full of
        predicate function bodies, insn-preds.c.
        * genrecog.c: Scan the machine description for predicate
        declarations.  Keep them in a hash table, along with
        predicates declared the old way.  Revamp handling of
        predicates with somewhat more sensible data structures.
        * gensupport.c: Put DEFINE_PREDICATE and
        DEFINE_SPECIAL_PREDICATE in their own queue.
        Expose 'in_fname' - name of primary input file.
        (init_md_reader_args_cb): New entry point, allowing the
        provision of a callback routine to parse program-specific options.
        * gensupport.h: Update to match.
        * Makefile.in (OBJS-common): Add insn-preds.o.
        (STAGESTUFF, .PRECIOUS): Add insn-preds.c.
        (insn-preds.c, insn-preds.o): New rules.
        (s-preds): Also generate insn-preds.c.
        (genpreds): Link with RTL reader.
        (genrecog.o): Depend on $(HASHTAB_H).
        (print-rtl.o): Don't depend on $(TM_P_H); do depend on $(FLAGS_H).
        (print-rtl1.o): Likewise.

        * tree.h: Move definition of enum tls_model...
        * coretypes.h: ... here.
        * config/ia64/ia64.c: Move all predicate definitions ...
        * config/ia64/ia64.md: ... here, except
        (destination_xfmode_operand, general_xfmode_operand): Delete.
        (*movxf_internal): Use destination_operand and general_operand.
        * config/ia64/ia64.h (PREDICATE_CODES): Delete.
        (ia64_section_threshold): Declare.

===================================================================
Index: Makefile.in
--- Makefile.in	23 Jul 2004 22:36:42 -0000	1.1335
+++ Makefile.in	24 Jul 2004 06:42:17 -0000
@@ -909,8 +909,8 @@ OBJS-common = \
  genrtl.o ggc-common.o global.o graph.o gtype-desc.o			   \
  haifa-sched.o hooks.o ifcvt.o insn-attrtab.o insn-emit.o insn-modes.o	   \
  insn-extract.o insn-opinit.o insn-output.o insn-peep.o insn-recog.o	   \
- integrate.o intl.o jump.o  langhooks.o lcm.o lists.o local-alloc.o  	   \
- loop.o modulo-sched.o							   \
+ insn-preds.o integrate.o intl.o jump.o  langhooks.o lcm.o lists.o 	   \
+ local-alloc.o loop.o modulo-sched.o					   \
  optabs.o options.o opts.o params.o postreload.o predict.o		   \
  print-rtl.o print-tree.o value-prof.o var-tracking.o			   \
  profile.o ra.o ra-build.o ra-colorize.o ra-debug.o ra-rewrite.o	   \
@@ -936,7 +936,8 @@ BACKEND = main.o @TREEBROWSER@ libbacken
 # Files to be copied away after each stage in building.
 STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
  insn-output.c insn-recog.c insn-emit.c insn-extract.c insn-peep.c \
- insn-attr.h insn-attrtab.c insn-opinit.c insn-constants.h tm-preds.h \
+ insn-attr.h insn-attrtab.c insn-opinit.c insn-preds.c insn-constants.h \
+ tm-preds.h \
  tree-check.h insn-conditions.c min-insn-modes.c insn-modes.c insn-modes.h \
  s-flags s-config s-codes s-mlib s-genrtl s-modes s-gtype gtyp-gen.h \
  s-gtyp-gen s-output s-recog s-emit s-extract s-peep s-check s-conditions \
@@ -1790,7 +1791,7 @@ rtl.o : rtl.c $(CONFIG_H) $(SYSTEM_H) co
 	$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
 
 print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
-    $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) real.h $(TM_P_H)
+    $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) real.h $(FLAGS_H)
 rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \
    $(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) real.h $(FLAGS_H) \
    $(BASIC_BLOCK_H) $(REGS_H) output.h target.h function.h
@@ -2162,7 +2163,7 @@ libbackend.o : $(OBJS-common:.o=.c) $(ou
 
 .PRECIOUS: insn-config.h insn-flags.h insn-codes.h insn-constants.h \
   insn-emit.c insn-recog.c insn-extract.c insn-output.c insn-peep.c \
-  insn-attr.h insn-attrtab.c
+  insn-attr.h insn-attrtab.c insn-preds.c
 
 # The following pair of rules has this effect:
 # genconfig is run only if the md has changed since genconfig was last run;
@@ -2336,13 +2337,19 @@ s-modes: genmodes$(build_exeext)
 	$(SHELL) $(srcdir)/../move-if-change tmp-modes.c insn-modes.c
 	$(STAMP) s-modes
 
-tm-preds.h: s-preds; @true
+insn-preds.c tm-preds.h: s-preds; @true
 
-s-preds: genpreds$(build_exeext)
-	$(RUN_GEN) ./genpreds$(build_exeext) > tmp-preds.h
+s-preds: $(md_file) genpreds$(build_exeext)
+	$(RUN_GEN) ./genpreds$(build_exeext) -h $(md_file) > tmp-preds.h
 	$(SHELL) $(srcdir)/../move-if-change tmp-preds.h tm-preds.h
+	$(RUN_GEN) ./genpreds$(build_exeext) $(md_file) > tmp-preds.c
+	$(SHELL) $(srcdir)/../move-if-change tmp-preds.c insn-preds.c
 	$(STAMP) s-preds
 
+insn-preds.o : insn-preds.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \
+  $(RTL_H) insn-config.h $(RECOG_H) real.h output.h $(FLAGS_H)  function.h \
+  hard-reg-set.h $(RESOURCE_H) $(TM_P_H) toplev.h reload.h
+
 GTFILES = $(srcdir)/input.h $(srcdir)/coretypes.h \
   $(CPP_ID_DATA_H) $(host_xm_file_list) \
   $(tm_file_list) $(HASHTAB_H) $(SPLAY_TREE_H) $(srcdir)/bitmap.h \
@@ -2492,7 +2499,7 @@ genopinit.o : genopinit.c $(RTL_H) $(BCO
   $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h
 
 genrecog.o : genrecog.c $(RTL_H) $(BCONFIG_H) \
-  $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h
+  $(SYSTEM_H) coretypes.h $(GTM_H) errors.h gensupport.h $(HASHTAB_H)
 
 genextract.o : genextract.c $(RTL_H) $(BCONFIG_H) \
   $(SYSTEM_H) coretypes.h $(GTM_H) insn-config.h errors.h gensupport.h
@@ -2533,11 +2540,13 @@ genmodes$(build_exeext) : genmodes.o $(B
 genmodes.o : genmodes.c $(BCONFIG_H) $(SYSTEM_H) errors.h $(HASHTAB_H) \
 	     machmode.def $(extra_modes_file)
 
-genpreds$(build_exeext) : genpreds.o $(BUILD_LIBDEPS)
+genpreds$(build_exeext) : genpreds.o $(BUILD_RTL) $(BUILD_EARLY_SUPPORT) \
+  $(BUILD_PRINT) $(BUILD_ERRORS) $(BUILD_LIBDEPS)
 	$(CC_FOR_BUILD) $(BUILD_CFLAGS) $(BUILD_LDFLAGS) -o $@ \
-	 genpreds.o $(BUILD_LIBS)
+	 genpreds.o $(BUILD_RTL) $(BUILD_EARLY_SUPPORT) $(BUILD_PRINT) \
+	 $(BUILD_ERRORS) $(BUILD_LIBS)
 
-genpreds.o : genpreds.c $(RTL_BASE_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H)
+genpreds.o : genpreds.c $(RTL_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h $(GTM_H)
 
 gengtype$(build_exeext) : gengtype.o gengtype-lex.o gengtype-yacc.o \
   $(BUILD_LIBDEPS)
@@ -2584,7 +2593,7 @@ $(BUILD_PREFIX_1)rtl.o: $(srcdir)/rtl.c 
 	$(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) $(BUILD_PREFIX)rtl.c $(OUTPUT_OPTION)
 
 print-rtl1.o: $(srcdir)/print-rtl.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \
-  $(GTM_H) $(RTL_H) $(TREE_H) hard-reg-set.h $(BASIC_BLOCK_H) $(TM_P_H)
+  $(GTM_H) $(RTL_H) $(TREE_H) $(FLAGS_H) hard-reg-set.h $(BASIC_BLOCK_H) 
 	rm -f print-rtl1.c
 	sed -e 's/config[.]h/bconfig.h/' $(srcdir)/print-rtl.c > print-rtl1.c
 	$(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) print-rtl1.c $(OUTPUT_OPTION)
===================================================================
Index: coretypes.h
--- coretypes.h	28 Jan 2003 23:26:22 -0000	1.4
+++ coretypes.h	24 Jul 2004 06:42:17 -0000
@@ -50,6 +50,16 @@ typedef union tree_node *tree;
 
 struct cpp_reader;
 
+/* The thread-local storage model associated with a given VAR_DECL
+   or SYMBOL_REF.  This isn't used much, but both trees and RTL refer
+   to it, so it's here.  */
+enum tls_model {
+  TLS_MODEL_GLOBAL_DYNAMIC = 1,
+  TLS_MODEL_LOCAL_DYNAMIC,
+  TLS_MODEL_INITIAL_EXEC,
+  TLS_MODEL_LOCAL_EXEC
+};
+
 #else
 
 struct _dont_use_rtx_here_;
===================================================================
Index: genpreds.c
--- genpreds.c	1 Jun 2003 15:59:08 -0000	1.6
+++ genpreds.c	24 Jul 2004 06:42:17 -0000
@@ -1,8 +1,8 @@
 /* Generate from machine description:
-   - some macros CODE_FOR_... giving the insn_code_number value
-   for each of the defined standard insn names.
-   Copyright (C) 1987, 1991, 1995, 1998,
-   1999, 2000, 2001, 2003 Free Software Foundation, Inc.
+   - prototype declarations for operand predicates (tm-preds.h)
+   - function definitions of operand predicates, if defined new-style
+     (insn-preds.c)
+   Copyright (C) 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
 
 This file is part of GCC.
 
@@ -25,44 +25,192 @@ Boston, MA 02111-1307, USA.  */
 #include "system.h"
 #include "coretypes.h"
 #include "tm.h"
-
-#define NO_GENRTL_H
 #include "rtl.h"
+#include "errors.h"
+#include "gensupport.h"
+
+/* This structure captures all the data that we care about for an
+   operand predicate: its name and its body, if available.  */
+struct predicate
+{
+  struct predicate *next;
+  const char *name;
+  const char *body;
+};
 
+struct predicate *all_predicates;
 
 static void
-output_predicate_decls (void)
+new_predicate (const char *name, const char *body)
 {
+  struct predicate *p = xmalloc (sizeof (struct predicate));
+  p->name = name;
+  p->body = body;
+  p->next = all_predicates;
+  all_predicates = p;
+}
+
+/* The old-fashioned way to declare predicates is with a #define in
+   tm.h, giving the name and the set of RTX codes it can match.  */
+struct old_form_predicate
+{
+  const char *name;
+  RTX_CODE codes[NUM_RTX_CODE];
+};
+
+static const struct old_form_predicate tm_h_preds[] = {
 #ifdef PREDICATE_CODES
-  static const struct {
-    const char *const name;
-    const RTX_CODE codes[NUM_RTX_CODE];
-  } predicate[] = {
-    PREDICATE_CODES
-  };
-  size_t i;
+  PREDICATE_CODES
+#endif
+};
 
-  puts ("#ifdef RTX_CODE\n");
-  for (i = 0; i < ARRAY_SIZE (predicate); i++)
-    printf ("extern int %s (rtx, enum machine_mode);\n",
-	    predicate[i].name);
-  puts ("\n#endif /* RTX_CODE */\n");
+static void
+process_old_form_predicate_declarations (void)
+{
+#ifdef PREDICATE_CODES
+  size_t i;
+  for (i = 0; i < ARRAY_SIZE (tm_h_preds); i++)
+    new_predicate (tm_h_preds[i].name, 0);
 #endif
 }
 
+/* The new way to declare predicates is with (define_predicate) or
+   (define_special_predicate) expressions in the machine description.
+   This provides a function body as well as a name.  */
+static void
+process_define_predicate (rtx defn)
+{
+  new_predicate (XSTR (defn, 0), XSTR (defn, 2));
+}
+
+/* Write tm-preds.h.  Unfortunately, it is impossible to forward-declare
+   an enumeration in portable C, so we have to condition all these
+   prototypes on HAVE_MACHINE_MODES.  */
+static void
+write_tm_preds_h (void)
+{
+  struct predicate *p;
+
+  printf ("\
+/* Generated automatically by the program '%s'\n\
+   from the machine description file '%s'.  */\n\n", progname, in_fname);
+
+  puts ("\
+#ifndef GCC_TM_PREDS_H\n\
+#define GCC_TM_PREDS_H\n\
+\n\
+#ifdef HAVE_MACHINE_MODES");
+
+  for (p = all_predicates; p; p = p->next)
+    printf ("extern int %s (rtx, enum machine_mode);\n", p->name);
+
+  puts ("\
+#endif /* HAVE_MACHINE_MODES */\n\
+#endif /* tm-preds.h */");
+}
+
+/* Write insn-preds.c.  The only wart is that there's no way to insist
+   on a { } string in an RTL template, so we have to handle "" strings.
+   N.B. the list of headers to include was copied from genrecog; it
+   may not be ideal.
+
+   FUTURE: Write #line markers referring back to the machine
+   description.  (Can't practically do this now since we don't know
+   the line number of the body - just the line number of the enclosing
+   expression.)  */
+static void
+write_insn_preds_c (void)
+{
+  struct predicate *p;
+
+  printf ("\
+/* Generated automatically by the program '%s'\n\
+   from the machine description file '%s'.  */\n\n", progname, in_fname);
+
+  puts ("\
+#include \"config.h\"\n\
+#include \"system.h\"\n\
+#include \"coretypes.h\"\n\
+#include \"tm.h\"\n\
+#include \"rtl.h\"\n\
+#include \"tm_p.h\"\n\
+#include \"function.h\"\n\
+#include \"insn-config.h\"\n\
+#include \"recog.h\"\n\
+#include \"real.h\"\n\
+#include \"output.h\"\n\
+#include \"flags.h\"\n\
+#include \"hard-reg-set.h\"\n\
+#include \"resource.h\"\n\
+#include \"toplev.h\"\n\
+#include \"reload.h\"\n");
+
+  for (p = all_predicates; p; p = p->next)
+    if (p->body)
+      {
+	if (p->body[0] == '{')
+	  printf ("int\n"
+		  "%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n"
+		  "%s\n\n",
+		  p->name, p->body);
+	else
+	  printf ("int\n"
+		  "%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n"
+		  "{\n  %s\n}\n\n",
+		  p->name, p->body);
+      }
+}
+
+/* Argument parsing.  */
+static bool gen_header;
+static bool
+parse_option (const char *opt)
+{
+  if (!strcmp (opt, "-h"))
+    {
+      gen_header = true;
+      return 1;
+    }
+  else
+    return 0;
+}
+
+/* Master control.  */
 int
-main (void)
+main (int argc, char **argv)
 {
-  puts ("/* Generated automatically by the program `genpreds'.  */\n");
-  puts ("#ifndef GCC_TM_PREDS_H");
-  puts ("#define GCC_TM_PREDS_H\n");
+  rtx defn;
+  int pattern_lineno, next_insn_code = 0;
+
+  progname = argv[0];
+  if (argc <= 1)
+    fatal ("no input file name");
+  if (init_md_reader_args_cb (argc, argv, parse_option) != SUCCESS_EXIT_CODE)
+    return FATAL_EXIT_CODE;
 
-  output_predicate_decls ();
+  process_old_form_predicate_declarations ();
 
-  puts ("#endif /* GCC_TM_PREDS_H */");
+  while ((defn = read_md_rtx (&pattern_lineno, &next_insn_code)) != 0)
+    {
+      if (GET_CODE (defn) == DEFINE_PREDICATE
+	  || GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE)
+	process_define_predicate (defn);
+    }
+
+  if (gen_header)
+    write_tm_preds_h ();
+  else
+    write_insn_preds_c ();
 
   if (ferror (stdout) || fflush (stdout) || fclose (stdout))
     return FATAL_EXIT_CODE;
 
   return SUCCESS_EXIT_CODE;
 }
+
+/* Dummy for debugging purposes.  */
+const char *
+get_insn_name (int code ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
===================================================================
Index: genrecog.c
--- genrecog.c	4 Jul 2004 08:06:54 -0000	1.143
+++ genrecog.c	24 Jul 2004 06:42:17 -0000
@@ -57,7 +57,7 @@
 #include "rtl.h"
 #include "errors.h"
 #include "gensupport.h"
-
+#include "hashtab.h"
 
 #define OUTPUT_LABEL(INDENT_STRING, LABEL_NUMBER) \
   printf("%sL%d: ATTRIBUTE_UNUSED_LABEL\n", (INDENT_STRING), (LABEL_NUMBER))
@@ -80,6 +80,8 @@ struct decision_head
    their equality (or lack thereof) does affect tree merging so
    it is convenient to keep them here.  */
 
+struct pred_data;
+
 struct decision_test
 {
   /* A linked list through the tests attached to a node.  */
@@ -103,7 +105,8 @@ struct decision_test
     struct
     {
       const char *name;		/* Predicate to call.  */
-      int index;		/* Index into `preds' or -1.  */
+      const struct pred_data *data;
+                                /* Optimization hints for this predicate.  */
       enum machine_mode mode;	/* Machine mode for node.  */
     } pred;
 
@@ -162,11 +165,6 @@ static int next_number;
 
 static int next_insn_code;
 
-/* Similar, but counts all expressions in the MD file; used for
-   error messages.  */
-
-static int next_index;
-
 /* Record the highest depth we ever have so we know how many variables to
    allocate in each subroutine we make.  */
 
@@ -178,22 +176,46 @@ static int pattern_lineno;
 /* Count of errors.  */
 static int error_count;
 \f
-/* This table contains a list of the rtl codes that can possibly match a
-   predicate defined in recog.c.  The function `maybe_both_true' uses it to
-   deduce that there are no expressions that can be matches by certain pairs
-   of tree nodes.  Also, if a predicate can match only one code, we can
-   hardwire that code into the node testing the predicate.  */
-
-static const struct pred_table
-{
-  const char *const name;
-  const RTX_CODE codes[NUM_RTX_CODE];
-} preds[] = {
+/* Predicate handling.
+
+   We construct from the machine description a table mapping each
+   predicate to a list of the rtl codes it can possibly match.  The
+   function 'maybe_both_true' uses it to deduce that there are no
+   expressions that can be matches by certain pairs of tree nodes.
+   Also, if a predicate can match only one code, we can hardwire that
+   code into the node testing the predicate.
+
+   Some predicates are flagged as special.  validate_pattern will not
+   warn about modeless match_operand expressions if they have a special
+   predicate.
+
+   validate_pattern will warn about predicates that allow non-lvalues
+   when they appear in destination operands.  */
+
+struct pred_data
+{
+  const char * name;
+  enum rtx_code singleton;
+  bool special;
+  bool allows_non_lvalue;
+  bool codes[NUM_RTX_CODE];
+};
+
+/* This array gives the initial content of the predicate table.  It
+   has entries for all predicates defined in recog.c.  The back end
+   can define PREDICATE_CODES to give additional entries for the
+   table; this is considered an obsolete mechanism (use
+   define_predicate instead).  */
+
+struct old_pred_table
+{
+  const char *name;
+  RTX_CODE codes[NUM_RTX_CODE];
+};
+
+static const struct old_pred_table old_preds[] = {
   {"general_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
 		       LABEL_REF, SUBREG, REG, MEM }},
-#ifdef PREDICATE_CODES
-  PREDICATE_CODES
-#endif
   {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
 		       LABEL_REF, SUBREG, REG, MEM,
 		       PLUS, MINUS, MULT}},
@@ -213,20 +235,186 @@ static const struct pred_table
   {"indirect_operand", {SUBREG, MEM}},
   {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU,
 			   UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE,
-			   UNLT, LTGT}}
+			   UNLT, LTGT}},
+#ifdef PREDICATE_CODES
+  PREDICATE_CODES
+#endif
 };
 
-#define NUM_KNOWN_PREDS ARRAY_SIZE (preds)
+#define NUM_KNOWN_OLD_PREDS ARRAY_SIZE (old_preds)
 
-static const char *const special_mode_pred_table[] = {
+static const char *const old_special_pred_table[] = {
+  "address_operand",
+  "pmode_register_operand",
 #ifdef SPECIAL_MODE_PREDICATES
   SPECIAL_MODE_PREDICATES
 #endif
-  "pmode_register_operand"
 };
 
-#define NUM_SPECIAL_MODE_PREDS ARRAY_SIZE (special_mode_pred_table)
+#define NUM_OLD_SPECIAL_MODE_PREDS ARRAY_SIZE (old_special_pred_table)
+
+static htab_t predicate_table;
+
+static hashval_t
+hash_struct_pred_data (const void *ptr)
+{
+  return htab_hash_string (((const struct pred_data *)ptr)->name);
+}
+
+static int
+eq_struct_pred_data (const void *a, const void *b)
+{
+  return !strcmp (((const struct pred_data *)a)->name,
+		  ((const struct pred_data *)b)->name);
+}
+
+static struct pred_data *
+lookup_predicate (const char *name)
+{
+  struct pred_data key;
+  key.name = name;
+  return htab_find (predicate_table, &key);
+}
+
+static void
+add_predicate (struct pred_data *new_pred)
+{
+  enum rtx_code c;
+
+  enum rtx_code singleton = UNKNOWN;
+  bool seen_one = false;
+
+  bool allows_non_lvalue = false;
+  bool allows_non_const = false;
+  
+  void **slot = htab_find_slot (predicate_table, new_pred, INSERT);
+  if (*slot)
+    {
+      message_with_line (pattern_lineno,
+			 "duplicate predicate definition for '%s'",
+			 new_pred->name);
+      error_count++;
+      return;
+    }
+  *slot = new_pred;
+
+  /* Compute and memoize some functions of the set of acceptable rtx codes.  */
+  for (c = 0; c < NUM_RTX_CODE; c++)
+    if (new_pred->codes[c])
+      {
+	if (seen_one)
+	  singleton = UNKNOWN;
+	else
+	  {
+	    singleton = c;
+	    seen_one = true;
+	  }
+
+	if (c != LABEL_REF
+	    && c != SYMBOL_REF
+	    && c != CONST_INT
+	    && c != CONST_DOUBLE
+	    && c != CONST
+	    && c != HIGH)
+	  allows_non_const = true;
+
+	if (c != REG
+	    && c != SUBREG
+	    && c != MEM
+	    && c != CONCAT
+	    && c != PARALLEL
+	    && c != STRICT_LOW_PART)
+	  allows_non_lvalue = true;
+
+      }
+  /* Predicates that allow only constants should be treated as 'special'.  */
+  new_pred->special |= !allows_non_const;
+  new_pred->allows_non_lvalue = allows_non_lvalue;
+  new_pred->singleton = singleton;
+}
+
+static void
+process_define_predicate (rtx desc)
+{
+  struct pred_data *new_pred = xcalloc (sizeof (struct pred_data), 1);
+  char *code, *codestr;
+
+  new_pred->name = XSTR (desc, 0);
+  if (GET_CODE (desc) == DEFINE_SPECIAL_PREDICATE)
+    new_pred->special = 1;
+
+  codestr = alloca (strlen (XSTR (desc, 1)));
+  strcpy (codestr, XSTR (desc, 1));
+
+  for (code = strtok (codestr, ", ");
+       code;
+       code = strtok (0, ", "))
+    {
+      int i;
+      const struct pred_data *old_pred;
+
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	if (!strcmp (code, GET_RTX_NAME (i)))
+	  {
+	    new_pred->codes[i] = 1;
+	    goto next;
+	  }
+
+      /* If it's not the name of an RTX code, it might be the name of
+	 an existing predicate.  */
+      old_pred = lookup_predicate (code);
+      if (!old_pred)
+	{
+	  message_with_line (pattern_lineno,
+			     "reference to unknown predicate '%s' "
+			     "in definition of predicate '%s'",
+			     code, new_pred->name);
+	  error_count++;
+	  goto next;
+	}
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	new_pred->codes[i] |= old_pred->codes[i];
+
+    next:;
+    }
+  add_predicate (new_pred);
+}
+
+static void
+init_predicate_tables (void)
+{
+  size_t i, j;
+  struct pred_data *pred;
+
+  predicate_table = htab_create_alloc (37, hash_struct_pred_data,
+				       eq_struct_pred_data, 0,
+				       xcalloc, free);
+
+  for (i = 0; i < NUM_KNOWN_OLD_PREDS; i++)
+    {
+      pred = xcalloc (sizeof (struct pred_data), 1);
+      pred->name = old_preds[i].name;
+      for (j = 0; old_preds[i].codes[j] != 0; j++)
+	pred->codes[old_preds[i].codes[j]] = true;
+
+      add_predicate (pred);
+    }
+
+  for (i = 0; i < NUM_OLD_SPECIAL_MODE_PREDS; i++)
+    {
+      pred = lookup_predicate (old_special_pred_table[i]);
+      if (!pred)
+	{
+	  error ("old-style special predicate list refers "
+		 "to unknown predicate '%s'", old_special_pred_table[i]);
+	  error_count++;
+	  continue;
+	}
+      pred->special = true;
+    }
+}
 
+\f
 static struct decision *new_decision
   (const char *, struct decision_head *);
 static struct decision_test *new_decision_test
@@ -485,8 +673,7 @@ validate_pattern (rtx pattern, rtx insn,
     case MATCH_OPERATOR:
       {
 	const char *pred_name = XSTR (pattern, 1);
-	int allows_non_lvalue = 1, allows_non_const = 1;
-	int special_mode_pred = 0;
+	const struct pred_data *pred;
 	const char *c_test;
 
 	if (GET_CODE (insn) == DEFINE_INSN)
@@ -496,53 +683,14 @@ validate_pattern (rtx pattern, rtx insn,
 
 	if (pred_name[0] != 0)
 	  {
-	    for (i = 0; i < NUM_KNOWN_PREDS; i++)
-	      if (! strcmp (preds[i].name, pred_name))
-		break;
-
-	    if (i < NUM_KNOWN_PREDS)
-	      {
-		int j;
-
-		allows_non_lvalue = allows_non_const = 0;
-		for (j = 0; preds[i].codes[j] != 0; j++)
-		  {
-		    RTX_CODE c = preds[i].codes[j];
-		    if (c != LABEL_REF
-			&& c != SYMBOL_REF
-			&& c != CONST_INT
-			&& c != CONST_DOUBLE
-			&& c != CONST
-			&& c != HIGH)
-		      allows_non_const = 1;
-
-		    if (c != REG
-			&& c != SUBREG
-			&& c != MEM
-			&& c != CONCAT
-			&& c != PARALLEL
-			&& c != STRICT_LOW_PART)
-		      allows_non_lvalue = 1;
-		  }
-	      }
-	    else
-	      {
-#ifdef PREDICATE_CODES
-		/* If the port has a list of the predicates it uses but
-		   omits one, warn.  */
-		message_with_line (pattern_lineno,
-				   "warning: `%s' not in PREDICATE_CODES",
-				   pred_name);
-#endif
-	      }
-
-	    for (i = 0; i < NUM_SPECIAL_MODE_PREDS; ++i)
-	      if (strcmp (pred_name, special_mode_pred_table[i]) == 0)
-		{
-		  special_mode_pred = 1;
-		  break;
-		}
+	    pred = lookup_predicate (pred_name);
+	    if (!pred)
+	      message_with_line (pattern_lineno,
+				 "warning: unknown predicate '%s'",
+				 pred_name);
 	  }
+	else
+	  pred = 0;
 
 	if (code == MATCH_OPERAND)
 	  {
@@ -595,39 +743,32 @@ validate_pattern (rtx pattern, rtx insn,
 	/* Allowing non-lvalues in destinations -- particularly CONST_INT --
 	   while not likely to occur at runtime, results in less efficient
 	   code from insn-recog.c.  */
-	if (set
-	    && pred_name[0] != '\0'
-	    && allows_non_lvalue)
-	  {
-	    message_with_line (pattern_lineno,
-			"warning: destination operand %d allows non-lvalue",
-			XINT (pattern, 0));
-	  }
+	if (set && pred && pred->allows_non_lvalue)
+	  message_with_line (pattern_lineno,
+			     "warning: destination operand %d "
+			     "allows non-lvalue",
+			     XINT (pattern, 0));
 
-	/* A modeless MATCH_OPERAND can be handy when we can
-	   check for multiple modes in the c_test.  In most other cases,
-	   it is a mistake.  Only DEFINE_INSN is eligible, since SPLIT
-	   and PEEP2 can FAIL within the output pattern.  Exclude
-	   address_operand, since its mode is related to the mode of
-	   the memory not the operand.  Exclude the SET_DEST of a call
-	   instruction, as that is a common idiom.  */
+	/* A modeless MATCH_OPERAND can be handy when we can check for
+	   multiple modes in the c_test.  In most other cases, it is a
+	   mistake.  Only DEFINE_INSN is eligible, since SPLIT and
+	   PEEP2 can FAIL within the output pattern.  Exclude special
+	   predicates, which check the mode themselves.  Also exclude
+	   predicates that allow only constants.  Exclude the SET_DEST
+	   of a call instruction, as that is a common idiom.  */
 
 	if (GET_MODE (pattern) == VOIDmode
 	    && code == MATCH_OPERAND
 	    && GET_CODE (insn) == DEFINE_INSN
-	    && allows_non_const
-	    && ! special_mode_pred
-	    && pred_name[0] != '\0'
-	    && strcmp (pred_name, "address_operand") != 0
+	    && pred
+	    && !pred->special
 	    && strstr (c_test, "operands") == NULL
 	    && ! (set
 		  && GET_CODE (set) == SET
 		  && GET_CODE (SET_SRC (set)) == CALL))
-	  {
-	    message_with_line (pattern_lineno,
-			       "warning: operand %d missing mode?",
-			       XINT (pattern, 0));
-	  }
+	  message_with_line (pattern_lineno,
+			     "warning: operand %d missing mode?",
+			     XINT (pattern, 0));
 	return;
       }
 
@@ -829,9 +970,9 @@ add_to_sequence (rtx pattern, struct dec
     case MATCH_SCRATCH:
     case MATCH_OPERATOR:
       {
-	const char *pred_name;
 	RTX_CODE was_code = code;
-	int allows_const_int = 1;
+	const char *pred_name;
+	bool allows_const_int = true;
 
 	if (code == MATCH_SCRATCH)
 	  {
@@ -849,44 +990,26 @@ add_to_sequence (rtx pattern, struct dec
 
 	if (pred_name[0] != 0)
 	  {
+	    const struct pred_data *pred;
+
 	    test = new_decision_test (DT_pred, &place);
 	    test->u.pred.name = pred_name;
 	    test->u.pred.mode = mode;
 
-	    /* See if we know about this predicate and save its number.
-	       If we do, and it only accepts one code, note that fact.
-
-	       If we know that the predicate does not allow CONST_INT,
-	       we know that the only way the predicate can match is if
-	       the modes match (here we use the kludge of relying on the
-	       fact that "address_operand" accepts CONST_INT; otherwise,
-	       it would have to be a special case), so we can test the
-	       mode (but we need not).  This fact should considerably
-	       simplify the generated code.  */
-
-	    for (i = 0; i < NUM_KNOWN_PREDS; i++)
-	      if (! strcmp (preds[i].name, pred_name))
-		break;
+	    /* See if we know about this predicate.
+	       If we do, remember it for use below.
 
-	    if (i < NUM_KNOWN_PREDS)
+	       We can optimize the generated code a little if either
+	       (a) the predicate only accepts one code, or (b) the
+	       predicate does not allow CONST_INT, in which case it
+	       can match only if the modes match.  */
+	    pred = lookup_predicate (pred_name);
+	    if (pred)
 	      {
-		int j;
-
-		test->u.pred.index = i;
-
-		if (preds[i].codes[1] == 0 && code == UNKNOWN)
-		  code = preds[i].codes[0];
-
-		allows_const_int = 0;
-		for (j = 0; preds[i].codes[j] != 0; j++)
-		  if (preds[i].codes[j] == CONST_INT)
-		    {
-		      allows_const_int = 1;
-		      break;
-		    }
+		test->u.pred.data = pred;
+		allows_const_int = pred->codes[CONST_INT];
+		code = pred->singleton;
 	      }
-	    else
-	      test->u.pred.index = -1;
 	  }
 
 	/* Can't enforce a mode if we allow const_int.  */
@@ -1109,39 +1232,28 @@ maybe_both_true_2 (struct decision_test 
 	     separate DT_mode that will make maybe_both_true_1 return 0.  */
 	}
 
-      if (d1->u.pred.index >= 0)
+      if (d1->u.pred.data)
 	{
 	  /* If D2 tests a code, see if it is in the list of valid
 	     codes for D1's predicate.  */
 	  if (d2->type == DT_code)
 	    {
-	      const RTX_CODE *c = &preds[d1->u.pred.index].codes[0];
-	      while (*c != 0)
-		{
-		  if (*c == d2->u.code)
-		    break;
-		  ++c;
-		}
-	      if (*c == 0)
+	      if (!d1->u.pred.data->codes[d2->u.code])
 		return 0;
 	    }
 
 	  /* Otherwise see if the predicates have any codes in common.  */
-	  else if (d2->type == DT_pred && d2->u.pred.index >= 0)
+	  else if (d2->type == DT_pred && d2->u.pred.data)
 	    {
-	      const RTX_CODE *c1 = &preds[d1->u.pred.index].codes[0];
-	      int common = 0;
+	      bool common = false;
+	      enum rtx_code c;
 
-	      while (*c1 != 0 && !common)
-		{
-		  const RTX_CODE *c2 = &preds[d2->u.pred.index].codes[0];
-		  while (*c2 != 0 && !common)
-		    {
-		      common = (*c1 == *c2);
-		      ++c2;
-		    }
-		  ++c1;
-		}
+	      for (c = 0; c < NUM_RTX_CODE; c++)
+		if (d1->u.pred.data->codes[c] && d2->u.pred.data->codes[c])
+		  {
+		    common = true;
+		    break;
+		  }
 
 	      if (!common)
 		return 0;
@@ -1823,22 +1935,22 @@ write_switch (struct decision *start, in
       else
 	ret = p;
 
-      while (p && p->tests->type == DT_pred
-	     && p->tests->u.pred.index >= 0)
+      while (p && p->tests->type == DT_pred && p->tests->u.pred.data)
 	{
-	  const RTX_CODE *c;
-
-	  for (c = &preds[p->tests->u.pred.index].codes[0]; *c ; ++c)
-	    if (codemap[(int) *c] != 0)
+	  const struct pred_data *data = p->tests->u.pred.data;
+	  RTX_CODE c;
+	  for (c = 0; c < NUM_RTX_CODE; c++)
+	    if (codemap[c] && data->codes[c])
 	      goto pred_done;
 
-	  for (c = &preds[p->tests->u.pred.index].codes[0]; *c ; ++c)
-	    {
-	      printf ("    case ");
-	      print_code (*c);
-	      printf (":\n");
-	      codemap[(int) *c] = 1;
-	    }
+	  for (c = 0; c < NUM_RTX_CODE; c++)
+	    if (data->codes[c])
+	      {
+		fputs ("    case ", stdout);
+		print_code (c);
+		fputs (":\n", stdout);
+		codemap[c] = 1;
+	      }
 
 	  printf ("      goto L%d;\n", p->number);
 	  p->need_label = 1;
@@ -2643,10 +2755,11 @@ main (int argc, char **argv)
     return (FATAL_EXIT_CODE);
 
   next_insn_code = 0;
-  next_index = 0;
 
   write_header ();
 
+  init_predicate_tables ();
+
   /* Read the machine description.  */
 
   while (1)
@@ -2655,23 +2768,30 @@ main (int argc, char **argv)
       if (desc == NULL)
 	break;
 
-      if (GET_CODE (desc) == DEFINE_INSN)
+      switch (GET_CODE (desc))
 	{
+	case DEFINE_PREDICATE:
+	case DEFINE_SPECIAL_PREDICATE:
+	  process_define_predicate (desc);
+	  break;
+
+	case DEFINE_INSN:
 	  h = make_insn_sequence (desc, RECOG);
 	  merge_trees (&recog_tree, &h);
-	}
-      else if (GET_CODE (desc) == DEFINE_SPLIT)
-	{
+	  break;
+
+	case DEFINE_SPLIT:
 	  h = make_insn_sequence (desc, SPLIT);
 	  merge_trees (&split_tree, &h);
-	}
-      else if (GET_CODE (desc) == DEFINE_PEEPHOLE2)
-	{
+	  break;
+
+	case DEFINE_PEEPHOLE2:
 	  h = make_insn_sequence (desc, PEEPHOLE2);
 	  merge_trees (&peephole2_tree, &h);
-	}
 
-      next_index++;
+	default:
+	  /* do nothing */;
+	}
     }
 
   if (error_count)
===================================================================
Index: gensupport.c
--- gensupport.c	30 May 2004 18:32:26 -0000	1.49
+++ gensupport.c	24 Jul 2004 06:42:17 -0000
@@ -35,6 +35,8 @@ int target_flags;
 
 int insn_elision = 1;
 
+const char *in_fname;
+
 static struct obstack obstack;
 struct obstack *rtl_obstack = &obstack;
 
@@ -65,6 +67,8 @@ struct queue_elem
 
 static struct queue_elem *define_attr_queue;
 static struct queue_elem **define_attr_tail = &define_attr_queue;
+static struct queue_elem *define_pred_queue;
+static struct queue_elem **define_pred_tail = &define_pred_queue;
 static struct queue_elem *define_insn_queue;
 static struct queue_elem **define_insn_tail = &define_insn_queue;
 static struct queue_elem *define_cond_exec_queue;
@@ -284,6 +288,11 @@ process_rtx (rtx desc, int lineno)
       queue_pattern (desc, &define_attr_tail, read_rtx_filename, lineno);
       break;
 
+    case DEFINE_PREDICATE:
+    case DEFINE_SPECIAL_PREDICATE:
+      queue_pattern (desc, &define_pred_tail, read_rtx_filename, lineno);
+      break;
+
     case INCLUDE:
       process_include (desc, lineno);
       break;
@@ -898,10 +907,9 @@ save_string (const char *s, int len)
 /* The entry point for initializing the reader.  */
 
 int
-init_md_reader_args (int argc, char **argv)
+init_md_reader_args_cb (int argc, char **argv, bool (*parse_opt)(const char *))
 {
   int i;
-  const char *in_fname;
 
   max_include_len = 0;
   in_fname = NULL;
@@ -939,15 +947,29 @@ init_md_reader_args (int argc, char **ar
 	      }
 	      break;
 	    default:
-	      fatal ("invalid option `%s'", argv[i]);
+	      /* The program may have provided a callback hook so it can
+		 accept its own options.  */
+	      if (parse_opt && parse_opt (argv[i]))
+		break;
 
+	      fatal ("invalid option `%s'", argv[i]);
 	    }
 	}
     }
     return init_md_reader (in_fname);
 }
+
+/* Programs that don't have their own options can use this entry point
+   instead.  */
+int
+init_md_reader_args (int argc, char **argv)
+{
+  return init_md_reader_args_cb (argc, argv, 0);
+}
+
 \f
-/* The entry point for initializing the reader.  */
+/* The old-style entry point for initializing the reader.  Does not work
+   for programs that need to take -I switches.  */
 
 int
 init_md_reader (const char *filename)
@@ -1018,6 +1040,8 @@ read_md_rtx (int *lineno, int *seqnr)
   /* Read all patterns from a given queue before moving on to the next.  */
   if (define_attr_queue != NULL)
     queue = &define_attr_queue;
+  else if (define_pred_queue != NULL)
+    queue = &define_pred_queue;
   else if (define_insn_queue != NULL)
     queue = &define_insn_queue;
   else if (other_queue != NULL)
===================================================================
Index: gensupport.h
--- gensupport.h	1 Jun 2003 15:59:09 -0000	1.7
+++ gensupport.h	24 Jul 2004 06:42:17 -0000
@@ -23,7 +23,9 @@ Software Foundation, 59 Temple Place - S
 
 struct obstack;
 extern struct obstack *rtl_obstack;
+extern const char *in_fname;
 
+extern int init_md_reader_args_cb (int, char **, bool (*)(const char *));
 extern int init_md_reader_args (int, char **);
 extern int init_md_reader (const char *);
 extern rtx read_md_rtx (int *, int *);
===================================================================
Index: print-rtl.c
--- print-rtl.c	23 Jul 2004 21:15:45 -0000	1.114
+++ print-rtl.c	24 Jul 2004 06:42:17 -0000
@@ -34,7 +34,6 @@ Software Foundation, 59 Temple Place - S
 #include "flags.h"
 #include "hard-reg-set.h"
 #include "basic-block.h"
-#include "tm_p.h"
 
 static FILE *outfile;
 
===================================================================
Index: rtl.def
--- rtl.def	20 Jul 2004 07:26:51 -0000	1.89
+++ rtl.def	24 Jul 2004 06:42:18 -0000
@@ -297,6 +297,20 @@ DEF_RTL_EXPR(DEFINE_ASM_ATTRIBUTES, "def
    2: A template or C code to produce assembler output.  */
 DEF_RTL_EXPR(DEFINE_COND_EXEC, "define_cond_exec", "Ess", RTX_EXTRA)
 
+/* Definition of an operand predicate.  The difference between
+   DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE is that genrecog will
+   not warn about a match_operand with no mode if it has a predicate
+   defined with DEFINE_SPECIAL_PREDICATE.
+
+   Operand:
+   0: The name of the predicate.
+   1: A comma-separated list of all the RTX codes that this predicate
+      can possibly match.  Or, the name of a different predicate, whose
+      list should be used.
+   2: The function body of the predicate.  Should be a {} string.  */
+DEF_RTL_EXPR(DEFINE_PREDICATE, "define_predicate", "sss", RTX_EXTRA)
+DEF_RTL_EXPR(DEFINE_SPECIAL_PREDICATE, "define_special_predicate", "sss", RTX_EXTRA)
+
 /* SEQUENCE appears in the result of a `gen_...' function
    for a DEFINE_EXPAND that wants to make several insns.
    Its elements are the bodies of the insns that should be made.
===================================================================
Index: tree.h
--- tree.h	24 Jul 2004 01:05:45 -0000	1.570
+++ tree.h	24 Jul 2004 06:42:18 -0000
@@ -2560,13 +2560,6 @@ extern GTY(()) tree integer_types[itk_no
 \f
 /* Set to the default thread-local storage (tls) model to use.  */
 
-enum tls_model {
-  TLS_MODEL_GLOBAL_DYNAMIC = 1,
-  TLS_MODEL_LOCAL_DYNAMIC,
-  TLS_MODEL_INITIAL_EXEC,
-  TLS_MODEL_LOCAL_EXEC
-};
-
 extern enum tls_model flag_tls_default;
 
 \f
===================================================================
Index: config/ia64/ia64.c
--- config/ia64/ia64.c	20 Jul 2004 07:27:08 -0000	1.309
+++ config/ia64/ia64.c	24 Jul 2004 06:42:18 -0000
@@ -418,586 +418,6 @@ static const struct attribute_spec ia64_
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 \f
-/* Return 1 if OP is a valid operand for the MEM of a CALL insn.  */
-
-int
-call_operand (rtx op, enum machine_mode mode)
-{
-  if (mode != GET_MODE (op) && mode != VOIDmode)
-    return 0;
-
-  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG
-	  || (GET_CODE (op) == SUBREG && GET_CODE (XEXP (op, 0)) == REG));
-}
-
-/* Return 1 if OP refers to a symbol in the sdata section.  */
-
-int
-sdata_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  switch (GET_CODE (op))
-    {
-    case CONST:
-      if (GET_CODE (XEXP (op, 0)) != PLUS
-	  || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF)
-	break;
-      op = XEXP (XEXP (op, 0), 0);
-      /* FALLTHRU */
-
-    case SYMBOL_REF:
-      if (CONSTANT_POOL_ADDRESS_P (op))
-	return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold;
-      else
-	return SYMBOL_REF_LOCAL_P (op) && SYMBOL_REF_SMALL_P (op);
-
-    default:
-      break;
-    }
-
-  return 0;
-}
-
-int
-small_addr_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return SYMBOL_REF_SMALL_ADDR_P (op);
-}
-
-/* Return 1 if OP refers to a symbol, and is appropriate for a GOT load.  */
-
-int
-got_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  switch (GET_CODE (op))
-    {
-    case CONST:
-      op = XEXP (op, 0);
-      if (GET_CODE (op) != PLUS)
-	return 0;
-      if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
-	return 0;
-      op = XEXP (op, 1);
-      if (GET_CODE (op) != CONST_INT)
-	return 0;
-
-	return 1;
-
-      /* Ok if we're not using GOT entries at all.  */
-      if (TARGET_NO_PIC || TARGET_AUTO_PIC)
-	return 1;
-
-      /* "Ok" while emitting rtl, since otherwise we won't be provided
-	 with the entire offset during emission, which makes it very
-	 hard to split the offset into high and low parts.  */
-      if (rtx_equal_function_value_matters)
-	return 1;
-
-      /* Force the low 14 bits of the constant to zero so that we do not
-	 use up so many GOT entries.  */
-      return (INTVAL (op) & 0x3fff) == 0;
-
-    case SYMBOL_REF:
-      if (SYMBOL_REF_SMALL_ADDR_P (op))
-	return 0;
-    case LABEL_REF:
-      return 1;
-
-    default:
-      break;
-    }
-  return 0;
-}
-
-/* Return 1 if OP refers to a symbol.  */
-
-int
-symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  switch (GET_CODE (op))
-    {
-    case CONST:
-    case SYMBOL_REF:
-    case LABEL_REF:
-      return 1;
-
-    default:
-      break;
-    }
-  return 0;
-}
-
-/* Return tls_model if OP refers to a TLS symbol.  */
-
-int
-tls_symbolic_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
-  return SYMBOL_REF_TLS_MODEL (op);
-}
-
-
-/* Return 1 if OP refers to a function.  */
-
-int
-function_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (op))
-    return 1;
-  else
-    return 0;
-}
-
-/* Return 1 if OP is setjmp or a similar function.  */
-
-/* ??? This is an unsatisfying solution.  Should rethink.  */
-
-int
-setjmp_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  const char *name;
-  int retval = 0;
-
-  if (GET_CODE (op) != SYMBOL_REF)
-    return 0;
-
-  name = XSTR (op, 0);
-
-  /* The following code is borrowed from special_function_p in calls.c.  */
-
-  /* Disregard prefix _, __ or __x.  */
-  if (name[0] == '_')
-    {
-      if (name[1] == '_' && name[2] == 'x')
-	name += 3;
-      else if (name[1] == '_')
-	name += 2;
-      else
-	name += 1;
-    }
-
-  if (name[0] == 's')
-    {
-      retval
-	= ((name[1] == 'e'
-	    && (! strcmp (name, "setjmp")
-		|| ! strcmp (name, "setjmp_syscall")))
-	   || (name[1] == 'i'
-	       && ! strcmp (name, "sigsetjmp"))
-	   || (name[1] == 'a'
-	       && ! strcmp (name, "savectx")));
-    }
-  else if ((name[0] == 'q' && name[1] == 's'
-	    && ! strcmp (name, "qsetjmp"))
-	   || (name[0] == 'v' && name[1] == 'f'
-	       && ! strcmp (name, "vfork")))
-    retval = 1;
-
-  return retval;
-}
-
-/* Return 1 if OP is a general operand, excluding tls symbolic operands.  */
-
-int
-move_operand (rtx op, enum machine_mode mode)
-{
-  return general_operand (op, mode) && !tls_symbolic_operand (op, mode);
-}
-
-/* Return 1 if OP is a register operand that is (or could be) a GR reg.  */
-
-int
-gr_register_operand (rtx op, enum machine_mode mode)
-{
-  if (! register_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) == REG)
-    {
-      unsigned int regno = REGNO (op);
-      if (regno < FIRST_PSEUDO_REGISTER)
-	return GENERAL_REGNO_P (regno);
-    }
-  return 1;
-}
-
-/* Return 1 if OP is a register operand that is (or could be) an FR reg.  */
-
-int
-fr_register_operand (rtx op, enum machine_mode mode)
-{
-  if (! register_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) == REG)
-    {
-      unsigned int regno = REGNO (op);
-      if (regno < FIRST_PSEUDO_REGISTER)
-	return FR_REGNO_P (regno);
-    }
-  return 1;
-}
-
-/* Return 1 if OP is a register operand that is (or could be) a GR/FR reg.  */
-
-int
-grfr_register_operand (rtx op, enum machine_mode mode)
-{
-  if (! register_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) == REG)
-    {
-      unsigned int regno = REGNO (op);
-      if (regno < FIRST_PSEUDO_REGISTER)
-	return GENERAL_REGNO_P (regno) || FR_REGNO_P (regno);
-    }
-  return 1;
-}
-
-/* Return 1 if OP is a nonimmediate operand that is (or could be) a GR reg.  */
-
-int
-gr_nonimmediate_operand (rtx op, enum machine_mode mode)
-{
-  if (! nonimmediate_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) == REG)
-    {
-      unsigned int regno = REGNO (op);
-      if (regno < FIRST_PSEUDO_REGISTER)
-	return GENERAL_REGNO_P (regno);
-    }
-  return 1;
-}
-
-/* Return 1 if OP is a nonimmediate operand that is (or could be) a FR reg.  */
-
-int
-fr_nonimmediate_operand (rtx op, enum machine_mode mode)
-{
-  if (! nonimmediate_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) == REG)
-    {
-      unsigned int regno = REGNO (op);
-      if (regno < FIRST_PSEUDO_REGISTER)
-	return FR_REGNO_P (regno);
-    }
-  return 1;
-}
-
-/* Return 1 if OP is a nonimmediate operand that is a GR/FR reg.  */
-
-int
-grfr_nonimmediate_operand (rtx op, enum machine_mode mode)
-{
-  if (! nonimmediate_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == SUBREG)
-    op = SUBREG_REG (op);
-  if (GET_CODE (op) == REG)
-    {
-      unsigned int regno = REGNO (op);
-      if (regno < FIRST_PSEUDO_REGISTER)
-	return GENERAL_REGNO_P (regno) || FR_REGNO_P (regno);
-    }
-  return 1;
-}
-
-/* Return 1 if OP is a GR register operand, or zero.  */
-
-int
-gr_reg_or_0_operand (rtx op, enum machine_mode mode)
-{
-  return (op == const0_rtx || gr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a GR register operand, or a 5 bit immediate operand.  */
-
-int
-gr_reg_or_5bit_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 32)
-	  || gr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a GR register operand, or a 6 bit immediate operand.  */
-
-int
-gr_reg_or_6bit_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op)))
-	  || gr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a GR register operand, or an 8 bit immediate operand.  */
-
-int
-gr_reg_or_8bit_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op)))
-	  || gr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a GR/FR register operand, or an 8 bit immediate.  */
-
-int
-grfr_reg_or_8bit_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op)))
-	  || grfr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a register operand, or an 8 bit adjusted immediate
-   operand.  */
-
-int
-gr_reg_or_8bit_adjusted_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_L (INTVAL (op)))
-	  || gr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a register operand, or is valid for both an 8 bit
-   immediate and an 8 bit adjusted immediate operand.  This is necessary
-   because when we emit a compare, we don't know what the condition will be,
-   so we need the union of the immediates accepted by GT and LT.  */
-
-int
-gr_reg_or_8bit_and_adjusted_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))
-	   && CONST_OK_FOR_L (INTVAL (op)))
-	  || gr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a register operand, or a 14 bit immediate operand.  */
-
-int
-gr_reg_or_14bit_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_I (INTVAL (op)))
-	  || gr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a register operand, or a 22 bit immediate operand.  */
-
-int
-gr_reg_or_22bit_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_J (INTVAL (op)))
-	  || gr_register_operand (op, mode));
-}
-
-/* Return 1 if OP is a 6 bit immediate operand.  */
-
-int
-shift_count_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op)));
-}
-
-/* Return 1 if OP is a 5 bit immediate operand.  */
-
-int
-shift_32bit_count_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-	   && (INTVAL (op) >= 0 && INTVAL (op) < 32));
-}
-
-/* Return 1 if OP is a 2, 4, 8, or 16 immediate operand.  */
-
-int
-shladd_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-	  && (INTVAL (op) == 2 || INTVAL (op) == 4
-	      || INTVAL (op) == 8 || INTVAL (op) == 16));
-}
-
-/* Return 1 if OP is a -16, -8, -4, -1, 1, 4, 8, or 16 immediate operand.  */
-
-int
-fetchadd_operand (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  return (GET_CODE (op) == CONST_INT
-          && (INTVAL (op) == -16 || INTVAL (op) == -8 ||
-              INTVAL (op) == -4  || INTVAL (op) == -1 ||
-              INTVAL (op) == 1   || INTVAL (op) == 4  ||
-              INTVAL (op) == 8   || INTVAL (op) == 16));
-}
-
-/* Return 1 if OP is a floating-point constant zero, one, or a register.  */
-
-int
-fr_reg_or_fp01_operand (rtx op, enum machine_mode mode)
-{
-  return ((GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (op))
-	  || fr_register_operand (op, mode));
-}
-
-/* Like nonimmediate_operand, but don't allow MEMs that try to use a
-   POST_MODIFY with a REG as displacement.  */
-
-int
-destination_operand (rtx op, enum machine_mode mode)
-{
-  if (! nonimmediate_operand (op, mode))
-    return 0;
-  if (GET_CODE (op) == MEM
-      && GET_CODE (XEXP (op, 0)) == POST_MODIFY
-      && GET_CODE (XEXP (XEXP (XEXP (op, 0), 1), 1)) == REG)
-    return 0;
-  return 1;
-}
-
-/* Like memory_operand, but don't allow post-increments.  */
-
-int
-not_postinc_memory_operand (rtx op, enum machine_mode mode)
-{
-  return (memory_operand (op, mode)
-	  && GET_RTX_CLASS (GET_CODE (XEXP (op, 0))) != RTX_AUTOINC);
-}
-
-/* Return 1 if this is a comparison operator, which accepts a normal 8-bit
-   signed immediate operand.  */
-
-int
-normal_comparison_operator (register rtx op, enum machine_mode mode)
-{
-  enum rtx_code code = GET_CODE (op);
-  return ((mode == VOIDmode || GET_MODE (op) == mode)
-	  && (code == EQ || code == NE
-	      || code == GT || code == LE || code == GTU || code == LEU));
-}
-
-/* Return 1 if this is a comparison operator, which accepts an adjusted 8-bit
-   signed immediate operand.  */
-
-int
-adjusted_comparison_operator (register rtx op, enum machine_mode mode)
-{
-  enum rtx_code code = GET_CODE (op);
-  return ((mode == VOIDmode || GET_MODE (op) == mode)
-	  && (code == LT || code == GE || code == LTU || code == GEU));
-}
-
-/* Return 1 if this is a signed inequality operator.  */
-
-int
-signed_inequality_operator (register rtx op, enum machine_mode mode)
-{
-  enum rtx_code code = GET_CODE (op);
-  return ((mode == VOIDmode || GET_MODE (op) == mode)
-	  && (code == GE || code == GT
-	      || code == LE || code == LT));
-}
-
-/* Return 1 if this operator is valid for predication.  */
-
-int
-predicate_operator (register rtx op, enum machine_mode mode)
-{
-  enum rtx_code code = GET_CODE (op);
-  return ((GET_MODE (op) == mode || mode == VOIDmode)
-	  && (code == EQ || code == NE));
-}
-
-/* Return 1 if this operator can be used in a conditional operation.  */
-
-int
-condop_operator (register rtx op, enum machine_mode mode)
-{
-  enum rtx_code code = GET_CODE (op);
-  return ((GET_MODE (op) == mode || mode == VOIDmode)
-	  && (code == PLUS || code == MINUS || code == AND
-	      || code == IOR || code == XOR));
-}
-
-/* Return 1 if this is the ar.lc register.  */
-
-int
-ar_lc_reg_operand (register rtx op, enum machine_mode mode)
-{
-  return (GET_MODE (op) == DImode
-	  && (mode == DImode || mode == VOIDmode)
-	  && GET_CODE (op) == REG
-	  && REGNO (op) == AR_LC_REGNUM);
-}
-
-/* Return 1 if this is the ar.ccv register.  */
-
-int
-ar_ccv_reg_operand (register rtx op, enum machine_mode mode)
-{
-  return ((GET_MODE (op) == mode || mode == VOIDmode)
-	  && GET_CODE (op) == REG
-	  && REGNO (op) == AR_CCV_REGNUM);
-}
-
-/* Return 1 if this is the ar.pfs register.  */
-
-int
-ar_pfs_reg_operand (register rtx op, enum machine_mode mode)
-{
-  return ((GET_MODE (op) == mode || mode == VOIDmode)
-	  && GET_CODE (op) == REG
-	  && REGNO (op) == AR_PFS_REGNUM);
-}
-
-/* Like general_operand, but don't allow (mem (addressof)).  */
-
-int
-general_xfmode_operand (rtx op, enum machine_mode mode)
-{
-  if (! general_operand (op, mode))
-    return 0;
-  return 1;
-}
-
-/* Similarly.  */
-
-int
-destination_xfmode_operand (rtx op, enum machine_mode mode)
-{
-  if (! destination_operand (op, mode))
-    return 0;
-  return 1;
-}
-
-/* Similarly.  */
-
-int
-xfreg_or_fp01_operand (rtx op, enum machine_mode mode)
-{
-  if (GET_CODE (op) == SUBREG)
-    return 0;
-  return fr_reg_or_fp01_operand (op, mode);
-}
-
-/* Return 1 if OP is valid as a base register in a reg + offset address.  */
-
-int
-basereg_operand (rtx op, enum machine_mode mode)
-{
-  /* ??? Should I copy the flag_omit_frame_pointer and cse_not_expected
-     checks from pa.c basereg_operand as well?  Seems to be OK without them
-     in test runs.  */
-
-  return (register_operand (op, mode) &&
-	  REG_POINTER ((GET_CODE (op) == SUBREG) ? SUBREG_REG (op) : op));
-}
-\f
 typedef enum
   {
     ADDR_AREA_NORMAL,	/* normal address area */
===================================================================
Index: config/ia64/ia64.h
--- config/ia64/ia64.h	16 Jul 2004 23:25:45 -0000	1.182
+++ config/ia64/ia64.h	24 Jul 2004 06:42:18 -0000
@@ -141,6 +141,10 @@ extern int target_flags;
 
 #define TARGET_DWARF2_ASM	(target_flags & MASK_DWARF2_ASM)
 
+/* Variables which are this size or smaller are put in the sdata/sbss
+   sections.  */
+extern unsigned int ia64_section_threshold;
+
 /* If the assembler supports thread-local storage, assume that the
    system does as well.  If a particular target system has an
    assembler that supports TLS -- but the rest of the system does not
@@ -2139,50 +2143,6 @@ do {									\
    `MACHINE.c'.  For each predicate, list all rtl codes that can be in
    expressions matched by the predicate.  */
 
-#define PREDICATE_CODES \
-{ "call_operand", {SUBREG, REG, SYMBOL_REF}},				\
-{ "got_symbolic_operand", {SYMBOL_REF, CONST, LABEL_REF}},		\
-{ "sdata_symbolic_operand", {SYMBOL_REF, CONST}},			\
-{ "small_addr_symbolic_operand", {SYMBOL_REF}},				\
-{ "symbolic_operand", {SYMBOL_REF, CONST, LABEL_REF}},			\
-{ "function_operand", {SYMBOL_REF}},					\
-{ "setjmp_operand", {SYMBOL_REF}},					\
-{ "destination_operand", {SUBREG, REG, MEM}},				\
-{ "not_postinc_memory_operand", {MEM}},					\
-{ "move_operand", {SUBREG, REG, MEM, CONST_INT, CONST_DOUBLE,		\
-		     SYMBOL_REF, CONST, LABEL_REF}},			\
-{ "gr_register_operand", {SUBREG, REG}},				\
-{ "fr_register_operand", {SUBREG, REG}},				\
-{ "grfr_register_operand", {SUBREG, REG}},				\
-{ "gr_nonimmediate_operand", {SUBREG, REG, MEM}},			\
-{ "fr_nonimmediate_operand", {SUBREG, REG, MEM}},			\
-{ "grfr_nonimmediate_operand", {SUBREG, REG, MEM}},			\
-{ "gr_reg_or_0_operand", {SUBREG, REG, CONST_INT}},			\
-{ "gr_reg_or_5bit_operand", {SUBREG, REG, CONST_INT}},			\
-{ "gr_reg_or_6bit_operand", {SUBREG, REG, CONST_INT}},			\
-{ "gr_reg_or_8bit_operand", {SUBREG, REG, CONST_INT}},			\
-{ "grfr_reg_or_8bit_operand", {SUBREG, REG, CONST_INT}}, 		\
-{ "gr_reg_or_8bit_adjusted_operand", {SUBREG, REG, CONST_INT}},		\
-{ "gr_reg_or_8bit_and_adjusted_operand", {SUBREG, REG, CONST_INT}},	\
-{ "gr_reg_or_14bit_operand", {SUBREG, REG, CONST_INT}}, 		\
-{ "gr_reg_or_22bit_operand", {SUBREG, REG, CONST_INT}}, 		\
-{ "shift_count_operand", {SUBREG, REG, CONST_INT}},			\
-{ "shift_32bit_count_operand", {SUBREG, REG, CONST_INT}},		\
-{ "shladd_operand", {CONST_INT}},					\
-{ "fetchadd_operand", {CONST_INT}},					\
-{ "fr_reg_or_fp01_operand", {SUBREG, REG, CONST_DOUBLE}},		\
-{ "normal_comparison_operator", {EQ, NE, GT, LE, GTU, LEU}},		\
-{ "adjusted_comparison_operator", {LT, GE, LTU, GEU}},			\
-{ "signed_inequality_operator", {GE, GT, LE, LT}},			\
-{ "predicate_operator", {NE, EQ}},					\
-{ "condop_operator", {PLUS, MINUS, IOR, XOR, AND}},			\
-{ "ar_lc_reg_operand", {REG}},						\
-{ "ar_ccv_reg_operand", {REG}},						\
-{ "ar_pfs_reg_operand", {REG}},						\
-{ "general_xfmode_operand", {SUBREG, REG, CONST_DOUBLE, MEM}},		\
-{ "destination_xfmode_operand", {SUBREG, REG, MEM}},			\
-{ "xfreg_or_fp01_operand", {REG, CONST_DOUBLE}},			\
-{ "basereg_operand", {SUBREG, REG}},
 
 /* An alias for a machine mode name.  This is the machine mode that elements of
    a jump-table should have.  */
===================================================================
Index: config/ia64/ia64.md
--- config/ia64/ia64.md	4 Jul 2004 03:03:00 -0000	1.131
+++ config/ia64/ia64.md	24 Jul 2004 06:42:18 -0000
@@ -92,6 +92,490 @@
 \f
 ;; ::::::::::::::::::::
 ;; ::
+;; :: Predicates
+;; ::
+;; ::::::::::::::::::::
+
+;; Return 1 if OP is a valid operand for the MEM of a CALL insn.
+(define_predicate "call_operand" "subreg,reg,symbol_ref"
+{
+  if (mode != GET_MODE (op) && mode != VOIDmode)
+    return 0;
+
+  return (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == REG
+	  || (GET_CODE (op) == SUBREG && GET_CODE (XEXP (op, 0)) == REG));
+})
+
+;; Return 1 if OP refers to a symbol.
+(define_predicate "symbolic_operand" "symbol_ref,const,label_ref"
+{
+  switch (GET_CODE (op))
+    {
+    case CONST:
+    case SYMBOL_REF:
+    case LABEL_REF:
+      return 1;
+
+    default:
+      break;
+    }
+  return 0;
+})
+
+;; Return 1 if OP refers to a symbol, and is appropriate for a GOT load.
+(define_predicate "got_symbolic_operand" "symbol_ref,const,label_ref"
+{
+  switch (GET_CODE (op))
+    {
+    case CONST:
+      op = XEXP (op, 0);
+      if (GET_CODE (op) != PLUS)
+	return 0;
+      if (GET_CODE (XEXP (op, 0)) != SYMBOL_REF)
+	return 0;
+      op = XEXP (op, 1);
+      if (GET_CODE (op) != CONST_INT)
+	return 0;
+
+	return 1;
+
+      /* Ok if we're not using GOT entries at all.  */
+      if (TARGET_NO_PIC || TARGET_AUTO_PIC)
+	return 1;
+
+      /* "Ok" while emitting rtl, since otherwise we won't be provided
+	 with the entire offset during emission, which makes it very
+	 hard to split the offset into high and low parts.  */
+      if (rtx_equal_function_value_matters)
+	return 1;
+
+      /* Force the low 14 bits of the constant to zero so that we do not
+	 use up so many GOT entries.  */
+      return (INTVAL (op) & 0x3fff) == 0;
+
+    case SYMBOL_REF:
+      if (SYMBOL_REF_SMALL_ADDR_P (op))
+	return 0;
+    case LABEL_REF:
+      return 1;
+
+    default:
+      break;
+    }
+  return 0;
+})
+
+;; Return 1 if OP refers to a symbol in the sdata section.
+(define_predicate "sdata_symbolic_operand" "symbol_ref,const"
+{
+  switch (GET_CODE (op))
+    {
+    case CONST:
+      if (GET_CODE (XEXP (op, 0)) != PLUS
+	  || GET_CODE (XEXP (XEXP (op, 0), 0)) != SYMBOL_REF)
+	break;
+      op = XEXP (XEXP (op, 0), 0);
+      /* FALLTHRU */
+
+    case SYMBOL_REF:
+      if (CONSTANT_POOL_ADDRESS_P (op))
+	return GET_MODE_SIZE (get_pool_mode (op)) <= ia64_section_threshold;
+      else
+	return SYMBOL_REF_LOCAL_P (op) && SYMBOL_REF_SMALL_P (op);
+
+    default:
+      break;
+    }
+
+  return 0;
+})
+
+(define_predicate "small_addr_symbolic_operand" "symbol_ref"
+{
+  return SYMBOL_REF_SMALL_ADDR_P (op);
+})
+
+;; Return 1 if OP refers to a symbol which is thread-local.
+(define_predicate "tls_symbolic_operand" "symbol_ref"
+{
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+  return SYMBOL_REF_TLS_MODEL (op);
+})
+
+;; Return 1 if OP is a symbol which refers to a function.
+(define_predicate "function_operand" "symbol_ref"
+{
+  if (GET_CODE (op) == SYMBOL_REF && SYMBOL_REF_FUNCTION_P (op))
+    return 1;
+  else
+    return 0;
+})
+
+;; Return 1 if OP is setjmp or a similar function.
+;; ??? This is an unsatisfying solution.  Should rethink.
+(define_predicate "setjmp_operand" "symbol_ref"
+{
+  const char *name;
+  int retval = 0;
+
+  if (GET_CODE (op) != SYMBOL_REF)
+    return 0;
+
+  name = XSTR (op, 0);
+
+  /* The following code is borrowed from special_function_p in calls.c.  */
+
+  /* Disregard prefix _, __ or __x.  */
+  if (name[0] == '_')
+    {
+      if (name[1] == '_' && name[2] == 'x')
+	name += 3;
+      else if (name[1] == '_')
+	name += 2;
+      else
+	name += 1;
+    }
+
+  if (name[0] == 's')
+    {
+      retval
+	= ((name[1] == 'e'
+	    && (! strcmp (name, "setjmp")
+		|| ! strcmp (name, "setjmp_syscall")))
+	   || (name[1] == 'i'
+	       && ! strcmp (name, "sigsetjmp"))
+	   || (name[1] == 'a'
+	       && ! strcmp (name, "savectx")));
+    }
+  else if ((name[0] == 'q' && name[1] == 's'
+	    && ! strcmp (name, "qsetjmp"))
+	   || (name[0] == 'v' && name[1] == 'f'
+	       && ! strcmp (name, "vfork")))
+    retval = 1;
+
+  return retval;
+})
+
+;; Like nonimmediate_operand, but don't allow MEMs that try to use a
+;; POST_MODIFY with a REG as displacement.
+(define_predicate "destination_operand" "subreg,reg,mem"
+{
+  if (! nonimmediate_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == MEM
+      && GET_CODE (XEXP (op, 0)) == POST_MODIFY
+      && GET_CODE (XEXP (XEXP (XEXP (op, 0), 1), 1)) == REG)
+    return 0;
+  return 1;
+})
+
+;; Like memory_operand, but don't allow post-increments.
+(define_predicate "not_postinc_memory_operand" "mem"
+{
+  return (memory_operand (op, mode)
+	  && GET_RTX_CLASS (GET_CODE (XEXP (op, 0))) != RTX_AUTOINC);
+})
+
+;; Return 1 if OP is a general operand, excluding tls symbolic operands.
+(define_predicate "move_operand" "general_operand"
+{
+  return general_operand (op, mode) && !tls_symbolic_operand (op, mode);
+})
+
+;; Return 1 if OP is a register operand that is (or could be) a GR reg.
+(define_predicate "gr_register_operand" "subreg,reg"
+{
+  if (! register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  if (GET_CODE (op) == REG)
+    {
+      unsigned int regno = REGNO (op);
+      if (regno < FIRST_PSEUDO_REGISTER)
+	return GENERAL_REGNO_P (regno);
+    }
+  return 1;
+})
+
+;; Return 1 if OP is a register operand that is (or could be) an FR reg.
+(define_predicate "fr_register_operand" "subreg,reg"
+{
+  if (! register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  if (GET_CODE (op) == REG)
+    {
+      unsigned int regno = REGNO (op);
+      if (regno < FIRST_PSEUDO_REGISTER)
+	return FR_REGNO_P (regno);
+    }
+  return 1;
+})
+
+;; Return 1 if OP is a register operand that is (or could be) a GR/FR reg.
+(define_predicate "grfr_register_operand" "subreg,reg"
+{
+  if (! register_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  if (GET_CODE (op) == REG)
+    {
+      unsigned int regno = REGNO (op);
+      if (regno < FIRST_PSEUDO_REGISTER)
+	return GENERAL_REGNO_P (regno) || FR_REGNO_P (regno);
+    }
+  return 1;
+})
+
+;; Return 1 if OP is a nonimmediate operand that is (or could be) a GR reg.
+(define_predicate "gr_nonimmediate_operand" "subreg,reg,mem"
+{
+  if (! nonimmediate_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  if (GET_CODE (op) == REG)
+    {
+      unsigned int regno = REGNO (op);
+      if (regno < FIRST_PSEUDO_REGISTER)
+	return GENERAL_REGNO_P (regno);
+    }
+  return 1;
+})
+
+;; Return 1 if OP is a nonimmediate operand that is (or could be) a FR reg.
+(define_predicate "fr_nonimmediate_operand" "subreg,reg,mem"
+{
+  if (! nonimmediate_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  if (GET_CODE (op) == REG)
+    {
+      unsigned int regno = REGNO (op);
+      if (regno < FIRST_PSEUDO_REGISTER)
+	return FR_REGNO_P (regno);
+    }
+  return 1;
+})
+
+;; Return 1 if OP is a nonimmediate operand that is a GR/FR reg.
+(define_predicate "grfr_nonimmediate_operand" "subreg,reg,mem"
+{
+  if (! nonimmediate_operand (op, mode))
+    return 0;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+  if (GET_CODE (op) == REG)
+    {
+      unsigned int regno = REGNO (op);
+      if (regno < FIRST_PSEUDO_REGISTER)
+	return GENERAL_REGNO_P (regno) || FR_REGNO_P (regno);
+    }
+  return 1;
+})
+
+;; Return 1 if OP is a GR register operand, or zero.
+(define_predicate "gr_reg_or_0_operand" "subreg,reg,const_int"
+{
+  return (op == const0_rtx || gr_register_operand (op, mode));
+})
+
+;; Return 1 if OP is a GR register operand, or a 5 bit immediate operand.
+(define_predicate "gr_reg_or_5bit_operand" "subreg,reg,const_int"
+{
+  return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0 && INTVAL (op) < 32)
+	  || gr_register_operand (op, mode));
+})
+
+;; Return 1 if OP is a GR register operand, or a 6 bit immediate operand.
+(define_predicate "gr_reg_or_6bit_operand" "subreg,reg,const_int"
+{
+  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op)))
+	  || gr_register_operand (op, mode));
+})
+
+;; Return 1 if OP is a GR register operand, or an 8 bit immediate operand.
+(define_predicate "gr_reg_or_8bit_operand" "subreg,reg,const_int"
+{
+  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op)))
+	  || gr_register_operand (op, mode));
+})
+
+;; Return 1 if OP is a GR/FR register operand, or an 8 bit immediate.
+(define_predicate "grfr_reg_or_8bit_operand" "subreg,reg,const_int"
+{
+  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op)))
+	  || grfr_register_operand (op, mode));
+})
+
+;; Return 1 if OP is a register operand, or an 8 bit adjusted immediate
+;; operand.
+(define_predicate "gr_reg_or_8bit_adjusted_operand" "subreg,reg,const_int"
+{
+  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_L (INTVAL (op)))
+	  || gr_register_operand (op, mode));
+})
+
+;; Return 1 if OP is a register operand, or is valid for both an 8 bit
+;; immediate and an 8 bit adjusted immediate operand.  This is necessary
+;; because when we emit a compare, we don't know what the condition will be,
+;; so we need the union of the immediates accepted by GT and LT.
+(define_predicate "gr_reg_or_8bit_and_adjusted_operand" "subreg,reg,const_int"
+{
+  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_K (INTVAL (op))
+	   && CONST_OK_FOR_L (INTVAL (op)))
+	  || gr_register_operand (op, mode));
+})
+
+;; Return 1 if OP is a register operand, or a 14 bit immediate operand.
+(define_predicate "gr_reg_or_14bit_operand" "subreg,reg,const_int"
+{
+  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_I (INTVAL (op)))
+	  || gr_register_operand (op, mode));
+})
+
+;;  Return 1 if OP is a register operand, or a 22 bit immediate operand.
+(define_predicate "gr_reg_or_22bit_operand" "subreg,reg,const_int"
+{
+  return ((GET_CODE (op) == CONST_INT && CONST_OK_FOR_J (INTVAL (op)))
+	  || gr_register_operand (op, mode));
+})
+
+;; Return 1 if OP is a 6 bit immediate operand.
+(define_predicate "shift_count_operand" "const_int"
+{
+  return (GET_CODE (op) == CONST_INT && CONST_OK_FOR_M (INTVAL (op)));
+})
+
+;; Return 1 if OP is a 5 bit immediate operand.
+(define_predicate "shift_32bit_count_operand" "const_int"
+{
+  return (GET_CODE (op) == CONST_INT
+	   && (INTVAL (op) >= 0 && INTVAL (op) < 32));
+})
+
+
+;; Return 1 if OP is one of the immediate valuse 2, 4, 8, or 16.
+(define_predicate "shladd_operand" "const_int"
+{
+  return (GET_CODE (op) == CONST_INT
+	  && (INTVAL (op) == 2 || INTVAL (op) == 4
+	      || INTVAL (op) == 8 || INTVAL (op) == 16));
+})
+
+;; Return 1 if OP is one of the immediate values  -16, -8, -4, -1, 1, 4, 8, 16.
+(define_predicate "fetchadd_operand" "const_int"
+{
+  return (GET_CODE (op) == CONST_INT
+          && (INTVAL (op) == -16 || INTVAL (op) == -8 ||
+              INTVAL (op) == -4  || INTVAL (op) == -1 ||
+              INTVAL (op) == 1   || INTVAL (op) == 4  ||
+              INTVAL (op) == 8   || INTVAL (op) == 16));
+})
+
+;; Return 1 if OP is a floating-point constant zero, one, or a register.
+(define_predicate "fr_reg_or_fp01_operand" "subreg,reg,const_double"
+{
+  return ((GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_OK_FOR_G (op))
+	  || fr_register_operand (op, mode));
+})
+
+;; Return 1 if this is a comparison operator, which accepts a normal 8-bit
+;; signed immediate operand.
+(define_predicate "normal_comparison_operator" "eq,ne,gt,le,gtu,leu"
+{
+  enum rtx_code code = GET_CODE (op);
+  return ((mode == VOIDmode || GET_MODE (op) == mode)
+	  && (code == EQ || code == NE
+	      || code == GT || code == LE || code == GTU || code == LEU));
+})
+
+;; Return 1 if this is a comparison operator, which accepts an adjusted 8-bit
+;; signed immediate operand.
+(define_predicate "adjusted_comparison_operator" "lt,ge,ltu,geu"
+{
+  enum rtx_code code = GET_CODE (op);
+  return ((mode == VOIDmode || GET_MODE (op) == mode)
+	  && (code == LT || code == GE || code == LTU || code == GEU));
+})
+
+;; Return 1 if this is a signed inequality operator.
+(define_predicate "signed_inequality_operator" "ge,gt,le,lt"
+{
+  enum rtx_code code = GET_CODE (op);
+  return ((mode == VOIDmode || GET_MODE (op) == mode)
+	  && (code == GE || code == GT
+	      || code == LE || code == LT));
+})
+
+;; Return 1 if this operator is valid for predication.
+(define_predicate "predicate_operator" "ne,eq"
+{
+  enum rtx_code code = GET_CODE (op);
+  return ((GET_MODE (op) == mode || mode == VOIDmode)
+	  && (code == EQ || code == NE));
+})
+
+;; Return 1 if this operator can be used in a conditional operation.
+(define_predicate "condop_operator" "plus,minus,ior,xor,and"
+{
+  enum rtx_code code = GET_CODE (op);
+  return ((GET_MODE (op) == mode || mode == VOIDmode)
+	  && (code == PLUS || code == MINUS || code == AND
+	      || code == IOR || code == XOR));
+})
+
+;; Return 1 if this is the ar.lc register.
+(define_predicate "ar_lc_reg_operand" "reg"
+{
+  return (GET_MODE (op) == DImode
+	  && (mode == DImode || mode == VOIDmode)
+	  && GET_CODE (op) == REG
+	  && REGNO (op) == AR_LC_REGNUM);
+})
+
+;; Return 1 if this is the ar.ccv register.
+(define_predicate "ar_ccv_reg_operand" "reg"
+{
+  return ((GET_MODE (op) == mode || mode == VOIDmode)
+	  && GET_CODE (op) == REG
+	  && REGNO (op) == AR_CCV_REGNUM);
+})
+
+;; Return 1 if this is the ar.pfs register.
+(define_predicate "ar_pfs_reg_operand" "reg"
+{
+  return ((GET_MODE (op) == mode || mode == VOIDmode)
+	  && GET_CODE (op) == REG
+	  && REGNO (op) == AR_PFS_REGNUM);
+})
+
+;; Like fr_reg_or_fp01_operand, but don't allow any SUBREGs.
+(define_predicate "xfreg_or_fp01_operand" "reg,const_double"
+{
+  if (GET_CODE (op) == SUBREG)
+    return 0;
+  return fr_reg_or_fp01_operand (op, mode);
+})
+
+;; Return 1 if OP is valid as a base register in a reg + offset address.
+(define_predicate "basereg_operand" "subreg,reg"
+{
+  /* ??? Should I copy the flag_omit_frame_pointer and cse_not_expected
+     checks from pa.c basereg_operand as well?  Seems to be OK without them
+     in test runs.  */
+
+  return (register_operand (op, mode) &&
+	  REG_POINTER ((GET_CODE (op) == SUBREG) ? SUBREG_REG (op) : op));
+})
+\f
+;; ::::::::::::::::::::
+;; ::
 ;; :: Attributes
 ;; ::
 ;; ::::::::::::::::::::
@@ -773,8 +1257,8 @@
 ;; ??? There's no easy way to mind volatile acquire/release semantics.
 
 (define_insn "*movxf_internal"
-  [(set (match_operand:XF 0 "destination_xfmode_operand" "=f,f, m")
-	(match_operand:XF 1 "general_xfmode_operand"     "fG,m,fG"))]
+  [(set (match_operand:XF 0 "destination_operand" "=f,f, m")
+	(match_operand:XF 1 "general_operand"     "fG,m,fG"))]
   "ia64_move_ok (operands[0], operands[1])"
   "@
    mov %0 = %F1

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2004-08-03 17:06 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-07-25  2:48 RFC: define_predicate Zack Weinberg
2004-07-30  9:45 ` Mark Mitchell
2004-08-02 14:33 ` Paolo Bonzini
2004-08-02 18:50   ` Joern Rennecke
2004-08-02 19:00     ` Andrew Pinski
2004-08-02 19:19       ` Joern Rennecke
2004-08-02 19:38         ` Zack Weinberg
2004-08-03 11:49           ` Joern Rennecke
2004-08-03 12:40             ` Paolo Bonzini
2004-08-03 17:27               ` Zack Weinberg
2004-08-02 19:28     ` tree-ssa optimizer limitations (was Re: RFC: define_predicate) Zack Weinberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).