mirror of https://github.com/python/cpython
GH-118926: Better distinguish between pointer and arrays in interpreter generator (GH-121496)
This commit is contained in:
parent
facf9862da
commit
bf8686e1ea
|
@ -815,7 +815,6 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
"""
|
"""
|
||||||
self.run_cases_test(input, output)
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
|
|
||||||
def test_deopt_and_exit(self):
|
def test_deopt_and_exit(self):
|
||||||
input = """
|
input = """
|
||||||
pure op(OP, (arg1 -- out)) {
|
pure op(OP, (arg1 -- out)) {
|
||||||
|
@ -827,6 +826,49 @@ class TestGeneratedCases(unittest.TestCase):
|
||||||
with self.assertRaises(Exception):
|
with self.assertRaises(Exception):
|
||||||
self.run_cases_test(input, output)
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
|
def test_array_of_one(self):
|
||||||
|
input = """
|
||||||
|
inst(OP, (arg[1] -- out[1])) {
|
||||||
|
out[0] = arg[0];
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
output = """
|
||||||
|
TARGET(OP) {
|
||||||
|
frame->instr_ptr = next_instr;
|
||||||
|
next_instr += 1;
|
||||||
|
INSTRUCTION_STATS(OP);
|
||||||
|
_PyStackRef *arg;
|
||||||
|
_PyStackRef *out;
|
||||||
|
arg = &stack_pointer[-1];
|
||||||
|
out = &stack_pointer[-1];
|
||||||
|
out[0] = arg[0];
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
|
def test_pointer_to_stackref(self):
|
||||||
|
input = """
|
||||||
|
inst(OP, (arg: _PyStackRef * -- out)) {
|
||||||
|
out = *arg;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
output = """
|
||||||
|
TARGET(OP) {
|
||||||
|
frame->instr_ptr = next_instr;
|
||||||
|
next_instr += 1;
|
||||||
|
INSTRUCTION_STATS(OP);
|
||||||
|
_PyStackRef *arg;
|
||||||
|
_PyStackRef out;
|
||||||
|
arg = (_PyStackRef *)stack_pointer[-1].bits;
|
||||||
|
out = *arg;
|
||||||
|
stack_pointer[-1] = out;
|
||||||
|
DISPATCH();
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
self.run_cases_test(input, output)
|
||||||
|
|
||||||
|
|
||||||
class TestGeneratedAbstractCases(unittest.TestCase):
|
class TestGeneratedAbstractCases(unittest.TestCase):
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
|
@ -106,13 +106,15 @@ class StackItem:
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
cond = f" if ({self.condition})" if self.condition else ""
|
cond = f" if ({self.condition})" if self.condition else ""
|
||||||
size = f"[{self.size}]" if self.size != "1" else ""
|
size = f"[{self.size}]" if self.size else ""
|
||||||
type = "" if self.type is None else f"{self.type} "
|
type = "" if self.type is None else f"{self.type} "
|
||||||
return f"{type}{self.name}{size}{cond} {self.peek}"
|
return f"{type}{self.name}{size}{cond} {self.peek}"
|
||||||
|
|
||||||
def is_array(self) -> bool:
|
def is_array(self) -> bool:
|
||||||
return self.type == "_PyStackRef *"
|
return self.size != ""
|
||||||
|
|
||||||
|
def get_size(self) -> str:
|
||||||
|
return self.size if self.size else "1"
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class StackEffect:
|
class StackEffect:
|
||||||
|
@ -293,7 +295,7 @@ def convert_stack_item(item: parser.StackEffect, replace_op_arg_1: str | None) -
|
||||||
if replace_op_arg_1 and OPARG_AND_1.match(item.cond):
|
if replace_op_arg_1 and OPARG_AND_1.match(item.cond):
|
||||||
cond = replace_op_arg_1
|
cond = replace_op_arg_1
|
||||||
return StackItem(
|
return StackItem(
|
||||||
item.name, item.type, cond, (item.size or "1")
|
item.name, item.type, cond, item.size
|
||||||
)
|
)
|
||||||
|
|
||||||
def analyze_stack(op: parser.InstDef | parser.Pseudo, replace_op_arg_1: str | None = None) -> StackEffect:
|
def analyze_stack(op: parser.InstDef | parser.Pseudo, replace_op_arg_1: str | None = None) -> StackEffect:
|
||||||
|
|
|
@ -5,9 +5,10 @@ from analyzer import (
|
||||||
Instruction,
|
Instruction,
|
||||||
Uop,
|
Uop,
|
||||||
Properties,
|
Properties,
|
||||||
|
StackItem,
|
||||||
)
|
)
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import Callable, Mapping, TextIO, Iterator
|
from typing import Callable, Mapping, TextIO, Iterator, Tuple
|
||||||
from lexer import Token
|
from lexer import Token
|
||||||
from stack import Stack
|
from stack import Stack
|
||||||
|
|
||||||
|
@ -24,6 +25,15 @@ def root_relative_path(filename: str) -> str:
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
|
def type_and_null(var: StackItem) -> Tuple[str, str]:
|
||||||
|
if var.type:
|
||||||
|
return var.type, "NULL"
|
||||||
|
elif var.is_array():
|
||||||
|
return "_PyStackRef *", "NULL"
|
||||||
|
else:
|
||||||
|
return "_PyStackRef", "PyStackRef_NULL"
|
||||||
|
|
||||||
|
|
||||||
def write_header(
|
def write_header(
|
||||||
generator: str, sources: list[str], outfile: TextIO, comment: str = "//"
|
generator: str, sources: list[str], outfile: TextIO, comment: str = "//"
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -126,7 +136,7 @@ def replace_decrefs(
|
||||||
for var in uop.stack.inputs:
|
for var in uop.stack.inputs:
|
||||||
if var.name == "unused" or var.name == "null" or var.peek:
|
if var.name == "unused" or var.name == "null" or var.peek:
|
||||||
continue
|
continue
|
||||||
if var.size != "1":
|
if var.size:
|
||||||
out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n")
|
out.emit(f"for (int _i = {var.size}; --_i >= 0;) {{\n")
|
||||||
out.emit(f"PyStackRef_CLOSE({var.name}[_i]);\n")
|
out.emit(f"PyStackRef_CLOSE({var.name}[_i]);\n")
|
||||||
out.emit("}\n")
|
out.emit("}\n")
|
||||||
|
|
|
@ -285,7 +285,6 @@ class Parser(PLexer):
|
||||||
if not (size := self.expression()):
|
if not (size := self.expression()):
|
||||||
raise self.make_syntax_error("Expected expression")
|
raise self.make_syntax_error("Expected expression")
|
||||||
self.require(lx.RBRACKET)
|
self.require(lx.RBRACKET)
|
||||||
type_text = "_PyStackRef *"
|
|
||||||
size_text = size.text.strip()
|
size_text = size.text.strip()
|
||||||
return StackEffect(tkn.text, type_text, cond_text, size_text)
|
return StackEffect(tkn.text, type_text, cond_text, size_text)
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -28,14 +28,15 @@ def var_size(var: StackItem) -> str:
|
||||||
if var.condition == "0":
|
if var.condition == "0":
|
||||||
return "0"
|
return "0"
|
||||||
elif var.condition == "1":
|
elif var.condition == "1":
|
||||||
return var.size
|
return var.get_size()
|
||||||
elif var.condition == "oparg & 1" and var.size == "1":
|
elif var.condition == "oparg & 1" and not var.size:
|
||||||
return f"({var.condition})"
|
return f"({var.condition})"
|
||||||
else:
|
else:
|
||||||
return f"(({var.condition}) ? {var.size} : 0)"
|
return f"(({var.condition}) ? {var.get_size()} : 0)"
|
||||||
else:
|
elif var.size:
|
||||||
return var.size
|
return var.size
|
||||||
|
else:
|
||||||
|
return "1"
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class StackOffset:
|
class StackOffset:
|
||||||
|
|
|
@ -13,12 +13,14 @@ from analyzer import (
|
||||||
analyze_files,
|
analyze_files,
|
||||||
Skip,
|
Skip,
|
||||||
analysis_error,
|
analysis_error,
|
||||||
|
StackItem,
|
||||||
)
|
)
|
||||||
from generators_common import (
|
from generators_common import (
|
||||||
DEFAULT_INPUT,
|
DEFAULT_INPUT,
|
||||||
ROOT,
|
ROOT,
|
||||||
write_header,
|
write_header,
|
||||||
emit_tokens,
|
emit_tokens,
|
||||||
|
type_and_null,
|
||||||
)
|
)
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import TextIO
|
from typing import TextIO
|
||||||
|
@ -38,19 +40,16 @@ def declare_variables(inst: Instruction, out: CWriter) -> None:
|
||||||
for var in reversed(uop.stack.inputs):
|
for var in reversed(uop.stack.inputs):
|
||||||
if var.name not in variables:
|
if var.name not in variables:
|
||||||
variables.add(var.name)
|
variables.add(var.name)
|
||||||
type, null = (var.type, "NULL") if var.type else ("_PyStackRef", "PyStackRef_NULL")
|
type, null = type_and_null(var)
|
||||||
space = " " if type[-1].isalnum() else ""
|
space = " " if type[-1].isalnum() else ""
|
||||||
if var.condition:
|
if var.condition:
|
||||||
out.emit(f"{type}{space}{var.name} = {null};\n")
|
out.emit(f"{type}{space}{var.name} = {null};\n")
|
||||||
else:
|
else:
|
||||||
if var.is_array():
|
out.emit(f"{type}{space}{var.name};\n")
|
||||||
out.emit(f"{var.type}{space}{var.name};\n")
|
|
||||||
else:
|
|
||||||
out.emit(f"{type}{space}{var.name};\n")
|
|
||||||
for var in uop.stack.outputs:
|
for var in uop.stack.outputs:
|
||||||
if var.name not in variables:
|
if var.name not in variables:
|
||||||
variables.add(var.name)
|
variables.add(var.name)
|
||||||
type, null = (var.type, "NULL") if var.type else ("_PyStackRef", "PyStackRef_NULL")
|
type, null = type_and_null(var)
|
||||||
space = " " if type[-1].isalnum() else ""
|
space = " " if type[-1].isalnum() else ""
|
||||||
if var.condition:
|
if var.condition:
|
||||||
out.emit(f"{type}{space}{var.name} = {null};\n")
|
out.emit(f"{type}{space}{var.name} = {null};\n")
|
||||||
|
|
|
@ -20,6 +20,7 @@ from generators_common import (
|
||||||
emit_tokens,
|
emit_tokens,
|
||||||
emit_to,
|
emit_to,
|
||||||
REPLACEMENT_FUNCTIONS,
|
REPLACEMENT_FUNCTIONS,
|
||||||
|
type_and_null,
|
||||||
)
|
)
|
||||||
from cwriter import CWriter
|
from cwriter import CWriter
|
||||||
from typing import TextIO, Iterator
|
from typing import TextIO, Iterator
|
||||||
|
@ -35,7 +36,7 @@ def declare_variable(
|
||||||
if var.name in variables:
|
if var.name in variables:
|
||||||
return
|
return
|
||||||
variables.add(var.name)
|
variables.add(var.name)
|
||||||
type, null = (var.type, "NULL") if var.type else ("_PyStackRef", "PyStackRef_NULL")
|
type, null = type_and_null(var)
|
||||||
space = " " if type[-1].isalnum() else ""
|
space = " " if type[-1].isalnum() else ""
|
||||||
if var.condition:
|
if var.condition:
|
||||||
out.emit(f"{type}{space}{var.name} = {null};\n")
|
out.emit(f"{type}{space}{var.name} = {null};\n")
|
||||||
|
|
Loading…
Reference in New Issue