when the type is a structure with flexible array member.

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.  */
+
+  if (object_sizes_unknown_p (object_size_type, varno)
+      && object_size_type & OST_DYNAMIC
+      && POINTER_TYPE_P (TREE_TYPE (var)))
+    {
+      const_tree pointee_type = TREE_TYPE (TREE_TYPE (var));
+      if (flexible_array_type_p (pointee_type))
+       record_with_fam_object_size (osi, var);
+    }
+
   /* Dynamic sizes use placeholder temps to return an answer, so it is always
      safe to set COMPUTED for them.  */
   if ((object_size_type & OST_DYNAMIC)
-- 
2.43.5

Reply via email to