9.5. Construct DFA-based pipeline hazards recognizer
9.5.1. Decl created for DEFINE_AUTOMATON pattern
In gen_automaton , we see that the pattern transformed into rtx object will be saved into decl instance. For the example used in 9.3.9 Read in DEFINE_AUTOMATON pattern , we have seen that the rtx object as following. This example comes from file pentium.md.
Then treated by gen_automaton , we will get following data structure. Notice that in fact in the vector is pointer of the decl.
figure 61 : example of decl objects for DEFINE_AUTOMATON pattern
9.5.2. Decl created for DEFINE_CPU_UNIT pattern
Also for the example in 9.3.6 Read in DEFINE_CPU_UNIT pattern , we have seen the rtx object as following. This example is from file pentium.md
Then treated by gen_cpu_unit , we will get following data structure. Notice that in fact, in the vector is pointer of the decl.
figure 62 : example of decl objects for DEFINE_CUP_UNIT pattern
9.5.3. Decl created for DEFINE_BYPASS pattern
Then for example of DEFINE_BYPASS, we have seen that the rtx object created from md file is as following. This example is from file pentium.md.
Then treated by gen_bypass , we will get following data structure. All decls are linked. Notice that in fact, in the vector is pointer of the decl.
figure 63 : example of decl objects for DEFINE_BYPASS pattern
9.5.4. Decl created for EXCULSION_SET pattern
Then for example of EXCLUSION_SET, we have seen that the rtx object created from md file is as following. This example is from file itantium.md.
We know that above two strings describe two set of units that excluded from each other. Then treated by gen_excl_set , we will get following data structure. All decls are linked. Notice that in fact, in the vector is pointer of the decl.
figure 64 : decl objects created for EXCLUSION_SET pattern
9.5.5. Decl created for DEFINE_RESERVATION pattern
Then for example of DEFINE_RESERVATION, we have seen that the rtx object created from md file is as following. This example is from file pentium.md.
Then treated by gen_reserv , we will get following data structure.
figure 65 : example of decl objects for DEFINE_RESERVATION pattern
9.5.6. Decl created for DEFINE_INSN_RESERVATION pattern
Then for example of DEFINE_INSN_RESERVATION, we have seen that the rtx object created from md file is as following. This example is from file pentium.md
Then treated by gen_insn_reserv , we will get following data structure.
figure 66 : declexample of objects for DEFINE_INSN_RESERVATION pattern
9.5.7. Handling of decls
The purpose of instruction scheduler is to issue intructions as many as possible. Pipeline hazards recognizer can tell scheduler whether certain instruction can execute with those running. All needed information is recorded dispersedly within related patterns in machine description files, but expand_automata will organize these informations and produce structured data for building DFA-based pipeline hazards recognizer.
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 first creates a description object to collect all decls created, which has definition in following.
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 };
In expand_automata till line 9832, following description object will be created.
figure 67 : example of description
Then check_all_description will handle this object in following way.
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. 1st Loop of Processing Decls – DECL_AUTOMATON
process_decls handling decls within six loops. In first loop, it needs find out how many automatons declared, and create data objects which must be ready for coming loops.
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 }
The first treated is decl of DEFINE_AUTOMATON pattern. This kind of decl is saved into static hash table automaton_decl_table . See that the name of automaton must be unique, otherwise triggers warning or error.
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. 2nd Loop of Processing Decls – DECL_UNIT
This loop just binds the decl of CPU unit with the automaton it belongs to.
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 }
The processes of decl of define_insn_reservation and define_bypass patterns are quite simple. Above, macros DECL_* accesses corresponding member of union field of decl .
At line 2221, we have seen check_attr_test before. This function will validate given attribute, and tranform related expression into so-called canonical form. For example, converts (eq_attr "att" "a1,a2") to (ior (eq_attr “att” “a1” ) (eq_attrq “att” “a2”)). Another example, converts (eq_attr "att" "!a1") to (not (eq_attr "att" "a1"))
At line 2227, insert_insn_decl will insert the decls of define_insn_reservation pattern into static hash table insn_decl_table .
Begin at line 2863, for decl of define_cpu_unit pattern, it will be bound with decl of corresponding define_automaton pattern as following.
figure 68 : example of decl of DEFINE_CPU_UNIT
9.5.7.3. 3rd Loop of Processing Decls – DECL_BYPASS
We know that define_bypass pattern is used to describe exceptions in the latency time for given instruction pair. It records the latency time that the result generated by the instructions given in string out_insn_name s will be ready for the instructions given in string in_insn_name s. The third loop binds decls of define_bypass with decls of define_insn_reservation pattern, which describes CPU units usage. (refer to 8.1.3 Overview of DEFINE_INSN_RESERVATION pattern ).
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 }
For our examples, we can get below figure (object “penrt_call” is omitted here).
figure 69 : example of decl of DECL_BYPASS
9.5.7.4. 4th Loop of Processing Decls – DECL_EXCL
This loop fills decls of define_cpu_unit pattern according to corresponding decl_excl.
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 }
At line 2978 and 2981, unit_set_el_list and unit_set_el_list_2 record units that exclusive to each other. process_excls will create the data related. Note field first_list_length tolds how many initial elements of names comes from the first group, and all_names_num indicates how many units present totally.
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 }
We see that decls of define_cpu_unit pattern having same name with the decl of define_bypass will be linked tegother. This list is constructed by unit_set_el as following.
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 ;
After creating the two lists, as they record units excluding each other, add_excls fills unit decl s of src_list in the next_unit_set_el of unit decl s in dst_list .
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 }
Note that unit_decl in dst and src is one of the units, in which excl_list records the list of units excluded by it.