9.5. 构建基于DFA 的流水线危险识别器
9.5.1. 为 DEFINE_AUTOMATON 模式构建的 decl
在 gen_automaton 中,我们看到这个模式转换来的 rtx 对象将被保存入 decl 实例。对于在 读入 DEFINE_AUTOMATON模式 一节中所使用的例子,我们已经看过如下的 rtx 对象。 这个例子来自文件 pentium.md 。
那么由 gen_automaton 处理后,我们将得到以下的数据结构。注意到在这个向量中实际上是 decl 的指针。
9.5.2. 为 DEFINE_CPU_UNIT 模式构建 decl
同样对于 读入 DEFINE_CPU_UNIT模式 一节中的例子,我们已经看到了如下的 rtx 对象。这个例子来自 pentium.md 文件。
在经由 gen_cpu_unit 的处理之后,我们将得到以下的数据结构。注意到在这个向量中实际上是 decl 的指针。
图 62 : DEFINE_CUP_UNIT 模式的 decl 对象的例子
9.5.3. 为 DEFINE_BYPASS 模式构建 decl
而对于 DEFINE_BYPASS 的例子,我们已经看到如下从 md 文件构建的 rtx 对象。这个例子来自 pentium.md 文件。
在经过 gen_bypass 的处理之后,我们将得到如下的数据结构。所有的 decl 都链接在一起。注意到在这个向量中实际上是 decl 的指针。
图 63 : DEFINE_BYPASS 模式的 decl 对象的例子
9.5.4. 为 EXCULSION_SET 模式构建 decl
而对于 EXCLUSION_SET 的例子,我们已经看到如下从 md 文件构建的 rtx 对象。这个例子来自 itantium.md 文件。
我们知道上面的这两个字符串描述了两组互斥的单元。在经过的处理 gen_excl_set 后,我们将得到以下的数据结构,所有的 decl 都链接在一起。注意到在这个向量中实际上是 decl 的指针。
图 64 : EXCLUSION_SET 模式的 decl 对象的例子
9.5.5. 为 DEFINE_RESERVATION 模式构建 decl
那么对于 DEFINE_RESERVATION 的例子,我们已经看到如下从 md 文件构建的 rtx 对象。这个例子来自 pentium.md 文件。
那么在 gen_reserv 的处理之后,我们将得到如下的数据结构。
图 65 : DEFINE_RESERVATION 模式的 decl 对象的例子
9.5.6. 为 DEFINE_INSN_RESERVATION 模式构建 decl
而对于 DEFINE_INSN_RESERVATION 的例子,我们已经看到如下从 md 文件构建的 rtx 对象。这个例子来自 pentium.md 文件。
那么在 gen_insn_reserv 的处理之后,我们将得到如下的数据结构。
图 66 : DEFINE_INSN_RESERVATION 模式的 decl 对象的例子
9.5.7. 处理 decl
指令调度器的目的是尽可能多地发布指令。流水线危险识别器可以告诉调度器某个指令是否可以与其它运行中指令一同执行。所有所需的信息被分散地记录在机器描述文件中相关的模式里,不过 expand_automata 将组织这些信息,并为构建基于 DFA 的流水线危险识别器生成结构化信息。
9810 void
9811 expand_automata (void) in genautomata.c
9812 {
9813 int i;
9814
9815 description = create_node (sizeof (struct description)
9816 /* One entry for cycle advancing insn. */
9817 + sizeof (decl_t) * VLA_PTR_LENGTH (decls ));
9818 description ->decls_num = VLA_PTR_LENGTH (decls );
9819 description ->query_units_num = 0;
9820 for (i = 0; i < description ->decls_num; i++)
9821 {
9822 description ->decls [i] = VLA_PTR (decls , i);
9823 if (description ->decls [i]->mode == dm_unit
9824 && DECL_UNIT (description ->decls [i])->query_p)
9825 DECL_UNIT (description ->decls [i])->query_num
9826 = description ->query_units_num++;
9827 }
9828 all_time = create_ticker ();
9829 check_time = create_ticker ();
9830 if (progress_flag )
9831 fprintf (stderr, "Check description...");
9832 check_all_description ();
9833 if (progress_flag )
9834 fprintf (stderr , "done/n");
9835 ticker_off (&check_time );
9836 generation_time = create_ticker ();
expand_automata 首先创建一个 description 对象来收集所有构建的 decl ,这个对象具有如下的定义。
1009 struct description in genautomata.c
1010 {
1011 int decls_num;
1012
1013 /* The following fields are defined by checker. */
1014
1015 /* The following fields values are correspondingly number of all
1016 units, query units, and insns in the description. */
1017 int units_num;
1018 int query_units_num;
1019 int insns_num;
1020 /* The following field value is max length (in cycles) of
1021 reservations of insns. The field value is defined only for
1022 correct programs. */
1023 int max_insn_reserv_cycles;
1024
1025 /* The following fields are defined by automaton generator. */
1026
1027 /* The following field value is the first automaton. */
1028 automaton_t first_automaton;
1029
1030 /* The following field is created by pipeline hazard parser and
1031 contains all declarations. We allocate additional entry for
1032 special insn "cycle advancing" which is added by the automaton
1033 generator. */
1034 decl_t decls [1];
1035 };
在 expand_automata 中,直到 9832 行,将创建如下的 description 对象。
图 67 : description 对象的例子
接着 check_all_description 将以如下方式来处理这个对象。
3387 static void
3388 check_all_description (void) in genautomata.c
3389 {
3390 process_decls ();
3391 check_automaton_usage ();
3392 process_regexp_decls ();
3393 check_usage ();
3394 check_loops_in_regexps ();
3395 if (!have_error )
3396 evaluate_max_reserv_cycles ();
3397 }
9.5.7.1. 处理 decl 的第一个循环 – DECL_AUTOMATON
process_decls 在 6 个循环中处理 decl 。在这个循环里,需要找出一共声明了多少个自动机,并为随后的循环准备必须的数据对象。
2802 static void
2803 process_decls (void) in genautomata.c
2804 {
2805 decl_t decl;
2806 decl_t automaton_decl;
2807 decl_t decl_in_table;
2808 decl_t out_insn_reserv;
2809 decl_t in_insn_reserv;
2810 struct bypass_decl *bypass;
2811 int automaton_presence;
2812 int i;
2813
2814 /* Checking repeated automata declarations. */
2815 automaton_presence = 0;
2816 for (i = 0; i < description ->decls_num; i++)
2817 {
2818 decl = description ->decls [i];
2819 if (decl->mode == dm_automaton)
2820 {
2821 automaton_presence = 1;
2822 decl_in_table = insert_automaton_decl (decl);
2823 if (decl_in_table != decl)
2824 {
2825 if (!w_flag )
2826 error ("repeated declaration of automaton `%s'",
2827 DECL_AUTOMATON (decl)->name);
2828 else
2829 warning ("repeated declaration of automaton `%s'",
2830 DECL_AUTOMATON (decl)->name);
2831 }
2832 }
2833 }
首先得到处理的是 DEFINE_AUTOMATON 模式的 decl 。这个类别的 decl 被保存在静态哈希表 automaton_decl_table 中。自动机的名字必须是唯一的,否则将触发警告或错误。
2202 static decl_t
2203 insert_automaton_decl ( decl_t automaton_decl) in genautomata.c
2204 {
2205 void **entry_ptr;
2206
2207 entry_ptr = htab_find_slot (automaton_decl_table , automaton_decl, 1);
2208 if (*entry_ptr == NULL)
2209 *entry_ptr = (void *) automaton_decl;
2210 return (decl_t) *entry_ptr;
2211 }
9.5.7.2. 处理 decl 的第二个循环 – DECL_UNIT
这次循环只是把 CPU 单元的 decl 与其从属的自动机绑定在一起。
process_decls (continued)
2834 /* Checking undeclared automata, repeated declarations (except for
2835 automata) and correctness of their attributes (insn latency times
2836 etc.). */
2837 for (i = 0; i < description ->decls_num; i++)
2838 {
2839 decl = description ->decls [i];
2840 if (decl->mode == dm_insn_reserv)
2841 {
2842 DECL_INSN_RESERV (decl)->condexp
2843 = check_attr_test (DECL_INSN_RESERV (decl)->condexp, 0, 0);
2844 if (DECL_INSN_RESERV (decl)->default_latency < 0)
2845 error ("define_insn_reservation `%s' has negative latency time",
2846 DECL_INSN_RESERV (decl)->name);
2847 DECL_INSN_RESERV (decl)->insn_num = description ->insns_num;
2848 description ->insns_num++;
2849 decl_in_table = insert_insn_decl (decl);
2850 if (decl_in_table != decl)
2851 error ("`%s' is already used as insn reservation name",
2852 DECL_INSN_RESERV (decl)->name);
2853 }
2854 else if (decl->mode == dm_bypass)
2855 {
2856 if (DECL_BYPASS (decl)->latency < 0)
2857 error ("define_bypass `%s - %s' has negative latency time",
2858 DECL_BYPASS (decl)->out_insn_name,
2859 DECL_BYPASS (decl)->in_insn_name);
2860 }
2861 else if (decl->mode == dm_unit || decl->mode == dm_reserv)
2862 {
2863 if (decl->mode == dm_unit)
2864 {
2865 DECL_UNIT (decl)->automaton_decl = NULL;
2866 if (DECL_UNIT (decl)->automaton_name != NULL)
2867 {
2868 automaton_decl
2869 = find_automaton_decl (DECL_UNIT (decl)->automaton_name);
2870 if (automaton_decl == NULL)
2871 error ("automaton `%s' is not declared",
2872 DECL_UNIT (decl)->automaton_name);
2873 else
2874 {
2875 DECL_AUTOMATON (automaton_decl)->automaton_is_used = 1;
2876 DECL_UNIT (decl)->automaton_decl
2877 = DECL_AUTOMATON (automaton_decl);
2878 }
2879 }
2880 else if (automaton_presence)
2881 error ("define_unit `%s' without automaton when one defined",
2882 DECL_UNIT (decl)->name);
2883 DECL_UNIT (decl)->unit_num = description ->units_num;
2884 description ->units_num++;
2885 if (strcmp (DECL_UNIT (decl)->name, NOTHING_NAME) == 0)
2886 {
2887 error ("`%s' is declared as cpu unit", NOTHING_NAME);
2888 continue ;
2889 }
2890 decl_in_table = find_decl (DECL_UNIT (decl)->name);
2891 }
2892 else
2893 {
2894 if (strcmp (DECL_RESERV (decl)->name, NOTHING_NAME) == 0)
2895 {
2896 error ("`%s' is declared as cpu reservation", NOTHING_NAME);
2897 continue ;
2898 }
2899 decl_in_table = find_decl (DECL_RESERV (decl)->name);
2900 }
2901 if (decl_in_table == NULL)
2902 decl_in_table = insert_decl (decl);
2903 else
2904 {
2905 if (decl->mode == dm_unit)
2906 error ("repeated declaration of unit `%s'",
2907 DECL_UNIT (decl)->name);
2908 else
2909 error ("repeated declaration of reservation `%s'",
2910 DECL_RESERV (decl)->name);
2911 }
2912 }
2913 }
define_insn_reservation 及 define_bypass 模式的 decl 的处理相当简单。上面,宏 DECL_* 访问 decl 的 union 域的对应成员。
在 2221 行,我们之前已经见过 check_attr_test 。这个函数将验证给定的属性,并把相关的表达式转换为所谓的规范形式。例如,转换“ (eq_attr "att" "a1,a2") ”为“ (ior (eq_attr “att” “a1” ) (eq_attrq “att” “a2”)) ”。另一个例子,转换“ (eq_attr "att" "!a1") ”为“ (not (eq_attr "att" "a1")) ”。
在 2227 行, insert_insn_decl 将把 define_insn_reservation 模式的 decl 加入静态哈希表 insn_decl_table 中。
在 2863 行开始,对于 define_cpu_unit 模式的 decl ,它将被与相应的 define_automaton 模式的 decl 绑定如下。
图 68 : DEFINE_CPU_UNIT 的 decl 的例子
9.5.7.3. 处理 decl 的第三个循环 – DECL_BYPASS
我们知道 define_bypass 模式用于描述给定指令对延迟时间的例外。它记录了在字符串 out_insn_name s 中指令的结果,对于在字符串 in_insn_name s 中指令就绪的延迟时间。第三个循环把 define_bypass 模式的 decl 域 define_insn_reservation 模式(描述 CPU 单元的使用,参见 DEFINE_INSN_RESERVATION模式的概览 一节)的 decl 绑定在一起。
process_decls (continued)
2914 /* Check bypasses and form list of bypasses for each (output)
2915 insn. */
2916 for (i = 0; i < description ->decls_num; i++)
2917 {
2918 decl = description ->decls [i];
2919 if (decl->mode == dm_bypass)
2920 {
2921 out_insn_reserv = find_insn_decl (DECL_BYPASS (decl)->out_insn_name);
2922 i n_insn_reserv = find_insn_decl (DECL_BYPASS (decl)->in_insn_name);
2923 if (out_insn_reserv == NULL)
2924 error ("there is no insn reservation `%s'",
2925 DECL_BYPASS (decl)->out_insn_name);
2926 else if (in_insn_reserv == NULL)
2927 error ("there is no insn reservation `%s'",
2928 DECL_BYPASS (decl)->in_insn_name);
2929 else
2930 {
2931 DECL_BYPASS (decl)->out_insn_reserv
2932 = DECL_INSN_RESERV (out_insn_reserv);
2933 DECL_BYPASS (decl)->in_insn_reserv
2934 = DECL_INSN_RESERV (in_insn_reserv);
2935 bypass
2936 = find_bypass (DECL_INSN_RESERV (out_insn_reserv)->bypass_list,
2937 DECL_BYPASS (decl)->in_insn_reserv);
2938 if (bypass != NULL)
2939 {
2940 if (DECL_BYPASS (decl)->latency == bypass->latency)
2941 {
2942 if (!w_flag )
2943 error
2944 ("the same bypass `%s - %s' is already defined",
2945 DECL_BYPASS (decl)->out_insn_name,
2946 DECL_BYPASS (decl)->in_insn_name);
2947 else
2948 warning
2949 ("the same bypass `%s - %s' is already defined",
2950 DECL_BYPASS (decl)->out_insn_name,
2951 DECL_BYPASS (decl)->in_insn_name);
2952 }
2953 else
2954 error ("bypass `%s - %s' is already defined",
2955 DECL_BYPASS (decl)->out_insn_name,
2956 DECL_BYPASS (decl)->in_insn_name);
2957 }
2958 else
2959 {
2960 DECL_BYPASS (decl)->next
2961 = DECL_INSN_RESERV (out_insn_reserv)->bypass_list;
2962 DECL_INSN_RESERV (out_insn_reserv)->bypass_list
2963 = DECL_BYPASS (decl);
2964 }
2965 }
2966 }
2967 }
对于我们的例子,我们可以得到下图(忽略了对象“ penrt_call ”)。
图 69 : DECL_BYPASS 的 decl 的例子
9.5.7.4. 处理 decl 的第四个循环 – DECL_EXCL
这次的循环根据对应的 decl_excl 填充 define_cpu_unit 模式的 decl 。
process_decls (continued)
2969 /* Check exclusion set declarations and form exclusion sets. */
2970 for (i = 0; i < description ->decls_num; i++)
2971 {
2972 decl = description ->decls [i];
2973 if (decl->mode == dm_excl)
2974 {
2975 unit_set_el_t unit_set_el_list;
2976 unit_set_el_t unit_set_el_list_2;
2977
2978 unit_set_el_list
2979 = process_excls (DECL_EXCL (decl)->names,
2980 DECL_EXCL (decl)->first_list_length, decl->pos);
2981 unit_set_el_list_2
2982 = process_excls (&DECL_EXCL (decl)->names
2983 [DECL_EXCL (decl)->first_list_length],
2984 DECL_EXCL (decl)->all_names_num
2985 - DECL_EXCL (decl)->first_list_length,
2986 decl->pos);
2987 add_excls (unit_set_el_list, unit_set_el_list_2, decl->pos);
2988 add_excls (unit_set_el_list_2, unit_set_el_list, decl->pos);
2989 }
2990 }
在 2978 及 2981 行, unit_set_el_list 与 unit_set_el_list_2 记录彼此互斥的单元,它们由 process_excls 构建。注意 first_list_length 域显示了 names 数组中前几个元素是来自第一组单元的, all_names_num 则表示一共出现了多少个单元。
2460 static unit_set_el_t
2461 process_excls (char **names, int num, pos_t excl_pos ATTRIBUTE_UNUSED) in genautomata.c
2462 {
2463 unit_set_el_t el_list;
2464 unit_set_el_t last_el;
2465 unit_set_el_t new_el;
2466 decl_t decl_in_table;
2467 int i;
2468
2469 el_list = NULL;
2470 last_el = NULL;
2471 for (i = 0; i < num; i++)
2472 {
2473 decl_in_table = find_decl (names [i]);
2474 if (decl_in_table == NULL)
2475 error ("unit `%s' in exclusion is not declared", names [i]);
2476 else if (decl_in_table->mode != dm_unit)
2477 error ("`%s' in exclusion is not unit", names [i]);
2478 else
2479 {
2480 new_el = create_node (sizeof (struct unit_set_el ));
2481 new_el->unit_decl = DECL_UNIT (decl_in_table);
2482 new_el->next_unit_set_el = NULL;
2483 if (last_el == NULL)
2484 el_list = last_el = new_el;
2485 else
2486 {
2487 last_el->next_unit_set_el = new_el;
2488 last_el = last_el->next_unit_set_el;
2489 }
2490 }
2491 }
2492 return el_list;
2493 }
unit_set_el_list 与 unit_set_el_list_2 链表由如下的 unit_set_el 类型的节点构成。
1042 struct unit_set_el in genautomata.c
1043 {
1044 unit_decl_t unit_decl;
1045 unit_set_el_t next_unit_set_el;
1046 };
198 typedef struct unit_set_el *unit_set_el_t ;
在构建了这两个链表后 , 因为这两个链表记录的是互斥的单元 , add_excls 把 src_list 中的单元 decl 填充到 dst_list 中每个单元 decl 的 next_unit_set_el 链表。
2498 static void
2499 add_excls (unit_set_el_t dest_list, unit_set_el_t source_list, in genautomata.c
2500 pos_t excl_pos ATTRIBUTE_UNUSED)
2501 {
2502 unit_set_el_t dst;
2503 unit_set_el_t src;
2504 unit_set_el_t curr_el;
2505 unit_set_el_t prev_el;
2506 unit_set_el_t copy;
2507
2508 for (dst = dest_list; dst != NULL; dst = dst->next_unit_set_el)
2509 for (src = source_list; src != NULL; src = src->next_unit_set_el)
2510 {
2511 if (dst->unit_decl == src->unit_decl)
2512 {
2513 error ("unit `%s' excludes itself", src->unit_decl->name);
2514 continue ;
2515 }
2516 if (dst->unit_decl->automaton_name != NULL
2517 && src->unit_decl->automaton_name != NULL
2518 && strcmp (dst->unit_decl->automaton_name,
2519 src->unit_decl->automaton_name) != 0)
2520 {
2521 error ("units `%s' and `%s' in exclusion set belong to different automata",
2522 src->unit_decl->name, dst->unit_decl->name);
2523 continue ;
2524 }
2525 for (curr_el = dst->unit_decl->excl_list, prev_el = NULL;
2526 curr_el != NULL;
2527 prev_el = curr_el, curr_el = curr_el->next_unit_set_el)
2528 if (curr_el->unit_decl == src->unit_decl)
2529 break ;
2530 if (curr_el == NULL)
2531 {
2532 /* Element not found - insert. */
2533 copy = copy_node (src, sizeof (*src));
2534 copy->next_unit_set_el = NULL;
2535 if (prev_el == NULL)
2536 dst->unit_decl->excl_list = copy;
2537 else
2538 prev_el->next_unit_set_el = copy;
2539 }
2540 }
2541 }
注意上面的 dst 以及 src 中的 unit_decl 是其中的某个单元,这个节点中的 excl_list 记录了与其互斥的单元的列表。