Module PostpassScheduling


Implementation (and basic properties) of the verified postpass scheduler


Require Import Coqlib Errors AST Integers.
Require Import Asmblock Axioms Memory Globalenvs.
Require Import Asmblockdeps Asmblockprops.
Require Import IterList.
Require Compopts.

Local Open Scope error_monad_scope.

Oracle taking as input a basic block, returns a scheduled basic block

Axiom schedule: bblock -> (list basic) * option control.

Axiom peephole_opt: bblock -> list basic.

Extract Constant schedule => "PostpassSchedulingOracle.schedule".

Extract Constant peephole_opt => "PeepholeOracle.peephole_opt".

Section verify_schedule.

Definition verify_schedule (bb bb' : bblock) : res unit :=
  match bblock_simub bb bb' with
  | true => OK tt
  | false => Error (msg "PostpassScheduling.verify_schedule")
  end.

Definition verify_size bb bb' := if (Z.eqb (size bb) (size bb')) then OK tt else Error (msg "PostpassScheduling:verify_size: wrong size").

Lemma verify_size_size:
  forall bb bb', verify_size bb bb' = OK tt -> size bb = size bb'.
Proof.
  intros. unfold verify_size in H. destruct (size bb =? size bb') eqn:SIZE; try discriminate.
  apply Z.eqb_eq. assumption.
Qed.

Program Definition make_bblock_from_basics lb :=
  match lb with
  | nil => Error (msg "PostpassScheduling.make_bblock_from_basics")
  | b :: lb => OK {| header := nil; body := b::lb; exit := None |}
  end.

Program Definition schedule_to_bblock (lb: list basic) (oc: option control) : res bblock :=
  match oc with
  | None => make_bblock_from_basics lb
  | Some c => OK {| header := nil; body := lb; exit := Some c |}
  end.
Next Obligation.
  unfold Is_true, non_empty_bblockb.
  unfold non_empty_exit. rewrite orb_true_r. reflexivity.
Qed.

Definition do_schedule (bb: bblock) : res bblock :=
  if (Z.eqb (size bb) 1) then OK (bb)
  else match (schedule bb) with (lb, oc) => schedule_to_bblock lb oc end.

Program Definition do_peephole (bb : bblock) :=
  let optimized := peephole_opt bb in
  let wf_ok := non_empty_bblockb optimized (exit bb) in
  {| header := header bb;
     body := if wf_ok then optimized else (body bb);
     exit := exit bb |}.
Next Obligation.
  destruct (non_empty_bblockb (peephole_opt bb)) eqn:Rwf.
  - rewrite Rwf. cbn. trivial.
  - exact (correct bb).
Qed.

Definition verified_schedule (bb : bblock) : res bblock :=
  let nhbb := no_header bb in
  let phbb := do_peephole nhbb in
  do schbb <- do_schedule phbb;
  let bb' := stick_header (header bb) schbb in
  do sizecheck <- verify_size bb bb';
  do schedcheck <- verify_schedule bb bb';
  OK (bb').

Lemma verified_schedule_size:
  forall bb bb', verified_schedule bb = OK bb' -> size bb = size bb'.
Proof.
  intros. unfold verified_schedule in H.
  monadInv H.
  unfold verify_size in EQ1.
  destruct (size _ =? size _) eqn:ESIZE_H in EQ1; try discriminate.
  rewrite Z.eqb_eq in ESIZE_H; rewrite ESIZE_H; reflexivity.
Qed.

Theorem verified_schedule_correct:
  forall ge f bb bb',
  verified_schedule bb = OK bb' ->
  bblock_simu ge f bb bb'.
Proof.
  intros.
  monadInv H.
  eapply bblock_simub_correct.
  unfold verify_schedule in EQ0.
  destruct (bblock_simub _ _) in *; try discriminate; auto.
Qed.

End verify_schedule.

Fixpoint transf_blocks (lbb : list bblock) : res (list bblock) :=
  match lbb with
  | nil => OK nil
  | bb :: lbb =>
      do tlbb <- transf_blocks lbb;
      do tbb <- verified_schedule bb;
      OK (tbb :: tlbb)
  end.

Definition transl_function (f: function) : res function :=
  do lb <- transf_blocks (fn_blocks f);
  OK (mkfunction (fn_sig f) lb).

Definition transf_function (f: function) : res function :=
  do tf <- transl_function f;
  if zlt Ptrofs.max_unsigned (size_blocks tf.(fn_blocks))
  then Error (msg "code size exceeded")
  else OK tf.

Definition transf_fundef (f: fundef) : res fundef :=
  transf_partial_fundef transf_function f.

Definition transf_program (p: program) : res program :=
  transform_partial_program transf_fundef p.