您的位置:首页 > 编程语言

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

2010-05-05 09:20 501 查看

4.2. 初始化后端

处理完命令行选项后,do_compile将初始化后端。

do_compile (continue)

4638 /* Don't do any more if an error has already occurred. */
4639 if (!errorcount)
4640 {
4641 /* This must be run always, because it is needed to compute the FP
4642 predefined macros, such as __LDBL_MAX__, for targets using non
4643 default FP formats. */
4644 init_adjust_machine_modes ();
4645
4646 /* Set up the back-end if requested. */
4647 if (!no_backend)
4648 backend_init ();

在4644行,init_adjust_machine_modes为目标平台相关,并由后端工具genmodes 产生。它确定了用于IEEE 扩展浮点对应的机器模式的属性——IEEE 扩展浮点是12字节的浮点值。

516 void
517 init_adjust_machine_modes (void) in insn-modes.c
518 {
519 size_t s ATTRIBUTE_UNUSED;
520
521 /* config/i386/i386-modes.def:35 */
522 s = TARGET_128BIT_LONG_DOUBLE ? 16 : 12;
523 mode_size[XFmode] = s;
524 mode_base_align[XFmode] = s & (~s + 1);
525 mode_size[XCmode] = 2*s;
526 mode_base_align[XCmode] = s & (~s + 1);
527
528 /* config/i386/i386-modes.def:36 */
529 s = TARGET_128BIT_LONG_DOUBLE ? 16 : 4;
530 mode_base_align[XFmode] = s;
531 mode_base_align[XCmode] = s;
532
533 /* config/i386/i386-modes.def:34 */
534 REAL_MODE_FORMAT (XFmode) = (TARGET_128BIT_LONG_DOUBLE? &ieee_extended_intel_128_format: TARGET_96_ROUND_53_LONG_DOUBLE? &ieee_extended_intel_96_round_53_format : &ieee_extended_intel_96_format);
535 }

其次,在4648行,如果不是仅要求预处理,backend_init 将被调用。

4495 static void
4496 backend_init (void) in toplev.c
4497 {
4498 init_emit_once (debug_info_level == DINFO_LEVEL_NORMAL
4499 || debug_info_level == DINFO_LEVEL_VERBOSE
4500 #ifdef VMS_DEBUGGING_INFO
4501 /* Enable line number info for traceback. */
4502 || debug_info_level > DINFO_LEVEL_NONE
4503 #endif
4504 || flag_test_coverage
4505 || warn_notreached);
4506
4507 init_regs ();
4508 init_fake_stack_mems ();

4.2.1. 创建后端永久共享对象

正如前端,编译器亦为后端设计了精巧的数据结构。下面的函数init_emit_once创建某些唯一的永久的rtl对象,这些对象为后端所有函数共享(后端使用rtl树,而不是前端使用的中间树)。

5443 void
5444 init_emit_once (int line_numbers) in emit-rtl.c
5445 {
5446 int i;
5447 enum machine_mode mode;
5448 enum machine_mode double_mode;
5449
5450 /* We need reg_raw_mode, so initialize the modes now. */
5451 init_reg_modes_once ();
5452
5453 /* Initialize the CONST_INT, CONST_DOUBLE, and memory attribute hash
5454 tables. */
5455 const_int_htab = htab_create_ggc (37, const_int_htab_hash,
5456 const_int_htab_eq, NULL);
5457
5458 const_double_htab = htab_create_ggc (37, const_double_htab_hash,
5459 const_double_htab_eq, NULL);
5460
5461 mem_attrs_htab = htab_create_ggc (37, mem_attrs_htab_hash,
5462 mem_attrs_htab_eq, NULL);
5463 reg_attrs_htab = htab_create_ggc (37, reg_attrs_htab_hash,
5464 reg_attrs_htab_eq, NULL);
5465
5466 no_line_numbers = ! line_numbers;
5467
5468 /* Compute the word and byte modes. */
5469
5470 byte_mode = VOIDmode;
5471 word_mode = VOIDmode;
5472 double_mode = VOIDmode;
5473
5474 for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT); mode != VOIDmode;
5475 mode = GET_MODE_WIDER_MODE (mode))
5476 {
5477 if (GET_MODE_BITSIZE (mode) == BITS_PER_UNIT
5478 && byte_mode == VOIDmode)
5479 byte_mode = mode;
5480
5481 if (GET_MODE_BITSIZE (mode) == BITS_PER_WORD
5482 && word_mode == VOIDmode)
5483 word_mode = mode;
5484 }
5485
5486 for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT); mode != VOIDmode;
5487 mode = GET_MODE_WIDER_MODE (mode))
5488 {
5489 if (GET_MODE_BITSIZE (mode) == DOUBLE_TYPE_SIZE
5490 && double_mode == VOIDmode)
5491 double_mode = mode;
5492 }
5493
5494 ptr_mode = mode_for_size (POINTER_SIZE, GET_MODE_CLASS (Pmode), 0);

