Skip to content

Commit

Permalink
gh-106529: Support JUMP_BACKWARD in Tier 2 (uops) (#106543)
Browse files Browse the repository at this point in the history
During superblock generation, a JUMP_BACKWARD instruction is translated to either a JUMP_TO_TOP micro-op (when the target of the jump is exactly the beginning of the superblock, closing the loop), or a SAVE_IP + EXIT_TRACE pair, when the jump goes elsewhere.

The new JUMP_TO_TOP instruction includes a CHECK_EVAL_BREAKER() call, so a closed loop can still be interrupted.
  • Loading branch information
gvanrossum authored Jul 11, 2023
1 parent 292ac4b commit cabd6e8
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 30 deletions.
16 changes: 14 additions & 2 deletions Lib/test/test_capi/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2525,7 +2525,6 @@ def testfunc(n):
i += 1

opt = _testinternalcapi.get_uop_optimizer()

with temporary_optimizer(opt):
testfunc(10)

Expand All @@ -2541,7 +2540,6 @@ def testfunc(n):
i += 1

opt = _testinternalcapi.get_uop_optimizer()

with temporary_optimizer(opt):
testfunc(10)

Expand All @@ -2550,6 +2548,20 @@ def testfunc(n):
uops = {opname for opname, _ in ex}
self.assertIn("_POP_JUMP_IF_TRUE", uops)

def test_jump_backward(self):
def testfunc(n):
i = 0
while i < n:
i += 1
opt = _testinternalcapi.get_uop_optimizer()
with temporary_optimizer(opt):
testfunc(10)

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


if __name__ == "__main__":
unittest.main()
7 changes: 7 additions & 0 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -2783,6 +2783,13 @@ _PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject
break;
}

case JUMP_TO_TOP:
{
pc = 0;
CHECK_EVAL_BREAKER();
break;
}

case SAVE_IP:
{
frame->prev_instr = ip_offset + oparg;
Expand Down
54 changes: 28 additions & 26 deletions Python/opcode_metadata.h

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

15 changes: 13 additions & 2 deletions Python/optimizer.c
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,7 @@ translate_bytecode_to_trace(
_PyUOpInstruction *trace,
int buffer_size)
{
#ifdef Py_DEBUG
_Py_CODEUNIT *initial_instr = instr;
#endif
int trace_length = 0;
int max_length = buffer_size;

Expand Down Expand Up @@ -456,6 +454,19 @@ translate_bytecode_to_trace(
break;
}

case JUMP_BACKWARD:
{
if (instr + 2 - oparg == initial_instr
&& trace_length + 3 <= max_length)
{
ADD_TO_TRACE(JUMP_TO_TOP, 0);
}
else {
DPRINTF(2, "JUMP_BACKWARD not to top ends trace\n");
}
goto done;
}

default:
{
const struct opcode_macro_expansion *expansion = &_PyOpcode_macro_expansion[opcode];
Expand Down
1 change: 1 addition & 0 deletions Tools/cases_generator/generate_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -1346,6 +1346,7 @@ def add(name: str) -> None:
add("SAVE_IP")
add("_POP_JUMP_IF_FALSE")
add("_POP_JUMP_IF_TRUE")
add("JUMP_TO_TOP")

for instr in self.instrs.values():
if instr.kind == "op" and instr.is_viable_uop():
Expand Down

0 comments on commit cabd6e8

Please sign in to comment.