OSDN Git Service

2001-08-27 Vladimir Makarov <vmakarov@touchme.toronto.redhat.com>
authorvmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 27 Aug 2001 18:13:42 +0000 (18:13 +0000)
committervmakarov <vmakarov@138bc75d-0d04-0410-961f-82ee72b054a4>
Mon, 27 Aug 2001 18:13:42 +0000 (18:13 +0000)
        * rtl.def (DEFINE_CPU_UNIT, DEFINE_QUERY_CPU_UNIT, EXCLUSION_SET,
PRESENCE_SET, ABSENCE_SET, DEFINE_BYPASS, DEFINE_AUTOMATON,
AUTOMATA_OPTION, DEFINE_RESERVATION, DEFINE_INSN_RESERVATION): New
RTL constructions.

* genattr.c (main): New variable num_insn_reservations.  Increase
it if there is DEFINE_INSN_RESERVATION.  Output automaton based
pipeline hazard recognizer interface.

* genattrtab.h: New file.

* genattrtab.c: Include genattrtab.h.
(attr_printf, check_attr_test, make_internal_attr,
make_numeric_value): Move protypes into genattrtab.h.  Define them
as external.
(num_dfa_decls): New global variable.
(main): Process DEFINE_CPU_UNIT, DEFINE_QUERY_CPU_UNIT,
DEFINE_BYPASS, EXCLUSION_SET, PRESENCE_SET, ABSENCE_SET,
DEFINE_AUTOMATON, AUTOMATA_OPTION, DEFINE_RESERVATION,
DEFINE_INSN_RESERVATION.  Call expand_automata and write_automata.

* genautomata.c: New file.

* rtl.h (LINK_COST_ZERO, LINK_COST_FREE): Remove them.

        * sched-int.h: (curr_state): Add the external definition for
automaton pipeline interface.
(haifa_insn_data): Add comments for members blockage and units.

* target-def.h (TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE,
TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN,
TARGET_SCHED_DFA_PRE_CYCLE_INSN,
TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN,
TARGET_SCHED_DFA_POST_CYCLE_INSN,
TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD,
TARGET_SCHED_INIT_DFA_BUBBLES, TARGET_SCHED_DFA_BUBBLE): New
macros.
(TARGET_SCHED): Use the new macros.

* target.h (use_dfa_pipeline_interface, init_dfa_pre_cycle_insn,
dfa_pre_cycle_insn, init_dfa_post_cycle_insn, dfa_post_cycle_insn,
first_cycle_multipass_dfa_lookahead, init_dfa_bubbles,
dfa_bubble): New members in gcc_target.sched.

        * haifa-sched.c (insert_schedule_bubbles_p): New variable.
(MAX_INSN_QUEUE_INDEX): New macro for automaton interface.
(insn_queue): Redefine it as pointer to array.
(NEXT_Q, NEXT_Q_AFTER): Use MAX_INSN_QUEUE_INDEX instead of
INSN_QUEUE_SIZE.
(max_insn_queue_index_macro_value): New variable.
(curr_state, dfa_state_size, ready_try): New varaibles for
automaton interface.
(ready_element, ready_remove, max_issue): New function prototypes
for automaton interface.
(choose_ready): New function prototype.
(insn_unit, blockage_range): Add comments.
(unit_last_insn, unit_tick, unit_n_insns): Define them for case
FUNCTION_UNITS_SIZE == 0.
(insn_issue_delay, actual_hazard_this_instance, schedule_unit,
actual_hazard, potential_hazard): Add comments.
(insn_cost): Use cost -1 as undefined value.  Remove
LINK_COST_ZERO and LINK_COST_FREE.  Add new code for automaton
pipeline interface.
(ready_element, ready_remove): New functions for automaton
interface.
(schedule_insn): Add new code for automaton pipeline interface.
(queue_to_ready): Add new code for automaton pipeline interface.
Use MAX_INSN_QUEUE_INDEX instead of INSN_QUEUE_SIZE.
(debug_ready_list): Print newline when the queue is empty.
(max_issue): New function for automaton pipeline interface.
(choose_ready): New function.
(schedule_block): Add new code for automaton pipeline interface.
Print ready list before scheduling each insn.
(sched_init): Add new code for automaton pipeline interface.
Initiate insn cost by -1.
(sched_finish): Free the current automaton state and finalize
automaton pipeline interface.

* sched-rgn.c: Include target.h.
(init_ready_list, new_ready, debug_dependencies): Add new code for
automaton pipeline interface.

* sched-vis.c: Include target.h.
(get_visual_tbl_length): Add code for automaton interface.
(target_units, print_block_visualization):  Add comments.

        * Makefile.in (GETRUNTIME, HASHTAB, HOST_GETRUNTIME, HOST_HASHTAB,
USE_HOST_GETRUNTIME, USE_HOST_HASHTAB, HOST_VARRAY): New variables.
(sched-rgn.o, sched-vis.o): Add new dependency file target.h.
(getruntime.o, genautomata.o): New entries.
(genattrtab.o): Add new dependency file genattrtab.h.
(genattrtab): Add new dependencies.  Link it with `libm.a'.
(getruntime.o, hashtab.o): New entries for canadian cross.

* doc/md.texi: Description of automaton based model.

* doc/tm.texi (TARGET_SCHED_ISSUE_RATE, TARGET_SCHED_ADJUST_COST):
Add comments.
(TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE,
TARGET_SCHED_DFA_PRE_CYCLE_INSN,
TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN,
TARGET_SCHED_DFA_POST_CYCLE_INSN,
TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN,
TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD,
TARGET_SCHED_INIT_DFA_BUBBLES, TARGET_SCHED_DFA_BUBBLE): The new
hook descriptions.
(TRADITIONAL_PIPELINE_INTERFACE, DFA_PIPELINE_INTERFACE,
MAX_DFA_ISSUE_RATE): New macro descriptions.

* doc/contrib.texi: Add dfa based scheduler contribution.

* doc/gcc.texi: Add more information about genattrtab.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@45202 138bc75d-0d04-0410-961f-82ee72b054a4

18 files changed:
gcc/ChangeLog
gcc/Makefile.in
gcc/doc/contrib.texi
gcc/doc/gcc.texi
gcc/doc/md.texi
gcc/doc/tm.texi
gcc/genattr.c
gcc/genattrtab.c
gcc/genattrtab.h [new file with mode: 0644]
gcc/genautomata.c [new file with mode: 0644]
gcc/haifa-sched.c
gcc/rtl.def
gcc/rtl.h
gcc/sched-int.h
gcc/sched-rgn.c
gcc/sched-vis.c
gcc/target-def.h
gcc/target.h

index 3b3c167..6e42ed1 100644 (file)
@@ -1,3 +1,118 @@
+2001-08-27  Vladimir Makarov  <vmakarov@touchme.toronto.redhat.com>
+
+        * rtl.def (DEFINE_CPU_UNIT, DEFINE_QUERY_CPU_UNIT, EXCLUSION_SET,
+       PRESENCE_SET, ABSENCE_SET, DEFINE_BYPASS, DEFINE_AUTOMATON,
+       AUTOMATA_OPTION, DEFINE_RESERVATION, DEFINE_INSN_RESERVATION): New
+       RTL constructions.
+       
+       * genattr.c (main): New variable num_insn_reservations.  Increase
+       it if there is DEFINE_INSN_RESERVATION.  Output automaton based
+       pipeline hazard recognizer interface.
+
+       * genattrtab.h: New file.
+       
+       * genattrtab.c: Include genattrtab.h.
+       (attr_printf, check_attr_test, make_internal_attr,
+       make_numeric_value): Move protypes into genattrtab.h.  Define them
+       as external.
+       (num_dfa_decls): New global variable.
+       (main): Process DEFINE_CPU_UNIT, DEFINE_QUERY_CPU_UNIT,
+       DEFINE_BYPASS, EXCLUSION_SET, PRESENCE_SET, ABSENCE_SET,
+       DEFINE_AUTOMATON, AUTOMATA_OPTION, DEFINE_RESERVATION,
+       DEFINE_INSN_RESERVATION.  Call expand_automata and write_automata.
+
+       * genautomata.c: New file.
+
+       * rtl.h (LINK_COST_ZERO, LINK_COST_FREE): Remove them.
+       
+        * sched-int.h: (curr_state): Add the external definition for
+       automaton pipeline interface.
+       (haifa_insn_data): Add comments for members blockage and units.
+       
+       * target-def.h (TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE,
+       TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN,
+       TARGET_SCHED_DFA_PRE_CYCLE_INSN,
+       TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN,
+       TARGET_SCHED_DFA_POST_CYCLE_INSN,
+       TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD,
+       TARGET_SCHED_INIT_DFA_BUBBLES, TARGET_SCHED_DFA_BUBBLE): New
+       macros.
+       (TARGET_SCHED): Use the new macros.
+
+       * target.h (use_dfa_pipeline_interface, init_dfa_pre_cycle_insn,
+       dfa_pre_cycle_insn, init_dfa_post_cycle_insn, dfa_post_cycle_insn,
+       first_cycle_multipass_dfa_lookahead, init_dfa_bubbles,
+       dfa_bubble): New members in gcc_target.sched.
+       
+        * haifa-sched.c (insert_schedule_bubbles_p): New variable.
+       (MAX_INSN_QUEUE_INDEX): New macro for automaton interface.
+       (insn_queue): Redefine it as pointer to array.
+       (NEXT_Q, NEXT_Q_AFTER): Use MAX_INSN_QUEUE_INDEX instead of
+       INSN_QUEUE_SIZE.
+       (max_insn_queue_index_macro_value): New variable.
+       (curr_state, dfa_state_size, ready_try): New varaibles for
+       automaton interface.
+       (ready_element, ready_remove, max_issue): New function prototypes
+       for automaton interface.
+       (choose_ready): New function prototype.
+       (insn_unit, blockage_range): Add comments.
+       (unit_last_insn, unit_tick, unit_n_insns): Define them for case
+       FUNCTION_UNITS_SIZE == 0.
+       (insn_issue_delay, actual_hazard_this_instance, schedule_unit,
+       actual_hazard, potential_hazard): Add comments.
+       (insn_cost): Use cost -1 as undefined value.  Remove
+       LINK_COST_ZERO and LINK_COST_FREE.  Add new code for automaton
+       pipeline interface.
+       (ready_element, ready_remove): New functions for automaton
+       interface.
+       (schedule_insn): Add new code for automaton pipeline interface.
+       (queue_to_ready): Add new code for automaton pipeline interface.
+       Use MAX_INSN_QUEUE_INDEX instead of INSN_QUEUE_SIZE.
+       (debug_ready_list): Print newline when the queue is empty.
+       (max_issue): New function for automaton pipeline interface.
+       (choose_ready): New function.
+       (schedule_block): Add new code for automaton pipeline interface.
+       Print ready list before scheduling each insn.
+       (sched_init): Add new code for automaton pipeline interface.
+       Initiate insn cost by -1.
+       (sched_finish): Free the current automaton state and finalize
+       automaton pipeline interface.
+       
+       * sched-rgn.c: Include target.h.
+       (init_ready_list, new_ready, debug_dependencies): Add new code for
+       automaton pipeline interface.
+
+       * sched-vis.c: Include target.h.
+       (get_visual_tbl_length): Add code for automaton interface.
+       (target_units, print_block_visualization):  Add comments.
+       
+        * Makefile.in (GETRUNTIME, HASHTAB, HOST_GETRUNTIME, HOST_HASHTAB,
+       USE_HOST_GETRUNTIME, USE_HOST_HASHTAB, HOST_VARRAY): New variables.
+       (sched-rgn.o, sched-vis.o): Add new dependency file target.h.
+       (getruntime.o, genautomata.o): New entries.
+       (genattrtab.o): Add new dependency file genattrtab.h.
+       (genattrtab): Add new dependencies.  Link it with `libm.a'.
+       (getruntime.o, hashtab.o): New entries for canadian cross.
+
+       * doc/md.texi: Description of automaton based model.
+       
+       * doc/tm.texi (TARGET_SCHED_ISSUE_RATE, TARGET_SCHED_ADJUST_COST):
+       Add comments.
+       (TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE,
+       TARGET_SCHED_DFA_PRE_CYCLE_INSN,
+       TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN,
+       TARGET_SCHED_DFA_POST_CYCLE_INSN,
+       TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN,
+       TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD,
+       TARGET_SCHED_INIT_DFA_BUBBLES, TARGET_SCHED_DFA_BUBBLE): The new
+       hook descriptions.
+       (TRADITIONAL_PIPELINE_INTERFACE, DFA_PIPELINE_INTERFACE,
+       MAX_DFA_ISSUE_RATE): New macro descriptions.
+       
+       * doc/contrib.texi: Add dfa based scheduler contribution.
+
+       * doc/gcc.texi: Add more information about genattrtab.
+
 2001-08-27  Diego Novillo  <dnovillo@redhat.com>
 
        * flow.c (flow_loop_dump): Do not display insn UIDs if this is not
index 90a1834..3ab9358 100644 (file)
@@ -346,6 +346,10 @@ INTL_SUBDIRS = intl $(POSUB)
 # system library.
 OBSTACK=obstack.o
 
+# The following object files is used by genautomata.
+GETRUNTIME = getruntime.o
+HASHTAB = hashtab.o
+
 # The GC method to be used on this system.
 GGC=@GGC@.o
 
@@ -482,6 +486,8 @@ HOST_CPPFLAGS=$(ALL_CPPFLAGS)
 HOST_OBSTACK=$(OBSTACK)
 HOST_VFPRINTF=$(VFPRINTF)
 HOST_DOPRINT=$(DOPRINT)
+HOST_GETRUNTIME=$(GETRUNTIME)
+HOST_HASHTAB=$(HASHTAB)
 HOST_STRSTR=$(STRSTR)
 
 # Actual name to use when installing a native compiler.
@@ -609,6 +615,8 @@ ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS)
 USE_HOST_OBSTACK= ` case "${HOST_OBSTACK}" in ?*) echo ${HOST_PREFIX}${HOST_OBSTACK} ;; esac `
 USE_HOST_VFPRINTF= ` case "${HOST_VFPRINTF}" in ?*) echo ${HOST_PREFIX}${HOST_VFPRINTF} ;; esac `
 USE_HOST_DOPRINT= ` case "${HOST_DOPRINT}" in ?*) echo ${HOST_PREFIX}${HOST_DOPRINT} ;; esac `
+USE_HOST_GETRUNTIME= ` case "${HOST_GETRUNTIME}" in ?*) echo ${HOST_PREFIX}${HOST_GETRUNTIME} ;; esac `
+USE_HOST_HASHTAB= ` case "${HOST_HASHTAB}" in ?*) echo ${HOST_PREFIX}${HOST_HASHTAB} ;; esac `
 USE_HOST_STRSTR= ` case "${HOST_STRSTR}" in ?*) echo ${HOST_PREFIX}${HOST_STRSTR} ;; esac `
 
 # Dependency on obstack or whatever library facilities
@@ -637,6 +645,7 @@ HOST_RTL = $(HOST_PREFIX)rtl.o read-rtl.o $(HOST_PREFIX)bitmap.o \
 
 HOST_PRINT = $(HOST_PREFIX)print-rtl.o
 HOST_ERRORS = $(HOST_PREFIX)errors.o
+HOST_VARRAY = $(HOST_PREFIX)varray.o
 
 # Specify the directories to be searched for header files.
 # Both . and srcdir are used, in that order,
@@ -1333,6 +1342,11 @@ obstack.o: $(srcdir)/../libiberty/obstack.c $(GCONFIG_H)
        $(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) \
                obstack.c $(OUTPUT_OPTION)
 
+getruntime.o: $(srcdir)/../libiberty/getruntime.c $(CONFIG_H)
+       rm -f getruntime.c
+       $(LN_S) $(srcdir)/../libiberty/getruntime.c getruntime.c
+       $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) getruntime.c
+
 prefix.o: prefix.c $(CONFIG_H) $(SYSTEM_H) Makefile prefix.h
        $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
        -DPREFIX=\"$(prefix)\" \
@@ -1533,12 +1547,13 @@ sched-deps.o : sched-deps.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) sched-int.h \
    $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h cselib.h $(PARAMS_H) $(TM_P_H)
 sched-rgn.o : sched-rgn.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) sched-int.h \
    $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
-   $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H)
+   $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H) $(TARGET_H)
 sched-ebb.o : sched-ebb.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) sched-int.h \
    $(BASIC_BLOCK_H) $(REGS_H) hard-reg-set.h flags.h insn-config.h function.h \
    $(INSN_ATTR_H) toplev.h $(RECOG_H) except.h $(TM_P_H)
 sched-vis.o : sched-vis.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) sched-int.h \
-   hard-reg-set.h $(BASIC_BLOCK_H) $(INSN_ATTR_H) $(REGS_H) $(TM_P_H)
+   hard-reg-set.h $(BASIC_BLOCK_H) $(INSN_ATTR_H) $(REGS_H) $(TM_P_H) \
+   $(TARGET_H)
 final.o : final.c $(CONFIG_H) $(SYSTEM_H) $(RTL_H) $(TREE_H) flags.h intl.h \
    $(REGS_H) $(RECOG_H) conditions.h insn-config.h $(INSN_ATTR_H) function.h \
    real.h output.h hard-reg-set.h except.h debug.h xcoffout.h \
@@ -1842,14 +1857,18 @@ genattr$(build_exeext) : genattr.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HO
 genattr.o : genattr.c $(RTL_H) $(HCONFIG_H) $(SYSTEM_H) errors.h gensupport.h
        $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genattr.c
 
-genattrtab$(build_exeext) : genattrtab.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS)
+genattrtab$(build_exeext) : genattrtab.o genautomata.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_VARRAY) $(HOST_PREFIX)$(HOST_GETRUNTIME) $(HOST_LIBDEPS)
        $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
-        genattrtab.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS)
+        genattrtab.o genautomata.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_VARRAY) $(USE_HOST_GETRUNTIME) $(HOST_LIBS) -lm
 
 genattrtab.o : genattrtab.c $(RTL_H) $(OBSTACK_H) $(HCONFIG_H) \
-  $(SYSTEM_H) errors.h $(GGC_H) gensupport.h
+  $(SYSTEM_H) errors.h $(GGC_H) gensupport.h genattrtab.h
        $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genattrtab.c
 
+genautomata.o : genautomata.c $(RTL_H) $(OBSTACK_H) $(HCONFIG_H) \
+  $(SYSTEM_H) errors.h varray.h hash.h genattrtab.h
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(srcdir)/genautomata.c
+
 genoutput$(build_exeext) : genoutput.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBDEPS)
        $(HOST_CC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $@ \
         genoutput.o $(HOST_RTL) $(HOST_PRINT) $(HOST_ERRORS) $(HOST_LIBS)
@@ -1900,6 +1919,16 @@ $(HOST_PREFIX_1)obstack.o: $(srcdir)/../libiberty/obstack.c $(HCONFIG_H)
        sed -e 's/config[.]h/hconfig.h/' $(srcdir)/../libiberty/obstack.c > $(HOST_PREFIX)obstack.c
        $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)obstack.c
 
+$(HOST_PREFIX_1)getruntime.o: $(srcdir)/../libiberty/getruntime.c
+       rm -f $(HOST_PREFIX)getruntime.c
+       sed -e 's/config[.]h/hconfig.h/' $(srcdir)/../libiberty/getruntime.c > $(HOST_PREFIX)getruntime.c
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)getruntime.c
+
+$(HOST_PREFIX_1)hashtab.o: $(srcdir)/../libiberty/hashtab.c
+       rm -f $(HOST_PREFIX)hashtab.c
+       sed -e 's/config[.]h/hconfig.h/' $(srcdir)/../libiberty/hashtab.c > $(HOST_PREFIX)hashtab.c
+       $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)hashtab.c
+
 $(HOST_PREFIX_1)vfprintf.o: $(srcdir)/../libiberty/vfprintf.c $(HCONFIG_H)
        rm -f $(HOST_PREFIX)vfprintf.c
        sed -e 's/config[.]h/hconfig.h/' $(srcdir)/../libiberty/vfprintf.c > $(HOST_PREFIX)vfprintf.c
index caaf15b..a60b25e 100644 (file)
@@ -313,9 +313,10 @@ Andrew MacLeod for his ongoing work in building a real EH system,
 various code generation improvements, work on the global optimizer, etc.
 
 @item
-Vladimir Makarov for hacking some ugly i960 problems, PowerPC
-hacking improvements to compile-time performance and overall knowledge
-and direction in the area of instruction scheduling.
+Vladimir Makarov for hacking some ugly i960 problems, PowerPC hacking
+improvements to compile-time performance, overall knowledge and
+direction in the area of instruction scheduling, and design and
+implementation of the automaton based instruction scheduler.
 
 @item
 Bob Manson for his behind the scenes work on dejagnu.
index befee36..0a048a8 100644 (file)
@@ -3826,8 +3826,10 @@ Several passes use instruction attributes.  A definition of the
 attributes defined for a particular machine is in file
 @file{insn-attr.h}, which is generated from the machine description by
 the program @file{genattr}.  The file @file{insn-attrtab.c} contains
-subroutines to obtain the attribute values for insns.  It is generated
-from the machine description by the program @file{genattrtab}.
+subroutines to obtain the attribute values for insns and information
+about processor pipeline characteristics for the instruction scheduler.
+It is generated from the machine description by the program
+@file{genattrtab}.
 @end itemize
 @end ifset
 
index f2e7b8f..f6349ae 100644 (file)
@@ -3676,13 +3676,14 @@ in the compiler.
 @cindex instruction splitting
 @cindex splitting instructions
 
-There are two cases where you should specify how to split a pattern into
-multiple insns.  On machines that have instructions requiring delay
-slots (@pxref{Delay Slots}) or that have instructions whose output is
-not available for multiple cycles (@pxref{Function Units}), the compiler
-phases that optimize these cases need to be able to move insns into
-one-instruction delay slots.  However, some insns may generate more than one
-machine instruction.  These insns cannot be placed into a delay slot.
+There are two cases where you should specify how to split a pattern
+into multiple insns.  On machines that have instructions requiring
+delay slots (@pxref{Delay Slots}) or that have instructions whose
+output is not available for multiple cycles (@pxref{Processor pipeline
+description}), the compiler phases that optimize these cases need to
+be able to move insns into one-instruction delay slots.  However, some
+insns may generate more than one machine instruction.  These insns
+cannot be placed into a delay slot.
 
 Often you can rewrite the single insn as a list of individual insns,
 each corresponding to one machine instruction.  The disadvantage of
@@ -4227,7 +4228,7 @@ to track the condition codes.
 * Insn Lengths::        Computing the length of insns.
 * Constant Attributes:: Defining attributes that are constant.
 * Delay Slots::         Defining delay slots required for a machine.
-* Function Units::      Specifying information for insn scheduling.
+* Processor pipeline description:: Specifying information for insn scheduling.
 @end menu
 
 @node Defining Attributes
@@ -4857,14 +4858,101 @@ branch is true, we might represent this as follows:
 @end smallexample
 @c the above is *still* too long.  --mew 4feb93
 
-@node Function Units
-@subsection Specifying Function Units
+@node Processor pipeline description
+@subsection Specifying processor pipeline description
+@cindex processor pipeline description
+@cindex processor functional units
+@cindex instruction latency time
+@cindex interlock delays
+@cindex data dependence delays
+@cindex reservation delays
+@cindex pipeline hazard recognizer
+@cindex automaton based pipeline description
+@cindex regular expressions
+@cindex deterministic finite state automaton
+@cindex automaton based scheduler
+@cindex RISC
+@cindex VLIW
+
+To achieve better productivity most modern processors
+(super-pipelined, superscalar @acronym{RISC}, and @acronym{VLIW}
+processors) have many @dfn{functional units} on which several
+instructions can be executed simultaneously.  An instruction starts
+execution if its issue conditions are satisfied.  If not, the
+instruction is interlocked until its conditions are satisfied.  Such
+@dfn{interlock (pipeline) delay} causes interruption of the fetching
+of successor instructions (or demands nop instructions, e.g. for some
+MIPS processors).
+
+There are two major kinds of interlock delays in modern processors.
+The first one is a data dependence delay determining @dfn{instruction
+latency time}.  The instruction execution is not started until all
+source data have been evaluated by prior instructions (there are more
+complex cases when the instruction execution starts even when the data
+are not availaible but will be ready in given time after the
+instruction execution start).  Taking the data dependence delays into
+account is simple.  The data dependence (true, output, and
+anti-dependence) delay between two instructions is given by a
+constant.  In most cases this approach is adequate.  The second kind
+of interlock delays is a reservation delay.  The reservation delay
+means that two instructions under execution will be in need of shared
+processors resources, i.e. buses, internal registers, and/or
+functional units, which are reserved for some time.  Taking this kind
+of delay into account is complex especially for modern @acronym{RISC}
+processors.
+
+The task of exploiting more processor parallelism is solved by an
+instruction scheduler.  For better solution of this problem, the
+instruction scheduler has to have an adequate description of the
+processor parallelism (or @dfn{pipeline description}).  Currently GCC
+has two ways to describe processor parallelism.  The first one is old
+and originated from instruction scheduler written by Michael Tiemann
+and described in the first subsequent section.  The second one was
+created later.  It is based on description of functional unit
+reservations by processor instructions with the aid of @dfn{regular
+expressions}.  This is so called @dfn{automaton based description}.
+
+Gcc instruction scheduler uses a @dfn{pipeline hazard recognizer} to
+figure out the possibility of the instruction issue by the processor
+on given simulated processor cycle.  The pipeline hazard recognizer is
+a code generated from the processor pipeline description.  The
+pipeline hazard recognizer generated from the automaton based
+description is more sophisticated and based on deterministic finite
+state automaton (@acronym{DFA}) and therefore faster than one
+generated from the old description.  Also its speed is not depended on
+processor complexity.  The instruction issue is possible if there is
+a transition from one automaton state to another one.
+
+You can use any model to describe processor pipeline characteristics
+or even a mix of them.  You could use the old description for some
+processor submodels and the @acronym{DFA}-based one for the rest
+processor submodels.
+
+In general, the usage of the automaton based description is more
+preferable.  Its model is more rich.  It permits to describe more
+accurately pipeline characteristics of processors which results in
+improving code quality (although sometimes only on several percent
+fractions).  It will be also used as an infrastructure to implement
+sophisticated and practical insn scheduling which will try many
+instruction sequences to choose the best one.
+
+
+@menu
+* Old pipeline description:: Specifying information for insn scheduling.
+* Automaton pipeline description:: Describing insn pipeline characteristics.
+* Comparison of the two descriptions:: Drawbacks of the old pipeline description
+@end menu
+
+@node Old pipeline description
+@subsubsection Specifying Function Units
+@cindex old pipeline description
 @cindex function units, for scheduling
 
-On most RISC machines, there are instructions whose results are not
-available for a specific number of cycles.  Common cases are instructions
-that load data from memory.  On many machines, a pipeline stall will result
-if the data is referenced too soon after the load instruction.
+On most @acronym{RISC} machines, there are instructions whose results
+are not available for a specific number of cycles.  Common cases are
+instructions that load data from memory.  On many machines, a pipeline
+stall will result if the data is referenced too soon after the load
+instruction.
 
 In addition, many newer microprocessors have multiple function units, usually
 one for integer and one for floating point, and often will incur pipeline
@@ -4878,13 +4966,14 @@ due to function unit conflicts.
 
 For the purposes of the specifications in this section, a machine is
 divided into @dfn{function units}, each of which execute a specific
-class of instructions in first-in-first-out order.  Function units that
-accept one instruction each cycle and allow a result to be used in the
-succeeding instruction (usually via forwarding) need not be specified.
-Classic RISC microprocessors will normally have a single function unit,
-which we can call @samp{memory}.  The newer ``superscalar'' processors
-will often have function units for floating point operations, usually at
-least a floating point adder and multiplier.
+class of instructions in first-in-first-out order.  Function units
+that accept one instruction each cycle and allow a result to be used
+in the succeeding instruction (usually via forwarding) need not be
+specified.  Classic @acronym{RISC} microprocessors will normally have
+a single function unit, which we can call @samp{memory}.  The newer
+``superscalar'' processors will often have function units for floating
+point operations, usually at least a floating point adder and
+multiplier.
 
 @findex define_function_unit
 Each usage of a function units by a class of insns is specified with a
@@ -4947,10 +5036,10 @@ Typical uses of this vector are where a floating point function unit can
 pipeline either single- or double-precision operations, but not both, or
 where a memory unit can pipeline loads, but not stores, etc.
 
-As an example, consider a classic RISC machine where the result of a
-load instruction is not available for two cycles (a single ``delay''
-instruction is required) and where only one load instruction can be executed
-simultaneously.  This would be specified as:
+As an example, consider a classic @acronym{RISC} machine where the
+result of a load instruction is not available for two cycles (a single
+``delay'' instruction is required) and where only one load instruction
+can be executed simultaneously.  This would be specified as:
 
 @smallexample
 (define_function_unit "memory" 1 1 (eq_attr "type" "load") 2 0)
@@ -4975,6 +5064,374 @@ units.  These insns will cause a potential conflict for the second unit
 used during their execution and there is no way of representing that
 conflict.  We welcome any examples of how function unit conflicts work
 in such processors and suggestions for their representation.
+
+@node Automaton pipeline description
+@subsubsection Describing instruction pipeline characteristics
+@cindex automaton based pipeline description
+
+This section describes constructions of the automaton based processor
+pipeline description.  The order of all mentioned below constructions
+in the machine description file is not important.
+
+@findex define_automaton
+@cindex pipeline hazard recognizer
+The following optional construction describes names of automata
+generated and used for the pipeline hazards recognition.  Sometimes
+the generated finite state automaton used by the pipeline hazard
+recognizer is large.  If we use more one automaton and bind functional
+units to the automata, the summary size of the automata usually is
+less than the size of the single automaton.  If there is no one such
+construction, only one finite state automaton is generated.
+
+@smallexample
+(define_automaton @var{automata-names})
+@end smallexample
+
+@var{automata-names} is a string giving names of the automata.  The
+names are separated by commas.  All the automata should have unique names.
+The automaton name is used in construction @code{define_cpu_unit} and
+@code{define_query_cpu_unit}.
+
+@findex define_cpu_unit
+@cindex processor functional units
+Each processor functional unit used in description of instruction
+reservations should be described by the following construction.
+
+@smallexample
+(define_cpu_unit @var{unit-names} [@var{automaton-name}])
+@end smallexample
+
+@var{unit-names} is a string giving the names of the functional units
+separated by commas.  Don't use name @samp{nothing}, it is reserved
+for other goals.
+
+@var{automaton-name} is a string giving the name of automaton with
+which the unit is bound.  The automaton should be described in
+construction @code{define_automaton}.  You should give
+@dfn{automaton-name}, if there is a defined automaton.
+
+@findex define_query_cpu_unit
+@cindex querying function unit reservations
+The following construction describes CPU functional units analogously
+to @code{define_cpu_unit}.  If we use automata without their
+minimization, the reservation of such units can be queried for an
+automaton state.  The instruction scheduler never queries reservation
+of functional units for given automaton state.  So as a rule, you
+don't need this construction.  This construction could be used for
+future code generation goals (e.g. to generate @acronym{VLIW} insn
+templates).
+
+@smallexample
+(define_query_cpu_unit @var{unit-names} [@var{automaton-name}])
+@end smallexample
+
+@var{unit-names} is a string giving names of the functional units
+separated by commas.
+
+@var{automaton-name} is a string giving name of the automaton with
+which the unit is bound.
+
+@findex define_insn_reservation
+@cindex instruction latency time
+@cindex regular expressions
+@cindex data bypass
+The following construction is major one to describe pipeline
+characteristics of an instruction.
+
+@smallexample
+(define_insn_reservation @var{insn-name} @var{default_latency}
+                         @var{condition} @var{regexp})
+@end smallexample
+
+@var{default_latency} is a number giving latency time of the
+instruction.
+
+@var{insn-names} is a string giving internal name of the insn.  The
+internal names are used in constructions @code{define_bypass} and in
+the automaton description file generated for debugging.  The internal
+name has nothing common with the names in @code{define_insn}.  It is a
+good practice to use insn classes described in the processor manual.
+
+@var{condition} defines what RTL insns are described by this
+construction.
+
+@var{regexp} is a string describing reservation of the cpu functional
+units by the instruction.  The reservations are described by a regular
+expression according to the following syntax:
+
+@smallexample
+       regexp = regexp "," oneof
+              | oneof
+
+       oneof = oneof "|" allof
+             | allof
+
+       allof = allof "+" repeat
+             | repeat
+       repeat = element "*" number
+              | element
+
+       element = cpu_function_unit_name
+               | reservation_name
+               | result_name
+               | "nothing"
+               | "(" regexp ")"
+@end smallexample
+
+@itemize @bullet
+@item
+@samp{,} is used for describing the start of the next cycle in
+the reservation.
+
+@item
+@samp{|} is used for describing a reservation described by the first
+regular expression @strong{or} a reservation described by the second
+regular expression @strong{or} etc.
+
+@item
+@samp{+} is used for describing a reservation described by the first
+regular expression @strong{and} a reservation described by the
+second regular expression @strong{and} etc.
+
+@item
+@samp{*} is used for convenience and simply means a sequence in which
+the regular expression are repeated @var{number} times with cycle
+advancing (see @samp{,}).
+
+@item
+@samp{cpu_function_unit_name} denotes reservation of the named
+functional unit.
+
+@item
+@samp{reservation_name} --- see description of construction
+@samp{define_reservation}.
+
+@item
+@samp{nothing} denotes no unit reservations.
+@end itemize
+
+@findex define_reservation
+Sometimes unit reservations for different insns contain common parts.
+In such case, you can simplify the pipeline description by describing
+the common part by the following construction
+
+@smallexample
+(define_reservation @var{reservation-name} @var{regexp})
+@end smallexample
+
+@var{reservation-name} is a string giving name of @var{regexp}.
+Functional unit names and reservation names are in the same name
+space.  So the reservation names should be different from the
+functional unit names and can not be reserved name @samp{nothing}.
+
+@findex define_bypass
+@cindex instruction latency time
+@cindex data bypass
+The following construction is used to describe exceptions in the
+latency time for given instruction pair.  This is so called bypasses.
+
+@smallexample
+(define_bypass @var{number} @var{out_insn_names} @var{in_insn_names}
+               [@var{guard}])
+@end smallexample
+
+@var{number} defines when the result generated by the instructions
+given in string @var{out_insn_names} will be ready for the
+instructions given in string @var{in_insn_names}.  The instructions in
+the string are separated by commas.
+
+@var{guard} is an optional string giving name of a C function which
+defines an additional guard for the bypass.  The function will get the
+two insns as parameters.  If the function returns zero the bypass will
+be ignored for this case.  The additional guard is necessary to
+recognize complicated bypasses, e.g. when consumer is only an address
+of insn @samp{store} (not a stored value).
+
+@findex exclusion_set
+@findex presence_set
+@findex absence_set
+@cindex VLIW
+@cindex RISC
+Usually the following three constructions are used to describe
+@acronym{VLIW} processors (more correctly to describe a placement of
+small insns into @acronym{VLIW} insn slots).  Although they can be
+used for @acronym{RISC} processors too.
+
+@smallexample
+(exclusion_set @var{unit-names} @var{unit-names})
+(presence_set @var{unit-names} @var{unit-names})
+(absence_set @var{unit-names} @var{unit-names})
+@end smallexample
+
+@var{unit-names} is a string giving names of functional units
+separated by commas.
+
+The first construction (@samp{exclusion_set}) means that each
+functional unit in the first string can not be reserved simultaneously
+with a unit whose name is in the second string and vice versa.  For
+example, the construction is useful for describing processors
+(e.g. some SPARC processors) with a fully pipelined floating point
+functional unit which can execute simultaneously only single floating
+point insns or only double floating point insns.
+
+The second construction (@samp{presence_set}) means that each
+functional unit in the first string can not be reserved unless at
+least one of units whose names are in the second string is reserved.
+This is an asymmetric relation.  For example, it is useful for
+description that @acronym{VLIW} @samp{slot1} is reserved after
+@samp{slot0} reservation.
+
+The third construction (@samp{absence_set}) means that each functional
+unit in the first string can be reserved only if each unit whose name
+is in the second string is not reserved.  This is an asymmetric
+relation (actually @samp{exclusion_set} is analogous to this one but
+it is symmetric).  For example, it is useful for description that
+@acronym{VLIW} @samp{slot0} can not be reserved after @samp{slot1} or
+@samp{slot2} reservation.
+
+@findex automata_option
+@cindex deterministic finite state automaton
+@cindex nondeterministic finite state automaton
+@cindex finite state automaton minimization
+You can control the generator of the pipeline hazard recognizer with
+the following construction.
+
+@smallexample
+(automata_option @var{options})
+@end smallexample
+
+@var{options} is a string giving options which affect the generated
+code.  Currently there are the following options:
+
+@itemize @bullet
+@item
+@dfn{no-minimization} makes no minimization of the automaton.  This is
+only worth to do when we are going to query CPU functional unit
+reservations in an automaton state.
+
+@item
+@dfn{w} means a generation of the file describing the result
+automaton.  The file can be used to verify the description.
+
+@item
+@dfn{ndfa} makes nondeterministic finite state automata.  This affects
+the treatment of operator @samp{|} in the regular expressions.  The
+usual treatment of the operator is to try the first alternative and,
+if the reservation is not possible, the second alternative.  The
+nondeterministic treatment means trying all alternatives, some of them
+may be rejected by reservations in the subsequent insns.  You can not
+query functional unit reservations in nondeterministic automaton
+states.
+@end itemize
+
+As an example, consider a superscalar @acronym{RISC} machine which can
+issue three insns (two integer insns and one floating point insn) on
+the cycle but can finish only two insns.  To describe this, we define
+the following functional units.
+
+@smallexample
+(define_cpu_unit "i0_pipeline, i1_pipeline, f_pipeline")
+(define_cpu_unit "port_0, port1")
+@end smallexample
+
+All simple integer insns can be executed in any integer pipeline and
+their result is ready in two cycles.  The simple integer insns are
+issued into the first pipeline unless it is reserved, otherwise they
+are issued into the second pipeline.  Integer division and
+multiplication insns can be executed only in the second integer
+pipeline and their results are ready correspondingly in 8 and 4
+cycles.  The integer division is not pipelined, i.e. the subsequent
+integer division insn can not be issued until the current division
+insn finished.  Floating point insns are fully pipelined and their
+results are ready in 3 cycles.  There is also additional one cycle
+delay in the usage by integer insns of result produced by floating
+point insns.  To describe all of this we could specify
+
+@smallexample
+(define_cpu_unit "div")
+
+(define_insn_reservation "simple" 2 (eq_attr "cpu" "int")
+                         "(i0_pipeline | i1_pipeline), (port_0 | port1)")
+
+(define_insn_reservation "mult" 4 (eq_attr "cpu" "mult")
+                         "i1_pipeline, nothing*3, (port_0 | port1)")
+
+(define_insn_reservation "div" 8 (eq_attr "cpu" "div")
+                         "i1_pipeline, div*7, (port_0 | port1)")
+
+(define_insn_reservation "float" 3 (eq_attr "cpu" "float")
+                         "f_pipeline, nothing, (port_0 | port1))
+
+(define_bypass 4 "float" "simple,mut,div")
+@end smallexample
+
+To simplify the description we could describe the following reservation
+
+@smallexample
+(define_reservation "finish" "port0|port1")
+@end smallexample
+
+and use it in all @code{define_insn_reservation} as in the following
+construction
+
+@smallexample
+(define_insn_reservation "simple" 2 (eq_attr "cpu" "int")
+                         "(i0_pipeline | i1_pipeline), finish")
+@end smallexample
+
+
+@node Comparison of the two descriptions
+@subsubsection Drawbacks of the old pipeline description
+@cindex old pipeline description
+@cindex automaton based pipeline description
+@cindex processor functional units
+@cindex interlock delays
+@cindex instruction latency time
+@cindex pipeline hazard recognizer
+@cindex data bypass
+
+The old instruction level parallelism description and the pipeline
+hazards recognizer based on it have the following drawbacks in
+comparison with the @acronym{DFA}-based ones:
+  
+@itemize @bullet
+@item
+Each functional unit is believed to be reserved at the instruction
+execution start.  This is a very inaccurate model for modern
+processors.
+
+@item
+An inadequate description of instruction latency times.  The latency
+time is bound with a functional unit reserved by an instruction not
+with the instruction itself.  In other words, the description is
+oriented to describe at most one unit reservation by each instruction.
+It also does not permit to describe special bypasses between
+instruction pairs.
+
+@item
+The implementation of the pipeline hazard recognizer interface has
+constraints on number of functional units.  This is a number of bits
+in integer on the host machine.
+
+@item
+The interface to the pipeline hazard recognizer is more complex than
+one to the automaton based pipeline recognizer.
+
+@item
+An unnatural description when you write an unit and a condition which
+selects instructions using the unit.  Writing all unit reservations
+for an instruction (an instruction class) is more natural.
+
+@item
+The recognition of the interlock delays has slow implementation.  GCC
+scheduler supports structures which describe the unit reservations.
+The more processor has functional units, the slower pipeline hazard
+recognizer.  Such implementation would become slower when we enable to
+reserve functional units not only at the instruction execution start.
+The automaton based pipeline hazard recognizer speed is not depended
+on processor complexity.
+@end itemize
 @end ifset
 
 @node Conditional Execution
index 80e8e75..6368b43 100644 (file)
@@ -5446,11 +5446,19 @@ hooks for this purpose.  It is usually enough to define just a few of
 them: try the first ones in this list first.
 
 @deftypefn {Target Hook} int TARGET_SCHED_ISSUE_RATE (void)
-This hook returns the maximum number of instructions that can ever issue
-at the same time on the target machine.  The default is one.  This value
-must be constant over the entire compilation.  If you need it to vary
-depending on what the instructions are, you must use
+This hook returns the maximum number of instructions that can ever
+issue at the same time on the target machine.  The default is one.
+Although the insn scheduler can define itself the possibility of issue
+an insn on the same cycle, the value can serve as an additional
+constraint to issue insns on the same simulated processor cycle (see
+hooks @samp{TARGET_SCHED_REORDER} and @samp{TARGET_SCHED_REORDER2}).
+This value must be constant over the entire compilation.  If you need
+it to vary depending on what the instructions are, you must use
 @samp{TARGET_SCHED_VARIABLE_ISSUE}.
+
+You could use the value of macro @samp{MAX_DFA_ISSUE_RATE} to return
+the value of the hook @samp{TARGET_SCHED_ISSUE_RATE} for the automaton
+based pipeline interface.
 @end deftypefn
 
 @deftypefn {Target Hook} int TARGET_SCHED_VARIABLE_ISSUE (FILE *@var{file}, int @var{verbose}, rtx @var{insn}, int @var{more})
@@ -5466,12 +5474,17 @@ instruction that was scheduled.
 @end deftypefn
 
 @deftypefn {Target Hook} int TARGET_SCHED_ADJUST_COST (rtx @var{insn}, rtx @var{link}, rtx @var{dep_insn}, int @var{cost})
-This function corrects the value of @var{cost} based on the relationship
-between @var{insn} and @var{dep_insn} through the dependence @var{link}.
-It should return the new value.  The default is to make no adjustment to
-@var{cost}.  This can be used for example to specify to the scheduler
+This function corrects the value of @var{cost} based on the
+relationship between @var{insn} and @var{dep_insn} through the
+dependence @var{link}.  It should return the new value.  The default
+is to make no adjustment to @var{cost}.  This can be used for example
+to specify to the scheduler using the traditional pipeline description
 that an output- or anti-dependence does not incur the same cost as a
-data-dependence.
+data-dependence.  If the scheduler using the automaton based pipeline
+description, the cost of anti-dependence is zero and the cost of
+output-dependence is maximum of one and the difference of latency
+times of the first and the second insns.  If these values are not
+acceptable, you could use the hook to modify them too.
 @end deftypefn
 
 @deftypefn {Target Hook} int TARGET_SCHED_ADJUST_PRIORITY (rtx @var{insn}, int @var{priority})
@@ -5537,6 +5550,140 @@ RTL dumps and assembly output.  Define this hook only if you need this
 level of detail about what the scheduler is doing.
 @end deftypefn
 
+@deftypefn {Target Hook} int TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE (void)
+This hook is called many times during insn scheduling.  If the hook
+returns nonzero, the automaton based pipeline description is used for
+insn scheduling.  Otherwise the traditional pipeline description is
+used.  The default is usage of the traditional pipeline description.
+
+You should also remember that to simplify the insn scheduler sources
+an empty traditional pipeline description interface is generated even
+if there is no a traditional pipeline description in the @file{.md}
+file.  The same is true for the automaton based pipeline description.
+That means that you should be accurate in defining the hook.
+@end deftypefn
+
+@deftypefn {Target Hook} int TARGET_SCHED_DFA_PRE_CYCLE_INSN (void)
+The hook returns an RTL insn.  The automaton state used in the
+pipeline hazard recognizer is changed as if the insn were scheduled
+when the new simulated processor cycle starts.  Usage of the hook may
+simplify the automaton pipeline description for some @acronym{VLIW}
+processors.  If the hook is defined, it is used only for the automaton
+based pipeline description.  The default is not to change the state
+when the new simulated processor cycle starts.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN (void)
+The hook can be used to initialize data used by the previous hook.
+@end deftypefn
+
+@deftypefn {Target Hook} int TARGET_SCHED_DFA_POST_CYCLE_INSN (void)
+The hook is analogous to @samp{TARGET_SCHED_DFA_PRE_CYCLE_INSN} but used
+to changed the state as if the insn were scheduled when the new
+simulated processor cycle finishes.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN (void)
+The hook is analogous to @samp{TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN} but
+used to initialize data used by the previous hook.
+@end deftypefn
+
+@deftypefn {Target Hook} int TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD (void)
+This hook controls better choosing an insn from the ready insn queue
+for the @acronym{DFA}-based insn scheduler.  Usually the scheduler
+chooses the first insn from the queue.  If the hook returns a positive
+value, an additional scheduler code tries all permutations of
+@samp{TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD ()}
+subsequent ready insns to choose an insn whose issue will result in
+maximal number of issued insns on the same cycle.  For the
+@acronym{VLIW} processor, the code could actually solve the problem of
+packing simple insns into the @acronym{VLIW} insn.  Of course, if the
+rules of @acronym{VLIW} packing are described in the automaton.
+
+This code also could be used for superscalar @acronym{RISC}
+processors.  Let us consider a superscalar @acronym{RISC} processor
+with 3 pipelines.  Some insns can be executed in pipelines @var{A} or
+@var{B}, some insns can be executed only in pipelines @var{B} or
+@var{C}, and one insn can be executed in pipeline @var{B}.  The
+processor may issue the 1st insn into @var{A} and the 2nd one into
+@var{B}.  In this case, the 3rd insn will wait for freeing @var{B}
+until the next cycle.  If the scheduler issues the 3rd insn the first,
+the processor could issue all 3 insns per cycle.
+
+Actually this code demonstrates advantages of the automaton based
+pipeline hazard recognizer.  We try quickly and easy many insn
+schedules to choose the best one.
+
+The default is no multipass scheduling.
+@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_SCHED_INIT_DFA_BUBBLES (void)
+The @acronym{DFA}-based scheduler could take the insertion of nop
+operations for better insn scheduling into account.  It can be done
+only if the multi-pass insn scheduling works (see hook
+@samp{TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD}).
+
+Let us consider a @acronym{VLIW} processor insn with 3 slots.  Each
+insn can be placed only in one of the three slots.  We have 3 ready
+insns @var{A}, @var{B}, and @var{C}.  @var{A} and @var{C} can be
+placed only in the 1st slot, @var{B} can be placed only in the 3rd
+slot.  We described the automaton which does not permit empty slot
+gaps between insns (usually such description is simpler).  Without
+this code the scheduler would place each insn in 3 separate
+@acronym{VLIW} insns.  If the scheduler places a nop insn into the 2nd
+slot, it could place the 3 insns into 2 @acronym{VLIW} insns.  What is
+the nop insn is returned by hook @samp{TARGET_SCHED_DFA_BUBBLE}.  Hook
+@samp{TARGET_SCHED_INIT_DFA_BUBBLES} can be used to initialize or
+create the nop insns.
+
+You should remember that the scheduler does not insert the nop insns.
+It is not wise because of the following optimizations.  The scheduler
+only considers such possibility to improve the result schedule.  The
+nop insns should be inserted lately, e.g. on the final phase.
+@end deftypefn
+
+@deftypefn {Target Hook} rtx TARGET_SCHED_DFA_BUBBLE (int @var{index})
+This hook @samp{FIRST_CYCLE_MULTIPASS_SCHEDULING} is used to insert
+nop operations for better insn scheduling when @acronym{DFA}-based
+scheduler makes multipass insn scheduling (see also description of
+hook @samp{TARGET_SCHED_INIT_DFA_BUBBLES}).  This hook
+returns a nop insn with given @var{index}.  The indexes start with
+zero.  The hook should return @code{NULL} if there are no more nop
+insns with indexes greater than given index.
+@end deftypefn
+
+Macros in the following table are generated by the program
+@file{genattr} and can be useful for writing the hooks.
+
+@table @code
+@findex TRADITIONAL_PIPELINE_INTERFACE
+@item TRADITIONAL_PIPELINE_INTERFACE
+The macro definition is generated if there is a traditional pipeline
+description in @file{.md} file. You should also remember that to
+simplify the insn scheduler sources an empty traditional pipeline
+description interface is generated even if there is no a traditional
+pipeline description in the @file{.md} file.  The macro can be used to
+distinguish the two types of the traditional interface.
+
+@findex DFA_PIPELINE_INTERFACE
+@item DFA_PIPELINE_INTERFACE
+The macro definition is generated if there is an automaton pipeline
+description in @file{.md} file.  You should also remember that to
+simplify the insn scheduler sources an empty automaton pipeline
+description interface is generated even if there is no an automaton
+pipeline description in the @file{.md} file.  The macro can be used to
+distinguish the two types of the automaton interface.
+
+@findex MAX_DFA_ISSUE_RATE
+@item MAX_DFA_ISSUE_RATE
+The macro definition is generated in the automaton based pipeline
+description interface.  Its value is calculated from the automaton
+based pipeline description and is equal to maximal number of all insns
+described in constructions @samp{define_insn_reservation} which can be
+issued on the same processor cycle.
+
+@end table
+
 @node Sections
 @section Dividing the Output into Sections (Texts, Data, @dots{})
 @c the above section title is WAY too long.  maybe cut the part between
index cbb1175..dd07899 100644 (file)
@@ -193,6 +193,7 @@ main (argc, argv)
   int have_delay = 0;
   int have_annul_true = 0;
   int have_annul_false = 0;
+  int num_insn_reservations = 0;
   int num_units = 0;
   struct range all_simultaneity, all_multiplicity;
   struct range all_ready_cost, all_issue_delay, all_blockage;
@@ -308,10 +309,18 @@ main (argc, argv)
          extend_range (&all_issue_delay,
                        unit->issue_delay.min, unit->issue_delay.max);
        }
+      else if (GET_CODE (desc) == DEFINE_INSN_RESERVATION)
+       num_insn_reservations++;
     }
 
-  if (num_units > 0)
+  if (num_units > 0 || num_insn_reservations > 0)
     {
+      if (num_units > 0)
+       printf ("#define TRADITIONAL_PIPELINE_INTERFACE 1\n");
+
+      if (num_insn_reservations > 0)
+       printf ("#define DFA_PIPELINE_INTERFACE 1\n");
+
       /* Compute the range of blockage cost values.  See genattrtab.c
         for the derivation.  BLOCKAGE (E,C) when SIMULTANEITY is zero is
 
@@ -348,6 +357,96 @@ main (argc, argv)
 
       write_units (num_units, &all_multiplicity, &all_simultaneity,
                   &all_ready_cost, &all_issue_delay, &all_blockage);
+
+      /* Output interface for pipeline hazards recognition based on
+        DFA (deterministic finite state automata.  */
+      printf ("\n/* DFA based pipeline interface.  */");
+      printf ("\n#ifndef AUTOMATON_STATE_ALTS\n");
+      printf ("#define AUTOMATON_STATE_ALTS 0\n");
+      printf ("#endif\n\n");
+      printf ("#ifndef CPU_UNITS_QUERY\n");
+      printf ("#define CPU_UNITS_QUERY 0\n");
+      printf ("#endif\n\n");
+      /* Interface itself: */
+      printf ("extern int max_dfa_issue_rate;\n\n");
+      printf ("/* The following macro value is calculated from the\n");
+      printf ("   automaton based pipeline description and is equal to\n");
+      printf ("   maximal number of all insns described in constructions\n");
+      printf ("   `define_insn_reservation' which can be issued on the\n");
+      printf ("   same processor cycle. */\n");
+      printf ("#define MAX_DFA_ISSUE_RATE max_dfa_issue_rate\n\n");
+      printf ("/* Insn latency time defined in define_insn_reservation. */\n");
+      printf ("extern int insn_default_latency PARAMS ((rtx));\n\n");
+      printf ("/* Return nonzero if there is a bypass for given insn\n");
+      printf ("   which is a data producer.  */\n");
+      printf ("extern int bypass_p PARAMS ((rtx));\n\n");
+      printf ("/* Insn latency time on data consumed by the 2nd insn.\n");
+      printf ("   Use the function if bypass_p returns nonzero for\n");
+      printf ("   the 1st insn. */\n");
+      printf ("extern int insn_latency PARAMS ((rtx, rtx));\n\n");
+      printf ("/* The following function returns number of alternative\n");
+      printf ("   reservations of given insn.  It may be used for better\n");
+      printf ("   insns scheduling heuristics. */\n");
+      printf ("extern int insn_alts PARAMS ((rtx));\n\n");
+      printf ("/* Maximal possible number of insns waiting results being\n");
+      printf ("   produced by insns whose execution is not finished. */\n");
+      printf ("extern int max_insn_queue_index;\n\n");
+      printf ("/* Pointer to data describing current state of DFA.  */\n");
+      printf ("typedef void *state_t;\n\n");
+      printf ("/* Size of the data in bytes.  */\n");
+      printf ("extern int state_size PARAMS ((void));\n\n");
+      printf ("/* Initiate given DFA state, i.e. Set up the state\n");
+      printf ("   as all functional units were not reserved.  */\n");
+      printf ("extern void state_reset PARAMS ((state_t));\n");
+      printf ("/* The following function returns negative value if given\n");
+      printf ("   insn can be issued in processor state described by given\n");
+      printf ("   DFA state.  In this case, the DFA state is changed to\n");
+      printf ("   reflect the current and future reservations by given\n");
+      printf ("   insn.  Otherwise the function returns minimal time\n");
+      printf ("   delay to issue the insn.  This delay may be zero\n");
+      printf ("   for superscalar or VLIW processors.  If the second\n");
+      printf ("   parameter is NULL the function changes given DFA state\n");
+      printf ("   as new processor cycle started.  */\n");
+      printf ("extern int state_transition PARAMS ((state_t, rtx));\n");
+      printf ("\n#if AUTOMATON_STATE_ALTS\n");
+      printf ("/* The following function returns number of possible\n");
+      printf ("   alternative reservations of given insn in given\n");
+      printf ("   DFA state.  It may be used for better insns scheduling\n");
+      printf ("   heuristics.  By default the function is defined if\n");
+      printf ("   macro AUTOMATON_STATE_ALTS is defined because its\n");
+      printf ("   implementation may require much memory.  */\n");
+      printf ("extern int state_alts PARAMS ((state_t, rtx));\n");
+      printf ("#endif\n\n");
+      printf ("extern int min_issue_delay PARAMS ((state_t, rtx));\n");
+      printf ("/* The following function returns nonzero if no one insn\n");
+      printf ("   can be issued in current DFA state. */\n");
+      printf ("extern int state_dead_lock_p PARAMS ((state_t));\n");
+      printf ("/* The function returns minimal delay of issue of the 2nd\n");
+      printf ("   insn after issuing the 1st insn in given DFA state.\n");
+      printf ("   The 1st insn should be issued in given state (i.e.\n");
+      printf ("    state_transition should return negative value for\n");
+      printf ("    the insn and the state).  Data dependencies between\n");
+      printf ("    the insns are ignored by the function.  */\n");
+      printf
+       ("extern int min_insn_conflict_delay PARAMS ((state_t, rtx, rtx));\n");
+      printf ("/* The following function outputs reservations for given\n");
+      printf ("   insn as they are described in the corresponding\n");
+      printf ("   define_insn_reservation.  */\n");
+      printf ("extern void print_reservation PARAMS ((FILE *, rtx));\n");
+      printf ("\n#if CPU_UNITS_QUERY\n");
+      printf ("/* The following function returns code of functional unit\n");
+      printf ("   with given name (see define_cpu_unit). */\n");
+      printf ("extern int get_cpu_unit_code PARAMS ((const char *));\n");
+      printf ("/* The following function returns nonzero if functional\n");
+      printf ("   unit with given code is currently reserved in given\n");
+      printf ("   DFA state.  */\n");
+      printf ("extern int cpu_unit_reservation_p PARAMS ((state_t, int));\n");
+      printf ("#endif\n\n");
+      printf ("/* Initiate and finish work with DFA.  They should be\n");
+      printf ("   called as the first and the last interface\n");
+      printf ("   functions.  */\n");
+      printf ("extern void dfa_start PARAMS ((void));\n");
+      printf ("extern void dfa_finish PARAMS ((void));\n");
     }
 
   /* Output flag masks for use by reorg.  
index 94f18e3..2a7b757 100644 (file)
@@ -110,6 +110,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "obstack.h"
 #include "errors.h"
 
+#include "genattrtab.h"
+
 static struct obstack obstack1, obstack2;
 struct obstack *hash_obstack = &obstack1;
 struct obstack *temp_obstack = &obstack2;
@@ -304,6 +306,8 @@ static int have_annul_true, have_annul_false;
 static int num_units, num_unit_opclasses;
 static int num_insn_ents;
 
+int num_dfa_decls;
+
 /* Used as operand to `operate_exp':  */
 
 enum operator {PLUS_OP, MINUS_OP, POS_MINUS_OP, EQ_OP, OR_OP, ORX_OP, MAX_OP, MIN_OP, RANGE_OP};
@@ -365,10 +369,7 @@ rtx pic_offset_table_rtx;
 static void attr_hash_add_rtx  PARAMS ((int, rtx));
 static void attr_hash_add_string PARAMS ((int, char *));
 static rtx attr_rtx            PARAMS ((enum rtx_code, ...));
-static char *attr_printf       PARAMS ((int, const char *, ...))
-  ATTRIBUTE_PRINTF_2;
 static char *attr_string        PARAMS ((const char *, int));
-static rtx check_attr_test     PARAMS ((rtx, int, int));
 static rtx check_attr_value    PARAMS ((rtx, struct attr_desc *));
 static rtx convert_set_attr_alternative PARAMS ((rtx, struct insn_def *));
 static rtx convert_set_attr    PARAMS ((rtx, struct insn_def *));
@@ -452,10 +453,8 @@ static void write_const_num_delay_slots PARAMS ((void));
 static int n_comma_elts                PARAMS ((const char *));
 static char *next_comma_elt    PARAMS ((const char **));
 static struct attr_desc *find_attr PARAMS ((const char *, int));
-static void make_internal_attr PARAMS ((const char *, rtx, int));
 static struct attr_value *find_most_used  PARAMS ((struct attr_desc *));
 static rtx find_single_value   PARAMS ((struct attr_desc *));
-static rtx make_numeric_value  PARAMS ((int));
 static void extend_range       PARAMS ((struct range *, int, int));
 static rtx attr_eq             PARAMS ((const char *, const char *));
 static const char *attr_numeral        PARAMS ((int));
@@ -742,7 +741,7 @@ attr_rtx VPARAMS ((enum rtx_code code, ...))
 
    rtx attr_printf (len, format, [arg1, ..., argn])  */
 
-static char *
+char *
 attr_printf VPARAMS ((register int len, const char *fmt, ...))
 {
 #ifndef ANSI_PROTOTYPES
@@ -930,7 +929,7 @@ attr_copy_rtx (orig)
 
    Return the new expression, if any.   */
 
-static rtx
+rtx
 check_attr_test (exp, is_const, lineno)
      rtx exp;
      int is_const;
@@ -5885,7 +5884,7 @@ find_attr (name, create)
 
 /* Create internal attribute with the given default value.  */
 
-static void
+void
 make_internal_attr (name, value, special)
      const char *name;
      rtx value;
@@ -5952,7 +5951,7 @@ find_single_value (attr)
 
 /* Return (attr_value "n") */
 
-static rtx
+rtx
 make_numeric_value (n)
      int n;
 {
@@ -6102,6 +6101,7 @@ from the machine description file `md'.  */\n\n");
 
   /* Read the machine description.  */
 
+  initiate_automaton_gen (argc, argv);
   while (1)
     {
       int lineno;
@@ -6130,6 +6130,46 @@ from the machine description file `md'.  */\n\n");
          gen_unit (desc, lineno);
          break;
 
+       case DEFINE_CPU_UNIT:
+         gen_cpu_unit (desc);
+         break;
+         
+       case DEFINE_QUERY_CPU_UNIT:
+         gen_query_cpu_unit (desc);
+         break;
+         
+       case DEFINE_BYPASS:
+         gen_bypass (desc);
+         break;
+         
+       case EXCLUSION_SET:
+         gen_excl_set (desc);
+         break;
+         
+       case PRESENCE_SET:
+         gen_presence_set (desc);
+         break;
+         
+       case ABSENCE_SET:
+         gen_absence_set (desc);
+         break;
+         
+       case DEFINE_AUTOMATON:
+         gen_automaton (desc);
+         break;
+         
+       case AUTOMATA_OPTION:
+         gen_automata_option (desc);
+         break;
+         
+       case DEFINE_RESERVATION:
+         gen_reserv (desc);
+         break;
+         
+       case DEFINE_INSN_RESERVATION:
+         gen_insn_reserv (desc);
+         break;
+
        default:
          break;
        }
@@ -6154,9 +6194,14 @@ from the machine description file `md'.  */\n\n");
   if (num_delays)
     expand_delays ();
 
-  /* Expand DEFINE_FUNCTION_UNIT information into new attributes.  */
-  if (num_units)
-    expand_units ();
+  if (num_units || num_dfa_decls)
+    {
+      /* Expand DEFINE_FUNCTION_UNIT information into new attributes.  */
+      expand_units ();
+      /* Build DFA, output some functions and expand DFA information
+        into new attributes.  */
+      expand_automata ();
+    }
 
   printf ("#include \"config.h\"\n");
   printf ("#include \"system.h\"\n");
@@ -6231,9 +6276,14 @@ from the machine description file `md'.  */\n\n");
        write_eligible_delay ("annul_false");
     }
 
-  /* Write out information about function units.  */
-  if (num_units)
-    write_function_unit_info ();
+  if (num_units || num_dfa_decls)
+    {
+      /* Write out information about function units.  */
+      write_function_unit_info ();
+      /* Output code for pipeline hazards recognition based on DFA
+        (deterministic finite state automata. */
+      write_automata ();
+    }
 
   /* Write out constant delay slot info */
   write_const_num_delay_slots ();
diff --git a/gcc/genattrtab.h b/gcc/genattrtab.h
new file mode 100644 (file)
index 0000000..cc9e36e
--- /dev/null
@@ -0,0 +1,43 @@
+/* External definitions of source files of genattrtab.
+   Copyright (C)  2001 Free Software Foundation, Inc.
+
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU CC is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA.  */
+
+/* Defined in genattrtab.c: */
+extern rtx check_attr_test     PARAMS ((rtx, int, int));
+extern rtx make_numeric_value  PARAMS ((int));
+extern void make_internal_attr PARAMS ((const char *, rtx, int));
+extern char *attr_printf       PARAMS ((int, const char *, ...))
+  ATTRIBUTE_PRINTF_2;
+
+extern int num_dfa_decls;
+
+/* Defined in genautomata.c: */
+extern void gen_cpu_unit               PARAMS ((rtx));
+extern void gen_query_cpu_unit         PARAMS ((rtx));
+extern void gen_bypass                 PARAMS ((rtx));
+extern void gen_excl_set               PARAMS ((rtx));
+extern void gen_presence_set           PARAMS ((rtx));
+extern void gen_absence_set            PARAMS ((rtx));
+extern void gen_automaton              PARAMS ((rtx));
+extern void gen_automata_option                PARAMS ((rtx));
+extern void gen_reserv                 PARAMS ((rtx));
+extern void gen_insn_reserv            PARAMS ((rtx));
+extern void initiate_automaton_gen     PARAMS ((int, char **));
+extern void expand_automata             PARAMS ((void));
+extern void write_automata              PARAMS ((void));
diff --git a/gcc/genautomata.c b/gcc/genautomata.c
new file mode 100644 (file)
index 0000000..f4fc572
--- /dev/null
@@ -0,0 +1,8771 @@
+/* Pipeline hazard description translator.
+   Copyright (C) 2000, 2001 Free Software Foundation, Inc.
+
+   Written by Vladimir Makarov <vmakarov@redhat.com>
+   
+This file is part of GNU CC.
+
+GNU CC is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 2, or (at your option) any
+later version.
+
+GNU CC is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU CC; see the file COPYING.  If not, write to the Free
+Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+02111-1307, USA.  */
+
+/* References:
+   
+   1. Detecting pipeline structural hazards quickly. T. Proebsting,
+      C. Fraser. Proceedings of ACM SIGPLAN-SIGACT Symposium on
+      Principles of Programming Languages, pages 280--286, 1994.
+
+      This article is a good start point to understand usage of finite
+      state automata for pipeline hazard recognizers.  But I'd
+      recommend the 2nd article for more deep understanding.
+
+   2. Efficient Instruction Scheduling Using Finite State Automata:
+      V. Bala and N. Rubin, Proceedings of MICRO-28.  This is the best
+      article about usage of finite state automata for pipeline hazard
+      recognizers.
+
+   The current implementation is different from the 2nd article in the
+   following:
+
+   1. New operator `|' (alternative) is permitted in functional unit
+      reservation which can be treated deterministicly and
+      non-deterministicly.
+
+   2. Possibility of usage of nondeterministic automata too.
+
+   3. Possibility to query functional unit reservations for given
+      automaton state.
+
+   4. Several constructions to describe impossible reservations
+      (`exclusion_set', `presence_set', and `absence_set').
+
+   5. No reverse automata are generated.  Trace instruction scheduling
+      requires this.  It can be easily added in the future if we
+      really need this.
+
+   6. Union of automaton states are not generated yet.  It is planned
+      to be implemented.  Such feature is needed to make more accurate
+      interlock insn scheduling to get state describing functional
+      unit reservation in a joint CFG point.
+*/
+
+/* This file code processes constructions of machine description file
+   which describes automaton used for recognition of processor pipeline
+   hazards by insn scheduler and can be used for other tasks (such as
+   VLIW insn packing.
+
+   The translator functions `gen_cpu_unit', `gen_query_cpu_unit',
+   `gen_bypass', `gen_excl_set', `gen_presence_set',
+   `gen_absence_set', `gen_automaton', `gen_automata_option',
+   `gen_reserv', `gen_insn_reserv' are called from file
+   `genattrtab.c'.  They transform RTL constructions describing
+   automata in .md file into internal representation convenient for
+   further processing.
+   The translator major function `expand_automata' processes the
+   description internal representation into finite state automaton.
+   It can be divided on:
+
+     o checking correctness of the automaton pipeline description
+       (major function is `check_all_description').
+
+     o generating automaton (automata) from the description (major
+       function is `make_automaton').
+
+     o optional transformation of nondeterministic finite state
+       automata into deterministic ones if the alternative operator
+       `|' is treated nondeterministicly in the description (major
+       function is NDFA_to_DFA).
+
+     o optional minimization of the finite state automata by merging
+       equivalent automaton states (major function is `minimize_DFA').
+
+     o forming tables (some as comb vectors) and attributes
+       representing the automata (functions output_..._table).
+
+   Function `write_automata' outputs the created finite state
+   automaton as different tables and functions which works with the
+   automata to inquire automaton state and to change its state.  These
+   function are used by gcc instruction scheduler and may be some
+   other gcc code.  */
+
+#include "hconfig.h"
+#include "system.h"
+#include "rtl.h"
+#include "obstack.h"
+#include "errors.h"
+
+#include <ctype.h>
+#include <math.h>
+#include "hashtab.h"
+#include "varray.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#else
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+#endif
+
+#include "genattrtab.h"
+
+#define obstack_chunk_alloc xmalloc
+#define obstack_chunk_free free
+
+/* Positions in machine description file.  Now they are not used.  But
+   they could be used in the future for better diagnostic messages.  */
+typedef int pos_t;
+
+/* The following is element of vector of current (and planned in the
+   future) functional unit reservations.  */
+typedef unsigned HOST_WIDE_INT set_el_t;
+
+/* Reservations of function units are represented by value of the following
+   type.  */
+typedef set_el_t *reserv_sets_t;
+
+/* The following structure represents variable length array (vla) of
+   pointers and HOST WIDE INTs.  We could be use only varray.  But we
+   add new lay because we add elements very frequently and this could
+   stress OS allocator when varray is used only.  */
+typedef struct {
+  size_t length;      /* current size of vla.  */
+  varray_type varray; /* container for vla.  */
+} vla_ptr_t;
+
+typedef vla_ptr_t vla_hwint_t;
+
+/* The following structure describes a ticker.  */
+struct ticker
+{
+  /* The following member value is time of the ticker creation with
+     taking into account time when the ticker is off.  Active time of
+     the ticker is current time minus the value.  */
+  int modified_creation_time;
+  /* The following member value is time (incremented by one) when the
+     ticker was off.  Zero value means that now the ticker is on.  */
+  int incremented_off_time;
+};
+
+/* The ticker is represented by the following type.  */
+typedef struct ticker ticker_t;
+
+/* The following type describes elements of output vectors.  */
+typedef HOST_WIDE_INT vect_el_t;
+
+/* Forward declaration of structures of internal representation of
+   pipeline description based on NDFA.  */
+
+struct unit_decl;
+struct bypass_decl;
+struct result_decl;
+struct automaton_decl;
+struct unit_rel_decl;
+struct reserv_decl;
+struct insn_reserv_decl;
+struct decl;
+struct unit_regexp;
+struct result_regexp;
+struct reserv_regexp;
+struct nothing_regexp;
+struct sequence_regexp;
+struct repeat_regexp;
+struct allof_regexp;
+struct oneof_regexp;
+struct regexp;
+struct description;
+struct unit_set_el;
+struct state;
+struct alt_state;
+struct arc;
+struct ainsn;
+struct automaton;
+struct state_ainsn_table;
+
+/* The following typedefs are for brevity.  */
+typedef struct decl *decl_t;
+typedef struct regexp *regexp_t;
+typedef struct unit_set_el *unit_set_el_t;
+typedef struct alt_state *alt_state_t;
+typedef struct state *state_t;
+typedef struct arc *arc_t;
+typedef struct ainsn *ainsn_t;
+typedef struct automaton *automaton_t;
+typedef struct state_ainsn_table *state_ainsn_table_t;
+
+
+/* Prototypes of functions gen_cpu_unit, gen_query_cpu_unit,
+   gen_bypass, gen_excl_set, gen_presence_set, gen_absence_set,
+   gen_automaton, gen_automata_option, gen_reserv, gen_insn_reserv,
+   initiate_automaton_gen, expand_automata, write_automata are
+   described on the file top because the functions are called from
+   function `main'.  */
+
+static void *create_node            PARAMS ((size_t));
+static void *copy_node              PARAMS ((void *, size_t));
+static char *check_name             PARAMS ((char *, pos_t));
+static char *next_sep_el            PARAMS ((char **, int, int));
+static int n_sep_els                PARAMS ((char *, int, int));
+static char **get_str_vect          PARAMS ((char *, int *, int, int));
+static regexp_t gen_regexp_el       PARAMS ((char *));
+static regexp_t gen_regexp_repeat   PARAMS ((char *));
+static regexp_t gen_regexp_allof    PARAMS ((char *));
+static regexp_t gen_regexp_oneof    PARAMS ((char *));
+static regexp_t gen_regexp_sequence PARAMS ((char *));
+static regexp_t gen_regexp          PARAMS ((char *));
+
+static unsigned string_hash         PARAMS ((const char *));
+static unsigned automaton_decl_hash PARAMS ((const void *));
+static int automaton_decl_eq_p      PARAMS ((const void *,
+                                                  const void *));
+static decl_t insert_automaton_decl       PARAMS ((decl_t));
+static decl_t find_automaton_decl         PARAMS ((char *));
+static void initiate_automaton_decl_table PARAMS ((void));
+static void finish_automaton_decl_table   PARAMS ((void));
+
+static unsigned insn_decl_hash            PARAMS ((const void *));
+static int insn_decl_eq_p                 PARAMS ((const void *,
+                                                  const void *));
+static decl_t insert_insn_decl            PARAMS ((decl_t));
+static decl_t find_insn_decl              PARAMS ((char *));
+static void initiate_insn_decl_table      PARAMS ((void));
+static void finish_insn_decl_table        PARAMS ((void));
+
+static unsigned decl_hash                 PARAMS ((const void *));
+static int decl_eq_p                      PARAMS ((const void *,
+                                                  const void *));
+static decl_t insert_decl                 PARAMS ((decl_t));
+static decl_t find_decl                   PARAMS ((char *));
+static void initiate_decl_table           PARAMS ((void));
+static void finish_decl_table             PARAMS ((void));
+
+static unit_set_el_t process_excls       PARAMS ((char **, int, pos_t));
+static void add_excls                    PARAMS ((unit_set_el_t, unit_set_el_t,
+                                                 pos_t));
+static unit_set_el_t process_presence_absence
+                                        PARAMS ((char **, int, pos_t, int));
+static void add_presence_absence        PARAMS ((unit_set_el_t, unit_set_el_t,
+                                                 pos_t, int));
+static void process_decls                PARAMS ((void));
+static struct bypass_decl *find_bypass   PARAMS ((struct bypass_decl *,
+                                                 struct insn_reserv_decl *));
+static void check_automaton_usage        PARAMS ((void));
+static regexp_t process_regexp           PARAMS ((regexp_t));
+static void process_regexp_decls         PARAMS ((void));
+static void check_usage                  PARAMS ((void));
+static int loop_in_regexp                PARAMS ((regexp_t, decl_t));
+static void check_loops_in_regexps       PARAMS ((void));
+static int process_regexp_cycles         PARAMS ((regexp_t, int));
+static void evaluate_max_reserv_cycles   PARAMS ((void));
+static void check_all_description        PARAMS ((void));
+
+static ticker_t create_ticker               PARAMS ((void));
+static void ticker_off                      PARAMS ((ticker_t *));
+static void ticker_on                       PARAMS ((ticker_t *));
+static int active_time                      PARAMS ((ticker_t));
+static void print_active_time               PARAMS ((FILE *, ticker_t));
+
+static void add_advance_cycle_insn_decl     PARAMS ((void));
+
+static alt_state_t get_free_alt_state PARAMS ((void));
+static void free_alt_state              PARAMS ((alt_state_t));
+static void free_alt_states             PARAMS ((alt_state_t));
+static int alt_state_cmp                PARAMS ((const void *alt_state_ptr_1,
+                                                const void *alt_state_ptr_2));
+static alt_state_t uniq_sort_alt_states PARAMS ((alt_state_t));
+static int alt_states_eq                PARAMS ((alt_state_t, alt_state_t));
+static void initiate_alt_states         PARAMS ((void));
+static void finish_alt_states           PARAMS ((void));
+
+static reserv_sets_t alloc_empty_reserv_sets PARAMS ((void));
+static unsigned reserv_sets_hash_value PARAMS ((reserv_sets_t));
+static int reserv_sets_cmp             PARAMS ((reserv_sets_t, reserv_sets_t));
+static int reserv_sets_eq              PARAMS ((reserv_sets_t, reserv_sets_t));
+static void set_unit_reserv            PARAMS ((reserv_sets_t, int, int));
+static int test_unit_reserv            PARAMS ((reserv_sets_t, int, int));
+static int it_is_empty_reserv_sets     PARAMS ((reserv_sets_t))
+                                            ATTRIBUTE_UNUSED;
+static int reserv_sets_are_intersected PARAMS ((reserv_sets_t, reserv_sets_t));
+static void reserv_sets_shift          PARAMS ((reserv_sets_t, reserv_sets_t));
+static void reserv_sets_or             PARAMS ((reserv_sets_t, reserv_sets_t,
+                                               reserv_sets_t));
+static void reserv_sets_and            PARAMS ((reserv_sets_t, reserv_sets_t,
+                                               reserv_sets_t))
+                                            ATTRIBUTE_UNUSED;
+static void output_cycle_reservs       PARAMS ((FILE *, reserv_sets_t,
+                                               int, int));
+static void output_reserv_sets         PARAMS ((FILE *, reserv_sets_t));
+static state_t get_free_state          PARAMS ((int, automaton_t));
+static void free_state                 PARAMS ((state_t));
+static unsigned state_hash             PARAMS ((const void *));
+static int state_eq_p                  PARAMS ((const void *, const void *));
+static state_t insert_state            PARAMS ((state_t));
+static void set_state_reserv           PARAMS ((state_t, int, int));
+static int intersected_state_reservs_p PARAMS ((state_t, state_t));
+static state_t states_union            PARAMS ((state_t, state_t));
+static state_t state_shift             PARAMS ((state_t));
+static void initiate_states            PARAMS ((void));
+static void finish_states              PARAMS ((void));
+
+static void free_arc           PARAMS ((arc_t));
+static void remove_arc         PARAMS ((state_t, arc_t));
+static arc_t find_arc          PARAMS ((state_t, state_t, ainsn_t));
+static arc_t add_arc           PARAMS ((state_t, state_t, ainsn_t, int));
+static arc_t first_out_arc     PARAMS ((state_t));
+static arc_t next_out_arc      PARAMS ((arc_t));
+static void initiate_arcs      PARAMS ((void));
+static void finish_arcs        PARAMS ((void));
+
+static void initiate_excl_sets             PARAMS ((void));
+static reserv_sets_t get_excl_set          PARAMS ((reserv_sets_t));
+
+static void initiate_presence_absence_sets     PARAMS ((void));
+static reserv_sets_t get_presence_absence_set  PARAMS ((reserv_sets_t, int));
+
+static regexp_t copy_insn_regexp     PARAMS ((regexp_t));
+static regexp_t transform_1          PARAMS ((regexp_t));
+static regexp_t transform_2          PARAMS ((regexp_t));
+static regexp_t transform_3          PARAMS ((regexp_t));
+static regexp_t regexp_transform_func
+                       PARAMS ((regexp_t, regexp_t (*) (regexp_t)));
+static regexp_t transform_regexp            PARAMS ((regexp_t));
+static void transform_insn_regexps          PARAMS ((void));
+
+static int process_seq_for_forming_states   PARAMS ((regexp_t, automaton_t,
+                                                    int));
+static void finish_forming_alt_state        PARAMS ((alt_state_t,
+                                                    automaton_t));
+static void process_alts_for_forming_states PARAMS ((regexp_t,
+                                                    automaton_t, int));
+static void create_alt_states               PARAMS ((automaton_t));
+
+static void form_ainsn_with_same_reservs    PARAMS ((automaton_t));
+
+static void make_automaton           PARAMS ((automaton_t));
+static void form_arcs_marked_by_insn PARAMS ((state_t));
+static void create_composed_state    PARAMS ((state_t, arc_t, vla_ptr_t *));
+static void NDFA_to_DFA              PARAMS ((automaton_t));
+static void pass_state_graph         PARAMS ((state_t, void (*) (state_t)));
+static void pass_states              PARAMS ((automaton_t,
+                                             void (*) (state_t)));
+static void initiate_pass_states       PARAMS ((void));
+static void add_achieved_state         PARAMS ((state_t));
+static int set_out_arc_insns_equiv_num PARAMS ((state_t, int));
+static void clear_arc_insns_equiv_num  PARAMS ((state_t));
+static void copy_equiv_class           PARAMS ((vla_ptr_t *to,
+                                               const vla_ptr_t *from));
+static int state_is_differed           PARAMS ((state_t, int, int));
+static state_t init_equiv_class        PARAMS ((state_t *states, int));
+static int partition_equiv_class       PARAMS ((state_t *, int,
+                                               vla_ptr_t *, int *));
+static void evaluate_equiv_classes     PARAMS ((automaton_t, vla_ptr_t *));
+static void merge_states               PARAMS ((automaton_t, vla_ptr_t *));
+static void set_new_cycle_flags        PARAMS ((state_t));
+static void minimize_DFA               PARAMS ((automaton_t));
+static void incr_states_and_arcs_nums  PARAMS ((state_t));
+static void count_states_and_arcs      PARAMS ((automaton_t, int *, int *));
+static void build_automaton            PARAMS ((automaton_t));
+
+static void set_order_state_num              PARAMS ((state_t));
+static void enumerate_states                 PARAMS ((automaton_t));
+
+static ainsn_t insert_ainsn_into_equiv_class       PARAMS ((ainsn_t, ainsn_t));
+static void delete_ainsn_from_equiv_class          PARAMS ((ainsn_t));
+static void process_insn_equiv_class               PARAMS ((ainsn_t, arc_t *));
+static void process_state_for_insn_equiv_partition PARAMS ((state_t));
+static void set_insn_equiv_classes                 PARAMS ((automaton_t));
+
+static double estimate_one_automaton_bound     PARAMS ((void));
+static int compare_max_occ_cycle_nums          PARAMS ((const void *,
+                                                       const void *));
+static void units_to_automata_heuristic_distr  PARAMS ((void));
+static ainsn_t create_ainsns                   PARAMS ((void));
+static void units_to_automata_distr            PARAMS ((void));
+static void create_automata                    PARAMS ((void));
+
+static void form_regexp                      PARAMS ((regexp_t));
+static const char *regexp_representation     PARAMS ((regexp_t));
+static void finish_regexp_representation     PARAMS ((void));
+
+static void output_range_type            PARAMS ((FILE *, long int, long int));
+static int longest_path_length           PARAMS ((state_t));
+static void process_state_longest_path_length PARAMS ((state_t));
+static void output_dfa_max_issue_rate    PARAMS ((void));
+static void output_vect                  PARAMS ((vect_el_t *, int));
+static void output_chip_member_name      PARAMS ((FILE *, automaton_t));
+static void output_temp_chip_member_name PARAMS ((FILE *, automaton_t));
+static void output_translate_vect_name   PARAMS ((FILE *, automaton_t));
+static void output_trans_full_vect_name  PARAMS ((FILE *, automaton_t));
+static void output_trans_comb_vect_name  PARAMS ((FILE *, automaton_t));
+static void output_trans_check_vect_name PARAMS ((FILE *, automaton_t));
+static void output_trans_base_vect_name  PARAMS ((FILE *, automaton_t));
+static void output_state_alts_full_vect_name    PARAMS ((FILE *, automaton_t));
+static void output_state_alts_comb_vect_name    PARAMS ((FILE *, automaton_t));
+static void output_state_alts_check_vect_name   PARAMS ((FILE *, automaton_t));
+static void output_state_alts_base_vect_name    PARAMS ((FILE *, automaton_t));
+static void output_min_issue_delay_vect_name    PARAMS ((FILE *, automaton_t));
+static void output_dead_lock_vect_name   PARAMS ((FILE *, automaton_t));
+static void output_reserved_units_table_name    PARAMS ((FILE *, automaton_t));
+static void output_state_member_type     PARAMS ((FILE *, automaton_t));
+static void output_chip_definitions      PARAMS ((void));
+static void output_translate_vect        PARAMS ((automaton_t));
+static int comb_vect_p                   PARAMS ((state_ainsn_table_t));
+static state_ainsn_table_t create_state_ainsn_table PARAMS ((automaton_t));
+static void output_state_ainsn_table
+   PARAMS ((state_ainsn_table_t, char *, void (*) (FILE *, automaton_t),
+           void (*) (FILE *, automaton_t), void (*) (FILE *, automaton_t),
+           void (*) (FILE *, automaton_t)));
+static void add_vect                     PARAMS ((state_ainsn_table_t,
+                                                 int, vect_el_t *, int));
+static int out_state_arcs_num            PARAMS ((state_t));
+static int compare_transition_els_num    PARAMS ((const void *, const void *));
+static void add_vect_el                 PARAMS ((vla_hwint_t *,
+                                                 ainsn_t, int));
+static void add_states_vect_el           PARAMS ((state_t));
+static void output_trans_table           PARAMS ((automaton_t));
+static void output_state_alts_table      PARAMS ((automaton_t));
+static void min_issue_delay_pass_states  PARAMS ((state_t, ainsn_t));
+static int min_issue_delay               PARAMS ((state_t, ainsn_t));
+static void initiate_min_issue_delay_pass_states PARAMS ((void));
+static void output_min_issue_delay_table PARAMS ((automaton_t));
+static void output_dead_lock_vect        PARAMS ((automaton_t));
+static void output_reserved_units_table  PARAMS ((automaton_t));
+static void output_tables                PARAMS ((void));
+static void output_max_insn_queue_index_def PARAMS ((void));
+static void output_internal_min_issue_delay_func PARAMS ((void));
+static void output_internal_trans_func   PARAMS ((void));
+static void output_internal_insn_code_evaluation PARAMS ((const char *,
+                                                         const char *, int));
+static void output_dfa_insn_code_func          PARAMS ((void));
+static void output_trans_func                   PARAMS ((void));
+static void output_internal_state_alts_func     PARAMS ((void));
+static void output_state_alts_func              PARAMS ((void));
+static void output_min_issue_delay_func         PARAMS ((void));
+static void output_internal_dead_lock_func      PARAMS ((void));
+static void output_dead_lock_func               PARAMS ((void));
+static void output_internal_reset_func          PARAMS ((void));
+static void output_size_func                   PARAMS ((void));
+static void output_reset_func                   PARAMS ((void));
+static void output_min_insn_conflict_delay_func PARAMS ((void));
+static void output_internal_insn_latency_func   PARAMS ((void));
+static void output_insn_latency_func            PARAMS ((void));
+static void output_print_reservation_func       PARAMS ((void));
+static int units_cmp                           PARAMS ((const void *,
+                                                        const void *));
+static void output_get_cpu_unit_code_func       PARAMS ((void));
+static void output_cpu_unit_reservation_p       PARAMS ((void));
+static void output_dfa_start_func              PARAMS ((void));
+static void output_dfa_finish_func             PARAMS ((void));
+
+static void output_regexp                  PARAMS ((regexp_t ));
+static void output_unit_set_el_list       PARAMS ((unit_set_el_t));
+static void output_description             PARAMS ((void));
+static void output_automaton_name          PARAMS ((FILE *, automaton_t));
+static void output_automaton_units         PARAMS ((automaton_t));
+static void add_state_reservs              PARAMS ((state_t));
+static void output_state_arcs              PARAMS ((state_t));
+static int state_reservs_cmp               PARAMS ((const void *,
+                                                   const void *));
+static void remove_state_duplicate_reservs PARAMS ((void));
+static void output_state                   PARAMS ((state_t));
+static void output_automaton_descriptions  PARAMS ((void));
+static void output_statistics              PARAMS ((FILE *));
+static void output_time_statistics         PARAMS ((FILE *));
+static void generate                       PARAMS ((void));
+
+static void make_insn_alts_attr               PARAMS ((void));
+static void make_internal_dfa_insn_code_attr  PARAMS ((void));
+static void make_default_insn_latency_attr    PARAMS ((void));
+static void make_bypass_attr                  PARAMS ((void));
+static const char *file_name_suffix           PARAMS ((const char *));
+static const char *base_file_name             PARAMS ((const char *));
+static void check_automata                   PARAMS ((void));
+
+/* Undefined position.  */
+static pos_t no_pos = 0;
+
+/* All IR is stored in the following obstack.  */
+static struct obstack irp;
+
+\f
+
+/* This page contains code for work with variable length array (vla)
+   of pointers.  We could be use only varray.  But we add new lay
+   because we add elements very frequently and this could stress OS
+   allocator when varray is used only.  */
+
+/* Start work with vla.  */
+#define VLA_PTR_CREATE(vla, allocated_length, name)                    \
+  do                                                                   \
+    {                                                                  \
+      vla_ptr_t *vla_ptr = &(vla);                                      \
+                                                                       \
+      VARRAY_GENERIC_PTR_INIT (vla_ptr->varray, allocated_length, name);\
+      vla_ptr->length = 0;                                              \
+    }                                                                  \
+  while (0)
+
+/* Finish work with the vla.  */
+#define VLA_PTR_DELETE(vla) VARRAY_FREE ((vla).varray)
+
+/* Return start address of the vla.  */
+#define VLA_PTR_BEGIN(vla) ((void *) &VARRAY_GENERIC_PTR ((vla).varray, 0))
+
+/* Address of the last element of the vla.  Do not use side effects in
+   the macro argument.  */
+#define VLA_PTR_LAST(vla) (&VARRAY_GENERIC_PTR ((vla).varray,         \
+                                                (vla).length - 1))
+/* Nullify the vla.  */
+#define VLA_PTR_NULLIFY(vla)  ((vla).length = 0)
+
+/* Shorten the vla on given number bytes.  */
+#define VLA_PTR_SHORTEN(vla, n)  ((vla).length -= (n))
+
+/* Expand the vla on N elements.  The values of new elements are
+   undefined.  */
+#define VLA_PTR_EXPAND(vla, n)                                        \
+  do {                                                                \
+    vla_ptr_t *expand_vla_ptr = &(vla);                               \
+    size_t new_length = (n) + expand_vla_ptr->length;                 \
+                                                                      \
+    if (VARRAY_SIZE (expand_vla_ptr->varray) < new_length)            \
+      VARRAY_GROW (expand_vla_ptr->varray,                            \
+                   (new_length - expand_vla_ptr->length < 128         \
+                    ? expand_vla_ptr->length + 128 : new_length));    \
+    expand_vla_ptr->length = new_length;                              \
+  } while (0)
+
+/* Add element to the end of the vla.  */
+#define VLA_PTR_ADD(vla, ptr)                                         \
+  do {                                                                \
+    vla_ptr_t *vla_ptr = &(vla);                                      \
+                                                                      \
+    VLA_PTR_EXPAND (*vla_ptr, 1);                                     \
+    VARRAY_GENERIC_PTR (vla_ptr->varray, vla_ptr->length - 1) = (ptr);\
+  } while (0)
+
+/* Length of the vla in elements.  */
+#define VLA_PTR_LENGTH(vla) ((vla).length)
+
+/* N-th element of the vla.  */
+#define VLA_PTR(vla, n) VARRAY_GENERIC_PTR ((vla).varray, n)
+
+
+/* The following macros are analogous to the previous ones but for
+   VLAs of HOST WIDE INTs.  */
+
+#define VLA_HWINT_CREATE(vla, allocated_length, name)                 \
+  do {                                                                \
+    vla_hwint_t *vla_ptr = &(vla);                                    \
+                                                                      \
+    VARRAY_WIDE_INT_INIT (vla_ptr->varray, allocated_length, name);   \
+    vla_ptr->length = 0;                                              \
+  } while (0)
+
+#define VLA_HWINT_DELETE(vla) VARRAY_FREE ((vla).varray)
+
+#define VLA_HWINT_BEGIN(vla) (&VARRAY_WIDE_INT ((vla).varray, 0))
+
+/* Do not use side effects in the macro argument.  */
+#define VLA_HWINT_LAST(vla) (&VARRAY_WIDE_INT ((vla).varray,          \
+                                              (vla).length - 1))
+
+#define VLA_HWINT_NULLIFY(vla)  ((vla).length = 0)
+
+#define VLA_HWINT_SHORTEN(vla, n)  ((vla).length -= (n))
+
+#define VLA_HWINT_EXPAND(vla, n)                                      \
+  do {                                                                \
+    vla_hwint_t *expand_vla_ptr = &(vla);                             \
+    size_t new_length = (n) + expand_vla_ptr->length;                 \
+                                                                      \
+    if (VARRAY_SIZE (expand_vla_ptr->varray) < new_length)            \
+      VARRAY_GROW (expand_vla_ptr->varray,                            \
+                   (new_length - expand_vla_ptr->length < 128         \
+                    ? expand_vla_ptr->length + 128 : new_length));    \
+    expand_vla_ptr->length = new_length;                              \
+  } while (0)
+
+#define VLA_HWINT_ADD(vla, ptr)                                       \
+  do {                                                                \
+    vla_hwint_t *vla_ptr = &(vla);                                    \
+                                                                      \
+    VLA_HWINT_EXPAND (*vla_ptr, 1);                                   \
+    VARRAY_WIDE_INT (vla_ptr->varray, vla_ptr->length - 1) = (ptr);   \
+  } while (0)
+
+#define VLA_HWINT_LENGTH(vla) ((vla).length)
+
+#define VLA_HWINT(vla, n) VARRAY_WIDE_INT ((vla).varray, n)
+
+\f
+
+/* Options with the following names can be set up in automata_option
+   construction.  Because the strings occur more one time we use the
+   macros.  */
+
+#define NO_MINIMIZATION_OPTION "-no-minimization"
+
+#define W_OPTION "-w"
+
+#define NDFA_OPTION "-ndfa"
+
+/* The following flags are set up by function `initiate_automaton_gen'.  */
+
+/* Make automata with nondeterministic reservation by insns (`-ndfa').  */
+static int ndfa_flag;
+
+/* Do not make minimization of DFA (`-no-minimization').  */
+static int no_minimization_flag;
+
+/* Value of this variable is number of automata being generated.  The
+   actual number of automata may be less this value if there is not
+   sufficient number of units.  This value is defined by argument of
+   option `-split' or by constructions automaton if the value is zero
+   (it is default value of the argument).  */
+static int split_argument;
+
+/* Flag of output time statistics (`-time').  */
+static int time_flag;
+
+/* Flag of creation of description file which contains description of
+   result automaton and statistics information (`-v').  */
+static int v_flag;
+
+/* Flag of generating warning instead of error for non-critical errors
+   (`-w').  */
+static int w_flag;
+
+
+/* Output file for pipeline hazard recognizer (PHR) being generated.
+   The value is NULL if the file is not defined.  */
+static FILE *output_file;
+
+/* Description file of PHR.  The value is NULL if the file is not
+   created.  */
+static FILE *output_description_file;
+
+/* PHR description file name.  */
+static char *output_description_file_name;
+
+/* Value of the following variable is node representing description
+   being processed.  This is start point of IR.  */
+static struct description *description;
+
+\f
+
+/* This page contains description of IR structure (nodes).  */
+
+enum decl_mode
+{
+  dm_unit,
+  dm_bypass,
+  dm_automaton,
+  dm_excl,
+  dm_presence,
+  dm_absence,
+  dm_reserv,
+  dm_insn_reserv
+};
+
+/* This describes define_cpu_unit and define_query_cpu_unit (see file
+   rtl.def).  */
+struct unit_decl
+{
+  char *name;
+  /* NULL if the automaton name is absent.  */
+  char *automaton_name;
+  /* If the following value is not zero, the cpu unit reservation is
+     described in define_query_cpu_unit.  */
+  char query_p;
+
+  /* The following fields are defined by checker.  */
+
+  /* The following field value is nonzero if the unit is used in an
+     regexp.  */
+  char unit_is_used;
+  /* The following field value is order number (0, 1, ...) of given
+     unit.  */
+  int unit_num;
+  /* The following field value is corresponding declaration of
+     automaton which was given in description.  If the field value is
+     NULL then automaton in the unit declaration was absent.  */
+  struct automaton_decl *automaton_decl;
+  /* The following field value is maximal cycle number (1, ...) on
+     which given unit occurs in insns.  Zero value means that given
+     unit is not used in insns.  */
+  int max_occ_cycle_num;
+  /* The following list contains units which conflict with given
+     unit.  */
+  unit_set_el_t excl_list;
+  /* The following list contains units which are required to
+     reservation of given unit.  */
+  unit_set_el_t presence_list;
+  /* The following list contains units which should be not present in
+     reservation for given unit.  */
+  unit_set_el_t absence_list;
+  /* The following is used only when `query_p' has nonzero value.
+     This is query number for the unit.  */
+  int query_num;
+
+  /* The following fields are defined by automaton generator.  */
+
+  /* The following field value is number of the automaton to which
+     given unit belongs.  */
+  int corresponding_automaton_num;
+};
+
+/* This describes define_bypass (see file rtl.def).  */
+struct bypass_decl
+{
+  int latency;
+  char *out_insn_name;
+  char *in_insn_name;
+  char *bypass_guard_name;
+
+  /* The following fields are defined by checker.  */
+
+  /* output and input insns of given bypass.  */
+  struct insn_reserv_decl *out_insn_reserv;
+  struct insn_reserv_decl *in_insn_reserv;
+  /* The next bypass for given output insn.  */
+  struct bypass_decl *next;
+};
+
+/* This describes define_automaton (see file rtl.def).  */
+struct automaton_decl
+{
+  char *name;
+
+  /* The following fields are defined by automaton generator.  */
+
+  /* The following field value is nonzero if the automaton is used in
+     an regexp definition.  */
+  char automaton_is_used;
+
+  /* The following fields are defined by checker.  */
+
+  /* The following field value is the corresponding automaton.  This
+     field is not NULL only if the automaton is present in unit
+     declarations and the automatic partition on automata is not
+     used.  */
+  automaton_t corresponding_automaton;
+};
+
+/* This describes unit relations: exclusion_set, presence_set, or
+   absence_set (see file rtl.def).  */
+struct unit_rel_decl
+{
+  int names_num;
+  int first_list_length;
+  char *names [1];
+};
+
+/* This describes define_reservation (see file rtl.def).  */
+struct reserv_decl
+{
+  char *name;
+  regexp_t regexp;
+
+  /* The following fields are defined by checker.  */
+
+  /* The following field value is nonzero if the unit is used in an
+     regexp.  */
+  char reserv_is_used;
+  /* The following field is used to check up cycle in expression
+     definition.  */
+  int loop_pass_num;
+};
+
+/* This describes define_insn_reservartion (see file rtl.def).  */
+struct insn_reserv_decl
+{
+  rtx condexp;
+  int default_latency;
+  regexp_t regexp;
+  char *name;
+
+  /* The following fields are defined by checker.  */
+
+  /* The following field value is order number (0, 1, ...) of given
+     insn.  */
+  int insn_num;
+  /* The following field value is list of bypasses in which given insn
+     is output insn.  */
+  struct bypass_decl *bypass_list;
+
+  /* The following fields are defined by automaton generator.  */
+
+  /* The following field is the insn regexp transformed that
+     the regexp has not optional regexp, repetition regexp, and an
+     reservation name (i.e. reservation identifiers are changed by the
+     corresponding regexp) and all alternations are the topest level
+     of the regexp.  The value can be NULL only if it is special
+     insn `cycle advancing'.  */
+  regexp_t transformed_regexp;
+  /* The following field value is list of arcs marked given
+     insn.  The field is used in transfromation NDFA -> DFA.  */
+  arc_t arcs_marked_by_insn;
+  /* The two following fields are used during minimization of a finite state
+     automaton.  */
+  /* The field value is number of equivalence class of state into
+     which arc marked by given insn enters from a state (fixed during
+     an automaton minimization).  */
+  int equiv_class_num;
+  /* The field value is state_alts of arc leaving a state (fixed
+     during an automaton minimization) and marked by given insn
+     enters.  */
+  int state_alts;
+};
+
+/* This contains a declaration mentioned above.  */
+struct decl
+{
+  /* What node in the union? */
+  enum decl_mode mode;
+  pos_t pos;
+  union
+  {
+    struct unit_decl unit;
+    struct bypass_decl bypass;
+    struct automaton_decl automaton;
+    struct unit_rel_decl excl;
+    struct unit_rel_decl presence;
+    struct unit_rel_decl absence;
+    struct reserv_decl reserv;
+    struct insn_reserv_decl insn_reserv;
+  } decl;
+};
+
+/* The following structures represent parsed reservation strings.  */
+enum regexp_mode
+{
+  rm_unit,
+  rm_reserv,
+  rm_nothing,
+  rm_sequence,
+  rm_repeat,
+  rm_allof,
+  rm_oneof
+};
+
+/* Cpu unit in reservation.  */
+struct unit_regexp
+{
+  char *name;
+  struct unit_decl *unit_decl;
+};
+
+/* Define_reservation in a reservation.  */
+struct reserv_regexp
+{
+  char *name;
+  struct reserv_decl *reserv_decl;
+};
+
+/* Absence of reservation (represented by string `nothing').  */
+struct nothing_regexp
+{
+  /* This used to be empty but ISO C doesn't allow that.  */
+  char unused;
+};
+
+/* Representation of reservations separated by ',' (see file
+   rtl.def).  */
+struct sequence_regexp
+{
+  int regexps_num;
+  regexp_t regexps [1];
+};
+
+/* Representation of construction `repeat' (see file rtl.def).  */
+struct repeat_regexp
+{
+  int repeat_num;
+  regexp_t regexp;
+};
+
+/* Representation of reservations separated by '+' (see file
+   rtl.def).  */
+struct allof_regexp
+{
+  int regexps_num;
+  regexp_t regexps [1];
+};
+
+/* Representation of reservations separated by '|' (see file
+   rtl.def).  */
+struct oneof_regexp
+{
+  int regexps_num;
+  regexp_t regexps [1];
+};
+
+/* Representation of a reservation string.  */
+struct regexp
+{
+  /* What node in the union? */
+  enum regexp_mode mode;
+  pos_t pos;
+  union
+  {
+    struct unit_regexp unit;
+    struct reserv_regexp reserv;
+    struct nothing_regexp nothing;
+    struct sequence_regexp sequence;
+    struct repeat_regexp repeat;
+    struct allof_regexp allof;
+    struct oneof_regexp oneof;
+  } regexp;
+};
+
+/* Reperesents description of pipeline hazard description based on
+   NDFA.  */
+struct description
+{
+  int decls_num;
+
+  /* The following fields are defined by checker.  */
+
+  /* The following fields values are correspondingly number of all
+     units, query units, and insns in the description.  */
+  int units_num;
+  int query_units_num;
+  int insns_num;
+  /* The following field value is max length (in cycles) of
+     reservations of insns.  The field value is defined only for
+     correct programs.  */
+  int max_insn_reserv_cycles;
+
+  /* The following fields are defined by automaton generator.  */
+
+  /* The following field value is the first automaton.  */
+  automaton_t first_automaton;
+
+  /* The following field is created by pipeline hazard parser and
+     contains all declarations.  We allocate additional entry for
+     special insn "cycle advancing" which is added by the automaton
+     generator.  */
+  decl_t decls [1];
+};
+
+
+
+/* The following nodes are created in automaton checker.  */
+
+/* The following nodes represent exclusion, presence, absence set for
+   cpu units.  Each element are accessed through only one excl_list,
+   presence_list, absence_list.  */
+struct unit_set_el
+{
+  struct unit_decl *unit_decl;
+  unit_set_el_t next_unit_set_el;
+};
+
+
+
+/* The following nodes are created in automaton generator.  */
+
+/* The following node type describes state automaton.  The state may
+   be deterministic or non-deterministic.  Non-deterministic state has
+   several component states which represent alternative cpu units
+   reservations.  The state also is used for describing a
+   deterministic reservation of automaton insn.  */
+struct state
+{
+  /* The following member value is nonzero if there is a transition by
+     cycle advancing.  */
+  int new_cycle_p;
+  /* The following field is list of processor unit reservations on
+     each cycle.  */
+  reserv_sets_t reservs;
+  /* The following field is unique number of given state between other
+     states.  */
+  int unique_num;
+  /* The following field value is automaton to which given state
+     belongs.  */
+  automaton_t automaton;
+  /* The following field value is the first arc output from given
+     state.  */
+  arc_t first_out_arc;
+  /* The following field is used to form NDFA.  */
+  char it_was_placed_in_stack_for_NDFA_forming;
+  /* The following field is used to form DFA.  */
+  char it_was_placed_in_stack_for_DFA_forming;
+  /* The following field is used to transform NDFA to DFA.  The field
+     value is not NULL if the state is a compound state.  In this case
+     the value of field `unit_sets_list' is NULL.  All states in the
+     list are in the hash table.  The list is formed through field
+     `next_sorted_alt_state'.  */
+  alt_state_t component_states;
+  /* The following field is used for passing graph of states.  */
+  int pass_num;
+  /* The list of states belonging to one equivalence class is formed
+     with the aid of the following field.  */
+  state_t next_equiv_class_state;
+  /* The two following fields are used during minimization of a finite
+     state automaton.  */
+  int equiv_class_num_1, equiv_class_num_2;
+  /* The following field is used during minimization of a finite state
+     automaton.  The field value is state corresponding to equivalence
+     class to which given state belongs.  */
+  state_t equiv_class_state;
+  /* The following field value is the order number of given state.
+     The states in final DFA is enumerated with the aid of the
+     following field.  */
+  int order_state_num;
+  /* This member is used for passing states for searching minimal
+     delay time.  */
+  int state_pass_num;
+  /* The following member is used to evaluate min issue delay of insn
+     for a state.  */
+  int min_insn_issue_delay;
+  /* The following member is used to evaluate max issue rate of the
+     processor.  The value of the member is maximal length of the path
+     from given state no containing arcs marked by special insn `cycle
+     advancing'.  */
+  int longest_path_length;
+};
+
+/* The following macro is an initial value of member
+   `longest_path_length' of a state. */
+#define UNDEFINED_LONGEST_PATH_LENGTH -1
+
+/* Automaton arc.  */
+struct arc
+{
+  /* The following field refers for the state into which given arc
+     enters.  */
+  state_t to_state;
+  /* The following field describes that the insn issue (with cycle
+     advancing for special insn `cycle advancing' and without cycle
+     advancing for others) makes transition from given state to
+     another given state.  */
+  ainsn_t insn;
+  /* The following field value is the next arc output from the same
+     state.  */
+  arc_t next_out_arc;
+  /* List of arcs marked given insn is formed with the following
+     field.  The field is used in transfromation NDFA -> DFA.  */
+  arc_t next_arc_marked_by_insn;
+  /* The following field is defined if NDFA_FLAG is zero.  The member
+     value is number of alternative reservations which can be used for
+     transition for given state by given insn.  */
+  int state_alts;
+};
+
+/* The following node type describes a deterministic alternative in
+   non-deterministic state which characterizes cpu unit reservations
+   of automaton insn or which is part of NDFA.  */
+struct alt_state
+{
+  /* The following field is a determinist state which characterizes
+     unit reservations of the instruction.  */
+  state_t state;
+  /* The following field refers to the next state which characterizes
+     unit reservations of the instruction.  */
+  alt_state_t next_alt_state;
+  /* The following field refers to the next state in sorted list.  */
+  alt_state_t next_sorted_alt_state;
+};
+
+/* The following node type describes insn of automaton.  They are
+   labels of FA arcs.  */
+struct ainsn
+{
+  /* The following field value is the corresponding insn declaration
+     of description.  */
+  struct insn_reserv_decl *insn_reserv_decl;
+  /* The following field value is the next insn declaration for an
+     automaton.  */
+  ainsn_t next_ainsn;
+  /* The following field is states which characterize automaton unit
+     reservations of the instruction.  The value can be NULL only if it
+     is special insn `cycle advancing'.  */
+  alt_state_t alt_states;
+  /* The following field is sorted list of states which characterize
+     automaton unit reservations of the instruction.  The value can be
+     NULL only if it is special insn `cycle advancing'.  */
+  alt_state_t sorted_alt_states;
+  /* The following field refers the next automaton insn with
+     the same reservations.  */
+  ainsn_t next_same_reservs_insn;
+  /* The following field is flag of the first automaton insn with the
+     same reservations in the declaration list.  Only arcs marked such
+     insn is present in the automaton.  This significantly decreases
+     memory requirements especially when several automata are
+     formed.  */
+  char first_insn_with_same_reservs;
+  /* The following member has nonzero value if there is arc from state of
+     the automaton marked by the ainsn.  */
+  char arc_exists_p;
+  /* Cyclic list of insns of a equivalence class is formed with the
+     aid of the following field.  */
+  ainsn_t next_equiv_class_insn;
+  /* The following field value is nonzero if the insn declaration is
+     the first insn declaration with given equivalence number.  */
+  char first_ainsn_with_given_equialence_num;
+  /* The following field is number of class of equivalence of insns.
+     It is necessary because many insns may be equivalent with the
+     point of view of pipeline hazards.  */
+  int insn_equiv_class_num;
+};
+
+/* The folowing describes an automaton for PHR.  */
+struct automaton
+{
+  /* The following field value is the list of insn declarations for
+     given automaton.  */
+  ainsn_t ainsn_list;
+  /* The following field value is the corresponding automaton
+     declaration.  This field is not NULL only if the automatic
+     partition on automata is not used.  */
+  struct automaton_decl *corresponding_automaton_decl;
+  /* The following field value is the next automaton.  */
+  automaton_t next_automaton;
+  /* The following field is start state of FA.  There are not unit
+     reservations in the state.  */
+  state_t start_state;
+  /* The following field value is number of equivalence classes of
+     insns (see field `insn_equiv_class_num' in
+     `insn_reserv_decl').  */
+  int insn_equiv_classes_num;
+  /* The following field value is number of states of final DFA.  */
+  int achieved_states_num;
+  /* The following field value is the order number (0, 1, ...) of
+     given automaton.  */
+  int automaton_order_num;
+  /* The following fields contain statistics information about
+     building automaton.  */
+  int NDFA_states_num, DFA_states_num;
+  /* The following field value is defined only if minimization of DFA
+     is used.  */
+  int minimal_DFA_states_num;
+  int NDFA_arcs_num, DFA_arcs_num;
+  /* The following field value is defined only if minimization of DFA
+     is used.  */
+  int minimal_DFA_arcs_num;
+  /* The following two members refer for two table state x ainsn ->
+     int.  */
+  state_ainsn_table_t trans_table;
+  state_ainsn_table_t state_alts_table;
+  /* The following member value is maximal value of min issue delay
+     for insns of the automaton.  */
+  int max_min_delay;
+  /* Usually min issue delay is small and we can place several (2, 4,
+     8) elements in one vector element.  So the compression factor can
+     be 1 (no compression), 2, 4, 8.  */
+  int min_issue_delay_table_compression_factor;
+};
+
+/* The following structure describes a table state X ainsn -> int(>= 0).  */
+struct state_ainsn_table
+{
+  /* Automaton to which given table belongs.  */
+  automaton_t automaton;
+  /* The following tree vectors for comb vector implementation of the
+     table.  */
+  vla_hwint_t comb_vect;
+  vla_hwint_t check_vect;
+  vla_hwint_t base_vect;
+  /* This is simple implementation of the table.  */
+  vla_hwint_t full_vect;
+  /* Minimal and maximal values of the previous vectors.  */
+  int min_comb_vect_el_value, max_comb_vect_el_value;
+  int min_base_vect_el_value, max_base_vect_el_value;
+};
+
+/* Create IR structure (node).  */
+static void *
+create_node (size)
+     size_t size;
+{
+  void *result;
+
+  obstack_blank (&irp, size);
+  result = obstack_base (&irp);
+  obstack_finish (&irp);
+  /* Default values of members are NULL and zero.  */
+  memset (result, 0, size);
+  return result;
+}
+
+/* Copy IR structure (node).  */
+static void *
+copy_node (from, size)
+     void *from;
+     size_t size;
+{
+  void *result;
+  result = create_node (size);
+  memcpy (result, from, size);
+  return result;
+}
+
+/* The function checks that NAME does not contain quotes (`"').  */
+static char *
+check_name (name, pos)
+     char * name;
+     pos_t pos ATTRIBUTE_UNUSED;
+{
+  char *str;
+
+  for (str = name; *str != '\0'; str++)
+    if (*str == '\"')
+      error ("Name `%s' contains quotes", name);
+  return name;
+}
+
+/* Pointers top all declartions during IR generation are stored in the
+   following.  */
+static vla_ptr_t decls;
+
+/* Given a pointer to a (char *) and a separator, return a alloc'ed
+   string containing the next separated element, taking parentheses
+   into account if PAR_FLAG has nonzero value.  Advance the pointer to
+   after the string scanned, or the end-of-string.  Return NULL if at
+   end of string.  */
+static char *
+next_sep_el (pstr, sep, par_flag)
+     char **pstr;
+     int sep;
+     int par_flag;
+{
+  char *out_str;
+  char *p;
+  int pars_num;
+  int n_spaces;
+
+  /* Remove leading whitespaces.  */
+  while (isspace ((int) **pstr))
+    (*pstr)++;
+
+  if (**pstr == '\0')
+    return NULL;
+
+  n_spaces = 0;
+  for (pars_num = 0, p = *pstr; *p != '\0'; p++)
+    {
+      if (par_flag && *p == '(')
+       pars_num++;
+      else if (par_flag && *p == ')')
+       pars_num--;
+      else if (pars_num == 0 && *p == sep)
+       break;
+      if (pars_num == 0 && isspace ((int) *p))
+       n_spaces++;
+      else
+       {
+         for (; n_spaces != 0; n_spaces--)
+           obstack_1grow (&irp, p [-n_spaces]);
+         obstack_1grow (&irp, *p);
+       }
+    }
+  obstack_1grow (&irp, '\0');
+  out_str = obstack_base (&irp);
+  obstack_finish (&irp);
+
+  *pstr = p;
+  if (**pstr == sep)
+    (*pstr)++;
+
+  return out_str;
+}
+
+/* Given a string and a separator, return the number of separated
+   elements in it, taking parentheses into account if PAR_FLAG has
+   nonzero value.  Return 0 for the null string, -1 if parantheses is
+   not balanced.  */
+static int
+n_sep_els (s, sep, par_flag)
+     char *s;
+     int sep;
+     int par_flag;
+{
+  int n;
+  int pars_num;
+
+  if (*s == '\0')
+    return 0;
+
+  for (pars_num = 0, n = 1; *s; s++)
+    if (par_flag && *s == '(')
+      pars_num++;
+    else if (par_flag && *s == ')')
+      pars_num--;
+    else if (pars_num == 0 && *s == sep)
+      n++;
+
+  return (pars_num != 0 ? -1 : n);
+}
+
+/* Given a string and a separator, return vector of strings which are
+   elements in the string and number of elements through els_num.
+   Take parentheses into account if PAR_FLAG has nonzero value.
+   Return 0 for the null string, -1 if parantheses are not balanced.  */
+static char **
+get_str_vect (str, els_num, sep, par_flag)
+     char *str;
+     int *els_num;
+     int sep;
+     int par_flag;
+{
+  int i;
+  char **vect;
+  char **pstr;
+
+  *els_num = n_sep_els (str, sep, par_flag);
+  if (*els_num <= 0)
+    return NULL;
+  obstack_blank (&irp, sizeof (char *) * (*els_num));
+  vect = (char **) obstack_base (&irp);
+  obstack_finish (&irp);
+  pstr = &str;
+  for (i = 0; i < *els_num; i++)
+    vect [i] = next_sep_el (pstr, sep, par_flag);
+  if (next_sep_el (pstr, sep, par_flag) != NULL)
+    abort ();
+  return vect;
+}
+
+/* Process a DEFINE_CPU_UNIT.  
+
+   This gives information about a unit contained in CPU.  We fill a
+   struct unit_decl with information used later by `expand_automata'.  */
+void
+gen_cpu_unit (def)
+     rtx def;
+{
+  decl_t decl;
+  char **str_cpu_units;
+  int vect_length;
+  int i;
+
+  str_cpu_units = get_str_vect ((char *) XSTR (def, 0), &vect_length, ',', 0);
+  if (str_cpu_units == NULL)
+    fatal ("invalid string `%s' in define_cpu_unit", XSTR (def, 0));
+  for (i = 0; i < vect_length; i++)
+    {
+      decl = create_node (sizeof (struct decl));
+      decl->mode = dm_unit;
+      decl->pos = 0;
+      decl->decl.unit.name = check_name (str_cpu_units [i], decl->pos);
+      decl->decl.unit.automaton_name = (char *) XSTR (def, 1);
+      decl->decl.unit.query_p = 0;
+      VLA_PTR_ADD (decls, decl);
+      num_dfa_decls++;
+    }
+}
+
+/* Process a DEFINE_QUERY_CPU_UNIT.  
+
+   This gives information about a unit contained in CPU.  We fill a
+   struct unit_decl with information used later by `expand_automata'.  */
+void
+gen_query_cpu_unit (def)
+     rtx def;
+{
+  decl_t decl;
+  char **str_cpu_units;
+  int vect_length;
+  int i;
+
+  str_cpu_units = get_str_vect ((char *) XSTR (def, 0), &vect_length, ',', 0);
+  if (str_cpu_units == NULL)
+    fatal ("invalid string `%s' in define_query_cpu_unit", XSTR (def, 0));
+  for (i = 0; i < vect_length; i++)
+    {
+      decl = create_node (sizeof (struct decl));
+      decl->mode = dm_unit;
+      decl->pos = 0;
+      decl->decl.unit.name = check_name (str_cpu_units [i], decl->pos);
+      decl->decl.unit.automaton_name = (char *) XSTR (def, 1);
+      decl->decl.unit.query_p = 1;
+      VLA_PTR_ADD (decls, decl);
+      num_dfa_decls++;
+    }
+}
+
+/* Process a DEFINE_BYPASS.  
+
+   This gives information about a unit contained in the CPU.  We fill
+   in a struct bypass_decl with information used later by
+   `expand_automata'.  */
+void
+gen_bypass (def)
+     rtx def;
+{
+  decl_t decl;
+  char **out_insns;
+  int out_length;
+  char **in_insns;
+  int in_length;
+  int i, j;
+
+  out_insns = get_str_vect ((char *) XSTR (def, 1), &out_length, ',', 0);
+  if (out_insns == NULL)
+    fatal ("invalid string `%s' in define_bypass", XSTR (def, 1));
+  in_insns = get_str_vect ((char *) XSTR (def, 2), &in_length, ',', 0);
+  if (in_insns == NULL)
+    fatal ("invalid string `%s' in define_bypass", XSTR (def, 2));
+  for (i = 0; i < out_length; i++)
+    for (j = 0; j < in_length; j++)
+      {
+       decl = create_node (sizeof (struct decl));
+       decl->mode = dm_bypass;
+       decl->pos = 0;
+       decl->decl.bypass.latency = XINT (def, 0);
+       decl->decl.bypass.out_insn_name = out_insns [i];
+       decl->decl.bypass.in_insn_name = in_insns [j];
+       decl->decl.bypass.bypass_guard_name = (char *) XSTR (def, 3);
+       VLA_PTR_ADD (decls, decl);
+       num_dfa_decls++;
+      }
+}
+
+/* Process a EXCLUSION_SET.  
+
+   This gives information about a cpu unit conflicts.  We fill a
+   struct unit_rel_decl (excl) with information used later by
+   `expand_automata'.  */
+void
+gen_excl_set (def)
+     rtx def;
+{
+  decl_t decl;
+  char **first_str_cpu_units;
+  char **second_str_cpu_units;
+  int first_vect_length;
+  int length;
+  int i;
+
+  first_str_cpu_units
+    = get_str_vect ((char *) XSTR (def, 0), &first_vect_length, ',', 0);
+  if (first_str_cpu_units == NULL)
+    fatal ("invalid first string `%s' in exclusion_set", XSTR (def, 0));
+  second_str_cpu_units = get_str_vect ((char *) XSTR (def, 1), &length, ',',
+                                      0);
+  if (second_str_cpu_units == NULL)
+    fatal ("invalid second string `%s' in exclusion_set", XSTR (def, 1));
+  length += first_vect_length;
+  decl = create_node (sizeof (struct decl) + (length - 1) * sizeof (char *));
+  decl->mode = dm_excl;
+  decl->pos = 0;
+  decl->decl.excl.names_num = length;
+  decl->decl.excl.first_list_length = first_vect_length;
+  for (i = 0; i < length; i++)
+    if (i < first_vect_length)
+      decl->decl.excl.names [i] = first_str_cpu_units [i];
+    else
+      decl->decl.excl.names [i] = second_str_cpu_units [i - first_vect_length];
+  VLA_PTR_ADD (decls, decl);
+  num_dfa_decls++;
+}
+
+/* Process a PRESENCE_SET.  
+
+   This gives information about a cpu unit reservation requirements.
+   We fill a struct unit_rel_decl (presence) with information used
+   later by `expand_automata'.  */
+void
+gen_presence_set (def)
+     rtx def;
+{
+  decl_t decl;
+  char **first_str_cpu_units;
+  char **second_str_cpu_units;
+  int first_vect_length;
+  int length;
+  int i;
+
+  first_str_cpu_units
+    = get_str_vect ((char *) XSTR (def, 0), &first_vect_length, ',', 0);
+  if (first_str_cpu_units == NULL)
+    fatal ("invalid first string `%s' in presence_set", XSTR (def, 0));
+  second_str_cpu_units = get_str_vect ((char *) XSTR (def, 1), &length, ',',
+                                      0);
+  if (second_str_cpu_units == NULL)
+    fatal ("invalid second string `%s' in presence_set", XSTR (def, 1));
+  length += first_vect_length;
+  decl = create_node (sizeof (struct decl) + (length - 1) * sizeof (char *));
+  decl->mode = dm_presence;
+  decl->pos = 0;
+  decl->decl.presence.names_num = length;
+  decl->decl.presence.first_list_length = first_vect_length;
+  for (i = 0; i < length; i++)
+    if (i < first_vect_length)
+      decl->decl.presence.names [i] = first_str_cpu_units [i];
+    else
+      decl->decl.presence.names [i]
+       = second_str_cpu_units [i - first_vect_length];
+  VLA_PTR_ADD (decls, decl);
+  num_dfa_decls++;
+}
+
+/* Process a ABSENCE_SET.  
+
+   This gives information about a cpu unit reservation requirements.
+   We fill a struct unit_rel_decl (absence) with information used
+   later by `expand_automata'.  */
+void
+gen_absence_set (def)
+     rtx def;
+{
+  decl_t decl;
+  char **first_str_cpu_units;
+  char **second_str_cpu_units;
+  int first_vect_length;
+  int length;
+  int i;
+
+  first_str_cpu_units
+    = get_str_vect ((char *) XSTR (def, 0), &first_vect_length, ',', 0);
+  if (first_str_cpu_units == NULL)
+    fatal ("invalid first string `%s' in absence_set", XSTR (def, 0));
+  second_str_cpu_units = get_str_vect ((char *) XSTR (def, 1), &length, ',',
+                                      0);
+  if (second_str_cpu_units == NULL)
+    fatal ("invalid second string `%s' in absence_set", XSTR (def, 1));
+  length += first_vect_length;
+  decl = create_node (sizeof (struct decl) + (length - 1) * sizeof (char *));
+  decl->mode = dm_absence;
+  decl->pos = 0;
+  decl->decl.absence.names_num = length;
+  decl->decl.absence.first_list_length = first_vect_length;
+  for (i = 0; i < length; i++)
+    if (i < first_vect_length)
+      decl->decl.absence.names [i] = first_str_cpu_units [i];
+    else
+      decl->decl.absence.names [i]
+       = second_str_cpu_units [i - first_vect_length];
+  VLA_PTR_ADD (decls, decl);
+  num_dfa_decls++;
+}
+
+/* Process a DEFINE_AUTOMATON.  
+
+   This gives information about a finite state automaton used for
+   recognizing pipeline hazards.  We fill a struct automaton_decl
+   with information used later by `expand_automata'.  */
+void
+gen_automaton (def)
+     rtx def;
+{
+  decl_t decl;
+  char **str_automata;
+  int vect_length;
+  int i;
+
+  str_automata = get_str_vect ((char *) XSTR (def, 0), &vect_length, ',', 0);
+  if (str_automata == NULL)
+    fatal ("invalid string `%s' in define_automaton", XSTR (def, 0));
+  for (i = 0; i < vect_length; i++)
+    {
+      decl = create_node (sizeof (struct decl));
+      decl->mode = dm_automaton;
+      decl->pos = 0;
+      decl->decl.automaton.name = check_name (str_automata [i], decl->pos);
+      VLA_PTR_ADD (decls, decl);
+      num_dfa_decls++;
+    }
+}
+
+/* Process a AUTOMATA_OPTION.  
+
+   This gives information how to generate finite state automaton used
+   for recognizing pipeline hazards.  */
+void
+gen_automata_option (def)
+     rtx def;
+{
+  if (strcmp ((char *) XSTR (def, 0), NO_MINIMIZATION_OPTION + 1) == 0)
+    no_minimization_flag = 1;
+  else if (strcmp ((char *) XSTR (def, 0), W_OPTION + 1) == 0)
+    w_flag = 1;
+  else if (strcmp ((char *) XSTR (def, 0), NDFA_OPTION + 1) == 0)
+    ndfa_flag = 1;
+  else
+    fatal ("invalid option `%s' in automata_option", XSTR (def, 0));
+}
+
+/* Name in reservation to denote absence reservation.  */
+#define NOTHING_NAME "nothing"
+
+/* The following string contains original reservation string being
+   parsed.  */
+static char *reserv_str;
+
+/* Parse an element in STR.  */
+static regexp_t
+gen_regexp_el (str)
+     char *str;
+{
+  regexp_t regexp;
+  int len;
+
+  if (*str == '(')
+    {
+      len = strlen (str);
+      if (str [len - 1] != ')')
+       fatal ("garbage after ) in reservation `%s'", reserv_str);
+      str [len - 1] = '\0';
+      regexp = gen_regexp_sequence (str + 1);
+    }
+  else if (strcmp (str, NOTHING_NAME) == 0)
+    {
+      regexp = create_node (sizeof (struct decl));
+      regexp->mode = rm_nothing;
+    }
+  else
+    {
+      regexp = create_node (sizeof (struct decl));
+      regexp->mode = rm_unit;
+      regexp->regexp.unit.name = str;
+    }
+  return regexp;
+}
+
+/* Parse construction `repeat' in STR.  */
+static regexp_t
+gen_regexp_repeat (str)
+     char *str;
+{
+  regexp_t regexp;
+  regexp_t repeat;
+  char **repeat_vect;
+  int els_num;
+  int i;
+
+  repeat_vect = get_str_vect (str, &els_num, '*', 1);
+  if (repeat_vect == NULL)
+    fatal ("invalid `%s' in reservation `%s'", str, reserv_str);
+  if (els_num > 1)
+    {
+      regexp = gen_regexp_el (repeat_vect [0]);
+      for (i = 1; i < els_num; i++)
+       {
+         repeat = create_node (sizeof (struct regexp));
+         repeat->mode = rm_repeat;
+         repeat->regexp.repeat.regexp = regexp;
+         repeat->regexp.repeat.repeat_num = atoi (repeat_vect [i]);
+          if (repeat->regexp.repeat.repeat_num <= 1)
+            fatal ("repetition `%s' <= 1 in reservation `%s'",
+                   str, reserv_str);
+          regexp = repeat;
+       }
+      return regexp;
+    }
+  else
+    return gen_regexp_el (str);
+}
+
+/* Parse reservation STR which possibly contains separator '+'.  */
+static regexp_t
+gen_regexp_allof (str)
+     char *str;
+{
+  regexp_t allof;
+  char **allof_vect;
+  int els_num;
+  int i;
+
+  allof_vect = get_str_vect (str, &els_num, '+', 1);
+  if (allof_vect == NULL)
+    fatal ("invalid `%s' in reservation `%s'", str, reserv_str);
+  if (els_num > 1)
+    {
+      allof = create_node (sizeof (struct regexp)
+                          + sizeof (regexp_t) * (els_num - 1));
+      allof->mode = rm_allof;
+      allof->regexp.allof.regexps_num = els_num;
+      for (i = 0; i < els_num; i++)
+       allof->regexp.allof.regexps [i] = gen_regexp_repeat (allof_vect [i]);
+      return allof;
+    }
+  else
+    return gen_regexp_repeat (str);
+}
+
+/* Parse reservation STR which possibly contains separator '|'.  */
+static regexp_t
+gen_regexp_oneof (str)
+     char *str;
+{
+  regexp_t oneof;
+  char **oneof_vect;
+  int els_num;
+  int i;
+
+  oneof_vect = get_str_vect (str, &els_num, '|', 1);
+  if (oneof_vect == NULL)
+    fatal ("invalid `%s' in reservation `%s'", str, reserv_str);
+  if (els_num > 1)
+    {
+      oneof = create_node (sizeof (struct regexp)
+                          + sizeof (regexp_t) * (els_num - 1));
+      oneof->mode = rm_oneof;
+      oneof->regexp.oneof.regexps_num = els_num;
+      for (i = 0; i < els_num; i++)
+       oneof->regexp.oneof.regexps [i] = gen_regexp_allof (oneof_vect [i]);
+      return oneof;
+    }
+  else
+    return gen_regexp_allof (str);
+}
+
+/* Parse reservation STR which possibly contains separator ','.  */
+static regexp_t
+gen_regexp_sequence (str)
+     char *str;
+{
+  regexp_t sequence;
+  char **sequence_vect;
+  int els_num;
+  int i;
+
+  sequence_vect = get_str_vect (str, &els_num, ',', 1);
+  if (els_num > 1)
+    {
+      sequence = create_node (sizeof (struct regexp)
+                             + sizeof (regexp_t) * (els_num - 1));
+      sequence->mode = rm_sequence;
+      sequence->regexp.sequence.regexps_num = els_num;
+      for (i = 0; i < els_num; i++)
+       sequence->regexp.sequence.regexps [i]
+          = gen_regexp_oneof (sequence_vect [i]);
+      return sequence;
+    }
+  else
+    return gen_regexp_oneof (str);
+}
+
+/* Parse construction reservation STR.  */
+static regexp_t
+gen_regexp (str)
+     char *str;
+{
+  reserv_str = str;
+  return gen_regexp_sequence (str);;
+}
+
+/* Process a DEFINE_RESERVATION.
+
+   This gives information about a reservation of cpu units.  We fill
+   in a struct reserv_decl with information used later by
+   `expand_automata'.  */
+void
+gen_reserv (def)
+     rtx def;
+{
+  decl_t decl;
+
+  decl = create_node (sizeof (struct decl));
+  decl->mode = dm_reserv;
+  decl->pos = 0;
+  decl->decl.reserv.name = check_name ((char *) XSTR (def, 0), decl->pos);
+  decl->decl.reserv.regexp = gen_regexp ((char *) XSTR (def, 1));
+  VLA_PTR_ADD (decls, decl);
+  num_dfa_decls++;
+}
+
+/* Process a DEFINE_INSN_RESERVATION.
+
+   This gives information about the reservation of cpu units by an
+   insn.  We fill a struct insn_reserv_decl with information used
+   later by `expand_automata'.  */
+void
+gen_insn_reserv (def)
+     rtx def;
+{
+  decl_t decl;
+
+  decl = create_node (sizeof (struct decl));
+  decl->mode = dm_insn_reserv;
+  decl->pos = 0;
+  decl->decl.insn_reserv.name = check_name ((char *) XSTR (def, 0), decl->pos);
+  decl->decl.insn_reserv.default_latency = XINT (def, 1);
+  decl->decl.insn_reserv.condexp = XEXP (def, 2);
+  decl->decl.insn_reserv.regexp = gen_regexp ((char *) XSTR (def, 3));
+  VLA_PTR_ADD (decls, decl);
+  num_dfa_decls++;
+}
+
+\f
+
+/* The function evaluates hash value (0..UINT_MAX) of string.  */
+static unsigned
+string_hash (string)
+     const char *string;
+{
+  unsigned result, i;
+
+  for (result = i = 0;*string++ != '\0'; i++)
+    result += ((unsigned char) *string << (i % CHAR_BIT));
+  return result;
+}
+
+\f
+
+/* This page contains abstract data `table of automaton declarations'.
+   Elements of the table is nodes representing automaton declarations.
+   Key of the table elements is name of given automaton.  Rememeber
+   that automaton names have own space.  */
+
+/* The function evaluates hash value of a automaton declaration.  The
+   function is used by abstract data `hashtab'.  The function returns
+   hash value (0..UINT_MAX) of given automaton declaration.  */
+static unsigned
+automaton_decl_hash (automaton_decl)
+     const void *automaton_decl;
+{
+  const decl_t decl = (decl_t) automaton_decl;
+
+  if (decl->mode == dm_automaton && decl->decl.automaton.name == NULL)
+    abort ();
+  return string_hash (decl->decl.automaton.name);
+}
+
+/* The function tests automaton declarations on equality of their
+   keys.  The function is used by abstract data `hashtab'.  The
+   function returns 1 if the declarations have the same key, 0
+   otherwise.  */
+static int
+automaton_decl_eq_p (automaton_decl_1, automaton_decl_2)
+     const void* automaton_decl_1;
+     const void* automaton_decl_2;
+{
+  const decl_t decl1 = (decl_t) automaton_decl_1;
+  const decl_t decl2 = (decl_t) automaton_decl_2;
+
+  if (decl1->mode != dm_automaton || decl1->decl.automaton.name == NULL
+      || decl2->mode != dm_automaton || decl2->decl.automaton.name == NULL)
+    abort ();
+  return strcmp (decl1->decl.automaton.name, decl2->decl.automaton.name) == 0;
+}
+
+/* The automaton declaration table itself is represented by the
+   following variable.  */
+static htab_t automaton_decl_table;
+
+/* The function inserts automaton declaration into the table.  The
+   function does nothing if an automaton declaration with the same key
+   exists already in the table.  The function returns automaton
+   declaration node in the table with the same key as given automaton
+   declaration node.  */
+static decl_t
+insert_automaton_decl (automaton_decl)
+     decl_t automaton_decl;
+{
+  void **entry_ptr;
+
+  entry_ptr = htab_find_slot (automaton_decl_table, automaton_decl, 1);
+  if (*entry_ptr == NULL)
+    *entry_ptr = (void *) automaton_decl;
+  return (decl_t) *entry_ptr;
+}
+
+/* The following variable value is node representing automaton
+   declaration.  The node used for searching automaton declaration
+   with given name.  */
+static struct decl work_automaton_decl;
+
+/* The function searches for automaton declaration in the table with
+   the same key as node representing name of the automaton
+   declaration.  The function returns node found in the table, NULL if
+   such node does not exist in the table.  */
+static decl_t
+find_automaton_decl (name)
+     char *name;
+{
+  void *entry;
+
+  work_automaton_decl.decl.automaton.name = name;
+  entry = htab_find (automaton_decl_table, &work_automaton_decl);
+  return (decl_t) entry;
+}
+
+/* The function creates empty automaton declaration table and node
+   representing automaton declaration and used for searching automaton
+   declaration with given name.  The function must be called only once
+   before any work with the automaton declaration table.  */
+static void
+initiate_automaton_decl_table ()
+{
+  work_automaton_decl.mode = dm_automaton;
+  automaton_decl_table = htab_create (10, automaton_decl_hash,
+                                     automaton_decl_eq_p, (htab_del) 0);
+}
+
+/* The function deletes the automaton declaration table.  Only call of
+   function `initiate_automaton_decl_table' is possible immediately
+   after this function call.  */
+static void
+finish_automaton_decl_table ()
+{
+  htab_delete (automaton_decl_table);
+}
+
+\f
+
+/* This page contains abstract data `table of insn declarations'.
+   Elements of the table is nodes representing insn declarations.  Key
+   of the table elements is name of given insn (in corresponding
+   define_insn_reservation).  Rememeber that insn names have own
+   space.  */
+
+/* The function evaluates hash value of a insn declaration.  The
+   function is used by abstract data `hashtab'.  The function returns
+   hash value (0..UINT_MAX) of given insn declaration.  */
+static unsigned
+insn_decl_hash (insn_decl)
+     const void *insn_decl;
+{
+  const decl_t decl = (decl_t) insn_decl;
+
+  if (decl->mode != dm_insn_reserv || decl->decl.insn_reserv.name == NULL)
+    abort ();
+  return string_hash (decl->decl.insn_reserv.name);
+}
+
+/* The function tests insn declarations on equality of their keys.
+   The function is used by abstract data `hashtab'.  The function
+   returns 1 if declarations have the same key, 0 otherwise.  */
+static int
+insn_decl_eq_p (insn_decl_1, insn_decl_2)
+     const void *insn_decl_1;
+     const void *insn_decl_2;
+{
+  const decl_t decl1 = (decl_t) insn_decl_1;
+  const decl_t decl2 = (decl_t) insn_decl_2;
+
+  if (decl1->mode != dm_insn_reserv || decl1->decl.insn_reserv.name == NULL
+      || decl2->mode != dm_insn_reserv || decl2->decl.insn_reserv.name == NULL)
+    abort ();
+  return strcmp (decl1->decl.insn_reserv.name,
+                 decl2->decl.insn_reserv.name) == 0;
+}
+
+/* The insn declaration table itself is represented by the following
+   variable.  The table does not contain insn reservation
+   declarations.  */
+static htab_t insn_decl_table;
+
+/* The function inserts insn declaration into the table.  The function
+   does nothing if an insn declaration with the same key exists
+   already in the table.  The function returns insn declaration node
+   in the table with the same key as given insn declaration node.  */
+static decl_t
+insert_insn_decl (insn_decl)
+     decl_t insn_decl;
+{
+  void **entry_ptr;
+
+  entry_ptr = htab_find_slot (insn_decl_table, insn_decl, 1);
+  if (*entry_ptr == NULL)
+    *entry_ptr = (void *) insn_decl;
+  return (decl_t) *entry_ptr;
+}
+
+/* The following variable value is node representing insn reservation
+   declaration.  The node used for searching insn reservation
+   declaration with given name.  */
+static struct decl work_insn_decl;
+
+/* The function searches for insn reservation declaration in the table
+   with the same key as node representing name of the insn reservation
+   declaration.  The function returns node found in the table, NULL if
+   such node does not exist in the table.  */
+static decl_t
+find_insn_decl (name)
+     char *name;
+{
+  void *entry;
+
+  work_insn_decl.decl.insn_reserv.name = name;
+  entry = htab_find (insn_decl_table, &work_insn_decl);
+  return (decl_t) entry;
+}
+
+/* The function creates empty insn declaration table and node
+   representing insn declaration and used for searching insn
+   declaration with given name.  The function must be called only once
+   before any work with the insn declaration table.  */
+static void
+initiate_insn_decl_table ()
+{
+  work_insn_decl.mode = dm_insn_reserv;
+  insn_decl_table = htab_create (10, insn_decl_hash, insn_decl_eq_p,
+                                (htab_del) 0);
+}
+
+/* The function deletes the insn declaration table.  Only call of
+   function `initiate_insn_decl_table' is possible immediately after
+   this function call.  */
+static void
+finish_insn_decl_table ()
+{
+  htab_delete (insn_decl_table);
+}
+
+\f
+
+/* This page contains abstract data `table of declarations'.  Elements
+   of the table is nodes representing declarations (of units and
+   reservations).  Key of the table elements is names of given
+   declarations.  */
+
+/* The function evaluates hash value of a declaration.  The function
+   is used by abstract data `hashtab'.  The function returns hash
+   value (0..UINT_MAX) of given declaration.  */
+static unsigned
+decl_hash (decl)
+     const void *decl;
+{
+  const decl_t d = (const decl_t) decl;
+
+  if ((d->mode != dm_unit || d->decl.unit.name == NULL)
+      && (d->mode != dm_reserv || d->decl.reserv.name == NULL))
+    abort ();
+  return string_hash (d->mode == dm_unit
+                     ? d->decl.unit.name : d->decl.reserv.name);
+}
+
+/* The function tests declarations on equality of their keys.  The
+   function is used by abstract data `hashtab'.  The function
+   returns 1 if the declarations have the same key, 0 otherwise.  */
+static int
+decl_eq_p (decl_1, decl_2)
+     const void *decl_1;
+     const void *decl_2;
+{
+  const decl_t d1 = (const decl_t) decl_1;
+  const decl_t d2 = (const decl_t) decl_2;
+
+  if (((d1->mode != dm_unit || d1->decl.unit.name == NULL)
+       && (d1->mode != dm_reserv || d1->decl.reserv.name == NULL))
+      || ((d2->mode != dm_unit || d2->decl.unit.name == NULL)
+         && (d2->mode != dm_reserv || d2->decl.reserv.name == NULL)))
+    abort ();
+  return strcmp ((d1->mode == dm_unit
+                  ? d1->decl.unit.name : d1->decl.reserv.name),
+                 (d2->mode == dm_unit
+                  ? d2->decl.unit.name : d2->decl.reserv.name)) == 0;
+}
+
+/* The declaration table itself is represented by the following
+   variable.  */
+static htab_t decl_table;
+
+/* The function inserts declaration into the table.  The function does
+   nothing if a declaration with the same key exists already in the
+   table.  The function returns declaration node in the table with the
+   same key as given declaration node.  */
+
+static decl_t
+insert_decl (decl)
+     decl_t decl;
+{
+  void **entry_ptr;
+
+  entry_ptr = htab_find_slot (decl_table, decl, 1);
+  if (*entry_ptr == NULL)
+    *entry_ptr = (void *) decl;
+  return (decl_t) *entry_ptr;
+}
+
+/* The following variable value is node representing declaration.  The
+   node used for searching declaration with given name.  */
+static struct decl work_decl;
+
+/* The function searches for declaration in the table with the same
+   key as node representing name of the declaration.  The function
+   returns node found in the table, NULL if such node does not exist
+   in the table.  */
+static decl_t
+find_decl (name)
+     char *name;
+{
+  void *entry;
+
+  work_decl.decl.unit.name = name;
+  entry = htab_find (decl_table, &work_decl);
+  return (decl_t) entry;
+}
+
+/* The function creates empty declaration table and node representing
+   declaration and used for searching declaration with given name.
+   The function must be called only once before any work with the
+   declaration table.  */
+static void
+initiate_decl_table ()
+{
+  work_decl.mode = dm_unit;
+  decl_table = htab_create (10, decl_hash, decl_eq_p, (htab_del) 0);
+}
+
+/* The function deletes the declaration table.  Only call of function
+   `initiate_declaration_table' is possible immediately after this
+   function call.  */
+static void
+finish_decl_table ()
+{
+  htab_delete (decl_table);
+}
+
+\f
+
+/* This page contains checker of pipeline hazard description.  */
+
+/* Checking NAMES in an exclusion clause vector and returning formed
+   unit_set_el_list.  */
+static unit_set_el_t
+process_excls (names, num, excl_pos)
+     char **names;
+     int num;
+     pos_t excl_pos ATTRIBUTE_UNUSED;
+{
+  unit_set_el_t el_list;
+  unit_set_el_t last_el;
+  unit_set_el_t new_el;
+  decl_t decl_in_table;
+  int i;
+
+  el_list = NULL;
+  last_el = NULL;
+  for (i = 0; i < num; i++)
+    {
+      decl_in_table = find_decl (names [i]);
+      if (decl_in_table == NULL)
+       error ("unit `%s' in exclusion is not declared", names [i]);
+      else if (decl_in_table->mode != dm_unit)
+       error ("`%s' in exclusion is not unit", names [i]);
+      else
+       {
+         new_el = create_node (sizeof (struct unit_set_el));
+         new_el->unit_decl = &decl_in_table->decl.unit;
+         new_el->next_unit_set_el = NULL;
+         if (last_el == NULL)
+           el_list = last_el = new_el;
+         else
+           {
+             last_el->next_unit_set_el = new_el;
+             last_el = last_el->next_unit_set_el;
+           }
+       }
+    }
+  return el_list;
+}
+
+/* The function adds each element from SOURCE_LIST to the exclusion
+   list of the each element from DEST_LIST.  Checking situation "unit
+   excludes itself".  */
+static void
+add_excls (dest_list, source_list, excl_pos)
+     unit_set_el_t dest_list;
+     unit_set_el_t source_list;
+     pos_t excl_pos ATTRIBUTE_UNUSED;
+{
+  unit_set_el_t dst;
+  unit_set_el_t src;
+  unit_set_el_t curr_el;
+  unit_set_el_t prev_el;
+  unit_set_el_t copy;
+
+  for (dst = dest_list; dst != NULL; dst = dst->next_unit_set_el)
+    for (src = source_list; src != NULL; src = src->next_unit_set_el)
+      {
+       if (dst->unit_decl == src->unit_decl)
+         {
+           error ("unit `%s' excludes itself", src->unit_decl->name);
+           continue;
+         }
+       for (curr_el = dst->unit_decl->excl_list, prev_el = NULL;
+            curr_el != NULL;
+            prev_el = curr_el, curr_el = curr_el->next_unit_set_el)
+         if (curr_el->unit_decl == src->unit_decl)
+           break;
+       if (curr_el == NULL)
+         {
+           /* Element not found - insert.  */
+           copy = copy_node (src, sizeof (*src));
+           copy->next_unit_set_el = NULL;
+           if (prev_el == NULL)
+             dst->unit_decl->excl_list = copy;
+           else
+             prev_el->next_unit_set_el = copy;
+       }
+    }
+}
+
+/* Checking NAMES in an presence clause vector and returning formed
+   unit_set_el_list.  The function is called only after processing all
+   exclusion sets.  */
+static unit_set_el_t
+process_presence_absence (names, num, req_pos, presence_p)
+     char **names;
+     int num;
+     pos_t req_pos ATTRIBUTE_UNUSED;
+     int presence_p;
+{
+  unit_set_el_t el_list;
+  unit_set_el_t last_el;
+  unit_set_el_t new_el;
+  decl_t decl_in_table;
+  int i;
+
+  el_list = NULL;
+  last_el = NULL;
+  for (i = 0; i < num; i++)
+    {
+      decl_in_table = find_decl (names [i]);
+      if (decl_in_table == NULL)
+       error ((presence_p
+               ? "unit `%s' in presence set is not declared"
+               : "unit `%s' in absence set is not declared"), names [i]);
+      else if (decl_in_table->mode != dm_unit)
+       error ((presence_p
+               ? "`%s' in presence set is not unit"
+               : "`%s' in absence set is not unit"), names [i]);
+      else
+       {
+         new_el = create_node (sizeof (struct unit_set_el));
+         new_el->unit_decl = &decl_in_table->decl.unit;
+         new_el->next_unit_set_el = NULL;
+         if (last_el == NULL)
+           el_list = last_el = new_el;
+         else
+           {
+             last_el->next_unit_set_el = new_el;
+             last_el = last_el->next_unit_set_el;
+           }
+       }
+    }
+  return el_list;
+}
+
+/* The function adds each element from SOURCE_LIST to presence (if
+   PRESENCE_P) or absence list of the each element from DEST_LIST.
+   Checking situations "unit requires own presence", "unit requires
+   own absence", and "unit excludes and requires presence of ...".
+   Remember that we process absence sets only after all presence
+   sets.  */
+static void
+add_presence_absence (dest_list, source_list, req_pos, presence_p)
+     unit_set_el_t dest_list;
+     unit_set_el_t source_list;
+     pos_t req_pos ATTRIBUTE_UNUSED;
+     int presence_p;
+{
+  unit_set_el_t dst;
+  unit_set_el_t src;
+  unit_set_el_t curr_el;
+  unit_set_el_t prev_el;
+  unit_set_el_t copy;
+
+  for (dst = dest_list; dst != NULL; dst = dst->next_unit_set_el)
+    for (src = source_list; src != NULL; src = src->next_unit_set_el)
+      {
+       if (dst->unit_decl == src->unit_decl)
+         {
+           error ((presence_p
+                   ? "unit `%s' requires own presence"
+                   : "unit `%s' requires own absence"), src->unit_decl->name);
+           continue;
+         }
+       for (curr_el = (presence_p
+                       ? dst->unit_decl->presence_list
+                       : dst->unit_decl->absence_list), prev_el = NULL;
+            curr_el != NULL;
+            prev_el = curr_el, curr_el = curr_el->next_unit_set_el)
+         if (curr_el->unit_decl == src->unit_decl)
+           break;
+       if (curr_el == NULL)
+         {
+           /* Element not found - insert if there is no error.  */
+           int no_error_flag = 1;
+
+           if (presence_p)
+             for (curr_el = dst->unit_decl->excl_list;
+                  curr_el != NULL;
+                  curr_el = curr_el->next_unit_set_el)
+               {
+                 if (src->unit_decl == curr_el->unit_decl)
+                   {
+                     if (!w_flag)
+                       {
+                         error
+                           ("unit `%s' excludes and requires presence of `%s'",
+                            dst->unit_decl->name, src->unit_decl->name);
+                         no_error_flag = 0;
+                       }
+                     else
+                       warning
+                         ("unit `%s' excludes and requires presence of `%s'",
+                          dst->unit_decl->name, src->unit_decl->name);
+                   }
+               }
+           else
+             for (curr_el = dst->unit_decl->presence_list;
+                  curr_el != NULL;
+                  curr_el = curr_el->next_unit_set_el)
+               {
+                 if (src->unit_decl == curr_el->unit_decl)
+                   {
+                     if (!w_flag)
+                       {
+                         error
+                           ("unit `%s' requires absence and presence of `%s'",
+                            dst->unit_decl->name, src->unit_decl->name);
+                         no_error_flag = 0;
+                       }
+                     else
+                       warning
+                         ("unit `%s' requires absence and presence of `%s'",
+                          dst->unit_decl->name, src->unit_decl->name);
+                   }
+               }
+           if (no_error_flag)
+             {
+               copy = copy_node (src, sizeof (*src));
+               copy->next_unit_set_el = NULL;
+               if (prev_el == NULL)
+                 {
+                   if (presence_p)
+                     dst->unit_decl->presence_list = copy;
+                   else
+                     dst->unit_decl->absence_list = copy;
+                 }
+               else
+                 prev_el->next_unit_set_el = copy;
+             }
+       }
+    }
+}
+
+/* The function searches for bypass with given IN_INSN_RESERV in given
+   BYPASS_LIST.  */
+static struct bypass_decl *
+find_bypass (bypass_list, in_insn_reserv)
+     struct bypass_decl *bypass_list;
+     struct insn_reserv_decl *in_insn_reserv;
+{
+  struct bypass_decl *bypass;
+
+  for (bypass = bypass_list; bypass != NULL; bypass = bypass->next)
+    if (bypass->in_insn_reserv == in_insn_reserv)
+      break;
+  return bypass;
+}
+
+/* The function processes pipeline description declarations, checks
+   their correctness, and forms exclusion/presence/absence sets.  */
+static void
+process_decls ()
+{
+  decl_t decl;
+  decl_t automaton_decl;
+  decl_t decl_in_table;
+  decl_t out_insn_reserv;
+  decl_t in_insn_reserv;
+  struct bypass_decl *bypass;
+  int automaton_presence;
+  int i;
+
+  /* Checking repeated automata declarations.  */
+  automaton_presence = 0;
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_automaton)
+       {
+         automaton_presence = 1;
+         decl_in_table = insert_automaton_decl (decl);
+         if (decl_in_table != decl)
+           {
+             if (!w_flag)
+               error ("repeated declaration of automaton `%s'",
+                      decl->decl.automaton.name);
+             else
+               warning ("repeated declaration of automaton `%s'",
+                        decl->decl.automaton.name);
+           }
+       }
+    }
+  /* Checking undeclared automata, repeated declarations (except for
+     automata) and correctness of their attributes (insn latency times
+     etc.).  */
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv)
+       {
+          decl->decl.insn_reserv.condexp
+           = check_attr_test (decl->decl.insn_reserv.condexp, 0, 0);
+         if (decl->decl.insn_reserv.default_latency < 0)
+           error ("define_insn_reservation `%s' has negative latency time",
+                  decl->decl.insn_reserv.name);
+         decl->decl.insn_reserv.insn_num = description->insns_num;
+         description->insns_num++;
+         decl_in_table = insert_insn_decl (decl);
+         if (decl_in_table != decl)
+           error ("`%s' is already used as insn reservation name",
+                  decl->decl.insn_reserv.name);
+       }
+      else if (decl->mode == dm_bypass)
+       {
+         if (decl->decl.bypass.latency < 0)
+           error ("define_bypass `%s - %s' has negative latency time",
+                  decl->decl.bypass.out_insn_name,
+                  decl->decl.bypass.in_insn_name);
+       }
+      else if (decl->mode == dm_unit || decl->mode == dm_reserv)
+       {
+         if (decl->mode == dm_unit)
+           {
+             decl->decl.unit.automaton_decl = NULL;
+             if (decl->decl.unit.automaton_name != NULL)
+               {
+                 automaton_decl
+                    = find_automaton_decl (decl->decl.unit.automaton_name);
+                 if (automaton_decl == NULL)
+                   error ("automaton `%s' is not declared",
+                          decl->decl.unit.automaton_name);
+                 else
+                   {
+                     automaton_decl->decl.automaton.automaton_is_used = 1;
+                     decl->decl.unit.automaton_decl
+                       = &automaton_decl->decl.automaton;
+                   }
+               }
+             else if (automaton_presence)
+               error ("define_unit `%s' without automaton when one defined",
+                      decl->decl.unit.name);
+             decl->decl.unit.unit_num = description->units_num;
+             description->units_num++;
+             if (strcmp (decl->decl.unit.name, NOTHING_NAME) == 0)
+               {
+                 error ("`%s' is declared as cpu unit", NOTHING_NAME);
+                 continue;
+               }
+             decl_in_table = find_decl (decl->decl.unit.name);
+           }
+         else
+           {
+             if (strcmp (decl->decl.reserv.name, NOTHING_NAME) == 0)
+               {
+                 error ("`%s' is declared as cpu reservation", NOTHING_NAME);
+                 continue;
+               }
+             decl_in_table = find_decl (decl->decl.reserv.name);
+           }
+         if (decl_in_table == NULL)
+           decl_in_table = insert_decl (decl);
+         else
+           {
+             if (decl->mode == dm_unit)
+               error ("repeated declaration of unit `%s'",
+                      decl->decl.unit.name);
+             else
+               error ("repeated declaration of reservation `%s'",
+                      decl->decl.reserv.name);
+           }
+       }
+    }
+  /* Check bypasses and form list of bypasses for each (output)
+     insn.  */
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_bypass)
+       {
+         out_insn_reserv = find_insn_decl (decl->decl.bypass.out_insn_name);
+         in_insn_reserv = find_insn_decl (decl->decl.bypass.in_insn_name);
+         if (out_insn_reserv == NULL)
+           error ("there is no insn reservation `%s'",
+                  decl->decl.bypass.out_insn_name);
+         else if (in_insn_reserv == NULL)
+           error ("there is no insn reservation `%s'",
+                  decl->decl.bypass.in_insn_name);
+         else
+           {
+             decl->decl.bypass.out_insn_reserv
+               = &out_insn_reserv->decl.insn_reserv;
+             decl->decl.bypass.in_insn_reserv
+               = &in_insn_reserv->decl.insn_reserv;
+             bypass
+               = find_bypass (out_insn_reserv->decl.insn_reserv.bypass_list,
+                              decl->decl.bypass.in_insn_reserv);
+             if (bypass != NULL)
+               {
+                 if (decl->decl.bypass.latency == bypass->latency)
+                   {
+                     if (!w_flag)
+                       error
+                         ("the same bypass `%s - %s' is already defined",
+                          decl->decl.bypass.out_insn_name,
+                          decl->decl.bypass.in_insn_name);
+                     else
+                       warning
+                         ("the same bypass `%s - %s' is already defined",
+                          decl->decl.bypass.out_insn_name,
+                          decl->decl.bypass.in_insn_name);
+                   }
+                 else
+                   error ("bypass `%s - %s' is already defined",
+                          decl->decl.bypass.out_insn_name,
+                          decl->decl.bypass.in_insn_name);
+               }
+             else
+               {
+                 decl->decl.bypass.next
+                   = out_insn_reserv->decl.insn_reserv.bypass_list;
+                 out_insn_reserv->decl.insn_reserv.bypass_list
+                   = &decl->decl.bypass;
+               }
+           }
+       }
+    }
+
+  /* Check exclusion set declarations and form exclussion sets.  */
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_excl)
+       {
+         unit_set_el_t unit_set_el_list;
+         unit_set_el_t unit_set_el_list_2;
+         
+         unit_set_el_list
+            = process_excls (decl->decl.excl.names,
+                            decl->decl.excl.first_list_length, decl->pos);
+         unit_set_el_list_2
+           = process_excls (&decl->decl.excl.names
+                            [decl->decl.excl.first_list_length],
+                             decl->decl.excl.names_num
+                             - decl->decl.excl.first_list_length,
+                             decl->pos);
+         add_excls (unit_set_el_list, unit_set_el_list_2, decl->pos);
+         add_excls (unit_set_el_list_2, unit_set_el_list, decl->pos);
+       }
+    }
+
+  /* Check presence set declarations and form presence sets.  */
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_presence)
+       {
+         unit_set_el_t unit_set_el_list;
+         unit_set_el_t unit_set_el_list_2;
+         
+         unit_set_el_list
+            = process_presence_absence
+             (decl->decl.presence.names,
+              decl->decl.presence.first_list_length, decl->pos, 1);
+         unit_set_el_list_2
+           = process_presence_absence
+             (&decl->decl.presence.names
+              [decl->decl.presence.first_list_length],
+              decl->decl.presence.names_num
+              - decl->decl.presence.first_list_length,
+              decl->pos, 1);
+         add_presence_absence (unit_set_el_list, unit_set_el_list_2,
+                               decl->pos, 1);
+       }
+    }
+
+  /* Check absence set declarations and form absence sets.  */
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_absence)
+       {
+         unit_set_el_t unit_set_el_list;
+         unit_set_el_t unit_set_el_list_2;
+         
+         unit_set_el_list
+            = process_presence_absence
+             (decl->decl.presence.names,
+              decl->decl.presence.first_list_length, decl->pos, 0);
+         unit_set_el_list_2
+           = process_presence_absence
+             (&decl->decl.presence.names
+              [decl->decl.presence.first_list_length],
+              decl->decl.presence.names_num
+              - decl->decl.presence.first_list_length,
+              decl->pos, 0);
+         add_presence_absence (unit_set_el_list, unit_set_el_list_2,
+                               decl->pos, 0);
+       }
+    }
+}
+
+/* The following function checks that declared automaton is used.  If
+   the automaton is not used, the function fixes error/warning.  The
+   following function must be called only after `process_decls'.  */
+static void
+check_automaton_usage ()
+{
+  decl_t decl;
+  int i;
+
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_automaton
+         && !decl->decl.automaton.automaton_is_used)
+       {
+         if (!w_flag)
+           error ("automaton `%s' is not used", decl->decl.automaton.name);
+         else
+           warning ("automaton `%s' is not used", decl->decl.automaton.name);
+       }
+    }
+}
+
+/* The following recursive function processes all regexp in order to
+   fix usage of units or reservations and to fix errors of undeclared
+   name.  The function may change unit_regexp onto reserv_regexp.
+   Remember that reserv_regexp does not exist before the function
+   call.  */
+static regexp_t
+process_regexp (regexp)
+     regexp_t regexp;
+{
+  decl_t decl_in_table;
+  regexp_t new_regexp;
+  int i;
+    
+  if (regexp->mode == rm_unit)
+    {
+      decl_in_table = find_decl (regexp->regexp.unit.name);
+      if (decl_in_table == NULL)
+        error ("undeclared unit or reservation `%s'",
+              regexp->regexp.unit.name);
+      else if (decl_in_table->mode == dm_unit)
+       {
+         decl_in_table->decl.unit.unit_is_used = 1;
+         regexp->regexp.unit.unit_decl = &decl_in_table->decl.unit;
+       }
+      else if (decl_in_table->mode == dm_reserv)
+       {
+         decl_in_table->decl.reserv.reserv_is_used = 1;
+         new_regexp = create_node (sizeof (struct regexp));
+         new_regexp->mode = rm_reserv;
+         new_regexp->pos = regexp->pos;
+         new_regexp->regexp.reserv.name = regexp->regexp.unit.name;
+         new_regexp->regexp.reserv.reserv_decl = &decl_in_table->decl.reserv;
+         regexp = new_regexp;
+       }
+      else
+       abort ();
+    }
+  else if (regexp->mode == rm_sequence)
+    for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+      regexp->regexp.sequence.regexps [i]
+       = process_regexp (regexp->regexp.sequence.regexps [i]);
+  else if (regexp->mode == rm_allof)
+    for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+      regexp->regexp.allof.regexps [i]
+        = process_regexp (regexp->regexp.allof.regexps [i]);
+  else if (regexp->mode == rm_oneof)
+    for (i = 0; i < regexp->regexp.oneof.regexps_num; i++)
+      regexp->regexp.oneof.regexps [i]
+       = process_regexp (regexp->regexp.oneof.regexps [i]);
+  else if (regexp->mode == rm_repeat)
+    regexp->regexp.repeat.regexp
+      = process_regexp (regexp->regexp.repeat.regexp);
+  else if (regexp->mode != rm_nothing)
+    abort ();
+  return regexp;
+}
+
+/* The following function processes regexp of define_reservation and
+   define_insn_reservation with the aid of function
+   `process_regexp'.  */
+static void
+process_regexp_decls ()
+{
+  decl_t decl;
+  int i;
+
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_reserv)
+       decl->decl.reserv.regexp = process_regexp (decl->decl.reserv.regexp);
+      else if (decl->mode == dm_insn_reserv)
+       decl->decl.insn_reserv.regexp
+         = process_regexp (decl->decl.insn_reserv.regexp);
+    }
+}
+
+/* The following function checks that declared unit is used.  If the
+   unit is not used, the function fixes errors/warnings.  The
+   following function must be called only after `process_decls',
+   `process_regexp_decls'.  */
+static void
+check_usage ()
+{
+  decl_t decl;
+  int i;
+
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit && !decl->decl.unit.unit_is_used)
+       {
+         if (!w_flag)
+           error ("unit `%s' is not used", decl->decl.unit.name);
+         else
+           warning ("unit `%s' is not used", decl->decl.unit.name);
+       }
+      else if (decl->mode == dm_reserv && !decl->decl.reserv.reserv_is_used)
+       {
+         if (!w_flag)
+           error ("reservation `%s' is not used", decl->decl.reserv.name);
+         else
+           warning ("reservation `%s' is not used", decl->decl.reserv.name);
+       }
+    }
+}
+
+/* The following variable value is number of reservation being
+   processed on loop recognition.  */
+static int curr_loop_pass_num;
+
+/* The following recursive function returns nonzero value if REGEXP
+   contains given decl or reservations in given regexp refers for
+   given decl.  */
+static int
+loop_in_regexp (regexp, start_decl)
+     regexp_t regexp;
+     decl_t start_decl;
+{
+  int i;
+
+  if (regexp == NULL)
+    return 0;
+  if (regexp->mode == rm_unit)
+    return 0;
+  else if (regexp->mode == rm_reserv)
+    {
+      if (start_decl->mode == dm_reserv
+          && regexp->regexp.reserv.reserv_decl == &start_decl->decl.reserv)
+        return 1;
+      else if (regexp->regexp.reserv.reserv_decl->loop_pass_num
+              == curr_loop_pass_num)
+        /* declaration has been processed.  */
+        return 0;
+      else
+        {
+         regexp->regexp.reserv.reserv_decl->loop_pass_num
+            = curr_loop_pass_num;
+          return loop_in_regexp (regexp->regexp.reserv.reserv_decl->regexp,
+                                 start_decl);
+        }
+    }
+  else if (regexp->mode == rm_sequence)
+    {
+      for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+       if (loop_in_regexp (regexp->regexp.sequence.regexps [i], start_decl))
+         return 1;
+      return 0;
+    }
+  else if (regexp->mode == rm_allof)
+    {
+      for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+       if (loop_in_regexp (regexp->regexp.allof.regexps [i], start_decl))
+         return 1;
+      return 0;
+    }
+  else if (regexp->mode == rm_oneof)
+    {
+      for (i = 0; i < regexp->regexp.oneof.regexps_num; i++)
+       if (loop_in_regexp (regexp->regexp.oneof.regexps [i], start_decl))
+         return 1;
+      return 0;
+    }
+  else if (regexp->mode == rm_repeat)
+    return loop_in_regexp (regexp->regexp.repeat.regexp, start_decl);
+  else
+    {
+      if (regexp->mode != rm_nothing)
+       abort ();
+      return 0;
+    }
+}
+
+/* The following function fixes errors "cycle in definition ...".  The
+   function uses function `loop_in_regexp' for that.  */
+static void
+check_loops_in_regexps ()
+{
+  decl_t decl;
+  int i;
+
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_reserv)
+       decl->decl.reserv.loop_pass_num = 0;
+    }
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      curr_loop_pass_num = i;
+      
+      if (decl->mode == dm_reserv)
+         {
+           decl->decl.reserv.loop_pass_num = curr_loop_pass_num;
+           if (loop_in_regexp (decl->decl.reserv.regexp, decl))
+             {
+               if (decl->decl.reserv.regexp == NULL)
+                 abort ();
+               error ("cycle in definition of reservation `%s'",
+                      decl->decl.reserv.name);
+             }
+         }
+    }
+}
+
+/* The function recursively processes IR of reservation and defines
+   max and min cycle for reservation of unit and for result in the
+   reservation.  */
+static int
+process_regexp_cycles (regexp, start_cycle)
+     regexp_t regexp;
+     int start_cycle;
+{
+  int i;
+
+  if (regexp->mode == rm_unit)
+    {
+      if (regexp->regexp.unit.unit_decl->max_occ_cycle_num < start_cycle)
+       regexp->regexp.unit.unit_decl->max_occ_cycle_num = start_cycle;
+      return start_cycle;
+    }
+  else if (regexp->mode == rm_reserv)
+    return process_regexp_cycles (regexp->regexp.reserv.reserv_decl->regexp,
+                                  start_cycle);
+  else if (regexp->mode == rm_repeat)
+    {
+      for (i = 0; i < regexp->regexp.repeat.repeat_num; i++)
+        start_cycle = process_regexp_cycles (regexp->regexp.repeat.regexp,
+                                            start_cycle) + 1;
+      return start_cycle;
+    }
+  else if (regexp->mode == rm_sequence)
+    {
+      for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+       start_cycle
+          = process_regexp_cycles (regexp->regexp.sequence.regexps [i],
+                                  start_cycle) + 1;
+      return start_cycle;
+    }
+  else if (regexp->mode == rm_allof)
+    {
+      int finish_cycle = 0;
+      int cycle;
+
+      for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+       {
+         cycle = process_regexp_cycles (regexp->regexp.allof.regexps [i],
+                                        start_cycle);
+         if (finish_cycle < cycle)
+           finish_cycle = cycle;
+       }
+      return finish_cycle;
+    }
+  else if (regexp->mode == rm_oneof)
+    {
+      int finish_cycle = 0;
+      int cycle;
+
+      for (i = 0; i < regexp->regexp.oneof.regexps_num; i++)
+       {
+         cycle = process_regexp_cycles (regexp->regexp.oneof.regexps [i],
+                                        start_cycle);
+         if (finish_cycle < cycle)
+           finish_cycle = cycle;
+       }
+      return finish_cycle;
+    }
+  else
+    {
+      if (regexp->mode != rm_nothing)
+       abort ();
+      return start_cycle;
+    }
+}
+
+/* The following function is called only for correct program.  The
+   function defines max reservation of insns in cycles.  */
+static void
+evaluate_max_reserv_cycles ()
+{
+  int max_insn_cycles_num;
+  decl_t decl;
+  int i;
+
+  description->max_insn_reserv_cycles = 0;
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv)
+      {
+        max_insn_cycles_num
+          = process_regexp_cycles (decl->decl.insn_reserv.regexp, 0);
+        if (description->max_insn_reserv_cycles < max_insn_cycles_num)
+         description->max_insn_reserv_cycles = max_insn_cycles_num;
+      }
+    }
+}
+
+/* The following function calls functions for checking all
+   description.  */
+static void
+check_all_description ()
+{
+  process_decls ();
+  check_automaton_usage ();
+  process_regexp_decls ();
+  check_usage ();
+  check_loops_in_regexps ();
+  if (!have_error)
+    evaluate_max_reserv_cycles ();
+}
+
+\f
+
+/* The page contains abstract data `ticker'.  This data is used to
+   report time of different phases of building automata.  It is
+   possibly to write a description for which automata will be built
+   during several minutes even on fast machine.  */
+
+/* The following function creates ticker and makes it active.  */
+static ticker_t
+create_ticker ()
+{
+  ticker_t ticker;
+
+  ticker.modified_creation_time = get_run_time ();
+  ticker.incremented_off_time = 0;
+  return ticker;
+}
+
+/* The following function switches off given ticker.  */
+static void
+ticker_off (ticker)
+     ticker_t *ticker;
+{
+  if (ticker->incremented_off_time == 0)
+    ticker->incremented_off_time = get_run_time () + 1;
+}
+
+/* The following function switches on given ticker.  */
+static void
+ticker_on (ticker)
+     ticker_t *ticker;
+{
+  if (ticker->incremented_off_time != 0)
+    {
+      ticker->modified_creation_time
+        += get_run_time () - ticker->incremented_off_time + 1;
+      ticker->incremented_off_time = 0;
+    }
+}
+
+/* The following function returns current time in milliseconds since
+   the moment when given ticker was created.  */
+static int
+active_time (ticker)
+     ticker_t ticker;
+{
+  if (ticker.incremented_off_time != 0)
+    return ticker.incremented_off_time - 1 - ticker.modified_creation_time;
+  else
+    return get_run_time () - ticker.modified_creation_time;
+}
+
+/* The following function returns string representation of active time
+   of given ticker.  The result is string representation of seconds
+   with accuracy of 1/100 second.  Only result of the last call of the
+   function exists.  Therefore the following code is not correct
+
+      printf ("parser time: %s\ngeneration time: %s\n",
+              active_time_string (parser_ticker),
+              active_time_string (generation_ticker));
+
+   Correct code has to be the following
+
+      printf ("parser time: %s\n", active_time_string (parser_ticker));
+      printf ("generation time: %s\n",
+              active_time_string (generation_ticker));
+
+*/
+static void
+print_active_time (f, ticker)
+     FILE *f;
+     ticker_t ticker;
+{
+  int msecs;
+
+  msecs = active_time (ticker);
+  fprintf (f, "%d.%06d", msecs / 1000000, msecs % 1000000);
+}
+
+\f
+
+/* The following variable value is number of automaton which are
+   really being created.  This value is defined on the base of
+   argument of option `-split'.  If the variable has zero value the
+   number of automata is defined by the constructions `%automaton'.
+   This case occures when option `-split' is absent or has zero
+   argument.  If constructions `define_automaton' is absent only one
+   automaton is created.  */
+static int automata_num;
+
+/* The following variable values are times of
+       o transformation of regular expressions
+       o building NDFA (DFA if !ndfa_flag)
+       o NDFA -> DFA   (simply the same automaton if !ndfa_flag)
+       o DFA minimization
+       o building insn equivalence classes
+       o all previous ones
+       o code output */
+static ticker_t transform_time;
+static ticker_t NDFA_time;
+static ticker_t NDFA_to_DFA_time;
+static ticker_t minimize_time;
+static ticker_t equiv_time;
+static ticker_t automaton_generation_time;
+static ticker_t output_time;
+
+/* The following variable values are times of
+       all checking
+       all generation
+       all pipeline hazard translator work */
+static ticker_t check_time;
+static ticker_t generation_time;
+static ticker_t all_time;
+
+\f
+
+/* Pseudo insn decl which denotes advancing cycle.  */
+static decl_t advance_cycle_insn_decl;
+static void
+add_advance_cycle_insn_decl ()
+{
+  advance_cycle_insn_decl = create_node (sizeof (struct decl));
+  advance_cycle_insn_decl->mode = dm_insn_reserv;
+  advance_cycle_insn_decl->pos = no_pos;
+  advance_cycle_insn_decl->decl.insn_reserv.regexp = NULL;
+  advance_cycle_insn_decl->decl.insn_reserv.name = (char *) "$advance_cycle";
+  advance_cycle_insn_decl->decl.insn_reserv.insn_num = description->insns_num;
+  description->decls [description->decls_num] = advance_cycle_insn_decl;
+  description->decls_num++;
+  description->insns_num++;
+  num_dfa_decls++;
+}
+
+\f
+/* Abstract data `alternative states' which reperesents
+   nondeterministic nature of the description (see comments for
+   structures alt_state and state).  */
+
+/* List of free states.  */
+static alt_state_t first_free_alt_state;
+
+#ifndef NDEBUG
+/* The following variables is maximal number of allocated nodes
+   alt_state.  */
+static int allocated_alt_states_num = 0;
+#endif
+
+/* The following function returns free node alt_state.  It may be new
+   allocated node or node freed eralier.  */
+static alt_state_t 
+get_free_alt_state ()
+{
+  alt_state_t result;
+
+  if (first_free_alt_state != NULL)
+    {
+      result = first_free_alt_state;
+      first_free_alt_state = first_free_alt_state->next_alt_state;
+    }
+  else
+    {
+#ifndef NDEBUG
+      allocated_alt_states_num++;
+#endif
+      result = create_node (sizeof (struct alt_state));
+    }
+  result->state = NULL;
+  result->next_alt_state = NULL;
+  result->next_sorted_alt_state = NULL;
+  return result;
+}
+
+/* The function frees node ALT_STATE.  */
+static void
+free_alt_state (alt_state)
+     alt_state_t alt_state;
+{
+  if (alt_state == NULL)
+    return;
+  alt_state->next_alt_state = first_free_alt_state;
+  first_free_alt_state = alt_state;
+}
+
+/* The function frees list started with node ALT_STATE_LIST.  */
+static void
+free_alt_states (alt_states_list)
+     alt_state_t alt_states_list;
+{
+  alt_state_t curr_alt_state;
+  alt_state_t next_alt_state;
+
+  for (curr_alt_state = alt_states_list;
+       curr_alt_state != NULL;
+       curr_alt_state = next_alt_state)
+    {
+      next_alt_state = curr_alt_state->next_alt_state;
+      free_alt_state (curr_alt_state);
+    }
+}
+
+/* The function compares unique numbers of alt states.  */
+static int
+alt_state_cmp (alt_state_ptr_1, alt_state_ptr_2)
+     const void *alt_state_ptr_1;
+     const void *alt_state_ptr_2;
+{
+  if ((*(alt_state_t *) alt_state_ptr_1)->state->unique_num
+      == (*(alt_state_t *) alt_state_ptr_2)->state->unique_num)
+    return 0;
+  else if ((*(alt_state_t *) alt_state_ptr_1)->state->unique_num
+          < (*(alt_state_t *) alt_state_ptr_2)->state->unique_num)
+    return -1;
+  else
+    return 1;
+}
+
+/* The function sorts ALT_STATES_LIST and removes duplicated alt
+   states from the list.  The comparison key is alt state unique
+   number.  */
+static alt_state_t 
+uniq_sort_alt_states (alt_states_list)
+     alt_state_t alt_states_list;
+{
+  alt_state_t curr_alt_state;
+  vla_ptr_t alt_states;
+  size_t i;
+  size_t prev_unique_state_ind;
+  alt_state_t result;
+  alt_state_t *result_ptr;
+
+  VLA_PTR_CREATE (alt_states, 150, "alt_states");
+  for (curr_alt_state = alt_states_list;
+       curr_alt_state != NULL;
+       curr_alt_state = curr_alt_state->next_alt_state)
+    VLA_PTR_ADD (alt_states, curr_alt_state);
+  qsort (VLA_PTR_BEGIN (alt_states), VLA_PTR_LENGTH (alt_states),
+        sizeof (alt_state_t), alt_state_cmp);
+  if (VLA_PTR_LENGTH (alt_states) == 0)
+    result = NULL;
+  else
+    {
+      result_ptr = VLA_PTR_BEGIN (alt_states);
+      prev_unique_state_ind = 0;
+      for (i = 1; i < VLA_PTR_LENGTH (alt_states); i++)
+        if (result_ptr [prev_unique_state_ind]->state != result_ptr [i]->state)
+          {
+            prev_unique_state_ind++;
+            result_ptr [prev_unique_state_ind] = result_ptr [i];
+          }
+#if 0
+      for (i = prev_unique_state_ind + 1; i < VLA_PTR_LENGTH (alt_states); i++)
+        free_alt_state (result_ptr [i]);
+#endif
+      VLA_PTR_SHORTEN (alt_states, i - prev_unique_state_ind - 1);
+      result_ptr = VLA_PTR_BEGIN (alt_states);
+      for (i = 1; i < VLA_PTR_LENGTH (alt_states); i++)
+        result_ptr [i - 1]->next_sorted_alt_state = result_ptr [i];
+      result_ptr [i - 1]->next_sorted_alt_state = NULL;
+      result = *result_ptr;
+    }
+  VLA_PTR_DELETE (alt_states);
+  return result;
+}
+
+/* The function checks equality of alt state lists.  Remember that the
+   lists must be already sorted by the previous function.  */
+static int
+alt_states_eq (alt_states_1, alt_states_2)
+     alt_state_t alt_states_1;
+     alt_state_t alt_states_2;
+{
+  while (alt_states_1 != NULL && alt_states_2 != NULL
+         && alt_state_cmp (&alt_states_1, &alt_states_2) == 0)
+    {
+      alt_states_1 = alt_states_1->next_sorted_alt_state;
+      alt_states_2 = alt_states_2->next_sorted_alt_state;
+    }
+  return alt_states_1 == alt_states_2;
+}
+
+/* Initialization of the abstract data.  */
+static void
+initiate_alt_states ()
+{
+  first_free_alt_state = NULL;
+}
+
+/* Finishing work with the abstract data.  */
+static void
+finish_alt_states ()
+{
+}
+
+\f
+
+/* The page contains macros for work with bits strings.  We could use
+   standard gcc bitmap or sbitmap but it would result in difficulties
+   of building canadian cross.  */
+
+/* Set bit number bitno in the bit string.  The macro is not side
+   effect proof.  */
+#define SET_BIT(bitstring, bitno)                                        \
+  (((char *) (bitstring)) [(bitno) / CHAR_BIT] |= 1 << (bitno) % CHAR_BIT)
+
+/* Test if bit number bitno in the bitstring is set.  The macro is not
+   side effect proof.  */
+#define TEST_BIT(bitstring, bitno)                                        \
+  (((char *) (bitstring)) [(bitno) / CHAR_BIT] >> (bitno) % CHAR_BIT & 1)
+
+\f
+
+/* This page contains abstract data `state'.  */
+
+/* Maximal length of reservations in cycles (> 1).  */
+static int max_cycles_num;
+
+/* Number of set elements (see type set_el_t) needed for
+   representation of one cycle reservation.  It is depended on units
+   number.  */
+static int els_in_cycle_reserv;
+
+/* Number of set elements (see type set_el_t) needed for
+   representation of maximal length reservation.  Deterministic
+   reservation is stored as set (bit string) of length equal to the
+   variable value * number of bits in set_el_t.  */
+static int els_in_reservs;
+
+/* VLA for representation of array of pointers to unit
+   declarations.  */
+static vla_ptr_t units_container;
+
+/* The start address of the array.  */
+static struct unit_decl **units_array;
+
+/* Empty reservation of maximal length.  */
+static reserv_sets_t empty_reserv;
+
+/* The state table itself is represented by the following variable.  */
+static htab_t state_table;
+
+/* VLA for representation of array of pointers to free nodes
+   `state'.  */
+static vla_ptr_t free_states;
+
+static int curr_unique_state_num;
+
+#ifndef NDEBUG
+/* The following variables is maximal number of allocated nodes
+   `state'.  */
+static int allocated_states_num = 0;
+#endif
+
+/* Allocate new reservation set.  */
+static reserv_sets_t
+alloc_empty_reserv_sets ()
+{
+  reserv_sets_t result;
+
+  obstack_blank (&irp, els_in_reservs * sizeof (set_el_t));
+  result = (reserv_sets_t) obstack_base (&irp);
+  obstack_finish (&irp);
+  memset (result, 0, els_in_reservs * sizeof (set_el_t));
+  return result;
+}
+
+/* Hash value of reservation set.  */
+static unsigned
+reserv_sets_hash_value (reservs)
+     reserv_sets_t reservs;
+{
+  unsigned int hash_value;
+  int reservs_num;
+  set_el_t *reserv_ptr;
+
+  hash_value = 0;
+  reservs_num = els_in_reservs;
+  reserv_ptr = reservs;
+  while (reservs_num != 0)
+    {
+      reservs_num--;
+      hash_value = ((hash_value >> (sizeof (unsigned) - 1) * CHAR_BIT)
+                    | (hash_value << CHAR_BIT)) + *reserv_ptr;
+      reserv_ptr++;
+    }
+  return hash_value;
+}
+
+/* Comparison of given reservation sets.  */
+static int
+reserv_sets_cmp (reservs_1, reservs_2)
+     reserv_sets_t reservs_1;
+     reserv_sets_t reservs_2;
+{
+  int reservs_num;
+  set_el_t *reserv_ptr_1;
+  set_el_t *reserv_ptr_2;
+
+  if (reservs_1 == NULL || reservs_2 == NULL)
+    abort ();
+  reservs_num = els_in_reservs;
+  reserv_ptr_1 = reservs_1;
+  reserv_ptr_2 = reservs_2;
+  while (reservs_num != 0 && *reserv_ptr_1 == *reserv_ptr_2)
+    {
+      reservs_num--;
+      reserv_ptr_1++;
+      reserv_ptr_2++;
+    }
+  if (reservs_num == 0)
+    return 0;
+  else if (*reserv_ptr_1 < *reserv_ptr_2)
+    return -1;
+  else
+    return 1;
+}
+
+/* The function checks equality of the reservation sets.  */
+static int
+reserv_sets_eq (reservs_1, reservs_2)
+     reserv_sets_t reservs_1;
+     reserv_sets_t reservs_2;
+{
+  return reserv_sets_cmp (reservs_1, reservs_2) == 0;
+}
+
+/* Set up in the reservation set that unit with UNIT_NUM is used on
+   CYCLE_NUM.  */
+static void
+set_unit_reserv (reservs, cycle_num, unit_num)
+     reserv_sets_t reservs;
+     int cycle_num;
+     int unit_num;
+{
+  if (cycle_num >= max_cycles_num)
+    abort ();
+  SET_BIT (reservs, cycle_num * els_in_cycle_reserv
+           * sizeof (set_el_t) * CHAR_BIT + unit_num);
+}
+
+/* Set up in the reservation set RESERVS that unit with UNIT_NUM is
+   used on CYCLE_NUM.  */
+static int
+test_unit_reserv (reservs, cycle_num, unit_num)
+     reserv_sets_t reservs;
+     int cycle_num;
+     int unit_num;
+{
+  if (cycle_num >= max_cycles_num)
+    abort ();
+  return TEST_BIT (reservs, cycle_num * els_in_cycle_reserv
+                  * sizeof (set_el_t) * CHAR_BIT + unit_num);
+}
+
+/* The function checks that the reservation set represents no one unit
+   reservation.  */
+static int
+it_is_empty_reserv_sets (operand)
+     reserv_sets_t operand;
+{
+  set_el_t *reserv_ptr;
+  int reservs_num;
+
+  if (operand == NULL)
+    abort ();
+  for (reservs_num = els_in_reservs, reserv_ptr = operand;
+       reservs_num != 0;
+       reserv_ptr++, reservs_num--)
+    if (*reserv_ptr != 0)
+      return 0;
+  return 1;
+}
+
+/* The function checks that the reservation sets are intersected,
+   i.e. there is a unit reservation on a cycle in both reservation
+   sets.  */
+static int
+reserv_sets_are_intersected (operand_1, operand_2)
+     reserv_sets_t operand_1;
+     reserv_sets_t operand_2;
+{
+  set_el_t *el_ptr_1;
+  set_el_t *el_ptr_2;
+  set_el_t *cycle_ptr_1;
+  set_el_t *cycle_ptr_2;
+  int nonzero_p;
+
+  if (operand_1 == NULL || operand_2 == NULL)
+    abort ();
+  for (el_ptr_1 = operand_1, el_ptr_2 = operand_2;
+       el_ptr_1 < operand_1 + els_in_reservs;
+       el_ptr_1++, el_ptr_2++)
+    if (*el_ptr_1 & *el_ptr_2)
+      return 1;
+  for (cycle_ptr_1 = operand_1, cycle_ptr_2 = operand_2;
+       cycle_ptr_1 < operand_1 + els_in_reservs;
+       cycle_ptr_1 += els_in_cycle_reserv, cycle_ptr_2 += els_in_cycle_reserv)
+    {
+      for (el_ptr_1 = cycle_ptr_1, el_ptr_2 = get_excl_set (cycle_ptr_2);
+          el_ptr_1 < cycle_ptr_1 + els_in_cycle_reserv;
+          el_ptr_1++, el_ptr_2++)
+       if (*el_ptr_1 & *el_ptr_2)
+         return 1;
+      nonzero_p = 0;
+      for (el_ptr_1 = cycle_ptr_1,
+            el_ptr_2 = get_presence_absence_set (cycle_ptr_2, 1);
+          el_ptr_1 < cycle_ptr_1 + els_in_cycle_reserv;
+          el_ptr_1++, el_ptr_2++)
+       if (*el_ptr_1 & *el_ptr_2)
+         break;
+       else if (*el_ptr_2 != 0)
+         nonzero_p = 1;
+      if (nonzero_p && el_ptr_1 >= cycle_ptr_1 + els_in_cycle_reserv)
+       return 1;
+      for (el_ptr_1 = cycle_ptr_1,
+            el_ptr_2 = get_presence_absence_set (cycle_ptr_2, 0);
+          el_ptr_1 < cycle_ptr_1 + els_in_cycle_reserv;
+          el_ptr_1++, el_ptr_2++)
+       /* It looks like code for exclusion but exclusion set is
+           made as symmetric relation preliminary.  */
+       if (*el_ptr_1 & *el_ptr_2)
+         return 1;
+    }
+  return 0;
+}
+
+/* The function sets up RESULT bits by bits of OPERAND shifted on one
+   cpu cycle.  The remaining bits of OPERAND (representing the last
+   cycle unit reservations) are not chenged.  */
+static void
+reserv_sets_shift (result, operand)
+     reserv_sets_t result;
+     reserv_sets_t operand;
+{
+  int i;
+
+  if (result == NULL || operand == NULL || result == operand)
+    abort ();
+  for (i = els_in_cycle_reserv; i < els_in_reservs; i++)
+    result [i - els_in_cycle_reserv] = operand [i];
+}
+
+/* OR of the reservation sets.  */
+static void
+reserv_sets_or (result, operand_1, operand_2)
+     reserv_sets_t result;
+     reserv_sets_t operand_1;
+     reserv_sets_t operand_2;
+{
+  set_el_t *el_ptr_1;
+  set_el_t *el_ptr_2;
+  set_el_t *result_set_el_ptr;
+
+  if (result == NULL || operand_1 == NULL || operand_2 == NULL)
+    abort ();
+  for (el_ptr_1 = operand_1, el_ptr_2 = operand_2, result_set_el_ptr = result;
+       el_ptr_1 < operand_1 + els_in_reservs;
+       el_ptr_1++, el_ptr_2++, result_set_el_ptr++)
+    *result_set_el_ptr = *el_ptr_1 | *el_ptr_2;
+}
+
+/* AND of the reservation sets.  */
+static void
+reserv_sets_and (result, operand_1, operand_2)
+     reserv_sets_t result;
+     reserv_sets_t operand_1;
+     reserv_sets_t operand_2;
+{
+  set_el_t *el_ptr_1;
+  set_el_t *el_ptr_2;
+  set_el_t *result_set_el_ptr;
+
+  if (result == NULL || operand_1 == NULL || operand_2 == NULL)
+    abort ();
+  for (el_ptr_1 = operand_1, el_ptr_2 = operand_2, result_set_el_ptr = result;
+       el_ptr_1 < operand_1 + els_in_reservs;
+       el_ptr_1++, el_ptr_2++, result_set_el_ptr++)
+    *result_set_el_ptr = *el_ptr_1 & *el_ptr_2;
+}
+
+/* The function outputs string representation of units reservation on
+   cycle START_CYCLE in the reservation set.  The function uses repeat
+   construction if REPETITION_NUM > 1.  */
+static void
+output_cycle_reservs (f, reservs, start_cycle, repetition_num)
+     FILE *f;
+     reserv_sets_t reservs;
+     int start_cycle;
+     int repetition_num;
+{
+  int unit_num;
+  int reserved_units_num;
+
+  reserved_units_num = 0;
+  for (unit_num = 0; unit_num < description->units_num; unit_num++)
+    if (TEST_BIT (reservs, start_cycle * els_in_cycle_reserv
+                  * sizeof (set_el_t) * CHAR_BIT + unit_num))
+      reserved_units_num++;
+  if (repetition_num <= 0)
+    abort ();
+  if (repetition_num != 1 && reserved_units_num > 1)
+    fprintf (f, "(");
+  reserved_units_num = 0;
+  for (unit_num = 0;
+       unit_num < description->units_num;
+       unit_num++)
+    if (TEST_BIT (reservs, start_cycle * els_in_cycle_reserv
+                 * sizeof (set_el_t) * CHAR_BIT + unit_num))
+      {
+        if (reserved_units_num != 0)
+          fprintf (f, "+");
+        reserved_units_num++;
+        fprintf (f, "%s", units_array [unit_num]->name);
+      }
+  if (reserved_units_num == 0)
+    fprintf (f, NOTHING_NAME);
+  if (repetition_num <= 0)
+    abort ();
+  if (reserved_units_num != 0 && repetition_num != 1)
+    {
+      if (reserved_units_num > 1)
+        fprintf (f, ")");
+      fprintf (f, "*%d", repetition_num);
+    }
+}
+
+/* The function outputs string representation of units reservation in
+   the reservation set.  */
+static void
+output_reserv_sets (f, reservs)
+     FILE *f;
+     reserv_sets_t reservs;
+{
+  int start_cycle = 0;
+  int cycle;
+  int repetition_num;
+  int next_cycle_output_flag;
+
+  repetition_num = 0;
+  next_cycle_output_flag = 0;
+  for (cycle = 0; cycle < max_cycles_num; cycle++)
+    if (repetition_num == 0)
+      {
+        repetition_num++;
+        start_cycle = cycle;
+      }
+    else if (memcmp
+             ((char *) reservs + start_cycle * els_in_cycle_reserv
+             * sizeof (set_el_t),
+              (char *) reservs + cycle * els_in_cycle_reserv
+             * sizeof (set_el_t),
+             els_in_cycle_reserv * sizeof (set_el_t)) == 0)
+      repetition_num++;
+    else
+      {
+        if (next_cycle_output_flag)
+          fprintf (f, ", ");
+        output_cycle_reservs (f, reservs, start_cycle, repetition_num);
+        next_cycle_output_flag = 1;
+        repetition_num = 1;
+        start_cycle = cycle;
+      }
+  if (!next_cycle_output_flag)
+    {
+      if (next_cycle_output_flag)
+        fprintf (f, ", ");
+      output_cycle_reservs (f, reservs, start_cycle, repetition_num);
+    }
+}
+
+/* The following function returns free node state for AUTOMATON.  It
+   may be new allocated node or node freed eralier.  The function also
+   allocates reservation set if WITH_RESERVS has nonzero value.  */
+static state_t
+get_free_state (with_reservs, automaton)
+     int with_reservs;
+     automaton_t automaton;
+{
+  state_t result;
+
+  if (max_cycles_num <= 0 || automaton == NULL)
+    abort ();
+  if (VLA_PTR_LENGTH (free_states) != 0)
+    {
+      result = VLA_PTR (free_states, VLA_PTR_LENGTH (free_states) - 1);
+      VLA_PTR_SHORTEN (free_states, 1);
+      result->automaton = automaton;
+      result->first_out_arc = NULL;
+      result->it_was_placed_in_stack_for_NDFA_forming = 0;
+      result->it_was_placed_in_stack_for_DFA_forming = 0;
+      result->component_states = NULL;
+      result->longest_path_length = UNDEFINED_LONGEST_PATH_LENGTH;
+    }
+  else
+    {
+#ifndef NDEBUG
+      allocated_states_num++;
+#endif
+      result = create_node (sizeof (struct state));
+      result->automaton = automaton;
+      result->first_out_arc = NULL;
+      result->unique_num = curr_unique_state_num;
+      result->longest_path_length = UNDEFINED_LONGEST_PATH_LENGTH;
+      curr_unique_state_num++;
+    }
+  if (with_reservs)
+    {
+      if (result->reservs == NULL)
+        result->reservs = alloc_empty_reserv_sets ();
+      else
+        memset (result->reservs, 0, els_in_reservs * sizeof (set_el_t));
+    }
+  return result;
+}
+
+/* The function frees node STATE.  */
+static void
+free_state (state)
+     state_t state;
+{
+  free_alt_states (state->component_states);
+  VLA_PTR_ADD (free_states, state);
+}
+
+/* Hash value of STATE.  If STATE represents deterministic state it is
+   simply hash value of the corresponding reservation set.  Otherwise
+   it is formed from hash values of the component deterministic
+   states.  One more key is order number of state automaton.  */
+static unsigned
+state_hash (state)
+     const void *state;
+{
+  unsigned int hash_value;
+  alt_state_t alt_state;
+
+  if (((state_t) state)->component_states == NULL)
+    hash_value = reserv_sets_hash_value (((state_t) state)->reservs);
+  else
+    {
+      hash_value = 0;
+      for (alt_state = ((state_t) state)->component_states;
+           alt_state != NULL;
+           alt_state = alt_state->next_sorted_alt_state)
+        hash_value = (((hash_value >> (sizeof (unsigned) - 1) * CHAR_BIT)
+                       | (hash_value << CHAR_BIT))
+                      + alt_state->state->unique_num);
+    }
+  hash_value = (((hash_value >> (sizeof (unsigned) - 1) * CHAR_BIT)
+                 | (hash_value << CHAR_BIT))
+                + ((state_t) state)->automaton->automaton_order_num);
+  return hash_value;
+}
+
+/* Return nonzero value if the states are the same.  */
+static int
+state_eq_p (state_1, state_2)
+     const void *state_1;
+     const void *state_2;
+{
+  alt_state_t alt_state_1;
+  alt_state_t alt_state_2;
+
+  if (((state_t) state_1)->automaton != ((state_t) state_2)->automaton)
+    return 0;
+  else if (((state_t) state_1)->component_states == NULL
+           && ((state_t) state_2)->component_states == NULL)
+    return reserv_sets_eq (((state_t) state_1)->reservs,
+                          ((state_t) state_2)->reservs);
+  else if (((state_t) state_1)->component_states != NULL
+           && ((state_t) state_2)->component_states != NULL)
+    {
+      for (alt_state_1 = ((state_t) state_1)->component_states,
+           alt_state_2 = ((state_t) state_2)->component_states;
+           alt_state_1 != NULL && alt_state_2 != NULL;
+           alt_state_1 = alt_state_1->next_sorted_alt_state,
+          alt_state_2 = alt_state_2->next_sorted_alt_state)
+        /* All state in the list must be already in the hash table.
+           Also the lists must be sorted.  */
+        if (alt_state_1->state != alt_state_2->state)
+          return 0;
+      return alt_state_1 == alt_state_2;
+    }
+  else
+    return 0;
+}
+
+/* Insert STATE into the state table.  */
+static state_t
+insert_state (state)
+     state_t state;
+{
+  void **entry_ptr;
+
+  entry_ptr = htab_find_slot (state_table, (void *) state, 1);
+  if (*entry_ptr == NULL)
+    *entry_ptr = (void *) state;
+  return (state_t) *entry_ptr;
+}
+
+/* Add reservation of unit with UNIT_NUM on cycle CYCLE_NUM to
+   deterministic STATE.  */
+static void
+set_state_reserv (state, cycle_num, unit_num)
+     state_t state;
+     int cycle_num;
+     int unit_num;
+{
+  set_unit_reserv (state->reservs, cycle_num, unit_num);
+}
+
+/* Return nonzero value if the deterministic states contains a
+   reservation of the same cpu unit on the same cpu cycle.  */
+static int
+intersected_state_reservs_p (state1, state2)
+     state_t state1;
+     state_t state2;
+{
+  if (state1->automaton != state2->automaton)
+    abort ();
+  return reserv_sets_are_intersected (state1->reservs, state2->reservs);
+}
+
+/* Return deterministic state (inserted into the table) which
+   representing the automaton state whic is union of reservations of
+   deterministic states.  */
+static state_t
+states_union (state1, state2)
+     state_t state1;
+     state_t state2;
+{
+  state_t result;
+  state_t state_in_table;
+
+  if (state1->automaton != state2->automaton)
+    abort ();
+  result = get_free_state (1, state1->automaton);
+  reserv_sets_or (result->reservs, state1->reservs, state2->reservs);
+  state_in_table = insert_state (result);
+  if (result != state_in_table)
+    {
+      free_state (result);
+      result = state_in_table;
+    }
+  return result;
+}
+
+/* Return deterministic state (inserted into the table) which
+   represent the automaton state is obtained from deterministic STATE
+   by advancing cpu cycle.  */
+static state_t
+state_shift (state)
+     state_t state;
+{
+  state_t result;
+  state_t state_in_table;
+
+  result = get_free_state (1, state->automaton);
+  reserv_sets_shift (result->reservs, state->reservs);
+  state_in_table = insert_state (result);
+  if (result != state_in_table)
+    {
+      free_state (result);
+      result = state_in_table;
+    }
+  return result;
+}
+
+/* Initialization of the abstract data.  */
+static void
+initiate_states ()
+{
+  decl_t decl;
+  int i;
+
+  VLA_PTR_CREATE (units_container, description->units_num, "units_container");
+  units_array
+    = (description->decls_num ? VLA_PTR_BEGIN (units_container) : NULL);
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit)
+       units_array [decl->decl.unit.unit_num] = &decl->decl.unit;
+    }
+  max_cycles_num = description->max_insn_reserv_cycles;
+  if (max_cycles_num == 0)
+    max_cycles_num++;
+  els_in_cycle_reserv
+    = ((description->units_num + sizeof (set_el_t) * CHAR_BIT - 1)
+       / (sizeof (set_el_t) * CHAR_BIT));
+  els_in_reservs = els_in_cycle_reserv * max_cycles_num;
+  curr_unique_state_num = 0;
+  initiate_alt_states ();
+  VLA_PTR_CREATE (free_states, 1500, "free states");
+  state_table = htab_create (1500, state_hash, state_eq_p, (htab_del) 0);
+  empty_reserv = alloc_empty_reserv_sets ();
+}
+
+/* Finisging work with the abstract data.  */
+static void
+finish_states ()
+{
+  VLA_PTR_DELETE (units_container);
+  htab_delete (state_table);
+  VLA_PTR_DELETE (free_states);
+  finish_alt_states ();
+}
+
+\f
+
+/* Abstract data `arcs'.  */
+
+/* List of free arcs.  */
+static arc_t first_free_arc;
+
+#ifndef NDEBUG
+/* The following variables is maximal number of allocated nodes
+   `arc'.  */
+static int allocated_arcs_num = 0;
+#endif
+
+/* The function frees node ARC.  */
+static void
+free_arc (arc)
+     arc_t arc;
+{
+  arc->next_out_arc = first_free_arc;
+  first_free_arc = arc;
+}
+
+/* The function removes and frees ARC staring from FROM_STATE.  */
+static void
+remove_arc (from_state, arc)
+     state_t from_state;
+     arc_t arc;
+{
+  arc_t prev_arc;
+  arc_t curr_arc;
+
+  if (arc == NULL)
+    abort ();
+  for (prev_arc = NULL, curr_arc = from_state->first_out_arc;
+       curr_arc != NULL;
+       prev_arc = curr_arc, curr_arc = curr_arc->next_out_arc)
+    if (curr_arc == arc)
+      break;
+  if (curr_arc == NULL)
+    abort ();
+  if (prev_arc == NULL)
+    from_state->first_out_arc = arc->next_out_arc;
+  else
+    prev_arc->next_out_arc = arc->next_out_arc;
+  free_arc (arc);
+}
+
+/* The functions returns arc with given characteristics (or NULL if
+   the arc does not exist).  */
+static arc_t
+find_arc (from_state, to_state, insn)
+     state_t from_state;
+     state_t to_state;
+     ainsn_t insn;
+{
+  arc_t arc;
+
+  for (arc = first_out_arc (from_state); arc != NULL; arc = next_out_arc (arc))
+    if (arc->to_state == to_state && arc->insn == insn)
+      return arc;
+  return NULL;
+}
+
+/* The function adds arc from FROM_STATE to TO_STATE marked by AINSN
+   and with given STATE_ALTS.  The function returns added arc (or
+   already existing arc).  */
+static arc_t
+add_arc (from_state, to_state, ainsn, state_alts)
+     state_t from_state;
+     state_t to_state;
+     ainsn_t ainsn;
+     int state_alts;
+{
+  arc_t new_arc;
+
+  new_arc = find_arc (from_state, to_state, ainsn);
+  if (new_arc != NULL)
+    return new_arc;
+  if (first_free_arc == NULL)
+    {
+#ifndef NDEBUG
+      allocated_arcs_num++;
+#endif
+      new_arc = create_node (sizeof (struct arc));
+      new_arc->to_state = NULL;
+      new_arc->insn = NULL;
+      new_arc->next_out_arc = NULL;
+    }
+  else
+    {
+      new_arc = first_free_arc;
+      first_free_arc =  first_free_arc->next_out_arc;
+    }
+  new_arc->to_state = to_state;
+  new_arc->insn = ainsn;
+  ainsn->arc_exists_p = 1;
+  new_arc->next_out_arc = from_state->first_out_arc;
+  from_state->first_out_arc = new_arc;
+  new_arc->next_arc_marked_by_insn = NULL;
+  new_arc->state_alts = state_alts;
+  return new_arc;
+}
+
+/* The function returns the first arc starting from STATE.  */
+static arc_t
+first_out_arc (state)
+     state_t state;
+{
+  return state->first_out_arc;
+}
+
+/* The function returns next out arc after ARC.  */
+static arc_t
+next_out_arc (arc)
+     arc_t arc;
+{
+  return arc->next_out_arc;
+}
+
+/* Initialization of the abstract data.  */
+static void
+initiate_arcs ()
+{
+  first_free_arc = NULL;
+}
+
+/* Finishing work with the abstract data.  */
+static void
+finish_arcs ()
+{
+}
+
+\f
+
+/* The page contains abstract data for work with exclusion sets (see
+   exclusion_set in file rtl.def).  */
+
+/* The following variable refers to an exclusion set returned by
+   get_excl_set.  This is bit string of length equal to cpu units
+   number.  If exclusion set for given unit contains 1 for a unit,
+   then simultaneous reservation of the units is prohibited.  */
+static reserv_sets_t excl_set;
+
+/* The array contains exclusion sets for each unit.  */
+static reserv_sets_t *unit_excl_set_table;
+
+/* The following function forms the array containing exclusion sets
+   for each unit.  */
+static void
+initiate_excl_sets ()
+{
+  decl_t decl;
+  reserv_sets_t unit_excl_set;
+  unit_set_el_t el;
+  int i;
+
+  obstack_blank (&irp, els_in_cycle_reserv * sizeof (set_el_t));
+  excl_set = (reserv_sets_t) obstack_base (&irp);
+  obstack_finish (&irp);
+  obstack_blank (&irp, description->units_num * sizeof (reserv_sets_t));
+  unit_excl_set_table = (reserv_sets_t *) obstack_base (&irp);
+  obstack_finish (&irp);
+  /* Evaluate unit exclusion sets.  */
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit)
+       {
+         obstack_blank (&irp, els_in_cycle_reserv * sizeof (set_el_t));
+         unit_excl_set = (reserv_sets_t) obstack_base (&irp);
+         obstack_finish (&irp);
+         memset (unit_excl_set, 0, els_in_cycle_reserv * sizeof (set_el_t));
+         for (el = decl->decl.unit.excl_list;
+              el != NULL;
+              el = el->next_unit_set_el)
+            SET_BIT (unit_excl_set, el->unit_decl->unit_num);
+          unit_excl_set_table [decl->decl.unit.unit_num] = unit_excl_set;
+        }
+    }
+}
+
+/* The function sets up and return EXCL_SET which is union of
+   exclusion sets for each unit in IN_SET.  */
+static reserv_sets_t
+get_excl_set (in_set)
+     reserv_sets_t in_set;
+{
+  int excl_char_num;
+  int chars_num;
+  int i;
+  int start_unit_num;
+  int unit_num;
+
+  chars_num = els_in_cycle_reserv * sizeof (set_el_t);
+  memset (excl_set, 0, chars_num);
+  for (excl_char_num = 0; excl_char_num < chars_num; excl_char_num++)
+    if (((unsigned char *) in_set) [excl_char_num])
+      for (i = CHAR_BIT - 1; i >= 0; i--)
+       if ((((unsigned char *) in_set) [excl_char_num] >> i) & 1)
+         {
+           start_unit_num = excl_char_num * CHAR_BIT + i;
+           if (start_unit_num >= description->units_num)
+             return excl_set;
+           for (unit_num = 0; unit_num < els_in_cycle_reserv; unit_num++)
+             {
+               excl_set [unit_num]
+                 |= unit_excl_set_table [start_unit_num] [unit_num];
+             }
+         }
+  return excl_set;
+}
+
+\f
+
+/* The page contains abstract data for work with presence/absence sets
+   (see presence_set/absence_set in file rtl.def).  */
+
+/* The following variables refer to correspondingly an presence and an
+   absence set returned by get_presence_absence_set.  This is bit
+   string of length equal to cpu units number.  */
+static reserv_sets_t presence_set, absence_set;
+
+/* The following arrays contain correspondingly presence and absence
+   sets for each unit.  */
+static reserv_sets_t *unit_presence_set_table, *unit_absence_set_table;
+
+/* The following function forms the array containing presence and
+   absence sets for each unit */
+static void
+initiate_presence_absence_sets ()
+{
+  decl_t decl;
+  reserv_sets_t unit_set;
+  unit_set_el_t el;
+  int i;
+
+  obstack_blank (&irp, els_in_cycle_reserv * sizeof (set_el_t));
+  presence_set = (reserv_sets_t) obstack_base (&irp);
+  obstack_finish (&irp);
+  obstack_blank (&irp, description->units_num * sizeof (reserv_sets_t));
+  unit_presence_set_table = (reserv_sets_t *) obstack_base (&irp);
+  obstack_finish (&irp);
+  obstack_blank (&irp, els_in_cycle_reserv * sizeof (set_el_t));
+  absence_set = (reserv_sets_t) obstack_base (&irp);
+  obstack_finish (&irp);
+  obstack_blank (&irp, description->units_num * sizeof (reserv_sets_t));
+  unit_absence_set_table = (reserv_sets_t *) obstack_base (&irp);
+  obstack_finish (&irp);
+  /* Evaluate unit presence/absence sets.  */
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit)
+       {
+         obstack_blank (&irp, els_in_cycle_reserv * sizeof (set_el_t));
+         unit_set = (reserv_sets_t) obstack_base (&irp);
+         obstack_finish (&irp);
+         memset (unit_set, 0, els_in_cycle_reserv * sizeof (set_el_t));
+         for (el = decl->decl.unit.presence_list;
+              el != NULL;
+              el = el->next_unit_set_el)
+            SET_BIT (unit_set, el->unit_decl->unit_num);
+          unit_presence_set_table [decl->decl.unit.unit_num] = unit_set;
+
+         obstack_blank (&irp, els_in_cycle_reserv * sizeof (set_el_t));
+         unit_set = (reserv_sets_t) obstack_base (&irp);
+         obstack_finish (&irp);
+         memset (unit_set, 0, els_in_cycle_reserv * sizeof (set_el_t));
+         for (el = decl->decl.unit.absence_list;
+              el != NULL;
+              el = el->next_unit_set_el)
+            SET_BIT (unit_set, el->unit_decl->unit_num);
+          unit_absence_set_table [decl->decl.unit.unit_num] = unit_set;
+        }
+    }
+}
+
+/* The function sets up and return PRESENCE_SET (if PRESENCE_P) or
+   ABSENCE_SET which is union of corresponding sets for each unit in
+   IN_SET.  */
+static reserv_sets_t
+get_presence_absence_set (in_set, presence_p)
+     reserv_sets_t in_set;
+     int presence_p;
+{
+  int char_num;
+  int chars_num;
+  int i;
+  int start_unit_num;
+  int unit_num;
+
+  chars_num = els_in_cycle_reserv * sizeof (set_el_t);
+  if (presence_p)
+    memset (presence_set, 0, chars_num);
+  else
+    memset (absence_set, 0, chars_num);
+  for (char_num = 0; char_num < chars_num; char_num++)
+    if (((unsigned char *) in_set) [char_num])
+      for (i = CHAR_BIT - 1; i >= 0; i--)
+       if ((((unsigned char *) in_set) [char_num] >> i) & 1)
+         {
+           start_unit_num = char_num * CHAR_BIT + i;
+           if (start_unit_num >= description->units_num)
+             return (presence_p ? presence_set : absence_set);
+           for (unit_num = 0; unit_num < els_in_cycle_reserv; unit_num++)
+             if (presence_p)
+               presence_set [unit_num]
+                 |= unit_presence_set_table [start_unit_num] [unit_num];
+             else
+               absence_set [unit_num]
+                 |= unit_absence_set_table [start_unit_num] [unit_num];
+         }
+  return (presence_p ? presence_set : absence_set);
+}
+
+\f
+
+/* This page contains code for transformation of original reservations
+   described in .md file.  The main goal of transformations is
+   simplifying reservation and lifting up all `|' on the top of IR
+   reservation representation.  */
+
+
+/* The following function makes copy of IR representation of
+   reservation.  The function also substitutes all reservations
+   defined by define_reservation by corresponding value during making
+   the copy.  */
+static regexp_t
+copy_insn_regexp (regexp)
+     regexp_t regexp;
+{
+  regexp_t  result;
+  int i;
+
+  if (regexp->mode == rm_reserv)
+    result = copy_insn_regexp (regexp->regexp.reserv.reserv_decl->regexp);
+  else if (regexp->mode == rm_unit)
+    result = copy_node (regexp, sizeof (struct regexp));
+  else if (regexp->mode == rm_repeat)
+    {
+      result = copy_node (regexp, sizeof (struct regexp));
+      result->regexp.repeat.regexp
+        = copy_insn_regexp (regexp->regexp.repeat.regexp);
+    }
+  else if (regexp->mode == rm_sequence)
+    {
+      result = copy_node (regexp,
+                          sizeof (struct regexp) + sizeof (regexp_t)
+                         * (regexp->regexp.sequence.regexps_num - 1));
+      for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+       result->regexp.sequence.regexps [i]
+         = copy_insn_regexp (regexp->regexp.sequence.regexps [i]);
+    }
+  else if (regexp->mode == rm_allof)
+    {
+      result = copy_node (regexp,
+                          sizeof (struct regexp) + sizeof (regexp_t)
+                         * (regexp->regexp.allof.regexps_num - 1));
+      for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+       result->regexp.allof.regexps [i]
+         = copy_insn_regexp (regexp->regexp.allof.regexps [i]);
+    }
+  else if (regexp->mode == rm_oneof)
+    {
+      result = copy_node (regexp,
+                          sizeof (struct regexp) + sizeof (regexp_t)
+                         * (regexp->regexp.oneof.regexps_num - 1));
+      for (i = 0; i < regexp->regexp.oneof.regexps_num; i++)
+       result->regexp.oneof.regexps [i]
+         = copy_insn_regexp (regexp->regexp.oneof.regexps [i]);
+    }
+  else
+    {
+      if (regexp->mode != rm_nothing)
+       abort ();
+      result = copy_node (regexp, sizeof (struct regexp));
+    }
+  return result;
+}
+
+/* The following variable is set up 1 if a transformation has been
+   applied.  */
+static int regexp_transformed_p;
+
+/* The function makes transformation
+   A*N -> A, A, ...  */
+static regexp_t
+transform_1 (regexp)
+     regexp_t regexp;
+{
+  int i;
+  int repeat_num;
+  regexp_t operand;
+  pos_t pos;
+
+  if (regexp->mode == rm_repeat)
+    {
+      repeat_num = regexp->regexp.repeat.repeat_num;
+      if (repeat_num <= 1)
+       abort ();
+      operand = regexp->regexp.repeat.regexp;
+      pos = regexp->mode;
+      regexp = create_node (sizeof (struct regexp) + sizeof (regexp_t)
+                           * (repeat_num - 1));
+      regexp->mode = rm_sequence;
+      regexp->pos = pos;
+      regexp->regexp.sequence.regexps_num = repeat_num;
+      for (i = 0; i < repeat_num; i++)
+       regexp->regexp.sequence.regexps [i] = copy_insn_regexp (operand);
+      regexp_transformed_p = 1;
+    }
+  return regexp;
+}
+
+/* The function makes transformations
+   ...,(A,B,...),C,... -> ...,A,B,...,C,...
+   ...+(A+B+...)+C+... -> ...+A+B+...+C+...
+   ...|(A|B|...)|C|... -> ...|A|B|...|C|...  */
+static regexp_t
+transform_2 (regexp)
+     regexp_t regexp;
+{
+  if (regexp->mode == rm_sequence)
+    {
+      regexp_t sequence;
+      regexp_t result;
+      int sequence_index;
+      int i, j;
+
+      for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+       if (regexp->regexp.sequence.regexps [i]->mode == rm_sequence)
+         {
+           sequence_index = i;
+           sequence = regexp->regexp.sequence.regexps [i];
+           break;
+         }
+      if (i < regexp->regexp.sequence.regexps_num)
+       {
+         if (sequence->regexp.sequence.regexps_num <= 1
+             || regexp->regexp.sequence.regexps_num <= 1)
+           abort ();
+         result = create_node (sizeof (struct regexp)
+                                + sizeof (regexp_t)
+                               * (regexp->regexp.sequence.regexps_num
+                                   + sequence->regexp.sequence.regexps_num
+                                   - 2));
+         result->mode = rm_sequence;
+         result->pos = regexp->pos;
+         result->regexp.sequence.regexps_num
+            = (regexp->regexp.sequence.regexps_num
+               + sequence->regexp.sequence.regexps_num - 1);
+         for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+            if (i < sequence_index)
+              result->regexp.sequence.regexps [i]
+                = copy_insn_regexp (regexp->regexp.sequence.regexps [i]);
+            else if (i > sequence_index)
+              result->regexp.sequence.regexps
+                [i + sequence->regexp.sequence.regexps_num - 1]
+                = copy_insn_regexp (regexp->regexp.sequence.regexps [i]);
+            else
+              for (j = 0; j < sequence->regexp.sequence.regexps_num; j++)
+                result->regexp.sequence.regexps [i + j]
+                  = copy_insn_regexp (sequence->regexp.sequence.regexps [j]);
+         regexp_transformed_p = 1;
+         regexp = result;
+       }
+    }
+  else if (regexp->mode == rm_allof)
+    {
+      regexp_t allof;
+      regexp_t result;
+      int allof_index;
+      int i, j;
+
+      for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+       if (regexp->regexp.allof.regexps [i]->mode == rm_allof)
+         {
+           allof_index = i;
+           allof = regexp->regexp.allof.regexps [i];
+           break;
+         }
+      if (i < regexp->regexp.allof.regexps_num)
+       {
+         if (allof->regexp.allof.regexps_num <= 1
+             || regexp->regexp.allof.regexps_num <= 1)
+           abort ();
+         result = create_node (sizeof (struct regexp)
+                                + sizeof (regexp_t)
+                               * (regexp->regexp.allof.regexps_num
+                                   + allof->regexp.allof.regexps_num - 2));
+         result->mode = rm_allof;
+         result->pos = regexp->pos;
+         result->regexp.allof.regexps_num
+            = (regexp->regexp.allof.regexps_num
+               + allof->regexp.allof.regexps_num - 1);
+         for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+            if (i < allof_index)
+              result->regexp.allof.regexps [i]
+                = copy_insn_regexp (regexp->regexp.allof.regexps [i]);
+            else if (i > allof_index)
+              result->regexp.allof.regexps
+                [i + allof->regexp.allof.regexps_num - 1]
+                = copy_insn_regexp (regexp->regexp.allof.regexps [i]);
+            else
+              for (j = 0; j < allof->regexp.allof.regexps_num; j++)
+                result->regexp.allof.regexps [i + j]
+                  = copy_insn_regexp (allof->regexp.allof.regexps [j]);
+         regexp_transformed_p = 1;
+         regexp = result;
+       }
+    }
+  else if (regexp->mode == rm_oneof)
+    {
+      regexp_t oneof;
+      regexp_t result;
+      int oneof_index;
+      int i, j;
+
+      for (i = 0; i < regexp->regexp.oneof.regexps_num; i++)
+       if (regexp->regexp.oneof.regexps [i]->mode == rm_oneof)
+         {
+           oneof_index = i;
+           oneof = regexp->regexp.oneof.regexps [i];
+           break;
+         }
+      if (i < regexp->regexp.oneof.regexps_num)
+       {
+         if (oneof->regexp.oneof.regexps_num <= 1
+             || regexp->regexp.oneof.regexps_num <= 1)
+           abort ();
+         result = create_node (sizeof (struct regexp)
+                               + sizeof (regexp_t)
+                               * (regexp->regexp.oneof.regexps_num
+                                   + oneof->regexp.oneof.regexps_num - 2));
+         result->mode = rm_oneof;
+         result->pos = regexp->pos;
+         result->regexp.oneof.regexps_num
+           = (regexp->regexp.oneof.regexps_num
+               + oneof->regexp.oneof.regexps_num - 1);
+         for (i = 0; i < regexp->regexp.oneof.regexps_num; i++)
+            if (i < oneof_index)
+              result->regexp.oneof.regexps [i]
+                = copy_insn_regexp (regexp->regexp.oneof.regexps [i]);
+            else if (i > oneof_index)
+              result->regexp.oneof.regexps
+                [i + oneof->regexp.oneof.regexps_num - 1]
+                = copy_insn_regexp (regexp->regexp.oneof.regexps [i]);
+            else
+              for (j = 0; j < oneof->regexp.oneof.regexps_num; j++)
+                result->regexp.oneof.regexps [i + j]
+                  = copy_insn_regexp (oneof->regexp.oneof.regexps [j]);
+         regexp_transformed_p = 1;
+         regexp = result;
+       }
+    }
+  return regexp;
+}
+
+/* The function makes transformations
+   ...,A|B|...,C,... -> (...,A,C,...)|(...,B,C,...)|...
+   ...+(A|B|...)+C+... -> (...+A+C+...)|(...+B+C+...)|...  */
+static regexp_t
+transform_3 (regexp)
+     regexp_t regexp;
+{
+  if (regexp->mode == rm_sequence)
+    {
+      regexp_t oneof;
+      int oneof_index;
+      regexp_t result;
+      regexp_t sequence;
+      int i, j;
+
+      for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+       if (regexp->regexp.sequence.regexps [i]->mode == rm_oneof)
+         {
+           oneof_index = i;
+           oneof = regexp->regexp.sequence.regexps [i];
+           break;
+         }
+      if (i < regexp->regexp.sequence.regexps_num)
+       {
+         if (oneof->regexp.oneof.regexps_num <= 1
+             || regexp->regexp.sequence.regexps_num <= 1)
+           abort ();
+         result = create_node (sizeof (struct regexp)
+                               + sizeof (regexp_t)
+                               * (oneof->regexp.oneof.regexps_num - 1));
+         result->mode = rm_oneof;
+         result->pos = regexp->pos;
+         result->regexp.oneof.regexps_num = oneof->regexp.oneof.regexps_num;
+         for (i = 0; i < result->regexp.oneof.regexps_num; i++)
+           {
+             sequence
+                = create_node (sizeof (struct regexp)
+                               + sizeof (regexp_t)
+                               * (regexp->regexp.sequence.regexps_num - 1));
+             sequence->mode = rm_sequence;
+             sequence->pos = regexp->pos;
+             sequence->regexp.sequence.regexps_num
+                = regexp->regexp.sequence.regexps_num;
+              result->regexp.oneof.regexps [i] = sequence;
+             for (j = 0; j < sequence->regexp.sequence.regexps_num; j++)
+               if (j != oneof_index)
+                 sequence->regexp.sequence.regexps [j]
+                   = copy_insn_regexp (regexp->regexp.sequence.regexps [j]);
+               else
+                 sequence->regexp.sequence.regexps [j]
+                   = copy_insn_regexp (oneof->regexp.oneof.regexps [i]);
+           }
+         regexp_transformed_p = 1;
+         regexp = result;
+       }
+    }
+  else if (regexp->mode == rm_allof)
+    {
+      regexp_t oneof;
+      int oneof_index;
+      regexp_t result;
+      regexp_t allof;
+      int i, j;
+
+      for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+       if (regexp->regexp.allof.regexps [i]->mode == rm_oneof)
+         {
+           oneof_index = i;
+           oneof = regexp->regexp.allof.regexps [i];
+           break;
+         }
+      if (i < regexp->regexp.allof.regexps_num)
+       {
+         if (oneof->regexp.oneof.regexps_num <= 1
+             || regexp->regexp.allof.regexps_num <= 1)
+           abort ();
+         result = create_node (sizeof (struct regexp)
+                               + sizeof (regexp_t)
+                               * (oneof->regexp.oneof.regexps_num - 1));
+         result->mode = rm_oneof;
+         result->pos = regexp->pos;
+         result->regexp.oneof.regexps_num = oneof->regexp.oneof.regexps_num;
+         for (i = 0; i < result->regexp.oneof.regexps_num; i++)
+           {
+             allof
+               = create_node (sizeof (struct regexp)
+                               + sizeof (regexp_t)
+                              * (regexp->regexp.allof.regexps_num - 1));
+             allof->mode = rm_allof;
+             allof->pos = regexp->pos;
+             allof->regexp.allof.regexps_num
+                = regexp->regexp.allof.regexps_num;
+              result->regexp.oneof.regexps [i] = allof;
+             for (j = 0; j < allof->regexp.allof.regexps_num; j++)
+               if (j != oneof_index)
+                 allof->regexp.allof.regexps [j]
+                   = copy_insn_regexp (regexp->regexp.allof.regexps [j]);
+               else
+                 allof->regexp.allof.regexps [j]
+                   = copy_insn_regexp (oneof->regexp.oneof.regexps [i]);
+           }
+         regexp_transformed_p = 1;
+         regexp = result;
+       }
+    }
+  return regexp;
+}
+
+/* The function traverses IR of reservation and applies transformations
+   implemented by FUNC.  */
+static regexp_t
+regexp_transform_func (regexp, func)
+     regexp_t regexp;
+     regexp_t (*func) PARAMS ((regexp_t regexp));
+{
+  int i;
+
+  if (regexp->mode == rm_sequence)
+    for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+      regexp->regexp.sequence.regexps [i]
+       = regexp_transform_func (regexp->regexp.sequence.regexps [i], func);
+  else if (regexp->mode == rm_allof)
+    for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+      regexp->regexp.allof.regexps [i]
+       = regexp_transform_func (regexp->regexp.allof.regexps [i], func);
+  else if (regexp->mode == rm_oneof)
+    for (i = 0; i < regexp->regexp.oneof.regexps_num; i++)
+      regexp->regexp.oneof.regexps [i]
+       = regexp_transform_func (regexp->regexp.oneof.regexps [i], func);
+  else if (regexp->mode == rm_repeat)
+    regexp->regexp.repeat.regexp
+      = regexp_transform_func (regexp->regexp.repeat.regexp, func);
+  else if (regexp->mode != rm_nothing && regexp->mode != rm_unit)
+    abort ();
+  return (*func) (regexp);
+}
+
+/* The function applies all transformations for IR representation of
+   reservation REGEXP.  */
+static regexp_t
+transform_regexp (regexp)
+     regexp_t regexp;
+{
+  regexp = regexp_transform_func (regexp, transform_1);  
+  do
+    {
+      regexp_transformed_p = 0;
+      regexp = regexp_transform_func (regexp, transform_2);
+      regexp = regexp_transform_func (regexp, transform_3);
+    }
+  while (regexp_transformed_p);
+  return regexp;
+}
+
+/* The function applys all transformations for reservations of all
+   insn declarations.  */
+static void
+transform_insn_regexps ()
+{
+  decl_t decl;
+  int i;
+
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv && decl != advance_cycle_insn_decl)
+       decl->decl.insn_reserv.transformed_regexp
+         = transform_regexp (copy_insn_regexp
+                             (decl->decl.insn_reserv.regexp));
+    }
+}
+
+\f
+
+/* The page contains code for building alt_states (see comments for
+   IR) describing all possible insns reservations of an automaton.  */
+
+/* Current state being formed for which the current alt_state
+   refers.  */
+static state_t state_being_formed;
+
+/* Current alt_state being formed.  */
+static alt_state_t alt_state_being_formed;
+/* This recursive function processes `,' and units in reservation
+   REGEXP for forming alt_states of AUTOMATON.  It is believed that
+   CURR_CYCLE is start cycle of all reservation REGEXP.  */
+static int
+process_seq_for_forming_states (regexp, automaton, curr_cycle)
+     regexp_t regexp;
+     automaton_t automaton;
+     int curr_cycle;
+{
+  int i;
+
+  if (regexp == NULL)
+    return curr_cycle;
+  else if (regexp->mode == rm_unit)
+    {
+      if (regexp->regexp.unit.unit_decl->corresponding_automaton_num
+          == automaton->automaton_order_num)
+        set_state_reserv (state_being_formed, curr_cycle,
+                          regexp->regexp.unit.unit_decl->unit_num);
+      return curr_cycle;
+    }
+  else if (regexp->mode == rm_sequence)
+    {
+      for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+       curr_cycle
+         = process_seq_for_forming_states
+           (regexp->regexp.sequence.regexps [i], automaton, curr_cycle) + 1;
+      return curr_cycle;
+    }
+  else if (regexp->mode == rm_allof)
+    {
+      int finish_cycle = 0;
+      int cycle;
+
+      for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+       {
+         cycle
+            = process_seq_for_forming_states (regexp->regexp.allof.regexps [i],
+                                              automaton, curr_cycle);
+         if (finish_cycle < cycle)
+           finish_cycle = cycle;
+       }
+      return finish_cycle;
+    }
+  else
+    {
+      if (regexp->mode != rm_nothing)
+       abort ();
+      return curr_cycle;
+    }
+}
+
+/* This recursive function finishes forming ALT_STATE of AUTOMATON and
+   inserts alt_state into the table.  */
+static void
+finish_forming_alt_state (alt_state, automaton)
+     alt_state_t alt_state;
+     automaton_t automaton ATTRIBUTE_UNUSED;
+{
+  state_t state_in_table;
+  state_t corresponding_state;
+
+  corresponding_state = alt_state->state;
+  state_in_table = insert_state (corresponding_state);
+  if (state_in_table != corresponding_state)
+    {
+      free_state (corresponding_state);
+      alt_state->state = state_in_table;
+    }
+}
+
+/* The following variable value is current automaton insn for whose
+   reservation the alt states are created.  */
+static ainsn_t curr_ainsn;
+
+/* This recursive function processes `|' in reservation REGEXP for
+   forming alt_states of AUTOMATON.  List of the alt states should
+   have the same order as in the description.  */
+static void
+process_alts_for_forming_states (regexp, automaton, inside_oneof_p)
+     regexp_t regexp;
+     automaton_t automaton;
+     int inside_oneof_p;
+{
+  int i;
+
+  if (regexp->mode != rm_oneof)
+    {
+      alt_state_being_formed = get_free_alt_state ();
+      state_being_formed = get_free_state (1, automaton);
+      alt_state_being_formed->state = state_being_formed;
+      /* We inserts in reverse order but we process alternatives also
+         in reverse order.  So we have the same order of alternative
+         as in the description.  */
+      alt_state_being_formed->next_alt_state = curr_ainsn->alt_states;
+      curr_ainsn->alt_states = alt_state_being_formed;
+      (void) process_seq_for_forming_states (regexp, automaton, 0);
+      finish_forming_alt_state (alt_state_being_formed, automaton);
+    }
+  else
+    {
+      if (inside_oneof_p)
+       abort ();
+      /* We processes it in reverse order to get list with the same
+        order as in the description.  See also the previous
+        commentary.  */
+      for (i = regexp->regexp.oneof.regexps_num - 1; i >= 0; i--)
+       process_alts_for_forming_states (regexp->regexp.oneof.regexps [i],
+                                        automaton, 1);
+    }
+}
+
+/* Create nodes alt_state for all AUTOMATON insns.  */
+static void
+create_alt_states (automaton)
+     automaton_t automaton;
+{
+  struct insn_reserv_decl *reserv_decl;
+
+  for (curr_ainsn = automaton->ainsn_list;
+       curr_ainsn != NULL;
+       curr_ainsn = curr_ainsn->next_ainsn)
+    {
+      reserv_decl = curr_ainsn->insn_reserv_decl;
+      if (reserv_decl != &advance_cycle_insn_decl->decl.insn_reserv)
+        {
+          curr_ainsn->alt_states = NULL;
+          process_alts_for_forming_states (reserv_decl->transformed_regexp,
+                                          automaton, 0);
+          curr_ainsn->sorted_alt_states
+           = uniq_sort_alt_states (curr_ainsn->alt_states);
+        }
+    }
+}
+
+\f
+
+/* The page contains major code for building DFA(s) for fast pipeline
+   hazards recognition.  */
+
+/* The function forms list of ainsns of AUTOMATON with the same
+   reservation.  */
+static void
+form_ainsn_with_same_reservs (automaton)
+     automaton_t automaton;
+{
+  ainsn_t curr_ainsn;
+  size_t i;
+  vla_ptr_t first_insns;
+  vla_ptr_t last_insns;
+
+  VLA_PTR_CREATE (first_insns, 150, "first insns with the same reservs");
+  VLA_PTR_CREATE (last_insns, 150, "last insns with the same reservs");
+  for (curr_ainsn = automaton->ainsn_list;
+       curr_ainsn != NULL;
+       curr_ainsn = curr_ainsn->next_ainsn)
+    if (curr_ainsn->insn_reserv_decl
+       == &advance_cycle_insn_decl->decl.insn_reserv)
+      {
+        curr_ainsn->next_same_reservs_insn = NULL;
+        curr_ainsn->first_insn_with_same_reservs = 1;
+      }
+    else
+      {
+        for (i = 0; i < VLA_PTR_LENGTH (first_insns); i++)
+          if (alt_states_eq
+              (curr_ainsn->sorted_alt_states,
+               ((ainsn_t) VLA_PTR (first_insns, i))->sorted_alt_states))
+            break;
+        curr_ainsn->next_same_reservs_insn = NULL;
+        if (i < VLA_PTR_LENGTH (first_insns))
+          {
+            curr_ainsn->first_insn_with_same_reservs = 0;
+           ((ainsn_t) VLA_PTR (last_insns, i))->next_same_reservs_insn
+             = curr_ainsn;
+            VLA_PTR (last_insns, i) = curr_ainsn;
+          }
+        else
+          {
+            VLA_PTR_ADD (first_insns, curr_ainsn);
+            VLA_PTR_ADD (last_insns, curr_ainsn);
+            curr_ainsn->first_insn_with_same_reservs = 1;
+          }
+      }
+  VLA_PTR_DELETE (first_insns);
+  VLA_PTR_DELETE (last_insns);
+}
+
+/* The following function creates all states of nondeterministic (if
+   NDFA_FLAG has nonzero value) or deterministic AUTOMATON.  */
+static void
+make_automaton (automaton)
+     automaton_t automaton;
+{
+  ainsn_t ainsn;
+  struct insn_reserv_decl *insn_reserv_decl;
+  alt_state_t alt_state;
+  state_t state;
+  state_t start_state;
+  state_t state2;
+  ainsn_t advance_cycle_ainsn;
+  arc_t added_arc;
+  vla_ptr_t state_stack;
+
+  VLA_PTR_CREATE (state_stack, 150, "state stack");
+  /* Create the start state (empty state).  */
+  start_state = insert_state (get_free_state (1, automaton));
+  automaton->start_state = start_state;
+  start_state->it_was_placed_in_stack_for_NDFA_forming = 1;
+  VLA_PTR_ADD (state_stack, start_state);
+  while (VLA_PTR_LENGTH (state_stack) != 0)
+    {
+      state = VLA_PTR (state_stack, VLA_PTR_LENGTH (state_stack) - 1);
+      VLA_PTR_SHORTEN (state_stack, 1);
+      advance_cycle_ainsn = NULL;
+      for (ainsn = automaton->ainsn_list;
+          ainsn != NULL;
+          ainsn = ainsn->next_ainsn)
+        if (ainsn->first_insn_with_same_reservs)
+          {
+            insn_reserv_decl = ainsn->insn_reserv_decl;
+            if (insn_reserv_decl != &advance_cycle_insn_decl->decl.insn_reserv)
+              {
+               /* We process alt_states in the same order as they are
+                   present in the description.  */
+               added_arc = NULL;
+                for (alt_state = ainsn->alt_states;
+                     alt_state != NULL;
+                     alt_state = alt_state->next_alt_state)
+                  {
+                    state2 = alt_state->state;
+                    if (!intersected_state_reservs_p (state, state2))
+                      {
+                        state2 = states_union (state, state2);
+                        if (!state2->it_was_placed_in_stack_for_NDFA_forming)
+                          {
+                            state2->it_was_placed_in_stack_for_NDFA_forming
+                             = 1;
+                            VLA_PTR_ADD (state_stack, state2);
+                          }
+                       added_arc = add_arc (state, state2, ainsn, 1);
+                       if (!ndfa_flag)
+                         break;
+                      }
+                  }
+               if (!ndfa_flag && added_arc != NULL)
+                 {
+                   added_arc->state_alts = 0;
+                   for (alt_state = ainsn->alt_states;
+                        alt_state != NULL;
+                        alt_state = alt_state->next_alt_state)
+                     {
+                       state2 = alt_state->state;
+                       if (!intersected_state_reservs_p (state, state2))
+                         added_arc->state_alts++;
+                     }
+                 }
+              }
+            else
+              advance_cycle_ainsn = ainsn;
+          }
+      /* Add transition to advance cycle.  */
+      state2 = state_shift (state);
+      if (!state2->it_was_placed_in_stack_for_NDFA_forming)
+        {
+          state2->it_was_placed_in_stack_for_NDFA_forming = 1;
+          VLA_PTR_ADD (state_stack, state2);
+        }
+      if (advance_cycle_ainsn == NULL)
+       abort ();
+      add_arc (state, state2, advance_cycle_ainsn, 1);
+    }
+  VLA_PTR_DELETE (state_stack);
+}
+
+/* Foms lists of all arcs of STATE marked by the same ainsn.  */
+static void
+form_arcs_marked_by_insn (state)
+     state_t state;
+{
+  decl_t decl;
+  arc_t arc;
+  int i;
+
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv)
+       decl->decl.insn_reserv.arcs_marked_by_insn = NULL;
+    }
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    {
+      if (arc->insn == NULL)
+       abort ();
+      arc->next_arc_marked_by_insn
+       = arc->insn->insn_reserv_decl->arcs_marked_by_insn;
+      arc->insn->insn_reserv_decl->arcs_marked_by_insn = arc;
+    }
+}
+
+/* The function creates composed state (see comments for IR) from
+   ORIGINAL_STATE and list of arcs ARCS_MARKED_BY_INSN marked by the
+   same insn.  If the composed state is not in STATE_STACK yet, it is
+   popped to STATE_STACK.  */
+static void
+create_composed_state (original_state, arcs_marked_by_insn, state_stack)
+     state_t original_state;
+     arc_t arcs_marked_by_insn;
+     vla_ptr_t *state_stack;
+{
+  state_t state;
+  alt_state_t curr_alt_state;
+  alt_state_t new_alt_state;
+  arc_t curr_arc;
+  arc_t next_arc;
+  state_t state_in_table;
+  state_t temp_state;
+  alt_state_t canonical_alt_states_list;
+  int alts_number;
+
+  if (arcs_marked_by_insn == NULL)
+    return;
+  if (arcs_marked_by_insn->next_arc_marked_by_insn == NULL)
+    state = arcs_marked_by_insn->to_state;
+  else
+    {
+      if (!ndfa_flag)
+       abort ();
+      /* Create composed state.  */
+      state = get_free_state (0, arcs_marked_by_insn->to_state->automaton);
+      curr_alt_state = NULL;
+      for (curr_arc = arcs_marked_by_insn;
+           curr_arc != NULL;
+           curr_arc = curr_arc->next_arc_marked_by_insn)
+        {
+          new_alt_state = get_free_alt_state ();
+          new_alt_state->next_alt_state = curr_alt_state;
+          new_alt_state->state = curr_arc->to_state;
+         if (curr_arc->to_state->component_states != NULL)
+           abort ();
+          curr_alt_state = new_alt_state;
+        }
+      /* There are not identical sets in the alt state list.  */
+      canonical_alt_states_list = uniq_sort_alt_states (curr_alt_state);
+      if (canonical_alt_states_list->next_sorted_alt_state == NULL)
+        {
+          temp_state = state;
+          state = canonical_alt_states_list->state;
+          free_state (temp_state);
+        }
+      else
+        {
+          state->component_states = canonical_alt_states_list;
+          state_in_table = insert_state (state);
+          if (state_in_table != state)
+            {
+              if (!state_in_table->it_was_placed_in_stack_for_DFA_forming)
+               abort ();
+              free_state (state);
+              state = state_in_table;
+            }
+          else
+            {
+              if (state->it_was_placed_in_stack_for_DFA_forming)
+               abort ();
+              for (curr_alt_state = state->component_states;
+                   curr_alt_state != NULL;
+                   curr_alt_state = curr_alt_state->next_sorted_alt_state)
+                for (curr_arc = first_out_arc (curr_alt_state->state);
+                     curr_arc != NULL;
+                     curr_arc = next_out_arc (curr_arc))
+                 add_arc (state, curr_arc->to_state, curr_arc->insn, 1);
+            }
+          arcs_marked_by_insn->to_state = state;
+          for (alts_number = 0,
+              curr_arc = arcs_marked_by_insn->next_arc_marked_by_insn;
+               curr_arc != NULL;
+               curr_arc = next_arc)
+            {
+              next_arc = curr_arc->next_arc_marked_by_insn;
+              remove_arc (original_state, curr_arc);
+             alts_number++;
+            }
+         arcs_marked_by_insn->state_alts = alts_number;
+        }
+    }
+  if (!state->it_was_placed_in_stack_for_DFA_forming)
+    {
+      state->it_was_placed_in_stack_for_DFA_forming = 1;
+      VLA_PTR_ADD (*state_stack, state);
+    }
+}
+
+/* The function transformes nondeterminstic AUTOMATON into
+   deterministic.  */
+static void
+NDFA_to_DFA (automaton)
+     automaton_t automaton;
+{
+  state_t start_state;
+  state_t state;
+  decl_t decl;
+  vla_ptr_t state_stack;
+  int i;
+
+  VLA_PTR_CREATE (state_stack, 150, "state stack");
+  /* Create the start state (empty state).  */
+  start_state = automaton->start_state;
+  start_state->it_was_placed_in_stack_for_DFA_forming = 1;
+  VLA_PTR_ADD (state_stack, start_state);
+  while (VLA_PTR_LENGTH (state_stack) != 0)
+    {
+      state = VLA_PTR (state_stack, VLA_PTR_LENGTH (state_stack) - 1);
+      VLA_PTR_SHORTEN (state_stack, 1);
+      form_arcs_marked_by_insn (state);
+      for (i = 0; i < description->decls_num; i++)
+       {
+         decl = description->decls [i];
+         if (decl->mode == dm_insn_reserv)
+           create_composed_state
+              (state, decl->decl.insn_reserv.arcs_marked_by_insn,
+              &state_stack);
+       }
+    }
+  VLA_PTR_DELETE (state_stack);
+}
+
+/* The following variable value is current number (1, 2, ...) of passing
+   graph of states.  */
+static int curr_state_graph_pass_num;
+
+/* This recursive function passes all states achieved from START_STATE
+   and applies APPLIED_FUNC to them.  */
+static void
+pass_state_graph (start_state, applied_func)
+     state_t start_state;
+     void (*applied_func) PARAMS ((state_t state));
+{
+  arc_t arc;
+
+  if (start_state->pass_num == curr_state_graph_pass_num)
+    return;
+  start_state->pass_num = curr_state_graph_pass_num;
+  (*applied_func) (start_state);
+  for (arc = first_out_arc (start_state);
+       arc != NULL;
+       arc = next_out_arc (arc))
+    pass_state_graph (arc->to_state, applied_func);
+}
+
+/* This recursive function passes all states of AUTOMATON and applies
+   APPLIED_FUNC to them.  */
+static void
+pass_states (automaton, applied_func)
+     automaton_t automaton;
+     void (*applied_func) PARAMS ((state_t state));
+{
+  curr_state_graph_pass_num++;
+  pass_state_graph (automaton->start_state, applied_func);
+}
+
+/* The function initializes code for passing of all states.  */
+static void
+initiate_pass_states ()
+{
+  curr_state_graph_pass_num = 0;
+}
+
+/* The following vla is used for storing pointers to all achieved
+   states.  */
+static vla_ptr_t all_achieved_states;
+
+/* This function is called by function pass_states to add an achieved
+   STATE.  */
+static void
+add_achieved_state (state)
+     state_t state;
+{
+  VLA_PTR_ADD (all_achieved_states, state);
+}
+
+/* The function sets up equivalence numbers of insns which mark all
+   out arcs of STATE by equiv_class_num_1 (if ODD_ITERATION_FLAG has
+   nonzero value) or by equiv_class_num_2 of the destination state.
+   The function returns number of out arcs of STATE.  */
+static int
+set_out_arc_insns_equiv_num (state, odd_iteration_flag)
+     state_t state;
+     int odd_iteration_flag;
+{
+  int state_out_arcs_num;
+  arc_t arc;
+
+  state_out_arcs_num = 0;
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    {
+      if (arc->insn->insn_reserv_decl->equiv_class_num != 0
+         || arc->insn->insn_reserv_decl->state_alts != 0)
+       abort ();
+      state_out_arcs_num++;
+      arc->insn->insn_reserv_decl->equiv_class_num
+       = (odd_iteration_flag
+           ? arc->to_state->equiv_class_num_1
+          : arc->to_state->equiv_class_num_2);
+      arc->insn->insn_reserv_decl->state_alts = arc->state_alts;
+      if (arc->insn->insn_reserv_decl->equiv_class_num == 0
+         || arc->insn->insn_reserv_decl->state_alts <= 0)
+       abort ();
+    }
+  return state_out_arcs_num;
+}
+
+/* The function clears equivalence numbers and alt_states in all insns
+   which mark all out arcs of STATE.  */
+static void
+clear_arc_insns_equiv_num (state)
+     state_t state;
+{
+  arc_t arc;
+
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    {
+      arc->insn->insn_reserv_decl->equiv_class_num = 0;
+      arc->insn->insn_reserv_decl->state_alts = 0;
+    }
+}
+
+/* The function copies pointers to equivalent states from vla FROM
+   into vla TO.  */
+static void
+copy_equiv_class (to, from)
+     vla_ptr_t *to;
+     const vla_ptr_t *from;
+{
+  state_t *class_ptr;
+
+  VLA_PTR_NULLIFY (*to);
+  for (class_ptr = VLA_PTR_BEGIN (*from);
+       class_ptr <= (state_t *) VLA_PTR_LAST (*from);
+       class_ptr++)
+    VLA_PTR_ADD (*to, *class_ptr);
+}
+
+/* The function returns nonzero value if STATE is not equivalent to
+   another state from the same current partition on equivalence
+   classes Another state has ORIGINAL_STATE_OUT_ARCS_NUM number of
+   output arcs.  Iteration of making equivalence partition is defined
+   by ODD_ITERATION_FLAG.  */
+static int
+state_is_differed (state, original_state_out_arcs_num, odd_iteration_flag)
+     state_t state;
+     int original_state_out_arcs_num;
+     int odd_iteration_flag;
+{
+  arc_t arc;
+  int state_out_arcs_num;
+
+  state_out_arcs_num = 0;
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    {
+      state_out_arcs_num++;
+      if ((odd_iteration_flag
+           ? arc->to_state->equiv_class_num_1
+          : arc->to_state->equiv_class_num_2)
+          != arc->insn->insn_reserv_decl->equiv_class_num
+         || (arc->insn->insn_reserv_decl->state_alts != arc->state_alts))
+        return 1;
+    }
+  return state_out_arcs_num != original_state_out_arcs_num;
+}
+
+/* The function makes initial partition of STATES on equivalent
+   classes.  */
+static state_t
+init_equiv_class (states, states_num)
+     state_t *states;
+     int states_num;
+{
+  state_t *state_ptr;
+  state_t result_equiv_class;
+
+  result_equiv_class = NULL;
+  for (state_ptr = states; state_ptr < states + states_num; state_ptr++)
+    {
+      (*state_ptr)->equiv_class_num_1 = 1;
+      (*state_ptr)->next_equiv_class_state = result_equiv_class;
+      result_equiv_class = *state_ptr;
+    }
+  return result_equiv_class;
+}
+
+/* The function processes equivalence class given by its pointer
+   EQUIV_CLASS_PTR on odd iteration if ODD_ITERATION_FLAG.  If there
+   are not equvalent states, the function partitions the class
+   removing nonequivalent states and placing them in
+   *NEXT_ITERATION_CLASSES, increments *NEW_EQUIV_CLASS_NUM_PTR ans
+   assigns it to the state equivalence number.  If the class has been
+   partitioned, the function returns nonzero value. */
+static int
+partition_equiv_class (equiv_class_ptr, odd_iteration_flag,
+                      next_iteration_classes, new_equiv_class_num_ptr)
+     state_t *equiv_class_ptr;
+     int odd_iteration_flag;
+     vla_ptr_t *next_iteration_classes;
+     int *new_equiv_class_num_ptr;
+{
+  state_t new_equiv_class;
+  int partition_p;
+  state_t first_state;
+  state_t curr_state;
+  state_t prev_state;
+  state_t next_state;
+  int out_arcs_num;
+
+  partition_p = 0;
+  if (*equiv_class_ptr == NULL)
+    abort ();
+  for (first_state = *equiv_class_ptr;
+       first_state != NULL;
+       first_state = new_equiv_class)
+    {
+      new_equiv_class = NULL;
+      if (first_state->next_equiv_class_state != NULL)
+       {
+         /* There are more one states in the class equivalence.  */
+         out_arcs_num = set_out_arc_insns_equiv_num (first_state,
+                                                     odd_iteration_flag);
+         for (prev_state = first_state,
+                curr_state = first_state->next_equiv_class_state;
+              curr_state != NULL;
+              curr_state = next_state)
+           {
+             next_state = curr_state->next_equiv_class_state;
+             if (state_is_differed (curr_state, out_arcs_num,
+                                    odd_iteration_flag))
+               {
+                 /* Remove curr state from the class equivalence.  */
+                 prev_state->next_equiv_class_state = next_state;
+                 /* Add curr state to the new class equivalence.  */
+                 curr_state->next_equiv_class_state = new_equiv_class;
+                 if (new_equiv_class == NULL)
+                   (*new_equiv_class_num_ptr)++;
+                 if (odd_iteration_flag)
+                   curr_state->equiv_class_num_2 = *new_equiv_class_num_ptr;
+                 else
+                   curr_state->equiv_class_num_1 = *new_equiv_class_num_ptr;
+                 new_equiv_class = curr_state;
+                 partition_p = 1;
+               }
+             else
+               prev_state = curr_state;
+           }
+         clear_arc_insns_equiv_num (first_state);
+       }
+      if (new_equiv_class != NULL)
+       VLA_PTR_ADD  (*next_iteration_classes, new_equiv_class);
+    }
+  return partition_p;
+}
+
+/* The function finds equivalent states of AUTOMATON.  */
+static void
+evaluate_equiv_classes (automaton, equiv_classes)
+     automaton_t automaton;
+     vla_ptr_t *equiv_classes;
+{
+  state_t new_equiv_class;
+  int new_equiv_class_num;
+  int odd_iteration_flag;
+  int finish_flag;
+  vla_ptr_t next_iteration_classes;
+  state_t *equiv_class_ptr;
+  state_t *state_ptr;
+  
+  VLA_PTR_CREATE (all_achieved_states, 1500, "all achieved states");
+  pass_states (automaton, add_achieved_state);
+  new_equiv_class = init_equiv_class (VLA_PTR_BEGIN (all_achieved_states),
+                                      VLA_PTR_LENGTH (all_achieved_states));
+  odd_iteration_flag = 0;
+  new_equiv_class_num = 1;
+  VLA_PTR_CREATE (next_iteration_classes, 150, "next iteration classes");
+  VLA_PTR_ADD (next_iteration_classes, new_equiv_class);
+  do
+    {
+      odd_iteration_flag = !odd_iteration_flag;
+      finish_flag = 1;
+      copy_equiv_class (equiv_classes, &next_iteration_classes);
+      /* Transfer equiv numbers for the next iteration.  */
+      for (state_ptr = VLA_PTR_BEGIN (all_achieved_states);
+          state_ptr <= (state_t *) VLA_PTR_LAST (all_achieved_states);
+           state_ptr++)
+       if (odd_iteration_flag)
+         (*state_ptr)->equiv_class_num_2 = (*state_ptr)->equiv_class_num_1;
+       else
+         (*state_ptr)->equiv_class_num_1 = (*state_ptr)->equiv_class_num_2;
+      for (equiv_class_ptr = VLA_PTR_BEGIN (*equiv_classes);
+           equiv_class_ptr <= (state_t *) VLA_PTR_LAST (*equiv_classes);
+           equiv_class_ptr++)
+       if (partition_equiv_class (equiv_class_ptr, odd_iteration_flag,
+                                  &next_iteration_classes,
+                                  &new_equiv_class_num))
+         finish_flag = 0;
+    }
+  while (!finish_flag);
+  VLA_PTR_DELETE (next_iteration_classes);
+  VLA_PTR_DELETE (all_achieved_states);
+}
+
+/* The function merges equivalent states of AUTOMATON.  */
+static void
+merge_states (automaton, equiv_classes)
+     automaton_t automaton;
+     vla_ptr_t *equiv_classes;
+{
+  state_t *equiv_class_ptr;
+  state_t curr_state;
+  state_t new_state;
+  state_t first_class_state;
+  alt_state_t alt_states;
+  alt_state_t new_alt_state;
+  arc_t curr_arc;
+  arc_t next_arc;
+
+  /* Create states corresponding to equivalence classes containing two
+     or more states.  */
+  for (equiv_class_ptr = VLA_PTR_BEGIN (*equiv_classes);
+       equiv_class_ptr <= (state_t *) VLA_PTR_LAST (*equiv_classes);
+       equiv_class_ptr++)
+    if ((*equiv_class_ptr)->next_equiv_class_state != NULL)
+      {
+        /* There are more one states in the class equivalence.  */
+        /* Create new compound state.  */
+        new_state = get_free_state (0, automaton);
+        alt_states = NULL;
+        first_class_state = *equiv_class_ptr;
+        for (curr_state = first_class_state;
+             curr_state != NULL;
+             curr_state = curr_state->next_equiv_class_state)
+          {
+            curr_state->equiv_class_state = new_state;
+            new_alt_state = get_free_alt_state ();
+            new_alt_state->state = curr_state;
+            new_alt_state->next_sorted_alt_state = alt_states;
+            alt_states = new_alt_state;
+          }
+        new_state->component_states = alt_states;
+      }
+    else
+      (*equiv_class_ptr)->equiv_class_state = *equiv_class_ptr;
+  for (equiv_class_ptr = VLA_PTR_BEGIN (*equiv_classes);
+       equiv_class_ptr <= (state_t *) VLA_PTR_LAST (*equiv_classes);
+       equiv_class_ptr++)
+    if ((*equiv_class_ptr)->next_equiv_class_state != NULL)
+      {
+        first_class_state = *equiv_class_ptr;
+        /* Create new arcs output from the state corresponding to
+           equiv class.  */
+        for (curr_arc = first_out_arc (first_class_state);
+             curr_arc != NULL;
+             curr_arc = next_out_arc (curr_arc))
+          add_arc (first_class_state->equiv_class_state,
+                   curr_arc->to_state->equiv_class_state,
+                  curr_arc->insn, curr_arc->state_alts);
+        /* Delete output arcs from states of given class equivalence.  */
+        for (curr_state = first_class_state;
+             curr_state != NULL;
+             curr_state = curr_state->next_equiv_class_state)
+          {
+            if (automaton->start_state == curr_state)
+              automaton->start_state = curr_state->equiv_class_state;
+            /* Delete the state and its output arcs.  */
+            for (curr_arc = first_out_arc (curr_state);
+                 curr_arc != NULL;
+                 curr_arc = next_arc)
+              {
+                next_arc = next_out_arc (curr_arc);
+                free_arc (curr_arc);
+              }
+          }
+      }
+    else
+      {
+        /* Change `to_state' of arcs output from the state of given
+           equivalence class.  */
+        for (curr_arc = first_out_arc (*equiv_class_ptr);
+             curr_arc != NULL;
+             curr_arc = next_out_arc (curr_arc))
+          curr_arc->to_state = curr_arc->to_state->equiv_class_state;
+      }
+}
+
+/* The function sets up new_cycle_p for states if there is arc to the
+   state marked by advance_cycle_insn_decl.  */
+static void
+set_new_cycle_flags (state)
+     state_t state;
+{
+  arc_t arc;
+
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    if (arc->insn->insn_reserv_decl
+       == &advance_cycle_insn_decl->decl.insn_reserv)
+      arc->to_state->new_cycle_p = 1;
+}
+
+/* The top level function for minimization of deterministic
+   AUTOMATON.  */
+static void
+minimize_DFA (automaton)
+     automaton_t automaton;
+{
+  vla_ptr_t equiv_classes;
+
+  VLA_PTR_CREATE (equiv_classes, 1500, "equivalence classes");
+  evaluate_equiv_classes (automaton, &equiv_classes);
+  merge_states (automaton, &equiv_classes);
+  pass_states (automaton, set_new_cycle_flags);
+  VLA_PTR_DELETE (equiv_classes);
+}
+
+/* Values of two variables are counted number of states and arcs in an
+   automaton.  */
+static int curr_counted_states_num;
+static int curr_counted_arcs_num;
+
+/* The function is called by function `pass_states' to count states
+   and arcs of an automaton.  */
+static void
+incr_states_and_arcs_nums (state)
+     state_t state;
+{
+  arc_t arc;
+
+  curr_counted_states_num++;
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    curr_counted_arcs_num++;
+}
+
+/* The function counts states and arcs of AUTOMATON.  */
+static void
+count_states_and_arcs (automaton, states_num, arcs_num)
+     automaton_t automaton;
+     int *states_num;
+     int *arcs_num;
+{
+  curr_counted_states_num = 0;
+  curr_counted_arcs_num = 0;
+  pass_states (automaton, incr_states_and_arcs_nums);
+  *states_num = curr_counted_states_num;
+  *arcs_num = curr_counted_arcs_num;
+}
+
+/* The function builds one DFA AUTOMATON for fast pipeline hazards
+   recognition after checking and simplifying IR of the
+   description.  */
+static void
+build_automaton (automaton)
+     automaton_t automaton;
+{
+  int states_num;
+  int arcs_num;
+
+  ticker_on (&NDFA_time);
+  make_automaton (automaton);
+  ticker_off (&NDFA_time);
+  count_states_and_arcs (automaton, &states_num, &arcs_num);
+  automaton->NDFA_states_num = states_num;
+  automaton->NDFA_arcs_num = arcs_num;
+  ticker_on (&NDFA_to_DFA_time);
+  NDFA_to_DFA (automaton);
+  ticker_off (&NDFA_to_DFA_time);
+  count_states_and_arcs (automaton, &states_num, &arcs_num);
+  automaton->DFA_states_num = states_num;
+  automaton->DFA_arcs_num = arcs_num;
+  if (!no_minimization_flag)
+    {
+      ticker_on (&minimize_time);
+      minimize_DFA (automaton);
+      ticker_off (&minimize_time);
+      count_states_and_arcs (automaton, &states_num, &arcs_num);
+      automaton->minimal_DFA_states_num = states_num;
+      automaton->minimal_DFA_arcs_num = arcs_num;
+    }
+}
+
+\f
+
+/* The page contains code for enumeration  of all states of an automaton.  */
+
+/* Variable used for enumeration of all states of an automaton.  Its
+   value is current number of automaton states.  */
+static int curr_state_order_num;
+
+/* The function is called by function `pass_states' for enumerating
+   states.  */
+static void
+set_order_state_num (state)
+     state_t state;
+{
+  state->order_state_num = curr_state_order_num;
+  curr_state_order_num++;
+}
+
+/* The function enumerates all states of AUTOMATON.  */
+static void
+enumerate_states (automaton)
+     automaton_t automaton;
+{
+  curr_state_order_num = 0;
+  pass_states (automaton, set_order_state_num);
+  automaton->achieved_states_num = curr_state_order_num;
+}
+
+\f
+
+/* The page contains code for finding equivalent automaton insns
+   (ainsns).  */
+
+/* The function inserts AINSN into cyclic list
+   CYCLIC_EQUIV_CLASS_INSN_LIST of ainsns.  */
+static ainsn_t
+insert_ainsn_into_equiv_class (ainsn, cyclic_equiv_class_insn_list)
+     ainsn_t ainsn;
+     ainsn_t cyclic_equiv_class_insn_list;
+{
+  if (cyclic_equiv_class_insn_list == NULL)
+    ainsn->next_equiv_class_insn = ainsn;
+  else
+    {
+      ainsn->next_equiv_class_insn
+        = cyclic_equiv_class_insn_list->next_equiv_class_insn;
+      cyclic_equiv_class_insn_list->next_equiv_class_insn = ainsn;
+    }
+  return ainsn;
+}
+
+/* The function deletes equiv_class_insn into cyclic list of
+   equivalent ainsns.  */
+static void
+delete_ainsn_from_equiv_class (equiv_class_insn)
+     ainsn_t equiv_class_insn;
+{
+  ainsn_t curr_equiv_class_insn;
+  ainsn_t prev_equiv_class_insn;
+
+  prev_equiv_class_insn = equiv_class_insn;
+  for (curr_equiv_class_insn = equiv_class_insn->next_equiv_class_insn;
+       curr_equiv_class_insn != equiv_class_insn;
+       curr_equiv_class_insn = curr_equiv_class_insn->next_equiv_class_insn)
+    prev_equiv_class_insn = curr_equiv_class_insn;
+  if (prev_equiv_class_insn != equiv_class_insn)
+    prev_equiv_class_insn->next_equiv_class_insn
+      = equiv_class_insn->next_equiv_class_insn;
+}
+
+/* The function processes AINSN of a state in order to find equivalent
+   ainsns.  INSN_ARCS_ARRAY is table: code of insn -> out arc of the
+   state.  */
+static void
+process_insn_equiv_class (ainsn, insn_arcs_array)
+     ainsn_t ainsn;
+     arc_t *insn_arcs_array;
+{
+  ainsn_t next_insn;
+  ainsn_t curr_insn;
+  ainsn_t cyclic_insn_list;
+  arc_t arc;
+
+  if (insn_arcs_array [ainsn->insn_reserv_decl->insn_num] == NULL)
+    abort ();
+  curr_insn = ainsn;
+  /* New class of ainsns which are not equivalent to given ainsn.  */
+  cyclic_insn_list = NULL;
+  do
+    {
+      next_insn = curr_insn->next_equiv_class_insn;
+      arc = insn_arcs_array [curr_insn->insn_reserv_decl->insn_num];
+      if (arc == NULL
+          || (insn_arcs_array [ainsn->insn_reserv_decl->insn_num]->to_state
+              != arc->to_state))
+        {
+          delete_ainsn_from_equiv_class (curr_insn);
+          cyclic_insn_list = insert_ainsn_into_equiv_class (curr_insn,
+                                                           cyclic_insn_list);
+        }
+      curr_insn = next_insn;
+    }
+  while (curr_insn != ainsn);
+}
+
+/* The function processes STATE in order to find equivalent ainsns.  */
+static void
+process_state_for_insn_equiv_partition (state)
+     state_t state;
+{
+  arc_t arc;
+  arc_t *insn_arcs_array;
+  int i;
+  vla_ptr_t insn_arcs_vect;
+
+  VLA_PTR_CREATE (insn_arcs_vect, 500, "insn arcs vector");
+  VLA_PTR_EXPAND (insn_arcs_vect, description->insns_num);
+  insn_arcs_array = VLA_PTR_BEGIN (insn_arcs_vect);
+  /* Process insns of the arcs.  */
+  for (i = 0; i < description->insns_num; i++)
+    insn_arcs_array [i] = NULL;
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    insn_arcs_array [arc->insn->insn_reserv_decl->insn_num] = arc;
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    process_insn_equiv_class (arc->insn, insn_arcs_array);
+  VLA_PTR_DELETE (insn_arcs_vect);
+}
+
+/* The function searches for equivalent ainsns of AUTOMATON.  */
+static void
+set_insn_equiv_classes (automaton)
+     automaton_t automaton;
+{
+  ainsn_t ainsn;
+  ainsn_t first_insn;
+  ainsn_t curr_insn;
+  ainsn_t cyclic_insn_list;
+  ainsn_t insn_with_same_reservs;
+  int equiv_classes_num;
+
+  /* All insns are included in one equivalence class.  */
+  cyclic_insn_list = NULL;
+  for (ainsn = automaton->ainsn_list; ainsn != NULL; ainsn = ainsn->next_ainsn)
+    if (ainsn->first_insn_with_same_reservs)
+      cyclic_insn_list = insert_ainsn_into_equiv_class (ainsn,
+                                                       cyclic_insn_list);
+  /* Process insns in order to make equivalence partition.  */
+  pass_states (automaton, process_state_for_insn_equiv_partition);
+  /* Enumerate equiv classes.  */
+  for (ainsn = automaton->ainsn_list; ainsn != NULL; ainsn = ainsn->next_ainsn)
+    /* Set undefined value.  */
+    ainsn->insn_equiv_class_num = -1;
+  equiv_classes_num = 0;
+  for (ainsn = automaton->ainsn_list; ainsn != NULL; ainsn = ainsn->next_ainsn)
+    if (ainsn->insn_equiv_class_num < 0)
+      {
+        first_insn = ainsn;
+        if (!first_insn->first_insn_with_same_reservs)
+         abort ();
+        first_insn->first_ainsn_with_given_equialence_num = 1;
+        curr_insn = first_insn;
+        do
+          {
+            for (insn_with_same_reservs = curr_insn;
+                 insn_with_same_reservs != NULL;
+                 insn_with_same_reservs
+                  = insn_with_same_reservs->next_same_reservs_insn)
+              insn_with_same_reservs->insn_equiv_class_num = equiv_classes_num;
+            curr_insn = curr_insn->next_equiv_class_insn;
+          }
+        while (curr_insn != first_insn);
+        equiv_classes_num++;
+      }
+  automaton->insn_equiv_classes_num = equiv_classes_num;
+}
+
+\f
+
+/* This page contains code for creating DFA(s) and calls functions
+   building them.  */
+
+
+/* The following value is used to prevent floating point overflow for
+   estimating an automaton bound.  The value should be less DBL_MAX on
+   the host machine.  We use here approximate minimum of maximal
+   double floating point value required by ANSI C standard.  It
+   will work for non ANSI sun compiler too.  */
+
+#define MAX_FLOATING_POINT_VALUE_FOR_AUTOMATON_BOUND  1.0E37
+
+/* The function estimate size of the single DFA used by PHR (pipeline
+   hazards recognizer).  */
+static double
+estimate_one_automaton_bound ()
+{
+  decl_t decl;
+  double one_automaton_estimation_bound;
+  double root_value;
+  int i;
+
+  one_automaton_estimation_bound = 1.0;
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit)
+       {
+         root_value = exp (log (decl->decl.unit.max_occ_cycle_num + 1.0)
+                            / automata_num);
+         if (MAX_FLOATING_POINT_VALUE_FOR_AUTOMATON_BOUND / root_value
+             > one_automaton_estimation_bound)
+           one_automaton_estimation_bound *= root_value;
+       }
+    }
+  return one_automaton_estimation_bound;
+}
+
+/* The function compares unit declarations acoording to their maximal
+   cycle in reservations.  */
+static int
+compare_max_occ_cycle_nums (unit_decl_1, unit_decl_2)
+     const void *unit_decl_1;
+     const void *unit_decl_2;
+{
+  if (((*(decl_t *) unit_decl_1)->decl.unit.max_occ_cycle_num)
+      < ((*(decl_t *) unit_decl_2)->decl.unit.max_occ_cycle_num))
+    return 1;
+  else if (((*(decl_t *) unit_decl_1)->decl.unit.max_occ_cycle_num)
+          == ((*(decl_t *) unit_decl_2)->decl.unit.max_occ_cycle_num))
+    return 0;
+  else
+    return -1;
+}
+
+/* The function makes heuristic assigning automata to units.  Actually
+   efficacy of the algorithm has been checked yet??? */
+static void
+units_to_automata_heuristic_distr ()
+{
+  double estimation_bound;
+  decl_t decl;
+  decl_t *unit_decl_ptr;
+  int automaton_num;
+  int rest_units_num;
+  double bound_value;
+  vla_ptr_t unit_decls;
+  int i;
+
+  if (description->units_num == 0)
+    return;
+  estimation_bound = estimate_one_automaton_bound ();
+  VLA_PTR_CREATE (unit_decls, 150, "unit decls");
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit)
+       VLA_PTR_ADD (unit_decls, decl);
+    }
+  qsort (VLA_PTR_BEGIN (unit_decls), VLA_PTR_LENGTH (unit_decls),
+         sizeof (decl_t), compare_max_occ_cycle_nums);
+  automaton_num = 0;
+  unit_decl_ptr = VLA_PTR_BEGIN (unit_decls);
+  bound_value = (*unit_decl_ptr)->decl.unit.max_occ_cycle_num;
+  (*unit_decl_ptr)->decl.unit.corresponding_automaton_num = automaton_num;
+  for (unit_decl_ptr++;
+       unit_decl_ptr <= (decl_t *) VLA_PTR_LAST (unit_decls);
+       unit_decl_ptr++)
+    {
+      rest_units_num
+       = ((decl_t *) VLA_PTR_LAST (unit_decls) - unit_decl_ptr + 1);
+      if (automata_num - automaton_num - 1 > rest_units_num)
+       abort ();
+      if (automaton_num < automata_num - 1
+          && ((automata_num - automaton_num - 1 == rest_units_num)
+              || (bound_value
+                  > (estimation_bound
+                    / ((*unit_decl_ptr)->decl.unit.max_occ_cycle_num)))))
+        {
+          bound_value = (*unit_decl_ptr)->decl.unit.max_occ_cycle_num;
+          automaton_num++;
+        }
+      else
+        bound_value *= (*unit_decl_ptr)->decl.unit.max_occ_cycle_num;
+      (*unit_decl_ptr)->decl.unit.corresponding_automaton_num = automaton_num;
+    }
+  if (automaton_num != automata_num - 1)
+    abort ();
+  VLA_PTR_DELETE (unit_decls);
+}
+
+/* The functions creates automaton insns for each automata.  Automaton
+   insn is simply insn for given automaton which makes reservation
+   only of units of the automaton.  */
+static ainsn_t
+create_ainsns ()
+{
+  decl_t decl;
+  ainsn_t first_ainsn;
+  ainsn_t curr_ainsn;
+  ainsn_t prev_ainsn;
+  int i;
+
+  first_ainsn = NULL;
+  prev_ainsn = NULL;
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv)
+       {
+         curr_ainsn = create_node (sizeof (struct ainsn));
+         curr_ainsn->insn_reserv_decl = &decl->decl.insn_reserv;
+         curr_ainsn->next_ainsn = NULL;
+         if (prev_ainsn == NULL)
+           first_ainsn = curr_ainsn;
+         else
+           prev_ainsn->next_ainsn = curr_ainsn;
+         prev_ainsn = curr_ainsn;
+       }
+    }
+  return first_ainsn;
+}
+
+/* The function assigns automata to units according to constructions
+   `define_automaton' in the description.  */
+static void
+units_to_automata_distr ()
+{
+  decl_t decl;
+  int i;
+  
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit)
+       {
+         if (decl->decl.unit.automaton_decl == NULL
+             || (decl->decl.unit.automaton_decl->corresponding_automaton
+                 == NULL))
+           /* Distribute to the first automaton.  */
+           decl->decl.unit.corresponding_automaton_num = 0;
+         else
+           decl->decl.unit.corresponding_automaton_num
+             = (decl->decl.unit.automaton_decl
+                 ->corresponding_automaton->automaton_order_num);
+       }
+    }
+}
+
+/* The function creates DFA(s) for fast pipeline hazards recognition
+   after checking and simplifying IR of the description.  */
+static void
+create_automata ()
+{
+  automaton_t curr_automaton;
+  automaton_t prev_automaton;
+  decl_t decl;
+  int curr_automaton_num;
+  int i;
+
+  if (automata_num != 0)
+    {
+      units_to_automata_heuristic_distr ();
+      for (prev_automaton = NULL, curr_automaton_num = 0;
+           curr_automaton_num < automata_num;
+           curr_automaton_num++, prev_automaton = curr_automaton)
+        {
+         curr_automaton = create_node (sizeof (struct automaton));
+         curr_automaton->ainsn_list = create_ainsns ();
+         curr_automaton->corresponding_automaton_decl = NULL;
+         curr_automaton->next_automaton = NULL;
+          curr_automaton->automaton_order_num = curr_automaton_num;
+          if (prev_automaton == NULL)
+            description->first_automaton = curr_automaton;
+          else
+            prev_automaton->next_automaton = curr_automaton;
+        }
+    }
+  else
+    {
+      curr_automaton_num = 0;
+      prev_automaton = NULL;
+      for (i = 0; i < description->decls_num; i++)
+       {
+         decl = description->decls [i];
+         if (decl->mode == dm_automaton
+             && decl->decl.automaton.automaton_is_used)
+           {
+             curr_automaton = create_node (sizeof (struct automaton));
+             curr_automaton->ainsn_list = create_ainsns ();
+             curr_automaton->corresponding_automaton_decl
+               = &decl->decl.automaton;
+             curr_automaton->next_automaton = NULL;
+             decl->decl.automaton.corresponding_automaton = curr_automaton;
+             curr_automaton->automaton_order_num = curr_automaton_num;
+             if (prev_automaton == NULL)
+               description->first_automaton = curr_automaton;
+             else
+               prev_automaton->next_automaton = curr_automaton;
+             curr_automaton_num++;
+             prev_automaton = curr_automaton;
+           }
+       }
+      if (curr_automaton_num == 0)
+       {
+         curr_automaton = create_node (sizeof (struct automaton));
+         curr_automaton->ainsn_list = create_ainsns ();
+         curr_automaton->corresponding_automaton_decl = NULL;
+         curr_automaton->next_automaton = NULL;
+         description->first_automaton = curr_automaton;
+       }
+      units_to_automata_distr ();
+    }
+  NDFA_time = create_ticker ();
+  ticker_off (&NDFA_time);
+  NDFA_to_DFA_time = create_ticker ();
+  ticker_off (&NDFA_to_DFA_time);
+  minimize_time = create_ticker ();
+  ticker_off (&minimize_time);
+  equiv_time = create_ticker ();
+  ticker_off (&equiv_time);
+  for (curr_automaton = description->first_automaton;
+       curr_automaton != NULL;
+       curr_automaton = curr_automaton->next_automaton)
+    {
+      create_alt_states (curr_automaton);
+      form_ainsn_with_same_reservs (curr_automaton);
+      build_automaton (curr_automaton);
+      enumerate_states (curr_automaton);
+      ticker_on (&equiv_time);
+      set_insn_equiv_classes (curr_automaton);
+      ticker_off (&equiv_time);
+    }
+}
+
+\f
+
+/* This page contains code for forming string representation of
+   regexp.  The representation is formed on IR obstack.  So you should
+   not work with IR obstack between regexp_representation and
+   finish_regexp_representation calls.  */
+
+/* This recursive function forms string representation of regexp
+   (without tailing '\0').  */
+static void
+form_regexp (regexp)
+     regexp_t regexp;
+{
+  int i;
+    
+  if (regexp->mode == rm_unit || regexp->mode == rm_reserv)
+    {
+      const char *name = (regexp->mode == rm_unit
+                          ? regexp->regexp.unit.name
+                         : regexp->regexp.reserv.name);
+
+      obstack_grow (&irp, name, strlen (name));
+    }
+  else if (regexp->mode == rm_sequence)
+    for (i = 0; i < regexp->regexp.sequence.regexps_num; i++)
+      {
+       if (i != 0)
+          obstack_1grow (&irp, ',');
+       form_regexp (regexp->regexp.sequence.regexps [i]);
+      }
+  else if (regexp->mode == rm_allof)
+    {
+      obstack_1grow (&irp, '(');
+      for (i = 0; i < regexp->regexp.allof.regexps_num; i++)
+       {
+         if (i != 0)
+            obstack_1grow (&irp, '+');
+         if (regexp->regexp.allof.regexps[i]->mode == rm_sequence
+              || regexp->regexp.oneof.regexps[i]->mode == rm_oneof)
+            obstack_1grow (&irp, '(');
+         form_regexp (regexp->regexp.allof.regexps [i]);
+         if (regexp->regexp.allof.regexps[i]->mode == rm_sequence
+              || regexp->regexp.oneof.regexps[i]->mode == rm_oneof)
+            obstack_1grow (&irp, ')');
+        }
+      obstack_1grow (&irp, ')');
+    }
+  else if (regexp->mode == rm_oneof)
+    for (i = 0; i < regexp->regexp.oneof.regexps_num; i++)
+      {
+       if (i != 0)
+          obstack_1grow (&irp, '|');
+       if (regexp->regexp.oneof.regexps[i]->mode == rm_sequence)
+          obstack_1grow (&irp, '(');
+        form_regexp (regexp->regexp.oneof.regexps [i]);
+       if (regexp->regexp.oneof.regexps[i]->mode == rm_sequence)
+          obstack_1grow (&irp, ')');
+      }
+  else if (regexp->mode == rm_repeat)
+    {
+      char digits [30];
+
+      if (regexp->regexp.repeat.regexp->mode == rm_sequence
+         || regexp->regexp.repeat.regexp->mode == rm_allof
+         || regexp->regexp.repeat.regexp->mode == rm_oneof)
+        obstack_1grow (&irp, '(');
+      form_regexp (regexp->regexp.repeat.regexp);
+      if (regexp->regexp.repeat.regexp->mode == rm_sequence
+         || regexp->regexp.repeat.regexp->mode == rm_allof
+         || regexp->regexp.repeat.regexp->mode == rm_oneof)
+        obstack_1grow (&irp, ')');
+      sprintf (digits, "*%d", regexp->regexp.repeat.repeat_num);
+      obstack_grow (&irp, digits, strlen (digits));
+    }
+  else if (regexp->mode == rm_nothing)
+    obstack_grow (&irp, NOTHING_NAME, strlen (NOTHING_NAME));
+  else
+    abort ();
+}
+
+/* The function returns string representation of REGEXP on IR
+   obstack.  */
+static const char *
+regexp_representation (regexp)
+     regexp_t regexp;
+{
+  form_regexp (regexp);
+  obstack_1grow (&irp, '\0');
+  return obstack_base (&irp);
+}
+
+/* The function frees memory allocated for last formed string
+   representation of regexp.  */
+static void
+finish_regexp_representation ()
+{
+  int length = obstack_object_size (&irp);
+  
+  obstack_blank_fast (&irp, -length);
+}
+
+\f
+
+/* This page contains code for output PHR (pipeline hazards recognizer).  */
+
+/* The function outputs minimal C type which is sufficient for
+   representation numbers in range min_range_value and
+   max_range_value.  Because host machine and build machine may be
+   different, we use here minimal values required by ANSI C standard
+   instead of UCHAR_MAX, SHRT_MAX, SHRT_MIN, etc.  This is a good
+   approximation.  */
+
+static void
+output_range_type (f, min_range_value, max_range_value)
+     FILE *f;
+     long int min_range_value;
+     long int max_range_value;
+{
+  if (min_range_value >= 0 && max_range_value <= 255)
+    fprintf (f, "unsigned char");
+  else if (min_range_value >= -127 && max_range_value <= 127)
+    fprintf (f, "signed char");
+  else if (min_range_value >= 0 && max_range_value <= 65535)
+    fprintf (f, "unsigned short");
+  else if (min_range_value >= -32767 && max_range_value <= 32767)
+    fprintf (f, "short");
+  else
+    fprintf (f, "int");
+}
+
+/* The following macro value is used as value of member
+   `longest_path_length' of state when we are processing path and the
+   state on the path.  */
+
+#define ON_THE_PATH -2
+
+/* The following recursive function searches for the length of the
+   longest path starting from STATE which does not contain cycles and
+   `cycle advance' arcs.  */
+
+static int
+longest_path_length (state)
+     state_t state;
+{
+  arc_t arc;
+  int length, result;
+  
+  if (state->longest_path_length == ON_THE_PATH)
+    /* We don't expect the path cycle here.  Our graph may contain
+       only cycles with one state on the path not containing `cycle
+       advance' arcs -- see comment below.  */
+    abort ();
+  else if (state->longest_path_length != UNDEFINED_LONGEST_PATH_LENGTH)
+    /* We alreday visited the state.  */
+    return state->longest_path_length;
+
+  result = 0;
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    /* Ignore cycles containing one state and `cycle advance' arcs. */
+    if (arc->to_state != state
+       && (arc->insn->insn_reserv_decl
+           != &advance_cycle_insn_decl->decl.insn_reserv))
+    {
+      length = longest_path_length (arc->to_state);
+      if (length > result)
+       result = length;
+    }
+  state->longest_path_length = result + 1;
+  return result;
+}
+
+/* The following variable value is value of the corresponding global
+   variable in the automaton based pipeline interface.  */
+
+static int max_dfa_issue_rate;
+
+/* The following function processes the longest path length staring
+   from STATE to find MAX_DFA_ISSUE_RATE. */
+
+static void
+process_state_longest_path_length (state)
+     state_t state;
+{
+  int value;
+
+  value = longest_path_length (state);
+  if (value > max_dfa_issue_rate)
+    max_dfa_issue_rate = value;
+}
+
+/* The following nacro value is name of the corresponding global
+   variable in the automaton based pipeline interface.  */
+
+#define MAX_DFA_ISSUE_RATE_VAR_NAME "max_dfa_issue_rate"
+
+/* The following function calculates value of the the corresponding
+   global variable and outputs its declaration.  */
+
+static void
+output_dfa_max_issue_rate (void)
+{
+  automaton_t automaton;
+
+  if (UNDEFINED_LONGEST_PATH_LENGTH == ON_THE_PATH || ON_THE_PATH >= 0)
+    abort ();
+  max_dfa_issue_rate = 0;
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    pass_states (automaton, process_state_longest_path_length);
+  fprintf (output_file, "\nint %s = %d;\n",
+          MAX_DFA_ISSUE_RATE_VAR_NAME, max_dfa_issue_rate);
+}
+
+/* The function outputs all initialization values of VECT with length
+   vect_length.  */
+static void
+output_vect (vect, vect_length)
+     vect_el_t *vect;
+     int vect_length;
+{
+  int els_on_line;
+
+  els_on_line = 1;
+  if (vect_length == 0)
+    fprintf (output_file,
+             "0 /* This is dummy el because the vect is empty */");
+  else
+    {
+      do
+        {
+          fprintf (output_file, "%5ld", (long) *vect);
+          vect_length--;
+          if (els_on_line == 10)
+           {
+             els_on_line = 0;
+             fprintf (output_file, ",\n");
+           }
+          else if (vect_length != 0)
+            fprintf (output_file, ", ");
+          els_on_line++;
+          vect++;
+        }
+      while (vect_length != 0);
+    }
+}
+
+/* The following is name of the structure which represents DFA(s) for
+   PHR.  */
+#define CHIP_NAME "DFA_chip"
+
+/* The following is name of member which represents state of a DFA for
+   PHR.  */
+static void
+output_chip_member_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "automaton_state_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_automaton_state",
+             automaton->corresponding_automaton_decl->name);
+}
+
+/* The following is name of temporary variable which stores state of a
+   DFA for PHR.  */
+static void
+output_temp_chip_member_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  fprintf (f, "_");
+  output_chip_member_name (f, automaton);
+}
+
+/* This is name of macro value which is code of pseudo_insn
+   representing advancing cpu cycle.  Its value is used as internal
+   code unknown insn.  */
+#define ADVANCE_CYCLE_VALUE_NAME "DFA__ADVANCE_CYCLE"
+
+/* Output name of translate vector for given automaton.  */
+static void
+output_translate_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "translate_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_translate", automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name for simple transition table representation.  */
+static void
+output_trans_full_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "transitions_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_transitions",
+            automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of comb vector of the transition table for given
+   automaton.  */
+static void
+output_trans_comb_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "transitions_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_transitions",
+             automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of check vector of the transition table for given
+   automaton.  */
+static void
+output_trans_check_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "check_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_check", automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of base vector of the transition table for given
+   automaton.  */
+static void
+output_trans_base_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "base_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_base", automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name for simple alternatives number representation.  */
+static void
+output_state_alts_full_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "state_alts_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_state_alts",
+             automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of comb vector of the alternatives number table for given
+   automaton.  */
+static void
+output_state_alts_comb_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "state_alts_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_state_alts",
+             automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of check vector of the alternatives number table for given
+   automaton.  */
+static void
+output_state_alts_check_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "check_state_alts_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_check_state_alts",
+            automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of base vector of the alternatives number table for given
+   automaton.  */
+static void
+output_state_alts_base_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "base_state_alts_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_base_state_alts",
+            automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of simple min issue delay table representation.  */
+static void
+output_min_issue_delay_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "min_issue_delay_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_min_issue_delay",
+             automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of deadlock vector for given automaton.  */
+static void
+output_dead_lock_vect_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "dead_lock_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_dead_lock", automaton->corresponding_automaton_decl->name);
+}
+
+/* Output name of reserved units table for AUTOMATON into file F.  */
+static void
+output_reserved_units_table_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "reserved_units_%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "%s_reserved_units",
+            automaton->corresponding_automaton_decl->name);
+}
+
+/* Name of the PHR interface macro.  */
+#define AUTOMATON_STATE_ALTS_MACRO_NAME "AUTOMATON_STATE_ALTS"
+
+/* Name of the PHR interface macro.  */
+#define CPU_UNITS_QUERY_MACRO_NAME "CPU_UNITS_QUERY"
+
+/* Names of an internal functions: */
+#define INTERNAL_MIN_ISSUE_DELAY_FUNC_NAME "internal_min_issue_delay"
+
+/* This is external type of DFA(s) state.  */
+#define STATE_TYPE_NAME "state_t"
+
+#define INTERNAL_TRANSITION_FUNC_NAME "internal_state_transition"
+
+#define INTERNAL_STATE_ALTS_FUNC_NAME "internal_state_alts"
+
+#define INTERNAL_RESET_FUNC_NAME "internal_reset"
+
+#define INTERNAL_DEAD_LOCK_FUNC_NAME "internal_state_dead_lock_p"
+
+#define INTERNAL_INSN_LATENCY_FUNC_NAME "internal_insn_latency"
+
+/* Name of cache of insn dfa codes.  */
+#define DFA_INSN_CODES_VARIABLE_NAME "dfa_insn_codes"
+
+/* Names of the PHR interface functions: */
+#define SIZE_FUNC_NAME "state_size"
+
+#define TRANSITION_FUNC_NAME "state_transition"
+
+#define STATE_ALTS_FUNC_NAME "state_alts"
+
+#define MIN_ISSUE_DELAY_FUNC_NAME "min_issue_delay"
+
+#define MIN_INSN_CONFLICT_DELAY_FUNC_NAME "min_insn_conflict_delay"
+
+#define DEAD_LOCK_FUNC_NAME "state_dead_lock_p"
+
+#define RESET_FUNC_NAME "state_reset"
+
+#define INSN_LATENCY_FUNC_NAME "insn_latency"
+
+#define PRINT_RESERVATION_FUNC_NAME "print_reservation"
+
+#define GET_CPU_UNIT_CODE_FUNC_NAME "get_cpu_unit_code"
+
+#define CPU_UNIT_RESERVATION_P_FUNC_NAME "cpu_unit_reservation_p"
+
+#define DFA_START_FUNC_NAME  "dfa_start"
+
+#define DFA_FINISH_FUNC_NAME "dfa_finish"
+
+/* Names of parameters of the PHR interface functions.  */
+#define STATE_NAME "state"
+
+#define INSN_PARAMETER_NAME "insn"
+
+#define INSN2_PARAMETER_NAME "insn2"
+
+#define CHIP_PARAMETER_NAME "chip"
+
+#define FILE_PARAMETER_NAME "f"
+
+#define CPU_UNIT_NAME_PARAMETER_NAME "cpu_unit_name"
+
+#define CPU_CODE_PARAMETER_NAME "cpu_unit_code"
+
+/* Names of the variables whose values are internal insn code of rtx
+   insn.  */
+#define INTERNAL_INSN_CODE_NAME "insn_code"
+
+#define INTERNAL_INSN2_CODE_NAME "insn2_code"
+
+/* Names of temporary variables in some functions.  */
+#define TEMPORARY_VARIABLE_NAME "temp"
+
+#define I_VARIABLE_NAME "i"
+
+/* Name of result variable in some functions.  */
+#define RESULT_VARIABLE_NAME "res"
+
+/* Name of function (attribute) to translate insn into number of insn
+   alternatives reservation.  */
+#define INSN_ALTS_FUNC_NAME "insn_alts"
+
+/* Name of function (attribute) to translate insn into internal insn
+   code.  */
+#define INTERNAL_DFA_INSN_CODE_FUNC_NAME "internal_dfa_insn_code"
+
+/* Name of function (attribute) to translate insn into internal insn
+   code with caching.  */
+#define DFA_INSN_CODE_FUNC_NAME "dfa_insn_code"
+
+/* Name of function (attribute) to translate insn into internal insn
+   code.  */
+#define INSN_DEFAULT_LATENCY_FUNC_NAME "insn_default_latency"
+
+/* Name of function (attribute) to translate insn into internal insn
+   code.  */
+#define BYPASS_P_FUNC_NAME "bypass_p"
+
+/* Output C type which is used for representation of codes of states
+   of AUTOMATON.  */
+static void
+output_state_member_type (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  output_range_type (f, 0, automaton->achieved_states_num);
+}
+
+/* Output definition of the structure representing current DFA(s)
+   state(s).  */
+static void
+output_chip_definitions ()
+{
+  automaton_t automaton;
+
+  fprintf (output_file, "struct %s\n{\n", CHIP_NAME);
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    {
+      fprintf (output_file, "  ");
+      output_state_member_type (output_file, automaton);
+      fprintf (output_file, " ");
+      output_chip_member_name (output_file, automaton);
+      fprintf (output_file, ";\n");
+    }
+  fprintf (output_file, "};\n\n");
+#if 0
+  fprintf (output_file, "static struct %s %s;\n\n", CHIP_NAME, CHIP_NAME);
+#endif
+}
+
+
+/* The function outputs translate vector of internal insn code into
+   insn equivalence class number.  The equivalence class number is
+   used to access to table and vectors reprewsenting DFA(s).  */
+static void
+output_translate_vect (automaton)
+     automaton_t automaton;
+{
+  ainsn_t ainsn;
+  int insn_value;
+  vla_hwint_t translate_vect;
+
+  VLA_HWINT_CREATE (translate_vect, 250, "translate vector");
+  VLA_HWINT_EXPAND (translate_vect, description->insns_num);
+  for (insn_value = 0; insn_value <= description->insns_num; insn_value++)
+    /* Undefined value */
+    VLA_HWINT (translate_vect, insn_value) = automaton->insn_equiv_classes_num;
+  for (ainsn = automaton->ainsn_list; ainsn != NULL; ainsn = ainsn->next_ainsn)
+    VLA_HWINT (translate_vect, ainsn->insn_reserv_decl->insn_num)
+      = ainsn->insn_equiv_class_num;
+  fprintf (output_file,
+           "/* Vector translating external insn codes to internal ones.*/\n");
+  fprintf (output_file, "static const ");
+  output_range_type (output_file, 0, automaton->insn_equiv_classes_num);
+  fprintf (output_file, " ");
+  output_translate_vect_name (output_file, automaton);
+  fprintf (output_file, "[] = {\n");
+  output_vect (VLA_HWINT_BEGIN (translate_vect),
+              VLA_HWINT_LENGTH (translate_vect));
+  fprintf (output_file, "};\n\n");
+  VLA_HWINT_DELETE (translate_vect);
+}
+
+/* The value in a table state x ainsn -> something which represents
+   undefined value.  */
+static int undefined_vect_el_value;
+
+/* The following function returns nonzero value if the best
+   representation of the table is comb vector.  */
+static int
+comb_vect_p (tab)
+     state_ainsn_table_t tab;
+{
+  return  (2 * VLA_HWINT_LENGTH (tab->full_vect)
+           > 5 * VLA_HWINT_LENGTH (tab->comb_vect));
+}
+
+/* The following function creates new table for AUTOMATON.  */
+static state_ainsn_table_t
+create_state_ainsn_table (automaton)
+     automaton_t automaton;
+{
+  state_ainsn_table_t tab;
+  int full_vect_length;
+  int i;
+
+  tab = create_node (sizeof (struct state_ainsn_table));
+  tab->automaton = automaton;
+  VLA_HWINT_CREATE (tab->comb_vect, 10000, "comb vector");
+  VLA_HWINT_CREATE (tab->check_vect, 10000, "check vector");
+  VLA_HWINT_CREATE (tab->base_vect, 1000, "base vector");
+  VLA_HWINT_EXPAND (tab->base_vect, automaton->achieved_states_num);
+  VLA_HWINT_CREATE (tab->full_vect, 10000, "full vector");
+  full_vect_length = (automaton->insn_equiv_classes_num
+                      * automaton->achieved_states_num);
+  VLA_HWINT_EXPAND (tab->full_vect, full_vect_length);
+  for (i = 0; i < full_vect_length; i++)
+    VLA_HWINT (tab->full_vect, i) = undefined_vect_el_value;
+  tab->min_base_vect_el_value = 0;
+  tab->max_base_vect_el_value = 0;
+  tab->min_comb_vect_el_value = 0;
+  tab->max_comb_vect_el_value = 0;
+  return tab;
+}
+
+/* The following function outputs the best C representation of the
+   table TAB of given TABLE_NAME.  */
+static void
+output_state_ainsn_table (tab, table_name, output_full_vect_name_func,
+                          output_comb_vect_name_func,
+                          output_check_vect_name_func,
+                          output_base_vect_name_func)
+     state_ainsn_table_t tab;
+     char *table_name;
+     void (*output_full_vect_name_func) PARAMS ((FILE *, automaton_t));
+     void (*output_comb_vect_name_func) PARAMS ((FILE *, automaton_t));
+     void (*output_check_vect_name_func) PARAMS ((FILE *, automaton_t));
+     void (*output_base_vect_name_func) PARAMS ((FILE *, automaton_t));
+{
+  if (!comb_vect_p (tab))
+    {
+      fprintf (output_file, "/* Vector for %s.  */\n", table_name);
+      fprintf (output_file, "static const ");
+      output_range_type (output_file, tab->min_comb_vect_el_value,
+                         tab->max_comb_vect_el_value);
+      fprintf (output_file, " ");
+      (*output_full_vect_name_func) (output_file, tab->automaton);
+      fprintf (output_file, "[] = {\n");
+      output_vect (VLA_HWINT_BEGIN (tab->full_vect),
+                   VLA_HWINT_LENGTH (tab->full_vect));
+      fprintf (output_file, "};\n\n");
+    }
+  else
+    {
+      fprintf (output_file, "/* Comb vector for %s.  */\n", table_name);
+      fprintf (output_file, "static const ");
+      output_range_type (output_file, tab->min_comb_vect_el_value,
+                         tab->max_comb_vect_el_value);
+      fprintf (output_file, " ");
+      (*output_comb_vect_name_func) (output_file, tab->automaton);
+      fprintf (output_file, "[] = {\n");
+      output_vect (VLA_HWINT_BEGIN (tab->comb_vect),
+                   VLA_HWINT_LENGTH (tab->comb_vect));
+      fprintf (output_file, "};\n\n");
+      fprintf (output_file, "/* Check vector for %s.  */\n", table_name);
+      fprintf (output_file, "static const ");
+      output_range_type (output_file, 0, tab->automaton->achieved_states_num);
+      fprintf (output_file, " ");
+      (*output_check_vect_name_func) (output_file, tab->automaton);
+      fprintf (output_file, "[] = {\n");
+      output_vect (VLA_HWINT_BEGIN (tab->check_vect),
+                   VLA_HWINT_LENGTH (tab->check_vect));
+      fprintf (output_file, "};\n\n");
+      fprintf (output_file, "/* Base vector for %s.  */\n", table_name);
+      fprintf (output_file, "static const ");
+      output_range_type (output_file, tab->min_base_vect_el_value,
+                         tab->max_base_vect_el_value);
+      fprintf (output_file, " ");
+      (*output_base_vect_name_func) (output_file, tab->automaton);
+      fprintf (output_file, "[] = {\n");
+      output_vect (VLA_HWINT_BEGIN (tab->base_vect),
+                   VLA_HWINT_LENGTH (tab->base_vect));
+      fprintf (output_file, "};\n\n");
+    }
+}
+
+/* The following function adds vector with length VECT_LENGTH and
+   elements pointed by VECT to table TAB as its line with number
+   VECT_NUM.  */
+static void
+add_vect (tab, vect_num, vect, vect_length)
+     state_ainsn_table_t tab;
+     int vect_num;
+     vect_el_t *vect;
+     int vect_length;
+{
+  int real_vect_length;
+  vect_el_t *comb_vect_start;
+  vect_el_t *check_vect_start;
+  int comb_vect_index;
+  int comb_vect_els_num;
+  int vect_index;
+  int first_unempty_vect_index;
+  int additional_els_num;
+  int no_state_value;
+  vect_el_t vect_el;
+  int i;
+
+  if (vect_length == 0)
+    abort ();
+  real_vect_length = tab->automaton->insn_equiv_classes_num;
+  if (vect [vect_length - 1] == undefined_vect_el_value)
+    abort ();
+  /* Form full vector in the table: */
+  for (i = 0; i < vect_length; i++)
+    VLA_HWINT (tab->full_vect,
+               i + tab->automaton->insn_equiv_classes_num * vect_num)
+      = vect [i];
+  /* Form comb vector in the table: */
+  if (VLA_HWINT_LENGTH (tab->comb_vect) != VLA_HWINT_LENGTH (tab->check_vect))
+    abort ();
+  comb_vect_start = VLA_HWINT_BEGIN (tab->comb_vect);
+  comb_vect_els_num = VLA_HWINT_LENGTH (tab->comb_vect);
+  for (first_unempty_vect_index = 0;
+       first_unempty_vect_index < vect_length;
+       first_unempty_vect_index++)
+    if (vect [first_unempty_vect_index] != undefined_vect_el_value)
+      break;
+  /* Search for the place in comb vect for the inserted vect.  */
+  for (comb_vect_index = 0;
+       comb_vect_index < comb_vect_els_num;
+       comb_vect_index++)
+    {
+      for (vect_index = first_unempty_vect_index;
+           vect_index < vect_length
+             && vect_index + comb_vect_index < comb_vect_els_num;
+           vect_index++)
+        if (vect [vect_index] != undefined_vect_el_value
+            && (comb_vect_start [vect_index + comb_vect_index]
+               != undefined_vect_el_value))
+          break;
+      if (vect_index >= vect_length
+          || vect_index + comb_vect_index >= comb_vect_els_num)
+        break;
+    }
+  /* Slot was found.  */
+  additional_els_num = comb_vect_index + real_vect_length - comb_vect_els_num;
+  if (additional_els_num < 0)
+    additional_els_num = 0;
+  /* Expand comb and check vectors.  */
+  vect_el = undefined_vect_el_value;
+  no_state_value = tab->automaton->achieved_states_num;
+  while (additional_els_num > 0)
+    {
+      VLA_HWINT_ADD (tab->comb_vect, vect_el);
+      VLA_HWINT_ADD (tab->check_vect, no_state_value);
+      additional_els_num--;
+    }
+  comb_vect_start = VLA_HWINT_BEGIN (tab->comb_vect);
+  check_vect_start = VLA_HWINT_BEGIN (tab->check_vect);
+  if (VLA_HWINT_LENGTH (tab->comb_vect)
+      < (size_t) (comb_vect_index + real_vect_length))
+    abort ();
+  /* Fill comb and check vectors.  */
+  for (vect_index = 0; vect_index < vect_length; vect_index++)
+    if (vect [vect_index] != undefined_vect_el_value)
+      {
+        if (comb_vect_start [comb_vect_index + vect_index]
+           != undefined_vect_el_value)
+         abort ();
+        comb_vect_start [comb_vect_index + vect_index] = vect [vect_index];
+        if (vect [vect_index] < 0)
+         abort ();
+        if (tab->max_comb_vect_el_value < vect [vect_index])
+          tab->max_comb_vect_el_value = vect [vect_index];
+        if (tab->min_comb_vect_el_value > vect [vect_index])
+          tab->min_comb_vect_el_value = vect [vect_index];
+        check_vect_start [comb_vect_index + vect_index] = vect_num;
+      }
+  if (tab->max_base_vect_el_value < comb_vect_index)
+    tab->max_base_vect_el_value = comb_vect_index;
+  if (tab->min_base_vect_el_value > comb_vect_index)
+    tab->min_base_vect_el_value = comb_vect_index;
+  VLA_HWINT (tab->base_vect, vect_num) = comb_vect_index;
+}
+
+/* Return number of out arcs of STATE.  */
+static int
+out_state_arcs_num (state)
+     state_t state;
+{
+  int result;
+  arc_t arc;
+
+  result = 0;
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    {
+      if (arc->insn == NULL)
+       abort ();
+      if (arc->insn->first_ainsn_with_given_equialence_num)
+        result++;
+    }
+  return result;
+}
+
+/* Compare number of possible transitions from the states.  */
+static int
+compare_transition_els_num (state_ptr_1, state_ptr_2)
+     const void *state_ptr_1;
+     const void *state_ptr_2;
+{
+  int transition_els_num_1;
+  int transition_els_num_2;
+
+  transition_els_num_1 = out_state_arcs_num (*(state_t *) state_ptr_1);
+  transition_els_num_2 = out_state_arcs_num (*(state_t *) state_ptr_2);
+  if (transition_els_num_1 < transition_els_num_2)
+    return 1;
+  else if (transition_els_num_1 == transition_els_num_2)
+    return 0;
+  else
+    return -1;
+}
+
+/* The function adds element EL_VALUE to vector VECT for a table state
+   x AINSN.  */
+static void
+add_vect_el (vect, ainsn, el_value)
+     vla_hwint_t *vect;
+     ainsn_t ainsn;
+     int el_value;
+{
+  int equiv_class_num;
+  int vect_index;
+
+  if (ainsn == NULL)
+    abort ();
+  equiv_class_num = ainsn->insn_equiv_class_num;
+  for (vect_index = VLA_HWINT_LENGTH (*vect);
+       vect_index <= equiv_class_num;
+       vect_index++)
+    VLA_HWINT_ADD (*vect, undefined_vect_el_value);
+  VLA_HWINT (*vect, equiv_class_num) = el_value;
+}
+
+/* This is for forming vector of states of an automaton.  */
+static vla_ptr_t output_states_vect;
+
+/* The function is called by function pass_states.  The function adds
+   STATE to `output_states_vect'.  */
+static void
+add_states_vect_el (state)
+     state_t state;
+{
+  VLA_PTR_ADD (output_states_vect, state);
+}
+
+/* Form and output vectors (comb, check, base or full vector)
+   representing transition table of AUTOMATON.  */
+static void
+output_trans_table (automaton)
+     automaton_t automaton;
+{
+  state_t *state_ptr;
+  arc_t arc;
+  vla_hwint_t transition_vect;
+
+  undefined_vect_el_value = automaton->achieved_states_num;
+  automaton->trans_table = create_state_ainsn_table (automaton);
+  /* Create vect of pointers to states ordered by num of transitions
+     from the state (state with the maximum num is the first).  */
+  VLA_PTR_CREATE (output_states_vect, 1500, "output states vector");
+  pass_states (automaton, add_states_vect_el);
+  qsort (VLA_PTR_BEGIN (output_states_vect),
+         VLA_PTR_LENGTH (output_states_vect),
+         sizeof (state_t), compare_transition_els_num);
+  VLA_HWINT_CREATE (transition_vect, 500, "transition vector");
+  for (state_ptr = VLA_PTR_BEGIN (output_states_vect);
+       state_ptr <= (state_t *) VLA_PTR_LAST (output_states_vect);
+       state_ptr++)
+    {
+      VLA_HWINT_NULLIFY (transition_vect);
+      for (arc = first_out_arc (*state_ptr);
+          arc != NULL;
+          arc = next_out_arc (arc))
+        {
+          if (arc->insn == NULL)
+           abort ();
+          if (arc->insn->first_ainsn_with_given_equialence_num)
+            add_vect_el (&transition_vect, arc->insn,
+                         arc->to_state->order_state_num);
+        }
+      add_vect (automaton->trans_table, (*state_ptr)->order_state_num,
+                VLA_HWINT_BEGIN (transition_vect),
+                VLA_HWINT_LENGTH (transition_vect));
+    }
+  output_state_ainsn_table
+    (automaton->trans_table, (char *) "state transitions",
+     output_trans_full_vect_name, output_trans_comb_vect_name,
+     output_trans_check_vect_name, output_trans_base_vect_name);
+  VLA_PTR_DELETE (output_states_vect);
+  VLA_HWINT_DELETE (transition_vect);
+}
+
+/* Form and output vectors (comb, check, base or simple vect)
+   representing alts number table of AUTOMATON.  The table is state x
+   ainsn -> number of possible alternative reservations by the
+   ainsn.  */
+static void
+output_state_alts_table (automaton)
+     automaton_t automaton;
+{
+  state_t *state_ptr;
+  arc_t arc;
+  vla_hwint_t state_alts_vect;
+
+  undefined_vect_el_value = 0; /* no alts when transition is not possible */
+  automaton->state_alts_table = create_state_ainsn_table (automaton);
+  /* Create vect of pointers to states ordered by num of transitions
+     from the state (state with the maximum num is the first).  */
+  VLA_PTR_CREATE (output_states_vect, 1500, "output states vector");
+  pass_states (automaton, add_states_vect_el);
+  qsort (VLA_PTR_BEGIN (output_states_vect),
+         VLA_PTR_LENGTH (output_states_vect),
+         sizeof (state_t), compare_transition_els_num);
+  /* Create base, comb, and check vectors.  */
+  VLA_HWINT_CREATE (state_alts_vect, 500, "state alts vector");
+  for (state_ptr = VLA_PTR_BEGIN (output_states_vect);
+       state_ptr <= (state_t *) VLA_PTR_LAST (output_states_vect);
+       state_ptr++)
+    {
+      VLA_HWINT_NULLIFY (state_alts_vect);
+      for (arc = first_out_arc (*state_ptr);
+          arc != NULL;
+          arc = next_out_arc (arc))
+        {
+          if (arc->insn == NULL)
+           abort ();
+          if (arc->insn->first_ainsn_with_given_equialence_num)
+            add_vect_el (&state_alts_vect, arc->insn, arc->state_alts);
+        }
+      add_vect (automaton->state_alts_table, (*state_ptr)->order_state_num,
+                VLA_HWINT_BEGIN (state_alts_vect),
+                VLA_HWINT_LENGTH (state_alts_vect));
+    }
+  output_state_ainsn_table
+    (automaton->state_alts_table, (char *) "state insn alternatives",
+     output_state_alts_full_vect_name, output_state_alts_comb_vect_name,
+     output_state_alts_check_vect_name, output_state_alts_base_vect_name);
+  VLA_PTR_DELETE (output_states_vect);
+  VLA_HWINT_DELETE (state_alts_vect);
+}
+
+/* The current number of passing states to find minimal issue delay
+   value for an ainsn and state.  */
+static int curr_state_pass_num;
+
+
+/* This recursive function passes states to find minimal issue delay
+   value for AINSN.  The state being visited is STATE.  */
+static void
+min_issue_delay_pass_states (state, ainsn)
+     state_t state;
+     ainsn_t ainsn;
+{
+  arc_t arc;
+  int min_insn_issue_delay, insn_issue_delay;
+
+  if (state->state_pass_num == curr_state_pass_num)
+    return;
+  state->state_pass_num = curr_state_pass_num;
+  min_insn_issue_delay = state->min_insn_issue_delay = -1;
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    if (arc->insn == ainsn)
+      {
+       min_insn_issue_delay = 0;
+       break;
+      }
+    else
+      {
+        min_issue_delay_pass_states (arc->to_state, ainsn);
+       if (arc->to_state->min_insn_issue_delay != -1)
+         {
+           insn_issue_delay
+             = (arc->to_state->min_insn_issue_delay
+                + (arc->insn->insn_reserv_decl
+                   == &advance_cycle_insn_decl->decl.insn_reserv ? 1 : 0));
+           if (min_insn_issue_delay == -1
+               || min_insn_issue_delay > insn_issue_delay)
+             min_insn_issue_delay = insn_issue_delay;
+         }
+      }
+  state->min_insn_issue_delay = min_insn_issue_delay;
+}
+
+/* The function searches minimal issue delay value for AINSN in STATE.
+   The function can return negative can not issue AINSN.  We will
+   report about it later.  */
+static int
+min_issue_delay (state, ainsn)
+     state_t state;
+     ainsn_t ainsn;
+{
+  curr_state_pass_num++;
+  min_issue_delay_pass_states (state, ainsn);
+  return state->min_insn_issue_delay;
+}
+
+/* The function initiates code for finding minimal issue delay values.
+   It should be called only once.  */
+static void
+initiate_min_issue_delay_pass_states ()
+{
+  curr_state_pass_num = 0;
+}
+
+/* Form and output vectors representing minimal issue delay table of
+   AUTOMATON.  The table is state x ainsn -> minimal issue delay of
+   the ainsn.  */
+static void
+output_min_issue_delay_table (automaton)
+     automaton_t automaton;
+{
+  vla_hwint_t min_issue_delay_vect;
+  vla_hwint_t compressed_min_issue_delay_vect;
+  vect_el_t min_delay;
+  ainsn_t ainsn;
+  state_t *state_ptr;
+  int i;
+
+  /* Create vect of pointers to states ordered by num of transitions
+     from the state (state with the maximum num is the first).  */
+  VLA_PTR_CREATE (output_states_vect, 1500, "output states vector");
+  pass_states (automaton, add_states_vect_el);
+  VLA_HWINT_CREATE (min_issue_delay_vect, 1500, "min issue delay vector");
+  VLA_HWINT_EXPAND (min_issue_delay_vect,
+                   VLA_HWINT_LENGTH (output_states_vect)
+                   * automaton->insn_equiv_classes_num);
+  for (i = 0;
+       i < ((int) VLA_HWINT_LENGTH (output_states_vect)
+           * automaton->insn_equiv_classes_num);
+       i++)
+    VLA_HWINT (min_issue_delay_vect, i) = 0;
+  automaton->max_min_delay = 0;
+  for (state_ptr = VLA_PTR_BEGIN (output_states_vect);
+       state_ptr <= (state_t *) VLA_PTR_LAST (output_states_vect);
+       state_ptr++)
+    {
+      for (ainsn = automaton->ainsn_list;
+          ainsn != NULL;
+          ainsn = ainsn->next_ainsn)
+        if (ainsn->first_ainsn_with_given_equialence_num)
+          {
+            min_delay = min_issue_delay (*state_ptr, ainsn);
+           if (automaton->max_min_delay < min_delay)
+             automaton->max_min_delay = min_delay;
+           VLA_HWINT (min_issue_delay_vect,
+                      (*state_ptr)->order_state_num
+                      * automaton->insn_equiv_classes_num
+                      + ainsn->insn_equiv_class_num) = min_delay;
+         }
+    }
+  fprintf (output_file, "/* Vector of min issue delay of insns.*/\n");
+  fprintf (output_file, "static const ");
+  output_range_type (output_file, 0, automaton->max_min_delay);
+  fprintf (output_file, " ");
+  output_min_issue_delay_vect_name (output_file, automaton);
+  fprintf (output_file, "[] = {\n");
+  /* Compress the vector */
+  if (automaton->max_min_delay < 2)
+    automaton->min_issue_delay_table_compression_factor = 8;
+  else if (automaton->max_min_delay < 4)
+    automaton->min_issue_delay_table_compression_factor = 4;
+  else if (automaton->max_min_delay < 16)
+    automaton->min_issue_delay_table_compression_factor = 2;
+  else
+    automaton->min_issue_delay_table_compression_factor = 1;
+  VLA_HWINT_CREATE (compressed_min_issue_delay_vect, 1500,
+                   "compressed min issue delay vector");
+  VLA_HWINT_EXPAND (compressed_min_issue_delay_vect,
+                   (VLA_HWINT_LENGTH (min_issue_delay_vect)
+                    + automaton->min_issue_delay_table_compression_factor
+                    - 1)
+                   / automaton->min_issue_delay_table_compression_factor);
+  for (i = 0;
+       i < (int) VLA_HWINT_LENGTH (compressed_min_issue_delay_vect);
+       i++)
+    VLA_HWINT (compressed_min_issue_delay_vect, i) = 0;
+  for (i = 0; i < (int) VLA_HWINT_LENGTH (min_issue_delay_vect); i++)
+    VLA_HWINT (compressed_min_issue_delay_vect,
+              i / automaton->min_issue_delay_table_compression_factor)
+      |= (VLA_HWINT (min_issue_delay_vect, i)
+         << (8 - (i % automaton->min_issue_delay_table_compression_factor
+                  + 1)
+             * (8 / automaton->min_issue_delay_table_compression_factor)));
+  output_vect (VLA_HWINT_BEGIN (compressed_min_issue_delay_vect),
+               VLA_HWINT_LENGTH (compressed_min_issue_delay_vect));
+  fprintf (output_file, "};\n\n");
+  VLA_PTR_DELETE (output_states_vect);
+  VLA_HWINT_DELETE (min_issue_delay_vect);
+  VLA_HWINT_DELETE (compressed_min_issue_delay_vect);
+}
+
+#ifndef NDEBUG
+/* Number of states which contains transition only by advancing cpu
+   cycle.  */
+static int locked_states_num;
+#endif
+
+/* Form and output vector representing the locked states of
+   AUTOMATON.  */
+static void
+output_dead_lock_vect (automaton)
+     automaton_t automaton;
+{
+  state_t *state_ptr;
+  arc_t arc;
+  vla_hwint_t dead_lock_vect;
+
+  /* Create vect of pointers to states ordered by num of
+     transitions from the state (state with the maximum num is the
+     first).  */
+  VLA_PTR_CREATE (output_states_vect, 1500, "output states vector");
+  pass_states (automaton, add_states_vect_el);
+  VLA_HWINT_CREATE (dead_lock_vect, 1500, "is dead locked vector");
+  VLA_HWINT_EXPAND (dead_lock_vect, VLA_HWINT_LENGTH (output_states_vect));
+  for (state_ptr = VLA_PTR_BEGIN (output_states_vect);
+       state_ptr <= (state_t *) VLA_PTR_LAST (output_states_vect);
+       state_ptr++)
+    {
+      arc = first_out_arc (*state_ptr);
+      if (arc == NULL)
+       abort ();
+      VLA_HWINT (dead_lock_vect, (*state_ptr)->order_state_num)
+        = (next_out_arc (arc) == NULL
+           && (arc->insn->insn_reserv_decl
+               == &advance_cycle_insn_decl->decl.insn_reserv) ? 1 : 0);
+#ifndef NDEBUG
+      if (VLA_HWINT (dead_lock_vect, (*state_ptr)->order_state_num))
+        locked_states_num++;
+#endif
+    }
+  fprintf (output_file, "/* Vector for locked state flags.  */\n");
+  fprintf (output_file, "static const ");
+  output_range_type (output_file, 0, 1);
+  fprintf (output_file, " ");
+  output_dead_lock_vect_name (output_file, automaton);
+  fprintf (output_file, "[] = {\n");
+  output_vect (VLA_HWINT_BEGIN (dead_lock_vect),
+              VLA_HWINT_LENGTH (dead_lock_vect));
+  fprintf (output_file, "};\n\n");
+  VLA_HWINT_DELETE (dead_lock_vect);
+  VLA_PTR_DELETE (output_states_vect);
+}
+
+/* Form and output vector representing reserved units of the states of
+   AUTOMATON.  */
+static void
+output_reserved_units_table (automaton)
+     automaton_t automaton;
+{
+  state_t *curr_state_ptr;
+  vla_hwint_t reserved_units_table;
+  size_t state_byte_size;
+  int i;
+
+  /* Create vect of pointers to states.  */
+  VLA_PTR_CREATE (output_states_vect, 1500, "output states vector");
+  pass_states (automaton, add_states_vect_el);
+  /* Create vector.  */
+  VLA_HWINT_CREATE (reserved_units_table, 1500, "reserved units vector");
+  state_byte_size = (description->query_units_num + 7) / 8;
+  VLA_HWINT_EXPAND (reserved_units_table,
+                   VLA_HWINT_LENGTH (output_states_vect) * state_byte_size);
+  for (i = 0;
+       i < (int) (VLA_HWINT_LENGTH (output_states_vect) * state_byte_size);
+       i++)
+    VLA_HWINT (reserved_units_table, i) = 0;
+  for (curr_state_ptr = VLA_PTR_BEGIN (output_states_vect);
+       curr_state_ptr <= (state_t *) VLA_PTR_LAST (output_states_vect);
+       curr_state_ptr++)
+    {
+      for (i = 0; i < description->units_num; i++)
+       if (units_array [i]->query_p)
+         {
+           if (test_unit_reserv ((*curr_state_ptr)->reservs, 0, i))
+             VLA_HWINT (reserved_units_table,
+                        (*curr_state_ptr)->order_state_num * state_byte_size
+                        + units_array [i]->query_num / 8)
+               += (1 << (units_array [i]->query_num % 8));
+         }
+    }
+  fprintf (output_file, "/* Vector for reserved units of states.  */\n");
+  fprintf (output_file, "static const ");
+  output_range_type (output_file, 0, 255);
+  fprintf (output_file, " ");
+  output_reserved_units_table_name (output_file, automaton);
+  fprintf (output_file, "[] = {\n");
+  output_vect (VLA_HWINT_BEGIN (reserved_units_table),
+               VLA_HWINT_LENGTH (reserved_units_table));
+  fprintf (output_file, "};\n\n");
+  VLA_HWINT_DELETE (reserved_units_table);
+  VLA_PTR_DELETE (output_states_vect);
+}
+
+/* The function outputs all tables representing DFA(s) used for fast
+   pipeline hazards recognition.  */
+static void
+output_tables ()
+{
+  automaton_t automaton;
+
+#ifndef NDEBUG
+  locked_states_num = 0;
+#endif
+  initiate_min_issue_delay_pass_states ();
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    {
+      output_translate_vect (automaton);
+      output_trans_table (automaton);
+      fprintf (output_file, "\n#if %s\n", AUTOMATON_STATE_ALTS_MACRO_NAME);
+      output_state_alts_table (automaton);
+      fprintf (output_file, "\n#endif /* #if %s */\n\n",
+              AUTOMATON_STATE_ALTS_MACRO_NAME);
+      output_min_issue_delay_table (automaton);
+      output_dead_lock_vect (automaton);
+      if (no_minimization_flag)
+       {
+         fprintf (output_file, "\n#if %s\n\n", CPU_UNITS_QUERY_MACRO_NAME);
+         output_reserved_units_table (automaton);
+         fprintf (output_file, "\n#endif /* #if %s */\n\n",
+                  CPU_UNITS_QUERY_MACRO_NAME);
+       }
+    }
+  fprintf (output_file, "\n#define %s %d\n\n", ADVANCE_CYCLE_VALUE_NAME,
+           advance_cycle_insn_decl->decl.insn_reserv.insn_num);
+}
+
+/* The function outputs definition and value of PHR interface variable
+   `max_insn_queue_index' */
+static void
+output_max_insn_queue_index_def ()
+{
+  int i;
+
+  for (i = 0; (1 << i) <= description->max_insn_reserv_cycles; i++)
+    ;
+  if (i < 0)
+    abort ();
+  fprintf (output_file, "\nint max_insn_queue_index = %d;\n\n", (1 << i) - 1);
+}
+
+
+/* Output function `internal_min_issue_delay'.  */
+static void
+output_internal_min_issue_delay_func ()
+{
+  automaton_t automaton;
+
+  fprintf (output_file, "static int %s PARAMS ((int, struct %s *));\n",
+          INTERNAL_MIN_ISSUE_DELAY_FUNC_NAME, CHIP_NAME);
+  fprintf (output_file,
+          "static int\n%s (%s, %s)\n\tint %s;\n\tstruct %s *%s;\n",
+          INTERNAL_MIN_ISSUE_DELAY_FUNC_NAME, INTERNAL_INSN_CODE_NAME,
+          CHIP_PARAMETER_NAME, INTERNAL_INSN_CODE_NAME, CHIP_NAME,
+          CHIP_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s;\n  int %s;\n",
+          TEMPORARY_VARIABLE_NAME, RESULT_VARIABLE_NAME);
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    {
+      fprintf (output_file, "\n  %s = ", TEMPORARY_VARIABLE_NAME);
+      output_min_issue_delay_vect_name (output_file, automaton);
+      fprintf (output_file,
+              (automaton->min_issue_delay_table_compression_factor != 1
+               ? " [(" : " ["));
+      output_translate_vect_name (output_file, automaton);
+      fprintf (output_file, " [%s] + ", INTERNAL_INSN_CODE_NAME);
+      fprintf (output_file, "%s->", CHIP_PARAMETER_NAME);
+      output_chip_member_name (output_file, automaton);
+      fprintf (output_file, " * %d", automaton->insn_equiv_classes_num);
+      if (automaton->min_issue_delay_table_compression_factor == 1)
+       fprintf (output_file, "];\n");
+      else
+       {
+         fprintf (output_file, ") / %d];\n",
+                  automaton->min_issue_delay_table_compression_factor);
+         fprintf (output_file, "  %s = (%s >> (8 - (",
+                  TEMPORARY_VARIABLE_NAME, TEMPORARY_VARIABLE_NAME);
+         output_translate_vect_name (output_file, automaton);
+         fprintf
+           (output_file, " [%s] %% %d + 1) * %d)) & %d;\n",
+            INTERNAL_INSN_CODE_NAME,
+            automaton->min_issue_delay_table_compression_factor,
+            8 / automaton->min_issue_delay_table_compression_factor,
+            (1 << (8 / automaton->min_issue_delay_table_compression_factor))
+            - 1);
+       }
+      if (automaton == description->first_automaton)
+       fprintf (output_file, "  %s = %s;\n",
+                RESULT_VARIABLE_NAME, TEMPORARY_VARIABLE_NAME);
+      else
+       {
+         fprintf (output_file, "  if (%s > %s)\n",
+                  TEMPORARY_VARIABLE_NAME, RESULT_VARIABLE_NAME);
+         fprintf (output_file, "    %s = %s;\n",
+                  RESULT_VARIABLE_NAME, TEMPORARY_VARIABLE_NAME);
+       }
+    }
+  fprintf (output_file, "  return %s;\n", RESULT_VARIABLE_NAME);
+  fprintf (output_file, "}\n\n");
+}
+
+/* Output function `internal_state_transition'.  */
+static void
+output_internal_trans_func ()
+{
+  automaton_t curr_automaton;
+  automaton_t next_automaton;
+
+  fprintf (output_file, "static int %s PARAMS ((int, struct %s *));\n",
+          INTERNAL_TRANSITION_FUNC_NAME, CHIP_NAME);
+  fprintf (output_file,
+          "static int\n%s (%s, %s)\n\tint %s;\n\tstruct %s *%s;\n",
+          INTERNAL_TRANSITION_FUNC_NAME, INTERNAL_INSN_CODE_NAME,
+          CHIP_PARAMETER_NAME, INTERNAL_INSN_CODE_NAME,
+          CHIP_NAME, CHIP_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s;\n", TEMPORARY_VARIABLE_NAME);
+  if (description->first_automaton != NULL)
+    for (curr_automaton = description->first_automaton;;
+         curr_automaton = next_automaton)
+      {
+        next_automaton = curr_automaton->next_automaton;
+        if (next_automaton == NULL)
+          break;
+        fprintf (output_file, "  ");
+        output_state_member_type (output_file, curr_automaton);
+       fprintf (output_file, " ");
+        output_temp_chip_member_name (output_file, curr_automaton);
+        fprintf (output_file, ";\n");
+      }
+  for (curr_automaton = description->first_automaton;
+       curr_automaton != NULL;
+       curr_automaton = curr_automaton->next_automaton)
+    if (comb_vect_p (curr_automaton->trans_table))
+      {
+       fprintf (output_file, "\n  %s = ", TEMPORARY_VARIABLE_NAME);
+       output_trans_base_vect_name (output_file, curr_automaton);
+       fprintf (output_file, " [%s->", CHIP_PARAMETER_NAME);
+       output_chip_member_name (output_file, curr_automaton);
+       fprintf (output_file, "] + ");
+       output_translate_vect_name (output_file, curr_automaton);
+       fprintf (output_file, " [%s];\n", INTERNAL_INSN_CODE_NAME);
+       fprintf (output_file, "  if (");
+       output_trans_check_vect_name (output_file, curr_automaton);
+       fprintf (output_file, " [%s] != %s->",
+                TEMPORARY_VARIABLE_NAME, CHIP_PARAMETER_NAME);
+       output_chip_member_name (output_file, curr_automaton);
+       fprintf (output_file, ")\n");
+       fprintf (output_file, "    return %s (%s, %s);\n",
+                INTERNAL_MIN_ISSUE_DELAY_FUNC_NAME, INTERNAL_INSN_CODE_NAME,
+                CHIP_PARAMETER_NAME);
+       fprintf (output_file, "  else\n");
+       fprintf (output_file, "    ");
+       if (curr_automaton->next_automaton != NULL)
+         output_temp_chip_member_name (output_file, curr_automaton);
+       else
+         {
+           fprintf (output_file, "%s->", CHIP_PARAMETER_NAME);
+           output_chip_member_name (output_file, curr_automaton);
+         }
+       fprintf (output_file, " = ");
+       output_trans_comb_vect_name (output_file, curr_automaton);
+       fprintf (output_file, " [%s];\n", TEMPORARY_VARIABLE_NAME);
+      }
+    else
+      {
+       fprintf (output_file, "\n  %s = ", TEMPORARY_VARIABLE_NAME);
+       output_trans_full_vect_name (output_file, curr_automaton);
+       fprintf (output_file, " [");
+       output_translate_vect_name (output_file, curr_automaton);
+       fprintf (output_file, " [%s] + ", INTERNAL_INSN_CODE_NAME);
+       fprintf (output_file, "%s->", CHIP_PARAMETER_NAME);
+       output_chip_member_name (output_file, curr_automaton);
+       fprintf (output_file, " * %d];\n",
+                curr_automaton->insn_equiv_classes_num);
+       fprintf (output_file, "  if (%s >= %d)\n", TEMPORARY_VARIABLE_NAME,
+                curr_automaton->achieved_states_num);
+       fprintf (output_file, "    return %s (%s, %s);\n",
+                INTERNAL_MIN_ISSUE_DELAY_FUNC_NAME, INTERNAL_INSN_CODE_NAME,
+                CHIP_PARAMETER_NAME);
+       fprintf (output_file, "  else\n    ");
+       if (curr_automaton->next_automaton != NULL)
+         output_temp_chip_member_name (output_file, curr_automaton);
+       else
+         {
+           fprintf (output_file, "%s->", CHIP_PARAMETER_NAME);
+           output_chip_member_name (output_file, curr_automaton);
+         }
+       fprintf (output_file, " = %s;\n", TEMPORARY_VARIABLE_NAME);
+      }
+  if (description->first_automaton != NULL)
+    for (curr_automaton = description->first_automaton;;
+         curr_automaton = next_automaton)
+      {
+        next_automaton = curr_automaton->next_automaton;
+        if (next_automaton == NULL)
+          break;
+        fprintf (output_file, "  %s->", CHIP_PARAMETER_NAME);
+        output_chip_member_name (output_file, curr_automaton);
+        fprintf (output_file, " = ");
+        output_temp_chip_member_name (output_file, curr_automaton);
+        fprintf (output_file, ";\n");
+      }
+  fprintf (output_file, "  return -1;\n");
+  fprintf (output_file, "}\n\n");
+}
+
+/* Output code
+
+  if (insn != 0)
+    {
+      insn_code = dfa_insn_code (insn);
+      if (insn_code > DFA__ADVANCE_CYCLE)
+        return code;
+    }
+  else
+    insn_code = DFA__ADVANCE_CYCLE;
+
+  where insn denotes INSN_NAME, insn_code denotes INSN_CODE_NAME, and
+  code denotes CODE.  */
+static void
+output_internal_insn_code_evaluation (insn_name, insn_code_name, code)
+     const char *insn_name;
+     const char *insn_code_name;
+     int code;
+{
+  fprintf (output_file, "\n  if (%s != 0)\n    {\n", insn_name);
+  fprintf (output_file, "      %s = %s (%s);\n", insn_code_name,
+          DFA_INSN_CODE_FUNC_NAME, insn_name);
+  fprintf (output_file, "      if (%s > %s)\n        return %d;\n",
+          insn_code_name, ADVANCE_CYCLE_VALUE_NAME, code);
+  fprintf (output_file, "    }\n  else\n    %s = %s;\n\n",
+          insn_code_name, ADVANCE_CYCLE_VALUE_NAME);
+}
+
+
+/* The function outputs function `dfa_insn_code'.  */
+static void
+output_dfa_insn_code_func ()
+{
+  fprintf (output_file, "#ifdef __GNUC__\n__inline__\n#endif\n");
+  fprintf (output_file, "static int %s PARAMS ((rtx));\n",
+          DFA_INSN_CODE_FUNC_NAME);
+  fprintf (output_file, "static int\n%s (%s)\n\trtx %s;\n",
+          DFA_INSN_CODE_FUNC_NAME, INSN_PARAMETER_NAME, INSN_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s;\n\n", INTERNAL_INSN_CODE_NAME);
+  fprintf (output_file, "  if ((%s = %s [INSN_UID (%s)]) < 0)\n    {\n",
+          INTERNAL_INSN_CODE_NAME, DFA_INSN_CODES_VARIABLE_NAME,
+          INSN_PARAMETER_NAME);
+  fprintf (output_file, "      %s = %s (%s);\n", INTERNAL_INSN_CODE_NAME,
+          INTERNAL_DFA_INSN_CODE_FUNC_NAME, INSN_PARAMETER_NAME);
+  fprintf (output_file, "      %s [INSN_UID (%s)] = %s;\n",
+          DFA_INSN_CODES_VARIABLE_NAME, INSN_PARAMETER_NAME,
+          INTERNAL_INSN_CODE_NAME);
+  fprintf (output_file, "    }\n  return %s;\n}\n\n",
+          INTERNAL_INSN_CODE_NAME);
+}
+
+/* The function outputs PHR interface function `state_transition'.  */
+static void
+output_trans_func ()
+{
+  fprintf (output_file, "int\n%s (%s, %s)\n\t%s %s;\n\trtx %s;\n",
+          TRANSITION_FUNC_NAME, STATE_NAME, INSN_PARAMETER_NAME,
+          STATE_TYPE_NAME, STATE_NAME, INSN_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s;\n", INTERNAL_INSN_CODE_NAME);
+  output_internal_insn_code_evaluation (INSN_PARAMETER_NAME,
+                                       INTERNAL_INSN_CODE_NAME, -1);
+  fprintf (output_file, "  return %s (%s, %s);\n}\n\n",
+          INTERNAL_TRANSITION_FUNC_NAME, INTERNAL_INSN_CODE_NAME, STATE_NAME);
+}
+
+/* Output function `internal_state_alts'.  */
+static void
+output_internal_state_alts_func ()
+{
+  automaton_t automaton;
+
+  fprintf (output_file, "static int %s PARAMS ((int, struct %s *));\n",
+          INTERNAL_STATE_ALTS_FUNC_NAME, CHIP_NAME);
+  fprintf (output_file,
+          "static int\n%s (%s, %s)\n\tint %s;\n\tstruct %s *%s;\n",
+          INTERNAL_STATE_ALTS_FUNC_NAME, INTERNAL_INSN_CODE_NAME,
+          CHIP_PARAMETER_NAME, INTERNAL_INSN_CODE_NAME, CHIP_NAME,
+          CHIP_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s;\n", RESULT_VARIABLE_NAME);
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    if (comb_vect_p (automaton->state_alts_table))
+      {
+       fprintf (output_file, "  int %s;\n", TEMPORARY_VARIABLE_NAME);
+       break;
+      }
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    if (comb_vect_p (automaton->state_alts_table))
+      {
+       fprintf (output_file, "\n  %s = ", TEMPORARY_VARIABLE_NAME);
+       output_state_alts_base_vect_name (output_file, automaton);
+       fprintf (output_file, " [%s->", CHIP_PARAMETER_NAME);
+       output_chip_member_name (output_file, automaton);
+       fprintf (output_file, "] + ");
+       output_translate_vect_name (output_file, automaton);
+       fprintf (output_file, " [%s];\n", INTERNAL_INSN_CODE_NAME);
+       fprintf (output_file, "  if (");
+       output_state_alts_check_vect_name (output_file, automaton);
+       fprintf (output_file, " [%s] != %s->",
+                TEMPORARY_VARIABLE_NAME, CHIP_PARAMETER_NAME);
+       output_chip_member_name (output_file, automaton);
+       fprintf (output_file, ")\n");
+       fprintf (output_file, "    return 0;\n");
+       fprintf (output_file, "  else\n");
+       fprintf (output_file,
+                (automaton == description->first_automaton
+                 ? "    %s = " : "    %s += "), RESULT_VARIABLE_NAME);
+       output_state_alts_comb_vect_name (output_file, automaton);
+       fprintf (output_file, " [%s];\n", TEMPORARY_VARIABLE_NAME);
+      }
+    else
+      {
+       fprintf (output_file,
+                (automaton == description->first_automaton
+                 ? "\n  %s = " : "  %s += "), RESULT_VARIABLE_NAME);
+       output_state_alts_full_vect_name (output_file, automaton);
+       fprintf (output_file, " [");
+       output_translate_vect_name (output_file, automaton);
+       fprintf (output_file, " [%s] + ", INTERNAL_INSN_CODE_NAME);
+       fprintf (output_file, "%s->", CHIP_PARAMETER_NAME);
+       output_chip_member_name (output_file, automaton);
+       fprintf (output_file, " * %d];\n", automaton->insn_equiv_classes_num);
+      }
+  fprintf (output_file, "  return %s;\n", RESULT_VARIABLE_NAME);
+  fprintf (output_file, "}\n\n");
+}
+
+/* The function outputs PHR interface function `state_alts'.  */
+static void
+output_state_alts_func ()
+{
+  fprintf (output_file, "int\n%s (%s, %s)\n\t%s %s;\n\trtx %s;\n",
+          STATE_ALTS_FUNC_NAME, STATE_NAME, INSN_PARAMETER_NAME,
+          STATE_TYPE_NAME, STATE_NAME, INSN_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s;\n", INTERNAL_INSN_CODE_NAME);
+  output_internal_insn_code_evaluation (INSN_PARAMETER_NAME,
+                                       INTERNAL_INSN_CODE_NAME, 0);
+  fprintf (output_file, "  return %s (%s, %s);\n}\n\n",
+          INTERNAL_STATE_ALTS_FUNC_NAME, INTERNAL_INSN_CODE_NAME, STATE_NAME);
+}
+
+/* Output function `min_issue_delay'.  */
+static void
+output_min_issue_delay_func ()
+{
+  fprintf (output_file, "int\n%s (%s, %s)\n\t%s %s;\n\trtx %s;\n",
+          MIN_ISSUE_DELAY_FUNC_NAME, STATE_NAME, INSN_PARAMETER_NAME,
+          STATE_TYPE_NAME, STATE_NAME, INSN_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s;\n", INTERNAL_INSN_CODE_NAME);
+  fprintf (output_file, "\n  if (%s != 0)\n    {\n", INSN_PARAMETER_NAME);
+  fprintf (output_file, "      %s = %s (%s);\n", INTERNAL_INSN_CODE_NAME,
+          DFA_INSN_CODE_FUNC_NAME, INSN_PARAMETER_NAME);
+  fprintf (output_file, "      if (%s > %s)\n        return 0;\n",
+          INTERNAL_INSN_CODE_NAME, ADVANCE_CYCLE_VALUE_NAME);
+  fprintf (output_file, "    }\n  else\n    %s = %s;\n",
+          INTERNAL_INSN_CODE_NAME, ADVANCE_CYCLE_VALUE_NAME);
+  fprintf (output_file, "\n  return %s (%s, %s);\n",
+          INTERNAL_MIN_ISSUE_DELAY_FUNC_NAME, INTERNAL_INSN_CODE_NAME,
+          STATE_NAME);
+  fprintf (output_file, "}\n\n");
+}
+
+/* Output function `internal_dead_lock'.  */
+static void
+output_internal_dead_lock_func ()
+{
+  automaton_t automaton;
+
+  fprintf (output_file, "static int %s PARAMS ((struct %s *));\n",
+          INTERNAL_DEAD_LOCK_FUNC_NAME, CHIP_NAME);
+  fprintf (output_file, "static int\n%s (%s)\n\tstruct %s *%s;\n",
+          INTERNAL_DEAD_LOCK_FUNC_NAME, CHIP_PARAMETER_NAME, CHIP_NAME,
+          CHIP_PARAMETER_NAME);
+  fprintf (output_file, "{\n");
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    {
+      fprintf (output_file, "  if (");
+      output_dead_lock_vect_name (output_file, automaton);
+      fprintf (output_file, " [%s->", CHIP_PARAMETER_NAME);
+      output_chip_member_name (output_file, automaton);
+      fprintf (output_file, "])\n    return 1/* TRUE */;\n");
+    }
+  fprintf (output_file, "  return 0/* FALSE */;\n}\n\n");
+}
+
+/* The function outputs PHR interface function `state_dead_lock_p'.  */
+static void
+output_dead_lock_func ()
+{
+  fprintf (output_file, "int\n%s (%s)\n\t%s %s;\n",
+          DEAD_LOCK_FUNC_NAME, STATE_NAME, STATE_TYPE_NAME, STATE_NAME);
+  fprintf (output_file, "{\n  return %s (%s);\n}\n\n",
+          INTERNAL_DEAD_LOCK_FUNC_NAME, STATE_NAME);
+}
+
+/* Output function `internal_reset'.  */
+static void
+output_internal_reset_func ()
+{
+  fprintf (output_file, "static void %s PARAMS ((struct %s *));\n",
+          INTERNAL_RESET_FUNC_NAME, CHIP_NAME);
+  fprintf (output_file, "static void\n%s (%s)\n\tstruct %s *%s;\n",
+          INTERNAL_RESET_FUNC_NAME, CHIP_PARAMETER_NAME,
+          CHIP_NAME, CHIP_PARAMETER_NAME);
+  fprintf (output_file, "{\n  memset (%s, 0, sizeof (struct %s));\n}\n\n",
+          CHIP_PARAMETER_NAME, CHIP_NAME);
+}
+
+/* The function outputs PHR interface function `state_size'.  */
+static void
+output_size_func ()
+{
+  fprintf (output_file, "int\n%s ()\n", SIZE_FUNC_NAME);
+  fprintf (output_file, "{\n  return sizeof (struct %s);\n}\n\n", CHIP_NAME);
+}
+
+/* The function outputs PHR interface function `state_reset'.  */
+static void
+output_reset_func ()
+{
+  fprintf (output_file, "void\n%s (%s)\n\t %s %s;\n",
+          RESET_FUNC_NAME, STATE_NAME, STATE_TYPE_NAME, STATE_NAME);
+  fprintf (output_file, "{\n  %s (%s);\n}\n\n", INTERNAL_RESET_FUNC_NAME,
+          STATE_NAME);
+}
+
+/* Output function `min_insn_conflict_delay'.  */
+static void
+output_min_insn_conflict_delay_func ()
+{
+  fprintf (output_file,
+          "int\n%s (%s, %s, %s)\n\t%s %s;\n\trtx %s;\n\trtx %s;\n",
+          MIN_INSN_CONFLICT_DELAY_FUNC_NAME,
+          STATE_NAME, INSN_PARAMETER_NAME, INSN2_PARAMETER_NAME,
+          STATE_TYPE_NAME, STATE_NAME,
+          INSN_PARAMETER_NAME, INSN2_PARAMETER_NAME);
+  fprintf (output_file, "{\n  struct %s %s;\n  int %s, %s;\n",
+          CHIP_NAME, CHIP_NAME, INTERNAL_INSN_CODE_NAME,
+          INTERNAL_INSN2_CODE_NAME);
+  output_internal_insn_code_evaluation (INSN_PARAMETER_NAME,
+                                       INTERNAL_INSN_CODE_NAME, 0);
+  output_internal_insn_code_evaluation (INSN2_PARAMETER_NAME,
+                                       INTERNAL_INSN2_CODE_NAME, 0);
+  fprintf (output_file, "  memcpy (&%s, %s, sizeof (%s));\n",
+          CHIP_NAME, STATE_NAME, CHIP_NAME);
+  fprintf (output_file, "  %s (&%s);\n", INTERNAL_RESET_FUNC_NAME, CHIP_NAME);
+  fprintf (output_file, "  if (%s (%s, &%s) > 0)\n    abort ();\n",
+          INTERNAL_TRANSITION_FUNC_NAME, INTERNAL_INSN_CODE_NAME, CHIP_NAME);
+  fprintf (output_file, "  return %s (%s, &%s);\n",
+          INTERNAL_MIN_ISSUE_DELAY_FUNC_NAME, INTERNAL_INSN2_CODE_NAME,
+          CHIP_NAME);
+  fprintf (output_file, "}\n\n");
+}
+
+/* Output function `internal_insn_latency'.  */
+static void
+output_internal_insn_latency_func ()
+{
+  decl_t decl;
+  struct bypass_decl *bypass;
+  int i;
+
+  fprintf (output_file, "static int %s PARAMS ((int, int, rtx, rtx));\n",
+          INTERNAL_INSN_LATENCY_FUNC_NAME);
+  fprintf (output_file, "static int\n%s (%s, %s, %s, %s)",
+          INTERNAL_INSN_LATENCY_FUNC_NAME, INTERNAL_INSN_CODE_NAME,
+          INTERNAL_INSN2_CODE_NAME,
+          INSN_PARAMETER_NAME, INSN2_PARAMETER_NAME);
+  fprintf (output_file, "\n\tint %s;\n\tint %s;\n",
+          INTERNAL_INSN_CODE_NAME, INTERNAL_INSN2_CODE_NAME);
+  fprintf (output_file,
+          "\trtx %s ATTRIBUTE_UNUSED;\n\trtx %s ATTRIBUTE_UNUSED;\n",
+          INSN_PARAMETER_NAME, INSN2_PARAMETER_NAME);
+  fprintf (output_file, "{\n  switch (%s)\n    {\n", INTERNAL_INSN_CODE_NAME);
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv)
+       {
+         fprintf (output_file, "    case %d:\n",
+                  decl->decl.insn_reserv.insn_num);
+         if (decl->decl.insn_reserv.bypass_list == NULL)
+           fprintf (output_file, "      return (%s != %s ? %d : 0);\n",
+                    INTERNAL_INSN2_CODE_NAME, ADVANCE_CYCLE_VALUE_NAME,
+                    decl->decl.insn_reserv.default_latency);
+         else
+           {
+             fprintf (output_file, "      switch (%s)\n        {\n",
+                      INTERNAL_INSN2_CODE_NAME);
+             for (bypass = decl->decl.insn_reserv.bypass_list;
+                  bypass != NULL;
+                  bypass = bypass->next)
+               {
+                 fprintf (output_file, "        case %d:\n",
+                          bypass->in_insn_reserv->insn_num);
+                 if (bypass->bypass_guard_name == NULL)
+                   fprintf (output_file, "          return %d;\n",
+                            bypass->latency);
+                 else
+                   fprintf (output_file,
+                            "          return (%s (%s, %s) ? %d : %d);\n",
+                            bypass->bypass_guard_name, INSN_PARAMETER_NAME,
+                            INSN2_PARAMETER_NAME, bypass->latency,
+                            decl->decl.insn_reserv.default_latency);
+               }
+             fprintf (output_file, "        default:\n");
+             fprintf (output_file,
+                      "          return (%s != %s ? %d : 0);\n        }\n",
+                      INTERNAL_INSN2_CODE_NAME, ADVANCE_CYCLE_VALUE_NAME,
+                      decl->decl.insn_reserv.default_latency);
+             
+           }
+       }
+    }
+  fprintf (output_file, "    default:\n      return 0;\n    }\n}\n\n");
+}
+
+/* The function outputs PHR interface function `insn_latency'.  */
+static void
+output_insn_latency_func ()
+{
+  fprintf (output_file, "int\n%s (%s, %s)\n\trtx %s;\n\trtx %s;\n",
+          INSN_LATENCY_FUNC_NAME, INSN_PARAMETER_NAME, INSN2_PARAMETER_NAME,
+          INSN_PARAMETER_NAME, INSN2_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s, %s;\n",
+          INTERNAL_INSN_CODE_NAME, INTERNAL_INSN2_CODE_NAME);
+  output_internal_insn_code_evaluation (INSN_PARAMETER_NAME,
+                                       INTERNAL_INSN_CODE_NAME, 0);
+  output_internal_insn_code_evaluation (INSN2_PARAMETER_NAME,
+                                       INTERNAL_INSN2_CODE_NAME, 0);
+  fprintf (output_file, "  return %s (%s, %s, %s, %s);\n}\n\n",
+          INTERNAL_INSN_LATENCY_FUNC_NAME,
+          INTERNAL_INSN_CODE_NAME, INTERNAL_INSN2_CODE_NAME,
+          INSN_PARAMETER_NAME, INSN2_PARAMETER_NAME);
+}
+
+/* The function outputs PHR interface function `print_reservation'.  */
+static void
+output_print_reservation_func ()
+{
+  decl_t decl;
+  int i;
+
+  fprintf (output_file, "void\n%s (%s, %s)\n\tFILE *%s;\n\trtx %s;\n",
+           PRINT_RESERVATION_FUNC_NAME, FILE_PARAMETER_NAME,
+           INSN_PARAMETER_NAME, FILE_PARAMETER_NAME,
+           INSN_PARAMETER_NAME);
+  fprintf (output_file, "{\n  int %s;\n", INTERNAL_INSN_CODE_NAME);
+  fprintf (output_file, "\n  if (%s != 0)\n    {\n", INSN_PARAMETER_NAME);
+  fprintf (output_file, "      %s = %s (%s);\n",
+          INTERNAL_INSN_CODE_NAME, DFA_INSN_CODE_FUNC_NAME,
+          INSN_PARAMETER_NAME);
+  fprintf (output_file, "      if (%s > %s)\n",
+          INTERNAL_INSN_CODE_NAME, ADVANCE_CYCLE_VALUE_NAME);
+  fprintf (output_file, "        {\n          fprintf (%s, \"%s\");\n",
+           FILE_PARAMETER_NAME, NOTHING_NAME);
+  fprintf (output_file, "          return;\n        }\n");
+  fprintf (output_file, "    }\n  else\n");
+  fprintf (output_file,
+           "    {\n      fprintf (%s, \"%s\");\n      return;\n    }\n",
+           FILE_PARAMETER_NAME, NOTHING_NAME);
+  fprintf (output_file, "  switch (%s)\n    {\n", INTERNAL_INSN_CODE_NAME);
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv && decl != advance_cycle_insn_decl)
+       {
+          fprintf (output_file,
+                   "    case %d:\n", decl->decl.insn_reserv.insn_num);
+          fprintf (output_file,
+                   "      fprintf (%s, \"%s\");\n      break;\n",
+                   FILE_PARAMETER_NAME,
+                   regexp_representation (decl->decl.insn_reserv.regexp));
+          finish_regexp_representation ();
+        }
+    }
+  fprintf (output_file, "    default:\n      fprintf (%s, \"%s\");\n    }\n",
+           FILE_PARAMETER_NAME, NOTHING_NAME);
+  fprintf (output_file, "}\n\n");
+}
+
+/* The following function is used to sort unit declaration by their
+   names.  */
+static int
+units_cmp (unit1, unit2)
+     const void *unit1, *unit2;
+{
+  const struct unit_decl *u1 = *(struct unit_decl **) unit1;
+  const struct unit_decl *u2 = *(struct unit_decl **) unit2;
+
+  return strcmp (u1->name, u2->name);
+}
+
+/* The following macro value is name of struct containing unit name
+   and unit code.  */
+#define NAME_CODE_STRUCT_NAME  "name_code"
+
+/* The following macro value is name of table of struct name_code.  */
+#define NAME_CODE_TABLE_NAME   "name_code_table"
+
+/* The following macro values are member names for struct name_code.  */
+#define NAME_MEMBER_NAME       "name"
+#define CODE_MEMBER_NAME       "code"
+
+/* The following macro values are local variable names for function
+   `get_cpu_unit_code'.  */
+#define CMP_VARIABLE_NAME      "cmp"
+#define LOW_VARIABLE_NAME      "l"
+#define MIDDLE_VARIABLE_NAME   "m"
+#define HIGH_VARIABLE_NAME     "h"
+
+/* The following function outputs function to obtain internal cpu unit
+   code by the cpu unit name.  */
+static void
+output_get_cpu_unit_code_func ()
+{
+  int i;
+  struct unit_decl **units;
+  
+  fprintf (output_file, "int\n%s (%s)\n\tconst char *%s;\n",
+          GET_CPU_UNIT_CODE_FUNC_NAME, CPU_UNIT_NAME_PARAMETER_NAME,
+          CPU_UNIT_NAME_PARAMETER_NAME);
+  fprintf (output_file, "{\n  struct %s {const char *%s; int %s;};\n",
+          NAME_CODE_STRUCT_NAME, NAME_MEMBER_NAME, CODE_MEMBER_NAME);
+  fprintf (output_file, "  int %s, %s, %s, %s;\n", CMP_VARIABLE_NAME,
+          LOW_VARIABLE_NAME, MIDDLE_VARIABLE_NAME, HIGH_VARIABLE_NAME);
+  fprintf (output_file, "  static struct %s %s [] =\n    {\n",
+          NAME_CODE_STRUCT_NAME, NAME_CODE_TABLE_NAME);
+  units = (struct unit_decl **) xmalloc (sizeof (struct unit_decl *)
+                                        * description->units_num);
+  memcpy (units, units_array,
+         sizeof (struct unit_decl *) * description->units_num);
+  qsort (units, description->units_num,
+        sizeof (struct unit_decl *), units_cmp);
+  for (i = 0; i < description->units_num; i++)
+    if (units [i]->query_p)
+      fprintf (output_file, "      {\"%s\", %d},\n",
+              units[i]->name, units[i]->query_num);
+  fprintf (output_file, "    };\n\n");
+  fprintf (output_file, "  /* The following is binary search: */\n");
+  fprintf (output_file, "  %s = 0;\n", LOW_VARIABLE_NAME);
+  fprintf (output_file, "  %s = sizeof (%s) / sizeof (struct %s) - 1;\n",
+          HIGH_VARIABLE_NAME, NAME_CODE_TABLE_NAME, NAME_CODE_STRUCT_NAME);
+  fprintf (output_file, "  while (%s <= %s)\n    {\n",
+          LOW_VARIABLE_NAME, HIGH_VARIABLE_NAME);
+  fprintf (output_file, "      %s = (%s + %s) / 2;\n",
+          MIDDLE_VARIABLE_NAME, LOW_VARIABLE_NAME, HIGH_VARIABLE_NAME);
+  fprintf (output_file, "      %s = strcmp (%s, %s [%s].%s);\n",
+          CMP_VARIABLE_NAME, CPU_UNIT_NAME_PARAMETER_NAME,
+          NAME_CODE_TABLE_NAME, MIDDLE_VARIABLE_NAME, NAME_MEMBER_NAME);
+  fprintf (output_file, "      if (%s < 0)\n", CMP_VARIABLE_NAME);
+  fprintf (output_file, "        %s = %s - 1;\n",
+          HIGH_VARIABLE_NAME, MIDDLE_VARIABLE_NAME);
+  fprintf (output_file, "      else if (%s > 0)\n", CMP_VARIABLE_NAME);
+  fprintf (output_file, "        %s = %s + 1;\n",
+          LOW_VARIABLE_NAME, MIDDLE_VARIABLE_NAME);
+  fprintf (output_file, "      else\n");
+  fprintf (output_file, "        return %s [%s].%s;\n    }\n",
+          NAME_CODE_TABLE_NAME, MIDDLE_VARIABLE_NAME, CODE_MEMBER_NAME);
+  fprintf (output_file, "  return -1;\n}\n\n");
+  free (units);
+}
+
+/* The following function outputs function to check reservation of cpu
+   unit (its internal code will be passed as the function argument) in
+   given cpu state.  */
+static void
+output_cpu_unit_reservation_p ()
+{
+  automaton_t automaton;
+
+  fprintf (output_file, "int\n%s (%s, %s)\n\t%s %s;\n\tint %s;\n",
+          CPU_UNIT_RESERVATION_P_FUNC_NAME, STATE_NAME,
+          CPU_CODE_PARAMETER_NAME, STATE_TYPE_NAME, STATE_NAME,
+          CPU_CODE_PARAMETER_NAME);
+  fprintf (output_file, "{\n  if (%s < 0 || %s >= %d)\n    abort ();\n",
+          CPU_CODE_PARAMETER_NAME, CPU_CODE_PARAMETER_NAME,
+          description->query_units_num);
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    {
+      fprintf (output_file, "  if ((");
+      output_reserved_units_table_name (output_file, automaton);
+      fprintf (output_file, " [((struct %s *) %s)->", CHIP_NAME, STATE_NAME);
+      output_chip_member_name (output_file, automaton);
+      fprintf (output_file, " * %d + %s / 8] >> (%s %% 8)) & 1)\n",
+              (description->query_units_num + 7) / 8,
+              CPU_CODE_PARAMETER_NAME, CPU_CODE_PARAMETER_NAME);
+      fprintf (output_file, "    return 1;\n");
+    }
+  fprintf (output_file, "  return 0;\n}\n\n");
+}
+
+/* The function outputs PHR interface function `dfa_start'.  */
+static void
+output_dfa_start_func ()
+{
+  fprintf (output_file,
+          "void\n%s ()\n{\n  int %s;\n  int %s = get_max_uid ();\n\n",
+          DFA_START_FUNC_NAME, I_VARIABLE_NAME, TEMPORARY_VARIABLE_NAME);
+  fprintf (output_file, "  %s = (int *) xmalloc (%s * sizeof (int));\n",
+          DFA_INSN_CODES_VARIABLE_NAME, TEMPORARY_VARIABLE_NAME);
+  fprintf (output_file,
+          "  for (%s = 0; %s < %s; %s++)\n    %s [%s] = -1;\n}\n\n",
+          I_VARIABLE_NAME, I_VARIABLE_NAME, TEMPORARY_VARIABLE_NAME,
+          I_VARIABLE_NAME, DFA_INSN_CODES_VARIABLE_NAME, I_VARIABLE_NAME);
+}
+
+/* The function outputs PHR interface function `dfa_finish'.  */
+static void
+output_dfa_finish_func ()
+{
+  fprintf (output_file, "void\n%s ()\n{\n  free (%s);\n}\n\n",
+          DFA_FINISH_FUNC_NAME, DFA_INSN_CODES_VARIABLE_NAME);
+}
+
+\f
+
+/* The page contains code for output description file (readable
+   representation of original description and generated DFA(s).  */
+
+/* The function outputs string representation of IR reservation.  */
+static void
+output_regexp (regexp)
+     regexp_t regexp;
+{
+  fprintf (output_description_file, "%s", regexp_representation (regexp));
+  finish_regexp_representation ();
+}
+
+/* Output names of units in LIST separated by comma.  */
+static void
+output_unit_set_el_list (list)
+     unit_set_el_t list;
+{
+  unit_set_el_t el;
+
+  for (el = list; el != NULL; el = el->next_unit_set_el)
+    {
+      if (el != list)
+       fprintf (output_description_file, ",");
+      fprintf (output_description_file, "%s", el->unit_decl->name);
+    }
+}
+
+/* The function outputs string representation of IR define_reservation
+   and define_insn_reservation.  */
+static void
+output_description ()
+{
+  decl_t decl;
+  int i;
+
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit)
+       {
+         if (decl->decl.unit.excl_list != NULL)
+           {
+             fprintf (output_description_file, "unit %s exlusion_set: ",
+                      decl->decl.unit.name);
+             output_unit_set_el_list (decl->decl.unit.excl_list);
+             fprintf (output_description_file, "\n");
+           }
+         if (decl->decl.unit.presence_list != NULL)
+           {
+             fprintf (output_description_file, "unit %s presence_set: ",
+                      decl->decl.unit.name);
+             output_unit_set_el_list (decl->decl.unit.presence_list);
+             fprintf (output_description_file, "\n");
+           }
+         if (decl->decl.unit.absence_list != NULL)
+           {
+             fprintf (output_description_file, "unit %s absence_set: ",
+                      decl->decl.unit.name);
+             output_unit_set_el_list (decl->decl.unit.absence_list);
+             fprintf (output_description_file, "\n");
+           }
+       }
+    }
+  fprintf (output_description_file, "\n");
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_reserv)
+       {
+          fprintf (output_description_file, "reservation ");
+          fprintf (output_description_file, decl->decl.reserv.name);
+          fprintf (output_description_file, ": ");
+          output_regexp (decl->decl.reserv.regexp);
+          fprintf (output_description_file, "\n");
+        }
+      else if (decl->mode == dm_insn_reserv && decl != advance_cycle_insn_decl)
+        {
+          fprintf (output_description_file, "insn reservation %s ",
+                  decl->decl.insn_reserv.name);
+          print_rtl (output_description_file, decl->decl.insn_reserv.condexp);
+          fprintf (output_description_file, ": ");
+          output_regexp (decl->decl.insn_reserv.regexp);
+          fprintf (output_description_file, "\n");
+        }
+      else if (decl->mode == dm_bypass)
+       fprintf (output_description_file, "bypass %d %s %s\n",
+                decl->decl.bypass.latency, decl->decl.bypass.out_insn_name,
+                decl->decl.bypass.in_insn_name);
+    }
+  fprintf (output_description_file, "\n\f\n");
+}
+
+/* The function outputs name of AUTOMATON.  */
+static void
+output_automaton_name (f, automaton)
+     FILE *f;
+     automaton_t automaton;
+{
+  if (automaton->corresponding_automaton_decl == NULL)
+    fprintf (f, "#%d", automaton->automaton_order_num);
+  else
+    fprintf (f, "`%s'", automaton->corresponding_automaton_decl->name);
+}
+
+/* Maximal length of line for pretty printing into description
+   file.  */
+#define MAX_LINE_LENGTH 70
+
+/* The function outputs units name belonging to AUTOMATON.  */
+static void
+output_automaton_units (automaton)
+     automaton_t automaton;
+{
+  decl_t decl;
+  char *name;
+  int curr_line_length;
+  int there_is_an_automaton_unit;
+  int i;
+
+  fprintf (output_description_file, "\n  Coresponding units:\n");
+  fprintf (output_description_file, "    ");
+  curr_line_length = 4;
+  there_is_an_automaton_unit = 0;
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_unit
+          && (decl->decl.unit.corresponding_automaton_num
+             == automaton->automaton_order_num))
+       {
+         there_is_an_automaton_unit = 1;
+         name = decl->decl.unit.name;
+         if (curr_line_length + strlen (name) + 1 > MAX_LINE_LENGTH )
+           {
+             curr_line_length = strlen (name) + 4;
+             fprintf (output_description_file, "\n    ");
+           }
+         else
+           {
+             curr_line_length += strlen (name) + 1;
+             fprintf (output_description_file, " ");
+           }
+         fprintf (output_description_file, name);
+       }
+    }
+  if (!there_is_an_automaton_unit)
+    fprintf (output_description_file, "<None>");
+  fprintf (output_description_file, "\n\n");
+}
+
+/* The following variable is used for forming array of all possible cpu unit
+   reservations described by the current DFA state.  */
+static vla_ptr_t state_reservs;
+
+/* The function forms `state_reservs' for STATE.  */
+static void
+add_state_reservs (state)
+     state_t state;
+{
+  alt_state_t curr_alt_state;
+  reserv_sets_t reservs;
+
+  if (state->component_states != NULL)
+    for (curr_alt_state = state->component_states;
+         curr_alt_state != NULL;
+         curr_alt_state = curr_alt_state->next_sorted_alt_state)
+      add_state_reservs (curr_alt_state->state);
+  else
+    {
+      reservs = state->reservs;
+      VLA_PTR_ADD (state_reservs, reservs);
+    }
+}
+
+/* The function outputs readable represenatation of all out arcs of
+   STATE.  */
+static void
+output_state_arcs (state)
+     state_t state;
+{
+  arc_t arc;
+  ainsn_t ainsn;
+  char *insn_name;
+  int curr_line_length;
+
+  for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
+    {
+      ainsn = arc->insn;
+      if (!ainsn->first_insn_with_same_reservs)
+       abort ();
+      fprintf (output_description_file, "    ");
+      curr_line_length = 7;
+      fprintf (output_description_file, "%2d: ", ainsn->insn_equiv_class_num);
+      do
+        {
+          insn_name = ainsn->insn_reserv_decl->name;
+          if (curr_line_length + strlen (insn_name) > MAX_LINE_LENGTH)
+            {
+              if (ainsn != arc->insn)
+                {
+                  fprintf (output_description_file, ",\n      ");
+                  curr_line_length = strlen (insn_name) + 6;
+                }
+              else
+                curr_line_length += strlen (insn_name);
+            }
+          else
+            {
+              curr_line_length += strlen (insn_name);
+              if (ainsn != arc->insn)
+                {
+                  curr_line_length += 2;
+                  fprintf (output_description_file, ", ");
+                }
+            }
+          fprintf (output_description_file, insn_name);
+          ainsn = ainsn->next_same_reservs_insn;
+        }
+      while (ainsn != NULL);
+      fprintf (output_description_file, "    %d (%d)\n",
+              arc->to_state->order_state_num, arc->state_alts);
+    }
+  fprintf (output_description_file, "\n");
+}
+
+/* The following function is used for sorting possible cpu unit
+   reservation of a DFA state.  */
+static int
+state_reservs_cmp (reservs_ptr_1, reservs_ptr_2)
+     const void *reservs_ptr_1;
+     const void *reservs_ptr_2;
+{
+  return reserv_sets_cmp (*(reserv_sets_t *) reservs_ptr_1,
+                          *(reserv_sets_t *) reservs_ptr_2);
+}
+
+/* The following function is used for sorting possible cpu unit
+   reservation of a DFA state.  */
+static void
+remove_state_duplicate_reservs ()
+{
+  reserv_sets_t *reservs_ptr;
+  reserv_sets_t *last_formed_reservs_ptr;
+
+  last_formed_reservs_ptr = NULL;
+  for (reservs_ptr = VLA_PTR_BEGIN (state_reservs);
+       reservs_ptr <= (reserv_sets_t *) VLA_PTR_LAST (state_reservs);
+       reservs_ptr++)
+    if (last_formed_reservs_ptr == NULL)
+      last_formed_reservs_ptr = reservs_ptr;
+    else if (reserv_sets_cmp (*last_formed_reservs_ptr, *reservs_ptr) != 0)
+      {
+        ++last_formed_reservs_ptr;
+        *last_formed_reservs_ptr = *reservs_ptr;
+      }
+  VLA_PTR_SHORTEN (state_reservs, reservs_ptr - last_formed_reservs_ptr - 1);
+}
+
+/* The following function output readable representation of DFA(s)
+   state used for fast recognition of pipeline hazards.  State is
+   described by possible (current and scehduled) cpu unit
+   reservations.  */
+static void
+output_state (state)
+     state_t state;
+{
+  reserv_sets_t *reservs_ptr;
+
+  VLA_PTR_CREATE (state_reservs, 150, "state reservations");
+  fprintf (output_description_file, "  State #%d", state->order_state_num);
+  fprintf (output_description_file,
+          state->new_cycle_p ? " (new cycle)\n" : "\n");
+  add_state_reservs (state);
+  qsort (VLA_PTR_BEGIN (state_reservs), VLA_PTR_LENGTH (state_reservs),
+         sizeof (reserv_sets_t), state_reservs_cmp);
+  remove_state_duplicate_reservs ();
+  for (reservs_ptr = VLA_PTR_BEGIN (state_reservs);
+       reservs_ptr <= (reserv_sets_t *) VLA_PTR_LAST (state_reservs);
+       reservs_ptr++)
+    {
+      fprintf (output_description_file, "    ");
+      output_reserv_sets (output_description_file, *reservs_ptr);
+      fprintf (output_description_file, "\n");
+    }
+  fprintf (output_description_file, "\n");
+  output_state_arcs (state);
+  VLA_PTR_DELETE (state_reservs);
+}
+
+/* The following function output readable representation of
+   DFAs used for fast recognition of pipeline hazards.  */
+static void
+output_automaton_descriptions ()
+{
+  automaton_t automaton;
+
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    {
+      fprintf (output_description_file, "\nAutomaton ");
+      output_automaton_name (output_description_file, automaton);
+      fprintf (output_description_file, "\n");
+      output_automaton_units (automaton);
+      pass_states (automaton, output_state);
+    }
+}
+
+\f
+
+/* The page contains top level function for generation DFA(s) used for
+   PHR.  */
+
+/* The function outputs statistics about work of different phases of
+   DFA generator.  */
+static void
+output_statistics (f)
+     FILE *f;
+{
+  automaton_t automaton;
+#ifndef NDEBUG
+  int transition_comb_vect_els = 0;
+  int transition_full_vect_els = 0;
+  int state_alts_comb_vect_els = 0;
+  int state_alts_full_vect_els = 0;
+  int min_issue_delay_vect_els = 0;
+#endif
+
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    {
+      fprintf (f, "\nAutomaton ");
+      output_automaton_name (f, automaton);
+      fprintf (f, "\n    %5d NDFA states,          %5d NDFA arcs\n",
+              automaton->NDFA_states_num, automaton->NDFA_arcs_num);
+      fprintf (f, "    %5d DFA states,           %5d DFA arcs\n",
+              automaton->DFA_states_num, automaton->DFA_arcs_num);
+      if (!no_minimization_flag)
+       fprintf (f, "    %5d minimal DFA states,   %5d minimal DFA arcs\n",
+                automaton->minimal_DFA_states_num,
+                automaton->minimal_DFA_arcs_num);
+      fprintf (f, "    %5d all insns      %5d insn equivalence classes\n",
+              description->insns_num, automaton->insn_equiv_classes_num);
+#ifndef NDEBUG
+      fprintf
+       (f, "%5ld transition comb vector els, %5ld trans table els: %s\n",
+        (long) VLA_HWINT_LENGTH (automaton->trans_table->comb_vect),
+        (long) VLA_HWINT_LENGTH (automaton->trans_table->full_vect),
+        (comb_vect_p (automaton->trans_table)
+         ? "use comb vect" : "use simple vect"));
+      fprintf
+        (f, "%5ld state alts comb vector els, %5ld state alts table els: %s\n",
+         (long) VLA_HWINT_LENGTH (automaton->state_alts_table->comb_vect),
+         (long) VLA_HWINT_LENGTH (automaton->state_alts_table->full_vect),
+         (comb_vect_p (automaton->state_alts_table)
+          ? "use comb vect" : "use simple vect"));
+      fprintf
+        (f, "%5ld min delay table els, compression factor %d\n",
+         (long) automaton->DFA_states_num * automaton->insn_equiv_classes_num,
+        automaton->min_issue_delay_table_compression_factor);
+      transition_comb_vect_els
+       += VLA_HWINT_LENGTH (automaton->trans_table->comb_vect);
+      transition_full_vect_els 
+        += VLA_HWINT_LENGTH (automaton->trans_table->full_vect);
+      state_alts_comb_vect_els
+        += VLA_HWINT_LENGTH (automaton->state_alts_table->comb_vect);
+      state_alts_full_vect_els
+        += VLA_HWINT_LENGTH (automaton->state_alts_table->full_vect);
+      min_issue_delay_vect_els
+        += automaton->DFA_states_num * automaton->insn_equiv_classes_num;
+#endif
+    }
+#ifndef NDEBUG
+  fprintf (f, "\n%5d all allocated states,     %5d all allocated arcs\n",
+          allocated_states_num, allocated_arcs_num);
+  fprintf (f, "%5d all allocated alternative states\n",
+          allocated_alt_states_num);
+  fprintf (f, "%5d all transition comb vector els, %5d all trans table els\n",
+          transition_comb_vect_els, transition_full_vect_els);
+  fprintf
+    (f, "%5d all state alts comb vector els, %5d all state alts table els\n",
+     state_alts_comb_vect_els, state_alts_full_vect_els);
+  fprintf (f, "%5d all min delay table els\n", min_issue_delay_vect_els);
+  fprintf (f, "%5d locked states num\n", locked_states_num);
+#endif
+}
+
+/* The function output times of work of different phases of DFA
+   generator.  */
+static void
+output_time_statistics (f)
+     FILE *f;
+{
+  fprintf (f, "\n  transformation: ");
+  print_active_time (f, transform_time);
+  fprintf (f, (!ndfa_flag ? ", building DFA: " : ", building NDFA: "));
+  print_active_time (f, NDFA_time);
+  if (ndfa_flag)
+    {
+      fprintf (f, ", NDFA -> DFA: ");
+      print_active_time (f, NDFA_to_DFA_time);
+    }
+  fprintf (f, "\n  DFA minimization: ");
+  print_active_time (f, minimize_time);
+  fprintf (f, ", making insn equivalence: ");
+  print_active_time (f, equiv_time);
+  fprintf (f, "\n all automaton generation: ");
+  print_active_time (f, automaton_generation_time);
+  fprintf (f, ", output: ");
+  print_active_time (f, output_time);
+  fprintf (f, "\n");
+}
+
+/* The function generates DFA (deterministic finate state automaton)
+   for fast recognition of pipeline hazards.  No errors during
+   checking must be fixed before this function call.  */
+static void
+generate ()
+{
+  automata_num = split_argument;
+  if (description->units_num < automata_num)
+    automata_num = description->units_num;
+  initiate_states ();
+  initiate_arcs ();
+  initiate_pass_states ();
+  initiate_excl_sets ();
+  initiate_presence_absence_sets ();
+  automaton_generation_time = create_ticker ();
+  transform_time = create_ticker ();
+  add_advance_cycle_insn_decl ();
+  fprintf (stderr, "Reservation transformation...");
+  fflush (stderr);
+  transform_insn_regexps ();
+  fprintf (stderr, "done\n");
+  ticker_off (&transform_time);
+  fprintf (stderr, "Create automata...");
+  fflush (stderr);
+  create_automata ();
+  fprintf (stderr, "done\n");
+  ticker_off (&automaton_generation_time);
+}
+
+\f
+
+/* The following function creates attribute which order number of insn
+   in pipeline hazard description translator.  */
+static void
+make_insn_alts_attr ()
+{
+  int i, insn_num;
+  decl_t decl;
+  rtx condexp;
+
+  condexp = rtx_alloc (COND);
+  XVEC (condexp, 0) = rtvec_alloc ((description->insns_num - 1) * 2);
+  XEXP (condexp, 1) = make_numeric_value (0);
+  for (i = insn_num = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv && decl != advance_cycle_insn_decl)
+       {
+          XVECEXP (condexp, 0, 2 * insn_num) = decl->decl.insn_reserv.condexp;
+          XVECEXP (condexp, 0, 2 * insn_num + 1)
+            = make_numeric_value (decl->decl.insn_reserv.transformed_regexp
+                                 ->regexp.oneof.regexps_num);
+          insn_num++;
+        }
+    }
+  if (description->insns_num != insn_num + 1)
+    abort ();
+  make_internal_attr (attr_printf (sizeof ("*")
+                                  + strlen (INSN_ALTS_FUNC_NAME) + 1,
+                                  "*%s", INSN_ALTS_FUNC_NAME),
+                     condexp, 0);
+}
+
+\f
+
+/* The following function creates attribute which is order number of
+   insn in pipeline hazard description translator.  */
+static void
+make_internal_dfa_insn_code_attr ()
+{
+  int i, insn_num;
+  decl_t decl;
+  rtx condexp;
+
+  condexp = rtx_alloc (COND);
+  XVEC (condexp, 0) = rtvec_alloc ((description->insns_num - 1) * 2);
+  XEXP (condexp, 1) = make_numeric_value (advance_cycle_insn_decl
+                                         ->decl.insn_reserv.insn_num + 1);
+  for (i = insn_num = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv && decl != advance_cycle_insn_decl)
+       {
+          XVECEXP (condexp, 0, 2 * insn_num) = decl->decl.insn_reserv.condexp;
+          XVECEXP (condexp, 0, 2 * insn_num + 1)
+            = make_numeric_value (decl->decl.insn_reserv.insn_num);
+          insn_num++;
+        }
+    }
+  if (description->insns_num != insn_num + 1)
+    abort ();
+  make_internal_attr
+    (attr_printf (sizeof ("*")
+                 + strlen (INTERNAL_DFA_INSN_CODE_FUNC_NAME) + 1,
+                 "*%s", INTERNAL_DFA_INSN_CODE_FUNC_NAME),
+     condexp, 0);
+}
+
+\f
+
+/* The following function creates attribute which order number of insn
+   in pipeline hazard description translator.  */
+static void
+make_default_insn_latency_attr ()
+{
+  int i, insn_num;
+  decl_t decl;
+  rtx condexp;
+
+  condexp = rtx_alloc (COND);
+  XVEC (condexp, 0) = rtvec_alloc ((description->insns_num - 1) * 2);
+  XEXP (condexp, 1) = make_numeric_value (0);
+  for (i = insn_num = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv && decl != advance_cycle_insn_decl)
+       {
+          XVECEXP (condexp, 0, 2 * insn_num) = decl->decl.insn_reserv.condexp;
+          XVECEXP (condexp, 0, 2 * insn_num + 1)
+            = make_numeric_value (decl->decl.insn_reserv.default_latency);
+          insn_num++;
+        }
+    }
+  if (description->insns_num != insn_num + 1)
+    abort ();
+  make_internal_attr (attr_printf (sizeof ("*")
+                                  + strlen (INSN_DEFAULT_LATENCY_FUNC_NAME)
+                                  + 1, "*%s", INSN_DEFAULT_LATENCY_FUNC_NAME),
+                     condexp, 0);
+}
+
+\f
+
+/* The following function creates attribute which returns 1 if given
+   output insn has bypassing and 0 otherwise.  */
+static void
+make_bypass_attr ()
+{
+  int i, bypass_insn;
+  int bypass_insns_num = 0;
+  decl_t decl;
+  rtx result_rtx;
+  
+  for (i = 0; i < description->decls_num; i++)
+    {
+      decl = description->decls [i];
+      if (decl->mode == dm_insn_reserv
+         && decl->decl.insn_reserv.condexp != NULL
+         && decl->decl.insn_reserv.bypass_list != NULL)
+       bypass_insns_num++;
+    }
+  if (bypass_insns_num == 0)
+    result_rtx = make_numeric_value (0);
+  else
+    {
+      result_rtx = rtx_alloc (COND);
+      XVEC (result_rtx, 0) = rtvec_alloc (bypass_insns_num * 2);
+      XEXP (result_rtx, 1) = make_numeric_value (0);
+
+      for (i = bypass_insn = 0; i < description->decls_num; i++)
+        {
+          decl = description->decls [i];
+          if (decl->mode == dm_insn_reserv
+             && decl->decl.insn_reserv.condexp != NULL
+             && decl->decl.insn_reserv.bypass_list != NULL)
+           {
+              XVECEXP (result_rtx, 0, 2 * bypass_insn)
+               = decl->decl.insn_reserv.condexp;
+              XVECEXP (result_rtx, 0, 2 * bypass_insn + 1)
+               = make_numeric_value (1);
+              bypass_insn++;
+            }
+        }
+    }
+  make_internal_attr (attr_printf (sizeof ("*")
+                                  + strlen (BYPASS_P_FUNC_NAME) + 1,
+                                  "*%s", BYPASS_P_FUNC_NAME),
+                     result_rtx, 0);
+}
+
+\f
+
+/* This page mainly contains top level functions of pipeline hazards
+   description translator.  */
+
+/* The following macro value is suffix of name of description file of
+   pipeline hazards description translator.  */
+#define STANDARD_OUTPUT_DESCRIPTION_FILE_SUFFIX ".dfa"
+
+/* The function returns suffix of given file name.  The returned
+   string can not be changed.  */
+static const char *
+file_name_suffix (file_name)
+     const char *file_name;
+{
+  const char *last_period;
+
+  for (last_period = NULL; *file_name != '\0'; file_name++)
+    if (*file_name == '.')
+      last_period = file_name;
+  return (last_period == NULL ? file_name : last_period);
+}
+
+/* The function returns base name of given file name, i.e. pointer to
+   first char after last `/' (or `\' for WIN32) in given file name,
+   given file name itself if the directory name is absent.  The
+   returned string can not be changed.  */
+static const char *
+base_file_name (file_name)
+     const char *file_name;
+{
+  int directory_name_length;
+
+  directory_name_length = strlen (file_name);
+#ifdef WIN32
+  while (directory_name_length >= 0 && file_name[directory_name_length] != '/'
+         && file_name[directory_name_length] != '\\')
+#else
+  while (directory_name_length >= 0 && file_name[directory_name_length] != '/')
+#endif
+    directory_name_length--;
+  return file_name + directory_name_length + 1;
+}
+
+/* The following is top level function to initialize the work of
+   pipeline hazards description translator.  */
+void
+initiate_automaton_gen (argc, argv)
+     int argc;
+     char **argv;
+{
+  const char *base_name;
+  int i;
+
+  ndfa_flag = 0;
+  split_argument = 0;  /* default value */
+  no_minimization_flag = 0;
+  time_flag = 0;
+  v_flag = 0;
+  w_flag = 0;
+  for (i = 2; i < argc; i++)
+    if (strcmp (argv [i], NO_MINIMIZATION_OPTION) == 0)
+      no_minimization_flag = 1;
+    else if (strcmp (argv [i], "-time") == 0)
+      time_flag = 1;
+    else if (strcmp (argv [i], "-v") == 0)
+      v_flag = 1;
+    else if (strcmp (argv [i], W_OPTION) == 0)
+      w_flag = 1;
+    else if (strcmp (argv [i], NDFA_OPTION) == 0)
+      ndfa_flag = 1;
+    else if (strcmp (argv [i], "-split") == 0)
+      {
+       if (i + 1 >= argc)
+         fatal ("-split has no argument.");
+       fatal ("option `-split' has not been implemented yet\n");
+       /* split_argument = atoi (argument_vect [i + 1]); */
+      }
+  VLA_PTR_CREATE (decls, 150, "decls");
+  /* Initialize IR storage.  */
+  obstack_init (&irp);
+  initiate_automaton_decl_table ();
+  initiate_insn_decl_table ();
+  initiate_decl_table ();
+  output_file = stdout;
+  output_description_file = NULL;
+  base_name = base_file_name (argv[1]);
+  obstack_grow (&irp, base_name,
+               strlen (base_name) - strlen (file_name_suffix (base_name)));
+  obstack_grow (&irp, STANDARD_OUTPUT_DESCRIPTION_FILE_SUFFIX,
+               strlen (STANDARD_OUTPUT_DESCRIPTION_FILE_SUFFIX) + 1);
+  obstack_1grow (&irp, '\0');
+  output_description_file_name = obstack_base (&irp);
+  obstack_finish (&irp);
+}
+
+/* The following function checks existence at least one arc marked by
+   each insn.  */
+static void
+check_automata ()
+{
+  automaton_t automaton;
+  ainsn_t ainsn, reserv_ainsn;
+
+  for (automaton = description->first_automaton;
+       automaton != NULL;
+       automaton = automaton->next_automaton)
+    {
+      for (ainsn = automaton->ainsn_list;
+          ainsn != NULL;
+          ainsn = ainsn->next_ainsn)
+       if (ainsn->first_insn_with_same_reservs && !ainsn->arc_exists_p)
+         {
+           for (reserv_ainsn = ainsn;
+                reserv_ainsn != NULL;
+                reserv_ainsn = reserv_ainsn->next_same_reservs_insn)
+             if (automaton->corresponding_automaton_decl != NULL)
+               {
+                 if (!w_flag)
+                   error ("Automaton `%s': Insn `%s' will never be issued",
+                          automaton->corresponding_automaton_decl->name,
+                          reserv_ainsn->insn_reserv_decl->name);
+                 else
+                   warning
+                     ("Automaton `%s': Insn `%s' will never be issued",
+                      automaton->corresponding_automaton_decl->name,
+                      reserv_ainsn->insn_reserv_decl->name);
+               }
+             else
+               {
+                 if (!w_flag)
+                   error ("Insn `%s' will never be issued",
+                          reserv_ainsn->insn_reserv_decl->name);
+                 else
+                   warning ("Insn `%s' will never be issued",
+                            reserv_ainsn->insn_reserv_decl->name);
+               }
+         }
+    }
+}
+
+/* The following is top level function to generate automat(a,on) for
+   fast recognition of pipeline hazards.  */
+void
+expand_automata ()
+{
+  int i;
+
+  if (VLA_PTR_LENGTH (decls) != 0)
+    {
+      description = create_node (sizeof (struct description)
+                                + sizeof (decl_t)
+                                /* One entry for cycle advancing insn.  */
+                                * VLA_PTR_LENGTH (decls));
+      description->decls_num = VLA_PTR_LENGTH (decls);
+      description->query_units_num = 0;
+      for (i = 0; i < description->decls_num; i++)
+       {
+         description->decls [i] = VLA_PTR (decls, i);
+         if (description->decls [i]->mode == dm_unit
+             && description->decls [i]->decl.unit.query_p)
+           description->decls [i]->decl.unit.query_num
+             = description->query_units_num++;
+       }
+      all_time = create_ticker ();
+      check_time = create_ticker ();
+      fprintf (stderr, "Check description...");
+      fflush (stderr);
+      check_all_description ();
+      fprintf (stderr, "done\n");
+      ticker_off (&check_time);
+      generation_time = create_ticker ();
+      if (!have_error)
+       {
+         generate ();
+         check_automata ();
+         if (!have_error)
+           {
+             fprintf (stderr, "Generation of attributes...");
+             fflush (stderr);
+             make_internal_dfa_insn_code_attr ();
+             make_insn_alts_attr ();
+             make_default_insn_latency_attr ();
+             make_bypass_attr ();
+             fprintf (stderr, "done\n");
+           }
+       }
+      ticker_off (&generation_time);
+      ticker_off (&all_time);
+    }
+  fprintf (stderr, "All other genattrtab stuff...");
+  fflush (stderr);
+}
+
+/* The following is top level function to output PHR and to finish
+   work with pipeline description translator.  */
+void
+write_automata ()
+{
+  fprintf (stderr, "done\n");
+  if (have_error)
+    fatal ("Errors in DFA description");
+  ticker_on (&all_time);
+  output_time = create_ticker ();
+  fprintf (stderr, "Forming and outputing automata tables...");
+  fflush (stderr);
+  output_dfa_max_issue_rate ();
+  output_tables ();
+  fprintf (stderr, "done\n");
+  fprintf (stderr, "Output functions to work with automata...");
+  fflush (stderr);
+  output_chip_definitions ();
+  output_max_insn_queue_index_def ();
+  output_internal_min_issue_delay_func ();
+  output_internal_trans_func ();
+  /* Cache of insn dfa codes: */
+  fprintf (output_file, "\nstatic int *%s;\n\n", DFA_INSN_CODES_VARIABLE_NAME);
+  output_dfa_insn_code_func ();
+  output_trans_func ();
+  fprintf (output_file, "\n#if %s\n\n", AUTOMATON_STATE_ALTS_MACRO_NAME);
+  output_internal_state_alts_func ();
+  output_state_alts_func ();
+  fprintf (output_file, "\n#endif /* #if %s */\n\n",
+          AUTOMATON_STATE_ALTS_MACRO_NAME);
+  output_min_issue_delay_func ();
+  output_internal_dead_lock_func ();
+  output_dead_lock_func ();
+  output_size_func ();
+  output_internal_reset_func ();
+  output_reset_func ();
+  output_min_insn_conflict_delay_func ();
+  output_internal_insn_latency_func ();
+  output_insn_latency_func ();
+  output_print_reservation_func ();
+  if (no_minimization_flag)
+    {
+      fprintf (output_file, "\n#if %s\n\n", CPU_UNITS_QUERY_MACRO_NAME);
+      output_get_cpu_unit_code_func ();
+      output_cpu_unit_reservation_p ();
+      fprintf (output_file, "\n#endif /* #if %s */\n\n",
+              CPU_UNITS_QUERY_MACRO_NAME);
+    }
+  output_dfa_start_func ();
+  output_dfa_finish_func ();
+  fprintf (stderr, "done\n");
+  if (v_flag)
+    {
+      output_description_file = fopen (output_description_file_name, "w");
+      if (output_description_file == NULL)
+       {
+         perror (output_description_file_name);
+         exit (FATAL_EXIT_CODE);
+       }
+      fprintf (stderr, "Output automata description...");
+      fflush (stderr);
+      output_description ();
+      output_automaton_descriptions ();
+      fprintf (stderr, "done\n");
+      output_statistics (output_description_file);
+    }
+  output_statistics (stderr);
+  ticker_off (&output_time);
+  output_time_statistics (stderr);
+  finish_states ();
+  finish_arcs ();
+  if (time_flag)
+    {
+      fprintf (stderr, "Summary:\n");
+      fprintf (stderr, "  check time ");
+      print_active_time (stderr, check_time);
+      fprintf (stderr, ", generation time ");
+      print_active_time (stderr, generation_time);
+      fprintf (stderr, ", all time ");
+      print_active_time (stderr, all_time);
+      fprintf (stderr, "\n");
+    }
+  /* Finish all work.  */
+  if (output_description_file != NULL)
+    {
+      fflush (output_description_file);
+      if (ferror (stdout) != 0)
+       fatal ("Error in writing DFA description file %s",
+               output_description_file_name);
+      fclose (output_description_file);
+    }
+  finish_automaton_decl_table ();
+  finish_insn_decl_table ();
+  finish_decl_table ();
+  obstack_free (&irp, NULL);
+  if (have_error && output_description_file != NULL)
+    remove (output_description_file_name);
+}
index 3fea98c..fa42745 100644 (file)
@@ -158,6 +158,12 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 
 static int issue_rate;
 
+/* If the following variable value is non zero, the scheduler inserts
+   bubbles (nop insns).  The value of variable affects on scheduler
+   behavior only if automaton pipeline interface with multipass
+   scheduling is used and hook dfa_bubble is defined.  */
+int insert_schedule_bubbles_p = 0;
+
 /* sched-verbose controls the amount of debugging output the
    scheduler prints.  It is controlled by -fsched-verbose=N:
    N>0 and no -DSR : the output is directed to stderr.
@@ -254,14 +260,39 @@ static rtx note_list;
    passes or stalls are introduced.  */
 
 /* Implement a circular buffer to delay instructions until sufficient
-   time has passed.  INSN_QUEUE_SIZE is a power of two larger than
-   MAX_BLOCKAGE and MAX_READY_COST computed by genattr.c.  This is the
-   longest time an isnsn may be queued.  */
-static rtx insn_queue[INSN_QUEUE_SIZE];
+   time has passed.  For the old pipeline description interface,
+   INSN_QUEUE_SIZE is a power of two larger than MAX_BLOCKAGE and
+   MAX_READY_COST computed by genattr.c.  For the new pipeline
+   description interface, MAX_INSN_QUEUE_INDEX is a power of two minus
+   one which is larger than maximal time of instruction execution
+   computed by genattr.c on the base maximal time of functional unit
+   reservations and geting a result.  This is the longest time an
+   insn may be queued.  */
+
+#define MAX_INSN_QUEUE_INDEX max_insn_queue_index_macro_value
+
+static rtx *insn_queue;
 static int q_ptr = 0;
 static int q_size = 0;
-#define NEXT_Q(X) (((X)+1) & (INSN_QUEUE_SIZE-1))
-#define NEXT_Q_AFTER(X, C) (((X)+C) & (INSN_QUEUE_SIZE-1))
+#define NEXT_Q(X) (((X)+1) & MAX_INSN_QUEUE_INDEX)
+#define NEXT_Q_AFTER(X, C) (((X)+C) & MAX_INSN_QUEUE_INDEX)
+
+/* The following variable defines value for macro
+   MAX_INSN_QUEUE_INDEX.  */
+static int max_insn_queue_index_macro_value;
+
+/* The following variable value refers for all current and future
+   reservations of the processor units.  */
+state_t curr_state;
+
+/* The following variable value is size of memory representing all
+   current and future reservations of the processor units.  It is used
+   only by DFA based scheduler.  */
+static size_t dfa_state_size;
+
+/* The following array is used to find the best insn from ready when
+   the automaton pipeline interface is used.  */
+static char *ready_try;
 
 /* Describe the ready list of the scheduler.
    VEC holds space enough for all insns in the current region.  VECLEN
@@ -280,11 +311,15 @@ struct ready_list
 };
 
 /* Forward declarations.  */
+
+/* The scheduler using only DFA description should never use the
+   following five functions:  */
 static unsigned int blockage_range PARAMS ((int, rtx));
 static void clear_units PARAMS ((void));
 static void schedule_unit PARAMS ((int, rtx, int));
 static int actual_hazard PARAMS ((int, rtx, int, int));
 static int potential_hazard PARAMS ((int, rtx, int));
+
 static int priority PARAMS ((rtx));
 static int rank_for_schedule PARAMS ((const PTR, const PTR));
 static void swap_sort PARAMS ((rtx *, int));
@@ -331,6 +366,14 @@ static void debug_ready_list PARAMS ((struct ready_list *));
 static rtx move_insn1 PARAMS ((rtx, rtx));
 static rtx move_insn PARAMS ((rtx, rtx));
 
+/* The following functions are used to implement multi-pass scheduling
+   on the first cycle.  It is used only for DFA based scheduler.  */
+static rtx ready_element PARAMS ((struct ready_list *, int));
+static rtx ready_remove PARAMS ((struct ready_list *, int));
+static int max_issue PARAMS ((struct ready_list *, state_t, int *, int *));
+
+static rtx choose_ready PARAMS ((struct ready_list *));
+
 #endif /* INSN_SCHEDULING */
 \f
 /* Point to state used for the current scheduling pass.  */
@@ -354,7 +397,8 @@ static rtx last_scheduled_insn;
    returned by function_units_used.  A function unit is encoded as the
    unit number if the value is non-negative and the compliment of a
    mask if the value is negative.  A function unit index is the
-   non-negative encoding.  */
+   non-negative encoding.  The scheduler using only DFA description
+   should never use the following function.  */
 
 HAIFA_INLINE int
 insn_unit (insn)
@@ -391,7 +435,9 @@ insn_unit (insn)
 /* Compute the blockage range for executing INSN on UNIT.  This caches
    the value returned by the blockage_range_function for the unit.
    These values are encoded in an int where the upper half gives the
-   minimum value and the lower half gives the maximum value.  */
+   minimum value and the lower half gives the maximum value.  The
+   scheduler using only DFA description should never use the following
+   function.  */
 
 HAIFA_INLINE static unsigned int
 blockage_range (unit, insn)
@@ -415,20 +461,38 @@ blockage_range (unit, insn)
   return range;
 }
 
-/* A vector indexed by function unit instance giving the last insn to use
-   the unit.  The value of the function unit instance index for unit U
-   instance I is (U + I * FUNCTION_UNITS_SIZE).  */
+/* A vector indexed by function unit instance giving the last insn to
+   use the unit.  The value of the function unit instance index for
+   unit U instance I is (U + I * FUNCTION_UNITS_SIZE).  The scheduler
+   using only DFA description should never use the following variable.  */
+#if FUNCTION_UNITS_SIZE
 static rtx unit_last_insn[FUNCTION_UNITS_SIZE * MAX_MULTIPLICITY];
+#else
+static rtx unit_last_insn[1];
+#endif
 
-/* A vector indexed by function unit instance giving the minimum time when
-   the unit will unblock based on the maximum blockage cost.  */
+/* A vector indexed by function unit instance giving the minimum time
+   when the unit will unblock based on the maximum blockage cost.  The
+   scheduler using only DFA description should never use the following
+   variable.  */
+#if FUNCTION_UNITS_SIZE
 static int unit_tick[FUNCTION_UNITS_SIZE * MAX_MULTIPLICITY];
+#else
+static int unit_tick[1];
+#endif
 
 /* A vector indexed by function unit number giving the number of insns
-   that remain to use the unit.  */
+   that remain to use the unit.  The scheduler using only DFA
+   description should never use the following variable.  */
+#if FUNCTION_UNITS_SIZE
 static int unit_n_insns[FUNCTION_UNITS_SIZE];
+#else
+static int unit_n_insns[1];
+#endif
 
-/* Access the unit_last_insn array.  Used by the visualization code.  */
+/* Access the unit_last_insn array.  Used by the visualization code.
+   The scheduler using only DFA description should never use the
+   following function.  */
 
 rtx
 get_unit_last_insn (instance)
@@ -447,7 +511,8 @@ clear_units ()
   memset ((char *) unit_n_insns, 0, sizeof (unit_n_insns));
 }
 
-/* Return the issue-delay of an insn.  */
+/* Return the issue-delay of an insn.  The scheduler using only DFA
+   description should never use the following function.  */
 
 HAIFA_INLINE int
 insn_issue_delay (insn)
@@ -477,7 +542,8 @@ insn_issue_delay (insn)
 
 /* Return the actual hazard cost of executing INSN on the unit UNIT,
    instance INSTANCE at time CLOCK if the previous actual hazard cost
-   was COST.  */
+   was COST.  The scheduler using only DFA description should never
+   use the following function.  */
 
 HAIFA_INLINE int
 actual_hazard_this_instance (unit, instance, insn, clock, cost)
@@ -513,8 +579,9 @@ actual_hazard_this_instance (unit, instance, insn, clock, cost)
   return cost;
 }
 
-/* Record INSN as having begun execution on the units encoded by UNIT at
-   time CLOCK.  */
+/* Record INSN as having begun execution on the units encoded by UNIT
+   at time CLOCK.  The scheduler using only DFA description should
+   never use the following function.  */
 
 HAIFA_INLINE static void
 schedule_unit (unit, insn, clock)
@@ -545,8 +612,10 @@ schedule_unit (unit, insn, clock)
        schedule_unit (i, insn, clock);
 }
 
-/* Return the actual hazard cost of executing INSN on the units encoded by
-   UNIT at time CLOCK if the previous actual hazard cost was COST.  */
+/* Return the actual hazard cost of executing INSN on the units
+   encoded by UNIT at time CLOCK if the previous actual hazard cost
+   was COST.  The scheduler using only DFA description should never
+   use the following function.  */
 
 HAIFA_INLINE static int
 actual_hazard (unit, insn, clock, cost)
@@ -591,11 +660,13 @@ actual_hazard (unit, insn, clock, cost)
 }
 
 /* Return the potential hazard cost of executing an instruction on the
-   units encoded by UNIT if the previous potential hazard cost was COST.
-   An insn with a large blockage time is chosen in preference to one
-   with a smaller time; an insn that uses a unit that is more likely
-   to be used is chosen in preference to one with a unit that is less
-   used.  We are trying to minimize a subsequent actual hazard.  */
+   units encoded by UNIT if the previous potential hazard cost was
+   COST.  An insn with a large blockage time is chosen in preference
+   to one with a smaller time; an insn that uses a unit that is more
+   likely to be used is chosen in preference to one with a unit that
+   is less used.  We are trying to minimize a subsequent actual
+   hazard.  The scheduler using only DFA description should never use
+   the following function.  */
 
 HAIFA_INLINE static int
 potential_hazard (unit, insn, cost)
@@ -648,62 +719,67 @@ insn_cost (insn, link, used)
 {
   register int cost = INSN_COST (insn);
 
-  if (cost == 0)
+  if (cost < 0)
     {
-      recog_memoized (insn);
-
-      /* A USE insn, or something else we don't need to understand.
-         We can't pass these directly to result_ready_cost because it will
-         trigger a fatal error for unrecognizable insns.  */
-      if (INSN_CODE (insn) < 0)
+      /* A USE insn, or something else we don't need to
+        understand.  We can't pass these directly to
+        result_ready_cost or insn_default_latency because it will
+        trigger a fatal error for unrecognizable insns.  */
+      if (recog_memoized (insn) < 0)
        {
-         INSN_COST (insn) = 1;
-         return 1;
+         INSN_COST (insn) = 0;
+         return 0;
        }
       else
        {
-         cost = result_ready_cost (insn);
-
-         if (cost < 1)
-           cost = 1;
-
+         if (targetm.sched.use_dfa_pipeline_interface)
+           cost = insn_default_latency (insn);
+         else
+           cost = result_ready_cost (insn);
+         
+         if (cost < 0)
+           cost = 0;
+         
          INSN_COST (insn) = cost;
        }
     }
 
   /* In this case estimate cost without caring how insn is used.  */
-  if (link == 0 && used == 0)
+  if (link == 0 || used == 0)
     return cost;
 
-  /* A USE insn should never require the value used to be computed.  This
-     allows the computation of a function's result and parameter values to
-     overlap the return and call.  */
-  recog_memoized (used);
-  if (INSN_CODE (used) < 0)
-    LINK_COST_FREE (link) = 1;
-
-  /* If some dependencies vary the cost, compute the adjustment.  Most
-     commonly, the adjustment is complete: either the cost is ignored
-     (in the case of an output- or anti-dependence), or the cost is
-     unchanged.  These values are cached in the link as LINK_COST_FREE
-     and LINK_COST_ZERO.  */
-
-  if (LINK_COST_FREE (link))
+  /* A USE insn should never require the value used to be computed.
+     This allows the computation of a function's result and parameter
+     values to overlap the return and call.  */
+  if (recog_memoized (used) < 0)
     cost = 0;
-  else if (!LINK_COST_ZERO (link) && targetm.sched.adjust_cost)
+  else
     {
-      int ncost = (*targetm.sched.adjust_cost) (used, link, insn, cost);
-
-      if (ncost < 1)
+      if (targetm.sched.use_dfa_pipeline_interface)
        {
-         LINK_COST_FREE (link) = 1;
-         ncost = 0;
+         if (INSN_CODE (insn) >= 0)
+           {
+             if (REG_NOTE_KIND (link) == REG_DEP_ANTI)
+               cost = 0;
+             else if (REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
+               {
+                 cost = (insn_default_latency (insn)
+                         - insn_default_latency (used));
+                 if (cost <= 0)
+                   cost = 1;
+               }
+             else if (bypass_p (insn))
+               cost = insn_latency (insn, used);
+           }
        }
-      if (cost == ncost)
-       LINK_COST_ZERO (link) = 1;
-      cost = ncost;
-    }
 
+      if (targetm.sched.adjust_cost)
+       cost = (*targetm.sched.adjust_cost) (used, link, insn, cost);
+
+      if (cost < 0)
+       cost = 0;
+    }
+  
   return cost;
 }
 
@@ -930,6 +1006,48 @@ ready_remove_first (ready)
   return t;
 }
 
+/* The following code implements multi-pass scheduling for the first
+   cycle.  In other words, we will try to choose ready insn which
+   permits to start maximum number of insns on the same cycle.  */
+
+/* Return a pointer to the element INDEX from the ready.  INDEX for
+   insn with the highest priority is 0, and the lowest priority has
+   N_READY - 1.  */
+
+HAIFA_INLINE static rtx
+ready_element (ready, index)
+     struct ready_list *ready;
+     int index;
+{
+  if (ready->n_ready == 0 || index >= ready->n_ready)
+    abort ();
+  return ready->vec[ready->first - index];
+}
+
+/* Remove the element INDEX from the ready list and return it.  INDEX
+   for insn with the highest priority is 0, and the lowest priority
+   has N_READY - 1.  */
+
+HAIFA_INLINE static rtx
+ready_remove (ready, index)
+     struct ready_list *ready;
+     int index;
+{
+  rtx t;
+  int i;
+
+  if (index == 0)
+    return ready_remove_first (ready);
+  if (ready->n_ready == 0 || index >= ready->n_ready)
+    abort ();
+  t = ready->vec[ready->first - index];
+  ready->n_ready--;
+  for (i = index; i < ready->n_ready; i++)
+    ready [ready->first - i] = ready [ready->first - i - 1];
+  return t;
+}
+
+
 /* Sort the ready list READY by ascending priority, using the SCHED_SORT
    macro.  */
 
@@ -976,26 +1094,47 @@ schedule_insn (insn, ready, clock)
      int clock;
 {
   rtx link;
-  int unit;
+  int unit = 0;
 
-  unit = insn_unit (insn);
+  if (!targetm.sched.use_dfa_pipeline_interface)
+    unit = insn_unit (insn);
 
   if (sched_verbose >= 2)
     {
-      fprintf (sched_dump, ";;\t\t--> scheduling insn <<<%d>>> on unit ",
-              INSN_UID (insn));
-      insn_print_units (insn);
+
+      if (targetm.sched.use_dfa_pipeline_interface)
+       {
+         fprintf (sched_dump,
+                  ";;\t\t--> scheduling insn <<<%d>>>:reservation ",
+                  INSN_UID (insn));
+         
+         if (recog_memoized (insn) < 0)
+           fprintf (sched_dump, "nothing");
+         else
+           print_reservation (sched_dump, insn);
+       }
+      else
+       {
+         fprintf (sched_dump, ";;\t\t--> scheduling insn <<<%d>>> on unit ",
+                  INSN_UID (insn));
+         insn_print_units (insn);
+       }
+
       fprintf (sched_dump, "\n");
     }
 
-  if (sched_verbose && unit == -1)
-    visualize_no_unit (insn);
+  if (!targetm.sched.use_dfa_pipeline_interface)
+    {
+      if (sched_verbose && unit == -1)
+       visualize_no_unit (insn);
 
-  if (MAX_BLOCKAGE > 1 || issue_rate > 1 || sched_verbose)
-    schedule_unit (unit, insn, clock);
 
-  if (INSN_DEPEND (insn) == 0)
-    return;
+      if (MAX_BLOCKAGE > 1 || issue_rate > 1 || sched_verbose)
+       schedule_unit (unit, insn, clock);
+      
+      if (INSN_DEPEND (insn) == 0)
+       return;
+    }
 
   for (link = INSN_DEPEND (insn); link != 0; link = XEXP (link, 1))
     {
@@ -1037,7 +1176,9 @@ schedule_insn (insn, ready, clock)
      to issue on the same cycle as the previous insn.  A machine
      may use this information to decide how the instruction should
      be aligned.  */
-  if (reload_completed && issue_rate > 1)
+  if (reload_completed && issue_rate > 1
+      && GET_CODE (PATTERN (insn)) != USE
+      && GET_CODE (PATTERN (insn)) != CLOBBER)
     {
       PUT_MODE (insn, clock > last_clock_var ? TImode : VOIDmode);
       last_clock_var = clock;
@@ -1464,7 +1605,7 @@ queue_to_ready (ready)
     {
       register int stalls;
 
-      for (stalls = 1; stalls < INSN_QUEUE_SIZE; stalls++)
+      for (stalls = 1; stalls <= MAX_INSN_QUEUE_INDEX; stalls++)
        {
          if ((link = insn_queue[NEXT_Q_AFTER (q_ptr, stalls)]))
            {
@@ -1483,13 +1624,28 @@ queue_to_ready (ready)
                }
              insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = 0;
 
+             /* Advance time on one cycle.  */
+             if (targetm.sched.use_dfa_pipeline_interface)
+               {
+                 if (targetm.sched.dfa_pre_cycle_insn)
+                   state_transition (curr_state,
+                                     (*targetm.sched.dfa_pre_cycle_insn) ());
+
+                 state_transition (curr_state, NULL);
+
+                 if (targetm.sched.dfa_post_cycle_insn)
+                   state_transition (curr_state,
+                                     (*targetm.sched.dfa_post_cycle_insn) ());
+               }
+
              if (ready->n_ready)
                break;
            }
        }
 
-      if (sched_verbose && stalls)
+      if (!targetm.sched.use_dfa_pipeline_interface && sched_verbose && stalls)
        visualize_stall_cycles (stalls);
+
       q_ptr = NEXT_Q_AFTER (q_ptr, stalls);
       clock_var += stalls;
     }
@@ -1505,7 +1661,10 @@ debug_ready_list (ready)
   int i;
 
   if (ready->n_ready == 0)
-    return;
+    {
+      fprintf (sched_dump, "\n");
+      return;
+    }
 
   p = ready_lastpos (ready);
   for (i = 0; i < ready->n_ready; i++)
@@ -1617,6 +1776,117 @@ move_insn (insn, last)
   return retval;
 }
 
+/* The following function returns maximal (or close to maximal) number
+   of insns which can be issued on the same cycle and one of which
+   insns is insns with the best rank (the last insn in READY).  To
+   make this function tries different samples of ready insns.  READY
+   is current queue `ready'.  Global array READY_TRY reflects what
+   insns are already issued in this try.  STATE is current processor
+   state.  If the function returns nonzero, INDEX will contain index
+   of the best insn in READY.  *LAST_P is nonzero if the insn with the
+   highest rank is in the current sample.  The following function is
+   used only for first cycle multipass scheduling.  */
+
+static int
+max_issue (ready, state, index, last_p)
+     struct ready_list *ready;
+     state_t state;
+     int *index;
+     int *last_p;
+     
+{
+  int i, best, n, temp_index, delay;
+  state_t temp_state;
+  rtx insn;
+  int max_lookahead = (*targetm.sched.first_cycle_multipass_dfa_lookahead) ();
+
+  if (state_dead_lock_p (state))
+    return 0;
+  
+  temp_state = alloca (dfa_state_size);
+  best = 0;
+  
+  for (i = 0; i < ready->n_ready; i++)
+    if (!ready_try [i])
+      {
+       insn = ready_element (ready, i);
+       
+       if (INSN_CODE (insn) < 0)
+         continue;
+       
+       memcpy (temp_state, state, dfa_state_size);
+       
+       delay = state_transition (temp_state, insn);
+       
+       if (delay == 0)
+         {
+           if (!targetm.sched.dfa_bubble)
+             continue;
+           else
+             {
+               int j;
+               rtx bubble;
+               
+               for (j = 0;
+                    (bubble = (*targetm.sched.dfa_bubble) (j)) != NULL_RTX;
+                    j++)
+                 if (state_transition (temp_state, bubble) < 0
+                     && state_transition (temp_state, insn) < 0)
+                   break;
+               
+               if (bubble == NULL_RTX)
+                 continue;
+             }
+         }
+       else if (delay > 0)
+         continue;
+       
+       --max_lookahead;
+       
+       if (max_lookahead < 0)
+         break;
+       
+       ready_try [i] = 1;
+       *last_p = 0;
+       
+       n = max_issue (ready, temp_state, &temp_index, last_p) + 1;
+       
+       if (best < n && (ready_try [0] || *last_p))
+         {
+           best = n;
+           *index = i;
+           *last_p = 1;
+         }
+       ready_try [i] = 0;
+      }
+  
+  return best;
+}
+
+/* The following function chooses insn from READY and modifies
+   *N_READY and READY.  The following function is used only for first
+   cycle multipass scheduling.  */
+
+static rtx
+choose_ready (ready)
+     struct ready_list *ready;
+{
+  if (!targetm.sched.first_cycle_multipass_dfa_lookahead
+      || (*targetm.sched.first_cycle_multipass_dfa_lookahead) () <= 0)
+    return ready_remove_first (ready);
+  else
+    {
+      /* Try to choose the better insn.  */
+      int index;
+      int last_p = 0;
+      
+      if (max_issue (ready, curr_state, &index, &last_p) == 0)
+       return ready_remove_first (ready);
+      else
+       return ready_remove (ready, index);
+    }
+}
+
 /* Use forward list scheduling to rearrange insns of block B in region RGN,
    possibly bringing insns from subsequent blocks in the same region.  */
 
@@ -1627,7 +1897,9 @@ schedule_block (b, rgn_n_insns)
 {
   rtx last;
   struct ready_list ready;
+  int first_cycle_insn_p;
   int can_issue_more;
+  state_t temp_state = NULL;  /* It is used for multipass scheduling.  */
 
   /* Head/tail info for this block.  */
   rtx prev_head = current_sched_info->prev_head;
@@ -1660,7 +1932,10 @@ schedule_block (b, rgn_n_insns)
       init_block_visualization ();
     }
 
-  clear_units ();
+  if (targetm.sched.use_dfa_pipeline_interface)
+    state_reset (curr_state);
+  else
+    clear_units ();
 
   /* Allocate the ready list.  */
   ready.veclen = rgn_n_insns + 1 + issue_rate;
@@ -1668,6 +1943,14 @@ schedule_block (b, rgn_n_insns)
   ready.vec = (rtx *) xmalloc (ready.veclen * sizeof (rtx));
   ready.n_ready = 0;
 
+  if (targetm.sched.use_dfa_pipeline_interface)
+    {
+      /* It is used for first cycle multipass scheduling.  */
+      temp_state = alloca (dfa_state_size);
+      ready_try = (char *) xmalloc ((rgn_n_insns + 1) * sizeof (char));
+      memset (ready_try, 0, (rgn_n_insns + 1) * sizeof (char));
+    }
+
   (*current_sched_info->init_ready_list) (&ready);
 
   if (targetm.sched.md_init)
@@ -1680,8 +1963,15 @@ schedule_block (b, rgn_n_insns)
      queue.  */
   q_ptr = 0;
   q_size = 0;
-  last_clock_var = 0;
-  memset ((char *) insn_queue, 0, sizeof (insn_queue));
+
+  if (!targetm.sched.use_dfa_pipeline_interface)
+    max_insn_queue_index_macro_value = INSN_QUEUE_SIZE - 1;
+  else
+    max_insn_queue_index_macro_value = max_insn_queue_index;
+
+  insn_queue = (rtx *) alloca ((MAX_INSN_QUEUE_INDEX + 1) * sizeof (rtx));
+  memset ((char *) insn_queue, 0, (MAX_INSN_QUEUE_INDEX + 1) * sizeof (rtx));
+  last_clock_var = -1;
 
   /* Start just before the beginning of time.  */
   clock_var = -1;
@@ -1694,6 +1984,20 @@ schedule_block (b, rgn_n_insns)
     {
       clock_var++;
 
+      if (targetm.sched.use_dfa_pipeline_interface)
+       {
+         if (targetm.sched.dfa_pre_cycle_insn)
+           state_transition (curr_state,
+                             (*targetm.sched.dfa_pre_cycle_insn) ());
+
+         /* Advance time on one cycle.  */
+         state_transition (curr_state, NULL);
+
+         if (targetm.sched.dfa_post_cycle_insn)
+           state_transition (curr_state,
+                             (*targetm.sched.dfa_post_cycle_insn) ());
+       }
+
       /* Add to the ready list all pending insns that can be issued now.
          If there are no ready insns, increment clock until one
          is ready and add all pending insns at that point to the ready
@@ -1725,20 +2029,122 @@ schedule_block (b, rgn_n_insns)
       else
        can_issue_more = issue_rate;
 
-      if (sched_verbose)
+      first_cycle_insn_p = 1;
+      for (;;)
        {
-         fprintf (sched_dump, "\n;;\tReady list (t =%3d):  ", clock_var);
-         debug_ready_list (&ready);
-       }
+         rtx insn;
+         int cost;
+
+         if (sched_verbose)
+           {
+             fprintf (sched_dump, ";;\tReady list (t =%3d):  ",
+                      clock_var);
+             debug_ready_list (&ready);
+           }
+
+         if (!targetm.sched.use_dfa_pipeline_interface)
+           {
+             if (ready.n_ready == 0 || !can_issue_more
+                 || !(*current_sched_info->schedule_more_p) ())
+               break;
+             insn = choose_ready (&ready);
+             cost = actual_hazard (insn_unit (insn), insn, clock_var, 0);
+           }
+         else
+           {
+             if (ready.n_ready == 0 || !can_issue_more
+                 || state_dead_lock_p (curr_state)
+                 || !(*current_sched_info->schedule_more_p) ())
+               break;
+             
+             /* Select and remove the insn from the ready list.  */
+             insn = choose_ready (&ready);
+             
+             if (recog_memoized (insn) < 0)
+               {
+                 if (!first_cycle_insn_p
+                     && (GET_CODE (PATTERN (insn)) == ASM_INPUT
+                         || asm_noperands (PATTERN (insn)) >= 0))
+                   /* This is asm insn which is tryed to be issued on the
+                      cycle not first.  Issue it on the next cycle.  */
+                   cost = 1;
+                 else
+                   /* A USE insn, or something else we don't need to
+                      understand.  We can't pass these directly to
+                      state_transition because it will trigger a
+                      fatal error for unrecognizable insns.  */
+                   cost = 0;
+               }
+             else
+               {
+                 cost = state_transition (curr_state, insn);
+
+                 if (targetm.sched.first_cycle_multipass_dfa_lookahead
+                     && targetm.sched.dfa_bubble)
+                   {
+                     if (cost == 0)
+                       {
+                         int j;
+                         rtx bubble;
+                         
+                         for (j = 0;
+                              (bubble = (*targetm.sched.dfa_bubble) (j))
+                                != NULL_RTX;
+                              j++)
+                           {
+                             memcpy (temp_state, curr_state, dfa_state_size);
+                             
+                             if (state_transition (temp_state, bubble) < 0
+                                 && state_transition (temp_state, insn) < 0)
+                               break;
+                           }
+                         
+                         if (bubble != NULL_RTX)
+                           {
+                             memcpy (curr_state, temp_state, dfa_state_size);
+                             
+                             if (insert_schedule_bubbles_p)
+                               {
+                                 rtx copy;
+                                 
+                                 copy = copy_rtx (PATTERN (bubble));
+                                 emit_insn_after (copy, last);
+                                 last = NEXT_INSN (last);
+                                 INSN_CODE (last) = INSN_CODE (bubble);
+                                 
+                                 /* Annotate the same for the first insns
+                                    scheduling by using mode.  */
+                                 PUT_MODE (last, (clock_var > last_clock_var
+                                                  ? clock_var - last_clock_var
+                                                  : VOIDmode));
+                                 last_clock_var = clock_var;
+                                 
+                                 if (sched_verbose >= 2)
+                                   {
+                                     fprintf (sched_dump,
+                                              ";;\t\t--> scheduling bubble insn <<<%d>>>:reservation ",
+                                              INSN_UID (last));
+                                     
+                                     if (recog_memoized (last) < 0)
+                                       fprintf (sched_dump, "nothing");
+                                     else
+                                       print_reservation (sched_dump, last);
+                                     
+                                     fprintf (sched_dump, "\n");
+                                   }
+                               }
+                             cost = -1;
+                           }
+                       }
+                   }
+
+                 if (cost < 0)
+                   cost = 0;
+                 else if (cost == 0)
+                   cost = 1;
+               }
+           }
 
-      /* Issue insns from ready list.  */
-      while (ready.n_ready != 0
-            && can_issue_more
-            && (*current_sched_info->schedule_more_p) ())
-       {
-         /* Select and remove the insn from the ready list.  */
-         rtx insn = ready_remove_first (&ready);
-         int cost = actual_hazard (insn_unit (insn), insn, clock_var, 0);
 
          if (cost >= 1)
            {
@@ -1762,6 +2168,8 @@ schedule_block (b, rgn_n_insns)
          schedule_insn (insn, &ready, clock_var);
 
        next:
+         first_cycle_insn_p = 0;
+
          if (targetm.sched.reorder2)
            {
              /* Sort the ready list based on priority.  */
@@ -1775,8 +2183,8 @@ schedule_block (b, rgn_n_insns)
            }
        }
 
-      /* Debug info.  */
-      if (sched_verbose)
+      if (!targetm.sched.use_dfa_pipeline_interface && sched_verbose)
+       /* Debug info.  */
        visualize_scheduled_insns (clock_var);
     }
 
@@ -1788,7 +2196,8 @@ schedule_block (b, rgn_n_insns)
     {
       fprintf (sched_dump, ";;\tReady list (final):  ");
       debug_ready_list (&ready);
-      print_block_visualization ("");
+      if (!targetm.sched.use_dfa_pipeline_interface)
+       print_block_visualization ("");
     }
 
   /* Sanity check -- queue must be empty now.  Meaningless if region has
@@ -1833,6 +2242,9 @@ schedule_block (b, rgn_n_insns)
   current_sched_info->tail = tail;
 
   free (ready.vec);
+
+  if (targetm.sched.use_dfa_pipeline_interface)
+    free (ready_try);
 }
 \f
 /* Set_priorities: compute priority of each insn in the block.  */
@@ -1874,6 +2286,7 @@ sched_init (dump_file)
 {
   int luid, b;
   rtx insn;
+  int i;
 
   /* Disable speculative loads in their presence if cc0 defined.  */
 #ifdef HAVE_cc0
@@ -1901,6 +2314,26 @@ sched_init (dump_file)
 
   h_i_d = (struct haifa_insn_data *) xcalloc (old_max_uid, sizeof (*h_i_d));
 
+  for (i = 0; i < old_max_uid; i++)
+    h_i_d [i].cost = -1;
+
+  if (targetm.sched.use_dfa_pipeline_interface)
+    {
+      if (targetm.sched.init_dfa_pre_cycle_insn)
+       (*targetm.sched.init_dfa_pre_cycle_insn) ();
+      
+      if (targetm.sched.init_dfa_post_cycle_insn)
+       (*targetm.sched.init_dfa_post_cycle_insn) ();
+      
+      if (targetm.sched.first_cycle_multipass_dfa_lookahead
+         && targetm.sched.init_dfa_bubbles)
+       (*targetm.sched.init_dfa_bubbles) ();
+      
+      dfa_start ();
+      dfa_state_size = state_size ();
+      curr_state = xmalloc (dfa_state_size);
+    }
+
   h_i_d[0].luid = 0;
   luid = 1;
   for (b = 0; b < n_basic_blocks; b++)
@@ -1958,8 +2391,8 @@ sched_init (dump_file)
        }
     }
 
-  /* Find units used in this fuction, for visualization.  */
-  if (sched_verbose)
+  if (!targetm.sched.use_dfa_pipeline_interface && sched_verbose)
+    /* Find units used in this function, for visualization.  */
     init_target_units ();
 
   /* ??? Add a NOTE after the last insn of the last basic block.  It is not
@@ -1985,6 +2418,12 @@ void
 sched_finish ()
 {
   free (h_i_d);
+
+  if (targetm.sched.use_dfa_pipeline_interface)
+    {
+      free (curr_state);
+      dfa_finish ();
+    }
   free_dependency_caches ();
   end_alias_analysis ();
   if (write_symbols != NO_DEBUG)
index 80f8e5c..720d605 100644 (file)
@@ -334,6 +334,144 @@ DEF_RTL_EXPR(SEQUENCE, "sequence", "E", 'x')
 DEF_RTL_EXPR(ADDRESS, "address", "e", 'm')
 
 /* ----------------------------------------------------------------------
+   Constructions for CPU pipeline description described by NDFAs.
+   These do not appear in actual rtl code in the compiler.
+   ---------------------------------------------------------------------- */
+
+/* (define_cpu_unit string [string]) describes cpu functional
+   units (separated by comma).
+
+   1st operand: Names of cpu functional units.
+   2nd operand: Name of automaton (see comments for DEFINE_AUTOMATON).
+
+   All define_reservations, define_cpu_units, and
+   define_query_cpu_units should have unique names which may not be
+   "nothing".  */
+DEF_RTL_EXPR(DEFINE_CPU_UNIT, "define_cpu_unit", "sS", 'x')
+
+/* (define_query_cpu_unit string [string]) describes cpu functional
+   units analogously to define_cpu_unit.  If we use automaton without
+   minimization, the reservation of such units can be queried for
+   automaton state.  */
+DEF_RTL_EXPR(DEFINE_QUERY_CPU_UNIT, "define_query_cpu_unit", "sS", 'x')
+
+/* (exclusion_set string string) means that each CPU functional unit
+   in the first string can not be reserved simultaneously with any
+   unit whose name is in the second string and vise versa.  CPU units
+   in the string are separated by commas.  For example, it is useful
+   for description CPU with fully pipelined floating point functional
+   unit which can execute simultaneously only single floating point
+   insns or only double floating point insns.  */
+DEF_RTL_EXPR(EXCLUSION_SET, "exclusion_set", "ss", 'x')
+
+/* (presence_set string string) means that each CPU functional unit in
+   the first string can not be reserved unless at least one of units
+   whose names are in the second string is reserved.  This is an
+   asymmetric relation.  CPU units in the string are separated by
+   commas.  For example, it is useful for description that slot1 is
+   reserved after slot0 reservation for VLIW processor.  */
+DEF_RTL_EXPR(PRESENCE_SET, "presence_set", "ss", 'x')
+
+/* (absence_set string string) means that each CPU functional unit in
+   the first string can not be reserved only if each unit whose name
+   is in the second string is not reserved.  This is an asymmetric
+   relation (actually exclusion set is analogous to this one but it is
+   symmetric).  CPU units in the string are separated by commas.  For
+   example, it is useful for description that slot0 can not be
+   reserved after slot1 or slot2 reservation for VLIW processor.  */
+DEF_RTL_EXPR(ABSENCE_SET, "absence_set", "ss", 'x')
+
+/* (define_bypass number out_insn_names in_insn_names) names bypass
+   with given latency (the first number) from insns given by the first
+   string (see define_insn_reservation) into insns given by the second
+   string.  Insn names in the strings are separated by commas.  The
+   third operand is optional name of function which is additional
+   guard for the bypass.  The function will get the two insns as
+   parameters.  If the function returns zero the bypass will be
+   ignored for this case.  Additional guard is necessary to recognize
+   complicated bypasses, e.g. when consumer is load address.  */
+DEF_RTL_EXPR(DEFINE_BYPASS, "define_bypass", "issS", 'x')
+
+/* (define_automaton string) describes names of automata generated and
+   used for pipeline hazards recognition.  The names are separated by
+   comma.  Actually it is possibly to generate the single automaton
+   but unfortunately it can be very large.  If we use more one
+   automata, the summary size of the automata usually is less than the
+   single one.  The automaton name is used in define_cpu_unit and
+   define_query_cpu_unit.  All automata should have unique names.  */
+DEF_RTL_EXPR(DEFINE_AUTOMATON, "define_automaton", "s", 'x')
+
+/* (automata_option string) describes option for generation of
+   automata.  Currently there are the following options:
+
+   o "no-minimization" which makes no minimization of automata.  This
+     is only worth to do when we are going to query CPU functional
+     unit reservations in an automaton state.
+
+   o "w" which means generation of file describing the result
+     automaton.  The file can be used for the description verification.
+
+   o "ndfa" which makes nondeterministic finite state automata.  */
+DEF_RTL_EXPR(AUTOMATA_OPTION, "automata_option", "s", 'x')
+
+/* (define_reservation string string) names reservation (the first
+   string) of cpu functional units (the 2nd string).  Sometimes unit
+   reservations for different insns contain common parts.  In such
+   case, you can describe common part and use its name (the 1st
+   parameter) in regular expression in define_insn_reservation.  All
+   define_reservations, define_cpu_units, and define_query_cpu_units
+   should have unique names which may not be "nothing".  */
+DEF_RTL_EXPR(DEFINE_RESERVATION, "define_reservation", "ss", 'x')
+
+/* (define_insn_reservation name default_latency condition regexpr)
+   describes reservation of cpu functional units (the 3nd operand) for
+   instruction which is selected by the condition (the 2nd parameter).
+   The first parameter is used for output of debugging information.
+   The reservations are described by a regular expression according
+   the following syntax:
+
+       regexp = regexp "," oneof
+              | oneof
+
+       oneof = oneof "|" allof
+             | allof
+
+       allof = allof "+" repeat
+             | repeat
+       repeat = element "*" number
+              | element
+
+       element = cpu_function_unit_name
+               | reservation_name
+               | result_name
+               | "nothing"
+               | "(" regexp ")"
+
+       1. "," is used for describing start of the next cycle in
+       reservation.
+
+       2. "|" is used for describing the reservation described by the
+       first regular expression *or* the reservation described by the
+       second regular expression *or* etc.
+
+       3. "+" is used for describing the reservation described by the
+       first regular expression *and* the reservation described by the
+       second regular expression *and* etc.
+
+       4. "*" is used for convinience and simply means sequence in
+       which the regular expression are repeated NUMBER times with
+       cycle advancing (see ",").
+
+       5. cpu functional unit name which means its reservation.
+
+       6. reservation name -- see define_reservation.
+
+       7. string "nothing" means no units reservation.  */
+
+DEF_RTL_EXPR(DEFINE_INSN_RESERVATION, "define_insn_reservation", "sies", 'x')
+
+/* ----------------------------------------------------------------------
    Expressions used for insn attributes.  These also do not appear in
    actual rtl code in the compiler.
    ---------------------------------------------------------------------- */
index 3a0a019..b40ac72 100644 (file)
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -110,11 +110,9 @@ struct rtx_def
   ENUM_BITFIELD(machine_mode) mode : 8;
 
   /* 1 in an INSN if it can alter flow of control
-     within this function.
-     LINK_COST_ZERO in an INSN_LIST.  */
+     within this function.  */
   unsigned int jump : 1;
-  /* 1 in an INSN if it can call another function.
-     LINK_COST_FREE in an INSN_LIST.  */
+  /* 1 in an INSN if it can call another function.  */
   unsigned int call : 1;
   /* 1 in a REG if value of this expression will never change during
      the current function, even though it is not manifestly constant.
@@ -899,16 +897,6 @@ extern unsigned int subreg_regno   PARAMS ((rtx));
    with the preceding insn.  */
 #define SCHED_GROUP_P(INSN) ((INSN)->in_struct)
 
-/* During sched, for the LOG_LINKS of an insn, these cache the adjusted
-   cost of the dependence link.  The cost of executing an instruction
-   may vary based on how the results are used.  LINK_COST_ZERO is 1 when
-   the cost through the link varies and is unchanged (i.e., the link has
-   zero additional cost).  LINK_COST_FREE is 1 when the cost through the
-   link is zero (i.e., the link makes the cost free).  In other cases,
-   the adjustment to the cost is recomputed each time it is needed.  */
-#define LINK_COST_ZERO(X) ((X)->jump)
-#define LINK_COST_FREE(X) ((X)->call)
-
 /* For a SET rtx, SET_DEST is the place that is set
    and SET_SRC is the value it is set to.  */
 #define SET_DEST(RTX) XC2EXP(RTX, 0, SET, CLOBBER)
index 0637813..1c6d654 100644 (file)
@@ -20,6 +20,9 @@ along with GCC; see the file COPYING.  If not, write to the Free the
 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 02111-1307, USA.  */
 
+/* Pointer to data describing the current DFA state.  */
+extern state_t curr_state;
+
 /* Forward declaration.  */
 struct ready_list;
 
@@ -181,7 +184,7 @@ struct haifa_insn_data
   int dep_count;
 
   /* An encoding of the blockage range function.  Both unit and range
-     are coded.  */
+     are coded.  This member is used only for old pipeline interface.  */
   unsigned int blockage;
 
   /* Number of instructions referring to this insn.  */
@@ -193,7 +196,8 @@ struct haifa_insn_data
 
   short cost;
 
-  /* An encoding of the function units used.  */
+  /* An encoding of the function units used.  This member is used only
+     for old pipeline interface.  */
   short units;
 
   /* This weight is an estimation of the insn's contribution to
index e0a2a63..d5310f3 100644 (file)
@@ -61,6 +61,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "toplev.h"
 #include "recog.h"
 #include "sched-int.h"
+#include "target.h"
 
 #ifdef INSN_SCHEDULING
 /* Some accessor macros for h_i_d members only used within this file.  */
@@ -2142,7 +2143,13 @@ init_ready_list (ready)
 
            if (!CANT_MOVE (insn)
                && (!IS_SPECULATIVE_INSN (insn)
-                   || (insn_issue_delay (insn) <= 3
+                   || ((0
+                        || (targetm.sched.use_dfa_pipeline_interface
+                            && recog_memoized (insn) >= 0
+                            && min_insn_conflict_delay (curr_state, insn,
+                                                        insn) <= 3)
+                        || (!targetm.sched.use_dfa_pipeline_interface
+                            && insn_issue_delay (insn) <= 3))
                        && check_live (insn, bb_src)
                        && is_exception_free (insn, bb_src, target_bb))))
              {
@@ -2250,7 +2257,13 @@ new_ready (next)
       && (!IS_VALID (INSN_BB (next))
          || CANT_MOVE (next)
          || (IS_SPECULATIVE_INSN (next)
-             && (insn_issue_delay (next) > 3
+             && (0
+                 || (targetm.sched.use_dfa_pipeline_interface
+                     && (recog_memoized (next) < 0
+                         || min_insn_conflict_delay (curr_state, next,
+                                                     next) > 3))
+                 || (!targetm.sched.use_dfa_pipeline_interface
+                     && insn_issue_delay (next) > 3)
                  || !check_live (next, INSN_BB (next))
                  || !is_exception_free (next, INSN_BB (next), target_bb)))))
     return 0;
@@ -2642,14 +2655,26 @@ debug_dependencies ()
          fprintf (sched_dump, "\n;;   --- Region Dependences --- b %d bb %d \n",
                   BB_TO_BLOCK (bb), bb);
 
-         fprintf (sched_dump, ";;   %7s%6s%6s%6s%6s%6s%11s%6s\n",
-         "insn", "code", "bb", "dep", "prio", "cost", "blockage", "units");
-         fprintf (sched_dump, ";;   %7s%6s%6s%6s%6s%6s%11s%6s\n",
-         "----", "----", "--", "---", "----", "----", "--------", "-----");
+         if (targetm.sched.use_dfa_pipeline_interface)
+           {
+             fprintf (sched_dump, ";;   %7s%6s%6s%6s%6s%6s%14s\n",
+                      "insn", "code", "bb", "dep", "prio", "cost",
+                      "reservation");
+             fprintf (sched_dump, ";;   %7s%6s%6s%6s%6s%6s%14s\n",
+                      "----", "----", "--", "---", "----", "----",
+                      "-----------");
+           }
+         else
+           {
+             fprintf (sched_dump, ";;   %7s%6s%6s%6s%6s%6s%11s%6s\n",
+             "insn", "code", "bb", "dep", "prio", "cost", "blockage", "units");
+             fprintf (sched_dump, ";;   %7s%6s%6s%6s%6s%6s%11s%6s\n",
+             "----", "----", "--", "---", "----", "----", "--------", "-----");
+           }
+
          for (insn = head; insn != next_tail; insn = NEXT_INSN (insn))
            {
              rtx link;
-             int unit, range;
 
              if (! INSN_P (insn))
                {
@@ -2669,22 +2694,45 @@ debug_dependencies ()
                  continue;
                }
 
-             unit = insn_unit (insn);
-             range = (unit < 0
-                || function_units[unit].blockage_range_function == 0) ? 0 :
-               function_units[unit].blockage_range_function (insn);
-             fprintf (sched_dump,
-                      ";;   %s%5d%6d%6d%6d%6d%6d  %3d -%3d   ",
-                      (SCHED_GROUP_P (insn) ? "+" : " "),
-                      INSN_UID (insn),
-                      INSN_CODE (insn),
-                      INSN_BB (insn),
-                      INSN_DEP_COUNT (insn),
-                      INSN_PRIORITY (insn),
-                      insn_cost (insn, 0, 0),
-                      (int) MIN_BLOCKAGE_COST (range),
-                      (int) MAX_BLOCKAGE_COST (range));
-             insn_print_units (insn);
+             if (targetm.sched.use_dfa_pipeline_interface)
+               {
+                 fprintf (sched_dump,
+                          ";;   %s%5d%6d%6d%6d%6d%6d   ",
+                          (SCHED_GROUP_P (insn) ? "+" : " "),
+                          INSN_UID (insn),
+                          INSN_CODE (insn),
+                          INSN_BB (insn),
+                          INSN_DEP_COUNT (insn),
+                          INSN_PRIORITY (insn),
+                          insn_cost (insn, 0, 0));
+                 
+                 if (recog_memoized (insn) < 0)
+                   fprintf (sched_dump, "nothing");
+                 else
+                   print_reservation (sched_dump, insn);
+               }
+             else
+               {
+                 int unit = insn_unit (insn);
+                 int range
+                   = (unit < 0
+                      || function_units[unit].blockage_range_function == 0
+                      ? 0
+                      : function_units[unit].blockage_range_function (insn));
+                 fprintf (sched_dump,
+                          ";;   %s%5d%6d%6d%6d%6d%6d  %3d -%3d   ",
+                          (SCHED_GROUP_P (insn) ? "+" : " "),
+                          INSN_UID (insn),
+                          INSN_CODE (insn),
+                          INSN_BB (insn),
+                          INSN_DEP_COUNT (insn),
+                          INSN_PRIORITY (insn),
+                          insn_cost (insn, 0, 0),
+                          (int) MIN_BLOCKAGE_COST (range),
+                          (int) MAX_BLOCKAGE_COST (range));
+                 insn_print_units (insn);
+               }
+
              fprintf (sched_dump, "\t: ");
              for (link = INSN_DEPEND (insn); link; link = XEXP (link, 1))
                fprintf (sched_dump, "%d ", INSN_UID (XEXP (link, 0)));
index 90521a2..9d761d1 100644 (file)
@@ -31,6 +31,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
 #include "basic-block.h"
 #include "insn-attr.h"
 #include "sched-int.h"
+#include "target.h"
 
 #ifdef INSN_SCHEDULING
 /* target_units bitmask has 1 for each unit in the cpu.  It should be
@@ -38,7 +39,8 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
    But currently it is computed by examining the insn list.  Since
    this is only needed for visualization, it seems an acceptable
    solution.  (For understanding the mapping of bits to units, see
-   definition of function_units[] in "insn-attrtab.c".)  */
+   definition of function_units[] in "insn-attrtab.c".)  The scheduler
+   using only DFA description should never use the following variable.  */
 
 static int target_units = 0;
 
@@ -122,6 +124,13 @@ get_visual_tbl_length ()
   int n, n1;
   char *s;
 
+  if (targetm.sched.use_dfa_pipeline_interface)
+    {
+      visual_tbl_line_length = 1;
+      return 1; /* Can't return 0 because that will cause problems
+                   with alloca.  */
+    }
+
   /* Compute length of one field in line.  */
   s = (char *) alloca (INSN_LEN + 6);
   sprintf (s, "  %33s", "uname");
@@ -809,7 +818,8 @@ print_insn (buf, x, verbose)
     }
 }                              /* print_insn */
 
-/* Print visualization debugging info.  */
+/* Print visualization debugging info.  The scheduler using only DFA
+   description should never use the following function.  */
 
 void
 print_block_visualization (s)
index 3282b3c..e3729b1 100644 (file)
@@ -93,16 +93,33 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 #define TARGET_SCHED_REORDER 0
 #define TARGET_SCHED_REORDER2 0
 #define TARGET_SCHED_CYCLE_DISPLAY 0
-
-#define TARGET_SCHED   {TARGET_SCHED_ADJUST_COST,      \
-                        TARGET_SCHED_ADJUST_PRIORITY,  \
-                        TARGET_SCHED_ISSUE_RATE,       \
-                        TARGET_SCHED_VARIABLE_ISSUE,   \
-                        TARGET_SCHED_INIT,             \
-                        TARGET_SCHED_FINISH,           \
-                        TARGET_SCHED_REORDER,          \
-                        TARGET_SCHED_REORDER2,         \
-                        TARGET_SCHED_CYCLE_DISPLAY}
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE 0
+#define TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN 0
+#define TARGET_SCHED_DFA_PRE_CYCLE_INSN 0
+#define TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN 0
+#define TARGET_SCHED_DFA_POST_CYCLE_INSN 0
+#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD 0
+#define TARGET_SCHED_INIT_DFA_BUBBLES 0
+#define TARGET_SCHED_DFA_BUBBLE 0
+
+#define TARGET_SCHED                                           \
+  {TARGET_SCHED_ADJUST_COST,                                   \
+   TARGET_SCHED_ADJUST_PRIORITY,                               \
+   TARGET_SCHED_ISSUE_RATE,                                    \
+   TARGET_SCHED_VARIABLE_ISSUE,                                        \
+   TARGET_SCHED_INIT,                                          \
+   TARGET_SCHED_FINISH,                                                \
+   TARGET_SCHED_REORDER,                                       \
+   TARGET_SCHED_REORDER2,                                      \
+   TARGET_SCHED_CYCLE_DISPLAY,                                 \
+   TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE,                    \
+   TARGET_SCHED_INIT_DFA_PRE_CYCLE_INSN,                       \
+   TARGET_SCHED_DFA_PRE_CYCLE_INSN,                            \
+   TARGET_SCHED_INIT_DFA_POST_CYCLE_INSN,                      \
+   TARGET_SCHED_DFA_POST_CYCLE_INSN,                           \
+   TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD,           \
+   TARGET_SCHED_INIT_DFA_BUBBLES,                              \
+   TARGET_SCHED_DFA_BUBBLE}
 
 /* All in tree.c.  */
 #define TARGET_MERGE_DECL_ATTRIBUTES merge_decl_attributes
index 8d73f49..afbdad0 100644 (file)
@@ -113,6 +113,47 @@ struct gcc_target
        insn in the new chain we're building.  Returns a new LAST.
        The default is to do nothing.  */
     rtx (* cycle_display) PARAMS ((int clock, rtx last));
+    /* The following member value is a pointer to a function returning
+       nonzero if we should use DFA based scheduling.  The default is
+       to use the old pipeline scheduler.  */
+    int (* use_dfa_pipeline_interface) PARAMS ((void));
+    /* The values of all the following members are used only for the
+       DFA based scheduler: */
+    /* The values of the following four members are pointers to
+       functions used to simplify the automaton descriptions.
+       dfa_pre_cycle_insn and dfa_post_cycle_insn give functions
+       returning insns which are used to change the pipeline hazard
+       recognizer state when the new simulated processor cycle
+       correspondingly starts and finishes.  The function defined by
+       init_dfa_pre_cycle_insn and init_dfa_post_cycle_insn are used
+       to initialize the corresponding insns.  The default values of
+       the memebers result in not changing the automaton state when
+       the new simulated processor cycle correspondingly starts and
+       finishes.  */
+    void (* init_dfa_pre_cycle_insn) PARAMS ((void));
+    rtx (* dfa_pre_cycle_insn) PARAMS ((void));
+    void (* init_dfa_post_cycle_insn) PARAMS ((void));
+    rtx (* dfa_post_cycle_insn) PARAMS ((void));
+    /* The following member value is a pointer to a function returning value
+       which defines how many insns in queue `ready' will we try for
+       multi-pass scheduling.  if the member value is nonzero and the
+       function returns positive value, the DFA based scheduler will make
+       multi-pass scheduling for the first cycle.  In other words, we will
+       try to choose ready insn which permits to start maximum number of
+       insns on the same cycle.  */
+    int (* first_cycle_multipass_dfa_lookahead) PARAMS ((void));
+    /* The values of the following members are pointers to functions
+       used to improve the first cycle multipass scheduling by
+       inserting nop insns.  dfa_scheduler_bubble gives a function
+       returning a nop insn with given index.  The indexes start with
+       zero.  The function should return NULL if there are no more nop
+       insns with indexes greater than given index.  To initialize the
+       nop insn the function given by member
+       init_dfa_scheduler_bubbles is used.  The default values of the
+       members result in not inserting nop insns during the multipass
+       scheduling.  */
+    void (* init_dfa_bubbles) PARAMS ((void));
+    rtx (* dfa_bubble) PARAMS ((int));
   } sched;
 
   /* Given two decls, merge their attributes and return the result.  */