summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2024-01-24 12:08:31 (GMT)
committerGitHub <noreply@github.com>2024-01-24 12:08:31 (GMT)
commit384429d1c0cf011dcf88d4043e0328de8b063c24 (patch)
treed3b325f08d9359bce60065b162ddec3572b08662 /Python
parent1e4f00ebd8db44a031b61eed0803b4c3d731aed7 (diff)
downloadcpython-384429d1c0cf011dcf88d4043e0328de8b063c24.zip
cpython-384429d1c0cf011dcf88d4043e0328de8b063c24.tar.gz
cpython-384429d1c0cf011dcf88d4043e0328de8b063c24.tar.bz2
GH-113710: Add a tier 2 peephole optimization pass. (GH-114487)
* Convert _LOAD_CONST to inline versions * Remove PEP 523 checks
Diffstat (limited to 'Python')
-rw-r--r--Python/bytecodes.c4
-rw-r--r--Python/executor_cases.c.h9
-rw-r--r--Python/optimizer.c6
-rw-r--r--Python/optimizer_analysis.c34
-rw-r--r--Python/pystate.c10
5 files changed, 60 insertions, 3 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 7674ff8..18749ce 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -4070,6 +4070,10 @@ dummy_func(
DEOPT_IF(!current_executor->vm_data.valid);
}
+ op(_LOAD_CONST_INLINE, (ptr/4 -- value)) {
+ value = Py_NewRef(ptr);
+ }
+
op(_LOAD_CONST_INLINE_BORROW, (ptr/4 -- value)) {
value = ptr;
}
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 2b4399b..241b905 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -3390,6 +3390,15 @@
break;
}
+ case _LOAD_CONST_INLINE: {
+ PyObject *value;
+ PyObject *ptr = (PyObject *)CURRENT_OPERAND();
+ value = Py_NewRef(ptr);
+ stack_pointer[0] = value;
+ stack_pointer += 1;
+ break;
+ }
+
case _LOAD_CONST_INLINE_BORROW: {
PyObject *value;
PyObject *ptr = (PyObject *)CURRENT_OPERAND();
diff --git a/Python/optimizer.c b/Python/optimizer.c
index 1551a5e..4b6ed17 100644
--- a/Python/optimizer.c
+++ b/Python/optimizer.c
@@ -588,6 +588,9 @@ top: // Jump here after _PUSH_FRAME or likely branches
ADD_TO_TRACE(uop, oparg, operand, target);
if (uop == _POP_FRAME) {
TRACE_STACK_POP();
+ /* Set the operand to the code object returned to,
+ * to assist optimization passes */
+ trace[trace_length-1].operand = (uintptr_t)code;
DPRINTF(2,
"Returning to %s (%s:%d) at byte offset %d\n",
PyUnicode_AsUTF8(code->co_qualname),
@@ -629,6 +632,9 @@ top: // Jump here after _PUSH_FRAME or likely branches
instr += _PyOpcode_Caches[_PyOpcode_Deopt[opcode]] + 1;
TRACE_STACK_PUSH();
_Py_BloomFilter_Add(dependencies, new_code);
+ /* Set the operand to the callee's code object,
+ * to assist optimization passes */
+ trace[trace_length-1].operand = (uintptr_t)new_code;
code = new_code;
instr = _PyCode_CODE(code);
DPRINTF(2,
diff --git a/Python/optimizer_analysis.c b/Python/optimizer_analysis.c
index 7db51f0..d122599 100644
--- a/Python/optimizer_analysis.c
+++ b/Python/optimizer_analysis.c
@@ -13,6 +13,39 @@
#include "pycore_optimizer.h"
static void
+peephole_opt(PyCodeObject *co, _PyUOpInstruction *buffer, int buffer_size)
+{
+ for (int pc = 0; pc < buffer_size; pc++) {
+ int opcode = buffer[pc].opcode;
+ switch(opcode) {
+ case _LOAD_CONST: {
+ assert(co != NULL);
+ PyObject *val = PyTuple_GET_ITEM(co->co_consts, buffer[pc].oparg);
+ buffer[pc].opcode = _Py_IsImmortal(val) ? _LOAD_CONST_INLINE_BORROW : _LOAD_CONST_INLINE;
+ buffer[pc].operand = (uintptr_t)val;
+ break;
+ }
+ case _CHECK_PEP_523:
+ {
+ /* Setting the eval frame function invalidates
+ * all executors, so no need to check dynamically */
+ if (_PyInterpreterState_GET()->eval_frame == NULL) {
+ buffer[pc].opcode = _NOP;
+ }
+ break;
+ }
+ case _PUSH_FRAME:
+ case _POP_FRAME:
+ co = (PyCodeObject *)buffer[pc].operand;
+ break;
+ case _JUMP_TO_TOP:
+ case _EXIT_TRACE:
+ return;
+ }
+ }
+}
+
+static void
remove_unneeded_uops(_PyUOpInstruction *buffer, int buffer_size)
{
int last_set_ip = -1;
@@ -59,6 +92,7 @@ _Py_uop_analyze_and_optimize(
int curr_stacklen
)
{
+ peephole_opt(co, buffer, buffer_size);
remove_unneeded_uops(buffer, buffer_size);
return 0;
}
diff --git a/Python/pystate.c b/Python/pystate.c
index 23ddc78..548c77b 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -2608,11 +2608,15 @@ _PyInterpreterState_SetEvalFrameFunc(PyInterpreterState *interp,
_PyFrameEvalFunction eval_frame)
{
if (eval_frame == _PyEval_EvalFrameDefault) {
- interp->eval_frame = NULL;
+ eval_frame = NULL;
}
- else {
- interp->eval_frame = eval_frame;
+ if (eval_frame == interp->eval_frame) {
+ return;
+ }
+ if (eval_frame != NULL) {
+ _Py_Executors_InvalidateAll(interp);
}
+ interp->eval_frame = eval_frame;
}