[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