builtins.c (expand_builtin_strncmp, [...]): New functions.

* builtins.c (expand_builtin_strncmp, expand_builtin_strncpy): New
	functions.
	(expand_builtin): Handle BUILT_IN_STRNCPY and BUILT_IN_STRNCMP.

	* builtins.def (BUILT_IN_STRNCPY, BUILT_IN_STRNCMP): New entries.

	* c-common.c (c_common_nodes_and_builtins): Declare builtin
	strncpy and strncmp.

	* extend.texi (strncmp, strncpy): Document new builtins.

testsuite:
	* gcc.c-torture/execute/string-opt-7.c: New test.
	* gcc.c-torture/execute/string-opt-8.c: Likewise.

From-SVN: r37777
This commit is contained in:
Kaveh R. Ghazi 2000-11-27 05:00:06 +00:00 committed by Kaveh Ghazi
parent 231db5f4ec
commit da9e9f0862
7 changed files with 332 additions and 6 deletions

View File

@ -1,3 +1,16 @@
2000-11-26 Kaveh R. Ghazi <ghazi@caip.rutgers.edu>
* builtins.c (expand_builtin_strncmp, expand_builtin_strncpy): New
functions.
(expand_builtin): Handle BUILT_IN_STRNCPY and BUILT_IN_STRNCMP.
* builtins.def (BUILT_IN_STRNCPY, BUILT_IN_STRNCMP): New entries.
* c-common.c (c_common_nodes_and_builtins): Declare builtin
strncpy and strncmp.
* extend.texi (strncmp, strncpy): Document new builtins.
2000-11-26 Mark Mitchell <mark@codesourcery.com>
* config/elfos.h (ASM_OUTPUT_SECTION_NAME): Use a hash table, not

View File

