Where are you going with those types? Vincent St-Amour, Sam - - PowerPoint PPT Presentation

where are you going with those types
SMART_READER_LITE
LIVE PREVIEW

Where are you going with those types? Vincent St-Amour, Sam - - PowerPoint PPT Presentation

Where are you going with those types? Vincent St-Amour, Sam Tobin-Hochstadt, Matthew Flatt, Matthias Felleisen PLT / Northeastern University Boston, MA, USA PLT / University of Utah Salt Lake City, UT, USA IFL 2010 - September 3rd, 2010


slide-1
SLIDE 1

Where are you going with those types?

Vincent St-Amour, Sam Tobin-Hochstadt, Matthew Flatt, Matthias Felleisen PLT / Northeastern University Boston, MA, USA PLT / University of Utah Salt Lake City, UT, USA

IFL 2010 - September 3rd, 2010

slide-2
SLIDE 2

Generating fast code in the presence of ad-hoc polymorphism is hard.

slide-3
SLIDE 3

Case study: generic arithmetic

(+ 2 2)

slide-4
SLIDE 4

Case study: generic arithmetic

(+ 2 2) (+ 2.3 2.4)

slide-5
SLIDE 5

Case study: generic arithmetic

(+ 2 2) (+ 2.3 2.4) (+ 2.3 2)

slide-6
SLIDE 6

Case study: generic arithmetic

(+ 2 2) (+ 2.3 2.4) (+ 2.3 2) (+ 2+3i 2+4i)

slide-7
SLIDE 7

Case study: generic arithmetic

(+ 2 2) (+ 2.3 2.4) (+ 2.3 2) (+ 2+3i 2+4i)

Types of arguments are not known statically.

slide-8
SLIDE 8

Case study: generic arithmetic

#lang racket (+ 2.3 2.4)

slide-9
SLIDE 9

Case study: generic arithmetic

#lang racket (+ 2.3 2.4)

(define (add x y) (cond ((and (float? x) (float? y)) (let* ([val-x (strip-type-tag x)] [val-y (strip-type-tag y)] [result (add-floats val-x val-y)]) (tag-as-float result))) ((and (integer? x) (integer? y)) ...) ((and (complex? x) (complex? y)) ...) (else (error))))

slide-10
SLIDE 10

Case study: generic arithmetic

#lang racket (+ 2.3 2.4)

(define (add x y) (cond ((and (float? x) (float? y)) (let* ([val-x (strip-type-tag x)] [val-y (strip-type-tag y)] [result (add-floats val-x val-y)]) (tag-as-float result))) ((and (integer? x) (integer? y)) ...) ((and (complex? x) (complex? y)) ...) (else (error))))

slide-11
SLIDE 11

Our solution

  • Type-specialized primitives
  • Composition of:
  • Type-driven rewriting
  • Primitives drive optimization

Typechecker Rewriting Compiler Primitives

τ

slide-12
SLIDE 12

Implementation

  • Typed Racket
  • Higher-order functional language
  • Generic arithmetic (and complexes)
slide-13
SLIDE 13

Implementation

  • Typed Racket
  • Higher-order functional language
  • Generic arithmetic (and complexes)

Applicable to other languages

slide-14
SLIDE 14

Type-specialized primitives

slide-15
SLIDE 15

#lang racket (fl+ x y)

slide-16
SLIDE 16

#lang racket (fl+ 2.3 2.4)

slide-17
SLIDE 17

#lang racket (fl+ 2.3 2.4) 4.7

slide-18
SLIDE 18

#lang racket (fl+ 2 2)

slide-19
SLIDE 19

#lang racket (fl+ 2 2) segmentation fault

slide-20
SLIDE 20

#lang typed/racket (let: ([x : Float 2.3] [y : Float 2.4]) (fl+ x y))

slide-21
SLIDE 21

#lang typed/racket (let: ([x : Float 2.3] [y : Float 2.4]) (fl+ x y))

slide-22
SLIDE 22

#lang typed/racket (let: ([x : Float 2.3] [y : Float 2.4]) (fl+ x y)) 4.7

slide-23
SLIDE 23

#lang typed/racket (let: ([x : Integer 2] [y : Integer 2]) (fl+ x y))

slide-24
SLIDE 24

#lang typed/racket (let: ([x : Integer 2] [y : Integer 2]) (fl+ x y))

slide-25
SLIDE 25

#lang typed/racket (let: ([x : Integer 2] [y : Integer 2]) (fl+ x y))

Type Checker: No function domains matched in function application: Domains: Float Float Arguments: Integer Integer in: (fl+ x y)

slide-26
SLIDE 26

Type-driven rewriting

slide-27
SLIDE 27

#lang typed/racket (let: ([x : Float 2.3] [y : Float 2.4]) (+ x y))

slide-28
SLIDE 28

#lang typed/racket (let: ([x : Float 2.3] [y : Float 2.4]) (+ x y))

slide-29
SLIDE 29

#lang typed/racket (let: ([x : Float 2.3] [y : Float 2.4]) (fl+ x y))

slide-30
SLIDE 30

#lang typed/racket (let: ([x : Float 2.3] [y : Float 2.4]) (fl+ x y)) 4.7

slide-31
SLIDE 31

Primitives drive optimization

slide-32
SLIDE 32

#lang typed/racket (* (+ x y) (+ z w))

slide-33
SLIDE 33

#lang typed/racket (* (+ x y) (+ z w)) load $x $r1 load $y $r2 ... fadd $r1 $r2 $r3 ... sto $r3 $tmp1 load $z $r4 load $w $r5 ... fadd $r4 $r5 $r6 ... sto $r6 $tmp2 load $tmp1 $r7 load $tmp2 $r8 ... fmul $r7 $r8 $r9 ... sto $r9 $tmp3

slide-34
SLIDE 34

#lang typed/racket (* (+ x y) (+ z w)) load $x $r1 load $y $r2 ... fadd $r1 $r2 $r3 ... sto $r3 $tmp1 load $z $r4 load $w $r5 ... fadd $r4 $r5 $r6 ... sto $r6 $tmp2 load $tmp1 $r7 load $tmp2 $r8 ... fmul $r3 $r6 $r9 ... sto $r9 $tmp3

slide-35
SLIDE 35

#lang typed/racket (* (+ x y) (+ z w)) #lang typed/racket (fl* (fl+ x y) (fl+ z w)) load $x $r1 load $y $r2 ... fadd $r1 $r2 $r3 ... sto $r3 $tmp1 load $z $r4 load $w $r5 ... fadd $r4 $r5 $r6 ... sto $r6 $tmp2 load $tmp1 $r7 load $tmp2 $r8 ... fmul $r3 $r6 $r9 ... sto $r9 $tmp3

slide-36
SLIDE 36

#lang typed/racket (* (+ x y) (+ z w)) #lang typed/racket (fl* (fl+ x y) (fl+ z w)) load $x $r1 load $y $r2 ... fadd $r1 $r2 $r3 ... sto $r3 $tmp1 load $z $r4 load $w $r5 ... fadd $r4 $r5 $r6 ... sto $r6 $tmp2 load $tmp1 $r7 load $tmp2 $r8 ... fmul $r3 $r6 $r9 ... sto $r9 $tmp3

slide-37
SLIDE 37

#lang typed/racket (let ([a (+ x y)]) (* a (- z a)))

slide-38
SLIDE 38

#lang typed/racket (let ([a (+ x y)]) (* a (- z a))) load $x $r1 load $y $r2 ... fadd $r1 $r2 $r3 ... sto $r3 $a load $z $r4 load $a $r5 ... fsub $r4 $r5 $r6 ... sto $r6 $tmp1 load $a $r7 load $tmp1 $r8 ... fmul $r7 $r8 $r9 ... sto $r9 $tmp2

slide-39
SLIDE 39

#lang typed/racket (let ([a (+ x y)]) (* a (- z a))) load $x $r1 load $y $r2 ... fadd $r1 $r2 $r3 ... sto $r3 $a load $z $r4 load $a $r5 ... fsub $r4 $r3 $r6 ... sto $r6 $tmp1 load $a $r7 load $tmp1 $r8 ... fmul $r3 $r6 $r9 ... sto $r9 $tmp2

slide-40
SLIDE 40

#lang typed/racket (let ([a (+ x y)]) (* a (- z a))) #lang typed/racket (let ([a (fl+ x y)]) (fl* a (fl- z a))) load $x $r1 load $y $r2 ... fadd $r1 $r2 $r3 ... sto $r3 $a load $z $r4 load $a $r5 ... fsub $r4 $r3 $r6 ... sto $r6 $tmp1 load $a $r7 load $tmp1 $r8 ... fmul $r3 $r6 $r9 ... sto $r9 $tmp2

slide-41
SLIDE 41

#lang typed/racket (let loop ([acc 0.0]) (if (> acc x) acc (loop (+ y acc))))

slide-42
SLIDE 42

#lang typed/racket (let loop ([acc 0.0]) (if (> acc x) acc (loop (+ y acc)))) mov 0.0 $r1 ... sto $r1 $acc loop: load $acc $r2 load $x $r3 ... flcmp $r2 $r3 jgt end load $y $r4 load $acc $r5 ... fadd $r4 $r5 $r6 ... sto $r6 $acc jmp loop end:

slide-43
SLIDE 43

#lang typed/racket (let loop ([acc 0.0]) (if (> acc x) acc (loop (+ y acc)))) mov 0.0 $r1 ... sto $r1 $acc loop: load $acc $r2 load $x $r3 ... flcmp $r2 $r3 jgt end load $y $r4 load $acc $r5 ... fadd $r4 $r5 $r6 ... sto $r6 $acc jmp loop end:

slide-44
SLIDE 44

#lang typed/racket (let loop ([acc 0.0]) (if (> acc x) acc (loop (+ y acc)))) #lang typed/racket (let loop ([acc 0.0]) (if (fl> acc x) acc (loop (fl+ y acc)))) mov 0.0 $r1 ... sto $r1 $acc loop: load $acc $r2 load $x $r3 ... flcmp $r1 $r3 jgt end load $y $r4 load $acc $r5 ... fadd $r4 $r1 $r6 ... sto $r6 $acc jmp loop end: sto $r1 $acc

slide-45
SLIDE 45

#lang typed/racket (let loop ([acc 0.0]) (if (> acc x) acc (loop (+ y acc)))) #lang typed/racket (let loop ([acc 0.0]) (if (fl> acc x) acc (loop (fl+ y acc)))) mov 0.0 $r1 ... sto $r1 $acc loop: load $acc $r2 load $x $r3 ... flcmp $r1 $r3 jgt end load $y $r4 load $acc $r5 ... fadd $r4 $r1 $r6 ... sto $r6 $acc jmp loop end: sto $r1 $acc

slide-46
SLIDE 46

#lang typed/racket (let loop ([acc 0.0]) (if (> acc x) acc (loop (+ y acc)))) #lang typed/racket (let loop ([acc 0.0]) (if (fl> acc x) acc (loop (fl+ y acc)))) mov 0.0 $r1 ... sto $r1 $acc load $x $r3 load $y $r4 loop: load $acc $r2 load $x $r3 ... flcmp $r1 $r3 jgt end load $y $r4 load $acc $r5 ... fadd $r4 $r1 $r6 ... sto $r6 $acc jmp loop end: sto $r1 $acc

slide-47
SLIDE 47

Results

slide-48
SLIDE 48

Speedup benchmarks pseudoknot 2.50 mandelbrot 15.72 nbody 2.16 takl 1.24 FFT 15.91 data structures banker's queue 1.60 leftist heap 1.34 industrial application FFT 2.78 Bigger is better Average of 5 runs on x86

slide-49
SLIDE 49

In-depth look: Industrial FFT

slide-50
SLIDE 50

#lang racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i]) (- (+ x y) z))

slide-51
SLIDE 51

#lang racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i] [x-real (real-part x)] [x-imag (imag-part x)] [y-real (real-part y)] [y-imag (imag-part y)] [z-real (real-part z)] [z-imag (imag-part z)]) (make-rectangular (- (+ x-real y-real) z-real) (- (+ x-imag y-imag) z-imag)))

slide-52
SLIDE 52

#lang racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i] [x-real (real-part x)] [x-imag (imag-part x)] [y-real (real-part y)] [y-imag (imag-part y)] [z-real (real-part z)] [z-imag (imag-part z)]) (make-rectangular (fl- (fl+ x-real y-real) z-real) (fl- (fl+ x-imag y-imag) z-imag)))

slide-53
SLIDE 53

