build_automaton (continued)
6418 if (progress_flag )
6419 fprintf (stderr , " done/n");
6420 ticker_off (&NDFA_time );
6421 count_states_and_arcs (automaton, &states_num, &arcs_num);
6422 automaton->NDFA_states_num = states_num;
6423 automaton->NDFA_arcs_num = arcs_num;
6424 ticker_on (&NDFA_to_DFA_time );
6425 if (progress_flag )
6426 {
6427 if (automaton->corresponding_automaton_decl == NULL)
6428 fprintf (stderr , "Make anonymous DFA");
6429 else
6430 fprintf (stderr , "Make DFA `%s'",
6431 automaton->corresponding_automaton_decl->name);
6432 fprintf (stderr , " (1 dot is 100 new states):");
6433 }
count_states_and_arcs 计算指定自动机的状态及迁移的数目。
6387 static void
6388 count_states_and_arcs (automaton_t automaton, int *states_num, in genautomata.c
6389 int *arcs_num)
6390 {
6391 curr_counted_states_num = 0;
6392 curr_counted_arcs_num = 0;
6393 pass_states (automaton, incr_states_and_arcs_nums );
6394 *states_num = curr_counted_states_num ;
6395 *arcs_num = curr_counted_arcs_num ;
6396 }
5978 static void
5979 pass_states (automaton_t automaton, void (*applied_func) (state_t state)) in genautomata.c
5980 {
5981 curr_state_graph_pass_num ++;
5982 pass_state_graph (automaton->start_state, applied_func );
5983 }
上面在 6394 行, curr_state_graph_pass_num 确保每个状态将仅会被计算一次。在下面的 5966 行我们可以看到这一点。
5961 static void
5962 pass_state_graph (state_t start_state, void (*applied_func) (state_t state)) in genautomata.c
5963 {
5964 arc_t arc;
5965
5966 if (start_state->pass_num == curr_state_graph_pass_num )
5967 return ;
5968 start_state->pass_num = curr_state_graph_pass_num ;
5969 (*applied_func ) (start_state);
5970 for (arc = first_out_arc (start_state);
5971 arc != NULL;
5972 arc = next_out_arc (arc))
5973 pass_state_graph (arc->to_state, applied_func);
5974 }
对于每个状态,调用 incr_states_and_arcs_nums 。
6376 static void
6377 incr_states_and_arcs_nums (state_t state) in genautomata.c
6378 {
6379 arc_t arc;
6380
6381 curr_counted_states_num ++;
6382 for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
6383 curr_counted_arcs_num ++;
6384 }
现在是时候把 NDFA 转换为 DFA 了。继续看 build_automaton 。
build_automaton (continued)
6434 NDFA_to_DFA (automaton);
6435 if (progress_flag )
6436 fprintf (stderr , " done/n");
6437 ticker_off (&NDFA_to_DFA_time );
6438 count_states_and_arcs (automaton, &states_num, &arcs_num);
6439 automaton->DFA_states_num = states_num;
6440 automaton->DFA_arcs_num = arcs_num;
6441 if (!no_minimization_flag )
6442 {
6443 ticker_on (&minimize_time );
6444 if (progress_flag )
6445 {
6446 if (automaton->corresponding_automaton_decl == NULL)
6447 fprintf (stderr, "Minimize anonymous DFA...");
6448 else
6449 fprintf (stderr , "Minimize DFA `%s'...",
6450 automaton->corresponding_automaton_decl->name);
6451 }
6452 minimize_DFA (automaton);
6453 if (progress_flag )
6454 fprintf (stderr , "done/n");
6455 ticker_off (&minimize_time );
6456 count_states_and_arcs (automaton, &states_num, &arcs_num);
6457 automaton->minimal_DFA_states_num = states_num;
6458 automaton->minimal_DFA_arcs_num = arcs_num;
6459 }
6460 }
在这里转换 NDFA 到 DFA 的算法很简单。对于我们的例子,从 start_state 状态出发,可以迁移到 SA , SB 或 SC 状态。为了解决这个非确定性,我们构建了一个新状态 A’ , A’ = {SA ∪ SB ∪ SC} – 这意味着它是一个在状态 S 下由类别为 (A|B|C) 的指令所触发的组合状态,它具有所有从状态 SA , SB 及 SC 出发的迁移。看到这个从状态 S 到 A’ 的迁移,现在是确定性的。对所有具有非确定性迁移的状态重复上述步骤,直到不存在这样的状态。
为了更好地清楚这个算法,考虑以下自动机。
图 74 : NDFA 转换到 DFA 的例子,步骤 1
除了状态 S 以外,从每个状态出发,可以找到至少一个闭环 – 对于可行的芯片这是个必须条件,因为任意开放的节点意味着芯片将死在那一点上。并且注意到初始状态( S )不能有进入的迁移。这个自动机例子是一个 NDFA ,看到从状态 S 到状态 A1 的迁移是非确定性的。
图 75 : NDFA 转换到 DFA 的例子,步骤 2
在状态 A1 及 A2 上应用这个算法,我们可以得到上图。状态 A12 仍然是非确定性的,因为指令类别 ib 可以触发两个迁移。看到状态 A12 是从状态 A1 及 A2 构建的复合状态,现在我们不能确定其单元预订了。不过,我们不再需要单元预订,我们所需要的仅是状态及其之间的迁移。
图 76 : NDFA 转换到 DFA 的例子,步骤 3
又,合并状态 B1 及 B2 ,我们得到上图,不过这个状态仍然是非确定性的,因为 advance_cycle_insn_decl 将触发两个状态迁移。看到这个状态 B12 甚至不能在前面自动机生成过程中存在。
图 77 : NDFA 转换到 DFA 的例子,步骤 4
最后修改出的确定性自动机显示于上图。注意到这个确定性版本及非确定性版本,仅从指令发布机会的意义上而言,是相等的。
5917 static void
5918 NDFA_to_DFA (automaton_t automaton)
5919 {
5920 state_t start_state;
5921 state_t state;
5922 decl_t decl;
5923 vla_ptr_t state_stack;
5924 int i;
5925 int states_n;
5926
5927 VLA_PTR_CREATE (state_stack, 150, "state stack");
5928 /* Create the start state (empty state). */
5929 start_state = automaton->start_state;
5930 start_state->it_was_placed_in_stack_for_DFA_forming = 1;
5931 VLA_PTR_ADD (state_stack, start_state);
5932 states_n = 1;
5933 while (VLA_PTR_LENGTH (state_stack) != 0)
5934 {
5935 state = VLA_PTR (state_stack, VLA_PTR_LENGTH (state_stack) - 1);
5936 VLA_PTR_SHORTEN (state_stack, 1);
5937 form_arcs_marked_by_insn (state);
5938 for (i = 0; i < description ->decls_num; i++)
5939 {
5940 decl = description ->decls [i];
5941 if (decl->mode == dm_insn_reserv
5942 && create_composed_state
5943 (state, DECL_INSN_RESERV (decl)->arcs_marked_by_insn,
5944 &state_stack))
5945 {
5946 states_n++;
5947 if (progress_flag && states_n % 100 == 0)
5948 fprintf (stderr , ".");
5949 }
5950 }
5951 }
5952 VLA_PTR_DELETE (state_stack);
5953 }
记住对于非确定性自动机,在我们上面的例子中,将评估 define_insn_reservation 中的每个替代;而对于确定性自动机,将仅评估第一个合格的替代。从这之后,这将形成很大的区别。事实上,当替代以确定性方式来处理时,构建出的自动机已经就是确定性的。
5787 static void
5788 form_arcs_marked_by_insn (state_t state) in genautomata.c
5789 {
5790 decl_t decl;
5791 arc_t arc;
5792 int i;
5793
5794 for (i = 0; i < description ->decls_num; i++)
5795 {
5796 decl = description ->decls [i];
5797 if (decl->mode == dm_insn_reserv)
5798 DECL_INSN_RESERV (decl)->arcs_marked_by_insn = NULL;
5799 }
5800 for (arc = first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
5801 {
5802 if (arc->insn == NULL)
5803 abort ();
5804 arc->next_arc_marked_by_insn
5805 = arc->insn->insn_reserv_decl->arcs_marked_by_insn;
5806 arc->insn->insn_reserv_decl->arcs_marked_by_insn = arc;
5807 }
5808 }
在跨越发布包含替代的指令类别的状态中,为了把这些特殊的迁移与其它确定性迁移区分开来, form_arcs_marked_by_insn 将通过 next_arc_marked_by_insn 域链接这些迁移(以 arc 的形式)。
在非确定性的例子中,对于 start_state 将得到如下。
对于指令类别( E|F )
arcSF->next_arc_marked_by_insn = NULL (arcSF->to_state = stateSF)
arcSF->insn->insn_reserv_decl->arcs_marked_by_insn = arcSF
arcSE->next_arc_marked_by_insn = arcSF (arcSE->to_state = stateSE)
arcSE->insn->insn_reserv_decl->arcs_marked_by_insn = arcSE (最后的值)
对于指令类别( A|B|C )
arcSC->next_arc_marked_by_insn = NULL (arcSC->to_state = stateSC)
arcSC->insn->insn_reserv_decl->arcs_marked_by_insn = arcSC
arcSB->next_arc_marked_by_insn = arcSC (arcSB->to_state = stateSB)
arcSB->insn->insn_reserv_decl->arcs_marked_by_insn = arcSB
arcSA->next_arc_marked_by_insn = arcSB (arcSA->to_state = stateSA)
arcSA->insn->insn_reserv_decl->arcs_marked_by_insn = arcSA (最后的值)
(注意到上面的两部分被 state 的 arc 的 next_out_arc 域链接起来)
在确定性的例子中,对于 start_state 将得到如下。
对于指令类别 A
arcSA->next_arc_marked_by_insn = NULL (arcSA->to_state = stateSA)
arcSA->insn->insn_reserv_decl->arcs_marked_by_insn = arcSA
对于指令类别 E
arcSE->next_arc_marked_by_insn = NULL (arcSE->to_state = stateSE)
arcSE->insn->insn_reserv_decl->arcs_marked_by_insn = arcSE
(注意到上面的两部分被 state 的 arc 的 next_out_arc 域链接起来)
显示在下图, insn (x1|x2|x3) 代表在 define_insn_reservation 中具有三个替代: x1 , x2 及 x3 的指令类别。在图中两个 arcs_marked_by_insn 是对应不同 insn_reserv_decl 的域 – 对应 define_insn_reservations 模式的 decl 。
图 78 : 构建 DFA ,阶段 2
现在在 state_stack 里仅是 state_start 。对于确定性自动机, create_composed_state 是简单的,因为 next_arc_marked_by_insn 总是 NULL (参见 5853 行的检查)。它将把在 5382 行获取的 to_state 压入 state_stack 并返回。现在在 state_stack 里,是 SA , SE 。
在非确定性自动机的例子中,域 component_states 用于所谓的复合状态(例如,上图中的状态 A12 , B12 , xy )。对于具有替代 A , B , C 的指令类别来说,第一个参数 original_state 是 start_state ,而第二个参数 arcs_marked_by_insn 指向上图中的 arcs_marked_by_insn ,它是 insn_reserv_decl – define_insn_reservation 模式的 decl ,中的域。
5814 static int
5815 create_composed_state (state_t original_state, arc_t arcs_marked_by_insn, in genautomata.c
5816 vla_ptr_t *state_stack)
5817 {
5818 state_t state;
5819 alt_state_t alt_state, curr_alt_state;
5820 alt_state_t new_alt_state;
5821 arc_t curr_arc;
5822 arc_t next_arc;
5823 state_t state_in_table;
5824 state_t temp_state;
5825 alt_state_t canonical_alt_states_list;
5826 int alts_number;
5827 int new_state_p = 0;
5828
5829 if (arcs_marked_by_insn == NULL)
5830 return new_state_p;
5831 if (arcs_marked_by_insn->next_arc_marked_by_insn == NULL)
5832 state = arcs_marked_by_insn->to_state;
5833 else
5834 {
5835 if (!ndfa_flag )
5836 abort ();
5837 /* Create composed state. */
5838 state = get_free_state (0, arcs_marked_by_insn->to_state->automaton);
5839 curr_alt_state = NULL;
5840 for (curr_arc = arcs_marked_by_insn;
5841 curr_arc != NULL;
5842 curr_arc = curr_arc->next_arc_marked_by_insn)
5843 if (curr_arc->to_state->component_states == NULL)
5844 {
5845 new_alt_state = get_free_alt_state ();
5846 new_alt_state->next_alt_state = curr_alt_state;
5847 new_alt_state->state = curr_arc->to_state;
5848 curr_alt_state = new_alt_state;
5849 }
5850 else
5851 for (alt_state = curr_arc->to_state->component_states;
5852 alt_state != NULL;
5853 alt_state = alt_state->next_sorted_alt_state)
5854 {
5855 new_alt_state = get_free_alt_state ();
5856 new_alt_state->next_alt_state = curr_alt_state;
5857 new_alt_state->state = alt_state->state;
5858 if (alt_state->state->component_states != NULL)
5859 abort ();
5860 curr_alt_state = new_alt_state;
5861 }
5862 /* There are not identical sets in the alt state list. */
5863 canonical_alt_states_list = uniq_sort_alt_states (curr_alt_state);
5864 if (canonical_alt_states_list->next_sorted_alt_state == NULL)
5865 {
5866 temp_state = state;
5867 state = canonical_alt_states_list->state;
5868 free_state (temp_state);
5869 }
5870 else
5871 {
5872 state->component_states = canonical_alt_states_list;
5873 state_in_table = insert_state (state);
5874 if (state_in_table != state)
5875 {
5876 if (!state_in_table->it_was_placed_in_stack_for_DFA_forming)
5877 abort ();
5878 free_state (state);
5879 state = state_in_table;
5880 }
5881 else
5882 {
5883 if (state->it_was_placed_in_stack_for_DFA_forming)
5884 abort ();
5885 new_state_p = 1;
5886 for (curr_alt_state = state->component_states;
5887 curr_alt_state != NULL;
5888 curr_alt_state = curr_alt_state->next_sorted_alt_state)
5889 for (curr_arc = first_out_arc (curr_alt_state->state);
5890 curr_arc != NULL;
5891 curr_arc = next_out_arc (curr_arc))
5892 add_arc (state, curr_arc->to_state, curr_arc->insn, 1);
5893 }
5894 arcs_marked_by_insn->to_state = state;
5895 for (alts_number = 0,
5896 curr_arc = arcs_marked_by_insn->next_arc_marked_by_insn;
5897 curr_arc != NULL;
5898 curr_arc = next_arc)
5899 {
5900 next_arc = curr_arc->next_arc_marked_by_insn;
5901 remove_arc (original_state, curr_arc);
5902 alts_number++;
5903 }
5904 arcs_marked_by_insn->state_alts = alts_number;
5905 }
5906 }
5907 if (!state->it_was_placed_in_stack_for_DFA_forming)
5908 {
5909 state->it_was_placed_in_stack_for_DFA_forming = 1;
5910 VLA_PTR_ADD (*state_stack, state);
5911 }
5912 return new_state_p;
5913 }
在我们例子中, curr_alt_state 是一个链表,形如: curr_alt_state(SA)->next_alt_state(SB)-> next_alt_state(SC) 。然后这个链表被传递给 uniq_sort_alt_states ,这个函数排序 alt_states_list ,并从这个链表中移去重复的 alt_state 。在这里,对于我们的非确定性例子,这个链表没有改变。
在 5864 行,如果 next_sorted_alt_state 不是 NULL ,那么在 5872 行的 state 是新构建的,它必然不出现在 state_table 里,因此我们进入 5882 行。在 create_composed_state 中构建的数据显示如下图。
图 79 : 构建 DFA ,阶段 3
正如我们之前提及的,一旦构建了新状态,当前状态的所有替代的迁移目标,就被设置为这个新状态的迁移目标。然后当前状态,在理论上,可以确定性地迁移到这个新状态,注意到在图中 arcSA 被留下了,蓝色的域被修改了;而其它用于当前状态替代的 arc 都被移除了。接着,这个新状态将被压入 state_stack 。然后在这个状态上重复上面的步骤。直到 state_stack 中没有状态(即,没有状态具有非确定性迁移), NDFA_to_DFA 才退出。