XEmacs 21.2.28 "Hermes".
[chise/xemacs-chise.git.1] / src / alloca.s
1 /* `alloca' standard 4.2 subroutine for 68000's and 16000's and others.
2    Also has _setjmp and _longjmp for pyramids.
3    Copyright (C) 1985, 1986, 1988 Free Software Foundation, Inc.
4
5 This file is part of XEmacs.
6
7 XEmacs is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
10 later version.
11
12 XEmacs is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with XEmacs; see the file COPYING.  If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.  */
21
22 /* Synched up with: FSF 19.30. */
23
24 /* Both 68000 systems I have run this on have had broken versions of alloca.
25    Also, I am told that non-berkeley systems do not have it at all.
26    So replace whatever system-provided alloca there may be
27    on all 68000 systems.  */
28
29 #define NOT_C_CODE
30 #ifdef emacs
31 #include <config.h>
32 #else
33 #include "config.h"
34 #endif
35
36 #ifndef HAVE_ALLOCA  /* define this to use system's alloca */
37
38 #ifndef hp9000s300
39 #ifndef m68k
40 #ifndef m68000
41 #ifndef WICAT
42 #ifndef ns32000
43 #ifndef ns16000
44 #ifndef sequent
45 #ifndef pyramid
46 #ifndef ATT3B5
47 #ifndef XENIX
48 you
49 lose!!
50 #endif /* XENIX */
51 #endif /* ATT3B5 */
52 #endif /* pyramid */
53 #endif /* sequent */
54 #endif /* ns16000 */
55 #endif /* ns32000 */
56 #endif /* WICAT */
57 #endif /* m68000 */
58 #endif /* m68k */
59 #endif /* hp9000s300 */
60
61
62 #ifdef hp9000s300
63 #ifdef OLD_HP_ASSEMBLER
64         data
65         text
66         globl   _alloca
67 _alloca
68         move.l  (sp)+,a0        ; pop return addr from top of stack
69         move.l  (sp)+,d0        ; pop size in bytes from top of stack
70         add.l   #ROUND,d0       ; round size up to long word
71         and.l   #MASK,d0        ; mask out lower two bits of size
72         sub.l   d0,sp           ; allocate by moving stack pointer
73         tst.b   PROBE(sp)       ; stack probe to allocate pages
74         move.l  sp,d0           ; return pointer
75         add.l   #-4,sp          ; new top of stack
76         jmp     (a0)            ; not a normal return
77 MASK    equ     -4              ; Longword alignment
78 ROUND   equ     3               ; ditto
79 PROBE   equ     -128            ; safety buffer for C compiler scratch
80         data
81 #else /* new hp assembler syntax */
82 /*
83   The new compiler does "move.m <registers> (%sp)" to save registers,
84     so we must copy the saved registers when we mung the sp.
85   The old compiler did "move.m <register> <offset>(%a6)", which
86     gave us no trouble
87  */
88         text
89         set     PROBE,-128      # safety for C frame temporaries
90         set     MAXREG,22       # d2-d7, a2-a5, fp2-fp7 may have been saved
91         global  _alloca
92 _alloca:
93         mov.l   (%sp)+,%a0      # return address
94         mov.l   (%sp)+,%d0      # number of bytes to allocate
95         mov.l   %sp,%a1         # save old sp for register copy
96         mov.l   %sp,%d1         # compute new sp
97         sub.l   %d0,%d1         # space requested
98         and.l   &-4,%d1         # round down to longword
99         sub.l   &MAXREG*4,%d1   # space for saving registers
100         mov.l   %d1,%sp         # save new value of sp
101         tst.b   PROBE(%sp)      # create pages (sigh)
102         mov.l   %a2,%d1         # save reg a2
103         mov.l   %sp,%a2
104         move.w  &MAXREG-1,%d0
105 copy_regs_loop:                 /* save caller's saved registers */
106         mov.l   (%a1)+,(%a2)+
107         dbra    %d0,copy_regs_loop
108         mov.l   %a2,%d0         # return value
109         mov.l   %d1,%a2         # restore a2
110         add.l   &-4,%sp         # adjust tos
111         jmp     (%a0)           # rts
112 #endif /* new hp assembler */
113 #else
114 #ifdef m68k                     /* SGS assembler totally different */
115         file    "alloca.s"
116         global  alloca
117 alloca:
118 #ifdef MOTOROLA_DELTA
119 /* slightly modified version of alloca to motorola sysV/68 pcc - based
120    compiler.
121    this compiler saves used registers relative to %sp instead of %fp.
122    alright, just make new copy of saved register set whenever we allocate
123    new space from stack..
124    this is true at last until SVR3V7 . bug has reported to Motorola. */
125         set     MAXREG,10       # max no of registers to save (d2-d7, a2-a5)
126         mov.l   (%sp)+,%a1      # pop return addr from top of stack
127         mov.l   (%sp)+,%d0      # pop size in bytes from top of stack
128         mov.l   %sp,%a0         # save stack pointer for register copy
129         addq.l  &3,%d0          # round size up to long word
130         andi.l  &-4,%d0         # mask out lower two bits of size
131         mov.l   %sp,%d1         # compute new value of sp to d1
132         sub.l   %d0,%d1         # pseudo-allocate by moving stack pointer
133         sub.l   &MAXREG*4,%d1   # allocate more space for saved regs.
134         mov.l   %d1,%sp         # actual allocation.
135         move.w  &MAXREG-1,%d0   # d0 counts saved regs.
136         mov.l   %a2,%d1         # preserve a2.
137         mov.l   %sp,%a2         # make pointer to new reg save area.
138 copy_regs_loop:                 # copy stuff from old save area.
139         mov.l   (%a0)+,(%a2)+   # save saved register
140         dbra    %d0,copy_regs_loop
141         mov.l   %a2,%a0         # now a2 is start of allocated space.
142         mov.l   %a2,%d0         # return it in both a0 and d0 to play safe.
143         mov.l   %d1,%a2         # restore a2.
144         subq.l  &4,%sp          # new top of stack
145         jmp     (%a1)           # far below normal return
146 #else /* not MOTOROLA_DELTA */
147         mov.l   (%sp)+,%a1      # pop return addr from top of stack
148         mov.l   (%sp)+,%d0      # pop size in bytes from top of stack
149         add.l   &R%1,%d0        # round size up to long word
150         and.l   &-4,%d0         # mask out lower two bits of size
151         sub.l   %d0,%sp         # allocate by moving stack pointer
152         tst.b   P%1(%sp)        # stack probe to allocate pages
153         mov.l   %sp,%a0         # return pointer as pointer
154         mov.l   %sp,%d0         # return pointer as int to avoid disaster
155         add.l   &-4,%sp         # new top of stack
156         jmp     (%a1)           # not a normal return
157         set     S%1,64          # safety factor for C compiler scratch
158         set     R%1,3+S%1       # add to size for rounding
159         set     P%1,-132        # probe this far below current top of stack
160 #endif /* not MOTOROLA_DELTA */
161
162 #else /* not m68k */
163
164 #ifdef m68000
165
166 #ifdef WICAT
167 /*
168  * Registers are saved after the corresponding link so we have to explicitly
169  * move them to the top of the stack where they are expected to be.
170  * Since we do not know how many registers were saved in the calling function
171  * we must assume the maximum possible (d2-d7,a2-a5).  Hence, we end up
172  * wasting some space on the stack.
173  *
174  * The large probe (tst.b) attempts to make up for the fact that we have
175  * potentially used up the space that the caller probed for its own needs.
176  */
177         .procss m0
178         .config "68000 1"
179         .module _alloca
180 MAXREG: .const  10
181         .sect   text
182         .global _alloca
183 _alloca:
184         move.l  (sp)+,a1        ; pop return address
185         move.l  (sp)+,d0        ; pop allocation size
186         move.l  sp,d1           ; get current SP value
187         sub.l   d0,d1           ; adjust to reflect required size...
188         sub.l   #MAXREG*4,d1    ; ...and space needed for registers
189         and.l   #-4,d1          ; backup to longword boundary
190         move.l  sp,a0           ; save old SP value for register copy
191         move.l  d1,sp           ; set the new SP value
192         tst.b   -4096(sp)       ; grab an extra page (to cover caller)
193         move.l  a2,d1           ; save callers register
194         move.l  sp,a2
195         move.w  #MAXREG-1,d0    ; # of longwords to copy
196 loop:   move.l  (a0)+,(a2)+     ; copy registers...
197         dbra    d0,loop         ; ...til there are no more
198         move.l  a2,d0           ; end of register area is addr for new space
199         move.l  d1,a2           ; restore saved a2.
200         addq.l  #4,sp           ; caller will increment sp by 4 after return.
201         move.l  d0,a0           ; return value in both a0 and d0.
202         jmp     (a1)
203         .end    _alloca
204 #else
205
206 /* Some systems want the _, some do not.  Win with both kinds.  */
207 .globl  _alloca
208 _alloca:
209 .globl  alloca
210 alloca:
211         movl    sp@+,a0
212         movl    a7,d0
213         subl    sp@,d0
214         andl    #~3,d0
215         movl    d0,sp
216         tstb    sp@(0)          /* Make stack pages exist  */
217                                 /* Needed on certain systems
218                                    that lack true demand paging */
219         addql   #4,d0
220         jmp     a0@
221
222 #endif /* not WICAT */
223 #endif /* m68000 */
224 #endif /* not m68k */
225 #endif /* not hp9000s300 */
226
227 #if defined (ns16000) || defined (ns32000)
228
229         .text
230         .align  2
231 /* Some systems want the _, some do not.  Win with both kinds.  */
232 .globl  _alloca
233 _alloca:
234 .globl  alloca
235 alloca:
236
237 /* Two different assembler syntaxes are used for the same code
238         on different systems.  */
239
240 #ifdef sequent
241 #define IM
242 #define REGISTER(x) x
243 #else
244 #ifdef NS5   /* ns SysV assembler */
245 #define IM $
246 #define REGISTER(x) x
247 #else
248 #define IM $
249 #define REGISTER(x) 0(x)
250 #endif
251 #endif
252
253 /*
254  * The ns16000 is a little more difficult, need to copy regs.
255  * Also the code assumes direct linkage call sequence (no mod table crap).
256  * We have to copy registers, and therefore waste 32 bytes.
257  *
258  * Stack layout:
259  * new  sp ->   junk
260  *              registers (copy)
261  *      r0 ->   new data
262  *               |        (orig retval)
263  *               |        (orig arg)
264  * old  sp ->   regs      (orig)
265  *              local data
266  *      fp ->   old fp
267  */
268
269         movd    tos,r1          /*  pop return addr */
270         negd    tos,r0          /*  pop amount to allocate */
271         sprd    sp,r2
272         addd    r2,r0
273         bicb    IM/**/3,r0      /*  4-byte align */
274         lprd    sp,r0
275         adjspb  IM/**/36        /*  space for regs, +4 for caller to pop */
276         movmd   0(r2),4(sp),IM/**/4     /*  copy regs */
277         movmd   0x10(r2),0x14(sp),IM/**/4
278         jump    REGISTER(r1)    /* funky return */
279 #endif /* ns16000 or ns32000 */
280
281 #ifdef pyramid
282
283 .globl _alloca
284
285 _alloca: addw $3,pr0    # add 3 (dec) to first argument
286         bicw $3,pr0     # then clear its last 2 bits
287         subw pr0,sp     # subtract from SP the val in PR0
288         andw $-32,sp    # keep sp aligned on multiple of 32.
289         movw sp,pr0     # ret. current SP
290         ret
291
292 #ifdef PYRAMID_OLD /* This isn't needed in system version 4.  */
293 .globl __longjmp
294 .globl _longjmp
295 .globl __setjmp
296 .globl _setjmp
297
298 __longjmp: jump _longjmp
299 __setjmp:  jump _setjmp
300 #endif
301
302 #endif /* pyramid */
303
304 #ifdef ATT3B5
305
306         .align 4
307         .globl alloca
308
309 alloca:
310         movw %ap, %r8
311         subw2 $9*4, %r8
312         movw 0(%r8), %r1    /* pc */
313         movw 4(%r8), %fp
314         movw 8(%r8), %sp
315         addw2 %r0, %sp /* make room */
316         movw %sp, %r0 /* return value */
317         jmp (%r1) /* continue... */
318
319 #endif /* ATT3B5 */
320
321 #ifdef XENIX
322
323 .386
324
325 _TEXT segment dword use32 public 'CODE'
326 assume   cs:_TEXT
327
328 ;-------------------------------------------------------------------------
329
330 public _alloca
331 _alloca proc near
332
333         pop     ecx             ; return address
334         pop     eax             ; amount to alloc
335         add     eax,3           ; round it to 32-bit boundary
336         and     al,11111100B    ;
337         mov     edx,esp         ; current sp in edx
338         sub     edx,eax         ; lower the stack
339         xchg    esp,edx         ; start of allocation in esp, old sp in edx
340         mov     eax,esp         ; return ptr to base in eax
341         push    [edx+8]         ; save poss. stored reg. values (esi,edi,ebx)
342         push    [edx+4]         ;  on lowered stack
343         push    [edx]           ;
344         sub     esp,4           ; allow for 'add esp, 4'
345         jmp     ecx             ; jump to return address
346
347 _alloca endp
348
349 _TEXT   ends
350
351 end
352
353 #endif /* XENIX */
354
355 #endif /* not HAVE_ALLOCA */