GH-98831: Typed stack effects, and more instructions converted (#99764)

Stack effects can now have a type, e.g. `inst(X, (left, right -- jump/uint64_t)) { ... }`.

Instructions converted to the non-legacy format:

* COMPARE_OP
* COMPARE_OP_FLOAT_JUMP
* COMPARE_OP_INT_JUMP
* COMPARE_OP_STR_JUMP
* STORE_ATTR
* DELETE_ATTR
* STORE_GLOBAL
* STORE_ATTR_INSTANCE_VALUE
* STORE_ATTR_WITH_HINT
* STORE_ATTR_SLOT, and complete the store_attr family
* Complete the store_subscr family: STORE_SUBSCR{,DICT,LIST_INT}
  (STORE_SUBSCR was alread half converted,
  but wasn't using cache effects yet.)
* DELETE_SUBSCR
* PRINT_EXPR
* INTERPRETER_EXIT (a bit weird, ends in return)
* RETURN_VALUE
* GET_AITER (had to restructure it some)
  The original had mysterious `SET_TOP(NULL)` before `goto error`.
  I assume those just account for `obj` having been decref'ed,
  so I got rid of them in favor of the cleanup implied by `ERROR_IF()`.
* LIST_APPEND (a bit unhappy with it)
* SET_ADD (also a bit unhappy with it)

Various other improvements/refactorings as well.
This commit is contained in:
Guido van Rossum 2022-12-08 13:31:27 -08:00 committed by GitHub
parent 35cc0ea736
commit c85be734d1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 545 additions and 604 deletions

View file

@ -62,7 +62,8 @@ class Block(Node):
@dataclass
class StackEffect(Node):
name: str
# TODO: type, condition
type: str = ""
# TODO: array, condition
@dataclass
@ -147,7 +148,7 @@ def inst_header(self) -> InstHeader | None:
if self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER)):
name = tkn.text
if self.expect(lx.COMMA):
inp, outp = self.stack_effect()
inp, outp = self.io_effect()
if self.expect(lx.RPAREN):
if (tkn := self.peek()) and tkn.kind == lx.LBRACE:
return InstHeader(kind, name, inp, outp)
@ -156,7 +157,7 @@ def inst_header(self) -> InstHeader | None:
return InstHeader(kind, name, [], [])
return None
def stack_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]:
def io_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]:
# '(' [inputs] '--' [outputs] ')'
if self.expect(lx.LPAREN):
inputs = self.inputs() or []
@ -181,23 +182,7 @@ def inputs(self) -> list[InputEffect] | None:
@contextual
def input(self) -> InputEffect | None:
# IDENTIFIER '/' INTEGER (CacheEffect)
# IDENTIFIER (StackEffect)
if tkn := self.expect(lx.IDENTIFIER):
if self.expect(lx.DIVIDE):
if num := self.expect(lx.NUMBER):
try:
size = int(num.text)
except ValueError:
raise self.make_syntax_error(
f"Expected integer, got {num.text!r}"
)
else:
return CacheEffect(tkn.text, size)
raise self.make_syntax_error("Expected integer")
else:
# TODO: Arrays, conditions
return StackEffect(tkn.text)
return self.cache_effect() or self.stack_effect()
def outputs(self) -> list[OutputEffect] | None:
# output (, output)*
@ -214,8 +199,30 @@ def outputs(self) -> list[OutputEffect] | None:
@contextual
def output(self) -> OutputEffect | None:
return self.stack_effect()
@contextual
def cache_effect(self) -> CacheEffect | None:
# IDENTIFIER '/' NUMBER
if tkn := self.expect(lx.IDENTIFIER):
return StackEffect(tkn.text)
if self.expect(lx.DIVIDE):
num = self.require(lx.NUMBER).text
try:
size = int(num)
except ValueError:
raise self.make_syntax_error(f"Expected integer, got {num!r}")
else:
return CacheEffect(tkn.text, size)
@contextual
def stack_effect(self) -> StackEffect | None:
# IDENTIFIER [':' IDENTIFIER]
# TODO: Arrays, conditions
if tkn := self.expect(lx.IDENTIFIER):
type = ""
if self.expect(lx.COLON):
type = self.require(lx.IDENTIFIER).text
return StackEffect(tkn.text, type)
@contextual
def super_def(self) -> Super | None: