Author: Carl Friedrich Bolz-Tereick <[email protected]>
Branch: regalloc-playground
Changeset: r92298:ffdf4c1bc430
Date: 2017-08-26 09:43 +0200
http://bitbucket.org/pypy/pypy/changeset/ffdf4c1bc430/
Log: improve interaction of fixed_register, try_use_same_register and
force_result_in_reg
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
@@ -63,6 +63,7 @@
@specialize.arg(1)
def foreach(self, function, arg):
+ # XXX unused?
node = self.master_node
while node is not None:
function(arg, node.val)
@@ -362,6 +363,9 @@
returns allocated register or None, if not possible.
"""
self._check_type(v)
+ if isinstance(v, TempVar):
+ self.longevity[v] = Lifetime(self.position, self.position)
+ # YYY all subtly similar code
assert not isinstance(v, Const)
if selected_reg is not None:
res = self.reg_bindings.get(v, None)
@@ -553,6 +557,7 @@
reg = self.reg_bindings[from_v]
del self.reg_bindings[from_v]
self.reg_bindings[to_v] = reg
+ return reg
def _move_variable_away(self, v, prev_loc):
# YYY here we should not move it to another reg, if all uses are in
@@ -573,27 +578,35 @@
self._check_type(result_v)
self._check_type(v)
if isinstance(v, Const):
- loc = self.force_allocate_reg(result_v, forbidden_vars)
- self.assembler.regalloc_mov(self.convert_to_imm(v), loc)
- return loc
+ result_loc = self.force_allocate_reg(result_v, forbidden_vars)
+ self.assembler.regalloc_mov(self.convert_to_imm(v), result_loc)
+ return result_loc
if v not in self.reg_bindings:
# v not in a register. allocate one for result_v and move v there
- prev_loc = self.frame_manager.loc(v)
- loc = self.force_allocate_reg(result_v, forbidden_vars)
- self.assembler.regalloc_mov(prev_loc, loc)
- return loc
+ v_loc = self.frame_manager.loc(v)
+ result_loc = self.force_allocate_reg(result_v, forbidden_vars)
+ self.assembler.regalloc_mov(v_loc, result_loc)
+ return result_loc
if self.longevity[v].last_usage > self.position:
- # we need to find a new place for variable v and
- # store result in the same place
- loc = self.reg_bindings[v]
- del self.reg_bindings[v]
- if self.frame_manager.get(v) is None:
- self._move_variable_away(v, loc)
- self.reg_bindings[result_v] = loc
+ # v keeps on being live. if there is a free register, we need a
+ # move anyway, so we can use force_allocate_reg on result_v to make
+ # sure any fixed registers are used
+ if self.free_regs:
+ v_loc = self.reg_bindings[v]
+ result_loc = self.force_allocate_reg(result_v, forbidden_vars)
+ self.assembler.regalloc_mov(v_loc, result_loc)
+ return result_loc
+ else:
+ result_loc = self.reg_bindings[v]
+ if self.frame_manager.get(v) is None:
+ v_loc = self.frame_manager.loc(v)
+ self.assembler.regalloc_mov(result_loc, v_loc)
+ del self.reg_bindings[v]
+ self.reg_bindings[result_v] = result_loc
+ return result_loc
else:
- self._reallocate_from_to(v, result_v)
- loc = self.reg_bindings[result_v]
- return loc
+ result_loc = self._reallocate_from_to(v, result_v)
+ return result_loc
def _sync_var(self, v):
self.assembler.num_spills += 1
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
@@ -863,13 +863,13 @@
# use it's own class since there are so many cases
def test_force_result_in_reg_1(self):
+ # var in reg, dies
b0, b1 = newboxes(0, 0)
longevity = {b0: Lifetime(0, 1), b1: Lifetime(1, 3)}
fm = TFrameManager()
asm = MockAsm()
rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
rm.next_instruction()
- # first path, var is already in reg and dies
loc0 = rm.force_allocate_reg(b0)
rm._check_invariants()
rm.next_instruction()
@@ -879,6 +879,7 @@
rm._check_invariants()
def test_force_result_in_reg_2(self):
+ # var in reg, survives
b0, b1 = newboxes(0, 0)
longevity = {b0: Lifetime(0, 2), b1: Lifetime(1, 3)}
fm = TFrameManager()
@@ -889,12 +890,13 @@
rm._check_invariants()
rm.next_instruction()
loc = rm.force_result_in_reg(b1, b0)
- assert loc is loc0
- assert rm.loc(b0) is not loc0
+ assert loc is not loc0
+ assert rm.loc(b0) is loc0
assert len(asm.moves) == 1
rm._check_invariants()
def test_force_result_in_reg_3(self):
+ # var in reg, survives, no free registers
b0, b1, b2, b3, b4 = newboxes(0, 0, 0, 0, 0)
longevity = {b0: Lifetime(0, 2), b1: Lifetime(0, 2),
b3: Lifetime(0, 2), b2: Lifetime(0, 2),
@@ -929,6 +931,7 @@
assert len(asm.moves) == 1
def test_force_result_in_reg_const(self):
+ # const
boxes, longevity = boxes_and_longevity(2)
fm = TFrameManager()
asm = MockAsm()
@@ -939,6 +942,50 @@
rm.force_result_in_reg(boxes[0], c)
rm._check_invariants()
+ # some tests where the result is supposed to go in a fixed register
+
+ def test_force_result_in_reg_fixed_reg_1(self):
+ # var in reg, dies
+ b0, b1 = newboxes(0, 0)
+ longevity = LifetimeManager({b0: Lifetime(0, 1), b1: Lifetime(1, 3)})
+ longevity.try_use_same_register(b0, b1)
+ longevity.fixed_register(1, r1, b1)
+ fm = TFrameManager()
+ asm = MockAsm()
+ rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
+ rm.next_instruction()
+ loc0 = rm.force_allocate_reg(b0)
+ rm._check_invariants()
+ rm.next_instruction()
+ loc = rm.force_result_in_reg(b1, b0)
+ assert loc is loc0
+ assert loc is r1
+ assert len(asm.moves) == 0
+ rm._check_invariants()
+
+ def test_force_result_in_reg_fixed_reg_2(self):
+ # var in reg, survives
+ b0, b1 = newboxes(0, 0)
+ longevity = LifetimeManager({b0: Lifetime(0, 2), b1: Lifetime(1, 3)})
+
+ # has no effect, lifetimes overlap
+ longevity.try_use_same_register(b0, b1)
+ longevity.fixed_register(1, r1, b1)
+
+ fm = TFrameManager()
+ asm = MockAsm()
+ rm = RegisterManager(longevity, frame_manager=fm, assembler=asm)
+ rm.next_instruction()
+ loc0 = rm.force_allocate_reg(b0)
+ rm._check_invariants()
+ rm.next_instruction()
+ loc = rm.force_result_in_reg(b1, b0)
+ assert loc is not loc0
+ assert rm.loc(b0) is loc0
+ assert loc is r1
+ assert len(asm.moves) == 1
+ rm._check_invariants()
+
# _____________________________________________________
# tests that assign registers in a mocked way for a fake CPU
@@ -1246,6 +1293,7 @@
('guard_true', r8, [])
]
+ @py.test.mark.skip("messy - later")
def test_coalescing_first_var_already_in_different_reg(self):
ops = '''
[i0]
@@ -1283,8 +1331,8 @@
('guard_false', r0, [fp0, r7, r4, r5, r6])
]
+ @py.test.mark.skip("messy - later")
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]
diff --git a/rpython/jit/backend/x86/regalloc.py
b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -508,6 +508,7 @@
# For symmetrical operations, if 'y' is already in a register
# and won't be used after the current operation finishes,
# then swap the role of 'x' and 'y'
+ # XXX only do that if x is *not* in a register
if (symm and isinstance(argloc, RegLoc) and
self.rm.longevity[y].last_usage == self.rm.position):
x, y = y, x
diff --git a/rpython/jit/backend/x86/vector_ext.py
b/rpython/jit/backend/x86/vector_ext.py
--- a/rpython/jit/backend/x86/vector_ext.py
+++ b/rpython/jit/backend/x86/vector_ext.py
@@ -695,7 +695,7 @@
if not candidate_to_spill:
raise NoVariableToSpill
reg = xrm.reg_bindings[candidate_to_spill]
- xrm._spill_var(candidate_to_spill, forbidden_vars, None)
+ xrm._spill_var(forbidden_vars, reg)
xrm.free_regs.append(reg)
loc = xrm.free_regs.pop()
self.assembler.mov(selected_reg, loc)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit