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