From patchwork Thu Dec 8 18:41:11 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jason Merrill X-Patchwork-Id: 1713844 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=AH5Riaem; dkim-atps=neutral Received: from sourceware.org (ip-8-43-85-97.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 4NSjfw2gJNz23pD for ; Fri, 9 Dec 2022 05:41:42 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 25F48389BC97 for ; Thu, 8 Dec 2022 18:41:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 25F48389BC97 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1670524900; bh=tRuwZr9pJCsDkUAQ5hhSzeh5X4LgXTGq76JF9iVsKOM=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=AH5RiaemUE+V6DAsZECd2OjLEfu+x3H8426VWQbmiB0wAVVjWo65Z2IPHxrTMv2Ik 58nuZMUOIgc/veT7ugzD2n0mAll7n77YvSPddJG89BjAgQsukJtG2BjtxodiAFdK1F sydeEMuZscqsKoHWQUdRG/eUMYjcjmkHhvU+3EIg= 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.133.124]) by sourceware.org (Postfix) with ESMTPS id 90D92389C03E for ; Thu, 8 Dec 2022 18:41:16 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 90D92389C03E Received: from mail-qv1-f70.google.com (mail-qv1-f70.google.com [209.85.219.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-456-sTXJTqM9Pqiind_HE_pJpQ-1; Thu, 08 Dec 2022 13:41:15 -0500 X-MC-Unique: sTXJTqM9Pqiind_HE_pJpQ-1 Received: by mail-qv1-f70.google.com with SMTP id nk7-20020a056214350700b004c68c912c93so2160678qvb.16 for ; Thu, 08 Dec 2022 10:41:15 -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=tRuwZr9pJCsDkUAQ5hhSzeh5X4LgXTGq76JF9iVsKOM=; b=MNNkwGJinywG/DxMZeAt++ufPFbymVpnWir+4Wb2dCGuGVoyzo1LlS0zlxLcwpF3LH ptZ1Sczng00Xp96/mGfZiQ1MLbU5yNCcWPMq9eO42qRYIuM4vMVOdf7aEStPAsBwHxcN cLqTAgyHVhCeb7eeBxpbDg13TXlhW8/mLwVVCFQTrWv17ZNxFwOodNSrVYm5NdCumvHY QTDxWvdiHESBmZtgxsQ1Y5ZbhVRDiDIXMxWGPMfGaDVFU8k7XqC+sW6ATpY6qCRDXO2I Q2pkw58/6A4sI2huxXfaD3QoHIytRXH4I34lGhVwPqfhvhYa3auwd3a7aWMiyWAU2wlM HIjQ== X-Gm-Message-State: ANoB5pmf4ARkw8W/s5XBbTJbV83NQxJXAWePV5bEV/GPQeHDAyJGTsdj Myat8tw8plVyGlXo9JpgouvwQU4guVkqNOmTrvuRaMEdVrY0uU8BMN0gGT67H2Q6TcRERZJkWld 28HdI5deEdCUnlTbWgo0wojeAudMmyQiglmwOnYMbf/RighgV2KMQx95dbeQr2tCS0g== X-Received: by 2002:a05:622a:4a87:b0:3a4:ec42:48d2 with SMTP id fw7-20020a05622a4a8700b003a4ec4248d2mr5064728qtb.2.1670524874450; Thu, 08 Dec 2022 10:41:14 -0800 (PST) X-Google-Smtp-Source: AA0mqf7kfJK13ACawXCzDCOz2/3F9AldeNdO2LST1hs2VAmakd+oPjjmAY+yxBOn+qL21k2NmHSyGg== X-Received: by 2002:a05:622a:4a87:b0:3a4:ec42:48d2 with SMTP id fw7-20020a05622a4a8700b003a4ec4248d2mr5064701qtb.2.1670524873909; Thu, 08 Dec 2022 10:41:13 -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 x26-20020a05620a0b5a00b006cfc01b4461sm18064865qkg.118.2022.12.08.10.41.13 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 08 Dec 2022 10:41:13 -0800 (PST) To: gcc-patches@gcc.gnu.org Subject: [pushed] c++: avoid initializer_list [PR105838] Date: Thu, 8 Dec 2022 13:41:11 -0500 Message-Id: <20221208184111.1649145-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< -- When constructing a vector from { "strings" }, first is built an initializer_list, which is then copied into the strings in the vector. But this is inefficient: better would be treat the { "strings" } as a range and construct the strings in the vector directly from the string-literals. We can do this transformation for standard library classes because we know the design patterns they follow. PR c++/105838 gcc/cp/ChangeLog: * call.cc (list_ctor_element_type): New. (braced_init_element_type): New. (has_non_trivial_temporaries): New. (maybe_init_list_as_array): New. (maybe_init_list_as_range): New. (build_user_type_conversion_1): Use maybe_init_list_as_range. * parser.cc (cp_parser_braced_list): Call recompute_constructor_flags. * cp-tree.h (find_temps_r): Declare. gcc/testsuite/ChangeLog: * g++.dg/tree-ssa/initlist-opt1.C: New test. --- gcc/cp/cp-tree.h | 1 + gcc/cp/call.cc | 138 ++++++++++++++++++ gcc/cp/parser.cc | 1 + gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C | 25 ++++ 4 files changed, 165 insertions(+) create mode 100644 gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C base-commit: 1e1847612d7f169f82c985b0b3a5e3301d6fe999 diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 581ac2b1817..0d6c234b3b0 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7087,6 +7087,7 @@ extern void set_global_friend (tree); extern bool is_global_friend (tree); /* in init.cc */ +extern tree find_temps_r (tree *, int *, void *); extern tree expand_member_init (tree); extern void emit_mem_initializers (tree); extern tree build_aggr_init (tree, tree, int, diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc index 459e86b5f09..33b5e7f87f5 100644 --- a/gcc/cp/call.cc +++ b/gcc/cp/call.cc @@ -4154,6 +4154,134 @@ add_list_candidates (tree fns, tree first_arg, access_path, flags, candidates, complain); } +/* Given C(std::initializer_list), return A. */ + +static tree +list_ctor_element_type (tree fn) +{ + gcc_checking_assert (is_list_ctor (fn)); + + tree parm = FUNCTION_FIRST_USER_PARMTYPE (fn); + parm = non_reference (TREE_VALUE (parm)); + return TREE_VEC_ELT (CLASSTYPE_TI_ARGS (parm), 0); +} + +/* If EXPR is a braced-init-list where the elements all decay to the same type, + return that type. */ + +static tree +braced_init_element_type (tree expr) +{ + if (TREE_CODE (expr) == CONSTRUCTOR + && TREE_CODE (TREE_TYPE (expr)) == ARRAY_TYPE) + return TREE_TYPE (TREE_TYPE (expr)); + if (!BRACE_ENCLOSED_INITIALIZER_P (expr)) + return NULL_TREE; + + tree elttype = NULL_TREE; + for (constructor_elt &e: CONSTRUCTOR_ELTS (expr)) + { + tree type = TREE_TYPE (e.value); + type = type_decays_to (type); + if (!elttype) + elttype = type; + else if (!same_type_p (type, elttype)) + return NULL_TREE; + } + return elttype; +} + +/* True iff EXPR contains any temporaries with non-trivial destruction. + + ??? Also ignore classes with non-trivial but no-op destruction other than + std::allocator? */ + +static bool +has_non_trivial_temporaries (tree expr) +{ + auto_vec temps; + cp_walk_tree_without_duplicates (&expr, find_temps_r, &temps); + for (tree *p : temps) + { + tree t = TREE_TYPE (*p); + if (!TYPE_HAS_TRIVIAL_DESTRUCTOR (t) + && !is_std_allocator (t)) + return true; + } + return false; +} + +/* We're initializing an array of ELTTYPE from INIT. If it seems useful, + return INIT as an array (of its own type) so the caller can initialize the + target array in a loop. */ + +static tree +maybe_init_list_as_array (tree elttype, tree init) +{ + /* Only do this if the array can go in rodata but not once converted. */ + if (!CLASS_TYPE_P (elttype)) + return NULL_TREE; + tree init_elttype = braced_init_element_type (init); + if (!init_elttype || !SCALAR_TYPE_P (init_elttype) || !TREE_CONSTANT (init)) + return NULL_TREE; + + tree first = CONSTRUCTOR_ELT (init, 0)->value; + if (TREE_CODE (init_elttype) == INTEGER_TYPE && null_ptr_cst_p (first)) + /* Avoid confusion from treating 0 as a null pointer constant. */ + first = build1 (UNARY_PLUS_EXPR, init_elttype, first); + first = (perform_implicit_conversion_flags + (elttype, first, tf_none, LOOKUP_IMPLICIT|LOOKUP_NO_NARROWING)); + if (first == error_mark_node) + /* Let the normal code give the error. */ + return NULL_TREE; + + /* Don't do this if the conversion would be constant. */ + first = maybe_constant_init (first); + if (TREE_CONSTANT (first)) + return NULL_TREE; + + /* We can't do this if the conversion creates temporaries that need + to live until the whole array is initialized. */ + if (has_non_trivial_temporaries (first)) + return NULL_TREE; + + init_elttype = cp_build_qualified_type (init_elttype, TYPE_QUAL_CONST); + tree arr = build_array_of_n_type (init_elttype, CONSTRUCTOR_NELTS (init)); + return finish_compound_literal (arr, init, tf_none); +} + +/* If we were going to call e.g. vector(initializer_list) starting + with a list of string-literals (which is inefficient, see PR105838), + instead build an array of const char* and pass it to the range constructor. + But only do this for standard library types, where we can assume the + transformation makes sense. + + Really the container classes should have initializer_list constructors to + get the same effect more simply; this is working around that lack. */ + +static tree +maybe_init_list_as_range (tree fn, tree expr) +{ + if (BRACE_ENCLOSED_INITIALIZER_P (expr) + && is_list_ctor (fn) + && decl_in_std_namespace_p (fn)) + { + tree to = list_ctor_element_type (fn); + if (tree init = maybe_init_list_as_array (to, expr)) + { + tree begin = decay_conversion (TARGET_EXPR_SLOT (init), tf_none); + tree nelts = array_type_nelts_top (TREE_TYPE (init)); + tree end = cp_build_binary_op (input_location, PLUS_EXPR, begin, + nelts, tf_none); + begin = cp_build_compound_expr (init, begin, tf_none); + return build_constructor_va (init_list_type_node, 2, + NULL_TREE, begin, NULL_TREE, end); + } + } + + return NULL_TREE; +} + /* Returns the best overload candidate to perform the requested conversion. This function is used for three the overloading situations described in [over.match.copy], [over.match.conv], and [over.match.ref]. @@ -4425,6 +4553,16 @@ build_user_type_conversion_1 (tree totype, tree expr, int flags, return cand; } + /* Maybe pass { } as iterators instead of an initializer_list. */ + if (tree iters = maybe_init_list_as_range (cand->fn, expr)) + if (z_candidate *cand2 + = build_user_type_conversion_1 (totype, iters, flags, tf_none)) + if (cand2->viable == 1) + { + cand = cand2; + expr = iters; + } + tree convtype; if (!DECL_CONSTRUCTOR_P (cand->fn)) convtype = non_reference (TREE_TYPE (TREE_TYPE (cand->fn))); diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc index e8a50904243..4798aae1fbb 100644 --- a/gcc/cp/parser.cc +++ b/gcc/cp/parser.cc @@ -25445,6 +25445,7 @@ cp_parser_braced_list (cp_parser* parser, bool* non_constant_p) location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location; braces.require_close (parser); TREE_TYPE (initializer) = init_list_type_node; + recompute_constructor_flags (initializer); cp_expr result (initializer); /* Build a location of the form: diff --git a/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C new file mode 100644 index 00000000000..053317b59d8 --- /dev/null +++ b/gcc/testsuite/g++.dg/tree-ssa/initlist-opt1.C @@ -0,0 +1,25 @@ +// PR c++/105838 +// { dg-additional-options -fdump-tree-gimple } +// { dg-do compile { target c++11 } } + +// Test that we do range-initialization from const char *. +// { dg-final { scan-tree-dump {_M_range_initialize} "gimple" } } + +#include +#include + +void g (const void *); + +void f (const char *p) +{ + std::vector lst = { + "aahing", "aaliis", "aarrgh", "abacas", "abacus", "abakas", "abamps", "abands", "abased", "abaser", "abases", "abasia", + "abated", "abater", "abates", "abatis", "abator", "abattu", "abayas", "abbacy", "abbess", "abbeys", "abbots", "abcees", + "abdabs", "abduce", "abduct", "abears", "abeigh", "abeles", "abelia", "abends", "abhors", "abided", "abider", "abides", + "abject", "abjure", "ablate", "ablaut", "ablaze", "ablest", "ablets", "abling", "ablins", "abloom", "ablush", "abmhos", + "aboard", "aboded", "abodes", "abohms", "abolla", "abomas", "aboral", "abords", "aborne", "aborts", "abound", "abouts", + "aboves", "abrade", "abraid", "abrash", "abrays", "abrazo", "abrege", "abrins", "abroad", "abrupt", "abseil", "absent", + }; + + g(&lst); +}