From patchwork Mon Feb 29 09:17:20 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric Botcazou X-Patchwork-Id: 589785 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 15690140557 for ; Mon, 29 Feb 2016 20:17:35 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=yLPDEV+a; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type :content-transfer-encoding; q=dns; s=default; b=BNM4PQ7URd23hM2l 8yol+k5j4cRJ8BSM1o9QHika64RSZZsluoSA7Clwsikr6R/T6DsoYvphONDBBXZD IAmsu/bXmchlnXfneMS8qDTQX35SKE5C/mhHEk2BxXbBrnrVvNq5+9pZwykVOhVm wsZAEKP5EpZEtkm0VxLRsLfPijA= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id:mime-version:content-type :content-transfer-encoding; s=default; bh=NKTgSn1caPuZdG2sjpKT0C R7PnY=; b=yLPDEV+aXXDIHqzj4rBNB3v/rH1fvQyhc7HyS/fujdl01lX+U2Fzgx uZBWxu0jQHjJgxu2dqKfkefidWGIa/5RH028EKBEoDljuBx3dR9acX/f248eNUvP NnZH8eBMoG0/bxkFd4v8hxqRu0D4ZDSJo6NnUG79crNUjk6J3N0IM= Received: (qmail 71469 invoked by alias); 29 Feb 2016 09:17:26 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 71410 invoked by uid 89); 29 Feb 2016 09:17:26 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=0.8 required=5.0 tests=AWL, BAYES_50, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.2 spammy=slice, binding, overlapping, UD:ads X-HELO: smtp.eu.adacore.com Received: from mel.act-europe.fr (HELO smtp.eu.adacore.com) (194.98.77.210) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES256-GCM-SHA384 encrypted) ESMTPS; Mon, 29 Feb 2016 09:17:24 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id B11E5812ED for ; Mon, 29 Feb 2016 10:17:21 +0100 (CET) Received: from smtp.eu.adacore.com ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id Jk5MHzqXxSdf for ; Mon, 29 Feb 2016 10:17:21 +0100 (CET) Received: from polaris.localnet (bon31-6-88-161-99-133.fbx.proxad.net [88.161.99.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.eu.adacore.com (Postfix) with ESMTPSA id 77F18812C8 for ; Mon, 29 Feb 2016 10:17:21 +0100 (CET) From: Eric Botcazou To: gcc-patches@gcc.gnu.org Subject: [Ada] Fix unexpectedly large frame with calls manipulating strings Date: Mon, 29 Feb 2016 10:17:20 +0100 Message-ID: <10048785.2YUzE6MUlj@polaris> User-Agent: KMail/4.14.9 (Linux/3.16.7-35-desktop; KDE/4.14.9; x86_64; ; ) MIME-Version: 1.0 Another long-standing regression present in the compiler (dating back to the Tree-SSA merge): the compiler generates code that has an unexpectedly large stack usage for nested calls on strings, because the gimplifier creates temporaries in the outermost scope that have overlapping live ranges. Tested on x86_64-suse-linux, applied on the mainline. 2016-02-29 Eric Botcazou * gcc-interface/trans.c (finalize_nrv_r): Remove obsolete code. (build_return_expr): Likewise. (Call_to_gnu): If this is a function call and there is no target, create a temporary for the return value for all aggregate types, but never create it for a return statement. Push a binding level around the call in more cases. Remove obsolete code. 2016-02-29 Eric Botcazou * gnat.dg/stack_usage3.adb: New test. * gnat.dg/stack_usage3_pkg.ads: New helper. Index: gcc-interface/trans.c =================================================================== --- gcc-interface/trans.c (revision 233804) +++ gcc-interface/trans.c (working copy) @@ -3330,32 +3330,14 @@ finalize_nrv_r (tree *tp, int *walk_subt else if (TREE_CODE (t) == RETURN_EXPR && TREE_CODE (TREE_OPERAND (t, 0)) == INIT_EXPR) { - tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1), init_expr; - - /* If this is the temporary created for a return value with variable - size in Call_to_gnu, we replace the RHS with the init expression. */ - if (TREE_CODE (ret_val) == COMPOUND_EXPR - && TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR - && TREE_OPERAND (TREE_OPERAND (ret_val, 0), 0) - == TREE_OPERAND (ret_val, 1)) - { - init_expr = TREE_OPERAND (TREE_OPERAND (ret_val, 0), 1); - ret_val = TREE_OPERAND (ret_val, 1); - } - else - init_expr = NULL_TREE; + tree ret_val = TREE_OPERAND (TREE_OPERAND (t, 0), 1); /* Strip useless conversions around the return value. */ if (gnat_useless_type_conversion (ret_val)) ret_val = TREE_OPERAND (ret_val, 0); if (is_nrv_p (dp->nrv, ret_val)) - { - if (init_expr) - TREE_OPERAND (TREE_OPERAND (t, 0), 1) = init_expr; - else - TREE_OPERAND (t, 0) = dp->result; - } + TREE_OPERAND (t, 0) = dp->result; } /* Replace the DECL_EXPR of NRVs with an initialization of the RESULT_DECL, @@ -3659,14 +3641,6 @@ build_return_expr (tree ret_obj, tree re && TYPE_MODE (operation_type) == BLKmode && aggregate_value_p (operation_type, current_function_decl)) { - /* Recognize the temporary created for a return value with variable - size in Call_to_gnu. We want to eliminate it if possible. */ - if (TREE_CODE (ret_val) == COMPOUND_EXPR - && TREE_CODE (TREE_OPERAND (ret_val, 0)) == INIT_EXPR - && TREE_OPERAND (TREE_OPERAND (ret_val, 0), 0) - == TREE_OPERAND (ret_val, 1)) - ret_val = TREE_OPERAND (ret_val, 1); - /* Strip useless conversions around the return value. */ if (gnat_useless_type_conversion (ret_val)) ret_val = TREE_OPERAND (ret_val, 0); @@ -4314,14 +4288,22 @@ Call_to_gnu (Node_Id gnat_node, tree *gn because we need to preserve the return value before copying back the parameters. - 2. There is no target and this is neither an object nor a renaming - declaration, and the return type has variable size, because in - these cases the gimplifier cannot create the temporary. + 2. There is no target and the call is made for neither an object nor a + renaming declaration, nor a return statement, and the return type has + variable size, because in this case the gimplifier cannot create the + temporary, or more generally is simply an aggregate type, because the + gimplifier would create the temporary in the outermost scope instead + of locally. 3. There is a target and it is a slice or an array with fixed size, and the return type has variable size, because the gimplifier doesn't handle these cases. + 4. There is no target and we have misaligned In Out or Out parameters + passed by reference, because we need to preserve the return value + before copying back the parameters. However, in this case, we'll + defer creating the temporary, see below. + This must be done before we push a binding level around the call, since we will pop it before copying the return value. */ if (function_call @@ -4329,7 +4311,9 @@ Call_to_gnu (Node_Id gnat_node, tree *gn || (!gnu_target && Nkind (Parent (gnat_node)) != N_Object_Declaration && Nkind (Parent (gnat_node)) != N_Object_Renaming_Declaration - && TREE_CODE (TYPE_SIZE (gnu_result_type)) != INTEGER_CST) + && Nkind (Parent (gnat_node)) != N_Simple_Return_Statement + && AGGREGATE_TYPE_P (gnu_result_type) + && !TYPE_IS_FAT_POINTER_P (gnu_result_type)) || (gnu_target && (TREE_CODE (gnu_target) == ARRAY_RANGE_REF || (TREE_CODE (TREE_TYPE (gnu_target)) == ARRAY_TYPE @@ -4341,6 +4325,16 @@ Call_to_gnu (Node_Id gnat_node, tree *gn DECL_RETURN_VALUE_P (gnu_retval) = 1; } + /* If we don't need a value or have already created it, push a binding level + around the call. This will narrow the lifetime of the temporaries we may + need to make when translating the parameters as much as possible. */ + if (!returning_value || gnu_retval) + { + start_stmt_group (); + gnat_pushlevel (); + pushed_binding_level = true; + } + /* Create the list of the actual parameters as GCC expects it, namely a chain of TREE_LIST nodes in which the TREE_VALUE field of each node is an expression and the TREE_PURPOSE field is null. But skip Out @@ -4469,12 +4463,10 @@ Call_to_gnu (Node_Id gnat_node, tree *gn DECL_RETURN_VALUE_P (gnu_retval) = 1; } - /* If we haven't pushed a binding level, push a new one. This will - narrow the lifetime of the temporary we are about to make as much - as possible. The drawback is that we'd need to create a temporary - for the return value, if any (see comment before the loop). So do - it only when this temporary was already created just above. */ - if (!pushed_binding_level && !(in_param && returning_value)) + /* If we haven't pushed a binding level, push it now. This will + narrow the lifetime of the temporary we are about to make as + much as possible. */ + if (!pushed_binding_level && (!returning_value || gnu_retval)) { start_stmt_group (); gnat_pushlevel (); @@ -4705,15 +4697,6 @@ Call_to_gnu (Node_Id gnat_node, tree *gn if (!gnu_retval) { tree gnu_stmt; - /* If we haven't pushed a binding level, push a new one. This - will narrow the lifetime of the temporary we are about to - make as much as possible. */ - if (!pushed_binding_level) - { - start_stmt_group (); - gnat_pushlevel (); - pushed_binding_level = true; - } gnu_call = create_init_temporary ("P", gnu_call, &gnu_stmt, gnat_node); append_to_statement_list (gnu_stmt, &gnu_stmt_list);