OpenMPI  0.1.1
arch.h
1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /*
3  * Copyright (c) 2004-2006 The Trustees of Indiana University and Indiana
4  * University Research and Technology
5  * Corporation. All rights reserved.
6  * Copyright (c) 2004-2006 The University of Tennessee and The University
7  * of Tennessee Research Foundation. All rights
8  * reserved.
9  * Copyright (c) 2004-2006 High Performance Computing Center Stuttgart,
10  * University of Stuttgart. All rights reserved.
11  * Copyright (c) 2004-2006 The Regents of the University of California.
12  * All rights reserved.
13  * Copyright (c) 2008 Cisco Systems, Inc. All rights reserved.
14  * $COPYRIGHT$
15  *
16  * Additional copyrights may follow
17  *
18  * $HEADER$
19  */
20 #ifndef OPAL_ARCH_H_HAS_BEEN_INCLUDED
21 #define OPAL_ARCH_H_HAS_BEEN_INCLUDED
22 
23 #include "opal_config.h"
24 
25 #include <float.h>
26 #include <assert.h>
27 
28 
29 /***************************************************
30 ** This file tries to classify the most relevant
31 ** platforms regarding their data representation.
32 ** Three aspects are important:
33 ** - byte ordering (little or big endian)
34 ** - integer representation
35 ** - floating point representation.
36 
37 ** In addition, don't forget about the C/Fortran problems.
38 **
39 *****************************************************/
40 
41 
42 /*****************************************************************
43 ** Part 1: Integer representation.
44 **
45 ** The following data types are considered relevant:
46 **
47 ** short
48 ** int
49 ** long
50 ** long long
51 ** integer (fortran)
52 **
53 ** The fortran integer is dismissed here, since there is no
54 ** platform known to me, were fortran and C-integer do not match
55 **
56 ** The following abbriviations are introduced:
57 **
58 ** a) il32 (int long are 32 bits) (e.g. IA32 LINUX, SGI n32, SUN)
59 **
60 ** short: 16 (else it would appear in the name)
61 ** int: 32
62 ** long: 32
63 ** long long: 64
64 **
65 ** b) il64 ( int long are 64 bits) (e.g. Cray T3E )
66 ** short: 32
67 ** int: 64
68 ** long: 64
69 ** long long: 64
70 **
71 ** c) l64 (long are 64 bits) (e.g. SGI 64 IRIX, NEC SX5)
72 **
73 ** short: 16
74 ** int: 32
75 ** long: 64
76 ** long long: 64
77 **
78 ***********************************************************************/
79 
80 /*********************************************************************
81 ** Part 2: Floating point representation
82 **
83 ** The following datatypes are considered relevant
84 **
85 ** float
86 ** double
87 ** long double
88 ** real
89 ** double precision
90 **
91 ** Unfortunatly, here we have to take care, whether float and real,
92 ** respectively double and double precision do match...
93 **
94 ** a) fr32 (float and real are 32 bits) (e.g. SGI n32 and 64, SUN, NEC SX5,...)
95 ** float: 32
96 ** double: 64
97 ** long double: 128
98 ** real: 32
99 ** double prec.:64
100 **
101 ** a1) fr32ld96 (float and real 32, long double 96) (e.g. IA32 LINUX gcc/icc)
102 ** see a), except long double is 96
103 **
104 ** a2) fr32ld64 (e.g. IBM )
105 ** see a), except long double is 64
106 **
107 ** b) cray ( e.g. Cray T3E)
108 ** float: 32
109 ** double: 64
110 ** long double: 64
111 ** real: 64
112 ** double prec.:64
113 **
114 **
115 ** Problem: long double is really treated differently on every machine. Therefore,
116 ** we are storing besides the length of the long double also the length of the mantisee,
117 ** and the number of *relevant* bits in the exponent. Here are the values:
118 **
119 ** Architecture sizeof(long double) mantisee relevant bits for exp.
120 **
121 ** SGIn32/64: 128 107 10
122 ** SUN(sparc): 128 113 14
123 ** IA64: 128 64 14
124 ** IA32: 96 64 14
125 ** Alpha: 128 113 14
126 ** 64 53 10 (gcc)
127 ** IBM: 64 53 10
128 ** (128 106 10) (special flags required).
129 ** SX5: 128 105 22
130 **
131 ** We will not implement all of these routiens, but we consider them
132 ** now when defining the header-settings
133 **
134 ***********************************************************************/
135 
136 /********************************************************************
137 **
138 ** Classification of machines:
139 **
140 ** IA32 LINUX: il32, fr32ld96, little endian
141 ** SUN: il32, fr32, big endian
142 ** SGI n32: il32, fr32, big endian
143 ** SGI 64: l64, fr32, big endian
144 ** NEC SX5: l64, fr32 big endian
145 ** Cray T3E: il64, cray, big endian
146 ** Cray X1: i32(+), fr32, big endian
147 ** IBM: il32, fr32ld64, big endian
148 ** ALPHA: l64, fr32, little endian
149 ** ITANIUM: l64, fr32, little endian
150 **
151 **
152 ** + sizeof ( long long ) not known
153 ** ? alpha supports both, big and little endian
154 ***********************************************************************/
155 
156 
157 /* Current conclusions:
158 ** we need at the moment three settings:
159 ** - big/little endian ?
160 ** - is long 32 or 64 bits ?
161 ** - is long double 64, 96 or 128 bits ?
162 ** - no. of rel. bits in the exponent of a long double ( 10 or 14 )
163 ** - no. of bits of the mantiss of a long double ( 53, 64, 105, 106, 107, 113 )
164 **
165 ** To store this in a 32 bit integer, we use the following definition:
166 **
167 ** 1 2 3 4
168 ** 12345678 12345678 12345678 12345678
169 **
170 ** 1. Byte:
171 ** bits 1 & 2: 00 (header) (to recognize the correct end)
172 ** bits 3 & 4: encoding: 00 = little, 01 = big
173 ** bits 5 & 6: reserved for later use. currently set to 00
174 ** bits 7 & 8: reserved for later use. currently set to 00
175 ** 2. Byte:
176 ** bits 1 & 2: length of long: 00 = 32, 01 = 64
177 ** bits 3 & 4: lenght of long long (not used currently, set to 00).
178 ** bits 5 & 6: length of C/C++ bool (00 = 8, 01 = 16, 10 = 32)
179 ** bits 7 & 8: length of Fortran Logical (00 = 8, 01 = 16, 10 = 32)
180 ** 3. Byte:
181 ** bits 1 & 2: length of long double: 00=64, 01=96,10 = 128
182 ** bits 3 & 4: no. of rel. bits in the exponent: 00 = 10, 01 = 14)
183 ** bits 5 - 7: no. of bits of mantisse ( 000 = 53, 001 = 64, 010 = 105,
184 ** 011 = 106, 100 = 107,101 = 113 )
185 ** bit 8: intel or sparc representation of mantisse (0 = sparc,
186 ** 1 = intel )
187 ** 4. Byte:
188 ** bits 1 & 2: 11 (header) (to recognize the correct end)
189 ** bits 3 & 4: reserved for later use. currently set to 11
190 ** bits 5 & 6: reserved for later use. currently set to 11
191 ** bits 7 & 8: reserved for later use. currently set to 11
192 */
193 
194 /* These masks implement the specification above above */
195 
196 #define OPAL_ARCH_HEADERMASK 0x03000000 /* set the fields for the header */
197 #define OPAL_ARCH_HEADERMASK2 0x00000003 /* other end, needed for checks */
198 #define OPAL_ARCH_UNUSEDMASK 0xfc000000 /* mark the unused fields */
199 
200 /* BYTE 1 */
201 #define OPAL_ARCH_ISBIGENDIAN 0x00000008
202 
203 /* BYTE 2 */
204 #define OPAL_ARCH_LONGISxx 0x0000c000 /* mask for sizeof long */
205 #define OPAL_ARCH_LONGIS64 0x00001000
206 #define OPAL_ARCH_LONGLONGISxx 0x00003000 /* mask for sizeof long long */
207 
208 #define OPAL_ARCH_BOOLISxx 0x00000c00 /* mask for sizeof bool */
209 #define OPAL_ARCH_BOOLIS8 0x00000000 /* bool is 8 bits */
210 #define OPAL_ARCH_BOOLIS16 0x00000400 /* bool is 16 bits */
211 #define OPAL_ARCH_BOOLIS32 0x00000800 /* bool is 32 bits */
212 
213 #define OPAL_ARCH_LOGICALISxx 0x00000300 /* mask for sizeof Fortran logical */
214 #define OPAL_ARCH_LOGICALIS8 0x00000000 /* logical is 8 bits */
215 #define OPAL_ARCH_LOGICALIS16 0x00000100 /* logical is 16 bits */
216 #define OPAL_ARCH_LOGICALIS32 0x00000200 /* logical is 32 bits */
217 
218 /* BYTE 3 */
219 #define OPAL_ARCH_LONGDOUBLEIS96 0x00020000
220 #define OPAL_ARCH_LONGDOUBLEIS128 0x00010000
221 
222 #define OPAL_ARCH_LDEXPSIZEIS15 0x00080000
223 
224 #define OPAL_ARCH_LDMANTDIGIS64 0x00400000
225 #define OPAL_ARCH_LDMANTDIGIS105 0x00200000
226 #define OPAL_ARCH_LDMANTDIGIS106 0x00600000
227 #define OPAL_ARCH_LDMANTDIGIS107 0x00100000
228 #define OPAL_ARCH_LDMANTDIGIS113 0x00500000
229 
230 #define OPAL_ARCH_LDISINTEL 0x00800000
231 
232 BEGIN_C_DECLS
233 
234 OPAL_DECLSPEC int32_t opal_arch_compute_local_id( uint32_t *var);
235 
236 OPAL_DECLSPEC int32_t opal_arch_checkmask ( uint32_t *var, uint32_t mask );
237 
238 static inline int32_t opal_arch_isbigendian ( void )
239 {
240  const uint32_t value = 0x12345678;
241  const char *ptr = (char*)&value;
242  int x = 0;
243 
244  /* if( sizeof(int) == 8 ) x = 4; */
245  if( ptr[x] == 0x12) return 1; /* big endian, true */
246  if( ptr[x] == 0x78 ) return 0; /* little endian, false */
247  assert( 0 ); /* unknown architecture not little nor big endian */
248  return -1;
249 }
250 
251 /* we must find which representation of long double is used
252  * intel or sparc. Both of them represent the long doubles using a close to
253  * IEEE representation (seeeeeee..emmm...m) where the mantissa look like
254  * 1.????. For the intel representaion the 1 is explicit, and for the sparc
255  * the first one is implicit. If we take the number 2.0 the exponent is 1
256  * and the mantissa is 1.0 (the sign of course should be 0). So if we check
257  * for the first one in the binary representation of the number, we will
258  * find the bit from the exponent, so the next one should be the begining
259  * of the mantissa. If it's 1 then we have an intel representaion, if not
260  * we have a sparc one. QED
261  */
262 static inline int32_t opal_arch_ldisintel( void )
263 {
264  long double ld = 2.0;
265  int i, j;
266  uint32_t* pui = (uint32_t*)(void*)&ld;
267 
268  j = LDBL_MANT_DIG / 32;
269  i = (LDBL_MANT_DIG % 32) - 1;
270  if( opal_arch_isbigendian() ) { /* big endian */
271  j = (sizeof(long double) / sizeof(unsigned int)) - j;
272  if( i < 0 ) {
273  i = 31;
274  j = j+1;
275  }
276  } else {
277  if( i < 0 ) {
278  i = 31;
279  j = j-1;
280  }
281  }
282  return (pui[j] & (1 << i) ? 1 : 0);
283 }
284 
285 static inline void opal_arch_setmask ( uint32_t *var, uint32_t mask)
286 {
287  *var |= mask;
288 }
289 
290 END_C_DECLS
291 
292 #endif /* OPAL_ARCH_H_HAS_BEEN_INCLUDED */
293