u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Faculty of Science Calculating Correct Compilers Patrick Bahr 1 Graham Hutton 2 1 University of Copenhagen, Department of Computer Science paba@diku.dk 2 University of Nottingham, Functional Programming Laboratory graham.hutton@nottingham.ac.uk IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 1
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Goal Calculate a compiler that is correct by construction: • Derive compiler implementation from denotational semantics • Derivation by formal calculations • Result: compiler + virtual machine + correctness proof Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 2
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Background Reasoning about compilers, Hutton & Wright • Verifying a compiler for a simple language with exceptions (MPC ’04) • Calculating an abstract machine that is correct by construction (TFP ’05) Last 2.1 meeting, Hutton & Danielsson • Calculating a compiler for a simple language with exceptions • Use of dependent types during the calculation Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 3
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e This Talk: A Simplified Approach • simple calculations without the need for dependent types • little prior knowledge needed (e.g. “Target machine has a stack.”) • scales to wide variety of language features: • arithmetic expressions • exceptions (synchronous and asynchronous) • state (global and local) • lambda calculi (call-by-value, call-by-name, call-by-need) • loops (bounded and unbounded) • non-determinism • Underlying techniques: continuation-passing style & defunctionalisation (Reynolds, 1972) Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 4
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e How Does it Work? Calculate a Compiler in 3 Steps: Semantics 1 Define evaluation function in compositional manner. 2 Calculate a version that uses a stack CPS + Stack and continuations. 3 Defunctionalise to produce a compiler Compiler VM & virtual machine. Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 5
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Toy Example: Simple Arithmetic Language Step 1: Semantics of the language Syntax data Expr = Val Int | Add Expr Expr Semantics eval :: Expr → Int eval ( Val n ) = n eval ( Add x y ) = eval x + eval y Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 6
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Step 2: Transformation into CPS Type Definitions type Stack = [ Int ] type Cont = Stack → Stack eval C :: Expr → Cont → Cont Specification eval C e c s = c ( eval e : s ) Constructive induction: “prove” specification by induction on e � definition of eval C Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 7
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e The easy case: Val eval C ( Val n ) c s = { specification of eval C } c ( eval ( Val n ) : s ) = { definition of eval } c ( n : s ) = { define: push n c s = c ( n : s ) } push n c s Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 8
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e The interesting case: Add eval C ( Add x y ) c s = { specification of eval C } c ( eval ( Add x y ) : s ) = { definition of eval } c (( eval x + eval y ) : s ) = { define: add c ( n : m : s ) = c (( m + n ) : s ) } add c ( eval y : eval x : s ) = { induction hypothesis for y } eval C y ( add c ) ( eval x : s ) = { induction hypothesis for x } eval C x ( eval C y ( add c )) s Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 9
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Step 2: Transformation into CPS (cont.) Derived definition eval C :: Expr → Cont → Cont eval C ( Val n ) c s = push n c s eval C ( Add x y ) c s = eval C x ( eval C y ( add c )) s push :: Int → Cont → Cont push n c s = c ( n : s ) add :: Cont → Cont add c ( n : m : s ) = c (( m + n ) : s ) Identity continuation eval S :: Expr → Cont halt :: Cont eval S e = eval C e halt halt s = s Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 10
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Step 3: Defunctionalisation comp :: Expr → Code comp e = comp’ e HALT comp’ :: Expr → Code → Code comp’ ( Val n ) c = PUSH n c comp’ ( Add x y ) c = comp’ x (comp’ y (ADD c )) data Code where HALT :: Code PUSH :: Int → Code → Code ADD :: Code → Code Example comp ( Val 1 ‘ Add ‘ Val 2 ) � PUSH 1 $ PUSH 2 $ ADD $ HALT Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 11
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Step 3: Defunctionalisation (cont.) data Code where HALT :: Code PUSH :: Int → Code → Code ADD :: Code → Code Type Code represents the function type Cont (= Stack → Stack ). Virtual Machine exec :: Code → Cont exec HALT = halt exec ( PUSH n c ) = push n ( exec c ) exec ( ADD c ) = add ( exec c ) Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 12
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Compiler Correctness proved by constructive induction eval C e c s = c ( eval e : s ) (Specification) exec ( comp e ) s = eval S e s (Defunctionalisation) eval S e = eval C e halt (Definition of eval S ) exec ( comp e ) s = eval e : s (Compiler correctness) Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 13
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e A Language with Exceptions Skip this data Expr = Val Int | Add Expr Expr | Throw | Catch Expr Expr eval :: Expr → Maybe Int eval ( Val n ) = Just n eval ( Add x y ) = case eval x of Nothing → Nothing Just n → case eval y of Nothing → Nothing Just m → Just ( n + m ) = Nothing eval Throw eval ( Catch x h ) = case eval x of Nothing → eval h → Just n Just n Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 14
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Partial Specifications Partial Type Definition type Stack = [ Elem ] data Elem = VAL Int | . . . Partial Specification of eval C eval C e c s = c ( VAL n : s ) if eval e = Just n eval C e c s = fail s if eval e = Nothing where fail :: Stack → Stack is left unspecified Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 15
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Constructive Induction: Add Skip this eval C ( Add x y ) c s = { specification } case eval x of Just n → case eval y of Just m → c ( VAL ( n + m ) : s ) Nothing → fail s Nothing → fail s = { define: add c ( VAL m : VAL n : s ) = c ( VAL ( n + m ) : s ) } case eval x of → case eval y of Just n Just m → add c ( VAL m : VAL n : s ) Nothing → fail s Nothing → fail s Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 16
u n i v e r s i t y o f c o p e n h a g e n d e p a r t m e n t o f c o m p u t e r s c i e n c e Constructive Induction: Add (2) case eval x of Just n → case eval y of Just m → add c ( VAL m : VAL n : s ) Nothing → fail s Nothing → fail s = { define: fail ( VAL n : s ) = fail s } case eval x of Just n → case eval y of Just m → add c ( VAL m : VAL n : s ) Nothing → fail ( VAL n : s ) Nothing → fail s = { induction hypothesis for y } case eval x of → eval C y ( add c ) ( VAL n : s ) Just n Nothing → fail s = { induction hypothesis for x } eval C x ( eval C y ( add c )) s Patrick Bahr, Graham Hutton — Calculating Correct Compilers — IFIP Working Group 2.1 Meeting, 24th-28th March, 2014 Slide 17
Recommend
More recommend