This question regards the ability of the multi-file optimizer to eliminate dead code.
I have a multi-file project that is conditionally compiled for several different products. I want to minimize the use of non-standard Fortran (conditional compilation) in favor of standard Fortran wherever possible. The project runs in real time, so efficiency is very important. Take the following example, where there are two files, and a pre-processor constant isAM is set to 0.
MODULE specify_product IMPLICIT NONE !DIR$ IF (isAM==1) LOGICAL, PARAMETER, PUBLIC :: AM = .TRUE. !DIR$ ELSE LOGICAL, PARAMETER, PUBLIC :: AM = .FALSE. !DIR$ END IF END MODULE
MODULE calculate USE specify_product IMPLICIT NONE CONTAINS SUBROUTINE do_calculation IF (AM) THEN [do something] ELSE [do something else] END IF END SUBROUTINE END MODULE
The subroutine is then called elsewhere in the code.
I could also achieve the same functionality by conditionally compiling the IF-THEN-ELSE like so:
!DIR$ IF (isAM==1) [do something]. !DIR$ ELSE [do something else]. !DIR$ END IF
My question is whether the multi-file optimizer will recognize that AM is a constant, it is always .FALSE., and therefore the IF-THEN-ELSE loop can be reduced to
[do something else]
In other words, is using standard Fortran as efficient as using the pre-processor?
I tried compiling my code with diagnostics at Level 5 and Optimization = Maximize Speed, but this did not report that the "dead" part of the IF-THEN-ELSE loop had been eliminated. But I don't know if it is supposed to report this.
Yes, the compiler will see that AM is a constant and will use that in determining whether code should be generated. I am not aware that the Intel compiler's optimization report includes dead code messages. It's pretty easy to look at the assembly output and determine if the IF branch was evaporated, but I'm reasonably confident that in a case such as you describe, it will be.
Bare in mind, while the IF...THEN...ENDIF will eliminate the test and the dead code branch of your example, it will not (necessarily) eliminate a subroutine that is only called from within the dead code branch of the sample code. To resolve this you will need to use
!DIR$ ATTRIBUTES FORCEINLINE :: YourProcedureNameHere
You will need to test to see if the IF...THEN...ENDIF and the inlined subroutine need to be in the same compilation unit (not necessarily as a CONTAINED procedure).
Another alternative is to compile the conditional use subroutine external to the main program as a static library, individual, object file. Then the linker would handle the inclusion or exclusion of the subroutine.
Thanks for the clarification. Will the linker also ignore subroutines that are in modules other than MODULE calculate and that are only called by the unreachable code?
The linker excludes only by object files. If an object has subroutines A and B, both will get loaded if only A is called. If every subroutine is in its own source file, they'll be in separate objects and un-called routines won't get loaded.
So I presume that this means that if a module is in a separate file and contains only subroutines that cannot be reached, nothing from that module will be loaded? (In other words, I am trying to verify that the "non-loading" occurs when code is written in a modern style with modules providing explicit interfaces, provided that all executable routines in the module cannot be reached.)
If NO symbols from that module are used, then nothing from that module will be loaded. Sometimes non-routine definitions in a module results in an object contribution (especially variables).
>> I am trying to verify that the "non-loading" occurs
Generate a map file and look for the (absences of) entry points, named commons, or anything identifiable with the file you want excluded.
You could also use the debugger, open a Memory or disassembly window, and type in the procedure name.