gh-107901: make compiler inline basic blocks with no line number and … · python/cpython@2091fb2 (original) (raw)
`@@ -212,14 +212,14 @@ basicblock_add_jump(basicblock *b, int opcode, basicblock *target, location loc)
`
212
212
`}
`
213
213
``
214
214
`static inline int
`
215
``
`-
basicblock_append_instructions(basicblock *target, basicblock *source)
`
``
215
`+
basicblock_append_instructions(basicblock *to, basicblock *from)
`
216
216
`{
`
217
``
`-
for (int i = 0; i < source->b_iused; i++) {
`
218
``
`-
int n = basicblock_next_instr(target);
`
``
217
`+
for (int i = 0; i < from->b_iused; i++) {
`
``
218
`+
int n = basicblock_next_instr(to);
`
219
219
`if (n < 0) {
`
220
220
`return ERROR;
`
221
221
` }
`
222
``
`-
target->b_instr[n] = source->b_instr[i];
`
``
222
`+
to->b_instr[n] = from->b_instr[i];
`
223
223
` }
`
224
224
`return SUCCESS;
`
225
225
`}
`
`@@ -292,9 +292,9 @@ static void
`
292
292
`dump_basicblock(const basicblock *b)
`
293
293
`{
`
294
294
`const char *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",
`
296
296
`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);
`
298
298
`if (b->b_instr) {
`
299
299
`int i;
`
300
300
`for (i = 0; i < b->b_iused; i++) {
`
`@@ -1165,15 +1165,26 @@ remove_redundant_jumps(cfg_builder *g) {
`
1165
1165
`return changes;
`
1166
1166
`}
`
1167
1167
``
``
1168
`+
static inline bool
`
``
1169
`+
basicblock_has_no_lineno(basicblock *b) {
`
``
1170
`+
for (int i = 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
+
1168
1178
`/* Maximum size of basic block that should be copied in optimizer */
`
1169
1179
`#define MAX_COPY_SIZE 4
`
1170
1180
``
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
`
1172
1183
` * remove the jump and extend this block with the target.
`
1173
1184
` * Returns 1 if extended, 0 if no change, and -1 on error.
`
1174
1185
` */
`
1175
1186
`static int
`
1176
``
`-
inline_small_exit_blocks(basicblock *bb) {
`
``
1187
`+
basicblock_inline_small_or_no_lineno_blocks(basicblock *bb) {
`
1177
1188
`cfg_instr *last = basicblock_last_instr(bb);
`
1178
1189
`if (last == NULL) {
`
1179
1190
`return 0;
`
`@@ -1182,14 +1193,46 @@ inline_small_exit_blocks(basicblock *bb) {
`
1182
1193
`return 0;
`
1183
1194
` }
`
1184
1195
`basicblock *target = last->i_target;
`
1185
``
`-
if (basicblock_exits_scope(target) && target->b_iused <= MAX_COPY_SIZE) {
`
``
1196
`+
bool small_exit_block = (basicblock_exits_scope(target) &&
`
``
1197
`+
target->b_iused <= MAX_COPY_SIZE);
`
``
1198
`+
bool no_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
`+
int removed_jump_opcode = last->i_opcode;
`
1186
1203
`INSTR_SET_OP0(last, NOP);
`
1187
1204
`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--;
`
1188
1215
`return 1;
`
1189
1216
` }
`
1190
1217
`return 0;
`
1191
1218
`}
`
1192
1219
``
``
1220
`+
static int
`
``
1221
`+
inline_small_or_no_lineno_blocks(basicblock *entryblock) {
`
``
1222
`+
bool changes;
`
``
1223
`+
do {
`
``
1224
`+
changes = false;
`
``
1225
`+
for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
`
``
1226
`+
int res = 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
`+
return changes;
`
``
1234
`+
}
`
``
1235
+
1193
1236
`// Attempt to eliminate jumps to jumps by updating inst to jump to
`
1194
1237
`// target->i_target using the provided opcode. Return whether or not the
`
1195
1238
`// optimization was successful.
`
`@@ -1804,19 +1847,14 @@ optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache, int firstl
`
1804
1847
`{
`
1805
1848
`assert(PyDict_CheckExact(const_cache));
`
1806
1849
`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));
`
1810
1851
`RETURN_IF_ERROR(remove_unreachable(g->g_entryblock));
`
1811
1852
`RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));
`
1812
1853
`RETURN_IF_ERROR(optimize_load_const(const_cache, g, consts));
`
1813
1854
`for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {
`
1814
1855
`RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts));
`
1815
1856
` }
`
1816
1857
`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
``
`-
}
`
1820
1858
`RETURN_IF_ERROR(remove_unreachable(g->g_entryblock));
`
1821
1859
``
1822
1860
`int removed_nops, removed_jumps;
`
`@@ -2333,12 +2371,7 @@ convert_pseudo_ops(cfg_builder *g)
`
2333
2371
`static inline bool
`
2334
2372
`is_exit_or_eval_check_without_lineno(basicblock *b) {
`
2335
2373
`if (basicblock_exits_scope(b) || basicblock_has_eval_break(b)) {
`
2336
``
`-
for (int i = 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
`+
return basicblock_has_no_lineno(b);
`
2342
2375
` }
`
2343
2376
`else {
`
2344
2377
`return false;
`