Studying note of GCC-3.4.6 source (112)

5.12.3.2.1.2.1.4.    Prepare for code generation

The last invocation in cp_parser_function_definition_after_declarator is expand_or_defer_fn . If appropriate, it will generate RTL code for the function; or it does some preparation for RTL generation.

 

2973   void

2974   expand_or_defer_fn (tree fn)                                                             in semantics.c

2975   {

2976     /* When the parser calls us after finishing the body of a template

2977       function, we don't really want to expand the body.  */

2978     if (processing_template_decl )

2979     {

2980       /* Normally, collection only occurs in rest_of_compilation. So,

2981         if we don't collect here, we never collect junk generated

2982         during the processing of templates until we hit a

2983         non-template function.  */

2984       ggc_collect ();

2985       return ;

2986     }

2987  

2988     /* Replace AGGR_INIT_EXPRs with appropriate CALL_EXPRs.  */

2989     walk_tree_without_duplicates (&DECL_SAVED_TREE (fn),

2990                               simplify_aggr_init_exprs_r,

2991                               NULL);

2992  

2993     /* If this is a constructor or destructor body, we have to clone

2994       it.  */

2995     if (maybe_clone_body (fn))

2996     {

2997       /* We don't want to process FN again, so pretend we've written

2998         it out, even though we haven't.  */

2999       TREE_ASM_WRITTEN (fn) = 1;

3000       return ;

3001     }

3002  

3003     /* There's no reason to do any of the work here if we're only doing

3004       semantic analysis; this code just generates RTL.  */

3005     if (flag_syntax_only )

3006       return ;

3007  

3008     /* Compute the appropriate object-file linkage for inline functions.  */

3009     if (DECL_DECLARED_INLINE_P (fn))

3010       import_export_decl (fn);

3011  

3012     /* If this function is marked with the constructor attribute, add it

3013       to the list of functions to be called along with constructors

3014       from static duration objects.  */

3015     if (DECL_STATIC_CONSTRUCTOR (fn))

3016       static_ctors = tree_cons (NULL_TREE, fn, static_ctors );

3017  

3018     /* If this function is marked with the destructor attribute, add it

3019       to the list of functions to be called along with destructors from

3020       static duration objects.  */

3021     if (DECL_STATIC_DESTRUCTOR (fn))

3022       static_dtors = tree_cons (NULL_TREE, fn, static_dtors );

3023  

3024     function_depth ++;

3025  

3026     /* Expand or defer, at the whim of the compilation unit manager.  */

3027     cgraph_finalize_function (fn, function_depth > 1);

3028  

3029     function_depth --;

3030   }

 

The iteration of the tree for the function definition at line 2989, processes the call of function suitable for named return value optimization. We will study it with nrv later.

Above predicate DECL_STATIC_CONSTRUCTOR or DECL_STATIC_DESTRUCTOR holds if the function is declared with __attribute__ ((constructor)) or __attribute__ ((destructor)) . The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.

5.12.3.2.1.2.1.4.1.            Update call-graph

Previous section Graph of relation between caller and callee describes cgraph_node and cgraph_edge . Also it studies routine cgraph_node which creates single node of cgraph_node for every function at first invocation and returns this unique node in later invocations. It is the first time to invoke cgraph_finalize_function and cgraph_node for function specified by decl during the compilation.

 

157    void

158    cgraph_finalize_function (tree decl, bool nested)                                 in cgraphunit.c

