summaryrefslogtreecommitdiffstats
path: root/stdlib/asm.tl
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2021-06-24 07:21:38 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-06-24 07:21:38 -0700
commit2034729c70161b16d99eee0503c4354df39cd49d (patch)
tree400e7b2f7c67625e7ab6da3fe4a16c3257f30eb8 /stdlib/asm.tl
parent65f1445db0d677189ab01635906869bfda56d3d9 (diff)
downloadtxr-2034729c70161b16d99eee0503c4354df39cd49d.tar.gz
txr-2034729c70161b16d99eee0503c4354df39cd49d.tar.bz2
txr-2034729c70161b16d99eee0503c4354df39cd49d.zip
file layout: moving share/txr/stdlib to stdlib.
This affects run-time also. Txr installations where the executable is not in directory ending in ${bindir} will look for stdlib rather than share/txr/stdlib, relative to the determined installation directory. * txr.c (sysroot_init): If we detect relative to the short name, or fall back on the program directory, use stdlib rather than share/txr/stdlib as the stdlib_path. * INSTALL: Update some installation notes not to refer to share/txr/stdlib but stdlib. * Makefile (STDLIB_SRCS): Refer to stdlib, not share/txr/stdlib. (clean): In unconfigured mode, remove the old share/txr/stdlib entirely. Remove .tlo files from stdlib. (install): Install lib materials from stdlib. * txr.1: Updated documentation under Deployment Directory Structure. * share/txr/stdlib/{asm,awk,build,cadr}.tl: Renamed to stdlib/{asm,awk,build,cadr}.tl. * share/txr/stdlib/{compiler,conv,copy-file,debugger}.tl: Renamed to stdlib/{compiler,conv,copy-file,debugger}.tl. * share/txr/stdlib/{defset,doc-lookup,doc-syms,doloop}.tl: Renamed to stdlib/{defset,doc-lookup,doc-syms,doloop}.tl. * share/txr/stdlib/{each-prod,error,except,ffi}.tl: Renamed to stdlib/{each-prod,error,except,ffi}.tl. * share/txr/stdlib/{getopts,getput,hash,ifa}.tl: Renamed to stdlib/{getopts,getput,hash,ifa}.tl. * share/txr/stdlib/{keyparams,match,op,optimize}.tl: Renamed to stdlib/{keyparams,match,op,optimize}.tl. * share/txr/stdlib/{package,param,path-test,pic}.tl: Renamed to stdlib/{package,param,path-test,pic}.tl. * share/txr/stdlib/{place,pmac,quips,save-exe}.tl: Renamed to stdlib/{place,pmac,quips,save-exe}.tl. * share/txr/stdlib/{socket,stream-wrap,struct,tagbody}.tl: Renamed to stdlib/{socket,stream-wrap,struct,tagbody}.tl. * share/txr/stdlib/{termios,trace,txr-case,type}.tl: Renamed to stdlib/{termios,trace,txr-case,type}.tl. * share/txr/stdlib/{ver,vm-param,with-resources,with-stream}.tl: Renamed to stdlib/{ver,vm-param,with-resources,with-stream}.tl. * share/txr/stdlib/yield.tl: Renamed to stdlib/yield.tl. * share/txr/stdlib/{txr-case,ver}.txr: Renamed to stdlib/{txr-case,ver}.txr. * gencadr.txr: Update to stdlib/place.tl. * genman.txr: Update to stdlib/cadr.tl.
Diffstat (limited to 'stdlib/asm.tl')
-rw-r--r--stdlib/asm.tl782
1 files changed, 782 insertions, 0 deletions
diff --git a/stdlib/asm.tl b/stdlib/asm.tl
new file mode 100644
index 00000000..624ddff6
--- /dev/null
+++ b/stdlib/asm.tl
@@ -0,0 +1,782 @@
+;; Copyright 2018-2021
+;; Kaz Kylheku <kaz@kylheku.com>
+;; Vancouver, Canada
+;; All rights reserved.
+;;
+;; Redistribution and use in source and binary forms, with or without
+;; modification, are permitted provided that the following conditions are met:
+;;
+;; 1. Redistributions of source code must retain the above copyright notice, this
+;; list of conditions and the following disclaimer.
+;;
+;; 2. Redistributions in binary form must reproduce the above copyright notice,
+;; this list of conditions and the following disclaimer in the documentation
+;; and/or other materials provided with the distribution.
+;;
+;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+;; ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+;; WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+;; DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+;; FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+;; DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+;; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+;; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+;; OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(load "vm-param")
+
+(defstruct oc-base nil
+ (:static deprecated nil)
+ (:method synerr (me fmt . args)
+ (error `opcode @{me.symbol}: @fmt` . args))
+
+ (:method chk-arg-count (me n syntax)
+ (when (neq (length (rest syntax)) n)
+ me.(synerr "~s arguments required; ~s is invalid"
+ n syntax)))
+
+ (:method chk-arg-count-min (me n syntax)
+ (when (< (length (rest syntax)) n)
+ me.(synerr "~s arguments required; ~s is invalid"
+ n syntax)))
+
+ (:method backpatch (me asm at offs)
+ (asm-error `@{me.symbol} doesn't backpatch`)))
+
+(compile-only
+ (defstruct assembler nil
+ buf
+ bstr
+ (max-treg 0)
+ (labdef (hash))
+ (labref (hash))
+ (:static imm-width (relate '(si mi bi) '(10 16 32)))
+ (:static sign-bits (relate '(fixnum bignum chr) '(1 1 0)))
+ (:static operand-name (relate '(si mi bi l r rs d ds n o)
+ '("small immediate"
+ "medium immediate"
+ "big immediate"
+ "label"
+ "register operand"
+ "register small operand"
+ "register destination operand"
+ "register small destination operand"
+ "integer"
+ "any object")))))
+
+(defmeth assembler :postinit (me)
+ (cond
+ (me.buf (set me.bstr (make-buf-stream me.buf)))
+ (me.bstr (set me.buf (get-buf-from-stream me.bstr)))
+ (t (set me.bstr (make-buf-stream)
+ me.buf (get-buf-from-stream me.bstr)))))
+
+(defmeth assembler cur-pos (me)
+ (seek-stream me.bstr 0 :from-current))
+
+(defmeth assembler set-pos (me pos)
+ (seek-stream me.bstr pos :from-start))
+
+(defmeth assembler lookup-label (me sym oc)
+ (condlet
+ (((n [me.labdef sym])) n)
+ (t (push (cons oc (trunc me.(cur-pos) 4)) [me.labref sym])
+ 0)))
+
+(defmeth assembler define-label (me sym)
+ (let* ((pos me.(cur-pos))
+ (ins (trunc pos 4)))
+ (set [me.labdef sym] ins)
+ (each ((entry (del [me.labref sym])))
+ (tree-bind (oc . offs) entry
+ me.(set-pos (* 4 offs))
+ oc.(backpatch me (* 4 offs) ins)))
+ me.(set-pos pos)
+ ins))
+
+(defmeth assembler read-buf (me bytes)
+ (let ((buf (make-buf bytes)))
+ (when (neql (fill-buf buf 0 me.bstr) bytes)
+ (asm-error "read past instruction block"))
+ buf))
+
+(defmeth assembler put-word (me word)
+ (let* ((buf (make-buf 0)))
+ (buf-put-u32 buf 0 word)
+ (put-buf buf 0 me.bstr)))
+
+(defmeth assembler put-insn (me code extension operand)
+ (let ((word (logior (ash code 26) (ash extension 16) operand))
+ (buf (make-buf 0)))
+ (buf-put-u32 buf 0 word)
+ (put-buf buf 0 me.bstr)))
+
+(defmeth assembler put-pair (me op1 op2)
+ (let ((word (logior (ash op1 16) op2))
+ (buf (make-buf 0)))
+ (buf-put-u32 buf 0 word)
+ (put-buf buf 0 me.bstr)))
+
+(defmeth assembler get-word (me)
+ (let* ((buf me.(read-buf (sizeof uint32))))
+ (buf-get-u32 buf 0)))
+
+(defmeth assembler get-insn (me)
+ (let* ((buf me.(read-buf (sizeof uint32)))
+ (word (buf-get-u32 buf 0)))
+ (list (ash word -26)
+ (logtrunc (ash word -16) 10)
+ (logtrunc word 16))))
+
+(defmeth assembler get-pair (me)
+ (let* ((buf me.(read-buf (sizeof uint32)))
+ (word (buf-get-u32 buf 0)))
+ (list (ash word -16) (logtrunc word 16))))
+
+(defmeth assembler immediate-fits-type (me arg operand-type)
+ (and (member (typeof arg)
+ '(fixnum chr))
+ (<= (+ (width arg)
+ [me.sign-bits (typeof arg)]
+ 2)
+ [me.imm-width operand-type])))
+
+(defmeth assembler parse-args (me oc syntax pattern)
+ (mapcar (lambda (type arg n)
+ (let ((parg (caseql type
+ ((si mi bi)
+ (when me.(immediate-fits-type arg type)
+ arg))
+ (l (cond
+ ((is-label arg) me.(lookup-label arg oc))
+ ((integerp arg) arg)))
+ (n (if (integerp arg) arg))
+ (o arg)
+ ((r rs d ds)
+ (cond
+ ((null arg) 0)
+ ((consp arg)
+ (parse-compound-operand arg))
+ ((symbolp arg)
+ (parse-operand (symbol-name arg)))))
+ (t (asm-error "invalid arg type spec ~s" type)))))
+ (unless (or parg (eq type 'o))
+ oc.(synerr "argument ~a of ~s invalid; ~a expected"
+ n syntax [me.operand-name type]))
+ (when (and (member type '(d ds))
+ (or (zerop parg)))
+ oc.(synerr "argument ~a of ~s cannot be destination"
+ n syntax))
+ (when (and (member type '(rs ds))
+ (not (small-op-p parg)))
+ oc.(synerr "argument ~a of ~s isn't a small register"
+ n syntax))
+ (when (and (member type '(r rs d ds)) (< parg %lev-size%))
+ (set me.max-treg (max parg me.max-treg)))
+ parg))
+ pattern (rest syntax) (range 1)))
+
+(defmeth assembler asm-one (me syntax)
+ (let ((oc (cond
+ ((is-label syntax) [%oc-hash% 'label])
+ ((consp syntax) [%oc-hash% (car syntax)]))))
+ (unless oc
+ (asm-error "invalid instruction ~s" syntax))
+ oc.(asm me syntax)))
+
+(defmeth assembler asm (me insns)
+ (each ((i insns))
+ me.(asm-one i))
+ (unless (empty me.labref)
+ (asm-error "dangling label references"))
+ (whenlet ((n (cdr [find-max me.labdef : cdr])))
+ (unless (< -1 n (len me.buf))
+ (asm-error "labels outside of code"))))
+
+(defmeth assembler dis-one (me)
+ (tree-bind (code extension operand) me.(get-insn)
+ (let ((oc [%oc-hash% code]))
+ oc.(dis me extension operand))))
+
+(defmeth assembler dis (me)
+ me.(set-pos 0)
+ (build
+ (while (< me.(cur-pos) (len me.buf))
+ (add me.(dis-one)))))
+
+(defmeth assembler dis-listing (me : (stream *stdout*))
+ (let ((p 0)
+ (c 0)
+ (l (len me.buf)))
+ me.(set-pos p)
+ (while (< p l)
+ (let* ((dis me.(dis-one))
+ (dis-txt (cat-str [mapcar tostringp dis] " "))
+ (q me.(cur-pos)))
+ (inc c)
+ me.(set-pos p)
+ (format t "~,5d: ~,08X ~a\n" (trunc p 4) me.(get-word) dis-txt)
+ (while (< (inc p 4) q)
+ (format t "~,5d: ~,08X\n" (trunc p 4) me.(get-word)))
+ me.(set-pos q)
+ (set p q)))
+ c))
+
+(defvarl %oc-list-builder% (new list-builder))
+
+(defvarl %oc-hash% (hash))
+
+(defparml %oc-code% 0)
+
+(defun asm-error (msg . args)
+ (error `~s: @msg` 'assembler . args))
+
+(defun register-opcode (oc)
+ %oc-list-builder%.(add oc)
+ (set [%oc-hash% oc.symbol] oc)
+ (set [%oc-hash% oc.code] oc))
+
+(defun is-label (obj)
+ (or (keywordp obj)
+ (and (symbolp obj)
+ (not (symbol-package obj)))))
+
+(defun parse-compound-operand (cons)
+ (tree-case cons
+ ((sym arg)
+ (when (< -1 arg %lev-size%)
+ (caseq sym
+ ((t) arg)
+ (d (+ arg %lev-size%)))))
+ ((sym arg1 arg2)
+ (when (and (<= 0 arg1 %max-v-lev%)
+ (<= 0 arg2 %max-lev-idx%))
+ (caseq sym
+ (v (+ (* (ssucc arg1) %lev-size%) arg2)))))))
+
+(defun parse-operand (str)
+ (cond
+ ((r^$ #/t[0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?/ str)
+ (int-str [str 1..:] 16))
+ ((r^$ #/d[0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?/ str)
+ (+ %lev-size% (int-str [str 1..:] 16)))
+ ((r^$ #/v[0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f][0-9A-Fa-f]/ str)
+ (let ((lv (int-str [`0@{str[1..:]}` -5..-3] 16))
+ (ix (int-str [str -3..:] 16)))
+ (+ (* %lev-size% (ssucc lv)) ix)))))
+
+(eval-only
+ (defmacro with-lev-idx ((lev-var idx-var) val-expr . body)
+ (with-gensyms (val-var)
+ ^(let* ((,val-var ,val-expr)
+ (,lev-var (ash ,val-var (- %lev-bits%)))
+ (,idx-var (logtrunc ,val-var %lev-bits%)))
+ ,*body))))
+
+(defun operand-to-sym (val)
+ (with-lev-idx (lv ix) val
+ (caseql lv
+ (0 (if (zerop ix)
+ nil
+ (intern (fmt "t~s" ix))))
+ (1 (intern (fmt "d~s" ix)))
+ (t (intern (fmt "v~,02X~,03X" (ppred lv) ix))))))
+
+(defun operand-to-exp (val)
+ (with-lev-idx (lv ix) val
+ (caseql lv
+ (0 (if (zerop ix)
+ nil
+ ^(t ,ix)))
+ (1 ^(d ,ix))
+ (t ^(v ,(ppred lv) ,ix)))))
+
+(defun bits-to-obj (bits width)
+ (let ((tag (logtrunc bits 2))
+ (val (ash bits -2)))
+ (caseq tag
+ (1 (sign-extend val (- width 2)))
+ (2 (chr-int val))
+ (t (error "~s: bad immediate operand: ~x" 'assembler bits)))))
+
+(defun small-op-p (val)
+ (with-lev-idx (lv ix) val
+ (and (<= 0 ix %max-sm-lev-idx%)
+ (<= 0 lv %max-sm-lev%))))
+
+(defun enc-small-op (val)
+ (with-lev-idx (lv ix) val
+ (logior (ash lv %sm-lev-bits%) ix)))
+
+(defun small-op-to-sym (sval)
+ (let ((lv (ash sval (- %sm-lev-bits%)))
+ (ix (logtrunc sval %sm-lev-bits%)))
+ (operand-to-sym (+ (* lv %lev-size%) ix))))
+
+(defstruct backpatch-low16 nil
+ (:method backpatch (me asm at offs)
+ (tree-bind (hi lo) asm.(get-pair)
+ asm.(set-pos at)
+ asm.(put-pair hi offs))))
+
+(defstruct backpatch-high16 nil
+ (:method backpatch (me asm at offs)
+ (tree-bind (hi lo) asm.(get-pair)
+ asm.(set-pos at)
+ asm.(put-pair offs lo))))
+
+(defvarl %backpatch-low16% (new backpatch-low16))
+(defvarl %backpatch-high16% (new backpatch-high16))
+
+(eval-only
+ (defmacro defopcode (class symbol code . slot-defs)
+ ^(symacrolet ((auto (pinc %oc-code%)))
+ (defstruct ,class oc-base
+ (:static symbol ',symbol)
+ (:static code ,code)
+ ,*slot-defs)
+ (register-opcode (new ,class))))
+
+ (defmacro defopcode-derived (class symbol code orig-class)
+ ^(symacrolet ((auto (pinc %oc-code%)))
+ (defstruct ,class ,orig-class
+ (:static symbol ',symbol)
+ (:static code ,code))
+ (register-opcode (new ,class))))
+
+ (defmacro defopcode-alias (alias-symbol orig-symbol)
+ ^(let ((oc [%oc-hash% ',orig-symbol]))
+ (set [%oc-hash% ',alias-symbol] oc))))
+
+(defopcode op-label label nil
+ (:method asm (me asm syntax)
+ (unless (is-label syntax)
+ asm.(synerr "label must be keyword or gensym"))
+ asm.(define-label syntax))
+
+ (:method dis (me asm extension operand)))
+
+(defopcode op-noop noop auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 0 syntax)
+ asm.(put-insn me.code 0 0))
+
+ (:method dis (me asm extension operand)
+ ^(,me.symbol)))
+
+(defopcode op-frame frame auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (lev size) asm.(parse-args me syntax '(n n))
+ (unless (<= 2 lev %max-v-lev%)
+ me.(synerr "level must range from 2 to ~a"
+ %max-v-lev%))
+ (unless (<= 0 size %lev-size%)
+ me.(synerr "size must range from 0 to ~a"
+ %lev-size%))
+ asm.(put-insn me.code lev size)))
+ (:method dis (me asm lev size)
+ ^(,me.symbol ,lev ,size)))
+
+(defopcode-derived op-sframe sframe auto op-frame)
+
+(defopcode-derived op-dframe dframe auto op-frame)
+
+(defopcode op-end end auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 1 syntax)
+ (let ((res (car asm.(parse-args me syntax '(r)))))
+ asm.(put-insn me.code 0 res)))
+ (:method dis (me asm extension res)
+ ^(,me.symbol ,(operand-to-sym res))))
+
+(defopcode-alias jend end)
+
+(defopcode-derived op-prof prof auto op-end)
+
+(defopcode op-call call auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count-min 2 syntax)
+ (let* ((nargs (pred (len syntax)))
+ (syn-pat (repeat '(r) (succ nargs)))
+ (funargs (ppred nargs))
+ (args asm.(parse-args me syntax syn-pat)))
+ asm.(put-insn me.code funargs (pop args))
+ (while args
+ (let ((x (pop args))
+ (y (or (pop args) 0)))
+ asm.(put-pair y x)))))
+
+ (:method dis (me asm funargs arg0)
+ (build
+ (add me.symbol)
+ (add (operand-to-sym arg0))
+ (inc funargs 1)
+ (while (> funargs 0)
+ (dec funargs 2)
+ (tree-bind (y x) asm.(get-pair)
+ (add (operand-to-sym x))
+ (unless (minusp funargs)
+ (add (operand-to-sym y))))))))
+
+(defopcode-derived op-apply apply auto op-call)
+
+(defopcode op-gcall gcall auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count-min 2 syntax)
+ (let* ((nargs (pred (len syntax)))
+ (syn-pat (list* 'r 'n (repeat '(r) (sssucc nargs))))
+ (funargs (ppred nargs))
+ (args asm.(parse-args me syntax syn-pat)))
+ asm.(put-insn me.code funargs (pop args))
+ (while args
+ (let ((x (pop args))
+ (y (or (pop args) 0)))
+ asm.(put-pair y x)))))
+
+ (:method dis (me asm funargs arg0)
+ (let ((first t))
+ (build
+ (add me.symbol)
+ (add (operand-to-sym arg0))
+ (inc funargs 1)
+ (while (> funargs 0)
+ (dec funargs 2)
+ (tree-bind (y x) asm.(get-pair)
+ (add (if (zap first) x (operand-to-sym x)))
+ (unless (minusp funargs)
+ (add (operand-to-sym y)))))))))
+
+(defopcode-derived op-gapply gapply auto op-gcall)
+
+(defopcode op-movrs movrs auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (dst src) asm.(parse-args me syntax '(d rs))
+ asm.(put-insn me.code (enc-small-op src) dst)))
+
+ (:method dis (me asm src dst)
+ ^(,me.symbol ,(operand-to-sym dst) ,(small-op-to-sym src))))
+
+(defopcode op-movsr movsr auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (dst src) asm.(parse-args me syntax '(ds r))
+ asm.(put-insn me.code (enc-small-op dst) src)))
+
+ (:method dis (me asm dst src)
+ ^(,me.symbol ,(small-op-to-sym dst) ,(operand-to-sym src))))
+
+(defopcode op-movrr movrr auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (dst src) asm.(parse-args me syntax '(d r))
+ asm.(put-insn me.code 0 dst)
+ asm.(put-pair 0 src)))
+
+ (:method dis (me asm extension dst)
+ (let ((src (cadr asm.(get-pair))))
+ ^(,me.symbol ,(operand-to-sym dst) ,(operand-to-sym src)))))
+
+(defopcode op-mov-pseudo mov nil
+ (:method asm (me asm syntax)
+ (tree-bind (dst src) asm.(parse-args me syntax '(d r))
+ (let ((real [%oc-hash% (cond
+ ((small-op-p dst) 'movsr)
+ ((small-op-p src) 'movrs)
+ (t 'movrr))]))
+ real.(asm asm syntax)))))
+
+(defopcode op-jmp jmp auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 1 syntax)
+ (let ((dst (car asm.(parse-args me syntax '(l)))))
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))))
+
+ (:method backpatch (me asm at dst)
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)))
+
+ (:method dis (me asm high16 low16)
+ ^(,me.symbol ,(logior (ash high16 16) low16))))
+
+(defopcode op-if if auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (reg dst) asm.(parse-args me syntax '(r l))
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))
+ asm.(put-pair 0 reg)))
+
+ (:method backpatch (me asm at dst)
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)))
+
+ (:method dis (me asm high16 low16)
+ (let ((dst (logior (ash high16 16) low16))
+ (reg (cadr asm.(get-pair))))
+ ^(,me.symbol ,(operand-to-sym reg) ,dst))))
+
+(defopcode op-ifq ifq auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 3 syntax)
+ (tree-bind (lreg rreg dst) asm.(parse-args me syntax '(r r l))
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))
+ asm.(put-pair lreg rreg)))
+
+ (:method backpatch (me asm at dst)
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)))
+
+ (:method dis (me asm high16 low16)
+ (let ((dst (logior (ash high16 16) low16)))
+ (tree-bind (lreg rreg) asm.(get-pair)
+ ^(,me.symbol ,(operand-to-sym lreg) ,(operand-to-sym rreg) ,dst)))))
+
+(defopcode-derived op-ifql ifql auto op-ifq)
+
+(defopcode op-swtch swtch auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count-min 1 syntax)
+ (let* ((args asm.(parse-args me syntax '(r)))
+ (lbls (cddr syntax))
+ (tblsz (len lbls)))
+ asm.(put-insn me.code tblsz (car args))
+ (while lbls
+ (let ((x asm.(lookup-label (pop lbls) %backpatch-low16%))
+ (y (if lbls
+ asm.(lookup-label (pop lbls) %backpatch-high16%)
+ 0)))
+ asm.(put-pair y x)))))
+
+ (:method dis (me asm tblsz switch-val)
+ (build
+ (add me.symbol)
+ (add (operand-to-sym switch-val))
+ (while (> tblsz 0)
+ (dec tblsz 2)
+ (tree-bind (y x) asm.(get-pair)
+ (add x)
+ (unless (minusp tblsz)
+ (add y)))))))
+
+(defopcode-derived op-uwprot uwprot auto op-jmp)
+
+(defopcode op-block block auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 3 syntax)
+ (tree-bind (outreg blname exitpt) asm.(parse-args me syntax '(d r l))
+ asm.(put-insn me.code (ash exitpt -16) (logtrunc exitpt 16))
+ asm.(put-pair outreg blname)))
+
+ (:method backpatch (me asm at exitpt)
+ asm.(put-insn me.code (ash exitpt -16) (logtrunc exitpt 16)))
+
+ (:method dis (me asm high16 low16)
+ (let ((exitpt (logior (ash high16 16) low16)))
+ (tree-bind (outreg blname) asm.(get-pair)
+ ^(,me.symbol ,(operand-to-sym outreg) ,(operand-to-sym blname)
+ ,exitpt)))))
+
+(defopcode op-retsr retsr auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (name reg) asm.(parse-args me syntax '(rs r))
+ asm.(put-insn me.code (enc-small-op name) reg)))
+
+ (:method dis (me asm name reg)
+ ^(,me.symbol ,(small-op-to-sym name) ,(operand-to-sym reg))))
+
+(defopcode op-retrs retrs auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (name reg) asm.(parse-args me syntax '(r rs))
+ asm.(put-insn me.code (enc-small-op reg) name)))
+
+ (:method dis (me asm reg name)
+ ^(,me.symbol ,(operand-to-sym name) ,(small-op-to-sym reg))))
+
+(defopcode op-retrr retrr auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (name reg) asm.(parse-args me syntax '(r r))
+ asm.(put-insn me.code 0 reg)
+ asm.(put-pair 0 name)))
+
+ (:method dis (me asm extension reg)
+ (let ((name (cadr asm.(get-pair))))
+ ^(,me.symbol ,(operand-to-sym name) ,(operand-to-sym reg)))))
+
+(defopcode op-ret-pseudo ret nil
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (name reg) asm.(parse-args me syntax '(r r))
+ (let ((real [%oc-hash% (cond
+ ((small-op-p name) 'retsr)
+ ((small-op-p reg) 'retrs)
+ (t 'retrr))]))
+ real.(asm asm syntax)))))
+
+(defopcode-derived op-abscsr abscsr auto op-retsr)
+
+(defopcode op-catch catch auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 5 syntax)
+ (tree-bind (sym args catch-syms desc dst)
+ asm.(parse-args me syntax '(d d r r l))
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))
+ asm.(put-pair sym args)
+ asm.(put-pair desc catch-syms)))
+
+ (:method backpatch (me asm at dst)
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)))
+
+ (:method dis (me asm high16 low16)
+ (let ((dst (logior (ash high16 16) low16)))
+ (tree-bind (sym args) asm.(get-pair)
+ (tree-bind (desc catch-syms) asm.(get-pair)
+ ^(,me.symbol ,(operand-to-sym sym) ,(operand-to-sym args)
+ ,(operand-to-sym catch-syms)
+ ,(operand-to-sym desc) ,dst))))))
+
+(defopcode op-handle handle auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (fun handle-syms) asm.(parse-args me syntax '(r r))
+ asm.(put-insn me.code 0 fun)
+ asm.(put-pair fun handle-syms)))
+
+ (:method dis (me asm extension fun)
+ (let ((handle-syms (cadr asm.(get-pair))))
+ ^(,me.symbol ,(operand-to-sym fun) ,(operand-to-sym handle-syms)))))
+
+(defopcode op-getv getv auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (reg name) asm.(parse-args me syntax '(d r))
+ (unless (small-op-p name)
+ asm.(asm-one ^(mov (t 1) ,(operand-to-exp name)))
+ (set name 1))
+ asm.(put-insn me.code (enc-small-op name) reg)))
+ (:method dis (me asm name reg)
+ ^(,me.symbol ,(operand-to-sym reg) ,(small-op-to-sym name))))
+
+(defopcode-derived op-oldgetf oldgetf auto op-getv)
+
+(defopcode-derived op-getl1 getl1 auto op-getv)
+
+(defopcode-derived op-getvb getvb auto op-getv)
+
+(defopcode-derived op-getfb getfb auto op-getv)
+
+(defopcode-derived op-getl1b getl1b auto op-getv)
+
+(defopcode op-setv setv auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (reg name) asm.(parse-args me syntax '(r r))
+ (unless (small-op-p name)
+ asm.(asm-one ^(mov (t 1) ,(operand-to-exp name)))
+ (set name 1))
+ asm.(put-insn me.code (enc-small-op name) reg)))
+ (:method dis (me asm name reg)
+ ^(,me.symbol ,(operand-to-sym reg) ,(small-op-to-sym name))))
+
+(defopcode-derived op-setl1 setl1 auto op-setv)
+
+(defopcode-derived op-bindv bindv auto op-setv)
+
+(defopcode op-close close auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count-min 6 syntax)
+ (let* ((syn-pat (repeat '(d) (- (length syntax) 7))))
+ (tree-bind (reg frsize ntreg dst fix req vari . regs)
+ asm.(parse-args me syntax ^(d n n l n n o,*syn-pat))
+ (unless (<= 0 frsize %lev-size%)
+ me.(synerr "frame size must be 0 to ~a" %lev-size%))
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16))
+ asm.(put-pair (logior (ash (if vari 1 0) %lev-bits%) frsize) reg)
+ asm.(put-pair req fix)
+ asm.(put-pair 0 ntreg)
+ (unless (eql fix (- (len regs) (if vari 1 0)))
+ me.(synerr "wrong number of registers"))
+ (while regs
+ (let ((x (pop regs))
+ (y (or (pop regs) 0)))
+ asm.(put-pair y x))))))
+
+ (:method backpatch (me asm at dst)
+ asm.(put-insn me.code (ash dst -16) (logtrunc dst 16)))
+
+ (:method dis (me asm high16 low16)
+ (let ((dst (logior (ash high16 16) low16)))
+ (tree-bind (vari-frsize reg) asm.(get-pair)
+ (let ((vari (bit vari-frsize %lev-bits%)))
+ (tree-bind (req fix) asm.(get-pair)
+ (tree-bind (ign ntreg) asm.(get-pair)
+ (build
+ (add me.symbol (operand-to-sym reg)
+ (logtrunc vari-frsize %lev-bits%)
+ ntreg dst fix req vari)
+ (when vari
+ (inc fix))
+ (while (> fix 0)
+ (dec fix 2)
+ (tree-bind (y x) asm.(get-pair)
+ (add (operand-to-sym x))
+ (unless (minusp fix)
+ (add (operand-to-sym y)))))))))))))
+
+(defopcode op-getlx getlx auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (dst idx) asm.(parse-args me syntax '(d n))
+ (cond
+ ((small-op-p dst)
+ asm.(put-insn me.code (enc-small-op dst) idx))
+ (t asm.(put-insn me.code (enc-small-op 1) idx)
+ asm.(asm-one ^(mov ,(operand-to-exp dst) t1))))))
+ (:method dis (me asm dst idx)
+ ^(,me.symbol ,(small-op-to-sym dst) ,idx)))
+
+(defopcode op-setlx setlx auto
+ (:method asm (me asm syntax)
+ me.(chk-arg-count 2 syntax)
+ (tree-bind (src idx) asm.(parse-args me syntax '(r n))
+ (cond
+ ((small-op-p src)
+ asm.(put-insn me.code (enc-small-op src) idx))
+ (t asm.(asm-one ^(mov t1 ,(operand-to-exp src)))
+ asm.(put-insn me.code (enc-small-op 1) idx)))))
+ (:method dis (me asm src idx)
+ ^(,me.symbol ,(small-op-to-sym src) ,idx)))
+
+(defopcode-derived op-getf getf auto op-getlx)
+
+(defun disassemble-cdf (code data funv *stdout*)
+ (let ((asm (new assembler buf code)))
+ (put-line "data:")
+ (mapdo (do format t "~5d: ~s\n" @1 @2) (range 0) data)
+ (put-line "syms:")
+ (mapdo (do format t "~5d: ~s\n" @1 @2) (range 0) funv)
+ (put-line "code:")
+ (let ((ninsn asm.(dis-listing)))
+ (put-line "instruction count:")
+ (format t "~5d\n" ninsn))))
+
+(defun disassemble (obj : (stream *stdout*))
+ (symacrolet ((self 'vm-disassemble-obj))
+ (typecase obj
+ (vm-desc (disassemble-cdf (vm-desc-bytecode obj)
+ (vm-desc-datavec obj)
+ (vm-desc-symvec obj)
+ stream))
+ (fun (unless (vm-fun-p obj)
+ (error "~s: not a vm function: ~s" self obj))
+ (let* ((clo (func-get-env obj))
+ (desc (sys:vm-closure-desc clo))
+ (ip (sys:vm-closure-entry clo)))
+ (disassemble desc stream)
+ (put-line "entry point:")
+ (format stream "~5d\n" ip)))
+ (t (iflet ((fun (symbol-function obj)))
+ (disassemble fun stream)
+ (error "~s: not a compiled object: ~s" self obj))))
+ obj))