<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "mediaobject.h"
#include <QtCore/QTimer>
#include <kdebug.h>
#include "videopath.h"
#include "audiopath.h"
#include "stream.h"
#include "../../abstractmediastream_p.h"
#include <QtCore/QVector>
#include <cmath>
#include <QtCore/QFile>
#include <QtCore/QByteRef>
#include <QtCore/QStringList>

namespace Phonon
{
namespace Fake
{
static const int SAMPLE_RATE = 44100;
static const float SAMPLE_RATE_FLOAT = 44100.0f;
static const int FRAME_RATE = 25;
static const int SAMPLES_PER_FRAME = SAMPLE_RATE / FRAME_RATE;

MediaObject::MediaObject(QObject *parent)
    : QObject(parent)
    , m_state(Phonon::LoadingState)
    , m_tickTimer(new QTimer(this))
    , m_bufferSize(SAMPLES_PER_FRAME)//512)
    , m_lastSamplesMissing(0)
    , m_position(0.0f)
    , m_frequency(440.0f)
    , m_prefinishMarkReachedNotEmitted(true)
{
    //kDebug(604) << k_funcinfo << endl;
    connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick()));
}

MediaObject::~MediaObject()
{
    //kDebug(604) << k_funcinfo << endl;
}

bool MediaObject::addVideoPath(QObject *videoPath)
{
    //kDebug(604) << k_funcinfo << endl;
    Q_ASSERT(videoPath);
    VideoPath *vp = qobject_cast<VideoPath *>(videoPath);
    Q_ASSERT(vp);
    Q_ASSERT(!m_videoPathList.contains(vp));
    m_videoPathList.append(vp);
    return true;
}

bool MediaObject::addAudioPath(QObject *audioPath)
{
    //kDebug(604) << k_funcinfo << endl;
    Q_ASSERT(audioPath);
    AudioPath *ap = qobject_cast<AudioPath *>(audioPath);
    Q_ASSERT(ap);
    Q_ASSERT(!m_audioPathList.contains(ap));
    m_audioPathList.append(ap);
    return true;
}

void MediaObject::removeVideoPath(QObject *videoPath)
{
    Q_ASSERT(videoPath);
    VideoPath *vp = qobject_cast<VideoPath *>(videoPath);
    Q_ASSERT(vp);
    Q_ASSERT(m_videoPathList.contains(vp));
    m_videoPathList.removeAll(vp);
}

void MediaObject::removeAudioPath(QObject *audioPath)
{
    Q_ASSERT(audioPath);
    AudioPath *ap = qobject_cast<AudioPath *>(audioPath);
    Q_ASSERT(ap);
    Q_ASSERT(m_audioPathList.contains(ap));
    m_audioPathList.removeAll(ap);
}

State MediaObject::state() const
{
    //kDebug(604) << k_funcinfo << endl;
    return m_state;
}

bool MediaObject::hasVideo() const
{
    //kDebug(604) << k_funcinfo << endl;
    return false;
}

bool MediaObject::isSeekable() const
{
    //kDebug(604) << k_funcinfo << endl;
    return true;
}

qint64 MediaObject::currentTime() const
{
    //kDebug(604) << k_funcinfo << endl;
    switch(state())
    {
    case Phonon::PausedState:
    case Phonon::BufferingState:
        return m_startTime.msecsTo(m_pauseTime);
    case Phonon::PlayingState:
        return m_startTime.elapsed();
    case Phonon::StoppedState:
    case Phonon::LoadingState:
        return 0;
    case Phonon::ErrorState:
        break;
    }
    return -1;
}

qint32 MediaObject::tickInterval() const
{
    //kDebug(604) << k_funcinfo << endl;
    return m_tickInterval;
}

void MediaObject::setTickInterval(qint32 newTickInterval)
{
    //kDebug(604) << k_funcinfo << endl;
    m_tickInterval = newTickInterval;
    if (m_tickInterval <= 0)
        m_tickTimer->setInterval(50);
    else
        m_tickTimer->setInterval(newTickInterval);
}

QStringList MediaObject::availableAudioStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QStringList MediaObject::availableVideoStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QStringList MediaObject::availableSubtitleStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QString MediaObject::currentAudioStream(const QObject *audioPath) const
{
    return m_selectedAudioStream[audioPath];
}

QString MediaObject::currentVideoStream(const QObject *videoPath) const
{
    return m_selectedVideoStream[videoPath];
}

QString MediaObject::currentSubtitleStream(const QObject *videoPath) const
{
    return m_selectedSubtitleStream[videoPath];
}

void MediaObject::setCurrentAudioStream(const QString &streamName, const QObject *audioPath)
{
    if (availableAudioStreams().contains(streamName))
        m_selectedAudioStream[audioPath] = streamName;
}

void MediaObject::setCurrentVideoStream(const QString &streamName, const QObject *videoPath)
{
    if (availableVideoStreams().contains(streamName))
        m_selectedVideoStream[videoPath] = streamName;
}

void MediaObject::setCurrentSubtitleStream(const QString &streamName, const QObject *videoPath)
{
    if (availableSubtitleStreams().contains(streamName))
        m_selectedSubtitleStream[videoPath] = streamName;
}

void MediaObject::play()
{
    //kDebug(604) << k_funcinfo << endl;
    if (m_state == Phonon::LoadingState) {
        setState(Phonon::BufferingState);
    } else {
        setState(Phonon::PlayingState);
    }
}

QString MediaObject::errorString() const
{
    return QString();
}

Phonon::ErrorType MediaObject::errorType() const
{
    return Phonon::NoError;
}

void MediaObject::setState(State newstate)
{
    if (newstate == m_state)
        return;
    State oldstate = m_state;
    m_state = newstate;
    switch(newstate)
    {
    case Phonon::PausedState:
    case Phonon::BufferingState:
        m_pauseTime.start();
        break;
    case Phonon::PlayingState:
        m_tickTimer->start();
        if (oldstate == Phonon::PausedState || oldstate == Phonon::BufferingState)
            m_startTime = m_startTime.addMSecs(m_pauseTime.elapsed());
        else
            m_startTime.start();
        break;
    case Phonon::StoppedState:
    case Phonon::ErrorState:
    case Phonon::LoadingState:
        m_startTime = QTime();
        break;
    }
    //kDebug(604) << "emit stateChanged(" << newstate << ", " << oldstate << ")" << endl;
    emit stateChanged(newstate, oldstate);
}

static const float TWOPI = 6.28318530718f;
static const float maxFrequency = 1760.0f;
static const float minFrequency = 440.0f;
static const float frequencyToDelta = TWOPI / SAMPLE_RATE_FLOAT;

void MediaObject::fillBuffer(QVector<float> *buffer)
{
    //static QFile createdump("createdump");
    //if (!createdump.isOpen())
        //createdump.open(QIODevice::WriteOnly);

    m_frequency *= 1.059463094359f;
    if (m_frequency > maxFrequency)
        m_frequency = minFrequency;
    float delta = frequencyToDelta * m_frequency;

    float *data = buffer->data();
    const float * const end = data + m_bufferSize;

    while (data != end)
    {
        const float sample = sinf(m_position);
        //createdump.write(QByteArray::number(sample) + "\n");
         *(data++) = sample;
        m_position += delta;
        if (m_position > TWOPI)
            m_position -= TWOPI;
    }
}

void MediaObject::fillFrameData(Phonon::Experimental::VideoFrame *frame)
{
    static quint32 frameCount = 0;
    quint8 *dataPtr = reinterpret_cast<quint8 *>(frame->data.data());
    for (int y = 0; y < frame->height; ++y)
        for (int x = 0; x < frame->width; ++x)
        {
             *dataPtr++ = static_cast<quint8>(0xff);
             *dataPtr++ = static_cast<quint8>((x + frameCount) * 2 / 3); //red
             *dataPtr++ = static_cast<quint8>(y + frameCount); //green
             *dataPtr++ = static_cast<quint8>(frameCount / 2); //blue
        }
    ++frameCount;
}

qint64 MediaObject::totalTime() const
{
    //kDebug(604) << k_funcinfo << endl;
    return 1000 *60 *3; // 3 minutes
}

qint32 MediaObject::prefinishMark() const
{
    //kDebug(604) << k_funcinfo << endl;
    return m_prefinishMark;
}

qint32 MediaObject::transitionTime() const
{
    return m_transitionTime;
}

void MediaObject::setTransitionTime(qint32 time)
{
    m_transitionTime = time;
}

MediaSource MediaObject::source() const
{
    return m_source;
}

void MediaObject::setNextSource(const MediaSource &source)
{
    setSource(source);
}

void MediaObject::setSource(const MediaSource &source)
{
    //kDebug(604) << k_funcinfo << endl;
    m_prefinishMarkReachedNotEmitted = true;
    m_source = source;
    setState(Phonon::LoadingState);
    switch (m_source.type()) {
    case MediaSource::Invalid:
        return;
    case MediaSource::Url:
        if (!m_source.url().isValid()) {
            return;
        }
        break;
    case MediaSource::LocalFile:
        if (m_source.filename().isEmpty()) {
            return;
        }
        break;
    case MediaSource::Stream:
        Stream *s = new Stream(m_source, this);
        //Q_ASSERT(qobject_cast<Stream *>(m_source.stream()->d_ptr->streamInterface));
        break;
    }
    emit totalTimeChanged(totalTime());
    QMultiMap<QString, QString> metaData;
    metaData.insert("TITLE", "Fake video");
    metaData.insert("ARTIST", "Matthias Kretz");
    emit metaDataChanged(metaData);
    QTimer::singleShot(50, this, SLOT(loadingComplete()));
}

