Module QuasiAbstractMachine

Require Import List.
Require Import Omega.
Require Import Utils.
Require Import Lattices.
Require Import Instr.
Require Import Semantics.
Require Import AbstractCommon.
Require Import Rules.

Require Vector.

Quasi-Abstract Machine. Like the abstract machine, but IFC decisions are factored out into a separate rule evaluator.

Set Implicit Arguments.

Definition run_tmr_type (labelCount : OpCode -> nat) (T : Type) :=
  forall (opcode : OpCode)
         (pclab : T)
         (labs : Vector.t T (labelCount opcode)),
    option (T * T).

Count how many argument labels come with this OpCode ?
Definition labelCount (c:OpCode) : nat :=
match c with
| OpNoop => 0
| OpAdd => 2
| OpSub => 2
| OpPush => 0
| OpPop => 0
| OpLoad => 2
| OpStore => 3
| OpJump => 1
| OpBranchNZ => 1
| OpCall => 1
| OpRet => 1
| OpVRet => 2
| OpOutput => 1
end.

Local Open Scope Z_scope.

Rules of the abstract machine


Section QAMachine.
Context {T: Type}.

The run_tmr opcode pclab labs should say if an instruction is allowed to execute on a given combination of PC label (pclab) and argument labels (labs). It should return Some (rpcl, rl) if execution is allowed, where rpcl is the new PC label and rl is a label for a possible result; otherwise, it should return None

Variable run_tmr : run_tmr_type labelCount T.

Step relation
Inductive step_rules : @AS T -> (@Event T)+τ -> @AS T -> Prop :=
| step_nop : forall m i s pcv pcl rpcl rl,
    index_list_Z pcv i = Some Noop ->
    run_tmr OpNoop pcl <||> = Some (rpcl,rl) ->
    step_rules (AState m i s (pcv,pcl)) τ (AState m i s (pcv+1,rpcl))

| step_add: forall m i s pcv pcl rpcl rl x1v x1l x2v x2l,
    index_list_Z pcv i = Some Add ->
    run_tmr OpAdd pcl <|x1l;x2l|> = Some (rpcl,rl) ->
    step_rules (AState m i ((AData (x1v,x1l)::(AData (x2v,x2l))::s)) (pcv,pcl))
               τ
               (AState m i ((AData (x1v+x2v,rl))::s) (pcv+1,rpcl))

| step_sub: forall m i s pcv pcl rpcl rl x1v x1l x2v x2l,
    index_list_Z pcv i = Some Sub ->
    run_tmr OpSub pcl <|x1l;x2l|> = Some (rpcl,rl) ->
    step_rules (AState m i ((AData (x1v,x1l)::(AData (x2v,x2l))::s)) (pcv,pcl))
               τ
               (AState m i ((AData (x1v-x2v,rl))::s) (pcv+1,rpcl))

| step_push: forall m i s pcv pcl rpcl rl cv,
    index_list_Z pcv i = Some (Push cv) ->
    run_tmr OpPush pcl <||> = Some (rpcl,rl) ->
    step_rules (AState m i s (pcv,pcl))
               τ
               (AState m i ((AData (cv,rl))::s) (pcv+1,rpcl))

| step_pop: forall m i s pcv pcl rpcl rl a,
    index_list_Z pcv i = Some Pop ->
    run_tmr OpPop pcl <||> = Some (rpcl,rl) ->
    step_rules (AState m i (AData a :: s) (pcv,pcl))
               τ
               (AState m i s (pcv+1,rpcl))

| step_load: forall m i s pcv pcl addrv addrl xv xl rl rpcl,
    index_list_Z pcv i = Some Load ->
    index_list_Z addrv m = Some (xv,xl) ->
    run_tmr OpLoad pcl <|addrl;xl|> = Some (rpcl,rl) ->
    step_rules (AState m i ((AData (addrv,addrl))::s) (pcv,pcl))
               τ
               (AState m i ((AData (xv, rl))::s) (pcv+1,rpcl))

| step_store: forall m i s pcv pcl addrv addrl xv xl mv ml rl rpcl m',
    index_list_Z pcv i = Some Store ->
    index_list_Z addrv m = Some (mv,ml) ->
    update_list_Z addrv (xv, rl) m = Some m' ->
    run_tmr OpStore pcl <|addrl;xl;ml|> = Some (rpcl,rl) ->
    step_rules (AState m i ((AData (addrv,addrl))::(AData (xv,xl))::s) (pcv,pcl))
               τ
               (AState m' i s (pcv+1,rpcl))

| step_jump: forall m i s pcv pcl pcv' pcl' rl rpcl,
    index_list_Z pcv i = Some Jump ->
    run_tmr OpJump pcl <|pcl'|> = Some (rpcl,rl) ->
    step_rules (AState m i ((AData (pcv',pcl'))::s) (pcv,pcl))
               τ
               (AState m i s (pcv',rpcl))
               
| step_branchnz_true: forall m i s pcv pcl offv al rl rpcl,
    index_list_Z pcv i = Some (BranchNZ offv) ->
    run_tmr OpBranchNZ pcl <|al|> = Some (rpcl,rl) ->
    step_rules (AState m i ((AData (0,al))::s) (pcv,pcl))
               τ
               (AState m i s (pcv+1,rpcl))

| step_branchnz_false: forall m i s pcv pcl offv av al rl rpcl,
    index_list_Z pcv i = Some (BranchNZ offv) ->
    run_tmr OpBranchNZ pcl <|al|> = Some (rpcl,rl) ->
    av <> 0 ->
    step_rules (AState m i ((AData (av,al))::s) (pcv,pcl))
               τ
               (AState m i s (pcv+offv,rpcl))

| step_call: forall m i s pcv pcl pcv' pcl' rl rpcl args a r,
    index_list_Z pcv i = Some (Call a r) ->
    run_tmr OpCall pcl <|pcl'|> = Some (rpcl,rl) ->
    length args = a ->
    (forall a, In a args -> exists d, a = AData d) ->
    step_rules (AState m i ((AData (pcv',pcl'))::args++s) (pcv,pcl))
               τ
               (AState m i (args++(ARet (pcv+1,rl) r)::s) (pcv',rpcl))

| step_ret: forall m i s pcv pcl pcv' pcl' rl rpcl s' ,
    index_list_Z pcv i = Some Ret ->
    pop_to_return s ((ARet (pcv',pcl') false)::s') ->
    run_tmr OpRet pcl <|pcl'|> = Some (rpcl,rl) ->
    step_rules (AState m i s (pcv,pcl)) τ (AState m i s' (pcv',rpcl))

| step_vret: forall m i s pcv pcl pcv' pcl' rl rpcl resv resl s' ,
    index_list_Z pcv i = Some VRet ->
    pop_to_return s ((ARet (pcv',pcl') true)::s') ->
    run_tmr OpVRet pcl <|resl;pcl'|> = Some (rpcl,rl) ->
    step_rules (AState m i (AData (resv,resl)::s) (pcv,pcl))
               τ (AState m i (AData (resv, rl)::s') (pcv',rpcl))

| step_output: forall m i s pcv pcl rl rpcl xv xl,
    index_list_Z pcv i = Some Output ->
    run_tmr OpOutput pcl <|xl|> = Some (rpcl,rl) ->
    step_rules (AState m i (AData (xv,xl)::s) (pcv,pcl))
               (E (EInt (xv,rl))) (AState m i s (pcv+1,rpcl)).

Definition quasi_abstract_machine :=
  {| state := AS ;
    event := Event ;
    step := step_rules ;
    init_data := list Instr * list (@Atom T) * nat * T;
    init_state := fun id =>
                    let '(p,d,n,def) := id in
                    {| amem := replicate (0%Z, def) n ;
                       aimem := p ;
                       astk := map (fun a => AData a) d;
                       apc := (0%Z, def) |}
  |}.

Lemma step_rules_instr : forall m i s pcv pcl s' e,
  step_rules (AState m i s (pcv,pcl)) e s' ->
  exists instr,
    index_list_Z pcv i = Some instr.
Proof.
  intros.
  inv H ; eauto.
Qed.

End QAMachine.

A version of the previous machine specialized for rules given as symbolic lattice expressions, as defined in Rules.v

Section IFCQuasiAbstractMachine.

Context {T : Type}
        {Latt : JoinSemiLattice T}.

Get the "rule" for a given operation.
Variable fetch_rule : forall opcode : OpCode, AllowModify (labelCount opcode).

Definition ifc_run_tmr (opcode: OpCode) (pclab: T) (vlabs:Vector.t T (labelCount opcode)) : option (T * T) :=
  let r := (fetch_rule opcode) in
  apply_rule r pclab vlabs.

Definition ifc_quasi_abstract_machine :=
  quasi_abstract_machine ifc_run_tmr.

End IFCQuasiAbstractMachine.

An instantiation of the Quasi-abstract machine with a particular symbolic rule table corresponding to the Abstract machine.

Section TINIQuasiAbstractMachine.

Context {T: Type}
        {Latt: JoinSemiLattice T}.

Definition fetch_rule (opcode:OpCode) : (AllowModify (labelCount opcode)) :=
  match opcode with
    | OpNoop => ≪ TRUE , LabPC , __
    | OpAdd => ≪ TRUE, LabPC , JOIN Lab1 Lab2
    | OpSub => ≪ TRUE, LabPC, JOIN Lab1 Lab2
    | OpPush => ≪ TRUE, LabPC , BOT
    | OpPop => ≪ TRUE, LabPC , BOT
    | OpLoad => ≪ TRUE, LabPC, JOIN Lab1 Lab2
    | OpStore => ≪ LE (JOIN Lab1 LabPC) Lab3,
                   LabPC ,
                  JOIN Lab1 (JOIN Lab2 LabPC) ≫
    | OpJump => ≪ TRUE, JOIN Lab1 LabPC , __
    | OpBranchNZ => ≪ TRUE, JOIN Lab1 LabPC , __
    | OpCall => ≪ TRUE , JOIN Lab1 LabPC , LabPC
    | OpRet => ≪ TRUE, Lab1 , __
    | OpVRet => ≪ TRUE, Lab2 , JOIN Lab1 LabPC
    | OpOutput => ≪ TRUE, LabPC , JOIN Lab1 LabPC
    end.

Definition tini_quasi_abstract_machine := ifc_quasi_abstract_machine fetch_rule.

Ltac step_tmr :=
  match goal with
    | [ H: ifc_run_tmr _ _ _ _ = _ |- _ ] => inv H
  end.

Lemma step_rules_non_ret_label_pc: forall m i stk pc l s instr e,
  step tini_quasi_abstract_machine (AState m i stk (pc, l)) e s ->
  index_list_Z pc i = Some instr ->
  instr <> Ret ->
  instr <> VRet ->
  exists (l' : T) (pc' : Z), apc s = (pc', l') /\ l <: l' = true.
Proof.
  intros. simpl in H.
  inv H; try step_tmr ; simpl in *; eauto.

  unfold ifc_run_tmr, apply_rule in H3. simpl in H3.
  unfold Vector.nth_order in H3. simpl in H3.
  set (assert1 := addrl \_/ l <: ml) in *.
  case_eq assert1; intros;
  (unfold assert1 in * );
  (rewrite H in *; simpl in * ) ; allinv.
  eauto.

  congruence.
  congruence.
Qed.


End TINIQuasiAbstractMachine.