[pypy-svn] r33950 - pypy/dist/pypy/jit/codegen/ppc

mwh at codespeak.net mwh at codespeak.net
Tue Oct 31 14:26:03 CET 2006


Author: mwh
Date: Tue Oct 31 14:26:01 2006
New Revision: 33950

Modified:
   pypy/dist/pypy/jit/codegen/ppc/rgenop.py
Log:
(mwh, a bit of ericvrp)
many changes to the ppc generation to enable a better approach to
register allocation.  no actual better register allocation yet though.


Modified: pypy/dist/pypy/jit/codegen/ppc/rgenop.py
==============================================================================
--- pypy/dist/pypy/jit/codegen/ppc/rgenop.py	(original)
+++ pypy/dist/pypy/jit/codegen/ppc/rgenop.py	Tue Oct 31 14:26:01 2006
@@ -4,72 +4,90 @@
 from pypy.rpython.objectmodel import specialize, we_are_translated
 from pypy.jit.codegen.ppc.conftest import option
 
-class VarLocation(object):
-    pass
+class Register(object):
+    def __init__(self):
+        pass
 
-class RegisterLocation(VarLocation):
-    def __init__(self, reg):
-        self.reg = reg
-    def load(self, builder):
-        return self.reg
-    def spill(self, builder):
-        XXX
+class GPR(Register):
+    def __init__(self, number):
+        self.number = number
     def __repr__(self):
-        return '$r%s'%(self.reg,)
+        return 'r' + str(self.number)
+gprs = map(GPR, range(32))
 
-class StackLocation(VarLocation):
-    def __init__(self, offset):
-        self.offset = offset
-    def load(self, builder):
-        XXX
-    def spill(self, builder):
-        XXX
-    def __repr__(self):
-        return 'stack+%s'%(self.offset,)
+class FPR(Register):
+    def __init__(self, number):
+        self.number = number
 
-class CRLocation(VarLocation):
-    # for variables that are in a bit of the condition register
-    def __init__(self, bit, negated):
-        self.bit = bit
-        self.negated = negated
-    def load(self, builder):
-        #XXX
-        # probably:
-        r = builder.newvar().reg()
-        builder.asm.mfcr(r)
-        builder.asm.extrwi(r, r, 1, self.bit)
-        return r
-        # though most of the time, if we know the result is going to
-        # be put in a register there are better ways of doing it...
+fprs = map(GPR, range(32))
 
-class Var(GenVar):
+class CRF(Register):
+    def __init__(self, number):
+        self.number = number
 
-    def __init__(self, location):
-        self.location = location
+crfs = map(CRF, range(8))
 
-    def load(self, builder):
-        return self.location.load(builder)
+class CTR(Register):
+    pass
 
-    def spill(self, builder):
-        return self.location.spill(builder)
+ctr = CTR()
 
-    def reg(self):
-        assert isinstance(self.location, RegisterLocation)
-        return self.location.reg
+class NullRegister(Register):
+    pass
 
-    def __repr__(self):
-        return 'var@%r' % (self.location,)
+NO_REGISTER = -1
+GP_REGISTER = 0
+FP_REGISTER = 1
+CR_FIELD = 2
+CT_REGISTER = 3
+
+class RegisterAllocation:
+    def __init__(self, initial_mapping):
+        self.insns = []
+        self.reg2var = {}
+        self.var2reg = {}
+        for var, reg in initial_mapping.iteritems():
+            self.reg2var[reg] = var
+            self.var2reg[var] = reg
+        self.crfinfo = [(0, 0)] * 8
+    def allocate_for_insns(self, insns):
+        for insn in insns:
+            for i in range(len(insn.reg_args)):
+                arg = insn.reg_args[i]
+                argcls = insn.reg_arg_regclasses[i]
+                assert arg in self.var2reg
+            cand = None
+            if insn.result_regclass is GP_REGISTER:
+                for cand in gprs[3:]:
+                    if cand not in self.reg2var:
+                        break
+                if not cand:
+                    assert 0
+            elif insn.result_regclass is CR_FIELD:
+                assert crfs[0] not in self.reg2var
+                cand = crfs[0]
+                self.crfinfo[0] = insn.info
+            elif insn.result_regclass is CT_REGISTER:
+                assert ctr not in self.reg2var
+                cand = ctr
+            elif insn.result_regclass is not NO_REGISTER:
+                assert 0
+            if cand is not None:
+                self.var2reg[insn.result] = cand
+                self.reg2var[cand] = insn.result
+            insn.allocate(self)
+            self.insns.append(insn)
+        return self.insns
+
+class Var(GenVar):
+    def load(self, builder):
+        return self
 
 class IntConst(GenConst):
 
     def __init__(self, value):
         self.value = value
 
-    def load(self, builder):
-        reg = builder.newvar().reg()
-        builder.asm.load_word(reg, self.value)
-        return reg
-
     @specialize.arg(1)
     def revealconst(self, T):
         if isinstance(T, lltype.Ptr):
@@ -79,9 +97,146 @@
         else:
             return lltype.cast_primitive(T, self.value)
 
-    def __repr__(self):
-        return "const=%r" % (self.value,)
-
+    def load(self, builder):
+        var = builder.newvar()
+        builder.insns.append(
+            Insn_GPR__IMM(RPPCAssembler.load_word,
+                          var, [self]))
+        return var
+
+class Insn(object):
+    '''
+    result is the Var instance that holds the result, or None
+    result_regclass is the class of the register the result goes into
+
+    reg_args is the vars that need to have registers allocated for them
+    reg_arg_regclasses is the type of register that needs to be allocated
+    '''
+
+class Insn_GPR__GPR_GPR(Insn):
+    def __init__(self, methptr, result, args):
+        self.methptr = methptr
+
+        self.result = result
+        self.result_regclass = GP_REGISTER
+        self.reg_args = args
+        self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER]
+
+    def allocate(self, allocator):
+        self.result_reg = allocator.var2reg[self.result]
+        self.arg_reg1 = allocator.var2reg[self.reg_args[0]]
+        self.arg_reg2 = allocator.var2reg[self.reg_args[1]]
+
+    def emit(self, asm):
+        self.methptr(asm,
+                     self.result_reg.number,
+                     self.arg_reg1.number,
+                     self.arg_reg2.number)
+
+class Insn_GPR__GPR_IMM(Insn):
+    def __init__(self, methptr, result, args):
+        self.methptr = methptr
+        self.imm = args[1]
+
+        self.result = result
+        self.result_regclass = GP_REGISTER
+        self.reg_args = [args[0]]
+        self.reg_arg_regclasses = [GP_REGISTER]
+    def allocate(self, allocator):
+        self.result_reg = allocator.var2reg[self.result]
+        self.arg_reg = allocator.var2reg[self.reg_args[0]]
+    def emit(self, asm):
+        self.methptr(asm,
+                     self.result_reg.number,
+                     self.arg_reg.number,
+                     self.imm.value)
+
+class Insn_GPR__IMM(Insn):
+    def __init__(self, methptr, result, args):
+        self.methptr = methptr
+        self.imm = args[0]
+
+        self.result = result
+        self.result_regclass = GP_REGISTER
+        self.reg_args = []
+        self.reg_arg_regclasses = []
+    def allocate(self, allocator):
+        self.result_reg = allocator.var2reg[self.result]
+    def emit(self, asm):
+        self.methptr(asm,
+                     self.result_reg.number,
+                     self.imm.value)
+
+class CMPW(Insn):
+    def __init__(self, info, result, args):
+        self.info = info
+
+        self.result = result
+        self.result_regclass = CR_FIELD
+
+        self.reg_args = args
+        self.reg_arg_regclasses = [GP_REGISTER, GP_REGISTER]
+
+    def allocate(self, allocator):
+        self.result_reg = allocator.var2reg[self.result]
+        self.arg_reg1 = allocator.var2reg[self.reg_args[0]]
+        self.arg_reg2 = allocator.var2reg[self.reg_args[1]]
+
+    def emit(self, asm):
+        asm.cmpw(self.result_reg.number, self.arg_reg1.number, self.arg_reg2.number)
+
+class CMPWI(Insn):
+    def __init__(self, info, result, args):
+        self.info = info
+        self.imm = args[1]
+
+        self.result = result
+        self.result_regclass = CR_FIELD
+
+        self.reg_args = [args[0]]
+        self.reg_arg_regclasses = [GP_REGISTER]
+
+    def allocate(self, allocator):
+        self.result_reg = allocator.var2reg[self.result]
+        self.arg_reg = allocator.var2reg[self.reg_args[0]]
+
+    def emit(self, asm):
+        asm.cmpwi(self.result_reg.number, self.arg_reg.number, self.imm.value)
+
+class MTCTR(Insn):
+    def __init__(self, result, args):
+        self.result = result
+        self.result_regclass = CT_REGISTER
+
+        self.reg_args = args
+        self.reg_arg_regclasses = [GP_REGISTER]
+
+    def allocate(self, allocator):
+        self.arg_reg = allocator.var2reg[self.reg_args[0]]
+
+    def emit(self, asm):
+        asm.mtctr(self.arg_reg.number)
+
+class Jump(Insn):
+    def __init__(self, gv_cond, gv_target, jump_if_true):
+        self.gv_cond = gv_cond
+        self.gv_target = gv_target
+        self.jump_if_true = jump_if_true
+
+        self.result = None
+        self.result_regclass = NO_REGISTER
+        self.reg_args = [gv_cond, gv_target]
+        self.reg_arg_regclasses = [CR_FIELD, CT_REGISTER]
+    def allocate(self, allocator):
+        assert allocator.var2reg[self.reg_args[1]] is ctr
+        self.crf = allocator.var2reg[self.reg_args[0]]
+        self.bit, self.negated = allocator.crfinfo[self.crf.number]
+    def emit(self, asm):
+        if self.negated ^ self.jump_if_true:
+            BO = 12 # jump if relavent bit is set in the CR
+        else:
+            BO = 4  # jump if relavent bit is NOT set in the CR
+        asm.bcctr(BO, self.bit)
 
 from pypy.jit.codegen.ppc import codebuf_posix as memhandler
 from ctypes import POINTER, cast, c_char, c_void_p, CFUNCTYPE, c_int
@@ -98,18 +253,11 @@
     self.mc.write(value)
 RPPCAssembler.emit = emit
 
-def prepare_for_jump(builder, outputargs_gv, target):
-    assert len(target.arg_locations) == len(outputargs_gv)
-    outregs = []
-    targetregs = []
-    for gv in outputargs_gv:
-        assert isinstance(gv, Var)
-        assert isinstance(gv.location, RegisterLocation)
-        outregs.append(gv.location.reg)
-    for loc in target.arg_locations:
-        assert isinstance(loc, RegisterLocation)
-        targetregs.append(loc.reg)
-    for i in range(len(outregs)):
+def prepare_for_jump(builder, cur_locations, target):
+    assert len(target.arg_locations) == len(cur_locations)
+    targetregs = target.arg_locations
+    outregs = cur_locations
+    for i in range(len(cur_locations)):
         treg = targetregs[i]
         oreg = outregs[i]
         if oreg == treg:
@@ -117,13 +265,13 @@
         if treg in outregs:
             outi = outregs.index(treg)
             assert outi > i
-            builder.asm.xor(treg, treg, oreg)
-            builder.asm.xor(oreg, treg, oreg)
-            builder.asm.xor(treg, treg, oreg)
+            builder.asm.xor(treg.number, treg.number, oreg.number)
+            builder.asm.xor(oreg.number, treg.number, oreg.number)
+            builder.asm.xor(treg.number, treg.number, oreg.number)
             outregs[outi] = oreg
             outregs[i] == treg
         else:
-            builder.asm.mr(treg, oreg)
+            builder.asm.mr(treg.number, oreg.number)
 
 class MachineCodeBlock:
 
@@ -201,17 +349,19 @@
         self.rgenop = rgenop
         self.asm = RPPCAssembler()
         self.asm.mc = mc
-        if parent is None:
-            self.curreg = 3
-        else:
-            self.curreg = parent.curreg
+        self.insns = []
+        self.parent = parent
 
     def _write_prologue(self, sigtoken):
+        assert self.parent is None
         numargs = sigtoken     # for now
-        self.curreg += numargs
         if not we_are_translated() and option.trap:
             self.asm.trap()
-        return [Var(RegisterLocation(pos)) for pos in range(3, 3+numargs)]
+        self.inputargs = [self.newvar() for i in range(numargs)]
+        self.initial_varmapping = {}
+        for arg in self.inputargs:
+            self.initial_varmapping[arg] = gprs[3+len(self.initial_varmapping)]
+        return self.inputargs
 
     def _close(self):
         self.rgenop.close_mc(self.asm.mc)
@@ -222,46 +372,50 @@
         genmethod = getattr(self, 'op_' + opname)
         return genmethod(gv_arg1, gv_arg2)
 
+    def emit(self):
+        if self.parent is not None:
+            allocator = RegisterAllocation(self.parent.var2reg)
+        else:
+            allocator = RegisterAllocation(self.initial_varmapping)
+        self.insns = allocator.allocate_for_insns(self.insns)
+        for insn in self.insns:
+            insn.emit(self.asm)
+        self.var2reg = allocator.var2reg
+        return allocator
+
     def finish_and_return(self, sigtoken, gv_returnvar):
-        self.asm.mr(3, gv_returnvar.load(self))
+        gv_returnvar = gv_returnvar.load(self)
+        allocator = self.emit()
+        reg = allocator.var2reg[gv_returnvar]
+        if reg.number != 3:
+            self.asm.mr(3, reg.number)
         self.asm.blr()
         self._close()
 
     def finish_and_goto(self, outputargs_gv, target):
-        prepare_for_jump(self, outputargs_gv, target)
-        gv = self.newvar()
-        self.asm.load_word(gv.reg(), target.startaddr)
-        self.asm.mtctr(gv.reg())
+        allocator = self.emit()
+        cur_locations = [allocator.var2reg[v] for v in outputargs_gv]
+        prepare_for_jump(self, cur_locations, target)
+        self.asm.load_word(0, target.startaddr)
+        self.asm.mtctr(0)
         self.asm.bctr()
         self._close()
 
     def enter_next_block(self, kinds, args_gv):
         arg_locations = []
-        seen = {}
         for i in range(len(args_gv)):
             gv = args_gv[i]
-            # turn constants into variables; also make copies of vars that
-            # are duplicate in args_gv
-            if not isinstance(gv, Var):
-                gv = args_gv[i] = Var(RegisterLocation(gv.load(self)))
-            elif gv.location in seen:
-                if isinstance(gv.location, RegisterLocation):
-                    new_gv = args_gv[i] = self.newvar()
-                    assert isinstance(gv.location, RegisterLocation)
-                    self.asm.mr(new_gv.reg(), gv.reg())
-                    gv = new_gv
-                else:
-                    gv = args_gv[i] = Var(RegisterLocation(gv.load(self)))
-            # remember the var's location
-            arg_locations.append(gv.location)
-            seen[gv.location] = None
+            gv = args_gv[i] = gv.load(self)
+        allocator = self.emit()
+        for gv in args_gv:
+            arg_locations.append(allocator.var2reg[gv])
+        self.insns = []
+        self.initial_varmapping = allocator.var2reg
         return Label(self.asm.mc.tell(), arg_locations)
 
     def newvar(self):
-        d = self.curreg
-        self.curreg += 1
-        assert d < 12
-        return Var(RegisterLocation(d))
+        gv = Var()
+        return gv
 
     def new_and_load_2(self, gv_x, gv_y):
         gv_result = self.newvar()
@@ -273,64 +427,61 @@
 
     def op_int_add(self, gv_x, gv_y):
         if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2*16:
-            gv_result, r_x = self.new_and_load_1(gv_x)
-            self.asm.addi(gv_result.reg(), r_x, gv_y.value)
+            gv_result = self.newvar()
+            self.insns.append(
+                Insn_GPR__GPR_IMM(RPPCAssembler.addi,
+                                  gv_result, [gv_x.load(self), gv_y]))
             return gv_result
         elif isinstance(gv_x, IntConst):
             return self.op_int_add(gv_y, gv_x)
         else:
-            gv_result, r_x, r_y = self.new_and_load_2(gv_x, gv_y)
-            self.asm.add(gv_result.reg(), r_x, r_y)
+            gv_result = self.newvar()
+            self.insns.append(
+                Insn_GPR__GPR_GPR(RPPCAssembler.add,
+                                  gv_result, [gv_x.load(self), gv_y.load(self)]))
             return gv_result
 
     def op_int_sub(self, gv_x, gv_y):
-        gv_result, r_x, r_y = self.new_and_load_2(gv_x, gv_y)
-        self.asm.sub(gv_result.reg(), r_x, r_y)
+        gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y)
+        self.insns.append(
+            Insn_GPR__GPR_GPR(RPPCAssembler.sub,
+                              gv_result, [gv_x, gv_y]))
         return gv_result
 
     def op_int_floordiv(self, gv_x, gv_y):
-        gv_result, r_x, r_y = self.new_and_load_2(gv_x, gv_y)
-        self.asm.divw(gv_result.reg(), r_x, r_y)
+        gv_result, gv_x, gv_y = self.new_and_load_2(gv_x, gv_y)
+        self.insns.append(
+            Insn_GPR__GPR_GPR(RPPCAssembler.divw,
+                              gv_result, [gv_x.load(self), gv_y.load(self)]))
         return gv_result
 
-    def _compare(self, gv_x, gv_y):
+    def _compare(self, op, gv_x, gv_y):
+        assert op == 'gt'
+        result = self.newvar()
         if isinstance(gv_y, IntConst) and abs(gv_y.value) < 2*16:
-            r_x = gv_x.load(self)
-            self.asm.cmpwi(0, r_x, gv_y.value)
-            return False
+            gv_x = gv_x.load(self)
+            self.insns.append(CMPWI((1, 0), result, [gv_x, gv_y]))
         elif isinstance(gv_x, IntConst) and abs(gv_x.value) < 2*16:
-            r_y = gv_y.load(self)
-            self.asm.cmpwi(0, r_y, gv_x.value)
-            return True
+            gv_y = gv_y.load(self)
+            self.insns.append(CMPWI((1, 1), result, [gv_y, gv_x]))
         else:
-            r_x, r_y = gv_x.load(self), gv_y.load(self)
-            self.asm.cmpw(0, r_x, r_y)
-            return False
+            self.insns.append(CMPW((1, 0), result, [gv_x.load(self), gv_y.load(self)]))
+        return result
 
     def op_int_gt(self, gv_x, gv_y):
-        flipped = self._compare(gv_x, gv_y)
-        return Var(CRLocation(1, flipped))
+        return self._compare('gt', gv_x, gv_y)
 
     def _jump(self, gv_condition, if_true):
         targetbuilder = self._fork()
         gv = self.newvar()
-        self.asm.load_word(gv.reg(), targetbuilder.asm.mc.tell())
-        self.asm.mtctr(gv.reg())
-        if isinstance(gv_condition.location, CRLocation):
-            loc = gv_condition.location
-            # scribbling on paper advised for understanding next
-            # lines:
-            if loc.negated ^ if_true:
-                BO = 12 # jump if relavent bit is set in the CR
-            else:
-                BO = 4  # jump if relavent bit is NOT set in the CR
-            self.asm.bcctr(BO, loc.bit)
-        else:
-            self.asm.cmpwi(0, gv_condition.load(self), 0)
-            if if_true:
-                self.asm.bnectr()
-            else:
-                self.asm.beqctr()
+        self.insns.append(
+            Insn_GPR__IMM(RPPCAssembler.load_word,
+                          gv, [IntConst(targetbuilder.asm.mc.tell())]))
+        gv2 = self.newvar()
+        self.insns.append(
+            MTCTR(gv2, [gv]))
+        self.insns.append(
+            Jump(gv_condition, gv2, if_true))
         return targetbuilder
 
     def jump_if_false(self, gv_condition):
@@ -373,7 +524,6 @@
 
     def newgraph(self, sigtoken):
         numargs = sigtoken          # for now
-        initialstackdepth = numargs+1
         builder = self.openbuilder(None)
         entrypoint = builder.asm.mc.tell()
         inputargs_gv = builder._write_prologue(sigtoken)



More information about the Pypy-commit mailing list