https://gcc.gnu.org/g:81092921c6393d4ed39aacb354228c55fc406d52

commit r17-3980-g81092921c6393d4ed39aacb354228c55fc406d52
Author: Jerry DeLisle <[email protected]>
Date:   Mon Sep 7 14:24:57 2026 -0700

    fortran: [PR126964] Fold the element spacing on the field alignment
    
    A target can align a component less strictly than its type: the i386
    ABI aligns a real(8) component to 4, so the spacing of one is not always a
    multiple of 8.  Compare against min_align_of_type instead.
    
            PR fortran/126964
    
    gcc/fortran/ChangeLog:
    
            * trans-array.cc: Include stor-layout.h.
            (gfc_span_folds_into_stride): Compare the element length against
            the least alignment of its type rather than the alignment.
    
    gcc/testsuite/ChangeLog:
    
            * gfortran.dg/target_dummy_span_2.f90: New test.
            * gfortran.dg/c_loc_test_22.f90: Expect the addressing of the
            target.
            * gfortran.dg/gomp/target-span-1.f90: Likewise.
            * gfortran.dg/target_dummy_repack_1.f90: Likewise.
            * gfortran.dg/target_dummy_span_1.f90: Likewise.
            * gfortran.dg/class_to_type_9.f90: Do not assert whether an
            assumed shape dummy is passed the strides or a copy.

Diff:
---
 gcc/fortran/trans-array.cc                         |  3 +-
 gcc/testsuite/gfortran.dg/c_loc_test_22.f90        | 16 +++++---
 gcc/testsuite/gfortran.dg/class_to_type_9.f90      |  7 ++--
 gcc/testsuite/gfortran.dg/gomp/target-span-1.f90   | 15 +++++---
 .../gfortran.dg/target_dummy_repack_1.f90          |  9 +++--
 gcc/testsuite/gfortran.dg/target_dummy_span_1.f90  | 18 ++++-----
 gcc/testsuite/gfortran.dg/target_dummy_span_2.f90  | 45 ++++++++++++++++++++++
 7 files changed, 84 insertions(+), 29 deletions(-)

diff --git a/gcc/fortran/trans-array.cc b/gcc/fortran/trans-array.cc
index c9e06c486319..3e3e88012efd 100644
--- a/gcc/fortran/trans-array.cc
+++ b/gcc/fortran/trans-array.cc
@@ -87,6 +87,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attribs.h" /* For lookup_attribute.  */
 #include "trans.h"
 #include "fold-const.h"
+#include "stor-layout.h" /* For min_align_of_type.  */
 #include "constructor.h"
 #include "trans-types.h"
 #include "trans-array.h"
@@ -541,7 +542,7 @@ gfc_span_folds_into_stride (gfc_symbol *sym)
 
   return (size
          && tree_fits_uhwi_p (size)
-         && tree_to_uhwi (size) == TYPE_ALIGN_UNIT (etype));
+         && tree_to_uhwi (size) == min_align_of_type (etype));
 }
 
 
diff --git a/gcc/testsuite/gfortran.dg/c_loc_test_22.f90 
b/gcc/testsuite/gfortran.dg/c_loc_test_22.f90
index fa5b06a588df..5a7172d952c1 100644
--- a/gcc/testsuite/gfortran.dg/c_loc_test_22.f90
+++ b/gcc/testsuite/gfortran.dg/c_loc_test_22.f90
@@ -18,11 +18,15 @@ end
 ! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void .\\) 
&\\(.xxx.\[0-9\]+\\)\\\[0\\\];" 1 "original" } }
 ! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void .\\) 
&\\(.xxx.\[0-9\]+\\)\\\[D.\[0-9\]+ \\* 4\\\];" 1 "original" } }
 ! The elements of a TARGET assumed-shape dummy can be spaced by more than the
