mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
gh-106581: Split CALL_PY_EXACT_ARGS
into uops (#107760)
* Split `CALL_PY_EXACT_ARGS` into uops This is only the first step for doing `CALL` in Tier 2. The next step involves tracing into the called code object and back. After that we'll have to do the remaining `CALL` specialization. Finally we'll have to deal with `KW_NAMES`. Note: this moves setting `frame->return_offset` directly in front of `DISPATCH_INLINED()`, to make it easier to move it into `_PUSH_FRAME`.
This commit is contained in:
parent
665a4391e1
commit
dc8fdf5fd5
14 changed files with 412 additions and 116 deletions
|
@ -59,7 +59,7 @@ class Instruction:
|
|||
block_line: int # First line of block in original code
|
||||
|
||||
# Computed by constructor
|
||||
always_exits: bool
|
||||
always_exits: str # If the block always exits, its last line; else ""
|
||||
has_deopt: bool
|
||||
cache_offset: int
|
||||
cache_effects: list[parsing.CacheEffect]
|
||||
|
@ -120,13 +120,13 @@ class Instruction:
|
|||
def is_viable_uop(self) -> bool:
|
||||
"""Whether this instruction is viable as a uop."""
|
||||
dprint: typing.Callable[..., None] = lambda *args, **kwargs: None
|
||||
# if self.name.startswith("CALL"):
|
||||
# dprint = print
|
||||
if "FRAME" in self.name:
|
||||
dprint = print
|
||||
|
||||
if self.name == "EXIT_TRACE":
|
||||
return True # This has 'return frame' but it's okay
|
||||
if self.always_exits:
|
||||
dprint(f"Skipping {self.name} because it always exits")
|
||||
dprint(f"Skipping {self.name} because it always exits: {self.always_exits}")
|
||||
return False
|
||||
if len(self.active_caches) > 1:
|
||||
# print(f"Skipping {self.name} because it has >1 cache entries")
|
||||
|
@ -140,23 +140,6 @@ class Instruction:
|
|||
res = False
|
||||
return res
|
||||
|
||||
def write(self, out: Formatter, tier: Tiers = TIER_ONE) -> None:
|
||||
"""Write one instruction, sans prologue and epilogue."""
|
||||
|
||||
# Write a static assertion that a family's cache size is correct
|
||||
out.static_assert_family_size(self.name, self.family, self.cache_offset)
|
||||
|
||||
# Write input stack effect variable declarations and initializations
|
||||
stacking.write_single_instr(self, out, tier)
|
||||
|
||||
# Skip the rest if the block always exits
|
||||
if self.always_exits:
|
||||
return
|
||||
|
||||
# Write cache effect
|
||||
if tier == TIER_ONE and self.cache_offset:
|
||||
out.emit(f"next_instr += {self.cache_offset};")
|
||||
|
||||
def write_body(
|
||||
self,
|
||||
out: Formatter,
|
||||
|
@ -341,16 +324,16 @@ def extract_block_text(block: parsing.Block) -> tuple[list[str], bool, int]:
|
|||
return blocklines, check_eval_breaker, block_line
|
||||
|
||||
|
||||
def always_exits(lines: list[str]) -> bool:
|
||||
def always_exits(lines: list[str]) -> str:
|
||||
"""Determine whether a block always ends in a return/goto/etc."""
|
||||
if not lines:
|
||||
return False
|
||||
return ""
|
||||
line = lines[-1].rstrip()
|
||||
# Indent must match exactly (TODO: Do something better)
|
||||
if line[:12] != " " * 12:
|
||||
return False
|
||||
return ""
|
||||
line = line[12:]
|
||||
return line.startswith(
|
||||
if line.startswith(
|
||||
(
|
||||
"goto ",
|
||||
"return ",
|
||||
|
@ -359,4 +342,6 @@ def always_exits(lines: list[str]) -> bool:
|
|||
"Py_UNREACHABLE()",
|
||||
"ERROR_IF(true, ",
|
||||
)
|
||||
)
|
||||
):
|
||||
return line
|
||||
return ""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue