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

antocuni at codespeak.net antocuni at codespeak.net
Tue Jul 22 13:53:40 CEST 2008


Author: antocuni
Date: Tue Jul 22 13:53:38 2008
New Revision: 56709

Modified:
   pypy/branch/oo-jit/pypy/jit/codegen/cli/operation.py
   pypy/branch/oo-jit/pypy/jit/codegen/cli/rgenop.py
   pypy/branch/oo-jit/pypy/jit/codegen/cli/test/test_rgenop.py
   pypy/branch/oo-jit/pypy/translator/cli/src/pypylib.cs
Log:
(in-progress)

start implementing flexswitches for the CLI backend.  Not finished
yet.



Modified: pypy/branch/oo-jit/pypy/jit/codegen/cli/operation.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/cli/operation.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/cli/operation.py	Tue Jul 22 13:53:38 2008
@@ -194,6 +194,64 @@
         self.gv_value.load(self.builder)
         self.builder.graphbuilder.il.Emit(OpCodes.Stfld, self.fieldinfo)
 
+class DoFlexSwitch(Operation):
+
+    def __init__(self, builder, gv_flexswitch, gv_exitswitch, args_gv):
+        self.builder = builder
+        self.gv_flexswitch = gv_flexswitch
+        self.gv_exitswitch = gv_exitswitch
+        self.args_gv = args_gv # XXX: remove duplicates
+
+    def restype(self):
+        return None
+
+    def emit(self):
+        gbuilder = self.builder.graphbuilder
+        il = gbuilder.il
+        # get MethodInfo for LowLevelFlexSwitch.execute
+        clitype = self.gv_flexswitch.flexswitch.GetType()
+        meth_execute = clitype.GetMethod('execute')
+
+        # setup the correct inputargs
+        manager = InputArgsManager(gbuilder, self.args_gv)
+        manager.copy_from_args(self.builder)
+
+        # jumpto = flexswitch.execute(exitswitch, inputargs);
+        # goto dispatch_jump;
+        self.gv_flexswitch.load(self.builder)
+        self.gv_exitswitch.load(self.builder)
+        il.Emit(OpCodes.Ldloc, gbuilder.inputargs_var)
+        il.Emit(OpCodes.Callvirt, meth_execute)
+        il.Emit(OpCodes.Stloc, gbuilder.jumpto_var)
+        il.Emit(OpCodes.Br, gbuilder.dispatch_jump_label)
+
+
+class InputArgsManager:
+
+    def __init__(self, graphbuilder, args_gv):
+        self.inputargs_var = graphbuilder.inputargs_var
+        self.inputargs_clitype = graphbuilder.inputargs_clitype
+        self.args_gv = args_gv
+
+    def basename_from_type(self, clitype):
+        return clitype.get_Name()
+
+    def copy_from_args(self, builder):
+        il = builder.graphbuilder.il
+        inputargs_var = self.inputargs_var
+        inputargs_clitype = self.inputargs_clitype
+        counters = {}
+        for gv_arg in self.args_gv:
+            clitype = gv_arg.getCliType()
+            basename = self.basename_from_type(clitype)
+            count = counters.get(clitype, 0)
+            fieldname = '%s_%d' % (basename, count)
+            counters[clitype] = count+1
+            field = inputargs_clitype.GetField(fieldname)
+
+            il.Emit(OpCodes.Ldloc, inputargs_var)
+            gv_arg.load(builder)
+            il.Emit(OpCodes.Stfld, field)
 
 class WriteLine(Operation):
 

Modified: pypy/branch/oo-jit/pypy/jit/codegen/cli/rgenop.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/cli/rgenop.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/cli/rgenop.py	Tue Jul 22 13:53:38 2008
@@ -4,13 +4,17 @@
 from pypy.rpython.lltypesystem import lltype
 from pypy.rlib.objectmodel import specialize
 from pypy.jit.codegen.model import AbstractRGenOp, GenBuilder, GenLabel
-from pypy.jit.codegen.model import GenVarOrConst, GenVar, GenConst, CodeGenSwitch
+from pypy.jit.codegen.model import GenVarOrConst, GenVar, GenConst
+from pypy.jit.codegen.model import CodeGenSwitch
 from pypy.jit.codegen.cli import operation as ops
 from pypy.jit.codegen.cli.methodbuilder import get_methodbuilder
-from pypy.translator.cli.dotnet import CLR, typeof, new_array, box, unbox, clidowncast, classof
+from pypy.translator.cli.dotnet import CLR, typeof, new_array, init_array
+from pypy.translator.cli.dotnet import box, unbox, clidowncast, classof
 from pypy.translator.cli import dotnet
 System = CLR.System
 DelegateHolder = CLR.pypy.runtime.DelegateHolder
