diff --git a/gcc/testsuite/c-c++-common/torture/pr117912-1.c b/gcc/testsuite/c-c++-common/torture/pr117912-1.c new file mode 100644 index 0000000000000000000000000000000000000000..2750585c7f77a5b88e3e697132c5466c521c9d23 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/pr117912-1.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ + +struct S { int a; int b[24]; int c[24]; int d; }; +volatile int *p; + +void __attribute__((noipa)) +bar (int *q) +{ + p = q; +} + +__SIZE_TYPE__ __attribute__((noipa)) +foo (struct S *p) +{ + bar (&p->b[24]); + bar (&p->c[0]); + return __builtin_object_size (&p->c[0], 1); +} + +int +main() +{ + struct S s; + __SIZE_TYPE__ x = foo (&s); + if (x < sizeof (int) * 24) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/torture/pr117912-2.c b/gcc/testsuite/c-c++-common/torture/pr117912-2.c new file mode 100644 index 0000000000000000000000000000000000000000..a3a6215756351ba97649292f404d4f441aa07d52 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/pr117912-2.c @@ -0,0 +1,28 @@ +/* { dg-do run } */ + +struct S { int a; int b[0]; int c[24]; int d; }; +volatile int *p; + +void __attribute__((noipa)) +bar (int *q) +{ + p = q; +} + +__SIZE_TYPE__ __attribute__((noipa)) +foo (struct S *p) +{ + bar (&p->b[0]); + bar (&p->c[0]); + return __builtin_object_size (&p->c[0], 1); +} + +int +main() +{ + struct S s; + __SIZE_TYPE__ x = foo (&s); + if (x < sizeof (int) * 24) + __builtin_abort (); + return 0; +} diff --git a/gcc/testsuite/c-c++-common/torture/pr117912-3.c b/gcc/testsuite/c-c++-common/torture/pr117912-3.c new file mode 100644 index 0000000000000000000000000000000000000000..64e981d2a5e7c16ab79bcaeae8436d162e261b33 --- /dev/null +++ b/gcc/testsuite/c-c++-common/torture/pr117912-3.c @@ -0,0 +1,61 @@ +/* { dg-do run } */ +/* { dg-additional-options "-std=gnu++20" { target c++ } } */ + +struct B {}; +struct A { int a; +#ifdef __cplusplus + [[no_unique_address]] +#endif + struct B b; + char c[]; }; +volatile void *p; + +void __attribute__((noipa)) +bar (void *q) +{ + p = q; +} + +__SIZE_TYPE__ __attribute__((noipa)) +foo (struct A *p) +{ + bar (&p->b); + bar (&p->c); + return __builtin_object_size (&p->c, 1); +} + +__SIZE_TYPE__ __attribute__((noipa)) +baz (void) +{ + struct A *p = (struct A *) __builtin_malloc (__builtin_offsetof (struct A, c) + 64); + bar (&p->b); + bar (&p->c); + return __builtin_object_size (&p->c, 1); +} + +__SIZE_TYPE__ __attribute__((noipa)) +qux (struct A *p) +{ + bar (&p->b); + bar (&p->c); + return __builtin_object_size (&p->c, 3); +} + +__SIZE_TYPE__ __attribute__((noipa)) +boo (void) +{ + struct A *p = (struct A *) __builtin_malloc (__builtin_offsetof (struct A, c) + 64); + bar (&p->b); + bar (&p->c); + return __builtin_object_size (&p->c, 3); +} + +int +main () +{ + static struct A a = { .a = 1, .b = {}, .c = { 1, 2, 3, 4, 0 } }; + if (foo (&a) < 5) + __builtin_abort (); + if (baz () < 64) + __builtin_abort (); +} diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc index 8d74731a891cfb76c4b794b92aeae012fec1d632..48819f559c51dd88d87c0180d5ee7fd34e50e6a3 100644 --- a/gcc/tree-ssa-sccvn.cc +++ b/gcc/tree-ssa-sccvn.cc @@ -985,11 +985,14 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result) poly_offset_int off = (wi::to_poly_offset (this_offset) + (wi::to_offset (bit_offset) >> LOG2_BITS_PER_UNIT)); - /* Probibit value-numbering zero offset components + /* Prohibit value-numbering zero offset components of addresses the same before the pass folding - __builtin_object_size had a chance to run. */ + __builtin_object_size had a chance to run. Likewise + for components of zero size at arbitrary offset. */ if (TREE_CODE (orig) != ADDR_EXPR - || maybe_ne (off, 0) + || (TYPE_SIZE (temp.type) + && integer_nonzerop (TYPE_SIZE (temp.type)) + && maybe_ne (off, 0)) || (cfun->curr_properties & PROP_objsz)) off.to_shwi (&temp.off); } @@ -1010,9 +1013,31 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result) if (! temp.op2) temp.op2 = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (eltype), size_int (TYPE_ALIGN_UNIT (eltype))); + /* Prohibit value-numbering addresses of one-after-the-last + element ARRAY_REFs the same as addresses of other components + before the pass folding __builtin_object_size had a chance + to run. */ + bool avoid_oob = true; + if (TREE_CODE (orig) != ADDR_EXPR + || cfun->curr_properties & PROP_objsz) + avoid_oob = false; + else if (poly_int_tree_p (temp.op0)) + { + tree ub = array_ref_up_bound (ref); + if (ub + && poly_int_tree_p (ub) + /* ??? The C frontend for T[0] uses [0:] and the + C++ frontend [0:-1U]. See layout_type for how + awkward this is. */ + && !integer_minus_onep (ub) + && known_le (wi::to_poly_offset (temp.op0), + wi::to_poly_offset (ub))) + avoid_oob = false; + } if (poly_int_tree_p (temp.op0) && poly_int_tree_p (temp.op1) - && TREE_CODE (temp.op2) == INTEGER_CST) + && TREE_CODE (temp.op2) == INTEGER_CST + && !avoid_oob) { poly_offset_int off = ((wi::to_poly_offset (temp.op0) - wi::to_poly_offset (temp.op1)) @@ -1754,6 +1779,24 @@ re_valueize: && poly_int_tree_p (vro->op1) && TREE_CODE (vro->op2) == INTEGER_CST) { + /* Prohibit value-numbering addresses of one-after-the-last + element ARRAY_REFs the same as addresses of other components + before the pass folding __builtin_object_size had a chance + to run. */ + if (!(cfun->curr_properties & PROP_objsz) + && (*orig)[0].opcode == ADDR_EXPR) + { + tree dom = TYPE_DOMAIN ((*orig)[i + 1].type); + if (!dom + || !TYPE_MAX_VALUE (dom) + || !poly_int_tree_p (TYPE_MAX_VALUE (dom)) + || integer_minus_onep (TYPE_MAX_VALUE (dom))) + continue; + if (!known_le (wi::to_poly_offset (vro->op0), + wi::to_poly_offset (TYPE_MAX_VALUE (dom)))) + continue; + } + poly_offset_int off = ((wi::to_poly_offset (vro->op0) - wi::to_poly_offset (vro->op1)) * wi::to_offset (vro->op2)