Commits

Armin Rigo committed 9df046c

Implement correctly raw_storage_{get,set}item_unaligned() in rlib.rawstorage

Comments (0)

Files changed (5)

rpython/rlib/rawstorage.py

 from rpython.rlib.rgc import lltype_is_gc
 from rpython.rlib.objectmodel import specialize
 
+WORD = rffi.sizeof(rffi.VOIDP)
 RAW_STORAGE = rffi.CCHARP.TO
 RAW_STORAGE_PTR = rffi.CCHARP
 
                          track_allocation=track_allocation,
                          zero=zero)
 
-def raw_storage_getitem_unaligned(TP, storage, index):
-    "NOT_RPYTHON"
-    return rffi.cast(rffi.CArrayPtr(TP), rffi.ptradd(storage, index))[0]
-
 def raw_storage_getitem(TP, storage, index):
     "NOT_RPYTHON"
-    ptr = rffi.ptradd(storage, index)
-    if TP is lltype.Float and rffi.cast(lltype.Signed, ptr) & 3:
-        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]
-    return rffi.cast(rffi.CArrayPtr(TP), ptr)[0]
+    _check_alignment(TP, index)
+    return rffi.cast(rffi.CArrayPtr(TP), rffi.ptradd(storage, index))[0]
+raw_storage_getitem._op_ = 'raw_load'
 
 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
+raw_storage_setitem._op_ = 'raw_store'
+
+class AlignmentError(Exception):
+    "NOT_RPYTHON"
+
+def _check_alignment(TP, index):
+    size = rffi.sizeof(TP)
+    alignment = 1
+    while (size & alignment) == 0 and alignment < WORD:
+        alignment *= 2
+    if (index & (alignment - 1)) != 0:
+        raise AlignmentError
+
+def raw_storage_getitem_unaligned(TP, storage, index):
+    "NOT_RPYTHON"
+    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]
+raw_storage_getitem_unaligned._op_ = 'raw_load_unaligned'
+
+def raw_storage_setitem_unaligned(storage, index, item):
+    "NOT_RPYTHON"
+    TP = lltype.typeOf(item)
+    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))
+raw_storage_setitem_unaligned._op_ = 'raw_store_unaligned'
 
 @specialize.arg(1)
 def free_raw_storage(storage, track_allocation=True):
     lltype.free(storage, flavor='raw', track_allocation=track_allocation)
 
+
 class RawStorageGetitemEntry(ExtRegistryEntry):
-    _about_ = raw_storage_getitem
+    _about_ = (raw_storage_getitem, raw_storage_getitem_unaligned)
 
     def compute_result_annotation(self, s_TP, s_storage, s_index):
         assert s_TP.is_constant()
         v_storage = hop.inputarg(hop.args_r[1], arg=1)
         v_index   = hop.inputarg(lltype.Signed, arg=2)
         hop.exception_cannot_occur()
-        v_addr = hop.genop('casst_ptr_to_adr', [v_storage],
+        v_addr = hop.genop('cast_ptr_to_adr', [v_storage],
                            resulttype=llmemory.Address)
-        return hop.genop('raw_load', [v_addr, v_index],
+        op = self.instance._op_
+        return hop.genop(op, [v_addr, v_index],
                          resulttype=hop.r_result.lowleveltype)
 
 class RawStorageSetitemEntry(ExtRegistryEntry):
-    _about_ = raw_storage_setitem
+    _about_ = (raw_storage_setitem, raw_storage_setitem_unaligned)
 
     def compute_result_annotation(self, s_storage, s_index, s_item):
         assert annmodel.SomeInteger().contains(s_index)
         hop.exception_cannot_occur()
         v_addr = hop.genop('cast_ptr_to_adr', [v_storage],
                            resulttype=llmemory.Address)
-        return hop.genop('raw_store', [v_addr, v_index, v_item])
+        op = self.instance._op_
+        return hop.genop(op, [v_addr, v_index, v_item])

rpython/rlib/test/test_rawstorage.py

-
+import py
 from rpython.rtyper.lltypesystem import lltype
 from rpython.rlib.rawstorage import alloc_raw_storage, free_raw_storage,\
-     raw_storage_setitem, raw_storage_getitem
+     raw_storage_setitem, raw_storage_getitem, AlignmentError,\
+     raw_storage_setitem_unaligned, raw_storage_getitem_unaligned
 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():
     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(r, 3, 3.14)
-    res = raw_storage_getitem(lltype.Float, r, 3)
+    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)
 
     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(self):
+
+    def test_storage_float_unaligned(self):
         def f(v):
             r = alloc_raw_storage(24)
-            raw_storage_setitem(r, 3, v)
-            res = raw_storage_getitem(lltype.Float, r, 3)
+            raw_storage_setitem_unaligned(r, 3, v)
+            res = raw_storage_getitem_unaligned(lltype.Float, r, 3)
             free_raw_storage(r)
             return res
         x = self.interpret(f, [3.14])

rpython/rtyper/lltypesystem/lloperation.py

     'raw_memcopy':          LLOp(),
     'raw_memmove':          LLOp(),
     'raw_load':             LLOp(sideeffects=False, canrun=True),
+    'raw_load_unaligned':   LLOp(sideeffects=False, canrun=True),
     'raw_store':            LLOp(canrun=True),
+    'raw_store_unaligned':  LLOp(canrun=True),
     'bare_raw_store':       LLOp(),
+    'bare_raw_store_unaligned': LLOp(),
     'stack_malloc':         LLOp(), # mmh
     'track_alloc_start':    LLOp(),
     'track_alloc_stop':     LLOp(),

rpython/rtyper/lltypesystem/opimpl.py

 
 def op_raw_store(p, ofs, newvalue):
     from rpython.rtyper.lltypesystem import rffi
+    from rpython.rlib.rawstorage import _check_alignment
     p = rffi.cast(llmemory.Address, p)
     TVAL = lltype.typeOf(newvalue)
+    _check_alignment(TVAL, ofs)
     p = rffi.cast(rffi.CArrayPtr(TVAL), p + ofs)
     p[0] = newvalue
 
 def op_raw_load(TVAL, p, ofs):
     from rpython.rtyper.lltypesystem import rffi
+    from rpython.rlib.rawstorage import _check_alignment
     p = rffi.cast(llmemory.Address, p)
+    _check_alignment(TVAL, ofs)
     p = rffi.cast(rffi.CArrayPtr(TVAL), p + ofs)
     return p[0]
 op_raw_load.need_result_type = True
 
+def op_raw_store_unaligned(p, ofs, newvalue):
+    from rpython.rtyper.lltypesystem import rffi
+    p = rffi.cast(llmemory.Address, p)
+    TVAL = lltype.typeOf(newvalue)
+    with lltype.scoped_alloc(rffi.CArray(TVAL), 1) as s_array:
+        rffi.cast(rffi.CArrayPtr(TVAL), s_array)[0] = newvalue
+        rffi.c_memcpy(rffi.cast(rffi.VOIDP, p + ofs),
+                      rffi.cast(rffi.VOIDP, s_array),
+                      rffi.sizeof(TVAL))
+
+def op_raw_load_unaligned(TVAL, p, ofs):
+    from rpython.rtyper.lltypesystem import rffi
+    p = rffi.cast(llmemory.Address, p)
+    with lltype.scoped_alloc(rffi.CArray(TVAL), 1) as s_array:
+        rffi.c_memcpy(rffi.cast(rffi.VOIDP, s_array),
+                      rffi.cast(rffi.VOIDP, p + ofs),
+                      rffi.sizeof(TVAL))
+        return rffi.cast(rffi.CArrayPtr(TVAL), s_array)[0]
+op_raw_load_unaligned.need_result_type = True
+
 # ____________________________________________________________
 
 def get_op_impl(opname):

rpython/rtyper/lltypesystem/test/test_lloperation.py

     x = llop.cast_float_to_ulonglong(lltype.UnsignedLongLong, f)
     assert x == r_ulonglong(f)
 
+def test_raw_load_store_alignment():
+    from rpython.rlib import rawstorage
+    from rpython.rlib.rawstorage import AlignmentError
+    p = rawstorage.alloc_raw_storage(37)
+    llop.raw_store(lltype.Void, p, 8, 4891379)
+    assert llop.raw_load(lltype.Signed, p, 8) == 4891379
+    py.test.raises(AlignmentError, llop.raw_load, lltype.Signed, p, 3)
+    py.test.raises(AlignmentError, llop.raw_store, lltype.Void, p, 3, 2987128)
+    rawstorage.free_raw_storage(p)
+
+def test_raw_load_store_unaligned():
+    from rpython.rlib import rawstorage
+    p = rawstorage.alloc_raw_storage(37)
+    rawstorage.raw_storage_setitem_unaligned(p, 3, 123456789)
+    res = llop.raw_load_unaligned(lltype.Signed, p, 3)
+    assert res == 123456789
+    llop.raw_store_unaligned(lltype.Void, p, 3, -987654321)
+    res = rawstorage.raw_storage_getitem_unaligned(lltype.Signed, p, 3)
+    assert res == -987654321
+    rawstorage.free_raw_storage(p)
+
 # ___________________________________________________________________________
 # This tests that the LLInterpreter and the LL_OPERATIONS tables are in sync.