As you already know, a new Intel Parallel Studio XE 2016 has recently been released, and with it, as it should be, new versions of all tools, including the Fortran compiler. It is still a “living room”, is actively developing, with this being highly demanded and used by many developers, especially in HPC and academic environments. The new version, as always, makes the life of these developers a little easier, maintaining new standards and giving more features. Let's see what appeared in version 16.0.
Submodules from F2008 (submodules)Support for 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 were the submodules waiting? Now I will show a clear 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 see, we have a large module, in which there are many different functions. This module is actively used in other files using the
USE operator:
! 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 a function from a
bigmod module, for example
sub47 , then we will have to rebuild the module itself, and even all the files in which it is used. And this will happen even if the interface of the function has not changed and, moreover, even if the function itself, to which we made 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. How great it was to avoid it and reassemble only what you need. The sub-modules are the solution to this problem.
')
The basic idea is to remove the implementation of functions from the module. This is done using interfaces (interface):
module bigmod … interface module subroutine sub1 … module function func2 … module subroutine sub47 … end interface end module bigmod
After that, in a separate file, a
bigmod_submodule submodule and implementation of functions are created:
submodule (bigmod) bigmod_submod contains module subroutine sub1 … <implementation of sub1> module function func2 … <implementation of func2> module subroutine sub3 … <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 only be visible there. Now changes in the submodule will not lead to recompilation of anything and everything, until we change the interface of the function. We must compile the parent module first and then move on to the submodules.
Interoperability C and FortranAs the Fortran Standardization Committee continues to take care of its friendship with the C language, the latest version
contains possibilities 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 (Technical Specification) appears toga when there is some sort of language feature that is not yet fully completed in order to be accepted in the standard, but it is quite needed for various compiler manufacturers to begin to implement it. By the way, they used to be called TR (Technhical Report). Usually, when such a specification is approved by the committee, it is adopted in the following standard without changes, so that those compilers that have already implemented support do not have awkward situations.
The appearance of this specification is mainly motivated by the needs of
MPI3 . In particular, it allows you to expand the interaction between C and Fortran in two main areas:
- allows to transfer to C functions pointers (pointer), adopting the configuration (assumed-shape) and allocated (allocatable) 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 transfer them to Fortran code.
- supports interoperability with C type void *, not having an explicit type and dimension.
Implement these tasks with new keywords. So, the adopting 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 face the challenge of trouble-free coexistence of C and Fortran, then you will definitely understand the
ISO_C_BINDING functions of the module from the Fortran2003 standard (I already wrote about them
here ), you will understand that there are open problems in it that are solved by this specification.
Clean or not?In the same standard F2008 there is a new opportunity to declare functions as
impure elemental .
In order to understand the essence of this feature, you need to start to figure out what
elemental and pure functions, which appeared in the F2003 standard, are.
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 function calculate (x)
This allows the use of pure functions in parallel
forall designs.
For all its arguments, you need to explicitly specify the
intent (in) attribute, which says that these are only input parameters and we do not change them, and it is forbidden to perform input / output operations, perform the
STOP operator, use static variables (with the
save attribute) in the function itself . Examples of pure functions:
sin (x) ,
length (s) and others.
An impure function will be any function that does not work with local variables, or gives a different result, regardless of the arguments. Let's say the use of
random () inside a pure function is prohibited, but in impure just right.
We now turn to element 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 a function in it, filling the array. By default, any elemental function is pure. Thus, impure elemental functions are still elemental, but with some indulgence, 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.1In a
post about the "plus" compiler, I wrote about the extension of support for OpenMP 4.1. Of course, in Fortran, new TARGET ENTER DATA and TARGET EXIT DATA directives are also supported, as well as TARGET NOWAIT and TARGET DEPEND, as in the C / C ++ compiler.
Omp ordered simd directiveWith the help of the
omp ordered directive, which was previously used only in task cycles, you can force the threads that were executed in parallel, reaching the
ordered block, be executed sequentially and in the same order as in the production 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 call work(i) end do ... subroutine work(k) !$omp ordered write(*,*) k !$omp end ordered
By the way, it worked before only with a dynamic layout. This construction works the same way now, but the ability to specify the
simd option has been
added (the threads option is on by default), which allows working with SIMD cycles as well.
Locking loopsThe new directive , which works when the O3 optimization level is enabled, allows you to control loop-optimized optimization for better work with the cache memory:
!DIR$ BLOCK_LOOP [clause[[,] clause]...] !DIR$ NOBLOCK_LOOP
Catch uninitialized variablesIn the 15th version of the compiler, the
-init option
appeared , which allows defining 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:
4 real, allocatable, dimension(:) :: A 5 6 ALLOCATE(A(N)) 7 8 do i = 1, N 9 Total = Total + A(I) 10 enddo
Putting this case with the
-init = arrays, snan key , in which all variables will be initialized with signal NaN, and we get a run-time 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 our research team will turn their attention to this option in order to avoid bizarre results based on uninitialized variables and incidents resulting from this.
"To surrender"In addition, there are a number of minor improvements that will also help developers to live easier. So, for example, a new option
-fpp-name appeared , which allows you to specify any preprocessor. Or a new attribute
asynchronous , for asnechronous communication. There are many more improvements that, as usual, try to make the compiler better.
By the way, with the compiler from Intel for Fortran a special version of VS 2010 Shell has long been delivered. It has some limitations (for example, there is no support for C / C ++ at all), but it is very, very useful for developers on Windows - you don’t have to spread your money for IDE (they don’t take any extra cash for VS Shell). So, now the VS version has been updated to 2013, and it is still supplied only with the Fortran compiler package.