4.2.1.1. 设定寄存器的模式

init_emit_once中的5451行,init_reg_modes_once为指定系统中所有物理寄存器(hard register)初始化reg_raw_modes。对应于每个物理寄存器,reg_raw_modes记录了该寄存器所能容纳的最大的机器模式对象。如果寄存器可以存放整数,这将是MODE_INT。否则将是MODE_FLOAT或MODE_CC模式,视何者对于该寄存器是有效的。这个模式由choose_hard_reg_mode来确定。

539 void
540 init_reg_modes_once (void) in regclass.c
541 {
542 int i;
543
544 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
545 {
546 reg_raw_mode[i] = choose_hard_reg_mode (i, 1, false);
547
548 /* If we couldn't find a valid mode, just use the previous mode.
549 ??? One situation in which we need to do this is on the mips where
550 HARD_REGNO_NREGS (fpreg, [SD]Fmode) returns 2. Ideally we'd like
551 to use DF mode for the even registers and VOIDmode for the odd
552 (for the cpu models where the odd ones are inaccessible). */
553 if (reg_raw_mode[i] == VOIDmode)
554 reg_raw_mode[i] = i == 0 ? word_mode : reg_raw_mode[i-1];
555 }
556 }

choose_hard_reg_mode是机器相关的。对于x86机器,它具有如下定义:

647 enum machine_mode
648 choose_hard_reg_mode (unsigned int regno ATTRIBUTE_UNUSED, in regclass.c
649 unsigned int nregs, bool call_saved)
650 {
651 unsigned int /* enum machine_mode */ m;
652 enum machine_mode found_mode = VOIDmode, mode;
653
654 /* We first look for the largest integer mode that can be validly
655 held in REGNO. If none, we look for the largest floating-point mode.
656 If we still didn't find a valid mode, try CCmode. */
657
658 for (mode = GET_CLASS_NARROWEST_MODE (MODE_INT);
659 mode != VOIDmode;
660 mode = GET_MODE_WIDER_MODE (mode))
661 if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs
662 && HARD_REGNO_MODE_OK (regno, mode)
663 && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
664 found_mode = mode;
665
666 if (found_mode != VOIDmode)
667 return found_mode;
668
669 for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
670 mode != VOIDmode;
671 mode = GET_MODE_WIDER_MODE (mode))
672 if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs
673 && HARD_REGNO_MODE_OK (regno, mode)
674 && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
675 found_mode = mode;
676
677 if (found_mode != VOIDmode)
678 return found_mode;
679
680 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_FLOAT);
681 mode != VOIDmode;
682 mode = GET_MODE_WIDER_MODE (mode))
683 if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs
684 && HARD_REGNO_MODE_OK (regno, mode)
685 && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
686 found_mode = mode;
687
688 if (found_mode != VOIDmode)
689 return found_mode;
690
691 for (mode = GET_CLASS_NARROWEST_MODE (MODE_VECTOR_INT);
692 mode != VOIDmode;
693 mode = GET_MODE_WIDER_MODE (mode))
694 if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs
695 && HARD_REGNO_MODE_OK (regno, mode)
696 && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
697 found_mode = mode;
698
699 if (found_mode != VOIDmode)
700 return found_mode;
701
702 /* Iterate over all of the CCmodes. */
703 for (m = (unsigned int) CCmode; m < (unsigned int) NUM_MACHINE_MODES; ++m)
704 {
705 mode = (enum machine_mode) m;
706 if ((unsigned) HARD_REGNO_NREGS (regno, mode) == nregs
707 && HARD_REGNO_MODE_OK (regno, mode)
708 && (! call_saved || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)))
709 return mode;
710 }
711
712 /* We can't find a mode valid for this register. */
713 return VOIDmode;
714 }

