GH-135379: Remove types from stack items in code generator. (GH-135384)

* Make casts explicit in the instruction definitions
This commit is contained in:
Mark Shannon 2025-06-11 15:52:25 +01:00 committed by GitHub
parent 49d72365cd
commit c87b5b2cb6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 257 additions and 255 deletions

View file

@ -135,15 +135,13 @@ class Flush:
@dataclass
class StackItem:
name: str
type: str | None
size: str
peek: bool = False
used: bool = False
def __str__(self) -> str:
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"{self.name}{size} {self.peek}"
def is_array(self) -> bool:
return self.size != ""
@ -345,7 +343,7 @@ def override_error(
def convert_stack_item(
item: parser.StackEffect, replace_op_arg_1: str | None
) -> StackItem:
return StackItem(item.name, item.type, item.size)
return StackItem(item.name, item.size)
def check_unused(stack: list[StackItem], input_names: dict[str, lexer.Token]) -> None:
"Unused items cannot be on the stack above used, non-peek items"
@ -683,6 +681,8 @@ NON_ESCAPING_FUNCTIONS = (
"PyStackRef_IsNullOrInt",
"PyStackRef_IsError",
"PyStackRef_IsValid",
"PyStackRef_Wrap",
"PyStackRef_Unwrap",
)
@ -811,7 +811,7 @@ def stack_effect_only_peeks(instr: parser.InstDef) -> bool:
if len(stack_inputs) == 0:
return False
return all(
(s.name == other.name and s.type == other.type and s.size == other.size)
(s.name == other.name and s.size == other.size)
for s, other in zip(stack_inputs, instr.outputs)
)

View file

@ -56,9 +56,7 @@ def root_relative_path(filename: str) -> str:
def type_and_null(var: StackItem) -> tuple[str, str]:
if var.type:
return var.type, "NULL"
elif var.is_array():
if var.is_array():
return "_PyStackRef *", "NULL"
else:
return "_PyStackRef", "PyStackRef_NULL"

View file

@ -73,8 +73,6 @@ def validate_uop(override: Uop, uop: Uop) -> None:
def type_name(var: StackItem) -> str:
if var.is_array():
return "JitOptSymbol **"
if var.type:
return var.type
return "JitOptSymbol *"
@ -230,7 +228,7 @@ def generate_abstract_interpreter(
declare_variables(override, out, skip_inputs=False)
else:
declare_variables(uop, out, skip_inputs=True)
stack = Stack(extract_bits=False, cast_type="JitOptSymbol *")
stack = Stack()
write_uop(override, uop, out, stack, debug, skip_inputs=(override is None))
out.start_line()
out.emit("break;\n")

View file

@ -247,12 +247,11 @@ class SimpleStmt(Stmt):
@dataclass
class StackEffect(Node):
name: str = field(compare=False) # __eq__ only uses type, cond, size
type: str = "" # Optional `:type`
size: str = "" # Optional `[size]`
# Note: size cannot be combined with type or cond
def __repr__(self) -> str:
items = [self.name, self.type, self.size]
items = [self.name, self.size]
while items and items[-1] == "":
del items[-1]
return f"StackEffect({', '.join(repr(item) for item in items)})"
@ -463,20 +462,13 @@ class Parser(PLexer):
# IDENTIFIER [':' IDENTIFIER [TIMES]] ['if' '(' expression ')']
# | IDENTIFIER '[' expression ']'
if tkn := self.expect(lx.IDENTIFIER):
type_text = ""
if self.expect(lx.COLON):
type_text = self.require(lx.IDENTIFIER).text.strip()
if self.expect(lx.TIMES):
type_text += " *"
size_text = ""
if self.expect(lx.LBRACKET):
if type_text:
raise self.make_syntax_error("Unexpected [")
if not (size := self.expression()):
raise self.make_syntax_error("Expected expression")
self.require(lx.RBRACKET)
size_text = size.text.strip()
return StackEffect(tkn.text, type_text, size_text)
return StackEffect(tkn.text, size_text)
return None
@contextual

View file

@ -168,7 +168,7 @@ class Local:
@staticmethod
def register(name: str) -> "Local":
item = StackItem(name, None, "", False, True)
item = StackItem(name, "", False, True)
return Local(item, None, True)
def kill(self) -> None:
@ -216,13 +216,11 @@ def array_or_scalar(var: StackItem | Local) -> str:
return "array" if var.is_array() else "scalar"
class Stack:
def __init__(self, extract_bits: bool=True, cast_type: str = "uintptr_t") -> None:
def __init__(self) -> None:
self.base_offset = PointerOffset.zero()
self.physical_sp = PointerOffset.zero()
self.logical_sp = PointerOffset.zero()
self.variables: list[Local] = []
self.extract_bits = extract_bits
self.cast_type = cast_type
def drop(self, var: StackItem, check_liveness: bool) -> None:
self.logical_sp = self.logical_sp.pop(var)
@ -268,10 +266,8 @@ class Stack:
self.base_offset = self.logical_sp
if var.name in UNUSED or not var.used:
return Local.unused(var, self.base_offset)
cast = f"({var.type})" if (not indirect and var.type) else ""
bits = ".bits" if cast and self.extract_bits else ""
c_offset = (self.base_offset - self.physical_sp).to_c()
assign = f"{var.name} = {cast}{indirect}stack_pointer[{c_offset}]{bits};\n"
assign = f"{var.name} = {indirect}stack_pointer[{c_offset}];\n"
out.emit(assign)
self._print(out)
return Local.from_memory(var, self.base_offset)
@ -292,12 +288,8 @@ class Stack:
out: CWriter,
var: StackItem,
stack_offset: PointerOffset,
cast_type: str,
extract_bits: bool,
) -> None:
cast = f"({cast_type})" if var.type else ""
bits = ".bits" if cast and extract_bits else ""
out.emit(f"stack_pointer[{stack_offset.to_c()}]{bits} = {cast}{var.name};\n")
out.emit(f"stack_pointer[{stack_offset.to_c()}] = {var.name};\n")
def _save_physical_sp(self, out: CWriter) -> None:
if self.physical_sp != self.logical_sp:
@ -320,7 +312,7 @@ class Stack:
self._print(out)
var.memory_offset = var_offset
stack_offset = var_offset - self.physical_sp
Stack._do_emit(out, var.item, stack_offset, self.cast_type, self.extract_bits)
Stack._do_emit(out, var.item, stack_offset)
self._print(out)
var_offset = var_offset.push(var.item)
@ -350,7 +342,7 @@ class Stack:
out.emit(self.as_comment() + "\n")
def copy(self) -> "Stack":
other = Stack(self.extract_bits, self.cast_type)
other = Stack()
other.base_offset = self.base_offset
other.physical_sp = self.physical_sp
other.logical_sp = self.logical_sp