https://gcc.gnu.org/g:68100373d73301c42bde6ca63a393d6c5adf4374

commit r16-6643-g68100373d73301c42bde6ca63a393d6c5adf4374
Author: Eric Botcazou <[email protected]>
Date:   Fri Jan 9 12:27:49 2026 +0100

    Ada: Fix suboptimal copy of discriminated record to local variable (2nd try)
    
    This happens for a discriminated record type with default discriminants, for
    which GNAT allocates mutable objects with the maximum size, while trying not
    to copy padding bits unnecessarily.  When the padded size is small enough to
    be copied efficiently, it should nevertheless be profitable to copy them in
    order to avoid a call to memcpy with a dynamic size.
    
    This version makes sure that it is safe to read the padded size on the RHS,
    which is not the case for example when the LHS is an unconstrained variable
    but the RHS is a constrained object.
    
    gcc/ada
            * gcc-interface/trans.cc (gnat_to_gnu): Add comment explaining why
            it is necessary to remove the padding for an object of a type with
            self-referential size when it is not converted to the result type.
            * gcc-interface/utils2.cc (build_binary_op) <MODIFY_EXPR>: For an
            assignment between small padded objects of the same type with self-
            referential size, and which have the same (constant) size, use the
            padded view of the objects.

Diff:
---
 gcc/ada/gcc-interface/trans.cc  | 24 +++++++++++-------------
 gcc/ada/gcc-interface/utils2.cc | 22 +++++++++++++++++++++-
 2 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc
index f819f577fa3f..9a3c5c905ad5 100644
--- a/gcc/ada/gcc-interface/trans.cc
+++ b/gcc/ada/gcc-interface/trans.cc
@@ -8903,21 +8903,19 @@ gnat_to_gnu (Node_Id gnat_node)
           && !(TREE_CODE (gnu_result_type) == RECORD_TYPE
                && TYPE_JUSTIFIED_MODULAR_P (gnu_result_type))))
     {
-      tree t = TREE_TYPE (gnu_result);
-
-      /* Remove the padding only if the inner object is of self-referential
-        size: in that case, it must be an object of an unconstrained type
-        with default discriminants and we want to avoid copying too much
-        data.  But we would nevertheless rather copy up to MOVE_MAX_PIECES
-        bytes than invoke memcpy for such a small amount of data.  In any
-        case, do not remove the padding if it is already too small.  */
-      if (type_is_padding_self_referential (t)
-         && (TREE_CODE (TYPE_SIZE_UNIT (t)) != INTEGER_CST
-             || compare_tree_int (TYPE_SIZE_UNIT (t), MOVE_MAX_PIECES) > 0)
+      /* Remove padding only if the inner object is of self-referential
+        size: in that case it must be an object of unconstrained type
+        with a default discriminant and we want to avoid copying too
+        much data, in particular reading too much data from the source,
+        which may be constrained and thus may contain no padding at all.
+        But do not remove the padding if it is already too small.  */
+      if (type_is_padding_self_referential (TREE_TYPE (gnu_result))
          && !(TREE_CODE (gnu_result) == COMPONENT_REF
               && DECL_BIT_FIELD (TREE_OPERAND (gnu_result, 1))
-              && DECL_SIZE (TREE_OPERAND (gnu_result, 1)) != TYPE_SIZE (t)))
-       gnu_result = convert (TREE_TYPE (TYPE_FIELDS (t)), gnu_result);
+              && DECL_SIZE (TREE_OPERAND (gnu_result, 1))
+                 != TYPE_SIZE (TREE_TYPE (gnu_result))))
+       gnu_result = convert (TREE_TYPE (TYPE_FIELDS (TREE_TYPE (gnu_result))),
+                             gnu_result);
     }
 
   else if (TREE_CODE (gnu_result) == LABEL_DECL
diff --git a/gcc/ada/gcc-interface/utils2.cc b/gcc/ada/gcc-interface/utils2.cc
index 8f2ad7b3b8ac..f8a7d718290f 100644
--- a/gcc/ada/gcc-interface/utils2.cc
+++ b/gcc/ada/gcc-interface/utils2.cc
@@ -992,7 +992,7 @@ build_binary_op (enum tree_code op_code, tree result_type,
   tree right_base_type = get_base_type (right_type);
   tree operation_type = result_type;
   tree best_type = NULL_TREE;
-  tree modulus, result;
+  tree modulus, result, t1, t2;
   bool has_side_effects = false;
 
   if (operation_type
@@ -1075,6 +1075,26 @@ build_binary_op (enum tree_code op_code, tree 
result_type,
            operation_type = left_type;
        }
 
+      /* If we are copying between small padded objects of the same type with
+        self-referential size, and the padded size is the same constant size,
+        use the padded view of the objects, this will be more efficient.  */
+      else if (left_type == right_type
+              && CONTAINS_PLACEHOLDER_P (TYPE_SIZE (left_type))
+              && TREE_CODE (left_operand) == COMPONENT_REF
+              && TREE_CODE (right_operand) == COMPONENT_REF
+              && (t1 = operand_type (left_operand))
+              && (t2 = operand_type (right_operand))
+              && TYPE_IS_PADDING_P (t1)
+              && TYPE_IS_PADDING_P (t2)
+              && TYPE_SIZE_UNIT (t1) == TYPE_SIZE_UNIT (t2)
+              && TREE_CODE (TYPE_SIZE_UNIT (t1)) == INTEGER_CST
+              && compare_tree_int (TYPE_SIZE_UNIT (t1), MOVE_MAX_PIECES) <= 0)
+       {
+         left_operand = convert (t1, left_operand);
+         right_operand = convert (t2, right_operand);
+         operation_type = t1;
+       }
+
       /* If we have a call to a function that returns with variable size, use
         the RHS type in case we want to use the return slot optimization.  */
       else if (TREE_CODE (right_operand) == CALL_EXPR

Reply via email to