GCC's bacl-end & assemble emission (40)

来源:互联网 发布:c语言bzero 编辑:程序博客网 时间:2024/04/30 14:05

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_modesincludesfile 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. */        inmachmode.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"                                                                 ingenmodes.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 theprecision,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 bynew_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);                                                 inmachmode.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 byRANDOM_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) \                                                        ingenmodes.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 ofmode_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 asadjustmentparameter 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);                                                                inmachmode.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 ofmode_data, and it is indexed by modeclasses. The element of this array is allocated bynew_mode.

Back make_complex_modes, at line 447, as now we arecreating a complex mode, we need record mode for the components. Note thatncomponentsfield 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 inmake_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__);      ingenmodes.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.