diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 50e69eb1621..aee5d83ac9d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2007-05-11 Paolo Carlini + + PR other/31852 + * builtin-types.def: Add BT_FN_PTR_CONST_PTR_INT_SIZE. + * builtins.def: Add BUILT_IN_MEMCHR, use the latter. + * builtins.c (fold_builtin_memchr): New. + (expand_builtin_memchr): Call the latter. + (expand_builtin, fold_builtin_3): Deal with BUILT_IN_MEMCHR. + * doc/extend.texi ([Other built-in functions provided by GCC]): + Document memchr. + 2007-05-11 Andreas Krebbel * config/s390/s390.md (GPR0_REGNUM, FPR0_REGNUM, FPR2_REGNUM, diff --git a/gcc/builtin-types.def b/gcc/builtin-types.def index e16fd7ab18c..bab6b9deaf5 100644 --- a/gcc/builtin-types.def +++ b/gcc/builtin-types.def @@ -1,4 +1,4 @@ -/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006 +/* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. This file is part of GCC. @@ -371,6 +371,8 @@ DEF_FUNCTION_TYPE_3 (BT_FN_I16_VPTR_I16_I16, BT_I16, BT_VOLATILE_PTR, BT_I16, BT_I16) DEF_FUNCTION_TYPE_3 (BT_FN_VOID_OMPFN_PTR_UINT, BT_VOID, BT_PTR_FN_VOID_PTR, BT_PTR, BT_UINT) +DEF_FUNCTION_TYPE_3 (BT_FN_PTR_CONST_PTR_INT_SIZE, BT_PTR, + BT_CONST_PTR, BT_INT, BT_SIZE) DEF_FUNCTION_TYPE_4 (BT_FN_SIZE_CONST_PTR_SIZE_SIZE_FILEPTR, BT_SIZE, BT_CONST_PTR, BT_SIZE, BT_SIZE, BT_FILEPTR) diff --git a/gcc/builtins.c b/gcc/builtins.c index 2cf15797d95..48c0cc0871f 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -105,6 +105,7 @@ static rtx expand_builtin_next_arg (void); static rtx expand_builtin_va_start (tree); static rtx expand_builtin_va_end (tree); static rtx expand_builtin_va_copy (tree); +static rtx expand_builtin_memchr (tree, rtx, enum machine_mode); static rtx expand_builtin_memcmp (tree, rtx, enum machine_mode); static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode); static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode); @@ -172,6 +173,7 @@ static tree fold_builtin_int_roundingfn (tree, tree); static tree fold_builtin_bitop (tree, tree); static tree fold_builtin_memory_op (tree, tree, tree, tree, bool, int); static tree fold_builtin_strchr (tree, tree, tree); +static tree fold_builtin_memchr (tree, tree, tree, tree); static tree fold_builtin_memcmp (tree, tree, tree); static tree fold_builtin_strcmp (tree, tree); static tree fold_builtin_strncmp (tree, tree, tree); @@ -3978,6 +3980,26 @@ expand_builtin_bzero (tree exp) const0_rtx, VOIDmode, exp); } +/* Expand a call to the memchr builtin. Return NULL_RTX if we failed the + caller should emit a normal call, otherwise try to get the result + in TARGET, if convenient (and in mode MODE if that's convenient). */ + +static rtx +expand_builtin_memchr (tree exp, rtx target, enum machine_mode mode) +{ + if (validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, + INTEGER_TYPE, VOID_TYPE)) + { + tree type = TREE_TYPE (exp); + tree result = fold_builtin_memchr (CALL_EXPR_ARG (exp, 0), + CALL_EXPR_ARG (exp, 1), + CALL_EXPR_ARG (exp, 2), type); + if (result) + return expand_expr (result, target, mode, EXPAND_NORMAL); + } + return NULL_RTX; +} + /* Expand expression EXP, which is a call to the memcmp built-in function. Return NULL_RTX if we failed and the caller should emit a normal call, otherwise try to get the result in @@ -6345,6 +6367,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, return target; break; + case BUILT_IN_MEMCHR: + target = expand_builtin_memchr (exp, target, mode); + if (target) + return target; + break; + case BUILT_IN_BCMP: case BUILT_IN_MEMCMP: target = expand_builtin_memcmp (exp, target, mode); @@ -8654,6 +8682,48 @@ fold_builtin_strncpy (tree fndecl, tree dest, tree src, tree len, tree slen) build_call_expr (fn, 3, dest, src, len)); } +/* Fold function call to builtin memchr. ARG1, ARG2 and LEN are the + arguments to the call, and TYPE is its return type. + Return NULL_TREE if no simplification can be made. */ + +static tree +fold_builtin_memchr (tree arg1, tree arg2, tree len, tree type) +{ + if (!validate_arg (arg1, POINTER_TYPE) + || !validate_arg (arg2, INTEGER_TYPE) + || !validate_arg (len, INTEGER_TYPE)) + return NULL_TREE; + else + { + const char *p1; + + if (TREE_CODE (arg2) != INTEGER_CST + || !host_integerp (len, 1)) + return NULL_TREE; + + p1 = c_getstr (arg1); + if (p1 && compare_tree_int (len, strlen (p1) + 1) <= 0) + { + char c; + const char *r; + tree tem; + + if (target_char_cast (arg2, &c)) + return NULL_TREE; + + r = memchr (p1, c, tree_low_cst (len, 1)); + + if (r == NULL) + return build_int_cst (TREE_TYPE (arg1), 0); + + tem = fold_build2 (PLUS_EXPR, TREE_TYPE (arg1), arg1, + build_int_cst (TREE_TYPE (arg1), r - p1)); + return fold_convert (type, tem); + } + return NULL_TREE; + } +} + /* Fold function call to builtin memcmp with arguments ARG1 and ARG2. Return NULL_TREE if no simplification can be made. */ @@ -9983,6 +10053,9 @@ fold_builtin_3 (tree fndecl, tree arg0, tree arg1, tree arg2, bool ignore) case BUILT_IN_STRNCMP: return fold_builtin_strncmp (arg0, arg1, arg2); + case BUILT_IN_MEMCHR: + return fold_builtin_memchr (arg0, arg1, arg2, type); + case BUILT_IN_BCMP: case BUILT_IN_MEMCMP: return fold_builtin_memcmp (arg0, arg1, arg2);; diff --git a/gcc/builtins.def b/gcc/builtins.def index e0652c85233..1c17edb2118 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -502,6 +502,7 @@ DEF_EXT_LIB_BUILTIN (BUILT_IN_BCMP, "bcmp", BT_FN_INT_CONST_PTR_CONST_PTR_SIZ DEF_EXT_LIB_BUILTIN (BUILT_IN_BCOPY, "bcopy", BT_FN_VOID_CONST_PTR_PTR_SIZE, ATTR_NOTHROW_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_BZERO, "bzero", BT_FN_VOID_PTR_SIZE, ATTR_NOTHROW_LIST) DEF_EXT_LIB_BUILTIN (BUILT_IN_INDEX, "index", BT_FN_STRING_CONST_STRING_INT, ATTR_PURE_NOTHROW_NONNULL) +DEF_LIB_BUILTIN (BUILT_IN_MEMCHR, "memchr", BT_FN_PTR_CONST_PTR_INT_SIZE, ATTR_PURE_NOTHROW_NONNULL) DEF_LIB_BUILTIN (BUILT_IN_MEMCMP, "memcmp", BT_FN_INT_CONST_PTR_CONST_PTR_SIZE, ATTR_PURE_NOTHROW_NONNULL) DEF_LIB_BUILTIN (BUILT_IN_MEMCPY, "memcpy", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL) DEF_LIB_BUILTIN (BUILT_IN_MEMMOVE, "memmove", BT_FN_PTR_PTR_CONST_PTR_SIZE, ATTR_NOTHROW_NONNULL) diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 1069892a50c..574bc127768 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -5592,6 +5592,7 @@ should be called and the @var{flag} argument passed to it. @findex lroundf @findex lroundl @findex malloc +@findex memchr @findex memcmp @findex memcpy @findex mempcpy @@ -5836,14 +5837,14 @@ The ISO C90 functions @code{isgraph}, @code{islower}, @code{isprint}, @code{ispunct}, @code{isspace}, @code{isupper}, @code{isxdigit}, @code{tolower}, @code{toupper}, @code{labs}, @code{ldexp}, @code{log10}, @code{log}, -@code{malloc}, @code{memcmp}, @code{memcpy}, @code{memset}, @code{modf}, -@code{pow}, @code{printf}, @code{putchar}, @code{puts}, @code{scanf}, -@code{sinh}, @code{sin}, @code{snprintf}, @code{sprintf}, @code{sqrt}, -@code{sscanf}, @code{strcat}, @code{strchr}, @code{strcmp}, -@code{strcpy}, @code{strcspn}, @code{strlen}, @code{strncat}, -@code{strncmp}, @code{strncpy}, @code{strpbrk}, @code{strrchr}, -@code{strspn}, @code{strstr}, @code{tanh}, @code{tan}, @code{vfprintf}, -@code{vprintf} and @code{vsprintf} +@code{malloc}, @code{memchr}, @code{memcmp}, @code{memcpy}, +@code{memset}, @code{modf}, @code{pow}, @code{printf}, @code{putchar}, +@code{puts}, @code{scanf}, @code{sinh}, @code{sin}, @code{snprintf}, +@code{sprintf}, @code{sqrt}, @code{sscanf}, @code{strcat}, +@code{strchr}, @code{strcmp}, @code{strcpy}, @code{strcspn}, +@code{strlen}, @code{strncat}, @code{strncmp}, @code{strncpy}, +@code{strpbrk}, @code{strrchr}, @code{strspn}, @code{strstr}, +@code{tanh}, @code{tan}, @code{vfprintf}, @code{vprintf} and @code{vsprintf} are all recognized as built-in functions unless @option{-fno-builtin} is specified (or @option{-fno-builtin-@var{function}} is specified for an individual function). All of these functions have diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 3f606756982..dc59bf04d8a 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2007-05-11 Paolo Carlini + + PR other/31852 + * gcc.c-torture/execute/builtins/memchr.c: New. + * gcc.c-torture/execute/builtins/memchr-lib.c: New. + * gcc.c-torture/execute/builtins/lib/memchr.c: New. + 2007-05-11 Paul Thomas PR fortran/30876 diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memchr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memchr.c new file mode 100644 index 00000000000..ddab08bcf8d --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/lib/memchr.c @@ -0,0 +1,21 @@ +extern void abort(void); +extern int inside_main; + +void * +memchr (const void *s, int c, __SIZE_TYPE__ n) +{ + const unsigned char uc = c; + const unsigned char *sp; + +#ifdef __OPTIMIZE__ + if (inside_main) + abort (); +#endif + + sp = s; + for (; n != 0; ++sp, --n) + if (*sp == uc) + return (void *) sp; + + return 0; +} diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memchr-lib.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memchr-lib.c new file mode 100644 index 00000000000..ccea6ba7d97 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memchr-lib.c @@ -0,0 +1 @@ +#include "lib/memchr.c" diff --git a/gcc/testsuite/gcc.c-torture/execute/builtins/memchr.c b/gcc/testsuite/gcc.c-torture/execute/builtins/memchr.c new file mode 100644 index 00000000000..88e731128f6 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/builtins/memchr.c @@ -0,0 +1,38 @@ +/* Copyright (C) 2007 Free Software Foundation. + + Ensure all expected transformations of builtin memchr occur + and perform correctly. + + Written by Paolo Carlini, 10/5/2007. */ + +extern void abort (void); +typedef __SIZE_TYPE__ size_t; +extern void *memchr (const void *, int, size_t); + +void +main_test (void) +{ + const char* const foo1 = "hello world"; + + if (memchr (foo1, 'x', 11)) + abort (); + if (memchr (foo1, 'o', 11) != foo1 + 4) + abort (); + if (memchr (foo1, 'w', 2)) + abort (); + if (memchr (foo1 + 5, 'o', 6) != foo1 + 7) + abort (); + if (memchr (foo1, 'd', 11) != foo1 + 10) + abort (); + if (memchr (foo1, 'd', 10)) + abort (); + if (memchr (foo1, '\0', 11)) + abort (); + if (memchr (foo1, '\0', 12) != foo1 + 11) + abort (); + + /* Test at least one instance of the __builtin_ style. We do this + to ensure that it works and that the prototype is correct. */ + if (__builtin_memchr (foo1, 'r', 11) != foo1 + 8) + abort (); +}