diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-03-05 01:33:27 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-03-05 01:33:27 +0000 |
commit | 80a85d8a0476d7921ab8a4f04c38a24c60ca159d (patch) | |
tree | c65a7c71518b86c824939e78d633204bce6006c7 | |
parent | f3672f9947359a3d452bed56c957e7ed418fabe5 (diff) | |
download | gcc-80a85d8a0476d7921ab8a4f04c38a24c60ca159d.tar.gz |
* gcc.dg/i386-local.c: New.
* toplev.c (rest_of_compilation): Deffer RTL compilation only when
RTL inlining is done.
* cgraphunit.c (cgraph_mark_local_functions): New local function.
(cgraph_optimize): Mark local functions.
* i386-protos.h (init_cumulative_args): Update prototype.
* i386.c (init_cumulative_args): Use register passing convention for
local functions.
* cgraph.c (cgraph_global_info_ready): New global variable
(cgraph_local_info, cgraph_global_info): New functions.
* cgraph.h (struct cgraph_local_info, cgraph_global_info): New
structures.
(cgraph_local_info, cgraph_global_info, cgraph_global_info_ready):
Declare.
* cgraphunit.c (cgraph_finalize_function): Set inline_many.
(cgraph_mark_functions_to_output): Use inline_many.
(cgraph_expand_function): Free DECL_SAVED_TREE uncondtionally.
(cgraph_expand_functions): Expand inline functions last.
(cgraph_optimize): Do not emit uneeded functions.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@63822 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/cgraph.c | 30 | ||||
-rw-r--r-- | gcc/cgraph.h | 26 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 67 | ||||
-rw-r--r-- | gcc/config/i386/i386-protos.h | 3 | ||||
-rw-r--r-- | gcc/config/i386/i386.c | 42 | ||||
-rw-r--r-- | gcc/config/i386/i386.h | 17 | ||||
-rw-r--r-- | gcc/doc/invoke.texi | 4 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 4 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/i386-local.c | 14 | ||||
-rw-r--r-- | gcc/toplev.c | 1 |
11 files changed, 200 insertions, 31 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 07a7c49ecef..4d30aba002b 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +Wed Mar 5 02:04:04 CET 2003 Jan Hubicka <jh@suse.cz> + + * toplev.c (rest_of_compilation): Deffer RTL compilation only when + RTL inlining is done. + + * cgraphunit.c (cgraph_mark_local_functions): New local function. + (cgraph_optimize): Mark local functions. + * i386-protos.h (init_cumulative_args): Update prototype. + * i386.c (init_cumulative_args): Use register passing convention for + local functions. + + * cgraph.c (cgraph_global_info_ready): New global variable + (cgraph_local_info, cgraph_global_info): New functions. + * cgraph.h (struct cgraph_local_info, cgraph_global_info): New + structures. + (cgraph_local_info, cgraph_global_info, cgraph_global_info_ready): + Declare. + * cgraphunit.c (cgraph_finalize_function): Set inline_many. + (cgraph_mark_functions_to_output): Use inline_many. + (cgraph_expand_function): Free DECL_SAVED_TREE uncondtionally. + (cgraph_expand_functions): Expand inline functions last. + (cgraph_optimize): Do not emit uneeded functions. + 2003-03-04 Steve Ellcey <sje@cup.hp.com> * expr.c (convert_modes): Check for legal hard register. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 7df18f14891..d947eb99910 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -43,6 +43,9 @@ struct cgraph_node *cgraph_nodes; /* Number of nodes in existence. */ int cgraph_n_nodes; +/* Set when whole unit has been analyzed so we can access global info. */ +bool cgraph_global_info_ready = false; + static struct cgraph_edge *create_edge PARAMS ((struct cgraph_node *, struct cgraph_node *)); static void remove_edge PARAMS ((struct cgraph_node *, struct cgraph_node *)); @@ -175,6 +178,33 @@ cgraph_calls_p (caller_decl, callee_decl) return edge != NULL; } +/* Return local info for the compiled function. */ + +struct cgraph_local_info * +cgraph_local_info (decl) + tree decl; +{ + struct cgraph_node *node; + if (TREE_CODE (decl) != FUNCTION_DECL) + abort (); + node = cgraph_node (decl); + return &node->local; +} + +/* Return local info for the compiled function. */ + +struct cgraph_global_info * +cgraph_global_info (decl) + tree decl; +{ + struct cgraph_node *node; + if (TREE_CODE (decl) != FUNCTION_DECL || !cgraph_global_info_ready) + abort (); + node = cgraph_node (decl); + return &node->global; +} + + /* Dump the callgraph. */ void diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 8dd37ed9e32..4404fb8b838 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -22,6 +22,27 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #ifndef GCC_CGRAPH_H #define GCC_CGRAPH_H +/* Information about the function collected locally. + Available after function is lowered */ + +struct cgraph_local_info +{ + /* Set when function function is visiable in current compilation unit only + and it's address is never taken. */ + bool local; + bool inline_many; +}; + +/* Information about the function that needs to be computed globally + once compilation is finished. Available only with -funit-at-time. */ + +struct cgraph_global_info +{ + /* Empty for the moment. */ + int dummy; +}; + + /* The cgraph data strutcture. Each function decl has assigned cgraph_node listing calees and callers. */ @@ -51,6 +72,8 @@ struct cgraph_node bool lowered; /* Set when function is scheduled to be assembled. */ bool output; + struct cgraph_local_info local; + struct cgraph_global_info global; }; struct cgraph_edge @@ -62,6 +85,7 @@ struct cgraph_edge extern struct cgraph_node *cgraph_nodes; extern int cgraph_n_nodes; +extern bool cgraph_global_info_ready; /* In cgraph.c */ void dump_cgraph PARAMS ((FILE *)); @@ -69,6 +93,8 @@ void cgraph_remove_call PARAMS ((tree, tree)); struct cgraph_edge *cgraph_record_call PARAMS ((tree, tree)); struct cgraph_node *cgraph_node PARAMS ((tree decl)); bool cgraph_calls_p PARAMS ((tree, tree)); +struct cgraph_local_info *cgraph_local_info PARAMS ((tree)); +struct cgraph_global_info *cgraph_global_info PARAMS ((tree)); /* In cgraphunit.c */ void cgraph_finalize_function PARAMS ((tree, tree)); diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 0a12ddad856..81a8b2e29f4 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -33,11 +33,13 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "debug.h" #include "target.h" #include "cgraph.h" +#include "diagnostic.h" static void cgraph_expand_functions PARAMS ((void)); static void cgraph_mark_functions_to_output PARAMS ((void)); static void cgraph_expand_function PARAMS ((struct cgraph_node *)); static tree record_call_1 PARAMS ((tree *, int *, void *)); +static void cgraph_mark_local_functions PARAMS ((void)); /* Analyze function once it is parsed. Set up the local information available - create cgraph edges for function calles via BODY. */ @@ -51,8 +53,10 @@ cgraph_finalize_function (decl, body) node->decl = decl; - /* Set TREE_UNINLINABLE flag. */ - tree_inlinable_function_p (decl); + if (flag_inline_trees) + node->local.inline_many = tree_inlinable_function_p (decl); + else + node->local.inline_many = 0; (*debug_hooks->deferred_inline_function) (decl); } @@ -217,7 +221,7 @@ cgraph_mark_functions_to_output () if (DECL_SAVED_TREE (decl) && (node->needed - || (DECL_UNINLINABLE (decl) && node->reachable) + || (!node->local.inline_many && node->reachable) || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) && !TREE_ASM_WRITTEN (decl) && !node->origin && !DECL_EXTERNAL (decl)) @@ -235,6 +239,8 @@ cgraph_expand_function (node) announce_function (decl); if (flag_inline_trees) optimize_inline_calls (decl); + + /* Avoid RTL inlining from taking place. */ (*lang_hooks.callgraph.expand_function) (decl); if (DECL_UNINLINABLE (decl)) DECL_SAVED_TREE (decl) = NULL; @@ -325,6 +331,30 @@ cgraph_expand_functions () free (order); } +/* Mark all local functions. + We can not use node->needed directly as it is modified during + execution of cgraph_optimize. */ + +static void +cgraph_mark_local_functions () +{ + struct cgraph_node *node; + + if (!quiet_flag) + fprintf (stderr, "\n\nMarking local functions:"); + + /* Figure out functions we want to assemble. */ + for (node = cgraph_nodes; node; node = node->next) + { + node->local.local = (!node->needed + && DECL_SAVED_TREE (node->decl) + && !TREE_PUBLIC (node->decl)); + if (node->local.local) + announce_function (node->decl); + } +} + + /* Perform simple optimizations based on callgraph. */ void @@ -332,8 +362,10 @@ cgraph_optimize () { struct cgraph_node *node; bool changed = true; - struct cgraph_edge *edge; + cgraph_mark_local_functions (); + + cgraph_global_info_ready = true; if (!quiet_flag) fprintf (stderr, "\n\nAssembling functions:"); @@ -343,18 +375,29 @@ cgraph_optimize () Later we should move all inlining decisions to callgraph code to make this impossible. */ cgraph_expand_functions (); - while (changed) + if (!quiet_flag) + fprintf (stderr, "\n\nAssembling functions that failed to inline:"); + while (changed && !errorcount && !sorrycount) { changed = false; for (node = cgraph_nodes; node; node = node->next) { - if (!node->needed) - continue; - - for (edge = node->callees; edge; edge = edge->next_callee) - if (!edge->callee->needed) - changed = edge->callee->needed = true; + tree decl = node->decl; + if (!node->origin + && !TREE_ASM_WRITTEN (decl) + && DECL_SAVED_TREE (decl) + && !DECL_EXTERNAL (decl)) + { + struct cgraph_edge *edge; + + for (edge = node->callers; edge; edge = edge->next_caller) + if (TREE_ASM_WRITTEN (edge->caller->decl)) + { + changed = true; + cgraph_expand_function (node); + break; + } + } } } - cgraph_expand_functions (); } diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h index b83aae745c8..beafa792cc7 100644 --- a/gcc/config/i386/i386-protos.h +++ b/gcc/config/i386/i386-protos.h @@ -194,7 +194,7 @@ extern void x86_emit_floatuns PARAMS ((rtx [2])); #ifdef TREE_CODE -extern void init_cumulative_args PARAMS ((CUMULATIVE_ARGS *, tree, rtx)); +extern void init_cumulative_args PARAMS ((CUMULATIVE_ARGS *, tree, rtx, tree)); extern rtx function_arg PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, tree, int)); extern int function_arg_pass_by_reference PARAMS ((CUMULATIVE_ARGS *, enum machine_mode, @@ -226,6 +226,7 @@ extern int x86_field_alignment PARAMS ((tree, int)); extern rtx ix86_tls_get_addr PARAMS ((void)); extern void x86_machine_dependent_reorg PARAMS ((rtx)); +extern bool ix86_must_pass_in_stack PARAMS ((enum machine_mode mode, tree)); /* In winnt.c */ extern int i386_pe_dllexport_name_p PARAMS ((const char *)); diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 81d64375e91..639ea1b180b 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -45,6 +45,7 @@ Boston, MA 02111-1307, USA. */ #include "target.h" #include "target-def.h" #include "langhooks.h" +#include "cgraph.h" #ifndef CHECK_STACK_LIMIT #define CHECK_STACK_LIMIT (-1) @@ -1765,13 +1766,15 @@ ix86_function_arg_regno_p (regno) For a library call, FNTYPE is 0. */ void -init_cumulative_args (cum, fntype, libname) +init_cumulative_args (cum, fntype, libname, fndecl) CUMULATIVE_ARGS *cum; /* Argument info to initialize */ tree fntype; /* tree ptr for function decl */ rtx libname; /* SYMBOL_REF of library name or 0 */ + tree fndecl; { static CUMULATIVE_ARGS zero_cum; tree param, next_param; + bool user_convention = false; if (TARGET_DEBUG_ARG) { @@ -1797,7 +1800,10 @@ init_cumulative_args (cum, fntype, libname) tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype)); if (attr) - cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); + { + cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); + user_convention = true; + } } cum->maybe_vaarg = false; @@ -1808,6 +1814,23 @@ init_cumulative_args (cum, fntype, libname) { cum->nregs = 2; cum->fastcall = 1; + user_convention = true; + } + } + + /* Use register calling convention for local functions when possible. */ + if (!TARGET_64BIT && !user_convention && fndecl + && flag_unit_at_a_time) + { + struct cgraph_local_info *i = cgraph_local_info (fndecl); + if (i && i->local) + { + /* We can't use regparm(3) for nested functions as these use + static chain pointer in third argument. */ + if (DECL_CONTEXT (fndecl) && !DECL_NO_STATIC_CHAIN (fndecl)) + cum->nregs = 2; + else + cum->nregs = 3; } } @@ -1914,6 +1937,10 @@ classify_argument (mode, type, classes, bit_offset) if (bytes < 0) return 0; + if (mode != VOIDmode + && MUST_PASS_IN_STACK (mode, type)) + return 0; + if (type && AGGREGATE_TYPE_P (type)) { int i; @@ -15639,4 +15666,15 @@ x86_emit_floatuns (operands) emit_label (donelab); } +/* Return if we do not know how to pass TYPE solely in registers. */ +bool +ix86_must_pass_in_stack (mode, type) + enum machine_mode mode; + tree type; +{ + if (default_must_pass_in_stack (mode, type)) + return true; + return (!TARGET_64BIT && type && mode == TImode); +} + #include "gt-i386.h" diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h index e5daa5d5c93..4b21c869161 100644 --- a/gcc/config/i386/i386.h +++ b/gcc/config/i386/i386.h @@ -1664,18 +1664,7 @@ enum reg_class definition that is usually appropriate, refer to expr.h for additional documentation. If `REG_PARM_STACK_SPACE' is defined, the argument will be computed in the stack and then loaded into a register. */ -#define MUST_PASS_IN_STACK(MODE, TYPE) \ - ((TYPE) != 0 \ - && (TREE_CODE (TYPE_SIZE (TYPE)) != INTEGER_CST \ - || TREE_ADDRESSABLE (TYPE) \ - || ((MODE) == TImode) \ - || ((MODE) == BLKmode \ - && ! ((TYPE) != 0 \ - && TREE_CODE (TYPE_SIZE (TYPE)) == INTEGER_CST \ - && 0 == (int_size_in_bytes (TYPE) \ - % (PARM_BOUNDARY / BITS_PER_UNIT))) \ - && (FUNCTION_ARG_PADDING (MODE, TYPE) \ - == (BYTES_BIG_ENDIAN ? upward : downward))))) +#define MUST_PASS_IN_STACK(MODE, TYPE) ix86_must_pass_in_stack ((MODE), (TYPE)) /* Value is the number of bytes of arguments automatically popped when returning from a subroutine call. @@ -1743,8 +1732,8 @@ typedef struct ix86_args { for a call to a function whose data type is FNTYPE. For a library call, FNTYPE is 0. */ -#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT) \ - init_cumulative_args (&(CUM), (FNTYPE), (LIBNAME)) +#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL) \ + init_cumulative_args (&(CUM), (FNTYPE), (LIBNAME), (FNDECL)) /* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 54a283c287d..c779bfba838 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -3521,8 +3521,8 @@ invoking @option{-O2} on programs that use computed gotos. @item -O3 @opindex O3 Optimize yet more. @option{-O3} turns on all optimizations specified by -@option{-O2} and also turns on the @option{-finline-functions} and -@option{-frename-registers} options. +@option{-O2} and also turns on the @option{-finline-functions}, +@option{-funit-at-a-time} and @option{-frename-registers} options. @item -O0 @opindex O0 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 043908ae1c6..b67b566c858 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +Wed Mar 5 02:05:19 CET 2003 Jan Hubicka <jh@suse.cz> + + * gcc.dg/i386-local.c: New. + Tue Mar 4 19:39:18 2003 J"orn Rennecke <joern.rennecke@superh.com> * gcc.dg/sh-relax.c: Disable for sh64-*-*. diff --git a/gcc/testsuite/gcc.dg/i386-local.c b/gcc/testsuite/gcc.dg/i386-local.c new file mode 100644 index 00000000000..ed4cef3f337 --- /dev/null +++ b/gcc/testsuite/gcc.dg/i386-local.c @@ -0,0 +1,14 @@ +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */ +/* { dg-options "-O2 -funit-at-a-time" } */ +/* { dg-final { scan-assembler "magic.*eax" } } */ + +/* Verify that local calling convention is used. */ +static t(int) __attribute__ ((noinline)); +m() +{ + t(1); +} +static t(int a) +{ + asm("magic %1"::"g"(a)); +} diff --git a/gcc/toplev.c b/gcc/toplev.c index e6c67d81daf..2dbdf4f8c95 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -2518,6 +2518,7 @@ rest_of_compilation (decl) if (inlinable || (DECL_INLINE (decl) + && flag_inline_functions && ((! TREE_PUBLIC (decl) && ! TREE_ADDRESSABLE (decl) && ! TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) && ! flag_keep_inline_functions) |