9. genattrtab 工具
9.1. 概览
上面我们看到了工具 genattr 产生文件 insn-attr.h 。这个文件包含了函数的声明。现在是时候看一下这些函数的定义从何而来。在这里它们由 genattratab 输出。再次的,在本节我们仍然使用上一级的例子。
通常,对于目标平台,有两种机器描述文件。第一种定义了,可以识别输入的 RTL 指令,并为目标平台提供了输出汇编信息的模式。这个文件为所有使用同一个指令集的机器所共享。在 genrecog工具 及 genoutput工具 中,我们已经看到这一点。
而另一个文件是特定于架构的。当前,有两种方式来描述架构,一种是通过利用描述芯片功能单元的 define_function_unit (参考 DEFINE_FUNCTION_UNIT模式的概览 ),而更新的方式是使用以指令的角度来描述芯片的 define_insn_reservation (参考 DEFINE_INSN_RESERVATION模式的概览 )。
除了这些模式,我们还需要其它模式来提供指令的细节。对于旧的方式,可以找到 define_attr , define_insn , define_delay 。而对于新的方式,则使用 define_attr , define_insn , define_delay , define_automaton , define_bypass , present_set 等。
9.2. 程序入口
5988 int
5989 main (int argc, char **argv) in genattrtab.c
5990 {
5991 rtx desc;
5992 struct attr_desc *attr;
5993 struct insn_def *id;
5994 rtx tem;
5995 int i;
5996
5997 progname = "genattrtab";
5998
5999 if (argc <= 1)
6000 fatal ("no input file name");
6001
6002 if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
6003 return (FATAL_EXIT_CODE);
6004
6005 obstack_init (hash_obstack );
6006 obstack_init (temp_obstack );
6007
6008 /* Set up true and false rtx's */
6009 true_rtx = rtx_alloc (CONST_INT);
6010 XWINT (true_rtx , 0) = 1;
6011 false_rtx = rtx_alloc (CONST_INT);
6012 XWINT (false_rtx , 0) = 0;
6013 ATTR_IND_SIMPLIFIED_P (true_rtx ) = ATTR_IND_SIMPLIFIED_P (false_rtx ) = 1;
6014 ATTR_PERMANENT_P (true_rtx ) = ATTR_PERMANENT_P (false_rtx ) = 1;
6015
6016 alternative_name = DEF_ATTR_STRING ("alternative");
6017 length_str = DEF_ATTR_STRING ("length");
6018 delay_type_str = DEF_ATTR_STRING ("*delay_type");
6019 delay_1_0_str = DEF_ATTR_STRING ("*delay_1_0");
6020 num_delay_slots_str = DEF_ATTR_STRING ("*num_delay_slots");
6021
6022 printf ("/* Generated automatically by the program `genattrtab'/n/
6023 from the machine description file `md'. *//n/n");
6024
6025 /* Read the machine description. */
6026
6027 initiate_automaton_gen (argc, argv);
首先我们看一下上面所使用的宏的定义。
98 #define ATTR_IND_SIMPLIFIED_P(RTX) (RTX_FLAG ((RTX), unchanging)) in genattrtab.c
100 #define ATTR_PERMANENT_P(RTX) ( RTX_FLAG ((RTX), integrated)) in genattrtab.c
402 #define RTX_FLAG(RTX, FLAG) ((RTX)->FLAG) in rtl.h
至于 DEF_ATTR_STRING , 它引用函数 attr _string 。这个函数 将把这个字符串保存入哈希表( attr_hash_table )。
382 #define DEF_ATTR_STRING(S) ( attr_string ((S), strlen (S))) in genattrtab.c
778 stati c char *
779 attr_string (const char *str, int len) in genattrtab.c
780 {
781 struct attr_hash *h;
782 int hashcode;
783 int i;
784 char *new_str;
785
786 /* Compute the hash code. */
787 hashcode = (len + 1) * 613 + (unsigned) str[0];
788 for (i = 1; i <= len; i += 2)
789 hashcode = ((hashcode * 613) + (unsigned) str[i]);
790 if (hashcode < 0)
791 hashcode = -hashcode;
792
793 /* Search the table for the string. */
794 for (h = attr_hash_table [hashcode % RTL_HASH_SIZE]; h; h = h->next)
795 if (h->hashcode == -hashcode && h->u.str[0] == str[0]
796 && !strncmp (h->u.str, str, len))
797 return h->u.str; /* <-- return if found. */
798
799 /* Not found; create a permanent copy and add it to the hash table. */
800 new_str = obstack_alloc (hash_obstack , len + 1);
801 memcpy (new_str, str, len);
802 new_str[len] = '/0';
803 attr_hash_add_string (hashcode, new_str);
804
805 return new_str; /* Return the new string. */
806 }
在 794 行,哈希表 attr_hash_table 包含了类型为 attr_hash 的元素,这个类型具有如下定义。
493 struct attr_hash in genattrtab.c
494 {
495 struct attr_hash *next; /* Next structure in the bucket. */
496 int hashcode; /* Hash code of this rtx or string. */
497 union
498 {
499 char *str; /* The string (negative hash codes) */
500 rtx rtl; /* or the RTL recorded here. */
501 } u;
502 };
9.3. 准备工作
像通常一样,这个工具需要读入机器描述文件,并为之构建数据结构。
9634 void
9635 initiate_automaton_gen (int argc, char **argv) in genattrtab.c
9636 {
9637 const char *base_name;
9638 int i;
9639
9640 ndfa_flag = 0;
9641 split_argument = 0; /* default value */
9642 no_minimization_flag = 0;
9643 time_flag = 0;
9644 v_flag = 0;
9645 w_flag = 0;
9646 progress_flag = 0;
9647 for (i = 2; i < argc; i++)
9648 if (strcmp (argv [i], NO_MINIMIZATION_OPTION) == 0)
9649 no_minimization_flag = 1;
9650 else if (strcmp (argv [i], TIME_OPTION) == 0)
9651 time_flag = 1;
9652 else if (strcmp (argv [i], V_OPTION) == 0)
9653 v_flag = 1;
9654 else if (strcmp (argv [i], W_OPTION) == 0)
9655 w_flag = 1;
9656 else if (strcmp (argv [i], NDFA_OPTION) == 0)
9657 ndfa_flag = 1;
9658 else if (strcmp (argv [i], PROGRESS_OPTION) == 0)
9659 progress_flag = 1;
9660 else if (strcmp (argv [i], "-split") == 0)
9661 {
9662 if (i + 1 >= argc)
9663 fatal ("-split has no argument.");
9664 fatal ("option `-split' has not been implemented yet/n");
9665 /* split_argument = atoi (argument_vect [i + 1]); */
9666 }
9667 VLA_PTR_CREATE (decls , 150, "decls");
9668 /* Initialize IR storage. */
9669 obstack_init (&irp );
9670 initiate_automaton_decl_table ();
9671 initiate_insn_decl_table ();
9672 initiate_decl_table ();
9673 output_file = stdout;
9674 output_description_file = NULL;
9675 base_name = base_file_name (argv[1]);
9676 obstack_grow (&irp , base_name,
9677 strlen (base_name) - strlen (file_name_suffix (base_name)));
9678 obstack_grow (&irp , STANDARD_OUTPUT_DESCRIPTION_FILE_SUFFIX,
9679 strlen (STANDARD_OUTPUT_DESCRIPTION_FILE_SUFFIX) + 1);
9680 obstack_1grow (&irp , '/0');
9681 output_description_file_name = obstack_base (&irp );
9682 obstack_finish (&irp );
9683 }
9.3.1. 可变长度数组指针
在这个工具中,使用了一个叫做可变长度数组指针( variable length array pointer )的结构。在上面 9667 行是一个例子。
547 #define VLA_PTR_CREATE(vla, allocated_length, name) / in genautomata.c
548 do /
549 { /
550 vla_ptr_t *const _vla_ptr = &(vla); /
551 /
552 VARRAY_GENERIC_PTR_INIT (_vla_ptr->varray, allocated_length, name);/
553 _vla_ptr->length = 0; /
554 } /
555 while (0)
可变长度数组指针具有如下定义:
138 typedef struct { in genautomata.c
139 size_t length; /* current size of vla. */
140 varray_type varray; /* container for vla. */
132 struct varray_head_tag GTY(()) { in varray.h
133 size_t num_elements; /* Maximum element number allocated. */
134 size_t elements_used; /* The number of elements used, if
135 using VARRAY_PUSH/VARRAY_POP. */
136 enum varray_data_enum type; /* The kind of elements in the varray. */
137 const char *name; /* name of the varray for reporting errors */
138 varray_data GTY ((desc ("%0.type"))) data; /* The data elements follow,
139 must be last. */
140 };
141 typedef struct varray_head_tag *varray_type;
varray_data_enum 显示 vla 可以保存何种数据。其值可以与 varray_data 的成员一一对应。
63 enum varray_data_enum { in varray .h
64 VARRAY_DATA_C,
65 VARRAY_DATA_UC,
66 VARRAY_DATA_S,
67 VARRAY_DATA_US,
68 VARRAY_DATA_I,
69 VARRAY_DATA_U,
70 VARRAY_DATA_L,
71 VARRAY_DATA_UL,
72 VARRAY_DATA_HINT,
73 VARRAY_DATA_UHINT,
74 VARRAY_DATA_GENERIC,
75 VARRAY_DATA_CPTR,
76 VARRAY_DATA_RTX,
77 VARRAY_DATA_RTVEC,
78 VARRAY_DATA_TREE,
79 VARRAY_DATA_BITMAP,
80 VARRAY_DATA_REG,
81 VARRAY_DATA_CONST_EQUIV,
82 VARRAY_DATA_BB,
83 VARRAY_DATA_TE,
84 NUM_VARRAY_DATA
85 };
注意到 varray_data 实际上是一个可变数组,它可以是任意长度,只要系统能支持。
88 typedef union varray_data_tag GTY (()) { in varray.h
89 char GTY ((length ("%0.num_elements"),
90 tag ("VARRAY_DATA_C"))) c[1];
91 unsigned char GTY ((length ("%0.num_elements"),
92 tag ("VARRAY_DATA_UC"))) uc[1];
93 short GTY ((length ("%0.num_elements"),
94 tag ("VARRAY_DATA_S"))) s[1];
95 unsigned short GTY ((length ("%0.num_elements"),
96 tag ("VARRAY_DATA_US"))) us[1];
97 int GTY ((length ("%0.num_elements"),
98 tag ("VARRAY_DATA_I"))) i[1];
99 unsigned int GTY ((length ("%0.num_elements"),
100 tag ("VARRAY_DATA_U"))) u[1];
101 long GTY ((length ("%0.num_elements"),
102 tag ("VARRAY_DATA_L"))) l[1];
103 unsigned long GTY ((length ("%0.num_elements"),
104 tag ("VARRAY_DATA_UL"))) ul[1];
105 HOST_WIDE_INT GTY ((length ("%0.num_elements"),
106 tag ("VARRAY_DATA_HINT"))) hint[1];
107 unsigned HOST_WIDE_INT GTY ((length ("%0.num_elements"),
108 tag ("VARRAY_DATA_UHINT"))) uhint[1];
109 PTR GTY ((length ("%0.num_elements"), use_param (""),
110 tag ("VARRAY_DATA_GENERIC"))) generic[1];
111 char *GTY ((length ("%0.num_elements"),
112 tag ("VARRAY_DATA_CPTR"))) cptr[1];
113 rtx GTY ((length ("%0.num_elements"),
114 tag ("VARRAY_DATA_RTX"))) rtx[1];
115 rtvec GTY ((length ("%0.num_elements"),
116 tag ("VARRAY_DATA_RTVEC"))) rtvec[1];
117 tree GTY ((length ("%0.num_elements"),
118 tag ("VARRAY_DATA_TREE"))) tree[1];
119 struct bitmap_head_def *GTY ((length ("%0.num_elements"),
120 tag ("VARRAY_DATA_BITMAP"))) bitmap[1];
121 struct reg_info_def *GTY ((length ("%0.num_elements"), skip (""),
122 tag ("VARRAY_DATA_REG"))) reg[1];
123 struct const_equiv_data GTY ((length ("%0.num_elements"),
124 tag ("VARRAY_DATA_CONST_EQUIV"))) const_equiv[1];
125 struct basic_block_def *GTY ((length ("%0.num_elements"), skip (""),
126 tag ("VARRAY_DATA_BB"))) bb[1];
127 struct elt_list *GTY ((length ("%0.num_elements"),
128 tag ("VARRAY_DATA_TE"))) te[1];
上面在 VLA_PTR_CREATE 中 , 在 552 行 , VARRAY_GENERIC_PTR_INIT 为该 varray 分配内存 , 并且元素的类型将是 VARRAY_DATA_GENERIC ( varray_data 的 PTR ) 。
177 #define VARRAY_GENERIC_PTR_INIT(va, num, name) / in varray.h
178 va = varray_init (num, VARRAY_DATA_GENERIC, name)
115 varray_type
116 varray_init (size_t num_elements, enum varray_data_enum element_kind, in varray.c
117 const char *name)
118 {
119 size_t data_size = num_elements * element[element_kind].size;
120 varray_type ptr;
121 #ifdef GATHER_STATISTICS
122 struct varray_descriptor *desc = varray_descriptor (name);
123
124 desc->created++;
125 desc->allocated += data_size + VARRAY_HDR_SIZE;
126 #endif
127 if (element[element_kind].uses_ggc)
128 ptr = ggc_alloc_cleared (VARRAY_HDR_SIZE + data_size);
129 else
130 ptr = xcalloc (VARRAY_HDR_SIZE + data_size, 1);
131
132 ptr->num_elements = num_elements;
133 ptr->elements_used = 0;
134 ptr->type = element_kind;
135 ptr->name = name;
136 return ptr;
137 }
然后接着,用于声明的哈希表由下面的函数来初始化。
2237 static void
2238 initiate_automaton_decl_table (void) in genattrtab.c
2239 {
2240 work_automaton_decl.mode = dm_automaton;
2241 automaton_decl_table = htab_create (10, automaton_decl_hash,
2242 automaton_decl_eq_p, (htab_del) 0);
2243 }
2336 static void
2337 initiate_insn_decl_table (void) in genattrtab.c
2338 {
2339 work_insn_decl.mode = dm_insn_reserv;
2340 insn_decl_table = htab_create (10, insn_decl_hash, insn_decl_eq_p,
2341 (htab_del) 0);
2342 }
2438 static void
2439 initiate_decl_table (void) in genattrtab.c
2440 {
2441 work_decl.mode = dm_unit;
2442 decl_table = htab_create (10, decl_hash, decl_eq_p, (htab_del) 0);
2443 }
接着 main ,在分配了所需的资源之后,系统开始读入机器描述文件。
main (continued)
5988 while (1)
5989 {
5990 int lineno;
5991
5992 desc = read_md_rtx (&lineno, &insn_code_number );
5993 if (desc == NULL)
5994 break ;
5995
5996 switch (GET_CODE (desc))
5997 {
5998 case DEFINE_INSN:
5999 case DEFINE_PEEPHOLE:
6000 case DEFINE_ASM_ATTRIBUTES:
6001 gen_insn (desc, lineno);
6002 break ;
6003
6004 case DEFINE_ATTR:
6005 gen_attr (desc, lineno);
6006 break ;
6007
6008 case DEFINE_DELAY:
6009 gen_delay (desc, lineno);
6010 break ;
6011
6012 case DEFINE_FUNCTION_UNIT:
6013 gen_unit (desc, lineno);
6014 break ;
6015
6016 case DEFINE_CPU_UNIT:
6017 gen_cpu_unit (desc);
6018 break ;
6019
6020 case DEFINE_QUERY_CPU_UNIT:
6021 gen_query_cpu_unit (desc);
6022 break ;
6023
6024 case DEFINE_BYPASS:
6025 gen_bypass (desc);
6026 break ;
6027
6028 case EXCLUSION_SET:
6029 gen_excl_set (desc);
6030 break ;
6031
6032 case PRESENCE_SET:
6033 gen_presence_set (desc);
6034 break ;
6035
6036 case FINAL_PRESENCE_SET:
6037 gen_final_presence_set (desc);
6038 break ;
6039
6040 case ABSENCE_SET:
6041 gen_absence_set (desc);
6042 break ;
6043
6044 case FINAL_ABSENCE_SET:
6045 gen_final_absence_set (desc);
6046 break ;
6047
6048 case DEFINE_AUTOMATON:
6049 gen_automaton (desc);
6050 break ;
6051
6052 case AUTOMATA_OPTION:
6053 gen_automata_option (desc);
6054 break ;
6055
6056 case DEFINE_RESERVATION:
6057 gen_reserv (desc);
6058 break;
6059
6060 case DEFINE_INSN_RESERVATION:
6061 gen_insn_reserv (desc);
6062 break ;
6063
6064 default :
6065 break ;
6066 }
6067 if (GET_CODE (desc) != DEFINE_ASM_ATTRIBUTES)
6068 insn_index_number ++;
6069 }