1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-15 10:30:25 -08:00

Constprop of lexical variables

Lexical variables bound to a constant value (symbol, number or string)
are substituted at their point of use and the variable then eliminated
if possible.  Example:

  (let ((x (+ 2 3))) (f x))  =>  (f 5)

This reduces code size, eliminates stack operations, and enables
further optimisations.  The implementation is conservative, and is
strongly curtailed by the presence of variable mutation, conditions
and loops.

* lisp/emacs-lisp/byte-opt.el
(byte-optimize-enable-variable-constprop)
(byte-optimize-warn-eliminated-variable): New constants.
(byte-optimize--lexvars, byte-optimize--vars-outside-condition)
(byte-optimize--vars-outside-loop, byte-optimize--dynamic-vars):
New dynamic variables.
(byte-optimize--substitutable-p, byte-optimize-let-form):
New functions.
(byte-optimize-form-code-walker): Adapt clauses for variable
constprop, and add clauses for 'setq' and 'defvar'.
* test/lisp/emacs-lisp/bytecomp-tests.el (bytecomp-test-var)
(bytecomp-test-get-var, bytecomp-test-identity)
(byte-opt-testsuite-arith-data): Add test cases.
This commit is contained in:
Mattias Engdegård 2021-02-06 18:34:45 +01:00
parent f95266ee68
commit 83983b6b7a
2 changed files with 303 additions and 70 deletions

View file

@ -32,6 +32,15 @@
(require 'bytecomp)
;;; Code:
(defvar bytecomp-test-var nil)
(defun bytecomp-test-get-var ()
bytecomp-test-var)
(defun bytecomp-test-identity (x)
"Identity, but hidden from some optimisations."
x)
(defconst byte-opt-testsuite-arith-data
'(
;; some functional tests
@ -371,7 +380,57 @@
(assoc 'b '((a 1) (b 2) (c 3)))
(assoc "b" '(("a" 1) ("b" 2) ("c" 3)))
(let ((x '((a 1) (b 2) (c 3)))) (assoc 'c x))
(assoc 'a '((a 1) (b 2) (c 3)) (lambda (u v) (not (equal u v)))))
(assoc 'a '((a 1) (b 2) (c 3)) (lambda (u v) (not (equal u v))))
;; Constprop test cases
(let ((a 'alpha) (b (concat "be" "ta")) (c nil) (d t) (e :gamma)
(f '(delta epsilon)))
(list a b c d e f))
(let ((x 1) (y (+ 3 4)))
(list
(let (q (y x) (z y))
(if q x (list x y z)))))
(let* ((x 3) (y (* x 2)) (x (1+ y)))
x)
(let ((x 1) (bytecomp-test-var 2) (y 3))
(list x bytecomp-test-var (bytecomp-get-test-var) y))
(progn
(defvar d)
(let ((x 'a) (y 'b)) (list x y)))
(let ((x 2))
(list x (setq x 13) (setq x (* x 2)) x))
(let ((x 'a) (y 'b))
(setq y x
x (cons 'c y)
y x)
(list x y))
(let ((x 3))
(let ((y x) z)
(setq x 5)
(setq y (+ y 8))
(setq z (if (bytecomp-test-identity t)
(progn
(setq x (+ x 1))
(list x y))
(setq x (+ x 2))
(list x y)))
(list x y z)))
(let ((i 1) (s 0) (x 13))
(while (< i 5)
(setq s (+ s i))
(setq i (1+ i)))
(list s x i))
(let ((x 2))
(list (or (bytecomp-identity 'a) (setq x 3)) x)))
"List of expression for test.
Each element will be executed by interpreter and with
bytecompiled code, and their results compared.")