blob: e218ba792f261c1ad3f3055c7b0486eb1a9caa60 [file] [log] [blame]
/*
* Copyright (C) 2011, 2014 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef DFGDominators_h
#define DFGDominators_h
#if ENABLE(DFG_JIT)
#include "DFGAnalysis.h"
#include "DFGBasicBlock.h"
#include "DFGBlockMap.h"
#include "DFGBlockSet.h"
#include "DFGCommon.h"
namespace JSC { namespace DFG {
class Graph;
class Dominators : public Analysis<Dominators> {
public:
Dominators();
~Dominators();
void compute(Graph&);
bool strictlyDominates(BasicBlock* from, BasicBlock* to) const
{
ASSERT(isValid());
return m_data[to].preNumber > m_data[from].preNumber
&& m_data[to].postNumber < m_data[from].postNumber;
}
bool dominates(BasicBlock* from, BasicBlock* to) const
{
return from == to || strictlyDominates(from, to);
}
BasicBlock* immediateDominatorOf(BasicBlock* block) const
{
return m_data[block].idomParent;
}
template<typename Functor>
void forAllStrictDominatorsOf(BasicBlock* to, const Functor& functor) const
{
for (BasicBlock* block = m_data[to].idomParent; block; block = m_data[block].idomParent)
functor(block);
}
template<typename Functor>
void forAllDominatorsOf(BasicBlock* to, const Functor& functor) const
{
for (BasicBlock* block = to; block; block = m_data[block].idomParent)
functor(block);
}
template<typename Functor>
void forAllBlocksStrictlyDominatedBy(BasicBlock* from, const Functor& functor) const
{
Vector<BasicBlock*, 16> worklist;
worklist.appendVector(m_data[from].idomKids);
while (!worklist.isEmpty()) {
BasicBlock* block = worklist.takeLast();
functor(block);
worklist.appendVector(m_data[block].idomKids);
}
}
template<typename Functor>
void forAllBlocksDominatedBy(BasicBlock* from, const Functor& functor) const
{
Vector<BasicBlock*, 16> worklist;
worklist.append(from);
while (!worklist.isEmpty()) {
BasicBlock* block = worklist.takeLast();
functor(block);
worklist.appendVector(m_data[block].idomKids);
}
}
BlockSet strictDominatorsOf(BasicBlock* to) const;
BlockSet dominatorsOf(BasicBlock* to) const;
BlockSet blocksStrictlyDominatedBy(BasicBlock* from) const;
BlockSet blocksDominatedBy(BasicBlock* from) const;
template<typename Functor>
void forAllBlocksInDominanceFrontierOf(
BasicBlock* from, const Functor& functor) const
{
BlockSet set;
forAllBlocksInDominanceFrontierOfImpl(
from,
[&] (BasicBlock* block) {
if (set.add(block))
functor(block);
});
}
BlockSet dominanceFrontierOf(BasicBlock* from) const;
template<typename Functor>
void forAllBlocksInIteratedDominanceFrontierOf(
const BlockList& from, const Functor& functor)
{
forAllBlocksInPrunedIteratedDominanceFrontierOf(
from,
[&] (BasicBlock* block) -> bool {
functor(block);
return true;
});
}
// This is a close relative of forAllBlocksInIteratedDominanceFrontierOf(), which allows the
// given functor to return false to indicate that we don't wish to consider the given block.
// Useful for computing pruned SSA form.
template<typename Functor>
void forAllBlocksInPrunedIteratedDominanceFrontierOf(
const BlockList& from, const Functor& functor)
{
BlockSet set;
forAllBlocksInIteratedDominanceFrontierOfImpl(
from,
[&] (BasicBlock* block) -> bool {
if (!set.add(block))
return false;
return functor(block);
});
}
BlockSet iteratedDominanceFrontierOf(const BlockList& from) const;
void dump(PrintStream&) const;
private:
bool naiveDominates(BasicBlock* from, BasicBlock* to) const;
template<typename Functor>
void forAllBlocksInDominanceFrontierOfImpl(
BasicBlock* from, const Functor& functor) const
{
// Paraphrasing from http://en.wikipedia.org/wiki/Dominator_(graph_theory):
// "The dominance frontier of a block 'from' is the set of all blocks 'to' such that
// 'from' dominates an immediate predecessor of 'to', but 'from' does not strictly
// dominate 'to'."
//
// A useful corner case to remember: a block may be in its own dominance frontier if it has
// a loop edge to itself, since it dominates itself and so it dominates its own immediate
// predecessor, and a block never strictly dominates itself.
forAllBlocksDominatedBy(
from,
[&] (BasicBlock* block) {
for (unsigned successorIndex = block->numSuccessors(); successorIndex--;) {
BasicBlock* to = block->successor(successorIndex);
if (!strictlyDominates(from, to))
functor(to);
}
});
}
template<typename Functor>
void forAllBlocksInIteratedDominanceFrontierOfImpl(
const BlockList& from, const Functor& functor) const
{
BlockList worklist = from;
while (!worklist.isEmpty()) {
BasicBlock* block = worklist.takeLast();
forAllBlocksInDominanceFrontierOfImpl(
block,
[&] (BasicBlock* otherBlock) {
if (functor(otherBlock))
worklist.append(otherBlock);
});
}
}
struct BlockData {
BlockData()
: idomParent(nullptr)
, preNumber(UINT_MAX)
, postNumber(UINT_MAX)
{
}
Vector<BasicBlock*> idomKids;
BasicBlock* idomParent;
unsigned preNumber;
unsigned postNumber;
};
BlockMap<BlockData> m_data;
};
} } // namespace JSC::DFG
#endif // ENABLE(DFG_JIT)
#endif // DFGDominators_h