7fcfd93ca8
Add MPIX_Async_start, MPIX_Async_get_state, MPIX_Async_spawn.
1731 linhas
70 KiB
Python
1731 linhas
70 KiB
Python
##
|
|
## Copyright (C) by Argonne National Laboratory
|
|
## See COPYRIGHT in top-level directory
|
|
##
|
|
|
|
from local_python import MPI_API_Global as G
|
|
from local_python.binding_common import *
|
|
from local_python import RE
|
|
|
|
import re
|
|
|
|
def get_cdesc_name(func, is_large):
|
|
name = re.sub(r'^MPIX?_', 'MPIR_', func['name'] + "_cdesc")
|
|
if is_large:
|
|
name += "_large"
|
|
return name
|
|
|
|
def get_f08_c_name(func, is_large):
|
|
name = re.sub(r'MPIX?_', r'MPIR_', func['name'] + '_c')
|
|
if is_large:
|
|
name += "_large"
|
|
return name
|
|
|
|
def get_f08ts_name(func, is_large):
|
|
if is_large:
|
|
name = func['name'] + "_c_f08ts"
|
|
else:
|
|
name = func['name'] + "_f08ts"
|
|
return name
|
|
|
|
def get_f08_name(func, is_large):
|
|
if is_large:
|
|
name = func['name'] + "_c_f08"
|
|
else:
|
|
name = func['name'] + "_f08"
|
|
return name
|
|
|
|
def dump_f08_wrappers_c(func, is_large):
|
|
c_mapping = get_kind_map('C', is_large)
|
|
|
|
c_param_list = []
|
|
c_arg_list = []
|
|
vardecl_list = []
|
|
code_list = []
|
|
end_list = []
|
|
|
|
def dump_buf(buf, check_in_place):
|
|
c_param_list.append("CFI_cdesc_t *%s" % buf)
|
|
vardecl_list.append("void *%s_i = %s->base_addr;" % (buf, buf))
|
|
c_arg_list.append(buf + "_i")
|
|
code_list.append("if (%s_i == &MPIR_F08_MPI_BOTTOM) {" % buf)
|
|
code_list.append(" %s_i = MPI_BOTTOM;" % buf)
|
|
if check_in_place:
|
|
code_list.append("} else if (%s_i == &MPIR_F08_MPI_IN_PLACE) {" % buf)
|
|
code_list.append(" %s_i = MPI_IN_PLACE;" % buf)
|
|
code_list.append("}")
|
|
code_list.append("")
|
|
|
|
def dump_ct_dt(buf, ct, dt):
|
|
ct_type = "int"
|
|
if is_large:
|
|
ct_type = "MPI_Count"
|
|
c_param_list.append("%s %s" % (ct_type, ct))
|
|
c_param_list.append("MPI_Datatype %s" % dt)
|
|
vardecl_list.append("%s %s_i = %s;" % (ct_type, ct, ct))
|
|
vardecl_list.append("MPI_Datatype %s_i = %s;" % (dt, dt))
|
|
c_arg_list.append(ct + "_i")
|
|
c_arg_list.append(dt + "_i")
|
|
|
|
code_list.append("if (%s->rank != 0 && !CFI_is_contiguous(%s)) {" % (buf, buf))
|
|
code_list.append(" err = cdesc_create_datatype(%s, %s, %s, &%s_i);" % (buf, ct, dt, dt))
|
|
code_list.append(" if (err) return err;")
|
|
code_list.append(" %s_i = 1;" % ct)
|
|
code_list.append("}")
|
|
code_list.append("")
|
|
|
|
end_list.append("if (%s_i != %s) PMPI_Type_free(&%s_i);" % (dt, dt, dt))
|
|
|
|
def dump_p(p):
|
|
c_param_list.append(get_C_param(p, func, c_mapping))
|
|
c_arg_list.append(p['name'])
|
|
|
|
n = len(func['parameters'])
|
|
i = 0
|
|
while i < n:
|
|
p = func['parameters'][i]
|
|
(group_kind, group_count) = ("", 0)
|
|
if i + 3 <= n and RE.search(r'BUFFER', p['kind']):
|
|
group_kind, group_count = get_userbuffer_group(func['name'], func['parameters'], i)
|
|
|
|
if group_count > 0:
|
|
p2 = func['parameters'][i + 1]
|
|
p3 = func['parameters'][i + 2]
|
|
if group_count == 3:
|
|
dump_buf(p['name'], re.search('-inplace', group_kind))
|
|
dump_ct_dt(p['name'], p2['name'], p3['name'])
|
|
elif group_count == 4:
|
|
p4 = func['parameters'][i + 3]
|
|
# assume no sub-array buffer
|
|
dump_buf(p['name'], re.search('-inplace', group_kind))
|
|
dump_p(p2)
|
|
dump_p(p3)
|
|
dump_p(p4)
|
|
elif group_count == 5:
|
|
# reduce
|
|
p4 = func['parameters'][i + 3]
|
|
p5 = func['parameters'][i + 4]
|
|
dump_buf(p['name'], True)
|
|
dump_buf(p2['name'], False)
|
|
# arbitrary: only recvbuf may be sub-array
|
|
if RE.match(r'mpi_i?reduce_scatter', func['name'], re.IGNORECASE):
|
|
dump_p(p3)
|
|
dump_p(p4)
|
|
else:
|
|
dump_ct_dt(p2['name'], p3['name'], p4['name'])
|
|
dump_p(p5)
|
|
|
|
i += group_count
|
|
continue
|
|
elif p['kind'] == "BUFFER":
|
|
dump_buf(p['name'], False)
|
|
i += 1
|
|
else:
|
|
dump_p(p)
|
|
i += 1
|
|
|
|
cdesc_name = get_cdesc_name(func, is_large)
|
|
s = "int %s(%s)" % (cdesc_name, ', '.join(c_param_list))
|
|
G.decls.append(s)
|
|
tlist = split_line_with_break(s, "", 80)
|
|
G.out.extend(tlist)
|
|
G.out.append("{")
|
|
if re.match(r'MPI_File_', func['name']):
|
|
if is_large:
|
|
# File large functions are not there yet
|
|
G.out.append(" return MPI_ERR_INTERN;")
|
|
G.out.append("}")
|
|
return
|
|
G.out.append("#ifndef HAVE_ROMIO")
|
|
G.out.append(" return MPI_ERR_INTERN;")
|
|
G.out.append("#else")
|
|
G.out.append("INDENT");
|
|
G.out.append("int err = MPI_SUCCESS;")
|
|
if re.match(r'MPI_F_sync_reg', func['name'], re.IGNORECASE):
|
|
# dummy
|
|
pass
|
|
else:
|
|
for l in vardecl_list:
|
|
G.out.append(l)
|
|
G.out.append("")
|
|
for l in code_list:
|
|
G.out.append(l)
|
|
G.out.append("err = %s(%s);" % (get_function_name(func, is_large), ', '.join(c_arg_list)))
|
|
G.out.append("")
|
|
for l in end_list:
|
|
G.out.append(l)
|
|
G.out.append("return err;")
|
|
G.out.append("DEDENT")
|
|
if re.match(r'MPI_File_', func['name']):
|
|
G.out.append("#endif")
|
|
G.out.append("}")
|
|
|
|
def dump_f08_wrappers_f(func, is_large):
|
|
c_mapping = get_kind_map('C', is_large)
|
|
f08_mapping = get_kind_map('F08', is_large)
|
|
|
|
f_param_list = []
|
|
uses = {}
|
|
f_decl_list = []
|
|
c_decl_list = []
|
|
arg_list_1 = [] # used if (c_int == kind(0))
|
|
arg_list_2 = [] # used otherwise
|
|
code_list = []
|
|
convert_list_pre = [] # conversions always needed
|
|
convert_list_post = []
|
|
convert_list_1 = [] # conversions only if c_int != kind(0)
|
|
convert_list_2 = []
|
|
need_check_int_kind = False
|
|
need_check_status_ignore = None # or p (the status parameter)
|
|
has_comm_size = False # arrays of length = comm_size
|
|
status_var = ""
|
|
status_count = ""
|
|
is_alltoallvw = False
|
|
|
|
if need_cdesc(func):
|
|
f08ts_name = get_f08ts_name(func, is_large)
|
|
c_func_name = get_cdesc_name(func, is_large)
|
|
else:
|
|
f08ts_name = get_f08_name(func, is_large)
|
|
c_func_name = get_f08_c_name(func, is_large)
|
|
uses[c_func_name] = 1
|
|
|
|
if RE.match(r'MPI_(Init|Init_thread)$', func['name'], re.IGNORECASE):
|
|
arg_list_1.append("c_null_ptr")
|
|
arg_list_1.append("c_null_ptr")
|
|
arg_list_2.append("c_null_ptr")
|
|
arg_list_2.append("c_null_ptr")
|
|
uses['c_null_ptr'] = 1
|
|
elif RE.match(r'mpi_i?alltoall[vw]', func['name'], re.IGNORECASE):
|
|
# Need check MPI_IN_PLACE in order to skip accessing sender arrays
|
|
is_alltoallvw = True
|
|
uses['c_loc'] = 1
|
|
uses['c_associated'] = 1
|
|
uses['MPI_IN_PLACE'] = 1
|
|
|
|
# alltoallw inplace hack (since it is a corner case)
|
|
def dump_alltoallvw_inplace(arg_list_1, arg_list_2, convert_list_2):
|
|
# cannot use like sendcounts(1:length)
|
|
if G.opts['fint-size'] == G.opts['cint-size']:
|
|
if re.match(r'mpi_i?alltoallw', func['name'], re.IGNORECASE):
|
|
send_args = "sendbuf, sendcounts, sdispls, sendtypes(1:1)%MPI_VAL"
|
|
args1 = send_args + ", " + ', '.join(arg_list_1[4:])
|
|
else:
|
|
# alltoallv is fine
|
|
args1 = ', '.join(arg_list_1)
|
|
dump_fortran_line("ierror_c = %s(%s)" % (c_func_name, args1))
|
|
else:
|
|
args2 = ', '.join(arg_list_2)
|
|
G.out.append("sendcounts_c = sendcounts(1:1)")
|
|
G.out.append("sdispls_c = sdispls(1:1)")
|
|
G.out.append("recvcounts_c = recvcounts(1:length)")
|
|
G.out.append("rdispls_c = rdispls(1:length)")
|
|
if re.match(r'mpi_i?alltoallw', func['name'], re.IGNORECASE):
|
|
G.out.append("sendtypes_c = sendtypes(1:1)%MPI_VAL")
|
|
G.out.append("recvtypes_c = recvtypes(1:length)%MPI_VAL")
|
|
dump_fortran_line("ierror_c = %s(%s)" % (c_func_name, args2))
|
|
G.out.extend(convert_list_2)
|
|
|
|
# ----
|
|
def process_integer(p):
|
|
nonlocal need_check_int_kind
|
|
|
|
# deal with user callbacks
|
|
def set_grequest_lang(arg):
|
|
# assume need_check_int_kind is False
|
|
uses['MPI_SUCCESS'] = 1
|
|
uses['MPIR_Grequest_set_lang_fortran'] = 1
|
|
convert_list_2.append("IF (ierror_c == MPI_SUCCESS) THEN")
|
|
convert_list_2.append(" call MPIR_Grequest_set_lang_fortran(%s)" % arg)
|
|
convert_list_2.append("END IF")
|
|
|
|
def set_attr_proxy(arg):
|
|
# assume need_check_int_kind is False
|
|
uses['MPI_SUCCESS'] = 1
|
|
uses['MPII_Keyval_set_f90_proxy'] = 1
|
|
convert_list_2.append("IF (ierror_c == MPI_SUCCESS) THEN")
|
|
convert_list_2.append(" call MPII_Keyval_set_f90_proxy(%s)" % arg)
|
|
convert_list_2.append("END IF")
|
|
|
|
def check_proxy_requirement(func_name, p):
|
|
if p['kind'] == "REQUEST" and RE.match(r'mpi_grequest_start', func_name, re.IGNORECASE):
|
|
set_grequest_lang(arg_2)
|
|
return True
|
|
elif p['kind'] == "KEYVAL" and RE.match(r'mpi_(.*)_create_keyval', func_name, re.IGNORECASE):
|
|
set_attr_proxy(arg_2)
|
|
return True
|
|
return False
|
|
|
|
def info_get_string_buflen():
|
|
convert_list_pre.append("IF (buflen > 0) THEN")
|
|
convert_list_pre.append(" buflen_c = buflen + 1")
|
|
convert_list_pre.append("ELSE")
|
|
convert_list_pre.append(" buflen_c = 0")
|
|
convert_list_pre.append("END IF")
|
|
|
|
def info_get_valuelen():
|
|
convert_list_2.append("IF (flag_c /= 0) THEN")
|
|
convert_list_2.append(" valuelen = valuelen_c")
|
|
convert_list_2.append("END IF")
|
|
|
|
# ----
|
|
if RE.match(r'TYPE\(MPIX?_\w+\)', f08_mapping[p['kind']], re.IGNORECASE):
|
|
arg_1 = p['name'] + "%MPI_VAL"
|
|
else:
|
|
arg_1 = p['name']
|
|
arg_2 = "%s_c" % p['name']
|
|
if p['name'] == 'comm' and (has_comm_size or RE.match(r'mpi_cart_(rank|sub)', func['name'], re.IGNORECASE)):
|
|
# already processed
|
|
pass
|
|
elif p['name'] == 'buflen' and func['name'] == "MPI_Info_get_string":
|
|
# always use "buflen_c"
|
|
arg_1 = arg_2
|
|
info_get_string_buflen()
|
|
elif p['name'] == 'valuelen' and func['name'] == "MPI_Info_get_valuelen":
|
|
info_get_valuelen()
|
|
else:
|
|
need_check_int_kind = True
|
|
if p['param_direction'] == 'in' or p['param_direction'] == 'inout':
|
|
convert_list_1.append("%s = %s" % (arg_2, arg_1))
|
|
if p['param_direction'] == 'out' or p['param_direction'] == 'inout':
|
|
if check_proxy_requirement(func['name'], p):
|
|
# proxy doesn't work with the branches
|
|
need_check_int_kind = False
|
|
|
|
convert_list_2.append("%s = %s" % (arg_1, arg_2))
|
|
return (arg_1, arg_2)
|
|
|
|
def process_mpi_file(p):
|
|
arg = "%s_c" % p['name']
|
|
if p['param_direction'] == 'in' or p['param_direction'] == 'inout':
|
|
uses['MPI_File_f2c'] = 1
|
|
convert_list_pre.append("%s = MPI_File_f2c(%s%%MPI_VAL)" % (arg, p['name']))
|
|
if p['param_direction'] == 'out' or p['param_direction'] == 'inout':
|
|
uses['MPI_File_c2f'] = 1
|
|
convert_list_post.append("%s%%MPI_VAL = MPI_File_c2f(%s)" % (p['name'], arg))
|
|
return (arg, arg)
|
|
|
|
def process_logical(p):
|
|
arg = "%s_c" % p['name']
|
|
if p['param_direction'] == 'in' or p['param_direction'] == 'inout':
|
|
convert_list_pre.append("IF (%s) THEN" % p['name'])
|
|
convert_list_pre.append(" %s = 1" % arg)
|
|
convert_list_pre.append("ELSE")
|
|
convert_list_pre.append(" %s = 0" % arg)
|
|
convert_list_pre.append("END IF")
|
|
if p['param_direction'] == 'out' or p['param_direction'] == 'inout':
|
|
convert_list_post.append("%s = (%s /= 0)" % (p['name'], arg))
|
|
return (arg, arg)
|
|
|
|
def process_index(p):
|
|
arg = "%s_c" % p['name']
|
|
if p['param_direction'] == 'in' or p['param_direction'] == 'inout':
|
|
convert_list_pre.append("%s = %s - 1" % (arg, p['name']))
|
|
if p['param_direction'] == 'out' or p['param_direction'] == 'inout':
|
|
uses['MPI_UNDEFINED'] = 1
|
|
convert_list_post.append("IF (%s == MPI_UNDEFINED) THEN" % arg)
|
|
convert_list_post.append(" %s = %s" % (p['name'], arg))
|
|
convert_list_post.append("ELSE")
|
|
convert_list_post.append(" %s = %s + 1" % (p['name'], arg))
|
|
convert_list_post.append("END IF")
|
|
return (arg, arg)
|
|
|
|
def process_string(p):
|
|
arg = "%s_c" % p['name']
|
|
|
|
def info_get_string_post():
|
|
convert_list_post.append("IF (flag_c /= 0) THEN")
|
|
# only update value when buflen /= 0
|
|
convert_list_post.append(" IF (buflen /= 0) THEN")
|
|
convert_list_post.append(" call MPIR_Fortran_string_c2f(%s, %s)" % (arg, p['name']))
|
|
convert_list_post.append(" END IF")
|
|
convert_list_post.append(" buflen = buflen_c - 1")
|
|
convert_list_post.append("END IF")
|
|
|
|
def info_get_post():
|
|
convert_list_post.append("IF (flag_c /= 0) THEN")
|
|
convert_list_post.append(" call MPIR_Fortran_string_c2f(%s, %s)" % (arg, p['name']))
|
|
convert_list_post.append("END IF")
|
|
|
|
# ----
|
|
if p['param_direction'] == 'in':
|
|
convert_list_pre.append("call MPIR_Fortran_string_f2c(%s, %s)" % (p['name'], arg))
|
|
uses["MPIR_Fortran_string_f2c"] = 1
|
|
else:
|
|
if func['name'] == "MPI_Info_get_string":
|
|
info_get_string_post()
|
|
elif func['name'] == "MPI_Info_get":
|
|
info_get_post()
|
|
else:
|
|
convert_list_post.append("call MPIR_Fortran_string_c2f(%s, %s)" % (arg, p['name']))
|
|
uses["MPIR_Fortran_string_c2f"] = 1
|
|
return (arg, arg)
|
|
|
|
def process_status(p):
|
|
nonlocal need_check_int_kind, need_check_status_ignore
|
|
need_check_int_kind = True
|
|
uses['c_loc'] = 1
|
|
uses['c_associated'] = 1
|
|
uses['assignment(=)'] = 1
|
|
if p['length'] is not None:
|
|
# always output parameter
|
|
uses['MPI_STATUSES_IGNORE'] = 1
|
|
uses['MPIR_F08_get_MPI_STATUSES_IGNORE_c'] = 1
|
|
need_check_status_ignore = p
|
|
arg_1 = ":STATUS:"
|
|
arg_2 = ":STATUS:"
|
|
length = p['_array_length']
|
|
if RE.match(r'mpix?_(test|wait|request_get_status_)some', func['name'], re.IGNORECASE):
|
|
length = "outcount_c"
|
|
p['_status_convert'] = "%s(1:%s) = %s_c(1:%s)" % (p['name'], length, p['name'], length)
|
|
else:
|
|
arg_1 = "c_loc(status)"
|
|
arg_2 = "c_loc(status_c)"
|
|
if p['param_direction'] == 'out':
|
|
need_check_status_ignore = p
|
|
uses['MPI_STATUS_IGNORE'] = 1
|
|
uses['MPIR_F08_get_MPI_STATUS_IGNORE_c'] = 1
|
|
arg_1 = ":STATUS:"
|
|
arg_2 = ":STATUS:"
|
|
p['_status_convert'] = "status = status_c"
|
|
elif p['param_direction'] == 'inout':
|
|
convert_list_1.append("status_c = status")
|
|
convert_list_2.append("status = status_c")
|
|
else:
|
|
convert_list_1.append("status_c = status")
|
|
return (arg_1, arg_2)
|
|
|
|
def process_array_check(p):
|
|
nonlocal need_check_int_kind
|
|
uses['c_loc'] = 1
|
|
uses['c_ptr'] = 1
|
|
arg_1 = "%s_cptr" % p['name']
|
|
arg_2 = arg_1
|
|
convert_list_pre.append("%s = c_loc(%s)" % (arg_1, p['name']))
|
|
|
|
check = None
|
|
if p['name'] == "argv":
|
|
check = "MPI_ARGV_NULL"
|
|
elif p['name'] == "array_of_argv":
|
|
check = "MPI_ARGVS_NULL"
|
|
elif RE.match(r'\w*weights', p['name']):
|
|
# weights are input int array
|
|
c_decl_list.append("LOGICAL :: has_%s = .false." % p['name'])
|
|
check = "MPI_UNWEIGHTED"
|
|
need_check_int_kind = True
|
|
if RE.match(r'mpi_dist_graph_create$', func['name'], re.IGNORECASE):
|
|
length = "sum(degrees)"
|
|
elif RE.match(r'mpi_dist_graph_create_adjacent$', func['name'], re.IGNORECASE):
|
|
if p['name'] == "sourceweights":
|
|
length = "indegree"
|
|
else:
|
|
length = "outdegree"
|
|
elif RE.match(r'mpi_dist_graph_neighbors$', func['name'], re.IGNORECASE):
|
|
if p['name'] == "sourceweights":
|
|
length = "maxindegree"
|
|
else:
|
|
length = "maxoutdegree"
|
|
else:
|
|
print("process_array_check: Unhandled %s" % p['name'])
|
|
|
|
c_decl_list.append("INTEGER(c_int), TARGET :: %s_c(%s)" % (p['name'], length))
|
|
convert_list_1.append("IF (has_%s) THEN" % p['name'])
|
|
convert_list_1.append(" %s_cptr = c_loc(%s_c)" % (p['name'], p['name']))
|
|
convert_list_1.append("END IF")
|
|
# output conversion for MPI_Dist_graph_neighbors
|
|
if p['param_direction'] == 'out':
|
|
convert_list_2.append("IF (has_%s) THEN" % p['name'])
|
|
convert_list_2.append(" %s(1:%s) = %s_c(1:%s)" % (p['name'], length, p['name'], length))
|
|
convert_list_2.append("END IF")
|
|
|
|
elif p['name'] == "array_of_errcodes":
|
|
# errcodes are output int array
|
|
c_decl_list.append("LOGICAL :: has_errcodes_ignore = .false.")
|
|
check = "MPI_ERRCODES_IGNORE"
|
|
need_check_int_kind = True
|
|
if RE.match(r'mpi_comm_spawn_multiple', func['name'], re.IGNORECASE):
|
|
length = "sum(array_of_maxprocs(1:count))"
|
|
else: # mpi_comm_spawn
|
|
length = "maxprocs"
|
|
c_decl_list.append("INTEGER(c_int), TARGET :: %s_c(%s)" % (p['name'], length))
|
|
convert_list_1.append("IF (.not. has_errcodes_ignore) THEN")
|
|
convert_list_1.append(" %s_cptr = c_loc(%s_c)" % (p['name'], p['name']))
|
|
convert_list_1.append("END IF")
|
|
convert_list_2.append("IF (.not. has_errcodes_ignore) THEN")
|
|
convert_list_2.append(" %s(1:%s) = %s_c" % (p['name'], length, p['name']))
|
|
convert_list_2.append("END IF")
|
|
else:
|
|
print("Unhandled process_array_check")
|
|
|
|
if check:
|
|
uses['c_associated'] = 1
|
|
uses[check] = 1
|
|
uses['MPIR_F08_get_%s_c' % check] = 1
|
|
convert_list_pre.append("IF (c_associated(%s, c_loc(%s))) THEN" % (arg_1, check))
|
|
convert_list_pre.append(" %s = MPIR_F08_get_%s_c()" % (arg_1, check))
|
|
if check == "MPI_ERRCODES_IGNORE":
|
|
convert_list_pre.append(" has_errcodes_ignore = .true.")
|
|
elif check == "MPI_UNWEIGHTED":
|
|
# also need check MPI_WEIGHTS_EMPTY
|
|
check = "MPI_WEIGHTS_EMPTY"
|
|
uses[check] = 1
|
|
uses['MPIR_F08_get_%s_c' % check] = 1
|
|
convert_list_pre.append("ELSE IF (c_associated(%s, c_loc(%s))) THEN" % (arg_1, check))
|
|
convert_list_pre.append(" %s = MPIR_F08_get_%s_c()" % (arg_1, check))
|
|
convert_list_pre.append("ELSE")
|
|
convert_list_pre.append(" %s = c_loc(%s)" % (arg_1, p['name']))
|
|
convert_list_pre.append(" has_%s = .true." % p['name'])
|
|
convert_list_pre.append("END IF")
|
|
|
|
return (arg_1, arg_2)
|
|
|
|
def process_array(p):
|
|
nonlocal need_check_int_kind, has_comm_size
|
|
|
|
if p['_array_convert'] == "MPI_VAL":
|
|
need_check_int_kind = True
|
|
if p['kind'] == "DATATYPE" and has_comm_size:
|
|
# alltoallw types array
|
|
arg_1 = "%s(1:length)%%MPI_VAL" % p['name']
|
|
else:
|
|
arg_1 = "%s%%MPI_VAL" % p['name']
|
|
arg_2 = "%s_c" % p['name']
|
|
if RE.match(r'in|inout', p['param_direction']):
|
|
convert_list_1.append("%s = %s" % (arg_2, arg_1))
|
|
if RE.match(r'out|inout', p['param_direction']):
|
|
convert_list_2.append("%s = %s" % (arg_1, arg_2))
|
|
elif p['_array_convert'] == "LOGICAL":
|
|
arg_1 = "%s_c" % p['name']
|
|
arg_2 = "%s_c" % p['name']
|
|
if RE.match(r'in|inout', p['param_direction']):
|
|
convert_list_pre.append("%s = merge(1, 0, %s)" % (arg_2, p['name']))
|
|
if RE.match(r'out|inout', p['param_direction']):
|
|
convert_list_post.append("%s = (%s /= 0)" % (p['name'], arg_2))
|
|
elif p['_array_convert'] == "INDEX":
|
|
arg_1 = "%s_c" % p['name']
|
|
arg_2 = "%s_c" % p['name']
|
|
if RE.match(r'MPI_(Wait|Test|Request_get_status_)some', func['name'], re.IGNORECASE):
|
|
convert_list_post.append("%s(1:outcount) = %s(1:outcount) + 1" % (p['name'], arg_2))
|
|
else:
|
|
raise Exception("Unexpected function encountered in process_array: %s" % func['name'])
|
|
elif RE.match(r'allocate:(.+)', p['_array_convert']):
|
|
# The length variable name
|
|
is_MPI_VAL = (RE.m.group(1) == 'MPI_VAL')
|
|
length = "length"
|
|
# get array length
|
|
if p['_array_length'] == 'comm_size':
|
|
need_check_int_kind = True
|
|
if not has_comm_size:
|
|
if RE.search(r'alltoallw', func['name'], re.IGNORECASE):
|
|
# always need the length for types array
|
|
use_list = convert_list_pre
|
|
else:
|
|
use_list = convert_list_1
|
|
use_list.append("comm_c = comm%MPI_VAL")
|
|
if RE.search(r'neighbor', func['name'], re.IGNORECASE):
|
|
c_decl_list.append("INTEGER(c_int) :: err, indegree, outdegree, weighted")
|
|
use_list.append("err = MPIR_Dist_graph_neighbors_count_c(comm_c, indegree, outdegree, weighted)")
|
|
uses['MPIR_Dist_graph_neighbors_count_c'] = 1
|
|
else:
|
|
c_decl_list.append("INTEGER(c_int) :: err, length")
|
|
use_list.append("err = MPIR_Comm_size_c(comm_c, length)")
|
|
uses['MPIR_Comm_size_c'] = 1
|
|
has_comm_size = True
|
|
if RE.search(r'neighbor', func['name'], re.IGNORECASE):
|
|
if RE.match(r'sendcounts|sdispls|sendtypes', p['name']):
|
|
length = "outdegree"
|
|
else:
|
|
length = "indegree"
|
|
elif p['_array_length'] == 'cart_dim':
|
|
# MPI_Cart_rank, only 1 allocatable array
|
|
c_decl_list.append("INTEGER(c_int) :: err, length")
|
|
use_list = convert_list_pre
|
|
if RE.match(r'mpi_cart_rank', func['name'], re.IGNORECASE):
|
|
use_list = convert_list_2
|
|
use_list.append("comm_c = comm%MPI_VAL")
|
|
use_list.append("err = MPIR_Cartdim_get_c(comm_c, length)")
|
|
uses['MPIR_Cartdim_get_c'] = 1
|
|
else:
|
|
print("process_array: Unhandled assumed array length")
|
|
|
|
# set args
|
|
if is_MPI_VAL:
|
|
if p['kind'] == "DATATYPE":
|
|
arg_1 = "%s(1:%s)%%MPI_VAL" % (p['name'], length)
|
|
else:
|
|
arg_1 = "%s%%MPI_VAL" % p['name']
|
|
args_1 = "%s(1:%s)%%MPI_VAL" % (p['name'], length)
|
|
else:
|
|
arg_1 = p['name']
|
|
args_1 = "%s(1:%s)" % (p['name'], length)
|
|
arg_2 = "%s_c" % p['name']
|
|
|
|
# convert
|
|
if p['kind'] == "LOGICAL":
|
|
convert_list_pre.append("%s = merge(1, 0, %s)" % (arg_2, args_1))
|
|
arg_1 = arg_2
|
|
else:
|
|
convert_list_1.append("%s = %s" % (arg_2, args_1))
|
|
elif p['_array_convert'] == "c_int":
|
|
need_check_int_kind = True
|
|
arg_1 = "%s" % p['name']
|
|
arg_2 = "%s_c" % p['name']
|
|
if p['_array_length']:
|
|
argv_1 = arg_1 + "(1:%s)" % p['_array_length']
|
|
argv_2 = arg_2 + "(1:%s)" % p['_array_length']
|
|
else:
|
|
argv_1 = arg_1
|
|
argv_2 = arg_2
|
|
if RE.match(r'in|inout', p['param_direction']):
|
|
convert_list_1.append("%s = %s" % (argv_2, argv_1))
|
|
if RE.match(r'out|inout', p['param_direction']):
|
|
if RE.match(r'mpix?_(test|wait|request_get_status_)some', func['name'], re.IGNORECASE) and p['name'] == "array_of_indices":
|
|
argv_1 = "array_of_indices(1:outcount_c)"
|
|
argv_2 = "array_of_indices_c(1:outcount_c)"
|
|
convert_list_2.append("%s = %s" % (argv_1, argv_2))
|
|
else:
|
|
print("Unhandled process_array")
|
|
|
|
return (arg_1, arg_2)
|
|
|
|
def process_procedure(p):
|
|
uses['c_funptr'] = 1
|
|
uses['c_funloc'] = 1
|
|
FN = get_F_procedure_type(p, is_large)
|
|
uses[FN] = 1
|
|
convert_list_pre.append("%s_c = c_funloc(%s)" % (p['name'], p['name']))
|
|
if RE.match(r'mpi_register_datarep', func['name'], re.IGNORECASE) and RE.match(r'(read|write)_conversion_fn', p['name']):
|
|
FN_NULL="MPI_CONVERSION_FN_NULL"
|
|
if is_large:
|
|
FN_NULL="MPI_CONVERSION_FN_NULL_C"
|
|
convert_list_pre.append("IF (c_associated(%s_c, c_funloc(%s))) then" % (p['name'], FN_NULL))
|
|
convert_list_pre.append(" %s_c = c_null_funptr" % p['name'])
|
|
convert_list_pre.append("END IF")
|
|
uses['c_associated'] = 1
|
|
uses['c_null_funptr'] = 1
|
|
uses[FN_NULL] = 1
|
|
arg = "%s_c" % p['name']
|
|
return (arg, arg)
|
|
|
|
def post_string_len(v):
|
|
c_decl_list.append("INTEGER(c_int) :: %s_len" % v)
|
|
convert_list_pre.append("%s_len = len(%s)" % (v, v))
|
|
arg_list_1.append("%s_len" % v)
|
|
arg_list_2.append("%s_len" % v)
|
|
|
|
# ----
|
|
has_attribute_val = False
|
|
for p in func['parameters']:
|
|
if f08_param_need_skip(p, f08_mapping):
|
|
continue
|
|
if p['kind'] == "ATTRIBUTE_VAL":
|
|
has_attribute_val = True
|
|
f_param_list.append(p['name'])
|
|
f_decl = get_F_decl(p, f08_mapping)
|
|
if is_alltoallvw and p['name'] == 'sendbuf':
|
|
f_decl = re.sub(r' ::', ', TARGET ::', f_decl)
|
|
f_decl_list.append(f_decl)
|
|
check_decl_uses(f_decl, uses)
|
|
|
|
c_decl = get_F_c_decl(func, p, f08_mapping, c_mapping)
|
|
if not c_decl:
|
|
if p['kind'] == "STRING_ARRAY":
|
|
arg_1 = "c_loc(%s)" % p['name']
|
|
uses['c_loc'] = 1
|
|
elif p['kind'] == "INFO":
|
|
arg_1 = "%s(1:%s)%%MPI_VAL" % (p['name'], p['_array_length'])
|
|
else:
|
|
# no conversion needed, e.g. choice buffer, MPI_Aint, etc.
|
|
arg_1 = p['name']
|
|
arg_2 = arg_1
|
|
else:
|
|
c_decl_list.append(c_decl)
|
|
check_decl_uses(c_decl, uses)
|
|
if p['kind'] == "STRING":
|
|
(arg_1, arg_2) = process_string(p)
|
|
elif p['kind'] == "STATUS":
|
|
(arg_1, arg_2) = process_status(p)
|
|
elif '_array_length' in p: # set by get_F_c_decl(p)
|
|
if p['_array_convert'] == 'c_ptr_check':
|
|
(arg_1, arg_2) = process_array_check(p)
|
|
else:
|
|
(arg_1, arg_2) = process_array(p)
|
|
elif p['kind'] == "LOGICAL" or p['kind'] == "LOGICAL_BOOLEAN":
|
|
(arg_1, arg_2) = process_logical(p)
|
|
elif p['kind'] == "INDEX" and re.match(r'MPI_(Test|Wait|Request_get_status_)any', func['name'], re.IGNORECASE):
|
|
(arg_1, arg_2) = process_index(p)
|
|
elif f08_mapping[p['kind']] == "PROCEDURE":
|
|
(arg_1, arg_2) = process_procedure(p)
|
|
elif p['kind'] == 'FILE':
|
|
(arg_1, arg_2) = process_mpi_file(p)
|
|
else:
|
|
(arg_1, arg_2) = process_integer(p)
|
|
arg_list_1.append(arg_1)
|
|
arg_list_2.append(arg_2)
|
|
|
|
if isinstance(p['length'], str) and RE.match(r'(MPI_\w+)', p['length'], re.IGNORECASE):
|
|
uses[RE.m.group(1)] = 1
|
|
|
|
# -- extra args for wrapper functions
|
|
if has_attribute_val:
|
|
uses["MPIR_ATTR_AINT"] = 1
|
|
arg_list_1.append("MPIR_ATTR_AINT")
|
|
arg_list_2.append("MPIR_ATTR_AINT")
|
|
elif func['name'] == "MPI_Comm_spawn":
|
|
post_string_len("argv")
|
|
elif func['name'] == "MPI_Comm_spawn_multiple":
|
|
post_string_len("array_of_commands")
|
|
post_string_len("array_of_argv")
|
|
|
|
# -- return
|
|
if 'return' not in func:
|
|
f_param_list.append("ierror")
|
|
f_decl_list.append("INTEGER, OPTIONAL, INTENT(out) :: ierror")
|
|
c_decl_list.append("INTEGER(c_int) :: ierror_c")
|
|
uses['c_int'] = 1
|
|
else:
|
|
f_decl_list.append("%s :: res" % f08_mapping[func['return']])
|
|
|
|
if need_check_int_kind:
|
|
uses['c_int'] = 1
|
|
|
|
# -- dump to G.out
|
|
G.out.append("")
|
|
if 'return' not in func:
|
|
dump_fortran_line("SUBROUTINE %s(%s)" % (f08ts_name, ', '.join(f_param_list)))
|
|
else:
|
|
dump_fortran_line("FUNCTION %s(%s) result(res)" % (f08ts_name, ', '.join(f_param_list)))
|
|
G.out.append("INDENT")
|
|
dump_F_uses(uses)
|
|
G.out.append("")
|
|
G.out.append("IMPLICIT NONE")
|
|
G.out.append("")
|
|
G.out.extend(f_decl_list)
|
|
G.out.append("")
|
|
G.out.extend(c_decl_list)
|
|
G.out.append("")
|
|
if convert_list_pre:
|
|
G.out.extend(convert_list_pre)
|
|
G.out.append("")
|
|
|
|
# ----
|
|
def dump_call(s, check_int_kind):
|
|
if need_check_status_ignore:
|
|
p = need_check_status_ignore # the status parameter
|
|
if p['length'] is None:
|
|
ignore = 'MPI_STATUS_IGNORE'
|
|
else:
|
|
ignore = 'MPI_STATUSES_IGNORE'
|
|
dump_F_if_open("c_associated(c_loc(%s), c_loc(%s))" % (p['name'], ignore))
|
|
s2 = re.sub(r':STATUS:', "MPIR_F08_get_%s_c()" % ignore, s)
|
|
dump_fortran_line(s2)
|
|
dump_F_else()
|
|
if check_int_kind:
|
|
s2 = re.sub(r':STATUS:', "c_loc(%s_c)" % p['name'], s)
|
|
else:
|
|
s2 = re.sub(r':STATUS:', "c_loc(%s)" % p['name'], s)
|
|
dump_fortran_line(s2)
|
|
if check_int_kind:
|
|
G.out.append(p['_status_convert'])
|
|
dump_F_if_close()
|
|
else:
|
|
dump_fortran_line(s)
|
|
|
|
# ----
|
|
if 'return' not in func:
|
|
ret = 'ierror_c'
|
|
else:
|
|
ret = 'res'
|
|
|
|
if is_alltoallvw:
|
|
dump_F_if_open("c_associated(c_loc(sendbuf), c_loc(MPI_IN_PLACE))")
|
|
dump_alltoallvw_inplace(arg_list_1, arg_list_2, convert_list_2)
|
|
dump_F_else()
|
|
if need_check_int_kind and G.opts['fint-size'] == G.opts['cint-size']:
|
|
dump_call("%s = %s(%s)" % (ret, c_func_name, ', '.join(arg_list_1)), False)
|
|
else:
|
|
G.out.extend(convert_list_1)
|
|
dump_call("%s = %s(%s)" % (ret, c_func_name, ', '.join(arg_list_2)), True)
|
|
G.out.extend(convert_list_2)
|
|
|
|
if is_alltoallvw:
|
|
dump_F_if_close()
|
|
G.out.append("")
|
|
|
|
if convert_list_post:
|
|
G.out.extend(convert_list_post)
|
|
G.out.append("")
|
|
if 'return' not in func:
|
|
G.out.append("IF (present(ierror)) ierror = ierror_c")
|
|
G.out.append("DEDENT")
|
|
G.out.append("END SUBROUTINE %s" % f08ts_name)
|
|
else:
|
|
G.out.append("DEDENT")
|
|
G.out.append("END FUNCTION %s" % f08ts_name)
|
|
|
|
# -----
|
|
def dump_interface_module_open(module):
|
|
G.out.append("module %s" % module)
|
|
G.out.append("")
|
|
G.out.append("IMPLICIT NONE")
|
|
G.out.append("")
|
|
G.out.append("INTERFACE")
|
|
|
|
def dump_interface_module_close(module):
|
|
G.out.append("")
|
|
G.out.append("END INTERFACE")
|
|
G.out.append("END module %s" % module)
|
|
|
|
def dump_mpi_c_interface_cdesc(func, is_large):
|
|
name = get_cdesc_name(func, is_large)
|
|
dump_interface_function(func, name, name, is_large)
|
|
|
|
def dump_mpi_c_interface_nobuf(func, is_large):
|
|
name = get_f08_c_name(func, is_large)
|
|
if RE.match(r'mpi_(comm|type|win)_(set|get)_attr', func['name'], re.IGNORECASE):
|
|
# use C wrapper functions exposed by C binding
|
|
c_name = re.sub(r'MPIX?_', r'MPII_', func['name'])
|
|
if is_large:
|
|
c_name += "_large"
|
|
elif RE.match(r'mpi_comm_spawn(_multiple)?$', func['name'], re.IGNORECASE):
|
|
# use wrapper c functions
|
|
c_name = name
|
|
else:
|
|
# uses PMPI c binding directly
|
|
c_name = 'P' + get_function_name(func, is_large)
|
|
dump_interface_function(func, name, c_name, is_large)
|
|
|
|
def dump_interface_function(func, name, c_name, is_large):
|
|
c_mapping = get_kind_map('C', is_large)
|
|
f08_mapping = get_kind_map('F08', is_large)
|
|
|
|
uses = {}
|
|
f_param_list = []
|
|
decl_list = []
|
|
# nearly always uses c_int
|
|
uses['c_int'] = 1
|
|
|
|
if RE.match(r'MPI_(Init|Init_thread)$', func['name'], re.IGNORECASE):
|
|
# special, just special treat it
|
|
f_param_list.append("argc")
|
|
f_param_list.append("argv")
|
|
decl_list.append("TYPE(c_ptr), VALUE, INTENT(in) :: argc")
|
|
decl_list.append("TYPE(c_ptr), VALUE, INTENT(in) :: argv")
|
|
uses['c_ptr'] = 1
|
|
|
|
# ----
|
|
for p in func['parameters']:
|
|
if f08_param_need_skip(p, f08_mapping):
|
|
continue
|
|
f_param_list.append(p['name'])
|
|
c_decl = get_F_c_interface_decl(func, p, f08_mapping, c_mapping)
|
|
decl_list.append(c_decl)
|
|
check_decl_uses(c_decl, uses)
|
|
|
|
# -- extra parameters for wrapper functions
|
|
if RE.match(r'MPII_\w+_(get|set)_attr', c_name):
|
|
# MPII attribute wrapper functions
|
|
f_param_list.append("attr_type")
|
|
decl_list.append("INTEGER(kind(MPIR_ATTR_AINT)), VALUE, INTENT(in) :: attr_type")
|
|
uses['MPIR_ATTR_AINT'] = 1
|
|
elif func['name'] == "MPI_Comm_spawn":
|
|
f_param_list.append("argv_elem_len")
|
|
decl_list.append("INTEGER(c_int), VALUE, INTENT(in) :: argv_elem_len")
|
|
elif func['name'] == "MPI_Comm_spawn_multiple":
|
|
f_param_list.append("commands_elem_len")
|
|
f_param_list.append("argv_elem_len")
|
|
decl_list.append("INTEGER(c_int), VALUE, INTENT(in) :: commands_elem_len")
|
|
decl_list.append("INTEGER(c_int), VALUE, INTENT(in) :: argv_elem_len")
|
|
|
|
# -- return
|
|
if 'return' not in func:
|
|
ret = "ierror"
|
|
decl_list.append("INTEGER(c_int) :: ierror")
|
|
else:
|
|
ret = "res"
|
|
decl_list.append("%s :: res" % f08_mapping[func['return']])
|
|
|
|
# ----
|
|
G.out.append("")
|
|
dump_fortran_line("FUNCTION %s(%s) &" % (name, ', '.join(f_param_list)))
|
|
G.out.append(" bind(C, name=\"%s\") result(%s)" % (c_name, ret))
|
|
G.out.append("INDENT")
|
|
dump_F_uses(uses)
|
|
G.out.append("IMPLICIT NONE")
|
|
G.out.extend(decl_list)
|
|
G.out.append("DEDENT")
|
|
G.out.append("END FUNCTION %s" % name)
|
|
|
|
# dump the interface block in `mpi_f08.f90`
|
|
def dump_mpi_f08(func, is_large):
|
|
f08_mapping = get_kind_map('F08', is_large)
|
|
|
|
uses = {}
|
|
f_param_list = []
|
|
decl_list = []
|
|
|
|
for p in func['parameters']:
|
|
if f08_param_need_skip(p, f08_mapping):
|
|
continue
|
|
f_param_list.append(p['name'])
|
|
decl = get_F_decl(p, f08_mapping)
|
|
decl_list.append(decl)
|
|
check_decl_uses(decl, uses)
|
|
if 'return' not in func:
|
|
f_param_list.append("ierror")
|
|
decl_list.append("INTEGER, OPTIONAL, INTENT(out) :: ierror")
|
|
else:
|
|
decl_list.append("%s :: res" % f08_mapping[func['return']])
|
|
|
|
# ----
|
|
if need_cdesc(func):
|
|
name = get_f08ts_name(func, is_large)
|
|
else:
|
|
name = get_f08_name(func, is_large)
|
|
if 'return' not in func:
|
|
dump_fortran_line("SUBROUTINE %s(%s)" % (name, ', '.join(f_param_list)))
|
|
else:
|
|
dump_fortran_line("FUNCTION %s(%s) result(res)" % (name, ', '.join(f_param_list)))
|
|
G.out.append("INDENT")
|
|
dump_F_uses(uses)
|
|
G.out.append("IMPLICIT NONE")
|
|
G.out.extend(decl_list)
|
|
G.out.append("DEDENT")
|
|
if 'return' not in func:
|
|
G.out.append("END SUBROUTINE %s" % name)
|
|
else:
|
|
G.out.append("END FUNCTION %s" % name)
|
|
|
|
# -------------------------------
|
|
def f08_param_need_skip(p, mapping):
|
|
if RE.search(r'suppress=.*f08_parameter', p['t']):
|
|
return True
|
|
if p['kind'] == 'VARARGS':
|
|
return True
|
|
if p['large_only'] and not mapping['_name'].startswith("BIG_"):
|
|
return True
|
|
return False
|
|
|
|
# check a type declaration' module requirement, sets keys in uses dictionary
|
|
def check_decl_uses(decl, uses):
|
|
if RE.match(r'TYPE\((\w+)\)', decl, re.IGNORECASE):
|
|
uses[RE.m.group(1)] = 1
|
|
elif RE.match(r'INTEGER\(KIND=(\w+)\)', decl, re.IGNORECASE):
|
|
uses[RE.m.group(1)] = 1
|
|
elif RE.match(r'INTEGER\((\w+)\)', decl, re.IGNORECASE):
|
|
uses[RE.m.group(1)] = 1
|
|
elif RE.match(r'CHARACTER\(KIND=(\w+)\)', decl, re.IGNORECASE):
|
|
uses[RE.m.group(1)] = 1
|
|
elif RE.match(r'CHARACTER\(len=(MPI_\w+)\)', decl, re.IGNORECASE):
|
|
uses[RE.m.group(1)] = 1
|
|
elif RE.match(r'procedure\((MPI_\w+)\)', decl, re.IGNORECASE):
|
|
uses[RE.m.group(1)] = 1
|
|
|
|
def dump_F_uses(uses):
|
|
iso_c_binding_list = []
|
|
mpi_f08_list_1 = [] # mpi_f08_types
|
|
mpi_f08_list_2 = [] # mpi_f08_compile_constants
|
|
mpi_f08_list_3 = [] # mpi_f08_link_constants
|
|
mpi_f08_list_4 = [] # mpi_f08_callbacks
|
|
mpi_c_list_1 = [] # mpi_c_interface_types
|
|
mpi_c_list_2 = [] # mpi_c_interfaces_{nobuf,cdesc}
|
|
mpi_c_list_3 = [] # mpi_c_interface_glue
|
|
for a in uses:
|
|
if re.match(r'c_(int|char|ptr|loc|associated|null_ptr|null_funptr|funptr|funloc)', a, re.IGNORECASE):
|
|
iso_c_binding_list.append(a)
|
|
elif re.match(r'MPIR_ATTR_AINT|MPII_.*_proxy|MPIR.*set_lang|MPIR_.*string_(f2c|c2f)', a):
|
|
mpi_c_list_3.append(a)
|
|
elif re.match(r'MPI_\w+_(function|FN|FN_NULL)(_c)?$', a, re.IGNORECASE):
|
|
mpi_f08_list_4.append(a)
|
|
elif re.search(r'(STATUS.*IGNORE|ARGV.*NULL|ERRCODES_IGNORE|_UNWEIGHTED|WEIGHTS_EMPTY|MPI_IN_PLACE|MPI_BOTTOM)', a, re.IGNORECASE):
|
|
mpi_f08_list_3.append(a)
|
|
elif re.match(r'MPI_[A-Z_]+$', a):
|
|
mpi_f08_list_2.append(a)
|
|
elif re.match(r'MPIX?_\w+', a):
|
|
mpi_f08_list_1.append(a)
|
|
elif re.match(r'assignment', a):
|
|
mpi_f08_list_1.append(a)
|
|
elif re.match(r'c_\w+', a):
|
|
mpi_c_list_1.append(a)
|
|
else:
|
|
mpi_c_list_2.append(a)
|
|
if iso_c_binding_list:
|
|
dump_fortran_line("USE, intrinsic :: iso_c_binding, ONLY : %s" % ', '.join(iso_c_binding_list))
|
|
if mpi_f08_list_1:
|
|
dump_fortran_line("USE :: mpi_f08_types, ONLY : %s" % ', '.join(mpi_f08_list_1))
|
|
if mpi_f08_list_2:
|
|
dump_fortran_line("USE :: mpi_f08_compile_constants, ONLY : %s" % ', '.join(mpi_f08_list_2))
|
|
if mpi_f08_list_3:
|
|
dump_fortran_line("USE :: mpi_f08_link_constants, ONLY : %s" % ', '.join(mpi_f08_list_3))
|
|
if mpi_f08_list_4:
|
|
dump_fortran_line("USE :: mpi_f08_callbacks, ONLY : %s" % ', '.join(mpi_f08_list_4))
|
|
if mpi_c_list_1:
|
|
dump_fortran_line("USE :: mpi_c_interface_types, ONLY : %s" % ', '.join(mpi_c_list_1))
|
|
if mpi_c_list_2:
|
|
dump_fortran_line("USE :: mpi_c_interface, ONLY : %s" % ', '.join(mpi_c_list_2))
|
|
if mpi_c_list_3:
|
|
dump_fortran_line("USE :: mpi_c_interface_glue, ONLY : %s" % ', '.join(mpi_c_list_3))
|
|
|
|
def dump_F_if_open(cond):
|
|
G.out.append("IF (%s) THEN" % cond)
|
|
G.out.append("INDENT")
|
|
|
|
def dump_F_else():
|
|
G.out.append("DEDENT")
|
|
G.out.append("ELSE")
|
|
G.out.append("INDENT")
|
|
|
|
def dump_F_if_close():
|
|
G.out.append("DEDENT")
|
|
G.out.append("END IF")
|
|
|
|
def dump_F_module_open(name):
|
|
G.out.append("MODULE %s" % name)
|
|
G.out.append("INDENT")
|
|
|
|
def dump_F_module_close(name):
|
|
G.out.append("DEDENT")
|
|
G.out.append("END MODULE %s" % name)
|
|
|
|
def dump_fortran_line(s):
|
|
tlist = split_line_with_break(s, '', 100)
|
|
n = len(tlist)
|
|
if n > 1:
|
|
for i in range(n-1):
|
|
tlist[i] = tlist[i] + ' &'
|
|
G.out.extend(tlist)
|
|
|
|
# ---- mpi_f08_types.f90 -------------------------
|
|
G.f08_sizeof_list = ["character", "logical", "xint8", "xint16", "xint32", "xint64", "xreal32", "xreal64", "xreal128", "xcomplex32", "xcomplex64", "xcomplex128"]
|
|
|
|
def dump_mpi_f08_types():
|
|
def dump_status_type():
|
|
# Status need be consistent with mpi.h
|
|
G.out.append("")
|
|
G.out.append("TYPE, bind(C) :: MPI_Status")
|
|
for field in G.status_fields:
|
|
G.out.append(" INTEGER :: %s" % field)
|
|
G.out.append("END TYPE MPI_Status")
|
|
G.out.append("")
|
|
G.out.append("INTEGER, parameter :: MPI_SOURCE = 3")
|
|
G.out.append("INTEGER, parameter :: MPI_TAG = 4")
|
|
G.out.append("INTEGER, parameter :: MPI_ERROR = 5")
|
|
G.out.append("INTEGER, parameter :: MPI_STATUS_SIZE = 5")
|
|
|
|
def dump_status_interface():
|
|
G.out.append("")
|
|
G.out.append("INTERFACE assignment(=)")
|
|
G.out.append(" module procedure MPI_Status_f08_assign_c")
|
|
G.out.append(" module procedure MPI_Status_c_assign_f08")
|
|
G.out.append("END INTERFACE")
|
|
G.out.append("")
|
|
G.out.append("private :: MPI_Status_f08_assign_c")
|
|
G.out.append("private :: MPI_Status_c_assign_f08")
|
|
G.out.append("private :: MPI_Status_f_assign_c")
|
|
G.out.append("private :: MPI_Status_c_assign_f")
|
|
|
|
def dump_status_routines():
|
|
# declare variable name of status in f, c, or f08
|
|
def dump_decl(intent, t, name):
|
|
if t == 'f':
|
|
G.out.append("INTEGER, INTENT(%s) :: %s(MPI_STATUS_SIZE)" % (intent, name))
|
|
elif t == 'c':
|
|
G.out.append("TYPE(c_Status), INTENT(%s) :: %s" % (intent, name))
|
|
else:
|
|
G.out.append("TYPE(MPI_Status), INTENT(%s) :: %s" % (intent, name))
|
|
|
|
# phrase of individual status field
|
|
def field(t, name, idx):
|
|
if t == 'f':
|
|
if idx < 2:
|
|
return "%s(%d)" % (name, idx + 1)
|
|
else:
|
|
return "%s(%s)" % (name, G.status_fields[idx])
|
|
else:
|
|
return "%s%%%s" % (name, G.status_fields[idx])
|
|
|
|
# body of the status conversion routines
|
|
def dump_convert(in_type, in_name, out_type, out_name, res):
|
|
dump_decl("in", in_type, in_name)
|
|
dump_decl("out", out_type, out_name)
|
|
if res == "ierror":
|
|
G.out.append("INTEGER, OPTIONAL, INTENT(out) :: ierror")
|
|
elif res == "res":
|
|
G.out.append("INTEGER(c_int) :: res")
|
|
|
|
G.out.append("")
|
|
if in_type == "f" or out_type == "f" or res is None:
|
|
for i in range(5):
|
|
G.out.append("%s = %s" % (field(out_type, out_name, i), field(in_type, in_name, i)))
|
|
else:
|
|
G.out.append("%s = %s" % (out_name, in_name))
|
|
|
|
if res == "ierror":
|
|
G.out.append("IF (present(ierror)) ierror = 0")
|
|
elif res == "res":
|
|
G.out.append("res = 0")
|
|
|
|
# e.g. MPI_Status_f08_assign_c
|
|
def dump_convert_assign(in_type, out_type):
|
|
G.out.append("")
|
|
in_name = "status_%s" % in_type
|
|
out_name = "status_%s" % out_type
|
|
|
|
if in_type != 'f' and out_type != 'f':
|
|
G.out.append("elemental SUBROUTINE MPI_Status_%s_assign_%s(%s, %s)" % (out_type, in_type, out_name, in_name))
|
|
else:
|
|
G.out.append("SUBROUTINE MPI_Status_%s_assign_%s(%s, %s)" % (out_type, in_type, out_name, in_name))
|
|
G.out.append("INDENT")
|
|
dump_convert(in_type, in_name, out_type, out_name, None)
|
|
G.out.append("DEDENT")
|
|
G.out.append("END SUBROUTINE")
|
|
|
|
# e.g. MPI_Status_f082f
|
|
def dump_convert_2(in_type, out_type, prefix):
|
|
G.out.append("")
|
|
mpi_name = "%s_Status_%s2%s" % (prefix, in_type, out_type)
|
|
in_name = "%s_status" % in_type
|
|
out_name = "%s_status" % out_type
|
|
|
|
G.out.append("SUBROUTINE %s(%s, %s, ierror)" % (mpi_name, in_name, out_name))
|
|
G.out.append("INDENT")
|
|
dump_convert(in_type, in_name, out_type, out_name, "ierror")
|
|
G.out.append("DEDENT")
|
|
G.out.append("END SUBROUTINE")
|
|
|
|
# e.g. MPI_Status_f082c
|
|
def dump_convert_mpi(in_type, out_type, prefix):
|
|
G.out.append("")
|
|
# open
|
|
mpi_name = "%s_Status_%s2%s" % (prefix, in_type, out_type)
|
|
in_name = "status_%s" % in_type
|
|
out_name = "status_%s" % out_type
|
|
|
|
G.out.append("FUNCTION %s(%s, %s) &" % (mpi_name, in_name, out_name))
|
|
G.out.append(" bind(C, name=\"%s\") result (res)" % mpi_name)
|
|
G.out.append("INDENT")
|
|
G.out.append("USE, intrinsic :: iso_c_binding, ONLY: c_int")
|
|
dump_convert(in_type, in_name, out_type, out_name, "res")
|
|
G.out.append("DEDENT")
|
|
G.out.append("END FUNCTION %s" % mpi_name)
|
|
|
|
# ----
|
|
dump_convert_assign("f08", "c")
|
|
dump_convert_assign("c", "f08")
|
|
dump_convert_assign("f", "c")
|
|
dump_convert_assign("c", "f")
|
|
for prefix in ["MPI", "PMPI"]:
|
|
dump_convert_mpi("f08", "c", prefix)
|
|
dump_convert_mpi("c", "f08", prefix)
|
|
dump_convert_2("f08", "f", prefix)
|
|
dump_convert_2("f", "f08", prefix)
|
|
|
|
def dump_handle_types():
|
|
for a in G.handle_list:
|
|
G.out.append("")
|
|
G.out.append("TYPE, bind(C) :: %s" % a)
|
|
G.out.append(" INTEGER :: MPI_VAL")
|
|
G.out.append("END TYPE %s" % a)
|
|
|
|
def dump_handle_interface():
|
|
for op in ["eq", "neq"]:
|
|
if op == "eq":
|
|
op_sym = "=="
|
|
else:
|
|
op_sym = "/="
|
|
G.out.append("")
|
|
G.out.append("INTERFACE operator(%s)" % op_sym)
|
|
for a in G.handle_list:
|
|
G.out.append(" module procedure %s_%s" % (a, op))
|
|
G.out.append(" module procedure %s_f08_%s_f" % (a, op))
|
|
G.out.append(" module procedure %s_f_%s_f08" % (a, op))
|
|
G.out.append("END INTERFACE")
|
|
G.out.append("")
|
|
for a in G.handle_list:
|
|
G.out.append("private :: %s_%s" % (a, op))
|
|
G.out.append("private :: %s_f08_%s_f" % (a, op))
|
|
G.out.append("private :: %s_f_%s_f08" % (a, op))
|
|
|
|
def dump_handle_routines():
|
|
for op in ["eq", "neq"]:
|
|
G.out.append("")
|
|
for a in G.handle_list:
|
|
# e.g. MPI_Comm_eq
|
|
G.out.append("")
|
|
G.out.append("elemental FUNCTION %s_%s(x, y) result(res)" % (a, op))
|
|
G.out.append(" TYPE(%s), INTENT(in) :: x, y" % a)
|
|
G.out.append(" LOGICAL :: res")
|
|
if op == "eq":
|
|
G.out.append(" res = (x%MPI_VAL == y%MPI_VAL)")
|
|
else:
|
|
G.out.append(" res = (x%MPI_VAL /= y%MPI_VAL)")
|
|
G.out.append("END FUNCTION %s_%s" % (a, op))
|
|
# e.g. MPI_Comm_f08_eq_f, MPI_Comm_f_eq_f08
|
|
G.out.append("")
|
|
for p in [("f08", "f"), ("f", "f08")]:
|
|
func_name = "%s_%s_%s_%s" % (a, p[0], op, p[1])
|
|
G.out.append("")
|
|
G.out.append("elemental FUNCTION %s(%s, %s) result(res)" % (func_name, p[0], p[1]))
|
|
G.out.append(" TYPE(%s), INTENT(in) :: f08" % a)
|
|
G.out.append(" INTEGER, INTENT(in) :: f")
|
|
G.out.append(" LOGICAL :: res")
|
|
if op == "eq":
|
|
G.out.append(" res = (f08%MPI_VAL == f)")
|
|
else:
|
|
G.out.append(" res = (f08%MPI_VAL /= f)")
|
|
G.out.append("END FUNCTION %s" % func_name)
|
|
# e.g. MPI_Comm_f2c
|
|
for a in G.handle_list:
|
|
if a == "MPI_File":
|
|
continue
|
|
if RE.match(r'MPIX?_(\w+)', a):
|
|
c_name = "c_" + RE.m.group(1)
|
|
for p in [("f", "c"), ("c", "f")]:
|
|
func_name = "%s_%s2%s" % (a, p[0], p[1])
|
|
G.out.append("")
|
|
G.out.append("FUNCTION %s(x) result(res)" % func_name)
|
|
G.out.append(" USE mpi_c_interface_types, ONLY: %s" % c_name)
|
|
if p[0] == "f":
|
|
G.out.append(" INTEGER, VALUE :: x")
|
|
G.out.append(" INTEGER(%s) :: res" % c_name)
|
|
else:
|
|
G.out.append(" INTEGER(%s), VALUE :: x" % c_name)
|
|
G.out.append(" INTEGER :: res")
|
|
G.out.append(" res = x")
|
|
G.out.append("END FUNCTION %s" % func_name)
|
|
|
|
def dump_file_interface():
|
|
G.out.append("")
|
|
G.out.append("INTERFACE")
|
|
G.out.append("INDENT")
|
|
for p in [("f", "c"), ("c", "f")]:
|
|
func_name = "MPI_File_%s2%s" % (p[0], p[1])
|
|
G.out.append("")
|
|
G.out.append("FUNCTION %s(x) bind(C, name=\"%s\") result(res)" % (func_name, func_name))
|
|
G.out.append(" USE mpi_c_interface_types, ONLY: c_File")
|
|
if p[0] == "f":
|
|
G.out.append(" INTEGER, VALUE :: x")
|
|
G.out.append(" INTEGER(c_File) :: res")
|
|
else:
|
|
G.out.append(" INTEGER(c_File), VALUE :: x")
|
|
G.out.append(" INTEGER :: res")
|
|
G.out.append("END FUNCTION MPI_File_%s2%s" % (p[0], p[1]))
|
|
G.out.append("DEDENT")
|
|
G.out.append("END INTERFACE")
|
|
|
|
def filter_f08_sizeof_list():
|
|
if "no-real128" in G.opts:
|
|
G.f08_sizeof_list = [a for a in G.f08_sizeof_list if not a.endswith("128")]
|
|
|
|
def dump_sizeof_interface():
|
|
G.out.append("")
|
|
G.out.append("INTERFACE MPI_Sizeof")
|
|
for a in G.f08_sizeof_list:
|
|
G.out.append(" module procedure MPI_Sizeof_%s" % a)
|
|
G.out.append("END INTERFACE")
|
|
G.out.append("")
|
|
for a in G.f08_sizeof_list:
|
|
G.out.append("private :: MPI_Sizeof_%s" % a)
|
|
|
|
def dump_sizeof_routines():
|
|
for a in G.f08_sizeof_list:
|
|
G.out.append("")
|
|
G.out.append("SUBROUTINE MPI_Sizeof_%s(x, size, ierror)" % a)
|
|
G.out.append("INDENT")
|
|
if RE.match(r'x(\w+?)(\d+)', a):
|
|
if RE.m.group(1) == 'int':
|
|
t = 'int%s' % RE.m.group(2)
|
|
T = "INTEGER(%s)" % t
|
|
else:
|
|
t = 'real%s' % RE.m.group(2)
|
|
T = "%s(%s)" % (RE.m.group(1), t)
|
|
G.out.append("USE, intrinsic :: iso_fortran_env, ONLY: %s" % t)
|
|
G.out.append("%s, dimension(..) :: x" % T)
|
|
else:
|
|
G.out.append("%s, dimension(..) :: x" % a)
|
|
G.out.append("INTEGER, INTENT(out) :: size")
|
|
G.out.append("INTEGER, OPTIONAL, INTENT(out) :: ierror")
|
|
G.out.append("")
|
|
G.out.append("size = storage_size(x)/8")
|
|
G.out.append("IF (present(ierror)) ierror = 0")
|
|
G.out.append("DEDENT")
|
|
G.out.append("END SUBROUTINE")
|
|
|
|
# ----
|
|
# optionally filter real128
|
|
filter_f08_sizeof_list()
|
|
|
|
dump_F_module_open("mpi_f08_types")
|
|
G.out.append("USE, intrinsic :: iso_c_binding, ONLY: c_int")
|
|
G.out.append("USE :: mpi_c_interface_types, ONLY: c_Count, c_Status")
|
|
G.out.append("IMPLICIT NONE")
|
|
G.out.append("")
|
|
G.out.append("private :: c_int, c_Count, c_Status")
|
|
dump_handle_types()
|
|
if "no-mpiio" not in G.opts:
|
|
dump_file_interface()
|
|
dump_status_type()
|
|
dump_status_interface()
|
|
dump_handle_interface()
|
|
dump_sizeof_interface()
|
|
G.out.append("")
|
|
G.out.append("contains")
|
|
G.out.append("")
|
|
dump_sizeof_routines()
|
|
dump_status_routines()
|
|
dump_handle_routines()
|
|
G.out.append("")
|
|
dump_F_module_close("mpi_f08_types")
|
|
|
|
# -----------------------------
|
|
def dump_cdesc_c(f, lines):
|
|
print(" --> [%s]" % f)
|
|
with open(f, "w") as Out:
|
|
for l in G.copyright_c:
|
|
print(l, file=Out)
|
|
print("#include \"cdesc.h\"", file=Out)
|
|
indent = 0
|
|
for l in lines:
|
|
if RE.match(r'INDENT', l):
|
|
indent += 1
|
|
elif RE.match(r'DEDENT', l):
|
|
indent -= 1
|
|
else:
|
|
if indent > 0:
|
|
print(" " * indent, end='', file=Out)
|
|
print(l, file=Out)
|
|
|
|
def dump_cdesc_proto_h(f, lines):
|
|
print(" --> [%s]" % f)
|
|
with open(f, "w") as Out:
|
|
for l in G.copyright_c:
|
|
print(l, file=Out)
|
|
for l in lines:
|
|
tlist = split_line_with_break(l, ';', 80)
|
|
for t in tlist:
|
|
print(t, file=Out)
|
|
|
|
def dump_f90_file(f, lines):
|
|
print(" --> [%s]" % f)
|
|
with open(f, "w") as Out:
|
|
for l in G.copyright_f90:
|
|
print(l, file=Out)
|
|
indent = 0
|
|
for l in lines:
|
|
if RE.match(r'INDENT', l):
|
|
indent += 1
|
|
elif RE.match(r'DEDENT', l):
|
|
indent -= 1
|
|
else:
|
|
if indent > 0:
|
|
print(" " * indent, end='', file=Out)
|
|
print(l, file=Out)
|
|
|
|
# -------------------------------
|
|
def need_cdesc(func):
|
|
if '_need_cdesc' in func:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def process_func_parameters(func):
|
|
for p in func['parameters']:
|
|
if p['kind'] == 'BUFFER':
|
|
func['_need_cdesc'] = True
|
|
return
|
|
|
|
def check_func_directives(func):
|
|
if 'dir' in func and func['dir'] == "mpit":
|
|
func['_skip_fortran'] = 1
|
|
elif RE.match(r'mpix_(grequest_|type_iov|async_)', func['name'], re.IGNORECASE):
|
|
func['_skip_fortran'] = 1
|
|
elif RE.match(r'mpi_attr_', func['name'], re.IGNORECASE):
|
|
func['_skip_fortran'] = 1
|
|
elif RE.match(r'mpi_\w+_(f|f08|c)2(f|f08|c)$', func['name'], re.IGNORECASE):
|
|
# implemented in mpi_f08_types.f90
|
|
func['_skip_fortran'] = 1
|
|
elif RE.match(r'mpi_.*_function$', func['name'], re.IGNORECASE):
|
|
# defined in mpi_f08_callbacks.f90
|
|
func['_skip_fortran'] = 1
|
|
elif RE.match(r'mpi_type_(lb|ub|extent|hindexed|hvector|struct)$', func['name'], re.IGNORECASE):
|
|
# removed in MPI-1 and not defined in mpi_f08
|
|
func['_skip_fortran'] = 1
|
|
elif RE.match(r'mpi_(address|errhandler_(create|get|set))$', func['name'], re.IGNORECASE):
|
|
# removed in MPI-1 and not defined in mpi_f08
|
|
func['_skip_fortran'] = 1
|
|
elif RE.match(r'mpi_keyval_(create|free)$', func['name'], re.IGNORECASE):
|
|
# deprecated and not defined in mpi_f08
|
|
func['_skip_fortran'] = 1
|
|
elif RE.match(r'mpix_op_create_x|mpix_(\w+)_create_errhandler_x$', func['name'], re.IGNORECASE):
|
|
# c-only
|
|
func['_skip_fortran'] = 1
|
|
|
|
# -------------------------------
|
|
def need_ptr_check(p):
|
|
# Array parameter that may have special constant values
|
|
if RE.match(r'(argv|array_of_argv|array_of_errcodes|\w*weights)', p['name']):
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
def get_F_procedure_type(p, is_large):
|
|
if re.match(r'MPI_(Datarep_conversion|User)_function', p['func_type']) and is_large:
|
|
return p['func_type'] + "_c"
|
|
else:
|
|
return p['func_type']
|
|
return s
|
|
|
|
def get_F_decl(p, mapping):
|
|
if p['kind'] == 'STRING':
|
|
if p['length']:
|
|
s = "CHARACTER(len=%s)" % p['length']
|
|
else:
|
|
s = "CHARACTER(len=*)"
|
|
elif RE.match(r'STRING_(2D)?ARRAY', p['kind']):
|
|
s = "CHARACTER(len=*)"
|
|
elif RE.match(r'(PROCEDURE)', mapping[p['kind']]):
|
|
s = "PROCEDURE(%s)" % get_F_procedure_type(p, re.match(r'BIG', mapping['_name']))
|
|
else:
|
|
s = mapping[p['kind']]
|
|
|
|
# intent
|
|
if p['kind'] == 'BUFFER' and p['param_direction'] == 'out':
|
|
# assumed-type may not have the INTENT(OUT) attribute
|
|
pass
|
|
elif RE.match(r'procedure', s, re.IGNORECASE):
|
|
pass
|
|
elif not RE.search(r'suppress=f08_intent', p['t']):
|
|
s += ", INTENT(%s)" % p['param_direction']
|
|
|
|
# asynchronous
|
|
if p['asynchronous']:
|
|
s += ", ASYNCHRONOUS"
|
|
|
|
# length
|
|
length = get_F_decl_length(p)
|
|
if p['name'] == "array_of_argv":
|
|
# MPI_Comm_spawn_multiple
|
|
length = "count, *"
|
|
if need_ptr_check(p) or p['kind'] == "STATUS" or p['kind'] == "STRING_ARRAY":
|
|
s += ', TARGET'
|
|
s += ' :: ' + p['name']
|
|
if length:
|
|
s += '(%s)' % length
|
|
|
|
return s
|
|
|
|
def get_F_decl_length(p):
|
|
if p['kind'] == "STRING_ARRAY" or p['kind'] == "STRING_2DARRAY":
|
|
return '*'
|
|
elif p['length'] is None or p['kind'] == 'STRING':
|
|
return None
|
|
elif isinstance(p['length'], list):
|
|
return ', '.join(p['length'])
|
|
elif p['length'] == '': # array with assumed length
|
|
return '*'
|
|
else:
|
|
return p['length']
|
|
|
|
def get_F_c_interface_decl(func, p, f_mapping, c_mapping):
|
|
t_c = c_mapping[p['kind']]
|
|
t_f = f_mapping[p['kind']]
|
|
c_ptr = "TYPE(c_ptr), VALUE, INTENT(in) :: %s" % p['name']
|
|
intent = "INTENT(%s)" % p['param_direction']
|
|
|
|
def get_array():
|
|
if t_c == 'int' and not RE.match(r'(array_of_errcodes|\w*weights)', p['name']):
|
|
s = "INTEGER(c_int), %s :: %s" % (intent, p['name'])
|
|
elif RE.match(r'MPI_(Fint|Aint|Count|Offset)', t_c):
|
|
s = "%s, %s :: %s" % (t_f, intent, p['name'])
|
|
else:
|
|
return "TYPE(c_ptr), VALUE, INTENT(in) :: %s" % p['name']
|
|
length = get_F_decl_length(p)
|
|
if length:
|
|
s += '(%s)' % length
|
|
return s
|
|
|
|
# ----
|
|
if RE.match(r'TYPE\(MPIX?_(\w+)\)', t_f, re.IGNORECASE):
|
|
if RE.m.group(1) == 'Status':
|
|
return c_ptr
|
|
elif p['param_direction'] == 'in' and p['length'] is None and func['name'] != "MPI_Cancel":
|
|
# note: MPI_Cancel passed in not as value due to MPI specification oversight
|
|
return "INTEGER(c_%s), VALUE, INTENT(in) :: %s" % (RE.m.group(1), p['name'])
|
|
elif p['length'] is not None:
|
|
return "INTEGER(c_%s), %s :: %s(%s)" % (RE.m.group(1), intent, p['name'], p['length'])
|
|
else:
|
|
return "INTEGER(c_%s), %s :: %s" % (RE.m.group(1), intent, p['name'])
|
|
elif p['kind'] == 'STRING':
|
|
return "character(kind=c_char), %s :: %s(*)" % (intent, p['name'])
|
|
elif RE.match(r'(BUFFER)', p['kind']):
|
|
if p['param_direction'] == 'in':
|
|
return "%s, INTENT(in) :: %s" % (t_f, p['name'])
|
|
else:
|
|
# assumed-type may not have the INTENT(OUT) attribute
|
|
return "%s :: %s" % (t_f, p['name'])
|
|
elif RE.match(r'(EXTRA_STATE)', p['kind']):
|
|
return "%s, %s :: %s" % (t_f, intent, p['name'])
|
|
elif RE.match(r'TYPE\((c_ptr)\)', t_f, re.IGNORECASE):
|
|
return "%s, %s :: %s" % (t_f, intent, p['name'])
|
|
elif p['length'] is not None or RE.match(r'STRING_(2D)?ARRAY', p['kind']):
|
|
return get_array()
|
|
elif RE.match(r'(out|inout)', p['param_direction'], re.IGNORECASE):
|
|
if t_c == 'int':
|
|
return "INTEGER(c_int), %s :: %s" % (intent, p['name'])
|
|
elif p['kind'] == 'ATTRIBUTE_VAL':
|
|
return "%s, %s :: %s" % (t_f, intent, p['name'])
|
|
elif RE.match(r'MPI_(Fint|Aint|Count|Offset)', t_c):
|
|
return "%s, %s :: %s" % (t_f, intent, p['name'])
|
|
else: # intent(in)
|
|
if t_f == 'PROCEDURE':
|
|
return "TYPE(c_funptr), VALUE :: %s" % p['name']
|
|
elif t_c == 'int':
|
|
return "INTEGER(c_int), VALUE, INTENT(in) :: %s" % p['name']
|
|
elif p['kind'] == 'ATTRIBUTE_VAL':
|
|
return "%s, VALUE, INTENT(in) :: %s" % (t_f, p['name'])
|
|
elif RE.match(r'MPI_(Fint|Aint|Count|Offset)', t_c):
|
|
return "%s, VALUE, INTENT(in) :: %s" % (t_f, p['name'])
|
|
|
|
print("get_F_c_interface_decl: unhandled type %s - %s" % (func['name'], p['name']))
|
|
return None
|
|
|
|
def get_F_c_decl(func, p, f_mapping, c_mapping):
|
|
t_c = c_mapping[p['kind']]
|
|
t_f = f_mapping[p['kind']]
|
|
|
|
def get_string():
|
|
t = "character(kind=c_char)"
|
|
if p['param_direction'] == "in":
|
|
return "%s :: %s_c(len_trim(%s) + 1)" % (t, p['name'], p['name'])
|
|
elif func['name'] == "MPI_Info_get_string":
|
|
return "%s :: %s_c(buflen + 1)" % (t, p['name'])
|
|
elif p['length'] is None:
|
|
return "%s :: %s_c(len(%s) + 1)" % (t, p['name'], p['name'])
|
|
else:
|
|
return "%s :: %s_c(%s + 1)" % (t, p['name'], p['length'])
|
|
|
|
def get_array_decl():
|
|
# Arrays: we'll use assumptions (since only with limited num of functions)
|
|
length = get_F_decl_length(p)
|
|
if RE.match(r'mpix?_(Test|Wait|Request_get_status_)(all|any)', func['name'], re.IGNORECASE):
|
|
length = 'count'
|
|
elif RE.match(r'mpix?_(Test|Wait|Request_get_status_)(some)', func['name'], re.IGNORECASE):
|
|
length = 'incount'
|
|
elif RE.match(r'mpi_cart_(rank|sub)', func['name'], re.IGNORECASE):
|
|
length = 'cart_dim'
|
|
elif RE.match(r'mpi_graph_(create|map)$', func['name'], re.IGNORECASE) and length != 'n':
|
|
if p['name'] == 'indx':
|
|
length = 'nnodes'
|
|
else:
|
|
length = 'indx(nnodes)'
|
|
elif RE.match(r'mpi_dist_graph_create$', func['name'], re.IGNORECASE) and length != 'n':
|
|
length = 'sum(degrees)'
|
|
elif 'dir' in func and func['dir'] == 'coll':
|
|
length = 'comm_size'
|
|
# store the length
|
|
p['_array_length'] = length
|
|
|
|
if need_ptr_check(p):
|
|
p['_array_convert'] = "c_ptr_check"
|
|
return "TYPE(c_ptr) :: %s_cptr" % p['name']
|
|
elif length == 'comm_size':
|
|
if p['kind'] == "DATATYPE":
|
|
p['_array_convert'] = "allocate:MPI_VAL"
|
|
return "INTEGER(c_Datatype), allocatable, dimension(:) :: %s_c" % p['name']
|
|
elif RE.match(r'MPI_(Count|Aint)', t_c):
|
|
# t_f is something like INTEGER(KIND=MPI_COUNT_KIND)
|
|
p['_array_convert'] = "allocate:%s" % RE.m.group(1)
|
|
return "%s, allocatable, dimension(:) :: %s_c" % (t_f, p['name'])
|
|
else:
|
|
# assume t_c == 'c_int'
|
|
p['_array_convert'] = "allocate:c_int"
|
|
return "INTEGER(c_int), allocatable, dimension(:) :: %s_c" % p['name']
|
|
elif length == 'cart_dim':
|
|
if p['kind'] == 'LOGICAL':
|
|
p['_array_convert'] = "allocate:logical"
|
|
return "INTEGER(c_int), allocatable, dimension(:) :: %s_c" % p['name']
|
|
else:
|
|
p['_array_convert'] = "allocate:c_int"
|
|
return "INTEGER(c_int), allocatable, dimension(:) :: %s_c" % p['name']
|
|
elif p['kind'] == 'STATUS':
|
|
p['_array_convert'] = "STATUS"
|
|
return "TYPE(c_Status), TARGET :: %s_c(%s)" % (p['name'], length)
|
|
elif RE.match(r'(REQUEST|DATATYPE|INFO|STREAM)', p['kind']):
|
|
t = RE.m.group(1)
|
|
c_type = "c_" + t[0].upper() + t[1:].lower()
|
|
p['_array_convert'] = "MPI_VAL"
|
|
return "INTEGER(%s) :: %s_c(%s)" % (c_type, p['name'], length)
|
|
elif p['kind'] == "INDEX" and re.match(r'MPI_(Test|Wait|Request_get_status_)some', func['name'], re.IGNORECASE):
|
|
p['_array_convert'] = "INDEX"
|
|
return "INTEGER(c_int) :: %s_c(%s)" % (p['name'], length)
|
|
elif p['kind'] == "LOGICAL":
|
|
p['_array_convert'] = "LOGICAL"
|
|
return "INTEGER(c_int) :: %s_c(%s)" % (p['name'], length)
|
|
elif t_c == 'int' and t_f == 'INTEGER':
|
|
p['_array_convert'] = "c_int"
|
|
return "INTEGER(c_int) :: %s_c(%s)" % (p['name'], length)
|
|
elif RE.match(r'MPI_(Fint|Aint|Count|Offset)', t_c):
|
|
# no conversion needed
|
|
return None
|
|
elif RE.match(r'STRING_ARRAY', p['kind']):
|
|
# direct conversion, handle it in dump_f08_wrappers_f
|
|
return None
|
|
else:
|
|
print("Unhandled array parameter: %s - %s" % (p['name'], p['kind']))
|
|
return None
|
|
|
|
# ----
|
|
if p['kind'] == 'STRING':
|
|
return get_string()
|
|
elif t_f == 'PROCEDURE':
|
|
return "TYPE(c_funptr) :: %s_c" % p['name']
|
|
elif p['length'] is not None or RE.match(r'STRING_(2D)?ARRAY', p['kind']):
|
|
return get_array_decl()
|
|
elif t_c == 'int':
|
|
return "INTEGER(c_int) :: %s_c" % p['name']
|
|
elif RE.match(r'TYPE\(MPIX?_(\w+)\)', t_f, re.IGNORECASE):
|
|
if RE.m.group(1) == 'Status':
|
|
return "TYPE(c_%s), TARGET :: %s_c" % (RE.m.group(1), p['name'])
|
|
else:
|
|
return "INTEGER(c_%s) :: %s_c" % (RE.m.group(1), p['name'])
|
|
elif RE.match(r'(BUFFER|EXTRA_STATE|ATTRIBUTE_VAL)', p['kind']):
|
|
return None
|
|
elif RE.match(r'MPI_(Fint|Aint|Count|Offset)', t_c):
|
|
return None
|
|
elif RE.match(r'TYPE\((c_ptr)\)', t_f, re.IGNORECASE):
|
|
return None
|
|
else:
|
|
print("get_F_c_decl: unhandled type %s: %s - %s" % (p['name'], t_f, t_c))
|
|
return None
|
|
|
|
#----------------------------------------
|
|
# Depend on integer size, POLY parameters don't always end up with different interfaces
|
|
def get_real_POLY_kinds():
|
|
G.real_poly_kinds = {}
|
|
|
|
def get_int_type(fortran_type):
|
|
if fortran_type == "INTEGER":
|
|
return "fint"
|
|
elif "MPI_ADDRESS_KIND" in fortran_type:
|
|
return "aint"
|
|
elif "MPI_COUNT_KIND" in fortran_type:
|
|
return "count"
|
|
else:
|
|
raise Exception("Unrecognized POLY int type: %s" % fortran_type)
|
|
|
|
small_map = G.MAPS['SMALL_F08_KIND_MAP']
|
|
large_map = G.MAPS['BIG_F08_KIND_MAP']
|
|
for kind in small_map:
|
|
if kind == 'POLYFUNCTION':
|
|
# Currently there are only two: MPI_User_function, MPI_Datarep_conversion_function,
|
|
# both contains parameter POLYXFER_NUM_ELEM. However, Fortran is not able to
|
|
# differentiate generic interface based on different function signature. Disable
|
|
# for now.
|
|
pass
|
|
elif kind.startswith('POLY'):
|
|
a = get_int_type(small_map[kind]) + "-size"
|
|
b = get_int_type(large_map[kind]) + "-size"
|
|
if G.opts[a] != G.opts[b]:
|
|
G.real_poly_kinds[kind] = 1
|
|
|
|
def function_has_real_POLY_parameters(func):
|
|
for p in func['parameters']:
|
|
if p['kind'] in G.real_poly_kinds:
|
|
return True
|
|
return False
|
|
|
|
#------------------------------------------
|
|
def dump_compile_constants_f90(f):
|
|
print(" --> [%s]" % f)
|
|
with open(f, "w") as Out:
|
|
for l in G.copyright_f90:
|
|
print(l, file=Out)
|
|
print("module mpi_f08_compile_constants", file=Out)
|
|
print("use,intrinsic :: iso_c_binding, only: c_int", file=Out)
|
|
print("use :: mpi_f08_types", file=Out)
|
|
print("use :: mpi_c_interface_types, only: c_Aint, c_Count, c_Offset", file=Out)
|
|
for a in ['c_int', 'c_Aint', 'c_Count', 'c_Offset']:
|
|
print("private :: %s" % a, file=Out)
|
|
|
|
print("integer, parameter :: %-32s = %s" % ('MPI_INTEGER_KIND', 'c_int'), file=Out)
|
|
print("integer, parameter :: %-32s = %s" % ('MPI_ADDRESS_KIND', 'c_Aint'), file=Out)
|
|
print("integer, parameter :: %-32s = %s" % ('MPI_OFFSET_KIND', 'c_Offset'), file=Out)
|
|
print("integer, parameter :: %-32s = %s" % ('MPI_COUNT_KIND', 'c_Count'), file=Out)
|
|
|
|
# -- all integer constants
|
|
for name in G.mpih_defines:
|
|
val = G.mpih_defines[name]
|
|
T = "integer"
|
|
if re.match(r'MPI_[TF]_', name):
|
|
continue
|
|
elif re.match(r'MPI_\w+_FN', name):
|
|
continue
|
|
elif re.match(r'MPI_\w+_FMT_(DEC|HEX)_SPEC', name):
|
|
continue
|
|
elif re.match(r'MPI_(UNWEIGHTED|WEIGHTS_EMPTY|BUFFER_AUTOMATIC|BOTTOM|IN_PLACE|STATUS_IGNORE|STATUSES_IGNORE|ERRCODES_IGNORE|ARGVS_NULL|ARGV_NULL)', name):
|
|
continue
|
|
elif RE.match(r'(MPI_\w+)\(', str(val)):
|
|
T = "type(%s)" % RE.m.group(1)
|
|
elif re.match(r'MPI_DISPLACEMENT_CURRENT', name):
|
|
T = 'integer(kind=MPI_OFFSET_KIND)'
|
|
|
|
if val == "DATATYPE":
|
|
if re.match(r'MPI_(AINT|COUNT|OFFSET)', name):
|
|
print("type(MPI_Datatype), parameter :: %-19s = MPI_Datatype(@F08_MPI_%s_DATATYPE@)" % (name, name[4:]), file=Out)
|
|
elif name.startswith("MPI_CXX_"):
|
|
print("type(MPI_Datatype), parameter :: %-19s = MPI_Datatype(@F08_MPIR_CXX_%s@)" % (name, name[8:]), file=Out)
|
|
else:
|
|
print("type(MPI_Datatype), parameter :: %-19s = MPI_Datatype(@F08_%s@)" % (name, name), file=Out)
|
|
else:
|
|
print("%s, parameter :: %-32s = %s" % (T, name, val), file=Out)
|
|
# -- Fortran08 capability
|
|
for a in ['MPI_SUBARRAYS_SUPPORTED', 'MPI_ASYNC_PROTECTS_NONBLOCKING']:
|
|
print("logical, parameter :: %-32s = %s" % (a, '.true.'), file=Out)
|
|
|
|
print("end module mpi_f08_compile_constants", file=Out)
|
|
|
|
def load_mpi_h_in(f):
|
|
# load constants into G.mpih_defines
|
|
with open(f, "r") as In:
|
|
for line in In:
|
|
# trim trailing comments
|
|
line = re.sub(r'\s+\/\*.*', '', line)
|
|
if RE.match(r'#define\s+(MPI_\w+)\s+(.+)', line):
|
|
# direct macros
|
|
(name, val) = RE.m.group(1, 2)
|
|
if re.match(r'MPI_FILE_NULL', name):
|
|
val = "MPI_File(0)"
|
|
elif re.match(r'MPI_(LONG_LONG|C_COMPLEX)', name):
|
|
# datatype aliases
|
|
val = "DATATYPE"
|
|
elif re.match(r'\(?\(MPI_Datatype\)\@(MPIR?_\w+)\@\)?', val):
|
|
val = "DATATYPE"
|
|
elif RE.match(r'\(+(MPI_\w+)\)\(?0x([0-9a-fA-F]+)', val):
|
|
# handle constants
|
|
T = RE.m.group(1)
|
|
val = int(RE.m.group(2), 16)
|
|
val = "%s(%d) ! 0x%08x" % (T, val, val)
|
|
|
|
elif RE.match(r'0x([0-9a-fA-F]+)', val):
|
|
# direct hex constants (KEYVAL constants)
|
|
val = int(RE.m.group(1), 16)
|
|
if RE.match(r'MPI_(TAG_UB|HOST|IO|WTIME_IS_GLOBAL|UNIVERSE_SIZE|LASTUSEDCODE|APPNUM|WIN_(BASE|SIZE|DISP_UNIT|CREATE_FLAVOR|MODEL))', name):
|
|
# KEYVAL, Fortran value is C-value + 1
|
|
val = val + 1
|
|
val = str(val) + (" ! 0x%08x" % val)
|
|
elif RE.match(r'MPI_MAX_', name):
|
|
# Fortran string buffer limit need be 1-less
|
|
if re.match(r'@\w+@', val):
|
|
val += "-1"
|
|
else:
|
|
val = int(val) - 1
|
|
elif RE.match(r'\(([-\d]+)\)', val):
|
|
# take off the extra parentheses
|
|
val = RE.m.group(1)
|
|
|
|
G.mpih_defines[name] = val
|
|
elif RE.match(r'\s+(MPI_\w+)\s*=\s*(\d+)', line):
|
|
# enum values
|
|
(name, val) = RE.m.group(1, 2)
|
|
G.mpih_defines[name] = val
|