void MediaObject::loadingComplete()
{
    if (state() == Phonon::LoadingState) {
        setState(Phonon::StoppedState);
    } else if (state() == Phonon::BufferingState) {
        setState(Phonon::PlayingState);
    }
}

void MediaObject::setPrefinishMark(qint32 newPrefinishMark)
{
    //kDebug(604) << k_funcinfo << endl;
    m_prefinishMark = newPrefinishMark;
    if (currentTime() < totalTime() - m_prefinishMark) // not about to finish
        m_prefinishMarkReachedNotEmitted = true;
}

void MediaObject::pause()
{
    //kDebug(604) << k_funcinfo << endl;
    switch (state()) {
    case PlayingState:
    case BufferingState:
    case StoppedState:
        m_tickTimer->stop();
        setState(Phonon::PausedState);
        break;
    case PausedState:
    case LoadingState:
    case ErrorState:
        break;
    }
}

void MediaObject::stop()
{
    //kDebug(604) << k_funcinfo << endl;
    if (state() == Phonon::PlayingState || state() == Phonon::BufferingState || state() == Phonon::PausedState) {
        m_tickTimer->stop();
        setState(Phonon::StoppedState);
        m_position = 0.0f;
        m_frequency = 440.0f;
        m_prefinishMarkReachedNotEmitted = true;
    }
}

void MediaObject::seek(qint64 time)
{
    //kDebug(604) << k_funcinfo << endl;
    if (isSeekable())
    {
        switch(state())
        {
        case Phonon::PausedState:
        case Phonon::BufferingState:
            m_startTime = m_pauseTime;
            break;
        case Phonon::PlayingState:
            m_startTime.start();
            break;
        case Phonon::StoppedState:
        case Phonon::ErrorState:
        case Phonon::LoadingState:
            return; // cannot seek
        }
        m_startTime = m_startTime.addMSecs(-time);
    }

    if (currentTime() < totalTime() - m_prefinishMark) // not about to finish
        m_prefinishMarkReachedNotEmitted = true;
}

void MediaObject::emitTick()
{
    //kDebug(604) << "emit tick(" << currentTime() << ")" << endl;
    int tickInterval = 50;
    if (m_tickInterval > 0)
    {
        emit tick(currentTime());
        tickInterval = m_tickInterval;
    }
    QVector<float> buffer(m_bufferSize);
    Experimental::VideoFrame frame;
    frame.fourcc = 0x00000000;
    frame.width = 320;
    frame.height = 240;
    frame.depth = 24;
    frame.bpp = 8;
    frame.data.resize(frame.width * frame.height * 4);

    const int availableSamples = tickInterval * SAMPLE_RATE / 1000 + m_lastSamplesMissing;
    const int bufferCount = availableSamples / m_bufferSize;
    m_lastSamplesMissing = availableSamples - bufferCount * m_bufferSize;
    for (int i = 0; i < bufferCount; ++i)
    {
        fillBuffer(&buffer);
        foreach (AudioPath *ap, m_audioPathList)
            ap->processBuffer(buffer);
        fillFrameData(&frame);
        foreach (VideoPath *vp, m_videoPathList)
            vp->processFrame(frame);
    }
    if (currentTime() >= totalTime() - m_prefinishMark) { // about to finish
        if (m_prefinishMarkReachedNotEmitted) {
            m_prefinishMarkReachedNotEmitted = false;
            emit prefinishMarkReached(totalTime() - currentTime());
        }
    }
    if (currentTime() >= totalTime()) // finished
    {
        stop();
        emit finished();
    }
}

}}

#include "mediaobject.moc"
// vim: sw=4 ts=4
<commit_msg>sinf is C99 and not C++<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License version 2 as published by the Free Software Foundation.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.

*/

#include "mediaobject.h"
#include <QtCore/QTimer>
#include <kdebug.h>
#include "videopath.h"
#include "audiopath.h"
#include "stream.h"
#include "../../abstractmediastream_p.h"
#include <QtCore/QVector>
#include <cmath>
#include <QtCore/QFile>
#include <QtCore/QByteRef>
#include <QtCore/QStringList>

