Most code is cold. This patch extends support for attribute ((cold)) to C++
Classes, Unions, and Structs (RECORD_TYPES and UNION_TYPES) to benefit from
encapsulation - reducing the verbosity of using the attribute where
deserved. The ((hot)) attribute is also extended for its semantic relation.
What is the sentiment on this use-case?

for gcc/c-family/ChangeLog

    * c-attribs.c (attribute_spec): Remove decl_required
    field for "hot" and "cold" attributes.
    (handle_cold_attribute): remove warning on RECORD_TYPE
    and UNION_TYPE when c_dialect_cxx.
    (handle_cold_attribute): remove warning on RECORD_TYPE
    and UNION_TYPE when c_dialect_cxx.

for gcc/cp/ChangeLog

    * class.c (finish_struct) propagate hot and cold
    attributes to all FUNCTION_DECL when the class
    itself is marked hot or cold.

for  gcc/testsuite/ChangeLog

    * g++.dg/ext/attr-hotness.C: New.


Signed-off-by: Javier Martinez <javier.martinez.bugzi...@gmail.com>

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index dc9579c..815df66 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -398,10 +398,10 @@ const struct attribute_spec
c_common_attribute_table[] =
   { "alloc_size",      1, 2, false, true, true, false,
       handle_alloc_size_attribute,
                       attr_alloc_exclusions },
-  { "cold",                   0, 0, true,  false, false, false,
+  { "cold",                   0, 0, false,  false, false, false,
       handle_cold_attribute,
                       attr_cold_hot_exclusions },
-  { "hot",                    0, 0, true,  false, false, false,
+  { "hot",                    0, 0, false,  false, false, false,
       handle_hot_attribute,
                       attr_cold_hot_exclusions },
   { "no_address_safety_analysis",
@@ -837,22 +837,23 @@ handle_noreturn_attribute (tree *node, tree name,
tree ARG_UNUSED (args),

 static tree
 handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args),
-      int ARG_UNUSED (flags), bool *no_add_attrs)
+       int ARG_UNUSED (flags), bool *no_add_attrs)
 {
-  if (TREE_CODE (*node) == FUNCTION_DECL
-      || TREE_CODE (*node) == LABEL_DECL)
+  if ( (TREE_CODE (*node) == FUNCTION_DECL ||
+        TREE_CODE (*node) == LABEL_DECL)
+      || ((TREE_CODE(*node) == RECORD_TYPE ||
+           TREE_CODE(*node) == UNION_TYPE) && c_dialect_cxx()))
     {
       /* Attribute hot processing is done later with lookup_attribute.  */
     }
   else
     {
       warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
+      *no_add_attrs = true;
     }

   return NULL_TREE;
 }
-
 /* Handle a "cold" and attribute; arguments as in
    struct attribute_spec.handler.  */

@@ -860,15 +861,17 @@ static tree
 handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args),
        int ARG_UNUSED (flags), bool *no_add_attrs)
 {
-  if (TREE_CODE (*node) == FUNCTION_DECL
-      || TREE_CODE (*node) == LABEL_DECL)
+  if ( (TREE_CODE (*node) == FUNCTION_DECL ||
+        TREE_CODE (*node) == LABEL_DECL)
+      || ((TREE_CODE(*node) == RECORD_TYPE ||
+           TREE_CODE(*node) == UNION_TYPE) && c_dialect_cxx()))
     {
       /* Attribute cold processing is done later with lookup_attribute.  */
     }
   else
     {
       warning (OPT_Wattributes, "%qE attribute ignored", name);
-      *no_add_attrs = true;
+      *no_add_attrs = true;
     }

   return NULL_TREE;
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 07abe52..70f734f 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -7540,6 +7540,35 @@ finish_struct (tree t, tree attributes)
       && !LAMBDA_TYPE_P (t))
     add_stmt (build_min (TAG_DEFN, t));

+
+  /* classes marked with hotness attributes propagate the attribute to
+  all methods. We propagate these here as there is a guarantee that
+  TYPE_FIELDS is populated, as opposed from within decl_attributes. */
+
+  tree has_cold_attr = lookup_attribute("cold", TYPE_ATTRIBUTES(t));
+  tree has_hot_attr = lookup_attribute("hot", TYPE_ATTRIBUTES(t));
+
+  if ( has_cold_attr || has_hot_attr ) {
+
+    /* hoisted out of the loop */
+    tree attr_cold_id = get_identifier("cold");
+    tree attr_hot_id = get_identifier("hot");
+
+    for (tree f = TYPE_FIELDS (t); f; f = DECL_CHAIN (f))
+      {
+        if (TREE_CODE (f) == FUNCTION_DECL) {
+          /* decl_attributes will take care of conflicts,
+          also prioritizing attributes explicitly marked in methods */
+
+          if (has_cold_attr) {
+            decl_attributes (&f, tree_cons (attr_cold_id, NULL, NULL), 0);
+          } else if (has_hot_attr) {
+            decl_attributes (&f, tree_cons (attr_hot_id, NULL, NULL), 0);
+          }
+        }
+      }
+  }
+
   return t;
 }

diff --git a/gcc/testsuite/g++.dg/ext/attr-hotness.C
b/gcc/testsuite/g++.dg/ext/attr-hotness.C
new file mode 100644
index 0000000..075c624
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attr-hotness.C
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -Wattributes -fdump-tree-gimple" } */
+
+
+struct __attribute((cold)) A { __attribute((noinline, used)) void
foo(void) { } };
+
+struct __attribute((cold)) B { __attribute((noinline, used, hot)) void
foo(void) { } }; /* { dg-warning "ignoring attribute .cold. because it
conflicts with attribute .hot." } */
+
+struct __attribute((hot)) D { __attribute((noinline, used)) void foo(void)
{ } };
+
+struct __attribute((hot)) E { __attribute((noinline, used, cold)) void
foo(void) { } }; /* { dg-warning "ignoring attribute .hot. because it
conflicts with attribute .cold." } */
+
+/* { dg-final { scan-tree-dump-times "cold" 2 "gimple" } } */
+/* { dg-final { scan-tree-dump-times "hot" 2 "gimple" } } */
+

Reply via email to