Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 334589f

Browse filesBrowse files
authored
gh-126835: Set location for noped out instructions after constant folding in CFG. (#130109)
1 parent 0f20281 commit 334589f
Copy full SHA for 334589f

File tree

2 files changed

+108
-54
lines changed
Filter options

2 files changed

+108
-54
lines changed

‎Lib/test/test_peepholer.py

Copy file name to clipboardExpand all lines: Lib/test/test_peepholer.py
+77Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,83 @@ def test_folding_subscript(self):
535535
self.assertInBytecode(code, 'BINARY_OP', argval=subscr_argval)
536536
self.check_lnotab(code)
537537

538+
def test_constant_folding_remove_nop_location(self):
539+
sources = [
540+
"""
541+
(-
542+
-
543+
-
544+
1)
545+
""",
546+
547+
"""
548+
(1
549+
+
550+
2
551+
+
552+
3)
553+
""",
554+
555+
"""
556+
(1,
557+
2,
558+
3)[0]
559+
""",
560+
561+
"""
562+
[1,
563+
2,
564+
3]
565+
""",
566+
567+
"""
568+
{1,
569+
2,
570+
3}
571+
""",
572+
573+
"""
574+
1 in [
575+
1,
576+
2,
577+
3
578+
]
579+
""",
580+
581+
"""
582+
1 in {
583+
1,
584+
2,
585+
3
586+
}
587+
""",
588+
589+
"""
590+
for _ in [1,
591+
2,
592+
3]:
593+
pass
594+
""",
595+
596+
"""
597+
for _ in [1,
598+
2,
599+
x]:
600+
pass
601+
""",
602+
603+
"""
604+
for _ in {1,
605+
2,
606+
3}:
607+
pass
608+
"""
609+
]
610+
611+
for source in sources:
612+
code = compile(textwrap.dedent(source), '', 'single')
613+
self.assertNotInBytecode(code, 'NOP')
614+
538615
def test_in_literal_list(self):
539616
def containtest():
540617
return x in [a, b]

‎Python/flowgraph.c

Copy file name to clipboardExpand all lines: Python/flowgraph.c
+31-54Lines changed: 31 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,12 @@ is_jump(cfg_instr *i)
126126
_instr__ptr_->i_oparg = 0; \
127127
} while (0);
128128

129+
#define INSTR_SET_LOC(I, LOC) \
130+
do { \
131+
cfg_instr *_instr__ptr_ = (I); \
132+
_instr__ptr_->i_loc = (LOC); \
133+
} while (0);
134+
129135
/***** Blocks *****/
130136

131137
/* Returns the offset of the next instruction in the current block's
@@ -1382,18 +1388,20 @@ get_constant_sequence(basicblock *bb, int start, int size,
13821388

13831389
/*
13841390
Walk basic block backwards starting from "start" and change "count" number of
1385-
non-NOP instructions to NOP's.
1391+
non-NOP instructions to NOP's and set their location to NO_LOCATION.
13861392
*/
13871393
static void
13881394
nop_out(basicblock *bb, int start, int count)
13891395
{
13901396
assert(start < bb->b_iused);
13911397
for (; count > 0; start--) {
13921398
assert(start >= 0);
1393-
if (bb->b_instr[start].i_opcode == NOP) {
1399+
cfg_instr *instr = &bb->b_instr[start];
1400+
if (instr->i_opcode == NOP) {
13941401
continue;
13951402
}
1396-
INSTR_SET_OP0(&bb->b_instr[start], NOP);
1403+
INSTR_SET_OP0(instr, NOP);
1404+
INSTR_SET_LOC(instr, NO_LOCATION);
13971405
count--;
13981406
}
13991407
}
@@ -1423,7 +1431,7 @@ fold_tuple_of_constants(basicblock *bb, int n, PyObject *consts, PyObject *const
14231431
int index = add_const(newconst, consts, const_cache);
14241432
RETURN_IF_ERROR(index);
14251433
nop_out(bb, n-1, seq_size);
1426-
INSTR_SET_OP1(&bb->b_instr[n], LOAD_CONST, index);
1434+
INSTR_SET_OP1(instr, LOAD_CONST, index);
14271435
return SUCCESS;
14281436
}
14291437

@@ -1479,40 +1487,16 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop,
14791487
else {
14801488
assert(i >= 2);
14811489
assert(instr->i_opcode == BUILD_LIST || instr->i_opcode == BUILD_SET);
1490+
1491+
INSTR_SET_LOC(&bb->b_instr[i-2], instr->i_loc);
1492+
14821493
INSTR_SET_OP1(&bb->b_instr[i-2], instr->i_opcode, 0);
14831494
INSTR_SET_OP1(&bb->b_instr[i-1], LOAD_CONST, index);
14841495
INSTR_SET_OP1(&bb->b_instr[i], instr->i_opcode == BUILD_LIST ? LIST_EXTEND : SET_UPDATE, 1);
14851496
}
14861497
return SUCCESS;
14871498
}
14881499

1489-
/*
1490-
Walk basic block backwards starting from "start" to collect instruction pair
1491-
that loads consts skipping NOP's in between.
1492-
*/
1493-
static bool
1494-
find_load_const_pair(basicblock *bb, int start, cfg_instr **first, cfg_instr **second)
1495-
{
1496-
cfg_instr *second_load_const = NULL;
1497-
while (start >= 0) {
1498-
cfg_instr *inst = &bb->b_instr[start--];
1499-
if (inst->i_opcode == NOP) {
1500-
continue;
1501-
}
1502-
if (!loads_const(inst->i_opcode)) {
1503-
return false;
1504-
}
1505-
if (second_load_const == NULL) {
1506-
second_load_const = inst;
1507-
continue;
1508-
}
1509-
*first = inst;
1510-
*second = second_load_const;
1511-
return true;
1512-
}
1513-
return false;
1514-
}
1515-
15161500
/* Determine opcode & oparg for freshly folded constant. */
15171501
static int
15181502
newop_from_folded(PyObject *newconst, PyObject *consts,
@@ -1534,27 +1518,25 @@ newop_from_folded(PyObject *newconst, PyObject *consts,
15341518
}
15351519

15361520
static int
1537-
optimize_if_const_op(basicblock *bb, int n, PyObject *consts, PyObject *const_cache)
1521+
optimize_if_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache)
15381522
{
1539-
cfg_instr *subscr = &bb->b_instr[n];
1540-
assert(subscr->i_opcode == BINARY_OP);
1541-
if (subscr->i_oparg != NB_SUBSCR) {
1523+
cfg_instr *binop = &bb->b_instr[i];
1524+
assert(binop->i_opcode == BINARY_OP);
1525+
if (binop->i_oparg != NB_SUBSCR) {
15421526
/* TODO: support other binary ops */
15431527
return SUCCESS;
15441528
}
1545-
cfg_instr *arg, *idx;
1546-
if (!find_load_const_pair(bb, n-1, &arg, &idx)) {
1529+
PyObject *pair;
1530+
RETURN_IF_ERROR(get_constant_sequence(bb, i-1, 2, consts, &pair));
1531+
if (pair == NULL) {
15471532
return SUCCESS;
15481533
}
1549-
PyObject *o = NULL, *key = NULL;
1550-
if ((o = get_const_value(arg->i_opcode, arg->i_oparg, consts)) == NULL
1551-
|| (key = get_const_value(idx->i_opcode, idx->i_oparg, consts)) == NULL)
1552-
{
1553-
goto error;
1554-
}
1555-
PyObject *newconst = PyObject_GetItem(o, key);
1556-
Py_DECREF(o);
1557-
Py_DECREF(key);
1534+
assert(PyTuple_CheckExact(pair) && PyTuple_Size(pair) == 2);
1535+
PyObject *left = PyTuple_GET_ITEM(pair, 0);
1536+
PyObject *right = PyTuple_GET_ITEM(pair, 1);
1537+
assert(left != NULL && right != NULL);
1538+
PyObject *newconst = PyObject_GetItem(left, right);
1539+
Py_DECREF(pair);
15581540
if (newconst == NULL) {
15591541
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) {
15601542
return ERROR;
@@ -1564,14 +1546,9 @@ optimize_if_const_op(basicblock *bb, int n, PyObject *consts, PyObject *const_ca
15641546
}
15651547
int newopcode, newoparg;
15661548
RETURN_IF_ERROR(newop_from_folded(newconst, consts, const_cache, &newopcode, &newoparg));
1567-
INSTR_SET_OP1(subscr, newopcode, newoparg);
1568-
INSTR_SET_OP0(arg, NOP);
1569-
INSTR_SET_OP0(idx, NOP);
1549+
nop_out(bb, i-1, 2);
1550+
INSTR_SET_OP1(binop, newopcode, newoparg);
15701551
return SUCCESS;
1571-
error:
1572-
Py_XDECREF(o);
1573-
Py_XDECREF(key);
1574-
return ERROR;
15751552
}
15761553

15771554
#define VISITED (-1)
@@ -2072,7 +2049,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)
20722049
}
20732050
break;
20742051
case BINARY_OP:
2075-
RETURN_IF_ERROR(optimize_if_const_op(bb, i, consts, const_cache));
2052+
RETURN_IF_ERROR(optimize_if_const_binop(bb, i, consts, const_cache));
20762053
break;
20772054
}
20782055
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.