From: Jakub Jelinek Date: Wed, 29 Nov 2000 18:24:50 +0000 (+0100) Subject: expr.h (store_by_pieces): Add prototype. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=57814e5ea3528a521e997fcc6b5d658174b63e10;p=gcc.git expr.h (store_by_pieces): Add prototype. * expr.h (store_by_pieces): Add prototype. (can_store_by_pieces): Likewise. * expr.c (struct store_by_pieces): Renamed from clear_by_pieces. (can_store_by_pieces): New. (store_by_pieces): New. (clear_by_pieces): New. (clear_by_pieces_1): New. (store_by_pieces_1): Renamed from clear_by_pieces, handle storing arbitrary compiler generated constants into memory block. (store_by_pieces_2): Renamed from clear_by_pieces_1, likewise. * builtins.c (c_readstr): New. (builtin_memcpy_read_str): New. (expand_builtin_memcpy): If src is string constant and emit_block_move would move it by pieces, compute integer constants from the string and store it into memory block instead. (builtin_strncpy_read_str): New. (expand_builtin_strncpy): If N is not constant zero and c_strlen does not return INTEGER_CST, don't optimize. If N is larger than strlen(src) + 1, try to copy the string including padding with store_by_pieces. (expand_builtin_strcmp): If both arguments have side effects, don't optimize. (expand_builtin_fputs): If STR has side effects, don't optimize. * gcc.c-torture/execute/string-opt-5.c: Add some strcmp and strncpy tests. * gcc.c-torture/execute/string-opt-6.c: New test. From-SVN: r37851 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index db00db23bc4..be3164c4414 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,29 @@ +2000-11-29 Jakub Jelinek + + * expr.h (store_by_pieces): Add prototype. + (can_store_by_pieces): Likewise. + * expr.c (struct store_by_pieces): Renamed from clear_by_pieces. + (can_store_by_pieces): New. + (store_by_pieces): New. + (clear_by_pieces): New. + (clear_by_pieces_1): New. + (store_by_pieces_1): Renamed from clear_by_pieces, handle storing + arbitrary compiler generated constants into memory block. + (store_by_pieces_2): Renamed from clear_by_pieces_1, likewise. + * builtins.c (c_readstr): New. + (builtin_memcpy_read_str): New. + (expand_builtin_memcpy): If src is string constant and + emit_block_move would move it by pieces, compute integer constants + from the string and store it into memory block instead. + (builtin_strncpy_read_str): New. + (expand_builtin_strncpy): If N is not constant zero and c_strlen does + not return INTEGER_CST, don't optimize. + If N is larger than strlen(src) + 1, try to copy the string + including padding with store_by_pieces. + (expand_builtin_strcmp): If both arguments have side effects, don't + optimize. + (expand_builtin_fputs): If STR has side effects, don't optimize. + 2000-11-29 Richard Earnshaw * arm.md (sibcall, sibcall_value, sibcall_insn, sibcall_value_insn): diff --git a/gcc/builtins.c b/gcc/builtins.c index 7db9b2622a2..07d10adf446 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -81,6 +81,8 @@ 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 c_readstr PARAMS ((const char *, + enum machine_mode)); static rtx get_memory_rtx PARAMS ((tree)); static int apply_args_size PARAMS ((void)); static int apply_result_size PARAMS ((void)); @@ -106,8 +108,12 @@ static rtx expand_builtin_strcmp PARAMS ((tree, rtx, enum machine_mode)); static rtx expand_builtin_strncmp PARAMS ((tree, rtx, enum machine_mode)); +static rtx builtin_memcpy_read_str PARAMS ((PTR, HOST_WIDE_INT, + enum machine_mode)); static rtx expand_builtin_memcpy PARAMS ((tree)); static rtx expand_builtin_strcpy PARAMS ((tree)); +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 expand_builtin_memset PARAMS ((tree)); @@ -308,6 +314,41 @@ c_getstr (src) return ptr + offset; } +/* 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; + enum machine_mode mode; +{ + HOST_WIDE_INT c[2]; + HOST_WIDE_INT ch; + unsigned int i, j; + + if (GET_MODE_CLASS (mode) != MODE_INT) + abort (); + c[0] = 0; + c[1] = 0; + ch = 1; + for (i = 0; i < GET_MODE_SIZE (mode); i++) + { + j = i; + if (WORDS_BIG_ENDIAN) + j = GET_MODE_SIZE (mode) - i - 1; + if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN + && GET_MODE_SIZE (mode) > UNITS_PER_WORD) + j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1; + j *= BITS_PER_UNIT; + if (j > 2 * HOST_BITS_PER_WIDE_INT) + abort (); + if (ch) + ch = (unsigned char) str[i]; + c[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT); + } + return immed_double_const (c[0], c[1], mode); +} + /* 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). */ @@ -1685,6 +1726,24 @@ expand_builtin_strpbrk (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_memcpy_read_str (data, offset, mode) + PTR data; + HOST_WIDE_INT offset; + enum machine_mode mode; +{ + const char *str = (const char *) data; + + if (offset + GET_MODE_SIZE (mode) > strlen (str) + 1) + abort (); /* Attempt to read past the end of constant string. */ + + return c_readstr (str + offset, mode); +} + /* Expand a call to the memcpy builtin, with arguments in ARGLIST. */ static rtx expand_builtin_memcpy (arglist) @@ -1706,6 +1765,7 @@ expand_builtin_memcpy (arglist) tree dest = TREE_VALUE (arglist); tree src = TREE_VALUE (TREE_CHAIN (arglist)); tree len = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist))); + const char *src_str; int src_align = get_pointer_alignment (src, BIGGEST_ALIGNMENT); int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); @@ -1717,8 +1777,26 @@ expand_builtin_memcpy (arglist) return 0; dest_mem = get_memory_rtx (dest); - src_mem = get_memory_rtx (src); len_rtx = expand_expr (len, NULL_RTX, VOIDmode, 0); + src_str = c_getstr (src); + + /* If SRC is a string constant and block move would be done + by pieces, we can avoid loading the string from memory + and only stored the computed constants. */ + if (src_str + && !current_function_check_memory_usage + && GET_CODE (len_rtx) == CONST_INT + && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1 + && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str, + (PTR) src_str, dest_align)) + { + store_by_pieces (dest_mem, INTVAL (len_rtx), + builtin_memcpy_read_str, + (PTR) src_str, dest_align); + return force_operand (XEXP (dest_mem, 0), NULL_RTX); + } + + src_mem = get_memory_rtx (src); /* Just copy the rights of SRC to the rights of DEST. */ if (current_function_check_memory_usage) @@ -1774,6 +1852,24 @@ expand_builtin_strcpy (exp) return result; } +/* 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_strncpy_read_str (data, offset, mode) + PTR data; + HOST_WIDE_INT offset; + enum machine_mode mode; +{ + const char *str = (const char *) data; + + if ((unsigned HOST_WIDE_INT) offset > strlen (str)) + return const0_rtx; + + return c_readstr (str + offset, mode); +} + /* Expand expression EXP, which is a call to the strncpy builtin. Return 0 if we failed the caller should emit a normal call. */ @@ -1814,17 +1910,35 @@ expand_builtin_strncpy (arglist, target, mode) return expand_expr (TREE_VALUE (arglist), target, mode, EXPAND_NORMAL); } - + /* Now, we must be passed a constant src ptr parameter. */ - if (slen == 0) + if (slen == 0 || TREE_CODE (slen) != INTEGER_CST) 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. */ + len is greater than strlen(s2)+1. In that case try to + use store_by_pieces, if it fails, punt. */ if (tree_int_cst_lt (slen, len)) - return 0; + { + tree dest = TREE_VALUE (arglist); + int dest_align = get_pointer_alignment (dest, BIGGEST_ALIGNMENT); + const char *p = c_getstr (TREE_VALUE (TREE_CHAIN (arglist))); + rtx dest_mem; + + if (!p || !dest_align || TREE_INT_CST_HIGH (len) + || !can_store_by_pieces (TREE_INT_CST_LOW (len), + builtin_strncpy_read_str, + (PTR) p, dest_align)) + return 0; + + dest_mem = get_memory_rtx (dest); + store_by_pieces (dest_mem, TREE_INT_CST_LOW (len), + builtin_strncpy_read_str, + (PTR) p, dest_align); + return force_operand (XEXP (dest_mem, 0), NULL_RTX); + } /* OK transform into builtin memcpy. */ return expand_builtin_memcpy (arglist); @@ -2081,7 +2195,8 @@ expand_builtin_strcmp (exp, target, mode) /* If we don't have a constant length for the first, use the length of the second, if we know it. We don't require a constant for this case; some cost analysis could be done if both are available - but neither is constant. For now, assume they're equally cheap. + but neither is constant. For now, assume they're equally cheap + unless one has side effects. If both strings have constant lengths, use the smaller. This could arise if optimization results in strcpy being called with @@ -2091,7 +2206,7 @@ expand_builtin_strcmp (exp, target, mode) if (!len || TREE_CODE (len) != INTEGER_CST) { - if (len2) + if (len2 && !TREE_SIDE_EFFECTS (len2)) len = len2; else if (len == 0) return 0; @@ -2100,6 +2215,10 @@ expand_builtin_strcmp (exp, target, mode) && tree_int_cst_lt (len2, len)) len = len2; + /* If both arguments have side effects, we cannot optimize. */ + if (TREE_SIDE_EFFECTS (len)) + return 0; + chainon (arglist, build_tree_list (NULL_TREE, len)); result = expand_builtin_memcmp (exp, arglist, target); if (! result) @@ -2760,7 +2879,8 @@ expand_builtin_fputs (arglist, ignore) /* Get the length of the string passed to fputs. If the length can't be determined, punt. */ - if (!(len = c_strlen (TREE_VALUE (arglist)))) + if (!(len = c_strlen (TREE_VALUE (arglist))) + || TREE_CODE (len) != INTEGER_CST) return 0; switch (compare_tree_int (len, 1)) diff --git a/gcc/expr.c b/gcc/expr.c index cbe46dd9558..e520c6df7b4 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -127,10 +127,10 @@ struct move_by_pieces int reverse; }; -/* This structure is used by clear_by_pieces to describe the clear to +/* This structure is used by store_by_pieces to describe the clear to be performed. */ -struct clear_by_pieces +struct store_by_pieces { rtx to; rtx to_addr; @@ -138,6 +138,8 @@ struct clear_by_pieces int explicit_inc_to; unsigned HOST_WIDE_INT len; HOST_WIDE_INT offset; + rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode)); + PTR constfundata; int reverse; }; @@ -151,11 +153,15 @@ static unsigned HOST_WIDE_INT move_by_pieces_ninsns unsigned int)); static void move_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), enum machine_mode, struct move_by_pieces *)); +static rtx clear_by_pieces_1 PARAMS ((PTR, HOST_WIDE_INT, + enum machine_mode)); static void clear_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT, unsigned int)); -static void clear_by_pieces_1 PARAMS ((rtx (*) (rtx, ...), +static void store_by_pieces_1 PARAMS ((struct store_by_pieces *, + unsigned int)); +static void store_by_pieces_2 PARAMS ((rtx (*) (rtx, ...), enum machine_mode, - struct clear_by_pieces *)); + struct store_by_pieces *)); static rtx get_subtarget PARAMS ((rtx)); static int is_zeros_p PARAMS ((tree)); static int mostly_zeros_p PARAMS ((tree)); @@ -2249,6 +2255,105 @@ use_group_regs (call_fusage, regs) } } + +int +can_store_by_pieces (len, constfun, constfundata, align) + unsigned HOST_WIDE_INT len; + rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode)); + PTR constfundata; + unsigned int align; +{ + unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1, l; + HOST_WIDE_INT offset = 0; + enum machine_mode mode, tmode; + enum insn_code icode; + int reverse; + rtx cst; + + if (! MOVE_BY_PIECES_P (len, align)) + return 0; + + if (! SLOW_UNALIGNED_ACCESS (word_mode, align) + || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT) + align = MOVE_MAX * BITS_PER_UNIT; + + /* We would first store what we can in the largest integer mode, then go to + successively smaller modes. */ + + for (reverse = 0; + reverse <= (HAVE_PRE_DECREMENT || HAVE_POST_DECREMENT); + reverse++) + { + l = len; + mode = VOIDmode; + while (max_size > 1) + { + for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT); + tmode != VOIDmode; tmode = GET_MODE_WIDER_MODE (tmode)) + if (GET_MODE_SIZE (tmode) < max_size) + mode = tmode; + + if (mode == VOIDmode) + break; + + icode = mov_optab->handlers[(int) mode].insn_code; + if (icode != CODE_FOR_nothing + && align >= GET_MODE_ALIGNMENT (mode)) + { + unsigned int size = GET_MODE_SIZE (mode); + + while (l >= size) + { + if (reverse) + offset -= size; + + cst = (*constfun) (constfundata, offset, mode); + if (!LEGITIMATE_CONSTANT_P (cst)) + return 0; + + if (!reverse) + offset += size; + + l -= size; + } + } + + max_size = GET_MODE_SIZE (mode); + } + + /* The code above should have handled everything. */ + if (l != 0) + abort (); + } + + return 1; +} + +/* Generate several move instructions to store LEN bytes generated by + CONSTFUN to block TO. (A MEM rtx with BLKmode). CONSTFUNDATA is a + pointer which will be passed as argument in every CONSTFUN call. + ALIGN is maximum alignment we can assume. */ + +void +store_by_pieces (to, len, constfun, constfundata, align) + rtx to; + unsigned HOST_WIDE_INT len; + rtx (*constfun) PARAMS ((PTR, HOST_WIDE_INT, enum machine_mode)); + PTR constfundata; + unsigned int align; +{ + struct store_by_pieces data; + + if (! MOVE_BY_PIECES_P (len, align)) + abort (); + to = protect_from_queue (to, 1); + data.constfun = constfun; + data.constfundata = constfundata; + data.len = len; + data.to = to; + store_by_pieces_1 (&data, align); +} + /* Generate several move instructions to clear LEN bytes of block TO. (A MEM rtx with BLKmode). The caller must pass TO through protect_from_queue before calling. ALIGN is maximum alignment we can assume. */ @@ -2259,31 +2364,59 @@ clear_by_pieces (to, len, align) unsigned HOST_WIDE_INT len; unsigned int align; { - struct clear_by_pieces data; - rtx to_addr = XEXP (to, 0); + struct store_by_pieces data; + + data.constfun = clear_by_pieces_1; + data.constfundata = NULL_PTR; + data.len = len; + data.to = to; + store_by_pieces_1 (&data, align); +} + +/* Callback routine for clear_by_pieces. + Return const0_rtx unconditionally. */ + +static rtx +clear_by_pieces_1 (data, offset, mode) + PTR data ATTRIBUTE_UNUSED; + HOST_WIDE_INT offset ATTRIBUTE_UNUSED; + enum machine_mode mode ATTRIBUTE_UNUSED; +{ + return const0_rtx; +} + +/* Subroutine of clear_by_pieces and store_by_pieces. + Generate several move instructions to store LEN bytes of block TO. (A MEM + rtx with BLKmode). The caller must pass TO through protect_from_queue + before calling. ALIGN is maximum alignment we can assume. */ + +static void +store_by_pieces_1 (data, align) + struct store_by_pieces *data; + unsigned int align; +{ + rtx to_addr = XEXP (data->to, 0); unsigned HOST_WIDE_INT max_size = MOVE_MAX_PIECES + 1; enum machine_mode mode = VOIDmode, tmode; enum insn_code icode; - data.offset = 0; - data.to_addr = to_addr; - data.to = to; - data.autinc_to + data->offset = 0; + data->to_addr = to_addr; + data->autinc_to = (GET_CODE (to_addr) == PRE_INC || GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_INC || GET_CODE (to_addr) == POST_DEC); - data.explicit_inc_to = 0; - data.reverse + data->explicit_inc_to = 0; + data->reverse = (GET_CODE (to_addr) == PRE_DEC || GET_CODE (to_addr) == POST_DEC); - if (data.reverse) - data.offset = len; - data.len = len; + if (data->reverse) + data->offset = data->len; - /* If copying requires more than two move insns, + /* If storing requires more than two move insns, copy addresses to registers (to make displacements shorter) and use post-increment if available. */ - if (!data.autinc_to - && move_by_pieces_ninsns (len, align) > 2) + if (!data->autinc_to + && move_by_pieces_ninsns (data->len, align) > 2) { /* Determine the main mode we'll be using. */ for (tmode = GET_CLASS_NARROWEST_MODE (MODE_INT); @@ -2291,30 +2424,30 @@ clear_by_pieces (to, len, align) if (GET_MODE_SIZE (tmode) < max_size) mode = tmode; - if (USE_STORE_PRE_DECREMENT (mode) && data.reverse && ! data.autinc_to) + if (USE_STORE_PRE_DECREMENT (mode) && data->reverse && ! data->autinc_to) { - data.to_addr = copy_addr_to_reg (plus_constant (to_addr, len)); - data.autinc_to = 1; - data.explicit_inc_to = -1; + data->to_addr = copy_addr_to_reg (plus_constant (to_addr, data->len)); + data->autinc_to = 1; + data->explicit_inc_to = -1; } - if (USE_STORE_POST_INCREMENT (mode) && ! data.reverse - && ! data.autinc_to) + if (USE_STORE_POST_INCREMENT (mode) && ! data->reverse + && ! data->autinc_to) { - data.to_addr = copy_addr_to_reg (to_addr); - data.autinc_to = 1; - data.explicit_inc_to = 1; + data->to_addr = copy_addr_to_reg (to_addr); + data->autinc_to = 1; + data->explicit_inc_to = 1; } - if ( !data.autinc_to && CONSTANT_P (to_addr)) - data.to_addr = copy_addr_to_reg (to_addr); + if ( !data->autinc_to && CONSTANT_P (to_addr)) + data->to_addr = copy_addr_to_reg (to_addr); } if (! SLOW_UNALIGNED_ACCESS (word_mode, align) || align > MOVE_MAX * BITS_PER_UNIT || align >= BIGGEST_ALIGNMENT) align = MOVE_MAX * BITS_PER_UNIT; - /* First move what we can in the largest integer mode, then go to + /* First store what we can in the largest integer mode, then go to successively smaller modes. */ while (max_size > 1) @@ -2329,28 +2462,28 @@ clear_by_pieces (to, len, align) icode = mov_optab->handlers[(int) mode].insn_code; if (icode != CODE_FOR_nothing && align >= GET_MODE_ALIGNMENT (mode)) - clear_by_pieces_1 (GEN_FCN (icode), mode, &data); + store_by_pieces_2 (GEN_FCN (icode), mode, data); max_size = GET_MODE_SIZE (mode); } /* The code above should have handled everything. */ - if (data.len != 0) + if (data->len != 0) abort (); } -/* Subroutine of clear_by_pieces. Clear as many bytes as appropriate +/* Subroutine of store_by_pieces_1. Store as many bytes as appropriate with move instructions for mode MODE. GENFUN is the gen_... function to make a move insn for that mode. DATA has all the other info. */ static void -clear_by_pieces_1 (genfun, mode, data) +store_by_pieces_2 (genfun, mode, data) rtx (*genfun) PARAMS ((rtx, ...)); enum machine_mode mode; - struct clear_by_pieces *data; + struct store_by_pieces *data; { unsigned int size = GET_MODE_SIZE (mode); - rtx to1; + rtx to1, cst; while (data->len >= size) { @@ -2367,9 +2500,11 @@ clear_by_pieces_1 (genfun, mode, data) plus_constant (data->to_addr, data->offset)); if (HAVE_PRE_DECREMENT && data->explicit_inc_to < 0) - emit_insn (gen_add2_insn (data->to_addr, GEN_INT (-size))); + emit_insn (gen_add2_insn (data->to_addr, + GEN_INT (-(HOST_WIDE_INT) size))); - emit_insn ((*genfun) (to1, const0_rtx)); + cst = (*data->constfun) (data->constfundata, data->offset, mode); + emit_insn ((*genfun) (to1, cst)); if (HAVE_POST_INCREMENT && data->explicit_inc_to > 0) emit_insn (gen_add2_insn (data->to_addr, GEN_INT (size))); diff --git a/gcc/expr.h b/gcc/expr.h index 8cb28361038..74af2d9957f 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -1010,6 +1010,25 @@ extern void use_group_regs PARAMS ((rtx *, rtx)); alignment. */ extern rtx clear_storage PARAMS ((rtx, rtx, unsigned int)); +/* Return non-zero if it is desirable to store LEN bytes generated by + CONSTFUN with several move instructions by store_by_pieces + function. CONSTFUNDATA is a pointer which will be passed as argument + in every CONSTFUN call. + ALIGN is maximum alignment we can assume. */ +extern int can_store_by_pieces PARAMS ((unsigned HOST_WIDE_INT, + rtx (*) (PTR, HOST_WIDE_INT, + enum machine_mode), + PTR, unsigned int)); + +/* Generate several move instructions to store LEN bytes generated by + CONSTFUN to block TO. (A MEM rtx with BLKmode). CONSTFUNDATA is a + pointer which will be passed as argument in every CONSTFUN call. + ALIGN is maximum alignment we can assume. */ +extern void store_by_pieces PARAMS ((rtx, unsigned HOST_WIDE_INT, + rtx (*) (PTR, HOST_WIDE_INT, + enum machine_mode), + PTR, unsigned int)); + /* Emit insns to set X from Y. */ extern rtx emit_move_insn PARAMS ((rtx, rtx)); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 6079e4a3bf6..d957093118e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2000-11-29 Jakub Jelinek + + * gcc.c-torture/execute/string-opt-5.c: Add some strcmp and strncpy + tests. + * gcc.c-torture/execute/string-opt-6.c: New test. + 2000-11-28 Geoffrey Keating * gcc.dg/noncompile/940510-1.c: Update to test c89 functionality. diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-5.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-5.c index 79b451d7f79..108c3ed4773 100644 --- a/gcc/testsuite/gcc.c-torture/execute/string-opt-5.c +++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-5.c @@ -1,6 +1,7 @@ /* Copyright (C) 2000 Free Software Foundation. - Ensure builtin strlen, strcmp, strchr and strrchr perform correctly. + Ensure builtin strlen, strcmp, strchr, strrchr and strncpy + perform correctly. Written by Jakub Jelinek, 11/7/2000. */ @@ -9,13 +10,18 @@ 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); +extern char *strncpy (char *, const char *, __SIZE_TYPE__); +extern void *memset (void *, int, __SIZE_TYPE__); +extern int memcmp (const void *, const void *, __SIZE_TYPE__); int x = 6; +int y = 1; char *bar = "hi world"; int main() { const char *const foo = "hello world"; + char dst [64]; if (strlen (bar) != 8) abort (); @@ -53,6 +59,27 @@ int main() abort (); if (strrchr (bar, 'o') != bar + 4) abort (); + if (strcmp (foo + (x++ & 1), "ello world" + (--y & 1))) + abort (); + if (x != 6 || y != 0) + abort (); + dst[5] = ' '; + dst[6] = '\0'; + x = 5; + y = 1; + if (strncpy (dst + 1, foo + (x++ & 3), 4) != dst + 1 + || x != 6 + || strcmp (dst + 1, "ello ")) + abort (); + memset (dst, ' ', sizeof dst); + if (strncpy (dst + (++x & 1), (y++ & 3) + "foo", 10) != dst + 1 + || x != 7 + || y != 2 + || memcmp (dst, " oo\0\0\0\0\0\0\0\0 ", 12)) + abort (); + memset (dst, ' ', sizeof dst); + if (strncpy (dst, "hello", 8) != dst || memcmp (dst, "hello\0\0\0 ", 9)) + abort(); return 0; } diff --git a/gcc/testsuite/gcc.c-torture/execute/string-opt-6.c b/gcc/testsuite/gcc.c-torture/execute/string-opt-6.c new file mode 100644 index 00000000000..781d96f1dcf --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/execute/string-opt-6.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2000 Free Software Foundation. + + Ensure builtin memcpy and strcpy perform correctly. + + Written by Jakub Jelinek, 11/24/2000. */ + +extern void abort (void); +extern char *strcpy (char *, const char *); +typedef __SIZE_TYPE__ size_t; +extern void *memcpy (void *, const void *, size_t); +extern int memcmp (const void *, const void *, size_t); + +char p[32] = ""; + +int main() +{ + if (strcpy (p, "abcde") != p || memcmp (p, "abcde", 6)) + abort (); + if (strcpy (p + 16, "vwxyz" + 1) != p + 16 || memcmp (p + 16, "wxyz", 5)) + abort (); + if (strcpy (p + 1, "") != p + 1 || memcmp (p, "a\0cde", 6)) + abort (); + if (strcpy (p + 3, "fghij") != p + 3 || memcmp (p, "a\0cfghij", 9)) + abort (); + if (memcpy (p, "ABCDE", 6) != p || memcmp (p, "ABCDE", 6)) + abort (); + if (memcpy (p + 16, "VWX" + 1, 2) != p + 16 || memcmp (p + 16, "WXyz", 5)) + abort (); + if (memcpy (p + 1, "", 1) != p + 1 || memcmp (p, "A\0CDE", 6)) + abort (); + if (memcpy (p + 3, "FGHI", 4) != p + 3 || memcmp (p, "A\0CFGHIj", 9)) + 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 * +strcpy (char *d, const char *s) +{ + abort (); +} +#endif