11. Toolof genmodes
11.1. Overview
Tool of genmodes outputs insn-modes.h and insn-modes.c from machmode.defwhich defines all the MACHINE MODES used by GCC and i386-modes.def whichdefines MACHINE MODES special for i386.
11.2. Program Entry
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 }
After handling program options and creates hash table modes_by_name,create_modes includesfile machmode.def.
639 static void
640 create_modes (void) ingenmodes.c
641 {
642 #include "machmode.def"
643 }
In this file, we will encounter following code fragment.
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
Besides, in the program, we will use the enumerate value mode_class,and static array mode_class_names, in which mode_class gives out all availableclasses of modes, and mode_class_names gives out the name of each class. Thesedata come from mode-classes.def. The content of the file is:
#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)
Then in genmodes, we can find following code fragment.
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
11.3. Creating modes
11.3.1. Creatingint modes
When we build GCC for i386 system, EXTRA_MODES_FILE will be generatedby configure into auto-host.h which is "config/i386/i386-modes.def".In both def files there are series macros which are defined in genmodes.c. Forexample,
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);
The macro INT_MODE has prototype INT_MODE (MODE, BYTESIZE) which declares MODE tobe of class INT and BYTESIZE bytes wide. As following definition demonstrates.
And macro FRACTIONAL_INT_MODE has prototype FRACTIONAL_INT_MODE (MODE, PRECISION,BYTESIZE) which declares MODE to be of class INT, BYTESIZE byteswide in storage, but with only PRECISION significant bits.
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 const char *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 }
Data of mode is kept in structure mode_data,it has definition in below. See that INT_MODE doesn’t care about the precision,it is as wide as 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 };
This structure is created by new_mode, which has following definition.
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 }
In GCC, name of modes are kept in hash table modes_by_name, find_mode will search thehash table for the existing modes name. Note that the hash table is managed by new_mode, sowhen adding mode in this function, it should not exist before.
11.3.1.1. Creating float modes
Then for float mode, in machmode.def file, there is:
173 FLOAT_MODE(SF, 4, ieee_single_format); in machmode.def
174 FLOAT_MODE (DF, 8, ieee_double_format);
The macro has prototype FLOAT_MODE (MODE, BYTESIZE, FORMAT) whichdeclares MODE to be of class FLOAT and BYTESIZE bytes wide, using floatingpoint format 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 }
The treatment is almost same as that of INT_MODE. Notice that formathere is a string describing the name of format.
11.3.1.2. Creating CC modes
This mode should be defined only the target needs it. So ini386-modes.def we can find following code fragment.
59 CC_MODE(CCGC); ini386-modes.def
60 CC_MODE (CCGOC);
61 CC_MODE (CCNO);
62 CC_MODE (CCZ);
63 CC_MODE (CCFP);
64 CC_MODE (CCFPU)
These modes are i386 system specific. Their meaning are:
l CCNO to indicate comparisonsagainst zero that requires Overflow flag to be unset. Sign bit test is usedinstead and thus can be used to form "a&b>0" type of tests.
l CCGC to indicate comparisons againstzero that allows unspecified garbage in the Carry flag. This mode is used byinc/dec instructions.
l CCGOC to indicate comparisonsagainst zero that allows unspecified garbage in the Carry and Overflow flag.This mode is used to simulate comparisons of (a-b) and (a+b) against zero usingsub/cmp/add operations.
l CCZ to indicate that only theZero flag is valid.
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 }
11.3.1.3. Creating modes for BLK & Void
VOIDmode is used when no mode needs to be specified, and BLKmode isused for structures, arrays, etc. that fit no more specific mode. These twomodes are created by RANDOM_MODE in machmode.def.
11.3.1.4. Creating data for adjustable format
The adjustable formats have prototypes:
ADJUST_BYTESIZE (MODE, EXPR);
ADJUST_ALIGNMENT (MODE, EXPR);
ADJUST_FLOAT_FORMAT (MODE, EXPR);
They arrange for the byte size, alignment, or floating point formatof MODE to be adjustable at run time. EXPR will be executed once afterprocessing all command line options, and should evaluate to the desired bytesize, alignment, or format. In i386-modes.def, we can see followingdeclarations.
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 specifies both XF and TF modes. XFmode is __float80 whichis IEEE extended; TFmode is __float128 which is IEEE quad. IEEE extended is 128bits wide, except in ILP32 mode, but we have to say it's 12 bytes so that thebitsize and wider_mode tables are correctly set up. We correct its size asabove.
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 %sadjustment",
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 }
For above three adjustments, the details are given by adj_bytesize,adj_alignment,adj_formatwhich are list of mode_adjust as following.
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 };
Adjustment of the same type is linked tegother. Note that for thesethree type of adjustments, the data of adjustment is passed as adjustmentparameter of new_adjust.
11.3.1.5. Creating complex modes
In machmode.def, we also can see modes for complex data asfollowing.
186 COMPLEX_MODES(INT); in machmode.def
187 COMPLEX_MODES(FLOAT);
The prototype of above macro is COMPLEX_MODES (CLASS) which, for all modespresently declared in class CLASS, constructs corresponding complex modes. Themacro has definition as following.
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 only maps MODE_INT and MODE_FLOAT to corresponding complex modes.
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 }
At line 413 in make_complex_modes,modesis an array of mode_data, and it is indexed by modeclasses. The element of this array is allocated by new_mode.
Back make_complex_modes, at line 447, as now we arecreating a complex mode, we need record mode for the components. Note that ncomponentsfield is not set here, but we know it is 2.
11.3.1.6. Creating vector modes
In machmode.def file, there is following code fragment.
190 VECTOR_MODES (INT, 2); /* V2QI */ in machmode.def
191 VECTOR_MODES (INT, 4); /* V4QIV2HI */
192 VECTOR_MODES (INT, 8); /* V8QI V4HIV2SI */
193 VECTOR_MODES (INT, 16); /* V16QI V8HI V4SI V2DI */
The macros have prototype of VECTOR_MODES (CLASS, WIDTH), which, for all modespresently declared in class CLASS, constructs corresponding vector modes havingwidth WIDTH. CLASS must be INT or FLOAT.The macro is defined in genmodes.c as following.
453 #define VECTOR_MODES(C, W) make_vector_modes(MODE_##C,W, __FILE__, __LINE__)
454 static void ingenmodes.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 /* SkipQFmode 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_classdoes the mapping for vector modes.
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 }
The new modes are also created by new_mode, see that at line 495 in make_vector_modes, ncomponents field is set. Noticethe way to decide the number at line 472.
Also in machmode.def, there is another macro for vector modedeclaration.
197 VECTOR_MODE (INT, SI, 8) inmachmode.def
198 VECTOR_MODE (INT, DI, 4);
199 VECTOR_MODE (INT, DI, 8);
The macro has prototype of VECTOR_MODE (CLASS, MODE, COUNT) which declares avector mode whose component mode is MODE (of class CLASS) with COUNTcomponents. CLASS must be INT or FLOAT. Thename of the vector mode takes the form VnX where n is COUNT in decimal and X isMODE.
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 }
It can see that the name of the mode is the same as that of VECTOR_MODES.In fact these two modes are same; the only difference is the way to design thesize of vector.