Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 17 additions & 20 deletions Python/bytecodes.c
Original file line numberDiff line numberDiff line change
Expand Up@@ -859,6 +859,13 @@ dummy_func(
}
}

family(unpack_sequence, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = {
UNPACK_SEQUENCE,
UNPACK_SEQUENCE_TWO_TUPLE,
UNPACK_SEQUENCE_TUPLE,
UNPACK_SEQUENCE_LIST,
};

inst(UNPACK_SEQUENCE, (unused/1, seq -- unused[oparg])) {
#if ENABLE_SPECIALIZATION
_PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr;
Expand All@@ -877,43 +884,36 @@ dummy_func(
ERROR_IF(res == 0, error);
}

inst(UNPACK_SEQUENCE_TWO_TUPLE, (unused/1, seq -- v1, v0)) {
inst(UNPACK_SEQUENCE_TWO_TUPLE, (unused/1, seq -- values[oparg])) {
DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE);
DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE);
assert(oparg == 2);
STAT_INC(UNPACK_SEQUENCE, hit);
v1 = Py_NewRef(PyTuple_GET_ITEM(seq, 1));
v0 = Py_NewRef(PyTuple_GET_ITEM(seq, 0));
values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1));
values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0));
Py_DECREF(seq);
}

// stack effect: (__0 -- __array[oparg])
inst(UNPACK_SEQUENCE_TUPLE) {
PyObject *seq = TOP();
inst(UNPACK_SEQUENCE_TUPLE, (unused/1, seq -- values[oparg])) {
DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE);
DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE);
STAT_INC(UNPACK_SEQUENCE, hit);
STACK_SHRINK(1);
PyObject **items = _PyTuple_ITEMS(seq);
while (oparg--) {
PUSH(Py_NewRef(items[oparg]));
for (int i = oparg; --i >= 0; ) {
*values++ = Py_NewRef(items[i]);
}
Py_DECREF(seq);
JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
}

// stack effect: (__0 -- __array[oparg])
inst(UNPACK_SEQUENCE_LIST) {
PyObject *seq = TOP();
inst(UNPACK_SEQUENCE_LIST, (unused/1, seq -- values[oparg])) {
DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE);
DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE);
STAT_INC(UNPACK_SEQUENCE, hit);
STACK_SHRINK(1);
PyObject **items = _PyList_ITEMS(seq);
while (oparg--) {
PUSH(Py_NewRef(items[oparg]));
for (int i = oparg; --i >= 0; ) {
*values++ = Py_NewRef(items[i]);
}
Py_DECREF(seq);
JUMPBY(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE);
}

inst(UNPACK_EX, (seq -- unused[oparg & 0xFF], unused, unused[oparg >> 8])) {
Expand DownExpand Up@@ -3168,6 +3168,3 @@ family(call, INLINE_CACHE_ENTRIES_CALL) = {
CALL_NO_KW_METHOD_DESCRIPTOR_O, CALL_NO_KW_STR_1, CALL_NO_KW_TUPLE_1,
CALL_NO_KW_TYPE_1 };
family(store_fast) = { STORE_FAST, STORE_FAST__LOAD_FAST, STORE_FAST__STORE_FAST };
family(unpack_sequence, INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE) = {
UNPACK_SEQUENCE, UNPACK_SEQUENCE_LIST,
UNPACK_SEQUENCE_TUPLE, UNPACK_SEQUENCE_TWO_TUPLE };
38 changes: 21 additions & 17 deletions Python/generated_cases.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions Python/opcode_metadata.h
Original file line numberDiff line numberDiff line change
Expand Up@@ -125,9 +125,9 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
case UNPACK_SEQUENCE_TWO_TUPLE:
return 1;
case UNPACK_SEQUENCE_TUPLE:
return -1;
return 1;
case UNPACK_SEQUENCE_LIST:
return -1;
return 1;
case UNPACK_EX:
return 1;
case STORE_ATTR:
Expand DownExpand Up@@ -469,11 +469,11 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
case UNPACK_SEQUENCE:
return oparg;
case UNPACK_SEQUENCE_TWO_TUPLE:
return 2;
return oparg;
case UNPACK_SEQUENCE_TUPLE:
return -1;
return oparg;
case UNPACK_SEQUENCE_LIST:
return -1;
return oparg;
case UNPACK_EX:
return (oparg & 0xFF) + (oparg >> 8) + 1;
case STORE_ATTR:
Expand DownExpand Up@@ -760,9 +760,9 @@ struct opcode_metadata {
[STORE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[DELETE_NAME] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[UNPACK_SEQUENCE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC },
[UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IXC },
[UNPACK_SEQUENCE_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[UNPACK_SEQUENCE_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[UNPACK_SEQUENCE_TWO_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC },
[UNPACK_SEQUENCE_TUPLE] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC },
[UNPACK_SEQUENCE_LIST] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC },
[UNPACK_EX] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
[STORE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IBC000 },
[DELETE_ATTR] = { DIR_NONE, DIR_NONE, DIR_NONE, true, INSTR_FMT_IB },
Expand Down
25 changes: 18 additions & 7 deletions Tools/cases_generator/generate_cases.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -180,11 +180,8 @@ def assign(self, dst: StackEffect, src: StackEffect):
stmt = f"if ({src.cond}) {{ {stmt} }}"
self.emit(stmt)
elif m := re.match(r"^&PEEK\(.*\)$", dst.name):
# NOTE: MOVE_ITEMS() does not actually exist.
# The only supported output array forms are:
# - unused[...]
# - X[...] where X[...] matches an input array exactly
self.emit(f"MOVE_ITEMS({dst.name}, {src.name}, {src.size});")
# The user code is responsible for writing to the output array.
pass
elif m := re.match(r"^REG\(oparg(\d+)\)$", dst.name):
self.emit(f"Py_XSETREF({dst.name}, {cast}{src.name});")
else:
Expand DownExpand Up@@ -309,10 +306,24 @@ def write(self, out: Formatter) -> None:
out.declare(ieffect, src)

# Write output stack effect variable declarations
isize = string_effect_size(list_effect_size(self.input_effects))
input_names = {ieffect.name for ieffect in self.input_effects}
for oeffect in self.output_effects:
for i, oeffect in enumerate(self.output_effects):
if oeffect.name not in input_names:
out.declare(oeffect, None)
if oeffect.size:
osize = string_effect_size(
list_effect_size([oeff for oeff in self.output_effects[:i]])
)
offset = "stack_pointer"
if isize != osize:
if isize != "0":
offset += f" - ({isize})"
if osize != "0":
offset += f" + {osize}"
src = StackEffect(offset, "PyObject **")
out.declare(oeffect, src)
else:
out.declare(oeffect, None)

# out.emit(f"JUMPBY(OPSIZE({self.inst.name}) - 1);")

Expand Down
19 changes: 8 additions & 11 deletions Tools/cases_generator/test_generator.py
Original file line numberDiff line numberDiff line change
Expand Up@@ -424,20 +424,18 @@ def test_array_input():

def test_array_output():
input = """
inst(OP, (-- below, values[oparg*3], above)) {
spam();
inst(OP, (unused, unused -- below, values[oparg*3], above)) {
spam(values, oparg);
}
"""
output = """
TARGET(OP) {
PyObject *below;
PyObject **values;
PyObject **values = stack_pointer - (2) + 1;
PyObject *above;
spam();
STACK_GROW(2);
spam(values, oparg);
STACK_GROW(oparg*3);
POKE(1, above);
MOVE_ITEMS(&PEEK(1 + oparg*3), values, oparg*3);
POKE(2 + oparg*3, below);
DISPATCH();
}
Expand All@@ -446,18 +444,17 @@ def test_array_output():

def test_array_input_output():
input = """
inst(OP, (below, values[oparg] -- values[oparg], above)) {
spam();
inst(OP, (values[oparg] -- values[oparg], above)) {
spam(values, oparg);
}
"""
output = """
TARGET(OP) {
PyObject **values = &PEEK(oparg);
PyObject *below = PEEK(1 + oparg);
PyObject *above;
spam();
spam(values, oparg);
STACK_GROW(1);
POKE(1, above);
MOVE_ITEMS(&PEEK(1 + oparg), values, oparg);
DISPATCH();
}
"""
Expand Down