-
-
Notifications
You must be signed in to change notification settings - Fork 32k
gh-126835: Set location for noped out instructions after constant folding in CFG. #130109
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -126,6 +126,12 @@ is_jump(cfg_instr *i) | |||||||||||||||||
_instr__ptr_->i_oparg = 0; \ | ||||||||||||||||||
} while (0); | ||||||||||||||||||
|
||||||||||||||||||
#define INSTR_SET_LOC(I, LOC) \ | ||||||||||||||||||
do { \ | ||||||||||||||||||
cfg_instr *_instr__ptr_ = (I); \ | ||||||||||||||||||
_instr__ptr_->i_loc = (LOC); \ | ||||||||||||||||||
} while (0); | ||||||||||||||||||
|
||||||||||||||||||
/***** Blocks *****/ | ||||||||||||||||||
|
||||||||||||||||||
/* Returns the offset of the next instruction in the current block's | ||||||||||||||||||
|
@@ -1382,18 +1388,22 @@ get_constant_sequence(basicblock *bb, int start, int size, | |||||||||||||||||
|
||||||||||||||||||
/* | ||||||||||||||||||
Walk basic block backwards starting from "start" and change "count" number of | ||||||||||||||||||
non-NOP instructions to NOP's. | ||||||||||||||||||
non-NOP instructions to NOP's and set their i_loc info to "location" if provided. | ||||||||||||||||||
*/ | ||||||||||||||||||
static void | ||||||||||||||||||
nop_out(basicblock *bb, int start, int count) | ||||||||||||||||||
nop_out(basicblock *bb, int start, int count, _Py_SourceLocation *location) | ||||||||||||||||||
{ | ||||||||||||||||||
assert(start < bb->b_iused); | ||||||||||||||||||
for (; count > 0; start--) { | ||||||||||||||||||
assert(start >= 0); | ||||||||||||||||||
if (bb->b_instr[start].i_opcode == NOP) { | ||||||||||||||||||
cfg_instr *instr = &bb->b_instr[start]; | ||||||||||||||||||
if (instr->i_opcode == NOP) { | ||||||||||||||||||
continue; | ||||||||||||||||||
} | ||||||||||||||||||
INSTR_SET_OP0(&bb->b_instr[start], NOP); | ||||||||||||||||||
INSTR_SET_OP0(instr, NOP); | ||||||||||||||||||
if (location != NULL) { | ||||||||||||||||||
INSTR_SET_LOC(instr, *location); | ||||||||||||||||||
} | ||||||||||||||||||
count--; | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
@@ -1422,8 +1432,8 @@ fold_tuple_of_constants(basicblock *bb, int n, PyObject *consts, PyObject *const | |||||||||||||||||
assert(PyTuple_CheckExact(newconst) && PyTuple_GET_SIZE(newconst) == seq_size); | ||||||||||||||||||
int index = add_const(newconst, consts, const_cache); | ||||||||||||||||||
RETURN_IF_ERROR(index); | ||||||||||||||||||
nop_out(bb, n-1, seq_size); | ||||||||||||||||||
INSTR_SET_OP1(&bb->b_instr[n], LOAD_CONST, index); | ||||||||||||||||||
nop_out(bb, n-1, seq_size, &instr->i_loc); | ||||||||||||||||||
INSTR_SET_OP1(instr, LOAD_CONST, index); | ||||||||||||||||||
return SUCCESS; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
|
@@ -1472,7 +1482,7 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, | |||||||||||||||||
} | ||||||||||||||||||
int index = add_const(newconst, consts, const_cache); | ||||||||||||||||||
RETURN_IF_ERROR(index); | ||||||||||||||||||
nop_out(bb, i-1, seq_size); | ||||||||||||||||||
nop_out(bb, i-1, seq_size, &instr->i_loc); | ||||||||||||||||||
if (contains_or_iter) { | ||||||||||||||||||
INSTR_SET_OP1(instr, LOAD_CONST, index); | ||||||||||||||||||
} | ||||||||||||||||||
|
@@ -1486,33 +1496,6 @@ optimize_lists_and_sets(basicblock *bb, int i, int nextop, | |||||||||||||||||
return SUCCESS; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/* | ||||||||||||||||||
Walk basic block backwards starting from "start" to collect instruction pair | ||||||||||||||||||
that loads consts skipping NOP's in between. | ||||||||||||||||||
*/ | ||||||||||||||||||
static bool | ||||||||||||||||||
find_load_const_pair(basicblock *bb, int start, cfg_instr **first, cfg_instr **second) | ||||||||||||||||||
{ | ||||||||||||||||||
cfg_instr *second_load_const = NULL; | ||||||||||||||||||
while (start >= 0) { | ||||||||||||||||||
cfg_instr *inst = &bb->b_instr[start--]; | ||||||||||||||||||
if (inst->i_opcode == NOP) { | ||||||||||||||||||
continue; | ||||||||||||||||||
} | ||||||||||||||||||
if (!loads_const(inst->i_opcode)) { | ||||||||||||||||||
return false; | ||||||||||||||||||
} | ||||||||||||||||||
if (second_load_const == NULL) { | ||||||||||||||||||
second_load_const = inst; | ||||||||||||||||||
continue; | ||||||||||||||||||
} | ||||||||||||||||||
*first = inst; | ||||||||||||||||||
*second = second_load_const; | ||||||||||||||||||
return true; | ||||||||||||||||||
} | ||||||||||||||||||
return false; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/* Determine opcode & oparg for freshly folded constant. */ | ||||||||||||||||||
static int | ||||||||||||||||||
newop_from_folded(PyObject *newconst, PyObject *consts, | ||||||||||||||||||
|
@@ -1534,27 +1517,25 @@ newop_from_folded(PyObject *newconst, PyObject *consts, | |||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
static int | ||||||||||||||||||
optimize_if_const_op(basicblock *bb, int n, PyObject *consts, PyObject *const_cache) | ||||||||||||||||||
optimize_if_const_binop(basicblock *bb, int i, PyObject *consts, PyObject *const_cache) | ||||||||||||||||||
{ | ||||||||||||||||||
cfg_instr *subscr = &bb->b_instr[n]; | ||||||||||||||||||
assert(subscr->i_opcode == BINARY_OP); | ||||||||||||||||||
if (subscr->i_oparg != NB_SUBSCR) { | ||||||||||||||||||
cfg_instr *binop = &bb->b_instr[i]; | ||||||||||||||||||
assert(binop->i_opcode == BINARY_OP); | ||||||||||||||||||
if (binop->i_oparg != NB_SUBSCR) { | ||||||||||||||||||
/* TODO: support other binary ops */ | ||||||||||||||||||
return SUCCESS; | ||||||||||||||||||
} | ||||||||||||||||||
cfg_instr *arg, *idx; | ||||||||||||||||||
if (!find_load_const_pair(bb, n-1, &arg, &idx)) { | ||||||||||||||||||
PyObject *pair; | ||||||||||||||||||
iritkatriel marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||
RETURN_IF_ERROR(get_constant_sequence(bb, i-1, 2, consts, &pair)); | ||||||||||||||||||
if (pair == NULL) { | ||||||||||||||||||
return SUCCESS; | ||||||||||||||||||
} | ||||||||||||||||||
PyObject *o = NULL, *key = NULL; | ||||||||||||||||||
if ((o = get_const_value(arg->i_opcode, arg->i_oparg, consts)) == NULL | ||||||||||||||||||
|| (key = get_const_value(idx->i_opcode, idx->i_oparg, consts)) == NULL) | ||||||||||||||||||
{ | ||||||||||||||||||
goto error; | ||||||||||||||||||
} | ||||||||||||||||||
PyObject *newconst = PyObject_GetItem(o, key); | ||||||||||||||||||
Py_DECREF(o); | ||||||||||||||||||
Py_DECREF(key); | ||||||||||||||||||
assert(PyTuple_CheckExact(pair) && PyTuple_Size(pair) == 2); | ||||||||||||||||||
PyObject *left = PyTuple_GET_ITEM(pair, 0); | ||||||||||||||||||
PyObject *right = PyTuple_GET_ITEM(pair, 1); | ||||||||||||||||||
assert(left != NULL && right != NULL); | ||||||||||||||||||
PyObject *newconst = PyObject_GetItem(left, right); | ||||||||||||||||||
Comment on lines
+1535
to
+1538
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
F438
I this clearer? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For subscript yes, but eventually there will be other binary ops as well. I could apply if you want. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, leave it. |
||||||||||||||||||
Py_DECREF(pair); | ||||||||||||||||||
if (newconst == NULL) { | ||||||||||||||||||
if (PyErr_ExceptionMatches(PyExc_KeyboardInterrupt)) { | ||||||||||||||||||
return ERROR; | ||||||||||||||||||
|
@@ -1564,14 +1545,9 @@ optimize_if_const_op(basicblock *bb, int n, PyObject *consts, PyObject *const_ca | |||||||||||||||||
} | ||||||||||||||||||
int newopcode, newoparg; | ||||||||||||||||||
RETURN_IF_ERROR(newop_from_folded(newconst, consts, const_cache, &newopcode, &newoparg)); | ||||||||||||||||||
INSTR_SET_OP1(subscr, newopcode, newoparg); | ||||||||||||||||||
INSTR_SET_OP0(arg, NOP); | ||||||||||||||||||
INSTR_SET_OP0(idx, NOP); | ||||||||||||||||||
nop_out(bb, i-1, 2, &binop->i_loc); | ||||||||||||||||||
INSTR_SET_OP1(binop, newopcode, newoparg); | ||||||||||||||||||
return SUCCESS; | ||||||||||||||||||
error: | ||||||||||||||||||
Py_XDECREF(o); | ||||||||||||||||||
Py_XDECREF(key); | ||||||||||||||||||
return ERROR; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
#define VISITED (-1) | ||||||||||||||||||
|
@@ -2072,7 +2048,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts) | |||||||||||||||||
} | ||||||||||||||||||
break; | ||||||||||||||||||
case BINARY_OP: | ||||||||||||||||||
RETURN_IF_ERROR(optimize_if_const_op(bb, i, consts, const_cache)); | ||||||||||||||||||
RETURN_IF_ERROR(optimize_if_const_binop(bb, i, consts, const_cache)); | ||||||||||||||||||
break; | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just set the location to
NO_LOCATION
. Then the NOP will be discarded.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, I forgot about
NO_LOCATION
. Thanks!Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we set
NO_LOCATION
, there is 1 test failing in test_dis.cpython/Lib/test/test_dis.py
Lines 891 to 912 in 140e69c
There is a bit of a difference in emitted dis, original is (showing only diff part):
and new dis:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we need to set the locations on the
BUILD_LIST
andLOAD_CONST
(but don't worry about the NOPs).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it would help. I wonder if that's cleaner than the proposed solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Anyway, I've updated the PR.