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

4.2.1.2.    初始化哈希表

与前端相似,后端亦对常用、共享的对象使用哈希表。在以后的章节,结合编译过程,我们再来看这些哈希表中,元素的意义。

接着在init_emit_once54745494行,找出适合字节类型,字类型及double类型的模式,而ptr_mode5494行由mode_for_size来确定。

4.2.1.3.    创建Rtl对象

4.2.1.3.1.            Rtl语言

接下来,init_emit_once开始创建唯一的rtx对象。与前端所使用的树的形式不同,后端使用rtl对象构成的树。前端树节点接近于源语言。而RTL比源语言要简单得多,因此将它翻译为汇编要更容易,而且独立于前端。在RTL语言中,编码用于描述所要执行的动作。在rtl.h文件中rtx_code被定义如下。

 

41    #define RTX_CODE     enum rtx_code                                                                      in rtl.h

42    enum rtx_code  {

43   

44    #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   ENUM ,

45    #include "rtl.def"          /* rtl expressions are documented here */

46    #undef DEF_RTL_EXPR

47   

48      LAST_AND_UNUSED_RTX_CODE};   /* A convenient way to get a value for

49                            NUM_RTX_CODE.

50                            Assumes default enum value assignment.  */

 

Rtl.def文件包含了表达式定义及可用于所有目标平台的描述。在这个文件中所有rtx对象以形式DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)给出。通过在此处相应地定义DEF_RTL_EXPR,可以为该rtx对象获得对应的数据(比如,rtx_classrtx_format)。

RTL使用五种对象:表达式,整数,宽整数,字符串及向量。表达式是其中最重要的一个。一个RTL表达式(为了简洁起见,称为RTX)是一个C结构,但通常它由一个指针来引用;这个指针的类型由一个rtxtypedef名字给出。

一个整数简单地是一个int;它们的书写形式使用十进制数。一个宽整数是一个类型为HOST_WIDE_INT的整数对象;它们的书写形式使用十进制数。

一个字符串是一串字符。其核心是普通的C风格的char *,同时以符合C语法。不过, RTL中的字符串永远不可为空。如果在一个机器描述中写入了一个空字符串,在核心里它被表示为一个空指针,而不是指向空字符的指针。在某些上下文环境下,这些空指针而不是字符串是有效的。在RTL代码里,字符串最可能在symbol_ref表达式中找到,不过它们也出现在,构成机器描述的RTL表达式的,其他上下文环境里。

在一个机器描述中,字符串通常带有双引号,就像在C里一样。不过机器描述里的字符串可能扩展至许多行,这在C中是非法的,并且相邻的字符串常量不能像在C中那样合并。任意字符串常量可能被一组括号所包含。这有时使得机器描述的可读性好一些。

RTL的字符串有一个特殊的语法,在C代码嵌入在机器描述里时有用。只要字符串能出现的地方,同样可以写入一个C风格的大括号块。整个大括号块,包含最外围的大括号对,被认为是字符串常量。大括号内双引号中的字符如常处理。因而,如果在这个C代码中有字符串常量,就不需要用”/”来转义双引号。

一个向量包含任意数目的指向表达式的指针。向量中元素的数目显式地在向量中指出。一个向量的书写形式由中括号及所包含的元素组成([...]),这些元素依次出现,并且由空格分隔开。0长度的向量不被创建,而是使用空指针来表示。

表示式由“表达式编码”(亦称为RTX编码)。表达式编码是在rtl.def文件中定义的名字,它是一个C枚举常量(大写)。可能的表达式编码及其含义是与机器无关的。一个rtx对象的编码可以通过宏GET_MODE(X)获取,通过PUT_CODE(X, NEWCODE )改写。

表达式编码确定了该表达式所包含的参数数目,及它们的类型。在RTL中,不像Lisp,不能通过观察参数而知道其类型。相反,必须从其上下文中得知——通过包含表达式的表达式编码。例如,在一个编码为subreg的表达式,第一个参数被认为是一个表达式,而第二个参数被视为一个整数。在一个编码为plus的表达式,有2个参数,均被认为是表达式。在一个symbol_ref表达式,有一个参数,其被视为一个字符串。

表达式被写成包含在括号中的表达式类型名,标识符,机器模式如果有的话,及表达式的参数(由空格分隔)。

md文件中,表达式编码名是小写,但当它们出现在C代码中时,它们被大写。

在一些上下文环境中,一个空指针是有效的。在那里一个表达式如常被期待。这个空指针的书写形式是(nil)

不同的表达式编码被分为多个“类别”,类别由单个字符表示。可以用宏GET_RTX_CLASS (CODE)来确定一个RTX编码的类别。当前,rtx.def定义了如下类别:

Ÿ        用于C源代码中rtx的内部名。它是定义在rtl.h 中的枚举类型enum rtx_code 中的一个标签(tag)。按常规它们都是大写。

Ÿ        read_rtx 读入,及被print_rtx 输出的外部ASCII格式的rtx名字。这些名字被保存在rtx_name[]值。按惯例,它们是内部名字的小写形式。

Ÿ        输出格式,及在该rtx中每个rtx->u.fld[] 域的类型。这些格式被保存在rtx_format[]中。这些格式的含义被注释在rtl.c文件,该数组定义之前。

Ÿ        Rtx的类别。这个信息被保存在rtx_class,并由宏GET_RTX_CLASS访问。类别被定义为如下:

w          o ——用于表示一个对象(例如REGMEM)的rtx编码

w          < ——用于比较的rtx编码(例如EQNELT

w          1 ——用于算术一元表达式的rtx编码(例如NEGNOT

w          c ——用于符合交换律的二元操作的rtx编码(例如PLUS, MULT)

w          3 ——用于非位域的三元操作(IF_THEN_ELSE)的rtx编码

w          2 ——用于不符合交换律的二元操作(例如MINUSDIV)的rtx编码

w          b ——用于位域操作(ZERO_EXTRACTSIGN_EXTRACT)的rtx编码

w          i ——用于机器指令(INSNJUMP_INSNCALL_INSN)的rtx编码

w          m ——用于在指令中所匹配之对象(例如MATCH_DUP)的rtx编码

w          g ——用于组合指令(例如GROUP_PARALLEL)的rtx编码

w          a ——用于自增地址模式(例如POST_DEC)的rtx编码

w          x ——其他

4.2.1.3.2.            创建对象
4.2.1.3.2.1.      用于寄存器及相关的对象

以下是将要创建的一些变量的含义:

virtual_incoming_args_rtx:指向在栈上所传入参数的第一个字,参数或者由调用者或者由被调用者传入,并假定为调用者传入。

virtual_stack_vars_rtx:如果设置了FRAME_GROWS_DOWNWARD,指向栈上第一个变量的正上方。否则,指向栈上的第一个变量。

virtual_stack_dynamic_rtx:在栈指针按所要求的数量进行调整后,指向栈上动态分配内存的位置。

virtual_cfa_rtx:指向函数的规范栈框地址(Canonical Frame AddressCFA)。这对应于由INCOMING_FRAME_SP_OFFSET产生的CFA,但出于简单起见,它相对于arg指针计算。栈指针或栈框指针,直到重装(reload)后,相对于CFA,不需要为不变。

virtual_outgoing_args_rtx:当栈在压入前(使用push指令压入的参数总是使用sp),指向栈中将写入传出参数的位置。

static_regno_reg_rtx:通常用于物理寄存器。这些对象不需要是唯一的,因此它们在global_rtl以外分配。在每个编译单元它们被初始化一次,然后在每个函数的开始被拷贝入regno_reg_rtx

 

init_emit_once (continue)

 

5496   /* Assign register numbers to the globally defined register rtx.

5497     This must be done at runtime because the register number field

5498     is in a union and some compilers can't initialize unions.  */

5499

5500   pc_rtx = gen_rtx (PC, VOIDmode);

5501   cc0_rtx = gen_rtx (CC0, VOIDmode);

5502   stack_pointer_rtx = gen_raw_REG (Pmode, STACK_POINTER_REGNUM);

5503   frame_pointer_rtx = gen_raw_REG (Pmode, FRAME_POINTER_REGNUM);

5504   if (hard_frame_pointer_rtx == 0)

5505     hard_frame_pointer_rtx = gen_raw_REG (Pmode,

5506                       HARD_FRAME_POINTER_REGNUM);

5507   if (arg_pointer_rtx == 0)

5508     arg_pointer_rtx = gen_raw_REG (Pmode, ARG_POINTER_REGNUM);

5509   virtual_incoming_args_rtx =

5510     gen_raw_REG (Pmode, VIRTUAL_INCOMING_ARGS_REGNUM);

5511   virtual_stack_vars_rtx =

5512     gen_raw_REG (Pmode, VIRTUAL_STACK_VARS_REGNUM);

5513   virtual_stack_dynamic_rtx =

5514     gen_raw_REG (Pmode, VIRTUAL_STACK_DYNAMIC_REGNUM);

5515   virtual_outgoing_args_rtx =

5516     gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);

5517   virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);

5518

5519   /* Initialize RTL for commonly used hard registers. These are

5520     copied into regno_reg_rtx as we begin to compile each function.  */

5521   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)

5522     static_regno_reg_rtx[i] = gen_raw_REG (reg_raw_mode[i], i);

5523

5524 #ifdef INIT_EXPANDERS

5525   /* This is to initialize {init|mark|free}_machine_status before the first

5526     call to push_function_context_to. This is needed by the Chill front

5527     end which calls push_function_context_to before the first call to

5528     init_function_start.  */

5529   INIT_EXPANDERS;

5530 #endif

 

在上面55005501行,pc_rtx(程序计数器)及cc0_rtx(条件代码)都是全局rtx数组global_rtl的成员。而从索引可以看出引用了何种寄存器。它们中的大多数没有对应的物理寄存器,创建它们是为了rtl语言处理上的方便。

 

1807 enum global_rtl_index                                                                                      in rtl.h

1808 {

1809   GR_PC,

1810   GR_CC0,

1811   GR_STACK_POINTER,

1812   GR_FRAME_POINTER,

1813   /* For register elimination to work properly these hard_frame_pointer_rtx,

1814     frame_pointer_rtx, and arg_pointer_rtx must be the same if they refer to

1815     the same register.  */

1816 #if FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM

1817   GR_ARG_POINTER = GR_FRAME_POINTER,

1818 #endif

1819 #if HARD_FRAME_POINTER_REGNUM == FRAME_POINTER_REGNUM

1820   GR_HARD_FRAME_POINTER = GR_FRAME_POINTER,

1821 #else

1822   GR_HARD_FRAME_POINTER,

1823 #endif

1824 #if FRAME_POINTER_REGNUM != ARG_POINTER_REGNUM

1825 #if HARD_FRAME_POINTER_REGNUM == ARG_POINTER_REGNUM

1826   GR_ARG_POINTER = GR_HARD_FRAME_POINTER,

1827 #else

1828   GR_ARG_POINTER,

1829 #endif

1830 #endif

1831   GR_VIRTUAL_INCOMING_ARGS,

1832   GR_VIRTUAL_STACK_ARGS,

1833   GR_VIRTUAL_STACK_DYNAMIC,

1834   GR_VIRTUAL_OUTGOING_ARGS,

1835   GR_VIRTUAL_CFA,

1836

1837   GR_MAX

1838 };

 

gen_rtx用于创建,除了赋予了寄存器号码的寄存器以外,普通rtx对象。在创建pc_rtxcc0_rtx对象时,执行了下面部分的代码。

 

673  rtx

674  gen_rtx (enum rtx_code code, enum machine_mode mode, ...)                             in emit-rtl.c

675  {

676    int i;          /* Array indices...   */

677    const char *fmt; /* Current rtx's format...       */

678    rtx rt_val;          /* RTX to return to caller...   */

679    va_list p;

680 

681    va_start (p, mode);

682 

683    switch (code)

684    {

   

706      default:

707        rt_val = rtx_alloc (code);        /* Allocate the storage space.  */

708        rt_val->mode = mode;             /* Store the machine mode...  */

709 

710        fmt = GET_RTX_FORMAT (code);  /* Find the right format...  */

711         for (i = 0; i < GET_RTX_LENGTH (code); i++)

712         {

       

750        }

751      }

752      break;

753   }

754 

755    va_end (p);

756    return rt_val;

757  }

 

上面在707行,所创建的rtx对象由GCC的垃圾收集器管理。每个rtx对象根据其大小来分配。这个大小尺寸记录着rtx_size中,这也是个全局数组,具有如下定义。

 

101    const unsigned char rtx_size[NUM_RTX_CODE] = {                                         in rtl.c

102    #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)                           /

103      ((ENUM) == CONST_INT || (ENUM) == CONST_DOUBLE                  /

104       ? RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (HOST_WIDE_INT)       /

105       : RTX_HDR_SIZE + (sizeof FORMAT - 1) * sizeof (rtunion)),

106   

107    #include "rtl.def"

108    #undef DEF_RTL_EXPR

109    };

 

rtl.def的内容是表达式,其具有形式:rtx编码,名字字符串,以字符串形式定义的格式,以字符串形式定义的类别。因而PCCC0具有以下的rtx形式。注意到两者的格式均是空字符串,而rtx_length都是0

 

803  /* program counter. Ordinary jumps are represented                                             in rtl.def

804      by a SET whose first operand is (PC).  */

805    DEF_RTL_EXPR(PC, "pc", "", 'o')

 

873    /* The condition code register is represented, in our imagination,

874      as a register holding a value that can be compared to zero.

875      In fact, the machine has already compared them and recorded the

876      results; but instructions that look at the condition code

877      pretend to be looking at the entire value and comparing it.  */

878    DEF_RTL_EXPR(CC0, "cc0", "", 'o')

 

104105rtx_size的定义中,RTX_HDR_SIZE被定义为从rtx_def的开头到其u域的偏移。

 

225    #define RTX_HDR_SIZE offsetof (struct rtx_def, u)                                         in rtl.h

 

对于PCCC0对象,它们只有RTX_HDR_SIZE大小,因为(sizeof FORMAT – 1)0。在gen_rtx中的710711行,宏形如GET_RTX_...被用于获取rtl定义中相应的域。

 

56    #define GET_RTX_LENGTH(CODE)         (rtx_length[(int) (CODE)])                 in rtl.h

62    #define GET_RTX_FORMAT(CODE)         (rtx_format[(int) (CODE)])

 

rtx_formatrtx_length也均是全局数组。它们的定义来自rtl.def

 

57    const char * const rtx_format[NUM_RTX_CODE] = {                                         in rtl.c

58      /* "*" undefined.

59             can cause a warning message

60        "0" field is unused (or used in a phase-dependent manner)

61             prints nothing

62        "i" an integer

63             prints the integer

64        "n" like "i", but prints entries from `note_insn_name'

65        "w" an integer of width HOST_BITS_PER_WIDE_INT

66             prints the integer

67        "s" a pointer to a string

68            prints the string

69        "S" like "s", but optional:

70             the containing rtx may end before this operand

71        "T" like "s", but treated specially by the RTL reader;

72             only found in machine description patterns.

73        "e" a pointer to an rtl expression

74             prints the expression

75        "E" a pointer to a vector that points to a number of rtl expressions

76             prints a list of the rtl expressions

77        "V" like "E", but optional:

78             the containing rtx may end before this operand

79        "u" a pointer to another insn

80             prints the uid of the insn.

81        "b" is a pointer to a bitmap header.

82        "B" is a basic block pointer.

83        "t" is a tree pointer.  */

84   

85    #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS)   FORMAT ,

86    #include "rtl.def"          /* rtl expressions are defined here */

87    #undef DEF_RTL_EXPR

88    };

 

35    #define DEF_RTL_EXPR(ENUM, NAME, FORMAT, CLASS) sizeof FORMAT - 1 ,

 

37    const unsigned char rtx_length[NUM_RTX_CODE] = {

38    #include "rtl.def"

39    };

 

而在gcc的源代码中,rtx对象由下面的struct rtx_def来代表。

 

139  struct rtx_def GTY((chain_next ("RTX_NEXT (&%h)"),                                      in rtl.h

140             chain_prev ("RTX_PREV (&%h)")))

141  {

142    /* The kind of expression this is.  */

143    ENUM_BITFIELD(rtx_code) code: 16;

144 

145    /* The kind of value the expression has.  */

146    ENUM_BITFIELD(machine_mode) mode : 8;

147 

148    /* 1 in a MEM if we should keep the alias set for this mem unchanged

149      when we access a component.

150      1 in a CALL_INSN if it is a sibling call.

151      1 in a SET that is for a return.

152      In a CODE_LABEL, part of the two-bit alternate entry field.  */

153    unsigned int jump : 1;

154   /* In a CODE_LABEL, part of the two-bit alternate entry field.

155      1 in a MEM if it cannot trap.  */

156    unsigned int call : 1;

157   /* 1 in a REG, MEM, or CONCAT if the value is set at most once, anywhere.

158      1 in a SUBREG if it references an unsigned object whose mode has been

159      from a promoted to a wider mode.

160     1 in a SYMBOL_REF if it addresses something in the per-function

161      constants pool.

162      1 in a CALL_INSN, NOTE, or EXPR_LIST for a const or pure call.

163      1 in a JUMP_INSN, CALL_INSN, or INSN of an annulling branch.  */

164    unsigned int unchanging : 1;

165    /* 1 in a MEM or ASM_OPERANDS expression if the memory reference is volatile.

166      1 in an INSN, CALL_INSN, JUMP_INSN, CODE_LABEL, BARRIER, or NOTE

167      if it has been deleted.

168      1 in a REG expression if corresponds to a variable declared by the user,

169      0 for an internally generated temporary.

170      1 in a SUBREG with a negative value.

171      1 in a LABEL_REF or in a REG_LABEL note for a non-local label.

172      In a SYMBOL_REF, this flag is used for machine-specific purposes.  */

173    unsigned int volatil : 1;

174    /* 1 in a MEM referring to a field of an aggregate.

175      0 if the MEM was a variable or the result of a * operator in C;

176      1 if it was the result of a . or -> operator (on a struct) in C.

177      1 in a REG if the register is used only in exit code a loop.

178      1 in a SUBREG expression if was generated from a variable with a

179      promoted mode.

180      1 in a CODE_LABEL if the label is used for nonlocal gotos

181      and must not be deleted even if its count is zero.

182      1 in a LABEL_REF if this is a reference to a label outside the

183      current loop.

184      1 in an INSN, JUMP_INSN or CALL_INSN if this insn must be scheduled

185      together with the preceding insn. Valid only within sched.

186      1 in an INSN, JUMP_INSN, or CALL_INSN if insn is in a delay slot and

187      from the target of a branch. Valid from reorg until end of compilation;

188      cleared before used.

189      1 in an INSN, JUMP_INSN or CALL_INSN or related rtx if this insn is

190      dead code. Valid only during dead-code elimination phase; cleared

191      before use.  */

192    unsigned int in_struct : 1;

193    /* At the end of RTL generation, 1 if this rtx is used. This is used for

194      copying shared structure. See `unshare_all_rtl'.

195      In a REG, this is not needed for that purpose, and used instead

196      in `leaf_renumber_regs_insn'.

197      1 in a SYMBOL_REF, means that emit_library_call

198      has used it as the function.  */

199    unsigned int used : 1;

200   /* Nonzero if this rtx came from procedure integration.

201      1 in a REG or PARALLEL means this rtx refers to the return value

202      of the current function.

203      1 in a SYMBOL_REF if the symbol is weak.  */

204    unsigned integrated : 1;

205   /* 1 in an INSN or a SET if this rtx is related to the call frame,

206      either changing how we compute the frame address or saving and

207      restoring registers in the prologue and epilogue.

208      1 in a MEM if the MEM refers to a scalar, rather than a member of

209      an aggregate.

210      1 in a REG if the register is a pointer.

211       1 in a SYMBOL_REF if it addresses something in the per-function

212      constant string pool.  */

213    unsigned frame_related : 1;

214 

215    /* The first element of the operands of this rtx.

216      The number of operands and their types are controlled

217      by the `code' field, according to rtl.def.  */

218    union u {

219      rtunion fld[1];

220      HOST_WIDE_INT hwint[1];

221    } GTY ((special ("rtx_def"), desc ("GET_CODE (&%0)"))) u;

222  };

 

在上面的定义中,ENUM_BITFIELD在当前版本里被定义为enum。域union u持有rtl表达式的成员。对于真实的rtx表达式,这个域是一个数组。数组中的每个元素保存表达式的一个子部分。

例如,表达式2+3+5,当转换为rtx语言时,它以中序的形式:+ (2) + (3) (5)出现。对于这个rtx表达式,它应是:

1rtx表达式例子

显然,rtunion必须是另一个union类型。它需要保存为目标平台产生代码所需的所有信息。

 

119   union rtunion_def                                                                                             in rtl.h

120  {

121    int rtint;

122    unsigned int rtuint;

123    const char *rtstr;

124    rtx rtx;

125    rtvec rtvec;

126    enum machine_mode rttype;

127    addr_diff_vec_flags rt_addr_diff_vec_flags;

128    struct cselib_val_struct *rt_cselib;

129    struct bitmap_head_def *rtbit;

130    tree rttree;

131    struct basic_block_def *bb;

132    mem_attrs *rtmem;

133    reg_attrs *rtreg;

134  };

135  typedef union rtunion_def rtunion;

 

其中,tinit用于整数的RTX表达式,rtuint用于无符号整数,rtstr用于字符串对象,rtx用于表达式(对于上面的图,rtx_expressioncont_int_RTX都保存在rtx的域rtunion中),rtvec则用于数组对象,rttype用于数据类型的机器模式,addr_diff_vec_flags保存用于优化分支块的信息,bb保存了基本块(一个入口,一个出口)的信息,rtmemrtreg分别保存了内存和寄存器的属性,rttree指向对应的前端子树。

在接下来的init_emit_once 中,从55025517行,其他global_rtl中的对象由gen_raw_REG创建,这包括了指定寄存器编号的寄存器对象。

 

377  rtx

378  gen_raw_REG (enum machine_mode mode, int regno)                                  in emit-rtl.c

379  {

380    rtx x = gen_rtx_raw_REG (mode, regno);

381    ORIGINAL_REGNO (x) = regno;

382    return x;

383  }

 

gen_rtx_raw_REG由工具gengenrtl根据rtl.def文件产生。通过这种方式,可以相当容易地扩展RTL语言,而不需要重新源文件,除了rtl.def。即便当需要对RTX语言进行大的改动,我们所需要做的只是重写gengenrtl.crtl.def。这是个聪明的设计。gen_rtx_raw_REG gen_rtx_fmt_i00的别名。

 

245  #define gen_rtx_raw_REG(MODE, ARG0) /                                                in genrtl.h

246     gen_rtx_fmt_i00 (REG, (MODE), (ARG0))

 

gen_rtx_fmt_i00的名字透露了如下的信息i表示rtx->u.fld第一个元素的类型是int,旁边的0表示rtx->u.fld中接下来的元素没有被使用。这些字符的含义与 rtx_format相同。rtx->u.fld的大小是3

 

630  rtx

631  gen_rtx_fmt_i00 (RTX_CODE code, enum machine_mode mode,                  in genrtl.c

632                int arg0)

633  {

634    rtx rt;

635    rt = ggc_alloc_rtx (code);

636 

637    memset (rt, 0, RTX_HDR_SIZE);

638 

639    PUT_CODE (rt, code);

640    PUT_MODE (rt, mode);

641    XINT (rt, 0) = arg0;

642    X0EXP (rt, 1) = NULL_RTX;

643    X0EXP (rt, 2) = NULL_RTX;

644 

645    return rt;

646  }

 

GCC定义了一系列的宏首先检查RTX对象的合法性,然后获取指定的域。在调用处,可以看到arg0是寄存器号码。而XINT是这些宏的其中之一。

 

506  #define XINT(RTX, N) (RTL_CHECK2 (RTX, N, 'i', 'n').rtint)                                    in rtl.h

 

RTL_CHECK2类似于RTL_CHECK1,除了需要验证给定的2个格式。

对于X0EXP,其名字中的0代表应用了rtx_format00的含义是未使用(或用于阶段相关的方式),EXP表明rtx的内容是rtx表达式。

 

525  #define X0EXP(RTX, N)         (RTL_CHECK1 (RTX, N, '0').rtx)                       in rtl.h

 

如果定义了ENABLE_RTL_CHECKINGRTL_CHECK1将进行合法性验证。这在GCC开发阶段很有意义。而在发布时,取消ENABLE_RTL_CHECKING的定义,RTL_CHECK1将只是RTX->u.fld[N],大大加快了执行速度。

 

302  #if defined ENABLE_RTL_CHECKING && (GCC_VERSION >= 2007)             in rtl.h

303  /* The bit with a star outside the statement expr and an & inside is

304    so that N can be evaluated only once.  */

305  #define RTL_CHECK1(RTX, N, C1) __extension__                        /

306  (*({ rtx const _rtx = (RTX); const int _n = (N);                     /

307       const enum rtx_code _code = GET_CODE (_rtx);                  /

308       if (_n < 0 || _n >= GET_RTX_LENGTH (_code))                   /

309         rtl_check_failed_bounds (_rtx, _n, __FILE__, __LINE__,          /

310                               __FUNCTION__);                      /

311        if (GET_RTX_FORMAT(_code)[_n] != C1)                           /

312         rtl_check_failed_type1 (_rtx, _n, C1, __FILE__, __LINE__,      /

313                              __FUNCTION__);                       /

314     &_rtx->u.fld[_n]; }))

 

gen_rtx_raw_REG返回时,gen_raw_REG用寄存器号码重写rtunion的第二个元素,这个元素保存寄存器原始的号码。对于一个变成物理寄存器的伪寄存器,这将是伪寄存器的原始号码。

 

1019 #define ORIGINAL_REGNO(RTX) X0UINT (RTX, 1)                                        in rtl.h

1020 #define X0UINT(RTX, N)       (RTL_CHECK1 (RTX, N, '0').rtuint)

 

然后在init_emit_once5522开始创建通用寄存器的rtx对象。reg_raw_mode记录了特定寄存器所能支持的最大机器模式,该数据在init_reg_modes_once中设置。

5529行,对于除ia64以外的x86机器,INIT_EXPANDERS没有定义。

 

init_emit_once (continue)

 

5532   /* Create the unique rtx's for certain rtx codes and operand values.  */

5533

5534   /* Don't use gen_rtx here since gen_rtx in this case

5535     tries to use these variables.  */

5536   for (i = - MAX_SAVED_CONST_INT; i <= MAX_SAVED_CONST_INT; i++)

5537     const_int_rtx[i + MAX_SAVED_CONST_INT] =

5538       gen_rtx_raw_CONST_INT (VOIDmode, (HOST_WIDE_INT) i);

5539

5540   if (STORE_FLAG_VALUE >= - MAX_SAVED_CONST_INT

5541       && STORE_FLAG_VALUE <= MAX_SAVED_CONST_INT)

5542     const_true_rtx = const_int_rtx[STORE_FLAG_VALUE + MAX_SAVED_CONST_INT];

5543   else

5544     const_true_rtx = gen_rtx_CONST_INT (VOIDmode, STORE_FLAG_VALUE);

 

5537行,const_int_rtx保存了(const_int C)的一份拷贝,C的取值在[-64, 64]。这将为整数的比较及计算节省空间。MAX_SAVED_CONST_INT被定义为64。这些常量的rtx对象由gen_rtx_raw_CONST_INT创建。

 

233  #define gen_rtx_raw_CONST_INT(MODE, ARG0) /                                    in genrtl.h

234    gen_rtx_fmt_w (CONST_INT, (MODE), (ARG0))

 

函数gen_rtx_fmt_w亦是由工具gengenrtl根据rtl.def生成。同样,它的名字泄露了它的内涵。字母w表示所处理rtx表达式的内容是宽整数,因此这次使用的是rtx->u.wint。而且rtx->u.wint也是一个数组。

 

599  rtx

600  gen_rtx_fmt_w (RTX_CODE code, enum machine_mode mode,                     in genrtl.c

601          HOST_WIDE_INT arg0)

602  {

603    rtx rt;

604    rt = ggc_alloc_rtx (code);

605 

606    memset (rt, 0, RTX_HDR_SIZE);

607 

608    PUT_CODE (rt, code);

609    PUT_MODE (rt, mode);

610    XWINT (rt, 0) = arg0;

611  

612    return rt;

613  }

 

350  #define XWINT(RTX, N) __extension__                                 /                    in rtl.h

351  (*({ rtx const _rtx = (RTX); const int _n = (N);                     /

352       const enum rtx_code _code = GET_CODE (_rtx);                  /

353       if (_n < 0 || _n >= GET_RTX_LENGTH (_code))                   /

354         rtl_check_failed_bounds (_rtx, _n, __FILE__, __LINE__,          /

355                               __FUNCTION__);                      /

356       if (GET_RTX_FORMAT(_code)[_n] != 'w')                           /

357         rtl_check_failed_type1 (_rtx, _n, 'w', __FILE__, __LINE__,       /

358                                   __FUNCTION__);                        /

359         &_rtx->u.hwint[_n]; }))

 

在上面的init_emit_once5540行,对于x86系统,STORE_FLAG_VALUE被定义为1。因此const_true_rtx只是const_int_rtx [65]的别名。

 

 

你可能感兴趣的:(function,struct,Integer,Class,语言,extension)