Author: Lukas Diekmann <[email protected]>
Branch: type-specialized-instances
Changeset: r51753:b15e618e3d82
Date: 2012-01-25 15:35 +0100
http://bitbucket.org/pypy/pypy/changeset/b15e618e3d82/
Log: (cfbolz, l.diekmann): merge int-tag-untag-as-operationus to get the
necessary optimizations to make this branch useful
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
@@ -92,10 +92,13 @@
'int_is_true' : (('int',), 'bool'),
'int_is_zero' : (('int',), 'bool'),
'int_neg' : (('int',), 'int'),
+ 'int_tag' : (('int', ), 'int'),
+ 'int_untag' : (('int', ), 'int'),
'int_invert' : (('int',), 'int'),
'int_add_ovf' : (('int', 'int'), 'int'),
'int_sub_ovf' : (('int', 'int'), 'int'),
'int_mul_ovf' : (('int', 'int'), 'int'),
+ 'int_tag_ovf' : (('int', ), 'int'),
'uint_add' : (('int', 'int'), 'int'),
'uint_sub' : (('int', 'int'), 'int'),
'uint_mul' : (('int', 'int'), 'int'),
@@ -747,6 +750,17 @@
if not flag:
raise GuardFailed
+ def op_int_tag_ovf(self, _, x):
+ try:
+ z = ovfcheck(x << 1) + 1
+ except OverflowError:
+ ovf = True
+ z = 0
+ else:
+ ovf = False
+ self.overflow_flag = ovf
+ return z
+
def op_int_add_ovf(self, _, x, y):
try:
z = ovfcheck(x + y)
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
@@ -294,6 +294,9 @@
class BinaryOvfOperation(AbstractOvfOperation, BinaryOperation):
pass
+class UnaryOvfOperation(AbstractOvfOperation, UnaryOperation):
+ pass
+
class AbstractFloatOperation(AbstractOperation):
def filter(self, builder):
if not builder.cpu.supports_floats:
@@ -422,6 +425,8 @@
for _op in [rop.INT_NEG,
rop.INT_INVERT,
+ rop.INT_TAG,
+ rop.INT_UNTAG,
]:
OPERATIONS.append(UnaryOperation(_op))
@@ -434,6 +439,7 @@
rop.INT_MUL_OVF,
]:
OPERATIONS.append(BinaryOvfOperation(_op))
+OPERATIONS.append(UnaryOvfOperation(rop.INT_TAG_OVF))
for _op in [rop.FLOAT_ADD,
rop.FLOAT_SUB,
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
@@ -1208,6 +1208,18 @@
genop_guard_float_gt = _cmpop_guard_float("A", "B", "BE","AE")
genop_guard_float_ge = _cmpop_guard_float("AE","BE", "B", "A")
+
+ def genop_int_tag(self, op, arglocs, resloc):
+ loc, = arglocs
+ assert isinstance(loc, RegLoc)
+ assert isinstance(resloc, RegLoc)
+ # res = loc + (loc << 0) + 1
+ self.mc.LEA_ra(resloc.value, (loc.value, loc.value, 0, 1))
+
+ def genop_int_untag(self, op, arglocs, resloc):
+ loc, = arglocs
+ self.mc.SAR(loc, imm1)
+
def genop_math_sqrt(self, op, arglocs, resloc):
self.mc.SQRTSD(arglocs[0], resloc)
@@ -1628,6 +1640,11 @@
self.genop_int_mul(op, arglocs, result_loc)
return self._gen_guard_overflow(guard_op, guard_token)
+ def genop_guard_int_tag_ovf(self, op, guard_op, guard_token, arglocs,
result_loc):
+ self.mc.STC()
+ self.mc.ADC(arglocs[0], arglocs[0])
+ return self._gen_guard_overflow(guard_op, guard_token)
+
def genop_guard_guard_false(self, ign_1, guard_op, guard_token, locs,
ign_2):
loc = locs[0]
self.mc.TEST(loc, loc)
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
@@ -619,11 +619,22 @@
consider_int_sub_ovf = _consider_binop_with_guard
consider_int_add_ovf = _consider_binop_with_guard
+ def consider_int_tag_ovf(self, op, guard_op):
+ loc = self.rm.force_result_in_reg(op.result, op.getarg(0))
+ self.perform_with_guard(op, guard_op, [loc], loc)
+
+ def consider_int_tag(self, op):
+ loc = self.rm.make_sure_var_in_reg(op.getarg(0))
+ self.rm.possibly_free_vars_for_op(op)
+ res = self.rm.force_allocate_reg(op.result)
+ self.Perform(op, [loc], res)
+
def consider_int_neg(self, op):
res = self.rm.force_result_in_reg(op.result, op.getarg(0))
self.Perform(op, [res], res)
consider_int_invert = consider_int_neg
+ consider_int_untag = consider_int_neg
def consider_int_lshift(self, op):
if isinstance(op.getarg(1), Const):
diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py
--- a/pypy/jit/backend/x86/regloc.py
+++ b/pypy/jit/backend/x86/regloc.py
@@ -530,6 +530,7 @@
BTS = _binaryop('BTS')
ADD = _binaryop('ADD')
+ ADC = _binaryop('ADC')
SUB = _binaryop('SUB')
IMUL = _binaryop('IMUL')
NEG = _unaryop('NEG')
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
@@ -470,6 +470,7 @@
# ------------------------------ Arithmetic ------------------------------
ADD_ri,ADD_rr,ADD_rb,_,_,ADD_rm,ADD_rj,_,_ = common_modes(0)
+ ADC_ri,ADC_rr,ADC_rb,_,_,ADC_rm,ADC_rj,_,_ = common_modes(2)
OR_ri, OR_rr, OR_rb, _,_,OR_rm, OR_rj, _,_ = common_modes(1)
AND_ri,AND_rr,AND_rb,_,_,AND_rm,AND_rj,_,_ = common_modes(4)
SUB_ri,SUB_rr,SUB_rb,_,_,SUB_rm,SUB_rj,SUB_ji8,SUB_mi8 = common_modes(5)
@@ -577,6 +578,8 @@
FSTPL_b = insn('\xDD', orbyte(3<<3), stack_bp(1)) # rffi.DOUBLE ('as'
wants L??)
FSTPS_s = insn('\xD9', orbyte(3<<3), stack_sp(1)) # lltype.SingleFloat
+ STC = insn('\xF9')
+
# ------------------------------ Random mess -----------------------
RDTSC = insn('\x0F\x31')
diff --git a/pypy/jit/backend/x86/test/test_regalloc.py
b/pypy/jit/backend/x86/test/test_regalloc.py
--- a/pypy/jit/backend/x86/test/test_regalloc.py
+++ b/pypy/jit/backend/x86/test/test_regalloc.py
@@ -692,3 +692,27 @@
self.run(loop, 4, 7)
assert self.getint(0) == 29
+ def test_int_untag(self):
+ ops = '''
+ [i0]
+ i1 = int_untag(i0)
+ finish(i1)
+ '''
+ self.interpret(ops, [1129])
+ assert self.getint(0) == 564
+ self.interpret(ops, [-1129])
+ assert self.getint(0) == -565
+
+ def test_int_tag(self):
+ ops = '''
+ [i0]
+ i1 = int_tag(i0)
+ i2 = int_tag(i0)
+ finish(i1, i2)
+ '''
+ self.interpret(ops, [1129])
+ assert self.getint(0) == 1129 * 2 + 1
+ assert self.getint(1) == 1129 * 2 + 1
+ self.interpret(ops, [-1129])
+ assert self.getint(0) == -1129 * 2 + 1
+ assert self.getint(1) == -1129 * 2 + 1
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
@@ -290,6 +290,10 @@
op1 = SpaceOperation('-live-', [], None)
return [op, op1]
+ def rewrite_op_int_tag_ovf(self, op):
+ op1 = SpaceOperation('-live-', [], None)
+ return [op, op1]
+
# ----------
# Various kinds of calls
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
@@ -446,6 +446,18 @@
def bhimpl_int_invert(a):
return intmask(~a)
+ @arguments("i", returns="i")
+ def bhimpl_int_untag(a):
+ ll_assert((a & 1) == 1, "bhimpl_int_untag: not an odd int")
+ return a >> 1
+ @arguments("i", returns="i")
+ def bhimpl_int_tag(a):
+ return intmask(a << 1) + 1 # mostly there for test_random
+ @arguments("i", returns="i")
+ def bhimpl_int_tag_ovf(a):
+ return ovfcheck(a << 1) + 1
+
+
@arguments("i", "i", returns="i")
def bhimpl_int_lt(a, b):
return a < b
@@ -508,7 +520,6 @@
@arguments("r", returns="i")
def bhimpl_cast_ptr_to_int(a):
i = lltype.cast_ptr_to_int(a)
- ll_assert((i & 1) == 1, "bhimpl_cast_ptr_to_int: not an odd int")
return i
@arguments("i", returns="r")
def bhimpl_cast_int_to_ptr(i):
diff --git a/pypy/jit/metainterp/executor.py b/pypy/jit/metainterp/executor.py
--- a/pypy/jit/metainterp/executor.py
+++ b/pypy/jit/metainterp/executor.py
@@ -224,6 +224,18 @@
z = 0
return BoxInt(z)
+def do_int_tag_ovf(cpu, metainterp, box1):
+ # the overflow operations can be called without a metainterp, if an
+ # overflow cannot occur
+ a = box1.getint()
+ try:
+ z = ovfcheck(a << 1)
+ except OverflowError:
+ assert metainterp is not None
+ metainterp.execute_raised(OverflowError(), constant=True)
+ z = 0
+ return BoxInt(z + 1)
+
def do_same_as(cpu, _, box):
return box.clonebox()
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py
b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -62,6 +62,14 @@
def optimize_INT_AND(self, op):
v1 = self.getvalue(op.getarg(0))
v2 = self.getvalue(op.getarg(1))
+ if (self.optimizer.metainterp_sd.config.translation.taggedpointers and
+ v2.is_constant() and v2.box.getint() == 1):
+ if self.has_pure_result(rop.INT_UNTAG, [v1.box], None):
+ # the result of untagging the int is known, so the box must be
+ # tagged, so int_and(x, 1) == 1
+ value = self.getvalue(ConstInt(1))
+ self.optimizer.make_equal_to(op.result, value)
+ return
self.emit_operation(op)
r = self.getvalue(op.result)
@@ -163,18 +171,16 @@
def optimize_GUARD_NO_OVERFLOW(self, op):
lastop = self.last_emitted_operation
if lastop is not None:
+ # If the INT_xxx_OVF was replaced with INT_xxx, then we can kill
+ # the GUARD_NO_OVERFLOW.
+ if not lastop.is_ovf():
+ return
opnum = lastop.getopnum()
args = lastop.getarglist()
result = lastop.result
- # If the INT_xxx_OVF was replaced with INT_xxx, then we can kill
- # the GUARD_NO_OVERFLOW.
- if (opnum == rop.INT_ADD or
- opnum == rop.INT_SUB or
- opnum == rop.INT_MUL):
- return
# Else, synthesize the non overflowing op for optimize_default to
- # reuse, as well as the reverse op
- elif opnum == rop.INT_ADD_OVF:
+ # reuse, as well as the reverse ops
+ if opnum == rop.INT_ADD_OVF:
self.pure(rop.INT_ADD, args[:], result)
self.pure(rop.INT_SUB, [result, args[1]], args[0])
self.pure(rop.INT_SUB, [result, args[0]], args[1])
@@ -184,6 +190,11 @@
self.pure(rop.INT_SUB, [args[0], result], args[1])
elif opnum == rop.INT_MUL_OVF:
self.pure(rop.INT_MUL, args[:], result)
+ elif opnum == rop.INT_TAG_OVF:
+ v1 = self.getvalue(lastop.getarg(0))
+ maxbounds = IntBound((-sys.maxint-1) >> 1, sys.maxint >> 1)
+ v1.intbound.intersect(maxbounds)
+ self.pure(rop.INT_UNTAG, [result], args[0])
self.emit_operation(op)
def optimize_GUARD_OVERFLOW(self, op):
@@ -193,7 +204,7 @@
if lastop is None:
raise InvalidLoop
opnum = lastop.getopnum()
- if opnum not in (rop.INT_ADD_OVF, rop.INT_SUB_OVF, rop.INT_MUL_OVF):
+ if not lastop.is_ovf():
raise InvalidLoop
self.emit_operation(op)
@@ -294,6 +305,32 @@
else:
self.emit_operation(op)
+ def optimize_INT_TAG_OVF(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ resbound = v1.intbound.mul(2).add(1)
+ if resbound.bounded():
+ op = op.copy_and_change(rop.INT_TAG)
+ self.optimize_INT_TAG(op) # emit the op
+ else:
+ self.emit_operation(op)
+
+ def optimize_INT_TAG(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ self.emit_operation(op)
+ r = self.getvalue(op.result)
+ resbound = v1.intbound.mul(2).add(1)
+ r.intbound.intersect(resbound)
+ maxbounds = IntBound((-sys.maxint-1) >> 1, sys.maxint >> 1)
+ v1.intbound.intersect(maxbounds)
+ self.pure(rop.INT_UNTAG, [op.result], op.getarg(0))
+
+ def optimize_INT_UNTAG(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ self.pure(rop.INT_TAG, [op.result], op.getarg(0))
+ self.emit_operation(op)
+ r = self.getvalue(op.result)
+ r.intbound.intersect(v1.intbound.rshift_bound(IntBound(1, 1)))
+
def optimize_ARRAYLEN_GC(self, op):
self.emit_operation(op)
array = self.getvalue(op.getarg(0))
diff --git a/pypy/jit/metainterp/optimizeopt/intutils.py
b/pypy/jit/metainterp/optimizeopt/intutils.py
--- a/pypy/jit/metainterp/optimizeopt/intutils.py
+++ b/pypy/jit/metainterp/optimizeopt/intutils.py
@@ -101,8 +101,32 @@
return res
def mul(self, value):
- return self.mul_bound(IntBound(value, value))
-
+ upper = 0
+ has_upper = False
+ if self.has_upper:
+ try:
+ upper = ovfcheck(self.upper * value)
+ except OverflowError:
+ pass
+ else:
+ has_upper = True
+ lower = 0
+ has_lower = False
+ if self.has_lower:
+ try:
+ lower = ovfcheck(self.lower * value)
+ except OverflowError:
+ pass
+ else:
+ has_lower = True
+ if value < 0:
+ has_upper, has_lower = has_lower, has_upper
+ upper, lower = lower, upper
+ result = IntBound(lower, upper)
+ result.has_lower = has_lower
+ result.has_upper = has_upper
+ return result
+
def add_bound(self, other):
res = self.clone()
if other.has_upper:
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_intutils.py
b/pypy/jit/metainterp/optimizeopt/test/test_intutils.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/optimizeopt/test/test_intutils.py
@@ -0,0 +1,29 @@
+from pypy.jit.metainterp.optimizeopt import intutils
+
+# XXX this file should really be filled with tests for all operations!
+
+def test_mul_with_constant():
+ x = intutils.IntBound(0, 100)
+ y = x.mul(2)
+ assert y.has_lower
+ assert y.has_upper
+ assert y.lower == 0
+ assert y.upper == 200
+
+ y = x.mul(-5)
+ assert y.has_lower
+ assert y.has_upper
+ assert y.lower == -500
+ assert y.upper == 0
+
+ x = intutils.IntUpperBound(100)
+ y = x.mul(2)
+ assert not y.has_lower
+ assert y.has_upper
+ assert y.upper == 200
+
+ y = x.mul(-5)
+ assert y.has_lower
+ assert not y.has_upper
+ assert y.lower == -500
+ assert y.upper == 0
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -232,7 +232,10 @@
args = []
for argtype in argtypes:
assert argtype in ('int', 'bool')
- args.append(random.randrange(1, 20))
+ arg = random.randrange(1, 20)
+ if opnum == rop.INT_UNTAG:
+ arg = arg | 1 # must be an odd int
+ args.append(arg)
assert restype in ('int', 'bool')
ops = """
[]
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_optimizeopt.py
@@ -205,7 +205,10 @@
args = []
for argtype in argtypes:
assert argtype in ('int', 'bool')
- args.append(random.randrange(1, 20))
+ arg = random.randrange(1, 20)
+ if opnum == rop.INT_UNTAG:
+ arg = arg | 1 # must be an odd int
+ args.append(arg)
assert restype in ('int', 'bool')
ops = """
[]
@@ -5217,6 +5220,137 @@
"""
self.optimize_loop(ops, ops, ops)
+ def test_int_tag_untag_reverses(self):
+ ops = """
+ [i0]
+ i1 = int_tag_ovf(i0)
+ guard_no_overflow() []
+ i2 = int_untag(i1)
+ i3 = int_add(i2, 1)
+ jump(i3)
+ """
+ expected = """
+ [i0]
+ i1 = int_tag_ovf(i0)
+ guard_no_overflow() []
+ i2 = int_add(i0, 1)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+ ops = """
+ [i0]
+ i1 = int_untag(i0)
+ i2 = int_tag_ovf(i1)
+ guard_no_overflow() []
+ i3 = int_untag(i2)
+ i4 = int_add(i3, 1)
+ jump(i4)
+ """
+ expected = """
+ [i0]
+ i1 = int_untag(i0)
+ i2 = int_add(i1, 1)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_int_tag_remove_overflow_checking(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 1000)
+ guard_true(i1), []
+ i2 = int_tag_ovf(i0)
+ guard_no_overflow() []
+ i3 = int_untag(i2)
+ i4 = int_add_ovf(i3, 1)
+ guard_no_overflow() []
+ jump(i4)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 1000)
+ guard_true(i1), []
+ i2 = int_tag(i0)
+ i3 = int_add(i0, 1)
+ jump(i3)
+ """
+ preamble = """
+ [i0]
+ i1 = int_lt(i0, 1000)
+ guard_true(i1), []
+ i2 = int_tag_ovf(i0)
+ guard_no_overflow() []
+ i3 = int_add(i0, 1)
+ jump(i3)
+ """
+ self.optimize_loop(ops, expected, preamble)
+
+ def test_int_tag_remove_overflow_checking2(self):
+ ops = """
+ [i0]
+ i1 = int_lt(i0, 1000)
+ guard_true(i1), []
+ i2 = int_gt(i0, 0)
+ guard_true(i2), []
+ i3 = int_tag_ovf(i0)
+ guard_no_overflow() []
+ i4 = escape(i3)
+ jump(i4)
+ """
+ expected = """
+ [i0]
+ i1 = int_lt(i0, 1000)
+ guard_true(i1), []
+ i2 = int_gt(i0, 0)
+ guard_true(i2), []
+ i3 = int_tag(i0)
+ i4 = escape(i3)
+ jump(i4)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_int_tag_removes_int_and(self):
+ ops = """
+ [i0]
+ i1 = int_tag_ovf(i0)
+ guard_no_overflow() []
+ i2 = int_and(i1, 1)
+ i3 = int_is_true(i2)
+ guard_true(i3) []
+ i4 = int_untag(i1)
+ i5 = int_add(i4, 1)
+ jump(i5)
+ """
+ expected = """
+ [i0]
+ i1 = int_tag_ovf(i0)
+ guard_no_overflow() []
+ i2 = int_add(i0, 1)
+ jump(i2)
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_int_tag_constfold(self):
+ ops = """
+ [i0]
+ i1 = int_tag_ovf(1)
+ guard_no_overflow() []
+ i4 = int_untag(i1)
+ i5 = int_add(i4, 1)
+ escape(i5)
+ jump(i5)
+ """
+ expected = """
+ []
+ escape(2)
+ jump()
+ """
+ preamble = """
+ [i0]
+ escape(2)
+ jump()
+ """
+ self.optimize_loop(ops, expected, preamble)
def test_mul_ovf(self):
ops = """
diff --git a/pypy/jit/metainterp/optimizeopt/test/test_util.py
b/pypy/jit/metainterp/optimizeopt/test/test_util.py
--- a/pypy/jit/metainterp/optimizeopt/test/test_util.py
+++ b/pypy/jit/metainterp/optimizeopt/test/test_util.py
@@ -346,6 +346,7 @@
self.globaldata = Fake()
self.config = get_pypy_config(translating=True)
self.config.translation.jit_ffi = True
+ self.config.translation.taggedpointers = True
class logger_noopt:
@classmethod
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
@@ -218,7 +218,7 @@
return resbox
''' % (_opimpl, _opimpl.upper())).compile()
- for _opimpl in ['int_is_true', 'int_is_zero', 'int_neg', 'int_invert',
+ for _opimpl in ['int_is_true', 'int_is_zero', 'int_neg', 'int_invert',
'int_untag',
'cast_float_to_int', 'cast_int_to_float',
'cast_float_to_singlefloat', 'cast_singlefloat_to_float',
'float_neg', 'float_abs',
@@ -231,6 +231,15 @@
''' % (_opimpl, _opimpl.upper())).compile()
@arguments("box")
+ def opimpl_int_tag_ovf(self, b1):
+ self.metainterp.clear_exception()
+ resbox = self.execute(rop.INT_TAG_OVF, b1)
+ self.make_result_of_lastop(resbox)
+ if not isinstance(resbox, Const):
+ self.metainterp.handle_possible_overflow_error()
+ return resbox
+
+ @arguments("box")
def opimpl_ptr_nonzero(self, box):
return self.execute(rop.PTR_NE, box, history.CONST_NULL)
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
@@ -441,6 +441,8 @@
'INT_IS_TRUE/1b',
'INT_NEG/1',
'INT_INVERT/1',
+ 'INT_UNTAG/1',
+ 'INT_TAG/1',
#
'SAME_AS/1', # gets a Const or a Box, turns it into another Box
'CAST_PTR_TO_INT/1',
@@ -523,6 +525,7 @@
'INT_ADD_OVF/2',
'INT_SUB_OVF/2',
'INT_MUL_OVF/2',
+ 'INT_TAG_OVF/1',
'_OVF_LAST', # ----- end of is_ovf operations -----
'_LAST', # for the backend to add more internal operations
]
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
@@ -3569,7 +3569,6 @@
translationoptions = {'withsmallfuncsets': 3}
self.interp_operations(f, [5], translationoptions=translationoptions)
-
def test_annotation_gives_class_knowledge_to_tracer(self):
py.test.skip("disabled")
class Base(object):
@@ -3696,7 +3695,6 @@
self.check_operations_history(guard_class=0, record_known_class=1)
-class TestLLtype(BaseLLtypeTests, LLJitMixin):
def test_tagged(self):
from pypy.rlib.objectmodel import UnboxedValue
class Base(object):
@@ -3821,3 +3819,6 @@
return 42
self.interp_operations(f, [1, 2, 3])
self.check_operations_history(call=1, guard_no_exception=0)
+
+class TestLLtype(BaseLLtypeTests, LLJitMixin):
+ pass # should be empty
diff --git a/pypy/jit/metainterp/test/test_immutable.py
b/pypy/jit/metainterp/test/test_immutable.py
--- a/pypy/jit/metainterp/test/test_immutable.py
+++ b/pypy/jit/metainterp/test/test_immutable.py
@@ -64,7 +64,7 @@
l[2] = 30
a = escape(X(l))
return a.y[index]
- res = self.interp_operations(f, [2], listops=True)
+ res = self.interp_operations(f, [2])
assert res == 30
self.check_operations_history(getfield_gc=0, getfield_gc_pure=1,
getarrayitem_gc=0, getarrayitem_gc_pure=1)
@@ -82,7 +82,7 @@
def f(x, index):
y = escape(X([x], x+1))
return y.lst[index] + y.y + 5
- res = self.interp_operations(f, [23, 0], listops=True)
+ res = self.interp_operations(f, [23, 0])
assert res == 23 + 24 + 5
self.check_operations_history(getfield_gc=0, getfield_gc_pure=2,
getarrayitem_gc=0, getarrayitem_gc_pure=1,
diff --git a/pypy/jit/metainterp/test/test_list.py
b/pypy/jit/metainterp/test/test_list.py
--- a/pypy/jit/metainterp/test/test_list.py
+++ b/pypy/jit/metainterp/test/test_list.py
@@ -124,7 +124,7 @@
l2 = l[:]
return l2[0] + l2[1] + l2[2] + l2[3]
- res = self.interp_operations(f, [], listops=True)
+ res = self.interp_operations(f, [])
assert res == 10
def test_arraycopy_full(self):
diff --git a/pypy/jit/metainterp/test/test_slist.py
b/pypy/jit/metainterp/test/test_slist.py
--- a/pypy/jit/metainterp/test/test_slist.py
+++ b/pypy/jit/metainterp/test/test_slist.py
@@ -31,7 +31,7 @@
lst2.append(FooBar(5))
m += lst2.pop().z # 49
return m
- res = self.interp_operations(f, [11], listops=True)
+ res = self.interp_operations(f, [11])
assert res == 49
self.check_operations_history(call=3)
diff --git a/pypy/rlib/rerased.py b/pypy/rlib/rerased.py
--- a/pypy/rlib/rerased.py
+++ b/pypy/rlib/rerased.py
@@ -160,7 +160,7 @@
from pypy.rlib.debug import ll_assert
x = llop.cast_ptr_to_int(lltype.Signed, gcref)
ll_assert((x&1) != 0, "unerased_int(): not an integer")
- return x >> 1
+ return llop.int_untag(lltype.Signed, x)
class Entry(ExtRegistryEntry):
@@ -220,11 +220,9 @@
[v_value] = hop.inputargs(lltype.Signed)
c_one = hop.inputconst(lltype.Signed, 1)
hop.exception_is_here()
- v2 = hop.genop('int_add_ovf', [v_value, v_value],
+ v2 = hop.genop('int_tag_ovf', [v_value],
resulttype = lltype.Signed)
- v2p1 = hop.genop('int_add', [v2, c_one],
- resulttype = lltype.Signed)
- v_instance = hop.genop('cast_int_to_ptr', [v2p1],
+ v_instance = hop.genop('cast_int_to_ptr', [v2],
resulttype=self.lowleveltype)
return v_instance
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -1101,6 +1101,16 @@
assert y >= 0
return self.op_int_add_ovf(x, y)
+ def op_int_tag_ovf(self, x):
+ try:
+ return ovfcheck(x + x + 1)
+ except OverflowError:
+ self.make_llexception()
+
+ def op_int_untag(self, x):
+ assert x & 1, "argument has to be tagged!"
+ return x >> 1
+
def op_int_is_true(self, x):
# special case
if type(x) is CDefinedIntSymbolic:
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
@@ -207,6 +207,8 @@
'int_abs': LLOp(canfold=True),
'int_abs_ovf': LLOp(canraise=(OverflowError,), tryfold=True),
'int_invert': LLOp(canfold=True),
+ 'int_tag_ovf': LLOp(canraise=(OverflowError, ), tryfold=True),
+ 'int_untag': LLOp(canfold=True),
'int_add': LLOp(canfold=True),
'int_sub': LLOp(canfold=True),
diff --git a/pypy/rpython/lltypesystem/rtagged.py
b/pypy/rpython/lltypesystem/rtagged.py
--- a/pypy/rpython/lltypesystem/rtagged.py
+++ b/pypy/rpython/lltypesystem/rtagged.py
@@ -4,6 +4,7 @@
from pypy.rpython.lltypesystem.rclass import InstanceRepr, CLASSTYPE,
ll_inst_type
from pypy.rpython.lltypesystem.rclass import MissingRTypeAttribute
from pypy.rpython.lltypesystem.rclass import ll_issubclass_const
+from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.rmodel import TyperError, inputconst
@@ -43,24 +44,22 @@
v_value = hop.inputarg(lltype.Signed, arg=1)
c_one = hop.inputconst(lltype.Signed, 1)
hop.exception_is_here()
- v2 = hop.genop('int_add_ovf', [v_value, v_value],
+ v2 = hop.genop('int_tag_ovf', [v_value],
resulttype = lltype.Signed)
- v2p1 = hop.genop('int_add', [v2, c_one],
- resulttype = lltype.Signed)
- v_instance = hop.genop('cast_int_to_ptr', [v2p1],
+ v_instance = hop.genop('cast_int_to_ptr', [v2],
resulttype = self.lowleveltype)
return v_instance, False # don't call __init__
def convert_const_exact(self, value):
self.setup()
number = value.get_untagged_value()
- return ll_int_to_unboxed(self.lowleveltype, number)
+ tagged = number * 2 + 1
+ return lltype.cast_int_to_ptr(self.lowleveltype, tagged)
def getvalue_from_unboxed(self, llops, vinst):
assert not self.is_parent
v2 = llops.genop('cast_ptr_to_int', [vinst], resulttype=lltype.Signed)
- c_one = inputconst(lltype.Signed, 1)
- return llops.genop('int_rshift', [v2, c_one], resulttype=lltype.Signed)
+ return llops.genop('int_untag', [v2], resulttype=lltype.Signed)
def gettype_from_unboxed(self, llops, vinst, can_be_none=False):
unboxedclass_repr = getclassrepr(self.rtyper, self.unboxedclassdef)
@@ -142,11 +141,9 @@
minid, maxid, c_answer_if_unboxed)
-def ll_int_to_unboxed(PTRTYPE, value):
- return lltype.cast_int_to_ptr(PTRTYPE, value*2+1)
def ll_unboxed_to_int(p):
- return lltype.cast_ptr_to_int(p) >> 1
+ return llop.int_untag(lltype.Signed, lltype.cast_ptr_to_int(p))
def ll_unboxed_getclass_canbenone(instance, class_if_unboxed):
if instance:
diff --git a/pypy/rpython/memory/gc/minimark.py
b/pypy/rpython/memory/gc/minimark.py
--- a/pypy/rpython/memory/gc/minimark.py
+++ b/pypy/rpython/memory/gc/minimark.py
@@ -756,6 +756,8 @@
def can_move(self, obj):
"""Overrides the parent can_move()."""
+ if not self.is_valid_gc_object(obj):
+ return False
return self.is_in_nursery(obj)
diff --git a/pypy/translator/c/src/int.h b/pypy/translator/c/src/int.h
--- a/pypy/translator/c/src/int.h
+++ b/pypy/translator/c/src/int.h
@@ -19,6 +19,13 @@
if ((x) == LONG_MIN) FAIL_OVF("integer absolute"); \
OP_INT_ABS(x,r)
+#define OP_INT_TAG_OVF(x, r) \
+ r = (long)((unsigned long)x << 1); \
+ if ((r ^ x) < 0) FAIL_OVF("integer tagging"); \
+ r = r + 1
+#define OP_INT_UNTAG(x, r) \
+ r = x >> 1
+
/*** binary operations ***/
#define OP_INT_EQ(x,y,r) r = ((x) == (y))
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit