Fast Computation of Strong Control Dependencies

We introduce new algorithms for computing non-termination sensitive control dependence (NTSCD) and decisive order dependence (DOD). These relations on control flow graph vertices have many applications including program slicing and compiler optimizations. Our algorithms are asymptotically faster than the current algorithms. We also show that the original algorithms for computing NTSCD and DOD may produce incorrect results. We implemented the new as well as fixed versions of the original algorithms for the computation of NTSCD and DOD and we experimentally compare their performance and outcome. Our algorithms dramatically outperform the original ones.

Since the 70s, when the first paper about control dependence appeared, there have been invented many different notions of control dependence. The one that is as of today considered as the "classical" control dependence was introduced by Ferrante et al. [1987] more than thirty years ago.
Informally, two statements in a program are control dependent if one controls the execution of the other in some way. This is typically the case for if statements and their bodies, but control dependence can emerge also when a loop infinitely delays the execution of some statement. Consider, for example, the control flow graph of a program in Figure 1. Node controls whether or is going to be executed, so and are control dependent on (note that the convention is to display dependence edges in the "controls" direction). Similarly, controls the execution of and , as these nodes may be bypassed by going from to . However, does not control as any path from hits eventually. The described dependencies were those that originate due to if statements. The figure shows also dependencies that arise due to possibly non-terminating loops (dotted red edges). These dependencies are called non-termination sensitive and belong to the class of strong control dependencies [Danicic et al. 2011]. For example, node is (non-termination sensitive) control dependent on node , because when follows the successor, the program may get stuck in the loop over and never reach . As the calling suggests, these dependencies are sensitive to (non-)termination of programs. In this paper, we are concerned with the computation of strong control dependencies. In particular, we are concerned with the computation of non-termination sensitive control dependence (NTSCD) and decisive order dependence (DOD), both introduced by Ranganath et al. [2005,2007].
We report on flaws of the original Ranganath et al. 's algorithms that result in incorrectly computed dependencies and suggest how to fix them. Moreover, we provide new algorithms that are easier and faster in theory and also in practice. Our algorithm for the computation of NTSCD has the worst-case execution time complexity (| | 2 ) whereas the algorithm of Ranganath et al. [2007] has the complexity (| | 4 · (| |)), where | | is the number of nodes in the control flow graph. Similarly, for the computation of DOD we provide an algorithm that runs in (| | 3 ) while the Ranganath et al. 's algorithm runs in (| | 5 · (| |)). Our algorithm is also optimal in the sense that it computes ternary relation that can have size (| | 3 ) in (| | 3 ) time.
The rest of the paper is structured as follows. At the end of this section, we summarize our contributions and discuss the related work. Section 2 contains the necessary preliminaries. Section 3 defines NTSCD and discusses the flaw in the Ranganath et al. 's algorithm. Subsequently we describe our new algorithm for the computation of NTSCD. Similarly structured is Section 4 that is concerned with the DOD relation. We define DOD, discuss the known algorithm for its computation and then we develop a theory that underpins our algorithm for the computation of DOD. The algorithm is presented at the end of the section. In Section 5 is a discussion about control closures, which are as of today considered as the state-of-the-art approach to the computation of control dependencies. Section 6 contains experimental evaluation of our work. The paper is concluded with Section 7.

Contributions
The main contributions of the paper are as follows: (1) We have identified flaws in algorithms by Ranganath et al. [2007] for the computation of NTSCD and DOD relations. We describe why the algorithms may fail and suggest a fix for each of them.
(2) We designed and implemented new algorithms for the computation of NTSCD and DOD that are asymptotically faster than the algorithms by Ranganath et al. Our algorithm for the computation of NTSCD runs in (| | 2 ) and for the computation of DOD in (| | 3 ). This is an improvement over the complexity of Ranganath et al.'s algorithms which run in (| | 4 · (| |)) and (| | 5 · (| |)), respectively. Moreover, our algorithm for the computation of DOD is optimal in the sense that it computes results of the size (| | 3 ) in (| | 3 ) time.
(3) We provide a solid experimental results that our algorithms are usable in practice and significantly faster than the previously known algorithms.

Related Work
There are many similar yet different notions of control dependence. The first paper concerned with control dependence is due to Denning and Denning [1977] who used control dependence to certify that flow of information in a program is secure (as determined by security requirements given as a lattice of flow constraints). Weiser [1984], Ottenstein and Ottenstein [1984], and Ferrante et al. [1987] used control dependencies in program slicing, which is also the motivation for the most of the latter research in this area. These papers, generally accepted as the "classical" literature about control dependence, study algorithms that work with procedures having a unique exit point and that always terminate. Such restrictions do not fit modern program structures, so researchers have been gradually extending the algorithms to more general settings. Podgurski and Clarke [1990] removed the restriction about termination of the program, but still work with procedures that have a unique exit point. Bilardi and Pingali [1996] achieved a generalization of previously known notions of control dependence by generalizing dominance relation in graphs.
Control dependencies are in most of the cases used at the level of standalone procedures. However, there are cases when also information about interprocedural control dependencies is needed. This direction was studied by Loyall and Mathisen [1993] and Harrold et al. [1998]; Sinha et al. [2001].
The notion of NTSCD and DOD was founded in works of Ranganath et al. [2005,2007] in order to slice reactive systems. Ranaganath et al. introduced also a non-termination insensitive control dependence that generalizes the classical control dependence (that assumes termination of programs) to graphs without a unique exit point. Further, they relax the conditions of DOD to obtain several other order dependencies that may be useful in program slicing. Danicic et al. [2011] provided an elegant generalization of the notion of control dependence using a so-called control closures. In their works, weak control closures generalize termination insensitive control dependence and strong control closures generalize termination sensitive (and thus also NTSCD) control dependence. Danicic et al. provide also algorithms for the computation of weak and strong control closures. Léchenet et al. [2018b] proved the correctness of the Danicic et al.'s weak control closure algorithm in Coq and provided several optimizations that significantly improve the performance of the algorithm (the optimized algorithm have been mechanically proved in Why3). Our algorithms are concerned with NTSCD and DOD and thus with strong control closures.

