;;; -*- Mode: Lisp; Package: CCL -*- ;;; ;;; Copyright (C) 2009 Clozure Associates ;;; Copyright (C) 1994-2001 Digitool, Inc ;;; 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 ;;; level-0;x86;x86-misc.lisp (in-package "CCL") ;;; Copy N bytes from pointer src, starting at byte offset src-offset, ;;; to ivector dest, starting at offset dest-offset. ;;; It's fine to leave this in lap. ;;; Depending on alignment, it might make sense to move more than ;;; a byte at a time. ;;; Does no arg checking of any kind. Really. (defppclapfunction %copy-ptr-to-ivector ((src (* 1 target::node-size) ) (src-byte-offset 0) (dest arg_x) (dest-byte-offset arg_y) (nbytes arg_z)) (let ((src-reg imm0) (src-byteptr imm1) (src-node-reg temp0) (dest-byteptr imm2) (val imm3) (node-temp temp1)) (cmpri cr0 nbytes 0) (ldr src-node-reg src vsp) (macptr-ptr src-reg src-node-reg) (ldr src-byteptr src-byte-offset vsp) (unbox-fixnum src-byteptr src-byteptr) (unbox-fixnum dest-byteptr dest-byte-offset) (la dest-byteptr target::misc-data-offset dest-byteptr) (b @test) @loop (subi nbytes nbytes '1) (cmpri cr0 nbytes '0) (lbzx val src-reg src-byteptr) (la src-byteptr 1 src-byteptr) (stbx val dest dest-byteptr) (la dest-byteptr 1 dest-byteptr) @test (bne cr0 @loop) (mr arg_z dest) (la vsp '2 vsp) (blr))) (defppclapfunction %copy-ivector-to-ptr ((src (* 1 target::node-size)) (src-byte-offset 0) (dest arg_x) (dest-byte-offset arg_y) (nbytes arg_z)) (ldr temp0 src vsp) (cmpri cr0 nbytes 0) (ldr imm0 src-byte-offset vsp) (unbox-fixnum imm0 imm0) (la imm0 target::misc-data-offset imm0) (unbox-fixnum imm2 dest-byte-offset) (ldr imm1 target::macptr.address dest) (b @test) @loop (subi nbytes nbytes '1) (cmpri cr0 nbytes 0) (lbzx imm3 temp0 imm0) (addi imm0 imm0 1) (stbx imm3 imm1 imm2) (addi imm2 imm2 1) @test (bne cr0 @loop) (mr arg_z dest) (la vsp '2 vsp) (blr)) #+ppc32-target (defppclapfunction %copy-ivector-to-ivector ((src 4) (src-byte-offset 0) (dest arg_x) (dest-byte-offset arg_y) (nbytes arg_z)) (lwz temp0 src vsp) (cmpwi cr0 nbytes 0) (cmpw cr2 temp0 dest) ; source and dest same? (rlwinm imm3 nbytes 0 (- 30 target::fixnum-shift) 31) (lwz imm0 src-byte-offset vsp) (rlwinm imm1 imm0 0 (- 30 target::fixnum-shift) 31) (or imm3 imm3 imm1) (unbox-fixnum imm0 imm0) (la imm0 target::misc-data-offset imm0) (unbox-fixnum imm2 dest-byte-offset) (rlwimi imm1 imm2 0 30 31) (or imm3 imm3 imm1) (cmpwi cr1 imm3 0) ; is everybody multiple of 4? (la imm2 target::misc-data-offset imm2) (beq cr2 @SisD) ; source and dest same @fwd (beq :cr1 @wtest) (b @test) @loop (subi nbytes nbytes '1) (cmpwi cr0 nbytes 0) (lbzx imm3 temp0 imm0) (addi imm0 imm0 1) (stbx imm3 dest imm2) (addi imm2 imm2 1) @test (bne cr0 @loop) (mr arg_z dest) (la vsp 8 vsp) (blr) @words ; source and dest different - words (subi nbytes nbytes '4) (cmpwi cr0 nbytes 0) (lwzx imm3 temp0 imm0) (addi imm0 imm0 4) (stwx imm3 dest imm2) (addi imm2 imm2 4) @wtest (bgt cr0 @words) @done (mr arg_z dest) (la vsp 8 vsp) (blr) @SisD (cmpw cr2 imm0 imm2) ; cmp src and dest (bgt cr2 @fwd) ;(B @bwd) ; Copy backwards when src & dest are the same and we're sliding down @bwd ; ok (unbox-fixnum imm3 nbytes) (add imm0 imm0 imm3) (add imm2 imm2 imm3) (b @test2) @loop2 (subi nbytes nbytes '1) (cmpwi cr0 nbytes 0) (subi imm0 imm0 1) (lbzx imm3 temp0 imm0) (subi imm2 imm2 1) (stbx imm3 dest imm2) @test2 (bne cr0 @loop2) (b @done)) #+ppc64-target (defppclapfunction %copy-ivector-to-ivector ((src-offset 8) (src-byte-offset-offset 0) (dest arg_x) (dest-byte-offset arg_y) (nbytes arg_z)) (let ((src temp0) (src-byte-offset imm0)) (subi nbytes nbytes '1) (ld src-byte-offset src-byte-offset-offset vsp) (cmpdi nbytes 0 ) (ld src src-offset vsp) (la vsp '2 vsp) (cmpd cr1 src dest) (cmpdi cr2 src-byte-offset dest-byte-offset) (unbox-fixnum src-byte-offset src-byte-offset) (unbox-fixnum imm1 dest-byte-offset) (la imm0 target::misc-data-offset src-byte-offset) (la imm1 target::misc-data-offset imm1) (bne cr1 @test) ;; Maybe overlap, or maybe nothing to do. (beq cr2 @done) ; same vectors, same offsets (blt cr2 @back) ; copy backwards, avoid overlap (b @test) @loop (subi nbytes nbytes '1) (lbzx imm3 src imm0) (cmpdi nbytes 0) (addi imm0 imm0 1) (stbx imm3 dest imm1) (addi imm1 imm1 1) @test (bge @loop) @done (mr arg_z dest) (blr) @back ;; nbytes was predecremented above (unbox-fixnum imm2 nbytes) (add imm0 imm2 imm0) (add imm1 imm2 imm1) (b @back-test) @back-loop (subi nbytes nbytes '1) (lbzx imm3 src imm0) (cmpdi nbytes 0) (subi imm0 imm0 1) (stbx imm3 dest imm1) (subi imm1 imm1 1) @back-test (bge @back-loop) (mr arg_z dest) (blr))) (defppclapfunction %copy-gvector-to-gvector ((src (* 1 target::node-size)) (src-element 0) (dest arg_x) (dest-element arg_y) (nelements arg_z)) (subi nelements nelements '1) (cmpri nelements 0) (ldr imm0 src-element vsp) (ldr temp0 src vsp) (la vsp '2 vsp) (cmpr cr1 temp0 dest) (cmpri cr2 src-element dest-element) (la imm0 target::misc-data-offset imm0) (la imm1 target::misc-data-offset dest-element) (bne cr1 @test) ;; Maybe overlap, or maybe nothing to do. (beq cr2 @done) ; same vectors, same offsets (blt cr2 @back) ; copy backwards, avoid overlap (b @test) @loop (subi nelements nelements '1) (cmpri nelements 0) (ldrx temp1 temp0 imm0) (addi imm0 imm0 '1) (strx temp1 dest imm1) (addi imm1 imm1 '1) @test (bge @loop) @done (mr arg_z dest) (blr) @back ;; We decremented NELEMENTS by 1 above. (add imm1 nelements imm1) (add imm0 nelements imm0) (b @back-test) @back-loop (subi nelements nelements '1) (cmpri nelements 0) (ldrx temp1 temp0 imm0) (subi imm0 imm0 '1) (strx temp1 dest imm1) (subi imm1 imm1 '1) @back-test (bge @back-loop) (mr arg_z dest) (blr)) #+ppc32-target (defppclapfunction %heap-bytes-allocated () (lwz imm2 target::tcr.last-allocptr ppc32::rcontext) (cmpwi cr1 imm2 0) (cmpwi allocptr -8) ;void_allocptr (lwz imm0 target::tcr.total-bytes-allocated-high ppc32::rcontext) (lwz imm1 target::tcr.total-bytes-allocated-low ppc32::rcontext) (sub imm2 imm2 allocptr) (beq cr1 @go) (beq @go) (addc imm1 imm1 imm2) (addze imm0 imm0) @go (ba .SPmakeu64)) #+ppc64-target (defppclapfunction %heap-bytes-allocated () (ld imm2 target::tcr.last-allocptr ppc64::rcontext) (cmpri cr1 imm2 0) (cmpri allocptr -16) ;void_allocptr (ld imm0 target::tcr.total-bytes-allocated-high ppc64::rcontext) (sub imm2 imm2 allocptr) (beq cr1 @go) (beq @go) (add imm0 imm0 imm2) @go (ba .SPmakeu64)) (defppclapfunction values () (:arglist (&rest values)) (vpush-argregs) (add temp0 nargs vsp) (ba .SPvalues)) ;; It would be nice if (%setf-macptr macptr (ash (the fixnum value) ash::fixnumshift)) ;; would do this inline. #+ppc-target (defppclapfunction %setf-macptr-to-object ((macptr arg_y) (object arg_z)) (check-nargs 2) (trap-unless-typecode= arg_y target::subtag-macptr) (str arg_z target::macptr.address arg_y) (blr)) (defppclapfunction %fixnum-from-macptr ((macptr arg_z)) (check-nargs 1) (trap-unless-typecode= arg_z target::subtag-macptr) (ldr imm0 target::macptr.address arg_z) (trap-unless-lisptag= imm0 target::tag-fixnum imm1) (mr arg_z imm0) (blr)) #+ppc32-target (defppclapfunction %%get-unsigned-longlong ((ptr arg_y) (offset arg_z)) (trap-unless-typecode= ptr ppc32::subtag-macptr) (macptr-ptr imm1 ptr) (unbox-fixnum imm2 offset) (add imm2 imm2 imm1) (lwz imm0 0 imm2) (lwz imm1 4 imm2) (ba .SPmakeu64)) #+ppc64-target (defppclapfunction %%get-unsigned-longlong ((ptr arg_y) (offset arg_z)) (trap-unless-typecode= ptr ppc64::subtag-macptr) (macptr-ptr imm1 ptr) (unbox-fixnum imm2 offset) (ldx imm0 imm2 imm1) (ba .SPmakeu64)) #+ppc32-target (defppclapfunction %%get-signed-longlong ((ptr arg_y) (offset arg_z)) (trap-unless-typecode= ptr ppc32::subtag-macptr) (macptr-ptr imm1 ptr) (unbox-fixnum imm2 offset) (add imm2 imm2 imm1) (lwz imm0 0 imm2) (lwz imm1 4 imm2) (ba .SPmakes64)) #+ppc64-target (defppclapfunction %%get-signed-longlong ((ptr arg_y) (offset arg_z)) (trap-unless-typecode= ptr ppc64::subtag-macptr) (macptr-ptr imm1 ptr) (unbox-fixnum imm2 offset) (ldx imm0 imm2 imm1) (ba .SPmakes64)) #+ppc32-target (defppclapfunction %%set-unsigned-longlong ((ptr arg_x) (offset arg_y) (val arg_z)) (save-lisp-context) (trap-unless-typecode= ptr ppc32::subtag-macptr) (bla .SPgetu64) (macptr-ptr imm2 ptr) (unbox-fixnum imm3 offset) (add imm2 imm3 imm2) (stw imm0 0 imm2) (stw imm1 4 imm2) (ba .SPpopj)) #+ppc64-target (defppclapfunction %%set-unsigned-longlong ((ptr arg_x) (offset arg_y) (val arg_z)) (save-lisp-context) (trap-unless-typecode= ptr ppc64::subtag-macptr) (bla .SPgetu64) (macptr-ptr imm2 ptr) (unbox-fixnum imm3 offset) (stdx imm0 imm3 imm2) (ba .SPpopj)) #+ppc32-target (defppclapfunction %%set-signed-longlong ((ptr arg_x) (offset arg_y) (val arg_z)) (save-lisp-context) (trap-unless-typecode= ptr ppc32::subtag-macptr) (bla .SPgets64) (macptr-ptr imm2 ptr) (unbox-fixnum imm3 offset) (add imm2 imm3 imm2) (stw imm0 0 imm2) (stw imm1 4 imm2) (ba .SPpopj)) #+ppc64-target (defppclapfunction %%set-signed-longlong ((ptr arg_x) (offset arg_y) (val arg_z)) (save-lisp-context) (trap-unless-typecode= ptr target::subtag-macptr) (bla .SPgets64) (macptr-ptr imm2 ptr) (unbox-fixnum imm3 offset) (stdx imm0 imm3 imm2) (ba .SPpopj)) (defppclapfunction interrupt-level () (ldr arg_z target::tcr.tlb-pointer target::rcontext) (ldr arg_z target::interrupt-level-binding-index arg_z) (blr)) (defppclapfunction disable-lisp-interrupts () (li imm0 '-1) (ldr imm1 target::tcr.tlb-pointer target::rcontext) (ldr arg_z target::interrupt-level-binding-index imm1) (str imm0 target::interrupt-level-binding-index imm1) (blr)) (defppclapfunction set-interrupt-level ((new arg_z)) (ldr imm1 target::tcr.tlb-pointer target::rcontext) (trap-unless-lisptag= new target::tag-fixnum imm0) (str new target::interrupt-level-binding-index imm1) (blr)) ;;; If we're restoring the interrupt level to 0 and an interrupt ;;; was pending, restore the level to 1 and zero the pending status. (defppclapfunction restore-interrupt-level ((old arg_z)) (cmpri :cr1 old 0) (ldr imm0 target::tcr.interrupt-pending target::rcontext) (ldr imm1 target::tcr.tlb-pointer target::rcontext) (cmpri :cr0 imm0 0) (bne :cr1 @store) (beq :cr0 @store) (str rzero target::tcr.interrupt-pending target::rcontext) (li old '1) @store (str old target::interrupt-level-binding-index imm1) (blr)) (defppclapfunction %current-tcr () (mr arg_z target::rcontext) (blr)) (defppclapfunction %tcr-toplevel-function ((tcr arg_z)) (check-nargs 1) (cmpr tcr target::rcontext) (mr imm0 vsp) (ldr temp0 target::tcr.vs-area tcr) (ldr imm1 target::area.high temp0) (beq @room) (ldr imm0 target::area.active temp0) @room (cmpr imm1 imm0) (li arg_z nil) (beqlr) (ldr arg_z (- target::node-size) imm1) (blr)) (defppclapfunction %set-tcr-toplevel-function ((tcr arg_y) (fun arg_z)) (check-nargs 2) (cmpr tcr target::rcontext) (mr imm0 vsp) (ldr temp0 target::tcr.vs-area tcr) (ldr imm1 target::area.high temp0) (beq @check-room) (ldr imm0 target::area.active temp0) @check-room (cmpr imm1 imm0) (push rzero imm1) (bne @have-room) (str imm1 target::area.active temp0) (str imm1 target::tcr.save-vsp tcr) @have-room (str fun 0 imm1) (blr)) ;;; This needs to be done out-of-line, to handle EGC memoization. (defppclapfunction %store-node-conditional ((offset 0) (object arg_x) (old arg_y) (new arg_z)) (ba .SPstore-node-conditional)) (defppclapfunction %store-immediate-conditional ((offset 0) (object arg_x) (old arg_y) (new arg_z)) (vpop temp0) (unbox-fixnum imm0 temp0) (let ((current temp1)) @again (lrarx current object imm0) (cmpr current old) (bne @lose) (strcx. new object imm0) (bne @again) (isync) (li arg_z (+ target::t-offset (target-nil-value))) (blr) @lose (li imm0 target::reservation-discharge) (strcx. rzero rzero imm0) (li arg_z nil) (blr))) (defppclapfunction set-%gcable-macptrs% ((ptr target::arg_z)) (li imm0 (+ (target-nil-value) (target::kernel-global gcable-pointers))) @again (lrarx arg_y rzero imm0) (str arg_y target::xmacptr.link ptr) (strcx. ptr rzero imm0) (bne @again) (isync) (blr)) ;;; Atomically increment or decrement the gc-inhibit-count kernel-global ;;; (It's decremented if it's currently negative, incremented otherwise.) (defppclapfunction %lock-gc-lock () (li imm0 (+ (target-nil-value) (target::kernel-global gc-inhibit-count))) @again (lrarx arg_y rzero imm0) (cmpri cr1 arg_y 0) (addi arg_z arg_y '1) (bge cr1 @store) (subi arg_z arg_y '1) @store (strcx. arg_z rzero imm0) (bne @again) ;; (isync) (blr)) ;;; Atomically decrement or increment the gc-inhibit-count kernel-global ;;; (It's incremented if it's currently negative, incremented otherwise.) ;;; If it's incremented from -1 to 0, try to GC (maybe just a little.) (defppclapfunction %unlock-gc-lock () ;; (sync) (li imm0 (+ (target-nil-value) (target::kernel-global gc-inhibit-count))) @again (lrarx arg_y rzero imm0) (cmpri cr1 arg_y -1) (subi arg_z arg_y '1) (bgt cr1 @store) (addi arg_z arg_y '1) @store (strcx. arg_z rzero imm0) (bne @again) (bnelr cr1) ;; The GC tried to run while it was inhibited. Unless something else ;; has just inhibited it, it should be possible to GC now. (li imm0 arch::gc-trap-function-immediate-gc) (trlgei allocptr 0) (blr)) (defppclapfunction %atomic-incf-node ((by arg_x) (node arg_y) (disp arg_z)) (check-nargs 3) (unbox-fixnum imm1 disp) @again (lrarx arg_z node imm1) (add arg_z arg_z by) (strcx. arg_z node imm1) (bne- @again) (isync) (blr)) (defppclapfunction %atomic-incf-ptr ((ptr arg_z)) (macptr-ptr imm1 ptr) @again (lrarx imm0 0 imm1) (addi imm0 imm0 1) (strcx. imm0 0 imm1) (bne @again) (isync) (box-fixnum arg_z imm0) (blr)) (defppclapfunction %atomic-incf-ptr-by ((ptr arg_y) (by arg_z)) (macptr-ptr imm1 ptr) (unbox-fixnum imm2 by) @again (lrarx imm0 0 imm1) (add imm0 imm0 imm2) (strcx. imm0 0 imm1) (bne @again) (isync) (box-fixnum arg_z imm0) (blr)) (defppclapfunction %atomic-decf-ptr ((ptr arg_z)) (macptr-ptr imm1 ptr) @again (lrarx imm0 0 imm1) (subi imm0 imm0 1) (strcx. imm0 0 imm1) (bne @again) (isync) (box-fixnum arg_z imm0) (blr)) (defppclapfunction %atomic-decf-ptr-if-positive ((ptr arg_z)) (macptr-ptr imm1 ptr) @again (lrarx imm0 0 imm1) (cmpri cr1 imm0 0) (subi imm0 imm0 1) (beq @done) (strcx. imm0 0 imm1) (bne @again) (isync) (box-fixnum arg_z imm0) (blr) @done (li imm1 target::reservation-discharge) (box-fixnum arg_z imm0) (strcx. rzero rzero imm1) (blr)) (defppclapfunction %atomic-swap-ptr ((ptr arg_y) (newval arg_z)) (sync) (macptr-ptr imm1 ptr) (unbox-fixnum imm2 arg_z) @again (lrarx imm0 0 imm1) (strcx. imm2 0 imm1) (bne @again) (isync) (box-fixnum arg_z imm0) (blr)) ;;; Try to store the fixnum NEWVAL at PTR, if and only if the old value ;;; was equal to OLDVAL. Return the old value (defppclapfunction %ptr-store-conditional ((ptr arg_x) (expected-oldval arg_y) (newval arg_z)) (macptr-ptr imm0 ptr) (unbox-fixnum imm1 expected-oldval) (unbox-fixnum imm2 newval) @again (lrarx imm3 0 imm0) (cmpr imm3 imm1) (bne- @done) (strcx. imm2 0 imm0) (bne- @again) (isync) (box-fixnum arg_z imm3) (blr) @done (li imm0 target::reservation-discharge) (box-fixnum arg_z imm3) (strcx. rzero 0 imm0) (blr)) (defppclapfunction %ptr-store-fixnum-conditional ((ptr arg_x) (expected-oldval arg_y) (newval arg_z)) (let ((address imm0) (actual-oldval imm1)) (macptr-ptr address ptr) @again (lrarx actual-oldval 0 address) (cmpr actual-oldval expected-oldval) (bne- @done) (strcx. newval 0 address) (bne- @again) (isync) (mr arg_z actual-oldval) (blr) @done (li address target::reservation-discharge) (mr arg_z actual-oldval) (strcx. rzero 0 address) (blr))) (defppclapfunction %macptr->dead-macptr ((macptr arg_z)) (check-nargs 1) (li imm0 target::subtag-dead-macptr) (stb imm0 target::misc-subtag-offset macptr) (blr)) (defppclapfunction %%apply-in-frame ((catch-count imm0) (srv temp0) (tsp-count imm0) (db-link imm0) (parent arg_x) (function arg_y) (arglist arg_z)) (check-nargs 7) ; Throw through catch-count catch frames (lwz imm0 12 vsp) ; catch-count (vpush parent) (vpush function) (vpush arglist) (bla .SPnthrowvalues) ; Pop tsp-count TSP frames (lwz tsp-count 16 vsp) (cmpi cr0 tsp-count 0) (b @test) @loop (subi tsp-count tsp-count '1) (cmpi cr0 tsp-count 0) (lwz tsp 0 tsp) @test (bne cr0 @loop) ; Pop dynamic bindings until we get to db-link (lwz imm0 12 vsp) ; db-link (lwz imm1 target::tcr.db-link target::rcontext) (cmp cr0 imm0 imm1) (beq cr0 @restore-regs) ; .SPunbind-to expects there to be something to do (bla .SPunbind-to) @restore-regs ; restore the saved registers from srv (lwz srv 20 vsp) @get0 (svref imm0 1 srv) (cmpwi cr0 imm0 (target-nil-value)) (beq @get1) (lwz save0 0 imm0) @get1 (svref imm0 2 srv) (cmpwi cr0 imm0 (target-nil-value)) (beq @get2) (lwz save1 0 imm0) @get2 (svref imm0 3 srv) (cmpwi cr0 imm0 (target-nil-value)) (beq @get3) (lwz save2 0 imm0) @get3 (svref imm0 4 srv) (cmpwi cr0 imm0 (target-nil-value)) (beq @get4) (lwz save3 0 imm0) @get4 (svref imm0 5 srv) (cmpwi cr0 imm0 (target-nil-value)) (beq @get5) (lwz save4 0 imm0) @get5 (svref imm0 6 srv) (cmpwi cr0 imm0 (target-nil-value)) (beq @get6) (lwz save5 0 imm0) @get6 (svref imm0 7 srv) (cmpwi cr0 imm0 (target-nil-value)) (beq @get7) (lwz save6 0 imm0) @get7 (svref imm0 8 srv) (cmpwi cr0 imm0 (target-nil-value)) (beq @got) (lwz save7 0 imm0) @got (vpop arg_z) ; arglist (vpop temp0) ; function (vpop parent) ; parent (extract-lisptag imm0 parent) (cmpi cr0 imm0 target::tag-fixnum) (if (:cr0 :ne) ; Parent is a fake-stack-frame. Make it real (progn (svref sp %fake-stack-frame.sp parent) (stwu sp (- target::lisp-frame.size) sp) (svref fn %fake-stack-frame.fn parent) (stw fn target::lisp-frame.savefn sp) (svref temp1 %fake-stack-frame.vsp parent) (stw temp1 target::lisp-frame.savevsp sp) (svref temp1 %fake-stack-frame.lr parent) (extract-lisptag imm0 temp1) (cmpi cr0 imm0 target::tag-fixnum) (if (:cr0 :ne) ;; must be a macptr encoding the actual link register (macptr-ptr loc-pc temp1) ;; Fixnum is offset from start of function vector (progn (svref temp2 0 fn) ; function vector (unbox-fixnum temp1 temp1) (add loc-pc temp2 temp1))) (stw loc-pc target::lisp-frame.savelr sp)) ;; Parent is a real stack frame (mr sp parent)) (set-nargs 0) (bla .SPspreadargz) (ba .SPtfuncallgen)) #+ppc32-target ;;; Easiest to do this in lap, to avoid consing bignums and/or ;;; multiple-value hair. ;;; Bang through code-vector until the end or a 0 (traceback table ;;; header) is found. Return high-half, low-half of last instruction ;;; and index where found. (defppclapfunction %code-vector-last-instruction ((cv arg_z)) (let ((previ imm0) (nexti imm1) (idx imm2) (offset imm3) (len imm4)) (vector-length len cv len) (li idx 0) (cmpw cr0 idx len) (li offset target::misc-data-offset) (li nexti 0) (b @test) @loop (mr previ nexti) (lwzx nexti cv offset) (cmpwi cr1 nexti 0) (addi idx idx '1) (cmpw cr0 idx len) (addi offset offset '1) (beq cr1 @done) @test (bne cr0 @loop) (mr previ nexti) @done (digit-h temp0 previ) (digit-l temp1 previ) (subi idx idx '1) (vpush temp0) (vpush temp1) (vpush idx) (set-nargs 3) (la temp0 '3 vsp) (ba .SPvalues))) #+ppc64-target (defun %code-vector-last-instruction (cv) (do* ((i 1 (1+ i)) (instr nil) (n (uvsize cv))) ((= i n) instr) (declare (fixnum i n)) (let* ((next (uvref cv i))) (declare (type (unsigned-byte 32) next)) (if (zerop next) (return instr) (setq instr next))))) (defppclapfunction %%save-application ((flags arg_y) (fd arg_z)) (unbox-fixnum imm0 flags) (ori imm0 imm0 arch::gc-trap-function-save-application) (unbox-fixnum imm1 fd) (trlgei allocptr 0) (blr)) (defppclapfunction %misc-address-fixnum ((misc-object arg_z)) (check-nargs 1) (la arg_z target::misc-data-offset misc-object) (blr)) #+ppc32-target (defppclapfunction fudge-heap-pointer ((ptr arg_x) (subtype arg_y) (len arg_z)) (check-nargs 3) (macptr-ptr imm1 ptr) ; address in macptr (addi imm0 imm1 9) ; 2 for delta + 7 for alignment (clrrwi imm0 imm0 3) ; Clear low three bits to align (subf imm1 imm1 imm0) ; imm1 = delta (sth imm1 -2 imm0) ; save delta halfword (unbox-fixnum imm1 subtype) ; subtype at low end of imm1 (rlwimi imm1 len (- target::num-subtag-bits target::fixnum-shift) 0 (- 31 target::num-subtag-bits)) (stw imm1 0 imm0) ; store subtype & length (addi arg_z imm0 target::fulltag-misc) ; tag it, return it (blr)) #+ppc64-target (defppclapfunction fudge-heap-pointer ((ptr arg_x) (subtype arg_y) (len arg_z)) (check-nargs 3) (macptr-ptr imm1 ptr) ; address in macptr (addi imm0 imm1 17) ; 2 for delta + 15 for alignment (clrrdi imm0 imm0 4) ; Clear low four bits to align (subf imm1 imm1 imm0) ; imm1 = delta (sth imm1 -2 imm0) ; save delta halfword (unbox-fixnum imm1 subtype) ; subtype at low end of imm1 (sldi imm2 len (- target::num-subtag-bits target::fixnum-shift)) (or imm1 imm2 imm1) (std imm1 0 imm0) ; store subtype & length (addi arg_z imm0 target::fulltag-misc) ; tag it, return it (blr)) (defppclapfunction %%make-disposable ((ptr arg_y) (vector arg_z)) (check-nargs 2) (subi imm0 vector target::fulltag-misc) ; imm0 is addr = vect less tag (lhz imm1 -2 imm0) ; get delta (sub imm0 imm0 imm1) ; vector addr (less tag) - delta is orig addr (str imm0 target::macptr.address ptr) (blr)) #+ppc32-target (defppclapfunction %vect-data-to-macptr ((vect arg_y) (ptr arg_z)) ;; put address of vect data in macptr. For all vector types ;; other than DOUBLE-FLOAT (or vectors thereof), the first byte ;; of data is at PPC32::MISC-DATA-OFFSET; for the double-float ;; types, it's at PPC32::MISC-DFLOAT-OFFSET. (extract-subtag imm0 vect) (cmpwi cr0 imm0 ppc32::subtag-double-float-vector) (cmpwi cr1 imm0 ppc32::subtag-double-float) (addi temp0 vect ppc32::misc-data-offset) (beq cr0 @dfloat) (beq cr1 @dfloat) (stw temp0 ppc32::macptr.address arg_z) (blr) @dfloat (addi temp0 vect ppc32::misc-dfloat-offset) (stw temp0 ppc32::macptr.address arg_z) (blr)) #+ppc64-target (defppclapfunction %vect-data-to-macptr ((vect arg_y) (ptr arg_z)) (la imm0 ppc64::misc-data-offset vect) (std imm0 ppc64::macptr.address ptr) (blr)) #+ppc32-target (defppclapfunction %ivector-from-macptr ((ptr arg_z)) (macptr-ptr imm0 ptr) (andi. imm1 imm0 target::node-size) (xori imm1 imm1 target::node-size) (addi imm0 imm0 (- target::fulltag-misc target::node-size)) (sub arg_z imm0 imm1) (blr)) #+ppc64-target (defppclapfunction %ivector-from-macptr ((ptr arg_z)) (macptr-ptr imm0 ptr) (addi arg_z imm0 (- target::fulltag-misc target::node-size)) (blr)) (defppclapfunction get-saved-register-values () (vpush save0) (vpush save1) (vpush save2) (vpush save3) (vpush save4) (vpush save5) (vpush save6) (vpush save7) (la temp0 (* 8 target::node-size) vsp) (set-nargs 8) (ba .SPvalues)) (defppclapfunction %current-db-link () (ldr arg_z target::tcr.db-link target::rcontext) (blr)) (defppclapfunction %no-thread-local-binding-marker () (li arg_z target::subtag-no-thread-local-binding) (blr)) (defppclapfunction pending-user-interrupt () (ref-global arg_z target::intflag) ;; If another signal happens now, it will get ignored, same as if it happened ;; before whatever signal is in arg_z. But then these are async signals, so ;; who can be sure it didn't actually happen just before... (set-global rzero target::intflag) (blr)) ;;; Should be called with interrupts disabled. (defppclapfunction %safe-get-ptr ((src arg_y) (dest arg_z)) (check-nargs 2) (macptr-ptr imm0 src) (str imm0 target::tcr.safe-ref-address target::rcontext) (ldr imm0 0 imm0) ; may fault (str imm0 target::macptr.address dest) (blr)) ;;; r13 contains thread context on Linux/Darwin PPC64. ;;; That's maintained in r2 on LinuxPPC32, and not maintained ;;; in a GPR on DarwinPPC32 (defppclapfunction %get-os-context () #+ppc64-target (mr arg_z 13) #+linuxppc32-target (mr arg_z 2) #+darinppc32-target (mr arg_z 0) (blr)) (defppclapfunction %check-deferred-gc () (ldr imm0 target::tcr.flags target::rcontext) (slri. imm0 imm0 (- (1- target::nbits-in-word) (+ arch::tcr-flag-bit-pending-suspend target::fixnumshift))) (li arg_z nil) (bgelr) (uuo_interr arch::error-propagate-suspend rzero) (li arg_z t) (blr)) (defppclapfunction %%tcr-interrupt ((target arg_z)) (check-nargs 1) (uuo_interr arch::error-interrupt rzero) (box-fixnum arg_z imm0) (blr)) (defppclapfunction %suspend-tcr ((target arg_z)) (check-nargs 1) (uuo_interr arch::error-suspend rzero) (ne0->boolean arg_z imm0 imm1) (blr)) (defppclapfunction %suspend-other-threads () (check-nargs 0) (uuo_interr arch::error-suspend-all rzero) (li arg_z nil) (blr)) (defppclapfunction %resume-tcr ((target arg_z)) (check-nargs 1) (uuo_interr arch::error-resume rzero) (ne0->boolean arg_z imm0 imm1) (blr)) (defppclapfunction %resume-other-threads () (check-nargs 0) (uuo_interr arch::error-resume-all rzero) (li arg_z nil) (blr)) (defppclapfunction %kill-tcr ((target arg_z)) (check-nargs 1) (uuo_interr arch::error-kill rzero) (ne0->boolean arg_z imm0 imm1) (blr)) (defppclapfunction %atomic-pop-static-cons () (li imm0 (+ (target-nil-value) (target::kernel-global static-conses))) @again (lrarx arg_z rzero imm0) (cmpri arg_z (target-nil-value)) (beq @lose) (%cdr arg_y arg_z) (strcx. arg_y rzero imm0) (bne @again) (li imm0 (+ (target-nil-value) (target::kernel-global free-static-conses))) @decf (lrarx imm1 rzero imm0) (subi imm1 imm1 '1) (strcx. imm1 rzero imm0) (bne @decf) (isync) (blr) @lose (li imm0 target::reservation-discharge) (strcx. rzero rzero imm0) (blr)) (defppclapfunction %staticp ((x arg_z)) (check-nargs 1) (ref-global temp0 static-cons-area) (ldr imm1 target::area.low temp0) (sub imm0 x imm1) (ldr imm1 target::area.ndnodes temp0) (srri imm0 imm0 target::dnode-shift) (li arg_z nil) (sub imm1 imm1 imm0) (cmplri imm1 0) (la imm1 128 imm1) (blelr) (box-fixnum arg_z imm1) (blr)) (defppclapfunction %static-inverse-cons ((n arg_z)) (check-nargs 1) (extract-lisptag imm0 arg_z) (cmpri imm0 0) (ref-global temp0 static-cons-area) (bne @fail) (la n '-128 n) (ldr imm0 target::area.ndnodes temp0) (ldr imm1 target::area.high temp0) (box-fixnum arg_y imm0) (sub imm1 imm1 n) (cmplr arg_z arg_y) (sub imm1 imm1 n) (bgt @fail) (la arg_z target::fulltag-cons imm1) (ldr arg_y target::cons.car arg_z) (cmpri arg_y target::unbound-marker) (bnelr) @fail (li arg_z nil) (blr)) ; end of ppc-misc.lisp