From patchwork Wed Aug 23 13:02:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Javier Martinez X-Patchwork-Id: 1824689 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.a=rsa-sha256 header.s=default header.b=fJ37Dazi; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=2620:52:3:1:0:246e:9693:128c; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [IPv6:2620:52:3:1:0:246e:9693:128c]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4RW5xN4g0kz1yg8 for ; Wed, 23 Aug 2023 23:03:18 +1000 (AEST) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BAA7D3853D02 for ; Wed, 23 Aug 2023 13:03:15 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BAA7D3853D02 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1692795795; bh=tB5wUYTHkQSCzeaL3NzsMby2cqpz/QCVfwRXcb4s6wE=; h=Date:Subject:To:Cc:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:From:Reply-To:From; b=fJ37DazietnOVOki7ke4qZ561DiQWWahq7sdceM1WwsMXuOeWUoU4ZpW+1dxXukOR KnF4v67mZUa3tEXWtiTAev1bkfSOfbJuegSj0//OyrI+lUsBc8L9zkIkzTSMyu462P 3Gfph9za6JPjJ378sJUJX+nXDEjhI2v5p0Eb0buQ= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-lf1-x143.google.com (mail-lf1-x143.google.com [IPv6:2a00:1450:4864:20::143]) by sourceware.org (Postfix) with ESMTPS id 230063858C01 for ; Wed, 23 Aug 2023 13:02:53 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 230063858C01 Received: by mail-lf1-x143.google.com with SMTP id 2adb3069b0e04-500760b296aso4498703e87.0 for ; Wed, 23 Aug 2023 06:02:53 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1692795771; x=1693400571; h=cc:to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=av1nyJgRbOCFRozhg22LNNo0RjVexC3qXiuMHuii7hY=; b=OcQE2sBSLxP82n5l4tpCzMAsbgG+VodWFOOnIFsjuWa+nZB9gw2T1HmBViFQV/GAOc 4tIHPs7QPGtlSbK8zFyTHtxgiikdWXXtp9rUKcDB678MQSf4/JKtFgsSsGg/U1wpKPPc sjmhXWaIwCjmiGFcbL0/tt+xRqDelQdSEwmMWkbGV4kxc8oSSojcamonjNvXyFKr03/h 9hvk720fIpeOBkoZFKdo0ZFetUH/UVwNYtPB2vpcPglQ/e15zyBVXx2aOoMYNe+2uY6S zBtk2LgohNIJ946TFCSYV5vwudGWSzay6Brs/r7UULkTTuGaEEhN5lO5RqXNDNu2NNVN cNbw== X-Gm-Message-State: AOJu0YyoqIomAHDzxCN7Eajw3M5vtHeItUX7KbDcNqArrX/xfS/OWvAH N62aHRLPG5HiWwk7A8z6YpMBsKC1VOCrz0s5plxk4Pu/gMLqkKgILo8= X-Google-Smtp-Source: AGHT+IEGUfGlCR/NlU+9AQFvP6Iv8R1fp//C7MtJIXyzG6/lhicxvjcBLAU8/YIzpOhwYlR6mqKqG5vedK3foHqeSPo= X-Received: by 2002:a05:6512:239f:b0:4fe:2815:8ba7 with SMTP id c31-20020a056512239f00b004fe28158ba7mr4792551lfv.25.1692795771218; Wed, 23 Aug 2023 06:02:51 -0700 (PDT) MIME-Version: 1.0 Date: Wed, 23 Aug 2023 15:02:40 +0200 Message-ID: Subject: [PATCH v5] c++: extend cold, hot attributes to classes To: gcc-patches@gcc.gnu.org Cc: jason@redhat.com X-Spam-Status: No, score=-9.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, HTML_MESSAGE, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-Content-Filtered-By: Mailman/MimeDel 2.1.29 X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Javier Martinez via Gcc-patches From: Javier Martinez Reply-To: Javier Martinez Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" On Tue, Aug 22, 2023 at 7:50 PM Jason Merrill wrote: > You still need an update to doc/extend.texi for this additional use of > the attribute. Sorry I didn't think of that before. I should have caught that too, many thanks. Also addressed the formatting comments. Patch attached. Signed-off-by: Javier Martinez Signed-off-by: Javier Martinez gcc/c-family/ChangeLog: * c-attribs.cc (handle_hot_attribute): remove warning on RECORD_TYPE and UNION_TYPE when in c_dialect_xx. (handle_cold_attribute): Likewise. gcc/cp/ChangeLog: * class.cc (propagate_class_warmth_attribute): New function. (check_bases_and_members): propagate hot and cold attributes to all FUNCTION_DECL when the record is marked hot or cold. * cp-tree.h (maybe_propagate_warmth_attributes): New function. * decl2.cc (maybe_propagate_warmth_attributes): New function. * method.cc (lazily_declare_fn): propagate hot and cold attributes to lazily declared functions when the record is marked hot or cold. gcc/ChangeLog: * doc/extend.texi: Document attributes hot, cold on C++ types. gcc/testsuite/ChangeLog: * g++.dg/ext/attr-hotness.C: New test. --- gcc/c-family/c-attribs.cc | 50 ++++++++++++++++++++++++- gcc/cp/class.cc | 29 ++++++++++++++ gcc/cp/cp-tree.h | 1 + gcc/cp/decl2.cc | 44 ++++++++++++++++++++++ gcc/cp/method.cc | 6 +++ gcc/doc/extend.texi | 37 +++++++++++++++++- gcc/testsuite/g++.dg/ext/attr-hotness.C | 16 ++++++++ 7 files changed, 179 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/ext/attr-hotness.C diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc index e2792ca6898..5d83f54561d 100644 --- a/gcc/c-family/c-attribs.cc +++ b/gcc/c-family/c-attribs.cc @@ -452,10 +452,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", @@ -1110,6 +1110,29 @@ handle_hot_attribute (tree *node, tree name, tree ARG_UNUSED (args), { /* Attribute hot processing is done later with lookup_attribute. */ } + else if ((TREE_CODE (*node) == RECORD_TYPE + || TREE_CODE (*node) == UNION_TYPE) + && c_dialect_cxx () + && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + { + /* Check conflict here as decl_attributes will otherwise only catch + it late at the function when the attribute is used on a class. */ + tree cold_attr = lookup_attribute ("cold", TYPE_ATTRIBUTES (*node)); + if (cold_attr) + { + warning (OPT_Wattributes, "ignoring attribute %qE because it " + "conflicts with attribute %qs", name, "cold"); + *no_add_attrs = true; + } + } + else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_DECL_NEXT)) + { + /* Avoid applying the attribute to a function return type when + used as: void __attribute ((hot)) foo (void). It will be + passed to the function. */ + *no_add_attrs = true; + } else { warning (OPT_Wattributes, "%qE attribute ignored", name); @@ -1131,6 +1154,29 @@ handle_cold_attribute (tree *node, tree name, tree ARG_UNUSED (args), { /* Attribute cold processing is done later with lookup_attribute. */ } + else if ((TREE_CODE (*node) == RECORD_TYPE + || TREE_CODE (*node) == UNION_TYPE) + && c_dialect_cxx () + && (flags & (int) ATTR_FLAG_TYPE_IN_PLACE)) + { + /* Check conflict here as decl_attributes will otherwise only catch + it late at the function when the attribute is used on a class. */ + tree hot_attr = lookup_attribute ("hot", TYPE_ATTRIBUTES (*node)); + if (hot_attr) + { + warning (OPT_Wattributes, "ignoring attribute %qE because it " + "conflicts with attribute %qs", name, "hot"); + *no_add_attrs = true; + } + } + else if (flags & ((int) ATTR_FLAG_FUNCTION_NEXT + | (int) ATTR_FLAG_DECL_NEXT)) + { + /* Avoid applying the attribute to a function return type when + used as: void __attribute ((cold)) foo (void). It will be + passed to the function. */ + *no_add_attrs = true; + } else { warning (OPT_Wattributes, "%qE attribute ignored", name); diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc index 778759237dc..0bb679f15be 100644 --- a/gcc/cp/class.cc +++ b/gcc/cp/class.cc @@ -205,6 +205,7 @@ static tree get_vcall_index (tree, tree); static bool type_maybe_constexpr_default_constructor (tree); static bool type_maybe_constexpr_destructor (tree); static bool field_poverlapping_p (tree); +static void propagate_class_warmth_attribute (tree); /* Set CURRENT_ACCESS_SPECIFIER based on the protection of DECL. */ @@ -6253,6 +6254,12 @@ check_bases_and_members (tree t) allocating an array of this type. */ LANG_TYPE_CLASS_CHECK (t)->vec_new_uses_cookie = type_requires_array_cookie (t); + + /* Classes marked hot or cold propagate the attribute to all members. We + may do this now that methods are declared. This does miss some lazily + declared special member functions (CLASSTYPE_LAZY_*), which are handled + in lazily_declare_fn later on. */ + propagate_class_warmth_attribute (t); } /* If T needs a pointer to its virtual function table, set TYPE_VFIELD @@ -7733,6 +7740,28 @@ unreverse_member_declarations (tree t) } } +/* Classes, structs or unions T marked with hotness attributes propagate + the attribute to all methods. */ + +void +propagate_class_warmth_attribute (tree t) +{ + if (t == NULL_TREE + || !(TREE_CODE (t) == RECORD_TYPE + || TREE_CODE (t) == UNION_TYPE)) + return; + + tree class_has_cold_attr + = lookup_attribute ("cold", TYPE_ATTRIBUTES (t)); + tree class_has_hot_attr + = lookup_attribute ("hot", TYPE_ATTRIBUTES (t)); + + if (class_has_cold_attr || class_has_hot_attr) + for (tree f = TYPE_FIELDS (t); f; f = DECL_CHAIN (f)) + if (TREE_CODE (f) == FUNCTION_DECL) + maybe_propagate_warmth_attributes (f, t); +} + tree finish_struct (tree t, tree attributes) { diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index d051ee85f70..4931a45607e 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7033,6 +7033,7 @@ extern int parm_index (tree); extern tree vtv_start_verification_constructor_init_function (void); extern tree vtv_finish_verification_constructor_init_function (tree); extern void cp_check_const_attributes (tree); +extern void maybe_propagate_warmth_attributes (tree, tree); /* in error.cc */ extern const char *type_as_string (tree, int); diff --git a/gcc/cp/decl2.cc b/gcc/cp/decl2.cc index b402befba6d..5dae6f3bbc0 100644 --- a/gcc/cp/decl2.cc +++ b/gcc/cp/decl2.cc @@ -1604,6 +1604,50 @@ cp_check_const_attributes (tree attributes) } } +/* Copies hot or cold attributes to a function FN if present on the + encapsulating class, struct, or union TYPE. */ + +void +maybe_propagate_warmth_attributes (tree fn, tree type) +{ + if (fn == NULL_TREE || type == NULL_TREE + || !(TREE_CODE (type) == RECORD_TYPE + || TREE_CODE (type) == UNION_TYPE)) + return; + + tree has_cold_attr = lookup_attribute ("cold", TYPE_ATTRIBUTES (type)); + tree has_hot_attr = lookup_attribute ("hot", TYPE_ATTRIBUTES (type)); + + if (has_cold_attr || has_hot_attr) + { + /* Transparently ignore the new warmth attribute if it + conflicts with a present function attribute. Otherwise + decl_attribute would still honour the present attribute, + but producing an undesired warning in the process. */ + + if (has_cold_attr) + { + if (lookup_attribute ("hot", DECL_ATTRIBUTES (fn)) == NULL) + { + tree cold_cons + = tree_cons (get_identifier ("cold"), NULL, NULL); + + decl_attributes (&fn, cold_cons, 0); + } + } + else if (has_hot_attr) + { + if (lookup_attribute ("cold", DECL_ATTRIBUTES (fn)) == NULL) + { + tree hot_cons + = tree_cons (get_identifier ("hot"), NULL, NULL); + + decl_attributes (&fn, hot_cons, 0); + } + } + } +} + /* Return the last pushed declaration for the symbol DECL or NULL when no such declaration exists. */ diff --git a/gcc/cp/method.cc b/gcc/cp/method.cc index 4ba00175048..a70dd5d6adc 100644 --- a/gcc/cp/method.cc +++ b/gcc/cp/method.cc @@ -3592,6 +3592,12 @@ lazily_declare_fn (special_function_kind sfk, tree type) /* Create appropriate clones. */ clone_cdtor (fn, /*update_methods=*/true); + /* Classes, structs or unions TYPE marked with hotness attributes propagate + the attribute to all methods. This is typically done in + check_bases_and_members, but we must also inject them here for deferred + lazily-declared functions. */ + maybe_propagate_warmth_attributes (fn, type); + return fn; } diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 89c5b4ea2b2..ce3c04e0fac 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2867,7 +2867,10 @@ improving code locality of non-cold parts of program. The paths leading to calls of cold functions within code are marked as unlikely by the branch prediction mechanism. It is thus useful to mark functions used to handle unlikely conditions, such as @code{perror}, as cold to improve optimization -of hot functions that do call marked functions in rare occasions. +of hot functions that do call marked functions in rare occasions. In C++, +the @code{cold} attribute can be applied to types with the effect of being +propagated to member functions. See +@ref{C++ Attributes}. When profile feedback is available, via @option{-fprofile-use}, cold functions are automatically detected and this attribute is ignored. @@ -3286,7 +3289,9 @@ The @code{hot} attribute on a function is used to inform the compiler that the function is a hot spot of the compiled program. The function is optimized more aggressively and on many targets it is placed into a special subsection of the text section so all hot functions appear close together, -improving locality. +improving locality. In C++, the @code{hot} attribute can be applied to types +with the effect of being propagated to member functions. See +@ref{C++ Attributes}. When profile feedback is available, via @option{-fprofile-use}, hot functions are automatically detected and this attribute is ignored. @@ -25537,6 +25542,34 @@ control a resource, such as @code{std::lock_guard}. This attribute is also accepted in C, but it is unnecessary because C does not have constructors or destructors. +@cindex @code{cold} type attribute +@item cold + +In addition to functions and labels, GNU C++ allows the @code{cold} +attribute to be used on C++ classes, structs, or unions. Applying +the @code{cold} attribute on a type has the effect of treating every +member function of the type, including implicit special member +functions, as cold. If a member function is marked with the +@code{hot} function attribute, the @code{hot} attribute takes +precedence and the @code{cold} attribute is not propagated. + +For the effects of the @code{cold} attribute on functions, see +@ref{Common Function Attributes}. + +@cindex @code{hot} type attribute +@item hot + +In addition to functions and labels, GNU C++ allows the @code{hot} +attribute to be used on C++ classes, structs, or unions. Applying +the @code{hot} attribute on a type has the effect of treating every +member function of the type, including implicit special member +functions, as hot. If a member function is marked with the +@code{cold} function attribute, the @code{cold} attribute takes +precedence and the @code{hot} attribute is not propagated. + +For the effects of the @code{hot} attribute on functions, see +@ref{Common Function Attributes}. + @end table @node Function Multiversioning 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 00000000000..f9a6930304d --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/attr-hotness.C @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O0 -Wattributes -fdump-tree-gimple" } */ + + +struct __attribute((cold)) A { __attribute((noinline, used)) void foo(void) { } }; + +struct __attribute((hot)) B { __attribute((noinline, used)) void foo(void) { } }; + +struct __attribute((hot, cold)) C { __attribute((noinline, used)) void foo(void) { } }; /* { dg-warning "ignoring attribute .cold. because it conflicts with attribute .hot." } */ + +struct __attribute((cold, hot)) D { __attribute((noinline, used)) 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" } } */ + -- 2.34.1