[pypy-svn] r57231 - in pypy/branch/oo-jit/pypy: jit/codegen/cli jit/codegen/test translator/cli/src

antocuni at codespeak.net antocuni at codespeak.net
Wed Aug 13 20:56:27 CEST 2008


Author: antocuni
Date: Wed Aug 13 20:56:25 2008
New Revision: 57231

Modified:
   pypy/branch/oo-jit/pypy/jit/codegen/cli/args_manager.py
   pypy/branch/oo-jit/pypy/jit/codegen/test/rgenop_tests.py
   pypy/branch/oo-jit/pypy/translator/cli/src/pypylib.cs
Log:
- add a test that passes "many" (==4) arguments across non-local links

- change completetly the way InputArgs is implemented, by using a chain of
  struct Pair<head, tail>.  As proven by user/antocuni/cli-bench/inputargs.cs,
  this has little impact on performances



Modified: pypy/branch/oo-jit/pypy/jit/codegen/cli/args_manager.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/cli/args_manager.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/cli/args_manager.py	Wed Aug 13 20:56:25 2008
@@ -4,13 +4,39 @@
 Assembly = System.Reflection.Assembly
 OpCodes = System.Reflection.Emit.OpCodes
 
+def new_type_array(types):
+    array = dotnet.new_array(System.Type, len(types))
+    for i in range(len(types)):
+        array[i] = types[i]
+    return array
+
+def MakeGenericType(clitype, paramtypes):
+    array = new_type_array(paramtypes)
+    return clitype.MakeGenericType(array)
+
 class ArgsManager:
     
     def __init__(self):
         self.type_counter = {}
+        self.type_index = {}
         self.clitype = None
-        self.fieldtypes = None
-        self.slots = None
+        self._init_types()
+
+    def _load_pypylib(self):
+        from pypy.translator.cli.query import pypylib, pypylib2
+        assembly = None
+        for name in [pypylib, pypylib2]:
+            assembly = Assembly.LoadWithPartialName(name)
+            if assembly:
+                break
+        assert assembly is not None
+        return assembly
+
+    def _init_types(self):
+        pypylib = self._load_pypylib()
+        self.clitype_InputArgs = pypylib.GetType('pypy.runtime.InputArgs`1')
+        self.clitype_Void = pypylib.GetType('pypy.runtime.Void')
+        self.clitype_Pair = pypylib.GetType('pypy.runtime.Pair`2')
 
     def is_open(self):
         return self.clitype is None
@@ -19,11 +45,10 @@
         assert not self.is_open()
         return self.clitype
 
-    def register(self, args_gv):
+    def register_types(self, types):
         assert self.is_open()
         newcounter = {}
-        for gv_arg in args_gv:
-            clitype = gv_arg.getCliType()
+        for clitype in types:
             newcount = newcounter.get(clitype, 0)
             newcounter[clitype] = newcount+1
 
@@ -32,99 +57,86 @@
             maxcount = max(oldcount, newcount)
             self.type_counter[clitype] = maxcount
 
+    def register(self, args_gv):
+        types = [gv_arg.getCliType() for gv_arg in args_gv]
+        self.register_types(types)
+
     def close(self):
         assert self.is_open()
-        templates = self._get_templates()
-        
-        self.fieldtypes = fieldtypes = []
-        self.slots = slots = {}
+        fieldtypes = []
         for clitype, count in self.type_counter.iteritems():
-            start = len(fieldtypes)
-            end = start+count
-            fieldtypes += [clitype]*count
-            slots[clitype] = self._myrange(start, end)
-        numfields = len(fieldtypes)
-        
-        if numfields <= len(templates):
-            template = templates[numfields-1]
-            array = dotnet.new_array(System.Type, numfields)
-            for i in range(numfields):
-                array[i] = fieldtypes[i]
-            self.clitype = template.MakeGenericType(array)
-        else:
-            assert False, 'TODO'
+            self.type_index[clitype] = len(fieldtypes)
+            fieldtypes += [clitype] * count
+
+        pairtype = self.clitype_Void
+        # iterate over reversed(fieldtypes)
+        i = len(fieldtypes)-1
+        while True:
+            if i < 0:
+                break
+            fieldtype = fieldtypes[i]
+            pairtype = MakeGenericType(self.clitype_Pair, [fieldtype, pairtype])
+            i-=1
+
+##         for fieldtype in fieldtypes[::-1]:
+##             pairtype = MakeGenericType(self.clitype_Pair, [fieldtype, pairtype])
+        self.clitype = MakeGenericType(self.clitype_InputArgs, [pairtype])
+
+    def _store_by_index(self, meth, gv_arg, i):
+        head_info = self._load_nth_head(meth, i)
+        gv_arg.load(meth)
+        meth.il.Emit(OpCodes.Stfld, head_info)
+
+    def _load_by_index(self, meth, i):
+        head_info = self._load_nth_head(meth, i)
+        meth.il.Emit(OpCodes.Ldfld, head_info)
+
+    def _load_nth_head(self, meth, n):
+        il = meth.il
+        fields_info = self.clitype.GetField("fields")
+        meth.gv_inputargs.load(meth)
+        il.Emit(OpCodes.Ldflda, fields_info)
+
+        lastfield_info = fields_info
+        for _ in range(n):
+            fieldtype = lastfield_info.get_FieldType()
+            lastfield_info = fieldtype.GetField("tail")
+            il.Emit(OpCodes.Ldflda, lastfield_info)
+        fieldtype = lastfield_info.get_FieldType()
+        return fieldtype.GetField("head")
 
     def copy_to_inputargs(self, meth, args_gv):
         "copy args_gv into the appropriate fields of inputargs"
         assert not self.is_open()
-        il = meth.il
-        gv_inputargs = meth.gv_inputargs
-        fields = self._get_fields(args_gv)
-        assert len(args_gv) == len(fields)
-        for i in range(len(args_gv)):
+        fieldtypes = [gv_arg.getCliType() for gv_arg in args_gv]
+        indexes = self._get_indexes(fieldtypes)
+        assert len(indexes) == len(fieldtypes)
+        for i in range(len(indexes)):
+            n = indexes[i]
             gv_arg = args_gv[i]
-            fieldinfo = fields[i]
-            gv_inputargs.load(meth)
-            gv_arg.load(meth)
-            il.Emit(OpCodes.Stfld, fieldinfo)
+            self._store_by_index(meth, gv_arg, n)
 
     def copy_from_inputargs(self, meth, args_gv):
         "copy the appropriate fields of inputargs into args_gv"
         assert not self.is_open()
-        il = meth.il
-        gv_inputargs = meth.gv_inputargs
-        fields = self._get_fields(args_gv)
-        assert len(args_gv) == len(fields)
-        for i in range(len(args_gv)):
+        fieldtypes = [gv_arg.getCliType() for gv_arg in args_gv]
+        indexes = self._get_indexes(fieldtypes)
+        assert len(indexes) == len(fieldtypes)
+        for i in range(len(indexes)):
+            n = indexes[i]
             gv_arg = args_gv[i]
-            fieldinfo = fields[i]
-            gv_inputargs.load(meth)
-            il.Emit(OpCodes.Ldfld, fieldinfo)
+            self._load_by_index(meth, n)
             gv_arg.store(meth)
 
-    def _myrange(self, start, end):
-        length = (end - start)
-        res = [0] * length
-        for i in range(start, end):
-            res[i] = i
-        return res
-
-    def _load_pypylib(self):
-        from pypy.translator.cli.query import pypylib, pypylib2
-        assembly = None
-        for name in [pypylib, pypylib2]:
-            assembly = Assembly.LoadWithPartialName(name)
-            if assembly:
-                break
-        assert assembly is not None
-        return assembly
-    
-    def _get_templates(self):
-        pypylib = self._load_pypylib()
-        templates = []
-        i = 1
-        while True:
-            typename = 'pypy.runtime.InputArgs`%d' % i
-            clitype = pypylib.GetType(typename)
-            if not clitype:
-                break
-            templates.append(clitype)
-            i += 1
-        return templates
-
-    def _copy_slots(self):
-        'Deepcopy self.slots'
-        slots = {}
-        for key, value in self.slots.iteritems():
-            slots[key] = value[:]
-        return slots
-
-    def _get_fields(self, args_gv):
-        slots = self._copy_slots()
-        types = [gv_arg.getCliType() for gv_arg in args_gv]
-        fields = []
-        for clitype in types:
-            slot = slots[clitype].pop()
-            fieldinfo = self.clitype.GetField('field%d' % slot)
-            fields.append(fieldinfo)
-        return fields
+    def _get_indexes(self, fieldtypes):
+        indexes = []
+        curtype = None
+        curidx = -1
+        for fieldtype in fieldtypes:
+            if fieldtype != curtype:
+                curidx = self.type_index[fieldtype]
+                curtype = fieldtype
+            else:
+                curidx += 1
+            indexes.append(curidx)
+        return indexes

Modified: pypy/branch/oo-jit/pypy/jit/codegen/test/rgenop_tests.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/test/rgenop_tests.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/test/rgenop_tests.py	Wed Aug 13 20:56:25 2008
@@ -404,6 +404,53 @@
         return res
     return switch_runner
 
