Verifying a Lustre Compiler (Part 1)

Timothy Bourke1,2 Lélio Brun1,2 Pierre-Évariste Dagand3 Xavier Leroy1 Marc Pouzet4,2,1 Lionel Rieg5

1. INRIA Paris

2. DI, École normale supérieure

3. CNRS

4. Univ. Pierre et Marie Curie

5. Yale University

SYNCHRON Workshop, Bamberg—December 2016

1 / 20 The Coq Development Team (2016): The Coq proof Coq [assistant reference manual ] • A functional programming language; • ‘Extraction’ to OCaml programs; • A specification language (higher-order logic); • Tactic-based interactive proof. • Why not use Isabelle, PVS, ACL2, Agda, or hyour favourite tooli? CompCert: a formal model and compiler for a subset of C • A generic machine-level model of execution and memory • A verified path to assembly code Blazy, Dargaye, and Leroy (2006): “Formal  Leroy (2009): “Formal verification of a  Verification of a C Compiler Front-End” realistic compiler” • Computer assistance is all but essential for such detailed models.

What are we doing? • Implementing a Lustre compiler in the Coq Interactive Theorem Prover • Proving that the generated code implements the dataflow semantics (Part of the ITEA 3 14014 ASSUME Project.)

2 / 20 CompCert: a formal model and compiler for a subset of C • A generic machine-level model of execution and memory • A verified path to assembly code Blazy, Dargaye, and Leroy (2006): “Formal  Leroy (2009): “Formal verification of a  Verification of a C Compiler Front-End” realistic compiler” • Computer assistance is all but essential for such detailed models.

What are we doing? • Implementing a Lustre compiler in the Coq Interactive Theorem Prover • Proving that the generated code implements the dataflow semantics (Part of the ITEA 3 14014 ASSUME Project.)

The Coq Development Team (2016): The Coq proof Coq [assistant reference manual ] • A functional programming language; • ‘Extraction’ to OCaml programs; • A specification language (higher-order logic); • Tactic-based interactive proof. • Why not use Isabelle, PVS, ACL2, Agda, or hyour favourite tooli?

2 / 20 • Computer assistance is all but essential for such detailed models.

What are we doing? • Implementing a Lustre compiler in the Coq Interactive Theorem Prover • Proving that the generated code implements the dataflow semantics (Part of the ITEA 3 14014 ASSUME Project.)

The Coq Development Team (2016): The Coq proof Coq [assistant reference manual ] • A functional programming language; • ‘Extraction’ to OCaml programs; • A specification language (higher-order logic); • Tactic-based interactive proof. • Why not use Isabelle, PVS, ACL2, Agda, or hyour favourite tooli? CompCert: a formal model and compiler for a subset of C • A generic machine-level model of execution and memory • A verified path to assembly code Blazy, Dargaye, and Leroy (2006): “Formal  Leroy (2009): “Formal verification of a  Verification of a C Compiler Front-End” realistic compiler”

2 / 20 What are we doing? • Implementing a Lustre compiler in the Coq Interactive Theorem Prover • Proving that the generated code implements the dataflow semantics (Part of the ITEA 3 14014 ASSUME Project.)

The Coq Development Team (2016): The Coq proof Coq [assistant reference manual ] • A functional programming language; • ‘Extraction’ to OCaml programs; • A specification language (higher-order logic); • Tactic-based interactive proof. • Why not use Isabelle, PVS, ACL2, Agda, or hyour favourite tooli? CompCert: a formal model and compiler for a subset of C • A generic machine-level model of execution and memory • A verified path to assembly code Blazy, Dargaye, and Leroy (2006): “Formal  Leroy (2009): “Formal verification of a  Verification of a C Compiler Front-End” realistic compiler”

• Computer assistance is all but essential for such detailed models. 2 / 20 • Implemented in Coq and (some) OCaml • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] • Not yet implemented: normalization and scheduling [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ] • Elaboration toScheduled andNormalized Lustre. • Translation to intermediate Obc code. • Optimization of intermediate Obc code. • Generation of CompCert Clight code. • Rely on CompCert for compilation.

The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization

Obc

generation

Clight

compilation

Assembly

printing

3 / 20 • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] • Not yet implemented: normalization and scheduling [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ] • Elaboration toScheduled andNormalized Lustre. • Translation to intermediate Obc code. • Optimization of intermediate Obc code. • Generation of CompCert Clight code. • Rely on CompCert for compilation.

The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization • Implemented in Coq and (some) OCaml Obc

generation

Clight

compilation

Assembly

printing

3 / 20 • Not yet implemented: normalization and scheduling [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ] • Elaboration toScheduled andNormalized Lustre. • Translation to intermediate Obc code. • Optimization of intermediate Obc code. • Generation of CompCert Clight code. • Rely on CompCert for compilation.

The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization • Implemented in Coq and (some) OCaml Obc • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] generation

Clight

compilation

Assembly

printing

3 / 20 • Elaboration toScheduled andNormalized Lustre. • Translation to intermediate Obc code. • Optimization of intermediate Obc code. • Generation of CompCert Clight code. • Rely on CompCert for compilation.

The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization • Implemented in Coq and (some) OCaml Obc • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] generation • Not yet implemented: normalization and scheduling Clight [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ]

compilation

Assembly

printing

3 / 20 • Translation to intermediate Obc code. • Optimization of intermediate Obc code. • Generation of CompCert Clight code. • Rely on CompCert for compilation.

The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization • Implemented in Coq and (some) OCaml Obc • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] generation • Not yet implemented: normalization and scheduling Clight [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ] • Elaboration toScheduled andNormalized Lustre. compilation

Assembly

printing

3 / 20 • Optimization of intermediate Obc code. • Generation of CompCert Clight code. • Rely on CompCert for compilation.

The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization • Implemented in Coq and (some) OCaml Obc • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] generation • Not yet implemented: normalization and scheduling Clight [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ] • Elaboration toScheduled andNormalized Lustre. compilation • Translation to intermediate Obc code. Assembly

printing

3 / 20 • Generation of CompCert Clight code. • Rely on CompCert for compilation.

The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization • Implemented in Coq and (some) OCaml Obc • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] generation • Not yet implemented: normalization and scheduling Clight [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ] • Elaboration toScheduled andNormalized Lustre. compilation • Translation to intermediate Obc code. Assembly • Optimization of intermediate Obc code. printing

3 / 20 • Rely on CompCert for compilation.

The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization • Implemented in Coq and (some) OCaml Obc • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] generation • Not yet implemented: normalization and scheduling Clight [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ] • Elaboration toScheduled andNormalized Lustre. compilation • Translation to intermediate Obc code. Assembly • Optimization of intermediate Obc code. printing • Generation of CompCert Clight code.

3 / 20 The Vélus Lustre Compiler

(normalized) elaboration / scheduling check

parsing elaboration normalization scheduling Unannotated Lustre N-Lustre SN-Lustre Lustre dataflow translation imperative fusion optimization • Implemented in Coq and (some) OCaml Obc • Validated parser (menhir –coq) [Jourdan, Pottier, and Leroy (2012): “Validating LR(1) parsers” ] generation • Not yet implemented: normalization and scheduling Clight [Auger (2013): “Compilation certifiée de SCADE/LUSTRE” ] • Elaboration toScheduled andNormalized Lustre. compilation • Translation to intermediate Obc code. Assembly • Optimization of intermediate Obc code. printing • Generation of CompCert Clight code. • Rely on CompCert for compilation. 3 / 20 Two talks

1 Tim: • Overview • Translation correctness: SN-Lustre to Obc (recap) • Control-fusion optimization • Integration of Clight operators 2 Lélio: • Obc to Clight • Demo

Caspi et al. (1987): “LUSTRE: A declarative language Lustre 30 years later? [for programming synchronous systems” ] Not quite. . . • No pre: use fby, avoid initialization analysis for now • No sub-clocking on inputs or outputs • No current: use (binary) merge • No external calls

4 / 20 Caspi et al. (1987): “LUSTRE: A declarative language Lustre 30 years later? [for programming synchronous systems” ] Not quite. . . • No pre: use fby, avoid initialization analysis for now • No sub-clocking on inputs or outputs • No current: use (binary) merge • No external calls

Two talks

1 Tim: • Overview • Translation correctness: SN-Lustre to Obc (recap) • Control-fusion optimization • Integration of Clight operators 2 Lélio: • Obc to Clight • Demo

4 / 20 Outline

Verifying Lustre compilation in Coq

Translation correctness: SN-Lustre to Obc

Fusion of control structures

Integrating Clight operators into N-Lustre and Obc

Conclusion

5 / 20 Translation of SN-Lustre to Obc

translation SN-Lustre Obc

6 / 20 Translation of SN-Lustre to Obc

translation SN-Lustre Obc functional program (≈100 lines)

6 / 20 Translation of SN-Lustre to Obc

translation SN-Lustre Obc functional program (≈100 lines)

sem_node G f xss yss + + (ft , s0) (Ti ) → stream(To )

+ + S × Ti → To × S S

6 / 20 Translation of SN-Lustre to Obc

translation SN-Lustre Obc functional program (≈100 lines)

induction is too weak %

sem_node G f xss yss + + (ft , s0) stream(Ti ) → stream(To )

+ + S × Ti → To × S S

6 / 20 Translation of SN-Lustre to Obc

translation SN-Lustre Obc functional program (≈100 lines)

sem_node G f xss yss msem_node G f xss M yss + + (ft , s0) stream(Ti ) → stream(To )

+ + S × Ti → To × S S

6 / 20 Translation of SN-Lustre to Obc

translation SN-Lustre Obc functional program (≈100 lines)

short proof

sem_node G f xss yss msem_node G f xss M yss + + (ft , s0) stream(Ti ) → stream(To )

+ + S × Ti → To × S S

6 / 20 Translation of SN-Lustre to Obc

translation SN-Lustre Obc functional program (≈100 lines)

long proof short proof

sem_node G f xss yss msem_node G f xss M yss + + (ft , s0) stream(Ti ) → stream(To )

+ + S × Ti → To × S S

6 / 20 Translation of SN-Lustre to Obc induction n translation SN-Lustre Obc induction G functional program (≈100 lines) induction eqs case: x = (ce)ck case: present long proof shortcase: proof absent case: x = (f e)ck case: present case: absent sem_node G f xss yss msem_node G f xss M yss case: x = (k fby e)ck + + (ft , s0) stream(Ti ) → stream(To ) case: present S × T + → T + × S case: absent i o S

6 / 20 SN-Lustre to Obc: main invariant

Corres G n M Memory menv M menv

instant n c0 · c1 · c2 ··· M1 M2 state(x3) o2 : f1 o4 : f1

......

• Memory ‘model’ does not change between SN-Lustre and Obc. • Corresponds at each ‘snapshot’. • The real challenge is in the change of semantic model: from dataflow streams to sequenced assignments

7 / 20 Outline

Verifying Lustre compilation in Coq

Translation correctness: SN-Lustre to Obc

Fusion of control structures

Integrating Clight operators into N-Lustre and Obc

Conclusion

8 / 20 Biernacki et al. (2008): “Clock-directed modular code Fusion of control structures [generation for synchronous data-flow languages” ]

step(delta: int, sec: bool) step(delta: int, sec: bool) returns (v: int){ returns (v: int){ varr,t: int; varr,t: int;

r := count.step o1 (0, delta, false); r := count.step o1 (0, delta, false); if sec then{ if sec then{ t := count.step o2 (1, 1, false) t := count.step o2 (1, 1, false); }; v := r / t if sec then{ } else{ v := r / t v := mem(w) } else{ }; v := mem(w) }; mem(w) := v mem(w) := v } } • Generate control for each equation (simpler to implement and prove). • Afterward fuse control structures together. • Effective if scheduler places similarly clocked equations together. 9 / 20 Biernacki et al. (2008): “Clock-directed modular code Fusion of control structures [generation for synchronous data-flow languages” ]

step(delta: int, sec: bool) step(delta: int, sec: bool) returns (v: int){ returns (v: int){ varr,t: int; varr,t: int;

r := count.step o1 (0, delta, false); r := count.step o1 (0, delta, false); if sec then{ if sec then{ t := count.step o2 (1, 1, false) t := count.step o2 (1, 1, false); }; v := r / t if sec then{ } else{ v := r / t v := mem(w) } else{ }; v := mem(w) }; mem(w) := v mem(w) := v } } • Generate control for each equation (simpler to implement and prove). • Afterward fuse control structures together. • Effective if scheduler places similarly clocked equations together. 9 / 20

normalized expression of the form ca for a and a new set of with several methods, in particular to give access to the components declarations; NormD D (D1) normalizes the definitions D1 and of a structured output and avoid copying the output when calling a NormV D (a) returns a fresh variable storing the result of the nor- node. Nonetheless, this optimization is orthogonal to the translation malized expression of a and a new set of declarations. To avoid and can be done afterwards. duplications, definitions of normalization functions are given in order. 5. The Translation Note that it would also be possible to introduce a new interme- diate language instead of the source-to-source transformation. This The translation closely follows the principle of the co-iterative se- is essentially a matter of taste, the main advantage of the present mantics described in [5], restricted to the first-order language. The formulation being to save the redefinition of auxiliary notions. main differences are that absent values are not explicitly repre- sented at run-time and states are modified in-place instead of being returned by transition functions. 4. A Simple Object-based Language We introduce the following notation. If p = [x1 : t1; ...; xn : A classical way to encapsulate a state and a collection of func- tn] and p2 = [x10 : t10 ; ...; xk0 : tk0 ] then p1 + p2 = [x1 : tions that manipulate this state is given by the object-orientation t1; ...; xn : tn; x10 : t10 ; ...; xk0 : tk0 ] provided xi = xj0 for all i, 6 paradigm. We are not interested in inheritance or object polymor- j such that 1 i n, 1 j k. [] denotes the empty list of ≤ ≤ ≤ ≤ phism aspects, but only in the capability to encapsulate a piece of variable declarations. In the same way, we write m1 + m2 for the memory managed exclusively by the methods of the class. We pro- composition of two substitutions on memory variables and j1 + j2 pose here to define a very simple object-based language that will on object instances. If s1 = S1, ..., Sn and s2 = S10 , ..., Sk0 are be used as an intermediate language for the translation. Adopting two lists of instructions, we write s1@s2 for their concatenation this point of view has two main advantages compared to a direct S1, ..., Sn,S10 , ..., Sk0 . translation into one target language. First, object orientation is a Clocks in the source language are transformed into control well-known paradigm, and this may help to understand the basic structures in the target language. Intuitively, a computation S on principles of the first level of our transformation. Second, using it clock base on C1(x1) on C10 (x10 ) is transformed into the code: as a generic intermediate language allows one to derive a very sim- case (x1) C1 : case (x10 ) C10 : S . We define the function { { }} ple translation to any target language like C or JAVA. Control(., .) such that Control(ck, S) returns a control structure A stateful stream function or node can be considered as a simple so that S is executed only when ck is true: class definition with instance variables and two methods step and Control(base,S) = S reset. Variables are used to represent the internal state of the node Control(ck on C(x),S) = Control(ck, case (x) C : S ) (i.e., one for each delay). The method step inherits its signature { } from the node it was generated from, and it implements a single We also define the function Join(., .) which merges two control step of the node. The method reset is parameterless, and it is in structures gathered by the same guards: charge of the initialization of the state variables. One difference Join( case (x) C1 : S1; ...; Cn : Sn , { } with respect to object orientation is the absence of dynamic object case (x) C1 : S0 ; ...; Cn : S0 ) { 1 n} creation; this is not necessary as we do not consider recursive block = case (x) C1 : Join(S1,S0 ); ...; Cn : Join(Sn,S0 ) { 1 n } diagrams. Join(S1,S2) = S1; S2 The syntax of the language is given below. A program is made of a sequence of global definitions (d) of classes. An instruction S JoinList(S) = S x := c may be an assignment of a local variable ( ) or of a state JoinList(S1, ..., Sn) = Join(S1, JoinList(S2, ..., Sn)) variable (state (x) := c), a sequence (S ; S), a reinitialization method invocation of an object o (o.reset), an invocation of the The translationBiernacki is et defined al. (2008): by “Clock-directed a set of mutually modular code recursive func- TE generation for(e synchronous) data-flow languages” step method of object o (o.step (e1, . . . , en)), a void statement tions. (m,si,j,d,s) defines the translation of an unannotated (skip), or a control structure (case (x) C1 : S1; ...; Cn : Sn ). expression e in a context (m, si, j, d, s) and returns an expres- { } If x is of type bt = C1 + ... + C + ... + Cn, we shall indif- sion from the target language c. We overload the notation for an- ferently write case (x) C1 : skip; ...; C : S; ...; Cn : skip or notated expressions a. m stands for a memory environment, si case (x) C : S . An expression{ (e) can be either an access} to a stands for a list of instructions that initialize the memory, j is local variable{ (x)} or to a state variable (state (x)), an immediate an environment for node instances, d is an environment for local integer constant (i) or a value constructor (C), a tuple (e1, ..., en), variables and s is a list of instructions. TA(m,si,j,d,s) (x, ca) de- or a function call (f (e1, . . . , en)). A machine (f) defines a set of fines the translation of an expression which is stored into x and memories (m), a set of instances for objects used inside the body it returns a new context. TEq (m,si,j,d,s) (eq) defines the transla- of the methods step or reset (j), and these two methods. tion of an equation. We use two auxiliary functions: the opera- tion TEList (m,si,j,d,s) (a1, ..., an) translates a list of expressions d ::= machine f = and returns a list of expressions from the target language, whereas memory m TEqList (m,si,j,d,s) (l) translates a list of equations. instances j The definitions of the translation functions are given in Figure 5. reset() = S The first six rules apply to stateless expressions. The translation step (p) returns (p) = var p in S of a merge operator, whose result is stored into a pattern pat, is 10 / 20 S ::= x := c state (x) := c S ; S skip | | | obtained by translating each branch and storing the corresponding o.reset (x, ..., x) = o.step (c, ..., c) result in pat. Note that since the result of each branch is annotated | case (x)| C : S; ...; C : S | { } with its proper clock, the merge construction does not generate c ::= x v state (x) op(c, ..., c) ck any code by itself. For a node instance (f (a1, ..., a ) every x) , v ::= C | i | | k we introduce a fresh name o which is an object of the machine j ::= o :|f, ..., o : f f. The initialization code consists in calling the reset method. p, m ::= x : t, ..., x : t The step function is essentially the result of calling the reset We only define the minimal intermediate language which is method when x is true and calling the step function associated to sufficient for the translation. One may consider a more general form o. These two actions must be performed only when ck is true. A

125

normalized expression of the form ca for a and a new set of with several methods, in particular to give access to the components declarations; NormD D (D1) normalizes the definitions D1 and of a structured output and avoid copying the output when calling a NormV D (a) returns a fresh variable storing the result of the nor- node. Nonetheless, this optimization is orthogonal to the translation malized expression of a and a new set of declarations. To avoid and can be done afterwards. duplications, definitions of normalization functions are given in order. 5. The Translation Note that it would also be possible to introduce a new interme- diate language instead of the source-to-source transformation. This The translation closely follows the principle of the co-iterative se- is essentially a matter of taste, the main advantage of the present mantics described in [5], restricted to the first-order language. The formulation being to save the redefinition of auxiliary notions. main differences are that absent values are not explicitly repre- sented at run-time and states are modified in-place instead of being returned by transition functions. 4. A Simple Object-based Language We introduce the following notation. If p = [x1 : t1; ...; xn : A classical way to encapsulate a state and a collection of func- tn] and p2 = [x10 : t10 ; ...; xk0 : tk0 ] then p1 + p2 = [x1 : tions that manipulate this state is given by the object-orientation t1; ...; xn : tn; x10 : t10 ; ...; xk0 : tk0 ] provided xi = xj0 for all i, 6 paradigm. We are not interested in inheritance or object polymor- j such that 1 i n, 1 j k. [] denotes the empty list of ≤ ≤ ≤ ≤ phism aspects, but only in the capability to encapsulate a piece of variable declarations. In the same way, we write m1 + m2 for the memory managed exclusively by the methods of the class. We pro- composition of two substitutions on memory variables and j1 + j2 pose here to define a very simple object-based language that will on object instances. If s1 = S1, ..., Sn and s2 = S10 , ..., Sk0 are be used as an intermediate language for the translation. Adopting two lists of instructions, we write s1@s2 for their concatenation this point of view has two main advantages compared to a direct S1, ..., Sn,S10 , ..., Sk0 . translation into one target language. First, object orientation is a Clocks in the source language are transformed into control well-known paradigm, and this may help to understand the basic structures in the target language. Intuitively, a computation S on principles of the first level of our transformation. Second, using it clock base on C1(x1) on C10 (x10 ) is transformed into the code: as a generic intermediate language allows one to derive a very sim- case (x1) C1 : case (x10 ) C10 : S . We define the function { { }} ple translation to any target language like C or JAVA. Control(., .) such that Control(ck, S) returns a control structure A stateful stream function or node can be considered as a simple so that S is executed only when ck is true: class definition with instance variables and two methods step and Control(base,S) = S reset. Variables are used to represent the internal state of the node Control(ck on C(x),S) = Control(ck, case (x) C : S ) (i.e., one for each delay). The method step inherits its signature { } from the node it was generated from, and it implements a single We also define the function Join(., .) which merges two control step of the node. The method reset is parameterless, and it is in structures gathered by the same guards: charge of the initialization of the state variables. One difference Join( case (x) C1 : S1; ...; Cn : Sn , { } with respect to object orientation is the absence of dynamic object case (x) C1 : S0 ; ...; Cn : S0 ) { 1 n} creation; this is not necessary as we do not consider recursive block = case (x) C1 : Join(S1,S0 ); ...; Cn : Join(Sn,S0 ) { 1 n } diagrams. Join(S1,S2) = S1; S2 The syntax of the language is given below. A program is made of a sequence of global definitions (d) of classes. An instruction S JoinList(S) = S x := c may be an assignment of a local variable ( ) or of a state JoinList(S1, ..., Sn) = Join(S1, JoinList(S2, ..., Sn)) variable (state (x) := c), a sequence (S ; S), a reinitialization method invocation of an object o (o.reset), an invocation of the The translation is defined by a set of mutually recursiveFixpoint func- zip s1 s2 : stmt := o o.step (e , . . . , e ) tions. TE (m,si,j,d,s) (e) defines the translation of an unannotatedmatch s1, s2 with step method of object ( 1 n ), a void statement | Ifte e1 t1 f1, Ifte e2 t2 f2 ⇒ (skip), or a control structure (case (x) C1 : S1; ...; Cn : Sn ). expression e in a context (m, si, j, d, s) and returns an expres-if equiv_decb e1 e2 { } then Ifte e1 (zip t1 t2)(zip f1 f2) If x is of type bt = C1 + ... + C + ... + Cn, we shall indif- sion from the target language c. We overload the notation for an- notated expressions a. m stands for a memory environment,elsesi Comp s1 s2 ferently write case (x) C1 : skip; ...; C : S; ...; Cn : skip or | Skip, s s ⇒ { } stands for a list of instructions that initialize the memory,| sj, is Skip s case (x) C : S . An expression (e) can be either an access to a ⇒ | Comp s1' s2', _ Comp s1' (zip s2' s2) { } an environment for node instances, d is an environment for local ⇒ local variable (x) or to a state variable (state (x)), an immediate | s1, s2 Comp s1 s2 ⇒ integer constant (i) or a value constructor (C), a tuple (e1, ..., en), variables and s is a list of instructions. TA(m,si,j,d,s) (x, caend) .de- f (e , . . . , e ) f fines the translation of an expression which is stored into x and or a function call ( 1 n ). A machine ( ) defines a set of Fixpoint fuse' s1 s2 : stmt := memories (m), a set of instances for objects used inside the body it returns a new context. TEq (m,si,j,d,s) (eq) defines the transla-match s1, s2 with | s1, Comp s2 s3 fuse' (zip s1 s2) s3 of the methods step or reset (j), and these two methods. tion of an equation. We use two auxiliary functions: the opera- ⇒ | s1, s2 zip s1 s2 tion TEList (a1, ..., an) translates a list of expressions ⇒ (m,si,j,d,s) end. d ::= machine f = and returns a list of expressions from the target language, whereas memory m TEqList (l) translates a list of equations. Definition fuses : stmt := instances j (m,si,j,d,s) matchs with The definitions of the translation functions are given in Figure| Comp 5. s1 s2 fuse' s1 s2 ⇒ reset() = S | _ s The first six rules apply to stateless expressions. The translation⇒ step (p) returns (p) = var p in S of a merge operator, whose result is stored into a pattern patend., is 10 / 20 S ::= x := c state (x) := c S ; S skip | | | obtained by translating each branch and storing the corresponding o.reset (x, ..., x) = o.step (c, ..., c) result in pat. Note that since the result of each branch is annotated | case (x)| C : S; ...; C : S | { } with its proper clock, the merge construction does not generate c ::= x v state (x) op(c, ..., c) ck any code by itself. For a node instance (f (a1, ..., a ) every x) , v ::= C | i | | k we introduce a fresh name o which is an object of the machine j ::= o :|f, ..., o : f f. The initialization code consists in calling the reset method. p, m ::= x : t, ..., x : t The step function is essentially the result of calling the reset We only define the minimal intermediate language which is method when x is true and calling the step function associated to sufficient for the translation. One may consider a more general form o. These two actions must be performed only when ck is true. A

125 Lemma fuse_method_m_name: m, ∀ exfalso; now apply true_not_false_val. (fuse_methodm ).(m_name) = m.(m_name). Require Import Coq.FSets.FMapPositive. + econstructor (eassumption). Proof. Lemma wt_stmt_map_fuse_class: Require Import PArith. (Import Trans : Velus.NLustreToObc.Translation.TRANSLATION inversion_clear Hstmt as [| | | |? ? ? ? ? ? ? ? ? ? Hx Hv Hs|]. unfold fuse_method; destructm ; auto. destruct (equiv_decb e1 e2) eqn:Heq Instance subrelation_stmt_fuse_eval_eq: p objs mems vars body, Require Import Velus.Common. − ∀ Ids Op OpAux NLus.Syn Obc.Syn NLus.Mem). destructb ; assert (Hv':=Hv); Qed. | Can_write_in_ (Ifte___ ) subrelation fuse_eval_eq stmt_eval_eq. wt_stmtp objs mems vars body Require Import Velus.Operators. ` ⇒ → [ apply val_to_bool_true' in Hv' (apply CWIIfteTrue; apply IHs1_1; now intuition) Proof. wt_stmt (map fuse_classp ) objs mems vars body. Require Import Velus.Obc.Syntax. (**** Show that the Obc code that results from translating an NLustre | apply val_to_bool_false' in Hv']; subst; Lemma fuse_method_body: || (apply CWIIfteFalse; apply IHs1_2; now intuition) intros s1 s2 Heqx menv env menv ' env'. Proof. Require Import Velus.Obc.Semantics. program satisfies the[Fusible] invariant, and thus that fusion inversion_clear Hs as [| | |? ? ? ? ? env'' menv'' ?? Hs1 Ht1| | ]; fm, | H:Can_write_in_ (zip__ ) _ now apply Heq. induction body; inversion_clear 1; eauto using wt_stmt. Require Import Velus.Obc.Typing. ∀ ` ⇒ preserves its semantics.*) apply Icomp with (menv1:=menv'')(env1:=env''). (fuse_method fm).(m_body) = fuse fm.(m_body). apply IHs1_1 inH || apply IHs1_2 inH Qed. eapply wt_Call Require Import Velus.Obc.Equiv. ( := )( ':= ')( := ); + apply Iifte with (1:=Hx) (2:=Hv) (3:=Hs1). Proof. | Can_write_in_ (Comp_ (zip__ )) Lemma not_Can_write_in_translate_cexpwith cls fuse_class: cls p map fuse_classp fm fuse_method fm ` ⇒ : ; ( ; ). + apply cannot_write_exp_eval with (3:=Hs1) in Hx; [|now cannot_write]. now destruct fm. now (apply CWIComp2; apply IHs1_2; intuition) Lemma zip_Comp x mems cei , auto try now destruct fm auto Require Import Velus.NLustre.Syntax. s1 s2, ∀ erewrite fuse_find_class; eauto. apply Iifte with (1:=Hx) (2:=Hv) (3:=Ht1). Qed. | _ intuition ∀ x <> i Can_write_ini (translate_cexp memsx ce ). Require Import Velus.RMemory. ⇒ → ¬ '. + apply Iifte with (1:=Hx) (2:=Hv) (3:=Hs1). end. Fusible s1 Proof. now apply fuse_find_method + apply cannot_write_exp_eval with (3:=Hs1) in Hx; [|now cannot_write]. Lemma map_fuse_class_c_name: Qed. Fusible s2 Qed. Require Import List. → induction ce; introsj Hxni Hcw . apply Iifte with (1:=Hx) (2:=Hv) (3:=Ht1). p, fuse_eval_eq (zip s1 s2)(Comp s1 s2). Import List.ListNotations. ∀ → specialize (IHce1_ Hxni ). Qed. map (fun cls (fuse_class cls).(c_name)) p = map c_namep . Lemma Cannot_write_in_zip: Proof. − Lemma wt_stmt_zip: Open Scope list_scope. ⇒ specialize (IHce2_ Hxni ). Proof. s1 s2x , intros s1 s2 Hfree1 Hfree2. p objs mems vars s1 s2, ∀ inversion_clear∀ Hcw; intuition. (**** Fusion functions*) inductionp ; auto. ( Can_write_inx s1 Can_write_inx s2 ) unfold fuse_eval_eq. wt_stmtp objs mems vars s1 Ltac invH := inversionH ; subst; clearH . ¬ ∧ ¬ specialize (IHce1_ Hxni ). → simpl. now rewrite IHp, fuse_class_c_name. Can_write_inx (zip s1 s2). split; [| split]. − wt_stmtp objs mems vars s2 ↔ ¬ specialize (IHce2_ Hxni ). → Fixpoint zip s1 s2 : stmt := Qed. Proof. rewrite zip_Comp' with (1:=Hfree1); reflexivity. wt_stmtp objs mems vars (zip s1 s2). Module Type FUSION − inversion_clear Hcw; intuition. match s1, s2 with intros s1 s2x . apply zip_free_write with (1:=Hfree1) (2:=Hfree2). Proof. (Import Ids : IDS) − inversion Hcw; intuition. | Ifte e1 t1 f1, Ifte e2 t2 f2 Lemma fuse_find_method': split; introHH . intuition. − induction s1, s2; simpl; repeat inversion_clear 1; eauto using wt_stmt. (Import Op : OPERATORS) ⇒ − Qed. if equiv_decb e1 e2 f fm cls, intro Hcan; apply Can_write_in_zip in Hcan; intuition. Qed. destruct (exp_dece e0 ) as [He|Hne]. (Import OpAux : OPERATORS_AUX Op) ∀ − then Ifte e1 (zip t1 t2)(zip f1 f2) find_methodf cls .(c_methods) = Some fm split; intro Hcan; applyHH ; apply Can_write_in_zip; intuition. rewrite He, equiv_decb_refl; eauto using wt_stmt. (Import SynObc: Velus.Obc.Syntax.SYNTAX Ids Op OpAux) → − Lemma Is_free_in_tovar− : else Comp s1 s2 find_methodf (fuse_class cls).(c_methods) = Some (fuse_method fm). Qed. (* TODO: Why don't we get this automatically via the subrelation?*) apply not_equiv_decb_equiv in Hne. rewrite Hne. eauto using wt_stmt. (Import SemObc: Velus.Obc.Semantics.SEMANTICS Ids Op OpAux SynObc) memsij ty , − | Skip, s s Proof. Instance fuse_eval_eq_Proper: ∀ Qed. (Import TypObc: Velus.Obc.Typing.TYPING Ids Op OpAux SynObc SemObc) ⇒ Is_free_in_expj (tovar mems (i, ty)) i = j. | s, Skip s destruct cls; simpl. Lemma zip_free_write: Proper (eq eq eq fuse_eval_eq eq iff) stmt_eval. ↔ (Import Equ : Velus.Obc.Equiv.EQUIV Ids Op OpAux SynObc SemObc). ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ Proof. | Comp s1' s2', _ Comp s1' (zip s2' s2) induction c_methods0 as [|m ms]; inversion 1. s1 s2, Proof. Lemma zip_wt: + introsx Hin . apply Hnin in Hin. ⇒ ∀ unfold tovar. | s1, s2 Comp s1 s2 simpl. Fusible s1 intros prog' prog HR1 menv' menv HR2 env' env HR3 s1 s2 Heqr ' r HR4; p insts mems vars s1 s2, apply not_Is_defined_in_cons in Hin. (**** Determine whether an Obc command can modifya variable.*) ⇒ intros memsij ty ∀. end. destruct (ident_eq_decm .(m_name) f) as [He|Hne]. Fusible s2 subst; destructr as [menv' env']. wt_stmtp insts mems vars s1 now intuition. → destruct (PS.memi mems ); split; introHH ; → rewrite fuse_method_m_name, He, ident_eqb_refl in ∗. Fusible (zip s1 s2). unfold fuse_eval_eq in Heq. wt_stmtp insts mems vars s2 clearIH . Inductive Can_write_in : ident stmt Prop := − → (inversion_clearHH ; reflexivity || subst; now →constructor). − → → Fixpoint fuse' s1 s2 : stmt := now injection H1; intro; subst. Proof. destruct Heq as [Heq ?]. wt_stmtp insts mems vars (zip s1 s2). repeat constructor. | CWIAssign: xe , Qed. ∀ match s1, s2 with apply ident_eqb_neq in Hne. Hint Constructors Fusible Can_write_in. rewrite Heq; reflexivity. Proof. destruct eq as [x cke |x ckfe |x ck v0e ]; simpl. Can_write_inx (Assignxe ) − . , ; ; + assert ( PS.Inx mems ) as Hnxm | s1, Comp s2 s3 fuse' (zip s1 s2) s3 rewrite fuse_method_m_name, Hne in ∗. induction s1, s2; Qed Lemma Is_free_translate_lexpinduction s1: s2 simpl ¬ | CWIAssignSt: xe , ⇒ try match goal with context [if ?e1 ==b ?e2 then_ else_ ] by (intro Hin; apply Hnvi with (1:=Hin); repeat constructor). ∀ | s1, s2 zip s1 s2 inv c_nodupm0; auto. intros Hfree1 Hfree2; j memsl , ` ⇒ Can_write_inx (AssignStxe ) ⇒ : ∀ ( ) ; inversion_clear Hwsch as [|? ? Hwsch' HH Hndef]. end. Qed. inversion_clear Hfree1; Instance fuse_eval_eq_Comp_Proper Is_free_in_expj (translate_lexp memsdestructl ) Is_free_in_lexpequiv_decb e1 e2jl end. | CWIIfteTrue: xe s1 s2 , Proper (fuse_eval_eq fuse_eval_eq fuse_eval_eq) Comp. auto with obctyping; → assert ( i, Is_free_in_caexpi cke x <> i) as Hfni. ∀ simpl; ⇒ ⇒ Proof. ∀ → Can_write_inx s1 . 1; { introsi Hfree . → (* (**** Invariant sufficient to justify semantic preservation of fusion try now intuition. Proof inductionl ; simpl; inversion_clearintroH . Can_write_inx (Iftee s1 s2 ) . 2; assert (Hfree': Is_free_in_eqi (EqDefx cke )) by auto. NB: almost got rid of zip, but this function decreases on the .*) match goal with Hint Constructors Fusible inversionH . try inversion_clear | CWIIfteFalse: xe s1 s2 , ' ' . − . eapplyHH in Hfree '. ∀ first | context [equiv_decb ?e1 ?e2] destruct (equiv_decb e1 e2) eqn: introsss Hseqtt Hteq now apply Is_free_in_tovarauto with obctyping inH ; subst. Can_write_inx s2 ` ⇒ ∗. − 1. destruct Hfree' as [Hm Hnm]. → argument, whereas the remaining instance of zip requiresa (* Heq unfold fuse_eval_eq in constructor; autoinversion_clear. Can_write_inx (Iftee s1 s2 ) [ [ ']]. − . assert ( Inx inputs ) as Hninp decrease The property"Fusible(translate_eqns mems eqs)" is obtained above end; [| intuition]. destruct Hseq as Hseq Hfrees Hfrees constructor; inversionauto withH ;obctypingauto. ¬ | CWICall_ap: x xs clsif es , [ [ ']]. − . by (intro Hin; eapply Hnin; eauto; do 2 constructor). ∀ on the second argument... using scheduling assumptions for EqDef, since they are needed to rewrite equiv_decb_equiv in Heq. destruct Hteq as Hteq Hfreet Hfreet constructor; QedinversionH ; subst. Inx xs ; [| ]. − assert ( PS.Inx mems ) as Hnxm' by intuition. → treat rewrite Heq in ∗. split intuition destruct H2;[left; auto | right; auto]. ¬ Can_write_inx (Call xs clsif es ) ← , ; . : intro Hxi; rewrite Hxi in ∗; clear Hxi. Fixpoint fuse' s1 s2: stmt := the translation of merge expressions, and clocking assumptions for inversion_clear Hfree2; rewrite Hseq Hteq reflexivity Qed. Lemma fuse_wt | CWIComp1: x s1 s2, Qed. p insts mems varss , specialize (Hnm Hnxm'). ∀ match s1, s2 with EqApp and constructor; ∀ Can_write_inx s1 wt_stmtp insts mems varss eapply Hndef; intuition. → | Ifte e1 t1 f1, Ifte e2 t2 f2 EqFby. While the EqApp case can also be obtained from the scheduling repeat progress Lemma Fusible_translate_cexp: → Can_write_inx (Comp s1 s2) ⇒ : ( ). now eapply Is_variable_in_eqs_Is_defined_in_eqs. if exp_eqb e1 e2 assumptions alone, the EqFby case cannot. Consider the equations: match goal with Instance zip_fuse_eval_eq_Proper memsx ce , wt_stmtp insts mems vars fuses | CWIComp2: x s1 s2, Proper (fuse_eval_eq fuse_eval_eq fuse_eval_eq) zip. ∀ Proof. } ∀ then Ifte e1(fuse ' t1 t2)(fuse ' f1 f2) y=(true whenx):: Con Cbasex true | H1:Fusible ?s1, ⇒ ⇒ ( i, Is_free_in_cexpi ce x <> i) Can_write_inx s2 . ∀ ∗∗ →. apply Fusible_Control_caexp. → else Comp s1 s2 x= true fbyy:: Con Cbasex true H2:Fusible ?s2, Proof Fusible (translate_cexpintros WTs memsx ce ). Can_write_inx (Comp s1 s2). ' ' . → ; ; ; . introsi Hfree . | s1, Comp s2 s3 fuse' (fuse' s1 s2) s3 Hi:context [Fusible (zip__ )] introsss Hseqtt Hteq Proof. destructs auto simpl inv WTs ⇒ unfold fuse_eval_eq in ∗. match goal with H1:wt_stmt____ s1 , H2:wt_stmt____ s2 _ apply not_Can_write_in_translate_cexp. | Skip,s s These equations and their clocks are incorrect, since"Con Cbasex" Fusible (zip ?s1 ?s2) intros ∗∗ Hfree. ` ⇒ Lemma cannot_write_in_Ifte: ⇒ ` [ [ ']]. . eapply Hfni; auto. |s, Skip s requires that the clock ofx be"Cbase", whereas the second equation apply Hi with (1:=H1) (2:=H2) destruct Hseq as Hseq Hfrees Hfrees induction ce. revert s2 s1 H1 H2 end xe s1 s2 , ⇒ ⇒ [ [ ']]. ; ; . apply Fusible_translate_cexp. ∀ | Comp s1' s2', Ifte___ Comp s1' (zip s2' s2) requires that it be"Con Cbasex true". Still, we could try compiling | x, Is_free_in_expx ?e _ destruct Hteq as Hteq Hfreet Hfreet simpl; constructorinduction; s2 simpl auto using zip_wt Can_write_inx (Iftee s1 s2 ) ⇒ ` ∀ → ; [| ]; [| (1:= ) (2:= − ) . introsi Hfree ; apply Hfni; intuition. ¬ | s1, s2 Comp s1 s2 them program: introsx Hfree split split apply zip_free_write with Hfrees Hfreet [ apply IHce1; introsnow auto s2|apply WTs1 WTcompIHce2; now auto|]. ⇒ ⇒ | (1:= ') (2:= ')]. . + assert ( i, ↔ end. ifx{y= true}; | H1:context [Is_free_in_exp_ ?e _ _], apply zip_free_write with Hfrees Hfreetintrosj Hfree ';invsplit WTcomp; ∀ Can_write_inx s1 Can_write_inx s2 . → ∧ ' (1:= ). ; . Is_free_in_clocki ck ¬ ∧ ¬ *) ifx{ mem(x)=y} H2:Is_free_in_exp_ ?e _ rewrite zip_Comp with Hfrees (apply not_Can_write_in_translate_cexpapply IHs2_2 auto ; → Proof. ` ' (1:= '). ; . Can_write_ini (Callxf (hd Ids.defaultx ) specialize (H1_ H2 ) rewrite zip_Comp with Hfrees apply Is_free_in_tovarapply zip_wt in autoHfree'; ¬ Hint Constructors Can_write_in. ⇒ , ; . . step (map (translate_lexp mems) e))). Definition fuses : stmt := This program is well scheduled, but it does not satisfy the invariant | _ _ split rewrite Hseq Hteq reflexivity subst; applyQed Hfree; constructor). intros; split; intro; try (introHH ; inversion_clearHH ); intuition. ` ∧ ⇒ . { matchs with Fusible. We could imaginea weaker invariant that allows the | Can_write_in_ (zip__ ) Qed simpl; constructor; Qed. ` ¬ − : intros ∗∗ Hwrite. | Comp s1 s2 fuse' s1 s2 right-most write under an expression to change free variables in the apply Cannot_write_in_zip; intuition [ apply IHce1Lemma; now fuse_wt_programauto|apply IHce2; now auto|]. ⇒ ⇒ Lemma fuse'_Comp: G, assert (Inix ) by now inv Hwrite. | _ s expression, which suffices to justify the optimisation, but the | _ idtac introsj Hfree ';∀split; Lemma cannot_write_in_Comp: ⇒ ⇒ s2 s1, wt_programG now eapply wc_EqApp_not_Is_free_in_clock; eauto. end. preservation of this invariant under the optimisation likely becomes end. ∀ apply not_Can_write_in_translate_cexp→ ; x s1 s2, ( ). } ∀ much Qed. Fusible s1 apply Hfree; wt_program map fuse_classG Can_write_inx (Comp s1 s2) Fusible s2 Proof. ¬ Definition fuse_method (m: method): method := trickier to prove. And, in any case, such programs are fundamentally → now constructor; apply Is_free_translate_lexp with mems. ↔ matchm with incorrect. Lemma zip_Comp': stmt_eval_eq (fuse' s1 s2)(Comp s1 s2). intros ∗∗ WTG. now apply Fusible_Control_laexp. Can_write_inx s1 Can_write_inx s2 . → now constructor. ¬ ∧ ¬ mk_method name ins vars out body nodup good s1 s2, Proof. − inductionG as [|cp ]; simpl; + assert ( Is_free_in_clockx ck ) as Hnfree Proof. ⇒ ∀ Qed. ¬ mk_method name ins vars out (fuse body) nodup good What about trying to reject such programs using sem_node rather than Fusible s1 FixpointHint Constructors Fusible. zip s1 s2 inversion_clearstmt WTG as [|? ? Wtc Wtp Nodup]; constructor; auto. by (eapply wc_EqFby_not_Is_free_in_clock; eauto). Hint Constructors Can_write_in. : := induction s2; inversion_clear Wtc as (Hos & Hms). apply Fusible_Control_laexp; end. introducing clocking assumptions? The problem is that certain (stmt_eval_eq (zip s1 s2)(Comp s1 s2)). Lemma Fusible_Control_caexp− : intros; split; intro; try (introHH ; inversion_clearHH ); intuition. → ; ; . [ introsi Hfree Hcw ; inversion Hcw; subst; contradiction|intuition]. circular Proof. intros s1 Hifte1 Hifte2 simpl mems ckf ce , constructor Qed. ( '; ). ∀ + . Qed. Lemma map_m_name_fuse_methods: programs(like the one above) still havea semantics(sincex andy induction s1, s2; try now rewrite zip_Comp intuition ( i, Is_free_in_caexprewritei ck cefuse_class_c_objsCan_write_ini (f ce)) methods, are effectively always present). try rewrite stmt_eval_eq_Comp_Skip1; rewrite Comp_assoc. ∀ apply Forall_impl_In→ ¬ with (2:=Hos). Ltac cannot_write := ∀ match s1 s2 withFusible (f ce) map m_name (map fuse_method methods) = map m_name methods. *) try rewrite stmt_eval_eq_Comp_Skip2; inversion_clear Hifte2. , → intros ic Hin Hfind. Lemma translate_reset_eqns_Fusible: repeat progress Fusible (Control mems ck (f ce)). Proof. try reflexivity; rewrite IHs2_2; → apply not_None_is_Some in Hfind. eqs, match goal with Proof. ∀ intro ms; induction ms as [|m ms]; auto. Inductive Fusible : stmt Prop := inversion_clear 1; match goal with destruct Hfind as ((cls & p')& Hfind). Fusible (translate_reset_eqns eqs). | x, Is_free_in_expx_ _ intros → induction ck as [|ckIHib ]; [ now intuition|]. ` ∀ → ⇒ simpl. rewrite IHms. | IFAssign: xe , simpl; | H1:Fusible ?s1, rewrite fuse_find_class with (1:=Hfind). Proof. | Hfw:( x, Is_free_in_expx ?e _), ∀ introsf ce Hxni Hfce . ∀ → now destructm . Fusible (Assignxe ) repeat progress H2:FusibleIfte?s2 Fusible (zip e1?s1 ?s2) t1 f1 discriminateIfte. e2 t2 f2intro eqs. Hfree: Is_free_in_exp ?x ?e _ | ` simpl. , ` Qed. | IFAssignSt: xe , match goal with apply zip_free_write with (1:=H1) (2:=H2) + destructc ; simpl in ∗. unfold translate_reset_eqns. pose proof (Hfwx Hfree ); clear Hfw ∀ ⇒ destructb . ⇒ Fusible (AssignStxe ) | context [equiv_decb ?e1 ?e2] | Fusible ?s assumption clear Nodup c_nodup0 c_nodupm0 Hos IHp Wtp. assert (Fusible Skip) as Hf by auto. | _ _ split ` ` ⇒ applyIH with (f:=fun ce Ifte (tovar mems (i, bool_type)) (f ce) Skip). ( : ): := | : , ( ) : ; | H:Fusible s2_2 _ pose proof (fuse_eval_eq_refl_H ) − induction⇒ c_methods0 as [|m ms]; simpl; auto using Forall_nil. revert Hf. generalize⇒ Skip. ` ∧ ⇒ Program Definition fuse_class c class class IFIfte e s1 s2 destruct equiv_decb e1 e2 eqn Heq ` ⇒ + introsj Hfree Hcw . | Can_write_in__ intro ∀ ⇒ . . induction eqs as [|eq eqs]; intross Hf ; auto. ` ¬ ⇒ matchc with Fusible s1 (rewrite equiv_decb_equiv in Heq; rewrite Heq in ∗) end apply Hxni with (i0apply:=j); Forall_cons2 [inversion_clear in Hms Hfree; now auto|]. | H: Can_write_in_ (Comp__ ) _ inversion_clearH → ← if equiv_decb e1 e2 . . ' '. ( & ). simpl apply IHeqs ` ⇒ mk_class name mems objs methods nodup nodupm Fusible s2 || rewrite not_equiv_decb_equiv in Heq intros prog menv env menv env inversion_clear Hcwdestruct as [| | Hms |? ? as ? ?WTmHskipWTms| | |]; | _ now intuition ⇒ → ;[ | | ]. ; . . destruct eq; simpl; auto. ⇒ mk_class name mems objs (map fuse_method methods) nodup_ ( x, Is_free_in_expxe Can_write_inx s1 Can_write_inx s2 ) | H:Fusible ?s1, rewrite zip_Comp now apply iff_refl assumption assumption [ assumption|inversionapply Forall_cons Hskip]. auto clear IHms WTms end. ∀ → ¬ ∧ ¬ . ∗. Qed. end. IH:context [stmt_eval_eq (zip ?s1_ ) _] Qed + repeat constructorunfold;[assumption wt_method| |now in inversion 1]. → ; ∗; ∗. Next Obligation. Fusible (Iftee s1 s2 ) context [zip ?s1 ?s2] apply Hxni. destructm unfold meth_vars in simpl in Lemma cannot_write_exp_eval: ` ' : . Lemma ClassFusible_translate: now rewrite map_m_name_fuse_methods. | IFStep_ap: xs clsif es , rewriteIH with (1:=H) Instance fusethen_fuse_eval_eq_Proper Ifte e1match goal withzipclear m_nodupvars0 t1 m_good0 t2 zip f1 f2 progs menv env menv ' env' ev , ∀ ⇒ ( )( , ) Proper (fuse_eval_eq fuse_eval_eq fuse_eval_eq) fuse'. apply wt_stmt_map_fuse_class. G ∀ Qed. Fusible (Call xs clsif es ) end; ⇒ ⇒ | H:Is_free_in_exp_ (tovar mems_ ) _ renameH into Hfree ∀ ( x, Is_free_in_expxe Can_write_inxs ) . ; ` ; ⇒ ; . wc_globalG ∀ → ¬ | IFComp: s1 s2, try (rewrite lift_Ifte; [|assumption]); Proof end. destruct m_body0 simpl inv WTm eauto using wt_stmt → exp_eval menv envev ∀ ' ' . . Welldef_globalG → (**** Basic lemmas around[fuse_class] and[fuse_method].*) Fusible s1 try rewrite Comp_assoc; introsss Hseqtt Hteq unfold tovar in Hfreerevert. m_body0_1 H1 → stmt_eval prog menv envs (menv', env') → ∗. ; ; . Forall ClassFusible (translateG ). → Fusible s2 reflexivity. unfold fuse_eval_eq in destruct (PS.memi inductionmems ); inversion m_body0_2 Hfreesimpl; substeauto; now using auto .wt_stmt_zip exp_eval menv' env' ev . → else[ [ Comp']]. s1 s2 . . Proof. → Lemma fuse_class_name: Fusible (Comp s1 s2) Qed. destruct Hseq as Hseq Hfrees Hfrees applyIH with (f:=funintros ce s1Ifte WT1(tovarinv H2 mems (i, bool_type)) Skip (f ce)). Proof. [ [ ']]. − ⇒ . inductionG as [|nG ]. c,(fuse_classc ).(c_name) = c.(c_name). | IFSkip: destruct Hteq as Hteq Hfreet Hfreet + introsj Hfree Hcweauto. using wt_stmt_zip Hint Constructors Is_free_in_exp Can_write_in exp_eval. ∀ split; [| split]; [| apply fuse'_free_write with (1:=Hfrees) (2:=Hfreet) simpl. now intros; simpl; auto using Forall_nil. Proof. destructc ; auto. Qed. Fusible Skip. Lemma fuse'_free_write: apply Hxni with− (i0:=j); [inversion_clear Hfree; now auto|]. inductions ; intros menv env menv' env' e' v Hfree Hexp Hstmt. | ' (1:= ') (2:= ')]. , , . intros WcG WdG. s2 s1, apply fuse _free_write with Hfrees Hfreetinversion_clearnow Hcw rewrite as [| |? fuse_class_c_name ? ? ? Hskip| | | |]; map_map map_fuse_class_c_name inv Hstmt. ∀ ' ; . . inversion_clear WcG as [|? ? Wcn]. − Lemma fuse_method_name: Definition ClassFusible (c: class): Prop := Fusible s1 repeat rewriteSkip fuse _Comp try assumptions s[ inversionQed Hskip|assumption]. apply exp_eval_extend_env; trivial. | , . , simpl; constructor; auto. m,(fuse_methodm ).(m_name) = m.(m_name). Forall (funm Fusiblem .(m_body)) c.(c_methods). Fusible s2 rewrite Hseq Hteq intro Habs. apply (Hfreei ); auto. ∀ ⇒ → + repeat constructor;[assumption|now inversion 1|]. Proof. destructm ; auto. Qed. Fusible (fuse' s1 s2). reflexivity. Lemma fuse_wt_mem: unfold translate_node, ClassFusible. inv Hstmt. → apply Hxni. − Lemma lift_Fusible: Proof. Qed. ⇒ mepc , repeat constructor; simpl. match goal with∀ apply exp_eval_extend_mem; trivial. wt_mem mepc rewrite ps_from_list_gather_eqs_memories. Lemma fuse_method_in: e s1 s2 t1 t2, induction s2; | H:Is_free_in_exp_ (tovar mems→ _ ) _ renameH into Hfree − intro Habs. apply (Hfreei ); auto. ∀ Lemma fuse_Comps: Skip swt_mem me (map fuse_class` p )(⇒fuse_classc ). assert (NoDup_defsn .(n_eqs)). m,(fuse_methodm ).(m_in) = m.(m_in). Fusible (Comp (Iftee s1 s2 )(Iftee t1 t2 )) try (intros; apply zip_free_write; assumption). | , end. inv Hstmt. destructb ;[eapply IHs1|eapply IHs2]; ∀ s, Proof. apply NoDup_defs_NoDup_vars_defined. − Proof. destructm ; auto. Qed. intros s1 Hfree1 Hfree2. ∀ unfold tovar in Hfree. try eassumption; try now cannot_write. ↔ ∗∗ . apply NoDup_var_defined_n_eqs. Fusible (Iftee (Comp s1 t1)(Comp s2 t2)). inversion_clear Hfree2. Fusibles destruct (PS.memintrosi mems );Hwt_meminversion Hfree; subst; now auto. inv Hstmt. ⇒ pose proof (not_Exists_Is_defined_in_eqs_n_inn ) as Hin. − Lemma fuse_method_out: Proof. apply IHs2_2; [|assumption]. stmt_eval_eq (fuses ) s. induction Hwt_mem match goal with → Qed. m,(fuse_methodm ).(m_out) = m.(m_out). Hint Constructors Fusible. apply zip_free_write; assumption. Proof. Comp s1 s2 _ using wt_mem_ind_multComp s1 inv Wcnzip. inv WdG. simpl ins2∗. s2 | Hs1: stmt_eval___ s1_ , ∀ |intross Hfree prog menv env menv ' env'. ' ', with (P := fun mep cl Hwt wt_mem me (map fuse_classp )(fuse_class' eapply( cl)) translate_eqns_Fusible; eauto'. ) Proof. destructm ; auto. Qed. introse s1 s2 t1 t2 . Qed. Lemma Fusible_Control_laexp: ⇒ Hs2: stmt_eval___ s2_ _ destructs ; simpl; try reflexivity. (Pinst := fun mep oc Hwt_inst wt_mem_inst me (map fuse_class+pintros) . apply not_Is_variable_in_memories; auto. ` split; intro Hifw. mems cks , ⇒ apply IHs1 with (2:=Hexp) in Hs1; . ∀ ). + introsi ' Hin' Hdef. ⇒ Lemma fuse_find_class: inversion_clear Hifw as [| | | |? ? Hs Ht|]. (** fuse_eval_eq*) inversion_clear Hfree ( i, Is_free_in_clockoc i ck⇒Can_write_inis ) [ apply IHs2 with (2:=Hs1) (3:=Hs2)|]; − destruct s2; ∀ constructor→. ¬ apply Hin, Exists_ . p idcp ', constructor; inversion_clear Hs; inversion_clear Ht; now cannot_write. Fusibles − ∃ now cannot_write ∀ match goals1 with s2 → Comp+ rewrite fuse_class_c_memss1 s2; auto. i'. intuition. find_class idp = Some (c, p') inversion_clear Hifw as [| |? ? ? Hfree1 Hfree2 Hcw| | | ]. Require Import Relations. | , Fusible (Control mems cks ). ∃ end. → − | H: Fusible ?s2 context [fuse' _ ?s2] → + rewrite fuse_class_c_objs. apply translate_reset_eqns_Fusible. find_class id (map fuse_classp ) = Some (fuse_classc , map fuse_classp inversion_clear Hfree1; inversion_clear Hfree2. Require Import Morphisms. ` Proof. − inv Hstmt. pose proof (fuse_eval_eq_refl_H ) eapply Forall_ ; intros oc Hin. inv WdG. apply IHG; auto. − '). repeat constructor; cannot_write. Require Import Setoid. ⇒ induction ck as [|ckIHib ]; [ now intuition∀ |]. − apply exp_eval_extend_mem_by_obj. ; ⇒ [? ?]; . Qed. Proof. Qed. end eapply In_Forall inH as eauto unfold adds. intross Hxni Hfce . inductionp as [|c']; simpl; intros ∗∗ Find; try discriminate. Definition fuse_eval_eq s1 s2: Prop := rewrite fuse'_Comp; auto; reflexivity. now constructor. remember (combinel rvs ) as lr eqn:Heq. end simpl. − Qed. . simpl in ∗. End FUSIBLE. rewrite fuse_class_name. Lemma Fusible_fold_left_shift: stmt_eval_eq s1 s2 (Fusible s1 Fusible s2). assert ( x, Inx lr In (fstx ) l) as Hin ∧ ∧ destructb ; applyIH− . ∀ → destruct (ident_eqb (c_namec ') id); auto. Af (xs : listA ) iacc, econstructor 2; eauto. by (destructx ; subst; apply in_combine_l). ∀ introsj Hfree Hcw . inv Find; auto. Fusible (fold_left (funix Comp (fx ) i) xs iacc) (* Lemma fuse_call: − apply fuse_find_class. eauto. Module FusibleFun clear Heq. induction lr as [|x lr]; auto. ⇒ apply Hxni with (i0:=j); [inversion_clear Hfree; now auto|]. Qed. Print relation. pn me me ' f xss rs, Qed. (Import Ids : IDS) destructx as [xv ']. ↔ ∀ inversion_clear Hcw as [| | |? ? ? ? Hskip| | |]; (Fusible (fold_left (funix Comp (fx ) i) xs Skip) Check(fuse_eval_eq: relation stmt). Forall ClassFusiblep (Import Op : OPERATORS) apply exp_eval_extend_env. ⇒ → [ assumption|inversion Hskip]. Lemma fuse_find_method: Fusible iacc). *) stmt_call_evalp menf xss me ' rs End FUSION. (Import OpAux : OPERATORS_AUX Op) + introHH ; apply (HfreexHH ). ∧ → repeat constructor;[assumption| |now inversion 1]. idcm , Proof. stmt_call_eval (map fuse_classp ) menf xss me ' rs. − (Import NLus : Velus.NLustre.NLUSTRE Ids Op OpAux) constructor. ∀ apply Hxni. find_method id (fuse_classc ).(c_methods) = Somem Hint Constructors Fusible. Lemma fuse_eval_eq_refl: Proof. Module FusionFun (Import Obc : Velus.Obc.OBC Ids Op OpAux) change (In (fst (x, v')) l). → renameH into Hfree . m', m = fuse_methodm ' induction xs as [|x xsIH ]; [ now intuition|]. s, cut (( p me ve stmte ', (Import Ids : IDS) (Import Trans : Velus.NLustreToObc.Translation.TRANSLATION apply Hin, in_eq. ∃ ∀ Fixpoint∀ fuse destructs1(PS .mems2i mems ); inversion Hfree;stmtsubst; now auto. find_method idc .(c_methods) = Somem '. intros; split. Fusibles stmt_evalp me ve stmte ' ' (Import Op : OPERATORS) := Ids Op OpAux NLus.Syn Obc.Syn NLus.Mem) + apply IHlr. introsy Hin '. apply Hin. ∧ → introsj Hfree Hcw . Proof. introHH . simpl inHH . applyIH inHH . Proper fuse_eval_eqs . Forall ClassFusiblep − (Import OpAux: OPERATORS_AUX Op) <: FUSIBLE Ids Op OpAux NLus Obc Trans. constructor (assumption). − → → apply Hxni with (i0:=j); [inversion_clear Hfree; now auto|]. intros ∗∗ Find. destructHH as [Hxs Hiacc]. Proof. stmt_eval (map fuse_classp ) me ve stmte ') (Import SynObc: Velus.Obc.Syntax.SYNTAX Ids Op OpAux) now inv Hstmt. inversion_clear Hcw as [| |? ? ? ? Hskip| | | | ]; − destructc as [? ? ? meths ? Nodup]; simpl in ∗. split;[ simpl; rewriteIH |]; intross Hfree ; unfold Proper, fuse_eval_eq; intuition. ( p me clsidf vs me ' rvs, (Import SemObc: Velus.Obc.Semantics.SEMANTICS Ids Op OpAux SynObcInclude) FUSIBLE Ids Op OpAux NLus Obc Trans. Qed. ∧ ∀ [ inversion Hskip|assumption]. induction meths as [|m']; simpl in ∗; try discriminate. repeat progress match goal with Qed. matchstmt_call_eval p me s1clsidf vs me ' rvs s2 with(Import TypObc: Velus.Obc.Typing.TYPING Ids Op OpAux SynObc SemObc) , → repeat constructor;[assumption|now inversion 1|]. inv Nodup; auto. | H:Fusible (Comp__ ) _ inversion_clearH Forall ClassFusiblep − (Import Equ : Velus.Obc.Equiv.EQUIV Ids Op OpAux SynObc SemObcEnd) FusibleFun. Lemma lift_Ifte: ` ⇒ → apply Hxni. rewrite fuse_method_name in Find. | _ now intuition Lemma fuse_eval_eq_trans: stmt_call_eval (map fuse_classp ) me clsidf vs me ' rvs)). <: FUSION Ids Op OpAux SynObc SemObc TypObc Equ. e s1 s2 t1 t2, ⇒ renameH into Hfree . ∀ destruct (ident_eqb (m_namem ') id); auto. end. transitive stmt fuse_eval_eq. now destruct 1 as (Hf1 & Hf2); intros; apply Hf2; auto. ( x, Is_free_in_expxe destruct (PS.memi mems ); inversion Hfree; subst; now auto. ∀ inv Find. intros [HH0 HH1]. Proof. apply stmt_eval_call_ind; intros; eauto using stmt_eval. Include FUSION Ids Op OpAux SynObc SemObc TypObc Equ. ( Can_write_inx s1 Can_write_inx s2 )) − s1 Comp s2Qed. s3 fuse zip s1 s2 s3 → ¬ ∧ ¬ m'; auto. simpl in HH0; rewriteIH in HH0 . intros s1 s2 s3 Heq1 Heq2. |pose proof (find_class_In, ____H ) as Hinp. ' ( ) stmt_eval_eq (Comp (Iftee s1 s2 )(Iftee t1 t2 )) ∃ → Qed. simpl; rewriteIH . unfold fuse_eval_eq in ∗. pose proof (find_method_In___ H0 ) as Hinc. End FusionFun. (Iftee (Comp s1 t1)(Comp s2 t2)). Lemma translate_eqns_Fusible: intuition. split; [| now intuition]. pose proof (find_class_app____H ) as Hprog'. Proof. C mems inputs eqs, ⇒ . ∀ . . . Lemma fuse_class_c_objs: repeat progress match goal with destruct Heq1 as [Heq1 ?]. apply fuse_find_class inH wc_envC Require Import Coq FSets FMapPositive Hint Constructors stmt_eval. ' . . c, | H:Fusible (Comp__ ) _ inversion_clearH destruct Heq2 as [Heq2 ?]. apply fuse_find_methods1 in H0 s2 zipForall ( wc_equationRequires1 ImportC ) eqsPAriths2 introse s1 s2 t1 t2 Hfw prog menv env menv ' env'. ∀ ` ⇒ | , → (fuse_classc ).(c_objs) = c.(c_objs). | _ now intuition rewrite Heq1, Heq2; reflexivity. econstructor; eauto. Require Import Velus.Common. split; intro Hstmt. ⇒ Is_well_sch mems inputs eqs Proof. end. Qed. 2:now rewrite fuse_method_out; eassumption. → Require Import Velus.Operators. inversion_clear Hstmt as [| | |? ? ? ? ? env'' menv'' ?? Hs Ht| | ]. ( x, PS.Inx mems Is_variable_in_eqsx eqs ) − unfold fuse_class. destructc ; auto. Qed. rewrite fuse_method_in. ⇒ → ∀ → ¬ ( input, In input inputs Is_defined_in_eqs input eqs) inversion_clear Hs as [| | | |? ? ? ? ? bs ???? Hx1 Hse Hss|]; (1:= ) . → ∀ → ¬. . Qed. Lemma fuse_eval_eq_sym: apply In_Forall with H4 in Hinp Fusible (Requiretranslate_eqns Import Velus mems NLustreeqs). inversion_clear Ht as [| | | |? ? ? ? ? bt ???? Hx3 Hte Hts|]; end (1:= ) . → . . Lemma Can_write_in_zip: symmetric stmt fuse_eval_eq. apply In_Forall. with Hinp in Hinc Proof. Require Import Velus Obc destruct bs; destruct bt; econstructor; try eassumption; . . . . Lemma fuse_class_c_mems: s1 s2x , Proof. rewrite fuse_method_body intros ∗∗ Hwk RequireHwks Hwsch Import Hnvi Velus Hnin.NLustreToObc Translation repeat progress match goal with ∀ (1:= ). c, (Can_write_inx s1 Can_write_inx s2 ) intros s1 s2 Heq. rewrite fuse_Comp with Hinc induction eqs as [|eq eqsIH ]; [ now constructor|]. | H:val_to_bool_ = Some true _ apply val_to_bool_true' in ∀ ∨ . . ` ⇒ (fuse_classc ).(c_mems) = c.(c_mems). Can_write_inx (zip s1 s2). unfold fuse_eval_eq in ∗. apply H2 inversion HwksRequire as [|eq 'Importeqs' Hwkeq List Hwks']; subst. H ↔ ' ( '' & & ). . . Proof. Proof. split; [| now intuition]. destruct Hprog as cls Hprog Hfind specialize (IHImport Hwks' List(Is_well_sch_consListNotations____ Hwsch )). | H:val_to_bool_ = Some false _ apply val_to_bool_false' . . ` ⇒ unfold fuse_class. destructc ; auto. Hint Constructors Can_write_in. destruct Heq as [Heq ?]. rewrite Hprog in H4 unfold translate_eqnsOpen Scope. list_scope inH . Qed. induction s1, s2; simpl; rewrite Heq; reflexivity. apply Forall_app in H4 simpl; apply Fusible_fold_left_shift. end; subst. . repeat progress Qed. rewrite Forall_cons2 in H4 split. Module Type FUSIBLE + econstructor (eassumption). . ( : ) Lemma fuse_class_c_name: match goal with intuition applyIH . Import Ids IDS + apply cannot_write_exp_eval with (3:=Hss) in Hx1; [|now cannot_write]. DefinitionQed. fuse− s (Import stmtOp : OPERATORS) c, | H:Can_write_in_ (Comp__ ) _ inversionH ; subst; clear Add Relation stmt (fuse_eval_eq) + introsx Hin ; :apply Hnvi in Hin. := apply exp_eval_det with (1:=Hx3) in Hx1. ∀ ` ⇒ (fuse_classc ).(c_name) = c.(c_name). H symmetry proved by fuse_eval_eq_sym (Import OpAux : OPERATORS_AUX Op) exfalso; now apply true_not_false_val. apply not_Is_variable_in_cons in Hin. Proof. | H:Can_write_in_ (Ifte___ ) _ inversionH ; subst; transitivity proved by fuse_eval_eq_trans (**** Fusion preserves well-typing.*) (Import NLus : Velus.NLustre.NLUSTRE Ids Op OpAux) + apply cannot_write_exp_eval with (3:=Hss) in Hx1; [|now cannot_write]. ` ⇒ now intuition. unfold fuse_class. destructc ; auto. clearH as fuse_eval_equiv. (Import Obc : Velus.Obc.OBC Ids Op OpAux) apply exp_eval_det with (1:=Hx3) in Hx1. Qed. | H:Can_write_in_ Skip _ now inversionH matchs with ` ⇒ | H:Can_write_in__ Can_write_in__ _ destructH ∨ ` ⇒ | context [equiv_decb ?e1 ?e2] ` ⇒ destruct (equiv_decb e1 e2) eqn:Heq | Comp s1 s2 fuse' s1 s2 ⇒ | _ s end ⇒ . 101 / / 2 20 2 / 2 3 / 2 4 / 2 Lemma fuse_method_m_name: m, ∀ exfalso; now apply true_not_false_val. (fuse_methodm ).(m_name) = m.(m_name). Require Import Coq.FSets.FMapPositive. + econstructor (eassumption). Proof. Lemma wt_stmt_map_fuse_class: Require Import PArith. (Import Trans : Velus.NLustreToObc.Translation.TRANSLATION inversion_clear Hstmt as [| | | |? ? ? ? ? ? ? ? ? ? Hx Hv Hs|]. unfold fuse_method; destructm ; auto. destruct (equiv_decb e1 e2) eqn:Heq Instance subrelation_stmt_fuse_eval_eq: p objs mems vars body, Require Import Velus.Common. − ∀ Ids Op OpAux NLus.Syn Obc.Syn NLus.Mem). destructb ; assert (Hv':=Hv); Qed. | Can_write_in_ (Ifte___ ) subrelation fuse_eval_eq stmt_eval_eq. wt_stmtp objs mems vars body Require Import Velus.Operators. ` ⇒ → [ apply val_to_bool_true' in Hv' (apply CWIIfteTrue; apply IHs1_1; now intuition) Proof. wt_stmt (map fuse_classp ) objs mems vars body. Require Import Velus.Obc.Syntax. (**** Show that the Obc code that results from translating an NLustre | apply val_to_bool_false' in Hv']; subst; Lemma fuse_method_body: || (apply CWIIfteFalse; apply IHs1_2; now intuition) intros s1 s2 Heqx menv env menv ' env'. Proof. Require Import Velus.Obc.Semantics. program satisfies the[Fusible] invariant, and thus that fusion inversion_clear Hs as [| | |? ? ? ? ? env'' menv'' ?? Hs1 Ht1| | ]; fm, | H:Can_write_in_ (zip__ ) _ now apply Heq. induction body; inversion_clear 1; eauto using wt_stmt. Require Import Velus.Obc.Typing. ∀ ` ⇒ preserves its semantics.*) apply Icomp with (menv1:=menv'')(env1:=env''). (fuse_method fm).(m_body) = fuse fm.(m_body). apply IHs1_1 inH || apply IHs1_2 inH Qed. eapply wt_Call Require Import Velus.Obc.Equiv. ( := )( ':= ')( := ); + apply Iifte with (1:=Hx) (2:=Hv) (3:=Hs1). Proof. | Can_write_in_ (Comp_ (zip__ )) Lemma not_Can_write_in_translate_cexpwith cls fuse_class: cls p map fuse_classp fm fuse_method fm ` ⇒ : ; ( ; ). + apply cannot_write_exp_eval with (3:=Hs1) in Hx; [|now cannot_write]. now destruct fm. now (apply CWIComp2; apply IHs1_2; intuition) Lemma zip_Comp x mems cei , auto try now destruct fm auto Require Import Velus.NLustre.Syntax. s1 s2, ∀ erewrite fuse_find_class; eauto. apply Iifte with (1:=Hx) (2:=Hv) (3:=Ht1). Qed. | _ intuition ∀ x <> i Can_write_ini (translate_cexp memsx ce ). Require Import Velus.RMemory. ⇒ → ¬ '. + apply Iifte with (1:=Hx) (2:=Hv) (3:=Hs1). end. Fusible s1 Proof. now apply fuse_find_method + apply cannot_write_exp_eval with (3:=Hs1) in Hx; [|now cannot_write]. Lemma map_fuse_class_c_name: Qed. Fusible s2 Qed. Require Import List. → induction ce; introsj Hxni Hcw . apply Iifte with (1:=Hx) (2:=Hv) (3:=Ht1). p, fuse_eval_eq (zip s1 s2)(Comp s1 s2). Import List.ListNotations. ∀ → specialize (IHce1_ Hxni ). Qed. map (fun cls (fuse_class cls).(c_name)) p = map c_namep . Lemma Cannot_write_in_zip: Proof. − Lemma wt_stmt_zip: Open Scope list_scope. ⇒ specialize (IHce2_ Hxni ). Proof. s1 s2x , intros s1 s2 Hfree1 Hfree2. p objs mems vars s1 s2, ∀ inversion_clear∀ Hcw; intuition. (**** Fusion functions*) inductionp ; auto. ( Can_write_inx s1 Can_write_inx s2 ) unfold fuse_eval_eq. wt_stmtp objs mems vars s1 Ltac invH := inversionH ; subst; clearH . ¬ ∧ ¬ specialize (IHce1_ Hxni ). → simpl. now rewrite IHp, fuse_class_c_name. Can_write_inx (zip s1 s2). split; [| split]. − wt_stmtp objs mems vars s2 ↔ ¬ specialize (IHce2_ Hxni ). → Fixpoint zip s1 s2 : stmt := Qed. Proof. rewrite zip_Comp' with (1:=Hfree1); reflexivity. wt_stmtp objs mems vars (zip s1 s2). Module Type FUSION − inversion_clear Hcw; intuition. match s1, s2 with intros s1 s2x . apply zip_free_write with (1:=Hfree1) (2:=Hfree2). Proof. (Import Ids : IDS) − inversion Hcw; intuition. | Ifte e1 t1 f1, Ifte e2 t2 f2 Lemma fuse_find_method': split; introHH . intuition. − induction s1, s2; simpl; repeat inversion_clear 1; eauto using wt_stmt. (Import Op : OPERATORS) ⇒ − Qed. if equiv_decb e1 e2 f fm cls, intro Hcan; apply Can_write_in_zip in Hcan; intuition. Qed. destruct (exp_dece e0 ) as [He|Hne]. (Import OpAux : OPERATORS_AUX Op) ∀ − then Ifte e1 (zip t1 t2)(zip f1 f2) find_methodf cls .(c_methods) = Some fm split; intro Hcan; applyHH ; apply Can_write_in_zip; intuition. rewrite He, equiv_decb_refl; eauto using wt_stmt. (Import SynObc: Velus.Obc.Syntax.SYNTAX Ids Op OpAux) → − Lemma Is_free_in_tovar− : else Comp s1 s2 find_methodf (fuse_class cls).(c_methods) = Some (fuse_method fm). Qed. (* TODO: Why don't we get this automatically via the subrelation?*) apply not_equiv_decb_equiv in Hne. rewrite Hne. eauto using wt_stmt. (Import SemObc: Velus.Obc.Semantics.SEMANTICS Ids Op OpAux SynObc) memsij ty , − | Skip, s s Proof. Instance fuse_eval_eq_Proper: ∀ Qed. (Import TypObc: Velus.Obc.Typing.TYPING Ids Op OpAux SynObc SemObc) ⇒ Is_free_in_expj (tovar mems (i, ty)) i = j. | s, Skip s destruct cls; simpl. Lemma zip_free_write: Proper (eq eq eq fuse_eval_eq eq iff) stmt_eval. ↔ (Import Equ : Velus.Obc.Equiv.EQUIV Ids Op OpAux SynObc SemObc). ⇒ ⇒ ⇒ ⇒ ⇒ ⇒ Proof. | Comp s1' s2', _ Comp s1' (zip s2' s2) induction c_methods0 as [|m ms]; inversion 1. s1 s2, Proof. Lemma zip_wt: + introsx Hin . apply Hnin in Hin. ⇒ ∀ unfold tovar. | s1, s2 Comp s1 s2 simpl. Fusible s1 intros prog' prog HR1 menv' menv HR2 env' env HR3 s1 s2 Heqr ' r HR4; p insts mems vars s1 s2, apply not_Is_defined_in_cons in Hin. (**** Determine whether an Obc command can modifya variable.*) ⇒ intros memsij ty ∀. end. destruct (ident_eq_decm .(m_name) f) as [He|Hne]. Fusible s2 subst; destructr as [menv' env']. wt_stmtp insts mems vars s1 now intuition. → destruct (PS.memi mems ); split; introHH ; → rewrite fuse_method_m_name, He, ident_eqb_refl in ∗. Fusible (zip s1 s2). unfold fuse_eval_eq in Heq. wt_stmtp insts mems vars s2 clearIH . Inductive Can_write_in : ident stmt Prop := − → (inversion_clearHH ; reflexivity || subst; now →constructor). − → → Fixpoint fuse' s1 s2 : stmt := now injection H1; intro; subst. Proof. destruct Heq as [Heq ?]. wt_stmtp insts mems vars (zip s1 s2). repeat constructor. | CWIAssign: xe , Qed. ∀ match s1, s2 with apply ident_eqb_neq in Hne. Hint Constructors Fusible Can_write_in. rewrite Heq; reflexivity. Proof. destruct eq as [x cke |x ckfe |x ck v0e ]; simpl. Can_write_inx (Assignxe ) − . , ; ; + assert ( PS.Inx mems ) as Hnxm | s1, Comp s2 s3 fuse' (zip s1 s2) s3 rewrite fuse_method_m_name, Hne in ∗. induction s1, s2; Qed Lemma Is_free_translate_lexpinduction s1: s2 simpl ¬ | CWIAssignSt: xe , ⇒ try match goal with context [if ?e1 ==b ?e2 then_ else_ ] by (intro Hin; apply Hnvi with (1:=Hin); repeat constructor). ∀ | s1, s2 zip s1 s2 inv c_nodupm0; auto. intros Hfree1 Hfree2; j memsl , ` ⇒ Can_write_inx (AssignStxe ) ⇒ : ∀ ( ) ; inversion_clear Hwsch as [|? ? Hwsch' HH Hndef]. end. Qed. inversion_clear Hfree1; Instance fuse_eval_eq_Comp_Proper Is_free_in_expj (translate_lexp memsdestructl ) Is_free_in_lexpequiv_decb e1 e2jl end. | CWIIfteTrue: xe s1 s2 , Proper (fuse_eval_eq fuse_eval_eq fuse_eval_eq) Comp. auto with obctyping; → assert ( i, Is_free_in_caexpi cke x <> i) as Hfni. ∀ simpl; ⇒ ⇒ Proof. ∀ → Can_write_inx s1 . 1; { introsi Hfree . → (* (**** Invariant sufficient to justify semantic preservation of fusion try now intuition. Proof inductionl ; simpl; inversion_clearintroH . Can_write_inx (Iftee s1 s2 ) . 2; assert (Hfree': Is_free_in_eqi (EqDefx cke )) by auto. NB: almost got rid of zip, but this function decreases on the .*) match goal with Hint Constructors Fusible inversionH . try inversion_clear | CWIIfteFalse: xe s1 s2 , ' ' . − . eapplyHH in Hfree '. ∀ first | context [equiv_decb ?e1 ?e2] destruct (equiv_decb e1 e2) eqn: introsss Hseqtt Hteq now apply Is_free_in_tovarauto with obctyping inH ; subst. Can_write_inx s2 ` ⇒ ∗. − 1. destruct Hfree' as [Hm Hnm]. → argument, whereas the remaining instance of zip requiresa (* Heq unfold fuse_eval_eq in constructor; autoinversion_clear. Can_write_inx (Iftee s1 s2 ) [ [ ']]. − . assert ( Inx inputs ) as Hninp decrease The property"Fusible(translate_eqns mems eqs)" is obtained above end; [| intuition]. destruct Hseq as Hseq Hfrees Hfrees constructor; inversionauto withH ;obctypingauto. ¬ | CWICall_ap: x xs clsif es , [ [ ']]. − . by (intro Hin; eapply Hnin; eauto; do 2 constructor). ∀ on the second argument... using scheduling assumptions for EqDef, since they are needed to rewrite equiv_decb_equiv in Heq. destruct Hteq as Hteq Hfreet Hfreet constructor; QedinversionH ; subst. Inx xs ; [| ]. − assert ( PS.Inx mems ) as Hnxm' by intuition. → treat rewrite Heq in ∗. split intuition destruct H2;[left; auto | right; auto]. ¬ Can_write_inx (Call xs clsif es ) ← , ; . : intro Hxi; rewrite Hxi in ∗; clear Hxi. Fixpoint fuse' s1 s2: stmt := the translation of merge expressions, and clocking assumptions for inversion_clear Hfree2; rewrite Hseq Hteq reflexivity Qed. Lemma fuse_wt | CWIComp1: x s1 s2, Qed. p insts mems varss , specialize (Hnm Hnxm'). ∀ match s1, s2 with EqApp and constructor; ∀ Can_write_inx s1 wt_stmtp insts mems varss eapply Hndef; intuition. → | Ifte e1 t1 f1, Ifte e2 t2 f2 EqFby. While the EqApp case can also be obtained from the scheduling repeat progress Lemma Fusible_translate_cexp: → Can_write_inx (Comp s1 s2) ⇒ : ( ). now eapply Is_variable_in_eqs_Is_defined_in_eqs. if exp_eqb e1 e2 assumptions alone, the EqFby case cannot. Consider the equations: match goal with Instance zip_fuse_eval_eq_Proper memsx ce , wt_stmtp insts mems vars fuses | CWIComp2: x s1 s2, Proper (fuse_eval_eq fuse_eval_eq fuse_eval_eq) zip. ∀ Proof. } ∀ then Ifte e1(fuse ' t1 t2)(fuse ' f1 f2) y=(true whenx):: Con Cbasex true | H1:Fusible ?s1, ⇒ ⇒ ( i, Is_free_in_cexpi ce x <> i) Can_write_inx s2 . ∀ ∗∗ →. apply Fusible_Control_caexp. → else Comp s1 s2 x= true fbyy:: Con Cbasex true H2:Fusible ?s2, Proof Fusible (translate_cexpintros WTs memsx ce ). Can_write_inx (Comp s1 s2). ' ' . → ; ; ; . introsi Hfree . | s1, Comp s2 s3 fuse' (fuse' s1 s2) s3 Hi:context [Fusible (zip__ )] introsss Hseqtt Hteq Proof. destructs auto simpl inv WTs ⇒ unfold fuse_eval_eq in ∗. match goal with H1:wt_stmt____ s1 , H2:wt_stmt____ s2 _ apply not_Can_write_in_translate_cexp. | Skip,s s These equations and their clocks are incorrect, since"Con Cbasex" Fusible (zip ?s1 ?s2) intros ∗∗ Hfree. ` ⇒ Lemma cannot_write_in_Ifte: ⇒ ` [ [ ']]. . eapply Hfni; auto. |s, Skip s requires that the clock ofx be"Cbase", whereas the second equation apply Hi with (1:=H1) (2:=H2) destruct Hseq as Hseq Hfrees Hfrees induction ce. revert s2 s1 H1 H2 end xe s1 s2 , ⇒ ⇒ [ [ ']]. ; ; . apply Fusible_translate_cexp. ∀ | Comp s1' s2', Ifte___ Comp s1' (zip s2' s2) requires that it be"Con Cbasex true". Still, we could try compiling | x, Is_free_in_expx ?e _ destruct Hteq as Hteq Hfreet Hfreet simpl; constructorinduction; s2 simpl auto using zip_wt Can_write_inx (Iftee s1 s2 ) ⇒ ` ∀ → ; [| ]; [| (1:= ) (2:= − ) . introsi Hfree ; apply Hfni; intuition. ¬ | s1, s2 Comp s1 s2 them program: introsx Hfree split split apply zip_free_write with Hfrees Hfreet [ apply IHce1; introsnow auto s2|apply WTs1 WTcompIHce2; now auto|]. ⇒ ⇒ | (1:= ') (2:= ')]. . + assert ( i, ↔ end. ifx{y= true}; | H1:context [Is_free_in_exp_ ?e _ _], apply zip_free_write with Hfrees Hfreetintrosj Hfree ';invsplit WTcomp; ∀ Can_write_inx s1 Can_write_inx s2 . → ∧ ' (1:= ). ; . Is_free_in_clocki ck ¬ ∧ ¬ *) ifx{ mem(x)=y} H2:Is_free_in_exp_ ?e _ rewrite zip_Comp with Hfrees (apply not_Can_write_in_translate_cexpapply IHs2_2 auto ; → Proof. ` ' (1:= '). ; . Can_write_ini (Callxf (hd Ids.defaultx ) specialize (H1_ H2 ) rewrite zip_Comp with Hfrees apply Is_free_in_tovarapply zip_wt in autoHfree'; ¬ Hint Constructors Can_write_in. ⇒ , ; . . step (map (translate_lexp mems) e))). Definition fuses : stmt := This program is well scheduled, but it does not satisfy the invariant | _ _ split rewrite Hseq Hteq reflexivity subst; applyQed Hfree; constructor). intros; split; intro; try (introHH ; inversion_clearHH ); intuition. ` ∧ ⇒ . { matchs with Fusible. We could imaginea weaker invariant that allows the | Can_write_in_ (zip__ ) Qed simpl; constructor; Qed. ` ¬ − : intros ∗∗ Hwrite. | Comp s1 s2 fuse' s1 s2 right-most write under an expression to change free variables in the apply Cannot_write_in_zip; intuition [ apply IHce1Lemma; now fuse_wt_programauto|apply IHce2; now auto|]. ⇒ ⇒ Lemma fuse'_Comp: G, assert (Inix ) by now inv Hwrite. | _ s expression, which suffices to justify the optimisation, but the | _ idtac introsj Hfree ';∀split; Lemma cannot_write_in_Comp: ⇒ ⇒ s2 s1, wt_programG now eapply wc_EqApp_not_Is_free_in_clock; eauto. end. preservation of this invariant under the optimisation likely becomes end. ∀ apply not_Can_write_in_translate_cexp→ ; x s1 s2, ( ). } ∀ much Qed. Fusible s1 apply Hfree; wt_program map fuse_classG Can_write_inx (Comp s1 s2) Fusible s2 Proof. ¬ Definition fuse_method (m: method): method := trickier to prove. And, in any case, such programs are fundamentally → now constructor; apply Is_free_translate_lexp with mems. ↔ matchm with incorrect. Lemma zip_Comp': stmt_eval_eq (fuse' s1 s2)(Comp s1 s2). intros ∗∗ WTG. now apply Fusible_Control_laexp. Can_write_inx s1 Can_write_inx s2 . → now constructor. ¬ ∧ ¬ mk_method name ins vars out body nodup good s1 s2, Proof. − inductionG as [|cp ]; simpl; + assert ( Is_free_in_clockx ck ) as Hnfree Proof. ⇒ ∀ Qed. ¬ mk_method name ins vars out (fuse body) nodup good What about trying to reject such programs using sem_node rather than Fusible s1 Hint Constructors Fusible. inversion_clear WTG as [|? ? Wtc Wtp Nodup]; constructor; auto. by (eapply wc_EqFby_not_Is_free_in_clock; eauto). Hint Constructors Can_write_in. induction s2; inversion_clear Wtc as (Hos & Hms). apply Fusible_Control_laexp; end. introducing clocking assumptions? The problem is that certain (stmt_eval_eq (zip s1 s2)(Comp s1 s2)). Lemma Fusible_Control_caexp− : intros; split; intro; try (introHH ; inversion_clearHH ); intuition. → ; ; . [ introsi Hfree Hcw ; inversion Hcw; subst; contradiction|intuition]. circular Proof. intros s1 Hifte1 Hifte2 simpl mems ckf ce , constructor Qed. ( '; ). ∀ + . Qed. Lemma map_m_name_fuse_methods: programs(like the one above) still havea semantics(sincex andy induction s1, s2; try now rewrite zip_Comp intuition ( i, Is_free_in_caexprewritei ck cefuse_class_c_objsCan_write_ini (f ce)) methods, are effectively always present). try rewrite stmt_eval_eq_Comp_Skip1; rewrite Comp_assoc. ∀ apply Forall_impl_In→ ¬ with (2:=Hos). Ltac cannot_write := ∀ Fusible (f ce) map m_name (map fuse_method methods) = map m_name methods. *) try rewrite stmt_eval_eq_Comp_Skip2; inversion_clear Hifte2. → intros ic Hin Hfind. Lemma translate_reset_eqns_Fusible: repeat progress Fusible (Control mems ck (f ce)). Proof. try reflexivity; rewrite IHs2_2; → apply not_None_is_Some in Hfind. eqs, match goal with Proof. ∀ intro ms; induction ms as [|m ms]; auto. Inductive Fusible : stmt Prop := inversion_clear 1; match goal with destruct Hfind as ((cls & p')& Hfind). Fusible (translate_reset_eqns eqs). | x, Is_free_in_expx_ _ intros → induction ck as [|ckIHib ]; [ now intuition|]. ` ∀ → ⇒ simpl. rewrite IHms. | IFAssign: xe , simpl; | H1:Fusible ?s1, rewrite fuse_find_class with (1:=Hfind). Proof. | Hfw:( x, Is_free_in_expx ?e _), ∀ introsf ce Hxni Hfce . ∀ → now destructm . Fusible (Assignxe ) repeat progress H2:Fusible ?s2 Fusible (zip ?s1 ?s2) discriminate. intro eqs. Hfree: Is_free_in_exp ?x ?e _ ` simpl. ` Qed. | IFAssignSt: xe , match goal with apply zip_free_write with (1:=H1) (2:=H2) + destructc ; simpl in ∗. unfold translate_reset_eqns. pose proof (Hfwx Hfree ); clear Hfw ∀ ⇒ destructb . ⇒ Fusible (AssignStxe ) | context [equiv_decb ?e1 ?e2] | Fusible ?s assumption clear Nodup c_nodup0 c_nodupm0 Hos IHp Wtp. assert (Fusible Skip) as Hf by auto. | _ _ split ` ` ⇒ applyIH with (f:=fun ce Ifte (tovar mems (i, bool_type)) (f ce) Skip). ` ∧ ⇒ Program Definition fuse_class (c: class): class := | IFIfte: e s1 s2, destruct (equiv_decb e1 e2) eqn:Heq; | H:Fusible s2_2 _ pose proof (fuse_eval_eq_refl_H ) − induction⇒ c_methods0 as [|m ms]; simpl; auto using Forall_nil. revert Hf. generalize Skip. | Can_write_in__ intro ∀ ⇒ ` ⇒ + introsj Hfree Hcw . ` ¬ ⇒ matchc with Fusible s1 (rewrite equiv_decb_equiv in Heq; rewrite Heq in ∗) end. apply Forall_cons2 in Hms. induction eqs as [|eq eqs]; intross Hf ; auto. | H: Can_write_in_ (Comp__ ) _ inversion_clearH → ← apply Hxni with (i0:=j); [inversion_clear Hfree; now auto|]. ` ⇒ mk_class name mems objs methods nodup nodupm Fusible s2 || rewrite not_equiv_decb_equiv in Heq intros prog menv env menv' env'. destruct Hms as (WTm & WTms). simpl. apply IHeqs. | _ now intuition ⇒ → inversion_clear Hcw as [| | |? ? ? ? Hskip| | |]; ⇒ mk_class name mems objs (map fuse_method methods) nodup_ ( x, Is_free_in_expxe Can_write_inx s1 Can_write_inx s2 ) | H:Fusible ?s1, rewrite zip_Comp;[now apply iff_refl|assumption|assumption]. apply Forall_cons; auto. clear IHms WTms. destruct eq; simpl; auto. end. ∀ → ¬ ∧ ¬ [ assumption|inversion Hskip]. end. IH:context [stmt_eval_eq (zip ?s1_ ) _] Qed. unfold wt_method in ∗. Qed. → + repeat constructor;[assumption| |now inversion 1]. Next Obligation. Fusible (Iftee s1 s2 ) context [zip ?s1 ?s2] destructm ; unfold meth_vars in ∗; simpl in ∗. Lemma cannot_write_exp_eval: ` apply Hxni. now rewrite map_m_name_fuse_methods. | IFStep_ap: xs clsif es , rewriteIH with (1:=H) Instance fuse'_fuse_eval_eq_Proper: clear m_nodupvars0 m_good0. Lemma ClassFusible_translate: progs menv env menv ' env' ev , ∀ ⇒ match goal with ∀ Qed. Fusible (Call xs clsif es ) end; Proper (fuse_eval_eq fuse_eval_eq fuse_eval_eq) fuse'. apply wt_stmt_map_fuse_class. G, ( x, Is_free_in_expxe Can_write_inxs ) ⇒ ⇒ | H:Is_free_in_exp_ (tovar mems_ ) _ renameH into Hfree ∀ ∀ → ¬ | IFComp: s1 s2, try (rewrite lift_Ifte; [|assumption]); Proof. destruct m_body0; simpl` ; inv⇒ WTm; eauto using wt_stmt. wc_globalG exp_eval menv envev ∀ end. → → (**** Basic lemmas around[fuse_class] and[fuse_method].*) Fusible s1 try rewrite Comp_assoc; introsss ' Hseqtt ' Hteq. revert m_body0_1 H1. Welldef_globalG stmt_eval prog menv envs (menv', env') → unfold tovar in Hfree. → → Fusible s2 reflexivity. unfold fuse_eval_eq in ∗. induction m_body0_2; simpl; eauto using wt_stmt_zip. Forall ClassFusible (translateG ). exp_eval menv' env' ev . → destruct (PS.memi mems ); inversion Hfree; subst; now auto. → Lemma fuse_class_name: Fusible (Comp s1 s2) Qed. destruct Hseq as [Hseq [Hfrees Hfrees']]. intros s1 WT1. inv H2. Proof. Proof. applyIH with (f:=fun ce Ifte (tovar mems (i, bool_type)) Skip (f ce)). c,(fuse_classc ).(c_name) = c.(c_name). | IFSkip: destruct Hteq as [Hteq [Hfreet Hfreet']]. − eauto ⇒using wt_stmt_zip. inductionG as [|nG ]. Hint Constructors Is_free_in_exp Can_write_in exp_eval. ∀ + introsj Hfree Hcw . Proof. destructc ; auto. Qed. Fusible Skip. Lemma fuse'_free_write: split; [| split]; [| apply fuse'_free_write with (1:=Hfrees) (2:=Hfreet) simpl. now intros; simpl; auto using Forall_nil. inductions ; intros menv env menv' env' e' v Hfree Hexp Hstmt. apply Hxni with− (i0:=j); [inversion_clear Hfree; now auto|]. s2 s1, | apply fuse'_free_write with (1:=Hfrees') (2:=Hfreet')]. now rewrite fuse_class_c_name, map_map, map_fuse_class_c_name. intros WcG WdG. inv Hstmt. ∀ inversion_clear Hcw as [| |? ? ? ? Hskip| | | |]; − Lemma fuse_method_name: Definition ClassFusible (c: class): Prop := Fusible s1 repeat rewrite fuse'_Comp; try assumption. Qed. inversion_clear WcG as [|? ? Wcn]. apply exp_eval_extend_env; trivial. [ inversion Hskip|assumption]. m,(fuse_methodm ).(m_name) = m.(m_name). Forall (funm Fusiblem .(m_body)) c.(c_methods). Fusible s2 rewrite Hseq, Hteq. simpl; constructor; auto. intro Habs. apply (Hfreei ); auto. ∀ ⇒ → + repeat constructor;[assumption|now inversion 1|]. Proof. destructm ; auto. Qed. Fusible (fuse' s1 s2). reflexivity. Lemma fuse_wt_mem: unfold translate_node, ClassFusible. inv Hstmt. → apply Hxni. − Lemma lift_Fusible: Proof. Qed. mepc , repeat constructor; simpl. apply exp_eval_extend_mem; trivial. match goal with∀ Lemma fuse_method_in: e s1 s2 t1 t2, induction s2; wt_mem mepc rewrite ps_from_list_gather_eqs_memories. intro Habs. apply (Hfreei ); auto. ∀ | H:Is_free_in_exp_ (tovar mems→ _ ) _ renameH into Hfree − m,(fuse_methodm ).(m_in) = m.(m_in). Fusible (Comp (Iftee s1 s2 )(Iftee t1 t2 )) try (intros; apply zip_free_write; assumption). Lemma fuse_Comp: wt_mem me (map fuse_class` p )(⇒fuse_classc ). assert (NoDup_defsn .(n_eqs)). inv Hstmt. destructb ;[eapply IHs1|eapply IHs2]; ∀ end. − Proof. destructm ; auto. Qed. intros s1 Hfree1 Hfree2. s, Proof. apply NoDup_defs_NoDup_vars_defined. try eassumption; try now cannot_write. ↔ ∀ unfold tovar in Hfree. Fusible (Iftee (Comp s1 t1)(Comp s2 t2)). inversion_clear Hfree2. Fusibles intros ∗∗ Hwt_mem. apply NoDup_var_defined_n_eqs. inv Hstmt. destruct (PS.memi mems ); inversion Hfree; subst; now auto. − Lemma fuse_method_out: Proof. apply IHs2_2; [|assumption]. stmt_eval_eq (fuses ) s. induction Hwt_mem pose proof (not_Exists_Is_defined_in_eqs_n_inn ) as Hin. match goal with → Qed. m,(fuse_methodm ).(m_out) = m.(m_out). Hint Constructors Fusible. apply zip_free_write; assumption. Proof. using wt_mem_ind_mult inv Wcn. inv WdG. simpl in ∗. | Hs1: stmt_eval___ s1_ , ∀ intross Hfree prog menv env menv ' env'. with (P := fun mep cl Hwt wt_mem me (map fuse_classp )(fuse_classeapply cl)) translate_eqns_Fusible; eauto. Proof. destructm ; auto. Qed. introse s1 s2 t1 t2 . Qed. Lemma Fusible_Control_laexp: ⇒ Hs2: stmt_eval___ s2_ _ destructs ; simpl; try reflexivity. (Pinst := fun mep oc Hwt_inst wt_mem_inst me (map fuse_class+pintros) . apply not_Is_variable_in_memories; auto. ` split; intro Hifw. mems cks , ⇒ apply IHs1 with (2:=Hexp) in Hs1; . ∀ ). + introsi ' Hin' Hdef. ⇒ Lemma fuse_find_class: inversion_clear Hifw as [| | | |? ? Hs Ht|]. (** fuse_eval_eq*) inversion_clear Hfree ( i, Is_free_in_clockoc i ck Can_write_inis ) [ apply IHs2 with (2:=Hs1) (3:=Hs2)|]; − destruct s2; ∀ constructor→. ¬ apply Hin, Exists_ . p idcp ', constructor; inversion_clear Hs; inversion_clear Ht; now cannot_write. Fusibles − ∃ now cannot_write ∀ → + ; . i'. intuition. find_class idp = Some (c, p') inversion_clear Hifw as [| |? ? ? Hfree1 Hfree2 Hcw| | | ]. Require Import Relations. match goal with Fusible (Controlrewrite mems ck sfuse_class_c_mems). auto ∃ end. → − | H: Fusible ?s2 context [fuse' _ ?s2] → + rewrite fuse_class_c_objs. apply translate_reset_eqns_Fusible. find_class id (map fuse_classp ) = Some (fuse_classc , map fuse_classp inversion_clear Hfree1; inversion_clear Hfree2. Require Import Morphisms. ` Proof. − inv Hstmt. pose proof (fuse_eval_eq_refl_H ) eapply Forall_ ; intros oc Hin. inv WdG. apply IHG; auto. − '). repeat constructor; cannot_write. Require Import Setoid. ⇒ induction ck as [|ckIHib ]; [ now intuition∀ |]. − apply exp_eval_extend_mem_by_obj. ; [? ?]; . Qed. Proof. Qed. end intross Hxni Hfce . eapply In_Forall inH as eauto unfold adds. rewrite fuse'_Comp; auto; reflexivity. now constructor. inductionp as [|c']; simpl; intros ∗∗ Find; try discriminate. Definition fuse_eval_eq s1 s2: Prop := simpl. − remember (combinel rvs ) as lr eqn:Heq. Qed. simpl in ∗. End FUSIBLE. rewrite fuse_class_name. Lemma Fusible_fold_left_shift: stmt_eval_eq s1 s2 (Fusible s1 Fusible s2). destructb ; applyIH− . assert ( x, Inx lr In (fstx ) l) as Hin ∧ ∧ 2; . ∀ → destruct (ident_eqb (c_namec ') id); auto. Af (xs : listA ) iacc, introsj Hfree Hcweconstructor. eauto by (destructx ; subst; apply in_combine_l). ∀ : − . . Module FusibleFun inv Find; auto. Fusible (fold_left (funix Comp (fx ) i) xs iacc) (* Lemma fuse_call apply Hxni with (i0apply:=j); fuse_find_class [inversion_cleareauto Hfree; now auto|]. clear Heq. induction lr as [|x lr]; auto. ⇒ pn me me ' f xss rs, Qed. (Import Ids : IDS) Qed. Print relation. ∀ inversion_clear Hcw as [| | |? ? ? ? Hskip| | |]; destructx as [xv ']. ↔ Forall ClassFusiblep (Import Op : OPERATORS) (Fusible (fold_left (funix Comp (fx ) i) xs Skip) Check(fuse_eval_eq: relation stmt). → [ assumption|inversion Hskip]. apply exp_eval_extend_env. ⇒ stmt_call_evalp menf xss me ' rs End FUSION. (Import OpAux : OPERATORS_AUX Op) Lemma fuse_find_method: Fusible iacc). *) → repeat constructor;[assumption| |now inversion 1]. + introHH ; apply (HfreexHH ). ∧ ( ) ' . − (Import NLus : Velus.NLustre.NLUSTRE Ids Op OpAux) idcm , Proof. stmt_call_eval map fuse_classp menf xss me rs apply Hxni. constructor. ∀ . (Import Obc : Velus.Obc.OBC Ids Op OpAux) find_method id (fuse_classc ).(c_methods) = Somem Hint Constructors Fusible. Lemma fuse_eval_eq_refl: Proof renameH intoModule Hfree FusionFun. change (In (fst (x, v')) l). → cut (( p me ve stmte ', (Import Ids : IDS) (Import Trans : Velus.NLustreToObc.Translation.TRANSLATION m', m = fuse_methodm ' induction xs as [|x xsIH ]; [ now intuition|]. s, ∀ destruct (PS.memi mems ); inversion Hfree; subst; now auto. apply Hin, in_eq. ∃ ∀ stmt_evalp me ve stmte ' (Import Op : OPERATORS) Ids Op OpAux NLus.Syn Obc.Syn NLus.Mem) find_method idc .(c_methods) = Somem '. intros; split. Fusibles → introsj Hfree Hcw . + apply IHlr. introsy Hin '. apply Hin. ∧ Forall ClassFusiblep − (Import OpAux: OPERATORS_AUX Op) <: FUSIBLE Ids Op OpAux NLus Obc Trans. Proof. introHH . simpl inHH . applyIH inHH . Proper fuse_eval_eqs . → apply Hxni with (i0:=j); [inversion_clear Hfree; now auto|]. constructor (assumption). − → ( ) ') ( : . . . ) intros ∗∗ Find. destructHH as [Hxs Hiacc]. Proof. stmt_eval map fuse_classp me ve stmte inversion_clear HcwImport as [||? SynObc ? ? ? HskipVelus| |Obc | |Syntax ]; SYNTAX Ids Op OpAux now inv Hstmt. ( p me clsidf vs me ' rvs, (Import SemObc: Velus.Obc.Semantics.SEMANTICS Ids Op OpAux SynObcInclude) FUSIBLE Ids Op OpAux NLus Obc Trans. − destructc as [? ? ? meths ? Nodup]; simpl in ∗. split;[ simpl; rewriteIH |]; intross Hfree ; unfold Proper, fuse_eval_eq; intuition. ∧ ∀ [ inversion Hskip|assumption]. Qed. stmt_call_evalp me clsidf vs me ' rvs (Import TypObc: Velus.Obc.Typing.TYPING Ids Op OpAux SynObc SemObc) induction meths as [|m']; simpl in ∗; try discriminate. repeat progress match goal with Qed. → repeat constructor;[assumption|now inversion 1|]. inv Nodup; auto. | H:Fusible (Comp__ ) _ inversion_clearH Forall ClassFusiblep − (Import Equ : Velus.Obc.Equiv.EQUIV Ids Op OpAux SynObc SemObcEnd) FusibleFun. Lemma lift_Ifte: ` ⇒ → apply Hxni. rewrite fuse_method_name in Find. | _ now intuition Lemma fuse_eval_eq_trans: stmt_call_eval (map fuse_classp ) me clsidf vs me ' rvs)). <: FUSION Ids Op OpAux SynObc SemObc TypObc Equ. e s1 s2 t1 t2, ⇒ renameH into Hfree . ∀ destruct (ident_eqb (m_namem ') id); auto. end. transitive stmt fuse_eval_eq. now destruct 1 as (Hf1 & Hf2); intros; apply Hf2; auto. ( x, Is_free_in_expxe destruct (PS.memi mems ); inversion Hfree; subst; now auto. ∀ inv Find. intros [HH0 HH1]. Proof. apply stmt_eval_call_ind; intros; eauto using stmt_eval. Include FUSION Ids Op OpAux SynObc SemObc TypObc Equ. ( Can_write_inx s1 Can_write_inx s2 )) − Qed. → ¬ ∧ ¬ m'; auto. simpl in HH0; rewriteIH in HH0 . intros s1 s2 s3 Heq1 Heq2. pose proof (find_class_In____H ) as Hinp. stmt_eval_eq (Comp (Iftee s1 s2 )(Iftee t1 t2 )) ∃ → Qed. simpl; rewriteIH . unfold fuse_eval_eq in ∗. pose proof (find_method_In___ H0 ) as Hinc. End FusionFun. (Iftee (Comp s1 t1)(Comp s2 t2)). Lemma translate_eqns_Fusible: intuition. split; [| now intuition]. pose proof (find_class_app____H ) as Hprog'. Proof. C mems inputs eqs, Lemma fuse_class_c_objs: repeat progress match goal with destruct Heq1 as [Heq1 ?]. apply fuse_find_class inH . ∀ Require Import Coq.FSets.FMapPositive. Hint Constructors stmt_eval. wc_envC c, | H:Fusible (Comp__ ) _ inversion_clearH destruct Heq2 as [Heq2 ?]. apply fuse_find_method' in H0. Require Import PArith. introse s1 s2 t1 t2 Hfw prog menv env menv ' env'. ∀ ` ⇒ Forall (wc_equationC ) eqs (fuse_classc ).(c_objs) = c.(c_objs). | _ now intuition rewrite Heq1, Heq2; reflexivity. econstructor; eauto. → Require Import Velus.Common. split; intro Hstmt. ⇒ Is_well_sch mems inputs eqs Proof. end. Qed. 2:now rewrite fuse_method_out; eassumption. → Require Import Velus.Operators. inversion_clear Hstmt as [| | |? ? ? ? ? env'' menv'' ?? Hs Ht| | ]. ( x, PS.Inx mems Is_variable_in_eqsx eqs ) − unfold fuse_class. destructc ; auto. Qed. rewrite fuse_method_in. → ∀ → ¬ inversion_clear Hs as [| | | |? ? ? ? ? bs ???? Hx1 Hse Hss|]; ( input, In input inputs Is_defined_in_eqs input eqs) Qed. Lemma fuse_eval_eq_sym: apply In_Forall with (1:=H4) in Hinp. → ∀ Require Import Velus→ ¬.NLustre. inversion_clear Ht as [| | | |? ? ? ? ? bt ???? Hx3 Hte Hts|]; Fusible (translate_eqns mems eqs). Lemma Can_write_in_zip: symmetric stmt fuse_eval_eq. apply In_Forall with (1:=Hinp) in Hinc. → Require Import Velus.Obc. destruct bs; destruct bt; econstructor; try eassumption; Proof. Lemma fuse_class_c_mems: s1 s2x , Proof. rewrite fuse_method_body. Require Import Velus.NLustreToObc.Translation. repeat progress match goal with ∀ intros ∗∗ Hwk Hwks Hwsch Hnvi Hnin. c, (Can_write_inx s1 Can_write_inx s2 ) intros s1 s2 Heq. rewrite fuse_Comp with (1:=Hinc). | H:val_to_bool_ = Some true _ apply val_to_bool_true' in ∀ ∨ induction eqs as [|eq eqsIH ]; [ now constructor|]. ` ⇒ (fuse_classc ).(c_mems) = c.(c_mems). Can_write_inx (zip s1 s2). unfold fuse_eval_eq in ∗. apply H2. Require Import List. H ↔ inversion Hwks as [|eq' eqs' Hwkeq Hwks']; subst. Proof. Proof. split; [| now intuition]. destruct Hprog' as (cls'' & Hprog & Hfind). Import List.ListNotations. | H:val_to_bool_ = Some false _ apply val_to_bool_false' specialize (IH Hwks' (Is_well_sch_cons____ Hwsch )). ` ⇒ unfold fuse_class. destructc ; auto. Hint Constructors Can_write_in. destruct Heq as [Heq ?]. rewrite Hprog in H4. Open Scope list_scope. inH unfold translate_eqns. Qed. induction s1, s2; simpl; rewrite Heq; reflexivity. apply Forall_app in H4. end; subst. simpl; apply Fusible_fold_left_shift. repeat progress Qed. rewrite Forall_cons2 in H4. Module Type FUSIBLE + econstructor (eassumption). split. Lemma fuse_class_c_name: match goal with intuition. (Import Ids : IDS) + apply cannot_write_exp_eval with (3:=Hss) in Hx1; [|now cannot_write]. applyIH . c, | H:Can_write_in_ (Comp__ ) _ inversionH ; subst; clear Add Relation stmt (fuse_eval_eq) Qed. − (Import Op : OPERATORS) apply exp_eval_det with (1:=Hx3) in Hx1. ∀ ` ⇒ + introsx Hin ; apply Hnvi in Hin. (fuse_classc ).(c_name) = c.(c_name). H symmetry proved by fuse_eval_eq_sym (Import OpAux : OPERATORS_AUX Op) exfalso; now apply true_not_false_val. apply not_Is_variable_in_cons in Hin. Proof. | H:Can_write_in_ (Ifte___ ) _ inversionH ; subst; transitivity proved by fuse_eval_eq_trans (**** Fusion preserves well-typing.*) (Import NLus : Velus.NLustre.NLUSTRE Ids Op OpAux) + apply cannot_write_exp_eval with (3:=Hss) in Hx1; [|now cannot_write]. ` ⇒ now intuition. unfold fuse_class. destructc ; auto. clearH as fuse_eval_equiv. (Import Obc : Velus.Obc.OBC Ids Op OpAux) apply exp_eval_det with (1:=Hx3) in Hx1. Qed. | H:Can_write_in_ Skip _ now inversionH ` ⇒ | H:Can_write_in__ Can_write_in__ _ destructH ∨ ` ⇒ | context [equiv_decb ?e1 ?e2] ` ⇒ destruct (equiv_decb e1 e2) eqn:Heq

101 / / 2 20 2 / 2 3 / 2 4 / 2 ifx then {x := false} else {x := true}; ifx then {t1} else {t2} %

fusible(s1) fusible(s2) ∀x ∈ free(e), ¬maywrite x s1 ∧ ¬maywrite x s2 fusible(s1) fusible(s2)

fusible(if e then {s1} else {s2}) fusible(s1; s2) ...

Fusion of control structures: requires invariant

ife then {s1} else {s2}; ife then {s1; t1} else {s2; t2}; ife then {t1} else {t2} w

11 / 20 fusible(s1) fusible(s2) ∀x ∈ free(e), ¬maywrite x s1 ∧ ¬maywrite x s2 fusible(s1) fusible(s2)

fusible(if e then {s1} else {s2}) fusible(s1; s2) ...

Fusion of control structures: requires invariant

ife then {s1} else {s2}; ife then {s1; t1} else {s2; t2}; ife then {t1} else {t2} w

ifx then {x := false} else {x := true}; ifx then {t1} else {t2} %

11 / 20 Fusion of control structures: requires invariant

ife then {s1} else {s2}; ife then {s1; t1} else {s2; t2}; ife then {t1} else {t2} w

ifx then {x := false} else {x := true}; ifx then {t1} else {t2} %

fusible(s1) fusible(s2) ∀x ∈ free(e), ¬maywrite x s1 ∧ ¬maywrite x s2 fusible(s1) fusible(s2)

fusible(if e then {s1} else {s2}) fusible(s1; s2) ...

11 / 20 Fusion of control structures: correctness translation eqns ;

fusible? if e ;

s1 s2 if e ;

t1 t2 if e0 ··· optimization u1 u2 preserves fusible?

General Schema • Implement optimization as a function on code. • Find invariant under which the semantics is preserved: • Satisfied by the generated code. • Preserved by (components of) the optimization.

12 / 20 Fusion of control structures: correctness translation eqns ;

fusible? if e ;

s1 s2 if e ;

t1 t2 if e0 ··· optimization u1 u2 preserves fusible? x = (merge b e1 e2)base on ck

if ck then{ ifb then{ • In a well scheduled dataflow program it is x := e1 not possible to read x before writing it. } else{ ck ck x := e2 • Compiling x = (ce) and x = (f le) gives } fusible imperative code. } 12 / 20 Fusion of control structures: correctness translation eqns ;

fusible? if e ;

s1 s2 if e ;

t1 t2 if e0 ··· optimization u1 u2 preserves fusible? x = (0 fby (x + 1))base on ck • But for fby equations, we must read x before writing it. if ck then{ mem(x) := mem(x) + 1 • A different invariant? } Once we write x, we never read it again. Trickier to express. Trickier to work with.

12 / 20 Fusion of control structures: correctness translation eqns ;

fusible? if e ;

s1 s2 if e ;

t1 t2 if e0 ··· optimization u1 u2 preserves fusible? y = (true whenx )base on x x = (true fbyy )base on x • Happily, such programs are not well clocked. if mem(x) then{ y := true C ` true :: baseC ` x :: base } C ` true when x :: base on (x = T ) if mem(x) then{ mem(x) := y C ` x :: base on (x = T ) } 12 / 20 Fusion of control structures: correctness translation eqns ;

fusible. if e ;

s1 s2 if e ;

t1 t2 if e0 ··· optimization u1 u2 preserves fusible? y = (true whenx )base on x x = (true fbyy )base on x • Happily, such programs are not well clocked. if mem(x) then{ y := true • Show that a variable x is never free in its own } clock in a well clocked program: if mem(x) then{ C 6` x :: base on ··· on x on ··· mem(x) := y • Compiling x = (v0 fby le)ck also gives fusible } imperative code. 12 / 20 Fusion of control structures: correctness translation eqns ;

fusible. if e ;

s1 s2 if e ;

t1 t2 if e0 ··· optimization u1 u2 preserves fusible?

• Define s1 ≈eval s2 Definition stmt_eval_eq s1 s2: Prop := prog menv env menv' env', ∀ stmt_eval prog menv env s1 (menv', env') ↔ stmt_eval prog menv env s2 (menv', env').

12 / 20 Fusion of control structures: correctness translation eqns ;

fusible. if e ;

s1 s2 if e ;

t1 t2 if e0 ··· optimization u1 u2 preserves fusible.

• Define s1 ≈eval s2

• Define s1 ≈fuse s2 as s1 ≈eval s2 ∧ fusible(s1) ∧ fusible(s2) • Show congruence for ;/fuse/fuse’/zip.

• Proofs by rewriting to get: fusible(s) fuse (s) ≈eval s 12 / 20 Outline

Verifying Lustre compilation in Coq

Translation correctness: SN-Lustre to Obc

Fusion of control structures

Integrating Clight operators into N-Lustre and Obc

Conclusion

13 / 20 Module Type OPERATORS.

Parameter val : Type. Parameter type : Type. Parameter const : Type.

(* Boolean values*) Parameter bool_type : type.

Parameter true_val : val. Parameter false_val : val. Axiom true_not_false_val : true_val <> false_val.

(* Constants*) Parameter type_const : const type. → Parameter sem_const : const val. → (* Operators*) Parameter unop : Type. Parameter binop : Type.

Parameter sem_unop : unop val type option val. → → → Parameter sem_binop : binop val type val type → → → → option val. → Parameter type_unop : unop type . → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS.

• Introduce an abstract interface for values, types, and operators. • Define SN-Lustre and Obc syntax and semantics against this interface. • Likewise for the SN-Lustre to Obc translation and proof.

• Instantiate with definitions for the Obc to Clight translation and proof.

14 / 20 (* Boolean values*) Parameter bool_type : type.

Parameter true_val : val. Parameter false_val : val. Axiom true_not_false_val : true_val <> false_val.

(* Constants*) Parameter type_const : const type. → Parameter sem_const : const val. → (* Operators*) Parameter unop : Type. Parameter binop : Type.

Parameter sem_unop : unop val type option val. → → → Parameter sem_binop : binop val type val type → → → → option val. → Parameter type_unop : unop type option type. → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS.

Module Type OPERATORS. • Introduce an abstract interface for values, Parameter val : Type. types, and operators. Parameter type : Type. Parameter const : Type. • Define SN-Lustre and Obc syntax and semantics against this interface. • Likewise for the SN-Lustre to Obc translation and proof.

• Instantiate with definitions for the Obc to Clight translation and proof.

14 / 20 (* Constants*) Parameter type_const : const type. → Parameter sem_const : const val. → (* Operators*) Parameter unop : Type. Parameter binop : Type.

Parameter sem_unop : unop val type option val. → → → Parameter sem_binop : binop val type val type → → → → option val. → Parameter type_unop : unop type option type. → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS.

Module Type OPERATORS. • Introduce an abstract interface for values, Parameter val : Type. types, and operators. Parameter type : Type. Parameter const : Type. • Define SN-Lustre and Obc syntax and (* Boolean values*) semantics against this interface. Parameter bool_type : type. • Likewise for the SN-Lustre to Obc Parameter true_val : val. translation and proof. Parameter false_val : val. Axiom true_not_false_val : true_val <> false_val. • Instantiate with definitions for the Obc to Clight translation and proof.

14 / 20 (* Operators*) Parameter unop : Type. Parameter binop : Type.

Parameter sem_unop : unop val type option val. → → → Parameter sem_binop : binop val type val type → → → → option val. → Parameter type_unop : unop type option type. → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS.

Module Type OPERATORS. • Introduce an abstract interface for values, Parameter val : Type. types, and operators. Parameter type : Type. Parameter const : Type. • Define SN-Lustre and Obc syntax and (* Boolean values*) semantics against this interface. Parameter bool_type : type. • Likewise for the SN-Lustre to Obc Parameter true_val : val. translation and proof. Parameter false_val : val. Axiom true_not_false_val : true_val <> false_val. • Instantiate with definitions for the Obc to (* Constants*) Parameter type_const : const type. Clight translation and proof. → Parameter sem_const : const val. →

14 / 20 Module Type OPERATORS. • Introduce an abstract interface for values, Parameter val : Type. types, and operators. Parameter type : Type. Parameter const : Type. • Define SN-Lustre and Obc syntax and (* Boolean values*) semantics against this interface. Parameter bool_type : type. • Likewise for the SN-Lustre to Obc Parameter true_val : val. translation and proof. Parameter false_val : val. Axiom true_not_false_val : true_val <> false_val. • Instantiate with definitions for the Obc to (* Constants*) Parameter type_const : const type. Clight translation and proof. → Parameter sem_const : const val. → (* Operators*) Parameter unop : Type. Parameter binop : Type.

Parameter sem_unop : unop val type option val. → → → Parameter sem_binop : binop val type val type → → → → option val. → Parameter type_unop : unop type option type. → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS. 14 / 20 Module Type OPERATORS. Module Export Op <: OPERATORS.

Parameter val : Type. Definition val: Type := Values. val. Parameter type : Type. Parameter const : Type.

(* Boolean values*) Parameter bool_type : type.

Parameter true_val : val. Inductive val: Type := Parameter false_val : val. | Vundef : val Axiom true_not_false_val : | Vint : int val → true_val <> false_val. | Vlong : int64 val → | Vfloat : float val (* Constants*) → | Vsingle : float32 val Parameter type_const : const type. → → | Vptr : block int val. Parameter sem_const : const val. → → → (* Operators*) Parameter unop : Type. Parameter binop : Type.

Parameter sem_unop : unop val type option val. → → → Parameter sem_binop : binop val type val type → → → → option val. → Parameter type_unop : unop type option type. → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS. 14 / 20 Module Type OPERATORS. Module Export Op <: OPERATORS.

Parameter val : Type. Definition val: Type := Values. val. Parameter type : Type. Parameter const : Type. Inductive type : Type := | Tint : intsize signedness type → → (* Boolean values*) | Tlong : signedness type → Parameter bool_type : type. | Tfloat : floatsize type. → Parameter true_val : val. Parameter false_val : val. Axiom true_not_false_val : true_val <> false_val.

(* Constants*) Inductive signedness : Type := Parameter type_const : const type. → | Signed : signedness Parameter sem_const : const val. → | Unsigned : signedness. (* Operators*) Inductive intsize : Type := Parameter unop Type : . | I8 : intsize(* char*) Parameter binop Type : . | I16 : intsize(* short*) | I32 : intsize(* int*) Parameter sem_unop : | IBool : intsize. (* bool*) unop val type option val. → → → Inductive floatsize : Type := Parameter sem_binop : | F32 : floatsize(* float*) binop val type val type → → → → | F64 : floatsize. (* double*) option val. → Parameter type_unop : unop type option type. → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS. 14 / 20 Module Type OPERATORS. Module Export Op <: OPERATORS.

Parameter val : Type. Definition val: Type := Values. val. Parameter type : Type. Parameter const : Type. Inductive type : Type := | Tint : intsize signedness type → → (* Boolean values*) | Tlong : signedness type → Parameter bool_type : type. | Tfloat : floatsize type. → Parameter true_val : val. Inductive const : Type := Parameter false_val : val. | Cint : int intsize signedness const → → → Axiom true_not_false_val : | Clong : int64 signedness const → → true_val <> false_val. | Cfloat : float const → | Csingle : float32 const. (* Constants*) → Parameter type_const : const type. → Parameter sem_const : const val. → (* Operators*) Parameter unop : Type. Parameter binop : Type.

Parameter sem_unop : unop val type option val. → → → Parameter sem_binop : binop val type val type → → → → option val. → Parameter type_unop : unop type option type. → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS. 14 / 20 Module Type OPERATORS. Module Export Op <: OPERATORS.

Parameter val : Type. Definition val: Type := Values. val. Parameter type : Type. Parameter const : Type. Inductive type : Type := | Tint : intsize signedness type → → (* Boolean values*) | Tlong : signedness type → Parameter bool_type : type. | Tfloat : floatsize type. → Parameter true_val : val. Inductive const : Type := Parameter false_val : val. | Cint : int intsize signedness const → → → Axiom true_not_false_val : | Clong : int64 signedness const → → true_val <> false_val. | Cfloat : float const → | Csingle : float32 const. (* Constants*) → Parameter type_const : const type. Definition true_val := Vtrue. (* Vint Int.one*) → Parameter sem_const : const val. Definition false_val := Vfalse. (* Vint Int.zero*) → (* Operators*) Lemma true_not_false_val: true_val <> false_val. Parameter unop : Type. Proof. discriminate. Qed. Parameter binop : Type. Definition bool_type : type := Tint IBool Signed. Parameter sem_unop : unop val type option val. → → → Parameter sem_binop : binop val type val type → → → → option val. → Parameter type_unop : unop type option type. → → Parameter type_binop : binop type type option type. → → → (* ...*) End OPERATORS. 14 / 20 Module Type OPERATORS. Module Export Op <: OPERATORS.

Parameter val : Type. Definition val: Type := Values. val. Parameter type : Type. Parameter const : Type. Inductive type : Type := | Tint : intsize signedness type → → (* Boolean values*) | Tlong : signedness type → Parameter bool_type : type. | Tfloat : floatsize type. → Parameter true_val : val. Inductive const : Type := Parameter false_val : val. | Cint : int intsize signedness const → → → Axiom true_not_false_val : | Clong : int64 signedness const → → true_val <> false_val. | Cfloat : float const → | Csingle : float32 const. (* Constants*) → Parameter type_const : const type. Definition true_val := Vtrue. (* Vint Int.one*) → Parameter sem_const : const val. Definition false_val := Vfalse. (* Vint Int.zero*) → (* Operators*) Lemma true_not_false_val: true_val <> false_val. Parameter unop : Type. Proof. discriminate. Qed. Parameter binop : Type. Definition bool_type : type := Tint IBool Signed. Parameter sem_unop : unop val type option val. Inductive unop : Type := → → → | UnaryOp: Cop. unary_operation unop → Parameter sem_binop : | CastOp: type unop. → binop val type val type → → → → option val. Definition binop := Cop. binary_operation. → Parameter type_unop : Definition sem_unop (uop: unop)(v: val)(ty: type): option val unop type option type. := match uop with → → | UnaryOp op sem_unary_operation opv (cltype ty) Mem. empty ⇒ Parameter type_binop : | CastOp ty' sem_castv (cltype ty)(cltype ty') Mem. empty ⇒ binop type type option type. end. → → → (* ...*) (* ...*) End OPERATORS. End Op. 14 / 20 implicit cast: x = (unsigned char) y

• No implicit casting in Obc. • Simple relation in simulation proof (equality of values). • Explicit casts simplify substitution (referential transparency).

• (+) : double → double → double • (+) : unsigned char → unsigned char → int • (+) : double → unsigned short → double

Obc Clight unsigned char x; int y;

x = y;

Operator types • (+) : int → int → int

15 / 20 implicit cast: x = (unsigned char) y

• No implicit casting in Obc. • Simple relation in simulation proof (equality of values). • Explicit casts simplify substitution (referential transparency).

• (+) : unsigned char → unsigned char → ? • (+) : double → unsigned short → double

Obc Clight unsigned char x; int y;

x = y;

Operator types • (+) : int → int → int • (+) : double → double → double

15 / 20 implicit cast: x = (unsigned char) y

• No implicit casting in Obc. • Simple relation in simulation proof (equality of values). • Explicit casts simplify substitution (referential transparency).

• (+) : double → unsigned short → double

Obc Clight unsigned char x; int y;

x = y;

Operator types • (+) : int → int → int • (+) : double → double → double • (+) : unsigned char → unsigned char → ?

15 / 20 implicit cast: x = (unsigned char) y

• No implicit casting in Obc. • Simple relation in simulation proof (equality of values). • Explicit casts simplify substitution (referential transparency).

• (+) : double → unsigned short → double

Obc Clight unsigned char x; int y;

x = y;

Operator types • (+) : int → int → int • (+) : double → double → double • (+) : unsigned char → unsigned char → int

15 / 20 implicit cast: x = (unsigned char) y

• No implicit casting in Obc. • Simple relation in simulation proof (equality of values). • Explicit casts simplify substitution (referential transparency).

Obc Clight unsigned char x; int y;

x = y;

Operator types • (+) : int → int → int • (+) : double → double → double • (+) : unsigned char → unsigned char → int • (+) : double → unsigned short → double

15 / 20 implicit cast: x = (unsigned char) y

• No implicit casting in Obc. • Simple relation in simulation proof (equality of values). • Explicit casts simplify substitution (referential transparency).

Operator types • (+) : int → int → int • (+) : double → double → double • (+) : unsigned char → unsigned char → int • (+) : double → unsigned short → double

Obc Clight varx: uint8, unsigned char x; y : int; int y; x := y x = y;

15 / 20 • No implicit casting in Obc. • Simple relation in simulation proof (equality of values). • Explicit casts simplify substitution (referential transparency).

Operator types • (+) : int → int → int • (+) : double → double → double • (+) : unsigned char → unsigned char → int • (+) : double → unsigned short → double

Obc Clight varx: uint8, unsigned char x; y : int; int y; x := y x = y;

implicit cast: x = (unsigned char) y

15 / 20 Operator types • (+) : int → int → int • (+) : double → double → double • (+) : unsigned char → unsigned char → int • (+) : double → unsigned short → double

Obc Clight varx: uint8, unsigned char x; y : int; int y; x := (y : uint8) x = y;

implicit cast: x = (unsigned char) y

• No implicit casting in Obc. • Simple relation in simulation proof (equality of values). • Explicit casts simplify substitution (referential transparency).

15 / 20 • The Clight type system is not strong enough for our purposes: • There is no typing invariant on the memory. • A _Bool is stored in 8-bits. • E.g., no way to know that y does not contain 7. • We refine the types of operators and use a typing invariant. (<): int → int → int =⇒ (<): int → int → bool (&) : bool → bool → int =⇒ (&) : bool → bool → bool

puts 1 into x.

Obc Clight var x, y : bool; _Bool x, y

x := y x = y; explicit cast not mandated implicit cast: x = (_Bool) y

Operator types: bool • _Bool: a special kind of integer that is normally 0 or 1. • x = (_Bool)7

16 / 20 • The Clight type system is not strong enough for our purposes: • There is no typing invariant on the memory. • A _Bool is stored in 8-bits. • E.g., no way to know that y does not contain 7. • We refine the types of operators and use a typing invariant. (<): int → int → int =⇒ (<): int → int → bool (&) : bool → bool → int =⇒ (&) : bool → bool → bool

Obc Clight var x, y : bool; _Bool x, y

x := y x = y; explicit cast not mandated implicit cast: x = (_Bool) y

Operator types: bool • _Bool: a special kind of integer that is normally 0 or 1. • x = (_Bool)7 puts 1 into x.

16 / 20 • The Clight type system is not strong enough for our purposes: • There is no typing invariant on the memory. • A _Bool is stored in 8-bits. • E.g., no way to know that y does not contain 7. • We refine the types of operators and use a typing invariant. (<): int → int → int =⇒ (<): int → int → bool (&) : bool → bool → int =⇒ (&) : bool → bool → bool

Operator types: bool • _Bool: a special kind of integer that is normally 0 or 1. • x = (_Bool)7 puts 1 into x.

Obc Clight var x, y : bool; _Bool x, y x := y x = y; explicit cast not mandated implicit cast: x = (_Bool) y

16 / 20 • We refine the types of operators and use a typing invariant. (<): int → int → int =⇒ (<): int → int → bool (&) : bool → bool → int =⇒ (&) : bool → bool → bool

Operator types: bool • _Bool: a special kind of integer that is normally 0 or 1. • x = (_Bool)7 puts 1 into x.

Obc Clight var x, y : bool; _Bool x, y x := y x = y; explicit cast not mandated implicit cast: x = (_Bool) y

• The Clight type system is not strong enough for our purposes: • There is no typing invariant on the memory. • A _Bool is stored in 8-bits. • E.g., no way to know that y does not contain 7.

16 / 20 Operator types: bool • _Bool: a special kind of integer that is normally 0 or 1. • x = (_Bool)7 puts 1 into x.

Obc Clight var x, y : bool; _Bool x, y x := y x = y; explicit cast not mandated implicit cast: x = (_Bool) y

• The Clight type system is not strong enough for our purposes: • There is no typing invariant on the memory. • A _Bool is stored in 8-bits. • E.g., no way to know that y does not contain 7. • We refine the types of operators and use a typing invariant. (<): int → int → int =⇒ (<): int → int → bool (&) : bool → bool → int =⇒ (&) : bool → bool → bool

16 / 20 Operator domains

• Partial operators: • integer division/modulo x/y, x % y: y = 0 ∨ (x = MIN_INT ∧ y = −1) • shifts x << y, x >> y: y < 0 ∨ y ≥ 32 • ‘Dynamic’ precondition in the existence proof. (∀i, sem_binopi <> None) • Alternative OPERATORS implementation and translation: x / y becomes if x != MIN_INT && y != 0 then x / y else 0

17 / 20 Outline

Verifying Lustre compilation in Coq

Translation correctness: SN-Lustre to Obc

Fusion of control structures

Integrating Clight operators into N-Lustre and Obc

Conclusion

18 / 20 Not cheap.

What does it cost?

• Elaborator/type checker: • 475 lines of Coq (monadic checks) + 80 lines of AST. • Rapid development and proof: 2 weeks. • N-Lustre Syntax: 82 lines of Coq (inductive datatypes) • Obc Syntax: 50 lines of Coq (inductive datatypes) • Translation function: 110 lines of Coq (functional definitions) Biernacki et al. (2008): “Clock-directed modular code gen-  • Almost direct from eration for synchronous data-flow languages” • 3 semantic models, auxiliary definitions, lemmas, etc. • Correctness proof: several months • Learning Coq / discovering proof strategy • Many elements are useful for other analyses • Still quite a complicated proof • Generation of Clight: Lélio’s talk

19 / 20 What does it cost?

• Elaborator/type checker: • 475 lines of Coq (monadic checks) + 80 lines of AST. • Rapid development and proof: 2 weeks. • N-Lustre Syntax: 82 lines of Coq (inductive datatypes) • Obc Syntax: 50 lines of Coq (inductive datatypes) • Translation function: 110 lines of Coq (functional definitions) Biernacki et al. (2008): “Clock-directed modular code gen-  • Almost direct from eration for synchronous data-flow languages” • 3 semantic models, auxiliary definitions, lemmas, etc. • Correctness proof: several months • Learning Coq / discovering proof strategy • Many elements are useful for other analyses • Still quite a complicated proof • Generation of Clight: Lélio’s talk Not cheap.

19 / 20 Intrinsic challenge: work out how to do it (simply and efficiently) Vision: verify Lustre program, get proof about assembly code • Treat machine representations and arithmetic. • Integrated verification of external host code. • More abstract models: parameters and timing properties. ‘Digitized’ formal models of Lustre and its compilation • A form of precise and executable documentation. • A base for other projects: • Trickier features: modular reset and automata; • Formal analysis of more optimization passes. Open question: what is the usefulness in practice? • Not a replacement for SCADE Suite. • Can we facilitate certification? • Can we help developers of industrial tools?

What’s it worth?

20 / 20 Vision: verify Lustre program, get proof about assembly code • Treat machine representations and arithmetic. • Integrated verification of external host code. • More abstract models: parameters and timing properties. ‘Digitized’ formal models of Lustre and its compilation • A form of precise and executable documentation. • A base for other projects: • Trickier features: modular reset and automata; • Formal analysis of more optimization passes. Open question: what is the usefulness in practice? • Not a replacement for SCADE Suite. • Can we facilitate certification? • Can we help developers of industrial tools?

What’s it worth? Intrinsic challenge: work out how to do it (simply and efficiently)

20 / 20 ‘Digitized’ formal models of Lustre and its compilation • A form of precise and executable documentation. • A base for other projects: • Trickier features: modular reset and automata; • Formal analysis of more optimization passes. Open question: what is the usefulness in practice? • Not a replacement for SCADE Suite. • Can we facilitate certification? • Can we help developers of industrial tools?

What’s it worth? Intrinsic challenge: work out how to do it (simply and efficiently) Vision: verify Lustre program, get proof about assembly code • Treat machine representations and arithmetic. • Integrated verification of external host code. • More abstract models: parameters and timing properties.

20 / 20 Open question: what is the usefulness in practice? • Not a replacement for SCADE Suite. • Can we facilitate certification? • Can we help developers of industrial tools?

What’s it worth? Intrinsic challenge: work out how to do it (simply and efficiently) Vision: verify Lustre program, get proof about assembly code • Treat machine representations and arithmetic. • Integrated verification of external host code. • More abstract models: parameters and timing properties. ‘Digitized’ formal models of Lustre and its compilation • A form of precise and executable documentation. • A base for other projects: • Trickier features: modular reset and automata; • Formal analysis of more optimization passes.

20 / 20 What’s it worth? Intrinsic challenge: work out how to do it (simply and efficiently) Vision: verify Lustre program, get proof about assembly code • Treat machine representations and arithmetic. • Integrated verification of external host code. • More abstract models: parameters and timing properties. ‘Digitized’ formal models of Lustre and its compilation • A form of precise and executable documentation. • A base for other projects: • Trickier features: modular reset and automata; • Formal analysis of more optimization passes. Open question: what is the usefulness in practice? • Not a replacement for SCADE Suite. • Can we facilitate certification? • Can we help developers of industrial tools? 20 / 20 I ReferencesI

Auger, C. (2013). “Compilation certifiée de SCADE/LUSTRE”. PhD thesis. Orsay, France: Univ. Paris Sud 11. Biernacki, D. et al. (2008). “Clock-directed modular code generation for synchronous data-flow languages”. In: Proc. 9th ACM SIGPLAN Conf. on Languages, Compilers, and Tools for Embedded Systems (LCTES 2008). ACM. Tucson, AZ, USA: ACM Press, pp. 121–130. Blazy, S., Z. Dargaye, and X. Leroy (2006). “Formal Verification of a C Compiler Front-End”. In: Proc. 14th Int. Symp. Formal Methods (FM 2006). Vol. 4085. Lecture Notes in Comp. Sci. Hamilton, Canada: Springer, pp. 460–475. Caspi, P. et al. (1987). “LUSTRE: A declarative language for programming synchronous systems”. In: Proc. 14th ACM SIGPLAN-SIGACT Symp. Principles Of Programming Languages (POPL 1987). ACM. Munich, Germany: ACM Press, pp. 178–188.

II ReferencesII

Jourdan, J.-H., F. Pottier, and X. Leroy (2012). “Validating LR(1) parsers”. In: 21st European Symposium on Programming (ESOP 2012), held as part of European Joint Conferences on Theory and Practice of Software (ETAPS 2012). Ed. by H. Seidl. Vol. 7211. Lecture Notes in Comp. Sci. Tallinn, Estonia: Springer, pp. 397–416. Leroy, X. (2009). “Formal verification of a realistic compiler”. In: Comms. ACM 52.7, pp. 107–115. The Coq Development Team (2016). The Coq proof assistant reference manual. Version 8.5. Inria. URL: http://coq.inria.fr.

III