summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2003-03-05 01:33:27 +0000
committerhubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4>2003-03-05 01:33:27 +0000
commit80a85d8a0476d7921ab8a4f04c38a24c60ca159d (patch)
treec65a7c71518b86c824939e78d633204bce6006c7
parentf3672f9947359a3d452bed56c957e7ed418fabe5 (diff)
downloadgcc-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/ChangeLog23
-rw-r--r--gcc/cgraph.c30
-rw-r--r--gcc/cgraph.h26
-rw-r--r--gcc/cgraphunit.c67
-rw-r--r--gcc/config/i386/i386-protos.h3
-rw-r--r--gcc/config/i386/i386.c42
-rw-r--r--gcc/config/i386/i386.h17
-rw-r--r--gcc/doc/invoke.texi4
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/i386-local.c14
-rw-r--r--gcc/toplev.c1
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)