[pypy-svn] r18856 - in pypy/dist/pypy/translator/asm: . ppc test

mwh at codespeak.net mwh at codespeak.net
Mon Oct 24 12:00:28 CEST 2005


Author: mwh
Date: Mon Oct 24 12:00:25 2005
New Revision: 18856

Added:
   pypy/dist/pypy/translator/asm/model.py
Removed:
   pypy/dist/pypy/translator/asm/infregmachine.py
   pypy/dist/pypy/translator/asm/test/test_simulator.py
Modified:
   pypy/dist/pypy/translator/asm/genasm.py
   pypy/dist/pypy/translator/asm/ppc/codegen.py
   pypy/dist/pypy/translator/asm/regalloc.py
   pypy/dist/pypy/translator/asm/simulator.py
   pypy/dist/pypy/translator/asm/test/test_asm.py
Log:
substantial refactoring of the assembly generating stuff.
most of the code is still there, just not where it was.
the only significant change is that the comparisons copy 
their results into a regular register (still need to sort this
out, but probably in the register allocator).


Modified: pypy/dist/pypy/translator/asm/genasm.py
==============================================================================
--- pypy/dist/pypy/translator/asm/genasm.py	(original)
+++ pypy/dist/pypy/translator/asm/genasm.py	Mon Oct 24 12:00:25 2005
@@ -1,37 +1,26 @@
 import sys, os
 from pypy.objspace.flow.model import traverse, Block, Variable, Constant
-from pypy.translator.asm import infregmachine
+#from pypy.translator.asm import infregmachine
 from pypy.rpython.lltype import Signed
 from pypy.translator.asm.simulator import Machine, TranslateProgram
+from pypy.translator.asm.model import *
 
-# #Available Machine code targets (processor+operating system)
-# TARGET_UNKNOWN=0
-# TARGET_PPC=1
-# TARGET_WIN386=2
-
-# #set one of these
-# ASM_TARGET=TARGET_UNKNOWN
-# #ASM_TARGET=TARGET_WIN386
+#Available Machine code targets (processor+operating system)
+TARGET_UNKNOWN=0
+TARGET_PPC=1
+TARGET_WIN386=2
 
 # def determine_target():
-#     global ASM_TARGET
 #     if sys.platform == 'darwin':
 #         if os.uname()[-1] == 'Power Macintosh':
-#             ASM_TARGET = TARGET_PPC
+#             return TARGET_PPC
 #     elif sys.platform == 'win32':
 #         if 'Intel' in sys.version:
-#             ASM_TARGET = TARGET_WIN386
-
-# determine_target()
-# if ASM_TARGET == TARGET_UNKNOWN:
-#     raise Exception, 'Unknown Machine-code target specified.'
-
-# if ASM_TARGET==TARGET_PPC:
-#     from pypy.translator.asm.ppcgen.ppc_assembler import PPCAssembler
-#     from pypy.translator.asm.ppcgen.func_builder import make_func
-# elif ASM_TARGET==TARGET_WIN386:
-#     from pypy.translator.asm.i386gen.i386_assembler import i386Assembler as PPCAssembler  #spoof system for time being
-#     from pypy.translator.asm.i386gen.i386_assembler import make_func
+#             return TARGET_WIN386
+#     else:
+#         return TARGET_UNKNOWN
+#
+# ASM_TARGET = determine_target()
 
 
 def genasm(translator, processor):
@@ -51,25 +40,23 @@
     g.gencode()
 
     if processor == 'virt':
+        machine = Machine(g.insns)
         def r(*args):
-            return Machine.RunProgram(g.assembler.instructions,
-                                      args,
-                                      tracing=True)
+            return machine.execute(*args)
 
         return r
     elif processor == 'virtfinite':
-        insns = TranslateProgram(g.assembler.instructions, 50)
+        insns = TranslateProgram(g.insns, 50)
         for i in insns:
             print i
         def r(*args):
             return Machine.RunProgram(insns,
-                                      args,
-                                      tracing=True)
+                                      args)
 
         return r
     elif processor == 'ppc':
         from pypy.translator.asm.ppc import codegen
