@@ -1336,6 +1336,17 @@ add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache)
13361336 return (int )index ;
13371337}
13381338
1339+ static bool
1340+ is_constant_sequence (cfg_instr * inst , int n )
1341+ {
1342+ for (int i = 0 ; i < n ; i ++ ) {
1343+ if (!loads_const (inst [i ].i_opcode )) {
1344+ return false;
1345+ }
1346+ }
1347+ return true;
1348+ }
1349+
13391350/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
13401351 with LOAD_CONST (c1, c2, ... cn).
13411352 The consts table must still be in list form so that the
@@ -1353,10 +1364,8 @@ fold_tuple_on_constants(PyObject *const_cache,
13531364 assert (inst [n ].i_opcode == BUILD_TUPLE );
13541365 assert (inst [n ].i_oparg == n );
13551366
1356- for (int i = 0 ; i < n ; i ++ ) {
1357- if (!loads_const (inst [i ].i_opcode )) {
1358- return SUCCESS ;
1359- }
1367+ if (!is_constant_sequence (inst , n )) {
1368+ return SUCCESS ;
13601369 }
13611370
13621371 /* Buildup new tuple of constants */
@@ -1384,6 +1393,56 @@ fold_tuple_on_constants(PyObject *const_cache,
13841393 return SUCCESS ;
13851394}
13861395
1396+ #define MIN_CONST_SEQUENCE_SIZE 3
1397+ /* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cN, BUILD_LIST N
1398+ with BUILD_LIST 0, LOAD_CONST (c1, c2, ... cN), LIST_EXTEND 1,
1399+ or BUILD_SET & SET_UPDATE respectively.
1400+ */
1401+ static int
1402+ optimize_if_const_list_or_set (PyObject * const_cache , cfg_instr * inst , int n , PyObject * consts )
1403+ {
1404+ assert (PyDict_CheckExact (const_cache ));
1405+ assert (PyList_CheckExact (consts ));
1406+ assert (inst [n ].i_oparg == n );
1407+
1408+ int build = inst [n ].i_opcode ;
1409+ assert (build == BUILD_LIST || build == BUILD_SET );
1410+ int extend = build == BUILD_LIST ? LIST_EXTEND : SET_UPDATE ;
1411+
1412+ if (n < MIN_CONST_SEQUENCE_SIZE || !is_constant_sequence (inst , n )) {
1413+ return SUCCESS ;
1414+ }
1415+ PyObject * newconst = PyTuple_New (n );
1416+ if (newconst == NULL ) {
1417+ return ERROR ;
1418+ }
1419+ for (int i = 0 ; i < n ; i ++ ) {
1420+ int op = inst [i ].i_opcode ;
1421+ int arg = inst [i ].i_oparg ;
1422+ PyObject * constant = get_const_value (op , arg , consts );
1423+ if (constant == NULL ) {
1424+ return ERROR ;
1425+ }
1426+ PyTuple_SET_ITEM (newconst , i , constant );
1427+ }
1428+ if (build == BUILD_SET ) {
1429+ PyObject * frozenset = PyFrozenSet_New (newconst );
1430+ if (frozenset == NULL ) {
1431+ return ERROR ;
1432+ }
1433+ Py_SETREF (newconst , frozenset );
1434+ }
1435+ int index = add_const (newconst , consts , const_cache );
1436+ RETURN_IF_ERROR (index );
1437+ INSTR_SET_OP1 (& inst [0 ], build , 0 );
1438+ for (int i = 1 ; i < n - 1 ; i ++ ) {
1439+ INSTR_SET_OP0 (& inst [i ], NOP );
1440+ }
1441+ INSTR_SET_OP1 (& inst [n - 1 ], LOAD_CONST , index );
1442+ INSTR_SET_OP1 (& inst [n ], extend , 1 );
1443+ return SUCCESS ;
1444+ }
1445+
13871446#define VISITED (-1)
13881447
13891448// Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the
@@ -1751,6 +1810,14 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
17511810 }
17521811 }
17531812 break ;
1813+ case BUILD_LIST :
1814+ case BUILD_SET :
1815+ if (i >= oparg ) {
1816+ if (optimize_if_const_list_or_set (const_cache , inst - oparg , oparg , consts ) < 0 ) {
1817+ goto error ;
1818+ }
1819+ }
1820+ break ;
17541821 case POP_JUMP_IF_NOT_NONE :
17551822 case POP_JUMP_IF_NONE :
17561823 switch (target -> i_opcode ) {
0 commit comments