From Coq Require Import FSets.FMapPositive.
From Coq Require Import PArith.
From Velus Require Import Common.
From Velus Require Import CommonTyping.
From Velus Require Import Environment.
From Velus Require Import Operators.
From Velus Require Import Obc.ObcSyntax.
From Velus Require Import Obc.ObcSemantics.
From Velus Require Import Obc.ObcInvariants.
From Velus Require Import Obc.ObcTyping.
From Velus Require Import Obc.Equiv.
From Velus Require Import VelusMemory.
From Coq Require Import List.
Import List.ListNotations.
Open Scope list_scope.
From Coq Require Import Relations.
From Coq Require Import Morphisms.
From Coq Require Import Setoid.
Module Type FUSION
(
Import Ids :
IDS)
(
Import Op :
OPERATORS)
(
Import OpAux :
OPERATORS_AUX Ids Op)
(
Import SynObc:
OBCSYNTAX Ids Op OpAux)
(
Import ComTyp:
COMMONTYPING Ids Op OpAux)
(
Import SemObc:
OBCSEMANTICS Ids Op OpAux SynObc)
(
Import InvObc:
OBCINVARIANTS Ids Op OpAux SynObc SemObc)
(
Import TypObc:
OBCTYPING Ids Op OpAux SynObc ComTyp SemObc)
(
Import Equ :
EQUIV Ids Op OpAux SynObc ComTyp SemObc TypObc).
Fusion functions
Definition option_map2_defaults {
A B C} (
f:
A ->
B ->
C) (
da:
A) (
db:
B) (
oa:
option A) (
ob:
option B) :
option C :=
match oa,
ob with
|
Some a,
Some b =>
Some (
f a b)
|
Some a,
None =>
Some (
f a db)
|
None,
Some b =>
Some (
f da b)
|
None,
None =>
None
end.
Fixpoint zip s1 s2 :
stmt :=
match s1,
s2 with
|
Switch e1 ss1 d1,
Switch e2 ss2 d2 =>
if e1 ==
b e2
then Switch e1 (
CommonList.map2 (
option_map2_defaults zip d1 d2)
ss1 ss2) (
zip d1 d2)
else Comp s1 s2
|
Skip,
s =>
s
|
s,
Skip =>
s
|
Comp s1'
s2',
_ =>
Comp s1' (
zip s2'
s2)
|
s1,
s2 =>
Comp s1 s2
end.
Fixpoint fuse'
s1 s2 :
stmt :=
match s1,
s2 with
|
s1,
Comp s2 s3 =>
fuse' (
zip s1 s2)
s3
|
s1,
s2 =>
zip s1 s2
end.
Definition fuse s :
stmt :=
match s with
|
Comp s1 s2 =>
fuse'
s1 s2
|
_ =>
s
end.
Definition fuse_method (
m:
method):
method :=
match m with
mk_method name ins vars out body nodup good =>
mk_method name ins vars out (
fuse body)
nodup good
end.
Lemma map_m_name_fuse_methods:
forall methods,
map m_name (
map fuse_method methods) =
map m_name methods.
Proof.
intro ms; induction ms as [|m ms]; auto.
simpl. rewrite IHms.
now destruct m.
Qed.
Program Definition fuse_class (
c:
class):
class :=
match c with
mk_class name mems objs methods nodup _ _ =>
mk_class name mems objs (
map fuse_method methods)
nodup _ _
end.
Next Obligation.
Global Program Instance fuse_class_transform_unit:
TransformUnit class class :=
{
transform_unit :=
fuse_class }.
Next Obligation.
Global Program Instance fuse_class_transform_state_unit:
TransformStateUnit class class.
Next Obligation.
Basic lemmas around fuse_class and fuse_method.
Lemma fuse_class_c_name:
forall c, (
fuse_class c).(
c_name) =
c.(
c_name).
Proof.
destruct c; auto. Qed.
Lemma fuse_class_c_objs:
forall c,
(
fuse_class c).(
c_objs) =
c.(
c_objs).
Proof.
Lemma fuse_class_c_mems:
forall c,
(
fuse_class c).(
c_mems) =
c.(
c_mems).
Proof.
Lemma fuse_method_m_name:
forall m, (
fuse_method m).(
m_name) =
m.(
m_name).
Proof.
destruct m; auto. Qed.
Lemma fuse_method_in:
forall m, (
fuse_method m).(
m_in) =
m.(
m_in).
Proof.
destruct m; auto. Qed.
Lemma fuse_method_out:
forall m, (
fuse_method m).(
m_out) =
m.(
m_out).
Proof.
destruct m; auto. Qed.
Lemma fuse_method_body:
forall fm,
(
fuse_method fm).(
m_body) =
fuse fm.(
m_body).
Proof.
now destruct fm.
Qed.
Definition fuse_program :
program ->
program :=
transform_units.
Lemma fuse_find_class:
forall p id c p',
find_class id p =
Some (
c,
p') ->
find_class id (
fuse_program p) =
Some (
fuse_class c,
fuse_program p').
Proof.
Lemma fuse_find_method:
forall id c m,
find_method id (
fuse_class c).(
c_methods) =
Some m ->
exists m',
m =
fuse_method m'
/\
find_method id c.(
c_methods) =
Some m'.
Proof.
intros *
Find.
destruct c as [? ? ?
meths ?
Nodup];
simpl in *.
induction meths as [|
m'];
simpl in *;
try discriminate.
inv Nodup;
auto.
rewrite fuse_method_m_name in Find.
destruct (
ident_eqb (
m_name m')
id);
auto.
inv Find.
exists m';
auto.
Qed.
Lemma map_fuse_class_c_name:
forall p,
map (
fun cls => (
fuse_class cls).(
c_name))
p =
map c_name p.
Proof.
Lemma fuse_find_method':
forall f fm cls,
find_method f cls.(
c_methods) =
Some fm ->
find_method f (
fuse_class cls).(
c_methods) =
Some (
fuse_method fm).
Proof.
Reading the current, or last value of a variable
Inductive read_var :=
|
RCurrent :
ident ->
read_var
|
RLast :
ident ->
read_var.
Inductive Is_free_in_exp :
read_var ->
exp ->
Prop :=
|
FreeVar:
forall i ty,
Is_free_in_exp (
RCurrent i) (
Var i ty)
|
FreeState:
forall i ty,
Is_free_in_exp (
RCurrent i) (
State i ty false)
|
FreeLast:
forall i ty,
Is_free_in_exp (
RLast i) (
State i ty true)
|
FreeUnop:
forall i op e ty,
Is_free_in_exp i e ->
Is_free_in_exp i (
Unop op e ty)
|
FreeBinop:
forall i op e1 e2 ty,
Is_free_in_exp i e1 \/
Is_free_in_exp i e2 ->
Is_free_in_exp i (
Binop op e1 e2 ty)
|
FreeValid:
forall i t,
Is_free_in_exp (
RCurrent i) (
Valid i t).
Inductive Is_free_in_stmt :
read_var ->
stmt ->
Prop :=
|
FreeAssign:
forall x y e,
Is_free_in_exp x e ->
Is_free_in_stmt x (
Assign y e)
|
FreeAssignSt:
forall x y e isreset,
Is_free_in_exp x e ->
Is_free_in_stmt x (
AssignSt y e isreset)
|
FreeSwitch1:
forall x e ss d,
Is_free_in_exp x e ->
Is_free_in_stmt x (
Switch e ss d)
|
FreeSwitch2:
forall x e ss d,
Exists (
fun s =>
Is_free_in_stmt x (
or_default d s))
ss ->
Is_free_in_stmt x (
Switch e ss d)
|
FreeCall:
forall x xs cls i f es,
Exists (
Is_free_in_exp x)
es ->
Is_free_in_stmt x (
Call xs cls i f es)
|
FreeExternCall:
forall x y f fty es,
Exists (
Is_free_in_exp x)
es ->
Is_free_in_stmt x (
ExternCall y f es fty)
|
FreeComp1:
forall x s1 s2,
Is_free_in_stmt x s1 ->
Is_free_in_stmt x (
Comp s1 s2)
|
FreeComp2:
forall x s1 s2,
Is_free_in_stmt x s2 ->
Is_free_in_stmt x (
Comp s1 s2).
Global Hint Constructors Is_free_in_stmt :
obcinv.
Lemma not_free_unop_inv :
forall i op e ty,
~
Is_free_in_exp i (
Unop op e ty) ->
~
Is_free_in_exp i e.
Proof.
Lemma not_free_binop_inv :
forall i op e1 e2 ty,
~
Is_free_in_exp i (
Binop op e1 e2 ty) ->
~
Is_free_in_exp i e1 /\ ~
Is_free_in_exp i e2.
Proof.
intros i op e1 e2 ty Hfree; split; intro H; apply Hfree;
constructor; [now left | now right].
Qed.
Ltac not_free :=
match goal with
|
H : ~
Is_free_in_exp ?
x (
Var ?
i _) |-
_ =>
let HH :=
fresh in
let Eq :=
fresh in
assert (
HH :
RCurrent i <>
x)
by (
intro Eq;
inv Eq;
subst;
apply H;
constructor);
clear H;
rename HH into H
|
H : ~
Is_free_in_exp (
RCurrent ?
x) (
State ?
i _ _) |-
_ =>
let HH :=
fresh in
let Eq :=
fresh in
assert (
HH :
i <>
x)
by (
intro Eq;
inv Eq;
subst;
apply H;
constructor);
clear H;
rename HH into H
|
H : ~
Is_free_in_exp (
RLast ?
x) (
State ?
i _ _) |-
_ =>
let HH :=
fresh in
let Eq :=
fresh in
assert (
HH :
i <>
x)
by (
intro Eq;
inv Eq;
subst;
apply H;
constructor);
clear H;
rename HH into H
|
H : ~
Is_free_in_exp ?
x (
Valid ?
i _) |-
_ =>
let HH :=
fresh in
let Eq :=
fresh in
assert (
HH :
RCurrent i <>
x)
by (
intro Eq;
inv Eq;
apply H;
constructor);
clear H;
rename HH into H
|
H : ~
Is_free_in_exp ?
x (
Unop _ _ _) |-
_ =>
apply not_free_unop_inv in H
|
H : ~
Is_free_in_exp ?
x (
Binop ?
op ?
e1 ?
e2 ?
ty) |-
_ =>
destruct (
not_free_binop_inv x op e1 e2 ty H)
end.
Determine whether an Obc command can modify a variable or state.
Inductive write_var :=
|
WCurrent:
ident ->
write_var
|
WReset :
ident ->
write_var.
Inductive Can_write_in :
write_var ->
stmt ->
Prop :=
|
CWIAssign:
forall x e,
Can_write_in (
WCurrent x) (
Assign x e)
|
CWIAssignSt:
forall x e,
Can_write_in (
WCurrent x) (
AssignSt x e false)
|
CWIAssignStReset:
forall x e,
Can_write_in (
WReset x) (
AssignSt x e true)
|
CWISwitch:
forall x e ss d,
Exists (
fun s =>
Can_write_in x (
or_default d s))
ss ->
Can_write_in x (
Switch e ss d)
|
CWICall_ap:
forall x xs cls i f es,
In x xs ->
Can_write_in (
WCurrent x) (
Call xs cls i f es)
|
CWIExternCall:
forall y f fty es,
Can_write_in (
WCurrent y) (
ExternCall y f fty es)
|
CWIComp1:
forall x s1 s2,
Can_write_in x s1 ->
Can_write_in x (
Comp s1 s2)
|
CWIComp2:
forall x s1 s2,
Can_write_in x s2 ->
Can_write_in x (
Comp s1 s2).
Global Hint Constructors Can_write_in :
obcinv.
Lemma cannot_write_in_Switch:
forall x e ss d,
~
Can_write_in x (
Switch e ss d)
<->
Forall (
fun s => ~
Can_write_in x (
or_default d s))
ss.
Proof.
intros;
split;
intro H.
-
induction ss;
constructor;
auto with obcinv.
apply IHss;
intro W;
apply H.
inv W;
constructor.
now right.
-
induction ss;
intro HH;
inv HH;
inv H;
take (
Exists _ _)
and inv it;
eauto.
apply IHss;
auto with obcinv.
Qed.
Lemma Can_write_in_Comp:
forall x s1 s2,
Can_write_in x (
Comp s1 s2) <-> (
Can_write_in x s1 \/
Can_write_in x s2).
Proof.
split; intros HH.
- inversion_clear HH; auto.
- destruct HH; auto with obcinv.
Qed.
Lemma cannot_write_in_Comp:
forall x s1 s2,
~
Can_write_in x (
Comp s1 s2)
<->
~
Can_write_in x s1 /\ ~
Can_write_in x s2.
Proof.
intros; split; intro; try (intro HH; inversion_clear HH); intuition.
Qed.
Lemma Can_write_in_Switch:
forall e ss d x,
Can_write_in x (
Switch e ss d) <-> (
Exists (
fun s =>
Can_write_in x (
or_default d s))
ss).
Proof.
split; [inversion_clear 1|intros [HH|HH]]; auto with obcinv.
Qed.
If we add irrelevent values to ve, evaluation does not change.
Lemma exp_eval_extend_venv :
forall me ve x v'
e v,
~
Is_free_in_exp (
RCurrent x)
e ->
(
exp_eval me ve e v <->
exp_eval me (
Env.add x v'
ve)
e v).
Proof.
intros me ve x v'
e v Hfree.
split;
intro Heval.
-
revert v Hfree Heval.
induction e;
intros ?
Hfree Heval;
inv Heval;
try not_free;
eauto using exp_eval.
+
erewrite <-
Env.gso;
eauto;
try constructor.
congruence.
+
constructor;
rewrite Env.gso;
auto.
congruence.
-
revert v Hfree Heval.
induction e;
intros ?
Hfree Heval;
inv Heval;
try not_free;
eauto using exp_eval.
+
erewrite Env.gso;
eauto;
try constructor.
congruence.
+
constructor;
erewrite <-
Env.gso;
eauto.
congruence.
Qed.
Lemma exp_eval_adds_extend_venv:
forall me e xs rvs ve v,
(
forall x,
In x xs -> ~
Is_free_in_exp (
RCurrent x)
e) ->
(
exp_eval me (
Env.adds_opt xs rvs ve)
e v <->
exp_eval me ve e v).
Proof.
Lemma exp_eval_adds_opt_extend_venv:
forall me e xs rvs ve v,
(
forall x,
In x xs -> ~
Is_free_in_exp (
RCurrent x)
e) ->
(
exp_eval me (
Env.adds_opt xs rvs ve)
e v <->
exp_eval me ve e v).
Proof.
If we add irrelevent values to me, evaluation does not change.
Lemma exp_eval_extend_menv :
forall me ve x v'
e v,
~
Is_free_in_exp (
RCurrent x)
e ->
~
Is_free_in_exp (
RLast x)
e ->
(
exp_eval (
add_val x v'
me)
ve e v <->
exp_eval me ve e v).
Proof.
intros me ve x v'
e v Hfree Hfreel.
split.
-
revert v Hfree.
induction e;
intros v1 Hfree Heval;
inv Heval;
try do 2
not_free;
try rewrite find_val_gso in *;
eauto using exp_eval.
+
destruct b;
not_free;
auto.
+
clear Hfree.
do 2
not_free.
eauto using exp_eval.
-
revert v Hfree.
induction e;
intros v1 Hfree Heval;
inv Heval;
try do 2
not_free;
eauto using exp_eval.
+
constructor;
rewrite find_val_gso;
auto.
destruct b;
not_free;
auto.
+
clear Hfree.
do 2
not_free.
eauto using exp_eval.
Qed.
If we add objects to me, evaluation does not change.
Lemma exp_eval_extend_menv_by_obj :
forall me ve f obj e v,
exp_eval (
add_inst f obj me)
ve e v <->
exp_eval me ve e v.
Proof.
intros me ve f v'
e v.
split;
revert v.
-
induction e;
intros v1 Heval;
inv Heval;
eauto using exp_eval.
-
induction e;
intros v1 Heval;
inv Heval;
eauto using exp_eval.
Qed.
Ltac cannot_write :=
repeat progress
match goal with
| |-
forall x,
Is_free_in_exp x _ ->
_ =>
intros
|
Hfw: (
forall x,
Is_free_in_exp x ?
e ->
_),
Hfree:
Is_free_in_exp ?
x ?
e |-
_
=>
pose proof (
Hfw x Hfree);
clear Hfw
| |-
_ /\
_ =>
split
| |- ~
Can_write_in _ _ =>
intro
|
H:
Can_write_in _ (
Comp _ _) |-
_ =>
inversion_clear H
|
_ =>
now intuition
end.
Local Hint Constructors Is_free_in_exp :
obcinv.
Lemma cannot_write_exp_eval:
forall prog s me ve me'
ve'
e v,
(
forall x,
Is_free_in_exp (
RCurrent x)
e \/
Is_free_in_exp (
RLast x)
e ->
Can_write_in (
WCurrent x)
s \/
Can_write_in (
WReset x)
s ->
False)
->
exp_eval me ve e v
->
stmt_eval prog me ve s (
me',
ve')
->
exp_eval me'
ve'
e v.
Proof.
induction s using stmt_ind2;
intros me ve me'
ve'
e'
v Hfree Hexp Hstmt.
-
inv Hstmt.
rewrite <-
exp_eval_extend_venv;
auto.
intro Habs.
apply (
Hfree x);
eauto with obcinv.
-
inv Hstmt.
eapply exp_eval_extend_menv;
eauto.
1,2:
intro Habs;
apply (
Hfree x);
auto with obcinv.
1,2:
destruct isreset;
eauto with obcinv.
-
inv Hstmt.
take (
nth_error _ _ =
_)
and eapply nth_error_In in it as Hin.
pose proof Hin as Hin';
eapply Forall_forall in Hin';
eauto;
simpl in Hin'.
cases.
eapply Hin';
eauto.
intros ???;
eapply Hfree;
eauto.
destruct H1; [
left|
right];
constructor;
apply Exists_exists;
eauto.
-
inv Hstmt.
take (
stmt_eval _ _ _ s1 _)
and eapply IHs1 in it;
eauto.
take (
stmt_eval _ _ _ s2 _)
and eapply IHs2 in it;
eauto.
1,2:
intros *
F;
specialize (
Hfree _ F);
now cannot_write.
-
inv Hstmt.
apply exp_eval_extend_menv_by_obj.
rewrite exp_eval_adds_opt_extend_venv;
auto.
intros x Hin Hfree'.
eapply Hfree;
eauto with obcinv.
-
inv Hstmt.
rewrite <-
exp_eval_extend_venv;
auto.
intros Habs.
apply (
Hfree y);
eauto with obcinv.
-
now inv Hstmt.
Qed.
Invariant sufficient to justify semantic preservation of fusion.
Inductive Fusible :
stmt ->
Prop :=
|
IFAssign:
forall x e,
Fusible (
Assign x e)
|
IFAssignSt:
forall x e isreset,
Fusible (
AssignSt x e isreset)
|
IFExternCall:
forall x f es ty,
Fusible (
ExternCall x f es ty)
|
IFSwitch:
forall e ss d,
Forall (
fun s =>
Fusible (
or_default d s))
ss ->
(
forall x,
Is_free_in_exp (
RCurrent x)
e ->
Forall (
fun s => ~(
Can_write_in (
WCurrent x) (
or_default d s) \/
Can_write_in (
WReset x) (
or_default d s)))
ss) ->
(
forall x,
Is_free_in_exp (
RLast x)
e ->
Forall (
fun s => ~
Can_write_in (
WReset x) (
or_default d s))
ss) ->
Fusible (
Switch e ss d)
|
IFStep_ap:
forall xs cls i f es,
Fusible (
Call xs cls i f es)
|
IFComp:
forall s1 s2,
Fusible s1 ->
Fusible s2 ->
(
forall x,
Can_write_in (
WCurrent x)
s1 -> ~
Is_free_in_stmt (
RLast x)
s2) ->
Fusible (
Comp s1 s2)
|
IFSkip:
Fusible Skip.
Global Hint Constructors Fusible :
obcinv.
Definition ClassFusible (
c:
class) :
Prop :=
Forall (
fun m=>
Fusible m.(
m_body))
c.(
c_methods).
Definition ProgramFusible (
p:
program) :
Prop :=
Forall ClassFusible p.(
classes).
Lemma lift_Switch:
forall e ss d1 tt d2,
(
forall x,
Is_free_in_exp (
RCurrent x)
e \/
Is_free_in_exp (
RLast x)
e ->
Forall (
fun s => ~ (
Can_write_in (
WCurrent x) (
or_default d1 s) \/
Can_write_in (
WReset x) (
or_default d1 s)))
ss) ->
stmt_eval_eq (
Comp (
Switch e ss d1) (
Switch e tt d2))
(
Switch e (
CommonList.map2 (
option_map2_defaults Comp d1 d2)
ss tt) (
Comp d1 d2)).
Proof.
intros *
Hfw prog memv env menv'
env'.
split;
intro Hstmt.
-
inversion_clear Hstmt as [| | | |? ? ? ? ?
env''
menv'' ? ?
Hs Ht| | ].
inversion_clear Hs as [| | | | |? ? ? ? ? ? ? ? ? ?
Hx1 Nths Hss|].
inversion_clear Ht as [| | | | |? ? ? ? ? ? ? ? ? ?
Hx3 Ntht Hts|].
econstructor;
eauto.
+
assert (
c0 =
c);
subst.
{
eapply cannot_write_exp_eval in Hx1;
eauto.
2:{
intros *
F.
specialize (
Hfw _ F).
apply nth_error_In in Nths.
now simpl_Forall. }
eapply exp_eval_det in Hx3;
eauto.
congruence.
}
pose proof (
conj Nths Ntht)
as Nth.
apply combine_nth_error in Nth.
rewrite map2_combine.
apply map_nth_error with (
f :=
fun '(
a,
b) =>
option_map2_defaults Comp d1 d2 a b);
eauto.
+
simpl;
unfold option_map2_defaults;
cases;
simpl in *;
eauto with obcsem.
-
inversion_clear Hstmt as [| | | | |? ? ? ? ? ? ? ? ? ?
Hx Hv Hs|].
rewrite map2_combine in Hv.
apply map_nth_error_inv in Hv as ((
s1 &
s2) &
Nth & ?);
subst.
apply combine_nth_error in Nth as (
Nths &?).
unfold option_map2_defaults in Hs;
cases;
simpl in *;
inv Hs;
do 2 (
econstructor;
eauto);
eapply cannot_write_exp_eval;
eauto;
intros *
F;
specialize (
Hfw _ F);
apply nth_error_In in Nths;
now simpl_Forall.
Qed.
Lemma zip_Comp':
forall s1 s2,
Fusible s1 ->
(
forall x,
Can_write_in (
WCurrent x)
s1 -> ~
Is_free_in_stmt (
RLast x)
s2) ->
stmt_eval_eq (
zip s1 s2) (
Comp s1 s2).
Proof.
Section CannotWriteZip.
Variables (
p:
program)
(
insts:
list (
ident *
ident))
(Γ
m:
list (
ident *
type))
(Γ
v:
list (
ident *
type)).
Lemma Can_write_in_zip:
forall s1 s2 x,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
(
Can_write_in x s1 \/
Can_write_in x s2)
<->
Can_write_in x (
zip s1 s2).
Proof.
Corollary Cannot_write_in_zip:
forall s1 s2 x,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
(~
Can_write_in x s1 /\ ~
Can_write_in x s2)
<-> ~
Can_write_in x (
zip s1 s2).
Proof.
intros s1 s2 x.
split;
intro HH.
-
intro Hcan;
eapply Can_write_in_zip in Hcan;
intuition.
-
split;
intro Hcan;
apply HH;
apply Can_write_in_zip;
intuition.
Qed.
Lemma Can_write_in_var_zip:
forall s1 s2 x,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
(
Can_write_in_var x s1 \/
Can_write_in_var x s2)
<->
Can_write_in_var x (
zip s1 s2).
Proof.
Corollary Cannot_write_in_var_zip:
forall s1 s2 x,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
(~
Can_write_in_var x s1 /\ ~
Can_write_in_var x s2)
<-> ~
Can_write_in_var x (
zip s1 s2).
Proof.
Lemma zip_free_in_stmt :
forall x s1 s2,
Is_free_in_stmt x (
zip s1 s2) ->
Is_free_in_stmt x s1 \/
Is_free_in_stmt x s2.
Proof.
Lemma zip_free_write:
forall s1 s2,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
Fusible (
Comp s1 s2) ->
Fusible (
zip s1 s2).
Proof.
Lemma wt_stmt_zip:
forall s1 s2,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
wt_stmt p insts Γ
m Γ
v (
zip s1 s2).
Proof.
induction s1 using stmt_ind2';
destruct s2;
simpl;
inversion_clear 1;
inversion_clear 1;
eauto with obctyping.
cases_eqn E;
eauto with obctyping.
rewrite equiv_decb_equiv in E;
assert (
e =
e0)
by auto;
subst.
match goal with H:
typeof _ =
_,
H':
typeof _ =
_ |-
_ =>
rewrite H in H';
inv H'
end.
assert (
length ss =
length l)
as E'
by congruence.
rewrite map2_combine.
econstructor;
eauto with obctyping.
-
rewrite map_length,
combine_length.
lia.
-
intros *
Hin;
apply in_map_iff in Hin as ((
os1,
os2) &
Eq &
Hin).
pose proof Hin as Hin';
apply in_combine_l in Hin;
apply in_combine_r in Hin'.
take (
Forall _ ss)
and apply Forall_forall with (2 :=
Hin)
in it;
eauto.
destruct os1,
os2;
simpl in *;
inv Eq;
eauto with obctyping.
Qed.
Lemma Can_write_in_var_fuse':
forall s1 s2 x,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
Can_write_in_var x (
Comp s1 s2) <->
Can_write_in_var x (
fuse'
s1 s2).
Proof.
Corollary Can_write_in_var_fuse:
forall s x,
wt_stmt p insts Γ
m Γ
v s ->
Can_write_in_var x s <->
Can_write_in_var x (
fuse s).
Proof.
destruct s; simpl; try reflexivity.
inversion_clear 1; apply Can_write_in_var_fuse'; auto.
Qed.
Lemma fuse'
_Comp:
forall s2 s1,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
Fusible (
Comp s1 s2) ->
stmt_eval_eq (
fuse'
s1 s2) (
Comp s1 s2).
Proof.
Corollary fuse_Comp:
forall s,
wt_stmt p insts Γ
m Γ
v s ->
Fusible s ->
stmt_eval_eq (
fuse s)
s.
Proof.
intros s WT Hfree prog menv env menv' env'.
destruct s; simpl; try reflexivity.
inv WT.
apply fuse'_Comp; auto.
Qed.
Lemma No_Overwrites_zip:
forall s1 s2,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
No_Overwrites (
Comp s1 s2) ->
No_Overwrites (
zip s1 s2).
Proof with
eauto with obctyping obcinv.
induction s1 using stmt_ind2;
destruct s2;
inversion_clear 1;
inversion_clear 1;
intros Hno;
inv Hno;
simpl;
eauto with obcinv;
repeat (
take (
No_Overwrites (
_ _))
and inv it).
2-7:
constructor;
eauto with obctyping obcinv;
intros;
repeat match goal with
| |- ~
_ =>
intros contra
|
H:
Can_write_in_var _ (
zip _ _) |-
_ =>
apply Can_write_in_var_zip in H as [|];
eauto with obctyping obcinv
|
Hc:
Can_write_in_var _ ?
e,
Hnc:
forall x,
_ -> ~
Can_write_in_var _ ?
e |-
_ =>
try solve [
eapply Hnc;
eauto with obcinv];
clear Hnc
|
H:
forall x,
_ ->
_ ->
_ ->
No_Overwrites (
zip ?
e1 _) |-
No_Overwrites (
zip ?
e1 _) =>
eapply H;
eauto with obctyping;
constructor;
eauto with obcinv;
intros
end.
-
destruct (
e ==
b e0)...
constructor.
rewrite map2_combine;
apply Forall_map,
Forall_forall;
intros (
os1,
os2)
Hin.
pose proof Hin as Hin';
apply in_combine_l in Hin;
apply in_combine_r in Hin'.
repeat (
take (
Forall _ ss)
and eapply Forall_forall with (2:=
Hin)
in it).
repeat (
take (
Forall _ _)
and eapply Forall_forall with (2:=
Hin')
in it).
match goal with H: (
forall x:
ident,
_),
H': (
forall x:
ident,
_) |-
_ =>
rename H into Cannot1;
rename H'
into Cannot2 end.
unfold option_map2_defaults;
cases;
simpl in *;
apply it1;
auto;
constructor;
auto;
intros x Can_s Can_t;
((
now eapply Cannot1;
constructor;
solve_Exists) ||
(
now eapply Cannot2;
constructor;
solve_Exists)).
Qed.
Lemma No_Overwrites_fuse':
forall s1 s2,
wt_stmt p insts Γ
m Γ
v s1 ->
wt_stmt p insts Γ
m Γ
v s2 ->
No_Overwrites (
Comp s1 s2) ->
No_Overwrites (
fuse'
s1 s2).
Proof.
Corollary No_Overwrites_fuse:
forall s,
wt_stmt p insts Γ
m Γ
v s ->
No_Overwrites s ->
No_Overwrites (
fuse s).
Proof.
destruct s; intros WT Hnoo; auto; inv WT.
now apply No_Overwrites_fuse'.
Qed.
End CannotWriteZip.
Lemma fuse_call:
forall p n me me'
f xss rs,
wt_program p ->
ProgramFusible p ->
stmt_call_eval p me n f xss me'
rs ->
stmt_call_eval (
fuse_program p)
me n f xss me'
rs.
Proof.
Corollary fuse_loop_call:
forall f c ins outs prog me,
wt_program prog ->
ProgramFusible prog ->
loop_call prog c f ins outs 0
me ->
loop_call (
fuse_program prog)
c f ins outs 0
me.
Proof.
intros ?????;
generalize 0%
nat.
cofix COINDHYP.
intros n me WT HCF Hdo.
destruct Hdo.
econstructor;
eauto using fuse_call.
Qed.
Fusion preserves well-typing.
Lemma wt_exp_fuse_program:
forall p Γ
m Γ
v e,
wt_exp p Γ
m Γ
v e ->
wt_exp (
fuse_program p) Γ
m Γ
v e.
Proof.
induction e;
inversion_clear 1;
eauto using wt_exp.
Qed.
Lemma wt_stmt_fuse_program:
forall p insts Γ
m Γ
v s,
wt_stmt p insts Γ
m Γ
v s ->
wt_stmt (
fuse_program p)
insts Γ
m Γ
v s.
Proof.
Lemma wt_stmt_fuse:
forall p insts Γ
m Γ
v s,
wt_stmt p insts Γ
m Γ
v s ->
wt_stmt p insts Γ
m Γ
v (
fuse s).
Proof.
intros *
WTs.
destruct s;
auto;
simpl;
inv WTs.
match goal with H1:
wt_stmt _ _ _ _ s1,
H2:
wt_stmt _ _ _ _ s2 |-
_ =>
revert s2 s1 H1 H2 end.
induction s2;
simpl;
auto using wt_stmt_zip.
intros s2 WTs1 WTcomp.
inv WTcomp.
apply IHs2_2;
auto.
apply wt_stmt_zip;
auto.
Qed.
Lemma meth_vars_fuse_method:
forall m,
meth_vars (
fuse_method m) =
meth_vars m.
Proof.
destruct m; simpl; auto.
Qed.
Lemma fuse_wt_program:
forall p,
wt_program p ->
wt_program (
fuse_program p).
Proof.
Lemma fuse_wt_memory:
forall me p c,
wt_memory me p c.(
c_mems)
c.(
c_objs) ->
wt_memory me (
fuse_program p) (
fuse_class c).(
c_mems) (
fuse_class c).(
c_objs).
Proof.
intros * WT.
pose proof transform_units_wt_memory' as Spec; simpl in Spec.
apply Spec in WT; auto.
Qed.
Fusion preserves Can_write_in.
Lemma fuse_cannot_write_inputs:
forall p,
wt_program p ->
Forall_methods (
fun m =>
Forall (
fun x => ~
Can_write_in_var x (
m_body m)) (
map fst (
m_in m)))
p ->
Forall_methods (
fun m =>
Forall (
fun x => ~
Can_write_in_var x (
m_body m)) (
map fst (
m_in m)))
(
fuse_program p).
Proof.
Fusion preserves No_Overwrites.
Lemma fuse_No_Overwrites:
forall p,
wt_program p ->
Forall_methods (
fun m =>
No_Overwrites (
m_body m))
p ->
Forall_methods (
fun m =>
No_Overwrites (
m_body m)) (
fuse_program p).
Proof.
End FUSION.
Module FusionFun
(
Ids :
IDS)
(
Op :
OPERATORS)
(
OpAux :
OPERATORS_AUX Ids Op)
(
SynObc:
OBCSYNTAX Ids Op OpAux)
(
ComTyp:
COMMONTYPING Ids Op OpAux)
(
SemObc:
OBCSEMANTICS Ids Op OpAux SynObc)
(
InvObc:
OBCINVARIANTS Ids Op OpAux SynObc SemObc)
(
TypObc:
OBCTYPING Ids Op OpAux SynObc ComTyp SemObc)
(
Equ :
EQUIV Ids Op OpAux SynObc ComTyp SemObc TypObc)
<:
FUSION Ids Op OpAux SynObc ComTyp SemObc InvObc TypObc Equ.
Include FUSION Ids Op OpAux SynObc ComTyp SemObc InvObc TypObc Equ.
End FusionFun.