Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commit2091fb2

Browse files
authored
gh-107901: make compiler inline basic blocks with no line number and no fallthrough (#114750)
1 parent41fde89 commit2091fb2

File tree

3 files changed

+108
-39
lines changed

3 files changed

+108
-39
lines changed

‎Lib/test/test_compile.py‎

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1104,6 +1104,17 @@ async def test(aseq):
11041104
code_lines=self.get_code_lines(test.__code__)
11051105
self.assertEqual(expected_lines,code_lines)
11061106

1107+
defcheck_line_numbers(self,code,opnames=None):
1108+
# Check that all instructions whose op matches opnames
1109+
# have a line number. opnames can be a single name, or
1110+
# a sequence of names. If it is None, match all ops.
1111+
1112+
ifisinstance(opnames,str):
1113+
opnames= (opnames, )
1114+
forinstindis.Bytecode(code):
1115+
ifopnamesandinst.opnameinopnames:
1116+
self.assertIsNotNone(inst.positions.lineno)
1117+
11071118
deftest_line_number_synthetic_jump_multiple_predecessors(self):
11081119
deff():
11091120
forxinit:
@@ -1113,25 +1124,52 @@ def f():
11131124
exceptOSError:
11141125
pass
11151126

1116-
# Ensure that all JUMP_BACKWARDs have line number
1117-
code=f.__code__
1118-
forinstindis.Bytecode(code):
1119-
ifinst.opname=='JUMP_BACKWARD':
1120-
self.assertIsNotNone(inst.positions.lineno)
1127+
self.check_line_numbers(f.__code__,'JUMP_BACKWARD')
11211128

1122-
deftest_lineno_of_backward_jump(self):
1129+
deftest_line_number_synthetic_jump_multiple_predecessors_nested(self):
1130+
deff():
1131+
forxinit:
1132+
try:
1133+
X=3
1134+
exceptOSError:
1135+
try:
1136+
ifC3:
1137+
X=4
1138+
exceptOSError:
1139+
pass
1140+
return42
1141+
1142+
self.check_line_numbers(f.__code__,'JUMP_BACKWARD')
1143+
1144+
deftest_line_number_synthetic_jump_multiple_predecessors_more_nested(self):
1145+
deff():
1146+
forxinit:
1147+
try:
1148+
X=3
1149+
exceptOSError:
1150+
try:
1151+
ifC3:
1152+
ifC4:
1153+
X=4
1154+
exceptOSError:
1155+
try:
1156+
ifC3:
1157+
ifC4:
1158+
X=5
1159+
exceptOSError:
1160+
pass
1161+
return42
1162+
1163+
self.check_line_numbers(f.__code__,'JUMP_BACKWARD')
1164+
1165+
deftest_lineno_of_backward_jump_conditional_in_loop(self):
11231166
# Issue gh-107901
11241167
deff():
11251168
foriinx:
11261169
ify:
11271170
pass
11281171

1129-
linenos=list(inst.positions.lineno
1130-
forinstindis.get_instructions(f.__code__)
1131-
ifinst.opname=='JUMP_BACKWARD')
1132-
1133-
self.assertTrue(len(linenos)>0)
1134-
self.assertTrue(all(lisnotNoneforlinlinenos))
1172+
self.check_line_numbers(f.__code__,'JUMP_BACKWARD')
11351173

11361174
deftest_big_dict_literal(self):
11371175
# The compiler has a flushing point in "compiler_dict" that calls compiles

‎Lib/test/test_monitoring.py‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,9 +1466,8 @@ def func():
14661466
('branch','func',4,4),
14671467
('line','func',5),
14681468
('line','meth',1),
1469-
('jump','func',5,5),
1470-
('jump','func',5,'[offset=114]'),
1471-
('branch','func','[offset=120]','[offset=124]'),
1469+
('jump','func',5,'[offset=118]'),
1470+
('branch','func','[offset=122]','[offset=126]'),
14721471
('line','get_events',11)])
14731472

