# Path: utils.py
# def set_union(*sets):
#     # Python's set.union is unfortunately not a class method,
#     # but a normal method, [and if used as unbound method],
#     # requires at least one argument (set).
#     if sets:
#         return set.union(*sets)
#     return set()


import logging
import arch
import progdb
import copy
                import progdb
import dataflow
from collections import defaultdict
from core import *
from cfgutils import *
from dce import *
from xform_expr import *
from xform_inst import *
from xform_bblock import *
from utils import set_union

    defs = set()

    def func(inst):
        if inst.op != "call":
            defs.update(inst.defs())

    foreach_inst(cfg, func)
    cfg.props["local_defines"] = defs
    return defs


def collect_reach_exit(cfg):
    all_defs = foreach_bblock(cfg, lambda b: b.defs(True), set_union)
    exit = cfg.exit()
    if "reachdef_out" in cfg.node(exit):
        all_defs2 = set(x[0] for x in cfg.node(exit)["reachdef_out"] if x[1] is not None)
        if "_DEADEND_" not in cfg:
            assert all_defs == all_defs2, "%r vs %r" % (all_defs, all_defs2)
        all_defs = all_defs2
    progdb.update_cfg_prop(cfg, "reach_exit", all_defs)


# Collect registers which may be either defined or not on the exit.
# These registers often represent parasitic arguments (as they
# may be either modified or not, the way to return the original value
# of the reg is take it as a param).
# Requires reachdef on raw CFG (before insert_initial_regs).
def collect_reach_exit_maybe(cfg):
    exit = cfg.exit()

# Path: utils.py
# def set_union(*sets):
#     # Python's set.union is unfortunately not a class method,
#     # but a normal method, [and if used as unbound method],
#     # requires at least one argument (set).
#     if sets:
#         return set.union(*sets)
#     return set()


# Path: xform_cfg.py
import logging
import arch
import progdb
import copy
                import progdb
import dataflow
from collections import defaultdict
from core import *
from cfgutils import *
from dce import *
from xform_expr import *
from xform_inst import *
from xform_bblock import *
from utils import set_union


    defs = set()

    def func(inst):
        if inst.op != "call":
            defs.update(inst.defs())

    foreach_inst(cfg, func)
    cfg.props["local_defines"] = defs
    return defs


def collect_reach_exit(cfg):
    all_defs = foreach_bblock(cfg, lambda b: b.defs(True), set_union)
    exit = cfg.exit()
    if "reachdef_out" in cfg.node(exit):
        all_defs2 = set(x[0] for x in cfg.node(exit)["reachdef_out"] if x[1] is not None)
        if "_DEADEND_" not in cfg:
            assert all_defs == all_defs2, "%r vs %r" % (all_defs, all_defs2)
        all_defs = all_defs2
    progdb.update_cfg_prop(cfg, "reach_exit", all_defs)


# Collect registers which may be either defined or not on the exit.
# These registers often represent parasitic arguments (as they
# may be either modified or not, the way to return the original value
# of the reg is take it as a param).
# Requires reachdef on raw CFG (before insert_initial_regs).
def collect_reach_exit_maybe(cfg):
    exit = cfg.exit()

    vardict = {}