PRELIMINARIES
The paper presents several algorithms working with finite directed graphs. Here we recall some basic terms.
A finite directed graph is a pair = ( , ), where is a finite set of nodes and ⊆ × is a set of edges. If there is an edge ( , ) ∈ , then is called a successor of , is a predecessor of , and the edge is an outgoing edge of . Given a node , the set of all its successors is denoted by Successors( ) and the set of all its predecessors is denoted by Predecessors( ). A path from a node 1 is a nonempty finite or infinite sequence 1 2 . . . ∈ + ∪ of nodes such that there is an edge ( , +1 ) ∈ for each pair , +1 of adjacent nodes in the sequence. A path is called maximal if it cannot be prolonged, i.e., if it is infinite or the last node of the path has no outgoing edge. A node is reachable from a node , written ⇀ , if there exists a finite path such that its first node is and its last node is . Further, nodes , are mutually reachable, written ⇌ , whenever ⇀ and ⇀ . The relation ⇌ is clearly an equivalence on and it provides a partition of into equivalence classes called strongly connected components (SCC). An SCC is called terminal if there is no edge leading outside this SCC, i.e., ∩ ( × ( ∖ )) = ∅. For each set of nodes ′ ⊆ we define a graph induced by ′ as the graph ( ′ , ′ ) where ′ = ∩ ( ′ × ′ ). An SCC is called trivial if it induces a graph without any edge. It is called nontrivial otherwise. Note that a trivial SCC has to be a singleton. When we talk about an SCC, we usually mean the graph induced by this SCC.
In this paper, we consider programs represented by control flow graphs, where nodes correspond to program statements and edges model the flow of control between the statements. As control dependence reflects only the program structure, our definition of a control flow graph does not contain any statements. Our definition also does not contain any start or exit nodes as these are not important for the problems we study in this paper.
Definition 2.1 (Control flow graph). A control flow graph (CFG) is a finite directed graph = ( , ) where each node ∈ has at most two outgoing edges. Nodes with exactly two outgoing edges are called predicate nodes or simply predicates. The set of all predicates of a CFG is denoted by Predicates( ).
Note that the number of edges in each control flow graph is at most twice the number of its nodes. We often use this fact in the complexity analysis of presented algorithms.

NON-TERMINATION SENSITIVE CONTROL DEPENDENCE
This section focuses on non-termination sensitive control dependence (NTSCD) introduced by Ranganath et al. [2005]. We start with its formal definition.
Definition 3.1 (Non-termination sensitive control dependence). Given a CFG = ( , ), a node ∈ is non-termination sensitive control dependent on a predicate node ∈ Predicates( ), written NTSCD − −−− → , if has two successors 1 and 2 such that • all maximal paths from 1 contain , and • there exists a maximal path from 2 that does not contain .
Before we present our algorithm for the computation of non-termination sensitive control dependencies, we recall the algorithm of Ranganath et al. [2007] and show that it can produce incorrect results.

Algorithm of Ranganath et al. [2007] for NTSCD
The algorithm is presented in Algorithm 1. The central data structure of the algorithm is a twodimensional array where for each node and for each predicate node with successors and , [ , ] always contains a subset of { , }. Intuitively, should be added to [ , ] if appears on all maximal paths from that start with the prefix . The workbag holds the set of nodes for which some [ , ] value has been changed and this change should be propagated. The first part of the algorithm initializes the array with the information that each successor of a predicate node is on all maximal paths from starting with . The main part of the algorithm then spreads the information about reachability on all maximal paths in the forward manner. Finally, the last part computes the NTSCD relation according to Definition 3.1 and with use of the information in .

Algorithm 1 The NTSCD algorithm by Ranganath et al. [2007]
Input: a CFG = ( , ) Output: a potentially incorrect NTSCD relation stored in ntscd 1: assume that [ , ] = ∅ for all ∈ and ∈ Predicates( ) ⊲ Initialization 2: workbag ← ∅ 3: for ∈ Predicates( )) do 4: for ∈ Successors( ) do 5: [ , ] ← { } Althought the correctness of the algorithm has been proved [Ranganath et al. 2005, Theorem 7], we present an example where the algorithm provides an incorrect answer. Consider the CFG in Figure 2. The first part of the algorithm initializes the array as shown in the figure and sets workbag to {2, 6, 3, 4}. Then any node from workbag can be popped and processed. Let us apply the policy used for queues: always pop the oldest element in workbag. Hence, we pop 2 and nothing happens as the condition on line 22 is not satisfied for any . This also means that the symbol 12 is not propagated any further. Next we pop 6, which has no effect as 6 has no successor. By processing 3 and 4, 23 and 24 are propagated to [5, 2] and 5 is added to the workbag. Finally, we process 5 and set [6, 2] to { 23 , 24 }. The final content of is provided in the figure. Unfortunately, the information in is sound but incomplete. In other words, if ∈ [ , ], then is indeed on all maximal paths from starting with , but the opposite implication does not hold. In particular, 12 is missing in [5, 1] and [6, 1]. This flaw causes that the last part of the algorithm computes an incorrect NTSCD relation. More precisely, it correctly produces dependecies 1 NTSCD − −−− → 2, 2 NTSCD − −−− → 3, and 2 NTSCD − −−− → 4, but it also incorrectly produces the dependence 1 NTSCD − −−− → 6 and it misses the dependence 1 NTSCD − −−− → 5. A neccessary condition to get the correct result is to process 2 only after 3, 4 are processed and [5, 2] = { 23 , 24 }. For example, one obtains the correct (also shown in the figure) when the nodes are processed in the order 3, 4, 2, 5, 6.
The algorithm is clearly sensitive to the order of popping nodes from workbag. We are currently not sure whether for each there exists an order that leads to the correct result. An easy way to fix the algorithm is to ignore the workbag and repeatedly execute the body of the while loop (lines 12-31) for all ∈ until the array reaches a fixpoint. However, this modification would slow down the algorithm substantially. Computing the fixpoint needs (| | 3 ) iterations over the loop body (lines 12-13) and one iteration of the body without the workbag handling instructions needs (| | 2 ). Hence, the overall time complexity of the fixed version is (| | 5 ).

New algorithm for NTSCD
We have designed and implemented an algorithm for the computation of NTSCD which is correct, significantly simpler and asymptotically faster than the original algorithm of Ranganath et al. [2007].
Roughly speaking, our algorithm calls for each node a procedure that identifies all NTSCD dependencies of on predicate nodes. The procedure works in the following steps.
(2) Pick an uncolored node with a positive number of successors such that all these successors are red and color the node red. Repeat this step until no such node exists.
(3) For each predicate node that has a red successor and an uncolored one, output NTSCD − −−− → .
Unlike the Ranganath et al. 's algorithm which works in a forward manner, our algorithm spreads the information about reachability of on all maximal paths in the backward direction starting from .
The algorithm is presented in Algorithm 2. The discussed procedure is called compute( ) and it actually implements only the first two steps mentioned above. In the second step, the procedure does not search over all nodes to pick the next node to color. Instead, it maintains the count of uncolored successors for each node. Once the count drops to 0 for a node, the node is colored red and the search continues with predecessors of this node. The third step is implemented directly in the main loop of the algorithm.
To prove that the algorithm is correct, we basically need to show that when compute( ) finishes, a node is red iff all maximal paths from contain . We start with a simple observation. Proof. For each node , the counter is initialized to the number of its successors and it is decreased by calls to visit( ) each time a successor of gets red. When the counter drops to 0 (i.e., all successors of the node are red), the node is colored red. Therefore, if is red, it got red either on line 17 and = , or ≠ and is red because all its successors got red (it must have a positive number of successors, otherwise the counter could not be 0 after its decrement). In the other direction, if = , it gets red on line 17. If it has a positive number of successors which all get red, the node is colored red by the argument above. □ Theorem 3.3. After compute( ) finishes, for each node it holds that is red if and only if all maximal paths from contain .
Proof. ("⇐=") We prove this implication by contraposition. Assume that is an uncolored node. Lemma 3.2 implies that each uncolored node has an uncolored successor (if it has any). Hence, we can construct a maximal path from containing only uncolored nodes simply by always going to an uncolored successor, either up to infinity or up to the node with no successors. This uncolored maximal path cannot contain which is red.
("=⇒") For the sake of contradiction, assume that there is a red node and a maximal path from that does not contain . Lemma 3.2 implies that all nodes on this path are red. If the maximal path is finite, it has to end with a node without any successor. Lemma 3.2 says that such a node can be red if and only if it is , which is a contradiction. If the maximal path is infinite, it must contain a cycle since the graph is finite. Let be the node on this cycle that has been colored red as the first one. Let be the successor of on the cycle. Recall that ≠ as the maximal path does not contain . Hence, node could be colored red only when all its successors including were already red. This contradicts the fact that was colored red as the first node on the cycle. □ To determine the complexity of our algorithm on a CFG ( , ), we first analyze the complexity of one run of compute( ). The lines 12-15 iterate over all nodes. The crucial observation is that the procedure visit is called at most once for each edge ( , ′ ) ∈ of the graph: to decrease the counter of when ′ gets red. Hence, the procedure compute( ) runs in (| | + | |). This procedure is .counter ← .counter − 1 3: if .counter = 0 then 4: .color ← red 5: for ∈ Predecessors( ) do .color ← uncolored 14: .counter ← |Successors( )| if has a successor and an uncolored successor then 28: end for 31: end for called on line 25 for each node . Finally, lines 27-29 are executed for each pair of a node and a predicate node . This gives us the overall complexity ((| | + | |) · | | + | | 2 ) = ((| | + | |) · | |). Since in control flow graphs it holds | | ≤ 2| |, the complexity can be simplified to (| | 2 ).
Note that our algorithm is in particular suitable for on-demand computation. Indeed, each call to compute( ) calculates exactly the control dependencies of and therefore may be used by a client analysis as per need.

DECISIVE ORDER DEPENDENCE
During program slicing, which is the main consumer of control dependence, there are cases when even the use of NTSCD fails to deliver correct results. If the CFG of a program is irreducible 1 , we may want to mark more nodes as dependent than only those that are non-termination sensitive control dependent.
For irreducible CFGs, Ranganath et al. [2007] introduced decisive order dependence (DOD). It is a relation between a predicate node and two other nodes that captures the cases when the two nodes both lie on all maximal paths from the predicate node, but the order in which they are executed may change the computed values. As an example, see the CFG in Figure 3. Nodes and both lie on all maximal paths originating at node . Therefore, neither nor are NTSCD on . However, controls which of and is executed first.
Definition 4.1 (Decisive order dependence). Let = ( , ) be a CFG and , , ∈ be three distinct nodes such that is a predicate node with successors 1 and 2 . Nodes , are decisive order-dependent (DOD) on , written DOD − −− → { , }, if • all maximal paths from contain both and , • all maximal paths from 1 contain before any occurrence of , and • all maximal paths from 2 contain before any occurrence of .
DOD is an auxiliary relation that has an effect only for irreducible graphs. Indeed, Ranganath et al. [2007] proved that DOD relation is empty for reducible graphs.
For each triple of nodes , , ∈ such that ∈ Predicates( ) and ≠ , the algorithm executes the following check and if it succeeds, then The procedure dependence( , , , ) returns true iff is on all maximal paths from one successor of before any occurrence of and is on all maximal paths from the other successor of before any occurrence of . The procedure reachable is specified only by words [Ranganath et al. 2007, description of Fig. 7] as follows: reachable(a, b, G) returns true if is reachable from in the graph . Unfortunately, this algorithm can provide incorrect results. For example, consider the CFG in Figure 4. For the triple of nodes , , , the formula (1) is clearly satisfied: appears on all maximal paths from one successor of (namely ) before any occurrence of , and appears on all maximal paths from the other successor of (which is ) before any occurrence of . At the same time, and are mutually reachable. However, it is not true that DOD − −− → { , }, because and do not lie on all maximal paths from (the first condition of Definition 4.1 is violated).
The algorithm can be easily fixed by modifying the procedure reachable( , , ) to return true if is on all maximal paths from . This change does not increase the overall complexity of the algorithm. Indeed, if we implement the modified procedure reachable( , , ) with use of the procedure compute( ) in Algorithm 2, it would run in (| |) time on a CFG ( , ). This is exactly the complexity of the original procedure reachable( , , ). By comparing the fixed and the original version of the reachable( , , ), one can readily confirm that the original version produces supersets of DOD relations.

New algorithm for DOD: crucial observations
As in the case of NTSCD, we have designed a new algorithm for the computation of DOD which is relatively simple and asymptotically faster than the DOD algorithm of Ranganath et al. [2007].
Given a CFG, our algorithm first computes for each predicate the set of nodes that are on all maximal paths from . Then we process every predicate separately. We build an auxiliary graph with nodes and from this graph we get all pairs of nodes that are DOD on . A graph is a central notion of our algorithm. This subsection highlights some important properties of these graphs and proves some statements that underpin the algorithm. The following definitions are needed for the construction of .
In other words, a ′ -interval is a finite path with at least one edge that has the first and the last node in ′ but no other node on the path is in ′ . Definition 4.3 (Projection graph 2 ). Given a CFG = ( , ) and a subset ′ ⊆ , the projection graph for ′ is the graph For a predicate , we take the set of all nodes that lie on all maximal paths from (including ). We compute the graph as the projection graph for . Note that does not have to be CFG any more as nodes in can have more than two successors. However, represents exactly all possible orders of the first occurrences of nodes in on maximal paths in starting from .
Lemma 4.4. Let = ( , ) be a CFG and ∈ be a predicate node. For each maximal path from in , there exists a maximal path from in with the same order of the first occurrences of all nodes from , and vice versa.
Proof. First, let us consider a maximal path from in . The path has to contain all nodes from . If there are infinitely many occurrences of such nodes in the path, we can easily construct a path in from which is identical to the path in , only the nodes outside are omitted. Indeed, every -interval 1 . . . that is a part of the maximal path in , can be simply replaced by 1 on the path in as contains the edge ( 1 , ). The situation is different when the maximal path in contains only finitely many occurrences of nodes from . We can apply exactly the same construction on the prefix of this path ending by the last occurrence of a node from . Again, the obtained path in is identical to the prefix of the path in , only the nodes outside are omitted. Note that the obtained path in does not have to be maximal. However, there has to be a maximal path in with this prefix and the prefix has to contain all nodes from . Hence, the order of the first occurrences of nodes from on this maximal path in is the same as on the original path in .
Second, let us consider a maximal path from in . We can transform it into a path in by replacing every two successive nodes +1 with a corresponding -interval . . . +1 in . Such -interval has to exist due to the construction of . If the original maximal path in is infinite, we obtain a maximal path in that is identical to the original path, only some nodes outside are added. If the original maximal path in is finite, then the constructed path in does not have to be maximal, but it already contains all nodes from in the same order as the original path in and it can be prolonged into a maximal path. □ The definition of and the above lemma imply that each maximal path from in contains all nodes in .
We now turn our attention to the computation of DOD relation from . The following lemma solves the easy case when has zero or one successor in .
Lemma 4.5. If has at most one successor in , then there are no nodes DOD on .
Proof. If has no successor in , then is the only node contained by all maximal paths from in . Definition 4.1 immediately implies that there are no nodes DOD on . Now assume that has a single successor in . Let 1 and 2 be the two different successors of in . Lemma 4.4 implies that on all maximal paths in from 1 or 2 , the node appears as the first node of . The paths can continue from regardless whether they start in 1 or 2 . This means that if the first occurrences of nodes , ∈ appear in some order on a maximal path in from 1 , they can appear in the same order also on a maximal path from 2 . Hence, , are not DOD on . □ Now we study the case when has at least two different successors in . Actually, we start with two general lemmas not specific to this case.
Lemma 4.6. The graph has at most one nontrivial SCC. Moreover, this SCC is terminal.
Proof. Recall that each maximal path from in has to visit all nodes. In particular, it has to pass through each SCC. However, when a path from enters its first nontrivial SCC, it can be prolonged into an infinite path that never leaves this SCC. Such a path is maximal and thus it has to contain all nodes of . Hence, there is at most one nontrivial SCC in and it is terminal. □ Lemma 4.7. All successors of in are in the same SCC.
Proof. Let 1 , 2 be two successors of in . As all maximal paths from in contain all nodes, 2 has to be reachable from 1 . For the same reason, 1 is reachable from 2 . Hence 1 and 2 are mutually reachable and thus in the same SCC. □ If has at least two successors in , all these successors are in the same SCC, which is therefore nontrivial. Due to Lemma 4.6, this SCC is terminal. This also implies that there is no other SCC besides the nontrivial one and potentially the trivial SCC formed by . The structure of such graph can be actually characterized even more precisely.   Lemma 4.8. If has at least two successors in , then is a trivial SCC and all other nodes of are in a single SCC, which is a cycle.
Proof. Let 1 and 1 be two distinct successors of and let be the nontrivial SCC containing all successors of . Because contains all successors of and it is terminal, it has to contain all nodes of , potentially except . Note that is not a successor of because a self-loop on would generate a maximal path that does not contain the other successors of in . Hence, if is not in , it is a trivial SCC. As 1 and 1 are in one SCC, there has to be a path 1 2 . . . 1 from 1 to 1 where all nodes on the path are distinct. Analogously, there has to be a path 1 2 . . . 1 from 1 to 1 where all nodes are distinct. To prove that all nodes 1 , 2 , . . . , , 1 , 2 , . . . , are distinct, it remains to show that { 2 , . . . , } ∩ { 2 , . . . , } = ∅. For the sake of contradiction, assume that = for some 2 ≤ ≤ and 2 ≤ ≤ . Then there exists the infinite path ( 1 2 . . . −1 +1 . . . ) that does not contain 1 , which is a contradiction.
To sum up, we know that all nodes , 1 , 2 , . . . , , 1 , 2 , . . . , are distinct and we know that they are connected by edges as depicted in Figure 5. We can easily see that contains an infinite path ( 1 2 . . . 1 2 . . . ) that has to contain all nodes in . Now we show that is not in the SCC . For the sake of contradiction, assume that there is an edge ( , ) (the case for an edge ( , ) is analogous). Then there exists the infinite path ( 1 2 . . . ) that does not contain 1 , which is a contradiction. As is not in , it forms a trivial SCC.
It remains to prove that is a cycle. In other words, we need to show that does not contain any other edges except those depicted in Figure 5. Intuitively, any additional edge would induce a maximal path from that misses some nodes of . For the sake of contradiction, assume that there is an additional edge leading from (the case of an edge leading from is analogous). The edge has to match one of the following three cases.
(3) ( , ), where < or > 1. Then there exists the infinite path ( 1 . . . +1 . . . ) that does not contain or 1 . In all cases, we get a contradiction. □ Note that Figure 5 depicts the shape of where has just 2 successors. However, may have more successors leading to the nodes in .
We now investigate how to compute the pairs of nodes , that are DOD on from the graph . Lemma 4.5 says that we can safely ignore graphs where has at most one successor. In the following, we study only graphs where has at least two successors. Lemma 4.8 shows that these graphs have the shape of a cycle and node with at least two outgoing edges going to some nodes on the cycle.
The definition of DOD uses maximal paths from successors of in . Let 1 and 2 be the two successors of in . Note that 1 , 2 can, but do not have to be in . For each successor we compute the set of nodes that appear as the first node of on some maximal path from in . Formally, for ∈ {1, 2}, we define Note that the nodes in 1 ∪ 2 are exactly all the successors of in . The motivation for defining sets is that the maximal paths from the nodes of 1 in represent exactly all possible orders of the first occurrences on nodes in on maximal paths in starting in . The relation is essentially the same as the one for maximal paths from in and in , as described by Lemma 4.4.
Lemma 4.9. Let be a CFG, be a predicate node with successors 1 , 2 in and with at least two successors in , and let ∈ {1, 2}. For each maximal path from in , there exists a maximal path from a node of in with the same order of the first occurrences of all nodes from ∖ { }, and vice versa.
Proof. Due to Lemma 4.8, the assumption that has at least two successors in means that is a trivial SCC in . The construction of then implies that is also a trivial SCC in . All maximal paths from in as well as in thus contain only as the starting node. Without loss of generality, assume that = 1. To prove the statement, we remove the edge ( , 2 ) from . The statement is now a direct corollary of Lemma 4.4, and the fact that maximal paths from 1 in are exactly the maximal paths from in just without the first node, and maximal paths from nodes of 1 in are exactly the maximal paths from in just without the first node. □ Note that the sets 1 and 2 do not have to be disjoint. The following lemma closes the case when they are not disjoint.
Lemma 4.10. Let be a CFG, be a predicate node with successors 1 , 2 in and with at least two successors in . If 1 ∩ 2 ≠ ∅, then there are no nodes DOD on .
Proof. Let be a node in 1 ∩ 2 . Lemma 4.9 implies that for every maximal path in from , there exist a maximal path in from 1 and from 2 with the same order of the first occurrences of all nodes from ∖ { }. This directly implies that there are no nodes DOD on . □ The nodes in divide the cycle of into -strips, which are parts of the cycle starting with a node from and ending just before the next node of .
Definition 4.11 ( -strip). Let be a CFG, be a predicate node with successors 1 , 2 in and with at least two successors in , and let ∈ {1, 2}. An -strip is a path . . . ∈ .( ∖ ) * in such that the successor of in is a node in . An example of with -strips is in Figure 6. The -strips directly say which pairs of nodes of are in the same order on all maximal paths from in . Lemma 4.12. Let be a CFG, be a predicate node with successors 1 , 2 in and with at least two successors in , and let ∈ {1, 2}. Further, let , ∈ ∖ { } be two distinct nodes. The node is before any occurrence of on all maximal paths from in if and only if there is an -strip containing both and where is before .
Proof. ("⇐=") Let , be two nodes such that appears before in an -strip. It is obvious that the first occurrence of appears before the first occurrence of on every maximal path from nodes of in . Due to Lemma 4.9, the first occurrences of and have the same order also in all maximal paths from in .
("=⇒") We prove this implication by contraposition. The case when is before in an -strip is actually proven by the previous paragraph where one just swaps and . To prove the remaining case, assume that and are in different -strips. Let ∈ be the first node of the -strip containing . Then the maximal path in from contains before the first occurrence of . Due to Lemma 4.9, there exists a maximal path in from where is before any occurrence of . □ The following theorem is an immediate corollary of Lemmas 4.5 and 4.12.
Theorem 4.13. Let = ( , ) be a CFG and , , ∈ be three distinct nodes such that is a predicate with successors 1 and 2 . Then , are DOD on if and only if • has at least two successors in , • there exists an 1 -strip in that contains before , and • there exists an 2 -strip in that contains before .
Let us consider again the in Figure 6. The theorem implies that nodes 1 , 5 are DOD on as they appear in 1 -strip 1 2 3 4 5 6 and in 2 -strip 5 6 7 8 1 in the opposite order. Nodes 1 , 6 are DOD on for the same reason.
With use of the previous theorem, we can find a regular language over such that there exist nodes , DOD on iff an unfolding of the cycle in is in the language.
The equivalence follows from this picture.
The path 1 . . . −1 corresponds to the left box in the unfolding and the path 1 . . . −1 to the right box. Each of the path 1 . . . −1 is before each of path 1 . . . −1 in the marked 1 -strip, and they are in the opposite order in the marked 2 -strip. Due to Theorem 4.13, we have DOD − −− → { , }. There is no other DOD dependence induced by the pair of marked strips. As all other 1 -strips are subparts of the marked 2 -strip, they cannot induce any DOD dependence on . Symmetric argument works for all other 2 -strips. □

New algorithm for DOD: pseudocode and complexity
The algorithm is shown in Algorithms 3 and 4. Because nearly all applications of DOD need also NTSCD, we presented the DOD algorithm with a simple extension (marked with gray lines) that computes NTSCD simultaneously with DOD. The DOD algoritm starts at the bottom of Algorithm 4. The first step is to compute the sets for all predicate nodes of a given CFG . The computation of predicate nodes can be found in Algorithms 3. It is a slightly modified version of Algorithm 2. Recall that the procedure compute( ) of Algorithm 2 marks red every node such that all maximal paths from the node contain . The procedure compute( ) of Algorithm 3 does in principle the same, but instead of the red color it .counter ← |Successors( )| end for 29: end procedure marks the nodes with the identifier of the node . Every node collects these marks in set . After we run compute( ) for all the nodes in the graph, each node has in its set precisely all nodes that are on all maximal paths from . For the computation of DOD, only the sets for predicate nodes are needed, but the extension computing NTSCD may actually use all these sets.
After we calculate sets , we compute DOD and potentially also NTSCD dependencies for each predicate node separately by procedures computeDOD( ) and computeNTSCD( ). The procedure computeDOD( ) first constructs the projection graph with use of build ( ). Nodes of the graph are these of . To compute edges, we trigger a depth-first search in from each ∈ . If we find a node ∈ , we add the edge ( , ) to the graph and stop the search on this path. When the graph is constructed, we check its structure. If the node has at most one successor in , we return the empty relation due to Lemma 4.5.
The next step is to compute the sets 1 and 2 of nodes on that are first-reachable from the two successors 1 , 2 of in via nodes outside . Again, we apply a similar depth-first search as ntscd ← ntscd ∪ computeNTSCD( ) 35: end for in the construction of described above. If the sets 1 , 2 are not disjoint, we return the empty relation due to Lemma 4.10.
Then we unfold the cycle in from an arbitrary node in 1 , compute the set , and return the empty relation if the unfolding does not match the pattern of Theorem 4.14. We actually use a slightly different pattern. But the check is correct as a cycle has an unfolding of the form Finally, we extract the paths of the form 1 . * . 2 and 2 . * . 1 from the unfolding. Note that the last node of the latter path can be in fact the first node of the unfolding. Finally, we compute the DOD dependencies according to Theorem 4.15.
The procedure computeNTSCD( ) used for the computation of NTSCD simply follows Definition 3.1: it makes dependent on each node that is on all maximal paths from the successor 1 but not on all maximal paths from the successor 2 or symmetrically for 2 and 1 .
As the correctness of our algorithm comes directly from the observations made in the previous subsection, it remains only to analyze its complexity. The procedure compute s consists of two cycles in sequence. The first cycle runs in (| |). The second cycle calls (| |)-times the procedure compute( ). This procedure is essentially identical to the procedure of the same name in Algorithm 2 and so is its time complexity, namely (| | + | |). Overall, the procedure compute s runs in (| | · (| | + | |)), which is (| | 2 ) for control flow graphs. Now we discuss the complexity of the procedure computeDOD( ). Creating the graph requires calling depth-first search (| |) times, which is (| | × | |) in total. Computation of 1 , 2 requires another two calls of depth-first search, which is in (| |). Checking that 1 and 2 are disjoint is in (| |), And so is unfolding a cycle, check of the unfolding for the pattern on line 14, and the calls to extract. The most demanding part is actually the construction of the DOD relation on line 20, which takes (| | 2 ). Altogether, computeDOD( ) runs in (| | × | | + | | 2 ) which simplifies to (| | 2 ) for control flow graphs.
computeDOD is called (| |) times, so the overall complexity of computing DOD for a CFG = ( , ) is (| | 3 ). If we compute also NTSCD, we make (| |) extra calls to computeNTSCD( ), where one call takes (| |) time. Therefore, the asymptotic complexity of computing NTSCD with DOD does not change from computing DOD only.
DOD is ternary relation, therefore its maximal size is (| | 3 ). There also exists a graph for which the DOD relation reaches this limit (a cycle on | |/2 nodes together with | |/2 predicate nodes; each predicate node has the same successors on the cycle such that these successors divide the cycle into two strips of length | |/4). Hence, our algorithm running in time (| | 3 ) is optimal.

COMPARISION TO CONTROL CLOSURES
In 2011, Danicic et al. [2011] introduced the notion of control closures (CC). Control closures generalize control dependence from control flow graphs to arbitrary graphs. In particular, strong control closure, which is sensitive to non-termination, generalizes strong forms of control dependence including NTSCD and DOD.
Definition 5.1 (Strongly control-closed set). Let = ( , ) be a CFG and let ′ ⊆ . The set ′ is strongly control-closed 3 in if and only if for every node ∈ ∖ ′ that is reachable in from a node of ′ , one of these holds: • any path starting at avoids ′ or • all maximal paths from contain a node from ′ and the set Θ( , ′ ) of the so-called firstreachable elements in ′ from defined as has at most one element, i.e., |Θ( , ′ )| ≤ 1. 3 The definition has been adjusted to our settings, notably that predicates in our CFGs always have two outgoing edges (our CFGs are complete in the terms of Danicic et al. [2011]).
Definition 5.2 (Strong control closure). Let = ( , ) be a CFG and let ⊆ . A strong control closure of is a strongly control-closed set ′ ⊆ such that there is no strongly control-closed set ′′ satisfying ⊆ ′′ ⊊ ′ . Danicic et al. present an algorithm for the computation of strong control closures running in (| | 4 ) [Danicic et al. 2011, Theorem 66]. In fact, the algorithm uses a procedure Γ that is very similar to our procedure compute( ) of Algorithm 2.
We can also define when a set is closed under NTSCD or DOD.
NTSCD and DOD closures are defined analogously to the strong control closure. An NTSCD closure for a set ⊆ can be computed by gathering nodes backward reachable from via the NTSCD edges. The DOD closure can be computed similarly. Danicic et al. [2011, Lemmas 93 and 94] proved that for a = ( , ) that has a distinguished start node from which all nodes in are reachable and a subset ′ ⊆ such that start ∈ ′ , the set ′ is strongly control-closed if and only if it is closed under NTSCD and DOD. Hence, the strong control closures of the sets containing the start node can be computed also by computing NTSCD and DOD relations and the backward reachability along the control dependencies. The complexity of computing the strong control closures via NTSCD and DOD closures is (| | 3 ) as the backward reachability is dominated by the computation of NTSCD and DOD relations.
A substantial difference between strong control closures and our algorithms is that we are able to compute DOD and NTSCD separately, whereas strong control closures are not. Moreover, our algorithm for the computation of DOD and NTSCD closure is asymptotically faster.

Implementation
We implemented our algorithms for the computation of NTSCD and DOD in C++ programming language on top of the LLVM [Lattner and Adve 2004] infrastructure. The implementation is now a part of a well maintained library for program analysis. We also implemented the original Ranganath et al. 's algorithms, the fixed versions of these algorithms as described in Subsection 3.1 and Subsection 4.1, and the algorithm for the computation of strong control closures.
There are several minor differences in the implementation of our algorithms compared to the description of algorithms in the text. The main difference is that we do not use recursion. We have rewritten the algorithms to use an explicit stack in order to avoid stack overflow on huge graphs. This step was rather a safeguard, as we had not hit stack overflow during any experiment with the preliminary versions of the algorithms that used recursion. Still, we believe that the exposition with recursion is more clear, therefore we describe the algorithms without the explicit stack.
Another, rather minor, difference is that we use sparse bitvectors instead of bitvectors of a fixed length. This step only saves memory on sparse graphs.
In the implementation of control closures, we use our procedure compute to implement the function Γ. This should have only a positive effect as this procedure is more efficient than iterating over all edges in the copy of the graph and removing them [Danicic et al. 2011].

Evaluation
We conducted a set of experiments on functions that we extracted from SV-COMP benchmarks 4 . These benchmarks contain many artificial or generated code, but also a lot of real-life code, e.g., from the Linux project. Each source code file was compiled with clang into LLVM and preprocessed by the -lowerswitch pass to ensure that every basic block has at most two successors. Then we extracted individual functions. As the computation of control dependencies runs swiftly on small functions, we filtered the extracted functions and kept only those that contain at least 100 basic blocks. After the deletion of duplicate functions, we were left with 2440 functions that we used for our experiments. Run on each function comprises building a directed graph from the basic blocks of the function and running the given algorithm on this graph.
The experiments were run on machines with AMD EPYC CPU with the frequency 3.1 GHz. Each benchmark run was constrained to 1 core and 8 GB of RAM. For enforcing the resources isolation, we used the tool Benchexec [Beyer et al. 2019]. We set the timeout to 100 s for each run of an algorithm.
In the following text, we denote the Ranganath et al. ' algorithms as the original algorithms (we distinguish between the incorrect and the fixed version at appropriate places) and the algorithms from this paper as the new algorithms.
6.2.1 NTSCD algorithms. In the first set of experiments, we compared the new NTSCD algorithm against the original NTSCD algorithm. We compared to both, the incorrect version of the original algorithm and against the fixed version. Although it seems that comparing to the incorrect version is meaningless, we did not want to compare only to the fixed version as the fix that we provided slows down the algorithm. On the right, the plot shows the running time of the algorithms on random graphs with 500 nodes and the number of edges as specified by the -axis. All CPU time is in seconds.
The results are depicted in Figure 7. On the left scatter plot, there is the comparison of the new algorithm to the incorrect original algorithm and on the right scatter plot we compare to the fixed original algorithm. As we can see, the new algorithm outperforms the original algorithm significantly. Since we did not prove that the fixed original algorithm is correct, we at least checked the outputs of the new NTSCD and the fixed original algorithms and found out that they output precisely the same control dependence relations. We can also see that the scatter plot on the right contains more timeouts of the original algorithm. It supports the claim that the fix slows down the algorithm.
6.2.2 DOD algorithms. We compared the new DOD algorithm to the original DOD algorithm with the fix described in Subsection 4.1. As the fix does not change the complexity of the original algorithm, we do not compare the new algorithm with the incorrect version of the original algorithm. The results of the experiments are displayed in Figure 8 on the left. We can see that the new algorithm is again very fast. In fact, the results resemble the results of the pure NTSCD algorithm (which is more or less a part of the DOD algorithm in the form of computing sets). Our algorithm takes the advantage that it can answer early that there are no DOD dependencies for a predicate node. Although this fact does not change the worst-case complexity, it helps in practice.
Irreducible graphs are rather rare in common code (because structured programs yield reducible graphs). Therefore, we tested the DOD algorithms also on randomly generated graphs, where we can expect that an irreducible graph emerges more often. Figure 8 on the right shows the results for graphs that have 500 nodes and 50, 100, 150, . . . randomly distributed edges (such that every node has at most two successors). The running CPU time is an average of 10 measurements.
We can see that the new algorithm is agnostic to the number of edges. Its running time in this experiment ranges from 4.12 · 10 −3 to 8.89 · 10 −3 seconds. The original DOD algorithm does not scale well with the increasing number of edges. control closures. One obstacle in these experiments was that control closures need a starting set of nodes that is going to be closed. We decided to run these experiments only on the subset of functions that have at least two exit points and set as the starting set the entry point and one of the exit points. This approach makes the closure algorithm to compute which nodes may influence getting to the other exit node. The new algorithm for the computation of DOD and NTSCD was setup to compute all the control dependencies for the given function and then construct the closure of the same set of starting nodes. Results are shown on the scatter plot in Figure 9. As expected, our algorithm runs similarly fast as in the other experiments and it outperforms the algorithm for the computation of control closures that has worse complexity. An observant reader can notice that in this set of experiments, the new algorithm has no result around 15 seconds even when the pure NTSCD computation has such results. It turns out that the computation of sets (which is basically the new NTSCD algorithm) that gathers the marks into bitvectors is in practice faster than the NTSCD algorithm (including deciding the NTSCD relation). The main reason for this is that the implementation with bitvectors does not need to initialize the counters for each call of compute.

CONCLUSION
We studied algorithms for the computations of strong control dependencies, namely non-termination sensitive control dependence (NTSCD) and decisive order dependence (DOD) by Ranganath et al. [2007] and strong control closures (CC) by Danicic et al. [2011] on arbitrary control flow graphs where each branching statement has two successors. We have demonstrated flaws in the original algorithms for computation of NTSCD and DOD and we have suggested corrections. Moreover, we have introduced new algorithms for NTSCD, DOD, and CC that are asymptotically faster (see Table 1). All the mentioned algorithms have been implemented and our expriments confirm better performance of the new algorithms.

ACKNOWLEDGMENTS
This material is based upon work supported by the Czech Science Foundation grant GA18-02177S.