From: Eric Botcazou <[email protected]>
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.
gcc/ada/ChangeLog:
* gcc-interface/trans.cc (gnat_to_gnu): For the LHS of an assignment
or an actual parameter of a call, do not remove the padding even for
a type of self-referential size when the padded size is small enough
to be copied efficiently.
Tested on x86_64-pc-linux-gnu (before the recent bootstrap breakage), committed
on master.
---
gcc/ada/gcc-interface/trans.cc | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/gcc/ada/gcc-interface/trans.cc b/gcc/ada/gcc-interface/trans.cc
index cdbd4828c82..f819f577fa3 100644
--- a/gcc/ada/gcc-interface/trans.cc
+++ b/gcc/ada/gcc-interface/trans.cc
@@ -8903,17 +8903,21 @@ gnat_to_gnu (Node_Id gnat_node)
&& !(TREE_CODE (gnu_result_type) == RECORD_TYPE
&& TYPE_JUSTIFIED_MODULAR_P (gnu_result_type))))
{
- /* 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. But do not remove it if it is already too small. */
- if (type_is_padding_self_referential (TREE_TYPE (gnu_result))
+ 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)
&& !(TREE_CODE (gnu_result) == COMPONENT_REF
&& DECL_BIT_FIELD (TREE_OPERAND (gnu_result, 1))
- && 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);
+ && DECL_SIZE (TREE_OPERAND (gnu_result, 1)) != TYPE_SIZE (t)))
+ gnu_result = convert (TREE_TYPE (TYPE_FIELDS (t)), gnu_result);
}
else if (TREE_CODE (gnu_result) == LABEL_DECL
--
2.51.0