/*
 * Copyright (C) 2015-2017 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. 
 */

#pragma once

#if ENABLE(B3_JIT)

#include "AirFrequentedBlock.h"
#include "AirInst.h"
#include "B3SuccessorCollection.h"
#include <wtf/FastMalloc.h>
#include <wtf/Noncopyable.h>

namespace JSC { namespace B3 {

template<typename> class GenericBlockInsertionSet;

namespace Air {

class BlockInsertionSet;
class Code;
class InsertionSet;
class PhaseInsertionSet;

class BasicBlock {
    WTF_MAKE_NONCOPYABLE(BasicBlock);
    WTF_MAKE_FAST_ALLOCATED;
public:
    static const char* const dumpPrefix;
    static constexpr unsigned uninsertedIndex = UINT_MAX;

    typedef Vector<Inst> InstList;
    typedef Vector<BasicBlock*, 2> PredecessorList;
    typedef Vector<FrequentedBlock, 2> SuccessorList;

    unsigned index() const { return m_index; }

    // This method is exposed for phases that mess with the layout of basic blocks. Currently that means just
    // optimizeBlockOrder().
    void setIndex(unsigned index) { m_index = index; }
    
    unsigned size() const { return m_insts.size(); }
    InstList::iterator begin() { return m_insts.begin(); }
    InstList::iterator end() { return m_insts.end(); }
    InstList::const_iterator begin() const { return m_insts.begin(); }
    InstList::const_iterator end() const { return m_insts.end(); }

    const Inst& at(unsigned index) const { return m_insts[index]; }
    Inst& at(unsigned index) { return m_insts[index]; }

    Inst* get(unsigned index)
    {
        return index < size() ? &at(index) : nullptr;
    }

    const Inst& last() const { return m_insts.last(); }
    Inst& last() { return m_insts.last(); }

    void resize(unsigned size) { m_insts.resize(size); }

    const InstList& insts() const { return m_insts; }
    InstList& insts() { return m_insts; }

    template<typename Inst>
    Inst& appendInst(Inst&& inst)
    {
        m_insts.append(std::forward<Inst>(inst));
        return m_insts.last();
    }

    template<typename... Arguments>
    Inst& append(Arguments&&... arguments)
    {
        m_insts.append(Inst(std::forward<Arguments>(arguments)...));
        return m_insts.last();
    }

    // The "0" case is the case to which the branch jumps, so the "then" case. The "1" case is the
    // "else" case, and is used to represent the fall-through of a conditional branch.
    unsigned numSuccessors() const { return m_successors.size(); }
    FrequentedBlock successor(unsigned index) const { return m_successors[index]; }
    FrequentedBlock& successor(unsigned index) { return m_successors[index]; }
    const SuccessorList& successors() const { return m_successors; }
    SuccessorList& successors() { return m_successors; }

    JS_EXPORT_PRIVATE void setSuccessors(FrequentedBlock);
    JS_EXPORT_PRIVATE void setSuccessors(FrequentedBlock, FrequentedBlock);

    BasicBlock* successorBlock(unsigned index) const { return successor(index).block(); }
    BasicBlock*& successorBlock(unsigned index) { return successor(index).block(); }
    SuccessorCollection<BasicBlock, SuccessorList> successorBlocks()
    {
        return SuccessorCollection<BasicBlock, SuccessorList>(m_successors);
    }
    SuccessorCollection<const BasicBlock, const SuccessorList> successorBlocks() const
    {
        return SuccessorCollection<const BasicBlock, const SuccessorList>(m_successors);
    }

    unsigned numPredecessors() const { return m_predecessors.size(); }
    BasicBlock* predecessor(unsigned index) const { return m_predecessors[index]; }
    BasicBlock*& predecessor(unsigned index) { return m_predecessors[index]; }
    const PredecessorList& predecessors() const { return m_predecessors; }
    PredecessorList& predecessors() { return m_predecessors; }

    bool addPredecessor(BasicBlock*);
    bool removePredecessor(BasicBlock*);
    bool replacePredecessor(BasicBlock* from, BasicBlock* to);
    bool containsPredecessor(BasicBlock* predecessor) const { return m_predecessors.contains(predecessor); }

    double frequency() const { return m_frequency; }

    void dump(PrintStream&) const;
    void deepDump(PrintStream&) const;

    void dumpHeader(PrintStream&) const;
    void dumpFooter(PrintStream&) const;

private:
    friend class BlockInsertionSet;
    friend class Code;
    friend class InsertionSet;
    friend class PhaseInsertionSet;
    template<typename> friend class B3::GenericBlockInsertionSet;
    
    BasicBlock(unsigned index, double frequency);

    unsigned m_index;
    InstList m_insts;
    SuccessorList m_successors;
    PredecessorList m_predecessors;
    double m_frequency;
};

class DeepBasicBlockDump {
public:
    DeepBasicBlockDump(const BasicBlock* block)
        : m_block(block)
    {
    }

    void dump(PrintStream& out) const
    {
        if (m_block)
            m_block->deepDump(out);
        else
            out.print("<null>");
    }

private:
    const BasicBlock* m_block;
};

inline DeepBasicBlockDump deepDump(const BasicBlock* block)
{
    return DeepBasicBlockDump(block);
}

} } } // namespace JSC::B3::Air

#endif // ENABLE(B3_JIT)
