[pypy-commit] pypy default: Add a utility to convert longlong's bytes to a double.
alex_gaynor
noreply at buildbot.pypy.org
Tue Mar 27 23:27:59 CEST 2012
Author: Alex Gaynor <alex.gaynor at gmail.com>
Branch:
Changeset: r54037:4d18306a2fb3
Date: 2012-03-27 17:27 -0400
http://bitbucket.org/pypy/pypy/changeset/4d18306a2fb3/
Log: Add a utility to convert longlong's bytes to a double.
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
@@ -27,6 +27,12 @@
def constfloat(x):
return ConstFloat(longlong.getfloatstorage(x))
+def boxlonglong(ll):
+ if longlong.is_64_bit:
+ return BoxInt(ll)
+ else:
+ return BoxFloat(ll)
+
class Runner(object):
@@ -1623,6 +1629,11 @@
[boxfloat(2.5)], t).value
assert res == longlong2float.float2longlong(2.5)
+ bytes = longlong2float.float2longlong(2.5)
+ res = self.execute_operation(rop.CONVERT_LONGLONG_BYTES_TO_FLOAT,
+ [boxlonglong(res)], 'float').value
+ assert longlong.getrealfloat(res) == 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
@@ -328,6 +328,15 @@
def produce_into(self, builder, r):
self.put(builder, [r.choice(builder.intvars)])
+class CastLongLongToFloatOperation(AbstractFloatOperation):
+ def produce_into(self, builder, r):
+ if longlong.is_64_bit:
+ self.put(builder, [r.choice(builder.intvars)])
+ else:
+ if not builder.floatvars:
+ raise CannotProduceOperation
+ self.put(builder, [r.choice(builder.floatvars)])
+
class CastFloatToIntOperation(AbstractFloatOperation):
def produce_into(self, builder, r):
if not builder.floatvars:
@@ -450,6 +459,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))
+OPERATIONS.append(CastLongLongToFloatOperation(rop.CONVERT_LONGLONG_BYTES_TO_FLOAT))
OperationBuilder.OPERATIONS = OPERATIONS
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
@@ -1251,6 +1251,15 @@
else:
self.mov(loc0, resloc)
+ def genop_convert_longlong_bytes_to_float(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
@@ -773,10 +773,24 @@
self.Perform(op, [loc0], loc1)
self.xrm.possibly_free_var(op.getarg(0))
else:
- loc0 = self.xrm.loc(op.getarg(0))
+ arg0 = op.getarg(0)
+ loc0 = self.xrm.loc(arg0)
+ loc1 = self.xrm.force_allocate_reg(op.result, forbidden_vars=[arg0])
+ self.Perform(op, [loc0], loc1)
+ self.xrm.possibly_free_var(arg0)
+
+ def consider_convert_longlong_bytes_to_float(self, op):
+ if longlong.is_64_bit:
+ loc0 = self.rm.make_sure_var_in_reg(op.getarg(0))
loc1 = self.xrm.force_allocate_reg(op.result)
self.Perform(op, [loc0], loc1)
- self.xrm.possibly_free_var(op.getarg(0))
+ self.rm.possibly_free_var(op.getarg(0))
+ else:
+ arg0 = op.getarg(0)
+ loc0 = self.xrm.make_sure_var_in_reg(arg0)
+ loc1 = self.xrm.force_allocate_reg(op.result, forbidden_vars=[arg0])
+ self.Perform(op, [loc0], loc1)
+ self.xrm.possibly_free_var(arg0)
def _consider_llong_binop_xx(self, op):
# must force both arguments into xmm registers, because we don't
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
@@ -295,6 +295,7 @@
return op
rewrite_op_convert_float_bytes_to_longlong = _noop_rewrite
+ rewrite_op_convert_longlong_bytes_to_float = _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,20 +968,22 @@
int_return %i2
""", transform=True)
- def test_convert_float_bytes_to_int(self):
- from pypy.rlib.longlong2float import float2longlong
+ def test_convert_float_bytes(self):
+ from pypy.rlib.longlong2float import float2longlong, longlong2float
def f(x):
- return float2longlong(x)
+ ll = float2longlong(x)
+ return longlong2float(ll)
if longlong.is_64_bit:
- result_var = "%i0"
- return_op = "int_return"
+ tmp_var = "%i0"
+ result_var = "%f1"
else:
- result_var = "%f1"
- return_op = "float_return"
+ tmp_var = "%f1"
+ result_var = "%f2"
self.encoding_test(f, [25.0], """
- convert_float_bytes_to_longlong %%f0 -> %(result_var)s
- %(return_op)s %(result_var)s
- """ % {"result_var": result_var, "return_op": return_op})
+ convert_float_bytes_to_longlong %%f0 -> %(tmp_var)s
+ convert_longlong_bytes_to_float %(tmp_var)s -> %(result_var)s
+ float_return %(result_var)s
+ """ % {"result_var": result_var, "tmp_var": tmp_var}, transform=True)
def check_force_cast(FROM, TO, operations, value):
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
@@ -672,6 +672,11 @@
a = longlong.getrealfloat(a)
return longlong2float.float2longlong(a)
+ @arguments(LONGLONG_TYPECODE, returns="f")
+ def bhimpl_convert_longlong_bytes_to_float(a):
+ a = longlong2float.longlong2float(a)
+ return longlong.getfloatstorage(a)
+
# ----------
# control flow operations
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
@@ -224,6 +224,7 @@
'float_neg', 'float_abs',
'cast_ptr_to_int', 'cast_int_to_ptr',
'convert_float_bytes_to_longlong',
+ 'convert_longlong_bytes_to_float',
]:
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
@@ -420,6 +420,7 @@
'CAST_FLOAT_TO_SINGLEFLOAT/1',
'CAST_SINGLEFLOAT_TO_FLOAT/1',
'CONVERT_FLOAT_BYTES_TO_LONGLONG/1',
+ 'CONVERT_LONGLONG_BYTES_TO_FLOAT/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
@@ -1,3 +1,4 @@
+import math
import sys
import py
@@ -15,7 +16,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.longlong2float import float2longlong, longlong2float
from pypy.rlib.rarithmetic import ovfcheck, is_valid_int
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.ootypesystem import ootype
@@ -3795,15 +3796,15 @@
res = self.interp_operations(g, [1])
assert res == 3
- def test_float2longlong(self):
+ def test_float_bytes(self):
def f(n):
- return float2longlong(n)
+ ll = float2longlong(n)
+ return longlong2float(ll)
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
+ assert res == x or math.isnan(x) and math.isnan(res)
class TestLLtype(BaseLLtypeTests, LLJitMixin):
diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py
--- a/pypy/rlib/longlong2float.py
+++ b/pypy/rlib/longlong2float.py
@@ -21,7 +21,7 @@
FLOAT_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.FLOAT))
# these definitions are used only in tests, when not translated
-def longlong2float_emulator(llval):
+def longlong2float(llval):
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
@@ -51,12 +51,6 @@
eci = ExternalCompilationInfo(includes=['string.h', 'assert.h'],
post_include_bits=["""
-static double pypy__longlong2float(long long x) {
- double dd;
- assert(sizeof(double) == 8 && sizeof(long long) == 8);
- memcpy(&dd, &x, 8);
- return dd;
-}
static float pypy__uint2singlefloat(unsigned int x) {
float ff;
assert(sizeof(float) == 4 && sizeof(unsigned int) == 4);
@@ -71,12 +65,6 @@
}
"""])
-longlong2float = rffi.llexternal(
- "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE,
- _callable=longlong2float_emulator, compilation_info=eci,
- _nowrapper=True, elidable_function=True, sandboxsafe=True,
- oo_primitive="pypy__longlong2float")
-
uint2singlefloat = rffi.llexternal(
"pypy__uint2singlefloat", [rffi.UINT], rffi.FLOAT,
_callable=uint2singlefloat_emulator, compilation_info=eci,
@@ -99,4 +87,17 @@
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)
+ hop.exception_cannot_occur()
+ return hop.genop("convert_float_bytes_to_longlong", [v_float], resulttype=lltype.SignedLongLong)
+
+class LongLong2FloatEntry(ExtRegistryEntry):
+ _about_ = longlong2float
+
+ def compute_result_annotation(self, s_longlong):
+ assert annmodel.SomeInteger(knowntype=r_int64).contains(s_longlong)
+ return annmodel.SomeFloat()
+
+ def specialize_call(self, hop):
+ [v_longlong] = hop.inputargs(lltype.SignedLongLong)
+ hop.exception_cannot_occur()
+ return hop.genop("convert_longlong_bytes_to_float", [v_longlong], resulttype=lltype.Float)
diff --git a/pypy/rlib/test/test_longlong2float.py b/pypy/rlib/test/test_longlong2float.py
--- a/pypy/rlib/test/test_longlong2float.py
+++ b/pypy/rlib/test/test_longlong2float.py
@@ -2,6 +2,7 @@
from pypy.rlib.longlong2float import longlong2float, float2longlong
from pypy.rlib.longlong2float import uint2singlefloat, singlefloat2uint
from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rpython.test.test_llinterp import interpret
def fn(f1):
@@ -31,6 +32,18 @@
res = fn2(x)
assert repr(res) == repr(x)
+def test_interpreted():
+ def f(f1):
+ try:
+ ll = float2longlong(f1)
+ return longlong2float(ll)
+ except Exception:
+ return 500
+
+ for x in enum_floats():
+ res = interpret(f, [x])
+ assert repr(res) == repr(x)
+
# ____________________________________________________________
def fnsingle(f1):
diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -350,6 +350,7 @@
'truncate_longlong_to_int':LLOp(canfold=True),
'force_cast': LLOp(sideeffects=False), # only for rffi.cast()
'convert_float_bytes_to_longlong': LLOp(canfold=True),
+ 'convert_longlong_bytes_to_float': LLOp(canfold=True),
# __________ pointer operations __________
diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py
--- a/pypy/rpython/lltypesystem/opimpl.py
+++ b/pypy/rpython/lltypesystem/opimpl.py
@@ -431,6 +431,10 @@
from pypy.rlib.longlong2float import float2longlong
return float2longlong(a)
+def op_convert_longlong_bytes_to_float(a):
+ from pypy.rlib.longlong2float import longlong2float
+ return longlong2float(a)
+
def op_unichar_eq(x, y):
assert isinstance(x, unicode) and len(x) == 1
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
@@ -43,5 +43,6 @@
#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))
+#define OP_CONVERT_LONGLONG_BYTES_TO_FLOAT(x,r) memcpy(&r, &x, sizeof(long long))
#endif
diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py
--- a/pypy/translator/jvm/opcodes.py
+++ b/pypy/translator/jvm/opcodes.py
@@ -243,4 +243,5 @@
'force_cast': [PushAllArgs, CastPrimitive, StoreResult],
'convert_float_bytes_to_longlong': jvm.PYPYDOUBLEBYTESTOLONG,
+ 'convert_longlong_bytes_to_float': jvm.PYPYLONGBYTESTODOUBLE,
})
diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py
--- a/pypy/translator/jvm/typesystem.py
+++ b/pypy/translator/jvm/typesystem.py
@@ -942,6 +942,7 @@
PYPYULONGTODOUBLE = Method.s(jPyPy, 'ulong_to_double', (jLong,), jDouble)
PYPYLONGBITWISENEGATE = Method.v(jPyPy, 'long_bitwise_negate', (jLong,), jLong)
PYPYDOUBLEBYTESTOLONG = Method.v(jPyPy, 'pypy__float2longlong', (jDouble,), jLong)
+PYPYLONGBYTESTODOUBLE = Method.v(jPyPy, 'pypy__longlong2float', (jLong,), jDouble)
PYPYSTRTOINT = Method.v(jPyPy, 'str_to_int', (jString,), jInt)
PYPYSTRTOUINT = Method.v(jPyPy, 'str_to_uint', (jString,), jInt)
PYPYSTRTOLONG = Method.v(jPyPy, 'str_to_long', (jString,), jLong)
More information about the pypy-commit
mailing list