choose_hard_reg_mode 查找指定寄存器所能保存的最大的模式,在这个时刻寄存器的基本信息已经就绪,稍后我们再回到这个议题,在这里我们只需记住每个寄存器的模式是已知的。在x86机器中,在663,674,696,708行,HARD_REGNO_CALL_PART_CLOBBERED被定义为0。
mode_precision,mode_wider,class_narrowest_mode都是全局数组,它们的内容依赖于目标机器,由genmodes 工具从文件machmode.def及‘target’-mode.def(这里是i386-mode.def)产生。它们被包含在生成的文件insn-modes.h中。仔细地查看这个文件,可以发现没有Pmode (指针的模式)相关的信息被产生,因为Pmode是依赖架构的,它是某些模式的别名,例如,Simode或者Dimode。
mode_precision记录了模式的有效比特位数,mode_wider则记录了仅大于指定模式的模式,对于每个类别的最宽的模式,其更宽的模式是VIODmode。而class_narrowest_mode 记录了指定类别中的最窄的模式。
在前面初始化寄存器集这一节,我们看到在x86机器上可用的寄存器,它们的编号,及它们的类别都显示在表6:x86机器的寄存器分组里,形如*_REGNO_P的宏保证指定的寄存器是期望的类型,例如,FP_REGNO_P检查由REGNO指定的寄存器是用于浮点数的。

1055 #define HARD_REGNO_NREGS(REGNO, MODE) / in i386.h
1056 (FP_REGNO_P (REGNO) || SSE_REGNO_P (REGNO)||MMX_REGNO_P (REGNO)/
1057 ? (COMPLEX_MODE_P (MODE) ? 2 : 1) /
1058 : ((MODE) == XFmode /
1059 ? (TARGET_64BIT ? 2 : 3) /
1060 : (MODE) == XCmode /
1061 ? (TARGET_64BIT ? 4 : 6) /
1062 : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)))

从HARD_REGNO_NREGS中,可以看到用于FP,SSE和MMX的寄存器是如此的大,可以假定这样的寄存器可以存放,除了复数模式以外的,所有的模式。对于其他寄存器,在32位x86机器上,它们是4字节大小的(这里为WORD的大小),而Xfmode和Xcmode则是固定的。
虽然HARD_REGNO_NREGS进行了初步的筛选,还需要确保指定的寄存器对于该模式是适合的。由函数ix86_hard_regno_mode_ok进行该项工作。

1109 #define HARD_REGNO_MODE_OK(REGNO, MODE) / in i386.h
1110 ix86_hard_regno_mode_ok ((REGNO), (MODE))

