diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9c99787c34cd5..e91015116a511 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2004-03-23 Zdenek Dvorak + + * 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 PR optimization/13985 diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 43a2e33b9d636..4b718d503d70d 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -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 \ diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index 81fdeb1850584..c6cf5d37e5539 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -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) diff --git a/gcc/builtins.c b/gcc/builtins.c index c7627c053dac0..7c6cae19f1008 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -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)) diff --git a/gcc/builtins.def b/gcc/builtins.def index 72f5f254cef76..72206254e97e3 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -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) diff --git a/gcc/c-common.c b/gcc/c-common.c index 9c868291e098b..c4f012920590e 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -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); diff --git a/gcc/calls.c b/gcc/calls.c index 44d6360d9bfbe..091ea4e026c96 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -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. */ diff --git a/gcc/gcov-io.h b/gcc/gcov-io.h index e83c5163c90c5..8e0da0e572a3b 100644 --- a/gcc/gcov-io.h +++ b/gcc/gcov-io.h @@ -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 diff --git a/gcc/libgcov.c b/gcc/libgcov.c index d3345024bcbe3..0731ed01e5fe1 100644 --- a/gcc/libgcov.c +++ b/gcc/libgcov.c @@ -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 */ diff --git a/gcc/tree.h b/gcc/tree.h index 52a17f0fc7068..085d5fec22706 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -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);