Skip to content

Commit a0b5616

Browse files
committed
implement constant intrinsic list to tuple folding
1 parent f68aa92 commit a0b5616

File tree

1 file changed

+93
-2
lines changed

1 file changed

+93
-2
lines changed

Python/flowgraph.c

Lines changed: 93 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,93 @@ fold_tuple_of_constants(basicblock *bb, int i, PyObject *consts, PyObject *const
14521452
return SUCCESS;
14531453
}
14541454

1455+
/* Replace:
1456+
BUILD_LIST 0
1457+
LOAD_CONST c1
1458+
LIST_APPEND
1459+
LOAD_CONST c2
1460+
LIST_APPEND
1461+
...
1462+
LOAD_CONST cN
1463+
LIST_APPEND
1464+
CALL_INTRINSIC_1 INTRINSIC_LIST_TO_TUPLE
1465+
with:
1466+
LOAD_CONST (c1, c2, ... cN)
1467+
*/
1468+
static int
1469+
fold_constant_intrinsic_list_to_tuple(basicblock *bb, int i,
1470+
PyObject *consts, PyObject *const_cache)
1471+
{
1472+
assert(PyDict_CheckExact(const_cache));
1473+
assert(PyList_CheckExact(consts));
1474+
assert(i >= 0 && i < bb->b_iused);
1475+
cfg_instr *intrinsic = &bb->b_instr[i];
1476+
assert(
1477+
intrinsic->i_opcode == CALL_INTRINSIC_1 &&
1478+
intrinsic->i_oparg == INTRINSIC_LIST_TO_TUPLE
1479+
);
1480+
1481+
PyObject *list = PyList_New(0);
1482+
if (list == NULL) {
1483+
return ERROR;
1484+
}
1485+
1486+
bool expect_append = true;
1487+
1488+
for (int pos = i-1; pos >= 0; pos--) {
1489+
cfg_instr *instr = &bb->b_instr[pos];
1490+
1491+
if (instr->i_opcode == NOP) {
1492+
continue;
1493+
}
1494+
1495+
if (instr->i_opcode == BUILD_LIST && instr->i_oparg == 0) {
1496+
if (!expect_append) {
1497+
/* Not a sequence start */
1498+
goto exit;
1499+
}
1500+
/* Sequence start, we are done. */
1501+
if (PyList_Reverse(list) < 0) {
1502+
goto error;
1503+
}
1504+
PyObject *newconst = PyList_AsTuple(list);
1505+
if (newconst == NULL) {
1506+
goto error;
1507+
}
1508+
Py_DECREF(list);
1509+
int nops = (int)PyTuple_Size(newconst) * 2 + 1;
1510+
nop_out(bb, i-1, nops);
1511+
return instr_make_load_const(intrinsic, newconst, consts, const_cache);
1512+
}
1513+
1514+
if (expect_append) {
1515+
if (!(instr->i_opcode == LIST_APPEND && instr->i_oparg == 1)) {
1516+
goto exit;
1517+
}
1518+
}
1519+
else {
1520+
if (!loads_const(instr->i_opcode)) {
1521+
goto exit;
1522+
}
1523+
PyObject *constant = get_const_value(instr->i_opcode, instr->i_oparg, consts);
1524+
int r = PyList_Append(list, constant);
1525+
Py_DECREF(constant);
1526+
if (r < 0) {
1527+
goto error;
1528+
}
1529+
}
1530+
1531+
expect_append = !expect_append;
1532+
}
1533+
1534+
exit:
1535+
Py_DECREF(list);
1536+
return SUCCESS;
1537+
error:
1538+
Py_DECREF(list);
1539+
return ERROR;
1540+
}
1541+
14551542
#define MIN_CONST_SEQUENCE_SIZE 3
14561543
/*
14571544
Optimize lists and sets for:
@@ -2295,8 +2382,12 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
22952382
break;
22962383
case CALL_INTRINSIC_1:
22972384
// for _ in (*foo, *bar) -> for _ in [*foo, *bar]
2298-
if (oparg == INTRINSIC_LIST_TO_TUPLE && nextop == GET_ITER) {
2299-
INSTR_SET_OP0(inst, NOP);
2385+
if (oparg == INTRINSIC_LIST_TO_TUPLE) {
2386+
if (nextop == GET_ITER) {
2387+
INSTR_SET_OP0(inst, NOP);
2388+
} else {
2389+
fold_constant_intrinsic_list_to_tuple(bb, i, consts, const_cache);
2390+
}
23002391
}
23012392
else if (oparg == INTRINSIC_UNARY_POSITIVE) {
23022393
RETURN_IF_ERROR(fold_const_unaryop(bb, i, consts, const_cache));

0 commit comments

Comments
 (0)