接下来,init_emit_once初始化浮点常量。
init_emit_once (continue)
5546 REAL_VALUE_FROM_INT (dconst0, 0, 0, double_mode);
5547 REAL_VALUE_FROM_INT (dconst1, 1, 0, double_mode);
5548 REAL_VALUE_FROM_INT (dconst2, 2, 0, double_mode);
5549 REAL_VALUE_FROM_INT (dconst3, 3, 0, double_mode);
5550 REAL_VALUE_FROM_INT (dconst10, 10, 0, double_mode);
5551 REAL_VALUE_FROM_INT (dconstm1, -1, -1, double_mode);
5552 REAL_VALUE_FROM_INT (dconstm2, -2, -1, double_mode);
5553
5554 dconsthalf = dconst1;
5555 dconsthalf.exp--;
5556
5557 real_arithmetic (&dconstthird, RDIV_EXPR, &dconst1, &dconst3);
5558
5559 /* Initialize mathematical constants for constant folding builtins.
5560 These constants need to be given to at least 160 bits precision. */
5561 real_from_string (&dconstpi,
5562 "3.1415926535897932384626433832795028841971693993751058209749445923078");
5563 real_from_string (&dconste,
5564 "2.7182818284590452353602874713526624977572470936999595749669676277241");
REAL_VALUE_FROM_INT用于从整数常量创建RTX浮点常量。形如dconst…都是real_value类型的全局变量。
279 #define REAL_VALUE_FROM_INT(r, lo, hi, mode) / in real.h
280 real_from_integer (&(r), mode, lo, hi, 0)
接着在init_emit_once中的5554行,为浮点数常量1/2创建对象,接着在5557行,为1/3创建对象,在5561及5563行,则是π和e。
init_emit_once (continue)
5566 for (i = 0; i < (int) ARRAY_SIZE (const_tiny_rtx); i++)
5567 {
5568 REAL_VALUE_TYPE *r =
5569 (i == 0 ? &dconst0 : i == 1 ? &dconst1 : &dconst2);
5570
5571 for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
5572 mode = GET_MODE_WIDER_MODE (mode))
5573 const_tiny_rtx[i][(int) mode] =
5574 CONST_DOUBLE_FROM_REAL_VALUE (*r, mode);
5575
5576 const_tiny_rtx[i][(int) VOIDmode] = GEN_INT (i);
5577
5578 for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
5579 mode = GET_MODE_WIDER_MODE (mode))
5580 const_tiny_rtx[i][(int) mode] = GEN_INT (i);
5581
5582 for (mode = GET_CLASS_NARROWEST_MODE (MODE_PARTIAL_INT);
5583 mode != VOIDmode;
5584 mode = GET_MODE_WIDER_MODE (mode))
5585 const_tiny_rtx[i][(int) mode] = GEN_INT (i);
5586 }
5587
5588 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
5589 mode != VOIDmode;
5590 mode = GET_MODE_WIDER_MODE (mode))
5591 const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode);
5592
5593 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
5594 mode != VOIDmode;
5595 mode = GET_MODE_WIDER_MODE (mode))
5596 const_tiny_rtx[0][(int) mode] = gen_const_vector_0 (mode);
5597
5598 for (i = (int) CCmode; i < (int) MAX_MACHINE_MODE; ++i)
5599 if (GET_MODE_CLASS ((enum machine_mode) i) == MODE_CC)
5600 const_tiny_rtx[0][i] = const0_rtx;
5601
5602 const_tiny_rtx[0][(int) BImode] = const0_rtx;
5603 if (STORE_FLAG_VALUE == 1)
5604 const_tiny_rtx[1][(int) BImode] = const1_rtx;
5605
5606 #ifdef RETURN_ADDRESS_POINTER_REGNUM
5607 return_address_pointer_rtx
5608 = gen_raw_REG (Pmode, RETURN_ADDRESS_POINTER_REGNUM);
5609 #endif
5610
5611 #ifdef STATIC_CHAIN_REGNUM
5612 static_chain_rtx = gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM);
5613
5614 #ifdef STATIC_CHAIN_INCOMING_REGNUM
5615 if (STATIC_CHAIN_INCOMING_REGNUM != STATIC_CHAIN_REGNUM)
5616 static_chain_incoming_rtx
5617 = gen_rtx_REG (Pmode, STATIC_CHAIN_INCOMING_REGNUM);
5618 else
5619 #endif
5620 static_chain_incoming_rtx = static_chain_rtx;
5621 #endif
5622
5623 #ifdef STATIC_CHAIN
5624 static_chain_rtx = STATIC_CHAIN;
5625
5626 #ifdef STATIC_CHAIN_INCOMING
5627 static_chain_incoming_rtx = STATIC_CHAIN_INCOMING;
5628 #else
5629 static_chain_incoming_rtx = static_chain_rtx;
5630 #endif
5631 #endif
5632
5633 if ((unsigned) PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
5634 pic_offset_table_rtx = gen_raw_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
5635 }
同样在上面,const_tiny_rtx是一个全局数组,它的定义为:rtx const_tiny_rtx[3][(int) MAX_MACHINE_MODE]。它记录了可能的具有各种可用模式的浮点或整型常量0,1及2。确保了这些对象的唯一性及全局性。
在5574行,CONST_DOUBLE_FROM_REAL_VALUE用于从值0.0,1.0及2.0来创建浮点常量的rtx对象。
350 #define CONST_DOUBLE_FROM_REAL_VALUE(r, m) / in real.h
351 const_double_from_real_value (r, m)
436 rtx
437 const_double_from_real_value (REAL_VALUE_TYPE value, enum machine_mode mode)
438 {
439 rtx real = rtx_alloc (CONST_DOUBLE);
440 PUT_MODE (real, mode);
441
442 memcpy (&CONST_DOUBLE_LOW (real), &value, sizeof (REAL_VALUE_TYPE));
443
444 return lookup_const_double (real);
445 }
下面的宏用于处理rtx对象中的浮点值。其中的XCWINT访问rtx对象的rtunion部分的hwint域。
1050 #define CONST_DOUBLE_LOW(r) XCWINT (r, 0, CONST_DOUBLE) in rtl.h
1051 #define CONST_DOUBLE_HIGH(r) XCWINT (r, 1, CONST_DOUBLE)
1052 #define CONST_DOUBLE_REAL_VALUE(r) ((struct real_value *)&CONST_DOUBLE_LOW(r))
在上面444行,lookup_const_double在哈希表const_double_htab中查找指定对象是否已经创建。如果找到,就直接返回这个对象,否则由该函数创建新对象并插入哈希表中。
GEN_INT是创建整数常量rtx对象的函数。
1882 #define GEN_INT(N) gen_rtx_CONST_INT (VOIDmode, (HOST_WIDE_INT) (N)) in rtl.h
389 rtx
390 gen_rtx_CONST_INT (enum machine_mode mode ATTRIBUTE_UNUSED, HOST_WIDE_INT arg)
391 {
392 void **slot;
393
394 if (arg >= - MAX_SAVED_CONST_INT && arg <= MAX_SAVED_CONST_INT)
395 return const_int_rtx[arg + MAX_SAVED_CONST_INT];
396
397 #if STORE_FLAG_VALUE != 1 && STORE_FLAG_VALUE != -1
398 if (const_true_rtx && arg == STORE_FLAG_VALUE)
399 return const_true_rtx;
400 #endif
401
402 /* Look up the CONST_INT in the hash table. */
403 slot = htab_find_slot_with_hash (const_int_htab, &arg,
404 (hashval_t) arg, INSERT);
405 if (*slot == 0)
406 *slot = gen_rtx_raw_CONST_INT (VOIDmode, arg);
407
408 return (rtx) *slot;
409 }
在init_emit_once的5591及5596行,gen_const_vector_0用于为向量模式创建0常量。结果亦存于const_tiny_rtx中。
5402 static rtx
5403 gen_const_vector_0 (enum machine_mode mode) in emit-rtl.c
5404 {
5405 rtx tem;
5406 rtvec v;
5407 int units, i;
5408 enum machine_mode inner;
5409
5410 units = GET_MODE_NUNITS (mode);
5411 inner = GET_MODE_INNER (mode);
5412
5413 v = rtvec_alloc (units);
5414
5415 /* We need to call this function after we to set CONST0_RTX first. */
5416 if (!CONST0_RTX (inner))
5417 abort ();
5418
5419 for (i = 0; i < units; ++i)
5420 RTVEC_ELT (v, i) = CONST0_RTX (inner);
5421
5422 tem = gen_rtx_raw_CONST_VECTOR (mode, v);
5423 return tem;
5424 }
在5410和5411行,宏GET_MODE_NUNITS及GET_MODE_INNER从mode_nunits 及 mode_inner中提取指定的元素。它们亦是由工具genmodes产生,输入至insn-modes.c文件中。mode_nunits定义了向量的大小。mode_inner定义了向量中元素的机器模式。
在5406行,类型rtvec被定义为指向rtvec_def结构的指针。Rtvec_def是rtunion中的一个域。
261 struct rtvec_def GTY(()) { in rtl.h
262 int num_elem; /* number of elements */
263 rtx GTY ((length ("%h.num_elem"))) elem[1];
264 };
在5420行的RTVEC_ELT用于访问rtvec中指定的元素。
343 #define RTVEC_ELT(RTVEC, I) __extension__ / in rtl.h
344 (*({ rtvec const _rtvec = (RTVEC); const int _i = (I); /
345 if (_i < 0 || _i >= GET_NUM_ELEM (_rtvec)) /
346 rtvec_check_failed_bounds (_rtvec, _i, __FILE__, __LINE__, /
347 __FUNCTION__); /
348 &_rtvec->elem[_i]; }))
在上面的5416行,宏CONST0_RTX从const_tiny_rtx中选择具有指定模式的对象。
1789 #define CONST0_RTX(MODE) (const_tiny_rtx[0][(int) (MODE)]) in rtl.h
在5422行,gen_rtx_raw_CONST_VECTOR的定义如下:
235 #define gen_rtx_raw_CONST_VECTOR(MODE, ARG0) / in genrtl.h
236 gen_rtx_fmt_E (CONST_VECTOR, (MODE), (ARG0))
gen_rtx_fmt_E亦是由工具gengenrtl产生,并输出至genrtl.c文件。从其名字,可以知道它所创建的rtx对象仅具有一个类型为rtvec的子对象。
在init_emit_once的余下部分,在5603行,STORE_FLAG_VALUE对于x86系统为1,在5606行,RETURN_ADDRESS_POINTER_REGNUM没有被定义,在5614,5623及5626行STATIC_CHAIN_INCOMING_REGNUM,STATIC_CHAIN_INCOMING,STATIC_CHAIN在x86系统中均没有定义。
在5611行,宏STATIC_CHAIN_REGNUM指明了用于传递给函数的静态链(static chain)的寄存器的编号。对于32位的ABI(例如pentium)使用的是ecx。而对于64位ABI(例如IA64)ecx是一个参数寄存器,因而使用r10。
在允许嵌套词法作用域的语言中,指向包含域(the enclosing scope)的活动记录(一个包含,特定函数或其他类似函数的语言构造的调用实例的,重要状态信息的数据结构)的指针——这个指针被称为静态链。在大多数这样的语言中,通常要求在调用链的某个位置,包含函数(the enclosing function)已被调用(在并发语言里,函数可能在不同的线程中被调用)。而在C/C++这样的语言里,嵌套词法作用域是不允许或受限(标准C/C++不允许函数嵌套函数),静态链不是必须的。但GNU C++提供了一个扩展,支持函数嵌套函数。
最后,init_emit_once创建保存用于访问位置无关代码中数据项基址的寄存器的rtx对象。对于64位的x86系统,PIC_OFFSET_TABLE_REGNUM被定义为INVALID_REGNUM——不创建pic_offset_table_rtx。为了避免不必要地破坏调用保存的寄存器,gcc尽可能对pic寄存器重编号。此处,起先,ebx被设为这个PIC寄存器。
回到backend_init,对于机器来说,寄存器是很宝贵的资源。在运行程序时,很多次的,需要把寄存器的内容放到内存中,使它可以被用于下一条指令,然后在需要时再把这个内容从内存中恢复回来。然而寄存器和内存间过多的交换将产生瓶颈。因此寄存器的分配必须小心仔细。为了便利寄存器的分配,寄存器,根据其用处及特定环境下其可用性,进行分组,随后组间的关系被尽可能地收集。所有这一切由函数init_regs完成。
561 void
562 init_regs (void) in regclass.c
563 {
564 /* This finishes what was started by init_reg_sets, but couldn't be done
565 until after register usage was specified. */
566 init_reg_sets_1 ();
567
568 init_reg_autoinc ();
569 }
296 static void
297 init_reg_sets_1 (void) in regclass.c
298 {
299 unsigned int i, j;
300 unsigned int /* enum machine_mode */ m;
301 char allocatable_regs_of_mode [MAX_MACHINE_MODE];
302
303 /* This macro allows the fixed or call-used registers
304 and the register classes to depend on target flags. */
305
306 #ifdef CONDITIONAL_REGISTER_USAGE
307 CONDITIONAL_REGISTER_USAGE;
308 #endif
回忆在init_reg_sets中,已经收集了与目标机器相关的寄存器信息,并保存至fixed_regs,call_used_regs,reg_class_content。这些信息描述了,对于机器的各种变种,可用的寄存器及其能力,因此现在需要根据作为目标机器使用的变种,来细化信息。这个更新由CONDITIONAL_REGISTER_USAGE来完成。
1005 /* Macro to conditionally modify fixed_regs/call_used_regs. */ in i386.h
1006 #define CONDITIONAL_REGISTER_USAGE /
1007 do { /
1008 int i; /
1009 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) /
1010 { /
1011 fixed_regs[i] = (fixed_regs[i] & (TARGET_64BIT ? 2 : 1)) != 0; /
1012 call_used_regs[i] = (call_used_regs[i] /
1013 & (TARGET_64BIT ? 2 : 1)) != 0; /
1014 } /
1015 if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM) /
1016 { /
1017 fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; /
1018 call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; /
1019 } /
1020 if (! TARGET_MMX) /
1021 { /
1022 int i; /
1023 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) /
1024 if (TEST_HARD_REG_BIT (reg_class_contents[(int)MMX_REGS], i)) /
1025 fixed_regs[i] = call_used_regs[i] = 1; /
1026 } /
1027 if (! TARGET_SSE) /
1028 { /
1029 int i; /
1030 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) /
1031 if (TEST_HARD_REG_BIT (reg_class_contents[(int)SSE_REGS], i)) /
1032 fixed_regs[i] = call_used_regs[i] = 1; /
1033 } /
1034 if (! TARGET_80387 && ! TARGET_FLOAT_RETURNS_IN_80387) /
1035 { /
1036 int i; /
1037 HARD_REG_SET x; /
1038 COPY_HARD_REG_SET (x, reg_class_contents[(int)FLOAT_REGS]); /
1039 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) /
1040 if (TEST_HARD_REG_BIT (x, i)) /
1041 fixed_regs[i] = call_used_regs[i] = 1; /
1042 } /
1043 } while (0)
上面,记住对于fixed_regs,call_used_regs中的每个字节,非0值表示,对于特定的机器变种,该寄存器不可用。第一个比特用于32位系统,第二个比特用于64位系统(参见表6:x86机器的寄存器分组)。
因为寄存器集间有重合部分,某些集合是其他集合的子集。接下来就是要找出这些关系。
init_reg_sets_1 (continue)
310 /* Compute number of hard regs in each class. */
311
312 memset (reg_class_size, 0, sizeof reg_class_size);
313 for (i = 0; i < N_REG_CLASSES; i++)
314 for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
315 if (TEST_HARD_REG_BIT (reg_class_contents[i], j))
316 reg_class_size[i]++;
317
318 /* Initialize the table of subunions.
319 reg_class_subunion[I][J] gets the largest-numbered reg-class
320 that is contained in the union of classes I and J. */
321
322 for (i = 0; i < N_REG_CLASSES; i++)
323 {
324 for (j = 0; j < N_REG_CLASSES; j++)
325 {
326 HARD_REG_SET c;
327 int k;
328
329 COPY_HARD_REG_SET (c, reg_class_contents[i]);
330 IOR_HARD_REG_SET (c, reg_class_contents[j]);
331 for (k = 0; k < N_REG_CLASSES; k++)
332 {
333 GO_IF_HARD_REG_SUBSET (reg_class_contents[k], c,
334 subclass1);
335 continue;
336
337 subclass1:
338 /* Keep the largest subclass. */ /* SPEE 900308 */
339 GO_IF_HARD_REG_SUBSET (reg_class_contents[k],
340 reg_class_contents[(int) reg_class_subunion[i][j]],
341 subclass2);
342 reg_class_subunion[i][j] = (enum reg_class) k;
343 subclass2:
344 ;
345 }
346 }
347 }
348
349 /* Initialize the table of superunions.
350 reg_class_superunion[I][J] gets the smallest-numbered reg-class
351 containing the union of classes I and J. */
352
353 for (i = 0; i < N_REG_CLASSES; i++)
354 {
355 for (j = 0; j < N_REG_CLASSES; j++)
356 {
357 HARD_REG_SET c;
358 int k;
359
360 COPY_HARD_REG_SET (c, reg_class_contents[i]);
361 IOR_HARD_REG_SET (c, reg_class_contents[j]);
362 for (k = 0; k < N_REG_CLASSES; k++)
363 GO_IF_HARD_REG_SUBSET (c, reg_class_contents[k], superclass);
364
365 superclass:
366 reg_class_superunion[i][j] = (enum reg_class) k;
367 }
368 }
369
370 /* Initialize the tables of subclasses and superclasses of each reg class.
371 First clear the whole table, then add the elements as they are found. */
372
373 for (i = 0; i < N_REG_CLASSES; i++)
374 {
375 for (j = 0; j < N_REG_CLASSES; j++)
376 {
377 reg_class_superclasses[i][j] = LIM_REG_CLASSES;
378 reg_class_subclasses[i][j] = LIM_REG_CLASSES;
379 }
380 }
381
382 for (i = 0; i < N_REG_CLASSES; i++)
383 {
384 if (i == (int) NO_REGS)
385 continue;
386
387 for (j = i + 1; j < N_REG_CLASSES; j++)
388 {
389 enum reg_class *p;
390
391 GO_IF_HARD_REG_SUBSET (reg_class_contents[i], reg_class_contents[j],
392 subclass);
393 continue;
394 subclass:
395 /* Reg class I is a subclass of J.
396 Add J to the table of superclasses of I. */
397 p = ®_class_superclasses[i][0];
398 while (*p != LIM_REG_CLASSES) p++;
399 *p = (enum reg_class) j;
400 /* Add I to the table of superclasses of J. */
401 p = ®_class_subclasses[j][0];
402 while (*p != LIM_REG_CLASSES) p++;
403 *p = (enum reg_class) i;
404 }
405 }
上面,312~316行计算每类寄存器的数目并把该值存入reg_class_size。然后322~347行找出任意2类寄存器合集的最大子集并把结果存入reg_class_subunion,而353~368行找出任意2类寄存器合集的最小超集并把结果存入reg_class_superunion。注意到在reg_class_contents中由寄存器编号索引的比特位,为1表示存在对应的寄存器。
GO_IF_HARD_REG_SUBSET (X, Y, TO)的行为是:如果X被Y所包含则跳到TO。然后373~405行找出被指定寄存器类别所包含的寄存器类别,反之亦然(即,如果X被Y所包含,Y是X的超类,而X是Y的子类)。
init_reg_sets_1 (continue)
407 /* Initialize "constant" tables. */
408
409 CLEAR_HARD_REG_SET (fixed_reg_set);
410 CLEAR_HARD_REG_SET (call_used_reg_set);
411 CLEAR_HARD_REG_SET (call_fixed_reg_set);
412 CLEAR_HARD_REG_SET (regs_invalidated_by_call);
413
414 memcpy (call_fixed_regs, fixed_regs, sizeof call_fixed_regs);
415
416 n_non_fixed_regs = 0;
417
418 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
419 {
420 if (fixed_regs[i])
421 SET_HARD_REG_BIT (fixed_reg_set, i);
422 else
423 n_non_fixed_regs++;
424
425 if (call_used_regs[i])
426 SET_HARD_REG_BIT (call_used_reg_set, i);
427 if (call_fixed_regs[i])
428 SET_HARD_REG_BIT (call_fixed_reg_set, i);
429 if (CLASS_LIKELY_SPILLED_P (REGNO_REG_CLASS (i)))
430 SET_HARD_REG_BIT (losing_caller_save_reg_set, i);
431
432 /* There are a couple of fixed registers that we know are safe to
433 exclude from being clobbered by calls:
434
435 The frame pointer is always preserved across calls. The arg pointer
436 is if it is fixed. The stack pointer usually is, unless
437 RETURN_POPS_ARGS, in which case an explicit CLOBBER will be present.
438 If we are generating PIC code, the PIC offset table register is
439 preserved across calls, though the target can override that. */
440
441 if (i == STACK_POINTER_REGNUM)
442 ;
443 else if (global_regs[i])
444 SET_HARD_REG_BIT (regs_invalidated_by_call, i);
445 else if (i == FRAME_POINTER_REGNUM)
446 ;
447 #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM
448 else if (i == HARD_FRAME_POINTER_REGNUM)
449 ;
450 #endif
451 #if ARG_POINTER_REGNUM != FRAME_POINTER_REGNUM
452 else if (i == ARG_POINTER_REGNUM && fixed_regs[i])
453 ;
454 #endif
455 #ifndef PIC_OFFSET_TABLE_REG_CALL_CLOBBERED
456 else if (i == (unsigned) PIC_OFFSET_TABLE_REGNUM && fixed_regs[i])
457 ;
458 #endif
459 else if (CALL_REALLY_USED_REGNO_P (i))
460 SET_HARD_REG_BIT (regs_invalidated_by_call, i);
461 }
462
463 memset (contains_reg_of_mode, 0, sizeof (contains_reg_of_mode));
464 memset (allocatable_regs_of_mode, 0, sizeof (allocatable_regs_of_mode));
465 for (m = 0; m < (unsigned int) MAX_MACHINE_MODE; m++)
466 for (i = 0; i < N_REG_CLASSES; i++)
467 if ((unsigned) CLASS_MAX_NREGS (i, m) <= reg_class_size[i])
468 for (j = 0; j < FIRST_PSEUDO_REGISTER; j++)
469 if (!fixed_regs [j] && TEST_HARD_REG_BIT (reg_class_contents[i], j)
470 && HARD_REGNO_MODE_OK (j, m))
471 {
472 contains_reg_of_mode [i][m] = 1;
473 allocatable_regs_of_mode [m] = 1;
474 break;
475 }
另外,对应于数组fixed_regs,call_used_regs,call_fixed_regs,有比特版的对象——fixed_reg_set,call_used_reg_set,call_fixed_reg_set。它们更紧凑,是编译器从现在开始使用的数据。 同时,每个寄存器类别所能使用的机器模式的信息也是非常有用的。在464行,数组allocatable_regs_of_mode表示指定的寄存器是否能用于指定的模式,而不考虑其类别。