Skip to content

Commit 05af848

Browse files
committed
Introduce SAVE_CURRENT_IP uop per Mark's proposal
1 parent 1e62876 commit 05af848

File tree

10 files changed

+63
-30
lines changed

10 files changed

+63
-30
lines changed

Include/internal/pycore_opcode_metadata.h

Lines changed: 8 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/abstract_interp_cases.c.h

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/bytecodes.c

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2991,7 +2991,7 @@ dummy_func(
29912991
// Eventually this should be the only occurrence of this code.
29922992
frame->return_offset = 0;
29932993
assert(tstate->interp->eval_frame == NULL);
2994-
SAVE_FRAME_STATE(); // Signals to the code generator
2994+
_PyFrame_SetStackPointer(frame, stack_pointer);
29952995
new_frame->previous = frame;
29962996
CALL_STAT_INC(inlined_py_calls);
29972997
#if TIER_ONE
@@ -3013,6 +3013,7 @@ dummy_func(
30133013
_CHECK_STACK_SPACE +
30143014
_INIT_CALL_PY_EXACT_ARGS +
30153015
SAVE_IP + // Tier 2 only; special-cased oparg
3016+
SAVE_CURRENT_IP + // Sets frame->prev_instr
30163017
_PUSH_FRAME;
30173018

30183019
inst(CALL_PY_WITH_DEFAULTS, (unused/1, func_version/2, callable, self_or_null, args[oparg] -- unused)) {
@@ -3775,6 +3776,16 @@ dummy_func(
37753776
frame->prev_instr = ip_offset + oparg;
37763777
}
37773778

3779+
op(SAVE_CURRENT_IP, (--)) {
3780+
#if TIER_ONE
3781+
frame->prev_instr = next_instr - 1;
3782+
#endif
3783+
#if TIER_TWO
3784+
// Relies on a preceding SAVE_IP
3785+
frame->prev_instr--;
3786+
#endif
3787+
}
3788+
37783789
op(EXIT_TRACE, (--)) {
37793790
frame->prev_instr--; // Back up to just before destination
37803791
_PyFrame_SetStackPointer(frame, stack_pointer);

Python/ceval_macros.h

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -103,16 +103,11 @@
103103
DISPATCH_GOTO(); \
104104
}
105105

106-
#define SAVE_FRAME_STATE() \
107-
do { \
108-
frame->prev_instr = next_instr - 1; \
109-
_PyFrame_SetStackPointer(frame, stack_pointer); \
110-
} while (0)
111-
112106
#define DISPATCH_INLINED(NEW_FRAME) \
113107
do { \
114108
assert(tstate->interp->eval_frame == NULL); \
115-
SAVE_FRAME_STATE(); \
109+
_PyFrame_SetStackPointer(frame, stack_pointer); \
110+
frame->prev_instr = next_instr - 1; \
116111
(NEW_FRAME)->previous = frame; \
117112
frame = cframe.current_frame = (NEW_FRAME); \
118113
CALL_STAT_INC(inlined_py_calls); \

Python/executor.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,6 @@
3030
#undef ENABLE_SPECIALIZATION
3131
#define ENABLE_SPECIALIZATION 0
3232

33-
#undef SAVE_FRAME_STATE
34-
#define SAVE_FRAME_STATE() \
35-
do { \
36-
/* Assume preceding SAVE_IP has set frame->prev_instr */ \
37-
frame->prev_instr--; \
38-
_PyFrame_SetStackPointer(frame, stack_pointer); \
39-
} while (0)
40-
4133

4234
_PyInterpreterFrame *
4335
_PyUopExecute(_PyExecutorObject *executor, _PyInterpreterFrame *frame, PyObject **stack_pointer)

Python/executor_cases.c.h

Lines changed: 12 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 12 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/flags.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def variable_used_unspecialized(node: parsing.Node, name: str) -> bool:
9292
if text == "#if":
9393
if (
9494
i + 1 < len(node.tokens)
95-
and node.tokens[i + 1].text == "ENABLE_SPECIALIZATION"
95+
and node.tokens[i + 1].text in ("ENABLE_SPECIALIZATION", "TIER_ONE")
9696
):
9797
skipping = True
9898
elif text in ("#else", "#endif"):

Tools/cases_generator/instructions.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,6 @@ class Instruction:
6060

6161
# Computed by constructor
6262
always_exits: str # If the block always exits, its last line; else ""
63-
save_frame_state: bool # Whether the instruction uses SAVE_FRAME_STATE()
6463
has_deopt: bool
6564
cache_offset: int
6665
cache_effects: list[parsing.CacheEffect]
@@ -84,7 +83,6 @@ def __init__(self, inst: parsing.InstDef):
8483
self.block
8584
)
8685
self.always_exits = always_exits(self.block_text)
87-
self.save_frame_state = variable_used(self.inst, "SAVE_FRAME_STATE")
8886
self.has_deopt = variable_used(self.inst, "DEOPT_IF")
8987
self.cache_effects = [
9088
effect for effect in inst.inputs if isinstance(effect, parsing.CacheEffect)
@@ -122,7 +120,7 @@ def __init__(self, inst: parsing.InstDef):
122120
def is_viable_uop(self) -> bool:
123121
"""Whether this instruction is viable as a uop."""
124122
dprint: typing.Callable[..., None] = lambda *args, **kwargs: None
125-
if "PUSH_FRAME" in self.name:
123+
if "FRAME" in self.name:
126124
dprint = print
127125

128126
if self.name == "EXIT_TRACE":

Tools/cases_generator/stacking.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,10 @@ def write_macro_instr(
324324
out.emit(f"PREDICTED({mac.name});")
325325
out.static_assert_family_size(mac.name, family, mac.cache_offset)
326326
try:
327-
write_components(parts, out, TIER_ONE, mac.cache_offset)
327+
next_instr_is_set = write_components(parts, out, TIER_ONE, mac.cache_offset)
328328
except AssertionError as err:
329329
raise AssertionError(f"Error writing macro {mac.name}") from err
330-
if not parts[-1].instr.always_exits and not parts[-1].instr.save_frame_state:
330+
if not parts[-1].instr.always_exits and not next_instr_is_set:
331331
if mac.cache_offset:
332332
out.emit(f"next_instr += {mac.cache_offset};")
333333
out.emit("DISPATCH();")
@@ -338,7 +338,7 @@ def write_components(
338338
out: Formatter,
339339
tier: Tiers,
340340
cache_offset: int,
341-
) -> None:
341+
) -> bool:
342342
managers = get_managers(parts)
343343

344344
all_vars: dict[str, StackEffect] = {}
@@ -359,6 +359,7 @@ def write_components(
359359
for name, eff in all_vars.items():
360360
out.declare(eff, None)
361361

362+
next_instr_is_set = False
362363
for mgr in managers:
363364
if len(parts) > 1:
364365
out.emit(f"// {mgr.instr.name}")
@@ -379,11 +380,14 @@ def write_components(
379380
poke.as_stack_effect(lax=True),
380381
)
381382

382-
if mgr.instr.save_frame_state:
383+
if mgr.instr.name == "_PUSH_FRAME":
383384
# Adjust stack to min_offset (input effects materialized)
384385
out.stack_adjust(mgr.min_offset.deep, mgr.min_offset.high)
385386
# Use clone() since adjust_inverse() mutates final_offset
386387
mgr.adjust_inverse(mgr.final_offset.clone())
388+
389+
if mgr.instr.name == "SAVE_CURRENT_IP":
390+
next_instr_is_set = True
387391
if cache_offset:
388392
out.emit(f"next_instr += {cache_offset};")
389393

@@ -393,7 +397,7 @@ def write_components(
393397
with out.block(""):
394398
mgr.instr.write_body(out, -4, mgr.active_caches, tier)
395399

396-
if mgr is managers[-1] and not mgr.instr.save_frame_state:
400+
if mgr is managers[-1] and not next_instr_is_set:
397401
# TODO: Explain why this adjustment is needed.
398402
out.stack_adjust(mgr.final_offset.deep, mgr.final_offset.high)
399403
# Use clone() since adjust_inverse() mutates final_offset
@@ -406,6 +410,8 @@ def write_components(
406410
poke.effect,
407411
)
408412

413+
return next_instr_is_set
414+
409415

410416
def write_single_instr_for_abstract_interp(
411417
instr: Instruction, out: Formatter

0 commit comments

Comments
 (0)