[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