gh-134584: Eliminate redundant refcounting from _LOAD_ATTR_WITH_HINT (GH-143062)
Some checks failed
mypy / Run mypy on Tools/check-c-api-docs (push) Has been cancelled
mypy / Run mypy on Tools/clinic (push) Has been cancelled
mypy / Run mypy on Tools/jit (push) Has been cancelled
mypy / Run mypy on Tools/peg_generator (push) Has been cancelled
Lint / lint (push) Has been cancelled
mypy / Run mypy on Lib/_pyrepl (push) Has been cancelled
mypy / Run mypy on Lib/test/libregrtest (push) Has been cancelled
mypy / Run mypy on Lib/tomllib (push) Has been cancelled
mypy / Run mypy on Tools/build (push) Has been cancelled
mypy / Run mypy on Tools/cases_generator (push) Has been cancelled
Tests / Change detection (push) Has been cancelled
JIT / Interpreter (Debug) (push) Has been cancelled
Tail calling interpreter / aarch64-apple-darwin/clang (push) Has been cancelled
Tail calling interpreter / aarch64-unknown-linux-gnu/gcc (push) Has been cancelled
Tail calling interpreter / x86_64-pc-windows-msvc/msvc (push) Has been cancelled
Tail calling interpreter / x86_64-apple-darwin/clang (push) Has been cancelled
Tail calling interpreter / free-threading (push) Has been cancelled
Tail calling interpreter / x86_64-unknown-linux-gnu/gcc (push) Has been cancelled
Tests / Windows MSI (push) Has been cancelled
Tests / Check if generated files are up to date (push) Has been cancelled
Tests / Ubuntu SSL tests with OpenSSL (push) Has been cancelled
Tests / Ubuntu SSL tests with AWS-LC (push) Has been cancelled
Tests / Android (aarch64) (push) Has been cancelled
Tests / Android (x86_64) (push) Has been cancelled
Tests / WASI (push) Has been cancelled
Tests / Hypothesis tests on Ubuntu (push) Has been cancelled
Tests / Sanitizers (push) Has been cancelled
Tests / Cross build Linux (push) Has been cancelled
Tests / CIFuzz (push) Has been cancelled
Tests / All required checks pass (push) Has been cancelled
JIT / aarch64-pc-windows-msvc/msvc (Release) (push) Has been cancelled
JIT / aarch64-pc-windows-msvc/msvc (Debug) (push) Has been cancelled
JIT / i686-pc-windows-msvc/msvc (Release) (push) Has been cancelled
JIT / i686-pc-windows-msvc/msvc (Debug) (push) Has been cancelled
JIT / aarch64-apple-darwin/clang (Release) (push) Has been cancelled
JIT / aarch64-unknown-linux-gnu/gcc (Debug) (push) Has been cancelled
JIT / x86_64-pc-windows-msvc/msvc (Release) (push) Has been cancelled
JIT / x86_64-pc-windows-msvc/msvc (Debug) (push) Has been cancelled
Tests / (push) Has been cancelled
Tests / Docs (push) Has been cancelled
Tests / Check if Autoconf files are up to date (push) Has been cancelled
Tests / iOS (push) Has been cancelled
Tests / Address sanitizer (push) Has been cancelled
JIT / aarch64-unknown-linux-gnu/gcc (Release) (push) Has been cancelled
JIT / aarch64-apple-darwin/clang (Debug) (push) Has been cancelled
JIT / x86_64-apple-darwin/clang (Release) (push) Has been cancelled
JIT / x86_64-unknown-linux-gnu/gcc (Release) (push) Has been cancelled
JIT / x86_64-apple-darwin/clang (Debug) (push) Has been cancelled
JIT / x86_64-unknown-linux-gnu/gcc (Debug) (push) Has been cancelled
JIT / Free-Threaded (Debug) (push) Has been cancelled
JIT / JIT without optimizations (Debug) (push) Has been cancelled
JIT / JIT with tail calling interpreter (push) Has been cancelled

Eliminate redundant refcounting from _LOAD_ATTR_WITH_HINT
This commit is contained in:
Hai Zhu 2025-12-23 08:28:08 +08:00 committed by GitHub
parent 9e51301234
commit 5b5ee3c4bf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 54 additions and 21 deletions

