QString Value::asString() const
{
    QString result;

    if (type() == Value::String)
        if (d->ps)
            result = QString(*d->ps);

    return result;
}

// This file is part of the KDE project

#include "Value.h"
#include "CalculationSettings.h"
#include "ValueStorage.h"
#include "SheetsDebug.h"

#include <KLocalizedString>

#include <QString>
#include <QTextStream>

#include <float.h>
#include <math.h>
#include <limits.h>

using namespace Calligra::Sheets;

class ValueArray
{
public:
    ValueArray() : m_size(0, 0) {}
    ValueArray(const ValueStorage& storage, const QSize& size) : m_size(size), m_storage(storage) {}

    ValueStorage& storage() { return m_storage; }
    int rows() const { return qMax(m_size.height(), m_storage.rows()); }
    int columns() const { return qMax(m_size.width(), m_storage.columns()); }

    bool operator==(const ValueArray& a) const { return rows() == a.rows() && columns() == a.columns() && m_storage == a.m_storage; }
private:
    QSize m_size;
    ValueStorage m_storage;
};

class Q_DECL_HIDDEN Value::Private : public QSharedData
{
public:

    Value::Type type: 4;
    Value::Format format: 4;

    union { // 64 bits at max!
        // b is also secondarily used to indicate a null value if type == Empty,
        // without using up space for an explicit member variable.
        bool b;
        qint64 i;
        Number f;
        complex<Number>* pc;
        QString* ps;
        ValueArray* pa;
    };

    // create empty data
    Private() : type(Value::Empty), format(Value::fmt_None), ps(0) {}

    Private(const Private& o)
            : QSharedData(o)
            , type(o.type)
            , format(o.format) {
        switch (type) {
        case Value::Empty:
        default:
            ps = 0;
            break;
        case Value::Boolean:
            b = o.b;
            break;
        case Value::Integer:
            i = o.i;
            break;
        case Value::Float:
            f = o.f;
            break;
        case Value::Complex:
            pc = new complex<Number>(*o.pc);
            break;
        case Value::String:
        case Value::Error:
            ps = new QString(*o.ps);
            break;
        case Value::Array:
            pa = new ValueArray(*o.pa);
            break;
        }
    }

    // destroys data
    ~Private() {
        if (this == s_null)
            s_null = 0;
        clear();
    }

    // static empty data to be shared
    static Private* null() {
        if (!s_null) s_null = new Private;
        return s_null;
    }

    // true if it's null (which is shared)
    bool isNull() {
        return this == s_null;
    }

    /** Deletes all data. */
    void clear() {
        if (type == Value::Array)   delete pa;
        if (type == Value::Complex) delete pc;
        if (type == Value::Error)   delete ps;
        if (type == Value::String)  delete ps;
        type = Value::Empty;
        b = 0;
    }

    /** set most probable formatting based on the type */
    void setFormatByType();

private:
    void operator=(const Value::Private& o);

    static Private* s_null;
};

void Value::Private::setFormatByType()
{
    switch (type) {
    case Value::Empty:
        format = Value::fmt_None;
        break;
    case Value::Boolean:
        format = Value::fmt_Boolean;
        break;
    case Value::Integer:
    case Value::Float:
    case Value::Complex:
        format = Value::fmt_Number;
        break;
    case Value::String:
        format = Value::fmt_String;
        break;
    case Value::Array:
        format = Value::fmt_None;
        break;
    case Value::CellRange:
        format = Value::fmt_None;
        break;
    case Value::Error:
        format = Value::fmt_String;
        break;
    };
}

// to be shared between all empty value
Value::Private* Value::Private::s_null = 0;

Value ks_value_empty;
Value ks_value_null;
Value ks_error_circle;
Value ks_error_depend;
Value ks_error_div0;
Value ks_error_na;
Value ks_error_name;
Value ks_error_null;
Value ks_error_num;
Value ks_error_parse;
Value ks_error_ref;
Value ks_error_value;

// create an empty value
Value::Value()
        : d(Private::null())
{
}

// destructor
Value::~Value()
{
}

// create value of certain type
Value::Value(Value::Type _type)
        : d(Private::null())
{
    d->type = _type;
    d->setFormatByType();
}

// copy constructor
Value::Value(const Value& _value)
        : d(_value.d)
{
}

// assignment operator
Value& Value::operator=(const Value & _value)
{
    d = _value.d;
    return *this;
}

// comparison operator - returns true only if strictly identical, unlike equal()/compare()
bool Value::operator==(const Value& o) const
{
    if (d->type != o.d->type)
        return false;
    switch (d->type) {
    // null() (d->b == 1) and empty() (d->b == 0) are equal to this operator
    case Empty:   return true;
    case Boolean: return o.d->b == d->b;
    case Integer: return o.d->i == d->i;
    case Float:   return compare(o.d->f, d->f) == 0;
    case Complex: return (!d->pc && !o.d->pc) || ((d->pc && o.d->pc) && (*o.d->pc == *d->pc));
    case String:  return (!d->ps && !o.d->ps) || ((d->ps && o.d->ps) && (*o.d->ps == *d->ps));
    case Array:   return (!d->pa && !o.d->pa) || ((d->pa && o.d->pa) && (*o.d->pa == *d->pa));
    case Error:   return (!d->ps && !o.d->ps) || ((d->ps && o.d->ps) && (*o.d->ps == *d->ps));
    default: break;
    }
    warnSheets << "Unhandled type in Value::operator==: " << d->type;
    return false;
}

// create a boolean value
Value::Value(bool b)
        : d(Private::null())
{
    d->type = Boolean;
    d->b = b;
    d->format = fmt_Boolean;
}

// create an integer value
Value::Value(qint64 i)
        : d(Private::null())
{
    d->type = Integer;
    d->i = i;
    d->format = fmt_Number;
}

// create an integer value
Value::Value(int i)
        : d(Private::null())
{
    d->type = Integer;
    d->i = static_cast<qint64>(i);
    d->format = fmt_Number;
}

// create a floating-point value
Value::Value(double f)
        : d(Private::null())
{
    d->type = Float;
    d->f = Number(f);
    d->format = fmt_Number;
}

// create a floating-point value
Value::Value(long double f)
        : d(Private::null())
{
    d->type = Float;
    d->f = Number(f);
    d->format = fmt_Number;
}

#ifdef CALLIGRA_SHEETS_HIGH_PRECISION_SUPPORT
// create a floating-point value
Value::Value(Number f)
        : d(Private::null())
{
    d->type = Float;
    d->f = f;
    d->format = fmt_Number;
}
#endif // CALLIGRA_SHEETS_HIGH_PRECISION_SUPPORT

// create a complex number value
Value::Value(const complex<Number>& c)
        : d(Private::null())
{
    d->type = Complex;
    d->pc = new complex<Number>(c);
    d->format = fmt_Number;
}

// create a string value
Value::Value(const QString& s)
        : d(Private::null())
{
    d->type = String;
    d->ps = new QString(s);
    d->format = fmt_String;
}

// create a string value
Value::Value(const char *s)
        : d(Private::null())
{
    d->type = String;
    d->ps = new QString(s);
    d->format = fmt_String;
}

// create a floating-point value from date/time
Value::Value(const QDateTime& dt, const CalculationSettings* settings)
        : d(Private::null())
{
    const QDate refDate(settings->referenceDate());
    const QTime refTime(0, 0);    // reference time is midnight
    d->type = Float;
    d->f = Number(refDate.daysTo(dt.date()));
    d->f += static_cast<double>(refTime.msecsTo(dt.time())) / 86400000.0;     // 24*60*60*1000
    d->format = fmt_DateTime;
}

// create a floating-point value from time
Value::Value(const QTime& time)
        : d(Private::null())
{
    const QTime refTime(0, 0);    // reference time is midnight

    d->type = Float;
    d->f = Number(static_cast<double>(refTime.msecsTo(time)) / 86400000.0);      // 24*60*60*1000
    d->format = fmt_Time;
}

// create a floating-point value from date
Value::Value(const QDate& date, const CalculationSettings* settings)
        : d(Private::null())
{
    const QDate refDate(settings->referenceDate());

    d->type = Integer;
    d->i = refDate.daysTo(date);
    d->format = fmt_Date;
}

// create an array value
Value::Value(const ValueStorage& array, const QSize& size)
        : d(Private::null())
{
    d->type = Array;
    d->pa = new ValueArray(array, size);
    d->format = fmt_None;
}

// return type of the value
Value::Type Value::type() const
{
    return d ? d->type : Empty;
}

bool Value::isNull() const
{
    return d ? d->type == Empty && d->b : false;
}

// get the value as boolean
bool Value::asBoolean() const
{
    bool result = false;

    if (type() == Value::Boolean)
        result = d->b;

    return result;
}

// get the value as integer
qint64 Value::asInteger() const
{
    qint64 result = 0;
    if (type() == Integer)
        result = d->i;
    else if (type() == Float)
        result = static_cast<qint64>(floor(numToDouble(d->f)));
    else if (type() == Complex)
        result = static_cast<qint64>(floor(numToDouble(d->pc->real())));
    return result;
}

// get the value as floating-point
Number Value::asFloat() const
{
    Number result = 0.0;
    if (type() == Float)
        result = d->f;
    else if (type() == Integer)
        result = static_cast<Number>(d->i);
    else if (type() == Complex)
        result = d->pc->real();
    return result;
}

// get the value as complex number
complex<Number> Value::asComplex() const
{
    complex<Number> result(0.0, 0.0);
    if (type() == Complex)
        result = *d->pc;
    else if (type() == Float)
        result = d->f;
    else if (type() == Integer)
        result = static_cast<Number>(d->i);
    return result;
}

// get the value as string

QString Value::asStringWithDoubleQuotes() const
{
    QString s = asString();
    if (type() == Value::String) {
        if (!(s.startsWith(QLatin1Char('\"')) && s.endsWith(QLatin1Char('\"')))) {
            if (s.startsWith(QLatin1Char('\'')) && s.endsWith(QLatin1Char('\'')))
                s = s.mid(1, s.length()-2);
            s = QLatin1Char('\"') + s + QLatin1Char('\"');
        }
    }
    return s;
}

// get the value as QVariant
QVariant Value::asVariant() const
{
    QVariant result;

    switch (d->type) {
    case Value::Empty:
    default:
        result = 0;
        break;
    case Value::Boolean:
        result = d->b;
        break;
    case Value::Integer:
        result = d->i;
        break;
    case Value::Float:
        result = (double) numToDouble(d->f);
        break;
    case Value::Complex:
        // FIXME: add support for complex numbers
        break;
    case Value::String:
    case Value::Error:
        result = *d->ps;
        break;
    case Value::Array:
        // FIXME: not supported yet
        break;
    }

    return result;
}

// set error message
void Value::setError(const QString& msg)
{
    d->clear();
    d->type = Error;
    d->ps = new QString(msg);
}

// get error message
QString Value::errorMessage() const
{
    QString result;

    if (type() == Value::Error)
        if (d->ps)
            result = QString(*d->ps);

    return result;
}

// get the value as date/time
QDateTime Value::asDateTime(const CalculationSettings* settings) const
{
    QDateTime datetime(settings->referenceDate(), QTime(), Qt::UTC);

    const int days = asInteger();
    const int msecs = ::round((numToDouble(asFloat() - double(days))) * 86400000.0);      // 24*60*60*1000
    datetime = datetime.addDays(days);
    datetime = datetime.addMSecs(msecs);

    return datetime;
}

// get the value as date
QDate Value::asDate(const CalculationSettings* settings) const
{
    QDate dt(settings->referenceDate());

    int i = asInteger();
    dt = dt.addDays(i);

    return dt;
}

// get the value as time
QTime Value::asTime() const
{
    QTime dt(0, 0, 0, 0);

    const int days = asInteger();
    const int msecs = ::round(numToDouble(asFloat() - double(days)) * 86400000.0);      // 24*60*60*1000
    dt = dt.addMSecs(msecs);

    return dt;
}

Value::Format Value::format() const
{
    return d ? d->format : fmt_None;
}

void Value::setFormat(Value::Format fmt)
{
    d->format = fmt;
}

Value Value::element(unsigned column, unsigned row) const
{
    if (d->type != Array) return *this;
    if (!d->pa) return empty();
    return d->pa->storage().lookup(column + 1, row + 1);
}

Value Value::element(unsigned index) const
{
    if (d->type != Array) return *this;
    if (!d->pa) return empty();
    return d->pa->storage().data(index);
}

void Value::setElement(unsigned column, unsigned row, const Value& v)
{
    if (d->type != Array) return;
    if (!d->pa) d->pa = new ValueArray();
    d->pa->storage().insert(column + 1, row + 1, v);
}

unsigned Value::columns() const
{
    if (d->type != Array) return 1;
    if (!d->pa) return 1;
    return d->pa->columns();
}

unsigned Value::rows() const
{
    if (d->type != Array) return 1;
    if (!d->pa) return 1;
    return d->pa->rows();
}

unsigned Value::count() const
{
    if (d->type != Array) return 1;
    if (!d->pa) return 1;
    return d->pa->storage().count();
}

