gh-114265: move line number propagation before cfg optimization, remo… · python/cpython@7e49f27 (original) (raw)

`@@ -29,6 +29,7 @@ typedef struct _PyCfgInstruction {

`

29

29

`int i_opcode;

`

30

30

`int i_oparg;

`

31

31

`_PyCompilerSrcLocation i_loc;

`

``

32

`+

unsigned i_loc_propagated : 1; /* location was set by propagate_line_numbers */

`

32

33

`struct _PyCfgBasicblock i_target; / target block (if jump instruction) */

`

33

34

`struct _PyCfgBasicblock i_except; / target block when exception is raised */

`

34

35

`} cfg_instr;

`

`@@ -504,6 +505,21 @@ no_redundant_jumps(cfg_builder *g) {

`

504

505

`return true;

`

505

506

`}

`

506

507

``

``

508

`+

static bool

`

``

509

`+

all_exits_have_lineno(basicblock *entryblock) {

`

``

510

`+

for (basicblock *b = entryblock; b != NULL; b = b->b_next) {

`

``

511

`+

for (int i = 0; i < b->b_iused; i++) {

`

``

512

`+

cfg_instr *instr = &b->b_instr[i];

`

``

513

`+

if (instr->i_opcode == RETURN_VALUE) {

`

``

514

`+

if (instr->i_loc.lineno < 0) {

`

``

515

`+

assert(0);

`

``

516

`+

return false;

`

``

517

`+

}

`

``

518

`+

}

`

``

519

`+

}

`

``

520

`+

}

`

``

521

`+

return true;

`

``

522

`+

}

`

507

523

`#endif

`

508

524

``

509

525

`/***** CFG preprocessing (jump targets and exceptions) *****/

`

`@@ -940,7 +956,10 @@ label_exception_targets(basicblock *entryblock) {

`

940

956

`/***** CFG optimizations *****/

`

941

957

``

942

958

`static int

`

943

``

`-

mark_reachable(basicblock *entryblock) {

`

``

959

`+

remove_unreachable(basicblock *entryblock) {

`

``

960

`+

for (basicblock *b = entryblock; b != NULL; b = b->b_next) {

`

``

961

`+

b->b_predecessors = 0;

`

``

962

`+

}

`

944

963

`basicblock **stack = make_cfg_traversal_stack(entryblock);

`

945

964

`if (stack == NULL) {

`

946

965

`return ERROR;

`

`@@ -972,6 +991,14 @@ mark_reachable(basicblock *entryblock) {

`

972

991

` }

`

973

992

` }

`

974

993

`PyMem_Free(stack);

`

``

994

+

``

995

`+

/* Delete unreachable instructions */

`

``

996

`+

for (basicblock *b = entryblock; b != NULL; b = b->b_next) {

`

``

997

`+

if (b->b_predecessors == 0) {

`

``

998

`+

b->b_iused = 0;

`

``

999

`+

b->b_except_handler = 0;

`

``

1000

`+

}

`

``

1001

`+

}

`

975

1002

`return SUCCESS;

`

976

1003

`}

`

977

1004

``

`@@ -1149,13 +1176,15 @@ jump_thread(cfg_instr *inst, cfg_instr *target, int opcode)

`

1149

1176

`assert(is_jump(target));

`

1150

1177

`// bpo-45773: If inst->i_target == target->i_target, then nothing actually

`

1151

1178

`// changes (and we fall into an infinite loop):

`

``

1179

`+

if (inst->i_loc.lineno == -1) assert(inst->i_loc_propagated);

`

``

1180

`+

if (target->i_loc.lineno == -1) assert(target->i_loc_propagated);

`

1152

1181

`if ((inst->i_loc.lineno == target->i_loc.lineno ||

`

1153

``

`-

inst->i_loc.lineno == -1 || target->i_loc.lineno == -1) &&

`

``

1182

`+

inst->i_loc_propagated || target->i_loc_propagated) &&

`

1154

1183

`inst->i_target != target->i_target)

`

1155

1184

` {

`

1156

1185

`inst->i_target = target->i_target;

`

1157

1186

`inst->i_opcode = opcode;

`

1158

``

`-

if (inst->i_loc.lineno == -1) {

`

``

1187

`+

if (inst->i_loc_propagated && !target->i_loc_propagated) {

`

1159

1188

`inst->i_loc = target->i_loc;

`

1160

1189

` }

`

1161

1190

`return true;

`

`@@ -1714,6 +1743,7 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)

`

1714

1743

`return ERROR;

`

1715

1744

`}

`

1716

1745

``

``

1746

`+

static int resolve_line_numbers(cfg_builder *g, int firstlineno);

`

1717

1747

``

1718

1748

`/* Perform optimizations on a control flow graph.

`

1719

1749

` The consts object should still be in list form to allow new constants

`

`@@ -1723,41 +1753,31 @@ optimize_basic_block(PyObject *const_cache, basicblock *bb, PyObject *consts)

`

1723

1753

` NOPs. Later those NOPs are removed.

`

1724

1754

`*/

`

1725

1755

`static int

`

1726

``

`-

optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache)

`

``

1756

`+

optimize_cfg(cfg_builder *g, PyObject *consts, PyObject *const_cache, int firstlineno)

`

1727

1757

`{

`

1728

1758

`assert(PyDict_CheckExact(const_cache));

`

1729

1759

`RETURN_IF_ERROR(check_cfg(g));

`

1730

1760

`for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {

`

1731

1761

`RETURN_IF_ERROR(inline_small_exit_blocks(b));

`

1732

1762

` }

`

``

1763

`+

RETURN_IF_ERROR(remove_unreachable(g->g_entryblock));

`

``

1764

`+

RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));

`

1733

1765

`for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {

`

1734

1766

`RETURN_IF_ERROR(optimize_basic_block(const_cache, b, consts));

`

1735

``

`-

assert(b->b_predecessors == 0);

`

1736

1767

` }

`

1737

1768

`RETURN_IF_ERROR(remove_redundant_nops_and_pairs(g->g_entryblock));

`

1738

1769

`for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {

`

1739

1770

`RETURN_IF_ERROR(inline_small_exit_blocks(b));

`

1740

1771

` }

`

1741

``

`-

RETURN_IF_ERROR(mark_reachable(g->g_entryblock));

`

1742

``

-

1743

``

`-

/* Delete unreachable instructions */

`

1744

``

`-

for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {

`

1745

``

`-

if (b->b_predecessors == 0) {

`

1746

``

`-

b->b_iused = 0;

`

1747

``

`-

b->b_except_handler = 0;

`

1748

``

`-

}

`

1749

``

`-

}

`

1750

``

`-

for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {

`

1751

``

`-

remove_redundant_nops(b);

`

1752

``

`-

}

`

1753

``

`-

RETURN_IF_ERROR(remove_redundant_jumps(g));

`

``

1772

`+

RETURN_IF_ERROR(remove_unreachable(g->g_entryblock));

`

1754

1773

``

1755

``

`-

for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {

`

1756

``

`-

remove_redundant_nops(b);

`

``

1774

`+

for (int n = 0; n < 2; n++) {

`

``

1775

`+

for (basicblock *b = g->g_entryblock; b != NULL; b = b->b_next) {

`

``

1776

`+

remove_redundant_nops(b);

`

``

1777

`+

}

`

``

1778

`+

RETURN_IF_ERROR(remove_redundant_jumps(g));

`

1757

1779

` }

`

1758

1780

``

1759

``

`-

RETURN_IF_ERROR(remove_redundant_jumps(g));

`

1760

``

-

1761

1781

`assert(no_redundant_jumps(g));

`

1762

1782

`return SUCCESS;

`

1763

1783

`}

`

`@@ -2174,7 +2194,13 @@ push_cold_blocks_to_end(cfg_builder *g) {

`

2174

2194

`if (!IS_LABEL(b->b_next->b_label)) {

`

2175

2195

`b->b_next->b_label.id = next_lbl++;

`

2176

2196

` }

`

2177

``

`-

basicblock_addop(explicit_jump, JUMP_NO_INTERRUPT, b->b_next->b_label.id, NO_LOCATION);

`

``

2197

`+

cfg_instr *prev_instr = basicblock_last_instr(b);

`

``

2198

`+

// b cannot be empty because at the end of an exception handler

`

``

2199

`+

// there is always a POP_EXCEPT + RERAISE/RETURN

`

``

2200

`+

assert(prev_instr);

`

``

2201

+

``

2202

`+

basicblock_addop(explicit_jump, JUMP_NO_INTERRUPT, b->b_next->b_label.id,

`

``

2203

`+

prev_instr->i_loc);

`

2178

2204

`explicit_jump->b_cold = 1;

`

2179

2205

`explicit_jump->b_next = b->b_next;

`

2180

2206

`b->b_next = explicit_jump;

`

`@@ -2345,6 +2371,7 @@ propagate_line_numbers(basicblock *entryblock) {

`

2345

2371

`for (int i = 0; i < b->b_iused; i++) {

`

2346

2372

`if (b->b_instr[i].i_loc.lineno < 0) {

`

2347

2373

`b->b_instr[i].i_loc = prev_location;

`

``

2374

`+

b->b_instr[i].i_loc_propagated = 1;

`

2348

2375

` }

`

2349

2376

`else {

`

2350

2377

`prev_location = b->b_instr[i].i_loc;

`

`@@ -2354,6 +2381,7 @@ propagate_line_numbers(basicblock *entryblock) {

`

2354

2381

`if (b->b_next->b_iused > 0) {

`

2355

2382

`if (b->b_next->b_instr[0].i_loc.lineno < 0) {

`

2356

2383

`b->b_next->b_instr[0].i_loc = prev_location;

`

``

2384

`+

b->b_next->b_instr[0].i_loc_propagated = 1;

`

2357

2385

` }

`

2358

2386

` }

`

2359

2387

` }

`

`@@ -2362,46 +2390,18 @@ propagate_line_numbers(basicblock *entryblock) {

`

2362

2390

`if (target->b_predecessors == 1) {

`

2363

2391

`if (target->b_instr[0].i_loc.lineno < 0) {

`

2364

2392

`target->b_instr[0].i_loc = prev_location;

`

``

2393

`+

target->b_instr[0].i_loc_propagated = 1;

`

2365

2394

` }

`

2366

2395

` }

`

2367

2396

` }

`

2368

2397

` }

`

2369

2398

`}

`

2370

2399

``

2371

``

`-

/* Make sure that all returns have a line number, even if early passes

`

2372

``

`-

`

2373

``

`-

`

2374

``

`-

`

2375

``

`-

static void

`

2376

``

`-

guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) {

`

2377

``

`-

int lineno = firstlineno;

`

2378

``

`-

assert(lineno > 0);

`

2379

``

`-

for (basicblock *b = entryblock; b != NULL; b = b->b_next) {

`

2380

``

`-

cfg_instr *last = basicblock_last_instr(b);

`

2381

``

`-

if (last == NULL) {

`

2382

``

`-

continue;

`

2383

``

`-

}

`

2384

``

`-

if (last->i_loc.lineno < 0) {

`

2385

``

`-

if (last->i_opcode == RETURN_VALUE) {

`

2386

``

`-

for (int i = 0; i < b->b_iused; i++) {

`

2387

``

`-

assert(b->b_instr[i].i_loc.lineno < 0);

`

2388

``

-

2389

``

`-

b->b_instr[i].i_loc.lineno = lineno;

`

2390

``

`-

}

`

2391

``

`-

}

`

2392

``

`-

}

`

2393

``

`-

else {

`

2394

``

`-

lineno = last->i_loc.lineno;

`

2395

``

`-

}

`

2396

``

`-

}

`

2397

``

`-

}

`

2398

``

-

2399

2400

`static int

`

2400

2401

`resolve_line_numbers(cfg_builder *g, int firstlineno)

`

2401

2402

`{

`

2402

2403

`RETURN_IF_ERROR(duplicate_exits_without_lineno(g));

`

2403

2404

`propagate_line_numbers(g->g_entryblock);

`

2404

``

`-

guarantee_lineno_for_exits(g->g_entryblock, firstlineno);

`

2405

2405

`return SUCCESS;

`

2406

2406

`}

`

2407

2407

``

`@@ -2417,14 +2417,15 @@ _PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,

`

2417

2417

`RETURN_IF_ERROR(label_exception_targets(g->g_entryblock));

`

2418

2418

``

2419

2419

`/** Optimization **/

`

2420

``

`-

RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache));

`

``

2420

`+

RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache, firstlineno));

`

2421

2421

`RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts));

`

2422

2422

`RETURN_IF_ERROR(

`

2423

2423

`add_checks_for_loads_of_uninitialized_variables(

`

2424

2424

`g->g_entryblock, nlocals, nparams));

`

2425

2425

`insert_superinstructions(g);

`

2426

2426

``

2427

2427

`RETURN_IF_ERROR(push_cold_blocks_to_end(g));

`

``

2428

`+

assert(all_exits_have_lineno(g->g_entryblock));

`

2428

2429

`RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));

`

2429

2430

`return SUCCESS;

`

2430

2431

`}

`