Makefile.in (LIBGCOV): Add _gcov_fork...

* Makefile.in (LIBGCOV): Add _gcov_fork, _gcov_execl, _gcov_execlp,
	_gcov_execle, _gcov_execv, _gcov_execvp, _gcov_execve.
	* builtin-types.def (BT_PID, BT_PTR_CONST_STRING, BT_FN_PID,
	BT_FN_INT_CONST_STRING_PTR_CONST_STRING,
	BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING): New.
	* builtins.c (expand_builtin_fork_or_exec): New.
	(expand_builtin): Call it.
	* builtins.def (BUILT_IN_EXECL, BUILT_IN_EXECLP,BUILT_IN_EXECLE,
	BUILT_IN_EXECV, BUILT_IN_EXECVP, BUILT_IN_EXECVE, BUILT_IN_FORK): New.
	* c-common.c (PID_TYPE): New macro.
	(c_common_nodes_and_builtins): Initialize pid_type_node.
	* calls.c (special_function_p): Do not handle fork and exec.
	(expand_call): Do not handle ECF_FORK_OR_EXEC.
	* gcov-io.h (__gcov_fork, __gcov_execl, __gcov_execlp, __gcov_execle,
	__gcov_execv, __gcov_execvp, __gcov_execve): Declare.
	* libgcov.c (__gcov_fork, __gcov_execl, __gcov_execlp, __gcov_execle,
	__gcov_execv, __gcov_execvp, __gcov_execve): New.
	* tree.h (enum tree_index): Add TI_PID_TYPE.
	(pid_type_node): New macro.
	(ECF_FORK_OR_EXEC): Removed.

From-SVN: r81118
This commit is contained in:
Zdenek Dvorak 2004-04-24 00:50:16 +02:00 committed by Zdenek Dvorak
parent adabbcf475
commit d1c3882392
10 changed files with 282 additions and 33 deletions

View File

@ -1,3 +1,26 @@
2004-03-23 Zdenek Dvorak <rakdver@atrey.karlin.mff.cuni.cz>
* Makefile.in (LIBGCOV): Add _gcov_fork, _gcov_execl, _gcov_execlp,
_gcov_execle, _gcov_execv, _gcov_execvp, _gcov_execve.
* builtin-types.def (BT_PID, BT_PTR_CONST_STRING, BT_FN_PID,
BT_FN_INT_CONST_STRING_PTR_CONST_STRING,
BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING): New.
* builtins.c (expand_builtin_fork_or_exec): New.
(expand_builtin): Call it.
* builtins.def (BUILT_IN_EXECL, BUILT_IN_EXECLP,BUILT_IN_EXECLE,
BUILT_IN_EXECV, BUILT_IN_EXECVP, BUILT_IN_EXECVE, BUILT_IN_FORK): New.
* c-common.c (PID_TYPE): New macro.
(c_common_nodes_and_builtins): Initialize pid_type_node.
* calls.c (special_function_p): Do not handle fork and exec.
(expand_call): Do not handle ECF_FORK_OR_EXEC.
* gcov-io.h (__gcov_fork, __gcov_execl, __gcov_execlp, __gcov_execle,
__gcov_execv, __gcov_execvp, __gcov_execve): Declare.
* libgcov.c (__gcov_fork, __gcov_execl, __gcov_execlp, __gcov_execle,
__gcov_execv, __gcov_execvp, __gcov_execve): New.
* tree.h (enum tree_index): Add TI_PID_TYPE.
(pid_type_node): New macro.
(ECF_FORK_OR_EXEC): Removed.
2004-04-23 Eric Botcazou <ebotcazou@libertysurf.fr>
PR optimization/13985

View File

@ -905,7 +905,9 @@ STAGESTUFF = *$(objext) insn-flags.h insn-config.h insn-codes.h \
LIB2FUNCS_ST = _eprintf __gcc_bcmp
# Defined in libgcov.c, included only in gcov library
LIBGCOV = _gcov _gcov_merge_add _gcov_merge_single _gcov_merge_delta
LIBGCOV = _gcov _gcov_merge_add _gcov_merge_single _gcov_merge_delta \
_gcov_fork _gcov_execl _gcov_execlp _gcov_execle \
_gcov_execv _gcov_execvp _gcov_execve
FPBIT_FUNCS = _pack_sf _unpack_sf _addsub_sf _mul_sf _div_sf \
_fpcmp_parts_sf _compare_sf _eq_sf _ne_sf _gt_sf _ge_sf \

View File

@ -80,6 +80,7 @@ DEF_PRIMITIVE_TYPE (BT_INT_PTR, integer_ptr_type_node)
DEF_PRIMITIVE_TYPE (BT_FLOAT_PTR, float_ptr_type_node)
DEF_PRIMITIVE_TYPE (BT_DOUBLE_PTR, double_ptr_type_node)
DEF_PRIMITIVE_TYPE (BT_LONGDOUBLE_PTR, long_double_ptr_type_node)
DEF_PRIMITIVE_TYPE (BT_PID, pid_type_node)
DEF_PRIMITIVE_TYPE (BT_SIZE, size_type_node)
DEF_PRIMITIVE_TYPE (BT_SSIZE, signed_size_type_node)
DEF_PRIMITIVE_TYPE (BT_WINT, wint_type_node)
@ -89,8 +90,11 @@ DEF_PRIMITIVE_TYPE (BT_CONST_STRING, const_string_type_node)
DEF_PRIMITIVE_TYPE (BT_VALIST_REF, va_list_ref_type_node)
DEF_PRIMITIVE_TYPE (BT_VALIST_ARG, va_list_arg_type_node)
DEF_POINTER_TYPE (BT_PTR_CONST_STRING, BT_CONST_STRING)
DEF_FUNCTION_TYPE_0 (BT_FN_VOID, BT_VOID)
DEF_FUNCTION_TYPE_0 (BT_FN_PTR, BT_PTR)
DEF_FUNCTION_TYPE_0 (BT_FN_PID, BT_PID)
DEF_FUNCTION_TYPE_0 (BT_FN_UNSIGNED, BT_UNSIGNED)
DEF_FUNCTION_TYPE_0 (BT_FN_FLOAT, BT_FLOAT)
DEF_FUNCTION_TYPE_0 (BT_FN_DOUBLE, BT_DOUBLE)
@ -223,6 +227,8 @@ DEF_FUNCTION_TYPE_2 (BT_FN_COMPLEX_DOUBLE_COMPLEX_DOUBLE_COMPLEX_DOUBLE,
BT_COMPLEX_DOUBLE, BT_COMPLEX_DOUBLE, BT_COMPLEX_DOUBLE)
DEF_FUNCTION_TYPE_2 (BT_FN_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE_COMPLEX_LONGDOUBLE,
BT_COMPLEX_LONGDOUBLE, BT_COMPLEX_LONGDOUBLE, BT_COMPLEX_LONGDOUBLE)
DEF_FUNCTION_TYPE_2 (BT_FN_INT_CONST_STRING_PTR_CONST_STRING,
BT_INT, BT_CONST_STRING, BT_PTR_CONST_STRING)
DEF_FUNCTION_TYPE_3 (BT_FN_STRING_STRING_CONST_STRING_SIZE,
BT_STRING, BT_STRING, BT_CONST_STRING, BT_SIZE)
@ -264,6 +270,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_VOID_DOUBLE_DOUBLEPTR_DOUBLEPTR,
BT_VOID, BT_DOUBLE, BT_DOUBLE_PTR, BT_DOUBLE_PTR)
DEF_FUNCTION_TYPE_3 (BT_FN_VOID_LONGDOUBLE_LONGDOUBLEPTR_LONGDOUBLEPTR,
BT_VOID, BT_LONGDOUBLE, BT_LONGDOUBLE_PTR, BT_LONGDOUBLE_PTR)
DEF_FUNCTION_TYPE_3 (BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING,
BT_INT, BT_CONST_STRING, BT_PTR_CONST_STRING, BT_PTR_CONST_STRING)
DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_PTR,
BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_PTR)

View File

@ -5081,6 +5081,69 @@ expand_builtin_signbit (tree exp, rtx target)
}
return temp;
}
/* Expand fork or exec calls. TARGET is the desired target of the
call. ARGLIST is the list of arguments of the call. FN is the
identificator of the actual function. IGNORE is nonzero if the
value is to be ignored. */
static rtx
expand_builtin_fork_or_exec (tree fn, tree arglist, rtx target, int ignore)
{
tree id, decl;
tree call;
/* If we are not profiling, just call the function. */
if (!profile_arc_flag)
return NULL_RTX;
/* Otherwise call the wrapper. This should be equivalent for the rest of
compiler, so the code does not diverge, and the wrapper may run the
code neccesary for keeping the profiling sane. */
switch (DECL_FUNCTION_CODE (fn))
{
case BUILT_IN_FORK:
id = get_identifier ("__gcov_fork");
break;
case BUILT_IN_EXECL:
id = get_identifier ("__gcov_execl");
break;
case BUILT_IN_EXECV:
id = get_identifier ("__gcov_execv");
break;
case BUILT_IN_EXECLP:
id = get_identifier ("__gcov_execlp");
break;
case BUILT_IN_EXECLE:
id = get_identifier ("__gcov_execle");
break;
case BUILT_IN_EXECVP:
id = get_identifier ("__gcov_execvp");
break;
case BUILT_IN_EXECVE:
id = get_identifier ("__gcov_execve");
break;
default:
abort ();
}
decl = build_decl (FUNCTION_DECL, id, TREE_TYPE (fn));
DECL_EXTERNAL (decl) = 1;
TREE_PUBLIC (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
TREE_NOTHROW (decl) = 1;
call = build_function_call_expr (decl, arglist);
return expand_call (call, target, ignore);
}
/* Expand an expression EXP that calls a built-in function,
with result going to TARGET if that's convenient
@ -5653,6 +5716,17 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
expand_builtin_prefetch (arglist);
return const0_rtx;
case BUILT_IN_FORK:
case BUILT_IN_EXECL:
case BUILT_IN_EXECV:
case BUILT_IN_EXECLP:
case BUILT_IN_EXECLE:
case BUILT_IN_EXECVP:
case BUILT_IN_EXECVE:
target = expand_builtin_fork_or_exec (fndecl, arglist, target, ignore);
if (target)
return target;
break;
default: /* just do library call, if unknown builtin */
if (!DECL_ASSEMBLER_NAME_SET_P (fndecl))

View File

@ -555,10 +555,17 @@ DEF_GCC_BUILTIN (BUILT_IN_DWARF_CFA, "dwarf_cfa", BT_FN_PTR, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_DWARF_SP_COLUMN, "dwarf_sp_column", BT_FN_UNSIGNED, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_EH_RETURN, "eh_return", BT_FN_VOID_PTRMODE_PTR, ATTR_NORETURN_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_EH_RETURN_DATA_REGNO, "eh_return_data_regno", BT_FN_INT_INT, ATTR_NULL)
DEF_LIB_BUILTIN (BUILT_IN_EXECL, "execl", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_EXECLP, "execlp", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_EXECLE, "execle", BT_FN_INT_CONST_STRING_CONST_STRING_VAR, ATTR_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_EXECV, "execv", BT_FN_INT_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_EXECVP, "execvp", BT_FN_INT_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_EXECVE, "execve", BT_FN_INT_CONST_STRING_PTR_CONST_STRING_PTR_CONST_STRING, ATTR_NOTHROW_LIST)
DEF_LIB_BUILTIN (BUILT_IN_EXIT, "exit", BT_FN_VOID_INT, ATTR_NORETURN_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_EXPECT, "expect", BT_FN_LONG_LONG_LONG, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_EXTEND_POINTER, "extend_pointer", BT_FN_WORD_PTR, ATTR_CONST_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_EXTRACT_RETURN_ADDR, "extract_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
DEF_LIB_BUILTIN (BUILT_IN_FORK, "fork", BT_FN_PID, ATTR_NOTHROW_LIST)
DEF_GCC_BUILTIN (BUILT_IN_FRAME_ADDRESS, "frame_address", BT_FN_PTR_UNSIGNED, ATTR_NULL)
DEF_GCC_BUILTIN (BUILT_IN_FROB_RETURN_ADDR, "frob_return_addr", BT_FN_PTR_PTR, ATTR_NULL)
DEF_EXT_LIB_BUILTIN (BUILT_IN_GETTEXT, "gettext", BT_FN_STRING_CONST_STRING, ATTR_FORMAT_ARG_1)

View File

@ -55,6 +55,10 @@ cpp_reader *parse_in; /* Declared in c-pragma.h. */
#define SIZE_TYPE "long unsigned int"
#endif
#ifndef PID_TYPE
#define PID_TYPE "int"
#endif
#ifndef WCHAR_TYPE
#define WCHAR_TYPE "int"
#endif
@ -3113,6 +3117,9 @@ c_common_nodes_and_builtins (void)
signed_size_type_node = c_common_signed_type (size_type_node);
set_sizetype (size_type_node);
pid_type_node =
TREE_TYPE (identifier_global_value (get_identifier (PID_TYPE)));
build_common_tree_nodes_2 (flag_short_double);
record_builtin_type (RID_FLOAT, NULL, float_type_node);

View File

@ -653,21 +653,8 @@ special_function_p (tree fndecl, int flags)
else if (tname[0] == 'l' && tname[1] == 'o'
&& ! strcmp (tname, "longjmp"))
flags |= ECF_LONGJMP;
else if ((tname[0] == 'f' && tname[1] == 'o'
&& ! strcmp (tname, "fork"))
/* Linux specific: __clone. check NAME to insist on the
leading underscores, to avoid polluting the ISO / POSIX
namespace. */
|| (name[0] == '_' && name[1] == '_'
&& ! strcmp (tname, "clone"))
|| (tname[0] == 'e' && tname[1] == 'x' && tname[2] == 'e'
&& tname[3] == 'c' && (tname[4] == 'l' || tname[4] == 'v')
&& (tname[5] == '\0'
|| ((tname[5] == 'p' || tname[5] == 'e')
&& tname[6] == '\0'))))
flags |= ECF_FORK_OR_EXEC;
}
return flags;
}
@ -2626,18 +2613,6 @@ expand_call (tree exp, rtx target, int ignore)
stack_pointer_delta = save_stack_pointer_delta;
}
if (profile_arc_flag && (flags & ECF_FORK_OR_EXEC))
{
/* A fork duplicates the profile information, and an exec discards
it. We can't rely on fork/exec to be paired. So write out the
profile information we have gathered so far, and clear it. */
/* ??? When Linux's __clone is called with CLONE_VM set, profiling
is subject to race conditions, just as with multithreaded
programs. */
emit_library_call (gcov_flush_libfunc, LCT_ALWAYS_RETURN, VOIDmode, 0);
}
/* Ensure current function's preferred stack boundary is at least
what we need. We don't have to increase alignment for recursive
functions. */

