Skip to content

Commit 68b8175

Browse files
committed
Generate .fypp files for stdlib
1 parent b018f12 commit 68b8175

File tree

1 file changed

+82
-65
lines changed

1 file changed

+82
-65
lines changed

scripts/modularize_blas.py

Lines changed: 82 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import copy
77

88
# Create linear algebra constants module
9-
def create_constants_module(module_name,out_folder):
9+
def create_constants_module(module_name,out_folder,stdlib_integration=None):
1010

1111
from platform import os
1212

@@ -23,20 +23,30 @@ def create_constants_module(module_name,out_folder):
2323

2424
# Header
2525
fid.write("module {}\n".format(module_name))
26-
#fid.write(INDENT + "use stdlib_kinds, only: sp,dp,lk,int32,int64\n")
27-
fid.write(INDENT + "use iso_fortran_env, only: int32,int64\n")
26+
27+
if stdlib_integration:
28+
fid.write(INDENT + "use stdlib_kinds, only: sp, dp, qp, int32, int64, lk\n")
29+
else:
30+
fid.write(INDENT + "use iso_fortran_env, only: real32,real64,real128,int32,int64\n")
31+
2832
fid.write(INDENT + "use, intrinsic :: ieee_arithmetic, only: ieee_is_nan \n")
2933
fid.write("#if defined(_OPENMP)\n")
3034
fid.write(INDENT + "use omp_lib\n")
3135
fid.write("#endif\n")
3236
fid.write(INDENT + "implicit none(type,external)\n")
3337
fid.write(INDENT + "public\n\n\n\n")
3438

39+
#:if WITH_QP
40+
#:set REAL_KINDS = REAL_KINDS + ["qp"]
41+
#:endif
42+
3543
# Temporary: to be replaced with stdlib_kinds
36-
fid.write(INDENT + "integer, parameter :: sp = selected_real_kind(6)\n")
37-
fid.write(INDENT + "integer, parameter :: dp = selected_real_kind(15)\n")
38-
fid.write(INDENT + "integer, parameter :: qp = selected_real_kind(33)\n")
39-
fid.write(INDENT + "integer, parameter :: lk = kind(.true.)\n")
44+
if not stdlib_integration:
45+
fid.write(INDENT + "integer, parameter :: sp = real32\n")
46+
fid.write(INDENT + "integer, parameter :: dp = real64\n")
47+
fid.write(INDENT + "integer, parameter :: qp = real128\n")
48+
fid.write(INDENT + "integer, parameter :: lk = kind(.true.)\n")
49+
4050
fid.write(INDENT + "! Integer size support for ILP64 builds should be done here\n")
4151
fid.write(INDENT + "integer, parameter :: ilp = int32\n")
4252
fid.write(INDENT + "private :: int32, int64\n\n\n")
@@ -99,7 +109,7 @@ def patch_lapack_aux(fid,prefix,indent):
99109
# Read all source files from the source folder, process them, refactor them, and put all
100110
# subroutines/function into a module
101111
def create_fortran_module(module_name,source_folder,out_folder,prefix,ext_functions,used_modules, \
102-
split_by_initial):
112+
split_by_initial,stdlib_export=False):
103113

104114
from datetime import date
105115
from platform import os
@@ -148,27 +158,43 @@ def create_fortran_module(module_name,source_folder,out_folder,prefix,ext_functi
148158
for m in range(len(modules)):
149159
this_module = module_name
150160
if len(initials[m])>0: this_module = this_module + "_" + initials[m]
151-
module_file = this_module + ".f90"
161+
if stdlib_export:
162+
module_file = this_module + ".fypp"
163+
else:
164+
module_file = this_module + ".f90"
152165
module_path = os.path.join(out_folder,module_file)
153166
fid = open(module_path,"w")
154167

168+
# Quad-precision directives
169+
if stdlib_export:
170+
fid.write('#:include "common.fypp" \n')
171+
if (initials[m]=='q' or initials[m]=='w'): fid.write("#!if WITH_QP \n")
172+
155173
# Header
156174
fid.write("module {}\n".format(this_module))
157175
for used in used_modules:
158176
fid.write(INDENT + "use " + used + "\n")
159177

160178
# Add top modules in the hierarchy
161179
for n in range(m):
180+
if stdlib_export and (initials[n]=='q' or initials[n]=='w'):
181+
fid.write("#!if WITH_QP \n")
162182
fid.write(INDENT + "use " + module_name + "_" + initials[n] + "\n")
183+
if stdlib_export and (initials[n]=='q' or initials[n]=='w'):
184+
fid.write("#!endif \n")
163185

164186
fid.write(INDENT + "implicit none(type,external)\n")
165-
fid.write(INDENT + "private\n\n\n\n")
187+
fid.write(INDENT + "private\n")
166188

167189
# Public interface.
168-
fid.write("\n\n\n" + INDENT + "public :: sp,dp,qp,lk,ilp\n")
190+
fid.write("\n\n"+INDENT + "public :: sp,dp,qp,lk,ilp\n")
169191
for function in fortran_functions:
170192
if function_in_module(initials[m],function.old_name):
193+
if stdlib_export and function.is_quad_precision():
194+
fid.write("#!if WITH_QP \n")
171195
fid.write(INDENT + "public :: " + function.new_name + "\n")
196+
if stdlib_export and function.is_quad_precision():
197+
fid.write("#!endif \n")
172198

173199
if function.new_name=="NONAME":
174200
print("\n".join(function.body))
@@ -194,20 +220,26 @@ def create_fortran_module(module_name,source_folder,out_folder,prefix,ext_functi
194220
for k in range(len(old_names)):
195221
print(module_name+"_"+initials[m]+": function "+old_names[k])
196222

197-
print_function_tree(fortran_functions,old_names,ext_functions,fid,INDENT,MAX_LINE_LENGTH,initials[m])
223+
print_function_tree(fortran_functions,old_names,ext_functions,fid,INDENT,MAX_LINE_LENGTH, \
224+
initials[m],stdlib_export)
198225

199226
# Close module
200227
fid.write("\n\n\nend module {}\n".format(this_module))
228+
229+
if stdlib_export and (initials[m]=='q' or initials[m]=='w'):
230+
fid.write("#!endif\n")
231+
201232
fid.close()
202233

203234
# Write wrapper module
204-
if split_by_initial: write_interface_module(INDENT,out_folder,module_name,used_modules,fortran_functions,prefix)
235+
if split_by_initial: write_interface_module(INDENT,out_folder,module_name,used_modules,fortran_functions,\
236+
prefix,stdlib_export)
205237

206238
# Return list of all functions defined in this module, including the external ones
207239
return fortran_functions
208240

209241
# Write interface module wrapping the whole library
210-
def write_interface_module(INDENT,out_folder,module_name,used_modules,fortran_functions,prefix):
242+
def write_interface_module(INDENT,out_folder,module_name,used_modules,fortran_functions,prefix,stdlib_export):
211243

212244
quad_precision = True
213245

@@ -225,18 +257,27 @@ def write_interface_module(INDENT,out_folder,module_name,used_modules,fortran_fu
225257

226258
interfaces.sort()
227259

228-
module_file = module_name + ".f90"
260+
if stdlib_export:
261+
module_file = module_name + ".fypp"
262+
else:
263+
module_file = module_name + ".f90"
229264
module_path = os.path.join(out_folder,module_file)
230265

231266
fid = open(module_path,"w")
267+
if stdlib_export:
268+
fid.write('#:include "common.fypp" \n')
232269

233270
# Header
234271
fid.write("module {}\n".format(module_name))
235272
for used in used_modules:
236273
fid.write(INDENT + "use " + used + "\n")
237274

238275
for i in initials:
276+
if stdlib_export and i=='q':
277+
fid.write("#!if WITH_QP \n")
239278
fid.write(INDENT + "use {mname}_{minit}\n".format(mname=module_name,minit=i))
279+
if stdlib_export and i=='q':
280+
fid.write("#!endif \n")
240281
fid.write(INDENT + "implicit none(type,external)\n")
241282
fid.write(INDENT + "public\n")
242283

@@ -253,19 +294,19 @@ def write_interface_module(INDENT,out_folder,module_name,used_modules,fortran_fu
253294
if len(interf_functions)>0 and len(interf_subroutines)>0:
254295
# There are mixed subroutines and functions with the same name, so, we need to
255296
# write two separate interfaces. Add _s and _f suffixes to differentiate between them
256-
write_interface(fid,interfaces[j]+"_f",interf_functions,INDENT,prefix,module_name)
257-
write_interface(fid,interfaces[j]+"_s",interf_subroutines,INDENT,prefix,module_name)
297+
write_interface(fid,interfaces[j]+"_f",interf_functions,INDENT,prefix,module_name,stdlib_export)
298+
write_interface(fid,interfaces[j]+"_s",interf_subroutines,INDENT,prefix,module_name,stdlib_export)
258299
elif len(interf_functions)>0:
259-
write_interface(fid,interfaces[j],interf_functions,INDENT,prefix,module_name)
300+
write_interface(fid,interfaces[j],interf_functions,INDENT,prefix,module_name,stdlib_export)
260301
elif len(interf_subroutines)>0:
261-
write_interface(fid,interfaces[j],interf_subroutines,INDENT,prefix,module_name)
302+
write_interface(fid,interfaces[j],interf_subroutines,INDENT,prefix,module_name,stdlib_export)
262303

263304
# Close module
264305
fid.write("\n\n\nend module {}\n".format(module_name))
265306
fid.close()
266307

267308
# write interface
268-
def write_interface(fid,name,functions,INDENT,prefix,module_name):
309+
def write_interface(fid,name,functions,INDENT,prefix,module_name,stdlib_export):
269310

270311
MAX_LINE_LENGTH = 100 # No line limits for the comments
271312

@@ -310,12 +351,17 @@ def write_interface(fid,name,functions,INDENT,prefix,module_name):
310351

311352
fid.write("#else\n")
312353

354+
elif stdlib_export:
355+
# Quad precision export
356+
fid.write("#!if WITH_QP\n")
313357

314358
# Local implementation
315359
fid.write(INDENT*3+"module procedure {}\n".format(f.new_name))
316360

317361
if has_external:
318362
fid.write("#endif\n")
363+
elif stdlib_export:
364+
fid.write("#!endif\n")
319365

320366
# Close interface
321367
fid.write(INDENT*2+"end interface {}\n\n\n".format(name))
@@ -453,41 +499,6 @@ def double_to_quad(lines,initial,newinit,prefix,procedure_name=None):
453499

454500
return whole
455501

456-
457-
# Double precision of the current module, 64-bit -> 128-bit
458-
def quad_precision_module(module_name,out_folder,initial,prefix):
459-
460-
import re
461-
462-
if initial=='d':
463-
newinit = 'q'
464-
elif initial=='z':
465-
newinit = 'w'
466-
else:
467-
print(initial + "is not a 64-bit type initial")
468-
exit(1)
469-
470-
dble_module = module_name + "_" + initial
471-
quad_module = module_name + "_" + newinit
472-
473-
dble_file = dble_module + ".f90"
474-
module_path = os.path.join(out_folder,dble_file)
475-
out_path = os.path.join(out_folder,quad_module + ".f90")
476-
477-
# Load whole module into a file
478-
dble_file = []
479-
with open(module_path, 'r') as file:
480-
for line in file:
481-
dble_file.append(line.rstrip())
482-
483-
whole = double_to_quad(dble_file,initial,newinit,prefix)
484-
485-
# Write to disk
486-
fid = open(out_path,"w")
487-
fid.write('\n'.join(whole))
488-
fid.close()
489-
490-
491502
def function_module_initial(function_name):
492503
initials = ['aux','c','s','d','z']
493504

@@ -763,7 +774,7 @@ def has_nonpure_deps(function,functions=None):
763774
return has_nonpure_deps
764775

765776
# Print function tree in a dependency-suitable way
766-
def print_function_tree(functions,fun_names,ext_funs,fid,INDENT,MAX_LINE_LENGTH,initial):
777+
def print_function_tree(functions,fun_names,ext_funs,fid,INDENT,MAX_LINE_LENGTH,initial,stdlib_export):
767778

768779
ext_fun_names = fun_names[len(functions):]
769780

@@ -816,13 +827,19 @@ def print_function_tree(functions,fun_names,ext_funs,fid,INDENT,MAX_LINE_LENGTH,
816827
elif functions[dep].printed:
817828
nprinted+=1
818829

819-
#print("function "+functions[i].old_name+" printed="+str(nprinted)+", len="+str(len(functions[i].deps)))
820-
830+
# Write actual function
821831
if nprinted==len(functions[i].deps) or attempt>=MAXIT:
832+
833+
if functions[i].is_quad_precision() and stdlib_export:
834+
fid.write("\n#!if WITH_QP \n")
835+
822836
write_function_body(fid,functions[i].header," " * header_indentation(functions[i].body),MAX_LINE_LENGTH,False)
823837
write_function_body(fid,functions[i].body,INDENT,MAX_LINE_LENGTH,True)
824838
functions[i].printed = True
825839

840+
if functions[i].is_quad_precision() and stdlib_export:
841+
fid.write("#!endif \n")
842+
826843

827844
# Final check
828845
not_printed = 0
@@ -3241,13 +3258,13 @@ def parse_interfaces(Sources):
32413258
"../assets/reference_lapack/BLAS/SRC","../src",\
32423259
"stdlib_",\
32433260
funs,\
3244-
["stdlib_linalg_constants"],True)
3245-
funs = create_fortran_module("stdlib_linalg_lapack",\
3246-
"../assets/lapack_sources",\
3247-
"../src",\
3248-
"stdlib_",\
3249-
funs,\
3250-
["stdlib_linalg_constants","stdlib_linalg_blas"],True)
3261+
["stdlib_linalg_constants"],True,True)
3262+
#funs = create_fortran_module("stdlib_linalg_lapack",\
3263+
# "../assets/lapack_sources",\
3264+
# "../src",\
3265+
# "stdlib_",\
3266+
# funs,\
3267+
# ["stdlib_linalg_constants","stdlib_linalg_blas"],True)
32513268
#create_fortran_module("stdlib_linalg_blas_test_eig","../assets/reference_lapack/TESTING/EIG","../test","stdlib_test_")
32523269

32533270

0 commit comments

Comments
 (0)