View file

@ -1434,7 +1434,7 @@ _PyOpcode_macro_expansion[256] = {
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } },
[LOAD_ATTR_PROPERTY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_PROPERTY_FRAME, 4, 5 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 9 }, { _PUSH_FRAME, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_SLOT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_WITH_HINT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_WITH_HINT] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { _LOAD_BUILD_CLASS, OPARG_SIMPLE, 0 } } },
[LOAD_COMMON_CONSTANT] = { .nuops = 1, .uops = { { _LOAD_COMMON_CONSTANT, OPARG_SIMPLE, 0 } } },
[LOAD_CONST] = { .nuops = 1, .uops = { { _LOAD_CONST, OPARG_SIMPLE, 0 } } },

View file

@ -807,7 +807,7 @@ extern "C" {
#define _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES_r11 1000
#define _LOAD_ATTR_PROPERTY_FRAME_r11 1001
#define _LOAD_ATTR_SLOT_r11 1002
#define _LOAD_ATTR_WITH_HINT_r11 1003
#define _LOAD_ATTR_WITH_HINT_r12 1003
#define _LOAD_BUILD_CLASS_r01 1004
#define _LOAD_BYTECODE_r00 1005
#define _LOAD_COMMON_CONSTANT_r01 1006

View file

@ -191,7 +191,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_INSTANCE_VALUE] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG,
[_LOAD_ATTR_SLOT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_CHECK_ATTR_CLASS] = HAS_EXIT_FLAG,
[_LOAD_ATTR_CLASS] = HAS_ESCAPES_FLAG,
@ -1774,7 +1774,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
.best = { 1, 1, 1, 1 },
.entries = {
{ -1, -1, -1 },
{ 1, 1, _LOAD_ATTR_WITH_HINT_r11 },
{ 2, 1, _LOAD_ATTR_WITH_HINT_r12 },
{ -1, -1, -1 },
{ -1, -1, -1 },
},
@ -3542,7 +3542,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_LOAD_ATTR_INSTANCE_VALUE_r12] = _LOAD_ATTR_INSTANCE_VALUE,
[_LOAD_ATTR_INSTANCE_VALUE_r23] = _LOAD_ATTR_INSTANCE_VALUE,
[_LOAD_ATTR_MODULE_r11] = _LOAD_ATTR_MODULE,
[_LOAD_ATTR_WITH_HINT_r11] = _LOAD_ATTR_WITH_HINT,
[_LOAD_ATTR_WITH_HINT_r12] = _LOAD_ATTR_WITH_HINT,
[_LOAD_ATTR_SLOT_r11] = _LOAD_ATTR_SLOT,
[_CHECK_ATTR_CLASS_r01] = _CHECK_ATTR_CLASS,
[_CHECK_ATTR_CLASS_r11] = _CHECK_ATTR_CLASS,
@ -4501,7 +4501,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_LOAD_ATTR_SLOT] = "_LOAD_ATTR_SLOT",
[_LOAD_ATTR_SLOT_r11] = "_LOAD_ATTR_SLOT_r11",
[_LOAD_ATTR_WITH_HINT] = "_LOAD_ATTR_WITH_HINT",
[_LOAD_ATTR_WITH_HINT_r11] = "_LOAD_ATTR_WITH_HINT_r11",
[_LOAD_ATTR_WITH_HINT_r12] = "_LOAD_ATTR_WITH_HINT_r12",
[_LOAD_BUILD_CLASS] = "_LOAD_BUILD_CLASS",
[_LOAD_BUILD_CLASS_r01] = "_LOAD_BUILD_CLASS_r01",
[_LOAD_COMMON_CONSTANT] = "_LOAD_COMMON_CONSTANT",

View file

