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