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

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 所用到的处理方法,我们基本上都看过,并不复杂,这里跳过它。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值