decl.c (components_to_record): Add REORDER parameter...
authorEric Botcazou <ebotcazou@adacore.com>
Mon, 21 Mar 2011 12:31:12 +0000 (12:31 +0000)
committerEric Botcazou <ebotcazou@gcc.gnu.org>
Mon, 21 Mar 2011 12:31:12 +0000 (12:31 +0000)
* gcc-interface/decl.c (components_to_record): Add REORDER parameter,
rename DEBUG_INFO_P into DEBUG_INFO and move P_GNU_REP_LIST parameter
to the end of the list.  Adjust recursive call.  Rename local variable.
If REORDER is true, reorder components of the record type.
(gnat_to_gnu_entity): Pass OK_To_Reorder_Components flag as argument to
components_to_record and adjust the parameter list.

From-SVN: r171228

gcc/ada/ChangeLog
gcc/ada/gcc-interface/decl.c

index a61c1e69e703d602207fa8f5b8952b1415007fda..3ddcda5ad491ac871ea105e44de7937cc9e472dd 100644 (file)
@@ -1,3 +1,12 @@
+2011-03-21  Eric Botcazou  <ebotcazou@adacore.com>
+
+       * gcc-interface/decl.c (components_to_record): Add REORDER parameter,
+       rename DEBUG_INFO_P into DEBUG_INFO and move P_GNU_REP_LIST parameter
+       to the end of the list.  Adjust recursive call.  Rename local variable.
+       If REORDER is true, reorder components of the record type.
+       (gnat_to_gnu_entity): Pass OK_To_Reorder_Components flag as argument to
+       components_to_record and adjust the parameter list.
+
 2011-03-21  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gcc-interface/decl.c (elaborate_expression_1): When optimization is
index f254ac4d0fc934c16f5fac542af5ee45d93ce781..ab571ab7b6c737f9d87a986c9e6d4a98144a5bfb 100644 (file)
@@ -159,8 +159,8 @@ static bool array_type_has_nonaliased_component (tree, Entity_Id);
 static bool compile_time_known_address_p (Node_Id);
 static bool cannot_be_superflat_p (Node_Id);
 static bool constructor_address_p (tree);
-static void components_to_record (tree, Node_Id, tree, int, bool, tree *,
-                                 bool, bool, bool, bool, bool);
+static void components_to_record (tree, Node_Id, tree, int, bool, bool, bool,
+                                 bool, bool, bool, bool, tree *);
 static Uint annotate_value (tree);
 static void annotate_rep (Entity_Id, tree);
 static tree build_position_list (tree, bool, tree, tree, unsigned int, tree);
@@ -2951,9 +2951,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
 
        /* Add the fields into the record type and finish it up.  */
        components_to_record (gnu_type, Component_List (record_definition),
-                             gnu_field_list, packed, definition, NULL,
-                             false, all_rep, is_unchecked_union,
-                             debug_info_p, false);
+                             gnu_field_list, packed, definition, false,
+                             all_rep, is_unchecked_union, debug_info_p,
+                             false, OK_To_Reorder_Components (gnat_entity),
+                             NULL);
 
        /* If it is passed by reference, force BLKmode to ensure that objects
           of this type will always be put in memory.  */
@@ -6992,10 +6993,6 @@ compare_field_bitpos (const PTR rt1, const PTR rt2)
 
    DEFINITION is true if we are defining this record type.
 
-   P_GNU_REP_LIST, if nonzero, is a pointer to a list to which each field
-   with a rep clause is to be added; in this case, that is all that should
-   be done with such fields.
-
    CANCEL_ALIGNMENT is true if the alignment should be zeroed before laying
    out the record.  This means the alignment only serves to force fields to
    be bitfields, but not to require the record to be that aligned.  This is
@@ -7006,27 +7003,37 @@ compare_field_bitpos (const PTR rt1, const PTR rt2)
    UNCHECKED_UNION is true if we are building this type for a record with a
    Pragma Unchecked_Union.
 
-   DEBUG_INFO_P is true if we need to write debug information about the type.
+   DEBUG_INFO is true if we need to write debug information about the type.
 
    MAYBE_UNUSED is true if this type may be unused in the end; this doesn't
-   mean that its contents may be unused as well, but only the container.  */
+   mean that its contents may be unused as well, only the container itself.
 
+   REORDER is true if we are permitted to reorder components of this type.
+
+   P_GNU_REP_LIST, if nonzero, is a pointer to a list to which each field
+   with a rep clause is to be added; in this case, that is all that should
+   be done with such fields.  */
 
 static void
 components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
                      tree gnu_field_list, int packed, bool definition,
-                     tree *p_gnu_rep_list, bool cancel_alignment,
-                     bool all_rep, bool unchecked_union, bool debug_info_p,
-                     bool maybe_unused)
+                     bool cancel_alignment, bool all_rep,
+                     bool unchecked_union, bool debug_info,
+                     bool maybe_unused, bool reorder,
+                     tree *p_gnu_rep_list)
 {
   bool all_rep_and_size = all_rep && TYPE_SIZE (gnu_record_type);
   bool layout_with_rep = false;
   Node_Id component_decl, variant_part;
-  tree gnu_our_rep_list = NULL_TREE;
-  tree gnu_field, gnu_next, gnu_last = tree_last (gnu_field_list);
+  tree gnu_field, gnu_next, gnu_last;
+  tree gnu_variant_part = NULL_TREE;
+  tree gnu_rep_list = NULL_TREE;
+  tree gnu_var_list = NULL_TREE;
+  tree gnu_self_list = NULL_TREE;
 
   /* For each component referenced in a component declaration create a GCC
      field and add it to the list, skipping pragmas in the GNAT list.  */
+  gnu_last = tree_last (gnu_field_list);
   if (Present (Component_Items (gnat_component_list)))
     for (component_decl
           = First_Non_Pragma (Component_Items (gnat_component_list));
@@ -7046,7 +7053,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
        else
          {
            gnu_field = gnat_to_gnu_field (gnat_field, gnu_record_type, packed,
-                                          definition, debug_info_p);
+                                          definition, debug_info);
 
            /* If this is the _Tag field, put it before any other fields.  */
            if (gnat_name == Name_uTag)
@@ -7091,7 +7098,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
       tree gnu_var_name
        = concat_name (get_identifier (Get_Name_String (Chars (gnat_discr))),
                       "XVN");
-      tree gnu_union_type, gnu_union_name, gnu_union_field;
+      tree gnu_union_type, gnu_union_name;
       tree gnu_variant_list = NULL_TREE;
 
       if (TREE_CODE (gnu_name) == TYPE_DECL)
@@ -7151,8 +7158,9 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
             we aren't sure to really use it at this point, see below.  */
          components_to_record (gnu_variant_type, Component_List (variant),
                                NULL_TREE, packed, definition,
-                               &gnu_our_rep_list, !all_rep_and_size, all_rep,
-                               unchecked_union, debug_info_p, true);
+                               !all_rep_and_size, all_rep,
+                               unchecked_union, debug_info,
+                               true, reorder, &gnu_rep_list);
 
          gnu_qual = choices_to_gnu (gnu_discr, Discrete_Choices (variant));
 
@@ -7177,7 +7185,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
                 the fields associated with these empty variants.  */
              rest_of_record_type_compilation (gnu_variant_type);
              create_type_decl (TYPE_NAME (gnu_variant_type), gnu_variant_type,
-                               NULL, true, debug_info_p, gnat_component_list);
+                               NULL, true, debug_info, gnat_component_list);
 
              gnu_field
                = create_field_decl (gnu_inner_name, gnu_variant_type,
@@ -7211,7 +7219,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
            }
 
          finish_record_type (gnu_union_type, nreverse (gnu_variant_list),
-                             all_rep_and_size ? 1 : 0, debug_info_p);
+                             all_rep_and_size ? 1 : 0, debug_info);
 
          /* If GNU_UNION_TYPE is our record type, it means we must have an
             Unchecked_Union with no fields.  Verify that and, if so, just
@@ -7220,71 +7228,124 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
            {
              gcc_assert (unchecked_union
                          && !gnu_field_list
-                         && !gnu_our_rep_list);
+                         && !gnu_rep_list);
              return;
            }
 
          create_type_decl (TYPE_NAME (gnu_union_type), gnu_union_type,
-                           NULL, true, debug_info_p, gnat_component_list);
+                           NULL, true, debug_info, gnat_component_list);
 
          /* Deal with packedness like in gnat_to_gnu_field.  */
          union_field_packed
            = adjust_packed (gnu_union_type, gnu_record_type, packed);
 
-         gnu_union_field
+         gnu_variant_part
            = create_field_decl (gnu_var_name, gnu_union_type, gnu_record_type,
                                 all_rep ? TYPE_SIZE (gnu_union_type) : 0,
                                 all_rep ? bitsize_zero_node : 0,
                                 union_field_packed, 0);
 
-         DECL_INTERNAL_P (gnu_union_field) = 1;
-         DECL_CHAIN (gnu_union_field) = gnu_field_list;
-         gnu_field_list = gnu_union_field;
+         DECL_INTERNAL_P (gnu_variant_part) = 1;
+         DECL_CHAIN (gnu_variant_part) = gnu_field_list;
+         gnu_field_list = gnu_variant_part;
        }
     }
 
-  /* Scan GNU_FIELD_LIST and see if any fields have rep clauses.  If they
-     do, pull them out and put them into GNU_OUR_REP_LIST.  We have to do
-     this in a separate pass since we want to handle the discriminants but
-     can't play with them until we've used them in debugging data above.
+  /* Scan GNU_FIELD_LIST and see if any fields have rep clauses and, if we are
+     permitted to reorder components, self-referential sizes or variable sizes.
+     If they do, pull them out and put them onto the appropriate list.  We have
+     to do this in a separate pass since we want to handle the discriminants
+     but can't play with them until we've used them in debugging data above.
 
-     ??? If we then reorder them, debugging information will be wrong but
-     there's nothing that can be done about this at the moment.  */
+     ??? If we reorder them, debugging information will be wrong but there is
+     nothing that can be done about this at the moment.  */
   gnu_last = NULL_TREE;
+
+#define MOVE_FROM_FIELD_LIST_TO(LIST)  \
+  do {                                 \
+    if (gnu_last)                      \
+      DECL_CHAIN (gnu_last) = gnu_next;        \
+    else                               \
+      gnu_field_list = gnu_next;       \
+                                       \
+    DECL_CHAIN (gnu_field) = (LIST);   \
+    (LIST) = gnu_field;                        \
+  } while (0)
+
   for (gnu_field = gnu_field_list; gnu_field; gnu_field = gnu_next)
     {
       gnu_next = DECL_CHAIN (gnu_field);
 
       if (DECL_FIELD_OFFSET (gnu_field))
        {
-         if (!gnu_last)
-           gnu_field_list = gnu_next;
-         else
-           DECL_CHAIN (gnu_last) = gnu_next;
+         MOVE_FROM_FIELD_LIST_TO (gnu_rep_list);
+         continue;
+       }
+
+      if (reorder)
+       {
+         /* Pull out the variant part and put it onto GNU_SELF_LIST.  */
+         if (gnu_field == gnu_variant_part)
+           {
+             MOVE_FROM_FIELD_LIST_TO (gnu_self_list);
+             continue;
+           }
 
-         DECL_CHAIN (gnu_field) = gnu_our_rep_list;
-         gnu_our_rep_list = gnu_field;
+         /* Skip internal fields and fields with fixed size.  */
+         if (!DECL_INTERNAL_P (gnu_field)
+             && !(DECL_SIZE (gnu_field)
+                  && TREE_CODE (DECL_SIZE (gnu_field)) == INTEGER_CST))
+           {
+             tree type_size = TYPE_SIZE (TREE_TYPE (gnu_field));
+
+             if (CONTAINS_PLACEHOLDER_P (type_size))
+               {
+                 MOVE_FROM_FIELD_LIST_TO (gnu_self_list);
+                 continue;
+               }
+
+             if (TREE_CODE (type_size) != INTEGER_CST)
+               {
+                 MOVE_FROM_FIELD_LIST_TO (gnu_var_list);
+                 continue;
+               }
+           }
        }
-      else
-       gnu_last = gnu_field;
+
+      gnu_last = gnu_field;
     }
 
+#undef MOVE_FROM_FIELD_LIST_TO
+
+  /* If permitted, we reorder the components as follows:
+
+       1) all fixed length fields,
+       2) all fields whose length doesn't depend on discriminants,
+       3) all fields whose length depends on discriminants,
+       4) the variant part,
+
+     within the record and within each variant recursively.  */
+  if (reorder)
+    gnu_field_list
+      = chainon (nreverse (gnu_self_list),
+                chainon (nreverse (gnu_var_list), gnu_field_list));
+
   /* If we have any fields in our rep'ed field list and it is not the case that
      all the fields in the record have rep clauses and P_REP_LIST is nonzero,
      set it and ignore these fields.  */
-  if (gnu_our_rep_list && p_gnu_rep_list && !all_rep)
-    *p_gnu_rep_list = chainon (*p_gnu_rep_list, gnu_our_rep_list);
+  if (gnu_rep_list && p_gnu_rep_list && !all_rep)
+    *p_gnu_rep_list = chainon (*p_gnu_rep_list, gnu_rep_list);
 
   /* Otherwise, sort the fields by bit position and put them into their own
      record, before the others, if we also have fields without rep clauses.  */
-  else if (gnu_our_rep_list)
+  else if (gnu_rep_list)
     {
       tree gnu_rep_type
        = (gnu_field_list ? make_node (RECORD_TYPE) : gnu_record_type);
-      int i, len = list_length (gnu_our_rep_list);
+      int i, len = list_length (gnu_rep_list);
       tree *gnu_arr = XALLOCAVEC (tree, len);
 
-      for (gnu_field = gnu_our_rep_list, i = 0;
+      for (gnu_field = gnu_rep_list, i = 0;
           gnu_field;
           gnu_field = DECL_CHAIN (gnu_field), i++)
        gnu_arr[i] = gnu_field;
@@ -7293,17 +7354,17 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
 
       /* Put the fields in the list in order of increasing position, which
         means we start from the end.  */
-      gnu_our_rep_list = NULL_TREE;
+      gnu_rep_list = NULL_TREE;
       for (i = len - 1; i >= 0; i--)
        {
-         DECL_CHAIN (gnu_arr[i]) = gnu_our_rep_list;
-         gnu_our_rep_list = gnu_arr[i];
+         DECL_CHAIN (gnu_arr[i]) = gnu_rep_list;
+         gnu_rep_list = gnu_arr[i];
          DECL_CONTEXT (gnu_arr[i]) = gnu_rep_type;
        }
 
       if (gnu_field_list)
        {
-         finish_record_type (gnu_rep_type, gnu_our_rep_list, 1, debug_info_p);
+         finish_record_type (gnu_rep_type, gnu_rep_list, 1, debug_info);
          gnu_field
            = create_field_decl (get_identifier ("REP"), gnu_rep_type,
                                 gnu_record_type, NULL_TREE, NULL_TREE, 0, 1);
@@ -7313,7 +7374,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
       else
        {
          layout_with_rep = true;
-         gnu_field_list = nreverse (gnu_our_rep_list);
+         gnu_field_list = nreverse (gnu_rep_list);
        }
     }
 
@@ -7321,7 +7382,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list,
     TYPE_ALIGN (gnu_record_type) = 0;
 
   finish_record_type (gnu_record_type, nreverse (gnu_field_list),
-                     layout_with_rep ? 1 : 0, debug_info_p && !maybe_unused);
+                     layout_with_rep ? 1 : 0, debug_info && !maybe_unused);
 }
 \f
 /* Given GNU_SIZE, a GCC tree representing a size, return a Uint to be