diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2021-06-24 07:21:38 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2021-06-24 07:21:38 -0700 |
commit | 2034729c70161b16d99eee0503c4354df39cd49d (patch) | |
tree | 400e7b2f7c67625e7ab6da3fe4a16c3257f30eb8 /stdlib/optimize.tl | |
parent | 65f1445db0d677189ab01635906869bfda56d3d9 (diff) | |
download | txr-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/optimize.tl')
-rw-r--r-- | stdlib/optimize.tl | 606 |
1 files changed, 606 insertions, 0 deletions
diff --git a/stdlib/optimize.tl b/stdlib/optimize.tl new file mode 100644 index 00000000..b011c568 --- /dev/null +++ b/stdlib/optimize.tl @@ -0,0 +1,606 @@ +;; Copyright 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. + +(compile-only + (defstruct live-info nil + (defined 0) + (used 0) + def) + + (defstruct basic-block (live-info) + live + label + next + links + rlinks + insns + + (:method print (bl stream pretty-p) + (put-string "#S" stream) + (print ^(basic-block live ,bl.live + label ,bl.label + insns ,bl.insns + links ,(mapcar .label bl.links) + rlinks ,(mapcar .label bl.rlinks) + next ,bl.next) stream))) + + (defstruct (basic-blocks insns lt-dregs symvec) nil + insns + lt-dregs + symvec + root + (hash (hash)) + (li-hash (hash :eq-based)) + list + rescan + recalc + reelim + (:static start (gensym "start-")) + (:static jump-ops '(jmp if ifq ifql close swtch ret abscsr + uwprot catch block jend)) + + (:postinit (bb) + (let* ((insns (early-peephole (dedup-labels (cons bb.start bb.insns)))) + (cuts (merge [where symbolp insns] + [where [andf consp + (op memq (car @1) bb.jump-ops)] + (cons nil insns)])) + (parts (partition insns cuts)) + (lparts (mapcar [iff [chain car symbolp] + use + (op cons (gensym))] + parts))) + (set bb.list (mapcar (do new basic-block + insns @1 label (car @1)) + lparts)) + (mapdo (do set [bb.hash @1.label] @1) bb.list)) + bb.(link-graph)) + + (:method get-insns (bb) + [mappend .insns bb.list]) + + (:method cut-block (bb bl at insns) + (let* ((nlabel (gensym "nl")) + (ltail (cdr (memq bl bb.list))) + (nbl (new basic-block + label nlabel + insns (cons nlabel at)))) + (set bb.list (append (ldiff bb.list ltail) (list nbl) ltail)) + (set bl.insns (ldiff insns at)) + (set [bb.hash nlabel] nbl) + (pushnew bl bb.rescan) + (pushnew nbl bb.rescan) + nbl)) + + (:method next-block (bb bl) + (let ((ltail (memq bl bb.list))) + (iflet ((next (cdr ltail))) + (car next)))) + + (:method join-block (bb bl nxbl) + (when (eql (car nxbl.insns) nxbl.label) + (pop nxbl.insns)) + (set bl.insns (append bl.insns nxbl.insns)) + (set bl.next nxbl.next) + (set bl.links nxbl.links) + (set bb.list (remq nxbl bb.list)) + (del [bb.hash nxbl.label]) + (each ((nx bl.links)) + (upd nx.rlinks (remq nxbl)) + (pushnew bl nx.rlinks))))) + +(defmacro rewrite-case (sym list . cases) + ^(rewrite (lambda (,sym) + (match-case ,sym + ,*cases)) + ,list)) + +(defmeth basic-blocks link-graph (bb) + (set bb.root (car bb.list)) + (each ((bl bb.list)) + (let* ((code bl.insns) + (tail (last code)) + (linsn (car tail)) + (link-next t) + (nxbl (cadr (memq bl bb.list)))) + (set bl.next nxbl) + (match-case linsn + ((jmp @jlabel) + (set bl.links (list [bb.hash jlabel]) + bl.next nil)) + ((if @nil @jlabel) + (set bl.links (list [bb.hash jlabel]))) + ((@(or ifq ifql) @nil @nil @jlabel) + (set bl.links (list [bb.hash jlabel]))) + ((close @nil @nil @nil @jlabel . @nil) + (set bl.links (list [bb.hash jlabel]) + link-next nil)) + ((swtch @nil . @jlabels) + (set bl.links [mapcar bb.hash (uniq jlabels)] + bl.next nil)) + ((catch @nil @nil @nil @nil @hlabel) + (set bl.links (list [bb.hash hlabel]))) + ((block @nil @nil @slabel) + (set bl.links (list [bb.hash slabel]))) + ((uwprot @clabel) + (set bl.links (list [bb.hash clabel]))) + ((@(or abscsr ret jend) . @nil) + (set bl.next nil))) + (if (and bl.next link-next) + (pushnew bl.next bl.links)) + (each ((nxbl bl.links)) + (pushnew bl nxbl.rlinks))))) + +(defmeth basic-blocks local-liveness (bb bl) + (set bl.live nil) + (labels ((regnum (reg) + (when-match (t @num) reg num)) + (regnums (regs) + (mappend (do when-match + (t @num) @1 (list num)) regs)) + (def (li insn def) + (set li (copy li) + li.def def + [bb.li-hash insn] li) + (let* ((dn (regnum def)) + (dmask (if dn (mask dn)))) + (cond + (dn (new live-info + used (logand li.used (lognot dmask)) + defined (logior li.defined dmask))) + (t (set [bb.li-hash insn] li))))) + (refs (li insn . refs) + (set [bb.li-hash insn] li) + (let* ((rn (regnums refs)) + (rmask (mask . rn))) + (new live-info + used (logior li.used rmask) + defined (logand li.defined (lognot rmask))))) + (def-ref (li insn def . refs) + (set li (copy li) + li.def def + [bb.li-hash insn] li) + (let* ((rn (regnums refs)) + (dn (regnum def)) + (dmask (if dn (mask dn))) + (rmask (mask . rn))) + (cond + (dn (new live-info + used (logior (logand li.used (lognot dmask)) rmask) + defined (logior (logand li.defined (lognot rmask)) dmask))) + (t (set [bb.li-hash insn] li) + (new live-info + used (logior li.used rmask) + defined (logand li.defined (lognot rmask))))))) + (liveness (insns) + (if (null insns) + (new live-info used 0) + (let* ((li (liveness (cdr insns))) + (insn (car insns))) + (match-case insn + ((@(or end jend prof) @reg) + (refs li insn reg)) + ((@(or apply call) @def . @refs) + (def-ref li insn def . refs)) + ((@(or gapply gcall) @def @fidx . @refs) + (def-ref li insn def . refs)) + ((mov @def @ref) + (def-ref li insn def ref)) + ((if @reg . @nil) + (refs li insn reg)) + ((@(or ifq ifql) @reg @creg . @nil) + (refs li insn reg creg)) + ((swtch @reg . @nil) + (refs li insn reg)) + ((block @reg @nreg . @nil) + (refs li insn reg nreg)) + ((@(or ret abscsr) @nreg @reg) + (refs li insn reg nreg)) + ((catch @esreg @eareg @syreg @descreg . @nil) + (refs li insn esreg eareg syreg descreg)) + ((handle @funreg @syreg) + (refs li insn funreg syreg)) + ((@(or getv getvb getfb getl1b getlx getf) @def . @nil) + (def li insn def)) + ((@(or setv setl1 setlx bindv) @reg . @nil) + (refs li insn reg)) + ((close @reg . @nil) + (def li insn reg)) + ((@op . @nil) + (caseq op + ((end jend prof or apply call or gapply gcall mov if + ifq ifql swtch block ret abscsr catch handle getv + getvb getfb getl1b getlx getf setl1 setlx bindv close) + (error `wrongly handled @insn instruction`)) + (t (set [bb.li-hash insn] li)))) + (@else (set [bb.li-hash insn] li))))))) + (let ((li (liveness bl.insns))) + (set bl.used li.used + bl.defined li.defined)))) + +(defmeth basic-blocks calc-liveness (bb : (blist bb.list)) + (each ((bl blist)) + bb.(local-liveness bl)) + (let (changed) + (while* changed + (let ((visited (hash :eq-based))) + (labels ((upd-used (bl insns live) + (tree-case insns + ((fi . re) + (let* ((live (upd-used bl re live)) + (lif [bb.li-hash fi])) + (set live (logand live (lognot lif.defined))) + (set lif.used (logior live lif.used)) + live)) + (else live))) + (visit (bl) + (unless [visited bl] + (set [visited bl] t) + (when bl.next + (visit bl.next)) + (let ((used 0) + (old-live (or bl.live 0))) + (each ((nx bl.links)) + (visit nx) + (set used (logior used nx.used))) + (when (neql (set bl.live (logior used old-live)) + old-live) + (let ((live-in (logand (upd-used bl bl.insns bl.live) + (lognot bl.defined)))) + (set bl.used (logior live-in bl.used))) + (set changed t)))))) + (set changed nil) + (visit bb.root)))))) + +(defmeth basic-blocks thread-jumps-block (bb code) + (let* ((tail (last code)) + (oinsn (car tail)) + (insn oinsn) + (ninsn oinsn)) + (while* (nequal ninsn insn) + (set insn ninsn + ninsn (match-case insn + (@(require (if @(as reg (d @dn)) @jlabel) + (not (memqual reg bb.lt-dregs))) + nil) + ((if (t 0) @jlabel) + ^(jmp ,jlabel)) + ((jmp @jlabel) + (let ((jinsns [bb.hash jlabel].insns)) + (match-case jinsns + ((@jlabel + (jmp @(and @jjlabel @(not @jlabel))) . @nil) + ^(jmp ,jjlabel)) + (@jelse insn)))) + ((if @reg @jlabel) + (let ((jinsns [bb.hash jlabel].insns)) + (match-case jinsns + ((@jlabel + (if @reg + @(and @jjlabel @(not @jlabel))) . @nil) + ^(if ,reg ,jjlabel)) + ((@jlabel + (jmp @(and @jjlabel @(not @jlabel))) . @nil) + ^(if ,reg ,jjlabel)) + ((@jlabel + (ifq @reg (t 0) @jjlabel) . @jrest) + (let ((xbl (if jrest + bb.(cut-block [bb.hash jlabel] jrest jinsns) + bb.(next-block [bb.hash jlabel])))) + (if xbl + ^(if ,reg ,xbl.label) + insn))) + (@jelse insn)))) + ((ifq @reg @creg @jlabel) + (let ((jinsns [bb.hash jlabel].insns)) + (match-case jinsns + ((@jlabel + (ifq @reg @creg + @(and @jjlabel @(not @jlabel))) . @nil) + ^(ifq ,reg ,creg ,jjlabel)) + ((@(require @jlabel (equal creg '(t 0))) + (if @reg + @(and @jjlabel @(not @jlabel))) . @jrest) + (let ((xbl (if jrest + bb.(cut-block [bb.hash jlabel] jrest jinsns) + bb.(next-block [bb.hash jlabel])))) + (if xbl + ^(ifq ,reg ,creg ,xbl.label) + insn))) + ((@jlabel + (jmp @(and @jjlabel @(not @jlabel))) . @nil) + ^(ifq ,reg ,creg ,jjlabel)) + (@jelse insn)))) + ((close @reg @frsize @ntregs @jlabel . @cargs) + (let ((jinsns [bb.hash jlabel].insns)) + (match-case jinsns + ((@jlabel + (jmp @(and @jjlabel @(not @jlabel))) . @nil) + ^(close ,reg ,frsize ,ntregs ,jjlabel ,*cargs)) + (@jelse insn)))) + (@else else)))) + (cond + ((null ninsn) (ldiff code tail)) + ((nequal ninsn oinsn) (append (ldiff code tail) (list ninsn))) + (t code)))) + +(defun subst (x y list) + (mapcar (lambda (item) + (if (equal item x) y item)) + list)) + +(defun subst-preserve (x y bb li list) + (let ((sub (subst x y list))) + (cond + ((equal sub list) list) + (t (set [bb.li-hash sub] li) sub)))) + +(defmeth basic-blocks peephole-block (bb bl code) + (labels ((dead-treg (insn n) + (let ((li [bb.li-hash insn])) + (and li (not (bit li.used n))))) + (only-locally-used-treg (insn n) + (let ((li [bb.li-hash insn])) + (and li (bit li.used n) (not (bit bl.live n)))))) + (rewrite-case insns code + ;; dead t-reg + (@(require ((@(or mov getlx getv getf getfb) (t @n) . @nil) . @nil) + (dead-treg (car insns) n)) + (pushnew bl bb.rescan) + (set bb.recalc t) + (cdr insns)) + (@(require ((close (t @n) @nil @nil @jlabel . @nil) . @nil) + (dead-treg (car insns) n)) + (pushnew bl bb.rescan) + (set bb.recalc t + bb.reelim t) + ^((jmp ,jlabel) ,*(cdr insns))) + (@(require ((@(or gcall gapply) (t @n) @idx . @nil) . @nil) + (dead-treg (car insns) n) + [%effect-free% [bb.symvec idx]]) + (pushnew bl bb.rescan) + (set bb.recalc t) + (cdr insns)) + ;; unnecessary copying t-reg + (@(require ((mov @(as dst (t @n)) @src) . @rest) + (only-locally-used-treg (car insns) n) + (or (neq (car src) 'v) + (none rest [andf [chain car (op eq 'end)] + [chain bb.li-hash .used (lop bit n)]])) + (not (find dst rest : [chain bb.li-hash .def])) + (not (find src rest : [chain bb.li-hash .def]))) + (pushnew bl bb.rescan) + (labels ((rename (insns n dst src) + (tree-case insns + ((fi . re) + (cons (subst-preserve dst src bb [bb.li-hash fi] fi) + (rename (cdr insns) n dst src))) + (else else)))) + (rename (cdr insns) n dst src))) + ;; wasteful moves + (((mov @reg0 @nil) (mov @reg0 @nil) . @nil) + (cdr insns)) + (((mov @reg0 @reg1) (mov reg1 @reg0) . @rest) + ^(,(car insns) ,*rest)) + ;; frame reduction + (((@(or frame dframe) @lev @size) + (@(or call gcall mov) + . @(require @(coll (v @vlev @nil)) + (none vlev (op eql (ppred lev))))) + . @rest) + ^(,(cadr insns) ,(car insns) ,*rest)) + (((@(or frame dframe) . @nil) + (if (t @reg) @jlabel)) + (let ((jinsns [bb.hash jlabel].insns)) + (match-case jinsns + ((@jlabel + (end (t @reg)) . @jrest) + (let* ((xbl (if jrest + bb.(cut-block [bb.hash jlabel] jrest jinsns) + bb.(next-block [bb.hash jlabel]))) + (ybl bb.(next-block bl)) + (yinsns ybl.insns)) + (cond + ((and xbl ybl) + (set ybl.insns ^(,ybl.label ,(car insns) ,*(cdr yinsns))) + (pushnew ybl bb.rescan) + ^((if (t ,reg) ,xbl.label))) + (t insns)))) + (@jelse insns)))) + (@(require ((if @(as reg (d @dn)) @jlabel) . @nil) + (not (memqual reg bb.lt-dregs))) + nil) + (@(require ((ifq @(as reg (d @dn)) (t 0) @jlabel) . @nil) + (not (memqual reg bb.lt-dregs))) + ^((jmp ,jlabel))) + (((jmp @jlabel) . @rest) + (let* ((jinsns (cdr [bb.hash jlabel].insns)) + (oinsns (match-case jinsns + (((jend @nil) . @nil) + ^(,(car jinsns) ,*rest)) + ((@nil (jend @nil) . @nil) + ^(,(car jinsns) ,(cadr jinsns) ,*rest)) + (@else insns)))) + (when (neq insns oinsns) + (pushnew bl bb.rescan) + (set bb.recalc t + bl.next nil + bl.links nil)) + oinsns)) + (@else insns)))) + +(defmeth basic-blocks peephole (bb) + (each ((bl bb.list)) + (set bl.insns bb.(peephole-block bl bl.insns))) + (whilet ((rescan bb.rescan)) + (set bb.rescan nil) + (when bb.recalc + bb.(calc-liveness rescan) + (set bb.recalc nil)) + (each ((bl rescan)) + (set bl.insns bb.(peephole-block bl bl.insns)))) + (when bb.reelim + bb.(elim-dead-code))) + +(defmeth basic-blocks thread-jumps (bb) + (each ((bl bb.list)) + (set bl.insns bb.(thread-jumps-block bl.insns)))) + +(defmeth basic-blocks elim-next-jump (bb bl) + (let* ((tail (last bl.insns)) + (linsn (car tail))) + (when-match (jmp @jlabel) linsn + (let ((nxbl bb.(next-block bl))) + (when (eql nxbl.?label jlabel) + (set bl.insns (butlast bl.insns))))))) + +(defmeth basic-blocks join-blocks (bb) + (labels ((joinbl (list) + (tree-case list + ((bl nxbl . rest) + (cond + ((and (eq bl.next nxbl) + (eq (car bl.links) nxbl) + (null (cdr bl.links)) + (null (cdr nxbl.rlinks))) + bb.(join-block bl nxbl) + (joinbl (cons bl rest))) + (t (cons bl (joinbl (cdr list)))))) + (else else)))) + (set bb.list (joinbl bb.list)))) + +(defmeth basic-blocks elim-dead-code (bb) + (each ((bl bb.list)) + (set bl.links nil) + (set bl.rlinks nil)) + bb.(link-graph) + (let* ((visited (hash :eq-based))) + (labels ((visit (bl) + (when (test-set [visited bl]) + (when bl.next + (visit bl.next)) + [mapcar visit bl.links]))) + (for ((bl bb.root)) (bl) ((set bl bl.next)) + (visit bl)) + (visit bb.root)) + (set bb.list [keep-if visited bb.list]) + (each ((bl bb.list)) + bb.(elim-next-jump bl))) + bb.(join-blocks)) + +(defmeth basic-blocks merge-jump-thunks (bb) + (let* ((candidates (mappend [andf [chain .links len (op eql 1)] + [chain .insns len (lop < 4)] + [chain .insns last car + [iff consp + [chain car (op eq 'jmp)]]] + list] + bb.list)) + (hash (group-by [chain .insns cdr] candidates))) + (dohash (insns bls hash) + (when (cdr bls) + (whenlet ((keep (or (keep-if (op some @1.rlinks (op eq @@1) .next) bls) + (list (car bls)))) + (leader (car keep))) + (whenlet ((dupes (diff bls keep))) + (each ((bl dupes)) + (each ((pbl bl.rlinks)) + (let* ((code pbl.insns) + (tail (last code)) + (lins (car tail)) + (sins (subst bl.label leader.label lins))) + (set pbl.insns (append (ldiff code tail) (list sins)))))) + (set bb.list (remove-if (lop memq dupes) bb.list)))))))) + +(defmeth basic-blocks late-peephole (bb code) + (rewrite-case insns code + (((if @reg @lab1) + @lab2 + (jmp @lab3) + @lab1 + . @rest) + (let* ((bl [bb.hash lab2])) + (if (some bl.rlinks (op eq bb) .next) + insns + ^((ifq ,reg (t 0) ,lab3) + ,lab1 + ,*rest)))) + (((mov (t @tn) (d @dn)) + (jmp @lab3) + @lab1 + (mov (t @tn) (t 0)) + (jmp @lab3) + @lab2 + (mov (t @tn) (t 0)) + @(symbolp @lab3) + (ifq (t @tn) (t 0) @lab4) + . @rest) + (let ((lab5 (gensym "nl"))) + ^((mov (t ,tn) (d ,dn)) + (jmp ,lab4) + ,lab1 + ,lab2 + (mov (t ,tn) (t 0)) + (jmp ,lab5) + ,lab3 + (ifq (t ,tn) (t 0) ,lab4) + ,lab5 + ,*rest))) + (@else else))) + +(defun rewrite (fun list) + (build + (while* list + (let ((nlist [fun list])) + (if (eq list nlist) + (if list (add (pop list))) + (set list nlist)))))) + +(defun dedup-labels (insns) + (rewrite-case tail insns + ((@(symbolp @label0) @(symbolp @label1) . @rest) + (set insns (mapcar [iffi listp (op subst label1 label0)] + (remq label1 insns))) + (cons label0 rest)) + (@else tail)) + insns) + +(defun early-peephole (code) + (rewrite-case insns code + (((mov (t @t1) (d @d1)) + (jmp @lab2) + @(symbolp @lab1) + (mov (t @t1) (t 0)) + @lab2 + (ifq (t @t1) (t 0) @lab3) + . @rest) + ^((mov (t ,t1) (d ,d1)) + (jmp ,lab3) + ,lab1 + (mov (t ,t1) (t 0)) + ,lab2 + ,*rest)) + (@else else))) |