]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ada: Improve code generated for return of Out parameter with access type
authorEric Botcazou <ebotcazou@adacore.com>
Tue, 17 Jun 2025 06:26:16 +0000 (08:26 +0200)
committerMarc Poulhiès <dkm@gcc.gnu.org>
Fri, 4 Jul 2025 07:41:47 +0000 (09:41 +0200)
The second problem occurs on 64-bit platforms where there is a second Out
parameter that is smaller than the access parameter, creating a hole in the
return structure.

gcc/ada/ChangeLog:

* gcc-interface/decl.cc (gnat_to_gnu_subprog_type): In the case of a
subprogram using the Copy-In/Copy-Out mechanism, deal specially with
the case of 2 parameters of differing sizes.
* gcc-interface/trans.cc (Subprogram_Body_to_gnu): In the case of a
subprogram using the Copy-In/Copy-Out mechanism, make sure the types
are consistent on the two sides for all the parameters.

gcc/ada/gcc-interface/decl.cc
gcc/ada/gcc-interface/trans.cc

index 903ec844b96813cfaffe8b4e8b7eb07271ccd81b..63c6851d1429464c519a222863157ea84fcd0743 100644 (file)
@@ -6421,6 +6421,29 @@ gnat_to_gnu_subprog_type (Entity_Id gnat_subprog, bool definition,
         since structures are incomplete for the back-end.  */
       else if (Convention (gnat_subprog) != Convention_Stubbed)
        {
+         /* If we have two entries that may be returned in integer registers,
+            the larger has power-of-2 size and the smaller is integral, then
+            extend the smaller to this power-of-2 size to get a return type
+            with power-of-2 size and no holes, again to speed up accesses.  */
+         if (list_length (gnu_cico_field_list) == 2
+             && gnu_cico_only_integral_type)
+           {
+             tree typ1 = TREE_TYPE (gnu_cico_field_list);
+             tree typ2 = TREE_TYPE (DECL_CHAIN (gnu_cico_field_list));
+             if (INTEGRAL_TYPE_P (typ1)
+                 && integer_pow2p (TYPE_SIZE (typ2))
+                 && tree_int_cst_lt (TYPE_SIZE (typ1), TYPE_SIZE (typ2)))
+               TREE_TYPE (gnu_cico_field_list)
+                 = gnat_type_for_size (TREE_INT_CST_LOW (TYPE_SIZE (typ2)),
+                                       TYPE_UNSIGNED (typ1));
+             else if (INTEGRAL_TYPE_P (typ2)
+                      && integer_pow2p (TYPE_SIZE (typ1))
+                      && tree_int_cst_lt (TYPE_SIZE (typ2), TYPE_SIZE (typ1)))
+               TREE_TYPE (DECL_CHAIN (gnu_cico_field_list))
+                 = gnat_type_for_size (TREE_INT_CST_LOW (TYPE_SIZE (typ1)),
+                                       TYPE_UNSIGNED (typ2));
+           }
+
          finish_record_type (gnu_cico_return_type,
                              nreverse (gnu_cico_field_list),
                              0, false);
index e02804b75af127d9822445037007b12190a03e62..520611e7d79aa2cdbc969debf6ac0151c83a23a5 100644 (file)
@@ -4049,7 +4049,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
            tree gnu_decl;
 
            /* Skip any entries that have been already filled in; they must
-              correspond to In Out parameters.  */
+              correspond to In Out parameters or previous Out parameters.  */
            while (gnu_cico_entry && TREE_VALUE (gnu_cico_entry))
              gnu_cico_entry = TREE_CHAIN (gnu_cico_entry);
 
@@ -4059,11 +4059,22 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
            if (DECL_BY_REF_P (gnu_decl))
              gnu_decl = build_unary_op (INDIRECT_REF, NULL_TREE, gnu_decl);
 
-           /* Do any needed references for padded types.  */
-           TREE_VALUE (gnu_cico_entry)
-             = convert (TREE_TYPE (TREE_PURPOSE (gnu_cico_entry)), gnu_decl);
+           TREE_VALUE (gnu_cico_entry) = gnu_decl;
          }
+
+      /* Finally, ensure type consistency between TREE_PURPOSE and TREE_VALUE
+        so that the assignment of the latter to the former can be done.  */
+      tree gnu_cico_entry = gnu_cico_list;
+      while (gnu_cico_entry)
+       {
+         if (!VOID_TYPE_P (TREE_VALUE (gnu_cico_entry)))
+           TREE_VALUE (gnu_cico_entry)
+             = convert (TREE_TYPE (TREE_PURPOSE (gnu_cico_entry)),
+                        TREE_VALUE (gnu_cico_entry));
+         gnu_cico_entry = TREE_CHAIN (gnu_cico_entry);
+       }
     }
+
   else
     vec_safe_push (gnu_return_label_stack, NULL_TREE);