159    {

160      struct cgraph_node *node = cgraph_node (decl);

161   

162      if (node->local.finalized)

163      {

164        /* As an GCC extension we allow redefinition of the function. The

165          semantics when both copies of bodies differ is not well defined.

166          We replace the old body with new body so in unit at a time mode

167          we always use new body, while in normal mode we may end up with

168          old body inlined into some functions and new body expanded and

169          inlined in others.

170        

171          ??? It may make more sense to use one body for inlining and other

172          body for expanding the function but this is difficult to do.  */

173   

174        /* If node->output is set, then this is a unit-at-a-time compilation

175          and we have already begun whole-unit analysis. This is *not*

176          testing for whether we've already emitted the function. That

177          case can be sort-of legitimately seen with real function

178          redefinition errors. I would argue that the front end should

179          never present us with such a case, but don't enforce that for now.  */

180        if (node->output)

181          abort ();

182   

183         /* Reset our datastructures so we can analyze the function again.  */

184        memset (&node->local, 0, sizeof (node->local));

185        memset (&node->global, 0, sizeof (node->global));

186        memset (&node->rtl, 0, sizeof (node->rtl));

187        node->analyzed = false;

188        node->local.redefined_extern_inline = true;

189        while (node->callees)

190          cgraph_remove_edge (node, node->callees->callee);

191   

192        /* We may need to re-queue the node for assembling in case

193          we already proceeded it and ignored as not needed.  */

194        if (node->reachable && !flag_unit_at_a_time )

195        {

196          struct cgraph_node *n;

197   

198          for (n = cgraph_nodes_queue ; n; n = n->next_needed)

199            if (n == node)

200              break ;

201          if (!n)

202            node->reachable = 0;

203        }

204      }

205   

206      notice_global_symbol (decl);

207      node->decl = decl;

208      node->local.finalized = true;

209   

210      /* If not unit at a time, then we need to create the call graph

211         now, so that called functions can be queued and emitted now.  */

212      if (!flag_unit_at_a_time )

213      {

214        cgraph_analyze_function (node);

215        cgraph_decide_inlining_incrementally (node);

216      }

 

In the first time invocation, node->local.finalized must be false, but it is updated to true at line 208 immediately. At line 206, notice_global_symbol collects first visible global symbol. As global symbol must be unique across the translation unit, it is useful to generate unique name for the nameless object by the compiler, for example, symbol collected here will be used to generate internal name of annoymous namespace.

 

1034   void

1035   notice_global_symbol (tree decl)                                                              in varasm.c

1036   {

1037     const char **type = &first_global_object_name ;

1038  

1039     if (first_global_object_name

1040         || !TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)

1041         || !DECL_NAME (decl)

1042         || (TREE_CODE (decl) != FUNCTION_DECL

1043            && (TREE_CODE (decl) != VAR_DECL

1044                 || (DECL_COMMON (decl)

1045                   && (DECL_INITIAL (decl) == 0

1046                       || DECL_INITIAL (decl) == error_mark_node))))

1047         || GET_CODE (DECL_RTL (decl)) != MEM)

1048       return ;

1049  

1050     /* We win when global object is found, but it is usefull to know about weak

1051       symbol as well so we can produce nicer unique names.  */

1052     if (DECL_WEAK (decl) || DECL_ONE_ONLY (decl))

1053       type = &weak_global_object_name ;

1054  

1055     if (!*type)

1056     {

1057       const char *p;

1058       char *name;

1059       rtx decl_rtl = DECL_RTL (decl);

1060  

1061       p = (* targetm .strip_name_encoding) (XSTR (XEXP (decl_rtl, 0), 0));

1062       name = xstrdup (p);

1063  

1064       *type = name;

1065     }

1066   }

 

At line 212 in cgraph_finalize_function , flag_unit_at_a_time is set as 1 if we specify optimization switch higher than –O2 in the compiling command. Usually, we would like to use –O3 option to squeeze out all optimization ability from the compiler. Here assuming flag_unit_at_a_time is 1.

 

cgraph_finalize_function (continue)

 

218      if (decide_is_function_needed (node, decl))

219        cgraph_mark_needed_node (node);

220   

221      /* If not unit at a time, go ahead and emit everything we've found

222        to be reachable at this time.  */

223      if (!nested)

224      {

225        if (!cgraph_assemble_pending_functions ())

226          ggc_collect ();

227      }

228   

229      /* If we've not yet emitted decl, tell the debug info about it.  */

230      if (!TREE_ASM_WRITTEN (decl))

231        (*debug_hooks ->deferred_inline_function) (decl);

232   

233      /* We will never really output the function body, clear the SAVED_INSNS array

234        early then.  */

235      if (DECL_EXTERNAL (decl))

236        DECL_SAVED_INSNS (decl) = NULL;

237    }

 

