[pypy-commit] pypy s390x-backend: saving f8 through f15 before entering the jit and restoring it before exiting it. (ABI demands this)

plan_rich pypy.commits at gmail.com
Wed Feb 10 06:44:43 EST 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: s390x-backend
Changeset: r82140:6cf6a1b5353a
Date: 2016-02-10 12:43 +0100
http://bitbucket.org/pypy/pypy/changeset/6cf6a1b5353a/

Log:	saving f8 through f15 before entering the jit and restoring it
	before exiting it. (ABI demands this)

diff --git a/rpython/jit/backend/zarch/arch.py b/rpython/jit/backend/zarch/arch.py
--- a/rpython/jit/backend/zarch/arch.py
+++ b/rpython/jit/backend/zarch/arch.py
@@ -83,3 +83,9 @@
 
 JUMPABS_TARGET_ADDR__POOL_OFFSET = 0
 JUMPABS_POOL_ADDR_POOL_OFFSET = 8
+
+# r8 through r15 are saved registers (= non volatile)
+# thus when entering the jit, we do not know if those
+# are overwritten in the jit. save them using some extra
+# stack space!
+JIT_ENTER_EXTRA_STACK_SPACE = 8*8
diff --git a/rpython/jit/backend/zarch/assembler.py b/rpython/jit/backend/zarch/assembler.py
--- a/rpython/jit/backend/zarch/assembler.py
+++ b/rpython/jit/backend/zarch/assembler.py
@@ -17,7 +17,7 @@
         STD_FRAME_SIZE_IN_BYTES, THREADLOCAL_ADDR_OFFSET,
         RECOVERY_GCMAP_POOL_OFFSET, RECOVERY_TARGET_POOL_OFFSET,
         JUMPABS_TARGET_ADDR__POOL_OFFSET, JUMPABS_POOL_ADDR_POOL_OFFSET,
-        THREADLOCAL_ON_ENTER_JIT)
+        THREADLOCAL_ON_ENTER_JIT, JIT_ENTER_EXTRA_STACK_SPACE)
 from rpython.jit.backend.zarch.opassembler import OpAssembler
 from rpython.jit.backend.zarch.regalloc import Regalloc
 from rpython.jit.codewriter.effectinfo import EffectInfo
@@ -50,6 +50,7 @@
         self.gcrootmap_retaddr_forced = 0
         self.failure_recovery_code = [0, 0, 0, 0]
         self.wb_slowpath = [0,0,0,0,0]
+        self.pool = None
 
     def setup(self, looptoken):
         BaseAssembler.setup(self, looptoken)
@@ -57,7 +58,8 @@
         if we_are_translated():
             self.debug = False
         self.current_clt = looptoken.compiled_loop_token
-        self.mc = InstrBuilder()
+        self.pool = LiteralPool()
+        self.mc = InstrBuilder(self.pool)
         self.pending_guard_tokens = []
         self.pending_guard_tokens_recovered = 0
         #assert self.datablockwrapper is None --- but obscure case
@@ -68,7 +70,6 @@
         self.mc.datablockwrapper = self.datablockwrapper
         self.target_tokens_currently_compiling = {}
         self.frame_depth_to_patch = []
-        self.pool = LiteralPool()
 
     def teardown(self):
         self.pending_guard_tokens = None
@@ -91,7 +92,7 @@
         self.mc.BCR_rr(0xf, register.value)
 
     def _build_failure_recovery(self, exc, withfloats=False):
-        mc = InstrBuilder()
+        mc = InstrBuilder(self.pool)
         self.mc = mc
         # fill in the jf_descr and jf_gcmap fields of the frame according
         # to which failure we are resuming from.  These are set before
@@ -202,6 +203,7 @@
             mc.LAY(r.SP, l.addr(-extra_stack_size, r.SP))
             mc.STMG(r.r10, r.r12, l.addr(off, r.SP))
             mc.STG(r.r2, l.addr(off+3*WORD, r.SP))
+            # OK to use STD, because offset is not negative
             mc.STD(r.f0, l.addr(off+4*WORD, r.SP))
             saved_regs = None
             saved_fp_regs = None
@@ -1008,14 +1010,22 @@
 
     def _call_header(self):
         # Build a new stackframe of size STD_FRAME_SIZE_IN_BYTES
-        self.mc.STMG(r.r6, r.r15, l.addr(6*WORD, r.SP))
+        fpoff = JIT_ENTER_EXTRA_STACK_SPACE
+        self.mc.STMG(r.r6, r.r15, l.addr(-fpoff+6*WORD, r.SP))
         self.mc.LARL(r.POOL, l.halfword(self.pool.pool_start - self.mc.get_relative_pos()))
