1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
2 /*
3 * Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
4 * University Research and Technology
5 * Corporation. All rights reserved.
6 * Copyright (c) 2004-2015 The University of Tennessee and The University
7 * of Tennessee Research Foundation. All rights
8 * reserved.
9 * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
10 * University of Stuttgart. All rights reserved.
11 * Copyright (c) 2004-2005 The Regents of the University of California.
12 * All rights reserved.
13 * Copyright (c) 2006-2009 Sun Microsystems, Inc. All rights reserved.
14 * Copyright (c) 2008-2018 Cisco Systems, Inc. All rights reserved
15 * Copyright (c) 2013 Los Alamos National Security, LLC. All rights
16 * reserved.
17 * Copyright (c) 2015 Research Organization for Information Science
18 * and Technology (RIST). All rights reserved.
19 * Copyright (c) 2017 IBM Corporation. All rights reserved.
20 * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved.
21 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved.
22 * $COPYRIGHT$
23 *
24 * Additional copyrights may follow
25 *
26 * $HEADER$
27 */
28
29 #include "ompi_config.h"
30
31 #include <float.h>
32
33 #include "opal/util/printf.h"
34
35 #include "ompi/mpi/c/bindings.h"
36 #include "ompi/runtime/params.h"
37 #include "ompi/communicator/communicator.h"
38 #include "ompi/errhandler/errhandler.h"
39
40 #if OMPI_BUILD_MPI_PROFILING
41 #if OPAL_HAVE_WEAK_SYMBOLS
42 #pragma weak MPI_Type_create_f90_real = PMPI_Type_create_f90_real
43 #endif
44 #define MPI_Type_create_f90_real PMPI_Type_create_f90_real
45 #endif
46
47 static const char FUNC_NAME[] = "MPI_Type_create_f90_real";
48
49
50 int MPI_Type_create_f90_real(int p, int r, MPI_Datatype *newtype)
51 {
52 uint64_t key;
53 int p_key, r_key;
54 int sflt_dig = 3, sflt_max_10_exp = +5, sflt_min_10_exp = -4;
55
56 OPAL_CR_NOOP_PROGRESS();
57
58 if (MPI_PARAM_CHECK) {
59 OMPI_ERR_INIT_FINALIZE(FUNC_NAME);
60
61 /* Note: These functions accept negative integers for the p and r
62 * arguments. This is because for the SELECTED_REAL_KIND,
63 * negative numbers are equivalent to zero values. See section
64 * 13.14.95 of the Fortran 95 standard. */
65
66 if ((MPI_UNDEFINED == p && MPI_UNDEFINED == r)) {
67 return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_ARG, FUNC_NAME);
68 }
69 }
70
71 /* if the user does not care about p or r set them to 0 so the
72 * test associate with them will always succeed.
73 */
74 p_key = p;
75 r_key = r;
76 if( MPI_UNDEFINED == p ) p_key = 0;
77 if( MPI_UNDEFINED == r ) r_key = 0;
78
79 /**
80 * With respect to the MPI standard, MPI-2.0 Sect. 10.2.5, MPI_TYPE_CREATE_F90_xxxx,
81 * page 295, line 47 we handle this nicely by caching the values in a hash table.
82 * However, as the value of might not always make sense, a little bit of optimization
83 * might be a good idea. Therefore, first we try to see if we can handle the value
84 * with some kind of default value, and if it's the case then we look into the
85 * cache.
86 */
87
88 if ( (LDBL_DIG < p) || (LDBL_MAX_10_EXP < r) || (-LDBL_MIN_10_EXP < r) ) *newtype = &ompi_mpi_datatype_null.dt;
89 else if( (DBL_DIG < p) || (DBL_MAX_10_EXP < r) || (-DBL_MIN_10_EXP < r) ) *newtype = &ompi_mpi_long_double.dt;
90 else if( (FLT_DIG < p) || (FLT_MAX_10_EXP < r) || (-FLT_MIN_10_EXP < r) ) *newtype = &ompi_mpi_double.dt;
91 else if( ! OMPI_HAVE_FORTRAN_REAL2 ||
92 (sflt_dig < p) || (sflt_max_10_exp < r) || (-sflt_min_10_exp < r) ) *newtype = &ompi_mpi_float.dt;
93 else *newtype = &ompi_mpi_real2.dt;
94
95 if( *newtype != &ompi_mpi_datatype_null.dt ) {
96 ompi_datatype_t* datatype;
97 const int* a_i[2] = {&p, &r};
98 int rc;
99
100 key = (((uint64_t)p_key) << 32) | ((uint64_t)r_key);
101 if( OPAL_SUCCESS == opal_hash_table_get_value_uint64( &ompi_mpi_f90_real_hashtable,
102 key, (void**)newtype ) ) {
103 return MPI_SUCCESS;
104 }
105 /* Create the duplicate type corresponding to selected type, then
106 * set the argument to be a COMBINER with the correct value of r
107 * and add it to the hash table. */
108 if (OMPI_SUCCESS != ompi_datatype_duplicate( *newtype, &datatype)) {
109 OMPI_ERRHANDLER_RETURN (MPI_ERR_INTERN, MPI_COMM_WORLD,
110 MPI_ERR_INTERN, FUNC_NAME );
111 }
112 /* Make sure the user is not allowed to free this datatype as specified
113 * in the MPI standard.
114 */
115 datatype->super.flags |= OMPI_DATATYPE_FLAG_PREDEFINED;
116 /* Mark the datatype as a special F90 convenience type */
117 // Specifically using opal_snprintf() here (instead of
118 // snprintf()) so that over-eager compilers do not warn us
119 // that we may be truncating the output. We *know* that the
120 // output may be truncated, and it's ok.
121 opal_snprintf(datatype->name, sizeof(datatype->name),
122 "COMBINER %s", (*newtype)->name);
123
124 ompi_datatype_set_args( datatype, 2, a_i, 0, NULL, 0, NULL, MPI_COMBINER_F90_REAL );
125
126 rc = opal_hash_table_set_value_uint64( &ompi_mpi_f90_real_hashtable, key, datatype );
127 if (OMPI_SUCCESS != rc) {
128 return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, rc, FUNC_NAME);
129 }
130 *newtype = datatype;
131 return MPI_SUCCESS;
132 }
133
134 return OMPI_ERRHANDLER_INVOKE(MPI_COMM_WORLD, MPI_ERR_ARG, FUNC_NAME);
135 }