-        return codegen.make_native_code(graph, g.assembler.instructions)
+        return codegen.make_native_code(graph, g.insns)
 
 class FuncGenerator(object):
 
@@ -86,10 +73,10 @@
             self.blocknum[block] = len(self.blocknum)
 
         self._block_counter = 0
-        self.assembler = infregmachine.Assembler()
+        self.insns = []
 
         for i, var in enumerate(graph.startblock.inputargs):
-            self.emit('LIA', self.reg(var), Constant(i))
+            self.insns.append(LOAD_ARGUMENT(self.reg(var), i))
 
     def assign_register(self, var):
         assert var not in self._var2reg
@@ -103,7 +90,7 @@
         if isinstance(var, Constant):
             r = self.next_register
             assert isinstance(var.value, int)
-            self.assembler.emit("LOAD", r, var)
+            self.insns.append(LOAD_IMMEDIATE(r, var.value))
             self.next_register += 1
             return r
         elif isinstance(var, Variable):
@@ -121,44 +108,38 @@
         return 'block' + str(self.blocknum[block])
 
     def genlinkcode(self, link):
-        A = self.assembler
         for s, t in zip(link.args, link.target.inputargs):
             if isinstance(s, Constant) or s.name != t.name:
-                A.emit('MOV', self.reg(t), self.reg(s))
-        A.emit('J', self.blocktarget(link.target))
+                self.insns.append(MOVE(self.reg(t), self.reg(s)))
+        self.insns.append(JUMP(self.blocktarget(link.target)))
 
     def genblockcode(self, block):
-        A = self.assembler
-        A.label(self.blocktarget(block))
+        self.insns.append(Label(self.blocktarget(block)))
 
         assert len(block.exits) in [0, 1, 2]
 
-        ordinaryops = block.operations[:]
-        if len(block.exits) == 2:
-            assert block.exitswitch is not None
-            assert block.operations[-1].result is block.exitswitch
-            del ordinaryops[-1]
-
-        for op in ordinaryops:
-            A.emit(op.opname, self.reg(op.result), *map(self.reg, op.args))
+        for op in block.operations:
+            self.insns.append(LLInstruction(
+                op.opname, self.reg(op.result), *map(self.reg, op.args)))
 
         if len(block.exits) == 2:
             assert block.exitswitch is not None
             falselink, truelink = block.exits
-            lastop = block.operations[-1]
-            assert lastop.opname in ['int_gt', 'int_lt', 'int_ge',
-                                     'int_eq', 'int_le', 'int_ne']
-            A.emit(lastop.opname, *map(self.reg, lastop.args))
+            assert truelink.exitcase == True
+            assert falselink.exitcase == False
+
             b = self.blockname()
-            A.emit('JT', b)
+            self.insns.append(JUMP_IF_TRUE(self.reg(block.exitswitch), b))
             self.genlinkcode(falselink)
-            A.label(b)
+
+            self.insns.append(Label(b))
             self.genlinkcode(truelink)
+            
         elif len(block.exits) == 1:
             self.genlinkcode(block.exits[0])
         else:
             assert len(block.inputargs) == 1
-            A.emit('RETPYTHON', self.reg(block.inputargs[0]))
+            self.insns.append(RETPYTHON(self.reg(block.inputargs[0])))
 
     def gencode(self):
         for block in self.allblocks:

