mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
Revert "GH-128914: Remove conditional stack effects from bytecodes.c
and the code generators (GH-128918)" (GH-129202)
The commit introduced a ~2.5-3% regression in the free threading build.
This reverts commit ab61d3f430
.
This commit is contained in:
parent
d7d066c3ab
commit
a10f99375e
44 changed files with 1679 additions and 1460 deletions
|
@ -25,6 +25,7 @@ class Properties:
|
|||
side_exit: bool
|
||||
pure: bool
|
||||
tier: int | None = None
|
||||
oparg_and_1: bool = False
|
||||
const_oparg: int = -1
|
||||
needs_prev: bool = False
|
||||
no_save_ip: bool = False
|
||||
|
@ -123,14 +124,16 @@ class Flush:
|
|||
class StackItem:
|
||||
name: str
|
||||
type: str | None
|
||||
condition: str | None
|
||||
size: str
|
||||
peek: bool = False
|
||||
used: bool = False
|
||||
|
||||
def __str__(self) -> str:
|
||||
cond = f" if ({self.condition})" if self.condition else ""
|
||||
size = f"[{self.size}]" if self.size else ""
|
||||
type = "" if self.type is None else f"{self.type} "
|
||||
return f"{type}{self.name}{size} {self.peek}"
|
||||
return f"{type}{self.name}{size}{cond} {self.peek}"
|
||||
|
||||
def is_array(self) -> bool:
|
||||
return self.size != ""
|
||||
|
@ -312,19 +315,25 @@ def override_error(
|
|||
)
|
||||
|
||||
|
||||
def convert_stack_item(item: parser.StackEffect) -> StackItem:
|
||||
return StackItem(item.name, item.type, item.size)
|
||||
def convert_stack_item(
|
||||
item: parser.StackEffect, replace_op_arg_1: str | None
|
||||
) -> StackItem:
|
||||
cond = item.cond
|
||||
if replace_op_arg_1 and OPARG_AND_1.match(item.cond):
|
||||
cond = replace_op_arg_1
|
||||
return StackItem(item.name, item.type, cond, item.size)
|
||||
|
||||
|
||||
def analyze_stack(
|
||||
op: parser.InstDef | parser.Pseudo) -> StackEffect:
|
||||
op: parser.InstDef | parser.Pseudo, replace_op_arg_1: str | None = None
|
||||
) -> StackEffect:
|
||||
inputs: list[StackItem] = [
|
||||
convert_stack_item(i)
|
||||
convert_stack_item(i, replace_op_arg_1)
|
||||
for i in op.inputs
|
||||
if isinstance(i, parser.StackEffect)
|
||||
]
|
||||
outputs: list[StackItem] = [
|
||||
convert_stack_item(i) for i in op.outputs
|
||||
convert_stack_item(i, replace_op_arg_1) for i in op.outputs
|
||||
]
|
||||
# Mark variables with matching names at the base of the stack as "peek"
|
||||
modified = False
|
||||
|
@ -746,6 +755,40 @@ def always_exits(op: parser.InstDef) -> bool:
|
|||
return True
|
||||
return False
|
||||
|
||||
|
||||
def stack_effect_only_peeks(instr: parser.InstDef) -> bool:
|
||||
stack_inputs = [s for s in instr.inputs if not isinstance(s, parser.CacheEffect)]
|
||||
if len(stack_inputs) != len(instr.outputs):
|
||||
return False
|
||||
if len(stack_inputs) == 0:
|
||||
return False
|
||||
if any(s.cond for s in stack_inputs) or any(s.cond for s in instr.outputs):
|
||||
return False
|
||||
return all(
|
||||
(s.name == other.name and s.type == other.type and s.size == other.size)
|
||||
for s, other in zip(stack_inputs, instr.outputs)
|
||||
)
|
||||
|
||||
|
||||
OPARG_AND_1 = re.compile("\\(*oparg *& *1")
|
||||
|
||||
|
||||
def effect_depends_on_oparg_1(op: parser.InstDef) -> bool:
|
||||
for effect in op.inputs:
|
||||
if isinstance(effect, parser.CacheEffect):
|
||||
continue
|
||||
if not effect.cond:
|
||||
continue
|
||||
if OPARG_AND_1.match(effect.cond):
|
||||
return True
|
||||
for effect in op.outputs:
|
||||
if not effect.cond:
|
||||
continue
|
||||
if OPARG_AND_1.match(effect.cond):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def compute_properties(op: parser.InstDef) -> Properties:
|
||||
escaping_calls = find_escaping_api_calls(op)
|
||||
has_free = (
|
||||
|
@ -819,6 +862,29 @@ def make_uop(
|
|||
body=op.block.tokens,
|
||||
properties=compute_properties(op),
|
||||
)
|
||||
if effect_depends_on_oparg_1(op) and "split" in op.annotations:
|
||||
result.properties.oparg_and_1 = True
|
||||
for bit in ("0", "1"):
|
||||
name_x = name + "_" + bit
|
||||
properties = compute_properties(op)
|
||||
if properties.oparg:
|
||||
# May not need oparg anymore
|
||||
properties.oparg = any(
|
||||
token.text == "oparg" for token in op.block.tokens
|
||||
)
|
||||
rep = Uop(
|
||||
name=name_x,
|
||||
context=op.context,
|
||||
annotations=op.annotations,
|
||||
stack=analyze_stack(op, bit),
|
||||
caches=analyze_caches(inputs),
|
||||
deferred_refs=analyze_deferred_refs(op),
|
||||
output_stores=find_stores_outputs(op),
|
||||
body=op.block.tokens,
|
||||
properties=properties,
|
||||
)
|
||||
rep.replicates = result
|
||||
uops[name_x] = rep
|
||||
for anno in op.annotations:
|
||||
if anno.startswith("replicate"):
|
||||
result.replicated = int(anno[10:-1])
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue