Hi Andre,
Am 03.07.24 um 12:58 schrieb Andre Vehreschild:
Hi Harald,
I am sorry for the long delay, but fixing the negative stride lead from one
issue to the next. I finally got a version that does not regress. Please have a
look.
This patch has two parts:
1. The runtime library part in pr96992_3p1.patch and
2. the compiler changes in pr96992_3p2.patch.
In my branch also the two patches from Paul for pr59104 and pr102689 are
living, which might lead to small shifts during application of the patches.
NOTE, this patch adds internal packing and unpacking of class arrays similar to
the regular pack and unpack. I think this is necessary, because the regular
un-/pack does not use the vptr's _copy routine for moving data and therefore
may produce bugs.
The un-/pack_class routines are yet only used for converting a derived type
array to a class array. Extending their use when a UN-/PACK() is applied on a
class array is still to be done (as part of another PR).
Regtests fine on x86_64-pc-linux-gnu/ Fedora 39.
this is a really huge patch to review, and I am not sure that I can do
this without help from others. Paul? Anybody else?
As far as I can tell for now:
- pr96992_3p1.patch (the libgfortran part) looks good to me.
- git had some whitespace issues with pr96992_3p2.patch as attached,
but I could fix that locally and do some testing parallel to reading.
A few advance comments on the latter patch:
- my understanding is that the PR at the end of a summary line should be
like in:
Fortran: Fix rejecting class arrays of different ranks as storage
association argument [PR96992]
I was told that this helps people explicitly scanning for the PR
number in that place.
- some rewrites of logical conditions change the coding style from
what it recommended GNU coding style, and I find the more compact
way used in some places harder to grok (but that may be just me).
Example:
@@ -8850,20 +8857,24 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr
* expr, bool g77,
/* There is no need to pack and unpack the array, if it is contiguous
and not a deferred- or assumed-shape array, or if it is simply
contiguous. */
- no_pack = ((sym && sym->as
- && !sym->attr.pointer
- && sym->as->type != AS_DEFERRED
- && sym->as->type != AS_ASSUMED_RANK
- && sym->as->type != AS_ASSUMED_SHAPE)
- ||
- (ref && ref->u.ar.as
- && ref->u.ar.as->type != AS_DEFERRED
+ no_pack = false;
+ gfc_array_spec *as;
+ if (sym)
+ {
+ symbol_attribute *attr
+ = &(IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->attr : sym->attr);
+ as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as;
+ no_pack
+ = (as && !attr->pointer && as->type != AS_DEFERRED
+ && as->type != AS_ASSUMED_RANK && as->type != AS_ASSUMED_SHAPE);
+ }
+ if (ref && ref->u.ar.as)
+ no_pack = no_pack
+ || (ref->u.ar.as->type != AS_DEFERRED
&& ref->u.ar.as->type != AS_ASSUMED_RANK
- && ref->u.ar.as->type != AS_ASSUMED_SHAPE)
- ||
- gfc_is_simply_contiguous (expr, false, true));
-
- no_pack = contiguous && no_pack;
+ && ref->u.ar.as->type != AS_ASSUMED_SHAPE);
+ no_pack
+ = contiguous && (no_pack || gfc_is_simply_contiguous (expr, false,
true));
/* If we have an EXPR_OP or a function returning an explicit-shaped
or allocatable array, an array temporary will be generated which
I understand that this may be your personal coding style, but you
might keep in mind that reviewers have to understand the code, too...
I have not fully understood your logic when packing is now invoked.
We not only need to do it for explicit-size arrays, but also for
assumed-size. This still fails for my slightly extended testcase
(see attached) where I pass the class array via:
subroutine d4(x,n)
integer, intent(in) :: n
! class (foo), intent(inout) :: x(n) ! OK
class (foo), intent(inout) :: x(*) ! not OK
call d3(x,n) ! Simply pass assumed-size array
end subroutine d4
I am unable to point to the places in your patch where you need to
handle that in addition.
Otherwise I was unable to see any obvious, major problem with the
patch, but then I am not fluent enough in class handling in the
gfortran FE. So if e.g. Paul jumps in here within the next 72 hours,
it would be great.
So here comes the issue with the attached code variant.
After your patch, this prints as last 4 relevant lines:
full: -43 44 45 -46 47
48 -49 50
d3_1: -43 44 45
d3_2: 43 -44 -45
full: 43 -44 -45 -46 47
48 -49 50
while when switching the declaration of the dummy argument of d4:
full: -43 44 45 -46 47
48 -49 50
d3_1: -43 -46 -49
d3_2: 43 46 49
full: 43 44 45 46 47
48 49 50
The latter one is correct, the former one isn't.
Sorry for spoiling the show...
Nevertheless, thanks for your great effort so far!
Harald
Regards,
Andre
PS: @Paul I could figure my test failures with -Ox with x e { 2, 3, s } to be
caused by initialization order. I.e. a member was set only after it was read.
[remaining part of mail removed]
module foo_mod
implicit none
type foo
integer :: i
end type foo
contains
subroutine d1(x,n)
integer, intent(in) :: n
integer :: i
class (foo), intent(out) :: x(n)
!print *, "d1:lbound=", lbound (x)
select type(x)
class is(foo)
x(:)%i = (/ (42 + i, i = 1, n ) /)
class default
stop 1
end select
end subroutine d1
subroutine d2(x,n)
integer, intent(in) :: n
integer :: i
class (foo), intent(in) :: x(n,n,n)
!print *, "d2:lbound=", lbound (x)
select type (x)
class is (foo)
print *,"d2: ", x%i
if ( any( x%i /= reshape((/ (42 + i, i = 1, n ** 3 ) /), [n, n, n] ))) stop 2
class default
stop 3
end select
end subroutine d2
subroutine d3(x,n)
integer, intent(in) :: n
integer :: i
class (foo), intent(inout) :: x(n)
!print *, "d3:lbound=", lbound (x)
select type (x)
class is (foo)
print *,"d3_1:", x%i
x%i = -x%i ! Simply negate elements
print *,"d3_2:", x%i
class default
stop 33
end select
end subroutine d3
subroutine d4(x,n)
integer, intent(in) :: n
! class (foo), intent(inout) :: x(n) ! OK
class (foo), intent(inout) :: x(*) ! not OK
call d3(x,n) ! Simply pass assumed-size array
end subroutine d4
end module foo_mod
program main
use foo_mod
implicit none
type (foo), dimension(:), allocatable :: f
integer :: n, k, m
n = 2
allocate (f(n*n*n))
! Original testcase:
call d1(f,n*n*n)
print *, "d1->:", f%i
call d2(f,n)
! Ensure that array f is ok:
print *, "d2->:", f%i
! The following shows that no appropriate internal pack is generated:
call d1(f,n*n*n)
print *, "d1->:", f%i
m = n*n*n
k = 3
print *, "->d3:", f(1:m:k)%i
call d3(f(1:m:k),1+(m-1)/k)
print *, "d3->:", f(1:m:k)%i
print *, "full:", f%i
call d4(f(1:m:k),1+(m-1)/k)
print *, "full:", f%i
print *, "(the last printed line should be identical to the first one)"
deallocate (f)
end program main