diff mbox series

[Ada] Do not make a local copy of large aggregate

Message ID 1789076.KqyaMx80o3@polaris
State New
Headers show
Series [Ada] Do not make a local copy of large aggregate | expand

Commit Message

Eric Botcazou May 9, 2020, 8:45 p.m. UTC
This prevents gigi from effectively making a local copy of large aggregates.

Tested on x86-64/Linux, applied on the mainline.


2020-05-09  Eric Botcazou  <ebotcazou@adacore.com>

	* gcc-interface/trans.c (lvalue_required_p) <N_Selected_Component>:
	Merge with N_Slice.
	<N_Allocator>: Move to...
	(lvalue_for_aggregate_p): ...here.  New function.
	(Identifier_to_gnu): For an identifier with aggregate type, also
	call lvalue_for_aggregate_p if lvalue_required_p returned false
	before substituting the identifier with the constant.
diff mbox series

Patch

diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 44b156ac3d8..a2f06d774d3 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -871,8 +871,9 @@  lvalue_required_p (Node_Id gnat_node, tree gnu_type, bool constant,
 
       /* ... fall through ... */
 
+    case N_Selected_Component:
     case N_Slice:
-      /* Only the array expression can require an lvalue.  */
+      /* Only the prefix expression can require an lvalue.  */
       if (Prefix (gnat_parent) != gnat_node)
 	return 0;
 
@@ -880,11 +881,6 @@  lvalue_required_p (Node_Id gnat_node, tree gnu_type, bool constant,
 				get_unpadded_type (Etype (gnat_parent)),
 				constant, address_of_constant);
 
-    case N_Selected_Component:
-      return lvalue_required_p (gnat_parent,
-				get_unpadded_type (Etype (gnat_parent)),
-				constant, address_of_constant);
-
     case N_Object_Renaming_Declaration:
       /* We need to preserve addresses through a renaming.  */
       return 1;
@@ -925,12 +921,6 @@  lvalue_required_p (Node_Id gnat_node, tree gnu_type, bool constant,
 			       get_unpadded_type (Etype (gnat_parent)),
 			       constant, address_of_constant);
 
-    case N_Allocator:
-      /* We should only reach here through the N_Qualified_Expression case.
-	 Force an lvalue for composite types since a block-copy to the newly
-	 allocated area of memory is made.  */
-      return Is_Composite_Type (Underlying_Type (Etype (gnat_node)));
-
    case N_Explicit_Dereference:
       /* We look through dereferences for address of constant because we need
 	 to handle the special cases listed above.  */
@@ -948,6 +938,74 @@  lvalue_required_p (Node_Id gnat_node, tree gnu_type, bool constant,
   gcc_unreachable ();
 }
 
+/* Return true if an lvalue should be used for GNAT_NODE.  GNU_TYPE is the type
+   that will be used for GNAT_NODE in the translated GNU tree and is assumed to
+   be an aggregate type.
+
+   The function climbs up the GNAT tree starting from the node and returns true
+   upon encountering a node that makes it doable to decide.  lvalue_required_p
+   should have been previously invoked on the arguments and returned false.  */
+
+static bool
+lvalue_for_aggregate_p (Node_Id gnat_node, tree gnu_type)
+{
+  Node_Id gnat_parent = Parent (gnat_node);
+
+  switch (Nkind (gnat_parent))
+    {
+    case N_Parameter_Association:
+    case N_Function_Call:
+    case N_Procedure_Call_Statement:
+      /* Even if the parameter is by copy, prefer an lvalue.  */
+      return true;
+
+    case N_Indexed_Component:
+    case N_Selected_Component:
+      /* If an elementary component is used, take it from the constant.  */
+      if (!Is_Composite_Type (Underlying_Type (Etype (gnat_parent))))
+	return false;
+
+      /* ... fall through ... */
+
+    case N_Slice:
+      return lvalue_for_aggregate_p (gnat_parent,
+				     get_unpadded_type (Etype (gnat_parent)));
+
+    case N_Object_Declaration:
+      /* For an aggregate object declaration, return the constant at top level
+	 in order to avoid generating elaboration code.  */
+      if (global_bindings_p ())
+	return false;
+
+      /* ... fall through ... */
+
+    case N_Assignment_Statement:
+      /* For an aggregate assignment, decide based on the size.  */
+      {
+	const HOST_WIDE_INT size = int_size_in_bytes (gnu_type);
+	return size < 0 || size >= param_large_stack_frame / 4;
+      }
+
+    case N_Unchecked_Type_Conversion:
+    case N_Type_Conversion:
+    case N_Qualified_Expression:
+      return lvalue_for_aggregate_p (gnat_parent,
+				     get_unpadded_type (Etype (gnat_parent)));
+
+    case N_Allocator:
+      /* We should only reach here through the N_Qualified_Expression case.
+	 Force an lvalue for aggregate types since a block-copy to the newly
+	 allocated area of memory is made.  */
+      return true;
+
+    default:
+      return false;
+    }
+
+  gcc_unreachable ();
+}
+
+
 /* Return true if T is a constant DECL node that can be safely replaced
    by its initializer.  */
 
@@ -1232,7 +1290,9 @@  Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
       if ((!constant_only || address_of_constant) && require_lvalue < 0)
 	require_lvalue
 	  = lvalue_required_p (gnat_node, gnu_result_type, true,
-			       address_of_constant);
+			       address_of_constant)
+	    || (AGGREGATE_TYPE_P (gnu_result_type)
+		&& lvalue_for_aggregate_p (gnat_node, gnu_result_type));
 
       /* Finally retrieve the initializer if this is deemed valid.  */
       if ((constant_only && !address_of_constant) || !require_lvalue)