https://gcc.gnu.org/g:571f250c66150301bebad35e9c8dac3169593acb
commit r16-6641-g571f250c66150301bebad35e9c8dac3169593acb Author: Eric Botcazou <[email protected]> Date: Tue Dec 16 12:30:14 2025 +0100 ada: Fix suboptimal copy of discriminated record to local variable 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. Diff: --- 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 cdbd4828c825..f819f577fa3f 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
