5.13.5.2.2.1.1.3. 发布汇编代码
回到 output_constant_def_contents ,如果变量有大于 1 字节的对齐要求,还要调用 ASM_OUTPUT_ALIGN 来输出这个信息,这里输出的是以 2 为底对齐量的对数。对于 x86 ,这个宏的定义是:
54 #define ASM_OUTPUT_ALIGN (FILE,LOG) / in att.h
55 if ((LOG)!=0) fprintf ((FILE), "/t.align %d/n", 1<<(LOG))
前面在 build_constant_desc 中,为常量构建了可作为符号使用的内部标签,现在要在这个常量之前输出这个标签。这里是通过下面的宏。
151 #ifndef ASM_OUTPUT_LABEL in default.h
152 #define ASM_OUTPUT_LABEL (FILE,NAME) /
153 do { assemble_name ((FILE), (NAME)); fputs (":/n", (FILE)); } while (0)
154 #endif
注意,在 153 行,在标签后还要加上“ :/n ”。
1699 void
1700 assemble_name (FILE *file, const char *name) in varasm.c
1701 {
1702 const char *real_name;
1703 tree id;
1704
1705 real_name = (* targetm .strip_name_encoding) (name);
1706
1707 id = maybe_get_identifier (real_name);
1708 if (id)
1709 mark_referenced (id);
1710
1711 if (name[0] == '*')
1712 fputs (&name[1], file);
1713 else
1714 ASM_OUTPUT_LABELREF (file, name);
1715 }
在 1705 行,缺省钩子 strip_name_encoding 不做任何事,只是除去开头的‘ * ’标记。然后 maybe_get_identifier 尝试得到 name 的标识符,如果它不是标识符就返回 NULL 。
129 tree
130 maybe_get_identifier (const char *text) in stringpool.c
131 {
132 hashnode ht_node;
133
134 ht_node = ht_lookup (ident_hash , (const unsigned char *) text,
135 strlen (text), HT_NO_INSERT);
136 if (ht_node)
137 return HT_IDENT_TO_GCC_IDENT (ht_node);
138
139 return NULL_TREE;
140 }
如果 name 对应着一个被设置,就应该把它标记为正被引用。下面当整个编译单元已经被分析过了,标记 cgraph_global_info_ready 是非 0 值,无疑,在此处,它仍然是 0 。
1671 void
1672 mark_referenced (tree id) in varasm.c
1673 {
1674 if (!TREE_SYMBOL_REFERENCED (id))
1675 {
1676 struct cgraph_node *node;
1677 struct cgraph_varpool_node *vnode;
1678
1679 if (!cgraph_global_info_ready )
1680 {
1681 node = cgraph_node_for_identifier (id);
1682 if (node)
1683 cgraph_mark_needed_node (node);
1684 }
1685
1686 vnode = cgraph_varpool_node_for_identifier (id);
1687 if (vnode)
1688 cgraph_varpool_mark_needed_node (vnode);
1689 }
1690 TREE_SYMBOL_REFERENCED (id) = 1;
1691 }
一个标识符可能是一个函数或变量的名字;因此在 1681 行, cgraph_node_for_identifier 获取了函数名相关 FUNCTION_DECL 的 cgraph_node ;而在 1686 行, cgraph_varpool_node_for_identifier 获取了变量名相关 VAR_DECL 的 cgraph_varpool_node 。
133 struct cgraph_node *
134 cgraph_node_for_identifier (tree id) in cgraph.c
135 {
136 struct cgraph_node **slot;
137
138 if (TREE_CODE (id) != IDENTIFIER_NODE)
139 abort ();
140
141 if (!cgraph_hash )
142 return NULL;
143
144 slot = (struct cgraph_node **)
145 htab_find_slot_with_hash (cgraph_hash , id,
146 IDENTIFIER_HASH_VALUE (id), NO_INSERT);
147 if (!slot)
148 return NULL;
149 return *slot;
150 }
如果一个标识符不是全局可见的,它将不被 cgraph_hash 或 cgraph_varpool_hash 所记录。而如果一个标识符是全局可见的,需要把它标记为“需要的”,那么后面的优化不会删除它。
队列 cgraph_nodes_queue 记录了在用的函数。而类似的队列 cgraph_varpool_nodes_queue 记录了在用的全局变量。
547 struct cgraph_varpool_node *
548 cgraph_varpool_node_for_identifier (tree id) in cgraph.c
549 {
550 struct cgraph_varpool_node **slot;
551
552 if (TREE_CODE (id) != IDENTIFIER_NODE)
553 abort ();
554
555 if (!cgraph_varpool_hash )
556 return NULL;
557
558 slot = (struct cgraph_varpool_node **)
559 htab_find_slot_with_hash (cgraph_varpool_hash , id,
560 IDENTIFIER_HASH_VALUE (id), NO_INSERT);
561 if (!slot)
562 return NULL;
563 return *slot;
564 }
回到 assemble_name ,可以看出前端自己生成的内部名字都以‘ * ’开头,对这些名字直接输出其除‘ * ’以外的部分。而其它名字则由 ASM_OUTPUT_LABELREF 输出,在我们的目标平台上,其定义如下。
158 #ifndef ASM_OUTPUT_LABELREF in default.h
159 #define ASM_OUTPUT_LABELREF (FILE,NAME) asm_fprintf ((FILE), "%U%s", (NAME))
160 #endif
在函数 asm_fprintf 中,格式串“ %U ”表示打印出 user_label_prefix 的内容,它在我们的目标平台上是 ”” (空字符串)。
再次回到 output_constant_def_contents ,最后调用 output_constant 来输出常量的内容。
3730 void
3731 output_constant (tree exp, unsigned HOST_WIDE_INT size, unsigned int align) in varasm.c
3732 {
3733 enum tree_code code;
3734 unsigned HOST_WIDE_INT thissize;
3735
3736 /* Some front-ends use constants other than the standard language-independent
3737 varieties, but which may still be output directly. Give the front-end a
3738 chance to convert EXP to a language-independent representation. */
3739 exp = (*lang_hooks .expand_constant) (exp);
3740
3741 if (size == 0 || flag_syntax_only )
3742 return ;
3743
3744 /* Eliminate any conversions since we'll be outputting the underlying
3745 constant. */
3746 while (TREE_CODE (exp) == NOP_EXPR || TREE_CODE (exp) == CONVERT_EXPR
3747 || TREE_CODE (exp) == NON_LVALUE_EXPR
3748 || TREE_CODE (exp) == VIEW_CONVERT_EXPR)
3749 exp = TREE_OPERAND (exp, 0);
3750
3751 code = TREE_CODE (TREE_TYPE (exp));
3752 thissize = int_size_in_bytes (TREE_TYPE (exp));
3753
3754 /* Allow a constructor with no elements for any data type.
3755 This means to fill the space with zeros. */
3756 if (TREE_CODE (exp) == CONSTRUCTOR && CONSTRUCTOR_ELTS (exp) == 0)
3757 {
3758 assemble_zeros (size);
3759 return ;
3760 }
同样,在上面 3739 行, C++ 钩子函数 cplus_expand_constant 把成员指针常量 PTRMEM_CST 转换为更合适的形式( PLUS_EXPR 或另一个 PTRMEM_CST )。
5.13.5.2.2.1.1.3.1. 全0 的内容
上面的 3756 行,如果聚集类具有空的初始值(不是没有初始值),就意味着初始化为全 0 。下面的函数可以输出留出 size 字节的 0 的汇编代码。
1155 void
1156 assemble_zeros (unsigned HOST_WIDE_INT size) in varasm.c
1157 {
1158 /* Do no output if -fsyntax-only. */
1159 if (flag_syntax_only )
1160 return ;
1161
1162 #ifdef ASM_NO_SKIP_IN_TEXT
1163 /* The `space' pseudo in the text section outputs nop insns rather than 0s,
1164 so we must output 0s explicitly in the text section. */
1165 if (ASM_NO_SKIP_IN_TEXT && in_text_section ())
1166 {
1167 unsigned HOST_WIDE_INT i;
1168 for (i = 0; i < size; i++)
1169 assemble_integer (const0_rtx, 1, BITS_PER_UNIT, 1);
1170 }
1171 else
1172 #endif
1173 if (size > 0)
1174 ASM_OUTPUT_SKIP (asm_out_file , size);
1175 }
如果在代码节及数据节中处理的方式不同,就要定义 ASM_NO_SKIP_IN_TEXT 宏;否则就会使用 ASM_OUTPUT_SKIP 来处理。在 x86/Linux 上需要不同的处理方式,其中 ASM_OUTPUT_SKIP 被定义为(它首先在 att.h 中定义,但于下面的文件中被重新定义):
104 #undef ASM_OUTPUT_SKIP i n elfos.h
105 #define ASM_OUTPUT_SKIP(FILE, SIZE) /
106 fprintf ((FILE), "%s"HOST_WIDE_INT_PRINT_UNSIGNED"/n",/
107 SKIP_ASM_OP, (SIZE))
上面的 SKIP_ASM_OP 是“ /t.zero/t ”,而 HOST_WIDE_INT_PRINT_UNSIGNED 实际上是“ llu ”,由于 C++ 中相邻的字符串常量将被合并,因此 106 行 fprintf 的第二个参数实际上就是“ %llu/n ”。
如果不能通过改变位置计数器( location counter )来留出所需的字节,就要通过 assemble_integer 真正地输出数据。这个函数我们很快就会看到。
5.13.5.2.2.1.1.3.2. 整数
x86/Linux 不使用函数描述符( function descriptor ),因此宏 ASM_OUTPUT_FDESC 没有定义。如果出现了 FDESC_EXPR ,将会调用 3769 行的 abort 退出编译。
output_constant (continue)
3762 if (TREE_CODE (exp) == FDESC_EXPR)
3763 {
3764 #ifdef ASM_OUTPUT_FDESC
3765 HOST_WIDE_INT part = tree_low_cst (TREE_OPERAND (exp, 1), 0);
3766 tree decl = TREE_OPERAND (exp, 0);
3767 ASM_OUTPUT_FDESC (asm_out_file , decl, part);
3768 #else
3769 abort ();
3770 #endif
3771 return ;
3772 }
3773
3774 /* Now output the underlying data. If we've handling the padding, return.
3775 Otherwise, break and ensure THISSIZE is the size written. */
3776 switch (code)
3777 {
3778 case CHAR_TYPE:
3779 case BOOLEAN_TYPE:
3780 case INTEGER_TYPE:
3781 case ENUMERAL_TYPE:
3782 case POINTER_TYPE:
3783 case REFERENCE_TYPE:
3784 case OFFSET_TYPE:
3785 if (! assemble_integer (expand_expr (exp, NULL_RTX, VOIDmode,
3786 EXPAND_INITIALIZER),
3787 size, align, 0))
3788 error ("initializer for integer value is too complicated");
3789 break ;
在 3785 行的 expand_expr 把给定的前端节点转换为 RTL 节点,这是个非常复杂的函数,我们这里暂时不看它。对于数值常量(非 VECTOR 类型),都将被构建为 CONST_DOUBLE 的 RTL 节点;而算术表达式则亦有对应的 RTL 节点。
1873 bool
1874 assemble_integer (rtx x, unsigned int size, unsigned int align, int force) in varasm.c
1875 {
1876 int aligned_p;
1877
1878 aligned_p = (align >= MIN (size * BITS_PER_UNIT, BIGGEST_ALIGNMENT));
1879
1880 /* See if the target hook can handle this kind of object. */
1881 if ((*targetm .asm_out.integer ) (x, size, aligned_p))
1882 return true;
1883
1884 /* If the object is a multi-byte one, try splitting it up. Split
1885 it into words it if is multi-word, otherwise split it into bytes. */
1886 if (size > 1)
1887 {
1888 enum machine_mode omode, imode;
1889 unsigned int subalign;
1890 unsigned int subsize, i;
1891
1892 subsize = size > UNITS_PER_WORD? UNITS_PER_WORD : 1;
1893 subalign = MIN (align, subsize * BITS_PER_UNIT);
1894 omode = mode_for_size (subsize * BITS_PER_UNIT, MODE_INT, 0);
1895 imode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
1896
1897 for (i = 0; i < size; i += subsize)
1898 {
1899 rtx partial = simplify_subreg (omode, x, imode, i);
1900 if (!partial || !assemble_integer (partial, subsize, subalign, 0))
1901 break ;
1902 }
1903 if (i == size)
1904 return true;
1905
1906 /* If we've printed some of it, but not all of it, there's no going
1907 back now. */
1908 if (i > 0)
1909 abort ();
1910 }
1911
1912 if (force)
1913 abort ();
1914
1915 return false;
1916 }
在 1881 行的钩子,对于我们的目标平台上,与下面的函数绑定。
1859 bool
1860 default_assemble_integer (rtx x ATTRIBUTE_UNUSED, in varasm.c
1861 unsigned int size ATTRIBUTE_UNUSED,
1862 int aligned_p ATTRIBUTE_UNUSED)
1863 {
1864 const char *op = integer_asm_op (size, aligned_p);
1865 return op && (assemble_integer_with_op (op, x), true);
1866 }
1819 const char *
1820 integer_asm_op (int size, int aligned_p) in varasm.c
1821 {
1822 struct asm_int_op *ops;
1823
1824 if (aligned_p)
1825 ops = &targetm .asm_out.aligned_op;
1826 else
1827 ops = &targetm .asm_out.unaligned_op;
1828
1829 switch (size)
1830 {
1831 case 1:
1832 return targetm .asm_out.byte_op;
1833 case 2:
1834 return ops->hi;
1835 case 4:
1836 return ops->si;
1837 case 8:
1838 return ops->di;
1839 case 16:
1840 return ops->ti;
1841 default :
1842 return NULL;
1843 }
1844 }
对于 x86/Linux ,无符号、有符号的钩子都是相同的: HI 模式对应 ASM_SHORT , SI 模式对应 ASM_LONG , DI 模式对应 ASM_QUAD 。它们的定义分别为:
30 #define ASM_SHORT "/t.value/t" in att.h
31 #define ASM_LONG "/t.long/t"
32 #define ASM_QUAD "/t.quad/t" /* Should not be used for 32bit compilation. */
而 byte_op 钩子,在绝大多数情形下,使用默认的定义:
35 #define TARGET_ASM_BYTE_OP "/t.byte/t" in target-def.h
如果钩子不是定义为 NULL ,就执行下面的函数(由 C++ 优化的规则,一旦 1865 行的 op 是 NULL ,就不会执行 assemble_integer_with_op )。
1849 void
1850 assemble_integer_with_op (const char *op, rtx x) in varasm.c
1851 {
1852 fputs (op, asm_out_file );
1853 output_addr_const (asm_out_file , x);
1854 fputc ('/n', asm_out_file );
1855 }
op 的内容首先被输出,它在汇编代码中声明了常量的大小。下面的函数则处理常量的内容。注意 LABEL_REF 用于表示用户定义的 label ,其操作数是 CODE_LABEL 。 CODE_LABEL 还可被编译器用来表示汇编代码中因为(条件)跳转指令所需要的额外的、非用户定义的 label 。看到这些 label 的命名是“ *LLn ”(前面常量 label 的名字是“ *LLCn ”)。
3163 void
3164 output_addr_const (FILE *file, rtx x) in final.c
3165 {
3166 char buf[256];
3167
3168 restart:
3169 switch (GET_CODE (x))
3170 {
3171 case PC:
3172 putc ('.', file);
3173 break ;
3174
3175 case SYMBOL_REF:
3176 #ifdef ASM_OUTPUT_SYMBOL_REF
3177 ASM_OUTPUT_SYMBOL_REF (file, x);
3178 #else
3179 assemble_name (file, XSTR (x, 0));
3180 #endif
3181 break ;
3182
3183 case LABEL_REF:
3184 x = XEXP (x, 0);
3185 /* Fall through. */
3186 case CODE_LABEL:
3187 ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
3188 #ifdef ASM_OUTPUT_LABEL_REF
3189 ASM_OUTPUT_LABEL_REF (file, buf);
3190 #else
3191 assemble_name (file, buf);
3192 #endif
3193 break ;
3194
3195 case CONST_INT:
3196 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
3197 break ;
3198
3199 case CONST:
3200 /* This used to output parentheses around the expression,
3201 but that does not work on the 386 (either ATT or BSD assembler). */
3202 output_addr_const (file, XEXP (x, 0));
3203 break ;
3204
3205 case CONST_DOUBLE:
3206 if (GET_MODE (x) == VOIDmode)
3207 {
3208 /* We can use %d if the number is one word and positive. */
3209 if (CONST_DOUBLE_HIGH (x))
3210 fprintf (file, HOST_WIDE_INT_PRINT_DOUBLE_HEX,
3211 CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
3212 else if (CONST_DOUBLE_LOW (x) < 0)
3213 fprintf (file, HOST_WIDE_INT_PRINT_HEX, CONST_DOUBLE_LOW (x));
3214 else
3215 fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
3216 }
3217 else
3218 /* We can't handle floating point constants;
3219 PRINT_OPERAND must handle them. */
3220 output_operand_lossage ("floating constant misused");
3221 break ;
3222
3223 case PLUS:
3224 /* Some assemblers need integer constants to appear last (eg masm). */
3225 if (GET_CODE (XEXP (x, 0)) == CONST_INT)
3226 {
3227 output_addr_const (file, XEXP (x, 1));
3228 if (INTVAL (XEXP (x, 0)) >= 0)
3229 fprintf (file, "+");
3230 output_addr_const (file, XEXP (x, 0));
3231 }
3232 else
3233 {
3234 output_addr_const (file, XEXP (x, 0));
3235 if (GET_CODE (XEXP (x, 1)) != CONST_INT
3236 || INTVAL (XEXP (x, 1)) >= 0)
3237 fprintf (file, "+");
3238 output_addr_const (file, XEXP (x, 1));
3239 }
3240 break ;
3241
3242 case MINUS:
3243 /* Avoid outputting things like x-x or x+5-x,
3244 since some assemblers can't handle that. */
3245 x = simplify_subtraction (x);
3246 if (GET_CODE (x) != MINUS)
3247 goto restart;
3248
3249 output_addr_const (file, XEXP (x, 0));
3250 fprintf (file, "-");
3251 if ((GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) >= 0)
3252 || GET_CODE (XEXP (x, 1)) == PC
3253 || GET_CODE (XEXP (x, 1)) == SYMBOL_REF)
3254 output_addr_const (file, XEXP (x, 1));
3255 else
3256 {
3257 fputs (targetm .asm_out.open_paren, file);
3258 output_addr_const (file, XEXP (x, 1));
3259 fputs (targetm .asm_out.close_paren, file);
3260 }
3261 break ;
3262
3263 case ZERO_EXTEND:
3264 case SIGN_EXTEND:
3265 case SUBREG:
3266 output_addr_const (file, XEXP (x, 0));
3267 break ;
3268
3269 default :
3270 #ifdef OUTPUT_ADDR_CONST_EXTRA
3271 OUTPUT_ADDR_CONST_EXTRA (file, x, fail);
3272 break ;
3273
3274 fail:
3275 #endif
3276 output_operand_lossage ("invalid expression as operand");
3277 }
3278 }
注意 3243 行的注释,记住表达式来到 RTX 形式时已经采用了前序( prefix )形式(波兰记法),那么 x+5-x 就是“ -(+(x, 5), x) ”——最外层的节点是 MINUS 。
2857 rtx
2858 simplify_subtraction (rtx x) in varasm.c
2859 {
2860 struct rtx_const val0, val1;
2861
2862 decode_rtx_const (GET_MODE (x), XEXP (x, 0), &val0);
2863 decode_rtx_const (GET_MODE (x), XEXP (x, 1), &val1);
2864
2865 if (val0.kind >= RTX_INT
2866 && val0.kind == val1.kind
2867 && val0.un.addr.base == val1.un.addr.base
2868 && val0.un.addr.symbol == val1.un.addr.symbol)
2869 return GEN_INT (val0.un.addr.offset - val1.un.addr.offset);
2870
2871 return x;
2872 }
在 RTX 形式中, x+5 是一个 CONST 节点(因为这是个右值,其内容不可改变),其中的‘ x ’是一个具有汇编名(即修饰名)的 SYMBOL_REF 节点,‘ 5 ’则是一个 CONST_INT 节点。注意, RTX 形式比前端的中间树节点更接近于汇编,在这里已经看不到 DECL 及 TYPE 这样的节点了。
2029 enum kind { RTX_UNKNOWN, RTX_DOUBLE, RTX_VECTOR, RTX_INT, RTX_UNSPEC };
2030 struct rtx_const GTY(()) in varasm.c
2031 {
2032 ENUM_BITFIELD(kind) kind : 16;
2033 ENUM_BITFIELD(machine_mode) mode : 16;
2034 union rtx_const_un {
2035 REAL_VALUE_TYPE GTY ((tag ("4"))) du;
2036 struct rtx_const_u_addr {
2037 rtx base;
2038 const char *symbol;
2039 HOST_WIDE_INT offset;
2040 } GTY ((tag ("1"))) addr;
2041 struct rtx_const_u_di {
2042 HOST_WIDE_INT high;
2043 HOST_WIDE_INT low;
2044 } GTY ((tag ("0"))) di;
2045
2046 /* The max vector size we have is 16 wide; two variants for
2047 integral and floating point vectors. */
2048 struct rtx_const_int_vec {
2049 HOST_WIDE_INT high;
2050 HOST_WIDE_INT low;
2051 } GTY ((tag ("2"))) int_vec[16];
2052
2053 REAL_VALUE_TYPE GTY ((tag ("3"))) fp_vec[8];
2054
2055 } GTY ((desc ("%1.kind >= RTX_INT"), descbits ("1"))) un;
2056 };
为了能简化表达式,那么必须能把不同类型的 RTL 节点以相同的方式表达出来,比如上面的“ x+5-x ”中“ x+5 ”是 CONST 节点,“ x ”则是 SYMBOL_REF 节点,要简化这个表达式,必须把“ x+5 ”与“ x ”以相同方式表达出来,从而可以进行进一步的处理。
这个形式就是上面的 rtx_const 结构,它把 RTL 节点归为 5 种,由枚举类型 kind 所描述。转换则由下面的函数完成。
2679 static void
2680 decode_rtx_const (enum machine_mode mode, rtx x, struct rtx_const *value) in varasm.c
2681 {
2682 /* Clear the whole structure, including any gaps. */
2683 memset (value, 0, sizeof (struct rtx_const));
2684
2685 value->kind = RTX_INT; /* Most usual kind. */
2686 value->mode = mode;
2687
2688 switch (GET_CODE (x))
2689 {
2690 case CONST_DOUBLE:
2691 value->kind = RTX_DOUBLE;
2692 if (GET_MODE (x) != VOIDmode)
2693 {
2694 const REAL_VALUE_TYPE *r = CONST_DOUBLE_REAL_VALUE (x);
2695
2696 value->mode = GET_MODE (x);
2697
2698 /* Copy the REAL_VALUE_TYPE by members so that we don't
2699 copy garbage from the original structure into our
2700 carefully cleaned hashing structure. */
2701 value->un.du.class = r->class;
2702 value->un.du.sign = r->sign;
2703 switch (r->class)
2704 {
2705 case rvc_zero:
2706 case rvc_inf:
2707 break ;
2708 case rvc_normal:
2709 value->un.du.exp = r->exp;
2710 /* Fall through. */
2711 case rvc_nan:
2712 memcpy (value->un.du.sig, r->sig, sizeof (r->sig));
2713 break ;
2714 default :
2715 abort ();
2716 }
2717 }
2718 else
2719 {
2720 value->un.di.low = CONST_DOUBLE_LOW (x);
2721 value->un.di.high = CONST_DOUBLE_HIGH (x);
2722 }
2723 break ;
2724
2725 case CONST_VECTOR:
2726 {
2727 int units, i;
2728
2729 units = CONST_VECTOR_NUNITS (x);
2730 value->kind = RTX_VECTOR;
2731 value->mode = mode;
2732
2733 if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
2734 {
2735 for (i = 0; i < units; ++i)
2736 {
2737 rtx elt = CONST_VECTOR_ELT (x, i);
2738 if (GET_CODE (elt) == CONST_INT)
2739 {
2740 value->un.int_vec[i].low = INTVAL (elt);
2741 value->un.int_vec[i].high = 0;
2742 }
2743 else
2744 {
2745 value->un.int_vec[i].low = CONST_DOUBLE_LOW (elt);
2746 value->un.int_vec[i].high = CONST_DOUBLE_HIGH (elt);
2747 }
2748 }
2749 }
2750 else if (GET_MODE_CLASS (mode) == MODE_VECTOR_FLOAT)
2751 {
2752 for (i = 0; i < units; ++i)
2753 {
2754 const REAL_VALUE_TYPE *r
2755 = CONST_DOUBLE_REAL_VALUE (CONST_VECTOR_ELT (x, i));
2756 REAL_VALUE_TYPE *d = &value->un.fp_vec[i];
2757
2758 /* Copy the REAL_VALUE_TYPE by members so that we don't
2759 copy garbage from the original structure into our
2760 carefully cleaned hashing structure. */
2761 d->class = r->class;
2762 d->sign = r->sign;
2763 switch (r->class)
2764 {
2765 case rvc_zero:
2766 case rvc_inf:
2767 break ;
2768 case rvc_normal:
2769 d->exp = r->exp;
2770 /* Fall through. */
2771 case rvc_nan:
2772 memcpy (d->sig, r->sig, sizeof (r->sig));
2773 break ;
2774 default :
2775 abort ();
2776 }
2777 }
2778 }
2779 else
2780 abort ();
2781 }
2782 break ;
2783
2784 case CONST_INT:
2785 value->un.addr.offset = INTVAL (x);
2786 break ;
2787
2788 case SYMBOL_REF:
2789 case LABEL_REF:
2790 case PC:
2791 value->un.addr.base = x;
2792 break ;
2793
2794 case CONST:
2795 x = XEXP (x, 0);
2796 if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
2797 {
2798 value->un.addr.base = XEXP (x, 0);
2799 value->un.addr.offset = INTVAL (XEXP (x, 1));
2800 }
2801 else if (GET_CODE (x) == MINUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
2802 {
2803 value->un.addr.base = XEXP (x, 0);
2804 value->un.addr.offset = - INTVAL (XEXP (x, 1));
2805 }
2806 else
2807 {
2808 value->un.addr.base = x;
2809 value->un.addr.offset = 0;
2810 }
2811 break ;
2812
2813 default :
2814 value->kind = RTX_UNKNOWN;
2815 break ;
2816 }
2817
2818 if (value->kind == RTX_INT && value->un.addr.base != 0
2819 && GET_CODE (value->un.addr.base) == UNSPEC)
2820 {
2821 /* For a simple UNSPEC, the base is set to the
2822 operand, the kind field is set to the index of
2823 the unspec expression.
2824 Together with the code below, in case that
2825 the operand is a SYMBOL_REF or LABEL_REF,
2826 the address of the string or the code_label
2827 is taken as base. */
2828 if (XVECLEN (value->un.addr.base, 0) == 1)
2829 {
2830 value->kind = RTX_UNSPEC + XINT (value->un.addr.base, 1);
2831 value->un.addr.base = XVECEXP (value->un.addr.base, 0, 0);
2832 }
2833 }
2834
2835 if (value->kind >= RTX_INT && value->un.addr.base != 0)
2836 switch (GET_CODE (value->un.addr.base))
2837 {
2838 case SYMBOL_REF:
2839 /* Use the string's address, not the SYMBOL_REF's address,
2840 for the sake of addresses of library routines. */
2841 value->un.addr.symbol = XSTR (value->un.addr.base, 0);
2842 value->un.addr.base = NULL_RTX;
2843 break ;
2844
2845 case LABEL_REF:
2846 /* For a LABEL_REF, compare labels. */
2847 value->un.addr.base = XEXP (value->un.addr.base, 0);
2848
2849 default :
2850 break ;
2851 }
2852 }
首先在 2685 行, value 的 kind 被设置为 RTX_INT ,这是最有可能使用的值; kind 域接着会在 2691 行、 2730 行、 2814 行及 2830 行改写。因此形如“ x+5 ”的表达式的 kind 将是 RTX_INT ,同样的还有‘ x ’( SYMBOL_REF ),“ goto label1 ”( LABEL_REF )。
在 2819 行, RTL 节点 UNSPEC 也是来自 CONST 节点中,它代表一个机器特定的操作。其第一个操作数是该操作所使用的一个操作数向量,因此可以任何需要的重新载入( reload );其第二个操作数是一个唯一值,告知所要执行的一组机器特定操作中哪一个。那么 2830 行就使得 kind 与这些机器特定操作一一对应。
回到 simplify_subtraction 之后,看到只有 kind 是 RTX_INT , RTX_UNSPEC 及之后(机器特定操作)才处理。其他,尤其是 RTX_CONST 是不管的,这是因为如果 RTX_CONST 节点的内容有优化的机会,它应该已经在前端的常量折叠优化中处理了。
上面是在目标机器中能高效支持的整数的处理。对于其它整数类型, assemble_integer 1881 行的钩子函数返回 false 。对于 x86/Linux ,这个整数模式是 TI 模式( 16 字节,在 64 位整型运算中,其中间值就是 TI 模式,一般保存在 SSE 寄存器中,但若发生溅出,就会调用 assemble_ineger 写入栈)。对 TI 模式数据的处理是把它分解为 4 个字( 4 字节),对于直接数( CONST_INT , CONST_DOUBLE 等),这通过 simplify_immed_subreg 来完成,然后通过 assemble_ineger 写入。 simplify_immed_subreg 所用到的处理方法,我们基本上都看过,并不复杂,这里跳过它。