https://gcc.gnu.org/g:8c7924c0e3ad450e98ae2081dce8fa2a9916479d
commit 8c7924c0e3ad450e98ae2081dce8fa2a9916479d Author: Mikael Morin <mik...@gcc.gnu.org> Date: Wed Jul 9 21:18:18 2025 +0200 fortran: Factor array descriptor references Save parts of array descriptor references to a variable so that all the expressions using the descriptor as base object benefit from the simplified reference. gcc/fortran/ChangeLog: * trans-array.cc (gfc_conv_ss_descriptor): Move the descriptor reference initialisation... (set_factored_descriptor_value): ... to this new function. Walk the reference passed as arguments and try to simplify some of it to a variable. Diff: --- gcc/fortran/trans-array.cc | 79 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc index 52888c1e1f1b..51ec1c78a28c 100644 --- a/gcc/fortran/trans-array.cc +++ b/gcc/fortran/trans-array.cc @@ -3437,6 +3437,83 @@ save_descriptor_data (tree descr, tree data) } +/* Save the descriptor reference VALUE to storage pointed by DESC_PTR. As there + may be a lot of code using subreferences of the descriptor, try to factor + them by evaluating the leading part of the data reference to a variable, + adding extra code to BLOCK. + + To avoid copying large amounts of data we only save pointers in the reference + chain, and as late in the chain as possible. */ + +void +set_factored_descriptor_value (stmtblock_t *block, tree *desc_ptr, tree value) +{ + /* As the reference is processed from last to first, statements will be + generate in reversed order, so can't be put directly in BLOCK. We use + TMP_BLOCK instead. */ + stmtblock_t tmp_block; + tree accumulated_code = NULL_TREE; + + gfc_init_block (&tmp_block); + + tree *ptr_ref = nullptr; + + tree data_ref = value; + bool seen_component = false; + while (true) + { + if (TREE_CODE (data_ref) == INDIRECT_REF) + { + /* If there is no component reference after the pointer dereference in + the reference chain, the pointer can't be saved to a variable as + it may be a pointer or allocatable, and we have to keep the parent + reference to be able to update the pointer value. Otherwise the + pointer can be saved to a variable. */ + if (seen_component) + { + /* Don't evaluate the pointer to a variable yet; do it only if the + variable would be significantly more simple than the reference + it replaces. That is if the reference contains anything + different from a NOP, a COMPONENT or a DECL. */ + ptr_ref = &TREE_OPERAND (data_ref, 0); + } + + data_ref = TREE_OPERAND (data_ref, 0); + } + else if (TREE_CODE (data_ref) == COMPONENT_REF) + { + seen_component = true; + data_ref = TREE_OPERAND (data_ref, 0); + } + else if (TREE_CODE (data_ref) == NOP_EXPR) + data_ref = TREE_OPERAND (data_ref, 0); + else + { + if (DECL_P (data_ref)) + break; + + if (ptr_ref != nullptr) + { + /* We have seen a pointer before, and its reference appears to be + worth saving. Do it now. */ + tree ptr = *ptr_ref; + *ptr_ref = gfc_evaluate_now (ptr, &tmp_block); + gfc_add_expr_to_block (&tmp_block, accumulated_code); + accumulated_code = gfc_finish_block (&tmp_block); + } + + if (TREE_CODE (data_ref) == ARRAY_REF) + data_ref = TREE_OPERAND (data_ref, 0); + else + break; + } + } + + *desc_ptr = value; + gfc_add_expr_to_block (block, accumulated_code); +} + + /* Translate expressions for the descriptor and data pointer of a SS. */ /*GCC ARRAYS*/ @@ -3457,7 +3534,7 @@ gfc_conv_ss_descriptor (stmtblock_t * block, gfc_ss * ss, int base) se.descriptor_only = 1; gfc_conv_expr_lhs (&se, ss_info->expr); gfc_add_block_to_block (block, &se.pre); - info->descriptor = se.expr; + set_factored_descriptor_value (block, &info->descriptor, se.expr); ss_info->string_length = se.string_length; ss_info->class_container = se.class_container;