diff options
Diffstat (limited to 'Tools/cases_generator/analyzer.py')
-rw-r--r-- | Tools/cases_generator/analyzer.py | 78 |
1 files changed, 72 insertions, 6 deletions
diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py index e8ee314..3daae46 100644 --- a/Tools/cases_generator/analyzer.py +++ b/Tools/cases_generator/analyzer.py @@ -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]) |