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:
Guido van Rossum 2023-10-03 10:13:50 -07:00 committed by GitHub
parent d73501602f
commit d67edcf0b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 315 additions and 315 deletions

View file

@ -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: