;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;
;;;;; Peephole Optimizer
;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; Based loosely on the peephole optimizer in Peter Norvig's book.
;;;;
;;;; The optimizer receives a list of code and literals. Code is a list of
;;;; instructions. Each instruction is a symbol, representing a label, or
;;;; a list of a symbol, representing an opcode, followed by numbers or
;;;; symbols.
;**** fun info; funs argument??
(in-package "XLSCMP")
(defun peephole-optimize (cl funs)
(loop (if (not (peephole-optimize-one cl funs)) (return cl))))
(defun peephole-optimize-one (cl funs)
(do* ((all-code (first cl))
(code all-code (rest code))
(instr (first code) (first code))
(changed nil))
((or changed (null code)) changed)
(setf changed
(cond
((consp instr)
(simplify-instruction instr code all-code))
((not (member instr funs))
(drop-label-if-not-used instr code all-code))))))
;;;;
;;;; Support Functions
;;;;
(defun find-target (label code)
(dolist (c (rest (member label code)) (error "no code after ~s" label))
(if (consp c) (return c))))
(defun drop-label-if-not-used (label code all-code)
(when (not (find label all-code
:test #'(lambda (x y) (if (consp y) (member x y)))))
(setf (first code) (second code) (rest code) (rest (rest code)))
t))
(defun tension-test-jump (instr code all-code)
(let ((ct (find-target (third instr) all-code))
(at (find-target (fourth instr) all-code))
(changed nil))
(when (eq '%goto (first ct))
(setf (third instr) (second ct))
(setf changed t))
(when (eq '%goto (first at))
(setf (fourth instr) (second at))
(setf changed t))
(when (drop-dead-code instr code all-code)
(setf changed t))
changed))
;;**** use loop here; is this ever called??
(defun drop-dead-code (instr code all-code)
(when (and (consp (rest code)) (consp (second code)))
(setf (rest code) (rest (rest code)))))
(defun short-operand-p (x) (<= 0 x 127))
;;;;
;;;; Data-Driven Instruction-Specific Optimizations
;;;;
(let ((table (make-hash-table :test 'eq)))
(defun add-peephole-simplifier (sym fun) (push fun (gethash sym table)))
(defun get-peephole-simplifiers (sym) (gethash sym table)))
(defun simplify-instruction (instr code all-code)
(let ((funs (get-peephole-simplifiers (first instr))))
(dolist (f funs)
(when (funcall f instr code all-code)
(return t)))))
(defmacro define-peephole-simplifier (sym args &body body)
`(add-peephole-simplifier ',sym #'(lambda ,args ,@body)))
;;;;
;;;; Test Jump and Goto Tensioning
;;;;
(dolist (s '(%test-1 %test-2 %test-arith-2))
(add-peephole-simplifier s #'tension-test-jump))
(define-peephole-simplifier %goto (instr code all-code)
(if (eq (second instr) (second code))
(setf (first code) (second code) (rest code) (rest (rest code)))
(let ((gt (find-target (second instr) all-code))
(changed nil))
(when (and (eq '%goto (first gt)) (not (eq instr gt)))
(setf (second instr) (second gt))
(setf changed t))
(when (drop-dead-code instr code all-code)
(setf changed t))
changed)))
;;;;
;;;; Simplifiers for Other Opcodes
;;;;
;; (%initialize 0 ...) => (%initialize-0 ...)
(define-peephole-simplifier %initialize (instr code all-code)
(when (eql 0 (second instr))
(setf (first code) `(%initialize-0 ,@(rest (rest instr))))
t))
;; (%set-one-value x) => (%set-one-value-return c x)
;; (%return c)
(define-peephole-simplifier %set-one-value (instr code all-code)
(let ((next-instr (first (rest code))))
(when (and (consp next-instr) (eq (first next-instr) '%return))
(setf (first code)
`(%set-one-value-return ,(second next-instr) ,(second instr)))
(setf (rest code) (rest (rest code)))
t)))
;; (%set-values ...) => (%set-values-return c ...)
;; (%return c)
(define-peephole-simplifier %set-values (instr code all-code)
(let ((next-instr (first (rest code))))
(when (and (consp next-instr) (eq (first next-instr) '%return))
(setf (first code)
`(%set-values-return ,(second next-instr) ,@(rest instr)))
(setf (rest code) (rest (rest code)))
t)))
;; (%set-values-list x y) => (%set-values-list-return c x y)
;; (%return c)
(define-peephole-simplifier %set-values-list (instr code all-code)
(let ((next-instr (first (rest code))))
(when (and (consp next-instr) (eq (first next-instr) '%return))
(setf (first code)
`(%set-values-list-return ,(second next-instr)
,(second instr)))
(setf (rest code) (rest (rest code)))
t)))
;; drop (%copy x x)
(define-peephole-simplifier %copy (instr code all-code)
(when (= (second instr) (third instr))
(setf (first code) (second code) (rest code) (rest (rest code)))
t))
;; (%copy x z) => (%copy y z)
;; (%copy y z)
(define-peephole-simplifier %copy (instr code all-code)
(let ((next-instr (first (rest code))))
(when (and (consp next-instr)
(eq (first next-instr) '%copy)
(/= (third instr) (second next-instr))
(= (third instr) (third next-instr)))
(setf (first code) (second code))
(setf (rest code) (rest (rest code)))
t)))
syntax highlighted by Code2HTML, v. 0.9.1