+        # f8 through f15 are saved registers (= non volatile)
+        # TODO it would be good to detect if any float is used in the loop
+        # and to skip this push/pop whenever no float operation occurs
+        for i,reg in enumerate(range(8,16)):
+            off = -fpoff + STD_FRAME_SIZE_IN_BYTES
+            assert off > 0
+            self.mc.STD_rx(reg, l.addr(off + i*8, r.SP))
 
         # save r3, the second argument, to the thread local position
         self.mc.STG(r.r3, l.addr(THREADLOCAL_ON_ENTER_JIT, r.SP))
 
-        # push a standard frame for any call
-        self.mc.push_std_frame()
+        # push a standard frame for any within the jit trace
+        self.mc.push_std_frame(fpoff)
 
         # move the first argument to SPP: the jitframe object
         self.mc.LGR(r.SPP, r.r2)
@@ -1060,8 +1070,13 @@
         if gcrootmap and gcrootmap.is_shadow_stack:
             self._call_footer_shadowstack(gcrootmap)
 
+        size = STD_FRAME_SIZE_IN_BYTES
+        # f8 through f15 are saved registers (= non volatile)
+        # TODO it would be good to detect if any float is used in the loop
+        # and to skip this push/pop whenever no float operation occurs
+        for i,reg in enumerate(range(8,16)):
+            self.mc.LD_rx(reg, l.addr(size + size + i*8, r.SP))
         # restore registers r6-r15
-        size = STD_FRAME_SIZE_IN_BYTES
         self.mc.LMG(r.r6, r.r15, l.addr(size+6*WORD, r.SP))
         self.jmpto(r.r14)
 
diff --git a/rpython/jit/backend/zarch/codebuilder.py b/rpython/jit/backend/zarch/codebuilder.py
--- a/rpython/jit/backend/zarch/codebuilder.py
+++ b/rpython/jit/backend/zarch/codebuilder.py
@@ -69,9 +69,10 @@
 
     RAW_CALL_REG = r.r14
 
-    def __init__(self):
+    def __init__(self, pool=None):
         AbstractZARCHBuilder.__init__(self)
         self.init_block_builder()
+        self.pool = pool
         #
         # ResOperation --> offset in the assembly.
         # ops_offset[None] represents the beginning of the code after the last op
@@ -173,6 +174,9 @@
         elif -2**31 <= word <= 2**31-1:
             self.LGFI(dest_reg, l.imm(word))
         else:
+            if self.pool and self.pool.contains_constant(word):
+                self.LG(dest_reg, l.pool(self.pool.get_direct_offset(word)))
+                return
             # this is not put into the constant pool, because it
             # is an immediate value that cannot easily be forseen
             self.IILF(dest_reg, l.imm(word & 0xFFFFffff))
diff --git a/rpython/jit/backend/zarch/pool.py b/rpython/jit/backend/zarch/pool.py
--- a/rpython/jit/backend/zarch/pool.py
+++ b/rpython/jit/backend/zarch/pool.py
@@ -95,6 +95,9 @@
             if arg.is_constant():
                 self.reserve_literal(8, arg)
 
+    def contains_constant(self, unique_val):
+        return unique_val in self.offset_map
+
     def get_descr_offset(self, descr):
         return self.offset_descr[descr]
 
@@ -105,6 +108,11 @@
             assert self.offset_map[uvalue] >= 0
         return self.offset_map[uvalue]
 
+    def get_direct_offset(self, unique_val):
+        """ Get the offset directly using a unique value,
+            use get_offset if you have a Const box """
+        return self.offset_map[unique_val]
+
     def unique_value(self, val):
         if val.type == FLOAT:
             if val.getfloat() == 0.0:
@@ -170,6 +178,8 @@
         self.pool_start = asm.mc.get_relative_pos()
         for op in operations:
             self.ensure_can_hold_constants(asm, op)
+        self.ensure_value(asm.cpu.pos_exc_value())
+        # TODO add more values that are loaded with load_imm
         if self.size == 0:
             # no pool needed!
             return
diff --git a/rpython/jit/backend/zarch/test/test_calling_convention.py b/rpython/jit/backend/zarch/test/test_calling_convention.py
--- a/rpython/jit/backend/zarch/test/test_calling_convention.py
+++ b/rpython/jit/backend/zarch/test/test_calling_convention.py
@@ -5,7 +5,7 @@
 import rpython.jit.backend.zarch.conditions as c
 
 
-class TestPPCCallingConvention(CallingConvTests):
+class TestZARCHCallingConvention(CallingConvTests):
     # ../../test/calling_convention_test.py
 
     def make_function_returning_stack_pointer(self):


More information about the pypy-commit mailing list