1*10d565efSmrg /* alloca.c -- allocate automatically reclaimed memory
2*10d565efSmrg (Mostly) portable public-domain implementation -- D A Gwyn
3*10d565efSmrg
4*10d565efSmrg This implementation of the PWB library alloca function,
5*10d565efSmrg which is used to allocate space off the run-time stack so
6*10d565efSmrg that it is automatically reclaimed upon procedure exit,
7*10d565efSmrg was inspired by discussions with J. Q. Johnson of Cornell.
8*10d565efSmrg J.Otto Tennant <jot@cray.com> contributed the Cray support.
9*10d565efSmrg
10*10d565efSmrg There are some preprocessor constants that can
11*10d565efSmrg be defined when compiling for your specific system, for
12*10d565efSmrg improved efficiency; however, the defaults should be okay.
13*10d565efSmrg
14*10d565efSmrg The general concept of this implementation is to keep
15*10d565efSmrg track of all alloca-allocated blocks, and reclaim any
16*10d565efSmrg that are found to be deeper in the stack than the current
17*10d565efSmrg invocation. This heuristic does not reclaim storage as
18*10d565efSmrg soon as it becomes invalid, but it will do so eventually.
19*10d565efSmrg
20*10d565efSmrg As a special case, alloca(0) reclaims storage without
21*10d565efSmrg allocating any. It is a good idea to use alloca(0) in
22*10d565efSmrg your main control loop, etc. to force garbage collection. */
23*10d565efSmrg
24*10d565efSmrg /*
25*10d565efSmrg
26*10d565efSmrg @deftypefn Replacement void* alloca (size_t @var{size})
27*10d565efSmrg
28*10d565efSmrg This function allocates memory which will be automatically reclaimed
29*10d565efSmrg after the procedure exits. The @libib{} implementation does not free
30*10d565efSmrg the memory immediately but will do so eventually during subsequent
31*10d565efSmrg calls to this function. Memory is allocated using @code{xmalloc} under
32*10d565efSmrg normal circumstances.
33*10d565efSmrg
34*10d565efSmrg The header file @file{alloca-conf.h} can be used in conjunction with the
35*10d565efSmrg GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make
36*10d565efSmrg available this function. The @code{AC_FUNC_ALLOCA} test requires that
37*10d565efSmrg client code use a block of preprocessor code to be safe (see the Autoconf
38*10d565efSmrg manual for more); this header incorporates that logic and more, including
39*10d565efSmrg the possibility of a GCC built-in function.
40*10d565efSmrg
41*10d565efSmrg @end deftypefn
42*10d565efSmrg
43*10d565efSmrg */
44*10d565efSmrg
45*10d565efSmrg #ifdef HAVE_CONFIG_H
46*10d565efSmrg #include <config.h>
47*10d565efSmrg #endif
48*10d565efSmrg
49*10d565efSmrg #include <libiberty.h>
50*10d565efSmrg
51*10d565efSmrg #ifdef HAVE_STRING_H
52*10d565efSmrg #include <string.h>
53*10d565efSmrg #endif
54*10d565efSmrg #ifdef HAVE_STDLIB_H
55*10d565efSmrg #include <stdlib.h>
56*10d565efSmrg #endif
57*10d565efSmrg
58*10d565efSmrg /* These variables are used by the ASTRDUP implementation that relies
59*10d565efSmrg on C_alloca. */
60*10d565efSmrg #ifdef __cplusplus
61*10d565efSmrg extern "C" {
62*10d565efSmrg #endif /* __cplusplus */
63*10d565efSmrg const char *libiberty_optr;
64*10d565efSmrg char *libiberty_nptr;
65*10d565efSmrg unsigned long libiberty_len;
66*10d565efSmrg #ifdef __cplusplus
67*10d565efSmrg }
68*10d565efSmrg #endif /* __cplusplus */
69*10d565efSmrg
70*10d565efSmrg /* If your stack is a linked list of frames, you have to
71*10d565efSmrg provide an "address metric" ADDRESS_FUNCTION macro. */
72*10d565efSmrg
73*10d565efSmrg #if defined (CRAY) && defined (CRAY_STACKSEG_END)
74*10d565efSmrg static long i00afunc ();
75*10d565efSmrg #define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
76*10d565efSmrg #else
77*10d565efSmrg #define ADDRESS_FUNCTION(arg) &(arg)
78*10d565efSmrg #endif
79*10d565efSmrg
80*10d565efSmrg #ifndef NULL
81*10d565efSmrg #define NULL 0
82*10d565efSmrg #endif
83*10d565efSmrg
84*10d565efSmrg /* Define STACK_DIRECTION if you know the direction of stack
85*10d565efSmrg growth for your system; otherwise it will be automatically
86*10d565efSmrg deduced at run-time.
87*10d565efSmrg
88*10d565efSmrg STACK_DIRECTION > 0 => grows toward higher addresses
89*10d565efSmrg STACK_DIRECTION < 0 => grows toward lower addresses
90*10d565efSmrg STACK_DIRECTION = 0 => direction of growth unknown */
91*10d565efSmrg
92*10d565efSmrg #ifndef STACK_DIRECTION
93*10d565efSmrg #define STACK_DIRECTION 0 /* Direction unknown. */
94*10d565efSmrg #endif
95*10d565efSmrg
96*10d565efSmrg #if STACK_DIRECTION != 0
97*10d565efSmrg
98*10d565efSmrg #define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
99*10d565efSmrg
100*10d565efSmrg #else /* STACK_DIRECTION == 0; need run-time code. */
101*10d565efSmrg
102*10d565efSmrg static int stack_dir; /* 1 or -1 once known. */
103*10d565efSmrg #define STACK_DIR stack_dir
104*10d565efSmrg
105*10d565efSmrg static void
find_stack_direction(void)106*10d565efSmrg find_stack_direction (void)
107*10d565efSmrg {
108*10d565efSmrg static char *addr = NULL; /* Address of first `dummy', once known. */
109*10d565efSmrg auto char dummy; /* To get stack address. */
110*10d565efSmrg
111*10d565efSmrg if (addr == NULL)
112*10d565efSmrg { /* Initial entry. */
113*10d565efSmrg addr = ADDRESS_FUNCTION (dummy);
114*10d565efSmrg
115*10d565efSmrg find_stack_direction (); /* Recurse once. */
116*10d565efSmrg }
117*10d565efSmrg else
118*10d565efSmrg {
119*10d565efSmrg /* Second entry. */
120*10d565efSmrg if (ADDRESS_FUNCTION (dummy) > addr)
121*10d565efSmrg stack_dir = 1; /* Stack grew upward. */
122*10d565efSmrg else
123*10d565efSmrg stack_dir = -1; /* Stack grew downward. */
124*10d565efSmrg }
125*10d565efSmrg }
126*10d565efSmrg
127*10d565efSmrg #endif /* STACK_DIRECTION == 0 */
128*10d565efSmrg
129*10d565efSmrg /* An "alloca header" is used to:
130*10d565efSmrg (a) chain together all alloca'ed blocks;
131*10d565efSmrg (b) keep track of stack depth.
132*10d565efSmrg
133*10d565efSmrg It is very important that sizeof(header) agree with malloc
134*10d565efSmrg alignment chunk size. The following default should work okay. */
135*10d565efSmrg
136*10d565efSmrg #ifndef ALIGN_SIZE
137*10d565efSmrg #define ALIGN_SIZE sizeof(double)
138*10d565efSmrg #endif
139*10d565efSmrg
140*10d565efSmrg typedef union hdr
141*10d565efSmrg {
142*10d565efSmrg char align[ALIGN_SIZE]; /* To force sizeof(header). */
143*10d565efSmrg struct
144*10d565efSmrg {
145*10d565efSmrg union hdr *next; /* For chaining headers. */
146*10d565efSmrg char *deep; /* For stack depth measure. */
147*10d565efSmrg } h;
148*10d565efSmrg } header;
149*10d565efSmrg
150*10d565efSmrg static header *last_alloca_header = NULL; /* -> last alloca header. */
151*10d565efSmrg
152*10d565efSmrg /* Return a pointer to at least SIZE bytes of storage,
153*10d565efSmrg which will be automatically reclaimed upon exit from
154*10d565efSmrg the procedure that called alloca. Originally, this space
155*10d565efSmrg was supposed to be taken from the current stack frame of the
156*10d565efSmrg caller, but that method cannot be made to work for some
157*10d565efSmrg implementations of C, for example under Gould's UTX/32. */
158*10d565efSmrg
159*10d565efSmrg /* @undocumented C_alloca */
160*10d565efSmrg
161*10d565efSmrg PTR
C_alloca(size_t size)162*10d565efSmrg C_alloca (size_t size)
163*10d565efSmrg {
164*10d565efSmrg char probe; /* Probes stack depth: */
165*10d565efSmrg register char *depth = ADDRESS_FUNCTION (probe);
166*10d565efSmrg
167*10d565efSmrg #if STACK_DIRECTION == 0
168*10d565efSmrg if (STACK_DIR == 0) /* Unknown growth direction. */
169*10d565efSmrg find_stack_direction ();
170*10d565efSmrg #endif
171*10d565efSmrg
172*10d565efSmrg /* Reclaim garbage, defined as all alloca'd storage that
173*10d565efSmrg was allocated from deeper in the stack than currently. */
174*10d565efSmrg
175*10d565efSmrg {
176*10d565efSmrg register header *hp; /* Traverses linked list. */
177*10d565efSmrg
178*10d565efSmrg for (hp = last_alloca_header; hp != NULL;)
179*10d565efSmrg if ((STACK_DIR > 0 && hp->h.deep > depth)
180*10d565efSmrg || (STACK_DIR < 0 && hp->h.deep < depth))
181*10d565efSmrg {
182*10d565efSmrg register header *np = hp->h.next;
183*10d565efSmrg
184*10d565efSmrg free ((PTR) hp); /* Collect garbage. */
185*10d565efSmrg
186*10d565efSmrg hp = np; /* -> next header. */
187*10d565efSmrg }
188*10d565efSmrg else
189*10d565efSmrg break; /* Rest are not deeper. */
190*10d565efSmrg
191*10d565efSmrg last_alloca_header = hp; /* -> last valid storage. */
192*10d565efSmrg }
193*10d565efSmrg
194*10d565efSmrg if (size == 0)
195*10d565efSmrg return NULL; /* No allocation required. */
196*10d565efSmrg
197*10d565efSmrg /* Allocate combined header + user data storage. */
198*10d565efSmrg
199*10d565efSmrg {
200*10d565efSmrg register void *new_storage = XNEWVEC (char, sizeof (header) + size);
201*10d565efSmrg /* Address of header. */
202*10d565efSmrg
203*10d565efSmrg if (new_storage == 0)
204*10d565efSmrg abort();
205*10d565efSmrg
206*10d565efSmrg ((header *) new_storage)->h.next = last_alloca_header;
207*10d565efSmrg ((header *) new_storage)->h.deep = depth;
208*10d565efSmrg
209*10d565efSmrg last_alloca_header = (header *) new_storage;
210*10d565efSmrg
211*10d565efSmrg /* User storage begins just after header. */
212*10d565efSmrg
213*10d565efSmrg return (PTR) ((char *) new_storage + sizeof (header));
214*10d565efSmrg }
215*10d565efSmrg }
216*10d565efSmrg
217*10d565efSmrg #if defined (CRAY) && defined (CRAY_STACKSEG_END)
218*10d565efSmrg
219*10d565efSmrg #ifdef DEBUG_I00AFUNC
220*10d565efSmrg #include <stdio.h>
221*10d565efSmrg #endif
222*10d565efSmrg
223*10d565efSmrg #ifndef CRAY_STACK
224*10d565efSmrg #define CRAY_STACK
225*10d565efSmrg #ifndef CRAY2
226*10d565efSmrg /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
227*10d565efSmrg struct stack_control_header
228*10d565efSmrg {
229*10d565efSmrg long shgrow:32; /* Number of times stack has grown. */
230*10d565efSmrg long shaseg:32; /* Size of increments to stack. */
231*10d565efSmrg long shhwm:32; /* High water mark of stack. */
232*10d565efSmrg long shsize:32; /* Current size of stack (all segments). */
233*10d565efSmrg };
234*10d565efSmrg
235*10d565efSmrg /* The stack segment linkage control information occurs at
236*10d565efSmrg the high-address end of a stack segment. (The stack
237*10d565efSmrg grows from low addresses to high addresses.) The initial
238*10d565efSmrg part of the stack segment linkage control information is
239*10d565efSmrg 0200 (octal) words. This provides for register storage
240*10d565efSmrg for the routine which overflows the stack. */
241*10d565efSmrg
242*10d565efSmrg struct stack_segment_linkage
243*10d565efSmrg {
244*10d565efSmrg long ss[0200]; /* 0200 overflow words. */
245*10d565efSmrg long sssize:32; /* Number of words in this segment. */
246*10d565efSmrg long ssbase:32; /* Offset to stack base. */
247*10d565efSmrg long:32;
248*10d565efSmrg long sspseg:32; /* Offset to linkage control of previous
249*10d565efSmrg segment of stack. */
250*10d565efSmrg long:32;
251*10d565efSmrg long sstcpt:32; /* Pointer to task common address block. */
252*10d565efSmrg long sscsnm; /* Private control structure number for
253*10d565efSmrg microtasking. */
254*10d565efSmrg long ssusr1; /* Reserved for user. */
255*10d565efSmrg long ssusr2; /* Reserved for user. */
256*10d565efSmrg long sstpid; /* Process ID for pid based multi-tasking. */
257*10d565efSmrg long ssgvup; /* Pointer to multitasking thread giveup. */
258*10d565efSmrg long sscray[7]; /* Reserved for Cray Research. */
259*10d565efSmrg long ssa0;
260*10d565efSmrg long ssa1;
261*10d565efSmrg long ssa2;
262*10d565efSmrg long ssa3;
263*10d565efSmrg long ssa4;
264*10d565efSmrg long ssa5;
265*10d565efSmrg long ssa6;
266*10d565efSmrg long ssa7;
267*10d565efSmrg long sss0;
268*10d565efSmrg long sss1;
269*10d565efSmrg long sss2;
270*10d565efSmrg long sss3;
271*10d565efSmrg long sss4;
272*10d565efSmrg long sss5;
273*10d565efSmrg long sss6;
274*10d565efSmrg long sss7;
275*10d565efSmrg };
276*10d565efSmrg
277*10d565efSmrg #else /* CRAY2 */
278*10d565efSmrg /* The following structure defines the vector of words
279*10d565efSmrg returned by the STKSTAT library routine. */
280*10d565efSmrg struct stk_stat
281*10d565efSmrg {
282*10d565efSmrg long now; /* Current total stack size. */
283*10d565efSmrg long maxc; /* Amount of contiguous space which would
284*10d565efSmrg be required to satisfy the maximum
285*10d565efSmrg stack demand to date. */
286*10d565efSmrg long high_water; /* Stack high-water mark. */
287*10d565efSmrg long overflows; /* Number of stack overflow ($STKOFEN) calls. */
288*10d565efSmrg long hits; /* Number of internal buffer hits. */
289*10d565efSmrg long extends; /* Number of block extensions. */
290*10d565efSmrg long stko_mallocs; /* Block allocations by $STKOFEN. */
291*10d565efSmrg long underflows; /* Number of stack underflow calls ($STKRETN). */
292*10d565efSmrg long stko_free; /* Number of deallocations by $STKRETN. */
293*10d565efSmrg long stkm_free; /* Number of deallocations by $STKMRET. */
294*10d565efSmrg long segments; /* Current number of stack segments. */
295*10d565efSmrg long maxs; /* Maximum number of stack segments so far. */
296*10d565efSmrg long pad_size; /* Stack pad size. */
297*10d565efSmrg long current_address; /* Current stack segment address. */
298*10d565efSmrg long current_size; /* Current stack segment size. This
299*10d565efSmrg number is actually corrupted by STKSTAT to
300*10d565efSmrg include the fifteen word trailer area. */
301*10d565efSmrg long initial_address; /* Address of initial segment. */
302*10d565efSmrg long initial_size; /* Size of initial segment. */
303*10d565efSmrg };
304*10d565efSmrg
305*10d565efSmrg /* The following structure describes the data structure which trails
306*10d565efSmrg any stack segment. I think that the description in 'asdef' is
307*10d565efSmrg out of date. I only describe the parts that I am sure about. */
308*10d565efSmrg
309*10d565efSmrg struct stk_trailer
310*10d565efSmrg {
311*10d565efSmrg long this_address; /* Address of this block. */
312*10d565efSmrg long this_size; /* Size of this block (does not include
313*10d565efSmrg this trailer). */
314*10d565efSmrg long unknown2;
315*10d565efSmrg long unknown3;
316*10d565efSmrg long link; /* Address of trailer block of previous
317*10d565efSmrg segment. */
318*10d565efSmrg long unknown5;
319*10d565efSmrg long unknown6;
320*10d565efSmrg long unknown7;
321*10d565efSmrg long unknown8;
322*10d565efSmrg long unknown9;
323*10d565efSmrg long unknown10;
324*10d565efSmrg long unknown11;
325*10d565efSmrg long unknown12;
326*10d565efSmrg long unknown13;
327*10d565efSmrg long unknown14;
328*10d565efSmrg };
329*10d565efSmrg
330*10d565efSmrg #endif /* CRAY2 */
331*10d565efSmrg #endif /* not CRAY_STACK */
332*10d565efSmrg
333*10d565efSmrg #ifdef CRAY2
334*10d565efSmrg /* Determine a "stack measure" for an arbitrary ADDRESS.
335*10d565efSmrg I doubt that "lint" will like this much. */
336*10d565efSmrg
337*10d565efSmrg static long
i00afunc(long * address)338*10d565efSmrg i00afunc (long *address)
339*10d565efSmrg {
340*10d565efSmrg struct stk_stat status;
341*10d565efSmrg struct stk_trailer *trailer;
342*10d565efSmrg long *block, size;
343*10d565efSmrg long result = 0;
344*10d565efSmrg
345*10d565efSmrg /* We want to iterate through all of the segments. The first
346*10d565efSmrg step is to get the stack status structure. We could do this
347*10d565efSmrg more quickly and more directly, perhaps, by referencing the
348*10d565efSmrg $LM00 common block, but I know that this works. */
349*10d565efSmrg
350*10d565efSmrg STKSTAT (&status);
351*10d565efSmrg
352*10d565efSmrg /* Set up the iteration. */
353*10d565efSmrg
354*10d565efSmrg trailer = (struct stk_trailer *) (status.current_address
355*10d565efSmrg + status.current_size
356*10d565efSmrg - 15);
357*10d565efSmrg
358*10d565efSmrg /* There must be at least one stack segment. Therefore it is
359*10d565efSmrg a fatal error if "trailer" is null. */
360*10d565efSmrg
361*10d565efSmrg if (trailer == 0)
362*10d565efSmrg abort ();
363*10d565efSmrg
364*10d565efSmrg /* Discard segments that do not contain our argument address. */
365*10d565efSmrg
366*10d565efSmrg while (trailer != 0)
367*10d565efSmrg {
368*10d565efSmrg block = (long *) trailer->this_address;
369*10d565efSmrg size = trailer->this_size;
370*10d565efSmrg if (block == 0 || size == 0)
371*10d565efSmrg abort ();
372*10d565efSmrg trailer = (struct stk_trailer *) trailer->link;
373*10d565efSmrg if ((block <= address) && (address < (block + size)))
374*10d565efSmrg break;
375*10d565efSmrg }
376*10d565efSmrg
377*10d565efSmrg /* Set the result to the offset in this segment and add the sizes
378*10d565efSmrg of all predecessor segments. */
379*10d565efSmrg
380*10d565efSmrg result = address - block;
381*10d565efSmrg
382*10d565efSmrg if (trailer == 0)
383*10d565efSmrg {
384*10d565efSmrg return result;
385*10d565efSmrg }
386*10d565efSmrg
387*10d565efSmrg do
388*10d565efSmrg {
389*10d565efSmrg if (trailer->this_size <= 0)
390*10d565efSmrg abort ();
391*10d565efSmrg result += trailer->this_size;
392*10d565efSmrg trailer = (struct stk_trailer *) trailer->link;
393*10d565efSmrg }
394*10d565efSmrg while (trailer != 0);
395*10d565efSmrg
396*10d565efSmrg /* We are done. Note that if you present a bogus address (one
397*10d565efSmrg not in any segment), you will get a different number back, formed
398*10d565efSmrg from subtracting the address of the first block. This is probably
399*10d565efSmrg not what you want. */
400*10d565efSmrg
401*10d565efSmrg return (result);
402*10d565efSmrg }
403*10d565efSmrg
404*10d565efSmrg #else /* not CRAY2 */
405*10d565efSmrg /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
406*10d565efSmrg Determine the number of the cell within the stack,
407*10d565efSmrg given the address of the cell. The purpose of this
408*10d565efSmrg routine is to linearize, in some sense, stack addresses
409*10d565efSmrg for alloca. */
410*10d565efSmrg
411*10d565efSmrg static long
i00afunc(long address)412*10d565efSmrg i00afunc (long address)
413*10d565efSmrg {
414*10d565efSmrg long stkl = 0;
415*10d565efSmrg
416*10d565efSmrg long size, pseg, this_segment, stack;
417*10d565efSmrg long result = 0;
418*10d565efSmrg
419*10d565efSmrg struct stack_segment_linkage *ssptr;
420*10d565efSmrg
421*10d565efSmrg /* Register B67 contains the address of the end of the
422*10d565efSmrg current stack segment. If you (as a subprogram) store
423*10d565efSmrg your registers on the stack and find that you are past
424*10d565efSmrg the contents of B67, you have overflowed the segment.
425*10d565efSmrg
426*10d565efSmrg B67 also points to the stack segment linkage control
427*10d565efSmrg area, which is what we are really interested in. */
428*10d565efSmrg
429*10d565efSmrg stkl = CRAY_STACKSEG_END ();
430*10d565efSmrg ssptr = (struct stack_segment_linkage *) stkl;
431*10d565efSmrg
432*10d565efSmrg /* If one subtracts 'size' from the end of the segment,
433*10d565efSmrg one has the address of the first word of the segment.
434*10d565efSmrg
435*10d565efSmrg If this is not the first segment, 'pseg' will be
436*10d565efSmrg nonzero. */
437*10d565efSmrg
438*10d565efSmrg pseg = ssptr->sspseg;
439*10d565efSmrg size = ssptr->sssize;
440*10d565efSmrg
441*10d565efSmrg this_segment = stkl - size;
442*10d565efSmrg
443*10d565efSmrg /* It is possible that calling this routine itself caused
444*10d565efSmrg a stack overflow. Discard stack segments which do not
445*10d565efSmrg contain the target address. */
446*10d565efSmrg
447*10d565efSmrg while (!(this_segment <= address && address <= stkl))
448*10d565efSmrg {
449*10d565efSmrg #ifdef DEBUG_I00AFUNC
450*10d565efSmrg fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
451*10d565efSmrg #endif
452*10d565efSmrg if (pseg == 0)
453*10d565efSmrg break;
454*10d565efSmrg stkl = stkl - pseg;
455*10d565efSmrg ssptr = (struct stack_segment_linkage *) stkl;
456*10d565efSmrg size = ssptr->sssize;
457*10d565efSmrg pseg = ssptr->sspseg;
458*10d565efSmrg this_segment = stkl - size;
459*10d565efSmrg }
460*10d565efSmrg
461*10d565efSmrg result = address - this_segment;
462*10d565efSmrg
463*10d565efSmrg /* If you subtract pseg from the current end of the stack,
464*10d565efSmrg you get the address of the previous stack segment's end.
465*10d565efSmrg This seems a little convoluted to me, but I'll bet you save
466*10d565efSmrg a cycle somewhere. */
467*10d565efSmrg
468*10d565efSmrg while (pseg != 0)
469*10d565efSmrg {
470*10d565efSmrg #ifdef DEBUG_I00AFUNC
471*10d565efSmrg fprintf (stderr, "%011o %011o\n", pseg, size);
472*10d565efSmrg #endif
473*10d565efSmrg stkl = stkl - pseg;
474*10d565efSmrg ssptr = (struct stack_segment_linkage *) stkl;
475*10d565efSmrg size = ssptr->sssize;
476*10d565efSmrg pseg = ssptr->sspseg;
477*10d565efSmrg result += size;
478*10d565efSmrg }
479*10d565efSmrg return (result);
480*10d565efSmrg }
481*10d565efSmrg
482*10d565efSmrg #endif /* not CRAY2 */
483*10d565efSmrg #endif /* CRAY */
484