Builds the Def-Use and Use-Def (DU/UD) chains of the variables of the
    method.

def build_def_use(graph, lparams):
    """
    Builds the Def-Use and Use-Def (DU/UD) chains of the variables of the
    method.
    """
    analysis = reach_def_analysis(graph, lparams)

    UD = defaultdict(list)
    for node in graph.rpo:
        for i, ins in node.get_loc_with_ins():
            for var in ins.get_used_vars():
                # var not in analysis.def_to_loc: test that the register
                # exists. It is possible that it is not the case, when a
                # variable is of a type which is stored on multiple registers
                # e.g: a 'double' stored in v3 is also present in v4, so a call
                # to foo(v3), will in fact call foo(v3, v4).
                if var not in analysis.def_to_loc:
                    continue
                ldefs = analysis.defs[node]
                prior_def = -1
                for v in ldefs.get(var, set()):
                    if prior_def < v < i:
                        prior_def = v
                if prior_def >= 0:
                    UD[var, i].append(prior_def)
                else:
                    intersect = analysis.def_to_loc[var].intersection(
                        analysis.R[node])
                    UD[var, i].extend(intersect)
    DU = defaultdict(list)
    for var_loc, defs_loc in UD.items():
        var, loc = var_loc
        for def_loc in defs_loc:
            DU[var, def_loc].append(loc)

    return UD, DU