From a4aca1edaf37d43b2b7e9111825837a7a317b1b0 Mon Sep 17 00:00:00 2001 From: Hans-Peter Nilsson Date: Sun, 5 Jul 2020 20:50:52 +0200 Subject: PR94600: fix volatile access to the whole of a compound object. The store to the whole of each volatile object was picked apart like there had been an individual assignment to each of the fields. Reads were added as part of that; see PR for details. The reads from volatile memory were a clear bug; individual stores questionable. A separate patch clarifies the docs. gcc: 2020-07-09 Richard Biener PR middle-end/94600 * expr.c (expand_constructor): Make a temporary also if we're storing to volatile memory. gcc/testsuite: 2020-07-09 Hans-Peter Nilsson PR middle-end/94600 * gcc.dg/pr94600-1.c, gcc.dg/pr94600-2.c, gcc.dg/pr94600-3.c, gcc.dg/pr94600-4.c, gcc.dg/pr94600-5.c, gcc.dg/pr94600-6.c, gcc.dg/pr94600-7.c, gcc.dg/pr94600-8.c: New tests. --- gcc/expr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index c7c3e9f..3d205ad 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8379,7 +8379,10 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier, /* Handle calls that pass values in multiple non-contiguous locations. The Irix 6 ABI has examples of this. */ if (target == 0 || ! safe_from_p (target, exp, 1) - || GET_CODE (target) == PARALLEL || modifier == EXPAND_STACK_PARM) + || GET_CODE (target) == PARALLEL || modifier == EXPAND_STACK_PARM + /* Also make a temporary if the store is to volatile memory, to + avoid individual accesses to aggregate members. */ + || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))) { if (avoid_temp_mem) return NULL_RTX; -- cgit v1.1 From b1d389d60d1929c7528ef984925ea010e3bf2c1a Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 14 Jul 2020 16:01:11 +0200 Subject: expr: Unbreak build of mesa [PR96194] > > The store to the whole of each volatile object was picked apart > > like there had been an individual assignment to each of the > > fields. Reads were added as part of that; see PR for details. > > The reads from volatile memory were a clear bug; individual > > stores questionable. A separate patch clarifies the docs. This breaks building of mesa on both the trunk and 10 branch. The problem is that the middle-end may never create temporaries of non-POD (TREE_ADDRESSABLE) types, those can be only created when the language says so and thus only the FE is allowed to create those. This patch just reverts the behavior to what we used to do before for the stores to volatile non-PODs. Perhaps we want to do something else, but definitely we can't create temporaries of the non-POD type. It is up to discussions on what should happen in those cases. 2020-07-14 Jakub Jelinek PR middle-end/96194 * expr.c (expand_constructor): Don't create temporary for store to volatile MEM if exp has an addressable type. * g++.dg/opt/pr96194.C: New test. --- gcc/expr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index 3d205ad..edc5571 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8382,7 +8382,9 @@ expand_constructor (tree exp, rtx target, enum expand_modifier modifier, || GET_CODE (target) == PARALLEL || modifier == EXPAND_STACK_PARM /* Also make a temporary if the store is to volatile memory, to avoid individual accesses to aggregate members. */ - || (GET_CODE (target) == MEM && MEM_VOLATILE_P (target))) + || (GET_CODE (target) == MEM + && MEM_VOLATILE_P (target) + && !TREE_ADDRESSABLE (TREE_TYPE (exp)))) { if (avoid_temp_mem) return NULL_RTX; -- cgit v1.1 From d5803b9876b3d11c93d1a10fabb3fbb1c4a14bd6 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Mon, 20 Jul 2020 12:06:18 -0600 Subject: Correct handling of constant representations containing embedded nuls. Resolves: PR middle-end/95189 - memcmp being wrongly stripped like strcm PR middle-end/95886 - suboptimal memcpy with embedded zero bytes gcc/ChangeLog: PR middle-end/95189 PR middle-end/95886 * builtins.c (inline_expand_builtin_string_cmp): Rename... (inline_expand_builtin_bytecmp): ...to this. (builtin_memcpy_read_str): Don't expect data to be nul-terminated. (expand_builtin_memory_copy_args): Handle object representations with embedded nul bytes. (expand_builtin_memcmp): Same. (expand_builtin_strcmp): Adjust call to naming change. (expand_builtin_strncmp): Same. * expr.c (string_constant): Create empty strings with nonzero size. * fold-const.c (c_getstr): Rename locals and update comments. * tree.c (build_string): Accept null pointer argument. (build_string_literal): Same. * tree.h (build_string): Provide a default. (build_string_literal): Same. gcc/testsuite/ChangeLog: PR middle-end/95189 PR middle-end/95886 * gcc.dg/memcmp-pr95189.c: New test. * gcc.dg/strncmp-3.c: New test. * gcc.target/i386/memcpy-pr95886.c: New test. --- gcc/expr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index edc5571..b4bbeff 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11829,12 +11829,12 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) while (TREE_CODE (chartype) == ARRAY_TYPE) chartype = TREE_TYPE (chartype); /* Convert a char array to an empty STRING_CST having an array - of the expected type. */ + of the expected type and size. */ if (!initsize) initsize = integer_zero_node; unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize); - init = build_string_literal (size ? 1 : 0, "", chartype, size); + init = build_string_literal (size, NULL, chartype, size); init = TREE_OPERAND (init, 0); init = TREE_OPERAND (init, 0); -- cgit v1.1 From 4821e0aabee57d5b7f955f138a8bee4588240609 Mon Sep 17 00:00:00 2001 From: Jozef Lawrynowicz Date: Wed, 22 Jul 2020 12:34:30 +0100 Subject: expr: Allow scalar_int_mode target mode when converting a constant is_int_mode does not allow MODE_PARTIAL_INT modes, so convert_modes was not allowing a constant value to be converted to a MODE_PARTIAL_INT for use as operand 2 in patterns such as ashlpsi3. The constant had to be copied into a register before it could be used, but now can be used directly as an operand without any copying. gcc/ChangeLog: * expr.c (convert_modes): Allow a constant integer to be converted to any scalar int mode. --- gcc/expr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index b4bbeff..5db0a7a 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -696,12 +696,12 @@ convert_modes (machine_mode mode, machine_mode oldmode, rtx x, int unsignedp) return x; if (CONST_SCALAR_INT_P (x) - && is_int_mode (mode, &int_mode)) + && is_a (mode, &int_mode)) { /* If the caller did not tell us the old mode, then there is not much to do with respect to canonicalization. We have to assume that all the bits are significant. */ - if (GET_MODE_CLASS (oldmode) != MODE_INT) + if (!is_a (oldmode)) oldmode = MAX_MODE_INT; wide_int w = wide_int::from (rtx_mode_t (x, oldmode), GET_MODE_PRECISION (int_mode), -- cgit v1.1 From 7355a9408b990cdd20db91e2e1ba0b03e801d6a6 Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 27 Jul 2020 12:30:24 +0200 Subject: expr: build string_constant only for a char type gcc/ChangeLog: PR tree-optimization/96058 * expr.c (string_constant): Build string_constant only for a type that has same precision as char_type_node and is an integral type. --- gcc/expr.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index 5db0a7a..a150fa0 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11828,17 +11828,22 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) chartype = TREE_TYPE (chartype); while (TREE_CODE (chartype) == ARRAY_TYPE) chartype = TREE_TYPE (chartype); - /* Convert a char array to an empty STRING_CST having an array - of the expected type and size. */ - if (!initsize) - initsize = integer_zero_node; - unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize); - init = build_string_literal (size, NULL, chartype, size); - init = TREE_OPERAND (init, 0); - init = TREE_OPERAND (init, 0); + if (INTEGRAL_TYPE_P (chartype) + && TYPE_PRECISION (chartype) == TYPE_PRECISION (char_type_node)) + { + /* Convert a char array to an empty STRING_CST having an array + of the expected type and size. */ + if (!initsize) + initsize = integer_zero_node; + + unsigned HOST_WIDE_INT size = tree_to_uhwi (initsize); + init = build_string_literal (size, NULL, chartype, size); + init = TREE_OPERAND (init, 0); + init = TREE_OPERAND (init, 0); - *ptr_offset = integer_zero_node; + *ptr_offset = integer_zero_node; + } } if (decl) -- cgit v1.1 From 287522613d661b4c5ba8403b051eb470c1674cba Mon Sep 17 00:00:00 2001 From: Marc Glisse Date: Mon, 10 Aug 2020 12:50:42 +0200 Subject: Simplify X * C1 == C2 with wrapping overflow Odd numbers are invertible in Z / 2^n Z, so X * C1 == C2 can be rewritten as X == C2 * inv(C1) when overflow wraps. mod_inv should probably be updated to better match the other wide_int functions, but that's a separate issue. 2020-08-10 Marc Glisse PR tree-optimization/95433 * match.pd (X * C1 == C2): Handle wrapping overflow. * expr.c (maybe_optimize_mod_cmp): Qualify call to mod_inv. (mod_inv): Move... * wide-int.cc (mod_inv): ... here. * wide-int.h (mod_inv): Declare it. * gcc.dg/tree-ssa/pr95433-2.c: New file. --- gcc/expr.c | 34 +--------------------------------- 1 file changed, 1 insertion(+), 33 deletions(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index a150fa0..ebf0c9e 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11859,38 +11859,6 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) return init; } -/* Compute the modular multiplicative inverse of A modulo M - using extended Euclid's algorithm. Assumes A and M are coprime. */ -static wide_int -mod_inv (const wide_int &a, const wide_int &b) -{ - /* Verify the assumption. */ - gcc_checking_assert (wi::eq_p (wi::gcd (a, b), 1)); - - unsigned int p = a.get_precision () + 1; - gcc_checking_assert (b.get_precision () + 1 == p); - wide_int c = wide_int::from (a, p, UNSIGNED); - wide_int d = wide_int::from (b, p, UNSIGNED); - wide_int x0 = wide_int::from (0, p, UNSIGNED); - wide_int x1 = wide_int::from (1, p, UNSIGNED); - - if (wi::eq_p (b, 1)) - return wide_int::from (1, p, UNSIGNED); - - while (wi::gt_p (c, 1, UNSIGNED)) - { - wide_int t = d; - wide_int q = wi::divmod_trunc (c, d, UNSIGNED, &d); - c = t; - wide_int s = x0; - x0 = wi::sub (x1, wi::mul (q, x0)); - x1 = s; - } - if (wi::lt_p (x1, 0, SIGNED)) - x1 += d; - return x1; -} - /* Optimize x % C1 == C2 for signed modulo if C1 is a power of two and C2 is non-zero and C3 ((1<<(prec-1)) | (C1 - 1)): for C2 > 0 to x & C3 == C2 @@ -12101,7 +12069,7 @@ maybe_optimize_mod_cmp (enum tree_code code, tree *arg0, tree *arg1) w = wi::lrshift (w, shift); wide_int a = wide_int::from (w, prec + 1, UNSIGNED); wide_int b = wi::shifted_mask (prec, 1, false, prec + 1); - wide_int m = wide_int::from (mod_inv (a, b), prec, UNSIGNED); + wide_int m = wide_int::from (wi::mod_inv (a, b), prec, UNSIGNED); tree c3 = wide_int_to_tree (type, m); tree c5 = NULL_TREE; wide_int d, e; -- cgit v1.1 From 299c98578bda88c020a6d5b2c319c9e191a315d4 Mon Sep 17 00:00:00 2001 From: Jakub Jelinek Date: Tue, 11 Aug 2020 13:47:29 +0200 Subject: expr: Optimize noop copies [PR96539] At GIMPLE e.g. for __builtin_memmove we optimize away (to just the return value) noop copies where src == dest, but at the RTL we don't, and as the testcase shows, in some cases such copies can appear only at the RTL level e.g. from trying to copy an aggregate by value argument to the same location as it already has. If the block move is expanded e.g. piecewise, we actually manage to optimize it away, as the individual memory copies are seen as noop moves, but if the target optabs are used, often the sequences stay until final. 2020-08-11 Jakub Jelinek PR rtl-optimization/96539 * expr.c (emit_block_move_hints): Don't copy anything if x and y are the same and neither is MEM_VOLATILE_P. * gcc.target/i386/pr96539.c: New test. --- gcc/expr.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index ebf0c9e..2406f90 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -1637,6 +1637,12 @@ emit_block_move_hints (rtx x, rtx y, rtx size, enum block_op_methods method, x = adjust_address (x, BLKmode, 0); y = adjust_address (y, BLKmode, 0); + /* If source and destination are the same, no need to copy anything. */ + if (rtx_equal_p (x, y) + && !MEM_VOLATILE_P (x) + && !MEM_VOLATILE_P (y)) + return 0; + /* Set MEM_SIZE as appropriate for this block copy. The main place this can be incorrect is coming from __builtin_memcpy. */ poly_int64 const_size; -- cgit v1.1 From 866626efd749ed3e2b7014e88e4340b5a4c73560 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Fri, 14 Aug 2020 17:11:53 -0600 Subject: PR tree-optimization/78257 - missing memcmp optimization with constant arrays gcc/ChangeLog: PR middle-end/78257 * builtins.c (expand_builtin_memory_copy_args): Rename called function. (expand_builtin_stpcpy_1): Remove argument from call. (expand_builtin_memcmp): Rename called function. (inline_expand_builtin_bytecmp): Same. * expr.c (convert_to_bytes): New function. (constant_byte_string): New function (formerly string_constant). (string_constant): Call constant_byte_string. (byte_representation): New function. * expr.h (byte_representation): Declare. * fold-const-call.c (fold_const_call): Rename called function. * fold-const.c (c_getstr): Remove an argument. (getbyterep): Define a new function. * fold-const.h (c_getstr): Remove an argument. (getbyterep): Declare a new function. * gimple-fold.c (gimple_fold_builtin_memory_op): Rename callee. (gimple_fold_builtin_string_compare): Same. (gimple_fold_builtin_memchr): Same. gcc/testsuite/ChangeLog: PR middle-end/78257 * gcc.dg/memchr.c: New test. * gcc.dg/memcmp-2.c: New test. * gcc.dg/memcmp-3.c: New test. * gcc.dg/memcmp-4.c: New test. --- gcc/expr.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 162 insertions(+), 18 deletions(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index 2406f90..dd2200d 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11600,15 +11600,112 @@ is_aligning_offset (const_tree offset, const_tree exp) /* This must now be the address of EXP. */ return TREE_CODE (offset) == ADDR_EXPR && TREE_OPERAND (offset, 0) == exp; } - -/* Return the tree node if an ARG corresponds to a string constant or zero - if it doesn't. If we return nonzero, set *PTR_OFFSET to the (possibly - non-constant) offset in bytes within the string that ARG is accessing. - If MEM_SIZE is non-zero the storage size of the memory is returned. - If DECL is non-zero the constant declaration is returned if available. */ -tree -string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) +/* If EXPR is a constant initializer (either an expression or CONSTRUCTOR), + attempt to obtain its native representation as an array of nonzero BYTES. + Return true on success and false on failure (the latter without modifying + BYTES). */ + +static bool +convert_to_bytes (tree type, tree expr, vec *bytes) +{ + if (TREE_CODE (expr) == CONSTRUCTOR) + { + /* Set to the size of the CONSTRUCTOR elements. */ + unsigned HOST_WIDE_INT ctor_size = bytes->length (); + + if (TREE_CODE (type) == ARRAY_TYPE) + { + tree val, idx; + tree eltype = TREE_TYPE (type); + unsigned HOST_WIDE_INT elsize = + tree_to_uhwi (TYPE_SIZE_UNIT (eltype)); + + /* Jump through hoops to determine the lower bound for languages + like Ada that can set it to an (almost) arbitrary value. */ + tree dom = TYPE_DOMAIN (type); + if (!dom) + return false; + tree min = TYPE_MIN_VALUE (dom); + if (!min || !tree_fits_uhwi_p (min)) + return false; + unsigned HOST_WIDE_INT i, last_idx = tree_to_uhwi (min) - 1; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, idx, val) + { + /* Append zeros for elements with no initializers. */ + if (!tree_fits_uhwi_p (idx)) + return false; + unsigned HOST_WIDE_INT cur_idx = tree_to_uhwi (idx); + if (unsigned HOST_WIDE_INT size = cur_idx - (last_idx + 1)) + { + size = size * elsize + bytes->length (); + bytes->safe_grow_cleared (size); + } + + if (!convert_to_bytes (eltype, val, bytes)) + return false; + + last_idx = cur_idx; + } + } + else if (TREE_CODE (type) == RECORD_TYPE) + { + tree val, fld; + unsigned HOST_WIDE_INT i; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (expr), i, fld, val) + { + /* Append zeros for members with no initializers and + any padding. */ + unsigned HOST_WIDE_INT cur_off = int_byte_position (fld); + if (bytes->length () < cur_off) + bytes->safe_grow_cleared (cur_off); + + if (!convert_to_bytes (TREE_TYPE (val), val, bytes)) + return false; + } + } + else + return false; + + /* Compute the size of the COSNTRUCTOR elements. */ + ctor_size = bytes->length () - ctor_size; + + /* Append zeros to the byte vector to the full size of the type. + The type size can be less than the size of the CONSTRUCTOR + if the latter contains initializers for a flexible array + member. */ + tree size = TYPE_SIZE_UNIT (type); + unsigned HOST_WIDE_INT type_size = tree_to_uhwi (size); + if (ctor_size < type_size) + if (unsigned HOST_WIDE_INT size_grow = type_size - ctor_size) + bytes->safe_grow_cleared (bytes->length () + size_grow); + + return true; + } + + unsigned char charbuf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT]; + int len = native_encode_expr (expr, charbuf, sizeof charbuf, 0); + if (len <= 0) + return false; + + unsigned n = bytes->length (); + bytes->safe_grow (n + len); + unsigned char *p = bytes->address (); + memcpy (p + n, charbuf, len); + return true; +} + +/* Return a STRING_CST corresponding to ARG's constant initializer either + if it's a string constant, or, when VALREP is set, any other constant, + or null otherwise. + On success, set *PTR_OFFSET to the (possibly non-constant) byte offset + within the byte string that ARG is references. If nonnull set *MEM_SIZE + to the size of the byte string. If nonnull, set *DECL to the constant + declaration ARG refers to. */ + +static tree +constant_byte_string (tree arg, tree *ptr_offset, tree *mem_size, tree *decl, + bool valrep = false) { tree dummy = NULL_TREE;; if (!mem_size) @@ -11755,18 +11852,43 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) return array; } - if (!VAR_P (array) && TREE_CODE (array) != CONST_DECL) - return NULL_TREE; - tree init = ctor_for_folding (array); - - /* Handle variables initialized with string literals. */ if (!init || init == error_mark_node) return NULL_TREE; + + if (valrep) + { + HOST_WIDE_INT cstoff; + if (!base_off.is_constant (&cstoff)) + return NULL_TREE; + + /* If value representation was requested convert the initializer + for the whole array or object into a string of bytes forming + its value representation and return it. */ + auto_vec bytes; + if (!convert_to_bytes (TREE_TYPE (init), init, &bytes)) + return NULL_TREE; + + unsigned n = bytes.length (); + const char *p = reinterpret_cast(bytes.address ()); + init = build_string_literal (n, p, char_type_node); + init = TREE_OPERAND (init, 0); + init = TREE_OPERAND (init, 0); + + *mem_size = size_int (TREE_STRING_LENGTH (init)); + *ptr_offset = wide_int_to_tree (ssizetype, base_off); + + if (decl) + *decl = array; + + return init; + } + if (TREE_CODE (init) == CONSTRUCTOR) { /* Convert the 64-bit constant offset to a wider type to avoid - overflow. */ + overflow and use it to obtain the initializer for the subobject + it points into. */ offset_int wioff; if (!base_off.is_constant (&wioff)) return NULL_TREE; @@ -11779,6 +11901,9 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) unsigned HOST_WIDE_INT fieldoff = 0; init = fold_ctor_reference (TREE_TYPE (arg), init, base_off, 0, array, &fieldoff); + if (!init || init == error_mark_node) + return NULL_TREE; + HOST_WIDE_INT cstoff; if (!base_off.is_constant (&cstoff)) return NULL_TREE; @@ -11791,9 +11916,6 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) offset = off; } - if (!init) - return NULL_TREE; - *ptr_offset = offset; tree inittype = TREE_TYPE (init); @@ -11864,7 +11986,29 @@ string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) return init; } - + +/* Return STRING_CST if an ARG corresponds to a string constant or zero + if it doesn't. If we return nonzero, set *PTR_OFFSET to the (possibly + non-constant) offset in bytes within the string that ARG is accessing. + If MEM_SIZE is non-zero the storage size of the memory is returned. + If DECL is non-zero the constant declaration is returned if available. */ + +tree +string_constant (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) +{ + return constant_byte_string (arg, ptr_offset, mem_size, decl, false); +} + +/* Similar to string_constant, return a STRING_CST corresponding + to the value representation of the first argument if it's + a constant. */ + +tree +byte_representation (tree arg, tree *ptr_offset, tree *mem_size, tree *decl) +{ + return constant_byte_string (arg, ptr_offset, mem_size, decl, true); +} + /* Optimize x % C1 == C2 for signed modulo if C1 is a power of two and C2 is non-zero and C3 ((1<<(prec-1)) | (C1 - 1)): for C2 > 0 to x & C3 == C2 -- cgit v1.1 From d367f5fcb579d21c3093cf5c464f5787fe584a1d Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Tue, 18 Aug 2020 12:57:18 -0600 Subject: PR middle-end/96665 - memcmp of a constant string not folded Related: PR middle-end/78257 - missing memcmp optimization with constant arrays gcc/ChangeLog: PR middle-end/96665 PR middle-end/78257 * expr.c (convert_to_bytes): Replace statically allocated buffer with a dynamically allocated one of sufficient size. gcc/testsuite/ChangeLog: PR middle-end/96665 PR middle-end/78257 * gcc.dg/memcmp-5.c: New test. --- gcc/expr.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index dd2200d..437faea 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11683,16 +11683,27 @@ convert_to_bytes (tree type, tree expr, vec *bytes) return true; } - unsigned char charbuf[MAX_BITSIZE_MODE_ANY_MODE / BITS_PER_UNIT]; - int len = native_encode_expr (expr, charbuf, sizeof charbuf, 0); - if (len <= 0) + /* Except for RECORD_TYPE which may have an initialized flexible array + member, the size of a type is the same as the size of the initializer + (including any implicitly zeroed out members and padding). Allocate + just enough for that many bytes. */ + tree expr_size = TYPE_SIZE_UNIT (TREE_TYPE (expr)); + if (!expr_size || !tree_fits_uhwi_p (expr_size)) + return false; + const unsigned HOST_WIDE_INT expr_bytes = tree_to_uhwi (expr_size); + const unsigned bytes_sofar = bytes->length (); + /* native_encode_expr can convert at most INT_MAX bytes. vec is limited + to at most UINT_MAX. */ + if (bytes_sofar + expr_bytes > INT_MAX) return false; - unsigned n = bytes->length (); - bytes->safe_grow (n + len); - unsigned char *p = bytes->address (); - memcpy (p + n, charbuf, len); - return true; + /* Unlike for RECORD_TYPE, there is no need to clear the memory since + it's completely overwritten by native_encode_expr. */ + bytes->safe_grow (bytes_sofar + expr_bytes); + unsigned char *pnext = bytes->begin () + bytes_sofar; + int nbytes = native_encode_expr (expr, pnext, expr_bytes, 0); + /* NBYTES is zero on failure. Otherwise it should equal EXPR_BYTES. */ + return (unsigned HOST_WIDE_INT) nbytes == expr_bytes; } /* Return a STRING_CST corresponding to ARG's constant initializer either -- cgit v1.1 From cb3874dcf82bc80c2552ef62f57cf08c28fc686a Mon Sep 17 00:00:00 2001 From: Martin Liska Date: Mon, 10 Aug 2020 11:11:05 +0200 Subject: vec: add exact argument for various grow functions. gcc/ada/ChangeLog: * gcc-interface/trans.c (gigi): Set exact argument of a vector growth function to true. (Attribute_to_gnu): Likewise. gcc/ChangeLog: * alias.c (init_alias_analysis): Set exact argument of a vector growth function to true. * calls.c (internal_arg_pointer_based_exp_scan): Likewise. * cfgbuild.c (find_many_sub_basic_blocks): Likewise. * cfgexpand.c (expand_asm_stmt): Likewise. * cfgrtl.c (rtl_create_basic_block): Likewise. * combine.c (combine_split_insns): Likewise. (combine_instructions): Likewise. * config/aarch64/aarch64-sve-builtins.cc (function_expander::add_output_operand): Likewise. (function_expander::add_input_operand): Likewise. (function_expander::add_integer_operand): Likewise. (function_expander::add_address_operand): Likewise. (function_expander::add_fixed_operand): Likewise. * df-core.c (df_worklist_dataflow_doublequeue): Likewise. * dwarf2cfi.c (update_row_reg_save): Likewise. * early-remat.c (early_remat::init_block_info): Likewise. (early_remat::finalize_candidate_indices): Likewise. * except.c (sjlj_build_landing_pads): Likewise. * final.c (compute_alignments): Likewise. (grow_label_align): Likewise. * function.c (temp_slots_at_level): Likewise. * fwprop.c (build_single_def_use_links): Likewise. (update_uses): Likewise. * gcc.c (insert_wrapper): Likewise. * genautomata.c (create_state_ainsn_table): Likewise. (add_vect): Likewise. (output_dead_lock_vect): Likewise. * genmatch.c (capture_info::capture_info): Likewise. (parser::finish_match_operand): Likewise. * genrecog.c (optimize_subroutine_group): Likewise. (merge_pattern_info::merge_pattern_info): Likewise. (merge_into_decision): Likewise. (print_subroutine_start): Likewise. (main): Likewise. * gimple-loop-versioning.cc (loop_versioning::loop_versioning): Likewise. * gimple.c (gimple_set_bb): Likewise. * graphite-isl-ast-to-gimple.c (translate_isl_ast_node_user): Likewise. * haifa-sched.c (sched_extend_luids): Likewise. (extend_h_i_d): Likewise. * insn-addr.h (insn_addresses_new): Likewise. * ipa-cp.c (gather_context_independent_values): Likewise. (find_more_contexts_for_caller_subset): Likewise. * ipa-devirt.c (final_warning_record::grow_type_warnings): Likewise. (ipa_odr_read_section): Likewise. * ipa-fnsummary.c (evaluate_properties_for_edge): Likewise. (ipa_fn_summary_t::duplicate): Likewise. (analyze_function_body): Likewise. (ipa_merge_fn_summary_after_inlining): Likewise. (read_ipa_call_summary): Likewise. * ipa-icf.c (sem_function::bb_dict_test): Likewise. * ipa-prop.c (ipa_alloc_node_params): Likewise. (parm_bb_aa_status_for_bb): Likewise. (ipa_compute_jump_functions_for_edge): Likewise. (ipa_analyze_node): Likewise. (update_jump_functions_after_inlining): Likewise. (ipa_read_edge_info): Likewise. (read_ipcp_transformation_info): Likewise. (ipcp_transform_function): Likewise. * ipa-reference.c (ipa_reference_write_optimization_summary): Likewise. * ipa-split.c (execute_split_functions): Likewise. * ira.c (find_moveable_pseudos): Likewise. * lower-subreg.c (decompose_multiword_subregs): Likewise. * lto-streamer-in.c (input_eh_regions): Likewise. (input_cfg): Likewise. (input_struct_function_base): Likewise. (input_function): Likewise. * modulo-sched.c (set_node_sched_params): Likewise. (extend_node_sched_params): Likewise. (schedule_reg_moves): Likewise. * omp-general.c (omp_construct_simd_compare): Likewise. * passes.c (pass_manager::create_pass_tab): Likewise. (enable_disable_pass): Likewise. * predict.c (determine_unlikely_bbs): Likewise. * profile.c (compute_branch_probabilities): Likewise. * read-rtl-function.c (function_reader::parse_block): Likewise. * read-rtl.c (rtx_reader::read_rtx_code): Likewise. * reg-stack.c (stack_regs_mentioned): Likewise. * regrename.c (regrename_init): Likewise. * rtlanal.c (T>::add_single_to_queue): Likewise. * sched-deps.c (init_deps_data_vector): Likewise. * sel-sched-ir.c (sel_extend_global_bb_info): Likewise. (extend_region_bb_info): Likewise. (extend_insn_data): Likewise. * symtab.c (symtab_node::create_reference): Likewise. * tracer.c (tail_duplicate): Likewise. * trans-mem.c (tm_region_init): Likewise. (get_bb_regions_instrumented): Likewise. * tree-cfg.c (init_empty_tree_cfg_for_function): Likewise. (build_gimple_cfg): Likewise. (create_bb): Likewise. (move_block_to_fn): Likewise. * tree-complex.c (tree_lower_complex): Likewise. * tree-if-conv.c (predicate_rhs_code): Likewise. * tree-inline.c (copy_bb): Likewise. * tree-into-ssa.c (get_ssa_name_ann): Likewise. (mark_phi_for_rewrite): Likewise. * tree-object-size.c (compute_builtin_object_size): Likewise. (init_object_sizes): Likewise. * tree-predcom.c (initialize_root_vars_store_elim_1): Likewise. (initialize_root_vars_store_elim_2): Likewise. (prepare_initializers_chain_store_elim): Likewise. * tree-ssa-address.c (addr_for_mem_ref): Likewise. (multiplier_allowed_in_address_p): Likewise. * tree-ssa-coalesce.c (ssa_conflicts_new): Likewise. * tree-ssa-forwprop.c (simplify_vector_constructor): Likewise. * tree-ssa-loop-ivopts.c (addr_offset_valid_p): Likewise. (get_address_cost_ainc): Likewise. * tree-ssa-loop-niter.c (discover_iteration_bound_by_body_walk): Likewise. * tree-ssa-pre.c (add_to_value): Likewise. (phi_translate_1): Likewise. (do_pre_regular_insertion): Likewise. (do_pre_partial_partial_insertion): Likewise. (init_pre): Likewise. * tree-ssa-propagate.c (ssa_prop_init): Likewise. (update_call_from_tree): Likewise. * tree-ssa-reassoc.c (optimize_range_tests_cmp_bitwise): Likewise. * tree-ssa-sccvn.c (vn_reference_lookup_3): Likewise. (vn_reference_lookup_pieces): Likewise. (eliminate_dom_walker::eliminate_push_avail): Likewise. * tree-ssa-strlen.c (set_strinfo): Likewise. (get_stridx_plus_constant): Likewise. (zero_length_string): Likewise. (find_equal_ptrs): Likewise. (printf_strlen_execute): Likewise. * tree-ssa-threadedge.c (set_ssa_name_value): Likewise. * tree-ssanames.c (make_ssa_name_fn): Likewise. * tree-streamer-in.c (streamer_read_tree_bitfields): Likewise. * tree-vect-loop.c (vect_record_loop_mask): Likewise. (vect_get_loop_mask): Likewise. (vect_record_loop_len): Likewise. (vect_get_loop_len): Likewise. * tree-vect-patterns.c (vect_recog_mask_conversion_pattern): Likewise. * tree-vect-slp.c (vect_slp_convert_to_external): Likewise. (vect_bb_slp_scalar_cost): Likewise. (vect_bb_vectorization_profitable_p): Likewise. (vectorizable_slp_permutation): Likewise. * tree-vect-stmts.c (vectorizable_call): Likewise. (vectorizable_simd_clone_call): Likewise. (scan_store_can_perm_p): Likewise. (vectorizable_store): Likewise. * expr.c: Likewise. * vec.c (test_safe_grow_cleared): Likewise. * vec.h (vec_safe_grow): Likewise. (vec_safe_grow_cleared): Likewise. (vl_ptr>::safe_grow): Likewise. (vl_ptr>::safe_grow_cleared): Likewise. * config/c6x/c6x.c (insn_set_clock): Likewise. gcc/c/ChangeLog: * gimple-parser.c (c_parser_gimple_compound_statement): Set exact argument of a vector growth function to true. gcc/cp/ChangeLog: * class.c (build_vtbl_initializer): Set exact argument of a vector growth function to true. * constraint.cc (get_mapped_args): Likewise. * decl.c (cp_maybe_mangle_decomp): Likewise. (cp_finish_decomp): Likewise. * parser.c (cp_parser_omp_for_loop): Likewise. * pt.c (canonical_type_parameter): Likewise. * rtti.c (get_pseudo_ti_init): Likewise. gcc/fortran/ChangeLog: * trans-openmp.c (gfc_trans_omp_do): Set exact argument of a vector growth function to true. gcc/lto/ChangeLog: * lto-common.c (lto_file_finalize): Set exact argument of a vector growth function to true. --- gcc/expr.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index 437faea..1a15f24 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -11639,7 +11639,7 @@ convert_to_bytes (tree type, tree expr, vec *bytes) if (unsigned HOST_WIDE_INT size = cur_idx - (last_idx + 1)) { size = size * elsize + bytes->length (); - bytes->safe_grow_cleared (size); + bytes->safe_grow_cleared (size, true); } if (!convert_to_bytes (eltype, val, bytes)) @@ -11658,7 +11658,7 @@ convert_to_bytes (tree type, tree expr, vec *bytes) any padding. */ unsigned HOST_WIDE_INT cur_off = int_byte_position (fld); if (bytes->length () < cur_off) - bytes->safe_grow_cleared (cur_off); + bytes->safe_grow_cleared (cur_off, true); if (!convert_to_bytes (TREE_TYPE (val), val, bytes)) return false; @@ -11678,7 +11678,7 @@ convert_to_bytes (tree type, tree expr, vec *bytes) unsigned HOST_WIDE_INT type_size = tree_to_uhwi (size); if (ctor_size < type_size) if (unsigned HOST_WIDE_INT size_grow = type_size - ctor_size) - bytes->safe_grow_cleared (bytes->length () + size_grow); + bytes->safe_grow_cleared (bytes->length () + size_grow, true); return true; } @@ -11699,7 +11699,7 @@ convert_to_bytes (tree type, tree expr, vec *bytes) /* Unlike for RECORD_TYPE, there is no need to clear the memory since it's completely overwritten by native_encode_expr. */ - bytes->safe_grow (bytes_sofar + expr_bytes); + bytes->safe_grow (bytes_sofar + expr_bytes, true); unsigned char *pnext = bytes->begin () + bytes_sofar; int nbytes = native_encode_expr (expr, pnext, expr_bytes, 0); /* NBYTES is zero on failure. Otherwise it should equal EXPR_BYTES. */ -- cgit v1.1 From d16b5975ca985cbe97698479fc38b6a636886978 Mon Sep 17 00:00:00 2001 From: Richard Biener Date: Fri, 25 Sep 2020 11:13:13 +0200 Subject: middle-end/96814 - fix VECTOR_BOOLEAN_TYPE_P CTOR RTL expansion The RTL expansion code for CTORs doesn't handle VECTOR_BOOLEAN_TYPE_P with bit-precision elements correctly as the testcase shows before the PR97085 fix. The following makes it do the correct thing (not 100% sure for CTOR of sub-vectors due to the lack of a testcase). The alternative would be to assert such CTORs do not happen (and also add IL verification for this). The GIMPLE FE needs a way to declare the VECTOR_BOOLEAN_TYPE_P vectors (thus the C FE needs that). 2020-09-25 Richard Biener PR middle-end/96814 * expr.c (store_constructor): Handle VECTOR_BOOLEAN_TYPE_P CTORs correctly. * gcc.target/i386/pr96814.c: New testcase. --- gcc/expr.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'gcc/expr.c') diff --git a/gcc/expr.c b/gcc/expr.c index 1a15f24..1c79518 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -6922,7 +6922,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, insn_code icode = CODE_FOR_nothing; tree elt; tree elttype = TREE_TYPE (type); - int elt_size = tree_to_uhwi (TYPE_SIZE (elttype)); + int elt_size = vector_element_bits (type); machine_mode eltmode = TYPE_MODE (elttype); HOST_WIDE_INT bitsize; HOST_WIDE_INT bitpos; @@ -6987,6 +6987,15 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, } } + /* Compute the size of the elements in the CTOR. It differs + from the size of the vector type elements only when the + CTOR elements are vectors themselves. */ + tree val_type = TREE_TYPE (CONSTRUCTOR_ELT (exp, 0)->value); + if (VECTOR_TYPE_P (val_type)) + bitsize = tree_to_uhwi (TYPE_SIZE (val_type)); + else + bitsize = elt_size; + /* If the constructor has fewer elements than the vector, clear the whole array first. Similarly if this is static constructor of a non-BLKmode object. */ @@ -7001,11 +7010,7 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value) { - tree sz = TYPE_SIZE (TREE_TYPE (value)); - int n_elts_here - = tree_to_uhwi (int_const_binop (TRUNC_DIV_EXPR, sz, - TYPE_SIZE (elttype))); - + int n_elts_here = bitsize / elt_size; count += n_elts_here; if (mostly_zeros_p (value)) zero_count += n_elts_here; @@ -7045,7 +7050,6 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size, HOST_WIDE_INT eltpos; tree value = ce->value; - bitsize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (value))); if (cleared && initializer_zerop (value)) continue; -- cgit v1.1