Added support for "long double".
[charm.git] / src / libs / ck-libs / idxl / idxl_layout.C
1 /*Charm++ Finite Element Framework:
2 Orion Sky Lawlor, olawlor@acm.org, 12/20/2002
3
4 Implementation file for IDXL: IDXL user data types.
5 These allow data to be scooped right out of a user's
6 arrays.
7 */
8 #include "idxl.h" /* for IDXL_Abort */
9 #include "idxl_layout.h"
10 #include <string.h> /* for memcpy */
11 #include <math.h>
12 #include <limits.h>
13 #include <float.h> /*for FLT_MIN on non-Suns*/
14
15 int IDXL_Layout::type_size(int dataType,const char *callingRoutine)
16 {
17     switch(dataType) {
18       case IDXL_BYTE : return 1;
19       case IDXL_INT : return sizeof(int);
20       case IDXL_REAL : return sizeof(float);
21       case IDXL_DOUBLE : return sizeof(double);
22       case IDXL_LONG_DOUBLE : return sizeof(long double); 
23       case IDXL_INDEX_0 : return sizeof(int);
24       case IDXL_INDEX_1 : return sizeof(int);
25       default: IDXL_Abort(callingRoutine,"Expected an IDXL data type, but got %d",dataType);
26     }
27     return -1;
28 }
29
30 const char *IDXL_Layout::type_name(int dataType,const char *callingRoutine) 
31 {
32     switch(dataType) {
33       case IDXL_BYTE : return "IDXL_BYTE";
34       case IDXL_INT : return "IDXL_INT";
35       case IDXL_REAL : return "IDXL_REAL";
36       case IDXL_DOUBLE : return "IDXL_DOUBLE";
37       case IDXL_LONG_DOUBLE : return "IDXL_LONG_DOUBLE";
38       case IDXL_INDEX_0 : return "IDXL_INDEX_0";
39       case IDXL_INDEX_1 : return "IDXL_INDEX_1";
40       default: break;
41     }
42     return "(unknown IDXL datatype)";
43 }
44
45 /******************** Reduction Support **********************/
46
47 // These functions apply this operation to a single value, and are called 
48 // directly.
49 template<class T>
50 inline void assignOne(T* lhs, T val) { *lhs = val; }
51
52 template<class T>
53 inline void assignOne(T* lhs, const T *rhs) { *lhs = *rhs; }
54
55 template<class T>
56 inline void sumOne(T* lhs, const T* rhs) { *lhs += *rhs; }
57
58 template<class T>
59 inline void prodOne(T* lhs, const T* rhs) { *lhs *= *rhs; }
60
61 template<class T>
62 inline void maxOne(T* lhs, const T* rhs) { *lhs = (*lhs > *rhs) ? *lhs : *rhs; }
63
64 template<class T>
65 inline void minOne(T* lhs, const T* rhs) { *lhs = (*lhs < *rhs) ? *lhs : *rhs; }
66
67 // reduction_combine_fn definitions.
68 // These functions apply the given operation to an entire user-formatted row src,
69 // accumulating the result into the compressed-format row dest.  
70 // FIXME: figure out how to define this using templates, not macros.
71 #define oneToFn(oneFn,gatherName) \
72 template<class T> \
73 void gatherName(T *dest,const byte *src,const IDXL_Layout *srcLayout) { \
74         src+=srcLayout->offset; \
75         int skew=srcLayout->skew; \
76         int i=0, width=srcLayout->width; \
77         for (i=0;i<width;i++) { \
78                 oneFn(dest,(const T *)src); \
79                 dest++; \
80                 src+=skew; \
81         } \
82 } \
83 /*Explicitly instantiate templates: */ \
84 template void gatherName(byte *dest,const byte *src,const IDXL_Layout *srcLayout); \
85 template void gatherName(int *dest,const byte *src,const IDXL_Layout *srcLayout); \
86 template void gatherName(float *dest,const byte *src,const IDXL_Layout *srcLayout); \
87 template void gatherName(double *dest,const byte *src,const IDXL_Layout *srcLayout); \
88 template void gatherName(long double *dest,const byte *src,const IDXL_Layout *srcLayout);
89
90 oneToFn(sumOne,sumFn)
91 oneToFn(prodOne,prodFn)
92 oneToFn(maxOne,maxFn)
93 oneToFn(minOne,minFn)
94
95 typedef void (*byteCombineFn)(byte *dest,const byte *src,const IDXL_Layout *srcLayout);
96 typedef void (*intCombineFn)(int *dest,const byte *src,const IDXL_Layout *srcLayout);
97 typedef void (*floatCombineFn)(float *dest,const byte *src,const IDXL_Layout *srcLayout);
98 typedef void (*doubleCombineFn)(double *dest,const byte *src,const IDXL_Layout *srcLayout);
99 typedef void (*longDoubleCombineFn)(long double *dest,const byte *src,const IDXL_Layout *srcLayout);
100
101
102 template<class T>
103 inline void assignFn(int len,T *dest,T val) {
104   for (int i=0;i<len;i++) dest[i]=val;
105 }
106
107
108 void reduction_initialize(const IDXL_Layout& dt, void *lhs, int op,const char *callingRoutine)
109 {
110   switch(op) {
111     case IDXL_SUM:
112       switch(dt.type) {
113         case IDXL_BYTE : assignFn(dt.width,(byte*)lhs, (byte)0); break;
114         case IDXL_INT : assignFn(dt.width,(int*)lhs, 0); break;
115         case IDXL_REAL : assignFn(dt.width,(float*)lhs, (float)0.0); break;
116         case IDXL_DOUBLE : assignFn(dt.width,(double*)lhs, 0.0); break;
117             case IDXL_LONG_DOUBLE : assignFn(dt.width,(long double*)lhs, 0.0L); break;
118             default: IDXL_Abort(callingRoutine,"Invalid IDXL data type %d",dt.type);
119       }
120       break;
121     case IDXL_PROD:
122       switch(dt.type) {
123         case IDXL_BYTE : assignFn(dt.width,(byte*)lhs, (byte)1); break;
124         case IDXL_INT : assignFn(dt.width,(int*)lhs, 1); break;
125         case IDXL_REAL : assignFn(dt.width,(float*)lhs, (float)1.0); break;
126         case IDXL_DOUBLE : assignFn(dt.width,(double*)lhs, 1.0); break;
127         case IDXL_LONG_DOUBLE : assignFn(dt.width,(long double*)lhs, 1.0L); break;
128       }
129       break;
130     case IDXL_MAX:
131       switch(dt.type) {
132         case IDXL_BYTE : assignFn(dt.width,(byte*)lhs, (byte)CHAR_MIN); break;
133         case IDXL_INT : assignFn(dt.width,(int*)lhs, INT_MIN); break;
134         case IDXL_REAL : assignFn(dt.width,(float*)lhs, (float)FLT_MIN); break;
135         case IDXL_DOUBLE : assignFn(dt.width,(double*)lhs, DBL_MIN); break;
136         case IDXL_LONG_DOUBLE : assignFn(dt.width,(long double*)lhs, LDBL_MIN); break;
137       }
138       break;
139     case IDXL_MIN:
140       switch(dt.type) {
141         case IDXL_BYTE : assignFn(dt.width,(byte*)lhs, (byte)CHAR_MAX); break;
142         case IDXL_INT : assignFn(dt.width,(int*)lhs, INT_MAX); break;
143         case IDXL_REAL : assignFn(dt.width,(float*)lhs, FLT_MAX); break;
144         case IDXL_DOUBLE : assignFn(dt.width,(double*)lhs, DBL_MAX); break;
145         case IDXL_LONG_DOUBLE : assignFn(dt.width,(long double*)lhs, LDBL_MAX); break;
146       }
147       break;
148     default: IDXL_Abort(callingRoutine,"Expected an IDXL reduction type, but got %d",op);
149   }
150 }
151
152 //This odd-looking define selects the appropriate templated function and
153 // returns it as a function pointer.
154 #define idxl_type_return(type,fn) \
155       switch(type) {\
156         case IDXL_BYTE : return (reduction_combine_fn)(byteCombineFn)fn;\
157         case IDXL_INT : return (reduction_combine_fn)(intCombineFn)fn;\
158         case IDXL_REAL : return (reduction_combine_fn)(floatCombineFn)fn;\
159         case IDXL_DOUBLE : return (reduction_combine_fn)(doubleCombineFn)fn;\
160         case IDXL_LONG_DOUBLE : return (reduction_combine_fn)(longDoubleCombineFn)fn;\
161           }
162
163 reduction_combine_fn reduction_combine(const IDXL_Layout& dt, int op,const char *callingRoutine)
164 {
165   switch(op) {
166     case IDXL_SUM: idxl_type_return(dt.type, sumFn); break;
167     case IDXL_PROD: idxl_type_return(dt.type, prodFn); break;
168     case IDXL_MIN: idxl_type_return(dt.type, minFn); break;
169     case IDXL_MAX: idxl_type_return(dt.type, maxFn); break;
170     default: IDXL_Abort(callingRoutine,"Expected an IDXL reduction type, but got %d",op);
171   }
172   IDXL_Abort(callingRoutine,"Expected an IDXL data type, but got %d",dt.type);
173   return NULL;
174 }
175
176
177 // Bizarre macro: call the appropriate version of fn for this IDXL type:
178 #define idxl_type_call(type,fn,args) \
179       switch(type) {\
180         case IDXL_BYTE : fn args(byte); break; \
181         case IDXL_INT : fn args(int); break; \
182         case IDXL_REAL : fn args(float); break; \
183         case IDXL_DOUBLE : fn args(double); break; \
184         case IDXL_LONG_DOUBLE : fn args(long double); break; \
185       }
186
187 // Even more bizarre macro: pass typecast arguments for typical scatter/gather 
188 #define scatterGatherArgs(type) \
189         (v_user, nIndices,indices, IDXL_LAYOUT_CALL(*this), (type *)v_compressed)
190
191 /************************* Gather ***********************
192 "Gather" routines extract data distributed (nodeIdx)
193 through the user's array (in) and collect it into a message (out).
194  */
195
196 // Hopefully the compiler's common-subexpression elimination will
197 //   get rid of the multiplies in the inner loop.
198 template <class T>
199 inline void gatherUserData(const void *user,int nIndices,const int *indices,
200                 IDXL_LAYOUT_PARAM,T *compressed) 
201 {
202         for (int r=0;r<nIndices;r++) {
203                 int sr=indices[r];
204                 if(sr!=-1) {
205                   for (int c=0;c<width;c++) {
206                     compressed[c]=IDXL_LAYOUT_DEREF(T,user,sr,c);
207                   }
208                   compressed+=width;
209                 }
210         }
211 }
212
213   /**
214    * For each record in nodes[0..nNodes-1], copy the
215    * user data in v_in into the compressed data in v_out.
216    */
217 void IDXL_Layout::gather(int nIndices,const int *indices,
218                    const void *v_user,void *v_compressed) const
219 {
220   idxl_type_call(this->type, gatherUserData, scatterGatherArgs);
221 }
222
223 /************************ Scatter ************************
224 "Scatter" routines are the opposite of gather: they take
225 compressed data from a message (in) and copy it into selected
226 indices of the user array (out).
227  */
228
229 template <class T>
230 inline void scatterUserData(void *user,int nIndices,const int *indices,
231                 IDXL_LAYOUT_PARAM,const T *compressed) 
232 {
233         for (int r=0;r<nIndices;r++) {
234                 int sr=indices[r];
235                 for (int c=0;c<width;c++)
236                         IDXL_LAYOUT_DEREF(T,user,sr,c)=compressed[c];
237                 compressed+=width;
238         }
239 }
240
241   /**
242    * For each field in the list nodes[0..nNodes-1], copy the
243    * compressed data from v_in into the user data in v_out.
244    */
245 void IDXL_Layout::scatter(int nIndices,const int *indices,
246                    const void *v_compressed,void *v_user) const
247 {
248   idxl_type_call(this->type, scatterUserData, scatterGatherArgs);
249 }
250
251
252 /************************ ScatterAdd ***********************
253 "ScatterAdd" routines add the message data (in) to the
254 shared nodes distributed through the user's data (out).
255  */
256 template <class T>
257 inline void scatterAddUserData(void *user,int nIndices,const int *indices,
258                 IDXL_LAYOUT_PARAM,const T *compressed) 
259 {
260         for (int r=0;r<nIndices;r++) {
261                 int sr=indices[r];
262                 if(sr!=-1) {
263                   for (int c=0;c<width;c++){
264                     IDXL_LAYOUT_DEREF(T,user,sr,c)+=compressed[c];
265                   }
266                   compressed+=width;
267                 }
268         }
269 }
270
271   /**
272    * For each field in the list nodes[0..nNodes-1], add the
273    * compressed data from v_in into the user data in v_out.
274    */
275 void IDXL_Layout::scatteradd(int nIndices,const int *indices,
276                    const void *v_compressed,void *v_user) const
277 {
278   idxl_type_call(this->type, scatterAddUserData, scatterGatherArgs);
279 }
280
281
282
283 /********************** Data_list: *******************/
284 void IDXL_Layout_List::badLayout(IDXL_Layout_t l,const char *callingRoutine) const
285 {
286         IDXL_Abort(callingRoutine,"Expected an IDXL_Layout_t, got %d",l);
287 }
288
289 IDXL_Layout_List::IDXL_Layout_List() {
290         for (int i=0;i<MAX_DT;i++) list[i]=NULL;
291 }
292 void IDXL_Layout_List::pup(PUP::er &p) {
293         for (int i=0;i<MAX_DT;i++) {
294                 int isNULL=(list[i]==NULL);
295                 p|isNULL;
296                 if (!isNULL) {
297                         if (list[i]==NULL) list[i]=new IDXL_Layout();
298                         p|*list[i];
299                 }
300         }
301 }
302 IDXL_Layout_List::~IDXL_Layout_List() {
303         empty();
304 }
305 /// Clear all stored layouts:
306 void IDXL_Layout_List::empty(void) {
307         for (int i=0;i<MAX_DT;i++) 
308                 if (list[i]!=NULL) {
309                         delete list[i];
310                         list[i]=NULL;
311                 }
312 }
313
314 IDXL_Layout_t IDXL_Layout_List::put(const IDXL_Layout &dt) {
315         for (int i=0;i<MAX_DT;i++) 
316                 if (list[i]==NULL) {
317                         list[i]=new IDXL_Layout(dt);
318                         return FIRST_DT+i;
319                 }
320         // if we get here, the table is full:
321         IDXL_Abort("","Registered too many IDXL_Layouts! (only have room for %d)",MAX_DT);
322         return 0; // For whining compilers
323 }
324 void IDXL_Layout_List::destroy(IDXL_Layout_t l,const char *callingRoutine) {
325         check(l,callingRoutine);
326         int i=l-FIRST_DT;
327         delete list[i];
328         list[i]=NULL;
329 }
330