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

`+

`

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;

`