# But all of the appends we care about are still there:
self.assertEqual(uops.count("_CALL_LIST_APPEND"), len("ABCDEFG"))
+ def test_unary_negative_pop_top_load_const_inline_borrow(self):
+ def testfunc(n):
+ x = 0
+ for i in range(n):
+ a = 1
+ result = -a
+ if result < 0:
+ x += 1
+ return x
+
+ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+ self.assertEqual(res, TIER2_THRESHOLD)
+ self.assertIsNotNone(ex)
+ uops = get_opnames(ex)
+ self.assertNotIn("_UNARY_NEGATIVE", uops)
+ self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops)
+
+ def test_unary_not_pop_top_load_const_inline_borrow(self):
+ def testfunc(n):
+ x = 0
+ for i in range(n):
+ a = 42
+ result = not a
+ if result:
+ x += 1
+ return x
+
+ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+ self.assertEqual(res, 0)
+ self.assertIsNotNone(ex)
+ uops = get_opnames(ex)
+ self.assertNotIn("_UNARY_NOT", uops)
+ self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops)
+
+ def test_unary_invert_pop_top_load_const_inline_borrow(self):
+ def testfunc(n):
+ x = 0
+ for i in range(n):
+ a = 0
+ result = ~a
+ if result < 0:
+ x += 1
+ return x
+
+ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+ self.assertEqual(res, TIER2_THRESHOLD)
+ self.assertIsNotNone(ex)
+ uops = get_opnames(ex)
+ self.assertNotIn("_UNARY_INVERT", uops)
+ self.assertNotIn("_POP_TOP_LOAD_CONST_INLINE_BORROW", uops)
+
+ def test_compare_op_pop_two_load_const_inline_borrow(self):
+ def testfunc(n):
+ x = 0
+ for _ in range(n):
+ a = 10
+ b = 10.0
+ if a == b:
+ x += 1
+ return x
+
+ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+ self.assertEqual(res, TIER2_THRESHOLD)
+ self.assertIsNotNone(ex)
+ uops = get_opnames(ex)
+ self.assertNotIn("_COMPARE_OP", uops)
+ self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops)
+
def test_compare_op_int_pop_two_load_const_inline_borrow(self):
def testfunc(n):
x = 0
self.assertNotIn("_COMPARE_OP_FLOAT", uops)
self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops)
+ def test_contains_op_pop_two_load_const_inline_borrow(self):
+ def testfunc(n):
+ x = 0
+ for _ in range(n):
+ a = "foo"
+ s = "foo bar baz"
+ if a in s:
+ x += 1
+ return x
+
+ res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
+ self.assertEqual(res, TIER2_THRESHOLD)
+ self.assertIsNotNone(ex)
+ uops = get_opnames(ex)
+ self.assertNotIn("_CONTAINS_OP", uops)
+ self.assertNotIn("_POP_TWO_LOAD_CONST_INLINE_BORROW", uops)
+
def test_to_bool_bool_contains_op_set(self):
"""
Test that _TO_BOOL_BOOL is removed from code like:
JitOptRef value;
JitOptRef res;
value = stack_pointer[-1];
+ if (
+ sym_is_safe_const(ctx, value)
+ ) {
+ JitOptRef value_sym = value;
+ _PyStackRef value = sym_get_const_as_stackref(ctx, value_sym);
+ _PyStackRef res_stackref;
+ /* Start of uop copied from bytecodes for constant evaluation */
+ PyObject *res_o = PyNumber_Negative(PyStackRef_AsPyObjectBorrow(value));
+ PyStackRef_CLOSE(value);
+ if (res_o == NULL) {
+ goto error;
+ }
+ res_stackref = PyStackRef_FromPyObjectSteal(res_o);
+ /* End of uop copied from bytecodes for constant evaluation */
+ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
+ if (sym_is_const(ctx, res)) {
+ PyObject *result = sym_get_const(ctx, res);
+ if (_Py_IsImmortal(result)) {
+ // Replace with _POP_TOP_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result
+ REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ }
+ }
+ stack_pointer[-1] = res;
+ break;
+ }
if (sym_is_compact_int(value)) {
res = sym_new_compact_int(ctx);
}
? PyStackRef_True : PyStackRef_False;
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
+ if (sym_is_const(ctx, res)) {
+ PyObject *result = sym_get_const(ctx, res);
+ if (_Py_IsImmortal(result)) {
+ // Replace with _POP_TOP_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result
+ REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ }
+ }
stack_pointer[-1] = res;
break;
}
JitOptRef value;
JitOptRef res;
value = stack_pointer[-1];
+ if (!sym_matches_type(value, &PyBool_Type)) {
+ if (
+ sym_is_safe_const(ctx, value)
+ ) {
+ JitOptRef value_sym = value;
+ _PyStackRef value = sym_get_const_as_stackref(ctx, value_sym);
+ _PyStackRef res_stackref;
+ /* Start of uop copied from bytecodes for constant evaluation */
+ PyObject *res_o = PyNumber_Invert(PyStackRef_AsPyObjectBorrow(value));
+ PyStackRef_CLOSE(value);
+ if (res_o == NULL) {
+ goto error;
+ }
+ res_stackref = PyStackRef_FromPyObjectSteal(res_o);
+ /* End of uop copied from bytecodes for constant evaluation */
+ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
+ if (sym_is_const(ctx, res)) {
+ PyObject *result = sym_get_const(ctx, res);
+ if (_Py_IsImmortal(result)) {
+ // Replace with _POP_TOP_LOAD_CONST_INLINE_BORROW since we have one input and an immortal result
+ REPLACE_OP(this_instr, _POP_TOP_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ }
+ }
+ stack_pointer[-1] = res;
+ break;
+ }
+ }
if (sym_matches_type(value, &PyLong_Type)) {
res = sym_new_type(ctx, &PyLong_Type);
}
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
PyStackRef_CLOSE_SPECIALIZED(left, _PyLong_ExactDealloc);
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
}
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
}
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
}
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
res_stackref = PyStackRef_FromPyObjectSteal(res_o);
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
}
case _COMPARE_OP: {
+ JitOptRef right;
+ JitOptRef left;
JitOptRef res;
+ right = stack_pointer[-1];
+ left = stack_pointer[-2];
+ if (
+ sym_is_safe_const(ctx, left) &&
+ sym_is_safe_const(ctx, right)
+ ) {
+ JitOptRef left_sym = left;
+ JitOptRef right_sym = right;
+ _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
+ _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
+ _PyStackRef res_stackref;
+ /* Start of uop copied from bytecodes for constant evaluation */
+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
+ assert((oparg >> 5) <= Py_GE);
+ PyObject *res_o = PyObject_RichCompare(left_o, right_o, oparg >> 5);
+ if (res_o == NULL) {
+ goto error;
+ }
+ if (oparg & 16) {
+ int res_bool = PyObject_IsTrue(res_o);
+ Py_DECREF(res_o);
+ if (res_bool < 0) {
+ goto error;
+ }
+ res_stackref = res_bool ? PyStackRef_True : PyStackRef_False;
+ }
+ else {
+ res_stackref = PyStackRef_FromPyObjectSteal(res_o);
+ }
+ /* End of uop copied from bytecodes for constant evaluation */
+ res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
+ if (sym_is_const(ctx, res)) {
+ PyObject *result = sym_get_const(ctx, res);
+ if (_Py_IsImmortal(result)) {
+ // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
+ REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ }
+ }
+ stack_pointer[-2] = res;
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
if (oparg & 16) {
res = sym_new_type(ctx, &PyBool_Type);
}
res_stackref = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False;
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
res_stackref = (sign_ish & oparg) ? PyStackRef_True : PyStackRef_False;
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
res_stackref = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? PyStackRef_True : PyStackRef_False;
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {
}
case _CONTAINS_OP: {
+ JitOptRef right;
+ JitOptRef left;
JitOptRef b;
+ right = stack_pointer[-1];
+ left = stack_pointer[-2];
+ if (
+ sym_is_safe_const(ctx, left) &&
+ sym_is_safe_const(ctx, right)
+ ) {
+ JitOptRef left_sym = left;
+ JitOptRef right_sym = right;
+ _PyStackRef left = sym_get_const_as_stackref(ctx, left_sym);
+ _PyStackRef right = sym_get_const_as_stackref(ctx, right_sym);
+ _PyStackRef b_stackref;
+ /* Start of uop copied from bytecodes for constant evaluation */
+ PyObject *left_o = PyStackRef_AsPyObjectBorrow(left);
+ PyObject *right_o = PyStackRef_AsPyObjectBorrow(right);
+ int res = PySequence_Contains(right_o, left_o);
+ if (res < 0) {
+ goto error;
+ }
+ b_stackref = (res ^ oparg) ? PyStackRef_True : PyStackRef_False;
+ /* End of uop copied from bytecodes for constant evaluation */
+ b = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(b_stackref));
+ if (sym_is_const(ctx, b)) {
+ PyObject *result = sym_get_const(ctx, b);
+ if (_Py_IsImmortal(result)) {
+ // Replace with _POP_TWO_LOAD_CONST_INLINE_BORROW since we have two inputs and an immortal result
+ REPLACE_OP(this_instr, _POP_TWO_LOAD_CONST_INLINE_BORROW, 0, (uintptr_t)result);
+ }
+ }
+ stack_pointer[-2] = b;
+ stack_pointer += -1;
+ assert(WITHIN_STACK_BOUNDS());
+ break;
+ }
b = sym_new_type(ctx, &PyBool_Type);
stack_pointer[-2] = b;
stack_pointer += -1;
res_stackref = PyStackRef_FromPyObjectSteal(res_o);
/* End of uop copied from bytecodes for constant evaluation */
res = sym_new_const_steal(ctx, PyStackRef_AsPyObjectSteal(res_stackref));
-
if (sym_is_const(ctx, res)) {
PyObject *result = sym_get_const(ctx, res);
if (_Py_IsImmortal(result)) {