9.5.8.2. Data initialization
Before building the automaton, resource is allocated first.
9416 static void
9417 generate (void) in genautomata.c
9418 {
9419 automata_num = split_argument ;
9420 if (description ->units_num < automata_num )
9421 automata_num = description ->units_num;
9422 initiate_states ();
9423 initiate_arcs ();
9424 initiate_automata_lists ();
9425 initiate_pass_states ();
9426 initiate_excl_sets ();
9427 initiate_presence_absence_pattern_sets ();
9428 automaton_generation_time = create_ticker ();
9429 create_automata ();
9430 ticker_off (&automaton_generation_time );
9431 }
split_argument holds the value of “-split” option of the automata generation command, which indicates the number of automatons generated. Of course it can’t be larger than the number of units.
As we have seen before, states of the automaton under creating describes the resource usage of every cycle for instructions’ execution. It is driven by instruction issue or cycle advance which now, after introducing pseudo advance_cycle_insn_decl , also can be regarded as instruction issue. So here, first, it needs to record declared CPU units into units_array – it is the resource with which instruction can be competed, and then allocates resource for the bitmap of state.
4221 static void
4222 initiate_states (void) in genautomata.c
4223 {
4224 decl_t decl;
4225 int i;
4226
4227 VLA_PTR_CREATE (units_container , description ->units_num, "units_container");
4228 units_array
4229 = (description ->decls_num && description ->units_num
4230 ? VLA_PTR_BEGIN (units_container ) : NULL);
4231 for (i = 0; i < description ->decls_num; i++)
4232 {
4233 decl = description ->decls [i];
4234 if (decl->mode == dm_unit)
4235 units_array [DECL_UNIT (decl)->unit_num] = DECL_UNIT (decl);
4236 }
4237 max_cycles_num = description ->max_insn_reserv_cycles;
4238 els_in_cycle_reserv
4239 = ((description ->units_num + sizeof (set_el_t) * CHAR_BIT - 1)
4240 / (sizeof (set_el_t) * CHAR_BIT));
4241 els_in_reservs = els_in_cycle_reserv * max_cycles_num ;
4242 curr_unique_state_num = 0;
4243 initiate_alt_states ();
4244 VLA_PTR_CREATE (free_states , 1500, "free states");
4245 state_table = htab_create (1500, state_hash, state_eq_p, (htab_del) 0);
4246 temp_reserv = alloc_empty_reserv_sets ();
4247 }
first_free_alt_state will point to list of freed alt_state, which will link alternatives tegother for certain state. It is first initialized as null in initiate_alt_states .
3669 static void
3670 initiate_alt_states (void) in genautomata.c
3671 {
3672 first_free_alt_state = NULL;
3673 }
set_el_t is typedef as “unsigned HOST_WIDE_INT”, and reserv_sets_t is typedef as the pointer type. Obvious the value of reserv_sets_t represents the reservations of function units. els_in_reservs is calculated at line 4241 in initiate_states , in related with: max_cycles_num , and els_in_cycle_reserv 。
3744 static reserv_sets_t
3745 alloc_empty_reserv_sets (void) in genautomata.c
3746 {
3747 reserv_sets_t result;
3748
3749 obstack_blank (&irp , els_in_reservs * sizeof (set_el_t));
3750 result = (reserv_sets_t) obstack_base (&irp );
3751 obstack_finish (&irp );
3752 memset (result, 0, els_in_reservs * sizeof (set_el_t));
3753 return result;
3754 }
first_free_arc will point to list of freed arc, which records the state transition.
4368 static void
4369 initiate_arcs (void) in genautomata.c
4370 {
4371 first_free_arc = NULL;
4372 }
Similarly, first_free_automata_list_el will point to list of freed automaton. And all automaton objects will be kept in hashtable to ensure its unique.
4474 static void
4475 initiate_automata_lists (void) in genautomata.c
4476 {
4477 first_free_automata_list_el = NULL;
4478 automata_list_table = htab_create (1500, automata_list_hash,
4479 automata_list_eq_p, (htab_del) 0);
4480 }
Static variable curr_state_graph_pass_num will be used to record current number of passing graph of states.
5986 static void
5987 initiate_pass_states (void) in genautomata.c
5988 {
5989 curr_state_graph_pass_num = 0;
5990 }
And for those insn refered in exclusion_set, allocate resource for the bitmap for recording exclusion set. Here it uses storage of obstack, which is described in detail in related sections for the front-end. In short, obstack is the block managed by GCC.
4544 static void
4545 initiate_excl_sets (void) in genautomata.c
4546 {
4547 decl_t decl;
4548 reserv_sets_t unit_excl_set;
4549 unit_set_el_t el;
4550 int i;
4551
4552 obstack_blank (&irp , els_in_cycle_reserv * sizeof (set_el_t));
4553 excl_set = (reserv_sets_t) obstack_base (&irp );
4554 obstack_finish (&irp );
4555 obstack_blank (&irp , description ->units_num * sizeof (reserv_sets_t));
4556 unit_excl_set_table = (reserv_sets_t *) obstack_base (&irp );
4557 obstack_finish (&irp );
4558 /* Evaluate unit exclusion sets. */
4559 for (i = 0; i < description ->decls_num; i++)
4560 {
4561 decl = description ->decls [i];
4562 if (decl->mode == dm_unit)
4563 {
4564 obstack_blank (&irp , els_in_cycle_reserv * sizeof (set_el_t));
4565 unit_excl_set = (reserv_sets_t) obstack_base (&irp );
4566 obstack_finish (&irp );
4567 memset (unit_excl_set, 0, els_in_cycle_reserv * sizeof (set_el_t));
4568 for (el = DECL_UNIT (decl)->excl_list;
4569 el != NULL;
4570 el = el->next_unit_set_el)
4571 {
4572 SET_BIT (unit_excl_set, el->unit_decl->unit_num);
4573 el->unit_decl->in_set_p = TRUE;
4574 }
4575 unit_excl_set_table [DECL_UNIT (decl)->unit_num] = unit_excl_set;
4576 }
4577 }
4578 }
Line 4552 to 4554 allocates memory for excl_set , which will be set by get_excl_set . Line 4555~4557 allocates memory for unit_excl_set_table , note that reserv_sets_t is the pointer type of set_el_t.
Above in 4th Loop of Processing Decls – DECL_EXCL , it integrates all exclude set of the unit tegother, which is used here. Loop at line 4568 uses this information of exclude-set to set unit_excl_set_table .
Also unit_presence_set_table , unit_presence_set_table , unit_absence_set_table and unit_final_absence_set_table are also set by the similar way.
4653 static void
4654 initiate_presence_absence_pattern_sets (void) in genautomata.c
4655 {
4656 decl_t decl;
4657 int i;
4658
4659 obstack_blank (&irp , description ->units_num * sizeof (pattern_reserv_t));
4660 unit_presence_set_table = (pattern_reserv_t *) obstack_base (&irp );
4661 obstack_finish (&irp );
4662 obstack_blank (&irp , description ->units_num * sizeof (pattern_reserv_t));
4663 unit_final_presence_set_table = (pattern_reserv_t *) obstack_base (&irp );
4664 obstack_finish (&irp );
4665 obstack_blank (&irp , description ->units_num * sizeof (pattern_reserv_t));
4666 unit_absence_set_table
4667
4668 = (pattern_reserv_t *) obstack_base (&irp );
4669 obstack_finish (&irp );
4670 obstack_blank (&irp , description ->units_num * sizeof (pattern_reserv_t));
4671 unit_final_absence_set_table = (pattern_reserv_t *) obstack_base (&irp );
4672 obstack_finish (&irp );
4673 /* Evaluate unit presence/absence sets. */
4674 for (i = 0; i < description ->decls_num; i++)
4675 {
4676 decl = description ->decls [i];
4677 if (decl->mode == dm_unit)
4678 {
4679 unit_presence_set_table [DECL_UNIT (decl)->unit_num]
4680 = form_reserv_sets_list (DECL_UNIT (decl)->presence_list);
4681 unit_final_presence_set_table [DECL_UNIT (decl)->unit_num]
4682 = form_reserv_sets_list (DECL_UNIT (decl)->final_presence_list);
4683 unit_absence_set_table [DECL_UNIT (decl)->unit_num]
4684 = form_reserv_sets_list (DECL_UNIT (decl)->absence_list);
4685 unit_final_absence_set_table [DECL_UNIT (decl)->unit_num]
4686 = form_reserv_sets_list (DECL_UNIT (decl)->final_absence_list);
4687 }
4688 }
4689 }
The value of automata_num comes from the “-split” option of automata generation command. However, it is not supported in this version, see initiate_automaton_gen , line 9664.
6804 static void
6805 create_automata (void) in genautomata.c
6806 {
6807 automaton_t curr_automaton;
6808 automaton_t prev_automaton;
6809 decl_t decl;
6810 int curr_automaton_num;
6811 int i;
6812
6813 if (automata_num != 0)
6814 {
…
6830 }
6831 else
6832 {
6833 curr_automaton_num = 0;
6834 prev_automaton = NULL;
6835 for (i = 0; i < description ->decls_num; i++)
6836 {
6837 decl = description ->decls [i];
6838 if (decl->mode == dm_automaton
6839 && DECL_AUTOMATON (decl)->automaton_is_used)
6840 {
6841 curr_automaton = create_node (sizeof (struct automaton));
6842 curr_automaton->ainsn_list = create_ainsns ();
6843 curr_automaton->corresponding_automaton_decl
6844 = DECL_AUTOMATON (decl);
6845 curr_automaton->next_automaton = NULL;
6846 DECL_AUTOMATON (decl)->corresponding_automaton = curr_automaton;
6847 curr_automaton->automaton_order_num = curr_automaton_num;
6848 if (prev_automaton == NULL)
6849 description ->first_automaton = curr_automaton;
6850 else
6851 prev_automaton->next_automaton = curr_automaton;
6852 curr_automaton_num++;
6853 prev_automaton = curr_automaton;
6854 }
6855 }
6856 if (curr_automaton_num == 0)
6857 {
6858 curr_automaton = create_node (sizeof (struct automaton));
6859 curr_automaton->ainsn_list = create_ainsns ();
6860 curr_automaton->corresponding_automaton_decl = NULL;
6861 curr_automaton->next_automaton = NULL;
6862 description ->first_automaton = curr_automaton;
6863 }
6864 units_to_automata_distr ();
6865 }
Loop at line 6835 first create automaton object for all automata, these objects have below definition.
1224 struct automaton in genautomata.c
1225 {
1226 /* The following field value is the list of insn declarations for
1227 given automaton. */
1228 ainsn_t ainsn_list;
1229 /* The following field value is the corresponding automaton
1230 declaration. This field is not NULL only if the automatic
1231 partition on automata is not used. */
1232 struct automaton_decl *corresponding_automaton_decl;
1233 /* The following field value is the next automaton. */
1234 automaton_t next_automaton;
1235 /* The following field is start state of FA. There are not unit
1236 reservations in the state. */
1237 state_t start_state;
1238 /* The following field value is number of equivalence classes of
1239 insns (see field `insn_equiv_class_num' in
1240 `insn_reserv_decl'). */
1241 int insn_equiv_classes_num;
1242 /* The following field value is number of states of final DFA. */
1243 int achieved_states_num;
1244 /* The following field value is the order number (0, 1, ...) of
1245 given automaton. */
1246 int automaton_order_num;
1247 /* The following fields contain statistics information about
1248 building automaton. */
1249 int NDFA_states_num, DFA_states_num;
1250 /* The following field value is defined only if minimization of DFA
1251 is used. */
1252 int minimal_DFA_states_num;
1253 int NDFA_arcs_num, DFA_arcs_num;
1254 /* The following field value is defined only if minimization of DFA
1255 is used. */
1256 int minimal_DFA_arcs_num;
1257 /* The following two members refer for two table state x ainsn ->
1258 int. */
1259 state_ainsn_table_t trans_table;
1260 state_ainsn_table_t state_alts_table;
1261 /* The following member value is maximal value of min issue delay
1262 for insns of the automaton. */
1263 int max_min_delay;
1264 /* Usually min issue delay is small and we can place several (2, 4,
1265 8) elements in one vector element. So the compression factor can
1266 be 1 (no compression), 2, 4, 8. */
1267 int min_issue_delay_table_compression_factor;
1268 };
205 typedef struct automaton *automaton_t ; in genautomata.c
In automaton definition, field ainsn_list records all instructions that drive this automaton from one state to another. And we will see later, ainsn_list also records the states involved as automaton growing. It is the most important field in automaton definition. At line 6842, create_ainsns creates this list for each automaton.
6746 static ainsn_t
6747 create_ainsns (void) in genautomata.c
6748 {
6749 decl_t decl;
6750 ainsn_t first_ainsn;
6751 ainsn_t curr_ainsn;
6752 ainsn_t prev_ainsn;
6753 int i;
6754
6755 first_ainsn = NULL;
6756 prev_ainsn = NULL;
6757 for (i = 0; i < description ->decls_num; i++)
6758 {
6759 decl = description ->decls [i];
6760 if (decl->mode == dm_insn_reserv)
6761 {
6762 curr_ainsn = create_node (sizeof (struct ainsn ));
6763 curr_ainsn->insn_reserv_decl = DECL_INSN_RESERV (decl);
6764 curr_ainsn->important_p = FALSE;
6765 curr_ainsn->next_ainsn = NULL;
6766 if (prev_ainsn == NULL)
6767 first_ainsn = curr_ainsn;
6768 else
6769 prev_ainsn->next_ainsn = curr_ainsn;
6770 prev_ainsn = curr_ainsn;
6771 }
6772 }
6773 return first_ainsn;
6774 }
At line 6762, ainsn has following definition. See that it has one-to-one relationship with define_insn_reservation.
1179 struct ainsn in genautomata.c
1180 {
1181 /* The following field value is the corresponding insn declaration
1182 of description. */
1183 struct insn_reserv_decl *insn_reserv_decl;
1184 /* The following field value is the next insn declaration for an
1185 automaton. */
1186 ainsn_t next_ainsn;
1187 /* The following field is states which characterize automaton unit
1188 reservations of the instruction. The value can be NULL only if it
1189 is special insn `cycle advancing'. */
1190 alt_state_t alt_states;
1191 /* The following field is sorted list of states which characterize
1192 automaton unit reservations of the instruction. The value can be
1193 NULL only if it is special insn `cycle advancing'. */
1194 alt_state_t sorted_alt_states;
1195 /* The following field refers the next automaton insn with
1196 the same reservations. */
1197 ainsn_t next_same_reservs_insn;
1198 /* The following field is flag of the first automaton insn with the
1199 same reservations in the declaration list. Only arcs marked such
1200 insn is present in the automaton. This significantly decreases
1201 memory requirements especially when several automata are
1202 formed. */
1203 char first_insn_with_same_reservs;
1204 /* The following member has nonzero value if there is arc from state of
1205 the automaton marked by the ainsn. */
1206 char arc_exists_p;
1207 /* Cyclic list of insns of an equivalence class is formed with the
1208 aid of the following field. */
1209 ainsn_t next_equiv_class_insn;
1210 /* The following field value is nonzero if the insn declaration is
1211 the first insn declaration with given equivalence number. */
1212 char first_ainsn_with_given_equialence_num;
1213 /* The following field is number of class of equivalence of insns.
1214 It is necessary because many insns may be equivalent with the
1215 point of view of pipeline hazards. */
1216 int insn_equiv_class_num;
1217 /* The following member value is TRUE if there is an arc in the
1218 automaton marked by the insn into another state. In other
1219 words, the insn can change the state of the automaton. */
1220 int important_p;
1221 };
For certain define_insn_reservation pattern, it may have more than one plan of unit reservation, which means from certain state by different plan will lead to different states. Field alt_states will records these different state transitions from the same start state. In this version, if no automaton is defined in machine description file, all cpu units will be assigned to the single default automaton, else the assignment has been done in machine description file. units_to_automata_distr does the distribution.
6778 static void
6779 units_to_automata_distr (void) in genautomata.c
6780 {
6781 decl_t decl;
6782 int i;
6783
6784 for (i = 0; i < description ->decls_num; i++)
6785 {
6786 decl = description ->decls [i];
6787 if (decl->mode == dm_unit)
6788 {
6789 if (DECL_UNIT (decl)->automaton_decl == NULL
6790 || (DECL_UNIT (decl)->automaton_decl->corresponding_automaton
6791 == NULL))
6792 /* Distribute to the first automaton. */
6793 DECL_UNIT (decl)->corresponding_automaton_num = 0;
6794 else
6795 DECL_UNIT (decl)->corresponding_automaton_num
6796 = (DECL_UNIT (decl)->automaton_decl
6797 ->corresponding_automaton->automaton_order_num);
6798 }
6799 }
6800 }
In fact distribution is done by setting corresponding_automaton_num field of the unit object.
9.5.8.3. Build bitmap and prepare data for state
All resources have been allocated. It is time to fill in bitmaps and create data to accommodate alternatives. Notice that even only one candidate present, this data still need created for purpose of uniformly handling data. Alternatives just are branches triggered simultaneously from certain state; it is not different from non-alternative in nature.
create_automata (continued)
6866 NDFA_time = create_ticker ();
6867 ticker_off (&NDFA_time );
6868 NDFA_to_DFA_time = create_ticker ();
6869 ticker_off (&NDFA_to_DFA_time );
6870 minimize_time = create_ticker ();
6871 ticker_off (&minimize_time );
6872 equiv_time = create_ticker ();
6873 ticker_off (&equiv_time );
6874 for (curr_automaton = description ->first_automaton;
6875 curr_automaton != NULL;
6876 curr_automaton = curr_automaton->next_automaton)
6877 {
6878 if (progress_flag )
6879 {
6880 if (curr_automaton->corresponding_automaton_decl == NULL)
6881 fprintf (stderr , "Prepare anonymous automaton creation ... ");
6882 else
6883 fprintf (stderr , "Prepare automaton `%s' creation...",
6884 curr_automaton->corresponding_automaton_decl->name);
6885 }
6886 create_alt_states (curr_automaton);
6887 form_ainsn_with_same_reservs (curr_automaton);
6888 if (progress_flag )
6889 fprintf (stderr , "done/n");
6890 build_automaton (curr_automaton);
6891 enumerate_states (curr_automaton);
6892 ticker_on (&equiv_time );
6893 set_insn_equiv_classes (curr_automaton);
6894 ticker_off (&equiv_time );
6895 }
6896 }
As we have seen before, define_insn_reservation defines the resource usage in every cycle, and bitmaps have been allocated to record CPU units usage per cycle per insn. When scheduling instruction, it will tell whether the instruction competes for the same resource with those already scheduled, and this is the important for making clever and efficient scheduler. create_alt_states creates data for alternatives and fills the bitmaps for every alternative.
5589 static void
5590 create_alt_states (automaton_t automaton) in genautomata.c
5591 {
5592 struct insn_reserv_decl *reserv_decl;
5593
5594 for (curr_ainsn = automaton->ainsn_list;
5595 curr_ainsn != NULL;
5596 curr_ainsn = curr_ainsn ->next_ainsn)
5597 {
5598 reserv_decl = curr_ainsn ->insn_reserv_decl;
5599 if (reserv_decl != DECL_INSN_RESERV (advance_cycle_insn_decl ))
5600 {
5601 curr_ainsn ->alt_states = NULL;
5602 process_alts_for_forming_states (reserv_decl->transformed_regexp,
5603 automaton, 0);
5604 curr_ainsn ->sorted_alt_states
5605 = uniq_sort_alt_states (curr_ainsn ->alt_states);
5606 }
5607 }
5608 }
Above the regexp of define_insn_reservation has been transformed to move “|” to outmost, no “|” is expected inside alternatives. That is no alternative should be found within another alternative. Below function bases on this assumption (refer to line 5577).
5556 static void
5557 process_alts_for_forming_states (regexp_t regexp, in genautomata.c
5558 automaton_t automaton, int inside_oneof_p)
5559 {
5560 int i;
5561
5562 if (regexp->mode != rm_oneof)
5563 {
5564 alt_state_being_formed = get_free_alt_state ();
5565 state_being_formed = get_free_state (1, automaton);
5566 alt_state_being_formed ->state = state_being_formed ;
5567 /* We inserts in reverse order but we process alternatives also
5568 i n reverse order. So we have the same order of alternative
5569 as in the description. */
5570 alt_state_being_formed ->next_alt_state = curr_ainsn ->alt_states;
5571 curr_ainsn ->alt_states = alt_state_being_formed ;
5572 (void) process_seq_for_forming_states (regexp, automaton, 0);
5573 finish_forming_alt_state (alt_state_being_formed , automaton);
5574 }
5575 else
5576 {
5577 if (inside_oneof_p)
5578 abort ();
5579 /* We processes it in reverse order to get list with the same
5580 order as in the description. See also the previous
5581 commentary. */
5582 for (i = REGEXP_ONEOF (regexp)->regexps_num - 1; i >= 0; i--)
5583 process_alts_for_forming_states (REGEXP_ONEOF (regexp)->regexps [i],
5584 automaton, 1);
5585 }
5586 }
Above, at line 5564, alt_state_being_formed is an object of alt_state which has following definition. The data forms a link per define_insn_reservation, the state field records the data of first alternative, and next_alt_state links other alternatives. next_sorted_alt_state holds sorted alternatives data which is used to distinct different define_insn_reservation.
1165 struct alt_state in genautomata.c
1166 {
1167 /* The following field is a deterministic state which characterizes
1168 unit reservations of the instruction. */
1169 state_t state ;
1170 /* The following field refers to the next state which characterizes
1171 unit reservations of the instruction. */
1172 alt_state_t next_alt_state;
1173 /* The following field refers to the next state in sorted list. */
1174 alt_state_t next_sorted_alt_state;
1175 };
And at line 1169, state_t is typedef as state * which defined as below. Initially, every define_insn_reservation is associated with a state per alternative. The reservs field at line 1085 in state records resource usage for every cycle.
1078 struct state in genautomata.c
1079 {
1080 /* The following member value is nonzero if there is a transition by
1081 cycle advancing. */
1082 int new_cycle_p;
1083 /* The following field is list of processor unit reservations on
1084 each cycle. */
1085 reserv_sets_t reservs;
1086 /* The following field is unique number of given state between other
1087 states. */
1088 int unique_num;
1089 /* The following field value is automaton to which given state
1090 belongs. */
1091 automaton_t automaton;
1092 /* The following field value is the first arc output from given
1093 state. */
1094 arc_t first_out_arc;
1095 /* The following field is used to form NDFA. */
1096 char it_was_placed_in_stack_for_NDFA_forming;
1097 /* The following field is used to form DFA. */
1098 char it_was_placed_in_stack_for_DFA_forming;
1099 /* The following field is used to transform NDFA to DFA and DFA
1100 minimization. The field value is not NULL if the state is a
1101 compound state. In this case the value of field `unit_sets_list'
1102 is NULL. All states in the list are in the hash table. The list
1103 is formed through field `next_sorted_alt_state'. We should
1104 support only one level of nesting state. */
1105 alt_state_t component_states;
1106 /* The following field is used for passing graph of states. */
1107 int pass_num;
1108 /* The list of states belonging to one equivalence class is formed
1109 with the aid of the following field. */
1110 state_t next_equiv_class_state;
1111 /* The two following fields are used during minimization of a finite
1112 state automaton. */
1113 int equiv_class_num_1, equiv_class_num_2;
1114 /* The following field is used during minimization of a finite state
1115 automaton. The field value is state corresponding to equivalence
1116 class to which given state belongs. */
1117 state_t equiv_class_state;
1118 /* The following field value is the order number of given state.
1119 The states in final DFA is enumerated with the aid of the
1120 following field. */
1121 int order_state_num;
1122 /* This member is used for passing states for searching minimal
1123 delay time. */
1124 int state_pass_num;
1125 /* The following member is used to evaluate min issue delay of insn
1126 for a state. */
1127 int min_insn_issue_delay;
1128 /* The following member is used to evaluate max issue rate of the
1129 processor. The value of the member is maximal length of the path
1130 from given state no containing arcs marked by special insn `cycle
1131 advancing'. */
1132 int longest_path_length;
1133 };
process_seq_for_forming_states builds the bitmap of unit reservation for every alternative in current cycle (here is cycle 0).
5484 static int
5485 process_seq_for_forming_states (regexp_t regexp, automaton_t automaton, in genautomata.c
5486 int curr_cycle)
5487 {
5488 int i;
5489
5490 if (regexp == NULL)
5491 return curr_cycle;
5492 else if (regexp->mode == rm_unit)
5493 {
5494 if (REGEXP_UNIT (regexp)->unit_decl->corresponding_automaton_num
5495 == automaton->automaton_order_num)
5496 set_state_reserv (state_being_formed , curr_cycle,
5497 REGEXP_UNIT (regexp)->unit_decl->unit_num);
5498 return curr_cycle;
5499 }
5500 else if (regexp->mode == rm_sequence)
5501 {
5502 for (i = 0; i < REGEXP_SEQUENCE (regexp)->regexps_num; i++)
5503 curr_cycle
5504 = process_seq_for_forming_states
5505 (REGEXP_SEQUENCE (regexp)->regexps [i], automaton, curr_cycle) + 1;
5506 return curr_cycle;
5507 }
5508 else if (regexp->mode == rm_allof)
5509 {
5510 int finish_cycle = 0;
5511 int cycle;
5512
5513 for (i = 0; i < REGEXP_ALLOF (regexp)->regexps_num; i++)
5514 {
5515 cycle = process_seq_for_forming_states (REGEXP_ALLOF (regexp)
5516 ->regexps [i],
5517 automaton, curr_cycle);
5518 if (finish_cycle < cycle)
5519 finish_cycle = cycle;
5520 }
5521 return finish_cycle;
5522 }
5523 else
5524 {
5525 if (regexp->mode != rm_nothing)
5526 abort ();
5527 return curr_cycle;
5528 }
5529 }
The bitmap of unit reservation is filled by set_state_reser v at line 5496. The bitmap is indexed by CPU cycle and unit_num . The bitmap is represented by state_being_formed which is assigned to alt_state_being_formed ->state at line 5566.
4160 static void
4161 set_state_reserv (state_t state, int cycle_num, int unit_num) in genautomata.c
4162 {
4163 set_unit_reserv (state->reservs, cycle_num, unit_num);
4164 }
3826 static void
3827 set_unit_reserv (reserv_sets_t reservs, int cycle_num, int unit_num)
3828 {
3829 if (cycle_num >= max_cycles_num )
3830 abort ();
3831 SET_BIT (reservs, cycle_num * els_in_cycle_reserv
3832 * sizeof (set_el_t) * CHAR_BIT + unit_num);
3833 }
Above, els_in_cycle_reserv is initialized in initiate_states at line 4238. It is the size of reservs . reservs is the bitmap to record the unit reservation in cycles. And notice that unit_num here comes from the field unit_num of the decl of define_cpu_unit, which is unique sequence number assigned in gen_unit .
Back to process_alts_for_forming_states , alt_state_being_formed is inserted into state_table by finish_forming_alt_state .
5533 static void
5534 finish_forming_alt_state (alt_state_t alt_state, in genautomata.c
5535 automaton_t automaton ATTRIBUTE_UNUSED)
5536 {
5537 state_t state_in_table;
5538 state_t corresponding_state;
5539
5540 corresponding_state = alt_state->state;
5541 state_in_table = insert_state (corresponding_state);
5542 if (state_in_table != corresponding_state)
5543 {
5544 free_state (corresponding_state);
5545 alt_state->state = state_in_table;
5546 }
5547 }
After building the bitmaps of current cycle, form_ainsn_with_same_reservs is invoked to link all instructions using the same unit reservation tegother. For those instructions having the same unit reservation, first_insns records the first one found, and last_insns records the last one found in the set. And those in first_insns have first_insn_with_same_reservs set. Besides, pseudo instruction advance_cycle_insn_decl always creates a seperate set as this instruction always advance CPU cycles.
After building the bitmaps for current cycle, form_ainsn_with_same_reservs traverses all ainsn objects which represent define_insn_reservation in the same automaton. Varray first_insns records ainsns using different units’ reservation, and at line 5654 it can see that last_insns is basically the same as first_insns , except finding another ainsn using the same units’ reservation, at the point these ainsns are linked via next_same_reservs_insn to form a queue, last_insns refers to the last found ainsn object.
Note that among ainsns using the same units’ reservation, only the first one found has first_insn_with_same_reservs set. Besides, pseduo instructuion advance_cycle_insn_decl always forms a single set, as it always advances CPU cycle.
5617 static void
5618 form_ainsn_with_same_reservs (automaton_t automaton) in genautomata.c
5619 {
5620 ainsn_t curr_ainsn;
5621 size_t i;
5622 vla_ptr_t first_insns;
5623 vla_ptr_t last_insns;
5624
5625 VLA_PTR_CREATE (first_insns, 150, "first insns with the same reservs");
5626 VLA_PTR_CREATE (last_insns, 150, "last insns with the same reservs");
5627 for (curr_ainsn = automaton->ainsn_list;
5628 curr_ainsn != NULL;
5629 curr_ainsn = curr_ainsn->next_ainsn)
5630 if (curr_ainsn->insn_reserv_decl
5631 == DECL_INSN_RESERV (advance_cycle_insn_decl ))
5632 {
5633 curr_ainsn->next_same_reservs_insn = NULL;
5634 curr_ainsn->first_insn_with_same_reservs = 1;
5635 }
5636 else
5637 {
5638 for (i = 0; i < VLA_PTR_LENGTH (first_insns); i++)
5639 if (alt_states_eq
5640 (curr_ainsn->sorted_alt_states,
5641 ((ainsn_t) VLA_PTR (first_insns, i))->sorted_alt_states))
5642 break ;
5643 curr_ainsn->next_same_reservs_insn = NULL;
5644 if (i < VLA_PTR_LENGTH (first_insns))
5645 {
5646 curr_ainsn->first_insn_with_same_reservs = 0;
5647 ((ainsn_t) VLA_PTR (last_insns, i))->next_same_reservs_insn
5648 = curr_ainsn;
5649 VLA_PTR (last_insns, i) = curr_ainsn;
5650 }
5651 else
5652 {
5653 VLA_PTR_ADD (first_insns, curr_ainsn);
5654 VLA_PTR_ADD (last_insns, curr_ainsn);
5655 curr_ainsn->first_insn_with_same_reservs = 1;
5656 }
5657 }
5658 VLA_PTR_DELETE (first_insns);
5659 VLA_PTR_DELETE (last_insns);
5660 }
So we can get following data at this step. At tail of the function, first and last will be deleted, but the lists are kept.
figure 72 : grouping instruction into equivalent class, stage 1