summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog362
-rw-r--r--gcc/Makefile.in90
-rw-r--r--gcc/config/pa/pa.c52
-rw-r--r--gcc/config/pa/pa.h1
-rw-r--r--gcc/config/pa/pa.md364
-rw-r--r--gcc/config/sh/sh.c32
-rw-r--r--gcc/config/sh/sh.md454
-rw-r--r--gcc/config/sparc/sparc-protos.h2
-rw-r--r--gcc/config/sparc/sparc.c1020
-rw-r--r--gcc/config/sparc/sparc.h21
-rw-r--r--gcc/config/sparc/sparc.md669
-rw-r--r--gcc/doc/contrib.texi7
-rw-r--r--gcc/doc/md.texi528
-rw-r--r--gcc/doc/passes.texi6
-rw-r--r--gcc/doc/tm.texi166
-rw-r--r--gcc/genattr.c107
-rw-r--r--gcc/genattrtab.c80
-rw-r--r--gcc/genattrtab.h43
-rw-r--r--gcc/genautomata.c9162
-rw-r--r--gcc/haifa-sched.c671
-rw-r--r--gcc/rtl.def141
-rw-r--r--gcc/rtl.h14
-rw-r--r--gcc/sched-int.h8
-rw-r--r--gcc/sched-rgn.c99
-rw-r--r--gcc/sched-vis.c15
-rw-r--r--gcc/target-def.h37
-rw-r--r--gcc/target.h41
27 files changed, 12622 insertions, 1570 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 6768d3c9780..8160501c622 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,365 @@
+2002-04-29 Vladimir Makarov <vmakarov@redhat.com>
+
+ Merging code from dfa-branch:
+
+ 2002-04-24 Vladimir Makarov <vmakarov@redhat.com>
+
+ * genautomata.c (output_reserv_sets): Fix typo.
+
+ 2002-04-23 Vladimir Makarov <vmakarov@redhat.com>
+
+ * genautomata.c (output_reserv_sets): Remove
+ next_cycle_output_flag.
+
+ Thu Apr 18 08:57:06 2002 Jeffrey A Law (law@redhat.com)
+
+ * sched-rgn.c (init_ready_list): Make the DFA code handle
+ USE/CLOBBER insns in the same way as the traditional
+ scheduler.
+ (new_ready): Similarly..
+
+ 2002-04-17 Vladimir Makarov <vmakarov@redhat.com>
+
+ * haifa-sched.c (schedule_block): Change the DFA state only after
+ issuing insn.
+
+ Wed Apr 17 15:38:36 2002 Jeffrey A Law (law@redhat.com)
+
+ * pa.c (hppa_use_dfa_pipeline_interface): New function.
+ (TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE): Define.
+ (override_options): Add PA7300 scheduling support.
+ (pa_adjust_cost): Update various comments. Properly
+ handle anti and output dependencies when using the
+ DFA scheduler.
+ (pa_issue_rate): Add PA7300 scheduling support.
+ (pa_can_combine_p): Call extract_insn before calling
+ constrain_operands (taken from mainline tree).
+ * pa.h (enum processor_type): Add PROCESSOR_PA7300.
+ * pa.md (cpu attr): Add 7300. Rewrite pipeline
+ descriptions using DFA descriptions. Add PA7300
+ scheduling support.
+
+ 2002-03-30 David S. Miller <davem@redhat.com>
+
+ Add UltraSPARC-III DFA scheduling support.
+ * config/sparc/sparc.md (define_attr type): Add fpcrmove.
+ Update FP conditional move on register insn patterns to use it, as
+ appropriate.
+ (define_attr cpu): Add ultrasparc3.
+ (define_attr us3load_type): New, update integer load patterns to
+ set it, as appropriate.
+ (define_automaton): Add ultrasparc3_0 and ultrasparc3_1.
+ (rest): Add UltraSPARC3 scheduling description.
+ * config/sparc/sparc.h (TARGET_CPU_ultrasparc3): New.
+ (PROCESSOR_ULTRASPARC3): New.
+ ({ASM,CPP}_CPU64_DEFAULT_SPEC): Handle ultrasparc3.
+ ({ASM,CPP}_CPU_SPEC): Likewise.
+ (REGISTER_MOVE_COST): Likewise.
+ (RTX_COSTS): Likewise.
+ * config/sparc/sparc.c (sparc_override_options,
+ sparc_initialize_trampoline, sparc64_initialize_trampoline,
+ sparc_use_dfa_pipeline_interface, sparc_use_sched_lookahead,
+ sparc_issue_rate): Likewise.
+ * config/sparc/sol2.h: Likewise.
+ * config/sparc/sol2-sld-64.h: Likewise.
+ * config/sparc/linux64.h: Likewise.
+
+ 2002-03-22 Vladimir Makarov <vmakarov@redhat.com>
+
+ * doc/md.texi: Add comments about usage the latency time for the
+ different dependencies and about case when two or more conditions
+ in different define_insn_reservations returns TRUE for an insn.
+
+ * doc/md.texi: Add reference for automaton based pipeline
+ description.
+
+ 2002-03-04 Vladimir Makarov <vmakarov@redhat.com>
+
+ * doc/passes.texi: Add missed information about genattrtab.
+
+ 2002-03-01 Vladimir Makarov <vmakarov@redhat.com>
+
+ * genautomata.c (output_automata_list_transition_code): Check
+ automata_list on NULL.
+
+ 2002-02-28 Vladimir Makarov <vmakarov@redhat.com>
+
+ * genautomata.c (output_insn_code_cases,
+ output_automata_list_min_issue_delay_code,
+ output_automata_list_transition_code,
+ output_automata_list_state_alts_code): Comment the functions.
+
+ 2002-02-22 Vladimir Makarov <vmakarov@redhat.com>
+
+ * genautomata.c (automata_list_el_t): New typedef.
+ (get_free_automata_list_el,free_automata_list_el,
+ free_automata_list, automata_list_hash, automata_list_eq_p,
+ initiate_automata_lists, automata_list_start, automata_list_add,
+ automata_list_finish, finish_automata_lists,
+ output_insn_code_cases, output_automata_list_min_issue_delay_code,
+ output_automata_list_transition_code,
+ output_automata_list_state_alts_code, add_automaton_state,
+ form_important_insn_automata_lists): New functions and prototypes.
+ (insn_reserv_decl): Add members important_automata_list and
+ processed_p.
+ (ainsn): Add members important_p.
+ (automata_list_el): New structure.
+ (first_free_automata_list_el, current_automata_list,
+ automata_list_table): New global variables.
+ (create_ainsns): Initiate member important_p.
+ (output_internal_min_issue_delay_func): Generate the switch and
+ call output_insn_code_cases.
+ (output_internal_trans_func, output_internal_state_alts_func):
+ Ditto.
+ (generate): Call initiate_automata_lists.
+ (automaton_states): New global variable.
+ (expand_automata): Call form_important_insn_automata_lists.
+ (write_automata): Call finish_automata_lists.
+
+ 2002-02-21 Vladimir Makarov <vmakarov@redhat.com>
+
+ * genautomata.c (add_excls, add_presence_absence): Check that
+ cpu units in the sets belong the same automaton.
+
+ * rtl.def (EXCLUSION_SET, PRESENCE_SET, ABSENCE_SET): Add comment
+ about that cpu units in the sets belong the same automaton.
+
+ * doc/md.texi: Ditto.
+
+ 2001-12-20 Naveen Sharma,Nitin Gupta <naveens@noida.hcltech.com,niting@noida.hcltech.com>
+
+ * config/sh/sh.c (sh_use_dfa_interface): New function.
+
+ (sh_issue_rate): New Function.
+ TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE: define.
+ TARGET_SCHED_ISSUE_RATE: define.
+
+ * config/sh/sh.md: Add DFA based pipeline description for SH4.
+
+ (define_attr insn_class): New attribute used for DFA
+ scheduling.
+ (define_insn cmpgtsi_t): Set attribute insn_class mt_group.
+ (cmpgesi_t,cmpgtusi_t,cmpgeusi_t,cmpeqsi_t,
+ cmpeqdi_t): Likewise.
+
+ (add,addc1,addsi3,subc,subc1,*subsi3_internal,
+ negc,negsi2,ashldi3_k,lshrdi3_k,ashrdi3_k): Set insn_class
+ ex_group.
+ (iorsi3,rotlsi3_1,rotlsi3_31,rotlsi3_16): Likewise.
+
+ 2001-10-03 Vladimir Makarov <vmakarov@toke.toronto.redhat.com>
+
+ * haifa-sched.c (queue_to_ready): Remove unnecessary condition for
+ break.
+
+ 2001-10-03 Vladimir Makarov <vmakarov@toke.toronto.redhat.com>
+
+ * genautomata.c (DFA_INSN_CODES_LENGTH_VARIABLE_NAME): New macro.
+ (output_dfa_insn_code_func): Expand dfa_insn_codes if it is
+ necessary.
+ (output_dfa_start_func): Initiate new variable insn_codes_length,
+ (write_automata): Output definition of the new variable.
+
+ 2001-10-02 David S. Miller <davem@redhat.com>
+
+ * haifa-sched.c (advance_one_cycle): New function.
+ (schedule_block): Use it.
+ (queue_to_ready): Use it, and also make sure to advance the DFA
+ state on all stall cycles, not just those where insn_queue links
+ are found.
+
+ 2001-10-02 Richard Sandiford <rsandifo@redhat.com>
+
+ * haifa-sched.c (max_issue): Remove last_p argument. Only return
+ non-zero if the highest-priority instruction could be scheduled.
+ (choose_ready): Remove last argument from max_issue call.
+
+ 2001-09-28 David S. Miller <davem@redhat.com>
+
+ * config/sparc/sparc.c (sparc_use_sched_lookahead): Use 4 for
+ ultrasparc and 3 for other multi-issue sparcs.
+
+ 2001-09-27 David S. Miller <davem@redhat.com>
+
+ * config/sparc/sparc.md (cycle_display): New pattern.
+ * config/sparc/sparc.c (sparc_cycle_display): New.
+ (TARGET_SCHED_CYCLE_DISPLAY): Set it.
+
+ 2001-09-25 David S. Miller <davem@redhat.com>
+
+ Convert all of Sparc scheduling to DFA
+ * config/sparc/sparc.md: Kill all define_function_unit
+ directives and replace with DFA equivalent.
+ * config/sparc/sparc.c (ultrasparc_adjust_cost,
+ mark_ultrasparc_pipeline_state, ultra_cmove_results_ready_p,
+ ultra_fpmode_conflict_exists, ultra_find_type,
+ ultra_build_types_avail, ultra_flush_pipeline,
+ ultra_rescan_pipeline_state, ultrasparc_sched_reorder,
+ ultrasparc_variable_issue, ultrasparc_sched_init,
+ sparc_variable_issue, sparc_sched_reorder, ultra_code_from_mask,
+ ultra_schedule_insn, ultra_code_names, ultra_pipe_hist,
+ ultra_cur_hist, ultra_cycles_elapsed): Kill.
+ (sparc_use_dfa_pipeline_interface, sparc_use_sched_lookahead,
+ ultrasparc_store_bypass_p): New.
+ * config/sparc/sparc-protos.h (ultrasparc_store_bypass_p):
+ Declare.
+
+ 2001-09-24 David S. Miller <davem@redhat.com>
+
+ * haifa-sched.c (ready_remove): Fix thinko, we want to copy around
+ ready->vec[foo] not ready[foo].
+
+ 2001-09-07 Vladimir Makarov <vmakarov@redhat.com>
+
+ * doc/md.texi: Correct examples for define_insn_reservations
+ `mult' and `div'.
+
+ 2001-09-07 Vladimir Makarov <vmakarov@redhat.com>
+
+ * genautomata.c (create_automata): Print message about creation of
+ each automaton.
+ (generate): Remove printing meease about creation of
+ automata.
+
+ 2001-09-05 David S. Miller <davem@redhat.com>
+
+ * config/sparc/linux.h: Set CPLUSPLUS_CPP_SPEC.
+ * config/sparc/linux64.h: Likewise.
+
+ 2001-08-31 Vladimir Makarov <vmakarov@redhat.com>
+
+ * haifa-sched.c (insn_cost, schedule_insn, queue_to_ready,
+ schedule_block, sched_init, sched_finish): Add missed calls of
+ use_dfa_pipeline_interface.
+
+ * sched-rgn.c (init_ready_list, new_ready, debug_dependencies):
+ Ditto.
+
+ * sched-vis.c (get_visual_tbl_length): Ditto.
+
+ 2001-08-27 Richard Henderson <rth@redhat.com>
+
+ * genattr.c (main): Emit state_t even when not doing scheduling.
+
+ 2001-08-27 Richard Henderson <rth@redhat.com>
+
+ * genautomata.c (expand_automata): Always create a description.
+
+ 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.
+
Mon Apr 29 17:19:10 2002 Richard Kenner <kenner@vlsi1.ultra.nyu.edu>
* reload1.c (eliminate_regs, case SUBREG): Fix typo in
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index f7ebd999199..8407632dcfa 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -344,6 +344,14 @@ LIBICONV = @LIBICONV@
# List of internationalization subdirectories.
INTL_SUBDIRS = intl
+# Change this to a null string if obstacks are installed in the
+# 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
@@ -475,6 +483,12 @@ HOST_CFLAGS= @HOST_CFLAGS@ -DGENERATOR_FILE
# Native linker and preprocessor flags. For x-fragment overrides.
HOST_LDFLAGS=$(LDFLAGS)
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.
GCC_INSTALL_NAME = `echo gcc|sed '$(program_transform_name)'`
@@ -598,8 +612,17 @@ ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS)
LIBIBERTY = ../libiberty/libiberty.a
BUILD_LIBIBERTY = @FORBUILD@/libiberty/libiberty.a
-# Dependencies on the intl and portability libraries.
-LIBDEPS= $(INTLDEPS) $(LIBIBERTY)
+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 the intl, portability libraries, obstack or whatever
+# library facilities are not installed in the system libraries.
+# We don't use USE_* because backquote expansion doesn't work in deps.
+LIBDEPS= $(INTLLIBS) $(LIBIBERTY) $(OBSTACK) $(VFPRINTF) $(DOPRINT) $(STRSTR)
# Likewise, for use in the tools that must run on this machine
# even if we are cross-building GCC.
@@ -618,6 +641,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,
@@ -1319,6 +1343,17 @@ line-map.o: line-map.c line-map.h intl.h $(CONFIG_H) $(SYSTEM_H)
ggc-none.o: ggc-none.c $(GCONFIG_H) $(SYSTEM_H) $(GGC_H)
$(CC) -c $(ALL_CFLAGS) -DGENERATOR_FILE $(ALL_CPPFLAGS) $(INCLUDES) $< $(OUTPUT_OPTION)
+obstack.o: $(srcdir)/../libiberty/obstack.c $(GCONFIG_H)
+ rm -f obstack.c
+ $(LN_S) $(srcdir)/../libiberty/obstack.c obstack.c
+ $(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)\" \
@@ -1558,12 +1593,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 \
@@ -1868,14 +1904,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 $(OUTPUT_OPTION)
-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 $(OUTPUT_OPTION)
+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 $(OUTPUT_OPTION)
+
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)
@@ -1921,11 +1961,47 @@ $(HOST_PREFIX_1)bitmap.o: $(srcdir)/bitmap.c $(HCONFIG_H) $(SYSTEM_H) $(RTL_H) \
sed -e 's/config[.]h/hconfig.h/' $(srcdir)/bitmap.c > $(HOST_PREFIX)bitmap.c
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)bitmap.c $(OUTPUT_OPTION)
+$(HOST_PREFIX_1)obstack.o: $(srcdir)/../libiberty/obstack.c $(HCONFIG_H)
+ rm -f $(HOST_PREFIX)obstack.c
+ 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 $(OUTPUT_OPTION)
+
+$(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 $(OUTPUT_OPTION)
+
+$(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 $(OUTPUT_OPTION)
+
+$(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
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)vfprintf.c $(OUTPUT_OPTION)
+
+$(HOST_PREFIX_1)doprint.o: doprint.c $(HCONFIG_H)
+ rm -f $(HOST_PREFIX)doprint.c
+ sed -e 's/config[.]h/hconfig.h/' $(srcdir)/doprint.c > $(HOST_PREFIX)doprint.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)doprint.c $(OUTPUT_OPTION)
+
+$(HOST_PREFIX_1)strstr.o: $(srcdir)/../libiberty/strstr.c $(HCONFIG_H)
+ rm -f $(HOST_PREFIX)strstr.c
+ sed -e 's/config[.]h/hconfig.h/' $(srcdir)/../libiberty/strstr.c > $(HOST_PREFIX)strstr.c
+ $(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)strstr.c $(OUTPUT_OPTION)
+
$(HOST_PREFIX_1)errors.o: errors.c $(HCONFIG_H) $(SYSTEM_H) errors.h
rm -f $(HOST_PREFIX)errors.c
sed -e 's/config[.]h/hconfig.h/' $(srcdir)/errors.c > $(HOST_PREFIX)errors.c
$(HOST_CC) -c $(HOST_CFLAGS) $(HOST_CPPFLAGS) $(INCLUDES) $(HOST_PREFIX)errors.c $(OUTPUT_OPTION)
+
+# This satisfies the dependency that we get if you cross-compile a compiler
+# that does not need to compile doprint or whatever.
+$(HOST_PREFIX_1):
+ $(STAMP) $(HOST_PREFIX_1)
+
$(HOST_PREFIX_1)ggc-none.o: ggc-none.c $(HCONFIG_H) $(SYSTEM_H) $(GCC_H)
rm -f $(HOST_PREFIX)ggc-none.c
sed -e 's/config[.]h/hconfig.h/' $(srcdir)/ggc-none.c > $(HOST_PREFIX)ggc-none.c
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index e5259da45bb..0cb46cd05bf 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -49,6 +49,17 @@ Boston, MA 02111-1307, USA. */
#include "target.h"
#include "target-def.h"
+static int hppa_use_dfa_pipeline_interface PARAMS ((void));
+
+#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE hppa_use_dfa_pipeline_interface
+
+static int
+hppa_use_dfa_pipeline_interface ()
+{
+ return 1;
+}
+
#ifndef DO_FRAME_NOTES
#ifdef INCOMING_RETURN_ADDR_RTX
#define DO_FRAME_NOTES 1
@@ -172,6 +183,11 @@ override_options ()
pa_cpu_string = "7200";
pa_cpu = PROCESSOR_7200;
}
+ else if (pa_cpu_string && ! strcmp (pa_cpu_string, "7300"))
+ {
+ pa_cpu_string = "7300";
+ pa_cpu = PROCESSOR_7300;
+ }
else if (pa_cpu_string && ! strcmp (pa_cpu_string, "8000"))
{
pa_cpu_string = "8000";
@@ -179,7 +195,7 @@ override_options ()
}
else
{
- warning ("unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, and 8000\n", pa_cpu_string);
+ warning ("unknown -mschedule= option (%s).\nValid options are 700, 7100, 7100LC, 7200, 7300, and 8000\n", pa_cpu_string);
}
/* Set the instruction set architecture. */
@@ -3929,7 +3945,7 @@ pa_adjust_cost (insn, link, dep_insn, cost)
{
case TYPE_FPLOAD:
/* This cost 3 cycles, not 2 as the md says for the
- 700 and 7100. */
+ 700 and 7100, 7100lc, 7200 and 7300. */
return cost + 1;
case TYPE_FPALU:
@@ -3947,6 +3963,11 @@ pa_adjust_cost (insn, link, dep_insn, cost)
return cost;
}
}
+
+ /* A flop-flop true depenendency where the sizes of the operand
+ carrying the dependency is difference causes an additional
+ cycle stall on the 7100lc, 7200, and 7300. Similarly for
+ a fpload-flop true dependency. */
}
/* For other data dependencies, the default cost specified in the
@@ -3989,7 +4010,10 @@ pa_adjust_cost (insn, link, dep_insn, cost)
preceding arithmetic operation has finished if
the target of the fpload is any of the sources
(or destination) of the arithmetic operation. */
- return cost - 1;
+ if (hppa_use_dfa_pipeline_interface ())
+ return insn_default_latency (dep_insn) - 1;
+ else
+ return cost - 1;
default:
return 0;
@@ -4024,7 +4048,10 @@ pa_adjust_cost (insn, link, dep_insn, cost)
preceding divide or sqrt operation has finished if
the target of the ALU flop is any of the sources
(or destination) of the divide or sqrt operation. */
- return cost - 2;
+ if (hppa_use_dfa_pipeline_interface ())
+ return insn_default_latency (dep_insn) - 2;
+ else
+ return cost - 2;
default:
return 0;
@@ -4069,8 +4096,15 @@ pa_adjust_cost (insn, link, dep_insn, cost)
/* A fpload can't be issued until one cycle before a
preceding arithmetic operation has finished if
the target of the fpload is the destination of the
- arithmetic operation. */
- return cost - 1;
+ arithmetic operation.
+
+ Exception: For PA7100LC, PA7200 and PA7300, the cost
+ is 3 cycles, unless they bundle together. We also
+ pay the penalty if the second insn is a fpload. */
+ if (hppa_use_dfa_pipeline_interface ())
+ return insn_default_latency (dep_insn) - 1;
+ else
+ return cost - 1;
default:
return 0;
@@ -4105,7 +4139,10 @@ pa_adjust_cost (insn, link, dep_insn, cost)
preceding divide or sqrt operation has finished if
the target of the ALU flop is also the target of
the divide or sqrt operation. */
- return cost - 2;
+ if (hppa_use_dfa_pipeline_interface ())
+ return insn_default_latency (dep_insn) - 2;
+ else
+ return cost - 2;
default:
return 0;
@@ -4165,6 +4202,7 @@ pa_issue_rate ()
case PROCESSOR_7100: return 2;
case PROCESSOR_7100LC: return 2;
case PROCESSOR_7200: return 2;
+ case PROCESSOR_7300: return 2;
case PROCESSOR_8000: return 4;
default:
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index d1d37739532..0fd96bcb3b7 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -41,6 +41,7 @@ enum processor_type
PROCESSOR_7100,
PROCESSOR_7100LC,
PROCESSOR_7200,
+ PROCESSOR_7300,
PROCESSOR_8000
};
diff --git a/gcc/config/pa/pa.md b/gcc/config/pa/pa.md
index c80edcc2e2b..ca99b3249e2 100644
--- a/gcc/config/pa/pa.md
+++ b/gcc/config/pa/pa.md
@@ -44,7 +44,7 @@
;;
;; FIXME: Add 800 scheduling for completeness?
-(define_attr "cpu" "700,7100,7100LC,7200,8000" (const (symbol_ref "pa_cpu_attr")))
+(define_attr "cpu" "700,7100,7100LC,7200,7300,8000" (const (symbol_ref "pa_cpu_attr")))
;; Length (in # of bytes).
(define_attr "length" ""
@@ -139,35 +139,10 @@
(const_int 0)))
[(eq_attr "in_branch_delay" "true") (nil) (nil)])
-;; Function units of the HPPA. The following data is for the 700 CPUs
-;; (Mustang CPU + Timex FPU aka PA-89) because that's what I have the docs for.
-;; Scheduling instructions for PA-83 machines according to the Snake
-;; constraints shouldn't hurt.
-
-;; (define_function_unit {name} {num-units} {n-users} {test}
-;; {ready-delay} {issue-delay} [{conflict-list}])
-
-;; The integer ALU.
-;; (Noted only for documentation; units that take one cycle do not need to
-;; be specified.)
-
-;; (define_function_unit "alu" 1 0
-;; (and (eq_attr "type" "unary,shift,nullshift,binary,move,address")
-;; (eq_attr "cpu" "700"))
-;; 1 0)
-
-
;; Memory. Disregarding Cache misses, the Mustang memory times are:
;; load: 2, fpload: 3
;; store, fpstore: 3, no D-cache operations should be scheduled.
-(define_function_unit "pa700memory" 1 0
- (and (eq_attr "type" "load,fpload")
- (eq_attr "cpu" "700")) 2 0)
-(define_function_unit "pa700memory" 1 0
- (and (eq_attr "type" "store,fpstore")
- (eq_attr "cpu" "700")) 3 3)
-
;; The Timex (aka 700) has two floating-point units: ALU, and MUL/DIV/SQRT.
;; Timings:
;; Instruction Time Unit Minimum Distance (unit contention)
@@ -186,44 +161,73 @@
;; fdiv,dbl 12 MPY 12
;; fsqrt,sgl 14 MPY 14
;; fsqrt,dbl 18 MPY 18
+;;
+;; We don't model fmpyadd/fmpysub properly as those instructions
+;; keep both the FP ALU and MPY units busy. Given that these
+;; processors are obsolete, I'm not going to spend the time to
+;; model those instructions correctly.
-(define_function_unit "pa700fp_alu" 1 0
+(define_automaton "pa700")
+(define_cpu_unit "dummy_700,mem_700,fpalu_700,fpmpy_700" "pa700")
+
+(define_insn_reservation "W0" 4
(and (eq_attr "type" "fpcc")
- (eq_attr "cpu" "700")) 4 2)
-(define_function_unit "pa700fp_alu" 1 0
+ (eq_attr "cpu" "700"))
+ "fpalu_700*2")
+
+(define_insn_reservation "W1" 3
(and (eq_attr "type" "fpalu")
- (eq_attr "cpu" "700")) 3 2)
-(define_function_unit "pa700fp_mpy" 1 0
+ (eq_attr "cpu" "700"))
+ "fpalu_700*2")
+
+(define_insn_reservation "W2" 3
(and (eq_attr "type" "fpmulsgl,fpmuldbl")
- (eq_attr "cpu" "700")) 3 2)
-(define_function_unit "pa700fp_mpy" 1 0
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*2")
+
+(define_insn_reservation "W3" 10
(and (eq_attr "type" "fpdivsgl")
- (eq_attr "cpu" "700")) 10 10)
-(define_function_unit "pa700fp_mpy" 1 0
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*10")
+
+(define_insn_reservation "W4" 12
(and (eq_attr "type" "fpdivdbl")
- (eq_attr "cpu" "700")) 12 12)
-(define_function_unit "pa700fp_mpy" 1 0
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*12")
+
+(define_insn_reservation "W5" 14
(and (eq_attr "type" "fpsqrtsgl")
- (eq_attr "cpu" "700")) 14 14)
-(define_function_unit "pa700fp_mpy" 1 0
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*14")
+
+(define_insn_reservation "W6" 18
(and (eq_attr "type" "fpsqrtdbl")
- (eq_attr "cpu" "700")) 18 18)
+ (eq_attr "cpu" "700"))
+ "fpmpy_700*18")
+
+(define_insn_reservation "W7" 2
+ (and (eq_attr "type" "load,fpload")
+ (eq_attr "cpu" "700"))
+ "mem_700")
+
+(define_insn_reservation "W8" 3
+ (and (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "700"))
+ "mem_700*3")
+
+(define_insn_reservation "W9" 1
+ (and (eq_attr "type" "!fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpdivdbl,fpsqrtsgl,fpsqrtdbl,load,fpload,store,fpstore")
+ (eq_attr "cpu" "700"))
+ "dummy_700")
;; Function units for the 7100 and 7150. The 7100/7150 can dual-issue
;; floating point computations with non-floating point computations (fp loads
;; and stores are not fp computations).
;;
-
;; Memory. Disregarding Cache misses, memory loads take two cycles; stores also
;; take two cycles, during which no Dcache operations should be scheduled.
;; Any special cases are handled in pa_adjust_cost. The 7100, 7150 and 7100LC
;; all have the same memory characteristics if one disregards cache misses.
-(define_function_unit "pa7100memory" 1 0
- (and (eq_attr "type" "load,fpload")
- (eq_attr "cpu" "7100,7100LC")) 2 0)
-(define_function_unit "pa7100memory" 1 0
- (and (eq_attr "type" "store,fpstore")
- (eq_attr "cpu" "7100,7100LC")) 2 2)
;; The 7100/7150 has three floating-point units: ALU, MUL, and DIV.
;; Timings:
@@ -243,41 +247,46 @@
;; fdiv,dbl 15 DIV 15
;; fsqrt,sgl 8 DIV 8
;; fsqrt,dbl 15 DIV 15
+;;
+;; We don't really model the FP ALU/MPY units properly (they are
+;; distinct subunits in the FP unit). However, there can never be
+;; a functional unit; conflict given the latency and issue rates
+;; for those units.
-(define_function_unit "pa7100fp_alu" 1 0
- (and (eq_attr "type" "fpcc,fpalu")
- (eq_attr "cpu" "7100")) 2 1)
-(define_function_unit "pa7100fp_mpy" 1 0
- (and (eq_attr "type" "fpmulsgl,fpmuldbl")
- (eq_attr "cpu" "7100")) 2 1)
-(define_function_unit "pa7100fp_div" 1 0
+(define_automaton "pa7100")
+(define_cpu_unit "i_7100, f_7100,fpmac_7100,fpdivsqrt_7100,mem_7100" "pa7100")
+
+(define_insn_reservation "X0" 2
+ (and (eq_attr "type" "fpcc,fpalu,fpmulsgl,fpmuldbl")
+ (eq_attr "cpu" "7100"))
+ "f_7100,fpmac_7100")
+
+(define_insn_reservation "X1" 8
(and (eq_attr "type" "fpdivsgl,fpsqrtsgl")
- (eq_attr "cpu" "7100")) 8 8)
-(define_function_unit "pa7100fp_div" 1 0
- (and (eq_attr "type" "fpdivdbl,fpsqrtdbl")
- (eq_attr "cpu" "7100")) 15 15)
+ (eq_attr "cpu" "7100"))
+ "f_7100+fpdivsqrt_7100,fpdivsqrt_7100*7")
-;; To encourage dual issue we define function units corresponding to
-;; the instructions which can be dual issued. This is a rather crude
-;; approximation, the "pa7100nonflop" test in particular could be refined.
-(define_function_unit "pa7100flop" 1 1
- (and
- (eq_attr "type" "fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl")
- (eq_attr "cpu" "7100")) 1 1)
+(define_insn_reservation "X2" 15
+ (and (eq_attr "type" "fpdivdbl,fpsqrtdbl")
+ (eq_attr "cpu" "7100"))
+ "f_7100+fpdivsqrt_7100,fpdivsqrt_7100*14")
-(define_function_unit "pa7100nonflop" 1 1
- (and
- (eq_attr "type" "!fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl")
- (eq_attr "cpu" "7100")) 1 1)
+(define_insn_reservation "X3" 2
+ (and (eq_attr "type" "load,fpload")
+ (eq_attr "cpu" "7100"))
+ "i_7100+mem_7100")
+(define_insn_reservation "X4" 2
+ (and (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "7100"))
+ "i_7100+mem_7100,mem_7100")
-;; Memory subsystem works just like 7100/7150 (except for cache miss times which
-;; we don't model here).
+(define_insn_reservation "X5" 1
+ (and (eq_attr "type" "!fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl,load,fpload,store,fpstore")
+ (eq_attr "cpu" "7100"))
+ "i_7100")
;; The 7100LC has three floating-point units: ALU, MUL, and DIV.
-;; Note divides and sqrt flops lock the cpu until the flop is
-;; finished. fmpy and xmpyu (fmpyi) lock the cpu for one cycle.
-;; There's no way to avoid the penalty.
;; Timings:
;; Instruction Time Unit Minimum Distance (unit contention)
;; fcpy 2 ALU 1
@@ -299,106 +308,179 @@
;; fdiv,dbl 15 DIV 15
;; fsqrt,sgl 8 DIV 8
;; fsqrt,dbl 15 DIV 15
-
-(define_function_unit "pa7100LCfp_alu" 1 0
+;;
+;; The PA7200 is just like the PA7100LC except that there is
+;; no store-store penalty.
+;;
+;; The PA7300 is just like the PA7200 except that there is
+;; no store-load penalty.
+;;
+;; Note there are some aspects of the 7100LC we are not modeling
+;; at the moment. I'll be reviewing the 7100LC scheduling info
+;; shortly and updating this description.
+;;
+;; load-load pairs
+;; store-store pairs
+;; fmpyadd,dbl
+;; fmpysub,dbl
+;; other issue modeling
+
+(define_automaton "pa7100lc")
+(define_cpu_unit "i0_7100lc, i1_7100lc, f_7100lc" "pa7100lc")
+(define_cpu_unit "fpalu_7100lc,fpdivsqrt_7100lc,fpmul_7100lc" "pa7100lc")
+(define_cpu_unit "mem_7100lc" "pa7100lc")
+
+(define_insn_reservation "Y0" 2
(and (eq_attr "type" "fpcc,fpalu")
- (eq_attr "cpu" "7100LC,7200")) 2 1)
-(define_function_unit "pa7100LCfp_mpy" 1 0
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "f_7100lc,fpalu_7100lc")
+
+(define_insn_reservation "Y1" 2
(and (eq_attr "type" "fpmulsgl")
- (eq_attr "cpu" "7100LC,7200")) 2 1)
-(define_function_unit "pa7100LCfp_mpy" 1 0
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "f_7100lc,fpmul_7100lc")
+
+(define_insn_reservation "Y2" 3
(and (eq_attr "type" "fpmuldbl")
- (eq_attr "cpu" "7100LC,7200")) 3 2)
-(define_function_unit "pa7100LCfp_div" 1 0
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "f_7100lc,fpmul_7100lc,fpmul_7100lc")
+
+(define_insn_reservation "Y3" 8
(and (eq_attr "type" "fpdivsgl,fpsqrtsgl")
- (eq_attr "cpu" "7100LC,7200")) 8 8)
-(define_function_unit "pa7100LCfp_div" 1 0
- (and (eq_attr "type" "fpdivdbl,fpsqrtdbl")
- (eq_attr "cpu" "7100LC,7200")) 15 15)
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "f_7100lc+fpdivsqrt_7100lc,fpdivsqrt_7100lc*7")
-;; Define the various functional units for dual-issue.
+(define_insn_reservation "Y4" 15
+ (and (eq_attr "type" "fpdivdbl,fpsqrtdbl")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "f_7100lc+fpdivsqrt_7100lc,fpdivsqrt_7100lc*14")
-;; There's only one floating point unit.
-(define_function_unit "pa7100LCflop" 1 1
- (and
- (eq_attr "type" "fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl")
- (eq_attr "cpu" "7100LC,7200")) 1 1)
+(define_insn_reservation "Y5" 2
+ (and (eq_attr "type" "load,fpload")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "i1_7100lc+mem_7100lc")
-;; Shifts and memory ops execute in only one of the integer ALUs
-(define_function_unit "pa7100LCshiftmem" 1 1
- (and
- (eq_attr "type" "shift,nullshift,load,fpload,store,fpstore")
- (eq_attr "cpu" "7100LC,7200")) 1 1)
+(define_insn_reservation "Y6" 2
+ (and (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "7100LC"))
+ "i1_7100lc+mem_7100lc,mem_7100lc")
-;; We have two basic ALUs.
-(define_function_unit "pa7100LCalu" 2 1
- (and
- (eq_attr "type" "!fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl")
- (eq_attr "cpu" "7100LC,7200")) 1 1)
+(define_insn_reservation "Y7" 1
+ (and (eq_attr "type" "shift,nullshift")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "i1_7100lc")
-;; I don't have complete information on the PA7200; however, most of
-;; what I've heard makes it look like a 7100LC without the store-store
-;; penalty. So that's how we'll model it.
+(define_insn_reservation "Y8" 1
+ (and (eq_attr "type" "!fpcc,fpalu,fpmulsgl,fpmuldbl,fpdivsgl,fpsqrtsgl,fpdivdbl,fpsqrtdbl,load,fpload,store,fpstore,shift,nullshift")
+ (eq_attr "cpu" "7100LC,7200,7300"))
+ "(i0_7100lc|i1_7100lc)")
-;; Memory. Disregarding Cache misses, memory loads and stores take
-;; two cycles. Any special cases are handled in pa_adjust_cost.
-(define_function_unit "pa7200memory" 1 0
- (and (eq_attr "type" "load,fpload,store,fpstore")
- (eq_attr "cpu" "7200")) 2 0)
+;; The 7200 has a store-load penalty
+(define_insn_reservation "Y9" 2
+ (and (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "7200"))
+ "i0_7100lc,mem_7100lc")
-;; I don't have detailed information on the PA7200 FP pipeline, so I
-;; treat it just like the 7100LC pipeline.
-;; Similarly for the multi-issue fake units.
+;; The 7300 has no penalty for store-store or store-load
+(define_insn_reservation "YA" 2
+ (and (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "7300"))
+ "i0_7100lc")
-;;
;; Scheduling for the PA8000 is somewhat different than scheduling for a
;; traditional architecture.
;;
;; The PA8000 has a large (56) entry reorder buffer that is split between
;; memory and non-memory operations.
;;
-;; The PA800 can issue two memory and two non-memory operations per cycle to
-;; the function units. Similarly, the PA8000 can retire two memory and two
-;; non-memory operations per cycle.
+;; The PA8000 can issue two memory and two non-memory operations per cycle to
+;; the function units, with the exception of branches and multi-output
+;; instructions. The PA8000 can retire two non-memory operations per cycle
+;; and two memory operations per cycle, only one of which may be a store.
;;
;; Given the large reorder buffer, the processor can hide most latencies.
;; According to HP, they've got the best results by scheduling for retirement
;; bandwidth with limited latency scheduling for floating point operations.
;; Latency for integer operations and memory references is ignored.
;;
-;; We claim floating point operations have a 2 cycle latency and are
-;; fully pipelined, except for div and sqrt which are not pipelined.
;;
-;; It is not necessary to define the shifter and integer alu units.
+;; We claim floating point operations have a 2 cycle latency and are
+;; fully pipelined, except for div and sqrt which are not pipelined and
+;; take from 17 to 31 cycles to complete.
;;
-;; These first two define_unit_unit descriptions model retirement from
-;; the reorder buffer.
-(define_function_unit "pa8000lsu" 2 1
+;; It's worth noting that there is no way to saturate all the functional
+;; units on the PA8000 as there is not enough issue bandwidth.
+
+(define_automaton "pa8000")
+(define_cpu_unit "inm0_8000, inm1_8000, im0_8000, im1_8000" "pa8000")
+(define_cpu_unit "rnm0_8000, rnm1_8000, rm0_8000, rm1_8000" "pa8000")
+(define_cpu_unit "store_8000" "pa8000")
+(define_cpu_unit "f0_8000, f1_8000" "pa8000")
+(define_cpu_unit "fdivsqrt0_8000, fdivsqrt1_8000" "pa8000")
+(define_reservation "inm_8000" "inm0_8000 | inm1_8000")
+(define_reservation "im_8000" "im0_8000 | im1_8000")
+(define_reservation "rnm_8000" "rnm0_8000 | rnm1_8000")
+(define_reservation "rm_8000" "rm0_8000 | rm1_8000")
+(define_reservation "f_8000" "f0_8000 | f1_8000")
+(define_reservation "fdivsqrt_8000" "fdivsqrt0_8000 | fdivsqrt1_8000")
+
+;; We can issue any two memops per cycle, but we can only retire
+;; one memory store per cycle. We assume that the reorder buffer
+;; will hide any memory latencies per HP's recommendation.
+(define_insn_reservation "Z0" 0
(and
- (eq_attr "type" "load,fpload,store,fpstore")
- (eq_attr "cpu" "8000")) 1 1)
+ (eq_attr "type" "load,fpload")
+ (eq_attr "cpu" "8000"))
+ "im_8000,rm_8000")
-(define_function_unit "pa8000alu" 2 1
+(define_insn_reservation "Z1" 0
(and
- (eq_attr "type" "!load,fpload,store,fpstore")
- (eq_attr "cpu" "8000")) 1 1)
-
-;; Claim floating point ops have a 2 cycle latency, excluding div and
-;; sqrt, which are not pipelined and issue to different units.
-(define_function_unit "pa8000fmac" 2 0
+ (eq_attr "type" "store,fpstore")
+ (eq_attr "cpu" "8000"))
+ "im_8000,rm_8000+store_8000")
+
+;; We can issue and retire two non-memory operations per cycle with
+;; a few exceptions (branches). This group catches those we want
+;; to assume have zero latency.
+(define_insn_reservation "Z2" 0
(and
- (eq_attr "type" "fpcc,fpalu,fpmulsgl,fpmuldbl")
- (eq_attr "cpu" "8000")) 2 1)
+ (eq_attr "type" "!load,fpload,store,fpstore,uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch,fpcc,fpalu,fpmulsgl,fpmuldbl,fpsqrtsgl,fpsqrtdbl,fpdivsgl,fpdivdbl")
+ (eq_attr "cpu" "8000"))
+ "inm_8000,rnm_8000")
-(define_function_unit "pa8000fdiv" 2 1
+;; Branches use both slots in the non-memory issue and
+;; retirement unit.
+(define_insn_reservation "Z3" 0
(and
- (eq_attr "type" "fpdivsgl,fpsqrtsgl")
- (eq_attr "cpu" "8000")) 17 17)
+ (eq_attr "type" "uncond_branch,branch,cbranch,fbranch,call,dyncall,multi,milli,parallel_branch")
+ (eq_attr "cpu" "8000"))
+ "inm0_8000+inm1_8000,rnm0_8000+rnm1_8000")
+
+;; We partial latency schedule the floating point units.
+;; They can issue/retire two at a time in the non-memory
+;; units. We fix their latency at 2 cycles and they
+;; are fully pipelined.
+(define_insn_reservation "Z4" 1
+ (and
+ (eq_attr "type" "fpcc,fpalu,fpmulsgl,fpmuldbl")
+ (eq_attr "cpu" "8000"))
+ "inm_8000,f_8000,rnm_8000")
+
+;; The fdivsqrt units are not pipelined and have a very long latency.
+;; To keep the DFA from exploding, we do not show all the
+;; reservations for the divsqrt unit.
+(define_insn_reservation "Z5" 17
+ (and
+ (eq_attr "type" "fpdivsgl,fpsqrtsgl")
+ (eq_attr "cpu" "8000"))
+ "inm_8000,fdivsqrt_8000*6,rnm_8000")
+
+(define_insn_reservation "Z6" 31
+ (and
+ (eq_attr "type" "fpdivdbl,fpsqrtdbl")
+ (eq_attr "cpu" "8000"))
+ "inm_8000,fdivsqrt_8000*6,rnm_8000")
-(define_function_unit "pa8000fdiv" 2 1
- (and
- (eq_attr "type" "fpdivdbl,fpsqrtdbl")
- (eq_attr "cpu" "8000")) 31 31)
;; Compare instructions.
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 43c70a29cc5..5eee362610b 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -197,6 +197,9 @@ static void sh_insert_attributes PARAMS ((tree, tree *));
static void sh_asm_named_section PARAMS ((const char *, unsigned int));
#endif
static int sh_adjust_cost PARAMS ((rtx, rtx, rtx, int));
+static int sh_use_dfa_interface PARAMS ((void));
+static int sh_issue_rate PARAMS ((void));
+
static bool sh_cannot_modify_jumps_p PARAMS ((void));
static bool sh_ms_bitfield_layout_p PARAMS ((tree));
@@ -226,6 +229,12 @@ static bool sh_ms_bitfield_layout_p PARAMS ((tree));
#undef TARGET_SCHED_ADJUST_COST
#define TARGET_SCHED_ADJUST_COST sh_adjust_cost
+#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE \
+ sh_use_dfa_interface
+#undef TARGET_SCHED_ISSUE_RATE
+#define TARGET_SCHED_ISSUE_RATE sh_issue_rate
+
#undef TARGET_CANNOT_MODIFY_JUMPS_P
#define TARGET_CANNOT_MODIFY_JUMPS_P sh_cannot_modify_jumps_p
@@ -6726,6 +6735,29 @@ sh_pr_n_sets ()
return REG_N_SETS (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG);
}
+/* This Function Returns non zero if DFA based scheduler
+ interface is to be used.At present supported only for
+ SH4. */
+static int
+sh_use_dfa_interface()
+{
+ if (TARGET_SH4)
+ return 1;
+ else
+ return 0;
+}
+
+/* This function returns "2" that signifies dual issue
+ for SH4 processor.To be used by DFA pipeline description. */
+static int
+sh_issue_rate()
+{
+ if(TARGET_SH4)
+ return 2;
+ else
+ return 1;
+}
+
/* SHmedia requires registers for branches, so we can't generate new
branches past reload. */
static bool
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 096b6840369..95aaa0d06f1 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -195,6 +195,28 @@
"cbranch,jump,jump_ind,arith,arith3,arith3b,dyn_shift,other,load,load_si,store,move,fmove,smpy,dmpy,return,pload,prset,pstore,prget,pcload,pcload_si,pt,ptabs,rte,sfunc,call,fp,fdiv,dfp_arith,dfp_cmp,dfp_conv,dfdiv,gp_fpul,nil"
(const_string "other"))
+;; We define a new attribute namely "insn_class".We use
+;; this for DFA based pipeline description.
+;; Although the "type" attribute covers almost all insn
+;; classes,it is more convenient to define new attribute
+;; for certain reservations.
+;;
+;; mt_group SH4 "mt" group instructions.
+;;
+;; ex_group SH4 "ex" group instructions.They mostly
+;; overlap with arithmetic instructions but
+;; new attribute defined to distinguish from
+;; mt group instructions.
+;;
+;; lds_to_fpscr The "type" attribute couldn't sufficiently
+;; distinguish it from others.It is part of
+;; new attribute.Similar case with ldsmem_to_fpscr
+;; and cwb.
+
+(define_attr "insn_class"
+ "mt_group,ex_group,lds_to_fpscr,ldsmem_to_fpscr,cwb,none"
+ (const_string "none"))
+
;; Indicate what precision must be selected in fpscr for this insn, if any.
(define_attr "fp_mode" "single,double,none" (const_string "none"))
@@ -631,7 +653,8 @@
(match_operand:SI 1 "arith_operand" "L,r"))
(const_int 0)))]
"TARGET_SH1"
- "tst %1,%0")
+ "tst %1,%0"
+ [(set_attr "insn_class" "mt_group")])
;; ??? Perhaps should only accept reg/constant if the register is reg 0.
;; That would still allow reload to create cmpi instructions, but would
@@ -647,7 +670,8 @@
"@
tst %0,%0
cmp/eq %1,%0
- cmp/eq %1,%0")
+ cmp/eq %1,%0"
+ [(set_attr "insn_class" "mt_group,mt_group,mt_group")])
(define_insn "cmpgtsi_t"
[(set (reg:SI T_REG)
@@ -656,7 +680,8 @@
"TARGET_SH1"
"@
cmp/gt %1,%0
- cmp/pl %0")
+ cmp/pl %0"
+ [(set_attr "insn_class" "mt_group,mt_group")])
(define_insn "cmpgesi_t"
[(set (reg:SI T_REG)
@@ -665,8 +690,9 @@
"TARGET_SH1"
"@
cmp/ge %1,%0
- cmp/pz %0")
-
+ cmp/pz %0"
+ [(set_attr "insn_class" "mt_group,mt_group")])
+
;; -------------------------------------------------------------------------
;; SImode unsigned integer comparisons
;; -------------------------------------------------------------------------
@@ -676,14 +702,16 @@
(geu:SI (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
- "cmp/hs %1,%0")
+ "cmp/hs %1,%0"
+ [(set_attr "insn_class" "mt_group")])
(define_insn "cmpgtusi_t"
[(set (reg:SI T_REG)
(gtu:SI (match_operand:SI 0 "arith_reg_operand" "r")
(match_operand:SI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
- "cmp/hi %1,%0")
+ "cmp/hi %1,%0"
+ [(set_attr "insn_class" "mt_group")])
;; We save the compare operands in the cmpxx patterns and use them when
;; we generate the branch.
@@ -1050,7 +1078,8 @@
(ltu:SI (plus:SI (match_dup 1) (match_dup 2)) (match_dup 1)))]
"TARGET_SH1"
"addc %2,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "addc1"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -1060,7 +1089,8 @@
(clobber (reg:SI T_REG))]
"TARGET_SH1"
"addc %2,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_expand "addsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "")
@@ -1088,8 +1118,9 @@
(match_operand:SI 2 "arith_operand" "rI")))]
"TARGET_SH1"
"add %2,%0"
- [(set_attr "type" "arith")])
-
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
+
;; -------------------------------------------------------------------------
;; Subtraction instructions
;; -------------------------------------------------------------------------
@@ -1155,7 +1186,8 @@
(gtu:SI (minus:SI (match_dup 1) (match_dup 2)) (match_dup 1)))]
"TARGET_SH1"
"subc %2,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "subc1"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -1165,7 +1197,8 @@
(clobber (reg:SI T_REG))]
"TARGET_SH1"
"subc %2,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "*subsi3_internal"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -1173,7 +1206,8 @@
(match_operand:SI 2 "arith_reg_operand" "r")))]
"TARGET_SH1"
"sub %2,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "*subsi3_media"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -1909,7 +1943,8 @@
(match_operand:SI 2 "logical_operand" "r,L")))]
"TARGET_SH1"
"and %2,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
;; If the constant is 255, then emit a extu.b instruction instead of an
;; and, since that will give better code.
@@ -1951,7 +1986,8 @@
(match_operand:SI 2 "logical_operand" "r,L")))]
"TARGET_SH1"
"or %2,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "iordi3"
[(set (match_operand:DI 0 "arith_reg_operand" "=r,r")
@@ -1968,7 +2004,8 @@
(match_operand:SI 2 "logical_operand" "L,r")))]
"TARGET_SH1"
"xor %2,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "xordi3"
[(set (match_operand:DI 0 "arith_reg_operand" "=r,r")
@@ -1991,7 +2028,8 @@
(lshiftrt:SI (match_dup 1) (const_int 31)))]
"TARGET_SH1"
"rotl %0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "rotlsi3_31"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -2000,7 +2038,8 @@
(clobber (reg:SI T_REG))]
"TARGET_SH1"
"rotr %0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "rotlsi3_16"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -2008,7 +2047,8 @@
(const_int 16)))]
"TARGET_SH1"
"swap.w %1,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_expand "rotlsi3"
[(set (match_operand:SI 0 "arith_reg_operand" "")
@@ -2072,7 +2112,8 @@
(const_int 8)))]
"TARGET_SH1"
"swap.b %1,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_expand "rotlhi3"
[(set (match_operand:HI 0 "arith_reg_operand" "")
@@ -2114,7 +2155,8 @@
(clobber (match_dup 4))])]
"operands[4] = gen_rtx_SCRATCH (SImode);"
[(set_attr "length" "*,*,*,4")
- (set_attr "type" "dyn_shift,arith,arith,arith")])
+ (set_attr "type" "dyn_shift,arith,arith,arith")
+ (set_attr "insn_class" "ex_group,ex_group,ex_group,ex_group")])
(define_insn "ashlhi3_k"
[(set (match_operand:HI 0 "arith_reg_operand" "=r,r")
@@ -2124,7 +2166,8 @@
"@
add %0,%0
shll%O2 %0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "ashlsi3_n"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -2141,7 +2184,8 @@
(eq (symbol_ref "shift_insns_rtx (insn)") (const_int 3))
(const_string "6")]
(const_string "8")))
- (set_attr "type" "arith")])
+ (set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_split
[(set (match_operand:SI 0 "arith_reg_operand" "")
@@ -2229,7 +2273,8 @@
(clobber (reg:SI T_REG))]
"TARGET_SH1 && INTVAL (operands[2]) == 1"
"shar %0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
;; We can't do HImode right shifts correctly unless we start out with an
;; explicit zero / sign extension; doing that would result in worse overall
@@ -2288,7 +2333,8 @@
(lt:SI (match_dup 1) (const_int 0)))]
"TARGET_SH1"
"shll %0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "ashrsi3_d"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -2296,7 +2342,8 @@
(neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
"TARGET_SH3"
"shad %2,%0"
- [(set_attr "type" "dyn_shift")])
+ [(set_attr "type" "dyn_shift")
+ (set_attr "insn_class" "ex_group")])
(define_insn "ashrsi3_n"
[(set (reg:SI R4_REG)
@@ -2346,7 +2393,8 @@
(neg:SI (match_operand:SI 2 "arith_reg_operand" "r"))))]
"TARGET_SH3"
"shld %2,%0"
- [(set_attr "type" "dyn_shift")])
+ [(set_attr "type" "dyn_shift")
+ (set_attr "insn_class" "ex_group")])
;; Only the single bit shift clobbers the T bit.
@@ -2357,7 +2405,8 @@
(clobber (reg:SI T_REG))]
"TARGET_SH1 && CONST_OK_FOR_M (INTVAL (operands[2]))"
"shlr %0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "lshrsi3_k"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -2366,7 +2415,8 @@
"TARGET_SH1 && CONST_OK_FOR_K (INTVAL (operands[2]))
&& ! CONST_OK_FOR_M (INTVAL (operands[2]))"
"shlr%O2 %0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "lshrsi3_n"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -2444,7 +2494,8 @@
"TARGET_SH1"
"shll %R0\;rotcl %S0"
[(set_attr "length" "4")
- (set_attr "type" "arith")])
+ (set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "ashldi3_media"
[(set (match_operand:DI 0 "arith_reg_operand" "=r,r")
@@ -2483,7 +2534,8 @@
"TARGET_SH1"
"shlr %S0\;rotcr %R0"
[(set_attr "length" "4")
- (set_attr "type" "arith")])
+ (set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "lshrdi3_media"
[(set (match_operand:DI 0 "arith_reg_operand" "=r,r")
@@ -2522,7 +2574,8 @@
"TARGET_SH1"
"shar %S0\;rotcr %R0"
[(set_attr "length" "4")
- (set_attr "type" "arith")])
+ (set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "ashrdi3_media"
[(set (match_operand:DI 0 "arith_reg_operand" "=r,r")
@@ -2756,7 +2809,8 @@
(const_int 16))))]
"TARGET_SH1"
"xtrct %1,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "xtrct_right"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
@@ -2766,8 +2820,9 @@
(const_int 16))))]
"TARGET_SH1"
"xtrct %2,%0"
- [(set_attr "type" "arith")])
-
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
+
;; -------------------------------------------------------------------------
;; Unary arithmetic
;; -------------------------------------------------------------------------
@@ -2781,7 +2836,8 @@
(const_int 0)))]
"TARGET_SH1"
"negc %1,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "*negdi_media"
[(set (match_operand:DI 0 "arith_reg_operand" "=r")
@@ -2819,14 +2875,16 @@
(neg:SI (match_operand:SI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
"neg %1,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "one_cmplsi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(not:SI (match_operand:SI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
"not %1,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_expand "one_cmpldi2"
[(set (match_operand:DI 0 "arith_reg_operand" "")
@@ -2872,22 +2930,25 @@
(zero_extend:SI (match_operand:HI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
"extu.w %1,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "zero_extendqisi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r")
(zero_extend:SI (match_operand:QI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
"extu.b %1,%0"
- [(set_attr "type" "arith")])
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
(define_insn "zero_extendqihi2"
[(set (match_operand:HI 0 "arith_reg_operand" "=r")
(zero_extend:HI (match_operand:QI 1 "arith_reg_operand" "r")))]
"TARGET_SH1"
"extu.b %1,%0"
- [(set_attr "type" "arith")])
-
+ [(set_attr "type" "arith")
+ (set_attr "insn_class" "ex_group")])
+
;; -------------------------------------------------------------------------
;; Sign extension instructions
;; -------------------------------------------------------------------------
@@ -2941,7 +3002,8 @@
"@
exts.w %1,%0
mov.w %1,%0"
- [(set_attr "type" "arith,load")])
+ [(set_attr "type" "arith,load")
+ (set_attr "insn_class" "ex_group,*")])
(define_insn "extendqisi2"
[(set (match_operand:SI 0 "arith_reg_operand" "=r,r")
@@ -2950,7 +3012,8 @@
"@
exts.b %1,%0
mov.b %1,%0"
- [(set_attr "type" "arith,load")])
+ [(set_attr "type" "arith,load")
+ (set_attr "insn_class" "ex_group,*")])
(define_insn "extendqihi2"
[(set (match_operand:HI 0 "arith_reg_operand" "=r,r")
@@ -2959,8 +3022,9 @@
"@
exts.b %1,%0
mov.b %1,%0"
- [(set_attr "type" "arith,load")])
-
+ [(set_attr "type" "arith,load")
+ (set_attr "insn_class" "ex_group,*")])
+
;; -------------------------------------------------------------------------
;; Move instructions
;; -------------------------------------------------------------------------
@@ -3070,6 +3134,7 @@
lds.l %1,%0
fake %1,%0"
[(set_attr "type" "pcload_si,move,*,load_si,move,prget,move,store,store,pstore,move,prset,load,pload,pcload_si")
+ (set_attr "insn_class" "*,*,mt_group,*,*,*,*,*,*,*,*,*,*,*,*")
(set_attr "length" "*,*,*,*,*,*,*,*,*,*,*,*,*,*,*")])
;; t/r must come after r/r, lest reload will try to reload stuff like
@@ -3227,7 +3292,8 @@
(clobber (match_scratch:SI 2 "=&r"))]
"TARGET_HARD_SH4"
"ocbwb\\t@%0\;extu.w\\t%0,%2\;or\\t%1,%2\;mov.l\\t%0,@%2"
- [(set_attr "length" "8")])
+ [(set_attr "length" "8")
+ (set_attr "insn_class" "cwb")])
(define_insn "ic_invalidate_line_media"
[(unspec_volatile [(match_operand 0 "register_operand" "r")]
@@ -7415,7 +7481,8 @@
mov.l %1,%0
sts fpscr,%0"
[(set_attr "length" "0,2,2,4,2,2,2,2")
- (set_attr "type" "dfp_conv,dfp_conv,load,dfp_conv,dfp_conv,move,store,gp_fpul")])
+ (set_attr "type" "dfp_conv,dfp_conv,load,dfp_conv,dfp_conv,move,store,gp_fpul")
+ (set_attr "insn_class" "ldsmem_to_fpscr,*,*,lds_to_fpscr,*,*,*,*")])
(define_split
[(set (reg:PSI FPSCR_REG)
@@ -8557,3 +8624,292 @@
"TARGET_SH1"
"mov.l @r15+,r15\;mov.l @r15+,r0"
[(set_attr "length" "4")])
+
+;; The following description models the
+;; SH4 pipeline using the DFA based scheduler.
+;; The DFA based description is better way to model
+;; a superscalar pipeline as compared to function unit
+;; reservation model.
+;; 1. The function unit based model is oriented to describe at most one
+;; unit reservation by each insn. It is difficult to model unit reservations in multiple
+;; pipeline units by same insn. This can be done using DFA based description.
+;; 2. The execution performance of DFA based scheduler does not depend on processor complexity.
+;; 3. Writing all unit reservations for an instruction class is more natural description
+;; of the pipeline and makes interface of the hazard recognizer simpler than the
+;; old function unit based model.
+;; 4. The DFA model is richer and is a part of greater overall framework of RCSP.
+
+
+;; Two automata are defined to reduce number of states
+;; which a single large automaton will have.(Factoring)
+
+(define_automaton "inst_pipeline,fpu_pipe")
+
+;; This unit is basically the decode unit of the processor.
+;; Since SH4 is a dual issue machine,it is as if there are two
+;; units so that any insn can be processed by either one
+;; of the decoding unit.
+
+(define_cpu_unit "pipe_01,pipe_02" "inst_pipeline")
+
+
+;; The fixed point arithmetic calculator(?? EX Unit).
+
+(define_cpu_unit "int" "inst_pipeline")
+
+;; f1_1 and f1_2 are floating point units.Actually there is
+;; a f1 unit which can overlap with other f1 unit but
+;; not another F1 unit.It is as though there were two
+;; f1 units.
+
+(define_cpu_unit "f1_1,f1_2" "fpu_pipe")
+
+;; The floating point units.
+
+(define_cpu_unit "F1,F2,F3,FS" "fpu_pipe")
+
+;; This is basically the MA unit of SH4
+;; used in LOAD/STORE pipeline.
+
+(define_cpu_unit "memory" "inst_pipeline")
+
+;; The address calculator used for branch instructions.
+;; This will be reserved with "issue" of branch instructions
+;; and this is to make sure that no two branch instructions
+;; can be issued in parallel.
+
+(define_cpu_unit "pcr_addrcalc" "inst_pipeline")
+
+;; ----------------------------------------------------
+;; This reservation is to simplify the dual issue description.
+
+(define_reservation "issue" "pipe_01|pipe_02")
+
+;; This is to express the locking of D stage.
+
+(define_reservation "d_lock" "pipe_01+pipe_02")
+
+;; This is to simplify description where F1,F2,FS
+;; are used simultaneously.
+
+(define_reservation "fpu" "F1+F2+FS")
+
+;; This is to highlight the fact that f1
+;; cannot overlap with F1.
+
+(exclusion_set "f1_1,f1_2" "F1")
+
+;; Although reg moves have a latency of zero
+;; we need to highlight that they use D stage
+;; for one cycle.
+
+(define_insn_reservation "reg_mov" 0
+ (eq_attr "type" "move,fmove")
+ "issue")
+
+;; Other MT group intructions(1 step operations)
+;; Group: MT
+;; Latency: 1
+;; Issue Rate: 1
+
+(define_insn_reservation "mt" 1
+ (eq_attr "insn_class" "mt_group")
+ "issue,nothing")
+
+;; Fixed Point Arithmetic Instructions(1 step operations)
+;; Group: EX
+;; Latency: 1
+;; Issue Rate: 1
+
+(define_insn_reservation "simple_arith" 1
+ (eq_attr "insn_class" "ex_group")
+ "issue,int")
+
+;; Load Store instructions. (MOV.[BWL]@(d,GBR)
+;; Group: LS
+;; Latency: 2
+;; Issue Rate: 1
+
+(define_insn_reservation "load_store" 2
+ (eq_attr "type" "load,load_si,pcload,pcload_si,store")
+ "issue,memory*2")
+
+;; Branch (BF,BF/S,BT,BT/S,BRA)
+;; Group: BR
+;; Latency: 2 (or 1) Actually Observed to be 5/7
+;; Issue Rate: 1
+;; The latency is 1 when displacement is 0.
+;; This reservation can be further broken into 2
+;; 1. branch_zero : One with latency 1 and in the TEST
+;; part it also checks for 0 (ZERO) displacement
+;; 2. branch: Latency 2.
+
+(define_insn_reservation "branch_zero" 5
+ (and (eq_attr "type" "cbranch")
+ (eq_attr "length" "2"))
+ "(issue+pcr_addrcalc),pcr_addrcalc,nothing")
+
+(define_insn_reservation "branch" 7
+ (eq_attr "type" "cbranch")
+ "(issue+pcr_addrcalc),pcr_addrcalc,nothing")
+
+;; Branch Far (JMP,RTS,BRAF)
+;; Group: CO
+;; Latency: 3
+;; Issue Rate: 2
+;; Since issue stage (D stage) is blocked for 2nd cycle,
+;; cpu_unit int is reserved since it might be required for far
+;; address calculation.
+
+(define_insn_reservation "branch_far" 12
+ (and (eq_attr "type" "jump,return")
+ (eq_attr "length" "6"))
+ "d_lock*2,int+pcr_addrcalc,pcr_addrcalc")
+
+;; RTE
+;; Group: CO
+;; atency: 5
+;; Issue Rate: 5
+;; this instruction can be executed in any of the pipelines
+;; and blocks the pipeline for next 4 stages.
+
+(define_insn_reservation "return_from_exp" 5
+ (eq_attr "type" "rte")
+ "(issue+pcr_addrcalc),d_lock*4,int+pcr_addrcalc,nothing")
+
+;; OCBP, OCBWB
+;; Group: CO
+;; Latency: 5
+;; Issue Rate: 1
+
+(define_insn_reservation "ocbwb" 5
+ (eq_attr "insn_class" "cwb")
+ "issue,(int+memory),memory*5")
+
+;; LDS to PR,JSR
+;; Group: CO
+;; Latency: 3
+;; Issue Rate: 2
+;; The SX stage is blocked for last 2 cycles.
+
+(define_insn_reservation "lds_to_pr" 3
+ (eq_attr "type" "prset,call,sfunc")
+ "(issue+pcr_addrcalc),(issue+int+pcr_addrcalc),(int+pcr_addrcalc)*2")
+
+;; LDS.L to PR
+;; Group: CO
+;; Latency: 3
+;; Issue Rate: 2
+;; The SX unit is blocked for last 2 cycles.
+
+(define_insn_reservation "ldsmem_to_pr" 3
+ (eq_attr "type" "pload")
+ "(issue+pcr_addrcalc),(issue+int+pcr_addrcalc),(int+memory+pcr_addrcalc),(int+pcr_addrcalc)")
+
+;; STS from PR
+;; Group: CO
+;; Latency: 2
+;; Issue Rate: 2
+;; The SX unit in second and third cycles.
+
+(define_insn_reservation "sts_from_pr" 2
+ (eq_attr "type" "prget")
+ "(issue+pcr_addrcalc),(pipe_01+int+pcr_addrcalc),(int+pcr_addrcalc),nothing")
+
+;; STS.L from PR
+;; Group: CO
+;; Latency: 2
+;; Issue Rate: 2
+
+(define_insn_reservation "prload_mem" 2
+ (eq_attr "type" "pstore")
+ "(issue+pcr_addrcalc),(pipe_01+int+pcr_addrcalc),(int+memory+pcr_addrcalc),memory")
+
+;; LDS to FPSCR
+;; Group: CO
+;; Latency: 4
+;; Issue Rate: 1
+;; F1 is blocked for last three cycles.
+
+(define_insn_reservation "fpscr_store" 4
+ (eq_attr "insn_class" "lds_to_fpscr")
+ "issue,int,F1*3")
+
+;; LDS.L to FPSCR
+;; Group: CO
+;; Latency: 1 / 4
+;; Latency to update Rn is 1 and latency to update FPSCR is 4
+;; Issue Rate: 1
+;; F1 is blocked for last three cycles.
+
+(define_insn_reservation "fpscr_store_mem" 4
+ (eq_attr "insn_class" "ldsmem_to_fpscr")
+ "issue,(int+memory),(F1+memory),F1*2")
+
+
+;; Fixed point multiplication (DMULS.L DMULU.L MUL.L MULS.W,MULU.W)
+;; Group: CO
+;; Latency: 4 / 4
+;; Issue Rate: 1
+
+(define_insn_reservation "multi" 4
+ (eq_attr "type" "smpy,dmpy")
+ "issue,(issue+int+f1_1),(int+f1_1),(f1_1|f1_2)*2,F2,FS")
+
+
+;; Single precision floating point computation FCMP/EQ,
+;; FCP/GT, FADD, FLOAT, FMAC, FMUL, FSUB, FTRC, FRVHG, FSCHG
+;; Group: FE
+;; Latency: 4
+;; Issue Rate: 1
+
+(define_insn_reservation "fp_arith" 4
+ (eq_attr "type" "fp")
+ "issue,F1,F2,FS")
+
+;; Single Precision FDIV/SQRT
+;; Group: FE
+;; Latency: 12/13
+;; Issue Rate: 1
+
+(define_insn_reservation "fp_div" 13
+ (eq_attr "type" "fdiv")
+ "issue,F1+F3,F1+F2+F3,F3*7,F1+F3,F2,FS")
+
+;; Double Precision floating point computation
+;; (FCNVDS, FCNVSD, FLOAT, FTRC)
+;; Group: FE
+;; Latency: (3,4)/5
+;; Issue Rate: 1
+
+(define_insn_reservation "dp_float" 5
+ (eq_attr "type" "dfp_conv")
+ "issue,F1,F1+F2,F2+FS,FS")
+
+;; Double-precision floating-point (FADD ,FMUL,FSUB)
+;; Group: FE
+;; Latency: (7,8)/9
+;; Issue Rate: 1
+
+(define_insn_reservation "fp_double_arith" 9
+ (eq_attr "type" "dfp_arith")
+ "issue,F1,F1+F2,fpu*4,F2+FS,FS")
+
+;; Double-precision FCMP (FCMP/EQ,FCMP/GT)
+;; Group: FE
+;; Latency: 3/5
+;; Issue Rate: 2
+
+(define_insn_reservation "fp_double_cmp" 5
+ (eq_attr "type" "dfp_cmp")
+ "issue,(issue+F1),F1+F2,F2+FS,FS")
+
+;; Double precision FDIV/SQRT
+;; Group: FE
+;; Latency: (24,25)/26
+;; Issue Rate: 1
+
+(define_insn_reservation "dp_div" 26
+ (eq_attr "type" "dfdiv")
+ "issue,F1+F3,F1+F2+F3,F2+F3+FS,F3*16,F1+F3,F1+F2+F3,fpu+F3,F2+FS,FS")
+
diff --git a/gcc/config/sparc/sparc-protos.h b/gcc/config/sparc/sparc-protos.h
index 17f22f463e1..fef6ecb6db0 100644
--- a/gcc/config/sparc/sparc-protos.h
+++ b/gcc/config/sparc/sparc-protos.h
@@ -117,6 +117,8 @@ extern char *sparc_v8plus_shift PARAMS ((rtx *, rtx, const char *));
32 bits of REG are 0 before INSN. */
extern int sparc_check_64 PARAMS ((rtx, rtx));
extern rtx gen_df_reg PARAMS ((rtx, int));
+/* Used for DFA scheduling when cpu is ultrasparc. */
+extern int ultrasparc_store_bypass_p PARAMS ((rtx, rtx));
extern int sparc_extra_constraint_check PARAMS ((rtx, int, int));
#endif /* RTX_CODE */
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index f2b3585413b..2f7633638bc 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -140,22 +140,14 @@ static int function_arg_slotno PARAMS ((const CUMULATIVE_ARGS *,
static int supersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int hypersparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
-static int ultrasparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static void sparc_output_addr_vec PARAMS ((rtx));
static void sparc_output_addr_diff_vec PARAMS ((rtx));
static void sparc_output_deferred_case_vectors PARAMS ((void));
static void sparc_add_gc_roots PARAMS ((void));
-static void mark_ultrasparc_pipeline_state PARAMS ((void *));
static int check_return_regs PARAMS ((rtx));
static int epilogue_renumber PARAMS ((rtx *, int));
static bool sparc_assemble_integer PARAMS ((rtx, unsigned int, int));
-static int ultra_cmove_results_ready_p PARAMS ((rtx));
-static int ultra_fpmode_conflict_exists PARAMS ((enum machine_mode));
-static rtx *ultra_find_type PARAMS ((int, rtx *, int));
-static void ultra_build_types_avail PARAMS ((rtx *, int));
-static void ultra_flush_pipeline PARAMS ((void));
-static void ultra_rescan_pipeline_state PARAMS ((rtx *, int));
static int set_extends PARAMS ((rtx));
static void output_restore_regs PARAMS ((FILE *, int));
static void sparc_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
@@ -169,15 +161,13 @@ static void sparc_nonflat_function_prologue PARAMS ((FILE *, HOST_WIDE_INT,
#ifdef OBJECT_FORMAT_ELF
static void sparc_elf_asm_named_section PARAMS ((const char *, unsigned int));
#endif
-static void ultrasparc_sched_reorder PARAMS ((FILE *, int, rtx *, int));
-static int ultrasparc_variable_issue PARAMS ((rtx));
-static void ultrasparc_sched_init PARAMS ((void));
static int sparc_adjust_cost PARAMS ((rtx, rtx, rtx, int));
static int sparc_issue_rate PARAMS ((void));
-static int sparc_variable_issue PARAMS ((FILE *, int, rtx, int));
static void sparc_sched_init PARAMS ((FILE *, int, int));
-static int sparc_sched_reorder PARAMS ((FILE *, int, rtx *, int *, int));
+static int sparc_use_dfa_pipeline_interface PARAMS ((void));
+static int sparc_use_sched_lookahead PARAMS ((void));
+static rtx sparc_cycle_display PARAMS ((int, rtx));
/* Option handling. */
@@ -231,12 +221,14 @@ enum processor_type sparc_cpu;
#define TARGET_SCHED_ADJUST_COST sparc_adjust_cost
#undef TARGET_SCHED_ISSUE_RATE
#define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
-#undef TARGET_SCHED_VARIABLE_ISSUE
-#define TARGET_SCHED_VARIABLE_ISSUE sparc_variable_issue
#undef TARGET_SCHED_INIT
#define TARGET_SCHED_INIT sparc_sched_init
-#undef TARGET_SCHED_REORDER
-#define TARGET_SCHED_REORDER sparc_sched_reorder
+#undef TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE
+#define TARGET_SCHED_USE_DFA_PIPELINE_INTERFACE sparc_use_dfa_pipeline_interface
+#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
+#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead
+#undef TARGET_SCHED_CYCLE_DISPLAY
+#define TARGET_SCHED_CYCLE_DISPLAY sparc_cycle_display
struct gcc_target targetm = TARGET_INITIALIZER;
@@ -273,6 +265,7 @@ sparc_override_options ()
{ TARGET_CPU_supersparc, "supersparc" },
{ TARGET_CPU_v9, "v9" },
{ TARGET_CPU_ultrasparc, "ultrasparc" },
+ { TARGET_CPU_ultrasparc3, "ultrasparc3" },
{ 0, 0 }
};
const struct cpu_default *def;
@@ -305,6 +298,9 @@ sparc_override_options ()
/* Although insns using %y are deprecated, it is a clear win on current
ultrasparcs. */
|MASK_DEPRECATED_V8_INSNS},
+ /* TI ultrasparc III */
+ /* ??? Check if %y issue still holds true in ultra3. */
+ { "ultrasparc3", PROCESSOR_ULTRASPARC3, MASK_ISA, MASK_V9|MASK_DEPRECATED_V8_INSNS},
{ 0, 0, 0, 0 }
};
const struct cpu_table *cpu;
@@ -417,7 +413,9 @@ sparc_override_options ()
target_flags &= ~MASK_STACK_BIAS;
/* Supply a default value for align_functions. */
- if (align_functions == 0 && sparc_cpu == PROCESSOR_ULTRASPARC)
+ if (align_functions == 0
+ && (sparc_cpu == PROCESSOR_ULTRASPARC
+ || sparc_cpu == PROCESSOR_ULTRASPARC3))
align_functions = 32;
/* Validate PCC_STRUCT_RETURN. */
@@ -6479,7 +6477,8 @@ sparc64_initialize_trampoline (tramp, fnaddr, cxt)
emit_move_insn (gen_rtx_MEM (DImode, plus_constant (tramp, 24)), fnaddr);
emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, tramp))));
- if (sparc_cpu != PROCESSOR_ULTRASPARC)
+ if (sparc_cpu != PROCESSOR_ULTRASPARC
+ && sparc_cpu != PROCESSOR_ULTRASPARC3)
emit_insn (gen_flushdi (validize_mem (gen_rtx_MEM (DImode, plus_constant (tramp, 8)))));
}
@@ -7332,157 +7331,6 @@ hypersparc_adjust_cost (insn, link, dep_insn, cost)
}
static int
-ultrasparc_adjust_cost (insn, link, dep_insn, cost)
- rtx insn;
- rtx link;
- rtx dep_insn;
- int cost;
-{
- enum attr_type insn_type, dep_type;
- rtx pat = PATTERN(insn);
- rtx dep_pat = PATTERN (dep_insn);
-
- if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
- return cost;
-
- insn_type = get_attr_type (insn);
- dep_type = get_attr_type (dep_insn);
-
- /* Nothing issues in parallel with integer multiplies, so
- mark as zero cost since the scheduler can not do anything
- about it. */
- if (insn_type == TYPE_IMUL || insn_type == TYPE_IDIV)
- return 0;
-
-#define SLOW_FP(dep_type) \
-(dep_type == TYPE_FPSQRTS || dep_type == TYPE_FPSQRTD || \
- dep_type == TYPE_FPDIVS || dep_type == TYPE_FPDIVD)
-
- switch (REG_NOTE_KIND (link))
- {
- case 0:
- /* Data dependency; DEP_INSN writes a register that INSN reads some
- cycles later. */
-
- if (dep_type == TYPE_CMOVE)
- {
- /* Instructions that read the result of conditional moves cannot
- be in the same group or the following group. */
- return cost + 1;
- }
-
- switch (insn_type)
- {
- /* UltraSPARC can dual issue a store and an instruction setting
- the value stored, except for divide and square root. */
- case TYPE_FPSTORE:
- if (! SLOW_FP (dep_type))
- return 0;
- return cost;
-
- case TYPE_STORE:
- if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
- return cost;
-
- if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
- /* The dependency between the two instructions is on the data
- that is being stored. Assume that the address of the store
- is not also dependent. */
- return 0;
- return cost;
-
- case TYPE_LOAD:
- case TYPE_SLOAD:
- case TYPE_FPLOAD:
- /* A load does not return data until at least 11 cycles after
- a store to the same location. 3 cycles are accounted for
- in the load latency; add the other 8 here. */
- if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
- {
- /* If the addresses are not equal this may be a false
- dependency because pointer aliasing could not be
- determined. Add only 2 cycles in that case. 2 is
- an arbitrary compromise between 8, which would cause
- the scheduler to generate worse code elsewhere to
- compensate for a dependency which might not really
- exist, and 0. */
- if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
- || GET_CODE (SET_SRC (pat)) != MEM
- || GET_CODE (SET_DEST (dep_pat)) != MEM
- || ! rtx_equal_p (XEXP (SET_SRC (pat), 0),
- XEXP (SET_DEST (dep_pat), 0)))
- return cost + 2;
-
- return cost + 8;
- }
- return cost;
-
- case TYPE_BRANCH:
- /* Compare to branch latency is 0. There is no benefit from
- separating compare and branch. */
- if (dep_type == TYPE_COMPARE)
- return 0;
- /* Floating point compare to branch latency is less than
- compare to conditional move. */
- if (dep_type == TYPE_FPCMP)
- return cost - 1;
- return cost;
-
- case TYPE_FPCMOVE:
- /* FMOVR class instructions can not issue in the same cycle
- or the cycle after an instruction which writes any
- integer register. Model this as cost 2 for dependent
- instructions. */
- if (dep_type == TYPE_IALU
- && cost < 2)
- return 2;
- /* Otherwise check as for integer conditional moves. */
-
- case TYPE_CMOVE:
- /* Conditional moves involving integer registers wait until
- 3 cycles after loads return data. The interlock applies
- to all loads, not just dependent loads, but that is hard
- to model. */
- if (dep_type == TYPE_LOAD || dep_type == TYPE_SLOAD)
- return cost + 3;
- return cost;
-
- default:
- break;
- }
- break;
-
- case REG_DEP_ANTI:
- /* Divide and square root lock destination registers for full latency. */
- if (! SLOW_FP (dep_type))
- return 0;
- break;
-
- case REG_DEP_OUTPUT:
- /* IEU and FPU instruction that have the same destination
- register cannot be grouped together. */
- return cost + 1;
-
- default:
- break;
- }
-
- /* Other costs not accounted for:
- - Single precision floating point loads lock the other half of
- the even/odd register pair.
- - Several hazards associated with ldd/std are ignored because these
- instructions are rarely generated for V9.
- - The floating point pipeline can not have both a single and double
- precision operation active at the same time. Format conversions
- and graphics instructions are given honorary double precision status.
- - call and jmpl are always the first instruction in a group. */
-
- return cost;
-
-#undef SLOW_FP
-}
-
-static int
sparc_adjust_cost(insn, link, dep, cost)
rtx insn;
rtx link;
@@ -7498,792 +7346,143 @@ sparc_adjust_cost(insn, link, dep, cost)
case PROCESSOR_SPARCLITE86X:
cost = hypersparc_adjust_cost (insn, link, dep, cost);
break;
- case PROCESSOR_ULTRASPARC:
- cost = ultrasparc_adjust_cost (insn, link, dep, cost);
- break;
default:
break;
}
return cost;
}
-/* This describes the state of the UltraSPARC pipeline during
- instruction scheduling. */
-
-#define TMASK(__x) ((unsigned)1 << ((int)(__x)))
-#define UMASK(__x) ((unsigned)1 << ((int)(__x)))
-
-enum ultra_code { NONE=0, /* no insn at all */
- IEU0, /* shifts and conditional moves */
- IEU1, /* condition code setting insns, calls+jumps */
- IEUN, /* all other single cycle ieu insns */
- LSU, /* loads and stores */
- CTI, /* branches */
- FPM, /* FPU pipeline 1, multiplies and divides */
- FPA, /* FPU pipeline 2, all other operations */
- SINGLE, /* single issue instructions */
- NUM_ULTRA_CODES };
-
-static enum ultra_code ultra_code_from_mask PARAMS ((int));
-static void ultra_schedule_insn PARAMS ((rtx *, rtx *, int, enum ultra_code));
-
-static const char *const ultra_code_names[NUM_ULTRA_CODES] = {
- "NONE", "IEU0", "IEU1", "IEUN", "LSU", "CTI",
- "FPM", "FPA", "SINGLE" };
-
-struct ultrasparc_pipeline_state {
- /* The insns in this group. */
- rtx group[4];
-
- /* The code for each insn. */
- enum ultra_code codes[4];
-
- /* Which insns in this group have been committed by the
- scheduler. This is how we determine how many more
- can issue this cycle. */
- char commit[4];
-
- /* How many insns in this group. */
- char group_size;
-
- /* Mask of free slots still in this group. */
- char free_slot_mask;
-
- /* The slotter uses the following to determine what other
- insn types can still make their way into this group. */
- char contents [NUM_ULTRA_CODES];
- char num_ieu_insns;
-};
-
-#define ULTRA_NUM_HIST 8
-static struct ultrasparc_pipeline_state ultra_pipe_hist[ULTRA_NUM_HIST];
-static int ultra_cur_hist;
-static int ultra_cycles_elapsed;
-
-#define ultra_pipe (ultra_pipe_hist[ultra_cur_hist])
-
-/* Given TYPE_MASK compute the ultra_code it has. */
-static enum ultra_code
-ultra_code_from_mask (type_mask)
- int type_mask;
-{
- if (type_mask & (TMASK (TYPE_SHIFT) | TMASK (TYPE_CMOVE)))
- return IEU0;
- else if (type_mask & (TMASK (TYPE_COMPARE) |
- TMASK (TYPE_CALL) |
- TMASK (TYPE_SIBCALL) |
- TMASK (TYPE_UNCOND_BRANCH)))
- return IEU1;
- else if (type_mask & TMASK (TYPE_IALU))
- return IEUN;
- else if (type_mask & (TMASK (TYPE_LOAD) | TMASK (TYPE_SLOAD) |
- TMASK (TYPE_STORE) | TMASK (TYPE_FPLOAD) |
- TMASK (TYPE_FPSTORE)))
- return LSU;
- else if (type_mask & (TMASK (TYPE_FPMUL) | TMASK (TYPE_FPDIVS) |
- TMASK (TYPE_FPDIVD) | TMASK (TYPE_FPSQRTS) |
- TMASK (TYPE_FPSQRTD)))
- return FPM;
- else if (type_mask & (TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPCMOVE) |
- TMASK (TYPE_FP) | TMASK (TYPE_FPCMP)))
- return FPA;
- else if (type_mask & TMASK (TYPE_BRANCH))
- return CTI;
-
- return SINGLE;
-}
-
-/* Check INSN (a conditional move) and make sure that it's
- results are available at this cycle. Return 1 if the
- results are in fact ready. */
-static int
-ultra_cmove_results_ready_p (insn)
- rtx insn;
+static void
+sparc_sched_init (dump, sched_verbose, max_ready)
+ FILE *dump ATTRIBUTE_UNUSED;
+ int sched_verbose ATTRIBUTE_UNUSED;
+ int max_ready ATTRIBUTE_UNUSED;
{
- struct ultrasparc_pipeline_state *up;
- int entry, slot;
-
- /* If this got dispatched in the previous
- group, the results are not ready. */
- entry = (ultra_cur_hist - 1) & (ULTRA_NUM_HIST - 1);
- up = &ultra_pipe_hist[entry];
- slot = 4;
- while (--slot >= 0)
- if (up->group[slot] == insn)
- return 0;
-
- return 1;
}
-
-/* Walk backwards in pipeline history looking for FPU
- operations which use a mode different than FPMODE and
- will create a stall if an insn using FPMODE were to be
- dispatched this cycle. */
+
static int
-ultra_fpmode_conflict_exists (fpmode)
- enum machine_mode fpmode;
+sparc_use_dfa_pipeline_interface ()
{
- int hist_ent;
- int hist_lim;
-
- hist_ent = (ultra_cur_hist - 1) & (ULTRA_NUM_HIST - 1);
- if (ultra_cycles_elapsed < 4)
- hist_lim = ultra_cycles_elapsed;
- else
- hist_lim = 4;
- while (hist_lim > 0)
- {
- struct ultrasparc_pipeline_state *up = &ultra_pipe_hist[hist_ent];
- int slot = 4;
-
- while (--slot >= 0)
- {
- rtx insn = up->group[slot];
- enum machine_mode this_mode;
- rtx pat;
-
- if (! insn
- || GET_CODE (insn) != INSN
- || (pat = PATTERN (insn)) == 0
- || GET_CODE (pat) != SET)
- continue;
-
- this_mode = GET_MODE (SET_DEST (pat));
- if ((this_mode != SFmode
- && this_mode != DFmode)
- || this_mode == fpmode)
- continue;
-
- /* If it is not FMOV, FABS, FNEG, FDIV, or FSQRT then
- we will get a stall. Loads and stores are independent
- of these rules. */
- if (GET_CODE (SET_SRC (pat)) != ABS
- && GET_CODE (SET_SRC (pat)) != NEG
- && ((TMASK (get_attr_type (insn)) &
- (TMASK (TYPE_FPDIVS) | TMASK (TYPE_FPDIVD) |
- TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPSQRTS) |
- TMASK (TYPE_FPSQRTD) |
- TMASK (TYPE_LOAD) | TMASK (TYPE_STORE))) == 0))
- return 1;
- }
- hist_lim--;
- hist_ent = (hist_ent - 1) & (ULTRA_NUM_HIST - 1);
- }
-
- /* No conflicts, safe to dispatch. */
+ if ((1 << sparc_cpu) &
+ ((1 << PROCESSOR_ULTRASPARC) | (1 << PROCESSOR_CYPRESS) |
+ (1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
+ (1 << PROCESSOR_SPARCLITE86X) | (1 << PROCESSOR_TSC701) |
+ (1 << PROCESSOR_ULTRASPARC3)))
+ return 1;
return 0;
}
-/* Find an instruction in LIST which has one of the
- type attributes enumerated in TYPE_MASK. START
- says where to begin the search.
-
- NOTE: This scheme depends upon the fact that we
- have less than 32 distinct type attributes. */
-
-static int ultra_types_avail;
-
-static rtx *
-ultra_find_type (type_mask, list, start)
- int type_mask;
- rtx *list;
- int start;
-{
- int i;
-
- /* Short circuit if no such insn exists in the ready
- at the moment. */
- if ((type_mask & ultra_types_avail) == 0)
- return 0;
-
- for (i = start; i >= 0; i--)
- {
- rtx insn = list[i];
-
- if (recog_memoized (insn) >= 0
- && (TMASK(get_attr_type (insn)) & type_mask))
- {
- enum machine_mode fpmode = SFmode;
- rtx pat = 0;
- int slot;
- int check_depend = 0;
- int check_fpmode_conflict = 0;
-
- if (GET_CODE (insn) == INSN
- && (pat = PATTERN(insn)) != 0
- && GET_CODE (pat) == SET
- && !(type_mask & (TMASK (TYPE_STORE) |
- TMASK (TYPE_FPSTORE))))
- {
- check_depend = 1;
- if (GET_MODE (SET_DEST (pat)) == SFmode
- || GET_MODE (SET_DEST (pat)) == DFmode)
- {
- fpmode = GET_MODE (SET_DEST (pat));
- check_fpmode_conflict = 1;
- }
- }
-
- slot = 4;
- while(--slot >= 0)
- {
- rtx slot_insn = ultra_pipe.group[slot];
- rtx slot_pat;
-
- /* Already issued, bad dependency, or FPU
- mode conflict. */
- if (slot_insn != 0
- && (slot_pat = PATTERN (slot_insn)) != 0
- && ((insn == slot_insn)
- || (check_depend == 1
- && GET_CODE (slot_insn) == INSN
- && GET_CODE (slot_pat) == SET
- && ((GET_CODE (SET_DEST (slot_pat)) == REG
- && GET_CODE (SET_SRC (pat)) == REG
- && REGNO (SET_DEST (slot_pat)) ==
- REGNO (SET_SRC (pat)))
- || (GET_CODE (SET_DEST (slot_pat)) == SUBREG
- && GET_CODE (SET_SRC (pat)) == SUBREG
- && REGNO (SUBREG_REG (SET_DEST (slot_pat))) ==
- REGNO (SUBREG_REG (SET_SRC (pat)))
- && SUBREG_BYTE (SET_DEST (slot_pat)) ==
- SUBREG_BYTE (SET_SRC (pat)))))
- || (check_fpmode_conflict == 1
- && GET_CODE (slot_insn) == INSN
- && GET_CODE (slot_pat) == SET
- && (GET_MODE (SET_DEST (slot_pat)) == SFmode
- || GET_MODE (SET_DEST (slot_pat)) == DFmode)
- && GET_MODE (SET_DEST (slot_pat)) != fpmode)))
- goto next;
- }
-
- /* Check for peculiar result availability and dispatch
- interference situations. */
- if (pat != 0
- && ultra_cycles_elapsed > 0)
- {
- rtx link;
-
- for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
- {
- rtx link_insn = XEXP (link, 0);
- if (GET_CODE (link_insn) == INSN
- && recog_memoized (link_insn) >= 0
- && (TMASK (get_attr_type (link_insn)) &
- (TMASK (TYPE_CMOVE) | TMASK (TYPE_FPCMOVE)))
- && ! ultra_cmove_results_ready_p (link_insn))
- goto next;
- }
-
- if (check_fpmode_conflict
- && ultra_fpmode_conflict_exists (fpmode))
- goto next;
- }
-
- return &list[i];
- }
- next:
- ;
- }
+static int
+sparc_use_sched_lookahead ()
+{
+ if (sparc_cpu == PROCESSOR_ULTRASPARC
+ || sparc_cpu == PROCESSOR_ULTRASPARC3)
+ return 4;
+ if ((1 << sparc_cpu) &
+ ((1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
+ (1 << PROCESSOR_SPARCLITE86X)))
+ return 3;
return 0;
}
-static void
-ultra_build_types_avail (ready, n_ready)
- rtx *ready;
- int n_ready;
+static rtx
+sparc_cycle_display (clock, last)
+ int clock;
+ rtx last;
{
- int i = n_ready - 1;
-
- ultra_types_avail = 0;
- while(i >= 0)
- {
- rtx insn = ready[i];
+ if (reload_completed)
+ return emit_insn_after (gen_cycle_display (GEN_INT (clock)), last);
+ else
+ return last;
+}
- if (recog_memoized (insn) >= 0)
- ultra_types_avail |= TMASK (get_attr_type (insn));
+/* Make sure that the dependency between OUT_INSN and
+ IN_INSN (a store) is on the store data not the address
+ operand(s) of the store. */
- i -= 1;
- }
-}
+int
+ultrasparc_store_bypass_p (out_insn, in_insn)
+ rtx out_insn, in_insn;
+{
+ rtx out_pat, in_pat;
+ unsigned int regno;
-/* Place insn pointed to my IP into the pipeline.
- Make element THIS of READY be that insn if it
- is not already. TYPE indicates the pipeline class
- this insn falls into. */
-static void
-ultra_schedule_insn (ip, ready, this, type)
- rtx *ip;
- rtx *ready;
- int this;
- enum ultra_code type;
-{
- int pipe_slot;
- char mask = ultra_pipe.free_slot_mask;
- rtx temp;
+ if (recog_memoized (in_insn) < 0)
+ return 0;
- /* Obtain free slot. */
- for (pipe_slot = 0; pipe_slot < 4; pipe_slot++)
- if ((mask & (1 << pipe_slot)) != 0)
- break;
- if (pipe_slot == 4)
+ if (get_attr_type (in_insn) != TYPE_STORE
+ && get_attr_type (in_insn) != TYPE_FPSTORE)
abort ();
- /* In it goes, and it hasn't been committed yet. */
- ultra_pipe.group[pipe_slot] = *ip;
- ultra_pipe.codes[pipe_slot] = type;
- ultra_pipe.contents[type] = 1;
- if (UMASK (type) &
- (UMASK (IEUN) | UMASK (IEU0) | UMASK (IEU1)))
- ultra_pipe.num_ieu_insns += 1;
+ out_pat = PATTERN (out_insn);
+ in_pat = PATTERN (in_insn);
- ultra_pipe.free_slot_mask = (mask & ~(1 << pipe_slot));
- ultra_pipe.group_size += 1;
- ultra_pipe.commit[pipe_slot] = 0;
+ if ((GET_CODE (out_pat) != SET
+ && GET_CODE (out_pat) != PARALLEL)
+ || GET_CODE (in_pat) != SET)
+ abort ();
- /* Update ready list. */
- temp = *ip;
- while (ip != &ready[this])
+ if (GET_CODE (SET_SRC (in_pat)) == REG)
{
- ip[0] = ip[1];
- ++ip;
+ regno = REGNO (SET_SRC (in_pat));
}
- *ip = temp;
-}
-
-/* Advance to the next pipeline group. */
-static void
-ultra_flush_pipeline ()
-{
- ultra_cur_hist = (ultra_cur_hist + 1) & (ULTRA_NUM_HIST - 1);
- ultra_cycles_elapsed += 1;
- memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
- ultra_pipe.free_slot_mask = 0xf;
-}
-
-/* Init our data structures for this current block. */
-static void
-ultrasparc_sched_init ()
-{
- memset ((char *) ultra_pipe_hist, 0, sizeof ultra_pipe_hist);
- ultra_cur_hist = 0;
- ultra_cycles_elapsed = 0;
- ultra_pipe.free_slot_mask = 0xf;
-}
-
-static void
-sparc_sched_init (dump, sched_verbose, max_ready)
- FILE *dump ATTRIBUTE_UNUSED;
- int sched_verbose ATTRIBUTE_UNUSED;
- int max_ready ATTRIBUTE_UNUSED;
-{
- if (sparc_cpu == PROCESSOR_ULTRASPARC)
- ultrasparc_sched_init ();
-}
-
-/* INSN has been scheduled, update pipeline commit state
- and return how many instructions are still to be
- scheduled in this group. */
-static int
-ultrasparc_variable_issue (insn)
- rtx insn;
-{
- struct ultrasparc_pipeline_state *up = &ultra_pipe;
- int i, left_to_fire;
-
- left_to_fire = 0;
- for (i = 0; i < 4; i++)
+ else if (GET_CODE (SET_SRC (in_pat)) == SUBREG)
{
- if (up->group[i] == 0)
- continue;
-
- if (up->group[i] == insn)
- {
- up->commit[i] = 1;
- }
- else if (! up->commit[i])
- left_to_fire++;
+ regno = REGNO (SUBREG_REG (SET_SRC (in_pat)));
}
-
- return left_to_fire;
-}
-
-static int
-sparc_variable_issue (dump, sched_verbose, insn, cim)
- FILE *dump ATTRIBUTE_UNUSED;
- int sched_verbose ATTRIBUTE_UNUSED;
- rtx insn;
- int cim;
-{
- if (sparc_cpu == PROCESSOR_ULTRASPARC)
- return ultrasparc_variable_issue (insn);
else
- return cim - 1;
-}
-
-/* In actual_hazard_this_instance, we may have yanked some
- instructions from the ready list due to conflict cost
- adjustments. If so, and such an insn was in our pipeline
- group, remove it and update state. */
-static void
-ultra_rescan_pipeline_state (ready, n_ready)
- rtx *ready;
- int n_ready;
-{
- struct ultrasparc_pipeline_state *up = &ultra_pipe;
- int i;
+ return 0;
- for (i = 0; i < 4; i++)
+ if (GET_CODE (out_pat) == PARALLEL)
{
- rtx insn = up->group[i];
- int j;
+ int i;
- if (! insn)
- continue;
+ for (i = 0; i < XVECLEN (out_pat, 0); i++)
+ {
+ rtx exp = XVECEXP (out_pat, 0, i);
- /* If it has been committed, then it was removed from
- the ready list because it was actually scheduled,
- and that is not the case we are searching for here. */
- if (up->commit[i] != 0)
- continue;
+ if (GET_CODE (exp) != SET)
+ return 0;
- for (j = n_ready - 1; j >= 0; j--)
- if (ready[j] == insn)
- break;
+ if (GET_CODE (SET_DEST (exp)) == REG
+ && regno == REGNO (SET_DEST (exp)))
+ return 1;
- /* If we didn't find it, toss it. */
- if (j < 0)
- {
- enum ultra_code ucode = up->codes[i];
-
- up->group[i] = 0;
- up->codes[i] = NONE;
- up->contents[ucode] = 0;
- if (UMASK (ucode) &
- (UMASK (IEUN) | UMASK (IEU0) | UMASK (IEU1)))
- up->num_ieu_insns -= 1;
-
- up->free_slot_mask |= (1 << i);
- up->group_size -= 1;
- up->commit[i] = 0;
+ if (GET_CODE (SET_DEST (exp)) == SUBREG
+ && regno == REGNO (SUBREG_REG (SET_DEST (exp))))
+ return 1;
}
}
-}
-
-static void
-ultrasparc_sched_reorder (dump, sched_verbose, ready, n_ready)
- FILE *dump;
- int sched_verbose;
- rtx *ready;
- int n_ready;
-{
- struct ultrasparc_pipeline_state *up = &ultra_pipe;
- int i, this_insn;
-
- if (sched_verbose)
+ else if (GET_CODE (SET_DEST (out_pat)) == REG)
{
- int n;
-
- fprintf (dump, "\n;;\tUltraSPARC Looking at [");
- for (n = n_ready - 1; n >= 0; n--)
- {
- rtx insn = ready[n];
- enum ultra_code ucode;
-
- if (recog_memoized (insn) < 0)
- continue;
- ucode = ultra_code_from_mask (TMASK (get_attr_type (insn)));
- if (n != 0)
- fprintf (dump, "%s(%d) ",
- ultra_code_names[ucode],
- INSN_UID (insn));
- else
- fprintf (dump, "%s(%d)",
- ultra_code_names[ucode],
- INSN_UID (insn));
- }
- fprintf (dump, "]\n");
+ return regno == REGNO (SET_DEST (out_pat));
}
-
- this_insn = n_ready - 1;
-
- /* Skip over junk we don't understand. */
- while ((this_insn >= 0)
- && recog_memoized (ready[this_insn]) < 0)
- this_insn--;
-
- ultra_build_types_avail (ready, this_insn + 1);
-
- while (this_insn >= 0) {
- int old_group_size = up->group_size;
-
- if (up->group_size != 0)
- {
- int num_committed;
-
- num_committed = (up->commit[0] + up->commit[1] +
- up->commit[2] + up->commit[3]);
- /* If nothing has been commited from our group, or all of
- them have. Clear out the (current cycle's) pipeline
- state and start afresh. */
- if (num_committed == 0
- || num_committed == up->group_size)
- {
- ultra_flush_pipeline ();
- up = &ultra_pipe;
- old_group_size = 0;
- }
- else
- {
- /* OK, some ready list insns got requeued and thus removed
- from the ready list. Account for this fact. */
- ultra_rescan_pipeline_state (ready, n_ready);
-
- /* Something "changed", make this look like a newly
- formed group so the code at the end of the loop
- knows that progress was in fact made. */
- if (up->group_size != old_group_size)
- old_group_size = 0;
- }
- }
-
- if (up->group_size == 0)
- {
- /* If the pipeline is (still) empty and we have any single
- group insns, get them out now as this is a good time. */
- rtx *ip = ultra_find_type ((TMASK (TYPE_RETURN) | TMASK (TYPE_IDIV) |
- TMASK (TYPE_IMUL) | TMASK (TYPE_CMOVE) |
- TMASK (TYPE_MULTI) | TMASK (TYPE_MISC)),
- ready, this_insn);
- if (ip)
- {
- ultra_schedule_insn (ip, ready, this_insn, SINGLE);
- break;
- }
-
- /* If we are not in the process of emptying out the pipe, try to
- obtain an instruction which must be the first in it's group. */
- ip = ultra_find_type ((TMASK (TYPE_CALL) |
- TMASK (TYPE_SIBCALL) |
- TMASK (TYPE_CALL_NO_DELAY_SLOT) |
- TMASK (TYPE_UNCOND_BRANCH)),
- ready, this_insn);
- if (ip)
- {
- ultra_schedule_insn (ip, ready, this_insn, IEU1);
- this_insn--;
- }
- else if ((ip = ultra_find_type ((TMASK (TYPE_FPDIVS) |
- TMASK (TYPE_FPDIVD) |
- TMASK (TYPE_FPSQRTS) |
- TMASK (TYPE_FPSQRTD)),
- ready, this_insn)) != 0)
- {
- ultra_schedule_insn (ip, ready, this_insn, FPM);
- this_insn--;
- }
- }
-
- /* Try to fill the integer pipeline. First, look for an IEU0 specific
- operation. We can't do more IEU operations if the first 3 slots are
- all full or we have dispatched two IEU insns already. */
- if ((up->free_slot_mask & 0x7) != 0
- && up->num_ieu_insns < 2
- && up->contents[IEU0] == 0
- && up->contents[IEUN] == 0)
- {
- rtx *ip = ultra_find_type (TMASK(TYPE_SHIFT), ready, this_insn);
- if (ip)
- {
- ultra_schedule_insn (ip, ready, this_insn, IEU0);
- this_insn--;
- }
- }
-
- /* If we can, try to find an IEU1 specific or an unnamed
- IEU instruction. */
- if ((up->free_slot_mask & 0x7) != 0
- && up->num_ieu_insns < 2)
- {
- rtx *ip = ultra_find_type ((TMASK (TYPE_IALU) |
- (up->contents[IEU1] == 0 ? TMASK (TYPE_COMPARE) : 0)),
- ready, this_insn);
- if (ip)
- {
- rtx insn = *ip;
-
- ultra_schedule_insn (ip, ready, this_insn,
- (!up->contents[IEU1]
- && get_attr_type (insn) == TYPE_COMPARE)
- ? IEU1 : IEUN);
- this_insn--;
- }
- }
-
- /* If only one IEU insn has been found, try to find another unnamed
- IEU operation or an IEU1 specific one. */
- if ((up->free_slot_mask & 0x7) != 0
- && up->num_ieu_insns < 2)
- {
- rtx *ip;
- int tmask = TMASK (TYPE_IALU);
-
- if (!up->contents[IEU1])
- tmask |= TMASK (TYPE_COMPARE);
- ip = ultra_find_type (tmask, ready, this_insn);
- if (ip)
- {
- rtx insn = *ip;
-
- ultra_schedule_insn (ip, ready, this_insn,
- (!up->contents[IEU1]
- && get_attr_type (insn) == TYPE_COMPARE)
- ? IEU1 : IEUN);
- this_insn--;
- }
- }
-
- /* Try for a load or store, but such an insn can only be issued
- if it is within' one of the first 3 slots. */
- if ((up->free_slot_mask & 0x7) != 0
- && up->contents[LSU] == 0)
- {
- rtx *ip = ultra_find_type ((TMASK (TYPE_LOAD) | TMASK (TYPE_SLOAD) |
- TMASK (TYPE_STORE) | TMASK (TYPE_FPLOAD) |
- TMASK (TYPE_FPSTORE)), ready, this_insn);
- if (ip)
- {
- ultra_schedule_insn (ip, ready, this_insn, LSU);
- this_insn--;
- }
- }
-
- /* Now find FPU operations, first FPM class. But not divisions or
- square-roots because those will break the group up. Unlike all
- the previous types, these can go in any slot. */
- if (up->free_slot_mask != 0
- && up->contents[FPM] == 0)
- {
- rtx *ip = ultra_find_type (TMASK (TYPE_FPMUL), ready, this_insn);
- if (ip)
- {
- ultra_schedule_insn (ip, ready, this_insn, FPM);
- this_insn--;
- }
- }
-
- /* Continue on with FPA class if we have not filled the group already. */
- if (up->free_slot_mask != 0
- && up->contents[FPA] == 0)
- {
- rtx *ip = ultra_find_type ((TMASK (TYPE_FPMOVE) | TMASK (TYPE_FPCMOVE) |
- TMASK (TYPE_FP) | TMASK (TYPE_FPCMP)),
- ready, this_insn);
- if (ip)
- {
- ultra_schedule_insn (ip, ready, this_insn, FPA);
- this_insn--;
- }
- }
-
- /* Finally, maybe stick a branch in here. */
- if (up->free_slot_mask != 0
- && up->contents[CTI] == 0)
- {
- rtx *ip = ultra_find_type (TMASK (TYPE_BRANCH), ready, this_insn);
-
- /* Try to slip in a branch only if it is one of the
- next 2 in the ready list. */
- if (ip && ((&ready[this_insn] - ip) < 2))
- {
- ultra_schedule_insn (ip, ready, this_insn, CTI);
- this_insn--;
- }
- }
-
- up->group_size = 0;
- for (i = 0; i < 4; i++)
- if ((up->free_slot_mask & (1 << i)) == 0)
- up->group_size++;
-
- /* See if we made any progress... */
- if (old_group_size != up->group_size)
- break;
-
- /* Clean out the (current cycle's) pipeline state
- and try once more. If we placed no instructions
- into the pipeline at all, it means a real hard
- conflict exists with some earlier issued instruction
- so we must advance to the next cycle to clear it up. */
- if (up->group_size == 0)
- {
- ultra_flush_pipeline ();
- up = &ultra_pipe;
- }
- else
- {
- memset ((char *) &ultra_pipe, 0, sizeof ultra_pipe);
- ultra_pipe.free_slot_mask = 0xf;
- }
- }
-
- if (sched_verbose)
+ else if (GET_CODE (SET_DEST (out_pat)) == SUBREG)
{
- int n, gsize;
-
- fprintf (dump, ";;\tUltraSPARC Launched [");
- gsize = up->group_size;
- for (n = 0; n < 4; n++)
- {
- rtx insn = up->group[n];
-
- if (! insn)
- continue;
-
- gsize -= 1;
- if (gsize != 0)
- fprintf (dump, "%s(%d) ",
- ultra_code_names[up->codes[n]],
- INSN_UID (insn));
- else
- fprintf (dump, "%s(%d)",
- ultra_code_names[up->codes[n]],
- INSN_UID (insn));
- }
- fprintf (dump, "]\n");
+ return regno == REGNO (SUBREG_REG (SET_DEST (out_pat)));
}
-}
-static int
-sparc_sched_reorder (dump, sched_verbose, ready, n_readyp, clock)
- FILE *dump;
- int sched_verbose;
- rtx *ready;
- int *n_readyp;
- int clock ATTRIBUTE_UNUSED;
-{
- if (sparc_cpu == PROCESSOR_ULTRASPARC)
- ultrasparc_sched_reorder (dump, sched_verbose, ready, *n_readyp);
- return sparc_issue_rate ();
+ return 0;
}
-static int
+static int
sparc_issue_rate ()
{
switch (sparc_cpu)
{
- default:
- return 1;
- case PROCESSOR_V9:
+ default:
+ return 1;
+ case PROCESSOR_V9:
/* Assume V9 processors are capable of at least dual-issue. */
return 2;
- case PROCESSOR_SUPERSPARC:
- return 3;
+ case PROCESSOR_SUPERSPARC:
+ return 3;
case PROCESSOR_HYPERSPARC:
case PROCESSOR_SPARCLITE86X:
return 2;
- case PROCESSOR_ULTRASPARC:
- return 4;
+ case PROCESSOR_ULTRASPARC:
+ case PROCESSOR_ULTRASPARC3:
+ return 4;
}
}
@@ -8564,21 +7763,6 @@ sparc_profile_hook (labelno)
emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
}
-/* Mark ARG, which is really a struct ultrasparc_pipline_state *, for
- GC. */
-
-static void
-mark_ultrasparc_pipeline_state (arg)
- void *arg;
-{
- struct ultrasparc_pipeline_state *ups;
- size_t i;
-
- ups = (struct ultrasparc_pipeline_state *) arg;
- for (i = 0; i < ARRAY_SIZE (ups->group); ++i)
- ggc_mark_rtx (ups->group[i]);
-}
-
/* Called to register all of our global variables with the garbage
collector. */
@@ -8591,8 +7775,6 @@ sparc_add_gc_roots ()
ggc_add_rtx_root (&get_pc_symbol, 1);
ggc_add_rtx_root (&sparc_addr_diff_list, 1);
ggc_add_rtx_root (&sparc_addr_list, 1);
- ggc_add_root (ultra_pipe_hist, ARRAY_SIZE (ultra_pipe_hist),
- sizeof (ultra_pipe_hist[0]), &mark_ultrasparc_pipeline_state);
}
#ifdef OBJECT_FORMAT_ELF
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index d246c5a29df..04dcbe3ab90 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -122,9 +122,11 @@ extern enum cmodel sparc_cmodel;
#define TARGET_CPU_sparcv9 7 /* alias */
#define TARGET_CPU_sparc64 7 /* alias */
#define TARGET_CPU_ultrasparc 8
+#define TARGET_CPU_ultrasparc3 9
#if TARGET_CPU_DEFAULT == TARGET_CPU_v9 \
- || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc
+ || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc \
+ || TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc3
#define CPP_CPU32_DEFAULT_SPEC ""
#define ASM_CPU32_DEFAULT_SPEC ""
@@ -141,6 +143,10 @@ extern enum cmodel sparc_cmodel;
#define CPP_CPU64_DEFAULT_SPEC "-D__sparc_v9__"
#define ASM_CPU64_DEFAULT_SPEC "-Av9a"
#endif
+#if TARGET_CPU_DEFAULT == TARGET_CPU_ultrasparc3
+#define CPP_CPU64_DEFAULT_SPEC "-D__sparc_v9__"
+#define ASM_CPU64_DEFAULT_SPEC "-Av9b"
+#endif
#else
@@ -230,6 +236,7 @@ Unrecognized value in TARGET_CPU_DEFAULT.
%{mcpu=sparclite86x:-D__sparclite86x__} \
%{mcpu=v9:-D__sparc_v9__} \
%{mcpu=ultrasparc:-D__sparc_v9__} \
+%{mcpu=ultrasparc3:-D__sparc_v9__} \
%{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:%(cpp_cpu_default)}}}}}}} \
"
@@ -296,6 +303,7 @@ Unrecognized value in TARGET_CPU_DEFAULT.
%{mv8plus:-Av8plus} \
%{mcpu=v9:-Av9} \
%{mcpu=ultrasparc:%{!mv8plus:-Av9a}} \
+%{mcpu=ultrasparc3:%{!mv8plus:-Av9b}} \
%{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:%(asm_cpu_default)}}}}}}} \
"
@@ -623,7 +631,8 @@ enum processor_type {
PROCESSOR_SPARCLET,
PROCESSOR_TSC701,
PROCESSOR_V9,
- PROCESSOR_ULTRASPARC
+ PROCESSOR_ULTRASPARC,
+ PROCESSOR_ULTRASPARC3
};
/* This is set from -m{cpu,tune}=xxx. */
@@ -2622,7 +2631,8 @@ do { \
(((FP_REG_CLASS_P (CLASS1) && GENERAL_OR_I64 (CLASS2)) \
|| (GENERAL_OR_I64 (CLASS1) && FP_REG_CLASS_P (CLASS2)) \
|| (CLASS1) == FPCC_REGS || (CLASS2) == FPCC_REGS) \
- ? (sparc_cpu == PROCESSOR_ULTRASPARC ? 12 : 6) : 2)
+ ? ((sparc_cpu == PROCESSOR_ULTRASPARC \
+ || sparc_cpu == PROCESSOR_ULTRASPARC3) ? 12 : 6) : 2)
/* Provide the cost of a branch. For pre-v9 processors we use
a value of 3 to take into account the potential annulling of
@@ -2653,6 +2663,8 @@ do { \
if (sparc_cpu == PROCESSOR_ULTRASPARC) \
return (GET_MODE (X) == DImode ? \
COSTS_N_INSNS (34) : COSTS_N_INSNS (19)); \
+ if (sparc_cpu == PROCESSOR_ULTRASPARC3) \
+ return COSTS_N_INSNS (6); \
return TARGET_HARD_MUL ? COSTS_N_INSNS (5) : COSTS_N_INSNS (25); \
case DIV: \
case UDIV: \
@@ -2661,6 +2673,9 @@ do { \
if (sparc_cpu == PROCESSOR_ULTRASPARC) \
return (GET_MODE (X) == DImode ? \
COSTS_N_INSNS (68) : COSTS_N_INSNS (37)); \
+ if (sparc_cpu == PROCESSOR_ULTRASPARC3) \
+ return (GET_MODE (X) == DImode ? \
+ COSTS_N_INSNS (71) : COSTS_N_INSNS (40)); \
return COSTS_N_INSNS (25); \
/* Make FLOAT and FIX more expensive than CONST_DOUBLE,\
so that cse will favor the latter. */ \
diff --git a/gcc/config/sparc/sparc.md b/gcc/config/sparc/sparc.md
index 65b390eaa62..c6b280679d0 100644
--- a/gcc/config/sparc/sparc.md
+++ b/gcc/config/sparc/sparc.md
@@ -44,6 +44,7 @@
;; 16 embmedany_textlo
;; 18 sethm
;; 19 setlo
+;; 20 cycle_display
;;
;; UNSPEC_VOLATILE: 0 blockage
;; 1 flush_register_windows
@@ -61,7 +62,7 @@
;; Attribute for cpu type.
;; These must match the values for enum processor_type in sparc.h.
-(define_attr "cpu" "v7,cypress,v8,supersparc,sparclite,f930,f934,hypersparc,sparclite86x,sparclet,tsc701,v9,ultrasparc"
+(define_attr "cpu" "v7,cypress,v8,supersparc,sparclite,f930,f934,hypersparc,sparclite86x,sparclet,tsc701,v9,ultrasparc,ultrasparc3"
(const (symbol_ref "sparc_cpu_attr")))
;; Attribute for the instruction set.
@@ -82,9 +83,8 @@
;; Insn type.
-;; If you add any new type here, please update ultrasparc_sched_reorder too.
(define_attr "type"
- "ialu,compare,shift,load,sload,store,uncond_branch,branch,call,sibcall,call_no_delay_slot,return,imul,idiv,fpload,fpstore,fp,fpmove,fpcmove,fpcmp,fpmul,fpdivs,fpdivd,fpsqrts,fpsqrtd,cmove,multi,misc"
+ "ialu,compare,shift,load,sload,store,uncond_branch,branch,call,sibcall,call_no_delay_slot,return,imul,idiv,fpload,fpstore,fp,fpmove,fpcmove,fpcrmove,fpcmp,fpmul,fpdivs,fpdivd,fpsqrts,fpsqrtd,cmove,multi,misc"
(const_string "ialu"))
;; true if branch/call has empty delay slot and will emit a nop in it
@@ -163,6 +163,9 @@
;; FP precision.
(define_attr "fptype" "single,double" (const_string "single"))
+;; UltraSPARC-III integer load type.
+(define_attr "us3load_type" "2cycle,3cycle" (const_string "2cycle"))
+
(define_asm_attributes
[(set_attr "length" "2")
(set_attr "type" "multi")])
@@ -245,344 +248,525 @@
[(eq_attr "in_uncond_branch_delay" "true")
(nil) (nil)])
-;; Function units of the SPARC
-
-;; (define_function_unit {name} {num-units} {n-users} {test}
-;; {ready-delay} {issue-delay} [{conflict-list}])
+;; DFA scheduling on the SPARC
-;; The integer ALU.
-;; (Noted only for documentation; units that take one cycle do not need to
-;; be specified.)
+(define_automaton "cypress_0,cypress_1,supersparc_0,supersparc_1,hypersparc_0,hypersparc_1,sparclet,ultrasparc_0,ultrasparc_1,ultrasparc3_0,ultrasparc3_1")
-;; On the sparclite, integer multiply takes 1, 3, or 5 cycles depending on
-;; the inputs.
+;; Cypress scheduling
-;; ---- cypress CY7C602 scheduling:
-;; Memory with load-delay of 1 (i.e., 2 cycle load).
+(define_cpu_unit "cyp_memory, cyp_fpalu" "cypress_0")
+(define_cpu_unit "cyp_fpmds" "cypress_1")
-(define_function_unit "memory" 1 0
+(define_insn_reservation "cyp_load" 2
(and (eq_attr "cpu" "cypress")
(eq_attr "type" "load,sload,fpload"))
- 2 2)
-
-;; SPARC has two floating-point units: the FP ALU,
-;; and the FP MUL/DIV/SQRT unit.
-;; Instruction timings on the CY7C602 are as follows
-;; FABSs 4
-;; FADDs/d 5/5
-;; FCMPs/d 4/4
-;; FDIVs/d 23/37
-;; FMOVs 4
-;; FMULs/d 5/7
-;; FNEGs 4
-;; FSQRTs/d 34/63
-;; FSUBs/d 5/5
-;; FdTOi/s 5/5
-;; FsTOi/d 5/5
-;; FiTOs/d 9/5
-
-;; The CY7C602 can only support 2 fp isnsn simultaneously.
-;; More insns cause the chip to stall.
-
-(define_function_unit "fp_alu" 1 0
+ "cyp_memory, nothing")
+
+(define_insn_reservation "cyp_fp_alu" 5
(and (eq_attr "cpu" "cypress")
(eq_attr "type" "fp,fpmove"))
- 5 5)
+ "cyp_fpalu, nothing*3")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "cyp_fp_mult" 7
(and (eq_attr "cpu" "cypress")
(eq_attr "type" "fpmul"))
- 7 7)
+ "cyp_fpmds, nothing*5")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "cyp_fp_div" 37
(and (eq_attr "cpu" "cypress")
(eq_attr "type" "fpdivs,fpdivd"))
- 37 37)
+ "cyp_fpmds, nothing*35")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "cyp_fp_sqrt" 63
(and (eq_attr "cpu" "cypress")
(eq_attr "type" "fpsqrts,fpsqrtd"))
- 63 63)
+ "cyp_fpmds, nothing*61")
+
+;; SuperSPARC scheduling
+
+(define_cpu_unit "ss_memory, ss_shift, ss_iwport0, ss_iwport1" "supersparc_0")
+(define_cpu_unit "ss_fpalu" "supersparc_0")
+(define_cpu_unit "ss_fpmds" "supersparc_1")
-;; ----- The TMS390Z55 scheduling
-;; The Supersparc can issue 1 - 3 insns per cycle: up to two integer,
-;; one ld/st, one fp.
-;; Memory delivers its result in one cycle to IU, zero cycles to FP
+(define_reservation "ss_iwport" "(ss_iwport0 | ss_iwport1)")
-(define_function_unit "memory" 1 0
+(define_insn_reservation "ss_iuload" 1
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "load,sload"))
- 1 1)
+ "ss_memory")
-(define_function_unit "memory" 1 0
+;; Ok, fpu loads deliver the result in zero cycles. But we
+;; have to show the ss_memory reservation somehow, thus...
+(define_insn_reservation "ss_fpload" 0
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "fpload"))
- 0 1)
+ "ss_memory")
-(define_function_unit "memory" 1 0
+(define_bypass 0 "ss_fpload" "ss_fp_alu,ss_fp_mult,ss_fp_divs,ss_fp_divd,ss_fp_sqrt")
+
+(define_insn_reservation "ss_store" 1
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "store,fpstore"))
- 1 1)
+ "ss_memory")
-(define_function_unit "shift" 1 0
+(define_insn_reservation "ss_ialu_shift" 1
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "shift"))
- 1 1)
-
-;; There are only two write ports to the integer register file
-;; A store also uses a write port
+ "ss_shift + ss_iwport")
-(define_function_unit "iwport" 2 0
+(define_insn_reservation "ss_ialu_any" 1
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "load,sload,store,shift,ialu"))
- 1 1)
-
-;; Timings; throughput/latency
-;; FADD 1/3 add/sub, format conv, compar, abs, neg
-;; FMUL 1/3
-;; FDIVs 4/6
-;; FDIVd 7/9
-;; FSQRTs 6/8
-;; FSQRTd 10/12
-;; IMUL 4/4
-
-(define_function_unit "fp_alu" 1 0
+ "ss_iwport")
+
+(define_insn_reservation "ss_fp_alu" 3
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "fp,fpmove,fpcmp"))
- 3 1)
+ "ss_fpalu, nothing*2")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "ss_fp_mult" 3
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "fpmul"))
- 3 1)
+ "ss_fpmds, nothing*2")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "ss_fp_divs" 6
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "fpdivs"))
- 6 4)
+ "ss_fpmds*4, nothing*2")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "ss_fp_divd" 9
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "fpdivd"))
- 9 7)
+ "ss_fpmds*7, nothing*2")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "ss_fp_sqrt" 12
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "fpsqrts,fpsqrtd"))
- 12 10)
+ "ss_fpmds*10, nothing*2")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "ss_imul" 4
(and (eq_attr "cpu" "supersparc")
(eq_attr "type" "imul"))
- 4 4)
+ "ss_fpmds*4")
-;; ----- hypersparc/sparclite86x scheduling
-;; The Hypersparc can issue 1 - 2 insns per cycle. The dual issue cases are:
-;; L-Ld/St I-Int F-Float B-Branch LI/LF/LB/II/IF/IB/FF/FB
-;; II/FF case is only when loading a 32 bit hi/lo constant
-;; Single issue insns include call, jmpl, u/smul, u/sdiv, lda, sta, fcmp
-;; Memory delivers its result in one cycle to IU
+;; HyperSPARC/sparclite86x scheduling
-(define_function_unit "memory" 1 0
+(define_cpu_unit "hs_memory,hs_branch,hs_shift,hs_fpalu" "hypersparc_0")
+(define_cpu_unit "hs_fpmds" "hypersparc_1")
+
+(define_insn_reservation "hs_load" 1
(and (ior (eq_attr "cpu" "hypersparc") (eq_attr "cpu" "sparclite86x"))
(eq_attr "type" "load,sload,fpload"))
- 1 1)
+ "hs_memory")
-(define_function_unit "memory" 1 0
+(define_insn_reservation "hs_store" 2
(and (ior (eq_attr "cpu" "hypersparc") (eq_attr "cpu" "sparclite86x"))
(eq_attr "type" "store,fpstore"))
- 2 1)
+ "hs_memory, nothing")
-(define_function_unit "sparclite86x_branch" 1 0
+(define_insn_reservation "hs_slbranch" 1
(and (eq_attr "cpu" "sparclite86x")
(eq_attr "type" "branch"))
- 1 1)
+ "hs_branch")
-;; integer multiply insns
-(define_function_unit "sparclite86x_shift" 1 0
+(define_insn_reservation "hs_slshift" 1
(and (eq_attr "cpu" "sparclite86x")
(eq_attr "type" "shift"))
- 1 1)
+ "hs_shift")
-(define_function_unit "fp_alu" 1 0
+(define_insn_reservation "hs_fp_alu" 1
(and (ior (eq_attr "cpu" "hypersparc") (eq_attr "cpu" "sparclite86x"))
(eq_attr "type" "fp,fpmove,fpcmp"))
- 1 1)
+ "hs_fpalu")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "hs_fp_mult" 1
(and (ior (eq_attr "cpu" "hypersparc") (eq_attr "cpu" "sparclite86x"))
(eq_attr "type" "fpmul"))
- 1 1)
+ "hs_fpmds")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "hs_fp_divs" 8
(and (ior (eq_attr "cpu" "hypersparc") (eq_attr "cpu" "sparclite86x"))
(eq_attr "type" "fpdivs"))
- 8 6)
+ "hs_fpmds*6, nothing*2")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "hs_fp_divd" 12
(and (ior (eq_attr "cpu" "hypersparc") (eq_attr "cpu" "sparclite86x"))
(eq_attr "type" "fpdivd"))
- 12 10)
+ "hs_fpmds*10, nothing*2")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "hs_fp_sqrt" 17
(and (ior (eq_attr "cpu" "hypersparc") (eq_attr "cpu" "sparclite86x"))
(eq_attr "type" "fpsqrts,fpsqrtd"))
- 17 15)
+ "hs_fpmds*15, nothing*2")
-(define_function_unit "fp_mds" 1 0
+(define_insn_reservation "hs_imul" 17
(and (ior (eq_attr "cpu" "hypersparc") (eq_attr "cpu" "sparclite86x"))
(eq_attr "type" "imul"))
- 17 15)
+ "hs_fpmds*15, nothing*2")
-;; ----- sparclet tsc701 scheduling
-;; The tsc701 issues 1 insn per cycle.
-;; Results may be written back out of order.
+;; Sparclet tsc701 scheduling
-;; Loads take 2 extra cycles to complete and 4 can be buffered at a time.
+(define_cpu_unit "sl_load0,sl_load1,sl_load2,sl_load3" "sparclet")
+(define_cpu_unit "sl_store,sl_imul" "sparclet")
-(define_function_unit "tsc701_load" 4 1
- (and (eq_attr "cpu" "tsc701")
- (eq_attr "type" "load,sload"))
- 3 1)
+(define_reservation "sl_load_any" "(sl_load0 | sl_load1 | sl_load2 | sl_load3)")
+(define_reservation "sl_load_all" "(sl_load0 + sl_load1 + sl_load2 + sl_load3)")
-;; Stores take 2(?) extra cycles to complete.
-;; It is desirable to not have any memory operation in the following 2 cycles.
-;; (??? or 2 memory ops in the case of std).
+(define_insn_reservation "sl_ld" 3
+ (and (eq_attr "cpu" "tsc701")
+ (eq_attr "type" "load,sload"))
+ "sl_load_any, sl_load_any, sl_load_any")
-(define_function_unit "tsc701_store" 1 0
+(define_insn_reservation "sl_st" 3
(and (eq_attr "cpu" "tsc701")
(eq_attr "type" "store"))
- 3 3
- [(eq_attr "type" "load,sload,store")])
+ "(sl_store+sl_load_all)*3")
-;; The multiply unit has a latency of 5.
-(define_function_unit "tsc701_mul" 1 0
+(define_insn_reservation "sl_imul" 5
(and (eq_attr "cpu" "tsc701")
(eq_attr "type" "imul"))
- 5 5)
-
-;; ----- The UltraSPARC-1 scheduling
-;; UltraSPARC has two integer units. Shift instructions can only execute
-;; on IE0. Condition code setting instructions, call, and jmpl (including
-;; the ret and retl pseudo-instructions) can only execute on IE1.
-;; Branch on register uses IE1, but branch on condition code does not.
-;; Conditional moves take 2 cycles. No other instruction can issue in the
-;; same cycle as a conditional move.
-;; Multiply and divide take many cycles during which no other instructions
-;; can issue.
-;; Memory delivers its result in two cycles (except for signed loads,
-;; which take one cycle more). One memory instruction can be issued per
-;; cycle.
-
-(define_function_unit "memory" 1 0
+ "sl_imul*5")
+
+;; UltraSPARC-I/II scheduling
+
+(define_cpu_unit "us1_fdivider,us1_fpm" "ultrasparc_0");
+(define_cpu_unit "us1_fpa,us1_load_writeback" "ultrasparc_1")
+(define_cpu_unit "us1_fps_0,us1_fps_1,us1_fpd_0,us1_fpd_1" "ultrasparc_1")
+(define_cpu_unit "us1_slot0,us1_slot1,us1_slot2,us1_slot3" "ultrasparc_1")
+(define_cpu_unit "us1_ieu0,us1_ieu1,us1_cti,us1_lsu" "ultrasparc_1")
+
+(define_reservation "us1_slot012" "(us1_slot0 | us1_slot1 | us1_slot2)")
+(define_reservation "us1_slotany" "(us1_slot0 | us1_slot1 | us1_slot2 | us1_slot3)")
+(define_reservation "us1_single_issue" "us1_slot0 + us1_slot1 + us1_slot2 + us1_slot3")
+
+(define_reservation "us1_fp_single" "(us1_fps_0 | us1_fps_1)")
+(define_reservation "us1_fp_double" "(us1_fpd_0 | us1_fpd_1)")
+;; This is a simplified representation of the issue at hand.
+;; For most cases, going from one FP precision type insn to another
+;; just breaks up the insn group. However for some cases, such
+;; a situation causes the second insn to stall 2 more cycles.
+(exclusion_set "us1_fps_0,us1_fps_1" "us1_fpd_0,us1_fpd_1")
+
+;; If we have to schedule an ieu1 specific instruction and we want
+;; to reserve the ieu0 unit as well, we must reserve it first. So for
+;; example we could not schedule this sequence:
+;; COMPARE IEU1
+;; IALU IEU0
+;; but we could schedule them together like this:
+;; IALU IEU0
+;; COMPARE IEU1
+;; This basically requires that ieu0 is reserved before ieu1 when
+;; it is required that both be reserved.
+(absence_set "us1_ieu0" "us1_ieu1")
+
+;; This defines the slotting order. Most IEU instructions can only
+;; execute in the first three slots, FPU and branches can go into
+;; any slot. We represent instructions which "break the group"
+;; as requiring reservation of us1_slot0.
+(absence_set "us1_slot0" "us1_slot1,us1_slot2,us1_slot3")
+(absence_set "us1_slot1" "us1_slot2,us1_slot3")
+(absence_set "us1_slot2" "us1_slot3")
+
+(define_insn_reservation "us1_simple_ieuN" 1
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "load,fpload"))
- 2 1)
+ (eq_attr "type" "ialu"))
+ "(us1_ieu0 | us1_ieu1) + us1_slot012")
-(define_function_unit "memory" 1 0
+(define_insn_reservation "us1_simple_ieu0" 1
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "sload"))
- 3 1)
+ (eq_attr "type" "shift"))
+ "us1_ieu0 + us1_slot012")
-(define_function_unit "memory" 1 0
+(define_insn_reservation "us1_simple_ieu1" 1
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "store,fpstore"))
- 1 1)
+ (eq_attr "type" "compare"))
+ "us1_ieu1 + us1_slot012")
-(define_function_unit "ieuN" 2 0
+(define_insn_reservation "us1_cmove" 2
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "ialu,shift,compare,call,sibcall,call_no_delay_slot,uncond_branch"))
- 1 1)
+ (eq_attr "type" "cmove"))
+ "us1_single_issue, nothing")
-(define_function_unit "ieu0" 1 0
+(define_insn_reservation "us1_imul" 1
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "shift"))
- 1 1)
+ (eq_attr "type" "imul"))
+ "us1_single_issue")
-(define_function_unit "ieu0" 1 0
+(define_insn_reservation "us1_idiv" 1
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "cmove"))
- 2 1)
+ (eq_attr "type" "idiv"))
+ "us1_single_issue")
-(define_function_unit "ieu1" 1 0
+;; For loads, the "delayed return mode" behavior of the chip
+;; is represented using the us1_load_writeback resource.
+(define_insn_reservation "us1_load" 2
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "compare,call,sibcall,call_no_delay_slot,uncond_branch"))
- 1 1)
+ (eq_attr "type" "load,fpload"))
+ "us1_lsu + us1_slot012, us1_load_writeback")
+
+(define_insn_reservation "us1_load_signed" 3
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "sload"))
+ "us1_lsu + us1_slot012, nothing, us1_load_writeback")
-(define_function_unit "cti" 1 0
+(define_insn_reservation "us1_store" 1
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "store,fpstore"))
+ "us1_lsu + us1_slot012")
+
+(define_insn_reservation "us1_branch" 1
(and (eq_attr "cpu" "ultrasparc")
(eq_attr "type" "branch"))
- 1 1)
-
-;; Timings; throughput/latency
-;; FMOV 1/1 fmov, fabs, fneg
-;; FMOVcc 1/2
-;; FADD 1/3 add/sub, format conv, compar
-;; FMUL 1/3
-;; FDIVs 12/12
-;; FDIVd 22/22
-;; FSQRTs 12/12
-;; FSQRTd 22/22
-;; FCMP takes 1 cycle to branch, 2 cycles to conditional move.
-;;
-;; FDIV{s,d}/FSQRT{s,d} are given their own unit since they only
-;; use the FPM multiplier for final rounding 3 cycles before the
-;; end of their latency and we have no real way to model that.
-;;
-;; ??? This is really bogus because the timings really depend upon
-;; who uses the result. We should record who the user is with
-;; more descriptive 'type' attribute names and account for these
-;; issues in ultrasparc_adjust_cost.
+ "us1_cti + us1_slotany")
-(define_function_unit "fadd" 1 0
+(define_insn_reservation "us1_call_jmpl" 1
(and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "fpmove"))
- 1 1)
+ (eq_attr "type" "call,sibcall,call_no_delay_slot,uncond_branch"))
+ "us1_cti + us1_ieu1 + us1_slot0")
+
+(define_insn_reservation "us1_fmov_single" 1
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpmove"))
+ (eq_attr "fptype" "single"))
+ "us1_fpa + us1_fp_single + us1_slotany")
+
+(define_insn_reservation "us1_fmov_double" 1
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpmove"))
+ (eq_attr "fptype" "double"))
+ "us1_fpa + us1_fp_double + us1_slotany")
+
+(define_insn_reservation "us1_fcmov_single" 2
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpcmove,fpcrmove"))
+ (eq_attr "fptype" "single"))
+ "us1_fpa + us1_fp_single + us1_slotany, nothing")
+
+(define_insn_reservation "us1_fcmov_double" 2
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpcmove,fpcrmove"))
+ (eq_attr "fptype" "double"))
+ "us1_fpa + us1_fp_double + us1_slotany, nothing")
+
+(define_insn_reservation "us1_faddsub_single" 4
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fp"))
+ (eq_attr "fptype" "single"))
+ "us1_fpa + us1_fp_single + us1_slotany, nothing*3")
+
+(define_insn_reservation "us1_faddsub_double" 4
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fp"))
+ (eq_attr "fptype" "double"))
+ "us1_fpa + us1_fp_double + us1_slotany, nothing*3")
+
+(define_insn_reservation "us1_fpcmp_single" 1
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpcmp"))
+ (eq_attr "fptype" "single"))
+ "us1_fpa + us1_fp_single + us1_slotany")
+
+(define_insn_reservation "us1_fpcmp_double" 1
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpcmp"))
+ (eq_attr "fptype" "double"))
+ "us1_fpa + us1_fp_double + us1_slotany")
+
+(define_insn_reservation "us1_fmult_single" 4
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpmul"))
+ (eq_attr "fptype" "single"))
+ "us1_fpm + us1_fp_single + us1_slotany, nothing*3")
+
+(define_insn_reservation "us1_fmult_double" 4
+ (and (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpmul"))
+ (eq_attr "fptype" "double"))
+ "us1_fpm + us1_fp_double + us1_slotany, nothing*3")
+
+;; This is actually in theory dangerous, because it is possible
+;; for the chip to prematurely dispatch the dependant instruction
+;; in the G stage, resulting in a 9 cycle stall. However I have never
+;; been able to trigger this case myself even with hand written code,
+;; so it must require some rare complicated pipeline state.
+(define_bypass 3
+ "us1_faddsub_single,us1_faddsub_double,us1_fmult_single,us1_fmult_double"
+ "us1_faddsub_single,us1_faddsub_double,us1_fmult_single,us1_fmult_double")
+
+;; Floating point divide and square root use the multiplier unit
+;; for final rounding 3 cycles before the divide/sqrt is complete.
+
+(define_insn_reservation "us1_fdivs"
+ 13
+ (and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpdivs,fpsqrts"))
+ "(us1_fpm + us1_fdivider + us1_slot0), us1_fdivider*8, (us1_fpm + us1_fdivider), us1_fdivider*2"
+ )
-(define_function_unit "fadd" 1 0
+(define_bypass
+ 12
+ "us1_fdivs"
+ "us1_faddsub_single,us1_faddsub_double,us1_fmult_single,us1_fmult_double")
+
+(define_insn_reservation "us1_fdivd"
+ 23
(and (eq_attr "cpu" "ultrasparc")
+ (eq_attr "type" "fpdivd,fpsqrtd"))
+ "(us1_fpm + us1_fdivider + us1_slot0), us1_fdivider*18, (us1_fpm + us1_fdivider), us1_fdivider*2"
+ )
+(define_bypass
+ 22
+ "us1_fdivd"
+ "us1_faddsub_single,us1_faddsub_double,us1_fmult_single,us1_fmult_double")
+
+;; Any store may multi issue with the insn creating the source
+;; data as long as that creating insn is not an FPU div/sqrt.
+;; We need a special guard function because this bypass does
+;; not apply to the address inputs of the store.
+(define_bypass 0 "us1_simple_ieuN,us1_simple_ieu1,us1_simple_ieu0,us1_faddsub_single,us1_faddsub_double,us1_fmov_single,us1_fmov_double,us1_fcmov_single,us1_fcmov_double,us1_fmult_single,us1_fmult_double" "us1_store"
+ "ultrasparc_store_bypass_p")
+
+;; An integer branch may execute in the same cycle as the compare
+;; creating the condition codes.
+(define_bypass 0 "us1_simple_ieu1" "us1_branch")
+
+;; UltraSPARC-III scheduling
+;;
+;; A much simpler beast, no silly slotting rules and both
+;; integer units are fully symmetric. It does still have
+;; single-issue instructions though.
+
+(define_cpu_unit "us3_a0,us3_a1,us3_ms,us3_br,us3_fpm" "ultrasparc3_0")
+(define_cpu_unit "us3_slot0,us3_slot1,us3_slot2,us3_slot3,us3_fpa" "ultrasparc3_1")
+(define_cpu_unit "us3_load_writeback" "ultrasparc3_1")
+
+(define_reservation "us3_slotany" "(us3_slot0 | us3_slot1 | us3_slot2 | us3_slot3)")
+(define_reservation "us3_single_issue" "us3_slot0 + us3_slot1 + us3_slot2 + us3_slot3")
+(define_reservation "us3_ax" "(us3_a0 | us3_a1)")
+
+(define_insn_reservation "us3_integer" 1
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "ialu,shift,compare"))
+ "us3_ax + us3_slotany")
+
+(define_insn_reservation "us3_cmove" 2
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "cmove"))
+ "us3_ms + us3_br + us3_slotany, nothing")
+
+;; ??? Not entirely accurate.
+;; ??? It can run from 6 to 9 cycles. The first cycle the MS pipe
+;; ??? is needed, and the instruction group is broken right after
+;; ??? the imul. Then 'helper' instructions are generated to perform
+;; ??? each further stage of the multiplication, each such 'helper' is
+;; ??? single group. So, the reservation aspect is represented accurately
+;; ??? here, but the variable cycles are not.
+;; ??? Currently I have no idea how to determine the variability, but once
+;; ??? known we can simply add a define_bypass or similar to model it.
+(define_insn_reservation "us3_imul" 6
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "imul"))
+ "us3_ms + us3_slotany, us3_single_issue*5")
+
+(define_insn_reservation "us3_idiv" 71
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "idiv"))
+ "us3_ms + us3_slotany, us3_single_issue*70")
+
+;; UltraSPARC-III has a similar load delay as UltraSPARC-I/II except
+;; that all loads except 32-bit/64-bit unsigned loads take the extra
+;; delay for sign/zero extension.
+(define_insn_reservation "us3_2cycle_load" 2
+ (and (eq_attr "cpu" "ultrasparc3")
+ (and (eq_attr "type" "load,fpload")
+ (eq_attr "us3load_type" "2cycle")))
+ "us3_ms + us3_slotany, us3_load_writeback")
+
+(define_insn_reservation "us3_load_delayed" 3
+ (and (eq_attr "cpu" "ultrasparc3")
+ (and (eq_attr "type" "load,sload")
+ (eq_attr "us3load_type" "3cycle")))
+ "us3_ms + us3_slotany, nothing, us3_load_writeback")
+
+(define_insn_reservation "us3_store" 1
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "store,fpstore"))
+ "us3_ms + us3_slotany")
+
+(define_insn_reservation "us3_branch" 1
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "branch"))
+ "us3_br + us3_slotany")
+
+(define_insn_reservation "us3_call_jmpl" 1
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "call,sibcall,call_no_delay_slot,uncond_branch"))
+ "us3_br + us3_ms + us3_slotany")
+
+(define_insn_reservation "us3_fmov" 3
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "fpmove"))
+ "us3_fpa + us3_slotany, nothing*2")
+
+(define_insn_reservation "us3_fcmov" 3
+ (and (eq_attr "cpu" "ultrasparc3")
(eq_attr "type" "fpcmove"))
- 2 1)
+ "us3_fpa + us3_br + us3_slotany, nothing*2")
-(define_function_unit "fadd" 1 0
- (and (eq_attr "cpu" "ultrasparc")
+(define_insn_reservation "us3_fcrmov" 3
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "fpcrmove"))
+ "us3_fpa + us3_ms + us3_slotany, nothing*2")
+
+(define_insn_reservation "us3_faddsub" 4
+ (and (eq_attr "cpu" "ultrasparc3")
(eq_attr "type" "fp"))
- 3 1)
+ "us3_fpa + us3_slotany, nothing*3")
-(define_function_unit "fadd" 1 0
- (and (eq_attr "cpu" "ultrasparc")
+(define_insn_reservation "us3_fpcmp" 5
+ (and (eq_attr "cpu" "ultrasparc3")
(eq_attr "type" "fpcmp"))
- 2 1)
+ "us3_fpa + us3_slotany, nothing*4")
-(define_function_unit "fmul" 1 0
- (and (eq_attr "cpu" "ultrasparc")
+(define_insn_reservation "us3_fmult" 4
+ (and (eq_attr "cpu" "ultrasparc3")
(eq_attr "type" "fpmul"))
- 3 1)
+ "us3_fpm + us3_slotany, nothing*3")
-(define_function_unit "fadd" 1 0
- (and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "fpcmove"))
- 2 1)
-
-(define_function_unit "fdiv" 1 0
- (and (eq_attr "cpu" "ultrasparc")
+(define_insn_reservation "us3_fdivs" 17
+ (and (eq_attr "cpu" "ultrasparc3")
(eq_attr "type" "fpdivs"))
- 12 12)
+ "(us3_fpm + us3_slotany), us3_fpm*14, nothing*2")
-(define_function_unit "fdiv" 1 0
- (and (eq_attr "cpu" "ultrasparc")
- (eq_attr "type" "fpdivd"))
- 22 22)
-
-(define_function_unit "fdiv" 1 0
- (and (eq_attr "cpu" "ultrasparc")
+(define_insn_reservation "us3_fsqrts" 20
+ (and (eq_attr "cpu" "ultrasparc3")
(eq_attr "type" "fpsqrts"))
- 12 12)
+ "(us3_fpm + us3_slotany), us3_fpm*17, nothing*2")
-(define_function_unit "fdiv" 1 0
- (and (eq_attr "cpu" "ultrasparc")
+(define_insn_reservation "us3_fdivd" 20
+ (and (eq_attr "cpu" "ultrasparc3")
+ (eq_attr "type" "fpdivd"))
+ "(us3_fpm + us3_slotany), us3_fpm*17, nothing*2")
+
+(define_insn_reservation "us3_fsqrtd" 29
+ (and (eq_attr "cpu" "ultrasparc3")
(eq_attr "type" "fpsqrtd"))
- 22 22)
+ "(us3_fpm + us3_slotany), us3_fpm*26, nothing*2")
+
+;; Any store may multi issue with the insn creating the source
+;; data as long as that creating insn is not an FPU div/sqrt.
+;; We need a special guard function because this bypass does
+;; not apply to the address inputs of the store.
+(define_bypass 0 "us3_integer,us3_faddsub,us3_fmov,us3_fcmov,us3_fmult" "us3_store"
+ "ultrasparc_store_bypass_p")
+
+;; An integer branch may execute in the same cycle as the compare
+;; creating the condition codes.
+(define_bypass 0 "us3_integer" "us3_branch")
+
+;; If FMOVfcc is user of FPCMP, latency is only 1 cycle.
+(define_bypass 1 "us3_fpcmp" "us3_fcmov")
+
;; Compare instructions.
;; This controls RTL generation and register allocation.
@@ -2181,7 +2365,8 @@
mov\\t%1, %0
ldub\\t%1, %0
stb\\t%r1, %0"
- [(set_attr "type" "*,load,store")])
+ [(set_attr "type" "*,load,store")
+ (set_attr "us3load_type" "*,3cycle,*")])
(define_expand "movhi"
[(set (match_operand:HI 0 "general_operand" "")
@@ -2255,7 +2440,8 @@
sethi\\t%%hi(%a1), %0
lduh\\t%1, %0
sth\\t%r1, %0"
- [(set_attr "type" "*,*,load,store")])
+ [(set_attr "type" "*,*,load,store")
+ (set_attr "us3load_type" "*,*,3cycle,*")])
;; We always work with constants here.
(define_insn "*movhi_lo_sum"
@@ -4404,7 +4590,7 @@
"@
fmovrs%D1\\t%2, %3, %0
fmovrs%d1\\t%2, %4, %0"
- [(set_attr "type" "fpcmove")])
+ [(set_attr "type" "fpcrmove")])
(define_insn "movdf_cc_reg_sp64"
[(set (match_operand:DF 0 "register_operand" "=e,e")
@@ -4417,7 +4603,7 @@
"@
fmovrd%D1\\t%2, %3, %0
fmovrd%d1\\t%2, %4, %0"
- [(set_attr "type" "fpcmove")
+ [(set_attr "type" "fpcrmove")
(set_attr "fptype" "double")])
(define_insn "*movtf_cc_reg_hq_sp64"
@@ -4431,7 +4617,7 @@
"@
fmovrq%D1\\t%2, %3, %0
fmovrq%d1\\t%2, %4, %0"
- [(set_attr "type" "fpcmove")])
+ [(set_attr "type" "fpcrmove")])
(define_insn "*movtf_cc_reg_sp64"
[(set (match_operand:TF 0 "register_operand" "=e,e")
@@ -4521,7 +4707,8 @@
(zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
""
"lduh\\t%1, %0"
- [(set_attr "type" "load")])
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
(define_expand "zero_extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
@@ -4536,7 +4723,8 @@
"@
and\\t%1, 0xff, %0
ldub\\t%1, %0"
- [(set_attr "type" "*,load")])
+ [(set_attr "type" "*,load")
+ (set_attr "us3load_type" "*,3cycle")])
(define_expand "zero_extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
@@ -4551,7 +4739,8 @@
"@
and\\t%1, 0xff, %0
ldub\\t%1, %0"
- [(set_attr "type" "*,load")])
+ [(set_attr "type" "*,load")
+ (set_attr "us3load_type" "*,3cycle")])
(define_expand "zero_extendqidi2"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4566,7 +4755,8 @@
"@
and\\t%1, 0xff, %0
ldub\\t%1, %0"
- [(set_attr "type" "*,load")])
+ [(set_attr "type" "*,load")
+ (set_attr "us3load_type" "*,3cycle")])
(define_expand "zero_extendhidi2"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4597,7 +4787,8 @@
(zero_extend:DI (match_operand:HI 1 "memory_operand" "m")))]
"TARGET_ARCH64"
"lduh\\t%1, %0"
- [(set_attr "type" "load")])
+ [(set_attr "type" "load")
+ (set_attr "us3load_type" "3cycle")])
;; ??? Write truncdisi pattern using sra?
@@ -4803,7 +4994,8 @@
(sign_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
""
"ldsh\\t%1, %0"
- [(set_attr "type" "sload")])
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
(define_expand "extendqihi2"
[(set (match_operand:HI 0 "register_operand" "")
@@ -4843,7 +5035,8 @@
(sign_extend:HI (match_operand:QI 1 "memory_operand" "m")))]
""
"ldsb\\t%1, %0"
- [(set_attr "type" "sload")])
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
(define_expand "extendqisi2"
[(set (match_operand:SI 0 "register_operand" "")
@@ -4874,7 +5067,8 @@
(sign_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
""
"ldsb\\t%1, %0"
- [(set_attr "type" "sload")])
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
(define_expand "extendqidi2"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4905,7 +5099,8 @@
(sign_extend:DI (match_operand:QI 1 "memory_operand" "m")))]
"TARGET_ARCH64"
"ldsb\\t%1, %0"
- [(set_attr "type" "sload")])
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
(define_expand "extendhidi2"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4936,7 +5131,8 @@
(sign_extend:DI (match_operand:HI 1 "memory_operand" "m")))]
"TARGET_ARCH64"
"ldsh\\t%1, %0"
- [(set_attr "type" "sload")])
+ [(set_attr "type" "sload")
+ (set_attr "us3load_type" "3cycle")])
(define_expand "extendsidi2"
[(set (match_operand:DI 0 "register_operand" "")
@@ -4951,7 +5147,8 @@
"@
sra\\t%1, 0, %0
ldsw\\t%1, %0"
- [(set_attr "type" "shift,sload")])
+ [(set_attr "type" "shift,sload")
+ (set_attr "us3load_type" "*,3cycle")])
;; Special pattern for optimizing bit-field compares. This is needed
;; because combine uses this as a canonical form.
@@ -9507,3 +9704,9 @@
"TARGET_V9"
"t%C0\\t%%xcc, %1"
[(set_attr "type" "misc")])
+
+(define_insn "cycle_display"
+ [(unspec [(match_operand 0 "const_int_operand" "")] 20)]
+ ""
+ "! cycle %0"
+ [(set_attr "length" "0")])
diff --git a/gcc/doc/contrib.texi b/gcc/doc/contrib.texi
index 2e19ba21c9d..cab46f08f39 100644
--- a/gcc/doc/contrib.texi
+++ b/gcc/doc/contrib.texi
@@ -330,9 +330,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.
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index a07163e1127..6a173521e22 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -3871,13 +3871,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
@@ -4497,7 +4498,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
@@ -5127,14 +5128,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
@@ -5148,13 +5236,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
@@ -5217,10 +5306,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)
@@ -5246,6 +5335,395 @@ 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. There is an important difference between the old
+description and the automaton based pipeline description. The latency
+time is used for all dependencies when we use the old description. In
+the automaton based pipeline description, given latency time is used
+only for true dependencies. The cost of anti-dependencies is always
+zero and the cost of output dependencies is the difference between
+latency times of the producing and consuming insns (if the difference
+is negative, the cost is considered to be zero). You always can
+change the default costs for any description by using target hook
+@code{TARGET_SCHED_ADJUST_COST} (@pxref{Scheduling}).
+
+@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. You should remember that you will be in trouble if
+@var{condition} for two or more different
+@code{define_insn_reservation} constructions is TRUE for an insn. In
+this case what reservation will be used for the insn is not defined.
+Such cases are not checked during generation of the pipeline hazards
+recognizer because in general recognizing that two conditions may have
+the same value is quite difficult (especially if the conditions
+contain @code{symbol_ref}). It is also not checked during the
+pipeline hazard recognizer work because it would slow down the
+recognizer considerably.
+
+@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.
+
+All functional units mentioned in a set should belong the same
+automaton.
+
+@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*2, (port_0 | port1)")
+
+(define_insn_reservation "div" 8 (eq_attr "cpu" "div")
+ "i1_pipeline, div*7, div + (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
+
@node Conditional Execution
@section Conditional Execution
@cindex conditional execution
diff --git a/gcc/doc/passes.texi b/gcc/doc/passes.texi
index 6ca5b856550..cdc694bf5c3 100644
--- a/gcc/doc/passes.texi
+++ b/gcc/doc/passes.texi
@@ -654,6 +654,8 @@ 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
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index f3243b22c6f..0157ef83840 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -5401,11 +5401,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})
@@ -5421,12 +5429,18 @@ 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. See also
+@pxref{Automaton pipeline description}.
@end deftypefn
@deftypefn {Target Hook} int TARGET_SCHED_ADJUST_PRIORITY (rtx @var{insn}, int @var{priority})
@@ -5492,6 +5506,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
diff --git a/gcc/genattr.c b/gcc/genattr.c
index 4d53077c506..60045ff8083 100644
--- a/gcc/genattr.c
+++ b/gcc/genattr.c
@@ -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,102 @@ 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");
+ }
+ else
+ {
+ /* Otherwise we do no scheduling, but we need these typedefs
+ in order to avoid uglifying other code with more ifdefs. */
+ printf ("typedef void *state_t;\n\n");
}
/* Output flag masks for use by reorg.
diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c
index 2c9b007000d..d78972cc87c 100644
--- a/gcc/genattrtab.c
+++ b/gcc/genattrtab.c
@@ -115,6 +115,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;
@@ -309,6 +311,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};
@@ -371,10 +375,7 @@ 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 rtx attr_rtx_1 PARAMS ((enum rtx_code, va_list));
-static char *attr_printf PARAMS ((unsigned 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 *));
@@ -458,10 +459,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));
@@ -739,7 +738,7 @@ attr_rtx VPARAMS ((enum rtx_code code, ...))
rtx attr_printf (len, format, [arg1, ..., argn]) */
-static char *
+char *
attr_printf VPARAMS ((unsigned int len, const char *fmt, ...))
{
char str[256];
@@ -920,7 +919,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;
@@ -5880,7 +5879,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;
@@ -5947,7 +5946,7 @@ find_single_value (attr)
/* Return (attr_value "n") */
-static rtx
+rtx
make_numeric_value (n)
int n;
{
@@ -6097,6 +6096,7 @@ from the machine description file `md'. */\n\n");
/* Read the machine description. */
+ initiate_automaton_gen (argc, argv);
while (1)
{
int lineno;
@@ -6125,6 +6125,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;
}
@@ -6149,9 +6189,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");
@@ -6226,9 +6271,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
index 00000000000..ea1f23991ea
--- /dev/null
+++ b/gcc/genattrtab.h
@@ -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 ((unsigned 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
index 00000000000..76a57bb3b43
--- /dev/null
+++ b/gcc/genautomata.c
@@ -0,0 +1,9162 @@
+/* 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 automata_list_el *automata_list_el_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 automata_list_el_t get_free_automata_list_el PARAMS ((void));
+static void free_automata_list_el PARAMS ((automata_list_el_t));
+static void free_automata_list PARAMS ((automata_list_el_t));
+static unsigned automata_list_hash PARAMS ((const void *));
+static int automata_list_eq_p PARAMS ((const void *, const void *));
+static void initiate_automata_lists PARAMS ((void));
+static void automata_list_start PARAMS ((void));
+static void automata_list_add PARAMS ((automaton_t));
+static automata_list_el_t automata_list_finish PARAMS ((void));
+static void finish_automata_lists 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_insn_code_cases PARAMS ((void (*) (automata_list_el_t)));
+static void output_automata_list_min_issue_delay_code PARAMS ((automata_list_el_t));
+static void output_internal_min_issue_delay_func PARAMS ((void));
+static void output_automata_list_transition_code PARAMS ((automata_list_el_t));
+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_automata_list_state_alts_code PARAMS ((automata_list_el_t));
+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));
+static void add_automaton_state PARAMS ((state_t));
+static void form_important_insn_automata_lists PARAMS ((void));
+
+/* Undefined position. */
+static pos_t no_pos = 0;
+
+/* All IR is stored in the following obstack. */
+static struct obstack irp;
+
+
+
+/* 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)
+
+
+
+/* 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;
+
+
+
+/* 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;
+ /* The following member value is the list to automata which can be
+ changed by the insn issue. */
+ automata_list_el_t important_automata_list;
+ /* The following member is used to process insn once for output. */
+ int processed_p;
+};
+
+/* 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 following member value is TRUE if there is an arc in the
+ automaton marked by the insn into another state. In other
+ words, the insn can change the state of the automaton. */
+ int important_p;
+};
+
+/* 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 is the element of the list of automata. */
+struct automata_list_el
+{
+ /* The automaton itself. */
+ automaton_t automaton;
+ /* The next automata set element. */
+ automata_list_el_t next_automata_list_el;
+};
+
+/* 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++;
+}
+
+
+
+/* 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;
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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;
+ }
+ if (dst->unit_decl->automaton_name != NULL
+ && src->unit_decl->automaton_name != NULL
+ && strcmp (dst->unit_decl->automaton_name,
+ src->unit_decl->automaton_name) != 0)
+ {
+ error ("units `%s' and `%s' in exclusion set belong to different automata",
+ src->unit_decl->name, dst->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;
+ }
+ if (dst->unit_decl->automaton_name != NULL
+ && src->unit_decl->automaton_name != NULL
+ && strcmp (dst->unit_decl->automaton_name,
+ src->unit_decl->automaton_name) != 0)
+ {
+ error ((presence_p
+ ? "units `%s' and `%s' in presence set belong to different automata"
+ : "units `%s' and `%s' in absence set belong to different automata"),
+ src->unit_decl->name, dst->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 ();
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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;
+
+
+
+/* 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++;
+}
+
+
+/* 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 ()
+{
+}
+
+
+
+/* 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)
+
+
+
+/* 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;
+
+ repetition_num = 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 (start_cycle != 0)
+ fprintf (f, ", ");
+ output_cycle_reservs (f, reservs, start_cycle, repetition_num);
+ repetition_num = 1;
+ start_cycle = cycle;
+ }
+ if (start_cycle < max_cycles_num)
+ {
+ if (start_cycle != 0)
+ 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 ();
+}
+
+
+
+/* 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 ()
+{
+}
+
+
+
+/* Abstract data `automata lists'. */
+
+/* List of free states. */
+static automata_list_el_t first_free_automata_list_el;
+
+/* The list being formed. */
+static automata_list_el_t current_automata_list;
+
+/* Hash table of automata lists. */
+static htab_t automata_list_table;
+
+/* The following function returns free automata list el. It may be
+ new allocated node or node freed earlier. */
+static automata_list_el_t
+get_free_automata_list_el ()
+{
+ automata_list_el_t result;
+
+ if (first_free_automata_list_el != NULL)
+ {
+ result = first_free_automata_list_el;
+ first_free_automata_list_el
+ = first_free_automata_list_el->next_automata_list_el;
+ }
+ else
+ result = create_node (sizeof (struct automata_list_el));
+ result->automaton = NULL;
+ result->next_automata_list_el = NULL;
+ return result;
+}
+
+/* The function frees node AUTOMATA_LIST_EL. */
+static void
+free_automata_list_el (automata_list_el)
+ automata_list_el_t automata_list_el;
+{
+ if (automata_list_el == NULL)
+ return;
+ automata_list_el->next_automata_list_el = first_free_automata_list_el;
+ first_free_automata_list_el = automata_list_el;
+}
+
+/* The function frees list AUTOMATA_LIST. */
+static void
+free_automata_list (automata_list)
+ automata_list_el_t automata_list;
+{
+ automata_list_el_t curr_automata_list_el;
+ automata_list_el_t next_automata_list_el;
+
+ for (curr_automata_list_el = automata_list;
+ curr_automata_list_el != NULL;
+ curr_automata_list_el = next_automata_list_el)
+ {
+ next_automata_list_el = curr_automata_list_el->next_automata_list_el;
+ free_automata_list_el (curr_automata_list_el);
+ }
+}
+
+/* Hash value of AUTOMATA_LIST. */
+static unsigned
+automata_list_hash (automata_list)
+ const void *automata_list;
+{
+ unsigned int hash_value;
+ automata_list_el_t curr_automata_list_el;
+
+ hash_value = 0;
+ for (curr_automata_list_el = (automata_list_el_t) automata_list;
+ curr_automata_list_el != NULL;
+ curr_automata_list_el = curr_automata_list_el->next_automata_list_el)
+ hash_value = (((hash_value >> (sizeof (unsigned) - 1) * CHAR_BIT)
+ | (hash_value << CHAR_BIT))
+ + curr_automata_list_el->automaton->automaton_order_num);
+ return hash_value;
+}
+
+/* Return nonzero value if the automata_lists are the same. */
+static int
+automata_list_eq_p (automata_list_1, automata_list_2)
+ const void *automata_list_1;
+ const void *automata_list_2;
+{
+ automata_list_el_t automata_list_el_1;
+ automata_list_el_t automata_list_el_2;
+
+ for (automata_list_el_1 = (automata_list_el_t) automata_list_1,
+ automata_list_el_2 = (automata_list_el_t) automata_list_2;
+ automata_list_el_1 != NULL && automata_list_el_2 != NULL;
+ automata_list_el_1 = automata_list_el_1->next_automata_list_el,
+ automata_list_el_2 = automata_list_el_2->next_automata_list_el)
+ if (automata_list_el_1->automaton != automata_list_el_2->automaton)
+ return 0;
+ return automata_list_el_1 == automata_list_el_2;
+}
+
+/* Initialization of the abstract data. */
+static void
+initiate_automata_lists ()
+{
+ first_free_automata_list_el = NULL;
+ automata_list_table = htab_create (1500, automata_list_hash,
+ automata_list_eq_p, (htab_del) 0);
+}
+
+/* The following function starts new automata list and makes it the
+ current one. */
+static void
+automata_list_start ()
+{
+ current_automata_list = NULL;
+}
+
+/* The following function adds AUTOMATON to the current list. */
+static void
+automata_list_add (automaton)
+ automaton_t automaton;
+{
+ automata_list_el_t el;
+
+ el = get_free_automata_list_el ();
+ el->automaton = automaton;
+ el->next_automata_list_el = current_automata_list;
+ current_automata_list = el;
+}
+
+/* The following function finishes forming the current list, inserts
+ it into the table and returns it. */
+static automata_list_el_t
+automata_list_finish ()
+{
+ void **entry_ptr;
+
+ if (current_automata_list == NULL)
+ return NULL;
+ entry_ptr = htab_find_slot (automata_list_table,
+ (void *) current_automata_list, 1);
+ if (*entry_ptr == NULL)
+ *entry_ptr = (void *) current_automata_list;
+ else
+ free_automata_list (current_automata_list);
+ current_automata_list = NULL;
+ return (automata_list_el_t) *entry_ptr;
+}
+
+/* Finishing work with the abstract data. */
+static void
+finish_automata_lists ()
+{
+ htab_delete (automata_list_table);
+}
+
+
+
+/* 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;
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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));
+ }
+}
+
+
+
+/* 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);
+ }
+ }
+}
+
+
+
+/* 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;
+ }
+}
+
+
+
+/* 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;
+}
+
+
+
+/* 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;
+}
+
+
+
+/* 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->important_p = FALSE;
+ 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)
+ {
+ if (curr_automaton->corresponding_automaton_decl == NULL)
+ fprintf (stderr, "Create anonymous automaton ...");
+ else
+ fprintf (stderr, "Create automaton `%s'...",
+ curr_automaton->corresponding_automaton_decl->name);
+ 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);
+ fprintf (stderr, "done\n");
+ }
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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 ()
+{
+ 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"
+
+/* Name of length of cache of insn dfa codes. */
+#define DFA_INSN_CODES_LENGTH_VARIABLE_NAME "dfa_insn_codes_length"
+
+/* 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);
+}
+
+
+/* The function outputs switch cases for insn reseravtions using
+ function *output_automata_list_code. */
+static void
+output_insn_code_cases (output_automata_list_code)
+ void (*output_automata_list_code) (automata_list_el_t);
+{
+ decl_t decl, decl_2;
+ int i, j;
+
+ for (i = 0; i < description->decls_num; i++)
+ {
+ decl = description->decls [i];
+ if (decl->mode == dm_insn_reserv)
+ decl->decl.insn_reserv.processed_p = FALSE;
+ }
+ for (i = 0; i < description->decls_num; i++)
+ {
+ decl = description->decls [i];
+ if (decl->mode == dm_insn_reserv && !decl->decl.insn_reserv.processed_p)
+ {
+ for (j = i; j < description->decls_num; j++)
+ {
+ decl_2 = description->decls [j];
+ if (decl_2->mode == dm_insn_reserv
+ && (decl_2->decl.insn_reserv.important_automata_list
+ == decl->decl.insn_reserv.important_automata_list))
+ {
+ decl_2->decl.insn_reserv.processed_p = TRUE;
+ fprintf (output_file, " case %d: /* %s */\n",
+ decl_2->decl.insn_reserv.insn_num,
+ decl_2->decl.insn_reserv.name);
+ }
+ }
+ (*output_automata_list_code)
+ (decl->decl.insn_reserv.important_automata_list);
+ }
+ }
+}
+
+
+/* The function outputs a code for evaluation of a minimal delay of
+ issue of insns which have reservations in given AUTOMATA_LIST. */
+static void
+output_automata_list_min_issue_delay_code (automata_list)
+ automata_list_el_t automata_list;
+{
+ automata_list_el_t el;
+ automaton_t automaton;
+
+ for (el = automata_list; el != NULL; el = el->next_automata_list_el)
+ {
+ automaton = el->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 (el == automata_list)
+ 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, " break;\n\n");
+}
+
+/* Output function `internal_min_issue_delay'. */
+static void
+output_internal_min_issue_delay_func ()
+{
+ 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);
+ fprintf (output_file, "\n switch (%s)\n {\n", INTERNAL_INSN_CODE_NAME);
+ output_insn_code_cases (output_automata_list_min_issue_delay_code);
+ fprintf (output_file,
+ "\n default:\n %s = -1;\n break;\n }\n",
+ RESULT_VARIABLE_NAME);
+ fprintf (output_file, " return %s;\n", RESULT_VARIABLE_NAME);
+ fprintf (output_file, "}\n\n");
+}
+
+/* The function outputs a code changing state after issue of insns
+ which have reservations in given AUTOMATA_LIST. */
+static void
+output_automata_list_transition_code (automata_list)
+ automata_list_el_t automata_list;
+{
+ automata_list_el_t el, next_el;
+
+ fprintf (output_file, " {\n");
+ if (automata_list != NULL && automata_list->next_automata_list_el != NULL)
+ for (el = automata_list;; el = next_el)
+ {
+ next_el = el->next_automata_list_el;
+ if (next_el == NULL)
+ break;
+ fprintf (output_file, " ");
+ output_state_member_type (output_file, el->automaton);
+ fprintf (output_file, " ");
+ output_temp_chip_member_name (output_file, el->automaton);
+ fprintf (output_file, ";\n");
+ }
+ for (el = automata_list; el != NULL; el = el->next_automata_list_el)
+ if (comb_vect_p (el->automaton->trans_table))
+ {
+ fprintf (output_file, "\n %s = ", TEMPORARY_VARIABLE_NAME);
+ output_trans_base_vect_name (output_file, el->automaton);
+ fprintf (output_file, " [%s->", CHIP_PARAMETER_NAME);
+ output_chip_member_name (output_file, el->automaton);
+ fprintf (output_file, "] + ");
+ output_translate_vect_name (output_file, el->automaton);
+ fprintf (output_file, " [%s];\n", INTERNAL_INSN_CODE_NAME);
+ fprintf (output_file, " if (");
+ output_trans_check_vect_name (output_file, el->automaton);
+ fprintf (output_file, " [%s] != %s->",
+ TEMPORARY_VARIABLE_NAME, CHIP_PARAMETER_NAME);
+ output_chip_member_name (output_file, el->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 (el->next_automata_list_el != NULL)
+ output_temp_chip_member_name (output_file, el->automaton);
+ else
+ {
+ fprintf (output_file, "%s->", CHIP_PARAMETER_NAME);
+ output_chip_member_name (output_file, el->automaton);
+ }
+ fprintf (output_file, " = ");
+ output_trans_comb_vect_name (output_file, el->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, el->automaton);
+ fprintf (output_file, " [");
+ output_translate_vect_name (output_file, el->automaton);
+ fprintf (output_file, " [%s] + ", INTERNAL_INSN_CODE_NAME);
+ fprintf (output_file, "%s->", CHIP_PARAMETER_NAME);
+ output_chip_member_name (output_file, el->automaton);
+ fprintf (output_file, " * %d];\n",
+ el->automaton->insn_equiv_classes_num);
+ fprintf (output_file, " if (%s >= %d)\n",
+ TEMPORARY_VARIABLE_NAME, el->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 (el->next_automata_list_el != NULL)
+ output_temp_chip_member_name (output_file, el->automaton);
+ else
+ {
+ fprintf (output_file, "%s->", CHIP_PARAMETER_NAME);
+ output_chip_member_name (output_file, el->automaton);
+ }
+ fprintf (output_file, " = %s;\n", TEMPORARY_VARIABLE_NAME);
+ }
+ if (automata_list != NULL && automata_list->next_automata_list_el != NULL)
+ for (el = automata_list;; el = next_el)
+ {
+ next_el = el->next_automata_list_el;
+ if (next_el == NULL)
+ break;
+ fprintf (output_file, " %s->", CHIP_PARAMETER_NAME);
+ output_chip_member_name (output_file, el->automaton);
+ fprintf (output_file, " = ");
+ output_temp_chip_member_name (output_file, el->automaton);
+ fprintf (output_file, ";\n");
+ }
+ fprintf (output_file, " return -1;\n");
+ fprintf (output_file, " }\n");
+}
+
+/* Output function `internal_state_transition'. */
+static void
+output_internal_trans_func ()
+{
+ 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);
+ fprintf (output_file, "\n switch (%s)\n {\n", INTERNAL_INSN_CODE_NAME);
+ output_insn_code_cases (output_automata_list_transition_code);
+ fprintf (output_file, "\n default:\n return -1;\n }\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 int %s;\n\n",
+ INTERNAL_INSN_CODE_NAME, TEMPORARY_VARIABLE_NAME);
+ fprintf (output_file, " if (INSN_UID (%s) >= %s)\n {\n",
+ INSN_PARAMETER_NAME, DFA_INSN_CODES_LENGTH_VARIABLE_NAME);
+ fprintf (output_file, " %s = %s;\n %s = 2 * INSN_UID (%s);\n",
+ TEMPORARY_VARIABLE_NAME, DFA_INSN_CODES_LENGTH_VARIABLE_NAME,
+ DFA_INSN_CODES_LENGTH_VARIABLE_NAME, INSN_PARAMETER_NAME);
+ fprintf (output_file, " %s = xrealloc (%s, %s * sizeof (int));\n",
+ DFA_INSN_CODES_VARIABLE_NAME, DFA_INSN_CODES_VARIABLE_NAME,
+ DFA_INSN_CODES_LENGTH_VARIABLE_NAME);
+ fprintf (output_file,
+ " for (; %s < %s; %s++)\n %s [%s] = -1;\n }\n",
+ TEMPORARY_VARIABLE_NAME, DFA_INSN_CODES_LENGTH_VARIABLE_NAME,
+ TEMPORARY_VARIABLE_NAME, DFA_INSN_CODES_VARIABLE_NAME,
+ TEMPORARY_VARIABLE_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);
+}
+
+/* The function outputs a code for evaluation of alternative states
+ number for insns which have reservations in given AUTOMATA_LIST. */
+static void
+output_automata_list_state_alts_code (automata_list)
+ automata_list_el_t automata_list;
+{
+ automata_list_el_t el;
+ automaton_t automaton;
+
+ fprintf (output_file, " {\n");
+ for (el = automata_list; el != NULL; el = el->next_automata_list_el)
+ if (comb_vect_p (el->automaton->state_alts_table))
+ {
+ fprintf (output_file, " int %s;\n", TEMPORARY_VARIABLE_NAME);
+ break;
+ }
+ for (el = automata_list; el != NULL; el = el->next_automata_list_el)
+ {
+ automaton = el->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,
+ (el == automata_list
+ ? " %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,
+ (el == automata_list
+ ? "\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, " break;\n }\n\n");
+}
+
+/* Output function `internal_state_alts'. */
+static void
+output_internal_state_alts_func ()
+{
+ 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);
+ fprintf (output_file, "\n switch (%s)\n {\n", INTERNAL_INSN_CODE_NAME);
+ output_insn_code_cases (output_automata_list_state_alts_code);
+ fprintf (output_file,
+ "\n default:\n %s = 0;\n break;\n }\n",
+ RESULT_VARIABLE_NAME);
+ 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\n %s = get_max_uid ();\n",
+ DFA_START_FUNC_NAME, I_VARIABLE_NAME,
+ DFA_INSN_CODES_LENGTH_VARIABLE_NAME);
+ fprintf (output_file, " %s = (int *) xmalloc (%s * sizeof (int));\n",
+ DFA_INSN_CODES_VARIABLE_NAME, DFA_INSN_CODES_LENGTH_VARIABLE_NAME);
+ fprintf (output_file,
+ " for (%s = 0; %s < %s; %s++)\n %s [%s] = -1;\n}\n\n",
+ I_VARIABLE_NAME, I_VARIABLE_NAME,
+ DFA_INSN_CODES_LENGTH_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);
+}
+
+
+
+/* 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);
+ }
+}
+
+
+
+/* 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_automata_lists ();
+ 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);
+ fflush (stderr);
+ create_automata ();
+ ticker_off (&automaton_generation_time);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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);
+}
+
+
+
+/* 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 vla is used for storing pointers to all achieved
+ states. */
+static vla_ptr_t automaton_states;
+
+/* This function is called by function pass_states to add an achieved
+ STATE. */
+static void
+add_automaton_state (state)
+ state_t state;
+{
+ VLA_PTR_ADD (automaton_states, state);
+}
+
+/* The following function forms list of important automata (whose
+ states may be changed after the insn issue) for each insn. */
+static void
+form_important_insn_automata_lists ()
+{
+ automaton_t automaton;
+ state_t *state_ptr;
+ decl_t decl;
+ ainsn_t ainsn;
+ arc_t arc;
+ int i;
+
+ VLA_PTR_CREATE (automaton_states, 1500,
+ "automaton states for forming important insn automata sets");
+ /* Mark important ainsns. */
+ for (automaton = description->first_automaton;
+ automaton != NULL;
+ automaton = automaton->next_automaton)
+ {
+ VLA_PTR_NULLIFY (automaton_states);
+ pass_states (automaton, add_automaton_state);
+ for (state_ptr = VLA_PTR_BEGIN (automaton_states);
+ state_ptr <= (state_t *) VLA_PTR_LAST (automaton_states);
+ state_ptr++)
+ {
+ for (arc = first_out_arc (*state_ptr);
+ arc != NULL;
+ arc = next_out_arc (arc))
+ if (arc->to_state != *state_ptr)
+ {
+ if (!arc->insn->first_insn_with_same_reservs)
+ abort ();
+ for (ainsn = arc->insn;
+ ainsn != NULL;
+ ainsn = ainsn->next_same_reservs_insn)
+ ainsn->important_p = TRUE;
+ }
+ }
+ }
+ VLA_PTR_DELETE (automaton_states);
+ /* Create automata sets for the insns. */
+ for (i = 0; i < description->decls_num; i++)
+ {
+ decl = description->decls [i];
+ if (decl->mode == dm_insn_reserv)
+ {
+ automata_list_start ();
+ for (automaton = description->first_automaton;
+ automaton != NULL;
+ automaton = automaton->next_automaton)
+ for (ainsn = automaton->ainsn_list;
+ ainsn != NULL;
+ ainsn = ainsn->next_ainsn)
+ if (ainsn->important_p
+ && ainsn->insn_reserv_decl == &decl->decl.insn_reserv)
+ {
+ automata_list_add (automaton);
+ break;
+ }
+ decl->decl.insn_reserv.important_automata_list
+ = automata_list_finish ();
+ }
+ }
+}
+
+
+/* The following is top level function to generate automat(a,on) for
+ fast recognition of pipeline hazards. */
+void
+expand_automata ()
+{
+ int i;
+
+ description = create_node (sizeof (struct description)
+ /* One entry for cycle advancing insn. */
+ + sizeof (decl_t) * 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)
+ {
+ form_important_insn_automata_lists ();
+ 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", DFA_INSN_CODES_VARIABLE_NAME);
+ fprintf (output_file, "\nstatic int %s;\n\n",
+ DFA_INSN_CODES_LENGTH_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 ();
+ finish_automata_lists ();
+ 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);
+}
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index 686369d418f..2ac8121801f 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -158,6 +158,12 @@ 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));
@@ -292,6 +327,7 @@ static void queue_insn PARAMS ((rtx, int));
static void schedule_insn PARAMS ((rtx, struct ready_list *, int));
static void find_insn_reg_weight PARAMS ((int));
static void adjust_priority PARAMS ((rtx));
+static void advance_one_cycle PARAMS ((void));
/* Notes handling mechanism:
=========================
@@ -331,6 +367,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 *));
+
+static rtx choose_ready PARAMS ((struct ready_list *));
+
#endif /* INSN_SCHEDULING */
/* Point to state used for the current scheduling pass. */
@@ -354,7 +398,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 +436,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 +462,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 +512,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 +543,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 +580,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 +613,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 +661,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 +720,69 @@ insn_cost (insn, link, used)
{
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
+ && (*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
+ && (*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 +1009,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->vec[ready->first - i] = ready->vec[ready->first - i - 1];
+ return t;
+}
+
+
/* Sort the ready list READY by ascending priority, using the SCHED_SORT
macro. */
@@ -961,6 +1082,25 @@ adjust_priority (prev)
(*targetm.sched.adjust_priority) (prev, INSN_PRIORITY (prev));
}
+/* Advance time on one cycle. */
+HAIFA_INLINE static void
+advance_one_cycle ()
+{
+ if (targetm.sched.use_dfa_pipeline_interface
+ && (*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) ());
+ }
+}
+
/* Clock at which the previous instruction was issued. */
static int last_clock_var;
@@ -976,26 +1116,50 @@ 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
+ || !(*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
+ && (*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
+ || !(*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 +1201,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 +1630,7 @@ queue_to_ready (ready)
{
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 +1649,19 @@ queue_to_ready (ready)
}
insn_queue[NEXT_Q_AFTER (q_ptr, stalls)] = 0;
- if (ready->n_ready)
- break;
+ advance_one_cycle ();
+
+ break;
}
+
+ advance_one_cycle ();
}
- if (sched_verbose && stalls)
+ if ((!targetm.sched.use_dfa_pipeline_interface
+ || !(*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 +1677,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 +1792,113 @@ 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. The following function is used only for
+ first cycle multipass scheduling. */
+
+static int
+max_issue (ready, state, index)
+ struct ready_list *ready;
+ state_t state;
+ int *index;
+{
+ 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;
+
+ n = max_issue (ready, temp_state, &temp_index);
+ if (n > 0 || ready_try[0])
+ n += 1;
+
+ if (best < n)
+ {
+ best = n;
+ *index = i;
+ }
+ 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;
+
+ if (max_issue (ready, curr_state, &index) == 0)
+ return ready_remove_first (ready);
+ else
+ return ready_remove (ready, index);
+ }
+}
+
/* Called from backends from targetm.sched.reorder to emit stuff into
the instruction stream. */
@@ -1638,7 +1920,9 @@ schedule_block (b, rgn_n_insns)
int rgn_n_insns;
{
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;
@@ -1671,7 +1955,11 @@ schedule_block (b, rgn_n_insns)
init_block_visualization ();
}
- clear_units ();
+ if (targetm.sched.use_dfa_pipeline_interface
+ && (*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;
@@ -1679,6 +1967,15 @@ 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
+ && (*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)
@@ -1691,8 +1988,16 @@ 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
+ || !(*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;
@@ -1702,12 +2007,18 @@ schedule_block (b, rgn_n_insns)
{
clock_var++;
+ advance_one_cycle ();
+
/* 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
list. */
queue_to_ready (&ready);
+ if (sched_verbose && targetm.sched.cycle_display)
+ last_scheduled_insn
+ = (*targetm.sched.cycle_display) (clock_var, last_scheduled_insn);
+
if (ready.n_ready == 0)
abort ();
@@ -1730,24 +2041,127 @@ schedule_block (b, rgn_n_insns)
else
can_issue_more = issue_rate;
- if (sched_verbose && targetm.sched.cycle_display)
- last_scheduled_insn
- = (*targetm.sched.cycle_display) (clock_var, last_scheduled_insn);
-
- 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
+ || !(*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);
+
+ memcpy (temp_state, curr_state, dfa_state_size);
+ 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 (temp_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)
+ {
+ if (insert_schedule_bubbles_p)
+ {
+ rtx copy;
+
+ copy = copy_rtx (PATTERN (bubble));
+ emit_insn_after (copy, last_scheduled_insn);
+ last_scheduled_insn
+ = NEXT_INSN (last_scheduled_insn);
+ INSN_CODE (last_scheduled_insn)
+ = INSN_CODE (bubble);
+
+ /* Annotate the same for the first insns
+ scheduling by using mode. */
+ PUT_MODE (last_scheduled_insn,
+ (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_scheduled_insn));
+
+ if (recog_memoized (last_scheduled_insn)
+ < 0)
+ fprintf (sched_dump, "nothing");
+ else
+ print_reservation
+ (sched_dump, last_scheduled_insn);
+
+ 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)
{
@@ -1760,6 +2174,10 @@ schedule_block (b, rgn_n_insns)
last_scheduled_insn = move_insn (insn, last_scheduled_insn);
+ if (targetm.sched.use_dfa_pipeline_interface
+ && (*targetm.sched.use_dfa_pipeline_interface) ())
+ memcpy (curr_state, temp_state, dfa_state_size);
+
if (targetm.sched.variable_issue)
can_issue_more =
(*targetm.sched.variable_issue) (sched_dump, sched_verbose,
@@ -1770,6 +2188,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. */
@@ -1783,8 +2203,10 @@ schedule_block (b, rgn_n_insns)
}
}
- /* Debug info. */
- if (sched_verbose)
+ if ((!targetm.sched.use_dfa_pipeline_interface
+ || !(*targetm.sched.use_dfa_pipeline_interface) ())
+ && sched_verbose)
+ /* Debug info. */
visualize_scheduled_insns (clock_var);
}
@@ -1796,7 +2218,9 @@ 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
+ || !(*targetm.sched.use_dfa_pipeline_interface) ())
+ print_block_visualization ("");
}
/* Sanity check -- queue must be empty now. Meaningless if region has
@@ -1841,6 +2265,10 @@ schedule_block (b, rgn_n_insns)
current_sched_info->tail = tail;
free (ready.vec);
+
+ if (targetm.sched.use_dfa_pipeline_interface
+ && (*targetm.sched.use_dfa_pipeline_interface) ())
+ free (ready_try);
}
/* Set_priorities: compute priority of each insn in the block. */
@@ -1882,6 +2310,7 @@ sched_init (dump_file)
{
int luid, b;
rtx insn;
+ int i;
/* Disable speculative loads in their presence if cc0 defined. */
#ifdef HAVE_cc0
@@ -1909,6 +2338,27 @@ 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
+ && (*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++)
@@ -1966,8 +2416,10 @@ sched_init (dump_file)
}
}
- /* Find units used in this function, for visualization. */
- if (sched_verbose)
+ if ((!targetm.sched.use_dfa_pipeline_interface
+ || !(*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
@@ -1997,6 +2449,13 @@ void
sched_finish ()
{
free (h_i_d);
+
+ if (targetm.sched.use_dfa_pipeline_interface
+ && (*targetm.sched.use_dfa_pipeline_interface) ())
+ {
+ free (curr_state);
+ dfa_finish ();
+ }
free_dependency_caches ();
end_alias_analysis ();
if (write_symbols != NO_DEBUG)
diff --git a/gcc/rtl.def b/gcc/rtl.def
index 8fad6501864..71c2ef18ab1 100644
--- a/gcc/rtl.def
+++ b/gcc/rtl.def
@@ -342,6 +342,147 @@ 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. All CPU functional
+ units in a set should belong the same automaton. */
+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. All CPU
+ functional units in a set should belong the same automaton. */
+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. All
+ CPU functional units in a set should belong the same automaton. */
+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.
---------------------------------------------------------------------- */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index efa66c28fc3..453592916bc 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -130,11 +130,9 @@ struct rtx_def
/* 1 in an INSN if it can alter flow of control
within this function.
MEM_KEEP_ALIAS_SET_P in a MEM.
- LINK_COST_ZERO in an INSN_LIST.
SET_IS_RETURN_P in a SET. */
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.
@@ -983,16 +981,6 @@ do { \
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)
diff --git a/gcc/sched-int.h b/gcc/sched-int.h
index f5a880809c8..2b18c28badc 100644
--- a/gcc/sched-int.h
+++ b/gcc/sched-int.h
@@ -20,6 +20,9 @@ along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. */
+/* Pointer to data describing the current DFA state. */
+extern state_t curr_state;
+
/* Forward declaration. */
struct ready_list;
@@ -184,7 +187,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. */
@@ -196,7 +199,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
diff --git a/gcc/sched-rgn.c b/gcc/sched-rgn.c
index ab65e2cec5e..0d41ec77dc7 100644
--- a/gcc/sched-rgn.c
+++ b/gcc/sched-rgn.c
@@ -62,6 +62,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "recog.h"
#include "cfglayout.h"
#include "sched-int.h"
+#include "target.h"
/* Define when we want to do count REG_DEAD notes before and after scheduling
for sanity checking. We can't do that when conditional execution is used,
@@ -2057,7 +2058,14 @@ init_ready_list (ready)
if (!CANT_MOVE (insn)
&& (!IS_SPECULATIVE_INSN (insn)
- || (insn_issue_delay (insn) <= 3
+ || ((((!targetm.sched.use_dfa_pipeline_interface
+ || !(*targetm.sched.use_dfa_pipeline_interface) ())
+ && insn_issue_delay (insn) <= 3)
+ || (targetm.sched.use_dfa_pipeline_interface
+ && (*targetm.sched.use_dfa_pipeline_interface) ()
+ && (recog_memoized (insn) < 0
+ || min_insn_conflict_delay (curr_state,
+ insn, insn) <= 3)))
&& check_live (insn, bb_src)
&& is_exception_free (insn, bb_src, target_bb))))
{
@@ -2165,7 +2173,15 @@ 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
+ && (*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
+ || !(*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;
@@ -2589,14 +2605,27 @@ 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
+ && (*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))
{
@@ -2616,22 +2645,46 @@ 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
+ && (*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)));
diff --git a/gcc/sched-vis.c b/gcc/sched-vis.c
index 2dd20d0cd50..d3e8472b3be 100644
--- a/gcc/sched-vis.c
+++ b/gcc/sched-vis.c
@@ -31,6 +31,7 @@ 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 @@ 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,14 @@ get_visual_tbl_length ()
int n, n1;
char *s;
+ if (targetm.sched.use_dfa_pipeline_interface
+ && (*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");
@@ -815,7 +825,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)
diff --git a/gcc/target-def.h b/gcc/target-def.h
index 41ed37f2bc2..7d287a76b50 100644
--- a/gcc/target-def.h
+++ b/gcc/target-def.h
@@ -145,16 +145,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
diff --git a/gcc/target.h b/gcc/target.h
index 201bb2cba30..6d8103e1930 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -136,6 +136,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. */