Commit 2dee4af1 by Jakub Jelinek Committed by Jakub Jelinek

builtins.c (c_strlen): Use TREE_STRING_LENGTH - 1 for max.

	* builtins.c (c_strlen): Use TREE_STRING_LENGTH - 1 for max.
	(c_getstr): New function.
	(expand_builtin_strstr): Do nothing if -fcheck-memory-usage.
	If both arguments are constant string, optimize out.
	(expand_builtin_strchr, expand_builtin_strrchr): New functions.
	(expand_builtin_strpbrk): Use c_getstr, do nothing if
	-fcheck-memory-usage.
	(expand_builtin_fputs): Likewise.
	(expand_builtin_strcmp): Add MODE argument.
	Use even if !HAVE_cmpstrsi.
	Optimize the case when both arguments are constant strings.
	(expand_builtin): Adjust expand_builtin_strcmp caller.
	Call expand_builtin_strchr and expand_builtin_strrchr.
	* c-common.c (c_common_nodes_and_builtins): Add strchr and strrchr
	builtins.
	* builtins.def (BUILT_IN_STRRCHR): Add.

	* gcc.c-torture/execute/string-opt-1.c: Add test for strstr
	with both arguments constant strings.
	* gcc.c-torture/execute/string-opt-3.c: New test.
	* gcc.c-torture/execute/string-opt-4.c: New test.
	* gcc.c-torture/execute/string-opt-5.c: New test.

From-SVN: r37338
parent 54d87db8
2000-11-09 Jakub Jelinek <jakub@redhat.com>
* builtins.c (c_strlen): Use TREE_STRING_LENGTH - 1 for max.
(c_getstr): New function.
(expand_builtin_strstr): Do nothing if -fcheck-memory-usage.
If both arguments are constant string, optimize out.
(expand_builtin_strchr, expand_builtin_strrchr): New functions.
(expand_builtin_strpbrk): Use c_getstr, do nothing if
-fcheck-memory-usage.
(expand_builtin_fputs): Likewise.
(expand_builtin_strcmp): Add MODE argument.
Use even if !HAVE_cmpstrsi.
Optimize the case when both arguments are constant strings.
(expand_builtin): Adjust expand_builtin_strcmp caller.
Call expand_builtin_strchr and expand_builtin_strrchr.
* c-common.c (c_common_nodes_and_builtins): Add strchr and strrchr
builtins.
* builtins.def (BUILT_IN_STRRCHR): Add.
2000-11-08 Gerald Pfeifer <pfeifer@dbai.tuwien.ac.at>
* fixinc/gnu-regex.c: Rename EGCS LOCAL markers to GCC LOCAL.
......
......@@ -80,6 +80,7 @@ tree (*lang_type_promotes_to) PARAMS ((tree));
static int get_pointer_alignment PARAMS ((tree, unsigned));
static tree c_strlen PARAMS ((tree));
static const char *c_getstr PARAMS ((tree));
static rtx get_memory_rtx PARAMS ((tree));
static int apply_args_size PARAMS ((void));
static int apply_result_size PARAMS ((void));
......@@ -100,8 +101,9 @@ static rtx expand_builtin_va_end PARAMS ((tree));
static rtx expand_builtin_va_copy PARAMS ((tree));
#ifdef HAVE_cmpstrsi
static rtx expand_builtin_memcmp PARAMS ((tree, tree, rtx));
static rtx expand_builtin_strcmp PARAMS ((tree, rtx));
#endif
static rtx expand_builtin_strcmp PARAMS ((tree, rtx,
enum machine_mode));
static rtx expand_builtin_memcpy PARAMS ((tree));
static rtx expand_builtin_strcpy PARAMS ((tree));
static rtx expand_builtin_memset PARAMS ((tree));
......@@ -111,6 +113,10 @@ static rtx expand_builtin_strstr PARAMS ((tree, rtx,
enum machine_mode));
static rtx expand_builtin_strpbrk PARAMS ((tree, rtx,
enum machine_mode));
static rtx expand_builtin_strchr PARAMS ((tree, rtx,
enum machine_mode));
static rtx expand_builtin_strrchr PARAMS ((tree, rtx,
enum machine_mode));
static rtx expand_builtin_alloca PARAMS ((tree, rtx));
static rtx expand_builtin_ffs PARAMS ((tree, rtx, rtx));
static rtx expand_builtin_frame_address PARAMS ((tree));
......@@ -210,7 +216,7 @@ c_strlen (src)
if (src == 0)
return 0;
max = TREE_STRING_LENGTH (src);
max = TREE_STRING_LENGTH (src) - 1;
ptr = TREE_STRING_POINTER (src);
if (offset_node && TREE_CODE (offset_node) != INTEGER_CST)
......@@ -263,6 +269,41 @@ c_strlen (src)
return ssize_int (strlen (ptr + offset));
}
/* Return a char pointer for a C string if it is a string constant
or sum of string constant and integer constant. */
static const char *
c_getstr (src)
tree src;
{
tree offset_node;
int offset, max;
char *ptr;
src = string_constant (src, &offset_node);
if (src == 0)
return 0;
max = TREE_STRING_LENGTH (src) - 1;
ptr = TREE_STRING_POINTER (src);
if (!offset_node)
offset = 0;
else if (TREE_CODE (offset_node) != INTEGER_CST)
return 0;
else
{
/* Did we get a long long offset? If so, punt. */
if (TREE_INT_CST_HIGH (offset_node) != 0)
return 0;
offset = TREE_INT_CST_LOW (offset_node);
if (offset < 0 || offset > max)
return 0;
}
return (const char *) ptr + offset;
}
/* Given TEM, a pointer to a stack frame, follow the dynamic chain COUNT
times to get the address of either a higher stack frame, or a return
address located within it (depending on FNDECL_CODE). */
......@@ -1416,57 +1457,63 @@ expand_builtin_strstr (arglist, target, mode)
if (arglist == 0
|| 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_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
|| current_function_check_memory_usage)
return 0;
else
{
tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
tree len = c_strlen (s2);
tree call_expr, fn;
const char *p1, *p2;
if (!len)
p2 = c_getstr (s2);
if (p2 == NULL)
return 0;
switch (compare_tree_int (len, 1))
{
case -1: /* length is 0, return s1. */
return expand_expr (s1, target, mode, EXPAND_NORMAL);
case 0: /* length is 1, return strchr(s1, s2[0]). */
{
tree call_expr, fn = built_in_decls[BUILT_IN_STRCHR];
p1 = c_getstr (s1);
if (p1 != NULL)
{
const char *r = strstr (p1, p2);
if (!fn)
return 0;
STRIP_NOPS (s2);
if (s2 && TREE_CODE (s2) == ADDR_EXPR)
s2 = TREE_OPERAND (s2, 0);
if (r == NULL)
return const0_rtx;
/* New argument list transforming strstr(s1, s2) to
strchr(s1, s2[0]). */
arglist =
build_tree_list (NULL_TREE,
build_int_2 (TREE_STRING_POINTER (s2)[0], 0));
arglist = tree_cons (NULL_TREE, s1, arglist);
call_expr = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arglist, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
}
case 1: /* length is greater than 1, really call strstr. */
return 0;
default:
abort();
/* Return an offset into the constant string argument. */
return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
s1, ssize_int (r - p1))),
target, mode, EXPAND_NORMAL);
}
if (p2[0] == '\0')
return expand_expr (s1, target, mode, EXPAND_NORMAL);
if (p2[1] != '\0')
return 0;
fn = built_in_decls[BUILT_IN_STRCHR];
if (!fn)
return 0;
/* New argument list transforming strstr(s1, s2) to
strchr(s1, s2[0]). */
arglist =
build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
arglist = tree_cons (NULL_TREE, s1, arglist);
call_expr = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arglist, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
}
}
/* Expand a call to the strpbrk builtin. Return 0 if we failed the
/* Expand a call to the strchr builtin. Return 0 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_strpbrk (arglist, target, mode)
expand_builtin_strchr (arglist, target, mode)
tree arglist;
rtx target;
enum machine_mode mode;
......@@ -1474,84 +1521,160 @@ expand_builtin_strpbrk (arglist, target, mode)
if (arglist == 0
|| 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_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != INTEGER_TYPE
|| current_function_check_memory_usage)
return 0;
else
{
tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
tree len1 = c_strlen (s1), len2 = c_strlen (s2);
tree stripped_s1 = s1, stripped_s2 = s2;
STRIP_NOPS (stripped_s1);
if (stripped_s1 && TREE_CODE (stripped_s1) == ADDR_EXPR)
stripped_s1 = TREE_OPERAND (stripped_s1, 0);
STRIP_NOPS (stripped_s2);
if (stripped_s2 && TREE_CODE (stripped_s2) == ADDR_EXPR)
stripped_s2 = TREE_OPERAND (stripped_s2, 0);
/* If both arguments are constants, calculate the result now. */
if (len1 && len2
&& TREE_CODE (stripped_s1) == STRING_CST
&& TREE_CODE (stripped_s2) == STRING_CST)
{
const char *const result =
strpbrk (TREE_STRING_POINTER (stripped_s1),
TREE_STRING_POINTER (stripped_s2));
if (result)
{
long offset = result - TREE_STRING_POINTER (stripped_s1);
const char *p1;
/* Return an offset into the constant string argument. */
return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
s1, ssize_int (offset))),
target, mode, EXPAND_NORMAL);
}
else
if (TREE_CODE (s2) != INTEGER_CST)
return 0;
p1 = c_getstr (s1);
if (p1 != NULL)
{
const char *r = strchr (p1, (char) TREE_INT_CST_LOW (s2));
if (r == NULL)
return const0_rtx;
/* Return an offset into the constant string argument. */
return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
s1, ssize_int (r - p1))),
target, mode, EXPAND_NORMAL);
}
/* We must have been able to figure out the second argument's
length to do anything else. */
if (!len2)
/* FIXME: Should use here strchrM optab so that ports can optimize
this. */
return 0;
}
}
/* Expand a call to the strrchr builtin. Return 0 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_strrchr (arglist, target, mode)
tree arglist;
rtx target;
enum machine_mode mode;
{
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != INTEGER_TYPE
|| current_function_check_memory_usage)
return 0;
else
{
tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
tree call_expr, fn;
const char *p1;
if (TREE_CODE (s2) != INTEGER_CST)
return 0;
/* OK, handle some cases. */
switch (compare_tree_int (len2, 1))
{
case -1: /* length is 0, return NULL. */
{
/* Evaluate and ignore the arguments in case they had
side-effects. */
expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
expand_expr (s2, const0_rtx, VOIDmode, EXPAND_NORMAL);
p1 = c_getstr (s1);
if (p1 != NULL)
{
const char *r = strrchr (p1, (char) TREE_INT_CST_LOW (s2));
if (r == NULL)
return const0_rtx;
}
case 0: /* length is 1, return strchr(s1, s2[0]). */
{
tree call_expr, fn = built_in_decls[BUILT_IN_STRCHR];
if (!fn)
return 0;
/* Return an offset into the constant string argument. */
return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
s1, ssize_int (r - p1))),
target, mode, EXPAND_NORMAL);
}
/* New argument list transforming strpbrk(s1, s2) to
strchr(s1, s2[0]). */
arglist =
build_tree_list (NULL_TREE, build_int_2
(TREE_STRING_POINTER (stripped_s2)[0], 0));
arglist = tree_cons (NULL_TREE, s1, arglist);
call_expr = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arglist, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
}
case 1: /* length is greater than 1, really call strpbrk. */
return 0;
default:
abort();
if (! integer_zerop (s2))
return 0;
fn = built_in_decls[BUILT_IN_STRCHR];
if (!fn)
return 0;
/* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */
call_expr = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arglist, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
}
}
/* Expand a call to the strpbrk builtin. Return 0 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_strpbrk (arglist, target, mode)
tree arglist;
rtx target;
enum machine_mode mode;
{
if (arglist == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE
|| TREE_CHAIN (arglist) == 0
|| TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist)))) != POINTER_TYPE
|| current_function_check_memory_usage)
return 0;
else
{
tree s1 = TREE_VALUE (arglist), s2 = TREE_VALUE (TREE_CHAIN (arglist));
tree call_expr, fn;
const char *p1, *p2;
p2 = c_getstr (s2);
if (p2 == NULL)
return 0;
p1 = c_getstr (s1);
if (p1 != NULL)
{
const char *r = strpbrk (p1, p2);
if (r == NULL)
return const0_rtx;
/* Return an offset into the constant string argument. */
return expand_expr (fold (build (PLUS_EXPR, TREE_TYPE (s1),
s1, ssize_int (r - p1))),
target, mode, EXPAND_NORMAL);
}
if (p2[0] == '\0')
{
/* strpbrk(x, "") == NULL.
Evaluate and ignore the arguments in case they had
side-effects. */
expand_expr (s1, const0_rtx, VOIDmode, EXPAND_NORMAL);
return const0_rtx;
}
if (p2[1] != '\0')
return 0; /* Really call strpbrk. */
fn = built_in_decls[BUILT_IN_STRCHR];
if (!fn)
return 0;
/* New argument list transforming strpbrk(s1, s2) to
strchr(s1, s2[0]). */
arglist =
build_tree_list (NULL_TREE, build_int_2 (p2[0], 0));
arglist = tree_cons (NULL_TREE, s1, arglist);
call_expr = build1 (ADDR_EXPR,
build_pointer_type (TREE_TYPE (fn)), fn);
call_expr = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (fn)),
call_expr, arglist, NULL_TREE);
TREE_SIDE_EFFECTS (call_expr) = 1;
return expand_expr (call_expr, target, mode, EXPAND_NORMAL);
}
}
......@@ -1832,17 +1955,21 @@ expand_builtin_memcmp (exp, arglist, target)
return convert_to_mode (mode, result, 0);
}
}
#endif
/* Expand expression EXP, which is a call to the strcmp 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_strcmp (exp, target)
expand_builtin_strcmp (exp, target, mode)
tree exp;
rtx target;
enum machine_mode mode;
{
tree arglist = TREE_OPERAND (exp, 1);
tree arg1, arg2;
const char *p1, *p2;
/* If we need to check memory accesses, call the library function. */
if (current_function_check_memory_usage)
......@@ -1856,11 +1983,27 @@ expand_builtin_strcmp (exp, target)
!= POINTER_TYPE))
return 0;
else if (! HAVE_cmpstrsi)
arg1 = TREE_VALUE (arglist);
arg2 = TREE_VALUE (TREE_CHAIN (arglist));
p1 = c_getstr (arg1);
p2 = c_getstr (arg2);
if (p1 && p2)
{
int i = strcmp (p1, p2);
return expand_expr (i < 0 ? build_int_2 (-1, -1)
: i == 0 ? integer_zero_node
: integer_one_node,
target, mode, EXPAND_NORMAL);
}
#ifdef HAVE_cmpstrsi
if (! HAVE_cmpstrsi)
return 0;
{
tree arg1 = TREE_VALUE (arglist);
tree arg2 = TREE_VALUE (TREE_CHAIN (arglist));
tree len = c_strlen (arg1);
tree len2 = c_strlen (arg2);
rtx result;
......@@ -1900,8 +2043,10 @@ expand_builtin_strcmp (exp, target)
return result;
}
}
#else
return 0;
#endif
}
/* Expand a call to __builtin_saveregs, generating the result in TARGET,
if that's convenient. */
......@@ -2464,7 +2609,8 @@ expand_builtin_fputs (arglist, ignore)
|| (TREE_CODE (TREE_TYPE (TREE_VALUE (arglist))) != POINTER_TYPE)
|| TREE_CHAIN (arglist) == 0
|| (TREE_CODE (TREE_TYPE (TREE_VALUE (TREE_CHAIN (arglist))))
!= POINTER_TYPE))
!= POINTER_TYPE)
|| current_function_check_memory_usage)
return 0;
/* Get the length of the string passed to fputs. If the length
......@@ -2484,23 +2630,21 @@ expand_builtin_fputs (arglist, ignore)
}
case 0: /* length is 1, call fputc. */
{
tree stripped_string = TREE_VALUE (arglist);
const char *p = c_getstr (TREE_VALUE (arglist));
STRIP_NOPS (stripped_string);
if (stripped_string && TREE_CODE (stripped_string) == ADDR_EXPR)
stripped_string = TREE_OPERAND (stripped_string, 0);
/* New argument list transforming fputs(string, stream) to
fputc(string[0], stream). */
arglist =
build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
arglist =
tree_cons (NULL_TREE,
build_int_2 (TREE_STRING_POINTER (stripped_string)[0], 0),
arglist);
fn = fn_fputc;
break;
if (p != NULL)
{
/* New argument list transforming fputs(string, stream) to
fputc(string[0], stream). */
arglist =
build_tree_list (NULL_TREE, TREE_VALUE (TREE_CHAIN (arglist)));
arglist =
tree_cons (NULL_TREE, build_int_2 (p[0], 0), arglist);
fn = fn_fputc;
break;
}
}
/* FALLTHROUGH */
case 1: /* length is greater than 1, call fwrite. */
{
tree string_arg = TREE_VALUE (arglist);
......@@ -2740,6 +2884,18 @@ expand_builtin (exp, target, subtarget, mode, ignore)
return target;
break;
case BUILT_IN_STRCHR:
target = expand_builtin_strchr (arglist, target, mode);
if (target)
return target;
break;
case BUILT_IN_STRRCHR:
target = expand_builtin_strrchr (arglist, target, mode);
if (target)
return target;
break;
case BUILT_IN_MEMCPY:
target = expand_builtin_memcpy (arglist);
if (target)
......@@ -2758,16 +2914,16 @@ expand_builtin (exp, target, subtarget, mode, ignore)
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. */
#ifdef HAVE_cmpstrsi
case BUILT_IN_STRCMP:
target = expand_builtin_strcmp (exp, target);
target = expand_builtin_strcmp (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. */
#ifdef HAVE_cmpstrsi
case BUILT_IN_BCMP:
case BUILT_IN_MEMCMP:
target = expand_builtin_memcmp (exp, arglist, target);
......@@ -2775,7 +2931,6 @@ expand_builtin (exp, target, subtarget, mode, ignore)
return target;
break;
#else
case BUILT_IN_STRCMP:
case BUILT_IN_BCMP:
case BUILT_IN_MEMCMP:
break;
......@@ -2833,9 +2988,7 @@ expand_builtin (exp, target, subtarget, mode, ignore)
case BUILT_IN_PUTS:
case BUILT_IN_FPUTC:
case BUILT_IN_FWRITE:
case BUILT_IN_STRCHR:
break;
case BUILT_IN_FPUTS:
target = expand_builtin_fputs (arglist, ignore);
if (target)
......
......@@ -42,6 +42,7 @@ DEF_BUILTIN(BUILT_IN_STRLEN)
DEF_BUILTIN(BUILT_IN_STRSTR)
DEF_BUILTIN(BUILT_IN_STRPBRK)
DEF_BUILTIN(BUILT_IN_STRCHR)
DEF_BUILTIN(BUILT_IN_STRRCHR)
DEF_BUILTIN(BUILT_IN_FSQRT)
DEF_BUILTIN(BUILT_IN_SIN)
DEF_BUILTIN(BUILT_IN_COS)
......
......@@ -5179,6 +5179,8 @@ c_common_nodes_and_builtins ()
built_in_decls[BUILT_IN_STRCHR] =
builtin_function ("__builtin_strchr", string_ftype_string_int,
BUILT_IN_STRCHR, BUILT_IN_NORMAL, "strchr");
builtin_function ("__builtin_strrchr", string_ftype_string_int,
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_strlen", strlen_ftype,
......@@ -5249,6 +5251,10 @@ c_common_nodes_and_builtins ()
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,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strrchr", string_ftype_string_int, BUILT_IN_STRRCHR,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strpbrk", string_ftype_string_string, BUILT_IN_STRPBRK,
BUILT_IN_NORMAL, NULL_PTR);
builtin_function ("strcpy", string_ftype_ptr_ptr, BUILT_IN_STRCPY,
......
2000-11-09 Jakub Jelinek <jakub@redhat.com>
* gcc.c-torture/execute/string-opt-1.c: Add test for strstr
with both arguments constant strings.
* gcc.c-torture/execute/string-opt-3.c: New test.
* gcc.c-torture/execute/string-opt-4.c: New test.
* gcc.c-torture/execute/string-opt-5.c: New test.
2000-11-08 Nick Clifton <nickc@redhat.com>
* gcc.c-torture/execute/20001108-1.c: New test case. Checks
......
......@@ -22,7 +22,9 @@ int main()
abort();
if (strstr (foo + 6, "o") != foo + 7)
abort();
if (strstr (foo + 1, "world") != foo + 6)
abort();
return 0;
}
......
/* Copyright (C) 2000 Free Software Foundation.
Ensure all expected transformations of builtin strlen, strcmp and strrchr
occur and perform correctly.
Written by Jakub Jelinek, 11/7/2000. */
extern void abort (void);
extern __SIZE_TYPE__ strlen (const char *);
extern int strcmp (const char *, const char *);
extern char *strrchr (const char *, int);
int x = 6;
char *bar = "hi world";
int main()
{
const char *const foo = "hello world";
if (strlen (foo) != 11)
abort ();
if (strlen (foo + 4) != 7)
abort ();
if (strlen (foo + (x++ & 7)) != 5)
abort ();
if (x != 7)
abort ();
if (strcmp (foo, "hello") <= 0)
abort ();
if (strcmp (foo + 2, "llo") <= 0)
abort ();
if (strcmp (foo, foo) != 0)
abort ();
if (strcmp (foo, "hello world ") >= 0)
abort ();
if (strcmp (foo + 10, "dx") >= 0)
abort ();
if (strcmp (10 + foo, "dx") >= 0)
abort ();
if (strrchr (foo, 'x'))
abort ();
if (strrchr (foo, 'o') != foo + 7)
abort ();
if (strrchr (foo, 'e') != foo + 1)
abort ();
if (strrchr (foo + 3, 'e'))
abort ();
if (strrchr (foo, '\0') != foo + 11)
abort ();
if (strrchr (bar, '\0') != bar + 8)
abort ();
if (strrchr (bar + 4, '\0') != bar + 8)
abort ();
if (strrchr (bar + (x++ & 3), '\0') != bar + 8)
abort ();
if (x != 8)
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. */
__SIZE_TYPE__
strlen (const char *s)
{
abort ();
}
int
strcmp (const char *s1, const char *s2)
{
abort ();
}
char *
strrchr (const char *s, int c)
{
abort ();
}
#endif
/* Copyright (C) 2000 Free Software Foundation.
Ensure all expected transformations of builtin strchr occur and
perform correctly.
Written by Jakub Jelinek, 11/7/2000. */
extern void abort (void);
extern char *strchr (const char *, int);
int main()
{
const char *const foo = "hello world";
if (strchr (foo, 'x'))
abort ();
if (strchr (foo, 'o') != foo + 4)
abort ();
if (strchr (foo + 5, 'o') != foo + 7)
abort ();
if (strchr (foo, '\0') != foo + 11)
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. */
char *
strchr (const char *s, int c)
{
abort ();
}
#endif
/* Copyright (C) 2000 Free Software Foundation.
Ensure builtin strlen, strcmp, strchr and strrchr perform correctly.
Written by Jakub Jelinek, 11/7/2000. */
extern void abort (void);
extern __SIZE_TYPE__ strlen (const char *);
extern int strcmp (const char *, const char *);
extern char *strchr (const char *, int);
extern char *strrchr (const char *, int);
int x = 6;
char *bar = "hi world";
int main()
{
const char *const foo = "hello world";
if (strlen (bar) != 8)
abort ();
if (strlen (bar + (++x & 2)) != 6)
abort ();
if (x != 7)
abort ();
if (strlen (foo + (x++, 6)) != 5)
abort ();
if (x != 8)
abort ();
if (strlen (foo + (++x & 1)) != 10)
abort ();
if (x != 9)
abort ();
if (strcmp (foo + (x -= 6), "lo world"))
abort ();
if (x != 3)
abort ();
if (strcmp (foo, bar) >= 0)
abort ();
if (strcmp (foo, bar + (x++ & 1)) >= 0)
abort ();
if (x != 4)
abort ();
if (strchr (foo + (x++ & 7), 'l') != foo + 9)
abort ();
if (x != 5)
abort ();
if (strchr (bar, 'o') != bar + 4)
abort ();
if (strchr (bar, '\0') != bar + 8)
abort ();
if (strrchr (bar, 'x'))
abort ();
if (strrchr (bar, 'o') != bar + 4)
abort ();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment