forked from FFTW/fftw3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgenf03.pl
executable file
·213 lines (184 loc) · 7.38 KB
/
genf03.pl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
#!/usr/bin/perl -w
# Generate Fortran 2003 interfaces from a sequence of C function declarations
# of the form (one per line):
# extern <type> <name>(...args...)
# extern <type> <name>(...args...)
# ...
# with no line breaks within a given function. (It's too much work to
# write a general parser, since we just have to handle FFTW's header files.)
sub canonicalize_type {
my($type);
($type) = @_;
$type =~ s/ +/ /g;
$type =~ s/^ //;
$type =~ s/ $//;
$type =~ s/([^\* ])\*/$1 \*/g;
return $type;
}
# C->Fortran map of supported return types
%return_types = (
"int" => "integer(C_INT)",
"ptrdiff_t" => "integer(C_INTPTR_T)",
"size_t" => "integer(C_SIZE_T)",
"double" => "real(C_DOUBLE)",
"float" => "real(C_FLOAT)",
"long double" => "real(C_LONG_DOUBLE)",
"__float128" => "real(16)",
"fftw_plan" => "type(C_PTR)",
"fftwf_plan" => "type(C_PTR)",
"fftwl_plan" => "type(C_PTR)",
"fftwq_plan" => "type(C_PTR)",
"void *" => "type(C_PTR)",
"char *" => "type(C_PTR)",
"double *" => "type(C_PTR)",
"float *" => "type(C_PTR)",
"long double *" => "type(C_PTR)",
"__float128 *" => "type(C_PTR)",
"fftw_complex *" => "type(C_PTR)",
"fftwf_complex *" => "type(C_PTR)",
"fftwl_complex *" => "type(C_PTR)",
"fftwq_complex *" => "type(C_PTR)",
);
# C->Fortran map of supported argument types
%arg_types = (
"int" => "integer(C_INT), value",
"unsigned" => "integer(C_INT), value",
"size_t" => "integer(C_SIZE_T), value",
"ptrdiff_t" => "integer(C_INTPTR_T), value",
"fftw_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
"fftwf_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
"fftwl_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
"fftwq_r2r_kind" => "integer(C_FFTW_R2R_KIND), value",
"double" => "real(C_DOUBLE), value",
"float" => "real(C_FLOAT), value",
"long double" => "real(C_LONG_DOUBLE), value",
"__float128" => "real(16), value",
"fftw_complex" => "complex(C_DOUBLE_COMPLEX), value",
"fftwf_complex" => "complex(C_DOUBLE_COMPLEX), value",
"fftwl_complex" => "complex(C_LONG_DOUBLE), value",
"fftwq_complex" => "complex(16), value",
"fftw_plan" => "type(C_PTR), value",
"fftwf_plan" => "type(C_PTR), value",
"fftwl_plan" => "type(C_PTR), value",
"fftwq_plan" => "type(C_PTR), value",
"const fftw_plan" => "type(C_PTR), value",
"const fftwf_plan" => "type(C_PTR), value",
"const fftwl_plan" => "type(C_PTR), value",
"const fftwq_plan" => "type(C_PTR), value",
"const int *" => "integer(C_INT), dimension(*), intent(in)",
"ptrdiff_t *" => "integer(C_INTPTR_T), intent(out)",
"const ptrdiff_t *" => "integer(C_INTPTR_T), dimension(*), intent(in)",
"const fftw_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
"const fftwf_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
"const fftwl_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
"const fftwq_r2r_kind *" => "integer(C_FFTW_R2R_KIND), dimension(*), intent(in)",
"double *" => "real(C_DOUBLE), dimension(*), intent(out)",
"float *" => "real(C_FLOAT), dimension(*), intent(out)",
"long double *" => "real(C_LONG_DOUBLE), dimension(*), intent(out)",
"__float128 *" => "real(16), dimension(*), intent(out)",
"fftw_complex *" => "complex(C_DOUBLE_COMPLEX), dimension(*), intent(out)",
"fftwf_complex *" => "complex(C_FLOAT_COMPLEX), dimension(*), intent(out)",
"fftwl_complex *" => "complex(C_LONG_DOUBLE_COMPLEX), dimension(*), intent(out)",
"fftwq_complex *" => "complex(16), dimension(*), intent(out)",
"const fftw_iodim *" => "type(fftw_iodim), dimension(*), intent(in)",
"const fftwf_iodim *" => "type(fftwf_iodim), dimension(*), intent(in)",
"const fftwl_iodim *" => "type(fftwl_iodim), dimension(*), intent(in)",
"const fftwq_iodim *" => "type(fftwq_iodim), dimension(*), intent(in)",
"const fftw_iodim64 *" => "type(fftw_iodim64), dimension(*), intent(in)",
"const fftwf_iodim64 *" => "type(fftwf_iodim64), dimension(*), intent(in)",
"const fftwl_iodim64 *" => "type(fftwl_iodim64), dimension(*), intent(in)",
"const fftwq_iodim64 *" => "type(fftwq_iodim64), dimension(*), intent(in)",
"void *" => "type(C_PTR), value",
"FILE *" => "type(C_PTR), value",
"const char *" => "character(C_CHAR), dimension(*), intent(in)",
"fftw_write_char_func" => "type(C_FUNPTR), value",
"fftwf_write_char_func" => "type(C_FUNPTR), value",
"fftwl_write_char_func" => "type(C_FUNPTR), value",
"fftwq_write_char_func" => "type(C_FUNPTR), value",
"fftw_read_char_func" => "type(C_FUNPTR), value",
"fftwf_read_char_func" => "type(C_FUNPTR), value",
"fftwl_read_char_func" => "type(C_FUNPTR), value",
"fftwq_read_char_func" => "type(C_FUNPTR), value",
# Although the MPI standard defines this type as simply "integer",
# if we use integer without a 'C_' kind in a bind(C) interface then
# gfortran complains. Instead, since MPI also requires the C type
# MPI_Fint to match Fortran integers, we use the size of this type
# (extracted by configure and substituted by the Makefile).
"MPI_Comm" => "integer(C_MPI_FINT), value"
);
while (<>) {
next if /^ *$/;
if (/^ *extern +([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *\((.*)\) *$/) {
$ret = &canonicalize_type($1);
$name = $2;
$args = $3;
$args =~ s/^ *void *$//;
$bad = ($ret ne "void") && !exists($return_types{$ret});
foreach $arg (split(/ *, */, $args)) {
$arg =~ /^([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *$/;
$argtype = &canonicalize_type($1);
$bad = 1 if !exists($arg_types{$argtype});
}
if ($bad) {
print "! Unable to generate Fortran interface for $name\n";
next;
}
# any function taking an MPI_Comm arg needs a C wrapper (grr).
if ($args =~ /MPI_Comm/) {
$cname = $name . "_f03";
}
else {
$cname = $name;
}
# Fortran has a 132-character line-length limit by default (grr)
$len = 0;
print " "; $len = $len + length(" ");
if ($ret eq "void") {
$kind = "subroutine"
}
else {
print "$return_types{$ret} ";
$len = $len + length("$return_types{$ret} ");
$kind = "function"
}
print "$kind $name("; $len = $len + length("$kind $name(");
$len0 = $len;
$argnames = $args;
$argnames =~ s/([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) */$2/g;
$comma = "";
foreach $argname (split(/ *, */, $argnames)) {
if ($len + length("$comma$argname") + 3 > 132) {
printf ", &\n%*s", $len0, "";
$len = $len0;
$comma = "";
}
print "$comma$argname";
$len = $len + length("$comma$argname");
$comma = ",";
}
print ") "; $len = $len + 2;
if ($len + length("bind(C, name='$cname')") > 132) {
printf "&\n%*s", $len0 - length("$name("), "";
}
print "bind(C, name='$cname')\n";
print " import\n";
foreach $arg (split(/ *, */, $args)) {
$arg =~ /^([a-zA-Z_0-9 ]+[ \*]) *([a-zA-Z_0-9]+) *$/;
$argtype = &canonicalize_type($1);
$argname = $2;
$ftype = $arg_types{$argtype};
# Various special cases for argument types:
if ($name =~ /_flops$/ && $argtype eq "double *") {
$ftype = "real(C_DOUBLE), intent(out)"
}
if ($name =~ /_execute/ && ($argname eq "ri" ||
$argname eq "ii" ||
$argname eq "in")) {
$ftype =~ s/intent\(out\)/intent(inout)/;
}
print " $ftype :: $argname\n"
}
print " end $kind $name\n";
print " \n";
}
}