您的位置:首页 > 其它

Studying note of GCC-3.4.6 source (112)

2010-10-11 11:56 281 查看
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.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: