@@ -96,6 +96,10 @@ typedef struct basicblock_ {
96
96
/* b_return is true if a RETURN_VALUE opcode is inserted. */
97
97
unsigned b_return : 1 ;
98
98
unsigned b_reachable : 1 ;
99
+ /* Basic block has no fall through (it ends with a return, raise or jump) */
100
+ unsigned b_nofallthrough : 1 ;
101
+ /* Basic block exits scope (it ends with a return or raise) */
102
+ unsigned b_exit : 1 ;
99
103
/* depth of stack upon entry of block, computed by stackdepth() */
100
104
int b_startdepth ;
101
105
/* instruction offset for block, computed by assemble_jump_offsets() */
@@ -5434,28 +5438,14 @@ struct assembler {
5434
5438
PyObject * a_bytecode ; /* string containing bytecode */
5435
5439
int a_offset ; /* offset into bytecode */
5436
5440
int a_nblocks ; /* number of reachable blocks */
5437
- basicblock * * a_reverse_postorder ; /* list of blocks in dfs postorder */
5438
5441
PyObject * a_lnotab ; /* string containing lnotab */
5439
5442
int a_lnotab_off ; /* offset into lnotab */
5440
5443
int a_prevlineno ; /* lineno of last emitted line in line table */
5441
5444
int a_lineno ; /* lineno of last emitted instruction */
5442
5445
int a_lineno_start ; /* bytecode start offset of current lineno */
5446
+ basicblock * a_entry ;
5443
5447
};
5444
5448
5445
- static void
5446
- dfs (struct compiler * c , basicblock * b , struct assembler * a , int end )
5447
- {
5448
-
5449
- /* There is no real depth-first-search to do here because all the
5450
- * blocks are emitted in topological order already, so we just need to
5451
- * follow the b_next pointers and place them in a->a_reverse_postorder in
5452
- * reverse order and make sure that the first one starts at 0. */
5453
-
5454
- for (a -> a_nblocks = 0 ; b != NULL ; b = b -> b_next ) {
5455
- a -> a_reverse_postorder [a -> a_nblocks ++ ] = b ;
5456
- }
5457
- }
5458
-
5459
5449
Py_LOCAL_INLINE (void )
5460
5450
stackdepth_push (basicblock * * * sp , basicblock * b , int depth )
5461
5451
{
@@ -5553,12 +5543,7 @@ assemble_init(struct assembler *a, int nblocks, int firstlineno)
5553
5543
PyErr_NoMemory ();
5554
5544
return 0 ;
5555
5545
}
5556
- a -> a_reverse_postorder = (basicblock * * )PyObject_Malloc (
5557
- sizeof (basicblock * ) * nblocks );
5558
- if (!a -> a_reverse_postorder ) {
5559
- PyErr_NoMemory ();
5560
- return 0 ;
5561
- }
5546
+
5562
5547
return 1 ;
5563
5548
}
5564
5549
@@ -5567,8 +5552,6 @@ assemble_free(struct assembler *a)
5567
5552
{
5568
5553
Py_XDECREF (a -> a_bytecode );
5569
5554
Py_XDECREF (a -> a_lnotab );
5570
- if (a -> a_reverse_postorder )
5571
- PyObject_Free (a -> a_reverse_postorder );
5572
5555
}
5573
5556
5574
5557
static int
@@ -5697,8 +5680,7 @@ assemble_jump_offsets(struct assembler *a, struct compiler *c)
5697
5680
Replace block pointer with position in bytecode. */
5698
5681
do {
5699
5682
totsize = 0 ;
5700
- for (i = 0 ; i < a -> a_nblocks ; i ++ ) {
5701
- b = a -> a_reverse_postorder [i ];
5683
+ for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
5702
5684
bsize = blocksize (b );
5703
5685
b -> b_offset = totsize ;
5704
5686
totsize += bsize ;
@@ -5966,7 +5948,7 @@ assemble(struct compiler *c, int addNone)
5966
5948
{
5967
5949
basicblock * b , * entryblock ;
5968
5950
struct assembler a ;
5969
- int i , j , nblocks ;
5951
+ int j , nblocks ;
5970
5952
PyCodeObject * co = NULL ;
5971
5953
PyObject * consts = NULL ;
5972
5954
@@ -5997,7 +5979,8 @@ assemble(struct compiler *c, int addNone)
5997
5979
}
5998
5980
if (!assemble_init (& a , nblocks , c -> u -> u_firstlineno ))
5999
5981
goto error ;
6000
- dfs (c , entryblock , & a , nblocks );
5982
+ a .a_entry = entryblock ;
5983
+ a .a_nblocks = nblocks ;
6001
5984
6002
5985
consts = consts_dict_keys_inorder (c -> u -> u_consts );
6003
5986
if (consts == NULL ) {
@@ -6010,9 +5993,8 @@ assemble(struct compiler *c, int addNone)
6010
5993
/* Can't modify the bytecode after computing jump offsets. */
6011
5994
assemble_jump_offsets (& a , c );
6012
5995
6013
- /* Emit code in reverse postorder from dfs. */
6014
- for (i = 0 ; i < a .a_nblocks ; i ++ ) {
6015
- b = a .a_reverse_postorder [i ];
5996
+ /* Emit code. */
5997
+ for (b = entryblock ; b != NULL ; b = b -> b_next ) {
6016
5998
for (j = 0 ; j < b -> b_iused ; j ++ )
6017
5999
if (!assemble_emit (& a , & b -> b_instr [j ]))
6018
6000
goto error ;
@@ -6097,6 +6079,8 @@ fold_tuple_on_constants(struct instr *inst,
6097
6079
return 0 ;
6098
6080
}
6099
6081
6082
+ /* Maximum size of basic block that should be copied in optimizer */
6083
+ #define MAX_COPY_SIZE 4
6100
6084
6101
6085
/* Optimization */
6102
6086
static int
@@ -6238,19 +6222,29 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
6238
6222
6239
6223
case JUMP_ABSOLUTE :
6240
6224
case JUMP_FORWARD :
6225
+ assert (i == bb -> b_iused - 1 );
6241
6226
switch (target -> i_opcode ) {
6242
6227
case JUMP_FORWARD :
6243
6228
inst -> i_target = target -> i_target ;
6244
6229
break ;
6245
6230
case JUMP_ABSOLUTE :
6246
- case RETURN_VALUE :
6247
- case RERAISE :
6248
- case RAISE_VARARGS :
6249
6231
lineno = inst -> i_lineno ;
6250
6232
* inst = * target ;
6251
6233
inst -> i_lineno = lineno ;
6252
6234
break ;
6253
6235
}
6236
+ if (inst -> i_target -> b_exit && inst -> i_target -> b_iused <= MAX_COPY_SIZE ) {
6237
+ basicblock * to_copy = inst -> i_target ;
6238
+ * inst = to_copy -> b_instr [0 ];
6239
+ for (i = 1 ; i < to_copy -> b_iused ; i ++ ) {
6240
+ int index = compiler_next_instr (bb );
6241
+ if (index < 0 ) {
6242
+ return -1 ;
6243
+ }
6244
+ bb -> b_instr [index ] = to_copy -> b_instr [i ];
6245
+ }
6246
+ bb -> b_exit = 1 ;
6247
+ }
6254
6248
break ;
6255
6249
}
6256
6250
}
@@ -6262,65 +6256,75 @@ optimize_basic_block(basicblock *bb, PyObject *consts)
6262
6256
6263
6257
static void
6264
6258
clean_basic_block (basicblock * bb ) {
6265
- /* Remove NOPs and any code following a return or re-raise . */
6259
+ /* Remove NOPs. */
6266
6260
int dest = 0 ;
6267
6261
int prev_lineno = -1 ;
6268
6262
for (int src = 0 ; src < bb -> b_iused ; src ++ ) {
6269
6263
int lineno = bb -> b_instr [src ].i_lineno ;
6270
- switch (bb -> b_instr [src ].i_opcode ) {
6271
- case RETURN_VALUE :
6272
- case RERAISE :
6273
- bb -> b_next = NULL ;
6274
- bb -> b_instr [dest ] = bb -> b_instr [src ];
6275
- dest ++ ;
6276
- goto end ;
6277
- case NOP :
6278
- {
6279
- /* Eliminate no-op if it doesn't have a line number, or
6280
- * if the next instruction has same line number or no line number, or
6281
- * if the previous instruction had the same line number. */
6282
- if (lineno < 0 ) {
6283
- break ;
6284
- }
6285
- if (prev_lineno == lineno ) {
6286
- break ;
6287
- }
6288
- if (src < bb -> b_iused - 1 ) {
6289
- int next_lineno = bb -> b_instr [src + 1 ].i_lineno ;
6290
- if (next_lineno < 0 || next_lineno == lineno ) {
6291
- bb -> b_instr [src + 1 ].i_lineno = lineno ;
6292
- break ;
6293
- }
6294
- }
6264
+ if (bb -> b_instr [src ].i_opcode == NOP ) {
6265
+ /* Eliminate no-op if it doesn't have a line number, or
6266
+ * if the next instruction has same line number or no line number, or
6267
+ * if the previous instruction had the same line number. */
6268
+ if (lineno < 0 ) {
6269
+ continue ;
6295
6270
}
6296
- /* fallthrough */
6297
- default :
6298
- if (dest != src ) {
6299
- bb -> b_instr [dest ] = bb -> b_instr [src ];
6271
+ if (prev_lineno == lineno ) {
6272
+ continue ;
6273
+ }
6274
+ if (src < bb -> b_iused - 1 ) {
6275
+ int next_lineno = bb -> b_instr [src + 1 ].i_lineno ;
6276
+ if (next_lineno < 0 || next_lineno == lineno ) {
6277
+ bb -> b_instr [src + 1 ].i_lineno = lineno ;
6278
+ continue ;
6300
6279
}
6301
- dest ++ ;
6302
- prev_lineno = lineno ;
6303
- break ;
6280
+ }
6281
+ }
6282
+ if (dest != src ) {
6283
+ bb -> b_instr [dest ] = bb -> b_instr [src ];
6304
6284
}
6285
+ dest ++ ;
6286
+ prev_lineno = lineno ;
6305
6287
}
6306
- end :
6307
6288
assert (dest <= bb -> b_iused );
6308
6289
bb -> b_iused = dest ;
6309
6290
}
6310
6291
6292
+ static void
6293
+ normalise_basic_block (basicblock * bb ) {
6294
+ /* Remove any code following a return or re-raise,
6295
+ and mark those blocks as exit and/or nofallthrough. */
6296
+ for (int i = 0 ; i < bb -> b_iused ; i ++ ) {
6297
+ switch (bb -> b_instr [i ].i_opcode ) {
6298
+ case RETURN_VALUE :
6299
+ case RAISE_VARARGS :
6300
+ case RERAISE :
6301
+ bb -> b_iused = i + 1 ;
6302
+ bb -> b_exit = 1 ;
6303
+ bb -> b_nofallthrough = 1 ;
6304
+ return ;
6305
+ case JUMP_ABSOLUTE :
6306
+ case JUMP_FORWARD :
6307
+ bb -> b_iused = i + 1 ;
6308
+ bb -> b_nofallthrough = 1 ;
6309
+ return ;
6310
+ }
6311
+ }
6312
+ }
6313
+
6314
+
6315
+
6311
6316
static int
6312
6317
mark_reachable (struct assembler * a ) {
6313
6318
basicblock * * stack , * * sp ;
6314
6319
sp = stack = (basicblock * * )PyObject_Malloc (sizeof (basicblock * ) * a -> a_nblocks );
6315
6320
if (stack == NULL ) {
6316
6321
return -1 ;
6317
6322
}
6318
- basicblock * entry = a -> a_reverse_postorder [0 ];
6319
- entry -> b_reachable = 1 ;
6320
- * sp ++ = entry ;
6323
+ a -> a_entry -> b_reachable = 1 ;
6324
+ * sp ++ = a -> a_entry ;
6321
6325
while (sp > stack ) {
6322
6326
basicblock * b = * (-- sp );
6323
- if (b -> b_next && b -> b_next -> b_reachable == 0 ) {
6327
+ if (b -> b_next && ! b -> b_nofallthrough && b -> b_next -> b_reachable == 0 ) {
6324
6328
b -> b_next -> b_reachable = 1 ;
6325
6329
* sp ++ = b -> b_next ;
6326
6330
}
@@ -6352,20 +6356,23 @@ mark_reachable(struct assembler *a) {
6352
6356
static int
6353
6357
optimize_cfg (struct assembler * a , PyObject * consts )
6354
6358
{
6355
- for (int i = 0 ; i < a -> a_nblocks ; i ++ ) {
6356
- if (optimize_basic_block (a -> a_reverse_postorder [i ], consts )) {
6359
+ for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6360
+ normalise_basic_block (b );
6361
+ }
6362
+ for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6363
+ if (optimize_basic_block (b , consts )) {
6357
6364
return -1 ;
6358
6365
}
6359
- clean_basic_block (a -> a_reverse_postorder [ i ] );
6360
- assert (a -> a_reverse_postorder [ i ] -> b_reachable == 0 );
6366
+ clean_basic_block (b );
6367
+ assert (b -> b_reachable == 0 );
6361
6368
}
6362
6369
if (mark_reachable (a )) {
6363
6370
return -1 ;
6364
6371
}
6365
6372
/* Delete unreachable instructions */
6366
- for (int i = 0 ; i < a -> a_nblocks ; i ++ ) {
6367
- if (a -> a_reverse_postorder [ i ] -> b_reachable == 0 ) {
6368
- a -> a_reverse_postorder [ i ] -> b_iused = 0 ;
6373
+ for (basicblock * b = a -> a_entry ; b != NULL ; b = b -> b_next ) {
6374
+ if (b -> b_reachable == 0 ) {
6375
+ b -> b_iused = 0 ;
6369
6376
}
6370
6377
}
6371
6378
return 0 ;
0 commit comments