+LowLevelFlexSwitch = CLR.pypy.runtime.LowLevelFlexSwitch
+InputArgs = CLR.pypy.runtime.InputArgs
 OpCodes = System.Reflection.Emit.OpCodes
 
 cVoid = ootype.nullruntimeclass
@@ -20,6 +24,8 @@
 cObject = classof(System.Object)
 cString = classof(System.String)
 cChar = classof(System.Char)
+cInputArgs = classof(InputArgs)
+cUtils = classof(CLR.pypy.runtime.Utils)
 
 class SigToken:
     def __init__(self, args, res, funcclass):
@@ -213,6 +219,19 @@
             assert T is ootype.Object
             return ootype.cast_to_object(self.holder.GetFunc())
 
+class FlexSwitchConst(BaseConst):
+
+    def __init__(self, flexswitch):
+        self.flexswitch = flexswitch
+
+    def getobj(self):
+        return self.flexswitch
+
+    def load(self, builder):
+        index = self._get_index(builder)
+        self._load_from_array(builder, index, self.flexswitch.GetType())
+
+
 class Label(GenLabel):
     def __init__(self, label, inputargs_gv):
         self.label = label
@@ -338,6 +357,8 @@
         else:
             self.retvar = None
         self.retlabel = self.il.DefineLabel()
+        self.blockids = {}
+        self.has_flexswitches = False
 
     def appendbranch(self, branchbuilder):
         self.branches.append(branchbuilder)
@@ -395,11 +416,20 @@
     def genop_ooisnull(self, gv_obj):
         raise NotImplementedError
 
+    def flexswitch(self, gv_exitswitch, args_gv):
+        return self.branches[0].flexswitch(gv_exitswitch, args_gv)
+
     def end(self):
+        # emit initialization code
+        self.emit_preamble()
+        
         # render all the pending branches
         for branchbuilder in self.branches:
             branchbuilder.replayops()
 
+        # emit dispatch_jump, if there are flexswitches
+        self.emit_dispatch_jump()
+
         # render the return block for last, else the verifier could complain        
         self.il.MarkLabel(self.retlabel)
         if self.retvar:
@@ -414,6 +444,45 @@
         myfunc = self.meth.create_delegate(self.delegatetype, consts)
         self.gv_entrypoint.holder.SetFunc(myfunc)
 
+    def _setup_flexswitches(self):
+        if self.has_flexswitches:
+            return
+        self.has_flexswitches = True
+        self.dispatch_jump_label = self.il.DefineLabel()
+        self.inputargs_clitype = class2type(cInputArgs)
+        self.inputargs_var = self.il.DeclareLocal(self.inputargs_clitype)
+        self.jumpto_var = self.il.DeclareLocal(class2type(cInt32))
+
+    def emit_preamble(self):
+        if not self.has_flexswitches:
+            return        
+        # InputArgs inputargs_var = new InputArgs()
+        clitype = class2type(cInputArgs)
+        ctor = clitype.GetConstructor(new_array(System.Type, 0))
+        self.il.Emit(OpCodes.Newobj, ctor)
+        self.il.Emit(OpCodes.Stloc, self.inputargs_var)
+
+    def emit_dispatch_jump(self):
+        if not self.has_flexswitches:
+            return
+        # make sure we don't enter dispatch_jump by mistake
+        self.il.Emit(OpCodes.Br, self.retlabel)
+        self.il.MarkLabel(self.dispatch_jump_label)
+
+        labels = new_array(System.Reflection.Emit.Label,
+                           len(self.blockids))
+        for genlabel, blockid in self.blockids.iteritems():
+            labels[blockid] = genlabel.label
+
+        self.il.Emit(OpCodes.Ldloc, self.jumpto_var)
+        self.il.Emit(OpCodes.Switch, labels)
+        # XXX: handle blockids that are inside flexswitch cases
+        # default: Utils.throwInvalidBlockId(jumpto)
+        clitype = class2type(cUtils)
+        meth = clitype.GetMethod("throwInvalidBlockId")
+        self.il.Emit(OpCodes.Ldloc, self.jumpto_var)
+        self.il.Emit(OpCodes.Call, meth)
+
 
 class BranchBuilder(GenBuilder):
 
@@ -488,7 +557,13 @@
                 seen[gv] = None
         label = self.graphbuilder.il.DefineLabel()
         self.appendop(ops.MarkLabel(self, label))
-        return Label(label, args_gv)
+        return self.create_label(label, args_gv)
+
+    def create_label(self, label, args_gv):
+        res = Label(label, args_gv)
+        blockids = self.graphbuilder.blockids
+        blockids[res] = len(blockids)
+        return res
 
     def _jump_if(self, gv_condition, opcode):
         label = self.graphbuilder.il.DefineLabel()
@@ -504,6 +579,22 @@
     def jump_if_true(self, gv_condition, args_for_jump_gv):
         return self._jump_if(gv_condition, OpCodes.Brtrue)
 
+    def flexswitch(self, gv_exitswitch, args_gv):
+        self.graphbuilder._setup_flexswitches()
+        flexswitch = IntFlexSwitch()
+        flexswitch.xxxbuilder = BranchBuilder(self.graphbuilder, self.graphbuilder.il.DefineLabel())
+        gv_flexswitch = flexswitch.gv_flexswitch
+        lbl = self.graphbuilder.il.DefineLabel()
+        default_label = self.create_label(lbl, args_gv)
+        default_blockid = self.graphbuilder.blockids[default_label]
+        flexswitch.llflexswitch.set_default_blockid(default_blockid)
+        op = ops.DoFlexSwitch(self, gv_flexswitch, gv_exitswitch, args_gv)
+        self.appendop(op)
+        default_builder = BranchBuilder(self.graphbuilder, default_label.label)
+        self.graphbuilder.appendbranch(default_builder)
+        self.is_open = False
+        return flexswitch, default_builder
+
     def appendop(self, op):
         self.operations.append(op)
 
@@ -517,6 +608,19 @@
         for op in self.operations:
             op.emit()
 
+
+class IntFlexSwitch(CodeGenSwitch):
+
+    def __init__(self):
+        self.llflexswitch = LowLevelFlexSwitch()
+        self.gv_flexswitch = FlexSwitchConst(self.llflexswitch)
+
+    def add_case(self, gv_case):
+        return self.xxxbuilder
+        #import pdb;pdb.set_trace()
+
+
+
 global_rgenop = RCliGenOp()
 RCliGenOp.constPrebuiltGlobal = global_rgenop.genconst
 zero_const = ObjectConst(ootype.NULL)

Modified: pypy/branch/oo-jit/pypy/jit/codegen/cli/test/test_rgenop.py
==============================================================================
--- pypy/branch/oo-jit/pypy/jit/codegen/cli/test/test_rgenop.py	(original)
+++ pypy/branch/oo-jit/pypy/jit/codegen/cli/test/test_rgenop.py	Tue Jul 22 13:53:38 2008
@@ -34,7 +34,7 @@
         py.test.skip('fixme')
 
     def test_switch_direct(self):
-        py.test.skip('no promotion/flexswitch for now please :-)')
+        py.test.skip('in-progress')
 
     def test_large_switch_direct(self):
         py.test.skip('no promotion/flexswitch for now please :-)')

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	Tue Jul 22 13:53:38 2008
@@ -103,6 +103,43 @@
 namespace pypy.runtime
 {
 
+    // XXX: these classes should be automatically generated by the JIT backend
+    public delegate int FlexSwitchCase(int block, InputArgs args);
+    public class InputArgs {
+        public int Int32_0;
+        public int Int32_1;
+    }
+
+    public class LowLevelFlexSwitch
+    {
+        public int default_blockid = -1;
+        public int numcases = 0;
+        public int[] values = new int[10]; // XXX maxlength?
+        public FlexSwitchCase[] cases = new FlexSwitchCase[10];
+
+        public void set_default_blockid(int blockid)
+        {
+            this.default_blockid = blockid;
+        }
+
+        public void add_case(int v, FlexSwitchCase c)
+        {
+            values[numcases] = v;
+            cases[numcases] = c;
+            numcases++;
+        }
+        
+        public int execute(int v, InputArgs args)
+        {
+            for(int i=0; i<numcases; i++)
+                if (values[i] == v) {
+                    return cases[i](-1, args); // -1 stands for "the first block of the function"
+                }
+            return default_blockid;
+        }        
+    }
+
+        
     public class DelegateHolder
     {
         public Delegate func;
@@ -122,6 +159,7 @@
     public class AutoSaveAssembly
     {
         private AssemblyBuilder assembly;
+        private bool saved = false;
         private string name;
 
         public static AutoSaveAssembly Create(string name)
@@ -137,9 +175,17 @@
             this.assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
         }
 
-        ~AutoSaveAssembly()
+        public void Save()
         {
+            if (this.saved)
+                return;
             this.assembly.Save(this.name);
+            this.saved = true;
+        }
+
+        ~AutoSaveAssembly()
+        {
+            this.Save();
         }
 
         public AssemblyBuilder GetAssemblyBuilder()
@@ -270,6 +316,11 @@
             return obj.GetHashCode();
         }
 
+        public static void throwInvalidBlockId(int blockid)
+        {
+            throw new Exception(string.Format("Invalid block id: {0}", blockid));
+        }
+
         public static void Serialize(object obj, string filename)
         {
             FileStream fs = new FileStream(filename, FileMode.Create);



More information about the Pypy-commit mailing list