Require Import Coqlib.
Require Import Maps.
Require Import TrMaps2.
Require Import AST.
Require Import Op.
Require Import Registers.
Require Import Utils.
Require Import Integers.
Require Import Floats.
Require Import Classical.
Require Import Lattice.
Require Import Iteration.
Require Import DLib.
Require Import Kildall.
Require Import KildallComp.
Require Import Dom.
Require Import SSA.
Require Import SSAutils.
This file defines a generic program optimization. In our SSA
middle-end, we instantiate this to SCCP and GVN-CSE, but in general,
it could also be instantiated to any intra-procedural, scala
optimization.
The optimization can be "conditional", hence we define the type
m_exec for storing executable flag for CFG edges.
Definition m_exec :=
P2Map.t bool.
Section Opt.
Definition of the optimization
Variable res :
Type.
Variable analysis :
function -> (
res *
m_exec).
Variable transf_instr :
res ->
node ->
instruction ->
instruction.
Definition transf_function (
f :
function) :
SSA.function :=
let (
res,
m_ex) :=
analysis f in
mkfunction
f.(
fn_sig)
f.(
fn_params)
(
fn_stacksize f)
(
PTree.map (
transf_instr res) (
fn_code f))
f.(
fn_phicode)
f.(
fn_max_indice)
f.(
fn_entrypoint)
f.(
fn_ext_params)
f.(
fn_dom)
.
Proof that it preserves the wf_ssa_function predicate
Hypothesis new_code_same_or_Iop :
forall f:
function,
wf_ssa_function f ->
forall pc ins,
(
fn_code f)!
pc =
Some ins ->
transf_instr (
fst (
analysis f))
pc ins =
ins
\/
match ins with
|
Iop _ _ dst pc'
|
Iload _ _ _ dst pc'
|
Icall _ _ _ dst pc'
|
Ibuiltin _ _ (
BR dst)
pc' =>
exists op'
args',
transf_instr (
fst (
analysis f))
pc ins =
Iop op'
args'
dst pc'
/\
forall x,
In x args' ->
exists d :
node,
def f x d /\
sdom f d pc
|
_ =>
False
end.
Lemma fn_params_transf_function :
forall f,
fn_params (
transf_function f) =
fn_params f.
Proof.
Lemma fn_phicode_transf_function :
forall f,
fn_phicode (
transf_function f) =
fn_phicode f.
Proof.
Lemma fn_entrypoint_transf_function :
forall f,
fn_entrypoint (
transf_function f) =
fn_entrypoint f.
Proof.
Lemma fn_code_transf_function :
forall (
f:
function)
pc ins,
(
fn_code f)!
pc =
Some ins ->
exists ins, (
SSA.fn_code (
transf_function f))!
pc =
Some ins.
Proof.
Lemma fn_code_transf_function' :
forall f pc ins,
(
SSA.fn_code (
transf_function f))!
pc =
Some ins ->
exists ins, (
fn_code f)!
pc =
Some ins.
Proof.
Hint Constructors assigned_code_spec.
Lemma assigned_phi_spec_same :
forall (
f:
function)
pc r,
assigned_phi_spec (
f.(
fn_phicode))
pc r <->
assigned_phi_spec ((
transf_function f).(
fn_phicode))
pc r.
Proof.
Definition assigned_code_spec2 (
code :
code) (
pc :
node) (
x:
reg) :
Prop :=
match code!
pc with
|
Some (
Iop _ _ dst succ)
|
Some (
Iload _ _ _ dst succ)
|
Some (
Icall _ _ _ dst succ) =>
dst =
x
|
Some (
Ibuiltin _ _ (
BR dst)
succ) =>
dst =
x
|
_ =>
False
end.
Lemma assigned_code_spec_equiv :
forall code pc r,
assigned_code_spec code pc r <->
assigned_code_spec2 code pc r.
Proof.
Lemma assigned_code_spec_same :
forall (
f:
function) (
Hwf:
wf_ssa_function f)
pc r,
assigned_code_spec (
fn_code f)
pc r <->
assigned_code_spec ((
transf_function f).(
SSA.fn_code))
pc r.
Proof.
Lemma use_code_transf_function:
forall f:
function,
wf_ssa_function f ->
forall x u,
use_code (
transf_function f)
x u ->
use_code f x u \/
exists d,
def f x d /\
sdom f d u.
Proof.
intros f H x u H0.
inv H0;
simpl in H1;
unfold transf_function in *;
case_eq (
analysis f) ;
intros lv es Ha ;
rewrite Ha in * ;
simpl in *;
rewrite PTree.gmap in H1;
destruct ((
fn_code f)!
u)
eqn:
E;
try (
inv H1;
fail);
simpl in H1;
(
destruct (
new_code_same_or_Iop f H u i)
as [
Hi |
Hi];
auto;
[
left;
rewrite Ha in * ;
simpl in * ;
rewrite Hi in H1;
rewrite <-
E in H1;
go
|
idtac]);
destruct i;
try (
elim Hi;
fail);
try (
destruct b ;
try intuition auto) ;
try (
destruct Hi as (
op' &
args' &
Hi1 &
Hi2);
try (
rewrite Ha in * ;
simpl in *) ;
try (
rewrite Ha in * ;
simpl in * ;
congruence);
right;
apply Hi2;
congruence).
Qed.
Lemma new_code:
forall pc ins (
f:
function) (
Hwf:
wf_ssa_function f),
(
fn_code f)!
pc =
Some ins ->
successors_instr ins =
successors_instr (
transf_instr (
fst (
analysis f))
pc ins).
Proof.
intros pc ins f Hwf Hi.
destruct (
new_code_same_or_Iop f Hwf pc ins);
auto.
-
rewrite H;
auto.
-
destruct ins;
try (
elim H;
fail);
try (
destruct b ;
try intuition auto) ;
destruct H as (
op' &
args' &
H1 &
H2);
rewrite H1;
auto.
Qed.
Hint Constructors use_code:
ssa.
Hint Constructors use:
ssa.
Lemma successors_transf_function:
forall (
f:
function) (
Hwf:
wf_ssa_function f)
pc,
(
successors (
transf_function f))!
pc = (
successors f)!
pc.
Proof.
Lemma map1_assoc:
forall (
A B C:
Type) (
f1:
A ->
B) (
f2:
B ->
C) (
m:
PTree.t A),
PTree.map1 (
fun x =>
f2 (
f1 x))
m =
PTree.map1 f2 (
PTree.map1 f1 m).
Proof.
Lemma join_point_transf_function :
forall (
f:
function) (
Hwf:
wf_ssa_function f)
j,
join_point j (
transf_function f) <->
join_point j f.
Proof.
Lemma make_predecessors_transf_function:
forall (
f:
function) (
Hwf:
wf_ssa_function f),
(
Kildall.make_predecessors (
SSA.fn_code (
transf_function f))
successors_instr) =
(
Kildall.make_predecessors (
fn_code f)
successors_instr).
Proof.
Lemma successors_list_transf_function:
forall (
f:
function) (
Hwf:
wf_ssa_function f)
pc,
(
Kildall.successors_list (
successors (
transf_function f))
pc) =
(
Kildall.successors_list (
successors f)
pc).
Proof.
Lemma use_phicode_transf_function:
forall f:
function,
wf_ssa_function f ->
forall x u,
use_phicode (
transf_function f)
x u ->
use_phicode f x u.
Proof.
Lemma use_transf_function:
forall (
f:
function)
x u,
wf_ssa_function f ->
use (
transf_function f)
x u ->
use f x u \/
exists d,
def f x d /\
sdom f d u.
Proof.
Lemma def_transf_function:
forall (
f:
function)
x d,
wf_ssa_function f ->
def (
transf_function f)
x d ->
def f x d.
Proof.
Lemma cfg_transf_function :
forall (
f:
function) (
Hwf:
wf_ssa_function f)
i j,
cfg f i j <->
cfg (
transf_function f)
i j.
Proof.
intros f i j.
split;
intros.
-
inv H.
exploit fn_code_transf_function ;
eauto.
intros [
ins'
Hins'].
intros.
unfold transf_function in *.
case_eq (
analysis f) ;
intros lv es Ha ;
simpl in *.
rewrite Ha in * ;
simpl in *.
econstructor;
simpl;
eauto.
rewrite PTree.gmap in *.
unfold fn_code in *.
unfold option_map in *.
rewrite HCFG_ins in *.
inv Hins'.
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto).
erewrite <-
new_code;
eauto.
-
inv H.
exploit fn_code_transf_function' ;
eauto.
intros [
ins'
Hins'].
unfold transf_function in *;
case_eq (
analysis f) ;
intros lv es Ha ;
rewrite Ha in * ;
simpl in *.
econstructor;
simpl;
eauto.
rewrite PTree.gmap in *.
unfold option_map in *.
rewrite Hins'
in *.
inv HCFG_ins.
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto).
erewrite new_code;
eauto.
Qed.
Lemma reached_transf_function :
forall (
f:
function) (
Hwf:
wf_ssa_function f)
i,
reached f i <->
reached (
transf_function f)
i.
Proof.
Lemma exit_exit :
forall (
f:
function) (
Hwf:
wf_ssa_function f)
pc,
exit f pc <->
exit (
transf_function f)
pc.
Proof.
split.
-
intros.
assert (
Hins:
exists ins, (
fn_code f) !
pc =
Some ins).
{
unfold exit in *.
flatten NOSTEP;
eauto.
inv H;
go.
}
destruct Hins as [
ins0 Hins0].
exploit (
fn_code_transf_function f pc);
eauto.
intros [
ins Hins].
unfold transf_function in *;
unfold exit in *;
rewrite Hins in *.
unfold fn_code in *.
rewrite Hins0 in *.
case_eq (
analysis f) ;
intros lv es Ha ;
rewrite Ha in *;
simpl in *.
rewrite PTree.gmap in *.
unfold option_map in *.
rewrite Hins0 in *.
inv Hins.
exploit new_code_same_or_Iop;
eauto.
flatten;
auto; (
intros [
Heq |
Hcont]; [
idtac |
elim Hcont]);
try intuition;
try (
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto));
try congruence.
-
intros.
assert (
Hins:
exists ins, (
SSA.fn_code (
transf_function f)) !
pc =
Some ins).
{
unfold exit in *.
flatten NOSTEP;
eauto.
inv H;
go.
}
destruct Hins as [
ins0 Hins0].
unfold transf_function in *.
unfold exit in *;
rewrite Hins0 in *.
case_eq (
analysis f) ;
intros lv es Ha ;
rewrite Ha in *;
simpl in *.
unfold fn_code in *.
rewrite PTree.gmap in *.
unfold option_map in *.
flatten Hins0;
intuition;
match goal with
|
id:
analysis ?
ff =
_ |-
_ =>
set (
f:=
ff)
in *
end.
+
destruct (
new_code_same_or_Iop f Hwf pc i);
auto.
*
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto).
rewrite H0 in H1 ;
inv H1;
auto.
*
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto);
destruct i;
try (
elim H1;
fail);
try (
destruct b ;
try intuition auto) ;
destruct H1 as (
op' &
args' &
H2 &
H3);
congruence.
+
destruct (
new_code_same_or_Iop f Hwf pc i);
auto.
*
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto).
rewrite H0 in H ;
inv H;
auto.
*
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto);
destruct i;
try (
elim H;
fail);
try (
destruct b ;
try intuition auto) ;
destruct H as (
op' &
args' &
H2 &
H3);
congruence.
+
destruct (
new_code_same_or_Iop f Hwf pc i);
auto.
*
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto).
rewrite H0 in H1 ;
inv H1;
auto.
*
replace lv with (
fst (
analysis f))
in *
by (
rewrite Ha ;
auto);
destruct i;
try (
elim H1;
fail);
try (
destruct b ;
try intuition auto) ;
destruct H1 as (
op' &
args' &
H2 &
H3);
congruence.
Qed.
Lemma ssa_path_transf_function :
forall (
f:
function) (
Hwf:
wf_ssa_function f)
i p j,
SSApath f i p j <->
SSApath (
transf_function f)
i p j.
Proof.
split.
-
induction 1;
go.
econstructor 2
with s2;
auto.
inv STEP.
+
assert (
cfg (
transf_function f)
pc pc')
by (
rewrite <-
cfg_transf_function;
eauto;
econstructor;
eauto).
inv H0.
econstructor;
eauto.
rewrite <-
reached_transf_function;
auto.
go.
+
assert (
Hins:
exists ins, (
fn_code f) !
pc =
Some ins).
{
unfold exit in *.
flatten NOSTEP;
eauto.
inv H;
go.
}
destruct Hins as [
ins0 Hins0].
exploit (
fn_code_transf_function f pc);
eauto.
intros [
ins Hins].
econstructor;
eauto.
*
eapply reached_transf_function in CFG;
eauto.
*
eapply (
exit_exit f);
eauto.
-
induction 1;
go.
econstructor 2
with s2;
auto.
inv STEP.
+
assert (
cfg f pc pc')
by (
rewrite cfg_transf_function;
eauto;
econstructor;
eauto).
inv H0.
econstructor;
eauto.
go.
+
assert (
Hins:
exists ins, (
SSA.fn_code (
transf_function f)) !
pc =
Some ins).
{
unfold exit in *.
flatten NOSTEP;
eauto.
inv H;
go.
}
destruct Hins as [
ins0 Hins0].
eelim fn_code_transf_function' ;
eauto.
intros ins'
H'.
econstructor;
eauto.
eapply exit_exit;
eauto.
Qed.
Lemma dom_transf_function :
forall (
f:
function) (
Hwf:
wf_ssa_function f)
i j,
dom f i j <->
dom (
transf_function f)
i j.
Proof.
Lemma transf_function_Inop :
forall (
f:
function) (
Hwf:
wf_ssa_function f)
pc jp,
(
fn_code f) !
pc =
Some (
Inop jp) ->
(
SSA.fn_code (
transf_function f)) !
pc =
Some (
Inop jp).
Proof.
Lemma transf_function_preserve_wf_ssa_function :
forall (
f:
function),
wf_ssa_function f ->
wf_ssa_function (
transf_function f).
Proof.
End Opt.