diff --git a/ompi/mpi/fortran/use-mpi-f08/Makefile.am b/ompi/mpi/fortran/use-mpi-f08/Makefile.am index 23a5f11de7a..50b40f63d9c 100644 --- a/ompi/mpi/fortran/use-mpi-f08/Makefile.am +++ b/ompi/mpi/fortran/use-mpi-f08/Makefile.am @@ -332,7 +332,6 @@ mpi_api_files = \ intercomm_create_from_groups_f08.F90 \ intercomm_merge_f08.F90 \ iprobe_f08.F90 \ - irecv_f08.F90 \ ireduce_f08.F90 \ ireduce_scatter_f08.F90 \ ireduce_scatter_block_f08.F90 \ @@ -340,7 +339,6 @@ mpi_api_files = \ iscan_f08.F90 \ iscatter_f08.F90 \ iscatterv_f08.F90 \ - isend_f08.F90 \ isendrecv_f08.F90 \ isendrecv_replace_f08.F90 \ issend_f08.F90 \ @@ -423,7 +421,6 @@ mpi_api_files = \ status_set_elements_f08.F90 \ status_set_elements_x_f08.F90 \ testall_f08.F90 \ - testany_f08.F90 \ test_cancelled_f08.F90 \ test_f08.F90 \ testsome_f08.F90 \ diff --git a/ompi/mpi/fortran/use-mpi-f08/generate_bindings.py b/ompi/mpi/fortran/use-mpi-f08/generate_bindings.py index 76465a84cc7..239ef484040 100644 --- a/ompi/mpi/fortran/use-mpi-f08/generate_bindings.py +++ b/ompi/mpi/fortran/use-mpi-f08/generate_bindings.py @@ -46,12 +46,12 @@ def fn_api_name(self): return c_api_func_name(self.fn_name, bigcount=self.bigcount).upper() @property - def tmp_c_name(self): + def tmp_name(self): """Return a temporary name for use in C.""" return f'c_{self.name}' @property - def tmp_c_name2(self): + def tmp_name2(self): """Return a secondary temporary name for use in C.""" return f'c_{self.name}2' @@ -65,6 +65,10 @@ def tmp_counter(self): def declare(self): """Return a declaration for the type.""" + def declare_tmp(self): + """Declare temporaries on in the subroutine.""" + return [] + def declare_cbinding_fortran(self): """Return the C binding declaration as seen from Fortran.""" return self.declare() @@ -77,6 +81,10 @@ def use(self): """Return list of (module, name) for a Fortran use-statement.""" return [] + def post(self): + """Return post-processing code to be run after the call.""" + return [] + @abstractmethod def c_parameter(self): """Return the parameter expression to be used in the C function.""" @@ -129,6 +137,24 @@ def c_argument(self): return f'OMPI_F2C_BOTTOM({self.name})' +@FortranType.add('BUFFER_ASYNC') +class BufferAsyncType(BufferType): + def declare(self): + return f'OMPI_FORTRAN_IGNORE_TKR_TYPE, INTENT(IN) OMPI_ASYNCHRONOUS :: {self.name}' + + +@FortranType.add('BUFFER_OUT') +class BufferOutType(BufferType): + def declare(self): + return f'OMPI_FORTRAN_IGNORE_TKR_TYPE :: {self.name}' + + +@FortranType.add('BUFFER_ASYNC_OUT') +class BufferAsyncOutType(BufferType): + def declare(self): + return f'OMPI_FORTRAN_IGNORE_TKR_TYPE OMPI_ASYNCHRONOUS :: {self.name}' + + @FortranType.add('COUNT') class CountType(FortranType): def declare(self): @@ -166,10 +192,10 @@ def c_parameter(self): return f'MPI_Fint *{self.name}' def c_prepare(self): - return [f'MPI_Datatype {self.tmp_c_name} = PMPI_Type_f2c(*{self.name});'] + return [f'MPI_Datatype {self.tmp_name} = PMPI_Type_f2c(*{self.name});'] def c_argument(self): - return self.tmp_c_name + return self.tmp_name class IntType(FortranType): @@ -193,6 +219,69 @@ class TagType(IntType): pass +@FortranType.add('INDEX_OUT') +class IndexOutType(IntType): + def declare(self): + return f'INTEGER, INTENT(OUT) :: {self.name}' + + def c_declare_tmp(self): + return [f'int {self.tmp_name};'] + + def c_shortcut_code(self): + return [f'*{self.name} = OMPI_INT_2_FINT(MPI_UNDEFINED);'] + + def c_argument(self): + return f'&{self.tmp_name}' + + def c_post(self): + return [ + f'if (MPI_SUCCESS == {C_ERROR_TMP_NAME} && MPI_UNDEFINED != {self.tmp_name}) {{', + f' {self.tmp_name} += 1;' + f' *{self.name} = OMPI_INT_2_FINT({self.tmp_name});' + '}', + ] + + +@FortranType.add('LOGICAL_OUT') +class LogicalOutType(IntType): + """Logical type. + + NOTE: Since the logical type causes difficulties when passed to C code, + this code uses a temporary integer in Fortran to pass to the C code. On + completion the logical type is set based on C's true/false rules. + """ + + def declare(self): + return f'LOGICAL, INTENT(OUT) :: {self.name}' + + def declare_tmp(self): + return [f'INTEGER :: {self.tmp_name} = 0'] + + def declare_cbinding_fortran(self): + return f'INTEGER, INTENT(OUT) :: {self.name}' + + def argument(self): + return self.tmp_name + + def post(self): + return [f'{self.name} = {self.tmp_name} /= 0'] + + def c_parameter(self): + return f'MPI_Fint *{self.name}' + + def c_declare_tmp(self): + return [f'int {self.tmp_name};'] + + def c_shortcut_code(self): + return [f'*{self.name} = OMPI_INT_2_FINT(1);'] + + def c_argument(self): + return f'&{self.tmp_name}' + + def c_post(self): + return [f'*{self.name} = OMPI_INT_2_FINT({self.tmp_name});'] + + @FortranType.add('COMM') class CommType(FortranType): def declare(self): @@ -211,10 +300,10 @@ def c_parameter(self): return f'MPI_Fint *{self.name}' def c_prepare(self): - return [f'MPI_Comm {self.tmp_c_name} = PMPI_Comm_f2c(*{self.name});'] + return [f'MPI_Comm {self.tmp_name} = PMPI_Comm_f2c(*{self.name});'] def c_argument(self): - return self.tmp_c_name + return self.tmp_name @FortranType.add('STATUS') @@ -229,17 +318,21 @@ def c_parameter(self): # TODO: Is this correct? (I've listed it as TYPE(MPI_Status) in the binding) return f'MPI_Fint *{self.name}' + def c_shortcut_code(self): + return [f'PMPI_Status_c2f(&ompi_status_empty, {self.name});'] + + # TODO: This code should be in c_declare_tmp() def c_prepare(self): return [ - f'OMPI_FORTRAN_STATUS_DECLARATION({self.tmp_c_name}, {self.tmp_c_name2});', - f'OMPI_FORTRAN_STATUS_SET_POINTER({self.tmp_c_name}, {self.tmp_c_name2}, {self.name});' + f'OMPI_FORTRAN_STATUS_DECLARATION({self.tmp_name}, {self.tmp_name2});', + f'OMPI_FORTRAN_STATUS_SET_POINTER({self.tmp_name}, {self.tmp_name2}, {self.name});' ] def c_argument(self): - return self.tmp_c_name + return self.tmp_name def c_post(self): - return [f'OMPI_FORTRAN_STATUS_RETURN({self.tmp_c_name}, {self.tmp_c_name2}, {self.name}, {C_ERROR_TMP_NAME});'] + return [f'OMPI_FORTRAN_STATUS_RETURN({self.tmp_name}, {self.tmp_name2}, {self.name}, {C_ERROR_TMP_NAME});'] @FortranType.add('SHORTCUT_COUNT') @@ -267,6 +360,37 @@ def c_argument(self): return f'OMPI_FINT_2_INT(*{self.name})' +@FortranType.add('REQUEST') +class RequestType(FortranType): + def declare(self): + return f'TYPE(MPI_Request), INTENT(OUT) :: {self.name}' + + def declare_cbinding_fortran(self): + return f'INTEGER, INTENT(OUT) :: {self.name}' + + def argument(self): + return f'{self.name}%MPI_VAL' + + def use(self): + return [('mpi_f08_types', 'MPI_Request')] + + def c_parameter(self): + return f'MPI_Fint *{self.name}' + + def c_declare_tmp(self): + return [f'MPI_Request {self.tmp_name};'] + + def c_argument(self): + return f'&{self.tmp_name}' + + def c_post(self): + return [ + f'if (MPI_SUCCESS == {C_ERROR_TMP_NAME}) {{', + f' *{self.name} = PMPI_Request_c2f({self.tmp_name});', + '}', + ] + + def allocate_array(name, malloc_expr, fn_api_name): """Generate code for allocating an array and checking the result.""" return [ @@ -297,10 +421,10 @@ def c_parameter(self): return f'MPI_Fint *{self.name}' def c_declare_tmp(self): - return [f'MPI_Request *{self.tmp_c_name};'] + return [f'MPI_Request *{self.tmp_name};'] def c_prepare(self): - tmp_name = self.tmp_c_name + tmp_name = self.tmp_name code = allocate_array(tmp_name, f'{self.dep_param.c_argument()} * sizeof(MPI_Request)', self.fn_api_name) @@ -313,17 +437,17 @@ def c_prepare(self): return code def c_argument(self): - return self.tmp_c_name + return self.tmp_name def c_post(self): i = self.tmp_counter() return [ f'if (MPI_SUCCESS == {C_ERROR_TMP_NAME}) {{', f' for (int {i} = 0; {i} < {self.dep_param.c_argument()}; ++{i}) {{', - f' {self.name}[{i}] = {self.tmp_c_name}[{i}]->req_f_to_c_index;', + f' {self.name}[{i}] = {self.tmp_name}[{i}]->req_f_to_c_index;', ' }', '}', - f'free({self.tmp_c_name});', + f'free({self.tmp_name});', ] @@ -339,15 +463,15 @@ def c_parameter(self): return f'MPI_Fint *{self.name}' def c_declare_tmp(self): - return [f'MPI_Status *{self.tmp_c_name};'] + return [f'MPI_Status *{self.tmp_name};'] def c_prepare(self): - return allocate_array(self.tmp_c_name, + return allocate_array(self.tmp_name, f'{self.dep_param.c_argument()} * sizeof(MPI_Status)', self.fn_api_name) def c_argument(self): - return self.tmp_c_name + return self.tmp_name def c_post(self): i = self.tmp_counter() @@ -356,11 +480,11 @@ def c_post(self): f' for (int {i} = 0; {i} < {self.dep_param.c_argument()}; ++{i}) {{', f' if (!OMPI_IS_FORTRAN_STATUSES_IGNORE({self.name}) &&', f' !OMPI_IS_FORTRAN_STATUS_IGNORE(&{self.name}[{i}])) {{', - f' PMPI_Status_c2f(&{self.tmp_c_name}[{i}], &{self.name}[{i} * (sizeof(MPI_Status) / sizeof(int))]);', + f' PMPI_Status_c2f(&{self.tmp_name}[{i}], &{self.name}[{i} * (sizeof(MPI_Status) / sizeof(int))]);', ' }', ' }', '}', - f'free({self.tmp_c_name});' + f'free({self.tmp_name});' ] @@ -379,6 +503,12 @@ def c_api_func_name_profile(fn_name, bigcount=False): return f'P{c_api_func_name(fn_name, bigcount)}' +def fortran_f08_name(fn_name, bigcount=False): + """Produce the final f08 name from base_name.""" + suffix = '_c' if bigcount else '' + return f'MPI_{fn_name.capitalize()}_f08{suffix}' + + FortranParameter = namedtuple('FortranParameter', ['type_', 'name', 'dep_name']) FortranPrototype = namedtuple('FortranPrototype', ['fn_name', 'parameters']) @@ -433,11 +563,6 @@ def _fn_name_suffix(self): """Return a suffix for function names.""" return '_c' if self.bigcount else '' - @property - def fortran_f08_name(self): - """Produce the final f08 name from base_name.""" - return f'MPI_{self.fn_name.capitalize()}_f08{self._fn_name_suffix()}' - @property def c_func_name(self): """Produce the final C func name from base_name.""" @@ -483,7 +608,7 @@ def _print_fortran_interface(self): def print_f_source(self): """Output the main MPI Fortran subroutine.""" - sub_name = self.fortran_f08_name + sub_name = fortran_f08_name(self.fn_name, bigcount=self.bigcount) c_func = self.c_func_name print('subroutine', f'{sub_name}({self._param_list()},{FORTRAN_ERROR_NAME})') # Use statements @@ -499,6 +624,9 @@ def print_f_source(self): print(f' INTEGER, OPTIONAL, INTENT(OUT) :: {FORTRAN_ERROR_NAME}') # Temporaries print(f' INTEGER :: {C_ERROR_TMP_NAME}') + for param in self.parameters: + for line in param.declare_tmp(): + print(f' {line}') # Interface for call to C function print() @@ -511,6 +639,10 @@ def print_f_source(self): # Convert error type print(f' if (present({FORTRAN_ERROR_NAME})) {FORTRAN_ERROR_NAME} = {C_ERROR_TMP_NAME}') + for param in self.parameters: + for line in param.post(): + print(f' {line}') + print(f'end subroutine {sub_name}') def print_c_source(self): @@ -541,6 +673,7 @@ def print_c_source(self): for other_param in self.parameters: for line in other_param.c_shortcut_code(): print(f' {line}') + print(' return;') print(' }') # Prepare code for temporaries, etc. @@ -566,7 +699,22 @@ def print_f_source_header(): """Print the fortran f08 file header.""" print(f'! {GENERATED_MESSAGE}') print('#include "ompi/mpi/fortran/configure-fortran-output.h"') - print('#include "mpi-f08-rename.h"') + + +def print_profiling_rename_macros(prototypes): + """Print macros for renaming functions for the profiling interface. + + Previously hardcoded in mpi-f08-rename.h. + """ + print('#if OMPI_BUILD_MPI_PROFILING') + for prototype in prototypes: + name = fortran_f08_name(prototype.fn_name) + print(f'#define {name} P{name}') + # Check for bigcount version + if any(param.type_ == 'COUNT' for param in prototype.parameters): + bigcount_name = fortran_f08_name(prototype.fn_name, bigcount=True) + print(f'#define {bigcount_name} P{bigcount_name}') + print('#endif /* OMPI_BUILD_MPI_PROFILING */') def print_c_source_header(): @@ -602,11 +750,16 @@ def main(): prototypes = load_prototypes(args.template) if args.lang == 'fortran': print_f_source_header() + print() + print_profiling_rename_macros(prototypes) + print() else: print_c_source_header() for prototype in prototypes: + print() print_binding(prototype, args.lang) if any(param.type_ == 'COUNT' for param in prototype.parameters): + print() print_binding(prototype, args.lang, bigcount=True) diff --git a/ompi/mpi/fortran/use-mpi-f08/interface.in b/ompi/mpi/fortran/use-mpi-f08/interface.in index 5d2863e3b0c..a52c99d43f1 100644 --- a/ompi/mpi/fortran/use-mpi-f08/interface.in +++ b/ompi/mpi/fortran/use-mpi-f08/interface.in @@ -1,3 +1,6 @@ -recv(BUFFER buf, COUNT count, DATATYPE datatype, RANK source, TAG tag, COMM comm, STATUS status) +recv(BUFFER_OUT buf, COUNT count, DATATYPE datatype, RANK source, TAG tag, COMM comm, STATUS status) +irecv(BUFFER_ASYNC_OUT buf, COUNT count, DATATYPE datatype, RANK source, TAG tag, COMM comm, REQUEST request) send(BUFFER buf, COUNT count, DATATYPE datatype, RANK dest, TAG tag, COMM comm) +isend(BUFFER_ASYNC buf, COUNT count, DATATYPE data, RANK dest, TAG tag, COMM comm, REQUEST request) waitall(SHORTCUT_COUNT count, REQUEST_ARRAY array_of_requests:count, STATUS_ARRAY array_of_statuses:count) +testany(SHORTCUT_COUNT count, REQUEST_ARRAY array_of_requests:count, INDEX_OUT index, LOGICAL_OUT flag, STATUS status)