1840175f0Skstailey /* alloca.c -- allocate automatically reclaimed memory
2840175f0Skstailey (Mostly) portable public-domain implementation -- D A Gwyn
3840175f0Skstailey
4840175f0Skstailey This implementation of the PWB library alloca function,
5840175f0Skstailey which is used to allocate space off the run-time stack so
6840175f0Skstailey that it is automatically reclaimed upon procedure exit,
7840175f0Skstailey was inspired by discussions with J. Q. Johnson of Cornell.
8840175f0Skstailey J.Otto Tennant <jot@cray.com> contributed the Cray support.
9840175f0Skstailey
10840175f0Skstailey There are some preprocessor constants that can
11840175f0Skstailey be defined when compiling for your specific system, for
12840175f0Skstailey improved efficiency; however, the defaults should be okay.
13840175f0Skstailey
14840175f0Skstailey The general concept of this implementation is to keep
15840175f0Skstailey track of all alloca-allocated blocks, and reclaim any
16840175f0Skstailey that are found to be deeper in the stack than the current
17840175f0Skstailey invocation. This heuristic does not reclaim storage as
18840175f0Skstailey soon as it becomes invalid, but it will do so eventually.
19840175f0Skstailey
20840175f0Skstailey As a special case, alloca(0) reclaims storage without
21840175f0Skstailey allocating any. It is a good idea to use alloca(0) in
22840175f0Skstailey your main control loop, etc. to force garbage collection. */
23840175f0Skstailey
24840175f0Skstailey #ifdef HAVE_CONFIG_H
25840175f0Skstailey # include <config.h>
26840175f0Skstailey #endif
27840175f0Skstailey
28*a1acfa9bSespie #include <alloca.h>
29*a1acfa9bSespie
30*a1acfa9bSespie #include <string.h>
31*a1acfa9bSespie #include <stdlib.h>
32*a1acfa9bSespie
33840175f0Skstailey #ifdef emacs
34*a1acfa9bSespie # include "lisp.h"
35840175f0Skstailey # include "blockinput.h"
36*a1acfa9bSespie # ifdef EMACS_FREE
37*a1acfa9bSespie # undef free
38*a1acfa9bSespie # define free EMACS_FREE
39*a1acfa9bSespie # endif
40*a1acfa9bSespie #else
41*a1acfa9bSespie # define memory_full() abort ()
42840175f0Skstailey #endif
43840175f0Skstailey
44840175f0Skstailey /* If compiling with GCC 2, this file's not needed. */
45840175f0Skstailey #if !defined (__GNUC__) || __GNUC__ < 2
46840175f0Skstailey
47840175f0Skstailey /* If someone has defined alloca as a macro,
48840175f0Skstailey there must be some other way alloca is supposed to work. */
49840175f0Skstailey # ifndef alloca
50840175f0Skstailey
51840175f0Skstailey # ifdef emacs
52840175f0Skstailey # ifdef static
53840175f0Skstailey /* actually, only want this if static is defined as ""
54840175f0Skstailey -- this is for usg, in which emacs must undefine static
55840175f0Skstailey in order to make unexec workable
56840175f0Skstailey */
57840175f0Skstailey # ifndef STACK_DIRECTION
58840175f0Skstailey you
59840175f0Skstailey lose
60840175f0Skstailey -- must know STACK_DIRECTION at compile-time
61*a1acfa9bSespie /* Using #error here is not wise since this file should work for
62*a1acfa9bSespie old and obscure compilers. */
63840175f0Skstailey # endif /* STACK_DIRECTION undefined */
64840175f0Skstailey # endif /* static */
65840175f0Skstailey # endif /* emacs */
66840175f0Skstailey
67840175f0Skstailey /* If your stack is a linked list of frames, you have to
68840175f0Skstailey provide an "address metric" ADDRESS_FUNCTION macro. */
69840175f0Skstailey
70840175f0Skstailey # if defined (CRAY) && defined (CRAY_STACKSEG_END)
71840175f0Skstailey long i00afunc ();
72840175f0Skstailey # define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
73840175f0Skstailey # else
74840175f0Skstailey # define ADDRESS_FUNCTION(arg) &(arg)
75840175f0Skstailey # endif
76840175f0Skstailey
77840175f0Skstailey /* Define STACK_DIRECTION if you know the direction of stack
78840175f0Skstailey growth for your system; otherwise it will be automatically
79840175f0Skstailey deduced at run-time.
80840175f0Skstailey
81840175f0Skstailey STACK_DIRECTION > 0 => grows toward higher addresses
82840175f0Skstailey STACK_DIRECTION < 0 => grows toward lower addresses
83840175f0Skstailey STACK_DIRECTION = 0 => direction of growth unknown */
84840175f0Skstailey
85840175f0Skstailey # ifndef STACK_DIRECTION
86840175f0Skstailey # define STACK_DIRECTION 0 /* Direction unknown. */
87840175f0Skstailey # endif
88840175f0Skstailey
89840175f0Skstailey # if STACK_DIRECTION != 0
90840175f0Skstailey
91840175f0Skstailey # define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
92840175f0Skstailey
93840175f0Skstailey # else /* STACK_DIRECTION == 0; need run-time code. */
94840175f0Skstailey
95840175f0Skstailey static int stack_dir; /* 1 or -1 once known. */
96840175f0Skstailey # define STACK_DIR stack_dir
97840175f0Skstailey
98840175f0Skstailey static void
find_stack_direction(void)99*a1acfa9bSespie find_stack_direction (void)
100840175f0Skstailey {
101840175f0Skstailey static char *addr = NULL; /* Address of first `dummy', once known. */
102840175f0Skstailey auto char dummy; /* To get stack address. */
103840175f0Skstailey
104840175f0Skstailey if (addr == NULL)
105840175f0Skstailey { /* Initial entry. */
106840175f0Skstailey addr = ADDRESS_FUNCTION (dummy);
107840175f0Skstailey
108840175f0Skstailey find_stack_direction (); /* Recurse once. */
109840175f0Skstailey }
110840175f0Skstailey else
111840175f0Skstailey {
112840175f0Skstailey /* Second entry. */
113840175f0Skstailey if (ADDRESS_FUNCTION (dummy) > addr)
114840175f0Skstailey stack_dir = 1; /* Stack grew upward. */
115840175f0Skstailey else
116840175f0Skstailey stack_dir = -1; /* Stack grew downward. */
117840175f0Skstailey }
118840175f0Skstailey }
119840175f0Skstailey
120840175f0Skstailey # endif /* STACK_DIRECTION == 0 */
121840175f0Skstailey
122840175f0Skstailey /* An "alloca header" is used to:
123840175f0Skstailey (a) chain together all alloca'ed blocks;
124840175f0Skstailey (b) keep track of stack depth.
125840175f0Skstailey
126840175f0Skstailey It is very important that sizeof(header) agree with malloc
127840175f0Skstailey alignment chunk size. The following default should work okay. */
128840175f0Skstailey
129840175f0Skstailey # ifndef ALIGN_SIZE
130840175f0Skstailey # define ALIGN_SIZE sizeof(double)
131840175f0Skstailey # endif
132840175f0Skstailey
133840175f0Skstailey typedef union hdr
134840175f0Skstailey {
135840175f0Skstailey char align[ALIGN_SIZE]; /* To force sizeof(header). */
136840175f0Skstailey struct
137840175f0Skstailey {
138840175f0Skstailey union hdr *next; /* For chaining headers. */
139840175f0Skstailey char *deep; /* For stack depth measure. */
140840175f0Skstailey } h;
141840175f0Skstailey } header;
142840175f0Skstailey
143840175f0Skstailey static header *last_alloca_header = NULL; /* -> last alloca header. */
144840175f0Skstailey
145840175f0Skstailey /* Return a pointer to at least SIZE bytes of storage,
146840175f0Skstailey which will be automatically reclaimed upon exit from
147840175f0Skstailey the procedure that called alloca. Originally, this space
148840175f0Skstailey was supposed to be taken from the current stack frame of the
149840175f0Skstailey caller, but that method cannot be made to work for some
150840175f0Skstailey implementations of C, for example under Gould's UTX/32. */
151840175f0Skstailey
152*a1acfa9bSespie void *
alloca(size_t size)153*a1acfa9bSespie alloca (size_t size)
154840175f0Skstailey {
155840175f0Skstailey auto char probe; /* Probes stack depth: */
156840175f0Skstailey register char *depth = ADDRESS_FUNCTION (probe);
157840175f0Skstailey
158840175f0Skstailey # if STACK_DIRECTION == 0
159840175f0Skstailey if (STACK_DIR == 0) /* Unknown growth direction. */
160840175f0Skstailey find_stack_direction ();
161840175f0Skstailey # endif
162840175f0Skstailey
163840175f0Skstailey /* Reclaim garbage, defined as all alloca'd storage that
164840175f0Skstailey was allocated from deeper in the stack than currently. */
165840175f0Skstailey
166840175f0Skstailey {
167840175f0Skstailey register header *hp; /* Traverses linked list. */
168840175f0Skstailey
169840175f0Skstailey # ifdef emacs
170840175f0Skstailey BLOCK_INPUT;
171840175f0Skstailey # endif
172840175f0Skstailey
173840175f0Skstailey for (hp = last_alloca_header; hp != NULL;)
174840175f0Skstailey if ((STACK_DIR > 0 && hp->h.deep > depth)
175840175f0Skstailey || (STACK_DIR < 0 && hp->h.deep < depth))
176840175f0Skstailey {
177840175f0Skstailey register header *np = hp->h.next;
178840175f0Skstailey
179*a1acfa9bSespie free (hp); /* Collect garbage. */
180840175f0Skstailey
181840175f0Skstailey hp = np; /* -> next header. */
182840175f0Skstailey }
183840175f0Skstailey else
184840175f0Skstailey break; /* Rest are not deeper. */
185840175f0Skstailey
186840175f0Skstailey last_alloca_header = hp; /* -> last valid storage. */
187840175f0Skstailey
188840175f0Skstailey # ifdef emacs
189840175f0Skstailey UNBLOCK_INPUT;
190840175f0Skstailey # endif
191840175f0Skstailey }
192840175f0Skstailey
193840175f0Skstailey if (size == 0)
194840175f0Skstailey return NULL; /* No allocation required. */
195840175f0Skstailey
196840175f0Skstailey /* Allocate combined header + user data storage. */
197840175f0Skstailey
198840175f0Skstailey {
199840175f0Skstailey /* Address of header. */
200*a1acfa9bSespie register header *new;
201840175f0Skstailey
202*a1acfa9bSespie size_t combined_size = sizeof (header) + size;
203*a1acfa9bSespie if (combined_size < sizeof (header))
204*a1acfa9bSespie memory_full ();
205840175f0Skstailey
206*a1acfa9bSespie new = malloc (combined_size);
207*a1acfa9bSespie
208*a1acfa9bSespie if (! new)
209*a1acfa9bSespie memory_full ();
210*a1acfa9bSespie
211*a1acfa9bSespie new->h.next = last_alloca_header;
212*a1acfa9bSespie new->h.deep = depth;
213*a1acfa9bSespie
214*a1acfa9bSespie last_alloca_header = new;
215840175f0Skstailey
216840175f0Skstailey /* User storage begins just after header. */
217840175f0Skstailey
218*a1acfa9bSespie return (void *) (new + 1);
219840175f0Skstailey }
220840175f0Skstailey }
221840175f0Skstailey
222840175f0Skstailey # if defined (CRAY) && defined (CRAY_STACKSEG_END)
223840175f0Skstailey
224840175f0Skstailey # ifdef DEBUG_I00AFUNC
225840175f0Skstailey # include <stdio.h>
226840175f0Skstailey # endif
227840175f0Skstailey
228840175f0Skstailey # ifndef CRAY_STACK
229840175f0Skstailey # define CRAY_STACK
230840175f0Skstailey # ifndef CRAY2
231840175f0Skstailey /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
232840175f0Skstailey struct stack_control_header
233840175f0Skstailey {
234840175f0Skstailey long shgrow:32; /* Number of times stack has grown. */
235840175f0Skstailey long shaseg:32; /* Size of increments to stack. */
236840175f0Skstailey long shhwm:32; /* High water mark of stack. */
237840175f0Skstailey long shsize:32; /* Current size of stack (all segments). */
238840175f0Skstailey };
239840175f0Skstailey
240840175f0Skstailey /* The stack segment linkage control information occurs at
241840175f0Skstailey the high-address end of a stack segment. (The stack
242840175f0Skstailey grows from low addresses to high addresses.) The initial
243840175f0Skstailey part of the stack segment linkage control information is
244840175f0Skstailey 0200 (octal) words. This provides for register storage
245840175f0Skstailey for the routine which overflows the stack. */
246840175f0Skstailey
247840175f0Skstailey struct stack_segment_linkage
248840175f0Skstailey {
249840175f0Skstailey long ss[0200]; /* 0200 overflow words. */
250840175f0Skstailey long sssize:32; /* Number of words in this segment. */
251840175f0Skstailey long ssbase:32; /* Offset to stack base. */
252840175f0Skstailey long:32;
253840175f0Skstailey long sspseg:32; /* Offset to linkage control of previous
254840175f0Skstailey segment of stack. */
255840175f0Skstailey long:32;
256840175f0Skstailey long sstcpt:32; /* Pointer to task common address block. */
257840175f0Skstailey long sscsnm; /* Private control structure number for
258840175f0Skstailey microtasking. */
259840175f0Skstailey long ssusr1; /* Reserved for user. */
260840175f0Skstailey long ssusr2; /* Reserved for user. */
261840175f0Skstailey long sstpid; /* Process ID for pid based multi-tasking. */
262840175f0Skstailey long ssgvup; /* Pointer to multitasking thread giveup. */
263840175f0Skstailey long sscray[7]; /* Reserved for Cray Research. */
264840175f0Skstailey long ssa0;
265840175f0Skstailey long ssa1;
266840175f0Skstailey long ssa2;
267840175f0Skstailey long ssa3;
268840175f0Skstailey long ssa4;
269840175f0Skstailey long ssa5;
270840175f0Skstailey long ssa6;
271840175f0Skstailey long ssa7;
272840175f0Skstailey long sss0;
273840175f0Skstailey long sss1;
274840175f0Skstailey long sss2;
275840175f0Skstailey long sss3;
276840175f0Skstailey long sss4;
277840175f0Skstailey long sss5;
278840175f0Skstailey long sss6;
279840175f0Skstailey long sss7;
280840175f0Skstailey };
281840175f0Skstailey
282840175f0Skstailey # else /* CRAY2 */
283840175f0Skstailey /* The following structure defines the vector of words
284840175f0Skstailey returned by the STKSTAT library routine. */
285840175f0Skstailey struct stk_stat
286840175f0Skstailey {
287840175f0Skstailey long now; /* Current total stack size. */
288840175f0Skstailey long maxc; /* Amount of contiguous space which would
289840175f0Skstailey be required to satisfy the maximum
290840175f0Skstailey stack demand to date. */
291840175f0Skstailey long high_water; /* Stack high-water mark. */
292840175f0Skstailey long overflows; /* Number of stack overflow ($STKOFEN) calls. */
293840175f0Skstailey long hits; /* Number of internal buffer hits. */
294840175f0Skstailey long extends; /* Number of block extensions. */
295840175f0Skstailey long stko_mallocs; /* Block allocations by $STKOFEN. */
296840175f0Skstailey long underflows; /* Number of stack underflow calls ($STKRETN). */
297840175f0Skstailey long stko_free; /* Number of deallocations by $STKRETN. */
298840175f0Skstailey long stkm_free; /* Number of deallocations by $STKMRET. */
299840175f0Skstailey long segments; /* Current number of stack segments. */
300840175f0Skstailey long maxs; /* Maximum number of stack segments so far. */
301840175f0Skstailey long pad_size; /* Stack pad size. */
302840175f0Skstailey long current_address; /* Current stack segment address. */
303840175f0Skstailey long current_size; /* Current stack segment size. This
304840175f0Skstailey number is actually corrupted by STKSTAT to
305840175f0Skstailey include the fifteen word trailer area. */
306840175f0Skstailey long initial_address; /* Address of initial segment. */
307840175f0Skstailey long initial_size; /* Size of initial segment. */
308840175f0Skstailey };
309840175f0Skstailey
310840175f0Skstailey /* The following structure describes the data structure which trails
311840175f0Skstailey any stack segment. I think that the description in 'asdef' is
312840175f0Skstailey out of date. I only describe the parts that I am sure about. */
313840175f0Skstailey
314840175f0Skstailey struct stk_trailer
315840175f0Skstailey {
316840175f0Skstailey long this_address; /* Address of this block. */
317840175f0Skstailey long this_size; /* Size of this block (does not include
318840175f0Skstailey this trailer). */
319840175f0Skstailey long unknown2;
320840175f0Skstailey long unknown3;
321840175f0Skstailey long link; /* Address of trailer block of previous
322840175f0Skstailey segment. */
323840175f0Skstailey long unknown5;
324840175f0Skstailey long unknown6;
325840175f0Skstailey long unknown7;
326840175f0Skstailey long unknown8;
327840175f0Skstailey long unknown9;
328840175f0Skstailey long unknown10;
329840175f0Skstailey long unknown11;
330840175f0Skstailey long unknown12;
331840175f0Skstailey long unknown13;
332840175f0Skstailey long unknown14;
333840175f0Skstailey };
334840175f0Skstailey
335840175f0Skstailey # endif /* CRAY2 */
336840175f0Skstailey # endif /* not CRAY_STACK */
337840175f0Skstailey
338840175f0Skstailey # ifdef CRAY2
339840175f0Skstailey /* Determine a "stack measure" for an arbitrary ADDRESS.
340840175f0Skstailey I doubt that "lint" will like this much. */
341840175f0Skstailey
342840175f0Skstailey static long
i00afunc(long * address)343840175f0Skstailey i00afunc (long *address)
344840175f0Skstailey {
345840175f0Skstailey struct stk_stat status;
346840175f0Skstailey struct stk_trailer *trailer;
347840175f0Skstailey long *block, size;
348840175f0Skstailey long result = 0;
349840175f0Skstailey
350840175f0Skstailey /* We want to iterate through all of the segments. The first
351840175f0Skstailey step is to get the stack status structure. We could do this
352840175f0Skstailey more quickly and more directly, perhaps, by referencing the
353840175f0Skstailey $LM00 common block, but I know that this works. */
354840175f0Skstailey
355840175f0Skstailey STKSTAT (&status);
356840175f0Skstailey
357840175f0Skstailey /* Set up the iteration. */
358840175f0Skstailey
359840175f0Skstailey trailer = (struct stk_trailer *) (status.current_address
360840175f0Skstailey + status.current_size
361840175f0Skstailey - 15);
362840175f0Skstailey
363840175f0Skstailey /* There must be at least one stack segment. Therefore it is
364840175f0Skstailey a fatal error if "trailer" is null. */
365840175f0Skstailey
366840175f0Skstailey if (trailer == 0)
367840175f0Skstailey abort ();
368840175f0Skstailey
369840175f0Skstailey /* Discard segments that do not contain our argument address. */
370840175f0Skstailey
371840175f0Skstailey while (trailer != 0)
372840175f0Skstailey {
373840175f0Skstailey block = (long *) trailer->this_address;
374840175f0Skstailey size = trailer->this_size;
375840175f0Skstailey if (block == 0 || size == 0)
376840175f0Skstailey abort ();
377840175f0Skstailey trailer = (struct stk_trailer *) trailer->link;
378840175f0Skstailey if ((block <= address) && (address < (block + size)))
379840175f0Skstailey break;
380840175f0Skstailey }
381840175f0Skstailey
382840175f0Skstailey /* Set the result to the offset in this segment and add the sizes
383840175f0Skstailey of all predecessor segments. */
384840175f0Skstailey
385840175f0Skstailey result = address - block;
386840175f0Skstailey
387840175f0Skstailey if (trailer == 0)
388840175f0Skstailey {
389840175f0Skstailey return result;
390840175f0Skstailey }
391840175f0Skstailey
392840175f0Skstailey do
393840175f0Skstailey {
394840175f0Skstailey if (trailer->this_size <= 0)
395840175f0Skstailey abort ();
396840175f0Skstailey result += trailer->this_size;
397840175f0Skstailey trailer = (struct stk_trailer *) trailer->link;
398840175f0Skstailey }
399840175f0Skstailey while (trailer != 0);
400840175f0Skstailey
401840175f0Skstailey /* We are done. Note that if you present a bogus address (one
402840175f0Skstailey not in any segment), you will get a different number back, formed
403840175f0Skstailey from subtracting the address of the first block. This is probably
404840175f0Skstailey not what you want. */
405840175f0Skstailey
406840175f0Skstailey return (result);
407840175f0Skstailey }
408840175f0Skstailey
409840175f0Skstailey # else /* not CRAY2 */
410840175f0Skstailey /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
411840175f0Skstailey Determine the number of the cell within the stack,
412840175f0Skstailey given the address of the cell. The purpose of this
413840175f0Skstailey routine is to linearize, in some sense, stack addresses
414840175f0Skstailey for alloca. */
415840175f0Skstailey
416840175f0Skstailey static long
i00afunc(long address)417840175f0Skstailey i00afunc (long address)
418840175f0Skstailey {
419840175f0Skstailey long stkl = 0;
420840175f0Skstailey
421840175f0Skstailey long size, pseg, this_segment, stack;
422840175f0Skstailey long result = 0;
423840175f0Skstailey
424840175f0Skstailey struct stack_segment_linkage *ssptr;
425840175f0Skstailey
426840175f0Skstailey /* Register B67 contains the address of the end of the
427840175f0Skstailey current stack segment. If you (as a subprogram) store
428840175f0Skstailey your registers on the stack and find that you are past
429840175f0Skstailey the contents of B67, you have overflowed the segment.
430840175f0Skstailey
431840175f0Skstailey B67 also points to the stack segment linkage control
432840175f0Skstailey area, which is what we are really interested in. */
433840175f0Skstailey
434840175f0Skstailey stkl = CRAY_STACKSEG_END ();
435840175f0Skstailey ssptr = (struct stack_segment_linkage *) stkl;
436840175f0Skstailey
437840175f0Skstailey /* If one subtracts 'size' from the end of the segment,
438840175f0Skstailey one has the address of the first word of the segment.
439840175f0Skstailey
440840175f0Skstailey If this is not the first segment, 'pseg' will be
441840175f0Skstailey nonzero. */
442840175f0Skstailey
443840175f0Skstailey pseg = ssptr->sspseg;
444840175f0Skstailey size = ssptr->sssize;
445840175f0Skstailey
446840175f0Skstailey this_segment = stkl - size;
447840175f0Skstailey
448840175f0Skstailey /* It is possible that calling this routine itself caused
449840175f0Skstailey a stack overflow. Discard stack segments which do not
450840175f0Skstailey contain the target address. */
451840175f0Skstailey
452840175f0Skstailey while (!(this_segment <= address && address <= stkl))
453840175f0Skstailey {
454840175f0Skstailey # ifdef DEBUG_I00AFUNC
455840175f0Skstailey fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
456840175f0Skstailey # endif
457840175f0Skstailey if (pseg == 0)
458840175f0Skstailey break;
459840175f0Skstailey stkl = stkl - pseg;
460840175f0Skstailey ssptr = (struct stack_segment_linkage *) stkl;
461840175f0Skstailey size = ssptr->sssize;
462840175f0Skstailey pseg = ssptr->sspseg;
463840175f0Skstailey this_segment = stkl - size;
464840175f0Skstailey }
465840175f0Skstailey
466840175f0Skstailey result = address - this_segment;
467840175f0Skstailey
468840175f0Skstailey /* If you subtract pseg from the current end of the stack,
469840175f0Skstailey you get the address of the previous stack segment's end.
470840175f0Skstailey This seems a little convoluted to me, but I'll bet you save
471840175f0Skstailey a cycle somewhere. */
472840175f0Skstailey
473840175f0Skstailey while (pseg != 0)
474840175f0Skstailey {
475840175f0Skstailey # ifdef DEBUG_I00AFUNC
476840175f0Skstailey fprintf (stderr, "%011o %011o\n", pseg, size);
477840175f0Skstailey # endif
478840175f0Skstailey stkl = stkl - pseg;
479840175f0Skstailey ssptr = (struct stack_segment_linkage *) stkl;
480840175f0Skstailey size = ssptr->sssize;
481840175f0Skstailey pseg = ssptr->sspseg;
482840175f0Skstailey result += size;
483840175f0Skstailey }
484840175f0Skstailey return (result);
485840175f0Skstailey }
486840175f0Skstailey
487840175f0Skstailey # endif /* not CRAY2 */
488840175f0Skstailey # endif /* CRAY */
489840175f0Skstailey
490840175f0Skstailey # endif /* no alloca */
491840175f0Skstailey #endif /* not GCC version 2 */
492