From patchwork Mon Jun 11 09:21:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pierre-Marie de Rodat X-Patchwork-Id: 927534 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-479430-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=adacore.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="tYXIE75s"; dkim-atps=neutral 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 4146wG6TPBz9ryk for ; Mon, 11 Jun 2018 19:21:50 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:cc:subject:message-id:mime-version:content-type; q=dns; s=default; b=Il/GKZMPF3d1c8xTd4HIrbtxHhPogZZKqjtB7KA4a8QOaE28ba FljDAXtwAnjOYy31QMVgYQOqwqsCjfh4Aq3bBLegMBTFIvld/HuB+4UgvO1bjlGA 99Vr0MORs0cxA1l6MSBrSry/NRYHeI0LCD6f+CUqEg9qxmmwzq54ZlaeU= 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:date :from:to:cc:subject:message-id:mime-version:content-type; s= default; bh=idCDYejZ/dHN2YJdEoVUvvawDsA=; b=tYXIE75szIx+L+JBsIi5 Fk8JMOMu2w3RRkAuQvaZO2oc6sapuuoP8i5iYG+LjnoGCCg132kjutL2d1PNbpby 3RdmFGVTIJYqF8dhpv+IGGt1n9KWCWaKXTkwbZZHsXmg/RuUnLLIb7OOuLt+sBSD +IGN6oP2ZFiTscvkaj+XpQY= Received: (qmail 16205 invoked by alias); 11 Jun 2018 09:21:40 -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 16082 invoked by uid 89); 11 Jun 2018 09:21:39 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-11.1 required=5.0 tests=BAYES_00, GIT_PATCH_2, GIT_PATCH_3, KAM_ASCII_DIVIDERS, RCVD_IN_DNSWL_NONE, SPF_PASS autolearn=ham version=3.3.2 spammy=role, expanded, falls, acts X-HELO: rock.gnat.com Received: from rock.gnat.com (HELO rock.gnat.com) (205.232.38.15) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Mon, 11 Jun 2018 09:21:35 +0000 Received: from localhost (localhost.localdomain [127.0.0.1]) by filtered-rock.gnat.com (Postfix) with ESMTP id CDE25560ED; Mon, 11 Jun 2018 05:21:33 -0400 (EDT) Received: from rock.gnat.com ([127.0.0.1]) by localhost (rock.gnat.com [127.0.0.1]) (amavisd-new, port 10024) with LMTP id 6e9MUisQ0KKt; Mon, 11 Jun 2018 05:21:33 -0400 (EDT) Received: from tron.gnat.com (tron.gnat.com [IPv6:2620:20:4000:0:46a8:42ff:fe0e:e294]) by rock.gnat.com (Postfix) with ESMTP id BBF4C560EC; Mon, 11 Jun 2018 05:21:33 -0400 (EDT) Received: by tron.gnat.com (Postfix, from userid 4862) id BAF0654C; Mon, 11 Jun 2018 05:21:33 -0400 (EDT) Date: Mon, 11 Jun 2018 05:21:33 -0400 From: Pierre-Marie de Rodat To: gcc-patches@gcc.gnu.org Cc: Hristian Kirtchev Subject: [Ada] Performance degradation with references Message-ID: <20180611092133.GA134814@adacore.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) X-IsSubscribed: yes This patch modifies the creation of markers for variable references in the context of SPARK elaboration checks. Previously, prior to checking whether a reference requires such a marker, the compiler performed a logarithmic look up to determine whether the reference appears within a call. This action caused the compiler to degrade when a source program contains multiple (100,000s) references. Now, the compiler no longer performs the look up immediately. Tested on x86_64-pc-linux-gnu, committed on trunk 2018-06-11 Hristian Kirtchev gcc/ada/ * sem_ch8.adb (Find_Direct_Name): Mode the declaration of Is_Assignment_LHS further in. Use predicate Needs_Variable_Reference_Marker to determine whether to create a variable marker. (Find_Expanded_Name): Mode the declaration of Is_Assignment_LHS further in. Use predicate Needs_Variable_Reference_Marker to determine whether to create a variable marker. * sem_elab.adb (Build_Variable_Reference_Marker): Remove the various checks that determine whether the identifier or expanded name is a suitable variable reference. The checks are now performed by Needs_Variable_Reference_Marker. * sem_res.adb (Resolve_Actuals): Use predicate Needs_Variable_Reference_Marker to determine whether to create a variable marker. * sem_util.adb (Needs_Variable_Reference_Marker): New routine. * sem_util.ads (Needs_Variable_Reference_Marker): New routine. --- gcc/ada/sem_ch8.adb +++ gcc/ada/sem_ch8.adb @@ -5423,8 +5423,6 @@ package body Sem_Ch8 is -- Local variables - Is_Assignment_LHS : constant Boolean := Is_LHS (N) = Yes; - Nested_Inst : Entity_Id := Empty; -- The entity of a nested instance which appears within Inst (if any) @@ -5970,11 +5968,19 @@ package body Sem_Ch8 is -- reference is a write when it appears on the left hand side of an -- assignment. - if not Within_Subprogram_Call (N) then - Build_Variable_Reference_Marker - (N => N, - Read => not Is_Assignment_LHS, - Write => Is_Assignment_LHS); + if Needs_Variable_Reference_Marker + (N => N, + Calls_OK => False) + then + declare + Is_Assignment_LHS : constant Boolean := Is_LHS (N) = Yes; + + begin + Build_Variable_Reference_Marker + (N => N, + Read => not Is_Assignment_LHS, + Write => Is_Assignment_LHS); + end; end if; end Find_Direct_Name; @@ -6047,8 +6053,7 @@ package body Sem_Ch8 is -- Local variables - Is_Assignment_LHS : constant Boolean := Is_LHS (N) = Yes; - Selector : constant Node_Id := Selector_Name (N); + Selector : constant Node_Id := Selector_Name (N); Candidate : Entity_Id := Empty; P_Name : Entity_Id; @@ -6621,11 +6626,19 @@ package body Sem_Ch8 is -- reference is a write when it appears on the left hand side of an -- assignment. - if not Within_Subprogram_Call (N) then - Build_Variable_Reference_Marker - (N => N, - Read => not Is_Assignment_LHS, - Write => Is_Assignment_LHS); + if Needs_Variable_Reference_Marker + (N => N, + Calls_OK => False) + then + declare + Is_Assignment_LHS : constant Boolean := Is_LHS (N) = Yes; + + begin + Build_Variable_Reference_Marker + (N => N, + Read => not Is_Assignment_LHS, + Write => Is_Assignment_LHS); + end; end if; end Find_Expanded_Name; @@ -8301,7 +8314,6 @@ package body Sem_Ch8 is ---------------------- procedure Mark_Use_Clauses (Id : Node_Or_Entity_Id) is - procedure Mark_Parameters (Call : Entity_Id); -- Perform use_type_clause marking for all parameters in a subprogram -- or operator call. --- gcc/ada/sem_elab.adb +++ gcc/ada/sem_elab.adb @@ -2072,8 +2072,8 @@ package body Sem_Elab is if Legacy_Elaboration_Checks then return; - -- Nothing to do for ASIS. As a result, ABE checks and diagnostics are - -- not performed in this mode. + -- Nothing to do for ASIS because ABE checks and diagnostics are not + -- performed in this mode. elsif ASIS_Mode then return; @@ -2274,166 +2274,16 @@ package body Sem_Elab is Read : Boolean; Write : Boolean) is - function In_Compilation_Instance_Formal_Part - (Nod : Node_Id) return Boolean; - -- Determine whether arbitrary node Nod appears within the formal part - -- of an instantiation which acts as a compilation unit. - - function In_Pragma (Nod : Node_Id) return Boolean; - -- Determine whether arbitrary node Nod appears within a pragma - - ----------------------------------------- - -- In_Compilation_Instance_Formal_Part -- - ----------------------------------------- - - function In_Compilation_Instance_Formal_Part - (Nod : Node_Id) return Boolean - is - Par : Node_Id; - - begin - Par := Nod; - while Present (Par) loop - if Nkind (Par) = N_Generic_Association - and then Nkind (Parent (Par)) in N_Generic_Instantiation - and then Nkind (Parent (Parent (Par))) = N_Compilation_Unit - then - return True; - - -- Prevent the search from going too far - - elsif Is_Body_Or_Package_Declaration (Par) then - exit; - end if; - - Par := Parent (Par); - end loop; - - return False; - end In_Compilation_Instance_Formal_Part; - - --------------- - -- In_Pragma -- - --------------- - - function In_Pragma (Nod : Node_Id) return Boolean is - Par : Node_Id; - - begin - Par := Nod; - while Present (Par) loop - if Nkind (Par) = N_Pragma then - return True; - - -- Prevent the search from going too far - - elsif Is_Body_Or_Package_Declaration (Par) then - exit; - end if; - - Par := Parent (Par); - end loop; - - return False; - end In_Pragma; - - -- Local variables - Marker : Node_Id; - Prag : Node_Id; Var_Attrs : Variable_Attributes; Var_Id : Entity_Id; - -- Start of processing for Build_Variable_Reference_Marker - begin - -- Nothing to do when switch -gnatH (legacy elaboration checking mode - -- enabled) is in effect because the legacy ABE mechanism does not need - -- to carry out this action. - - if Legacy_Elaboration_Checks then - return; - - -- Nothing to do for ASIS. As a result, ABE checks and diagnostics are - -- not performed in this mode. - - elsif ASIS_Mode then - return; - - -- Nothing to do when the reference is being preanalyzed as the marker - -- will be inserted in the wrong place. - - elsif Preanalysis_Active then - return; - - -- Nothing to do when the input does not denote a reference - - elsif not Nkind_In (N, N_Expanded_Name, N_Identifier) then - return; - - -- Nothing to do for internally-generated references - - elsif not Comes_From_Source (N) then - return; - - -- Nothing to do when the reference is erroneous, left in a bad state, - -- or does not denote a variable. - - elsif not (Present (Entity (N)) - and then Ekind (Entity (N)) = E_Variable - and then Entity (N) /= Any_Id) - then - return; - - -- Nothing to do when the reference appears within the formal part of - -- an instantiation which acts as compilation unit because there is no - -- proper context for the insertion of the marker. - - -- Performance note: parent traversal - - elsif In_Compilation_Instance_Formal_Part (N) then - return; - end if; - Extract_Variable_Reference_Attributes (Ref => N, Var_Id => Var_Id, Attrs => Var_Attrs); - Prag := SPARK_Pragma (Var_Id); - - if Comes_From_Source (Var_Id) - - -- Both the variable and the reference must appear in SPARK_Mode On - -- regions because this scenario falls under the SPARK rules. - - and then Present (Prag) - and then Get_SPARK_Mode_From_Annotation (Prag) = On - and then Is_SPARK_Mode_On_Node (N) - - -- The reference must not be considered when it appears in a pragma. - -- If the pragma has run-time semantics, then the reference will be - -- reconsidered once the pragma is expanded. - - -- Performance note: parent traversal - - and then not In_Pragma (N) - then - null; - - -- Otherwise the reference is not suitable for ABE processing. This - -- prevents the generation of variable markers which will never play - -- a role in ABE diagnostics. - - else - return; - end if; - - -- At this point it is known that the variable reference will play some - -- role in ABE checks and diagnostics. Create a corresponding variable - -- marker in case the original variable reference is folded or optimized - -- away. - Marker := Make_Variable_Reference_Marker (Sloc (N)); -- Inherit the attributes of the original variable reference @@ -2469,8 +2319,8 @@ package body Sem_Elab is if Legacy_Elaboration_Checks then return; - -- Nothing to do for ASIS. As a result, no ABE checks and diagnostics - -- are performed in this mode. + -- Nothing to do for ASIS because ABE checks and diagnostics are not + -- performed in this mode. elsif ASIS_Mode then return; @@ -10860,8 +10710,8 @@ package body Sem_Elab is if Legacy_Elaboration_Checks then return; - -- Nothing to do for ASIS. As a result, no ABE checks and diagnostics - -- are performed in this mode. + -- Nothing to do for ASIS because ABE checks and diagnostics are not + -- performed in this mode. elsif ASIS_Mode then return; --- gcc/ada/sem_res.adb +++ gcc/ada/sem_res.adb @@ -3667,10 +3667,15 @@ package body Sem_Res is -- read IN, IN OUT -- write IN OUT, OUT - Build_Variable_Reference_Marker - (N => A, - Read => Ekind (F) /= E_Out_Parameter, - Write => Ekind (F) /= E_In_Parameter); + if Needs_Variable_Reference_Marker + (N => A, + Calls_OK => True) + then + Build_Variable_Reference_Marker + (N => A, + Read => Ekind (F) /= E_Out_Parameter, + Write => Ekind (F) /= E_In_Parameter); + end if; Orig_A := Entity (A); --- gcc/ada/sem_util.adb +++ gcc/ada/sem_util.adb @@ -19247,6 +19247,144 @@ package body Sem_Util is end if; end Needs_Simple_Initialization; + ------------------------------------- + -- Needs_Variable_Reference_Marker -- + ------------------------------------- + + function Needs_Variable_Reference_Marker + (N : Node_Id; + Calls_OK : Boolean) return Boolean + is + function Within_Suitable_Context (Ref : Node_Id) return Boolean; + -- Deteremine whether variable reference Ref appears within a suitable + -- context that allows the creation of a marker. + + ----------------------------- + -- Within_Suitable_Context -- + ----------------------------- + + function Within_Suitable_Context (Ref : Node_Id) return Boolean is + Par : Node_Id; + + begin + Par := Ref; + while Present (Par) loop + + -- The context is not suitable when the reference appears within + -- the formal part of an instantiation which acts as compilation + -- unit because there is no proper list for the insertion of the + -- marker. + + if Nkind (Par) = N_Generic_Association + and then Nkind (Parent (Par)) in N_Generic_Instantiation + and then Nkind (Parent (Parent (Par))) = N_Compilation_Unit + then + return False; + + -- The context is not suitable when the reference appears within + -- a pragma. If the pragma has run-time semantics, the reference + -- will be reconsidered once the pragma is expanded. + + elsif Nkind (Par) = N_Pragma then + return False; + + -- The context is not suitable when the reference appears within a + -- subprogram call, and the caller requests this behavior. + + elsif not Calls_OK + and then Nkind_In (Par, N_Entry_Call_Statement, + N_Function_Call, + N_Procedure_Call_Statement) + then + return False; + + -- Prevent the search from going too far + + elsif Is_Body_Or_Package_Declaration (Par) then + exit; + end if; + + Par := Parent (Par); + end loop; + + return True; + end Within_Suitable_Context; + + -- Local variables + + Prag : Node_Id; + Var_Id : Entity_Id; + + -- Start of processing for Needs_Variable_Reference_Marker + + begin + -- No marker needs to be created when switch -gnatH (legacy elaboration + -- checking mode enabled) is in effect because the legacy ABE mechanism + -- does use markers. + + if Legacy_Elaboration_Checks then + return False; + + -- No marker needs to be created for ASIS because ABE diagnostics and + -- checks are not performed in this mode. + + elsif ASIS_Mode then + return False; + + -- No marker needs to be created when the reference is preanalyzed + -- because the marker will be inserted in the wrong place. + + elsif Preanalysis_Active then + return False; + + -- Only references warrant a marker + + elsif not Nkind_In (N, N_Expanded_Name, N_Identifier) then + return False; + + -- Only source references warrant a marker + + elsif not Comes_From_Source (N) then + return False; + + -- No marker needs to be created when the reference is erroneous, left + -- in a bad state, or does not denote a variable. + + elsif not (Present (Entity (N)) + and then Ekind (Entity (N)) = E_Variable + and then Entity (N) /= Any_Id) + then + return False; + end if; + + Var_Id := Entity (N); + Prag := SPARK_Pragma (Var_Id); + + -- Both the variable and reference must appear in SPARK_Mode On regions + -- because this elaboration scenario falls under the SPARK rules. + + if not (Comes_From_Source (Var_Id) + and then Present (Prag) + and then Get_SPARK_Mode_From_Annotation (Prag) = On + and then Is_SPARK_Mode_On_Node (N)) + then + return False; + + -- No marker needs to be created when the reference does not appear + -- within a suitable context (see body for details). + + -- Performance note: parent traversal + + elsif not Within_Suitable_Context (N) then + return False; + end if; + + -- At this point it is known that the variable reference will play a + -- role in ABE diagnostics and requires a marker. + + return True; + end Needs_Variable_Reference_Marker; + ------------------------ -- New_Copy_List_Tree -- ------------------------ --- gcc/ada/sem_util.ads +++ gcc/ada/sem_util.ads @@ -2224,6 +2224,13 @@ package Sem_Util is -- set to False, but if Consider_IS is set to True, then the cases above -- mentioning Normalize_Scalars also apply for Initialize_Scalars mode. + function Needs_Variable_Reference_Marker + (N : Node_Id; + Calls_OK : Boolean) return Boolean; + -- Determine whether arbitrary node N denotes a reference to a variable + -- which is suitable for SPARK elaboration checks. Flag Calls_OK should + -- be set when the reference is allowed to appear within calls. + function New_Copy_List_Tree (List : List_Id) return List_Id; -- Copy recursively an analyzed list of nodes. Uses New_Copy_Tree defined -- below. As for New_Copy_Tree, it is illegal to attempt to copy extended