14926 int
14927 ix86_hard_regno_mode_ok (int regno, enum machine_mode mode) in i386.c
14928 {
14929 /* Flags and only flags can only hold CCmode values. */
14930 if (CC_REGNO_P (regno))
14931 return GET_MODE_CLASS (mode) == MODE_CC;
14932 if (GET_MODE_CLASS (mode) == MODE_CC
14933 || GET_MODE_CLASS (mode) == MODE_RANDOM
14934 || GET_MODE_CLASS (mode) == MODE_PARTIAL_INT)
14935 return 0;
14936 if (FP_REGNO_P (regno))
14937 return VALID_FP_MODE_P (mode);
14938 if (SSE_REGNO_P (regno))
14939 {
14940 /* HACK! We didn't change all of the constraints for SSE1 for the
14941 scalar modes on the branch. Fortunately, they're not required
14942 for ABI compatibility. */
14943 if (!TARGET_SSE2 && !VECTOR_MODE_P (mode))
14944 return VALID_SSE_REG_MODE (mode);
14945
14946 /* We implement the move patterns for all vector modes into and
14947 out of SSE registers, even when no operation instructions
14948 are available. */
14949 return (VALID_SSE_REG_MODE (mode)
14950 || VALID_SSE2_REG_MODE (mode)
14951 || VALID_MMX_REG_MODE (mode)
14952 || VALID_MMX_REG_MODE_3DNOW (mode));
14953 }
14954 if (MMX_REGNO_P (regno))
14955 {
14956 /* We implement the move patterns for 3DNOW modes even in MMX mode,
14957 so if the register is available at all, then we can move data of
14958 the given mode into or out of it. */
14959 return (VALID_MMX_REG_MODE (mode)
14960 || VALID_MMX_REG_MODE_3DNOW (mode));
14961 }
14962 /* We handle both integer and floats in the general purpose registers.
14963 In future we should be able to handle vector modes as well. */
14964 if (!VALID_INT_MODE_P (mode) && !VALID_FP_MODE_P (mode))
14965 return 0;
14966 /* Take care for QImode values - they can be in non-QI regs, but then
14967 they do cause partial register stalls. */
14968 if (regno < 4 || mode != QImode || TARGET_64BIT)
14969 return 1;
14970 return reload_in_progress || reload_completed || !TARGET_PARTIAL_REG_STALL;
14971 }

上面在14930行,CC_REGNO_P检查指定寄存器是否属于CC类别,对于x86机器,寄存器(注意不是物理寄存器)flags(编号17),fpsr(编号18)是为此目的仅有的寄存器。其他*_REGNO_P的功用相似。从下面的形如VALID_*的宏,可以看出寄存器所能存放的数据类型。记住对于x86机器的32位ABI,Pmode是SImode的别名。在该机器中,仅MMX及INT模式的寄存器可以存放地址(支持SImode)。

1064 #define VALID_SSE2_REG_MODE(MODE) / in i386.h
1065 ((MODE) == V16QImode || (MODE) == V8HImode || (MODE) == V2DFmode /
1066 || (MODE) == V2DImode || (MODE) == DFmode)
1067
1068 #define VALID_SSE_REG_MODE(MODE) /
1069 ((MODE) == TImode || (MODE) == V4SFmode || (MODE) == V4SImode /
1070 || (MODE) == SFmode || (MODE) == TFmode)
1071
1072 #define VALID_MMX_REG_MODE_3DNOW(MODE) /
1073 ((MODE) == V2SFmode || (MODE) == SFmode)
1074
1075 #define VALID_MMX_REG_MODE(MODE) /
1076 ((MODE) == DImode || (MODE) == V8QImode || (MODE) == V4HImode /
1077 || (MODE) == V2SImode || (MODE) == SImode)

1084 #define VALID_FP_MODE_P(MODE) /
1085 ((MODE) == SFmode || (MODE) == DFmode || (MODE) == XFmode /
1086 || (MODE) == SCmode || (MODE) == DCmode || (MODE) == XCmode) /
1087
1088 #define VALID_INT_MODE_P(MODE) /
1089 ((MODE) == QImode || (MODE) == HImode || (MODE) == SImode /
1090 || (MODE) == DImode /
1091 || (MODE) == CQImode || (MODE) == CHImode || (MODE) == CSImode /
1092 || (MODE) == CDImode /
1093 || (TARGET_64BIT && ((MODE) == TImode || (MODE) == CTImode /
1094 || (MODE) == TFmode || (MODE) == TCmode)))
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: