[pypy-commit] pypy default: Merged float-bytes. This adds a new llop/resop which converts a floats bytes to an integer.

alex_gaynor noreply at buildbot.pypy.org
Mon Mar 19 21:42:11 CET 2012


Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch: 
Changeset: r53812:68334a9e9db1
Date: 2012-03-19 15:39 -0500
http://bitbucket.org/pypy/pypy/changeset/68334a9e9db1/

Log:	Merged float-bytes. This adds a new llop/resop which converts a
	floats bytes to an integer.

diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -16,9 +16,11 @@
 from pypy.rpython.annlowlevel import llhelper
 from pypy.rpython.llinterp import LLException
 from pypy.jit.codewriter import heaptracker, longlong
+from pypy.rlib import longlong2float
 from pypy.rlib.rarithmetic import intmask, is_valid_int
 from pypy.jit.backend.detect_cpu import autodetect_main_model_and_size
 
+
 def boxfloat(x):
     return BoxFloat(longlong.getfloatstorage(x))
 
@@ -1615,6 +1617,11 @@
                                      [BoxPtr(x)], 'int').value
         assert res == -19
 
+    def test_convert_float_bytes(self):
+        res = self.execute_operation(rop.CONVERT_FLOAT_BYTES_TO_LONGLONG,
+                                     [boxfloat(2.5)], 'int').value
+        assert res == longlong2float.float2longlong(2.5)
+
     def test_ooops_non_gc(self):
         x = lltype.malloc(lltype.Struct('x'), flavor='raw')
         v = heaptracker.adr2int(llmemory.cast_ptr_to_adr(x))
diff --git a/pypy/jit/backend/test/test_random.py b/pypy/jit/backend/test/test_random.py
--- a/pypy/jit/backend/test/test_random.py
+++ b/pypy/jit/backend/test/test_random.py
@@ -449,6 +449,7 @@
 
 OPERATIONS.append(CastFloatToIntOperation(rop.CAST_FLOAT_TO_INT))
 OPERATIONS.append(CastIntToFloatOperation(rop.CAST_INT_TO_FLOAT))
+OPERATIONS.append(CastFloatToIntOperation(rop.CONVERT_FLOAT_BYTES_TO_LONGLONG))
 
 OperationBuilder.OPERATIONS = OPERATIONS
 
@@ -502,11 +503,11 @@
     else:
         assert 0, "unknown backend %r" % pytest.config.option.backend
 
-# ____________________________________________________________    
+# ____________________________________________________________
 
 class RandomLoop(object):
     dont_generate_more = False
-    
+
     def __init__(self, cpu, builder_factory, r, startvars=None):
         self.cpu = cpu
         if startvars is None:
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -606,7 +606,7 @@
         else:
             assert token
             struct.number = compute_unique_id(token)
-        self.loop_run_counters.append(struct)            
+        self.loop_run_counters.append(struct)
         return struct
 
     def _find_failure_recovery_bytecode(self, faildescr):
@@ -665,7 +665,7 @@
                ResOperation(rop.SETFIELD_RAW, [c_adr, box2],
                             None, descr=self.debug_counter_descr)]
         operations.extend(ops)
-        
+
     @specialize.argtype(1)
     def _inject_debugging_code(self, looptoken, operations, tp, number):
         if self._debug:
@@ -1242,6 +1242,15 @@
         self.mc.MOVD_xr(resloc.value, loc0.value)
         self.mc.CVTSS2SD_xx(resloc.value, resloc.value)
 
+    def genop_convert_float_bytes_to_longlong(self, op, arglocs, resloc):
+        loc0, = arglocs
+        if longlong.is_64_bit:
+            assert isinstance(resloc, RegLoc)
+            assert isinstance(loc0, RegLoc)
+            self.mc.MOVD(resloc, loc0)
+        else:
+            self.mov(loc0, resloc)
+
     def genop_guard_int_is_true(self, op, guard_op, guard_token, arglocs, resloc):
         guard_opnum = guard_op.getopnum()
         self.mc.CMP(arglocs[0], imm0)
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -766,6 +766,18 @@
 
     consider_cast_singlefloat_to_float = consider_cast_int_to_float
 
+    def consider_convert_float_bytes_to_longlong(self, op):
+        if longlong.is_64_bit:
+            loc0 = self.xrm.make_sure_var_in_reg(op.getarg(0))
+            loc1 = self.rm.force_allocate_reg(op.result)
+            self.Perform(op, [loc0], loc1)
+            self.xrm.possibly_free_var(op.getarg(0))
+        else:
+            loc0 = self.xrm.loc(op.getarg(0))
+            loc1 = self.xrm.force_allocate_reg(op.result)
+            self.Perform(op, [loc0], loc1)
+            self.xrm.possibly_free_var(op.getarg(0))
+
     def _consider_llong_binop_xx(self, op):
         # must force both arguments into xmm registers, because we don't
         # know if they will be suitably aligned.  Exception: if the second
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -601,9 +601,10 @@
     CVTSS2SD_xb = xmminsn('\xF3', rex_nw, '\x0F\x5A',
                           register(1, 8), stack_bp(2))
 
-    MOVD_rx = xmminsn('\x66', rex_nw, '\x0F\x7E', register(2, 8), register(1), '\xC0')
-    MOVD_xr = xmminsn('\x66', rex_nw, '\x0F\x6E', register(1, 8), register(2), '\xC0')
-    MOVD_xb = xmminsn('\x66', rex_nw, '\x0F\x6E', register(1, 8), stack_bp(2))
+    # These work on machine sized registers.
+    MOVD_rx = xmminsn('\x66', rex_w, '\x0F\x7E', register(2, 8), register(1), '\xC0')
+    MOVD_xr = xmminsn('\x66', rex_w, '\x0F\x6E', register(1, 8), register(2), '\xC0')
+    MOVD_xb = xmminsn('\x66', rex_w, '\x0F\x6E', register(1, 8), stack_bp(2))
 
     PSRAD_xi = xmminsn('\x66', rex_nw, '\x0F\x72', register(1), '\xE0', immediate(2, 'b'))
 
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -291,6 +291,11 @@
         op1 = SpaceOperation('-live-', [], None)
         return [op, op1]
 
+    def _noop_rewrite(self, op):
+        return op
+
+    rewrite_op_convert_float_bytes_to_longlong = _noop_rewrite
+
     # ----------
     # Various kinds of calls
 
diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py
--- a/pypy/jit/codewriter/test/test_flatten.py
+++ b/pypy/jit/codewriter/test/test_flatten.py
@@ -968,6 +968,15 @@
             int_return %i2
         """, transform=True)
 
+    def test_convert_float_bytes_to_int(self):
+        from pypy.rlib.longlong2float import float2longlong
+        def f(x):
+            return float2longlong(x)
+        self.encoding_test(f, [25.0], """
+            convert_float_bytes_to_longlong %f0 -> %i0
+            int_return %i0
+        """)
+
 
 def check_force_cast(FROM, TO, operations, value):
     """Check that the test is correctly written..."""
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -1,15 +1,16 @@
+from pypy.jit.codewriter import heaptracker, longlong
+from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
+from pypy.jit.metainterp.compile import ResumeAtPositionDescr
+from pypy.jit.metainterp.jitexc import JitException, get_llexception, reraise
+from pypy.rlib import longlong2float
+from pypy.rlib.debug import debug_start, debug_stop, ll_assert, make_sure_not_resized
+from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck
+from pypy.rlib.rtimer import read_timestamp
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.rlib.rtimer import read_timestamp
-from pypy.rlib.rarithmetic import intmask, LONG_BIT, r_uint, ovfcheck
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.debug import debug_start, debug_stop, ll_assert
-from pypy.rlib.debug import make_sure_not_resized
 from pypy.rpython.lltypesystem import lltype, llmemory, rclass
 from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.jit.codewriter.jitcode import JitCode, SwitchDictDescr
-from pypy.jit.codewriter import heaptracker, longlong
-from pypy.jit.metainterp.jitexc import JitException, get_llexception, reraise
-from pypy.jit.metainterp.compile import ResumeAtPositionDescr
+
 
 def arguments(*argtypes, **kwds):
     resulttype = kwds.pop('returns', None)
@@ -20,6 +21,9 @@
         return function
     return decorate
 
+LONGLONG_TYPECODE = 'i' if longlong.is_64_bit else 'f'
+
+
 class LeaveFrame(JitException):
     pass
 
@@ -663,6 +667,11 @@
         a = float(a)
         return longlong.getfloatstorage(a)
 
+    @arguments("f", returns=LONGLONG_TYPECODE)
+    def bhimpl_convert_float_bytes_to_longlong(a):
+        a = longlong.getrealfloat(a)
+        return longlong2float.float2longlong(a)
+
     # ----------
     # control flow operations
 
@@ -1309,7 +1318,7 @@
     def bhimpl_copyunicodecontent(cpu, src, dst, srcstart, dststart, length):
         cpu.bh_copyunicodecontent(src, dst, srcstart, dststart, length)
 
-    @arguments(returns=(longlong.is_64_bit and "i" or "f"))
+    @arguments(returns=LONGLONG_TYPECODE)
     def bhimpl_ll_read_timestamp():
         return read_timestamp()
 
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -223,6 +223,7 @@
                     'cast_float_to_singlefloat', 'cast_singlefloat_to_float',
                     'float_neg', 'float_abs',
                     'cast_ptr_to_int', 'cast_int_to_ptr',
+                    'convert_float_bytes_to_longlong',
                     ]:
         exec py.code.Source('''
             @arguments("box")
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -419,6 +419,7 @@
     'CAST_INT_TO_FLOAT/1',          # need some messy code in the backend
     'CAST_FLOAT_TO_SINGLEFLOAT/1',
     'CAST_SINGLEFLOAT_TO_FLOAT/1',
+    'CONVERT_FLOAT_BYTES_TO_LONGLONG/1',
     #
     'INT_LT/2b',
     'INT_LE/2b',
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3,6 +3,7 @@
 import py
 
 from pypy import conftest
+from pypy.jit.codewriter import longlong
 from pypy.jit.codewriter.policy import JitPolicy, StopAtXPolicy
 from pypy.jit.metainterp import pyjitpl, history
 from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT
@@ -14,6 +15,7 @@
     loop_invariant, elidable, promote, jit_debug, assert_green,
     AssertGreenFailed, unroll_safe, current_trace_length, look_inside_iff,
     isconstant, isvirtual, promote_string, set_param, record_known_class)
+from pypy.rlib.longlong2float import float2longlong
 from pypy.rlib.rarithmetic import ovfcheck, is_valid_int
 from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rpython.ootypesystem import ootype
@@ -292,7 +294,7 @@
         assert res == f(6, sys.maxint, 32, 48)
         res = self.meta_interp(f, [sys.maxint, 6, 32, 48])
         assert res == f(sys.maxint, 6, 32, 48)
-        
+
 
     def test_loop_invariant_intbox(self):
         myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
@@ -953,7 +955,7 @@
         self.meta_interp(f, [20], repeat=7)
         # the loop and the entry path as a single trace
         self.check_jitcell_token_count(1)
-        
+
         # we get:
         #    ENTER             - compile the new loop and the entry bridge
         #    ENTER             - compile the leaving path
@@ -1470,7 +1472,7 @@
         assert res == f(299)
         self.check_resops(guard_class=0, guard_nonnull=4,
                           guard_nonnull_class=4, guard_isnull=2)
-        
+
 
     def test_merge_guardnonnull_guardvalue(self):
         from pypy.rlib.objectmodel import instantiate
@@ -1499,7 +1501,7 @@
         assert res == f(299)
         self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4,
                           guard_nonnull_class=0, guard_isnull=2)
-        
+
 
     def test_merge_guardnonnull_guardvalue_2(self):
         from pypy.rlib.objectmodel import instantiate
@@ -1528,7 +1530,7 @@
         assert res == f(299)
         self.check_resops(guard_value=4, guard_class=0, guard_nonnull=4,
                           guard_nonnull_class=0, guard_isnull=2)
-        
+
 
     def test_merge_guardnonnull_guardclass_guardvalue(self):
         from pypy.rlib.objectmodel import instantiate
@@ -2636,7 +2638,7 @@
             return sa
         assert self.meta_interp(f, [20]) == f(20)
         self.check_resops(int_lt=6, int_le=2, int_ge=4, int_gt=3)
-        
+
 
     def test_intbounds_not_generalized2(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'node'])
@@ -2677,7 +2679,7 @@
         assert self.meta_interp(f, [20, 3]) == f(20, 3)
         self.check_jitcell_token_count(1)
         self.check_target_token_count(5)
-        
+
     def test_max_retrace_guards(self):
         myjitdriver = JitDriver(greens = [], reds = ['n', 'i', 'sa', 'a'])
 
@@ -2815,7 +2817,7 @@
         for cell in get_stats().get_all_jitcell_tokens():
             # Initialal trace with two labels and 5 retraces
             assert len(cell.target_tokens) <= 7
-            
+
     def test_nested_retrace(self):
 
         myjitdriver = JitDriver(greens = ['pc'], reds = ['n', 'a', 'i', 'j', 'sa'])
@@ -3793,6 +3795,16 @@
         res = self.interp_operations(g, [1])
         assert res == 3
 
+    def test_float2longlong(self):
+        def f(n):
+            return float2longlong(n)
+
+        for x in [2.5, float("nan"), -2.5, float("inf")]:
+            # There are tests elsewhere to verify the correctness of this.
+            expected = float2longlong(x)
+            res = self.interp_operations(f, [x])
+            assert longlong.getfloatstorage(res) == expected
+
 
 class TestLLtype(BaseLLtypeTests, LLJitMixin):
     def test_tagged(self):
diff --git a/pypy/rlib/bitmanipulation.py b/pypy/rlib/bitmanipulation.py
--- a/pypy/rlib/bitmanipulation.py
+++ b/pypy/rlib/bitmanipulation.py
@@ -1,5 +1,6 @@
 from pypy.rlib import unroll
 
+
 class BitSplitter(dict):
     def __getitem__(self, lengths):
         if isinstance(lengths, int):
diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py
--- a/pypy/rlib/longlong2float.py
+++ b/pypy/rlib/longlong2float.py
@@ -5,7 +5,12 @@
 long long to a float and back to a long long.  There are corner cases
 in which it does not work.
 """
+
+from pypy.annotation import model as annmodel
+from pypy.rlib.rarithmetic import r_int64
 from pypy.rpython.lltypesystem import lltype, rffi
+from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.translator.tool.cbuild import ExternalCompilationInfo
 
 
 # -------- implement longlong2float and float2longlong --------
@@ -16,38 +21,33 @@
 
 # these definitions are used only in tests, when not translated
 def longlong2float_emulator(llval):
-    d_array = lltype.malloc(DOUBLE_ARRAY_PTR.TO, 1, flavor='raw')
-    ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
-    ll_array[0] = llval
-    floatval = d_array[0]
-    lltype.free(d_array, flavor='raw')
-    return floatval
+    with lltype.scoped_alloc(DOUBLE_ARRAY_PTR.TO, 1) as d_array:
+        ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
+        ll_array[0] = llval
+        floatval = d_array[0]
+        return floatval
 
-def float2longlong_emulator(floatval):
-    d_array = lltype.malloc(DOUBLE_ARRAY_PTR.TO, 1, flavor='raw')
-    ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
-    d_array[0] = floatval
-    llval = ll_array[0]
-    lltype.free(d_array, flavor='raw')
-    return llval
+def float2longlong(floatval):
+    with lltype.scoped_alloc(DOUBLE_ARRAY_PTR.TO, 1) as d_array:
+        ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
+        d_array[0] = floatval
+        llval = ll_array[0]
+        return llval
 
 def uint2singlefloat_emulator(ival):
-    f_array = lltype.malloc(FLOAT_ARRAY_PTR.TO, 1, flavor='raw')
-    i_array = rffi.cast(UINT_ARRAY_PTR, f_array)
-    i_array[0] = ival
-    singlefloatval = f_array[0]
-    lltype.free(f_array, flavor='raw')
-    return singlefloatval
+    with lltype.scoped_alloc(FLOAT_ARRAY_PTR.TO, 1) as f_array:
+        i_array = rffi.cast(UINT_ARRAY_PTR, f_array)
+        i_array[0] = ival
+        singlefloatval = f_array[0]
+        return singlefloatval
 
 def singlefloat2uint_emulator(singlefloatval):
-    f_array = lltype.malloc(FLOAT_ARRAY_PTR.TO, 1, flavor='raw')
-    i_array = rffi.cast(UINT_ARRAY_PTR, f_array)
-    f_array[0] = singlefloatval
-    ival = i_array[0]
-    lltype.free(f_array, flavor='raw')
-    return ival
+    with lltype.scoped_alloc(FLOAT_ARRAY_PTR.TO, 1) as f_array:
+        i_array = rffi.cast(UINT_ARRAY_PTR, f_array)
+        f_array[0] = singlefloatval
+        ival = i_array[0]
+        return ival
 
-from pypy.translator.tool.cbuild import ExternalCompilationInfo
 eci = ExternalCompilationInfo(includes=['string.h', 'assert.h'],
                               post_include_bits=["""
 static double pypy__longlong2float(long long x) {
@@ -56,12 +56,6 @@
     memcpy(&dd, &x, 8);
     return dd;
 }
-static long long pypy__float2longlong(double x) {
-    long long ll;
-    assert(sizeof(double) == 8 && sizeof(long long) == 8);
-    memcpy(&ll, &x, 8);
-    return ll;
-}
 static float pypy__uint2singlefloat(unsigned int x) {
     float ff;
     assert(sizeof(float) == 4 && sizeof(unsigned int) == 4);
@@ -82,12 +76,6 @@
     _nowrapper=True, elidable_function=True, sandboxsafe=True,
     oo_primitive="pypy__longlong2float")
 
-float2longlong = rffi.llexternal(
-    "pypy__float2longlong", [rffi.DOUBLE], rffi.LONGLONG,
-    _callable=float2longlong_emulator, compilation_info=eci,
-    _nowrapper=True, elidable_function=True, sandboxsafe=True,
-    oo_primitive="pypy__float2longlong")
-
 uint2singlefloat = rffi.llexternal(
     "pypy__uint2singlefloat", [rffi.UINT], rffi.FLOAT,
     _callable=uint2singlefloat_emulator, compilation_info=eci,
@@ -99,3 +87,15 @@
     _callable=singlefloat2uint_emulator, compilation_info=eci,
     _nowrapper=True, elidable_function=True, sandboxsafe=True,
     oo_primitive="pypy__singlefloat2uint")
+
+
+class Float2LongLongEntry(ExtRegistryEntry):
+    _about_ = float2longlong
+
+    def compute_result_annotation(self, s_float):
+        assert annmodel.SomeFloat().contains(s_float)
+        return annmodel.SomeInteger(knowntype=r_int64)
+
+    def specialize_call(self, hop):
+        [v_float] = hop.inputargs(lltype.Float)
+        return hop.genop("convert_float_bytes_to_longlong", [v_float], resulttype=hop.r_result)
diff --git a/pypy/rlib/rfloat.py b/pypy/rlib/rfloat.py
--- a/pypy/rlib/rfloat.py
+++ b/pypy/rlib/rfloat.py
@@ -1,11 +1,13 @@
 """Float constants"""
 
 import math
+
+from pypy.annotation.model import SomeString
+from pypy.rlib import objectmodel
+from pypy.rpython.extfunc import register_external
 from pypy.rpython.tool import rffi_platform
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rlib import objectmodel
-from pypy.rpython.extfunc import register_external
-from pypy.annotation.model import SomeString
+
 
 USE_SHORT_FLOAT_REPR = True # XXX make it a translation option?
 
@@ -74,7 +76,7 @@
         while i < len(s) and s[i] in '0123456789':
             after_point += s[i]
             i += 1
-            
+
         if i == len(s):
             return sign, before_point, after_point, exponent
 
@@ -91,7 +93,7 @@
 
     if i == len(s):
         raise ValueError
-    
+
     while i < len(s) and s[i] in '0123456789':
         exponent += s[i]
         i += 1
diff --git a/pypy/rlib/rstruct/nativefmttable.py b/pypy/rlib/rstruct/nativefmttable.py
--- a/pypy/rlib/rstruct/nativefmttable.py
+++ b/pypy/rlib/rstruct/nativefmttable.py
@@ -3,14 +3,17 @@
 The table 'native_fmttable' is also used by pypy.module.array.interp_array.
 """
 import struct
-from pypy.rlib import jit
+
+from pypy.rlib import jit, longlong2float
+from pypy.rlib.objectmodel import specialize
+from pypy.rlib.rarithmetic import r_singlefloat, widen
 from pypy.rlib.rstruct import standardfmttable as std
 from pypy.rlib.rstruct.error import StructError
+from pypy.rlib.unroll import unrolling_iterable
+from pypy.rpython.lltypesystem import lltype, rffi
 from pypy.rpython.tool import rffi_platform
-from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.rlib.rarithmetic import r_singlefloat
 from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rlib.objectmodel import specialize
+
 
 native_is_bigendian = struct.pack("=i", 1) == struct.pack(">i", 1)
 
@@ -23,18 +26,24 @@
 
 # ____________________________________________________________
 
+
 double_buf = lltype.malloc(rffi.DOUBLEP.TO, 1, flavor='raw', immortal=True)
 float_buf = lltype.malloc(rffi.FLOATP.TO, 1, flavor='raw', immortal=True)
 
- at jit.dont_look_inside
-def double_to_ccharp(doubleval):
-    double_buf[0] = doubleval
-    return rffi.cast(rffi.CCHARP, double_buf)
+range_8_unroll = unrolling_iterable(list(reversed(range(8))))
+range_4_unroll = unrolling_iterable(list(reversed(range(4))))
 
 def pack_double(fmtiter):
     doubleval = fmtiter.accept_float_arg()
-    p = double_to_ccharp(doubleval)
-    fmtiter.result.append_charpsize(p, rffi.sizeof(rffi.DOUBLE))
+    value = longlong2float.float2longlong(doubleval)
+    if fmtiter.bigendian:
+        for i in range_8_unroll:
+            x = (value >> (8*i)) & 0xff
+            fmtiter.result.append(chr(x))
+    else:
+        for i in range_8_unroll:
+            fmtiter.result.append(chr(value & 0xff))
+            value >>= 8
 
 @specialize.argtype(0)
 def unpack_double(fmtiter):
@@ -45,16 +54,19 @@
     doubleval = double_buf[0]
     fmtiter.appendobj(doubleval)
 
- at jit.dont_look_inside
-def float_to_ccharp(floatval):
-    float_buf[0] = floatval
-    return rffi.cast(rffi.CCHARP, float_buf)
-
 def pack_float(fmtiter):
     doubleval = fmtiter.accept_float_arg()
     floatval = r_singlefloat(doubleval)
-    p = float_to_ccharp(floatval)
-    fmtiter.result.append_charpsize(p, rffi.sizeof(rffi.FLOAT))
+    value = longlong2float.singlefloat2uint(floatval)
+    value = widen(value)
+    if fmtiter.bigendian:
+        for i in range_4_unroll:
+            x = (value >> (8*i)) & 0xff
+            fmtiter.result.append(chr(x))
+    else:
+        for i in range_4_unroll:
+            fmtiter.result.append(chr(value & 0xff))
+            value >>= 8
 
 @specialize.argtype(0)
 def unpack_float(fmtiter):
diff --git a/pypy/rlib/rstruct/standardfmttable.py b/pypy/rlib/rstruct/standardfmttable.py
--- a/pypy/rlib/rstruct/standardfmttable.py
+++ b/pypy/rlib/rstruct/standardfmttable.py
@@ -6,11 +6,12 @@
 # values when packing.
 
 import struct
+
+from pypy.rlib.objectmodel import specialize
+from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
+from pypy.rlib.rstruct import ieee
 from pypy.rlib.rstruct.error import StructError, StructOverflowError
-from pypy.rlib.rstruct import ieee
 from pypy.rlib.unroll import unrolling_iterable
-from pypy.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
-from pypy.rlib.objectmodel import specialize
 
 # In the CPython struct module, pack() unconsistently accepts inputs
 # that are out-of-range or floats instead of ints.  Should we emulate
diff --git a/pypy/translator/c/src/float.h b/pypy/translator/c/src/float.h
--- a/pypy/translator/c/src/float.h
+++ b/pypy/translator/c/src/float.h
@@ -27,7 +27,7 @@
 #define OP_FLOAT_SUB(x,y,r)     r = x - y
 #define OP_FLOAT_MUL(x,y,r)     r = x * y
 #define OP_FLOAT_TRUEDIV(x,y,r) r = x / y
-#define OP_FLOAT_POW(x,y,r)     r = pow(x, y) 
+#define OP_FLOAT_POW(x,y,r)     r = pow(x, y)
 
 /*** conversions ***/
 
@@ -42,5 +42,6 @@
 #ifdef HAVE_LONG_LONG
 #define OP_CAST_FLOAT_TO_LONGLONG(x,r) r = (long long)(x)
 #define OP_CAST_FLOAT_TO_ULONGLONG(x,r) r = (unsigned long long)(x)
+#define OP_CONVERT_FLOAT_BYTES_TO_LONGLONG(x,r) memcpy(&r, &x, sizeof(double))
 #endif
 


More information about the pypy-commit mailing list