#lang racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i] [x-real (real-part x)] [x-imag (imag-part x)] [y-real (real-part y)] [y-imag (imag-part y)] [z-real (real-part z)] [z-imag (imag-part z)]) (make-rectangular (fl- (fl+ x-real y-real) z-real) (fl- (fl+ x-imag y-imag) z-imag))) Significant manual labor

slide-54
SLIDE 54

#lang racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i] [x-real (real-part x)] [x-imag (imag-part x)] [y-real (real-part y)] [y-imag (imag-part y)] [z-real (real-part z)] [z-imag (imag-part z)]) (make-rectangular (fl- (fl+ x-real y-real) z-real) (fl- (fl+ x-imag y-imag) z-imag))) Significant manual labor Error prone

slide-55
SLIDE 55

#lang typed/racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i]) (- (+ x y) z))

slide-56
SLIDE 56

#lang typed/racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i]) (- (+ x y) z)) Unboxed intermediate results

slide-57
SLIDE 57

#lang typed/racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i]) (- (+ x y) z)) Unboxed intermediate results Unboxed let bindings

slide-58
SLIDE 58

#lang typed/racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i]) (- (+ x y) z)) Unboxed intermediate results Unboxed let bindings Unboxed loop variables

slide-59
SLIDE 59

#lang typed/racket (let* ([x 2.3+2.4i] [y 2.5+2.6i] [z 2.7+2.8i]) (- (+ x y) z)) Unboxed intermediate results Unboxed let bindings Unboxed loop variables Faster than hand-optimized code

slide-60
SLIDE 60

Related Work

slide-61
SLIDE 61

Gallium / FLINT

typechecker

code types

CPS

code

λ-lifting

code

...

code

  • ptimization

Typed Racket

typechecker

code types

CPS

code

λ-lifting

code

...

code

  • ptimization
slide-62
SLIDE 62

Gallium / FLINT

typechecker

code types

CPS

code

CPS

types

λ-lifting

code

λ-lifting

types

...

code

...

types

  • ptimization

Typed Racket

typechecker

code types

CPS

code

λ-lifting

code

...

code

  • ptimization
slide-63
SLIDE 63

Gallium / FLINT

typechecker

code types

CPS

code

CPS

types

λ-lifting

code

λ-lifting

types

...

code

...

types

  • ptimization

Typed Racket

typechecker

code types

rewriting

code

CPS

code

λ-lifting

code

...

code

  • ptimization
slide-64
SLIDE 64

OCaml

2 + 2 2.3 +. 2.4

Typed Racket

(+ 2 2) (+ 2.3 2.4)

slide-65
SLIDE 65

OCaml

2 + 2 2.3 +. 2.4

Typed Racket

(+ 2 2) (+ 2.3 2.4) OCaml limits specialization to integer vs float.

slide-66
SLIDE 66

Common LISP

(defun f (x) (declare (type function x) (optimize (speed 3) (safety 0))) (funcall x 3)) (defun g (fun) (declare (type function fun)) (funcall fun "a")) (g #'f)

Typed Racket

#lang typed/racket (define: (f (x : (Integer -> Integer))) : Integer (x 3)) (define: (g (fun : (String -> String))) : String (fun "a")) (g f)

slide-67
SLIDE 67

Common LISP

(defun f (x) (declare (type function x) (optimize (speed 3) (safety 0))) (funcall x 3)) (defun g (fun) (declare (type function fun)) (funcall fun "a")) (g #'f)

Typed Racket

#lang typed/racket (define: (f (x : (Integer -> Integer))) : Integer (x 3)) (define: (g (fun : (String -> String))) : String (fun "a")) (g f)

slide-68
SLIDE 68

Common LISP

(defun f (x) (declare (type function x) (optimize (speed 3) (safety 0))) (funcall x 3)) (defun g (fun) (declare (type function fun)) (funcall fun "a")) (g #'f) Unhandled memory fault at #x610000.

Typed Racket

#lang typed/racket (define: (f (x : (Integer -> Integer))) : Integer (x 3)) (define: (g (fun : (String -> String))) : String (fun "a")) (g f) Type Checker: Expected (String -> String), but got ((Integer -> Integer)

  • > Integer)

in: f

slide-69
SLIDE 69

Our solution

  • Type-specialized primitives
  • Composition of:
  • Type-driven rewriting
  • Primitives drive optimization

Typechecker Rewriting Compiler Primitives

τ

slide-70
SLIDE 70

racket-lang.org