--- /dev/null
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+#include "builtin-object-size-common.h"
+typedef __SIZE_TYPE__ size_t;
+#define NUM_MCAST_RATE 6
+
+#define MIN(a,b) ((a) < (b) ? (a) : (b))
+#define MAX(a,b) ((a) > (b) ? (a) : (b))
+
+struct inner
+{
+ int dummy[4];
+};
+
+struct container
+{
+ int mcast_rate[NUM_MCAST_RATE];
+ struct inner mesh;
+};
+
+static void
+test1_child (struct inner *ifmsh, size_t expected)
+{
+ struct container *sdata =
+ (struct container *) ((void *) ifmsh
+ - __builtin_offsetof (struct container, mesh));
+
+ if (__builtin_dynamic_object_size (sdata->mcast_rate, 1)
+ != sizeof (sdata->mcast_rate))
+ FAIL ();
+
+ if (__builtin_dynamic_object_size (&sdata->mesh, 1) != expected)
+ FAIL ();
+}
+
+void
+__attribute__((noinline))
+test1 (size_t sz)
+{
+ struct container *sdata = __builtin_malloc (sz);
+ struct inner *ifmsh = &sdata->mesh;
+
+ test1_child (ifmsh,
+ (sz > sizeof (sdata->mcast_rate)
+ ? sz - sizeof (sdata->mcast_rate) : 0));
+
+ __builtin_free (sdata);
+}
+
+struct container2
+{
+ int mcast_rate[NUM_MCAST_RATE];
+ union
+ {
+ int dummy;
+ double dbl;
+ struct inner mesh;
+ } u;
+};
+
+static void
+test2_child (struct inner *ifmsh, size_t sz)
+{
+ struct container2 *sdata =
+ (struct container2 *) ((void *) ifmsh
+ - __builtin_offsetof (struct container2, u.mesh));
+
+ if (__builtin_dynamic_object_size (sdata->mcast_rate, 1)
+ != sizeof (sdata->mcast_rate))
+ FAIL ();
+
+ size_t diff = sizeof (*sdata) - sz;
+ size_t expected = MIN(sizeof (double), MAX (sizeof (sdata->u), diff) - diff);
+
+ if (__builtin_dynamic_object_size (&sdata->u.dbl, 1) != expected)
+ FAIL ();
+
+ expected = MAX (sizeof (sdata->u.mesh), diff) - diff;
+ if (__builtin_dynamic_object_size (&sdata->u.mesh, 1) != expected)
+ FAIL ();
+}
+
+void
+__attribute__((noinline))
+test2 (size_t sz)
+{
+ struct container2 *sdata = __builtin_malloc (sz);
+ struct inner *ifmsh = &sdata->u.mesh;
+
+ test2_child (ifmsh, sz);;
+
+ __builtin_free (sdata);
+}
+
+struct container3
+{
+ int mcast_rate[NUM_MCAST_RATE];
+ char mesh[8];
+};
+
+static void
+test3_child (char ifmsh[], size_t expected)
+{
+ struct container3 *sdata =
+ (struct container3 *) ((void *) ifmsh
+ - __builtin_offsetof (struct container3, mesh));
+
+ if (__builtin_dynamic_object_size (sdata->mcast_rate, 1)
+ != sizeof (sdata->mcast_rate))
+ FAIL ();
+
+ if (__builtin_dynamic_object_size (sdata->mesh, 1) != expected)
+ FAIL ();
+}
+
+void
+__attribute__((noinline))
+test3 (size_t sz)
+{
+ struct container3 *sdata = __builtin_malloc (sz);
+ char *ifmsh = sdata->mesh;
+ size_t diff = sizeof (*sdata) - sz;
+
+ test3_child (ifmsh, MAX(sizeof (sdata->mesh), diff) - diff);
+
+ __builtin_free (sdata);
+}
+
+
+struct container4
+{
+ int mcast_rate[NUM_MCAST_RATE];
+ struct
+ {
+ int dummy;
+ struct inner mesh;
+ } s;
+};
+
+static void
+test4_child (struct inner *ifmsh, size_t expected)
+{
+ struct container4 *sdata =
+ (struct container4 *) ((void *) ifmsh
+ - __builtin_offsetof (struct container4, s.mesh));
+
+
+ if (__builtin_dynamic_object_size (sdata->mcast_rate, 1)
+ != sizeof (sdata->mcast_rate))
+ FAIL ();
+
+ if (__builtin_dynamic_object_size (&sdata->s.mesh, 1) != expected)
+ FAIL ();
+}
+
+void
+__attribute__((noinline))
+test4 (size_t sz)
+{
+ struct container4 *sdata = __builtin_malloc (sz);
+ struct inner *ifmsh = &sdata->s.mesh;
+ size_t diff = sizeof (*sdata) - sz;
+
+ test4_child (ifmsh, MAX(sizeof (sdata->s.mesh), diff) - diff);
+
+ __builtin_free (sdata);
+}
+
+struct container5
+{
+ int mcast_rate[NUM_MCAST_RATE];
+ struct
+ {
+ int dummy;
+ struct inner *mesh;
+ } s;
+};
+
+static void
+test5_child (struct inner **ifmsh, size_t expected)
+{
+ struct container5 *sdata =
+ (struct container5 *) ((void *) ifmsh
+ - __builtin_offsetof (struct container5, s.mesh));
+
+
+ if (__builtin_dynamic_object_size (sdata->mcast_rate, 1)
+ != sizeof (sdata->mcast_rate))
+ FAIL ();
+
+ if (__builtin_dynamic_object_size (&sdata->s.mesh, 1) != expected)
+ FAIL ();
+}
+
+void
+__attribute__((noinline))
+test5 (size_t sz)
+{
+ struct container5 *sdata = __builtin_malloc (sz);
+ struct inner **ifmsh = &sdata->s.mesh;
+ size_t diff = sizeof (*sdata) - sz;
+
+ test5_child (ifmsh, MAX(sizeof (sdata->s.mesh), diff) - diff);
+
+ __builtin_free (sdata);
+}
+
+int
+main (size_t sz)
+{
+ test1 (sizeof (struct container));
+ test1 (sizeof (struct container) - sizeof (int));
+ test1 (sizeof (int) * NUM_MCAST_RATE - 1);
+
+ test2 (sizeof (struct container2));
+ test2 (sizeof (struct container2) - sizeof (int));
+ test2 (sizeof (int) * NUM_MCAST_RATE - 1);
+
+ test3 (sizeof (struct container3));
+ test3 (sizeof (struct container3) - sizeof (int));
+ test3 (sizeof (int) * NUM_MCAST_RATE - 1);
+
+ test4 (sizeof (struct container4));
+ test4 (sizeof (struct container4) - sizeof (int));
+ test4 (sizeof (int) * NUM_MCAST_RATE - 1);
+
+ test5 (sizeof (struct container5));
+ test5 (sizeof (struct container5) - sizeof (int));
+ test5 (sizeof (int) * NUM_MCAST_RATE - 1);
+
+ DONE ();
+}
return size_binop (code, base, off);
}
+/* Return true if CONTAINER has a field of type INNER at OFFSET. */
+
+static bool
+inner_at_offset (tree container, tree inner, tree offset)
+{
+ gcc_assert (RECORD_OR_UNION_TYPE_P (container));
+
+ for (tree t = TYPE_FIELDS (container); t; t = DECL_CHAIN (t))
+ {
+ if (TREE_CODE (t) != FIELD_DECL)
+ continue;
+
+ /* Skip over fields at bit offsets that are not BITS_PER_UNIT aligned
+ to avoid an accidental truncated match with BYTE_POSITION below since
+ the address of such fields cannot be taken. */
+ if (wi::bit_and (wi::to_offset (DECL_FIELD_BIT_OFFSET (t)),
+ BITS_PER_UNIT - 1) != 0)
+ continue;
+
+ tree byte_offset = byte_position (t);
+ if (TREE_CODE (byte_offset) != INTEGER_CST
+ || tree_int_cst_lt (offset, byte_offset))
+ return false;
+
+ /* For an array, check the element type, otherwise the actual type. This
+ deliberately does not support the case of jumping from a pointer to
+ the middle of an array to its containing struct. */
+ tree t_type = TREE_TYPE (t);
+ if (((TREE_CODE (t_type) == ARRAY_TYPE && TREE_TYPE (t_type) == inner)
+ || t_type == inner)
+ && tree_int_cst_equal (byte_offset, offset))
+ return true;
+
+ /* Nested structure or union, adjust the expected offset and dive in. */
+ if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (t))
+ && inner_at_offset (TREE_TYPE (t), inner,
+ fold_build2 (MINUS_EXPR, sizetype, offset,
+ byte_offset)))
+ return true;
+ }
+
+ return false;
+}
+
+/* For the input MEMREF of type MEMREF_TYPE, look for the presence of a field
+ of BASE_TYPE at OFFSET and return an adjusted WHOLESIZE if found. */
+
+static tree
+get_wholesize_for_memref (tree memref, tree wholesize)
+{
+ tree base = TREE_OPERAND (memref, 0);
+ tree offset = fold_convert (sizetype, TREE_OPERAND (memref, 1));
+ tree memref_type = TREE_TYPE (memref);
+ tree base_type = TREE_TYPE (base);
+
+ if (POINTER_TYPE_P (base_type))
+ base_type = TREE_TYPE ((base_type));
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "wholesize_for_memref: ");
+ print_generic_expr (dump_file, wholesize, dump_flags);
+ fprintf (dump_file, ", offset: ");
+ print_generic_expr (dump_file, offset, dump_flags);
+ fprintf (dump_file, "\n");
+ }
+
+ if (TREE_CODE (offset) != INTEGER_CST
+ || compare_tree_int (offset, offset_limit) < 0
+ || !RECORD_OR_UNION_TYPE_P (memref_type))
+ return wholesize;
+
+ offset = fold_build1 (NEGATE_EXPR, sizetype, offset);
+
+ if (inner_at_offset (memref_type, base_type, offset))
+ wholesize = size_binop (PLUS_EXPR, wholesize, offset);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, " new wholesize: ");
+ print_generic_expr (dump_file, wholesize, dump_flags);
+ fprintf (dump_file, "\n");
+ }
+
+ return wholesize;
+}
+
/* Returns the size of the object designated by DECL considering its
initializer if it either has one or if it would not affect its size,
otherwise the size of the object without the initializer when MIN
{
compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
object_size_type & ~OST_SUBOBJECT, &sz);
- wholesize = sz;
+ wholesize = get_wholesize_for_memref (pt_var, sz);
}
else
{
{
sz = object_sizes_get (osi, SSA_NAME_VERSION (var));
wholesize = object_sizes_get (osi, SSA_NAME_VERSION (var), true);
+ wholesize = get_wholesize_for_memref (pt_var, wholesize);
}
else
sz = wholesize = size_unknown (object_size_type);