View File

@ -447,6 +447,16 @@ extern void __gcov_merge_single (gcov_type *, unsigned);
/* The merge function to choose the most common difference between
consecutive values. */
extern void __gcov_merge_delta (gcov_type *, unsigned);
/* The wrappers around some library functions.. */
extern pid_t __gcov_fork (void);
extern int __gcov_execl (const char *, const char *, ...);
extern int __gcov_execlp (const char *, const char *, ...);
extern int __gcov_execle (const char *, const char *, ...);
extern int __gcov_execv (const char *, char *const []);
extern int __gcov_execvp (const char *, char *const []);
extern int __gcov_execve (const char *, char *const [], char *const []);
#endif /* IN_LIBGCOV */
#if IN_LIBGCOV >= 0

View File

@ -580,4 +580,146 @@ __gcov_merge_delta (gcov_type *counters, unsigned n_counters)
}
#endif /* L_gcov_merge_delta */
#ifdef L_gcov_fork
/* A wrapper for the fork function. Flushes the accumulated profiling data, so
that they are not counted twice. */
pid_t
__gcov_fork (void)
{
__gcov_flush ();
return fork ();
}
#endif
#ifdef L_gcov_execl
/* A wrapper for the execl function. Flushes the accumulated profiling data, so
that they are not lost. */
int
__gcov_execl (const char *path, const char *arg, ...)
{
va_list ap, aq;
unsigned i, length;
char **args;
__gcov_flush ();
va_start (ap, arg);
va_copy (aq, ap);
length = 2;
while (va_arg (ap, char *))
length++;
va_end (ap);
args = alloca (length * sizeof (void *));
args[0] = (char *) arg;
for (i = 1; i < length; i++)
args[i] = va_arg (aq, char *);
va_end (aq);
return execv (path, args);
}
#endif
#ifdef L_gcov_execlp
/* A wrapper for the execlp function. Flushes the accumulated profiling data, so
that they are not lost. */
int
__gcov_execlp (const char *path, const char *arg, ...)
{
va_list ap, aq;
unsigned i, length;
char **args;
__gcov_flush ();
va_start (ap, arg);
va_copy (aq, ap);
length = 2;
while (va_arg (ap, char *))
length++;
va_end (ap);
args = alloca (length * sizeof (void *));
args[0] = (char *) arg;
for (i = 1; i < length; i++)
args[i] = va_arg (aq, char *);
va_end (aq);
return execvp (path, args);
}
#endif
#ifdef L_gcov_execle
/* A wrapper for the execle function. Flushes the accumulated profiling data, so
that they are not lost. */
int
__gcov_execle (const char *path, const char *arg, ...)
{
va_list ap, aq;
unsigned i, length;
char **args;
char **envp;
__gcov_flush ();
va_start (ap, arg);
va_copy (aq, ap);
length = 2;
while (va_arg (ap, char *))
length++;
va_end (ap);
args = alloca (length * sizeof (void *));
args[0] = (char *) arg;
for (i = 1; i < length; i++)
args[i] = va_arg (aq, char *);
envp = va_arg (aq, char **);
va_end (aq);
return execve (path, args, envp);
}
#endif
#ifdef L_gcov_execv
/* A wrapper for the execv function. Flushes the accumulated profiling data, so
that they are not lost. */
int
__gcov_execv (const char *path, char *const argv[])
{
__gcov_flush ();
return execv (path, argv);
}
#endif
#ifdef L_gcov_execvp
/* A wrapper for the execvp function. Flushes the accumulated profiling data, so
that they are not lost. */
int
__gcov_execvp (const char *path, char *const argv[])
{
__gcov_flush ();
return execvp (path, argv);
}
#endif
#ifdef L_gcov_execve
/* A wrapper for the execve function. Flushes the accumulated profiling data, so
that they are not lost. */
int
__gcov_execve (const char *path, char *const argv[], char *const envp[])
{
__gcov_flush ();
return execve (path, argv, envp);
}
#endif
#endif /* inhibit_libc */

