Skip to content

Commit 504bdc7

Browse files
committed
Refactor: Break dependenecy of metadata generation on Stack class
1 parent 61e9a43 commit 504bdc7

File tree

5 files changed

+85
-69
lines changed

5 files changed

+85
-69
lines changed

Python/generated_cases.c.h

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/opcode_metadata_generator.py

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@
44
"""
55

66
import argparse
7+
from typing import Iterator
78

89
from analyzer import (
910
Analysis,
1011
Instruction,
1112
PseudoInstruction,
1213
analyze_files,
1314
Uop,
15+
StackEffect
1416
)
1517
from generators_common import (
1618
DEFAULT_INPUT,
@@ -21,7 +23,7 @@
2123
from cwriter import CWriter
2224
from dataclasses import dataclass
2325
from typing import TextIO
24-
from stack import Stack, get_stack_effect, get_stack_effects
26+
from stack import StackOffset
2527

2628
# Constants used instead of size for macro expansions.
2729
# Note: 1, 2, 4 must match actual cache entry sizes.
@@ -93,16 +95,55 @@ def emit_stack_effect_function(
9395
out.emit("#endif\n\n")
9496

9597

98+
def stacks(inst: Instruction | PseudoInstruction) -> Iterator[StackEffect]:
99+
if isinstance(inst, Instruction):
100+
for uop in inst.parts:
101+
if isinstance(uop, Uop):
102+
yield uop.stack
103+
else:
104+
assert isinstance(inst, PseudoInstruction)
105+
yield inst.stack
106+
107+
108+
def apply_stack_effect(stack: StackOffset, effect: StackEffect) -> None:
109+
for var in reversed(effect.inputs):
110+
stack.pop(var)
111+
for var in effect.outputs:
112+
stack.push(var)
113+
114+
115+
def get_stack_effect(inst: Instruction | PseudoInstruction) -> StackOffset:
116+
stack = StackOffset.empty()
117+
for s in stacks(inst):
118+
apply_stack_effect(stack, s)
119+
return stack
120+
121+
122+
def get_stack_effects(inst: Instruction | PseudoInstruction) -> list[StackOffset]:
123+
"""Returns a list of stack effects after each uop"""
124+
result = []
125+
stack = StackOffset.empty()
126+
for s in stacks(inst):
127+
apply_stack_effect(stack, s)
128+
result.append(stack.copy())
129+
return result
130+
96131
def generate_stack_effect_functions(analysis: Analysis, out: CWriter) -> None:
97132
popped_data: list[tuple[str, str]] = []
98133
pushed_data: list[tuple[str, str]] = []
99134

100135
def add(inst: Instruction | PseudoInstruction) -> None:
101-
stack = get_stack_effect(inst)
102-
popped = (-stack.base_offset).to_c()
103-
pushed = (stack.top_offset - stack.base_offset).to_c()
104-
popped_data.append((inst.name, popped))
105-
pushed_data.append((inst.name, pushed))
136+
popped = StackOffset.empty()
137+
stack = StackOffset.empty()
138+
for effect in stacks(inst):
139+
for var in reversed(effect.inputs):
140+
stack.pop(var)
141+
popped = popped.minimum(stack)
142+
for var in effect.outputs:
143+
stack.push(var)
144+
pushed = stack - popped
145+
popped_data.append((inst.name, (-popped).to_c()))
146+
pushed_data.append((inst.name, pushed.to_c()))
106147

107148
for inst in analysis.instructions.values():
108149
add(inst)
@@ -152,8 +193,7 @@ def __init__(self) -> None:
152193
self.int_effect = None
153194
self.cond_effects = set()
154195

155-
def add(self, stack: Stack) -> None:
156-
top_off = stack.top_offset
196+
def add(self, top_off: StackOffset) -> None:
157197
top_off_int = top_off.as_int()
158198
if top_off_int is not None:
159199
if self.int_effect is None or top_off_int > self.int_effect:

Tools/cases_generator/stack.py

Lines changed: 22 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,18 @@ def __sub__(self, other: "StackOffset") -> "StackOffset":
134134
def __neg__(self) -> "StackOffset":
135135
return StackOffset(self.pushed, self.popped)
136136

137+
def is_negative(self) -> bool:
138+
self.simplify()
139+
if not self.pushed:
140+
return bool(self.popped)
141+
return False
142+
143+
def is_non_negative(self) -> bool:
144+
self.simplify()
145+
if not self.popped:
146+
return True
147+
return False
148+
137149
def simplify(self) -> None:
138150
"Remove matching values from both the popped and pushed list"
139151
if not self.popped:
@@ -164,6 +176,16 @@ def simplify(self) -> None:
164176
self.pushed.sort()
165177
self.popped.sort()
166178

179+
def minimum(self, other: "StackOffset") -> "StackOffset":
180+
self.simplify()
181+
other.simplify()
182+
diff = self - other
183+
if diff.is_non_negative():
184+
return other.copy()
185+
if diff.is_negative():
186+
return self.copy()
187+
raise StackError("Cannot determine minimum")
188+
167189
def to_c(self) -> str:
168190
self.simplify()
169191
int_offset = 0
@@ -386,47 +408,6 @@ def merge(self, other: "Stack", out: CWriter) -> None:
386408
self.align(other, out)
387409

388410

389-
def stacks(inst: Instruction | PseudoInstruction) -> Iterator[StackEffect]:
390-
if isinstance(inst, Instruction):
391-
for uop in inst.parts:
392-
if isinstance(uop, Uop):
393-
yield uop.stack
394-
else:
395-
assert isinstance(inst, PseudoInstruction)
396-
yield inst.stack
397-
398-
399-
def apply_stack_effect(stack: Stack, effect: StackEffect) -> None:
400-
locals: dict[str, Local] = {}
401-
for var in reversed(effect.inputs):
402-
_, local = stack.pop(var)
403-
if var.name != "unused":
404-
locals[local.name] = local
405-
for var in effect.outputs:
406-
if var.name in locals:
407-
local = locals[var.name]
408-
else:
409-
local = Local.unused(var)
410-
stack.push(local)
411-
412-
413-
def get_stack_effect(inst: Instruction | PseudoInstruction) -> Stack:
414-
stack = Stack()
415-
for s in stacks(inst):
416-
apply_stack_effect(stack, s)
417-
return stack
418-
419-
420-
def get_stack_effects(inst: Instruction | PseudoInstruction) -> list[Stack]:
421-
"""Returns a list of stack effects after each uop"""
422-
result = []
423-
stack = Stack()
424-
for s in stacks(inst):
425-
apply_stack_effect(stack, s)
426-
result.append(stack.copy())
427-
return result
428-
429-
430411
@dataclass
431412
class Storage:
432413

Tools/cases_generator/tier1_generator.py

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
)
2626
from cwriter import CWriter
2727
from typing import TextIO, Callable
28-
from stack import Local, Stack, StackError, get_stack_effect, Storage
28+
from stack import Local, Stack, StackError, Storage
2929

3030
DEFAULT_OUTPUT = ROOT / "Python/generated_cases.c.h"
3131

@@ -47,22 +47,17 @@ def declare_variable(var: StackItem, out: CWriter) -> None:
4747

4848

4949
def declare_variables(inst: Instruction, out: CWriter) -> None:
50-
try:
51-
stack = get_stack_effect(inst)
52-
except StackError as ex:
53-
raise analysis_error(ex.args[0], inst.where) from None
54-
required = set(stack.defined)
55-
required.discard("unused")
50+
declared = {"unused"}
5651
for part in inst.parts:
5752
if not isinstance(part, Uop):
5853
continue
5954
for var in part.stack.inputs:
60-
if var.name in required:
61-
required.remove(var.name)
55+
if var.used and var.name not in declared:
56+
declared.add(var.name)
6257
declare_variable(var, out)
6358
for var in part.stack.outputs:
64-
if var.name in required:
65-
required.remove(var.name)
59+
if var.used and var.name not in declared:
60+
declared.add(var.name)
6661
declare_variable(var, out)
6762

6863

Tools/cases_generator/uop_metadata_generator.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
write_header,
1616
cflags,
1717
)
18-
from stack import Stack
18+
from stack import StackOffset
1919
from cwriter import CWriter
2020
from typing import TextIO
2121

@@ -49,12 +49,12 @@ def generate_names_and_flags(analysis: Analysis, out: CWriter) -> None:
4949
out.emit("switch(opcode) {\n")
5050
for uop in analysis.uops.values():
5151
if uop.is_viable() and uop.properties.tier != 1:
52-
stack = Stack()
52+
stack = StackOffset.empty()
5353
for var in reversed(uop.stack.inputs):
5454
if var.peek:
5555
break
5656
stack.pop(var)
57-
popped = (-stack.base_offset).to_c()
57+
popped = (-stack).to_c()
5858
out.emit(f"case {uop.name}:\n")
5959
out.emit(f" return {popped};\n")
6060
out.emit("default:\n")

0 commit comments

Comments
 (0)