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

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_FLOATMODE_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机器中,在663674696708行,HARD_REGNO_CALL_PART_CLOBBERED被定义为0

mode_precisionmode_widerclass_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机器上可用的寄存器,它们的编号,及它们的类别都显示在6x86机器的寄存器分组里,形如*_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中,可以看到用于FPSSEMMX的寄存器是如此的大,可以假定这样的寄存器可以存放,除了复数模式以外的,所有的模式。对于其他寄存器,在32x86机器上,它们是4字节大小的(这里为WORD的大小),而XfmodeXcmode则是固定的。

虽然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机器的32ABIPmodeSImode的别名。在该机器中,仅MMXINT模式的寄存器可以存放地址(支持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)))

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值