+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.
/* 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 *));
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
#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. */
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
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 *));
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));
#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. */
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);
}
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))
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;
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
{
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:");
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 ();
}
#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,
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 *));
#include "target.h"
#include "target-def.h"
#include "langhooks.h"
+#include "cgraph.h"
#ifndef CHECK_STACK_LIMIT
#define CHECK_STACK_LIMIT (-1)
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)
{
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;
{
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;
}
}
if (bytes < 0)
return 0;
+ if (mode != VOIDmode
+ && MUST_PASS_IN_STACK (mode, type))
+ return 0;
+
if (type && AGGREGATE_TYPE_P (type))
{
int i;
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"
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.
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.
@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
+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-*-*.
--- /dev/null
+/* { 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));
+}
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)