[pypy-svn] pypy arm-backend-2: merge default
bivab
commits-noreply at bitbucket.org
Wed Feb 2 13:50:28 CET 2011
Author: David Schneider <david.schneider at picle.org>
Branch: arm-backend-2
Changeset: r41553:ac3fe5c04e9b
Date: 2011-01-29 17:30 +0100
http://bitbucket.org/pypy/pypy/changeset/ac3fe5c04e9b/
Log: merge default
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -1045,20 +1045,6 @@
except OverflowError:
self.make_llexception()
- def op_llong_neg_ovf(self, x):
- assert type(x) is r_longlong
- try:
- return ovfcheck(-x)
- except OverflowError:
- self.make_llexception()
-
- def op_llong_abs_ovf(self, x):
- assert type(x) is r_longlong
- try:
- return ovfcheck(abs(x))
- except OverflowError:
- self.make_llexception()
-
def op_int_lshift_ovf(self, x, y):
assert isinstance(x, int)
assert isinstance(y, int)
diff --git a/pypy/interpreter/argument.py b/pypy/interpreter/argument.py
--- a/pypy/interpreter/argument.py
+++ b/pypy/interpreter/argument.py
@@ -154,6 +154,8 @@
# unpack the ** arguments
space = self.space
if space.isinstance_w(w_starstararg, space.w_dict):
+ if not space.is_true(w_starstararg):
+ return False # don't call unpackiterable - it's jit-opaque
keys_w = space.unpackiterable(w_starstararg)
else:
try:
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -199,6 +199,8 @@
error = CANNOT_FAIL
if type(error) is int:
error = rffi.cast(restype, error)
+ expect_integer = (isinstance(restype, lltype.Primitive) and
+ rffi.cast(restype, 0) == 0)
def decorate(func):
func_name = func.func_name
@@ -268,6 +270,9 @@
return None
else:
return api_function.error_value
+ if not we_are_translated():
+ got_integer = isinstance(res, (int, long, float))
+ assert got_integer == expect_integer
if res is None:
return None
elif isinstance(res, Reference):
diff --git a/pypy/objspace/std/callmethod.py b/pypy/objspace/std/callmethod.py
--- a/pypy/objspace/std/callmethod.py
+++ b/pypy/objspace/std/callmethod.py
@@ -104,7 +104,10 @@
if w_self is None:
f.popvalue() # removes w_self, which is None
w_callable = f.popvalue()
- w_result = f.space.call_args(w_callable, args)
+ if f.is_being_profiled and function.is_builtin_code(w_callable):
+ w_result = f.space.call_args_and_c_profile(f, w_callable, args)
+ else:
+ w_result = f.space.call_args(w_callable, args)
rstack.resume_point("CALL_METHOD_KW", f, returns=w_result)
f.pushvalue(w_result)
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
@@ -39,6 +39,7 @@
def optimize_block(self, block):
if block.operations == ():
return
+ self.remove_longlong_constants(block)
self.vable_array_vars = {}
self.vable_flags = {}
renamings = {}
@@ -134,6 +135,55 @@
block.exits = block.exits[:1]
block.exitswitch = None
+ def remove_longlong_constants(self, block):
+ # remove all Constant({Un}signedLongLong), and replace them with
+ # cast_int_to_longlong(Constant(Signed)) or
+ # two_ints_to_longlong(Constant(Signed), Constant(Signed)).
+ operations = []
+ all_constants = {}
+ #
+ def _get_const_as_var(c):
+ v = all_constants.get(c)
+ if v is None:
+ from pypy.rlib.rarithmetic import intmask
+ v = varoftype(c.concretetype)
+ value = int(c.value)
+ c_hi = Constant(intmask(value >> 32), lltype.Signed)
+ c_lo = Constant(intmask(value), lltype.Signed)
+ if c_lo.value == value:
+ # a long long constant, but it fits in 32 bits
+ op1 = SpaceOperation('cast_int_to_longlong', [c_lo], v)
+ else:
+ # a 64-bit long long constant, requires two ints
+ op1 = SpaceOperation('two_ints_to_longlong', [c_lo, c_hi],
+ v)
+ operations.append(op1)
+ all_constants[c] = v
+ return v
+ #
+ for op in block.operations:
+ for i, v in enumerate(op.args):
+ if (isinstance(v, Constant) and
+ self._is_longlong(v.concretetype)):
+ args = op.args[:]
+ args[i] = _get_const_as_var(v)
+ op = SpaceOperation(op.opname, args, op.result)
+ operations.append(op)
+ #
+ last_op = None
+ if block.exitswitch == c_last_exception:
+ last_op = operations.pop()
+ for link in block.exits:
+ for i, v in enumerate(link.args):
+ if (isinstance(v, Constant) and
+ self._is_longlong(v.concretetype)):
+ args = link.args[:]
+ args[i] = _get_const_as_var(v)
+ link.args = args
+ if last_op is not None:
+ operations.append(last_op)
+ block.operations = operations
+
# ----------
def follow_constant_exit(self, block):
@@ -199,7 +249,6 @@
rewrite_op_cast_pointer = rewrite_op_same_as
rewrite_op_cast_opaque_ptr = rewrite_op_same_as # rlib.rerased
- def rewrite_op_cast_primitive(self, op): pass
def rewrite_op_cast_bool_to_int(self, op): pass
def rewrite_op_cast_bool_to_uint(self, op): pass
def rewrite_op_cast_char_to_int(self, op): pass
@@ -424,6 +473,15 @@
rewrite_op_int_mod_zer = _do_builtin_call
rewrite_op_int_lshift_ovf = _do_builtin_call
rewrite_op_int_abs = _do_builtin_call
+ rewrite_op_llong_abs = _do_builtin_call
+ rewrite_op_llong_floordiv = _do_builtin_call
+ rewrite_op_llong_floordiv_zer = _do_builtin_call
+ rewrite_op_llong_mod = _do_builtin_call
+ rewrite_op_llong_mod_zer = _do_builtin_call
+ rewrite_op_ullong_floordiv = _do_builtin_call
+ rewrite_op_ullong_floordiv_zer = _do_builtin_call
+ rewrite_op_ullong_mod = _do_builtin_call
+ rewrite_op_ullong_mod_zer = _do_builtin_call
rewrite_op_gc_identityhash = _do_builtin_call
rewrite_op_gc_id = _do_builtin_call
@@ -779,6 +837,116 @@
return result
# ----------
+ # Long longs, for 32-bit only. Supported operations are left unmodified,
+ # and unsupported ones are turned into a call to a function from
+ # jit.codewriter.support.
+
+ if lltype.SignedLongLong != lltype.Signed:
+ @staticmethod
+ def _is_longlong(TYPE):
+ return (TYPE == lltype.SignedLongLong or
+ TYPE == lltype.UnsignedLongLong)
+ else:
+ # on 64-bit, _is_longlong() returns always False
+ @staticmethod
+ def _is_longlong(TYPE):
+ return False
+
+ for _op, _oopspec in [('llong_invert', 'INVERT'),
+ ('ullong_invert', 'INVERT'),
+ ('llong_lt', 'LT'),
+ ('llong_le', 'LE'),
+ ('llong_eq', 'EQ'),
+ ('llong_ne', 'NE'),
+ ('llong_gt', 'GT'),
+ ('llong_ge', 'GE'),
+ ('ullong_lt', 'ULT'),
+ ('ullong_le', 'ULE'),
+ ('ullong_eq', 'EQ'),
+ ('ullong_ne', 'NE'),
+ ('ullong_gt', 'UGT'),
+ ('ullong_ge', 'UGE'),
+ ('llong_add', 'ADD'),
+ ('llong_sub', 'SUB'),
+ ('llong_mul', 'MUL'),
+ ('llong_and', 'AND'),
+ ('llong_or', 'OR'),
+ ('llong_xor', 'XOR'),
+ ('ullong_add', 'ADD'),
+ ('ullong_sub', 'SUB'),
+ ('ullong_mul', 'MUL'),
+ ('ullong_and', 'AND'),
+ ('ullong_or', 'OR'),
+ ('ullong_xor', 'XOR'),
+ ('llong_lshift', 'LSHIFT'),
+ ('llong_rshift', 'RSHIFT'),
+ ('ullong_lshift', 'LSHIFT'),
+ ('ullong_rshift', 'URSHIFT'),
+ ('cast_int_to_longlong', 'FROM_INT'),
+ ('truncate_longlong_to_int', 'TO_INT'),
+ ('cast_float_to_longlong', 'FROM_FLOAT'),
+ ('cast_longlong_to_float', 'TO_FLOAT'),
+ # internal pseuso-operation:
+ ('two_ints_to_longlong', 'FROM_TWO_INTS'),
+ ]:
+ exec py.code.Source('''
+ def rewrite_op_%s(self, op):
+ args = op.args
+ op1 = self.prepare_builtin_call(op, "llong_%s", args)
+ op2 = self._handle_oopspec_call(op1, args,
+ EffectInfo.OS_LLONG_%s,
+ EffectInfo.EF_PURE)
+ return op2
+ ''' % (_op, _oopspec.lower(), _oopspec)).compile()
+
+ def _normalize(self, oplist):
+ if isinstance(oplist, SpaceOperation):
+ return [oplist]
+ else:
+ assert type(oplist) is list
+ return oplist
+
+ def rewrite_op_llong_neg(self, op):
+ v = varoftype(lltype.SignedLongLong)
+ op0 = SpaceOperation('cast_int_to_longlong',
+ [Constant(0, lltype.Signed)],
+ v)
+ args = [v, op.args[0]]
+ op1 = SpaceOperation('llong_sub', args, op.result)
+ return (self._normalize(self.rewrite_operation(op0)) +
+ self._normalize(self.rewrite_operation(op1)))
+
+ def rewrite_op_llong_is_true(self, op):
+ v = varoftype(lltype.SignedLongLong)
+ op0 = SpaceOperation('cast_int_to_longlong',
+ [Constant(0, lltype.Signed)],
+ v)
+ args = [op.args[0], v]
+ op1 = SpaceOperation('llong_ne', args, op.result)
+ return (self._normalize(self.rewrite_operation(op0)) +
+ self._normalize(self.rewrite_operation(op1)))
+
+ rewrite_op_ullong_is_true = rewrite_op_llong_is_true
+
+ def rewrite_op_cast_primitive(self, op):
+ fromll = self._is_longlong(op.args[0].concretetype)
+ toll = self._is_longlong(op.result.concretetype)
+ if fromll != toll:
+ args = op.args
+ if fromll:
+ opname = 'truncate_longlong_to_int'
+ else:
+ from pypy.rpython.lltypesystem import rffi
+ if rffi.cast(op.args[0].concretetype, -1) < 0:
+ opname = 'cast_int_to_longlong'
+ else:
+ opname = 'two_ints_to_longlong'
+ c_hi = Constant(0, lltype.Signed)
+ args = [args[0], c_hi]
+ op1 = SpaceOperation(opname, args, op.result)
+ return self.rewrite_operation(op1)
+
+ # ----------
# Renames, from the _old opname to the _new one.
# The new operation is optionally further processed by rewrite_operation().
for _old, _new in [('bool_not', 'int_is_zero'),
@@ -1107,9 +1275,11 @@
# Strings and Unicodes.
def _handle_oopspec_call(self, op, args, oopspecindex, extraeffect=None):
- calldescr = self.callcontrol.getcalldescr(op, oopspecindex)
- if extraeffect:
- calldescr.get_extra_info().extraeffect = extraeffect
+ calldescr = self.callcontrol.getcalldescr(op, oopspecindex,
+ extraeffect)
+ if extraeffect is not None:
+ assert (type(calldescr) is str # for tests
+ or calldescr.get_extra_info().extraeffect == extraeffect)
if isinstance(op.args[0].value, str):
pass # for tests only
else:
diff --git a/pypy/jit/metainterp/test/test_basic.py b/pypy/jit/metainterp/test/test_basic.py
--- a/pypy/jit/metainterp/test/test_basic.py
+++ b/pypy/jit/metainterp/test/test_basic.py
@@ -7,6 +7,7 @@
from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
from pypy.jit.backend.llgraph import runner
from pypy.jit.metainterp import pyjitpl, history
+from pypy.jit.metainterp.warmstate import set_future_value
from pypy.jit.codewriter.policy import JitPolicy, StopAtXPolicy
from pypy import conftest
from pypy.rlib.rarithmetic import ovfcheck
@@ -14,7 +15,8 @@
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.ootypesystem import ootype
-def _get_jitcodes(testself, CPUClass, func, values, type_system):
+def _get_jitcodes(testself, CPUClass, func, values, type_system,
+ supports_longlong=False, **kwds):
from pypy.jit.codewriter import support, codewriter
from pypy.jit.metainterp import simple_optimize
@@ -57,7 +59,9 @@
cpu = CPUClass(rtyper, stats, None, False)
cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
testself.cw = cw
- cw.find_all_graphs(JitPolicy())
+ policy = JitPolicy()
+ policy.set_supports_longlong(supports_longlong)
+ cw.find_all_graphs(policy)
#
testself.warmrunnerstate = FakeWarmRunnerState()
testself.warmrunnerstate.cpu = cpu
@@ -119,6 +123,29 @@
else:
raise Exception("FAILED")
+def _run_with_machine_code(testself, args):
+ metainterp = testself.metainterp
+ num_green_args = metainterp.jitdriver_sd.num_green_args
+ loop_tokens = metainterp.get_compiled_merge_points(args[:num_green_args])
+ if len(loop_tokens) != 1:
+ return NotImplemented
+ # a loop was successfully created by _run_with_pyjitpl(); call it
+ cpu = metainterp.cpu
+ for i in range(len(args) - num_green_args):
+ x = args[num_green_args + i]
+ typecode = history.getkind(lltype.typeOf(x))
+ set_future_value(cpu, i, x, typecode)
+ faildescr = cpu.execute_token(loop_tokens[0])
+ assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr')
+ if metainterp.jitdriver_sd.result_type == history.INT:
+ return cpu.get_latest_value_int(0)
+ elif metainterp.jitdriver_sd.result_type == history.REF:
+ return cpu.get_latest_value_ref(0)
+ elif metainterp.jitdriver_sd.result_type == history.FLOAT:
+ return cpu.get_latest_value_float(0)
+ else:
+ return None
+
class JitMixin:
basic = True
@@ -156,12 +183,15 @@
def interp_operations(self, f, args, **kwds):
# get the JitCodes for the function f
- _get_jitcodes(self, self.CPUClass, f, args, self.type_system)
+ _get_jitcodes(self, self.CPUClass, f, args, self.type_system, **kwds)
# try to run it with blackhole.py
result1 = _run_with_blackhole(self, args)
# try to run it with pyjitpl.py
result2 = _run_with_pyjitpl(self, args)
assert result1 == result2
+ # try to run it by running the code compiled just before
+ result3 = _run_with_machine_code(self, args)
+ assert result1 == result3 or result3 == NotImplemented
return result1
def check_history(self, expected=None, **isns):
@@ -1261,20 +1291,6 @@
res = self.interp_operations(f, [5])
assert res == f(5)
- def test_long_long(self):
- from pypy.rlib.rarithmetic import r_longlong, intmask
- def g(n, m, o):
- # This function should be completely marked as residual by
- # codewriter.py on 32-bit platforms. On 64-bit platforms,
- # this function should be JITted and the test should pass too.
- n = r_longlong(n)
- m = r_longlong(m)
- return intmask((n*m) // o)
- def f(n, m, o):
- return g(n, m, o) // 3
- res = self.interp_operations(f, [1000000000, 90, 91])
- assert res == (1000000000 * 90 // 91) // 3
-
def test_free_object(self):
import weakref
from pypy.rlib import rgc
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -86,6 +86,7 @@
class BaseCPU(model.AbstractCPU):
supports_floats = True
+ supports_longlong = True
def __init__(self, rtyper, stats=None, opts=None,
translate_support_code=False,
diff --git a/pypy/translator/c/src/math.c b/pypy/translator/c/src/math.c
deleted file mode 100644
--- a/pypy/translator/c/src/math.c
+++ /dev/null
@@ -1,256 +0,0 @@
-/* Definitions of some C99 math library functions, for those platforms
- that don't implement these functions already. */
-
-#include <errno.h>
-
-/* The following macros are copied from CPython header files */
-
-#ifdef _MSC_VER
-#include <float.h>
-#define PyPy_IS_NAN _isnan
-#define PyPy_IS_INFINITY(X) (!_finite(X) && !_isnan(X))
-#define copysign _copysign
-#else
-#define PyPy_IS_NAN(X) ((X) != (X))
-#define PyPy_IS_INFINITY(X) ((X) && \
- (Py_FORCE_DOUBLE(X)*0.5 == Py_FORCE_DOUBLE(X)))
-#endif
-
-#undef PyPy_NAN
-
-int
-_pypy_math_isinf(double x)
-{
- return PyPy_IS_INFINITY(x);
-}
-
-int
-_pypy_math_isnan(double x)
-{
- return PyPy_IS_NAN(x);
-}
-
-/* The following copyright notice applies to the original
- implementations of acosh, asinh and atanh. */
-
-/*
- * ====================================================
- * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
- *
- * Developed at SunPro, a Sun Microsystems, Inc. business.
- * Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
- * is preserved.
- * ====================================================
- */
-
-double _pypy_math_log1p(double x);
-
-static const double ln2 = 6.93147180559945286227E-01;
-static const double two_pow_m28 = 3.7252902984619141E-09; /* 2**-28 */
-static const double two_pow_p28 = 268435456.0; /* 2**28 */
-static const double zero = 0.0;
-
-/* acosh(x)
- * Method :
- * Based on
- * acosh(x) = log [ x + sqrt(x*x-1) ]
- * we have
- * acosh(x) := log(x)+ln2, if x is large; else
- * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
- * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
- *
- * Special cases:
- * acosh(x) is NaN with signal if x<1.
- * acosh(NaN) is NaN without signal.
- */
-
-double
-_pypy_math_acosh(double x)
-{
- if (PyPy_IS_NAN(x)) {
- return x+x;
- }
- if (x < 1.) { /* x < 1; return a signaling NaN */
- errno = EDOM;
-#ifdef PyPy_NAN
- return PyPy_NAN;
-#else
- return (x-x)/(x-x);
-#endif
- }
- else if (x >= two_pow_p28) { /* x > 2**28 */
- if (PyPy_IS_INFINITY(x)) {
- return x+x;
- } else {
- return log(x)+ln2; /* acosh(huge)=log(2x) */
- }
- }
- else if (x == 1.) {
- return 0.0; /* acosh(1) = 0 */
- }
- else if (x > 2.) { /* 2 < x < 2**28 */
- double t = x*x;
- return log(2.0*x - 1.0 / (x + sqrt(t - 1.0)));
- }
- else { /* 1 < x <= 2 */
- double t = x - 1.0;
- return _pypy_math_log1p(t + sqrt(2.0*t + t*t));
- }
-}
-
-
-/* asinh(x)
- * Method :
- * Based on
- * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
- * we have
- * asinh(x) := x if 1+x*x=1,
- * := sign(x)*(log(x)+ln2)) for large |x|, else
- * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
- * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
- */
-
-double
-_pypy_math_asinh(double x)
-{
- double w;
- double absx = fabs(x);
-
- if (PyPy_IS_NAN(x) || PyPy_IS_INFINITY(x)) {
- return x+x;
- }
- if (absx < two_pow_m28) { /* |x| < 2**-28 */
- return x; /* return x inexact except 0 */
- }
- if (absx > two_pow_p28) { /* |x| > 2**28 */
- w = log(absx)+ln2;
- }
- else if (absx > 2.0) { /* 2 < |x| < 2**28 */
- w = log(2.0*absx + 1.0 / (sqrt(x*x + 1.0) + absx));
- }
- else { /* 2**-28 <= |x| < 2= */
- double t = x*x;
- w = _pypy_math_log1p(absx + t / (1.0 + sqrt(1.0 + t)));
- }
- return copysign(w, x);
-
-}
-
-/* atanh(x)
- * Method :
- * 1.Reduced x to positive by atanh(-x) = -atanh(x)
- * 2.For x>=0.5
- * 1 2x x
- * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
- * 2 1 - x 1 - x
- *
- * For x<0.5
- * atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
- *
- * Special cases:
- * atanh(x) is NaN if |x| >= 1 with signal;
- * atanh(NaN) is that NaN with no signal;
- *
- */
-
-double
-_pypy_math_atanh(double x)
-{
- double absx;
- double t;
-
- if (PyPy_IS_NAN(x)) {
- return x+x;
- }
- absx = fabs(x);
- if (absx >= 1.) { /* |x| >= 1 */
- errno = EDOM;
-#ifdef PyPy_NAN
- return PyPy_NAN;
-#else
- return x/zero;
-#endif
- }
- if (absx < two_pow_m28) { /* |x| < 2**-28 */
- return x;
- }
- if (absx < 0.5) { /* |x| < 0.5 */
- t = absx+absx;
- t = 0.5 * _pypy_math_log1p(t + t*absx / (1.0 - absx));
- }
- else { /* 0.5 <= |x| <= 1.0 */
- t = 0.5 * _pypy_math_log1p((absx + absx) / (1.0 - absx));
- }
- return copysign(t, x);
-}
-
-/* Mathematically, expm1(x) = exp(x) - 1. The expm1 function is designed
- to avoid the significant loss of precision that arises from direct
- evaluation of the expression exp(x) - 1, for x near 0. */
-
-double
-_pypy_math_expm1(double x)
-{
- /* For abs(x) >= log(2), it's safe to evaluate exp(x) - 1 directly; this
- also works fine for infinities and nans.
-
- For smaller x, we can use a method due to Kahan that achieves close to
- full accuracy.
- */
-
- if (fabs(x) < 0.7) {
- double u;
- u = exp(x);
- if (u == 1.0)
- return x;
- else
- return (u - 1.0) * x / log(u);
- }
- else
- return exp(x) - 1.0;
-}
-
-/* log1p(x) = log(1+x). The log1p function is designed to avoid the
- significant loss of precision that arises from direct evaluation when x is
- small. */
-
-double
-_pypy_math_log1p(double x)
-{
- /* For x small, we use the following approach. Let y be the nearest float
- to 1+x, then
-
- 1+x = y * (1 - (y-1-x)/y)
-
- so log(1+x) = log(y) + log(1-(y-1-x)/y). Since (y-1-x)/y is tiny, the
- second term is well approximated by (y-1-x)/y. If abs(x) >=
- DBL_EPSILON/2 or the rounding-mode is some form of round-to-nearest
- then y-1-x will be exactly representable, and is computed exactly by
- (y-1)-x.
-
- If abs(x) < DBL_EPSILON/2 and the rounding mode is not known to be
- round-to-nearest then this method is slightly dangerous: 1+x could be
- rounded up to 1+DBL_EPSILON instead of down to 1, and in that case
- y-1-x will not be exactly representable any more and the result can be
- off by many ulps. But this is easily fixed: for a floating-point
- number |x| < DBL_EPSILON/2., the closest floating-point number to
- log(1+x) is exactly x.
- */
-
- double y;
- if (fabs(x) < DBL_EPSILON/2.) {
- return x;
- } else if (-0.5 <= x && x <= 1.) {
- /* WARNING: it's possible than an overeager compiler
- will incorrectly optimize the following two lines
- to the equivalent of "return log(1.+x)". If this
- happens, then results from log1p will be inaccurate
- for small x. */
- y = 1.+x;
- return log(y)-((y-1.)-x)/y;
- } else {
- /* NaNs and infinities should end up here */
- return log(1.+x);
- }
-}
diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py
--- a/pypy/jit/tl/pypyjit.py
+++ b/pypy/jit/tl/pypyjit.py
@@ -30,7 +30,6 @@
BACKEND = 'c'
config = get_pypy_config(translating=True)
-config.translation.backendopt.inline_threshold = 0.1
config.translation.gc = 'boehm'
config.objspace.nofaking = True
config.translating = True
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
@@ -5,7 +5,7 @@
import os
from pypy.jit.metainterp.history import (Box, Const, ConstInt, ConstPtr,
ResOperation, BoxPtr, ConstFloat,
- LoopToken, INT, REF, FLOAT)
+ BoxFloat, LoopToken, INT, REF, FLOAT)
from pypy.jit.backend.x86.regloc import *
from pypy.rpython.lltypesystem import lltype, ll2ctypes, rffi, rstr
from pypy.rlib.objectmodel import we_are_translated
@@ -13,12 +13,14 @@
from pypy.jit.backend.llsupport import symbolic
from pypy.jit.backend.x86.jump import remap_frame_layout
from pypy.jit.codewriter import heaptracker
+from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.backend.llsupport.descr import BaseFieldDescr, BaseArrayDescr
from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr
from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\
TempBox, compute_vars_longevity, compute_loop_consts
from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE, IS_X86_32, IS_X86_64
+from pypy.rlib.rarithmetic import r_longlong, r_uint
class X86RegisterManager(RegisterManager):
@@ -72,6 +74,12 @@
rffi.cast(rffi.CArrayPtr(rffi.DOUBLE), adr)[0] = c.getfloat()
return ConstFloatLoc(adr)
+ def convert_to_imm_16bytes_align(self, c):
+ adr = self.assembler.datablockwrapper.malloc_aligned(16, 16)
+ rffi.cast(rffi.CArrayPtr(rffi.DOUBLE), adr)[0] = c.getfloat()
+ rffi.cast(rffi.CArrayPtr(rffi.DOUBLE), adr)[1] = 0.0
+ return ConstFloatLoc(adr)
+
def after_call(self, v):
# the result is stored in st0, but we don't have this around,
# so genop_call will move it to some frame location immediately
@@ -229,6 +237,14 @@
return self.rm.force_allocate_reg(var, forbidden_vars,
selected_reg, need_lower_byte)
+ def load_xmm_aligned_16_bytes(self, var, forbidden_vars=[]):
+ # Load 'var' in a register; but if it is a constant, we can return
+ # a 16-bytes-aligned ConstFloatLoc.
+ if isinstance(var, Const):
+ return self.xrm.convert_to_imm_16bytes_align(var)
+ else:
+ return self.xrm.make_sure_var_in_reg(var, forbidden_vars)
+
def _update_bindings(self, locs, inputargs):
# XXX this should probably go to llsupport/regalloc.py
used = {}
@@ -269,6 +285,11 @@
self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs))
self.assembler.regalloc_perform(op, arglocs, result_loc)
+ def PerformLLong(self, op, arglocs, result_loc):
+ if not we_are_translated():
+ self.assembler.dump('%s <- %s(%s)' % (result_loc, op, arglocs))
+ self.assembler.regalloc_perform_llong(op, arglocs, result_loc)
+
def locs_for_fail(self, guard_op):
return [self.loc(v) for v in guard_op.getfailargs()]
@@ -583,6 +604,110 @@
self.Perform(op, [loc0], loc1)
self.rm.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
+ # argument is a constant, we can ask it to be aligned to 16 bytes.
+ args = [op.getarg(1), op.getarg(2)]
+ loc1 = self.load_xmm_aligned_16_bytes(args[1])
+ loc0 = self.xrm.force_result_in_reg(op.result, args[0], args)
+ self.PerformLLong(op, [loc0, loc1], loc0)
+ self.xrm.possibly_free_vars(args)
+
+ def _consider_llong_eq_ne_xx(self, op):
+ # must force both arguments into xmm registers, because we don't
+ # know if they will be suitably aligned. Exception: if they are
+ # constants, we can ask them to be aligned to 16 bytes.
+ args = [op.getarg(1), op.getarg(2)]
+ loc1 = self.load_xmm_aligned_16_bytes(args[0])
+ loc2 = self.load_xmm_aligned_16_bytes(args[1], args)
+ tmpxvar = TempBox()
+ loc3 = self.xrm.force_allocate_reg(tmpxvar, args)
+ self.xrm.possibly_free_var(tmpxvar)
+ loc0 = self.rm.force_allocate_reg(op.result, need_lower_byte=True)
+ self.PerformLLong(op, [loc1, loc2, loc3], loc0)
+ self.xrm.possibly_free_vars(args)
+
+ def _maybe_consider_llong_lt(self, op):
+ # XXX just a special case for now
+ from pypy.rlib.longlong2float import longlong2float
+ box = op.getarg(2)
+ if not isinstance(box, ConstFloat):
+ return False
+ if not (box.value == longlong2float(r_longlong(0))):
+ return False
+ # "x < 0"
+ box = op.getarg(1)
+ assert isinstance(box, BoxFloat)
+ loc1 = self.xrm.make_sure_var_in_reg(box)
+ loc0 = self.rm.force_allocate_reg(op.result)
+ self.PerformLLong(op, [loc1], loc0)
+ self.xrm.possibly_free_var(box)
+ return True
+
+ def _consider_llong_to_int(self, op):
+ # accept an argument in a xmm register or in the stack
+ loc1 = self.xrm.loc(op.getarg(1))
+ loc0 = self.rm.force_allocate_reg(op.result)
+ self.PerformLLong(op, [loc1], loc0)
+ self.xrm.possibly_free_var(op.getarg(1))
+
+ def _loc_of_const_longlong(self, value64):
+ from pypy.rlib.longlong2float import longlong2float
+ c = ConstFloat(longlong2float(value64))
+ return self.xrm.convert_to_imm(c)
+
+ def _consider_llong_from_int(self, op):
+ assert IS_X86_32
+ loc0 = self.xrm.force_allocate_reg(op.result)
+ box = op.getarg(1)
+ if isinstance(box, ConstInt):
+ loc1 = self._loc_of_const_longlong(r_longlong(box.value))
+ loc2 = None # unused
+ else:
+ # requires the argument to be in eax, and trash edx.
+ loc1 = self.rm.make_sure_var_in_reg(box, selected_reg=eax)
+ tmpvar = TempBox()
+ self.rm.force_allocate_reg(tmpvar, [box], selected_reg=edx)
+ self.rm.possibly_free_var(tmpvar)
+ tmpxvar = TempBox()
+ loc2 = self.xrm.force_allocate_reg(tmpxvar, [op.result])
+ self.xrm.possibly_free_var(tmpxvar)
+ self.PerformLLong(op, [loc1, loc2], loc0)
+ self.rm.possibly_free_var(box)
+
+ def _consider_llong_from_two_ints(self, op):
+ assert IS_X86_32
+ box1 = op.getarg(1)
+ box2 = op.getarg(2)
+ loc0 = self.xrm.force_allocate_reg(op.result)
+ #
+ if isinstance(box1, ConstInt) and isinstance(box2, ConstInt):
+ # all-constant arguments: load the result value in a single step
+ value64 = r_longlong(box2.value) << 32
+ value64 |= r_longlong(r_uint(box1.value))
+ loc1 = self._loc_of_const_longlong(value64)
+ loc2 = None # unused
+ loc3 = None # unused
+ #
+ else:
+ tmpxvar = TempBox()
+ loc3 = self.xrm.force_allocate_reg(tmpxvar, [op.result])
+ self.xrm.possibly_free_var(tmpxvar)
+ #
+ if isinstance(box1, ConstInt):
+ loc1 = self._loc_of_const_longlong(r_longlong(box1.value))
+ else:
+ loc1 = self.rm.make_sure_var_in_reg(box1)
+ #
+ if isinstance(box2, ConstInt):
+ loc2 = self._loc_of_const_longlong(r_longlong(box2.value))
+ else:
+ loc2 = self.rm.make_sure_var_in_reg(box2, [box1])
+ #
+ self.PerformLLong(op, [loc1, loc2, loc3], loc0)
+ self.rm.possibly_free_vars_for_op(op)
+
def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None):
save_all_regs = guard_not_forced_op is not None
self.rm.before_call(force_store, save_all_regs=save_all_regs)
@@ -614,6 +739,31 @@
guard_not_forced_op=guard_not_forced_op)
def consider_call(self, op):
+ if IS_X86_32:
+ # support for some of the llong operations,
+ # which only exist on x86-32
+ effectinfo = op.getdescr().get_extra_info()
+ if effectinfo is not None:
+ oopspecindex = effectinfo.oopspecindex
+ if oopspecindex in (EffectInfo.OS_LLONG_ADD,
+ EffectInfo.OS_LLONG_SUB,
+ EffectInfo.OS_LLONG_AND,
+ EffectInfo.OS_LLONG_OR,
+ EffectInfo.OS_LLONG_XOR):
+ return self._consider_llong_binop_xx(op)
+ if oopspecindex == EffectInfo.OS_LLONG_TO_INT:
+ return self._consider_llong_to_int(op)
+ if oopspecindex == EffectInfo.OS_LLONG_FROM_INT:
+ return self._consider_llong_from_int(op)
+ if oopspecindex == EffectInfo.OS_LLONG_FROM_TWO_INTS:
+ return self._consider_llong_from_two_ints(op)
+ if (oopspecindex == EffectInfo.OS_LLONG_EQ or
+ oopspecindex == EffectInfo.OS_LLONG_NE):
+ return self._consider_llong_eq_ne_xx(op)
+ if oopspecindex == EffectInfo.OS_LLONG_LT:
+ if self._maybe_consider_llong_lt(op):
+ return
+ #
self._consider_call(op)
def consider_call_may_force(self, op, guard_op):
diff --git a/pypy/interpreter/test/test_executioncontext.py b/pypy/interpreter/test/test_executioncontext.py
--- a/pypy/interpreter/test/test_executioncontext.py
+++ b/pypy/interpreter/test/test_executioncontext.py
@@ -164,6 +164,25 @@
events = space.unwrap(w_events)
assert events == ['return', 'c_call', 'c_return', 'return', 'c_call']
+ def test_c_call_setprofile_kwargs(self):
+ space = self.space
+ w_events = space.appexec([], """():
+ import sys
+ l = []
+ def profile(frame, event, arg):
+ l.append(event)
+
+ def bar():
+ sys.setprofile(profile)
+ [].sort(reverse=True)
+ sys.setprofile(None)
+
+ bar()
+ return l
+ """)
+ events = space.unwrap(w_events)
+ assert events == ['c_call', 'c_return', 'c_call']
+
def test_c_call_setprofile_strange_method(self):
space = self.space
w_events = space.appexec([], """():
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -49,6 +49,7 @@
absolute = "from __future__ import absolute_import\nimport string",
relative_b = "from __future__ import absolute_import\nfrom . import string",
relative_c = "from __future__ import absolute_import\nfrom .string import inpackage",
+ relative_f = "from .os import sep",
)
setuppkg("pkg.pkg1",
a = '',
@@ -189,6 +190,13 @@
def test_import_keywords(self):
__import__(name='sys', level=0)
+ def test_import_by_filename(self):
+ import pkg.a
+ filename = pkg.a.__file__
+ assert filename.endswith('.py')
+ exc = raises(ImportError, __import__, filename[:-3])
+ assert exc.value.message == "Import by filename is not supported."
+
def test_import_badcase(self):
def missing(name):
try:
@@ -269,7 +277,7 @@
def test_import_relative_partial_success(self):
def imp():
import pkg_r.inpkg
- raises(ImportError,imp)
+ raises(ImportError, imp)
def test_import_builtin_inpackage(self):
def imp():
@@ -347,6 +355,12 @@
from pkg import relative_b
assert relative_b.string.inpackage == 1
+ def test_no_relative_import(self):
+ def imp():
+ from pkg import relative_f
+ exc = raises(ImportError, imp)
+ assert exc.value.message == "No module named pkg.os"
+
def test_future_relative_import_level_1(self):
from pkg import relative_c
assert relative_c.inpackage == 1
@@ -722,6 +736,7 @@
def test_write_compiled_module(self):
space = self.space
pathname = _testfilesource()
+ os.chmod(pathname, 0777)
stream = streamio.open_file_as_stream(pathname, "r")
try:
w_ret = importing.parse_source_module(space,
@@ -733,10 +748,12 @@
assert type(pycode) is pypy.interpreter.pycode.PyCode
cpathname = str(udir.join('cpathname.pyc'))
+ mode = 0777
mtime = 12345
importing.write_compiled_module(space,
pycode,
cpathname,
+ mode,
mtime)
# check
@@ -746,6 +763,9 @@
assert ret is not None
ret.close()
+ # Check that the executable bit was removed
+ assert os.stat(cpathname).st_mode & 0111 == 0
+
# read compiled module
stream = streamio.open_file_as_stream(cpathname, "rb")
try:
diff --git a/pypy/translator/c/src/signals.h b/pypy/translator/c/src/signals.h
--- a/pypy/translator/c/src/signals.h
+++ b/pypy/translator/c/src/signals.h
@@ -117,8 +117,11 @@
pypysig_counter.value = -1;
}
- if (wakeup_fd != -1)
- write(wakeup_fd, "\0", 1);
+ if (wakeup_fd != -1)
+ {
+ write(wakeup_fd, "\0", 1);
+ /* the return value is ignored here */
+ }
}
void pypysig_setflag(int signum)
diff --git a/pypy/jit/backend/llgraph/llimpl.py b/pypy/jit/backend/llgraph/llimpl.py
--- a/pypy/jit/backend/llgraph/llimpl.py
+++ b/pypy/jit/backend/llgraph/llimpl.py
@@ -23,12 +23,16 @@
from pypy.rlib.objectmodel import ComputedIntSymbolic, we_are_translated
from pypy.rlib.rarithmetic import ovfcheck
+from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint
+from pypy.rlib.longlong2float import longlong2float, float2longlong
import py
from pypy.tool.ansi_print import ansi_log
log = py.log.Producer('runner')
py.log.setconsumer('runner', ansi_log)
+IS_32_BIT = r_ulonglong is not r_uint
+
def _from_opaque(opq):
return opq._obj.externalobj
@@ -1071,14 +1075,26 @@
def cast_from_ptr(TYPE, x):
return lltype.cast_opaque_ptr(TYPE, x)
-def cast_to_float(x): # not really a cast, just a type check
+def cast_to_float(x):
+ if isinstance(x, float):
+ return x # common case
+ if IS_32_BIT:
+ if isinstance(x, r_longlong):
+ return longlong2float(x)
+ if isinstance(x, r_ulonglong):
+ return longlong2float(rffi.cast(lltype.SignedLongLong, x))
+ raise TypeError(type(x))
+
+def cast_from_float(TYPE, x):
assert isinstance(x, float)
- return x
-
-def cast_from_float(TYPE, x): # not really a cast, just a type check
- assert TYPE is lltype.Float
- assert isinstance(x, float)
- return x
+ if TYPE is lltype.Float:
+ return x
+ if IS_32_BIT:
+ if TYPE is lltype.SignedLongLong:
+ return float2longlong(x)
+ if TYPE is lltype.UnsignedLongLong:
+ return r_ulonglong(float2longlong(x))
+ raise TypeError(TYPE)
def new_frame(is_oo, cpu):
@@ -1518,7 +1534,9 @@
assert n == 'r'
x = argsiter_r.next()
x = cast_from_ptr(TYPE, x)
- elif TYPE is lltype.Float:
+ elif TYPE is lltype.Float or (
+ IS_32_BIT and TYPE in (lltype.SignedLongLong,
+ lltype.UnsignedLongLong)):
if args_in_order is not None:
n = orderiter.next()
assert n == 'f'
diff --git a/pypy/jit/codewriter/test/test_jtransform.py b/pypy/jit/codewriter/test/test_jtransform.py
--- a/pypy/jit/codewriter/test/test_jtransform.py
+++ b/pypy/jit/codewriter/test/test_jtransform.py
@@ -90,7 +90,7 @@
self.callinfocollection = FakeCallInfoCollection()
def guess_call_kind(self, op):
return 'builtin'
- def getcalldescr(self, op, oopspecindex=None):
+ def getcalldescr(self, op, oopspecindex=None, extraeffect=None):
assert oopspecindex is not None # in this test
EI = effectinfo.EffectInfo
if oopspecindex != EI.OS_ARRAYCOPY:
diff --git a/pypy/jit/codewriter/effectinfo.py b/pypy/jit/codewriter/effectinfo.py
--- a/pypy/jit/codewriter/effectinfo.py
+++ b/pypy/jit/codewriter/effectinfo.py
@@ -46,6 +46,32 @@
OS_LIBFFI_PREPARE = 60
OS_LIBFFI_PUSH_ARG = 61
OS_LIBFFI_CALL = 62
+ #
+ OS_LLONG_INVERT = 69
+ OS_LLONG_ADD = 70
+ OS_LLONG_SUB = 71
+ OS_LLONG_MUL = 72
+ OS_LLONG_LT = 73
+ OS_LLONG_LE = 74
+ OS_LLONG_EQ = 75
+ OS_LLONG_NE = 76
+ OS_LLONG_GT = 77
+ OS_LLONG_GE = 78
+ OS_LLONG_AND = 79
+ OS_LLONG_OR = 80
+ OS_LLONG_LSHIFT = 81
+ OS_LLONG_RSHIFT = 82
+ OS_LLONG_XOR = 83
+ OS_LLONG_FROM_INT = 84
+ OS_LLONG_TO_INT = 85
+ OS_LLONG_FROM_FLOAT = 86
+ OS_LLONG_TO_FLOAT = 87
+ OS_LLONG_ULT = 88
+ OS_LLONG_ULE = 89
+ OS_LLONG_UGT = 90
+ OS_LLONG_UGE = 91
+ OS_LLONG_URSHIFT = 92
+ OS_LLONG_FROM_TWO_INTS = 93
def __new__(cls, readonly_descrs_fields,
write_descrs_fields, write_descrs_arrays,
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
@@ -1163,7 +1163,7 @@
src_r += 1
if box.type == history.REF:
break
- elif kind == history.FLOAT:
+ elif kind == history.FLOAT or kind == 'L': # long long
while True:
box = argboxes[src_f]
src_f += 1
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -10,7 +10,7 @@
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.baseobjspace import W_Root, ObjSpace, Wrappable
from pypy.interpreter.eval import Code
-from pypy.rlib import streamio, jit
+from pypy.rlib import streamio, jit, rposix
from pypy.rlib.streamio import StreamErrors
from pypy.rlib.rarithmetic import intmask
from pypy.rlib.objectmodel import we_are_translated, specialize
@@ -127,42 +127,58 @@
if (level != 0 and
w_globals is not None and
space.isinstance_w(w_globals, space.w_dict)):
+
ctxt_w_name = space.finditem(w_globals, w('__name__'))
ctxt_w_path = space.finditem(w_globals, w('__path__'))
+
+ ctxt_name = None
if ctxt_w_name is not None:
try:
ctxt_name = space.str_w(ctxt_w_name)
except OperationError, e:
if not e.match(space, space.w_TypeError):
raise
- else:
- ctxt_name_prefix_parts = ctxt_name.split('.')
- if level > 0:
- n = len(ctxt_name_prefix_parts)-level+1
- assert n>=0
- ctxt_name_prefix_parts = ctxt_name_prefix_parts[:n]
- if ctxt_name_prefix_parts and ctxt_w_path is None: # plain module
- ctxt_name_prefix_parts.pop()
- if ctxt_name_prefix_parts:
- rel_modulename = '.'.join(ctxt_name_prefix_parts)
- if modulename:
- rel_modulename += '.' + modulename
- baselevel = len(ctxt_name_prefix_parts)
- if rel_modulename is not None:
- w_mod = check_sys_modules(space, w(rel_modulename))
- if (w_mod is None or
- not space.is_w(w_mod, space.w_None)):
- w_mod = absolute_import(space, rel_modulename,
- baselevel,
- fromlist_w, tentative=1)
- if w_mod is not None:
- space.timer.stop_name("importhook", modulename)
- return w_mod
+
+ if ctxt_name is not None:
+ ctxt_name_prefix_parts = ctxt_name.split('.')
+ if level > 0:
+ n = len(ctxt_name_prefix_parts)-level+1
+ assert n>=0
+ ctxt_name_prefix_parts = ctxt_name_prefix_parts[:n]
+ if ctxt_name_prefix_parts and ctxt_w_path is None: # plain module
+ ctxt_name_prefix_parts.pop()
+ if ctxt_name_prefix_parts:
+ rel_modulename = '.'.join(ctxt_name_prefix_parts)
+ if modulename:
+ rel_modulename += '.' + modulename
+ baselevel = len(ctxt_name_prefix_parts)
+ if rel_modulename is not None:
+ # XXX What is this check about? There is no test for it
+ w_mod = check_sys_modules(space, w(rel_modulename))
+
+ if (w_mod is None or
+ not space.is_w(w_mod, space.w_None)):
+
+ # if no level was set, ignore import errors, and
+ # fall back to absolute import at the end of the
+ # function.
+ if level == -1:
+ tentative = True
else:
- rel_modulename = None
- if level > 0:
- msg = "Attempted relative import in non-package"
- raise OperationError(space.w_ValueError, w(msg))
+ tentative = False
+
+ w_mod = absolute_import(space, rel_modulename,
+ baselevel, fromlist_w,
+ tentative=tentative)
+ if w_mod is not None:
+ space.timer.stop_name("importhook", modulename)
+ return w_mod
+ else:
+ rel_modulename = None
+
+ if level > 0:
+ msg = "Attempted relative import in non-package"
+ raise OperationError(space.w_ValueError, w(msg))
w_mod = absolute_import_try(space, modulename, 0, fromlist_w)
if w_mod is None or space.is_w(w_mod, space.w_None):
w_mod = absolute_import(space, modulename, 0, fromlist_w, tentative=0)
@@ -226,6 +242,10 @@
def _absolute_import(space, modulename, baselevel, fromlist_w, tentative):
w = space.wrap
+ if '/' in modulename or '\\' in modulename:
+ raise OperationError(space.w_ImportError, space.wrap(
+ "Import by filename is not supported."))
+
w_mod = None
parts = modulename.split('.')
prefix = []
@@ -720,11 +740,14 @@
if space.config.objspace.usepycfiles:
cpathname = pathname + 'c'
- mtime = int(os.stat(pathname)[stat.ST_MTIME])
+ src_stat = os.stat(pathname)
+ mtime = int(src_stat[stat.ST_MTIME])
+ mode = src_stat[stat.ST_MODE]
stream = check_compiled_module(space, cpathname, mtime)
else:
cpathname = None
mtime = 0
+ mode = 0
stream = None
if stream:
@@ -738,7 +761,7 @@
code_w = parse_source_module(space, pathname, source)
if space.config.objspace.usepycfiles and write_pyc:
- write_compiled_module(space, code_w, cpathname, mtime)
+ write_compiled_module(space, code_w, cpathname, mode, mtime)
exec_code_module(space, w_mod, code_w)
@@ -825,8 +848,18 @@
return w_mod
+def open_exclusive(space, cpathname, mode):
+ try:
+ os.unlink(cpathname)
+ except OSError:
+ pass
-def write_compiled_module(space, co, cpathname, mtime):
+ flags = (os.O_EXCL|os.O_CREAT|os.O_WRONLY|os.O_TRUNC|
+ streamio.O_BINARY)
+ fd = os.open(cpathname, flags, mode)
+ return streamio.fdopen_as_stream(fd, "wb")
+
+def write_compiled_module(space, co, cpathname, src_mode, src_mtime):
"""
Write a compiled module to a file, placing the time of last
modification of its source into the header.
@@ -847,10 +880,16 @@
# Careful here: we must not crash nor leave behind something that looks
# too much like a valid pyc file but really isn't one.
#
+ mode = src_mode & ~0111
try:
- stream = streamio.open_file_as_stream(cpathname, "wb")
- except StreamErrors:
- return # cannot create file
+ stream = open_exclusive(space, cpathname, mode)
+ except (OSError, StreamErrors):
+ try:
+ os.unlink(cpathname)
+ except OSError:
+ pass
+ return
+
try:
try:
# will patch the header later; write zeroes until we are sure that
@@ -862,7 +901,7 @@
# should be ok (XXX or should call os.fsync() to be sure?)
stream.seek(0, 0)
_w_long(stream, get_pyc_magic(space))
- _w_long(stream, mtime)
+ _w_long(stream, src_mtime)
finally:
stream.close()
except StreamErrors:
diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -13,6 +13,7 @@
class AbstractX86CPU(AbstractLLCPU):
debug = True
supports_floats = True
+ supports_longlong = True
BOOTSTRAP_TP = lltype.FuncType([], lltype.Signed)
dont_keepalive_stuff = False # for tests
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
@@ -265,8 +265,8 @@
'uint_ge': LLOp(canfold=True),
'uint_and': LLOp(canfold=True),
'uint_or': LLOp(canfold=True),
- 'uint_lshift': LLOp(canfold=True),
- 'uint_rshift': LLOp(canfold=True),
+ 'uint_lshift': LLOp(canfold=True), # args (r_uint, int)
+ 'uint_rshift': LLOp(canfold=True), # args (r_uint, int)
'uint_xor': LLOp(canfold=True),
'float_is_true': LLOp(canfold=True), # it really means "x != 0.0"
@@ -288,9 +288,7 @@
'llong_is_true': LLOp(canfold=True),
'llong_neg': LLOp(canfold=True),
- 'llong_neg_ovf': LLOp(canraise=(OverflowError,), tryfold=True),
'llong_abs': LLOp(canfold=True),
- 'llong_abs_ovf': LLOp(canraise=(OverflowError,), tryfold=True),
'llong_invert': LLOp(canfold=True),
'llong_add': LLOp(canfold=True),
@@ -308,8 +306,8 @@
'llong_ge': LLOp(canfold=True),
'llong_and': LLOp(canfold=True),
'llong_or': LLOp(canfold=True),
- 'llong_lshift': LLOp(canfold=True),
- 'llong_rshift': LLOp(canfold=True),
+ 'llong_lshift': LLOp(canfold=True), # args (r_longlong, int)
+ 'llong_rshift': LLOp(canfold=True), # args (r_longlong, int)
'llong_xor': LLOp(canfold=True),
'ullong_is_true': LLOp(canfold=True),
@@ -330,8 +328,8 @@
'ullong_ge': LLOp(canfold=True),
'ullong_and': LLOp(canfold=True),
'ullong_or': LLOp(canfold=True),
- 'ullong_lshift': LLOp(canfold=True),
- 'ullong_rshift': LLOp(canfold=True),
+ 'ullong_lshift': LLOp(canfold=True), # args (r_ulonglong, int)
+ 'ullong_rshift': LLOp(canfold=True), # args (r_ulonglong, int)
'ullong_xor': LLOp(canfold=True),
'cast_primitive': LLOp(canfold=True),
diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py
--- a/pypy/jit/backend/llsupport/test/test_descr.py
+++ b/pypy/jit/backend/llsupport/test/test_descr.py
@@ -5,7 +5,7 @@
from pypy.rpython.annlowlevel import llhelper
from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
from pypy.jit.metainterp import history
-import struct
+import sys, struct, py
def test_get_size_descr():
c0 = GcCache(False)
@@ -95,6 +95,16 @@
descr_x = get_field_descr(c2, S, 'x')
assert descr_x.is_field_signed() == signed
+def test_get_field_descr_longlong():
+ if sys.maxint > 2147483647:
+ py.test.skip("long long: for 32-bit only")
+ c0 = GcCache(False)
+ S = lltype.GcStruct('S', ('y', lltype.UnsignedLongLong))
+ descr = get_field_descr(c0, S, 'y')
+ assert not descr.is_pointer_field()
+ assert descr.is_float_field()
+ assert descr.get_field_size(False) == 8
+
def test_get_array_descr():
U = lltype.Struct('U')
@@ -226,6 +236,21 @@
assert descr4.get_return_type() == history.FLOAT
assert descr4.arg_classes == "ff"
+def test_get_call_descr_not_translated_longlong():
+ if sys.maxint > 2147483647:
+ py.test.skip("long long: for 32-bit only")
+ c0 = GcCache(False)
+ #
+ descr5 = get_call_descr(c0, [lltype.SignedLongLong], lltype.Signed)
+ assert descr5.get_result_size(False) == 4
+ assert descr5.get_return_type() == history.INT
+ assert descr5.arg_classes == "L"
+ #
+ descr6 = get_call_descr(c0, [lltype.Signed], lltype.SignedLongLong)
+ assert descr6.get_result_size(False) == 8
+ assert descr6.get_return_type() == history.FLOAT
+ assert descr6.arg_classes == "i"
+
def test_get_call_descr_translated():
c1 = GcCache(True)
T = lltype.GcStruct('T')
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -6,6 +6,8 @@
from pypy.jit.metainterp import history
from pypy.jit.metainterp.resoperation import ResOperation, rop
from pypy.jit.codewriter import heaptracker
+from pypy.rlib.rarithmetic import r_longlong, r_ulonglong
+from pypy.rlib.longlong2float import longlong2float, float2longlong
# The point of the class organization in this file is to make instances
# as compact as possible. This is done by not storing the field size or
@@ -29,6 +31,14 @@
assert isinstance(ARRAY, lltype.GcArray)
+if lltype.SignedLongLong is lltype.Signed:
+ def is_longlong(TYPE):
+ return False
+else:
+ assert rffi.sizeof(lltype.SignedLongLong) == rffi.sizeof(lltype.Float)
+ def is_longlong(TYPE):
+ return TYPE in (lltype.SignedLongLong, lltype.UnsignedLongLong)
+
# ____________________________________________________________
# SizeDescrs
@@ -264,6 +274,8 @@
def create_call_stub(self, rtyper, RESULT):
def process(c):
+ if c == 'L':
+ return 'float2longlong(%s)' % (process('f'),)
arg = 'args_%s[%d]' % (c, seen[c])
seen[c] += 1
return arg
@@ -277,6 +289,10 @@
return llmemory.GCREF
elif arg == 'v':
return lltype.Void
+ elif arg == 'L':
+ return lltype.SignedLongLong
+ else:
+ raise AssertionError(arg)
seen = {'i': 0, 'r': 0, 'f': 0}
args = ", ".join([process(c) for c in self.arg_classes])
@@ -286,7 +302,7 @@
elif self.get_return_type() == history.REF:
result = 'lltype.cast_opaque_ptr(llmemory.GCREF, res)'
elif self.get_return_type() == history.FLOAT:
- result = 'res'
+ result = 'cast_to_float(res)'
elif self.get_return_type() == history.VOID:
result = 'None'
else:
@@ -308,11 +324,21 @@
assert self._return_type == return_type
assert self.arg_classes.count('i') == len(args_i or ())
assert self.arg_classes.count('r') == len(args_r or ())
- assert self.arg_classes.count('f') == len(args_f or ())
+ assert (self.arg_classes.count('f') +
+ self.arg_classes.count('L')) == len(args_f or ())
def repr_of_descr(self):
return '<%s>' % self._clsname
+def cast_to_float(x):
+ if isinstance(x, r_longlong):
+ return longlong2float(x)
+ if isinstance(x, r_ulonglong):
+ return longlong2float(rffi.cast(lltype.SignedLongLong, x))
+ assert isinstance(x, float)
+ return x
+cast_to_float._annspecialcase_ = 'specialize:argtype(0)'
+
class BaseIntCallDescr(BaseCallDescr):
# Base class of the various subclasses of descrs corresponding to
@@ -371,6 +397,9 @@
def get_result_size(self, translate_support_code):
return symbolic.get_size(lltype.Float, translate_support_code)
+class LongLongCallDescr(FloatCallDescr):
+ _clsname = 'LongLongCallDescr'
+
class VoidCallDescr(BaseCallDescr):
_clsname = 'VoidCallDescr'
_return_type = history.VOID
@@ -383,6 +412,8 @@
return VoidCallDescr
if RESULT is lltype.Float:
return FloatCallDescr
+ if is_longlong(RESULT):
+ return LongLongCallDescr
return getDescrClass(RESULT, BaseIntCallDescr, GcPtrCallDescr,
NonGcPtrCallDescr, 'Call', 'get_result_size',
Ellipsis, # <= floatattrname should not be used here
@@ -394,7 +425,11 @@
kind = getkind(ARG)
if kind == 'int': arg_classes.append('i')
elif kind == 'ref': arg_classes.append('r')
- elif kind == 'float': arg_classes.append('f')
+ elif kind == 'float':
+ if is_longlong(ARG):
+ arg_classes.append('L')
+ else:
+ arg_classes.append('f')
else:
raise NotImplementedError('ARG = %r' % (ARG,))
arg_classes = ''.join(arg_classes)
@@ -432,7 +467,7 @@
return symbolic.get_size(TYPE, translate_support_code)
setattr(Descr, methodname, method)
#
- if TYPE is lltype.Float:
+ if TYPE is lltype.Float or is_longlong(TYPE):
setattr(Descr, floatattrname, True)
elif TYPE is not lltype.Bool and rffi.cast(TYPE, -1) == -1:
setattr(Descr, signedattrname, True)
diff --git a/pypy/rlib/rsre/rsre_core.py b/pypy/rlib/rsre/rsre_core.py
--- a/pypy/rlib/rsre/rsre_core.py
+++ b/pypy/rlib/rsre/rsre_core.py
@@ -385,10 +385,13 @@
marks = p.marks
enum = p.enum.move_to_next_result(ctx)
#
+ # zero-width match protection
min = ctx.pat(ppos+1)
- if (enum is not None and
- (ptr != ctx.match_end or self.num_pending < min)):
- # ^^^^^^^^^^ zero-width match protection
+ if self.num_pending >= min:
+ while enum is not None and ptr == ctx.match_end:
+ enum = enum.move_to_next_result(ctx)
+ #
+ if enum is not None:
# matched one more 'item'. record it and continue.
self.pending = Pending(ptr, marks, enum, self.pending)
self.num_pending += 1
@@ -436,12 +439,15 @@
if max == 65535 or self.num_pending < max:
# try to match one more 'item'
enum = sre_match(ctx, ppos + 3, ptr, marks)
+ #
+ # zero-width match protection
+ if self.num_pending >= min:
+ while enum is not None and ptr == ctx.match_end:
+ enum = enum.move_to_next_result(ctx)
else:
enum = None # 'max' reached, no more matches
- while (enum is None or
- (ptr == ctx.match_end and self.num_pending >= min)):
- # ^^^^^^^^^^ zero-width match protection
+ while enum is None:
# 'item' does not match; try to get further results from
# the 'pending' list.
p = self.pending
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -177,6 +177,13 @@
#print 'wrapping', x, '->', w_result
return w_result
if isinstance(x, base_int):
+ if self.config.objspace.std.withsmalllong:
+ from pypy.objspace.std.smalllongobject import W_SmallLongObject
+ from pypy.rlib.rarithmetic import r_longlong, r_ulonglong
+ from pypy.rlib.rarithmetic import longlongmax
+ if (not isinstance(x, r_ulonglong)
+ or x <= r_ulonglong(longlongmax)):
+ return W_SmallLongObject(r_longlong(x))
x = widen(x)
if isinstance(x, int):
return self.newint(x)
@@ -207,6 +214,16 @@
# The following cases are even stranger.
# Really really only for tests.
if type(x) is long:
+ if self.config.objspace.std.withsmalllong:
+ from pypy.rlib.rarithmetic import r_longlong
+ try:
+ rx = r_longlong(x)
+ except OverflowError:
+ pass
+ else:
+ from pypy.objspace.std.smalllongobject import \
+ W_SmallLongObject
+ return W_SmallLongObject(rx)
return W_LongObject.fromlong(x)
if isinstance(x, slice):
return W_SliceObject(self.wrap(x.start),
@@ -269,6 +286,9 @@
return unpackcomplex(self, w_complex)
def newlong(self, val): # val is an int
+ if self.config.objspace.std.withsmalllong:
+ from pypy.objspace.std.smalllongobject import W_SmallLongObject
+ return W_SmallLongObject.fromint(val)
return W_LongObject.fromint(self, val)
def newlong_from_rbigint(self, val):
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -155,6 +155,7 @@
if policy is None:
policy = JitPolicy()
policy.set_supports_floats(self.cpu.supports_floats)
+ policy.set_supports_longlong(self.cpu.supports_longlong)
graphs = self.codewriter.find_all_graphs(policy)
policy.dump_unsafe_loops()
self.check_access_directly_sanity(graphs)
diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -4,6 +4,11 @@
class AbstractCPU(object):
supports_floats = False
+ supports_longlong = False
+ # ^^^ This is only useful on 32-bit platforms. If True,
+ # longlongs are supported by the JIT, but stored as doubles.
+ # Boxes and Consts are BoxFloats and ConstFloats.
+
done_with_this_frame_void_v = -1
done_with_this_frame_int_v = -1
done_with_this_frame_ref_v = -1
diff --git a/pypy/module/cpyext/include/modsupport.inl b/pypy/module/cpyext/include/modsupport.inl
deleted file mode 100644
--- a/pypy/module/cpyext/include/modsupport.inl
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- C -*- */
-/* Module support interface */
-
-#ifndef Py_MODSUPPORT_INL
-#define Py_MODSUPPORT_INL
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifdef PYPY_STANDALONE
-/* XXX1 On translation, forwarddecl.h is included after this file */
-/* XXX2 genc.py transforms "const char*" into "char*" */
-extern PyObject *_Py_InitPyPyModule(char *, PyMethodDef *, char *, PyObject *, int);
-#endif
-
-Py_LOCAL_INLINE(PyObject *) Py_InitModule4(
- const char* name, PyMethodDef* methods,
- const char* doc, PyObject *self,
- int api_version)
-{
- return _Py_InitPyPyModule((char*)name, methods,
- (char*)doc, self,
- api_version);
-}
-
-#ifdef __cplusplus
-}
-#endif
-#endif /* !Py_MODSUPPORT_INL */
diff --git a/pypy/jit/codewriter/call.py b/pypy/jit/codewriter/call.py
--- a/pypy/jit/codewriter/call.py
+++ b/pypy/jit/codewriter/call.py
@@ -188,7 +188,8 @@
FUNC.RESULT)
return (fnaddr, calldescr)
- def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE):
+ def getcalldescr(self, op, oopspecindex=EffectInfo.OS_NONE,
+ extraeffect=None):
"""Return the calldescr that describes all calls done by 'op'.
This returns a calldescr that we can put in the corresponding
call operation in the calling jitcode. It gets an effectinfo
@@ -216,17 +217,18 @@
assert not NON_VOID_ARGS, ("arguments not supported for "
"loop-invariant function!")
# build the extraeffect
- if self.virtualizable_analyzer.analyze(op):
- extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
- elif loopinvariant:
- extraeffect = EffectInfo.EF_LOOPINVARIANT
- elif pure:
- # XXX check what to do about exceptions (also MemoryError?)
- extraeffect = EffectInfo.EF_PURE
- elif self._canraise(op):
- extraeffect = EffectInfo.EF_CAN_RAISE
- else:
- extraeffect = EffectInfo.EF_CANNOT_RAISE
+ if extraeffect is None:
+ if self.virtualizable_analyzer.analyze(op):
+ extraeffect = EffectInfo.EF_FORCES_VIRTUAL_OR_VIRTUALIZABLE
+ elif loopinvariant:
+ extraeffect = EffectInfo.EF_LOOPINVARIANT
+ elif pure:
+ # XXX check what to do about exceptions (also MemoryError?)
+ extraeffect = EffectInfo.EF_PURE
+ elif self._canraise(op):
+ extraeffect = EffectInfo.EF_CAN_RAISE
+ else:
+ extraeffect = EffectInfo.EF_CANNOT_RAISE
#
effectinfo = effectinfo_from_writeanalyze(
self.readwrite_analyzer.analyze(op), self.cpu, extraeffect,
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
@@ -37,6 +37,7 @@
from pypy.rlib import rgc
from pypy.jit.backend.x86.jump import remap_frame_layout
from pypy.jit.metainterp.history import ConstInt, BoxInt
+from pypy.jit.codewriter.effectinfo import EffectInfo
# darwin requires the stack to be 16 bytes aligned on calls. Same for gcc 4.5.0,
# better safe than sorry
@@ -769,6 +770,11 @@
def regalloc_perform_discard(self, op, arglocs):
genop_discard_list[op.getopnum()](self, op, arglocs)
+ def regalloc_perform_llong(self, op, arglocs, resloc):
+ effectinfo = op.getdescr().get_extra_info()
+ oopspecindex = effectinfo.oopspecindex
+ genop_llong_list[oopspecindex](self, op, arglocs, resloc)
+
def regalloc_perform_with_guard(self, op, guard_op, faillocs,
arglocs, resloc, current_depths):
faildescr = guard_op.getdescr()
@@ -1115,6 +1121,88 @@
self.mc.XOR_rr(edx.value, edx.value)
self.mc.DIV_r(ecx.value)
+ genop_llong_add = _binaryop("PADDQ", True)
+ genop_llong_sub = _binaryop("PSUBQ")
+ genop_llong_and = _binaryop("PAND", True)
+ genop_llong_or = _binaryop("POR", True)
+ genop_llong_xor = _binaryop("PXOR", True)
+
+ def genop_llong_to_int(self, op, arglocs, resloc):
+ loc = arglocs[0]
+ assert isinstance(resloc, RegLoc)
+ if isinstance(loc, RegLoc):
+ self.mc.MOVD_rx(resloc.value, loc.value)
+ elif isinstance(loc, StackLoc):
+ self.mc.MOV_rb(resloc.value, loc.value)
+ else:
+ not_implemented("llong_to_int: %s" % (loc,))
+
+ def genop_llong_from_int(self, op, arglocs, resloc):
+ loc = arglocs[0]
+ if isinstance(loc, ConstFloatLoc):
+ self.mc.MOVSD(resloc, loc)
+ else:
+ assert loc is eax
+ assert isinstance(resloc, RegLoc)
+ loc2 = arglocs[1]
+ assert isinstance(loc2, RegLoc)
+ self.mc.CDQ() # eax -> eax:edx
+ self.mc.MOVD_xr(resloc.value, eax.value)
+ self.mc.MOVD_xr(loc2.value, edx.value)
+ self.mc.PUNPCKLDQ_xx(resloc.value, loc2.value)
+
+ def genop_llong_from_two_ints(self, op, arglocs, resloc):
+ assert isinstance(resloc, RegLoc)
+ loc1, loc2, loc3 = arglocs
+ #
+ if isinstance(loc1, ConstFloatLoc):
+ self.mc.MOVSD(resloc, loc1)
+ else:
+ assert isinstance(loc1, RegLoc)
+ self.mc.MOVD_xr(resloc.value, loc1.value)
+ #
+ if loc2 is not None:
+ assert isinstance(loc3, RegLoc)
+ if isinstance(loc2, ConstFloatLoc):
+ self.mc.MOVSD(loc3, loc2)
+ else:
+ assert isinstance(loc2, RegLoc)
+ self.mc.MOVD_xr(loc3.value, loc2.value)
+ self.mc.PUNPCKLDQ_xx(resloc.value, loc3.value)
+
+ def genop_llong_eq(self, op, arglocs, resloc):
+ loc1, loc2, locxtmp = arglocs
+ self.mc.MOVSD(locxtmp, loc1)
+ self.mc.PCMPEQD(locxtmp, loc2)
+ self.mc.PMOVMSKB_rx(resloc.value, locxtmp.value)
+ # Now the lower 8 bits of resloc contain 0x00, 0x0F, 0xF0 or 0xFF
+ # depending on the result of the comparison of each of the two
+ # double-words of loc1 and loc2. The higher 8 bits contain random
+ # results. We want to map 0xFF to 1, and 0x00, 0x0F and 0xF0 to 0.
+ self.mc.CMP8_ri(resloc.value | rx86.BYTE_REG_FLAG, -1)
+ self.mc.SBB_rr(resloc.value, resloc.value)
+ self.mc.ADD_ri(resloc.value, 1)
+
+ def genop_llong_ne(self, op, arglocs, resloc):
+ loc1, loc2, locxtmp = arglocs
+ self.mc.MOVSD(locxtmp, loc1)
+ self.mc.PCMPEQD(locxtmp, loc2)
+ self.mc.PMOVMSKB_rx(resloc.value, locxtmp.value)
+ # Now the lower 8 bits of resloc contain 0x00, 0x0F, 0xF0 or 0xFF
+ # depending on the result of the comparison of each of the two
+ # double-words of loc1 and loc2. The higher 8 bits contain random
+ # results. We want to map 0xFF to 0, and 0x00, 0x0F and 0xF0 to 1.
+ self.mc.CMP8_ri(resloc.value | rx86.BYTE_REG_FLAG, -1)
+ self.mc.SBB_rr(resloc.value, resloc.value)
+ self.mc.NEG_r(resloc.value)
+
+ def genop_llong_lt(self, op, arglocs, resloc):
+ # XXX just a special case for now: "x < 0"
+ loc1, = arglocs
+ self.mc.PMOVMSKB_rx(resloc.value, loc1.value)
+ self.mc.SHR_ri(resloc.value, 7)
+ self.mc.AND_ri(resloc.value, 1)
+
def genop_new_with_vtable(self, op, arglocs, result_loc):
assert result_loc is eax
loc_vtable = arglocs[-1]
@@ -1725,7 +1813,14 @@
self._emit_call(x, arglocs, 3, tmp=tmp)
if IS_X86_32 and isinstance(resloc, StackLoc) and resloc.width == 8:
- self.mc.FSTP_b(resloc.value) # float return
+ # a float or a long long return
+ from pypy.jit.backend.llsupport.descr import LongLongCallDescr
+ if isinstance(op.getdescr(), LongLongCallDescr):
+ self.mc.MOV_br(resloc.value, eax.value) # long long
+ self.mc.MOV_br(resloc.value + 4, edx.value)
+ # XXX should ideally not move the result on the stack
+ else:
+ self.mc.FSTP_b(resloc.value) # float return
elif size == WORD:
assert resloc is eax or resloc is xmm0 # a full word
elif size == 0:
@@ -1959,6 +2054,7 @@
genop_discard_list = [Assembler386.not_implemented_op_discard] * rop._LAST
genop_list = [Assembler386.not_implemented_op] * rop._LAST
+genop_llong_list = {}
genop_guard_list = [Assembler386.not_implemented_op_guard] * rop._LAST
for name, value in Assembler386.__dict__.iteritems():
@@ -1970,6 +2066,10 @@
opname = name[len('genop_guard_'):]
num = getattr(rop, opname.upper())
genop_guard_list[num] = value
+ elif name.startswith('genop_llong_'):
+ opname = name[len('genop_llong_'):]
+ num = getattr(EffectInfo, 'OS_LLONG_' + opname.upper())
+ genop_llong_list[num] = value
elif name.startswith('genop_'):
opname = name[len('genop_'):]
num = getattr(rop, opname.upper())
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -19,6 +19,7 @@
from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
from pypy.jit.metainterp.typesystem import deref
from pypy.rlib import rgc
+from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask
def getargtypes(annotator, values):
if values is None: # for backend tests producing stand-alone exe's
@@ -222,6 +223,136 @@
return x
+# long long support
+# -----------------
+
+def u_to_longlong(x):
+ return rffi.cast(lltype.SignedLongLong, x)
+
+def _ll_1_llong_invert(xll):
+ y = ~r_ulonglong(xll)
+ return u_to_longlong(y)
+
+def _ll_2_llong_lt(xll, yll):
+ return xll < yll
+
+def _ll_2_llong_le(xll, yll):
+ return xll <= yll
+
+def _ll_2_llong_eq(xll, yll):
+ return xll == yll
+
+def _ll_2_llong_ne(xll, yll):
+ return xll != yll
+
+def _ll_2_llong_gt(xll, yll):
+ return xll > yll
+
+def _ll_2_llong_ge(xll, yll):
+ return xll >= yll
+
+def _ll_2_llong_ult(xull, yull):
+ return xull < yull
+
+def _ll_2_llong_ule(xull, yull):
+ return xull <= yull
+
+def _ll_2_llong_ugt(xull, yull):
+ return xull > yull
+
+def _ll_2_llong_uge(xull, yull):
+ return xull >= yull
+
+def _ll_2_llong_add(xll, yll):
+ z = r_ulonglong(xll) + r_ulonglong(yll)
+ return u_to_longlong(z)
+
+def _ll_2_llong_sub(xll, yll):
+ z = r_ulonglong(xll) - r_ulonglong(yll)
+ return u_to_longlong(z)
+
+def _ll_2_llong_mul(xll, yll):
+ z = r_ulonglong(xll) * r_ulonglong(yll)
+ return u_to_longlong(z)
+
+def _ll_2_llong_and(xll, yll):
+ z = r_ulonglong(xll) & r_ulonglong(yll)
+ return u_to_longlong(z)
+
+def _ll_2_llong_or(xll, yll):
+ z = r_ulonglong(xll) | r_ulonglong(yll)
+ return u_to_longlong(z)
+
+def _ll_2_llong_xor(xll, yll):
+ z = r_ulonglong(xll) ^ r_ulonglong(yll)
+ return u_to_longlong(z)
+
+def _ll_2_llong_lshift(xll, y):
+ z = r_ulonglong(xll) << y
+ return u_to_longlong(z)
+
+def _ll_2_llong_rshift(xll, y):
+ return xll >> y
+
+def _ll_2_llong_urshift(xull, y):
+ return xull >> y
+
+def _ll_1_llong_from_int(x):
+ return r_longlong(intmask(x))
+
+def _ll_2_llong_from_two_ints(x_lo, x_hi):
+ z = (r_ulonglong(r_uint(x_hi)) << 32) | r_ulonglong(r_uint(x_lo))
+ return u_to_longlong(z)
+
+def _ll_1_llong_to_int(xll):
+ return intmask(xll)
+
+def _ll_1_llong_from_float(xf):
+ return r_longlong(xf)
+
+def _ll_1_llong_to_float(xll):
+ return float(rffi.cast(lltype.SignedLongLong, xll))
+
+
+def _ll_1_llong_abs(xll):
+ if xll < 0:
+ return -xll
+ else:
+ return xll
+
+def _ll_2_llong_floordiv(xll, yll):
+ return llop.llong_floordiv(lltype.SignedLongLong, xll, yll)
+
+def _ll_2_llong_floordiv_zer(xll, yll):
+ if yll == 0:
+ raise ZeroDivisionError
+ return llop.llong_floordiv(lltype.SignedLongLong, xll, yll)
+
+def _ll_2_llong_mod(xll, yll):
+ return llop.llong_mod(lltype.SignedLongLong, xll, yll)
+
+def _ll_2_llong_mod_zer(xll, yll):
+ if yll == 0:
+ raise ZeroDivisionError
+ return llop.llong_mod(lltype.SignedLongLong, xll, yll)
+
+def _ll_2_ullong_floordiv(xll, yll):
+ return llop.ullong_floordiv(lltype.SignedLongLong, xll, yll)
+
+def _ll_2_ullong_floordiv_zer(xll, yll):
+ if yll == 0:
+ raise ZeroDivisionError
+ return llop.ullong_floordiv(lltype.SignedLongLong, xll, yll)
+
+def _ll_2_ullong_mod(xll, yll):
+ return llop.ullong_mod(lltype.SignedLongLong, xll, yll)
+
+def _ll_2_ullong_mod_zer(xll, yll):
+ if yll == 0:
+ raise ZeroDivisionError
+ return llop.ullong_mod(lltype.SignedLongLong, xll, yll)
+
+
# libffi support
# --------------
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -4,6 +4,7 @@
from pypy.config.config import OptionDescription, BoolOption, IntOption, ArbitraryOption
from pypy.config.config import ChoiceOption, StrOption, to_optparse, Config
from pypy.config.config import ConflictConfigError
+from pypy.config.translationoption import IS_64_BITS
modulepath = py.path.local(__file__).dirpath().dirpath().join("module")
all_modules = [p.basename for p in modulepath.listdir()
@@ -212,6 +213,11 @@
IntOption("prebuiltintto", "highest integer which is prebuilt",
default=100, cmdline="--prebuiltintto"),
+ BoolOption("withsmalllong", "use a version of 'long' in a C long long",
+ default=False,
+ requires=[("objspace.std.withsmallint", False)]),
+ # ^^^ because of missing delegate_xx2yy
+
BoolOption("withstrjoin", "use strings optimized for addition",
default=False),
@@ -345,6 +351,8 @@
config.objspace.std.suggest(optimized_list_getitem=True)
config.objspace.std.suggest(getattributeshortcut=True)
config.objspace.std.suggest(newshortcut=True)
+ if not IS_64_BITS:
+ config.objspace.std.suggest(withsmalllong=True)
# extra costly optimizations only go in level 3
if level == '3':
@@ -360,6 +368,8 @@
config.objspace.std.suggest(withmapdict=True)
config.objspace.std.suggest(withstrslice=True)
config.objspace.std.suggest(withstrjoin=True)
+ if not IS_64_BITS:
+ config.objspace.std.suggest(withsmalllong=True)
# xxx other options? ropes maybe?
# completely disable geninterp in a level 0 translation
More information about the Pypy-commit
mailing list