9434c3e5278928d225a34bc617ac89508a4b2e8d
[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/funcallable-instance.h"
21 #include "genesis/fdefn.h"
22 #include "genesis/static-symbols.h"
23 #include "genesis/symbol.h"
24 #include "genesis/thread.h"
25         
26 /* Minimize conditionalization for different OS naming schemes. 
27  *
28  * (As of sbcl-0.8.10, this seems no longer to be much of an issue, 
29  * since everyone has converged on ELF. If this generality really 
30  * turns out not to matter, perhaps it's just clutter we could get
31  * rid of? -- WHN 2004-04-18)
32  *
33  * (Except Win32, which is unlikely ever to be ELF, sorry. -- AB 2005-12-08)
34  */
35 #if defined __linux__  || defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __sun
36 #define GNAME(var) var
37 #else
38 #define GNAME(var) _##var
39 #endif
40
41 /* Get the right type of alignment. Linux, FreeBSD and NetBSD (but not OpenBSD)
42  * want alignment in bytes. 
43  *
44  * (As in the GNAME() definitions above, as of sbcl-0.8.10, this seems 
45  * no longer to be much of an issue, since everyone has converged on
46  * the same value. If this generality really turns out not to 
47  * matter any more, perhaps it's just clutter we could get
48  * rid of? -- WHN 2004-04-18)
49  */
50 #if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__sun) || defined(LISP_FEATURE_WIN32)
51 #define align_4byte     4
52 #define align_8byte     8
53 #define align_16byte    16
54 #else
55 #define align_4byte     2
56 #define align_8byte     3
57 #define align_16byte    4       
58 #endif                  
59
60 /*
61  * The assembler used for win32 doesn't like .type or .size directives,
62  * so we want to conditionally kill them out. So let's wrap them in macros
63  * that are defined to be no-ops on win32. Hopefully this still works on
64  * other platforms.
65  */
66 #if !defined(LISP_FEATURE_WIN32) && !defined(LISP_FEATURE_DARWIN)
67 #define TYPE(name) .type name,@function
68 #define SIZE(name) .size name,.-name
69 #else
70 #define TYPE(name)
71 #define SIZE(name)
72 #endif
73
74 /*
75  * x86/darwin (as of MacOS X 10.4.5) doesn't reliably file signal
76  * handlers (SIGTRAP or Mach exception handlers) for 0xCC, wo we have
77  * to use ud2 instead. ud2 is an undefined opcode, #x0b0f, or
78  * 0F 0B in low-endian notation, that causes SIGILL to fire. We check
79  * for this instruction in the SIGILL handler and if we see it, we
80  * advance the EIP by two bytes to skip over ud2 instruction and
81  * call sigtrap_handler. */
82 #if defined(LISP_FEATURE_DARWIN)
83 #define END()
84 #define TRAP ud2
85 #else
86 #define END() .end
87 #define TRAP int3
88 #endif
89
90         .text
91         .globl  GNAME(foreign_function_call_active)
92         .globl  GNAME(all_threads)
93 \f
94 /*
95  * A call to call_into_c preserves esi, edi, and ebp.   
96  * (The C function will preserve ebx, esi, edi, and ebp across its
97  * function call, but we trash ebx ourselves by using it to save the
98  * return Lisp address.)
99  *
100  * Return values are in eax and maybe edx for quads, or st(0) for
101  * floats.
102  *
103  * This should work for Lisp calls C calls Lisp calls C..
104  */
105         .text
106         .align  align_16byte,0x90
107         .globl GNAME(call_into_c)
108         TYPE(GNAME(call_into_c))
109 GNAME(call_into_c):
110         movl    $1,GNAME(foreign_function_call_active)
111
112 /* Save the return Lisp address in ebx. */
113         popl    %ebx
114
115 /* Setup the NPX for C */
116         fstp    %st(0)
117         fstp    %st(0)
118         fstp    %st(0)
119         fstp    %st(0)
120         fstp    %st(0)
121         fstp    %st(0)
122         fstp    %st(0)
123         fstp    %st(0)
124
125 #ifdef LISP_FEATURE_WIN32
126         cld
127 #endif
128
129 #ifdef LISP_FEATURE_DARWIN
130         andl    $0xfffffff0,%esp        # align stack to 16-byte boundary before calling C
131 #endif
132         call    *%eax           # normal callout using Lisp stack
133
134         movl    %eax,%ecx       # remember integer return value
135
136 /* Check for a return FP value. */
137         fxam
138         fnstsw  %eax
139         andl    $0x4500,%eax
140         cmpl    $0x4100,%eax
141         jne     Lfp_rtn_value
142
143 /* The return value is in eax, or eax,edx? */
144 /* Set up the NPX stack for Lisp. */
145         fldz                    # Ensure no regs are empty.
146         fldz
147         fldz
148         fldz
149         fldz
150         fldz
151         fldz
152         fldz
153
154 /* Restore the return value. */
155         movl    %ecx,%eax       # maybe return value
156
157         movl    $0,GNAME(foreign_function_call_active)
158 /* Return. */
159         jmp     *%ebx
160
161 Lfp_rtn_value:
162 /* The return result is in st(0). */
163 /* Set up the NPX stack for Lisp, placing the result in st(0). */
164         fldz                    # Ensure no regs are empty.
165         fldz
166         fldz
167         fldz
168         fldz
169         fldz
170         fldz
171         fxch    %st(7)          # Move the result back to st(0).
172
173 /* We don't need to restore eax, because the result is in st(0). */
174
175         movl    $0,GNAME(foreign_function_call_active)
176 /* Return. */   
177         jmp     *%ebx
178
179         SIZE(GNAME(call_into_c))
180
181 \f
182         .text   
183         .globl GNAME(call_into_lisp_first_time)
184         TYPE(GNAME(call_into_lisp_first_time))
185                 
186 /* The *ALIEN-STACK* pointer is set up on the first call_into_lisp when
187  * the stack changes.  We don't worry too much about saving registers 
188  * here, because we never expect to return from the initial call to lisp 
189  * anyway */
190         
191         .align  align_16byte,0x90
192 GNAME(call_into_lisp_first_time):
193         pushl   %ebp            # Save old frame pointer.
194         movl    %esp,%ebp       # Establish new frame.
195 #ifndef LISP_FEATURE_WIN32
196         movl    %esp,ALIEN_STACK + SYMBOL_VALUE_OFFSET
197         movl    GNAME(all_threads),%eax
198         movl    THREAD_CONTROL_STACK_START_OFFSET(%eax) ,%esp
199         /* don't think too hard about what happens if we get interrupted
200         * here */
201         addl    $(THREAD_CONTROL_STACK_SIZE),%esp
202 #else
203 /* Win32 -really- doesn't like you switching stacks out from under it. */
204         movl    GNAME(all_threads),%eax
205 #endif
206         jmp     Lstack
207 \f
208         .text   
209         .globl GNAME(call_into_lisp)
210         TYPE(GNAME(call_into_lisp))
211                 
212 /* The C conventions require that ebx, esi, edi, and ebp be preserved
213  * across function calls. */
214         
215         .align  align_16byte,0x90
216 GNAME(call_into_lisp):
217         pushl   %ebp            # Save old frame pointer.
218         movl    %esp,%ebp       # Establish new frame.
219 Lstack:
220 /* Save the NPX state */
221         fwait                   # Catch any pending NPX exceptions.
222         subl    $108,%esp       # Make room for the NPX state.
223         fnsave  (%esp)          # save and reset NPX
224
225         movl    (%esp),%eax     # Load NPX control word.
226         andl    $0xfffff2ff,%eax        # Set rounding mode to nearest.
227         orl     $0x00000200,%eax        # Set precision to 64 bits.  (53-bit mantissa)
228         pushl   %eax
229         fldcw   (%esp)          # Recover modes.
230         popl    %eax
231
232         fldz                    # Ensure no FP regs are empty.
233         fldz
234         fldz
235         fldz
236         fldz
237         fldz
238         fldz
239         fldz
240         
241 /* Save C regs: ebx esi edi. */
242         pushl   %ebx
243         pushl   %esi
244         pushl   %edi
245         
246 /* Clear descriptor regs. */
247         xorl    %eax,%eax       # lexenv
248         xorl    %ebx,%ebx       # available
249         xorl    %ecx,%ecx       # arg count
250         xorl    %edx,%edx       # first arg
251         xorl    %edi,%edi       # second arg
252         xorl    %esi,%esi       # third arg
253
254 /* no longer in function call */
255         movl    %eax, GNAME(foreign_function_call_active)
256
257         movl    %esp,%ebx       # remember current stack
258         pushl   %ebx            # Save entry stack on (maybe) new stack.
259
260         /* Establish Lisp args. */
261         movl     8(%ebp),%eax   # lexenv?
262         movl    12(%ebp),%ebx   # address of arg vec
263         movl    16(%ebp),%ecx   # num args
264         shll    $2,%ecx         # Make num args into fixnum.
265         cmpl    $0,%ecx
266         je      Ldone
267         movl    (%ebx),%edx     # arg0
268         cmpl    $4,%ecx
269         je      Ldone
270         movl    4(%ebx),%edi    # arg1
271         cmpl    $8,%ecx
272         je      Ldone
273         movl    8(%ebx),%esi    # arg2
274 Ldone:  
275         /* Registers eax, ecx, edx, edi, and esi are now live. */
276
277         /* Alloc new frame. */
278         mov     %esp,%ebx       # The current sp marks start of new frame.
279         push    %ebp            # fp in save location S0
280         sub     $8,%esp         # Ensure 3 slots are allocated, one above.
281         mov     %ebx,%ebp       # Switch to new frame.
282
283         call    *CLOSURE_FUN_OFFSET(%eax)
284         
285         /* If the function returned multiple values, it will return to
286            this point.  Lose them */
287         jnc     LsingleValue
288         mov     %ebx, %esp
289 LsingleValue:
290         /* A singled value function returns here */
291
292 /* Restore the stack, in case there was a stack change. */
293         popl    %esp            # c-sp
294
295 /* Restore C regs: ebx esi edi. */
296         popl    %edi
297         popl    %esi
298         popl    %ebx
299
300 /* Restore the NPX state. */
301         frstor  (%esp)
302         addl    $108, %esp
303         
304         popl    %ebp            # c-sp
305         movl    %edx,%eax       # c-val
306         ret
307         SIZE(GNAME(call_into_lisp))
308 \f
309 /* support for saving and restoring the NPX state from C */
310         .text
311         .globl  GNAME(fpu_save)
312         TYPE(GNAME(fpu_save))
313         .align  2,0x90
314 GNAME(fpu_save):
315         movl    4(%esp),%eax
316         fnsave  (%eax)          # Save the NPX state. (resets NPX)
317         ret
318         SIZE(GNAME(fpu_save))
319
320         .globl  GNAME(fpu_restore)
321         TYPE(GNAME(fpu_restore))
322         .align  2,0x90
323 GNAME(fpu_restore):
324         movl    4(%esp),%eax
325         frstor  (%eax)          # Restore the NPX state.
326         ret
327         SIZE(GNAME(fpu_restore))
328 \f
329 /*
330  * the undefined-function trampoline
331  */
332         .text
333         .align  align_4byte,0x90
334         .globl GNAME(undefined_tramp)
335         TYPE(GNAME(undefined_tramp))
336         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
337 GNAME(undefined_tramp):
338         TRAP
339         .byte   trap_Error
340         .byte   2
341         .byte   UNDEFINED_FUN_ERROR
342         .byte   sc_DescriptorReg # eax in the Descriptor-reg SC
343         ret
344         SIZE(GNAME(undefined_tramp))
345
346 /*
347  * the closure trampoline
348  */
349         .text
350         .align  align_4byte,0x90
351         .globl GNAME(closure_tramp)
352         TYPE(GNAME(closure_tramp))
353         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
354 GNAME(closure_tramp):
355         movl    FDEFN_FUN_OFFSET(%eax),%eax
356         /* FIXME: The '*' after "jmp" in the next line is from PVE's
357          * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
358          * reasonable, and it certainly seems as though if CMU CL needs it,
359          * SBCL needs it too, but I haven't actually verified that it's
360          * right. It would be good to find a way to force the flow of
361          * control through here to test it. */
362         jmp     *CLOSURE_FUN_OFFSET(%eax)
363         SIZE(GNAME(closure_tramp))
364
365         .text
366         .align  align_4byte,0x90
367         .globl GNAME(funcallable_instance_tramp)
368         TYPE(GNAME(funcallable_instance_tramp))
369 GNAME(funcallable_instance_tramp):
370         movl    FUNCALLABLE_INSTANCE_FUNCTION_OFFSET(%eax),%eax 
371         /* KLUDGE: on this platform, whatever kind of function is in %rax
372          * now, the first word of it contains the address to jump to. */
373         jmp     *CLOSURE_FUN_OFFSET(%eax)
374         SIZE(GNAME(funcallable_instance_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    $(NIL),%edi     # default second value
392         movl    $(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
848 #ifdef LISP_FEATURE_DARWIN
849         .align align_4byte
850         .globl GNAME(call_into_lisp_tramp)
851         TYPE(GNAME(call_into_lisp_tramp))
852 GNAME(call_into_lisp_tramp):
853         /* 1. build the stack frame from the block that's pointed to by ECX
854            2. free the block
855            3. set ECX to 0
856            4. call the function via call_into_lisp
857         */
858         pushl   0(%ecx)          /* return address */
859
860         pushl   %ebp
861         movl    %esp, %ebp
862
863         pushl   32(%ecx)         /* eflags */
864         pushl   28(%ecx)         /* EAX */
865         pushl   20(%ecx)         /* ECX */
866         pushl   16(%ecx)         /* EDX */
867         pushl   24(%ecx)         /* EBX */
868         pushl   $0                /* popal is going to ignore esp */
869         pushl   %ebp              /* is this right?? */
870         pushl   12(%ecx)         /* ESI */
871         pushl   8(%ecx)          /* EDI */
872         pushl   $0                /* args for call_into_lisp */
873         pushl   $0
874         pushl   4(%ecx)          /* function to call */
875
876         /* free our save block */
877         pushl   %ecx              /* reserve sufficient space on stack for args */
878         pushl   %ecx
879         andl    $0xfffffff0, %esp  /* align stack */
880         movl    $0x40, 4(%esp)
881         movl    %ecx, (%esp)
882         call    GNAME(os_invalidate)
883
884         /* call call_into_lisp */
885         leal    -48(%ebp), %esp
886         call    GNAME(call_into_lisp)
887
888         /* Clean up our mess */
889         leal    -36(%ebp), %esp
890         popal
891         popfl
892         leave
893         ret
894         
895         SIZE(call_into_lisp_tramp)
896 #endif
897         
898         .align  align_4byte,0x90
899         .globl  GNAME(post_signal_tramp)
900         TYPE(GNAME(post_signal_tramp))
901 GNAME(post_signal_tramp):
902         /* this is notionally the second half of a function whose first half
903          * doesn't exist.  This is where call_into_lisp returns when called 
904          * using return_to_lisp_function */
905         addl $12,%esp   /* clear call_into_lisp args from stack */
906         popal           /* restore registers */
907         popfl
908 #ifdef LISP_FEATURE_DARWIN
909         /* skip two padding words */
910         addl $8,%esp
911 #endif
912         leave
913         ret
914         SIZE(GNAME(post_signal_tramp))
915
916 #ifdef LISP_FEATURE_WIN32
917         /*
918          * This is part of the funky magic for exception handling on win32.
919          * see sigtrap_emulator() in win32-os.c for details.
920          */
921         .globl GNAME(sigtrap_trampoline)
922 GNAME(sigtrap_trampoline):
923         pushl   %eax
924         pushl   %ebp
925         movl    %esp, %ebp
926         call    GNAME(sigtrap_wrapper)
927         pop     %eax
928         pop     %eax
929         TRAP
930         .byte   trap_ContextRestore
931         hlt                     # We should never return here.
932         
933         /*
934          * This is part of the funky magic for exception handling on win32.
935          * see handle_exception() in win32-os.c for details.
936          */
937         .globl GNAME(exception_trampoline)
938 GNAME(exception_trampoline):
939         pushl   %eax
940         pushl   %ebp
941         movl    %esp, %ebp
942         call    GNAME(handle_win32_exception_wrapper)
943         pop     %eax
944         pop     %eax
945         TRAP
946         .byte   trap_ContextRestore
947         hlt                     # We should never return here.
948 #endif
949
950         /* fast_bzero implementations and code to detect which implementation
951          * to use.
952          */
953 \f
954         .globl GNAME(fast_bzero_pointer)
955         .data
956         .align  align_4byte
957 GNAME(fast_bzero_pointer):
958         /* Variable containing a pointer to the bzero function to use.
959          * Initially points to a basic function.  Change this variable
960          * to fast_bzero_detect if OS supports SSE.  */
961         .long GNAME(fast_bzero_base)
962 \f
963         .text
964         .align  align_8byte,0x90
965         .globl GNAME(fast_bzero)
966         TYPE(GNAME(fast_bzero))
967 GNAME(fast_bzero):        
968         /* Indirect function call */
969         jmp *GNAME(fast_bzero_pointer)
970         SIZE(GNAME(fast_bzero))
971         
972 \f      
973         .text
974         .align  align_8byte,0x90
975         .globl GNAME(fast_bzero_detect)
976         TYPE(GNAME(fast_bzero_detect))
977 GNAME(fast_bzero_detect):
978         /* Decide whether to use SSE, MMX or REP version */
979         push %eax /* CPUID uses EAX-EDX */
980         push %ebx
981         push %ecx
982         push %edx
983         mov $1, %eax
984         cpuid
985         test $0x04000000, %edx    /* SSE2 needed for MOVNTDQ */
986         jnz Lsse2
987         /* Originally there was another case here for using the
988          * MOVNTQ instruction for processors that supported MMX but
989          * not SSE2. This turned out to be a loss especially on
990          * Athlons (where this instruction is apparently microcoded
991          * somewhat slowly). So for simplicity revert to REP STOSL
992          * for all non-SSE2 processors.
993          */
994 Lbase:
995         movl $(GNAME(fast_bzero_base)), GNAME(fast_bzero_pointer)
996         jmp Lrestore
997 Lsse2:
998         movl $(GNAME(fast_bzero_sse)), GNAME(fast_bzero_pointer)
999         jmp Lrestore
1000         
1001 Lrestore:
1002         pop %edx
1003         pop %ecx
1004         pop %ebx
1005         pop %eax
1006         jmp *GNAME(fast_bzero_pointer)
1007         
1008         SIZE(GNAME(fast_bzero_detect))
1009         
1010 \f
1011         .text
1012         .align  align_8byte,0x90
1013         .globl GNAME(fast_bzero_sse)
1014         TYPE(GNAME(fast_bzero_sse))
1015         
1016 GNAME(fast_bzero_sse):
1017         /* A fast routine for zero-filling blocks of memory that are
1018          * guaranteed to start and end at a 4096-byte aligned address.
1019          */        
1020         push %esi                 /* Save temporary registers */
1021         push %edi
1022         mov 16(%esp), %esi        /* Parameter: amount of bytes to fill */
1023         mov 12(%esp), %edi        /* Parameter: start address */
1024         shr $6, %esi              /* Amount of 64-byte blocks to copy */
1025         jz Lend_sse               /* If none, stop */
1026         movups %xmm7, -16(%esp)   /* Save XMM register */
1027         xorps  %xmm7, %xmm7       /* Zero the XMM register */
1028         jmp Lloop_sse
1029         .align align_16byte
1030 Lloop_sse:
1031
1032         /* Copy the 16 zeroes from xmm7 to memory, 4 times. MOVNTDQ is the
1033          * non-caching double-quadword moving variant, i.e. the memory areas
1034          * we're touching are not fetched into the L1 cache, since we're just
1035          * going to overwrite the memory soon anyway.
1036          */
1037         movntdq %xmm7, 0(%edi)
1038         movntdq %xmm7, 16(%edi)
1039         movntdq %xmm7, 32(%edi)
1040         movntdq %xmm7, 48(%edi)
1041  
1042         add $64, %edi /* Advance pointer */
1043         dec %esi      /* Decrement 64-byte block count */
1044         jnz Lloop_sse
1045         movups -16(%esp), %xmm7 /* Restore the XMM register */
1046         sfence        /* Ensure that weakly ordered writes are flushed. */
1047 Lend_sse:
1048         mov 12(%esp), %esi      /* Parameter: start address */
1049         prefetcht0 0(%esi)      /* Prefetch the start of the block into cache,
1050                                  * since it's likely to be used immediately. */
1051         pop %edi      /* Restore temp registers */
1052         pop %esi
1053         ret
1054         SIZE(GNAME(fast_bzero_sse))
1055                 
1056 \f
1057         .text
1058         .align  align_8byte,0x90
1059         .globl GNAME(fast_bzero_base)
1060         TYPE(GNAME(fast_bzero_base))
1061         
1062 GNAME(fast_bzero_base):
1063         /* A fast routine for zero-filling blocks of memory that are
1064          * guaranteed to start and end at a 4096-byte aligned address.
1065          */        
1066         push %eax                 /* Save temporary registers */
1067         push %ecx
1068         push %edi
1069         mov 20(%esp), %ecx        /* Parameter: amount of bytes to fill */
1070         mov 16(%esp), %edi        /* Parameter: start address */
1071         xor %eax, %eax            /* Zero EAX */
1072         shr $2, %ecx              /* Amount of 4-byte blocks to copy */
1073         jz  Lend_base
1074         cld                       /* Set direction of STOSL to increment */
1075
1076         rep
1077         stosl                     /* Store EAX to *EDI, ECX times, incrementing
1078                                    * EDI by 4 after each store */
1079         
1080 Lend_base:        
1081         pop %edi                  /* Restore temp registers */
1082         pop %ecx
1083         pop %eax
1084         ret
1085         SIZE(GNAME(fast_bzero_base))
1086         
1087 \f       
1088         END()
1089