9.6.4. 输出自动机数据
在自动机的生成一节,我们已经看到在自动机的产生过程中,构建了许多数据。现在是时候为这些数据输出代码了。
9867 void
9868 write_automata (void) ingenautomata.c
9869 {
9870 if (progress_flag)
9871 fprintf (stderr, "done\n");
9872 if (have_error)
9873 fatal ("Errors in DFAdescription");
9874 ticker_on (&all_time);
9875 output_time = create_ticker ();
9876 if (progress_flag)
9877 fprintf (stderr, "Forming andoutputting automata tables...");
9878 output_dfa_max_issue_rate();
9879 output_tables();
9880 if (progress_flag)
9881 {
9882 fprintf (stderr, "done\n");
9883 fprintf (stderr, "Output functions towork with automata...");
9884 }
在9878行,output_dfa_max_issue_rate确定max_dfa_issue_rate的值,这个变量通过宏MAX_DFA_ISSUE_RATE来访问。其值等于在define_insn_reservation中描述的所有指令,这些指令可以在同一个处理器周期内发布。
7090 static void
7091 output_dfa_max_issue_rate (void) ingenautomata.c
7092 {
7093 automaton_tautomaton;
7094
7095 if (UNDEFINED_LONGEST_PATH_LENGTH ==ON_THE_PATH || ON_THE_PATH >= 0)
7096 abort ();
7097 max_dfa_issue_rate = 0;
7098 for(automaton = description->first_automaton;
7099 automaton != NULL;
7100 automaton = automaton->next_automaton)
7101 pass_states(automaton, process_state_longest_path_length);
7102 fprintf (output_file, "\nint %s = %d;\n",
7103 MAX_DFA_ISSUE_RATE_VAR_NAME, max_dfa_issue_rate);
7104 }
上面UNDEFINED_LONGEST_PATH_LENGTH被定义为1,ON_THE_PATH被定义为2。
7072 static void
7073 process_state_longest_path_length (state_t state) ingenautomata.c
7074 {
7075 int value;
7076
7077 value = longest_path_length(state);
7078 if (value > max_dfa_issue_rate)
7079 max_dfa_issue_rate = value;
7080 }
我们已经看到在这里指令发布驱动自动机。并且伪指令advance_cycle_insn_decl推进CPU一个周期。因此longest_path_length找出可以在一个周期内1的最大指令数。这个值在上面7079行被保存入max_dfa_issue_rate。
7034 static int
7035 longest_path_length (state_tstate) ingenautomata.c
7036 {
7037 arc_t arc;
7038 int length, result;
7039
7040 if (state->longest_path_length ==ON_THE_PATH)
7041 /* We don'texpect the path cycle here. Our graph may contain
7042 only cycles with one state on the pathnot containing `cycle
7043 advance' arcs -- see comment below. */
7044 abort ();
7045 else if (state->longest_path_length !=UNDEFINED_LONGEST_PATH_LENGTH)
7046 /* We alreadyvisited the state. */
7047 returnstate->longest_path_length;
7048
7049 result = 0;
7050 for (arc =first_out_arc (state); arc != NULL; arc = next_out_arc (arc))
7051 /* Ignore cyclescontaining one state and `cycle advance' arcs. */
7052 if (arc->to_state != state
7053 &&(arc->insn->insn_reserv_decl
7054 != DECL_INSN_RESERV (advance_cycle_insn_decl)))
7055 {
7056 length = longest_path_length(arc->to_state);
7057 if (length > result)
7058 result = length;
7059 }
7060 state->longest_path_length = result + 1;
7061 returnresult;
7062 }
9.6.4.1. 输出表
正如在绝大多数自动机里,表驱动通常能给出期望的性能,在这里产生的自动机也同样是表驱动的。函数output_tables为这个自动机产生表。
8077 static void
8078 output_tables (void) ingenautomata.c
8079 {
8080 automaton_tautomaton;
8081
8082 #ifndef NDEBUG
8083 locked_states_num = 0;
8084 #endif
8085 initiate_min_issue_delay_pass_states ();
8086 for(automaton = description->first_automaton;
8087 automaton != NULL;
8088 automaton = automaton->next_automaton)
8089 {
8090 output_translate_vect(automaton);
8091 output_trans_table (automaton);
8092 fprintf (output_file, "\n#if%s\n", AUTOMATON_STATE_ALTS_MACRO_NAME);
8093 output_state_alts_table(automaton);
8094 fprintf (output_file, "\n#endif /* #if%s */\n\n",
8095 AUTOMATON_STATE_ALTS_MACRO_NAME);
8096 output_min_issue_delay_table(automaton);
8097 output_dead_lock_vect(automaton);
8098 fprintf (output_file, "\n#if%s\n\n", CPU_UNITS_QUERY_MACRO_NAME);
8099 output_reserved_units_table(automaton);
8100 fprintf (output_file, "\n#endif /* #if%s */\n\n",
8101 CPU_UNITS_QUERY_MACRO_NAME);
8102 }
8103 fprintf (output_file, "\n#define %s %d\n\n",ADVANCE_CYCLE_VALUE_NAME,
8104 DECL_INSN_RESERV (advance_cycle_insn_decl)->insn_num);
8105 }
9.6.4.1.1. 输出等效指令集表
在上面的8085行,initiate_min_issue_delay_pass_states把curr_state_pass_num初始化为0。我们已经知道自动机由等效指令类别的指令集,而不是单个指令所驱动。通常,给定某个指令编码(指令的识别符),需要找出所从属的等效类别。在自动机的生成一节,我们已经找出这个关系。这需要一个表来把外部的指令编号映射到内部的指令编号(实际是等效类别的编号)。
7439 static void
7440 output_translate_vect (automaton_t automaton) ingenautomata.c
7441 {
7442 ainsn_t ainsn;
7443 int insn_value;
7444 vla_hwint_t translate_vect;
7445
7446 VLA_HWINT_CREATE (translate_vect, 250,"translate vector");
7447 VLA_HWINT_EXPAND (translate_vect, description->insns_num);
7448 for(insn_value = 0; insn_value < description->insns_num; insn_value++)
7449 /* Undefinedvalue */
7450 VLA_HWINT (translate_vect, insn_value) =automaton->insn_equiv_classes_num;
7451 for (ainsn = automaton->ainsn_list; ainsn != NULL;ainsn = ainsn->next_ainsn)
7452 VLA_HWINT (translate_vect, ainsn->insn_reserv_decl->insn_num)
7453 = ainsn->insn_equiv_class_num;
7454 fprintf (output_file,
7455 "/* Vector translating externalinsn codes to internal ones.*/\n");
7456 fprintf (output_file, "static const ");
7457 output_range_type(output_file,0, automaton->insn_equiv_classes_num);
7458 fprintf (output_file, " ");
7459 output_translate_vect_name(output_file,automaton);
7460 fprintf (output_file, "[] ATTRIBUTE_UNUSED ={\n");
7461 output_vect(VLA_HWINT_BEGIN (translate_vect),
7462 VLA_HWINT_LENGTH (translate_vect));
7463 fprintf (output_file, "};\n\n");
7464 VLA_HWINT_DELETE (translate_vect);
7465 }
我们已经知道自动机的insn_equiv_classes_num记录了在该自动机中的等效类别的数目,而ainsn的域insn_equiv_class_num记录了它所从属的等效类别的编号(参见set_insn_equiv_classes)。
output_range_type确定,在输出文件中,为这个变量所声明的类型。
7008 static void
7009 output_range_type (FILE *f, long intmin_range_value, ingenautomata.c
7010 long int max_range_value)
7011 {
7012 if (min_range_value >= 0 &&max_range_value <= 255)
7013 fprintf (f, "unsigned char");
7014 else if (min_range_value >= -127&& max_range_value <= 127)
7015 fprintf (f, "signed char");
7016 else if (min_range_value >= 0 &&max_range_value <= 65535)
7017 fprintf (f, "unsigned short");
7018 else if (min_range_value >= -32767&& max_range_value <= 32767)
7019 fprintf (f, "short");
7020 else
7021 fprintf (f, "int");
7022 }
然后,output_translate_vect_name为自动机输出名字,接着在7027行,在create_automata中automaton_order_num被赋值为该序列号。
7168 static void
7169 output_translate_vect_name (FILE *f, automaton_t automaton) ingenautomata.c
7170 {
7171 if(automaton->corresponding_automaton_decl == NULL)
7172 fprintf (f, "translate_%d",automaton->automaton_order_num);
7173 else
7174 fprintf (f, "%s_translate",automaton->corresponding_automaton_decl->name);
7175 }
在这一步,为自动机我们输出以下代码。假定该自动机的等效指令类别的数目少于255,并且仅构建了一个自动机(缺省的情形,不过对于现代CPU架构,通常会声明多个自动机)。
/* Vector translating external insn codes to internalones.*/
static const unsigned char translate_0 []ATTRIBUTE_UNUSED = {
在这里vect是output_translate_vect中的translate_vect,因为所有指令被确信,当构建自动机时,可以被发布,在vect中的每个元素(指令)将包含等效集编号。注意vect使用指令编号——指令的序列号作为索引。
7108 static void
7109 output_vect (vect_el_t *vect, intvect_length) ingenautomata.c
7110 {
7111 int els_on_line;
7112
7113 els_on_line = 1;
7114 if (vect_length == 0)
7115 fprintf (output_file,
7116 "0 /* This is dummy el becausethe vect is empty */");
7117 else
7118 {
7119 do
7120 {
7121 fprintf (output_file, "%5ld",(long) *vect);
7122 vect_length--;
7123 if (els_on_line == 10)
7124 {
7125 els_on_line = 0;
7126 fprintf (output_file, ",\n");
7127 }
7128 else if (vect_length != 0)
7129 fprintf (output_file, ", ");
7130 els_on_line++;
7131 vect++;
7132 }
7133 while(vect_length != 0);
7134 }
7135 }
因此输出的translate_0是一个外部指令编号与指令单元预订等效类别编号之间的映射。
9.6.4.1.2. 输出状态迁移表
状态,根据其创建的方式,可以显示所占用的资源。状态迁移由指令(实际以等效指令类别)发布所驱动,arc被创建来记录迁移的细节。看到状态与arc是不可分割的数据,输出的表应该体现两者。
7731 static void
7732 output_trans_table (automaton_t automaton) ingenautomata.c
7733 {
7734 state_t *state_ptr;
7735 arc_t arc;
7736 vla_hwint_t transition_vect;
7737
7738 undefined_vect_el_value = automaton->achieved_states_num;
7739 automaton->trans_table = create_state_ainsn_table (automaton);
7740 /* Create vect ofpointers to states ordered by num of transitions
7741 from the state (state with the maximum numis the first). */
7742 VLA_PTR_CREATE (output_states_vect, 1500,"output states vector");
7743 pass_states(automaton, add_states_vect_el);
7744 qsort (VLA_PTR_BEGIN (output_states_vect),
7745 VLA_PTR_LENGTH (output_states_vect),
7746 sizeof (state_t), compare_transition_els_num);
7747 VLA_HWINT_CREATE (transition_vect, 500,"transition vector");
7748 for(state_ptr = VLA_PTR_BEGIN (output_states_vect);
7749 state_ptr <= (state_t*) VLA_PTR_LAST (output_states_vect);
7750 state_ptr++)
7751 {
7752 VLA_HWINT_NULLIFY (transition_vect);
7753 for (arc =first_out_arc (*state_ptr);
7754 arc != NULL;
7755 arc = next_out_arc (arc))
7756 {
7757 if (arc->insn == NULL)
7758 abort ();
7759 if(arc->insn->first_ainsn_with_given_equialence_num)
7760 add_vect_el(&transition_vect, arc->insn,
7761 arc->to_state->order_state_num);
7762 }
7763 add_vect(automaton->trans_table, (*state_ptr)->order_state_num,
7764 VLA_HWINT_BEGIN (transition_vect),
7765 VLA_HWINT_LENGTH(transition_vect));
7766 }
7768 (automaton->trans_table, (char *)"state transitions",
7769 output_trans_full_vect_name, output_trans_comb_vect_name,
7770 output_trans_check_vect_name, output_trans_base_vect_name);
7771 VLA_PTR_DELETE (output_states_vect);
7772 VLA_HWINT_DELETE (transition_vect);
7773 }
在7738行的achieved_states_num记录了该自动机的状态的数目(参见enumerate_states)。在7739行的create_state_ainsn_table构建了state_ainsn_table的一个实例。
7481 static state_ainsn_table_t
7482 create_state_ainsn_table (automaton_t automaton) ingenautomata.c
7483 {
7484 state_ainsn_table_ttab;
7485 int full_vect_length;
7486 int i;
7487
7488 tab = create_node (sizeof(struct state_ainsn_table));
7489 tab->automaton = automaton;
7490 VLA_HWINT_CREATE (tab->comb_vect, 10000,"comb vector");
7491 VLA_HWINT_CREATE (tab->check_vect, 10000,"check vector");
7492 VLA_HWINT_CREATE (tab->base_vect, 1000,"base vector");
7493 VLA_HWINT_EXPAND (tab->base_vect,automaton->achieved_states_num);
7494 VLA_HWINT_CREATE (tab->full_vect, 10000,"full vector");
7495 full_vect_length =(automaton->insn_equiv_classes_num
7496 *automaton->achieved_states_num);
7497 VLA_HWINT_EXPAND (tab->full_vect,full_vect_length);
7498 for (i = 0; i< full_vect_length; i++)
7499 VLA_HWINT (tab->full_vect, i) = undefined_vect_el_value;
7500 tab->min_base_vect_el_value= 0;
7501 tab->max_base_vect_el_value = 0;
7502 tab->min_comb_vect_el_value = 0;
7503 tab->max_comb_vect_el_value = 0;
7504 return tab;
7505 }
state_ainsn_table具有如下定义。它为输出表收集数据。
1280 struct state_ainsn_table ingenautomata.c
1281 {
1282 /* Automaton towhich given table belongs. */
1283 automaton_tautomaton;
1284 /* The followingtree vectors for comb vector implementation of the
1285 table. */
1286 vla_hwint_t comb_vect;
1287 vla_hwint_tcheck_vect;
1288 vla_hwint_t base_vect;
1289 /* This is simpleimplementation of the table. */
1290 vla_hwint_t full_vect;
1291 /* Minimal andmaximal values of the previous vectors. */
1292 int min_comb_vect_el_value,max_comb_vect_el_value;
1293 int min_base_vect_el_value,max_base_vect_el_value;
1294 };
207 typedef struct state_ainsn_table*state_ainsn_table_t; ingenautomata.c
在create_state_ainsn_table的7743行,add_states_vect_el及pass_states把该自动机的每个状态加入类型为vla_ptr_t的output_states_vect中。
7723 static void
7724 add_states_vect_el (state_tstate) ingenautomata.c
7725 {
7726 VLA_PTR_ADD (output_states_vect, state);
7727 }
在output_trans_table的7746行,compare_transition_els_num根据迁移的数目,以升序排序。然后output_trans_table遍历output_states_vect中,现在以迁移编号的升序排序的状态。对于每个来自该状态的迁移,正如我们已经知道的,由特定的指令所触发,并且所有的指令通过其所预订的资源来分组(等效类别)。在7759行的first_ainsn_with_given_equialence_num为在该类别中首先找到的指令所设置(参见set_insn_equiv_classes)。对于这个类别的指令,目的状态的序列号(参见在7761行的order_state_num,在下面通过el_value传递),以及该指令(参见下面的ainsn)被传递给add_vect_el。
7702 static void
7703 add_vect_el (vla_hwint_t *vect, ainsn_tainsn, int el_value) ingenautomata.c
7704 {
7705 int equiv_class_num;
7706 int vect_index;
7707
7708 if (ainsn == NULL)
7709 abort ();
7710 equiv_class_num = ainsn->insn_equiv_class_num;
7711 for(vect_index = VLA_HWINT_LENGTH (*vect);
7712 vect_index <= equiv_class_num;
7713 vect_index++)
7714 VLA_HWINT_ADD (*vect, undefined_vect_el_value);
7715 VLA_HWINT (*vect, equiv_class_num) =el_value;
7716 }
看到add_vect_el位于FOR循环之内,因而,transition_vect被输入如下数据。注意到order_state_num是目的状态的序列号,并且其位置由触发该迁移的等效指令类别编号所决定。因此这个数组把所有目的状态与给定源状态的触发指令绑定起来。
由于VLA_HWINT_ADD的作用是把vect扩大一个单元,然后在vect的末尾加入undefined_vect_el_value,因此vect的大小是最大的“equiv_class_num”。
图97:输出state_transition表,步骤1
接着这个数组由下面的vect传递给add_vect。而参数tab指向在create_state_ainsn_table中构建的trans_table,它现在还是空的。
7566 static void
7567 add_vect (state_ainsn_table_ttab, int vect_num, ingenautomata.c
7568 vect_el_t *vect, int vect_length)
7569 {
7570 int real_vect_length;
7571 vect_el_t *comb_vect_start;
7572 vect_el_t *check_vect_start;
7573 int comb_vect_index;
7574 int comb_vect_els_num;
7575 int vect_index;
7576 int first_unempty_vect_index;
7577 int additional_els_num;
7578 int no_state_value;
7579 vect_el_t vect_el;
7580 int i;
7581
7582 if (vect_length == 0)
7583 abort ();
7584 real_vect_length =tab->automaton->insn_equiv_classes_num;
7585 if (vect [vect_length - 1] == undefined_vect_el_value)
7586 abort ();
7587 /* Form full vectorin the table: */
7588 for (i = 0; i< vect_length; i++)
7589 VLA_HWINT (tab->full_vect,
7590 i +tab->automaton->insn_equiv_classes_num * vect_num)
7591 = vect [i];
7592 /* Form comb vectorin the table: */
7593 if (VLA_HWINT_LENGTH (tab->comb_vect) !=VLA_HWINT_LENGTH (tab->check_vect))
7594 abort ();
7595 comb_vect_start = VLA_HWINT_BEGIN(tab->comb_vect);
7596 comb_vect_els_num = VLA_HWINT_LENGTH(tab->comb_vect);
7597 for(first_unempty_vect_index = 0;
7598 first_unempty_vect_index <vect_length;
7599 first_unempty_vect_index++)
7600 if (vect [first_unempty_vect_index] != undefined_vect_el_value)
7601 break;
7602 /* Search for theplace in comb vect for the inserted vect. */
7603 for(comb_vect_index = 0;
7604 comb_vect_index < comb_vect_els_num;
7605 comb_vect_index++)
7606 {
7607 for(vect_index = first_unempty_vect_index;
7608 vect_index < vect_length
7609 && vect_index +comb_vect_index < comb_vect_els_num;
7610 vect_index++)
7611 if (vect [vect_index] != undefined_vect_el_value
7612 && (comb_vect_start[vect_index + comb_vect_index]
7613 != undefined_vect_el_value))
7614 break;
7615 if (vect_index >= vect_length
7616 || vect_index + comb_vect_index >=comb_vect_els_num)
7617 break;
7618 }
7619 /* Slot wasfound. */
7620 additional_els_num = comb_vect_index +real_vect_length - comb_vect_els_num;
7621 if (additional_els_num < 0)
7622 additional_els_num = 0;
7623 /* Expand comb andcheck vectors. */
7624 vect_el = undefined_vect_el_value;
7625 no_state_value =tab->automaton->achieved_states_num;
7626 while(additional_els_num > 0)
7627 {
7628 VLA_HWINT_ADD (tab->comb_vect, vect_el);
7629 VLA_HWINT_ADD (tab->check_vect,no_state_value);
7630 additional_els_num--;
7631 }
7632 comb_vect_start = VLA_HWINT_BEGIN(tab->comb_vect);
7633 check_vect_start = VLA_HWINT_BEGIN(tab->check_vect);
7634 if (VLA_HWINT_LENGTH (tab->comb_vect)
7635 < (size_t) (comb_vect_index +real_vect_length))
7636 abort ();
7637 /* Fill comb andcheck vectors. */
7638 for(vect_index = 0; vect_index < vect_length; vect_index++)
7639 if (vect [vect_index] != undefined_vect_el_value)
7640 {
7641 if (comb_vect_start [comb_vect_index +vect_index]
7642 != undefined_vect_el_value)
7643 abort ();
7644 comb_vect_start [comb_vect_index +vect_index] = vect [vect_index];
7645 if (vect [vect_index] < 0)
7646 abort ();
7647 if(tab->max_comb_vect_el_value < vect [vect_index])
7648 tab->max_comb_vect_el_value = vect[vect_index];
7649 if (tab->min_comb_vect_el_value >vect [vect_index])
7650 tab->min_comb_vect_el_value = vect[vect_index];
7651 check_vect_start [comb_vect_index +vect_index] = vect_num;
7652 }
7653 if (tab->max_comb_vect_el_value < undefined_vect_el_value)
7654 tab->max_comb_vect_el_value = undefined_vect_el_value;
7655 if (tab->min_comb_vect_el_value > undefined_vect_el_value)
7656 tab->min_comb_vect_el_value = undefined_vect_el_value;
7657 if (tab->max_base_vect_el_value <comb_vect_index)
7658 tab->max_base_vect_el_value =comb_vect_index;
7659 if (tab->min_base_vect_el_value >comb_vect_index)
7660 tab->min_base_vect_el_value =comb_vect_index;
7661 VLA_HWINT (tab->base_vect, vect_num) =comb_vect_index;
7662 }
在7588行的FOR循环里,tab(类型为state_ainsn_table)的full_vect实际上可视为一个二维数组,它的内容如下图所示。
图98:输出state_transition表,步骤2
看到这个数组很可能是稀疏。为了减小状态相关函数输出的大小,我们可以构建一个类似但更加紧凑的vector,tab的comb_vect就是这样的一个vector。因为这个vector不是与状态一一对应的,我们需要额外的vector来保存源状态的信息。
为了更好地理解comb_vect及check_vect的填充过程,我们假定这个自动机总共具有8个有效状态,在第一个状态中,可以迁移到状态3及5(这里我们不需要在意状态的编号),第二个状态的目的状态的编号分别是2及4,而第三个状态,则是编号为3及6的状态。
在7597行的FOR循环首先找出图97所示数组中第一个有效填充单元的索引,该索引将是7607行FOR循环的初始值。而7603行的FOR循环扫描comb_vect与vect,满足7611行条件,表示comb_vect对应的单元已经进行了有效填充。
对于第一个状态,起初comb_vect是空的,因此7620行的additional_els_num将是automaton->insn_equiv_classes_num。在7626行的WHILE循环,把comb_vect填充为全undefined_vect_el_value,而check_vect为全automaton->achieved_states_num(自动机状态数目)。在接下来7638行的FOR循环中,填充comb_vect与第一个状态的数组相同,check_vect的对应位置为源状态编号,如下图所示。
图99:输出state_transition表,步骤3
然后对于第二个状态,transition_vect重新填充(output_trans_table的7752行),在7603行的FOR循环检查comb_vect是否在对应的位置已经填充了,若然在7614行跳出7607行的FOR循环,在7603行递增comb_vect_index重新尝试,直到某个comb_vect_index能使comb_vect容纳transition_vect。对于第二个状态,显然comb_vect_index为0就可以了,如下图所示。
图100:输出state_transition表,步骤4
对于第三个状态,comb_vect [2]已经为状态1所占据,因此递增 comb_vect_index为1,但此时comb_vect [3]也已经为状态2使用,继续递增 comb_vect_index到2,可是comb_vect [4]也已被状态1使用。直到递增 comb_vect_index到3,此时comb_vect [5]可用,加入状态3的信息后,得到如下图。图101:输出state_transition表,步骤5
在上图中,我们忽略了向量base_vect,它以源状态序号为索引,并且其内容为comb_vect_index。从这个索引,我们可以恢复状态的初始的vector。
现在是时候由output_state_ainsn_table输出我们在上面看到的这些vector了。
7509 static void
7510 output_state_ainsn_table (state_ainsn_table_t tab, char *table_name, ingenautomata.c
7511 void (*output_full_vect_name_func) (FILE *,automaton_t),
7512 void (*output_comb_vect_name_func) (FILE *,automaton_t),
7513 void (*output_check_vect_name_func) (FILE *,automaton_t),
7514 void (*output_base_vect_name_func) (FILE *,automaton_t))
7515 {
7516 if (!comb_vect_p (tab))
7517 {
7518 fprintf (output_file, "/* Vector for%s. */\n", table_name);
7519 fprintf (output_file, "static const");
7520 output_range_type(output_file,tab->min_comb_vect_el_value,
7521 tab->max_comb_vect_el_value);
7522 fprintf (output_file, " ");
7523 (*output_full_vect_name_func) (output_file,tab->automaton);
7524 fprintf (output_file, "[]ATTRIBUTE_UNUSED = {\n");
7525 output_vect(VLA_HWINT_BEGIN (tab->full_vect),
7526 VLA_HWINT_LENGTH(tab->full_vect));
7527 fprintf (output_file, "};\n\n");
7528 }
7529 else
7530 {
7531 fprintf (output_file, "/* Comb vectorfor %s. */\n", table_name);
7532 fprintf (output_file, "static const");
7533 output_range_type(output_file,tab->min_comb_vect_el_value,
7534 tab->max_comb_vect_el_value);
7535 fprintf (output_file, " ");
7536 (*output_comb_vect_name_func) (output_file,tab->automaton);
7537 fprintf (output_file, "[]ATTRIBUTE_UNUSED = {\n");
7538 output_vect (VLA_HWINT_BEGIN(tab->comb_vect),
7539 VLA_HWINT_LENGTH(tab->comb_vect));
7540 fprintf (output_file, "};\n\n");
7541 fprintf (output_file, "/* Check vectorfor %s. */\n", table_name);
7542 fprintf (output_file, "static const");
7543 output_range_type(output_file,0, tab->automaton->achieved_states_num);
7544 fprintf (output_file, " ");
7545 (*output_check_vect_name_func) (output_file,tab->automaton);
7546 fprintf (output_file, "[] = {\n");
7547 output_vect(VLA_HWINT_BEGIN (tab->check_vect),
7548 VLA_HWINT_LENGTH(tab->check_vect));
7549 fprintf (output_file, "};\n\n");
7550 fprintf (output_file, "/* Base vectorfor %s. */\n", table_name);
7551 fprintf (output_file, "static const");
7552 output_range_type(output_file,tab->min_base_vect_el_value,
7553 tab->max_base_vect_el_value);
7554 fprintf (output_file, " ");
7555 (*output_base_vect_name_func) (output_file,tab->automaton);
7556 fprintf (output_file, "[] = {\n");
7557 output_vect(VLA_HWINT_BEGIN (tab->base_vect),
7558 VLA_HWINT_LENGTH(tab->base_vect));
7559 fprintf (output_file, "};\n\n");
7560 }
7561 }
上面在7516行,comb_vect_p检查comb_vect是否大于full_vect的五分之二。若然,我们使用comb_vect,否则使用full_vect。假定我们使用comb_vect,现在我们将得到如下输出文件(insn-attrtab.c)。
/*Vector translating external insn codes to internal ones.*/
static const unsigned char translate_0 []ATTRIBUTE_UNUSED = {
`equivalent class set` //in description order
};
/*Comb vector for state transitions */
staticconst unsigned char transitions_0 [] ATTRIBUTE_UNUSED = {
`content of comb_vect` // refer to add_vect
};
/*Check vector for state transitions */
staticconst unsigned char check_0 [] ATTRIBUTE_UNUSED = {
`content of check_vect` // refer to add_vect
};
/* Basevector for state transitions */
staticconst unsigned char base_0 [] ATTRIBUTE_UNUSED = {
`content of base_vect` // refer to add_vect
}