[Ada] Performance degradation with references
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. 2018-06-11 Hristian Kirtchev <kirtchev@adacore.com> 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. From-SVN: r261400
This commit is contained in:
parent
51b84f99dc
commit
692918a9c1
@ -1,3 +1,22 @@
|
||||
2018-06-11 Hristian Kirtchev <kirtchev@adacore.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2018-06-11 Valentine Reboul <reboul@adacore.com>
|
||||
|
||||
* doc/gnat_rm.rst, doc/gnat_ugn.rst: Rename "GPL Edition" into
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 --
|
||||
------------------------
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user