|
6 | 6 | #include "pycore_compile.h"
|
7 | 7 | #include "pycore_intrinsics.h"
|
8 | 8 | #include "pycore_pymem.h" // _PyMem_IsPtrFreed()
|
| 9 | +#include "pycore_long.h" // _PY_IS_SMALL_INT() |
9 | 10 |
|
10 | 11 | #include "pycore_opcode_utils.h"
|
11 | 12 | #include "pycore_opcode_metadata.h" // OPCODE_HAS_ARG, etc
|
@@ -1443,6 +1444,84 @@ optimize_if_const_list_or_set(PyObject *const_cache, cfg_instr* inst, int n, PyO
|
1443 | 1444 | return SUCCESS;
|
1444 | 1445 | }
|
1445 | 1446 |
|
| 1447 | +/* |
| 1448 | + Walk basic block upwards starting from "start" to collect instruction pair |
| 1449 | + that loads consts skipping NOP's in between. |
| 1450 | +*/ |
| 1451 | +static bool |
| 1452 | +find_load_const_pair(basicblock *bb, int start, cfg_instr **first, cfg_instr **second) |
| 1453 | +{ |
| 1454 | + cfg_instr *second_load_const = NULL; |
| 1455 | + while (start >= 0) { |
| 1456 | + cfg_instr *inst = &bb->b_instr[start--]; |
| 1457 | + if (inst->i_opcode == NOP) { |
| 1458 | + continue; |
| 1459 | + } |
| 1460 | + if (!loads_const(inst->i_opcode)) { |
| 1461 | + return false; |
| 1462 | + } |
| 1463 | + if (second_load_const == NULL) { |
| 1464 | + second_load_const = inst; |
| 1465 | + continue; |
| 1466 | + } |
| 1467 | + *first = inst; |
| 1468 | + *second = second_load_const; |
| 1469 | + return true; |
| 1470 | + } |
| 1471 | + return false; |
| 1472 | +} |
| 1473 | + |
| 1474 | +/* Determine opcode & oparg for freshly folded constant. */ |
| 1475 | +static int |
| 1476 | +newop_from_folded(PyObject *newconst, PyObject *consts, |
| 1477 | + PyObject *const_cache, int *newopcode, int *newoparg) |
| 1478 | +{ |
| 1479 | + if (PyLong_CheckExact(newconst)) { |
| 1480 | + int overflow; |
| 1481 | + long val = PyLong_AsLongAndOverflow(newconst, &overflow); |
| 1482 | + if (!overflow && _PY_IS_SMALL_INT(val)) { |
| 1483 | + *newopcode = LOAD_SMALL_INT; |
| 1484 | + *newoparg = val; |
| 1485 | + return SUCCESS; |
| 1486 | + } |
| 1487 | + } |
| 1488 | + *newopcode = LOAD_CONST; |
| 1489 | + *newoparg = add_const(newconst, consts, const_cache); |
| 1490 | + RETURN_IF_ERROR(*newoparg); |
| 1491 | + return SUCCESS; |
| 1492 | +} |
| 1493 | + |
| 1494 | +static int |
| 1495 | +optimize_if_const_subscr(basicblock *bb, int n, PyObject *consts, PyObject *const_cache) |
| 1496 | +{ |
| 1497 | + cfg_instr *subscr = &bb->b_instr[n]; |
| 1498 | + assert(subscr->i_opcode == BINARY_SUBSCR); |
| 1499 | + cfg_instr *arg, *idx; |
| 1500 | + if (!find_load_const_pair(bb, n-1, &arg, &idx)) { |
| 1501 | + return SUCCESS; |
| 1502 | + } |
| 1503 | + PyObject *o, *key; |
| 1504 | + if ((o = get_const_value(arg->i_opcode, arg->i_oparg, consts)) == NULL |
| 1505 | + || (key = get_const_value(idx->i_opcode, idx->i_oparg, consts)) == NULL) |
| 1506 | + { |
| 1507 | + return ERROR; |
| 1508 | + } |
| 1509 | + PyObject *newconst = PyObject_GetItem(o, key); |
| 1510 | + if (newconst == NULL) { |
| 1511 | + if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { |
| 1512 | + return ERROR; |
| 1513 | + } |
| 1514 | + PyErr_Clear(); |
| 1515 | + return SUCCESS; |
| 1516 | + } |
| 1517 | + int newopcode, newoparg; |
| 1518 | + RETURN_IF_ERROR(newop_from_folded(newconst, consts, const_cache, &newopcode, &newoparg)); |
| 1519 | + INSTR_SET_OP1(subscr, newopcode, newoparg); |
| 1520 | + INSTR_SET_OP0(arg, NOP); |
| 1521 | + INSTR_SET_OP0(idx, NOP); |
| 1522 | + return SUCCESS; |
| 1523 | +} |
| 1524 | + |
1446 | 1525 | #define VISITED (-1)
|
1447 | 1526 |
|
1448 | 1527 | // Replace an arbitrary run of SWAPs and NOPs with an optimal one that has the
|
@@ -1948,6 +2027,9 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
|
1948 | 2027 | INSTR_SET_OP0(inst, NOP);
|
1949 | 2028 | }
|
1950 | 2029 | break;
|
| 2030 | + case BINARY_SUBSCR: |
| 2031 | + RETURN_IF_ERROR(optimize_if_const_subscr(bb, i, consts, const_cache)); |
| 2032 | + break; |
1951 | 2033 | }
|
1952 | 2034 | }
|
1953 | 2035 |
|
|
0 commit comments