dominators.scm 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Mark Reinhold
  3. ;;; Find immediate dominators in a directed graph
  4. ;;; Mark Reinhold (mbr@research.nj.nec.com)/3 February 1995
  5. ; Debugging code removed and everything reluctantly Scheme-ized by
  6. ; R. Kelsey, St. Valentine's Day, 1995
  7. ; This fast dominator code is based upon Lengauer and Tarjan, "A Fast
  8. ; Algorithm for Finding Dominators in a Flowgraph," ACM TOPLAS 1:1, pp.
  9. ; 121--141, July 1979. It runs in time $O(|E|\log|V|)$, where $|E|$ is the
  10. ; number of edges and $|V|$ is the number of vertices. A smaller time bound
  11. ; of $O(|E|\alpha(|E|,|V|))$, where $\alpha$ is the inverse of Ackerman's
  12. ; function, can be achieved with more complex versions of the internal link!
  13. ; and eval! procedures.
  14. ;
  15. ; The client provides a rooted, directed graph by passing a root node,
  16. ; successor and predecessor functions, and auxiliary procedures for accessing
  17. ; and setting a slot in each node. The dominator code creates a shadow of
  18. ; the client's graph using the vertex record type defined below. To keep
  19. ; things clear, the client's graph is considered to contain "nodes," while
  20. ; the shadow graph contains "vertices."
  21. (define-record-type vertex :vertex
  22. (really-make-vertex node semi bucket ancestor debug)
  23. vertex?
  24. (node vertex-node) ; Corresponding node in client's graph
  25. (semi vertex-semi ; A number for this vertex, w, as follows:
  26. set-vertex-semi!) ; After w is numbered, but before its semidominator
  27. ; is computed: w's DFS number
  28. ; After w's semidominator is computed:
  29. ; the number of its semidominator
  30. (parent vertex-parent ; Parent of this vertex in DFS spanning tree
  31. set-vertex-parent!)
  32. (pred vertex-pred ; Parents
  33. set-vertex-pred!)
  34. (label vertex-label ; Label in spanning forest, initially this vertex
  35. set-vertex-label!)
  36. (bucket vertex-bucket ; List of vertices whose semidominator is this vertex
  37. set-vertex-bucket!)
  38. (dom vertex-dom ; A vertex, as follows:
  39. set-vertex-dom!) ; After step 3: If the semidominator of this
  40. ; vertex, w, is its immediate dominator, then
  41. ; this slot contains that vertex; otherwise,
  42. ; this slot is a vertex v whose number is
  43. ; smaller than w's and whose immediate dominator
  44. ; is also w's immediate dominator
  45. ; After step 4: The immediate dominator of this
  46. ; vertex
  47. (ancestor vertex-ancestor ; An ancestor of this vertex in the spanning forest
  48. set-vertex-ancestor!)
  49. (debug vertex-debug ; Debug field ##
  50. set-vertex-debug!))
  51. (define (make-vertex node semi)
  52. (really-make-vertex node
  53. semi
  54. '() ; bucket
  55. #f ; ancestor
  56. #f)) ; debug
  57. (define (push-vertex-bucket! inf elt)
  58. (set-vertex-bucket! inf (cons elt (vertex-bucket inf))))
  59. (define (find-dominators-quickly! root ; root node
  60. succ ; maps a node to its children
  61. pred ; maps a node to its parents
  62. slot ; result slot accessor
  63. set-slot!) ; result slot setter
  64. ;; Compute the dominator tree of the given rooted, directed graph;
  65. ;; when done, the slot of each node will contain its immediate dominator.
  66. ;; Requires that each slot initially contain #f.
  67. (define (dfs root)
  68. (let ((n 0) (vertices '()))
  69. (let go ((node root) (parent #f))
  70. (let ((v (make-vertex node n)))
  71. (set-slot! node v)
  72. (set! n (+ n 1))
  73. (set-vertex-parent! v parent)
  74. (set-vertex-label! v v)
  75. (set! vertices (cons v vertices))
  76. (for-each (lambda (node)
  77. (if (not (slot node))
  78. (go node v)))
  79. (succ node))))
  80. (let ((vertex-map (list->vector (reverse! vertices))))
  81. (do ((i 0 (+ i 1)))
  82. ((= i (vector-length vertex-map)))
  83. (let ((v (vector-ref vertex-map i)))
  84. (set-vertex-pred! v (map slot (pred (vertex-node v))))))
  85. (values n vertex-map))))
  86. (define (compress! v)
  87. (let ((a (vertex-ancestor v)))
  88. (if (vertex-ancestor a)
  89. (begin
  90. (compress! a)
  91. (if (< (vertex-semi (vertex-label a))
  92. (vertex-semi (vertex-label v)))
  93. (set-vertex-label! v (vertex-label a)))
  94. (set-vertex-ancestor! v (vertex-ancestor (vertex-ancestor v)))))))
  95. (define (eval! v)
  96. (cond ((not (vertex-ancestor v))
  97. v)
  98. (else
  99. (compress! v)
  100. (vertex-label v))))
  101. (define (link! v w)
  102. (set-vertex-ancestor! w v))
  103. (receive (n vertex-map) (dfs root) ; Step 1
  104. (do ((i (- n 1) (- i 1)))
  105. ((= i 0))
  106. (let ((w (vector-ref vertex-map i)))
  107. (for-each (lambda (v) ; Step 2
  108. (let ((u (eval! v)))
  109. (if (< (vertex-semi u)
  110. (vertex-semi w))
  111. (set-vertex-semi! w
  112. (vertex-semi u)))))
  113. (vertex-pred w))
  114. (push-vertex-bucket! (vector-ref vertex-map (vertex-semi w)) w)
  115. (link! (vertex-parent w) w)
  116. (for-each (lambda (v) ; Step 3
  117. ;; T&L delete v from the bucket list at this point,
  118. ;; but there is no reason to do so
  119. (let ((u (eval! v)))
  120. (set-vertex-dom! v
  121. (if (< (vertex-semi u)
  122. (vertex-semi v))
  123. u
  124. (vertex-parent w)))))
  125. (vertex-bucket (vertex-parent w)))))
  126. (do ((i 1 (+ i 1))) ; Step 4
  127. ((= i n))
  128. (let ((w (vector-ref vertex-map i)))
  129. (if (not (eq? (vertex-dom w)
  130. (vector-ref vertex-map (vertex-semi w))))
  131. (set-vertex-dom! w
  132. (vertex-dom (vertex-dom w))))))
  133. (set-vertex-dom! (slot root) #f)
  134. ;(show-nodes root succ slot) ; ## debug
  135. (do ((i 0 (+ i 1))) ; Set dominator pointers
  136. ((= i n))
  137. (let ((w (vector-ref vertex-map i)))
  138. (let ((d (vertex-dom w)))
  139. (set-slot! (vertex-node w) (if d (vertex-node d) #f)))))))
  140. ;;; The fast dominator algorithm is difficult to prove correct, so the
  141. ;;; following slow code is provided in order to check its results. The slow
  142. ;;; algorithm, which runs in time $O(|E||V|)$, is adapted from Aho and Ullman,
  143. ;;; _The Theory of Parsing, Translation, and Compiling_, Prentice-Hall, 1973,
  144. ;;; p. 916.
  145. (define (find-dominators-slowly! root succ pred slot set-slot!)
  146. (define vertex-succ vertex-pred)
  147. (define set-vertex-succ! set-vertex-pred!)
  148. (define vertex-mark vertex-ancestor)
  149. (define set-vertex-mark! set-vertex-ancestor!)
  150. (define (dfs root)
  151. (let ((n 0) (vertices '()))
  152. (let go ((node root) (parent #f))
  153. (let ((v (make-vertex node n)))
  154. (set-slot! node v)
  155. (set! n (+ n 1))
  156. (set! vertices (cons v vertices))
  157. (set-vertex-parent! v #f)
  158. (set-vertex-label! v #f)
  159. (for-each (lambda (node)
  160. (if (not (slot node))
  161. (go node v)))
  162. (succ node))))
  163. (for-each (lambda (v)
  164. (set-vertex-succ! v (map slot (succ (vertex-node v)))))
  165. vertices)
  166. (values n (reverse! vertices))))
  167. (receive (n vertices) (dfs root)
  168. (define (inaccessible v)
  169. ;; Determine set of vertices that are inaccessible if vertex v is ignored
  170. (set-vertex-mark! v #t)
  171. (let go ((w (car vertices)))
  172. (set-vertex-mark! w #t)
  173. (for-each (lambda (u)
  174. (if (not (vertex-mark u))
  175. (go u)))
  176. (vertex-succ w)))
  177. (filter (lambda (w)
  178. (cond
  179. ((vertex-mark w)
  180. (set-vertex-mark! w #f)
  181. #f)
  182. (else #t)))
  183. vertices))
  184. (for-each (lambda (v) (set-vertex-dom! v (car vertices)))
  185. (cdr vertices))
  186. (for-each (lambda (v)
  187. (let ((dominated-by-v (inaccessible v)))
  188. (for-each (lambda (w)
  189. (if (eq? (vertex-dom w) (vertex-dom v))
  190. (set-vertex-dom! w v)))
  191. dominated-by-v)))
  192. (cdr vertices))
  193. (set-vertex-dom! (car vertices) #f)
  194. ;(show-nodes root succ slot) ; ## debug
  195. (for-each (lambda (v)
  196. (set-slot! (vertex-node v)
  197. (let ((d (vertex-dom v)))
  198. (if d (vertex-node d) #f))))
  199. vertices)))
  200. (define (time-thunk thunk) (thunk))
  201. (define (find-and-check-dominators! root succ pred slot set-slot!)
  202. (let ((set-fast-slot! (lambda (x v) (set-car! (slot x) v)))
  203. (fast-slot (lambda (x) (car (slot x))))
  204. (set-slow-slot! (lambda (x v) (set-cdr! (slot x) v)))
  205. (slow-slot (lambda (x) (cdr (slot x)))))
  206. (let go ((node root))
  207. (set-slot! node (cons #f #f))
  208. (for-each (lambda (node)
  209. (if (not (slot node))
  210. (go node)))
  211. (succ node)))
  212. (let ((fast (time-thunk
  213. (lambda ()
  214. (find-dominators-quickly!
  215. root succ pred fast-slot set-fast-slot!))))
  216. (slow (time-thunk (lambda ()
  217. (find-dominators-slowly!
  218. root succ pred slow-slot set-slow-slot!)))))
  219. ; (format #t "** find-and-check-dominators!: fast ~a, slow ~a~%" fast slow) ; ##
  220. (let go ((node root))
  221. (if (not (eq? (fast-slot node) (slow-slot node)))
  222. (bug "Dominator algorithm error"))
  223. (set-slot! node (fast-slot node))
  224. (for-each (lambda (node)
  225. (if (pair? (slot node)) ; ## Assumes nodes are not pairs
  226. (go node)))
  227. (succ node))))))
  228. (define *check?* #t)
  229. (define (find-dominators! . args)
  230. (apply (if *check?*
  231. find-and-check-dominators!
  232. find-dominators-quickly!)
  233. args))