[pypy-svn] r36443 - pypy/branch/i386-regalloc/pypy/jit/codegen/i386
arigo at codespeak.net
arigo at codespeak.net
Wed Jan 10 23:20:03 CET 2007
Author: arigo
Date: Wed Jan 10 23:19:58 2007
New Revision: 36443
Modified:
pypy/branch/i386-regalloc/pypy/jit/codegen/i386/rgenop.py
Log:
More work. Register allocator seems to be working, but wack wack wack.
Modified: pypy/branch/i386-regalloc/pypy/jit/codegen/i386/rgenop.py
==============================================================================
--- pypy/branch/i386-regalloc/pypy/jit/codegen/i386/rgenop.py (original)
+++ pypy/branch/i386-regalloc/pypy/jit/codegen/i386/rgenop.py Wed Jan 10 23:19:58 2007
@@ -21,9 +21,12 @@
def allocate_registers(self, allocator):
allocator.using(self.x)
def generate(self, allocator):
- operand = allocator.var2loc[self]
- allocator.load_operand(operand, self.x)
- self.emit(allocator.mc, operand)
+ try:
+ loc = allocator.var2loc[self]
+ except KeyError:
+ return # simple operation whose result is not used anyway
+ op = allocator.load_location_with(loc, self.x)
+ self.emit(allocator.mc, op)
class OpSameAs(Op1):
emit = staticmethod(lambda mc, x: None)
@@ -36,10 +39,13 @@
allocator.using(self.x)
allocator.using(self.y)
def generate(self, allocator):
- operand1 = allocator.var2loc[self]
- allocator.load_operand(operand1, self.x)
- operand2 = allocator.get_location(self.y)
- self.emit(allocator.mc, operand1, operand2)
+ try:
+ loc = allocator.var2loc[self]
+ except KeyError:
+ return # simple operation whose result is not used anyway
+ op1 = allocator.load_location_with(loc, self.x)
+ op2 = allocator.get_operand(self.y)
+ self.emit(allocator.mc, op1, op2)
class OpIntAdd(Op2):
opname = 'int_add'
@@ -126,113 +132,189 @@
OPCLASSES2 = setup_opclasses(Op2)
del setup_opclasses
+OPCLASSES1['int_is_true'] = None
+
+
+class OutOfRegisters(Exception):
+ pass
+
class RegAllocator(object):
AVAILABLE_REGS = [eax, ecx, edx, ebx, esi, edi]
- AVAILABLE_REGS_REV = AVAILABLE_REGS[:]
- AVAILABLE_REGS_REV.reverse()
- def __init__(self, operations, input_var2loc):
- self.operations = operations
- self.input_var2loc = input_var2loc
- self.var2loc = {}
+ # 'gv' -- GenVars, used as arguments and results of operations
+ #
+ # 'loc' -- location, a small integer that represents an abstract
+ # register number
+ #
+ # 'operand' -- a concrete machine code operand, which can be a
+ # register (ri386.eax, etc.) or a stack memory operand
- def set_final(self, final_vars_gv, final_locs):
- used = {}
- for i in range(len(final_vars_gv)):
- v = final_vars_gv[i]
- loc = final_locs[i]
- if v.is_const or v in self.var2loc or (
- self.input_var2loc.get(v, loc) != loc):
- v = OpSameAs(v)
- self.operations.append(v)
- self.var2loc[v] = loc
- used[loc] = True
- self.available_regs = [reg for reg in self.AVAILABLE_REGS_REV
- if reg not in used]
+ def __init__(self):
+ self.nextloc = 0
+ self.var2loc = {}
+ self.available_locs = []
+ self.force_loc2operand = {}
+ self.force_operand2loc = {}
+ self.initial_moves = []
+
+ def set_final(self, final_vars_gv):
+ for v in final_vars_gv:
+ if not v.is_const and v not in self.var2loc:
+ self.var2loc[v] = self.nextloc
+ self.nextloc += 1
def creating(self, v):
- loc = self.var2loc.get(v, None)
- if isinstance(loc, REG):
- self.available_regs.append(loc)
+ try:
+ loc = self.var2loc[v]
+ except KeyError:
+ pass
+ else:
+ self.available_locs.append(loc) # now available again for reuse
def using(self, v):
if not v.is_const and v not in self.var2loc:
try:
- loc = self.input_var2loc[v]
+ loc = self.available_locs.pop()
+ except IndexError:
+ loc = self.nextloc
+ self.nextloc += 1
+ self.var2loc[v] = loc
+
+ def allocate_locations(self, operations):
+ # assign locations to gvars
+ self.operations = operations
+ for i in range(len(operations)-1, -1, -1):
+ v = operations[i]
+ self.creating(v)
+ v.allocate_registers(self)
+
+ def force_var_operands(self, force_vars, force_operands, at_start):
+ force_loc2operand = self.force_loc2operand
+ force_operand2loc = self.force_operand2loc
+ for i in range(len(force_vars)):
+ v = force_vars[i]
+ try:
+ loc = self.var2loc[v]
except KeyError:
+ pass
+ else:
+ operand = force_operands[i]
+ if loc in force_loc2operand or operand in force_operand2loc:
+ if not at_start: raise NotImplementedError
+ self.initial_moves.append((loc, operand))
+ else:
+ force_loc2operand[loc] = operand
+ force_operand2loc[operand] = loc
+
+ def allocate_registers(self):
+ # assign registers to locations that don't have one already
+ force_loc2operand = self.force_loc2operand
+ operands = []
+ seen_regs = 0
+ for op in force_loc2operand.values():
+ if isinstance(op, REG):
+ seen_regs |= 1 << op.op
+ i = 0
+ for loc in range(self.nextloc):
+ try:
+ operand = force_loc2operand[loc]
+ except KeyError:
+ # grab the next free register
+ while seen_regs & (1 << i):
+ i += 1
try:
- loc = self.available_regs.pop()
+ operand = RegAllocator.AVAILABLE_REGS[i]
+ i += 1
except IndexError:
- #loc = ...
- raise NotImplementedError
- self.var2loc[v] = loc
+ raise OutOfRegisters
+ operands.append(operand)
+ self.operands = operands
- def get_location(self, gv_source):
+ def get_operand(self, gv_source):
if isinstance(gv_source, IntConst):
return imm(gv_source.value)
else:
- return self.var2loc[gv_source]
+ loc = self.var2loc[gv_source]
+ return self.operands[loc]
- def load_operand(self, operand, gv_source):
- srcloc = self.get_location(gv_source)
- if srcloc != operand:
- self.mc.MOV(operand, srcloc)
+ def load_location_with(self, loc, gv_source):
+ dstop = self.operands[loc]
+ srcop = self.get_operand(gv_source)
+ if srcop != dstop:
+ self.mc.MOV(dstop, srcop)
+ return dstop
+
+ def generate_initial_moves(self):
+ # XXX naive algo for now
+ initial_moves = self.initial_moves
+ for loc, srcoperand in initial_moves:
+ self.mc.PUSH(srcoperand)
+ initial_moves.reverse()
+ for loc, srcoperand in initial_moves:
+ self.mc.POP(self.operands[loc])
class Builder(GenBuilder):
coming_from = 0
- def __init__(self, rgenop, input_vars_gv, input_var2loc):
+ def __init__(self, rgenop, inputargs_gv, inputoperands):
self.rgenop = rgenop
- self.input_vars_gv = input_vars_gv
- self.input_var2loc = input_var2loc
+ self.inputargs_gv = inputargs_gv
+ self.inputoperands = inputoperands
def start_writing(self):
self.operations = []
- def generate_block_code(self, final_vars_gv, final_locs):
- operations = self.operations
- allocator = RegAllocator(operations, self.input_var2loc)
- allocator.set_final(final_vars_gv, final_locs)
- for i in range(len(operations)-1, -1, -1):
- v = operations[i]
- allocator.creating(v)
- v.allocate_registers(allocator)
+ def generate_block_code(self, final_vars_gv, force_vars=[],
+ force_operands=[]):
+ allocator = RegAllocator()
+ allocator.set_final(final_vars_gv)
+ allocator.allocate_locations(self.operations)
+ allocator.force_var_operands(force_vars, force_operands,
+ at_start=False)
+ #import pdb; pdb.set_trace()
+ allocator.force_var_operands(self.inputargs_gv, self.inputoperands,
+ at_start=True)
+ allocator.allocate_registers()
mc = self.start_mc()
allocator.mc = mc
- for op in operations:
+ allocator.generate_initial_moves()
+ for op in self.operations:
op.generate(allocator)
self.operations = None
+ self.inputargs_gv = [GenVar() for v in final_vars_gv]
+ self.inputoperands = [allocator.operands[allocator.var2loc[v]]
+ for v in final_vars_gv]
return mc
def enter_next_block(self, kinds, args_gv):
- locs = {}
- seen_regs = 0
- for v in args_gv:
- loc = self.input_var2loc.get(v, None)
- locs[v] = loc
- if isinstance(loc, REG):
- i = loc.op
- seen_regs |= 1 << i
- i = 0
- final_locs = []
- final_var2loc = {}
- for v in args_gv:
- loc = locs[v]
- if loc is None:
- while seen_regs & (1 << i):
- i += 1
- assert i < len(RegAllocator.AVAILABLE_REGS) # XXX
- loc = RegAllocator.AVAILABLE_REGS[i]
- i += 1
- final_locs.append(loc)
- final_var2loc[v] = loc
- mc = self.generate_block_code(args_gv, final_locs)
+## locs = {}
+## seen_regs = 0
+## for v in args_gv:
+## loc = self.input_var2loc.get(v, None)
+## locs[v] = loc
+## if isinstance(loc, REG):
+## i = loc.op
+## seen_regs |= 1 << i
+## i = 0
+## final_locs = []
+## final_var2loc = {}
+## for v in args_gv:
+## loc = locs[v]
+## if loc is None:
+## while seen_regs & (1 << i):
+## i += 1
+## assert i < len(RegAllocator.AVAILABLE_REGS) # XXX
+## loc = RegAllocator.AVAILABLE_REGS[i]
+## i += 1
+## final_locs.append(loc)
+## final_var2loc[v] = loc
+
+ mc = self.generate_block_code(args_gv)
+ args_gv[:] = self.inputargs_gv
self.set_coming_from(mc)
self.rgenop.close_mc(mc)
- self.input_args_gv = args_gv
- self.input_var2loc = final_var2loc
self.start_writing()
def set_coming_from(self, mc, insn=I386CodeBuilder.JMP):
@@ -255,7 +337,7 @@
return mc
def finish_and_return(self, sigtoken, gv_returnvar):
- mc = self.generate_block_code([gv_returnvar], [eax])
+ mc = self.generate_block_code([gv_returnvar], [gv_returnvar], [eax])
# --- epilogue ---
mc.POP(edi)
mc.POP(esi)
@@ -271,6 +353,8 @@
@specialize.arg(1)
def genop1(self, opname, gv_arg):
cls = OPCLASSES1[opname]
+ if cls is None: # identity
+ return gv_arg
op = cls(gv_arg)
self.operations.append(op)
return op
@@ -329,13 +413,15 @@
# ----------------
numargs = sigtoken # for now
inputargs_gv = []
- input_var2loc = {}
+ inputoperands = []
for i in range(numargs):
- v = GenVar()
- inputargs_gv.append(v)
- input_var2loc[v] = mem(ebp, WORD * (2+i))
- builder = Builder(self, inputargs_gv, input_var2loc)
+ inputargs_gv.append(GenVar())
+ inputoperands.append(mem(ebp, WORD * (2+i)))
+ builder = Builder(self, inputargs_gv, inputoperands)
builder.start_writing()
+ #ops = [OpSameAs(v) for v in inputargs_gv]
+ #builder.operations.extend(ops)
+ #inputargs_gv = ops
return builder, IntConst(entrypoint), inputargs_gv
## def replay(self, label, kinds):
More information about the Pypy-commit
mailing list