“Fortran is more alive than all living things” or “What's new with grandfather ifort”


    As you already know, the new Intel Parallel Studio XE 2016 has recently been released, and with it, as expected, new versions of all the tools, including the Fortran compiler. He is still a “smoking room”, is actively developing, while it is in high demand and is used by many developers, especially in HPC and the academic environment. The new version, as always, makes the lives of these developers a little easier, supporting new standards and giving more opportunities. Let's see what appeared in version 16.0.

    Submodules from F2008 (submodules)

    Support for submodules (submodules) from the Fortran 2008 standard has been waiting for a long time, and they are the biggest feature of the language, not supported until the last release. Now it is implemented, and only in the second compiler in the world. Who is the first? There is a compiler that fully supports Fortran 2008 - this is Cray.

    So why did the submodules wait? Now I will show you with a good example. So, we have the following code:
    module bigmod
    …
    contains
      subroutine sub1
      …<implementation of sub1>
      function func2
      …<implementation of func2>
      subroutine sub47
      …<implementation of sub47>
    …
    end module bigmod
    

    As we can see, we have a large module in which there are many different functions. This module is actively used in other files using the USE statement :
    ! Source source1.f90
    use bigmod
    …
    сall sub1
    ! Source source2.f90
    use bigmod
    …
    x = func2(…)
    ! Source source47.f90
    use bigmod
    …
    call sub47
    

    If we wanted (this sometimes happens) to change the code of some function from the bigmod module , for example sub47 , then we will have to reassemble the module itself, and even all the files in which it is used. Moreover, this will happen even if the interface of the function has not changed and, moreover, even if the function itself, into which we made the changes, is not called at all in the code, but there is only USE . As a result, for large applications, we get a whole series of not always necessary recompilations. It would be great to avoid this and reassemble only what is needed. The solution to this problem is submodules.

    The main idea is to remove the implementation of functions from the module. This is done using interfaces:
    modulebigmod
    …
      interface
      modulesubroutinesub1modulefunctionfunc2modulesubroutinesub47end interface
    endmodulebigmod

    After that, in a separate file, the bigmod_submodule submodule and the implementation of the functions are created:
    submodule (bigmod) bigmod_submod
    contains
      modulesubroutinesub1
      … <implementation of sub1>
      modulefunctionfunc2
      … <implementation of func2>
      modulesubroutinesub3
      … <implementation of sub3>
    end submodule bigmod_submod
    

    In this case, when implementing functions, you must use the module keyword , and everything that we declare inside the submodule will be visible only there. Now, changes in the submodule will not lead to recompilation of everything and everything until we change the interface of the function. We must compile the parent module first, and only then move on to the submodules.

    Interoperability of C and Fortran

    Since the Fortran standardization committee continues to take care of friendship with the C language, the latest version introduces opportunities from the technical specification TS29113 ( Further Interoperability of Fortran with C), which will be part of the F2015 standard. In general, the term Technical Specification appears when there is some kind of language feature that has not yet been completely completed in order to be adopted in the standard, but is in great demand so that various compiler manufacturers begin to implement it. By the way, before they were called TR (Technhical Report). Usually, when such a specification is approved by the committee, it is adopted in the next standard without changes, so that those compilers that have already implemented support do not have awkward situations.

    The appearance of this specification itself is mainly motivated by the needs of MPI3 . In particular, it allows expanding the interaction between C and Fortran in two main directions:

    • permits passing pointers to functions in C that take over the configuration (assumed-shape) and allocated variables. At the moment, the method of transmitting information about the boundaries of arrays is not standardized and depends on the compiler implementation. With this specification, it is standardized. In addition, C developers can read, write, and allocate memory for these arguments, as well as define them and pass them to Fortran code.
    • It supports interoperability with C type void *, which does not have an explicit type and dimension.

    These tasks are being implemented using new keywords. So, the assumed type (assumed type) TYPE (*) , and the dimension of the array (assumed rank) DIMENSION (..) appear . In addition, there is now a C descriptor. In general, if you are faced with the problem of seamless coexistence between C and Fortran, then you will definitely understand the functions of the ISO_C_BINDING module from the Fortran2003 standard (I already wrote about them here ), you will understand that it has open problems that are just solved by this specification.

    Is it clean or not?

    In the same F2008 standard, there is a new ability to declare functions as impure elemental .

    In order to understand the nature of this feature, we first need to understand what element ( elemental ) and clean ( pure ) function appeared in F2003 standard.

    Pointing before the pure function, we tell the compiler that the function cannot change anything outside of itself, and always returns the same result with the same input parameters.

    pure functioncalculate(x)

    This allows you to use pure functions in parallel forall constructs .

    For all its arguments, you must explicitly specify the intent (in) attribute , which says that these are only input parameters and we don’t change them, but in the function itself it is forbidden to do I / O operations, execute the STOP operator , use static variables (with the save attribute ) . Examples of pure functions: sin (x) , length (s) and others.

    Impure function will be any function that does not work with local variables, or gives a different result, regardless of the arguments. Say using random ()inside a pure function is prohibited, but in impure just right.

    Now let's move on to elemental functions.

    elemental subroutine swap(a, b)
    

    They are declared with scalar arguments, but can be called with arrays as actual arguments. In this case, the compiler creates a loop to call the function in it, filling the array. By default, any element function is pure. Thus, the impure element ( impure elemental ) functions - is still elemental, but with some relaxation, functions. In particular, they are allowed to do I / O operations, use random () , static variables.

    It is worth noting that the use of impure can affect vectorization, since the optimizer no longer knows whether this function can change something “outside” or not.

    OpenMP 4.1
    In a postabout the "plus" compiler, I wrote about the expansion of support for OpenMP 4.1. Of course, Fortran also now supports the new TARGET ENTER DATA and TARGET EXIT DATA directives, as well as TARGET NOWAIT and TARGET DEPEND, as in the C / C ++ compiler.

    Omp ordered simd
    directive Using the omp ordered directive , which was previously used only in tasks parallel to tasks, it is possible to force threads that run in parallel, reaching the ordered block , to execute sequentially and in exactly the same order as in the serial version:
    !$omp ordered [simd]
        structured code block
    !$omp end ordered
    

    This creates a kind of dependency between threads. A simple example showing how this works. In this case, the index will be printed sequentially, in ascending order:
    !$omp do ordered schedule(dynamic)
            do i=lb,ub,st
              callwork(i)
            enddo
            ...
            subroutine work(k)
      !$omp ordered
            write(*,*) k
      !$omp end ordered
    

    By the way, this worked only with dynamic layout before. This design works the same now, but the ability to specify the simd option (by default there is the threads option), which allows you to work with SIMD cycles , has also been added .

    We lock loops The
    new directive , which works with the O3 optimization level turned on, allows you to control optimizations with split loops for better work with cache memory:
    !DIR$ BLOCK_LOOP [clause[[,] clause]...]
    !DIR$ NOBLOCK_LOOP
    


    Catching uninitialized variables
    In the 15th version of the compiler, the -init option appeared , which allows to determine access to uninitialized variables in runtime, but it was implemented only for working with static variables. Now they can be used with automatic, as well as allocated ( allocatable ) arrays and pointers.
    A simple example:
    4real, allocatable, dimension(:) :: A
    56  ALLOCATE(A(N))
    78do i = 1, N
    9     Total = Total + A(I)
    10  enddo
    

    We collect this case with the -init = arrays, snan switch , in which all variables will be initialized with a signal NaN, and we get a runtime error:
    $ ifort -init=arrays,snan -g -traceback sample.F90 -o sample.exe
    $ sample.exe
    forrtl: error (182): floating invalid - possible uninitialized real/complex variable.
    Image              PC                Routine            Line        Source      
    ...
    sample.exe         0000000000402E12  MAIN__                      9  sample.F90
    ...
    Aborted (core dumped)
    

    I hope that our scientists will pay close attention to this option in order to avoid fancy results based on uninitialized variables and the resulting incidents.

    "On delivery"
    In addition, there are a number of minor improvements that will also help developers live easier. So, for example, a new option -fpp-name has appeared , which allows you to specify any preprocessor. Or a new attribute asynchronous , for asynchronous communication. There are many more improvements that, as usual, try to make the compiler better.

    By the way, a special version of VS 2010 Shell has long been delivered with the Intel compiler for Fortran. It has some limitations (for example, there is no C / C ++ support at all), but it is very, very useful for developers on Windows - you don’t have to give your money for IDEs (they don’t take any additional cash injections for VS Shell). So, now the version of VS has been updated to 2013, and it still comes only with the Fortran compiler package.

    Also popular now: