source: branches/arm/lisp-kernel/arm-macros.s @ 13632

Last change on this file since 13632 was 13632, checked in by gb, 10 years ago

Work-in-progress. (Just barely in progress.)

File size: 15.5 KB
Line 
1/*   Copyright (C) 2009 Clozure Associates */
2/*   Copyright (C) 1994-2001 Digitool, Inc */
3/*   This file is part of Clozure CL.  */
4
5/*   Clozure CL is licensed under the terms of the Lisp Lesser GNU Public */
6/*   License , known as the LLGPL and distributed with Clozure CL as the */
7/*   file "LICENSE".  The LLGPL consists of a preamble and the LGPL, */
8/*   which is distributed with Clozure CL as the file "LGPL".  Where these */
9/*   conflict, the preamble takes precedence.   */
10
11/*   Clozure CL is referenced in the preamble as the "LIBRARY." */
12
13/*   The LLGPL is also available online at */
14/*   http://opensource.franz.com/preamble.html */
15
16/* The assembler has to do the arithmetic here:  the expression */
17/*   may not be evaluable by m4. */
18
19
20
21
22/* dnode_align(dest,src,delta) */
23        define(`dnode_align',`
24        __(add $1,[$2,#(dnode_size-1)])
25        __(bic $1,$1,#((1<<dnode_align_bits)-1))
26')
27
28define(`extract_fulltag',`
29        __(and $1,$1,#((1<<ntagbits)-1))
30        ')
31
32define(`extract_lisptag',`
33        __(and $1,$1,#((1<<nlisptagbits)-1))
34        ')
35
36define(`extract_lisptag_',`
37        __(ands $1,$1,#((1<<nlisptagbits)-1))
38        ')
39
40define(`extract_subtag',`
41        __(ldrb $1,[$2,#misc_subtag_offset])
42        ')
43
44                               
45define(`extract_lowbyte',`
46        __(and $1,$2,#((1<<num_subtag_bits)-1))
47        ')
48
49define(`extract_header',`
50        __(ldr $1,[$2,#misc_header_offset])
51        ')
52
53define(`extract_typecode',`
54        __(extract_lisptag($1,$2))
55        __(cmp $1,#fulltag_misc)
56        __(ldrbeq $1,[$2,#misc_subtag_offset])
57        ')
58
59define(`box_fixnum',`
60        __(mov #1,$2 lsl #fixnumshift)
61        ')
62
63define(`unbox_fixnum',`
64        __(mov $1,$2 asr #fixnumshift)
65        ')
66
67define(`loaddf',`
68        __(lfd $1,dfloat.value($2))')
69       
70define(`storedf',`
71        __(stfd $1,dfloat.value($2))
72        ')
73
74define(`push',`
75        __(stru($1,-node_size($2)))
76        ')
77       
78        /* Generally not a great idea. */
79define(`pop',`
80        __(ldr($1,0($2)))
81        __(la $2,node_size($2))
82        ')
83       
84define(`vpush',`
85        __(push($1,vsp))
86        ')
87       
88define(`vpop',`
89        __(pop($1,vsp))
90        ')
91       
92               
93define(`unlink',`
94        __(ldr($1,0($1)))
95 ')
96
97       
98define(`set_nargs',`
99        __(lwi(nargs,($1)<<fixnumshift))
100        ')
101       
102define(`bitclr',`
103        __(rlwinm $1,$2,0,0x1f&((31-($3))+1),0x1f&((31-($3))-1))
104        ')
105       
106
107define(`vref32',`
108        __(lwz $1,misc_data_offset+(($3)<<2)($2))
109        ')
110       
111define(`vref16',`/* dest,src,n*/
112        __(lhz $1,misc_data_offset+(($3)<<1)($2))
113        ')
114       
115ifdef(`PPC64',`
116        define(`vref64',`
117        __(ld $1,misc_data_offset+(($3)<<3)($2))
118        ')
119
120        define(`vrefr',`
121        __(vref64($1,$2,$3))
122        ')
123',`
124        define(`vrefr',`
125        __(vref32($1,$2,$3))
126        ')
127')
128       
129                       
130define(`getvheader',`
131        __(ldr($1,vector.header($2)))
132        ')
133       
134        /* Size is unboxed element count */
135define(`header_size',`
136        __(srri($1,$2,num_subtag_bits))
137        ')
138       
139        /* "Length" is fixnum element count */
140define(`header_length',`
141ifdef(`PPC64',`
142        __(rldicr $1,$2,nbits_in_word-(num_subtag_bits-nfixnumtagbits),63-nfixnumtagbits)
143        __(clrldi $1,$1,(num_subtag_bits-nfixnumtagbits))
144        ',`               
145        __(rlwinm $1,$2,nbits_in_word-(num_subtag_bits-nfixnumtagbits),(num_subtag_bits-nfixnumtagbits),31-nfixnumtagbits)
146        ')
147')       
148
149
150define(`vector_size',`
151        __(getvheader(ifelse($3.`',$1,$3),$2))
152        __(header_size($1,ifelse($3.`',$1,$3)))
153        ')
154       
155define(`vector_length',`
156        __(getvheader($3,$2))
157        __(header_length($1,$3))
158        ')
159
160       
161define(`ref_global',`
162        __(ldr($1,lisp_globals.$2(0)))
163')
164
165define(`set_global',`
166        __(str($1,lisp_globals.$2(0)))
167')
168
169define(`ref_nrs_value',`
170        __(ldr($1,((nrs.$2)+(symbol.vcell))(0)))
171')
172       
173define(`set_nrs_value',`
174        __(str($1,((nrs.$2)+(symbol.vcell))(0)))
175')
176
177define(`extract_unsigned_byte_bits',`
178ifdef(`PPC64',`
179        __(rldicr $1,$2,64-fixnumshift,63-$3)
180',`               
181        __(rlwinm $1,$2,0,32-fixnumshift,31-($3+fixnumshift))
182')       
183')
184
185define(`extract_unsigned_byte_bits_',`
186ifdef(`PPC64',`
187        __(rldicr. $1,$2,64-fixnumshift,63-$3)
188',`               
189        __(rlwinm. $1,$2,0,32-fixnumshift,31-($3+fixnumshift))
190')       
191')
192
193        /* vpop argregs - nargs is known to be non-zero */
194define(`vpop_argregs_nz',`
195        new_macro_labels()
196        __(cmplri(cr1,nargs,node_size*2))
197        __(vpop(arg_z))
198        __(blt cr1,macro_label(l0))
199        __(vpop(arg_y))
200        __(bne cr1,macro_label(l0))
201        __(vpop(arg_x))
202macro_label(l0):')
203
204               
205        /* vpush argregs */
206define(`vpush_argregs',`
207        new_macro_labels()
208        __(cmplri(cr0,nargs,0))
209        __(cmplri(cr1,nargs,node_size*2))
210        __(beq cr0,macro_label(done))
211        __(blt cr1,macro_label(z))
212        __(beq cr1,macro_label(yz))
213        __(vpush(arg_x))
214macro_label(yz):
215        __(vpush(arg_y))
216macro_label(z):
217        __(vpush(arg_z))
218macro_label(done):
219')
220
221define(`create_lisp_frame',`
222        __(stru(sp,-lisp_frame.size(sp)))
223')
224
225               
226define(`build_lisp_frame',`
227        create_lisp_frame()
228        __(str(ifelse($1,`',fn,$1),lisp_frame.savefn(sp)))
229        __(str(ifelse($2,`',loc_pc,$2),lisp_frame.savelr(sp)))
230        __(str(ifelse($3,`',vsp,$3),lisp_frame.savevsp(sp)))
231')
232
233               
234define(`discard_lisp_frame',`
235        __(la sp,lisp_frame.size(sp))
236        ')
237       
238       
239define(`_car',`
240        __(ldr($1,cons.car($2)))
241')
242       
243define(`_cdr',`
244        __(ldr($1,cons.cdr($2)))
245        ')
246       
247define(`_rplaca',`
248        __(str($2,cons.car($1)))
249        ')
250       
251define(`_rplacd',`
252        __(str($2,cons.cdr($1)))
253        ')
254
255define(`vpush_saveregs',`
256        __(vpush(save7))
257        __(vpush(save6))
258        __(vpush(save5))
259        __(vpush(save4))
260        __(vpush(save3))
261        __(vpush(save2))
262        __(vpush(save1))
263        __(vpush(save0))
264        ')
265       
266define(`restore_saveregs',`
267        __(ldr(save0,node_size*0($1)))
268        __(ldr(save1,node_size*1($1)))
269        __(ldr(save2,node_size*2($1)))
270        __(ldr(save3,node_size*3($1)))
271        __(ldr(save4,node_size*4($1)))
272        __(ldr(save5,node_size*5($1)))
273        __(ldr(save6,node_size*6($1)))
274        __(ldr(save7,node_size*7($1)))
275')
276
277define(`vpop_saveregs',`
278        __(restore_saveregs(vsp))
279        __(la vsp,node_size*8(vsp))
280')
281
282define(`trap_unless_lisptag_equal',`
283        __(extract_lisptag($3,$1))
284        __(trnei($3,$2))
285')
286
287ifdef(`PPC64',`
288define(`trap_unless_list',`
289        new_macro_labels()
290        __(cmpdi ifelse($3,$3,cr0),$1,nil_value)
291        __(extract_fulltag($2,$1))
292        __(beq ifelse($3,$3,cr0),macro_label(is_list))
293        __(tdnei $2,fulltag_cons)
294macro_label(is_list):   
295
296')',`   
297define(`trap_unless_list',`
298        __(trap_unless_lisptag_equal($1,tag_list,$2))
299')
300')
301
302define(`trap_unless_fulltag_equal',`
303        __(extract_fulltag($3,$1))
304        __(trnei($3,$2))
305')
306       
307define(`trap_unless_typecode_equal',`
308        __(extract_typecode($3,$1))
309        __(trnei($3,$2))
310')
311       
312/* "jump" to the code-vector of the function in nfn. */
313define(`jump_nfn',`
314        __(ldr(temp0,_function.codevector(nfn)))
315        __(mtctr temp0)
316        __(bctr)
317')
318
319/* "call the code-vector of the function in nfn. */
320define(`call_nfn',`
321        __(ldr(temp0,_function.codevector(nfn)))
322        __(mtctr temp0)
323        __(bctrl)
324')
325       
326
327/* "jump" to the function in fnames function cell. */
328define(`jump_fname',`
329        __(ldr(nfn,symbol.fcell(fname)))
330        __(jump_nfn())
331')
332
333/* call the function in fnames function cell. */
334define(`call_fname',`
335        __(ldr(nfn,symbol.fcell(fname)))
336        __(call_nfn())
337')
338
339define(`do_funcall',`
340        new_macro_labels()
341        __(extract_fulltag(imm0,temp0))
342        __(cmpri(imm0,fulltag_misc))
343        __(mr nfn,temp0)
344        __(bne- macro_label(bad))
345        __(extract_subtag(imm0,temp0))
346        __(cmpri(imm0,subtag_function))
347        __(cmpri(cr1,imm0,subtag_symbol))
348        __(bne cr0,macro_label(_sym))
349        __(jump_nfn())
350macro_label(_sym):             
351        __(mr fname,temp0)
352        __(bne cr1,macro_label(bad))
353        __(jump_fname())
354macro_label(bad):
355        __(uuo_interr(error_cant_call,temp0))
356')     
357
358define(`mkcatch',`
359        __(mflr loc_pc)
360        __(ldr(imm0,tcr.catch_top(rcontext)))
361        __(lwz imm1,0(loc_pc)) /* a forward branch to the catch/unwind cleanup */
362        __(rlwinm imm1,imm1,0,6,29)     /* extract LI */
363        __(add loc_pc,loc_pc,imm1)
364        __(build_lisp_frame(fn,loc_pc,vsp))
365        __(sub loc_pc,loc_pc,imm1)
366        __(la loc_pc,4(loc_pc)) /* skip over the forward branch */
367        __(mtlr loc_pc)
368        __(lwi(imm4,(catch_frame.element_count<<num_subtag_bits)|subtag_catch_frame))
369        __(ldr(imm3,tcr.xframe(rcontext)))
370        __(ldr(imm1,tcr.db_link(rcontext)))
371        __(TSP_Alloc_Fixed_Unboxed(catch_frame.size))
372        __(la nargs,tsp_frame.data_offset+fulltag_misc(tsp))
373        __(str(imm4,catch_frame.header(nargs)))
374        __(str(arg_z,catch_frame.catch_tag(nargs)))
375        __(str(imm0,catch_frame.link(nargs)))
376        __(str(imm2,catch_frame.mvflag(nargs)))
377        __(str(sp,catch_frame.csp(nargs)))
378        __(str(imm1,catch_frame.db_link(nargs)))
379        __(str(first_nvr,catch_frame.regs+0*node_size(nargs)))
380        __(str(second_nvr,catch_frame.regs+1*node_size(nargs)))
381        __(str(third_nvr,catch_frame.regs+2*node_size(nargs)))
382        __(str(fourth_nvr,catch_frame.regs+3*node_size(nargs)))
383        __(str(fifth_nvr,catch_frame.regs+4*node_size(nargs)))
384        __(str(sixth_nvr,catch_frame.regs+5*node_size(nargs)))
385        __(str(seventh_nvr,catch_frame.regs+6*node_size(nargs)))
386        __(str(eighth_nvr,catch_frame.regs+7*node_size(nargs)))
387        __(str(imm3,catch_frame.xframe(nargs)))
388        __(str(rzero,catch_frame.tsp_segment(nargs)))
389        __(Set_TSP_Frame_Boxed())
390        __(str(nargs,tcr.catch_top(rcontext)))
391        __(li nargs,0)
392
393')     
394
395define(`restore_catch_nvrs',`
396        __(ldr(first_nvr,catch_frame.regs+(node_size*0)($1)))
397        __(ldr(second_nvr,catch_frame.regs+(node_size*1)($1)))
398        __(ldr(third_nvr,catch_frame.regs+(node_size*2)($1)))
399        __(ldr(fourth_nvr,catch_frame.regs+(node_size*3)($1)))
400        __(ldr(fifth_nvr,catch_frame.regs+(node_size*4)($1)))
401        __(ldr(sixth_nvr,catch_frame.regs+(node_size*5)($1)))
402        __(ldr(seventh_nvr,catch_frame.regs+(node_size*6)($1)))
403        __(ldr(eighth_nvr,catch_frame.regs+(node_size*7)($1)))
404')               
405
406define(`DCBZL',`
407        __(.long (31<<26)+(1<<21)+($1<<16)+($2<<11)+(1014<<1))
408')
409       
410define(`check_stack_alignment',`
411        new_macro_labels()
412        __(andi. $1,sp,STACK_ALIGN_MASK)
413        __(beq+ macro_label(stack_ok))
414        __(.long 0)
415macro_label(stack_ok):
416')
417
418define(`stack_align',`((($1)+STACK_ALIGN_MASK)&~STACK_ALIGN_MASK)')
419
420define(`clear_alloc_tag',`
421        __(clrrri(allocptr,allocptr,ntagbits))
422')
423
424/* If the GC interrupts the current thread (after the trap), it needs */
425/*   to ensure that the cons cell that's been "reserved" stays reserved */
426/*   (e.g. the tagged allocptr has to be treated as a node.)  If that */
427/*   reserved cons cell gets tenured, the car and cdr are of a generation */
428/*   that's at least as old (so memoization isn't an issue.) */
429
430/*   More generally, if the GC interrupts a thread when allocptr is */
431/*   tagged as a cons: */
432
433/*    a) if the trap hasn't been taken (yet), the GC should force the */
434/*       thread to resume in such a way that the trap will be taken ; */
435/*       the segment allocator should worry about allocating the object. */
436
437/*    b) If the trap has been taken, allocptr is treated as a node as */
438/*       described above.  Allocbase is made to point to the base of the */
439/*       cons cell, so that the thread's next allocation attempt will */
440/*       invoke the segment allocator. */
441       
442define(`Cons',`
443        __(la allocptr,(-cons.size+fulltag_cons)(allocptr))
444        __(alloc_trap())
445        __(str($3,cons.cdr(allocptr)))
446        __(str($2,cons.car(allocptr)))
447        __(mr $1,allocptr)
448        __(clear_alloc_tag())
449')
450
451
452/* This is probably only used once or twice in the entire kernel, but */
453/* I wanted a place to describe the constraints on the mechanism. */
454
455/* Those constaints are (not surprisingly) similar to those which apply */
456/* to cons cells, except for the fact that the header (and any length */
457/* field that might describe large arrays) has to have been stored in */
458/* the object if the trap has succeeded on entry to the GC.  It follows */
459/* that storing the register containing the header must immediately */
460/* follow the allocation trap (and an auxiliary length register must */
461/* be stored immediately after the header.)  Successfully falling */
462/* through the trap must emulate any header initialization: it would */
463/* be a bad idea to have allocptr pointing to a zero header ... */
464
465
466
467/* Parameters: */
468
469/* $1 = dest reg */
470/* $2 = header.  (For now, assume that this always encodes length ; */
471/* that may change with "large vector" support.) */
472/* $3 = register containing size in bytes.  (We're going to subtract */
473/* fulltag_misc from this; do it in the macro body, rather than force the
474/* (1 ?) caller to do it. */
475
476
477define(`Misc_Alloc',`
478        __(la $3,-fulltag_misc($3))
479        __(sub allocptr,allocptr,$3)
480        __(alloc_trap())
481        __(str($2,misc_header_offset(allocptr)))
482        __(mr $1,allocptr)
483        __(clear_alloc_tag())
484')
485
486/*  Parameters $1, $2 as above; $3 = physical size constant. */
487define(`Misc_Alloc_Fixed',`
488        __(la allocptr,(-$3)+fulltag_misc(allocptr))
489        __(alloc_trap())
490        __(str($2,misc_header_offset(allocptr)))
491        __(mr $1,allocptr)
492        __(clear_alloc_tag())
493')
494
495
496/*  Zero $3 bytes worth of doublewords, starting at offset $2 relative */
497/* to the base register $1. */
498
499
500ifdef(`DARWIN',`
501        .macro zero_doublewords
502        .if $2
503        stfd fp_zero,$1($0)
504        zero_doublewords $0,$1+8,$2-8
505        .endif
506        .endmacro
507')
508
509ifdef(`LINUX',`
510        .macro zero_doublewords base,disp,nbytes
511        .if \nbytes
512        stfd fp_zero,\disp(\base)
513        zero_doublewords \base,\disp+8,\nbytes-8
514        .endif
515        .endm
516')     
517
518define(`Set_TSP_Frame_Unboxed',`
519        __(str(tsp,tsp_frame.type(tsp)))
520')
521
522define(`Set_TSP_Frame_Boxed',`
523        __(str(rzero,tsp_frame.type(tsp)))
524')
525               
526/* A newly allocated TSP frame is always "raw" (has non-zero type, indicating */
527/* that it doesn't contain tagged data. */
528
529define(`TSP_Alloc_Fixed_Unboxed',`
530        __(stru(tsp,-($1+tsp_frame.data_offset)(tsp)))
531        __(Set_TSP_Frame_Unboxed())
532')
533
534define(`TSP_Alloc_Fixed_Unboxed_Zeroed',`
535        __(TSP_Alloc_Fixed_Unboxed($1))
536        __(zero_doublewords tsp,tsp_frame.fixed_overhead,$1)
537')
538
539define(`TSP_Alloc_Fixed_Boxed',`
540        __(TSP_Alloc_Fixed_Unboxed_Zeroed($1))
541        __(Set_TSP_Frame_Boxed())
542')
543
544
545       
546       
547
548/* This assumes that the backpointer points  to the first byte beyond */
549/* each frame.  If we allow segmented tstacks, that constraint might */
550/* complicate  their implementation. */
551/* We don't need to know the size of the frame (positive or negative, */
552/* with or without header).  $1 and $2 are temp registers, $3 is an */
553/* optional CR field. */
554
555
556/* Handle the general case, where the frame might be empty */
557define(`Zero_TSP_Frame',`
558        __(new_macro_labels())
559        __(la $1,tsp_frame.size-8(tsp))
560        __(ldr($2,tsp_frame.backlink(tsp)))
561        __(la $2,-8($2))
562        __(b macro_label(zero_tsp_test))
563macro_label(zero_tsp_loop):
564        __(stfdu fp_zero,8($1))
565macro_label(zero_tsp_test):     
566        __(cmpr(ifelse($3,`',`cr0',$3),$1,$2))
567        __(bne ifelse($3,`',`cr0',$3),macro_label(zero_tsp_loop))
568')
569
570/* Save some branching when we know that the frame can't be empty.*/
571define(`Zero_TSP_Frame_nz',`
572        new_macro_labels()
573        __(la $1,tsp_frame.size-8(tsp))
574        __(ldr($2,tsp_frame.backlink(tsp)))
575        __(la $2,-8($2))
576macro_label(zero_tsp_loop):
577        __(stfdu fp_zero,8($1))
578        __(cmpr(ifelse($3,`',`cr0',$3),$1,$2))
579        __(bne ifelse($3,`',`cr0',$3),macro_label(zero_tsp_loop))
580')
581       
582/* $1 = 8-byte-aligned size, positive.  $2 (optiional) set */
583/* to negated size. */
584define(`TSP_Alloc_Var_Unboxed',`
585        __(neg ifelse($2,`',$1,$2),$1)
586        __(strux(tsp,tsp,ifelse($2,`',$1,$2)))
587        __(Set_TSP_Frame_Unboxed())
588')
589
590define(`TSP_Alloc_Var_Boxed',`
591        __(TSP_Alloc_Var_Unboxed($1))
592        __(Zero_TSP_Frame($1,$2))
593        __(Set_TSP_Frame_Boxed())
594')             
595
596
597define(`TSP_Alloc_Var_Boxed_nz',`
598        __(TSP_Alloc_Var_Unboxed($1))
599        __(Zero_TSP_Frame_nz($1,$2))
600        __(Set_TSP_Frame_Boxed())
601')             
602
603define(`check_pending_interrupt',`
604        new_macro_labels()
605        __(ldr(nargs,tcr.tlb_pointer(rcontext)))
606        __(ldr(nargs,INTERRUPT_LEVEL_BINDING_INDEX(nargs)))
607        __(cmpri(ifelse($1,`',`cr0',$1),nargs,0))
608        __(blt ifelse($1,`',`cr0',$1),macro_label(done))
609        __(bgt ifelse($1,`',`cr0',$1),macro_label(trap))
610        __(ldr(nargs,tcr.interrupt_pending(rcontext)))
611macro_label(trap):
612        __(trgti(nargs,0))
613macro_label(done):
614')
615
616/* $1 = ndigits.  Assumes 4-byte digits */       
617define(`aligned_bignum_size',`((~(dnode_size-1)&(node_size+(dnode_size-1)+(4*$1))))')
618
619define(`suspend_now',`
620        __(uuo_interr(error_propagate_suspend,rzero))
621')
Note: See TracBrowser for help on using the repository browser.