[ Home ]
SBCL Internals

The pages on this CLiki-driven site can be edited by anybody at any time. No warranty of any kind can therefore be made; any implied warranties of merchantability or fitness for a particular purpose are expressly disclaimed
[ Home ] [ Recent Changes ] [ About CLiki ] [ Text Formatting ]

This email message by Daniel Barlow came from here, and it is supposed to have the same contents as this broken link. Can anyone confirm this?

"Thomas F. Burdick"  writes:
 
 > There"s a thread on comp.lang.lisp where someone"s asking about how to
 > micro-optimize his code in LispWorks, and it got me wondering about
 > how to do that in SBCL.  I don"t remember ever seeing this in the
 > CMUCL manual, but I apologize if it"s covered there.  So, if I had an
 > inner loop that I couldn"t get the compiler to produce sufficiently
 > optimized code for, how would I go about writing it in assembly?
 
 It"s not covered in the manual, and I doubt it"s officially supported
 either.  But it"s something I spent some time with recently, so here"s
 the short guide.  Note that this is largely based on experimentation
 and looking at the source code, so is quite likely all wrong.  People
 who know more than me are welcome to chime in.
 
 1) you need a VOP 
 
 A VOP is a Virtual OPeration, which is (more or less) the basic thing
 that the compiler backend works on.  grep compiler/target/*.lisp in
 SBCL source for lots of examples.
 
 Here"s (part of) one of the ones I wrote for thread switching support:
 
 (define-vop (load-some-registers-from-thread)
   (:args (from :scs (sb-vm::sap-reg)))
   (:arg-types system-area-pointer)
   (:translate load-some-registers-from-thread)
   (:generator
    32
    ;; splat reg_nl0
    (inst bis from from (regtn 16))
    ;; csp,cfp,ocfp,bsp
    ;; [...]
    (inst ldq (regtn 28) (+ 24 (* 8 28)) (regtn 16))
    (inst ldq (regtn 29) (+ 24 (* 8 29)) (regtn 16))
    (inst ldq (regtn 30) (+ 24 (* 8 30)) (regtn 16))
    (inst ldq (regtn 16) (+ 24 (* 8 16)) (regtn 16))
    ))
 
 This is for the Alpha backend, so if you don"t recognise the
 mnemonics, that"s why.  One possible reason, at least.  Alternatively
 you"re reading this in rot13, or you need to turn the contrast up.
 Anyway
 
 The vop is called LOAD-SOME-REGISTERS-FROM-THREAD.  The keywords -
 
 :args - the VOP has an argument FROM which it expects to find in a
 SAP-REG.  This is a storage class; you can see how these are set up in 
 src/compiler/target/vm.lisp - in this case a sap-reg is any
 non-descriptor register
 
 :arg-types - you have to call this with a SYSTEM-AREA-DESCRIPTOR
 argument
 
 :translate - you can call this vop by writing 
 (load-some-registers-from-thread foo) .  Note that this doesn"t have
 to be the same thing as the VOP name.  For example, if you look at
 compiler/alpha/cell.lisp to see that the instance-length VOP would 
 actually get called as (%instance-length instance)
 
 :generator is where the "cost" of the operation (if you have several
 VOPs to do the same thing, I think this gets used to select between
 them.  Tends to relate to the number of instructions that follow it,
 but can be anything you like) and the actual assembler to run.
 
 Register arguments are what we call TNs.  Once back in the mists of
 time TN actually stood for something, but I don"t know what (I
 vaguely recall reading that it was "Temporary Name", but I can"t find 
 any documentation any more to confirm this) - but anyway, look in your
 vm.lisp to find out which registers are named and how.  Alpha has
 
   (defregtn zero any-reg)
   (defregtn null descriptor-reg)
   (defregtn code descriptor-reg)
   (defregtn alloc any-reg)
   (defregtn bsp any-reg)
   (defregtn csp any-reg)
   (defregtn cfp any-reg)
   (defregtn nsp any-reg)
 
 defregtn is a macro which creates TNs called zero-tn, null-tn,
 code-tn, etc etc.  In the VOP I"ve shown I needed to deal with other registers
 as well (on thread switch we"re presently saving and restoring _all_
 registers).  Not knowing the "approved" way to do this, if there is
 one, I defined a regtn macro:
 
 (defmacro regtn (offset)
   `(make-random-tn :kind :normal
     :sc (sc-or-lose "descriptor-reg) :offset ,offset))
 
 so I could just say (regtn 28) for register number 28.  This is
 probably evil not least because it"s declaring them all as descriptor
 regs and they"re not, but I can fix that up another time.
 
 You can see more exciting stuff about TNs in compiler/vop.lisp
 
 2) you need to make it a known function.
 
 (sb-c:defknown load-some-registers-from-thread (system-area-pointer) (values))
 
 3) Maybe it"s going to be a function itself, maybe you want it to be
 inlined. (declaim (inline ...)) works how you"d expect it to.
 
 4) There you go!
 
 
 -dan


This page is presently Uncategorized?: please add appropriate topic markers? and remove this text

This page is linked from: VOP  

CLiki pages can be edited by anyone at any time. Imagine a fearsomely comprehensive disclaimer of liability. Now fear, comprehensively