namespace Phonon
{
namespace Fake
{
static const int SAMPLE_RATE = 44100;
static const float SAMPLE_RATE_FLOAT = 44100.0f;
static const int FRAME_RATE = 25;
static const int SAMPLES_PER_FRAME = SAMPLE_RATE / FRAME_RATE;

MediaObject::MediaObject(QObject *parent)
    : QObject(parent)
    , m_state(Phonon::LoadingState)
    , m_tickTimer(new QTimer(this))
    , m_bufferSize(SAMPLES_PER_FRAME)//512)
    , m_lastSamplesMissing(0)
    , m_position(0.0f)
    , m_frequency(440.0f)
    , m_prefinishMarkReachedNotEmitted(true)
{
    //kDebug(604) << k_funcinfo << endl;
    connect(m_tickTimer, SIGNAL(timeout()), SLOT(emitTick()));
}

MediaObject::~MediaObject()
{
    //kDebug(604) << k_funcinfo << endl;
}

bool MediaObject::addVideoPath(QObject *videoPath)
{
    //kDebug(604) << k_funcinfo << endl;
    Q_ASSERT(videoPath);
    VideoPath *vp = qobject_cast<VideoPath *>(videoPath);
    Q_ASSERT(vp);
    Q_ASSERT(!m_videoPathList.contains(vp));
    m_videoPathList.append(vp);
    return true;
}

bool MediaObject::addAudioPath(QObject *audioPath)
{
    //kDebug(604) << k_funcinfo << endl;
    Q_ASSERT(audioPath);
    AudioPath *ap = qobject_cast<AudioPath *>(audioPath);
    Q_ASSERT(ap);
    Q_ASSERT(!m_audioPathList.contains(ap));
    m_audioPathList.append(ap);
    return true;
}

void MediaObject::removeVideoPath(QObject *videoPath)
{
    Q_ASSERT(videoPath);
    VideoPath *vp = qobject_cast<VideoPath *>(videoPath);
    Q_ASSERT(vp);
    Q_ASSERT(m_videoPathList.contains(vp));
    m_videoPathList.removeAll(vp);
}

void MediaObject::removeAudioPath(QObject *audioPath)
{
    Q_ASSERT(audioPath);
    AudioPath *ap = qobject_cast<AudioPath *>(audioPath);
    Q_ASSERT(ap);
    Q_ASSERT(m_audioPathList.contains(ap));
    m_audioPathList.removeAll(ap);
}

State MediaObject::state() const
{
    //kDebug(604) << k_funcinfo << endl;
    return m_state;
}

bool MediaObject::hasVideo() const
{
    //kDebug(604) << k_funcinfo << endl;
    return false;
}

bool MediaObject::isSeekable() const
{
    //kDebug(604) << k_funcinfo << endl;
    return true;
}

qint64 MediaObject::currentTime() const
{
    //kDebug(604) << k_funcinfo << endl;
    switch(state())
    {
    case Phonon::PausedState:
    case Phonon::BufferingState:
        return m_startTime.msecsTo(m_pauseTime);
    case Phonon::PlayingState:
        return m_startTime.elapsed();
    case Phonon::StoppedState:
    case Phonon::LoadingState:
        return 0;
    case Phonon::ErrorState:
        break;
    }
    return -1;
}

qint32 MediaObject::tickInterval() const
{
    //kDebug(604) << k_funcinfo << endl;
    return m_tickInterval;
}

void MediaObject::setTickInterval(qint32 newTickInterval)
{
    //kDebug(604) << k_funcinfo << endl;
    m_tickInterval = newTickInterval;
    if (m_tickInterval <= 0)
        m_tickTimer->setInterval(50);
    else
        m_tickTimer->setInterval(newTickInterval);
}

QStringList MediaObject::availableAudioStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QStringList MediaObject::availableVideoStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QStringList MediaObject::availableSubtitleStreams() const
{
    QStringList ret;
    ret << QLatin1String("en") << QLatin1String("de");
    return ret;
}

QString MediaObject::currentAudioStream(const QObject *audioPath) const
{
    return m_selectedAudioStream[audioPath];
}

QString MediaObject::currentVideoStream(const QObject *videoPath) const
{
    return m_selectedVideoStream[videoPath];
}

QString MediaObject::currentSubtitleStream(const QObject *videoPath) const
{
    return m_selectedSubtitleStream[videoPath];
}

void MediaObject::setCurrentAudioStream(const QString &streamName, const QObject *audioPath)
{
    if (availableAudioStreams().contains(streamName))
        m_selectedAudioStream[audioPath] = streamName;
}

void MediaObject::setCurrentVideoStream(const QString &streamName, const QObject *videoPath)
{
    if (availableVideoStreams().contains(streamName))
        m_selectedVideoStream[videoPath] = streamName;
}

void MediaObject::setCurrentSubtitleStream(const QString &streamName, const QObject *videoPath)
{
    if (availableSubtitleStreams().contains(streamName))
        m_selectedSubtitleStream[videoPath] = streamName;
}

void MediaObject::play()
{
    //kDebug(604) << k_funcinfo << endl;
    if (m_state == Phonon::LoadingState) {
        setState(Phonon::BufferingState);
    } else {
        setState(Phonon::PlayingState);
    }
}

QString MediaObject::errorString() const
{
    return QString();
}

Phonon::ErrorType MediaObject::errorType() const
{
    return Phonon::NoError;
}

void MediaObject::setState(State newstate)
{
    if (newstate == m_state)
        return;
    State oldstate = m_state;
    m_state = newstate;
    switch(newstate)
    {
    case Phonon::PausedState:
    case Phonon::BufferingState:
        m_pauseTime.start();
        break;
    case Phonon::PlayingState:
        m_tickTimer->start();
        if (oldstate == Phonon::PausedState || oldstate == Phonon::BufferingState)
            m_startTime = m_startTime.addMSecs(m_pauseTime.elapsed());
        else
            m_startTime.start();
        break;
    case Phonon::StoppedState:
    case Phonon::ErrorState:
    case Phonon::LoadingState:
        m_startTime = QTime();
        break;
    }
    //kDebug(604) << "emit stateChanged(" << newstate << ", " << oldstate << ")" << endl;
    emit stateChanged(newstate, oldstate);
}

static const float TWOPI = 6.28318530718f;
static const float maxFrequency = 1760.0f;
static const float minFrequency = 440.0f;
static const float frequencyToDelta = TWOPI / SAMPLE_RATE_FLOAT;

void MediaObject::fillBuffer(QVector<float> *buffer)
{
    //static QFile createdump("createdump");
    //if (!createdump.isOpen())
        //createdump.open(QIODevice::WriteOnly);

    m_frequency *= 1.059463094359f;
    if (m_frequency > maxFrequency)
        m_frequency = minFrequency;
    float delta = frequencyToDelta * m_frequency;

    float *data = buffer->data();
    const float * const end = data + m_bufferSize;

    while (data != end)
    {
        const float sample = sin(m_position);
        //createdump.write(QByteArray::number(sample) + "\n");
         *(data++) = sample;
        m_position += delta;
        if (m_position > TWOPI)
            m_position -= TWOPI;
    }
}

void MediaObject::fillFrameData(Phonon::Experimental::VideoFrame *frame)
{
    static quint32 frameCount = 0;
    quint8 *dataPtr = reinterpret_cast<quint8 *>(frame->data.data());
    for (int y = 0; y < frame->height; ++y)
        for (int x = 0; x < frame->width; ++x)
        {
             *dataPtr++ = static_cast<quint8>(0xff);
             *dataPtr++ = static_cast<quint8>((x + frameCount) * 2 / 3); //red
             *dataPtr++ = static_cast<quint8>(y + frameCount); //green
             *dataPtr++ = static_cast<quint8>(frameCount / 2); //blue
        }
    ++frameCount;
}

qint64 MediaObject::totalTime() const
{
    //kDebug(604) << k_funcinfo << endl;
    return 1000 *60 *3; // 3 minutes
}

qint32 MediaObject::prefinishMark() const
{
    //kDebug(604) << k_funcinfo << endl;
    return m_prefinishMark;
}

qint32 MediaObject::transitionTime() const
{
    return m_transitionTime;
}

void MediaObject::setTransitionTime(qint32 time)
{
    m_transitionTime = time;
}

MediaSource MediaObject::source() const
{
    return m_source;
}

void MediaObject::setNextSource(const MediaSource &source)
{
    setSource(source);
}

void MediaObject::setSource(const MediaSource &source)
{
    //kDebug(604) << k_funcinfo << endl;
    m_prefinishMarkReachedNotEmitted = true;
    m_source = source;
    setState(Phonon::LoadingState);
    switch (m_source.type()) {
    case MediaSource::Invalid:
        return;
    case MediaSource::Url:
        if (!m_source.url().isValid()) {
            return;
        }
        break;
    case MediaSource::LocalFile:
        if (m_source.filename().isEmpty()) {
            return;
        }
        break;
    case MediaSource::Stream:
        Stream *s = new Stream(m_source, this);
        //Q_ASSERT(qobject_cast<Stream *>(m_source.stream()->d_ptr->streamInterface));
        break;
    }
    emit totalTimeChanged(totalTime());
    QMultiMap<QString, QString> metaData;
    metaData.insert("TITLE", "Fake video");
    metaData.insert("ARTIST", "Matthias Kretz");
    emit metaDataChanged(metaData);
    QTimer::singleShot(50, this, SLOT(loadingComplete()));
}

void MediaObject::loadingComplete()
{
    if (state() == Phonon::LoadingState) {
        setState(Phonon::StoppedState);
    } else if (state() == Phonon::BufferingState) {
        setState(Phonon::PlayingState);
    }
}

void MediaObject::setPrefinishMark(qint32 newPrefinishMark)
{
    //kDebug(604) << k_funcinfo << endl;
    m_prefinishMark = newPrefinishMark;
    if (currentTime() < totalTime() - m_prefinishMark) // not about to finish
        m_prefinishMarkReachedNotEmitted = true;
}

void MediaObject::pause()
{
    //kDebug(604) << k_funcinfo << endl;
    switch (state()) {
    case PlayingState:
    case BufferingState:
    case StoppedState:
        m_tickTimer->stop();
        setState(Phonon::PausedState);
        break;
    case PausedState:
    case LoadingState:
    case ErrorState:
        break;
    }
}

void MediaObject::stop()
{
    //kDebug(604) << k_funcinfo << endl;
    if (state() == Phonon::PlayingState || state() == Phonon::BufferingState || state() == Phonon::PausedState) {
        m_tickTimer->stop();
        setState(Phonon::StoppedState);
        m_position = 0.0f;
        m_frequency = 440.0f;
        m_prefinishMarkReachedNotEmitted = true;
    }
}

void MediaObject::seek(qint64 time)
{
    //kDebug(604) << k_funcinfo << endl;
    if (isSeekable())
    {
        switch(state())
        {
        case Phonon::PausedState:
        case Phonon::BufferingState:
            m_startTime = m_pauseTime;
            break;
        case Phonon::PlayingState:
            m_startTime.start();
            break;
        case Phonon::StoppedState:
        case Phonon::ErrorState:
        case Phonon::LoadingState:
            return; // cannot seek
        }
        m_startTime = m_startTime.addMSecs(-time);
    }

    if (currentTime() < totalTime() - m_prefinishMark) // not about to finish
        m_prefinishMarkReachedNotEmitted = true;
}

void MediaObject::emitTick()
{
    //kDebug(604) << "emit tick(" << currentTime() << ")" << endl;
    int tickInterval = 50;
    if (m_tickInterval > 0)
    {
        emit tick(currentTime());
        tickInterval = m_tickInterval;
    }
    QVector<float> buffer(m_bufferSize);
    Experimental::VideoFrame frame;
    frame.fourcc = 0x00000000;
    frame.width = 320;
    frame.height = 240;
    frame.depth = 24;
    frame.bpp = 8;
    frame.data.resize(frame.width * frame.height * 4);

    const int availableSamples = tickInterval * SAMPLE_RATE / 1000 + m_lastSamplesMissing;
    const int bufferCount = availableSamples / m_bufferSize;
    m_lastSamplesMissing = availableSamples - bufferCount * m_bufferSize;
    for (int i = 0; i < bufferCount; ++i)
    {
        fillBuffer(&buffer);
        foreach (AudioPath *ap, m_audioPathList)
            ap->processBuffer(buffer);
        fillFrameData(&frame);
        foreach (VideoPath *vp, m_videoPathList)
            vp->processFrame(frame);
    }
    if (currentTime() >= totalTime() - m_prefinishMark) { // about to finish
        if (m_prefinishMarkReachedNotEmitted) {
            m_prefinishMarkReachedNotEmitted = false;
            emit prefinishMarkReached(totalTime() - currentTime());
        }
    }
    if (currentTime() >= totalTime()) // finished
    {
        stop();
        emit finished();
    }
}

}}

#include "mediaobject.moc"
// vim: sw=4 ts=4
<|endoftext|>


<commit_before>#include "TestFunction.h"

#define TEST_LOG_TRACE   false