View File

@ -1992,6 +1992,7 @@ enum tree_index
TI_PTR_TYPE,
TI_CONST_PTR_TYPE,
TI_SIZE_TYPE,
TI_PID_TYPE,
TI_PTRDIFF_TYPE,
TI_VA_LIST_TYPE,
TI_BOOLEAN_TYPE,
@ -2056,6 +2057,7 @@ extern GTY(()) tree global_trees[TI_MAX];
#define const_ptr_type_node global_trees[TI_CONST_PTR_TYPE]
/* The C type `size_t'. */
#define size_type_node global_trees[TI_SIZE_TYPE]
#define pid_type_node global_trees[TI_PID_TYPE]
#define ptrdiff_type_node global_trees[TI_PTRDIFF_TYPE]
#define va_list_type_node global_trees[TI_VA_LIST_TYPE]
@ -3090,18 +3092,17 @@ extern rtx emit_line_note (location_t);
#define ECF_LONGJMP 64
/* Nonzero if this is a syscall that makes a new process in the image of
the current one. */
#define ECF_FORK_OR_EXEC 128
#define ECF_SIBCALL 256
#define ECF_SIBCALL 128
/* Nonzero if this is a call to "pure" function (like const function,
but may read memory. */
#define ECF_PURE 512
#define ECF_PURE 256
/* Nonzero if this is a call to a function that returns with the stack
pointer depressed. */
#define ECF_SP_DEPRESSED 1024
#define ECF_SP_DEPRESSED 512
/* Nonzero if this call is known to always return. */
#define ECF_ALWAYS_RETURN 2048
#define ECF_ALWAYS_RETURN 1024
/* Create libcall block around the call. */
#define ECF_LIBCALL_BLOCK 4096
#define ECF_LIBCALL_BLOCK 2048
extern int flags_from_decl_or_type (tree);
extern int call_expr_flags (tree);