@@ -749,16 +749,31 @@ static int dominates(zend_basic_block *blocks, int a, int b) /* {{{ */
749
749
}
750
750
/* }}} */
751
751
752
+ typedef struct {
753
+ int id ;
754
+ int level ;
755
+ } block_info ;
756
+ static int compare_block_level (const block_info * a , const block_info * b ) {
757
+ return b -> level - a -> level ;
758
+ }
759
+ static void swap_blocks (block_info * a , block_info * b ) {
760
+ block_info tmp = * a ;
761
+ * a = * b ;
762
+ * b = tmp ;
763
+ }
764
+
752
765
int zend_cfg_identify_loops (const zend_op_array * op_array , zend_cfg * cfg , uint32_t * flags ) /* {{{ */
753
766
{
754
- int i , j , k ;
767
+ int i , j , k , n ;
755
768
int depth ;
756
769
zend_basic_block * blocks = cfg -> blocks ;
757
770
int * dj_spanning_tree ;
758
771
zend_worklist work ;
759
772
int flag = ZEND_FUNC_NO_LOOPS ;
773
+ block_info * sorted_blocks ;
760
774
ALLOCA_FLAG (list_use_heap )
761
775
ALLOCA_FLAG (tree_use_heap )
776
+ ALLOCA_FLAG (sorted_blocks_use_heap )
762
777
763
778
ZEND_WORKLIST_ALLOCA (& work , cfg - > blocks_count , list_use_heap );
764
779
dj_spanning_tree = do_alloca (sizeof (int ) * cfg -> blocks_count , tree_use_heap );
@@ -792,64 +807,66 @@ int zend_cfg_identify_loops(const zend_op_array *op_array, zend_cfg *cfg, uint32
792
807
zend_worklist_pop (& work );
793
808
}
794
809
810
+ /* Sort blocks by decreasing level, which is the order in which we want to process them */
811
+ sorted_blocks = do_alloca (sizeof (block_info ) * cfg -> blocks_count , sorted_blocks_use_heap );
812
+ for (i = 0 ; i < cfg -> blocks_count ; i ++ ) {
813
+ sorted_blocks [i ].id = i ;
814
+ sorted_blocks [i ].level = blocks [i ].level ;
815
+ }
816
+ zend_sort (sorted_blocks , cfg -> blocks_count , sizeof (block_info ),
817
+ (compare_func_t ) compare_block_level , (swap_func_t ) swap_blocks );
818
+
795
819
/* Identify loops. See Sreedhar et al, "Identifying Loops Using DJ
796
820
Graphs". */
797
821
798
- for (i = 0 , depth = 0 ; i < cfg -> blocks_count ; i ++ ) {
799
- if (blocks [i ].level > depth ) {
800
- depth = blocks [i ].level ;
801
- }
802
- }
803
- for (; depth >= 0 ; depth -- ) {
804
- for (i = 0 ; i < cfg -> blocks_count ; i ++ ) {
805
- if (blocks [i ].level != depth ) {
822
+ for (n = 0 ; n < cfg -> blocks_count ; n ++ ) {
823
+ i = sorted_blocks [n ].id ;
824
+
825
+ zend_bitset_clear (work .visited , zend_bitset_len (cfg -> blocks_count ));
826
+ for (j = 0 ; j < blocks [i ].predecessors_count ; j ++ ) {
827
+ int pred = cfg -> predecessors [blocks [i ].predecessor_offset + j ];
828
+
829
+ /* A join edge is one for which the predecessor does not
830
+ immediately dominate the successor. */
831
+ if (blocks [i ].idom == pred ) {
806
832
continue ;
807
833
}
808
- zend_bitset_clear (work .visited , zend_bitset_len (cfg -> blocks_count ));
809
- for (j = 0 ; j < blocks [i ].predecessors_count ; j ++ ) {
810
- int pred = cfg -> predecessors [blocks [i ].predecessor_offset + j ];
811
834
812
- /* A join edge is one for which the predecessor does not
813
- immediately dominate the successor. */
814
- if (blocks [i ].idom == pred ) {
815
- continue ;
816
- }
817
-
818
- /* In a loop back-edge (back-join edge), the successor dominates
819
- the predecessor. */
820
- if (dominates (blocks , i , pred )) {
821
- blocks [i ].flags |= ZEND_BB_LOOP_HEADER ;
822
- flag &= ~ZEND_FUNC_NO_LOOPS ;
823
- zend_worklist_push (& work , pred );
824
- } else {
825
- /* Otherwise it's a cross-join edge. See if it's a branch
826
- to an ancestor on the dominator spanning tree. */
827
- int dj_parent = pred ;
828
- while (dj_parent >= 0 ) {
829
- if (dj_parent == i ) {
830
- /* An sp-back edge: mark as irreducible. */
831
- blocks [i ].flags |= ZEND_BB_IRREDUCIBLE_LOOP ;
832
- flag |= ZEND_FUNC_IRREDUCIBLE ;
833
- flag &= ~ZEND_FUNC_NO_LOOPS ;
834
- break ;
835
- } else {
836
- dj_parent = dj_spanning_tree [dj_parent ];
837
- }
835
+ /* In a loop back-edge (back-join edge), the successor dominates
836
+ the predecessor. */
837
+ if (dominates (blocks , i , pred )) {
838
+ blocks [i ].flags |= ZEND_BB_LOOP_HEADER ;
839
+ flag &= ~ZEND_FUNC_NO_LOOPS ;
840
+ zend_worklist_push (& work , pred );
841
+ } else {
842
+ /* 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 ];
838
854
}
839
855
}
840
856
}
841
- while ( zend_worklist_len ( & work )) {
842
- j = zend_worklist_pop ( & work );
843
- if ( blocks [ j ]. loop_header < 0 && j != i ) {
844
- blocks [j ].loop_header = i ;
845
- for ( k = 0 ; k < blocks [j ].predecessors_count ; k ++ ) {
846
- zend_worklist_push ( & work , cfg -> predecessors [ blocks [j ].predecessor_offset + k ]);
847
- }
857
+ }
858
+ while ( zend_worklist_len ( & work )) {
859
+ j = zend_worklist_pop ( & work );
860
+ if ( blocks [j ].loop_header < 0 && j ! = i ) {
861
+ blocks [j ].loop_header = i ;
862
+ for ( k = 0 ; k < blocks [j ].predecessors_count ; k ++ ) {
863
+ zend_worklist_push ( & work , cfg -> predecessors [ blocks [ j ]. predecessor_offset + k ]);
848
864
}
849
865
}
850
866
}
851
867
}
852
868
869
+ free_alloca (sorted_blocks , sorted_blocks_use_heap );
853
870
free_alloca (dj_spanning_tree , tree_use_heap );
854
871
ZEND_WORKLIST_FREE_ALLOCA (& work , list_use_heap );
855
872
* flags |= flag ;
0 commit comments