This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Ada] Improve allocation of constants with discriminated types


As demonstrated by the following testcase, the allocation of constants with 
discriminated types in Gigi is suboptimal.  For

   type T (Big : Boolean := False) is record
      case Big is
         when True =>
            Content : Integer;
         when False =>
            null;
       end case;
    end record;

    D : constant T := (True, 0);

    Var :          T := D;
    Con : constant T := D;

D is allocated statically with exact size, Var is allocated statically with 
maximum size, but Con is allocated dynamically (with exact size).

We can do better by propagating the size of D thanks to its constantness.

Tested on i586-suse-linux, applied on the mainline


2008-04-02  Eric Botcazou  <ebotcazou@adacore.com>

	* decl.c (gnat_to_gnu_entity) <object>: For a constant object whose
	type has self-referential size, get the size from the initializing
	expression directly if it is also a constant whose nominal type
	has self-referential size.


2008-04-02  Eric Botcazou  <ebotcazou@adacore.com>

	* gnat.dg/specs/discr_record_constant.ads: New test.


-- 
Eric Botcazou
Index: decl.c
===================================================================
--- decl.c	(revision 133768)
+++ decl.c	(working copy)
@@ -607,15 +607,34 @@ gnat_to_gnu_entity (Entity_Id gnat_entit
 	   initializing expression, in which case we can get the size from
 	   that.  Note that the resulting size may still be a variable, so
 	   this may end up with an indirect allocation.  */
-
 	if (No (Renamed_Object (gnat_entity))
 	    && CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_type)))
 	  {
 	    if (gnu_expr && kind == E_Constant)
-	      gnu_size
-		= SUBSTITUTE_PLACEHOLDER_IN_EXPR
-		  (TYPE_SIZE (TREE_TYPE (gnu_expr)), gnu_expr);
-
+	      {
+		tree size = TYPE_SIZE (TREE_TYPE (gnu_expr));
+		if (CONTAINS_PLACEHOLDER_P (size))
+		  {
+		    /* If the initializing expression is itself a constant,
+		       despite having a nominal type with self-referential
+		       size, we can get the size directly from it.  */
+		    if (TREE_CODE (gnu_expr) == COMPONENT_REF
+			&& TREE_CODE (TREE_TYPE (TREE_OPERAND (gnu_expr, 0)))
+			   == RECORD_TYPE
+			&& TYPE_IS_PADDING_P
+			   (TREE_TYPE (TREE_OPERAND (gnu_expr, 0)))
+			&& TREE_CODE (TREE_OPERAND (gnu_expr, 0)) == VAR_DECL
+			&& (TREE_READONLY (TREE_OPERAND (gnu_expr, 0))
+			    || DECL_READONLY_ONCE_ELAB
+			       (TREE_OPERAND (gnu_expr, 0))))
+		      gnu_size = DECL_SIZE (TREE_OPERAND (gnu_expr, 0));
+		    else
+		      gnu_size
+			= SUBSTITUTE_PLACEHOLDER_IN_EXPR (size, gnu_expr);
+		  }
+		else
+		  gnu_size = size;
+	      }
 	    /* We may have no GNU_EXPR because No_Initialization is
 	       set even though there's an Expression.  */
 	    else if (kind == E_Constant
-- { dg-do compile }

pragma Restrictions (No_Implicit_Heap_Allocations);

package Discr_Record_Constant is

   type T (Big : Boolean := False) is record
      case Big is
         when True =>
            Content : Integer;
         when False =>
            null;
       end case;
    end record;

    D : constant T := (True, 0);

    Var :          T := D;    --  OK, maximum size
    Con : constant T := D;    --  Violation of restriction
    Ter : constant T := Con;  --  Violation of restriction

end Discr_Record_Constant;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]