This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

define_predicate, revised (1/2)


Here is a revised patch to allow defining predicates in the machine
description.  There's been a lot of changes since the last version.
Highlights:

 - The (define_predicate) form now takes an RTL expression as well as
   the body of a C function.  The set of RTL codes that the predicate
   allows is deduced from the RTL expression.  In many cases one does
   not need to write a C block at all.

 - Normal predicates (those not defined by define_special_predicate)
   automatically get the "mode == VOIDmode || mode == GET_MODE (op)"
   test; you don't have to write that explicitly.

 - Lots and lots of crunchy documentation.

I played around with changing predicates to return 'bool', but that
would have required updating every target at once, which is out of
scope for right now.  Instead I removed the prototypes of the generic
predicates from recog.h; genpreds.c is now responsible for them.  Thus
all predicate prototypes are centralized and we can adjust them as we
like once all targets are updated to the new mechanism.

There is a third kind of predicate, an "operation predicate", which
ia64 does not use and frankly I'm not clear on what they're for.  So
I'm not sure whether this mechanism can handle them.  Comments from
folks who maintain targets that do use these would be appreciated; I
know ARM does, for instance.

The first part of the patch is the generic handling for
define_predicate; the second is an update of the ia64 back end to use
this new mechanism.  I would like to check this in in short order,
assuming people approve of the idea.  It's been bootstrapped on
ia64-hpux (a converted target) and amd64-linux (an unconverted
target) with no regressions in either case.

A couple notes on the changes in this component:

 - dummy-conditions.c now doesn't include anything but stddef.h, and
   duplicates the declaration of struct c_test from gensupport.h.
   This is because gensupport.h now drags in far too much for this
   file (which is built very very early).  It contains nothing that is
   not mandated by C90, so I feel safe not including bconfig.h or
   system.h, and it sure makes life simpler.

 - The logic for inserting mode tests (in genpreds.c) and calculating
   matchable code sets (in genrecog.c) is subtle.  I hope I have
   commented it adequately.  If it's confusing, please let me know.

 - genpreds.c uses the new init_md_reader_args_cb function I added
   last week.

 - Exposing in_fname from gensupport.c makes it possible for genpreds
   to give better diagnostics.

 - It might now be the case that most of the gen*.c files do not need
   to include tm.h (gensupport.c definitely does).  I'm not sure
   whether rtl.h still has a dependency on tm.h.

 - print-rtl.c really does need flags.h; I messed up its dependencies
   in an earlier patch.  *sigh* One of these days I'll get to doing
   automatic dependency generation...

zw

        * genpreds.c: Add capability to generate predicate bodies as
        well as function prototypes.  Write function prototypes for
        the generic predicates too.
        (process_define_predicate, write_tm_preds_h, write_insn_preds_c)
        (write_predicate_subfunction, mark_mode_tests, add_mode_tests)
        (write_match_code, write_predicate_expr, write_one_predicate_function)
        (parse_option): New functions.
        (output_predicate_decls): Delete.
        (main): Read the machine description, process DEFINE_PREDICATE or
        DEFINE_SPECIAL_PREDICATE patterns, write tm-preds.h or insn-preds.c
        as appropriate.

        * genrecog.c (struct decision_test): Replace index with
        struct pred_data pointer.
        (next_index): Remove, unused.
        (pred_table, preds, special_mode_pred_table): Delete.
        (compute_predicate_codes, process_define_predicate): New functions.
        (validate_pattern, add_to_sequence, write_switch): Update for
        new data structures.
        (main): Handle DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE.
        Check both error_count and have_error.

        * gensupport.c (in_fname, first_predicate): New globals.
        (define_pred_queue, define_pred_tail): New RTL-pattern queue.
        (predicate_table, last_predicate, old_pred_table)
        (old_special_pred_table): New statics.
        (hash_struct_pred_data, eq_struct_pred_data, lookup_predicate)
        (add_predicate, init_predicate_table): New functions.
        (process_rtx): Handle DEFINE_PREDICATE and DEFINE_SPECIAL_PREDICATE.
        (init_md_reader_args_cb): Use the global in_fname.  No need to zero
        it or max_include_len.  Call init_predicate_table.
        (read_rtx): Run the predicate queue after the attribute queue
        but before all the others.
        * gensupport.h (in_fname, struct pred_data, first_predicate)
        (lookup_predicate, add_predicate, FOR_ALL_PREDICATES): Declare.
        * rtl.def (MATCH_CODE, MATCH_TEST, DEFINE_PREDICATE)
        (DEFINE_SPECIAL_PREDICATE): New RTL codes.
        * dummy-conditions.c: Don't include bconfig.h, system.h,
        coretypes.h, tm.h, or system.h.  Do include stddef.h.
        Duplicate declaration of struct c_test from gensupport.h.

        * 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.
        (dummy-conditions.o, genpreds$(build_exeext), genpreds.o):
        Update dependencies.
        (print-rtl.o, print-rtl1.o): Correct dependencies.

        * recog.h: Delete prototypes of predicate functions.

        * doc/md.texi (Predicates): New section with complete
        documentation of operand/operator predicates.  Remove some
        incomplete documentation of predicates from other places.
        * doc/tm.texi (Misc): Move SPECIAL_MODE_PREDICATES next to
        PREDICATE_CODES; indicate that both are deprecated in favor
        of define_predicate/define_special_predicate.

===================================================================
Index: doc/md.texi
--- doc/md.texi	20 Jul 2004 07:27:17 -0000	1.106
+++ doc/md.texi	11 Aug 2004 17:44:47 -0000
@@ -28,7 +28,9 @@ See the next chapter for information on 
                           from such an insn.
 * Output Statement::    For more generality, write C code to output
                           the assembler code.
-* Constraints::         When not all operands are general operands.
+* Predicates::          Controlling what kinds of operands can be used
+                          for an insn.
+* Constraints::         Fine-tuning operand selection.
 * Standard Names::      Names mark patterns to use for code generation.
 * Pattern Ordering::    When the order of patterns makes a difference.
 * Dependent Patterns::  Having one pattern may make you need another.
