making an optimizing compiler
the obvious
- less code
- to process
- to run
- to debug
the honest
- gee, vectors cause a lot of my bugs
- wow, functions cause a lot of my bugs
motivation
optimization pass overview
inline functions
reveal functions
minimize vectors
propagate let-bindings
simplify
convert to closures
repeat?
until
- effort limit reached
- ast and defs have not changed
inline functions
simple functions
complex functions
(define (sum3 [x_1 : Integer]
[y_2 : Integer]
[z_3 : Integer]) : Integer
(+ x_1 (+ y_2 z_3)))
(define (zero? [x_4 : Integer]) : Boolean
(eq? x_4 0))
(define (foo [x_5 : Integer]) : Integer
(if (zero? x_5)
42
(sum3 x_5 x_5 x_5)))
(define (mult [x_1 : Integer]
[y_2 : Integer]) : Integer
(if (zero? x_1)
0
(+ y_2 (mult (sub1 x_1) y_2))))
(define (sq [x_3 : Integer]) : Integer
(mult x_3 x_3))
inline functions
(define (foo [x_5 : Integer]) : Integer
(if (zero? x_5) 42 (sum3 x_5 x_5 x_5)))
by generating lets
(define (foo [x_5 : Integer]) : Integer
(if
(let ([x_4 x_5]) (eq? x_4 0))
42
(let ([x_1 x_5])
(let ([y_2 x_5])
(let ([z_3 x_5])
(+ x_1 (+ y_2 z_3)))))))
minimize vectors
simple elements
(vector 40 (vector 42) 2 (mult 6 7))
complex elements
minimize vectors
vector-set! can make simple elements complex
(let ([v_1 (vector (vector 42) 2)])
(let ([_2 (vector-set! v_1 1 (sq 3))])
(let ([_3 (vector-set! v_1 0 42)])
v_1)))
with a caveat...
and make complex elements simple
... from anywhere in the program
by replacing simple vector-refs
(let ([v_1 (vector (mult 6 7) 2)])
(+ 40 2))
minimize vectors
(let ([v_1 (vector (mult 6 7) 2)])
(let ([_3 (vector-set! v_1 0 40)])
(+ (vector-ref v_1 0) (vector-ref v_1 1))))
(+ 40 2)
on subsequent runs
complex lets should not be propagated
(let ([v_0 (vector 42)])
(let ([a_1 (mult 2 1)])
(let ([x_2 40])
(let ([y_3 (read)])
(let ([z_4 (+ 1 0)])
(mult (+ x_2 a_1) z_4))))))
with a caveat...
propagate let-bindings
(let ([a_1 (mult 2 1)])
(let ([y_3 (read)])
(mult (+ 40 a_1) (+ 1 0))))
but can still be removed if never referenced and no side effects
simplify
...is the best pass
(not #f)
negations
simplify
#t
(not (not (eq? (read) 0)))
(eq? (read) 0)
(- (- (read)))
(read)
(- 6)
-6
and
simplify
(and #f (eq? (read) (mult 6 7)))
#f
(and #t #t)
#t
(+ 40 2)
operations
simplify
42
(>= 4 5)
#f
(eq? 0 0)
#t
if statements
simplify
(if #f (read) (mult 6 7))
(mult 6 7)
(if #t 42 777)
42
42
recursively
(if (and (eq? (+ 2 3) (- (+ 2 (- 3)))) (> (mult (read) 7) 42))
(let ([v_1 (vector (mult 6 7))])
(vector-ref v_1 0))
(if (not (not (<= 2 (+ 20 20))))
(+ 11 (- (- (+ 21 10))))
(- (- (read)))))
simplify
all together now
results
questions?
More info about the compiler and language referenced can be found here:
https://homes.soic.indiana.edu/classes/fall2017/csci/p523-rrnewton/book.pdf
making an optimizing compiler
By Trevan Haskell
making an optimizing compiler
A short presentation on optimizing racket code during compilation. Based on this book: https://homes.soic.indiana.edu/classes/fall2017/csci/p523-rrnewton/book.pdf
- 1,168