Author: Richard Plangger <planri...@gmail.com>
Branch: fix-longevity
Changeset: r82449:e1c902c90c70
Date: 2016-02-23 16:55 +0100
http://bitbucket.org/pypy/pypy/changeset/e1c902c90c70/

Log:    (remi, plan_rich) a new test to check that liveranges containing
        calls will prefer callee_saved registers

diff --git a/rpython/jit/backend/llsupport/test/test_regalloc_call.py 
b/rpython/jit/backend/llsupport/test/test_regalloc_call.py
--- a/rpython/jit/backend/llsupport/test/test_regalloc_call.py
+++ b/rpython/jit/backend/llsupport/test/test_regalloc_call.py
@@ -23,6 +23,11 @@
 
 CPU = getcpuclass()
 
+def get_param(i):
+    # x86 specific!!
+    ABI_PARAMS_REGISTERS = [edi, esi, edx, ecx, r8, r9]
+    return ABI_PARAMS_REGISTERS[i]
+
 def parse_loop(text, namespace={}):
     ops = parse(text, namespace=namespace)
     tt = None
@@ -95,31 +100,49 @@
         self.trace = trace
         self.regalloc = FakeRegAlloc(self, caller_saved, callee_saved)
         self.initial_binding = { var: reg for var, reg in zip(trace.inputargs, 
binding) }
+        tt._x86_arglocs = binding
+
+    def run_allocation(self, free_regs=None):
+        inputargs = self.trace.inputargs
+        operations = self.trace.operations
         looptoken = FakeLoopToken()
         gcrefs = []
-        tt._x86_arglocs = binding
 
+        # force naming of the variables!
         AbstractValue._repr_memo = CountingDict()
-        for op in trace.operations:
+        for op in operations:
             for arg in op.getarglist():
                 arg.repr_short(arg._repr_memo)
-                pass
             op.repr_short(op._repr_memo)
-        self.regalloc.prepare_loop(self.trace.inputargs, 
self.trace.operations, looptoken, gcrefs)
 
-        for var, reg in zip(trace.inputargs, binding):
+        # setup the register allocator
+        self.regalloc.prepare_loop(inputargs, operations, looptoken, gcrefs)
+
+        # setup the initial binding the test requires
+        for var, reg in self.initial_binding.items():
             self.regalloc.rm.reg_bindings[var] = reg
+
+        # instead of having all machine registers, we want only to provide some
         fr = self.regalloc.free_regs
-        self.regalloc.rm.free_regs = [reg for reg in fr if reg not in binding]
-
+        if free_regs is None:
+            self.regalloc.rm.free_regs = [reg for reg in fr if reg not in 
binding]
+        else:
+            self.regalloc.rm.free_regs = free_regs
         self.regalloc.rm.all_regs = self.regalloc.all_regs
         self.regalloc.rm.save_around_call_regs = self.regalloc.caller_saved
 
-        self.regalloc.walk_operations(trace.inputargs, trace.operations)
+        # invoke the allocator!
+        self.regalloc.walk_operations(inputargs, operations)
 
     def initial_register(self, var):
         return self.initial_binding.get(var, None)
 
+    def is_caller_saved(self, var):
+        return self.initial_register(var) in self.regalloc.caller_saved
+
+    def is_callee_saved(self, var):
+        return self.initial_register(var) in self.regalloc.callee_saved
+
     def move_count(self):
         return len(self.regalloc.assembler.moves)
 
@@ -153,11 +176,13 @@
         i3 = int_add(i2,i1)
         jump(p0,i2)
         """)
+        i2 = ops.operations[0]
         trace_alloc = TraceAllocation(ops, [eax, edx], [r8, r9], [eax, edx], 
tt)
-        i2 = trace_alloc.initial_register('i2')
+        trace_alloc.run_allocation()
+        i2 = trace_alloc.initial_register(i2)
         assert i2 == edx
 
-    def test_2allocate_register_into_jump_register2(self):
+    def test_single_move(self):
         tt, ops = parse_loop("""
         [p0,i0]
         i1 = int_add(i0,i0)
@@ -165,27 +190,29 @@
         guard_true(i2) []
         jump(p0,i1)
         """)
-        i1 = ops.operations[0]
-        i2 = ops.operations[1]
         trace_alloc = TraceAllocation(ops, [eax, edx], [r8, r9], [eax, edx], 
tt)
-        assert trace_alloc.initial_register(i1) == edx
-        assert trace_alloc.initial_register(i2) != edx
+        trace_alloc.run_allocation()
         assert trace_alloc.move_count() == 1
 
-    def test_call_allocate_first_param_to_callee(self):
+    def test_prefer_callee_saved_register(self):
         tt, ops = parse_loop("""
         [p0,i0]
         i1 = int_add(i0,i0)
-        i2 = int_add(i0,i1)
+        i2 = int_sub(i0,i1)
         call_n(p0, i1, descr=calldescr)
-        guard_true(i2) []
-        jump(p0,i1)
+        i3 = int_mul(i2,i0)
+        jump(p0,i2)
         """, namespace=self.namespace)
         i1 = ops.operations[0]
         i2 = ops.operations[1]
-        trace_alloc = TraceAllocation(ops, [eax, edx], [r8, r9], [eax, edx], 
tt)
-        assert trace_alloc.initial_register(i1) == edx
-        assert trace_alloc.initial_register(i2) != edx
+        trace_alloc = TraceAllocation(ops, [eax, edx], [r8, r9, r10], [eax, 
r10], tt)
+        trace_alloc.run_allocation([r8,r9,edx])
+        # we force the allocation to immediately take the first call parameter 
register
+        # the new regalloc will not shuffle register binding around (other 
than spilling)
+        # in the best case this will reduce a lot of movement
+        assert trace_alloc.initial_register(i1) == get_param(0)
+        assert trace_alloc.is_caller_saved(i1)
+        assert trace_alloc.is_callee_saved(i2)
         assert trace_alloc.move_count() == 1
 
     def test_call_allocate_first_param_to_callee2(self):
@@ -204,6 +231,7 @@
         i1 = ops.operations[0]
         i2 = ops.operations[1]
         trace_alloc = TraceAllocation(ops, [eax, edx], [r8, r9], [eax, edx], 
tt)
+        trace_alloc.run_allocation()
         assert trace_alloc.initial_register(i1) == edx
         assert trace_alloc.initial_register(i2) != edx
         assert trace_alloc.move_count() == 1
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to