End BACKWARD_DATAFLOW_SOLVER.
(** We construct a generic backward dataflow solver, working over any semi-lattice structure, by applying the forward dataflow solver with the predecessor relation instead of the successor relation. *)
Module Backward_Dataflow_Solver (LAT: SEMILATTICE) (NS: NODE_SET):
BACKWARD_DATAFLOW_SOLVER with Module L := LAT.
Module L := LAT.
Module DS := Dataflow_Solver L NS.
Section Kildall.
Context {A: Type}.
Variable code: PTree.t A.
Variable successors: A -> list positive.
Variable transf: positive -> L.t -> L.t.
(** Finding entry points for the reverse control-flow graph. *)
Section Exit_points.
(** Assuming that the nodes of the CFG [code] are numbered in reverse postorder (cf. pass [Renumber]), an edge from [n] to [s] is a normal edge if [s < n] and a back-edge otherwise. [sequential_node] returns [true] if the given node has at least one normal outgoing edge.  It returns [false] if the given node is an exit node (no outgoing edges) or the final node of a loop body (all outgoing edges are back-edges).  As we prove later, the set of all non-sequential node is an appropriate set of entry points for exploring the reverse CFG. *)
Definition sequential_node (pc: positive) (instr: A): bool :=
existsb (fun s => match code!s with None => false | Some _ => plt s pc end)
(successors instr).
Definition exit_points : NS.t :=
PTree.fold
(fun ep pc instr =>
if sequential_node pc instr
then ep
else NS.add pc ep)
code NS.empty.

Lemma reachable_exit_points:
forall pc i,
code!pc = Some i -> exists x, NS.In x exit_points /\ reachable code successors pc x.