Module RTLofRTLinjectspec

Require Import Utf8.

Require Import
  Coqlib Registers Maps Ast.

Require Import
  Utils Common Transcode
  INJECT RTLinject RTLofRTLinject.

Section TRCODE.

  Variable bi : backend_info.
  Variable c : RTL.code.
  Inductive tr_stmt : statementnodelist regnodenodeProp :=
  | Tr_assert cond args nd res exit
    : tr_stmt (Sassume cond args) nd res exit nd
  | Tr_freeperm nd res exit
    : tr_stmt Sfreeperm nd res exit nd
  | Tr_requestperm rp ad args nd res exit
    : tr_stmt (Srequestperm rp ad args) nd res exit nd
  | Tr_release nd res exit
    : tr_stmt Srelease nd res exit nd
  | Tr_skip nd res exit
    : tr_stmt Sskip nd res exit nd
  | Tr_op op args dst ns res exit nd
     (OP: ok_op op)
     (NS: c ! ns = Some (RTL.Iop op (List.map xI args) (xI dst) nd))
    : tr_stmt (Sop op args dst) ns res exit nd
  | Tr_load addr args dst b ns res exit nd
     (NS: c ! ns = Some (RTL.Iload Mint32 addr (List.map xI args) (xI dst) nd))
    : tr_stmt (Sload b addr args dst) ns res exit nd
  | Tr_store addr args src r b ns res exit nd
     (NS: c ! ns = Some (RTL.Istore Mint32 addr (List.map xI args) (xI src) nd))
    : tr_stmt (Sstore r b addr args src) ns res exit nd
  | Tr_seq s1 s2 ns ni res exit nd
     (S1: tr_stmt s1 ns res exit ni)
     (S2: tr_stmt s2 ni res exit nd)
    : tr_stmt (Sseq s1 s2) ns res exit nd
  | Tr_ifthenelse cnd args strue sfalse ns nt nf res exit nd
     (STRUE: tr_stmt strue nt res exit nd)
     (SFALSE: tr_stmt sfalse nf res exit nd)
     (NS: c ! ns = Some (RTL.Icond cnd (List.map xI args) nt nf))
    : tr_stmt (Sifthenelse cnd args strue sfalse) ns res exit nd
  | Tr_while cnd args sbody ns nb res exit nd
     (BODY: tr_stmt sbody nb res exit ns)
     (NS: c ! ns = Some (RTL.Icond cnd (List.map xI args) nb nd))
    : tr_stmt (Swhile cnd args sbody) ns res exit nd
  | Tr_repeat cnd args sbody ns nb res exit nd
     (BODY: tr_stmt sbody nb res exit ns)
     (NS: c ! ns = Some (RTL.Icond (Op.negate_condition cnd) (List.map xI args) nb nd))
    : tr_stmt (Srepeat sbody cnd args) nb res exit nd
  | Tr_atomic b aop args r ns res exit nd
     (NS: c ! ns = Some (RTL.Iatomic aop (List.map xI args) (xI r) nd))
    : tr_stmt (Satomicmem b aop args r) ns res exit nd
  | Tr_fence ns res exit nd r
     (NS: c ! ns = Some (RTL.Ifence nd))
    : tr_stmt (Sfence r) ns res exit nd
  | Tr_abort af msg ns ni res exit nd r
     (NS: c ! ns = Some (RTL.Iop (Op.Ointconst (bi_translate_abort_msg bi msg)) nil xH ni))
     (ABORT: c ! ni = Some (RTL.Icall abort_sig (inr reg (bi_abort bi)) (xH :: nil) xH nd))
    : tr_stmt (Sabort af r msg) ns res exit nd
  | Tr_return_nil exit nd
    : tr_stmt (Sreturn nil) exit nil exit nd
  | Tr_return_cons s srcl t tgtl ni ns nd exit
      (NS: c ! ns = Some (RTL.Iop Op.Omove (xI s :: nil) t exit))
      (RET: tr_stmt (Sreturn srcl) ni tgtl ns nd)
    : tr_stmt (Sreturn (s::srcl)) ni (t::tgtl) exit nd
  | Tr_leak_off l r o res exit nd
      (LEAK: ¬ bi.(bi_show_leak))
    : tr_stmt (Leak l r o) nd res exit nd
  | Tr_leak_on l r o ns ni res exit nd
      (LEAK: bi.(bi_show_leak))
      (NS: c ! ns = Some (RTL.Iop (Op.Ointconst (bi.(bi_translate_leak) l)) nil (xI o) ni))
      (NS': c ! ni = Some (RTL.Icall leak_sig (inr _ bi.(bi_leak)) (xI o::xI r::nil) (xI o) nd))
    : tr_stmt (Leak l r o) ns res exit nd
  .

  Inductive tr_init : nodelist reglist regnodeProp :=
  | TrInit_nil n : tr_init n nil nil n
  | TrInit_cons a args p param ns ni nd
    (INIT: tr_init ni args param nd)
    (NS: c ! ns = Some (RTL.Iop Op.Omove (xO a::nil) (xI p) ni))
    : tr_init ns (a::args) (p::param) nd
  .

  Variable pc : node.
  Inductive tr_instr : instructionProp :=
  | Tr_inop succ
      (PC: c ! pc = Some (RTL.Inop succ))
    : tr_instr (Inop succ)
  | Tr_iop op args dst succ
      (OKOP: ok_op op)
      (PC: c ! pc = Some (RTL.Iop op (List.map xO args) (xO dst) succ))
    : tr_instr (Iop op args dst succ)
  | Tr_icall sg func args dst succ func'
      (FUNC: func' = match func with inl f => inl _ (xO f) | inr f => inr _ f end)
      (PC: c ! pc = Some (RTL.Icall sg func' (List.map xO args) (xO dst) succ))
    : tr_instr (Icall sg func args dst succ)
  | Tr_ithreadcreate fp arg succ
      (PC: c ! pc = Some (RTL.Ithreadcreate (xO fp) (xO arg) succ))
    : tr_instr (Ithreadcreate fp arg succ)
  | Tr_icond cond args if_so if_not
      (PC: c ! pc = Some (RTL.Icond cond (List.map xO args) if_so if_not))
    : tr_instr (Icond cond args if_so if_not)
  | Tr_ireturn tgt
      (PC: c ! pc = Some (RTL.Ireturn (Some (xO tgt))))
    : tr_instr (Ireturn tgt)
  | Tr_iinject ic args dst succ np nd
      (STMT: tr_stmt ic.(ic_stmt_low) nd (List.map xO dst) succ succ)
      (INIT: tr_init np args ic.(ic_params) nd)
      (PC: c ! pc = Some (RTL.Inop np))
    : tr_instr (Iinject ic args dst succ)
  .

End TRCODE.

Section S.

  Variable bi : backend_info.

  Lemma tr_stmt_incr:
    ∀ s1 s2, state_incr s1 s2
    ∀ stmt,
    ∀ res exit nd ns,
    tr_stmt bi s1.(st_code) stmt ns res exit nd
    tr_stmt bi s2.(st_code) stmt ns res exit nd.
Proof.
    intros s1 s2 INCR. pose proof (incr_some s1 s2 INCR).
    induction 1; vauto;
    try (now constructor (eauto));
    try (now econstructor (eauto)).
  Qed.

Ltac bind_inv :=
  match goal with
    | [H: bind ?f ?g ?s1 = OK ?y ?s3 ?i |- _] =>
      destruct (bind_inversion _ _ f g y s1 s3 i H) as
          (? & ? & ? & ? & ?Hbind & ?Hbind' );
      clear H
  end.

  Lemma translate_statement_correct stmt :
    ∀ res exit nd,
    ∀ st ns st' p,
    transl_stmt bi res exit stmt nd st = OK ns st' p
    tr_stmt bi st'.(st_code) stmt ns res exit nd.
Proof.
    Hint Resolve tr_stmt_incr.
    induction stmt; simpl;
    try now inversion 1; vauto; simpl; econstructor; rewrite PTree.gss.
    intros res exit nd st ns st' p H.
    bif2. inv H. eapply Tr_leak_on; eauto. simpl. rewrite PTree.gss. reflexivity.
    simpl. rewrite PTree.gso. rewrite PTree.gss. reflexivity. apply Psucc_discr.
    inv H. apply Tr_leak_off. congruence.
    intros res exit nd st ns st' p H.
    repeat bind_inv.
    bif2. inv H. econstructor; eauto. simpl. now rewrite PTree.gss.
    intros res exit nd st ns st' p H.
    repeat bind_inv.
    exploit IHstmt1. eassumption. intros H1.
    exploit IHstmt2. eassumption. intros H2.
    econstructor (eauto). inv Hbind'0. simpl. now rewrite PTree.gss.
    intros res exit nd st ns st' p H.
    repeat bind_inv. inv Hbind'. inv Hbind.
    destruct (update_instr_inv Hbind1) as (-> & A & B).
    econstructor (eauto). rewrite B. now rewrite PTree.gss.
    intros res exit nd st ns st' p H.
    repeat bind_inv. inv Hbind. inv Hbind'.
    destruct (update_instr_inv Hbind1) as (-> & A & B).
    econstructor (eauto). rewrite B. now rewrite PTree.gss.
    intros res exit nd st ns st' p H.
    bind_inv. econstructor (eauto).
    induction args; intros [|r res] exit nd st ns st' p H.
    inv H; constructor.
    inversion H.
    inversion H.
    simpl in H. destruct (bind_inversion _ _ _ _ _ _ _ _ H) as (i & j & k & l & A & B).
    pose proof (IHargs _ _ nd _ _ _ _ B).
    econstructor (eauto). inv A.
    erewrite incr_some. reflexivity. eassumption.
    simpl. now rewrite PTree.gss.
    intros res exit nd st ns st' p H.
    unfold translate_abort in H. bind_inv. inv Hbind. inv Hbind'.
    simpl in *.
    econstructor. now rewrite PTree.gss. rewrite PTree.gso. now rewrite PTree.gss.
    apply Psucc_discr.
  Qed.

  Lemma tr_init_incr:
    ∀ s1 s2, state_incr s1 s2
    ∀ ns args param nd,
      tr_init s1.(st_code) ns args param nd
      tr_init s2.(st_code) ns args param nd.
Proof.
    intros s1 s2 INCR. pose proof (incr_some s1 s2 INCR).
    induction 1; vauto;
    econstructor (eauto).
  Qed.

  Lemma init_stmt_correct :
    ∀ args param nd,
    ∀ s ns s' p,
      init_stmt args param nd s = OK ns s' p
      tr_init s'.(st_code) ns args param nd.
Proof.
    induction args; intros [|p param] nd s ns s' INCR H.
    inv H. constructor.
    inversion H.
    inversion H.
    inv H. bind_inv.
    econstructor.
    eapply tr_init_incr; eauto.
    inv Hbind'. simpl. now rewrite PTree.gss.
  Qed.

  Lemma translate_instruction_correct {k i s s' p} :
    translate_instruction bi k i s = OK tt s' p
    tr_instr bi s'.(st_code) k i.
Proof.
    induction i; simpl;
    try (now intros H; try bif2; destruct (update_instr_inv H) as (_ & A & B);
         econstructor (eauto); rewrite B; rewrite PTree.gss).
    intros H. repeat bind_inv.
    destruct (update_instr_inv Hbind'0) as (_ & A & B).
    econstructor. 3: now rewrite B; rewrite PTree.gss.
    eapply tr_stmt_incr.
    2: eapply translate_statement_correct; eauto. assumption.
    eapply tr_init_incr; eauto.
    eapply init_stmt_correct; eauto.
  Qed.

  Lemma tr_instr_incr:
    ∀ s1 s2, state_incr s1 s2
    ∀ k i,
      tr_instr bi s1.(st_code) k i
      tr_instr bi s2.(st_code) k i.
Proof.
    intros s1 s2 INCR. pose proof (incr_some s1 s2 INCR).
    induction 1; vauto;
    econstructor (eauto).
    now eapply tr_init_incr; eauto.
  Qed.

  Definition match_code c c' : Prop :=
    ∀ k i, c ! k = Some itr_instr bi c' k i.

  Lemma translate_code_correct :
    ∀ c z,
    match translate_code bi c z with
      | Errors.OK s =>
        match_code c s.(st_code)
      | Errors.Error _ => True
    end.
Proof.
    unfold translate_code.
    intros c z.
    apply PTree_Properties.fold_rec.
    intros m m' [a|a] H H0. intros k i. rewrite <- (H k). intuition. trivial.
    destruct z; trivial. intros k i. rewrite PTree.gempty. inversion 1.
    intros m [a|msg] k v H H0 H1. 2: easy.
    simpl.
    case_eq (translate_instruction bi k v a).
    easy.
    simpl.
    intros () s' s H2 k0 i H3.
    pose proof (translate_instruction_correct H2).
    destruct (peq k0 k). subst. rewrite PTree.gss in H3. congruence.
    rewrite PTree.gso in H3.
    eapply tr_instr_incr; eauto.
    assumption.
  Qed.

End S.