mirror of
https://github.com/python/cpython.git
synced 2025-08-04 00:48:58 +00:00
gh-112519: Make it possible to specify instruction flags for pseudo instructions in bytecodes.c (#112520)
This commit is contained in:
parent
7eeea13403
commit
07ebd46f9e
6 changed files with 76 additions and 12 deletions
8
Include/internal/pycore_opcode_metadata.h
generated
8
Include/internal/pycore_opcode_metadata.h
generated
|
@ -1661,7 +1661,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
|
||||||
[IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
[IMPORT_FROM] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||||
[JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[JUMP_FORWARD] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
[JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
[JUMP_BACKWARD] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||||
[JUMP] = { true, 0, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[JUMP] = { true, 0, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||||
[JUMP_NO_INTERRUPT] = { true, 0, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[JUMP_NO_INTERRUPT] = { true, 0, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
[ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG },
|
[ENTER_EXECUTOR] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG },
|
||||||
[_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
[_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG },
|
||||||
|
@ -1703,9 +1703,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[OPCODE_METADATA_SIZE] = {
|
||||||
[BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
[BEFORE_ASYNC_WITH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||||
[BEFORE_WITH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
[BEFORE_WITH] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||||
[WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
[WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
|
||||||
[SETUP_FINALLY] = { true, 0, 0 },
|
[SETUP_FINALLY] = { true, 0, HAS_ARG_FLAG },
|
||||||
[SETUP_CLEANUP] = { true, 0, 0 },
|
[SETUP_CLEANUP] = { true, 0, HAS_ARG_FLAG },
|
||||||
[SETUP_WITH] = { true, 0, 0 },
|
[SETUP_WITH] = { true, 0, HAS_ARG_FLAG },
|
||||||
[POP_BLOCK] = { true, 0, 0 },
|
[POP_BLOCK] = { true, 0, 0 },
|
||||||
[PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 },
|
[PUSH_EXC_INFO] = { true, INSTR_FMT_IX, 0 },
|
||||||
[_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
|
[_GUARD_DORV_VALUES_INST_ATTR_FROM_DICT] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
|
||||||
|
|
|
@ -466,6 +466,44 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
self.run_cases_test(input, output)
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
|
def test_pseudo_instruction_no_flags(self):
|
||||||
|
input = """
|
||||||
|
pseudo(OP) = {
|
||||||
|
OP1,
|
||||||
|
};
|
||||||
|
|
||||||
|
inst(OP1, (--)) {
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
output = """
|
||||||
|
TARGET(OP1) {
|
||||||
|
frame->instr_ptr = next_instr;
|
||||||
|
next_instr += 1;
|
||||||
|
INSTRUCTION_STATS(OP1);
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
|
def test_pseudo_instruction_with_flags(self):
|
||||||
|
input = """
|
||||||
|
pseudo(OP, (HAS_ARG, HAS_JUMP)) = {
|
||||||
|
OP1,
|
||||||
|
};
|
||||||
|
|
||||||
|
inst(OP1, (--)) {
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
output = """
|
||||||
|
TARGET(OP1) {
|
||||||
|
frame->instr_ptr = next_instr;
|
||||||
|
next_instr += 1;
|
||||||
|
INSTRUCTION_STATS(OP1);
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
def test_array_input(self):
|
def test_array_input(self):
|
||||||
input = """
|
input = """
|
||||||
inst(OP, (below, values[oparg*2], above --)) {
|
inst(OP, (below, values[oparg*2], above --)) {
|
||||||
|
|
|
@ -2831,15 +2831,15 @@ dummy_func(
|
||||||
ERROR_IF(res == NULL, error);
|
ERROR_IF(res == NULL, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudo(SETUP_FINALLY) = {
|
pseudo(SETUP_FINALLY, (HAS_ARG)) = {
|
||||||
NOP,
|
NOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
pseudo(SETUP_CLEANUP) = {
|
pseudo(SETUP_CLEANUP, (HAS_ARG)) = {
|
||||||
NOP,
|
NOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
pseudo(SETUP_WITH) = {
|
pseudo(SETUP_WITH, (HAS_ARG)) = {
|
||||||
NOP,
|
NOP,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,7 @@ static const jump_target_label NO_LABEL = {-1};
|
||||||
static inline int
|
static inline int
|
||||||
is_block_push(cfg_instr *i)
|
is_block_push(cfg_instr *i)
|
||||||
{
|
{
|
||||||
|
assert(OPCODE_HAS_ARG(i->i_opcode) || !IS_BLOCK_PUSH_OPCODE(i->i_opcode));
|
||||||
return IS_BLOCK_PUSH_OPCODE(i->i_opcode);
|
return IS_BLOCK_PUSH_OPCODE(i->i_opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2239,7 +2240,6 @@ convert_pseudo_ops(basicblock *entryblock)
|
||||||
for (int i = 0; i < b->b_iused; i++) {
|
for (int i = 0; i < b->b_iused; i++) {
|
||||||
cfg_instr *instr = &b->b_instr[i];
|
cfg_instr *instr = &b->b_instr[i];
|
||||||
if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) {
|
if (is_block_push(instr) || instr->i_opcode == POP_BLOCK) {
|
||||||
assert(SAME_OPCODE_METADATA(instr->i_opcode, NOP));
|
|
||||||
INSTR_SET_OP0(instr, NOP);
|
INSTR_SET_OP0(instr, NOP);
|
||||||
}
|
}
|
||||||
else if (instr->i_opcode == LOAD_CLOSURE) {
|
else if (instr->i_opcode == LOAD_CLOSURE) {
|
||||||
|
|
|
@ -390,9 +390,14 @@ class Analyzer:
|
||||||
else:
|
else:
|
||||||
targets.append(self.macro_instrs[target_name])
|
targets.append(self.macro_instrs[target_name])
|
||||||
assert targets
|
assert targets
|
||||||
ignored_flags = {"HAS_EVAL_BREAK_FLAG", "HAS_DEOPT_FLAG", "HAS_ERROR_FLAG", "HAS_ESCAPES_FLAG"}
|
ignored_flags = {"HAS_EVAL_BREAK_FLAG", "HAS_DEOPT_FLAG", "HAS_ERROR_FLAG",
|
||||||
|
"HAS_ESCAPES_FLAG"}
|
||||||
assert len({t.instr_flags.bitmap(ignore=ignored_flags) for t in targets}) == 1
|
assert len({t.instr_flags.bitmap(ignore=ignored_flags) for t in targets}) == 1
|
||||||
return PseudoInstruction(pseudo.name, targets, targets[0].instr_flags)
|
|
||||||
|
flags = InstructionFlags(**{f"{f}_FLAG" : True for f in pseudo.flags})
|
||||||
|
for t in targets:
|
||||||
|
flags.add(t.instr_flags)
|
||||||
|
return PseudoInstruction(pseudo.name, targets, flags)
|
||||||
|
|
||||||
def analyze_instruction(
|
def analyze_instruction(
|
||||||
self, instr: Instruction, offset: int
|
self, instr: Instruction, offset: int
|
||||||
|
|
|
@ -138,7 +138,8 @@ class Family(Node):
|
||||||
@dataclass
|
@dataclass
|
||||||
class Pseudo(Node):
|
class Pseudo(Node):
|
||||||
name: str
|
name: str
|
||||||
targets: list[str] # opcodes this can be replaced by
|
flags: list[str] # instr flags to set on the pseudo instruction
|
||||||
|
targets: list[str] # opcodes this can be replaced by
|
||||||
|
|
||||||
|
|
||||||
class Parser(PLexer):
|
class Parser(PLexer):
|
||||||
|
@ -374,19 +375,39 @@ class Parser(PLexer):
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def flags(self) -> list[str]:
|
||||||
|
here = self.getpos()
|
||||||
|
if self.expect(lx.LPAREN):
|
||||||
|
if tkn := self.expect(lx.IDENTIFIER):
|
||||||
|
flags = [tkn.text]
|
||||||
|
while self.expect(lx.COMMA):
|
||||||
|
if tkn := self.expect(lx.IDENTIFIER):
|
||||||
|
flags.append(tkn.text)
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
if not self.expect(lx.RPAREN):
|
||||||
|
raise self.make_syntax_error("Expected comma or right paren")
|
||||||
|
return flags
|
||||||
|
self.setpos(here)
|
||||||
|
return []
|
||||||
|
|
||||||
@contextual
|
@contextual
|
||||||
def pseudo_def(self) -> Pseudo | None:
|
def pseudo_def(self) -> Pseudo | None:
|
||||||
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "pseudo":
|
if (tkn := self.expect(lx.IDENTIFIER)) and tkn.text == "pseudo":
|
||||||
size = None
|
size = None
|
||||||
if self.expect(lx.LPAREN):
|
if self.expect(lx.LPAREN):
|
||||||
if tkn := self.expect(lx.IDENTIFIER):
|
if tkn := self.expect(lx.IDENTIFIER):
|
||||||
|
if self.expect(lx.COMMA):
|
||||||
|
flags = self.flags()
|
||||||
|
else:
|
||||||
|
flags = []
|
||||||
if self.expect(lx.RPAREN):
|
if self.expect(lx.RPAREN):
|
||||||
if self.expect(lx.EQUALS):
|
if self.expect(lx.EQUALS):
|
||||||
if not self.expect(lx.LBRACE):
|
if not self.expect(lx.LBRACE):
|
||||||
raise self.make_syntax_error("Expected {")
|
raise self.make_syntax_error("Expected {")
|
||||||
if members := self.members():
|
if members := self.members():
|
||||||
if self.expect(lx.RBRACE) and self.expect(lx.SEMI):
|
if self.expect(lx.RBRACE) and self.expect(lx.SEMI):
|
||||||
return Pseudo(tkn.text, members)
|
return Pseudo(tkn.text, flags, members)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def members(self) -> list[str] | None:
|
def members(self) -> list[str] | None:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue