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;

Reply via email to