[pypy-svn] r32767 - in pypy/dist/pypy/jit: codegen codegen/llgraph timeshifter timeshifter/test

arigo at codespeak.net arigo at codespeak.net
Sat Sep 30 18:48:11 CEST 2006


Author: arigo
Date: Sat Sep 30 18:48:09 2006
New Revision: 32767

Modified:
   pypy/dist/pypy/jit/codegen/llgraph/rgenop.py
   pypy/dist/pypy/jit/codegen/model.py
   pypy/dist/pypy/jit/timeshifter/rtimeshift.py
   pypy/dist/pypy/jit/timeshifter/rtyper.py
   pypy/dist/pypy/jit/timeshifter/test/test_promotion.py
   pypy/dist/pypy/jit/timeshifter/transform.py
Log:
(pedronis, arigo)

Generate residual indirect calls when the target is not known at
compile-time.  (It's in test_promotion but it's not about promotion so
far.)



Modified: pypy/dist/pypy/jit/codegen/llgraph/rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/llgraph/rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/llgraph/rgenop.py	Sat Sep 30 18:48:09 2006
@@ -70,8 +70,12 @@
             if gv_arg is not None:
                 gv_arg = LLVar(llimpl.cast(self.b, ARGS_gv[i].v, gv_arg.v))
             vars_gv.append(gv_arg)
-        # XXX indirect_call later
-        return LLVar(llimpl.genop(self.b, 'direct_call', vars_gv, gv_RESULT.v))
+        if gv_callable.is_const:
+            v = llimpl.genop(self.b, 'direct_call', vars_gv, gv_RESULT.v)
+        else:
+            vars_gv.append(gv_dummy_placeholder)
+            v = llimpl.genop(self.b, 'indirect_call', vars_gv, gv_RESULT.v)
+        return LLVar(v)
 
     def genop_getfield(self, (gv_name, gv_PTRTYPE, gv_FIELDTYPE), gv_ptr):
         vars_gv = [llimpl.cast(self.b, gv_PTRTYPE.v, gv_ptr.v), gv_name.v]

Modified: pypy/dist/pypy/jit/codegen/model.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/model.py	(original)
+++ pypy/dist/pypy/jit/codegen/model.py	Sat Sep 30 18:48:09 2006
@@ -1,11 +1,15 @@
 from pypy.rpython.objectmodel import specialize
 
 
+class NotConstant(Exception):
+    pass
+
+
 class GenVarOrConst(object):
 
     @specialize.arg(1)
     def revealconst(self, T):
-        raise NotImplementedError
+        raise NotConstant(self)
 
 class GenVar(GenVarOrConst):
     is_const = False

Modified: pypy/dist/pypy/jit/timeshifter/rtimeshift.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtimeshift.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtimeshift.py	Sat Sep 30 18:48:09 2006
@@ -321,6 +321,24 @@
 ##def ll_gvar_from_constant(jitstate, ll_value):
 ##    return jitstate.curbuilder.rgenop.genconst(ll_value)
 
+class CallDesc:
+    __metaclass__ = cachedtype
+
+    def __init__(self, RGenOp, FUNCTYPE):
+        self.sigtoken = RGenOp.sigToken(FUNCTYPE)
+        self.result_kind = RGenOp.kindToken(FUNCTYPE.RESULT)
+        self.redboxbuilder = rvalue.ll_redboxbuilder(FUNCTYPE.RESULT)
+
+    def _freeze_(self):
+        return True
+
+def ll_gen_residual_call(jitstate, calldesc, funcbox):
+    builder = jitstate.curbuilder
+    gv_funcbox = funcbox.getgenvar(builder)
+    argboxes = jitstate.frame.local_boxes
+    args_gv = [argbox.getgenvar(builder) for argbox in argboxes]
+    gv_result = builder.genop_call(calldesc.sigtoken, gv_funcbox, args_gv)
+    return calldesc.redboxbuilder(calldesc.result_kind, gv_result)
 
 
 class ResumingInfo(object):

Modified: pypy/dist/pypy/jit/timeshifter/rtyper.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/rtyper.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/rtyper.py	Sat Sep 30 18:48:09 2006
@@ -911,7 +911,6 @@
         hop.llops.setjitstate(v_newjitstate)
 
     def translate_op_indirect_red_call(self, hop):
