source: branches/working-0711/ccl/lisp-kernel/x86-macros.s @ 8040

Last change on this file since 8040 was 8040, checked in by gb, 12 years ago

Set save_rbp slot of newly-created tsp frames.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.2 KB
Line 
1/*   Copyright (C) 2005 Clozure Associates  */
2/*   This file is part of OpenMCL.    */
3
4/*   OpenMCL is licensed under the terms of the Lisp Lesser GNU Public  */
5/*   License , known as the LLGPL and distributed with OpenMCL as the  */
6/*   file "LICENSE".  The LLGPL consists of a preamble and the LGPL,  */
7/*   which is distributed with OpenMCL as the file "LGPL".  Where these  */
8/*   conflict, the preamble takes precedence.    */
9
10/*   OpenMCL is referenced in the preamble as the "LIBRARY."  */
11
12/*   The LLGPL is also available online at  */
13/*   http://opensource.franz.com/preamble.html  */
14
15
16/* Try to make macros follow GAS/ATT conventions, where source precedes  */
17/* destination.  */
18
19define([lisp_global],[lisp_globals.$1])
20                                       
21define([ref_global],[
22        mov lisp_global($1),$2
23])
24
25define([set_global],[
26        mov $1,lisp_global($2)
27])
28
29define([ref_nrs_value],[
30        mov nrs.$1+symbol.vcell,$2
31])
32       
33define([set_nrs_value],[
34        mov $1,nrs.$2+symbol.vcell
35])
36                                                       
37define([unbox_fixnum],[
38        mov $1,$2
39        sar [$]fixnumshift,$2
40])
41
42define([box_fixnum],[
43        imulq [$]fixnumone,$1,$2
44])     
45
46
47/* box_fixnum, with no effect on flags */
48define([box_fixnum_no_flags],[
49        leaq (,$1,8),$2
50])
51                               
52define([save_node_regs],[
53        push %arg_z
54        push %arg_y
55        push %arg_x
56        push %temp0
57        push %temp1
58        push %temp2
59        push %save0
60        push %save1
61        push %save2
62        push %save3
63        push %ra0
64        push %fn
65])
66
67/* This needs to be done before we transition back to the lisp stack  */
68/* from the foreign stack.   */
69               
70define([zero_node_regs],[
71        xor %fn,%fn
72        mov %fn,%ra0
73        mov %fn,%save3
74        mov %fn,%save2
75        mov %fn,%save1
76        mov %fn,%save0
77        mov %fn,%temp2
78        mov %fn,%temp1
79        mov %fn,%temp0
80        mov %fn,%arg_x
81        mov %fn,%arg_y
82        mov %fn,arg_z
83])     
84define([restore_node_regs],[
85        pop %fn
86        pop %ra0
87        pop %save3
88        pop %save2
89        pop %save1
90        pop %save0
91        pop %temp2
92        pop %temp1
93        pop %temp0
94        pop %arg_x
95        pop %arg_y
96        pop %arg_z
97])     
98
99/* Zero $3 bytes worth of dnodes, starting at offset $2 relative  */
100/* to the base register $1.  */
101
102
103ifdef([DarwinAssembler],[
104        .macro zero_dnodes
105        .if $2
106        movapd %fpzero,$1($0)
107        zero_dnodes $0,$1+dnode_size,$2-dnode_size
108        .endif
109        .endmacro
110],[
111        .macro zero_dnodes base,disp,nbytes
112        .ifgt \nbytes
113        movapd %fpzero,\disp(\base)
114        zero_dnodes \base,"\disp+dnode_size","\nbytes-dnode_size"
115        .endif
116        .endm
117])     
118
119
120/* Allocate $1+dnode_size zeroed bytes on the tstack, using $2 as a temp  */
121/* reg.  */
122       
123define([TSP_Alloc_Fixed],[
124        define([TSP_Alloc_Size],[((($1+node_size) & ~(dnode_size-1))+dnode_size)])
125        subq [$]TSP_Alloc_Size,%rcontext:tcr.next_tsp
126        movq %rcontext:tcr.save_tsp,%stack_temp
127        movq %rcontext:tcr.next_tsp,$2
128        zero_dnodes $2,0,TSP_Alloc_Size
129        movq %stack_temp,($2)
130        movq %rbp,tsp_frame.save_rbp($2)
131        movq $2,%rcontext:tcr.save_tsp
132        undefine([TSP_Alloc_Size])
133])
134
135/* $1 = size (dnode-aligned, including tsp overhead, $2 scratch.  */
136/* Modifies both $1 and $2; on exit, $2 = new_tsp+tsp_overhead, $1 = old tsp  */
137       
138define([TSP_Alloc_Var],[
139        new_macro_labels()
140        subq $1,%rcontext:tcr.next_tsp
141        movq %rcontext:tcr.save_tsp,%stack_temp
142        movq %rcontext:tcr.next_tsp,$2
143        jmp macro_label(test)
144macro_label(loop):
145        movapd %fpzero,0($2)
146        addq $dnode_size,$2
147macro_label(test):     
148        subq $dnode_size,$1
149        jge macro_label(loop)
150        movq %rcontext:tcr.next_tsp,$2
151        movd %stack_temp,$1
152        movq $1,($2)
153        movq %rbp,tsp_frame.save_rbp($2)
154        movq $2,%rcontext:tcr.save_tsp
155        addq $dnode_size,$2
156])
157       
158       
159
160define([Allocate_Catch_Frame],[
161        TSP_Alloc_Fixed(catch_frame.size,$1)
162        movq [$](catch_frame.element_count<<subtag_shift)|subtag_catch_frame,dnode_size($1)
163        addq [$]dnode_size+fulltag_misc,$1
164])
165
166/* %arg_z = tag,  %xfn = pc, $1 = mvflag          */
167       
168define([Make_Catch],[
169        Allocate_Catch_Frame(%imm2)
170        movq %rcontext:tcr.catch_top,%imm0
171        movq %rcontext:tcr.db_link,%imm1
172        movq %arg_z,catch_frame.catch_tag(%imm2)
173        movq %imm0,catch_frame.link(%imm2)
174        movq [$]$1,catch_frame.mvflag(%imm2)
175        movq %rcontext:tcr.xframe,%imm0
176        movq %rsp,catch_frame.rsp(%imm2)
177        movq %rbp,catch_frame.rbp(%imm2)
178        movq %rcontext:tcr.foreign_sp,%stack_temp
179        movq %imm1,catch_frame.db_link(%imm2)
180        movq %save3,catch_frame._save3(%imm2)
181        movq %save2,catch_frame._save2(%imm2)
182        movq %save1,catch_frame._save1(%imm2)
183        movq %save0,catch_frame._save0(%imm2)
184        movq %imm0,catch_frame.xframe(%imm2)
185        movq %stack_temp,catch_frame.foreign_sp(%imm2)
186        movq %xfn,catch_frame.pc(%imm2)
187        movq %imm2,%rcontext:tcr.catch_top
188])     
189
190define([nMake_Catch],[
191        Allocate_Catch_Frame(%imm2)
192        movq %rcontext:tcr.catch_top,%imm0
193        movq %rcontext:tcr.db_link,%imm1
194        movq %arg_z,catch_frame.catch_tag(%imm2)
195        movq %imm0,catch_frame.link(%imm2)
196        lea node_size(%rsp),%imm0
197        movq [$]$1,catch_frame.mvflag(%imm2)
198        movq %imm0,catch_frame.rsp(%imm2)
199        movq %rcontext:tcr.xframe,%imm0
200        movq %rbp,catch_frame.rbp(%imm2)
201        movq %rcontext:tcr.foreign_sp,%stack_temp
202        movq %imm1,catch_frame.db_link(%imm2)
203        movq %save3,catch_frame._save3(%imm2)
204        movq %save2,catch_frame._save2(%imm2)
205        movq %save1,catch_frame._save1(%imm2)
206        movq %save0,catch_frame._save0(%imm2)
207        movq %imm0,catch_frame.xframe(%imm2)
208        movq %stack_temp,catch_frame.foreign_sp(%imm2)
209        movq %xfn,catch_frame.pc(%imm2)
210        movq %imm2,%rcontext:tcr.catch_top
211])     
212               
213       
214/* Consing can get interrupted (either by PROCESS-INTERRUPT or by GC  */
215/* activity in some other thread; if it's interrupted, the interrupting  */
216/* process needs to be able to determine what's going on well enough  */
217/* to be able to either back out of the attempt or finish the job.  */
218/* That requires that we use easily recogninized instruction sequences  */
219/* and follow certain conventions when consing (either in the kernel  */
220/* or in compiled code.)  (One of those conventions involves using  */
221/* %allocptr = %temp0 as a freepointer; when consing, %temp0 can't  */
222/* contain a live value.)  */
223/* Making a CONS cell is a little simpler than making a uvector.  */
224
225/* $1=new_car,$2=new_cdr,$3=dest   */
226define([Cons],[
227        new_macro_labels()
228/* The instructions where tcr.save_allocptr is tagged are difficult  */
229/* to interrupt; the interrupting code has to recognize and possibly  */
230/* emulate the instructions in between   */
231        subq $cons.size-fulltag_cons,%rcontext:tcr.save_allocptr
232        movq %rcontext:tcr.save_allocptr,%allocptr
233        rcmpq(%allocptr,%rcontext:tcr.save_allocbase)
234        jg macro_label(no_trap)
235        uuo_alloc()
236macro_label(no_trap):   
237        andb $~fulltagmask,%rcontext:tcr.save_allocptr
238/* Easy to interrupt now that tcr.save_allocptr isn't tagged as a cons    */
239        movq $2,cons.cdr(%allocptr)
240        movq $1,cons.car(%allocptr)
241        ifelse($3,[],[],[
242         movq %allocptr,$3
243        ])
244])
245
246/* The header has to be in %imm0, and the physical size in bytes has  */
247/*  to be in %imm1. We bash %imm1.   */
248
249define([Misc_Alloc],[
250        subq [$]fulltag_misc,%imm1
251        Misc_Alloc_Internal($1)
252])
253
254define([Misc_Alloc_Internal],[                 
255/* Here Be Monsters: we have to treat some/all of this instruction   */
256/* sequence atomically, as soon as tcr.save_allocptr becomes tagged.  */
257               
258        new_macro_labels()
259        subq %imm1,%rcontext:tcr.save_allocptr
260        movq %rcontext:tcr.save_allocptr,%allocptr
261        rcmpq(%allocptr,%rcontext:tcr.save_allocbase)
262        jg macro_label(no_trap)
263        uuo_alloc()
264macro_label(no_trap):   
265        movq %imm0,misc_header_offset(%allocptr)
266        andb $~fulltagmask,%rcontext:tcr.save_allocptr
267/* Now that tcr.save_allocptr is untagged, it's easier to be interrupted   */
268        ifelse($1,[],[],[
269         mov %allocptr,$1
270        ])
271])
272       
273define([Misc_Alloc_Fixed],[
274        movq [$]$2-fulltag_misc,%imm1
275        Misc_Alloc_Internal($1)
276])                                     
277
278define([vrefr],[
279        mov misc_data_offset+($3<<word_shift)($2),$1
280])     
281
282define([jump_fn],[
283        jmpq *%fn
284])
285                       
286define([jump_fname],[
287        mov symbol.fcell(%fname),%fn
288        jump_fn()
289])     
290       
291define([set_nargs],[
292        movw [$]$1<<fixnumshift,%nargs
293])
294
295/* $1 = ndigits.  Assumes 4-byte digits           */
296define([aligned_bignum_size],[((~(dnode_size-1)&(node_size+(dnode_size-1)+(4*$1))))])
297       
298
299define([_car],[
300        movq cons.car($1),$2
301])     
302
303define([_rplaca],[
304        movq $2,cons.car($1)
305])     
306               
307define([_cdr],[
308        movq cons.cdr($1),$2
309])
310
311define([_rplacd],[
312        movq $2,cons.cdr($1)
313])     
314               
315       
316       
317define([tra],[
318        .p2align 3
319        ifelse($2,[],[
320        .long 0
321        ],[
322        .long $1-$2
323        ])
324$1:     
325])
326                               
327define([do_funcall],[
328        new_macro_labels()
329        movb %temp0_b,%imm0_b
330        andb $fulltagmask,%imm0_b
331        cmpb $fulltag_symbol,%imm0_b
332        /* %fname == %temp0   */
333        cmovgq %temp0,%fn
334        jl macro_label(bad)
335        cmoveq symbol.fcell(%fname),%fn
336        jmp *%fn
337macro_label(bad):               
338        __(uuo_error_not_callable)
339])
340
341define([getvheader],[
342        movq misc_header_offset($1),$2
343])
344
345/* "Size" is unboxed element-count.  $1 (header) and $2 (dest) should  */
346/*    both be immediate registers   */
347define([header_size],[
348        movq $1,$2
349        shr $num_subtag_bits,$2
350])
351
352/* $2 (length) is fixnum element-count.   */
353define([header_length],[
354        movq $~255,$2
355        andq $1,$2
356        shr $num_subtag_bits-fixnumshift,$2
357])
358
359/* $1 = vector, $2 = header, $3 = dest   */
360define([vector_size],[                                 
361        getvheader($1,$2)
362        header_size($2,$3)
363])
364
365/* $1 = vector, $2 = dest   */
366define([vector_length],[                                 
367        movq $~255,$2
368        andq misc_header_offset($1),$2
369        shr $num_subtag_bits-fixnumshift,$2
370])
371               
372/* GAS/ATT comparison arg order drives me nuts   */
373define([rcmpq],[
374        cmpq $2,$1
375])
376
377define([rcmpl],[
378        cmpl $2,$1
379])     
380
381define([rcmpw],[
382        cmpw $2,$1
383])     
384
385define([rcmpb],[
386        cmpb $2,$1
387])             
388
389
390define([condition_to_boolean],[
391        movl [$]t_value,$2_l
392        lea (-t_offset)($2),$3
393        cmov$1l $2_l,$3_l
394])
395
396define([compare_reg_to_nil],[
397        cmpb $fulltag_nil,$1_b
398])             
399       
400define([extract_lisptag],[
401        movzbl $1_b,$2_l
402        andb [$]tagmask,$2_b
403])
404
405                                                               
406define([extract_fulltag],[
407        movzbl $1_b,$2_l
408        andb [$]fulltagmask,$2_b
409])
410
411define([extract_subtag],[
412        movb misc_subtag_offset($1),$2
413])
414
415define([extract_typecode],[
416        new_macro_labels()
417        movzbl $1_b,$2_l
418        andb $tagmask,$2_b
419        cmpb $tag_misc,$2_b
420        jne macro_label(done)
421        movb misc_subtag_offset($1),$2_b
422macro_label(done):     
423])
424
425/* dnode_align(src,delta,dest)  */
426
427        define([dnode_align],[
428        lea ($2+(dnode_size-1))($1),$3
429        andb $~(dnode_size-1),$3_b
430])
431       
432define([push_argregs],[
433        new_macro_labels()
434        testw %nargs,%nargs
435        jz macro_label(done)
436        cmpw [$]2*node_size,%nargs
437        je macro_label(yz)
438        jb macro_label(z)
439        push %arg_x
440macro_label(yz):
441        push %arg_y
442macro_label(z):
443        push %arg_z
444macro_label(done):
445])     
446
447
448/* $1 = ndigits.  Assumes 4-byte digits           */
449define([aligned_bignum_size],[((~(dnode_size-1)&(node_size+(dnode_size-1)+(4*$1))))])
450
451define([discard_temp_frame],[
452        movq %rcontext:tcr.save_tsp,$1
453        movq ($1),$1
454        movq $1,%rcontext:tcr.save_tsp
455        movq $1,%rcontext:tcr.next_tsp
456
457])     
458
459define([check_pending_enabled_interrupt],[
460        btrq [$]63,%rcontext:tcr.interrupt_pending
461        jnc,pt $1
462        interrupt_now()
463])
464       
465/* $1 = scratch register, used to access tcr.tlb_pointer.  An interrupt  */
466/*   should be taken if interrupts are enabled and the most significant  */
467/*   bit of tcr.interrupt_pending is set.  If we take the interrupt, we  */
468/*   test and clear the pending bit.  */
469
470define([check_pending_interrupt],[
471        new_macro_labels()
472        movq %rcontext:tcr.tlb_pointer,$1
473        cmpq [$]0,INTERRUPT_LEVEL_BINDING_INDEX($1)
474        js,pt macro_label(done)
475        check_pending_enabled_interrupt(macro_label(done))
476macro_label(done):
477])
478
479/* This should only be called from a foreign context; it should be */
480/* assumed to bash all non-volatile C registers.  And of course it's */
481/* ugly, awful, non-portable, and slow.  %rdi should point to the */
482/* linear address that %gs should be made to address (tcr or pthread data) */
483                               
484ifdef([DARWIN_GS_HACK],[
485define([set_gs_base],[
486        ifelse($1,[],[
487        ],[
488        movq $1,%rdi
489        ])
490        movl [$]0x3000003,%eax
491        syscall
492])
493
494/* %gs addresses the tcr.  Make it address pthread data before running */
495/* foreign code */       
496       
497define([set_foreign_gs_base],[
498        set_gs_base([%rcontext:tcr.osid])
499])
500
501/* %gs addresses the tcr.  Get the linear address of the tcr and */
502/* copy it to $1 */
503
504define([save_tcr_linear],[
505        movq %rcontext:tcr.linear,$1
506]) 
507       
508])
509
510/*  On AMD hardware (at least), a one-byte RET instruction should be */
511/*  prefixed with a REP prefix if it (a) is the target of a  */
512/*  branch or (b) immediately follows a conditional branch not taken. */
513define([repret],[
514        .byte 0xf3
515         ret
516])
517                               
518       
Note: See TracBrowser for help on using the repository browser.