GCC后端及汇编发布(40)

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

11.   genmodes工具

11.1.  概览

工具genmodes从machmode.def及i386-modes.def输出insn-modes.h及insn-modes.c,machmode.def定义所有为GCC使用的机器模式(machine mode),而i386-modes.def定义了特定于i386的机器模式。

11.2.  程序入口

 

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. */        inmachmode.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"                                                                 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.  构建模式(mode)

11.3.1.     构建int模式(modes)

当我们为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)时,这个模式必须是之前不存在的。

11.3.1.1.             构建float模式(mode)

那么对于浮点模式(mode),在machmode.def文件中,有:

 

173  FLOAT_MODE(SF, 4, ieee_single_format);                                                 inmachmode.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是一个描述格式名字的字符串。

11.3.1.2.             构建CC模式(mode)

这个模式(mode),仅在目标机器需要它,才应该被定义。因此在i386-modes.def里,我们可以找到如下代码片段。

 

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)

 

这些模式(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  }

11.3.1.3.             构建BLK及void模式(mode)

如果没有模式需要被指定,就使用VOIDmode,而BLKmode用于结构体,数组等,它们不适用更具体的模式。这两个模式由machmode.def中的RANDOM_MODE构建。

11.3.1.4.             为可调整格式构建数据

可调整格式的原型是:

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) \                                                        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 %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_bytesizeadj_alignmentadj_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传入。

11.3.1.5.             构建复数模式(mode)

在machmode.def中,我们同样可以看到如下用于复数的模式。

 

186  COMPLEX_MODES(INT);                                                                inmachmode.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。

11.3.1.6.             构建向量模式(vector modes)

在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                                                                                           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     /*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__);      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  }

 

可以看到这个模式的名字实际上与VECTOR_MODES的相同。实际上这两个模式是相同的,仅有的区别在于指定向量大小的方式。


原创粉丝点击