Studying note of GCC-3.4.6 source (41)

本文详细介绍了编译器在处理命令选项后,进行后端初始化的步骤,包括错误处理、目标依赖性函数调用以及寄存器模式的初始化。重点讨论了如何在x86架构下为不同的模式分配寄存器,以及如何通过宏函数来确定寄存器可以容纳的最宽模式。同时,文章还展示了如何通过一系列函数调用和条件判断来实现这一过程。

4.2. Initialize the back-end

After handling command options, do_compile will do initialization for back-end.

 

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 ();

 

At line 4644, init_adjust_machine_modes is target dependent and generated by back-end tools genmodes. It determines the attributions of machine mode of extended floating which is used for IEEE extended floating point - a twelve byte floating point number.

 

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  }

 

Next, at line 4648, if we don’t require only preprocessing, backend_init will be called.

 

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. Create unique shared objects of back-end

Like the front-end, the compiler also uses delicate data structures for the back-end. Below, function init_emit_once creates some permanent unique rtl objects shared between all functions in the back-end (the back-end uses rtl tree instead of the intermediate tree used by the front-end).

 

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.    Set registers’ mode

In init_emit_once, at line 5451, init_reg_modes_once initializes reg_raw_modes for all hard registers available for the specified system. reg_raw_modes, corresponding to every hard register, records the widest mode object that it can contain. This will be a MODE_INT mode if the register can hold integers. Otherwise it will be a MODE_FLOAT or a MODE_CC mode, whichever is valid for the register. This mode is determined by 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 is machine dependence. For x86 machine, it is defined as below:

 

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 finds out the largest mode specified register can hold, the basic information about registers has already ready this moment and we will come to this topic soon, here we just keep in mind that every register is known belong to certain mode. In x86 machine, macro at line 663, 674, 696, 708, HARD_REGNO_CALL_PART_CLOBBERED is defined as 0.

mode_precision, mode_wider, class_narrowest_mode are all global arrays, their content are dependent on the target machine, which are generated from machmode.def and ‘target’-mode.def (i386-mode.def here) by genmodes tool. They are contained in the generated file insn-modes.h. By carefully checking the file, no Pmode (mode of pointer) related information is generated, as Pmode is architecture dependent, and it is the alias of certain mode, for example, SImode or DImode.

mode_precision records the effective bits of the mode, mode_wider records the next wider mode for the specified mode, for the widest mode of every class, the next wider mode is VIODmode. While class_narrowest_mode records the narrowest mode for specified class.

As we have seen in section Initialize registers sets, the registers available on x86 machine, their number, the class they belong to are given by Table 6: register classes for x86 machine, macros like *_REGNO_P ensure specified register is the expected type, for example, FP_REGNO_P check whether register specified by REGNO is a register for float.

 

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)))

 

From HARD_REGNO_NREGS, we can see that register for FP, SSE, and MMX is so big, it just assumes that one such register can hold all kinds of mode except complex ones. For other registers, in 32bits machine of x86, they will be of size 4 bytes (size of WORD here), and XFmode and XCmode are fixed.

Though HARD_REGNO_NREGS does the rough selection by size, it needs ensure that the specified register is suitable for the mode. ix86_hard_regno_mode_ok takes the work.

 

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 }

 

Above, at line 14930, CC_REGNO_P checks if specified register belongs to CC class, for x86 machine, registers (note not hard register) flags (register number 17), fpsr (register number 18) are the only registers for this purpose. Other *_REGNO_P acts in similar way. And from above VALID_* macros, we can see which types of data the registers can hold. Remember that for 32 bits ABI of x86 machine, Pmode is alias of SImode. Only registers of MMX and INT can hold address in the machine (supports 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)))

 

乐播投屏是一款简单好用、功能强大的专业投屏软件,支持手机投屏电视、手机投电脑、电脑投电视等多种投屏方式。 多端兼容与跨网投屏:支持手机、平板、电脑等多种设备之间的自由组合投屏,且无需连接 WiFi,通过跨屏技术打破网络限制,扫一扫即可投屏。 广泛的应用支持:支持 10000+APP 投屏,包括综合视频、网盘与浏览器、美韩剧、斗鱼、虎牙等直播平台,还能将央视、湖南卫视等各大卫视的直播内容一键投屏。 高清流畅投屏体验:腾讯独家智能音画调校技术,支持 4K 高清画质、240Hz 超高帧率,低延迟不卡顿,能为用户提供更高清、流畅的视觉享受。 会议办公功能强大:拥有全球唯一的 “超级投屏空间”,扫码即投,无需安装。支持多人共享投屏、远程协作批注,PPT、Excel、视频等文件都能流畅展示,还具备企业级安全加密,保障会议资料不泄露。 多人互动功能:支持多人投屏,邀请好友加入投屏互动,远程也可加入。同时具备一屏多显、语音互动功能,支持多人连麦,实时语音交流。 文件支持全面:支持 PPT、PDF、Word、Excel 等办公文件,以及视频、图片等多种类型文件的投屏,还支持网盘直投,无需下载和转格式。 特色功能丰富:投屏时可同步录制投屏画面,部分版本还支持通过触控屏或电视端外接鼠标反控电脑,以及在投屏过程中用画笔实时标注等功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值