[pypy-commit] pypy default: Merged in int-test-is-zero (pull request #684)
arigo
pypy.commits at gmail.com
Sat Nov 16 08:13:58 EST 2019
Author: Armin Rigo <armin.rigo at gmail.com>
Branch:
Changeset: r98070:18443d3a74d5
Date: 2019-11-16 13:13 +0000
http://bitbucket.org/pypy/pypy/changeset/18443d3a74d5/
Log: Merged in int-test-is-zero (pull request #684)
Use the TEST assembler instruction on x86
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -1,4 +1,5 @@
import py, sys
+import platform
from pypy.module.pypyjit.test_pypy_c.test_00_model import BaseTestPyPyC
@@ -420,3 +421,23 @@
# the following assertion fails if the loop was cancelled due
# to "abort: vable escape"
assert len(loops) == 1
+
+ def test_bit_check(self):
+ if not platform.machine().startswith('x86'):
+ py.test.skip("only x86 supports int_test_instructions for now")
+
+ def main(n):
+ x = 0
+ while n:
+ y = bool(n & 7) # ID: bitcheck
+ x += y
+ n -= 1
+
+ log = self.run(main, [300])
+ loop, = log.loops_by_id("bitcheck")
+ assert loop.match_by_id("bitcheck", """
+ guard_not_invalidated?
+ i11 = int_and(i7, 7) # not used
+ i12 = int_test_is_true(i7, 7)
+ guard_true(i12, descr=...)
+ """)
diff --git a/rpython/jit/backend/llgraph/runner.py b/rpython/jit/backend/llgraph/runner.py
--- a/rpython/jit/backend/llgraph/runner.py
+++ b/rpython/jit/backend/llgraph/runner.py
@@ -333,6 +333,7 @@
vector_ext.enable(16, accum=True)
vector_ext.setup_once = lambda asm: asm
load_supported_factors = (1,2,4,8)
+ supports_int_test_instructions = True
assembler = None
def __init__(self, rtyper, stats=None, *ignored_args, **kwds):
diff --git a/rpython/jit/backend/model.py b/rpython/jit/backend/model.py
--- a/rpython/jit/backend/model.py
+++ b/rpython/jit/backend/model.py
@@ -20,6 +20,7 @@
supports_singlefloats = False
supports_guard_gc_type = False
supports_load_effective_address = False
+ supports_int_test_instructions = False
propagate_exception_descr = None
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -1491,6 +1491,8 @@
(rop.INT_NE, lambda x, y: x != y),
(rop.INT_GT, lambda x, y: x > y),
(rop.INT_GE, lambda x, y: x >= y),
+ (rop.INT_TEST_IS_ZERO, lambda x, y: (x & y) == 0),
+ (rop.INT_TEST_IS_TRUE, lambda x, y: (x & y) != 0),
]:
for opguard, guard_case in [
(rop.GUARD_FALSE, False),
diff --git a/rpython/jit/backend/test/test_random.py b/rpython/jit/backend/test/test_random.py
--- a/rpython/jit/backend/test/test_random.py
+++ b/rpython/jit/backend/test/test_random.py
@@ -546,6 +546,8 @@
rop.UINT_LE,
rop.UINT_GT,
rop.UINT_GE,
+ rop.INT_TEST_IS_ZERO,
+ rop.INT_TEST_IS_TRUE,
]:
OPERATIONS.append(BinaryOperation(_op, boolres=True))
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -1281,6 +1281,17 @@
self.flush_cc(cond, result_loc)
return genop_cmp
+ def _testop(cond):
+ cond = rx86.Conditions[cond]
+ #
+ def genop_test(self, op, arglocs, result_loc):
+ if arglocs[1].is_stack() or isinstance(arglocs[0], ImmedLoc):
+ self.mc.TEST(arglocs[1], arglocs[0])
+ else:
+ self.mc.TEST(arglocs[0], arglocs[1])
+ self.flush_cc(cond, result_loc)
+ return genop_test
+
def _if_parity_clear_zero_and_carry(self):
jnp_location = self.mc.emit_forward_jump('NP')
# CMP EBP, 0: as EBP cannot be null here, that operation should
@@ -1401,6 +1412,9 @@
genop_float_gt = _cmpop_float("A", "B")
genop_float_ge = _cmpop_float("AE","BE")
+ genop_int_test_is_zero = _testop("Z")
+ genop_int_test_is_true = _testop("NZ")
+
def genop_math_sqrt(self, op, arglocs, resloc):
self.mc.SQRTSD(arglocs[0], resloc)
diff --git a/rpython/jit/backend/x86/regalloc.py b/rpython/jit/backend/x86/regalloc.py
--- a/rpython/jit/backend/x86/regalloc.py
+++ b/rpython/jit/backend/x86/regalloc.py
@@ -644,6 +644,8 @@
consider_uint_ge = _consider_compop
consider_ptr_eq = consider_instance_ptr_eq = _consider_compop
consider_ptr_ne = consider_instance_ptr_ne = _consider_compop
+ consider_int_test_is_zero = _consider_compop
+ consider_int_test_is_true = _consider_compop
def _consider_float_op(self, op):
loc1 = self.xrm.loc(op.getarg(1))
diff --git a/rpython/jit/backend/x86/runner.py b/rpython/jit/backend/x86/runner.py
--- a/rpython/jit/backend/x86/runner.py
+++ b/rpython/jit/backend/x86/runner.py
@@ -17,6 +17,7 @@
supports_floats = True
supports_singlefloats = True
supports_load_effective_address = True
+ supports_int_test_instructions = True
dont_keepalive_stuff = False # for tests
with_threads = False
diff --git a/rpython/jit/backend/x86/rx86.py b/rpython/jit/backend/x86/rx86.py
--- a/rpython/jit/backend/x86/rx86.py
+++ b/rpython/jit/backend/x86/rx86.py
@@ -699,6 +699,9 @@
TEST_ai = insn(rex_w, '\xF7', orbyte(0<<3), mem_reg_plus_scaled_reg_plus_const(1), immediate(2))
TEST_mi = insn(rex_w, '\xF7', orbyte(0<<3), mem_reg_plus_const(1), immediate(2))
TEST_ji = insn(rex_w, '\xF7', orbyte(0<<3), abs_(1), immediate(2))
+ TEST_ri = insn(rex_w, '\xF7', orbyte(0<<3), register(1), '\xC0', immediate(2))
+ TEST_bi = insn(rex_w, '\xF7', orbyte(0<<3), stack_bp(1), immediate(2))
+ TEST_br = insn(rex_w, '\x85', register(2,8), stack_bp(1))
BTS_mr = insn(rex_w, '\x0F\xAB', register(2,8), mem_reg_plus_const(1))
BTS_jr = insn(rex_w, '\x0F\xAB', register(2,8), abs_(1))
diff --git a/rpython/jit/backend/x86/test/test_rx86_32_auto_encoding.py b/rpython/jit/backend/x86/test/test_rx86_32_auto_encoding.py
--- a/rpython/jit/backend/x86/test/test_rx86_32_auto_encoding.py
+++ b/rpython/jit/backend/x86/test/test_rx86_32_auto_encoding.py
@@ -311,6 +311,8 @@
return [] # MOV AL, [immediate]: there is a special encoding
if methname == 'MOV8_jr' and args[1] == rx86.R.al:
return [] # MOV [immediate], AL: there is a special encoding
+ if methname == 'TEST_ri' and args[0] == rx86.R.eax:
+ return [] # TEST EAX, constant: there is a special encoding
return [args]
diff --git a/rpython/jit/metainterp/blackhole.py b/rpython/jit/metainterp/blackhole.py
--- a/rpython/jit/metainterp/blackhole.py
+++ b/rpython/jit/metainterp/blackhole.py
@@ -542,6 +542,12 @@
@arguments("i", "i", returns="i")
def bhimpl_int_signext(a, b):
return int_signext(a, b)
+ @arguments("i", "i", returns="i")
+ def bhimpl_int_test_is_zero(a, b):
+ return (a & b) == 0
+ @arguments("i", "i", returns="i")
+ def bhimpl_int_test_is_true(a, b):
+ return (a & b) != 0
@arguments("i", "i", returns="i")
def bhimpl_uint_lt(a, b):
diff --git a/rpython/jit/metainterp/executor.py b/rpython/jit/metainterp/executor.py
--- a/rpython/jit/metainterp/executor.py
+++ b/rpython/jit/metainterp/executor.py
@@ -442,6 +442,8 @@
rop.GC_STORE_INDEXED,
rop.LOAD_FROM_GC_TABLE,
rop.LOAD_EFFECTIVE_ADDRESS,
+ rop.INT_TEST_IS_ZERO,
+ rop.INT_TEST_IS_TRUE,
): # list of opcodes never executed by pyjitpl
continue
if rop._VEC_PURE_FIRST <= value <= rop._VEC_PURE_LAST:
diff --git a/rpython/jit/metainterp/optimizeopt/rewrite.py b/rpython/jit/metainterp/optimizeopt/rewrite.py
--- a/rpython/jit/metainterp/optimizeopt/rewrite.py
+++ b/rpython/jit/metainterp/optimizeopt/rewrite.py
@@ -646,6 +646,16 @@
elif info == INFO_NULL:
self.make_constant_int(op, not expect_nonnull)
else:
+ if self.optimizer.cpu.supports_int_test_instructions:
+ box = get_box_replacement(box)
+ box1 = self.optimizer.as_operation(box)
+ if box1 is not None and box1.getopnum() == rop.INT_AND:
+ if expect_nonnull:
+ opnum = rop.INT_TEST_IS_TRUE
+ else:
+ opnum = rop.INT_TEST_IS_ZERO
+ args = [box1.getarg(0), box1.getarg(1)]
+ op = self.replace_op_with(op, opnum, args=args)
return self.emit(op)
def optimize_INT_IS_TRUE(self, op):
diff --git a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
--- a/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
+++ b/rpython/jit/metainterp/optimizeopt/test/test_optimizebasic.py
@@ -5790,3 +5790,33 @@
i57 = int_or(i51, i52)
"""
self.optimize_loop(ops, expected)
+
+ def test_int_test_is_zero(self):
+ ops = """
+ [i1, i2]
+ i51 = int_and(i1, i2)
+ i52 = int_is_zero(i51)
+ guard_true(i52) []
+ """
+ expected = """
+ [i1, i2]
+ i51 = int_and(i1, i2) # likely dead instruction
+ i52 = int_test_is_zero(i1, i2)
+ guard_true(i52) []
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_int_test_is_true(self):
+ ops = """
+ [i1, i2]
+ i51 = int_and(i1, i2)
+ i52 = int_is_true(i51)
+ guard_true(i52) []
+ """
+ expected = """
+ [i1, i2]
+ i51 = int_and(i1, i2) # likely dead instruction
+ i52 = int_test_is_true(i1, i2)
+ guard_true(i52) []
+ """
+ self.optimize_loop(ops, expected)
diff --git a/rpython/jit/metainterp/resoperation.py b/rpython/jit/metainterp/resoperation.py
--- a/rpython/jit/metainterp/resoperation.py
+++ b/rpython/jit/metainterp/resoperation.py
@@ -1036,6 +1036,8 @@
'INT_NEG/1/i',
'INT_INVERT/1/i',
'INT_FORCE_GE_ZERO/1/i',
+ 'INT_TEST_IS_ZERO/2b/i',
+ 'INT_TEST_IS_TRUE/2b/i',
#
'SAME_AS/1/ifr', # gets a Const or a Box, turns it into another Box
'CAST_PTR_TO_INT/1/i',
diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -4832,3 +4832,11 @@
res2 = self.interp_operations(f, [6])
assert res1 == res2
self.check_operations_history(guard_class=1, record_exact_class=0)
+
+ def test_int_test_instructions(self):
+ def f(x, y):
+ if (x & 7) == 0 and (y & 7) != 0:
+ return 1
+ return 0
+ res = self.interp_operations(f, [24, 25])
+ assert res == 1
diff --git a/rpython/jit/metainterp/test/test_executor.py b/rpython/jit/metainterp/test/test_executor.py
--- a/rpython/jit/metainterp/test/test_executor.py
+++ b/rpython/jit/metainterp/test/test_executor.py
@@ -187,6 +187,8 @@
(rop.UINT_LE, lambda x, y: r_uint(x) <= r_uint(y)),
(rop.UINT_GT, lambda x, y: r_uint(x) > r_uint(y)),
(rop.UINT_GE, lambda x, y: r_uint(x) >= r_uint(y)),
+ (rop.INT_TEST_IS_ZERO, lambda x, y: (x & y) == 0),
+ (rop.INT_TEST_IS_TRUE, lambda x, y: (x & y) != 0),
]:
for i in range(20):
x = pick()
More information about the pypy-commit
mailing list