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
