[pypy-commit] pypy regalloc-playground: use the regular spill heuristics to chose the variables to spill before a call
cfbolz
pypy.commits at gmail.com
Wed Aug 23 12:34:34 EDT 2017
Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: regalloc-playground
Changeset: r92233:f68f729a80cf
Date: 2017-08-23 18:33 +0200
http://bitbucket.org/pypy/pypy/changeset/f68f729a80cf/
Log: use the regular spill heuristics to chose the variables to spill
before a call
diff --git a/rpython/jit/backend/llsupport/regalloc.py b/rpython/jit/backend/llsupport/regalloc.py
--- a/rpython/jit/backend/llsupport/regalloc.py
+++ b/rpython/jit/backend/llsupport/regalloc.py
@@ -418,20 +418,24 @@
return loc
def _pick_variable_to_spill(self, v, forbidden_vars, selected_reg=None,
- need_lower_byte=False):
+ need_lower_byte=False, vars=None):
+ # YYY v is unused, remove
+
# try to spill a variable that has no further real usages, ie that only
# appears in failargs or in a jump
# if that doesn't exist, spill the variable that has a real_usage that
# is the furthest away from the current position
# YYY check for fixed variable usages
+ if vars is None:
+ vars = self.reg_bindings.keys()
cur_max_use_distance = -1
position = self.position
candidate = None
cur_max_age_failargs = -1
candidate_from_failargs = None
- for next in self.reg_bindings:
+ for next in vars:
reg = self.reg_bindings[next]
if next in forbidden_vars:
continue
@@ -696,46 +700,31 @@
else:
# this is a register like eax/rax, which needs either
# spilling or moving.
- move_or_spill.append((v, max_age))
+ move_or_spill.append(v)
if len(move_or_spill) > 0:
- while len(self.free_regs) > 0:
- # YYY here we need to use the new information to pick stuff
- new_reg = self.free_regs.pop()
- if new_reg in self.save_around_call_regs:
- new_free_regs.append(new_reg) # not this register...
- continue
- # This 'new_reg' is suitable for moving a candidate to.
- # Pick the one with the smallest max_age. (This
- # is one step of a naive sorting algo, slow in theory,
- # but the list should always be very small so it
- # doesn't matter.)
- best_i = 0
- smallest_max_age = move_or_spill[0][1]
- for i in range(1, len(move_or_spill)):
- max_age = move_or_spill[i][1]
- if max_age < smallest_max_age:
- best_i = i
- smallest_max_age = max_age
- v, max_age = move_or_spill.pop(best_i)
- # move from 'reg' to 'new_reg'
+ free_regs = [reg for reg in self.free_regs
+ if reg not in self.save_around_call_regs]
+ # chose which to spill using the usual spill heuristics
+ while len(move_or_spill) > len(free_regs):
+ v = self._pick_variable_to_spill(None, [], vars=move_or_spill)
+ self._bc_spill(v, new_free_regs)
+ move_or_spill.remove(v)
+ assert len(move_or_spill) <= len(free_regs)
+ for v in move_or_spill:
+ # search next good reg
+ new_reg = None
+ while True:
+ new_reg = self.free_regs.pop()
+ if new_reg in self.save_around_call_regs:
+ new_free_regs.append(new_reg) # not this register...
+ continue
+ break
+ assert new_reg is not None # must succeed
reg = self.reg_bindings[v]
- if not we_are_translated():
- if move_or_spill:
- assert max_age <= min([_a for _, _a in move_or_spill])
- assert reg in save_sublist
- assert reg in self.save_around_call_regs
- assert new_reg not in self.save_around_call_regs
self.assembler.regalloc_mov(reg, new_reg)
self.reg_bindings[v] = new_reg # change the binding
new_free_regs.append(reg)
- #
- if len(move_or_spill) == 0:
- break
- else:
- # no more free registers to move to, spill the rest
- for v, max_age in move_or_spill:
- self._bc_spill(v, new_free_regs)
# re-add registers in 'new_free_regs', but in reverse order,
# so that the last ones (added just above, from
diff --git a/rpython/jit/backend/llsupport/test/test_regalloc.py b/rpython/jit/backend/llsupport/test/test_regalloc.py
--- a/rpython/jit/backend/llsupport/test/test_regalloc.py
+++ b/rpython/jit/backend/llsupport/test/test_regalloc.py
@@ -617,6 +617,7 @@
assembler=asm)
for b in boxes[:-1]:
rm.force_allocate_reg(b)
+ rm.position = 0
rm.before_call()
assert len(rm.reg_bindings) == 2
assert fm.get_frame_depth() == 2
@@ -1236,3 +1237,35 @@
('guard_false', r0, [])
]
+ def test_call_spill_furthest_use(self):
+ # here, i2 should be spilled, because its use is farther away
+ ops = '''
+ [i0, i1, i2, i3, i4, i5, i6]
+ i8 = call_i(ConstClass(f2ptr), i0, i1, descr=f2_calldescr)
+ escape_i(i3)
+ escape_i(i2)
+ guard_false(i8) [i2, i3, i4, i5, i6]
+ '''
+ emitted = self.allocate(ops, [r1, r2, r0, r3, r4, r5, r6])
+ fp0 = FakeFramePos(0, INT)
+ assert emitted == [
+ ('move', fp0, r0),
+ ('move', r7, r3),
+ ('call_i', r0, [r1, r2]),
+ ('escape_i', r1, [r7]),
+ ('escape_i', r1, [fp0]),
+ ('guard_false', r0, [fp0, r7, r4, r5, r6])
+ ]
+
+ def test_call_spill(self):
+ py.test.skip("also messy")
+ # i0 dies, i1 is the argument, the other fight for caller-saved regs
+ # all_regs = [r0, r1, r2, r3, r4, r5, r6, r7]
+ # save_around_call_regs = [r0, r1, r2, r3]
+ ops = '''
+ [i0, i1, i2, i3, i4, i5, i6]
+ i8 = call_i(ConstClass(f2ptr), i1, i0, descr=f2_calldescr)
+ guard_false(i8) [i2, i3, i4, i5, i6]
+ '''
+ emitted = self.allocate(ops, [r5, r1, r0, r2, r3, r6, r7])
+ assert emitted == ["???"]
More information about the pypy-commit
mailing list