def read(self, varnum: str) -> ANFNode: """Read a variable. If this name has defined given in one of the previous statements, it will be trivially resolved. It is possible that the variable was defined in a previous block (e.g. outside of the loop body or the branch). In this case, it will be resolved only if all predecessor blocks are available. If they are not, we will assume that this variable is given as a function argument (which plays the role of a phi node). Args: varnum: The name of the variable to read. """ if varnum in self.variables: return self.variables[varnum] if self.matured: if len(self.preds) == 1: return self.preds[0].read(varnum) elif not self.preds: return self.parser.read(varnum) # TODO: point to the original definition with About(DebugInherit(name=varnum), 'phi'): phi = Parameter(self.graph) self.graph.parameters.append(phi) self.phi_nodes[phi] = varnum self.write(varnum, phi) if self.matured: self.set_phi_arguments(phi) return phi
def _opt_fancy_resolve(optimizer, node, equiv): ns = equiv[V1] name = equiv[V2] with About(node.debug, 'cosmetic'): lbl = f'{ns.value.label}.{name.value}' ct = Constant(GraphCosmeticPrimitive(lbl)) return ct
def f(): nonlocal exc try: a = NamedDebugInfo() with About(a, 'thing'): NamedDebugInfo() except Exception as e: exc = e
def _opt_fancy_transpose(optimizer, node, equiv): if equiv[V].value == (1, 0): x = equiv[X] ct = Constant(GraphCosmeticPrimitive(f'T', on_edge=True)) with About(node.debug, 'cosmetic'): return Apply([ct, x], node.graph) else: return node
def _opt_fancy_array_map(optimizer, node, equiv): xs = equiv[Xs] v = equiv[V] if v.is_constant_graph(): return node name = short_labeler.label(v) ct = Constant(GraphCosmeticPrimitive(f'[{name}]')) with About(node.debug, 'cosmetic'): return Apply([ct, *xs], node.graph)
def test_info_find(): a = NamedDebugInfo() a.field1 = 1 a.field2 = 2 with About(a, 'thing'): b = NamedDebugInfo() b.field2 = 3 assert a.find('field1') == 1 assert a.find('field2') == 2 assert b.find('field1') == 1 assert b.find('field2') == 3 assert b.find('field3') is None
def test_info_find(): a = NamedDebugInfo() a.field1 = 1 a.field2 = 2 with About(a, "thing"): b = NamedDebugInfo() b.field2 = 3 assert a.find("field1") == 1 assert a.find("field2") == 2 assert b.find("field1") == 1 assert b.find("field2") == 3 assert b.find("field3") is None
def process_If(self, block: 'Block', node: ast.If) -> 'Block': """Process a conditional statement. A conditional statement generates 3 functions: The true branch, the false branch, and the continuation. """ # Process the condition cond = self.process_node(block, node.test) # Create two branches with About(block.graph.debug, 'if_true'): true_block = Block(self) with About(block.graph.debug, 'if_false'): false_block = Block(self) true_block.preds.append(block) false_block.preds.append(block) true_block.mature() false_block.mature() # Create the continuation with About(block.graph.debug, 'if_after'): after_block = Block(self) # Process the first branch true_end = self.process_statements(true_block, node.body) # A return statement in the branch might mean that a continuation has # already been set if not true_end.graph.return_: true_end.jump(after_block) # And the second false_end = self.process_statements(false_block, node.orelse) if not false_end.graph.return_: false_end.jump(after_block) # And stich it together block.cond(cond, true_block, false_block) after_block.mature() return after_block
def process_While(self, block: 'Block', node: ast.While) -> 'Block': """Process a while loop. A while loop will generate 3 functions: The test, the body, and the continuation. """ with About(block.graph.debug, 'while_header'): header_block = Block(self) with About(block.graph.debug, 'while_body'): body_block = Block(self) with About(block.graph.debug, 'while_after'): after_block = Block(self) body_block.preds.append(header_block) after_block.preds.append(header_block) block.jump(header_block) cond = self.process_node(header_block, node.test) body_block.mature() header_block.cond(cond, body_block, after_block) after_body = self.process_statements(body_block, node.body) after_body.jump(header_block) header_block.mature() after_block.mature() return after_block
def _opt_fancy_sum(optimizer, node, equiv): x = equiv[X] shp = equiv[V].value ct = Constant(GraphCosmeticPrimitive(f'sum {"x".join(map(str, shp))}')) with About(node.debug, 'cosmetic'): return Apply([ct, x], node.graph)
def _opt_fancy_array_to_scalar(optimizer, node, equiv): x = equiv[X] ct = Constant(GraphCosmeticPrimitive(f'to_scalar', on_edge=True)) with About(node.debug, 'cosmetic'): return Apply([ct, x], node.graph)
def _opt_fancy_distribute(optimizer, node, equiv): x = equiv[X] v = equiv[V] ct = Constant(GraphCosmeticPrimitive(f'shape→{v.value}', on_edge=True)) with About(node.debug, 'cosmetic'): return Apply([ct, x], node.graph)
def _opt_fancy_unsafe_static_cast(optimizer, node, equiv): x = equiv[X] ct = Constant(GraphCosmeticPrimitive(f'cast', on_edge=True)) with About(node.debug, 'cosmetic'): return Apply([ct, x], node.graph)
def _opt_fancy_make_tuple(optimizer, node, equiv): xs = equiv[Xs] ct = Constant(GraphCosmeticPrimitive('(...)')) with About(node.debug, 'cosmetic'): return Apply([ct, *xs], node.graph)
def _opt_fancy_scalar_to_array(optimizer, node, equiv): x = equiv[X] ct = Constant(GraphCosmeticPrimitive(f"to_array", on_edge=True)) with About(node.debug, "cosmetic"): return Apply([ct, x], node.graph)
def _opt_fancy_tagged(optimizer, node, equiv): x = equiv[X] v = equiv[V] ct = Constant(GraphCosmeticPrimitive(f"@{v.value}", on_edge=True)) with About(node.debug, "cosmetic"): return Apply([ct, x], node.graph)