工具genmodes从machmode.def及i386-modes.def输出insn-modes.h及insn-modes.c,machmode.def定义所有为GCC使用的机器模式(machine mode),而i386-modes.def定义了特定于i386的机器模式。
1182 int
1183 main(int argc, char**argv) ingenmodes.c
1184 {
1185 bool gen_header = false, gen_min = false;
1186 progname = argv[0];
1187
1188 if (argc == 1)
1189 ;
1190 else if (argc == 2 && !strcmp(argv[1], "-h"))
1191 gen_header = true;
1192 else if (argc == 2 && !strcmp (argv[1], "-m"))
1193 gen_min = true;
1194 else
1195 {
1196 error ("usage: %s [-h|-m] >file", progname);
1197 returnFATAL_EXIT_CODE;
1198 }
1199
1200 modes_by_name = htab_create_alloc (64, hash_mode,eq_mode, 0, xcalloc, free);
1201
1202 create_modes ();
1203 complete_all_modes();
1204
1205 if (have_error)
1206 returnFATAL_EXIT_CODE;
1207
1208 calc_wider_mode();
1209
1210 if (gen_header)
1211 emit_insn_modes_h ();
1212 else if (gen_min)
1213 emit_min_insn_modes_c ();
1214 else
1215 emit_insn_modes_c ();
1216
1217 if (fflush (stdout) || fclose (stdout))
1218 returnFATAL_EXIT_CODE;
1219 returnSUCCESS_EXIT_CODE;
1220 }
在处理了程序选项及构建了哈希表modes_by_name之后,create_modes包含引入了文件machmode.def。
639 static void
640 create_modes (void) ingenmodes.c
641 {
642 #include "machmode.def"
643 }
在这个文件中,我们将遇到如下代码片段。
180 /* Allow the targetto specify additional modes of various kinds. */ in machmode.def
181 #if HAVE_EXTRA_MODES
182 # include EXTRA_MODES_FILE
183 #endif
另外,在这个程序里,我们将使用枚举值mode_class,以及静态数组mode_class_names,其中mode_class给出所有可用的模式(mode)类别,而mode_class_names给出了每个类别的名字。这些数据来自mode-classes.def。这个文件的内容是:
#define MODE_CLASSES \
DEF_MODE_CLASS (MODE_RANDOM), /* other */ \
DEF_MODE_CLASS (MODE_CC), /* condition code in a register */\
DEF_MODE_CLASS (MODE_INT), /* integer */ \
DEF_MODE_CLASS (MODE_PARTIAL_INT), /* integer with padding bits */ \
DEF_MODE_CLASS (MODE_FLOAT), /* floating point */ \
DEF_MODE_CLASS (MODE_COMPLEX_INT), /* complex numbers */ \
DEF_MODE_CLASS (MODE_COMPLEX_FLOAT), \
DEF_MODE_CLASS (MODE_VECTOR_INT), /* SIMD vectors */ \
DEF_MODE_CLASS (MODE_VECTOR_FLOAT)
那么在genmodes中,我们可以找到以下代码片段。
29 #include "mode-classes.def" in genmodes.c
30
31 #define DEF_MODE_CLASS(M) M
32 enummode_class { MODE_CLASSES, MAX_MODE_CLASS };
33 #undef DEF_MODE_CLASS
34
35 /* Text names ofmode classes, for output. */
36 #define DEF_MODE_CLASS(M) #M
37 static const char *const mode_class_names[MAX_MODE_CLASS] =
38 {
39 MODE_CLASSES
40 };
41 #undef DEF_MODE_CLASS
42 #undef MODE_CLASSES
当我们为i386系统构建GCC时,EXTRA_MODES_FILE将被configure产生入auto-host.h,其定义是“config/i386/i386-modes.def”。在这两个定义文件中,使用了一系列的宏,这些宏被定义在genmodes.c里。例如,
158 INT_MODE (QI, 1); inmachmode.def
159 INT_MODE (HI, 2);
160 INT_MODE (SI, 4);
161 INT_MODE (DI, 8);
162 INT_MODE (TI, 16);
153 FRACTIONAL_INT_MODE (BI, 1, 1);
宏INT_MODE具有原型INT_MODE (MODE, BYTESIZE),它声明MODE具有类别INT并且宽度为BYTESIZE个字节。如下所示。
而宏FRACTIONAL_INT_MODE具有原型FRACTIONAL_INT_MODE (MODE, PRECISION, BYTESIZE),它声明MODE具有类别INT,并且存储宽度为BYTESIZE个字节,但仅有PRECISION个有效比特。
511 #define INT_MODE(N, Y) FRACTIONAL_INT_MODE (N, -1, Y)
512 #define FRACTIONAL_INT_MODE(N, B, Y) \
513 make_int_mode (#N, B, Y, __FILE__,__LINE__)
514
515 static void
516 make_int_mode (const char *name, ingenmodes.c
517 unsigned int precision, unsigned intbytesize,
518 constchar *file, unsigned int line)
519 {
520 struct mode_data*m = new_mode (MODE_INT, name, file, line);
521 m->bytesize = bytesize;
522 m->precision = precision;
523 }
模式(mode)的数据被保持在结构体mode_data里,它具有如下定义。看到INT_MODE并不在意precision,它与bytesize一样大。
53 struct mode_data ingenmodes.c
54 {
55 struct mode_data *next; /* next thisclass - arbitrary order */
56
57 const char *name; /* printable mode name -- SI,not SImode */
58 enum mode_class class; /* this modeclass */
59 unsigned int precision; /* size in bits, equiv to TYPE_PRECISION */
60 unsigned int bytesize; /* storage size in addressable units */
61 unsigned int ncomponents; /* number of subunits */
62 unsigned int alignment; /* mode alignment */
63 const char *format; /* floatingpoint format - MODE_FLOAT only */
64
65 struct mode_data *component; /* mode ofcomponents */
66 struct mode_data *wider; /*next wider mode */
67
68 struct mode_data *contained; /* Pointer to listof modes that have
69 this mode as acomponent. */
70 struct mode_data *next_cont; /* Next mode in thatlist. */
71
72 const char *file; /* file and line of definition, */
73 unsigned int line; /* for error reporting */
74 };
这个结构体由new_mode生成,这个函数具有以下定义。
143 static struct mode_data *
144 new_mode (enum mode_class class, const char *name, ingenmodes.c
145 const char*file, unsigned int line)
146 {
147 struct mode_data*m;
148
149 m = find_mode (name);
150 if (m)
151 {
152 error ("%s:%d: duplicate definition of mode \"%s\"",
153 trim_filename (file), line, name);
154 error ("%s:%d: previous definition here", m->file,m->line);
155 return m;
156 }
157
158 m = xmalloc (sizeof (struct mode_data));
159 memcpy (m, &blank_mode, sizeof(struct mode_data));
160 m->class = class;
161 m->name = name;
162 if (file)
163 m->file= trim_filename (file);
164 m->line = line;
165
166 m->next = modes[class];
167 modes[class]= m;
168 n_modes[class]++;
169
170 *htab_find_slot (modes_by_name, m, INSERT) = m;
171
172 return m;
173 }
在GCC里,模式(mode)的名字保存在哈希表modes_by_name中,find_mode在这个哈希表中查找已存在的模式(mode)名字。注意到这个哈希表是由new_mode管理的,因此当在这个函数中加入模式(mode)时,这个模式必须是之前不存在的。
那么对于浮点模式(mode),在machmode.def文件中,有:
173 FLOAT_MODE(SF, 4, ieee_single_format); in machmode.def
174 FLOAT_MODE (DF, 8, ieee_double_format);
这个宏具有原型FLOAT_MODE (MODE, BYTESIZE,FORMAT),它声明MODE具有类别FLOAT,并且宽度为BYTESIZE个字节,使用浮点格式FORMAT。
526 #define FLOAT_MODE(N, Y, F) FRACTIONAL_FLOAT_MODE (N, -1, Y, F)
527 #define FRACTIONAL_FLOAT_MODE(N, B, Y, F) \
528 make_float_mode (#N, B, Y, #F, __FILE__,__LINE__)
529
530 static void
531 make_float_mode (const char *name,
532 unsigned int precision, unsigned int bytesize,
533 const char *format,
534 const char *file, unsigned int line)
535 {
536 structmode_data *m = new_mode(MODE_FLOAT, name, file, line);
537 m->bytesize = bytesize;
539 m->precision = precision;
539 m->format = format;
540 }
其处理几乎与INT_MODE的处理相同。注意在这里format是一个描述格式名字的字符串。
这个模式(mode),仅在目标机器需要它,才应该被定义。因此在i386-modes.def里,我们可以找到如下代码片段。
59 CC_MODE(CCGC); in i386-modes.def
60 CC_MODE (CCGOC);
61 CC_MODE (CCNO);
62 CC_MODE (CCZ);
63 CC_MODE (CCFP);
64 CC_MODE(CCFPU)
这些模式(mode)是特定于i386系统的。它们的含义是:
l CCNO表示要求不设置溢出标记的与0的比较。取而代之使用符号位测试,因而可以被用于构成“a&b>0”类型的测试。
l CCGC表示允许在进位标记中存在未指定内容的与0的比较。这个模式可以被inc/dec指令所使用。
l CCGOC表示允许在溢出标记及进位标记中存在未指定内容的与0的比较。这个模式用于模拟,使用sub/cmp/add操作的,(a-b)及(a+b)与0的比较。
l CCZ表示仅零(Zero)标记是有效的。
501 #define _SPECIAL_MODE(C, N) make_special_mode(MODE_##C, #N, __FILE__,__LINE__)
502 #define RANDOM_MODE(N) _SPECIAL_MODE(RANDOM, N)
503 #define CC_MODE(N) _SPECIAL_MODE (CC, N)
504
505 static void
506 make_special_mode (enum mode_class class, const char *name,
507 const char*file, unsigned int line)
508 {
509 new_mode (class, name, file, line);
510 }
如果没有模式需要被指定,就使用VOIDmode,而BLKmode用于结构体,数组等,它们不适用更具体的模式。这两个模式由machmode.def中的RANDOM_MODE构建。
可调整格式的原型是:
ADJUST_BYTESIZE (MODE, EXPR);
ADJUST_ALIGNMENT (MODE, EXPR);
ADJUST_FLOAT_FORMAT (MODE, EXPR);
它们安排MODE的字节大小,对齐,或浮点格式为运行时可调整。EXPR将在处理了所有的命令行选项后执行一次,并且应该求值为所期望的字节大小,对齐,或格式。在i386-modes.def中,我们可以看到如下声明。
29 FLOAT_MODE(XF, 12, ieee_extended_intel_96_format); ini386-modes.def
30 ADJUST_FLOAT_FORMAT(XF, (TARGET_128BIT_LONG_DOUBLE
31 ? &ieee_extended_intel_128_format
32 : TARGET_96_ROUND_53_LONG_DOUBLE
33 ? &ieee_extended_intel_96_round_53_format
34 : &ieee_extended_intel_96_format));
35 ADJUST_BYTESIZE (XF, TARGET_128BIT_LONG_DOUBLE ? 16 : 12);
36 ADJUST_ALIGNMENT(XF, TARGET_128BIT_LONG_DOUBLE ? 16 : 4);
x86_64 ABI同时指定了XF及TF模式(mode)。Xfmode是__float80,它是IEEE的扩展;Tfmode是__float128,它是IEEE quad。IEEE扩展的宽度是128位,除了在ILP32模式中,不过我们必须称其为12字节,使得bitsize及wider_mode表都能正确设置。我们据此正其大小。
632 #define _ADD_ADJUST(A, M, X, C) \ in genmodes.c
633 new_adjust (#M, &adj_##A, #A, #X,MODE_##C, __FILE__, __LINE__)
634
635 #define ADJUST_BYTESIZE(M, X) _ADD_ADJUST(bytesize,M, X, RANDOM)
636 #define ADJUST_ALIGNMENT(M, X) _ADD_ADJUST (alignment, M, X, RANDOM)
637 #define ADJUST_FLOAT_FORMAT(M, X) _ADD_ADJUST(format, M, X, FLOAT)
195 static void ATTRIBUTE_UNUSED
196 new_adjust (const char *name, ingenmodes.c
197 structmode_adjust **category, const char *catname,
198 const char*adjustment,
199 enummode_class required_class,
200 const char*file, unsigned int line)
201 {
202 struct mode_data*mode = find_mode (name);
203 struct mode_adjust*a;
204
205 file = trim_filename (file);
206
207 if (!mode)
208 {
209 error ("%s:%d: no mode \"%s\"", file, line, name);
210 return;
211 }
212
213 if (required_class != MODE_RANDOM && mode->class !=required_class)
214 {
215 error ("%s:%d: mode \"%s\" is not class %s",
216 file, line, name, mode_class_names[required_class]+ 5);
217 return;
218 }
219
220 for (a = *category; a; a = a->next)
221 if (a->mode == mode)
222 {
223 error ("%s:%d: mode\"%s\" already has a %s adjustment",
224 file, line, name, catname);
225 error ("%s:%d: previous adjustment here", a->file,a->line);
226 return;
227 }
228
229 a = xmalloc (sizeof (struct mode_adjust));
230 a->mode = mode;
231 a->adjustment = adjustment;
232 a->file = file;
233 a->line = line;
234
235 a->next = *category;
236 *category = a;
237 }
至于上面的三个调整,细节由adj_bytesize,adj_alignment,adj_format给出,它们是下面mode_adjust的列表。
92 struct mode_adjust ingenmodes.c
93 {
94 struct mode_adjust *next;
95 struct mode_data*mode;
96 const char *adjustment;
97
98 const char *file;
99 unsigned int line;
100 };
相同类型的调整链接在一起。注意对于这三个调整,调整的数据被作为new_adjust的参数adjustment传入。
在machmode.def中,我们同样可以看到如下用于复数的模式。
186 COMPLEX_MODES(INT); in machmode.def
187 COMPLEX_MODES(FLOAT);
上面宏的原型是COMPLEX_MODES (CLASS),对于当前所有声明在类别CLASS中的模式,它构建对应的复数模式。这个宏具有如下定义。
400 #define COMPLEX_MODES(C) make_complex_modes(MODE_##C, __FILE__, __LINE__)
401 static void ingenmodes.c
402 make_complex_modes (enum mode_class class,
403 const char*file, unsigned int line)
404 {
405 struct mode_data*m;
406 struct mode_data*c;
407 char buf[8];
408 enum mode_class cclass = complex_class (class);
409
410 if (cclass == MODE_RANDOM)
411 return;
412
413 for (m = modes[class]; m; m = m->next)
414 {
415 /* Skip BImode. FIXME: BImode probablyshouldn't be MODE_INT. */
416 if (m->precision == 1)
417 continue;
418
419 if (strlen (m->name) >= sizeofbuf)
420 {
421 error ("%s:%d:mode name \"%s\" is too long",
422 m->file, m->line, m->name);
423 continue;
424 }
425
426 /* Float complex modes are named SCmode, etc.
427 Int complex modes are named CSImode, etc.
428 This inconsistency should beeliminated. */
429 if (class == MODE_FLOAT)
430 {
431 char *p;
432 strncpy (buf, m->name, sizeof buf);
433 p = strchr (buf, 'F');
434 if (p == 0)
435 {
436 error ("%s:%d: float mode \"%s\" has no 'F'",
437 m->file, m->line, m->name);
438 continue;
439 }
440
441 *p = 'C';
442 }
443 else
444 snprintf (buf, sizeof buf, "C%s", m->name);
445
446 c = new_mode (cclass, xstrdup (buf), file,line);
447 c->component = m;
448 }
449 }
complex_class仅是把MODE_INT及MODE_FLOAT映射到相应的复数模式。
107 static enum mode_class
108 complex_class (enum mode_class class) ingenmodes.c
109 {
110 switch (class)
111 {
112 case MODE_INT: returnMODE_COMPLEX_INT;
113 case MODE_FLOAT: return MODE_COMPLEX_FLOAT;
114 default:
115 error ("no complex class for class %s",mode_class_names[class]);
116 return MODE_RANDOM;
117 }
118 }
在make_complex_modes的413行,modes是一个mode_data的数组,并且它以模式类别为索引。这个数组的单元由new_mode来分配。
回到make_complex_modes,在447行,因为现在我们正在构建一个复数模式,我们需要为这些元素记录模式。注意ncomponents域不在这里设置,不过我们知道它是2。
在machmode.def文件中,有如下代码片段。
190 VECTOR_MODES (INT, 2); /* V2QI */ in machmode.def
191 VECTOR_MODES (INT, 4); /* V4QI V2HI */
192 VECTOR_MODES (INT, 8); /* V8QI V4HIV2SI */
193 VECTOR_MODES (INT, 16); /* V16QI V8HI V4SI V2DI */
这些宏具有原型VECTOR_MODES (CLASS, WIDTH),对于当前所有声明在类别CLASS中的模式,它构建相应的宽度为WIDTH的向量模式。CLASS必须是INT或者FLOAT。这个宏被如下定义在genmodes.c里。
453 #define VECTOR_MODES(C, W) make_vector_modes(MODE_##C,W, __FILE__, __LINE__)
454 static void in genmodes.c
455 make_vector_modes (enum mode_class class, unsignedint width,
456 const char*file, unsigned int line)
457 {
458 struct mode_data*m;
459 struct mode_data*v;
460 char buf[8];
461 unsigned int ncomponents;
462 enum mode_class vclass = vector_class (class);
463
464 if (vclass == MODE_RANDOM)
465 return;
466
467 for (m = modes[class]; m; m = m->next)
468 {
469 /* Do not construct vector modes with only oneelement, or
470 vector modes where the element sizedoesn't divide the full
471 size evenly. */
472 ncomponents = width / m->bytesize;
473 if (ncomponents < 2)
474 continue;
475 if (width % m->bytesize)
476 continue;
477
478 /*Skip QFmode and BImode. FIXME: this special case should
479 not be necessary. */
480 if (class == MODE_FLOAT && m->bytesize == 1)
481 continue;
482 if (class == MODE_INT && m->precision == 1)
483 continue;
484
485 if ((size_t)snprintf (buf, sizeof buf,"V%u%s", ncomponents, m->name)
486 >= sizeof buf)
487 {
488 error ("%s:%d: mode name \"%s\" is too long",
489 m->file, m->line, m->name);
490 continue;
491 }
492
493 v = new_mode (vclass, xstrdup (buf), file,line);
494 v->component = m;
495 v->ncomponents = ncomponents;
496 }
497 }
vector_class为向量模式执行映射。
120 static enum mode_class
121 vector_class (enum mode_class class) ingenmodes.c
122 {
123 switch (class)
124 {
125 case MODE_INT: returnMODE_VECTOR_INT;
126 case MODE_FLOAT: return MODE_VECTOR_FLOAT;
127 default:
128 error ("no vector class for class %s", mode_class_names[class]);
129 return MODE_RANDOM;
130 }
131 }
这个新的模式也是由new_mode来构建,看到在make_vector_modes的495行,设置了ncomponents域。注意在472行确定这个数值的方法。
同样在machmode.def里,有另一个用于向量模式声明的宏。
197 VECTOR_MODE (INT, SI, 8) inmachmode.def
198 VECTOR_MODE (INT, DI, 4);
199 VECTOR_MODE (INT, DI, 8);
这个宏具有原型VECTOR_MODE (CLASS, MODE,COUNT),它声明了一个具有COUNT个元素的向量模式,其元素是MODE(类别CLASS)。CLASS必须是INT或FLOAT。这个向量模式的名字具有形式VnX,其中n是十进制的COUNT,而X是MODE。
591 #define VECTOR_MODE(C,M, N) \
592 make_vector_mode (MODE_##C, #M, N, __FILE__,__LINE__); in genmodes.c
593 static void ATTRIBUTE_UNUSED
594 make_vector_mode (enum mode_class bclass,
595 const char*base,
596 unsigned int ncomponents,
597 const char*file, unsigned int line)
598 {
599 struct mode_data*v;
600 enum mode_class vclass = vector_class (bclass);
601 struct mode_data*component = find_mode (base);
602 char namebuf[8];
603
604 if (vclass == MODE_RANDOM)
605 return;
606 if (component == 0)
607 {
608 error ("%s:%d: no mode \"%s\"", file, line, base);
609 return;
610 }
611 if (component->class != bclass)
612 {
613 error ("%s:%d: mode \"%s\" is not class %s",
614 file, line, base, mode_class_names[bclass] + 5);
615 return;
616 }
617
618 if ((size_t)snprintf (namebuf, sizeofnamebuf, "V%u%s",
619 ncomponents,base) >= sizeof namebuf)
620 {
621 error ("%s:%d: mode name \"%s\" is too long",
622 base, file, line);
623 return;
624 }
625
626 v = new_mode (vclass, xstrdup (namebuf), file,line);
627 v->ncomponents = ncomponents;
628 v->component = component;
629 }
可以看到这个模式的名字实际上与VECTOR_MODES的相同。实际上这两个模式是相同的,仅有的区别在于指定向量大小的方式。