+def make_switch_many_args(T, rgenop):
+    """
+    def f(v0, v1, v2, v3, v4):
+        if v0 == 0: # switch
+            return 21*v1
+        elif v0 == 1:
+            return 21+v1+v2+v3+v4
+        else:
+            return v1
+    """
+    sigtoken = rgenop.sigToken(T.FUNC5)
+    builder, gv_switch, [gv0, gv1, gv2, gv3, gv4] = rgenop.newgraph(sigtoken, "switch_many_args")
+    builder.start_writing()
+
+    flexswitch, default_builder = builder.flexswitch(gv0, [gv1, gv2, gv3, gv4])
+    const21 = rgenop.genconst(21)
+
+    # default
+    default_builder.finish_and_return(sigtoken, gv1)
+    # case == 0
+    const0 = rgenop.genconst(0)
+    case_builder = flexswitch.add_case(const0)
+    gv_res_case0 = case_builder.genop2('int_mul', const21, gv1)
+    case_builder.finish_and_return(sigtoken, gv_res_case0)
+    # case == 1
+    const1 = rgenop.genconst(1)
+    case_builder = flexswitch.add_case(const1)
+    gv_tmp1 = case_builder.genop2('int_add', const21, gv1)
+    gv_tmp2 = case_builder.genop2('int_add', gv_tmp1, gv2)
+    gv_tmp3 = case_builder.genop2('int_add', gv_tmp2, gv3)
+    gv_res_case1 = case_builder.genop2('int_add', gv_tmp3, gv3)
+    case_builder.finish_and_return(sigtoken, gv_res_case1)
+
+    builder.end()
+    return gv_switch
+
+def get_switch_many_args_runner(T, RGenOp):
+    def switch_runner(x, y, z, w, k):
+        rgenop = RGenOp()
+        gv_switchfn = make_switch_many_args(T, rgenop)
+        switchfn = gv_switchfn.revealconst(T.Ptr(T.FUNC5))
+        res = switchfn(x, y, z, w, k)
+        keepalive_until_here(rgenop)    # to keep the code blocks alive
+        return res
+    return switch_runner
+
+
 def make_large_switch(T, rgenop):
     """
     def f(v0, v1):
@@ -1101,6 +1148,15 @@
         res = fn(42, 18)
         assert res == 18
 
+    def test_switch_many_args_compile(self):
+        fn = self.compile(get_switch_many_args_runner(self.T, self.RGenOp), [int, int, int, int, int])
+        res = fn(0, 2, 3, 4, 5)
+        assert res == 42
+        res = fn(1, 4, 5, 6, 6)
+        assert res == 42
+        res = fn(42, 16, 3, 4, 5)
+        assert res == 16
+
     def test_large_switch_compile(self):
         fn = self.compile(get_large_switch_runner(self.T, self.RGenOp), [int, int])
         res = fn(0, 2)
@@ -1340,6 +1396,17 @@
         res = fnptr(42, 16)
         assert res == 16
 
+    def test_switch_many_args_direct(self):
+        rgenop = self.RGenOp()
+        gv_switchfn = make_switch_many_args(self.T, rgenop)
+        fnptr = self.cast(gv_switchfn, 5)
+        res = fnptr(0, 2, 3, 4, 5)
+        assert res == 42
+        res = fnptr(1, 4, 5, 6, 6)
+        assert res == 42
+        res = fnptr(42, 16, 3, 4, 5)
+        assert res == 16
+
     def test_large_switch_direct(self):
         rgenop = self.RGenOp()
         gv_switchfn = make_large_switch(self.T, rgenop)

Modified: pypy/branch/oo-jit/pypy/translator/cli/src/pypylib.cs
==============================================================================
--- pypy/branch/oo-jit/pypy/translator/cli/src/pypylib.cs	(original)
+++ pypy/branch/oo-jit/pypy/translator/cli/src/pypylib.cs	Wed Aug 13 20:56:25 2008
@@ -105,13 +105,20 @@
 namespace pypy.runtime
 {
 
-    // XXX: these classes should be automatically generated by the JIT backend
-    public delegate int FlexSwitchCase(int block, object args);
-    public class InputArgs {
-        public int Int32_0;
-        public int Int32_1;
+    public struct Void {
+    }
+
+    public struct Pair<T0, T1> {
+      public T0 head;
+      public T1 tail;
     }
 
+    public class InputArgs<T> {
+      public T fields;
+    }
+
+    public delegate int FlexSwitchCase(int block, object args);
+
     public class LowLevelFlexSwitch
     {
         public int default_blockid = -1;



More information about the Pypy-commit mailing list