GH-120024: Tidy up case generator code a bit. (GH-122780)

This commit is contained in:
Mark Shannon 2024-08-08 10:57:59 +01:00 committed by GitHub
parent 0d9c123d1a
commit 81c739e2dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 175 additions and 103 deletions

View file

@ -38,9 +38,9 @@ def var_size(var: StackItem) -> str:
else:
return "1"
@dataclass
class Local:
item: StackItem
cached: bool
in_memory: bool
@ -75,6 +75,7 @@ class Local:
def is_array(self) -> bool:
return self.item.is_array()
@dataclass
class StackOffset:
"The stack offset of the virtual base of the stack from the physical stack pointer"
@ -183,44 +184,37 @@ class Stack:
)
if var.name in UNUSED:
if popped.name not in UNUSED and popped.name in self.defined:
raise StackError(f"Value is declared unused, but is already cached by prior operation")
raise StackError(
f"Value is declared unused, but is already cached by prior operation"
)
return "", popped
if not var.used:
return "", popped
self.defined.add(var.name)
# Always define array variables as it is free, and their offset might have changed
if var.is_array():
return (
f"{var.name} = &stack_pointer[{self.top_offset.to_c()}];\n",
Local.redefinition(var, popped)
)
if not popped.defined:
return (
f"{var.name} = stack_pointer[{self.top_offset.to_c()}];\n",
Local.redefinition(var, popped)
)
else:
if popped.defined:
if popped.name == var.name:
return "", popped
else:
return (
f"{var.name} = {popped.name};\n",
Local.redefinition(var, popped)
)
defn = f"{var.name} = {popped.name};\n"
else:
if var.is_array():
defn = f"{var.name} = &stack_pointer[{self.top_offset.to_c()}];\n"
else:
defn = f"{var.name} = stack_pointer[{self.top_offset.to_c()}];\n"
return defn, Local.redefinition(var, popped)
self.base_offset.pop(var)
if var.name in UNUSED or not var.used:
return "", Local.unused(var)
self.defined.add(var.name)
cast = f"({var.type})" if (not indirect and var.type) else ""
bits = ".bits" if cast and not extract_bits else ""
assign = (
f"{var.name} = {cast}{indirect}stack_pointer[{self.base_offset.to_c()}]{bits};"
)
assign = f"{var.name} = {cast}{indirect}stack_pointer[{self.base_offset.to_c()}]{bits};"
if var.condition:
if var.condition == "1":
assign = f"{assign}\n"
elif var.condition == "0":
return "", Local.unused(var)
return "", Local.unused(var)
else:
assign = f"if ({var.condition}) {{ {assign} }}\n"
else:
@ -228,21 +222,12 @@ class Stack:
in_memory = var.is_array() or var.peek
return assign, Local(var, not var.is_array(), in_memory, True)
def push(self, var: Local) -> str:
def push(self, var: Local) -> None:
self.variables.append(var)
if var.is_array() and not var.defined and var.item.used:
assert var.in_memory
assert not var.cached
c_offset = self.top_offset.to_c()
self.top_offset.push(var.item)
self.top_offset.push(var.item)
if var.item.used:
self.defined.add(var.name)
var.defined = True
return f"{var.name} = &stack_pointer[{c_offset}];\n"
else:
self.top_offset.push(var.item)
if var.item.used:
self.defined.add(var.name)
return ""
def define_output_arrays(self, outputs: list[StackItem]) -> str:
res = []
@ -257,24 +242,38 @@ class Stack:
return "\n".join(res)
@staticmethod
def _do_emit(out: CWriter, var: StackItem, base_offset: StackOffset,
cast_type: str = "uintptr_t", extract_bits: bool = False) -> None:
def _do_emit(
out: CWriter,
var: StackItem,
base_offset: StackOffset,
cast_type: str = "uintptr_t",
extract_bits: bool = False,
) -> None:
cast = f"({cast_type})" if var.type else ""
bits = ".bits" if cast and not extract_bits else ""
if var.condition == "0":
return
if var.condition and var.condition != "1":
out.emit(f"if ({var.condition}) ")
out.emit(
f"stack_pointer[{base_offset.to_c()}]{bits} = {cast}{var.name};\n"
)
out.emit(f"stack_pointer[{base_offset.to_c()}]{bits} = {cast}{var.name};\n")
@staticmethod
def _do_flush(out: CWriter, variables: list[Local], base_offset: StackOffset, top_offset: StackOffset,
cast_type: str = "uintptr_t", extract_bits: bool = False) -> None:
def _do_flush(
out: CWriter,
variables: list[Local],
base_offset: StackOffset,
top_offset: StackOffset,
cast_type: str = "uintptr_t",
extract_bits: bool = False,
) -> None:
out.start_line()
for var in variables:
if var.cached and not var.in_memory and not var.item.peek and not var.name in UNUSED:
if (
var.cached
and not var.in_memory
and not var.item.peek
and not var.name in UNUSED
):
Stack._do_emit(out, var.item, base_offset, cast_type, extract_bits)
base_offset.push(var.item)
if base_offset.to_c() != top_offset.to_c():
@ -286,31 +285,55 @@ class Stack:
out.emit("assert(WITHIN_STACK_BOUNDS());\n")
out.start_line()
def flush_locally(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = False) -> None:
self._do_flush(out, self.variables[:], self.base_offset.copy(), self.top_offset.copy(), cast_type, extract_bits)
def flush_locally(
self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = False
) -> None:
self._do_flush(
out,
self.variables[:],
self.base_offset.copy(),
self.top_offset.copy(),
cast_type,
extract_bits,
)
def flush(self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = False) -> None:
self._do_flush(out, self.variables, self.base_offset, self.top_offset, cast_type, extract_bits)
def flush(
self, out: CWriter, cast_type: str = "uintptr_t", extract_bits: bool = False
) -> None:
self._do_flush(
out,
self.variables,
self.base_offset,
self.top_offset,
cast_type,
extract_bits,
)
self.variables = []
self.base_offset.clear()
self.top_offset.clear()
def flush_single_var(self, out: CWriter, var_name: str, outputs: list[StackItem],
cast_type: str = "uintptr_t", extract_bits: bool = False) -> None:
def flush_single_var(
self,
out: CWriter,
var_name: str,
outputs: list[StackItem],
cast_type: str = "uintptr_t",
extract_bits: bool = False,
) -> None:
assert any(var.name == var_name for var in outputs)
base_offset = self.base_offset.copy()
top_offset = self.top_offset.copy()
for var in self.variables:
base_offset.push(var.item)
for var in outputs:
if any(var == v.item for v in self.variables):
for output in outputs:
if any(output == v.item for v in self.variables):
# The variable is already on the stack, such as a peeked value
# in the tier1 generator
continue
if var.name == var_name:
Stack._do_emit(out, var, base_offset, cast_type, extract_bits)
base_offset.push(var)
top_offset.push(var)
if output.name == var_name:
Stack._do_emit(out, output, base_offset, cast_type, extract_bits)
base_offset.push(output)
top_offset.push(output)
if base_offset.to_c() != top_offset.to_c():
print("base", base_offset, "top", top_offset)
assert False
@ -324,7 +347,8 @@ class Stack:
def get_stack_effect(inst: Instruction | PseudoInstruction) -> Stack:
stack = Stack()
def stacks(inst : Instruction | PseudoInstruction) -> Iterator[StackEffect]:
def stacks(inst: Instruction | PseudoInstruction) -> Iterator[StackEffect]:
if isinstance(inst, Instruction):
for uop in inst.parts:
if isinstance(uop, Uop):