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

Last change on this file since 9991 was 9991, checked in by gb, 11 years ago

Use () in macroexpansions.

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