add dead code removal pass

This commit is contained in:
Andrea Corallo 2019-09-22 18:49:11 +02:00
parent e3ed0208a8
commit d9670ef135
2 changed files with 96 additions and 10 deletions

View file

@ -58,6 +58,7 @@
comp-propagate
comp-call-optim
comp-propagate
comp-dead-code
comp-final)
"Passes to be executed in order.")
@ -72,14 +73,23 @@
(% . number))
"Alist used for type propagation.")
(defconst comp-limple-assignments '(set
setimm
set-par-to-local
set-args-to-local
set-rest-args-to-local
push-handler)
(defconst comp-limple-sets '(set
setimm
set-par-to-local
set-args-to-local
set-rest-args-to-local)
"Limple set operators.")
(defconst comp-limple-assignments `(push-handler
,@comp-limple-sets)
"Limple operators that clobbers the first mvar argument.")
(defconst comp-limple-calls '(call
callref
direct-call
direct-callref)
"Limple operators use to call subrs.")
(defconst comp-mostly-pure-funcs
'(% * + - / /= 1+ 1- < <= = > >= cons list % concat logand logcount logior
lognot logxor regexp-opt regexp-quote string-to-char string-to-syntax
@ -234,10 +244,19 @@ structure.")
(defun comp-set-op-p (op)
"Assignment predicate for OP."
(cl-find op comp-limple-sets))
(defun comp-assign-op-p (op)
"Assignment predicate for OP."
(cl-find op comp-limple-assignments))
(defun comp-limple-insn-call-p (insn)
"Limple INSN call predicate."
(when (member (car-safe insn) comp-limple-calls)
t))
(defun comp-add-const-to-relocs (obj)
"Keep track of OBJ into the ctxt relocations.
The corresponding index is returned."
@ -1384,12 +1403,75 @@ This can run just once."
(comp-call-optim-func)))
(comp-ctxt-funcs-h comp-ctxt))))
;;; Dead code elimination pass specific code.
;; This simple pass try to eliminate insns became useful after propagation.
;; Even if gcc would take care of this is good to perform this here
;; in the hope of removing memory references (remember that most lisp
;; objects are loaded from the reloc array).
;; This pass can be run as last optim.
(defun comp-collect-mvar-ids (insn)
"Collect the mvar unique identifiers into INSN."
(cl-loop for x in insn
if (consp x)
append (comp-collect-mvar-ids x)
else
when (comp-mvar-p x)
collect (comp-mvar-id x)))
(defun comp-dead-code-func ()
"Clean-up dead code into current function."
(let ((l-vals ())
(r-vals ()))
;; Collect used r and l values.
(cl-loop
for b being each hash-value of (comp-func-blocks comp-func)
do (cl-loop
for insn in (comp-block-insns b)
for (op arg0 . rest) = insn
if (comp-set-op-p op)
do (push (comp-mvar-id arg0) l-vals)
and
do (setf r-vals (nconc (comp-collect-mvar-ids rest) r-vals))
else
do (setf r-vals (nconc (comp-collect-mvar-ids insn) r-vals))))
;; Every l-value appearing that does not appear as r-value has no right to
;; exist and gets nuked.
(let ((nuke-list (cl-set-difference l-vals r-vals)))
(comp-log (format "Function %s\n" (comp-func-symbol-name comp-func)))
(comp-log (format "l-vals %s\n" l-vals))
(comp-log (format "r-vals %s\n" r-vals))
(comp-log (format "Nuking ids: %s\n" nuke-list))
(cl-loop
for b being each hash-value of (comp-func-blocks comp-func)
do (cl-loop
for insn-cell on (comp-block-insns b)
for insn = (car insn-cell)
for (op arg0 rest) = insn
when (and (comp-set-op-p op)
(member (comp-mvar-id arg0) nuke-list))
do (setcar insn-cell
(if (comp-limple-insn-call-p rest)
rest
`(comment ,(format "optimized out %s"
insn)))))))))
(defun comp-dead-code (_)
"Dead code elimination."
(when (>= comp-speed 2)
(maphash (lambda (_ f)
(let ((comp-func f))
(comp-dead-code-func)
(comp-log-func comp-func)))
(comp-ctxt-funcs-h comp-ctxt))))
;;; Final pass specific code.
(defun comp-compile-ctxt-to-file (name)
"Compile as native code the current context naming it NAME.
Prepare every functions for final compilation and drive the C side."
Prepare every function for final compilation and drive the C back-end."
(cl-assert (= (length (comp-ctxt-data-relocs-l comp-ctxt))
(hash-table-count (comp-ctxt-data-relocs-idx comp-ctxt))))
(setf (comp-ctxt-exp-funcs comp-ctxt)