10000 gh-119689: generate stack effect metadata for pseudo instructions (#1… · python/cpython@c1e9647 · GitHub
[go: up one dir, main page]

Skip to content

Commit c1e9647

Browse files
authored
gh-119689: generate stack effect metadata for pseudo instructions (#119691)
1 parent 7ca74a7 commit c1e9647

File tree

10 files changed

+112
-73
lines changed

10 files changed

+112
-73
lines changed

Include/internal/pycore_opcode_metadata.h

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

Lib/test/test_generated_cases.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ def test_unused_caches(self):
485485

486486
def test_pseudo_instruction_no_flags(self):
487487
input = """
488-
pseudo(OP) = {
488+
pseudo(OP, (in -- out1, out2)) = {
489489
OP1,
490490
};
491491
@@ -504,7 +504,7 @@ def test_pseudo_instruction_no_flags(self):
504504

505505
def test_pseudo_instruction_with_flags(self):
506506
input = """
507-
pseudo(OP, (HAS_ARG, HAS_JUMP)) = {
507+
pseudo(OP, (in1, in2 --), (HAS_ARG, HAS_JUMP)) = {
508508
OP1,
509509
};
510510
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Generate stack effect metadata for pseudo instructions from bytecodes.c.

Python/bytecodes.c

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ dummy_func(
213213
}
214214
}
215215

216-
pseudo(LOAD_CLOSURE) = {
216+
pseudo(LOAD_CLOSURE, (-- unused)) = {
217217
LOAD_FAST,
218218
};
219219

@@ -259,7 +259,7 @@ dummy_func(
259259
SETLOCAL(oparg, value);
260260
}
261261

262-
pseudo(STORE_FAST_MAYBE_NULL) = {
262+
pseudo(STORE_FAST_MAYBE_NULL, (unused --)) = {
263263
STORE_FAST,
264264
};
265265

@@ -2393,12 +2393,12 @@ dummy_func(
23932393
#endif /* _Py_TIER2 */
23942394
}
23952395

2396-
pseudo(JUMP) = {
2396+
pseudo(JUMP, (--)) = {
23972397
JUMP_FORWARD,
23982398
JUMP_BACKWARD,
23992399
};
24002400

2401-
pseudo(JUMP_NO_INTERRUPT) = {
2401+
pseudo(JUMP_NO_INTERRUPT, (--)) = {
24022402
JUMP_FORWARD,
24032403
JUMP_BACKWARD_NO_INTERRUPT,
24042404
};
@@ -2895,19 +2895,27 @@ dummy_func(
28952895
ERROR_IF(res == NULL, error);
28962896
}
28972897

2898-
pseudo(SETUP_FINALLY, (HAS_ARG)) = {
2898+
pseudo(SETUP_FINALLY, (-- unused), (HAS_ARG)) = {
2899+
/* If an exception is raised, restore the stack position
2900+
* and push one value before jumping to the handler.
2901+
*/
28992902
NOP,
29002903
};
29012904

2902-
pseudo(SETUP_CLEANUP, (HAS_ARG)) = {
2905+
pseudo(SETUP_CLEANUP, (-- unused, unused), (HAS_ARG)) = {
2906+
/* As SETUP_FINALLY, but push lasti as well */
29032907
NOP,
29042908
};
29052909

2906-
pseudo(SETUP_WITH, (HAS_ARG)) = {
2910+
pseudo(SETUP_WITH, (-- unused), (HAS_ARG)) = {
2911+
/* If an exception is raised, restore the stack position to the
2912+
* position before the result of __(a)enter__ and push 2 values
2913+
* before jumping to the handler.
2914+
*/
29072915
NOP,
29082916
};
29092917

2910-
pseudo(POP_BLOCK) = {
2918+
pseudo(POP_BLOCK, (--)) = {
29112919
NOP,
29122920
};
29132921

Python/compile.c

Lines changed: 14 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -703,51 +703,22 @@ compiler_set_qualname(struct compiler *c)
703703
static int
704704
stack_effect(int opcode, int oparg, int jump)
705705
{
706-
if (0 <= opcode && opcode <= MAX_REAL_OPCODE) {
707-
if (_PyOpcode_Deopt[opcode] != opcode) {
708-
// Specialized instructions are not supported.
709-
return PY_INVALID_STACK_EFFECT;
710-
}
711-
int popped = _PyOpcode_num_popped(opcode, oparg);
712-
int pushed = _PyOpcode_num_pushed(opcode, oparg);
713-
if (popped < 0 || pushed < 0) {
714-
return PY_INVALID_STACK_EFFECT;
715-
}
716-
return pushed - popped;
706+
if (opcode < 0) {
707+
return PY_INVALID_STACK_EFFECT;
717708
}
718-
719-
// Pseudo ops
720-
switch (opcode) {
721-
case POP_BLOCK:
722-
case JUMP:
723-
case JUMP_NO_INTERRUPT:
724-
return 0;
725-
726-
/* Exception handling pseudo-instructions */
727-
case SETUP_FINALLY:
728-
/* 0 in the normal flow.
729-
* Restore the stack position and push 1 value before jumping to
730-
* the handler if an exception be raised. */
731-
return jump ? 1 : 0;
732-
case SETUP_CLEANUP:
733-
/* As SETUP_FINALLY, but pushes lasti as well */
734-
return jump ? 2 : 0;
735-
case SETUP_WITH:
736-
/* 0 in the normal flow.
737-
* Restore the stack position to the position before the result
738-
* of __(a)enter__ and push 2 values before jumping to the handler
739-
* if an exception be raised. */
740-
return jump ? 1 : 0;
741-
742-
case STORE_FAST_MAYBE_NULL:
743-
return -1;
744-
case LOAD_CLOSURE:
745-
return 1;
746-
default:
747-
return PY_INVALID_STACK_EFFECT;
709+
if ((opcode <= MAX_REAL_OPCODE) && (_PyOpcode_Deopt[opcode] != opcode)) {
710+
// Specialized instructions are not supported.
711+
return PY_INVALID_STACK_EFFECT;
748712
}
749-
750-
return PY_INVALID_STACK_EFFECT; /* not reachable */
713+
int popped = _PyOpcode_num_popped(opcode, oparg);
714+
int pushed = _PyOpcode_num_pushed(opcode, oparg);
715+
if (popped < 0 || pushed < 0) {
716+
return PY_INVALID_STACK_EFFECT;
717+
}
718+
if (IS_BLOCK_PUSH_OPCODE(opcode) && !jump) {
719+
return 0;
720+
}
721+
return pushed - popped;
751722
}
752723

753724
int

Tools/cases_generator/analyzer.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ def is_super(self) -> bool:
235235
@dataclass
236236
class PseudoInstruction:
237237
name: str
238+
stack: StackEffect
238239
targets: list[Instruction]
239240
flags: list[str]
240241
opcode: int = -1
@@ -295,7 +296,7 @@ def convert_stack_item(item: parser.StackEffect, replace_op_arg_1: str | None) -
295296
item.name, item.type, cond, (item.size or "1")
296297
)
297298

298-
def analyze_stack(op: parser.InstDef, replace_op_arg_1: str | None = None) -> StackEffect:
299+
def analyze_stack(op: parser.InstDef | parser.Pseudo, replace_op_arg_1: str | None = None) -> StackEffect:
299300
inputs: list[StackItem] = [
300301
convert_stack_item(i, replace_op_arg_1) for i in op.inputs if isinstance(i, parser.StackEffect)
301302
]
@@ -706,6 +707,7 @@ def add_pseudo(
706707
) -> None:
707708
pseudos[pseudo.name] = PseudoInstruction(
708709
pseudo.name,
710+
analyze_stack(pseudo),
709711
[instructions[target] for target in pseudo.targets],
710712
pseudo.flags,
711713
)

Tools/cases_generator/interpreter_definition.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,13 @@ and a piece of C code describing its semantics::
124124
"family" "(" NAME ")" = "{" NAME ("," NAME)+ [","] "}" ";"
125125
126126
pseudo:
127-
"pseudo" "(" NAME ")" = "{" NAME ("," NAME)+ [","] "}" ";"
127+
"pseudo" "(" NAME "," stack_effect ["," "(" flags ")"]")" = "{" NAME ("," NAME)+ [","] "}" ";"
128+
129+
flags:
130+
flag ("|" flag)*
131+
132+
flag:
133+
HAS_ARG | HAS_DEOPT | etc..
128134
```
129135

130136
The following definitions may occur:

Tools/cases_generator/opcode_metadata_generator.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from analyzer import (
1111
Analysis,
1212
Instruction,
13+
PseudoInstruction,
1314
analyze_files,
1415
Skip,
1516
Uop,
@@ -94,12 +95,18 @@ def emit_stack_effect_function(
9495
def generate_stack_effect_functions(analysis: Analysis, out: CWriter) -> None:
9596
popped_data: list[tuple[str, str]] = []
9697
pushed_data: list[tuple[str, str]] = []
97-
for inst in analysis.instructions.values():
98+
def add(inst: Instruction | PseudoInstruction) -> None:
9899
stack = get_stack_effect(inst)
99100
popped = (-stack.base_offset).to_c()
100101
pushed = (stack.top_offset - stack.base_offset).to_c()
101102
popped_data.append((inst.name, popped))
102103
pushed_data.append((inst.name, pushed))
104+
105+
for inst in analysis.instructions.values():
106+
add(inst)
107+
for pseudo in analysis.pseudos.values():
108+
add(pseudo)
109+
103110
emit_stack_effect_function(out, "popped", sorted(popped_data))
104111
emit_stack_effect_function(out, "pushed", sorted(pushed_data))
105112

Tools/cases_generator/parsing.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ class Family(Node):
138138
@dataclass
139139
class Pseudo(Node):
140140
name: str
141+
inputs: list[InputEffect]
142+
outputs: list[OutputEffect]
141143
flags: list[str] # instr flags to set on the pseudo instruction
142144
targets: list[str] # opcodes this can be replaced by
143145

@@ -409,16 +411,18 @@ def pseudo_def(self) -> Pseudo | None:
409411
if self.expect(lx.LPAREN):
410412
if tkn := self.expect(lx.IDENTIFIER):
411413
if self.expect(lx.COMMA):
412-
flags = self.flags()
413-
else:
414-
flags = []
415-
if self.expect(lx.RPAREN):
416-
if self.expect(lx.EQUALS):
417-
if not self.expect(lx.LBRACE):
418-
raise self.make_syntax_error("Expected {")
419-
if members := self.members():
420-
if self.expect(lx.RBRACE) and self.expect(lx.SEMI):
421-
return Pseudo(tkn.text, flags, members)
414+
inp, outp = self.io_effect()
415+
if self.expect(lx.COMMA):
416+
flags = self.flags()
417+
else:
418+
flags = []
419+
if self.expect(lx.RPAREN):
420+
if self.expect(lx.EQUALS):
421+
if not self.expect(lx.LBRACE):
422+
raise self.make_syntax_error("Expected {")
423+
if members := self.members():
424+
if self.expect(lx.RBRACE) and self.expect(lx.SEMI):
425+
return Pseudo(tkn.text, inp, outp, flags, members)
422426
return None
423427

424428
def members(self) -> list[str] | None:

0 commit comments

Comments
 (0)
0