mirror of
https://github.com/python/cpython.git
synced 2025-10-13 10:23:28 +00:00
gh-109979: Auto-generate the target for DEOPT_IF() (#110193)
In Python/bytecodes.c, you now write ``` DEOPT_IF(condition); ``` The code generator expands this to ``` DEOPT_IF(condition, opcode); ``` where `opcode` is the name of the unspecialized instruction. This works inside macro expansions too. **CAVEAT:** The entire `DEOPT_IF(condition)` statement must be on a single line. If it isn't, the substitution will fail; an error will be printed by the code generator and the C compiler will report some errors.
This commit is contained in:
parent
d73501602f
commit
d67edcf0b3
8 changed files with 315 additions and 315 deletions
|
@ -26,7 +26,7 @@ RESERVED_WORDS = {
|
|||
"co_names": "Use FRAME_CO_NAMES.",
|
||||
}
|
||||
|
||||
RE_PREDICTED = r"^\s*(?:GO_TO_INSTRUCTION\(|DEOPT_IF\(.*?,\s*)(\w+)\);\s*(?://.*)?$"
|
||||
RE_GO_TO_INSTR = r"^\s*GO_TO_INSTRUCTION\((\w+)\);\s*(?://.*)?$"
|
||||
|
||||
|
||||
class Analyzer:
|
||||
|
@ -187,16 +187,23 @@ class Analyzer:
|
|||
Raises SystemExit if there is an error.
|
||||
"""
|
||||
self.analyze_macros_and_pseudos()
|
||||
self.find_predictions()
|
||||
self.map_families()
|
||||
self.mark_predictions()
|
||||
self.check_families()
|
||||
|
||||
def find_predictions(self) -> None:
|
||||
"""Find the instructions that need PREDICTED() labels."""
|
||||
def mark_predictions(self) -> None:
|
||||
"""Mark the instructions that need PREDICTED() labels."""
|
||||
# Start with family heads
|
||||
for family in self.families.values():
|
||||
if family.name in self.instrs:
|
||||
self.instrs[family.name].predicted = True
|
||||
if family.name in self.macro_instrs:
|
||||
self.macro_instrs[family.name].predicted = True
|
||||
# Also look for GO_TO_INSTRUCTION() calls
|
||||
for instr in self.instrs.values():
|
||||
targets: set[str] = set()
|
||||
for line in instr.block_text:
|
||||
if m := re.match(RE_PREDICTED, line):
|
||||
if m := re.match(RE_GO_TO_INSTR, line):
|
||||
targets.add(m.group(1))
|
||||
for target in targets:
|
||||
if target_instr := self.instrs.get(target):
|
||||
|
@ -225,11 +232,18 @@ class Analyzer:
|
|||
)
|
||||
else:
|
||||
member_instr.family = family
|
||||
elif not self.macro_instrs.get(member):
|
||||
if member_mac := self.macro_instrs.get(member):
|
||||
assert member_mac.family is None, (member, member_mac.family.name)
|
||||
member_mac.family = family
|
||||
if not member_instr and not member_mac:
|
||||
self.error(
|
||||
f"Unknown instruction {member!r} referenced in family {family.name!r}",
|
||||
family,
|
||||
)
|
||||
# A sanctioned exception:
|
||||
# This opcode is a member of the family but it doesn't pass the checks.
|
||||
if mac := self.macro_instrs.get("BINARY_OP_INPLACE_ADD_UNICODE"):
|
||||
mac.family = self.families.get("BINARY_OP")
|
||||
|
||||
def check_families(self) -> None:
|
||||
"""Check each family:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue