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.
(** The crucial property of exit points is that any nonempty node in the CFG is reverse-reachable from an exit point. *)
End Exit_points.
(** The efficient backward solver.  *)
Definition fixpoint :=
DS.fixpoint_nodeset
(make_predecessors code successors) (fun l => l)
transf exit_points.
(** The alternate solver that starts with all nodes of the CFG instead of just the exit points. *)
Definition fixpoint_allnodes :=
DS.fixpoint_allnodes
(make_predecessors code successors) (fun l => l)
transf.

Theorem fixpoint_allnodes_solution:
forall res n instr s,
fixpoint_allnodes = Some res ->
code!n = Some instr -> In s (successors instr) ->
L.ge res!!n (transf s res!!s).