> 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 turned out to be too optimistic, so I have installed the attached 
follow-up fix, which should be safer.


        * 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.

-- 
Eric Botcazou
diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc
index f819f577fa3..9a3c5c905ad 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 8f2ad7b3b8a..f8a7d718290 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