Skip to content

Commit

Permalink
teach cases generator about sequence-shortcut psuedo instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
iritkatriel committed Sep 24, 2024
1 parent 9cd97d4 commit 2612ace
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 31 deletions.
27 changes: 14 additions & 13 deletions Include/internal/pycore_opcode_metadata.h

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

30 changes: 30 additions & 0 deletions Lib/test/test_generated_cases.py
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,36 @@ def test_pseudo_instruction_with_flags(self):
"""
self.run_cases_test(input, output)

def test_pseudo_instruction_as_sequence(self):
input = """
pseudo(OP, (in -- out1, out2)) = [
OP1, OP2
];
inst(OP1, (--)) {
}
inst(OP2, (--)) {
}
"""
output = """
TARGET(OP1) {
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP1);
DISPATCH();
}
TARGET(OP2) {
frame->instr_ptr = next_instr;
next_instr += 1;
INSTRUCTION_STATS(OP2);
DISPATCH();
}
"""
self.run_cases_test(input, output)


def test_array_input(self):
input = """
inst(OP, (below, values[oparg*2], above --)) {
Expand Down
14 changes: 6 additions & 8 deletions Python/bytecodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2571,15 +2571,13 @@ dummy_func(
JUMP_BACKWARD_NO_INTERRUPT,
};

pseudo(JUMP_IF_FALSE, (cond -- cond)) = {
JUMP_FORWARD,
JUMP_BACKWARD,
};
pseudo(JUMP_IF_FALSE, (cond -- cond)) = [
COPY, TO_BOOL, POP_JUMP_IF_FALSE,
];

pseudo(JUMP_IF_TRUE, (cond -- cond)) = {
JUMP_FORWARD,
JUMP_BACKWARD,
};
pseudo(JUMP_IF_TRUE, (cond -- cond)) = [
COPY, TO_BOOL, POP_JUMP_IF_TRUE,
];

tier1 inst(ENTER_EXECUTOR, (--)) {
#ifdef _Py_TIER2
Expand Down
2 changes: 2 additions & 0 deletions Tools/cases_generator/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,7 @@ class PseudoInstruction:
name: str
stack: StackEffect
targets: list[Instruction]
as_sequence: bool
flags: list[str]
opcode: int = -1

Expand Down Expand Up @@ -840,6 +841,7 @@ def add_pseudo(
pseudo.name,
analyze_stack(pseudo),
[instructions[target] for target in pseudo.targets],
pseudo.as_sequence,
pseudo.flags,
)

Expand Down
6 changes: 4 additions & 2 deletions Tools/cases_generator/opcode_metadata_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,8 @@ def generate_pseudo_targets(analysis: Analysis, out: CWriter) -> None:
table_size = len(analysis.pseudos)
max_targets = max(len(pseudo.targets) for pseudo in analysis.pseudos.values())
out.emit("struct pseudo_targets {\n")
out.emit(f"uint8_t targets[{max_targets + 1}];\n")
out.emit(f"uint8_t as_sequence;\n")
out.emit(f"uint8_t targets[{1 + max_targets + 1}];\n")
out.emit("};\n")
out.emit(
f"extern const struct pseudo_targets _PyOpcode_PseudoTargets[{table_size}];\n"
Expand All @@ -315,10 +316,11 @@ def generate_pseudo_targets(analysis: Analysis, out: CWriter) -> None:
f"const struct pseudo_targets _PyOpcode_PseudoTargets[{table_size}] = {{\n"
)
for pseudo in analysis.pseudos.values():
as_sequence = "1" if pseudo.as_sequence else "0"
targets = ["0"] * (max_targets + 1)
for i, target in enumerate(pseudo.targets):
targets[i] = target.name
out.emit(f"[{pseudo.name}-256] = {{ {{ {', '.join(targets)} }} }},\n")
out.emit(f"[{pseudo.name}-256] = {{ {as_sequence}, {{ {', '.join(targets)} }} }},\n")
out.emit("};\n\n")
out.emit("#endif // NEED_OPCODE_METADATA\n")
out.emit("static inline bool\n")
Expand Down
25 changes: 17 additions & 8 deletions Tools/cases_generator/parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ class Pseudo(Node):
outputs: list[OutputEffect]
flags: list[str] # instr flags to set on the pseudo instruction
targets: list[str] # opcodes this can be replaced by
as_sequence: bool


AstNode = InstDef | Macro | Pseudo | Family
Expand Down Expand Up @@ -423,16 +424,22 @@ def pseudo_def(self) -> Pseudo | None:
flags = []
if self.expect(lx.RPAREN):
if self.expect(lx.EQUALS):
if not self.expect(lx.LBRACE):
raise self.make_syntax_error("Expected {")
if members := self.members():
if self.expect(lx.RBRACE) and self.expect(lx.SEMI):
if self.expect(lx.LBRACE):
as_sequence = False
closing = lx.RBRACE
elif self.expect(lx.LBRACKET):
as_sequence = True
closing = lx.RBRACKET
else:
raise self.make_syntax_error("Expected { or [")
if members := self.members(allow_sequence=True):
if self.expect(closing) and self.expect(lx.SEMI):
return Pseudo(
tkn.text, inp, outp, flags, members
tkn.text, inp, outp, flags, members, as_sequence
)
return None

def members(self) -> list[str] | None:
def members(self, allow_sequence=False) -> list[str] | None:
here = self.getpos()
if tkn := self.expect(lx.IDENTIFIER):
members = [tkn.text]
Expand All @@ -442,8 +449,10 @@ def members(self) -> list[str] | None:
else:
break
peek = self.peek()
if not peek or peek.kind != lx.RBRACE:
raise self.make_syntax_error("Expected comma or right paren")
kinds = [lx.RBRACE, lx.RBRACKET] if allow_sequence else [lx.RBRACE]
if not peek or peek.kind not in kinds:
raise self.make_syntax_error(
f"Expected comma or right paren{'/bracket' if allow_sequence else ''}")
return members
self.setpos(here)
return None
Expand Down

0 comments on commit 2612ace

Please sign in to comment.