@ -104,8 +104,12 @@ static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx));
#endif
static rtx expand_builtin_strcmp PARAMS ((tree, rtx,
enum machine_mode));
static rtx expand_builtin_strncmp PARAMS ((tree, rtx,
enum machine_mode));
static rtx expand_builtin_memcpy PARAMS ((tree));
static rtx expand_builtin_strcpy PARAMS ((tree));
static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
enum machine_mode));
static rtx expand_builtin_memset PARAMS ((tree));
static rtx expand_builtin_bzero PARAMS ((tree));
static rtx expand_builtin_strlen PARAMS ((tree, rtx));
@ -1770,6 +1774,63 @@ expand_builtin_strcpy (exp)
return result;
}
/* Expand expression EXP, which is a call to the strncpy builtin. Return 0
if we failed the caller should emit a normal call. */
static rtx
expand_builtin_strncpy (arglist, target, mode)
tree arglist;
rtx target;
enum machine_mode mode;
{
if (arglist == 0
/* Arg could be non-pointer if user redeclared this fcn wrong. */
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
!= POINTER_TYPE)
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
|| (TREE_CODE (TREE_TYPE (TREE_VALUE
(TREE_CHAIN (TREE_CHAIN (arglist)))))
!= INTEGER_TYPE))
return 0;
else
{
tree slen = c_strlen (TREE_VALUE (TREE_CHAIN (arglist)));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
/* We must be passed a constant len parameter. */
if (TREE_CODE (len) != INTEGER_CST)
return 0;
/* If the len parameter is zero, return the dst parameter. */
if (compare_tree_int (len, 0) == 0)
{
/* Evaluate and ignore the src argument in case it has
side-effects. */
expand_expr (TREE_VALUE (TREE_CHAIN (arglist)), const0_rtx,
VOIDmode, EXPAND_NORMAL);
/* Return the dst parameter. */
return expand_expr (TREE_VALUE (arglist), target, mode,
EXPAND_NORMAL);
}
/* Now, we must be passed a constant src ptr parameter. */
if (slen == 0)
return 0;
slen = size_binop (PLUS_EXPR, slen, ssize_int (1));
/* We're required to pad with trailing zeros if the requested
len is greater than strlen(s2)+1, so in that case punt. */
if (tree_int_cst_lt (slen, len))
return 0;
/* OK transform into builtin memcpy. */
return expand_builtin_memcpy (arglist);
}
}
/* Expand expression EXP, which is a call to the memset builtin. Return 0
if we failed the caller should emit a normal call. */
@ -2051,6 +2112,83 @@ expand_builtin_strcmp (exp, target, mode)
#endif
}
/* Expand expression EXP, which is a call to the strncmp builtin. Return 0
if we failed the caller should emit a normal call, otherwise try to get
the result in TARGET, if convenient. */
static rtx
expand_builtin_strncmp (exp, target, mode)
tree exp;
rtx target;
enum machine_mode mode;
{
tree arglist = TREE_OPERAND (exp, 1);
tree arg1, arg2, arg3;
const char *p1, *p2;
/* If we need to check memory accesses, call the library function. */
if (current_function_check_memory_usage)
return 0;
if (arglist == 0
/* Arg could be non-pointer if user redeclared this fcn wrong. */
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
|| TREE_CHAIN (TREE_CHAIN (arglist)) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))))) != INTEGER_TYPE)
return 0;
arg1 = TREE_VALUE (arglist);
arg2 = TREE_VALUE (TREE_CHAIN (arglist));
arg3 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
/* We must be passed a constant len parameter. */
if (TREE_CODE (arg3) != INTEGER_CST)
return 0;
/* If the len parameter is zero, return zero. */
if (compare_tree_int (arg3, 0) == 0)
{
/* Evaluate and ignore arg1 and arg2 in case they have
side-effects. */
expand_expr (arg1, const0_rtx, VOIDmode, EXPAND_NORMAL);
expand_expr (arg2, const0_rtx, VOIDmode, EXPAND_NORMAL);
return const0_rtx;
}
p1 = c_getstr (arg1);
p2 = c_getstr (arg2);
/* If all arguments are constant, evaluate at compile-time. */
if (p1 && p2)
{
const int r = strncmp (p1, p2, TREE_INT_CST_LOW (arg3));
return (r < 0 ? constm1_rtx : (r > 0 ? const1_rtx : const0_rtx));
}
/* If either string parameter is constant and its strlen is strictly
less than the length parameter, call expand_builtin_strcmp(). */
if ((p1 && compare_tree_int (arg3, strlen (p1)) > 0)
|| (p2 && compare_tree_int (arg3, strlen (p2)) > 0))
{
tree newarglist =
tree_cons (NULL_TREE, arg1, build_tree_list (NULL_TREE, arg2));
rtx result;
/* Call expand_builtin_strcmp with the modified newarglist. If
the expansion does not occur, do not allow strncmp to expand to
strcmp since strcmp requires that both strings be NULL
terminated whereas strncmp does not. */
TREE_OPERAND (exp, 1) = newarglist;
result = expand_builtin_strcmp (exp, target, mode);
/* Always restore the original arguments. */
TREE_OPERAND (exp, 1) = arglist;
return result;
}
return 0;
}
/* Expand a call to __builtin_saveregs, generating the result in TARGET,
if that's convenient. */
@ -2752,6 +2890,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
|| fcode == BUILT_IN_INDEX || fcode == BUILT_IN_RINDEX
|| fcode == BUILT_IN_STRCHR || fcode == BUILT_IN_STRRCHR
|| fcode == BUILT_IN_STRLEN || fcode == BUILT_IN_STRCPY
|| fcode == BUILT_IN_STRNCPY || fcode == BUILT_IN_STRNCMP
|| fcode == BUILT_IN_STRSTR || fcode == BUILT_IN_STRPBRK
|| fcode == BUILT_IN_STRCMP || fcode == BUILT_IN_FFS
|| fcode == BUILT_IN_PUTCHAR || fcode == BUILT_IN_PUTS
@ -2881,6 +3020,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
return target;
break;
case BUILT_IN_STRNCPY:
target = expand_builtin_strncpy (arglist, target, mode);
if (target)
return target;
break;
case BUILT_IN_STRSTR:
target = expand_builtin_strstr (arglist, target, mode);
if (target)
@ -2931,6 +3076,12 @@ expand_builtin (exp, target, subtarget, mode, ignore)
return target;
break;
case BUILT_IN_STRNCMP:
target = expand_builtin_strncmp (exp, target, mode);
if (target)
return target;
break;
/* These comparison functions need an instruction that returns an actual
index. An ordinary compare that just sets the condition codes
is not enough. */

View File

@ -39,7 +39,9 @@ DEF_BUILTIN(BUILT_IN_BCMP)
DEF_BUILTIN(BUILT_IN_INDEX)
DEF_BUILTIN(BUILT_IN_RINDEX)
DEF_BUILTIN(BUILT_IN_STRCPY)
DEF_BUILTIN(BUILT_IN_STRNCPY)
DEF_BUILTIN(BUILT_IN_STRCMP)
DEF_BUILTIN(BUILT_IN_STRNCMP)
DEF_BUILTIN(BUILT_IN_STRLEN)
DEF_BUILTIN(BUILT_IN_STRSTR)
DEF_BUILTIN(BUILT_IN_STRPBRK)

View File

