Author: Armin Rigo <ar...@tunes.org> Branch: int-test-is-zero Changeset: r98064:092643ba66ac Date: 2019-11-16 12:51 +0100 http://bitbucket.org/pypy/pypy/changeset/092643ba66ac/
Log: Generate more compact code for bit tests using the TEST instruction: i1 = int_and(i0, 7); i2 = int_is_zero(i1); guard_true(i2) => i2 = int_test_is_zero(i0, 7); guard_true(i2) The more compact version doesn't need to allocate a register, copy a value there, AND a constant, and then CMP the result with zero. Instead a single TEST instruction suffices. 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/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,15 @@ elif info == INFO_NULL: self.make_constant_int(op, not expect_nonnull) else: + 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() _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit