From 1a9a108a2bb4113210b043232847ee7eb21fb186 Mon Sep 17 00:00:00 2001 From: Jake Tronge Date: Wed, 10 Jan 2024 13:06:07 -0700 Subject: [PATCH] Generate interfaces for Fortran and C with bigcount This adds scripts for generating the Fortran and C API bindings from template files, while also generating bigcount interfaces for those that require them. The Fortran binding code (for mpi_f08) is designed to generate both the Fortran subroutines and wrapping C code which calls into the MPI C api. Python >=3.6 is required for running these scripts, which is only necessary when the binding files have not already been generated. Users of the distribution tarball should not need to generate these files and thus should not require Python. Signed-off-by: Jake Tronge --- .gitignore | 8 + config/ompi_config_files.m4 | 2 +- config/ompi_configure_options.m4 | 7 + ompi/include/mpi.h.in | 27 +- ompi/mpi/c/Makefile.am | 87 +- ompi/mpi/c/{abort.c => abort.c.in} | 12 +- ompi/mpi/c/{accumulate.c => accumulate.c.in} | 15 +- ompi/mpi/c/{allreduce.c => allreduce.c.in} | 14 +- ompi/mpi/c/{barrier.c => barrier.c.in} | 12 +- ompi/mpi/c/{comm_f2c.c => comm_f2c.c.in} | 12 +- ompi/mpi/c/{comm_free.c => comm_free.c.in} | 12 +- ompi/mpi/c/{comm_rank.c => comm_rank.c.in} | 12 +- ompi/mpi/c/{comm_size.c => comm_size.c.in} | 12 +- ompi/mpi/c/{comm_split.c => comm_split.c.in} | 14 +- ...comm_split_type.c => comm_split_type.c.in} | 16 +- ompi/mpi/c/{file_open.c => file_open.c.in} | 14 +- ompi/mpi/c/{finalize.c => finalize.c.in} | 12 +- ompi/mpi/c/{finalized.c => finalized.c.in} | 12 +- ompi/mpi/c/generate_bindings.py | 1278 +++++++++++++++++ ...ary_version.c => get_library_version.c.in} | 12 +- ...ocessor_name.c => get_processor_name.c.in} | 12 +- ompi/mpi/c/{init.c => init.c.in} | 12 +- .../mpi/c/{initialized.c => initialized.c.in} | 12 +- ompi/mpi/c/{irecv.c => irecv.c.in} | 14 +- ompi/mpi/c/{isend.c => isend.c.in} | 14 +- ompi/mpi/c/{recv.c => recv.c.in} | 14 +- ompi/mpi/c/{send.c => send.c.in} | 14 +- ompi/mpi/c/{waitall.c => waitall.c.in} | 13 +- ompi/mpi/c/{waitsome.c => waitsome.c.in} | 16 +- ompi/mpi/c/{wtime.c => wtime.c.in} | 9 +- ompi/mpi/fortran/use-mpi-f08/Makefile.am | 78 +- ompi/mpi/fortran/use-mpi-f08/alltoall_f08.F90 | 32 - ompi/mpi/fortran/use-mpi-f08/base/Makefile.am | 10 +- .../use-mpi-f08/generate_bindings.py.in | 781 ++++++++++ ompi/mpi/fortran/use-mpi-f08/interface.in | 20 + .../use-mpi-f08/mod/mpi-f08-interfaces.h.in | 23 + .../fortran/use-mpi-f08/mod/mpi-f08-rename.h | 2 + .../fortran/use-mpi-f08/profile/Makefile.am | 477 ------ .../profile/pcomm_create_from_group_f08.F90 | 29 - .../profile/pgroup_from_session_pset_f08.F90 | 29 - .../pintercomm_create_from_groups_f08.F90 | 35 - .../profile/psession_finalize_f08.F90 | 24 - ompi/mpi/fortran/use-mpi-f08/recv_f08.F90 | 29 - ompi/mpi/fortran/use-mpi-f08/send_f08.F90 | 28 - ompi/mpi/fortran/use-mpi-f08/waitall_f08.F90 | 25 - 45 files changed, 2314 insertions(+), 1028 deletions(-) rename ompi/mpi/c/{abort.c => abort.c.in} (88%) rename ompi/mpi/c/{accumulate.c => accumulate.c.in} (92%) rename ompi/mpi/c/{allreduce.c => allreduce.c.in} (92%) rename ompi/mpi/c/{barrier.c => barrier.c.in} (91%) rename ompi/mpi/c/{comm_f2c.c => comm_f2c.c.in} (88%) rename ompi/mpi/c/{comm_free.c => comm_free.c.in} (88%) rename ompi/mpi/c/{comm_rank.c => comm_rank.c.in} (87%) rename ompi/mpi/c/{comm_size.c => comm_size.c.in} (87%) rename ompi/mpi/c/{comm_split.c => comm_split.c.in} (89%) rename ompi/mpi/c/{comm_split_type.c => comm_split_type.c.in} (92%) rename ompi/mpi/c/{file_open.c => file_open.c.in} (92%) rename ompi/mpi/c/{finalize.c => finalize.c.in} (86%) rename ompi/mpi/c/{finalized.c => finalized.c.in} (90%) create mode 100755 ompi/mpi/c/generate_bindings.py rename ompi/mpi/c/{get_library_version.c => get_library_version.c.in} (93%) rename ompi/mpi/c/{get_processor_name.c => get_processor_name.c.in} (87%) rename ompi/mpi/c/{init.c => init.c.in} (92%) rename ompi/mpi/c/{initialized.c => initialized.c.in} (90%) rename ompi/mpi/c/{irecv.c => irecv.c.in} (89%) rename ompi/mpi/c/{isend.c => isend.c.in} (91%) rename ompi/mpi/c/{recv.c => recv.c.in} (91%) rename ompi/mpi/c/{send.c => send.c.in} (91%) rename ompi/mpi/c/{waitall.c => waitall.c.in} (92%) rename ompi/mpi/c/{waitsome.c => waitsome.c.in} (91%) rename ompi/mpi/c/{wtime.c => wtime.c.in} (93%) delete mode 100644 ompi/mpi/fortran/use-mpi-f08/alltoall_f08.F90 create mode 100644 ompi/mpi/fortran/use-mpi-f08/generate_bindings.py.in create mode 100644 ompi/mpi/fortran/use-mpi-f08/interface.in delete mode 100644 ompi/mpi/fortran/use-mpi-f08/profile/Makefile.am delete mode 100644 ompi/mpi/fortran/use-mpi-f08/profile/pcomm_create_from_group_f08.F90 delete mode 100644 ompi/mpi/fortran/use-mpi-f08/profile/pgroup_from_session_pset_f08.F90 delete mode 100644 ompi/mpi/fortran/use-mpi-f08/profile/pintercomm_create_from_groups_f08.F90 delete mode 100644 ompi/mpi/fortran/use-mpi-f08/profile/psession_finalize_f08.F90 delete mode 100644 ompi/mpi/fortran/use-mpi-f08/recv_f08.F90 delete mode 100644 ompi/mpi/fortran/use-mpi-f08/send_f08.F90 delete mode 100644 ompi/mpi/fortran/use-mpi-f08/waitall_f08.F90 diff --git a/.gitignore b/.gitignore index c1bfe01444a..65d4083ba4c 100644 --- a/.gitignore +++ b/.gitignore @@ -543,3 +543,11 @@ docs/schizo-ompi-rst-content # tarballs) docs/html docs/man + +# Generated C Bindings +ompi/mpi/c/ompi_*.c + +# Generated Fortran Bindings +ompi/mpi/fortran/use-mpi-f08/*_generated.F90 +ompi/mpi/fortran/use-mpi-f08/base/*_generated.c +ompi/mpi/fortran/use-mpi-f08/generate_bindings.py diff --git a/config/ompi_config_files.m4 b/config/ompi_config_files.m4 index 119d0ddabaf..b373cf83920 100644 --- a/config/ompi_config_files.m4 +++ b/config/ompi_config_files.m4 @@ -41,10 +41,10 @@ AC_DEFUN([OMPI_CONFIG_FILES],[ ompi/mpi/fortran/use-mpi-ignore-tkr/mpi-ignore-tkr-removed-interfaces.h ompi/mpi/fortran/use-mpi-f08/Makefile ompi/mpi/fortran/use-mpi-f08/base/Makefile - ompi/mpi/fortran/use-mpi-f08/profile/Makefile ompi/mpi/fortran/use-mpi-f08/bindings/Makefile ompi/mpi/fortran/use-mpi-f08/mod/Makefile ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces.h + ompi/mpi/fortran/use-mpi-f08/generate_bindings.py ompi/mpi/fortran/mpiext-use-mpi/Makefile ompi/mpi/fortran/mpiext-use-mpi-f08/Makefile ompi/mpi/tool/Makefile diff --git a/config/ompi_configure_options.m4 b/config/ompi_configure_options.m4 index 70353f0fe41..df507d03fce 100644 --- a/config/ompi_configure_options.m4 +++ b/config/ompi_configure_options.m4 @@ -244,5 +244,12 @@ else fi AM_CONDITIONAL(OMPI_OMPIO_SUPPORT, test "$ompi_want_ompio" = "1") +# If the binding source files don't exist, then we need Python to generate them +AM_PATH_PYTHON([3.6],,[:]) +binding_file="${srcdir}/ompi/mpi/c/ompi_send.c" +AS_IF([! test -e "$binding_file" && test "$PYTHON" = ":"], + [AC_MSG_ERROR([Open MPI requires Python >=3.6 for generating the bindings. Aborting])]) +AM_CONDITIONAL(OMPI_GENERATE_BINDINGS,[test "$PYTHON" != ":"]) + ])dnl diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index 0c26fa08d8f..ec642fb38f8 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -1389,7 +1389,7 @@ OMPI_DECLSPEC extern struct ompi_predefined_datatype_t ompi_mpi_ub; /* * MPI API */ - +#ifndef OMPI_NO_MPI_PROTOTYPES OMPI_DECLSPEC int MPI_Abort(MPI_Comm comm, int errorcode); OMPI_DECLSPEC int MPI_Accumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, @@ -1419,6 +1419,8 @@ OMPI_DECLSPEC int MPI_Alloc_mem(MPI_Aint size, MPI_Info info, void *baseptr); OMPI_DECLSPEC int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); +OMPI_DECLSPEC int MPI_Allreduce_c(const void *sendbuf, void *recvbuf, MPI_Count count, MPI_Datatype datatype, + MPI_Op op, MPI_Comm comm); OMPI_DECLSPEC int MPI_Iallreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int MPI_Allreduce_init(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, @@ -1774,10 +1776,14 @@ OMPI_DECLSPEC int MPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status); OMPI_DECLSPEC int MPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request); +OMPI_DECLSPEC int MPI_Irecv_c(void *buf, MPI_Count count, MPI_Datatype datatype, int source, + int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int MPI_Irsend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int MPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request); +OMPI_DECLSPEC int MPI_Isend_c(const void *buf, MPI_Count count, MPI_Datatype datatype, int dest, + int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int MPI_Isendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, @@ -1882,6 +1888,8 @@ OMPI_DECLSPEC int MPI_Recv_init(void *buf, int count, MPI_Datatype datatype, in int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status); +OMPI_DECLSPEC int MPI_Recv_c(void *buf, MPI_Count count, MPI_Datatype datatype, int source, + int tag, MPI_Comm comm, MPI_Status *status); OMPI_DECLSPEC int MPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm); OMPI_DECLSPEC int MPI_Ireduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, @@ -1957,6 +1965,8 @@ OMPI_DECLSPEC int MPI_Send_init(const void *buf, int count, MPI_Datatype dataty MPI_Request *request); OMPI_DECLSPEC int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); +OMPI_DECLSPEC int MPI_Send_c(const void *buf, MPI_Count count, MPI_Datatype datatype, int dest, + int tag, MPI_Comm comm); OMPI_DECLSPEC int MPI_Sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, @@ -2153,6 +2163,9 @@ OMPI_DECLSPEC int PMPI_Abort(MPI_Comm comm, int errorcode); OMPI_DECLSPEC int PMPI_Accumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, int target_rank, MPI_Aint target_disp, int target_count, MPI_Datatype target_datatype, MPI_Op op, MPI_Win win); +OMPI_DECLSPEC int PMPI_Accumulate_c(const void *origin_addr, MPI_Count origin_count, MPI_Datatype origin_datatype, + int target_rank, MPI_Aint target_disp, MPI_Count target_count, + MPI_Datatype target_datatype, MPI_Op op, MPI_Win win); OMPI_DECLSPEC int PMPI_Add_error_class(int *errorclass); OMPI_DECLSPEC int PMPI_Add_error_code(int errorclass, int *errorcode); OMPI_DECLSPEC int PMPI_Add_error_string(int errorcode, const char *string); @@ -2178,6 +2191,8 @@ OMPI_DECLSPEC int PMPI_Alloc_mem(MPI_Aint size, MPI_Info info, void *baseptr); OMPI_DECLSPEC int PMPI_Allreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); +OMPI_DECLSPEC int PMPI_Allreduce_c(const void *sendbuf, void *recvbuf, MPI_Count count, + MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); OMPI_DECLSPEC int PMPI_Iallreduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int PMPI_Allreduce_init(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, @@ -2535,10 +2550,14 @@ OMPI_DECLSPEC int PMPI_Iprobe(int source, int tag, MPI_Comm comm, int *flag, MPI_Status *status); OMPI_DECLSPEC int PMPI_Irecv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Irecv_c(void *buf, MPI_Count count, MPI_Datatype datatype, int source, + int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int PMPI_Irsend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int PMPI_Isend(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Request *request); +OMPI_DECLSPEC int PMPI_Isend_c(const void *buf, MPI_Count count, MPI_Datatype datatype, int dest, + int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int PMPI_Isendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, @@ -2643,6 +2662,8 @@ OMPI_DECLSPEC int PMPI_Recv_init(void *buf, int count, MPI_Datatype datatype, i int tag, MPI_Comm comm, MPI_Request *request); OMPI_DECLSPEC int PMPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status); +OMPI_DECLSPEC int PMPI_Recv_c(void *buf, MPI_Count count, MPI_Datatype datatype, int source, + int tag, MPI_Comm comm, MPI_Status *status); OMPI_DECLSPEC int PMPI_Reduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm); OMPI_DECLSPEC int PMPI_Ireduce(const void *sendbuf, void *recvbuf, int count, MPI_Datatype datatype, @@ -2718,6 +2739,8 @@ OMPI_DECLSPEC int PMPI_Send_init(const void *buf, int count, MPI_Datatype datat MPI_Request *request); OMPI_DECLSPEC int PMPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm); +OMPI_DECLSPEC int PMPI_Send_c(const void *buf, MPI_Count count, MPI_Datatype datatype, int dest, + int tag, MPI_Comm comm); OMPI_DECLSPEC int PMPI_Sendrecv(const void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, int recvtag, @@ -3176,6 +3199,8 @@ OMPI_DECLSPEC int PMPI_Type_ub(MPI_Datatype mtype, MPI_Aint *ub) #define MPI_Type_ub(...) THIS_FUNCTION_WAS_REMOVED_IN_MPI30(MPI_Type_ub, MPI_Type_get_extent) #endif +#endif /* OMPI_NO_MPI_PROTOTYPES */ + #if defined(c_plusplus) || defined(__cplusplus) } #endif diff --git a/ompi/mpi/c/Makefile.am b/ompi/mpi/c/Makefile.am index 8e7487a31a2..6fc08bc75eb 100644 --- a/ompi/mpi/c/Makefile.am +++ b/ompi/mpi/c/Makefile.am @@ -41,6 +41,36 @@ endif headers = bindings.h +prototype_sources = \ + abort.c.in \ + send.c.in \ + isend.c.in \ + recv.c.in \ + irecv.c.in \ + waitsome.c.in \ + accumulate.c.in \ + comm_f2c.c.in \ + wtime.c.in \ + file_open.c.in \ + init.c.in \ + finalize.c.in \ + comm_rank.c.in \ + comm_size.c.in \ + waitall.c.in \ + comm_split.c.in \ + comm_split_type.c.in \ + comm_free.c.in \ + finalized.c.in \ + initialized.c.in \ + allreduce.c.in \ + get_library_version.c.in \ + get_processor_name.c.in \ + barrier.c.in + +# Include script and template files in case someone wants to update the +# template files +EXTRA_DIST = generate_bindings.py $(prototype_sources) + # attr_fn.c contains attribute manipulation functions which do not # profiling implications, and so are always built. libmpi_c_la_SOURCES = \ @@ -60,7 +90,7 @@ endif # List of all C files that have profile versions # interface_profile_sources = \ - abort.c \ + ompi_abort.c \ add_error_class.c \ add_error_code.c \ add_error_string.c \ @@ -71,7 +101,7 @@ interface_profile_sources = \ iallgatherv.c \ allgatherv_init.c \ alloc_mem.c \ - allreduce.c \ + ompi_allreduce.c \ iallreduce.c \ allreduce_init.c \ alltoall.c \ @@ -86,7 +116,7 @@ interface_profile_sources = \ attr_delete.c \ attr_get.c \ attr_put.c \ - barrier.c \ + ompi_barrier.c \ ibarrier.c \ barrier_init.c \ bcast.c \ @@ -122,8 +152,8 @@ interface_profile_sources = \ comm_dup_with_info.c \ comm_idup.c \ comm_idup_with_info.c \ - comm_f2c.c \ - comm_free.c \ + ompi_comm_f2c.c \ + ompi_comm_free.c \ comm_free_keyval.c \ comm_get_attr.c \ comm_get_errhandler.c \ @@ -132,7 +162,7 @@ interface_profile_sources = \ comm_get_parent.c \ comm_group.c \ comm_join.c \ - comm_rank.c \ + ompi_comm_rank.c \ comm_remote_group.c \ comm_remote_size.c \ comm_set_attr.c \ @@ -143,11 +173,11 @@ interface_profile_sources = \ dist_graph_neighbors_count.c \ comm_set_errhandler.c \ comm_set_name.c \ - comm_size.c \ + ompi_comm_size.c \ comm_spawn.c \ comm_spawn_multiple.c \ - comm_split.c \ - comm_split_type.c \ + ompi_comm_split.c \ + ompi_comm_split_type.c \ comm_test_inter.c \ compare_and_swap.c \ dims_create.c \ @@ -187,7 +217,7 @@ interface_profile_sources = \ file_iwrite.c \ file_iwrite_all.c \ file_iwrite_shared.c \ - file_open.c \ + ompi_file_open.c \ file_preallocate.c \ file_read_all_begin.c \ file_read_all.c \ @@ -221,8 +251,8 @@ interface_profile_sources = \ file_write_ordered.c \ file_write_ordered_end.c \ file_write_shared.c \ - finalize.c \ - finalized.c \ + ompi_finalize.c \ + ompi_finalized.c \ free_mem.c \ gather.c \ igather.c \ @@ -235,8 +265,8 @@ interface_profile_sources = \ get_elements.c \ get_elements_x.c \ get_accumulate.c \ - get_library_version.c \ - get_processor_name.c \ + ompi_get_library_version.c \ + ompi_get_processor_name.c \ get_version.c \ graph_create.c \ graph_get.c \ @@ -277,17 +307,17 @@ interface_profile_sources = \ info_get_string.c \ info_get_valuelen.c \ info_set.c \ - init.c \ + ompi_init.c \ init_thread.c \ - initialized.c \ + ompi_initialized.c \ intercomm_create.c \ intercomm_create_from_groups.c \ intercomm_merge.c \ iprobe.c \ - irecv.c \ + ompi_irecv.c \ irsend.c \ is_thread_main.c \ - isend.c \ + ompi_isend.c \ isendrecv.c \ isendrecv_replace.c \ issend.c \ @@ -335,7 +365,7 @@ interface_profile_sources = \ query_thread.c \ raccumulate.c \ recv_init.c \ - recv.c \ + ompi_recv.c \ reduce.c \ ireduce.c \ reduce_init.c \ @@ -365,7 +395,6 @@ interface_profile_sources = \ scatterv.c \ iscatterv.c \ scatterv_init.c \ - send.c \ send_init.c \ sendrecv.c \ sendrecv_replace.c \ @@ -440,12 +469,12 @@ interface_profile_sources = \ unpack.c \ unpublish_name.c \ wait.c \ - waitall.c \ + ompi_waitall.c \ waitany.c \ - waitsome.c \ - wtime.c \ + ompi_waitsome.c \ + ompi_wtime.c \ wtick.c \ - accumulate.c \ + ompi_accumulate.c \ get.c \ put.c \ win_allocate.c \ @@ -486,6 +515,7 @@ interface_profile_sources = \ win_test.c \ win_unlock.c \ win_unlock_all.c \ + ompi_send.c \ win_wait.c # The following functions were removed from the MPI standard, but are @@ -509,3 +539,12 @@ libmpi_c_profile_la_CPPFLAGS = -DOMPI_BUILD_MPI_PROFILING=1 libmpi_c_noprofile_la_SOURCES = $(interface_profile_sources) libmpi_c_noprofile_la_CPPFLAGS = -DOMPI_BUILD_MPI_PROFILING=0 + +# ABI generation rules +if OMPI_GENERATE_BINDINGS +ompi_%.c: %.c.in generate_bindings.py + $(PYTHON) $(srcdir)/generate_bindings.py source ompi $< > $@ + +distclean-local: + -rm -rf ompi_*.c +endif diff --git a/ompi/mpi/c/abort.c b/ompi/mpi/c/abort.c.in similarity index 88% rename from ompi/mpi/c/abort.c rename to ompi/mpi/c/abort.c.in index 889fe1738b3..af43118d331 100644 --- a/ompi/mpi/c/abort.c +++ b/ompi/mpi/c/abort.c.in @@ -28,17 +28,7 @@ #include "ompi/memchecker.h" #include "ompi/communicator/communicator.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Abort = PMPI_Abort -#endif -#define MPI_Abort PMPI_Abort -#endif - -static const char FUNC_NAME[] = "MPI_Abort"; - - -int MPI_Abort(MPI_Comm comm, int errorcode) +PROTOTYPE ERROR_CLASS abort(COMM comm, INT errorcode) { MEMCHECKER( memchecker_comm(comm); diff --git a/ompi/mpi/c/accumulate.c b/ompi/mpi/c/accumulate.c.in similarity index 92% rename from ompi/mpi/c/accumulate.c rename to ompi/mpi/c/accumulate.c.in index a1e6bf91365..7a6b39bafd6 100644 --- a/ompi/mpi/c/accumulate.c +++ b/ompi/mpi/c/accumulate.c.in @@ -34,18 +34,9 @@ #include "ompi/datatype/ompi_datatype_internal.h" #include "ompi/memchecker.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Accumulate = PMPI_Accumulate -#endif -#define MPI_Accumulate PMPI_Accumulate -#endif - -static const char FUNC_NAME[] = "MPI_Accumulate"; - -int MPI_Accumulate(const void *origin_addr, int origin_count, MPI_Datatype origin_datatype, - int target_rank, MPI_Aint target_disp, int target_count, - MPI_Datatype target_datatype, MPI_Op op, MPI_Win win) +PROTOTYPE ERROR_CLASS accumulate(BUFFER origin_addr, COUNT origin_count, DATATYPE origin_datatype, + INT target_rank, AINT target_disp, COUNT target_count, + DATATYPE target_datatype, OP op, WIN win) { int rc; ompi_win_t *ompi_win = (ompi_win_t*) win; diff --git a/ompi/mpi/c/allreduce.c b/ompi/mpi/c/allreduce.c.in similarity index 92% rename from ompi/mpi/c/allreduce.c rename to ompi/mpi/c/allreduce.c.in index 9f2c5023cac..7d4e278bfdf 100644 --- a/ompi/mpi/c/allreduce.c +++ b/ompi/mpi/c/allreduce.c.in @@ -34,18 +34,8 @@ #include "ompi/memchecker.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Allreduce = PMPI_Allreduce -#endif -#define MPI_Allreduce PMPI_Allreduce -#endif - -static const char FUNC_NAME[] = "MPI_Allreduce"; - - -int MPI_Allreduce(const void *sendbuf, void *recvbuf, int count, - MPI_Datatype datatype, MPI_Op op, MPI_Comm comm) +PROTOTYPE ERROR_CLASS allreduce(BUFFER sendbuf, BUFFER_OUT recvbuf, COUNT count, + DATATYPE datatype, OP op, COMM comm) { int err; diff --git a/ompi/mpi/c/barrier.c b/ompi/mpi/c/barrier.c.in similarity index 91% rename from ompi/mpi/c/barrier.c rename to ompi/mpi/c/barrier.c.in index 35e629b0524..005abe6f4e0 100644 --- a/ompi/mpi/c/barrier.c +++ b/ompi/mpi/c/barrier.c.in @@ -28,17 +28,7 @@ #include "ompi/memchecker.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Barrier = PMPI_Barrier -#endif -#define MPI_Barrier PMPI_Barrier -#endif - -static const char FUNC_NAME[] = "MPI_Barrier"; - - -int MPI_Barrier(MPI_Comm comm) +PROTOTYPE ERROR_CLASS barrier(COMM comm) { int err = MPI_SUCCESS; diff --git a/ompi/mpi/c/comm_f2c.c b/ompi/mpi/c/comm_f2c.c.in similarity index 88% rename from ompi/mpi/c/comm_f2c.c rename to ompi/mpi/c/comm_f2c.c.in index a0bd6be2acb..0df53a1e2de 100644 --- a/ompi/mpi/c/comm_f2c.c +++ b/ompi/mpi/c/comm_f2c.c.in @@ -28,17 +28,7 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/mpi/fortran/base/fint_2_int.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Comm_f2c = PMPI_Comm_f2c -#endif -#define MPI_Comm_f2c PMPI_Comm_f2c -#endif - -static const char FUNC_NAME[] = "MPI_Comm_f2c"; - - -MPI_Comm MPI_Comm_f2c(MPI_Fint comm) +PROTOTYPE COMM comm_f2c(FINT comm) { int o_index= OMPI_FINT_2_INT(comm); diff --git a/ompi/mpi/c/comm_free.c b/ompi/mpi/c/comm_free.c.in similarity index 88% rename from ompi/mpi/c/comm_free.c rename to ompi/mpi/c/comm_free.c.in index f190011aabd..640865ade41 100644 --- a/ompi/mpi/c/comm_free.c +++ b/ompi/mpi/c/comm_free.c.in @@ -26,17 +26,7 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/memchecker.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Comm_free = PMPI_Comm_free -#endif -#define MPI_Comm_free PMPI_Comm_free -#endif - -static const char FUNC_NAME[] = "MPI_Comm_free"; - - -int MPI_Comm_free(MPI_Comm *comm) +PROTOTYPE ERROR_CLASS comm_free(COMM_OUT comm) { int ret; diff --git a/ompi/mpi/c/comm_rank.c b/ompi/mpi/c/comm_rank.c.in similarity index 87% rename from ompi/mpi/c/comm_rank.c rename to ompi/mpi/c/comm_rank.c.in index 8709d71f34d..5959e19422b 100644 --- a/ompi/mpi/c/comm_rank.c +++ b/ompi/mpi/c/comm_rank.c.in @@ -27,17 +27,7 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/memchecker.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Comm_rank = PMPI_Comm_rank -#endif -#define MPI_Comm_rank PMPI_Comm_rank -#endif - -static const char FUNC_NAME[] = "MPI_Comm_rank"; - - -int MPI_Comm_rank(MPI_Comm comm, int *rank) +PROTOTYPE ERROR_CLASS comm_rank(COMM comm, INT_OUT rank) { MEMCHECKER( memchecker_comm(comm); diff --git a/ompi/mpi/c/comm_size.c b/ompi/mpi/c/comm_size.c.in similarity index 87% rename from ompi/mpi/c/comm_size.c rename to ompi/mpi/c/comm_size.c.in index 2c9f0232f48..b3aefff6f74 100644 --- a/ompi/mpi/c/comm_size.c +++ b/ompi/mpi/c/comm_size.c.in @@ -29,17 +29,7 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/memchecker.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Comm_size = PMPI_Comm_size -#endif -#define MPI_Comm_size PMPI_Comm_size -#endif - -static const char FUNC_NAME[] = "MPI_Comm_size"; - - -int MPI_Comm_size(MPI_Comm comm, int *size) +PROTOTYPE ERROR_CLASS comm_size(COMM comm, INT_OUT size) { MEMCHECKER( memchecker_comm(comm); diff --git a/ompi/mpi/c/comm_split.c b/ompi/mpi/c/comm_split.c.in similarity index 89% rename from ompi/mpi/c/comm_split.c rename to ompi/mpi/c/comm_split.c.in index a55f0fa7204..0e25e798a19 100644 --- a/ompi/mpi/c/comm_split.c +++ b/ompi/mpi/c/comm_split.c.in @@ -28,18 +28,8 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/memchecker.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Comm_split = PMPI_Comm_split -#endif -#define MPI_Comm_split PMPI_Comm_split -#endif - -static const char FUNC_NAME[] = "MPI_Comm_split"; - - -int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm) { - +PROTOTYPE ERROR_CLASS comm_split(COMM comm, INT color, INT key, COMM_OUT newcomm) +{ int rc; MEMCHECKER( diff --git a/ompi/mpi/c/comm_split_type.c b/ompi/mpi/c/comm_split_type.c.in similarity index 92% rename from ompi/mpi/c/comm_split_type.c rename to ompi/mpi/c/comm_split_type.c.in index 3af3087eded..be277b35af9 100644 --- a/ompi/mpi/c/comm_split_type.c +++ b/ompi/mpi/c/comm_split_type.c.in @@ -32,19 +32,9 @@ #include "ompi/info/info.h" #include "ompi/memchecker.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Comm_split_type = PMPI_Comm_split_type -#endif -#define MPI_Comm_split_type PMPI_Comm_split_type -#endif - -static const char FUNC_NAME[] = "MPI_Comm_split_type"; - - -int MPI_Comm_split_type(MPI_Comm comm, int split_type, int key, - MPI_Info info, MPI_Comm *newcomm) { - +PROTOTYPE ERROR_CLASS comm_split_type(COMM comm, INT split_type, INT key, + INFO info, COMM_OUT newcomm) +{ int rc; MEMCHECKER( diff --git a/ompi/mpi/c/file_open.c b/ompi/mpi/c/file_open.c.in similarity index 92% rename from ompi/mpi/c/file_open.c rename to ompi/mpi/c/file_open.c.in index 204e92e9e44..0303ef4f970 100644 --- a/ompi/mpi/c/file_open.c +++ b/ompi/mpi/c/file_open.c.in @@ -39,18 +39,8 @@ extern opal_mutex_t ompi_mpi_file_bootstrap_mutex; -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_File_open = PMPI_File_open -#endif -#define MPI_File_open PMPI_File_open -#endif - -static const char FUNC_NAME[] = "MPI_File_open"; - - -int MPI_File_open(MPI_Comm comm, const char *filename, int amode, - MPI_Info info, MPI_File *fh) +PROTOTYPE ERROR_CLASS file_open(COMM comm, STRING filename, INT amode, + INFO info, FILE_OUT fh) { int rc; diff --git a/ompi/mpi/c/finalize.c b/ompi/mpi/c/finalize.c.in similarity index 86% rename from ompi/mpi/c/finalize.c rename to ompi/mpi/c/finalize.c.in index be7989261ba..a50fef2c5b0 100644 --- a/ompi/mpi/c/finalize.c +++ b/ompi/mpi/c/finalize.c.in @@ -25,17 +25,7 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Finalize = PMPI_Finalize -#endif -#define MPI_Finalize PMPI_Finalize -#endif - -static const char FUNC_NAME[] = "MPI_Finalize"; - - -int MPI_Finalize(void) +PROTOTYPE ERROR_CLASS finalize() { /* If --with-spc and ompi_mpi_spc_dump_enabled were specified, print * all of the final SPC values aggregated across the whole MPI run. diff --git a/ompi/mpi/c/finalized.c b/ompi/mpi/c/finalized.c.in similarity index 90% rename from ompi/mpi/c/finalized.c rename to ompi/mpi/c/finalized.c.in index 514e91b3b25..1a2934db784 100644 --- a/ompi/mpi/c/finalized.c +++ b/ompi/mpi/c/finalized.c.in @@ -28,17 +28,7 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/mca/hook/base/base.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Finalized = PMPI_Finalized -#endif -#define MPI_Finalized PMPI_Finalized -#endif - -static const char FUNC_NAME[] = "MPI_Finalized"; - - -int MPI_Finalized(int *flag) +PROTOTYPE ERROR_CLASS finalized(INT_OUT flag) { ompi_hook_base_mpi_finalized_top(flag); diff --git a/ompi/mpi/c/generate_bindings.py b/ompi/mpi/c/generate_bindings.py new file mode 100755 index 00000000000..f40986ff981 --- /dev/null +++ b/ompi/mpi/c/generate_bindings.py @@ -0,0 +1,1278 @@ +#!/usr/bin/env python3 +# Copyright (c) 2023 Triad National Security, LLC. All rights reserved. +# Copyright (c) 2023 Research Organization for Information Science +# and Technology (RIST). All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADERS$ +# +# +"""MPI Standard ABI Generation. + +TEMPLATE SOURCE FILE ASSUMPTIONS: +* Only one function per file +* Nothing (other than blank lines) after closing '}' +* Function prototype is preceded by PROTOTYPE +* All types in the function prototype are converted to one-word capital types + as defined here (to be later converted to ompi or standard ABI types) +* Functions requiring a bigcount implementation should have type COUNT in + place of MPI_Count or int for each count parameter. Bigcount functions will + be generated automatically for any function that includes a COUNT type. +""" +from abc import ABC, abstractmethod +import argparse +import re +import sys +import os + +# C type: const int +ERROR_CLASSES = [ + 'MPI_SUCCESS', + 'MPI_ERR_BUFFER', + 'MPI_ERR_COUNT', + 'MPI_ERR_TYPE', + 'MPI_ERR_TAG', + 'MPI_ERR_COMM', + 'MPI_ERR_RANK', + 'MPI_ERR_REQUEST', + 'MPI_ERR_ROOT', + 'MPI_ERR_GROUP', + 'MPI_ERR_OP', + 'MPI_ERR_TOPOLOGY', + 'MPI_ERR_DIMS', + 'MPI_ERR_ARG', + 'MPI_ERR_UNKNOWN', + 'MPI_ERR_TRUNCATE', + 'MPI_ERR_OTHER', + 'MPI_ERR_INTERN', + 'MPI_ERR_PENDING', + 'MPI_ERR_IN_STATUS', + 'MPI_ERR_ACCESS', + 'MPI_ERR_AMODE', + 'MPI_ERR_ASSERT', + 'MPI_ERR_BAD_FILE', + 'MPI_ERR_BASE', + 'MPI_ERR_CONVERSION', + 'MPI_ERR_DISP', + 'MPI_ERR_DUP_DATAREP', + 'MPI_ERR_FILE_EXISTS', + 'MPI_ERR_FILE_IN_USE', + 'MPI_ERR_FILE', + 'MPI_ERR_INFO_KEY', + 'MPI_ERR_INFO_NOKEY', + 'MPI_ERR_INFO_VALUE', + 'MPI_ERR_INFO', + 'MPI_ERR_IO', + 'MPI_ERR_KEYVAL', + 'MPI_ERR_LOCKTYPE', + 'MPI_ERR_NAME', + 'MPI_ERR_NO_MEM', + 'MPI_ERR_NOT_SAME', + 'MPI_ERR_NO_SPACE', + 'MPI_ERR_NO_SUCH_FILE', + 'MPI_ERR_PORT', + 'MPI_ERR_PROC_ABORTED', + 'MPI_ERR_QUOTA', + 'MPI_ERR_READ_ONLY', + 'MPI_ERR_RMA_ATTACH', + 'MPI_ERR_RMA_CONFLICT', + 'MPI_ERR_RMA_RANGE', + 'MPI_ERR_RMA_SHARED', + 'MPI_ERR_RMA_SYNC', + 'MPI_ERR_RMA_FLAVOR', + 'MPI_ERR_SERVICE', + 'MPI_ERR_SESSION', + 'MPI_ERR_SIZE', + 'MPI_ERR_SPAWN', + 'MPI_ERR_UNSUPPORTED_DATAREP', + 'MPI_ERR_UNSUPPORTED_OPERATION', + 'MPI_ERR_WIN', + 'MPI_T_ERR_CANNOT_INIT', + 'MPI_T_ERR_NOT_INITIALIZED', + 'MPI_T_ERR_MEMORY', + 'MPI_T_ERR_INVALID', + 'MPI_T_ERR_INVALID_INDEX', + 'MPI_T_ERR_INVALID_ITEM', + 'MPI_T_ERR_INVALID_SESSION', + 'MPI_T_ERR_INVALID_HANDLE', + 'MPI_T_ERR_INVALID_NAME', + 'MPI_T_ERR_OUT_OF_HANDLES', + 'MPI_T_ERR_OUT_OF_SESSIONS', + 'MPI_T_ERR_CVAR_SET_NOT_NOW', + 'MPI_T_ERR_CVAR_SET_NEVER', + 'MPI_T_ERR_PVAR_NO_WRITE', + 'MPI_T_ERR_PVAR_NO_STARTSTOP', + 'MPI_T_ERR_PVAR_NO_ATOMIC', + 'MPI_ERR_LASTCODE', +] + +PREDEFINED_DATATYPES = [ + 'MPI_CHAR', + 'MPI_SHORT', + 'MPI_INT', + 'MPI_LONG', + 'MPI_LONG_LONG_INT', + 'MPI_LONG_LONG', + 'MPI_SIGNED_CHAR', + 'MPI_UNSIGNED_CHAR', + 'MPI_UNSIGNED_SHORT', + 'MPI_UNSIGNED', + 'MPI_UNSIGNED_LONG', + 'MPI_UNSIGNED_LONG_LONG', + 'MPI_FLOAT', + 'MPI_DOUBLE', + 'MPI_LONG_DOUBLE', + 'MPI_WCHAR', + 'MPI_C_BOOL', + 'MPI_INT8_T', + 'MPI_INT16_T', + 'MPI_INT32_T', + 'MPI_INT64_T', + 'MPI_UINT8_T', + 'MPI_UINT16_T', + 'MPI_UINT32_T', + 'MPI_UINT64_T', + 'MPI_AINT', + 'MPI_COUNT', + 'MPI_OFFSET', + 'MPI_C_COMPLEX', + 'MPI_C_FLOAT_COMPLEX', + 'MPI_C_DOUBLE_COMPLEX', + 'MPI_C_LONG_DOUBLE_COMPLEX', + 'MPI_BYTE', + 'MPI_PACKED', + 'MPI_CXX_BOOL', + 'MPI_CXX_FLOAT_COMPLEX', + 'MPI_CXX_DOUBLE_COMPLEX', + 'MPI_CXX_LONG_DOUBLE_COMPLEX', + 'MPI_FLOAT_INT', + 'MPI_DOUBLE_INT', + 'MPI_LONG_INT', + 'MPI_2INT', + 'MPI_SHORT_INT', + 'MPI_LONG_DOUBLE_INT', +] + +# C type: MPI_Comm +RESERVED_COMMUNICATORS = [ + 'MPI_COMM_NULL', + 'MPI_COMM_WORLD', + 'MPI_COMM_SELF', +] + +COMMUNICATOR_SPLIT_TYPES = [ + 'MPI_COMM_TYPE_SHARED', + 'MPI_COMM_TYPE_HW_UNGUIDED', + 'MPI_COMM_TYPE_HW_GUIDED', +] + +RESERVED_WINDOWS = [ + 'MPI_WIN_NULL', +] + +RESERVED_REQUESTS = [ + 'MPI_REQUEST_NULL', +] + +RESERVED_INFOS = [ + 'MPI_INFO_ENV', + 'MPI_INFO_NULL', +] + +RESERVED_FILES = [ + 'MPI_FILE_NULL', +] + +IGNORED_STATUS_HANDLES = [ + 'MPI_STATUSES_IGNORE', + 'MPI_STATUS_IGNORE', +] + +COLLECTIVE_OPERATIONS = [ + 'MPI_MAX', + 'MPI_MIN', + 'MPI_SUM', + 'MPI_PROD', + 'MPI_MAXLOC', + 'MPI_MINLOC', + 'MPI_BAND', + 'MPI_BOR', + 'MPI_BXOR', + 'MPI_LAND', + 'MPI_LOR', + 'MPI_LXOR', + 'MPI_REPLACE', + 'MPI_NO_OP', +] + +VARIOUS_CONSTANTS = { + # Just setting this to the same as ompi ABI for right now, but will need to + # match the standard ABI value when defined + 'MPI_MAX_LIBRARY_VERSION_STRING': 256, + 'MPI_MAX_PROCESSOR_NAME': 256, +} + +# Types + +C_OPAQUE_TYPES = { + 'MPI_Aint': 'intptr_t', + 'MPI_Offset': 'int64_t', + 'MPI_Count': 'size_t', + # The below type needs to be set externally depending on Fortran compiler + 'MPI_Fint': 'int64_t', +} + +C_HANDLES = [ + 'MPI_Comm', + 'MPI_Datatype', + 'MPI_Errhandler', + 'MPI_File', + 'MPI_Group', + 'MPI_Info', + 'MPI_Message', + 'MPI_Op', + 'MPI_Request', + 'MPI_Session', + 'MPI_Win', +] + + +class ConvertFuncs: + """Names of conversion functions (between standard ABI and OMPI ABI).""" + + ERROR_CLASS = 'ompi_convert_intern_error_abi_error' + COMM = 'ompi_convert_abi_comm_intern_comm' + DATATYPE = 'ompi_convert_abi_datatype_intern_datatype' + REQUEST = 'ompi_convert_abi_request_intern_request' + STATUS = 'ompi_convert_intern_status_abi_status' + OP = 'ompi_convert_abi_op_intern_op' + WIN = 'ompi_convert_abi_win_intern_win' + INFO = 'ompi_convert_abi_info_intern_info' + FILE = 'ompi_convert_abi_file_intern_file' + + +class ConvertOMPIToStandard: + """Generated function for converting from OMPI to standard ABI.""" + + COMM = 'ompi_convert_comm_ompi_to_standard' + + +# Inline function attributes +INLINE_ATTRS = '__opal_attribute_always_inline__ static inline' + + +def mpi_fn_name_from_base_fn_name(name): + """Convert from a base name to the standard 'MPI_*' name.""" + return f'MPI_{name.capitalize()}' + + +def abi_internal_name(extname): + """Convert from the ABI external name to an internal name. + + Used to avoid conflicts with existing MPI names. + """ + return f'{extname}_ABI_INTERNAL' + + +class ABIHeaderBuilder: + """ABI header builder code.""" + + def __init__(self, prototypes, external=False, file=sys.stdout): + self.file = file + self.external = external + + if external: + mangle_name = lambda name: name + else: + mangle_name = abi_internal_name + + # Build up the list of standard ABI signatures + signatures = [] + for prototype in prototypes: + base_name = mpi_fn_name_from_base_fn_name(prototype.name) + signatures.append(prototype.signature('standard', base_name, + mangle_name=mangle_name)) + # Profiling prototype + signatures.append(prototype.signature('standard', f'P{base_name}', + mangle_name=mangle_name)) + if prototype.need_bigcount: + signatures.append(prototype.signature('standard', f'{base_name}_c', + count_type='MPI_Count', + mangle_name=mangle_name)) + # Profiling prototype + signatures.append(prototype.signature('standard', f'P{base_name}_c', + count_type='MPI_Count', + mangle_name=mangle_name)) + self.signatures = signatures + + def mangle_name(self, extname): + """Mangle names, depending on whether building external or internal header.""" + if self.external: + return extname + return abi_internal_name(extname) + + def dump(self, *pargs, **kwargs): + print(*pargs, **kwargs, file=self.file) + + def dump_lines(self, lines): + lines = indent_lines(lines, 4 * ' ', start=1) + for line in lines: + self.dump(line) + + def generate_error_convert_fn(self): + self.dump(f'{INLINE_ATTRS} int {ConvertFuncs.ERROR_CLASS}(int error_class)') + self.dump('{') + lines = [] + lines.append('switch (error_class) {') + for error in ERROR_CLASSES: + lines.append(f'case {self.mangle_name(error)}:') + lines.append(f'return {error};') + lines.append('default:') + lines.append('return error_class;') + lines.append('}') + self.dump_lines(lines) + self.dump('}') + + def generic_convert(self, fn_name, param_name, type_, value_names): + intern_type = self.mangle_name(type_) + self.dump(f'{INLINE_ATTRS} {type_} {fn_name}({intern_type} {param_name})') + self.dump('{') + lines = [] + for i, value_name in enumerate(value_names): + intern_name = self.mangle_name(value_name) + if i == 0: + lines.append('if (%s == %s) {' % (intern_name, param_name)) + else: + lines.append('} else if (%s == %s) {' % (intern_name, param_name)) + lines.append(f'return {value_name};') + lines.append('}') + lines.append(f'return ({type_}) {param_name};') + self.dump_lines(lines) + self.dump('}') + + def generic_convert_reverse(self, fn_name, param_name, type_, value_names): + intern_type = self.mangle_name(type_) + self.dump(f'{INLINE_ATTRS} {intern_type} {fn_name}({type_} {param_name})') + self.dump('{') + lines = [] + for i, value_name in enumerate(value_names): + intern_name = self.mangle_name(value_name) + if i == 0: + lines.append('if (%s == %s) {' % (value_name, param_name)) + else: + lines.append('} else if (%s == %s) {' % (value_name, param_name)) + lines.append(f'return {intern_name};') + lines.append('}') + lines.append(f'return ({intern_type}) {param_name};') + self.dump_lines(lines) + self.dump('}') + + def generate_comm_convert_fn(self): + self.generic_convert(ConvertFuncs.COMM, 'comm', 'MPI_Comm', RESERVED_COMMUNICATORS) + + def generate_comm_convert_fn_intern_to_abi(self): + self.generic_convert_reverse(ConvertOMPIToStandard.COMM, 'comm', 'MPI_Comm', RESERVED_COMMUNICATORS) + + def generate_info_convert_fn(self): + self.generic_convert(ConvertFuncs.INFO, 'info', 'MPI_Info', RESERVED_INFOS) + + def generate_file_convert_fn_intern_to_abi(self): + self.generic_convert_reverse(ConvertFuncs.FILE, 'file', 'MPI_File', RESERVED_FILES) + + def generate_datatype_convert_fn(self): + self.generic_convert(ConvertFuncs.DATATYPE, 'datatype', 'MPI_Datatype', PREDEFINED_DATATYPES) + + def generate_op_convert_fn(self): + self.generic_convert(ConvertFuncs.OP, 'op', 'MPI_Op', COLLECTIVE_OPERATIONS) + + def generate_win_convert_fn(self): + self.generic_convert(ConvertFuncs.WIN, 'win', 'MPI_Win', RESERVED_WINDOWS) + + def generate_pointer_convert_fn(self, type_, fn_name, constants): + abi_type = self.mangle_name(type_) + self.dump(f'{INLINE_ATTRS} void {fn_name}({abi_type} *ptr)') + self.dump('{') + lines = [] + for i, ompi_name in enumerate(constants): + abi_name = self.mangle_name(ompi_name) + if i == 0: + lines.append('if (%s == (%s) *ptr) {' % (ompi_name, type_)) + else: + lines.append('} else if (%s == (%s) *ptr) {' % (ompi_name, type_)) + lines.append(f'*ptr = {abi_name};') + lines.append('}') + self.dump_lines(lines) + self.dump('}') + + def generate_request_convert_fn(self): + self.generate_pointer_convert_fn('MPI_Request', ConvertFuncs.REQUEST, RESERVED_REQUESTS) + + def generate_file_convert_fn(self): + self.generate_pointer_convert_fn('MPI_File', ConvertFuncs.FILE, RESERVED_FILES) + + def generate_status_convert_fn(self): + type_ = 'MPI_Status' + abi_type = self.mangle_name(type_) + self.dump(f'{INLINE_ATTRS} void {ConvertFuncs.STATUS}({abi_type} *out, {type_} *inp)') + self.dump('{') + self.dump(' out->MPI_SOURCE = inp->MPI_SOURCE;') + self.dump(' out->MPI_TAG = inp->MPI_TAG;') + self.dump(f' out->MPI_ERROR = {ConvertFuncs.ERROR_CLASS}(inp->MPI_ERROR);') + # TODO: What to do with the private fields? + self.dump('}') + + def define(self, type_, name, value): + self.dump(f'#define {name} OMPI_CAST_CONSTANT({type_}, {value})') + + def define_all(self, type_, constants): + for i, const in enumerate(constants): + self.define(self.mangle_name(type_), self.mangle_name(const), i + 1) + self.dump() + + def dump_header(self): + header_guard = '_ABI_INTERNAL_' + self.dump(f'#ifndef {header_guard}') + self.dump(f'#define {header_guard}') + + self.dump('#include "stddef.h"') + self.dump('#include "stdint.h"') + + self.dump(""" +#if defined(c_plusplus) || defined(__cplusplus) +extern "C" { +#endif +""") + + self.dump(""" +#if defined(c_plusplus) || defined(__cplusplus) +#define OMPI_CAST_CONSTANT(type, value) (static_cast (static_cast (value))) +#else +#define OMPI_CAST_CONSTANT(type, value) ((type) ((void *) value)) +#endif +""") + + for i, err in enumerate(ERROR_CLASSES): + self.dump(f'#define {self.mangle_name(err)} {i + 1}') + self.dump() + + self.define_all('MPI_Datatype', PREDEFINED_DATATYPES) + self.define_all('MPI_Op', COLLECTIVE_OPERATIONS) + self.define_all('MPI_Comm', RESERVED_COMMUNICATORS) + self.define_all('MPI_Request', RESERVED_REQUESTS) + self.define_all('MPI_Win', RESERVED_WINDOWS) + self.define_all('MPI_Info', RESERVED_INFOS) + self.define_all('MPI_File', RESERVED_FILES) + + for name, value in VARIOUS_CONSTANTS.items(): + self.dump(f'#define {self.mangle_name(name)} {value}') + self.dump() + + status_type = self.mangle_name('MPI_Status') + for i, name in enumerate(IGNORED_STATUS_HANDLES): + self.define(f'{status_type} *', self.mangle_name(name), i + 1) + self.dump() + + for i, name in enumerate(COMMUNICATOR_SPLIT_TYPES): + self.dump(f'#define {self.mangle_name(name)} {i}') + self.dump() + + for mpi_type, c_type in C_OPAQUE_TYPES.items(): + self.dump(f'typedef {c_type} {self.mangle_name(mpi_type)};') + self.dump() + + for handle in C_HANDLES: + prefix, suffix = handle.split('_') + name = f'{prefix}_ABI_{suffix}' + self.dump(f'typedef struct {self.mangle_name(name)} *{self.mangle_name(handle)};') + self.dump() + self.dump(""" +struct MPI_Status_ABI { + int MPI_SOURCE; + int MPI_TAG; + int MPI_ERROR; + int mpi_abi_private[5]; +};""") + self.dump(f'typedef struct MPI_Status_ABI {self.mangle_name("MPI_Status")};') + self.dump() + # Function signatures + for sig in self.signatures: + self.dump(f'{sig};') + self.dump('int MPI_Abi_details(int *buflen, char *details, MPI_Info *info);') + self.dump('int MPI_Abi_supported(int *flag);') + self.dump('int MPI_Abi_version(int *abi_major, int *abi_minor);') + if not self.external: + # Now generate the conversion code + self.generate_error_convert_fn() + self.generate_comm_convert_fn() + self.generate_comm_convert_fn_intern_to_abi() + self.generate_info_convert_fn() + self.generate_file_convert_fn() + self.generate_datatype_convert_fn() + self.generate_op_convert_fn() + self.generate_win_convert_fn() + self.generate_request_convert_fn() + self.generate_status_convert_fn() + + self.dump(""" +#if defined(c_plusplus) || defined(__cplusplus) +} +#endif +""") + self.dump(f'#endif /* {header_guard} */') + + +class Parameter: + + def __init__(self, text): + """Parse a parameter.""" + # parameter in the form "TYPE NAME" or "TYPE NAME:COUNT_VAR" + type_, namecount = text.split() + if ':' in namecount: + name, count_param = namecount.split(':') + else: + name, count_param = namecount, None + self.type_ = type_ + self.name = name + self.count_param = count_param + + def construct(self, abi_type, **kwargs): + """Construct the type parameter for the given ABI.""" + return Type.construct(abi_type, type_=self.type_, name=self.name, + count_param=self.count_param, **kwargs) + + +class ReturnType: + """Return type wrapper.""" + + def __init__(self, type_): + self.type_ = type_ + + def construct(self, abi_type, **kwargs): + """Construct the return type for the given ABI.""" + return Type.construct(abi_type, type_=self.type_, **kwargs) + + +class Type(ABC): + """Type representation.""" + + PARAMS_OMPI_ABI = {} + + PARAMS_STANDARD_ABI = {} + + def __init__(self, type_, name=None, + mangle_name=lambda name: abi_internal_name(name), + count_param=None, **kwargs): + self.type = type_ + self.name = name + self.count_param = count_param + self.mangle_name = mangle_name + + @staticmethod + def construct(abi_type, type_, **kwargs): + """Construct the parameter for the given ABI and type.""" + if abi_type == 'ompi': + return Type.PARAMS_OMPI_ABI[type_](type_, **kwargs) + elif abi_type == 'standard': + return Type.PARAMS_STANDARD_ABI[type_](type_, **kwargs) + else: + raise RuntimeError(f'invalid ABI type {abi_type}') + + @staticmethod + def add_type(type_name, abi_type=('ompi', 'standard')): + """Add a new class corresponding to a type.""" + def wrapper(class_): + if 'ompi' in abi_type: + Type.PARAMS_OMPI_ABI[type_name] = class_ + if 'standard' in abi_type: + Type.PARAMS_STANDARD_ABI[type_name] = class_ + # Parameter.TYPES[type_] = class_ + return class_ + return wrapper + + @property + def is_count(self): + """Return True if this parameter is a count (requiring bigcount API).""" + return False + + @property + def init_code(self): + """Return the initialization code needed for an ABI wrapper.""" + return [] + + @property + def final_code(self): + """Return the finalization code needed for an ABI wrapper.""" + return [] + + def return_code(self, name): + """Process a value and then build up a return statement.""" + return [f'return {name};'] + + @property + def argument(self): + """Return the argument text required for passing an argument to a function.""" + return self.name + + @abstractmethod + def type_text(self, count_type=None): + """Return the source text corresponding to a type definition.""" + + def tmp_type_text(self, count_type=None): + """Return source text corresponding to a temporary type definition before conversion.""" + return self.type_text(count_type=count_type) + + def parameter(self, count_type=None, **kwargs): + return f'{self.type_text(count_type)} {self.name}' + + +@Type.add_type('ERROR_CLASS') +class TypeErrorClass(Type): + + def type_text(self, count_type=None): + return 'int' + + def return_code(self, name): + return [f'return {ConvertFuncs.ERROR_CLASS}({name});'] + + +@Type.add_type('BUFFER') +class TypeBuffer(Type): + + def type_text(self, count_type=None): + return 'const void *' + + +@Type.add_type('BUFFER_OUT') +class TypeBufferOut(Type): + + def type_text(self, count_type=None): + return f'void *' + + +@Type.add_type('COUNT') +class TypeCount(Type): + + @property + def is_count(self): + return True + + def type_text(self, count_type=None): + return 'int' if count_type is None else count_type + + +@Type.add_type('INT') +class TypeBufferOut(Type): + + def type_text(self, count_type=None): + return 'int' + + +@Type.add_type('AINT') +class TypeBufferOut(Type): + + def type_text(self, count_type=None): + return 'MPI_Aint' + + +@Type.add_type('INT_OUT') +class TypeBufferOut(Type): + + def type_text(self, count_type=None): + return 'int *' + + def parameter(self, count_type=None, **kwargs): + if self.count_param is None: + return f'int *{self.name}' + else: + return f'int {self.name}[]' + + +@Type.add_type('DOUBLE') +class TypeDouble(Type): + + def type_text(self, count_type=None): + return 'double' + + +@Type.add_type('ARGV') +class TypeArgv(Type): + + def type_text(self, count_type=None): + return 'char ***' + + +@Type.add_type('DATATYPE', abi_type=['ompi']) +class TypeDatatype(Type): + + def type_text(self, count_type=None): + return 'MPI_Datatype' + + +class StandardABIType(Type): + + @property + def tmpname(self): + return f'{self.name}_tmp' + + @property + def argument(self): + return self.tmpname + + +@Type.add_type('DATATYPE', abi_type=['standard']) +class TypeDatatype(StandardABIType): + + @property + def init_code(self): + return [f'MPI_Datatype {self.tmpname} = {ConvertFuncs.DATATYPE}({self.name});'] + + def type_text(self, count_type=None): + return self.mangle_name('MPI_Datatype') + + +@Type.add_type('OP', abi_type=['ompi']) +class TypeDatatype(Type): + + def type_text(self, count_type=None): + return 'MPI_Op' + + +@Type.add_type('OP', abi_type=['standard']) +class TypeDatatype(StandardABIType): + + @property + def init_code(self): + return [f'MPI_Op {self.tmpname} = {ConvertFuncs.OP}({self.name});'] + + def type_text(self, count_type=None): + return self.mangle_name('MPI_Op') + + +@Type.add_type('RANK') +class TypeRank(Type): + + def type_text(self, count_type=None): + return 'int' + + +@Type.add_type('TAG') +class TypeRank(Type): + + def type_text(self, count_type=None): + return 'int' + + +@Type.add_type('COMM', abi_type=['ompi']) +class TypeCommunicator(Type): + + def type_text(self, count_type=None): + return 'MPI_Comm' + + +@Type.add_type('COMM', abi_type=['standard']) +class TypeCommunicatorStandard(StandardABIType): + + @property + def init_code(self): + return [f'MPI_Comm {self.tmpname} = {ConvertFuncs.COMM}({self.name});'] + + def tmp_type_text(self, count_type=None): + return 'MPI_Comm' + + def return_code(self, name): + return [f'return {ConvertOMPIToStandard.COMM}({name});'] + + def type_text(self, count_type=None): + return self.mangle_name('MPI_Comm') + + +@Type.add_type('COMM_OUT', abi_type=['ompi']) +class TypeCommunicator(Type): + + def type_text(self, count_type=None): + return 'MPI_Comm *' + + +@Type.add_type('COMM_OUT', abi_type=['standard']) +class TypeCommunicator(Type): + + @property + def final_code(self): + return [f'*{self.name} = {ConvertOMPIToStandard.COMM}((MPI_Comm) *{self.name});'] + + def type_text(self, count_type=None): + type_name = self.mangle_name('MPI_Comm') + return f'{type_name} *' + + @property + def argument(self): + return f'(MPI_Comm *) {self.name}' + + +@Type.add_type('WIN', abi_type=['ompi']) +class TypeWindow(Type): + + def type_text(self, count_type=None): + return 'MPI_Win' + + +@Type.add_type('WIN', abi_type=['standard']) +class TypeWindowStandard(StandardABIType): + + @property + def init_code(self): + return [f'MPI_Win {self.tmpname} = {ConvertFuncs.WIN}({self.name});'] + + def type_text(self, count_type=None): + return self.mangle_name('MPI_Win') + + +@Type.add_type('REQUEST', abi_type=['ompi']) +class TypeRequest(Type): + + def type_text(self, count_type=None): + return 'MPI_Request' + + +@Type.add_type('REQUEST', abi_type=['standard']) +class TypeRequestStandard(Type): + + def type_text(self, count_type=None): + return self.mangle_name('MPI_Request') + + @property + def argument(self): + return f'(MPI_Request) {self.name}' + + +@Type.add_type('REQUEST_INOUT', abi_type=['ompi']) +class TypeRequestInOut(Type): + + def type_text(self, count_type=None): + return 'MPI_Request *' + + +@Type.add_type('REQUEST_INOUT', abi_type=['standard']) +class TypeRequestInOutStandard(Type): + + @property + def final_code(self): + if self.count_param is None: + return [f'{ConvertFuncs.REQUEST}({self.name});'] + else: + return [ + 'for (int i = 0; i < %s; ++i) {' % (self.count_param,), + f'{ConvertFuncs.REQUEST}(&{self.name}[i]);', + '}', + ] + + @property + def argument(self): + return f'(MPI_Request *) {self.name}' + + def type_text(self, count_type=None): + type_name = self.mangle_name('MPI_Request') + return f'{type_name} *' + + def parameter(self, count_type=None, **kwargs): + type_name = self.mangle_name('MPI_Request') + if self.count_param is None: + return f'{type_name} *{self.name}' + else: + return f'{type_name} {self.name}[]' + + +@Type.add_type('STATUS_OUT', abi_type=['ompi']) +class TypeStatusOut(Type): + + def type_text(self, count_type=None): + return 'MPI_Status *' + + def parameter(self, count_type=None, **kwargs): + if self.count_param is None: + return f'MPI_Status *{self.name}' + else: + return f'MPI_Status {self.name}[]' + + +@Type.add_type('STATUS_OUT', abi_type=['standard']) +class TypeStausOutStandard(StandardABIType): + + def if_should_set_status(self): + """Generate the condition to check if the status(es) should be set.""" + condition = ' && '.join(f'{self.mangle_name(const)} != {self.name}' + for const in IGNORED_STATUS_HANDLES) + return 'if (%s) {' % (condition,) + + @property + def status_argument(self): + return f'{self.name}_arg' + + @property + def init_code(self): + code = [f'MPI_Status *{self.status_argument} = NULL;'] + if self.count_param is None: + code.append(f'MPI_Status {self.tmpname};') + else: + code.append(f'MPI_Status *{self.tmpname} = NULL;') + code.append(self.if_should_set_status()) + if self.count_param is not None: + code.append(f'{self.tmpname} = malloc({self.count_param} * sizeof(MPI_Status));') + code.append(f'{self.status_argument} = {self.tmpname};') + else: + code.append(f'{self.status_argument} = &{self.tmpname};') + code.append('} else {') + if self.count_param is not None: + code.append(f'{self.status_argument} = MPI_STATUSES_IGNORE;') + else: + code.append(f'{self.status_argument} = MPI_STATUS_IGNORE;') + code.append('}') + return code + + @property + def final_code(self): + code = [self.if_should_set_status()] + if self.count_param is None: + code.append(f'{ConvertFuncs.STATUS}({self.name}, &{self.tmpname});') + else: + code.extend([ + 'for (int i = 0; i < %s; ++i) {' % (self.count_param,), + f'{ConvertFuncs.STATUS}(&{self.name}[i], &{self.tmpname}[i]);', + '}', + f'free({self.tmpname});', + ]) + code.append('}') + return code + + @property + def argument(self): + return self.status_argument + + def type_text(self, count_type=None): + type_name = self.mangle_name('MPI_Status') + return f'{type_name} *' + + def parameter(self, count_type=None, **kwargs): + type_name = self.mangle_name('MPI_Status') + if self.count_param is None: + return f'{type_name} *{self.name}' + else: + return f'{type_name} {self.name}[]' + + +# For now this just assumes that MPI_Fint doesn't need any conversions +@Type.add_type('FINT') +class TypeFint(Type): + + def type_text(self, count_type=None): + return 'MPI_Fint' + + +@Type.add_type('STRING') +class TypeString(Type): + + def type_text(self, count_type=None): + return 'const char *' + + +@Type.add_type('STRING_OUT') +class TypeStringOut(Type): + + def type_text(self, count_type=None): + return 'char *' + + +@Type.add_type('INFO', abi_type=['ompi']) +class TypeInfo(Type): + + def type_text(self, count_type=None): + return 'MPI_Info' + + +@Type.add_type('INFO', abi_type=['standard']) +class TypeInfoStandard(StandardABIType): + + @property + def init_code(self): + return [f'MPI_Info {self.tmpname} = {ConvertFuncs.INFO}({self.name});'] + + def type_text(self, count_type=None): + return self.mangle_name('MPI_Info') + + +@Type.add_type('FILE_OUT', abi_type=['ompi']) +class TypeFileOut(Type): + + def type_text(self, count_type=None): + return 'MPI_File *' + + +@Type.add_type('FILE_OUT', abi_type=['standard']) +class TypeFileOutStandard(Type): + + @property + def argument(self): + return f'(MPI_File *) {self.name}' + + @property + def final_code(self): + return [f'{ConvertFuncs.FILE}({self.name});'] + + def type_text(self, count_type=None): + type_name = self.mangle_name('MPI_File') + return f'{type_name} *' + + +class Prototype: + """MPI function prototype.""" + + def __init__(self, name, return_type, params): + self.name = name + self.return_type = return_type + self.params = params + + def signature(self, abi_type, fn_name, count_type=None, **kwargs): + """Build a signature with the given name and count_type.""" + params = ', '.join(param.construct(abi_type, **kwargs).parameter(count_type=count_type, **kwargs) + for param in self.params) + if not params: + params = 'void' + return_type_text = self.return_type.construct(abi_type, **kwargs).type_text(count_type=count_type) + return f'{return_type_text} {fn_name}({params})' + + @property + def need_bigcount(self): + """Check if a bigcount interface is required for a prototype.""" + return any('COUNT' in param.type_ for param in self.params) + + +class TemplateParseError(Exception): + """Error raised during parsing.""" + pass + + +def validate_body(body): + """Validate the body of a template.""" + # Just do a simple bracket balance test to determine the bounds of the + # function body. All lines after the function body should be blank. There + # are cases where this will break, such as if someone puts code all on one + # line. + bracket_balance = 0 + line_count = 0 + for line in body: + line = line.strip() + if bracket_balance == 0 and line_count > 0 and line: + raise TemplateParseError('Extra code found in template; only one function body is allowed') + + update = line.count('{') - line.count('}') + bracket_balance += update + if bracket_balance != 0: + line_count += 1 + + if bracket_balance != 0: + raise TemplateParseError('Mismatched brackets found in template') + + +class SourceTemplate: + """Source template for a single API function.""" + + def __init__(self, prototype, header, body): + self.prototype = prototype + self.header = header + self.body = body + + @staticmethod + def load(fname, prefix=None): + """Load a template file and return the SourceTemplate.""" + if prefix is not None: + fname = os.path.join(prefix, fname) + with open(fname) as fp: + header = [] + prototype = [] + body = [] + + for line in fp: + line = line.rstrip() + if prototype and line.startswith('PROTOTYPE'): + raise TemplateParseError('more than one prototype found in template file') + elif ((prototype and not any(')' in s for s in prototype)) + or line.startswith('PROTOTYPE')): + prototype.append(line) + elif prototype: + # Validate bracket balance + body.append(line) + else: + header.append(line) + + if not prototype: + raise RuntimeError('missing prototype') + # Parse the prototype + prototype = ''.join(prototype) + prototype = prototype[len('PROTOTYPE'):] + i = prototype.index('(') + j = prototype.index(')') + return_type, name = prototype[:i].split() + return_type = ReturnType(return_type) + params = [param.strip() for param in prototype[i + 1:j].split(',') if param.strip()] + params = [Parameter(param) for param in params] + prototype = Prototype(name, return_type, params) + # Ensure the body contains only one function + validate_body(body) + return SourceTemplate(prototype, header, body) + + def print_header(self, file=sys.stdout): + """Print the source header.""" + for line in self.header: + print(line, file=file) + + def print_body(self, func_name, file=sys.stdout): + """Print the body.""" + for line in self.body: + # FUNC_NAME is used for error messages + line = line.replace('FUNC_NAME', f'"{func_name}"') + print(line, file=file) + + +def print_profiling_header(fn_name, file=sys.stdout): + """Print the profiling header code.""" + print('#if OMPI_BUILD_MPI_PROFILING') + print('#if OPAL_HAVE_WEAK_SYMBOLS', file=file) + print(f'#pragma weak {fn_name} = P{fn_name}', file=file) + print('#endif', file=file) + print(f'#define {fn_name} P{fn_name}', file=file) + print('#endif') + + +def ompi_abi(base_name, template): + """Generate the OMPI ABI functions.""" + template.print_header() + print_profiling_header(base_name) + print(template.prototype.signature('ompi', base_name)) + template.print_body(func_name=base_name) + # Check if we need to generate the bigcount interface + if template.prototype.need_bigcount: + base_name_c = f'{base_name}_c' + print_profiling_header(base_name_c) + print(template.prototype.signature('ompi', base_name_c, count_type='MPI_Count')) + template.print_body(func_name=base_name_c) + + +ABI_INTERNAL_HEADER = 'ompi/mpi/c/abi.h' + + +def indent_lines(lines, tab, start=0): + """Crude pretty-printing function.""" + new_lines = [] + indent_count = start + for line in lines: + # Closing bracket + if '}' in line: + indent_count -= 1 + + prefix = indent_count * tab + new_lines.append(f'{prefix}{line}') + + # Opening bracket + if '{' in line: + indent_count += 1 + return new_lines + + +def standard_abi(base_name, template): + """Generate the standard ABI functions.""" + template.print_header() + print(f'#include "{ABI_INTERNAL_HEADER}"') + + # Static internal function (add a random component to avoid conflicts) + internal_name = f'ompi_abi_{template.prototype.name}' + internal_sig = template.prototype.signature('ompi', internal_name, + count_type='MPI_Count') + print(INLINE_ATTRS, internal_sig) + template.print_body(func_name=base_name) + + def generate_function(prototype, fn_name, internal_fn, count_type='int'): + """Generate a function for the standard ABI.""" + print_profiling_header(fn_name) + + # Handle type conversions and arguments + params = [param.construct('standard') for param in prototype.params] + print(prototype.signature('standard', fn_name, count_type=count_type)) + print('{') + lines = [] + return_type = prototype.return_type.construct('standard') + lines.append(f'{return_type.tmp_type_text()} ret_value;') + for param in params: + if param.init_code: + lines.extend(param.init_code) + pass_args = ', '.join(param.argument for param in params) + lines.append(f'ret_value = {internal_fn}({pass_args});') + for param in params: + if param.final_code: + lines.extend(param.final_code) + lines.extend(return_type.return_code('ret_value')) + + # Indent the lines + lines = indent_lines(lines, 4 * ' ', start=1) + for line in lines: + print(line) + print('}') + + generate_function(template.prototype, base_name, internal_name) + if template.prototype.need_bigcount: + base_name_c = f'{base_name}_c' + generate_function(template.prototype, base_name_c, internal_name, + count_type='MPI_Count') + + +def gen_header(args): + """Generate an ABI header and conversion code.""" + prototypes = [SourceTemplate.load(file_, args.srcdir).prototype for file_ in args.file] + + builder = ABIHeaderBuilder(prototypes, external=args.external) + builder.dump_header() + + +def gen_source(args): + """Generate source file.""" + template = SourceTemplate.load(args.source_file) + + base_name = mpi_fn_name_from_base_fn_name(template.prototype.name) + if args.type == 'ompi': + ompi_abi(base_name, template) + else: + standard_abi(base_name, template) + + +def main(): + if len(sys.argv) < 2: + # Fix required for Python 3.6 + print('ERROR: missing subparser argument (see --help)') + sys.exit(1) + + parser = argparse.ArgumentParser(description='generate ABI header file and conversion code') + subparsers = parser.add_subparsers() + + parser_header = subparsers.add_parser('header') + parser_header.add_argument('file', nargs='+', help='list of template source files') + parser_header.add_argument('--external', action='store_true', help='generate external mpi.h header file') + parser_header.add_argument('--srcdir', help='source directory') + parser_header.set_defaults(func=gen_header) + + parser_gen = subparsers.add_parser('source') + # parser = argparse.ArgumentParser(description='C ABI binding generation code') + parser_gen.add_argument('type', choices=('ompi', 'standard'), + help='generate the OMPI ABI functions or the standard ABI functions') + parser_gen.add_argument('source_file', help='source template file') + parser_gen.set_defaults(func=gen_source) + + args = parser.parse_args() + + # Always add the header + print('/* THIS FILE WAS AUTOGENERATED BY ompi/mpi/c/abi.py. DO NOT EDIT BY HAND. */') + args.func(args) + + +if __name__ == '__main__': + main() diff --git a/ompi/mpi/c/get_library_version.c b/ompi/mpi/c/get_library_version.c.in similarity index 93% rename from ompi/mpi/c/get_library_version.c rename to ompi/mpi/c/get_library_version.c.in index cb82d91c108..52da2059e39 100644 --- a/ompi/mpi/c/get_library_version.c +++ b/ompi/mpi/c/get_library_version.c.in @@ -27,17 +27,7 @@ #include "ompi/communicator/communicator.h" #include "ompi/errhandler/errhandler.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Get_library_version = PMPI_Get_library_version -#endif -#define MPI_Get_library_version PMPI_Get_library_version -#endif - -static const char FUNC_NAME[] = "MPI_Get_library_version"; - - -int MPI_Get_library_version(char *version, int *resultlen) +PROTOTYPE ERROR_CLASS get_library_version(STRING_OUT version, INT_OUT resultlen) { int len_left; char *ptr, tmp[MPI_MAX_LIBRARY_VERSION_STRING]; diff --git a/ompi/mpi/c/get_processor_name.c b/ompi/mpi/c/get_processor_name.c.in similarity index 87% rename from ompi/mpi/c/get_processor_name.c rename to ompi/mpi/c/get_processor_name.c.in index c76fd6dcdd3..d705c4d25a3 100644 --- a/ompi/mpi/c/get_processor_name.c +++ b/ompi/mpi/c/get_processor_name.c.in @@ -30,17 +30,7 @@ #include "ompi/communicator/communicator.h" #include "ompi/errhandler/errhandler.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Get_processor_name = PMPI_Get_processor_name -#endif -#define MPI_Get_processor_name PMPI_Get_processor_name -#endif - -static const char FUNC_NAME[] = "MPI_Get_processor_name"; - - -int MPI_Get_processor_name(char *name, int *resultlen) +PROTOTYPE ERROR_CLASS get_processor_name(STRING_OUT name, INT_OUT resultlen) { if ( MPI_PARAM_CHECK) { OMPI_ERR_INIT_FINALIZE(FUNC_NAME); diff --git a/ompi/mpi/c/init.c b/ompi/mpi/c/init.c.in similarity index 92% rename from ompi/mpi/c/init.c rename to ompi/mpi/c/init.c.in index eb5a50a7643..65a493e85a4 100644 --- a/ompi/mpi/c/init.c +++ b/ompi/mpi/c/init.c.in @@ -31,17 +31,7 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/constants.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Init = PMPI_Init -#endif -#define MPI_Init PMPI_Init -#endif - -static const char FUNC_NAME[] = "MPI_Init"; - - -int MPI_Init(int *argc, char ***argv) +PROTOTYPE INT init(INT_OUT argc, ARGV argv) { int err; int provided; diff --git a/ompi/mpi/c/initialized.c b/ompi/mpi/c/initialized.c.in similarity index 90% rename from ompi/mpi/c/initialized.c rename to ompi/mpi/c/initialized.c.in index 57f4e466243..e05e6ba2b4e 100644 --- a/ompi/mpi/c/initialized.c +++ b/ompi/mpi/c/initialized.c.in @@ -28,17 +28,7 @@ #include "ompi/errhandler/errhandler.h" #include "ompi/mca/hook/base/base.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Initialized = PMPI_Initialized -#endif -#define MPI_Initialized PMPI_Initialized -#endif - -static const char FUNC_NAME[] = "MPI_Initialized"; - - -int MPI_Initialized(int *flag) +PROTOTYPE ERROR_CLASS initialized(INT_OUT flag) { ompi_hook_base_mpi_initialized_top(flag); diff --git a/ompi/mpi/c/irecv.c b/ompi/mpi/c/irecv.c.in similarity index 89% rename from ompi/mpi/c/irecv.c rename to ompi/mpi/c/irecv.c.in index 7173282de18..1668e7aa7d4 100644 --- a/ompi/mpi/c/irecv.c +++ b/ompi/mpi/c/irecv.c.in @@ -30,18 +30,8 @@ #include "ompi/memchecker.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Irecv = PMPI_Irecv -#endif -#define MPI_Irecv PMPI_Irecv -#endif - -static const char FUNC_NAME[] = "MPI_Irecv"; - - -int MPI_Irecv(void *buf, int count, MPI_Datatype type, int source, - int tag, MPI_Comm comm, MPI_Request *request) +PROTOTYPE ERROR_CLASS irecv(BUFFER_OUT buf, COUNT count, DATATYPE type, + INT source, INT tag, COMM comm, REQUEST_INOUT request) { int rc = MPI_SUCCESS; diff --git a/ompi/mpi/c/isend.c b/ompi/mpi/c/isend.c.in similarity index 91% rename from ompi/mpi/c/isend.c rename to ompi/mpi/c/isend.c.in index 5cbcd36d0d7..595929ece2f 100644 --- a/ompi/mpi/c/isend.c +++ b/ompi/mpi/c/isend.c.in @@ -34,18 +34,8 @@ #include "ompi/memchecker.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Isend = PMPI_Isend -#endif -#define MPI_Isend PMPI_Isend -#endif - -static const char FUNC_NAME[] = "MPI_Isend"; - - -int MPI_Isend(const void *buf, int count, MPI_Datatype type, int dest, - int tag, MPI_Comm comm, MPI_Request *request) +PROTOTYPE ERROR_CLASS isend(BUFFER buf, COUNT count, DATATYPE type, INT dest, + INT tag, COMM comm, REQUEST_INOUT request) { int rc = MPI_SUCCESS; diff --git a/ompi/mpi/c/recv.c b/ompi/mpi/c/recv.c.in similarity index 91% rename from ompi/mpi/c/recv.c rename to ompi/mpi/c/recv.c.in index 6a36bcf1167..573e82a90b4 100644 --- a/ompi/mpi/c/recv.c +++ b/ompi/mpi/c/recv.c.in @@ -31,18 +31,8 @@ #include "ompi/request/request.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Recv = PMPI_Recv -#endif -#define MPI_Recv PMPI_Recv -#endif - -static const char FUNC_NAME[] = "MPI_Recv"; - - -int MPI_Recv(void *buf, int count, MPI_Datatype type, int source, - int tag, MPI_Comm comm, MPI_Status *status) +PROTOTYPE ERROR_CLASS recv(BUFFER_OUT buf, COUNT count, DATATYPE type, + INT source, INT tag, COMM comm, STATUS_OUT status) { int rc = MPI_SUCCESS; diff --git a/ompi/mpi/c/send.c b/ompi/mpi/c/send.c.in similarity index 91% rename from ompi/mpi/c/send.c rename to ompi/mpi/c/send.c.in index b21bba2c7bc..4b71b0bacf4 100644 --- a/ompi/mpi/c/send.c +++ b/ompi/mpi/c/send.c.in @@ -33,18 +33,8 @@ #include "ompi/memchecker.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Send = PMPI_Send -#endif -#define MPI_Send PMPI_Send -#endif - -static const char FUNC_NAME[] = "MPI_Send"; - - -int MPI_Send(const void *buf, int count, MPI_Datatype type, int dest, - int tag, MPI_Comm comm) +PROTOTYPE ERROR_CLASS send(BUFFER buf, COUNT count, DATATYPE type, RANK dest, + TAG tag, COMM comm) { int rc = MPI_SUCCESS; diff --git a/ompi/mpi/c/waitall.c b/ompi/mpi/c/waitall.c.in similarity index 92% rename from ompi/mpi/c/waitall.c rename to ompi/mpi/c/waitall.c.in index 14485de4e70..bedb80d9240 100644 --- a/ompi/mpi/c/waitall.c +++ b/ompi/mpi/c/waitall.c.in @@ -33,17 +33,8 @@ #include "ompi/memchecker.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Waitall = PMPI_Waitall -#endif -#define MPI_Waitall PMPI_Waitall -#endif - -static const char FUNC_NAME[] = "MPI_Waitall"; - - -int MPI_Waitall(int count, MPI_Request requests[], MPI_Status statuses[]) +PROTOTYPE ERROR_CLASS waitall(INT count, REQUEST_INOUT requests:count, + STATUS_OUT statuses:count) { SPC_RECORD(OMPI_SPC_WAITALL, 1); diff --git a/ompi/mpi/c/waitsome.c b/ompi/mpi/c/waitsome.c.in similarity index 91% rename from ompi/mpi/c/waitsome.c rename to ompi/mpi/c/waitsome.c.in index 169c7e10ec4..4828ba4999b 100644 --- a/ompi/mpi/c/waitsome.c +++ b/ompi/mpi/c/waitsome.c.in @@ -34,19 +34,9 @@ #include "ompi/memchecker.h" #include "ompi/runtime/ompi_spc.h" -#if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Waitsome = PMPI_Waitsome -#endif -#define MPI_Waitsome PMPI_Waitsome -#endif - -static const char FUNC_NAME[] = "MPI_Waitsome"; - - -int MPI_Waitsome(int incount, MPI_Request requests[], - int *outcount, int indices[], - MPI_Status statuses[]) +PROTOTYPE ERROR_CLASS waitsome(INT incount, REQUEST_INOUT requests:incount, + INT_OUT outcount, INT_OUT indices:incount, + STATUS_OUT statuses:incount) { SPC_RECORD(OMPI_SPC_WAITSOME, 1); diff --git a/ompi/mpi/c/wtime.c b/ompi/mpi/c/wtime.c.in similarity index 93% rename from ompi/mpi/c/wtime.c rename to ompi/mpi/c/wtime.c.in index b7918ad5d0d..3c2f88cbdfb 100644 --- a/ompi/mpi/c/wtime.c +++ b/ompi/mpi/c/wtime.c.in @@ -38,21 +38,18 @@ #include "opal/util/clock_gettime.h" #if OMPI_BUILD_MPI_PROFILING -#if OPAL_HAVE_WEAK_SYMBOLS -#pragma weak MPI_Wtime = PMPI_Wtime -#endif -#define MPI_Wtime PMPI_Wtime /** * Have a base time set on the first call to wtime, to improve the range * and accuracy of the user visible timer. * More info: https://github.com/mpi-forum/mpi-issues/issues/77#issuecomment-369663119 */ struct timespec ompi_wtime_time_origin = {.tv_sec = 0}; -#else /* OMPI_BUILD_MPI_PROFILING */ +#else extern struct timespec ompi_wtime_time_origin; #endif -double MPI_Wtime(void) + +PROTOTYPE DOUBLE wtime() { double wtime; diff --git a/ompi/mpi/fortran/use-mpi-f08/Makefile.am b/ompi/mpi/fortran/use-mpi-f08/Makefile.am index d788d56c2da..3f1fc831c45 100644 --- a/ompi/mpi/fortran/use-mpi-f08/Makefile.am +++ b/ompi/mpi/fortran/use-mpi-f08/Makefile.am @@ -23,8 +23,6 @@ # $HEADER$ # -SUBDIRS = profile - include $(top_srcdir)/Makefile.ompi-rules # Note that Automake's Fortran-buidling rules uses CPPFLAGS and @@ -45,14 +43,14 @@ AM_FCFLAGS = -I$(top_srcdir)/ompi/mpi/fortran/use-mpi-f08/mod \ $(OMPI_FC_MODULE_FLAG)$(top_builddir)/ompi/$(OMPI_FORTRAN_USEMPI_DIR) \ $(OMPI_FC_MODULE_FLAG)mod \ $(OMPI_FC_MODULE_FLAG)bindings \ - -I$(top_srcdir) -I$(top_builddir) $(FCFLAGS_f90) \ - -DOMPI_BUILD_MPI_PROFILING=0 + -I$(top_srcdir) -I$(top_builddir) $(FCFLAGS_f90) MOSTLYCLEANFILES = *.mod CLEANFILES += *.i90 lib_LTLIBRARIES = lib@OMPI_LIBMPI_NAME@_usempif08.la +noinst_LTLIBRARIES = lib@OMPI_LIBMPI_NAME@_usempif08_profile.la module_sentinel_files = \ mod/libforce_usempif08_internal_modules_to_be_built.la \ @@ -97,9 +95,9 @@ sizeof_f08.f90: --complex4=$(OMPI_HAVE_FORTRAN_COMPLEX4) \ --complex32=$(OMPI_HAVE_FORTRAN_COMPLEX32) -profile/psizeof_f08.f90: $(top_builddir)/config.status -profile/psizeof_f08.f90: $(sizeof_pl) -profile/psizeof_f08.f90: +psizeof_f08.f90: $(top_builddir)/config.status +psizeof_f08.f90: $(sizeof_pl) +psizeof_f08.f90: $(OMPI_V_GEN) $(sizeof_pl) \ --impl=$@ --ierror=optional --pmpi \ --maxrank=$(OMPI_FORTRAN_MAX_ARRAY_RANK) \ @@ -110,7 +108,7 @@ profile/psizeof_f08.f90: --complex4=$(OMPI_HAVE_FORTRAN_COMPLEX4) \ --complex32=$(OMPI_HAVE_FORTRAN_COMPLEX32) -CLEANFILES += sizeof_f08.h sizeof_f08.f90 profile/psizeof_f08.f90 +CLEANFILES += sizeof_f08.h sizeof_f08.f90 psizeof_f08.f90 mpi_api_files = \ abort_f08.F90 \ @@ -127,7 +125,6 @@ mpi_api_files = \ alloc_mem_f08.F90 \ allreduce_f08.F90 \ allreduce_init_f08.F90 \ - alltoall_f08.F90 \ alltoall_init_f08.F90 \ alltoallv_f08.F90 \ alltoallv_init_f08.F90 \ @@ -334,7 +331,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 \ @@ -342,7 +338,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 \ @@ -380,7 +375,6 @@ mpi_api_files = \ put_f08.F90 \ query_thread_f08.F90 \ raccumulate_f08.F90 \ - recv_f08.F90 \ recv_init_f08.F90 \ reduce_f08.F90 \ reduce_init_f08.F90 \ @@ -403,7 +397,6 @@ mpi_api_files = \ scatter_init_f08.F90 \ scatterv_f08.F90 \ scatterv_init_f08.F90 \ - send_f08.F90 \ send_init_f08.F90 \ sendrecv_f08.F90 \ sendrecv_replace_f08.F90 \ @@ -427,7 +420,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 \ @@ -468,7 +460,6 @@ mpi_api_files = \ unpack_external_f08.F90 \ unpack_f08.F90 \ unpublish_name_f08.F90 \ - waitall_f08.F90 \ waitany_f08.F90 \ wait_f08.F90 \ waitsome_f08.F90 \ @@ -508,28 +499,33 @@ mpi_api_files = \ win_test_f08.F90 \ win_unlock_f08.F90 \ win_unlock_all_f08.F90 \ - win_wait_f08.F90 + win_wait_f08.F90 \ + api_f08_generated.F90 # JMS Somehow this variable substitution isn't quite working, and I # don't have time to figure it out. So just wholesale copy the file # list. :-( -#pmpi_api_files = $(mpi_api_files:%=profile/p%) +#pmpi_api_files = $(mpi_api_files:%=p%) lib@OMPI_LIBMPI_NAME@_usempif08_la_SOURCES = \ $(mpi_api_files) \ mpi-f08.F90 # These are generated; do not ship them -nodist_lib@OMPI_LIBMPI_NAME@_usempif08_la_SOURCES = +# nodist_lib@OMPI_LIBMPI_NAME@_usempif08_la_SOURCES = if BUILD_FORTRAN_SIZEOF SIZEOF_H = sizeof_f08.h -nodist_lib@OMPI_LIBMPI_NAME@_usempif08_la_SOURCES += \ +lib@OMPI_LIBMPI_NAME@_usempif08_la_SOURCES += \ sizeof_f08.h \ sizeof_f08.f90 \ - profile/psizeof_f08.f90 + psizeof_f08.f90 endif +lib@OMPI_LIBMPI_NAME@_usempif08_la_FCFLAGS = \ + $(AM_FCFLAGS) \ + -DOMPI_BUILD_MPI_PROFILING=0 + # # Include the mpi_f08-based MPI extensions in libmpi_usempif08, too. # @@ -539,13 +535,19 @@ endif # lib@OMPI_LIBMPI_NAME@_usempif08_la_LIBADD = \ - profile/libmpi_usempif08_pmpi.la \ + lib@OMPI_LIBMPI_NAME@_usempif08_profile.la \ $(OMPI_MPIEXT_USEMPIF08_LIBS) \ $(top_builddir)/ompi/mpi/fortran/mpif-h/lib@OMPI_LIBMPI_NAME@_mpifh.la \ $(top_builddir)/ompi/lib@OMPI_LIBMPI_NAME@.la \ mod/libusempif08_internal_modules.la \ base/libusempif08_ccode.la -lib@OMPI_LIBMPI_NAME@_usempif08_la_DEPENDENCIES = $(module_sentinel_files) +# +# I'm not sure why, but the profile library is not getting built before this +# library even when listed in LIBADD, so adding it here as a dependency. +# +lib@OMPI_LIBMPI_NAME@_usempif08_la_DEPENDENCIES = \ + $(module_sentinel_files) \ + lib@OMPI_LIBMPI_NAME@_usempif08_profile.la lib@OMPI_LIBMPI_NAME@_usempif08_la_LDFLAGS = -version-info $(libmpi_usempif08_so_version) # @@ -558,6 +560,38 @@ mpi_api_lo_files = $(mpi_api_files:.F90=.lo) $(mpi_api_lo_files): bindings/libforce_usempif08_internal_bindings_to_be_built.la mpi-f08.lo: $(module_sentinel_files) $(SIZEOF_H) +mpi-f08.F90: $(SIZEOF_H) + +# +# Profiling interface +# + +lib@OMPI_LIBMPI_NAME@_usempif08_profile_la_SOURCES = \ + $(mpi_api_files) + +lib@OMPI_LIBMPI_NAME@_usempif08_profile_la_FCFLAGS = \ + $(AM_FCFLAGS) \ + -DOMPI_BUILD_MPI_PROFILING=1 + +MAINTAINERCLEANFILES = + +# Include script and template files for ABI generation from a distribution +# tarball +EXTRA_DIST = \ + generate_bindings.py \ + interface.in + +# +# Generate the Fortran bindings and C wrapper functions for bindings with a +# *.in template. +# + +if OMPI_GENERATE_BINDINGS +api_f08_generated.F90: interface.in generate_bindings.py + $(PYTHON) $(srcdir)/generate_bindings.py fortran $< > $@ + +MAINTAINERCLEANFILES += api_f08_generated.F90 +endif ########################################################################### diff --git a/ompi/mpi/fortran/use-mpi-f08/alltoall_f08.F90 b/ompi/mpi/fortran/use-mpi-f08/alltoall_f08.F90 deleted file mode 100644 index f201dd2f769..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/alltoall_f08.F90 +++ /dev/null @@ -1,32 +0,0 @@ -! -*- f90 -*- -! -! Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. -! Copyright (c) 2009-2012 Los Alamos National Security, LLC. -! All rights reserved. -! Copyright (c) 2018-2020 Research Organization for Information Science -! and Technology (RIST). All rights reserved. -! $COPYRIGHT$ - -#include "ompi/mpi/fortran/configure-fortran-output.h" - -#include "mpi-f08-rename.h" - -subroutine MPI_Alltoall_f08(sendbuf,sendcount,sendtype,recvbuf,& - recvcount,recvtype,comm,ierror) - use :: mpi_f08_types, only : MPI_Datatype, MPI_Comm - use :: ompi_mpifh_bindings, only : ompi_alltoall_f - implicit none - OMPI_FORTRAN_IGNORE_TKR_TYPE, INTENT(IN) :: sendbuf - OMPI_FORTRAN_IGNORE_TKR_TYPE :: recvbuf - INTEGER, INTENT(IN) :: sendcount, recvcount - TYPE(MPI_Datatype), INTENT(IN) :: sendtype - TYPE(MPI_Datatype), INTENT(IN) :: recvtype - TYPE(MPI_Comm), INTENT(IN) :: comm - INTEGER, OPTIONAL, INTENT(OUT) :: ierror - integer :: c_ierror - - call ompi_alltoall_f(sendbuf,sendcount,sendtype%MPI_VAL,recvbuf,& - recvcount,recvtype%MPI_VAL,comm%MPI_VAL,c_ierror) - if (present(ierror)) ierror = c_ierror - -end subroutine MPI_Alltoall_f08 diff --git a/ompi/mpi/fortran/use-mpi-f08/base/Makefile.am b/ompi/mpi/fortran/use-mpi-f08/base/Makefile.am index 7b62c571a4a..76ebb0aed41 100644 --- a/ompi/mpi/fortran/use-mpi-f08/base/Makefile.am +++ b/ompi/mpi/fortran/use-mpi-f08/base/Makefile.am @@ -31,6 +31,14 @@ if OMPI_BUILD_FORTRAN_USEMPIF08_BINDINGS noinst_LTLIBRARIES = libusempif08_ccode.la libusempif08_ccode_la_SOURCES = \ - buffer_detach.c + buffer_detach.c \ + api_f08_generated.c + +if OMPI_GENERATE_BINDINGS +api_f08_generated.c: ../interface.in $(srcdir)/../generate_bindings.py + $(PYTHON) $(srcdir)/../generate_bindings.py c $< > $@ + +MAINTAINERCLEANFILES = api_f08_generated.c +endif endif diff --git a/ompi/mpi/fortran/use-mpi-f08/generate_bindings.py.in b/ompi/mpi/fortran/use-mpi-f08/generate_bindings.py.in new file mode 100644 index 00000000000..37d0fdad8f7 --- /dev/null +++ b/ompi/mpi/fortran/use-mpi-f08/generate_bindings.py.in @@ -0,0 +1,781 @@ +# Copyright (c) 2023 Triad National Security, LLC. All rights +# reserved. +# +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# +"""Fortran binding generation code. + +This takes as input a *.in file containing a list of prototypes for Fortran +subroutines with generic types. Using this file, it can generate the Fortran +subroutines in one file and the C wraping code in another for all prototypes +listed. +""" +from abc import ABC, abstractmethod +import argparse +from collections import namedtuple +import re + +FORTRAN_ERROR_NAME = 'ierror' +C_ERROR_NAME = 'ierr' +C_ERROR_TMP_NAME = 'c_ierr' +GENERATED_MESSAGE = 'THIS FILE WAS AUTOMATICALLY GENERATED. DO NOT EDIT BY HAND.' +PROTOTYPE_RE = re.compile(r'^\w+\((\s*\w+\s+\w+(:\w+)?\s*,?)+\)$') + + +class FortranType(ABC): + + def __init__(self, name, fn_name, bigcount=False, **kwargs): + self.name = name + self.fn_name = fn_name + self.bigcount = bigcount + # A dependent type/parameter, such as a count + self.dep_param = None + self.used_counters = 0 + + TYPES = {} + + @classmethod + def add(cls, type_name): + """Decorator for adding types.""" + def wrapper(class_): + cls.TYPES[type_name] = class_ + return class_ + return wrapper + + @classmethod + def get(cls, type_name): + return cls.TYPES[type_name] + + @property + def fn_api_name(self): + """Return the MPI API name to be used in error messages, etc..""" + return c_api_func_name(self.fn_name, bigcount=self.bigcount).upper() + + @property + def tmp_name(self): + """Return a temporary name for use in C.""" + return f'c_{self.name}' + + @property + def tmp_name2(self): + """Return a secondary temporary name for use in C.""" + return f'c_{self.name}2' + + def tmp_counter(self): + """Get a temporary counter variable to be used in a loop.""" + name = f'{self.name}_i_{self.used_counters}' + self.used_counters += 1 + return name + + @abstractmethod + 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() + + def argument(self): + """Return the value to pass as an argument.""" + return self.name + + 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.""" + + def c_declare_tmp(self): + """Code to declare temporary variables for conversions, etc..""" + return [] + + def c_shortcut_condition(self): + """Shortcut conditional code. + + If the conditional evaluates to true in C, then code defined in + c_shortcut_code() for all other parameters will be run and the + underlying C function will not be called. + """ + return None + + def c_shortcut_code(self): + """Shortcut code to run if a parameter defines a shortcut condition.""" + return [] + + def c_prepare(self): + """Code to be called before being passed to underlying C function.""" + return [] + + def c_argument(self): + """Return the value to pass as an argument in the C code.""" + return self.name + + def c_post(self): + """Code to be run after a call to the underlying C function.""" + return [] + + +# +# Definitions of generic types in Fortran and how these can be converted +# to and from C. +# + + +@FortranType.add('BUFFER') +class BufferType(FortranType): + def declare(self): + return f'OMPI_FORTRAN_IGNORE_TKR_TYPE, INTENT(IN) :: {self.name}' + + def c_parameter(self): + return f'char *{self.name}' + + 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): + if self.bigcount: + return f'INTEGER(KIND=MPI_COUNT_KIND), INTENT(IN) :: {self.name}' + else: + return f'INTEGER, INTENT(IN) :: {self.name}' + + def use(self): + return [('mpi_f08_types', 'MPI_COUNT_KIND')] + + def c_parameter(self): + type_ = 'MPI_Count' if self.bigcount else 'MPI_Fint' + return f'{type_} *{self.name}' + + def c_argument(self): + return f'*{self.name}' if self.bigcount else f'OMPI_FINT_2_INT(*{self.name})' + + +@FortranType.add('DATATYPE') +class DatatypeType(FortranType): + def declare(self): + return f'TYPE(MPI_Datatype), INTENT(IN) :: {self.name}' + + def declare_cbinding_fortran(self): + return f'INTEGER, INTENT(IN) :: {self.name}' + + def argument(self): + return f'{self.name}%MPI_VAL' + + def use(self): + return [('mpi_f08_types', 'MPI_Datatype')] + + def c_parameter(self): + return f'MPI_Fint *{self.name}' + + def c_prepare(self): + return [f'MPI_Datatype {self.tmp_name} = PMPI_Type_f2c(*{self.name});'] + + def c_argument(self): + return self.tmp_name + + +@FortranType.add('INT') +class IntType(FortranType): + def declare(self): + return f'INTEGER, INTENT(IN) :: {self.name}' + + def c_parameter(self): + return f'MPI_Fint *{self.name}' + + def c_argument(self): + return f'OMPI_FINT_2_INT(*{self.name})' + + +@FortranType.add('RANK') +class RankType(IntType): + pass + + +@FortranType.add('TAG') +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): + return f'TYPE(MPI_Comm), INTENT(IN) :: {self.name}' + + def declare_cbinding_fortran(self): + return f'INTEGER, INTENT(IN) :: {self.name}' + + def argument(self): + return f'{self.name}%MPI_VAL' + + def use(self): + return [('mpi_f08_types', 'MPI_Comm')] + + def c_parameter(self): + return f'MPI_Fint *{self.name}' + + def c_prepare(self): + return [f'MPI_Comm {self.tmp_name} = PMPI_Comm_f2c(*{self.name});'] + + def c_argument(self): + return self.tmp_name + + +@FortranType.add('STATUS') +class StatusType(FortranType): + def declare(self): + return f'TYPE(MPI_Status), INTENT(OUT) :: {self.name}' + + def use(self): + return [('mpi_f08_types', 'MPI_Status')] + + 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_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_name + + def c_post(self): + return [f'OMPI_FORTRAN_STATUS_RETURN({self.tmp_name}, {self.tmp_name2}, {self.name}, {C_ERROR_TMP_NAME});'] + + +@FortranType.add('SHORTCUT_COUNT') +class ShortcutCountType(FortranType): + """Shortcut count type. + + This type is an integer that, when 0, can be used to shortcut a call to the + underyling C binding. Other types may implement a `c_shortcut` method that + will return code to execute upon a shortcut operation. + + The shortcut conditional is placed right after c temporary declarations but + before the c prepare code. + """ + + def declare(self): + return f'INTEGER, INTENT(IN) :: {self.name}' + + def c_parameter(self): + return f'MPI_Fint *{self.name}' + + def c_shortcut_condition(self): + return f'OPAL_UNLIKELY(0 == OMPI_FINT_2_INT(*{self.name}))' + + 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 [ + f'{name} = malloc({malloc_expr});', + f'if (NULL == {name}) {{', + f' {C_ERROR_TMP_NAME} = OMPI_ERRHANDLER_NOHANDLE_INVOKE(MPI_ERR_NO_MEM, "{fn_api_name}");', + f' *{C_ERROR_NAME} = OMPI_INT_2_FINT({C_ERROR_TMP_NAME});', + ' return;', + '}', + ] + + +@FortranType.add('REQUEST_ARRAY') +class RequestArrayType(FortranType): + def declare(self): + return f'TYPE(MPI_Request), INTENT(INOUT) :: {self.name}({self.dep_param.name})' + + def declare_cbinding_fortran(self): + return f'INTEGER, INTENT(INOUT) :: {self.name}({self.dep_param.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_prepare(self): + tmp_name = self.tmp_name + code = allocate_array(tmp_name, + f'{self.dep_param.c_argument()} * sizeof(MPI_Request)', + self.fn_api_name) + i = self.tmp_counter() + code.extend([ + f'for (int {i} = 0; {i} < {self.dep_param.c_argument()}; ++{i}) {{', + f' {tmp_name}[{i}] = PMPI_Request_f2c({self.name}[{i}]);', + '}', + ]) + return code + + def c_argument(self): + 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_name}[{i}]->req_f_to_c_index;', + ' }', + '}', + f'free({self.tmp_name});', + ] + + +@FortranType.add('STATUS_ARRAY') +class StatusArrayType(FortranType): + def declare(self): + return f'TYPE(MPI_Status), INTENT(OUT) :: {self.name}(*)' + + def use(self): + return [('mpi_f08_types', 'MPI_Status')] + + def c_parameter(self): + return f'MPI_Fint *{self.name}' + + def c_declare_tmp(self): + return [f'MPI_Status *{self.tmp_name};'] + + def c_prepare(self): + 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_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' if (!OMPI_IS_FORTRAN_STATUSES_IGNORE({self.name}) &&', + f' !OMPI_IS_FORTRAN_STATUS_IGNORE(&{self.name}[{i}])) {{', + f' PMPI_Status_c2f(&{self.tmp_name}[{i}], &{self.name}[{i} * (sizeof(MPI_Status) / sizeof(int))]);', + ' }', + ' }', + '}', + f'free({self.tmp_name});' + ] + + +class PrototypeParseError(Exception): + """Thrown when a parsing error is encountered.""" + + +def c_api_func_name(fn_name, bigcount=False): + """Produce the actual MPI API function name to call into.""" + suffix = '_c' if bigcount else '' + return f'MPI_{fn_name.capitalize()}{suffix}' + + +def c_api_func_name_profile(fn_name, bigcount=False): + """Produce the actual PMPI API function name to call into.""" + 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']) + + +def load_prototypes(fname): + """Load the prototypes from a file.""" + with open(fname) as fp: + prototypes = [] + for i, line in enumerate(fp): + lno = i + 1 + line = line.strip() + if line and line[0] == '#': + continue + if PROTOTYPE_RE.match(line) is None: + raise PrototypeParseError(f'Invalid function prototype for Fortran interface on line {lno}') + start = line.index('(') + end = line.index(')') + fn_name = line[:start].strip() + parameters = line[start+1:end].split(',') + parsed_parameters = [] + for param in parameters: + param = param.strip() + type_, name = param.split() + dep_name = None + # Check for 'param:other_param' parameters, indicating a + # dependency on that other parameter (such as for a count) + if ':' in name: + name, dep_name = name.split(':') + parsed_parameters.append(FortranParameter(type_, name, dep_name)) + prototypes.append(FortranPrototype(fn_name, parsed_parameters)) + return prototypes + + +class FortranBinding: + """Class for generating the binding for a single function.""" + + def __init__(self, prototype, bigcount=False): + self.bigcount = bigcount + self.fn_name = prototype.fn_name + self.parameters = [] + param_map = {} + dep_params = {} + for param in prototype.parameters: + type_ = FortranType.get(param.type_) + param_type = type_(param.name, self.fn_name, bigcount=bigcount) + self.parameters.append(param_type) + param_map[param.name] = param_type + if param.dep_name is not None: + dep_params[param.name] = param.dep_name + # Set dependent parameters for those that need them + for name, dep_name in dep_params.items(): + param_map[name].dep_param = param_map[dep_name] + + def _fn_name_suffix(self): + """Return a suffix for function names.""" + return '_c' if self.bigcount else '' + + @property + def c_func_name(self): + """Produce the final C func name from base_name.""" + return f'ompi_{self.fn_name}_wrapper_f08{self._fn_name_suffix()}' + + def _param_list(self): + return ','.join(type_.name for type_ in self.parameters) + + def _use(self): + """Determine the Fortran use-statements needed.""" + use = {} + for param in self.parameters: + for mod, name in param.use(): + if mod not in use: + use[mod] = set() + use[mod].add(name) + return use + + def _use_stmts(self): + """Return a list of required use statments.""" + use = self._use() + stmts = [] + for mod, names in use.items(): + names = ', '.join(names) + stmts.append(f'use :: {mod}, only: {names}') + return stmts + + def _print_fortran_interface(self): + """Output the C subroutine binding for the Fortran code.""" + name = self.c_func_name + print(' interface') + print(f' subroutine {name}({self._param_list()},{FORTRAN_ERROR_NAME}) &') + print(f' BIND(C, name="{name}")') + use_stmts = self._use_stmts() + for stmt in use_stmts: + print(f' {stmt}') + print(' implicit none') + for param in self.parameters: + print(f' {param.declare_cbinding_fortran()}') + print(f' INTEGER, INTENT(OUT) :: {FORTRAN_ERROR_NAME}') + print(f' end subroutine {name}') + print(' end interface') + + def print_f_source(self): + """Output the main MPI Fortran subroutine.""" + 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 + use_stmts = self._use_stmts() + for stmt in use_stmts: + print(f' {stmt}') + print(' implicit none') + # Parameters/dummy variable declarations + types = [] + for param in self.parameters: + print(f' {param.declare()}') + # Add the integer error manually + 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() + self._print_fortran_interface() + print() + + # Call into the C function + args = ','.join(param.argument() for param in self.parameters) + print(f' call {c_func}({args},{C_ERROR_TMP_NAME})') + # 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): + """Output the C source and function that the Fortran calls into.""" + parameters = [param.c_parameter() for param in self.parameters] + # Always append the integer error + parameters.append(f'MPI_Fint *{C_ERROR_NAME}') + parameters = ', '.join(parameters) + # Just put the signature here to silence `-Wmissing-prototypes` + c_func = self.c_func_name + print(f'void {c_func}({parameters});') + print(f'void {c_func}({parameters})') + print('{') + print(f' int {C_ERROR_TMP_NAME}; ') + + # First the temporary declarations + for param in self.parameters: + for line in param.c_declare_tmp(): + print(f' {line}') + + # Shortcut conditions, if any + for param in self.parameters: + condition = param.c_shortcut_condition() + if condition is None: + continue + print(f' if ({condition}) {{') + print(f' *{C_ERROR_NAME} = OMPI_INT_2_FINT(MPI_SUCCESS);') + 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. + for param in self.parameters: + for line in param.c_prepare(): + print(f' {line}') + + # Call into the C API + c_api_func = c_api_func_name_profile(self.fn_name, bigcount=self.bigcount) + arguments = [param.c_argument() for param in self.parameters] + arguments = ', '.join(arguments) + print(f' {C_ERROR_TMP_NAME} = {c_api_func}({arguments});') + + # Post-processing code + print(f' *{C_ERROR_NAME} = OMPI_INT_2_FINT({C_ERROR_TMP_NAME});') + for param in self.parameters: + for line in param.c_post(): + print(f' {line}') + print('}') + + +def print_f_source_header(): + """Print the fortran f08 file header.""" + print(f'! {GENERATED_MESSAGE}') + print('#include "ompi/mpi/fortran/configure-fortran-output.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(): + """Print the header of the C source file.""" + print(f'/* {GENERATED_MESSAGE} */') + print('#include "ompi_config.h"') + print('#include "mpi.h"') + print('#include "ompi/errhandler/errhandler.h"') + print('#include "ompi/mpi/fortran/mpif-h/status-conversion.h"') + print('#include "ompi/mpi/fortran/base/constants.h"') + print('#include "ompi/mpi/fortran/base/fint_2_int.h"') + print('#include "ompi/request/request.h"') + + +def print_binding(prototype, lang, bigcount=False): + """Print the binding with or without bigcount.""" + binding = FortranBinding(prototype, bigcount=bigcount) + if lang == 'fortran': + binding.print_f_source() + else: + binding.print_c_source() + + +def main(): + parser = argparse.ArgumentParser(description='generate fortran binding files') + parser.add_argument('lang', choices=('fortran', 'c'), + help='generate dependent files in C or Fortran') + parser.add_argument('template', help='template file to use') + parser.add_argument('--bigcount', action='store_true', + help='generate bigcount interface for function') + args = parser.parse_args() + + 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) + + +if __name__ == '__main__': + main() diff --git a/ompi/mpi/fortran/use-mpi-f08/interface.in b/ompi/mpi/fortran/use-mpi-f08/interface.in new file mode 100644 index 00000000000..3593fa81c8c --- /dev/null +++ b/ompi/mpi/fortran/use-mpi-f08/interface.in @@ -0,0 +1,20 @@ +# Copyright (c) 2023 Triad National Security, LLC. All rights +# reserved. +# +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# +# This file contains a list of prototypes to be used by 'generate_bindings.py' +# to generate Fortran subroutines and internal C functions that wrap the C MPI +# interface versions of each function. +# +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) +alltoall(BUFFER sendbuf, INT sendcount, DATATYPE sendtype, BUFFER recvbuf, INT recvcount, DATATYPE recvtype, COMM comm) diff --git a/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces.h.in b/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces.h.in index c66f92d1332..578b7cb3709 100644 --- a/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces.h.in +++ b/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-interfaces.h.in @@ -302,6 +302,18 @@ subroutine MPI_Recv_f08(buf,count,datatype,source,tag,comm,status,ierror) TYPE(MPI_Status) :: status INTEGER, OPTIONAL, INTENT(OUT) :: ierror end subroutine MPI_Recv_f08 +subroutine MPI_Recv_f08_c(buf,count,datatype,source,tag,comm,status,ierror) + use :: mpi_f08_types, only : MPI_Datatype, MPI_Comm, MPI_Status, MPI_COUNT_KIND + implicit none + @OMPI_FORTRAN_IGNORE_TKR_PREDECL@ buf + @OMPI_FORTRAN_IGNORE_TKR_TYPE@ :: buf + INTEGER(KIND=MPI_COUNT_KIND), INTENT(IN) :: count + INTEGER, INTENT(IN) :: source, tag + TYPE(MPI_Datatype), INTENT(IN) :: datatype + TYPE(MPI_Comm), INTENT(IN) :: comm + TYPE(MPI_Status) :: status + INTEGER, OPTIONAL, INTENT(OUT) :: ierror +end subroutine MPI_Recv_f08_c end interface MPI_Recv interface MPI_Recv_init @@ -376,6 +388,17 @@ subroutine MPI_Send_f08(buf,count,datatype,dest,tag,comm,ierror) TYPE(MPI_Comm), INTENT(IN) :: comm INTEGER, OPTIONAL, INTENT(OUT) :: ierror end subroutine MPI_Send_f08 +subroutine MPI_Send_f08_c(buf,count,datatype,dest,tag,comm,ierror) + use :: mpi_f08_types, only : MPI_Datatype, MPI_Comm, MPI_COUNT_KIND + implicit none + @OMPI_FORTRAN_IGNORE_TKR_PREDECL@ buf + @OMPI_FORTRAN_IGNORE_TKR_TYPE@, INTENT(IN) :: buf + INTEGER(KIND=MPI_COUNT_KIND), INTENT(IN) :: count + INTEGER, INTENT(IN) :: dest, tag + TYPE(MPI_Datatype), INTENT(IN) :: datatype + TYPE(MPI_Comm), INTENT(IN) :: comm + INTEGER, OPTIONAL, INTENT(OUT) :: ierror +end subroutine MPI_Send_f08_c end interface MPI_Send interface MPI_Sendrecv diff --git a/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-rename.h b/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-rename.h index 41e747e975c..14b396bcbb5 100644 --- a/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-rename.h +++ b/ompi/mpi/fortran/use-mpi-f08/mod/mpi-f08-rename.h @@ -49,6 +49,7 @@ #define MPI_Probe_f08 PMPI_Probe_f08 #define MPI_Recv PMPI_Recv #define MPI_Recv_f08 PMPI_Recv_f08 +#define MPI_Recv_f08_c PMPI_Recv_f08_c #define MPI_Recv_init PMPI_Recv_init #define MPI_Recv_init_f08 PMPI_Recv_init_f08 #define MPI_Request_free PMPI_Request_free @@ -61,6 +62,7 @@ #define MPI_Rsend_init_f08 PMPI_Rsend_init_f08 #define MPI_Send PMPI_Send #define MPI_Send_f08 PMPI_Send_f08 +#define MPI_Send_f08_c PMPI_Send_f08_c #define MPI_Sendrecv PMPI_Sendrecv #define MPI_Sendrecv_f08 PMPI_Sendrecv_f08 #define MPI_Sendrecv_replace PMPI_Sendrecv_replace diff --git a/ompi/mpi/fortran/use-mpi-f08/profile/Makefile.am b/ompi/mpi/fortran/use-mpi-f08/profile/Makefile.am deleted file mode 100644 index 13a6148ade7..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/profile/Makefile.am +++ /dev/null @@ -1,477 +0,0 @@ - -# -*- makefile.am -*- -# -# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana -# University Research and Technology -# Corporation. All rights reserved. -# Copyright (c) 2004-2013 The University of Tennessee and The University -# of Tennessee Research Foundation. All rights -# reserved. -# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart, -# University of Stuttgart. All rights reserved. -# Copyright (c) 2004-2005 The Regents of the University of California. -# All rights reserved. -# Copyright (c) 2009-2021 Cisco Systems, Inc. All rights reserved. -# Copyright (c) 2011 Sandia National Laboratories. All rights reserved. -# Copyright (c) 2012 Oak Ridge National Laboratory. All rights reserved. -# Copyright (c) 2012-2013 Inria. All rights reserved. -# Copyright (c) 2013 Los Alamos National Security, LLC. All rights -# reserved. -# Copyright (c) 2015-2021 Research Organization for Information Science -# and Technology (RIST). All rights reserved. -# Copyright (c) 2022 Triad National Security, LLC. All rights -# reserved. -# $COPYRIGHT$ -# -# Additional copyrights may follow -# -# $HEADER$ -# - -include $(top_srcdir)/Makefile.ompi-rules - -# Note that Automake's Fortran-buidling rules uses CPPFLAGS and -# AM_CPPFLAGS. This can cause weirdness (e.g., -# https://github.com/open-mpi/ompi/issues/7253). Let's just zero -# those out and rely on AM_FCFLAGS. -CPPFLAGS = -AM_CPPFLAGS = - -# This Makefile is only relevant if we're building the "use mpi_f08" -# MPI bindings. -if OMPI_BUILD_FORTRAN_USEMPIF08_BINDINGS - -AM_FCFLAGS = -I$(top_srcdir)/ompi/mpi/fortran/use-mpi-f08/mod \ - -I$(top_builddir)/ompi/include \ - -I$(top_srcdir)/ompi/include \ - $(OMPI_FC_MODULE_FLAG)$(top_builddir)/ompi/mpi/fortran/use-mpi \ - $(OMPI_FC_MODULE_FLAG)$(top_builddir)/ompi/$(OMPI_FORTRAN_USEMPI_DIR) \ - $(OMPI_FC_MODULE_FLAG)../mod \ - $(OMPI_FC_MODULE_FLAG)../bindings \ - -I$(top_srcdir) -I$(top_builddir) $(FCFLAGS_f90) \ - -DOMPI_BUILD_MPI_PROFILING=1 - -CLEANFILES += *.i90 - -noinst_LTLIBRARIES = libmpi_usempif08_pmpi.la - -pmpi_api_files = \ - pabort_f08.F90 \ - paccumulate_f08.F90 \ - padd_error_class_f08.F90 \ - padd_error_code_f08.F90 \ - padd_error_string_f08.F90 \ - paint_add_f08.F90 \ - paint_diff_f08.F90 \ - pallgather_f08.F90 \ - pallgather_init_f08.F90 \ - pallgatherv_f08.F90 \ - pallgatherv_init_f08.F90 \ - palloc_mem_f08.F90 \ - pallreduce_f08.F90 \ - palltoall_f08.F90 \ - palltoall_init_f08.F90 \ - palltoallv_f08.F90 \ - palltoallv_init_f08.F90 \ - palltoallw_f08.F90 \ - palltoallw_init_f08.F90 \ - pbarrier_f08.F90 \ - pbarrier_init_f08.F90 \ - pbcast_f08.F90 \ - pbcast_init_f08.F90 \ - pbsend_f08.F90 \ - pbsend_init_f08.F90 \ - pbuffer_attach_f08.F90 \ - pbuffer_detach_f08.F90 \ - pcancel_f08.F90 \ - pcart_coords_f08.F90 \ - pcart_create_f08.F90 \ - pcartdim_get_f08.F90 \ - pcart_get_f08.F90 \ - pcart_map_f08.F90 \ - pcart_rank_f08.F90 \ - pcart_shift_f08.F90 \ - pcart_sub_f08.F90 \ - pclose_port_f08.F90 \ - pcomm_accept_f08.F90 \ - pcomm_call_errhandler_f08.F90 \ - pcomm_compare_f08.F90 \ - pcomm_connect_f08.F90 \ - pcomm_create_from_group_f08.F90 \ - pcomm_create_errhandler_f08.F90 \ - pcomm_create_f08.F90 \ - pcomm_create_group_f08.F90 \ - pcomm_create_keyval_f08.F90 \ - pcomm_delete_attr_f08.F90 \ - pcomm_disconnect_f08.F90 \ - pcomm_dup_f08.F90 \ - pcomm_dup_with_info_f08.F90 \ - pcomm_idup_f08.F90 \ - pcomm_idup_with_info_f08.F90 \ - pcomm_free_f08.F90 \ - pcomm_free_keyval_f08.F90 \ - pcomm_get_attr_f08.F90 \ - pcomm_get_errhandler_f08.F90 \ - pcomm_get_info_f08.F90 \ - pcomm_get_name_f08.F90 \ - pcomm_get_parent_f08.F90 \ - pcomm_group_f08.F90 \ - pcomm_join_f08.F90 \ - pcomm_rank_f08.F90 \ - pcomm_remote_group_f08.F90 \ - pcomm_remote_size_f08.F90 \ - pcomm_set_attr_f08.F90 \ - pcomm_set_errhandler_f08.F90 \ - pcomm_set_info_f08.F90 \ - pcomm_set_name_f08.F90 \ - pcomm_size_f08.F90 \ - pcomm_spawn_f08.F90 \ - pcomm_spawn_multiple_f08.F90 \ - pcomm_split_f08.F90 \ - pcomm_split_type_f08.F90 \ - pcomm_test_inter_f08.F90 \ - pcompare_and_swap_f08.F90 \ - pdims_create_f08.F90 \ - pdist_graph_create_adjacent_f08.F90 \ - pdist_graph_create_f08.F90 \ - pdist_graph_neighbors_count_f08.F90 \ - pdist_graph_neighbors_f08.F90 \ - perrhandler_free_f08.F90 \ - perror_class_f08.F90 \ - perror_string_f08.F90 \ - pexscan_f08.F90 \ - pexscan_init_f08.F90 \ - pf_sync_reg_f08.F90 \ - pfetch_and_op_f08.F90 \ - pfile_call_errhandler_f08.F90 \ - pfile_close_f08.F90 \ - pfile_create_errhandler_f08.F90 \ - pfile_delete_f08.F90 \ - pfile_get_amode_f08.F90 \ - pfile_get_atomicity_f08.F90 \ - pfile_get_byte_offset_f08.F90 \ - pfile_get_errhandler_f08.F90 \ - pfile_get_group_f08.F90 \ - pfile_get_info_f08.F90 \ - pfile_get_position_f08.F90 \ - pfile_get_position_shared_f08.F90 \ - pfile_get_size_f08.F90 \ - pfile_get_type_extent_f08.F90 \ - pfile_get_view_f08.F90 \ - pfile_iread_at_f08.F90 \ - pfile_iread_f08.F90 \ - pfile_iread_at_all_f08.F90 \ - pfile_iread_all_f08.F90 \ - pfile_iread_shared_f08.F90 \ - pfile_iwrite_at_f08.F90 \ - pfile_iwrite_f08.F90 \ - pfile_iwrite_at_all_f08.F90 \ - pfile_iwrite_all_f08.F90 \ - pfile_iwrite_shared_f08.F90 \ - pfile_open_f08.F90 \ - pfile_preallocate_f08.F90 \ - pfile_read_all_begin_f08.F90 \ - pfile_read_all_end_f08.F90 \ - pfile_read_all_f08.F90 \ - pfile_read_at_all_begin_f08.F90 \ - pfile_read_at_all_end_f08.F90 \ - pfile_read_at_all_f08.F90 \ - pfile_read_at_f08.F90 \ - pfile_read_f08.F90 \ - pfile_read_ordered_begin_f08.F90 \ - pfile_read_ordered_end_f08.F90 \ - pfile_read_ordered_f08.F90 \ - pfile_read_shared_f08.F90 \ - pfile_seek_f08.F90 \ - pfile_seek_shared_f08.F90 \ - pfile_set_atomicity_f08.F90 \ - pfile_set_errhandler_f08.F90 \ - pfile_set_info_f08.F90 \ - pfile_set_size_f08.F90 \ - pfile_set_view_f08.F90 \ - pfile_sync_f08.F90 \ - pfile_write_all_begin_f08.F90 \ - pfile_write_all_end_f08.F90 \ - pfile_write_all_f08.F90 \ - pfile_write_at_all_begin_f08.F90 \ - pfile_write_at_all_end_f08.F90 \ - pfile_write_at_all_f08.F90 \ - pfile_write_at_f08.F90 \ - pfile_write_f08.F90 \ - pfile_write_ordered_begin_f08.F90 \ - pfile_write_ordered_end_f08.F90 \ - pfile_write_ordered_f08.F90 \ - pfile_write_shared_f08.F90 \ - pfinalized_f08.F90 \ - pfinalize_f08.F90 \ - pfree_mem_f08.F90 \ - pgather_f08.F90 \ - pgather_init_f08.F90 \ - pgatherv_f08.F90 \ - pgatherv_init_f08.F90 \ - pget_accumulate_f08.F90 \ - pget_address_f08.F90 \ - pget_count_f08.F90 \ - pget_elements_f08.F90 \ - pget_elements_x_f08.F90 \ - pget_f08.F90 \ - pget_library_version_f08.F90 \ - pget_processor_name_f08.F90 \ - pget_version_f08.F90 \ - pgraph_create_f08.F90 \ - pgraphdims_get_f08.F90 \ - pgraph_get_f08.F90 \ - pgraph_map_f08.F90 \ - pgraph_neighbors_count_f08.F90 \ - pgraph_neighbors_f08.F90 \ - pgrequest_complete_f08.F90 \ - pgrequest_start_f08.F90 \ - pgroup_compare_f08.F90 \ - pgroup_difference_f08.F90 \ - pgroup_excl_f08.F90 \ - pgroup_free_f08.F90 \ - pgroup_incl_f08.F90 \ - pgroup_intersection_f08.F90 \ - pgroup_range_excl_f08.F90 \ - pgroup_range_incl_f08.F90 \ - pgroup_rank_f08.F90 \ - pgroup_size_f08.F90 \ - pgroup_translate_ranks_f08.F90 \ - pgroup_union_f08.F90 \ - piallgather_f08.F90 \ - piallgatherv_f08.F90 \ - piallreduce_f08.F90 \ - pialltoall_f08.F90 \ - pialltoallv_f08.F90 \ - pialltoallw_f08.F90 \ - pibarrier_f08.F90 \ - pibcast_f08.F90 \ - pibsend_f08.F90 \ - pigather_f08.F90 \ - pigatherv_f08.F90 \ - piexscan_f08.F90 \ - pimprobe_f08.F90 \ - pimrecv_f08.F90 \ - pineighbor_allgather_f08.F90 \ - pineighbor_allgatherv_f08.F90 \ - pineighbor_alltoall_f08.F90 \ - pineighbor_alltoallv_f08.F90 \ - pineighbor_alltoallw_f08.F90 \ - pinfo_create_f08.F90 \ - pinfo_create_env_f08.F90 \ - pinfo_delete_f08.F90 \ - pinfo_dup_f08.F90 \ - pinfo_free_f08.F90 \ - pinfo_get_f08.F90 \ - pinfo_get_nkeys_f08.F90 \ - pinfo_get_nthkey_f08.F90 \ - pinfo_get_string_f08.F90 \ - pinfo_get_valuelen_f08.F90 \ - pinfo_set_f08.F90 \ - pinit_f08.F90 \ - pinitialized_f08.F90 \ - pinit_thread_f08.F90 \ - pintercomm_create_f08.F90 \ - pintercomm_create_from_groups_f08.F90 \ - pintercomm_merge_f08.F90 \ - piprobe_f08.F90 \ - pirecv_f08.F90 \ - pireduce_f08.F90 \ - pireduce_scatter_f08.F90 \ - pireduce_scatter_block_f08.F90 \ - pirsend_f08.F90 \ - piscan_f08.F90 \ - piscatter_f08.F90 \ - piscatterv_f08.F90 \ - pisend_f08.F90 \ - pisendrecv_f08.F90 \ - pisendrecv_replace_f08.F90 \ - pissend_f08.F90 \ - pis_thread_main_f08.F90 \ - plookup_name_f08.F90 \ - pmprobe_f08.F90 \ - pmrecv_f08.F90 \ - pneighbor_allgather_f08.F90 \ - pneighbor_allgather_init_f08.F90 \ - pneighbor_allgatherv_f08.F90 \ - pneighbor_allgatherv_init_f08.F90 \ - pneighbor_alltoall_f08.F90 \ - pneighbor_alltoall_init_f08.F90 \ - pneighbor_alltoallv_f08.F90 \ - pneighbor_alltoallv_init_f08.F90 \ - pneighbor_alltoallw_f08.F90 \ - pneighbor_alltoallw_init_f08.F90 \ - pop_commutative_f08.F90 \ - pop_create_f08.F90 \ - popen_port_f08.F90 \ - pop_free_f08.F90 \ - ppack_external_f08.F90 \ - ppack_external_size_f08.F90 \ - ppack_f08.F90 \ - ppack_size_f08.F90 \ - pparrived_f08.F90 \ - ppcontrol_f08.F90 \ - ppready_f08.F90 \ - ppready_list_f08.F90 \ - ppready_range_f08.F90 \ - pprobe_f08.F90 \ - ppsend_init_f08.F90 \ - ppublish_name_f08.F90 \ - pput_f08.F90 \ - pquery_thread_f08.F90 \ - praccumulate_f08.F90 \ - precv_f08.F90 \ - precv_init_f08.F90 \ - preduce_f08.F90 \ - preduce_init_f08.F90 \ - preduce_local_f08.F90 \ - preduce_scatter_f08.F90 \ - preduce_scatter_init_f08.F90 \ - preduce_scatter_block_f08.F90 \ - preduce_scatter_block_init_f08.F90 \ - pregister_datarep_f08.F90 \ - prequest_free_f08.F90 \ - prequest_get_status_f08.F90 \ - prget_f08.F90 \ - prget_accumulate_f08.F90 \ - prput_f08.F90 \ - prsend_f08.F90 \ - prsend_init_f08.F90 \ - pscan_f08.F90 \ - pscan_init_f08.F90 \ - pscatter_f08.F90 \ - pscatter_init_f08.F90 \ - pscatterv_f08.F90 \ - pscatterv_init_f08.F90 \ - psend_f08.F90 \ - psend_init_f08.F90 \ - psendrecv_f08.F90 \ - psendrecv_replace_f08.F90 \ - psession_create_errhandler_f08.F90\ - psession_get_errhandler_f08.F90\ - psession_get_info_f08.F90 \ - psession_get_nth_pset_f08.F90 \ - psession_get_num_psets_f08.F90 \ - psession_get_pset_info_f08.F90 \ - psession_init_f08.F90 \ - psession_finalize_f08.F90 \ - psession_set_errhandler_f08.F90\ - pssend_f08.F90 \ - pssend_init_f08.F90 \ - pstartall_f08.F90 \ - pstart_f08.F90 \ - pstatus_f082f_f08.F90 \ - pstatus_f2f08_f08.F90 \ - pstatus_set_cancelled_f08.F90 \ - pstatus_set_elements_f08.F90 \ - pstatus_set_elements_x_f08.F90 \ - ptestall_f08.F90 \ - ptestany_f08.F90 \ - ptest_cancelled_f08.F90 \ - ptest_f08.F90 \ - ptestsome_f08.F90 \ - ptopo_test_f08.F90 \ - ptype_commit_f08.F90 \ - ptype_contiguous_f08.F90 \ - ptype_create_darray_f08.F90 \ - ptype_create_f90_complex_f08.F90 \ - ptype_create_f90_integer_f08.F90 \ - ptype_create_f90_real_f08.F90 \ - ptype_create_hindexed_f08.F90 \ - ptype_create_hvector_f08.F90 \ - ptype_create_indexed_block_f08.F90 \ - ptype_create_hindexed_block_f08.F90 \ - ptype_create_keyval_f08.F90 \ - ptype_create_resized_f08.F90 \ - ptype_create_struct_f08.F90 \ - ptype_create_subarray_f08.F90 \ - ptype_delete_attr_f08.F90 \ - ptype_dup_f08.F90 \ - ptype_free_f08.F90 \ - ptype_free_keyval_f08.F90 \ - ptype_get_attr_f08.F90 \ - ptype_get_contents_f08.F90 \ - ptype_get_envelope_f08.F90 \ - ptype_get_extent_f08.F90 \ - ptype_get_extent_x_f08.F90 \ - ptype_get_name_f08.F90 \ - ptype_get_true_extent_f08.F90 \ - ptype_get_true_extent_x_f08.F90 \ - ptype_indexed_f08.F90 \ - ptype_match_size_f08.F90 \ - ptype_set_attr_f08.F90 \ - ptype_set_name_f08.F90 \ - ptype_size_f08.F90 \ - ptype_size_x_f08.F90 \ - ptype_vector_f08.F90 \ - punpack_external_f08.F90 \ - punpack_f08.F90 \ - punpublish_name_f08.F90 \ - pwaitall_f08.F90 \ - pwaitany_f08.F90 \ - pwait_f08.F90 \ - pwaitsome_f08.F90 \ - pwin_allocate_f08.F90 \ - pwin_allocate_shared_f08.F90 \ - pwin_attach_f08.F90 \ - pwin_call_errhandler_f08.F90 \ - pwin_complete_f08.F90 \ - pwin_create_dynamic_f08.F90 \ - pwin_create_errhandler_f08.F90 \ - pwin_create_f08.F90 \ - pwin_create_keyval_f08.F90 \ - pwin_delete_attr_f08.F90 \ - pwin_detach_f08.F90 \ - pwin_fence_f08.F90 \ - pwin_flush_f08.F90 \ - pwin_flush_all_f08.F90 \ - pwin_flush_local_f08.F90 \ - pwin_flush_local_all_f08.F90 \ - pwin_free_f08.F90 \ - pwin_free_keyval_f08.F90 \ - pwin_get_attr_f08.F90 \ - pwin_get_errhandler_f08.F90 \ - pwin_get_group_f08.F90 \ - pwin_get_info_f08.F90 \ - pwin_get_name_f08.F90 \ - pwin_lock_f08.F90 \ - pwin_lock_all_f08.F90 \ - pwin_post_f08.F90 \ - pwin_set_attr_f08.F90 \ - pwin_set_errhandler_f08.F90 \ - pwin_set_info_f08.F90 \ - pwin_set_name_f08.F90 \ - pwin_shared_query_f08.F90 \ - pwin_start_f08.F90 \ - pwin_sync_f08.F90 \ - pwin_test_f08.F90 \ - pwin_unlock_f08.F90 \ - pwin_unlock_all_f08.F90 \ - pwin_wait_f08.F90 - -# -# Automake doesn't do Fortran dependency analysis, so must list them -# manually here. Bummer! -# - -pmpi_api_lo_files = $(pmpi_api_files:.F90=.lo) - -$(pmpi_api_lo_files): ../bindings/libforce_usempif08_internal_bindings_to_be_built.la - -nodist_libmpi_usempif08_pmpi_la_SOURCES = \ - $(pmpi_api_files) - -# -# Sym link in the sources from the real MPI directory -# -$(nodist_libmpi_usempif08_pmpi_la_SOURCES): - $(OMPI_V_LN_S) if test ! -r $@ ; then \ - pname=`echo $@ | cut -b '2-'` ; \ - $(LN_S) $(top_srcdir)/ompi/mpi/fortran/use-mpi-f08/$$pname $@ ; \ - fi - -# These files were created by targets above - -MAINTAINERCLEANFILES = $(nodist_libmpi_usempif08_pmpi_la_SOURCES) - -endif diff --git a/ompi/mpi/fortran/use-mpi-f08/profile/pcomm_create_from_group_f08.F90 b/ompi/mpi/fortran/use-mpi-f08/profile/pcomm_create_from_group_f08.F90 deleted file mode 100644 index 84098a44dc2..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/profile/pcomm_create_from_group_f08.F90 +++ /dev/null @@ -1,29 +0,0 @@ -! -*- f90 -*- -! -! Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. -! Copyright (c) 2009-2013 Los Alamos National Security, LLC. -! All rights reserved. -! Copyright (c) 2018 Research Organization for Information Science -! and Technology (RIST). All rights reserved. -! Copyright (c) 2019 Triad National Security, LLC. All rights -! reserved. -! $COPYRIGHT$ - -subroutine PMPI_Comm_create_from_group_f08(group, stringtag, info, errhandler, newcomm, ierror) - use :: mpi_f08_types, only : MPI_Session, MPI_Group, MPI_Errhandler, MPI_Info, MPI_Comm - use :: ompi_mpifh_bindings, only : ompi_comm_create_from_group_f - implicit none - TYPE(MPI_Group), INTENT(IN) :: group - CHARACTER(LEN=*), INTENT(IN) :: stringtag - TYPE(MPI_Info), INTENT(IN) :: info - TYPE(MPI_Errhandler), INTENT(IN) :: errhandler - TYPE(MPI_Comm), INTENT(OUT) :: newcomm - INTEGER, OPTIONAL, INTENT(OUT) :: ierror - integer :: c_ierror - - call ompi_comm_create_from_group_f(group%MPI_VAL, stringtag, info%MPI_VAL, errhandler%MPI_VAL, & - newcomm%MPI_VAL, c_ierror, len(stringtag)) - if (present(ierror)) ierror = c_ierror - -end subroutine PMPI_Comm_create_from_group_f08 - diff --git a/ompi/mpi/fortran/use-mpi-f08/profile/pgroup_from_session_pset_f08.F90 b/ompi/mpi/fortran/use-mpi-f08/profile/pgroup_from_session_pset_f08.F90 deleted file mode 100644 index a719b361302..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/profile/pgroup_from_session_pset_f08.F90 +++ /dev/null @@ -1,29 +0,0 @@ -! -*- f90 -*- -! -! Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. -! Copyright (c) 2009-2013 Los Alamos National Security, LLC. -! All rights reserved. -! Copyright (c) 2018 Research Organization for Information Science -! and Technology (RIST). All rights reserved. -! Copyright (c) 2019-2021 Triad National Security, LLC. All rights -! reserved. -! $COPYRIGHT$ - -#include "ompi/mpi/fortran/configure-fortran-output.h" -#include "mpi-f08-rename.h" - -subroutine PMPI_Group_from_session_pset_f08(session, pset_name, newgroup, ierror) - use :: mpi_f08_types, only : MPI_Session, MPI_Group - use :: ompi_mpifh_bindings, only : ompi_group_from_session_pset_f - implicit none - TYPE(MPI_Session), INTENT(IN) :: session - CHARACTER(LEN=*), INTENT(IN) :: pset_name - TYPE(MPI_Group), INTENT(OUT) :: newgroup - INTEGER, OPTIONAL, INTENT(OUT) :: ierror - integer :: c_ierror - - call ompi_group_from_session_pset_f(session%MPI_VAL, pset_name, newgroup%MPI_VAL, c_ierror, len(pset_name)) - if (present(ierror)) ierror = c_ierror - -end subroutine PMPI_Group_from_session_pset_f08 - diff --git a/ompi/mpi/fortran/use-mpi-f08/profile/pintercomm_create_from_groups_f08.F90 b/ompi/mpi/fortran/use-mpi-f08/profile/pintercomm_create_from_groups_f08.F90 deleted file mode 100644 index 668188d1adb..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/profile/pintercomm_create_from_groups_f08.F90 +++ /dev/null @@ -1,35 +0,0 @@ -! -*- f90 -*- -! -! Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. -! Copyright (c) 2009-2013 Los Alamos National Security, LLC. -! All rights reserved. -! Copyright (c) 2018 Research Organization for Information Science -! and Technology (RIST). All rights reserved. -! Copyright (c) 2019 Triad National Security, LLC. All rights -! reserved. -! $COPYRIGHT$ - -subroutine PMPI_Intercomm_create_from_groups_f08(local_group, local_leader, remote_group, & - remote_leader, stringtag, info, errhandler, & - newintercomm, ierror) - use :: mpi_f08_types, only : MPI_Comm, MPI_Group, MPI_Errhandler, MPI_Info - use :: ompi_mpifh_bindings, only : ompi_intercomm_create_from_groups_f - implicit none - TYPE(MPI_Group), INTENT(IN) :: local_group, remote_group - INTEGER, INTENT(IN):: local_leader, remote_leader - CHARACTER(LEN=*), INTENT(IN) :: stringtag - TYPE(MPI_Info), INTENT(IN) :: info - TYPE(MPI_Errhandler), INTENT(IN) :: errhandler - TYPE(MPI_Comm), INTENT(OUT) :: newintercomm - INTEGER, OPTIONAL, INTENT(OUT) :: ierror - integer :: c_ierror - - call ompi_intercomm_create_from_groups_f(local_group%MPI_VAL, local_leader, & - remote_group%MPI_VAL, & - remote_leader, stringtag, info%MPI_VAL, & - errhandler%MPI_VAL, & - newintercomm%MPI_VAL, c_ierror, len(stringtag)) - if (present(ierror)) ierror = c_ierror - -end subroutine PMPI_Intercomm_create_from_groups_f08 - diff --git a/ompi/mpi/fortran/use-mpi-f08/profile/psession_finalize_f08.F90 b/ompi/mpi/fortran/use-mpi-f08/profile/psession_finalize_f08.F90 deleted file mode 100644 index 01316dd79ca..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/profile/psession_finalize_f08.F90 +++ /dev/null @@ -1,24 +0,0 @@ -! -*- f90 -*- -! -! Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. -! Copyright (c) 2009-2013 Los Alamos National Security, LLC. -! All rights reserved. -! Copyright (c) 2018 Research Organization for Information Science -! and Technology (RIST). All rights reserved. -! Copyright (c) 2019 Triad National Security, LLC. All rights -! reserved. -! $COPYRIGHT$ - -subroutine PMPI_Session_finalize_f08(session,ierror) - use :: mpi_f08_types, only : MPI_Session - use :: ompi_mpifh_bindings, only : ompi_session_finalize_f - implicit none - TYPE(MPI_Session), INTENT(OUT) :: session - INTEGER, OPTIONAL, INTENT(OUT) :: ierror - integer :: c_ierror - - call ompi_session_finalize_f(session%MPI_VAL,c_ierror) - if (present(ierror)) ierror = c_ierror - -end subroutine PMPI_Session_finalize_f08 - diff --git a/ompi/mpi/fortran/use-mpi-f08/recv_f08.F90 b/ompi/mpi/fortran/use-mpi-f08/recv_f08.F90 deleted file mode 100644 index 034fe0fdc19..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/recv_f08.F90 +++ /dev/null @@ -1,29 +0,0 @@ -! -*- f90 -*- -! -! Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. -! Copyright (c) 2009-2012 Los Alamos National Security, LLC. -! All rights reserved. -! Copyright (c) 2018-2020 Research Organization for Information Science -! and Technology (RIST). All rights reserved. -! $COPYRIGHT$ - -#include "ompi/mpi/fortran/configure-fortran-output.h" - -#include "mpi-f08-rename.h" - -subroutine MPI_Recv_f08(buf,count,datatype,source,tag,comm,status,ierror) - use :: mpi_f08_types, only : MPI_Datatype, MPI_Comm, MPI_Status - use :: ompi_mpifh_bindings, only : ompi_recv_f - implicit none - OMPI_FORTRAN_IGNORE_TKR_TYPE :: buf - INTEGER, INTENT(IN) :: count, source, tag - TYPE(MPI_Datatype), INTENT(IN) :: datatype - TYPE(MPI_Comm), INTENT(IN) :: comm - TYPE(MPI_Status), INTENT(OUT) :: status - INTEGER, OPTIONAL, INTENT(OUT) :: ierror - integer :: c_ierror - - call ompi_recv_f(buf,count,datatype%MPI_VAL,source,tag,comm%MPI_VAL,status,c_ierror) - if (present(ierror)) ierror = c_ierror - -end subroutine MPI_Recv_f08 diff --git a/ompi/mpi/fortran/use-mpi-f08/send_f08.F90 b/ompi/mpi/fortran/use-mpi-f08/send_f08.F90 deleted file mode 100644 index 25fecbffb7a..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/send_f08.F90 +++ /dev/null @@ -1,28 +0,0 @@ -! -*- f90 -*- -! -! Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. -! Copyright (c) 2009-2012 Los Alamos National Security, LLC. -! All rights reserved. -! Copyright (c) 2018-2020 Research Organization for Information Science -! and Technology (RIST). All rights reserved. -! $COPYRIGHT$ - -#include "ompi/mpi/fortran/configure-fortran-output.h" - -#include "mpi-f08-rename.h" - -subroutine MPI_Send_f08(buf,count,datatype,dest,tag,comm,ierror) - use :: mpi_f08_types, only : MPI_Datatype, MPI_Comm - use :: ompi_mpifh_bindings, only : ompi_send_f - implicit none - OMPI_FORTRAN_IGNORE_TKR_TYPE, INTENT(IN) :: buf - INTEGER, INTENT(IN) :: count, dest, tag - TYPE(MPI_Datatype), INTENT(IN) :: datatype - TYPE(MPI_Comm), INTENT(IN) :: comm - INTEGER, OPTIONAL, INTENT(OUT) :: ierror - integer :: c_ierror - - call ompi_send_f(buf,count,datatype%MPI_VAL,dest,tag,comm%MPI_VAL,c_ierror) - if (present(ierror)) ierror = c_ierror - -end subroutine MPI_Send_f08 diff --git a/ompi/mpi/fortran/use-mpi-f08/waitall_f08.F90 b/ompi/mpi/fortran/use-mpi-f08/waitall_f08.F90 deleted file mode 100644 index f07551d4c45..00000000000 --- a/ompi/mpi/fortran/use-mpi-f08/waitall_f08.F90 +++ /dev/null @@ -1,25 +0,0 @@ -! -*- f90 -*- -! -! Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved. -! Copyright (c) 2009-2012 Los Alamos National Security, LLC. -! All rights reserved. -! Copyright (c) 2018-2020 Research Organization for Information Science -! and Technology (RIST). All rights reserved. -! $COPYRIGHT$ - -#include "mpi-f08-rename.h" - -subroutine MPI_Waitall_f08(count,array_of_requests,array_of_statuses,ierror) - use :: mpi_f08_types, only : MPI_Request, MPI_Status - use :: ompi_mpifh_bindings, only : ompi_waitall_f - implicit none - INTEGER, INTENT(IN) :: count - TYPE(MPI_Request), INTENT(INOUT) :: array_of_requests(count) - TYPE(MPI_Status), INTENT(OUT) :: array_of_statuses(*) - INTEGER, OPTIONAL, INTENT(OUT) :: ierror - integer :: c_ierror - - call ompi_waitall_f(count,array_of_requests(:)%MPI_VAL,array_of_statuses,c_ierror) - if (present(ierror)) ierror = c_ierror - -end subroutine MPI_Waitall_f08