Author: Richard Plangger <[email protected]>
Branch: s390x-backend
Changeset: r81876:30073c0bccb6
Date: 2016-01-20 13:48 +0100
http://bitbucket.org/pypy/pypy/changeset/30073c0bccb6/
Log: literal pool enhancement. it now stores unique values, no 64 bit
integer/float/ref is every stored twice in the pool
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
@@ -10,6 +10,9 @@
RECOVERY_GCMAP_POOL_OFFSET, RECOVERY_TARGET_POOL_OFFSET)
from rpython.rlib.longlong2float import float2longlong
+class PoolOverflow(Exception):
+ pass
+
class LiteralPool(object):
def __init__(self):
self.size = 0
@@ -17,7 +20,10 @@
self.pool_start = 0
self.label_offset = 0
self.label_count = 0
+ # for constant offsets
self.offset_map = {}
+ # for descriptors
+ self.offset_descr = {}
self.constant_64_zeros = -1
self.constant_64_ones = -1
self.constant_64_sign_bit = -1
@@ -28,19 +34,21 @@
if op.is_guard():
# 1x gcmap pointer
# 1x target address
- self.offset_map[op.getdescr()] = self.size
- self.reserve_literal(2 * 8)
+ self.offset_descr[op.getdescr()] = self.size
+ self.allocate_slot(2*8)
elif op.getopnum() == rop.JUMP:
descr = op.getdescr()
if descr not in asm.target_tokens_currently_compiling:
# this is a 'long' jump instead of a relative jump
- self.offset_map[descr] = self.size
- self.reserve_literal(8)
+ self.offset_descr[descr] = self.size
+ self.allocate_slot(8)
elif op.getopnum() == rop.LABEL:
descr = op.getdescr()
if descr not in asm.target_tokens_currently_compiling:
# this is a 'long' jump instead of a relative jump
- self.offset_map[descr] = self.size
+ # TODO why no reserve literal? self.offset_map[descr] =
self.size
+ self.offset_descr[descr] = self.size
+ self.allocate_slot(8)
elif op.getopnum() == rop.INT_INVERT:
self.constant_64_ones = 1 # we need constant ones!!!
elif op.getopnum() == rop.INT_MUL_OVF:
@@ -50,18 +58,15 @@
opnum == rop.UINT_RSHIFT:
a0 = op.getarg(0)
if a0.is_constant():
- self.offset_map[a0] = self.size
- self.reserve_literal(8)
+ self.reserve_literal(8, a0)
return
elif opnum == rop.GC_STORE or opnum == rop.GC_STORE_INDEXED:
arg = op.getarg(0)
if arg.is_constant():
- self.offset_map[arg] = self.size
- self.reserve_literal(8)
+ self.reserve_literal(8, arg)
arg = op.getarg(2)
if arg.is_constant():
- self.offset_map[arg] = self.size
- self.reserve_literal(8)
+ self.reserve_literal(8, arg)
return
elif opnum in (rop.GC_LOAD_F,
rop.GC_LOAD_I,
@@ -71,27 +76,42 @@
rop.GC_LOAD_INDEXED_I,):
arg = op.getarg(0)
if arg.is_constant():
- self.offset_map[arg] = self.size
- self.reserve_literal(8)
+ self.reserve_literal(8, arg)
+ if opnum == rop.GC_LOAD_INDEXED_R:
+ arg = op.getarg(1)
+ if arg.is_constant():
+ self.reserve_literal(8, arg)
return
elif op.is_call_release_gil():
for arg in op.getarglist()[1:]:
if arg.is_constant():
- self.offset_map[arg] = self.size
- self.reserve_literal(8)
+ self.reserve_literal(8, arg)
return
for arg in op.getarglist():
if arg.is_constant():
- self.offset_map[arg] = self.size
- self.reserve_literal(8)
+ self.reserve_literal(8, arg)
def get_offset(self, box):
+ assert box.is_constant()
+ uvalue = self.unique_value(box)
if not we_are_translated():
- assert self.offset_map[box] >= 0
- return self.offset_map[box]
+ assert self.offset_map[uvalue] >= 0
+ return self.offset_map[uvalue]
- def reserve_literal(self, size):
- self.size += size
+ def unique_value(self, val):
+ if val.type == FLOAT:
+ return float2longlong(val.getfloat())
+ elif val.type == INT:
+ return rffi.cast(lltype.Signed, val.getint())
+ else:
+ assert val.type == REF
+ return rffi.cast(lltype.Signed, val.getref_base())
+
+ def reserve_literal(self, size, box):
+ uvalue = self.unique_value(box)
+ if uvalue not in self.offset_map:
+ self.offset_map[uvalue] = self.size
+ self.allocate_slot(size)
def reset(self):
self.pool_start = 0
@@ -103,6 +123,26 @@
self.constant_64_sign_bit = -1
self.constant_max_64_positive -1
+ def check_size(self, size=-1):
+ if size == -1:
+ size = self.size
+ if size >= 2**19:
+ msg = '[S390X/literalpool] size exceeded %d >= %d\n' % (size,
2**19-8)
+ if we_are_translated():
+ llop.debug_print(lltype.Void, msg)
+ raise PoolOverflow(msg)
+
+ def allocate_slot(self, size):
+ val = self.size + size
+ self.check_size(val)
+ self.size = val
+
+ def ensure_value(self, val):
+ if val not in self.offset_map:
+ self.offset_map[val] = self.size
+ self.allocate_slot(8)
+ return self.offset_map[val]
+
def pre_assemble(self, asm, operations, bridge=False):
# O(len(operations)). I do not think there is a way
# around this.
@@ -110,9 +150,9 @@
# Problem:
# constants such as floating point operations, plain pointers,
# or integers might serve as parameter to an operation. thus
- # it must be loaded into a register. You cannot do this with
- # assembler immediates, because the biggest immediate value
- # is 32 bit for branch instructions.
+ # it must be loaded into a register. There is a space benefit
+ # for 64-bit integers, or python floats, when a constant is used
+ # twice.
#
# Solution:
# the current solution (gcc does the same), use a literal pool
@@ -125,25 +165,23 @@
# no pool needed!
return
assert self.size % 2 == 0, "not aligned properly"
- asm.mc.write('\x00' * self.size)
- written = 0
if self.constant_64_ones != -1:
- asm.mc.write('\xFF' * 8)
- self.constant_64_ones = self.size + written
- written += 8
+ self.constant_64_ones = self.ensure_value(0xffffFFFFffffFFFF)
if self.constant_64_zeros != -1:
- asm.mc.write('\x00' * 8)
- self.constant_64_zeros = self.size + written
- written += 8
+ self.constant_64_zeros = self.ensure_value(0x0)
if self.constant_64_sign_bit != -1:
- asm.mc.write('\x80' + ('\x00' * 7))
- self.constant_64_sign_bit = self.size + written
- written += 8
+ self.constant_64_zeros = self.ensure_value(0x8000000000000000)
if self.constant_max_64_positive != -1:
- asm.mc.write('\x7F' + ('\xFF' * 7))
- self.constant_max_64_positive = self.size + written
- written += 8
- self.size += written
+ self.constant_max_64_positive =
self.ensure_value(0x7fffFFFFffffFFFF)
+ wrote = 0
+ for val, offset in self.offset_map.items():
+ if not we_are_translated():
+ print('pool: %s at offset: %d' % (val, offset))
+ self.mc.write_i64()
+ wrote += 8
+ self.offset_map = {}
+ # for the descriptors
+ asm.mc.write('\x00' * (self.size - wrote))
if not we_are_translated():
print "pool with %d quad words" % (self.size // 8)
@@ -163,24 +201,11 @@
pending_guard_tokens = asm.pending_guard_tokens
if self.size == 0:
return
- for val, offset in self.offset_map.items():
- if not we_are_translated():
- print('pool: %s at offset: %d' % (val, offset))
- if val.is_constant():
- if val.type == FLOAT:
- self.overwrite_64(mc, offset,
float2longlong(val.getfloat()))
- elif val.type == INT:
- i64 = rffi.cast(lltype.Signed, val.getint())
- self.overwrite_64(mc, offset, i64)
- else:
- assert val.type == REF
- i64 = rffi.cast(lltype.Signed, val.getref_base())
- self.overwrite_64(mc, offset, i64)
-
for guard_token in pending_guard_tokens:
descr = guard_token.faildescr
- offset = self.offset_map[descr]
+ offset = self.offset_descr[descr]
assert isinstance(offset, int)
+ assert offset >= 0
guard_token._pool_offset = offset
ptr = rffi.cast(lltype.Signed, guard_token.gcmap)
self.overwrite_64(mc, offset + RECOVERY_GCMAP_POOL_OFFSET, ptr)
diff --git a/rpython/jit/backend/zarch/test/test_pool.py
b/rpython/jit/backend/zarch/test/test_pool.py
--- a/rpython/jit/backend/zarch/test/test_pool.py
+++ b/rpython/jit/backend/zarch/test/test_pool.py
@@ -1,5 +1,5 @@
import py
-from rpython.jit.backend.zarch.pool import LiteralPool
+from rpython.jit.backend.zarch.pool import LiteralPool, PoolOverflow
from rpython.jit.metainterp.history import (AbstractFailDescr,
AbstractDescr, BasicFailDescr, BasicFinalDescr, JitCellToken,
TargetToken, ConstInt, ConstPtr, Const, ConstFloat)
@@ -10,6 +10,7 @@
from rpython.jit.backend.zarch.helper.regalloc import check_imm32
from rpython.jit.backend.zarch.assembler import AssemblerZARCH
from rpython.jit.backend.detect_cpu import getcpuclass
+from rpython.jit.tool.oparser import parse
class TestPoolZARCH(object):
def setup_class(self):
@@ -18,6 +19,8 @@
def setup_method(self, name):
self.pool = LiteralPool()
self.asm = None
+ self.cpu = getcpuclass()(None, None)
+ self.cpu.setup_once()
def ensure_can_hold(self, opnum, args, descr=None):
op = ResOperation(opnum, args, descr=descr)
@@ -26,9 +29,9 @@
def const_in_pool(self, c):
try:
self.pool.get_offset(c)
+ return True
except KeyError:
return False
- return True
def test_constant_in_call_malloc(self):
c = ConstPtr(rffi.cast(llmemory.GCREF, 0xdeadbeef))
@@ -42,18 +45,14 @@
for c1 in [ConstInt(1), ConstInt(2**44), InputArgInt(1)]:
for c2 in [InputArgInt(1), ConstInt(1), ConstInt(2**55)]:
self.ensure_can_hold(opnum, [c1,c2])
- if c1.is_constant() and check_imm32(c1):
+ if c1.is_constant():
assert self.const_in_pool(c1)
- else:
- assert not self.const_in_pool(c1)
- if c2.is_constant() and check_imm32(c2):
+ if c2.is_constant():
assert self.const_in_pool(c2)
- else:
- assert not self.const_in_pool(c2)
def test_pool_overflow(self):
- cpu = getcpuclass()(None, None)
- cpu.setup_once()
- ops = [ResOperation(rop.FLOAT_ADD, [ConstFloat(0.0125),
ConstFloat(float(i))]) for i in range(100)]
- cpu.compile_loop([], ops, JitCellToken())
-
+ self.pool.size = (2**19-1) - 8
+ self.pool.allocate_slot(8)
+ assert self.pool.size == 2**19-1
+ with py.test.raises(PoolOverflow) as of:
+ self.pool.allocate_slot(8)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit