From patchwork Mon Oct 4 14:10:43 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnaud Charlet X-Patchwork-Id: 66683 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]) by ozlabs.org (Postfix) with SMTP id BE1C6B70D2 for ; Tue, 5 Oct 2010 01:11:03 +1100 (EST) Received: (qmail 18503 invoked by alias); 4 Oct 2010 14:10:58 -0000 Received: (qmail 17590 invoked by uid 22791); 4 Oct 2010 14:10:53 -0000 X-SWARE-Spam-Status: No, hits=-1.8 required=5.0 tests=AWL, BAYES_00, T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mel.act-europe.fr (HELO mel.act-europe.fr) (212.99.106.210) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 04 Oct 2010 14:10:46 +0000 Received: from localhost (localhost [127.0.0.1]) by filtered-smtp.eu.adacore.com (Postfix) with ESMTP id E39C2CB0263; Mon, 4 Oct 2010 16:10:43 +0200 (CEST) Received: from mel.act-europe.fr ([127.0.0.1]) by localhost (smtp.eu.adacore.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id FX0WTMJbBnmy; Mon, 4 Oct 2010 16:10:43 +0200 (CEST) Received: from saumur.act-europe.fr (saumur.act-europe.fr [10.10.0.183]) by mel.act-europe.fr (Postfix) with ESMTP id CD16FCB0244; Mon, 4 Oct 2010 16:10:43 +0200 (CEST) Received: by saumur.act-europe.fr (Postfix, from userid 525) id AE85ED9BB4; Mon, 4 Oct 2010 16:10:43 +0200 (CEST) Date: Mon, 4 Oct 2010 16:10:43 +0200 From: Arnaud Charlet To: gcc-patches@gcc.gnu.org Cc: Eric Botcazou Subject: [Ada] Avoid making library-level subprograms public unnecessarily Message-ID: <20101004141043.GA8369@adacore.com> Mime-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.9i X-IsSubscribed: yes 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 In order to support various features of the language, the compiler needs to make library-level symbols that are initially local to a unit public under certain circumstances. This applies to both code (subprograms) and data. Making subprograms public can change the inlining decisions made by the code generator on a purely local basis and degrade performances of the generated code at low or intermediate optimization levels. This enhancement is aimed at not making library-level subprograms public unnecessarily when pragma Inline subprograms are present in the unit by scanning those and finding out whether they reference other subprograms. No functional changes. Tested on x86_64-pc-linux-gnu, committed on trunk 2010-10-04 Eric Botcazou * sem_ch7.adb (Analyze_Package_Body_Helper) : New Check_Subprogram_Ref function and Check_Subprogram_Refs instantiation of Traverse_Func on it to look for subprogram references in a body. Call Check_Subprogram_Refs on the body of inlined subprograms at the outer level and keep clearing the Is_Public flag of subprograms as long as it returns OK. Do not look at anything else than subprograms once an inlined subprogram has been seen. Index: sem_ch7.adb =================================================================== --- sem_ch7.adb (revision 164906) +++ sem_ch7.adb (working copy) @@ -52,6 +52,7 @@ with Sem_Ch8; use Sem_Ch8; with Sem_Ch10; use Sem_Ch10; with Sem_Ch12; use Sem_Ch12; with Sem_Disp; use Sem_Disp; +with Sem_Eval; use Sem_Eval; with Sem_Prag; use Sem_Prag; with Sem_Util; use Sem_Util; with Sem_Warn; use Sem_Warn; @@ -473,9 +474,10 @@ package body Sem_Ch7 is -- is conservative and definitely correct. -- We only do this at the outer (library) level non-generic packages. - -- The reason is simply to cut down on the number of external symbols - -- generated, so this is simply an optimization of the efficiency - -- of the compilation process. It has no other effect. + -- The reason is simply to cut down on the number of global symbols + -- generated, which has a double effect: (1) to make the compilation + -- process more efficient and (2) to give the code generator more + -- freedom to optimize within each unit, especially subprograms. if (Scope (Spec_Id) = Standard_Standard or else Is_Child_Unit (Spec_Id)) and then not Is_Generic_Unit (Spec_Id) @@ -488,16 +490,18 @@ package body Sem_Ch7 is Outer : Boolean) return Boolean; -- Traverse the given list of declarations in reverse order. - -- Return True as soon as a referencer is reached. Return False if - -- none is found. The Outer parameter is True for the outer level - -- call, and False for inner level calls for nested packages. If - -- Outer is True, then any entities up to the point of hitting a - -- referencer get their Is_Public flag cleared, so that the - -- entities will be treated as static entities in the C sense, and - -- need not have fully qualified names. For inner levels, we need - -- all names to be fully qualified to deal with the same name - -- appearing in parallel packages (right now this is tied to their - -- being external). + -- Return True if a referencer is present. Return False if none is + -- found. The Outer parameter is True for the outer level call and + -- False for inner level calls for nested packages. If Outer is + -- True, then any entities up to the point of hitting a referencer + -- get their Is_Public flag cleared, so that the entities will be + -- treated as static entities in the C sense, and need not have + -- fully qualified names. Furthermore, if the referencer is an + -- inlined subprogram that doesn't reference other subprograms, + -- we keep clearing the Is_Public flag on subprograms. For inner + -- levels, we need all names to be fully qualified to deal with + -- the same name appearing in parallel packages (right now this + -- is tied to their being external). -------------------- -- Has_Referencer -- @@ -508,11 +512,66 @@ package body Sem_Ch7 is Outer : Boolean) return Boolean is + Has_Referencer_Except_For_Subprograms : Boolean := False; D : Node_Id; E : Entity_Id; K : Node_Kind; S : Entity_Id; + function Check_Subprogram_Ref (N : Node_Id) + return Traverse_Result; + -- Look for references to subprograms + + -------------------------- + -- Check_Subprogram_Ref -- + -------------------------- + + function Check_Subprogram_Ref (N : Node_Id) + return Traverse_Result + is + V : Node_Id; + + begin + + -- Check name of procedure or function calls + + if Nkind_In (N, N_Procedure_Call_Statement, N_Function_Call) + and then Is_Entity_Name (Name (N)) + then + return Abandon; + end if; + + -- Check prefix of attribute references + + if Nkind (N) = N_Attribute_Reference + and then Is_Entity_Name (Prefix (N)) + and then Present (Entity (Prefix (N))) + and then Ekind (Entity (Prefix (N))) in Subprogram_Kind + then + return Abandon; + end if; + + -- Check value of constants + + if Nkind (N) = N_Identifier + and then Present (Entity (N)) + and then Ekind (Entity (N)) = E_Constant + then + V := Constant_Value (Entity (N)); + if Present (V) + and then not Compile_Time_Known_Value_Or_Aggr (V) + then + return Abandon; + end if; + end if; + + return OK; + + end Check_Subprogram_Ref; + + function Check_Subprogram_Refs is + new Traverse_Func (Check_Subprogram_Ref); + begin if No (L) then return False; @@ -525,6 +584,8 @@ package body Sem_Ch7 is if K in N_Body_Stub then return True; + -- Processing for subprogram bodies + elsif K = N_Subprogram_Body then if Acts_As_Spec (D) then E := Defining_Entity (D); @@ -541,7 +602,13 @@ package body Sem_Ch7 is -- of accessing global entities. if Has_Pragma_Inline (E) then - return True; + if Outer + and then Check_Subprogram_Refs (D) = OK + then + Has_Referencer_Except_For_Subprograms := True; + else + return True; + end if; else Set_Is_Public (E, False); end if; @@ -549,18 +616,30 @@ package body Sem_Ch7 is else E := Corresponding_Spec (D); - if Present (E) - and then (Is_Generic_Unit (E) - or else Has_Pragma_Inline (E) - or else Is_Inlined (E)) - then - return True; + if Present (E) then + + -- A generic subprogram body acts as a referencer + + if Is_Generic_Unit (E) then + return True; + end if; + + if Has_Pragma_Inline (E) or else Is_Inlined (E) then + if Outer + and then Check_Subprogram_Refs (D) = OK + then + Has_Referencer_Except_For_Subprograms := True; + else + return True; + end if; + end if; end if; end if; -- Processing for package bodies elsif K = N_Package_Body + and then not Has_Referencer_Except_For_Subprograms and then Present (Corresponding_Spec (D)) then E := Corresponding_Spec (D); @@ -590,7 +669,9 @@ package body Sem_Ch7 is -- Processing for package specs, recurse into declarations. -- Again we skip this for the case of generic instances. - elsif K = N_Package_Declaration then + elsif K = N_Package_Declaration + and then not Has_Referencer_Except_For_Subprograms + then S := Specification (D); if not Is_Generic_Unit (Defining_Entity (S)) then @@ -617,6 +698,8 @@ package body Sem_Ch7 is E := Defining_Entity (D); if Outer + and then (not Has_Referencer_Except_For_Subprograms + or else K = N_Subprogram_Declaration) and then not Is_Imported (E) and then not Is_Exported (E) and then No (Interface_Name (E)) @@ -628,7 +711,7 @@ package body Sem_Ch7 is Prev (D); end loop; - return False; + return Has_Referencer_Except_For_Subprograms; end Has_Referencer; -- Start of processing for Make_Non_Public_Where_Possible