OSDN Git Service

2008-04-30 Thomas Koenig <tkoenig@gcc.gnu.org>
[pf3gnuchains/gcc-fork.git] / libgfortran / m4 / ifunction.m4
1 dnl Support macro file for intrinsic functions.
2 dnl Contains the generic sections of the array functions.
3 dnl This file is part of the GNU Fortran 95 Runtime Library (libgfortran)
4 dnl Distributed under the GNU GPL with exception.  See COPYING for details.
5 dnl
6 dnl Pass the implementation for a single section as the parameter to
7 dnl {MASK_}ARRAY_FUNCTION.
8 dnl The variables base, delta, and len describe the input section.
9 dnl For masked section the mask is described by mbase and mdelta.
10 dnl These should not be modified. The result should be stored in *dest.
11 dnl The names count, extent, sstride, dstride, base, dest, rank, dim
12 dnl retarray, array, pdim and mstride should not be used.
13 dnl The variable n is declared as index_type and may be used.
14 dnl Other variable declarations may be placed at the start of the code,
15 dnl The types of the array parameter and the return value are
16 dnl atype_name and rtype_name respectively.
17 dnl Execution should be allowed to continue to the end of the block.
18 dnl You should not return or break from the inner loop of the implementation.
19 dnl Care should also be taken to avoid using the names defined in iparm.m4
20 define(START_ARRAY_FUNCTION,
21 `
22 extern void name`'rtype_qual`_'atype_code (rtype * const restrict, 
23         atype * const restrict, const index_type * const restrict);
24 export_proto(name`'rtype_qual`_'atype_code);
25
26 void
27 name`'rtype_qual`_'atype_code (rtype * const restrict retarray, 
28         atype * const restrict array, 
29         const index_type * const restrict pdim)
30 {
31   index_type count[GFC_MAX_DIMENSIONS];
32   index_type extent[GFC_MAX_DIMENSIONS];
33   index_type sstride[GFC_MAX_DIMENSIONS];
34   index_type dstride[GFC_MAX_DIMENSIONS];
35   const atype_name * restrict base;
36   rtype_name * restrict dest;
37   index_type rank;
38   index_type n;
39   index_type len;
40   index_type delta;
41   index_type dim;
42
43   /* Make dim zero based to avoid confusion.  */
44   dim = (*pdim) - 1;
45   rank = GFC_DESCRIPTOR_RANK (array) - 1;
46
47   len = array->dim[dim].ubound + 1 - array->dim[dim].lbound;
48   delta = array->dim[dim].stride;
49
50   for (n = 0; n < dim; n++)
51     {
52       sstride[n] = array->dim[n].stride;
53       extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound;
54
55       if (extent[n] < 0)
56         extent[n] = 0;
57     }
58   for (n = dim; n < rank; n++)
59     {
60       sstride[n] = array->dim[n + 1].stride;
61       extent[n] =
62         array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound;
63
64       if (extent[n] < 0)
65         extent[n] = 0;
66     }
67
68   if (retarray->data == NULL)
69     {
70       size_t alloc_size;
71
72       for (n = 0; n < rank; n++)
73         {
74           retarray->dim[n].lbound = 0;
75           retarray->dim[n].ubound = extent[n]-1;
76           if (n == 0)
77             retarray->dim[n].stride = 1;
78           else
79             retarray->dim[n].stride = retarray->dim[n-1].stride * extent[n-1];
80         }
81
82       retarray->offset = 0;
83       retarray->dtype = (array->dtype & ~GFC_DTYPE_RANK_MASK) | rank;
84
85       alloc_size = sizeof (rtype_name) * retarray->dim[rank-1].stride
86                    * extent[rank-1];
87
88       if (alloc_size == 0)
89         {
90           /* Make sure we have a zero-sized array.  */
91           retarray->dim[0].lbound = 0;
92           retarray->dim[0].ubound = -1;
93           return;
94         }
95       else
96         retarray->data = internal_malloc_size (alloc_size);
97     }
98   else
99     {
100       if (rank != GFC_DESCRIPTOR_RANK (retarray))
101         runtime_error ("rank of return array incorrect in"
102                        " u_name intrinsic: is %ld, should be %ld",
103                        (long int) (GFC_DESCRIPTOR_RANK (retarray)),
104                        (long int) rank);
105
106       if (compile_options.bounds_check)
107         {
108           for (n=0; n < rank; n++)
109             {
110               index_type ret_extent;
111
112               ret_extent = retarray->dim[n].ubound + 1
113                 - retarray->dim[n].lbound;
114               if (extent[n] != ret_extent)
115                 runtime_error ("Incorrect extent in return value of"
116                                " u_name intrinsic in dimension %ld:"
117                                " is %ld, should be %ld", (long int) n + 1,
118                                (long int) ret_extent, (long int) extent[n]);
119             }
120         }
121     }
122
123   for (n = 0; n < rank; n++)
124     {
125       count[n] = 0;
126       dstride[n] = retarray->dim[n].stride;
127       if (extent[n] <= 0)
128         len = 0;
129     }
130
131   base = array->data;
132   dest = retarray->data;
133
134   while (base)
135     {
136       const atype_name * restrict src;
137       rtype_name result;
138       src = base;
139       {
140 ')dnl
141 define(START_ARRAY_BLOCK,
142 `        if (len <= 0)
143           *dest = '$1`;
144         else
145           {
146             for (n = 0; n < len; n++, src += delta)
147               {
148 ')dnl
149 define(FINISH_ARRAY_FUNCTION,
150     `          }
151             *dest = result;
152           }
153       }
154       /* Advance to the next element.  */
155       count[0]++;
156       base += sstride[0];
157       dest += dstride[0];
158       n = 0;
159       while (count[n] == extent[n])
160         {
161           /* When we get to the end of a dimension, reset it and increment
162              the next dimension.  */
163           count[n] = 0;
164           /* We could precalculate these products, but this is a less
165              frequently used path so probably not worth it.  */
166           base -= sstride[n] * extent[n];
167           dest -= dstride[n] * extent[n];
168           n++;
169           if (n == rank)
170             {
171               /* Break out of the look.  */
172               base = NULL;
173               break;
174             }
175           else
176             {
177               count[n]++;
178               base += sstride[n];
179               dest += dstride[n];
180             }
181         }
182     }
183 }')dnl
184 define(START_MASKED_ARRAY_FUNCTION,
185 `
186 extern void `m'name`'rtype_qual`_'atype_code (rtype * const restrict, 
187         atype * const restrict, const index_type * const restrict,
188         gfc_array_l1 * const restrict);
189 export_proto(`m'name`'rtype_qual`_'atype_code);
190
191 void
192 `m'name`'rtype_qual`_'atype_code (rtype * const restrict retarray, 
193         atype * const restrict array, 
194         const index_type * const restrict pdim, 
195         gfc_array_l1 * const restrict mask)
196 {
197   index_type count[GFC_MAX_DIMENSIONS];
198   index_type extent[GFC_MAX_DIMENSIONS];
199   index_type sstride[GFC_MAX_DIMENSIONS];
200   index_type dstride[GFC_MAX_DIMENSIONS];
201   index_type mstride[GFC_MAX_DIMENSIONS];
202   rtype_name * restrict dest;
203   const atype_name * restrict base;
204   const GFC_LOGICAL_1 * restrict mbase;
205   int rank;
206   int dim;
207   index_type n;
208   index_type len;
209   index_type delta;
210   index_type mdelta;
211   int mask_kind;
212
213   dim = (*pdim) - 1;
214   rank = GFC_DESCRIPTOR_RANK (array) - 1;
215
216   len = array->dim[dim].ubound + 1 - array->dim[dim].lbound;
217   if (len <= 0)
218     return;
219
220   mbase = mask->data;
221
222   mask_kind = GFC_DESCRIPTOR_SIZE (mask);
223
224   if (mask_kind == 1 || mask_kind == 2 || mask_kind == 4 || mask_kind == 8
225 #ifdef HAVE_GFC_LOGICAL_16
226       || mask_kind == 16
227 #endif
228       )
229     mbase = GFOR_POINTER_TO_L1 (mbase, mask_kind);
230   else
231     runtime_error ("Funny sized logical array");
232
233   delta = array->dim[dim].stride;
234   mdelta = mask->dim[dim].stride * mask_kind;
235
236   for (n = 0; n < dim; n++)
237     {
238       sstride[n] = array->dim[n].stride;
239       mstride[n] = mask->dim[n].stride * mask_kind;
240       extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound;
241
242       if (extent[n] < 0)
243         extent[n] = 0;
244
245     }
246   for (n = dim; n < rank; n++)
247     {
248       sstride[n] = array->dim[n + 1].stride;
249       mstride[n] = mask->dim[n + 1].stride * mask_kind;
250       extent[n] =
251         array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound;
252
253       if (extent[n] < 0)
254         extent[n] = 0;
255     }
256
257   if (retarray->data == NULL)
258     {
259       size_t alloc_size;
260
261       for (n = 0; n < rank; n++)
262         {
263           retarray->dim[n].lbound = 0;
264           retarray->dim[n].ubound = extent[n]-1;
265           if (n == 0)
266             retarray->dim[n].stride = 1;
267           else
268             retarray->dim[n].stride = retarray->dim[n-1].stride * extent[n-1];
269         }
270
271       alloc_size = sizeof (rtype_name) * retarray->dim[rank-1].stride
272                    * extent[rank-1];
273
274       retarray->offset = 0;
275       retarray->dtype = (array->dtype & ~GFC_DTYPE_RANK_MASK) | rank;
276
277       if (alloc_size == 0)
278         {
279           /* Make sure we have a zero-sized array.  */
280           retarray->dim[0].lbound = 0;
281           retarray->dim[0].ubound = -1;
282           return;
283         }
284       else
285         retarray->data = internal_malloc_size (alloc_size);
286
287     }
288   else
289     {
290       if (rank != GFC_DESCRIPTOR_RANK (retarray))
291         runtime_error ("rank of return array incorrect in u_name intrinsic");
292
293       if (compile_options.bounds_check)
294         {
295           for (n=0; n < rank; n++)
296             {
297               index_type ret_extent;
298
299               ret_extent = retarray->dim[n].ubound + 1
300                 - retarray->dim[n].lbound;
301               if (extent[n] != ret_extent)
302                 runtime_error ("Incorrect extent in return value of"
303                                " u_name intrinsic in dimension %ld:"
304                                " is %ld, should be %ld", (long int) n + 1,
305                                (long int) ret_extent, (long int) extent[n]);
306             }
307           for (n=0; n<= rank; n++)
308             {
309               index_type mask_extent, array_extent;
310
311               array_extent = array->dim[n].ubound + 1 - array->dim[n].lbound;
312               mask_extent = mask->dim[n].ubound + 1 - mask->dim[n].lbound;
313               if (array_extent != mask_extent)
314                 runtime_error ("Incorrect extent in MASK argument of"
315                                " u_name intrinsic in dimension %ld:"
316                                " is %ld, should be %ld", (long int) n + 1,
317                                (long int) mask_extent, (long int) array_extent);
318             }
319         }
320     }
321
322   for (n = 0; n < rank; n++)
323     {
324       count[n] = 0;
325       dstride[n] = retarray->dim[n].stride;
326       if (extent[n] <= 0)
327         return;
328     }
329
330   dest = retarray->data;
331   base = array->data;
332
333   while (base)
334     {
335       const atype_name * restrict src;
336       const GFC_LOGICAL_1 * restrict msrc;
337       rtype_name result;
338       src = base;
339       msrc = mbase;
340       {
341 ')dnl
342 define(START_MASKED_ARRAY_BLOCK,
343 `        if (len <= 0)
344           *dest = '$1`;
345         else
346           {
347             for (n = 0; n < len; n++, src += delta, msrc += mdelta)
348               {
349 ')dnl
350 define(FINISH_MASKED_ARRAY_FUNCTION,
351 `              }
352             *dest = result;
353           }
354       }
355       /* Advance to the next element.  */
356       count[0]++;
357       base += sstride[0];
358       mbase += mstride[0];
359       dest += dstride[0];
360       n = 0;
361       while (count[n] == extent[n])
362         {
363           /* When we get to the end of a dimension, reset it and increment
364              the next dimension.  */
365           count[n] = 0;
366           /* We could precalculate these products, but this is a less
367              frequently used path so probably not worth it.  */
368           base -= sstride[n] * extent[n];
369           mbase -= mstride[n] * extent[n];
370           dest -= dstride[n] * extent[n];
371           n++;
372           if (n == rank)
373             {
374               /* Break out of the look.  */
375               base = NULL;
376               break;
377             }
378           else
379             {
380               count[n]++;
381               base += sstride[n];
382               mbase += mstride[n];
383               dest += dstride[n];
384             }
385         }
386     }
387 }')dnl
388 define(SCALAR_ARRAY_FUNCTION,
389 `
390 extern void `s'name`'rtype_qual`_'atype_code (rtype * const restrict, 
391         atype * const restrict, const index_type * const restrict,
392         GFC_LOGICAL_4 *);
393 export_proto(`s'name`'rtype_qual`_'atype_code);
394
395 void
396 `s'name`'rtype_qual`_'atype_code (rtype * const restrict retarray, 
397         atype * const restrict array, 
398         const index_type * const restrict pdim, 
399         GFC_LOGICAL_4 * mask)
400 {
401   index_type count[GFC_MAX_DIMENSIONS];
402   index_type extent[GFC_MAX_DIMENSIONS];
403   index_type sstride[GFC_MAX_DIMENSIONS];
404   index_type dstride[GFC_MAX_DIMENSIONS];
405   rtype_name * restrict dest;
406   index_type rank;
407   index_type n;
408   index_type dim;
409
410
411   if (*mask)
412     {
413       name`'rtype_qual`_'atype_code (retarray, array, pdim);
414       return;
415     }
416   /* Make dim zero based to avoid confusion.  */
417   dim = (*pdim) - 1;
418   rank = GFC_DESCRIPTOR_RANK (array) - 1;
419
420   for (n = 0; n < dim; n++)
421     {
422       sstride[n] = array->dim[n].stride;
423       extent[n] = array->dim[n].ubound + 1 - array->dim[n].lbound;
424
425       if (extent[n] <= 0)
426         extent[n] = 0;
427     }
428
429   for (n = dim; n < rank; n++)
430     {
431       sstride[n] = array->dim[n + 1].stride;
432       extent[n] =
433         array->dim[n + 1].ubound + 1 - array->dim[n + 1].lbound;
434
435       if (extent[n] <= 0)
436         extent[n] = 0;
437     }
438
439   if (retarray->data == NULL)
440     {
441       size_t alloc_size;
442
443       for (n = 0; n < rank; n++)
444         {
445           retarray->dim[n].lbound = 0;
446           retarray->dim[n].ubound = extent[n]-1;
447           if (n == 0)
448             retarray->dim[n].stride = 1;
449           else
450             retarray->dim[n].stride = retarray->dim[n-1].stride * extent[n-1];
451         }
452
453       retarray->offset = 0;
454       retarray->dtype = (array->dtype & ~GFC_DTYPE_RANK_MASK) | rank;
455
456       alloc_size = sizeof (rtype_name) * retarray->dim[rank-1].stride
457                    * extent[rank-1];
458
459       if (alloc_size == 0)
460         {
461           /* Make sure we have a zero-sized array.  */
462           retarray->dim[0].lbound = 0;
463           retarray->dim[0].ubound = -1;
464           return;
465         }
466       else
467         retarray->data = internal_malloc_size (alloc_size);
468     }
469   else
470     {
471       if (rank != GFC_DESCRIPTOR_RANK (retarray))
472         runtime_error ("rank of return array incorrect in"
473                        " u_name intrinsic: is %ld, should be %ld",
474                        (long int) (GFC_DESCRIPTOR_RANK (retarray)),
475                        (long int) rank);
476
477       if (compile_options.bounds_check)
478         {
479           for (n=0; n < rank; n++)
480             {
481               index_type ret_extent;
482
483               ret_extent = retarray->dim[n].ubound + 1
484                 - retarray->dim[n].lbound;
485               if (extent[n] != ret_extent)
486                 runtime_error ("Incorrect extent in return value of"
487                                " u_name intrinsic in dimension %ld:"
488                                " is %ld, should be %ld", (long int) n + 1,
489                                (long int) ret_extent, (long int) extent[n]);
490             }
491         }
492     }
493
494   for (n = 0; n < rank; n++)
495     {
496       count[n] = 0;
497       dstride[n] = retarray->dim[n].stride;
498     }
499
500   dest = retarray->data;
501
502   while(1)
503     {
504       *dest = '$1`;
505       count[0]++;
506       dest += dstride[0];
507       n = 0;
508       while (count[n] == extent[n])
509         {
510           /* When we get to the end of a dimension, reset it and increment
511              the next dimension.  */
512           count[n] = 0;
513           /* We could precalculate these products, but this is a less
514              frequently used path so probably not worth it.  */
515           dest -= dstride[n] * extent[n];
516           n++;
517           if (n == rank)
518             return;
519           else
520             {
521               count[n]++;
522               dest += dstride[n];
523             }
524         }
525     }
526 }')dnl
527 define(ARRAY_FUNCTION,
528 `START_ARRAY_FUNCTION
529 $2
530 START_ARRAY_BLOCK($1)
531 $3
532 FINISH_ARRAY_FUNCTION')dnl
533 define(MASKED_ARRAY_FUNCTION,
534 `START_MASKED_ARRAY_FUNCTION
535 $2
536 START_MASKED_ARRAY_BLOCK($1)
537 $3
538 FINISH_MASKED_ARRAY_FUNCTION')dnl