10. genopinit工具
10.1. 概览
这个工具将从机器描述文件输出insn-opinit.c。这个文件提供函数init_all_optabs来把内建函数与枚举insn_code绑定一起。而通过这个值,能显示该指令是否被支持。
10.2. 程序入口
332 int
333 main (int argc, char **argv) ingenopinit.c
334 {
335 rtx desc;
336
337 progname= "genopinit";
338
339 if (argc <= 1)
340 fatal ("no input file name");
341
342 if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
343 return (FATAL_EXIT_CODE);
344
345 printf ("/* Generated automatically by the program `genopinit'\n\
346 from the machine description file `md'. */\n\n");
347
348 printf ("#include\"config.h\"\n");
349 printf("#include \"system.h\"\n");
350 printf ("#include \"coretypes.h\"\n");
351 printf ("#include \"tm.h\"\n");
352 printf ("#include \"rtl.h\"\n");
353 printf ("#include \"flags.h\"\n");
354 printf ("#include \"insn-config.h\"\n");
355 printf ("#include \"recog.h\"\n");
356 printf ("#include \"expr.h\"\n");
357 printf ("#include\"optabs.h\"\n");
358 printf ("#include\"reload.h\"\n\n");
359
360 printf("void\ninit_all_optabs (void)\n{\n");
361
362 puts ("\
363 #ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC\n\
364 int i, j;\n\
365 #endif\n");
366
367 /* Read the machine description. */
368
369 while (1)
370 {
371 int line_no, insn_code_number = 0;
372
373 desc = read_md_rtx (&line_no,&insn_code_number);
374 if (desc == NULL)
375 break;
376
377 if (GET_CODE (desc) ==DEFINE_INSN || GET_CODE (desc) == DEFINE_EXPAND)
378 gen_insn (desc);
379 }
380
381 puts ("\
382 \n\
383 #ifdef FIXUNS_TRUNC_LIKE_FIX_TRUNC\n\
384 /* This flag says the same insns that convertto a signed fixnum\n\
385 also convert validly to an unsigned one. */\n\
386 for (i = 0; i <NUM_MACHINE_MODES; i++)\n\
387 for (j = 0; j <NUM_MACHINE_MODES; j++)\n\
388 ufixtrunc_optab->handlers[i][j].insn_code\n\
389 =sfixtrunc_optab->handlers[i][j].insn_code;\n\
390 #endif\n\
391 }");
392
393 fflush (stdout);
394 return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
395 }
对应define_insn或define_expand模式的每个rtx对象将由gen_insn来处理。
162 static void
163 gen_insn (rtx insn) in genopinit.c
164 {
165 const char *name = XSTR (insn, 0);
166 int m1 = 0, m2 = 0, op = 0;
167 size_t pindex;
168 int i;
169 const char *np, *pp, *p, *q;
170
171 /* Don't mention instructions whose names arethe null string.
172 They are in the machine description just tobe recognized. */
173 if (*name == 0)
174 return;
175
176 /* See if NAME matches one of the patterns wehave for the optabs we know
177 about. */
178
179 for (pindex = 0; pindex < ARRAY_SIZE(optabs);pindex++)
180 {
181 int force_float = 0, force_int = 0, force_partial_int = 0;
182 int force_consec = 0;
183 int matches = 1;
184
185 for (pp = optabs[pindex]; pp[0] != '$' ||pp[1] != '('; pp++)
186 ;
187
188 for (pp += 2, np = name; matches&& ! (pp[0] == '$' && pp[1] == ')');
189 pp++)
190 {
191 if (*pp != '$')
192 {
193 if (*pp != *np++)
194 break;
195 }
196 else
197 switch (*++pp)
198 {
199 case'N':
200 force_consec = 1;
201 break;
202 case'I':
203 force_int = 1;
204 break;
205 case'P':
206 force_partial_int = 1;
207 break;
208 case'F':
209 force_float = 1;
210 break;
211 case'V':
212 break;
213 case'c':
214 for(op = 0; op < NUM_RTX_CODE; op++)
215 {
216 for(p = GET_RTX_NAME(op), q = np; *p; p++, q++)
217 if (*p != *q)
218 break;
219
220 /* Wehave to be concerned about matching "gt" and
221 missing "gtu", e.g.,so verify we have reached the
222 end of thing we are tomatch. */
223 if (*p == 0 && *q == 0&& GET_RTX_CLASS(op) == '<')
224 break;
225 }
226
227 if (op == NUM_RTX_CODE)
228 matches = 0;
229 else
230 np += strlen (GET_RTX_NAME(op));
231 break;
232 case'a':
233 case'b':
234 /* Thisloop will stop at the first prefix match, so
235 look through the modes in reverseorder, in case
236 there are extra CC modes and CCis a prefix of the
237 CC modes (as it should be). */
238 for(i = (MAX_MACHINE_MODE) - 1; i >= 0; i--)
239 {
240 for(p = GET_MODE_NAME(i), q = np; *p; p++, q++)
241 if (TOLOWER (*p) != *q)
242 break;
243
244 if (*p == 0
245 && (! force_int ||mode_class[i] == MODE_INT
246 || mode_class[i] ==MODE_VECTOR_INT)
247 && (!force_partial_int
248 || mode_class[i] ==MODE_INT
249 || mode_class[i] == MODE_PARTIAL_INT
250 || mode_class[i] ==MODE_VECTOR_INT)
251 && (! force_float ||mode_class[i] == MODE_FLOAT
252 || mode_class[i] ==MODE_VECTOR_FLOAT))
253 break;
254 }
255
256 if (i < 0)
257 matches = 0;
258 else if (*pp == 'a')
259 m1 = i, np += strlen (GET_MODE_NAME(i));
260 else
261 m2 = i, np += strlen (GET_MODE_NAME(i));
262
263 force_int = force_partial_int = force_float =0;
264 break;
265
266 default:
267 abort ();
268 }
269 }
270
271 if (matches && pp[0] == '$' && pp[1] == ')'
272 && *np == 0
273 && (! force_consec || (int) GET_MODE_WIDER_MODE(m1) == m2))
274 break;
275 }
数据optabs 具有如下的定义。
61 static const char * const optabs[] = in genopinit.c
62 {"sext_optab->handlers[$B][$A].insn_code =CODE_FOR_$(extend$a$b2$)",
63 "zext_optab->handlers[$B][$A].insn_code =CODE_FOR_$(zero_extend$a$b2$)",
64 "sfix_optab->handlers[$B][$A].insn_code =CODE_FOR_$(fix$F$a$I$b2$)",
65 "ufix_optab->handlers[$B][$A].insn_code =CODE_FOR_$(fixuns$F$a$b2$)",
66 "sfixtrunc_optab->handlers[$B][$A].insn_code = CODE_FOR_$(fix_trunc$F$a$I$b2$)",
67 "ufixtrunc_optab->handlers[$B][$A].insn_code =CODE_FOR_$(fixuns_trunc$F$a$I$b2$)",
68 …
以62行的内容为例子,在gen_insn的185行将扫描这个字符串直到遇到“$(”。然后188行的FOR循环将检测子字符串“extend$a$b2$”。接着在193行,检查define_insn或define_expand的名字是否匹配“extend”。对于i386系统,为了匹配这些子字符串,我们以以下的define_insn模式作为例子。
3227 (define_expand"extendsidi2" in i386.c
3228 [(parallel [(set (match_operand:DI 0"register_operand" "")
3229 (sign_extend:DI (match_operand:SI 1 "register_operand""")))
3230 (clobber (reg:CC 17))
3231 (clobber (match_scratch:SI 2 ""))])]
3232 ""
3233 {
3234 if (TARGET_64BIT)
3235 {
3236 emit_insn (gen_extendsidi2_rex64(operands[0], operands[1]));
3237 DONE;
3238 }
3239 })
在匹配之后,我们遇到子字符串“$a$b2$”。
在这个字符串中,“$a”及“$b”被用于匹配一个短的模式(mode)名(模式名部分不包括“mode”并转换到小写)。当输出这个初始值时,使用整个字符串。“$A”及“$B”为该模式的完整名字所替代;“$a”及“$b”则如上所示,为这个模式名字的短短形式所替代。 如果在这个模式(pattern)中出现了“$N”,这意味着这两个模式(mode)必须是同一个模式(mode)类别中,具有相邻长度的(比如,Qimode与Himode)。“$I”则表示下一个模式(mode)仅考虑完整的整数模式(mode),而“$F”则表示仅考虑浮点模式(mode)。“$P”表示完整的及部分的整数模式(mode)都应该考虑。“$V”表示如果第一个模式(mode)是MODE_FLOAT模式,输出‘'v’。
gen_insn (continued)
277 if (pindex == ARRAY_SIZE (optabs))
278 return;
279
280 /* We found a match. If this pattern is onlyconditionally present,
281 write out the "if" and two extrablanks. */
282
283 if (*XSTR (insn, 2) != 0)
284 printf (" if(HAVE_%s)\n ", name);
285
286 printf (" ");
287
288 /* Now write out the initialization, makingall required substitutions. */
289 for (pp = optabs[pindex]; *pp; pp++)
290 {
291 if (*pp != '$')
292 putchar (*pp);
293 else
294 switch (*++pp)
295 {
296 case '(': case ')':
297 case 'I': case'F': case'N':
298 break;
299 case 'V':
300 if (GET_MODE_CLASS (m1) ==MODE_FLOAT)
301 printf ("v");
302 break;
303 case 'a':
304 for(np = GET_MODE_NAME(m1); *np; np++)
305 putchar (TOLOWER (*np));
306 break;
307 case 'b':
308 for(np = GET_MODE_NAME(m2); *np; np++)
309 putchar (TOLOWER (*np));
310 break;
311 case 'A':
312 printf ("%smode",GET_MODE_NAME(m1));
313 break;
314 case 'B':
315 printf ("%smode",GET_MODE_NAME(m2));
316 break;
317 case 'c':
318 printf ("%s",GET_RTX_NAME(op));
319 break;
320 case 'C':
321 for(np = GET_RTX_NAME(op); *np; np++)
322 putchar (TOUPPER (*np));
323 break;
324 }
325 }
326
327 printf (";\n");
328 }
注意在284行,宏HAVE_`insn-name`在genflags工具一节中输出,该宏的细节参考着一节。仅当这些宏等于1时,才把指令编号赋给相应的optab。
然后在289行的FOR循环为这个optab输出初始编号。等于我们的例子,sext_optab被定义为convert_optab_table[CTI_sext],其定义为convert_optab。照这个结构体定义模式(mode)间某种转换操作。
等于我们的例子,我们将得到如下代码片段。
sext_optab->handlers[SImode][HImode].insn_code = CODE_FOR_extendhisi2;
sext_optab->handlers[HImode][QImode].insn_code= CODE_FOR_extendqihi2;
sext_optab->handlers[SImode][QImode].insn_code = CODE_FOR_extendqisi2;
上面handlers的定义是optab_handler,域insn_code是enum insn_code,它显示在一个特定机器模式(mode)上,如何为这个操作生成一条指令。如果在目标机器上没有这样的指令,它是CODE_FOR_nothing。enum insn_code由gencodes(gencodes工具)产生。