Routine decide_is_function_needed determines if decl is visible to something either outside this translation unit, something magic in the system configuration, or (if not doing unit-at-a-time) to something we haven't seen yet. At line 93, attribute “used” means that the variable must be emitted even if it appears that the variable is not referenced (compiler will eliminate dead code).

 

73      static bool

74      decide_is_function_needed (struct cgraph_node *node, tree decl)          in cgraphunit.c

75      {

76        /* If we decided it was needed before, but at the time we didn't have

77          the body of the function available, then it's still needed. We have

78          to go back and re-check its dependencies now.  */

79        if (node->needed)

80          return true;

81     

82        /* Externally visible functions must be output. The exception is

83          COMDAT functions that must be output only when they are needed.  */

84        if (TREE_PUBLIC (decl) && !DECL_COMDAT (decl) && !DECL_EXTERNAL (decl))

85          return true;

86     

87        /* Constructors and destructors are reachable from the runtime by

88          some mechanism.  */

89        if (DECL_STATIC_CONSTRUCTOR (decl) || DECL_STATIC_DESTRUCTOR (decl))

90          return true;

91     

92        /* If the user told us it is used, then it must be so.  */

93        if (lookup_attribute ("used", DECL_ATTRIBUTES (decl)))

94          return true;

95     

96        /* ??? If the assembler name is set by hand, it is possible to assemble

97          the name later after finalizing the function and the fact is noticed

98          i n assemble_name then. This is arguably a bug.  */

99        if (DECL_ASSEMBLER_NAME_SET_P (decl)

100          && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))

101        return true;

102   

103      if (flag_unit_at_a_time )

104        return false;

105   

106      /* If not doing unit at a time, then we'll only defer this function

107        if its marked for inlining. Otherwise we want to emit it now.  */

108   

109      /* "extern inline" functions are never output locally.  */

110       if (DECL_EXTERNAL (decl))

111         return false;

112       /* We want to emit COMDAT functions only when absolutely necessary.  */

113       if (DECL_COMDAT (decl))

114         return false;

115       if (!DECL_INLINE (decl)

116          || (!node->local.disregard_inline_limits

117            /* When declared inline, defer even the uninlinable functions.

118               This allows them to be eliminated when unused.  */

119            && !DECL_DECLARED_INLINE_P (decl)

120           && (!node->local.inlinable || !cgraph_default_inline_p (node))))

121        return true;

122   

123      return false;

124    }

 

If the declaration is visible, cgraph_mark_needed_node needs set the relevant cgraph_node as needed and mark its subnodes as reachable.

 

286    void

287    cgraph_mark_needed_node (struct cgraph_node *node)                               in cgraph.c

288    {

289      node->needed = 1;

290      cgraph_mark_reachable_node (node);

291    }

 

Slot local.finalized is set as true in cgraph_finalize_function already. In routine cgraph_node , line 123 through 128, field origin refers to node of containing function; field nested refers to the node of contained function (i.e, function invoked within); and field next_nested refers to the node of sibling functions contained within the containing function.

 

260    void

261    cgraph_mark_reachable_node (struct cgraph_node *node)                           in cgraph.c

262    {

263      if (!node->reachable && node->local.finalized)

264      {

265        notice_global_symbol (node->decl);

266        node->reachable = 1;

267   

268        node->next_needed = cgraph_nodes_queue ;

269        cgraph_nodes_queue = node;

270   

271        /* At the moment frontend automatically emits all nested functions.  */

272        if (node->nested)

273        {

274          struct cgraph_node *node2;

275   

276          for (node2 = node->nested; node2; node2 = node2->next_nested)

277            if (!node2->reachable)

278              cgraph_mark_reachable_node (node2);

279        }

280      }

281    }

 

All nodes of external visible functions should be chained tegother, which is pointed by cgraph_nodes_queue .

Back cgraph_finalize_function , if it is not a nested function (inline function defined within another function or class context), cgraph_assemble_pending_functions just returns false, if flag_unit_at_a_time is true, to trigger garbage collection.

 

你可能感兴趣的:(Studying note of GCC-3.4.6 source (112))