summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Python/bytecodes.c2
-rw-r--r--Python/executor_cases.c.h34
-rw-r--r--Python/generated_cases.c.h40
-rw-r--r--Tools/cases_generator/analyzer.py45
-rw-r--r--Tools/cases_generator/generators_common.py25
-rw-r--r--Tools/cases_generator/lexer.py2
-rw-r--r--Tools/cases_generator/stack.py43
-rw-r--r--Tools/cases_generator/tier1_generator.py24
-rw-r--r--Tools/cases_generator/tier2_generator.py18
9 files changed, 173 insertions, 60 deletions
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index d28cbd7..b68f932 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -1424,7 +1424,7 @@ dummy_func(
"no locals found");
ERROR_IF(true, error);
}
- locals = PyStackRef_FromPyObjectNew(l);;
+ locals = PyStackRef_FromPyObjectNew(l);
}
inst(LOAD_FROM_DICT_OR_GLOBALS, (mod_or_class_dict -- v)) {
diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h
index 4def11c..f274128 100644
--- a/Python/executor_cases.c.h
+++ b/Python/executor_cases.c.h
@@ -1469,10 +1469,10 @@
}
STAT_INC(UNPACK_SEQUENCE, hit);
val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0));
+ stack_pointer[0] = val0;
val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1));
- PyStackRef_CLOSE(seq);
stack_pointer[-1] = val1;
- stack_pointer[0] = val0;
+ PyStackRef_CLOSE(seq);
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
break;
@@ -1612,7 +1612,7 @@
"no locals found");
if (true) JUMP_TO_ERROR();
}
- locals = PyStackRef_FromPyObjectNew(l);;
+ locals = PyStackRef_FromPyObjectNew(l);
stack_pointer[0] = locals;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -2422,8 +2422,8 @@
STAT_INC(LOAD_ATTR, hit);
null = PyStackRef_NULL;
attr = PyStackRef_FromPyObjectNew(attr_o);
- PyStackRef_CLOSE(owner);
stack_pointer[-1] = attr;
+ PyStackRef_CLOSE(owner);
break;
}
@@ -2444,8 +2444,8 @@
STAT_INC(LOAD_ATTR, hit);
null = PyStackRef_NULL;
attr = PyStackRef_FromPyObjectNew(attr_o);
- PyStackRef_CLOSE(owner);
stack_pointer[-1] = attr;
+ PyStackRef_CLOSE(owner);
stack_pointer[0] = null;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -2481,9 +2481,9 @@
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
attr = PyStackRef_FromPyObjectNew(descr);
+ stack_pointer[-1] = attr;
null = PyStackRef_NULL;
PyStackRef_CLOSE(owner);
- stack_pointer[-1] = attr;
break;
}
@@ -2497,9 +2497,9 @@
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
attr = PyStackRef_FromPyObjectNew(descr);
+ stack_pointer[-1] = attr;
null = PyStackRef_NULL;
PyStackRef_CLOSE(owner);
- stack_pointer[-1] = attr;
stack_pointer[0] = null;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -3437,8 +3437,8 @@
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
attr = PyStackRef_FromPyObjectNew(descr);
- self = owner;
stack_pointer[-1] = attr;
+ self = owner;
stack_pointer[0] = self;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -3458,8 +3458,8 @@
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
attr = PyStackRef_FromPyObjectNew(descr);
- self = owner;
stack_pointer[-1] = attr;
+ self = owner;
stack_pointer[0] = self;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -3523,8 +3523,8 @@
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
attr = PyStackRef_FromPyObjectNew(descr);
- self = owner;
stack_pointer[-1] = attr;
+ self = owner;
stack_pointer[0] = self;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -3546,8 +3546,10 @@
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
maybe_self = PyStackRef_FromPyObjectNew(self);
+ stack_pointer[-1 - oparg] = maybe_self;
PyObject *method = ((PyMethodObject *)callable_o)->im_func;
func = PyStackRef_FromPyObjectNew(method);
+ stack_pointer[-2 - oparg] = func;
/* Make sure that callable and all args are in memory */
args[-2] = func;
args[-1] = maybe_self;
@@ -3557,8 +3559,6 @@
func = callable;
maybe_self = self_or_null;
}
- stack_pointer[-2 - oparg] = func;
- stack_pointer[-1 - oparg] = maybe_self;
break;
}
@@ -3666,11 +3666,11 @@
assert(PyStackRef_IsNull(null));
assert(Py_TYPE(callable_o) == &PyMethod_Type);
self = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self);
+ stack_pointer[-1 - oparg] = self;
method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func);
+ stack_pointer[-2 - oparg] = method;
assert(PyStackRef_FunctionCheck(method));
PyStackRef_CLOSE(callable);
- stack_pointer[-2 - oparg] = method;
- stack_pointer[-1 - oparg] = self;
break;
}
@@ -3763,10 +3763,10 @@
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
STAT_INC(CALL, hit);
self = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self);
+ stack_pointer[-1 - oparg] = self;
func = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func);
- PyStackRef_CLOSE(callable);
stack_pointer[-2 - oparg] = func;
- stack_pointer[-1 - oparg] = self;
+ PyStackRef_CLOSE(callable);
break;
}
@@ -5088,8 +5088,8 @@
_PyStackRef null;
PyObject *ptr = (PyObject *)CURRENT_OPERAND();
value = PyStackRef_FromPyObjectNew(ptr);
- null = PyStackRef_NULL;
stack_pointer[0] = value;
+ null = PyStackRef_NULL;
stack_pointer[1] = null;
stack_pointer += 2;
assert(WITHIN_STACK_BOUNDS());
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 5890fce..31f95eb 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -867,8 +867,10 @@
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
maybe_self = PyStackRef_FromPyObjectNew(self);
+ stack_pointer[-1 - oparg] = maybe_self;
PyObject *method = ((PyMethodObject *)callable_o)->im_func;
func = PyStackRef_FromPyObjectNew(method);
+ stack_pointer[-2 - oparg] = func;
/* Make sure that callable and all args are in memory */
args[-2] = func;
args[-1] = maybe_self;
@@ -1063,12 +1065,12 @@
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
STAT_INC(CALL, hit);
self = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self);
+ stack_pointer[-1 - oparg] = self;
func = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func);
+ stack_pointer[-2 - oparg] = func;
PyStackRef_CLOSE(callable);
}
// flush
- stack_pointer[-2 - oparg] = func;
- stack_pointer[-1 - oparg] = self;
// _CHECK_FUNCTION_VERSION
callable = stack_pointer[-2 - oparg];
{
@@ -1172,13 +1174,13 @@
assert(PyStackRef_IsNull(null));
assert(Py_TYPE(callable_o) == &PyMethod_Type);
self = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_self);
+ stack_pointer[-1 - oparg] = self;
method = PyStackRef_FromPyObjectNew(((PyMethodObject *)callable_o)->im_func);
+ stack_pointer[-2 - oparg] = method;
assert(PyStackRef_FunctionCheck(method));
PyStackRef_CLOSE(callable);
}
// flush
- stack_pointer[-2 - oparg] = method;
- stack_pointer[-1 - oparg] = self;
// _PY_FRAME_GENERAL
args = &stack_pointer[-oparg];
self_or_null = stack_pointer[-1 - oparg];
@@ -2534,6 +2536,7 @@
int matches = PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration);
if (matches) {
value = PyStackRef_FromPyObjectNew(((PyStopIterationObject *)exc_value)->value);
+ stack_pointer[-2] = value;
PyStackRef_CLOSE(sub_iter_st);
PyStackRef_CLOSE(last_sent_val_st);
PyStackRef_CLOSE(exc_value_st);
@@ -2545,7 +2548,6 @@
goto exception_unwind;
}
stack_pointer[-3] = none;
- stack_pointer[-2] = value;
stack_pointer += -1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH();
@@ -3330,8 +3332,8 @@
assert(seq);
assert(it->it_index < PyList_GET_SIZE(seq));
next = PyStackRef_FromPyObjectNew(PyList_GET_ITEM(seq, it->it_index++));
+ stack_pointer[0] = next;
}
- stack_pointer[0] = next;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH();
@@ -3423,8 +3425,8 @@
assert(seq);
assert(it->it_index < PyTuple_GET_SIZE(seq));
next = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq, it->it_index++));
+ stack_pointer[0] = next;
}
- stack_pointer[0] = next;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH();
@@ -3634,8 +3636,10 @@
PyObject *callable_o = PyStackRef_AsPyObjectBorrow(callable);
PyObject *self = ((PyMethodObject *)callable_o)->im_self;
maybe_self = PyStackRef_FromPyObjectNew(self);
+ stack_pointer[-1 - oparg] = maybe_self;
PyObject *method = ((PyMethodObject *)callable_o)->im_func;
func = PyStackRef_FromPyObjectNew(method);
+ stack_pointer[-2 - oparg] = func;
/* Make sure that callable and all args are in memory */
args[-2] = func;
args[-1] = maybe_self;
@@ -4071,6 +4075,7 @@
// _LOAD_CONST
{
value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg));
+ stack_pointer[0] = value;
}
// _RETURN_VALUE_EVENT
val = value;
@@ -4453,10 +4458,10 @@
STAT_INC(LOAD_ATTR, hit);
assert(descr != NULL);
attr = PyStackRef_FromPyObjectNew(descr);
+ stack_pointer[-1] = attr;
null = PyStackRef_NULL;
PyStackRef_CLOSE(owner);
}
- stack_pointer[-1] = attr;
if (oparg & 1) stack_pointer[0] = null;
stack_pointer += (oparg & 1);
assert(WITHIN_STACK_BOUNDS());
@@ -4577,9 +4582,9 @@
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
attr = PyStackRef_FromPyObjectNew(descr);
+ stack_pointer[-1] = attr;
self = owner;
}
- stack_pointer[-1] = attr;
stack_pointer[0] = self;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -4613,9 +4618,9 @@
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
attr = PyStackRef_FromPyObjectNew(descr);
+ stack_pointer[-1] = attr;
self = owner;
}
- stack_pointer[-1] = attr;
stack_pointer[0] = self;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -4661,9 +4666,9 @@
assert(descr != NULL);
assert(_PyType_HasFeature(Py_TYPE(descr), Py_TPFLAGS_METHOD_DESCRIPTOR));
attr = PyStackRef_FromPyObjectNew(descr);
+ stack_pointer[-1] = attr;
self = owner;
}
- stack_pointer[-1] = attr;
stack_pointer[0] = self;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -4739,8 +4744,8 @@
assert(descr != NULL);
PyStackRef_CLOSE(owner);
attr = PyStackRef_FromPyObjectNew(descr);
+ stack_pointer[-1] = attr;
}
- stack_pointer[-1] = attr;
DISPATCH();
}
@@ -4781,8 +4786,8 @@
assert(descr != NULL);
PyStackRef_CLOSE(owner);
attr = PyStackRef_FromPyObjectNew(descr);
+ stack_pointer[-1] = attr;
}
- stack_pointer[-1] = attr;
DISPATCH();
}
@@ -4878,10 +4883,10 @@
STAT_INC(LOAD_ATTR, hit);
null = PyStackRef_NULL;
attr = PyStackRef_FromPyObjectNew(attr_o);
+ stack_pointer[-1] = attr;
PyStackRef_CLOSE(owner);
}
/* Skip 5 cache entries */
- stack_pointer[-1] = attr;
if (oparg & 1) stack_pointer[0] = null;
stack_pointer += (oparg & 1);
assert(WITHIN_STACK_BOUNDS());
@@ -5290,7 +5295,7 @@
"no locals found");
if (true) goto error;
}
- locals = PyStackRef_FromPyObjectNew(l);;
+ locals = PyStackRef_FromPyObjectNew(l);
stack_pointer[0] = locals;
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
@@ -5958,6 +5963,7 @@
// _LOAD_CONST
{
value = PyStackRef_FromPyObjectNew(GETITEM(FRAME_CO_CONSTS, oparg));
+ stack_pointer[0] = value;
}
// _RETURN_VALUE
retval = value;
@@ -7018,10 +7024,10 @@
DEOPT_IF(PyTuple_GET_SIZE(seq_o) != 2, UNPACK_SEQUENCE);
STAT_INC(UNPACK_SEQUENCE, hit);
val0 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 0));
+ stack_pointer[0] = val0;
val1 = PyStackRef_FromPyObjectNew(PyTuple_GET_ITEM(seq_o, 1));
- PyStackRef_CLOSE(seq);
stack_pointer[-1] = val1;
- stack_pointer[0] = val0;
+ PyStackRef_CLOSE(seq);
stack_pointer += 1;
assert(WITHIN_STACK_BOUNDS());
DISPATCH();
diff --git a/Tools/cases_generator/analyzer.py b/Tools/cases_generator/analyzer.py
index f6625a3..3dc9838 100644
--- a/Tools/cases_generator/analyzer.py
+++ b/Tools/cases_generator/analyzer.py
@@ -157,6 +157,7 @@ class Uop:
annotations: list[str]
stack: StackEffect
caches: list[CacheEntry]
+ deferred_refs: dict[lexer.Token, str | None]
body: list[lexer.Token]
properties: Properties
_size: int = -1
@@ -352,6 +353,47 @@ def analyze_caches(inputs: list[parser.InputEffect]) -> list[CacheEntry]:
return [CacheEntry(i.name, int(i.size)) for i in caches]
+def analyze_deferred_refs(node: parser.InstDef) -> dict[lexer.Token, str | None]:
+ """Look for PyStackRef_FromPyObjectNew() calls"""
+
+ def find_assignment_target(idx: int) -> list[lexer.Token]:
+ """Find the tokens that make up the left-hand side of an assignment"""
+ offset = 1
+ for tkn in reversed(node.block.tokens[:idx-1]):
+ if tkn.kind == "SEMI" or tkn.kind == "LBRACE" or tkn.kind == "RBRACE":
+ return node.block.tokens[idx-offset:idx-1]
+ offset += 1
+ return []
+
+ refs: dict[lexer.Token, str | None] = {}
+ for idx, tkn in enumerate(node.block.tokens):
+ if tkn.kind != "IDENTIFIER" or tkn.text != "PyStackRef_FromPyObjectNew":
+ continue
+
+ if idx == 0 or node.block.tokens[idx-1].kind != "EQUALS":
+ raise analysis_error("Expected '=' before PyStackRef_FromPyObjectNew", tkn)
+
+ lhs = find_assignment_target(idx)
+ if len(lhs) == 0:
+ raise analysis_error("PyStackRef_FromPyObjectNew() must be assigned to an output", tkn)
+
+ if lhs[0].kind == "TIMES" or any(t.kind == "ARROW" or t.kind == "LBRACKET" for t in lhs[1:]):
+ # Don't handle: *ptr = ..., ptr->field = ..., or ptr[field] = ...
+ # Assume that they are visible to the GC.
+ refs[tkn] = None
+ continue
+
+ if len(lhs) != 1 or lhs[0].kind != "IDENTIFIER":
+ raise analysis_error("PyStackRef_FromPyObjectNew() must be assigned to an output", tkn)
+
+ name = lhs[0].text
+ if not any(var.name == name for var in node.outputs):
+ raise analysis_error(f"PyStackRef_FromPyObjectNew() must be assigned to an output, not '{name}'", tkn)
+
+ refs[tkn] = name
+
+ return refs
+
def variable_used(node: parser.InstDef, name: str) -> bool:
"""Determine whether a variable with a given name is used in a node."""
return any(
@@ -632,6 +674,7 @@ def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect], uo
annotations=op.annotations,
stack=analyze_stack(op),
caches=analyze_caches(inputs),
+ deferred_refs=analyze_deferred_refs(op),
body=op.block.tokens,
properties=compute_properties(op),
)
@@ -649,6 +692,7 @@ def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect], uo
annotations=op.annotations,
stack=analyze_stack(op, bit),
caches=analyze_caches(inputs),
+ deferred_refs=analyze_deferred_refs(op),
body=op.block.tokens,
properties=properties,
)
@@ -671,6 +715,7 @@ def make_uop(name: str, op: parser.InstDef, inputs: list[parser.InputEffect], uo
annotations=op.annotations,
stack=analyze_stack(op),
caches=analyze_caches(inputs),
+ deferred_refs=analyze_deferred_refs(op),
body=op.block.tokens,
properties=properties,
)
diff --git a/Tools/cases_generator/generators_common.py b/Tools/cases_generator/generators_common.py
index 2a339f8..37060e2 100644
--- a/Tools/cases_generator/generators_common.py
+++ b/Tools/cases_generator/generators_common.py
@@ -6,6 +6,7 @@ from analyzer import (
Uop,
Properties,
StackItem,
+ analysis_error,
)
from cwriter import CWriter
from typing import Callable, Mapping, TextIO, Iterator
@@ -75,6 +76,7 @@ class Emitter:
"DECREF_INPUTS": self.decref_inputs,
"CHECK_EVAL_BREAKER": self.check_eval_breaker,
"SYNC_SP": self.sync_sp,
+ "PyStackRef_FromPyObjectNew": self.py_stack_ref_from_py_object_new,
}
self.out = out
@@ -203,6 +205,29 @@ class Emitter:
if not uop.properties.ends_with_eval_breaker:
self.out.emit_at("CHECK_EVAL_BREAKER();", tkn)
+ def py_stack_ref_from_py_object_new(
+ self,
+ tkn: Token,
+ tkn_iter: Iterator[Token],
+ uop: Uop,
+ stack: Stack,
+ inst: Instruction | None,
+ ) -> None:
+ self.out.emit(tkn)
+ emit_to(self.out, tkn_iter, "SEMI")
+ self.out.emit(";\n")
+
+ target = uop.deferred_refs[tkn]
+ if target is None:
+ # An assignment we don't handle, such as to a pointer or array.
+ return
+
+ # Flush the assignment to the stack. Note that we don't flush the
+ # stack pointer here, and instead are currently relying on initializing
+ # unused portions of the stack to NULL.
+ stack.flush_single_var(self.out, target, uop.stack.outputs)
+
+
def emit_tokens(
self,
uop: Uop,
diff --git a/Tools/cases_generator/lexer.py b/Tools/cases_generator/lexer.py
index 13aee94..d583159 100644
--- a/Tools/cases_generator/lexer.py
+++ b/Tools/cases_generator/lexer.py
@@ -242,7 +242,7 @@ def make_syntax_error(
return SyntaxError(message, (filename, line, column, line_text))
-@dataclass(slots=True)
+@dataclass(slots=True, frozen=True)
class Token:
filename: str
kind: str
diff --git a/Tools/cases_generator/stack.py b/Tools/cases_generator/stack.py
index d2d598a..b44e48a 100644
--- a/Tools/cases_generator/stack.py
+++ b/Tools/cases_generator/stack.py
@@ -257,20 +257,25 @@ 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:
+ 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"
+ )
+
+ @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:
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:
- cast = f"({cast_type})" if var.item.type else ""
- bits = ".bits" if cast and not extract_bits else ""
- if var.condition == "0":
- continue
- 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"
- )
+ 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():
print("base", base_offset, "top", top_offset)
@@ -290,6 +295,26 @@ class Stack:
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:
+ 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):
+ # 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 base_offset.to_c() != top_offset.to_c():
+ print("base", base_offset, "top", top_offset)
+ assert False
+
def peek_offset(self) -> str:
return self.top_offset.to_c()
diff --git a/Tools/cases_generator/tier1_generator.py b/Tools/cases_generator/tier1_generator.py
index 6c13d1f..1ea31a0 100644
--- a/Tools/cases_generator/tier1_generator.py
+++ b/Tools/cases_generator/tier1_generator.py
@@ -93,6 +93,16 @@ def write_uop(
if braces:
emitter.emit("{\n")
emitter.out.emit(stack.define_output_arrays(uop.stack.outputs))
+ outputs: list[Local] = []
+ for var in uop.stack.outputs:
+ if not var.peek:
+ if var.name in locals:
+ local = locals[var.name]
+ elif var.name == "unused":
+ local = Local.unused(var)
+ else:
+ local = Local.local(var)
+ outputs.append(local)
for cache in uop.caches:
if cache.name != "unused":
@@ -109,15 +119,11 @@ def write_uop(
emitter.emit(f"(void){cache.name};\n")
offset += cache.size
emitter.emit_tokens(uop, stack, inst)
- for i, var in enumerate(uop.stack.outputs):
- if not var.peek:
- if var.name in locals:
- local = locals[var.name]
- elif var.name == "unused":
- local = Local.unused(var)
- else:
- local = Local.local(var)
- emitter.emit(stack.push(local))
+ for output in outputs:
+ if output.name in uop.deferred_refs.values():
+ # We've already spilled this when emitting tokens
+ output.cached = False
+ emitter.emit(stack.push(output))
if braces:
emitter.out.start_line()
emitter.emit("}\n")
diff --git a/Tools/cases_generator/tier2_generator.py b/Tools/cases_generator/tier2_generator.py
index 8c212f7..461375c 100644
--- a/Tools/cases_generator/tier2_generator.py
+++ b/Tools/cases_generator/tier2_generator.py
@@ -166,6 +166,13 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> None:
if local.defined:
locals[local.name] = local
emitter.emit(stack.define_output_arrays(uop.stack.outputs))
+ outputs: list[Local] = []
+ for var in uop.stack.outputs:
+ if var.name in locals:
+ local = locals[var.name]
+ else:
+ local = Local.local(var)
+ outputs.append(local)
for cache in uop.caches:
if cache.name != "unused":
if cache.size == 4:
@@ -175,12 +182,11 @@ def write_uop(uop: Uop, emitter: Emitter, stack: Stack) -> None:
cast = f"uint{cache.size*16}_t"
emitter.emit(f"{type}{cache.name} = ({cast})CURRENT_OPERAND();\n")
emitter.emit_tokens(uop, stack, None)
- for i, var in enumerate(uop.stack.outputs):
- if var.name in locals:
- local = locals[var.name]
- else:
- local = Local.local(var)
- emitter.emit(stack.push(local))
+ for output in outputs:
+ if output.name in uop.deferred_refs.values():
+ # We've already spilled this when emitting tokens
+ output.cached = False
+ emitter.emit(stack.push(output))
except StackError as ex:
raise analysis_error(ex.args[0], uop.body[0]) from None