接下来,跟着init_ttree,general_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机器,其寄存器编号如下: ax(0),dx(1),cx(2),bx(3),si(4),di(5),bp(6),sp(7),st(8)~ st7(15),arg(16,伪寄存器),flags(17),fpsr(18)dir(19),frame(20),xmm0(21)~ xmm7(28),mmx0(29)~ mmx7(36),r8(37)~ r15(44),xmm8(45)~ xmm15(52)。因此, FIRST_PSEUDO_REGISTER是53。编号的方法通常由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_SET把reg_class_contents置为0。274 ~ 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)。我们可以得到以下的表格。
表 6: x86机器的寄存器分组
在init_reg_sets的280行,设置有固定用途的寄存器的标识(栈指针,指令寄存器,栈框寄存器等)。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_sets的281行,标记有固定用途或者在函数调用中内容不被保留的寄存器。这些寄存器不能分配给生命期跨越多个函数调用的伪寄存器(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} /
依照上面的数组,我们得到下面的表。
表 7: x86机器的固定及函数用寄存器组
在init_reg_sets的285行,INIT_ONCE_REG_SET在当前版本没有定义。而在287行,REG_ALLOC_ORDER如果定义了,表明了分配寄存器的顺序。对于x86机器,在i386.h文件中,这个宏被定义为0 ~ 52的顺序数组。而reg_alloc_order被REG_ALLOC_ORDER初始化。因此,对于x86,inv_reg_alloc_order也是0 ~ 52的顺序数组。