https://gcc.gnu.org/g:3c970c69e4ce586030af3833d8bf6ec8e191fbbd

commit 3c970c69e4ce586030af3833d8bf6ec8e191fbbd
Author: Mikael Morin <mik...@gcc.gnu.org>
Date:   Mon Jun 2 15:00:40 2025 +0200

    Passage de subreferences sans copie

Diff:
---
 gcc/fortran/trans-expr.cc                          |   4 +
 .../gfortran.dg/array_subref_actual_arg_1.f90      | 186 +++++++++++++++++++++
 gcc/testsuite/lib/scandump.exp                     |  50 ++++++
 gcc/testsuite/lib/scantree.exp                     |  26 +++
 4 files changed, 266 insertions(+)

diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index fa54e2a5ae37..09cdea6e2b8b 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -7550,6 +7550,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym,
 
              else if (e->expr_type == EXPR_VARIABLE
                    && is_subref_array (e)
+                   && !(fsym && fsym->as
+                        && (fsym->as->type == AS_ASSUMED_SHAPE
+                            || fsym->as->type == AS_ASSUMED_RANK
+                            || fsym->as->type == AS_DEFERRED))
                    && !(fsym && fsym->attr.pointer))
                /* The actual argument is a component reference to an
                   array of derived types.  In this case, the argument
diff --git a/gcc/testsuite/gfortran.dg/array_subref_actual_arg_1.f90 
b/gcc/testsuite/gfortran.dg/array_subref_actual_arg_1.f90
new file mode 100644
index 000000000000..a52f9c39c320
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/array_subref_actual_arg_1.f90
@@ -0,0 +1,186 @@
+! { dg-do run }
+! { dg-additional-options "-Warray-temporaries -fdump-tree-original" }
+!
+! Check correct passing of subreference arrays, with either a descriptor
+! without data copy to a temporary, or no descriptor and data copy.
+! 
+! We check the presence of temporaries in the dump based on the variable name
+! array descriptors that don't use a temporary are named PARM, whereas 
variables
+! that do data copy are named ATMP.
+
+module m
+
+  implicit none
+  integer, parameter :: k = selected_int_kind (6)
+  type :: t
+    integer(kind=k) :: a, b
+  end type t
+  type, extends(t) :: u
+    integer(kind=k) :: c
+  end type u
+  integer, parameter :: s = 3 ! number of integers in a type u 
+  integer, parameter :: r = 3 ! extent of x in each dimension
+  type(u) :: x(r, r)
+  integer, parameter :: dat(s*r*r) =  (/  2,  3,  5,  7, 11, 13,  &
+                                         17, 19, 23, 29, 31, 37,  &
+                                         41, 43, 47, 53, 59, 61,  &
+                                         67, 71, 73, 79, 83, 89,  &
+                                         97,101,103  /)
+
+contains
+
+  subroutine init(z)
+    type(u) :: z(:,:)
+    integer :: i, j
+    do j=1,r
+      associate (n => (j-1)*r*s)
+        do i = 1,r
+          associate(m => n+(i-1)*s)
+            associate(p => dat(m+1:m+s))
+              z(i,j) = u(p(1), p(2), p(3))
+            end associate
+          end associate
+        end do
+      end associate
+    end do
+  end subroutine init
+
+  subroutine check(z, i, j, p1, p2, error_code)
+    type(t), intent(in) :: z
+    integer, intent(in) :: i, j,  error_code
+    integer(kind=k), intent(in) :: p1, p2
+    if (z%a /= p1 .or. z%b /= p2) then
+      print *, i, j
+      print *, z
+      print *, p1, p2
+      error stop error_code
+    end if
+  end subroutine check
+
+  subroutine sub_assumed_shape(y)
+    type(t), intent(in) :: y(:,:)
+    integer :: i, j
+    if (any(shape(y) /= shape(x))) error stop 1
+    do j=1,r
+      associate (n => (j-1)*r*s)
+        do i = 1,r
+          associate(m => n+(i-1)*s)
+            associate(p => dat(m+1:m+s))
+              call check(y(i,j), i, j, p(1), p(2), 2)
+            end associate
+          end associate
+        end do
+      end associate
+    end do
+  end subroutine sub_assumed_shape
+
+  subroutine sub_explicit(y)
+    type(t), intent(in) :: y(r,r)
+    integer :: i, j
+    if (any(shape(y) /= shape(x))) error stop 11
+    do j=1,r
+      associate (n => (j-1)*r*s)
+        do i = 1,r
+          associate(m => n+(i-1)*s)
+            associate(p => dat(m+1:m+s))
+              call check(y(i, j), i, j, p(1), p(2), 12)
+            end associate
+          end associate
+        end do
+      end associate
+    end do
+  end subroutine sub_explicit
+
+  subroutine sub_assumed_size(y)
+    type(t), intent(in) :: y(r,*)
+    integer :: i, j
+    if (size(y,1) /= size(x,1)) error stop 21
+    do j=1,r
+      associate (n => (j-1)*r*s)
+        do i = 1,r
+          associate(m => n+(i-1)*s)
+            associate(p => dat(m+1:m+s))
+              call check(y(i, j), i, j, p(1), p(2), 22)
+            end associate
+          end associate
+        end do
+      end associate
+    end do
+  end subroutine sub_assumed_size
+
+  subroutine sub_assumed_rank(y)
+    type(t), intent(in) :: y(..)
+    integer :: i, j
+    if (any(shape(y) /= shape(x))) error stop 41
+    select rank (y)
+      rank(2)
+        do j=1,r
+          associate (n => (j-1)*r*s)
+            do i = 1,r
+              associate(m => n+(i-1)*s)
+                associate(p => dat(m+1:m+s))
+                  call check(y(i, j), i, j, p(1), p(2), 42)
+                end associate
+              end associate
+            end do
+          end associate
+        end do
+      rank default
+        error stop 43
+    end select
+  end subroutine sub_assumed_rank
+
+end module m
+
+subroutine sub_implicit(y)
+  use m
+  type(t), intent(in) :: y(r,r)
+  integer :: i, j
+  if (size(y,1) /= size(x,1)) error stop 31
+  do j=1,r
+    associate (n => (j-1)*r*s)
+      do i = 1,r
+        associate(m => n+(i-1)*s)
+          associate(p => dat(m+1:m+s))
+            call check(y(i, j), i, j, p(1), p(2), 32)
+          end associate
+        end associate
+      end do
+    end associate
+  end do
+end subroutine sub_implicit
+
+program p
+  use m
+  implicit none
+
+  call init(x)
+
+  ! Descriptor without data copy: one single usage of the data pointer for its 
initialisation.
+  call sub_assumed_shape(x%t)
+  ! { dg-final { scan-tree-dump-var {sub_assumed_shape \(&parm\.(\d+)\);} 
original ashp_parm_id } }
+  ! { dg-final { global ashp_parm_id; scan-tree-dump-times 
"parm.${ashp_parm_id}\\.data" 1 original } }
+
+  ! Use a temporary; there are three usages of the data pointer: one for its 
initialisation,
+  ! one for the data copy, and one for passing as actual argument
+  call sub_explicit(x%t)       ! { dg-warning "array temporary" }
+  ! { dg-final { scan-tree-dump-var {sub_explicit \(\(.*?\) 
atmp.(\d+)\.data\);} original expl_tmp_id } }
+  ! { dg-final { global expl_tmp_id; scan-tree-dump-times 
"atmp.${expl_tmp_id}\\.data" 3 original } }
+
+  ! Use a temporary; there are three usages of the data pointer: one for its 
initialisation,
+  ! one for the data copy, and one for passing as actual argument
+  call sub_assumed_size(x%t)   ! { dg-warning "array temporary" }
+  ! { dg-final { scan-tree-dump-var {sub_assumed_size \(\(.*?\) 
atmp.(\d+)\.data\);} original asz_tmp_id } }
+  ! { dg-final { global asz_tmp_id; scan-tree-dump-times 
"atmp.${asz_tmp_id}\\.data" 3 original } }
+
+  ! Use a temporary; there are four usages of the data pointer: one for its 
initialisation,
+  ! one for the data copy in, one for passing as actual argument, and one for 
data copy out
+  call sub_implicit(x%t)       ! { dg-warning "array temporary" }
+  ! { dg-final { scan-tree-dump-var {sub_implicit \(\(.*?\) 
atmp.(\d+)\.data\);} original impl_tmp_id } }
+  ! { dg-final { global impl_tmp_id; scan-tree-dump-times 
"atmp.${impl_tmp_id}\\.data" 4 original } }
+
+  ! Descriptor without data copy: one single usage of the data pointer for its 
initialisation.
+  call sub_assumed_rank(x%t)
+  ! { dg-final { scan-tree-dump-var {sub_assumed_rank \(&parm\.(\d+)\);} 
original arnk_parm_id } }
+  ! { dg-final { global arnk_parm_id; scan-tree-dump-times 
"parm.${arnk_parm_id}\\.data" 1 original } }
+end program p
diff --git a/gcc/testsuite/lib/scandump.exp b/gcc/testsuite/lib/scandump.exp
index a8441daa22fa..74a77f0a57e1 100644
--- a/gcc/testsuite/lib/scandump.exp
+++ b/gcc/testsuite/lib/scandump.exp
@@ -214,6 +214,56 @@ proc scan-dump-not { args } {
     }
 }
 
+# Utility for scanning compiler result, invoked via dg-final.
+# Call pass if pattern is present, otherwise fail.
+#
+# Argument 0 is the type of dump we are searching (rtl, tree, ipa)
+# Argument 1 is the regexp to match.
+# Argument 2 is the suffix for the dump file
+# Argument 3 is the suffix of the dump base
+# Argument 4 is the variable name to store the matched content
+# Argument 5 handles expected failures and the like
+proc scan-dump-var { args } {
+
+    if { [llength $args] >= 6 } {
+        switch [dg-process-target [lindex $args 5]] {
+            "S" { }
+            "N" { return }
+            "F" { setup_xfail "*-*-*" }
+            "P" { }
+        }
+    }
+
+    set testcase [testname-for-summary]
+    # The name might include a list of options; extract the file name.
+    set filename [lindex $testcase 0]
+
+    set printable_pattern [make_pattern_printable [lindex $args 1]]
+    set suf [dump-suffix [lindex $args 2]]
+    set testname "$testcase scan-[lindex $args 0]-dump $suf 
\"$printable_pattern\""
+    set src [file tail $filename]
+    set dumpbase [dump-base $src [lindex $args 3]]
+
+    set pattern "$dumpbase.[lindex $args 2]"
+    set output_file "[glob-dump-file $testcase $pattern]"
+    if { $output_file == "" } {
+       unresolved "$testname"
+       return
+    }
+
+    set fd [open $output_file r]
+    set text [read $fd]
+    close $fd
+
+    global [lindex $args 4]
+    set [lindex $args 4] {}
+    if [regexp -- [lindex $args 1] $text scratch [lindex $args 4]] {
+       pass "$testname"
+    } else {
+       fail "$testname"
+    }
+}
+
 # Utility for scanning demangled compiler result, invoked via dg-final.
 # Call pass if pattern is present, otherwise fail.
 #
diff --git a/gcc/testsuite/lib/scantree.exp b/gcc/testsuite/lib/scantree.exp
index 833ac387eb4b..b67713e11cbf 100644
--- a/gcc/testsuite/lib/scantree.exp
+++ b/gcc/testsuite/lib/scantree.exp
@@ -94,6 +94,32 @@ proc scan-tree-dump-not { args } {
     }
 }
 
+# Utility for scanning compiler result, invoked via dg-final.
+# Call pass if pattern is present, otherwise fail.
+#
+# Argument 0 is the regexp to match
+# Argument 1 is the name of the dumped tree pass
+# Argument 2 is the variable name to store the matched content
+# Argument 3 handles expected failures and the like
+proc scan-tree-dump-var { args } {
+
+    if { [llength $args] < 3 } {
+       error "scan-tree-dump-var: too few arguments"
+       return
+    }
+    if { [llength $args] > 4 } {
+       error "scan-tree-dump-var: too many arguments"
+       return
+    }
+    if { [llength $args] >= 4 } {
+       scan-dump-var "tree" [lindex $args 0] \
+                 "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" "" [lindex $args 2] 
[lindex $args 3]
+    } else {
+       scan-dump-var "tree" [lindex $args 0] \
+                 "\[0-9\]\[0-9\]\[0-9\]t.[lindex $args 1]" "" [lindex $args 2]
+    }
+}
+
 # Utility for scanning demangled compiler result, invoked via dg-final.
 # Call pass if pattern is present, otherwise fail.
 #

Reply via email to