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