|  | /* | 
|  | * Copyright (C) 2013 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 DFGNaturalLoops_h | 
|  | #define DFGNaturalLoops_h | 
|  |  | 
|  | #if ENABLE(DFG_JIT) | 
|  |  | 
|  | #include "DFGAnalysis.h" | 
|  | #include "DFGBasicBlock.h" | 
|  | #include "DFGCommon.h" | 
|  |  | 
|  | namespace JSC { namespace DFG { | 
|  |  | 
|  | class NaturalLoops; | 
|  |  | 
|  | class NaturalLoop { | 
|  | public: | 
|  | NaturalLoop() | 
|  | : m_header(0) | 
|  | , m_outerLoopIndex(UINT_MAX) | 
|  | { | 
|  | } | 
|  |  | 
|  | NaturalLoop(BasicBlock* header, unsigned index) | 
|  | : m_header(header) | 
|  | , m_outerLoopIndex(UINT_MAX) | 
|  | , m_index(index) | 
|  | { | 
|  | } | 
|  |  | 
|  | BasicBlock* header() const { return m_header; } | 
|  |  | 
|  | unsigned size() const { return m_body.size(); } | 
|  | BasicBlock* at(unsigned i) const { return m_body[i]; } | 
|  | BasicBlock* operator[](unsigned i) const { return at(i); } | 
|  |  | 
|  | // This is the slower, but simpler, way of asking if a block belongs to | 
|  | // a natural loop. It's faster to call NaturalLoops::belongsTo(), which | 
|  | // tries to be O(loop depth) rather than O(loop size). Loop depth is | 
|  | // almost always smaller than loop size. A *lot* smaller. | 
|  | bool contains(BasicBlock* block) const | 
|  | { | 
|  | for (unsigned i = m_body.size(); i--;) { | 
|  | if (m_body[i] == block) | 
|  | return true; | 
|  | } | 
|  | ASSERT(block != header()); // Header should be contained. | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // The index of this loop in NaturalLoops. | 
|  | unsigned index() const { return m_index; } | 
|  |  | 
|  | bool isOuterMostLoop() const { return m_outerLoopIndex == UINT_MAX; } | 
|  |  | 
|  | void dump(PrintStream&) const; | 
|  | private: | 
|  | friend class NaturalLoops; | 
|  |  | 
|  | void addBlock(BasicBlock* block) { m_body.append(block); } | 
|  |  | 
|  | BasicBlock* m_header; | 
|  | Vector<BasicBlock*, 4> m_body; | 
|  | unsigned m_outerLoopIndex; | 
|  | unsigned m_index; | 
|  | }; | 
|  |  | 
|  | class NaturalLoops : public Analysis<NaturalLoops> { | 
|  | public: | 
|  | NaturalLoops(); | 
|  | ~NaturalLoops(); | 
|  |  | 
|  | void compute(Graph&); | 
|  |  | 
|  | unsigned numLoops() const | 
|  | { | 
|  | ASSERT(isValid()); | 
|  | return m_loops.size(); | 
|  | } | 
|  | const NaturalLoop& loop(unsigned i) const | 
|  | { | 
|  | ASSERT(isValid()); | 
|  | return m_loops[i]; | 
|  | } | 
|  |  | 
|  | // Return either null if the block isn't a loop header, or the | 
|  | // loop it belongs to. | 
|  | const NaturalLoop* headerOf(BasicBlock* block) const | 
|  | { | 
|  | ASSERT(isValid()); | 
|  | const NaturalLoop* loop = innerMostLoopOf(block); | 
|  | if (!loop) | 
|  | return 0; | 
|  | if (loop->header() == block) | 
|  | return loop; | 
|  | if (!ASSERT_DISABLED) { | 
|  | for (; loop; loop = innerMostOuterLoop(*loop)) | 
|  | ASSERT(loop->header() != block); | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | const NaturalLoop* innerMostLoopOf(BasicBlock* block) const | 
|  | { | 
|  | ASSERT(isValid()); | 
|  | unsigned index = block->innerMostLoopIndices[0]; | 
|  | if (index == UINT_MAX) | 
|  | return 0; | 
|  | return &m_loops[index]; | 
|  | } | 
|  |  | 
|  | const NaturalLoop* innerMostOuterLoop(const NaturalLoop& loop) const | 
|  | { | 
|  | ASSERT(isValid()); | 
|  | if (loop.m_outerLoopIndex == UINT_MAX) | 
|  | return 0; | 
|  | return &m_loops[loop.m_outerLoopIndex]; | 
|  | } | 
|  |  | 
|  | bool belongsTo(BasicBlock* block, const NaturalLoop& candidateLoop) const | 
|  | { | 
|  | ASSERT(isValid()); | 
|  | // It's faster to do this test using the loop itself, if it's small. | 
|  | if (candidateLoop.size() < 4) | 
|  | return candidateLoop.contains(block); | 
|  |  | 
|  | for (const NaturalLoop* loop = innerMostLoopOf(block); loop; loop = innerMostOuterLoop(*loop)) { | 
|  | if (loop == &candidateLoop) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | unsigned loopDepth(BasicBlock* block) const | 
|  | { | 
|  | unsigned depth = 0; | 
|  | for (const NaturalLoop* loop = innerMostLoopOf(block); loop; loop = innerMostOuterLoop(*loop)) | 
|  | depth++; | 
|  | return depth; | 
|  | } | 
|  |  | 
|  | // Return the indices of all loops this belongs to. | 
|  | Vector<const NaturalLoop*> loopsOf(BasicBlock*) const; | 
|  |  | 
|  | void dump(PrintStream&) const; | 
|  | private: | 
|  | // If we ever had a scalability problem in our natural loop finder, we could | 
|  | // use some HashMap's here. But it just feels a heck of a lot less convenient. | 
|  | Vector<NaturalLoop, 4> m_loops; | 
|  | }; | 
|  |  | 
|  | } } // namespace JSC::DFG | 
|  |  | 
|  | #endif // ENABLE(DFG_JIT) | 
|  |  | 
|  | #endif // DFGNaturalLoops_h | 
|  |  |