@@ -258,14 +260,16 @@ expressions.  In the case of a @code{def
 used only in @code{match_dup} expressions have higher values than all
 other operand numbers.
 
-@var{predicate} is a string that is the name of a C function that accepts two
-arguments, an expression and a machine mode.  During matching, the
-function will be called with the putative operand as the expression and
-@var{m} as the mode argument (if @var{m} is not specified,
-@code{VOIDmode} will be used, which normally causes @var{predicate} to accept
-any mode).  If it returns zero, this instruction pattern fails to match.
-@var{predicate} may be an empty string; then it means no test is to be done
-on the operand, so anything which occurs in this position is valid.
+@var{predicate} is a string that is the name of a function that
+accepts two arguments, an expression and a machine mode.
+@xref{Predicates}.  During matching, the function will be called with
+the putative operand as the expression and @var{m} as the mode
+argument (if @var{m} is not specified, @code{VOIDmode} will be used,
+which normally causes @var{predicate} to accept any mode).  If it
+returns zero, this instruction pattern fails to match.
+@var{predicate} may be an empty string; then it means no test is to be
+done on the operand, so anything which occurs in this position is
+valid.
 
 Most of the time, @var{predicate} will reject modes other than @var{m}---but
 not always.  For example, the predicate @code{address_operand} uses
@@ -275,36 +279,13 @@ Many predicates accept @code{const_int} 
 
 @var{constraint} controls reloading and the choice of the best register
 class to use for a value, as explained later (@pxref{Constraints}).
+If the constraint would be an empty string, it can be omitted.
 
 People are often unclear on the difference between the constraint and the
 predicate.  The predicate helps decide whether a given insn matches the
 pattern.  The constraint plays no role in this decision; instead, it
 controls various decisions in the case of an insn which does match.
 
-@findex general_operand
-On CISC machines, the most common @var{predicate} is
-@code{"general_operand"}.  This function checks that the putative
-operand is either a constant, a register or a memory reference, and that
-it is valid for mode @var{m}.
-
-@findex register_operand
-For an operand that must be a register, @var{predicate} should be
-@code{"register_operand"}.  Using @code{"general_operand"} would be
-valid, since the reload pass would copy any non-register operands
-through registers, but this would make GCC do extra work, it would
-prevent invariant operands (such as constant) from being removed from
-loops, and it would prevent the register allocator from doing the best
-possible job.  On RISC machines, it is usually most efficient to allow
-@var{predicate} to accept only objects that the constraints allow.
-
-@findex immediate_operand
-For an operand that must be a constant, you must be sure to either use
-@code{"immediate_operand"} for @var{predicate}, or make the instruction
-pattern's extra condition require a constant, or both.  You cannot
-expect the constraints to do this work!  If the constraints allow only
-constants, but the predicate allows something else, the compiler will
-crash when that case arises.
-
 @findex match_scratch
 @item (match_scratch:@var{m} @var{n} @var{constraint})
 This expression is also a placeholder for operand number @var{n}
@@ -681,6 +662,333 @@ as follows, having the output control st
    clrmem %0")
 @end group
 @end smallexample
+
+@node Predicates
+@section Predicates
+@cindex predicates
+@cindex operand predicates
+@cindex operator predicates
+
+A predicate determines whether a @code{match_operand} or
+@code{match_operator} expression matches, and therefore whether the
+surrounding instruction pattern will be used for that combination of
+operands.  GCC has a number of machine-independent predicates, and you
+can define machine-specific predicates as needed.  By convention,
+predicates used with @code{match_operand} have names that end in
+@samp{_operand}, and those used with @code{match_operator} have names
+that end in @samp{_operator}.
+
+All predicates are Boolean functions (in the mathematical sense) of
+two arguments: the RTL expression that is being considered at that
+position in the instruction pattern, and the machine mode that the
+@code{match_operand} or @code{match_operator} specifies.  In this
+section, the first argument is called @var{op} and the second argument
+@var{mode}.  Predicates can be called from C as ordinary two-argument
+functions; this can be useful in output templates or other
+machine-specific code.
+
+Operand predicates can allow operands that are not actually acceptable
+to the hardware, as long as the constraints give reload the ability to
+fix them up (@pxref{Constraints}).  However, GCC will usually generate
+better code if the predicates specify the requirements of the machine
+instructions as closely as possible.  Reload cannot fix up operands
+that must be constants (``immediate operands''); you must use a
+predicate that allows only constants, or else enforce the requirement
+in the extra condition.
+
+@cindex predicates and machine modes
+@cindex normal predicates
+@cindex special predicates
+Most predicates handle their @var{mode} argument in a uniform manner.
+If @var{mode} is @code{VOIDmode} (unspecified), then @var{op} can have
+any mode.  If @var{mode} is anything else, then @var{op} must have the
+same mode, unless @var{op} is a @code{CONST_INT} or integer
+@code{CONST_DOUBLE}.  These RTL expressions always have
+@code{VOIDmode}, so it would be counterproductive to check that their
+mode matches.  Instead, predicates that accept @code{CONST_INT} and/or
+integer @code{CONST_DOUBLE} check that the value stored in the
+constant will fit in the requested mode.
+
+Predicates with this behavior are called @dfn{normal}.
+@command{genrecog} can optimize the instruction recognizer based on
+knowledge of how normal predicates treat modes.  It can also diagnose
+certain kinds of common errors in the use of normal predicates; for
+instance, it is almost always an error to use a normal predicate
+without specifying a mode.
+
+Predicates that do something different with their @var{mode} argument
+are called @dfn{special}.  The generic predicates
+@code{address_operand} and @code{pmode_register_operand} are special
+predicates.  @command{genrecog} does not do any optimizations or
+diagnosis when special predicates are used.
+
+@menu
+* Machine-Independent Predicates::  Predicates available to all back ends.
+* Defining Predicates::             How to write machine-specific predicate
+                                    functions.
+@end menu
+
+@node Machine-Independent Predicates
+@subsection Machine-Independent Predicates
+@cindex machine-independent predicates
+@cindex generic predicates
+
+These are the generic predicates available to all back ends.  They are
+defined in @file{recog.c}.  The first category of predicates allow
+only constant, or @dfn{immediate}, operands.
+
+@defun immediate_operand
+This predicate allows any sort of constant that fits in @var{mode}.
+It is an appropriate choice for instructions that take operands that
+must be constant.
+@end defun
+
+@defun const_int_operand
+This predicate allows any @code{CONST_INT} expression that fits in
+@var{mode}.  It is an appropriate choice for an immediate operand that
+does not allow a symbol or label.
+@end defun
+
+@defun const_double_operand
+This predicate accepts any @code{CONST_DOUBLE} expression that has
+exactly @var{mode}.  If @var{mode} is @code{VOIDmode}, it will also
+accept @code{CONST_INT}.  It is intended for immediate floating point
+constants.
+@end defun
+
+@noindent
+The second category of predicates allow only some kind of machine
+register.
+
+@defun register_operand
+This predicate allows any @code{REG} or @code{SUBREG} expression that
+is valid for @var{mode}.  It is often suitable for arithmetic
+instruction operands on a RISC machine.
+@end defun
+
+@defun pmode_register_operand
+This is a slight variant on @code{register_operand} which works around
+a limitation in the machine-description reader.
+
+@example
+(match_operand @var{n} "pmode_register_operand" @var{constraint})
+@end example
+
+@noindent
+means exactly what
+
+@example
+(match_operand:P @var{n} "register_operand" @var{constraint})
+@end example
+
+@noindent
+would mean, if the machine-description reader accepted @samp{:P}
+mode suffixes.  Unfortunately, it cannot, because @code{Pmode} is an
+alias for some other mode, and might vary with machine-specific
+options. @xref{Misc}.
+@end defun
+
+@defun scratch_operand
+This predicate allows hard registers and @code{SCRATCH} expressions,
+but not pseudo-registers.  It is used internally by @code{match_scratch};
+it should not be used directly.
+@end defun
+
+@noindent
+The third category of predicates allow only some kind of memory reference.
+
+@defun memory_operand
+This predicate allows any valid reference to a quantity of mode
+@var{mode} in memory, as determined by the weak form of
+@code{GO_IF_LEGITIMATE_ADDRESS} (@pxref{Addressing Modes}).
+@end defun
+
+@defun address_operand
+This predicate is a little unusual; it allows any operand that is a
+valid expression for the @emph{address} of a quantity of mode
+@var{mode}, again determined by the weak form of
+@code{GO_IF_LEGITIMATE_ADDRESS}.  To first order, if
+@samp{@w{(mem:@var{mode} (@var{exp}))}} is acceptable to
+@code{memory_operand}, then @var{exp} is acceptable to
+@code{address_operand}.  Note that @var{exp} does not necessarily have
+the mode @var{mode}.
+@end defun
+
+@defun indirect_operand
+This is a stricter form of @code{memory_operand} which allows only
+memory references with a @code{general_operand} as the address
+expression.  New uses of this predicate are discouraged, because
+@code{general_operand} is very permissive, so it's hard to tell what
+an @code{indirect_operand} does or does not allow.  If a target has
+different requirements for memory operands for different instructions,
+it is better to define target-specific predicates which enforce the
+hardware's requirements explicitly.
+@end defun
+
+@defun push_operand
+This predicate allows a memory reference suitable for pushing a value
+onto the stack.  This will be a @code{MEM} which refers to
+@code{stack_pointer_rtx}, with a side-effect in its address expression
+(@pxref{Incdec}); which one is determined by the
+@code{STACK_PUSH_CODE} macro (@pxref{Frame Layout}).
+@end defun
+
+@defun pop_operand
+This predicate allows a memory reference suitable for popping a value
+off the stack.  Again, this will be a @code{MEM} referring to
+@code{stack_pointer_rtx}, with a side-effect in its address
+expression.  However, this time @code{STACK_POP_CODE} is expected.
+@end defun
+
+@noindent
+The fourth category of predicates allow some combination of the above
+operands.
+
+@defun nonmemory_operand
+This predicate allows any immediate or register operand valid for @var{mode}.
+@end defun
+
+@defun nonimmediate_operand
+This predicate allows any register or memory operand valid for @var{mode}.
+@end defun
+
+@defun general_operand
+This predicate allows any immediate, register, or memory operand
+valid for @var{mode}.
+@end defun
+
+@noindent
+Finally, there is one generic operator predicate.
+
+@defun comparison_operator
+This predicate matches any expression which performs an arithmetic
+comparison in @var{mode}; that is, @code{COMPARISON_P} is true for the
+expression code.
+@end defun
+
+@node Defining Predicates
+@subsection Defining Machine-Specific Predicates
+@cindex defining predicates
+@findex define_predicate
+@findex define_special_predicate
+
+Many machines have requirements for their operands that cannot be
+expressed precisely using the generic predicates.  You can define
+additional predicates using @code{define_predicate} and
+@code{define_special_predicate} expressions.  These expressions have
+three operands:
+
+@itemize @bullet
+@item
+The name of the predicate, as it will be referred to in
+@code{match_operand} or @code{match_operator} expressions.
+
+@item
+An RTL expression which evaluates to true if the predicate allows the
+operand @var{op}, false if it does not.  This expression can only use
+the following RTL codes:
+
+@table @code
+@item MATCH_OPERAND
+When written inside a predicate expression, a @code{MATCH_OPERAND}
+expression evaluates to true if the predicate it names would allow
+@var{op}.  The operand number and constraint are ignored.  Due to
+limitations in @command{genrecog}, you can only refer to generic
+predicates and predicates that have already been defined.
+
+@item MATCH_CODE
+This expression has one operand, a string constant containing a
+comma-separated list of RTX code names (in lower case).  It evaluates
+to true if @var{op} has any of the listed codes.
+
+@item MATCH_TEST
+This expression has one operand, a string constant containing a C
+expression.  The predicate's arguments, @var{op} and @var{mode}, are
+available with those names in the C expression.  The @code{MATCH_TEST}
+evaluates to true if the C expression evaluates to a nonzero value.
+@code{MATCH_TEST} expressions must not have side effects.
+
+@item  AND
+@itemx IOR
+@itemx NOT
+@itemx IF_THEN_ELSE
+The basic @samp{MATCH_} expressions can be combined using these
+logical operators, which have the semantics of the C operators
+@samp{&&}, @samp{||}, @samp{!}, and @samp{@w{? :}} respectively.
+@end table
+
+@item
+An optional block of C code, which should execute 
+@samp{@w{return true}} if the predicate is found to match and
+@samp{@w{return false}} if it does not.  It must not have any side
+effects.  The predicate arguments, @var{op} and @var{mode}, are
+available with those names.
+
+If a code block is present in a predicate definition, then the RTL
+expression must evaluate to true @emph{and} the code block must
+execute @samp{@w{return true}} for the predicate to allow the operand.
+The RTL expression is evaluated first; do not re-check anything in the
+code block that was checked in the RTL expression.
+@end itemize
+
+The program @command{genrecog} scans @code{define_predicate} and
+@code{define_special_predicate} expressions to determine which RTX
+codes are possibly allowed.  You should always make this explicit in
+the RTL predicate expression, using @code{MATCH_OPERAND} and
+@code{MATCH_CODE}.
+
+Here is an example of a simple predicate definition, from the IA64
+machine description:
+
+@smallexample
+@group
+;; @r{True if @var{op} is a @code{SYMBOL_REF} which refers to the sdata section.}
+(define_predicate "small_addr_symbolic_operand"
+  (and (match_code "symbol_ref")
+       (match_test "SYMBOL_REF_SMALL_ADDR_P (op)")))
+@end group
+@end smallexample
+
+@noindent
+And here is another, showing the use of the C block.
+
+@smallexample
+@group
+;; @r{True if @var{op} is a register operand that is (or could be) a GR reg.}
+(define_predicate "gr_register_operand"
+  (match_operand 0 "register_operand")
+@{
+  unsigned int regno;
+  if (GET_CODE (op) == SUBREG)
+    op = SUBREG_REG (op);
+
+  regno = REGNO (op);
+  return (regno >= FIRST_PSEUDO_REGISTER || GENERAL_REGNO_P (regno));
+@})
+@end group
+@end smallexample
+
+Predicates written with @code{define_predicate} automatically include
+a test that @var{mode} is @code{VOIDmode}, or @var{op} has the same
+mode as @var{mode}, or @var{op} is a @code{CONST_INT} or
+@code{CONST_DOUBLE}.  They do @emph{not} check specifically for
+integer @code{CONST_DOUBLE}, nor do they test that the value of either
+kind of constant fits in the requested mode.  This is because
+target-specific predicates that take constants usually have to do more
+stringent value checks anyway.  If you need the exact same treatment
+of @code{CONST_INT} or @code{CONST_DOUBLE} that the generic predicates
+provide, use a @code{MATCH_OPERAND} subexpression to call
+@code{const_int_operand}, @code{const_double_operand}, or
+@code{immediate_operand}.
+
+Predicates written with @code{define_special_predicate} do not get any
+automatic mode checks, and are treated as having special mode handling
+by @command{genrecog}.
+
+The program @command{genpreds} is responsible for generating code to
+test predicates.  It also writes a header file containing function
+declarations for all machine-specific predicates.  It is not necessary
+to declare these predicates in @file{@var{cpu}-protos.h}.
 @end ifset
 
 @c Most of this node appears by itself (in a different place) even
@@ -692,8 +1000,11 @@ as follows, having the output control st
 @cindex operand constraints
 @cindex constraints
 
-Each @code{match_operand} in an instruction pattern can specify a
-constraint for the type of operands allowed.
+Each @code{match_operand} in an instruction pattern can specify
+constraints for the operands allowed.  The constraints allow you to
+fine-tune matching within the set of operands allowed by the
+predicate.
+
 @end ifset
 @ifclear INTERNALS
 @node Constraints
===================================================================
Index: doc/tm.texi
--- doc/tm.texi	11 Aug 2004 02:50:07 -0000	1.351
+++ doc/tm.texi	11 Aug 2004 17:44:47 -0000
@@ -8539,24 +8539,9 @@ patterns.
 
 For each predicate function named in @code{PREDICATE_CODES}, a
 declaration will be generated in @file{insn-codes.h}.
-@end defmac
-
-@defmac HAS_LONG_COND_BRANCH
-Define this boolean macro to indicate whether or not your architecture
-has conditional branches that can span all of memory.  It is used in
-conjunction with an optimization that partitions hot and cold basic
-blocks into separate sections of the executable.  If this macro is
-set to false, gcc will convert any conditional branches that attempt
-to cross between sections into unconditional branches or indirect jumps.
-@end defmac
 
-@defmac HAS_LONG_UNCOND_BRANCH
-Define this boolean macro to indicate whether or not your architecture
-has unconditional branches that can span all of memory.  It is used in
-conjunction with an optimization that partitions hot and cold basic
-blocks into separate sections of the executable.  If this macro is
-set to false, gcc will convert any unconditional branches that attempt
-to cross between sections into indirect jumps.
+Use of this macro is deprecated; use @code{define_predicate} instead.
+@xref{Defining Predicates}.
 @end defmac
 
 @defmac SPECIAL_MODE_PREDICATES
@@ -8574,6 +8559,27 @@ for a byte extraction from @code{%ah} et
 #define SPECIAL_MODE_PREDICATES \
   "ext_register_operand",
 @end smallexample
+
+Use of this macro is deprecated; use @code{define_special_predicate}
+instead.  @xref{Defining Predicates}.
+@end defmac
+
+@defmac HAS_LONG_COND_BRANCH
+Define this boolean macro to indicate whether or not your architecture
+has conditional branches that can span all of memory.  It is used in
+conjunction with an optimization that partitions hot and cold basic
+blocks into separate sections of the executable.  If this macro is
+set to false, gcc will convert any conditional branches that attempt
+to cross between sections into unconditional branches or indirect jumps.
+@end defmac
+
+@defmac HAS_LONG_UNCOND_BRANCH
+Define this boolean macro to indicate whether or not your architecture
+has unconditional branches that can span all of memory.  It is used in
+conjunction with an optimization that partitions hot and cold basic
+blocks into separate sections of the executable.  If this macro is
+set to false, gcc will convert any unconditional branches that attempt
+to cross between sections into indirect jumps.
 @end defmac
 
 @defmac CASE_VECTOR_MODE
===================================================================
Index: rtl.def
--- rtl.def	20 Jul 2004 07:26:51 -0000	1.89
+++ rtl.def	11 Aug 2004 17:44:47 -0000
@@ -182,6 +182,17 @@ DEF_RTL_EXPR(MATCH_OP_DUP, "match_op_dup
    at the index specified by the argument.  For MATCH_PARALLEL.  */
 DEF_RTL_EXPR(MATCH_PAR_DUP, "match_par_dup", "iE", RTX_MATCH)
 
+/* Appears only in define_predicate/define_special predicate
+   expressions in a machine description.  Evaluates true only if the
+   operand has an RTX code from the set given by the argument (a
+   comma-separated list).  */
+DEF_RTL_EXPR(MATCH_CODE, "match_code", "s", RTX_MATCH)
+
+/* Appears only in define_predicate/define_special_predicate expressions
+   in a machine description.  The argument is a C expression to be injected
+   at this point in the predicate formula.  */
+DEF_RTL_EXPR(MATCH_TEST, "match_test", "s", RTX_MATCH)
+
 /* Appears only in machine descriptions.
    Defines the pattern for one kind of instruction.
    Operand:
@@ -297,6 +308,23 @@ 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 boolean expression which computes whether or not the predicate
+      matches.  This expression can use IOR, AND, NOT, MATCH_OPERAND,
+      MATCH_CODE, and MATCH_TEST.  It must be specific enough that genrecog
+      can calculate the set of RTX codes that can possibly match.
+   2: A C function body which must return true for the predicate to match.
+      Optional.  Use this when the test is too complicated to fit into a
+      match_test expression.  */
+DEF_RTL_EXPR(DEFINE_PREDICATE, "define_predicate", "ses", RTX_EXTRA)
+DEF_RTL_EXPR(DEFINE_SPECIAL_PREDICATE, "define_special_predicate", "ses", 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: gensupport.h
--- gensupport.h	3 Aug 2004 23:30:45 -0000	1.8
+++ gensupport.h	11 Aug 2004 17:44:47 -0000
@@ -23,6 +23,7 @@ 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 **);
@@ -66,4 +67,29 @@ extern int cmp_c_test (const void *, con
 extern int n_comma_elts	(const char *);
 extern const char *scan_comma_elt (const char **);
 
+/* Predicate handling: helper functions and data structures.  */
+
+struct pred_data
+{
+  struct pred_data *next;	/* for iterating over the set of all preds */
+  const char *name;		/* predicate name */
+  bool special;			/* special handling of modes? */
+
+  /* data used primarily by genpreds.c */
+  const char *c_block;		/* C test block */
+  rtx exp;			/* RTL test expression */
+
+  /* data used primarily by genrecog.c */
+  enum rtx_code singleton;	/* if pred takes only one code, that code */
+  bool allows_non_lvalue;	/* if pred allows non-lvalue expressions */
+  bool allows_non_const;	/* if pred allows non-const expressions */
+  bool codes[NUM_RTX_CODE];	/* set of codes accepted */
+};
+
+extern struct pred_data *first_predicate;
+extern struct pred_data *lookup_predicate (const char *);
+extern void add_predicate (struct pred_data *);
+
+#define FOR_ALL_PREDICATES(p) for (p = first_predicate; p; p = p->next)
+
 #endif /* GCC_GENSUPPORT_H */
===================================================================
Index: gensupport.c
--- gensupport.c	3 Aug 2004 23:30:45 -0000	1.54
+++ gensupport.c	11 Aug 2004 17:44:47 -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;
@@ -109,6 +113,7 @@ static void process_one_cond_exec (struc
 static void process_define_cond_exec (void);
 static void process_include (rtx, int);
 static char *save_string (const char *, int);
+static void init_predicate_table (void);
 
 void
 message_with_line (int lineno, const char *msg, ...)
@@ -284,6 +289,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;
@@ -904,10 +914,7 @@ init_md_reader_args_cb (int argc, char *
   int i;
   size_t ix;
   char *lastsl;
-  const char *in_fname;
 
-  max_include_len = 0;
-  in_fname = NULL;
   for (i = 1; i < argc; i++)
     {
       if (argv[i][0] != '-')
@@ -977,6 +984,8 @@ init_md_reader_args_cb (int argc, char *
     *(htab_find_slot (condition_table, &insn_conditions[ix], INSERT))
       = (void *) &insn_conditions[ix];
 
+  init_predicate_table ();
+
   obstack_init (rtl_obstack);
   errors = 0;
   sequence_num = 0;
@@ -1025,6 +1034,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)
@@ -1181,3 +1192,154 @@ scan_comma_elt (const char **pstr)
   *pstr = p;
   return start;
 }
+
+/* Helper functions for define_predicate and define_special_predicate
+   processing.  Shared between genrecog.c and genpreds.c.  */
+
+static htab_t predicate_table;
+struct pred_data *first_predicate;
+static struct pred_data **last_predicate = &first_predicate;
+
+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);
+}
+
+struct pred_data *
+lookup_predicate (const char *name)
+{
+  struct pred_data key;
+  key.name = name;
+  return htab_find (predicate_table, &key);
+}
+
+void
+add_predicate (struct pred_data *pred)
+{
+  void **slot = htab_find_slot (predicate_table, pred, INSERT);
+  if (*slot)
+    {
+      error ("duplicate predicate definition for '%s'", pred->name);
+      return;
+    }
+  *slot = pred;
+  *last_predicate = pred;
+  last_predicate = &pred->next;
+}
+
+/* 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 }},
+  {"address_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
+		       LABEL_REF, SUBREG, REG, MEM,
+		       PLUS, MINUS, MULT}},
+  {"register_operand", {SUBREG, REG}},
+  {"pmode_register_operand", {SUBREG, REG}},
+  {"scratch_operand", {SCRATCH, REG}},
+  {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
+			 LABEL_REF}},
+  {"const_int_operand", {CONST_INT}},
+  {"const_double_operand", {CONST_INT, CONST_DOUBLE}},
+  {"nonimmediate_operand", {SUBREG, REG, MEM}},
+  {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
+			 LABEL_REF, SUBREG, REG}},
+  {"push_operand", {MEM}},
+  {"pop_operand", {MEM}},
+  {"memory_operand", {SUBREG, MEM}},
+  {"indirect_operand", {SUBREG, MEM}},
+  {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU,
+			   UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE,
+			   UNLT, LTGT}},
+#ifdef PREDICATE_CODES
+  PREDICATE_CODES
+#endif
+};
+#define NUM_KNOWN_OLD_PREDS ARRAY_SIZE (old_preds)
+
+/* This table gives the initial set of special predicates.  It has
+   entries for all special predicates defined in recog.c.  The back
+   end can define SPECIAL_MODE_PREDICATES to give additional entries
+   for the table; this is considered an obsolete mechanism (use
+   define_special_predicate instead).  */
+static const char *const old_special_pred_table[] = {
+  "address_operand",
+  "pmode_register_operand",
+#ifdef SPECIAL_MODE_PREDICATES
+  SPECIAL_MODE_PREDICATES
+#endif
+};
+
+#define NUM_OLD_SPECIAL_MODE_PREDS ARRAY_SIZE (old_special_pred_table)
+
+/* Initialize the table of predicate definitions, starting with
+   the information we have on generic predicates, and the old-style
+   PREDICATE_CODES definitions.  */
+
+static void
+init_predicate_table (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++)
+	{
+	  enum rtx_code code = old_preds[i].codes[j];
+
+	  pred->codes[code] = true;
+	  if (GET_RTX_CLASS (code) != RTX_CONST_OBJ)
+	    pred->allows_non_const = true;
+	  if (code != REG
+	      && code != SUBREG
+	      && code != MEM
+	      && code != CONCAT
+	      && code != PARALLEL
+	      && code != STRICT_LOW_PART)
+	    pred->allows_non_lvalue = true;
+	}
+      if (j == 1)
+	pred->singleton = old_preds[i].codes[0];
+      
+      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]);
+	  continue;
+	}
+      pred->special = true;
+    }
+}
===================================================================
Index: genpreds.c
--- genpreds.c	4 Aug 2004 20:55:08 -0000	1.7
+++ genpreds.c	11 Aug 2004 17:44:47 -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.
 
@@ -26,40 +26,461 @@ Boston, MA 02111-1307, USA.  */
 #include "coretypes.h"
 #include "tm.h"
 #include "rtl.h"
+#include "errors.h"
+#include "gensupport.h"
+#include "obstack.h"
+
+/* 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)
+{
+  struct pred_data *pred;
+  if (XEXP (defn, 1) == 0)
+    {
+      error ("%s: must give a predicate expression", XSTR (defn, 0));
+      return;
+    }
+
+  pred = xcalloc (sizeof (struct pred_data), 1);
+  pred->name    = XSTR (defn, 0);
+  pred->exp     = XEXP (defn, 1);
+  pred->c_block = XSTR (defn, 2);
+
+  if (GET_CODE (defn) == DEFINE_SPECIAL_PREDICATE)
+    pred->special = true;
+
+  add_predicate (pred);
+}
+
+/* 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 pred_data *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_ALL_PREDICATES (p)
+    printf ("extern int %s (rtx, enum machine_mode);\n", p->name);
+
+  puts ("\
+#endif /* HAVE_MACHINE_MODES */\n\
+#endif /* tm-preds.h */");
+}
+
+/* Given a predicate, if it has an embedded C block, write the block
+   out as a static inline subroutine, and augment the RTL test with a
+   match_test that calls that subroutine.  For instance,
+
+       (define_predicate "basereg_operand"
+         (match_operand 0 "register_operand")
+       {
+         if (GET_CODE (op) == SUBREG)
+           op = SUBREG_REG (op);
+         return REG_POINTER (op);
+       })
+
+   becomes
+
+       static inline int basereg_operand_1(rtx op, enum machine_mode mode)
+       {
+         if (GET_CODE (op) == SUBREG)
+           op = SUBREG_REG (op);
+         return REG_POINTER (op);
+       }
+
+       (define_predicate "basereg_operand"
+         (and (match_operand 0 "register_operand")
+	      (match_test "basereg_operand_1 (op, mode)")))
+
+   The only wart is that there's no way to insist on a { } string in
+   an RTL template, so we have to handle "" strings. */
+
+   
+static void
+write_predicate_subfunction (struct pred_data *p)
+{
+  const char *match_test_str;
+  rtx match_test_exp, and_exp;
+
+  if (p->c_block[0] == '\0')
+    return;
+
+  /* Construct the function-call expression.  */
+  obstack_grow (rtl_obstack, p->name, strlen (p->name));
+  obstack_grow (rtl_obstack, "_1 (op, mode)",
+		sizeof "_1 (op, mode)");
+  match_test_str = obstack_finish (rtl_obstack);
+
+  /* Add the function-call expression to the complete expression to be
+     evaluated.  */
+  match_test_exp = rtx_alloc (MATCH_TEST);
+  XSTR (match_test_exp, 0) = match_test_str;
+
+  and_exp = rtx_alloc (AND);
+  XEXP (and_exp, 0) = p->exp;
+  XEXP (and_exp, 1) = match_test_exp;
+
+  p->exp = and_exp;
+
+  printf ("static inline int\n"
+	  "%s_1 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n",
+	  p->name);
+  if (p->c_block[0] == '{')
+    fputs (p->c_block, stdout);
+  else
+    printf ("{\n  %s\n}", p->c_block);
+  fputs ("\n\n", stdout);
+}
+
+/* Given an RTL expression EXP, find all subexpressions which we may
+   assume to perform mode tests.  Normal MATCH_OPERAND does;
+   MATCH_CODE does if and only if it accepts CONST_INT or
+   CONST_DOUBLE; and we have to assume that MATCH_TEST does not.
+   These combine in almost-boolean fashion - the only exception is
+   that (not X) must be assumed not to perform a mode test, whether or
+   not X does.
+
+   The mark is the RTL /v flag, which is true for subexpressions which
+   do *not* perform mode tests.
+*/
+#define NO_MODE_TEST(EXP) RTX_FLAG (EXP, volatil)
+static void
+mark_mode_tests (rtx exp)
+{
+  switch (GET_CODE (exp))
+    {
+    case MATCH_OPERAND:
+      {
+	struct pred_data *p = lookup_predicate (XSTR (exp, 1));
+	if (!p)
+	  error ("reference to undefined predicate '%s'", XSTR (exp, 1));
+	else if (p->special)
+	  NO_MODE_TEST (exp) = 1;
+      }
+      break;
+
+    case MATCH_CODE:
+      if (!strstr (XSTR (exp, 0), "const_int")
+	  && !strstr (XSTR (exp, 0), "const_double"))
+	NO_MODE_TEST (exp) = 1;
+      break;
+
+    case MATCH_TEST:
+    case NOT:
+      NO_MODE_TEST (exp) = 1;
+      break;
+
+    case AND:
+      mark_mode_tests (XEXP (exp, 0));
+      mark_mode_tests (XEXP (exp, 1));
+
+      NO_MODE_TEST (exp) = (NO_MODE_TEST (XEXP (exp, 0))
+			    && NO_MODE_TEST (XEXP (exp, 1)));
+      break;
+      
+    case IOR:
+      mark_mode_tests (XEXP (exp, 0));
+      mark_mode_tests (XEXP (exp, 1));
+
+      NO_MODE_TEST (exp) = (NO_MODE_TEST (XEXP (exp, 0))
+			    || NO_MODE_TEST (XEXP (exp, 1)));
+      break;
+
+    case IF_THEN_ELSE:
+      /* A ? B : C does a mode test if (one of A and B) does a mode
+	 test, and C does too.  */
+      mark_mode_tests (XEXP (exp, 0));
+      mark_mode_tests (XEXP (exp, 1));
+      mark_mode_tests (XEXP (exp, 2));
+
+      NO_MODE_TEST (exp) = ((NO_MODE_TEST (XEXP (exp, 0))
+			     && NO_MODE_TEST (XEXP (exp, 1)))
+			    || NO_MODE_TEST (XEXP (exp, 2)));
+      break;
+
+    default:
+      error ("'%s' cannot be used in a define_predicate expression",
+	     GET_RTX_NAME (GET_CODE (exp)));
+    }
+}
+
+/* Given a predicate, work out where in its RTL expression to add
+   tests for proper modes.  Special predicates do not get any such
+   tests.  We try to avoid adding tests when we don't have to; in
+   particular, other normal predicates can be counted on to do it for
+   us.  */
+
+static void
+add_mode_tests (struct pred_data *p)
+{
+  rtx match_test_exp, and_exp;
+  rtx *pos;
+
+  /* Don't touch special predicates.  */
+  if (p->special)
+    return;
+
+  mark_mode_tests (p->exp);
+
+  /* If the whole expression already tests the mode, we're done.  */
+  if (!NO_MODE_TEST (p->exp))
+    return;
+
+  match_test_exp = rtx_alloc (MATCH_TEST);
+  XSTR (match_test_exp, 0) = "mode == VOIDmode || GET_MODE (op) == mode";
+  and_exp = rtx_alloc (AND);
+  XEXP (and_exp, 1) = match_test_exp;
+
+  /* It is always correct to rewrite p->exp as
+
+        (and (...) (match_test "mode == VOIDmode || GET_MODE (op) == mode"))
+
+     but there are a couple forms where we can do better.  If the
+     top-level pattern is an IOR, and one of the two branches does test
+     the mode, we can wrap just the branch that doesn't.  Likewise, if
+     we have an IF_THEN_ELSE, and one side of it tests the mode, we can
+     wrap just the side that doesn't.  And, of course, we can repeat this
+     descent as many times as it works.  */
+
+  pos = &p->exp;
+  for (;;)
+    {
+      rtx subexp = *pos;
+      if (GET_CODE (subexp) == IOR)
+	{
+	  if (NO_MODE_TEST (XEXP (subexp, 0))
+	      && NO_MODE_TEST (XEXP (subexp, 1)))
+	    break;
+	  else if (NO_MODE_TEST (XEXP (subexp, 0)))
+	    pos = &XEXP (subexp, 0);
+	  else if (NO_MODE_TEST (XEXP (subexp, 1)))
+	    pos = &XEXP (subexp, 1);
+	  else
+	    abort ();
+	}
+      else if (GET_CODE (subexp) == IF_THEN_ELSE)
+	{
+	  if (NO_MODE_TEST (XEXP (subexp, 0))
+	      && NO_MODE_TEST (XEXP (subexp, 1))
+	      && NO_MODE_TEST (XEXP (subexp, 2)))
+	    break;
+	  else if (NO_MODE_TEST (XEXP (subexp, 0))
+		   && NO_MODE_TEST (XEXP (subexp, 1)))
+	    /* Must put it on the dependent clause, not the controlling
+	       expression, or we change the meaning of the test. */
+	    pos = &XEXP (subexp, 1);
+	  else if (NO_MODE_TEST (XEXP (subexp, 2)))
+	    pos = &XEXP (subexp, 2);
+	  else
+	    abort ();
+	}
+      else
+	break;
+    }
 
+  XEXP (and_exp, 0) = *pos;
+  *pos = and_exp;
+}
+
+
+/* CODES is a list of RTX codes.  Write out an expression which
+   determines whether the operand has one of those codes.  */
+static void
+write_match_code (const char *next_code)
+{
+  const char *code;
+
+  while ((code = scan_comma_elt (&next_code)) != 0)
+    {
+      fputs ("GET_CODE (op) == ", stdout);
+      while (code < next_code)
+	{
+	  putchar (TOUPPER (*code));
+	  code++;
+	}
+      
+      if (*next_code == ',')
+	fputs (" || ", stdout);
+    }
+}
+
+/* EXP is an RTL (sub)expression for a predicate.  Recursively
+   descend the expression and write out an equivalent C expression.  */
 static void
-output_predicate_decls (void)
+write_predicate_expr (const char *name, rtx exp)
 {
-#ifdef PREDICATE_CODES
-  static const struct {
-    const char *const name;
-    const RTX_CODE codes[NUM_RTX_CODE];
-  } predicate[] = {
-    PREDICATE_CODES
-  };
-  size_t i;
-
-  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");
-#endif
+  switch (GET_CODE (exp))
+    {
+    case AND:
+      putchar ('(');
+      write_predicate_expr (name, XEXP (exp, 0));
+      fputs (") && (", stdout);
+      write_predicate_expr (name, XEXP (exp, 1));
+      putchar (')');
+      break;
+  
+    case IOR:
+      putchar ('(');
+      write_predicate_expr (name, XEXP (exp, 0));
+      fputs (") || (", stdout);
+      write_predicate_expr (name, XEXP (exp, 1));
+      putchar (')');
+      break;
+
+    case NOT:
+      fputs ("!(", stdout);
+      write_predicate_expr (name, XEXP (exp, 0));
+      putchar (')');
+      break;
+
+    case IF_THEN_ELSE:
+      putchar ('(');
+      write_predicate_expr (name, XEXP (exp, 0));
+      fputs (") ? (", stdout);
+      write_predicate_expr (name, XEXP (exp, 1));
+      fputs (") : (", stdout);
+      write_predicate_expr (name, XEXP (exp, 2));
+      putchar (')');
+      break;
+
+    case MATCH_OPERAND:
+      printf ("%s (op, mode)", XSTR (exp, 1));
+      break;
+
+    case MATCH_CODE:
+      write_match_code (XSTR (exp, 0));
+      break;
+
+    case MATCH_TEST:
+      fputs (XSTR (exp, 0), stdout);
+      break;
+
+    default:
+      error ("%s: cannot use '%s' in a predicate expression",
+	     name, GET_RTX_NAME (GET_CODE (exp)));
+      putchar ('0');
+    }
+}
+
+/* Given a predicate, write out a complete C function to compute it.  */
+static void
+write_one_predicate_function (struct pred_data *p)
+{
+  if (!p->exp)
+    return;
+
+  write_predicate_subfunction (p);
+  add_mode_tests (p);
+
+  /* A normal predicate can legitimately not look at enum machine_mode
+     if it accepts only CONST_INTs and/or CONST_DOUBLEs.  */
+  printf ("int\n%s (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)\n"
+	  "{\n  return ",
+	  p->name);
+  write_predicate_expr (p->name, p->exp);
+  fputs (";\n}\n\n", stdout);
 }
 
+/* Write insn-preds.c.  
+   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 C block - just the line number of the enclosing
+   expression.)  */
+static void
+write_insn_preds_c (void)
+{
+  struct pred_data *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_ALL_PREDICATES (p)
+    write_one_predicate_function (p);
+}
+
+/* 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;
 
-  output_predicate_decls ();
+  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;
 
-  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))
+  if (have_error || 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	3 Aug 2004 23:30:44 -0000	1.144
+++ genrecog.c	11 Aug 2004 18:07:06 -0000
@@ -58,7 +58,6 @@
 #include "errors.h"
 #include "gensupport.h"
 
-
 #define OUTPUT_LABEL(INDENT_STRING, LABEL_NUMBER) \
   printf("%sL%d: ATTRIBUTE_UNUSED_LABEL\n", (INDENT_STRING), (LABEL_NUMBER))
 
@@ -103,7 +102,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 +162,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,55 +173,213 @@ static int pattern_lineno;
 /* Count of errors.  */
 static int error_count;
 
-/* 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[] = {
-  {"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}},
-  {"register_operand", {SUBREG, REG}},
-  {"pmode_register_operand", {SUBREG, REG}},
-  {"scratch_operand", {SCRATCH, REG}},
-  {"immediate_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
-			 LABEL_REF}},
-  {"const_int_operand", {CONST_INT}},
-  {"const_double_operand", {CONST_INT, CONST_DOUBLE}},
-  {"nonimmediate_operand", {SUBREG, REG, MEM}},
-  {"nonmemory_operand", {CONST_INT, CONST_DOUBLE, CONST, SYMBOL_REF,
-			 LABEL_REF, SUBREG, REG}},
-  {"push_operand", {MEM}},
-  {"pop_operand", {MEM}},
-  {"memory_operand", {SUBREG, MEM}},
-  {"indirect_operand", {SUBREG, MEM}},
-  {"comparison_operator", {EQ, NE, LE, LT, GE, GT, LEU, LTU, GEU, GTU,
-			   UNORDERED, ORDERED, UNEQ, UNGE, UNGT, UNLE,
-			   UNLT, LTGT}}
-};
+/* Predicate handling. 
 
-#define NUM_KNOWN_PREDS ARRAY_SIZE (preds)
+   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.  Predicates that allow only constants are also
+   treated as special, for this purpose.
+
+   validate_pattern will warn about predicates that allow non-lvalues
+   when they appear in destination operands.
+
+   Calculating the set of rtx codes that can possibly be accepted by a
+   predicate expression EXP requires a three-state logic: any given
+   subexpression may definitively accept a code C (Y), definitively
+   reject a code C (N), or may have an indeterminate effect (I).  N
+   and I is N; Y or I is Y; Y and I, N or I are both I.  Here are full
+   truth tables.
+
+     a b  a&b  a|b
+     Y Y   Y   	Y
+     N Y   N 	Y
+     N N   N 	N
+     I Y   I 	Y
+     I N   N 	I
+     I I   I	I
+
+   We represent Y with 1, N with 0, I with 2.  If any code is left in
+   an I state by the complete expression, we must assume that that
+   code can be accepted.  */
+
+#define N 0
+#define Y 1
+#define I 2
+
+#define TRISTATE_AND(a,b)			\
+  ((a) == I ? ((b) == N ? N : I) :		\
+   (b) == I ? ((a) == N ? N : I) :		\
+   (a) && (b))
+
+#define TRISTATE_OR(a,b)			\
+  ((a) == I ? ((b) == Y ? Y : I) :		\
+   (b) == I ? ((a) == Y ? Y : I) :		\
+   (a) || (b))
+
+#define TRISTATE_NOT(a)				\
+  ((a) == I ? I : !(a))
+
+/* Recursively calculate the set of rtx codes accepted by the
+   predicate expression EXP, writing the result to CODES.  */
+static void
+compute_predicate_codes (rtx exp, char codes[NUM_RTX_CODE])
+{
+  char op0_codes[NUM_RTX_CODE];
+  char op1_codes[NUM_RTX_CODE];
+  char op2_codes[NUM_RTX_CODE];
+  int i;
 
-static const char *const special_mode_pred_table[] = {
-#ifdef SPECIAL_MODE_PREDICATES
-  SPECIAL_MODE_PREDICATES
-#endif
-  "pmode_register_operand"
-};
+  switch (GET_CODE (exp))
+    {
+    case AND:
+      compute_predicate_codes (XEXP (exp, 0), op0_codes);
+      compute_predicate_codes (XEXP (exp, 1), op1_codes);
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	codes[i] = TRISTATE_AND (op0_codes[i], op1_codes[i]);
+      break;
+
+    case IOR:
+      compute_predicate_codes (XEXP (exp, 0), op0_codes);
+      compute_predicate_codes (XEXP (exp, 1), op1_codes);
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	codes[i] = TRISTATE_OR (op0_codes[i], op1_codes[i]);
+      break;
+    case NOT:
+      compute_predicate_codes (XEXP (exp, 0), op0_codes);
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	codes[i] = TRISTATE_NOT (codes[i]);
+      break;
+
+    case IF_THEN_ELSE:
+      /* a ? b : c  accepts the same codes as (a & b) | (!a & c).  */ 
+      compute_predicate_codes (XEXP (exp, 0), op0_codes);
+      compute_predicate_codes (XEXP (exp, 1), op1_codes);
+      compute_predicate_codes (XEXP (exp, 2), op2_codes);
+      for (i = 0; i < NUM_RTX_CODE; i++)
+	codes[i] = TRISTATE_OR (TRISTATE_AND (op0_codes[i], op1_codes[i]),
+				TRISTATE_AND (TRISTATE_NOT (op0_codes[i]),
+					      op2_codes[i]));
+      break;
+
+    case MATCH_CODE:
+      /* MATCH_CODE allows a specified list of codes.  */
+      memset (codes, N, NUM_RTX_CODE);
+      {
+	const char *next_code = XSTR (exp, 0);
+	const char *code;
+
+	if (*next_code == '\0')
+	  {
+	    message_with_line (pattern_lineno, "empty match_code expression");
+	    error_count++;
+	    break;
+	  }
+
+	while ((code = scan_comma_elt (&next_code)) != 0)
+	  {
+	    size_t n = next_code - code;
+	    
+	    for (i = 0; i < NUM_RTX_CODE; i++)
+	      if (!strncmp (code, GET_RTX_NAME (i), n)
+		  && GET_RTX_NAME (i)[n] == '\0')
+		{
+		  codes[i] = Y;
+		  break;
+		}
+	  }
+      }
+      break;
+
+    case MATCH_OPERAND:
+      /* MATCH_OPERAND disallows the set of codes that the named predicate
+	 disallows, and is indeterminate for the codes that it does allow.  */
+      {
+	struct pred_data *p = lookup_predicate (XSTR (exp, 1));
+	if (!p)
+	  {
+	    message_with_line (pattern_lineno,
+			       "reference to unknown predicate '%s'",
+			       XSTR (exp, 1));
+	    error_count++;
+	    break;
+	  }
+	for (i = 0; i < NUM_RTX_CODE; i++)
+	  codes[i] = p->codes[i] ? I : N;
+      }
+      break;
+
+
+    case MATCH_TEST:
+      /* (match_test WHATEVER) is completely indeterminate.  */
+      memset (codes, I, NUM_RTX_CODE);
+      break;
 
-#define NUM_SPECIAL_MODE_PREDS ARRAY_SIZE (special_mode_pred_table)
+    default:
+      message_with_line (pattern_lineno,
+	 "'%s' cannot be used in a define_predicate expression",
+	 GET_RTX_NAME (GET_CODE (exp)));
+      error_count++;
+      memset (codes, I, NUM_RTX_CODE);
+      break;
+    }
+}
+
+#undef TRISTATE_OR
+#undef TRISTATE_AND
+#undef TRISTATE_NOT
+
+/* Process a define_predicate expression: compute the set of predicates
+   that can be matched, and record this as a known predicate.  */
+static void
+process_define_predicate (rtx desc)
+{
+  struct pred_data *pred = xcalloc (sizeof (struct pred_data), 1);
+  char codes[NUM_RTX_CODE];
+  bool seen_one = false;
+  int i;
 
+  pred->name = XSTR (desc, 0);
+  if (GET_CODE (desc) == DEFINE_SPECIAL_PREDICATE)
+    pred->special = 1;
+
+  compute_predicate_codes (XEXP (desc, 1), codes);
+
+  for (i = 0; i < NUM_RTX_CODE; i++)
+    if (codes[i] != N)
+      {
+	pred->codes[i] = true;
+	if (GET_RTX_CLASS (i) != RTX_CONST_OBJ)
+	  pred->allows_non_const = true;
+	if (i != REG
+	    && i != SUBREG
+	    && i != MEM
+	    && i != CONCAT
+	    && i != PARALLEL
+	    && i != STRICT_LOW_PART)
+	  pred->allows_non_lvalue = true;
+
+	if (seen_one)
+	  pred->singleton = UNKNOWN;
+	else
+	  {
+	    pred->singleton = i;
+	    seen_one = true;
+	  }
+      }
+  add_predicate (pred);
+}
+#undef I
+#undef N
+#undef Y
+
+
 static struct decision *new_decision
   (const char *, struct decision_head *);
 static struct decision_test *new_decision_test
