2 * Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "DFGDominators.h"
31 #include "DFGBlockMapInlines.h"
32 #include "DFGBlockWorklist.h"
34 #include "DFGNaiveDominators.h"
35 #include "JSCInlines.h"
37 namespace JSC
{ namespace DFG
{
39 Dominators::Dominators()
43 Dominators::~Dominators()
49 // This implements Lengauer and Tarjan's "A Fast Algorithm for Finding Dominators in a Flowgraph"
50 // (TOPLAS 1979). It uses the "simple" implementation of LINK and EVAL, which yields an O(n log n)
51 // solution. The full paper is linked below; this code attempts to closely follow the algorithm as
52 // it is presented in the paper; in particular sections 3 and 4 as well as appendix B.
53 // https://www.cs.princeton.edu/courses/archive/fall03/cs528/handouts/a%20fast%20algorithm%20for%20finding.pdf
55 // This code is very subtle. The Lengauer-Tarjan algorithm is incredibly deep to begin with. The
56 // goal of this code is to follow the code in the paper, however our implementation must deviate
57 // from the paper when it comes to recursion. The authors had used recursion to implement DFS, and
58 // also to implement the "simple" EVAL. We convert both of those into worklist-based solutions.
59 // Finally, once the algorithm gives us immediate dominators, we implement dominance tests by
60 // walking the dominator tree and computing pre and post numbers. We then use the range inclusion
61 // check trick that was first discovered by Paul F. Dietz in 1982 in "Maintaining order in a linked
62 // list" (see http://dl.acm.org/citation.cfm?id=802184).
64 class LengauerTarjan
{
66 LengauerTarjan(Graph
& graph
)
70 for (BlockIndex blockIndex
= m_graph
.numBlocks(); blockIndex
--;) {
71 BasicBlock
* block
= m_graph
.block(blockIndex
);
74 m_data
[block
].label
= block
;
80 computeDepthFirstPreNumbering(); // Step 1.
81 computeSemiDominatorsAndImplicitImmediateDominators(); // Steps 2 and 3.
82 computeExplicitImmediateDominators(); // Step 4.
85 BasicBlock
* immediateDominator(BasicBlock
* block
)
87 return m_data
[block
].dom
;
91 void computeDepthFirstPreNumbering()
93 // Use a block worklist that also tracks the index inside the successor list. This is
94 // necessary for ensuring that we don't attempt to visit a successor until the previous
95 // successors that we had visited are fully processed. This ends up being revealed in the
96 // output of this method because the first time we see an edge to a block, we set the
97 // block's parent. So, if we have:
103 // And we're processing A, then we want to ensure that if we see A->B first (and hence set
104 // B's prenumber before we set C's) then we also end up setting C's parent to B by virtue
105 // of not noticing A->C until we're done processing B.
107 ExtendedBlockWorklist
<unsigned> worklist
;
108 worklist
.push(m_graph
.block(0), 0);
110 while (BlockWith
<unsigned> item
= worklist
.pop()) {
111 BasicBlock
* block
= item
.block
;
112 unsigned successorIndex
= item
.data
;
114 // We initially push with successorIndex = 0 regardless of whether or not we have any
115 // successors. This is so that we can assign our prenumber. Subsequently we get pushed
116 // with higher successorIndex values, but only if they are in range.
117 ASSERT(!successorIndex
|| successorIndex
< block
->numSuccessors());
119 if (!successorIndex
) {
120 m_data
[block
].semiNumber
= m_blockByPreNumber
.size();
121 m_blockByPreNumber
.append(block
);
124 if (successorIndex
< block
->numSuccessors()) {
125 unsigned nextSuccessorIndex
= successorIndex
+ 1;
126 if (nextSuccessorIndex
< block
->numSuccessors())
127 worklist
.forcePush(block
, nextSuccessorIndex
);
129 BasicBlock
* successorBlock
= block
->successor(successorIndex
);
130 if (worklist
.push(successorBlock
, 0))
131 m_data
[successorBlock
].parent
= block
;
136 void computeSemiDominatorsAndImplicitImmediateDominators()
138 for (unsigned currentPreNumber
= m_blockByPreNumber
.size(); currentPreNumber
-- > 1;) {
139 BasicBlock
* block
= m_blockByPreNumber
[currentPreNumber
];
140 BlockData
& blockData
= m_data
[block
];
143 for (BasicBlock
* predecessorBlock
: block
->predecessors
) {
144 BasicBlock
* intermediateBlock
= eval(predecessorBlock
);
145 blockData
.semiNumber
= std::min(
146 m_data
[intermediateBlock
].semiNumber
, blockData
.semiNumber
);
148 unsigned bucketPreNumber
= blockData
.semiNumber
;
149 ASSERT(bucketPreNumber
<= currentPreNumber
);
150 m_data
[m_blockByPreNumber
[bucketPreNumber
]].bucket
.append(block
);
151 link(blockData
.parent
, block
);
154 for (BasicBlock
* semiDominee
: m_data
[blockData
.parent
].bucket
) {
155 BasicBlock
* possibleDominator
= eval(semiDominee
);
156 BlockData
& semiDomineeData
= m_data
[semiDominee
];
157 ASSERT(m_blockByPreNumber
[semiDomineeData
.semiNumber
] == blockData
.parent
);
158 BlockData
& possibleDominatorData
= m_data
[possibleDominator
];
159 if (possibleDominatorData
.semiNumber
< semiDomineeData
.semiNumber
)
160 semiDomineeData
.dom
= possibleDominator
;
162 semiDomineeData
.dom
= blockData
.parent
;
164 m_data
[blockData
.parent
].bucket
.clear();
168 void computeExplicitImmediateDominators()
170 for (unsigned currentPreNumber
= 1; currentPreNumber
< m_blockByPreNumber
.size(); ++currentPreNumber
) {
171 BasicBlock
* block
= m_blockByPreNumber
[currentPreNumber
];
172 BlockData
& blockData
= m_data
[block
];
174 if (blockData
.dom
!= m_blockByPreNumber
[blockData
.semiNumber
])
175 blockData
.dom
= m_data
[blockData
.dom
].dom
;
179 void link(BasicBlock
* from
, BasicBlock
* to
)
181 m_data
[to
].ancestor
= from
;
184 BasicBlock
* eval(BasicBlock
* block
)
186 if (!m_data
[block
].ancestor
)
190 return m_data
[block
].label
;
193 void compress(BasicBlock
* initialBlock
)
195 // This was meant to be a recursive function, but we don't like recursion because we don't
196 // want to blow the stack. The original function will call compress() recursively on the
197 // ancestor of anything that has an ancestor. So, we populate our worklist with the
198 // recursive ancestors of initialBlock. Then we process the list starting from the block
199 // that is furthest up the ancestor chain.
201 BasicBlock
* ancestor
= m_data
[initialBlock
].ancestor
;
203 if (!m_data
[ancestor
].ancestor
)
206 Vector
<BasicBlock
*, 16> stack
;
207 for (BasicBlock
* block
= initialBlock
; block
; block
= m_data
[block
].ancestor
)
210 // We only care about blocks that have an ancestor that has an ancestor. The last two
211 // elements in the stack won't satisfy this property.
212 ASSERT(stack
.size() >= 2);
213 ASSERT(!m_data
[stack
[stack
.size() - 1]].ancestor
);
214 ASSERT(!m_data
[m_data
[stack
[stack
.size() - 2]].ancestor
].ancestor
);
216 for (unsigned i
= stack
.size() - 2; i
--;) {
217 BasicBlock
* block
= stack
[i
];
218 BasicBlock
*& labelOfBlock
= m_data
[block
].label
;
219 BasicBlock
*& ancestorOfBlock
= m_data
[block
].ancestor
;
220 ASSERT(ancestorOfBlock
);
221 ASSERT(m_data
[ancestorOfBlock
].ancestor
);
223 BasicBlock
* labelOfAncestorOfBlock
= m_data
[ancestorOfBlock
].label
;
225 if (m_data
[labelOfAncestorOfBlock
].semiNumber
< m_data
[labelOfBlock
].semiNumber
)
226 labelOfBlock
= labelOfAncestorOfBlock
;
227 ancestorOfBlock
= m_data
[ancestorOfBlock
].ancestor
;
234 , preNumber(UINT_MAX
)
235 , semiNumber(UINT_MAX
)
245 BasicBlock
* ancestor
;
247 Vector
<BasicBlock
*> bucket
;
252 BlockMap
<BlockData
> m_data
;
253 Vector
<BasicBlock
*> m_blockByPreNumber
;
256 struct ValidationContext
{
257 ValidationContext(Graph
& graph
, Dominators
& dominators
)
259 , dominators(dominators
)
263 void reportError(BasicBlock
* from
, BasicBlock
* to
, const char* message
)
268 error
.message
= message
;
269 errors
.append(error
);
274 if (errors
.isEmpty())
278 dataLog("DFG DOMINATOR VALIDATION FAILED:\n");
280 dataLog("For block domination relationships:\n");
281 for (unsigned i
= 0; i
< errors
.size(); ++i
) {
283 " ", pointerDump(errors
[i
].from
), " -> ", pointerDump(errors
[i
].to
),
284 " (", errors
[i
].message
, ")\n");
287 dataLog("Control flow graph:\n");
288 for (BlockIndex blockIndex
= 0; blockIndex
< graph
.numBlocks(); ++blockIndex
) {
289 BasicBlock
* block
= graph
.block(blockIndex
);
292 dataLog(" Block #", blockIndex
, ": successors = [");
294 for (unsigned i
= 0; i
< block
->numSuccessors(); ++i
)
295 dataLog(comma
, *block
->successor(i
));
296 dataLog("], predecessors = [");
297 comma
= CommaPrinter();
298 for (unsigned i
= 0; i
< block
->predecessors
.size(); ++i
)
299 dataLog(comma
, *block
->predecessors
[i
]);
303 dataLog("Lengauer-Tarjan Dominators:\n");
306 dataLog("Naive Dominators:\n");
307 naiveDominators
.dump(graph
, WTF::dataFile());
309 dataLog("Graph at time of failure:\n");
312 dataLog("DFG DOMINATOR VALIDATION FAILIED!\n");
317 Dominators
& dominators
;
318 NaiveDominators naiveDominators
;
326 Vector
<Error
> errors
;
329 } // anonymous namespace
331 void Dominators::compute(Graph
& graph
)
333 LengauerTarjan
lengauerTarjan(graph
);
334 lengauerTarjan
.compute();
336 m_data
= BlockMap
<BlockData
>(graph
);
338 // From here we want to build a spanning tree with both upward and downward links and we want
339 // to do a search over this tree to compute pre and post numbers that can be used for dominance
342 for (BlockIndex blockIndex
= graph
.numBlocks(); blockIndex
--;) {
343 BasicBlock
* block
= graph
.block(blockIndex
);
347 BasicBlock
* idomBlock
= lengauerTarjan
.immediateDominator(block
);
348 m_data
[block
].idomParent
= idomBlock
;
350 m_data
[idomBlock
].idomKids
.append(block
);
353 unsigned nextPreNumber
= 0;
354 unsigned nextPostNumber
= 0;
356 // Plain stack-based worklist because we are guaranteed to see each block exactly once anyway.
357 Vector
<BlockWithOrder
> worklist
;
358 worklist
.append(BlockWithOrder(graph
.block(0), PreOrder
));
359 while (!worklist
.isEmpty()) {
360 BlockWithOrder item
= worklist
.takeLast();
361 switch (item
.order
) {
363 m_data
[item
.block
].preNumber
= nextPreNumber
++;
364 worklist
.append(BlockWithOrder(item
.block
, PostOrder
));
365 for (BasicBlock
* kid
: m_data
[item
.block
].idomKids
)
366 worklist
.append(BlockWithOrder(kid
, PreOrder
));
369 m_data
[item
.block
].postNumber
= nextPostNumber
++;
374 if (validationEnabled()) {
375 // Check our dominator calculation:
376 // 1) Check that our range-based ancestry test is the same as a naive ancestry test.
377 // 2) Check that our notion of who dominates whom is identical to a naive (not
378 // Lengauer-Tarjan) dominator calculation.
380 ValidationContext
context(graph
, *this);
381 context
.naiveDominators
.compute(graph
);
383 for (BlockIndex fromBlockIndex
= graph
.numBlocks(); fromBlockIndex
--;) {
384 BasicBlock
* fromBlock
= graph
.block(fromBlockIndex
);
385 if (!fromBlock
|| m_data
[fromBlock
].preNumber
== UINT_MAX
)
387 for (BlockIndex toBlockIndex
= graph
.numBlocks(); toBlockIndex
--;) {
388 BasicBlock
* toBlock
= graph
.block(toBlockIndex
);
389 if (!toBlock
|| m_data
[toBlock
].preNumber
== UINT_MAX
)
392 if (dominates(fromBlock
, toBlock
) != naiveDominates(fromBlock
, toBlock
))
393 context
.reportError(fromBlock
, toBlock
, "Range-based domination check is broken");
394 if (dominates(fromBlock
, toBlock
) != context
.naiveDominators
.dominates(fromBlock
, toBlock
))
395 context
.reportError(fromBlock
, toBlock
, "Lengauer-Tarjan domination is broken");
399 context
.handleErrors();
403 BlockSet
Dominators::strictDominatorsOf(BasicBlock
* to
) const
406 forAllStrictDominatorsOf(to
, BlockAdder(result
));
410 BlockSet
Dominators::dominatorsOf(BasicBlock
* to
) const
413 forAllDominatorsOf(to
, BlockAdder(result
));
417 BlockSet
Dominators::blocksStrictlyDominatedBy(BasicBlock
* from
) const
420 forAllBlocksStrictlyDominatedBy(from
, BlockAdder(result
));
424 BlockSet
Dominators::blocksDominatedBy(BasicBlock
* from
) const
427 forAllBlocksDominatedBy(from
, BlockAdder(result
));
431 BlockSet
Dominators::dominanceFrontierOf(BasicBlock
* from
) const
434 forAllBlocksInDominanceFrontierOfImpl(from
, BlockAdder(result
));
438 BlockSet
Dominators::iteratedDominanceFrontierOf(const BlockList
& from
) const
441 forAllBlocksInIteratedDominanceFrontierOfImpl(from
, BlockAdder(result
));
445 bool Dominators::naiveDominates(BasicBlock
* from
, BasicBlock
* to
) const
447 for (BasicBlock
* block
= to
; block
; block
= m_data
[block
].idomParent
) {
454 void Dominators::dump(PrintStream
& out
) const
457 out
.print(" Not Valid.\n");
461 for (BlockIndex blockIndex
= 0; blockIndex
< m_data
.size(); ++blockIndex
) {
462 if (m_data
[blockIndex
].preNumber
== UINT_MAX
)
465 out
.print(" Block #", blockIndex
, ": idom = ", pointerDump(m_data
[blockIndex
].idomParent
), ", idomKids = [");
467 for (unsigned i
= 0; i
< m_data
[blockIndex
].idomKids
.size(); ++i
)
468 out
.print(comma
, *m_data
[blockIndex
].idomKids
[i
]);
469 out
.print("], pre/post = ", m_data
[blockIndex
].preNumber
, "/", m_data
[blockIndex
].postNumber
, "\n");
473 } } // namespace JSC::DFG
475 #endif // ENABLE(DFG_JIT)