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