-        bk = self.annotator.bookkeeper
         v_jitstate = hop.llops.getjitstate()
         FUNC = originalconcretetype(hop.args_s[0])
         v_func = hop.inputarg(self.getgreenrepr(FUNC), arg=0)
@@ -935,6 +934,25 @@
     translate_op_yellow_call          = translate_op_red_call
     translate_op_indirect_yellow_call = translate_op_indirect_red_call
 
+    def translate_op_residual_red_call(self, hop, color='red'):
+        FUNC = originalconcretetype(hop.args_s[0])
+        [v_funcbox] = hop.inputargs(self.getredrepr(FUNC))
+        calldesc = rtimeshift.CallDesc(self.RGenOp, FUNC.TO)
+        c_calldesc = inputconst(lltype.Void, calldesc)
+        s_calldesc = self.rtyper.annotator.bookkeeper.immutablevalue(calldesc)
+        v_jitstate = hop.llops.getjitstate()
+        if color == 'red':
+            s_result = self.s_RedBox
+        else:
+            s_result = annmodel.s_None
+        return hop.llops.genmixlevelhelpercall(rtimeshift.ll_gen_residual_call,
+                                 [self.s_JITState, s_calldesc, self.s_RedBox],
+                                 [v_jitstate,      c_calldesc, v_funcbox    ],
+                                 s_result)
+
+    def translate_op_residual_gray_call(self, hop):
+        self.translate_op_residual_red_call(hop, color='gray')
+
 
 class HintLowLevelOpList(LowLevelOpList):
     """Warning: the HintLowLevelOpList's rtyper is the *original*

Modified: pypy/dist/pypy/jit/timeshifter/test/test_promotion.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/test/test_promotion.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/test/test_promotion.py	Sat Sep 30 18:48:09 2006
@@ -42,16 +42,36 @@
         assert res == ll_function(10, 0)
         self.check_insns(int_add=10, int_mul=0)
 
-##    def test_method_call(self):
-##        class Base(object):
-##            pass
-##        class Int(Base):
-##            def __init__(self, n):
-##                self.n = n
-##            def double(self):
-##                return Int(self.n * 2)
-##        class Str(Base):
-##            def __init__(self, s):
-##                self.s = s
-##            def double(self):
-##                return Str(self.s + self.s)
+    def test_method_call_nonpromote(self):
+        class Base(object):
+            pass
+        class Int(Base):
+            def __init__(self, n):
+                self.n = n
+            def double(self):
+                return Int(self.n * 2)
+            def get(self):
+                return self.n
+        class Str(Base):
+            def __init__(self, s):
+                self.s = s
+            def double(self):
+                return Str(self.s + self.s)
+            def get(self):
+                return int(self.s)
+
+        def ll_make(n):
+            if n > 0:
+                return Int(n)
+            else:
+                return Str('123')
+
+        def ll_function(n):
+            o = ll_make(n)
+            return o.double().get()
+
+        res = self.timeshift(ll_function, [5], [], policy=P_NOVIRTUAL)
+        assert res == 10
+
+        res = self.timeshift(ll_function, [0], [], policy=P_NOVIRTUAL)
+        assert res == 123123

Modified: pypy/dist/pypy/jit/timeshifter/transform.py
==============================================================================
--- pypy/dist/pypy/jit/timeshifter/transform.py	(original)
+++ pypy/dist/pypy/jit/timeshifter/transform.py	Sat Sep 30 18:48:09 2006
@@ -417,6 +417,8 @@
                     handler(block, i)
 
     def make_call(self, block, op, save_locals_vars, color='red'):
+        # the 'save_locals' pseudo-operation is used to save all
+        # alive local variables into the current JITState
         self.genop(block, 'save_locals', save_locals_vars)
         targets = dict(self.graphs_from(op))
         for tsgraph in targets.values():
@@ -424,15 +426,18 @@
                 # make sure jitstate.resumepoint is set to zero
                 self.genop(block, 'resetresumepoint', [])
                 break
+        args_v = op.args[1:]
+        if op.opname == 'indirect_call':
+            del args_v[-1]
         if len(targets) == 1:
             [tsgraph] = targets.values()
             c_tsgraph = inputconst(lltype.Void, tsgraph)
-            self.genop(block, '%s_call' % (color,), [c_tsgraph] + op.args[1:])
+            self.genop(block, '%s_call' % (color,), [c_tsgraph] + args_v)
             # Void result, because the call doesn't return its redbox result,
             # but only has the hidden side-effect of putting it in the jitstate
         else:
             c_targets = inputconst(lltype.Void, targets)
-            args_v = op.args[:-1] + [c_targets]
+            args_v = op.args[:1] + args_v + [c_targets]
             hs_func = self.hannotator.binding(args_v[0])
             if not hs_func.is_green():
                 # XXX for now, assume that it will be a constant red box
@@ -442,13 +447,8 @@
             self.genop(block, 'indirect_%s_call' % (color,), args_v)
 
     def handle_red_call(self, block, pos, color='red'):
-        # the 'save_locals' pseudo-operation is used to save all
-        # alive local variables into the current JITState
-        beforeops = block.operations[:pos]
-        op        = block.operations[pos]
-        afterops  = block.operations[pos+1:]
-
         varsalive = self.variables_alive(block, pos+1)
+        op = block.operations.pop(pos)
         try:
             varsalive.remove(op.result)
             uses_retval = True      # it will be restored by 'fetch_return'
@@ -456,29 +456,69 @@
             uses_retval = False
         reds, greens = self.sort_by_color(varsalive)
 
-        newops = []
-        self.make_call(newops, op, reds, color)
+        nextblock = self.naive_split_block(block, pos)
+
+        v_func = op.args[0]
+        hs_func = self.hannotator.binding(v_func)
+        if hs_func.is_green():
+            constantblock = block
+            nonconstantblock = None
+            blockset = {}
+        else:
+            constantblock = Block([])
+            nonconstantblock = Block([])
+            blockset = {constantblock: False,
+                        nonconstantblock: False}
+            v_is_constant = self.genop(block, 'is_constant', [v_func],
+                                       resulttype = lltype.Bool)
+            self.genswitch(block, v_is_constant, true  = constantblock,
+                                                 false = nonconstantblock)
+            constantblock.closeblock(Link([], nextblock))
+            nonconstantblock.closeblock(Link([], nextblock))
+
+        self.make_call(constantblock, op, reds, color)
 
         mapping = {}
         for i, var in enumerate(reds):
             c_index = Constant(i, concretetype=lltype.Signed)
-            newvar = self.genop(newops, 'restore_local', [c_index],
+            newvar = self.genop(constantblock, 'restore_local', [c_index],
                                 result_like = var)
             mapping[var] = newvar
 
         if uses_retval:
             assert not self.hannotator.binding(op.result).is_green()
             var = op.result
-            newvar = self.genop(newops, 'fetch_return', [],
+            newvar = self.genop(constantblock, 'fetch_return', [],
                                 result_like = var)
             mapping[var] = newvar
 
-        saved = block.inputargs
-        block.inputargs = []     # don't rename these!
-        block.operations = afterops
-        block.renamevariables(mapping)
-        block.inputargs = saved
-        block.operations[:0] = beforeops + newops
+        nextblock.renamevariables(mapping)
+
+        if nonconstantblock is not None:
+            args_v = op.args[1:]
+            if op.opname == 'indirect_call':
+                del args_v[-1]
+            # pseudo-obscure: the arguments for the call go in save_locals
+            self.genop(nonconstantblock, 'save_locals', args_v)
+            v_res = self.genop(nonconstantblock, 'residual_%s_call' % (color,),
+                               [op.args[0]], result_like = op.result)
+
+            oldvars = mapping.keys()
+            newvars = [mapping[v] for v in oldvars]
+            constantblock.exits[0].args = newvars
+            nextblock.inputargs = newvars
+
+            mapping2 = dict([(v, copyvar(self.hannotator, v))
+                             for v in newvars])
+            nextblock.renamevariables(mapping2)
+
+            mapping3 = {op.result: v_res}
+            nonconstantblock.exits[0].args = [mapping3.get(v, v)
+                                              for v in oldvars]
+
+        blockset[block] = True    # reachable from outside
+        blockset[nextblock] = False
+        SSA_to_SSI(blockset, self.hannotator)
 
     def handle_gray_call(self, block, pos):
         self.handle_red_call(block, pos, color='gray')



More information about the Pypy-commit mailing list