'Find post-dominators for each node in CFG.
This implementation is based on paper A Fast Algorithm for Finding Dominators in a Flow Graph by Thomas
Lengauer and Robert E. Tarjan from Stanford University, ACM Transactions on Programming Languages and Systems,
Vol. 1, No. 1, July 1979'

def _pd_construct(self):

    (_normalized_cfg, vertices, parent) = self._pd_normalize_graph()
    bucket = defaultdict(set)
    dom = ([None] * len(vertices))
    self._ancestor = ([None] * (len(vertices) + 1))
    for i in xrange((len(vertices) - 1), 0, (-1)):
        w = vertices[i]
        if (w not in parent):
            continue
        predecessors = _normalized_cfg.predecessors(w)
        for v in predecessors:
            u = self._pd_eval(v)
            if (self._semi[u.index].index < self._semi[w.index].index):
                self._semi[w.index] = self._semi[u.index]
        bucket[vertices[self._semi[w.index].index].index].add(w)
        self._pd_link(parent[w], w)
        for v in bucket[parent[w].index]:
            u = self._pd_eval(v)
            if (self._semi[u.index].index < self._semi[v.index].index):
                dom[v.index] = u
            else:
                dom[v.index] = parent[w]
        bucket[parent[w].index].clear()
    for i in xrange(1, len(vertices)):
        w = vertices[i]
        if (w not in parent):
            continue
        if (dom[w.index].index != vertices[self._semi[w.index].index].index):
            dom[w.index] = dom[dom[w.index].index]
    self._post_dom = networkx.DiGraph()
    for i in xrange(1, len(vertices)):
        if ((dom[i] is not None) and (vertices[i] is not None)):
            self._post_dom.add_edge(dom[i].obj, vertices[i].obj)
    self._pd_post_process()
    self._normalized_cfg = networkx.DiGraph()
    for (src, dst) in _normalized_cfg.edges_iter():
        self._normalized_cfg.add_edge(src.obj, dst.obj)