@@ -485,8 +638,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 +648,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 +708,33 @@ 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
+	    && pred->allows_non_const
 	    && 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 +936,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 +956,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.  */
+	    /* See if we know about this predicate.
+	       If we do, remember it for use below.
 
-	    for (i = 0; i < NUM_KNOWN_PREDS; i++)
-	      if (! strcmp (preds[i].name, pred_name))
-		break;
-
-	    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 +1198,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 +1901,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;
@@ -2640,7 +2718,6 @@ main (int argc, char **argv)
     return (FATAL_EXIT_CODE);
 
   next_insn_code = 0;
-  next_index = 0;
 
   write_header ();
 
@@ -2652,26 +2729,33 @@ 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)
+  if (error_count || have_error)
     return FATAL_EXIT_CODE;
 
   puts ("\n\n");
===================================================================
Index: dummy-conditions.c
--- dummy-conditions.c	13 Mar 2003 03:48:27 -0000	1.3
+++ dummy-conditions.c	11 Aug 2004 17:44:47 -0000
@@ -1,5 +1,5 @@
 /* Support for calculating constant conditions.
-   Copyright (C) 2002 Free Software Foundation, Inc.
+   Copyright (C) 2002, 2004 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -18,16 +18,22 @@
    the Free Software Foundation, 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.  */
 
