source: branches/arm64/lisp-kernel/arm64-macros.s @ 15550

Last change on this file since 15550 was 15550, checked in by gb, 8 years ago

Move along, nothing to see here. Honest.
Some the files (those that aren't missing ...) are empty; there's very
little in the way of actual ARMv8 code here, and there'll need to be
a lot more before this is even worth talking about.

File size: 15.7 KB
Line 
1/*   Copyright (C) 2012 Clozure Associates */
2/*   This file is part of Clozure CL.  */
3
4/*   Clozure CL is licensed under the terms of the Lisp Lesser GNU Public */
5/*   License , known as the LLGPL and distributed with Clozure CL as the */
6/*   file "LICENSE".  The LLGPL consists of a preamble and the LGPL, */
7/*   which is distributed with Clozure CL as the file "LGPL".  Where these */
8/*   conflict, the preamble takes precedence.   */
9
10/*   Clozure CL 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
15define(`gprval',`substr($1,1)')
16define(`gpr32',``w'gprval($1)')
17define(`gpr64',``x'gprval($1)')                       
18
19/* dnode_align(dest,src,delta) */
20        define(`dnode_align',`
21        __(add $1,$2,#$3+(dnode_size-1))
22        __(bic $1,$1,#((1<<dnode_align_bits)-1))
23')
24
25define(`make_header',`(($1<<num_subtag_bits)|($2&subtag_mask))')
26       
27/* Load a 16-bit constant into $1 */
28define(`movc16',`
29        __(mov $1,#$2)
30        ')
31
32define(`_clrex',`
33        __(clrex)
34        ')       
35
36       
37define(`branch_if_not_fixnum',`
38        __(tbnz gpr32($1),#fixnum_clr_bit,$2)
39        ')
40
41define(`branch_if_fixnum',`
42        __(tbz gpr32($1),#fixnum_clr_bit,$2)
43        ')
44
45define(`branch_if_not_fixnum',`
46        __(tbnz gpr32($1),#fixnum_clr_bit,$2)
47        ')
48
49define(`branch_if_list',`
50        __(tbnz gpr32($1),#list_set_bit,$2)
51        ')
52
53define(`branch_if_not_list',`
54        __(tbz gpr32($1),#list_set_bit,$2)
55        ')                       
56               
57define(`branch_if_negative',`
58        __(tbnz $1,#63,$2)
59        ')
60       
61define(`lisp_boolean',`
62        __(csel $1,rt,rnil,$2)
63        ')
64               
65define(`test_two_fixnums',`
66        __(orr $3,$1,$2)
67        __(test_fixnum($3))
68        ')
69               
70define(`extract_fulltag',`
71        __(and $1,$2,#fulltagmask)
72        ')
73
74define(`extract_lisptag',`
75        __(and $1,$2,#tagmask)
76        ')
77
78define(`extract_lisptag_',`
79        __(ands $1,$1,#tagmask)
80        ')
81
82define(`extract_subtag',`
83        __(ldrb $1,[$2,#misc_subtag_offset])
84        ')
85
86                               
87define(`extract_lowbyte',`
88        __(and $1,$2,#((1<<num_subtag_bits)-1))
89        ')
90
91define(`extract_header',`
92        __(ldr $1,[$2,#misc_header_offset])
93        ')
94
95define(`extract_typecode',`
96        __(extract_lisptag($1,$2))
97        __(cmp $1,#tag_misc)
98        __(ldrbeq $1,[$2,#misc_subtag_offset])
99        ')
100
101define(`box_fixnum',`
102        __(lsl $1,$2, #fixnumshift)
103        ')
104
105define(`unbox_fixnum',`
106        __(asr $1,$2, #fixnumshift)
107        ')
108
109define(`unbox_character',`
110        __(lsr $1,$2, #charcode_shift)
111        ')
112               
113define(`loaddf',`
114        __(lfd $1,dfloat.value($2))')
115       
116define(`storedf',`
117        __(stfd $1,dfloat.value($2))
118        ')
119
120define(`push1',`
121        __(str $1,[$2,#-node_size]!)
122        ')
123       
124        /* Generally not a great idea. */
125define(`pop1',`
126        __(ldr $1,[$2],#node_size)
127        ')
128       
129define(`vpush1',`
130        __(push1($1,vsp))
131        ')
132       
133define(`vpop1',`
134        __(pop1($1,vsp))
135        ')
136       
137               
138define(`unlink',`
139        __(ldr($1,0($1)))
140 ')
141
142       
143define(`set_nargs',`
144        __(mov nargs,#($1)<<fixnumshift)
145        ')
146       
147define(`bitclr',`
148        __(rlwinm $1,$2,0,0x1f&((31-($3))+1),0x1f&((31-($3))-1))
149        ')
150       
151
152define(`vref32',`
153        __(ldr $1,[$2,#misc_data_offset+(($3)<<2)])
154        ')
155       
156define(`vref16',`/* dest,src,n*/
157        __(lhz $1,misc_data_offset+(($3)<<1)($2))
158        ')
159       
160define(`vrefr',`
161        __(vref32($1,$2,$3))
162        ')
163
164
165       
166                       
167define(`getvheader',`
168        __(ldr $1,[$2,#vector.header])
169        ')
170       
171       
172        /* "Length" is fixnum element count */
173define(`header_length',`
174        __(bic $1,$2,#subtag_mask)
175        __(mov $1,$1,lsr #num_subtag_bits-fixnumshift)
176        ')
177
178
179
180define(`vector_length',`
181        __(getvheader($3,$2))
182        __(header_length($1,$3))
183        ')
184
185       
186define(`ref_global',`
187        __(mov ifelse($3,`',$1,$3),#nil_value)
188        __(ldr $1,[ifelse($3,`',$1,$3),#lisp_globals.$2])
189')
190
191
192define(`ref_nrs_value',`
193        __(mov $1,#nil_value)
194        __(ldr $1,[$1,#((nrs.$2)+(symbol.vcell))])
195')
196
197define(`ref_nrs_function',`
198        __(mov $1,#nil_value)
199        __(ldr $1,[$1,#((nrs.$2)+(symbol.fcell))])
200')
201       
202define(`ref_nrs_symbol',`
203        __(movc16($3,nrs.$2))
204        __(add $1,$3,#nil_value)
205        ')
206       
207define(`set_nrs_value',`
208        __(str($1,((nrs.$2)+(symbol.vcell))(0)))
209')
210
211
212        /* vpop argregs - nargs is known to be non-zero */
213define(`vpop_argregs_nz',`
214        __(cmp nargs,#node_size*2)
215        __(vpop1(arg_z))
216        __(ldrhs arg_y,[vsp],#node_size)
217        __(ldrhi arg_x,[vsp],#node_size)
218        ')
219
220               
221        /* vpush argregs */
222define(`vpush_argregs',`
223        new_macro_labels()
224        __(cmp nargs,#0)
225        __(beq macro_label(done))
226        __(cmp nargs,#node_size*2)
227        __(strhi arg_x,[vsp,#-node_size]!)
228        __(strhs arg_y,[vsp,#-node_size]!)
229        __(str arg_z,[vsp,#-node_size]!)
230macro_label(done):
231')
232
233define(`vpush_all_argregs',`
234        __(stmdb vsp!,{arg_z,arg_y,arg_x})
235        ')
236
237define(`vpop_all_argregs',`
238        __(ldmia vsp!,{arg_z,arg_y,arg_x})
239        ')
240                       
241               
242
243/* $1 = value for lisp_frame.savevsp */               
244define(`build_lisp_frame',`
245        __(stp ifelse($1,`',vsp,$1),lr,[sp,#-(2*node_size)]!)
246')
247
248/* This has the odd side effect of loading lisp_frame_marker into
249   the arg/temp/imm reg $1.  I think that that's probably better
250   than adjusting sp and loading the other regs ; it'd be good
251   to say (at interrupt time) that there's either a lisp frame
252   on the stack or there isn't. */
253define(`restore_lisp_frame',`
254        __(ldm sp!,{$1,vsp,fn,lr})
255        ')
256
257define(`return_lisp_frame',`
258        __(ldm sp!,{$1,vsp,fn,pc})
259        ')
260       
261define(`discard_lisp_frame',`
262        __(add sp,sp,#lisp_frame.size)
263        ')
264       
265       
266define(`_car',`
267        __(ldr $1,[$2,#cons.car])
268')
269       
270define(`_cdr',`
271        __(ldr $1,[$2,#cons.cdr])
272        ')
273       
274define(`_rplaca',`
275        __(str $2,[$1,#cons.car])
276        ')
277       
278define(`_rplacd',`
279        __(str $2,[$1,#cons.cdr])
280        ')
281
282
283define(`trap_unless_lisptag_equal',`
284        new_macro_labels()
285        __(extract_lisptag($3,$1))
286        __(cmp $3,#$2)
287        __(beq macro_label(ok))
288        __(uuo_error_reg_not_lisptag(al,$3,$2))
289macro_label(ok):               
290')
291
292define(`trap_unless_list',`
293        new_macro_labels()
294        __(tbnz $1,#0,macro_label(ok))
295        __(uuo_error_reg_not_tag($1,tag_list))
296macro_label(ok):       
297')
298
299define(`trap_unless_fixnum',`
300        __(new_macro_labels())
301        __(test_fixnum($1))
302        __(beq macro_label(ok))
303        __(uuo_error_reg_not_lisptag(al,$1,tag_fixnum))
304macro_label(ok):       
305        ')
306               
307define(`trap_unless_fulltag_equal',`
308        new_macro_labels()
309        __(extract_fulltag($3,$1))
310        __(cmp $3,#$2)
311        __(beq macro_label(ok))
312        __(uuo_error_reg_not_fulltag(al,$1,$2))
313macro_label(ok):       
314')
315       
316define(`trap_unless_typecode_equal',`
317        new_macro_labels()
318        __(extract_typecode($3,$1))
319        __(cmp $3,#$2)
320        __(beq macro_label(ok))
321        __(uuo_error_reg_not_xtype(al,$2))
322macro_label(ok):               
323')
324       
325/* "jump" to the code-vector of the function in nfn. */
326define(`jump_nfn',`
327        __(ldr pc,[nfn,#_function.entrypoint])
328')
329
330/* "call the code-vector of the function in nfn. */
331define(`call_nfn',`
332        __(ldr lr,[nfn,#_function.entrypoint])
333        __(blx lr)
334')
335       
336
337/* "jump" to the function in fnames function cell. */
338define(`jump_fname',`
339        __(ldr nfn,[fname,#symbol.fcell])
340        __(jump_nfn())
341')
342
343/* call the function in fnames function cell. */
344define(`call_fname',`
345        __(ldr nfn,[fname,#symbol.fcell])
346        __(call_nfn())
347')
348
349define(`funcall_nfn',`
350        __(extract_typecode(imm0,nfn))
351        __(cmp imm0,#subtag_symbol)
352        __(moveq fname,nfn)
353        __(ldreq nfn,[fname,#symbol.fcell])
354        __(cmpne imm0,#subtag_function)
355        __(ldreq pc,[nfn,#_function.entrypoint])
356        __(uuo_error_not_callable(al,nfn))
357
358')
359
360/* Save the non-volatile FPRs (d8-d15) in a stack-allocated vector.
361   Clobber d7.  Note that d7/s14 wind up looking like denormalized
362   floats (we effectively load a vector header into d7.)
363*/       
364   
365define(`push_foreign_fprs',`
366        __(b macro_label(next))
367        .align 3
368macro_label(data):     
369        .long make_header(8,subtag_double_float_vector)
370        .long 0
371macro_label(next):
372        __(fldd d7,[pc,#-16])
373        __(fstmfdd sp!,{d7-d15})
374')
375
376/* Save the lisp non-volatile FPRs. These are exactly the same as the foreign
377   FPRs. */
378define(`push_lisp_fprs',`
379        new_macro_labels()
380        __(b macro_label(next))
381macro_label(data):     
382        .long make_header(8,subtag_double_float_vector)
383macro_label(next):
384        __(flds single_float_zero,[pc,#-12])
385        __(fstmfdd sp!,{d7-d15})
386        __(fcpys single_float_zero,s15)
387')
388       
389/* Pop the non-volatile FPRs (d8-d15) from the stack-consed vector
390   on top of the stack.  This loads the vector header
391   into d7 as a side-effect. */
392define(`pop_foreign_fprs',`
393        __(fldmfdd sp!,{d7-d15})
394')
395
396/* Pop the lisp non-volatile FPRs */       
397define(`pop_lisp_fprs',`
398        __(fldmfdd sp!,{d7-d15})
399        __(fcpys single_float_zero,s15)
400')
401
402/* Reload the non-volatile lisp FPRs (d8-d15) from the stack-consed vector
403   on top of the stack, leaving the vector in place.  d7 winds up with
404   a denormalized float in it, if anything cares. */
405define(`restore_lisp_fprs',`
406        __(fldmfdd $1,{d7-d15})
407        __(fcpys single_float_zero,s15)
408')               
409
410/* discard the stack-consed vector which contains a set of 8 non-volatile
411   FPRs. */
412define(`discard_lisp_fprs',`
413        __(add sp,sp,#9*8)
414')                       
415       
416define(`mkcatch',`
417        new_macro_labels()
418        __(push_lisp_fprs())
419        __(build_lisp_frame(imm0))
420        __(movc16(imm0,make_header(catch_frame.element_count,subtag_u32_vector)))
421        __(mov imm1,#catch_frame.element_count<<word_shift)
422        __(dnode_align(imm1,imm1,node_size))
423        __(stack_allocate_zeroed_ivector(imm0,imm1))
424        __(movc16(imm0,make_header(catch_frame.element_count,subtag_catch_frame)))
425        __(movs temp2,fn)
426        __(ldrne temp2,[temp2,_function.codevector])
427        __(ldr temp1,[rcontext,#tcr.last_lisp_frame])
428        __(ldr imm1,[rcontext,#tcr.catch_top])
429        /* imm2 is mvflag */
430        /* arg_z is tag */
431        __(ldr arg_x,[rcontext,#tcr.db_link])
432        __(ldr temp0,[rcontext,#tcr.xframe])
433        __(stmia sp,{imm0,imm1,imm2,arg_z,arg_x,temp0,temp1,temp2})
434        __(add imm0,sp,#fulltag_misc)
435        __(str imm0,[rcontext,#tcr.catch_top])
436        __(add lr,lr,#4)
437')     
438
439
440
441
442define(`stack_align',`((($1)+STACK_ALIGN_MASK)&~STACK_ALIGN_MASK)')
443
444define(`clear_alloc_tag',`
445        __(bic allocptr,allocptr,#fulltagmask)
446')
447
448define(`Cons',`
449        new_macro_labels()
450        __(add allocptr,allocptr,#-cons.size+fulltag_cons)
451        __(ldr allocbase,[rcontext,#tcr.save_allocbase])
452        __(cmp allocptr,allocbase)
453        __(bhi macro_label(ok))
454        __(uuo_alloc_trap(al))
455macro_label(ok):               
456        __(str $3,[allocptr,#cons.cdr])
457        __(str $2,[allocptr,#cons.car])
458        __(mov $1,allocptr)
459        __(clear_alloc_tag())
460')
461
462
463/* This is probably only used once or twice in the entire kernel, but */
464/* I wanted a place to describe the constraints on the mechanism. */
465
466/* Those constaints are (not surprisingly) similar to those which apply */
467/* to cons cells, except for the fact that the header (and any length */
468/* field that might describe large arrays) has to have been stored in */
469/* the object if the trap has succeeded on entry to the GC.  It follows */
470/* that storing the register containing the header must immediately */
471/* follow the allocation trap (and an auxiliary length register must */
472/* be stored immediately after the header.)  Successfully falling */
473/* through the trap must emulate any header initialization: it would */
474/* be a bad idea to have allocptr pointing to a zero header ... */
475
476
477
478/* Parameters: */
479
480/* $1 = dest reg */
481/* $2 = header.
482/* $3 = register containing size in bytes.  (We're going to subtract */
483/* fulltag_misc from this; do it in the macro body, rather than force the
484/* (1 ?) caller to do it. */
485
486
487define(`Misc_Alloc',`
488        new_macro_labels()
489        __(sub $3,$3,#fulltag_misc)
490        __(sub allocptr,allocptr,$3)
491        __(ldr allocbase,[rcontext,#tcr.save_allocbase])
492        __(cmp allocptr,allocbase)
493        __(bhi macro_label(ok))
494        __(uuo_alloc_trap(al))
495macro_label(ok):               
496        __(str $2,[allocptr,#misc_header_offset])
497        __(mov $1,allocptr)
498        __(clear_alloc_tag())
499')
500
501/*  Parameters $1, $2 as above; $3 = physical size constant. */
502define(`Misc_Alloc_Fixed',`
503        new_macro_labels()
504        __(add allocptr,allocptr,#(-$3)+fulltag_misc)
505        __(ldr allocbase,[rcontext,#tcr.save_allocbase])
506        __(cmp allocptr,allocbase)
507        __(bhi macro_label(ok))
508        __(uuo_alloc_trap(al))
509macro_label(ok):               
510        __(str $2,[allocptr,#misc_header_offset])
511        __(mov $1,allocptr)
512        __(clear_alloc_tag())
513')
514
515/* Stack-allocate an ivector; $1 = header, $0 = dnode-aligned
516   size in bytes. */
517define(`stack_allocate_ivector',`
518        __(str $1,[sp,-$2]!)
519        ')
520       
521                       
522/* Stack-allocate an ivector and zero its contents; caller may
523   change subtag of header after it's zeroed.
524   $1 = header (tagged as subtag_u32_vector until zeroed), $2 = dnode-
525   aligned size in bytes).  Both $1 and $2 are modified here. */
526define(`stack_allocate_zeroed_ivector',`
527       new_macro_labels()
528        __(str $1,[sp,-$2]!)
529        __(mov $1,#0)
530        __(add $2,sp,$2)
531        __(b macro_label(test))
532macro_label(loop):     
533        __(str $1,[$2])
534macro_label(test):                     
535        __(sub $2,#dnode_size)
536        __(cmp $2,sp)
537        __(str $1,[$2,#node_size])
538        __(bne macro_label(loop))
539        ')
540   
541
542define(`check_enabled_pending_interrupt',`
543        __(ldr $1,[rcontext,#tcr.interrupt_pending])
544        __(cmp $1,0)
545        __(ble $2)
546        __(uuo_interrupt_now(al))
547        ')
548       
549define(`check_pending_interrupt',`
550        new_macro_labels()
551        __(ldr $1,[rcontext,#tcr.tlb_pointer])
552        __(ldr $1,[$1,$INTERRUPT_LEVEL_BINDING_INDEX])
553        __(cmp $1,#0)
554        __(blt macro_label(done))
555        __(check_enabled_pending_interrupt($1,macro_label(done)))
556macro_label(done):
557')
558
559/* $1 = ndigits.  Assumes 4-byte digits */       
560define(`aligned_bignum_size',`((~(dnode_size-1)&(node_size+(dnode_size-1)+(4*$1))))')
561
562define(`suspend_now',`
563        __(uuo_suspend_now(al))
564')
565
566/* $3 points to a uvector header.  Set $1 to the first dnode-aligned address */
567/* beyond the uvector, using imm regs $1 and $2 as temporaries. */
568define(`skip_stack_vector',`
569        new_macro_labels()
570        __(ldr $1,[$3])
571        __(extract_fulltag($2,$1))       
572        __(cmp $2,#fulltag_immheader)
573        __(extract_lowbyte($2,$1))
574        __(mov $1,$1,lsr #num_subtag_bits)
575        __(moveq $1,$1,lsl #2)
576        __(beq macro_label(bytes))
577        __(cmp $2,#max_32_bit_ivector_subtag)
578        __(movle $1,$1,lsl #2)
579        __(ble macro_label(bytes))
580        __(cmp $2,#max_8_bit_ivector_subtag)
581        __(ble macro_label(bytes))
582        __(cmp $2,#max_16_bit_ivector_subtag)
583        __(movle $1,$1,lsl #1)
584        __(ble macro_label(bytes))
585        __(cmp $2,subtag_double_float_vector)
586        __(moveq $1,$1,lsl #3)
587        __(addeq $1,$1,#4)
588        __(beq macro_label(bytes))
589        __(add $1,$1,#7)
590        __(mov $1,$1,lsr #3)
591macro_label(bytes):     
592        __(add $1,$1,#node_size+(dnode_size-1))
593        __(bic $1,$1,#fulltagmask)
594        __(add $1,$1,$3)
595        ')
596
597/* This may need to be inlined.  $1=link, $2=saved sym idx, $3 = tlb, $4 = value */
598define(`do_unbind_to',`
599        __(ldr $1,[rcontext,#tcr.db_link])
600        __(ldr $3,[rcontext,#tcr.tlb_pointer])
6011:      __(ldr $2,[$1,#binding.sym])
602        __(ldr $4,[$1,#binding.val])
603        __(ldr $1,[$1,#binding.link])
604        __(cmp imm0,$1)
605        __(str $4,[$3,$2])
606        __(bne 1b)
607        __(str $1,[rcontext,#tcr.db_link])
608        ')               
609
Note: See TracBrowser for help on using the repository browser.