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
