def check_scoping(func, env): for op in func.ops: if op.opcode == 'phi': continue for arg in flatten(op.args): if isinstance(arg, Undef): raise NameError("Variable referenced before assignment")
def _process(self, ty, args=None, result=None, **metadata): if args is None: args = [] assert ty is not None assert isinstance(args, list), args assert not any(arg is None for arg in flatten(args)), args result = Op(op, ty, args, result) if metadata: result.add_metadata(metadata) self._insert_op(result) return result
def op_call(self, op): """ Γ ⊢ f : (α -> β) Γ ⊢ x : α ---------------------------------- Γ ⊢ f(a) : β """ for arg in flatten(op.args): self.G.add_edge(arg, op) self.constraints[op] = 'call' func, args = op.args self.metadata[op] = { 'func': func, 'args': args, 'call': op }
def op_call(self, op): """ Γ ⊢ f : (α -> β) Γ ⊢ x : α ---------------------------------- Γ ⊢ f(a) : β """ for arg in flatten(op.args): self.G.add_edge(arg, op) self.constraints[op] = 'call' func, args = op.args self.metadata[op] = { 'func': func, 'args': args}
def vmap(f, func): """ Apply `f` over all the values in `func`, that is, all Op, Const, FuncArg and GlobalValue. """ from . import GlobalValue, Const, Function for arg in func.args: yield f(arg) for op in func.ops: yield f(op) for arg in flatten(op.args): if isinstance(arg, (GlobalValue, Const, Function)): yield f(arg)
def defuse(func): """ Map definitions to uses, e.g. %0 = add %a %b %1 = mul %0 %b => { '%a': {'%0'}, '%b': {'%0', '%1'}, '%0': {'%1'}} """ defuse = defaultdict(set) # { def : { use } } for block in func.blocks: for op in block: for arg in flatten(op.operands): defuse[arg].add(op.result) return defuse
def build_graph(func): """ Build a constraint network and initial context. This is a generic templates share-able between input types. """ G = networkx.DiGraph() context = initial_context(func) for op in func.ops: G.add_node(op) for arg in flatten(op.args): if isinstance(arg, (ir.Const, ir.GlobalValue, ir.FuncArg)): G.add_node(arg) constraints, metadata = generate_constraints(func, G) return Context(func, context, constraints, G, metadata)
def defuse(func): """ Map definitions to uses, e.g. %0 = add %a %b %1 = mul %0 %b => { Op('%a'): {Op('%0')}, ... } """ defuse = defaultdict(set) # { def : { use } } for block in func.blocks: for op in block: for arg in flatten(op.args): if isinstance(arg, (Op, FuncArg, Block)): defuse[arg].add(op) return defuse
def initial_context(func): """Initialize context with argtypes""" context = { 'return': set(), void: void, bool_: bool_} context['return'] = set() count = 0 for op in func.ops: context[op] = set() if op.opcode == 'alloca': context['alloca%d' % count] = set() count += 1 for arg in flatten(op.args): if (isinstance(arg, ir.Const) and isinstance(arg.const, FunctionWrapper)): context[arg] = set([None]) elif isinstance(arg, ir.Const): context[arg] = set([typeof(arg.const)]) elif isinstance(arg, ir.GlobalValue): raise NotImplementedError("Globals") return context
def initial_context(func): """Initialize context with argtypes""" context = { 'return': set(), 'generator': set(), void: void, bool_: bool_ } context['return'] = set() count = 0 for op in func.ops: context[op] = set() if op.opcode == 'alloca': context['alloca%d' % count] = set() count += 1 for arg in flatten(op.args): if (isinstance(arg, ir.Const) and isinstance(arg.const, FunctionWrapper)): context[arg] = set([None]) elif isinstance(arg, ir.Const): context[arg] = set([typeof(arg.const)]) elif isinstance(arg, ir.Undef): context[arg] = set() elif isinstance(arg, ir.GlobalValue): raise NotImplementedError("Globals") return context
def symbols(self): """Set of symbolic register operands""" return [x for x in flatten(self.args)]