optimize.c revision 90075
190075Sobrien/* Perform optimizations on tree structure. 290075Sobrien Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc. 390075Sobrien Written by Mark Michell (mark@codesourcery.com). 490075Sobrien 590075SobrienThis file is part of GNU CC. 690075Sobrien 790075SobrienGNU CC is free software; you can redistribute it and/or modify it 890075Sobrienunder the terms of the GNU General Public License as published by 990075Sobrienthe Free Software Foundation; either version 2, or (at your option) 1090075Sobrienany later version. 1190075Sobrien 1290075SobrienGNU CC is distributed in the hope that it will be useful, but 1390075SobrienWITHOUT ANY WARRANTY; without even the implied warranty of 1490075SobrienMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1590075SobrienGeneral Public License for more details. 1690075Sobrien 1790075SobrienYou should have received a copy of the GNU General Public License 1890075Sobrienalong with GNU CC; see the file COPYING. If not, write to the Free 1990075SobrienSoftware Foundation, 59 Temple Place - Suite 330, Boston, MA 2090075Sobrien02111-1307, USA. */ 2190075Sobrien 2290075Sobrien#include "config.h" 2390075Sobrien#include "system.h" 2490075Sobrien#include "tree.h" 2590075Sobrien#include "cp-tree.h" 2690075Sobrien#include "rtl.h" 2790075Sobrien#include "insn-config.h" 2890075Sobrien#include "input.h" 2990075Sobrien#include "integrate.h" 3090075Sobrien#include "toplev.h" 3190075Sobrien#include "varray.h" 3290075Sobrien#include "ggc.h" 3390075Sobrien#include "params.h" 3490075Sobrien#include "hashtab.h" 3590075Sobrien#include "debug.h" 3690075Sobrien#include "tree-inline.h" 3790075Sobrien 3890075Sobrien/* Prototypes. */ 3990075Sobrien 4090075Sobrienstatic tree calls_setjmp_r PARAMS ((tree *, int *, void *)); 4190075Sobrienstatic void update_cloned_parm PARAMS ((tree, tree)); 4290075Sobrienstatic void dump_function PARAMS ((enum tree_dump_index, tree)); 4390075Sobrien 4490075Sobrien/* Optimize the body of FN. */ 4590075Sobrien 4690075Sobrienvoid 4790075Sobrienoptimize_function (fn) 4890075Sobrien tree fn; 4990075Sobrien{ 5090075Sobrien dump_function (TDI_original, fn); 5190075Sobrien 5290075Sobrien /* While in this function, we may choose to go off and compile 5390075Sobrien another function. For example, we might instantiate a function 5490075Sobrien in the hopes of inlining it. Normally, that wouldn't trigger any 5590075Sobrien actual RTL code-generation -- but it will if the template is 5690075Sobrien actually needed. (For example, if it's address is taken, or if 5790075Sobrien some other function already refers to the template.) If 5890075Sobrien code-generation occurs, then garbage collection will occur, so we 5990075Sobrien must protect ourselves, just as we do while building up the body 6090075Sobrien of the function. */ 6190075Sobrien ++function_depth; 6290075Sobrien 6390075Sobrien if (flag_inline_trees 6490075Sobrien /* We do not inline thunks, as (a) the backend tries to optimize 6590075Sobrien the call to the thunkee, (b) tree based inlining breaks that 6690075Sobrien optimization, (c) virtual functions are rarely inlineable, 6790075Sobrien and (d) ASM_OUTPUT_MI_THUNK is there to DTRT anyway. */ 6890075Sobrien && !DECL_THUNK_P (fn)) 6990075Sobrien { 7090075Sobrien optimize_inline_calls (fn); 7190075Sobrien 7290075Sobrien dump_function (TDI_inlined, fn); 7390075Sobrien } 7490075Sobrien 7590075Sobrien /* Undo the call to ggc_push_context above. */ 7690075Sobrien --function_depth; 7790075Sobrien 7890075Sobrien dump_function (TDI_optimized, fn); 7990075Sobrien} 8090075Sobrien 8190075Sobrien/* Called from calls_setjmp_p via walk_tree. */ 8290075Sobrien 8390075Sobrienstatic tree 8490075Sobriencalls_setjmp_r (tp, walk_subtrees, data) 8590075Sobrien tree *tp; 8690075Sobrien int *walk_subtrees ATTRIBUTE_UNUSED; 8790075Sobrien void *data ATTRIBUTE_UNUSED; 8890075Sobrien{ 8990075Sobrien /* We're only interested in FUNCTION_DECLS. */ 9090075Sobrien if (TREE_CODE (*tp) != FUNCTION_DECL) 9190075Sobrien return NULL_TREE; 9290075Sobrien 9390075Sobrien return setjmp_call_p (*tp) ? *tp : NULL_TREE; 9490075Sobrien} 9590075Sobrien 9690075Sobrien/* Returns non-zero if FN calls `setjmp' or some other function that 9790075Sobrien can return more than once. This function is conservative; it may 9890075Sobrien occasionally return a non-zero value even when FN does not actually 9990075Sobrien call `setjmp'. */ 10090075Sobrien 10190075Sobrienint 10290075Sobriencalls_setjmp_p (fn) 10390075Sobrien tree fn; 10490075Sobrien{ 10590075Sobrien return walk_tree_without_duplicates (&DECL_SAVED_TREE (fn), 10690075Sobrien calls_setjmp_r, 10790075Sobrien NULL) != NULL_TREE; 10890075Sobrien} 10990075Sobrien 11090075Sobrien/* CLONED_PARM is a copy of CLONE, generated for a cloned constructor 11190075Sobrien or destructor. Update it to ensure that the source-position for 11290075Sobrien the cloned parameter matches that for the original, and that the 11390075Sobrien debugging generation code will be able to find the original PARM. */ 11490075Sobrien 11590075Sobrienstatic void 11690075Sobrienupdate_cloned_parm (parm, cloned_parm) 11790075Sobrien tree parm; 11890075Sobrien tree cloned_parm; 11990075Sobrien{ 12090075Sobrien DECL_ABSTRACT_ORIGIN (cloned_parm) = parm; 12190075Sobrien 12290075Sobrien /* We may have taken its address. */ 12390075Sobrien TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm); 12490075Sobrien 12590075Sobrien /* The definition might have different constness. */ 12690075Sobrien TREE_READONLY (cloned_parm) = TREE_READONLY (parm); 12790075Sobrien 12890075Sobrien TREE_USED (cloned_parm) = TREE_USED (parm); 12990075Sobrien 13090075Sobrien /* The name may have changed from the declaration. */ 13190075Sobrien DECL_NAME (cloned_parm) = DECL_NAME (parm); 13290075Sobrien DECL_SOURCE_FILE (cloned_parm) = DECL_SOURCE_FILE (parm); 13390075Sobrien DECL_SOURCE_LINE (cloned_parm) = DECL_SOURCE_LINE (parm); 13490075Sobrien} 13590075Sobrien 13690075Sobrien/* FN is a function that has a complete body. Clone the body as 13790075Sobrien necessary. Returns non-zero if there's no longer any need to 13890075Sobrien process the main body. */ 13990075Sobrien 14090075Sobrienint 14190075Sobrienmaybe_clone_body (fn) 14290075Sobrien tree fn; 14390075Sobrien{ 14490075Sobrien tree clone; 14590075Sobrien int first = 1; 14690075Sobrien 14790075Sobrien /* We only clone constructors and destructors. */ 14890075Sobrien if (!DECL_MAYBE_IN_CHARGE_CONSTRUCTOR_P (fn) 14990075Sobrien && !DECL_MAYBE_IN_CHARGE_DESTRUCTOR_P (fn)) 15090075Sobrien return 0; 15190075Sobrien 15290075Sobrien /* Emit the DWARF1 abstract instance. */ 15390075Sobrien (*debug_hooks->deferred_inline_function) (fn); 15490075Sobrien 15590075Sobrien /* We know that any clones immediately follow FN in the TYPE_METHODS 15690075Sobrien list. */ 15790075Sobrien for (clone = TREE_CHAIN (fn); 15890075Sobrien clone && DECL_CLONED_FUNCTION_P (clone); 15990075Sobrien clone = TREE_CHAIN (clone), first = 0) 16090075Sobrien { 16190075Sobrien tree parm; 16290075Sobrien tree clone_parm; 16390075Sobrien int parmno; 16490075Sobrien splay_tree decl_map; 16590075Sobrien 16690075Sobrien /* Update CLONE's source position information to match FN's. */ 16790075Sobrien DECL_SOURCE_FILE (clone) = DECL_SOURCE_FILE (fn); 16890075Sobrien DECL_SOURCE_LINE (clone) = DECL_SOURCE_LINE (fn); 16990075Sobrien DECL_INLINE (clone) = DECL_INLINE (fn); 17090075Sobrien DECL_DECLARED_INLINE_P (clone) = DECL_DECLARED_INLINE_P (fn); 17190075Sobrien DECL_COMDAT (clone) = DECL_COMDAT (fn); 17290075Sobrien DECL_WEAK (clone) = DECL_WEAK (fn); 17390075Sobrien DECL_ONE_ONLY (clone) = DECL_ONE_ONLY (fn); 17490075Sobrien DECL_SECTION_NAME (clone) = DECL_SECTION_NAME (fn); 17590075Sobrien DECL_USE_TEMPLATE (clone) = DECL_USE_TEMPLATE (fn); 17690075Sobrien DECL_EXTERNAL (clone) = DECL_EXTERNAL (fn); 17790075Sobrien DECL_INTERFACE_KNOWN (clone) = DECL_INTERFACE_KNOWN (fn); 17890075Sobrien DECL_NOT_REALLY_EXTERN (clone) = DECL_NOT_REALLY_EXTERN (fn); 17990075Sobrien TREE_PUBLIC (clone) = TREE_PUBLIC (fn); 18090075Sobrien 18190075Sobrien /* Adjust the parameter names and locations. */ 18290075Sobrien parm = DECL_ARGUMENTS (fn); 18390075Sobrien clone_parm = DECL_ARGUMENTS (clone); 18490075Sobrien /* Update the `this' parameter, which is always first. */ 18590075Sobrien update_cloned_parm (parm, clone_parm); 18690075Sobrien parm = TREE_CHAIN (parm); 18790075Sobrien clone_parm = TREE_CHAIN (clone_parm); 18890075Sobrien if (DECL_HAS_IN_CHARGE_PARM_P (fn)) 18990075Sobrien parm = TREE_CHAIN (parm); 19090075Sobrien if (DECL_HAS_VTT_PARM_P (fn)) 19190075Sobrien parm = TREE_CHAIN (parm); 19290075Sobrien if (DECL_HAS_VTT_PARM_P (clone)) 19390075Sobrien clone_parm = TREE_CHAIN (clone_parm); 19490075Sobrien for (; parm; 19590075Sobrien parm = TREE_CHAIN (parm), clone_parm = TREE_CHAIN (clone_parm)) 19690075Sobrien { 19790075Sobrien /* Update this parameter. */ 19890075Sobrien update_cloned_parm (parm, clone_parm); 19990075Sobrien /* We should only give unused information for one clone. */ 20090075Sobrien if (!first) 20190075Sobrien TREE_USED (clone_parm) = 1; 20290075Sobrien } 20390075Sobrien 20490075Sobrien /* Start processing the function. */ 20590075Sobrien push_to_top_level (); 20690075Sobrien start_function (NULL_TREE, clone, NULL_TREE, SF_PRE_PARSED); 20790075Sobrien 20890075Sobrien /* Remap the parameters. */ 20990075Sobrien decl_map = splay_tree_new (splay_tree_compare_pointers, NULL, NULL); 21090075Sobrien for (parmno = 0, 21190075Sobrien parm = DECL_ARGUMENTS (fn), 21290075Sobrien clone_parm = DECL_ARGUMENTS (clone); 21390075Sobrien parm; 21490075Sobrien ++parmno, 21590075Sobrien parm = TREE_CHAIN (parm)) 21690075Sobrien { 21790075Sobrien /* Map the in-charge parameter to an appropriate constant. */ 21890075Sobrien if (DECL_HAS_IN_CHARGE_PARM_P (fn) && parmno == 1) 21990075Sobrien { 22090075Sobrien tree in_charge; 22190075Sobrien in_charge = in_charge_arg_for_name (DECL_NAME (clone)); 22290075Sobrien splay_tree_insert (decl_map, 22390075Sobrien (splay_tree_key) parm, 22490075Sobrien (splay_tree_value) in_charge); 22590075Sobrien } 22690075Sobrien else if (DECL_ARTIFICIAL (parm) 22790075Sobrien && DECL_NAME (parm) == vtt_parm_identifier) 22890075Sobrien { 22990075Sobrien /* For a subobject constructor or destructor, the next 23090075Sobrien argument is the VTT parameter. Remap the VTT_PARM 23190075Sobrien from the CLONE to this parameter. */ 23290075Sobrien if (DECL_HAS_VTT_PARM_P (clone)) 23390075Sobrien { 23490075Sobrien DECL_ABSTRACT_ORIGIN (clone_parm) = parm; 23590075Sobrien splay_tree_insert (decl_map, 23690075Sobrien (splay_tree_key) parm, 23790075Sobrien (splay_tree_value) clone_parm); 23890075Sobrien clone_parm = TREE_CHAIN (clone_parm); 23990075Sobrien } 24090075Sobrien /* Otherwise, map the VTT parameter to `NULL'. */ 24190075Sobrien else 24290075Sobrien { 24390075Sobrien splay_tree_insert (decl_map, 24490075Sobrien (splay_tree_key) parm, 24590075Sobrien (splay_tree_value) null_pointer_node); 24690075Sobrien } 24790075Sobrien } 24890075Sobrien /* Map other parameters to their equivalents in the cloned 24990075Sobrien function. */ 25090075Sobrien else 25190075Sobrien { 25290075Sobrien splay_tree_insert (decl_map, 25390075Sobrien (splay_tree_key) parm, 25490075Sobrien (splay_tree_value) clone_parm); 25590075Sobrien clone_parm = TREE_CHAIN (clone_parm); 25690075Sobrien } 25790075Sobrien } 25890075Sobrien 25990075Sobrien /* Clone the body. */ 26090075Sobrien clone_body (clone, fn, decl_map); 26190075Sobrien 26290075Sobrien /* There are as many statements in the clone as in the 26390075Sobrien original. */ 26490075Sobrien DECL_NUM_STMTS (clone) = DECL_NUM_STMTS (fn); 26590075Sobrien 26690075Sobrien /* Clean up. */ 26790075Sobrien splay_tree_delete (decl_map); 26890075Sobrien 26990075Sobrien /* Now, expand this function into RTL, if appropriate. */ 27090075Sobrien finish_function (0); 27190075Sobrien BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn); 27290075Sobrien expand_body (clone); 27390075Sobrien pop_from_top_level (); 27490075Sobrien } 27590075Sobrien 27690075Sobrien /* We don't need to process the original function any further. */ 27790075Sobrien return 1; 27890075Sobrien} 27990075Sobrien 28090075Sobrien/* Dump FUNCTION_DECL FN as tree dump PHASE. */ 28190075Sobrien 28290075Sobrienstatic void 28390075Sobriendump_function (phase, fn) 28490075Sobrien enum tree_dump_index phase; 28590075Sobrien tree fn; 28690075Sobrien{ 28790075Sobrien FILE *stream; 28890075Sobrien int flags; 28990075Sobrien 29090075Sobrien stream = dump_begin (phase, &flags); 29190075Sobrien if (stream) 29290075Sobrien { 29390075Sobrien fprintf (stream, "\n;; Function %s", 29490075Sobrien decl_as_string (fn, TFF_DECL_SPECIFIERS)); 29590075Sobrien fprintf (stream, " (%s)\n", 29690075Sobrien decl_as_string (DECL_ASSEMBLER_NAME (fn), 0)); 29790075Sobrien fprintf (stream, ";; enabled by -%s\n", dump_flag_name (phase)); 29890075Sobrien fprintf (stream, "\n"); 29990075Sobrien 30090075Sobrien dump_node (fn, TDF_SLIM | flags, stream); 30190075Sobrien dump_end (phase, stream); 30290075Sobrien } 30390075Sobrien} 304