/* Copyright (C) 2010 Clozure Associates */ /* This file is part of Clozure CL. */ /* Clozure CL is licensed under the terms of the Lisp Lesser GNU Public */ /* License , known as the LLGPL and distributed with Clozure CL as the */ /* file "LICENSE". The LLGPL consists of a preamble and the LGPL, */ /* which is distributed with Clozure CL as the file "LGPL". Where these */ /* conflict, the preamble takes precedence. */ /* Clozure CL is referenced in the preamble as the "LIBRARY." */ /* The LLGPL is also available online at */ /* http://opensource.franz.com/preamble.html */ include(lisp.s) _beginfile .align 2 .arm .syntax unified local_label(start): define(`_spentry',`ifdef(`__func_name',`_endfn',`') _startfn(_SP$1) L__SP$1: .line __line__ ') define(`_endsubp',` _endfn(_SP$1) # __line__ ') define(`jump_builtin',` ref_nrs_value(fname,builtin_functions) set_nargs($2) vrefr(fname,fname,$1) jump_fname() ') /* Set the _function.entrypoint locative in nfn - which pointed here - to the address of the first instruction in the _function.codevector. This must be the first ARM subprim. */ _spentry(fix_nfn_entrypoint) __(build_lisp_frame(imm0)) __(vpush1(arg_z)) __(ldr arg_z,[nfn,#_function.codevector]) __(add lr,arg_z,#misc_data_offset) __(str lr,[nfn,#_function.entrypoint]) __(vpop1(arg_z)) __(restore_lisp_frame(imm0)) __(jump_nfn()) _spentry(builtin_plus) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(adds arg_z,arg_y,arg_z) __(bxvc lr) __(b _SPfix_overflow) 1: __(jump_builtin(_builtin_plus,2)) _spentry(builtin_minus) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(subs arg_z,arg_y,arg_z) __(bxvc lr) __(b _SPfix_overflow) 1: __(jump_builtin(_builtin_minus,2)) _spentry(builtin_times) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(unbox_fixnum(imm2,arg_z)) __(unbox_fixnum(imm0,arg_y)) __(smull imm0,imm1,imm2,imm0) __(b _SPmakes64) 1: __(jump_builtin(_builtin_times,2)) _spentry(builtin_div) __(jump_builtin(_builtin_div,2)) _spentry(builtin_eq) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(cmp arg_y,arg_z) __(mov arg_z,#nil_value) __(addeq arg_z,arg_z,#t_offset) __(bx lr) 1: __(jump_builtin(_builtin_eq,2)) _spentry(builtin_ne) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(cmp arg_y,arg_z) __(mov arg_z,#nil_value) __(addne arg_z,arg_z,#t_offset) __(bx lr) 1: __(jump_builtin(_builtin_ne,2)) _spentry(builtin_gt) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(cmp arg_y,arg_z) __(mov arg_z,#nil_value) __(addgt arg_z,arg_z,#t_offset) __(bx lr) 1: __(jump_builtin(_builtin_gt,2)) _spentry(builtin_ge) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(cmp arg_y,arg_z) __(mov arg_z,#nil_value) __(addge arg_z,arg_z,#t_offset) __(bx lr) 1: __(jump_builtin(_builtin_ge,2)) _spentry(builtin_lt) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(cmp arg_y,arg_z) __(mov arg_z,#nil_value) __(addlt arg_z,arg_z,#t_offset) __(bx lr) 1: __(jump_builtin(_builtin_lt,2)) _spentry(builtin_le) __(test_two_fixnums(arg_y,arg_z,imm0)) __(bne 1f) __(cmp arg_y,arg_z) __(mov arg_z,#nil_value) __(addle arg_z,arg_z,#t_offset) __(bx lr) 1: __(jump_builtin(_builtin_le,2)) _spentry(builtin_eql) 0: __(cmp arg_y,arg_z) __(beq 8f) __(extract_fulltag(imm0,arg_y)) __(extract_fulltag(imm1,arg_z)) __(cmp imm0,imm1) __(bne 9f) __(cmp imm0,#fulltag_misc) __(bne 9f) __(extract_subtag(imm0,arg_y)) __(extract_subtag(imm1,arg_z)) __(cmp imm0,imm1) __(bne 9f) __(cmp imm0,#subtag_macptr) __(cmpne imm0,#subtag_single_float) __(bne 1f) __(ldr imm0,[arg_y,#misc_data_offset]) __(ldr imm1,[arg_z,#misc_data_offset]) __(cmp imm0,imm1) __(mov arg_z,#nil_value) __(addeq arg_z,arg_z,#t_offset) __(bx lr) 1: __(cmp imm0,#subtag_double_float) __(bne 2f) __(ldr imm0,[arg_y,#misc_dfloat_offset]) __(ldr imm1,[arg_z,#misc_dfloat_offset]) __(cmp imm0,imm1) __(ldreq imm0,[arg_y,#misc_dfloat_offset+node_size]) __(ldreq imm1,[arg_z,#misc_dfloat_offset+node_size]) __(cmpeq imm0,imm1) __(mov arg_z,#nil_value) __(addeq arg_z,arg_z,#t_offset) __(bx lr) 2: __(cmp imm0,#subtag_ratio) __(cmpne imm0,#subtag_complex) __(bne 3f) __(ldr temp0,[arg_y,#ratio.denom]) __(ldr temp1,[arg_z,#ratio.denom]) __(stmdb vsp!,{temp0,temp1}) __(ldr arg_y,[arg_y,#ratio.numer]) __(ldr arg_z,[arg_z,#ratio.numer]) __(build_lisp_frame(imm0)) __(bl 0b) __(cmp arg_z,#nil_value) __(restore_lisp_frame(imm0)) __(ldmia vsp!,{arg_z,arg_y}) __(bne 0b) __(mov arg_z,#nil_value) __(bx lr) 3: __(cmp imm0,#subtag_bignum) __(bne 9f) __(getvheader(imm0,arg_y)) __(getvheader(imm1,arg_z)) __(cmp imm0,imm1) __(bne 9f) __(header_length(temp0,imm0)) __(mov imm2,#misc_data_offset) 4: __(ldr imm0,[arg_y,imm2]) __(ldr imm1,[arg_z,imm2]) __(cmp imm0,imm1) __(bne 9f) __(add imm2,imm2,#node_size) __(subs temp0,temp0,#fixnumone) __(bne 4b) 8: __(mov arg_z,#nil_value) __(add arg_z,arg_z,#t_offset) __(bx lr) 9: __(mov arg_z,#nil_value) __(bx lr) _spentry(builtin_length) __(extract_typecode(imm0,arg_z)) __(cmp imm0,#min_vector_subtag) __(ldreq arg_z,[arg_z,#vectorH.logsize]) __(bxeq lr) __(blo 1f) __(vector_length(arg_z,arg_z,imm0)) __(bx lr) 1: __(cmp imm0,#tag_list) __(bne 8f) __(mov temp2,#-1< nil. */ __(mov arg_z,#nil_value) __(rsb imm1,imm1,#0) __(sub imm1,imm1,#node_size) __(ldrlo arg_z,[imm0,imm1]) __(add vsp,imm0,#node_size) __(bx lr) /* Provide default (NIL) values for &optional arguments; imm0 is */ /* the (fixnum) upper limit on the total of required and &optional */ /* arguments. nargs is preserved, all arguments wind up on the */ /* vstack. */ _spentry(default_optional_args) __(vpush_argregs()) __(cmp nargs,imm0) __(mov arg_z,#nil_value) __(mov imm1,nargs) __(bxhs lr) 1: __(add imm1,imm1,#fixnum_one) __(cmp imm1,imm0) __(vpush1(arg_z)) __(bne 1b) __(bx lr) /* Indicate whether &optional arguments were actually supplied. nargs */ /* contains the actual arg count (minus the number of required args); */ /* imm0 contains the number of &optional args in the lambda list. */ /* Note that nargs may be > imm0 if &rest/&key is involved. */ _spentry(opt_supplied_p) __(mov imm1,#0) __(mov arg_x,#nil_value) __(add arg_x,arg_x,#t_offset) 1: /* (vpush (< imm1 nargs)) */ __(cmp imm1,nargs) __(add imm1,imm1,#fixnumone) __(subeq arg_x,arg_x,#t_offset) __(vpush1(arg_x)) __(cmp imm1,imm0) __(bne 1b) __(bx lr) /* Cons a list of length nargs and vpush it. */ /* Use this entry point to heap-cons a simple &rest arg. */ _spentry(heap_rest_arg) __(vpush_argregs()) __(movs imm1,nargs) __(mov arg_z,#nil_value) __(b 2f) 1: __(vpop1(arg_y)) __(Cons(arg_z,arg_y,arg_z)) __(subs imm1,imm1,#fixnum_one) 2: __(bne 1b) __(vpush1(arg_z)) __(bx lr) /* And this entry point when the argument registers haven't yet been */ /* vpushed (as is typically the case when required/&rest but no */ /* &optional/&key.) */ _spentry(req_heap_rest_arg) __(vpush_argregs()) __(subs imm1,nargs,imm0) __(mov arg_z,#nil_value) __(b 2f) 1: __(vpop1(arg_y)) __(Cons(arg_z,arg_y,arg_z)) __(subs imm1,imm1,#fixnum_one) 2: __(bgt 1b) __(vpush1(arg_z)) __(bx lr) /* Here where argregs already pushed */ _spentry(heap_cons_rest_arg) __(subs imm1,nargs,imm0) __(mov arg_z,#nil_value) __(b 2f) 1: __(vpop1(arg_y)) __(Cons(arg_z,arg_y,arg_z)) __(subs imm1,imm1,#fixnum_one) 2: __(bgt 1b) __(vpush1(arg_z)) __(bx lr) _spentry(check_fpu_exception) __(fmrx imm0,fpscr) __(mov imm2,imm0) __(ldr imm1,[rcontext,#tcr.lisp_fpscr]) __(ands imm0,imm0,imm1,lsr #8) __(bxeq lr) __(bic imm2,imm2,#0xff) __(fmxr fpscr,imm2) __(build_lisp_frame(imm2)) __(mov imm2,#34< 1 (and we know that it was < 3), it must have */ /* been 2. Set arg_x, then vpush the remaining args. */ __(cmp nargs,#fixnumone) __(ble local_label(set_y_z)) local_label(set_arg_x): __(subs imm0,imm0,#fixnum_one) __(sub imm1,imm1,#fixnum_one) __(ldr arg_x,[nfn,imm1]) __(add nargs,nargs,#fixnum_one) __(bne local_label(vpush_remaining)) __(b local_label(go)) /* Maybe set arg_y or arg_z, preceding args */ local_label(set_y_z): __(cmp nargs,#fixnumone) __(bne local_label(set_arg_z)) /* Set arg_y, maybe arg_x, preceding args */ local_label(set_arg_y): __(subs imm0,imm0,fixnum_one) __(sub imm1,imm1,#fixnum_one) __(ldr arg_y,[nfn,imm1]) __(add nargs,nargs,#fixnum_one) __(bne local_label(set_arg_x)) __(b local_label(go)) local_label(set_arg_z): __(subs imm0,imm0,#fixnum_one) __(sub imm1,imm1,#fixnum_one) __(ldr arg_z,[nfn,imm1]) __(add nargs,nargs,#fixnum_one) __(bne local_label(set_arg_y)) local_label(go): __(vrefr(nfn,nfn,2)) __(ldr pc,[nfn,#_function.entrypoint]) /* Everything up to the last arg has been vpushed, nargs is set to */ /* the (boxed) count of things already pushed. */ /* On exit, arg_x, arg_y, arg_z, and nargs are set as per a normal */ /* function call (this may require vpopping a few things.) */ /* ppc2-invoke-fn assumes that temp1 is preserved here. */ _spentry(spreadargz) __(extract_lisptag(imm1,arg_z)) __(cmp arg_z,#nil_value) __(mov imm0,#0) __(mov arg_y,arg_z) /* save in case of error */ __(beq 2f) 1: __(cmp imm1,#tag_list) __(bne 3f) __(_car(arg_x,arg_z)) __(_cdr(arg_z,arg_z)) __(cmp arg_z,#nil_value) __(extract_lisptag(imm1,arg_z)) __(vpush1(arg_x)) __(add imm0,imm0,#fixnum_one) __(bne 1b) 2: __(adds nargs,nargs,imm0) __(bxeq lr) __(vpop_argregs_nz) __(bx lr) /* Discard whatever's been vpushed already, complain. */ 3: __(add vsp,vsp,imm0) __(mov arg_z,arg_y) /* recover original arg_z */ __(mov arg_y,#XNOSPREAD) __(set_nargs(2)) __(b _SPksignalerr) /* Tail-recursively funcall temp0. */ /* Pretty much the same as the tcallsym* cases above. */ _spentry(tfuncallgen) __(cmp nargs,#nargregs<