summaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2000-12-01 17:53:07 +0000
committerjakub <jakub@138bc75d-0d04-0410-961f-82ee72b054a4>2000-12-01 17:53:07 +0000
commitecc318ffed53691bbbe44a6c0402df6f11e7dcce (patch)
tree5cf6632448272597f83a9be9809285ed8776ef09 /gcc/builtins.c
parent1fe257c543bbc1521680b754d64ff5fb3af238a2 (diff)
downloadgcc-ecc318ffed53691bbbe44a6c0402df6f11e7dcce.tar.gz
* builtins.c (target_char_cast): New function.
(expand_builtin_strchr): Use it. (expand_builtin_strrchr): Use it. (builtin_memset_read_str): New function. (expand_builtin_memset): Use target_char_cast. Try to optimize memset with second argument non-zero using store_by_pieces. * gcc.c-torture/execute/string-opt-5.c: Add some memset tests. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@37918 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c97
1 files changed, 86 insertions, 11 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 07d10adf446..0e59904325e 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -83,6 +83,7 @@ static tree c_strlen PARAMS ((tree));
static const char *c_getstr PARAMS ((tree));
static rtx c_readstr PARAMS ((const char *,
enum machine_mode));
+static int target_char_cast PARAMS ((tree, char *));
static rtx get_memory_rtx PARAMS ((tree));
static int apply_args_size PARAMS ((void));
static int apply_result_size PARAMS ((void));
@@ -116,6 +117,8 @@ static rtx builtin_strncpy_read_str PARAMS ((PTR, HOST_WIDE_INT,
enum machine_mode));
static rtx expand_builtin_strncpy PARAMS ((tree, rtx,
enum machine_mode));
+static rtx builtin_memset_read_str PARAMS ((PTR, HOST_WIDE_INT,
+ 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));
@@ -317,6 +320,7 @@ c_getstr (src)
/* Return a CONST_INT or CONST_DOUBLE corresponding to target
reading GET_MODE_BITSIZE (MODE) bits from string constant
STR. */
+
static rtx
c_readstr (str, mode)
const char *str;
@@ -349,6 +353,36 @@ c_readstr (str, mode)
return immed_double_const (c[0], c[1], mode);
}
+/* Cast a target constant CST to target CHAR and if that value fits into
+ host char type, return zero and put that value into variable pointed by
+ P. */
+
+static int
+target_char_cast (cst, p)
+ tree cst;
+ char *p;
+{
+ unsigned HOST_WIDE_INT val, hostval;
+
+ if (TREE_CODE (cst) != INTEGER_CST
+ || CHAR_TYPE_SIZE > HOST_BITS_PER_WIDE_INT)
+ return 1;
+
+ val = TREE_INT_CST_LOW (cst);
+ if (CHAR_TYPE_SIZE < HOST_BITS_PER_WIDE_INT)
+ val &= (((unsigned HOST_WIDE_INT) 1) << CHAR_TYPE_SIZE) - 1;
+
+ hostval = val;
+ if (HOST_BITS_PER_CHAR < HOST_BITS_PER_WIDE_INT)
+ hostval &= (((unsigned HOST_WIDE_INT) 1) << HOST_BITS_PER_CHAR) - 1;
+
+ if (val != hostval)
+ return 1;
+
+ *p = hostval;
+ return 0;
+}
+
/* 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). */
@@ -1583,7 +1617,13 @@ expand_builtin_strchr (arglist, target, mode)
p1 = c_getstr (s1);
if (p1 != NULL)
{
- const char *r = strchr (p1, (char) TREE_INT_CST_LOW (s2));
+ char c;
+ const char *r;
+
+ if (target_char_cast (s2, &c))
+ return 0;
+
+ r = strchr (p1, c);
if (r == NULL)
return const0_rtx;
@@ -1628,7 +1668,13 @@ expand_builtin_strrchr (arglist, target, mode)
p1 = c_getstr (s1);
if (p1 != NULL)
{
- const char *r = strrchr (p1, (char) TREE_INT_CST_LOW (s2));
+ char c;
+ const char *r;
+
+ if (target_char_cast (s2, &c))
+ return 0;
+
+ r = strrchr (p1, c);
if (r == NULL)
return const0_rtx;
@@ -1945,6 +1991,24 @@ expand_builtin_strncpy (arglist, target, mode)
}
}
+/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
+ bytes from constant string DATA + OFFSET and return it as target
+ constant. */
+
+static rtx
+builtin_memset_read_str (data, offset, mode)
+ PTR data;
+ HOST_WIDE_INT offset ATTRIBUTE_UNUSED;
+ enum machine_mode mode;
+{
+ const char *c = (const char *) data;
+ char *p = alloca (GET_MODE_SIZE (mode));
+
+ memset (p, *c, GET_MODE_SIZE (mode));
+
+ return c_readstr (p, mode);
+}
+
/* Expand expression EXP, which is a call to the memset builtin. Return 0
if we failed the caller should emit a normal call. */
@@ -1971,6 +2035,7 @@ expand_builtin_memset (exp)
tree dest = TREE_VALUE (arglist);
tree val = TREE_VALUE (TREE_CHAIN (arglist));
tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
+ char c;
int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT);
rtx dest_mem, dest_addr, len_rtx;
@@ -1980,19 +2045,29 @@ expand_builtin_memset (exp)
if (dest_align == 0)
return 0;
- /* If the arguments have side-effects, then we can only evaluate
- them at most once. The following code evaluates them twice if
- they are not constants because we break out to expand_call
- in that case. They can't be constants if they have side-effects
- so we can check for that first. Alternatively, we could call
- save_expr to make multiple evaluation safe. */
- if (TREE_SIDE_EFFECTS (val) || TREE_SIDE_EFFECTS (len))
+ if (TREE_CODE (val) != INTEGER_CST)
return 0;
- /* If VAL is not 0, don't do this operation in-line. */
- if (expand_expr (val, NULL_RTX, VOIDmode, 0) != const0_rtx)
+ if (target_char_cast (val, &c))
return 0;
+ if (c)
+ {
+ if (TREE_CODE (len) != INTEGER_CST || TREE_INT_CST_HIGH (len))
+ return 0;
+ if (current_function_check_memory_usage
+ || !can_store_by_pieces (TREE_INT_CST_LOW (len),
+ builtin_memset_read_str,
+ (PTR) &c, dest_align))
+ return 0;
+
+ dest_mem = get_memory_rtx (dest);
+ store_by_pieces (dest_mem, TREE_INT_CST_LOW (len),
+ builtin_memset_read_str,
+ (PTR) &c, dest_align);
+ return force_operand (XEXP (dest_mem, 0), NULL_RTX);
+ }
+
len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0);
dest_mem = get_memory_rtx (dest);