From patchwork Thu Dec 8 18:34:44 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 1713841 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) 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=BjIXYrc5; dkim-atps=neutral Received: from sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-384) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NSjWk2M4dz23p1 for ; Fri, 9 Dec 2022 05:35:29 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1437C3884FBD for ; Thu, 8 Dec 2022 18:35:27 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1437C3884FBD DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1670524527; bh=pD3UopbfC6nQn8wAZj1W1ixpBOtPIZZXlOnT2nhXL8s=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=BjIXYrc5Hb2rh7hX7Cn70S9rkp+q+aNI3iQJ2l5V+bpqRmf/5tb99NCeLnqJqJaoh hDMBdxUSY5HUbjwF2ACxwUr9LhtWEJKSQqHZUDJEorq5NyoGKxxBci+f0jQNizGw8y il5/fzhN7Y1ptVkP+g6t6LzYLBC4Raa1X8hUd6h8= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id E56FF39DD7D0 for ; Thu, 8 Dec 2022 18:34:50 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org E56FF39DD7D0 Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-601-NRFXJKw9P1ydmV818Rkptw-1; Thu, 08 Dec 2022 13:34:49 -0500 X-MC-Unique: NRFXJKw9P1ydmV818Rkptw-1 Received: by mail-qk1-f198.google.com with SMTP id u5-20020a05620a0c4500b006fb30780443so2337289qki.22 for ; Thu, 08 Dec 2022 10:34:49 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:message-id:date:subject:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=pD3UopbfC6nQn8wAZj1W1ixpBOtPIZZXlOnT2nhXL8s=; b=vMlTbM1y0wD8gzPs2FXRzOEkM+/JHGqNmCHgoZocR7MIlGv4OTwfhFoyK8psjJcM81 r67b+E5eCnpGNcYeFA/WTl7uwIShP0L33ddxK2cOXiSAyXSCNZTE8kSWvWWU96ye8urI /FvFLUxi3dLKAEamrwpNG522kV18H/PLr8T4fuKgyOkQl1F9np0GrNfPD8hu6MvTyjBk 4oeZ+1zNzK3Pfr76Em9tb1bdzhvEL/0ZzOd0wo5IVm+lZfIwfjF+QrJnNUYflWDp6Y7R aUxgb2/VlAW8draKPftiyz+eD80cxdXoRMtOSfwAF6obdZUC+tmMVX0p/Gmb45OBgrrF ZAxw== X-Gm-Message-State: ANoB5pmgiulrR56IGTg75PqHh7EHYN9OwZI7JVhvZbeOt2WWLyk98QFW sb5UzER8QGUxFxh7atzHa0qQ76/IIUNN4m7UmZetxZ7Dy5HMYtjG84/e3UD5mf/7l4BgRg6eCbp u5SGUcGWMN949LK0+HG1S8vVgDKEPBHUxt+UdtzJYtgETBxY6asoJUrjLEwskSfDIsA== X-Received: by 2002:ac8:7c8:0:b0:3a7:ee95:cc37 with SMTP id m8-20020ac807c8000000b003a7ee95cc37mr4317208qth.14.1670524488726; Thu, 08 Dec 2022 10:34:48 -0800 (PST) X-Google-Smtp-Source: AA0mqf6MZsCxuB3g4E98abazWpW0qFoI6EcXiZN5NN/XSSJxsPx5Bx5J2qCmI5nLSX4KOXF1jj92hA== X-Received: by 2002:ac8:7c8:0:b0:3a7:ee95:cc37 with SMTP id m8-20020ac807c8000000b003a7ee95cc37mr4317160qth.14.1670524488127; Thu, 08 Dec 2022 10:34:48 -0800 (PST) Received: from jason.com (130-44-159-43.s15913.c3-0.arl-cbr1.sbo-arl.ma.cable.rcncustomer.com. [130.44.159.43]) by smtp.gmail.com with ESMTPSA id f40-20020a05622a1a2800b003a7f4c69334sm2850723qtb.24.2022.12.08.10.34.47 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 10:34:47 -0800 (PST) To: gcc-patches@gcc.gnu.org Subject: [pushed] c++: fewer allocator temps [PR105838] Date: Thu, 8 Dec 2022 13:34:44 -0500 Message-Id: <20221208183444.1648084-1-jason@redhat.com> X-Mailer: git-send-email 2.31.1 MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-12.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, 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-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: Jason Merrill via Gcc-patches From: Jason Merrill Reply-To: Jason Merrill Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org Sender: "Gcc-patches" Tested x86_64-pc-linux-gnu, applying to trunk. -- 8< -- In this PR, initializing the array of std::string to pass to the vector initializer_list constructor gets very confusing to the optimizers as the number of elements increases, primarily because of all the std::allocator temporaries passed to all the string constructors. Instead of creating one for each string, let's share an allocator between all the strings; we can do this safely because we know that std::allocator is stateless and that string doesn't care about the object identity of its allocator parameter. PR c++/105838 gcc/cp/ChangeLog: * cp-tree.h (is_std_allocator): Declare. * constexpr.cc (is_std_allocator): Split out from... (is_std_allocator_allocate): ...here. * init.cc (find_temps_r): New. (find_allocator_temp): New. (build_vec_init): Use it. gcc/testsuite/ChangeLog: * g++.dg/tree-ssa/allocator-opt1.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/constexpr.cc | 27 +++++---- gcc/cp/init.cc | 59 ++++++++++++++++++- .../g++.dg/tree-ssa/allocator-opt1.C | 12 ++++ 4 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/allocator-opt1.C base-commit: 3da5ae7a347b7d74765053f4a08eaf7ec58f8735 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index addd26ea077..581ac2b1817 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8472,6 +8472,7 @@ extern bool is_rvalue_constant_expression (tree); extern bool is_nondependent_constant_expression (tree); extern bool is_nondependent_static_init_expression (tree); extern bool is_static_init_expression (tree); +extern bool is_std_allocator (tree); extern bool potential_rvalue_constant_expression (tree); extern bool require_potential_constant_expression (tree); extern bool require_constant_expression (tree); diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc index 23a27a962de..e43d92864f5 100644 --- a/gcc/cp/constexpr.cc +++ b/gcc/cp/constexpr.cc @@ -2214,6 +2214,22 @@ is_std_construct_at (const constexpr_call *call) && is_std_construct_at (call->fundef->decl)); } +/* True if CTX is an instance of std::allocator. */ + +bool +is_std_allocator (tree ctx) +{ + if (ctx == NULL_TREE || !CLASS_TYPE_P (ctx) || !TYPE_MAIN_DECL (ctx)) + return false; + + tree decl = TYPE_MAIN_DECL (ctx); + tree name = DECL_NAME (decl); + if (name == NULL_TREE || !id_equal (name, "allocator")) + return false; + + return decl_in_std_namespace_p (decl); +} + /* Return true if FNDECL is std::allocator::{,de}allocate. */ static inline bool @@ -2224,16 +2240,7 @@ is_std_allocator_allocate (tree fndecl) || !(id_equal (name, "allocate") || id_equal (name, "deallocate"))) return false; - tree ctx = DECL_CONTEXT (fndecl); - if (ctx == NULL_TREE || !CLASS_TYPE_P (ctx) || !TYPE_MAIN_DECL (ctx)) - return false; - - tree decl = TYPE_MAIN_DECL (ctx); - name = DECL_NAME (decl); - if (name == NULL_TREE || !id_equal (name, "allocator")) - return false; - - return decl_in_std_namespace_p (decl); + return is_std_allocator (DECL_CONTEXT (fndecl)); } /* Overload for the above taking constexpr_call*. */ diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc index 2fff4ad2dc7..428fac5621c 100644 --- a/gcc/cp/init.cc +++ b/gcc/cp/init.cc @@ -4308,6 +4308,51 @@ finish_length_check (tree atype, tree iterator, tree obase, unsigned n) } } +/* walk_tree callback to collect temporaries in an expression. */ + +tree +find_temps_r (tree *tp, int *walk_subtrees, void *data) +{ + vec &temps = *static_cast *>(data); + tree t = *tp; + if (TREE_CODE (t) == TARGET_EXPR + && !TARGET_EXPR_ELIDING_P (t)) + temps.safe_push (tp); + else if (TYPE_P (t)) + *walk_subtrees = 0; + + return NULL_TREE; +} + +/* If INIT initializes a standard library class, and involves a temporary + std::allocator, return a pointer to the temp. + + Used by build_vec_init when initializing an array of e.g. strings to reuse + the same temporary allocator for all of the strings. We can do this because + std::allocator has no data and the standard library doesn't care about the + address of allocator objects. + + ??? Add an attribute to allow users to assert the same property for other + classes, i.e. one object of the type is interchangeable with any other? */ + +static tree* +find_allocator_temp (tree init) +{ + if (TREE_CODE (init) == EXPR_STMT) + init = EXPR_STMT_EXPR (init); + if (TREE_CODE (init) == CONVERT_EXPR) + init = TREE_OPERAND (init, 0); + tree type = TREE_TYPE (init); + if (!CLASS_TYPE_P (type) || !decl_in_std_namespace_p (TYPE_NAME (type))) + return NULL; + auto_vec temps; + cp_walk_tree_without_duplicates (&init, find_temps_r, &temps); + for (tree *p : temps) + if (is_std_allocator (TREE_TYPE (*p))) + return p; + return NULL; +} + /* `build_vec_init' returns tree structure that performs initialization of a vector of aggregate types. @@ -4589,6 +4634,8 @@ build_vec_init (tree base, tree maxindex, tree init, if (try_const) vec_alloc (const_vec, CONSTRUCTOR_NELTS (init)); + tree alloc_obj = NULL_TREE; + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, elt) { tree baseref = build1 (INDIRECT_REF, type, base); @@ -4638,7 +4685,17 @@ build_vec_init (tree base, tree maxindex, tree init, } if (one_init) - finish_expr_stmt (one_init); + { + /* Only create one std::allocator temporary. */ + if (tree *this_alloc = find_allocator_temp (one_init)) + { + if (alloc_obj) + *this_alloc = alloc_obj; + else + alloc_obj = TARGET_EXPR_SLOT (*this_alloc); + } + finish_expr_stmt (one_init); + } one_init = cp_build_unary_op (PREINCREMENT_EXPR, base, false, complain); diff --git a/gcc/testsuite/g++.dg/tree-ssa/allocator-opt1.C b/gcc/testsuite/g++.dg/tree-ssa/allocator-opt1.C new file mode 100644 index 00000000000..e8394c7ad70 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/allocator-opt1.C @@ -0,0 +1,12 @@ +// PR c++/105838 +// { dg-additional-options -fdump-tree-gimple } + +// Check that there's only one allocator (temporary) variable. +// Currently the dump doesn't print the allocator template arg in this context. +// { dg-final { scan-tree-dump-times "struct allocator D" 1 "gimple" } } + +#include +void f (const char *p) +{ + std::string lst[] = { p, p, p, p }; +}