# Path: core.py
# def is_expr(e):
#     return isinstance(e, EXPR)
# 
# def is_mem(e):
#     return isinstance(e, MEM)
# 
# 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()
# 
# def set_intersection(*sets):
#     # Python's set.intersection 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.intersection(*sets)
#     return set()
# 
# Path: cfgutils.py
# def foreach_bblock(cfg, func, join_func=lambda a, b: a or b, **kwargs):
#     """Apply basic-block level transformation to each block in CFG.
#     Return cumulative status (OR of each block's status).
#     """
#     res = Ellipsis
#     for addr, info in cfg.iter_sorted_nodes():
#         bblock = info["val"]
#         r = func(bblock, **kwargs)
#         if res is Ellipsis:
#             res = r
#         else:
#             res = join_func(res, r)
#     return res


import logging
import core
                    import progdb
from core import is_expr, is_mem
from utils import set_union, set_intersection
from cfgutils import foreach_bblock
                addr = inst.addr if self.inst_level else bblock.addr
                defs = inst.defs(self.regs_only)
                # Kill any real matching defs in function
                kill |= {x for x in all_defs if x[0] in defs}
                # and also any "undefined" defs from function reach-in
                kill |= {(r, None) for r in defs}
                for d in defs:
                    gen.add((d, addr))
            info[self.node_prop_kill] = kill
            info[self.node_prop_gen] = gen


class LiveVarAnalysis(GenKillAnalysis):
    forward = False
    join_op = staticmethod(set_union)
    prop_prefix = "live"

    def __init__(self, cfg, skip_calls=False, underestimate=False):
        """If skip_calls is True, skip call instructions. This is useful
        to estimate current function's argument registers (using unspecific
        call-conventions driven .uses() for a call instruction may/will make
        all call-conventions arg registers live for function entry)."""
        super().__init__(cfg)
        self.skip_calls = skip_calls
        self.underestimate = underestimate

    def init(self):
        "In and out sets of all nodes is set to empty."
        exits = self.g.exits()
        assert len(exits) == 1

# Path: core.py
# def is_expr(e):
#     return isinstance(e, EXPR)
# 
# def is_mem(e):
#     return isinstance(e, MEM)
# 
# 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()
# 
# def set_intersection(*sets):
#     # Python's set.intersection 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.intersection(*sets)
#     return set()
# 
# Path: cfgutils.py
# def foreach_bblock(cfg, func, join_func=lambda a, b: a or b, **kwargs):
#     """Apply basic-block level transformation to each block in CFG.
#     Return cumulative status (OR of each block's status).
#     """
#     res = Ellipsis
#     for addr, info in cfg.iter_sorted_nodes():
#         bblock = info["val"]
#         r = func(bblock, **kwargs)
#         if res is Ellipsis:
#             res = r
#         else:
#             res = join_func(res, r)
#     return res


# Path: dataflow.py
import logging
import core
                    import progdb
from core import is_expr, is_mem
from utils import set_union, set_intersection
from cfgutils import foreach_bblock

                addr = inst.addr if self.inst_level else bblock.addr
                defs = inst.defs(self.regs_only)
                # Kill any real matching defs in function
                kill |= {x for x in all_defs if x[0] in defs}
                # and also any "undefined" defs from function reach-in
                kill |= {(r, None) for r in defs}
                for d in defs:
                    gen.add((d, addr))
            info[self.node_prop_kill] = kill
            info[self.node_prop_gen] = gen


class LiveVarAnalysis(GenKillAnalysis):
    forward = False
    join_op = staticmethod(set_union)
    prop_prefix = "live"

    def __init__(self, cfg, skip_calls=False, underestimate=False):
        """If skip_calls is True, skip call instructions. This is useful
        to estimate current function's argument registers (using unspecific
        call-conventions driven .uses() for a call instruction may/will make
        all call-conventions arg registers live for function entry)."""
        super().__init__(cfg)
        self.skip_calls = skip_calls
        self.underestimate = underestimate

    def init(self):
        "In and out sets of all nodes is set to empty."
        exits = self.g.exits()
        assert len(exits) == 1

        exit = exits[0]