TEST_START(TestMain);
TEST_LOG_INIT(TEST_LOG_TRACE, LOG_TARGET_STDOUT|LOG_TARGET_FILE);
TEST_ADD(TestArrayListBasic);
TEST_ADD(TestArrayListRemove);
TEST_ADD(TestClientAdd);
TEST_ADD(TestClientBasic);
TEST_ADD(TestClientBatchedDelete);
TEST_ADD(TestClientBatchedSet);
TEST_ADD(TestClientBatchedSet2);
TEST_ADD(TestClientBatchedSetBulk);
TEST_ADD(TestClientBatchedSetRandom);
TEST_ADD(TestClientBatchLimit);
TEST_ADD(TestClientCount);
TEST_ADD(TestClientCreateSchema);
TEST_ADD(TestClientDistributeList);
TEST_ADD(TestClientAddFailover);
TEST_ADD(TestClientMaro);
TEST_ADD(TestClientGetFailover);
TEST_ADD(TestClientGetLatency);
TEST_ADD(TestClientGetSetGetSetSubmit);
TEST_ADD(TestClientInfiniteLoop);
TEST_ADD(TestClientListKeys);
TEST_ADD(TestClientListKeysMultiple);
TEST_ADD(TestClientListKeysWithPrefix);
TEST_ADD(TestClientMixedReadWriteBatched);
TEST_ADD(TestClientMixedWriteReadBatched);
TEST_ADD(TestClientMultiThread);
TEST_ADD(TestClientMultiThreadMulti);
TEST_ADD(TestClientPrintableList);
TEST_ADD(TestClientSet);
TEST_ADD(TestClientSetFailover);
TEST_ADD(TestClientShardConnectionPooling);
TEST_ADD(TestClientTransactionBasic);
TEST_ADD(TestClientTruncateTable);
TEST_ADD(TestCrashReporterAssert);
TEST_ADD(TestCrashReporterInvalidAccess);
TEST_ADD(TestCrashReporterStackOverflow);
TEST_ADD(TestCrashReporterNullPointerMemberFunction);
TEST_ADD(TestCrashReporterDivisionByZero);
TEST_ADD(TestCrashReporterDoubleFree);
TEST_ADD(TestCommonGetTotalCpuUsage);
TEST_ADD(TestCommonHumanBytes);
TEST_ADD(TestCommonHumanBytesBrute);
TEST_ADD(TestCommonRandomDistribution);
TEST_ADD(TestCommonUInt64ToBufferWithBase);
TEST_ADD(TestConfigStateJSON);
TEST_ADD(TestEndpointValidity);
TEST_ADD(TestFileSystemDiskSpace);
TEST_ADD(TestFileSystemFileSize);
TEST_ADD(TestFileSystemTruncate);
TEST_ADD(TestFormattingFD);
TEST_ADD(TestFormattingOverflow);
TEST_ADD(TestFormattingUnsigned);
TEST_ADD(TestFormattingPadding);
TEST_ADD(TestInTreeMap);
TEST_ADD(TestInTreeMapInsert);
TEST_ADD(TestInTreeMapInsertRandom);
TEST_ADD(TestInTreeMapMidpoint);
TEST_ADD(TestInTreeMapRemoveRandom);
TEST_ADD(TestJSONReaderBasic1);
TEST_ADD(TestJSONReaderBasic2);
TEST_ADD(TestJSONReaderBasic3);
TEST_ADD(TestJSONReaderBasic4);
TEST_ADD(TestJSONReaderBasic5);
TEST_ADD(TestJSONReaderBasic6);
TEST_ADD(TestJSONReaderBasic7);
TEST_ADD(TestJSONBasic);
TEST_ADD(TestJSONAdvanced);
TEST_ADD(TestJSONConfigStateReader);
TEST_ADD(TestJSONConfigStateReader_ReadAndWrite);
TEST_ADD(TestJSONConfigStateReader_Benchmark);
TEST_ADD(TestLogRotate);
TEST_ADD(TestLogRotateMultiThreaded);
TEST_ADD(TestLogTraceBuffer);
TEST_ADD(TestManualBasic);
TEST_ADD(TestMemoryOutOfMemoryError);
TEST_ADD(TestShardExtensionBasic);
TEST_ADD(TestStorageAsyncList);
TEST_ADD(TestStorageSet);
TEST_ADD(TestTimingBasicWrite);
TEST_ADD(TestTimingSnprintf);
TEST_ADD(TestTimingFileSystemWrite);
TEST_ADD(TestTimingFileSystemParallelWrite);
TEST_ADD(TestTimingWrite);
TEST_EXECUTE();

int main(int argc, char* argv[])
{
    return TestMain(argc, argv);
}
<commit_msg>Added tests to TestMain.<commit_after>#include "TestFunction.h"

#define TEST_LOG_TRACE   false

TEST_START(TestMain);
TEST_LOG_INIT(TEST_LOG_TRACE, LOG_TARGET_STDOUT|LOG_TARGET_FILE);
TEST_ADD(TestArrayListBasic);
TEST_ADD(TestArrayListRemove);
TEST_ADD(TestClientAdd);
TEST_ADD(TestClientBasic);
TEST_ADD(TestClientBatchedDelete);
TEST_ADD(TestClientBatchedSet);
TEST_ADD(TestClientBatchedSet2);
TEST_ADD(TestClientBatchedSetBulk);
TEST_ADD(TestClientBatchedSetRandom);
TEST_ADD(TestClientBatchLimit);
TEST_ADD(TestClientCount);
TEST_ADD(TestClientCreateSchema);
TEST_ADD(TestClientDistributeList);
TEST_ADD(TestClientAddFailover);
TEST_ADD(TestClientMaro);
TEST_ADD(TestClientGetFailover);
TEST_ADD(TestClientGetLatency);
TEST_ADD(TestClientGetSetGetSetSubmit);
TEST_ADD(TestClientInfiniteLoop);
TEST_ADD(TestClientListFailover);
TEST_ADD(TestClientListKeys);
TEST_ADD(TestClientListKeysMultiple);
TEST_ADD(TestClientListKeysWithPrefix);
TEST_ADD(TestClientMixedReadWriteBatched);
TEST_ADD(TestClientMixedWriteReadBatched);
TEST_ADD(TestClientMultiThread);
TEST_ADD(TestClientMultiThreadMulti);
TEST_ADD(TestClientPrintableList);
TEST_ADD(TestClientSet);
TEST_ADD(TestClientSetFailover);
TEST_ADD(TestClientSetGetFailover);
TEST_ADD(TestClientShardConnectionPooling);
TEST_ADD(TestClientTransactionBasic);
TEST_ADD(TestClientTruncateTable);
TEST_ADD(TestCrashReporterAssert);
TEST_ADD(TestCrashReporterInvalidAccess);
TEST_ADD(TestCrashReporterStackOverflow);
TEST_ADD(TestCrashReporterNullPointerMemberFunction);
TEST_ADD(TestCrashReporterDivisionByZero);
TEST_ADD(TestCrashReporterDoubleFree);
TEST_ADD(TestCommonGetTotalCpuUsage);
TEST_ADD(TestCommonHumanBytes);
TEST_ADD(TestCommonHumanBytesBrute);
TEST_ADD(TestCommonRandomDistribution);
TEST_ADD(TestCommonUInt64ToBufferWithBase);
TEST_ADD(TestConfigStateJSON);
TEST_ADD(TestEndpointValidity);
TEST_ADD(TestFileSystemDiskSpace);
TEST_ADD(TestFileSystemFileSize);
TEST_ADD(TestFileSystemTruncate);
TEST_ADD(TestFormattingFD);
TEST_ADD(TestFormattingOverflow);
TEST_ADD(TestFormattingUnsigned);
TEST_ADD(TestFormattingPadding);
TEST_ADD(TestInTreeMap);
TEST_ADD(TestInTreeMapInsert);
TEST_ADD(TestInTreeMapInsertRandom);
TEST_ADD(TestInTreeMapMidpoint);
TEST_ADD(TestInTreeMapRemoveRandom);
TEST_ADD(TestJSONReaderBasic1);
TEST_ADD(TestJSONReaderBasic2);
TEST_ADD(TestJSONReaderBasic3);
TEST_ADD(TestJSONReaderBasic4);
TEST_ADD(TestJSONReaderBasic5);
TEST_ADD(TestJSONReaderBasic6);
TEST_ADD(TestJSONReaderBasic7);
TEST_ADD(TestJSONBasic);
TEST_ADD(TestJSONAdvanced);
TEST_ADD(TestJSONConfigStateReader);
TEST_ADD(TestJSONConfigStateReader_ReadAndWrite);
TEST_ADD(TestJSONConfigStateReader_Benchmark);
TEST_ADD(TestLogRotate);
TEST_ADD(TestLogRotateMultiThreaded);
TEST_ADD(TestLogTraceBuffer);
TEST_ADD(TestManualBasic);
TEST_ADD(TestMemoryOutOfMemoryError);
TEST_ADD(TestShardExtensionBasic);
TEST_ADD(TestStorageAsyncList);
TEST_ADD(TestStorageSet);
TEST_ADD(TestTimingBasicWrite);
TEST_ADD(TestTimingSnprintf);
TEST_ADD(TestTimingFileSystemWrite);
TEST_ADD(TestTimingFileSystemParallelWrite);
TEST_ADD(TestTimingWrite);
TEST_EXECUTE();

int main(int argc, char* argv[])
{
    return TestMain(argc, argv);
}
<|endoftext|>


<commit_before>//===-- PhiElimination.cpp - Eliminate PHI nodes by inserting copies ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass eliminates machine instruction PHI nodes by inserting copy
// instructions.  This destroys SSA information, but is the desired input for
// some register allocators.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include <set>
#include <algorithm>
using namespace llvm;

namespace {
  static Statistic<> NumAtomic("phielim", "Number of atomic phis lowered");
  static Statistic<> NumSimple("phielim", "Number of simple phis lowered");

  struct VISIBILITY_HIDDEN PNE : public MachineFunctionPass {
    bool runOnMachineFunction(MachineFunction &Fn) {
      analyzePHINodes(Fn);

      bool Changed = false;

      // Eliminate PHI instructions by inserting copies into predecessor blocks.
      for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I)
        Changed |= EliminatePHINodes(Fn, *I);

      VRegPHIUseCount.clear();
      return Changed;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addPreserved<LiveVariables>();
      MachineFunctionPass::getAnalysisUsage(AU);
    }

  private:
    /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions
    /// in predecessor basic blocks.
    ///
    bool EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB);
    void LowerAtomicPHINode(MachineBasicBlock &MBB,
                            MachineBasicBlock::iterator AfterPHIsIt);

    /// analyzePHINodes - Gather information about the PHI nodes in
    /// here. In particular, we want to map the number of uses of a virtual
    /// register which is used in a PHI node. We map that to the BB the
    /// vreg is coming from. This is used later to determine when the vreg
    /// is killed in the BB.
    ///
    void analyzePHINodes(const MachineFunction& Fn);

    typedef std::pair<const MachineBasicBlock*, unsigned> BBVRegPair;
    typedef std::map<BBVRegPair, unsigned> VRegPHIUse;

    VRegPHIUse VRegPHIUseCount;
  };

  RegisterPass<PNE> X("phi-node-elimination",
                      "Eliminate PHI nodes for register allocation");
}

const PassInfo *llvm::PHIEliminationID = X.getPassInfo();

/// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in
/// predecessor basic blocks.
///
bool PNE::EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB) {
  if (MBB.empty() || MBB.front().getOpcode() != TargetInstrInfo::PHI)
    return false;   // Quick exit for basic blocks without PHIs.

  // Get an iterator to the first instruction after the last PHI node (this may
  // also be the end of the basic block).
  MachineBasicBlock::iterator AfterPHIsIt = MBB.begin();
  while (AfterPHIsIt != MBB.end() &&
         AfterPHIsIt->getOpcode() == TargetInstrInfo::PHI)
    ++AfterPHIsIt;    // Skip over all of the PHI nodes...

  while (MBB.front().getOpcode() == TargetInstrInfo::PHI)
    LowerAtomicPHINode(MBB, AfterPHIsIt);

  return true;
}

/// InstructionUsesRegister - Return true if the specified machine instr has a
/// use of the specified register.
static bool InstructionUsesRegister(MachineInstr *MI, unsigned SrcReg) {
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i)
    if (MI->getOperand(i).isRegister() &&
        MI->getOperand(i).getReg() == SrcReg &&
        MI->getOperand(i).isUse())
      return true;
  return false;
}

/// LowerAtomicPHINode - Lower the PHI node at the top of the specified block,
/// under the assuption that it needs to be lowered in a way that supports
/// atomic execution of PHIs.  This lowering method is always correct all of the
/// time.
void PNE::LowerAtomicPHINode(MachineBasicBlock &MBB,
                             MachineBasicBlock::iterator AfterPHIsIt) {
  // Unlink the PHI node from the basic block, but don't delete the PHI yet.
  MachineInstr *MPhi = MBB.remove(MBB.begin());

  unsigned DestReg = MPhi->getOperand(0).getReg();

  // Create a new register for the incoming PHI arguments/
  MachineFunction &MF = *MBB.getParent();
  const TargetRegisterClass *RC = MF.getSSARegMap()->getRegClass(DestReg);
  unsigned IncomingReg = MF.getSSARegMap()->createVirtualRegister(RC);

  // Insert a register to register copy in the top of the current block (but
  // after any remaining phi nodes) which copies the new incoming register
  // into the phi node destination.
  //
  const MRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();
  RegInfo->copyRegToReg(MBB, AfterPHIsIt, DestReg, IncomingReg, RC);

  // Update live variable information if there is any...
  LiveVariables *LV = getAnalysisToUpdate<LiveVariables>();
  if (LV) {
    MachineInstr *PHICopy = prior(AfterPHIsIt);

    // Add information to LiveVariables to know that the incoming value is
    // killed.  Note that because the value is defined in several places (once
    // each for each incoming block), the "def" block and instruction fields
    // for the VarInfo is not filled in.
    //
    LV->addVirtualRegisterKilled(IncomingReg, PHICopy);

    // Since we are going to be deleting the PHI node, if it is the last use
    // of any registers, or if the value itself is dead, we need to move this
    // information over to the new copy we just inserted.
    //
    LV->removeVirtualRegistersKilled(MPhi);

    // If the result is dead, update LV.
    if (LV->RegisterDefIsDead(MPhi, DestReg)) {
      LV->addVirtualRegisterDead(DestReg, PHICopy);
      LV->removeVirtualRegistersDead(MPhi);
    }

    // Realize that the destination register is defined by the PHI copy now, not
    // the PHI itself.
    LV->getVarInfo(DestReg).DefInst = PHICopy;
  }

  // Adjust the VRegPHIUseCount map to account for the removal of this PHI
  // node.
  unsigned NumPreds = (MPhi->getNumOperands()-1)/2;
  for (unsigned i = 1; i != MPhi->getNumOperands(); i += 2)
    VRegPHIUseCount[BBVRegPair(
                      MPhi->getOperand(i + 1).getMachineBasicBlock(),
                      MPhi->getOperand(i).getReg())] -= NumPreds;

  // Now loop over all of the incoming arguments, changing them to copy into
  // the IncomingReg register in the corresponding predecessor basic block.
  //
  std::set<MachineBasicBlock*> MBBsInsertedInto;
  for (int i = MPhi->getNumOperands() - 1; i >= 2; i-=2) {
    unsigned SrcReg = MPhi->getOperand(i-1).getReg();
    assert(MRegisterInfo::isVirtualRegister(SrcReg) &&
           "Machine PHI Operands must all be virtual registers!");

    // Get the MachineBasicBlock equivalent of the BasicBlock that is the
    // source path the PHI.
    MachineBasicBlock &opBlock = *MPhi->getOperand(i).getMachineBasicBlock();

    // Check to make sure we haven't already emitted the copy for this block.
    // This can happen because PHI nodes may have multiple entries for the
    // same basic block.
    if (!MBBsInsertedInto.insert(&opBlock).second)
      continue;  // If the copy has already been emitted, we're done.

    // Get an iterator pointing to the first terminator in the block (or end()).
    // This is the point where we can insert a copy if we'd like to.
    MachineBasicBlock::iterator I = opBlock.getFirstTerminator();

    // Insert the copy.
    RegInfo->copyRegToReg(opBlock, I, IncomingReg, SrcReg, RC);

    // Now update live variable information if we have it.  Otherwise we're done
    if (!LV) continue;

    // We want to be able to insert a kill of the register if this PHI
    // (aka, the copy we just inserted) is the last use of the source
    // value.  Live variable analysis conservatively handles this by
    // saying that the value is live until the end of the block the PHI
    // entry lives in.  If the value really is dead at the PHI copy, there
    // will be no successor blocks which have the value live-in.
    //
    // Check to see if the copy is the last use, and if so, update the
    // live variables information so that it knows the copy source
    // instruction kills the incoming value.
    //
    LiveVariables::VarInfo &InRegVI = LV->getVarInfo(SrcReg);

    // Loop over all of the successors of the basic block, checking to see
    // if the value is either live in the block, or if it is killed in the
    // block.  Also check to see if this register is in use by another PHI
    // node which has not yet been eliminated.  If so, it will be killed
    // at an appropriate point later.
    //

    // Is it used by any PHI instructions in this block?
    bool ValueIsLive =
      VRegPHIUseCount[BBVRegPair(
                        MPhi->getOperand(i).getMachineBasicBlock(),
                        SrcReg)] != 0;

    std::vector<MachineBasicBlock*> OpSuccBlocks;

    // Otherwise, scan successors, including the BB the PHI node lives in.
    for (MachineBasicBlock::succ_iterator SI = opBlock.succ_begin(),
           E = opBlock.succ_end(); SI != E && !ValueIsLive; ++SI) {
      MachineBasicBlock *SuccMBB = *SI;

      // Is it alive in this successor?
      unsigned SuccIdx = SuccMBB->getNumber();
      if (SuccIdx < InRegVI.AliveBlocks.size() &&
          InRegVI.AliveBlocks[SuccIdx]) {
        ValueIsLive = true;
        break;
      }

      OpSuccBlocks.push_back(SuccMBB);
    }

    // Check to see if this value is live because there is a use in a successor
    // that kills it.
    if (!ValueIsLive) {
      switch (OpSuccBlocks.size()) {
      case 1: {
        MachineBasicBlock *MBB = OpSuccBlocks[0];
        for (unsigned i = 0, e = InRegVI.Kills.size(); i != e; ++i)
          if (InRegVI.Kills[i]->getParent() == MBB) {
            ValueIsLive = true;
            break;
          }
        break;
      }
      case 2: {
        MachineBasicBlock *MBB1 = OpSuccBlocks[0], *MBB2 = OpSuccBlocks[1];
        for (unsigned i = 0, e = InRegVI.Kills.size(); i != e; ++i)
          if (InRegVI.Kills[i]->getParent() == MBB1 ||
              InRegVI.Kills[i]->getParent() == MBB2) {
            ValueIsLive = true;
            break;
          }
        break;
      }
      default:
        std::sort(OpSuccBlocks.begin(), OpSuccBlocks.end());
        for (unsigned i = 0, e = InRegVI.Kills.size(); i != e; ++i)
          if (std::binary_search(OpSuccBlocks.begin(), OpSuccBlocks.end(),
                                 InRegVI.Kills[i]->getParent())) {
            ValueIsLive = true;
            break;
          }
      }
    }

    // Okay, if we now know that the value is not live out of the block,
    // we can add a kill marker in this block saying that it kills the incoming
    // value!
    if (!ValueIsLive) {
      // In our final twist, we have to decide which instruction kills the
      // register.  In most cases this is the copy, however, the first
      // terminator instruction at the end of the block may also use the value.
      // In this case, we should mark *it* as being the killing block, not the
      // copy.
      bool FirstTerminatorUsesValue = false;
      if (I != opBlock.end()) {
        FirstTerminatorUsesValue = InstructionUsesRegister(I, SrcReg);

        // Check that no other terminators use values.
#ifndef NDEBUG
        for (MachineBasicBlock::iterator TI = next(I); TI != opBlock.end();
             ++TI) {
          assert(!InstructionUsesRegister(TI, SrcReg) &&
                 "Terminator instructions cannot use virtual registers unless"
                 "they are the first terminator in a block!");
        }
#endif
      }

      MachineBasicBlock::iterator KillInst;
      if (!FirstTerminatorUsesValue)
        KillInst = prior(I);
      else
        KillInst = I;

      // Finally, mark it killed.
      LV->addVirtualRegisterKilled(SrcReg, KillInst);

      // This vreg no longer lives all of the way through opBlock.
      unsigned opBlockNum = opBlock.getNumber();
      if (opBlockNum < InRegVI.AliveBlocks.size())
        InRegVI.AliveBlocks[opBlockNum] = false;
    }
  }

  // Really delete the PHI instruction now!
  delete MPhi;
  ++NumAtomic;
}

/// analyzePHINodes - Gather information about the PHI nodes in here. In
/// particular, we want to map the number of uses of a virtual register which is
/// used in a PHI node. We map that to the BB the vreg is coming from. This is
/// used later to determine when the vreg is killed in the BB.
///
void PNE::analyzePHINodes(const MachineFunction& Fn) {
  for (MachineFunction::const_iterator I = Fn.begin(), E = Fn.end();
       I != E; ++I)
    for (MachineBasicBlock::const_iterator BBI = I->begin(), BBE = I->end();
         BBI != BBE && BBI->getOpcode() == TargetInstrInfo::PHI; ++BBI)
      for (unsigned i = 1, e = BBI->getNumOperands(); i != e; i += 2)
        VRegPHIUseCount[BBVRegPair(
                          BBI->getOperand(i + 1).getMachineBasicBlock(),
                          BBI->getOperand(i).getReg())]++;
}
<commit_msg>re-revert this patch, bisort and mst are still broken in Olden.<commit_after>//===-- PhiElimination.cpp - Eliminate PHI nodes by inserting copies ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass eliminates machine instruction PHI nodes by inserting copy
// instructions.  This destroys SSA information, but is the desired input for
// some register allocators.
//
//===----------------------------------------------------------------------===//

#include "llvm/CodeGen/LiveVariables.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/SSARegMap.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/Compiler.h"
#include <set>
#include <algorithm>
using namespace llvm;

namespace {
  static Statistic<> NumAtomic("phielim", "Number of atomic phis lowered");
  static Statistic<> NumSimple("phielim", "Number of simple phis lowered");

  struct VISIBILITY_HIDDEN PNE : public MachineFunctionPass {
    bool runOnMachineFunction(MachineFunction &Fn) {
      analyzePHINodes(Fn);

      bool Changed = false;

      // Eliminate PHI instructions by inserting copies into predecessor blocks.
      for (MachineFunction::iterator I = Fn.begin(), E = Fn.end(); I != E; ++I)
        Changed |= EliminatePHINodes(Fn, *I);

      VRegPHIUseCount.clear();
      return Changed;
    }

    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addPreserved<LiveVariables>();
      MachineFunctionPass::getAnalysisUsage(AU);
    }

  private:
    /// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions
    /// in predecessor basic blocks.
    ///
    bool EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB);
    void LowerAtomicPHINode(MachineBasicBlock &MBB,
                            MachineBasicBlock::iterator AfterPHIsIt);

    /// analyzePHINodes - Gather information about the PHI nodes in
    /// here. In particular, we want to map the number of uses of a virtual
    /// register which is used in a PHI node. We map that to the BB the
    /// vreg is coming from. This is used later to determine when the vreg
    /// is killed in the BB.
    ///
    void analyzePHINodes(const MachineFunction& Fn);

    typedef std::pair<const MachineBasicBlock*, unsigned> BBVRegPair;
    typedef std::map<BBVRegPair, unsigned> VRegPHIUse;

    VRegPHIUse VRegPHIUseCount;
  };

  RegisterPass<PNE> X("phi-node-elimination",
                      "Eliminate PHI nodes for register allocation");
}

const PassInfo *llvm::PHIEliminationID = X.getPassInfo();

/// EliminatePHINodes - Eliminate phi nodes by inserting copy instructions in
/// predecessor basic blocks.
///
bool PNE::EliminatePHINodes(MachineFunction &MF, MachineBasicBlock &MBB) {
  if (MBB.empty() || MBB.front().getOpcode() != TargetInstrInfo::PHI)
    return false;   // Quick exit for basic blocks without PHIs.

  // Get an iterator to the first instruction after the last PHI node (this may
  // also be the end of the basic block).
  MachineBasicBlock::iterator AfterPHIsIt = MBB.begin();
  while (AfterPHIsIt != MBB.end() &&
         AfterPHIsIt->getOpcode() == TargetInstrInfo::PHI)
    ++AfterPHIsIt;    // Skip over all of the PHI nodes...

  while (MBB.front().getOpcode() == TargetInstrInfo::PHI)
    LowerAtomicPHINode(MBB, AfterPHIsIt);

  return true;
}

/// InstructionUsesRegister - Return true if the specified machine instr has a
/// use of the specified register.
static bool InstructionUsesRegister(MachineInstr *MI, unsigned SrcReg) {
  for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i)
    if (MI->getOperand(i).isRegister() &&
        MI->getOperand(i).getReg() == SrcReg &&
        MI->getOperand(i).isUse())
      return true;
  return false;
}

/// LowerAtomicPHINode - Lower the PHI node at the top of the specified block,
/// under the assuption that it needs to be lowered in a way that supports
/// atomic execution of PHIs.  This lowering method is always correct all of the
/// time.
void PNE::LowerAtomicPHINode(MachineBasicBlock &MBB,
                             MachineBasicBlock::iterator AfterPHIsIt) {
  // Unlink the PHI node from the basic block, but don't delete the PHI yet.
  MachineInstr *MPhi = MBB.remove(MBB.begin());

  unsigned DestReg = MPhi->getOperand(0).getReg();

  // Create a new register for the incoming PHI arguments/
  MachineFunction &MF = *MBB.getParent();
  const TargetRegisterClass *RC = MF.getSSARegMap()->getRegClass(DestReg);
  unsigned IncomingReg = MF.getSSARegMap()->createVirtualRegister(RC);

  // Insert a register to register copy in the top of the current block (but
  // after any remaining phi nodes) which copies the new incoming register
  // into the phi node destination.
  //
  const MRegisterInfo *RegInfo = MF.getTarget().getRegisterInfo();
  RegInfo->copyRegToReg(MBB, AfterPHIsIt, DestReg, IncomingReg, RC);

  // Update live variable information if there is any...
  LiveVariables *LV = getAnalysisToUpdate<LiveVariables>();
  if (LV) {
    MachineInstr *PHICopy = prior(AfterPHIsIt);

    // Add information to LiveVariables to know that the incoming value is
    // killed.  Note that because the value is defined in several places (once
    // each for each incoming block), the "def" block and instruction fields
    // for the VarInfo is not filled in.
    //
    LV->addVirtualRegisterKilled(IncomingReg, PHICopy);

    // Since we are going to be deleting the PHI node, if it is the last use
    // of any registers, or if the value itself is dead, we need to move this
    // information over to the new copy we just inserted.
    //
    LV->removeVirtualRegistersKilled(MPhi);

    // If the result is dead, update LV.
    if (LV->RegisterDefIsDead(MPhi, DestReg)) {
      LV->addVirtualRegisterDead(DestReg, PHICopy);
      LV->removeVirtualRegistersDead(MPhi);
    }

    // Realize that the destination register is defined by the PHI copy now, not
    // the PHI itself.
    LV->getVarInfo(DestReg).DefInst = PHICopy;
  }

  // Adjust the VRegPHIUseCount map to account for the removal of this PHI
  // node.
  unsigned NumPreds = (MPhi->getNumOperands()-1)/2;
  for (unsigned i = 1; i != MPhi->getNumOperands(); i += 2)
    VRegPHIUseCount[BBVRegPair(
                      MPhi->getOperand(i + 1).getMachineBasicBlock(),
                      MPhi->getOperand(i).getReg())] -= NumPreds;

  // Now loop over all of the incoming arguments, changing them to copy into
  // the IncomingReg register in the corresponding predecessor basic block.
  //
  std::set<MachineBasicBlock*> MBBsInsertedInto;
  for (int i = MPhi->getNumOperands() - 1; i >= 2; i-=2) {
    unsigned SrcReg = MPhi->getOperand(i-1).getReg();
    assert(MRegisterInfo::isVirtualRegister(SrcReg) &&
           "Machine PHI Operands must all be virtual registers!");

    // Get the MachineBasicBlock equivalent of the BasicBlock that is the
    // source path the PHI.
    MachineBasicBlock &opBlock = *MPhi->getOperand(i).getMachineBasicBlock();

    // Check to make sure we haven't already emitted the copy for this block.
    // This can happen because PHI nodes may have multiple entries for the
    // same basic block.
    if (!MBBsInsertedInto.insert(&opBlock).second)
      continue;  // If the copy has already been emitted, we're done.

    // Get an iterator pointing to the first terminator in the block (or end()).
    // This is the point where we can insert a copy if we'd like to.
    MachineBasicBlock::iterator I = opBlock.getFirstTerminator();

    // Insert the copy.
    RegInfo->copyRegToReg(opBlock, I, IncomingReg, SrcReg, RC);

    // Now update live variable information if we have it.  Otherwise we're done
    if (!LV) continue;

    // We want to be able to insert a kill of the register if this PHI
    // (aka, the copy we just inserted) is the last use of the source
    // value.  Live variable analysis conservatively handles this by
    // saying that the value is live until the end of the block the PHI
    // entry lives in.  If the value really is dead at the PHI copy, there
    // will be no successor blocks which have the value live-in.
    //
    // Check to see if the copy is the last use, and if so, update the
    // live variables information so that it knows the copy source
    // instruction kills the incoming value.
    //
    LiveVariables::VarInfo &InRegVI = LV->getVarInfo(SrcReg);

    // Loop over all of the successors of the basic block, checking to see
    // if the value is either live in the block, or if it is killed in the
    // block.  Also check to see if this register is in use by another PHI
    // node which has not yet been eliminated.  If so, it will be killed
    // at an appropriate point later.
    //

    // Is it used by any PHI instructions in this block?
    bool ValueIsLive =
      VRegPHIUseCount[BBVRegPair(
                        MPhi->getOperand(i).getMachineBasicBlock(),
                        SrcReg)] != 0;

    std::vector<MachineBasicBlock*> OpSuccBlocks;

    // Otherwise, scan successors, including the BB the PHI node lives in.
    for (MachineBasicBlock::succ_iterator SI = opBlock.succ_begin(),
           E = opBlock.succ_end(); SI != E && !ValueIsLive; ++SI) {
      MachineBasicBlock *SuccMBB = *SI;

      // Is it alive in this successor?
      unsigned SuccIdx = SuccMBB->getNumber();
      if (SuccIdx < InRegVI.AliveBlocks.size() &&
          InRegVI.AliveBlocks[SuccIdx]) {
        ValueIsLive = true;
        break;
      }

      OpSuccBlocks.push_back(SuccMBB);
    }

    // Check to see if this value is live because there is a use in a successor
    // that kills it.
    if (!ValueIsLive) {
      switch (OpSuccBlocks.size()) {
      case 1: {
        MachineBasicBlock *MBB = OpSuccBlocks[0];
        for (unsigned i = 0, e = InRegVI.Kills.size(); i != e; ++i)
          if (InRegVI.Kills[i]->getParent() == MBB) {
            ValueIsLive = true;
            break;
          }
        break;
      }
      case 2: {
        MachineBasicBlock *MBB1 = OpSuccBlocks[0], *MBB2 = OpSuccBlocks[1];
        for (unsigned i = 0, e = InRegVI.Kills.size(); i != e; ++i)
          if (InRegVI.Kills[i]->getParent() == MBB1 ||
              InRegVI.Kills[i]->getParent() == MBB2) {
            ValueIsLive = true;
            break;
          }
        break;
      }
      default:
        std::sort(OpSuccBlocks.begin(), OpSuccBlocks.end());
        for (unsigned i = 0, e = InRegVI.Kills.size(); i != e; ++i)
          if (std::binary_search(OpSuccBlocks.begin(), OpSuccBlocks.end(),
                                 InRegVI.Kills[i]->getParent())) {
            ValueIsLive = true;
            break;
          }
      }
    }

    // Okay, if we now know that the value is not live out of the block,
    // we can add a kill marker in this block saying that it kills the incoming
    // value!
    if (!ValueIsLive) {
      // In our final twist, we have to decide which instruction kills the
      // register.  In most cases this is the copy, however, the first
      // terminator instruction at the end of the block may also use the value.
      // In this case, we should mark *it* as being the killing block, not the
      // copy.
      bool FirstTerminatorUsesValue = false;
      if (I != opBlock.end()) {
        FirstTerminatorUsesValue = InstructionUsesRegister(I, SrcReg);

        // Check that no other terminators use values.
#ifndef NDEBUG
        for (MachineBasicBlock::iterator TI = next(I); TI != opBlock.end();
             ++TI) {
          assert(!InstructionUsesRegister(TI, SrcReg) &&
                 "Terminator instructions cannot use virtual registers unless"
                 "they are the first terminator in a block!");
        }
#endif
      }

      MachineBasicBlock::iterator KillInst;
      if (!FirstTerminatorUsesValue)
        KillInst = prior(I);
      else
        KillInst = I;

      // Finally, mark it killed.
      LV->addVirtualRegisterKilled(SrcReg, KillInst);

      // This vreg no longer lives all of the way through opBlock.
      unsigned opBlockNum = opBlock.getNumber();
      if (opBlockNum < InRegVI.AliveBlocks.size())
        InRegVI.AliveBlocks[opBlockNum] = false;
    }
  }

  // Really delete the PHI instruction now!
  delete MPhi;
  ++NumAtomic;
}

/// analyzePHINodes - Gather information about the PHI nodes in here. In
/// particular, we want to map the number of uses of a virtual register which is
/// used in a PHI node. We map that to the BB the vreg is coming from. This is
/// used later to determine when the vreg is killed in the BB.
///
void PNE::analyzePHINodes(const MachineFunction& Fn) {
  for (MachineFunction::const_iterator I = Fn.begin(), E = Fn.end();
       I != E; ++I)
    for (MachineBasicBlock::const_iterator BBI = I->begin(), BBE = I->end();
         BBI != BBE && BBI->getOpcode() == TargetInstrInfo::PHI; ++BBI)
      for (unsigned i = 1, e = BBI->getNumOperands(); i != e; i += 2)
        VRegPHIUseCount[BBVRegPair(
                          BBI->getOperand(i + 1).getMachineBasicBlock(),
                          BBI->getOperand(i).getReg())]++;
}
<|endoftext|>


<commit_before>//===-- StackProtector.cpp - Stack Protector Insertion --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass inserts stack protectors into functions which need them. A variable
// with a random value in it is stored onto the stack before the local variables
// are allocated. Upon exiting the block, the stored value is checked. If it's
// changed, then there was some sort of violation and the program aborts.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "stack-protector"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;

// SSPBufferSize - The lower bound for a buffer to be considered for stack
// smashing protection.
static cl::opt<unsigned>
SSPBufferSize("stack-protector-buffer-size", cl::init(8),
              cl::desc("The lower bound for a buffer to be considered for "
                       "stack smashing protection."));

namespace {
  class VISIBILITY_HIDDEN StackProtector : public FunctionPass {
    /// Level - The level of stack protection.
    SSP::StackProtectorLevel Level;

    /// TLI - Keep a pointer of a TargetLowering to consult for determining
    /// target type sizes.
    const TargetLowering *TLI;

    Function *F;
    Module *M;

    /// InsertStackProtectors - Insert code into the prologue and epilogue of
    /// the function.
    ///
    ///  - The prologue code loads and stores the stack guard onto the stack.
    ///  - The epilogue checks the value stored in the prologue against the
    ///    original value. It calls __stack_chk_fail if they differ.
    bool InsertStackProtectors();

    /// CreateFailBB - Create a basic block to jump to when the stack protector
    /// check fails.
    BasicBlock *CreateFailBB();

    /// RequiresStackProtector - Check whether or not this function needs a
    /// stack protector based upon the stack protector level.
    bool RequiresStackProtector() const;
  public:
    static char ID;             // Pass identification, replacement for typeid.
    StackProtector() : FunctionPass(&ID), Level(SSP::OFF), TLI(0) {}
    StackProtector(SSP::StackProtectorLevel lvl, const TargetLowering *tli)
      : FunctionPass(&ID), Level(lvl), TLI(tli) {}

    virtual bool runOnFunction(Function &Fn);
  };
} // end anonymous namespace

char StackProtector::ID = 0;
static RegisterPass<StackProtector>
X("stack-protector", "Insert stack protectors");

FunctionPass *llvm::createStackProtectorPass(SSP::StackProtectorLevel lvl,
                                             const TargetLowering *tli) {
  return new StackProtector(lvl, tli);
}

bool StackProtector::runOnFunction(Function &Fn) {
  F = &Fn;
  M = F->getParent();

  if (!RequiresStackProtector()) return false;

  return InsertStackProtectors();
}

/// InsertStackProtectors - Insert code into the prologue and epilogue of the
/// function.
///
///  - The prologue code loads and stores the stack guard onto the stack.
///  - The epilogue checks the value stored in the prologue against the original
///    value. It calls __stack_chk_fail if they differ.
bool StackProtector::InsertStackProtectors() {
  std::vector<BasicBlock*> ReturnBBs;

  for (Function::iterator I = F->begin(); I != F->end(); ++I)
    if (isa<ReturnInst>(I->getTerminator()))
      ReturnBBs.push_back(I);

  // If this function doesn't return, don't bother with stack protectors.
  if (ReturnBBs.empty()) return false;

  // Insert code into the entry block that stores the __stack_chk_guard variable
  // onto the stack.
  BasicBlock &Entry = F->getEntryBlock();
  Instruction *InsertPt = &Entry.front();

  const PointerType *GuardTy = PointerType::getUnqual(Type::Int8Ty);

  // The global variable for the stack guard.
  Constant *StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", GuardTy);
  LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", false, InsertPt);
  CallInst::
    Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector_create),
           LI, "", InsertPt);

  // Create the basic block to jump to when the guard check fails.
  BasicBlock *FailBB = CreateFailBB();

  // Loop through the basic blocks that have return instructions. Convert this:
  //
  //   return:
  //     ...
  //     ret ...
  //
  // into this:
  //
  //   return:
  //     ...
  //     %1 = load __stack_chk_guard
  //     %2 = load <stored stack guard>
  //     %3 = cmp i1 %1, %2
  //     br i1 %3, label %SP_return, label %CallStackCheckFailBlk
  //
  //   SP_return:
  //     ret ...
  //
  //   CallStackCheckFailBlk:
  //     call void @__stack_chk_fail()
  //     unreachable
  //
  for (std::vector<BasicBlock*>::iterator
         I = ReturnBBs.begin(), E = ReturnBBs.end(); I != E; ++I) {
    BasicBlock *BB = *I;
    ReturnInst *RI = cast<ReturnInst>(BB->getTerminator());
    Function::iterator InsPt = BB; ++InsPt; // Insertion point for new BB.

    // Split the basic block before the return instruction.
    BasicBlock *NewBB = BB->splitBasicBlock(RI, "SP_return");

    // Move the newly created basic block to the point right after the old basic
    // block so that it's in the "fall through" position.
    NewBB->removeFromParent();
    F->getBasicBlockList().insert(InsPt, NewBB);

    // Generate the stack protector instructions in the old basic block.
    LoadInst *LI1 = new LoadInst(StackGuardVar, "", false, BB);
    CallInst *CI = CallInst::
      Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector_check),
             "", BB);
    ICmpInst *Cmp = new ICmpInst(CmpInst::ICMP_EQ, CI, LI1, "", BB);
    BranchInst::Create(NewBB, FailBB, Cmp, BB);
  }

  return true;
}

/// CreateFailBB - Create a basic block to jump to when the stack protector
/// check fails.
BasicBlock *StackProtector::CreateFailBB() {
  BasicBlock *FailBB = BasicBlock::Create("CallStackCheckFailBlk", F);
  Constant *StackChkFail =
    M->getOrInsertFunction("__stack_chk_fail", Type::VoidTy, NULL);
  CallInst::Create(StackChkFail, "", FailBB);
  new UnreachableInst(FailBB);
  return FailBB;
}

/// RequiresStackProtector - Check whether or not this function needs a stack
/// protector based upon the stack protector level. The heuristic we use is to
/// add a guard variable to functions that call alloca, and functions with
/// buffers larger than 8 bytes.
bool StackProtector::RequiresStackProtector() const {
  switch (Level) {
  default: return false;
  case SSP::ALL: return true;
  case SSP::SOME: {
    // If the size of the local variables allocated on the stack is greater than
    // SSPBufferSize, then we require a stack protector.
    uint64_t StackSize = 0;
    const TargetData *TD = TLI->getTargetData();

    for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
      BasicBlock *BB = I;

      for (BasicBlock::iterator
             II = BB->begin(), IE = BB->end(); II != IE; ++II)
        if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
          if (!AI->isArrayAllocation()) continue; // Only care about arrays.

          if (ConstantInt *CI = dyn_cast<ConstantInt>(AI->getArraySize())) {
            const Type *Ty = AI->getAllocatedType();
            uint64_t TySize = TD->getABITypeSize(Ty);
            StackSize += TySize * CI->getZExtValue(); // Total allocated size.

            if (SSPBufferSize <= StackSize)
              return true;
          } else {
            // This is a call to alloca with a variable size. Default to adding
            // stack protectors.
            return true;
          }
        }
    }

    return false;
  }
  }
}
<commit_msg>The size limit is for individual arrays. So if any array has more than 8 bytes in it, then emit stack protectors.<commit_after>//===-- StackProtector.cpp - Stack Protector Insertion --------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass inserts stack protectors into functions which need them. A variable
// with a random value in it is stored onto the stack before the local variables
// are allocated. Upon exiting the block, the stored value is checked. If it's
// changed, then there was some sort of violation and the program aborts.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "stack-protector"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Intrinsics.h"
#include "llvm/Module.h"
#include "llvm/Pass.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLowering.h"
using namespace llvm;

// SSPBufferSize - The lower bound for a buffer to be considered for stack
// smashing protection.
static cl::opt<unsigned>
SSPBufferSize("stack-protector-buffer-size", cl::init(8),
              cl::desc("The lower bound for a buffer to be considered for "
                       "stack smashing protection."));

namespace {
  class VISIBILITY_HIDDEN StackProtector : public FunctionPass {
    /// Level - The level of stack protection.
    SSP::StackProtectorLevel Level;

    /// TLI - Keep a pointer of a TargetLowering to consult for determining
    /// target type sizes.
    const TargetLowering *TLI;

    Function *F;
    Module *M;

    /// InsertStackProtectors - Insert code into the prologue and epilogue of
    /// the function.
    ///
    ///  - The prologue code loads and stores the stack guard onto the stack.
    ///  - The epilogue checks the value stored in the prologue against the
    ///    original value. It calls __stack_chk_fail if they differ.
    bool InsertStackProtectors();

    /// CreateFailBB - Create a basic block to jump to when the stack protector
    /// check fails.
    BasicBlock *CreateFailBB();

    /// RequiresStackProtector - Check whether or not this function needs a
    /// stack protector based upon the stack protector level.
    bool RequiresStackProtector() const;
  public:
    static char ID;             // Pass identification, replacement for typeid.
    StackProtector() : FunctionPass(&ID), Level(SSP::OFF), TLI(0) {}
    StackProtector(SSP::StackProtectorLevel lvl, const TargetLowering *tli)
      : FunctionPass(&ID), Level(lvl), TLI(tli) {}

    virtual bool runOnFunction(Function &Fn);
  };
} // end anonymous namespace

char StackProtector::ID = 0;
static RegisterPass<StackProtector>
X("stack-protector", "Insert stack protectors");

FunctionPass *llvm::createStackProtectorPass(SSP::StackProtectorLevel lvl,
                                             const TargetLowering *tli) {
  return new StackProtector(lvl, tli);
}

bool StackProtector::runOnFunction(Function &Fn) {
  F = &Fn;
  M = F->getParent();

  if (!RequiresStackProtector()) return false;

  return InsertStackProtectors();
}

/// InsertStackProtectors - Insert code into the prologue and epilogue of the
/// function.
///
///  - The prologue code loads and stores the stack guard onto the stack.
///  - The epilogue checks the value stored in the prologue against the original
///    value. It calls __stack_chk_fail if they differ.
bool StackProtector::InsertStackProtectors() {
  std::vector<BasicBlock*> ReturnBBs;

  for (Function::iterator I = F->begin(); I != F->end(); ++I)
    if (isa<ReturnInst>(I->getTerminator()))
      ReturnBBs.push_back(I);

  // If this function doesn't return, don't bother with stack protectors.
  if (ReturnBBs.empty()) return false;

  // Insert code into the entry block that stores the __stack_chk_guard variable
  // onto the stack.
  BasicBlock &Entry = F->getEntryBlock();
  Instruction *InsertPt = &Entry.front();

  const PointerType *GuardTy = PointerType::getUnqual(Type::Int8Ty);

  // The global variable for the stack guard.
  Constant *StackGuardVar = M->getOrInsertGlobal("__stack_chk_guard", GuardTy);
  LoadInst *LI = new LoadInst(StackGuardVar, "StackGuard", false, InsertPt);
  CallInst::
    Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector_create),
           LI, "", InsertPt);

  // Create the basic block to jump to when the guard check fails.
  BasicBlock *FailBB = CreateFailBB();

  // Loop through the basic blocks that have return instructions. Convert this:
  //
  //   return:
  //     ...
  //     ret ...
  //
  // into this:
  //
  //   return:
  //     ...
  //     %1 = load __stack_chk_guard
  //     %2 = load <stored stack guard>
  //     %3 = cmp i1 %1, %2
  //     br i1 %3, label %SP_return, label %CallStackCheckFailBlk
  //
  //   SP_return:
  //     ret ...
  //
  //   CallStackCheckFailBlk:
  //     call void @__stack_chk_fail()
  //     unreachable
  //
  for (std::vector<BasicBlock*>::iterator
         I = ReturnBBs.begin(), E = ReturnBBs.end(); I != E; ++I) {
    BasicBlock *BB = *I;
    ReturnInst *RI = cast<ReturnInst>(BB->getTerminator());
    Function::iterator InsPt = BB; ++InsPt; // Insertion point for new BB.

    // Split the basic block before the return instruction.
    BasicBlock *NewBB = BB->splitBasicBlock(RI, "SP_return");

    // Move the newly created basic block to the point right after the old basic
    // block so that it's in the "fall through" position.
    NewBB->removeFromParent();
    F->getBasicBlockList().insert(InsPt, NewBB);

    // Generate the stack protector instructions in the old basic block.
    LoadInst *LI1 = new LoadInst(StackGuardVar, "", false, BB);
    CallInst *CI = CallInst::
      Create(Intrinsic::getDeclaration(M, Intrinsic::stackprotector_check),
             "", BB);
    ICmpInst *Cmp = new ICmpInst(CmpInst::ICMP_EQ, CI, LI1, "", BB);
    BranchInst::Create(NewBB, FailBB, Cmp, BB);
  }

  return true;
}

/// CreateFailBB - Create a basic block to jump to when the stack protector
/// check fails.
BasicBlock *StackProtector::CreateFailBB() {
  BasicBlock *FailBB = BasicBlock::Create("CallStackCheckFailBlk", F);
  Constant *StackChkFail =
    M->getOrInsertFunction("__stack_chk_fail", Type::VoidTy, NULL);
  CallInst::Create(StackChkFail, "", FailBB);
  new UnreachableInst(FailBB);
  return FailBB;
}

/// RequiresStackProtector - Check whether or not this function needs a stack
/// protector based upon the stack protector level. The heuristic we use is to
/// add a guard variable to functions that call alloca, and functions with
/// buffers larger than 8 bytes.
bool StackProtector::RequiresStackProtector() const {
  switch (Level) {
  default: return false;
  case SSP::ALL: return true;
  case SSP::SOME: {
    const TargetData *TD = TLI->getTargetData();

    for (Function::iterator I = F->begin(), E = F->end(); I != E; ++I) {
      BasicBlock *BB = I;

      for (BasicBlock::iterator
             II = BB->begin(), IE = BB->end(); II != IE; ++II)
        if (AllocaInst *AI = dyn_cast<AllocaInst>(II)) {
          if (!AI->isArrayAllocation()) continue; // Only care about arrays.

          if (ConstantInt *CI = dyn_cast<ConstantInt>(AI->getArraySize())) {
            const Type *Ty = AI->getAllocatedType();
            uint64_t TySize = TD->getABITypeSize(Ty);

            // If an array has more than 8 bytes of allocated space, then we
            // emit stack protectors.
            if (SSPBufferSize <= TySize * CI->getZExtValue())
              return true;
          } else {
            // This is a call to alloca with a variable size. Default to adding
            // stack protectors.
            return true;
          }
        }
    }

    return false;
  }
  }
}
<|endoftext|>