Added: pypy/dist/pypy/translator/asm/model.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/asm/model.py	Mon Oct 24 12:00:25 2005
@@ -0,0 +1,263 @@
+from pypy.annotation.pairtype import extendabletype
+
+class Instruction(object):
+    __metaclass__ = extendabletype
+    
+    def registers_used(self):
+        return [self.target_register()] + list(self.source_registers())
+
+    def target_register(self):
+        pass
+
+    def source_registers(self):
+        pass
+
+    def renumber(self, map):
+        pass
+
+    def execute(self, machine):
+        assert not "not here"
+
+    def __repr__(self):
+        args = []
+        for k, v in self.__dict__.iteritems():
+            args.append('%s=%r'%(k, v))
+        return '%s(%s)'%(self.__class__.__name__, ', '.join(args))
+
+
+class LLInstruction(Instruction):
+    def __init__(self, opname, dest, *sources):
+        self.opname = opname
+        self.dest = dest
+        self.sources = sources
+
+    def target_register(self):
+        return self.dest
+
+    def source_registers(self):
+        return self.sources
+
+    def renumber(self, map):
+        return LLInstruction(self.opname,
+                             map[self.dest],
+                             *[map[s] for s in self.sources])
+
+    def execute(self, machine):
+        from pypy.rpython.llinterp import LLFrame
+        sources = map(machine.get_register, self.sources)
+        result = LLFrame.__dict__['op_' + self.opname](None, *sources)
+        machine.store_register(self.dest, result)
+
+
+class LOAD_IMMEDIATE(Instruction):
+    def __init__(self, target, immed):
+        self.target = target
+        self.immed = immed
+
+    def target_register(self):
+        return self.target
+
+    def source_registers(self):
+        return []
+
+    def renumber(self, map):
+        return LOAD_IMMEDIATE(map[self.target], self.immed)
+
+    def execute(self, machine):
+        machine.store_register(self.target, self.immed)
+
+
+class LOAD_ARGUMENT(Instruction):
+    def __init__(self, target, argindex):
+        self.target = target
+        self.argindex = argindex
+
+    def target_register(self):
+        return self.target
+
+    def source_registers(self):
+        return []
+
+    def renumber(self, map):
+        return LOAD_ARGUMENT(map[self.target], self.argindex)
+
+    def execute(self, machine):
+        machine.store_register(self.target, machine.args[self.argindex])
+
+
+class MOVE(Instruction):
+    def __init__(self, target, source):
+        self.target = target
+        self.source = source
+
+    def target_register(self):
+        return self.target
+
+    def source_registers(self):
+        return [self.source]
+
+    def renumber(self, map):
+        return MOVE(map[self.target], map[self.source])
+
+    def execute(self, machine):
+        machine.store_register(self.target, machine.get_register(self.source))
+    
+
+class RETPYTHON(Instruction):
+    def __init__(self, source):
+        self.source = source
+
+    def target_register(self):
+        return None
+
+    def source_registers(self):
+        return [self.source]
+
+    def renumber(self, map):
+        return RETPYTHON(map[self.source])
+
+    def execute(self, machine):
+        machine.retval = machine.get_register(self.source)
+        machine.stopped = True
+
+
+class ControlFlowInstruction(Instruction):
+    def registers_used(self):
+        return []
+
+    def target_register(self):
+        return None
+
+    def source_registers(self):
+        return []
+
+    def renumber(self, map):
+        return self
+
+
+class Label(ControlFlowInstruction):
+    def __init__(self, name):
+        self.name = name
+
+    def execute(self, machine):
+        pass
+    
+
+class Jump(ControlFlowInstruction):
+    def __init__(self, target):
+        self.target = target
+
+    def do_jump(self, machine):
+        for i, insn in enumerate(machine.insns):
+            print i, insn
+            if isinstance(insn, Label):
+                if insn.name == self.target:
+                    break
+        else:
+            raise Exception, ""
+        machine.program_counter = i
+
+
+class JUMP(Jump):
+    def execute(self, machine):
+        self.do_jump(machine)
+
+
+class ConditionalJump(Jump):
+    def __init__(self, source, target):
+        self.source = source
+        self.target = target
+
+    def source_registers(self):
+        return [self.source]
+
+    def renumber(self, map):
+        return self.__class__(map[self.source], self.target)
+
+
+class JUMP_IF_TRUE(ConditionalJump):
+    def execute(self, machine):
+        val = machine.get_register(self.source)
+        assert isinstance(val, bool)
+        if val:
+            self.do_jump(machine)
+
+
+class JUMP_IF_FALSE(ConditionalJump):
+    def execute(self, machine):
+        val = machine.get_register(self.source)
+        assert isinstance(val, bool)
+        if not val:
+            self.do_jump(machine)
+
+
+class STORE_STACK(Instruction):
+    def __init__(self, stackindex, source):
+        self.stackindex = stackindex
+        self.source = source
+
+    def target_register(self):
+        return None
+
+    def source_registers(self):
+        return [self.source]
+
+    def renumber(self, map):
+        return STORESTACK(stackindex, map[source])
+
+    def execute(self, machine):
+        machine.stack[self.stackindex] = machine.get_register(self.source)
+
+
+class LOAD_STACK(Instruction):
+    def __init__(self, target, stackindex):
+        self.target = target
+        self.stackindex = stackindex
+
+    def target_register(self):
+        return self.target
+
+    def source_registers(self):
+        return []
+
+    def renumber(self, map):
+        return LOADSTACK(map[self.target], self.stackindex)
+
+    def execute(self, machine):
+        machine.store_register(self.target, machine.stack[self.stackindex])
+
+
+class Machine(object):
+    def __init__(self, insns, nreg=None, tracing=False):
+        self.insns = insns
+        self.nreg = nreg
+        self.tracing = tracing
+
+    def execute(self, *args):
+        self.stopped = False
+        self.registers = {}
+        self.stack = {}
+        self.program_counter = 0
+        self.args = args
+        if hasattr(self, 'retval'):
+            del self.retval
+        
+        while not self.stopped:
+            insn = self.insns[self.program_counter]
+            if self.tracing:
+                print self.program_counter, insn,
+                t = insn.target_register()
+                if t is not None:
+                    print t, '<-', 
+                print ', '.join(map(
+                    str, map(self.get_register, insn.source_registers())))
+            insn.execute(self)
+            self.program_counter += 1
+        return self.retval
+
+    def store_register(self, reg, value):
+        self.registers[reg] = value
+
+    def get_register(self, reg):
+        return self.registers[reg]
+

Modified: pypy/dist/pypy/translator/asm/ppc/codegen.py
==============================================================================
--- pypy/dist/pypy/translator/asm/ppc/codegen.py	(original)
+++ pypy/dist/pypy/translator/asm/ppc/codegen.py	Mon Oct 24 12:00:25 2005
@@ -1,14 +1,12 @@
-
+from pypy.translator.asm.model import *
 
 def make_native_code(graph, infreginsns):
     from pypy.translator.asm.ppcgen.func_builder import make_func
     maxregs = 0
     for insn in infreginsns:
-        if isinstance(insn, str):
-            continue
         for r in insn.registers_used():
             maxregs = max(r, maxregs)
-    
+
     from pypy.translator.asm import regalloc, simulator
 
     insns = regalloc.regalloc(infreginsns, 30)
@@ -21,7 +19,7 @@
                      'i'*len(graph.startblock.inputargs),
                      maxregs)
 
-    
+
 class PPCCodeGen(object):
 
     def assemble(self, insns):
@@ -29,88 +27,107 @@
         A = ppc_assembler.PPCAssembler()
 
         for i in insns:
-            if isinstance(i, str):
-                A.label(i)
-                continue
-
-            getattr(self, i.name)(A, *i.arguments)
+            i.ppc_assemble(A)
 
         return A
 
-    def LIA(self, A, dest, argindex):
-        assert dest + 2 == argindex.value + 3
-
-    def LOAD(self, A, dest, value):
-        value = value.value
-        assert isinstance(value, int)
-        assert -30000 < value < 30000
-        A.li(dest + 2, value)
+class __extend__(LOAD_ARGUMENT):
+    def ppc_assemble(self, A):
+        assert self.target + 2 == self.argindex + 3
+
+class __extend__(LOAD_IMMEDIATE):
+    def ppc_assemble(self, A):
+        assert isinstance(self.immed, int)
+        assert -30000 < self.immed < 30000
+        A.li(self.target + 2, self.immed)
+
+class __extend__(Label):
+    def ppc_assemble(self, A):
+        A.label(self.name)
 
-    def JT(self, A, branch):
+class __extend__(JUMP_IF_TRUE):
+    def ppc_assemble(self, A):
         # should be "A.bt(BI=0, BD=branch)" but this crashes.
-        A.blt(branch)
+        A.blt(self.target)
 
-    def J(self, A, branch):
-        A.b(branch)
-
-    def RETPYTHON(self, A, reg):
-        A.mr(3, reg + 2)
+class __extend__(JUMP):
+    def ppc_assemble(self, A):
+        A.b(self.target)
+
+class __extend__(RETPYTHON):
+    def ppc_assemble(self, A):
+        A.mr(3, self.source + 2)
         A.blr()
 
-    def MOV(self, A, dest, src):
-        A.mr(dest + 2, src + 2)
-
-    def EXCH(self, A, a, b):
-        A.xor(a+2, a+2, b+2)
-        A.xor(b+2, b+2, a+2)
-        A.xor(a+2, a+2, b+2)
-
-    def STORESTACK(self, A, s, v):
-        A.stw(v+2, 1, 24+4*s.value)
-
-    def LOADSTACK(self, A, v, s):
-        A.lwz(v+2, 1, 24+4*s.value)
+class __extend__(MOVE):
+    def ppc_assemble(self, A):
+        A.mr(self.target + 2, self.source + 2)
+
+class __extend__(STORE_STACK):
+    def ppc_assemble(self, A):
+        A.stw(self.source+2, 1, 24+4*self.stackindex)
+
+class __extend__(LOAD_STACK):
+    def ppc_assemble(self, A):
+        A.lwz(self.target+2, 1, 24+4*self.stackindex)
+
+class __extend__(LLInstruction):
+    def ppc_assemble(self, A):
+        getattr(self, self.opname)(A, self.dest+2,
+                                   *[s + 2 for s in self.sources])
 
 
     def int_add(self, A, dest, a, b):
-        A.add(dest + 2, a + 2, b + 2)
+        A.add(dest, a, b)
 
     def int_sub(self, A, dest, a, b):
-        A.sub(dest + 2, a + 2, b + 2)
+        A.sub(dest, a, b)
 
     def int_mul(self, A, dest, a, b):
-        A.mullw(dest + 2, a + 2, b + 2)
+        A.mullw(dest, a, b)
 
     def int_mod(self, A, dest, a, b):
-        dest += 2; a += 2; b += 2
         A.divw(dest, a, b)
         A.mullw(dest, dest, b)
         A.subf(dest, dest, a)
 
 
     def int_and(self, A, dest, a, b):
-        A.and_(dest + 2, a + 2, b + 2)
+        A.and_(dest, a, b)
 
 
-    def int_gt(self, A, a, b):
-        A.cmpw(a + 2, b + 2)
+    def int_gt(self, A, dest, a, b):
+        A.cmpw(a, b)
         A.crmove(0, 1)
+        A.mfcr(dest)
+        A.srwi(dest, dest, 31)
+        
+    def int_lt(self, A, dest, a, b):
+        A.cmpw(a, b)
+        A.mfcr(dest)
+        A.srwi(dest, dest, 31)
 
-    def int_lt(self, A, a, b):
-        A.cmpw(a + 2, b + 2)
-
-    def int_ge(self, A, a, b):
-        A.cmpw(a + 2, b + 2)
+    def int_ge(self, A, dest, a, b):
+        A.cmpw(a, b)
         A.cror(0, 1, 2)
+        A.mfcr(dest)
+        A.srwi(dest, dest, 31)
 
-    def int_le(self, A, a, b):
-        A.cmpw(a + 2, b + 2)
+    def int_le(self, A, dest, a, b):
+        A.cmpw(a, b)
         A.cror(0, 0, 2)
+        A.mfcr(dest)
+        A.srwi(dest, dest, 31)
 
-    def int_eq(self, A, a, b):
-        A.cmpw(a + 2, b + 2)
+    def int_eq(self, A, dest, a, b):
+        A.cmpw(a, b)
         A.crmove(0, 2)
+        A.mfcr(dest)
+        A.srwi(dest, dest, 31)
 
-    def int_ne(self, A, a, b):
-        A.cmpw(a + 2, b + 2)
+    def int_ne(self, A, dest, a, b):
+        A.cmpw(a, b)
         A.cror(0, 0, 1)
+        A.mfcr(dest)
+        A.srwi(dest, dest, 31)
+        

Modified: pypy/dist/pypy/translator/asm/regalloc.py
==============================================================================
--- pypy/dist/pypy/translator/asm/regalloc.py	(original)
+++ pypy/dist/pypy/translator/asm/regalloc.py	Mon Oct 24 12:00:25 2005
@@ -1,24 +1,28 @@
-from pypy.objspace.flow.model import Constant
+from pypy.translator.asm.model import *
 
 def regalloc(insns, nregisters):
-    from pypy.translator.asm.infregmachine import Instruction
-
     output = []
-    
+
     for insn in insns:
-        if isinstance(insn, str):
-            output.append(insn)
-            continue
         thismap = {}
-        for i, r in enumerate(insn.registers_used()):
+        i = 1
+        target = insn.target_register()
+        if target is not None:
+            if not isinstance(insn, LOAD_ARGUMENT):
+                thismap[target] = i
+                i += 1
+            else:
+                thismap[target] = target
+
+        for r in insn.source_registers():
             if r not in thismap:
-                if insn.name != 'LIA':
-                    output.append(Instruction('LOADSTACK', (i+1, Constant(r))))
-                    thismap[r] = i+1
-                else:
-                    thismap[r] = r
+                output.append(LOAD_STACK(i+1, r))
+                thismap[r] = i+1
+                i += 1
+
         output.append(insn.renumber(thismap))
-        for r, i in thismap.items():
-            output.append(Instruction('STORESTACK', (Constant(r), i)))
-            
+
+        if target is not None:
+            output.append(STORE_STACK(target, thismap[target]))
+
     return output

Modified: pypy/dist/pypy/translator/asm/simulator.py
==============================================================================
--- pypy/dist/pypy/translator/asm/simulator.py	(original)
+++ pypy/dist/pypy/translator/asm/simulator.py	Mon Oct 24 12:00:25 2005
@@ -1,7 +1,7 @@
 """ IRM Simulator """
 import autopath
 from pypy.rpython.llinterp import LLFrame
-from pypy.translator.asm.infregmachine import Instruction
+#from pypy.translator.asm.infregmachine import Instruction
 from pypy.objspace.flow.model import Constant
 
 """
@@ -54,15 +54,20 @@
     assert nreg>=3 ,'Some commands may use 3 registers!!!!'
     newprog=[]
     pipe=[]
-    old2new=range(0,totreg+1)  #this must be as big as the total number of registers+1 (we start at index 1)
+    
+    # this must be as big as the total number of registers+1 (we start
+    # at index 1)
+    old2new=range(0,totreg+1)
 
 
     for cmd in commands:
-        #if we use any registers, we must possibly swap first, and then remap
-        if  isinstance(cmd,str) or cmd.name in ('J','JT','JF'): #label or jump so  pass through
+        # if we use any registers, we must possibly swap first, and
+        # then remap
+        if isinstance(cmd,str) or cmd.name in ('J','JT','JF'):
+            # label or jump so  pass through
             newprog.append(cmd)
         else:
-            #so now remap the registers!
+            # so now remap the registers!
 
             regused=cmd.registers_used()
             t2p=[old2new[x] for x in regused]

Modified: pypy/dist/pypy/translator/asm/test/test_asm.py
==============================================================================
--- pypy/dist/pypy/translator/asm/test/test_asm.py	(original)
+++ pypy/dist/pypy/translator/asm/test/test_asm.py	Mon Oct 24 12:00:25 2005
@@ -121,9 +121,9 @@
         big = 1000000000
         assert f(big, big) == g(big, big)
         
-class TestAsmAfterAllocation(TestAsm):
+## class TestAsmAfterAllocation(TestAsm):
 
-    processor = 'virtfinite'
+##     processor = 'virtfinite'
 
 
 class TestAsmPPC(TestAsm):



More information about the Pypy-commit mailing list