0.9.10.30:
[sbcl.git] / src / runtime / x86-assem.S
1 /*
2  * very-low-level utilities for runtime support
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15 \f
16 #define LANGUAGE_ASSEMBLY
17 #include "sbcl.h"
18 #include "validate.h"
19 #include "genesis/closure.h"
20 #include "genesis/fdefn.h"
21 #include "genesis/static-symbols.h"
22 #include "genesis/symbol.h"
23 #include "genesis/thread.h"
24         
25 /* Minimize conditionalization for different OS naming schemes. 
26  *
27  * (As of sbcl-0.8.10, this seems no longer to be much of an issue, 
28  * since everyone has converged on ELF. If this generality really 
29  * turns out not to matter, perhaps it's just clutter we could get
30  * rid of? -- WHN 2004-04-18)
31  *
32  * (Except Win32, which is unlikely ever to be ELF, sorry. -- AB 2005-12-08)
33  */
34 #if defined __linux__  || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __sun
35 #define GNAME(var) var
36 #else
37 #define GNAME(var) _##var
38 #endif
39
40 #if defined __linux__  || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __sun
41 #define GNAMEDOLLAR(var) $##var
42 #else
43 #define GNAMEDOLLAR(var) $_##var
44 #endif
45
46 #if defined __linux__  || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __sun
47 #define DOLLARLITERAL(var) $##var
48 #else
49 #define DOLLARLITERAL(var) $##(var)
50 #endif
51
52 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
53  * want alignment in bytes. 
54  *
55  * (As in the GNAME() definitions above, as of sbcl-0.8.10, this seems 
56  * no longer to be much of an issue, since everyone has converged on
57  * the same value. If this generality really turns out not to 
58  * matter any more, perhaps it's just clutter we could get
59  * rid of? -- WHN 2004-04-18)
60  */
61 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun) || defined(LISP_FEATURE_WIN32)
62 #define align_4byte     4
63 #define align_8byte     8
64 #define align_16byte    16
65 #else
66 #define align_4byte     2
67 #define align_8byte     3
68 #define align_16byte    4       
69 #endif                  
70
71 /*
72  * The assembler used for win32 doesn't like .type or .size directives,
73  * so we want to conditionally kill them out. So let's wrap them in macros
74  * that are defined to be no-ops on win32. Hopefully this still works on
75  * other platforms.
76  */
77 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
78 #define TYPE(name) .type name,@function
79 #define SIZE(name) .size name,.-name
80 #else
81 #define TYPE(name)
82 #define SIZE(name)
83 #endif
84
85 /*
86  * x86/darwin (as of MacOS X 10.4.5) doesn't reliably file signal
87  * handlers (SIGTRAP or Mach exception handlers) for 0xCC, wo we have
88  * to use ud2 instead. ud2 is an undefined opcode, #x0b0f, or
89  * 0F 0B in low-endian notation, that causes SIGILL to fire. We check
90  * for this instruction in the SIGILL handler and if we see it, we
91  * advance the EIP by two bytes to skip over ud2 instruction and
92  * call sigtrap_handler. */
93 #if defined(LISP_FEATURE_DARWIN)
94 #define END()
95 #define TRAP ud2
96 #else
97 #define END() .end
98 #define TRAP int3
99 #endif
100
101         .text
102         .globl  GNAME(foreign_function_call_active)
103         .globl  GNAME(all_threads)
104 \f
105 /*
106  * A call to call_into_c preserves esi, edi, and ebp.   
107  * (The C function will preserve ebx, esi, edi, and ebp across its
108  * function call, but we trash ebx ourselves by using it to save the
109  * return Lisp address.)
110  *
111  * Return values are in eax and maybe edx for quads, or st(0) for
112  * floats.
113  *
114  * This should work for Lisp calls C calls Lisp calls C..
115  */
116         .text
117         .align  align_16byte,0x90
118         .globl GNAME(call_into_c)
119         TYPE(GNAME(call_into_c))
120 GNAME(call_into_c):
121         movl    $1,GNAME(foreign_function_call_active)
122
123 /* Save the return Lisp address in ebx. */
124         popl    %ebx
125
126 /* Setup the NPX for C */
127         fstp    %st(0)
128         fstp    %st(0)
129         fstp    %st(0)
130         fstp    %st(0)
131         fstp    %st(0)
132         fstp    %st(0)
133         fstp    %st(0)
134         fstp    %st(0)
135
136 #ifdef LISP_FEATURE_WIN32
137         cld
138 #endif
139
140 #ifdef LISP_FEATURE_DARWIN
141         andl    $0xfffffff0,%esp        # align stack to 16-byte boundary before calling C
142 #endif
143         call    *%eax           # normal callout using Lisp stack
144
145         movl    %eax,%ecx       # remember integer return value
146
147 /* Check for a return FP value. */
148         fxam
149         fnstsw  %eax
150         andl    $0x4500,%eax
151         cmpl    $0x4100,%eax
152         jne     Lfp_rtn_value
153
154 /* The return value is in eax, or eax,edx? */
155 /* Set up the NPX stack for Lisp. */
156         fldz                    # Ensure no regs are empty.
157         fldz
158         fldz
159         fldz
160         fldz
161         fldz
162         fldz
163         fldz
164
165 /* Restore the return value. */
166         movl    %ecx,%eax       # maybe return value
167
168         movl    $0,GNAME(foreign_function_call_active)
169 /* Return. */
170         jmp     *%ebx
171
172 Lfp_rtn_value:
173 /* The return result is in st(0). */
174 /* Set up the NPX stack for Lisp, placing the result in st(0). */
175         fldz                    # Ensure no regs are empty.
176         fldz
177         fldz
178         fldz
179         fldz
180         fldz
181         fldz
182         fxch    %st(7)          # Move the result back to st(0).
183
184 /* We don't need to restore eax, because the result is in st(0). */
185
186         movl    $0,GNAME(foreign_function_call_active)
187 /* Return. */   
188         jmp     *%ebx
189
190         SIZE(GNAME(call_into_c))
191
192 \f
193         .text   
194         .globl GNAME(call_into_lisp_first_time)
195         TYPE(GNAME(call_into_lisp_first_time))
196                 
197 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
198  * the stack changes.  We don't worry too much about saving registers 
199  * here, because we never expect to return from the initial call to lisp 
200  * anyway */
201         
202         .align  align_16byte,0x90
203 GNAME(call_into_lisp_first_time):
204         pushl   %ebp            # Save old frame pointer.
205         movl    %esp,%ebp       # Establish new frame.
206 #ifndef LISP_FEATURE_WIN32
207         movl    %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
208         movl    GNAME(all_threads),%eax
209         movl    THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
210         /* don't think too hard about what happens if we get interrupted
211         * here */
212         addl    DOLLARLITERAL(THREAD_CONTROL_STACK_SIZE),%esp
213 #else
214 /* Win32 -really- doesn't like you switching stacks out from under it. */
215         movl    GNAME(all_threads),%eax
216 #endif
217         jmp     Lstack
218 \f
219         .text   
220         .globl GNAME(call_into_lisp)
221         TYPE(GNAME(call_into_lisp))
222                 
223 /* The C conventions require that ebx, esi, edi, and ebp be preserved
224  * across function calls. */
225         
226         .align  align_16byte,0x90
227 GNAME(call_into_lisp):
228         pushl   %ebp            # Save old frame pointer.
229         movl    %esp,%ebp       # Establish new frame.
230 Lstack:
231 /* Save the NPX state */
232         fwait                   # Catch any pending NPX exceptions.
233         subl    $108,%esp       # Make room for the NPX state.
234         fnsave  (%esp)          # save and reset NPX
235
236         movl    (%esp),%eax     # Load NPX control word.
237         andl    $0xfffff2ff,%eax        # Set rounding mode to nearest.
238         orl     $0x00000200,%eax        # Set precision to 64 bits.  (53-bit mantissa)
239         pushl   %eax
240         fldcw   (%esp)          # Recover modes.
241         popl    %eax
242
243         fldz                    # Ensure no FP regs are empty.
244         fldz
245         fldz
246         fldz
247         fldz
248         fldz
249         fldz
250         fldz
251         
252 /* Save C regs: ebx esi edi. */
253         pushl   %ebx
254         pushl   %esi
255         pushl   %edi
256         
257 /* Clear descriptor regs. */
258         xorl    %eax,%eax       # lexenv
259         xorl    %ebx,%ebx       # available
260         xorl    %ecx,%ecx       # arg count
261         xorl    %edx,%edx       # first arg
262         xorl    %edi,%edi       # second arg
263         xorl    %esi,%esi       # third arg
264
265 /* no longer in function call */
266         movl    %eax, GNAME(foreign_function_call_active)
267
268         movl    %esp,%ebx       # remember current stack
269         pushl   %ebx            # Save entry stack on (maybe) new stack.
270
271         /* Establish Lisp args. */
272         movl     8(%ebp),%eax   # lexenv?
273         movl    12(%ebp),%ebx   # address of arg vec
274         movl    16(%ebp),%ecx   # num args
275         shll    $2,%ecx         # Make num args into fixnum.
276         cmpl    $0,%ecx
277         je      Ldone
278         movl    (%ebx),%edx     # arg0
279         cmpl    $4,%ecx
280         je      Ldone
281         movl    4(%ebx),%edi    # arg1
282         cmpl    $8,%ecx
283         je      Ldone
284         movl    8(%ebx),%esi    # arg2
285 Ldone:  
286         /* Registers eax, ecx, edx, edi, and esi are now live. */
287
288         /* Alloc new frame. */
289         mov     %esp,%ebx       # The current sp marks start of new frame.
290         push    %ebp            # fp in save location S0
291         sub     $8,%esp         # Ensure 3 slots are allocated, one above.
292         mov     %ebx,%ebp       # Switch to new frame.
293
294         call    *CLOSURE_FUN_OFFSET(%eax)
295         
296         /* If the function returned multiple values, it will return to
297            this point.  Lose them */
298         jnc     LsingleValue
299         mov     %ebx, %esp
300 LsingleValue:
301         /* A singled value function returns here */
302
303 /* Restore the stack, in case there was a stack change. */
304         popl    %esp            # c-sp
305
306 /* Restore C regs: ebx esi edi. */
307         popl    %edi
308         popl    %esi
309         popl    %ebx
310
311 /* Restore the NPX state. */
312         frstor  (%esp)
313         addl    $108, %esp
314         
315         popl    %ebp            # c-sp
316         movl    %edx,%eax       # c-val
317         ret
318         SIZE(GNAME(call_into_lisp))
319 \f
320 /* support for saving and restoring the NPX state from C */
321         .text
322         .globl  GNAME(fpu_save)
323         TYPE(GNAME(fpu_save))
324         .align  2,0x90
325 GNAME(fpu_save):
326         movl    4(%esp),%eax
327         fnsave  (%eax)          # Save the NPX state. (resets NPX)
328         ret
329         SIZE(GNAME(fpu_save))
330
331         .globl  GNAME(fpu_restore)
332         TYPE(GNAME(fpu_restore))
333         .align  2,0x90
334 GNAME(fpu_restore):
335         movl    4(%esp),%eax
336         frstor  (%eax)          # Restore the NPX state.
337         ret
338         SIZE(GNAME(fpu_restore))
339 \f
340 /*
341  * the undefined-function trampoline
342  */
343         .text
344         .align  align_4byte,0x90
345         .globl GNAME(undefined_tramp)
346         TYPE(GNAME(undefined_tramp))
347         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
348 GNAME(undefined_tramp):
349         TRAP
350         .byte   trap_Error
351         .byte   2
352         .byte   UNDEFINED_FUN_ERROR
353         .byte   sc_DescriptorReg # eax in the Descriptor-reg SC
354         ret
355         SIZE(GNAME(undefined_tramp))
356
357 /*
358  * the closure trampoline
359  */
360         .text
361         .align  align_4byte,0x90
362         .globl GNAME(closure_tramp)
363         TYPE(GNAME(closure_tramp))
364         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
365 GNAME(closure_tramp):
366         movl    FDEFN_FUN_OFFSET(%eax),%eax
367         /* FIXME: The '*' after "jmp" in the next line is from PVE's
368          * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
369          * reasonable, and it certainly seems as though if CMU CL needs it,
370          * SBCL needs it too, but I haven't actually verified that it's
371          * right. It would be good to find a way to force the flow of
372          * control through here to test it. */
373         jmp     *CLOSURE_FUN_OFFSET(%eax)
374         SIZE(GNAME(closure_tramp))
375
376 /*
377  * fun-end breakpoint magic
378  */
379         .text
380         .globl  GNAME(fun_end_breakpoint_guts)
381         .align  align_4byte
382 GNAME(fun_end_breakpoint_guts):
383         /* Multiple Value return */
384         jc      multiple_value_return
385         /* Single value return: The eventual return will now use the
386            multiple values return convention but with a return values
387            count of one. */
388         movl    %esp,%ebx       # Setup ebx - the ofp.
389         subl    $4,%esp         # Allocate one stack slot for the return value
390         movl    $4,%ecx         # Setup ecx for one return value.
391         movl    DOLLARLITERAL(NIL),%edi # default second value
392         movl    DOLLARLITERAL(NIL),%esi # default third value
393                 
394 multiple_value_return:
395         
396         .globl GNAME(fun_end_breakpoint_trap)
397 GNAME(fun_end_breakpoint_trap):
398         TRAP
399         .byte   trap_FunEndBreakpoint
400         hlt                     # We should never return here.
401
402         .globl GNAME(fun_end_breakpoint_end)
403 GNAME(fun_end_breakpoint_end):
404
405 \f
406         .globl  GNAME(do_pending_interrupt)
407         TYPE(GNAME(do_pending_interrupt))
408         .align  align_4byte,0x90
409 GNAME(do_pending_interrupt):
410         TRAP
411         .byte   trap_PendingInterrupt
412         ret
413         SIZE(GNAME(do_pending_interrupt))
414 \f
415
416 /*
417  * Allocate bytes and return the start of the allocated space
418  * in the specified destination register.
419  *
420  * In the general case the size will be in the destination register.
421  *
422  * All registers must be preserved except the destination.
423  * The C conventions will preserve ebx, esi, edi, and ebp.
424  * So only eax, ecx, and edx need special care here.
425  */
426         
427         .globl  GNAME(alloc_to_eax)
428         TYPE(GNAME(alloc_to_eax))
429         .align  align_4byte,0x90
430 GNAME(alloc_to_eax):
431         pushl   %ecx    # Save ecx and edx as C could destroy them.
432         pushl   %edx
433         pushl   %eax    # Push the size.
434         call    GNAME(alloc)
435         addl    $4,%esp # Pop the size arg.
436         popl    %edx    # Restore ecx and edx.
437         popl    %ecx
438         ret
439         SIZE(GNAME(alloc_to_eax))
440
441         .globl  GNAME(alloc_8_to_eax)
442         TYPE(GNAME(alloc_8_to_eax))
443         .align  align_4byte,0x90
444 GNAME(alloc_8_to_eax):
445         pushl   %ecx    # Save ecx and edx as C could destroy them.
446         pushl   %edx
447         pushl   $8      # Push the size.
448         call    GNAME(alloc)
449         addl    $4,%esp # Pop the size arg.
450         popl    %edx    # Restore ecx and edx.
451         popl    %ecx
452         ret
453         SIZE(GNAME(alloc_8_to_eax))
454
455         .globl  GNAME(alloc_8_to_eax)
456         TYPE(GNAME(alloc_8_to_eax))
457         .align  align_4byte,0x90
458
459         .globl  GNAME(alloc_16_to_eax)
460         TYPE(GNAME(alloc_16_to_eax))
461         .align  align_4byte,0x90
462 GNAME(alloc_16_to_eax):
463         pushl   %ecx    # Save ecx and edx as C could destroy them.
464         pushl   %edx
465         pushl   $16     # Push the size.
466         call    GNAME(alloc)
467         addl    $4,%esp # Pop the size arg.
468         popl    %edx    # Restore ecx and edx.
469         popl    %ecx
470         ret
471         SIZE(GNAME(alloc_16_to_eax))
472
473         .globl  GNAME(alloc_to_ecx)
474         TYPE(GNAME(alloc_to_ecx))
475         .align  align_4byte,0x90
476 GNAME(alloc_to_ecx):
477         pushl   %eax    # Save eax and edx as C could destroy them.
478         pushl   %edx
479         pushl   %ecx    # Push the size.
480         call    GNAME(alloc)
481         addl    $4,%esp # Pop the size arg.
482         movl    %eax,%ecx       # Set up the destination.
483         popl    %edx    # Restore eax and edx.
484         popl    %eax
485         ret
486         SIZE(GNAME(alloc_to_ecx))
487
488         .globl  GNAME(alloc_8_to_ecx)
489         TYPE(GNAME(alloc_8_to_ecx))
490         .align  align_4byte,0x90
491 GNAME(alloc_8_to_ecx):
492         pushl   %eax    # Save eax and edx as C could destroy them.
493         pushl   %edx
494         pushl   $8      # Push the size.
495         call    GNAME(alloc)
496         addl    $4,%esp # Pop the size arg.
497         movl    %eax,%ecx       # Set up the destination.
498         popl    %edx    # Restore eax and edx.
499         popl    %eax
500         ret
501         SIZE(GNAME(alloc_8_to_ecx))
502
503         .globl  GNAME(alloc_16_to_ecx)
504         TYPE(GNAME(alloc_16_to_ecx))
505         .align  align_4byte,0x90
506 GNAME(alloc_16_to_ecx):
507         pushl   %eax    # Save eax and edx as C could destroy them.
508         pushl   %edx
509         pushl   $16     # Push the size.
510         call    GNAME(alloc)
511         addl    $4,%esp # Pop the size arg.
512         movl    %eax,%ecx       # Set up the destination.
513         popl    %edx    # Restore eax and edx.
514         popl    %eax
515         ret
516         SIZE(GNAME(alloc_16_to_ecx))
517
518
519         .globl  GNAME(alloc_to_edx)
520         TYPE(GNAME(alloc_to_edx))
521         .align  align_4byte,0x90
522 GNAME(alloc_to_edx):
523         pushl   %eax    # Save eax and ecx as C could destroy them.
524         pushl   %ecx
525         pushl   %edx    # Push the size.
526         call    GNAME(alloc)
527         addl    $4,%esp # Pop the size arg.
528         movl    %eax,%edx       # Set up the destination.
529         popl    %ecx    # Restore eax and ecx.
530         popl    %eax
531         ret
532         SIZE(GNAME(alloc_to_edx))
533
534         .globl  GNAME(alloc_8_to_edx)
535         TYPE(GNAME(alloc_8_to_edx))
536         .align  align_4byte,0x90
537 GNAME(alloc_8_to_edx):
538         pushl   %eax    # Save eax and ecx as C could destroy them.
539         pushl   %ecx
540         pushl   $8      # Push the size.
541         call    GNAME(alloc)
542         addl    $4,%esp # Pop the size arg.
543         movl    %eax,%edx       # Set up the destination.
544         popl    %ecx    # Restore eax and ecx.
545         popl    %eax
546         ret
547         SIZE(GNAME(alloc_8_to_edx))
548
549         .globl  GNAME(alloc_16_to_edx)
550         TYPE(GNAME(alloc_16_to_edx))
551         .align  align_4byte,0x90
552 GNAME(alloc_16_to_edx):
553         pushl   %eax    # Save eax and ecx as C could destroy them.
554         pushl   %ecx
555         pushl   $16     # Push the size.
556         call    GNAME(alloc)
557         addl    $4,%esp # Pop the size arg.
558         movl    %eax,%edx       # Set up the destination.
559         popl    %ecx    # Restore eax and ecx.
560         popl    %eax
561         ret
562         SIZE(GNAME(alloc_16_to_edx))
563
564
565
566         .globl  GNAME(alloc_to_ebx)
567         TYPE(GNAME(alloc_to_ebx))
568         .align  align_4byte,0x90
569 GNAME(alloc_to_ebx):
570         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
571         pushl   %ecx
572         pushl   %edx
573         pushl   %ebx    # Push the size.
574         call    GNAME(alloc)
575         addl    $4,%esp # Pop the size arg.
576         movl    %eax,%ebx       # Set up the destination.
577         popl    %edx    # Restore eax, ecx and edx.
578         popl    %ecx
579         popl    %eax
580         ret
581         SIZE(GNAME(alloc_to_ebx))
582
583         .globl  GNAME(alloc_8_to_ebx)
584         TYPE(GNAME(alloc_8_to_ebx))
585         .align  align_4byte,0x90
586 GNAME(alloc_8_to_ebx):
587         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
588         pushl   %ecx
589         pushl   %edx
590         pushl   $8      # Push the size.
591         call    GNAME(alloc)
592         addl    $4,%esp # Pop the size arg.
593         movl    %eax,%ebx       # Set up the destination.
594         popl    %edx    # Restore eax, ecx and edx.
595         popl    %ecx
596         popl    %eax
597         ret
598         SIZE(GNAME(alloc_8_to_ebx))
599
600         .globl  GNAME(alloc_16_to_ebx)
601         TYPE(GNAME(alloc_16_to_ebx))
602         .align  align_4byte,0x90
603 GNAME(alloc_16_to_ebx):
604         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
605         pushl   %ecx
606         pushl   %edx
607         pushl   $16     # Push the size
608         call    GNAME(alloc)
609         addl    $4,%esp # pop the size arg.
610         movl    %eax,%ebx       # setup the destination.
611         popl    %edx    # Restore eax, ecx and edx.
612         popl    %ecx
613         popl    %eax
614         ret
615         SIZE(GNAME(alloc_16_to_ebx))
616
617
618
619         .globl  GNAME(alloc_to_esi)
620         TYPE(GNAME(alloc_to_esi))
621         .align  align_4byte,0x90
622 GNAME(alloc_to_esi):
623         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
624         pushl   %ecx
625         pushl   %edx
626         pushl   %esi    # Push the size
627         call    GNAME(alloc)
628         addl    $4,%esp # pop the size arg.
629         movl    %eax,%esi       # setup the destination.
630         popl    %edx    # Restore eax, ecx and edx.
631         popl    %ecx
632         popl    %eax
633         ret
634         SIZE(GNAME(alloc_to_esi))
635
636         .globl  GNAME(alloc_8_to_esi)
637         TYPE(GNAME(alloc_8_to_esi))
638         .align  align_4byte,0x90
639 GNAME(alloc_8_to_esi):
640         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
641         pushl   %ecx
642         pushl   %edx
643         pushl   $8      # Push the size
644         call    GNAME(alloc)
645         addl    $4,%esp # pop the size arg.
646         movl    %eax,%esi       # setup the destination.
647         popl    %edx    # Restore eax, ecx and edx.
648         popl    %ecx
649         popl    %eax
650         ret
651         SIZE(GNAME(alloc_8_to_esi))
652
653         .globl  GNAME(alloc_16_to_esi)
654         TYPE(GNAME(alloc_16_to_esi))
655         .align  align_4byte,0x90
656 GNAME(alloc_16_to_esi):
657         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
658         pushl   %ecx
659         pushl   %edx
660         pushl   $16     # Push the size
661         call    GNAME(alloc)
662         addl    $4,%esp # pop the size arg.
663         movl    %eax,%esi       # setup the destination.
664         popl    %edx    # Restore eax, ecx and edx.
665         popl    %ecx
666         popl    %eax
667         ret
668         SIZE(GNAME(alloc_16_to_esi))
669
670
671         .globl  GNAME(alloc_to_edi)
672         TYPE(GNAME(alloc_to_edi))
673         .align  align_4byte,0x90
674 GNAME(alloc_to_edi):
675         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
676         pushl   %ecx
677         pushl   %edx
678         pushl   %edi    # Push the size
679         call    GNAME(alloc)
680         addl    $4,%esp # pop the size arg.
681         movl    %eax,%edi       # setup the destination.
682         popl    %edx    # Restore eax, ecx and edx.
683         popl    %ecx
684         popl    %eax
685         ret
686         SIZE(GNAME(alloc_to_edi))
687
688         .globl  GNAME(alloc_8_to_edi)
689         TYPE(GNAME(alloc_8_to_edi))
690         .align  align_4byte,0x90
691 GNAME(alloc_8_to_edi):
692         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
693         pushl   %ecx
694         pushl   %edx
695         pushl   $8      # Push the size
696         call    GNAME(alloc)
697         addl    $4,%esp # pop the size arg.
698         movl    %eax,%edi       # setup the destination.
699         popl    %edx    # Restore eax, ecx and edx.
700         popl    %ecx
701         popl    %eax
702         ret
703         SIZE(GNAME(alloc_8_to_edi))
704
705         .globl  GNAME(alloc_16_to_edi)
706         TYPE(GNAME(alloc_16_to_edi))
707         .align  align_4byte,0x90
708 GNAME(alloc_16_to_edi):
709         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
710         pushl   %ecx
711         pushl   %edx
712         pushl   $16     # Push the size
713         call    GNAME(alloc)
714         addl    $4,%esp # pop the size arg.
715         movl    %eax,%edi       # setup the destination.
716         popl    %edx    # Restore eax, ecx and edx.
717         popl    %ecx
718         popl    %eax
719         ret
720         SIZE(GNAME(alloc_16_to_edi))
721
722         
723 /* Called from lisp when an inline allocation overflows.
724    Every register except the result needs to be preserved.
725    We depend on C to preserve ebx, esi, edi, and ebp.
726    But where necessary must save eax, ecx, edx. */
727
728 #ifdef LISP_FEATURE_SB_THREAD
729 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
730 #else
731 #define START_REGION GNAME(boxed_region)
732 #endif
733                 
734 /* This routine handles an overflow with eax=crfp+size. So the
735    size=eax-crfp. */
736         .align  align_4byte
737         .globl  GNAME(alloc_overflow_eax)
738         TYPE(GNAME(alloc_overflow_eax))
739 GNAME(alloc_overflow_eax):
740         pushl   %ecx            # Save ecx
741         pushl   %edx            # Save edx
742         /* Calculate the size for the allocation. */
743         subl    START_REGION,%eax
744         pushl   %eax            # Push the size
745         call    GNAME(alloc)
746         addl    $4,%esp # pop the size arg.
747         popl    %edx    # Restore edx.
748         popl    %ecx    # Restore ecx.
749         ret
750         SIZE(GNAME(alloc_overflow_eax))
751
752         .align  align_4byte
753         .globl  GNAME(alloc_overflow_ecx)
754         TYPE(GNAME(alloc_overflow_ecx))
755 GNAME(alloc_overflow_ecx):
756         pushl   %eax            # Save eax
757         pushl   %edx            # Save edx
758         /* Calculate the size for the allocation. */
759         subl    START_REGION,%ecx
760         pushl   %ecx            # Push the size
761         call    GNAME(alloc)
762         addl    $4,%esp # pop the size arg.
763         movl    %eax,%ecx       # setup the destination.
764         popl    %edx    # Restore edx.
765         popl    %eax    # Restore eax.
766         ret
767         SIZE(GNAME(alloc_overflow_ecx))
768
769         .align  align_4byte
770         .globl  GNAME(alloc_overflow_edx)
771         TYPE(GNAME(alloc_overflow_edx))
772 GNAME(alloc_overflow_edx):
773         pushl   %eax            # Save eax
774         pushl   %ecx            # Save ecx
775         /* Calculate the size for the allocation. */
776         subl    START_REGION,%edx
777         pushl   %edx            # Push the size
778         call    GNAME(alloc)
779         addl    $4,%esp # pop the size arg.
780         movl    %eax,%edx       # setup the destination.
781         popl    %ecx    # Restore ecx.
782         popl    %eax    # Restore eax.
783         ret
784         SIZE(GNAME(alloc_overflow_edx))
785
786 /* This routine handles an overflow with ebx=crfp+size. So the
787    size=ebx-crfp. */
788         .align  align_4byte
789         .globl  GNAME(alloc_overflow_ebx)
790         TYPE(GNAME(alloc_overflow_ebx))
791 GNAME(alloc_overflow_ebx):
792         pushl   %eax            # Save eax
793         pushl   %ecx            # Save ecx
794         pushl   %edx            # Save edx
795         /* Calculate the size for the allocation. */
796         subl    START_REGION,%ebx
797         pushl   %ebx            # Push the size
798         call    GNAME(alloc)
799         addl    $4,%esp # pop the size arg.
800         movl    %eax,%ebx       # setup the destination.
801         popl    %edx    # Restore edx.
802         popl    %ecx    # Restore ecx.
803         popl    %eax    # Restore eax.
804         ret
805         SIZE(GNAME(alloc_overflow_ebx))
806
807 /* This routine handles an overflow with esi=crfp+size. So the
808    size=esi-crfp. */
809         .align  align_4byte
810         .globl  GNAME(alloc_overflow_esi)
811         TYPE(GNAME(alloc_overflow_esi))
812 GNAME(alloc_overflow_esi):
813         pushl   %eax            # Save eax
814         pushl   %ecx            # Save ecx
815         pushl   %edx            # Save edx
816         /* Calculate the size for the allocation. */
817         subl    START_REGION,%esi
818         pushl   %esi            # Push the size
819         call    GNAME(alloc)
820         addl    $4,%esp # pop the size arg.
821         movl    %eax,%esi       # setup the destination.
822         popl    %edx    # Restore edx.
823         popl    %ecx    # Restore ecx.
824         popl    %eax    # Restore eax.
825         ret
826         SIZE(GNAME(alloc_overflow_esi))
827
828         .align  align_4byte
829         .globl  GNAME(alloc_overflow_edi)
830         TYPE(GNAME(alloc_overflow_edi))
831 GNAME(alloc_overflow_edi):
832         pushl   %eax            # Save eax
833         pushl   %ecx            # Save ecx
834         pushl   %edx            # Save edx
835         /* Calculate the size for the allocation. */
836         subl    START_REGION,%edi
837         pushl   %edi            # Push the size
838         call    GNAME(alloc)
839         addl    $4,%esp # pop the size arg.
840         movl    %eax,%edi       # setup the destination.
841         popl    %edx    # Restore edx.
842         popl    %ecx    # Restore ecx.
843         popl    %eax    # Restore eax.
844         ret
845         SIZE(GNAME(alloc_overflow_edi))
846
847         .align  align_4byte,0x90
848         .globl  GNAME(post_signal_tramp)
849         TYPE(GNAME(post_signal_tramp))
850 GNAME(post_signal_tramp):
851         /* this is notionally the second half of a function whose first half
852          * doesn't exist.  This is where call_into_lisp returns when called 
853          * using return_to_lisp_function */
854         addl $12,%esp   /* clear call_into_lisp args from stack */
855         popal           /* restore registers */
856         popfl
857         leave
858         ret
859         SIZE(GNAME(post_signal_tramp))
860
861 #ifdef LISP_FEATURE_WIN32
862         /*
863          * This is part of the funky magic for exception handling on win32.
864          * see sigtrap_emulator() in win32-os.c for details.
865          */
866         .globl GNAME(sigtrap_trampoline)
867 GNAME(sigtrap_trampoline):
868         pushl   %eax
869         pushl   %ebp
870         movl    %esp, %ebp
871         call    GNAME(sigtrap_wrapper)
872         pop     %eax
873         pop     %eax
874         TRAP
875         .byte   trap_ContextRestore
876         hlt                     # We should never return here.
877         
878         /*
879          * This is part of the funky magic for exception handling on win32.
880          * see handle_exception() in win32-os.c for details.
881          */
882         .globl GNAME(exception_trampoline)
883 GNAME(exception_trampoline):
884         pushl   %eax
885         pushl   %ebp
886         movl    %esp, %ebp
887         call    GNAME(handle_win32_exception_wrapper)
888         pop     %eax
889         pop     %eax
890         TRAP
891         .byte   trap_ContextRestore
892         hlt                     # We should never return here.
893 #endif
894
895         /* fast_bzero implementations and code to detect which implementation
896          * to use.
897          */
898 \f
899         .globl GNAME(fast_bzero_pointer)
900         .data
901         .align  align_4byte
902 GNAME(fast_bzero_pointer):
903         /* Variable containing a pointer to the bzero function to use.
904          * Initially points to a basic function.  Change this variable
905          * to fast_bzero_detect if OS supports SSE.  */
906         .long GNAME(fast_bzero_base)
907 \f
908         .text
909         .align  align_8byte,0x90
910         .globl GNAME(fast_bzero)
911         TYPE(GNAME(fast_bzero))
912 GNAME(fast_bzero):        
913         /* Indirect function call */
914         jmp *GNAME(fast_bzero_pointer)
915         SIZE(GNAME(fast_bzero))
916         
917 \f      
918         .text
919         .align  align_8byte,0x90
920         .globl GNAME(fast_bzero_detect)
921         TYPE(GNAME(fast_bzero_detect))
922 GNAME(fast_bzero_detect):
923         /* Decide whether to use SSE, MMX or REP version */
924         push %eax /* CPUID uses EAX-EDX */
925         push %ebx
926         push %ecx
927         push %edx
928         mov $1, %eax
929         cpuid
930         test $0x04000000, %edx    /* SSE2 needed for MOVNTDQ */
931         jnz Lsse2
932         /* Originally there was another case here for using the
933          * MOVNTQ instruction for processors that supported MMX but
934          * not SSE2. This turned out to be a loss especially on
935          * Athlons (where this instruction is apparently microcoded
936          * somewhat slowly). So for simplicity revert to REP STOSL
937          * for all non-SSE2 processors.
938          */
939 Lbase:
940         movl GNAMEDOLLAR(fast_bzero_base), GNAME(fast_bzero_pointer)
941         jmp Lrestore
942 Lsse2:
943         movl GNAMEDOLLAR(fast_bzero_sse), GNAME(fast_bzero_pointer)
944         jmp Lrestore
945         
946 Lrestore:
947         pop %edx
948         pop %ecx
949         pop %ebx
950         pop %eax
951         jmp *GNAME(fast_bzero_pointer)
952         
953         SIZE(GNAME(fast_bzero_detect))
954         
955 \f
956         .text
957         .align  align_8byte,0x90
958         .globl GNAME(fast_bzero_sse)
959         TYPE(GNAME(fast_bzero_sse))
960         
961 GNAME(fast_bzero_sse):
962         /* A fast routine for zero-filling blocks of memory that are
963          * guaranteed to start and end at a 4096-byte aligned address.
964          */        
965         push %esi                 /* Save temporary registers */
966         push %edi
967         mov 16(%esp), %esi        /* Parameter: amount of bytes to fill */
968         mov 12(%esp), %edi        /* Parameter: start address */
969         shr $6, %esi              /* Amount of 64-byte blocks to copy */
970         jz Lend_sse               /* If none, stop */
971         movups %xmm7, -16(%esp)   /* Save XMM register */
972         xorps  %xmm7, %xmm7       /* Zero the XMM register */
973         jmp Lloop_sse
974         .align align_16byte
975 Lloop_sse:
976
977         /* Copy the 16 zeroes from xmm7 to memory, 4 times. MOVNTDQ is the
978          * non-caching double-quadword moving variant, i.e. the memory areas
979          * we're touching are not fetched into the L1 cache, since we're just
980          * going to overwrite the memory soon anyway.
981          */
982         movntdq %xmm7, 0(%edi)
983         movntdq %xmm7, 16(%edi)
984         movntdq %xmm7, 32(%edi)
985         movntdq %xmm7, 48(%edi)
986  
987         add $64, %edi /* Advance pointer */
988         dec %esi      /* Decrement 64-byte block count */
989         jnz Lloop_sse
990         movups -16(%esp), %xmm7 /* Restore the XMM register */
991         sfence        /* Ensure that weakly ordered writes are flushed. */
992 Lend_sse:
993         mov 12(%esp), %esi      /* Parameter: start address */
994         prefetcht0 0(%esi)      /* Prefetch the start of the block into cache,
995                                  * since it's likely to be used immediately. */
996         pop %edi      /* Restore temp registers */
997         pop %esi
998         ret
999         SIZE(GNAME(fast_bzero_sse))
1000                 
1001 \f
1002         .text
1003         .align  align_8byte,0x90
1004         .globl GNAME(fast_bzero_base)
1005         TYPE(GNAME(fast_bzero_base))
1006         
1007 GNAME(fast_bzero_base):
1008         /* A fast routine for zero-filling blocks of memory that are
1009          * guaranteed to start and end at a 4096-byte aligned address.
1010          */        
1011         push %eax                 /* Save temporary registers */
1012         push %ecx
1013         push %edi
1014         mov 20(%esp), %ecx        /* Parameter: amount of bytes to fill */
1015         mov 16(%esp), %edi        /* Parameter: start address */
1016         xor %eax, %eax            /* Zero EAX */
1017         shr $2, %ecx              /* Amount of 4-byte blocks to copy */
1018         jz  Lend_base
1019         cld                       /* Set direction of STOSL to increment */
1020
1021         rep
1022         stosl                     /* Store EAX to *EDI, ECX times, incrementing
1023                                    * EDI by 4 after each store */
1024         
1025 Lend_base:        
1026         pop %edi                  /* Restore temp registers */
1027         pop %ecx
1028         pop %eax
1029         ret
1030         SIZE(GNAME(fast_bzero_base))
1031         
1032 \f       
1033         END()
1034