Module LightLive

Liveness analysis over RTL.

Require Import Coqlib.
Require Import Errors.
Require Import Maps.
Require Import Lattice.
Require Import AST.
Require Import Integers.
Require Import Values.
Require Import Globalenvs.
Require Import Op.
Require Import Registers.
Require Import RTL.
Require Import Kildall.
Require Import Locations.
Require Import Conventions.
Require Import DLib.



Notation reg_live := Regset.add.
Notation reg_dead := Regset.remove.

Definition reg_option_live (or: option reg) (lv: Regset.t) :=
  match or with None => lv | Some r => reg_live r lv end.

Definition reg_sum_live (ros: reg + ident) (lv: Regset.t) :=
  match ros with inl r => reg_live r lv | inr s => lv end.

Fixpoint reg_list_live
             (rl: list reg) (lv: Regset.t) {struct rl} : Regset.t :=
  match rl with
  | nil => lv
  | r1 :: rs => reg_list_live rs (reg_live r1 lv)
  end.

Fixpoint reg_list_dead
             (rl: list reg) (lv: Regset.t) {struct rl} : Regset.t :=
  match rl with
  | nil => lv
  | r1 :: rs => reg_list_dead rs (reg_dead r1 lv)
  end.

Definition transfer
            (f: RTL.function) (pc: node) (after: Regset.t) : Regset.t :=
  match f.(fn_code)!pc with
  | None =>
      Regset.empty
  | Some i =>
      match i with
      | Inop s =>
          after
      | Iop op args res s =>
          reg_list_live args (reg_dead res after)
      | Iload chunk addr args dst s =>
          reg_list_live args (reg_dead dst after)
      | Istore chunk addr args src s =>
          reg_list_live args (reg_live src after)
      | Icall sig ros args res s =>
          reg_list_live args
           (reg_sum_live ros (reg_dead res after))
      | Itailcall sig ros args =>
          reg_list_live args (reg_sum_live ros Regset.empty)
      | Ibuiltin ef args res s =>
          reg_list_live args (reg_dead res after)
      | Icond cond args ifso ifnot =>
          reg_list_live args after
      | Ijumptable arg tbl =>
          reg_live arg after
      | Ireturn optarg =>
          reg_option_live optarg Regset.empty
      end
  end.

The liveness analysis is then obtained by instantiating the general framework for backward dataflow analysis provided by module Kildall.

Module RegsetLat := LFSet(Regset).
Module DS := Backward_Dataflow_Solver(RegsetLat)(NodeSetBackward).

Definition analyze (f: RTL.function): option (PMap.t Regset.t) :=
  DS.fixpoint (successors f) (transfer f) nil.

Well-formedness condition for a liveness analysis


Section WF_LIVE.

  Variable f: RTL.function.
  
  Definition Lin := (fun pc live_out => (transfer f pc (live_out pc))).
  
  Definition Lout {A: Type} := (fun (live: PMap.t A) pc => live # pc).


Auxiliary lemmas about analyze

  Lemma reg_list_live_incl : forall x l s,
    Regset.In x s ->
    Regset.In x (reg_list_live l s).
Proof.
    induction l ; intros ; simpl ; auto.
    eapply IHl ; eauto.
    eapply Regset.add_2 ; eauto.
  Qed.
  
  Lemma reg_list_live_incl_2 : forall x l s,
    In x l ->
    Regset.In x (reg_list_live l s).
Proof.
    induction l ; intros ; inv H.
    simpl.
    eapply reg_list_live_incl ; eauto.
    eapply Regset.add_1 ; eauto.
    eapply IHl ; eauto.
  Qed.

  Lemma reg_list_live_cases : forall x l s,
    Regset.In x (reg_list_live l s) ->
    (Regset.In x s) \/ In x l.
Proof.
    induction l ; intros ; simpl ; auto.
    exploit IHl ; eauto.
    intros [Hcase1 | Hcase2].
    destruct (peq a x).
    inv e; auto.
    left.
    eapply Regset.add_3 ; eauto.
    auto.
  Qed.
    
  Inductive def (pc:node) : reg -> Prop :=
  | AIop: forall op args dst succ,
    (fn_code f)!pc = Some (Iop op args dst succ) ->
    def pc dst
  | AIload: forall chunk addr args dst succ,
    (fn_code f)!pc = Some (Iload chunk addr args dst succ) ->
    def pc dst
  | AIcall: forall sig fn args dst succ,
    (fn_code f)!pc = Some (Icall sig fn args dst succ) ->
    def pc dst
  | AIbuiltin: forall fn args dst succ,
    (fn_code f)!pc = Some (Ibuiltin fn args dst succ) ->
    def pc dst.

  Inductive use (pc:node): reg -> Prop :=
  | UIop: forall arg op args dst s,
    (fn_code f) !pc = Some (Iop op args dst s) -> In arg args -> use pc arg
  | UIload: forall arg chk adr args dst s,
    (fn_code f) !pc = Some (Iload chk adr args dst s) -> In arg args -> use pc arg
  | UIcond: forall arg cond args s s',
    (fn_code f) !pc = Some (Icond cond args s s') -> In arg args -> use pc arg
  | UIbuiltin: forall arg ef args dst s,
    (fn_code f) !pc = Some (Ibuiltin ef args dst s) -> In arg args -> use pc arg
  | UIstore1: forall arg chk adr args src s,
    (fn_code f) !pc = Some (Istore chk adr args src s) -> In arg args -> use pc arg
  | UIstore2: forall chk adr args src s,
    (fn_code f) !pc = Some (Istore chk adr args src s) -> use pc src
  | UIcall: forall arg sig r args dst s,
    (fn_code f) !pc = Some (Icall sig (inl ident r) args dst s) -> In arg (r::args) -> use pc arg
  | UItailcall: forall arg sig r args,
    (fn_code f) !pc = Some (Itailcall sig (inl ident r) args) -> In arg (r::args) -> use pc arg
  | UIcall2: forall arg sig id args dst s,
    (fn_code f) !pc = Some (Icall sig (inr reg id) args dst s) -> In arg args -> use pc arg
  | UItailcall2: forall arg sig id args,
    (fn_code f) !pc = Some (Itailcall sig (inr reg id) args) -> In arg args -> use pc arg
  | UIjump: forall arg tbl,
    (fn_code f) !pc = Some (Ijumptable arg tbl) -> use pc arg
  | UIret: forall arg,
    (fn_code f) !pc = Some (Ireturn (Some arg)) -> use pc arg.

  Inductive Live (pc:node) (v:reg) : Prop :=
    | Live_Inop : forall pc',
      (fn_code f) ! pc = Some (Inop pc') ->
      Live pc' v -> Live pc v
    | Live_Iop : forall op args res pc',
      (fn_code f) ! pc = Some (Iop op args res pc') ->
      Live pc' v -> v<> res -> Live pc v
    | Live_Iload : forall chunk addr args dst pc',
      (fn_code f) ! pc = Some (Iload chunk addr args dst pc') ->
      Live pc' v -> v<> dst -> Live pc v
    | Live_Icond1 : forall cond args ifso ifnot,
      (fn_code f) ! pc = Some (Icond cond args ifso ifnot) ->
      Live ifso v -> Live pc v
    | Live_Icond2 : forall cond args ifso ifnot,
      (fn_code f) ! pc = Some (Icond cond args ifso ifnot) ->
      Live ifnot v -> Live pc v
    | Live_Ibuiltin : forall ef args res pc',
      (fn_code f) ! pc = Some (Ibuiltin ef args res pc') ->
      Live pc' v -> v<> res -> Live pc v
    | Live_Ijumptable : forall arg tbl pc',
      (fn_code f) ! pc = Some (Ijumptable arg tbl) ->
      In pc' tbl ->
      Live pc' v -> Live pc v
    | Live_use : use pc v -> Live pc v.

  Lemma build_live_correct: forall live,
    analyze f = Some live ->
    forall n v,
      Live n v -> Regset.In v (Lin n (Lout live)).
Proof.
    induction 2;
    try assert (In pc' (successors f) !!! pc) by
       (unfold successors, successors_list;
        rewrite PTree.gmap1;
        rewrite H0; simpl; auto).
    > exploit DS.fixpoint_solution; eauto; intro FIX.
      unfold Lout, Lin in * ; unfold transfer.
      rewrite H0; auto.
    > exploit DS.fixpoint_solution; eauto; intro FIX.
      unfold Lout, Lin in * ; unfold transfer.
      rewrite H0; auto.
      eapply reg_list_live_incl ; eauto.
      eapply Regset.remove_2 ; eauto.
    > exploit DS.fixpoint_solution; eauto; intro FIX.
      unfold Lout, Lin in * ; unfold transfer.
      rewrite H0; auto.
      eapply reg_list_live_incl ; eauto.
      eapply Regset.remove_2 ; eauto.
    > assert (In ifso (successors f) !!! pc).
        unfold successors, successors_list.
        rewrite PTree.gmap1.
        rewrite H0; simpl; auto.
      exploit DS.fixpoint_solution; eauto; intro FIX.
      unfold Lout, Lin in * ; unfold transfer.
      rewrite H0; auto.
      eapply reg_list_live_incl ; eauto.
    > assert (In ifnot (successors f) !!! pc).
        unfold successors, successors_list.
        rewrite PTree.gmap1.
        rewrite H0; simpl; auto.
      exploit DS.fixpoint_solution; eauto; intro FIX.
      unfold Lout, Lin in * ; unfold transfer.
      rewrite H0; auto.
      eapply reg_list_live_incl ; eauto.
    > exploit DS.fixpoint_solution; eauto; intro FIX.
      unfold Lout, Lin in * ; unfold transfer.
      rewrite H0; auto.
      eapply reg_list_live_incl ; eauto.
      eapply Regset.remove_2 ; eauto.
    > assert (In pc' (successors f) !!! pc).
        unfold successors, successors_list.
        rewrite PTree.gmap1.
        rewrite H0; simpl; auto.
      exploit DS.fixpoint_solution; eauto; intro FIX.
      unfold Lout, Lin in * ; unfold transfer.
      rewrite H0; auto.
      eapply Regset.add_2 ; eauto.
    > inv H0;
      unfold Lout, Lin in * ; unfold transfer;
      rewrite H1; auto.
      > apply reg_list_live_incl_2; auto.
      > apply reg_list_live_incl_2; auto.
      > apply reg_list_live_incl_2; auto.
      > apply reg_list_live_incl_2; auto.
      > apply reg_list_live_incl_2; auto.
      > apply reg_list_live_incl; auto.
        eapply Regset.add_1 ; eauto.
      > simpl in H2; destruct H2.
        > subst; apply reg_list_live_incl; auto.
          eapply Regset.add_1 ; eauto.
        > apply reg_list_live_incl_2; auto.
      > simpl in H2; destruct H2.
        > subst; apply reg_list_live_incl; auto.
          eapply Regset.add_1 ; eauto.
        > apply reg_list_live_incl_2; auto.
      > apply reg_list_live_incl_2; auto.
      > apply reg_list_live_incl_2; auto.
      > eapply Regset.add_1 ; eauto.
      > eapply Regset.add_1 ; eauto.
  Qed.

End WF_LIVE.