1.0.1.34: quote fix for old cpp
[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 #ifdef LISP_FEATURE_WIN32
278         /* Establish an SEH frame. */
279 #ifdef LISP_FEATURE_SB_THREAD
280         /* FIXME: need to save BSP here. */
281 #error "need to save BSP here, but don't know how yet."
282 #else
283         pushl   BINDING_STACK_POINTER + SYMBOL_VALUE_OFFSET
284 #endif
285         pushl   $GNAME(exception_handler_wrapper)
286         pushl   %fs:0
287         movl    %esp, %fs:0
288 #endif
289
290         /* Alloc new frame. */
291         mov     %esp,%ebx       # The current sp marks start of new frame.
292         push    %ebp            # fp in save location S0
293         sub     $8,%esp         # Ensure 3 slots are allocated, one above.
294         mov     %ebx,%ebp       # Switch to new frame.
295
296         call    *CLOSURE_FUN_OFFSET(%eax)
297         
298         /* If the function returned multiple values, it will return to
299            this point.  Lose them */
300         jnc     LsingleValue
301         mov     %ebx, %esp
302 LsingleValue:
303         /* A singled value function returns here */
304
305 #ifdef LISP_FEATURE_WIN32
306         /* Remove our SEH frame. */
307         popl    %fs:0
308         add     $8, %esp
309 #endif
310
311 /* Restore the stack, in case there was a stack change. */
312         popl    %esp            # c-sp
313
314 /* Restore C regs: ebx esi edi. */
315         popl    %edi
316         popl    %esi
317         popl    %ebx
318
319 /* Restore the NPX state. */
320         frstor  (%esp)
321         addl    $108, %esp
322         
323         popl    %ebp            # c-sp
324         movl    %edx,%eax       # c-val
325         ret
326         SIZE(GNAME(call_into_lisp))
327 \f
328 /* support for saving and restoring the NPX state from C */
329         .text
330         .globl  GNAME(fpu_save)
331         TYPE(GNAME(fpu_save))
332         .align  2,0x90
333 GNAME(fpu_save):
334         movl    4(%esp),%eax
335         fnsave  (%eax)          # Save the NPX state. (resets NPX)
336         ret
337         SIZE(GNAME(fpu_save))
338
339         .globl  GNAME(fpu_restore)
340         TYPE(GNAME(fpu_restore))
341         .align  2,0x90
342 GNAME(fpu_restore):
343         movl    4(%esp),%eax
344         frstor  (%eax)          # Restore the NPX state.
345         ret
346         SIZE(GNAME(fpu_restore))
347 \f
348 /*
349  * the undefined-function trampoline
350  */
351         .text
352         .align  align_4byte,0x90
353         .globl GNAME(undefined_tramp)
354         TYPE(GNAME(undefined_tramp))
355         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
356 GNAME(undefined_tramp):
357         TRAP
358         .byte   trap_Error
359         .byte   2
360         .byte   UNDEFINED_FUN_ERROR
361         .byte   sc_DescriptorReg # eax in the Descriptor-reg SC
362         ret
363         SIZE(GNAME(undefined_tramp))
364
365 /*
366  * the closure trampoline
367  */
368         .text
369         .align  align_4byte,0x90
370         .globl GNAME(closure_tramp)
371         TYPE(GNAME(closure_tramp))
372         .byte   0, 0, 0, SIMPLE_FUN_HEADER_WIDETAG
373 GNAME(closure_tramp):
374         movl    FDEFN_FUN_OFFSET(%eax),%eax
375         /* FIXME: The '*' after "jmp" in the next line is from PVE's
376          * patch posted to the CMU CL mailing list Oct 6, 1999. It looks
377          * reasonable, and it certainly seems as though if CMU CL needs it,
378          * SBCL needs it too, but I haven't actually verified that it's
379          * right. It would be good to find a way to force the flow of
380          * control through here to test it. */
381         jmp     *CLOSURE_FUN_OFFSET(%eax)
382         SIZE(GNAME(closure_tramp))
383
384         .text
385         .align  align_4byte,0x90
386         .globl GNAME(funcallable_instance_tramp)
387         TYPE(GNAME(funcallable_instance_tramp))
388 GNAME(funcallable_instance_tramp):
389         movl    FUNCALLABLE_INSTANCE_FUNCTION_OFFSET(%eax),%eax 
390         /* KLUDGE: on this platform, whatever kind of function is in %rax
391          * now, the first word of it contains the address to jump to. */
392         jmp     *CLOSURE_FUN_OFFSET(%eax)
393         SIZE(GNAME(funcallable_instance_tramp))
394         
395 /*
396  * fun-end breakpoint magic
397  */
398         .text
399         .globl  GNAME(fun_end_breakpoint_guts)
400         .align  align_4byte
401 GNAME(fun_end_breakpoint_guts):
402         /* Multiple Value return */
403         jc      multiple_value_return
404         /* Single value return: The eventual return will now use the
405            multiple values return convention but with a return values
406            count of one. */
407         movl    %esp,%ebx       # Setup ebx - the ofp.
408         subl    $4,%esp         # Allocate one stack slot for the return value
409         movl    $4,%ecx         # Setup ecx for one return value.
410         movl    $(NIL),%edi     # default second value
411         movl    $(NIL),%esi     # default third value
412                 
413 multiple_value_return:
414         
415         .globl GNAME(fun_end_breakpoint_trap)
416 GNAME(fun_end_breakpoint_trap):
417         TRAP
418         .byte   trap_FunEndBreakpoint
419         hlt                     # We should never return here.
420
421         .globl GNAME(fun_end_breakpoint_end)
422 GNAME(fun_end_breakpoint_end):
423
424 \f
425         .globl  GNAME(do_pending_interrupt)
426         TYPE(GNAME(do_pending_interrupt))
427         .align  align_4byte,0x90
428 GNAME(do_pending_interrupt):
429         TRAP
430         .byte   trap_PendingInterrupt
431         ret
432         SIZE(GNAME(do_pending_interrupt))
433 \f
434
435 /*
436  * Allocate bytes and return the start of the allocated space
437  * in the specified destination register.
438  *
439  * In the general case the size will be in the destination register.
440  *
441  * All registers must be preserved except the destination.
442  * The C conventions will preserve ebx, esi, edi, and ebp.
443  * So only eax, ecx, and edx need special care here.
444  */
445         
446         .globl  GNAME(alloc_to_eax)
447         TYPE(GNAME(alloc_to_eax))
448         .align  align_4byte,0x90
449 GNAME(alloc_to_eax):
450         pushl   %ecx    # Save ecx and edx as C could destroy them.
451         pushl   %edx
452         pushl   %eax    # Push the size.
453         call    GNAME(alloc)
454         addl    $4,%esp # Pop the size arg.
455         popl    %edx    # Restore ecx and edx.
456         popl    %ecx
457         ret
458         SIZE(GNAME(alloc_to_eax))
459
460         .globl  GNAME(alloc_8_to_eax)
461         TYPE(GNAME(alloc_8_to_eax))
462         .align  align_4byte,0x90
463 GNAME(alloc_8_to_eax):
464         pushl   %ecx    # Save ecx and edx as C could destroy them.
465         pushl   %edx
466         pushl   $8      # Push the size.
467         call    GNAME(alloc)
468         addl    $4,%esp # Pop the size arg.
469         popl    %edx    # Restore ecx and edx.
470         popl    %ecx
471         ret
472         SIZE(GNAME(alloc_8_to_eax))
473
474         .globl  GNAME(alloc_8_to_eax)
475         TYPE(GNAME(alloc_8_to_eax))
476         .align  align_4byte,0x90
477
478         .globl  GNAME(alloc_16_to_eax)
479         TYPE(GNAME(alloc_16_to_eax))
480         .align  align_4byte,0x90
481 GNAME(alloc_16_to_eax):
482         pushl   %ecx    # Save ecx and edx as C could destroy them.
483         pushl   %edx
484         pushl   $16     # Push the size.
485         call    GNAME(alloc)
486         addl    $4,%esp # Pop the size arg.
487         popl    %edx    # Restore ecx and edx.
488         popl    %ecx
489         ret
490         SIZE(GNAME(alloc_16_to_eax))
491
492         .globl  GNAME(alloc_to_ecx)
493         TYPE(GNAME(alloc_to_ecx))
494         .align  align_4byte,0x90
495 GNAME(alloc_to_ecx):
496         pushl   %eax    # Save eax and edx as C could destroy them.
497         pushl   %edx
498         pushl   %ecx    # Push the size.
499         call    GNAME(alloc)
500         addl    $4,%esp # Pop the size arg.
501         movl    %eax,%ecx       # Set up the destination.
502         popl    %edx    # Restore eax and edx.
503         popl    %eax
504         ret
505         SIZE(GNAME(alloc_to_ecx))
506
507         .globl  GNAME(alloc_8_to_ecx)
508         TYPE(GNAME(alloc_8_to_ecx))
509         .align  align_4byte,0x90
510 GNAME(alloc_8_to_ecx):
511         pushl   %eax    # Save eax and edx as C could destroy them.
512         pushl   %edx
513         pushl   $8      # Push the size.
514         call    GNAME(alloc)
515         addl    $4,%esp # Pop the size arg.
516         movl    %eax,%ecx       # Set up the destination.
517         popl    %edx    # Restore eax and edx.
518         popl    %eax
519         ret
520         SIZE(GNAME(alloc_8_to_ecx))
521
522         .globl  GNAME(alloc_16_to_ecx)
523         TYPE(GNAME(alloc_16_to_ecx))
524         .align  align_4byte,0x90
525 GNAME(alloc_16_to_ecx):
526         pushl   %eax    # Save eax and edx as C could destroy them.
527         pushl   %edx
528         pushl   $16     # Push the size.
529         call    GNAME(alloc)
530         addl    $4,%esp # Pop the size arg.
531         movl    %eax,%ecx       # Set up the destination.
532         popl    %edx    # Restore eax and edx.
533         popl    %eax
534         ret
535         SIZE(GNAME(alloc_16_to_ecx))
536
537
538         .globl  GNAME(alloc_to_edx)
539         TYPE(GNAME(alloc_to_edx))
540         .align  align_4byte,0x90
541 GNAME(alloc_to_edx):
542         pushl   %eax    # Save eax and ecx as C could destroy them.
543         pushl   %ecx
544         pushl   %edx    # Push the size.
545         call    GNAME(alloc)
546         addl    $4,%esp # Pop the size arg.
547         movl    %eax,%edx       # Set up the destination.
548         popl    %ecx    # Restore eax and ecx.
549         popl    %eax
550         ret
551         SIZE(GNAME(alloc_to_edx))
552
553         .globl  GNAME(alloc_8_to_edx)
554         TYPE(GNAME(alloc_8_to_edx))
555         .align  align_4byte,0x90
556 GNAME(alloc_8_to_edx):
557         pushl   %eax    # Save eax and ecx as C could destroy them.
558         pushl   %ecx
559         pushl   $8      # Push the size.
560         call    GNAME(alloc)
561         addl    $4,%esp # Pop the size arg.
562         movl    %eax,%edx       # Set up the destination.
563         popl    %ecx    # Restore eax and ecx.
564         popl    %eax
565         ret
566         SIZE(GNAME(alloc_8_to_edx))
567
568         .globl  GNAME(alloc_16_to_edx)
569         TYPE(GNAME(alloc_16_to_edx))
570         .align  align_4byte,0x90
571 GNAME(alloc_16_to_edx):
572         pushl   %eax    # Save eax and ecx as C could destroy them.
573         pushl   %ecx
574         pushl   $16     # Push the size.
575         call    GNAME(alloc)
576         addl    $4,%esp # Pop the size arg.
577         movl    %eax,%edx       # Set up the destination.
578         popl    %ecx    # Restore eax and ecx.
579         popl    %eax
580         ret
581         SIZE(GNAME(alloc_16_to_edx))
582
583
584
585         .globl  GNAME(alloc_to_ebx)
586         TYPE(GNAME(alloc_to_ebx))
587         .align  align_4byte,0x90
588 GNAME(alloc_to_ebx):
589         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
590         pushl   %ecx
591         pushl   %edx
592         pushl   %ebx    # Push the size.
593         call    GNAME(alloc)
594         addl    $4,%esp # Pop the size arg.
595         movl    %eax,%ebx       # Set up the destination.
596         popl    %edx    # Restore eax, ecx and edx.
597         popl    %ecx
598         popl    %eax
599         ret
600         SIZE(GNAME(alloc_to_ebx))
601
602         .globl  GNAME(alloc_8_to_ebx)
603         TYPE(GNAME(alloc_8_to_ebx))
604         .align  align_4byte,0x90
605 GNAME(alloc_8_to_ebx):
606         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
607         pushl   %ecx
608         pushl   %edx
609         pushl   $8      # Push the size.
610         call    GNAME(alloc)
611         addl    $4,%esp # Pop the size arg.
612         movl    %eax,%ebx       # Set up the destination.
613         popl    %edx    # Restore eax, ecx and edx.
614         popl    %ecx
615         popl    %eax
616         ret
617         SIZE(GNAME(alloc_8_to_ebx))
618
619         .globl  GNAME(alloc_16_to_ebx)
620         TYPE(GNAME(alloc_16_to_ebx))
621         .align  align_4byte,0x90
622 GNAME(alloc_16_to_ebx):
623         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
624         pushl   %ecx
625         pushl   %edx
626         pushl   $16     # Push the size
627         call    GNAME(alloc)
628         addl    $4,%esp # pop the size arg.
629         movl    %eax,%ebx       # setup the destination.
630         popl    %edx    # Restore eax, ecx and edx.
631         popl    %ecx
632         popl    %eax
633         ret
634         SIZE(GNAME(alloc_16_to_ebx))
635
636
637
638         .globl  GNAME(alloc_to_esi)
639         TYPE(GNAME(alloc_to_esi))
640         .align  align_4byte,0x90
641 GNAME(alloc_to_esi):
642         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
643         pushl   %ecx
644         pushl   %edx
645         pushl   %esi    # Push the size
646         call    GNAME(alloc)
647         addl    $4,%esp # pop the size arg.
648         movl    %eax,%esi       # setup the destination.
649         popl    %edx    # Restore eax, ecx and edx.
650         popl    %ecx
651         popl    %eax
652         ret
653         SIZE(GNAME(alloc_to_esi))
654
655         .globl  GNAME(alloc_8_to_esi)
656         TYPE(GNAME(alloc_8_to_esi))
657         .align  align_4byte,0x90
658 GNAME(alloc_8_to_esi):
659         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
660         pushl   %ecx
661         pushl   %edx
662         pushl   $8      # Push the size
663         call    GNAME(alloc)
664         addl    $4,%esp # pop the size arg.
665         movl    %eax,%esi       # setup the destination.
666         popl    %edx    # Restore eax, ecx and edx.
667         popl    %ecx
668         popl    %eax
669         ret
670         SIZE(GNAME(alloc_8_to_esi))
671
672         .globl  GNAME(alloc_16_to_esi)
673         TYPE(GNAME(alloc_16_to_esi))
674         .align  align_4byte,0x90
675 GNAME(alloc_16_to_esi):
676         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
677         pushl   %ecx
678         pushl   %edx
679         pushl   $16     # Push the size
680         call    GNAME(alloc)
681         addl    $4,%esp # pop the size arg.
682         movl    %eax,%esi       # setup the destination.
683         popl    %edx    # Restore eax, ecx and edx.
684         popl    %ecx
685         popl    %eax
686         ret
687         SIZE(GNAME(alloc_16_to_esi))
688
689
690         .globl  GNAME(alloc_to_edi)
691         TYPE(GNAME(alloc_to_edi))
692         .align  align_4byte,0x90
693 GNAME(alloc_to_edi):
694         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
695         pushl   %ecx
696         pushl   %edx
697         pushl   %edi    # Push the size
698         call    GNAME(alloc)
699         addl    $4,%esp # pop the size arg.
700         movl    %eax,%edi       # setup the destination.
701         popl    %edx    # Restore eax, ecx and edx.
702         popl    %ecx
703         popl    %eax
704         ret
705         SIZE(GNAME(alloc_to_edi))
706
707         .globl  GNAME(alloc_8_to_edi)
708         TYPE(GNAME(alloc_8_to_edi))
709         .align  align_4byte,0x90
710 GNAME(alloc_8_to_edi):
711         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
712         pushl   %ecx
713         pushl   %edx
714         pushl   $8      # Push the size
715         call    GNAME(alloc)
716         addl    $4,%esp # pop the size arg.
717         movl    %eax,%edi       # setup the destination.
718         popl    %edx    # Restore eax, ecx and edx.
719         popl    %ecx
720         popl    %eax
721         ret
722         SIZE(GNAME(alloc_8_to_edi))
723
724         .globl  GNAME(alloc_16_to_edi)
725         TYPE(GNAME(alloc_16_to_edi))
726         .align  align_4byte,0x90
727 GNAME(alloc_16_to_edi):
728         pushl   %eax    # Save eax, ecx, and edx as C could destroy them.
729         pushl   %ecx
730         pushl   %edx
731         pushl   $16     # Push the size
732         call    GNAME(alloc)
733         addl    $4,%esp # pop the size arg.
734         movl    %eax,%edi       # setup the destination.
735         popl    %edx    # Restore eax, ecx and edx.
736         popl    %ecx
737         popl    %eax
738         ret
739         SIZE(GNAME(alloc_16_to_edi))
740
741         
742 /* Called from lisp when an inline allocation overflows.
743    Every register except the result needs to be preserved.
744    We depend on C to preserve ebx, esi, edi, and ebp.
745    But where necessary must save eax, ecx, edx. */
746
747 #ifdef LISP_FEATURE_SB_THREAD
748 #define START_REGION %fs:THREAD_ALLOC_REGION_OFFSET
749 #else
750 #define START_REGION GNAME(boxed_region)
751 #endif
752                 
753 /* This routine handles an overflow with eax=crfp+size. So the
754    size=eax-crfp. */
755         .align  align_4byte
756         .globl  GNAME(alloc_overflow_eax)
757         TYPE(GNAME(alloc_overflow_eax))
758 GNAME(alloc_overflow_eax):
759         pushl   %ecx            # Save ecx
760         pushl   %edx            # Save edx
761         /* Calculate the size for the allocation. */
762         subl    START_REGION,%eax
763         pushl   %eax            # Push the size
764         call    GNAME(alloc)
765         addl    $4,%esp # pop the size arg.
766         popl    %edx    # Restore edx.
767         popl    %ecx    # Restore ecx.
768         ret
769         SIZE(GNAME(alloc_overflow_eax))
770
771         .align  align_4byte
772         .globl  GNAME(alloc_overflow_ecx)
773         TYPE(GNAME(alloc_overflow_ecx))
774 GNAME(alloc_overflow_ecx):
775         pushl   %eax            # Save eax
776         pushl   %edx            # Save edx
777         /* Calculate the size for the allocation. */
778         subl    START_REGION,%ecx
779         pushl   %ecx            # Push the size
780         call    GNAME(alloc)
781         addl    $4,%esp # pop the size arg.
782         movl    %eax,%ecx       # setup the destination.
783         popl    %edx    # Restore edx.
784         popl    %eax    # Restore eax.
785         ret
786         SIZE(GNAME(alloc_overflow_ecx))
787
788         .align  align_4byte
789         .globl  GNAME(alloc_overflow_edx)
790         TYPE(GNAME(alloc_overflow_edx))
791 GNAME(alloc_overflow_edx):
792         pushl   %eax            # Save eax
793         pushl   %ecx            # Save ecx
794         /* Calculate the size for the allocation. */
795         subl    START_REGION,%edx
796         pushl   %edx            # Push the size
797         call    GNAME(alloc)
798         addl    $4,%esp # pop the size arg.
799         movl    %eax,%edx       # setup the destination.
800         popl    %ecx    # Restore ecx.
801         popl    %eax    # Restore eax.
802         ret
803         SIZE(GNAME(alloc_overflow_edx))
804
805 /* This routine handles an overflow with ebx=crfp+size. So the
806    size=ebx-crfp. */
807         .align  align_4byte
808         .globl  GNAME(alloc_overflow_ebx)
809         TYPE(GNAME(alloc_overflow_ebx))
810 GNAME(alloc_overflow_ebx):
811         pushl   %eax            # Save eax
812         pushl   %ecx            # Save ecx
813         pushl   %edx            # Save edx
814         /* Calculate the size for the allocation. */
815         subl    START_REGION,%ebx
816         pushl   %ebx            # Push the size
817         call    GNAME(alloc)
818         addl    $4,%esp # pop the size arg.
819         movl    %eax,%ebx       # setup the destination.
820         popl    %edx    # Restore edx.
821         popl    %ecx    # Restore ecx.
822         popl    %eax    # Restore eax.
823         ret
824         SIZE(GNAME(alloc_overflow_ebx))
825
826 /* This routine handles an overflow with esi=crfp+size. So the
827    size=esi-crfp. */
828         .align  align_4byte
829         .globl  GNAME(alloc_overflow_esi)
830         TYPE(GNAME(alloc_overflow_esi))
831 GNAME(alloc_overflow_esi):
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,%esi
837         pushl   %esi            # Push the size
838         call    GNAME(alloc)
839         addl    $4,%esp # pop the size arg.
840         movl    %eax,%esi       # 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_esi))
846
847         .align  align_4byte
848         .globl  GNAME(alloc_overflow_edi)
849         TYPE(GNAME(alloc_overflow_edi))
850 GNAME(alloc_overflow_edi):
851         pushl   %eax            # Save eax
852         pushl   %ecx            # Save ecx
853         pushl   %edx            # Save edx
854         /* Calculate the size for the allocation. */
855         subl    START_REGION,%edi
856         pushl   %edi            # Push the size
857         call    GNAME(alloc)
858         addl    $4,%esp # pop the size arg.
859         movl    %eax,%edi       # setup the destination.
860         popl    %edx    # Restore edx.
861         popl    %ecx    # Restore ecx.
862         popl    %eax    # Restore eax.
863         ret
864         SIZE(GNAME(alloc_overflow_edi))
865
866
867 #ifdef LISP_FEATURE_WIN32
868         /* The guts of the exception-handling system doesn't use
869          * frame pointers, which manages to throw off backtraces
870          * rather badly.  So here we grab the (known-good) EBP
871          * and EIP from the exception context and use it to fake
872          * up a stack frame which will skip over the system SEH
873          * code. */
874         .align  align_4byte
875         .globl  GNAME(exception_handler_wrapper)
876         TYPE(GNAME(exception_handler_wrapper))
877 GNAME(exception_handler_wrapper):
878         /* Context layout is: */
879         /* 7 dwords before FSA. (0x1c) */
880         /* 8 dwords and 0x50 bytes in the FSA. (0x70/0x8c) */
881         /* 4 dwords segregs. (0x10/0x9c) */
882         /* 6 dwords non-stack GPRs. (0x18/0xb4) */
883         /* EBP (at 0xb4) */
884         /* EIP (at 0xb8) */
885 #define CONTEXT_EBP_OFFSET 0xb4
886 #define CONTEXT_EIP_OFFSET 0xb8
887         /* some other stuff we don't care about. */
888         pushl   %ebp
889         movl    0x10(%esp), %ebp        /* context */
890         pushl   CONTEXT_EIP_OFFSET(%ebp)
891         pushl   CONTEXT_EBP_OFFSET(%ebp)
892         movl    %esp, %ebp
893         pushl   0x1c(%esp)
894         pushl   0x1c(%esp)
895         pushl   0x1c(%esp)
896         pushl   0x1c(%esp)
897         call    GNAME(handle_exception)
898         lea     8(%ebp), %esp
899         popl    %ebp
900         ret
901         SIZE(GNAME(exception_handler_wrapper))
902 #endif
903
904 #ifdef LISP_FEATURE_DARWIN
905         .align align_4byte
906         .globl GNAME(call_into_lisp_tramp)
907         TYPE(GNAME(call_into_lisp_tramp))
908 GNAME(call_into_lisp_tramp):
909         /* 1. build the stack frame from the block that's pointed to by ECX
910            2. free the block
911            3. set ECX to 0
912            4. call the function via call_into_lisp
913         */
914         pushl   0(%ecx)          /* return address */
915
916         pushl   %ebp
917         movl    %esp, %ebp
918
919         pushl   32(%ecx)         /* eflags */
920         pushl   28(%ecx)         /* EAX */
921         pushl   20(%ecx)         /* ECX */
922         pushl   16(%ecx)         /* EDX */
923         pushl   24(%ecx)         /* EBX */
924         pushl   $0                /* popal is going to ignore esp */
925         pushl   %ebp              /* is this right?? */
926         pushl   12(%ecx)         /* ESI */
927         pushl   8(%ecx)          /* EDI */
928         pushl   $0                /* args for call_into_lisp */
929         pushl   $0
930         pushl   4(%ecx)          /* function to call */
931
932         /* free our save block */
933         pushl   %ecx              /* reserve sufficient space on stack for args */
934         pushl   %ecx
935         andl    $0xfffffff0, %esp  /* align stack */
936         movl    $0x40, 4(%esp)
937         movl    %ecx, (%esp)
938         call    GNAME(os_invalidate)
939
940         /* call call_into_lisp */
941         leal    -48(%ebp), %esp
942         call    GNAME(call_into_lisp)
943
944         /* Clean up our mess */
945         leal    -36(%ebp), %esp
946         popal
947         popfl
948         leave
949         ret
950         
951         SIZE(call_into_lisp_tramp)
952 #endif
953         
954         .align  align_4byte,0x90
955         .globl  GNAME(post_signal_tramp)
956         TYPE(GNAME(post_signal_tramp))
957 GNAME(post_signal_tramp):
958         /* this is notionally the second half of a function whose first half
959          * doesn't exist.  This is where call_into_lisp returns when called 
960          * using return_to_lisp_function */
961         addl $12,%esp   /* clear call_into_lisp args from stack */
962         popal           /* restore registers */
963         popfl
964 #ifdef LISP_FEATURE_DARWIN
965         /* skip two padding words */
966         addl $8,%esp
967 #endif
968         leave
969         ret
970         SIZE(GNAME(post_signal_tramp))
971
972
973         /* fast_bzero implementations and code to detect which implementation
974          * to use.
975          */
976 \f
977         .globl GNAME(fast_bzero_pointer)
978         .data
979         .align  align_4byte
980 GNAME(fast_bzero_pointer):
981         /* Variable containing a pointer to the bzero function to use.
982          * Initially points to a basic function.  Change this variable
983          * to fast_bzero_detect if OS supports SSE.  */
984         .long GNAME(fast_bzero_base)
985 \f
986         .text
987         .align  align_8byte,0x90
988         .globl GNAME(fast_bzero)
989         TYPE(GNAME(fast_bzero))
990 GNAME(fast_bzero):        
991         /* Indirect function call */
992         jmp *GNAME(fast_bzero_pointer)
993         SIZE(GNAME(fast_bzero))
994         
995 \f      
996         .text
997         .align  align_8byte,0x90
998         .globl GNAME(fast_bzero_detect)
999         TYPE(GNAME(fast_bzero_detect))
1000 GNAME(fast_bzero_detect):
1001         /* Decide whether to use SSE, MMX or REP version */
1002         push %eax /* CPUID uses EAX-EDX */
1003         push %ebx
1004         push %ecx
1005         push %edx
1006         mov $1, %eax
1007         cpuid
1008         test $0x04000000, %edx    /* SSE2 needed for MOVNTDQ */
1009         jnz Lsse2
1010         /* Originally there was another case here for using the
1011          * MOVNTQ instruction for processors that supported MMX but
1012          * not SSE2. This turned out to be a loss especially on
1013          * Athlons (where this instruction is apparently microcoded
1014          * somewhat slowly). So for simplicity revert to REP STOSL
1015          * for all non-SSE2 processors.
1016          */
1017 Lbase:
1018         movl $(GNAME(fast_bzero_base)), GNAME(fast_bzero_pointer)
1019         jmp Lrestore
1020 Lsse2:
1021         movl $(GNAME(fast_bzero_sse)), GNAME(fast_bzero_pointer)
1022         jmp Lrestore
1023         
1024 Lrestore:
1025         pop %edx
1026         pop %ecx
1027         pop %ebx
1028         pop %eax
1029         jmp *GNAME(fast_bzero_pointer)
1030         
1031         SIZE(GNAME(fast_bzero_detect))
1032         
1033 \f
1034         .text
1035         .align  align_8byte,0x90
1036         .globl GNAME(fast_bzero_sse)
1037         TYPE(GNAME(fast_bzero_sse))
1038         
1039 GNAME(fast_bzero_sse):
1040         /* A fast routine for zero-filling blocks of memory that are
1041          * guaranteed to start and end at a 4096-byte aligned address.
1042          */        
1043         push %esi                 /* Save temporary registers */
1044         push %edi
1045         mov 16(%esp), %esi        /* Parameter: amount of bytes to fill */
1046         mov 12(%esp), %edi        /* Parameter: start address */
1047         shr $6, %esi              /* Amount of 64-byte blocks to copy */
1048         jz Lend_sse               /* If none, stop */
1049         movups %xmm7, -16(%esp)   /* Save XMM register */
1050         xorps  %xmm7, %xmm7       /* Zero the XMM register */
1051         jmp Lloop_sse
1052         .align align_16byte
1053 Lloop_sse:
1054
1055         /* Copy the 16 zeroes from xmm7 to memory, 4 times. MOVNTDQ is the
1056          * non-caching double-quadword moving variant, i.e. the memory areas
1057          * we're touching are not fetched into the L1 cache, since we're just
1058          * going to overwrite the memory soon anyway.
1059          */
1060         movntdq %xmm7, 0(%edi)
1061         movntdq %xmm7, 16(%edi)
1062         movntdq %xmm7, 32(%edi)
1063         movntdq %xmm7, 48(%edi)
1064  
1065         add $64, %edi /* Advance pointer */
1066         dec %esi      /* Decrement 64-byte block count */
1067         jnz Lloop_sse
1068         movups -16(%esp), %xmm7 /* Restore the XMM register */
1069         sfence        /* Ensure that weakly ordered writes are flushed. */
1070 Lend_sse:
1071         mov 12(%esp), %esi      /* Parameter: start address */
1072         prefetcht0 0(%esi)      /* Prefetch the start of the block into cache,
1073                                  * since it's likely to be used immediately. */
1074         pop %edi      /* Restore temp registers */
1075         pop %esi
1076         ret
1077         SIZE(GNAME(fast_bzero_sse))
1078                 
1079 \f
1080         .text
1081         .align  align_8byte,0x90
1082         .globl GNAME(fast_bzero_base)
1083         TYPE(GNAME(fast_bzero_base))
1084         
1085 GNAME(fast_bzero_base):
1086         /* A fast routine for zero-filling blocks of memory that are
1087          * guaranteed to start and end at a 4096-byte aligned address.
1088          */        
1089         push %eax                 /* Save temporary registers */
1090         push %ecx
1091         push %edi
1092         mov 20(%esp), %ecx        /* Parameter: amount of bytes to fill */
1093         mov 16(%esp), %edi        /* Parameter: start address */
1094         xor %eax, %eax            /* Zero EAX */
1095         shr $2, %ecx              /* Amount of 4-byte blocks to copy */
1096         jz  Lend_base
1097         cld                       /* Set direction of STOSL to increment */
1098
1099         rep
1100         stosl                     /* Store EAX to *EDI, ECX times, incrementing
1101                                    * EDI by 4 after each store */
1102         
1103 Lend_base:        
1104         pop %edi                  /* Restore temp registers */
1105         pop %ecx
1106         pop %eax
1107         ret
1108         SIZE(GNAME(fast_bzero_base))
1109         
1110 \f       
1111         END()
1112