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

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

2010-05-12 09:38 316 查看

4.2.1.2. 初始化哈希表

与前端相似,后端亦对常用、共享的对象使用哈希表。在以后的章节,结合编译过程,我们再来看这些哈希表中,元素的意义。
接着在init_emit_once,5474到5494行,找出适合字节类型,字类型及double类型的模式,而ptr_mode在5494行由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_class,rtx_format)。
RTL使用五种对象:表达式,整数,宽整数,字符串及向量。表达式是其中最重要的一个。一个RTL表达式(为了简洁起见,称为RTX)是一个C结构,但通常它由一个指针来引用;这个指针的类型由一个rtx的typedef名字给出。
一个整数简单地是一个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 ——用于表示一个对象(例如REG,MEM)的rtx编码
w < ——用于比较的rtx编码(例如EQ,NE,LT)
w 1 ——用于算术一元表达式的rtx编码(例如NEG,NOT)
w c ——用于符合交换律的二元操作的rtx编码(例如PLUS, MULT)
w 3 ——用于非位域的三元操作(IF_THEN_ELSE)的rtx编码
w 2 ——用于不符合交换律的二元操作(例如MINUS,DIV)的rtx编码
w b ——用于位域操作(ZERO_EXTRACT,SIGN_EXTRACT)的rtx编码
w i ——用于机器指令(INSN,JUMP_INSN,CALL_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 Address,CFA)。这对应于由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

在上面5500和5501行,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_rtx及cc0_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编码,名字字符串,以字符串形式定义的格式,以字符串形式定义的类别。因而PC和CC0具有以下的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')

在104及105行rtx_size的定义中,RTX_HDR_SIZE被定义为从rtx_def的开头到其u域的偏移。

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

对于PC及CC0对象,它们只有RTX_HDR_SIZE大小,因为(sizeof FORMAT – 1)是0。在gen_rtx中的710及711行,宏形如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_format及rtx_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表达式,它应是:



图1:rtx表达式例子

显然,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_expression,cont_int_RTX都保存在rtx的域rtunion中),rtvec则用于数组对象,rttype用于数据类型的机器模式,addr_diff_vec_flags保存用于优化分支块的信息,bb保存了基本块(一个入口,一个出口)的信息,rtmem和rtreg分别保存了内存和寄存器的属性,rttree指向对应的前端子树。
在接下来的init_emit_once 中,从5502到5517行,其他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.c和rtl.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_format中0,0的含义是未使用(或用于阶段相关的方式),EXP表明rtx的内容是rtx表达式。

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

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

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_once的5522行,开始创建通用寄存器的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_once的5540行,对于x86系统,STORE_FLAG_VALUE被定义为1。因此const_true_rtx只是const_int_rtx [65]的别名。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: