Skip to content

Commit 86c1a60

Browse files
pythongh-128563: Move GO_TO_INSTRUCTION and PREDICT to cases generator (pythonGH-129115)
1 parent 767cf70 commit 86c1a60

File tree

5 files changed

+47
-59
lines changed

5 files changed

+47
-59
lines changed

Lib/test/test_generated_cases.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ def test_predictions(self):
412412
frame->instr_ptr = next_instr;
413413
next_instr += 1;
414414
INSTRUCTION_STATS(OP1);
415-
PREDICTED(OP1);
415+
PREDICTED_OP1:;
416416
_PyStackRef res;
417417
res = Py_None;
418418
stack_pointer[-1] = res;
@@ -646,7 +646,7 @@ def test_macro_instruction(self):
646646
frame->instr_ptr = next_instr;
647647
next_instr += 6;
648648
INSTRUCTION_STATS(OP);
649-
PREDICTED(OP);
649+
PREDICTED_OP:;
650650
_Py_CODEUNIT* const this_instr = next_instr - 6;
651651
(void)this_instr;
652652
_PyStackRef left;

Python/ceval_macros.h

+1-32
Original file line numberDiff line numberDiff line change
@@ -166,35 +166,6 @@ GETITEM(PyObject *v, Py_ssize_t i) {
166166
#define JUMPBY(x) (next_instr += (x))
167167
#define SKIP_OVER(x) (next_instr += (x))
168168

169-
/* OpCode prediction macros
170-
Some opcodes tend to come in pairs thus making it possible to
171-
predict the second code when the first is run. For example,
172-
COMPARE_OP is often followed by POP_JUMP_IF_FALSE or POP_JUMP_IF_TRUE.
173-
174-
Verifying the prediction costs a single high-speed test of a register
175-
variable against a constant. If the pairing was good, then the
176-
processor's own internal branch predication has a high likelihood of
177-
success, resulting in a nearly zero-overhead transition to the
178-
next opcode. A successful prediction saves a trip through the eval-loop
179-
including its unpredictable switch-case branch. Combined with the
180-
processor's internal branch prediction, a successful PREDICT has the
181-
effect of making the two opcodes run as if they were a single new opcode
182-
with the bodies combined.
183-
184-
If collecting opcode statistics, your choices are to either keep the
185-
predictions turned-on and interpret the results as if some opcodes
186-
had been combined or turn-off predictions so that the opcode frequency
187-
counter updates for both opcodes.
188-
189-
Opcode prediction is disabled with threaded code, since the latter allows
190-
the CPU to record separate branch prediction information for each
191-
opcode.
192-
193-
*/
194-
195-
#define PREDICT_ID(op) PRED_##op
196-
#define PREDICTED(op) PREDICT_ID(op):
197-
198169

199170
/* Stack manipulation macros */
200171

@@ -260,8 +231,6 @@ GETITEM(PyObject *v, Py_ssize_t i) {
260231
GETLOCAL(i) = value; \
261232
PyStackRef_XCLOSE(tmp); } while (0)
262233

263-
#define GO_TO_INSTRUCTION(op) goto PREDICT_ID(op)
264-
265234
#ifdef Py_STATS
266235
#define UPDATE_MISS_STATS(INSTNAME) \
267236
do { \
@@ -281,7 +250,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
281250
/* This is only a single jump on release builds! */ \
282251
UPDATE_MISS_STATS((INSTNAME)); \
283252
assert(_PyOpcode_Deopt[opcode] == (INSTNAME)); \
284-
GO_TO_INSTRUCTION(INSTNAME); \
253+
goto PREDICTED_##INSTNAME; \
285254
}
286255

287256

Python/generated_cases.c.h

+25-24
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/generators_common.py

+18
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ def __init__(self, out: CWriter):
127127
"DISPATCH": self.dispatch,
128128
"INSTRUCTION_SIZE": self.instruction_size,
129129
"POP_INPUT": self.pop_input,
130+
"GO_TO_INSTRUCTION": self.go_to_instruction,
130131
}
131132
self.out = out
132133

@@ -402,6 +403,23 @@ def sync_sp(
402403
self._print_storage(storage)
403404
return True
404405

406+
def go_to_instruction(
407+
self,
408+
tkn: Token,
409+
tkn_iter: TokenIterator,
410+
uop: Uop,
411+
storage: Storage,
412+
inst: Instruction | None,
413+
) -> bool:
414+
next(tkn_iter)
415+
name = next(tkn_iter)
416+
next(tkn_iter)
417+
next(tkn_iter)
418+
assert name.kind == "IDENTIFIER"
419+
self.emit("\n")
420+
self.emit(f"goto PREDICTED_{name.text};\n")
421+
return True
422+
405423
def emit_save(self, storage: Storage) -> None:
406424
storage.save(self.out)
407425
self._print_storage(storage)

Tools/cases_generator/tier1_generator.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def generate_tier1(
158158
out.emit(f"next_instr += {inst.size};\n")
159159
out.emit(f"INSTRUCTION_STATS({name});\n")
160160
if inst.is_target:
161-
out.emit(f"PREDICTED({name});\n")
161+
out.emit(f"PREDICTED_{name}:;\n")
162162
if needs_this:
163163
out.emit(f"_Py_CODEUNIT* const this_instr = next_instr - {inst.size};\n")
164164
out.emit(unused_guard)

0 commit comments

Comments
 (0)