2.4. Fortran Comments (Free Source Form)#

OpenMP directives in Fortran codes with free source form are specified as comments that use the !$omp sentinel, followed by the directive name, and required and optional clauses. Lines are continued with an ending ampersand (&), and the continued line begins with !$omp or !$omp& . Comments may appear on the same line as the directive. Directives are case insensitive.

In the example below the first directive (DIR 1) specifies the parallel do combined directive, with a num_threads clause, and a comment. The second directive (DIR 2) shows the same directive split across two lines. The next nested directives (DIR 3 and 4) show the previous combined directive as two separate directives. Here, an end directive (end parallel) must be specified to demarcate the range (region) of the parallel directive.

!!%compiler: gfortran
!!%cflags: -fopenmp

! name:       directive_syntax_F_free_comment.1
! type:       F-free
  program main
     use omp_lib
     integer,parameter :: NT = 4

     !$omp parallel do num_threads(NT)                !DIR 1
     do i = 1,NT
       write(*,'("thrd no", i2)') omp_get_thread_num()
     end do

     !$omp  parallel do  &     !continue line         !DIR 2
     !$omp num_threads(NT)     !or !$omp&
     do i = 1,NT
       write(*,'("thrd no", i2)') omp_get_thread_num()
     end do

     !$omp parallel num_threads(NT)                   !DIR 3
     !$omp do                                         !DIR 4
     do i = 1,NT
        write(*,'("thrd no", i2)') omp_get_thread_num()
     end do
     !$omp end parallel

  end program

!     repeated 3 times, any order
!     OUTPUT: thrd no  0
!     OUTPUT: thrd no  1
!     OUTPUT: thrd no  2
!     OUTPUT: thrd no  3

As of OpenMP 5.1, block and end block statements can be used to designate a structured block for an OpenMP region, and any paired OpenMP end directive becomes optional, as shown in the next example. Note, the variables i and thrd_no are declared within the block structure and are hence private. It was necessary to explicitly declare the i variable, due to the implicit none statement; it could have also been declared outside the structured block.

!!%compiler: gfortran
!!%cflags: -fopenmp

! name:       directive_syntax_F_block.1
! type:       F-free
! version:    omp_5.1
  program main

     use omp_lib
     implicit none
     integer,parameter :: NT = 2, chunks=3

    !$omp parallel num_threads(NT)
     block                          ! Fortran 2008 OMP 5.1
       integer :: thrd_no,i
       thrd_no= omp_get_thread_num()
        !$omp do schedule(static,chunks)
        do i = 1,NT*chunks
           write(*,'("ndx=",i0.2," thrd_no=", i0.2)') i,thrd_no
        end do
     end block
  end program

! any order
! OUTPUT: ndx=01 thrd_no=00
! OUTPUT: ndx=02 thrd_no=00
! OUTPUT: ndx=03 thrd_no=00
! OUTPUT: ndx=04 thrd_no=01
! OUTPUT: ndx=05 thrd_no=01
! OUTPUT: ndx=06 thrd_no=01

A Fortran BLOCK construct may eliminate the need for a paired end directive for an OpenMP construct, as illustrated in the following example.

The first parallel construct is specified with an OpenMP loosely structured block (where the first executable construct is not a Fortran 2008 BLOCK construct). A paired end directive must end the OpenMP construct. The second parallel construct is specified with an OpenMP strictly structured block (consists only of a single Fortran BLOCK construct). The paired end directive is optional in this case, and is not used here.

The next two parallel directives form an enclosing outer parallel construct and a nested inner parallel construct. The first end parallel directive that subsequently appears terminates the inner parallel construct, because a paired end directive immediately following a BLOCK construct that is a strictly structured block of an OpenMP construct is treated as the terminating end directive of that construct. The next end parallel directive is required to terminate the outer parallel construct.

!!%compiler: gfortran
!!%cflags: -fopenmp

! name:       directive_syntax_F_block.2
! type:       F-free
! version:    omp_5.1
program main

   use omp_lib
   implicit none

  !$omp parallel num_threads(2)
     if( omp_get_thread_num() == 0 ) &
         print*, "Loosely  structured block  -- end required."
     block                                ! BLOCK Fortran 2008
       if( omp_get_thread_num() == 0 ) &
           print*, "                           --"
     end block
  !$omp end parallel

  !$omp parallel num_threads(2)
     block
       if( omp_get_thread_num() == 0 ) &
           print*, "Strictly structured block  -- end not required."
     end block
 !!$omp end parallel !is optional for strictly structured block

  print*, "Sequential part"

  !$omp parallel num_threads(2)                      !outer parallel
     if( omp_get_thread_num() == 0 ) &
         print*, "Outer, loosely  structured block."
     !$omp parallel num_threads(2)                   !inner parallel
        block
          if( omp_get_thread_num() == 0 ) &
          print*, "Inner, strictly structured block."
        end block
     !$omp end parallel
  !$omp end parallel
  ! Two end directives are required here.
  ! A single "!$omp end parallel" terminator will fail.
  ! 1st end directive is assumed to be for inner parallel construct.
  ! 2nd end directive applies to outer parallel construct.

end program

!OUTPUT, in order:
! Loosely  structured block  -- end required.
!                            --
! Strictly structured block  -- end not required.
! Sequential part
! Outer, loosely  structured block.
! Inner, strictly structured block.
! Inner, strictly structured block.