@@ -765,9 +765,9 @@ static void swap_blocks(block_info *a, block_info *b) {
765
765
int zend_cfg_identify_loops (const zend_op_array * op_array , zend_cfg * cfg , uint32_t * flags ) /* {{{ */
766
766
{
767
767
int i , j , k , n ;
768
- int depth ;
768
+ int depth , time ;
769
769
zend_basic_block * blocks = cfg -> blocks ;
770
- int * dj_spanning_tree ;
770
+ int * entry_times , * exit_times ;
771
771
zend_worklist work ;
772
772
int flag = ZEND_FUNC_NO_LOOPS ;
773
773
block_info * sorted_blocks ;
@@ -776,19 +776,24 @@ int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32
776
776
ALLOCA_FLAG (sorted_blocks_use_heap )
777
777
778
778
ZEND_WORKLIST_ALLOCA (& work , cfg - > blocks_count , list_use_heap );
779
- dj_spanning_tree = do_alloca (sizeof (int ) * cfg -> blocks_count , tree_use_heap );
780
779
781
- for (i = 0 ; i < cfg -> blocks_count ; i ++ ) {
782
- dj_spanning_tree [i ] = -1 ;
783
- }
780
+ /* We don't materialize the DJ spanning tree explicitly, as we are only interested in ancestor
781
+ * querties. These are implemented by checking entry/exit times of the DFS search. */
782
+ entry_times = do_alloca (2 * sizeof (int ) * cfg -> blocks_count , tree_use_heap );
783
+ exit_times = entry_times + cfg -> blocks_count ;
784
+ memset (entry_times , -1 , 2 * sizeof (int ) * cfg -> blocks_count );
785
+
784
786
zend_worklist_push (& work , 0 );
787
+ time = 0 ;
785
788
while (zend_worklist_len (& work )) {
786
789
next :
787
790
i = zend_worklist_peek (& work );
791
+ if (entry_times [i ] == -1 ) {
792
+ entry_times [i ] = time ++ ;
793
+ }
788
794
/* Visit blocks immediately dominated by i. */
789
795
for (j = blocks [i ].children ; j >= 0 ; j = blocks [j ].next_child ) {
790
796
if (zend_worklist_push (& work , j )) {
791
- dj_spanning_tree [j ] = i ;
792
797
goto next ;
793
798
}
794
799
}
@@ -800,10 +805,10 @@ int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32
800
805
} else if (blocks [succ ].idom == i ) {
801
806
continue ;
802
807
} else if (zend_worklist_push (& work , succ )) {
803
- dj_spanning_tree [succ ] = i ;
804
808
goto next ;
805
809
}
806
810
}
811
+ exit_times [i ] = time ++ ;
807
812
zend_worklist_pop (& work );
808
813
}
809
814
@@ -840,18 +845,11 @@ int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32
840
845
zend_worklist_push (& work , pred );
841
846
} else {
842
847
/* Otherwise it's a cross-join edge. See if it's a branch
843
- to an ancestor on the dominator spanning tree. */
844
- int dj_parent = pred ;
845
- while (dj_parent >= 0 ) {
846
- if (dj_parent == i ) {
847
- /* An sp-back edge: mark as irreducible. */
848
- blocks [i ].flags |= ZEND_BB_IRREDUCIBLE_LOOP ;
849
- flag |= ZEND_FUNC_IRREDUCIBLE ;
850
- flag &= ~ZEND_FUNC_NO_LOOPS ;
851
- break ;
852
- } else {
853
- dj_parent = dj_spanning_tree [dj_parent ];
854
- }
848
+ to an ancestor on the DJ spanning tree. */
849
+ if (entry_times [pred ] > entry_times [i ] && exit_times [pred ] < exit_times [i ]) {
850
+ blocks [i ].flags |= ZEND_BB_IRREDUCIBLE_LOOP ;
851
+ flag |= ZEND_FUNC_IRREDUCIBLE ;
852
+ flag &= ~ZEND_FUNC_NO_LOOPS ;
855
853
}
856
854
}
857
855
}
@@ -867,7 +865,7 @@ int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32
867
865
}
868
866
869
867
free_alloca (sorted_blocks , sorted_blocks_use_heap );
870
- free_alloca (dj_spanning_tree , tree_use_heap );
868
+ free_alloca (entry_times , tree_use_heap );
871
869
ZEND_WORKLIST_FREE_ALLOCA (& work , list_use_heap );
872
870
* flags |= flag ;
873
871
0 commit comments