// reference to empty value
const Value& Value::empty()
{
    return ks_value_empty;
}

// reference to null value
const Value& Value::null()
{
    if (!ks_value_null.isNull())
        ks_value_null.d->b = true;
    return ks_value_null;
}

// reference to #CIRCLE! error
const Value& Value::errorCIRCLE()
{
    if (!ks_error_circle.isError())
        ks_error_circle.setError(i18nc("Error: circular formula dependency", "#CIRCLE!"));
    return ks_error_circle;
}

// reference to #DEPEND! error
const Value& Value::errorDEPEND()
{
    if (!ks_error_depend.isError())
        ks_error_depend.setError(i18nc("Error: broken cell reference", "#DEPEND!"));
    return ks_error_depend;
}

const Value& Value::errorDIV0()
{
    if (!ks_error_div0.isError())
        ks_error_div0.setError(i18nc("Error: division by zero", "#DIV/0!"));
    return ks_error_div0;
}

// reference to #N/A error
const Value& Value::errorNA()
{
    if (!ks_error_na.isError())
        ks_error_na.setError(i18nc("Error: not available", "#N/A"));
    return ks_error_na;
}

// reference to #NAME? error
const Value& Value::errorNAME()
{
    if (!ks_error_name.isError())
        ks_error_name.setError(i18nc("Error: unknown function name", "#NAME?"));
    return ks_error_name;
}

// reference to #NUM! error
const Value& Value::errorNUM()
{
    if (!ks_error_num.isError())
        ks_error_num.setError(i18nc("Error: number out of range", "#NUM!"));
    return ks_error_num;
}

// reference to #NULL! error
const Value& Value::errorNULL()
{
    if (!ks_error_null.isError())
        ks_error_null.setError(i18nc("Error: empty intersecting area", "#NULL!"));
    return ks_error_null;
}

// reference to #PARSE! error
const Value& Value::errorPARSE()
{
    if (!ks_error_parse.isError())
        ks_error_parse.setError(i18nc("Error: formula not parseable", "#PARSE!"));
    return ks_error_parse;
}

// reference to #REF! error
const Value& Value::errorREF()
{
    if (!ks_error_ref.isError())
        ks_error_ref.setError(i18nc("Error: invalid cell/array reference", "#REF!"));
    return ks_error_ref;
}

// reference to #VALUE! error
const Value& Value::errorVALUE()
{
    if (!ks_error_value.isError())
        ks_error_value.setError(i18nc("Error: wrong (number of) function argument(s)", "#VALUE!"));
    return ks_error_value;
}

int Value::compare(Number v1, Number v2)
{
    Number v3 = v1 - v2;
    if (v3 > DBL_EPSILON) return 1;
    if (v3 < -DBL_EPSILON) return -1;
    return 0;
}

bool Value::isZero(Number v)
{
    return abs(v) < DBL_EPSILON;
}

bool Value::isZero() const
{
    if (!isNumber()) return false;
    return isZero(asFloat());
}

bool Value::allowComparison(const Value& v) const
{
    Value::Type t1 = d->type;
    Value::Type t2 = v.type();

    if ((t1 == Empty) && (t2 == Empty)) return true;
    if ((t1 == Empty) && (t2 == String)) return true;
    if ((t1 == Empty) && (t2 == Integer)) return true;
    if ((t1 == Empty) && (t2 == Float)) return true;
    if ((t1 == Empty) && (t2 == Boolean)) return true;

    if ((t1 == Boolean) && (t2 == Boolean)) return true;
    if ((t1 == Boolean) && (t2 == Integer)) return true;
    if ((t1 == Boolean) && (t2 == Float)) return true;
    if ((t1 == Boolean) && (t2 == String)) return true;

    if ((t1 == Integer) && (t2 == Boolean)) return true;
    if ((t1 == Integer) && (t2 == Integer)) return true;
    if ((t1 == Integer) && (t2 == Float)) return true;
    if ((t1 == Integer) && (t2 == String)) return true;

    if ((t1 == Float) && (t2 == Boolean)) return true;
    if ((t1 == Float) && (t2 == Integer)) return true;
    if ((t1 == Float) && (t2 == Float)) return true;
    if ((t1 == Float) && (t2 == String)) return true;

    if ((t1 == Complex) && (t2 == Boolean)) return true;
    if ((t1 == Complex) && (t2 == Integer)) return true;
    if ((t1 == Complex) && (t2 == Float)) return true;
    if ((t1 == Complex) && (t2 == String)) return true;

    if ((t1 == String) && (t2 == Empty)) return true;
    if ((t1 == String) && (t2 == Boolean)) return true;
    if ((t1 == String) && (t2 == Integer)) return true;
    if ((t1 == String) && (t2 == Float)) return true;
    if ((t1 == String) && (t2 == Complex)) return true;
    if ((t1 == String) && (t2 == String)) return true;

    // errors can be compared too ...
    if ((t1 == Error) && (t2 == Error)) return true;

    return false;
}

// compare values. looks strange in order to be compatible with Excel
int Value::compare(const Value& v, Qt::CaseSensitivity cs) const
{
    Value::Type t1 = d->type;
    Value::Type t2 = v.type();

    // errors always less than everything else
    if ((t1 == Error) && (t2 != Error))
        return -1;
    if ((t2 == Error) && (t1 != Error))
        return 1;

    // comparing errors only yields 0 if they are the same
    if ((t1 == Error) && (t2 == Error))
        return errorMessage() != v.errorMessage();

    if ((t1 == Empty) && (t2 == Empty))
        return 0;

    // empty value is always less than string
    // (except when the string is empty)
    if ((t1 == Empty) && (t2 == String))
        return(v.asString().isEmpty()) ? 0 : -1;

    // empty vs integer
    if ((t1 == Empty) && (t2 == Integer))
        return -1;

    // empty vs float
    if ((t1  == Empty) && (t2 == Float))
        return -1;

    // empty vs boolean
    if ((t1 == Empty) && (t2 == Boolean))
        return -1;

    if ((t1 == Boolean) && (t2 == Boolean)) {
        bool p = asBoolean();
        bool q = v.asBoolean();
        if (p) return q ? 0 : 1;
        else return q ? -1 : 0;
    }

    // boolean is always greater than integer
    if ((t1 == Boolean) && (t2 == Integer))
        return 1;

    // boolean is always greater than float
    if ((t1 == Boolean) && (t2 == Float))
        return 1;

    // boolean is always greater than string
    if ((t1 == Boolean) && (t2 == String))
        return 1;

    // integer is always less than boolean
    if ((t1 == Integer) && (t2 == Boolean))
        return -1;

    // integer vs integer
    if ((t1 == Integer) && (t2 == Integer)) {
        qint64 p = asInteger();
        qint64 q = v.asInteger();
        return (p == q) ? 0 : (p < q) ? -1 : 1;
    }

    if ((t1 == Integer) && (t2 == Float))
        return compare(asFloat(), v.asFloat());

    // integer is always less than string
    if ((t1 == Integer) && (t2 == String))
        return -1;

    // float is always less than boolean
    if ((t1 == Float) && (t2 == Boolean))
        return -1;

    if ((t1 == Float) && (t2 == Integer))
        return compare(asFloat(), v.asFloat());

    if ((t1 == Float) && (t2 == Float))
        return compare(asFloat(), v.asFloat());

    // float is always less than string
    if ((t1 == Float) && (t2 == String))
        return -1;

    // TODO Stefan: Complex

    // string is always greater than empty value
    // (except when the string is empty)
    if ((t1 == String) && (t2 == Empty))
        return(asString().isEmpty()) ? 0 : 1;

    // string is always less than boolean
    if ((t1 == String) && (t2 == Boolean))
        return -1;

    // string is always greater than integer
    if ((t1 == String) && (t2 == Integer))
        return 1;

    // string is always greater than float
    if ((t1 == String) && (t2 == Float))
        return 1;

    // The-Real-String comparison
    if ((t1 == String) && (t2 == String))
        return asString().compare(v.asString(), cs);

    // Undefined, actually allowComparison would return false
    return 0;
}

bool Value::equal(const Value& v, Qt::CaseSensitivity cs) const
{
    if (!allowComparison(v)) return false;
    return compare(v, cs) == 0;
}

bool Value::less(const Value& v, Qt::CaseSensitivity cs) const
{
    if (!allowComparison(v)) return false;
    return compare(v, cs) < 0;
}

bool Value::greater(const Value& v, Qt::CaseSensitivity cs) const
{
    if (!allowComparison(v)) return false;
    return compare(v, cs) > 0;
}

QTextStream& operator<<(QTextStream& ts, Value::Type type)
{
    switch (type) {
    case Value::Empty:   ts << "Empty"; break;
    case Value::Boolean: ts << "Boolean"; break;
    case Value::Integer: ts << "Integer"; break;
    case Value::Float:   ts << "Float"; break;
    case Value::Complex: ts << "Complex"; break;
    case Value::String:  ts << "String"; break;
    case Value::Array:   ts << "Array"; break;
    case Value::Error:   ts << "Error"; break;
    default: ts << "Unknown!"; break;
    };
    return ts;
}

QTextStream& operator<<(QTextStream& ts, Value value)
{
    ts << value.type();
    switch (value.type()) {
    case Value::Empty:   break;

    case Value::Boolean:
        ts << ": ";
        if (value.asBoolean()) ts << "TRUE";
        else ts << "FALSE";
        break;

    case Value::Integer:
        ts << ": " << value.asInteger(); break;

    case Value::Float:
        ts << ": " << (double) numToDouble(value.asFloat()); break;

    case Value::Complex: {
        const complex<Number> complex(value.asComplex());
        ts << ": " << (double) numToDouble(complex.real());
        if (complex.imag() >= 0.0)
            ts << '+';
        ts << (double) numToDouble(complex.imag()) << 'i';
        break;
    }

    case Value::String:
        ts << ": " << value.asString(); break;

    case Value::Array: {
        ts << ": {" << value.asString();
        const int cols = value.columns();
        const int rows = value.rows();
        for (int row = 0; row < rows; ++row) {
            for (int col = 0; col < cols; ++col) {
                ts << value.element(col, row);
                if (col < cols - 1)
                    ts << ';';
            }
            if (row < rows - 1)
                ts << '|';
        }
        ts << '}';
        break;
    }

    case Value::Error:
        ts << '(' << value.errorMessage() << ')'; break;

    default: break;
    }
    return ts;
}

/***************************************************************************
  QHash/QSet support
****************************************************************************/

namespace Calligra
{
namespace Sheets
{
uint qHash(const Value& value)
{
    switch (value.type()) {
    case Value::Empty:
    case Value::CellRange:
        return 0;
    case Value::Boolean:
        return ::qHash(value.asBoolean());
    case Value::Integer:
        return ::qHash(value.asInteger());
    case Value::Float:
        return ::qHash((qint64)numToDouble(value.asFloat()));
    case Value::Complex:
        return ::qHash((qint64)value.asComplex().real());
    case Value::String:
        return ::qHash(value.asString());
    case Value::Array:
        return qHash(value.element(0, 0));
    case Value::Error:
        return ::qHash(value.errorMessage());
    }
    return 0;
}
} // namespace Sheets
} // namespace Calligra

/***************************************************************************
  QDebug support
****************************************************************************/

QDebug operator<<(QDebug str, const Calligra::Sheets::Value& v)
{
    QString string;
    QTextStream stream(&string);
    stream << v;
    str << string;
    return str;
}

QDebug operator<<(QDebug stream, const Calligra::Sheets::Value::Format& f)
{
    switch (f) {
    case Calligra::Sheets::Value::fmt_None:     stream << "None";     break;
    case Calligra::Sheets::Value::fmt_Boolean:  stream << "Boolean";  break;
    case Calligra::Sheets::Value::fmt_Number:   stream << "Number";   break;
    case Calligra::Sheets::Value::fmt_Percent:  stream << "Percent";  break;
    case Calligra::Sheets::Value::fmt_Money:    stream << "Money";    break;
    case Calligra::Sheets::Value::fmt_DateTime: stream << "DateTime"; break;
    case Calligra::Sheets::Value::fmt_Date:     stream << "Date";     break;
    case Calligra::Sheets::Value::fmt_Time:     stream << "Time";     break;
    case Calligra::Sheets::Value::fmt_String:   stream << "String";   break;
    }
    return stream;
}


try {
            load_fs_curv (path, mesh);
          } catch (Exception& e) {
            DEBUG (e[0]);
            throw Exception ("Input surface scalar file \"" + path + "\" not in supported format");
          }

/*
 *
 *
 * statutory, including, without limitation, warranties that the
 * Covered Software is free of defects, merchantable, fit for a
 * particular purpose or non-infringing.
 *
 * For more details, see http://example.com.
 */

#include "surface/scalar.h"

#include "math/math.h"

#include "surface/freesurfer.h"

namespace MR
{
  namespace Surface
  {

