Mercurial > hg > CbC > CbC_gcc
comparison gcc/cp/optimize.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | |
children | 84e7813d76e9 |
comparison
equal
deleted
inserted
replaced
68:561a7518be6b | 111:04ced10e8804 |
---|---|
1 /* Perform optimizations on tree structure. | |
2 Copyright (C) 1998-2017 Free Software Foundation, Inc. | |
3 Written by Mark Michell (mark@codesourcery.com). | |
4 | |
5 This file is part of GCC. | |
6 | |
7 GCC is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published by | |
9 the Free Software Foundation; either version 3, or (at your option) | |
10 any later version. | |
11 | |
12 GCC is distributed in the hope that it will be useful, but | |
13 WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 General Public License for more details. | |
16 | |
17 You should have received a copy of the GNU General Public License | |
18 along with GCC; see the file COPYING3. If not see | |
19 <http://www.gnu.org/licenses/>. */ | |
20 | |
21 #include "config.h" | |
22 #include "system.h" | |
23 #include "coretypes.h" | |
24 #include "target.h" | |
25 #include "cp-tree.h" | |
26 #include "stringpool.h" | |
27 #include "cgraph.h" | |
28 #include "debug.h" | |
29 #include "tree-inline.h" | |
30 #include "tree-iterator.h" | |
31 | |
32 /* Prototypes. */ | |
33 | |
34 static void update_cloned_parm (tree, tree, bool); | |
35 | |
36 /* CLONED_PARM is a copy of CLONE, generated for a cloned constructor | |
37 or destructor. Update it to ensure that the source-position for | |
38 the cloned parameter matches that for the original, and that the | |
39 debugging generation code will be able to find the original PARM. */ | |
40 | |
41 static void | |
42 update_cloned_parm (tree parm, tree cloned_parm, bool first) | |
43 { | |
44 DECL_ABSTRACT_ORIGIN (cloned_parm) = parm; | |
45 | |
46 /* We may have taken its address. */ | |
47 TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm); | |
48 | |
49 /* The definition might have different constness. */ | |
50 TREE_READONLY (cloned_parm) = TREE_READONLY (parm); | |
51 | |
52 TREE_USED (cloned_parm) = !first || TREE_USED (parm); | |
53 | |
54 /* The name may have changed from the declaration. */ | |
55 DECL_NAME (cloned_parm) = DECL_NAME (parm); | |
56 DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm); | |
57 TREE_TYPE (cloned_parm) = TREE_TYPE (parm); | |
58 | |
59 DECL_GIMPLE_REG_P (cloned_parm) = DECL_GIMPLE_REG_P (parm); | |
60 } | |
61 | |
62 | |
63 /* FN is a function in High GIMPLE form that has a complete body and no | |
64 CFG. CLONE is a function whose body is to be set to a copy of FN, | |
65 mapping argument declarations according to the ARG_MAP splay_tree. */ | |
66 | |
67 static void | |
68 clone_body (tree clone, tree fn, void *arg_map) | |
69 { | |
70 copy_body_data id; | |
71 tree stmts; | |
72 | |
73 /* Clone the body, as if we were making an inline call. But, remap | |
74 the parameters in the callee to the parameters of caller. */ | |
75 memset (&id, 0, sizeof (id)); | |
76 id.src_fn = fn; | |
77 id.dst_fn = clone; | |
78 id.src_cfun = DECL_STRUCT_FUNCTION (fn); | |
79 id.decl_map = static_cast<hash_map<tree, tree> *> (arg_map); | |
80 | |
81 id.copy_decl = copy_decl_no_change; | |
82 id.transform_call_graph_edges = CB_CGE_DUPLICATE; | |
83 id.transform_new_cfg = true; | |
84 id.transform_return_to_modify = false; | |
85 id.transform_lang_insert_block = NULL; | |
86 | |
87 /* We're not inside any EH region. */ | |
88 id.eh_lp_nr = 0; | |
89 | |
90 stmts = DECL_SAVED_TREE (fn); | |
91 walk_tree (&stmts, copy_tree_body_r, &id, NULL); | |
92 | |
93 /* Also remap the initializer of any static variables so that they (in | |
94 particular, any label addresses) correspond to the base variant rather | |
95 than the abstract one. */ | |
96 if (DECL_NAME (clone) == base_dtor_identifier | |
97 || DECL_NAME (clone) == base_ctor_identifier) | |
98 { | |
99 unsigned ix; | |
100 tree decl; | |
101 | |
102 FOR_EACH_LOCAL_DECL (DECL_STRUCT_FUNCTION (fn), ix, decl) | |
103 walk_tree (&DECL_INITIAL (decl), copy_tree_body_r, &id, NULL); | |
104 } | |
105 | |
106 append_to_statement_list_force (stmts, &DECL_SAVED_TREE (clone)); | |
107 } | |
108 | |
109 /* DELETE_DTOR is a delete destructor whose body will be built. | |
110 COMPLETE_DTOR is the corresponding complete destructor. */ | |
111 | |
112 static void | |
113 build_delete_destructor_body (tree delete_dtor, tree complete_dtor) | |
114 { | |
115 tree parm = DECL_ARGUMENTS (delete_dtor); | |
116 tree virtual_size = cxx_sizeof (current_class_type); | |
117 | |
118 /* Call the corresponding complete destructor. */ | |
119 gcc_assert (complete_dtor); | |
120 tree call_dtor = build_cxx_call (complete_dtor, 1, &parm, | |
121 tf_warning_or_error); | |
122 | |
123 /* Call the delete function. */ | |
124 tree call_delete = build_op_delete_call (DELETE_EXPR, current_class_ptr, | |
125 virtual_size, | |
126 /*global_p=*/false, | |
127 /*placement=*/NULL_TREE, | |
128 /*alloc_fn=*/NULL_TREE, | |
129 tf_warning_or_error); | |
130 | |
131 /* Operator delete must be called, whether or not the dtor throws. */ | |
132 add_stmt (build2 (TRY_FINALLY_EXPR, void_type_node, call_dtor, call_delete)); | |
133 | |
134 /* Return the address of the object. */ | |
135 if (targetm.cxx.cdtor_returns_this ()) | |
136 { | |
137 tree val = DECL_ARGUMENTS (delete_dtor); | |
138 val = build2 (MODIFY_EXPR, TREE_TYPE (val), | |
139 DECL_RESULT (delete_dtor), val); | |
140 add_stmt (build_stmt (0, RETURN_EXPR, val)); | |
141 } | |
142 } | |
143 | |
144 /* Return name of comdat group for complete and base ctor (or dtor) | |
145 that have the same body. If dtor is virtual, deleting dtor goes | |
146 into this comdat group as well. */ | |
147 | |
148 static tree | |
149 cdtor_comdat_group (tree complete, tree base) | |
150 { | |
151 tree complete_name = DECL_ASSEMBLER_NAME (complete); | |
152 tree base_name = DECL_ASSEMBLER_NAME (base); | |
153 char *grp_name; | |
154 const char *p, *q; | |
155 bool diff_seen = false; | |
156 size_t idx; | |
157 gcc_assert (IDENTIFIER_LENGTH (complete_name) | |
158 == IDENTIFIER_LENGTH (base_name)); | |
159 grp_name = XALLOCAVEC (char, IDENTIFIER_LENGTH (complete_name) + 1); | |
160 p = IDENTIFIER_POINTER (complete_name); | |
161 q = IDENTIFIER_POINTER (base_name); | |
162 for (idx = 0; idx < IDENTIFIER_LENGTH (complete_name); idx++) | |
163 if (p[idx] == q[idx]) | |
164 grp_name[idx] = p[idx]; | |
165 else | |
166 { | |
167 gcc_assert (!diff_seen | |
168 && idx > 0 | |
169 && (p[idx - 1] == 'C' || p[idx - 1] == 'D' | |
170 || p[idx - 1] == 'I') | |
171 && p[idx] == '1' | |
172 && q[idx] == '2'); | |
173 grp_name[idx] = '5'; | |
174 diff_seen = true; | |
175 } | |
176 grp_name[idx] = '\0'; | |
177 gcc_assert (diff_seen); | |
178 return get_identifier (grp_name); | |
179 } | |
180 | |
181 /* Returns true iff we can make the base and complete [cd]tor aliases of | |
182 the same symbol rather than separate functions. */ | |
183 | |
184 static bool | |
185 can_alias_cdtor (tree fn) | |
186 { | |
187 /* If aliases aren't supported by the assembler, fail. */ | |
188 if (!TARGET_SUPPORTS_ALIASES) | |
189 return false; | |
190 | |
191 /* We can't use an alias if there are virtual bases. */ | |
192 if (CLASSTYPE_VBASECLASSES (DECL_CONTEXT (fn))) | |
193 return false; | |
194 /* ??? Why not use aliases with -frepo? */ | |
195 if (flag_use_repository) | |
196 return false; | |
197 gcc_assert (DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) | |
198 || DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)); | |
199 /* Don't use aliases for weak/linkonce definitions unless we can put both | |
200 symbols in the same COMDAT group. */ | |
201 return (DECL_INTERFACE_KNOWN (fn) | |
202 && (SUPPORTS_ONE_ONLY || !DECL_WEAK (fn)) | |
203 && (!DECL_ONE_ONLY (fn) | |
204 || (HAVE_COMDAT_GROUP && DECL_WEAK (fn)))); | |
205 } | |
206 | |
207 /* FN is a [cd]tor, fns is a pointer to an array of length 3. Fill fns | |
208 with pointers to the base, complete, and deleting variants. */ | |
209 | |
210 static void | |
211 populate_clone_array (tree fn, tree *fns) | |
212 { | |
213 tree clone; | |
214 | |
215 fns[0] = NULL_TREE; | |
216 fns[1] = NULL_TREE; | |
217 fns[2] = NULL_TREE; | |
218 | |
219 /* Look for the complete destructor which may be used to build the | |
220 delete destructor. */ | |
221 FOR_EACH_CLONE (clone, fn) | |
222 if (DECL_NAME (clone) == complete_dtor_identifier | |
223 || DECL_NAME (clone) == complete_ctor_identifier) | |
224 fns[1] = clone; | |
225 else if (DECL_NAME (clone) == base_dtor_identifier | |
226 || DECL_NAME (clone) == base_ctor_identifier) | |
227 fns[0] = clone; | |
228 else if (DECL_NAME (clone) == deleting_dtor_identifier) | |
229 fns[2] = clone; | |
230 else | |
231 gcc_unreachable (); | |
232 } | |
233 | |
234 /* FN is a constructor or destructor, and there are FUNCTION_DECLs | |
235 cloned from it nearby. Instead of cloning this body, leave it | |
236 alone and create tiny one-call bodies for the cloned | |
237 FUNCTION_DECLs. These clones are sibcall candidates, and their | |
238 resulting code will be very thunk-esque. */ | |
239 | |
240 static bool | |
241 maybe_thunk_body (tree fn, bool force) | |
242 { | |
243 tree bind, block, call, clone, clone_result, fn_parm, fn_parm_typelist; | |
244 tree last_arg, modify, *args; | |
245 int parmno, vtt_parmno, max_parms; | |
246 tree fns[3]; | |
247 | |
248 if (!force && !flag_declone_ctor_dtor) | |
249 return 0; | |
250 | |
251 /* If function accepts variable arguments, give up. */ | |
252 last_arg = tree_last (TYPE_ARG_TYPES (TREE_TYPE (fn))); | |
253 if (last_arg != void_list_node) | |
254 return 0; | |
255 | |
256 /* If we got this far, we've decided to turn the clones into thunks. */ | |
257 | |
258 /* We're going to generate code for fn, so it is no longer "abstract." | |
259 Also make the unified ctor/dtor private to either the translation unit | |
260 (for non-vague linkage ctors) or the COMDAT group (otherwise). */ | |
261 | |
262 populate_clone_array (fn, fns); | |
263 | |
264 /* Don't use thunks if the base clone omits inherited parameters. */ | |
265 if (fns[0] && ctor_omit_inherited_parms (fns[0])) | |
266 return 0; | |
267 | |
268 DECL_ABSTRACT_P (fn) = false; | |
269 if (!DECL_WEAK (fn)) | |
270 { | |
271 TREE_PUBLIC (fn) = false; | |
272 DECL_EXTERNAL (fn) = false; | |
273 DECL_INTERFACE_KNOWN (fn) = true; | |
274 } | |
275 else if (HAVE_COMDAT_GROUP) | |
276 { | |
277 /* At eof, defer creation of mangling aliases temporarily. */ | |
278 bool save_defer_mangling_aliases = defer_mangling_aliases; | |
279 defer_mangling_aliases = true; | |
280 tree comdat_group = cdtor_comdat_group (fns[1], fns[0]); | |
281 defer_mangling_aliases = save_defer_mangling_aliases; | |
282 cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group); | |
283 cgraph_node::get_create (fns[1])->add_to_same_comdat_group | |
284 (cgraph_node::get_create (fns[0])); | |
285 symtab_node::get (fn)->add_to_same_comdat_group | |
286 (symtab_node::get (fns[0])); | |
287 if (fns[2]) | |
288 /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is | |
289 virtual, it goes into the same comdat group as well. */ | |
290 cgraph_node::get_create (fns[2])->add_to_same_comdat_group | |
291 (symtab_node::get (fns[0])); | |
292 /* Emit them now that the thunks are same comdat group aliases. */ | |
293 if (!save_defer_mangling_aliases) | |
294 generate_mangling_aliases (); | |
295 TREE_PUBLIC (fn) = false; | |
296 DECL_EXTERNAL (fn) = false; | |
297 DECL_INTERFACE_KNOWN (fn) = true; | |
298 /* function_and_variable_visibility doesn't want !PUBLIC decls to | |
299 have these flags set. */ | |
300 DECL_WEAK (fn) = false; | |
301 DECL_COMDAT (fn) = false; | |
302 } | |
303 | |
304 /* Find the vtt_parm, if present. */ | |
305 for (vtt_parmno = -1, parmno = 0, fn_parm = DECL_ARGUMENTS (fn); | |
306 fn_parm; | |
307 ++parmno, fn_parm = TREE_CHAIN (fn_parm)) | |
308 { | |
309 if (DECL_ARTIFICIAL (fn_parm) | |
310 && DECL_NAME (fn_parm) == vtt_parm_identifier) | |
311 { | |
312 /* Compensate for removed in_charge parameter. */ | |
313 vtt_parmno = parmno; | |
314 break; | |
315 } | |
316 } | |
317 | |
318 /* Allocate an argument buffer for build_cxx_call(). | |
319 Make sure it is large enough for any of the clones. */ | |
320 max_parms = 0; | |
321 FOR_EACH_CLONE (clone, fn) | |
322 { | |
323 int length = list_length (DECL_ARGUMENTS (fn)); | |
324 if (length > max_parms) | |
325 max_parms = length; | |
326 } | |
327 args = XALLOCAVEC (tree, max_parms); | |
328 | |
329 /* We know that any clones immediately follow FN in TYPE_FIELDS. */ | |
330 FOR_EACH_CLONE (clone, fn) | |
331 { | |
332 tree clone_parm; | |
333 | |
334 /* If we've already generated a body for this clone, avoid | |
335 duplicating it. (Is it possible for a clone-list to grow after we | |
336 first see it?) */ | |
337 if (DECL_SAVED_TREE (clone) || TREE_ASM_WRITTEN (clone)) | |
338 continue; | |
339 | |
340 /* Start processing the function. */ | |
341 start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED); | |
342 | |
343 if (clone == fns[2]) | |
344 { | |
345 for (clone_parm = DECL_ARGUMENTS (clone); clone_parm; | |
346 clone_parm = TREE_CHAIN (clone_parm)) | |
347 DECL_ABSTRACT_ORIGIN (clone_parm) = NULL_TREE; | |
348 /* Build the delete destructor by calling complete destructor and | |
349 delete function. */ | |
350 build_delete_destructor_body (clone, fns[1]); | |
351 } | |
352 else | |
353 { | |
354 /* Walk parameter lists together, creating parameter list for | |
355 call to original function. */ | |
356 for (parmno = 0, | |
357 fn_parm = DECL_ARGUMENTS (fn), | |
358 fn_parm_typelist = TYPE_ARG_TYPES (TREE_TYPE (fn)), | |
359 clone_parm = DECL_ARGUMENTS (clone); | |
360 fn_parm; | |
361 ++parmno, | |
362 fn_parm = TREE_CHAIN (fn_parm)) | |
363 { | |
364 if (parmno == vtt_parmno && ! DECL_HAS_VTT_PARM_P (clone)) | |
365 { | |
366 gcc_assert (fn_parm_typelist); | |
367 /* Clobber argument with formal parameter type. */ | |
368 args[parmno] | |
369 = convert (TREE_VALUE (fn_parm_typelist), | |
370 null_pointer_node); | |
371 } | |
372 else if (parmno == 1 && DECL_HAS_IN_CHARGE_PARM_P (fn)) | |
373 { | |
374 tree in_charge | |
375 = copy_node (in_charge_arg_for_name (DECL_NAME (clone))); | |
376 args[parmno] = in_charge; | |
377 } | |
378 /* Map other parameters to their equivalents in the cloned | |
379 function. */ | |
380 else | |
381 { | |
382 gcc_assert (clone_parm); | |
383 DECL_ABSTRACT_ORIGIN (clone_parm) = NULL; | |
384 args[parmno] = clone_parm; | |
385 clone_parm = TREE_CHAIN (clone_parm); | |
386 } | |
387 if (fn_parm_typelist) | |
388 fn_parm_typelist = TREE_CHAIN (fn_parm_typelist); | |
389 } | |
390 | |
391 /* We built this list backwards; fix now. */ | |
392 mark_used (fn); | |
393 call = build_cxx_call (fn, parmno, args, tf_warning_or_error); | |
394 /* Arguments passed to the thunk by invisible reference should | |
395 be transmitted to the callee unchanged. Do not create a | |
396 temporary and invoke the copy constructor. The thunking | |
397 transformation must not introduce any constructor calls. */ | |
398 CALL_FROM_THUNK_P (call) = 1; | |
399 block = make_node (BLOCK); | |
400 if (targetm.cxx.cdtor_returns_this ()) | |
401 { | |
402 clone_result = DECL_RESULT (clone); | |
403 modify = build2 (MODIFY_EXPR, TREE_TYPE (clone_result), | |
404 clone_result, call); | |
405 modify = build1 (RETURN_EXPR, void_type_node, modify); | |
406 add_stmt (modify); | |
407 } | |
408 else | |
409 { | |
410 add_stmt (call); | |
411 } | |
412 bind = c_build_bind_expr (DECL_SOURCE_LOCATION (clone), | |
413 block, cur_stmt_list); | |
414 DECL_SAVED_TREE (clone) = push_stmt_list (); | |
415 add_stmt (bind); | |
416 } | |
417 | |
418 DECL_ABSTRACT_ORIGIN (clone) = NULL; | |
419 expand_or_defer_fn (finish_function (/*inline_p=*/false)); | |
420 } | |
421 return 1; | |
422 } | |
423 | |
424 /* FN is a function that has a complete body. Clone the body as | |
425 necessary. Returns nonzero if there's no longer any need to | |
426 process the main body. */ | |
427 | |
428 bool | |
429 maybe_clone_body (tree fn) | |
430 { | |
431 tree comdat_group = NULL_TREE; | |
432 tree clone; | |
433 tree fns[3]; | |
434 bool first = true; | |
435 int idx; | |
436 bool need_alias = false; | |
437 | |
438 /* We only clone constructors and destructors. */ | |
439 if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) | |
440 && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)) | |
441 return 0; | |
442 | |
443 populate_clone_array (fn, fns); | |
444 | |
445 /* Remember if we can't have multiple clones for some reason. We need to | |
446 check this before we remap local static initializers in clone_body. */ | |
447 if (!tree_versionable_function_p (fn)) | |
448 need_alias = true; | |
449 | |
450 /* We know that any clones immediately follow FN in the TYPE_FIELDS | |
451 list. */ | |
452 push_to_top_level (); | |
453 for (idx = 0; idx < 3; idx++) | |
454 { | |
455 tree parm; | |
456 tree clone_parm; | |
457 | |
458 clone = fns[idx]; | |
459 if (!clone) | |
460 continue; | |
461 | |
462 /* Update CLONE's source position information to match FN's. */ | |
463 DECL_SOURCE_LOCATION (clone) = DECL_SOURCE_LOCATION (fn); | |
464 DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn); | |
465 DECL_DECLARED_CONSTEXPR_P (clone) = DECL_DECLARED_CONSTEXPR_P (fn); | |
466 DECL_COMDAT (clone) = DECL_COMDAT (fn); | |
467 DECL_WEAK (clone) = DECL_WEAK (fn); | |
468 | |
469 /* We don't copy the comdat group from fn to clone because the assembler | |
470 name of fn was corrupted by write_mangled_name by adding *INTERNAL* | |
471 to it. By doing so, it also corrupted the comdat group. */ | |
472 if (DECL_ONE_ONLY (fn)) | |
473 cgraph_node::get_create (clone)->set_comdat_group (cxx_comdat_group (clone)); | |
474 DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn); | |
475 DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn); | |
476 DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn); | |
477 DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn); | |
478 TREE_PUBLIC (clone) = TREE_PUBLIC (fn); | |
479 DECL_VISIBILITY (clone) = DECL_VISIBILITY (fn); | |
480 DECL_VISIBILITY_SPECIFIED (clone) = DECL_VISIBILITY_SPECIFIED (fn); | |
481 DECL_DLLIMPORT_P (clone) = DECL_DLLIMPORT_P (fn); | |
482 DECL_ATTRIBUTES (clone) = copy_list (DECL_ATTRIBUTES (fn)); | |
483 DECL_DISREGARD_INLINE_LIMITS (clone) = DECL_DISREGARD_INLINE_LIMITS (fn); | |
484 set_decl_section_name (clone, DECL_SECTION_NAME (fn)); | |
485 | |
486 /* Adjust the parameter names and locations. */ | |
487 parm = DECL_ARGUMENTS (fn); | |
488 clone_parm = DECL_ARGUMENTS (clone); | |
489 /* Update the `this' parameter, which is always first. */ | |
490 update_cloned_parm (parm, clone_parm, first); | |
491 parm = DECL_CHAIN (parm); | |
492 clone_parm = DECL_CHAIN (clone_parm); | |
493 if (DECL_HAS_IN_CHARGE_PARM_P (fn)) | |
494 parm = DECL_CHAIN (parm); | |
495 if (DECL_HAS_VTT_PARM_P (fn)) | |
496 parm = DECL_CHAIN (parm); | |
497 if (DECL_HAS_VTT_PARM_P (clone)) | |
498 clone_parm = DECL_CHAIN (clone_parm); | |
499 for (; parm && clone_parm; | |
500 parm = DECL_CHAIN (parm), clone_parm = DECL_CHAIN (clone_parm)) | |
501 /* Update this parameter. */ | |
502 update_cloned_parm (parm, clone_parm, first); | |
503 } | |
504 | |
505 bool can_alias = can_alias_cdtor (fn); | |
506 | |
507 /* If we decide to turn clones into thunks, they will branch to fn. | |
508 Must have original function available to call. */ | |
509 if (!can_alias && maybe_thunk_body (fn, need_alias)) | |
510 { | |
511 pop_from_top_level (); | |
512 /* We still need to emit the original function. */ | |
513 return 0; | |
514 } | |
515 | |
516 /* Emit the DWARF1 abstract instance. */ | |
517 (*debug_hooks->deferred_inline_function) (fn); | |
518 | |
519 /* We know that any clones immediately follow FN in the TYPE_FIELDS. */ | |
520 for (idx = 0; idx < 3; idx++) | |
521 { | |
522 tree parm; | |
523 tree clone_parm; | |
524 int parmno; | |
525 hash_map<tree, tree> *decl_map; | |
526 bool alias = false; | |
527 | |
528 clone = fns[idx]; | |
529 if (!clone) | |
530 continue; | |
531 | |
532 /* Start processing the function. */ | |
533 start_preparsed_function (clone, NULL_TREE, SF_PRE_PARSED); | |
534 | |
535 /* Tell cgraph if both ctors or both dtors are known to have | |
536 the same body. */ | |
537 if (can_alias | |
538 && fns[0] | |
539 && idx == 1 | |
540 && cgraph_node::get_create (fns[0])->create_same_body_alias | |
541 (clone, fns[0])) | |
542 { | |
543 alias = true; | |
544 if (DECL_ONE_ONLY (fns[0])) | |
545 { | |
546 /* For comdat base and complete cdtors put them | |
547 into the same, *[CD]5* comdat group instead of | |
548 *[CD][12]*. */ | |
549 comdat_group = cdtor_comdat_group (fns[1], fns[0]); | |
550 cgraph_node::get_create (fns[0])->set_comdat_group (comdat_group); | |
551 if (symtab_node::get (clone)->same_comdat_group) | |
552 symtab_node::get (clone)->remove_from_same_comdat_group (); | |
553 symtab_node::get (clone)->add_to_same_comdat_group | |
554 (symtab_node::get (fns[0])); | |
555 } | |
556 } | |
557 | |
558 /* Build the delete destructor by calling complete destructor | |
559 and delete function. */ | |
560 if (idx == 2) | |
561 { | |
562 build_delete_destructor_body (clone, fns[1]); | |
563 /* If *[CD][12]* dtors go into the *[CD]5* comdat group and dtor is | |
564 virtual, it goes into the same comdat group as well. */ | |
565 if (comdat_group) | |
566 cgraph_node::get_create (clone)->add_to_same_comdat_group | |
567 (symtab_node::get (fns[0])); | |
568 } | |
569 else if (alias) | |
570 /* No need to populate body. */ ; | |
571 else | |
572 { | |
573 /* If we can't have multiple copies of FN (say, because there's a | |
574 static local initialized with the address of a label), we need | |
575 to use an alias for the complete variant. */ | |
576 if (idx == 1 && need_alias) | |
577 { | |
578 if (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_set) | |
579 sorry (DECL_STRUCT_FUNCTION (fn)->cannot_be_copied_reason, fn); | |
580 else | |
581 sorry ("making multiple clones of %qD", fn); | |
582 } | |
583 | |
584 /* Remap the parameters. */ | |
585 decl_map = new hash_map<tree, tree>; | |
586 for (parmno = 0, | |
587 parm = DECL_ARGUMENTS (fn), | |
588 clone_parm = DECL_ARGUMENTS (clone); | |
589 parm; | |
590 ++parmno, | |
591 parm = DECL_CHAIN (parm)) | |
592 { | |
593 /* Map the in-charge parameter to an appropriate constant. */ | |
594 if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1) | |
595 { | |
596 tree in_charge; | |
597 in_charge = in_charge_arg_for_name (DECL_NAME (clone)); | |
598 decl_map->put (parm, in_charge); | |
599 } | |
600 else if (DECL_ARTIFICIAL (parm) | |
601 && DECL_NAME (parm) == vtt_parm_identifier) | |
602 { | |
603 /* For a subobject constructor or destructor, the next | |
604 argument is the VTT parameter. Remap the VTT_PARM | |
605 from the CLONE to this parameter. */ | |
606 if (DECL_HAS_VTT_PARM_P (clone)) | |
607 { | |
608 DECL_ABSTRACT_ORIGIN (clone_parm) = parm; | |
609 decl_map->put (parm, clone_parm); | |
610 clone_parm = DECL_CHAIN (clone_parm); | |
611 } | |
612 /* Otherwise, map the VTT parameter to `NULL'. */ | |
613 else | |
614 { | |
615 tree t | |
616 = fold_convert (TREE_TYPE (parm), null_pointer_node); | |
617 decl_map->put (parm, t); | |
618 } | |
619 } | |
620 /* Map other parameters to their equivalents in the cloned | |
621 function. */ | |
622 else | |
623 { | |
624 tree replacement; | |
625 if (clone_parm) | |
626 { | |
627 replacement = clone_parm; | |
628 clone_parm = DECL_CHAIN (clone_parm); | |
629 } | |
630 else | |
631 { | |
632 /* Inheriting ctors can omit parameters from the base | |
633 clone. Replace them with null lvalues. */ | |
634 tree reftype = build_reference_type (TREE_TYPE (parm)); | |
635 replacement = fold_convert (reftype, null_pointer_node); | |
636 replacement = convert_from_reference (replacement); | |
637 } | |
638 decl_map->put (parm, replacement); | |
639 } | |
640 } | |
641 | |
642 if (targetm.cxx.cdtor_returns_this ()) | |
643 { | |
644 parm = DECL_RESULT (fn); | |
645 clone_parm = DECL_RESULT (clone); | |
646 decl_map->put (parm, clone_parm); | |
647 } | |
648 | |
649 /* Clone the body. */ | |
650 clone_body (clone, fn, decl_map); | |
651 | |
652 /* Clean up. */ | |
653 delete decl_map; | |
654 } | |
655 | |
656 /* The clone can throw iff the original function can throw. */ | |
657 cp_function_chain->can_throw = !TREE_NOTHROW (fn); | |
658 | |
659 /* Now, expand this function into RTL, if appropriate. */ | |
660 finish_function (/*inline_p=*/false); | |
661 BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn); | |
662 if (alias) | |
663 { | |
664 if (expand_or_defer_fn_1 (clone)) | |
665 emit_associated_thunks (clone); | |
666 /* We didn't generate a body, so remove the empty one. */ | |
667 DECL_SAVED_TREE (clone) = NULL_TREE; | |
668 } | |
669 else | |
670 expand_or_defer_fn (clone); | |
671 first = false; | |
672 } | |
673 pop_from_top_level (); | |
674 | |
675 /* We don't need to process the original function any further. */ | |
676 return 1; | |
677 } |