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

#include "config.h"
#include "DFGSSACalculator.h"

#if ENABLE(DFG_JIT)

#include "DFGBlockMapInlines.h"
#include "JSCJSValueInlines.h"
#include <wtf/CommaPrinter.h>

namespace JSC { namespace DFG {

void SSACalculator::Variable::dump(PrintStream& out) const
{
    out.print("var", m_index);
}

void SSACalculator::Variable::dumpVerbose(PrintStream& out) const
{
    dump(out);
    if (!m_blocksWithDefs.isEmpty()) {
        out.print("(defs: ");
        CommaPrinter comma;
        for (BasicBlock* block : m_blocksWithDefs)
            out.print(comma, *block);
        out.print(")");
    }
}

void SSACalculator::Def::dump(PrintStream& out) const
{
    out.print("def(", *m_variable, ", ", *m_block, ", ", m_value, ")");
}

SSACalculator::SSACalculator(Graph& graph)
    : m_data(graph)
    , m_graph(graph)
{
}

SSACalculator::~SSACalculator()
{
}

void SSACalculator::reset()
{
    m_variables.clear();
    m_defs.clear();
    m_phis.clear();
    for (BlockIndex blockIndex = m_data.size(); blockIndex--;) {
        m_data[blockIndex].m_defs.clear();
        m_data[blockIndex].m_phis.clear();
    }
}

SSACalculator::Variable* SSACalculator::newVariable()
{
    return &m_variables.alloc(Variable(m_variables.size()));
}

SSACalculator::Def* SSACalculator::newDef(Variable* variable, BasicBlock* block, Node* value)
{
    Def* def = m_defs.add(Def(variable, block, value));
    auto result = m_data[block].m_defs.add(variable, def);
    if (result.isNewEntry)
        variable->m_blocksWithDefs.append(block);
    else
        result.iterator->value = def;
    return def;
}

SSACalculator::Def* SSACalculator::nonLocalReachingDef(BasicBlock* block, Variable* variable)
{
    return reachingDefAtTail(m_graph.m_ssaDominators->idom(block), variable);
}

SSACalculator::Def* SSACalculator::reachingDefAtTail(BasicBlock* block, Variable* variable)
{
    for (; block; block = m_graph.m_ssaDominators->idom(block)) {
        if (Def* def = m_data[block].m_defs.get(variable))
            return def;
    }
    return nullptr;
}

void SSACalculator::dump(PrintStream& out) const
{
    out.print("<Variables: [");
    CommaPrinter comma;
    for (unsigned i = 0; i < m_variables.size(); ++i) {
        out.print(comma);
        m_variables[i].dumpVerbose(out);
    }
    out.print("], \nDefs: [");
    comma = CommaPrinter();
    for (Def* def : const_cast<SSACalculator*>(this)->m_defs)
        out.print(comma, *def);
    out.print("], \nPhis: [");
    comma = CommaPrinter();
    for (Def* def : const_cast<SSACalculator*>(this)->m_phis)
        out.print(comma, *def);
    out.print("], \nBlock data: [");
    comma = CommaPrinter(",\n");
    for (BlockIndex blockIndex = 0; blockIndex < m_graph.numBlocks(); ++blockIndex) {
        BasicBlock* block = m_graph.block(blockIndex);
        if (!block)
            continue;
        
        out.print(comma, *block, "=>(");
        out.print("Defs: {");
        CommaPrinter innerComma;
        for (auto entry : m_data[block].m_defs)
            out.print(innerComma, *entry.key, "->", *entry.value);
        out.print("}, Phis: {");
        innerComma = CommaPrinter();
        for (Def* def : m_data[block].m_phis)
            out.print(innerComma, *def);
        out.print("})");
    }
    out.print("]>");
}

} } // namespace JSC::DFG

#endif // ENABLE(DFG_JIT)

