1-- SPDX-FileCopyrightText: 2010 Tristan Ravitch <travitch@cs.wisc.edu>2-- SPDX-FileCopyrightText: 2026 Reliable System Software, Technische Universität Braunschweig <vss@ibr.cs.tu-bs.de>3--4-- SPDX-License-Identifier: BSD-3-Clause AND GPL-3.0-only56-- Based on the implementation provided by LLVM.Analysis.CDG from Tristan Ravitch7-- See https://hackage.haskell.org/package/llvm-analysis-0.3.0/docs/src/LLVM-Analysis-CDG.html8--9-- The implementation by Tristan Ravitch mentions a paper by Cytron et al.10-- See: https://doi.org/10.1145/115372.11532011--12-- However, I found that the original paper by Ferrante et al. does a much better job at13-- explaining what was implemented by Tristan Ravitch in llvm-analysis. Hence, the comments14-- below mainly refer to that: https://doi.org/10.1145/24039.240411516-- | This module implements a control dependency analysis, using a17-- /control dependency graph/ (CDG) for more information on the concept18-- refer to <https://doi.org/10.1145/24039.24041>. Roughly speaking, a19-- node /A/ is control dependent on /B/ if there is an edge /B → A/ so20-- that the node is taken, as well as an edge so that it is not taken.21module Language.QBE.Analysis.CDG22 ( CDG (..),23 build,24 edges,25 ctrlDeps,26 )27where2829import Data.Bifunctor (second)30import Data.IntMap (IntMap)31import Data.IntMap qualified as M32import Data.IntSet (IntSet)33import Data.IntSet qualified as S34import Data.List (find)35import Data.Maybe (fromMaybe)36import Language.QBE.Analysis.CFG qualified as CFG37import Language.QBE.Analysis.Graph qualified as G3839-- | A CDG signifying control-dependence between nodes in the 'CFG.CFG'.40data CDG41 = CDG42 { -- | Underlying 'CFG.CFG' for which the CDG was built.43 cdgCfg :: CFG.CFG,44 -- | Root node of the t'CDG', used for determining post-dominance.45 cdgRoot :: CFG.Label,46 -- | Graph representation of control-dependence.47 cdgGraph :: G.Graph48 }4950-- | All edges of the t'CDG', in an unspecified order.51edges :: CDG -> [(CFG.Label, CFG.Label)]52edges cdg = foldl go [] $ M.toList (cdgGraph cdg)53 where54 go acc (p, c) = acc ++ map (p,) (S.toList c)5556-- | Returns the control dependencies of a given node in the 'CFG.CFG'.57-- If the node doesn't have any control dependencies, 'Nothing' is58-- returned.59ctrlDeps :: CDG -> CFG.Label -> Maybe IntSet60ctrlDeps CDG {cdgGraph = cDeps} = (`M.lookup` cDeps)6162------------------------------------------------------------------------6364-- | Construct a new t'CDG' from an existing 'CFG.CFG'. The CDG is build65-- based on the given 'CFG.Label' from the CFG, which is used to as the66-- root of a post-dominator tree to establish a post-dominance67-- relationship between nodes.68build :: CFG.CFG -> CFG.Label -> CDG69build cfg root =70 CDG71 { cdgCfg = cfg,72 cdgRoot = root,73 cdgGraph = build' cfg root74 }7576build' :: CFG.CFG -> CFG.Label -> IntMap IntSet77build' cfg label =78 -- From the CFG, generate a post-dominator tree and also convert this tree79 -- to an IntMap representation for efficient successor lookup in 'addCDGEdge'.80 let rooted = (label, CFG.asDomGraph cfg)81 pdTree = G.pdomTree rooted82 pdtMap = M.fromList $ map (second S.fromList) (G.pdom rooted)83 pdtAnc = M.fromList (G.ancestors pdTree)84 in foldr (uncurry $ addCDGEdge pdtMap pdtAnc) M.empty $ CFG.edges cfg8586-- This function essentially implements the algorithm described in Section 3.187-- of the Paper by Ferrante et al., using the algorithm by Cytron et al. may be88-- more efficient and could be considered in the future.89addCDGEdge ::90 IntMap IntSet ->91 IntMap [Int] ->92 CFG.Label ->93 CFG.Label ->94 IntMap IntSet ->95 IntMap IntSet96addCDGEdge pdtMap pdtAnc a b acc97 -- Consider all edges (A, B) in the control flow graph such that B does not98 -- post-dominate M. If it does, we return 'acc' unmodified (insert nothing).99 | postdominates b a = acc100 | otherwise =101 -- Let AC denote the least common ancestor of A and B in the post-dominator tree.102 case commonAncestor b a of103 -- Case 1: All nodes in the post-dominator tree on the path from AC to104 -- B, including B but not AC, should be made control dependent on A.105 Just ac ->106 let cdepsOnA = S.insert b (S.filter (/= ac) $ lookupSucc b)107 in foldr insertEdge acc (S.toList cdepsOnA)108 -- Case 2: All nodes in the post-dominator tree on the path from A to B,109 -- including A and B, should be made control dependent on A.110 Nothing ->111 let deps = S.insert b $ lookupSucc b112 in foldr insertEdge acc (S.toList deps)113 where114 insertEdge :: CFG.Label -> IntMap IntSet -> IntMap IntSet115 insertEdge blk = M.insertWith S.union blk (S.singleton a)116117 lookupSucc :: CFG.Label -> IntSet118 lookupSucc l = fromMaybe S.empty $ M.lookup l pdtMap119120 -- Returns true if 'x' post-dominates 'y'.121 postdominates :: CFG.Label -> CFG.Label -> Bool122 postdominates x y = maybe False (x `S.member`) $ M.lookup y pdtMap123124 commonAncestor :: G.Node -> G.Node -> Maybe G.Node125 commonAncestor n1 n2 = do126 a1 <- M.lookup n1 pdtAnc127 a2 <- M.lookup n2 pdtAnc128 find (`elem` a1) a2