aboutsummaryrefslogtreecommitdiffstats
path: root/src/hls/GibleSubPargenproof.v
diff options
context:
space:
mode:
Diffstat (limited to 'src/hls/GibleSubPargenproof.v')
-rw-r--r--src/hls/GibleSubPargenproof.v379
1 files changed, 379 insertions, 0 deletions
diff --git a/src/hls/GibleSubPargenproof.v b/src/hls/GibleSubPargenproof.v
new file mode 100644
index 0000000..7d90a46
--- /dev/null
+++ b/src/hls/GibleSubPargenproof.v
@@ -0,0 +1,379 @@
+(*
+ * Vericert: Verified high-level synthesis.
+ * Copyright (C) 2023 Yann Herklotz <yann@yannherklotz.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *)
+
+Require Import Coq.micromega.Lia.
+
+Require Import compcert.lib.Maps.
+Require Import compcert.common.Errors.
+Require Import compcert.common.Globalenvs.
+Require compcert.backend.Registers.
+Require Import compcert.common.Linking.
+Require Import compcert.common.Memory.
+Require compcert.common.Globalenvs.
+Require Import compcert.lib.Integers.
+Require Import compcert.common.AST.
+
+Require Import vericert.common.IntegerExtra.
+Require Import vericert.common.Vericertlib.
+Require Import vericert.common.ZExtra.
+Require Import vericert.hls.Gible.
+Require Import vericert.hls.GiblePar.
+Require Import vericert.hls.GibleSubPar.
+Require Import vericert.hls.GibleSubPargen.
+Require Import vericert.hls.Predicate.
+Require Import vericert.common.Errormonad.
+Import ErrorMonad.
+Import ErrorMonadExtra.
+
+Require Import Lia.
+
+ Inductive match_stackframe : GiblePar.stackframe -> GibleSubPar.stackframe -> Prop :=
+ | match_stackframe_init : forall r f tf sp n rs ps
+ (TF: transl_function f = OK tf),
+ match_stackframe (GiblePar.Stackframe r f sp n rs ps)
+ (Stackframe r tf sp n rs ps).
+
+ Variant match_states : GiblePar.state -> GibleSubPar.state -> Prop :=
+ | match_state :
+ forall stk stk' f tf sp pc rs m ps
+ (HSTACK: Forall2 match_stackframe stk stk')
+ (TF: transl_function f = OK tf),
+ match_states (GiblePar.State stk f sp pc rs ps m)
+ (State stk' tf sp pc rs ps m)
+ | match_callstate :
+ forall cs cs' f tf args m
+ (TF: transl_fundef f = OK tf)
+ (STK: Forall2 match_stackframe cs cs'),
+ match_states (GiblePar.Callstate cs f args m) (Callstate cs' tf args m)
+ | match_returnstate :
+ forall cs cs' v m
+ (STK: Forall2 match_stackframe cs cs'),
+ match_states (GiblePar.Returnstate cs v m) (Returnstate cs' v m).
+
+ Definition match_prog (p: GiblePar.program) (tp: GibleSubPar.program) :=
+ Linking.match_program (fun cu f tf => transl_fundef f = Errors.OK tf) eq p tp.
+
+Section CORRECTNESS.
+
+ Context (prog : GiblePar.program).
+ Context (tprog : GibleSubPar.program).
+
+ Let ge : GiblePar.genv := Globalenvs.Genv.globalenv prog.
+ Let tge : GibleSubPar.genv := Globalenvs.Genv.globalenv tprog.
+
+ Context (TRANSL : match_prog prog tprog).
+
+ Lemma symbols_preserved:
+ forall (s: AST.ident), Genv.find_symbol tge s = Genv.find_symbol ge s.
+ Proof using TRANSL. intros. eapply (Genv.find_symbol_match TRANSL). Qed.
+
+ Lemma senv_preserved:
+ Senv.equiv (Genv.to_senv ge) (Genv.to_senv tge).
+ Proof using TRANSL. intros; eapply (Genv.senv_transf_partial TRANSL). Qed.
+ #[local] Hint Resolve senv_preserved : rtlbg.
+
+ Lemma function_ptr_translated:
+ forall b f,
+ Genv.find_funct_ptr ge b = Some f ->
+ exists tf, Genv.find_funct_ptr tge b = Some tf /\ transl_fundef f = OK tf.
+ Proof (Genv.find_funct_ptr_transf_partial TRANSL).
+
+ Lemma sig_transl_function:
+ forall (f: GiblePar.fundef) (tf: GibleSubPar.fundef),
+ transl_fundef f = OK tf ->
+ GibleSubPar.funsig tf = GiblePar.funsig f.
+ Proof using.
+ unfold transl_fundef. unfold transf_partial_fundef.
+ intros. destruct_match. unfold Errors.bind in *. destruct_match; try discriminate.
+ inv H. cbn. unfold transl_function in Heqr; unfold bind in *.
+ repeat (destruct_match; try discriminate). inv Heqr. auto.
+ inv H; auto.
+ Qed.
+
+ Lemma stacksize_equal:
+ forall f f0,
+ transl_function f = OK f0 ->
+ f0.(fn_stacksize) = f.(GiblePar.fn_stacksize).
+ Proof.
+ unfold transl_function, bind; intros. destruct_match; [|discriminate].
+ inv H. auto.
+ Qed.
+
+ Lemma entrypoint_equal:
+ forall f f0,
+ transl_function f = OK f0 ->
+ f0.(fn_entrypoint) = f.(GiblePar.fn_entrypoint).
+ Proof.
+ unfold transl_function, bind; intros. destruct_match; [|discriminate].
+ inv H. auto.
+ Qed.
+
+ Lemma params_equal:
+ forall f f0,
+ transl_function f = OK f0 ->
+ f0.(fn_params) = f.(GiblePar.fn_params).
+ Proof.
+ unfold transl_function, bind; intros. destruct_match; [|discriminate].
+ inv H. auto.
+ Qed.
+
+ Lemma mfold_left_error:
+ forall A B f l m, @mfold_left A B f l (Error m) = Error m.
+ Proof. now induction l. Qed.
+
+ Lemma mfold_left_cons:
+ forall A B f a l x y,
+ @mfold_left A B f (a :: l) x = OK y ->
+ exists x' y', @mfold_left A B f l (OK y') = OK y /\ f x' a = OK y' /\ x = OK x'.
+ Proof.
+ intros.
+ destruct x; [|now rewrite mfold_left_error in H].
+ cbn in H.
+ replace (fold_left (fun (a : mon A) (b : B) => bind (fun a' : A => f a' b) a) l (f a0 a) = OK y) with
+ (mfold_left f l (f a0 a) = OK y) in H by auto.
+ destruct (f a0 a) eqn:?; [|now rewrite mfold_left_error in H].
+ eauto.
+ Qed.
+
+ Lemma step_cf_instr_pc_ind :
+ forall s f sp rs' pr' m' pc pc' cf t state,
+ GiblePar.step_cf_instr ge (GiblePar.State s f sp pc rs' pr' m') cf t state ->
+ GiblePar.step_cf_instr ge (GiblePar.State s f sp pc' rs' pr' m') cf t state.
+ Proof. destruct cf; intros; inv H; econstructor; eauto. Qed.
+
+ Lemma step_list_inter_not_term :
+ forall A step_i sp i cf l i' cf',
+ @step_list_inter A step_i sp (Iterm i cf) l (Iterm i' cf') ->
+ i = i' /\ cf = cf'.
+ Proof. now inversion 1. Qed.
+
+ Lemma step_list_inter_not_exec :
+ forall A step_i sp i cf l i',
+ ~ @step_list_inter A step_i sp (Iterm i cf) l (Iexec i').
+ Proof. now inversion 1. Qed.
+
+ Lemma step_instr_seq_with_exit:
+ forall sp a rs pr m rs' pr' m' pc,
+ ParBB.step_instr_seq ge sp
+ (Iexec {| is_rs := rs; is_ps := pr; is_mem := m |}) a
+ (Iexec {| is_rs := rs'; is_ps := pr'; is_mem := m' |}) ->
+ SubParBB.step_instr_seq tge sp
+ (Iexec {| is_rs := rs; is_ps := pr; is_mem := m |}) (a ++ ((RBexit None (RBgoto pc) :: nil) :: nil))
+ (Iterm {| is_rs := rs'; is_ps := pr'; is_mem := m' |} (RBgoto pc)).
+ Proof.
+ induction a; intros.
+ - cbn in *. inv H. eapply exec_RBterm. repeat econstructor.
+ - cbn in *. inv H. destruct i1. destruct i. econstructor; eauto.
+ Admitted.
+
+ Lemma step_instr_seq_with_exit':
+ forall sp a rs pr m rs' pr' m' pc cf,
+ ParBB.step_instr_seq ge sp
+ (Iexec {| is_rs := rs; is_ps := pr; is_mem := m |}) a
+ (Iterm {| is_rs := rs'; is_ps := pr'; is_mem := m' |} cf) ->
+ SubParBB.step_instr_seq tge sp
+ (Iexec {| is_rs := rs; is_ps := pr; is_mem := m |}) (a ++ ((RBexit None (RBgoto pc) :: nil) :: nil))
+ (Iterm {| is_rs := rs'; is_ps := pr'; is_mem := m' |} cf).
+ Proof.
+ induction a; intros.
+ - cbn in *. inv H.
+ Admitted.
+
+ Lemma transl_spec_not_in':
+ forall bb pc fresh code_start fresh' code_end pc' y,
+ transl_block (fresh, code_start) (pc', bb) = OK (fresh', code_end) ->
+ code_start ! pc = Some y ->
+ code_end ! pc = Some y.
+ Proof.
+ induction bb; unfold transl_block; intros; cbn in *.
+ - inv H; auto.
+ - remember (
+ match code_start ! pc' with
+ | Some _ => Error (msg "GibleSubPargen: Overlapping blocks in translation")
+ | None =>
+ OK (fresh, (Pos.succ fresh, PTree.set pc' (a ++ (RBexit None (RBgoto fresh) :: nil) :: nil) code_start))
+ end) as trans. setoid_rewrite <- Heqtrans in H.
+ replace (fold_left
+ (fun (a : mon (positive * (positive * code))) (b : SubParBB.t) =>
+ bind (fun a' : positive * (positive * code) => transl_block' a' b) a) bb trans) with
+ (mfold_left transl_block' bb trans) in H by auto.
+ destruct trans; [|rewrite mfold_left_error in H; cbn in *; inversion H].
+ repeat (destruct_match; try discriminate; []).
+ inversion Heqtrans as []. rewrite H1 in H.
+ exploit IHbb; eauto.
+ destruct (peq pc pc').
+ + subst. rewrite Heqo in H0. discriminate.
+ + rewrite PTree.gso by auto; auto.
+ Qed.
+
+ Lemma transl_spec_not_in:
+ forall l pc fresh code_start fresh' code_end y,
+ mfold_left transl_block l (OK (fresh, code_start)) = OK (fresh', code_end) ->
+ code_start ! pc = Some y ->
+ code_end ! pc = Some y.
+ Proof.
+ induction l; cbn in *; [inversion 1; auto|].
+ intros * HFOLD HNOT.
+ remember (transl_block (fresh, code_start) a) as tblock.
+ replace (fold_left
+ (fun (a : mon (positive * code)) (b : positive * ParBB.t) =>
+ bind (fun a' : positive * code => transl_block a' b) a) l tblock) with
+ (mfold_left transl_block l tblock) in HFOLD by auto.
+ destruct tblock; [|rewrite mfold_left_error in HFOLD; discriminate].
+ symmetry in Heqtblock. destruct p, a. eapply transl_spec_not_in' in Heqtblock; eauto.
+ Qed.
+
+ Lemma transl_plus_correct:
+ forall f sp bb pc pc' fresh fresh' code code' s rs pr m rs' pr' m' cf t state0 s' tf,
+ ParBB.step (Smallstep.globalenv (GiblePar.semantics prog)) sp (Iexec {| is_rs := rs; is_ps := pr; is_mem := m |})
+ bb (Iterm {| is_rs := rs'; is_ps := pr'; is_mem := m' |} cf) ->
+ GiblePar.step_cf_instr (Smallstep.globalenv (GiblePar.semantics prog)) (GiblePar.State s f sp pc rs' pr' m') cf t
+ state0 ->
+ mfold_left transl_block' bb (OK (pc, (fresh, code))) = OK (pc', (fresh', code')) ->
+ (forall x y, code' ! x = Some y -> (fn_code tf) ! x = Some y) ->
+ match_states (GiblePar.State s f sp pc rs pr m) (State s' tf sp pc rs pr m) ->
+ exists s2' : Smallstep.state (semantics tprog),
+ Smallstep.plus (Smallstep.step (semantics tprog)) (Smallstep.globalenv (semantics tprog)) (State s' tf sp pc rs pr m) t s2' /\
+ match_states state0 s2'.
+ Proof.
+ induction bb; [inversion 1|].
+ intros. exploit mfold_left_cons; eauto.
+ intros (ytemp & (pc_mid & (fresh_mid & code_mid)) & HFOLD & HTRANSL & HOK).
+ inv HOK. inv H.
+ - destruct state'. exploit IHbb. eauto. eapply step_cf_instr_pc_ind; eauto.
+ eauto. eauto. inv H3. econstructor; eauto.
+ intros (s2' & HPLUS & HMATCH).
+ unfold transl_block' in HTRANSL. repeat (destruct_match; try discriminate; []).
+ inv HTRANSL.
+ exploit transl_spec_not_in'. unfold transl_block.
+ rewrite HFOLD. cbn. eauto. rewrite PTree.gss. eauto.
+ intros. eapply H2 in H.
+ econstructor. split.
+ eapply Smallstep.plus_left'. econstructor. eauto. cbn. eapply step_instr_seq_with_exit.
+ eauto. econstructor. eauto. eauto. eauto.
+ - cbn in HTRANSL. repeat (destruct_match; try discriminate). inv HTRANSL.
+ exploit transl_spec_not_in'. unfold transl_block. rewrite HFOLD. cbn. eauto.
+ rewrite PTree.gss. eauto. intros. eapply H2 in H.
+ econstructor. split.
+ + apply Smallstep.plus_one. econstructor; eauto.
+ eapply step_instr_seq_with_exit'; eauto.
+ Admitted.
+
+ Lemma transl_spec':
+ forall l fresh fresh' code_start code_end pc bb,
+ mfold_left transl_block l (OK (fresh, code_start)) = OK (fresh', code_end) ->
+ In (pc, bb) l ->
+ exists (code0 code' : code) (fresh fresh' : positive),
+ transl_block (fresh, code0) (pc, bb) = OK (fresh', code') /\
+ (forall (x : positive) (y : SubParBB.t), code' ! x = Some y -> code_end ! x = Some y).
+ Proof.
+ induction l; [inversion 2|].
+ intros * HFOLD HIN.
+ cbn in *.
+ remember (transl_block (fresh, code_start) a) as HTRANSL.
+ replace (fold_left
+ (fun (a : mon (positive * code)) (b : positive * ParBB.t) =>
+ bind (fun a' : positive * code => transl_block a' b) a) l HTRANSL) with
+ (mfold_left transl_block l HTRANSL) in HFOLD by auto.
+ destruct HTRANSL;
+ [|erewrite mfold_left_error in HFOLD; discriminate].
+ destruct p as [fresh_mid code_mid].
+ symmetry in HeqHTRANSL.
+ inv HIN; eauto.
+ exists code_start, code_mid, fresh, fresh_mid; split; auto.
+ intros. eapply transl_spec_not_in; eauto.
+ Qed.
+
+ Lemma transl_spec:
+ forall f tf pc bb,
+ transl_function f = OK tf ->
+ f.(GiblePar.fn_code) ! pc = Some bb ->
+ exists code code' fresh fresh',
+ transl_block (fresh, code) (pc, bb) = OK (fresh', code')
+ /\ (forall x y, code' ! x = Some y -> tf.(fn_code) ! x = Some y).
+ Proof.
+ unfold transl_function, bind; intros. destruct_match; [|discriminate].
+ inversion_clear H as []. cbn -[transl_block] in *.
+ destruct p.
+ eapply transl_spec'; eauto.
+ now apply PTree.elements_correct.
+ Qed.
+
+ Lemma transl_plus_step:
+ forall (s1 : Smallstep.state (GiblePar.semantics prog)) (t : Events.trace)
+ (s1' : Smallstep.state (GiblePar.semantics prog)),
+ Smallstep.step (GiblePar.semantics prog) (Smallstep.globalenv (GiblePar.semantics prog)) s1 t s1' ->
+ forall s2 : Smallstep.state (semantics tprog),
+ match_states s1 s2 ->
+ exists s2' : Smallstep.state (semantics tprog),
+ Smallstep.plus (Smallstep.step (semantics tprog)) (Smallstep.globalenv (semantics tprog)) s2 t s2' /\
+ match_states s1' s2'.
+ Proof.
+ induction 1.
+ - inversion 1; subst. exploit transl_spec; eauto.
+ intros (code0 & code' & fresh & fresh' & HFOLD & HIN).
+ unfold transl_block in HFOLD.
+ unfold map in HFOLD. repeat (destruct_match; try discriminate). destruct p. destruct p0.
+ inv HFOLD. eapply transl_plus_correct; eauto.
+ - eauto. intros * HMATCH. inv HMATCH. cbn in TF. unfold Errors.bind in TF. destruct_match; [|discriminate].
+ inv TF. econstructor. split.
+ + apply Smallstep.plus_one. econstructor. erewrite stacksize_equal by eauto. eauto.
+ + erewrite params_equal by eauto. erewrite entrypoint_equal by eauto. now econstructor.
+ - cbn in *. intros * HMATCH. inv HMATCH. cbn in *. inv TF.
+ econstructor. split.
+ + apply Smallstep.plus_one. econstructor. eapply Events.external_call_symbols_preserved; eauto.
+ eapply senv_preserved.
+ + now constructor.
+ - cbn in *. intros * HMATCH. inv HMATCH. inv STK. inv H1.
+ econstructor; split.
+ + apply Smallstep.plus_one. econstructor.
+ + now constructor.
+ Qed.
+
+ Lemma transl_initial_states:
+ forall S,
+ GiblePar.initial_state prog S ->
+ exists R, GibleSubPar.initial_state tprog R /\ match_states S R.
+ Proof.
+ induction 1.
+ exploit function_ptr_translated; eauto. intros [tf [A B]].
+ econstructor; split.
+ econstructor. apply (Genv.init_mem_transf_partial TRANSL); eauto.
+ replace (prog_main tprog) with (prog_main prog). rewrite symbols_preserved; eauto.
+ symmetry; eapply match_program_main; eauto.
+ eexact A.
+ rewrite <- H2. apply sig_transl_function; auto.
+ constructor. auto. constructor.
+ Qed.
+
+ Lemma transl_final_states:
+ forall S R r,
+ match_states S R -> GiblePar.final_state S r -> GibleSubPar.final_state R r.
+ Proof. intros. inv H0. inv H. inv STK. constructor. Qed.
+
+ Theorem transl_program_correct:
+ Smallstep.forward_simulation (GiblePar.semantics prog) (semantics tprog).
+ Proof using TRANSL.
+ eapply Smallstep.forward_simulation_plus.
+ - apply senv_preserved.
+ - apply transl_initial_states.
+ - apply transl_final_states.
+ - apply transl_plus_step.
+ Qed.
+
+End CORRECTNESS.