14741473
self.check_events(func,recorders=FLOW_AND_LINE_RECORDERS,expected= [
@@ -1482,9 +1481,8 @@ def func():
14821481
('line','func',5),
14831482
('line','meth',1),
14841483
('return','meth',None),
1485-
('jump','func',5,5),
1486-
('jump','func',5,'[offset=114]'),
1487-
('branch','func','[offset=120]','[offset=124]'),
1484+
('jump','func',5,'[offset=118]'),
1485+
('branch','func','[offset=122]','[offset=126]'),
14881486
('return','func',None),
14891487
('line','get_events',11)])
14901488

‎Python/flowgraph.c‎

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -212,14 +212,14 @@ basicblock_add_jump(basicblock *b, int opcode, basicblock *target, location loc)
212212
}
213213

214214
staticinlineint
215-
basicblock_append_instructions(basicblock*target,basicblock*source)
215+
basicblock_append_instructions(basicblock*to,basicblock*from)
216216
{
217-
for (inti=0;i<source->b_iused;i++) {
218-
intn=basicblock_next_instr(target);
217+
for (inti=0;i<from->b_iused;i++) {
218+
intn=basicblock_next_instr(to);
219219
if (n<0) {
220220
returnERROR;
221221
}
222-
target->b_instr[n]=source->b_instr[i];
222+
to->b_instr[n]=from->b_instr[i];
223223
}
224224
returnSUCCESS;
225225
}
@@ -292,9 +292,9 @@ static void
292292
dump_basicblock(constbasicblock*b)
293293
{
294294
constchar*b_return=basicblock_returns(b) ?"return " :"";
295-
fprintf(stderr,"%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d, %s\n",
295+
fprintf(stderr,"%d: [EH=%d CLD=%d WRM=%d NO_FT=%d %p] used: %d, depth: %d,preds: %d%s\n",
296296
b->b_label.id,b->b_except_handler,b->b_cold,b->b_warm,BB_NO_FALLTHROUGH(b),b,b->b_iused,
297-
b->b_startdepth,b_return);
297+
b->b_startdepth,b->b_predecessors,b_return);
298298
if (b->b_instr) {
299299
inti;
300300
for (i=0;i<b->b_iused;i++) {
@@ -1165,15 +1165,26 @@ remove_redundant_jumps(cfg_builder *g) {
11651165
returnchanges;
11661166
}
11671167

1168+
staticinlinebool
1169+
basicblock_has_no_lineno(basicblock*b) {
1170+
for (inti=0;i<b->b_iused;i++) {
1171+
if (b->b_instr[i].i_loc.lineno >=0) {
1172+
return false;
1173+
}
1174+
}
1175+
return true;
1176+
}
1177+
11681178
/* Maximum size of basic block that should be copied in optimizer */
11691179
#defineMAX_COPY_SIZE 4
11701180

1171-
/* If this block ends with an unconditional jump to a small exit block, then
1181+
/* If this block ends with an unconditional jump to a small exit block or
1182+
* a block that has no line numbers (and no fallthrough), then
11721183
* remove the jump and extend this block with the target.
11731184
* Returns 1 if extended, 0 if no change, and -1 on error.
11741185
*/
11751186
staticint
1176-
inline_small_exit_blocks(basicblock*bb) {
1187+
basicblock_inline_small_or_no_lineno_blocks(basicblock*bb) {
11771188
cfg_instr*last=basicblock_last_instr(bb);
11781189
if (last==NULL) {
11791190
return0;
@@ -1182,14 +1193,46 @@ inline_small_exit_blocks(basicblock *bb) {
11821193
return0;
11831194
}
11841195
basicblock*target=last->i_target;
1185-
if (basicblock_exits_scope(target)&&target->b_iused <=MAX_COPY_SIZE) {
1196+
boolsmall_exit_block= (basicblock_exits_scope(target)&&
1197+
target->b_iused <=MAX_COPY_SIZE);
1198+
boolno_lineno_no_fallthrough= (basicblock_has_no_lineno(target)&&
1199+
!BB_HAS_FALLTHROUGH(target));
1200+
if (small_exit_block||no_lineno_no_fallthrough) {
1201+
assert(is_jump(last));
1202+
intremoved_jump_opcode=last->i_opcode;
11861203
INSTR_SET_OP0(last,NOP);
11871204
RETURN_IF_ERROR(basicblock_append_instructions(bb,target));
1205+
if (no_lineno_no_fallthrough) {
1206+
last=basicblock_last_instr(bb);
1207+
if (IS_UNCONDITIONAL_JUMP_OPCODE(last->i_opcode)&&
1208+
removed_jump_opcode==JUMP)
1209+
{
1210+
/* Make sure we don't lose eval breaker checks */
1211+
last->i_opcode=JUMP;
1212+
}
1213+
}
1214+
target->b_predecessors--;
11881215
return1;
11891216
}
11901217
return0;
11911218
}
11921219

1220+
staticint
1221+
inline_small_or_no_lineno_blocks(basicblock*entryblock) {
1222+
boolchanges;
1223+
do {
1224+
changes= false;
1225+
for (basicblock*b=entryblock;b!=NULL;b=b->b_next) {
1226+
intres=basicblock_inline_small_or_no_lineno_blocks(b);
1227+
RETURN_IF_ERROR(res);
1228+
if (res) {
1229+
changes= true;
1230+
}
1231+
}
1232+
}while(changes);/* every change removes a jump, ensuring convergence */
1233+
returnchanges;
1234+
}
1235+
11931236
// Attempt to eliminate jumps to jumps by updating inst to jump to
11941237
// target->i_target using the provided opcode. Return whether or not the
11951238
// optimization was successful.
@@ -1804,19 +1847,14 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache, int firstl
18041847
{
18051848
assert(PyDict_CheckExact(const_cache));
18061849
RETURN_IF_ERROR(check_cfg(g));
1807-
for (basicblock*b=g->g_entryblock;b!=NULL;b=b->b_next) {
1808-
RETURN_IF_ERROR(inline_small_exit_blocks(b));
1809-
}
1850+
RETURN_IF_ERROR(inline_small_or_no_lineno_blocks(g->g_entryblock));
18101851
RETURN_IF_ERROR(remove_unreachable(g->g_entryblock));
18111852
RETURN_IF_ERROR(resolve_line_numbers(g,firstlineno));
18121853
RETURN_IF_ERROR(optimize_load_const(const_cache,g,consts));
18131854
for (basicblock*b=g->g_entryblock;b!=NULL;b=b->b_next) {
18141855
RETURN_IF_ERROR(optimize_basic_block(const_cache,b,consts));
18151856
}
18161857
RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock));
1817-
for (basicblock*b=g->g_entryblock;b!=NULL;b=b->b_next) {
1818-
RETURN_IF_ERROR(inline_small_exit_blocks(b));
1819-
}
18201858
RETURN_IF_ERROR(remove_unreachable(g->g_entryblock));
18211859

18221860
intremoved_nops,removed_jumps;
@@ -2333,12 +2371,7 @@ convert_pseudo_ops(cfg_builder *g)
23332371
staticinlinebool
23342372
is_exit_or_eval_check_without_lineno(basicblock*b) {
23352373
if (basicblock_exits_scope(b)||basicblock_has_eval_break(b)) {
2336-
for (inti=0;i<b->b_iused;i++) {
2337-
if (b->b_instr[i].i_loc.lineno >=0) {
2338-
return false;
2339-
}
2340-
}
2341-
return true;
2374+
returnbasicblock_has_no_lineno(b);
23422375
}
23432376
else {
23442377
return false;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp