From Coq Require Import List.
Import List.ListNotations.
Open Scope list_scope.
From Velus Require Import Common.
From Velus Require Import CommonTyping.
From Velus Require Import Environment.
From Velus Require Import Operators.
From Velus Require Import Clocks.
From Velus Require Import Fresh.
From Velus Require Import Lustre.StaticEnv.
From Velus Require Import Lustre.LSyntax.
Remove Local Blocks
Module Type DELAST
(
Import Ids :
IDS)
(
Import Op :
OPERATORS)
(
OpAux :
OPERATORS_AUX Ids Op)
(
Import Cks :
CLOCKS Ids Op OpAux)
(
Import Senv :
STATICENV Ids Op OpAux Cks)
(
Import Syn :
LSYNTAX Ids Op OpAux Cks Senv).
Rename some variables
Section rename.
Variable (
sub :
Env.t ident).
Definition rename_in_var (
x :
ident) :=
or_default x (
Env.find x sub).
Fixpoint rename_in_exp (
e :
exp) :=
match e with
|
Econst _ |
Eenum _ _ |
Evar _ _ =>
e
|
Elast x ann =>
Evar (
rename_in_var x)
ann
|
Eunop op e1 ann =>
Eunop op (
rename_in_exp e1)
ann
|
Ebinop op e1 e2 ann =>
Ebinop op (
rename_in_exp e1) (
rename_in_exp e2)
ann
|
Eextcall f es ann =>
Eextcall f (
map rename_in_exp es)
ann
|
Efby e0s e1s anns =>
Efby (
map rename_in_exp e0s) (
map rename_in_exp e1s)
anns
|
Earrow e0s e1s anns =>
Earrow (
map rename_in_exp e0s) (
map rename_in_exp e1s)
anns
|
Ewhen es x t ann =>
Ewhen (
map rename_in_exp es)
x t ann
|
Emerge (
x,
ty)
es ann =>
Emerge (
x,
ty) (
map (
fun '(
i,
es) => (
i,
map rename_in_exp es))
es)
ann
|
Ecase e es d ann =>
Ecase (
rename_in_exp e) (
map (
fun '(
i,
es) => (
i,
map rename_in_exp es))
es) (
option_map (
map rename_in_exp)
d)
ann
|
Eapp f es er ann =>
Eapp f (
map rename_in_exp es) (
map rename_in_exp er)
ann
end.
Definition rename_in_equation '(
xs,
es) :
equation :=
(
xs,
map rename_in_exp es).
End rename.
More properties
Section rename_empty.
Fact rename_in_var_empty :
forall x,
rename_in_var (
Env.empty _)
x =
x.
Proof.
Corollary rename_in_vars_empty :
forall xs,
map (
rename_in_var (
Env.empty _))
xs =
xs.
Proof.
End rename_empty.
Fact not_in_union_rename1 :
forall x y sub xs,
NoDupMembers xs ->
In (
x,
y)
xs ->
rename_in_var (
Env.adds'
xs sub)
x =
y.
Proof.
unfold rename_in_var.
intros *
ND In.
erewrite Env.In_find_adds';
simpl;
eauto.
Qed.
Fact not_in_union_rename2 :
forall x sub xs,
~
InMembers x xs ->
rename_in_var (
Env.adds'
xs sub)
x =
rename_in_var sub x.
Proof.
unfold rename_in_var.
intros *
Hnin.
destruct (
Env.find x _)
eqn:
Hfind.
-
eapply Env.find_adds'
_In in Hfind as [
Hfind|
Hfind].
+
exfalso.
eapply Hnin;
eauto using In_InMembers.
+
now rewrite Hfind.
-
apply Env.find_adds'
_nIn in Hfind as (
Hfind1&
Hfind2).
simpl.
destruct (
Env.find x sub);
simpl in *;
auto.
congruence.
Qed.
Inlining of local blocks
Module Fresh :=
Fresh.Fresh(
Ids).
Import Fresh Notations Facts Tactics.
Local Open Scope fresh_monad_scope.
Definition FreshAnn A :=
Fresh last A (
type *
clock).
Definition fresh_idents (
lasts :
list (
ident * (
type *
clock *
exp))) :
FreshAnn _ :=
mmap (
fun '(
x, (
ty,
ck,
e)) =>
do lx <-
fresh_ident (
Some x) (
ty,
ck);
ret (
x,
lx, (
ty,
ck,
e)))
lasts.
Section delast_scope.
Context {
A :
Type}.
Variable f_delast :
Env.t ident ->
A ->
FreshAnn A.
Variable f_add_eqs :
list block ->
A ->
A.
Definition delast_scope sub (
s :
scope A) :
FreshAnn (
scope A) :=
let '
Scope locs blks :=
s in
let lasts :=
map_filter (
fun '(
x, (
ty,
ck,
_,
o)) =>
option_map (
fun '(
e,
_) => (
x, (
ty,
ck,
e)))
o)
locs in
do lasts' <-
fresh_idents lasts;
let sub' :=
Env.adds' (
map fst lasts')
sub in
do blks' <-
f_delast sub'
blks;
let fbyeqs :=
map (
fun '(
x,
lx, (
ty,
ck,
e)) =>
([
lx], [
Efby [
rename_in_exp sub'
e]
[
Evar x (
ty,
ck)] [(
ty,
ck)]]))
lasts'
in
ret (
Scope (
map (
fun '(
x, (
ty,
ck,
cx,
_)) => (
x, (
ty,
ck,
cx,
None)))
locs
++
map (
fun '(
_,
lx, (
ty,
ck,
_)) => (
lx, (
ty,
ck,
xH,
None)))
lasts')
(
f_add_eqs (
map Beq fbyeqs)
blks')).
End delast_scope.
Fixpoint delast_block sub (
blk :
block) :
FreshAnn block :=
match blk with
|
Beq eq =>
ret (
Beq (
rename_in_equation sub eq))
|
Breset blks er =>
do blks' <-
mmap (
delast_block sub)
blks;
ret (
Breset blks' (
rename_in_exp sub er))
|
Bswitch ec branches =>
do branches' <-
mmap (
fun '(
k,
Branch _ blks) =>
do blks' <-
mmap (
delast_block sub)
blks;
ret (
k,
Branch []
blks'))
branches;
ret (
Bswitch (
rename_in_exp sub ec)
branches')
|
Bauto type ck (
ini,
oth)
states =>
do states' <-
mmap (
fun '(
k,
Branch _ (
unl,
scope)) =>
let unl' :=
map (
fun '(
e,
k) => (
rename_in_exp sub e,
k))
unl in
do scope' <-
delast_scope (
fun sub '(
blks,
trans) =>
do blks' <-
mmap (
delast_block sub)
blks;
ret (
blks',
map (
fun '(
e,
k) => (
rename_in_exp sub e,
k))
trans))
(
fun eqs '(
blks,
trans) => (
eqs++
blks,
trans))
sub scope;
ret (
k,
Branch [] (
unl',
scope')))
states;
ret (
Bauto type ck (
map (
fun '(
e,
k) => (
rename_in_exp sub e,
k))
ini,
oth)
states')
|
Blocal scope =>
do scope' <-
delast_scope (
fun sub =>
mmap (
delast_block sub))
(
fun eqs blks =>
eqs++
blks)
sub scope;
ret (
Blocal scope')
end.
Definition delast_outs_and_block (
outs :
list decl)
blk :
FreshAnn block :=
let lasts :=
map_filter (
fun '(
x, (
ty,
ck,
_,
o)) =>
option_map (
fun '(
e,
_) => (
x, (
ty,
ck,
e)))
o)
outs in
do lasts' <-
fresh_idents lasts;
let sub :=
Env.from_list (
map fst lasts')
in
do blk' <-
delast_block sub blk;
let fbyeqs :=
map (
fun '(
x,
lx, (
ty,
ck,
e)) =>
([
lx], [
Efby [
rename_in_exp sub e]
[
Evar x (
ty,
ck)] [(
ty,
ck)]]))
lasts'
in
if is_nil lasts'
then
ret blk'
else
ret (
Blocal (
Scope (
map (
fun '(
_,
lx, (
ty,
ck,
_)) => (
lx, (
ty,
ck,
xH,
None)))
lasts')
(
map Beq fbyeqs ++ [
blk']))).
Some properties
Lemma fresh_idents_In :
forall lasts lasts'
st st',
fresh_idents lasts st = (
lasts',
st') ->
forall x ty ck e,
In (
x, (
ty,
ck,
e))
lasts ->
exists lx,
In (
x,
lx, (
ty,
ck,
e))
lasts'.
Proof.
Lemma fresh_idents_In' :
forall lasts lasts'
st st',
fresh_idents lasts st = (
lasts',
st') ->
forall x lx ty ck e,
In (
x,
lx, (
ty,
ck,
e))
lasts' ->
In (
x, (
ty,
ck,
e))
lasts.
Proof.
Lemma fresh_idents_InMembers :
forall lasts lasts'
st st',
fresh_idents lasts st = (
lasts',
st') ->
forall x,
InMembers x lasts <->
InMembers x (
map fst lasts').
Proof.
Lemma fresh_idents_NoDupMembers :
forall lasts lasts'
st st',
NoDupMembers lasts ->
fresh_idents lasts st = (
lasts',
st') ->
NoDupMembers (
map fst lasts').
Proof.
induction lasts;
intros *
Hnd Hfresh;
inv Hnd;
destruct_conjs;
repeat inv_bind;
simpl;
constructor;
eauto.
erewrite <-
fresh_idents_InMembers;
eauto.
Qed.
Lemma fresh_idents_In_rename sub :
forall lasts lasts'
st st',
NoDupMembers lasts ->
fresh_idents lasts st = (
lasts',
st') ->
forall x ty ck e,
In (
x, (
ty,
ck,
e))
lasts ->
In (
x, (
rename_in_var (
Env.adds' (
map fst lasts')
sub)
x), (
ty,
ck,
e))
lasts'.
Proof.
Lemma fresh_idents_In'
_rename sub :
forall lasts lasts'
st st',
NoDupMembers lasts ->
fresh_idents lasts st = (
lasts',
st') ->
forall x lx ty ck e,
In (
x,
lx, (
ty,
ck,
e))
lasts' ->
In (
x, (
ty,
ck,
e))
lasts /\
lx =
rename_in_var (
Env.adds' (
map fst lasts')
sub)
x.
Proof.
State properties
Lemma fresh_idents_st_follows :
forall lasts lasts'
st st',
fresh_idents lasts st = (
lasts',
st') ->
st_follows st st'.
Proof.
intros *
Hfresh.
eapply mmap_st_follows in Hfresh;
eauto.
simpl_Forall.
repeat inv_bind;
eauto with fresh.
Qed.
Fact delast_scope_st_follows {
A}
f_dl f_add :
forall sub locs (
blks :
A)
s'
st st',
delast_scope f_dl f_add sub (
Scope locs blks)
st = (
s',
st') ->
(
forall sub blks'
st st',
f_dl sub blks st = (
blks',
st') ->
st_follows st st') ->
st_follows st st'.
Proof.
Lemma delast_block_st_follows :
forall blk sub blks'
st st',
delast_block sub blk st = (
blks',
st') ->
st_follows st st'.
Proof.
Global Hint Resolve delast_block_st_follows :
fresh.
Wellformedness properties
VarsDefinedComp
Import Permutation.
Fact mmap_vars_perm :
forall (
f : (
Env.t ident) ->
block ->
FreshAnn block)
blks sub blks'
xs st st',
Forall
(
fun blk =>
forall sub blk'
xs st st',
VarsDefinedComp blk xs ->
f sub blk st = (
blk',
st') ->
VarsDefinedComp blk'
xs)
blks ->
Forall2 VarsDefinedComp blks xs ->
mmap (
f sub)
blks st = (
blks',
st') ->
Forall2 VarsDefinedComp blks'
xs.
Proof.
induction blks; intros * Hf Hvars Hnorm;
inv Hf; inv Hvars; repeat inv_bind; simpl; constructor; eauto.
Qed.
Lemma delast_scope_vars_perm {
A}
P_vd f_dl f_add :
forall locs (
blks:
A)
sub s'
xs st st',
VarsDefinedCompScope P_vd (
Scope locs blks)
xs ->
delast_scope f_dl f_add sub (
Scope locs blks)
st = (
s',
st') ->
(
forall xs sub blks'
st st',
P_vd blks xs ->
f_dl sub blks st = (
blks',
st') ->
P_vd blks'
xs) ->
(
forall xs1 xs2 blks1 blks2,
Forall2 VarsDefinedComp blks1 xs2 ->
P_vd blks2 xs1 ->
P_vd (
f_add blks1 blks2) (
xs1 ++
concat xs2)) ->
VarsDefinedCompScope P_vd s'
xs.
Proof.
intros *
Hvd Hdl Hind Hadd;
inv Hvd.
repeat inv_bind.
eapply Hind in H0;
eauto.
econstructor;
eauto using incl_nil'.
rewrite map_app,
app_assoc,
map_map.
rewrite <-
concat_map_singl1 with (
l:=
map _ (
map _ x)).
eapply Hadd.
-
simpl_Forall.
constructor.
-
erewrite map_map,
map_ext;
eauto.
intros;
destruct_conjs;
auto.
Qed.
Lemma delast_block_vars_perm :
forall blk sub blk'
xs st st',
VarsDefinedComp blk xs ->
delast_block sub blk st = (
blk',
st') ->
VarsDefinedComp blk'
xs.
Proof.
Lemma delast_outs_and_block_vars_perm :
forall outs blk blk'
xs st st',
VarsDefinedComp blk xs ->
delast_outs_and_block outs blk st = (
blk',
st') ->
VarsDefinedComp blk'
xs.
Proof.
GoodLocals
Fact fresh_idents_prefixed :
forall lasts lasts'
st st',
fresh_idents lasts st = (
lasts',
st') ->
Forall (
fun '(
_,
lx,
_) =>
exists n hint,
lx =
gensym last hint n)
lasts'.
Proof.
Lemma delast_scope_GoodLocals {
A}
P_good1 (
P_good2:
_ ->
Prop)
f_dl f_add :
forall locs (
blks:
A)
sub s'
st st',
GoodLocalsScope P_good1 elab_prefs (
Scope locs blks) ->
delast_scope f_dl f_add sub (
Scope locs blks)
st = (
s',
st') ->
(
forall sub blks'
st st',
P_good1 blks ->
f_dl sub blks st = (
blks',
st') ->
P_good2 blks') ->
(
forall blks1 blks2,
Forall (
GoodLocals last_prefs)
blks1 ->
P_good2 blks2 ->
P_good2 (
f_add blks1 blks2)) ->
GoodLocalsScope P_good2 last_prefs s'.
Proof.
Lemma delast_block_GoodLocals :
forall blk sub blk'
st st',
GoodLocals elab_prefs blk ->
delast_block sub blk st = (
blk',
st') ->
GoodLocals last_prefs blk'.
Proof.
Lemma delast_outs_and_block_GoodLocals :
forall outs blk blk'
st st',
GoodLocals elab_prefs blk ->
delast_outs_and_block outs blk st = (
blk',
st') ->
GoodLocals last_prefs blk'.
Proof.
NoDupLocals
Lemma last_not_in_elab_prefs :
~
PS.In last elab_prefs.
Proof.
Fact fresh_idents_In_ids :
forall lasts lasts'
st st',
fresh_idents lasts st = (
lasts',
st') ->
Forall (
fun '(
_,
lx,
_) =>
In lx (
st_ids st'))
lasts'.
Proof.
Fact fresh_idents_nIn_ids :
forall lasts lasts'
st st',
fresh_idents lasts st = (
lasts',
st') ->
Forall (
fun '(
_,
lx,
_) => ~
In lx (
st_ids st))
lasts'.
Proof.
unfold fresh_idents.
induction lasts;
intros;
destruct_conjs;
repeat inv_bind;
constructor;
eauto.
-
eapply fresh_ident_nIn in H;
eauto.
-
eapply IHlasts in H0.
simpl_Forall.
contradict H0.
eapply incl_map;
eauto.
apply st_follows_incl;
eauto with fresh.
Qed.
Fact fresh_idents_NoDup :
forall lasts lasts'
st st',
fresh_idents lasts st = (
lasts',
st') ->
NoDupMembers (
map (
fun '(
_,
lx, (
ty,
ck,
_)) => (
lx, (
ty,
ck,
xH, @
None (
exp *
ident))))
lasts').
Proof.
Fact mmap_delast_NoDupLocals sub :
forall blks blks'
xs st st',
Forall
(
fun blk =>
forall xs sub blk'
st st',
Forall (
fun x :
ident =>
AtomOrGensym elab_prefs x \/
In x (
st_ids st))
xs ->
GoodLocals elab_prefs blk ->
NoDupLocals xs blk ->
delast_block sub blk st = (
blk',
st') ->
NoDupLocals xs blk')
blks ->
Forall (
fun x :
ident =>
AtomOrGensym elab_prefs x \/
In x (
st_ids st))
xs ->
Forall (
GoodLocals elab_prefs)
blks ->
Forall (
NoDupLocals xs)
blks ->
mmap (
delast_block sub)
blks st = (
blks',
st') ->
Forall (
NoDupLocals xs)
blks'.
Proof.
Lemma delast_scope_NoDupLocals {
A}
P_good P_nd f_dl f_add :
forall locs (
blks:
A)
xs sub s'
st st',
Forall (
fun x =>
AtomOrGensym elab_prefs x \/
In x (
st_ids st))
xs ->
GoodLocalsScope P_good elab_prefs (
Scope locs blks) ->
NoDupScope P_nd xs (
Scope locs blks) ->
delast_scope f_dl f_add sub (
Scope locs blks)
st = (
s',
st') ->
(
forall xs ys,
P_good blks ->
(
forall x :
ident,
In x ys ->
In x xs \/ (
exists id hint,
x =
gensym last hint id)) ->
P_nd xs blks ->
P_nd ys blks) ->
(
forall sub xs blks'
st st',
Forall (
fun x =>
AtomOrGensym elab_prefs x \/
In x (
st_ids st))
xs ->
P_good blks ->
P_nd xs blks ->
f_dl sub blks st = (
blks',
st') ->
P_nd xs blks') ->
(
forall xs blks1 blks2,
Forall (
NoDupLocals xs)
blks1 ->
P_nd xs blks2 ->
P_nd xs (
f_add blks1 blks2)) ->
NoDupScope P_nd xs s'.
Proof.
Lemma delast_block_NoDupLocals :
forall blk xs sub blk'
st st',
Forall (
fun x =>
AtomOrGensym elab_prefs x \/
In x (
st_ids st))
xs ->
GoodLocals elab_prefs blk ->
NoDupLocals xs blk ->
delast_block sub blk st = (
blk',
st') ->
NoDupLocals xs blk'.
Proof.
Lemma delast_outs_and_block_NoDupLocals :
forall outs blk xs blk'
st st',
Forall (
fun x =>
AtomOrGensym elab_prefs x \/
In x (
st_ids st))
xs ->
GoodLocals elab_prefs blk ->
NoDupLocals xs blk ->
delast_outs_and_block outs blk st = (
blk',
st') ->
NoDupLocals xs blk'.
Proof.
No last remaining
Fact delast_scope_nolast {
A}
f_dl f_add (
P_nl:
_ ->
Prop) :
forall sub locs (
blks :
A)
s'
st st',
delast_scope f_dl f_add sub (
Scope locs blks)
st = (
s',
st') ->
(
forall sub blks'
st st',
f_dl sub blks st = (
blks',
st') ->
P_nl blks') ->
(
forall blks1 blks2,
Forall nolast_block blks1 ->
P_nl blks2 ->
P_nl (
f_add blks1 blks2)) ->
nolast_scope P_nl s'.
Proof.
intros *
Hdl Hind Hadd;
repeat inv_bind.
constructor.
-
apply Forall_app.
split;
simpl_Forall;
auto.
-
eapply Hadd;
eauto.
simpl_Forall.
constructor.
Qed.
Lemma delast_block_nolast :
forall blk sub blk'
st st',
delast_block sub blk st = (
blk',
st') ->
nolast_block blk'.
Proof.
Lemma delast_outs_and_block_nolast :
forall blk outs blk'
st st',
delast_outs_and_block outs blk st = (
blk',
st') ->
nolast_block blk'.
Proof.
Transformation of node and program
Program Definition delast_node (
n: @
node complete elab_prefs) : @
node nolast last_prefs :=
let res :=
delast_outs_and_block (
n_out n) (
n_block n)
init_st in
{|
n_name := (
n_name n);
n_hasstate := (
n_hasstate n);
n_in := (
n_in n);
n_out :=
List.map (
fun xtc => (
fst xtc, (
fst (
fst (
fst (
snd xtc))), (
snd (
fst (
fst (
snd xtc)))),
xH,
None))) (
n_out n);
n_block :=
fst res;
n_ingt0 := (
n_ingt0 n);
n_outgt0 := (
n_outgt0 n);
|}.
Next Obligation.
Next Obligation.
Next Obligation.
Next Obligation.
Next Obligation.
Global Program Instance delast_node_transform_unit:
TransformUnit (@
node complete elab_prefs)
node :=
{
transform_unit :=
delast_node }.
Global Program Instance delast_global_without_units :
TransformProgramWithoutUnits (@
global complete elab_prefs) (@
global nolast last_prefs) :=
{
transform_program_without_units :=
fun g =>
Global g.(
types)
g.(
externs) [] }.
Definition delast_global : @
global complete elab_prefs -> @
global nolast last_prefs :=
transform_units.
Equality of interfaces
Lemma delast_global_iface_eq :
forall G,
global_iface_eq G (
delast_global G).
Proof.
End DELAST.
Module DeLastFun
(
Ids :
IDS)
(
Op :
OPERATORS)
(
OpAux :
OPERATORS_AUX Ids Op)
(
Cks :
CLOCKS Ids Op OpAux)
(
Senv :
STATICENV Ids Op OpAux Cks)
(
Syn :
LSYNTAX Ids Op OpAux Cks Senv)
<:
DELAST Ids Op OpAux Cks Senv Syn.
Include DELAST Ids Op OpAux Cks Senv Syn.
End DeLastFun.