From a02dc3b6bad881d3345c6f4fdefba0ff2d05369c Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 13:03:21 -0600 Subject: [PATCH 01/20] CHANGES: remove a stray conflict marker Model: Claude Opus 5.5 --- CHANGES | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGES b/CHANGES index a6c86a04fd4..3b377644bd3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,7 +1,6 @@ =============================================================================== Changes in 5.1 =============================================================================== -<<<<<<< HEAD # Removed MPID collective interfaces. Binding layer call MPIR_Xxx_impl instead of MPIR_Xxx. Use a single json config file. Generate json parsing from coll_algorithms.txt. MPIR_Xxx_impl functions call MPIR_Coll_auto for CSEL From a8c9c10bd516bd874708669f94ab3f901503b662 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 10:14:01 -0600 Subject: [PATCH 02/20] mpix.h: define MPIX constants for MPI ABI builds mpix.h now defines the MPIX constants for the MPI ABI together under "#ifdef MPI_ABI_VERSION", with values that follow the MPI ABI encoding as if they were standard constants: MPIX_C_FLOAT16 and MPIX_BFLOAT16 in the 2-byte C datatype category, and MPIX_EQUAL in the other-operations category. They go through the regular gen_abi conversions; mpi.h keeps the native values. MPIX constants that are passed through unconverted and don't conflict with either ABI are defined once in mpix.h for both ABIs, moved from mpi.h: the MPIX error classes, which stay at 101-107 since MPICH encodes error classes in 7 bits, and MPIX_COMM_TYPE_NEIGHBORHOOD (5). mpix.h also declares MPIX_Stream_toint, MPIX_Stream_fromint and MPIX_Async_get_state, and gen_abi.py recognizes prototypes returning MPIX types and void *, so they are declared with MPICH_API_PUBLIC in mpi_abi_internal.h. maint/extracterrmsgs reads the MPIX error classes from mpix.h as well. Previously the ABI constants were guarded by "#ifndef MPICH", which has been dead since mpi.h always defines MPICH, and MPIX_STREAM_NULL, MPIX_COMM_TYPE_NEIGHBORHOOD and MPIX_ERR_* were missing in MPI ABI mode. Model: Claude Opus 5.5 --- maint/extracterrmsgs | 10 ++++---- maint/gen_abi.py | 4 ++-- src/include/mpi.h.in | 23 ++++-------------- src/include/mpix.h | 56 +++++++++++++++++++++++++++++++++++++++----- 4 files changed, 61 insertions(+), 32 deletions(-) diff --git a/maint/extracterrmsgs b/maint/extracterrmsgs index b8906ced257..2ceac8b87f2 100755 --- a/maint/extracterrmsgs +++ b/maint/extracterrmsgs @@ -47,6 +47,7 @@ foreach my $k ("envvarparse", "cvar_val"){ # Check for special args my $mpi_h = "src/include/mpi.h.in"; +my $mpix_h = "src/include/mpix.h"; my $mpi_abi_h = "src/binding/abi/mpi_abi.h"; my $baseerrnames_txt = "src/mpi/errhan/baseerrnames.txt"; my @files = (); @@ -119,10 +120,11 @@ if ($build_test_pgm && -d "test/mpi/errhan") { print TESTFD "{\n int err;\n MPI_Init( 0, 0 );\n"; } -# Load mpi.h for error class constants +# Load mpi.h for error class constants, and mpix.h for the MPIX error classes my %mpi_h_constants; $mpi_h_constants{"MPI_SUCCESS"} = 0; -if (open In, $mpi_h) { +foreach my $h ($mpi_h, $mpix_h) { + open In, $h or die "Unable to read $h\n"; while () { if (/^#define\s+((MPICH|MPI|MPI_T|MPIX)_ERR_\w+)\s+(.+)/) { my ($key, $t) = ($1, $3); @@ -134,8 +136,6 @@ if (open In, $mpi_h) { } } close In; -} else { - die "Unable to read $mpi_h\n"; } # Load mpi_abi.h for ABI error class constants @@ -154,7 +154,7 @@ if (open In, $mpi_abi_h) { my $max_err_class = $mpi_h_constants{MPICH_ERR_LAST_MPIX}; if (!$max_err_class) { - die "Failed to load MPICH_ERR_LAST_MPIX from $mpi_h\n"; + die "Failed to load MPICH_ERR_LAST_MPIX from $mpix_h\n"; } # Process the definitions diff --git a/maint/gen_abi.py b/maint/gen_abi.py index a0f2cd4f3cf..29d400726fb 100644 --- a/maint/gen_abi.py +++ b/maint/gen_abi.py @@ -37,7 +37,7 @@ def load_mpi_abi_h(mpi_abi_h): if RE.search(r'(MPI_ABI|MPIX)_H_INCLUDED', line): # skip the include guard, harmless pass - elif RE.match(r'^(int|double|MPI_\w+)\s+(P?MPI\w+)\((.*)', line): + elif RE.match(r'^(int|double|void \*|MPIX?_\w+)\s*(P?MPI\w+)\((.*)', line): # handle multi-line function prototypes lines = [line.strip()] while not RE.match(r'(.*)\);', lines[-1]): @@ -82,7 +82,7 @@ def gen_mpi_abi_internal_h(out): # rename to internal mpi_t struct type T = RE.m.group(1) out.append("typedef struct %s_s *%s;" % (re.sub(r'MPI_', 'MPIR_', T), T)) - elif RE.match(r'^(int|double|MPI_\w+)\s+(P?MPI\w+)\((.*)\);', line): + elif RE.match(r'^(int|double|void \*|MPIX?_\w+)\s*(P?MPI\w+)\((.*)\);', line): # prototypes, rename param prefix, add MPICH_API_PUBLIC (T, name, param) = RE.m.group(1,2,3) T=re.sub(re_Handle, r'ABI_\1', T) diff --git a/src/include/mpi.h.in b/src/include/mpi.h.in index 4634c43acca..f47d14aaa92 100644 --- a/src/include/mpi.h.in +++ b/src/include/mpi.h.in @@ -604,10 +604,8 @@ enum MPIR_Combiner_enum { #define MPI_COMM_TYPE_HW_UNGUIDED 3 #define MPI_COMM_TYPE_RESOURCE_GUIDED 4 -#endif /* MPICH_BUILD_MPI_ABI */ -/* MPICH-specific types */ -#define MPIX_COMM_TYPE_NEIGHBORHOOD 5 -#ifndef MPICH_BUILD_MPI_ABI +/* MPIX_COMM_TYPE_NEIGHBORHOOD is defined in mpix.h, shared by the MPICH + * native ABI and the MPI ABI */ /* For supported thread levels */ #define MPI_THREAD_SINGLE 0 @@ -750,21 +748,8 @@ enum MPIR_Combiner_enum { #define MPICH_ERR_LAST_CLASS 81 /* It is also helpful to know the last valid class */ -#define MPICH_ERR_FIRST_MPIX 100 /* Define a gap here because sock is - * already using some of the values in this - * range. All MPIX error codes will be - * above this value to be ABI complaint. */ - -#define MPIX_ERR_PROC_FAILED MPICH_ERR_FIRST_MPIX+1 /* Process failure */ -#define MPIX_ERR_PROC_FAILED_PENDING MPICH_ERR_FIRST_MPIX+2 /* A failure has caused this request - * to be pending */ -#define MPIX_ERR_REVOKED MPICH_ERR_FIRST_MPIX+3 /* The communication object has been revoked */ -#define MPIX_ERR_EAGAIN MPICH_ERR_FIRST_MPIX+4 /* Operation could not be issued */ -#define MPIX_ERR_NOREQ MPICH_ERR_FIRST_MPIX+5 /* Cannot allocate request */ -#define MPIX_ERR_STREAM MPICH_ERR_FIRST_MPIX+6 /* Invalid stream */ -#define MPIX_ERR_TIMEOUT MPICH_ERR_FIRST_MPIX+7 /* Operation timed out */ - -#define MPICH_ERR_LAST_MPIX MPICH_ERR_FIRST_MPIX+7 +/* MPIX error classes, MPICH_ERR_FIRST_MPIX and MPICH_ERR_LAST_MPIX are + * defined in mpix.h, shared by the MPICH native ABI and the MPI ABI */ /* End of MPI's error classes */ diff --git a/src/include/mpix.h b/src/include/mpix.h index 137074d3ae8..af2e9debec3 100644 --- a/src/include/mpix.h +++ b/src/include/mpix.h @@ -15,17 +15,55 @@ extern "C" { #define MPIX_GPU_SUPPORT_ZE (1) #define MPIX_GPU_SUPPORT_HIP (2) -#ifndef MPICH -#define MPIX_C_FLOAT16 ((MPI_Datatype)0x000002f0) -#define MPIX_BFLOAT16 ((MPI_Datatype)0x000002f1) -#define MPIX_EQUAL ((MPI_Op)0x0000003e) -#endif - /* Generalized requests extensions */ typedef int MPIX_Grequest_class; /* MPI stream objects */ typedef int MPIX_Stream; +#ifdef MPI_ABI_VERSION +/* MPI ABI: all MPIX constants are defined here, kept together so their ranges + * are easy to maintain. They follow the MPI ABI encoding as if they were + * standard constants, and go through the same conversions in libmpi_abi. + * + * Handle values are picked from unassigned slots of the MPI ABI handle + * encoding and may change in the future to avoid collisions with new + * standard handles. + */ +#define MPIX_C_FLOAT16 ((MPI_Datatype)0x0000024a) /* 2-byte C types */ +#define MPIX_BFLOAT16 ((MPI_Datatype)0x0000024b) /* 2-byte C types */ +#define MPIX_EQUAL ((MPI_Op)0x0000003e) /* other operations */ + +/* TODO: convert MPIX_Stream as an ABI handle */ +#define MPIX_STREAM_NULL ((MPIX_Stream)0x3c000000) + +#else +/* MPICH native ABI: the MPIX constant values that differ from the MPI ABI + * are defined in mpi.h */ +#endif + +/* MPIX constants passed through libmpi_abi unconverted. A single set serves + * both the MPICH native ABI and the MPI ABI as long as the values don't + * conflict with either. */ + +/* MPIX error classes. They stay below 128 because MPICH encodes the error + * class in the lowest 7 bits of an error code, so they cannot go above 16384 + * as MPI 5.0 asks. Starting at 101 leaves room for new standard error + * classes. */ +#define MPICH_ERR_FIRST_MPIX 100 +#define MPIX_ERR_PROC_FAILED MPICH_ERR_FIRST_MPIX+1 /* Process failure */ +#define MPIX_ERR_PROC_FAILED_PENDING MPICH_ERR_FIRST_MPIX+2 /* A failure has caused this request + * to be pending */ +#define MPIX_ERR_REVOKED MPICH_ERR_FIRST_MPIX+3 /* The communication object has been revoked */ +#define MPIX_ERR_EAGAIN MPICH_ERR_FIRST_MPIX+4 /* Operation could not be issued */ +#define MPIX_ERR_NOREQ MPICH_ERR_FIRST_MPIX+5 /* Cannot allocate request */ +#define MPIX_ERR_STREAM MPICH_ERR_FIRST_MPIX+6 /* Invalid stream */ +#define MPIX_ERR_TIMEOUT MPICH_ERR_FIRST_MPIX+7 /* Operation timed out */ +#define MPICH_ERR_LAST_MPIX MPICH_ERR_FIRST_MPIX+7 + +/* MPIX split types for MPI_Comm_split_type. The standard split types are + * 221-224 in the MPI ABI and 1-4 in the MPICH native ABI. */ +#define MPIX_COMM_TYPE_NEIGHBORHOOD 5 + /* MPIX Async extensions */ /* poll_fn return following states. */ enum { @@ -74,6 +112,7 @@ int MPI_Errhandler_get(MPI_Comm comm, MPI_Errhandler * errhandler); int MPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhandler); int MPIX_Async_start(MPIX_Async_poll_function * poll_fn, void *extra_state, MPIX_Stream stream); +void *MPIX_Async_get_state(MPIX_Async_thing async_thing); int MPIX_Async_spawn(MPIX_Async_thing async_thing, MPIX_Async_poll_function * poll_fn, void *extra_state, MPIX_Stream stream); int MPIX_Op_create_x(MPIX_User_function_x * user_fn_x, MPIX_Destructor_function * destructor_fn, @@ -133,6 +172,8 @@ int MPIX_Stream_comm_create_multiplex(MPI_Comm comm, int count, MPIX_Stream arra MPI_Comm * newcomm); int MPIX_Comm_get_stream(MPI_Comm comm, int idx, MPIX_Stream * stream); int MPIX_Stream_progress(MPIX_Stream stream); +int MPIX_Stream_toint(MPIX_Stream stream); +MPIX_Stream MPIX_Stream_fromint(int stream); int MPIX_Start_progress_thread(MPIX_Stream stream); int MPIX_Stop_progress_thread(MPIX_Stream stream); int MPIX_Stream_send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, @@ -215,6 +256,7 @@ int PMPI_Errhandler_get(MPI_Comm comm, MPI_Errhandler * errhandler); int PMPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhandler); int PMPIX_Async_start(MPIX_Async_poll_function * poll_fn, void *extra_state, MPIX_Stream stream); +void *PMPIX_Async_get_state(MPIX_Async_thing async_thing); int PMPIX_Async_spawn(MPIX_Async_thing async_thing, MPIX_Async_poll_function * poll_fn, void *extra_state, MPIX_Stream stream); int PMPIX_Op_create_x(MPIX_User_function_x * user_fn_x, MPIX_Destructor_function * destructor_fn, @@ -274,6 +316,8 @@ int PMPIX_Stream_comm_create_multiplex(MPI_Comm comm, int count, MPIX_Stream arr MPI_Comm * newcomm); int PMPIX_Comm_get_stream(MPI_Comm comm, int idx, MPIX_Stream * stream); int PMPIX_Stream_progress(MPIX_Stream stream); +int PMPIX_Stream_toint(MPIX_Stream stream); +MPIX_Stream PMPIX_Stream_fromint(int stream); int PMPIX_Start_progress_thread(MPIX_Stream stream); int PMPIX_Stop_progress_thread(MPIX_Stream stream); int PMPIX_Stream_send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, From 4795ef5edecb99f60954cde8f7535ed606fe170e Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 10:14:19 -0600 Subject: [PATCH 03/20] mpix.h: remove declarations of removed MPI functions Functions removed from the MPI standard are declared only in mpi_legacy.h for the MPI ABI, and in mpi_proto.h for the MPICH native ABI. mpix.h is for MPIX extensions only. Update the mpi_legacy.h header comment to match. Previously mpix.h declared a subset of the removed functions, so an MPI ABI user with only -mpi-mpix got half of the legacy API, and both headers declared them with -mpi-mpix -mpi-legacy. Model: Claude Opus 5.5 --- src/include/mpi_legacy.h | 11 ++++++----- src/include/mpix.h | 30 ------------------------------ 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/src/include/mpi_legacy.h b/src/include/mpi_legacy.h index 8790b307113..64165a88282 100644 --- a/src/include/mpi_legacy.h +++ b/src/include/mpi_legacy.h @@ -4,12 +4,13 @@ */ /* This header provides declarations for MPI functions and types that have - * been removed from the MPI standard. It is included by mpi.h when the - * MPI_LEGACY macro is defined (e.g. via mpicc -mpi-legacy). + * been removed from the MPI standard. It is for the MPI ABI only: the MPI ABI + * mpi.h includes it when the MPI_LEGACY macro is defined (e.g. via + * mpicc -mpi-legacy). This is the only header that declares them for the + * MPI ABI; mpix.h is for MPIX extensions only. * - * For MPICH ABI builds, these declarations are also available via mpix.h - * and mpi.h directly. For MPI ABI builds, this header is the only way - * to access them. + * The MPICH native mpi.h does not include this header. It declares the + * removed functions in mpi_proto.h, with native constant values. * * New code should use the replacement functions specified by the MPI standard. */ diff --git a/src/include/mpix.h b/src/include/mpix.h index af2e9debec3..ea56e1211eb 100644 --- a/src/include/mpix.h +++ b/src/include/mpix.h @@ -96,21 +96,6 @@ typedef int (MPIX_Grequest_wait_function) (int, void **, double, MPI_Status *); typedef int (MPIX_Async_poll_function) (MPIX_Async_thing); -int MPI_Address(void *location, MPI_Aint * address); -int MPI_Type_hindexed(int count, int array_of_blocklengths[], MPI_Aint array_of_displacements[], - MPI_Datatype oldtype, MPI_Datatype * newtype); -int MPI_Type_hvector(int count, int blocklength, MPI_Aint stride, MPI_Datatype oldtype, - MPI_Datatype * newtype); -int MPI_Type_struct(int count, int array_of_blocklengths[], MPI_Aint array_of_displacements[], - MPI_Datatype array_of_types[], MPI_Datatype * newtype); -int MPI_Type_extent(MPI_Datatype datatype, MPI_Aint * extent); -int MPI_Type_lb(MPI_Datatype datatype, MPI_Aint * displacement); -int MPI_Type_ub(MPI_Datatype datatype, MPI_Aint * displacement); -int MPI_Errhandler_create(MPI_Comm_errhandler_function * comm_errhandler_fn, - MPI_Errhandler * errhandler); -int MPI_Errhandler_get(MPI_Comm comm, MPI_Errhandler * errhandler); -int MPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhandler); - int MPIX_Async_start(MPIX_Async_poll_function * poll_fn, void *extra_state, MPIX_Stream stream); void *MPIX_Async_get_state(MPIX_Async_thing async_thing); int MPIX_Async_spawn(MPIX_Async_thing async_thing, MPIX_Async_poll_function * poll_fn, @@ -240,21 +225,6 @@ int MPIX_Irecv_enqueue_c(void *buf, MPI_Count count, MPI_Datatype datatype, int int MPIX_Allreduce_enqueue_c(const void *sendbuf, void *recvbuf, MPI_Count count, MPI_Datatype datatype, MPI_Op op, MPI_Comm comm); -int PMPI_Address(void *location, MPI_Aint * address); -int PMPI_Type_hindexed(int count, int array_of_blocklengths[], MPI_Aint array_of_displacements[], - MPI_Datatype oldtype, MPI_Datatype * newtype); -int PMPI_Type_hvector(int count, int blocklength, MPI_Aint stride, MPI_Datatype oldtype, - MPI_Datatype * newtype); -int PMPI_Type_struct(int count, int array_of_blocklengths[], MPI_Aint array_of_displacements[], - MPI_Datatype array_of_types[], MPI_Datatype * newtype); -int PMPI_Type_extent(MPI_Datatype datatype, MPI_Aint * extent); -int PMPI_Type_lb(MPI_Datatype datatype, MPI_Aint * displacement); -int PMPI_Type_ub(MPI_Datatype datatype, MPI_Aint * displacement); -int PMPI_Errhandler_create(MPI_Comm_errhandler_function * comm_errhandler_fn, - MPI_Errhandler * errhandler); -int PMPI_Errhandler_get(MPI_Comm comm, MPI_Errhandler * errhandler); -int PMPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhandler); - int PMPIX_Async_start(MPIX_Async_poll_function * poll_fn, void *extra_state, MPIX_Stream stream); void *PMPIX_Async_get_state(MPIX_Async_thing async_thing); int PMPIX_Async_spawn(MPIX_Async_thing async_thing, MPIX_Async_poll_function * poll_fn, From 3a85ce6299ac044fe9288959fe53365719559560 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 10:57:33 -0600 Subject: [PATCH 04/20] abi: make MPIX_Stream and MPIX_Grequest_class MPI ABI handles In the MPI ABI, MPIX_Stream and MPIX_Grequest_class are now opaque handles like the standard handles. MPIX_STREAM_NULL is in handle category 0b0001_11111 and MPIX_Grequest_class takes 0b0001_11110, without predefined handles: MPIX handle categories are allocated from the back to avoid collisions with new standard handles. libmpi_abi converts them with ABI_Stream_to_mpi/from_mpi and ABI_Grequest_class_to_mpi/from_mpi, and the binding generators treat them as handle types. The native typedefs move to mpi.h, next to MPIX_STREAM_NULL. Fix the stream_multiplex test, whose forward declaration of test_stream_send took an MPIX_Stream instead of the MPI_Comm of its definition. Previously both were ints in both modes, and the MPI ABI used the native MPIX_STREAM_NULL value. Model: Claude Opus 5.5 --- maint/gen_abi.py | 4 +-- maint/local_python/binding_c.py | 38 ++++++++++++-------- src/binding/abi/mpi_abi_util.h | 36 +++++++++++++++++++ src/include/mpi.h.in | 4 +++ src/include/mpix.h | 17 +++++---- test/mpi/impls/mpich/comm/stream_multiplex.c | 2 +- 6 files changed, 74 insertions(+), 27 deletions(-) diff --git a/maint/gen_abi.py b/maint/gen_abi.py index 29d400726fb..eefa7c53024 100644 --- a/maint/gen_abi.py +++ b/maint/gen_abi.py @@ -49,7 +49,7 @@ def load_mpi_abi_h(mpi_abi_h): def dump_mpi_abi_internal_h(mpi_abi_internal_h): define_constants = {} def gen_mpi_abi_internal_h(out): - re_Handle = r'\bMPI_(Comm|Datatype|Errhandler|Group|Info|Message|Op|Request|Session|Win|File|KEYVAL_INVALID|TAG_UB|IO|HOST|WTIME_IS_GLOBAL|APPNUM|LASTUSEDCODE|UNIVERSE_SIZE|WIN_BASE|WIN_DISP_UNIT|WIN_SIZE|WIN_CREATE_FLAVOR|WIN_MODEL)\b' + re_Handle = r'\bMPIX?_(Comm|Datatype|Errhandler|Group|Info|Message|Op|Request|Session|Win|File|Stream|Grequest_class|KEYVAL_INVALID|TAG_UB|IO|HOST|WTIME_IS_GLOBAL|APPNUM|LASTUSEDCODE|UNIVERSE_SIZE|WIN_BASE|WIN_DISP_UNIT|WIN_SIZE|WIN_CREATE_FLAVOR|WIN_MODEL)\b' for line in G.abi_h_lines: if RE.match(r'\s*int MPI_(SOURCE|TAG|ERROR);', line): # no need to rename status fields @@ -61,7 +61,7 @@ def gen_mpi_abi_internal_h(out): out.append(" %s count_lo;" % T) out.append(" %s count_hi_and_cancelled;" % T) out.append(" %s reserved[%d];" % (T, n - 2)) - elif RE.match(r'#define\s+(MPIX?_\w+)\s+\(?\((MPI_\w+)\)\s*(0x\w+)\)?', line): + elif RE.match(r'#define\s+(MPIX?_\w+)\s+\(?\((MPIX?_\w+)\)\s*(0x\w+)\)?', line): (name, T, val) = RE.m.group(1,2,3) if T == "MPI_File": # Both ROMIO and ABI use pointers, thus we can directly replace constants diff --git a/maint/local_python/binding_c.py b/maint/local_python/binding_c.py index 251caeedd4e..4b7eb2329f3 100644 --- a/maint/local_python/binding_c.py +++ b/maint/local_python/binding_c.py @@ -1028,6 +1028,9 @@ def dump_abi_wrappers(func, is_large): # special treatment below because it is optional array_type = "Datatype" array_size = "(*num_elements)" + elif re.match(r'mpix_stream_comm_create_multiplex', func['name'], re.IGNORECASE): + array_type = "Stream" + array_size = "count" elif re.match(r'mpi_comm_spawn$', func['name'], re.IGNORECASE): pre_filters.append("MPI_Info info = MPI_INFO_NULL;") pre_filters.append("if (ABI_Comm_rank(comm_abi) == root) {") @@ -1054,7 +1057,8 @@ def process_handle(p): name = p['name'] if name in already_done: return - T = re.sub(r'MPI_', '', mapping[p['kind']]) + MPI_T = mapping[p['kind']] # e.g. MPI_Comm, MPIX_Stream + T = re.sub(r'MPIX?_', '', MPI_T) # translate to internal parameters if p['length']: # neighbor_alltoallw @@ -1066,9 +1070,9 @@ def process_handle(p): if re.match(r'mpi_t_event_get_info', func['name'], re.IGNORECASE): # array_of_datatypes[] - pre_filters.append("MPI_%s *%s = NULL;" % (array_type, name)) + pre_filters.append("%s *%s = NULL;" % (MPI_T, name)) pre_filters.append("if (num_elements && %s > 0) {" % array_size) - pre_filters.append(" %s = MPL_malloc(sizeof(MPI_%s) * %s, MPL_MEM_OTHER);" % (name, array_type, array_size)) + pre_filters.append(" %s = MPL_malloc(sizeof(%s) * %s, MPL_MEM_OTHER);" % (name, MPI_T, array_size)) pre_filters.append("}") post_filters.append("if (num_elements) {") post_filters.append(" for (int i = 0; i < %s; i++) {" % array_size) @@ -1077,7 +1081,7 @@ def process_handle(p): post_filters.append("}") elif array_size: # assume input only - pre_filters.append("MPI_%s *%s = NULL;" % (array_type, name)) + pre_filters.append("%s *%s = NULL;" % (MPI_T, name)) if is_alltoallw: if name == "sendtypes": pre_filters.append("if (sendbuf != MPI_IN_PLACE && sendtypes_abi != NULL) {") @@ -1091,9 +1095,9 @@ def process_handle(p): pre_filters.append("if (%s > 0) {" % array_size) if array_size == "max_datatypes": # zero the output array so we know whether it is filled at output - pre_filters.append(" %s = MPL_calloc(sizeof(MPI_%s), %s, MPL_MEM_OTHER);" % (name, array_type, array_size)) + pre_filters.append(" %s = MPL_calloc(sizeof(%s), %s, MPL_MEM_OTHER);" % (name, MPI_T, array_size)) else: - pre_filters.append(" %s = MPL_malloc(sizeof(MPI_%s) * %s, MPL_MEM_OTHER);" % (name, array_type, array_size)) + pre_filters.append(" %s = MPL_malloc(sizeof(%s) * %s, MPL_MEM_OTHER);" % (name, MPI_T, array_size)) pre_filters.append("}") if p['param_direction'] == 'in' or p['param_direction'] == 'inout': pre_filters.append("for (int i = 0; i < %s; i++) {" % array_size) @@ -1143,8 +1147,12 @@ def process_handle(p): else: if p['param_direction'] == 'out': # pass NULL thru for error-checking - pre_filters.append("MPI_%s %s_i = MPI_%s_NULL;" % (T, name, T.upper())) - pre_filters.append("MPI_%s *%s = NULL;" % (T, name)) + null_handle = MPI_T.upper() + "_NULL" + if T == "Grequest_class": + # no predefined null handle + null_handle = "0" + pre_filters.append("%s %s_i = %s;" % (MPI_T, name, null_handle)) + pre_filters.append("%s *%s = NULL;" % (MPI_T, name)) pre_filters.append("if (%s_abi != NULL) {" % name) pre_filters.append(" %s = &%s_i;" % (name, name)) pre_filters.append("}") @@ -1153,8 +1161,8 @@ def process_handle(p): post_filters.append("}") elif p['param_direction'] == 'inout' or func['name'] == "MPI_Cancel": # pass NULL thru for error-checking - pre_filters.append("MPI_%s %s_i;" % (T, name)) - pre_filters.append("MPI_%s *%s = NULL;" % (T, name)) + pre_filters.append("%s %s_i;" % (MPI_T, name)) + pre_filters.append("%s *%s = NULL;" % (MPI_T, name)) pre_filters.append("if (%s_abi != NULL) {" % name) pre_filters.append(" %s_i = ABI_%s_to_mpi(*%s_abi);" % (name, T, name)) pre_filters.append(" %s = &%s_i;" % (name, name)) @@ -1163,7 +1171,7 @@ def process_handle(p): post_filters.append(" *%s_abi = ABI_%s_from_mpi(%s_i);" % (name, T, name)); post_filters.append("}") else: - pre_filters.append("MPI_%s %s = ABI_%s_to_mpi(%s_abi);" % (T, name, T, name)) + pre_filters.append("%s %s = ABI_%s_to_mpi(%s_abi);" % (MPI_T, name, T, name)) def out_can_be_undefined(p): if p['param_direction'] == 'out': @@ -1227,12 +1235,12 @@ def out_can_be_undefined(p): # 1. the regular conversion will reserve the [0, 4096) range # 2. ABI handle type can be safely cast into (uintptr_t) # - if RE.match(r'..._(Comm|Type|Errhandler|Group|Info|Message|Op|Request|Session|Win|File)_(toint|c2f)\b', func_name): + if RE.match(r'MPIX?_(Comm|Type|Errhandler|Group|Info|Message|Op|Request|Session|Win|File|Stream)_(toint|c2f)\b', func_name): handle_in = "(uintptr_t) " + func['c_parameters'][0]['name'] + "_abi" dump_if_open("%s > 0 && %s < 4096" % (handle_in, handle_in)) G.out.append("return (int) %s;" % handle_in) dump_if_close() - elif RE.match(r'..._(Comm|Type|Errhandler|Group|Info|Message|Op|Request|Session|Win|File)_(fromint|f2c)\b', func_name): + elif RE.match(r'MPIX?_(Comm|Type|Errhandler|Group|Info|Message|Op|Request|Session|Win|File|Stream)_(fromint|f2c)\b', func_name): handle_in = func['c_parameters'][0]['name'] dump_if_open("%s > 0 && %s < 4096" % (handle_in, handle_in)) ABI_type = "ABI_" + RE.m.group(1) @@ -1246,7 +1254,7 @@ def out_can_be_undefined(p): if ret != 'int': # MPI_Wtime, MPI_Aint_{add,diff}, MPI_{Comm,...}_{c2f,f2c} - if RE.match(r'..._(Comm|Datatype|Errhandler|Group|Info|Message|Op|Request|Session|Win|File)\b', ret): + if RE.match(r'..._(Comm|Datatype|Errhandler|Group|Info|Message|Op|Request|Session|Win|File|Stream)\b', ret): G.out.append("return ABI_%s_from_mpi(%s);" % (RE.m.group(1), static_call)) else: G.out.append("return " + static_call + ";") @@ -2991,7 +2999,7 @@ def dump_validate_get_topo_size(func): def get_abi_re_Handle(): # the following handle types need perform ABI-swap for abi bindings - return r'MPI_(Comm|Datatype|Errhandler|Group|Info|Message|Op|Request|Session|Win|File)\b' + return r'MPIX?_(Comm|Datatype|Errhandler|Group|Info|Message|Op|Request|Session|Win|File|Stream|Grequest_class)\b' def is_type_create(func): last_p = func['c_parameters'][-1] diff --git a/src/binding/abi/mpi_abi_util.h b/src/binding/abi/mpi_abi_util.h index ea598353bd4..a362fd5fefd 100644 --- a/src/binding/abi/mpi_abi_util.h +++ b/src/binding/abi/mpi_abi_util.h @@ -306,6 +306,42 @@ static inline ABI_Session ABI_Session_from_mpi(MPI_Session in) return (ABI_Session) (void *) ptr; } +static inline MPIX_Stream ABI_Stream_to_mpi(ABI_Stream in) +{ + if (in == ABI_STREAM_NULL) { + return MPIX_STREAM_NULL; + } + return ((MPIR_Stream *) in)->handle; +} + +static inline ABI_Stream ABI_Stream_from_mpi(MPIX_Stream in) +{ + if (in == MPIX_STREAM_NULL) { + return ABI_STREAM_NULL; + } + MPIR_Stream *ptr; + MPIR_Stream_get_ptr(in, ptr); + return (ABI_Stream) (void *) ptr; +} + +static inline MPIX_Grequest_class ABI_Grequest_class_to_mpi(ABI_Grequest_class in) +{ + if (in == NULL) { + return 0; + } + return ((MPIR_Grequest_class *) in)->handle; +} + +static inline ABI_Grequest_class ABI_Grequest_class_from_mpi(MPIX_Grequest_class in) +{ + if (in == 0) { + return NULL; + } + MPIR_Grequest_class *ptr; + MPIR_Grequest_class_get_ptr(in, ptr); + return (ABI_Grequest_class) (void *) ptr; +} + static inline MPI_Win ABI_Win_to_mpi(ABI_Win in) { if (in == ABI_WIN_NULL) { diff --git a/src/include/mpi.h.in b/src/include/mpi.h.in index f47d14aaa92..f12b53519ce 100644 --- a/src/include/mpi.h.in +++ b/src/include/mpi.h.in @@ -176,7 +176,11 @@ extern "C" { #define MPI_ERRHANDLER_NULL ((MPI_Errhandler)0x14000000) #define MPI_MESSAGE_NULL ((MPI_Message)0x2c000000) #define MPI_MESSAGE_NO_PROC ((MPI_Message)0x6c000000) +/* MPI stream objects, the MPI ABI definitions are in mpix.h */ +typedef int MPIX_Stream; #define MPIX_STREAM_NULL ((MPIX_Stream)0x3c000000) +/* Generalized request classes, the MPI ABI definition is in mpix.h */ +typedef int MPIX_Grequest_class; typedef int MPI_Datatype; #define MPI_CHAR ((MPI_Datatype)0x4c000101) diff --git a/src/include/mpix.h b/src/include/mpix.h index ea56e1211eb..0be782b25b6 100644 --- a/src/include/mpix.h +++ b/src/include/mpix.h @@ -15,11 +15,6 @@ extern "C" { #define MPIX_GPU_SUPPORT_ZE (1) #define MPIX_GPU_SUPPORT_HIP (2) -/* Generalized requests extensions */ -typedef int MPIX_Grequest_class; -/* MPI stream objects */ -typedef int MPIX_Stream; - #ifdef MPI_ABI_VERSION /* MPI ABI: all MPIX constants are defined here, kept together so their ranges * are easy to maintain. They follow the MPI ABI encoding as if they were @@ -33,12 +28,16 @@ typedef int MPIX_Stream; #define MPIX_BFLOAT16 ((MPI_Datatype)0x0000024b) /* 2-byte C types */ #define MPIX_EQUAL ((MPI_Op)0x0000003e) /* other operations */ -/* TODO: convert MPIX_Stream as an ABI handle */ -#define MPIX_STREAM_NULL ((MPIX_Stream)0x3c000000) +/* MPIX handle categories are allocated from the back of the MPI ABI + * handle encoding to avoid collisions with new standard handles. */ +typedef struct MPIX_ABI_Stream *MPIX_Stream; +#define MPIX_STREAM_NULL ((MPIX_Stream)0x000001f8) /* 0b0001_11111_000 */ +/* Generalized request classes have no predefined handles (0b0001_11110_***) */ +typedef struct MPIX_ABI_Grequest_class *MPIX_Grequest_class; #else -/* MPICH native ABI: the MPIX constant values that differ from the MPI ABI - * are defined in mpi.h */ +/* MPICH native ABI: the MPIX handle types and the constant values that + * differ from the MPI ABI are defined in mpi.h */ #endif /* MPIX constants passed through libmpi_abi unconverted. A single set serves diff --git a/test/mpi/impls/mpich/comm/stream_multiplex.c b/test/mpi/impls/mpich/comm/stream_multiplex.c index 3b5331be34f..f7415f44047 100644 --- a/test/mpi/impls/mpich/comm/stream_multiplex.c +++ b/test/mpi/impls/mpich/comm/stream_multiplex.c @@ -18,7 +18,7 @@ int rank, size; -static int test_stream_send(MPIX_Stream stream, int src_idx, int dst_idx); +static int test_stream_send(MPI_Comm stream_comm, int src_idx, int dst_idx); int main(int argc, char **argv) { From f824d09719a44cd63def241b035e628bc5b25134 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 12:58:50 -0600 Subject: [PATCH 05/20] abi: add MPIX functions to libmpi_abi libmpi_abi now provides all the MPIX functions. The generated ABI wrappers convert their handle arguments like the standard ones; the callbacks that take handles are already converted where the library calls them. MPIX_Waitall_enqueue is added to the request-array conversions. The Fortran configure now identifies the MPI ABI by the library it picked rather than by the absence of MPIX functions, and still keeps MPIX off in the Fortran binding on the MPI ABI. Previously libmpi_abi only had the MPIX functions ROMIO needs (MPIX_Grequest_* and MPIX_Type_iov*), so MPI ABI programs using "mpicc -mpi-mpix" failed to link. Model: Claude Opus 5.5 --- CHANGES | 1 + doc/wiki/how_to/MPI_ABI_Build_Interface.md | 5 ++++- maint/gen_binding_c.py | 7 ------- maint/local_python/binding_c.py | 4 +++- src/binding/fortran/configure.ac | 23 +++++++++++----------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/CHANGES b/CHANGES index 3b377644bd3..131abd14553 100644 --- a/CHANGES +++ b/CHANGES @@ -15,6 +15,7 @@ from the MPI C library. mpifort now explicitly links -lmpi (or -lmpi_abi). # Split mpix.h from mpi.h. MPIX constants are available with ABI conversion support. + libmpi_abi provides the MPIX functions (mpicc -mpi-mpix). # Added circulant graph (circ_graph) algorithms for Bcast, Reduce, Allgather, and nonblocking IBcast. diff --git a/doc/wiki/how_to/MPI_ABI_Build_Interface.md b/doc/wiki/how_to/MPI_ABI_Build_Interface.md index 0f71e97991e..0fe4e8d4024 100644 --- a/doc/wiki/how_to/MPI_ABI_Build_Interface.md +++ b/doc/wiki/how_to/MPI_ABI_Build_Interface.md @@ -129,7 +129,10 @@ provides access to MPIX extension functions (e.g. `MPIX_Query_cuda_support`). The MPIX declarations are split into a separate header because `mpi_abi.h` does not declare them. This flag makes them available -regardless of which ABI is in use. +regardless of which ABI is in use, and `libmpi_abi` provides the MPIX +functions, converting MPIX handles such as `MPIX_Stream` like the +standard ones. The Fortran binding does not use MPIX on the MPI ABI yet +(see below). ### `-mpi-fortran` diff --git a/maint/gen_binding_c.py b/maint/gen_binding_c.py index a73142c2997..f0c6da7e1b2 100644 --- a/maint/gen_binding_c.py +++ b/maint/gen_binding_c.py @@ -180,13 +180,6 @@ def dump_c_binding_abi(): if 'replace' in func and 'body' not in func: continue - if re.match(r'MPIX_', func['name']): - if re.match(r'MPIX_(Grequest_|Type_iov)', func['name']): - # needed by ROMIO - pass - else: - continue - dump_func_abi(func) if '_replaces' in func: for t_func in func['_replaces']: diff --git a/maint/local_python/binding_c.py b/maint/local_python/binding_c.py index 4b7eb2329f3..ba44d7c122a 100644 --- a/maint/local_python/binding_c.py +++ b/maint/local_python/binding_c.py @@ -1044,7 +1044,7 @@ def dump_abi_wrappers(func, is_large): pre_filters.append("if (ABI_Comm_rank(comm_abi) == root) {") pre_filters.append(" count_info = count;") pre_filters.append("}") - elif re.match(r'mpi_((wait|test|request_get_status_)(all|any)|startall)', func['name'], re.IGNORECASE): + elif re.match(r'mpi_((wait|test|request_get_status_)(all|any)|startall)|mpix_waitall_enqueue', func['name'], re.IGNORECASE): array_type = "Request" array_size = "count" elif re.match(r'mpi_(wait|test|request_get_status_)some', func['name'], re.IGNORECASE): @@ -1216,6 +1216,8 @@ def out_can_be_undefined(p): ret = "int" if 'return' in func: ret = mapping[func['return']] + if func['return'] == 'EXTRA_STATE': + ret = 'void *' ret = re.sub(re_Handle, r'ABI_\1', ret) if 'impl' in func and func['impl'] == "skip": diff --git a/src/binding/fortran/configure.ac b/src/binding/fortran/configure.ac index 3bb3578a234..66ef6d52394 100644 --- a/src/binding/fortran/configure.ac +++ b/src/binding/fortran/configure.ac @@ -246,22 +246,23 @@ AC_ARG_ENABLE([gen-bindings], [AS_HELP_STRING([--disable-gen-bindings], [skip ge AC_ARG_ENABLE([fortran-mpix], [AS_HELP_STRING([--disable-fortran-mpix], [skip mpix in Fortran bindings])], [enable_fortran_mpix=$enableval], [enable_fortran_mpix=auto]) +if test "$WITH_MPI" = "abi" ; then + if test "$FROM_MPICH" = "yes" -o "$MPI_IS_MPICH" = "yes" ; then + # mpich's mpi.h require -DMPI_ABI for abi build + AC_DEFINE([FORTRAN_BUILD_MPI_ABI],1,[Define to build Fortran binding on MPI ABI]) + fi +fi + if test "$enable_fortran_mpix" != "no" ; then # unless --disable-fortran-mpix, we probe whether MPIX callbacks are available - if test "$FROM_MPICH" = "yes" ; then + if test "$WITH_MPI" = "abi" ; then + # For now, the Fortran binding does not use MPIX on the MPI ABI + has_mpix_callbacks=no + enable_fortran_mpix=no + elif test "$FROM_MPICH" = "yes" ; then has_mpix_callbacks=yes - if test "$WITH_MPI" != "mpich" ; then - # For now, ABI build does not provide MPIX functions - has_mpix_callbacks=no - enable_fortran_mpix=no - AC_DEFINE([FORTRAN_BUILD_MPI_ABI],1,[Define to build Fortran binding on MPI ABI]) - fi else AC_CHECK_FUNCS([MPIX_Comm_create_keyval_x], [has_mpix_callbacks=yes], [has_mpix_callbacks=no]) - if test "$has_mpix_callbacks" = "no" -a "$MPI_IS_MPICH" = "yes" ; then - # mpich's mpi.h require -DMPI_ABI for abi build - AC_DEFINE([FORTRAN_BUILD_MPI_ABI],1,[Define to build Fortran binding on MPI ABI]) - fi fi fi From 1025956a56b432e7bde823e40fe4695cfa1f815f Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 13:08:51 -0600 Subject: [PATCH 06/20] binding/fortran: use MPIX callbacks on the MPI ABI The Fortran binding now uses the MPIX callbacks (MPIX_Op_create_x, MPIX_*_create_keyval_x, MPIX_*_create_errhandler_x) for its user-function proxies whenever the C library provides them, including libmpi_abi, and independent of --disable-fortran-mpix, which only controls the MPIX routines for Fortran users. MPI_MPIX is defined with them so that mpi.h provides the declarations on the MPI ABI. Previously the callbacks were off on the MPI ABI, so a Fortran user op received an MPI ABI datatype handle instead of a Fortran integer, and the keyval and errhandler proxies had no cleanup. Model: Claude Opus 5.5 --- doc/wiki/how_to/MPI_ABI_Build_Interface.md | 4 ++- src/binding/fortran/configure.ac | 29 +++++++++++----------- 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/doc/wiki/how_to/MPI_ABI_Build_Interface.md b/doc/wiki/how_to/MPI_ABI_Build_Interface.md index 0fe4e8d4024..541aa6385a9 100644 --- a/doc/wiki/how_to/MPI_ABI_Build_Interface.md +++ b/doc/wiki/how_to/MPI_ABI_Build_Interface.md @@ -230,7 +230,9 @@ mixed Fortran/C programs can still be linked with `mpifort`. On the MPI ABI, the Fortran binding does not provide the `MPIX_` routines (`--disable-fortran-mpix` is implied) and is compiled with -`FORTRAN_BUILD_MPI_ABI`. +`FORTRAN_BUILD_MPI_ABI`. It still uses the MPIX callbacks of the C library +(`HAS_MPIX_CALLBACKS`, e.g. `MPIX_Op_create_x`) for its user-function +proxies, whenever the library provides them. ### Fortran on the MPI ABI in a Dual Build diff --git a/src/binding/fortran/configure.ac b/src/binding/fortran/configure.ac index 66ef6d52394..7374938990c 100644 --- a/src/binding/fortran/configure.ac +++ b/src/binding/fortran/configure.ac @@ -253,17 +253,17 @@ if test "$WITH_MPI" = "abi" ; then fi fi -if test "$enable_fortran_mpix" != "no" ; then - # unless --disable-fortran-mpix, we probe whether MPIX callbacks are available - if test "$WITH_MPI" = "abi" ; then - # For now, the Fortran binding does not use MPIX on the MPI ABI - has_mpix_callbacks=no - enable_fortran_mpix=no - elif test "$FROM_MPICH" = "yes" ; then - has_mpix_callbacks=yes - else - AC_CHECK_FUNCS([MPIX_Comm_create_keyval_x], [has_mpix_callbacks=yes], [has_mpix_callbacks=no]) - fi +# The binding uses the MPIX callbacks (e.g. MPIX_Comm_create_keyval_x) internally +# when the C library provides them, independent of --disable-fortran-mpix +if test "$FROM_MPICH" = "yes" ; then + has_mpix_callbacks=yes +else + AC_CHECK_FUNCS([MPIX_Comm_create_keyval_x], [has_mpix_callbacks=yes], [has_mpix_callbacks=no]) +fi + +if test "$WITH_MPI" = "abi" ; then + # For now, the Fortran binding does not provide MPIX routines on the MPI ABI + enable_fortran_mpix=no fi if test "$has_mpix_callbacks" = "yes" ; then @@ -1091,9 +1091,10 @@ export modincdir AC_SUBST(modincdir) gen_cmd_common="-mpi-h=$mpi_h" -if test "$enable_fortran_mpix" = "yes" ; then - AC_DEFINE([MPI_MPIX], 1, [Define if the fortran binding supports MPIX]) -else +if test "$has_mpix_callbacks" = "yes" -o "$enable_fortran_mpix" = "yes" ; then + AC_DEFINE([MPI_MPIX], 1, [Define to get the MPIX declarations from mpi.h]) +fi +if test "$enable_fortran_mpix" != "yes" ; then gen_cmd_common="$gen_cmd_common -skip-mpix" fi From 718b452e857ce6035ea17c04693cf265f264d4bd Mon Sep 17 00:00:00 2001 From: Lisandro Dalcin Date: Wed, 2 Sep 2026 10:52:20 +0300 Subject: [PATCH 07/20] romio: Remove dependency on legacy MPI APIS Remove usage of: * MPI_Copy_function * MPI_Delete_function * MPI_NULL_COPY_FN --- src/mpi/romio/adio/ad_daos/ad_daos_common.c | 2 +- src/mpi/romio/adio/ad_ime/ad_ime_common.c | 3 ++- src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_common.c | 3 ++- src/mpi/romio/adio/common/cb_config_list.c | 4 ++-- src/mpi/romio/mpi-io/mpioimpl.h | 2 +- src/mpi/romio/mpi-io/mpir-mpioinit.c | 3 ++- 6 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/mpi/romio/adio/ad_daos/ad_daos_common.c b/src/mpi/romio/adio/ad_daos/ad_daos_common.c index 99985656bc9..85568d78a4d 100644 --- a/src/mpi/romio/adio/ad_daos/ad_daos_common.c +++ b/src/mpi/romio/adio/ad_daos/ad_daos_common.c @@ -57,7 +57,7 @@ void ADIOI_DAOS_Init(int *error_code) adio_daos_path_prefix = getenv("DAOS_UNS_PREFIX"); /** attach to comm_self destroy to finalize DAOS */ - MPI_Comm_create_keyval(MPI_NULL_COPY_FN, ad_daos_end, &ADIOI_DAOS_Initialized, (void *) 0); + MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, ad_daos_end, &ADIOI_DAOS_Initialized, (void *) 0); MPI_Comm_set_attr(MPI_COMM_SELF, ADIOI_DAOS_Initialized, (void *) 0); } diff --git a/src/mpi/romio/adio/ad_ime/ad_ime_common.c b/src/mpi/romio/adio/ad_ime/ad_ime_common.c index 36f78b0a6f7..72cb03a4707 100644 --- a/src/mpi/romio/adio/ad_ime/ad_ime_common.c +++ b/src/mpi/romio/adio/ad_ime/ad_ime_common.c @@ -52,7 +52,8 @@ void ADIOI_IME_Init(int rank, int *error_code) *error_code = MPI_SUCCESS; - MPI_Comm_create_keyval(MPI_NULL_COPY_FN, ADIOI_IME_End_call, &ADIOI_IME_Initialized, (void *) 0); + MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, ADIOI_IME_End_call, &ADIOI_IME_Initialized, + (void *) 0); /* just like romio does, we make a dummy attribute so we * get cleaned up */ MPI_Comm_set_attr(MPI_COMM_SELF, ADIOI_IME_Initialized, (void *) 0); diff --git a/src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_common.c b/src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_common.c index 667288c8a85..11e1973b3e6 100644 --- a/src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_common.c +++ b/src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_common.c @@ -75,7 +75,8 @@ void ADIOI_PVFS2_Init(int *error_code) return; } - MPI_Comm_create_keyval(MPI_NULL_COPY_FN, ADIOI_PVFS2_End_call, &ADIOI_PVFS2_Initialized, (void *) 0); + MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, ADIOI_PVFS2_End_call, &ADIOI_PVFS2_Initialized, + (void *) 0); /* just like romio does, we make a dummy attribute so we * get cleaned up */ MPI_Comm_set_attr(MPI_COMM_SELF, ADIOI_PVFS2_Initialized, (void *) 0); diff --git a/src/mpi/romio/adio/common/cb_config_list.c b/src/mpi/romio/adio/common/cb_config_list.c index b1ee3d6cf6d..3af56df454e 100644 --- a/src/mpi/romio/adio/common/cb_config_list.c +++ b/src/mpi/romio/adio/common/cb_config_list.c @@ -123,8 +123,8 @@ int ADIOI_cb_gather_name_array(MPI_Comm comm, MPI_Comm dupcomm, ADIO_cb_name_arr if (ADIOI_cb_config_list_keyval == MPI_KEYVAL_INVALID) { /* cleaned up by ADIOI_End_call */ - MPI_Comm_create_keyval((MPI_Copy_function *) ADIOI_cb_copy_name_array, - (MPI_Delete_function *) ADIOI_cb_delete_name_array, + MPI_Comm_create_keyval((MPI_Comm_copy_attr_function *) ADIOI_cb_copy_name_array, + (MPI_Comm_delete_attr_function *) ADIOI_cb_delete_name_array, &ADIOI_cb_config_list_keyval, NULL); } else { MPI_Comm_get_attr(comm, ADIOI_cb_config_list_keyval, (void *) &array, &found); diff --git a/src/mpi/romio/mpi-io/mpioimpl.h b/src/mpi/romio/mpi-io/mpioimpl.h index 588fce858d7..261b979ecad 100644 --- a/src/mpi/romio/mpi-io/mpioimpl.h +++ b/src/mpi/romio/mpi-io/mpioimpl.h @@ -74,7 +74,7 @@ struct MPIR_Info { #define MPIR_INFO_COOKIE 5835657 -MPI_Delete_function ADIOI_End_call; +MPI_Comm_delete_attr_function ADIOI_End_call; /* common initialization routine */ void MPIR_MPIOInit(int *error_code); diff --git a/src/mpi/romio/mpi-io/mpir-mpioinit.c b/src/mpi/romio/mpi-io/mpir-mpioinit.c index 229a33aef66..abfdb4a9ee0 100644 --- a/src/mpi/romio/mpi-io/mpir-mpioinit.c +++ b/src/mpi/romio/mpi-io/mpir-mpioinit.c @@ -37,7 +37,8 @@ void MPIR_MPIOInit(int *error_code) } /* --END ERROR HANDLING-- */ - MPI_Comm_create_keyval(MPI_NULL_COPY_FN, ADIOI_End_call, &ADIO_Init_keyval, (void *) 0); + MPI_Comm_create_keyval(MPI_COMM_NULL_COPY_FN, ADIOI_End_call, &ADIO_Init_keyval, + (void *) 0); /* put a dummy attribute on MPI_COMM_SELF, because we want the delete * function to be called when MPI_COMM_SELF is freed. Clarified From d26b6accdc21772e32302c8dcd9b0ce3c4879229 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 13:44:47 -0600 Subject: [PATCH 08/20] binding/abi: do not export removed MPI functions from libmpi_abi libmpi_abi no longer has wrappers for the functions removed from the MPI standard, such as MPI_Address, MPI_Type_extent and MPI_Attr_get. The MPI ABI does not include them, and a program built against the MPI ABI should not depend on them. This temporarily breaks "mpicc -mpi-legacy" for the MPI ABI: mpi_legacy.h still declares the removed functions, so programs using them, including the removed-API tests in test/mpi, fail to link. The next commit maps them to their replacements in mpi_legacy.h. Previously libmpi_abi exported the removed functions, which made programs that use them run only on MPICH's libmpi_abi. Model: Claude Opus 5.5 --- maint/gen_binding_c.py | 6 ++---- maint/local_python/binding_c.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/maint/gen_binding_c.py b/maint/gen_binding_c.py index f0c6da7e1b2..4267c79caf0 100644 --- a/maint/gen_binding_c.py +++ b/maint/gen_binding_c.py @@ -177,13 +177,11 @@ def dump_c_binding_abi(): G.out.append("") for func in func_list: - if 'replace' in func and 'body' not in func: + if 'replace' in func: + # removed functions are header-only in the MPI ABI (mpi_legacy.h) continue dump_func_abi(func) - if '_replaces' in func: - for t_func in func['_replaces']: - dump_func_abi(t_func) abi_file_path = G.abi_dir + "/c_binding_abi.c" G.check_write_path(abi_file_path) diff --git a/maint/local_python/binding_c.py b/maint/local_python/binding_c.py index ba44d7c122a..44d89f655c6 100644 --- a/maint/local_python/binding_c.py +++ b/maint/local_python/binding_c.py @@ -1018,7 +1018,7 @@ def dump_abi_wrappers(func, is_large): # array_size set per parameters pre_filters.append("int indegree, outdegree;") pre_filters.append("ABI_Comm_neighbors_count(comm_abi, &indegree, &outdegree);") - elif re.match(r'mpi_type_(create_struct|struct)', func['name'], re.IGNORECASE): + elif re.match(r'mpi_type_create_struct', func['name'], re.IGNORECASE): array_type = "Datatype" array_size = "count" elif re.match(r'mpi_type_get_contents', func['name'], re.IGNORECASE): From 84cbd9e9276543172d9f377b3764409443a2261b Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 14:55:42 -0600 Subject: [PATCH 09/20] romio: allow building pvfs2 without MPI_LB and MPI_UB The pvfs2 driver checks for the MPI_LB and MPI_UB markers only when mpi.h provides them. They were removed from the MPI standard and the MPI ABI does not have them, so without them no datatype can contain the markers. Previously the driver required MPI_LB and MPI_UB to compile. Model: Claude Opus 5.5 --- src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_io_dtype.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_io_dtype.c b/src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_io_dtype.c index 05d09a5419d..feb9ec13e82 100644 --- a/src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_io_dtype.c +++ b/src/mpi/romio/adio/ad_pvfs2/ad_pvfs2_io_dtype.c @@ -10,6 +10,13 @@ #include "ad_pvfs2_io.h" #include "ad_pvfs2_common.h" +#ifdef MPI_LB +#define ADIOI_PVFS2_IS_LB_UB(t) ((t) == MPI_LB || (t) == MPI_UB) +#else +/* MPI_LB and MPI_UB are not defined in the MPI ABI, thus the test is always false */ +#define ADIOI_PVFS2_IS_LB_UB(t) 0 +#endif + int ADIOI_PVFS2_StridedDtypeIO(ADIO_File fd, void *buf, MPI_Aint count, MPI_Datatype datatype, int file_ptr_type, ADIO_Offset offset, ADIO_Status * status, int @@ -366,7 +373,7 @@ int convert_mpi_pvfs2_dtype(MPI_Datatype * mpi_dtype, PVFS_Request * pvfs_dtype) arr_count = 0; for (i = 0; i < arr_int[0]; i++) { - if (arr_dtype[i] != MPI_LB && arr_dtype[i] != MPI_UB) { + if (!ADIOI_PVFS2_IS_LB_UB(arr_dtype[i])) { arr_count++; } } @@ -392,7 +399,7 @@ int convert_mpi_pvfs2_dtype(MPI_Datatype * mpi_dtype, PVFS_Request * pvfs_dtype) arr_count = 0; for (i = 0; i < arr_int[0]; i++) { - if (arr_dtype[i] != MPI_LB && arr_dtype[i] != MPI_UB) { + if (!ADIOI_PVFS2_IS_LB_UB(arr_dtype[i])) { leaf = convert_mpi_pvfs2_dtype(&arr_dtype[i], &old_pvfs_dtype_arr[arr_count]); if (leaf != 1) MPI_Type_free(&arr_dtype[i]); @@ -418,7 +425,7 @@ int convert_mpi_pvfs2_dtype(MPI_Datatype * mpi_dtype, PVFS_Request * pvfs_dtype) arr_count = 0; for (i = 0; i < arr_int[0]; i++) { - if (arr_dtype[i] != MPI_LB && arr_dtype[i] != MPI_UB) { + if (!ADIOI_PVFS2_IS_LB_UB(arr_dtype[i])) { PVFS_Request_free(&old_pvfs_dtype_arr[arr_count]); arr_count++; } @@ -445,7 +452,7 @@ int convert_mpi_pvfs2_dtype(MPI_Datatype * mpi_dtype, PVFS_Request * pvfs_dtype) fprintf(stderr, "Error in PVFS_Request_struct\n"); for (i = 0; i < arr_int[0]; i++) { - if (arr_dtype[i] != MPI_LB && arr_dtype[i] != MPI_UB) + if (!ADIOI_PVFS2_IS_LB_UB(arr_dtype[i])) PVFS_Request_free(&old_pvfs_dtype_arr[i]); } From 2ead529a45cd9a8aab7765cf0f86f591bd7ed35a Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 13:44:57 -0600 Subject: [PATCH 10/20] mpi_legacy.h: map removed APIs to their replacements in the MPI ABI In the MPI ABI, mpi_legacy.h now maps the APIs removed from the MPI standard to their replacements with macros, and implements MPI_Type_extent/lb/ub as static inline functions, so a program built with "mpicc -mpi-legacy" needs no removed symbol from the library and stays portable across MPI ABI implementations. MPI_LB and MPI_UB are not provided, so using them is a compile-time error: the markers only work if the library interprets them, which a standard libmpi_abi need not do. In the MPICH native ABI the removed APIs, including MPI_LB and MPI_UB, stay real and always available, declared in mpi.h and mpi_proto.h. gen_abi.py no longer reads mpi_legacy.h, which has nothing the libmpi_abi build needs. The header follows the one proposed in pmodels/mpich#7948, with the PMPI_Get_address and PMPI_Comm_create_errhandler names fixed. Previously mpi_legacy.h declared the removed functions as prototypes of functions in libmpi_abi, and gave MPI_LB and MPI_UB MPI ABI handle values. Co-authored-by: Lisandro Dalcin Model: Claude Opus 5.5 --- maint/gen_abi.py | 1 - src/include/mpi_legacy.h | 211 +++++++++++++++++++++++---------------- 2 files changed, 125 insertions(+), 87 deletions(-) diff --git a/maint/gen_abi.py b/maint/gen_abi.py index eefa7c53024..4bcdc1941ce 100644 --- a/maint/gen_abi.py +++ b/maint/gen_abi.py @@ -25,7 +25,6 @@ def search(pat, str, flags=0): def main(): load_mpi_abi_h("src/binding/abi/mpi_abi.h") load_mpi_abi_h("src/include/mpix.h") - load_mpi_abi_h("src/include/mpi_legacy.h") dump_mpi_abi_internal_h("src/binding/abi/mpi_abi_internal.h") dump_io_abi_internal_h("src/binding/abi/io_abi_internal.h") dump_romio_abi_internal_h("src/mpi/romio/include/romio_abi_internal.h") diff --git a/src/include/mpi_legacy.h b/src/include/mpi_legacy.h index 64165a88282..46d93b4c72f 100644 --- a/src/include/mpi_legacy.h +++ b/src/include/mpi_legacy.h @@ -3,108 +3,147 @@ * See COPYRIGHT in top-level directory */ -/* This header provides declarations for MPI functions and types that have - * been removed from the MPI standard. It is for the MPI ABI only: the MPI ABI - * mpi.h includes it when the MPI_LEGACY macro is defined (e.g. via - * mpicc -mpi-legacy). This is the only header that declares them for the - * MPI ABI; mpix.h is for MPIX extensions only. +/* This header provides the MPI functions and types that have been removed + * from the MPI standard, for source compatibility with old codes. New code + * should use the replacement functions specified by the MPI standard. * - * The MPICH native mpi.h does not include this header. It declares the - * removed functions in mpi_proto.h, with native constant values. + * MPI ABI: the MPI ABI mpi.h includes this header when MPI_LEGACY is defined + * (e.g. via mpicc -mpi-legacy). The removed APIs are mapped to their + * replacements with macros and static inline functions, so libmpi_abi does + * not export any removed symbol and the program stays portable across MPI ABI + * implementations. MPI_LB and MPI_UB are not provided. * - * New code should use the replacement functions specified by the MPI standard. + * MPICH native ABI: the removed APIs are always available. They are real + * functions in libmpi for backward compatibility, declared in mpi.h and + * mpi_proto.h. */ #ifndef MPI_LEGACY_H_INCLUDED #define MPI_LEGACY_H_INCLUDED +#ifdef MPI_ABI_VERSION + #if defined(__cplusplus) extern "C" { #endif -/* ---- Removed datatype constants ---- */ +/* ---- Removed types and constants ---- */ + +#define MPI_Copy_function MPI_Comm_copy_attr_function +#define MPI_Delete_function MPI_Comm_delete_attr_function +#define MPI_Handler_function MPI_Comm_errhandler_function + +#define MPI_DUP_FN MPI_COMM_DUP_FN +#define MPI_NULL_COPY_FN MPI_COMM_NULL_COPY_FN +#define MPI_NULL_DELETE_FN MPI_COMM_NULL_DELETE_FN + +/* Defined to unique values so legacy switch cases can compile */ +#define MPI_COMBINER_HVECTOR_INTEGER (MPI_COMBINER_NAMED-1) +#define MPI_COMBINER_HINDEXED_INTEGER (MPI_COMBINER_NAMED-2) +#define MPI_COMBINER_STRUCT_INTEGER (MPI_COMBINER_NAMED-3) -/* MPI_LB and MPI_UB were removed from the MPI standard. These values are - * picked from the unassigned slots in the language-independent datatype - * range (0b0010_00000_***) of the MPI ABI handle encoding and may change - * in the future to avoid collisions with new standard datatypes. +/* MPI_LB and MPI_UB are not provided, so using them is a compile-time + * error. They are markers that only work if the MPI library interprets + * them, which a standard libmpi_abi need not do. Use MPI_Type_create_resized + * to set the lower bound and extent of a datatype instead. */ -#define MPI_LB ((MPI_Datatype)0x206) -#define MPI_UB ((MPI_Datatype)0x205) - -/* ---- Removed typedefs ---- */ - -/* Removed in MPI-2.2 (replaced by MPI_Comm_errhandler_function) */ -typedef void (MPI_Handler_function) (MPI_Comm *, int *, ...); - -/* Removed in MPI-5.0 (replaced by MPI_Comm_copy_attr_function / MPI_Comm_delete_attr_function) */ -typedef int (MPI_Copy_function)(MPI_Comm comm, int keyval, void *extra_state, - void *attribute_val_in, void *attribute_val_out, int *flag); -typedef int (MPI_Delete_function)(MPI_Comm comm, int keyval, - void *attribute_val, void *extra_state); - -/* ---- Removed constants ---- */ - -/* Removed in MPI-5.0 (replaced by MPI_COMM_NULL_COPY_FN etc.) */ -#define MPI_NULL_COPY_FN ((MPI_Copy_function *)0) -#define MPI_NULL_DELETE_FN ((MPI_Delete_function *)0) -#define MPI_DUP_FN ((MPI_Copy_function *)0x1) - -/* ---- Removed MPI-1 functions (replaced in MPI-2.0) ---- */ - -int MPI_Address(void *location, MPI_Aint *address); -int MPI_Type_hindexed(int count, int array_of_blocklengths[], - MPI_Aint array_of_displacements[], - MPI_Datatype oldtype, MPI_Datatype *newtype); -int MPI_Type_hvector(int count, int blocklength, MPI_Aint stride, - MPI_Datatype oldtype, MPI_Datatype *newtype); -int MPI_Type_struct(int count, int array_of_blocklengths[], - MPI_Aint array_of_displacements[], - MPI_Datatype array_of_types[], MPI_Datatype *newtype); -int MPI_Type_extent(MPI_Datatype datatype, MPI_Aint *extent); -int MPI_Type_lb(MPI_Datatype datatype, MPI_Aint *displacement); -int MPI_Type_ub(MPI_Datatype datatype, MPI_Aint *displacement); -int MPI_Errhandler_create(MPI_Comm_errhandler_function *comm_errhandler_fn, - MPI_Errhandler *errhandler); -int MPI_Errhandler_get(MPI_Comm comm, MPI_Errhandler *errhandler); -int MPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhandler); - -/* ---- Removed MPI-1 attribute functions (replaced in MPI-2.0) ---- */ - -int MPI_Keyval_create(MPI_Copy_function *copy_fn, MPI_Delete_function *delete_fn, - int *keyval, void *extra_state); -int MPI_Keyval_free(int *keyval); -int MPI_Attr_put(MPI_Comm comm, int keyval, void *attribute_val); -int MPI_Attr_get(MPI_Comm comm, int keyval, void *attribute_val, int *flag); -int MPI_Attr_delete(MPI_Comm comm, int keyval); - -/* ---- PMPI variants ---- */ - -int PMPI_Address(void *location, MPI_Aint *address); -int PMPI_Type_hindexed(int count, int array_of_blocklengths[], - MPI_Aint array_of_displacements[], - MPI_Datatype oldtype, MPI_Datatype *newtype); -int PMPI_Type_hvector(int count, int blocklength, MPI_Aint stride, - MPI_Datatype oldtype, MPI_Datatype *newtype); -int PMPI_Type_struct(int count, int array_of_blocklengths[], - MPI_Aint array_of_displacements[], - MPI_Datatype array_of_types[], MPI_Datatype *newtype); -int PMPI_Type_extent(MPI_Datatype datatype, MPI_Aint *extent); -int PMPI_Type_lb(MPI_Datatype datatype, MPI_Aint *displacement); -int PMPI_Type_ub(MPI_Datatype datatype, MPI_Aint *displacement); -int PMPI_Errhandler_create(MPI_Comm_errhandler_function *comm_errhandler_fn, - MPI_Errhandler *errhandler); -int PMPI_Errhandler_get(MPI_Comm comm, MPI_Errhandler *errhandler); -int PMPI_Errhandler_set(MPI_Comm comm, MPI_Errhandler errhandler); -int PMPI_Keyval_create(MPI_Copy_function *copy_fn, MPI_Delete_function *delete_fn, - int *keyval, void *extra_state); -int PMPI_Keyval_free(int *keyval); -int PMPI_Attr_put(MPI_Comm comm, int keyval, void *attribute_val); -int PMPI_Attr_get(MPI_Comm comm, int keyval, void *attribute_val, int *flag); -int PMPI_Attr_delete(MPI_Comm comm, int keyval); + +/* ---- Removed functions ---- */ + +#define MPI_Address MPI_Get_address + +#define MPI_Attr_delete MPI_Comm_delete_attr +#define MPI_Attr_get MPI_Comm_get_attr +#define MPI_Attr_put MPI_Comm_set_attr + +#define MPI_Errhandler_create MPI_Comm_create_errhandler +#define MPI_Errhandler_get MPI_Comm_get_errhandler +#define MPI_Errhandler_set MPI_Comm_set_errhandler + +#define MPI_Keyval_create MPI_Comm_create_keyval +#define MPI_Keyval_free MPI_Comm_free_keyval + +#define MPI_Type_hindexed MPI_Type_create_hindexed +#define MPI_Type_hvector MPI_Type_create_hvector +#define MPI_Type_struct MPI_Type_create_struct + +#define MPI_Type_extent MPI_ABI_Type_extent +#define MPI_Type_lb MPI_ABI_Type_lb +#define MPI_Type_ub MPI_ABI_Type_ub + +static inline int MPI_Type_extent(MPI_Datatype MPI_datatype, MPI_Aint * MPI_extent) +{ + MPI_Aint MPI_lb; + return MPI_Type_get_extent(MPI_datatype, &MPI_lb, MPI_extent); +} + +static inline int MPI_Type_lb(MPI_Datatype MPI_datatype, MPI_Aint * MPI_lb) +{ + MPI_Aint MPI_extent; + return MPI_Type_get_extent(MPI_datatype, MPI_lb, &MPI_extent); +} + +static inline int MPI_Type_ub(MPI_Datatype MPI_datatype, MPI_Aint * MPI_ub) +{ + MPI_Aint MPI_lb; + int MPI_ierr; + MPI_ierr = MPI_Type_get_extent(MPI_datatype, &MPI_lb, MPI_ub); + if (MPI_ierr == MPI_SUCCESS && MPI_ub) + *MPI_ub += MPI_lb; + return MPI_ierr; +} + +/* ---- Removed PMPI functions ---- */ + +#define PMPI_Address PMPI_Get_address + +#define PMPI_Attr_delete PMPI_Comm_delete_attr +#define PMPI_Attr_get PMPI_Comm_get_attr +#define PMPI_Attr_put PMPI_Comm_set_attr + +#define PMPI_Errhandler_create PMPI_Comm_create_errhandler +#define PMPI_Errhandler_get PMPI_Comm_get_errhandler +#define PMPI_Errhandler_set PMPI_Comm_set_errhandler + +#define PMPI_Keyval_create PMPI_Comm_create_keyval +#define PMPI_Keyval_free PMPI_Comm_free_keyval + +#define PMPI_Type_hindexed PMPI_Type_create_hindexed +#define PMPI_Type_hvector PMPI_Type_create_hvector +#define PMPI_Type_struct PMPI_Type_create_struct + +#define PMPI_Type_extent PMPI_ABI_Type_extent +#define PMPI_Type_lb PMPI_ABI_Type_lb +#define PMPI_Type_ub PMPI_ABI_Type_ub + +static inline int PMPI_Type_extent(MPI_Datatype MPI_datatype, MPI_Aint * MPI_extent) +{ + MPI_Aint MPI_lb; + return PMPI_Type_get_extent(MPI_datatype, &MPI_lb, MPI_extent); +} + +static inline int PMPI_Type_lb(MPI_Datatype MPI_datatype, MPI_Aint * MPI_lb) +{ + MPI_Aint MPI_extent; + return PMPI_Type_get_extent(MPI_datatype, MPI_lb, &MPI_extent); +} + +static inline int PMPI_Type_ub(MPI_Datatype MPI_datatype, MPI_Aint * MPI_ub) +{ + MPI_Aint MPI_lb; + int MPI_ierr; + MPI_ierr = PMPI_Type_get_extent(MPI_datatype, &MPI_lb, MPI_ub); + if (MPI_ierr == MPI_SUCCESS && MPI_ub) + *MPI_ub += MPI_lb; + return MPI_ierr; +} #if defined(__cplusplus) } #endif +#else +/* MPICH native ABI: the removed APIs are declared in mpi.h and mpi_proto.h */ +#endif /* MPI_ABI_VERSION */ + #endif /* MPI_LEGACY_H_INCLUDED */ From 3d3fd5f227c0af76a8c899720d4867c95a59f887 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 14:56:58 -0600 Subject: [PATCH 11/20] test: skip the MPI_LB and MPI_UB tests when mpi.h lacks them configure checks whether mpi.h provides MPI_LB and MPI_UB, which the MPI ABI does not even with -mpi-legacy, and builds and runs lbub_oldapi, typename_oldapi and struct_no_real_types only when it does. Previously these tests failed to compile against the MPI ABI. Model: Claude Opus 5.5 --- test/mpi/configure.ac | 14 ++++++++++++++ test/mpi/datatype/Makefile.am | 7 +++++-- test/mpi/datatype/testlist.in | 6 +++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/test/mpi/configure.ac b/test/mpi/configure.ac index 9728ac67f51..340b846b649 100644 --- a/test/mpi/configure.ac +++ b/test/mpi/configure.ac @@ -480,6 +480,20 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], [AC_MSG_RESULT([no]) CFLAGS="$saved_CFLAGS"]) +# MPI_LB and MPI_UB were removed from the MPI standard, and the MPI ABI does +# not provide them even with -mpi-legacy +AC_MSG_CHECKING([whether mpi.h provides MPI_LB and MPI_UB]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([#include "mpi.h"], + [MPI_Datatype lb = MPI_LB, ub = MPI_UB; return lb == ub;])], + [have_mpi_lb_ub=yes], [have_mpi_lb_ub=no]) +AC_MSG_RESULT([$have_mpi_lb_ub]) +lbub_tests="#" +if test "$have_mpi_lb_ub" = "yes" ; then + lbub_tests="" +fi +AC_SUBST(lbub_tests) +AM_CONDITIONAL([HAVE_MPI_LB_UB], [test "$have_mpi_lb_ub" = "yes"]) + # Check whether we are testing MPI derived from MPICH MPI_IS_MPICH=no AC_MSG_CHECKING([Is the MPI derived from MPICH]) diff --git a/test/mpi/datatype/Makefile.am b/test/mpi/datatype/Makefile.am index 3154fce8ffd..75511566a4c 100644 --- a/test/mpi/datatype/Makefile.am +++ b/test/mpi/datatype/Makefile.am @@ -86,12 +86,15 @@ noinst_PROGRAMS = \ if NOT_STRICTMPI noinst_PROGRAMS += \ indexed_misc_oldapi \ - lbub_oldapi \ simple_size_extent_oldapi \ + transpose_pack_oldapi +if HAVE_MPI_LB_UB +noinst_PROGRAMS += \ + lbub_oldapi \ struct_no_real_types \ - transpose_pack_oldapi \ typename_oldapi endif +endif # Some of the tests use a more comprehensive set of datatype tests. # These must specify a different LDADD that includes the object file diff --git a/test/mpi/datatype/testlist.in b/test/mpi/datatype/testlist.in index d5450c0ecc4..4382ec5d2ec 100644 --- a/test/mpi/datatype/testlist.in +++ b/test/mpi/datatype/testlist.in @@ -1,7 +1,7 @@ contents 1 gaddress 1 lbub 1 -lbub_oldapi 1 strict=FALSE +@lbub_tests@lbub_oldapi 1 strict=FALSE localpack 1 pack_external 1 simple_pack 1 @@ -16,7 +16,7 @@ struct_pack_mpi_bottom 1 struct_unpack_mpi_bottom 1 typecommit 1 typename 1 -typename_oldapi 1 strict=FALSE +@lbub_tests@typename_oldapi 1 strict=FALSE typefree 1 zeroparms 1 concurrent_irecv 3 @@ -46,7 +46,7 @@ pairtype_size_extent 1 simple_commit 1 simple_size_extent 1 simple_size_extent_oldapi 1 strict=FALSE -struct_no_real_types 1 strict=FALSE +@lbub_tests@struct_no_real_types 1 strict=FALSE struct_empty_el 1 contig_zero_count 1 simple_resized 1 From 6a66a3df0948d23bb6803f2e297a35a3d21ef5a9 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 15:27:17 -0600 Subject: [PATCH 12/20] mpicc: accept -mpix as an alias of -mpi-mpix The compiler wrappers now accept -mpix as a shorter form of -mpi-mpix, which makes mpi.h include mpix.h on the MPI ABI. Model: Claude Opus 5.5 --- src/env/mpicc.def | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/env/mpicc.def b/src/env/mpicc.def index cfab296f495..787f9a3de0f 100644 --- a/src/env/mpicc.def +++ b/src/env/mpicc.def @@ -381,7 +381,7 @@ subcode: parse_args subcode: parse_need_mpix $(block:parse_args_init) need_mpix= - &call case, -mpi-mpix + &call case, -mpi-mpix|-mpix need_mpix="yes" subcode: parse_need_fortran From ebf7199d54fb15c31f62f95ac2083fb621e18553 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 15:43:07 -0600 Subject: [PATCH 13/20] errhan: do not export MPIR_Err_* functions MPIR_Err_create_code and the MPIR_Err_return_* functions are no longer exported from libmpi and libmpi_abi. Their only users outside the error handling code are ROMIO and io_abi.c, which are linked into the same library. Also remove the declaration of MPIR_Err_return_file, which is not defined anywhere and was guarded by the never-defined MPI__FILE_DEFINED. Previously these internal functions were exported for the language binding libraries, which no longer use them. Model: Claude Opus 5.5 --- src/include/mpir_err.h | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/include/mpir_err.h b/src/include/mpir_err.h index e25adcc7f46..30235d174d1 100644 --- a/src/include/mpir_err.h +++ b/src/include/mpir_err.h @@ -17,17 +17,12 @@ struct MPIR_Errhandler; struct MPIR_Group; /* Bindings for internal routines */ -MPICH_API_PUBLIC int MPIR_Err_return_comm(struct MPIR_Comm *, const char[], int); -MPICH_API_PUBLIC int MPIR_Err_return_win(struct MPIR_Win *, const char[], int); -MPICH_API_PUBLIC int MPIR_Err_return_session(struct MPIR_Session *, const char[], int); -MPICH_API_PUBLIC int MPIR_Err_return_session_init(struct MPIR_Errhandler *, const char[], int); -MPICH_API_PUBLIC int MPIR_Err_return_group(struct MPIR_Group *, const char[], int); -MPICH_API_PUBLIC int MPIR_Err_return_comm_create_from_group(struct MPIR_Errhandler *, const char[], - int); -#ifdef MPI__FILE_DEFINED -/* Only define if we have MPI_File */ -MPICH_API_PUBLIC int MPIR_Err_return_file(MPI_File, const char[], int); /* Romio version */ -#endif +int MPIR_Err_return_comm(struct MPIR_Comm *, const char[], int); +int MPIR_Err_return_win(struct MPIR_Win *, const char[], int); +int MPIR_Err_return_session(struct MPIR_Session *, const char[], int); +int MPIR_Err_return_session_init(struct MPIR_Errhandler *, const char[], int); +int MPIR_Err_return_group(struct MPIR_Group *, const char[], int); +int MPIR_Err_return_comm_create_from_group(struct MPIR_Errhandler *, const char[], int); /* FIXME: * Update this description to match the current version of the routine, * in particular, the pseudo-format types (even better, fix it so that @@ -107,8 +102,7 @@ MPICH_API_PUBLIC int MPIR_Err_return_file(MPI_File, const char[], int); /* Romio Error @*/ -MPICH_API_PUBLIC int MPIR_Err_create_code(int, int, const char[], int, int, const char[], - const char[], ...); +int MPIR_Err_create_code(int, int, const char[], int, int, const char[], const char[], ...); int MPIR_Err_create_code_valist(int, int, const char[], int, int, const char[], const char[], va_list); From 9551dfa6cbe5d3650e7c41f0eb644d2c6add9274 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 15:48:31 -0600 Subject: [PATCH 14/20] binding/cxx: use MPIX keyval callbacks for attribute proxies The C++ binding now creates keyvals with MPIX_*_create_keyval_x, passing the user's C++ copy and delete functions in the extra_state and freeing it in the destructor, as it already does for user ops and errhandlers. The proxies handle NULL_COPY_FN and NULL_DELETE_FN themselves, since MPIX_*_create_keyval_x requires non-null callbacks. MPII_Keyval_set_proxy has no other user and is removed, so libmpi no longer exports it. Previously the C++ binding installed its proxies with the internal MPII_Keyval_set_proxy, which libmpi had to export. Model: Claude Opus 5.5 --- src/binding/cxx/buildiface | 117 ++++++++++++++++++++++++++++---- src/include/mpir_attr_generic.h | 4 -- src/mpi/attr/attrutil.c | 14 ---- 3 files changed, 104 insertions(+), 31 deletions(-) diff --git a/src/binding/cxx/buildiface b/src/binding/cxx/buildiface index 5038ed8316e..9abc5085858 100755 --- a/src/binding/cxx/buildiface +++ b/src/binding/cxx/buildiface @@ -2281,7 +2281,19 @@ void operator delete[](void *p) { # Keyval and attribute routines print $OUTFD <copy_fn) { + /* NULL_COPY_FN: do not copy */ + *flag = 0; + return MPI_SUCCESS; + } + return MPII_Comm_copy_attr_cxx_proxy((MPI_Comm_copy_attr_function *) p->copy_fn, comm, keyval, + p->extra_state, attrib, (void **) new_value, flag); +} + +static int CXX_Comm_delete_attr_proxy(MPI_Comm comm, int keyval, void *attrib, void *extra_state) +{ + CXX_keyval_state *p = (CXX_keyval_state *) extra_state; + if (!p->delete_fn) { + /* NULL_DELETE_FN */ + return MPI_SUCCESS; + } + return MPIR_Comm_delete_attr_cxx_proxy((MPI_Comm_delete_attr_function *) p->delete_fn, comm, + keyval, attrib, p->extra_state); +} + int Comm::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, void *extra_state ) { int keyval; @@ -2410,10 +2446,12 @@ int Comm::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, void EOT &printCoverageStart( $OUTFD, "Comm_create_keyval", 3 ); print $OUTFD <copy_fn = (void (*)(void)) cf; + p->delete_fn = (void (*)(void)) df; + p->extra_state = extra_state; + MPIX_CALLWORLD( MPIX_Comm_create_keyval_x( CXX_Comm_copy_attr_proxy, CXX_Comm_delete_attr_proxy, + CXX_keyval_free, &keyval, p ) ); EOT &printCoverageEnd( $OUTFD, "Comm_create_keyval", 3 ); print $OUTFD <copy_fn) { + /* NULL_COPY_FN: do not copy */ + *flag = 0; + return MPI_SUCCESS; + } + return MPIR_Type_copy_attr_cxx_proxy((MPI_Type_copy_attr_function *) p->copy_fn, datatype, + keyval, p->extra_state, attrib, (void **) new_value, flag); +} + +static int CXX_Type_delete_attr_proxy(MPI_Datatype datatype, int keyval, void *attrib, + void *extra_state) +{ + CXX_keyval_state *p = (CXX_keyval_state *) extra_state; + if (!p->delete_fn) { + /* NULL_DELETE_FN */ + return MPI_SUCCESS; + } + return MPIR_Type_delete_attr_cxx_proxy((MPI_Type_delete_attr_function *) p->delete_fn, datatype, + keyval, attrib, p->extra_state); +} + int Datatype::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, void *extra_state ) { int keyval; @@ -2464,10 +2527,12 @@ int Datatype::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, v EOT &printCoverageStart( $OUTFD, "Type_create_keyval", 3 ); print $OUTFD <copy_fn = (void (*)(void)) cf; + p->delete_fn = (void (*)(void)) df; + p->extra_state = extra_state; + MPIX_CALLWORLD( MPIX_Type_create_keyval_x( CXX_Type_copy_attr_proxy, CXX_Type_delete_attr_proxy, + CXX_keyval_free, &keyval, p ) ); EOT &printCoverageEnd( $OUTFD, "Type_create_keyval", 3 ); print $OUTFD <copy_fn) { + /* NULL_COPY_FN: do not copy */ + *flag = 0; + return MPI_SUCCESS; + } + return MPIR_Win_copy_attr_cxx_proxy((MPI_Win_copy_attr_function *) p->copy_fn, win, keyval, + p->extra_state, attrib, (void **) new_value, flag); +} + +static int CXX_Win_delete_attr_proxy(MPI_Win win, int keyval, void *attrib, void *extra_state) +{ + CXX_keyval_state *p = (CXX_keyval_state *) extra_state; + if (!p->delete_fn) { + /* NULL_DELETE_FN */ + return MPI_SUCCESS; + } + return MPIR_Win_delete_attr_cxx_proxy((MPI_Win_delete_attr_function *) p->delete_fn, win, + keyval, attrib, p->extra_state); +} + int Win::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, void *extra_state ) { int keyval; @@ -2518,10 +2607,12 @@ int Win::Create_keyval( Copy_attr_function *cf, Delete_attr_function *df, void * EOT &printCoverageStart( $OUTFD, "Win_create_keyval", 3 ); print $OUTFD <copy_fn = (void (*)(void)) cf; + p->delete_fn = (void (*)(void)) df; + p->extra_state = extra_state; + MPIX_CALLWORLD( MPIX_Win_create_keyval_x( CXX_Win_copy_attr_proxy, CXX_Win_delete_attr_proxy, + CXX_keyval_free, &keyval, p ) ); EOT &printCoverageEnd( $OUTFD, "Win_create_keyval", 3 ); print $OUTFD <copyfn.proxy = copy_proxy; - keyval_ptr->delfn.proxy = delete_proxy; -} From 36644202bc3c0c0947d33556eb5161ac241e51ef Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 17:55:02 -0600 Subject: [PATCH 15/20] mpicxx: link the C++ binding library mpicxx links libmpicxx when the C++ binding is built, and only for the MPICH ABI, since the C++ binding does not exist for the MPI ABI (mpicxx_abi, mpicxx -mpi-abi). Previously configure tested the literal string "enable_cxx" instead of $enable_cxx, so LMPICXXLIBNAME was always empty and C++ programs using the C++ binding failed to link. Model: Claude Opus 5.5 --- configure.ac | 2 +- src/env/mpicc.def | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index b41f123c731..abe6487efc3 100644 --- a/configure.ac +++ b/configure.ac @@ -2955,7 +2955,7 @@ fi AC_SUBST(LPMPILIBNAME) AC_SUBST(LPMPIABILIBNAME) -if test "enable_cxx" = "yes" ; then +if test "$enable_cxx" = "yes" ; then LMPICXXLIBNAME="-l${MPICXXLIBNAME}" else LMPICXXLIBNAME= diff --git a/src/env/mpicc.def b/src/env/mpicc.def index 787f9a3de0f..e8d9fd17bab 100644 --- a/src/env/mpicc.def +++ b/src/env/mpicc.def @@ -521,6 +521,10 @@ subcode: set_final_vars if [ "$mpi_abi" = no ] ; then mpi_libs_shared="-l@MPILIBNAME@ @LPMPILIBNAME@" mpi_libs_static="$libdir/lib@MPILIBNAME@.a @LPMPILIBNAME@" + $(if:cc=cxx) + # the C++ binding is only built on the MPICH ABI + mpi_libs_shared="@LMPICXXLIBNAME@ $mpi_libs_shared" + mpi_libs_static="@LMPICXXLIBNAME@ $mpi_libs_static" else final_cppflags="-DMPI_ABI ${final_cppflags}" mpi_libs_shared="-l@MPIABILIBNAME@ @LPMPIABILIBNAME@" @@ -564,9 +568,7 @@ subcode: set_cmd_macros \x23 suppressing linking, such as -c or -M. $(set:LD0=-L$libdir) - $(if:cc=cxx) - $(set:LD0.= @LMPICXXLIBNAME@) - $(elif:cc=fc) + $(if:cc=fc) $(set:LD0.= -l@MPIFCLIBNAME@) $(if:cc!=fc) From 822f98164cf996f2cd5001844a4f56fa189bece9 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 17:55:19 -0600 Subject: [PATCH 16/20] errhan: return the result of get_file_errhand in the MPI ABI build The MPI ABI version of get_file_errhand now returns the result of MPIR_ROMIO_Get_file_errhand, and initializes the errhandler so that it is not read uninitialized when the call fails. Previously the function had no return statement (-Wreturn-type in the MPI ABI build). Model: Claude Opus 5.5 --- src/mpi/errhan/errhan_file.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/mpi/errhan/errhan_file.c b/src/mpi/errhan/errhan_file.c index c9b85e96ca5..86e85849f52 100644 --- a/src/mpi/errhan/errhan_file.c +++ b/src/mpi/errhan/errhan_file.c @@ -17,13 +17,14 @@ int MPIR_ROMIO_Set_file_errhand(MPI_File, ABI_Errhandler); static int get_file_errhand(MPI_File file, MPI_Errhandler * eh_ptr) { - ABI_Errhandler eh_abi; + ABI_Errhandler eh_abi = NULL; int ret = MPIR_ROMIO_Get_file_errhand(file, &eh_abi); if (!eh_abi) { *eh_ptr = 0; } else { *eh_ptr = ABI_Errhandler_to_mpi(eh_abi); } + return ret; } static int set_file_errhand(MPI_File file, MPI_Errhandler eh) From 8054f41d699ff1a1745ef21f8685fd0c20f6b93e Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 18:15:11 -0600 Subject: [PATCH 17/20] binding/abi: count threads in the communicator size of a threadcomm ABI_Comm_rank and ABI_Comm_peer_size, which the MPI ABI wrappers use to size the per-peer arrays of collectives such as MPI_Alltoallw, now count threads on a threadcomm, as MPI_Comm_rank and MPI_Comm_size do. Previously they returned the process rank and size, so MPI_Alltoallw on a threadcomm converted too few datatypes and failed with "Invalid datatype". Model: Claude Opus 5.5 --- src/binding/abi/mpi_abi_util.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/binding/abi/mpi_abi_util.h b/src/binding/abi/mpi_abi_util.h index a362fd5fefd..16003469c0c 100644 --- a/src/binding/abi/mpi_abi_util.h +++ b/src/binding/abi/mpi_abi_util.h @@ -62,12 +62,15 @@ static inline MPIR_Comm *ABI_Comm_ptr(ABI_Comm comm_abi) return comm_ptr; } +/* rank and size count threads on a threadcomm, as in MPI_Comm_rank/size */ static inline int ABI_Comm_rank(ABI_Comm comm_abi) { MPIR_Comm *comm_ptr = ABI_Comm_ptr(comm_abi); int rank = MPI_PROC_NULL; if (comm_ptr != NULL) { - MPIR_Comm_rank_impl(comm_ptr, &rank); + int size; + MPIR_COMM_RANK_SIZE(comm_ptr, rank, size); + (void) size; } return rank; } @@ -82,7 +85,9 @@ static inline int ABI_Comm_peer_size(ABI_Comm comm_abi) if (flag) { MPIR_Comm_remote_size_impl(comm_ptr, &size); } else { - MPIR_Comm_size_impl(comm_ptr, &size); + int rank; + MPIR_COMM_RANK_SIZE(comm_ptr, rank, size); + (void) rank; } } return size; From 724876dc245677ba9f5355bb1eee56f0d64407f5 Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 18:15:11 -0600 Subject: [PATCH 18/20] test: run the impls/mpich tests on the MPICH MPI ABI When testing MPICH's MPI ABI, configure checks that the MPIX functions link with -mpi-mpix, then adds the flag and enables the impls/mpich tests, which exercise the MPIX extensions. Previously impls/mpich was enabled only for the MPICH ABI, since libmpi_abi did not provide the MPIX functions. Model: Claude Opus 5.5 --- test/mpi/configure.ac | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/test/mpi/configure.ac b/test/mpi/configure.ac index 340b846b649..00a3f52cabe 100644 --- a/test/mpi/configure.ac +++ b/test/mpi/configure.ac @@ -1673,9 +1673,21 @@ AC_SUBST(iodir) impldir="" # # Check for implementation to enable implementation-specific options -if test $enable_strictmpi != "yes" ; then - if test "$MPI_IS_MPICH" = "yes" ; then +if test "$MPI_IS_MPICH" = "yes" ; then + if test $enable_strictmpi != "yes" ; then impldir="mpich" + elif test "$enable_mpi_abi" = "yes" ; then + # MPICH's MPI ABI library provides the MPIX functions; mpi.h declares + # them with -mpi-mpix + AC_MSG_CHECKING([whether MPIX functions are available with -mpi-mpix]) + saved_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -mpi-mpix" + AC_LINK_IFELSE([AC_LANG_PROGRAM([#include "mpi.h"], + [return MPIX_Stream_toint(MPIX_STREAM_NULL);])], + [AC_MSG_RESULT([yes]) + impldir="mpich"], + [AC_MSG_RESULT([no]) + CFLAGS="$saved_CFLAGS"]) fi fi AC_SUBST(impldir) From 29d4b0c5c41d792d07f1c143dcdcc2c43b90604b Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Tue, 10 Nov 2026 21:33:41 -0600 Subject: [PATCH 19/20] include: include mpi_proto.h with quotes Include mpi_proto.h with quotes, like the other MPICH headers mpi.h includes. Previously it used angle brackets. Co-Authored-By: Claude Opus 5.5 --- src/include/mpi.h.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/mpi.h.in b/src/include/mpi.h.in index f12b53519ce..0e25ca6c3b5 100644 --- a/src/include/mpi.h.in +++ b/src/include/mpi.h.in @@ -997,7 +997,7 @@ int QMPI_Get_calling_address(QMPI_Context context, void **address) MPICH_API_PUB #if defined(__cplusplus) extern "C" { #endif -#include +#include "mpi_proto.h" #if defined(__cplusplus) } #endif From e0a0bde59386cc612a80e4814e9e8a1143d38e9c Mon Sep 17 00:00:00 2001 From: hzhou-muse Date: Mon, 9 Nov 2026 12:47:54 -0600 Subject: [PATCH 20/20] doc: add a design page for mpi.h and describe the removed APIs Add a design page describing the three modes in which mpi.h is consumed: the MPI ABI header, the MPICH ABI header, and the header for building libmpi_abi, how mpi.h.in is laid out for them, what the generated mpi_abi_internal.h provides in the library build, and the rules for editing mpi.h.in and mpix.h. Describe how -mpi-legacy maps the removed APIs to their replacements on the MPI ABI and that MPI_LB and MPI_UB are not available there, and add a CHANGES entry. Mention the -mpix alias of -mpi-mpix. Update the stand-alone Fortran binding page for the MPIX callbacks now being independent of --disable-fortran-mpix. Model: Claude Opus 5.5 --- CHANGES | 6 +- doc/wiki/design/Design_Documentation_Index.md | 1 + doc/wiki/design/MPI_Header.md | 125 ++++++++++++++++++ doc/wiki/design/Standalone_Fortran_Binding.md | 21 ++- doc/wiki/how_to/MPI_ABI_Build_Interface.md | 17 ++- 5 files changed, 159 insertions(+), 11 deletions(-) create mode 100644 doc/wiki/design/MPI_Header.md diff --git a/CHANGES b/CHANGES index 131abd14553..0f09ded2be3 100644 --- a/CHANGES +++ b/CHANGES @@ -15,7 +15,11 @@ from the MPI C library. mpifort now explicitly links -lmpi (or -lmpi_abi). # Split mpix.h from mpi.h. MPIX constants are available with ABI conversion support. - libmpi_abi provides the MPIX functions (mpicc -mpi-mpix). + libmpi_abi provides the MPIX functions (mpicc -mpi-mpix, or its alias -mpix). + +# libmpi_abi no longer exports the APIs removed from the MPI standard. With + mpicc -mpi-legacy, mpi_legacy.h maps them to their replacements; MPI_LB and + MPI_UB are not available in the MPI ABI. # Added circulant graph (circ_graph) algorithms for Bcast, Reduce, Allgather, and nonblocking IBcast. diff --git a/doc/wiki/design/Design_Documentation_Index.md b/doc/wiki/design/Design_Documentation_Index.md index b10e5c5ccd9..3a6558114c1 100644 --- a/doc/wiki/design/Design_Documentation_Index.md +++ b/doc/wiki/design/Design_Documentation_Index.md @@ -42,6 +42,7 @@ - [Overriding Collective Functions](Overriding_Collective_Functions.md) - Language Bindings + - [The `mpi.h` Header](MPI_Header.md) - [Fortran Bindings](Fortran_Binding.md) - [Stand-Alone Fortran Binding](Standalone_Fortran_Binding.md) diff --git a/doc/wiki/design/MPI_Header.md b/doc/wiki/design/MPI_Header.md new file mode 100644 index 00000000000..af744dc362c --- /dev/null +++ b/doc/wiki/design/MPI_Header.md @@ -0,0 +1,125 @@ +# The `mpi.h` Header + +This page describes how `src/include/mpi.h.in` is organized. One installed +`mpi.h` serves two ABIs, the MPICH ABI and the MPI ABI of MPI-5.0, and it is +also the header the MPI ABI library itself is compiled with. For the +user-facing side (configure options, `mpicc` flags, installed files), see +[MPI ABI Build Interface](../how_to/MPI_ABI_Build_Interface.md). + +## The Three Modes + +`mpi.h` is consumed in three modes, selected by two macros: + +| Mode | Consumer | `MPI_ABI` | `MPICH_BUILD_MPI_ABI` | Set by | +|---|---|---|---|---| +| 1. MPI ABI header | user code built for `libmpi_abi` | defined | – | `mpicc` for the MPI ABI (`src/env/mpicc.def`) | +| 2. MPICH ABI header | user code built for `libmpi`, and the `libmpi` build itself | – | – | default | +| 3. MPI ABI library build | the MPICH sources compiled into `libmpi_abi` | – | defined | `abi_cppflags` in `Makefile.am` | + +`MPI_ABI` is an input switch: it picks the branch of `mpi.h`, but it is not +what code should test afterwards. To tell which ABI a header provides, test +the macros the header defines: + +- `MPICH` is defined in every mode, so code can tell that the header comes + from MPICH whichever ABI it is. +- `MPI_ABI_VERSION` is defined only by the MPI ABI header (`mpi_abi.h`), as + the MPI standard requires. MPICH's own headers, such as `mpix.h`, use it + to branch between the two ABIs. + +## Layout of mpi.h.in + +``` +#define MPICH always +#ifdef MPI_ABI -- mode 1 + #include "mpi_abi.h" + #include "mpix.h" if MPI_MPIX + #include "mpi_legacy.h" if MPI_LEGACY + #include "mpi_fortran.h" if MPI_FORTRAN +#else -- modes 2 and 3 + #define MPI_MPIX MPIX is always on + #ifdef MPICH_BUILD_MPI_ABI -- mode 3 only + #include "mpi_abi_internal.h" + #endif + ... MPICH native types and constants ... + #ifndef MPICH_BUILD_MPI_ABI -- mode 2 only + #include "mpix.h" + #include "mpi_proto.h" + #include "mpicxx.h" if C++ + #include "mpi_fortran.h" if MPI_FORTRAN + #endif +#endif +``` + +### Mode 1: MPI ABI header + +`mpi.h` is only a switch: everything comes from `mpi_abi.h`, the standard +ABI header kept in sync with the MPI Forum's `mpi-abi-stubs` +(`src/binding/abi/mpi_abi.h`). The MPICH-specific parts are opt-in, because +code that uses them is no longer portable across MPI ABI implementations: + +| Macro | `mpicc` flag | Header | Provides | +|---|---|---|---| +| `MPI_MPIX` | `-mpi-mpix` (alias `-mpix`) | `mpix.h` | MPIX extensions | +| `MPI_LEGACY` | `-mpi-legacy` | `mpi_legacy.h` | APIs removed from the MPI standard, mapped to their replacements (no `MPI_LB`/`MPI_UB`) | +| `MPI_FORTRAN` | `-mpi-fortran` | `mpi_fortran.h` | Fortran interop (`MPI_Fint`, f2c/c2f), see [Stand-Alone Fortran Binding](Standalone_Fortran_Binding.md) | + +### Mode 2: MPICH ABI header + +This is the traditional MPICH `mpi.h`. Handles are `int`s with MPICH's own +encoding. `MPI_MPIX` is always defined, so `mpix.h` is always included. +Prototypes come from the generated `mpi_proto.h`, which also declares the +APIs removed from the standard; `mpi_legacy.h` is not used in this mode. +`mpix.h` comes before `mpi_proto.h` because `mpi_proto.h` declares the MPIX +functions too, and their types (`MPIX_Stream`, `MPIX_Iov`, ...) are defined +in `mpix.h`. `mpicxx.h` is included if the C++ binding is configured. + +### Mode 3: MPI ABI library build + +`libmpi_abi` is built from the same sources as `libmpi`, with +`-DMPICH_BUILD_MPI_ABI`. The internals keep using MPICH's native handles, +while the public functions take MPI ABI handles and convert them. To make +this work, `mpi.h` first includes `mpi_abi_internal.h`, which +`maint/gen_abi.py` generates from `mpi_abi.h` and `mpix.h`: + +| From the MPI ABI headers | In `mpi_abi_internal.h` | Why | +|---|---|---| +| Handle types and constants, e.g. `MPI_Comm`, `MPI_COMM_WORLD` | renamed `ABI_Comm`, `ABI_COMM_WORLD` | the native `MPI_Comm` and `MPI_COMM_WORLD` follow in `mpi.h` and are what the internals use | +| Integer constants, e.g. `MPI_COMM_TYPE_SHARED` | kept, with the MPI ABI value (221) | the internals are compiled with the ABI values, so these need no conversion | +| `MPI_`/`MPIX_` prototypes | handle parameters use `ABI_` types, plus `MPICH_API_PUBLIC` | these are the functions `libmpi_abi` exports | + +The rest of `mpi.h` then defines the native types and handle constants as in +mode 2. The native integer constants that the MPI ABI defines differently, +such as `MPI_COMM_TYPE_SHARED` (1 in the MPICH ABI), sit inside +`#ifndef MPICH_BUILD_MPI_ABI` blocks, so the ABI values from +`mpi_abi_internal.h` win. The tail of `mpi.h` (`mpix.h`, `mpi_proto.h`, +C++, `mpi_fortran.h`) is skipped; the MPIX declarations already come from +`mpi_abi_internal.h`. + +The public functions are the generated wrappers in +`src/binding/abi/c_binding_abi.c`. They convert handle arguments with the +`ABI__to_mpi` and `ABI__from_mpi` functions in +`src/binding/abi/mpi_abi_util.h`, and pass everything else through. The +datatype and op conversion tables come from `mpi_abi_util.c`, also generated +by `maint/gen_abi.py`. + +In a dual build (`--enable-mpi-abi=dual`) every source is compiled twice, once +in mode 2 for `libmpi` and once in mode 3 for `libmpi_abi`, so a constant can +have different values in the two libraries. + +ROMIO does not go through `mpi.h` in this mode: its build includes the +generated `romio_abi_internal.h`, which keeps the MPI ABI types +(`src/mpi/romio/adio/include/adio.h`). + +## Rules for Editing mpi.h.in + +- A native integer constant that the MPI ABI also defines goes inside an + `#ifndef MPICH_BUILD_MPI_ABI` block, so mode 3 gets the ABI value. +- Native handle types and handle constants stay outside those blocks; mode 3 + needs them for the internals. +- MPIX constants go in `mpix.h`. Those passed through `libmpi_abi` + unconverted and with no conflict in either ABI are defined once, for both + ABIs. Those that differ, such as handles, are defined in the + `#ifdef MPI_ABI_VERSION` branch of `mpix.h` for the MPI ABI and in + `mpi.h.in` for the MPICH ABI. +- After changing a header that `maint/gen_abi.py` reads, check the generated + `src/binding/abi/mpi_abi_internal.h` to see what mode 3 gets. diff --git a/doc/wiki/design/Standalone_Fortran_Binding.md b/doc/wiki/design/Standalone_Fortran_Binding.md index 885613460f3..4fdcfce1f26 100644 --- a/doc/wiki/design/Standalone_Fortran_Binding.md +++ b/doc/wiki/design/Standalone_Fortran_Binding.md @@ -202,8 +202,8 @@ else: ## Fallback Without MPIX When building against an MPI implementation that does not provide these -MPIX extensions (or with `--disable-fortran-mpix`), the binding falls -back to standard MPI functions with degraded behavior: +MPIX extensions, the binding falls back to standard MPI functions with +degraded behavior: | Feature | With MPIX | Fallback (without MPIX) | |---------|-----------|------------------------| @@ -212,6 +212,11 @@ back to standard MPI functions with degraded behavior: | Error handler | Proxy converts handle to `MPI_Fint` | Fortran function called directly; handle argument is a C pointer, **unusable in Fortran** | | Attr get/set | Uses `MPIX_*_as_fortran` with correct Fortran value semantics | Uses `MPI_*_get_attr` / `MPI_*_set_attr` with C pointer semantics (see notes below) | +The first three rows depend only on whether the C library provides the +MPIX callbacks (`HAS_MPIX_CALLBACKS`). The attribute get/set row depends on +whether the binding includes the MPIX routines (`--disable-fortran-mpix`, +and always off on the MPI ABI for now). + The fallback is functional for programs that do not inspect callback arguments (e.g. error handlers that only print the error code, or ops that ignore the datatype). @@ -238,11 +243,15 @@ AC_CHECK_FUNCS([MPIX_Comm_create_keyval_x], [has_mpix_callbacks=yes], [has_mpix_callbacks=no]) ``` -If not found, `HAS_MPIX_CALLBACKS` is not defined and the Python binding -generators receive `-skip-mpix` to omit MPIX function wrappers from the -generated Fortran bindings. +In-tree builds assume the callbacks on both ABIs. When they are available, +`HAS_MPIX_CALLBACKS` and `MPI_MPIX` (so that `mpi.h` declares them) are +defined and the proxies use them, independent of `--disable-fortran-mpix`. -Users can explicitly disable with `--disable-fortran-mpix`. +Separately, `enable_fortran_mpix` decides whether the generated bindings +include the MPIX routines; otherwise the Python binding generators receive +`-skip-mpix`. It defaults to whether the callbacks were found, can be +turned off with `--disable-fortran-mpix`, and is always off on the MPI ABI +for now. ## Fortran Initialization: `MPIX_Init_fortran` diff --git a/doc/wiki/how_to/MPI_ABI_Build_Interface.md b/doc/wiki/how_to/MPI_ABI_Build_Interface.md index 541aa6385a9..8962d76f7a9 100644 --- a/doc/wiki/how_to/MPI_ABI_Build_Interface.md +++ b/doc/wiki/how_to/MPI_ABI_Build_Interface.md @@ -124,7 +124,8 @@ the optional parts (see `src/include/mpi.h.in`). ### `-mpi-mpix` -Defines `MPI_MPIX`, which causes `mpi.h` to include `mpix.h`. This +Defines `MPI_MPIX`, which causes `mpi.h` to include `mpix.h`. `-mpix` is +a shorter alias. This provides access to MPIX extension functions (e.g. `MPIX_Query_cuda_support`). The MPIX declarations are split into a separate header because @@ -154,8 +155,16 @@ that loads both `libmpi_abi.so` and `libmpi.so` (see the warning above). ### `-mpi-legacy` Defines `MPI_LEGACY`, which causes `mpi.h` to include `mpi_legacy.h`. -This provides deprecated or removed MPI symbols for backward -compatibility. +This provides the APIs removed from the MPI standard for source +compatibility with old codes. On the MPI ABI they are mapped to their +replacements with macros and static inline functions (e.g. `MPI_Address` +to `MPI_Get_address`), so `libmpi_abi` exports no removed symbol and the +program runs on any MPI ABI implementation. `MPI_LB` and `MPI_UB` are +not provided on the MPI ABI, because they only work if the library +interprets them; use `MPI_Type_create_resized` instead. + +With the MPICH ABI the removed APIs are always available as real +functions in `libmpi`, and the flag has no effect. ## What Gets Built and Installed @@ -191,7 +200,7 @@ from `main` installs `libmpi.so.0`; stable releases restore the | `mpi_abi.h` | MPI ABI is built | The standard MPI ABI header (`MPI_ABI_VERSION` 1, `MPI_ABI_SUBVERSION` 0). | | `mpi_proto.h` | MPICH ABI is built | MPICH ABI prototypes. | | `mpix.h` | always | MPICH extensions (`MPIX_`), see `-mpi-mpix`. | -| `mpi_legacy.h` | always | Deprecated or removed MPI symbols, see `-mpi-legacy`. | +| `mpi_legacy.h` | always | APIs removed from the MPI standard, for the MPI ABI, see `-mpi-legacy`. | | `mpi_fortran.h` | the Fortran binding is built | Fortran interoperability for C code, see `-mpi-fortran`. | ### Tools