[pypy-commit] pypy default: Support possibly-misaligned raw-storage getitems and setitems.
arigo
noreply at buildbot.pypy.org
Sun Feb 23 10:36:27 CET 2014
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r69283:6b8aaf94225a
Date: 2014-02-23 10:35 +0100
http://bitbucket.org/pypy/pypy/changeset/6b8aaf94225a/
Log: Support possibly-misaligned raw-storage getitems and setitems.
diff --git a/rpython/rlib/rawstorage.py b/rpython/rlib/rawstorage.py
--- a/rpython/rlib/rawstorage.py
+++ b/rpython/rlib/rawstorage.py
@@ -18,17 +18,87 @@
def raw_storage_getitem(TP, storage, index):
"NOT_RPYTHON"
+ _check_alignment(TP, index)
return rffi.cast(rffi.CArrayPtr(TP), rffi.ptradd(storage, index))[0]
def raw_storage_setitem(storage, index, item):
"NOT_RPYTHON"
- TP = rffi.CArrayPtr(lltype.typeOf(item))
- rffi.cast(TP, rffi.ptradd(storage, index))[0] = item
+ TP = lltype.typeOf(item)
+ _check_alignment(TP, index)
+ rffi.cast(rffi.CArrayPtr(TP), rffi.ptradd(storage, index))[0] = item
@specialize.arg(1)
def free_raw_storage(storage, track_allocation=True):
lltype.free(storage, flavor='raw', track_allocation=track_allocation)
+# ____________________________________________________________
+#
+# Support for possibly-unaligned accesses
+
+from rpython.jit.backend import detect_cpu
+try:
+ misaligned_is_fine = detect_cpu.autodetect().startswith('x86')
+except detect_cpu.ProcessorAutodetectError:
+ misaligned_is_fine = False
+
+
+class AlignmentError(NotImplementedError):
+ "Means that raw_storage_{get,set}item was used on unaligned memory"
+
+# Tweak? It seems a reasonable value for any system out there: requiring
+# an aligned access to be up to 8-bytes-aligned, even for 64-bit data
+# types on 32-bit systems.
+MAXIMUM_ALIGNMENT = 8
+
+ at specialize.memo()
+def _get_alignment_mask(TP):
+ size = rffi.sizeof(TP)
+ alignment = 1
+ while (size & alignment) == 0 and alignment < MAXIMUM_ALIGNMENT:
+ alignment *= 2
+ return alignment - 1
+
+def _check_alignment(TP, index):
+ """Check that the 'index' does indeed have the maximum alignment
+ for the given type."""
+ mask = _get_alignment_mask(TP)
+ if (index & mask) != 0:
+ raise AlignmentError
+
+ at specialize.ll()
+def raw_storage_getitem_unaligned(TP, storage, index):
+ if misaligned_is_fine:
+ return raw_storage_getitem(TP, storage, index)
+ mask = _get_alignment_mask(TP)
+ if (index & mask) == 0:
+ return raw_storage_getitem(TP, storage, index)
+ ptr = rffi.ptradd(storage, index)
+ with lltype.scoped_alloc(rffi.CArray(TP), 1) as s_array:
+ rffi.c_memcpy(rffi.cast(rffi.VOIDP, s_array),
+ rffi.cast(rffi.VOIDP, ptr),
+ rffi.sizeof(TP))
+ return rffi.cast(rffi.CArrayPtr(TP), s_array)[0]
+
+ at specialize.ll()
+def raw_storage_setitem_unaligned(storage, index, item):
+ if misaligned_is_fine:
+ raw_storage_setitem(storage, index, item)
+ return
+ TP = lltype.typeOf(item)
+ mask = _get_alignment_mask(TP)
+ if (index & mask) == 0:
+ raw_storage_setitem(storage, index, item)
+ return
+ ptr = rffi.ptradd(storage, index)
+ with lltype.scoped_alloc(rffi.CArray(TP), 1) as s_array:
+ rffi.cast(rffi.CArrayPtr(TP), s_array)[0] = item
+ rffi.c_memcpy(rffi.cast(rffi.VOIDP, ptr),
+ rffi.cast(rffi.VOIDP, s_array),
+ rffi.sizeof(TP))
+
+# ____________________________________________________________
+
+
class RawStorageGetitemEntry(ExtRegistryEntry):
_about_ = raw_storage_getitem
diff --git a/rpython/rlib/test/test_rawstorage.py b/rpython/rlib/test/test_rawstorage.py
--- a/rpython/rlib/test/test_rawstorage.py
+++ b/rpython/rlib/test/test_rawstorage.py
@@ -1,23 +1,91 @@
+import py
+import sys
+from rpython.rtyper.lltypesystem import lltype
+from rpython.rlib import rawstorage
+from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage,\
+ raw_storage_setitem, raw_storage_getitem, AlignmentError,\
+ raw_storage_setitem_unaligned, raw_storage_getitem_unaligned
+from rpython.rtyper.test.tool import BaseRtypingTest
+from rpython.translator.c.test.test_genc import compile
-from rpython.rtyper.lltypesystem import lltype
-from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage,\
- raw_storage_setitem, raw_storage_getitem
-from rpython.rtyper.test.tool import BaseRtypingTest
def test_untranslated_storage():
+ r = alloc_raw_storage(37)
+ raw_storage_setitem(r, 8, 1<<30)
+ res = raw_storage_getitem(lltype.Signed, r, 8)
+ assert res == 1<<30
+ raw_storage_setitem(r, 8, 3.14)
+ res = raw_storage_getitem(lltype.Float, r, 8)
+ assert res == 3.14
+ py.test.raises(AlignmentError, raw_storage_getitem, lltype.Signed, r, 3)
+ py.test.raises(AlignmentError, raw_storage_setitem, r, 3, 42.5)
+ free_raw_storage(r)
+
+def test_untranslated_storage_unaligned(monkeypatch):
+ monkeypatch.setattr(rawstorage, 'misaligned_is_fine', False)
r = alloc_raw_storage(15)
- raw_storage_setitem(r, 3, 1<<30)
- res = raw_storage_getitem(lltype.Signed, r, 3)
+ raw_storage_setitem_unaligned(r, 3, 1<<30)
+ res = raw_storage_getitem_unaligned(lltype.Signed, r, 3)
+ assert res == 1<<30
+ raw_storage_setitem_unaligned(r, 3, 3.14)
+ res = raw_storage_getitem_unaligned(lltype.Float, r, 3)
+ assert res == 3.14
free_raw_storage(r)
- assert res == 1<<30
+
class TestRawStorage(BaseRtypingTest):
+
def test_storage_int(self):
def f(i):
r = alloc_raw_storage(24)
- raw_storage_setitem(r, 3, i)
- res = raw_storage_getitem(lltype.Signed, r, 3)
+ raw_storage_setitem(r, 8, i)
+ res = raw_storage_getitem(lltype.Signed, r, 8)
free_raw_storage(r)
return res
+
x = self.interpret(f, [1<<30])
assert x == 1 << 30
+
+ def test_storage_float_unaligned(self, monkeypatch):
+ def f(v):
+ r = alloc_raw_storage(24)
+ raw_storage_setitem_unaligned(r, 3, v)
+ res = raw_storage_getitem_unaligned(lltype.Float, r, 3)
+ free_raw_storage(r)
+ return res
+
+ monkeypatch.setattr(rawstorage, 'misaligned_is_fine', False)
+ x = self.interpret(f, [3.14])
+ assert x == 3.14
+
+
+class TestCBackend(object):
+
+ def test_backend_int(self):
+ def f(i):
+ r = alloc_raw_storage(24)
+ raw_storage_setitem(r, 8, i)
+ res = raw_storage_getitem(lltype.Signed, r, 8)
+ free_raw_storage(r)
+ return res != i
+
+ fc = compile(f, [int])
+ x = fc(-sys.maxint // 3)
+ assert x == 0
+
+ def test_backend_float_unaligned(self, monkeypatch):
+ def f(v):
+ r = alloc_raw_storage(24)
+ raw_storage_setitem_unaligned(r, 3, v)
+ res = raw_storage_getitem_unaligned(lltype.Float, r, 3)
+ free_raw_storage(r)
+ return res != v
+
+ if monkeypatch is not None:
+ monkeypatch.setattr(rawstorage, 'misaligned_is_fine', False)
+ fc = compile(f, [float])
+ x = fc(-3.14)
+ assert x == 0
+
+ def test_backend_float_unaligned_allow_misalign(self):
+ self.test_backend_float_unaligned(monkeypatch=None)
More information about the pypy-commit
mailing list