    Scalar::Scalar (const std::string& path, const Mesh& mesh)
    {
      DEBUG ("Attempting to load surface scalar file \"" + path + "\"...");
      try {
        load_vector (path);
      } catch (Exception& e) {
        DEBUG (e[0]);
        try {
          load_fs_w (path, mesh);
        } catch (Exception& e) {
          DEBUG (e[0]);

        }
      }
      if (size_t(size()) != mesh.num_vertices())
        throw Exception ("Input surface scalar file \"" + path + "\" has incorrect number of vertices (" + str(size()) + ", mesh has " + str (mesh.num_vertices()) + ")");
      name = Path::basename (path);
    }

    void Scalar::save (const std::string& path) const
    {
      save_vector (*this, path);
    }

    void Scalar::load_fs_w (const std::string& path, const Mesh& mesh)
    {
      std::ifstream in (path, std::ios_base::in | std::ios_base::binary);
      if (!in)
        throw Exception ("Error opening surface scalar file \"" + path + "\"");

      FreeSurfer::get_BE<int16_t> (in); // 'latency'
      const int32_t num_entries = FreeSurfer::get_int24_BE (in);
      Base::operator= (Base::Zero (num_entries));
      for (int32_t i = 0; i != num_entries; ++i) {
        const int32_t index = FreeSurfer::get_int24_BE (in);
        const float value = FreeSurfer::get_BE<float> (in);
        if (size_t(index) >= mesh.num_vertices())
          throw Exception ("Error opening file \"" + path + "\" as FreeSurfer w-file: invalid vertex index (" + str(index) + ", mesh has " + str(mesh.num_vertices()) + ")");
        if (!in.good())
          throw Exception ("Error opening file \"" + path + "\" as FreeSurfer w-file: truncated file");
        (*this)[index] = value;
      }
    }

    void Scalar::load_fs_curv (const std::string& path, const Mesh& mesh)
    {
      std::ifstream in (path, std::ios_base::in | std::ios_base::binary);
      if (!in)
        throw Exception ("Error opening surface scalar file \"" + path + "\"");

      const int32_t magic_number = FreeSurfer::get_int24_BE (in);
      if (magic_number == FreeSurfer::new_curv_file_magic_number) {

        const int32_t num_vertices = FreeSurfer::get_BE<int32_t> (in);
        if (size_t(num_vertices) != mesh.num_vertices())
          throw Exception ("Error opening file \"" + path + "\" as Freesurfer curv file: Incorrect number of vertices (" + str(num_vertices) + ", mesh has " + str(mesh.num_vertices()) + ")");

        const int32_t num_faces = FreeSurfer::get_BE<int32_t> (in);
        if (size_t(num_faces) != mesh.num_polygons())
          throw Exception ("Error opening file \"" + path + "\" as Freesurfer curv file: Incorrect number of polygons (" + str(num_faces) + ", mesh has " + str(mesh.num_polygons()) + ")");

        const int32_t vals_per_vertex = FreeSurfer::get_BE<int32_t> (in);
        if (vals_per_vertex != 1)
          throw Exception ("Error opening file \"" + path + "\" as Freesurfer curv file: Only support 1 value per vertex");

        (*this).resize (num_vertices);
        for (int32_t i = 0; i != num_vertices; ++i)
          (*this)[i] = FreeSurfer::get_BE<float> (in);

      } else {

        const int32_t num_vertices = magic_number;
        if (size_t(num_vertices) != mesh.num_vertices())
          throw Exception ("Error opening file \"" + path + "\" as Freesurfer curv file: Incorrect number of vertices (" + str(num_vertices) + ", mesh has " + str(mesh.num_vertices()) + ")");

        const int32_t num_faces = FreeSurfer::get_int24_BE (in);
        if (size_t(num_faces) != mesh.num_polygons())
          throw Exception ("Error opening file \"" + path + "\" as Freesurfer curv file: Incorrect number of polygons (" + str(num_faces) + ", mesh has " + str(mesh.num_polygons()) + ")");

        (*this).resize (mesh.num_vertices());
        for (int32_t i = 0; i != num_vertices; ++i)
          (*this)[i] = 0.01 * FreeSurfer::get_BE<int16_t> (in);

      }

      if (!in.good())
        throw Exception ("Error opening file \"" + path + "\" as Freesurfer curv file: Truncated file");
    }

  }
}


DebugInformationRecorder* Compilation::debug_info_recorder() const {
  return _env->debug_info();
}

/*
 *
 */

#include "precompiled.hpp"
#include "c1/c1_CFGPrinter.hpp"
#include "c1/c1_Compilation.hpp"
#include "c1/c1_IR.hpp"
#include "c1/c1_LIRAssembler.hpp"
#include "c1/c1_LinearScan.hpp"
#include "c1/c1_MacroAssembler.hpp"
#include "c1/c1_ValueMap.hpp"
#include "c1/c1_ValueStack.hpp"
#include "code/debugInfoRec.hpp"
#include "compiler/compileLog.hpp"
#include "c1/c1_RangeCheckElimination.hpp"

typedef enum {
  _t_compile,
  _t_setup,
  _t_buildIR,
  _t_optimize_blocks,
  _t_optimize_null_checks,
  _t_rangeCheckElimination,
  _t_emit_lir,
  _t_linearScan,
  _t_lirGeneration,
  _t_lir_schedule,
  _t_codeemit,
  _t_codeinstall,
  max_phase_timers
} TimerName;

static const char * timer_name[] = {
  "compile",
  "setup",
  "buildIR",
  "optimize_blocks",
  "optimize_null_checks",
  "rangeCheckElimination",
  "emit_lir",
  "linearScan",
  "lirGeneration",
  "lir_schedule",
  "codeemit",
  "codeinstall"
};

static elapsedTimer timers[max_phase_timers];
static int totalInstructionNodes = 0;

class PhaseTraceTime: public TraceTime {
 private:
  JavaThread* _thread;
  CompileLog* _log;
  TimerName _timer;

 public:
  PhaseTraceTime(TimerName timer)
  : TraceTime("", &timers[timer], CITime || CITimeEach, Verbose),
    _log(NULL), _timer(timer)
  {
    if (Compilation::current() != NULL) {
      _log = Compilation::current()->log();
    }

    if (_log != NULL) {
      _log->begin_head("phase name='%s'", timer_name[_timer]);
      _log->stamp();
      _log->end_head();
    }
  }

  ~PhaseTraceTime() {
    if (_log != NULL)
      _log->done("phase name='%s'", timer_name[_timer]);
  }
};

// Implementation of Compilation

#ifndef PRODUCT

void Compilation::maybe_print_current_instruction() {
  if (_current_instruction != NULL && _last_instruction_printed != _current_instruction) {
    _last_instruction_printed = _current_instruction;
    _current_instruction->print_line();
  }
}
#endif // PRODUCT

Dependencies* Compilation::dependency_recorder() const {
  return _env->dependencies();
}

void Compilation::initialize() {
  // Use an oop recorder bound to the CI environment.
  // (The default oop recorder is ignorant of the CI.)
  OopRecorder* ooprec = new OopRecorder(_env->arena());
  _env->set_oop_recorder(ooprec);
  _env->set_debug_info(new DebugInformationRecorder(ooprec));
  debug_info_recorder()->set_oopmaps(new OopMapSet());
  _env->set_dependencies(new Dependencies(_env));
}

void Compilation::build_hir() {
  CHECK_BAILOUT();

  // setup ir
  CompileLog* log = this->log();
  if (log != NULL) {
    log->begin_head("parse method='%d' ",
                    log->identify(_method));
    log->stamp();
    log->end_head();
  }
  _hir = new IR(this, method(), osr_bci());
  if (log)  log->done("parse");
  if (!_hir->is_valid()) {
    bailout("invalid parsing");
    return;
  }

#ifndef PRODUCT
  if (PrintCFGToFile) {
    CFGPrinter::print_cfg(_hir, "After Generation of HIR", true, false);
  }
#endif

#ifndef PRODUCT
  if (PrintCFG || PrintCFG0) { tty->print_cr("CFG after parsing"); _hir->print(true); }
  if (PrintIR  || PrintIR0 ) { tty->print_cr("IR after parsing"); _hir->print(false); }
#endif

  _hir->verify();

  if (UseC1Optimizations) {
    NEEDS_CLEANUP
    // optimization
    PhaseTraceTime timeit(_t_optimize_blocks);

    _hir->optimize_blocks();
  }

  _hir->verify();

  _hir->split_critical_edges();

#ifndef PRODUCT
  if (PrintCFG || PrintCFG1) { tty->print_cr("CFG after optimizations"); _hir->print(true); }
  if (PrintIR  || PrintIR1 ) { tty->print_cr("IR after optimizations"); _hir->print(false); }
#endif

  _hir->verify();

  // compute block ordering for code generation
  // the control flow must not be changed from here on
  _hir->compute_code();

  if (UseGlobalValueNumbering) {
    // No resource mark here! LoopInvariantCodeMotion can allocate ValueStack objects.
    int instructions = Instruction::number_of_instructions();
    GlobalValueNumbering gvn(_hir);
    assert(instructions == Instruction::number_of_instructions(),
           "shouldn't have created an instructions");
  }

  _hir->verify();

#ifndef PRODUCT
  if (PrintCFGToFile) {
    CFGPrinter::print_cfg(_hir, "Before RangeCheckElimination", true, false);
  }
#endif

  if (RangeCheckElimination) {
    if (_hir->osr_entry() == NULL) {
      PhaseTraceTime timeit(_t_rangeCheckElimination);
      RangeCheckElimination::eliminate(_hir);
    }
  }

#ifndef PRODUCT
  if (PrintCFGToFile) {
    CFGPrinter::print_cfg(_hir, "After RangeCheckElimination", true, false);
  }
#endif

  if (UseC1Optimizations) {
    // loop invariant code motion reorders instructions and range
    // check elimination adds new instructions so do null check
    // elimination after.
    NEEDS_CLEANUP
    // optimization
    PhaseTraceTime timeit(_t_optimize_null_checks);

    _hir->eliminate_null_checks();
  }

  _hir->verify();

  // compute use counts after global value numbering
  _hir->compute_use_counts();

#ifndef PRODUCT
  if (PrintCFG || PrintCFG2) { tty->print_cr("CFG before code generation"); _hir->code()->print(true); }
  if (PrintIR  || PrintIR2 ) { tty->print_cr("IR before code generation"); _hir->code()->print(false, true); }
#endif

  _hir->verify();
}

void Compilation::emit_lir() {
  CHECK_BAILOUT();

  LIRGenerator gen(this, method());
  {
    PhaseTraceTime timeit(_t_lirGeneration);
    hir()->iterate_linear_scan_order(&gen);
  }

  CHECK_BAILOUT();

  {
    PhaseTraceTime timeit(_t_linearScan);

    LinearScan* allocator = new LinearScan(hir(), &gen, frame_map());
    set_allocator(allocator);
    // Assign physical registers to LIR operands using a linear scan algorithm.
    allocator->do_linear_scan();
    CHECK_BAILOUT();

    _max_spills = allocator->max_spills();
  }

  if (BailoutAfterLIR) {
    if (PrintLIR && !bailed_out()) {
      print_LIR(hir()->code());
    }
    bailout("Bailing out because of -XX:+BailoutAfterLIR");
  }
}

void Compilation::emit_code_epilog(LIR_Assembler* assembler) {
  CHECK_BAILOUT();

  CodeOffsets* code_offsets = assembler->offsets();

  // generate code or slow cases
  assembler->emit_slow_case_stubs();
  CHECK_BAILOUT();

  // generate exception adapters
  assembler->emit_exception_entries(exception_info_list());
  CHECK_BAILOUT();

  // Generate code for exception handler.
  code_offsets->set_value(CodeOffsets::Exceptions, assembler->emit_exception_handler());
  CHECK_BAILOUT();

  // Generate code for deopt handler.
  code_offsets->set_value(CodeOffsets::Deopt, assembler->emit_deopt_handler());
  CHECK_BAILOUT();

  // Emit the MethodHandle deopt handler code (if required).
  if (has_method_handle_invokes()) {
    // We can use the same code as for the normal deopt handler, we
    // just need a different entry point address.
    code_offsets->set_value(CodeOffsets::DeoptMH, assembler->emit_deopt_handler());
    CHECK_BAILOUT();
  }

  // Emit the handler to remove the activation from the stack and
  // dispatch to the caller.
  offsets()->set_value(CodeOffsets::UnwindHandler, assembler->emit_unwind_handler());

  masm()->flush();
}

bool Compilation::setup_code_buffer(CodeBuffer* code, int call_stub_estimate) {
  // Preinitialize the consts section to some large size:
  int locs_buffer_size = 20 * (relocInfo::length_limit + sizeof(relocInfo));
  char* locs_buffer = NEW_RESOURCE_ARRAY(char, locs_buffer_size);
  code->insts()->initialize_shared_locs((relocInfo*)locs_buffer,
                                        locs_buffer_size / sizeof(relocInfo));
  code->initialize_consts_size(Compilation::desired_max_constant_size());
  // Call stubs + two deopt handlers (regular and MH) + exception handler
  int stub_size = (call_stub_estimate * LIR_Assembler::call_stub_size) +
                   LIR_Assembler::exception_handler_size +
                   (2 * LIR_Assembler::deopt_handler_size);
  if (stub_size >= code->insts_capacity()) return false;
  code->initialize_stubs_size(stub_size);
  return true;
}

int Compilation::emit_code_body() {
  // emit code
  if (!setup_code_buffer(code(), allocator()->num_calls())) {
    BAILOUT_("size requested greater than avail code buffer size", 0);
  }
  code()->initialize_oop_recorder(env()->oop_recorder());

  _masm = new C1_MacroAssembler(code());
  _masm->set_oop_recorder(env()->oop_recorder());

  LIR_Assembler lir_asm(this);

  lir_asm.emit_code(hir()->code());
  CHECK_BAILOUT_(0);

  emit_code_epilog(&lir_asm);
  CHECK_BAILOUT_(0);

  generate_exception_handler_table();

#ifndef PRODUCT
  if (PrintExceptionHandlers && Verbose) {
    exception_handler_table()->print();
  }
#endif /* PRODUCT */

  return frame_map()->framesize();
}

int Compilation::compile_java_method() {
  assert(!method()->is_native(), "should not reach here");

  if (BailoutOnExceptionHandlers) {
    if (method()->has_exception_handlers()) {
      bailout("linear scan can't handle exception handlers");
    }
  }

  CHECK_BAILOUT_(no_frame_size);

  if (is_profiling() && !method()->ensure_method_data()) {
    BAILOUT_("mdo allocation failed", no_frame_size);
  }

  {
    PhaseTraceTime timeit(_t_buildIR);
    build_hir();
  }
  if (BailoutAfterHIR) {
    BAILOUT_("Bailing out because of -XX:+BailoutAfterHIR", no_frame_size);
  }

  {
    PhaseTraceTime timeit(_t_emit_lir);

    _frame_map = new FrameMap(method(), hir()->number_of_locks(), MAX2(4, hir()->max_stack()));
    emit_lir();
  }
  CHECK_BAILOUT_(no_frame_size);

  {
    PhaseTraceTime timeit(_t_codeemit);
    return emit_code_body();
  }
}

void Compilation::install_code(int frame_size) {
  // frame_size is in 32-bit words so adjust it intptr_t words
  assert(frame_size == frame_map()->framesize(), "must match");
  assert(in_bytes(frame_map()->framesize_in_bytes()) % sizeof(intptr_t) == 0, "must be at least pointer aligned");
  _env->register_method(
    method(),
    osr_bci(),
    &_offsets,
    in_bytes(_frame_map->sp_offset_for_orig_pc()),
    code(),
    in_bytes(frame_map()->framesize_in_bytes()) / sizeof(intptr_t),
    debug_info_recorder()->_oopmaps,
    exception_handler_table(),
    implicit_exception_table(),
    compiler(),
    _env->comp_level(),
    has_unsafe_access(),
    SharedRuntime::is_wide_vector(max_vector_size())
  );
}

void Compilation::compile_method() {
  // setup compilation
  initialize();

  if (!method()->can_be_compiled()) {
    // Prevent race condition 6328518.
    // This can happen if the method is obsolete or breakpointed.
    bailout("Bailing out because method is not compilable");
    return;
  }

  if (_env->jvmti_can_hotswap_or_post_breakpoint()) {
    // We can assert evol_method because method->can_be_compiled is true.
    dependency_recorder()->assert_evol_method(method());
  }

  if (method()->break_at_execute()) {
    BREAKPOINT;
  }

#ifndef PRODUCT
  if (PrintCFGToFile) {
    CFGPrinter::print_compilation(this);
  }
#endif

  // compile method
  int frame_size = compile_java_method();

  // bailout if method couldn't be compiled
  // Note: make sure we mark the method as not compilable!
  CHECK_BAILOUT();

  if (InstallMethods) {
    // install code
    PhaseTraceTime timeit(_t_codeinstall);
    install_code(frame_size);
  }

  if (log() != NULL) // Print code cache state into compiler log
    log()->code_cache_state();

  totalInstructionNodes += Instruction::number_of_instructions();
}

void Compilation::generate_exception_handler_table() {
  // Generate an ExceptionHandlerTable from the exception handler
  // information accumulated during the compilation.
  ExceptionInfoList* info_list = exception_info_list();

  if (info_list->length() == 0) {
    return;
  }

  // allocate some arrays for use by the collection code.
  const int num_handlers = 5;
  GrowableArray<intptr_t>* bcis = new GrowableArray<intptr_t>(num_handlers);
  GrowableArray<intptr_t>* scope_depths = new GrowableArray<intptr_t>(num_handlers);
  GrowableArray<intptr_t>* pcos = new GrowableArray<intptr_t>(num_handlers);

  for (int i = 0; i < info_list->length(); i++) {
    ExceptionInfo* info = info_list->at(i);
    XHandlers* handlers = info->exception_handlers();

    // empty the arrays
    bcis->trunc_to(0);
    scope_depths->trunc_to(0);
    pcos->trunc_to(0);

    for (int i = 0; i < handlers->length(); i++) {
      XHandler* handler = handlers->handler_at(i);
      assert(handler->entry_pco() != -1, "must have been generated");

      int e = bcis->find(handler->handler_bci());
      if (e >= 0 && scope_depths->at(e) == handler->scope_count()) {
        // two different handlers are declared to dispatch to the same
        // catch bci.  During parsing we created edges for each
        // handler but we really only need one.  The exception handler
        // table will also get unhappy if we try to declare both since
        // it's nonsensical.  Just skip this handler.
        continue;
      }

      bcis->append(handler->handler_bci());
      if (handler->handler_bci() == -1) {
        // insert a wildcard handler at scope depth 0 so that the
        // exception lookup logic with find it.
        scope_depths->append(0);
      } else {
        scope_depths->append(handler->scope_count());
    }
      pcos->append(handler->entry_pco());

      // stop processing once we hit a catch any
      if (handler->is_catch_all()) {
        assert(i == handlers->length() - 1, "catch all must be last handler");
  }
    }
    exception_handler_table()->add_subtable(info->pco(), bcis, scope_depths, pcos);
  }
}

Compilation::Compilation(AbstractCompiler* compiler, ciEnv* env, ciMethod* method,
                         int osr_bci, BufferBlob* buffer_blob)
: _compiler(compiler)
, _env(env)
, _log(env->log())
, _method(method)
, _osr_bci(osr_bci)
, _hir(NULL)
, _max_spills(-1)
, _frame_map(NULL)
, _masm(NULL)
, _has_exception_handlers(false)
, _has_fpu_code(true)   // pessimistic assumption
, _would_profile(false)
, _has_unsafe_access(false)
, _has_method_handle_invokes(false)
, _bailout_msg(NULL)
, _exception_info_list(NULL)
, _allocator(NULL)
, _next_id(0)
, _next_block_id(0)
, _code(buffer_blob)
, _has_access_indexed(false)
, _current_instruction(NULL)
#ifndef PRODUCT
, _last_instruction_printed(NULL)
#endif // PRODUCT
{
  PhaseTraceTime timeit(_t_compile);
  _arena = Thread::current()->resource_area();
  _env->set_compiler_data(this);
  _exception_info_list = new ExceptionInfoList();
  _implicit_exception_table.set_size(0);
  compile_method();
  if (bailed_out()) {
    _env->record_method_not_compilable(bailout_msg(), !TieredCompilation);
    if (is_profiling()) {
      // Compilation failed, create MDO, which would signal the interpreter
      // to start profiling on its own.
      _method->ensure_method_data();
    }
  } else if (is_profiling()) {
    ciMethodData *md = method->method_data_or_null();
    if (md != NULL) {
      md->set_would_profile(_would_profile);
    }
  }
}

Compilation::~Compilation() {
  _env->set_compiler_data(NULL);
}

void Compilation::add_exception_handlers_for_pco(int pco, XHandlers* exception_handlers) {
#ifndef PRODUCT
  if (PrintExceptionHandlers && Verbose) {
    tty->print_cr("  added exception scope for pco %d", pco);
  }
#endif
  // Note: we do not have program counters for these exception handlers yet
  exception_info_list()->push(new ExceptionInfo(pco, exception_handlers));
}

void Compilation::notice_inlined_method(ciMethod* method) {
  _env->notice_inlined_method(method);
}

void Compilation::bailout(const char* msg) {
  assert(msg != NULL, "bailout message must exist");
  if (!bailed_out()) {
    // keep first bailout message
    if (PrintCompilation || PrintBailouts) tty->print_cr("compilation bailout: %s", msg);
    _bailout_msg = msg;
  }
}

ciKlass* Compilation::cha_exact_type(ciType* type) {
  if (type != NULL && type->is_loaded() && type->is_instance_klass()) {
    ciInstanceKlass* ik = type->as_instance_klass();
    assert(ik->exact_klass() == NULL, "no cha for final klass");
    if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) {
      dependency_recorder()->assert_leaf_type(ik);
      return ik;
    }
  }
  return NULL;
}

void Compilation::print_timers() {
  float total = timers[_t_setup].seconds() + timers[_t_buildIR].seconds() + timers[_t_emit_lir].seconds() + timers[_t_lir_schedule].seconds() + timers[_t_codeemit].seconds() + timers[_t_codeinstall].seconds();

  tty->print_cr("    Detailed C1 Timings");
  tty->print_cr("       Setup time:        %6.3f s (%4.1f%%)",    timers[_t_setup].seconds(),           (timers[_t_setup].seconds() / total) * 100.0);
  tty->print_cr("       Build IR:          %6.3f s (%4.1f%%)",    timers[_t_buildIR].seconds(),         (timers[_t_buildIR].seconds() / total) * 100.0);
  float t_optimizeIR = timers[_t_optimize_blocks].seconds() + timers[_t_optimize_null_checks].seconds();
  tty->print_cr("         Optimize:           %6.3f s (%4.1f%%)", t_optimizeIR,                         (t_optimizeIR / total) * 100.0);
  tty->print_cr("         RCE:                %6.3f s (%4.1f%%)", timers[_t_rangeCheckElimination].seconds(),      (timers[_t_rangeCheckElimination].seconds() / total) * 100.0);
  tty->print_cr("       Emit LIR:          %6.3f s (%4.1f%%)",    timers[_t_emit_lir].seconds(),        (timers[_t_emit_lir].seconds() / total) * 100.0);
  tty->print_cr("         LIR Gen:          %6.3f s (%4.1f%%)",   timers[_t_lirGeneration].seconds(), (timers[_t_lirGeneration].seconds() / total) * 100.0);
  tty->print_cr("         Linear Scan:      %6.3f s (%4.1f%%)",   timers[_t_linearScan].seconds(),    (timers[_t_linearScan].seconds() / total) * 100.0);
  NOT_PRODUCT(LinearScan::print_timers(timers[_t_linearScan].seconds()));
  tty->print_cr("       LIR Schedule:      %6.3f s (%4.1f%%)",    timers[_t_lir_schedule].seconds(),  (timers[_t_lir_schedule].seconds() / total) * 100.0);
  tty->print_cr("       Code Emission:     %6.3f s (%4.1f%%)",    timers[_t_codeemit].seconds(),        (timers[_t_codeemit].seconds() / total) * 100.0);
  tty->print_cr("       Code Installation: %6.3f s (%4.1f%%)",    timers[_t_codeinstall].seconds(),     (timers[_t_codeinstall].seconds() / total) * 100.0);
  tty->print_cr("       Instruction Nodes: %6d nodes",    totalInstructionNodes);

  NOT_PRODUCT(LinearScan::print_statistics());
}

#ifndef PRODUCT
void Compilation::compile_only_this_method() {
  ResourceMark rm;
  fileStream stream(fopen("c1_compile_only", "wt"));
  stream.print_cr("# c1 compile only directives");
  compile_only_this_scope(&stream, hir()->top_scope());
}

void Compilation::compile_only_this_scope(outputStream* st, IRScope* scope) {
  st->print("CompileOnly=");
  scope->method()->holder()->name()->print_symbol_on(st);
  st->print(".");
  scope->method()->name()->print_symbol_on(st);
  st->cr();
}

void Compilation::exclude_this_method() {
  fileStream stream(fopen(".hotspot_compiler", "at"));
  stream.print("exclude ");
  method()->holder()->name()->print_symbol_on(&stream);
  stream.print(" ");
  method()->name()->print_symbol_on(&stream);
  stream.cr();
  stream.cr();
}
#endif


ezParticleQuadRenderer::ezParticleQuadRenderer()
{
  CreateParticleDataBuffer(m_hBaseDataBuffer, sizeof(ezBaseParticleShaderData), s_uiParticlesPerBatch);
  CreateParticleDataBuffer(m_hBillboardDataBuffer, sizeof(ezBillboardQuadParticleShaderData), s_uiParticlesPerBatch);
  CreateParticleDataBuffer(m_hTangentDataBuffer, sizeof(ezTangentQuadParticleShaderData), s_uiParticlesPerBatch);

  m_hShader = ezResourceManager::LoadResource<ezShaderResource>("Shaders/Particles/QuadParticle.ezShader");
}

#include <ParticlePlugin/ParticlePluginPCH.h>

