In tree-object-size.cc, if the size is UNKNOWN after evaluating use-def
chain, We can evaluate the SIZE of the pointee TYPE ONLY when this TYPE
is a structure type with flexible array member, since a structure with
FAM can not be an element of an array, so, the pointer must point to a
single object with this structure with FAM.
This is only available for C now.
bootstrapped and regression tested on both x86 and aarch64.
Okay for stage1?
thanks.
Qing
gcc/c/ChangeLog:
* c-lang.cc (LANG_HOOKS_BUILD_COUNTED_BY_REF):
Define to below function.
* c-tree.h (c_build_counted_by_ref): New extern function.
* c-typeck.cc (build_counted_by_ref): Rename to ...
(c_build_counted_by_ref): ...this.
(handle_counted_by_for_component_ref): Call the renamed function.
gcc/ChangeLog:
* langhooks-def.h (LANG_HOOKS_BUILD_COUNTED_BY_REF):
New language hook.
* langhooks.h (struct lang_hooks_for_types): Add
build_counted_by_ref.
* tree-object-size.cc (struct object_size_info): Add a new field
insert_after.
(gimplify_size_expressions): Insert sequence after or before
depending on the new field insert_after.
(compute_builtin_object_size): Init the new field to false;
(record_with_fam_object_size): New function.
(collect_object_sizes_for): Call record_with_fam_object_size.
gcc/testsuite/ChangeLog:
* gcc.dg/flex-array-counted-by-3.c: Update test;
* gcc.dg/flex-array-counted-by-4.c: Likewise.
* gcc.dg/flex-array-counted-by-5.c: Likewise.
---
gcc/c/c-lang.cc | 3 +
gcc/c/c-tree.h | 1 +
gcc/c/c-typeck.cc | 6 +-
gcc/langhooks-def.h | 4 +-
gcc/langhooks.h | 5 +
.../gcc.dg/flex-array-counted-by-3.c | 5 +
.../gcc.dg/flex-array-counted-by-4.c | 34 ++++--
.../gcc.dg/flex-array-counted-by-5.c | 4 +
gcc/tree-object-size.cc | 106 +++++++++++++++++-
9 files changed, 152 insertions(+), 16 deletions(-)
diff --git a/gcc/c/c-lang.cc b/gcc/c/c-lang.cc
index c69077b2a93..e9ec9e6e64a 100644
--- a/gcc/c/c-lang.cc
+++ b/gcc/c/c-lang.cc
@@ -51,6 +51,9 @@ enum c_language_kind c_language = clk_c;
#undef LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE
#define LANG_HOOKS_GET_SARIF_SOURCE_LANGUAGE c_get_sarif_source_language
+#undef LANG_HOOKS_BUILD_COUNTED_BY_REF
+#define LANG_HOOKS_BUILD_COUNTED_BY_REF c_build_counted_by_ref
+
/* Each front end provides its own lang hook initializer. */
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 743ec5cbae6..66bec5d92fa 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -776,6 +776,7 @@ extern struct c_switch *c_switch_stack;
extern bool null_pointer_constant_p (const_tree);
+extern tree c_build_counted_by_ref (tree, tree, tree *);
inline bool
c_type_variably_modified_p (tree t)
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 19e79b554dc..6efc3fb3e5d 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -2936,8 +2936,8 @@ should_suggest_deref_p (tree datum_type)
&(p->k)
*/
-static tree
-build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type)
+tree
+c_build_counted_by_ref (tree datum, tree subdatum, tree *counted_by_type)
{
tree type = TREE_TYPE (datum);
if (!c_flexible_array_member_type_p (TREE_TYPE (subdatum)))
@@ -3031,7 +3031,7 @@ handle_counted_by_for_component_ref (location_t loc, tree
ref)
tree datum = TREE_OPERAND (ref, 0);
tree subdatum = TREE_OPERAND (ref, 1);
tree counted_by_type = NULL_TREE;
- tree counted_by_ref = build_counted_by_ref (datum, subdatum,
+ tree counted_by_ref = c_build_counted_by_ref (datum, subdatum,
&counted_by_type);
if (counted_by_ref)
ref = build_access_with_size_for_counted_by (loc, ref,
diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h
index 6b34d324ab5..7909ea8a92c 100644
--- a/gcc/langhooks-def.h
+++ b/gcc/langhooks-def.h
@@ -221,6 +221,7 @@ extern tree lhd_unit_size_without_reusable_padding (tree);
#define LANG_HOOKS_TYPE_DWARF_ATTRIBUTE lhd_type_dwarf_attribute
#define LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING
lhd_unit_size_without_reusable_padding
#define LANG_HOOKS_CLASSTYPE_AS_BASE hook_tree_const_tree_null
+#define LANG_HOOKS_BUILD_COUNTED_BY_REF NULL
#define LANG_HOOKS_FOR_TYPES_INITIALIZER { \
LANG_HOOKS_MAKE_TYPE, \
@@ -248,7 +249,8 @@ extern tree lhd_unit_size_without_reusable_padding (tree);
LANG_HOOKS_GET_FIXED_POINT_TYPE_INFO, \
LANG_HOOKS_TYPE_DWARF_ATTRIBUTE, \
LANG_HOOKS_UNIT_SIZE_WITHOUT_REUSABLE_PADDING, \
- LANG_HOOKS_CLASSTYPE_AS_BASE \
+ LANG_HOOKS_CLASSTYPE_AS_BASE, \
+ LANG_HOOKS_BUILD_COUNTED_BY_REF \
}
/* Declaration hooks. */
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index dc8d878c7fb..797c8bcc0c0 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -190,6 +190,11 @@ struct lang_hooks_for_types
i.e., type without virtual base classes or tail padding. Returns
NULL_TREE otherwise. */
tree (*classtype_as_base) (const_tree);
+
+ /* Build a REF to the object that represents the counted_by per the attribute
+ counted_by attached to the field. Otherwise return NULL_TREE. Set the
+ TYPE of the counted_by field to the last parameter. */
+ tree (*build_counted_by_ref) (tree, tree, tree *);
};
/* Language hooks related to decls and the symbol table. */
diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c
b/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c
index 78f50230e89..88ad50bea6b 100644
--- a/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c
+++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-3.c
@@ -53,6 +53,11 @@ void __attribute__((__noinline__)) test ()
array_annotated->b * sizeof (int));
EXPECT(__builtin_dynamic_object_size(array_nested_annotated->c, 1),
array_nested_annotated->b * sizeof (int));
+ EXPECT(__builtin_dynamic_object_size(array_annotated, 1),
+ sizeof (struct annotated) + array_annotated->b * sizeof (int));
+ EXPECT(__builtin_dynamic_object_size(array_nested_annotated, 1),
+ sizeof (struct nested_annotated)
+ + array_nested_annotated->b * sizeof (int));
}
int main(int argc, char *argv[])
diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c
b/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c
index 20103d58ef5..6ac2be4471d 100644
--- a/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c
+++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-4.c
@@ -23,7 +23,15 @@ struct annotated {
So, __builtin_object_size can not directly use the type of the pointee
to decide the size of the object the pointer points to.
- There are only two reliable ways:
+ However, if the pointer points to a strucure with FAM, and the FAM is
+ annotated with counted_by attribute, we can get the size of the pointee
+ object by the size of the structure type and the counted_by attribute
+ since structure with FAM cannot be an element of an array, the pointer
+ that points to such type must point to a single object with the type,
+ therefore, we can decide the size of the object from the size of the
+ type for the pointee.
+
+ There are other two reliable ways:
A. observed allocations (call to the allocation functions in the routine)
B. observed accesses (read or write access to the location of the
pointer points to)
@@ -155,11 +163,13 @@ int main ()
EXPECT(__builtin_dynamic_object_size(p->array, 2), p->foo * sizeof(char));
EXPECT(__builtin_dynamic_object_size(p->array, 3), p->foo * sizeof(char));
/* When checking the pointer p, we have no observed allocation nor observed
- access, therefore, we cannot determine the size info here. */
- EXPECT(__builtin_dynamic_object_size(p, 0), -1);
- EXPECT(__builtin_dynamic_object_size(p, 1), -1);
- EXPECT(__builtin_dynamic_object_size(p, 2), 0);
- EXPECT(__builtin_dynamic_object_size(p, 3), 0);
+ access, however, since the pointer points to a strucure with FAM, and the
+ FAM is annotated with counted_by attribute, we can get the size of the
+ pointee object by the size of the TYPE and the counted_by attribute. */
+ EXPECT(__builtin_dynamic_object_size(p, 0), 19);
+ EXPECT(__builtin_dynamic_object_size(p, 1), 19);
+ EXPECT(__builtin_dynamic_object_size(p, 2), 19);
+ EXPECT(__builtin_dynamic_object_size(p, 3), 19);
/* When checking the access p->array, we only have info on the counted-by
value. */
@@ -168,11 +178,13 @@ int main ()
EXPECT(__builtin_dynamic_object_size(q->array, 2), q->foo * sizeof(char));
EXPECT(__builtin_dynamic_object_size(q->array, 3), q->foo * sizeof(char));
/* When checking the pointer p, we have no observed allocation nor observed
- access, therefore, we cannot determine the size info here. */
- EXPECT(__builtin_dynamic_object_size(q, 0), -1);
- EXPECT(__builtin_dynamic_object_size(q, 1), -1);
- EXPECT(__builtin_dynamic_object_size(q, 2), 0);
- EXPECT(__builtin_dynamic_object_size(q, 3), 0);
+ access, however, since the pointer points to a strucure with FAM, and the
+ FAM is annotated with counted_by attribute, we can get the size of the
+ pointee object by the size of the TYPE and the counted_by attribute. */
+ EXPECT(__builtin_dynamic_object_size(q, 0), 29);
+ EXPECT(__builtin_dynamic_object_size(q, 1), 29);
+ EXPECT(__builtin_dynamic_object_size(q, 2), 29);
+ EXPECT(__builtin_dynamic_object_size(q, 3), 29);
DONE ();
}
diff --git a/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c
b/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c
index 68f9b0f7c8d..44bfce9976f 100644
--- a/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c
+++ b/gcc/testsuite/gcc.dg/flex-array-counted-by-5.c
@@ -38,6 +38,10 @@ void __attribute__((__noinline__)) test ()
{
EXPECT(__builtin_dynamic_object_size(array_annotated->c, 1), 0);
EXPECT(__builtin_dynamic_object_size(array_nested_annotated->c, 1), 0);
+ EXPECT(__builtin_dynamic_object_size(array_annotated, 1),
+ sizeof (struct annotated));
+ EXPECT(__builtin_dynamic_object_size(array_nested_annotated, 1),
+ sizeof (struct nested_annotated));
}
int main(int argc, char *argv[])
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index f348673ae75..5ff2da18f50 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "fold-const.h"
#include "tree-object-size.h"
#include "gimple-iterator.h"
+#include "langhooks.h"
#include "gimple-fold.h"
#include "tree-cfg.h"
#include "tree-dfa.h"
@@ -45,6 +46,7 @@ struct object_size_info
int object_size_type;
unsigned char pass;
bool changed;
+ bool insert_after;
bitmap visited, reexamine;
unsigned int *depths;
unsigned int *stack, *tos;
@@ -1174,7 +1176,10 @@ gimplify_size_expressions (object_size_info *osi)
gsi = gsi_for_stmt (stmt);
force_gimple_operand (size_expr, &seq, true, NULL);
- gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING);
+ if (osi->insert_after)
+ gsi_insert_seq_after (&gsi, seq, GSI_CONTINUE_LINKING);
+ else
+ gsi_insert_seq_before (&gsi, seq, GSI_CONTINUE_LINKING);
}
}
@@ -1279,6 +1284,7 @@ compute_builtin_object_size (tree ptr, int object_size_type,
expression needs to be gimplified. */
osi.pass = 0;
osi.changed = false;
+ osi.insert_after = false;
collect_object_sizes_for (&osi, ptr);
if (object_size_type & OST_DYNAMIC)
@@ -1768,6 +1774,89 @@ phi_dynamic_object_size (struct object_size_info *osi,
tree var)
object_sizes_set (osi, varno, sizes, wholesizes);
}
+/* Compute an object size expression for VAR, whose pointee TYPE is a
+ structure with flexible array member. */
+
+static void
+record_with_fam_object_size (struct object_size_info *osi, tree var)
+{
+ int object_size_type = osi->object_size_type;
+ tree size = size_unknown (object_size_type);
+
+ tree pointee_type = TREE_TYPE (TREE_TYPE (var));
+ tree counted_by_ref = NULL_TREE;
+ tree counted_by_type = NULL_TREE;
+ tree last = NULL_TREE;
+
+ if (TREE_CODE (pointee_type) == RECORD_TYPE
+ && flexible_array_type_p (pointee_type))
+ {
+ for (tree x = TYPE_FIELDS (pointee_type); x != NULL_TREE;
+ x = DECL_CHAIN (x))
+ if (TREE_CODE (x) == FIELD_DECL
+ && TREE_CODE (TREE_TYPE (x)) == ARRAY_TYPE
+ && TYPE_SIZE (TREE_TYPE (x)) == NULL_TREE
+ && TYPE_DOMAIN (TREE_TYPE (x)) != NULL_TREE
+ && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (x))) == NULL_TREE
+ && DECL_CHAIN (x) == NULL_TREE)
+ last = x;
+ /* Check whether the last FAM field has a counted_by attribute.
+ If so, build a counted_by reference. */
+ if (last
+ && lookup_attribute ("counted_by", DECL_ATTRIBUTES (last))
+ && lang_hooks.types.build_counted_by_ref)
+ {
+ tree datum = build1 (INDIRECT_REF, pointee_type, var);
+ counted_by_ref
+ = lang_hooks.types.build_counted_by_ref (datum, last,
+ &counted_by_type);
+ }
+ }
+
+ /* If the counted_by reference is available, the size of the whole structure
+ can be computed. */
+ if (counted_by_ref)
+ {
+ tree element_type = TREE_TYPE (TREE_TYPE (last));
+ tree element_size = TYPE_SIZE_UNIT (element_type);
+ size = fold_build2 (MEM_REF, counted_by_type, counted_by_ref,
+ build_int_cst (ptr_type_node, 0));
+ /* If counted_by is a negative value, treat it as zero. */
+ if (!TYPE_UNSIGNED (counted_by_type))
+ {
+ tree cond_expr = fold_build2 (LT_EXPR, boolean_type_node,
+ unshare_expr (size),
+ build_zero_cst (counted_by_type));
+ size = fold_build3 (COND_EXPR, integer_type_node, cond_expr,
+ build_zero_cst (counted_by_type), size);
+ }
+
+ /* The total size of the whole object is computed as:
+ MAX (sizeof (pointee_type),
+ offsetof (pointee_type, last) + counted_by * element_size). */
+ size = size_binop (MULT_EXPR,
+ fold_convert (sizetype, size),
+ fold_convert (sizetype, element_size));
+ size = size_binop (PLUS_EXPR,
+ byte_position (last),
+ size);
+ size = size_binop (MAX_EXPR,
+ TYPE_SIZE_UNIT (pointee_type),
+ size);
+ if (!todo)
+ todo = TODO_update_ssa_only_virtuals;
+
+ }
+ /* Initialize to 0 for maximum size and M1U for minimum size so that
+ it gets immediately overridden. */
+ object_sizes_initialize (osi, SSA_NAME_VERSION (var),
+ size_initval (object_size_type),
+ size_initval (object_size_type));
+
+ osi->insert_after = true;
+ object_sizes_set (osi, SSA_NAME_VERSION (var), size, size);
+}
+
/* Compute object sizes for VAR.
For ADDR_EXPR an object size is the number of remaining bytes
to the end of the object (where what is considered an object depends on
@@ -1922,6 +2011,21 @@ collect_object_sizes_for (struct object_size_info *osi,
tree var)
gcc_unreachable ();
}
+ /* If the size is UNKNOWN after evaluating use-def chain, We can evaluate
+ * the SIZE of the pointee TYPE ONLY when this TYPE is a structure type
+ * with flexible array member, Since a structure with FAM can not be an
+ * element of an array, so, PTR must point to an single object with this
+ * strucure with FAM. */