> 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 Botcazoudiff --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