@@ -510,13 +510,54 @@ static void compress_block(zend_op_array *op_array, zend_basic_block *block)
510
510
}
511
511
}
512
512
513
+ static void replace_predecessor (zend_ssa * ssa , int block_id , int old_pred , int new_pred ) {
514
+ zend_basic_block * block = & ssa -> cfg .blocks [block_id ];
515
+ int * predecessors = & ssa -> cfg .predecessors [block -> predecessor_offset ];
516
+ zend_ssa_phi * phi ;
517
+
518
+ int i ;
519
+ int old_pred_idx = -1 ;
520
+ int new_pred_idx = -1 ;
521
+ for (i = 0 ; i < block -> predecessors_count ; i ++ ) {
522
+ if (predecessors [i ] == old_pred ) {
523
+ old_pred_idx = i ;
524
+ }
525
+ if (predecessors [i ] == new_pred ) {
526
+ new_pred_idx = i ;
527
+ }
528
+ }
529
+
530
+ ZEND_ASSERT (old_pred_idx != -1 );
531
+ if (new_pred_idx == -1 ) {
532
+ /* If the new predecessor doesn't exist yet, simply rewire the old one */
533
+ predecessors [old_pred_idx ] = new_pred ;
534
+ } else {
535
+ /* Otherwise, rewiring the old predecessor would make the new predecessor appear
536
+ * twice, which violates our CFG invariants. Remove the old predecessor instead. */
537
+ memmove (
538
+ predecessors + old_pred_idx ,
539
+ predecessors + old_pred_idx + 1 ,
540
+ sizeof (int ) * (block -> predecessors_count - old_pred_idx - 1 )
541
+ );
542
+
543
+ /* Also remove the corresponding phi node entries */
544
+ for (phi = ssa -> blocks [block_id ].phis ; phi ; phi = phi -> next ) {
545
+ memmove (
546
+ phi -> sources + old_pred_idx ,
547
+ phi -> sources + old_pred_idx + 1 ,
548
+ sizeof (int ) * (block -> predecessors_count - old_pred_idx - 1 )
549
+ );
550
+ }
551
+
552
+ block -> predecessors_count -- ;
553
+ }
554
+ }
555
+
513
556
static void zend_ssa_replace_control_link (zend_op_array * op_array , zend_ssa * ssa , int from , int to , int new_to )
514
557
{
515
558
zend_basic_block * src = & ssa -> cfg .blocks [from ];
516
559
zend_basic_block * old = & ssa -> cfg .blocks [to ];
517
560
zend_basic_block * dst = & ssa -> cfg .blocks [new_to ];
518
- int * predecessors = & ssa -> cfg .predecessors [dst -> predecessor_offset ];
519
- int dup = 0 ;
520
561
int i ;
521
562
zend_op * opline ;
522
563
@@ -585,16 +626,7 @@ static void zend_ssa_replace_control_link(zend_op_array *op_array, zend_ssa *ssa
585
626
}
586
627
}
587
628
588
- for (i = 0 ; i < dst -> predecessors_count ; i ++ ) {
589
- if (dup ) {
590
- predecessors [i ] = predecessors [i + 1 ];
591
- } else if (predecessors [i ] == to ) {
592
- predecessors [i ] = from ;
593
- } else if (predecessors [i ] == from ) {
594
- dup = 1 ;
595
- dst -> predecessors_count -- ;
596
- }
597
- }
629
+ replace_predecessor (ssa , new_to , to , from );
598
630
}
599
631
600
632
static void zend_ssa_unlink_block (zend_op_array * op_array , zend_ssa * ssa , zend_basic_block * block , int block_num )
0 commit comments