@ -2512,6 +2512,27 @@ class TestUopsOptimization(unittest.TestCase):
self.assertNotIn("_POP_TOP", uops)
self.assertIn("_POP_TOP_NOP", uops)
def test_load_attr_with_hint(self):
def testfunc(n):
class C:
pass
c = C()
c.x = 42
for i in range(_testinternalcapi.SHARED_KEYS_MAX_SIZE - 1):
setattr(c, f"_{i}", None)
x = 0
for i in range(n):
x += c.x
return x
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
self.assertEqual(res, 42 * TIER2_THRESHOLD)
self.assertIsNotNone(ex)
uops = get_opnames(ex)
self.assertIn("_LOAD_ATTR_WITH_HINT", uops)
self.assertNotIn("_POP_TOP", uops)
self.assertIn("_POP_TOP_NOP", uops)
def test_int_add_op_refcount_elimination(self):
def testfunc(n):
c = 1

View file

@ -2426,7 +2426,7 @@ dummy_func(
unused/5 +
_PUSH_NULL_CONDITIONAL;
op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr)) {
op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, o)) {
PyObject *owner_o = PyStackRef_AsPyObjectBorrow(owner);
assert(Py_TYPE(owner_o)->tp_flags & Py_TPFLAGS_MANAGED_DICT);
PyDictObject *dict = _PyObject_GetManagedDict(owner_o);
@ -2462,13 +2462,15 @@ dummy_func(
#else
attr = PyStackRef_FromPyObjectNew(attr_o);
#endif
PyStackRef_CLOSE(owner);
o = owner;
DEAD(owner);
}
macro(LOAD_ATTR_WITH_HINT) =
unused/1 +
_GUARD_TYPE_VERSION +
_LOAD_ATTR_WITH_HINT +
POP_TOP +
unused/5 +
_PUSH_NULL_CONDITIONAL;

View file

@ -8261,11 +8261,12 @@
break;
}
case _LOAD_ATTR_WITH_HINT_r11: {
case _LOAD_ATTR_WITH_HINT_r12: {
CHECK_CURRENT_CACHED_VALUES(1);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef o;
_PyStackRef _stack_item_0 = _tos_cache0;
oparg = CURRENT_OPARG();
owner = _stack_item_0;
@ -8339,18 +8340,11 @@
#else
attr = PyStackRef_FromPyObjectNew(attr_o);
#endif
stack_pointer[0] = attr;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(owner);
stack_pointer = _PyFrame_GetStackPointer(frame);
o = owner;
_tos_cache1 = o;
_tos_cache0 = attr;
_tos_cache1 = PyStackRef_ZERO_BITS;
_tos_cache2 = PyStackRef_ZERO_BITS;
SET_CURRENT_CACHED_VALUES(1);
stack_pointer += -1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
SET_CURRENT_CACHED_VALUES(2);
assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE());
break;
}

View file

@ -8280,6 +8280,8 @@
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
_PyStackRef owner;
_PyStackRef attr;
_PyStackRef o;
_PyStackRef value;
_PyStackRef *null;
/* Skip 1 cache entry */
// _GUARD_TYPE_VERSION
@ -8359,9 +8361,14 @@
#else
attr = PyStackRef_FromPyObjectNew(attr_o);
#endif
o = owner;
}
// _POP_TOP
{
value = o;
stack_pointer[-1] = attr;
_PyFrame_SetStackPointer(frame, stack_pointer);
PyStackRef_CLOSE(owner);
PyStackRef_XCLOSE(value);
stack_pointer = _PyFrame_GetStackPointer(frame);
}
/* Skip 5 cache entries */

View file

@ -634,9 +634,10 @@ dummy_func(void) {
}
}
op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr)) {
op(_LOAD_ATTR_WITH_HINT, (hint/1, owner -- attr, o)) {
attr = sym_new_not_null(ctx);
(void)hint;
o = owner;
}
op(_LOAD_ATTR_SLOT, (index/1, owner -- attr)) {

View file

@ -1658,11 +1658,19 @@
}
case _LOAD_ATTR_WITH_HINT: {
JitOptRef owner;
JitOptRef attr;
JitOptRef o;
owner = stack_pointer[-1];
uint16_t hint = (uint16_t)this_instr->operand0;
attr = sym_new_not_null(ctx);
(void)hint;
o = owner;
CHECK_STACK_BOUNDS(1);
stack_pointer[-1] = attr;
stack_pointer[0] = o;
stack_pointer += 1;
ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__);
break;
}