Studying note of GCC-3.4.6 source (170)

5.13.5.2.2.1.1.3.    Emit assembler code

Back output_constant_def_contents , if the variable has alignment bigger than 1 byte, it needs invoke ASM_OUTPUT_ALIGN to output this requirement, here what output is logarithm of base 2 of the alignemnt. For x86, the macro has definition:

 

54    #define ASM_OUTPUT_ALIGN (FILE,LOG)       /                                                in att.h

55        if ((LOG)!=0) fprintf ((FILE), "/t.align %d/n", 1<<(LOG))

 

In build_constant_desc previous, it makes the internal label for constant, now needs output this label just before the constant. Here it is done by following macro.

 

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

 

Note, at line 153, “:/n” is appended after the label.

 

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 }

 

At line 1705, default hook strip_name_encoding does anything but discard the '*' marker at head. Then maybe_get_identifier tries to get identifer of name , and returns NULL if it is not an identifier.

 

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  }

 

If name corresponds to an identifier, it should mark it as being referenced. Below flag cgraph_global_info_ready is nonzero when whole unit has been analyzed, no doubt at here, it is still zero.

 

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 }

 

An identifier may be name of a function or a variable; so cgraph_node_for_identifier at line 1681 retrieves the cgraph_node for FUNCTION_DECL of the name; and at line 1686, cgraph_varpool_node_for_identifier retrieves the cgraph_varpool_node for VAR_DECL of the name.

 

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  }

 

If an identifier is not global visible, it won’t be recorded by cgraph_hash or cgraph_varpool_hash . And if an identifier is global visible, it needs be marked as needed, so later optimization will not delete it.

Queue cgraph_nodes_queue records the functions in used. And similarly queue cgraph_varpool_nodes_queue records the global variables in used.

 

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  }

 

Back assemble_name , can see that the internal names generated by the front-end itself has ‘*’ at head, it just outputs these names without ‘*’. While other names are output by ASM_OUTPUT_LABELREF, which on our taget has following definition.

 

158  #ifndef ASM_OUTPUT_LABELREF                                                             in default.h

159  #define ASM_OUTPUT_LABELREF (FILE,NAME)  asm_fprintf ((FILE), "%U%s", (NAME))

160  #endif

 

In function asm_fprintf , format “%U” means prints the value of user_label_prefix which is “” for the target.

Back output_constant_def_contents again, at last invokes output_constant to output the content of the constants.

 

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   }

 

Again, above at line 3739, hook of C++ cplus_expand_constant changes pointer-to-member constant into more appropriate form (PLUS_EXPR or another PTRMEM_CST).

5.13.5.2.2.1.1.3.1.            Content of 0

Below function can leave size bytes 0 in assembler code.

 

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 }

 

If data section and text section reqiure different treatment, it needs define macro ASM_NO_SKIP_IN_TEXT; otherwise needs ASM_OUTPUT_SKIP. In x86/Linux, it needs the differentiated treatment, so ASM_OUTPUT_SKIP is defined as (it is first defined in att.h, but overwritten in below file):

 

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

 

Above, SKIP_ASM_OP is “/t.zero/t”, and HOST_WIDE_INT_PRINT_UNSIGNED in fact is” llu”, as in C++ adjancent strings will be concatenated, so at line 106, the second parameter of fprintf is “%llu/n”.

If it can’t leave the required bytes by changing the location counter, it needs to output the data via assemble_integer . We will see this function shortly.

5.13.5.2.2.1.1.3.2.            Integer

x86/Linux doesn’t use function descriptor, so macro ASM_OUTPUT_FDESC is not defined. And if found FDESC_EXPR, it will invoke abort at line 3769 to exit the compilation.

 

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 ;

 

At line 3785, expand_expr transforms the given frond-end node into RTL node, it is a complex function, we don't see it temperarily. For scalar constant (non-VECTOR type), will all be built with RTL node of CONST_DOUBLE; and arithmetic experssion also has corresponding RTL node.

 

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 }

 

At line 1881 the hook, for our target machine, is bound with below funciton.

 

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 }

 

For x86/Linux, hooks of unsigned, singed are equal: HI mode uses ASM_SHORT, SI mode uses ASM_LONG, and DI mode uses ASM_QUAD. Their definitions are:

 

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.  */

 

While for byte_op hook, in most targets, it uses the default definition:

 

35    #define TARGET_ASM_BYTE_OP "/t.byte/t"                                        in target-def.h

 

If the hook is not NULL, then executes below function (by C++’s optimization rule, once op at line 1865 is NULL, it won’t call 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 }

 

The content of op is first output, which declares the size of the constant. Then below function handles the content of the constant. Note that LABEL_REF represents user-defined label, its operand is CODE_LABEL. Besides, CODE_LABEL is also used for extra and no user-defined label for (conditional) jump by the compiler. See that these labels have name of form “*LLn ” (name of constant has format “*LLCn ” instead).

 

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 }

 

Pay attention to comment at line 3243, remember that expression in RTX form uses prefix (Polish) notation, so “x+5-x” would be “-(+(x, 5), x)” --- the outmost node is 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 }

 

In RTX form, “x+5” is a CONST node (because it is a rvalue, which content can’t be modified), in which ‘x” is a SYMBOL_REF having assemble name (mangled name), and ‘5’ is a CONST_INT. See that as RTX form is much closer assemble than the front-end’s intermediate tree form, at here there is no DECL, TYPE and such nodes.

 

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 };

 

To simplify the expression, it should express RTL node of different type in the same way, for example, in “x+5-x”, “x+5” is a CONST, and “x” is SYMBOL_REF, to simplify this expression, it must represent “x+5” and “x” in the same way to make further processing possible.

The way uses above structure rtx_const, it classifies RTL nodes into 5 kinds which is described by enumerator kind. The transformation is done by below function.

 

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 }

 

First at line 2685, value ’s kind is set as RTX_INT, which is the most possible value; kind is then will be overwritten at line 2691, 2730, 2814 and 2830. So expression in from “x+5” would have kind of RTX_INT, similarly are ‘x’ (SYMBOL_REF), and “goto label1” (LABEL_REF).

At line 2819, RTL node UNSPEC is also from CONST node, it represents a machine specifies operation. Its 1st operand is a vector of operands being used by the operation so that any needed reloads can be done; 2nd operand is a unique value saying which of a number of machine-specific operations is to be performed. So line 2830 makes these operations matches kind one for one.

Back simplify_subtraction , see that only kind of RTX_INT, RTX_UNSPEC or following (machine specifies operation) gets handled. Others, especial RTX_CONST, are ignore, it is because if RTX_CONST node’s content has optimization opportunity, it should have been processed by constant folding before.

Above is the handling of integer target can support efficiently, for other integer, in assemble_integer at line 1881, the hook returns false. For x86/Linux, the integer has TI mode (16 bytes, in 64 bits arithmetic operation, the intermediate value is of TI mode, usually saved by SSE register, but if spill happens, it will invoke assemble_ineger to push into the stack). The handling of data of TI mode is to split it into 4 words (4 bytes), then for immediate number (CONST_INT, CONST_DOUBLE etc), which is done by simplify_immed_subreg , then output by assemble_ineger . The treatment in simplify_immed_subreg is not complex and we have seen before, so skip it here.

 

你可能感兴趣的:(vector,struct,File,tree,Integer,output)