# Memory alignment for SIMD

**URL:** <https://fortran-lang.discourse.group/t/memory-alignment-for-simd/6839>\
**Category:** Uncategorized\
**Created:** [November 20, 2023, 4:19pm UTC](https://fortran-lang.discourse.group/t/memory-alignment-for-simd/6839 "2023-11-20T16:19:52Z")\
**Posts on this page:** 1\
**Showing post:** 4

<div class="post-metadata">

**Author:** ![ivanpribec](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/ivanpribec/32/3290_2.png) [@ivanpribec](https://fortran-lang.discourse.group/u/ivanpribec)\
**Post date:** [November 20, 2023, 7:22pm UTC](https://fortran-lang.discourse.group/t/memory-alignment-for-simd/6839/4 "2023-11-20T19:22:47Z")

</div>

Perhaps using `aligned_alloc` is slightly easier, since it comes with the C standard library:

```fortran
! test_aligned_alloc.f90
!
program test_aligned_alloc
use, intrinsic :: iso_c_binding
implicit none
interface
    ! size must be a multiple of alignment
    function c_aligned_alloc(alignment,size) bind(c,name="aligned_alloc")
         import c_size_t, c_ptr
         integer(c_size_t), value :: alignment, size
         type(c_ptr) :: c_aligned_alloc
    end function
    subroutine c_free(ptr) bind(c,name="free")
        import c_ptr
        type(c_ptr), value :: ptr
    end subroutine
end interface

integer, parameter :: wp = c_float

type(c_ptr) :: a_p = c_null_ptr
real(wp), pointer :: a(:)
integer :: n, npad

integer, parameter :: balign = 16

n = 5
print *, "n = ", n

npad = n + (balign - mod(n * c_sizeof(1.0_wp), balign))/c_sizeof(1.0_wp)
print *, "npad = ", npad

! size of allocated array must be an integer multiple of the alignment
a_p = c_aligned_alloc( int(balign,c_size_t), npad * c_sizeof(1.0_wp))
call c_f_pointer(a_p,a,[n])
print *, "mod(loc(a),balign) = ", mod(loc(a),balign)

call random_number(a)
call square(a)

print '(F10.3,2X)', a

nullify(a)
call c_free(a_p)
a_p = c_null_ptr

contains 
    subroutine square(a)
        real(wp), intent(inout) :: a(:)
        a = a**2
    end subroutine
end program

```

The [`omp_alloc`](https://www.openmp.org/spec-html/5.1/openmpsu200.html) function also works with gfortran v13, unfortunately, the [`allocators`](https://fortran-lang.discourse.group/t/openmp-and-allocate/6795/5) directive for allocatable arrays is not supported yet:

```auto
! test_omp_alloc.f90
!
program test_aligned_alloc
use, intrinsic :: iso_c_binding
use omp_lib
implicit none

integer, parameter :: wp = c_float

integer(omp_memspace_handle_kind) :: a_memspace = omp_default_mem_space
type(omp_alloctrait) :: a_traits(1) = &
                                        [omp_alloctrait(omp_atk_alignment,16)]
integer(omp_allocator_handle_kind) :: a_alloc

real(wp), pointer :: a(:)
type(c_ptr) :: a_p = c_null_ptr
integer :: i, n

a_alloc = omp_init_allocator( a_memspace, 1, a_traits)

n = 5
a_p = omp_alloc(n * c_sizeof(1.0_wp), a_alloc)
call c_f_pointer(a_p, a, [n])
print *, "mod(loc(a),16) = ", mod(loc(a),16)

call random_number(a)
call square(a)

print '(F10.3,2X)', a

! Edit 2: inserted lines to free memory
nullify(a)
call omp_free(a_p, a_alloc)
call omp_destroy_allocator(a_alloc)

contains 
    subroutine square(a)
        real(wp), intent(inout) :: a(:)
        a = a**2
    end subroutine
end program

```

Even if you obtain aligned memory, GNU Fortran doesn’t have a directive to force aligned loads and stores. The `!$omp simd aligned(...)` is there, but its unclear what type of variables are allowed to appear in it.

Currently, gfortran appears to follow the [OpenMP 4.0](https://www.openmp.org/wp-content/uploads/OpenMP4.0.0.pdf#G4.1507435) standard, which lists the restriction:

> - The type of list items appearing in the aligned clause must be C\_PTR or Cray Fortran pointer, or the list item must have the POINTER or ALLOCATABLE attribute.

In [OpenMP 5.0](https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5.0.pdf), this is changed to:

> - If a list item on the aligned clause has the ALLOCATABLE attribute, the allocation status must be allocated.
> - If a list item on the aligned clause has the POINTER attribute, the association status must be associated.
> - If the type of a list item on the aligned clause is either C\_PTR or Cray pointer, the list item must be defined

Note there is no restriction regarding assumed-size or other arrays (on the stack).

In [OpenMP 5.2](https://www.openmp.org/wp-content/uploads/OpenMP-API-Specification-5-2.pdf) the aligned clause is changed again:

> - Each list item must have C\_PTR or Cray pointer type or have the POINTER or ALLOCATABLE attribute. Cray pointer support has been deprecated.
> - If a list item has the ALLOCATABLE attribute, the allocation status must be allocated.
> - If a list item has the POINTER attribute, the association status must be associated.
> - If the type of a list item is either C\_PTR or Cray pointer, it must be defined. Cray pointer support has been deprecated.

gfortran and the Intel Fortran compilers appears to interpret these differently: [Compiler Explorer](https://godbolt.org/z/bTPjaMsjh)

Edit: In the upcoming [OpenMP 6.0](https://www.openmp.org/wp-content/uploads/openmp-TR11.pdf) standard (currently just a technical preview), the restrictions on `aligned` items are changed again:

> Each list item must be an array.

---

_[View the full topic](https://fortran-lang.discourse.group/t/memory-alignment-for-simd/6839)._
