From 3140b2ed036c51b9df0fda28b153ebecb4f906ec Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Sat, 16 Feb 2019 12:20:33 +0100 Subject: [PATCH] re PR rtl-optimization/66152 (suboptimal load bytes to stack) PR rtl-optimization/66152 * builtins.h (c_readstr): Declare. * builtins.c (c_readstr): Remove forward declaration. Add null_terminated_p argument, if false, read all bytes from the string instead of stopping after '\0'. * expr.c (string_cst_read_str): New function. (store_expr): Use string_cst_read_str instead of builtin_strncpy_read_str. Try to store by pieces the whole exp_len first, and only if that fails, split it up into store by pieces followed by clear_storage. Formatting fix. * gcc.target/i386/pr66152.c: New test. From-SVN: r268957 --- gcc/ChangeLog | 11 +++++ gcc/builtins.c | 13 +++-- gcc/builtins.h | 1 + gcc/expr.c | 66 ++++++++++++++++--------- gcc/testsuite/ChangeLog | 5 ++ gcc/testsuite/gcc.target/i386/pr66152.c | 25 ++++++++++ 6 files changed, 93 insertions(+), 28 deletions(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr66152.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a63f2abba13..addbd399932 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 2019-02-16 Jakub Jelinek + PR rtl-optimization/66152 + * builtins.h (c_readstr): Declare. + * builtins.c (c_readstr): Remove forward declaration. Add + null_terminated_p argument, if false, read all bytes from the + string instead of stopping after '\0'. + * expr.c (string_cst_read_str): New function. + (store_expr): Use string_cst_read_str instead of + builtin_strncpy_read_str. Try to store by pieces the whole + exp_len first, and only if that fails, split it up into + store by pieces followed by clear_storage. Formatting fix. + * config/i386/i386.md (*movqi_internal): Remove static from buf variable. Use output_asm_insn (buf, operands); return ""; instead of return buf;. diff --git a/gcc/builtins.c b/gcc/builtins.c index 693e8937918..6f266ad15d0 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -95,7 +95,6 @@ builtin_info_type builtin_info[(int)END_BUILTINS]; /* Non-zero if __builtin_constant_p should be folded right away. */ bool force_folding_builtin_constant_p; -static rtx c_readstr (const char *, scalar_int_mode); static int target_char_cast (tree, char *); static rtx get_memory_rtx (tree, tree); static int apply_args_size (void); @@ -802,10 +801,14 @@ c_strlen (tree src, int only_value, c_strlen_data *data, unsigned eltsize) } /* Return a constant integer corresponding to target reading - GET_MODE_BITSIZE (MODE) bits from string constant STR. */ + GET_MODE_BITSIZE (MODE) bits from string constant STR. If + NULL_TERMINATED_P, reading stops after '\0' character, all further ones + are assumed to be zero, otherwise it reads as many characters + as needed. */ -static rtx -c_readstr (const char *str, scalar_int_mode mode) +rtx +c_readstr (const char *str, scalar_int_mode mode, + bool null_terminated_p/*=true*/) { HOST_WIDE_INT ch; unsigned int i, j; @@ -830,7 +833,7 @@ c_readstr (const char *str, scalar_int_mode mode) j = j + UNITS_PER_WORD - 2 * (j % UNITS_PER_WORD) - 1; j *= BITS_PER_UNIT; - if (ch) + if (ch || !null_terminated_p) ch = (unsigned char) str[i]; tmp[j / HOST_BITS_PER_WIDE_INT] |= ch << (j % HOST_BITS_PER_WIDE_INT); } diff --git a/gcc/builtins.h b/gcc/builtins.h index 599c96e72e1..1ffb491d785 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -103,6 +103,7 @@ struct c_strlen_data }; extern tree c_strlen (tree, int, c_strlen_data * = NULL, unsigned = 1); +extern rtx c_readstr (const char *, scalar_int_mode, bool = true); extern void expand_builtin_setjmp_setup (rtx, rtx); extern void expand_builtin_setjmp_receiver (rtx); extern void expand_builtin_update_setjmp_buf (rtx); diff --git a/gcc/expr.c b/gcc/expr.c index 01ddf5a41bd..ce71ae71089 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -5453,6 +5453,30 @@ emit_storent_insn (rtx to, rtx from) return maybe_expand_insn (code, 2, ops); } +/* Helper function for store_expr storing of STRING_CST. */ + +static rtx +string_cst_read_str (void *data, HOST_WIDE_INT offset, scalar_int_mode mode) +{ + tree str = (tree) data; + + gcc_assert (offset >= 0); + if (offset >= TREE_STRING_LENGTH (str)) + return const0_rtx; + + if ((unsigned HOST_WIDE_INT) offset + GET_MODE_SIZE (mode) + > (unsigned HOST_WIDE_INT) TREE_STRING_LENGTH (str)) + { + char *p = XALLOCAVEC (char, GET_MODE_SIZE (mode)); + size_t l = TREE_STRING_LENGTH (str) - offset; + memcpy (p, TREE_STRING_POINTER (str) + offset, l); + memset (p + l, '\0', GET_MODE_SIZE (mode) - l); + return c_readstr (p, mode, false); + } + + return c_readstr (TREE_STRING_POINTER (str) + offset, mode, false); +} + /* Generate code for computing expression EXP, and storing the value into TARGET. @@ -5472,7 +5496,7 @@ emit_storent_insn (rtx to, rtx from) rtx store_expr (tree exp, rtx target, int call_param_p, - bool nontemporal, bool reverse) + bool nontemporal, bool reverse) { rtx temp; rtx alt_rtl = NULL_RTX; @@ -5606,36 +5630,32 @@ store_expr (tree exp, rtx target, int call_param_p, if (TREE_STRING_LENGTH (str) <= 0) goto normal_expr; - str_copy_len = strlen (TREE_STRING_POINTER (str)); - if (str_copy_len < TREE_STRING_LENGTH (str) - 1) - goto normal_expr; + if (can_store_by_pieces (exp_len, string_cst_read_str, (void *) str, + MEM_ALIGN (target), false)) + { + store_by_pieces (target, exp_len, string_cst_read_str, (void *) str, + MEM_ALIGN (target), false, RETURN_BEGIN); + return NULL_RTX; + } str_copy_len = TREE_STRING_LENGTH (str); - if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0 - && TREE_STRING_POINTER (str)[TREE_STRING_LENGTH (str) - 1] == '\0') + if ((STORE_MAX_PIECES & (STORE_MAX_PIECES - 1)) == 0) { str_copy_len += STORE_MAX_PIECES - 1; str_copy_len &= ~(STORE_MAX_PIECES - 1); } - str_copy_len = MIN (str_copy_len, exp_len); - if (!can_store_by_pieces (str_copy_len, builtin_strncpy_read_str, - CONST_CAST (char *, TREE_STRING_POINTER (str)), - MEM_ALIGN (target), false)) + if (str_copy_len >= exp_len) + goto normal_expr; + + if (!can_store_by_pieces (str_copy_len, string_cst_read_str, + (void *) str, MEM_ALIGN (target), false)) goto normal_expr; - dest_mem = target; - - memop_ret retmode = exp_len > str_copy_len ? RETURN_END : RETURN_BEGIN; - dest_mem = store_by_pieces (dest_mem, - str_copy_len, builtin_strncpy_read_str, - CONST_CAST (char *, - TREE_STRING_POINTER (str)), - MEM_ALIGN (target), false, - retmode); - if (exp_len > str_copy_len) - clear_storage (adjust_address (dest_mem, BLKmode, 0), - GEN_INT (exp_len - str_copy_len), - BLOCK_OP_NORMAL); + dest_mem = store_by_pieces (target, str_copy_len, string_cst_read_str, + (void *) str, MEM_ALIGN (target), false, + RETURN_END); + clear_storage (adjust_address (dest_mem, BLKmode, 0), + GEN_INT (exp_len - str_copy_len), BLOCK_OP_NORMAL); return NULL_RTX; } else diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7fa8da548bd..ebc75cef578 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2019-02-16 Jakub Jelinek + + PR rtl-optimization/66152 + * gcc.target/i386/pr66152.c: New test. + 2019-02-15 Eric Botcazou * g++.dg/asan/asan_oob_test.cc: Skip OOB_int on SPARC. diff --git a/gcc/testsuite/gcc.target/i386/pr66152.c b/gcc/testsuite/gcc.target/i386/pr66152.c new file mode 100644 index 00000000000..3d152ebc248 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66152.c @@ -0,0 +1,25 @@ +/* PR rtl-optimization/66152 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +/* { dg-final { scan-assembler "movabs\[^\n\r]*506097522914230528" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "movabs\[^\n\r]*505813836079825408" { target { ! ia32 } } } } */ +/* { dg-final { scan-assembler "mov\[^\n\r]*50462976" { target ia32 } } } */ +/* { dg-final { scan-assembler "mov\[^\n\r]*117835012" { target ia32 } } } */ +/* { dg-final { scan-assembler "mov\[^\n\r]*100925952" { target ia32 } } } */ +/* { dg-final { scan-assembler "mov\[^\n\r]*117768961" { target ia32 } } } */ + +void foo (char *); + +void +bar (void) +{ + char a[] = {0,1,2,3,4,5,6,7}; + foo (a); +} + +void +baz (void) +{ + char a[8] = "\0\2\4\6\1\3\5\7"; + foo (a); +} -- 2.30.2