[gcc(refs/users/mikael/heads/refactor_descriptor_v05)] Passage de subreferences sans copie
Mikael Morin
mikael@gcc.gnu.org
Fri Jun 13 15:11:16 GMT 2025
https://gcc.gnu.org/g:66ce7c9e5f7d0f29c06e091975b3575de4400f58
commit 66ce7c9e5f7d0f29c06e091975b3575de4400f58
Author: Mikael Morin <mikael@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 4a0ec68bf60b..7181d3b0bec4 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -7568,6 +7568,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.
#
More information about the Gcc-cvs
mailing list