Jakub Jelinek wrpte:
On Fri, May 09, 2014 at 09:35:03PM +0200, Tobias Burnus wrote:
Fortran - as also C and C++ - does not provide much support for
aligned memory. [Well, C++ has now alignas and align(ment_)of.] But
contrary to C/C++, using library functions for dynamic allocation is
more difficult and gfortran doesn't support GCC's align attribute for
non-heap allocation. I only know of one commercial compiler, which
has alignment directives (for static and dynamically allocated
memory). I also was considering adding support for it - but I haven't
found the time to do so, yet.
Yeah, but besides alignas/_Alignas in C/C++ one has also posix_memalign etc.
That's what I meant with calling library functions. But posix_memalign
is restricted to POSIX systems while _mm_malloc only works on i*86 and
x86_64 systems.
The OpenMP standard allows for aligned clause:
C_PTR or Cray pointer, or var with POINTER or ALLOCATABLE attribute.
so best would be to actually test all of those, but supposedly one can't
really test it e.g. with ALLOCATABLE attribute, unless say the test is
restricted to x86_64-linux or similar platform where we know glibc malloc
allocates 16 byte aligned chunks at least and we rely on libgfortran to use
glibc malloc.
Well, as written before, you could use the manual alignment as I
suggested before. My code assumes that malloc returns memory which is
aligned to sizeof(data type); I think one can assume that this is
aligned to at least 4-byte or sizeof(void*).
I think that should be sufficient; if not, one can also first align the
memory down to byte level and then associate it with a pointer variable.
That should work with all sizeof(data type).
Below, you have a small program which gives you access to C_PTR, Cray
pointer and POINTER; combining ALLOCATABLE with aligned memory is more
difficult. BTW: gfortran doesn't call libgfortran for allocating the
memory but uses BUILTIN_MALLOC directy (since GCC 4.2?).
Tobias
program align_test
use iso_c_binding
implicit none
real, target :: x, array1(1024)
real, allocatable, target :: array2(:)
real, pointer :: ptr(:)
integer(c_ptrdiff_t) :: offset1
integer(c_ptrdiff_t) :: offset2
integer, parameter :: ALIGNVALUE = 128
offset1 = ALIGNVALUE - mod (loc (array1), ALIGNVALUE)
if (offset1 == ALIGNVALUE) &
offset1 = 0
offset1 = offset1/c_sizeof(x)
allocate (array2(-5:1024))
offset2 = ALIGNVALUE - mod (loc (array2), ALIGNVALUE)
if (offset2 == ALIGNVALUE) &
offset2 = 0
offset2 = offset2/c_sizeof(x)
! Use a lower bound which is not "1"
! For some reasons, the following does not align the memory!
!ptr(-5:) => array2(lbound(array2,dim=1)+offset2 :)
ptr => array2(lbound(array2,dim=1)+offset2 :)
call some_subroutine(array1(lbound(array1,dim=1)+offset1 : ), ptr)
contains
subroutine some_subroutine(a, b)
real, pointer, intent(in) :: a(:), b(:)
type(c_ptr) :: c
! Use an explicit size for the Cray pointer; can also be '*' instead
real :: arr(1024-ALIGNVALUE)
pointer (pt, arr)
if (mod (loc(a), ALIGNVALUE) /= 0) &
call abort()
if (mod (loc(b), ALIGNVALUE) /= 0) &
call abort()
c = c_loc(a)
pt = loc(b)
! ...
end subroutine some_subroutine
end program align_test