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

Reply via email to