接着 genconditions 将产生包含指令描述模式的条件测试部分的数组 insn_conditions 。这个数组将被用于协助优化后端功能单元的生成,我们将在后面的章节看到这一点。
main (continued, genconditions)
199 /* Read the machine description. */
200
201 while (1)
202 {
203 desc = read_md_rtx (&pattern_lineno, &code);
204 if (desc == NULL)
205 break ;
206
207 /* N.B. define_insn_and_split, define_cond_exec are handled
208 entirely within read_md_rtx; we never see them. */
209 switch (GET_CODE (desc))
210 {
211 default :
212 break ;
213
214 case DEFINE_INSN:
215 case DEFINE_EXPAND:
216 add_condition (XSTR (desc, 2));
217 /* except.h needs to know whether there is an eh_return
218 pattern in the machine description. */
219 if (!strcmp (XSTR (desc, 0), "eh_return"))
220 saw_eh_return = 1;
221 break ;
222
223 case DEFINE_SPLIT:
224 case DEFINE_PEEPHOLE:
225 case DEFINE_PEEPHOLE2:
226 add_condition (XSTR (desc, 1));
227 break ;
228 }
229 }
230
231 write_header ();
232 write_conditions ();
233
234 fflush (stdout);
235 return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
236 }
这里,在 203 行, read_md_rtx 几乎不作任何事,因为 insn_elision_unavailable 是 1 ——仅创建它。 read_md_rtx 仅相应地从 define_attr_queue , define_insn_queue 或 other_queue 返回 rtx 对象。
52 static void
53 add_condition (const char *expr) in genconditions.c
54 {
55 struct c_test *test;
56
57 if (expr[0] == 0)
58 return ;
59
60 test = xmalloc (sizeof (struct c_test));
61 test->expr = expr;
62
63 *(htab_find_slot (condition_table , test, INSERT)) = test;
64 }
所有的模式都将被函数 add_condition 加入哈希表 condition_table 。注意传递给 add_condition 的参数,它是模式的条件部分。在 231 行, write_header 输出该输出文件的常量部分。
163 static void
164 write_conditions (void) in genconditions.c
165 {
166 puts ("/
167 /* This table lists each condition found in the machine description./n/
168 Each condition is mapped to its truth value (0 or 1), or -1 if that/n/
169 cannot be calculated at compile time. *//n/
170 /n/
171 const struct c_test insn_conditions[] = {");
172
173 htab_traverse (condition_table , write_one_condition , 0);
174
175 puts ("};/n");
176
177 printf ("const size_t n_insn_conditions = %lu;/n",
178 (unsigned long) htab_elements (condition_table ));
179 puts ("const int insn_elision_unavailable = 0;");
180 }
上面,在 173 行, htab_traverse 将为每个 condition_table 的成员调用 write_one_condition 。在这里这个函数构建了数组 insn_conditions 。注意到在 179 行,当构建 insn-recog.c 时, maybe_eval_c_test 将执行评估,因为现在 insn_elision_unavailable 是 0 了。
140 static int
141 write_one_condition (void **slot, void *dummy ATTRIBUTE_UNUSED) in genconditions.c
142 {
143 const struct c_test *test = * (const struct c_test **) slot;
144 const char *p;
145
146 fputs (" { /"", stdout);
147 for (p = test->expr; *p; p++)
148 {
149 if (*p == '/n')
150 fputs ("//n///n", stdout);
151 else if (*p == '"')
152 fputs ("///"", stdout);
153 else
154 putchar (*p);
155 }
156
157 printf ("/",/n MAYBE_EVAL (%s) },/n", test->expr);
158 return 1;
159 }
上面在 157 行, MAYBE_EVAL 具有如下定义,它同样出现在产生的文件 insn-conditions.c 中(通过 write_header 输出)。
#if (GCC_VERSION >= 3001) || ((GCC_VERSION == 3000) && !__OPTIMIZE__)
# define MAYBE_EVAL(expr) (__builtin_constant_p(expr) ? (int) (expr) : -1)
#else
# define MAYBE_EVAL(expr) -1
#endif
__builtin_constant_p 是 GCC 在 3.0.1 版本之后提供的内建函数,如果 expr 是编译时刻已知的常量,它返回 1 ;否则返回 0 。因此 MAYBE_EVAL ,如果表达式的值是编译时刻可以计算的,就返回这个值,否则返回 -1 。这个宏被 insn-conditions 大量用于其它工具,后面我们可以看到。它确实能帮助减小产生代码的大小,及节省处理时间,因为在处理的某个时间点上,工具可以跳过那些已知不匹配的模式。