@@ -672,6 +672,11 @@ ZEND_API void zend_cfg_compute_dominators_tree(const zend_op_array *op_array, ze
672672 int blocks_count = cfg -> blocks_count ;
673673 int j , k , changed ;
674674
675+ if (cfg -> blocks_count == 1 ) {
676+ blocks [0 ].level = 0 ;
677+ return ;
678+ }
679+
675680 ALLOCA_FLAG (use_heap )
676681 int * postnum = do_alloca (sizeof (int ) * cfg -> blocks_count , use_heap );
677682 memset (postnum , -1 , sizeof (int ) * cfg -> blocks_count );
@@ -692,16 +697,14 @@ ZEND_API void zend_cfg_compute_dominators_tree(const zend_op_array *op_array, ze
692697 for (k = 0 ; k < blocks [j ].predecessors_count ; k ++ ) {
693698 int pred = cfg -> predecessors [blocks [j ].predecessor_offset + k ];
694699
695- if (idom < 0 ) {
696- if (blocks [pred ].idom >= 0 )
697- idom = pred ;
698- continue ;
699- }
700-
701700 if (blocks [pred ].idom >= 0 ) {
702- while (idom != pred ) {
703- while (postnum [pred ] < postnum [idom ]) pred = blocks [pred ].idom ;
704- while (postnum [idom ] < postnum [pred ]) idom = blocks [idom ].idom ;
701+ if (idom < 0 ) {
702+ idom = pred ;
703+ } else {
704+ while (idom != pred ) {
705+ while (postnum [pred ] < postnum [idom ]) pred = blocks [pred ].idom ;
706+ while (postnum [idom ] < postnum [pred ]) idom = blocks [idom ].idom ;
707+ }
705708 }
706709 }
707710 }
@@ -765,19 +768,6 @@ static bool dominates(zend_basic_block *blocks, int a, int b) /* {{{ */
765768}
766769/* }}} */
767770
768- typedef struct {
769- int id ;
770- int level ;
771- } block_info ;
772- static int compare_block_level (const block_info * a , const block_info * b ) {
773- return b -> level - a -> level ;
774- }
775- static void swap_blocks (block_info * a , block_info * b ) {
776- block_info tmp = * a ;
777- * a = * b ;
778- * b = tmp ;
779- }
780-
781771ZEND_API void zend_cfg_identify_loops (const zend_op_array * op_array , zend_cfg * cfg ) /* {{{ */
782772{
783773 int i , j , k , n ;
@@ -786,17 +776,22 @@ ZEND_API void zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *c
786776 int * entry_times , * exit_times ;
787777 zend_worklist work ;
788778 int flag = ZEND_FUNC_NO_LOOPS ;
789- block_info * sorted_blocks ;
779+ int * sorted_blocks ;
790780 ALLOCA_FLAG (list_use_heap )
791781 ALLOCA_FLAG (tree_use_heap )
792- ALLOCA_FLAG (sorted_blocks_use_heap )
782+
783+ if (cfg - > blocks_count == 1 ) {
784+ cfg -> flags |= flag ;
785+ return ;
786+ }
793787
794788 ZEND_WORKLIST_ALLOCA (& work , cfg -> blocks_count , list_use_heap );
795789
796790 /* We don't materialize the DJ spanning tree explicitly, as we are only interested in ancestor
797791 * queries. These are implemented by checking entry/exit times of the DFS search. */
798- entry_times = do_alloca (2 * sizeof (int ) * cfg -> blocks_count , tree_use_heap );
792+ entry_times = do_alloca (3 * sizeof (int ) * cfg -> blocks_count , tree_use_heap );
799793 exit_times = entry_times + cfg -> blocks_count ;
794+ sorted_blocks = exit_times + cfg -> blocks_count ;
800795 memset (entry_times , -1 , 2 * sizeof (int ) * cfg -> blocks_count );
801796
802797 zend_worklist_push (& work , 0 );
@@ -826,27 +821,35 @@ ZEND_API void zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *c
826821 zend_worklist_pop (& work );
827822 }
828823
829- /* Sort blocks by decreasing level, which is the order in which we want to process them */
830- sorted_blocks = do_alloca (sizeof (block_info ) * cfg -> blocks_count , sorted_blocks_use_heap );
831- for (i = 0 ; i < cfg -> blocks_count ; i ++ ) {
832- sorted_blocks [i ].id = i ;
833- sorted_blocks [i ].level = blocks [i ].level ;
824+ /* Sort blocks by level, which is the opposite order in which we want to process them */
825+ sorted_blocks [0 ] = 0 ;
826+ j = 0 ;
827+ n = 1 ;
828+ while (j != n ) {
829+ i = j ;
830+ j = n ;
831+ for (; i < j ; i ++ ) {
832+ int child ;
833+ for (child = blocks [sorted_blocks [i ]].children ; child >= 0 ; child = blocks [child ].next_child ) {
834+ sorted_blocks [n ++ ] = child ;
835+ }
836+ }
834837 }
835- zend_sort (sorted_blocks , cfg -> blocks_count , sizeof (block_info ),
836- (compare_func_t ) compare_block_level , (swap_func_t ) swap_blocks );
837838
838- /* Identify loops. See Sreedhar et al, "Identifying Loops Using DJ
839- Graphs". */
839+ /* Identify loops. See Sreedhar et al, "Identifying Loops Using DJ Graphs". */
840+ while (n > 0 ) {
841+ i = sorted_blocks [-- n ];
840842
841- for (n = 0 ; n < cfg -> blocks_count ; n ++ ) {
842- i = sorted_blocks [n ].id ;
843+ if (blocks [i ].predecessors_count < 2 ) {
844+ /* loop header has at least two input edges */
845+ continue ;
846+ }
843847
844- zend_bitset_clear (work .visited , zend_bitset_len (cfg -> blocks_count ));
845848 for (j = 0 ; j < blocks [i ].predecessors_count ; j ++ ) {
846849 int pred = cfg -> predecessors [blocks [i ].predecessor_offset + j ];
847850
848851 /* A join edge is one for which the predecessor does not
849- immediately dominate the successor. */
852+ immediately dominate the successor. */
850853 if (blocks [i ].idom == pred ) {
851854 continue ;
852855 }
@@ -856,6 +859,9 @@ ZEND_API void zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *c
856859 if (dominates (blocks , i , pred )) {
857860 blocks [i ].flags |= ZEND_BB_LOOP_HEADER ;
858861 flag &= ~ZEND_FUNC_NO_LOOPS ;
862+ if (!zend_worklist_len (& work )) {
863+ zend_bitset_clear (work .visited , zend_bitset_len (cfg -> blocks_count ));
864+ }
859865 zend_worklist_push (& work , pred );
860866 } else {
861867 /* Otherwise it's a cross-join edge. See if it's a branch
@@ -885,7 +891,6 @@ ZEND_API void zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *c
885891 }
886892 }
887893
888- free_alloca (sorted_blocks , sorted_blocks_use_heap );
889894 free_alloca (entry_times , tree_use_heap );
890895 ZEND_WORKLIST_FREE_ALLOCA (& work , list_use_heap );
891896
0 commit comments