Scopes: definition, validation and construction
Require Import Coqlib.
Require Import Maps.
Require Import Errors.
Require Import AST.
Require Import Integers.
Require Import Values.
Require Import Events.
Require Import Memory.
Require Import Globalenvs.
Require Import Smallstep.
Require Import Op.
Require Import Registers.
Require Import RTL.
Require Import UtilBase.
Require Import RTLPaths.
Require Import Utf8.
Require Import DLib.
Require Import Bourdoncle.
Require Import Maps.
Definition path :=
rev_path.
Module Type SCOPE.
Parameter t :
Type.
Parameter nodes :
t ->
list node.
Parameter sons:
t ->
list t.
Notation "
n ∈
sc" := (
In n (
nodes sc)) (
at level 10).
Notation "
sc1 ⊆
sc2" := (
incl (
nodes sc1) (
nodes sc2)) (
at level 10).
Record family (
f:
function) := {
scope :
node ->
t;
header :
t ->
node;
parent :
t ->
t;
elements:
list t;
in_scope:
forall n,
f_In n f ->
n ∈ (
scope n);
scope_least:
forall n sc,
In sc elements ->
n ∈
sc -> (
scope n) ⊆
sc;
header_f_In:
forall sc,
In sc elements ->
f_In (
header sc)
f;
scope_header:
forall sc,
In sc elements ->
scope (
header sc) =
sc;
incl_in_parent:
forall sc,
In sc elements ->
sc ⊆ (
parent sc);
parent_least:
forall sc sc',
In sc elements ->
In sc'
elements ->
sc ⊆
sc' ->
sc =
sc' \/ (
parent sc) ⊆
sc';
sons_in_element:
forall sc sc',
In sc elements ->
In sc' (
sons sc) ->
In sc'
elements;
parent_in_element:
forall sc,
In sc elements ->
In (
parent sc)
elements;
scope_in_elements:
forall n,
In (
scope n)
elements;
enter_in_scope_at_header_only:
forall n n',
succ_node f n n' ->
~
n ∈ (
scope n') ->
n' =
header (
scope n') /\
parent (
scope n') =
scope n;
cycle_at_not_header:
forall rl n,
f_In n f ->
n <>
header (
scope n) ->
path f n rl n ->
rl <>
nil ->
In (
header (
scope n))
rl;
cycle_at_header:
forall rl n,
f_In n f ->
n =
header (
scope n) ->
path f n rl n ->
rl <>
nil ->
In (
header (
parent (
scope n)))
rl \/
(
forall n',
In n'
rl ->
n' ∈ (
scope n));
in_scope_root:
forall sc,
In sc elements ->
f.(
fn_entrypoint) ∈
sc ->
f.(
fn_entrypoint) =
header sc;
parent_strict_subset:
forall sc,
In sc elements ->
(
header (
parent sc)) ∈
sc ->
f.(
fn_entrypoint) =
header sc;
root_no_pred:
forall n, ~
succ_node f n f.(
fn_entrypoint)
}.
Implicit Arguments scope [
f].
Implicit Arguments header [
f].
Implicit Arguments parent [
f].
Implicit Arguments elements [
f].
Parameter build_family:
forall (
f:
function),
option (
family f).
End SCOPE.
Untrusted OCaml code validated a posteriori.
Parameter build_bourdoncle :
function -> (
bourdoncle *
PMap.t N).
Lemma succ_node_f_In:
forall f n n',
succ_node f n n' ->
f_In n f.
Proof.
destruct 1 as (x & X1 & X2).
unfold f_In; congruence.
Qed.
Module ImplemScope.
Definition t := (
node *
list bourdoncle)%
type.
Fixpoint bourdoncle_elements (
l:
list node) (
b:
bourdoncle) :
list node :=
match b with
|
I n =>
n ::
l
|
L h lb =>
List.fold_left bourdoncle_elements lb (
h::
l)
end.
Definition nodes (
sc:
t) :
list node :=
let (
h,
l) :=
sc in
List.fold_left bourdoncle_elements l (
h::
nil).
Definition sons1 (
l:
list t) (
b:
bourdoncle) :
list t :=
match b with
|
I n =>
l
|
L h lb => (
h,
lb)::
l
end.
Definition sons (
sc:
t) :
list t :=
fold_left sons1 (
snd sc)
nil.
Module I.
Definition scope_table := (
PTree.t (
node *
list bourdoncle) *
PTree.t node)%
type.
Fixpoint build_scope_table_aux (
myscope:
t) (
st:
scope_table*
bool) (
b:
bourdoncle) :
(
scope_table *
bool) :=
let (
m,
distinct) :=
st in
let (
scope,
parent) :=
m in
match b with
|
I n => ((
PTree.set n myscope scope,
parent),
negb (
ptree_mem n scope) &&
distinct)
|
L h lb =>
List.fold_left (
build_scope_table_aux (
h,
lb))
lb
((
PTree.set h (
h,
lb)
scope,
PTree.set h (
fst myscope)
parent),
negb (
ptree_mem h scope) &&
distinct)
end.
Fixpoint in_bourdoncle (
n0:
node) (
b:
bourdoncle) :
bool :=
match b with
|
I n =>
Peqb n0 n
|
L h lb =>
orb (
Peqb n0 h) (
List.existsb (
in_bourdoncle n0)
lb)
end.
Definition build_scope_table (
sc:
t) :
res scope_table :=
let (
h,
l) :=
sc in
let (
tab,
distinct) :=
List.fold_left (
build_scope_table_aux sc)
l
((
PTree.set h (
h,
l) (
PTree.empty _), (
PTree.empty _)),
true)
in
if distinct
then OK tab
else Error (
MSG "
bourdoncle contains dup" ::
nil).
Definition header_ (
sc:
t) :
node :=
fst sc.
Definition scope_ (
tab:
scope_table) (
main:
t) (
n:
node) :=
match PTree.get n (
fst tab)
with
|
None =>
main
|
Some sc =>
sc
end.
Definition parent_ (
tab:
scope_table) (
sc:
t) :
t :=
match PTree.get (
header_ sc) (
snd tab)
with
|
None =>
sc
|
Some h' =>
match PTree.get h' (
fst tab)
with
|
None =>
sc
|
Some sc' =>
sc'
end
end.
Definition cast_bourdoncle (
b:
bourdoncle) :
res (
node *
list bourdoncle) :=
match b with
|
I _ =>
Error (
MSG "
cast_bourdoncle error" ::
nil)
|
L h lb =>
OK (
h,
lb)
end.
Open Scope error_monad_scope.
Section Exists.
Context {
A:
Type}.
Variable (
f:
A->
Prop).
Fixpoint Exists (
l:
list A) :
Prop :=
match l with
|
nil =>
False
|
a::
l =>
f a \/
Exists l
end.
End Exists.
Fixpoint sc_In (
h0:
node) (
l0:
list bourdoncle) (
b:
bourdoncle) :
Prop :=
match b with
|
I n =>
False
|
L h lb => (
h=
h0 /\
lb=
l0)
\/
Exists (
sc_In h0 l0)
lb
end.
Notation "
a !
b" := (
PTree.get b a) (
at level 1).
Lemma fold_build_scope_false_aux:
(
forall b0 sc0 tab,
snd (
build_scope_table_aux sc0 (
tab,
false)
b0) =
false) ->
forall lb0 sc0 tab,
snd (
fold_left (
build_scope_table_aux sc0)
lb0 (
tab,
false)) =
false.
Proof.
intros HP.
fix IH 1;
intros [|
b0 lb0];
simpl in *;
intros.
>
congruence.
>
case_eq (
build_scope_table_aux sc0 (
tab,
false)
b0);
intros tab1 b1 Ht.
generalize (
HP b0 sc0 tab);
rewrite Ht;
simpl;
intros HH;
inv HH.
exploit IH;
eauto.
Defined.
Lemma fold_build_scope_false:
forall b0 sc0 tab,
snd (
build_scope_table_aux sc0 (
tab,
false)
b0) =
false.
Proof.
Lemma fold_build_scope_false_elim:
forall lb0 sc0 tab tab',
fold_left (
build_scope_table_aux sc0)
lb0 (
tab,
false) <> (
tab',
true).
Proof.
Lemma old_map_build_scope_table_aux:
(
forall b0 sc0 tab n b tab1,
(
fst tab) !
n <>
None ->
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab1,
true) ->
(
fst tab1) !
n = (
fst tab) !
n) ->
forall lb0 sc0 tab b tab',
fold_left (
build_scope_table_aux sc0)
lb0 (
tab,
b) = (
tab',
true) ->
forall n,
PTree.get n (
fst tab) <>
None ->
PTree.get n (
fst tab') =
PTree.get n (
fst tab).
Proof.
intros HP.
fix 1;
intros [|
b0 lb0];
simpl in *;
intros.
>
congruence.
>
case_eq (
build_scope_table_aux sc0 (
tab,
b)
b0);
intros tab1 b1 Ht.
rewrite Ht in *.
destruct b1.
>
rewrite (
old_map_build_scope_table_aux _ _ _ _ _ H);
eauto.
rewrite (
HP _ _ _ _ _ _ H0 Ht);
eauto.
>
generalize (
fold_build_scope_false_aux fold_build_scope_false lb0 sc0 tab1).
rewrite H.
simpl;
congruence.
Defined.
Lemma old_map_build_scope_table:
forall b0 sc0 tab n b tab1,
(
fst tab) !
n <>
None ->
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab1,
true) ->
(
fst tab1) !
n = (
fst tab) !
n.
Proof.
fix IH 1.
intros [
n|
h0 lb0];
simpl in *;
intros.
>
destruct tab;
inv H0;
simpl in *.
rewrite PTree.gsspec;
destruct peq;
subst;
auto.
unfold ptree_mem in *.
destruct (
t0!
n);
simpl in *;
congruence.
>
destruct tab;
simpl in *.
generalize (
old_map_build_scope_table_aux IH _ _ _ _ _ H0).
simpl;
intros.
rewrite H1;
rewrite PTree.gsspec;
destruct peq;
try congruence.
subst.
unfold ptree_mem in *;
destruct (
t0!
h0);
try congruence.
simpl in *.
elim fold_build_scope_false_elim with (1:=
H0).
Qed.
Lemma build_scope_table_same:
forall b0 sc0 tab n b tab1 p,
(
fst tab) !
n =
Some p ->
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab1,
true) ->
(
fst tab1) !
n =
Some p.
Proof.
Lemma fold_build_scope_table_same:
forall lb0 sc0 tab n b tab'
p,
(
fst tab) !
n =
Some p ->
fold_left (
build_scope_table_aux sc0)
lb0 (
tab,
b) = (
tab',
true) ->
(
fst tab') !
n =
Some p.
Proof.
Hint Resolve build_scope_table_same fold_build_scope_table_same.
Lemma old_map_build_scope_table_snd_aux:
(
forall b0 sc0 tab n b tab1,
(
fst tab) !
n <>
None ->
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab1,
true) ->
(
snd tab1) !
n = (
snd tab) !
n) ->
forall lb0 sc0 tab b tab',
fold_left (
build_scope_table_aux sc0)
lb0 (
tab,
b) = (
tab',
true) ->
forall n,
PTree.get n (
fst tab) <>
None ->
PTree.get n (
snd tab') =
PTree.get n (
snd tab).
Proof.
Lemma old_map_build_scope_table_snd:
forall b0 sc0 tab n b tab1,
(
fst tab) !
n <>
None ->
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab1,
true) ->
(
snd tab1) !
n = (
snd tab) !
n.
Proof.
fix IH 1.
intros [
n|
h0 lb0];
simpl in *;
intros.
>
destruct tab;
inv H0;
simpl in *;
auto.
>
destruct tab;
simpl in *.
generalize (
old_map_build_scope_table_snd_aux IH _ _ _ _ _ H0).
simpl;
intros.
rewrite H1;
rewrite PTree.gsspec;
destruct peq;
try congruence.
subst.
unfold ptree_mem in *;
destruct (
t0!
h0);
try congruence.
simpl in *.
elim fold_build_scope_false_elim with (1:=
H0).
Qed.
Lemma sc_In_get_aux:
(
forall b0 sc0 tab b tab',
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab',
true) ->
forall h n lb,
In (
I n) (
I h ::
lb) ->
sc_In h lb b0 ->
PTree.get n (
fst tab') =
Some (
h,
lb)) ->
forall lb0 sc0 tab b tab',
fold_left (
build_scope_table_aux sc0)
lb0 (
tab,
b) = (
tab',
true) ->
forall h n lb,
In (
I n) (
I h ::
lb) ->
Exists (
sc_In h lb)
lb0 -> (
fst tab') !
n =
Some (
h,
lb).
Proof.
Lemma sc_In_get_aux2:
(
forall b0 sc0 tab b tab',
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab',
true) ->
forall h n lb,
In (
I n) (
I h ::
lb) ->
sc_In h lb b0 ->
PTree.get n (
fst tab') =
Some (
h,
lb)) ->
forall lb0 h0 lb0'
tab b tab',
fold_left (
build_scope_table_aux (
h0,
lb0'++
lb0))
lb0 (
tab,
b) = (
tab',
true) ->
forall n,
In (
I n)
lb0 -> (
fst tab') !
n =
Some (
h0,
lb0'++
lb0).
Proof.
Lemma sc_In_get :
forall b0 sc0 tab b tab',
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab',
true) ->
forall h n lb,
In (
I n) (
I h ::
lb) ->
sc_In h lb b0 ->
PTree.get n (
fst tab') =
Some (
h,
lb).
Proof.
Lemma sc_In_get_main :
forall b lb0 tab',
build_scope_table (
b,
lb0) =
OK tab' ->
forall h n lb,
In (
I n) (
I h ::
lb) ->
sc_In h lb (
L b lb0) ->
PTree.get n (
fst tab') =
Some (
h,
lb).
Proof.
Definition In_scope (
main:
t) (
n:
node) (
sc:
t) :
Prop :=
let (
h,
lb) :=
sc in
let (
h0,
lb0) :=
main in
In (
I n) (
I h ::
lb) /\
sc_In h lb (
L h0 lb0).
Lemma In_scope_get_fst :
forall main tab,
build_scope_table main =
OK tab ->
forall n sc,
In_scope main n sc ->
PTree.get n (
fst tab) =
Some sc.
Proof.
intros.
destruct main;
destruct sc;
simpl in H0;
intros.
destruct H0.
exploit (
sc_In_get_main);
eauto.
Qed.
Lemma fold_sc_In_get_inv :
(
forall b0 h0 l0 tab b tab',
build_scope_table_aux (
h0,
l0) (
tab,
b)
b0 = (
tab',
true) ->
forall h n lb,
PTree.get n (
fst tab') =
Some (
h,
lb) ->
PTree.get n (
fst tab) =
Some (
h,
lb) \/
((
h,
lb) = (
h0,
l0) /\
b0 =
I n) \/
(
In (
I n) (
I h ::
lb) /\
sc_In h lb b0)) ->
forall lb0 sc0 n tab b tab'
h lb,
fold_left (
build_scope_table_aux sc0)
lb0 (
tab,
b) = (
tab',
true) ->
(
fst tab') !
n =
Some (
h,
lb) ->
(
fst tab)!
n =
Some (
h,
lb) \/
(
sc0 = (
h,
lb) /\
In (
I n)
lb0) \/
(
In (
I n) (
I h ::
lb) /\
Exists (
sc_In h lb)
lb0).
Proof.
intros IH';
fix IH 1;
intros [|
b0 lb0];
simpl;
intros.
>
inv H;
auto.
>
case_eq (
build_scope_table_aux sc0 (
tab,
b)
b0);
intros;
rewrite H1 in *.
destruct b1.
>
exploit IH;
eauto.
simpl;
destruct 1;
auto.
>
destruct sc0;
exploit IH';
eauto.
destruct 1;
auto.
intuition.
>
intuition.
>
elim fold_build_scope_false_elim with (1:=
H).
Defined.
Lemma sc_In_get_inv :
forall b0 h0 l0 tab b tab',
build_scope_table_aux (
h0,
l0) (
tab,
b)
b0 = (
tab',
true) ->
forall h n lb,
PTree.get n (
fst tab') =
Some (
h,
lb) ->
PTree.get n (
fst tab) =
Some (
h,
lb) \/
((
h,
lb) = (
h0,
l0) /\
b0 =
I n) \/
(
In (
I n) (
I h ::
lb) /\
sc_In h lb b0).
Proof.
fix 1.
intros [
n|
h0 lb0];
simpl in *.
>
destruct tab;
intros.
inv H;
simpl in *.
rewrite PTree.gsspec in *;
destruct peq.
>
inv H0;
auto.
>
auto.
>
intros h1 l0 tab b tab'
H h n lb H0.
destruct tab;
simpl in *.
exploit (
fold_sc_In_get_inv sc_In_get_inv);
eauto;
simpl;
clear H.
intuition.
>
rewrite PTree.gsspec in *;
destruct peq;
auto.
inv H1;
intuition.
>
inv H1;
intuition.
Qed.
Lemma sc_In_get_main_inv :
forall b lb0 tab',
build_scope_table (
b,
lb0) =
OK tab' ->
forall h n lb,
PTree.get n (
fst tab') =
Some (
h,
lb) ->
In (
I n) (
I h ::
lb) /\
sc_In h lb (
L b lb0).
Proof.
Lemma In_scope_get_fst_inv :
forall main tab,
build_scope_table main =
OK tab ->
forall n sc,
PTree.get n (
fst tab) =
Some sc ->
In_scope main n sc.
Proof.
Lemma get_fst_In_scope_iff :
forall main tab,
build_scope_table main =
OK tab ->
forall n sc,
In_scope main n sc <->
PTree.get n (
fst tab) =
Some sc.
Proof.
Lemma get_fst_of_my_header :
forall main tab,
build_scope_table main =
OK tab ->
forall n h l,
PTree.get n (
fst tab) =
Some (
h,
l) ->
PTree.get h (
fst tab) =
Some (
h,
l).
Proof.
Lemma get_root_main :
forall sc tab',
build_scope_table sc =
OK tab' ->
(
fst tab')!(
fst sc) =
Some sc.
Proof.
Lemma fold_in_parent :
(
forall b0 sc0 tab b tab',
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab',
true) ->
(
fst tab)!(
fst sc0) =
Some sc0 ->
In b0 (
snd sc0) ->
forall p n,
PTree.get n (
snd tab') =
Some p ->
PTree.get n (
snd tab) =
Some p \/
(
exists sc,
PTree.get p (
fst tab') =
Some (
p,
sc) /\
exists l,
In (
L n l)
sc)) ->
forall lb0 n p sc0 tab b tab',
fold_left (
build_scope_table_aux sc0)
lb0 (
tab,
b) = (
tab',
true) ->
(
fst tab)!(
fst sc0) =
Some sc0 ->
(
incl lb0 (
snd sc0)) ->
(
snd tab') !
n =
Some p ->
PTree.get n (
snd tab) =
Some p \/
(
exists sc,
PTree.get p (
fst tab') =
Some (
p,
sc) /\
exists l,
In (
L n l)
sc).
Proof.
intros IH';
fix IH 1;
intros [|
b lb];
simpl;
intros.
>
inv H;
auto.
>
case_eq (
build_scope_table_aux sc0 (
tab,
b0)
b).
intros tab1 b1 Hb.
destruct b1.
>
rewrite Hb in *.
exploit IH;
eauto with datatypes.
destruct 1;
auto.
exploit IH';
eauto.
destruct 1;
auto.
destruct H4 as (
sc &
S1 &
S2).
right;
exists sc;
split;
eauto.
>
rewrite Hb in *.
elim fold_build_scope_false_elim with (1:=
H).
Defined.
Lemma in_parent :
forall b0 sc0 tab b tab',
build_scope_table_aux sc0 (
tab,
b)
b0 = (
tab',
true) ->
(
fst tab)!(
fst sc0) =
Some sc0 ->
In b0 (
snd sc0) ->
forall p n,
PTree.get n (
snd tab') =
Some p ->
PTree.get n (
snd tab) =
Some p \/
(
exists sc,
PTree.get p (
fst tab') =
Some (
p,
sc) /\
exists l,
In (
L n l)
sc).
Proof.
fix 1.
intros [
n|
h0 lb0];
simpl in *.
>
destruct tab;
intros.
inv H;
simpl in *;
auto.
>
intros sc0 tab b tab'
H Hp1 Hp2 p n H0.
destruct tab;
simpl in *.
exploit (
fold_in_parent in_parent);
eauto with datatypes;
simpl.
rewrite PTree.gss;
auto.
destruct 1;
auto.
rewrite PTree.gsspec in *;
destruct peq;
auto.
inv H1;
auto.
destruct sc0;
simpl in *.
right;
exists l;
split;
eauto.
eapply fold_build_scope_table_same;
eauto.
simpl.
rewrite PTree.gsspec in *;
destruct peq;
auto.
assert (
ptree_mem h0 t0=
true).
unfold ptree_mem.
rewrite <-
e;
rewrite Hp1;
auto.
rewrite H1 in H;
simpl in *.
elim fold_build_scope_false_elim with (1:=
H).
Qed.
Lemma in_parent_main :
forall main tab,
build_scope_table main =
OK tab ->
forall p n,
(
snd tab)!
n =
Some p ->
(
exists sc, (
fst tab)!
p =
Some (
p,
sc) /\
exists l,
In (
L n l)
sc).
Proof.
Section In_fold1.
Variable n0:
node.
Variable f:
list node ->
bourdoncle ->
list node.
Variable P:
forall b l,
In n0 l ->
In n0 (
f l b).
Lemma In_fold1:
forall lb l,
In n0 l ->
In n0 (
fold_left f lb l).
Proof.
fix 1.
intros [|
b lb]
l Hi;
simpl.
apply Hi.
apply In_fold1.
apply P.
apply Hi.
Defined.
End In_fold1.
Lemma in_acc_in_bourdoncle_elements :
forall n0 b l,
In n0 l ->
In n0 (
bourdoncle_elements l b).
Proof.
intros n0.
fix 1.
intros [
n|
h lb];
simpl in *;
auto.
intros l Hl.
apply In_fold1.
apply in_acc_in_bourdoncle_elements.
right;
auto.
Qed.
Section In_fold2.
Variable n0:
node.
Variable Q :
bourdoncle ->
Prop.
Variable f:
list node ->
bourdoncle ->
list node.
Variable P1:
forall b l,
In n0 l ->
In n0 (
f l b).
Variable P2:
forall b l,
Q b ->
In n0 (
f l b).
Lemma In_fold2:
forall lb l b,
In b lb ->
Q b ->
In n0 (
fold_left f lb l).
Proof.
fix 1.
intros [|
b lb]
l b0 H1 H2.
elim H1.
simpl in H1;
destruct H1.
simpl.
apply In_fold1.
apply P1.
apply P2.
subst;
auto.
simpl.
apply (
In_fold2 lb (
f l b)
b0);
auto.
Defined.
End In_fold2.
Lemma in_bourdoncle_in_bourdoncle_elements :
forall n0 b l,
in_bourdoncle n0 b =
true ->
In n0 (
bourdoncle_elements l b).
Proof.
Section In_fold3.
Variable n0:
node.
Variable Q :
bourdoncle ->
Prop.
Variable f:
list node ->
bourdoncle ->
list node.
Variable P:
forall b l,
In n0 (
f l b) ->
Q b \/
In n0 l.
Lemma In_fold3:
forall lb l,
In n0 (
fold_left f lb l) ->
(
exists b,
In b lb /\
Q b) \/
In n0 l.
Proof.
fix 1.
intros [|
h lb]
l;
simpl;
intros Hi.
auto.
destruct (
In_fold3 _ _ Hi).
destruct H as (
b &
B1 &
B2);
left;
eauto.
destruct (
P _ _ H);
eauto.
Defined.
End In_fold3.
Lemma in_bourdoncle_elements_in_bourdoncle :
forall n0 b l,
In n0 (
bourdoncle_elements l b) ->
in_bourdoncle n0 b =
true \/
In n0 l.
Proof.
Lemma in_bourdoncle_elements_sc_In_aux:
(
forall b n l,
In n (
bourdoncle_elements l b) ->
In n l \/
b =
I n \/
exists h,
exists lb,
In (
I n) (
I h ::
lb) /\
sc_In h lb b) ->
(
forall l n l0 h',
In n (
fold_left bourdoncle_elements l l0) ->
In n l0 \/
In (
I n)
l \/
exists h,
exists lb,
In (
I n) (
I h ::
lb) /\
sc_In h lb (
L h'
l)).
Proof.
intros HP.
fix IH 1; intros [|n0 l0]; simpl; auto.
intros n l1 h' Hi.
destruct (IH _ _ _ h' Hi) as [H1|[H1|H1]]; clear IH.
> destruct (HP _ _ _ H1); clear HP; auto.
destruct H; subst; auto.
destruct H as (h & lb & L1 & L2).
right; right.
exists h; exists lb; split; auto.
> auto.
> destruct H1 as (h & lb & L1 & L2).
right; right.
simpl in L2; destruct L2.
> destruct H; subst.
exists h; exists (n0::lb); split; auto.
simpl in *; destruct L1; subst; auto.
> exists h; exists lb; auto.
Defined.
Lemma in_bourdoncle_elements_sc_In:
forall b n l,
In n (
bourdoncle_elements l b) ->
In n l \/
b =
I n \/
exists h,
exists lb,
In (
I n) (
I h ::
lb) /\
sc_In h lb b.
Proof.
fix IH 1;
intros [
n0|
h0 lb0];
simpl.
>
destruct 1;
auto.
subst;
auto.
>
intros.
destruct (
in_bourdoncle_elements_sc_In_aux IH _ _ _ h0 H);
clear H.
>
simpl in H0;
destruct H0;
auto.
right;
right;
subst.
exists n;
exists lb0;
auto.
>
right;
right.
destruct H0.
>
exists h0;
exists lb0;
split;
auto.
>
destruct H as (
h &
lb &
L1 &
L2).
simpl in L2.
eauto.
Qed.
Lemma in_nodes:
forall n sc,
In n (
nodes sc) ->
exists sc_n,
In_scope sc n sc_n.
Proof.
intros n (
b,
l)
Hi;
simpl in *.
unfold In_scope.
destruct (
in_bourdoncle_elements_sc_In_aux in_bourdoncle_elements_sc_In _ _ _ b Hi);
clear Hi.
simpl in H;
intuition;
subst.
>
exists (
n,
l);
simpl;
auto.
>
destruct H.
>
exists (
b,
l);
simpl;
auto.
>
destruct H as (
h &
lb &
L1 &
L2).
exists (
h,
lb);
split;
auto.
Qed.
Lemma fold_sc_In_in_bourdoncle_elements:
(
forall b h lb l,
sc_In h lb b ->
In h (
bourdoncle_elements l b)) ->
forall l h lb l0,
Exists (
sc_In h lb)
l ->
In h (
fold_left bourdoncle_elements l l0).
Proof.
Lemma sc_In_in_bourdoncle_elements:
forall b h lb l,
sc_In h lb b ->
In h (
bourdoncle_elements l b).
Proof.
Lemma Exists_exists :
forall A P (
l:
list A),
Exists P l <->
exists x,
In x l /\
P x.
Proof.
induction l; simpl; intuition eauto.
destruct H as (x & H1 & H2); eauto.
destruct H1 as (x & H3 & H4); eauto.
destruct H1 as (x & H3 & H4); intuition eauto.
subst; auto.
Qed.
Lemma sc_In_in_bourdoncle_elements2:
forall b h lb l n,
In (
I n)
lb ->
sc_In h lb b ->
In n (
bourdoncle_elements l b).
Proof.
Lemma in_nodes_inv:
forall n sc sc_n,
In_scope sc n sc_n ->
In n (
nodes sc).
Proof.
Lemma list_sc_In_trans:
(
forall b0 n1 l1 n2 l2,
sc_In n1 l1 b0 ->
sc_In n2 l2 (
L n1 l1) ->
sc_In n2 l2 b0) ->
forall l0 n1 l1 n2 l2,
Exists (
sc_In n1 l1)
l0 ->
Exists (
sc_In n2 l2)
l1 ->
Exists (
sc_In n2 l2)
l0.
Proof.
intros HP.
fix IH' 1; intros [|n l]; intros; simpl in *; intuition.
> exploit (HP n); eauto.
> exploit (IH' l); eauto.
Defined.
Lemma sc_In_trans:
forall b0 n1 l1 n2 l2,
sc_In n1 l1 b0 ->
sc_In n2 l2 (
L n1 l1) ->
sc_In n2 l2 b0.
Proof.
fix IH 1;
intros [
n0|
n0 l0];
intros;
simpl in *.
intuition.
intuition;
subst;
auto.
right.
eapply list_sc_In_trans;
eauto.
Qed.
Lemma In_scope_trans:
forall sc0 n1 sc1 n2 sc2,
In_scope sc0 n1 sc1 ->
In_scope sc1 n2 sc2 ->
In_scope sc0 n2 sc2.
Proof.
Notation "
sc1 ⊆
sc2" := (
incl (
nodes sc1) (
nodes sc2)) (
at level 10).
Lemma In_scope_incl:
forall (
sc:
t) (
n:
node) (
sc_n:
t),
In_scope sc n sc_n ->
sc_n ⊆
sc.
Proof.
Definition in_scope_test (
n:
node) (
s:
t) :
bool :=
let (
h,
l) :=
s in
Peqb n h ||
List.existsb (
in_bourdoncle n)
l.
Lemma in_scope_test_correct :
forall sc n,
in_scope_test n sc =
true <->
In n (
nodes sc).
Proof.
Definition incl_scope_test (
s1 s2:
t) :
bool :=
List.forallb (
fun n =>
in_scope_test n s2) (
nodes s1).
Lemma incl_scope_test_correct :
forall sc1 sc2,
incl_scope_test sc1 sc2 =
true <->
sc1 ⊆
sc2.
Proof.
Section scope_properties.
Variable f :
function.
Variable main :
t.
Variable tab:
scope_table.
Variable headers:
list node.
Let elements:
list t :=
map (
scope_ tab main)
headers.
Hypothesis get_fst_In_scope_iff :
forall n sc,
In_scope main n sc <->
PTree.get n (
fst tab) =
Some sc.
Hypothesis f_In_In_scope :
forall n,
f_In n f ->
PTree.get n (
fst tab) <>
None.
Hypothesis in_headers1:
forall h,
In h headers ->
exists l,
PTree.get h (
fst tab) =
Some (
h,
l).
Hypothesis in_headers2:
forall h,
In h headers ->
f_In h f.
Hypothesis root_In_headers:
In f.(
fn_entrypoint)
headers.
Hypothesis snd_root:
PTree.get f.(
fn_entrypoint) (
snd tab) =
None.
Hypothesis scope_root: (
fst tab)!(
f.(
fn_entrypoint)) =
Some main.
Hypothesis in_headers3:
forall h l,
PTree.get h (
fst tab) =
Some (
h,
l) ->
In h headers.
Hypothesis get_fst_of_my_header :
forall n h l,
PTree.get n (
fst tab) =
Some (
h,
l) ->
PTree.get h (
fst tab) =
Some (
h,
l).
Hypothesis parent_is_header :
forall h p,
PTree.get h (
snd tab) =
Some p ->
In p headers.
Hypothesis parent_tab:
forall p n,
(
snd tab)!
n =
Some p ->
(
exists sc, (
fst tab)!
p =
Some sc /\
exists l,
In (
L n l) (
snd sc)).
Hypothesis check_root:
forall h,
In h headers ->
h=
f.(
fn_entrypoint) \/
in_scope_test f.(
fn_entrypoint) (
scope_ tab main h) =
false.
Hypothesis headers_snd_some:
forall h,
In h headers ->
h =
f.(
fn_entrypoint) \/
exists p, (
snd tab)!
h =
Some p /\
in_scope_test p (
scope_ tab main h) =
false.
Hypothesis parent_least_check:
forall h h',
In h headers ->
In h'
headers ->
h<>
h' ->
In h (
nodes (
scope_ tab main h')) ->
match (
snd tab)!
h with
|
None =>
True
|
Some p =>
In p (
nodes (
scope_ tab main h'))
end.
Lemma in_scope:
forall n,
f_In n f ->
In n (
nodes (
scope_ tab main n)).
Proof.
Lemma scope_least:
forall n sc,
In sc elements ->
In n (
nodes sc) -> (
scope_ tab main n) ⊆
sc.
Proof.
Lemma header_scope_:
forall h,
In h headers ->
header_ (
scope_ tab main h) =
h.
Proof.
unfold scope_,
header_;
intros h.
intros;
destruct in_headers1 with h as (
l &
L);
auto.
rewrite L;
auto.
Qed.
Lemma header_f_In:
forall sc,
In sc elements ->
f_In (
header_ sc)
f.
Proof.
unfold elements;
intros.
rewrite in_map_iff in H.
destruct H as (
h &
T1 &
T2).
subst;
rewrite header_scope_;
auto.
Qed.
Lemma scope_header:
forall sc,
In sc elements ->
scope_ tab main (
header_ sc) =
sc.
Proof.
unfold elements,
scope_;
intros.
rewrite in_map_iff in H.
destruct H as (
h &
T1 &
T2).
apply in_headers1 in T2.
destruct T2 as (
l &
T2).
rewrite T2 in *.
subst;
simpl in *.
rewrite T2;
auto.
Qed.
Lemma scope_main_or_in_header:
forall n,
exists h,
In h headers /\
scope_ tab main n =
scope_ tab main h.
Proof.
intros;
unfold scope_.
case_eq ((
fst tab)!
n);
intros.
destruct p as (
h &
l).
assert ((
fst tab)!
h =
Some (
h,
l))
by (
eauto).
exists h;
rewrite H0.
split;
eauto.
exists (
f.(
fn_entrypoint));
split;
auto.
rewrite scope_root;
auto.
Qed.
Lemma scope_in_elements:
forall n,
In (
scope_ tab main n)
elements.
Proof.
Lemma incl_in_parent:
forall sc,
In sc elements ->
sc ⊆ (
parent_ tab sc).
Proof.
Lemma parent_least:
forall sc sc',
In sc elements ->
In sc'
elements ->
sc ⊆
sc' ->
sc =
sc' \/ (
parent_ tab sc) ⊆
sc'.
Proof.
Lemma In_sons_aux:
forall b0 lb0 lb l,
In (
b0,
lb0) (
fold_left sons1 lb l) ->
In (
L b0 lb0)
lb \/
In (
b0,
lb0)
l.
Proof.
induction lb; simpl; auto.
intros.
elim IHlb with (1:=H); auto.
destruct a; simpl; intuition.
left; left; congruence.
Qed.
Lemma sons_in_element:
forall sc sc',
In sc elements ->
In sc' (
sons sc) ->
In sc'
elements.
Proof.
Lemma parent_in_element:
forall sc,
In sc elements ->
In (
parent_ tab sc)
elements.
Proof.
unfold elements,
parent_;
intros.
destruct sc as (
h &
l);
simpl.
case_eq ((
snd tab)!
h);
intros;
auto.
elim parent_tab with (1:=
H0);
intros sc (
S1 &
lh &
S2).
rewrite S1.
replace sc with (
scope_ tab main p).
apply scope_in_elements.
unfold scope_;
rewrite S1;
auto.
Qed.
Lemma in_scope_root:
forall sc,
In sc elements ->
In f.(
fn_entrypoint) (
nodes sc) ->
f.(
fn_entrypoint) =
header_ sc.
Proof.
Lemma parent_strict_subset:
forall sc,
In sc elements ->
In (
header_ (
parent_ tab sc)) (
nodes sc) ->
f.(
fn_entrypoint) =
header_ sc.
Proof.
unfold parent_,
elements;
intros.
rewrite in_map_iff in H.
destruct H as (
h &
H1 &
H2).
elim in_headers1 with h;
auto;
intros l Hl.
generalize H1;
unfold scope_.
rewrite Hl;
simpl;
intros;
subst.
rewrite <-
H3;
simpl.
elim headers_snd_some with h;
auto.
intros (
p &
P1 &
P2).
rewrite <-
H3 in H0;
simpl in H0.
rewrite P1 in H0.
assert (
In p (
nodes (
scope_ tab main h))).
rewrite <-
H3;
simpl.
elim in_headers1 with p;
eauto.
intros lp L.
rewrite L in H0;
auto.
rewrite <-
in_scope_test_correct in H.
congruence.
Qed.
Variable order:
node ->
N.
Notation scope := (
scope_ tab main).
Notation parent := (
parent_ tab).
Hypothesis succ_order:
forall n s,
succ_node f n s -> (
order n <
order s)%
N \/
s =
header_ (
scope n).
Hypothesis
enter_in_scope_at_header_only:
forall n n',
succ_node f n n' ->
~
In n (
nodes (
scope n')) ->
n' =
header_ (
scope n') /\
parent (
scope n') =
scope n.
Lemma enter_in_scope_at_header_only1:
forall n n'
sc,
succ_node f n n' ->
In sc elements ->
~
In n (
nodes sc) ->
In n' (
nodes sc) ->
n' =
header_ sc.
Proof.
Lemma path_inv0 :
forall n1 tr n2,
path f n1 tr n2 ->
incl (
n1::
tr) (
nodes (
scope n2)) ->
forall sc,
In sc elements -> ~
In n2 (
nodes sc) ->
In n1 (
nodes sc) ->
In (
header_ sc) (
n1::
tr).
Proof.
Lemma path_inv1 :
forall n1 tr n2,
f_In n1 f ->
path f n1 tr n2 ->
incl (
n1::
tr) (
nodes (
scope n2)) ->
~
In n2 (
nodes (
scope n1)) ->
In (
header_ (
scope n1)) (
n1::
tr).
Proof.
Lemma path_in_other_path:
forall n1 tr n2,
path f n1 tr n2 ->
forall n3,
In n3 (
n1::
tr) ->
exists tr',
path f n3 tr'
n2 /\
incl tr'
tr /\ (
length tr' <=
length tr)%
nat.
Proof.
induction 1;
simpl;
intros.
>
intuition;
subst.
exists nil;
repeat constructor;
auto with datatypes.
>
destruct H1.
>
subst.
exists (
n'::
rl);
split;
auto.
>
econstructor;
eauto.
>
split;
auto with datatypes.
>
elim IHrev_path with n3;
auto;
intros tr' (
T1 &
T2 &
T3).
exists tr';
split;
auto.
split;
auto with datatypes.
Qed.
Lemma header_in_scope:
forall sc,
In sc elements ->
In (
header_ sc) (
nodes sc).
Proof.
Lemma sim_in_scope:
forall n1 n2,
In n1 (
nodes (
scope n2)) ->
In n2 (
nodes (
scope n1)) ->
header_ (
scope n1) =
header_ (
scope n2).
Proof.
Lemma path_inv2:
forall N n1 tr n2,
length tr =
N ->
path f n1 tr n2 ->
incl (
n1::
tr) (
nodes (
scope n2)) ->
(
order n2 <
order n1)%
N \/
In (
header_ (
scope n2)) (
n1::
tr) \/
tr=
nil.
Proof.
Lemma path_incl_case:
forall n1 rl n,
path f n1 rl n ->
In n1 (
nodes (
scope n)) ->
incl rl (
nodes (
scope n)) \/
In (
header_ (
scope n)) (
n1::
rl).
Proof.
Lemma cycle_at_not_header:
forall rl n,
f_In n f ->
n <>
header_ (
scope n) ->
path f n rl n ->
rl <>
nil ->
In (
header_ (
scope n))
rl.
Proof.
Lemma path_header_aux:
forall n1 rl n,
path f n1 rl n ->
n =
header_ (
scope n) ->
incl (
n1::
rl) (
nodes (
scope n)) \/
~
In n1 (
nodes (
scope n)) \/
exists rl',
exists n',
incl (
n'::
rl')
rl /\
path f n (
n'::
rl')
n /\
~
In n' (
nodes (
scope n)).
Proof.
induction 1.
>
left;
intro;
simpl;
intuition.
subst;
apply in_scope;
auto.
>
destruct (
List.In_dec peq n'' (
nodes (
scope n)));
intros;
auto.
destruct IHrev_path;
eauto with datatypes.
destruct H2.
>
exploit enter_in_scope_at_header_only1;
eauto.
apply scope_in_elements.
intros.
right;
right;
exists rl;
exists n';
repeat split;
auto with datatypes.
constructor;
auto.
congruence.
>
destruct H2 as (
rl' &
n0 &
N1 &
N2 &
N3).
right;
right;
exists rl';
exists n0;
repeat split;
auto with datatypes.
Qed.
Lemma path_header:
forall rl n,
f_In n f ->
path f n rl n ->
n =
header_ (
scope n) ->
incl rl (
nodes (
scope n)) \/
exists rl',
exists n',
incl (
n'::
rl')
rl /\
path f n (
n'::
rl')
n /\
parent (
scope n) =
scope n'.
Proof.
intros.
edestruct path_header_aux;
eauto with datatypes.
destruct H2.
>
destruct H2.
apply in_scope;
auto.
>
destruct H2 as (
rl' &
n' &
N1 &
N2 &
N3).
right;
exists rl';
exists n';
repeat split;
auto.
exploit enter_in_scope_at_header_only;
eauto.
inversion N2;
auto.
intuition.
Qed.
Lemma rotate_path:
forall n'
rl n,
path f n'
rl n ->
forall n'',
f_In n''
f ->
succ_node f n''
n ->
path f n' (
rl++
n''::
nil)
n''.
Proof.
induction 1; simpl.
> constructor; auto.
constructor; auto.
> intros.
exploit IHrev_path; eauto; clear IHrev_path; intros IH.
constructor; auto.
Qed.
Lemma cycle_at_header:
forall rl n,
f_In n f ->
n =
header_ (
scope n) ->
path f n rl n ->
rl <>
nil ->
In (
header_ (
parent_ tab (
scope n)))
rl \/
(
forall n',
In n'
rl ->
In n' (
nodes (
scope n))).
Proof.
intros.
exploit path_header;
eauto.
destruct 1;
auto.
destruct H3 as (
rl' &
n' &
N1 &
N2 &
N3);
left.
clear H1 H2.
revert H0;
inv N2;
intuition.
assert (
path f n' (
rl'++
n'::
nil)
n').
eapply rotate_path;
eauto.
eapply succ_f_In;
eauto.
rewrite N3 in *.
destruct (
peq n' (
header_ (
scope n')));
auto.
apply N1;
simpl;
left;
congruence.
exploit (
cycle_at_not_header (
rl' ++
n' ::
nil)
n');
eauto.
eapply succ_f_In;
eauto.
destruct rl';
simpl;
congruence.
rewrite in_app;
intros.
apply N1.
simpl;
intuition.
simpl in H4;
intuition.
Qed.
End scope_properties.
End I.
Notation "
n ∈
sc" := (
In n (
nodes sc)) (
at level 10).
Notation "
sc1 ⊆
sc2" := (
incl (
nodes sc1) (
nodes sc2)) (
at level 10).
Record family (
f:
function) := {
scope :
node ->
t;
header :
t ->
node;
parent :
t ->
t;
elements:
list t;
in_scope:
forall n,
f_In n f ->
n ∈ (
scope n);
scope_least:
forall n sc,
In sc elements ->
n ∈
sc -> (
scope n) ⊆
sc;
header_f_In:
forall sc,
In sc elements ->
f_In (
header sc)
f;
scope_header:
forall sc,
In sc elements ->
scope (
header sc) =
sc;
incl_in_parent:
forall sc,
In sc elements ->
sc ⊆ (
parent sc);
parent_least:
forall sc sc',
In sc elements ->
In sc'
elements ->
sc ⊆
sc' ->
sc =
sc' \/ (
parent sc) ⊆
sc';
sons_in_element:
forall sc sc',
In sc elements ->
In sc' (
sons sc) ->
In sc'
elements;
parent_in_element:
forall sc,
In sc elements ->
In (
parent sc)
elements;
scope_in_elements:
forall n,
In (
scope n)
elements;
enter_in_scope_at_header_only:
forall n n',
succ_node f n n' ->
~
n ∈ (
scope n') ->
n' =
header (
scope n') /\
parent (
scope n') =
scope n;
cycle_at_not_header:
forall rl n,
f_In n f ->
n <>
header (
scope n) ->
path f n rl n ->
rl <>
nil ->
In (
header (
scope n))
rl;
cycle_at_header:
forall rl n,
f_In n f ->
n =
header (
scope n) ->
path f n rl n ->
rl <>
nil ->
In (
header (
parent (
scope n)))
rl \/
(
forall n',
In n'
rl ->
n' ∈ (
scope n));
in_scope_root:
forall sc,
In sc elements ->
f.(
fn_entrypoint) ∈
sc ->
f.(
fn_entrypoint) =
header sc;
parent_strict_subset:
forall sc,
In sc elements ->
(
header (
parent sc)) ∈
sc ->
f.(
fn_entrypoint) =
header sc;
root_no_pred:
forall n, ~
succ_node f n f.(
fn_entrypoint)
}.
Implicit Arguments scope [
f].
Implicit Arguments header [
f].
Implicit Arguments parent [
f].
Implicit Arguments elements [
f].
Lemma po1:
forall f (
tab:
I.scope_table),
ptree_forall (
fn_code f)
(
fun (
n :
node) (
_ :
instruction) =>
ptree_mem n (
fst tab)) =
true ->
forall n0 :
RTL.node,
f_In n0 f -> (
fst tab) !
n0 <>
None.
Proof.
Definition headers {
A} (
tab:
PTree.t (
node*
A)) :
list node :=
PTree.fold (
fun l p a =>
if peq p (
fst a)
then p::
l else l)
tab nil.
Lemma in_headers1 :
forall A tab h,
In h (@
headers A tab) ->
exists a,
tab!
h =
Some (
h,
a).
Proof.
intros A tab h;
unfold headers.
apply PTree_Properties.fold_rec
with (
P:=
fun m l =>
In h l ->
exists a,
m!
h =
Some (
h,
a));
intros.
rewrite <-
H;
auto.
intuition.
destruct peq.
simpl in H2;
destruct H2;
subst.
rewrite H2;
rewrite PTree.gss;
auto.
destruct v;
simpl in *.
subst;
eauto.
rewrite PTree.gsspec;
destruct peq.
destruct v;
simpl in *.
subst;
eauto.
eauto.
rewrite PTree.gsspec;
destruct peq.
subst.
elim H1;
auto;
intros;
congruence.
eauto.
Qed.
Lemma in_headers2 :
forall A tab a h,
tab!
h =
Some (
h,
a) ->
In h (@
headers A tab).
Proof.
Definition forall_cfg_edge (
f:
function) (
test:
node->
node->
bool) :
bool :=
ptree_forall (
fn_code f)
(
fun n ins =>
forallb (
fun n' =>
test n n') (
successors_instr ins)).
Lemma forall_cfg_edge_correct :
forall f test,
forall_cfg_edge f test =
true ->
forall n n',
succ_node f n n' ->
test n n' =
true.
Proof.
Definition build_family (
f:
function) :
option (
family f).
Proof.
destruct (
build_bourdoncle f)
as (
b &
order).
case_eq (
I.cast_bourdoncle b); [
intros (
h,
l)
Hb|
intros;
exact None].
case_eq (
I.build_scope_table (
h,
l)); [
intros tab Htab|
intros;
exact None].
destruct (
peq h f.(
fn_entrypoint)); [|
exact None].
case_eq (
ptree_forall (
fn_code f) (
fun n _ =>
ptree_mem n (
fst tab)));
intros Hp1; [|
exact None].
set (
headers :=
headers (
fst tab)).
set (
elements:=
map (
I.scope_ tab (
h,
l))
headers).
case_eq (
forallb (
fun h =>
ptree_mem h (
fn_code f))
headers);
intros Hf1; [|
exact None].
assert(
get_fst_In_scope_iff :
forall n sc,
I.In_scope (
h,
l)
n sc <->
PTree.get n (
fst tab) =
Some sc).
eapply I.get_fst_In_scope_iff;
eauto.
assert (
f_In_In_scope :
forall n,
f_In n f ->
PTree.get n (
fst tab) <>
None).
eapply po1;
eauto.
assert (
in_headers1:
forall h,
In h headers ->
exists l,
PTree.get h (
fst tab) =
Some (
h,
l)).
apply in_headers1.
assert (
root_In_headers:
In f.(
fn_entrypoint)
headers).
exploit I.get_root_main;
eauto.
simpl;
rewrite <-
e.
intros;
eapply in_headers2;
eauto.
assert (
in_headers3:
forall h l,
PTree.get h (
fst tab) =
Some (
h,
l) ->
In h headers).
intros;
eapply in_headers2;
eauto.
assert (
in_headers2:
forall h,
In h headers ->
f_In h f).
rewrite forallb_forall in Hf1.
intros;
exploit Hf1;
eauto.
unfold f_In,
ptree_mem.
destruct ((
fn_code f)!
h0);
congruence.
case_eq (
PTree.get f.(
fn_entrypoint) (
snd tab)); [
intros;
exact None|
intros snd_root].
assert (
scope_root: (
fst tab)!(
f.(
fn_entrypoint)) =
Some (
h,
l)).
exploit I.get_root_main;
eauto.
rewrite <-
e;
auto.
assert (
get_fst_of_my_header :
forall n h l,
PTree.get n (
fst tab) =
Some (
h,
l) ->
PTree.get h (
fst tab) =
Some (
h,
l)).
intros;
eapply I.get_fst_of_my_header;
eauto.
assert (
parent_is_header :
forall h p,
PTree.get h (
snd tab) =
Some p ->
In p headers).
intros.
exploit I.in_parent_main;
eauto.
intros (
ll &
H1 &
l0 &
H2).
eauto.
assert (
parent_tab:
forall p n,
(
snd tab)!
n =
Some p ->
(
exists sc, (
fst tab)!
p =
Some sc /\
exists l,
In (
L n l) (
snd sc))).
intros.
exploit I.in_parent_main;
eauto.
intros (
ll &
H1 &
l0 &
H2).
eauto.
case_eq (
forallb (
fun h0 =>
if peq h0 f.(
fn_entrypoint)
then true else
negb (
I.in_scope_test f.(
fn_entrypoint) (
I.scope_ tab (
h,
l)
h0)))
headers);
intros Hf2; [|
exact None].
assert (
check_root:
forall h0,
In h0 headers ->
h0=
f.(
fn_entrypoint) \/
I.in_scope_test f.(
fn_entrypoint) (
I.scope_ tab (
h,
l)
h0) =
false).
rewrite forallb_forall in Hf2.
intros;
exploit Hf2;
eauto.
destruct peq;
auto;
right.
destruct I.in_scope_test;
simpl in *;
congruence.
case_eq (
forallb (
fun h0 =>
if peq h0 f.(
fn_entrypoint)
then true else
match (
snd tab)!
h0 with
|
None =>
false
|
Some p =>
negb (
I.in_scope_test p (
I.scope_ tab (
h,
l)
h0))
end)
headers);
intros Hf3; [|
exact None].
assert (
headers_snd_some:
forall h0,
In h0 headers ->
h0 =
f.(
fn_entrypoint) \/
exists p, (
snd tab)!
h0 =
Some p /\
I.in_scope_test p (
I.scope_ tab (
h,
l)
h0) =
false).
rewrite forallb_forall in Hf3.
intros;
exploit Hf3;
eauto.
destruct peq;
auto;
right.
case_eq ((
snd tab)!
h0);
intros;
rewrite H1 in *;
try congruence.
exists p;
split;
auto.
destruct I.in_scope_test;
simpl in *;
congruence.
case_eq (
forallb (
fun h0 =>
forallb (
fun h' =>
if peq h0 h'
then true else
if I.in_scope_test h0 (
I.scope_ tab (
h,
l)
h')
then
match (
snd tab)!
h0 with
|
None =>
true
|
Some p =>
I.in_scope_test p (
I.scope_ tab (
h,
l)
h')
end
else true)
headers)
headers);
intros Hf4; [|
exact None].
assert (
parent_least_check:
forall h0 h',
In h0 headers ->
In h'
headers ->
h0<>
h' ->
In h0 (
nodes (
I.scope_ tab (
h,
l)
h')) ->
match (
snd tab)!
h0 with
|
None =>
True
|
Some p =>
In p (
nodes (
I.scope_ tab (
h,
l)
h'))
end).
intros.
rewrite forallb_forall in Hf4.
apply Hf4 in H;
clear Hf4.
rewrite forallb_forall in H.
apply H in H0;
clear H.
destruct peq;
try (
elim H1;
assumption).
rewrite <-
I.in_scope_test_correct in H2.
rewrite H2 in *.
case_eq ((
snd tab)!
h0);
intros;
rewrite H in *;
auto.
rewrite <-
I.in_scope_test_correct;
auto.
case_eq (
forall_cfg_edge f
(
fun n n' =>
if I.in_scope_test n (
I.scope_ tab (
h,
l)
n')
then true
else (
peq n' (
I.header_ (
I.scope_ tab (
h,
l)
n')))
&& (
peq (
I.header_ (
I.parent_ tab (
I.scope_ tab (
h,
l)
n')))
(
I.header_ (
I.scope_ tab (
h,
l)
n)))));
intros Hf5; [|
exact None].
case_eq (
forall_cfg_edge f
(
fun n s =>
nlt (
PMap.get n order) (
PMap.get s order)
||
peq s (
I.header_ (
I.scope_ tab (
h,
l)
n))));
intros Hf6; [|
exact None].
assert (
succ_order:
forall n s,
succ_node f n s -> ((
PMap.get n order) < (
PMap.get s order))%
N \/
s =
I.header_ (
I.scope_ tab (
h,
l)
n)).
intros.
exploit forall_cfg_edge_correct;
eauto;
simpl.
simpl.
rewrite orb_true_iff;
destruct 1.
destruct nlt;
auto.
inv H0.
destruct peq;
auto.
inv H0.
assert (
enter_in_scope_at_header_only:
forall n n',
succ_node f n n' ->
~
In n (
nodes (
I.scope_ tab (
h,
l)
n')) ->
n' =
I.header_ (
I.scope_ tab (
h,
l)
n') /\
I.parent_ tab (
I.scope_ tab (
h,
l)
n') =
I.scope_ tab (
h,
l)
n).
intros.
clear Hf6.
exploit forall_cfg_edge_correct;
eauto;
clear Hf5;
simpl.
rewrite <-
I.in_scope_test_correct in H0.
destruct I.in_scope_test;
try congruence.
destruct (
peq n' (
I.header_ (
I.scope_ tab (
h,
l)
n')));
simpl;
try congruence.
destruct (
peq (
I.header_ (
I.parent_ tab (
I.scope_ tab (
h,
l)
n')))
(
I.header_ (
I.scope_ tab (
h,
l)
n)));
simpl;
try congruence.
intros _.
split;
auto.
assert (
I.scope_ tab (
h,
l) (
I.header_ (
I.parent_ tab (
I.scope_ tab (
h,
l)
n'))) =
I.scope_ tab (
h,
l) (
I.header_ (
I.scope_ tab (
h,
l)
n)))
by congruence.
erewrite I.scope_header in H1;
eauto.
erewrite I.scope_header in H1;
eauto.
eapply I.scope_in_elements;
eauto.
eapply I.parent_in_element;
eauto.
eapply I.scope_in_elements;
eauto.
case_eq (
forall_cfg_edge f
(
fun n n' =>
negb (
peq n'
f.(
fn_entrypoint))));
intros Hf7; [|
exact None].
apply Some.
apply (
Build_family _
(
I.scope_ tab (
h,
l))
I.header_
(
I.parent_ tab)
(
elements)).
eapply I.in_scope;
eauto.
intros n sc H1 H2;
eapply I.scope_least;
eauto.
unfold elements;
intros;
eapply I.header_f_In;
eauto.
unfold elements;
intros;
eapply I.scope_header;
eauto.
unfold elements;
intros;
eapply I.incl_in_parent;
eauto.
unfold elements;
intros;
eapply I.parent_least;
eauto.
unfold elements;
intros;
eapply I.sons_in_element;
eauto.
unfold elements;
intros;
eapply I.parent_in_element;
eauto.
unfold elements;
intros;
eapply I.scope_in_elements;
eauto.
assumption.
intros;
eapply I.cycle_at_not_header with (
order:=
fun n =>
PMap.get n order);
eauto.
intros;
eapply I.cycle_at_header with (
order:=
fun n =>
PMap.get n order);
eauto.
unfold elements;
intros;
eapply I.in_scope_root;
eauto.
unfold elements;
intros;
eapply I.parent_strict_subset;
eauto.
red;
intros.
exploit forall_cfg_edge_correct;
eauto.
simpl.
destruct peq;
intuition.
Qed.
End ImplemScope.
Module Scope:
SCOPE :=
ImplemScope.
Section transf_family.
Variable f tf:
function.
Variable fsc:
Scope.family f.
Variable same_dom:
forall n,
f_In n f <->
f_In n tf.
Variable same_cfg:
forall n s,
succ_node f n s <->
succ_node tf n s.
Variable same_fn_entrypoint:
f.(
fn_entrypoint) =
tf.(
fn_entrypoint).
Lemma same_path:
forall rl n n',
path tf n rl n' <->
path f n rl n'.
Proof.
unfold path.
induction rl;
split;
try constructor.
intros T;
inv T;
constructor.
rewrite same_dom;
auto.
intros T;
inv T;
constructor.
rewrite <-
same_dom;
auto.
inv H.
rewrite <-
same_cfg in *;
rewrite IHrl in *;
eauto.
inv H.
rewrite same_cfg in *;
rewrite IHrl in *;
eauto.
inv H.
rewrite same_cfg in *;
rewrite IHrl in *;
eauto.
inv H.
rewrite same_cfg in *;
auto.
Qed.
Definition transf_family :
Scope.family tf.
Proof.
End transf_family.
Notation "
n ∈
sc" := (
In n (
Scope.nodes sc)) (
at level 10).
Notation "
sc1 ⊆
sc2" := (
incl (
Scope.nodes sc1) (
Scope.nodes sc2)) (
at level 10).
Definition In_dec (
n:
node) (
sc:
Scope.t): {
n ∈
sc } + {~
n ∈
sc} :=
List.In_dec peq n (
Scope.nodes sc).
Hint Resolve Scope.in_scope Scope.scope_least.
Definition exited_scopes {
f} (
fsc:
Scope.family f) (
n n':
node) :
list node :=
flat_map
(
fun s =>
if In_dec n s &&
negb (
In_dec n'
s)
then Scope.nodes s else nil)
(
Scope.elements fsc).
Definition is_header {
f} (
fsc:
Scope.family f) (
n:
node) :
Prop :=
f_In n f /\
Scope.header fsc (
Scope.scope fsc n) =
n.
Lemma incl_in :
forall sc1 sc2 n,
n ∈
sc1 ->
sc1 ⊆
sc2 ->
n ∈
sc2.
Proof.
unfold incl; intros; eauto.
Qed.
Section properties.
Variable f:
function.
Variable fsc:
Scope.family f.
Notation header := (
Scope.header fsc).
Notation scope := (
Scope.scope fsc).
Notation parent := (
Scope.parent fsc).
Notation elements := (
Scope.elements fsc).
Lemma contains_header:
forall sc,
In sc elements ->
header sc ∈
sc.
Proof.
Lemma in_scope_header_in_scope:
forall n sc,
In sc elements ->
f_In n f ->
(
header (
scope n)) ∈
sc ->
n ∈
sc.
Proof.
Lemma enter_in_scope_at_header_only1:
forall n n'
sc,
succ_node f n n' ->
In sc elements ->
~
n ∈
sc ->
n' ∈
sc ->
n' =
header sc.
Proof.
Lemma in_scope_get_scope_trans:
forall n n'
sc,
In sc elements ->
n ∈ (
scope n') ->
n' ∈
sc ->
n ∈
sc.
Proof.
Lemma in_exited_trans:
forall n n'
n'',
f_In n f ->
n' ∈ (
scope n) ->
~
n'' ∈ (
scope n) ->
In n (
exited_scopes fsc n'
n'').
Proof.
End properties.