Module RTLWfFunction

Well-formed RTL function validator.

Require Import Bool.
Require Import Arith.
Require Import List.
Require Import BinPos.

Require Import Coqlib.
Require Import Maps.
Require Import RTL.
Require Import Lattice.
Require Import Kildall.
Require Import Registers.
Require Import Errors.
Require Import Integers.

Require Import UtilBase.
Require Import UtilTacs.
Require Import Utils.
Require Import VarsUseDef.
Require Import RTLReaches.

Open Scope error_monad_scope.




Definition wf_cond_acc (f : function) : bool :=
  forall_ptree (fun p i => forallb (fun s => Pmem s f.(fn_code)) (successors_instr i)) f.(fn_code).

Definition wf_cond_entry (f : function) : bool :=
  forall_ptree (fun p i => forallb (fun s => negb (positive_eq_dec s f.(fn_entrypoint))) (successors_instr i)) f.(fn_code).

Definition wf_entry_acc (f : function) : bool :=
  match RTLReaches.transf_function f with
      | Error _ => false
      | OK (seen, tf) =>
        forall_ptree (fun p i => TheoryList.mem positive_eq_dec p seen) f.(fn_code)
  end.

Definition check_inst_entry (i : instruction) : res reg :=
  match i with
      | Iop op args res s =>
        match op with
          | Op.Ointconst i' =>
            if Int.eq_dec i' Int.zero then
              match args with
                | nil => OK res
                | _ => Error (MSG "inst_entry: args <> nil" :: nil)
              end
            else
              Error (MSG "inst_entry: val <> 0" :: nil)
          | _ => Error (MSG "inst_entry: op <> Ointconst" :: nil)
        end
      | _ => Error (MSG "inst_entry: not Iop" :: nil)
  end.

Definition f_exit (f : function) : res node :=
    let exits := List.filter (fun p_i => match snd p_i with
                                           | Itailcall _ _ _ => true
                                           | Ijumptable _ tbl => match tbl with
                                                                     | nil => true
                                                                     | _ => false
                                                                 end
                                           | Ireturn _ => true
                                           | _ => false
                                         end) (PTree.elements f.(fn_code)) in
    match exits with
      | nil => Error (MSG "f_exit: no exit" :: nil)
      | p_exit_n :: nil => match snd p_exit_n with
                               | Ireturn _ => OK (fst p_exit_n)
                               | _ => Error (MSG "f_exit: no tailcall/empty jumptable allowed" :: nil)
                           end
      | _ => Error (MSG "f_exit: too many exits" :: nil)
    end.

Definition check_valid_rs_function (f: function) : res reg :=
  match (fn_code f) ! (fn_entrypoint f) with
      | None => Error (MSG "check_valid_rs_function: entrypoint not in function" :: nil)
      | Some i =>
        do reg_vint <- check_inst_entry i;
          let vvint := reg_to_var reg_vint in
          if
          forall_ptree
            (fun n i =>
               if positive_eq_dec n f.(fn_entrypoint) then true
               else negb (Regset.mem vvint (def f n))
            ) f.(fn_code)
          then OK reg_vint
          else Error (MSG "check_valid_rs_function: reg_vint defd/used in function" :: nil)
  end.

Definition check_wf (f : function) : res (node * reg) :=
  if wf_cond_acc f && wf_cond_entry f && wf_entry_acc f then
    do exit <- f_exit f;
    do reg_vint <- check_valid_rs_function f;
    OK (exit, reg_vint)
else
  Error (MSG "check_wf: invalid function" :: nil).