aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.cc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2024-11-28 11:18:07 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2024-11-28 11:38:08 +0100
commit0547dbb725b6d8e878a79e28a2e171eafcfbc1aa (patch)
tree6426997152f77426ee77150dc69eac7c02ca912f /gcc/gimple-fold.cc
parent1b3bff737b2d5a7dc0d5977b77200c785fc53f01 (diff)
downloadgcc-0547dbb725b6d8e878a79e28a2e171eafcfbc1aa.zip
gcc-0547dbb725b6d8e878a79e28a2e171eafcfbc1aa.tar.gz
gcc-0547dbb725b6d8e878a79e28a2e171eafcfbc1aa.tar.bz2
expr, c: Don't clear whole unions [PR116416]
As discussed earlier, we currently clear padding bits even when we don't have to and that causes pessimization of emitted code, e.g. for union U { int a; long b[64]; }; void bar (union U *); void foo (void) { union U u = { 0 }; bar (&u); } we need to clear just u.a, not the whole union, but on the other side in cases where the standard requires padding bits to be zeroed, like for C23 {} initializers of aggregates with padding bits, or for C++11 zero initialization we don't do that. This patch a) moves some of the stuff into complete_ctor_at_level_p (but not all the *p_complete = 0; case, for that it would need to change so that it passes around the ctor rather than just its type) and changes the handling of unions b) introduces a new option, so that users can either get the new behavior (only what is guaranteed by the standards, the default), or previous behavior (union padding zero initialization, no such guarantees in structures) or also a guarantee in structures c) introduces a new CONSTRUCTOR flag which says that the padding bits (if any) should be zero initialized (and sets it for now in the C FE for C23 {} initializers). Am not sure the CONSTRUCTOR_ZERO_PADDING_BITS flag is really needed for C23, if there is just empty initializer, I think we already mark it as incomplete if there are any missing initializers. Maybe with some designated initializer games, say void foo () { struct S { char a; long long b; }; struct T { struct S c; } t = { .c = {}, .c.a = 1, .c.b = 2 }; ... } Is this supposed to initialize padding bits in C23 and then the .c.a = 1 and .c.b = 2 stores preserve those padding bits, so is that supposed to be different from struct T t2 = { .c = { 1, 2 } }; ? What about just struct T t3 = { .c.a = 1, .c.b = 2 }; ? And I haven't touched the C++ FE for the flag, because I'm afraid I'm lost on where exactly is zero-initialization done (vs. other types of initialization) and where is e.g. zero-initialization of a temporary then (member-wise) copied. Say struct S { char a; long long b; }; struct T { constexpr T (int a, int b) : c () { c.a = a; c.b = b; } S c; }; void bar (T *); void foo () { T t (1, 2); bar (&t); } Is the c () value-initialization of t.c followed by c.a and c.b updates which preserve the zero initialized padding bits? Or is there some copy construction involved which does member-wise copying and makes the padding bits undefined? Looking at (older) clang++ with -O2, it initializes also the padding bits when c () is used and doesn't with c {}. For GCC, note that there is that optimization from Alex to zero padding bits for optimization purposes for small aggregates, so either one needs to look at -O0 -fdump-tree-gimple dumps, or use larger structures which aren't optimized that way. 2024-11-28 Jakub Jelinek <jakub@redhat.com> PR c++/116416 gcc/ * flag-types.h (enum zero_init_padding_bits_kind): New type. * tree.h (CONSTRUCTOR_ZERO_PADDING_BITS): Define. * common.opt (fzero-init-padding-bits=): New option. * expr.cc (categorize_ctor_elements_1): Handle CONSTRUCTOR_ZERO_PADDING_BITS or flag_zero_init_padding_bits == ZERO_INIT_PADDING_BITS_ALL. Fix up *p_complete = -1; setting for unions. (complete_ctor_at_level_p): Handle unions differently for flag_zero_init_padding_bits == ZERO_INIT_PADDING_BITS_STANDARD. * gimple-fold.cc (type_has_padding_at_level_p): Fix up UNION_TYPE handling, return also true for UNION_TYPE with no FIELD_DECLs and non-zero size, handle QUAL_UNION_TYPE like UNION_TYPE. * doc/invoke.texi (-fzero-init-padding-bits=@var{value}): Document. gcc/c/ * c-parser.cc (c_parser_braced_init): Set CONSTRUCTOR_ZERO_PADDING_BITS for flag_isoc23 empty initializers. * c-typeck.cc (constructor_zero_padding_bits): New variable. (struct constructor_stack): Add zero_padding_bits member. (really_start_incremental_init): Save and clear constructor_zero_padding_bits. (push_init_level): Save constructor_zero_padding_bits. Or into it CONSTRUCTOR_ZERO_PADDING_BITS from previous value if implicit. (pop_init_level): Set CONSTRUCTOR_ZERO_PADDING_BITS if constructor_zero_padding_bits and restore constructor_zero_padding_bits. gcc/testsuite/ * gcc.dg/plugin/infoleak-1.c (test_union_2b, test_union_4b): Expect diagnostics. * gcc.dg/c23-empty-init-5.c: New test. * gcc.dg/gnu11-empty-init-1.c: New test. * gcc.dg/gnu11-empty-init-2.c: New test. * gcc.dg/gnu11-empty-init-3.c: New test. * gcc.dg/gnu11-empty-init-4.c: New test.
Diffstat (limited to 'gcc/gimple-fold.cc')
-rw-r--r--gcc/gimple-fold.cc18
1 files changed, 14 insertions, 4 deletions
diff --git a/gcc/gimple-fold.cc b/gcc/gimple-fold.cc
index 3911237..e857446 100644
--- a/gcc/gimple-fold.cc
+++ b/gcc/gimple-fold.cc
@@ -4858,12 +4858,22 @@ type_has_padding_at_level_p (tree type)
return false;
}
case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ bool any_fields;
+ any_fields = false;
/* If any of the fields is smaller than the whole, there is padding. */
for (tree f = TYPE_FIELDS (type); f; f = DECL_CHAIN (f))
- if (TREE_CODE (f) == FIELD_DECL)
- if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (f)),
- TREE_TYPE (type)) != 1)
- return true;
+ if (TREE_CODE (f) != FIELD_DECL)
+ continue;
+ else if (simple_cst_equal (TYPE_SIZE (TREE_TYPE (f)),
+ TYPE_SIZE (type)) != 1)
+ return true;
+ else
+ any_fields = true;
+ /* If the union doesn't have any fields and still has non-zero size,
+ all of it is padding. */
+ if (!any_fields && !integer_zerop (TYPE_SIZE (type)))
+ return true;
return false;
case ARRAY_TYPE:
case COMPLEX_TYPE: