Author: Richard Plangger <planri...@gmail.com>
Branch: fix-longevity
Changeset: r82507:5678f7fbd0b3
Date: 2016-02-25 15:49 +0100
http://bitbucket.org/pypy/pypy/changeset/5678f7fbd0b3/

Log:    (remi, plan_rich) forward with argument allocation for calls

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
@@ -276,6 +276,7 @@
     save_around_call_regs = []
     frame_reg             = None
 
+    # TODO would be good to keep free_caller_regs sorted (according to the ABI)
     free_callee_regs      = []
     free_caller_regs      = []
     is_callee_lookup      = None
@@ -300,6 +301,16 @@
         else:
             target_pool = self.free_caller_regs
             second_pool = self.free_callee_regs
+        if target_reg is not None:
+            # try to allocate this regsiter to a special register
+            for i,reg in enumerate(target_pool):
+                if reg is target_reg:
+                    del target_pool[i]
+                    return reg
+            for i,reg in enumerate(second_pool):
+                if reg is target_reg:
+                    del second_pool[i]
+                    return reg
         if target_pool:
             return target_pool.pop()
         if second_pool:
@@ -309,12 +320,25 @@
     def has_free_registers(self):
         return self.free_callee_regs or self.free_caller_regs
 
+    def get_abi_param_register(self, i):
+        raise NotImplementedError
+
     def allocate_new(self, var):
         if self.live_ranges.exists(var) and 
self.live_ranges.survives_call(var, self.position):
             # we want a callee save register
             return self.get_free_register(var, callee=True)
         else:
-            return self.get_free_register(var, callee=False, target_reg=None)
+            # if survives_call indicates that the live range ends at the call 
site
+            # we would like to allocate the register directly to the parameter
+            # register
+
+            index = self.live_ranges.get_call_argument_index(var, 
self.position)
+            target_reg = None
+            if index != -1:
+                target_reg = self.get_abi_param_register(index)
+
+
+            return self.get_free_register(var, callee=False, 
target_reg=target_reg)
 
     def update_free_registers(self, regs_in_use):
         self._reinit_free_regs()
@@ -641,13 +665,20 @@
         if self.live_ranges.last_use(v) > 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 or self.has_free_registers():
-                self._move_variable_away(v, loc)
+            # only spill variable is allowed to reassign a new register to a 
live range
+            result_loc = self.force_allocate_reg(result_v, 
forbidden_vars=forbidden_vars)
+            self.assembler.regalloc_mov(loc, result_loc)
+            loc = result_loc
 
-            self.reg_bindings[result_v] = loc
+            #del self.reg_bindings[v]
+            #if self.frame_manager.get(v) is None or self.has_free_registers():
+            #    self._move_variable_away(v, loc)
+
+            #self.reg_bindings[result_v] = loc
         else:
+            import pdb; pdb.set_trace()
             self._reallocate_from_to(v, result_v)
             loc = self.reg_bindings[result_v]
         return loc
@@ -756,10 +787,11 @@
 
 
 class LiveRanges(object):
-    def __init__(self, longevity, last_real_usage, dist_to_next_call):
+    def __init__(self, longevity, last_real_usage, dist_to_next_call, 
operations):
         self.longevity = longevity
         self.last_real_usage = last_real_usage
         self.dist_to_next_call = dist_to_next_call
+        self.operations = operations
 
     def exists(self, var):
         return var in self.longevity
@@ -770,6 +802,14 @@
     def new_live_range(self, var, start, end):
         self.longevity[var] = (start, end)
 
+    def get_call_argument_index(self, var, pos):
+        assert self.dist_to_next_call[pos] >= 0
+        op = self.operations[pos + self.dist_to_next_call[pos]]
+        for i,arg in enumerate(op.getarglist()):
+            if arg is var:
+                return i-1 # first parameter is the functionh
+        return -1
+
     def survives_call(self, var, position):
         if not we_are_translated():
             if self.dist_to_next_call is None:
@@ -777,8 +817,8 @@
         start, end = self.longevity[var]
         dist = self.dist_to_next_call[position]
         assert end >= position
-        if end-position <= dist:
-            # it is 'live during a call' if it live range ends after the call
+        if end-position < dist:
+            # the variable is used after the call instr
             return True
         return False
 
@@ -796,6 +836,9 @@
     last_call_pos = -1
     for i in range(len(operations)-1, -1, -1):
         op = operations[i]
+        if op.is_call():
+            last_call_pos = i
+        dist_to_next_call[i] = last_call_pos - i
         if op.type != 'v':
             if op not in last_used and op.has_no_side_effect():
                 continue
@@ -816,9 +859,6 @@
                 assert not isinstance(arg, Const)
                 if arg not in last_used:
                     last_used[arg] = i
-        if op.is_call():
-            last_call_pos = i
-        dist_to_next_call[i] = last_call_pos - i
     #
     longevity = {}
     for i, arg in enumerate(operations):
@@ -846,7 +886,9 @@
                     assert arg in produced
             produced[op] = None
 
-    return LiveRanges(longevity, last_real_usage, dist_to_next_call)
+    lr = LiveRanges(longevity, last_real_usage,
+                    dist_to_next_call, operations)
+    return lr
 
 def is_comparison_or_ovf_op(opnum):
     from rpython.jit.metainterp.resoperation import opclasses
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
@@ -196,12 +196,13 @@
         i2 = int_sub(i0,i1)
         call_n(p0, i1, descr=calldescr)
         i3 = int_mul(i2,i0)
+        guard_true(i3) []
         jump(p0,i2)
         """, namespace=self.namespace)
         i1 = ops.operations[0]
         i2 = ops.operations[1]
-        trace_alloc = TraceAllocation(ops, [eax, edx], [r8, r9, r10], [eax, 
r10], tt)
-        trace_alloc.run_allocation([r8,r9,edx])
+        trace_alloc = TraceAllocation(ops, [eax, edx, get_param(0)], [r8, r9, 
r12], [eax, r12], tt)
+        trace_alloc.run_allocation()
         # 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
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
@@ -58,7 +58,12 @@
     all_regs = [ecx, eax, edx, ebx, esi, edi, r8, r9, r10, r12, r13, r14, r15]
 
     no_lower_byte_regs = []
-    save_around_call_regs = [eax, ecx, edx, esi, edi, r8, r9, r10]
+    abi_param_regs = [edi, esi, ecx, r8, r9]
+    save_around_call_regs = abi_param_regs + [eax, edx, r10]
+
+    def get_abi_param_register(self, i):
+        assert i >= 0 and i < len(self.abi_param_regs)
+        return self.abi_param_regs[i]
 
 class X86XMMRegisterManager(RegisterManager):
     box_types = [FLOAT, INT] # yes INT!
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to