GCC-3.4.6源代码学习笔记(16)

2.3. 初始化寄存器集

接下来,跟着init_ttreegeneral_init调用init_reg_sets

对于大多数机器,某些寄存器具有特殊的用途。例如,在x86机器上,esp总是保存栈顶的地址,它不能用于传递函数参数。而在函数调用过程中,根据特定的惯例,其他一些寄存器需要被保存及恢复;而其他则不需要。显然这些都是与机器有关的。

这里init_reg_sets收集芯片系列的通用信息(不同位的芯片的处理相同)。在后面init_reg_sets_1会收集与架构有关的信息(不同位的芯片分别处理)。

 

261  void

262  init_reg_sets (void)                                                                                     in regclass.c

263  {

264    int i, j;

265 

266    /* First copy the register information from the initial int form into

267      the regsets.  */

268 

269    for (i = 0; i < N_REG_CLASSES; i++)

270    {

271      CLEAR_HARD_REG_SET (reg_class_contents[i]);

272 

273      /* Note that we hard-code 32 here, not HOST_BITS_PER_INT.  */

274      for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)

275            if (int_reg_class_contents[i][j / 32]

276              & ((unsigned) 1 << (j % 32)))

277              SET_HARD_REG_BIT (reg_class_contents[i], j);

278    }

279 

280    memcpy (fixed_regs, initial_fixed_regs, sizeof fixed_regs);

281    memcpy (call_used_regs, initial_call_used_regs, sizeof call_used_regs);

282    memset (global_regs, 0, sizeof global_regs);

283 

284    /* Do any additional initialization regsets may need.  */

285    INIT_ONCE_REG_SET ();

286 

287  #ifdef REG_ALLOC_ORDER

288    for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)

289      inv_reg_alloc_order[reg_alloc_order[i]] = i;

290  #endif

291  }

 

同时,某些寄存器能用于多个用途。例如,在x86机器中,edx可用于传递函数参数,也可用于保存地址用于间接访问。因此寄存器需要按用途分组。这种分组对寄存器分配有重要的作用。

上面的reg_class_contents是一个描述寄存器分组的全局数组。其中的每个元素包含足够多的比特用于代表每一个真实的寄存器,因此它可能是整型类型或者整型数组,这取决于寄存器的数目。寄存器都被编号,号码就是对应比特位的索引。对应比特位为1,表示该寄存器属于这个分组。我们看到它仅仅是从int_reg_class_contents中获取其内容。这里使用它,因为它是一个紧凑的形式。

对于x86机器,其寄存器编号如下: ax0),dx1),cx2),bx3),si4),di5),bp6),sp7),st8~ st715),arg16,伪寄存器),flags17),fpsr18dir19),frame20),xmm021~ xmm728),mmx029~ mmx736),r837~ r1544),xmm845~ xmm1552)。因此, FIRST_PSEUDO_REGISTER53。编号的方法通常由ABI(抽象2进制接口)文档给出。

x86系统中,st集(st0 ~ st7)是80位的浮点寄存器。它们构成了环形栈,st7位于栈底,st1在头。Mmx集(mmx0 ~ mmx7)是64位浮点寄存器,与相关的指令集(共57条),用于加速浮点数的计算。第一组sse集(sse0 ~ sse7)是128位浮点寄存器,连同相关的指令集,是mmx的超集。上述寄存器集在32位及64位架构上都出现。

第二组sse集(sse8 ~ sse15)也是128位浮点寄存器,连同增强指令集2。它只出现在64位系统上。同样,r8 ~ r15是引入64位系统的64位通用寄存器。

这些寄存器的分组如下。

 

1257 /* Define the classes of registers for register constraints in the

1258   machine description. Also define ranges of constants.

1259

1260   One of the classes must always be named ALL_REGS and include all hard regs.

1261   If there is more than one class, another class must be named NO_REGS

1262   and contain no registers.

1263

1264   The name GENERAL_REGS must be the name of a class (or an alias for

1265   another name such as ALL_REGS). This is the class of registers

1266   that is allowed by "g" or "r" in a register constraint.

1267   Also, registers outside this class are allocated only when

1268   instructions express preferences for them.

1269

1270   The classes must be numbered in nondecreasing order; that is,

1271   a larger-numbered class must never be contained completely

1272   in a smaller-numbered class.

1273

1274   For any two classes, it is very desirable that there be another

1275   class that represents their union.

1276

1277   It might seem that class BREG is unnecessary, since no useful 386

1278   opcode needs reg %ebx. But some systems pass args to the OS in ebx,

1279   and the "b" register constraint is useful in asms for syscalls.

1280

1281   The flags and fpsr registers are in no class.  */

1282

1283 enum reg_class                                                                                          in i386.h

1284 {

1285   NO_REGS,

1286   AREG, DREG, CREG, BREG, SIREG, DIREG,

1287   AD_REGS,                    /* %eax/%edx for DImode */

1288   Q_REGS,                       /* %eax %ebx %ecx %edx */

1289   NON_Q_REGS,             /* %esi %edi %ebp %esp */

1290   INDEX_REGS,              /* %eax %ebx %ecx %edx %esi %edi %ebp */

1291   LEGACY_REGS,           /* %eax %ebx %ecx %edx %esi %edi %ebp %esp */

1292   GENERAL_REGS,         /* %eax %ebx %ecx %edx %esi %edi %ebp %esp %r8 - %r15*/

1293   FP_TOP_REG, FP_SECOND_REG,      /* %st(0) %st(1) */

1294   FLOAT_REGS,

1295   SSE_REGS,

1296   MMX_REGS,

1297   FP_TOP_SSE_REGS,

1298   FP_SECOND_SSE_REGS,

1299   FLOAT_SSE_REGS,

1300   FLOAT_INT_REGS,

1301   INT_SSE_REGS,

1302   FLOAT_INT_SSE_REGS,

1303   ALL_REGS, LIM_REG_CLASSES

1304 };

 

1307 #define N_REG_CLASSES ((int) LIM_REG_CLASSES)

 

上面init_reg_sets 271行的CLEAR_HARD_REG_SETreg_class_contents置为0274 ~ 278行把reg_class_contents设置成与int_reg_class_contents一致。int_reg_class_contents的内容是机器相关的。在x86系统中,它定义如下。

 

162  #define N_REG_INTS  /

163    ((FIRST_PSEUDO_REGISTER + (32 - 1)) / 32)                                       in regclass.c

164 

165  static const unsigned int_reg_class_contents[N_REG_CLASSES][N_REG_INTS]

166    = REG_CLASS_CONTENTS;

 

1355 #define REG_CLASS_CONTENTS                                       /                    in i386.h

1356 {     { 0x00,     0x0 },                                     /

1357       { 0x01,     0x0 }, { 0x02, 0x0 }, /* AREG, DREG */              /

1358       { 0x04,     0x0 }, { 0x08, 0x0 }, /* CREG, BREG */        /

1359       { 0x10,     0x0 }, { 0x20, 0x0 }, /* SIREG, DIREG */            /

1360       { 0x03,     0x0 },        /* AD_REGS */                   /

1361       { 0x0f,     0x0 },         /* Q_REGS */                     /

1362   { 0x1100f0,  0x1fe0 },          /* NON_Q_REGS */            /

1363       { 0x7f,  0x1fe0 },          /* INDEX_REGS */             /

1364   { 0x1100ff,  0x0 },               /* LEGACY_REGS */          /

1365   { 0x1100ff,  0x1fe0 },          /* GENERAL_REGS */        /

1366      { 0x100,     0x0 }, { 0x0200, 0x0 },/* FP_TOP_REG, FP_SECOND_REG *//

1367     { 0xff00,     0x0 },         /* FLOAT_REGS */             /

1368 { 0x1fe00000,0x1fe000 },           /* SSE_REGS */                  /

1369 { 0xe0000000,    0x1f },          /* MMX_REGS */               /

1370 { 0x1fe00100,0x1fe000 },           /* FP_TOP_SSE_REG */             /

1371 { 0x1fe00200,0x1fe000 },           /* FP_SECOND_SSE_REG */            /

1372 { 0x1fe0ff00,0x1fe000 },            /* FLOAT_SSE_REGS */            /

1373    { 0x1ffff,  0x1fe0 },           /* FLOAT_INT_REGS */             /

1374 { 0x1fe100ff,0x1fffe0 },             /* INT_SSE_REGS */          /

1375 { 0x1fe1ffff,0x1fffe0 },              /* FLOAT_INT_SSE_REGS */     /

1376 { 0xffffffff,0x1fffff }                                             /

1377 }

 

因为寄存器的编号用于对应比特位的索引,这里需要类型(int [2])来保存所有的寄存器(总数53)。我们可以得到以下的表格。

t6

6: x86机器的寄存器分组

init_reg_sets280行,设置有固定用途的寄存器的标识(栈指针,指令寄存器,栈框寄存器等)。initial_fixed_regs被定义如下。在其中每一个数组元素中,第一位比特用于32位系统,第二位比特用于64位系统。

 

77    static const char initial_fixed_regs[] = FIXED_REGISTERS;                         in regclass.c

 

935  /* 1 for registers that have pervasive standard uses

936    and are not available for the register allocator.

937    On the 80386, the stack pointer is such, as is the arg pointer.

938 

939    The value is a mask - bit 1 is set for fixed registers

940    for 32bit target, while 2 is set for fixed registers for 64bit.

941    Proper value is computed in the CONDITIONAL_REGISTER_USAGE.

942  */

943  #define FIXED_REGISTERS                                          /

944  /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7*/ /

945  { 0, 0,  0, 0, 0, 0, 0,  3, 0, 0,  0, 0,  0, 0,  0, 0,   /

946  /*arg,flags,fpsr,dir,frame*/                                /

947    3,  3,   3,  3,  3,                              /

948  /*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/                     /

949     0,    0,    0,    0,    0,    0,    0,    0,               /

950  /*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/                     /

951     0,    0,    0,    0,    0,    0,    0,    0,               /

952  /*  r8,  r9, r10, r11, r12, r13, r14, r15*/                 /

953     1,    1, 1,   1,  1,  1,  1,   1,                     /

954  /*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/          /

955     1,    1,     1,     1,     1,     1,     1,     1}

935          

 

而在init_reg_sets281行,标记有固定用途或者在函数调用中内容不被保留的寄存器。这些寄存器不能分配给生命期跨越多个函数调用的伪寄存器(pseudo reg),除非我们能在调用的间隔,保存及恢复它们。它们也是由对应比特位1来表示。

 

96    static const char initial_call_used_regs[] = CALL_USED_REGISTERS;          in regclass.c

 

958  /* 1 for registers not available across function calls.

959    These must include the FIXED_REGISTERS and also any

960    registers that can be used without being saved.

961    The latter must include the registers where values are returned

962    and the register where structure-value addresses are passed.

963    Aside from that, you can include as many other registers as you like.

964 

965    The value is a mask - bit 1 is set for call used

966    for 32bit target, while 2 is set for call used for 64bit.

967    Proper value is computed in the CONDITIONAL_REGISTER_USAGE.

968  */

969  #define CALL_USED_REGISTERS                                /                           in i386.h

970  /*ax,dx,cx,bx,si,di,bp,sp,st,st1,st2,st3,st4,st5,st6,st7*/ /

971  { 3, 3,  3, 0, 2, 2, 0,  3, 3, 3, 3,  3,  3, 3,  3,  3,       /

972  /*arg,flags,fpsr,dir,frame*/                                /

973    3,  3,   3,  3,  3,                              /

974  /*xmm0,xmm1,xmm2,xmm3,xmm4,xmm5,xmm6,xmm7*/                     /

975     3,    3,    3,     3,    3,   3,     3,    3,                    /

976  /*mmx0,mmx1,mmx2,mmx3,mmx4,mmx5,mmx6,mmx7*/                     /

977     3,    3,    3,     3,    3,   3,     3,    3,                    /

978  /*  r8,  r9, r10, r11, r12, r13, r14, r15*/                 /

979      3,   3,  3,  3,  1,  1,  1,  1,               /

980  /*xmm8,xmm9,xmm10,xmm11,xmm12,xmm13,xmm14,xmm15*/          /

981     3,    3,     3,     3,     3,     3,     3,     3}           /

 

依照上面的数组,我们得到下面的表。

t7

7: x86机器的固定及函数用寄存器组

init_reg_sets285行,INIT_ONCE_REG_SET在当前版本没有定义。而在287行,REG_ALLOC_ORDER如果定义了,表明了分配寄存器的顺序。对于x86机器,在i386.h文件中,这个宏被定义为0 ~ 52的顺序数组。而reg_alloc_orderREG_ALLOC_ORDER初始化。因此,对于x86inv_reg_alloc_order也是0 ~ 52的顺序数组。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值