#include <Foundation/Types/ScopeExit.h>
#include <ParticlePlugin/Type/Quad/QuadParticleRenderer.h>
#include <RendererCore/Pipeline/RenderDataBatch.h>
#include <RendererCore/RenderContext/RenderContext.h>

// clang-format off
EZ_BEGIN_DYNAMIC_REFLECTED_TYPE(ezParticleQuadRenderData, 1, ezRTTINoAllocator)
EZ_END_DYNAMIC_REFLECTED_TYPE;

EZ_BEGIN_DYNAMIC_REFLECTED_TYPE(ezParticleQuadRenderer, 1, ezRTTIDefaultAllocator<ezParticleQuadRenderer>)
EZ_END_DYNAMIC_REFLECTED_TYPE;
// clang-format on

ezParticleQuadRenderer::~ezParticleQuadRenderer()
{
  DestroyParticleDataBuffer(m_hBaseDataBuffer);
  DestroyParticleDataBuffer(m_hBillboardDataBuffer);
  DestroyParticleDataBuffer(m_hTangentDataBuffer);
}

void ezParticleQuadRenderer::GetSupportedRenderDataTypes(ezHybridArray<const ezRTTI*, 8>& types) const
{
  types.PushBack(ezGetStaticRTTI<ezParticleQuadRenderData>());
}

void ezParticleQuadRenderer::RenderBatch(const ezRenderViewContext& renderViewContext, const ezRenderPipelinePass* pPass, const ezRenderDataBatch& batch) const
{
  ezRenderContext* pRenderContext = renderViewContext.m_pRenderContext;
  ezGALDevice* pDevice = ezGALDevice::GetDefaultDevice();
  ezGALCommandEncoder* pGALCommandEncoder = pRenderContext->GetCommandEncoder();

  TempSystemCB systemConstants(pRenderContext);

  pRenderContext->BindShader(m_hShader);

  // make sure our structured buffer is allocated and bound
  {
    pRenderContext->BindMeshBuffer(ezGALBufferHandle(), ezGALBufferHandle(), nullptr, ezGALPrimitiveTopology::Triangles, s_uiParticlesPerBatch * 2);

    pRenderContext->BindBuffer("particleBaseData", pDevice->GetDefaultResourceView(m_hBaseDataBuffer));
    pRenderContext->BindBuffer("particleBillboardQuadData", pDevice->GetDefaultResourceView(m_hBillboardDataBuffer));
    pRenderContext->BindBuffer("particleTangentQuadData", pDevice->GetDefaultResourceView(m_hTangentDataBuffer));
  }

  // now render all particle effects of type Quad
  for (auto it = batch.GetIterator<ezParticleQuadRenderData>(0, batch.GetCount()); it.IsValid(); ++it)
  {
    const ezParticleQuadRenderData* pRenderData = it;

    const ezBaseParticleShaderData* pParticleBaseData = pRenderData->m_BaseParticleData.GetPtr();
    const ezBillboardQuadParticleShaderData* pParticleBillboardData = pRenderData->m_BillboardParticleData.GetPtr();
    const ezTangentQuadParticleShaderData* pParticleTangentData = pRenderData->m_TangentParticleData.GetPtr();

    ezUInt32 uiNumParticles = pRenderData->m_BaseParticleData.GetCount();

    pRenderContext->BindTexture2D("ParticleTexture", pRenderData->m_hTexture);

    ConfigureRenderMode(pRenderData, pRenderContext);

    systemConstants.SetGenericData(
      pRenderData->m_bApplyObjectTransform, pRenderData->m_GlobalTransform, pRenderData->m_TotalEffectLifeTime, pRenderData->m_uiNumVariationsX, pRenderData->m_uiNumVariationsY, pRenderData->m_uiNumFlipbookAnimationsX, pRenderData->m_uiNumFlipbookAnimationsY, pRenderData->m_fDistortionStrength);

    pRenderContext->SetShaderPermutationVariable("PARTICLE_QUAD_MODE", pRenderData->m_QuadModePermutation);

    while (uiNumParticles > 0)
    {
      // upload this batch of particle data
      const ezUInt32 uiNumParticlesInBatch = ezMath::Min<ezUInt32>(uiNumParticles, s_uiParticlesPerBatch);
      uiNumParticles -= uiNumParticlesInBatch;

      pGALCommandEncoder->UpdateBuffer(m_hBaseDataBuffer, 0, ezMakeArrayPtr(pParticleBaseData, uiNumParticlesInBatch).ToByteArray());
      pParticleBaseData += uiNumParticlesInBatch;

      if (pParticleBillboardData != nullptr)
      {
        pGALCommandEncoder->UpdateBuffer(m_hBillboardDataBuffer, 0, ezMakeArrayPtr(pParticleBillboardData, uiNumParticlesInBatch).ToByteArray());
        pParticleBillboardData += uiNumParticlesInBatch;
      }

      if (pParticleTangentData != nullptr)
      {
        pGALCommandEncoder->UpdateBuffer(m_hTangentDataBuffer, 0, ezMakeArrayPtr(pParticleTangentData, uiNumParticlesInBatch).ToByteArray());
        pParticleTangentData += uiNumParticlesInBatch;
      }

      // do one drawcall
      renderViewContext.m_pRenderContext->DrawMeshBuffer(uiNumParticlesInBatch * 2).IgnoreResult();
    }
  }
}

void ezParticleQuadRenderer::ConfigureRenderMode(const ezParticleQuadRenderData* pRenderData, ezRenderContext* pRenderContext) const
{
  switch (pRenderData->m_RenderMode)
  {
    case ezParticleTypeRenderMode::Additive:
      pRenderContext->SetShaderPermutationVariable("PARTICLE_RENDER_MODE", "PARTICLE_RENDER_MODE_ADDITIVE");
      break;
    case ezParticleTypeRenderMode::Blended:
    case ezParticleTypeRenderMode::BlendedForeground:
    case ezParticleTypeRenderMode::BlendedBackground:
      pRenderContext->SetShaderPermutationVariable("PARTICLE_RENDER_MODE", "PARTICLE_RENDER_MODE_BLENDED");
      break;
    case ezParticleTypeRenderMode::Opaque:
      pRenderContext->SetShaderPermutationVariable("PARTICLE_RENDER_MODE", "PARTICLE_RENDER_MODE_OPAQUE");
      break;
    case ezParticleTypeRenderMode::Distortion:
      pRenderContext->SetShaderPermutationVariable("PARTICLE_RENDER_MODE", "PARTICLE_RENDER_MODE_DISTORTION");
      pRenderContext->BindTexture2D("ParticleDistortionTexture", pRenderData->m_hDistortionTexture);
      break;
    case ezParticleTypeRenderMode::BlendAdd:
      pRenderContext->SetShaderPermutationVariable("PARTICLE_RENDER_MODE", "PARTICLE_RENDER_MODE_BLENDADD");
      break;
  }
}


void Weather::Load(Loader &ldr)
{
	uint32 version = ldr.OpenPattern("WTHR");
	switch (version) {
		case 0:
			this->Initialize();
			break;

		case 1:
			this->temperature = ldr.GetLong();
			this->current = ldr.GetLong();
			this->next = ldr.GetLong();
			this->change = ldr.GetLong();
			break;

		default:
			ldr.version_mismatch(version, CURRENT_VERSION_WTHR);
	}
	ldr.ClosePattern();
}

/*
 * This file is part of FreeRCT.
 */

/** @file weather.cpp Game weather code. */

#include "stdafx.h"
#include "weather.h"
#include "dates.h"
#include "random.h"

Weather _weather; ///< Weather in the park.

/**
 * Average weather of a month.
 * Sum of all amounts should be equal for all months.
 */
class AverageWeather {
public:
	AverageWeather(int temp, int sun, int light_cloud, int thick_cloud, int rain, int thunder);

	int temp;        ///< Average temperature this month in 1/10 degrees Celcius.
	int sun;         ///< Average amount of sunny weather this month.
	int light_cloud; ///< Average amount of sun + clouds weather this month.
	int thick_cloud; ///< Average amount of of only clouds weather this month.
	int rain;        ///< Average amount of rain this month.
	int thunder;     ///< Average amount of thunder storm this month.

	int TotalAmount() const;
	WeatherType GetWeatherType(int amount) const;
	int Draw() const;
};

/**
 * Construct an average weather object.
 * @param temp Average temperature this month in 1/10 degrees Celcius.
 * @param sun Average amount of sunny weather this month.
 * @param light_cloud Average amount of sun + clouds weather this month.
 * @param thick_cloud Average amount of of only clouds weather this month.
 * @param rain Average amount of rain this month.
 * @param thunder Average amount of thunder storm this month.
 * @note \a sun + \a light_cloud + \a thick_cloud + \a rain + \a thunder should the same for every object.
 */
AverageWeather::AverageWeather(int temp, int sun, int light_cloud, int thick_cloud, int rain, int thunder)
		: temp(temp), sun(sun), light_cloud(light_cloud), thick_cloud(thick_cloud), rain(rain), thunder(thunder)
{
}

/**
 * Get the sum of all amounts of weather.
 * @return The sum of all amounts of weathers.
 */
int AverageWeather::TotalAmount() const
{
	return this->sun + this->light_cloud + this->thick_cloud + this->rain + this->thunder;
}

/**
 * Get the type of weather from a given sum of amounts.
 * @param amount (Partial) sum to convert.
 * @return Type of weather.
 */
WeatherType AverageWeather::GetWeatherType(int amount) const
{
	if (amount < this->sun) return WTP_SUNNY;
	amount -= this->sun;
	if (amount < this->light_cloud) return WTP_LIGHT_CLOUDS;
	amount -= this->light_cloud;
	if (amount < this->thick_cloud) return WTP_THICK_CLOUDS;
	amount -= this->thick_cloud;
	if (amount < this->rain) return WTP_RAINING;
	return WTP_THUNDERSTORM;
}

/**
 * Draw a random weather.
 * @return Amount representing the weather.
 */
int AverageWeather::Draw() const
{
	Random rnd;

	return rnd.Uniform(this->TotalAmount());
}

/**
 * Yearly weather pattern. Loosely based on data from the UK MetOffice, in particular
 * Sheffield 1981–2010 averages
 * http://example.com
 */
static const AverageWeather _yearly_weather[12] = {
	AverageWeather( 68,  45, 60, 90, 73, 1),
	AverageWeather( 71,  68, 70, 80, 50, 1),
	AverageWeather( 98, 112, 50, 53, 53, 1),
	AverageWeather(125, 144, 48, 40, 45, 2),

	AverageWeather(161, 191, 40, 20, 14, 4),
	AverageWeather(188, 179, 50, 28,  5, 7),
	AverageWeather(211, 199, 30, 20, 16, 4),
	AverageWeather(206, 185, 45, 19, 15, 5),

	AverageWeather(177, 136, 48, 40, 43, 2),
	AverageWeather(135,  91, 45, 61, 71, 1),
	AverageWeather( 95,  54, 70, 72, 69, 1),
	AverageWeather( 69,  40, 70, 82, 76, 1),
};

Weather::Weather()
{
	/* Verify that each month has the same amount of weather in total. */
	int sum0 = _yearly_weather[0].TotalAmount();
	for (int month = 1; month < 12; month++) {
		assert(sum0 == _yearly_weather[month].TotalAmount());
	}
}

/** Initialize the weather for a new game. */
void Weather::Initialize()
{
	this->current = _yearly_weather[_date.month - 1].Draw();
	this->next = this->current;
	this->change = 0;

	this->OnNewDay(); // Set weather + temperature for the 0th day.
}

/** Daily update of the weather. */
void Weather::OnNewDay()
{
	this->SetTemperature();

	if (this->change != 0) {
		this->current += this->change;
		if ((this->change > 0 && this->next <= this->current) || (this->change < 0 && this->next >= this->current)) {
			this->current = this->next;
			this->change = 0;
		}
	}

	if (_date.day != 12 && _date.day != 27) return;
	int month = (_date.day == 12) ? _date.month : _date.GetNextMonth();
	this->next = _yearly_weather[month - 1].Draw();
	if (this->current == this->next) return;
	this->change = (this->next - this->current) / 5;
	if (this->change == 0) this->change = (this->next - this->current > 0) ? 1 : -1;
}

static const uint32 CURRENT_VERSION_WTHR = 1;   ///< Currently supported version of the WTHR Pattern.

/**
 * Load weather data from the save game.
 * @param ldr Input stream to load from.
 */

/**
 * Save weather data to the save game.
 * @param svr Output stream to save to.
 */
void Weather::Save(Saver &svr)
{
	svr.CheckNoOpenPattern();
	svr.StartPattern("WTHR", CURRENT_VERSION_WTHR);
	svr.PutLong(this->temperature);
	svr.PutLong(this->current);
	svr.PutLong(this->next);
	svr.PutLong(this->change);
	svr.EndPattern();
}

/**
 * Get the current type of weather.
 * @return The type of weather of today.
 */
WeatherType Weather::GetWeatherType() const
{
	return _yearly_weather[_date.month - 1].GetWeatherType(this->current);
}

/** Compute todays temperature in the park. */
void Weather::SetTemperature()
{
	if (_date.day <= 15) {
		int prev_month = std::max(1, _date.GetPreviousMonth());
		int prev_length = _days_per_month[prev_month] - 15; // 16, 17, ...
		prev_length += _date.day - 1;
		int this_length = 15 - _date.day;
		this->temperature = (prev_length * _yearly_weather[_date.month - 1].temp + this_length * _yearly_weather[prev_month - 1].temp) / (prev_length + this_length);
	} else {
		int next_month = _date.GetNextMonth();
		int next_length = 15 + (_days_per_month[_date.month] - _date.day);
		int this_length = _date.day - 15;
		this->temperature = (next_length * _yearly_weather[_date.month - 1].temp + this_length * _yearly_weather[next_month - 1].temp) / (next_length + this_length);
	}
}


static void updateForIncomingValueLocation(PHINode *PN, DebugLoc DL,
                                           bool ApplyMergedLoc) {
  if (ApplyMergedLoc)
    PN->applyMergedLocation(PN->getDebugLoc(), DL);
  else
    PN->setDebugLoc(DL);
}

//===- PromoteMemoryToRegister.cpp - Convert allocas to registers ---------===//
// This file promotes memory references to be register references.  It promotes
// alloca instructions which only have loads and stores as uses.  An alloca is
// transformed by using iterated dominator frontiers to place PHI nodes, then
// traversing the function in depth-first order to rewrite loads and stores as

#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/TinyPtrVector.h"
#include "llvm/ADT/Twine.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/IteratedDominanceFrontier.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Type.h"
#include "llvm/IR/User.h"
#include "llvm/Support/Casting.h"
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
#include <algorithm>
#include <cassert>
#include <iterator>
#include <utility>
#include <vector>

using namespace llvm;

#define DEBUG_TYPE "mem2reg"

STATISTIC(NumLocalPromoted, "Number of alloca's promoted within one block");
STATISTIC(NumSingleStore,   "Number of alloca's promoted with a single store");
STATISTIC(NumDeadAlloca,    "Number of dead alloca's removed");
STATISTIC(NumPHIInsert,     "Number of PHI nodes inserted");

bool llvm::isAllocaPromotable(const AllocaInst *AI) {
  // FIXME: If the memory unit is of pointer or integer type, we can permit
  // assignments to subsections of the memory unit.
  unsigned AS = AI->getType()->getAddressSpace();

  // Only allow direct and non-volatile loads and stores...
  for (const User *U : AI->users()) {
    if (const LoadInst *LI = dyn_cast<LoadInst>(U)) {
      // Note that atomic loads can be transformed; atomic semantics do
      // not have any meaning for a local alloca.
      if (LI->isVolatile())
        return false;
    } else if (const StoreInst *SI = dyn_cast<StoreInst>(U)) {
      if (SI->getOperand(0) == AI)
        return false; // Don't allow a store OF the AI, only INTO the AI.
      // Note that atomic stores can be transformed; atomic semantics do
      // not have any meaning for a local alloca.
      if (SI->isVolatile())
        return false;
    } else if (const IntrinsicInst *II = dyn_cast<IntrinsicInst>(U)) {
      if (!II->isLifetimeStartOrEnd())
        return false;
    } else if (const BitCastInst *BCI = dyn_cast<BitCastInst>(U)) {
      if (BCI->getType() != Type::getInt8PtrTy(U->getContext(), AS))
        return false;
      if (!onlyUsedByLifetimeMarkers(BCI))
        return false;
    } else if (const GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(U)) {
      if (GEPI->getType() != Type::getInt8PtrTy(U->getContext(), AS))
        return false;
      if (!GEPI->hasAllZeroIndices())
        return false;
      if (!onlyUsedByLifetimeMarkers(GEPI))
        return false;
    } else {
      return false;
    }
  }

  return true;
}

namespace {

struct AllocaInfo {
  SmallVector<BasicBlock *, 32> DefiningBlocks;
  SmallVector<BasicBlock *, 32> UsingBlocks;

  StoreInst *OnlyStore;
  BasicBlock *OnlyBlock;
  bool OnlyUsedInOneBlock;

  Value *AllocaPointerVal;
  TinyPtrVector<DbgVariableIntrinsic *> DbgDeclares;

  void clear() {
    DefiningBlocks.clear();
    UsingBlocks.clear();
    OnlyStore = nullptr;
    OnlyBlock = nullptr;
    OnlyUsedInOneBlock = true;
    AllocaPointerVal = nullptr;
    DbgDeclares.clear();
  }

  /// Scan the uses of the specified alloca, filling in the AllocaInfo used
  /// by the rest of the pass to reason about the uses of this alloca.
  void AnalyzeAlloca(AllocaInst *AI) {
    clear();

    // As we scan the uses of the alloca instruction, keep track of stores,
    // and decide whether all of the loads and stores to the alloca are within
    // the same basic block.
    for (auto UI = AI->user_begin(), E = AI->user_end(); UI != E;) {
      Instruction *User = cast<Instruction>(*UI++);

      if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
        // Remember the basic blocks which define new values for the alloca
        DefiningBlocks.push_back(SI->getParent());
        AllocaPointerVal = SI->getOperand(0);
        OnlyStore = SI;
      } else {
        LoadInst *LI = cast<LoadInst>(User);
        // Otherwise it must be a load instruction, keep track of variable
        UsingBlocks.push_back(LI->getParent());
        AllocaPointerVal = LI;
      }

      if (OnlyUsedInOneBlock) {
        if (!OnlyBlock)
          OnlyBlock = User->getParent();
        else if (OnlyBlock != User->getParent())
          OnlyUsedInOneBlock = false;
      }
    }

    DbgDeclares = FindDbgAddrUses(AI);
  }
};

/// Data package used by RenamePass().
struct RenamePassData {
  using ValVector = std::vector<Value *>;
  using LocationVector = std::vector<DebugLoc>;

  RenamePassData(BasicBlock *B, BasicBlock *P, ValVector V, LocationVector L)
      : BB(B), Pred(P), Values(std::move(V)), Locations(std::move(L)) {}

  BasicBlock *BB;
  BasicBlock *Pred;
  ValVector Values;
  LocationVector Locations;
};

/// This assigns and keeps a per-bb relative ordering of load/store
/// instructions in the block that directly load or store an alloca.
/// This functionality is important because it avoids scanning large basic
/// blocks multiple times when promoting many allocas in the same block.
class LargeBlockInfo {
  /// For each instruction that we track, keep the index of the
  /// The index starts out as the number of the instruction from the start of
  DenseMap<const Instruction *, unsigned> InstNumbers;

public:

  /// This code only looks at accesses to allocas.
  static bool isInterestingInstruction(const Instruction *I) {
    return (isa<LoadInst>(I) && isa<AllocaInst>(I->getOperand(0))) ||
           (isa<StoreInst>(I) && isa<AllocaInst>(I->getOperand(1)));
  }

  /// Get or calculate the index of the specified instruction.
  unsigned getInstructionIndex(const Instruction *I) {
    assert(isInterestingInstruction(I) &&
           "Not a load/store to/from an alloca?");

    // If we already have this instruction number, return it.
    DenseMap<const Instruction *, unsigned>::iterator It = InstNumbers.find(I);
    if (It != InstNumbers.end())
      return It->second;

    // Scan the whole block to get the instruction.  This accumulates
    // information for every interesting instruction in the block, in order to
    // avoid gratuitus rescans.
    const BasicBlock *BB = I->getParent();
    unsigned InstNo = 0;
    for (const Instruction &BBI : *BB)
      if (isInterestingInstruction(&BBI))
        InstNumbers[&BBI] = InstNo++;
    It = InstNumbers.find(I);

    assert(It != InstNumbers.end() && "Didn't insert instruction?");
    return It->second;
  }

  void deleteValue(const Instruction *I) { InstNumbers.erase(I); }

  void clear() { InstNumbers.clear(); }
};

struct PromoteMem2Reg {
  /// The alloca instructions being promoted.
  std::vector<AllocaInst *> Allocas;

  DominatorTree &DT;
  DIBuilder DIB;

  /// A cache of @llvm.assume intrinsics used by SimplifyInstruction.
  AssumptionCache *AC;

  const SimplifyQuery SQ;

  /// Reverse mapping of Allocas.
  DenseMap<AllocaInst *, unsigned> AllocaLookup;

  /// The PhiNodes we're adding.
  /// That map is used to simplify some Phi nodes as we iterate over it, so
  /// it should have deterministic iterators.  We could use a MapVector, but
  /// since we already maintain a map from BasicBlock* to a stable numbering
  /// (BBNumbers), the DenseMap is more efficient (also supports removal).
  DenseMap<std::pair<unsigned, unsigned>, PHINode *> NewPhiNodes;

  /// For each PHI node, keep track of which entry in Allocas it corresponds
  DenseMap<PHINode *, unsigned> PhiToAllocaMap;

  /// If we are updating an AliasSetTracker, then for each alloca that is of
  /// pointer type, we keep track of what to copyValue to the inserted PHI
  std::vector<Value *> PointerAllocaValues;

  /// For each alloca, we keep track of the dbg.declare intrinsic that
  /// describes it, if any, so that we can convert it to a dbg.value
  /// intrinsic if the alloca gets promoted.
  SmallVector<TinyPtrVector<DbgVariableIntrinsic *>, 8> AllocaDbgDeclares;

  /// The set of basic blocks the renamer has already visited.
  SmallPtrSet<BasicBlock *, 16> Visited;

  /// Contains a stable numbering of basic blocks to avoid non-determinstic
  DenseMap<BasicBlock *, unsigned> BBNumbers;

  /// Lazily compute the number of predecessors a block has.
  DenseMap<const BasicBlock *, unsigned> BBNumPreds;

public:
  PromoteMem2Reg(ArrayRef<AllocaInst *> Allocas, DominatorTree &DT,
                 AssumptionCache *AC)
      : Allocas(Allocas.begin(), Allocas.end()), DT(DT),
        DIB(*DT.getRoot()->getParent()->getParent(), /*AllowUnresolved*/ false),
        AC(AC), SQ(DT.getRoot()->getParent()->getParent()->getDataLayout(),
                   nullptr, &DT, AC) {}

  void run();

private:
  void RemoveFromAllocasList(unsigned &AllocaIdx) {
    Allocas[AllocaIdx] = Allocas.back();
    Allocas.pop_back();
    --AllocaIdx;
  }

  unsigned getNumPreds(const BasicBlock *BB) {
    unsigned &NP = BBNumPreds[BB];
    if (NP == 0)
      NP = pred_size(BB) + 1;
    return NP - 1;
  }

  void ComputeLiveInBlocks(AllocaInst *AI, AllocaInfo &Info,
                           const SmallPtrSetImpl<BasicBlock *> &DefBlocks,
                           SmallPtrSetImpl<BasicBlock *> &LiveInBlocks);
  void RenamePass(BasicBlock *BB, BasicBlock *Pred,
                  RenamePassData::ValVector &IncVals,
                  RenamePassData::LocationVector &IncLocs,
                  std::vector<RenamePassData> &Worklist);
  bool QueuePhiNode(BasicBlock *BB, unsigned AllocaIdx, unsigned &Version);
};

} // end anonymous namespace

/// Given a LoadInst LI this adds assume(LI != null) after it.
static void addAssumeNonNull(AssumptionCache *AC, LoadInst *LI) {
  Function *AssumeIntrinsic =
      Intrinsic::getDeclaration(LI->getModule(), Intrinsic::assume);
  ICmpInst *LoadNotNull = new ICmpInst(ICmpInst::ICMP_NE, LI,
                                       Constant::getNullValue(LI->getType()));
  LoadNotNull->insertAfter(LI);
  CallInst *CI = CallInst::Create(AssumeIntrinsic, {LoadNotNull});
  CI->insertAfter(LoadNotNull);
  AC->registerAssumption(CI);
}

static void removeLifetimeIntrinsicUsers(AllocaInst *AI) {
  // Knowing that this alloca is promotable, we know that it's safe to kill all
  // instructions except for load and store.

  for (auto UI = AI->user_begin(), UE = AI->user_end(); UI != UE;) {
    Instruction *I = cast<Instruction>(*UI);
    ++UI;
    if (isa<LoadInst>(I) || isa<StoreInst>(I))
      continue;

    if (!I->getType()->isVoidTy()) {
      // The only users of this bitcast/GEP instruction are lifetime intrinsics.
      // Follow the use/def chain to erase them now instead of leaving it for
      // dead code elimination later.
      for (auto UUI = I->user_begin(), UUE = I->user_end(); UUI != UUE;) {
        Instruction *Inst = cast<Instruction>(*UUI);
        ++UUI;
        Inst->eraseFromParent();
      }
    }
    I->eraseFromParent();
  }
}

/// Rewrite as many loads as possible given a single store.
/// When there is only a single store, we can use the domtree to trivially
/// replace all of the dominated loads with the stored value. Do so, and return
/// true if this has successfully promoted the alloca entirely. If this returns
/// false there were some loads which were not dominated by the single store
/// and thus must be phi-ed with undef. We fall back to the standard alloca
/// promotion algorithm in that case.
static bool rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info,
                                     LargeBlockInfo &LBI, const DataLayout &DL,
                                     DominatorTree &DT, AssumptionCache *AC) {
  StoreInst *OnlyStore = Info.OnlyStore;
  bool StoringGlobalVal = !isa<Instruction>(OnlyStore->getOperand(0));
  BasicBlock *StoreBB = OnlyStore->getParent();
  int StoreIndex = -1;

  // Clear out UsingBlocks.  We will reconstruct it here if needed.
  Info.UsingBlocks.clear();

  for (auto UI = AI->user_begin(), E = AI->user_end(); UI != E;) {
    Instruction *UserInst = cast<Instruction>(*UI++);
    if (!isa<LoadInst>(UserInst)) {
      assert(UserInst == OnlyStore && "Should only have load/stores");
      continue;
    }
    LoadInst *LI = cast<LoadInst>(UserInst);

    // Okay, if we have a load from the alloca, we want to replace it with the
    // only value stored to the alloca.  We can do this if the value is
    // dominated by the store.  If not, we use the rest of the mem2reg machinery
    // to insert the phi nodes as needed.
    if (!StoringGlobalVal) { // Non-instructions are always dominated.
      if (LI->getParent() == StoreBB) {
        // If we have a use that is in the same block as the store, compare the
        // indices of the two instructions to see which one came first.  If the
        // load came before the store, we can't handle it.
        if (StoreIndex == -1)
          StoreIndex = LBI.getInstructionIndex(OnlyStore);

        if (unsigned(StoreIndex) > LBI.getInstructionIndex(LI)) {
          // Can't handle this load, bail out.
          Info.UsingBlocks.push_back(StoreBB);
          continue;
        }
      } else if (LI->getParent() != StoreBB &&
                 !DT.dominates(StoreBB, LI->getParent())) {
        // If the load and store are in different blocks, use BB dominance to
        // check their relationships.  If the store doesn't dom the use, bail
        Info.UsingBlocks.push_back(LI->getParent());
        continue;
      }
    }

    // Otherwise, we *can* safely rewrite this load.
    Value *ReplVal = OnlyStore->getOperand(0);
    // If the replacement value is the load, this must occur in unreachable
    if (ReplVal == LI)
      ReplVal = UndefValue::get(LI->getType());

    // If the load was marked as nonnull we don't want to lose
    // that information when we erase this Load. So we preserve
    // it with an assume.
    if (AC && LI->getMetadata(LLVMContext::MD_nonnull) &&
        !isKnownNonZero(ReplVal, DL, 0, AC, LI, &DT))
      addAssumeNonNull(AC, LI);

    LI->replaceAllUsesWith(ReplVal);
    LI->eraseFromParent();
    LBI.deleteValue(LI);
  }

  // Finally, after the scan, check to see if the store is all that is left.
  if (!Info.UsingBlocks.empty())
    return false; // If not, we'll have to fall back for the remainder.

  // Record debuginfo for the store and remove the declaration's
  for (DbgVariableIntrinsic *DII : Info.DbgDeclares) {
    DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false);
    ConvertDebugDeclareToDebugValue(DII, Info.OnlyStore, DIB);
    DII->eraseFromParent();
    LBI.deleteValue(DII);
  }
  // Remove the (now dead) store and alloca.
  Info.OnlyStore->eraseFromParent();
  LBI.deleteValue(Info.OnlyStore);

  AI->eraseFromParent();
  LBI.deleteValue(AI);
  return true;
}

/// Many allocas are only used within a single basic block.  If this is the
/// case, avoid traversing the CFG and inserting a lot of potentially useless
/// PHI nodes by just performing a single linear pass over the basic block
/// If we cannot promote this alloca (because it is read before it is written),
/// return false.  This is necessary in cases where, due to control flow, the
/// alloca is undefined only on some control flow paths.  e.g. code like
/// this is correct in LLVM IR:
///  // A is an alloca with no stores so far
static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info,
                                     LargeBlockInfo &LBI,
                                     const DataLayout &DL,
                                     DominatorTree &DT,
                                     AssumptionCache *AC) {
  // The trickiest case to handle is when we have large blocks. Because of this,
  // this code is optimized assuming that large blocks happen.  This does not
  // significantly pessimize the small block case.  This uses LargeBlockInfo to
  // make it efficient to get the index of various operations in the block.

  // Walk the use-def list of the alloca, getting the locations of all stores.
  using StoresByIndexTy = SmallVector<std::pair<unsigned, StoreInst *>, 64>;
  StoresByIndexTy StoresByIndex;

  for (User *U : AI->users())
    if (StoreInst *SI = dyn_cast<StoreInst>(U))
      StoresByIndex.push_back(std::make_pair(LBI.getInstructionIndex(SI), SI));

  // Sort the stores by their index, making it efficient to do a lookup with a
  // binary search.
  llvm::sort(StoresByIndex, less_first());

  // Walk all of the loads from this alloca, replacing them with the nearest
  // store above them, if any.
  for (auto UI = AI->user_begin(), E = AI->user_end(); UI != E;) {
    LoadInst *LI = dyn_cast<LoadInst>(*UI++);
    if (!LI)
      continue;

    unsigned LoadIdx = LBI.getInstructionIndex(LI);

    // Find the nearest store that has a lower index than this load.
    StoresByIndexTy::iterator I =
        std::lower_bound(StoresByIndex.begin(), StoresByIndex.end(),
                         std::make_pair(LoadIdx,
                                        static_cast<StoreInst *>(nullptr)),
                         less_first());
    if (I == StoresByIndex.begin()) {
      if (StoresByIndex.empty())
        // If there are no stores, the load takes the undef value.
        LI->replaceAllUsesWith(UndefValue::get(LI->getType()));
      else
        // There is no store before this load, bail out (load may be affected
        // by the following stores - see main comment).
        return false;
    } else {
      // Otherwise, there was a store before this load, the load takes its value.
      // Note, if the load was marked as nonnull we don't want to lose that
      // information when we erase it. So we preserve it with an assume.
      Value *ReplVal = std::prev(I)->second->getOperand(0);
      if (AC && LI->getMetadata(LLVMContext::MD_nonnull) &&
          !isKnownNonZero(ReplVal, DL, 0, AC, LI, &DT))
        addAssumeNonNull(AC, LI);

      // If the replacement value is the load, this must occur in unreachable
      if (ReplVal == LI)
        ReplVal = UndefValue::get(LI->getType());

      LI->replaceAllUsesWith(ReplVal);
    }

    LI->eraseFromParent();
    LBI.deleteValue(LI);
  }

  // Remove the (now dead) stores and alloca.
  while (!AI->use_empty()) {
    StoreInst *SI = cast<StoreInst>(AI->user_back());
    // Record debuginfo for the store before removing it.
    for (DbgVariableIntrinsic *DII : Info.DbgDeclares) {
      DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false);
      ConvertDebugDeclareToDebugValue(DII, SI, DIB);
    }
    SI->eraseFromParent();
    LBI.deleteValue(SI);
  }

  AI->eraseFromParent();
  LBI.deleteValue(AI);

  // The alloca's debuginfo can be removed as well.
  for (DbgVariableIntrinsic *DII : Info.DbgDeclares) {
    DII->eraseFromParent();
    LBI.deleteValue(DII);
  }

  ++NumLocalPromoted;
  return true;
}

void PromoteMem2Reg::run() {
  Function &F = *DT.getRoot()->getParent();

  AllocaDbgDeclares.resize(Allocas.size());

  AllocaInfo Info;
  LargeBlockInfo LBI;
  ForwardIDFCalculator IDF(DT);

  for (unsigned AllocaNum = 0; AllocaNum != Allocas.size(); ++AllocaNum) {
    AllocaInst *AI = Allocas[AllocaNum];

    assert(isAllocaPromotable(AI) && "Cannot promote non-promotable alloca!");
    assert(AI->getParent()->getParent() == &F &&
           "All allocas should be in the same function, which is same as DF!");

    removeLifetimeIntrinsicUsers(AI);

    if (AI->use_empty()) {
      // If there are no uses of the alloca, just delete it now.
      AI->eraseFromParent();

      // Remove the alloca from the Allocas list, since it has been processed
      RemoveFromAllocasList(AllocaNum);
      ++NumDeadAlloca;
      continue;
    }

    // Calculate the set of read and write-locations for each alloca.  This is
    // analogous to finding the 'uses' and 'definitions' of each variable.
    Info.AnalyzeAlloca(AI);

    // If there is only a single store to this value, replace any loads of
    // it that are directly dominated by the definition with the value stored.
    if (Info.DefiningBlocks.size() == 1) {
      if (rewriteSingleStoreAlloca(AI, Info, LBI, SQ.DL, DT, AC)) {
        // The alloca has been processed, move on.
        RemoveFromAllocasList(AllocaNum);
        ++NumSingleStore;
        continue;
      }
    }

    // If the alloca is only read and written in one basic block, just perform a
    // linear sweep over the block to eliminate it.
    if (Info.OnlyUsedInOneBlock &&
        promoteSingleBlockAlloca(AI, Info, LBI, SQ.DL, DT, AC)) {
      // The alloca has been processed, move on.
      RemoveFromAllocasList(AllocaNum);
      continue;
    }

    // If we haven't computed a numbering for the BB's in the function, do so
    if (BBNumbers.empty()) {
      unsigned ID = 0;
      for (auto &BB : F)
        BBNumbers[&BB] = ID++;
    }

    // Remember the dbg.declare intrinsic describing this alloca, if any.
    if (!Info.DbgDeclares.empty())
      AllocaDbgDeclares[AllocaNum] = Info.DbgDeclares;

    // Keep the reverse mapping of the 'Allocas' array for the rename pass.
    AllocaLookup[Allocas[AllocaNum]] = AllocaNum;

    // At this point, we're committed to promoting the alloca using IDF's, and
    // the standard SSA construction algorithm.  Determine which blocks need PHI
    // nodes and see if we can optimize out some work by avoiding insertion of
    // dead phi nodes.

    // Unique the set of defining blocks for efficient lookup.
    SmallPtrSet<BasicBlock *, 32> DefBlocks;
    DefBlocks.insert(Info.DefiningBlocks.begin(), Info.DefiningBlocks.end());

    // Determine which blocks the value is live in.  These are blocks which lead
    // to uses.
    SmallPtrSet<BasicBlock *, 32> LiveInBlocks;
    ComputeLiveInBlocks(AI, Info, DefBlocks, LiveInBlocks);

    // At this point, we're committed to promoting the alloca using IDF's, and
    // the standard SSA construction algorithm.  Determine which blocks need phi
    // nodes and see if we can optimize out some work by avoiding insertion of
    // dead phi nodes.
    IDF.setLiveInBlocks(LiveInBlocks);
    IDF.setDefiningBlocks(DefBlocks);
    SmallVector<BasicBlock *, 32> PHIBlocks;
    IDF.calculate(PHIBlocks);
    if (PHIBlocks.size() > 1)
      llvm::sort(PHIBlocks, [this](BasicBlock *A, BasicBlock *B) {
        return BBNumbers.lookup(A) < BBNumbers.lookup(B);
      });

    unsigned CurrentVersion = 0;
    for (BasicBlock *BB : PHIBlocks)
      QueuePhiNode(BB, AllocaNum, CurrentVersion);
  }

  if (Allocas.empty())
    return; // All of the allocas must have been trivial!

  LBI.clear();

  // Set the incoming values for the basic block to be null values for all of
  // the alloca's.  We do this in case there is a load of a value that has not
  // been stored yet.  In this case, it will get this null value.
  RenamePassData::ValVector Values(Allocas.size());
  for (unsigned i = 0, e = Allocas.size(); i != e; ++i)
    Values[i] = UndefValue::get(Allocas[i]->getAllocatedType());

  // When handling debug info, treat all incoming values as if they have unknown
  // locations until proven otherwise.
  RenamePassData::LocationVector Locations(Allocas.size());

  // Walks all basic blocks in the function performing the SSA rename algorithm
  // and inserting the phi nodes we marked as necessary
  std::vector<RenamePassData> RenamePassWorkList;
  RenamePassWorkList.emplace_back(&F.front(), nullptr, std::move(Values),
                                  std::move(Locations));
  do {
    RenamePassData RPD = std::move(RenamePassWorkList.back());
    RenamePassWorkList.pop_back();
    // RenamePass may add new worklist entries.
    RenamePass(RPD.BB, RPD.Pred, RPD.Values, RPD.Locations, RenamePassWorkList);
  } while (!RenamePassWorkList.empty());

  // The renamer uses the Visited set to avoid infinite loops.  Clear it now.
  Visited.clear();

  // Remove the allocas themselves from the function.
  for (Instruction *A : Allocas) {
    // If there are any uses of the alloca instructions left, they must be in
    // unreachable basic blocks that were not processed by walking the dominator
    // tree. Just delete the users now.
    if (!A->use_empty())
      A->replaceAllUsesWith(UndefValue::get(A->getType()));
    A->eraseFromParent();
  }

  // Remove alloca's dbg.declare instrinsics from the function.
  for (auto &Declares : AllocaDbgDeclares)
    for (auto *DII : Declares)
      DII->eraseFromParent();

  // Loop over all of the PHI nodes and see if there are any that we can get
  // rid of because they merge all of the same incoming values.  This can
  // happen due to undef values coming into the PHI nodes.  This process is
  // iterative, because eliminating one PHI node can cause others to be removed.
  bool EliminatedAPHI = true;
  while (EliminatedAPHI) {
    EliminatedAPHI = false;

    // Iterating over NewPhiNodes is deterministic, so it is safe to try to
    // simplify and RAUW them as we go.  If it was not, we could add uses to
    // the values we replace with in a non-deterministic order, thus creating
    // non-deterministic def->use chains.
    for (DenseMap<std::pair<unsigned, unsigned>, PHINode *>::iterator
             I = NewPhiNodes.begin(),
             E = NewPhiNodes.end();
         I != E;) {
      PHINode *PN = I->second;

      // If this PHI node merges one value and/or undefs, get the value.
      if (Value *V = SimplifyInstruction(PN, SQ)) {
        PN->replaceAllUsesWith(V);
        PN->eraseFromParent();
        NewPhiNodes.erase(I++);
        EliminatedAPHI = true;
        continue;
      }
      ++I;
    }
  }

  // At this point, the renamer has added entries to PHI nodes for all reachable
  // code.  Unfortunately, there may be unreachable blocks which the renamer
  // hasn't traversed.  If this is the case, the PHI nodes may not
  // have incoming values for all predecessors.  Loop over all PHI nodes we have
  // created, inserting undef values if they are missing any incoming values.
  for (DenseMap<std::pair<unsigned, unsigned>, PHINode *>::iterator
           I = NewPhiNodes.begin(),
           E = NewPhiNodes.end();
       I != E; ++I) {
    // We want to do this once per basic block.  As such, only process a block
    // when we find the PHI that is the first entry in the block.
    PHINode *SomePHI = I->second;
    BasicBlock *BB = SomePHI->getParent();
    if (&BB->front() != SomePHI)
      continue;

    // Only do work here if there the PHI nodes are missing incoming values.  We
    // know that all PHI nodes that were inserted in a block will have the same
    // number of incoming values, so we can just check any of them.
    if (SomePHI->getNumIncomingValues() == getNumPreds(BB))
      continue;

    // Get the preds for BB.
    SmallVector<BasicBlock *, 16> Preds(pred_begin(BB), pred_end(BB));

    // Ok, now we know that all of the PHI nodes are missing entries for some
    // basic blocks.  Start by sorting the incoming predecessors for efficient
    auto CompareBBNumbers = [this](BasicBlock *A, BasicBlock *B) {
      return BBNumbers.lookup(A) < BBNumbers.lookup(B);
    };
    llvm::sort(Preds, CompareBBNumbers);

    // Now we loop through all BB's which have entries in SomePHI and remove
    // them from the Preds list.
    for (unsigned i = 0, e = SomePHI->getNumIncomingValues(); i != e; ++i) {
      // Do a log(n) search of the Preds list for the entry we want.
      SmallVectorImpl<BasicBlock *>::iterator EntIt = std::lower_bound(
          Preds.begin(), Preds.end(), SomePHI->getIncomingBlock(i),
          CompareBBNumbers);
      assert(EntIt != Preds.end() && *EntIt == SomePHI->getIncomingBlock(i) &&
             "PHI node has entry for a block which is not a predecessor!");

      // Remove the entry
      Preds.erase(EntIt);
    }

    // At this point, the blocks left in the preds list must have dummy
    // entries inserted into every PHI nodes for the block.  Update all the phi
    // nodes in this block that we are inserting (there could be phis before
    unsigned NumBadPreds = SomePHI->getNumIncomingValues();
    BasicBlock::iterator BBI = BB->begin();
    while ((SomePHI = dyn_cast<PHINode>(BBI++)) &&
           SomePHI->getNumIncomingValues() == NumBadPreds) {
      Value *UndefVal = UndefValue::get(SomePHI->getType());
      for (BasicBlock *Pred : Preds)
        SomePHI->addIncoming(UndefVal, Pred);
    }
  }

  NewPhiNodes.clear();
}

/// Determine which blocks the value is live in.
/// These are blocks which lead to uses.  Knowing this allows us to avoid
/// inserting PHI nodes into blocks which don't lead to uses (thus, the
/// inserted phi nodes would be dead).
void PromoteMem2Reg::ComputeLiveInBlocks(
    AllocaInst *AI, AllocaInfo &Info,
    const SmallPtrSetImpl<BasicBlock *> &DefBlocks,
    SmallPtrSetImpl<BasicBlock *> &LiveInBlocks) {
  // To determine liveness, we must iterate through the predecessors of blocks
  // where the def is live.  Blocks are added to the worklist if we need to
  // check their predecessors.  Start with all the using blocks.
  SmallVector<BasicBlock *, 64> LiveInBlockWorklist(Info.UsingBlocks.begin(),
                                                    Info.UsingBlocks.end());

  // If any of the using blocks is also a definition block, check to see if the
  // definition occurs before or after the use.  If it happens before the use,
  // the value isn't really live-in.
  for (unsigned i = 0, e = LiveInBlockWorklist.size(); i != e; ++i) {
    BasicBlock *BB = LiveInBlockWorklist[i];
    if (!DefBlocks.count(BB))
      continue;

    // Okay, this is a block that both uses and defines the value.  If the first
    // reference to the alloca is a def (store), then we know it isn't live-in.
    for (BasicBlock::iterator I = BB->begin();; ++I) {
      if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
        if (SI->getOperand(1) != AI)
          continue;

        // We found a store to the alloca before a load.  The alloca is not
        // actually live-in here.
        LiveInBlockWorklist[i] = LiveInBlockWorklist.back();
        LiveInBlockWorklist.pop_back();
        --i;
        --e;
        break;
      }

      if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
        if (LI->getOperand(0) != AI)
          continue;

        // Okay, we found a load before a store to the alloca.  It is actually
        break;
      }
    }
  }

  // Now that we have a set of blocks where the phi is live-in, recursively add
  // their predecessors until we find the full region the value is live.
  while (!LiveInBlockWorklist.empty()) {
    BasicBlock *BB = LiveInBlockWorklist.pop_back_val();

    // The block really is live in here, insert it into the set.  If already in
    // the set, then it has already been processed.
    if (!LiveInBlocks.insert(BB).second)
      continue;

    // Since the value is live into BB, it is either defined in a predecessor or
    // live into it to.  Add the preds to the worklist unless they are a
    // defining block.
    for (BasicBlock *P : predecessors(BB)) {
      // The value is not live into a predecessor if it defines the value.
      if (DefBlocks.count(P))
        continue;

      // Otherwise it is, add to the worklist.
      LiveInBlockWorklist.push_back(P);
    }
  }
}

/// Queue a phi-node to be added to a basic-block for a specific Alloca.
/// Returns true if there wasn't already a phi-node for that variable
bool PromoteMem2Reg::QueuePhiNode(BasicBlock *BB, unsigned AllocaNo,
                                  unsigned &Version) {
  // Look up the basic-block in question.
  PHINode *&PN = NewPhiNodes[std::make_pair(BBNumbers[BB], AllocaNo)];

  // If the BB already has a phi node added for the i'th alloca then we're done!
  if (PN)
    return false;

  // Create a PhiNode using the dereferenced type... and add the phi-node to the
  PN = PHINode::Create(Allocas[AllocaNo]->getAllocatedType(), getNumPreds(BB),
                       Allocas[AllocaNo]->getName() + "." + Twine(Version++),
                       &BB->front());
  ++NumPHIInsert;
  PhiToAllocaMap[PN] = AllocaNo;
  return true;
}

/// Update the debug location of a phi. \p ApplyMergedLoc indicates whether to
/// create a merged location incorporating \p DL, or to set \p DL directly.

/// Recursively traverse the CFG of the function, renaming loads and
/// stores to the allocas which we are promoting.
/// IncomingVals indicates what value each Alloca contains on exit from the
/// predecessor block Pred.
void PromoteMem2Reg::RenamePass(BasicBlock *BB, BasicBlock *Pred,
                                RenamePassData::ValVector &IncomingVals,
                                RenamePassData::LocationVector &IncomingLocs,
                                std::vector<RenamePassData> &Worklist) {
NextIteration:
  // If we are inserting any phi nodes into this BB, they will already be in the
  if (PHINode *APN = dyn_cast<PHINode>(BB->begin())) {
    // If we have PHI nodes to update, compute the number of edges from Pred to
    if (PhiToAllocaMap.count(APN)) {
      // We want to be able to distinguish between PHI nodes being inserted by
      // this invocation of mem2reg from those phi nodes that already existed in
      // the IR before mem2reg was run.  We determine that APN is being inserted
      // because it is missing incoming edges.  All other PHI nodes being
      // inserted by this pass of mem2reg will have the same number of incoming
      // operands so far.  Remember this count.
      unsigned NewPHINumOperands = APN->getNumOperands();

      unsigned NumEdges = std::count(succ_begin(Pred), succ_end(Pred), BB);
      assert(NumEdges && "Must be at least one edge from Pred to BB!");

      // Add entries for all the phis.
      BasicBlock::iterator PNI = BB->begin();
      do {
        unsigned AllocaNo = PhiToAllocaMap[APN];

        // Update the location of the phi node.
        updateForIncomingValueLocation(APN, IncomingLocs[AllocaNo],
                                       APN->getNumIncomingValues() > 0);

        // Add N incoming values to the PHI node.
        for (unsigned i = 0; i != NumEdges; ++i)
          APN->addIncoming(IncomingVals[AllocaNo], Pred);

        // The currently active variable for this block is now the PHI.
        IncomingVals[AllocaNo] = APN;
        for (DbgVariableIntrinsic *DII : AllocaDbgDeclares[AllocaNo])
          ConvertDebugDeclareToDebugValue(DII, APN, DIB);

        // Get the next phi node.
        ++PNI;
        APN = dyn_cast<PHINode>(PNI);
        if (!APN)
          break;

        // Verify that it is missing entries.  If not, it is not being inserted
        // by this mem2reg invocation so we want to ignore it.
      } while (APN->getNumOperands() == NewPHINumOperands);
    }
  }

  // Don't revisit blocks.
  if (!Visited.insert(BB).second)
    return;

  for (BasicBlock::iterator II = BB->begin(); !II->isTerminator();) {
    Instruction *I = &*II++; // get the instruction, increment iterator

    if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
      AllocaInst *Src = dyn_cast<AllocaInst>(LI->getPointerOperand());
      if (!Src)
        continue;

      DenseMap<AllocaInst *, unsigned>::iterator AI = AllocaLookup.find(Src);
      if (AI == AllocaLookup.end())
        continue;

      Value *V = IncomingVals[AI->second];

      // If the load was marked as nonnull we don't want to lose
      // that information when we erase this Load. So we preserve
      // it with an assume.
      if (AC && LI->getMetadata(LLVMContext::MD_nonnull) &&
          !isKnownNonZero(V, SQ.DL, 0, AC, LI, &DT))
        addAssumeNonNull(AC, LI);

      // Anything using the load now uses the current value.
      LI->replaceAllUsesWith(V);
      BB->getInstList().erase(LI);
    } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
      // Delete this instruction and mark the name as the current holder of the
      // value
      AllocaInst *Dest = dyn_cast<AllocaInst>(SI->getPointerOperand());
      if (!Dest)
        continue;

      DenseMap<AllocaInst *, unsigned>::iterator ai = AllocaLookup.find(Dest);
      if (ai == AllocaLookup.end())
        continue;

      // what value were we writing?
      unsigned AllocaNo = ai->second;
      IncomingVals[AllocaNo] = SI->getOperand(0);

      // Record debuginfo for the store before removing it.
      IncomingLocs[AllocaNo] = SI->getDebugLoc();
      for (DbgVariableIntrinsic *DII : AllocaDbgDeclares[ai->second])
        ConvertDebugDeclareToDebugValue(DII, SI, DIB);
      BB->getInstList().erase(SI);
    }
  }

  // 'Recurse' to our successors.
  succ_iterator I = succ_begin(BB), E = succ_end(BB);
  if (I == E)
    return;

  // Keep track of the successors so we don't visit the same successor twice
  SmallPtrSet<BasicBlock *, 8> VisitedSuccs;

  // Handle the first successor without using the worklist.
  VisitedSuccs.insert(*I);
  Pred = BB;
  BB = *I;
  ++I;

  for (; I != E; ++I)
    if (VisitedSuccs.insert(*I).second)
      Worklist.emplace_back(*I, Pred, IncomingVals, IncomingLocs);

  goto NextIteration;
}

void llvm::PromoteMemToReg(ArrayRef<AllocaInst *> Allocas, DominatorTree &DT,
                           AssumptionCache *AC) {
  // If there is nothing to do, bail out...
  if (Allocas.empty())
    return;

  PromoteMem2Reg(Allocas, DT, AC).run();
}