Reputation: 65
I have an existing Fortran codebase I'm working with and it's quite large. I am no Fortran programmer so I know that I'm not doing everything correctly here.
I'm trying to create and initialize an array of 1.6 million integers. I cannot get this to initialize in Fortran (using ifort or gfort) as I either would have too many line continuations or too long of lines.
So naturally, I switched to C and wrote a function to just initialize an array and it compiles in seconds with no problem. Now I'm trying to link the two together properly. I created a small test case here to simplify things. Here are the three files I'm working with:
init.c
void c_init_()
{
static const int f_init_g[1600000] =
{
3263, 322, 3261, 60, 32249, 32244, 3229, 23408, 252407, 25326,
25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806,
---------------------------------------------------------------------
25805, 25723, 25562, 25787, 4549, 32248, 32244, 32243, 253207, 21806
};
}
init_mod.f90
MODULE INIT_MOD
USE, INTRINSIC :: ISO_C_BINDING
IMPLICIT NONE
SAVE
TYPE :: INIT_TYPE
INTEGER (C_INT), DIMENSION(1600000) :: INIT
END TYPE INIT_TYPE
TYPE (C_PTR), BIND(C,NAME="f_init_g") :: INIT_CP
TYPE (INIT_TYPE), POINTER :: INIT_FP
END MODULE INIT_MOD
main.f90
PROGRAM INIT
USE INIT_MOD
USE, INTRINSIC :: ISO_C_BINDING
TYPE (INIT_TYPE) :: INIT_T
CALL c_init()
CALL C_F_POINTER(INIT_CP,INIT_FP)
INIT_T = INIT_FP
END PROGRAM INIT
I compile this using the following commands:
icc -c init.c
ifort -c init_mod.f90
ifort main.f90 init_mod.o init.o
I get a segmentation fault when running because INIT_CP
points to nothing as far as I can tell. I know I'm not successfully getting INIT_CP
to point at the array in my C function. So I'm trying to figure out how to do that.
I would like if someone has a suggestion on how to initialize this array natively in Fortran. My final option that I'll do is make a small initialization of this array in assembly and write a script to generate the assembly code to initialize this array myself (based off the assembly from the small initialization I can mimic the same thing for any size array). I'm not as excited to do that, but it may be the easiest and most reliable solution.
Most importantly I want other Fortran subroutines that use this array to see that it is static in shape and value so that appropriate inter procedural optimizations can be done.
Upvotes: 1
Views: 709
Reputation: 21451
Fortran-C Interoperable variables must have external linkage. As suggested by others in the comments, move the C declaration to file scope and lose the static
specifier.
There is no need for an intermediate C_PTR
- a Fortran array variable is directly interoperable with the appropriate C array.
Reducing the size of the array slightly:
/* C File scope */
const int f_init_g[3] = { 101, 102, 103 };
! Fortran
MODULE m
USE, INTRINSIC :: ISO_C_BINDING, ONLY: C_INT
IMPLICIT NONE
INTEGER(C_INT), BIND(C, NAME='f_init_g') :: f_init_g(3)
END MODULE m
PROGRAM p
USE m
IMPLICIT NONE
PRINT *, f_init_g(2)
END PROGRAM p
Note that the starting premise - that it is impossible to define or initialize such an array from within Fortran only - is false. The rules around constant expressions in Fortran permit reference to existing named constants, including named constants that are arrays. If you decide to persist with this madness, and assuming that the value of the initializer cannot be described by some sort of expression, consider:
INTEGER, PARAMETER :: first(10) &
= [ 3263, 322, 3261, 60, 32249, &
32244, 3229, 23408, 252407, 25326 ]
INTEGER, PARAMETER :: second(10) &
= [ 25805, 25723, 25562, 25787, 4549, &
32248, 32244, 32243, 253207, 21806]
...
INTEGER, PARAMETER :: f_init_g(1600000) = [ first, second, ... ]
You will probably need intermediate named constant arrays before the final array constructor.
In the immediate above, f_init_g
is a named constant, which is very visible to the compiler, and more likely to result in the optimisations that you seek.
However, you may run into compiler complexity limits, that defeat this latter approach.
When f_init_g
is a variable initialized by C, you are basically reliant on the inter-language and inter-procedural optimisation capabilities of your tool set - and if those capabilities even exist, I wouldn't expect much from them for this case. I expect that you aren't going to lose much performance wise, beyond the one-off time for IO, if you read the value of the array in from a file at runtime.
Upvotes: 5