From 578b8b3e5005584b1cf1f2ed3df8e3b3ad27cc33 Mon Sep 17 00:00:00 2001 From: Tomislav Janjusic Date: Tue, 24 Feb 2026 22:03:17 -0600 Subject: [PATCH 1/2] ompi: fix optional Fortran predefined datatypes per MPI-5 section 20.4 MPI-5 section 20.4 requires that all optional predefined datatype handles are always present in mpi.h, and that unavailable types are detected at runtime via MPI_Type_size returning MPI_UNDEFINED. Two issues are fixed: 1. mpi.h.in: remove #if OMPI_HAVE_FORTRAN_* guards around the 24 optional Fortran predefined datatype #define macros (MPI_LOGICAL1/2/4/8/16, MPI_INTEGER1/2/4/8/16, MPI_REAL2/4/8/16, MPI_COMPLEX4/8/16/32, MPI_DOUBLE_COMPLEX). The underlying global variables are always defined (either as a real type or via OMPI_DATATYPE_INIT_UNAVAILABLE), so the handles can safely be unconditional. 2. MPI_Type_size / MPI_Type_size_x: add an opal_datatype_is_valid() check so that types initialized with OPAL_DATATYPE_FLAG_UNAVAILABLE return MPI_UNDEFINED instead of 0. Fixes: https://github.com/open-mpi/ompi/issues/13741 Signed-off-by: Tomislav Janjusic --- ompi/include/mpi.h.in | 36 ------------------------------------ ompi/mpi/c/type_size.c.in | 6 +++++- ompi/mpi/c/type_size_x.c.in | 6 +++++- 3 files changed, 10 insertions(+), 38 deletions(-) diff --git a/ompi/include/mpi.h.in b/ompi/include/mpi.h.in index e06865b182f..15741817c9f 100644 --- a/ompi/include/mpi.h.in +++ b/ompi/include/mpi.h.in @@ -1334,64 +1334,28 @@ OMPI_DECLSPEC extern struct ompi_predefined_datatype_t ompi_mpi_ub; /* Fortran datatype bindings */ #define MPI_CHARACTER OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_character) #define MPI_LOGICAL OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_logical) -#if OMPI_HAVE_FORTRAN_LOGICAL1 #define MPI_LOGICAL1 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_logical1) -#endif -#if OMPI_HAVE_FORTRAN_LOGICAL2 #define MPI_LOGICAL2 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_logical2) -#endif -#if OMPI_HAVE_FORTRAN_LOGICAL4 #define MPI_LOGICAL4 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_logical4) -#endif -#if OMPI_HAVE_FORTRAN_LOGICAL8 #define MPI_LOGICAL8 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_logical8) -#endif -#if OMPI_HAVE_FORTRAN_LOGICAL16 #define MPI_LOGICAL16 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_logical16) -#endif #define MPI_INTEGER OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_integer) -#if OMPI_HAVE_FORTRAN_INTEGER1 #define MPI_INTEGER1 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_integer1) -#endif -#if OMPI_HAVE_FORTRAN_INTEGER2 #define MPI_INTEGER2 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_integer2) -#endif -#if OMPI_HAVE_FORTRAN_INTEGER4 #define MPI_INTEGER4 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_integer4) -#endif -#if OMPI_HAVE_FORTRAN_INTEGER8 #define MPI_INTEGER8 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_integer8) -#endif -#if OMPI_HAVE_FORTRAN_INTEGER16 #define MPI_INTEGER16 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_integer16) -#endif #define MPI_REAL OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_real) -#if OMPI_HAVE_FORTRAN_REAL2 #define MPI_REAL2 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_real2) -#endif -#if OMPI_HAVE_FORTRAN_REAL4 #define MPI_REAL4 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_real4) -#endif -#if OMPI_HAVE_FORTRAN_REAL8 #define MPI_REAL8 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_real8) -#endif -#if OMPI_HAVE_FORTRAN_REAL16 #define MPI_REAL16 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_real16) -#endif #define MPI_DOUBLE_PRECISION OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_dblprec) #define MPI_COMPLEX OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_cplex) -#if OMPI_HAVE_FORTRAN_REAL2 #define MPI_COMPLEX4 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_complex4) -#endif -#if OMPI_HAVE_FORTRAN_REAL4 #define MPI_COMPLEX8 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_complex8) -#endif -#if OMPI_HAVE_FORTRAN_REAL8 #define MPI_COMPLEX16 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_complex16) -#endif -#if OMPI_HAVE_FORTRAN_REAL16 #define MPI_COMPLEX32 OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_complex32) -#endif #define MPI_DOUBLE_COMPLEX OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_dblcplex) #define MPI_2REAL OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_2real) #define MPI_2DOUBLE_PRECISION OMPI_PREDEFINED_GLOBAL(MPI_Datatype, ompi_mpi_2dblprec) diff --git a/ompi/mpi/c/type_size.c.in b/ompi/mpi/c/type_size.c.in index 6e0897dd7aa..1c74c4dd273 100644 --- a/ompi/mpi/c/type_size.c.in +++ b/ompi/mpi/c/type_size.c.in @@ -51,7 +51,11 @@ PROTOTYPE ERROR_CLASS type_size(DATATYPE type, COUNT_OUT size) opal_datatype_type_size ( &type->super, &type_size); - *size = (type_size > (size_t) INT_MAX) ? MPI_UNDEFINED : (int) type_size; + if (!opal_datatype_is_valid(&type->super)) { + *size = MPI_UNDEFINED; + } else { + *size = (type_size > (size_t) INT_MAX) ? MPI_UNDEFINED : (int) type_size; + } return MPI_SUCCESS; } diff --git a/ompi/mpi/c/type_size_x.c.in b/ompi/mpi/c/type_size_x.c.in index ded1005acc6..006ebebcaf4 100644 --- a/ompi/mpi/c/type_size_x.c.in +++ b/ompi/mpi/c/type_size_x.c.in @@ -51,7 +51,11 @@ PROTOTYPE ERROR_CLASS type_size_x(DATATYPE type, ELEMENT_COUNT size) opal_datatype_type_size ( &type->super, &type_size); - *size = (type_size > (size_t) MPI_COUNT_MAX) ? MPI_UNDEFINED : (MPI_Count) type_size; + if (!opal_datatype_is_valid(&type->super)) { + *size = MPI_UNDEFINED; + } else { + *size = (type_size > (size_t) MPI_COUNT_MAX) ? MPI_UNDEFINED : (MPI_Count) type_size; + } return MPI_SUCCESS; } From f4cc981cb56400b4ec9a1e9bb46bdc957e30255a Mon Sep 17 00:00:00 2001 From: Tomislav Janjusic Date: Tue, 24 Feb 2026 22:03:35 -0600 Subject: [PATCH 2/2] test/datatype: add sizedtypes test for optional Fortran predefined types Adds a new test that verifies MPI_Type_size behavior for all 24 optional Fortran predefined datatypes (MPI_LOGICAL1/2/4/8/16, MPI_INTEGER1/2/4/8/16, MPI_REAL2/4/8/16, MPI_COMPLEX4/8/16/32, MPI_DOUBLE_COMPLEX) as required by MPI-5 section 20.4. For each type, the test calls MPI_Type_size and asserts: - the correct size (OMPI_SIZEOF_FORTRAN_*) when the type is available (OMPI_HAVE_FORTRAN_* is set), or - MPI_UNDEFINED when the type is not available on the platform. The test is integrated into the existing test/datatype make check suite. Signed-off-by: Tomislav Janjusic --- test/datatype/Makefile.am | 8 +- test/datatype/sizedtypes.c | 146 +++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 test/datatype/sizedtypes.c diff --git a/test/datatype/Makefile.am b/test/datatype/Makefile.am index 3d6fd3289b5..014a520bbf7 100644 --- a/test/datatype/Makefile.am +++ b/test/datatype/Makefile.am @@ -15,7 +15,7 @@ # if PROJECT_OMPI - MPI_TESTS = checksum position position_noncontig ddt_test ddt_raw ddt_raw2 unpack_ooo ddt_pack external32 large_data partial + MPI_TESTS = checksum position position_noncontig ddt_test ddt_raw ddt_raw2 unpack_ooo ddt_pack external32 large_data partial sizedtypes MPI_CHECKS = to_self reduce_local endif TESTS = opal_datatype_test unpack_hetero $(MPI_TESTS) @@ -108,5 +108,11 @@ partial_LDADD = \ $(top_builddir)/ompi/lib@OMPI_LIBMPI_NAME@.la \ $(top_builddir)/opal/lib@OPAL_LIB_NAME@.la +sizedtypes_SOURCES = sizedtypes.c +sizedtypes_LDFLAGS = $(OMPI_PKG_CONFIG_LDFLAGS) +sizedtypes_LDADD = \ + $(top_builddir)/ompi/lib@OMPI_LIBMPI_NAME@.la \ + $(top_builddir)/opal/lib@OPAL_LIB_NAME@.la + distclean-local: rm -rf *.dSYM .deps .libs *.log *.o *.trs $(check_PROGRAMS) Makefile diff --git a/test/datatype/sizedtypes.c b/test/datatype/sizedtypes.c new file mode 100644 index 00000000000..9b1fd4a1316 --- /dev/null +++ b/test/datatype/sizedtypes.c @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2024 Triad National Security, LLC. All rights + * reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +/* + * Test that all optional Fortran predefined datatypes are always defined in + * mpi.h (per MPI-5 section 20.4), and that MPI_Type_size returns + * MPI_UNDEFINED for types that are not supported on the current platform. + */ + +#include "ompi_config.h" + +#include +#include +#include "mpi.h" + +#define CHECK_TYPE(type, name, expected) \ + do { \ + MPI_Type_size(type, &size); \ + if (size != (expected)) { \ + fprintf(stderr, "FAIL: MPI_Type_size(%s) = %d, expected %d\n", \ + name, size, (expected)); \ + errors++; \ + } \ + } while (0) + +int main(int argc, char *argv[]) +{ + int size; + int errors = 0; + + MPI_Init(&argc, &argv); + +#if OMPI_HAVE_FORTRAN_LOGICAL1 + CHECK_TYPE(MPI_LOGICAL1, "MPI_LOGICAL1", OMPI_SIZEOF_FORTRAN_LOGICAL1); +#else + CHECK_TYPE(MPI_LOGICAL1, "MPI_LOGICAL1", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_LOGICAL2 + CHECK_TYPE(MPI_LOGICAL2, "MPI_LOGICAL2", OMPI_SIZEOF_FORTRAN_LOGICAL2); +#else + CHECK_TYPE(MPI_LOGICAL2, "MPI_LOGICAL2", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_LOGICAL4 + CHECK_TYPE(MPI_LOGICAL4, "MPI_LOGICAL4", OMPI_SIZEOF_FORTRAN_LOGICAL4); +#else + CHECK_TYPE(MPI_LOGICAL4, "MPI_LOGICAL4", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_LOGICAL8 + CHECK_TYPE(MPI_LOGICAL8, "MPI_LOGICAL8", OMPI_SIZEOF_FORTRAN_LOGICAL8); +#else + CHECK_TYPE(MPI_LOGICAL8, "MPI_LOGICAL8", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_LOGICAL16 + CHECK_TYPE(MPI_LOGICAL16, "MPI_LOGICAL16", OMPI_SIZEOF_FORTRAN_LOGICAL16); +#else + CHECK_TYPE(MPI_LOGICAL16, "MPI_LOGICAL16", MPI_UNDEFINED); +#endif + +#if OMPI_HAVE_FORTRAN_INTEGER1 + CHECK_TYPE(MPI_INTEGER1, "MPI_INTEGER1", OMPI_SIZEOF_FORTRAN_INTEGER1); +#else + CHECK_TYPE(MPI_INTEGER1, "MPI_INTEGER1", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_INTEGER2 + CHECK_TYPE(MPI_INTEGER2, "MPI_INTEGER2", OMPI_SIZEOF_FORTRAN_INTEGER2); +#else + CHECK_TYPE(MPI_INTEGER2, "MPI_INTEGER2", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_INTEGER4 + CHECK_TYPE(MPI_INTEGER4, "MPI_INTEGER4", OMPI_SIZEOF_FORTRAN_INTEGER4); +#else + CHECK_TYPE(MPI_INTEGER4, "MPI_INTEGER4", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_INTEGER8 + CHECK_TYPE(MPI_INTEGER8, "MPI_INTEGER8", OMPI_SIZEOF_FORTRAN_INTEGER8); +#else + CHECK_TYPE(MPI_INTEGER8, "MPI_INTEGER8", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_INTEGER16 + CHECK_TYPE(MPI_INTEGER16, "MPI_INTEGER16", OMPI_SIZEOF_FORTRAN_INTEGER16); +#else + CHECK_TYPE(MPI_INTEGER16, "MPI_INTEGER16", MPI_UNDEFINED); +#endif + +#if OMPI_HAVE_FORTRAN_REAL2 + CHECK_TYPE(MPI_REAL2, "MPI_REAL2", OMPI_SIZEOF_FORTRAN_REAL2); +#else + CHECK_TYPE(MPI_REAL2, "MPI_REAL2", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_REAL4 + CHECK_TYPE(MPI_REAL4, "MPI_REAL4", OMPI_SIZEOF_FORTRAN_REAL4); +#else + CHECK_TYPE(MPI_REAL4, "MPI_REAL4", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_REAL8 + CHECK_TYPE(MPI_REAL8, "MPI_REAL8", OMPI_SIZEOF_FORTRAN_REAL8); +#else + CHECK_TYPE(MPI_REAL8, "MPI_REAL8", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_REAL16 + CHECK_TYPE(MPI_REAL16, "MPI_REAL16", OMPI_SIZEOF_FORTRAN_REAL16); +#else + CHECK_TYPE(MPI_REAL16, "MPI_REAL16", MPI_UNDEFINED); +#endif + +#if OMPI_HAVE_FORTRAN_COMPLEX4 + CHECK_TYPE(MPI_COMPLEX4, "MPI_COMPLEX4", OMPI_SIZEOF_FORTRAN_COMPLEX4); +#else + CHECK_TYPE(MPI_COMPLEX4, "MPI_COMPLEX4", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_COMPLEX8 + CHECK_TYPE(MPI_COMPLEX8, "MPI_COMPLEX8", OMPI_SIZEOF_FORTRAN_COMPLEX8); +#else + CHECK_TYPE(MPI_COMPLEX8, "MPI_COMPLEX8", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_COMPLEX16 + CHECK_TYPE(MPI_COMPLEX16, "MPI_COMPLEX16", OMPI_SIZEOF_FORTRAN_COMPLEX16); +#else + CHECK_TYPE(MPI_COMPLEX16, "MPI_COMPLEX16", MPI_UNDEFINED); +#endif +#if OMPI_HAVE_FORTRAN_COMPLEX32 + CHECK_TYPE(MPI_COMPLEX32, "MPI_COMPLEX32", OMPI_SIZEOF_FORTRAN_COMPLEX32); +#else + CHECK_TYPE(MPI_COMPLEX32, "MPI_COMPLEX32", MPI_UNDEFINED); +#endif + +#if OMPI_HAVE_FORTRAN_DOUBLE_COMPLEX + CHECK_TYPE(MPI_DOUBLE_COMPLEX, "MPI_DOUBLE_COMPLEX", OMPI_SIZEOF_FORTRAN_DOUBLE_COMPLEX); +#else + CHECK_TYPE(MPI_DOUBLE_COMPLEX, "MPI_DOUBLE_COMPLEX", MPI_UNDEFINED); +#endif + + MPI_Finalize(); + if (errors > 0) { + fprintf(stderr, "%d error(s) found\n", errors); + return 1; + } + return 0; +}