@ -4887,6 +4887,7 @@ c_common_nodes_and_builtins ()
tree int_ftype_cptr_cptr_sizet;
tree int_ftype_string_string, string_ftype_ptr_ptr;
tree string_ftype_string_int, string_ftype_string_string;
tree string_ftype_string_cstring_sizet, int_ftype_cstring_cstring_sizet;
tree long_ftype_long;
tree longlong_ftype_longlong;
/* Either char* or void*. */
@ -4987,6 +4988,14 @@ c_common_nodes_and_builtins ()
const_string_type_node,
endlink)));
/* Prototype for strncpy. */
string_ftype_string_cstring_sizet
= build_function_type (string_type_node,
tree_cons (NULL_TREE, string_type_node,
tree_cons (NULL_TREE,
const_string_type_node,
sizetype_endlink)));
traditional_len_type_node = ((flag_traditional &&
c_language != clk_cplusplus)
? integer_type_node : sizetype);
@ -5001,6 +5010,14 @@ c_common_nodes_and_builtins ()
const_string_type_node,
endlink)));
/* Prototype for strncmp. */
int_ftype_cstring_cstring_sizet
= build_function_type (integer_type_node,
tree_cons (NULL_TREE, const_string_type_node,
tree_cons (NULL_TREE,
const_string_type_node,
sizetype_endlink)));
/* Prototype for strstr, strpbrk, etc. */
string_ftype_string_string
= build_function_type (string_type_node,
@ -5246,8 +5263,11 @@ c_common_nodes_and_builtins ()
BUILT_IN_INDEX, BUILT_IN_NORMAL, "index");
builtin_function ("__builtin_rindex", string_ftype_string_int,
BUILT_IN_RINDEX, BUILT_IN_NORMAL, "rindex");
builtin_function ("__builtin_strcmp", int_ftype_string_string,
BUILT_IN_STRCMP, BUILT_IN_NORMAL, "strcmp");
built_in_decls[BUILT_IN_STRCMP] =
builtin_function ("__builtin_strcmp", int_ftype_string_string,
BUILT_IN_STRCMP, BUILT_IN_NORMAL, "strcmp");
builtin_function ("__builtin_strncmp", int_ftype_cstring_cstring_sizet,
BUILT_IN_STRNCMP, BUILT_IN_NORMAL, "strncmp");
builtin_function ("__builtin_strstr", string_ftype_string_string,
BUILT_IN_STRSTR, BUILT_IN_NORMAL, "strstr");
builtin_function ("__builtin_strpbrk", string_ftype_string_string,
@ -5259,6 +5279,8 @@ c_common_nodes_and_builtins ()
BUILT_IN_STRRCHR, BUILT_IN_NORMAL, "strrchr");
builtin_function ("__builtin_strcpy", string_ftype_ptr_ptr,
BUILT_IN_STRCPY, BUILT_IN_NORMAL, "strcpy");
builtin_function ("__builtin_strncpy", string_ftype_string_cstring_sizet,
BUILT_IN_STRNCPY, BUILT_IN_NORMAL, "strncpy");
builtin_function ("__builtin_strlen", strlen_ftype,
BUILT_IN_STRLEN, BUILT_IN_NORMAL, "strlen");
builtin_function ("__builtin_sqrtf", float_ftype_float,
@ -5325,6 +5347,8 @@ c_common_nodes_and_builtins ()
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strcmp", int_ftype_string_string, BUILT_IN_STRCMP,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strncmp", int_ftype_cstring_cstring_sizet,
BUILT_IN_STRNCMP, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strstr", string_ftype_string_string, BUILT_IN_STRSTR,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strchr", string_ftype_string_int, BUILT_IN_STRCHR,
@ -5335,6 +5359,8 @@ c_common_nodes_and_builtins ()
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strncpy", string_ftype_string_cstring_sizet,
BUILT_IN_STRNCPY, BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strlen", strlen_ftype, BUILT_IN_STRLEN,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("sqrtf", float_ftype_float, BUILT_IN_FSQRT,

View File

@ -3294,6 +3294,8 @@ function as well.
@findex strcmp
@findex strcpy
@findex strlen
@findex strncmp
@findex strncpy
@findex strpbrk
@findex strrchr
@findex strstr
@ -3338,10 +3340,11 @@ The following ISO C89 functions are recognized as builtins unless
@samp{-fno-builtin} is specified: @code{abs}, @code{cos}, @code{fabs},
@code{fputs}, @code{labs}, @code{memcmp}, @code{memcpy}, @code{memset},
@code{printf}, @code{sin}, @code{sqrt}, @code{strchr}, @code{strcmp},
@code{strcpy}, @code{strlen}, @code{strpbrk}, @code{strrchr}, and
@code{strstr}. All of these functions have corresponding versions
prefixed with @code{__builtin_}, except that the version for @code{sqrt}
is called @code{__builtin_fsqrt}.
@code{strcpy}, @code{strlen}, @code{strncmp}, @code{strncpy},
@code{strpbrk}, @code{strrchr}, and @code{strstr}. All of these
functions have corresponding versions prefixed with @code{__builtin_},
except that the version for @code{sqrt} is called
@code{__builtin_fsqrt}.
GNU CC provides builtin versions of the ISO C99 floating point
comparison macros (that avoid raising exceptions for unordered

View File

@ -0,0 +1,71 @@
/* Copyright (C) 2000 Free Software Foundation.
Ensure all expected transformations of builtin strncpy occur and
perform correctly.
Written by Kaveh R. Ghazi, 11/25/2000. */
extern void abort (void);
typedef __SIZE_TYPE__ size_t;
extern char *strncpy (char *, const char *, size_t);
extern int strcmp (const char *, const char *);
extern int strncmp (const char *, const char *, size_t);
extern void *memset (void *, int, size_t);
int main ()
{
const char *const src = "hello world";
const char *src2;
char dst[64], *dst2;
memset (dst, 0, sizeof (dst));
if (strncpy (dst, src, 4) != dst || strncmp (dst, src, 4))
abort();
memset (dst, 0, sizeof (dst));
if (strncpy (dst+16, src, 4) != dst+16 || strncmp (dst+16, src, 4))
abort();
memset (dst, 0, sizeof (dst));
if (strncpy (dst+32, src+5, 4) != dst+32 || strncmp (dst+32, src+5, 4))
abort();
memset (dst, 0, sizeof (dst));
dst2 = dst;
if (strncpy (++dst2, src+5, 4) != dst+1 || strncmp (dst2, src+5, 4)
|| dst2 != dst+1)
abort();
memset (dst, 0, sizeof (dst));
if (strncpy (dst, src, 0) != dst || strcmp (dst, ""))
abort();
memset (dst, 0, sizeof (dst));
dst2 = dst; src2 = src;
if (strncpy (++dst2, ++src2, 0) != dst+1 || strcmp (dst2, "")
|| dst2 != dst+1 || src2 != src+1)
abort();
memset (dst, 0, sizeof (dst));
dst2 = dst; src2 = src;
if (strncpy (++dst2+5, ++src2+5, 0) != dst+6 || strcmp (dst2+5, "")
|| dst2 != dst+1 || src2 != src+1)
abort();
memset (dst, 0, sizeof (dst));
if (strncpy (dst, src, 12) != dst || strcmp (dst, src))
abort();
return 0;
}
#ifdef __OPTIMIZE__
/* When optimizing, all the above cases should be transformed into
something else. So any remaining calls to the original function
should abort. */
static char *
strncpy(char *s1, const char *s2, size_t n)
{
abort();
}
#endif

View File

@ -0,0 +1,60 @@
/* Copyright (C) 2000 Free Software Foundation.
Ensure all expected transformations of builtin strncmp occur and
perform correctly.
Written by Kaveh R. Ghazi, 11/26/2000. */
extern void abort (void);
typedef __SIZE_TYPE__ size_t;
extern int strncmp (const char *, const char *, size_t);
int main ()
{
const char *const s1 = "hello world";
const char *s2, *s3;
if (strncmp (s1, "hello world", 12) != 0)
abort();
if (strncmp ("hello world", s1, 12) != 0)
abort();
if (strncmp ("hello", "hello", 6) != 0)
abort();
if (strncmp ("hello", "hello", 2) != 0)
abort();
if (strncmp ("hello", "hello", 100) != 0)
abort();
if (strncmp (s1+10, "d", 100) != 0)
abort();
if (strncmp (10+s1, "d", 100) != 0)
abort();
if (strncmp ("d", s1+10, 1) != 0)
abort();
if (strncmp ("d", 10+s1, 1) != 0)
abort();
if (strncmp ("hello", "aaaaa", 100) <= 0)
abort();
if (strncmp ("aaaaa", "hello", 100) >= 0)
abort();
if (strncmp ("hello", "aaaaa", 1) <= 0)
abort();
if (strncmp ("aaaaa", "hello", 1) >= 0)
abort();
s2 = s1; s3 = s1+4;
if (strncmp (++s2, ++s3, 0) != 0 || s2 != s1+1 || s3 != s1+5)
abort();
return 0;
}
#ifdef __OPTIMIZE__
/* When optimizing, all the above cases should be transformed into
something else. So any remaining calls to the original function
should abort. */
static char *
strncmp(const char *s1, const char *s2, size_t n)
{
abort();
}
#endif