Skip to content

Commit

Permalink
gh-106603: Make uop struct a triple (opcode, oparg, operand) (#106794)
Browse files Browse the repository at this point in the history
  • Loading branch information
gvanrossum committed Jul 17, 2023
1 parent 7e96370 commit 8e9a1a0
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 109 deletions.
42 changes: 26 additions & 16 deletions Include/internal/pycore_opcode_metadata.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions Include/internal/pycore_uops.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,9 @@ extern "C" {
#define _Py_UOP_MAX_TRACE_LENGTH 32

typedef struct {
int opcode;
uint64_t operand; // Sometimes oparg, sometimes a cache entry
uint32_t opcode;
uint32_t oparg;
uint64_t operand; // A cache entry
} _PyUOpInstruction;

typedef struct {
Expand Down
24 changes: 12 additions & 12 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2448,7 +2448,7 @@ def testfunc(x):

ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("SAVE_IP", uops)
self.assertIn("LOAD_FAST", uops)

Expand Down Expand Up @@ -2493,7 +2493,7 @@ def many_vars():

ex = get_first_executor(many_vars)
self.assertIsNotNone(ex)
self.assertIn(("LOAD_FAST", 259), list(ex))
self.assertIn(("LOAD_FAST", 259, 0), list(ex))

def test_unspecialized_unpack(self):
# An example of an unspecialized opcode
Expand All @@ -2514,7 +2514,7 @@ def testfunc(x):

ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("UNPACK_SEQUENCE", uops)

def test_pop_jump_if_false(self):
Expand All @@ -2529,7 +2529,7 @@ def testfunc(n):

ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("_POP_JUMP_IF_FALSE", uops)

def test_pop_jump_if_none(self):
Expand All @@ -2544,7 +2544,7 @@ def testfunc(a):

ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("_POP_JUMP_IF_TRUE", uops)

def test_pop_jump_if_not_none(self):
Expand All @@ -2559,7 +2559,7 @@ def testfunc(a):

ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("_POP_JUMP_IF_FALSE", uops)

def test_pop_jump_if_true(self):
Expand All @@ -2574,7 +2574,7 @@ def testfunc(n):

ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("_POP_JUMP_IF_TRUE", uops)

def test_jump_backward(self):
Expand All @@ -2589,7 +2589,7 @@ def testfunc(n):

ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("JUMP_TO_TOP", uops)

def test_jump_forward(self):
Expand All @@ -2609,7 +2609,7 @@ def testfunc(n):

ex = get_first_executor(testfunc)
self.assertIsNotNone(ex)
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
# Since there is no JUMP_FORWARD instruction,
# look for indirect evidence: the += operator
self.assertIn("_BINARY_OP_ADD_INT", uops)
Expand All @@ -2630,7 +2630,7 @@ def testfunc(n):
self.assertIsNotNone(ex)
# for i, (opname, oparg) in enumerate(ex):
# print(f"{i:4d}: {opname:<20s} {oparg:3d}")
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("_IS_ITER_EXHAUSTED_RANGE", uops)
# Verification that the jump goes past END_FOR
# is done by manual inspection of the output
Expand All @@ -2652,7 +2652,7 @@ def testfunc(a):
self.assertIsNotNone(ex)
# for i, (opname, oparg) in enumerate(ex):
# print(f"{i:4d}: {opname:<20s} {oparg:3d}")
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("_IS_ITER_EXHAUSTED_LIST", uops)
# Verification that the jump goes past END_FOR
# is done by manual inspection of the output
Expand All @@ -2674,7 +2674,7 @@ def testfunc(a):
self.assertIsNotNone(ex)
# for i, (opname, oparg) in enumerate(ex):
# print(f"{i:4d}: {opname:<20s} {oparg:3d}")
uops = {opname for opname, _ in ex}
uops = {opname for opname, _, _ in ex}
self.assertIn("_IS_ITER_EXHAUSTED_TUPLE", uops)
# Verification that the jump goes past END_FOR
# is done by manual inspection of the output
Expand Down
16 changes: 6 additions & 10 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -645,18 +645,16 @@ dummy_func(
STORE_SUBSCR_LIST_INT,
};

inst(STORE_SUBSCR, (counter/1, v, container, sub -- )) {
inst(STORE_SUBSCR, (unused/1, v, container, sub -- )) {
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
next_instr--;
_Py_Specialize_StoreSubscr(container, sub, next_instr);
DISPATCH_SAME_OPARG();
}
STAT_INC(STORE_SUBSCR, deferred);
_PyStoreSubscrCache *cache = (_PyStoreSubscrCache *)next_instr;
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#else
(void)counter; // Unused.
#endif /* ENABLE_SPECIALIZATION */
/* container[sub] = v */
int err = PyObject_SetItem(container, sub, v);
Expand Down Expand Up @@ -1198,19 +1196,17 @@ dummy_func(
STORE_ATTR_WITH_HINT,
};

inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) {
inst(STORE_ATTR, (unused/1, unused/3, v, owner --)) {
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
next_instr--;
_Py_Specialize_StoreAttr(owner, next_instr, name);
DISPATCH_SAME_OPARG();
}
STAT_INC(STORE_ATTR, deferred);
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#else
(void)counter; // Unused.
#endif /* ENABLE_SPECIALIZATION */
PyObject *name = GETITEM(FRAME_CO_NAMES, oparg);
int err = PyObject_SetAttr(owner, name, v);
Expand Down
7 changes: 4 additions & 3 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -2747,17 +2747,18 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
_Py_CODEUNIT *ip_offset = (_Py_CODEUNIT *)_PyFrame_GetCode(frame)->co_code_adaptive;
int pc = 0;
int opcode;
uint64_t operand;
int oparg;
uint64_t operand;

for (;;) {
opcode = self->trace[pc].opcode;
oparg = self->trace[pc].oparg;
operand = self->trace[pc].operand;
oparg = (int)operand;
DPRINTF(3,
"%4d: uop %s, operand %" PRIu64 ", stack_level %d\n",
"%4d: uop %s, oparg %d, operand %" PRIu64 ", stack_level %d\n",
pc,
opcode < 256 ? _PyOpcode_OpName[opcode] : _PyOpcode_uop_name[opcode],
oparg,
operand,
(int)(stack_pointer - _PyFrame_Stackbase(frame)));
pc++;
Expand Down
85 changes: 80 additions & 5 deletions Python/executor_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 8e9a1a0

Please sign in to comment.