-#include "bconfig.h"
-#include "system.h"
-#include "coretypes.h"
-#include "tm.h"
-#include "gensupport.h"
+#include <stddef.h>  /* for size_t */
 
 /* MD generators that are run before insn-conditions.c exists should
    link against this file instead.  Currently that is genconditions
    and genconstants.  */
 
+/* In order to avoid dragging in all the headers that are needed to
+   declare things that gensupport.h uses, we duplicate the declaration
+   of struct c_test here.  (In particular we do not want to have to
+   include tm.h nor rtl.h in this file.)  */
+struct c_test
+{
+  const char *expr;
+  int value;
+};
+
 /* Empty conditions table to prevent link errors.  */
 const struct c_test insn_conditions[1] = { { 0, 0 } };
 const size_t n_insn_conditions = 0;
===================================================================
Index: recog.h
--- recog.h	25 Jul 2004 17:57:23 -0000	1.50
+++ recog.h	11 Aug 2004 17:44:47 -0000
@@ -96,22 +96,6 @@ extern int next_insn_tests_no_inequality
 extern int reg_fits_class_p (rtx, enum reg_class, int, enum machine_mode);
 extern rtx *find_single_use (rtx, rtx, rtx *);
 
-extern int general_operand (rtx, enum machine_mode);
-extern int address_operand (rtx, enum machine_mode);
-extern int register_operand (rtx, enum machine_mode);
-extern int pmode_register_operand (rtx, enum machine_mode);
-extern int scratch_operand (rtx, enum machine_mode);
-extern int immediate_operand (rtx, enum machine_mode);
-extern int const_int_operand (rtx, enum machine_mode);
-extern int const_double_operand (rtx, enum machine_mode);
-extern int nonimmediate_operand (rtx, enum machine_mode);
-extern int nonmemory_operand (rtx, enum machine_mode);
-extern int push_operand (rtx, enum machine_mode);
-extern int pop_operand (rtx, enum machine_mode);
-extern int memory_operand (rtx, enum machine_mode);
-extern int indirect_operand (rtx, enum machine_mode);
-extern int comparison_operator (rtx, enum machine_mode);
-
 extern int offsettable_memref_p (rtx);
 extern int offsettable_nonstrict_memref_p (rtx);
 extern int offsettable_address_p (int, enum machine_mode, rtx);
===================================================================
Index: Makefile.in
--- Makefile.in	10 Aug 2004 20:43:05 -0000	1.1342
+++ Makefile.in	11 Aug 2004 18:15:49 -0000
@@ -910,8 +910,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	   \
@@ -937,7 +937,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 \
@@ -1796,7 +1797,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
+    $(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
@@ -2166,7 +2167,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;
@@ -2205,8 +2206,7 @@ insn-conditions.o : insn-conditions.c $(
   insn-constants.h
 	$(CC_FOR_BUILD) -c $(BUILD_CFLAGS) $(BUILD_CPPFLAGS) $(INCLUDES) insn-conditions.c
 
-dummy-conditions.o : dummy-conditions.c $(BCONFIG_H) $(SYSTEM_H) \
-  coretypes.h $(GTM_H) gensupport.h
+dummy-conditions.o : dummy-conditions.c
 
 insn-flags.h: s-flags ; @true
 s-flags : $(md_file) genflags$(build_exeext)
@@ -2340,13 +2340,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 \
@@ -2539,11 +2545,14 @@ 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_BASE_H) $(BCONFIG_H) $(SYSTEM_H) coretypes.h \
+	$(GTM_H) errors.h gensupport.h $(OBSTACK_H)
 
 gengtype$(build_exeext) : gengtype.o gengtype-lex.o gengtype-yacc.o \
   $(BUILD_LIBDEPS)
@@ -2593,7 +2602,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)
+  $(GTM_H) $(RTL_BASE_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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]