def test_funny_links(): from pypy.objspace.flow.model import Block, FunctionGraph, \ SpaceOperation, Variable, Constant, Link for i in range(2): v_i = Variable("i") v_case = Variable("case") block = Block([v_i]) g = FunctionGraph("is_one", block) block.operations.append( SpaceOperation("eq", [v_i, Constant(1)], v_case)) block.exitswitch = v_case tlink = Link([Constant(1)], g.returnblock, True) flink = Link([Constant(0)], g.returnblock, False) links = [tlink, flink] if i: links.reverse() block.closeblock(*links) t = TranslationContext() a = t.buildannotator() a.build_graph_types(g, [annmodel.SomeInteger()]) rtyper = t.buildrtyper() rtyper.specialize() interp = LLInterpreter(rtyper) assert interp.eval_graph(g, [1]) == 1 assert interp.eval_graph(g, [0]) == 0
def test_optimize_goto_if_not__incoming(): v1 = Variable() v1.concretetype = lltype.Bool block = Block([v1]) block.exitswitch = v1 block.exits = [FakeLink(False), FakeLink(True)] assert not Transformer().optimize_goto_if_not(block)
def dispatcher(self, shape, index, argtypes, resulttype): key = shape, index, tuple(argtypes), resulttype if key in self._dispatch_cache: return self._dispatch_cache[key] from pypy.translator.unsimplify import varoftype from pypy.objspace.flow.model import FunctionGraph, Link, Block, SpaceOperation inputargs = [varoftype(t) for t in [Char] + argtypes] startblock = Block(inputargs) startblock.exitswitch = inputargs[0] graph = FunctionGraph("dispatcher", startblock, varoftype(resulttype)) row_of_graphs = self.callfamily.calltables[shape][index] links = [] descs = list(self.s_pbc.descriptions) if self.s_pbc.can_be_None: descs.insert(0, None) for desc in descs: if desc is None: continue args_v = [varoftype(t) for t in argtypes] b = Block(args_v) llfn = self.rtyper.getcallable(row_of_graphs[desc]) v_fn = inputconst(typeOf(llfn), llfn) v_result = varoftype(resulttype) b.operations.append( SpaceOperation("direct_call", [v_fn] + args_v, v_result)) b.closeblock(Link([v_result], graph.returnblock)) i = self.descriptions.index(desc) links.append(Link(inputargs[1:], b, chr(i))) links[-1].llexitcase = chr(i) startblock.closeblock(*links) self.rtyper.annotator.translator.graphs.append(graph) ll_ret = self.rtyper.type_system.getcallable(graph) #FTYPE = FuncType c_ret = self._dispatch_cache[key] = inputconst(typeOf(ll_ret), ll_ret) return c_ret
def test_regalloc_exitswitch_2(self): v1 = Variable(); v1.concretetype = rclass.CLASSTYPE v2 = Variable(); v2.concretetype = rclass.CLASSTYPE v3 = Variable(); v3.concretetype = rclass.CLASSTYPE v4 = Variable(); v4.concretetype = rclass.CLASSTYPE block = Block([]) block.operations = [ SpaceOperation('res_call', [], v1), SpaceOperation('-live-', [], None), ] graph = FunctionGraph('f', block, v4) exclink = Link([v2], graph.returnblock) exclink.llexitcase = 123 # normally an exception class exclink.last_exception = v2 exclink.last_exc_value = "unused" block.exitswitch = c_last_exception block.closeblock(Link([v1], graph.returnblock), exclink) # self.check_assembler(graph, """ res_call -> %i0 -live- catch_exception L1 int_return %i0 --- L1: goto_if_exception_mismatch $123, L2 last_exception -> %i0 int_return %i0 --- L2: reraise """)
def test_optimize_goto_if_not__unknownop(): v3 = Variable(); v3.concretetype = lltype.Bool block = Block([]) block.operations = [SpaceOperation('foobar', [], v3)] block.exitswitch = v3 block.exits = [FakeLink(False), FakeLink(True)] assert not Transformer().optimize_goto_if_not(block)
def test_optimize_goto_if_not__unknownop(): v3 = Variable() v3.concretetype = lltype.Bool block = Block([]) block.operations = [SpaceOperation('foobar', [], v3)] block.exitswitch = v3 block.exits = [FakeLink(False), FakeLink(True)] assert not Transformer().optimize_goto_if_not(block)
def naive_split_block(self, block, position): newblock = Block([]) newblock.operations = block.operations[position:] del block.operations[position:] newblock.exitswitch = block.exitswitch block.exitswitch = None newblock.recloseblock(*block.exits) block.recloseblock(Link([], newblock)) return newblock
def copy_block(self, block): if block in self._copied_blocks: return self._copied_blocks[block] args = ([self.get_new_name(var) for var in block.inputargs] + self.passon_vars(block)) newblock = Block(args) self._copied_blocks[block] = newblock newblock.operations = [self.copy_operation(op) for op in block.operations] newblock.closeblock(*[self.copy_link(link, block) for link in block.exits]) newblock.exitswitch = self.get_new_name(block.exitswitch) self.search_for_calls(newblock) return newblock
def test_optimize_goto_if_not__ptr_iszero(): for opname in ['ptr_iszero', 'ptr_nonzero']: v1 = Variable() v3 = Variable(); v3.concretetype = lltype.Bool block = Block([v1]) block.operations = [SpaceOperation(opname, [v1], v3)] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] assert block.exitswitch == (opname, v1, '-live-before') assert block.exits == exits
def test_optimize_goto_if_not__ptr_iszero(): for opname in ['ptr_iszero', 'ptr_nonzero']: v1 = Variable() v3 = Variable() v3.concretetype = lltype.Bool block = Block([v1]) block.operations = [SpaceOperation(opname, [v1], v3)] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] assert block.exitswitch == (opname, v1, '-live-before') assert block.exits == exits
def test_optimize_goto_if_not(): v1 = Variable() v2 = Variable() v3 = Variable(); v3.concretetype = lltype.Bool sp1 = SpaceOperation('foobar', [], None) sp2 = SpaceOperation('foobaz', [], None) block = Block([v1, v2]) block.operations = [sp1, SpaceOperation('int_gt', [v1, v2], v3), sp2] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [sp1, sp2] assert block.exitswitch == ('int_gt', v1, v2) assert block.exits == exits
def test_optimize_goto_if_not__ptr_eq(): for opname in ["ptr_eq", "ptr_ne"]: v1 = Variable() v2 = Variable() v3 = Variable() v3.concretetype = lltype.Bool block = Block([v1, v2]) block.operations = [SpaceOperation(opname, [v1, v2], v3)] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] assert block.exitswitch == (opname, v1, v2) assert block.exits == exits
def test_optimize_goto_if_not(): v1 = Variable() v2 = Variable() v3 = Variable() v3.concretetype = lltype.Bool sp1 = SpaceOperation('foobar', [], None) sp2 = SpaceOperation('foobaz', [], None) block = Block([v1, v2]) block.operations = [sp1, SpaceOperation('int_gt', [v1, v2], v3), sp2] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [sp1, sp2] assert block.exitswitch == ('int_gt', v1, v2) assert block.exits == exits
def test_optimize_goto_if_not__exit(): # this case occurs in practice, e.g. with RPython code like: # return bool(p) and p.somefield > 0 v1 = Variable() v2 = Variable() v3 = Variable(); v3.concretetype = lltype.Bool block = Block([v1, v2]) block.operations = [SpaceOperation('int_gt', [v1, v2], v3)] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] block.exits[1].args = [v3] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] assert block.exitswitch == ('int_gt', v1, v2) assert block.exits == exits assert exits[1].args == [const(True)]
def test_switch_no_default(): from pypy.objspace.flow.model import FunctionGraph, Block, Constant, Link from pypy.rpython.lltypesystem.lltype import FuncType, Signed, functionptr from pypy.translator.unsimplify import varoftype block = Block([varoftype(Signed)]) block.exitswitch = block.inputargs[0] graph = FunctionGraph("t", block, varoftype(Signed)) links = [] for i in range(10): links.append(Link([Constant(i*i, Signed)], graph.returnblock, i)) links[-1].llexitcase = i block.closeblock(*links) fptr = functionptr(FuncType([Signed], Signed), "t", graph=graph) def func(x): return fptr(x) f = compile_function(func, [int]) res = f(4) assert res == 16
def test_optimize_goto_if_not__exit(): # this case occurs in practice, e.g. with RPython code like: # return bool(p) and p.somefield > 0 v1 = Variable() v2 = Variable() v3 = Variable() v3.concretetype = lltype.Bool block = Block([v1, v2]) block.operations = [SpaceOperation('int_gt', [v1, v2], v3)] block.exitswitch = v3 block.exits = exits = [FakeLink(False), FakeLink(True)] block.exits[1].args = [v3] res = Transformer().optimize_goto_if_not(block) assert res == True assert block.operations == [] assert block.exitswitch == ('int_gt', v1, v2) assert block.exits == exits assert exits[1].args == [const(True)]
def generic_exception_matching(self, afterblock, copiedexceptblock): #XXXXX don't look: insert blocks that do exception matching #for the cases where direct matching did not work exc_match = Constant( self.translator.rtyper.getexceptiondata().fn_exception_match) exc_match.concretetype = typeOf(exc_match.value) blocks = [] for i, link in enumerate(afterblock.exits[1:]): etype = copyvar(None, copiedexceptblock.inputargs[0]) evalue = copyvar(None, copiedexceptblock.inputargs[1]) passon_vars = self.passon_vars(i) block = Block([etype, evalue] + passon_vars) res = Variable() res.concretetype = Bool cexitcase = Constant(link.llexitcase) cexitcase.concretetype = typeOf(cexitcase.value) args = [exc_match, etype, cexitcase] block.operations.append(SpaceOperation("direct_call", args, res)) block.exitswitch = res linkargs = self.find_args_in_exceptional_case(link, link.target, etype, evalue, afterblock, passon_vars) l = Link(linkargs, link.target) l.prevblock = block l.exitcase = True l.llexitcase = True block.closeblock(l) if i > 0: l = Link(blocks[-1].inputargs, block) l.exitcase = False l.llexitcase = False blocks[-1].recloseblock(l, *blocks[-1].exits) blocks.append(block) blocks[-1].recloseblock(*blocks[-1].exits[:1]) blocks[-1].operations = [] blocks[-1].exitswitch = None blocks[-1].exits[0].exitcase = None del blocks[-1].exits[0].llexitcase linkargs = copiedexceptblock.inputargs copiedexceptblock.recloseblock(Link(linkargs, blocks[0])) copiedexceptblock.operations += self.generate_keepalive(linkargs)
def test_SSA_to_SSI(): c = Variable('c') x = Variable('x') y = Variable('y') b1 = Block([c]) b2 = Block([x]) b3 = Block([]) b2.operations.append(SpaceOperation('add', [x, c], y)) b2.exitswitch = y b1.closeblock(Link([Constant(0)], b2)) b2.closeblock(Link([y], b2), Link([], b3)) b3.closeblock(Link([y, c], None)) SSA_to_SSI({ b1: True, # reachable from outside b2: False, b3: False }) assert len(b1.inputargs) == 1 assert len(b2.inputargs) == 2 assert len(b3.inputargs) == 2 assert b2.inputargs == b2.operations[0].args assert len(b1.exits[0].args) == 2 assert b1.exits[0].args[1] is c assert len(b2.exits[0].args) == 2 assert b2.exits[0].args == [y, b2.inputargs[1]] assert len(b2.exits[1].args) == 2 assert len(b3.exits[0].args) == 2 index = b3.inputargs.index(b3.exits[0].args[0]) assert b2.exits[1].args[index] is b2.operations[0].result index = b3.inputargs.index(b3.exits[0].args[1]) assert b2.exits[1].args[index] is b2.inputargs[1]
def test_regalloc_exitswitch_2(self): v1 = Variable() v1.concretetype = rclass.CLASSTYPE v2 = Variable() v2.concretetype = rclass.CLASSTYPE v3 = Variable() v3.concretetype = rclass.CLASSTYPE v4 = Variable() v4.concretetype = rclass.CLASSTYPE block = Block([]) block.operations = [ SpaceOperation('res_call', [], v1), SpaceOperation('-live-', [], None), ] graph = FunctionGraph('f', block, v4) exclink = Link([v2], graph.returnblock) exclink.llexitcase = 123 # normally an exception class exclink.last_exception = v2 exclink.last_exc_value = "unused" block.exitswitch = c_last_exception block.closeblock(Link([v1], graph.returnblock), exclink) # self.check_assembler( graph, """ res_call -> %i0 -live- catch_exception L1 int_return %i0 --- L1: goto_if_exception_mismatch $123, L2 last_exception -> %i0 int_return %i0 --- L2: reraise """)
def test_SSA_to_SSI(): c = Variable('c') x = Variable('x') y = Variable('y') b1 = Block([c]) b2 = Block([x]) b3 = Block([]) b2.operations.append(SpaceOperation('add', [x, c], y)) b2.exitswitch = y b1.closeblock(Link([Constant(0)], b2)) b2.closeblock(Link([y], b2), Link([], b3)) b3.closeblock(Link([y, c], None)) SSA_to_SSI({b1: True, # reachable from outside b2: False, b3: False}) assert len(b1.inputargs) == 1 assert len(b2.inputargs) == 2 assert len(b3.inputargs) == 2 assert b2.inputargs == b2.operations[0].args assert len(b1.exits[0].args) == 2 assert b1.exits[0].args[1] is c assert len(b2.exits[0].args) == 2 assert b2.exits[0].args == [y, b2.inputargs[1]] assert len(b2.exits[1].args) == 2 assert len(b3.exits[0].args) == 2 index = b3.inputargs.index(b3.exits[0].args[0]) assert b2.exits[1].args[index] is b2.operations[0].result index = b3.inputargs.index(b3.exits[0].args[1]) assert b2.exits[1].args[index] is b2.inputargs[1]
def test_funny_links(): from pypy.objspace.flow.model import Block, FunctionGraph, \ SpaceOperation, Variable, Constant, Link for i in range(2): v_i = Variable("i") v_case = Variable("case") block = Block([v_i]) g = FunctionGraph("is_one", block) block.operations.append(SpaceOperation("eq", [v_i, Constant(1)], v_case)) block.exitswitch = v_case tlink = Link([Constant(1)], g.returnblock, True) flink = Link([Constant(0)], g.returnblock, False) links = [tlink, flink] if i: links.reverse() block.closeblock(*links) t = TranslationContext() a = t.buildannotator() a.build_graph_types(g, [annmodel.SomeInteger()]) rtyper = t.buildrtyper() rtyper.specialize() interp = LLInterpreter(rtyper) assert interp.eval_graph(g, [1]) == 1 assert interp.eval_graph(g, [0]) == 0
def insert_integer_search(self, block, cases, defaultlink, blockset, range_start, range_stop): # fix the exit of the 'block' to check for the given remaining # 'cases', knowing that if we get there then the value must # be contained in range(range_start, range_stop). if not cases: assert defaultlink is not None block.exitswitch = None block.recloseblock(Link(defaultlink.args, defaultlink.target)) elif len(cases) == 1 and (defaultlink is None or range_start == range_stop-1): block.exitswitch = None block.recloseblock(cases.values()[0]) else: intvalues = cases.keys() intvalues.sort() if len(intvalues) <= 3: # not much point in being clever with no more than 3 cases intval = intvalues[-1] remainingcases = cases.copy() link = remainingcases.pop(intval) c_intval = inputconst(lltype.Signed, intval) v = self.genop(block, 'int_eq', [block.exitswitch, c_intval], resulttype=lltype.Bool, red=True) link.exitcase = True link.llexitcase = True falseblock = Block([]) falseblock.exitswitch = block.exitswitch blockset[falseblock] = False falselink = Link([], falseblock) falselink.exitcase = False falselink.llexitcase = False block.exitswitch = v block.recloseblock(falselink, link) if defaultlink is None or intval == range_stop-1: range_stop = intval self.insert_integer_search(falseblock, remainingcases, defaultlink, blockset, range_start, range_stop) else: intval = intvalues[len(intvalues) // 2] c_intval = inputconst(lltype.Signed, intval) v = self.genop(block, 'int_ge', [block.exitswitch, c_intval], resulttype=lltype.Bool, red=True) falseblock = Block([]) falseblock.exitswitch = block.exitswitch trueblock = Block([]) trueblock.exitswitch = block.exitswitch blockset[falseblock] = False blockset[trueblock] = False falselink = Link([], falseblock) falselink.exitcase = False falselink.llexitcase = False truelink = Link([], trueblock) truelink.exitcase = True truelink.llexitcase = True block.exitswitch = v block.recloseblock(falselink, truelink) falsecases = {} truecases = {} for intval1, link1 in cases.items(): if intval1 < intval: falsecases[intval1] = link1 else: truecases[intval1] = link1 self.insert_integer_search(falseblock, falsecases, defaultlink, blockset, range_start, intval) self.insert_integer_search(trueblock, truecases, defaultlink, blockset, intval, range_stop)