@@ -1336,6 +1336,17 @@ add_const(PyObject *newconst, PyObject *consts, PyObject *const_cache)
1336
1336
return (int )index ;
1337
1337
}
1338
1338
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
+
1339
1350
/* Replace LOAD_CONST c1, LOAD_CONST c2 ... LOAD_CONST cn, BUILD_TUPLE n
1340
1351
with LOAD_CONST (c1, c2, ... cn).
1341
1352
The consts table must still be in list form so that the
@@ -1353,10 +1364,8 @@ fold_tuple_on_constants(PyObject *const_cache,
1353
1364
assert (inst [n ].i_opcode == BUILD_TUPLE );
1354
1365
assert (inst [n ].i_oparg == n );
1355
1366
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 ;
1360
1369
}
1361
1370
1362
1371
/* Buildup new tuple of constants */
@@ -1384,6 +1393,56 @@ fold_tuple_on_constants(PyObject *const_cache,
1384
1393
return SUCCESS ;
1385
1394
}
1386
1395
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
+
1387
1446
#define VISITED (-1)
1388
1447
1389
1448
// 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)
1751
1810
}
1752
1811
}
1753
1812
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 ;
1754
1821
case POP_JUMP_IF_NOT_NONE :
1755
1822
case POP_JUMP_IF_NONE :
1756
1823
switch (target -> i_opcode ) {
0 commit comments