-! element length.  For an element length that divides the spacing, the spacing
-! is folded into the strides on entry, so the elements are addressed by the
-! constant element length rather than by a span loaded from the descriptor.
-! { dg-final { scan-tree-dump-not "span.\[0-9\]+ = yyy->span;" "original" } }
-! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void .\\) 
yyy.\[0-9\]+;" 1 "original" } }
-! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void .\\) 
yyy.\[0-9\]+ \\+ \\(sizetype\\) \\(D.\[0-9\]+ \\* 16\\);" 1 "original" } }
+! element length.  The spacing is folded into the strides on entry where the
+! element length is the element alignment, so that the elements are addressed
+! by the constant element length rather than by a span loaded from the
+! descriptor.  Elsewhere they are addressed by the span.
+! { dg-final { scan-tree-dump-not "span.\[0-9\]+ = yyy->span;" "original" { 
target natural_alignment_32 } } }
+! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void .\\) 
yyy.\[0-9\]+;" 1 "original" { target natural_alignment_32 } } }
+! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void .\\) 
yyy.\[0-9\]+ \\+ \\(sizetype\\) \\(D.\[0-9\]+ \\* 16\\);" 1 "original" { target 
natural_alignment_32 } } }
+! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void .\\) 
&\\(.yyy.\[0-9\]+\\)\\\[0\\\];" 1 "original" { target { ! natural_alignment_32 
} } } }
+! { dg-final { scan-tree-dump-times "span.\[0-9\]+ = yyy->span;" 1 "original" 
{ target { ! natural_alignment_32 } } } }
+! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void .\\) 
yyy.\[0-9\]+ \\+ \\(sizetype\\) \\(\\(D.\[0-9\]+ \\* span.\[0-9\]+\\) \\* 
4\\);" 1 "original" { target { ! natural_alignment_32 } } } }
 
 ! { dg-final { scan-tree-dump-times "D.\[0-9\]+ = 
parm.\[0-9\]+.data;\[^;]+ptr\[1-4\] = D.\[0-9\]+;" 4 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/class_to_type_9.f90 
b/gcc/testsuite/gfortran.dg/class_to_type_9.f90
index 47d90c5080e5..c366ff1906b7 100644
--- a/gcc/testsuite/gfortran.dg/class_to_type_9.f90
+++ b/gcc/testsuite/gfortran.dg/class_to_type_9.f90
@@ -5,7 +5,9 @@
 ! A TARGET dummy associated with elements that are spaced by more than the
 ! element size: pointers to it stay valid after the call, it is written
 ! through, it is not contiguous, it is passed on to an assumed-shape dummy
-! by its strides and copied for a dummy that has no descriptor.
+! and copied for a dummy that has no descriptor.  Whether the assumed-shape
+! dummy takes the strides or a copy depends on the element alignment of the
+! target, so it is not asserted here.
 
 module m
   implicit none
@@ -28,10 +30,9 @@ contains
     saved => a
     a(2) = -a(2)
   end subroutine
-  subroutine assumed_shape(b)  ! strides passed on, no copy
+  subroutine assumed_shape(b)
     integer :: b(:)
     if (any(b /= [1, 4, 9, 16])) stop 5
-    if (is_contiguous(b)) stop 6
   end subroutine
   subroutine assumed_size(c)   ! no descriptor
     integer :: c(*)
diff --git a/gcc/testsuite/gfortran.dg/gomp/target-span-1.f90 
b/gcc/testsuite/gfortran.dg/gomp/target-span-1.f90
index e391d1bbc024..27a9de573a66 100644
--- a/gcc/testsuite/gfortran.dg/gomp/target-span-1.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/target-span-1.f90
@@ -6,8 +6,8 @@
 !
 ! A TARGET assumed-shape dummy is addressed through the span of its
 ! descriptor.  The descriptor is not mapped to the device, so the span has
-! to be read on entry and folded into the local strides, rather than the
-! target region dereferencing the descriptor.
+! to be read into a local variable on entry, rather than the target region
+! dereferencing the descriptor.
 
 module m
   use iso_c_binding
@@ -24,9 +24,12 @@ contains
   end subroutine inner
 end module m
 
-! The span is read from the descriptor once, on entry, and scales the strides.
+! The span is read from the descriptor once, on entry.  Where the element
+! length is the element alignment it scales the strides, and the element
+! reference uses the local strides and the element length.
 ! { dg-final { scan-tree-dump-times "= t->span;" 1 "original" } }
-! { dg-final { scan-tree-dump "stride\.\[0-9\]+ = \[^;\]* != 8 \\? 
stride\.\[0-9\]+ \\* \[^;\]* : stride\.\[0-9\]+;" "original" } }
-! The element reference uses the local strides and the element length.
-! { dg-final { scan-tree-dump "t\.\[0-9\]+ \\+ \\(sizetype\\) 
\\(\\(offset\.\[0-9\]+ \\+ \[^)\]*stride\.\[0-9\]+\[^)\]*\\) \\* 8\\)" 
"original" } }
+! { dg-final { scan-tree-dump "stride\.\[0-9\]+ = \[^;\]* != 8 \\? 
stride\.\[0-9\]+ \\* \[^;\]* : stride\.\[0-9\]+;" "original" { target 
natural_alignment_64 } } }
+! { dg-final { scan-tree-dump "t\.\[0-9\]+ \\+ \\(sizetype\\) 
\\(\\(offset\.\[0-9\]+ \\+ \[^)\]*stride\.\[0-9\]+\[^)\]*\\) \\* 8\\)" 
"original" { target natural_alignment_64 } } }
+! Elsewhere the reference uses that local span, not the descriptor.
+! { dg-final { scan-tree-dump "t\.\[0-9\]+ \\+ \\(sizetype\\) 
\\(\\(offset\.\[0-9\]+ \\+ \[^)\]*stride\.\[0-9\]+\[^)\]*\\) \\* 
span\.\[0-9\]+\\)" "original" { target { ! natural_alignment_64 } } } }
 ! { dg-final { scan-tree-dump-not "\\* t->span" "original" } }
diff --git a/gcc/testsuite/gfortran.dg/target_dummy_repack_1.f90 
b/gcc/testsuite/gfortran.dg/target_dummy_repack_1.f90
index e94bd8a13539..f67fa081735b 100644
--- a/gcc/testsuite/gfortran.dg/target_dummy_repack_1.f90
+++ b/gcc/testsuite/gfortran.dg/target_dummy_repack_1.f90
@@ -1,8 +1,9 @@
 ! { dg-do run }
 ! { dg-options "-fdump-tree-original" }
 ! PR126964
-! The spacing of the elements of a numeric TARGET assumed-shape dummy is
-! folded into the strides of its descriptor on entry, so the dummy is not
+! The spacing of the elements of a numeric TARGET assumed-shape dummy whose
+! element length is its alignment is folded into the strides of its
+! descriptor on entry, so the dummy is not
 ! addressed through its span and its elements are not subobjects of larger
 ! ones.  Passing it on to a dummy that has a descriptor of its own therefore
 ! needs neither a copy nor a test.  Testing full contiguity instead made a
@@ -73,5 +74,5 @@ program p
 end program
 
 ! The dummy is passed on directly: no copy and no test of its span.
-! { dg-final { scan-tree-dump-not "contiguous\\.\[0-9\]+" "original" } }
-! { dg-final { scan-tree-dump-not "atmp\\.\[0-9\]+" "original" } }
+! { dg-final { scan-tree-dump-not "contiguous\\.\[0-9\]+" "original" { target 
natural_alignment_32 } } }
+! { dg-final { scan-tree-dump-not "atmp\\.\[0-9\]+" "original" { target 
natural_alignment_32 } } }
diff --git a/gcc/testsuite/gfortran.dg/target_dummy_span_1.f90 
b/gcc/testsuite/gfortran.dg/target_dummy_span_1.f90
index 43870a2be781..314bd8c8abb2 100644
--- a/gcc/testsuite/gfortran.dg/target_dummy_span_1.f90
+++ b/gcc/testsuite/gfortran.dg/target_dummy_span_1.f90
@@ -4,8 +4,8 @@
 ! PR126964
 !
 ! The elements of a TARGET assumed-shape dummy can be spaced by more than
-! the element length.  Where the element length divides the spacing, the
-! spacing is folded into the strides on entry, so that the elements are
+! the element length.  Where the element length is the element alignment,
+! the spacing is folded into the strides on entry, so that the elements are
 ! addressed by the constant element length rather than by a span loaded
 ! from the descriptor.  Addressing by a runtime span leaves the data
 ! reference step symbolic, which stops the loops from being vectorized.
@@ -51,12 +51,12 @@ program p
   if (any (x%a /= -1.0_8)) stop 5
 end program
 
-! The spacing is read from the descriptor once, on entry, and scales both
-! strides and the offset.
-! { dg-final { scan-tree-dump-times "= self->span;" 1 "original" } }
-! { dg-final { scan-tree-dump-times "\\? stride\.\[0-9\]+ \\* \[^;\]+ : 
stride\.\[0-9\]+;" 2 "original" } }
-! { dg-final { scan-tree-dump-times "\\? offset\.\[0-9\]+ \\* \[^;\]+ : 
offset\.\[0-9\]+;" 1 "original" } }
-! No span variable is created and the elements are addressed by the element
+! Where the element length is the element alignment, the spacing is read from
+! the descriptor once, on entry, and scales both strides and the offset; no
+! span variable is created and the elements are addressed by the element
 ! length.
-! { dg-final { scan-tree-dump-not "span\.\[0-9\]+" "original" } }
+! { dg-final { scan-tree-dump-times "= self->span;" 1 "original" } }
+! { dg-final { scan-tree-dump-times "\\? stride\.\[0-9\]+ \\* \[^;\]+ : 
stride\.\[0-9\]+;" 2 "original" { target natural_alignment_64 } } }
+! { dg-final { scan-tree-dump-times "\\? offset\.\[0-9\]+ \\* \[^;\]+ : 
offset\.\[0-9\]+;" 1 "original" { target natural_alignment_64 } } }
+! { dg-final { scan-tree-dump-not "span\.\[0-9\]+" "original" { target 
natural_alignment_64 } } }
 ! { dg-final { scan-tree-dump-not "\\* self->span" "original" } }
diff --git a/gcc/testsuite/gfortran.dg/target_dummy_span_2.f90 
b/gcc/testsuite/gfortran.dg/target_dummy_span_2.f90
new file mode 100644
index 000000000000..a7473e460146
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/target_dummy_span_2.f90
@@ -0,0 +1,45 @@
+! { dg-do run }
+!
+! PR126964
+!
+! The spacing of the elements of a TARGET assumed-shape dummy is folded into
+! its strides only where the element length is the least alignment the element
+! can be given as a component, so that the spacing is a multiple of it.  Using
+! the alignment of the type instead scaled the strides by a truncated ratio
+! wherever a target aligns a component less strictly than its type: a real(8)
+! component is aligned to 4 by the i386 ABI, so the spacing here is 12.
+
+module m
+  implicit none
+  type :: t
+     integer :: i
+     real(8) :: d
+  end type
+contains
+  subroutine chk (a, n)
+    real(8), target :: a(:)
+    integer, intent(in) :: n
+    integer :: k
+    do k = 1, n
+       if (a(k) /= real (k, 8)) stop 1
+    end do
+    a(2) = -a(2)
+  end subroutine
+end module
+
+program p
+  use m
+  implicit none
+  integer, parameter :: n = 5
+  type(t), target :: v(n)
+  integer :: k
+
+  v%i = 0
+  v%d = [(real (k, 8), k = 1, n)]
+
+  call chk (v%d, n)
+
+  if (v(2)%d /= -2.0_8) stop 2
+  if (any (v%i /= 0)) stop 3
+  if (any (v((/1,3,4,5/))%d /= [1.0_8, 3.0_8, 4.0_8, 5.0_8])) stop 4
+end program

Reply via email to