<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2004-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 "factory.h"
#include "factory_p.h"

#include "backendinterface.h"
#include "medianode_p.h"
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "globalstatic_p.h"
#include "platformplugin.h"
#include "phononnamespace_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QLibrary>
#include <QtCore/QList>
#include <QtCore/QPluginLoader>
#include <QtDBus/QtDBus>
#include <QtGui/QIcon>

namespace Phonon
{

PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)

void Factory::createBackend(const QString &library, const QString &version)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        globalFactory->m_backendObject = f->createBackend(library, version);
    }
}

bool FactoryPrivate::createBackend()
{
    Q_ASSERT(m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        m_backendObject = f->createBackend();
    }
    if (!m_backendObject) {
        // could not load a backend through the platform plugin. Falling back to the default.
#if defined(Q_WS_MAC)
        const QLatin1String pluginName("libphonon_qt7");
        const QLatin1String suffix("/phonon/");
#elif defined(Q_WS_WIN)
#if defined(QT_NO_DEBUG)
        const QLatin1String pluginName("phonon_ds9");
#else
        const QLatin1String pluginName("phonon_ds9d");
#endif
        const QLatin1String suffix("/phonon_backend/");
#else
        const QLatin1String pluginName("xine");
        const QLatin1String suffix("/phonon_backend/");
#endif
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            QLibrary pluginLib(libPath + pluginName);
            if (pluginLib.load()) {
                pDebug() << Q_FUNC_INFO << "trying to load " << pluginLib.fileName();
                QPluginLoader pluginLoader(pluginLib.fileName());
                Q_ASSERT(pluginLoader.load());
                pDebug() << pluginLoader.instance();
                m_backendObject = pluginLoader.instance();
                if (m_backendObject) {
                    break;
                }
            }
        }
        if (!m_backendObject) {
            pDebug() << Q_FUNC_INFO << "phonon plugin could not be loaded:" << pluginName;
            return false;
        }
    }

    connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SLOT(objectDescriptionChanged(ObjectDescriptionType)));

    return true;
}

FactoryPrivate::FactoryPrivate()
    : m_backendObject(0),
    m_platformPlugin(0),
    m_noPlatformPlugin(false)
{
    // Add the post routine to make sure that all other global statics (especially the ones from Qt)
    // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
    // as the whole backend might still be alive.
    qAddPostRoutine(globalFactory.destroy);
#ifndef QT_NO_DBUS
    QDBusConnection::sessionBus().connect(QString(), QString(), "org.kde.Phonon.Factory",
            "phononBackendChanged", this, SLOT(phononBackendChanged()));
#endif
}

FactoryPrivate::~FactoryPrivate()
{
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->deleteBackendObject();
    }
    if (objects.size() > 0) {
        pError() << "The backend objects are not deleted as was requested.";
        qDeleteAll(objects);
    }
    delete m_backendObject;
    delete m_platformPlugin;
}

void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
{
#ifdef PHONON_METHODTEST
    Q_UNUSED(type);
#else
    pDebug() << Q_FUNC_INFO << type;
    switch (type) {
    case AudioOutputDeviceType:
        emit availableAudioOutputDevicesChanged();
        break;
    default:
        break;
    }
    //emit capabilitiesChanged();
#endif // PHONON_METHODTEST
}

Factory::Sender *Factory::sender()
{
    return globalFactory;
}

bool Factory::isMimeTypeAvailable(const QString &mimeType)
{
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        return f->isMimeTypeAvailable(mimeType);
    }
    return true; // the MIME type might be supported, let BackendCapabilities find out
}

void Factory::registerFrontendObject(MediaNodePrivate *bp)
{
    globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
}

void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
{
    // The Factory can already be cleaned up while there are other frontend objects still alive.
    // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
    if (!globalFactory.isDestroyed()) {
        globalFactory->mediaNodePrivateList.removeAll(bp);
    }
}

void FactoryPrivate::phononBackendChanged()
{
    if (m_backendObject) {
        foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
            bp->deleteBackendObject();
        }
        if (objects.size() > 0) {
            pDebug() << "WARNING: we were asked to change the backend but the application did\n"
                "not free all references to objects created by the factory. Therefore we can not\n"
                "change the backend without crashing. Now we have to wait for a restart to make\n"
                "backendswitching possible.";
            // in case there were objects deleted give 'em a chance to recreate
            // them now
            foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
                bp->createBackendObject();
            }
            return;
        }
        delete m_backendObject;
        m_backendObject = 0;
    }
    createBackend();
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->createBackendObject();
    }
    emit backendChanged();
}

//X void Factory::freeSoundcardDevices()
//X {
//X     if (globalFactory->backend) {
//X         globalFactory->backend->freeSoundcardDevices();
//X     }
//X }

void FactoryPrivate::objectDestroyed(QObject * obj)
{
    //pDebug() << Q_FUNC_INFO << obj;
    objects.removeAll(obj);
}

#define FACTORY_IMPL(classname) \
QObject *Factory::create ## classname(QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
    } \
    return 0; \
}
#define FACTORY_IMPL_1ARG(classname) \
QObject *Factory::create ## classname(int arg1, QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
    } \
    return 0; \
}

FACTORY_IMPL(MediaObject)
FACTORY_IMPL_1ARG(Effect)
FACTORY_IMPL(VolumeFaderEffect)
FACTORY_IMPL(AudioOutput)
FACTORY_IMPL(AudioDataOutput)
FACTORY_IMPL(Visualization)
FACTORY_IMPL(VideoDataOutput)
FACTORY_IMPL(VideoWidget)

#undef FACTORY_IMPL

PlatformPlugin *FactoryPrivate::platformPlugin()
{
    if (!m_platformPlugin) {
        if (m_noPlatformPlugin) {
            return 0;
        }
        if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
            pFatal("Phonon needs QCoreApplication::applicationName to be set");
        }
        const QString suffix(QLatin1String("/phonon_platform"));
        Q_ASSERT(QCoreApplication::instance());
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            QLibrary pluginLib(libPath + QLatin1String("/kde"));
            if (pluginLib.load()) {
                pDebug() << Q_FUNC_INFO << "trying to load " << pluginLib.fileName();
                QPluginLoader pluginLoader(pluginLib.fileName());
                Q_ASSERT(pluginLoader.load());
                pDebug() << pluginLoader.instance();
                m_platformPlugin = qobject_cast<PlatformPlugin *>(pluginLoader.instance());
                pDebug() << m_platformPlugin;
                if (m_platformPlugin) {
                    return m_platformPlugin;
                }
            } else {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the KDE platform plugin was not loadable:" << pluginLib.errorString();
            }
        }
        if (!m_platformPlugin) {
            pDebug() << Q_FUNC_INFO << "phonon_platform/kde plugin could not be loaded";
            m_noPlatformPlugin = true;
        }
    }
    return m_platformPlugin;
}

PlatformPlugin *Factory::platformPlugin()
{
    return globalFactory->platformPlugin();
}

QObject *Factory::backend(bool createWhenNull)
{
    if (createWhenNull && globalFactory->m_backendObject == 0) {
        globalFactory->createBackend();
        // XXX: might create "reentrancy" problems:
        // a method calls this method and is called again because the
        // backendChanged signal is emitted
        emit globalFactory->backendChanged();
    }
    return globalFactory->m_backendObject;
}

#define GET_STRING_PROPERTY(name) \
QString Factory::name() \
{ \
    if (globalFactory->m_backendObject) { \
        return globalFactory->m_backendObject->property(#name).toString(); \
    } \
    return QString(); \
} \

GET_STRING_PROPERTY(identifier)
GET_STRING_PROPERTY(backendName)
GET_STRING_PROPERTY(backendComment)
GET_STRING_PROPERTY(backendVersion)
GET_STRING_PROPERTY(backendIcon)
GET_STRING_PROPERTY(backendWebsite)

QObject *Factory::registerQObject(QObject *o)
{
    if (o) {
        QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
        globalFactory->objects.append(o);
    }
    return o;
}

} //namespace Phonon

#include "moc_factory.cpp"
#include "moc_factory_p.cpp"

// vim: sw=4 ts=4
<commit_msg>better debug output (output the failure reason when asserting)<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2004-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 "factory.h"
#include "factory_p.h"

#include "backendinterface.h"
#include "medianode_p.h"
#include "audiooutput.h"
#include "audiooutput_p.h"
#include "globalstatic_p.h"
#include "platformplugin.h"
#include "phononnamespace_p.h"

#include <QtCore/QCoreApplication>
#include <QtCore/QDir>
#include <QtCore/QFile>
#include <QtCore/QLibrary>
#include <QtCore/QList>
#include <QtCore/QPluginLoader>
#include <QtDBus/QtDBus>
#include <QtGui/QIcon>

namespace Phonon
{

PHONON_GLOBAL_STATIC(Phonon::FactoryPrivate, globalFactory)

void Factory::createBackend(const QString &library, const QString &version)
{
    Q_ASSERT(globalFactory->m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        globalFactory->m_backendObject = f->createBackend(library, version);
    }
}

bool FactoryPrivate::createBackend()
{
    Q_ASSERT(m_backendObject == 0);
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        m_backendObject = f->createBackend();
    }
    if (!m_backendObject) {
        // could not load a backend through the platform plugin. Falling back to the default.
#if defined(Q_WS_MAC)
        const QLatin1String pluginName("libphonon_qt7");
        const QLatin1String suffix("/phonon/");
#elif defined(Q_WS_WIN)
#if defined(QT_NO_DEBUG)
        const QLatin1String pluginName("phonon_ds9");
#else
        const QLatin1String pluginName("phonon_ds9d");
#endif
        const QLatin1String suffix("/phonon_backend/");
#else
        const QLatin1String pluginName("xine");
        const QLatin1String suffix("/phonon_backend/");
#endif
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            QLibrary pluginLib(libPath + pluginName);
            if (pluginLib.load()) {
                pDebug() << Q_FUNC_INFO << "trying to load " << pluginLib.fileName();
                QPluginLoader pluginLoader(pluginLib.fileName());
                Q_ASSERT(pluginLoader.load());
                pDebug() << pluginLoader.instance();
                m_backendObject = pluginLoader.instance();
                if (m_backendObject) {
                    break;
                }
            }
        }
        if (!m_backendObject) {
            pDebug() << Q_FUNC_INFO << "phonon plugin could not be loaded:" << pluginName;
            return false;
        }
    }

    connect(m_backendObject, SIGNAL(objectDescriptionChanged(ObjectDescriptionType)),
            SLOT(objectDescriptionChanged(ObjectDescriptionType)));

    return true;
}

FactoryPrivate::FactoryPrivate()
    : m_backendObject(0),
    m_platformPlugin(0),
    m_noPlatformPlugin(false)
{
    // Add the post routine to make sure that all other global statics (especially the ones from Qt)
    // are still available. If the FactoryPrivate dtor is called too late many bad things can happen
    // as the whole backend might still be alive.
    qAddPostRoutine(globalFactory.destroy);
#ifndef QT_NO_DBUS
    QDBusConnection::sessionBus().connect(QString(), QString(), "org.kde.Phonon.Factory",
            "phononBackendChanged", this, SLOT(phononBackendChanged()));
#endif
}

FactoryPrivate::~FactoryPrivate()
{
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->deleteBackendObject();
    }
    if (objects.size() > 0) {
        pError() << "The backend objects are not deleted as was requested.";
        qDeleteAll(objects);
    }
    delete m_backendObject;
    delete m_platformPlugin;
}

void FactoryPrivate::objectDescriptionChanged(ObjectDescriptionType type)
{
#ifdef PHONON_METHODTEST
    Q_UNUSED(type);
#else
    pDebug() << Q_FUNC_INFO << type;
    switch (type) {
    case AudioOutputDeviceType:
        emit availableAudioOutputDevicesChanged();
        break;
    default:
        break;
    }
    //emit capabilitiesChanged();
#endif // PHONON_METHODTEST
}

Factory::Sender *Factory::sender()
{
    return globalFactory;
}

bool Factory::isMimeTypeAvailable(const QString &mimeType)
{
    PlatformPlugin *f = globalFactory->platformPlugin();
    if (f) {
        return f->isMimeTypeAvailable(mimeType);
    }
    return true; // the MIME type might be supported, let BackendCapabilities find out
}

void Factory::registerFrontendObject(MediaNodePrivate *bp)
{
    globalFactory->mediaNodePrivateList.prepend(bp); // inserted last => deleted first
}

void Factory::deregisterFrontendObject(MediaNodePrivate *bp)
{
    // The Factory can already be cleaned up while there are other frontend objects still alive.
    // When those are deleted they'll call deregisterFrontendObject through ~BasePrivate
    if (!globalFactory.isDestroyed()) {
        globalFactory->mediaNodePrivateList.removeAll(bp);
    }
}

void FactoryPrivate::phononBackendChanged()
{
    if (m_backendObject) {
        foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
            bp->deleteBackendObject();
        }
        if (objects.size() > 0) {
            pDebug() << "WARNING: we were asked to change the backend but the application did\n"
                "not free all references to objects created by the factory. Therefore we can not\n"
                "change the backend without crashing. Now we have to wait for a restart to make\n"
                "backendswitching possible.";
            // in case there were objects deleted give 'em a chance to recreate
            // them now
            foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
                bp->createBackendObject();
            }
            return;
        }
        delete m_backendObject;
        m_backendObject = 0;
    }
    createBackend();
    foreach (MediaNodePrivate *bp, mediaNodePrivateList) {
        bp->createBackendObject();
    }
    emit backendChanged();
}

//X void Factory::freeSoundcardDevices()
//X {
//X     if (globalFactory->backend) {
//X         globalFactory->backend->freeSoundcardDevices();
//X     }
//X }

void FactoryPrivate::objectDestroyed(QObject * obj)
{
    //pDebug() << Q_FUNC_INFO << obj;
    objects.removeAll(obj);
}

#define FACTORY_IMPL(classname) \
QObject *Factory::create ## classname(QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent)); \
    } \
    return 0; \
}
#define FACTORY_IMPL_1ARG(classname) \
QObject *Factory::create ## classname(int arg1, QObject *parent) \
{ \
    if (backend()) { \
        return registerQObject(qobject_cast<BackendInterface *>(backend())->createObject(BackendInterface::classname##Class, parent, QList<QVariant>() << arg1)); \
    } \
    return 0; \
}

FACTORY_IMPL(MediaObject)
FACTORY_IMPL_1ARG(Effect)
FACTORY_IMPL(VolumeFaderEffect)
FACTORY_IMPL(AudioOutput)
FACTORY_IMPL(AudioDataOutput)
FACTORY_IMPL(Visualization)
FACTORY_IMPL(VideoDataOutput)
FACTORY_IMPL(VideoWidget)

#undef FACTORY_IMPL

PlatformPlugin *FactoryPrivate::platformPlugin()
{
    if (!m_platformPlugin) {
        if (m_noPlatformPlugin) {
            return 0;
        }
        if (!QCoreApplication::instance() || QCoreApplication::applicationName().isEmpty()) {
            pFatal("Phonon needs QCoreApplication::applicationName to be set");
        }
        const QString suffix(QLatin1String("/phonon_platform"));
        Q_ASSERT(QCoreApplication::instance());
        foreach (QString libPath, QCoreApplication::libraryPaths()) {
            libPath += suffix;
            const QDir dir(libPath);
            if (!dir.exists()) {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "does not exist";
                continue;
            }
            QLibrary pluginLib(libPath + QLatin1String("/kde"));
            if (pluginLib.load()) {
                pDebug() << Q_FUNC_INFO << "trying to load " << pluginLib.fileName();
                QPluginLoader pluginLoader(pluginLib.fileName());
                Q_ASSERT_X(pluginLoader.load(), Q_FUNC_INFO,
                           qPrintable(pluginLoader.errorString()));
                pDebug() << pluginLoader.instance();
                m_platformPlugin = qobject_cast<PlatformPlugin *>(pluginLoader.instance());
                pDebug() << m_platformPlugin;
                if (m_platformPlugin) {
                    return m_platformPlugin;
                }
            } else {
                pDebug() << Q_FUNC_INFO << dir.absolutePath() << "exists but the KDE platform plugin was not loadable:" << pluginLib.errorString();
            }
        }
        if (!m_platformPlugin) {
            pDebug() << Q_FUNC_INFO << "phonon_platform/kde plugin could not be loaded";
            m_noPlatformPlugin = true;
        }
    }
    return m_platformPlugin;
}

PlatformPlugin *Factory::platformPlugin()
{
    return globalFactory->platformPlugin();
}

QObject *Factory::backend(bool createWhenNull)
{
    if (createWhenNull && globalFactory->m_backendObject == 0) {
        globalFactory->createBackend();
        // XXX: might create "reentrancy" problems:
        // a method calls this method and is called again because the
        // backendChanged signal is emitted
        emit globalFactory->backendChanged();
    }
    return globalFactory->m_backendObject;
}

#define GET_STRING_PROPERTY(name) \
QString Factory::name() \
{ \
    if (globalFactory->m_backendObject) { \
        return globalFactory->m_backendObject->property(#name).toString(); \
    } \
    return QString(); \
} \

GET_STRING_PROPERTY(identifier)
GET_STRING_PROPERTY(backendName)
GET_STRING_PROPERTY(backendComment)
GET_STRING_PROPERTY(backendVersion)
GET_STRING_PROPERTY(backendIcon)
GET_STRING_PROPERTY(backendWebsite)

QObject *Factory::registerQObject(QObject *o)
{
    if (o) {
        QObject::connect(o, SIGNAL(destroyed(QObject *)), globalFactory, SLOT(objectDestroyed(QObject *)), Qt::DirectConnection);
        globalFactory->objects.append(o);
    }
    return o;
}

} //namespace Phonon

#include "moc_factory.cpp"
#include "moc_factory_p.cpp"

// vim: sw=4 ts=4
<|endoftext|>


<commit_before>#pragma once

#include <boost/noncopyable.hpp>

#include "error_checked.hpp"
#include "type_traits.hpp"

namespace rusql { namespace mysql {
	struct TooFewBoundParameters : SQLError { TooFewBoundParameters(std::string const msg) : SQLError(msg) {} };
	struct TooManyBoundParameters : SQLError { TooManyBoundParameters(std::string const msg) : SQLError(msg) {} };

	template <typename T>
	MYSQL_BIND get_mysql_bind(T const& x){
		MYSQL_BIND b;
		std::memset(&b, 0, sizeof(b));
		b.buffer_type = type_traits<T>::type::get(x);
		b.buffer = type_traits<T>::data::get(const_cast<T&>(x));
		b.buffer_length = type_traits<T>::length::get(x);
		b.is_unsigned = type_traits<T>::is_unsigned::get(x);
		return b;
	}

	template <typename T>
	std::pair<MYSQL_BIND, OutputProcessor> get_mysql_output_bind(T& x, my_bool &is_null){
		MYSQL_BIND b;
		std::memset(&b, 0, sizeof(b));
		b.buffer_type = type_traits<T>::output_type::get(x);
		b.buffer = type_traits<T>::data::get(x);
		b.buffer_length = type_traits<T>::length::get(x);
		b.is_unsigned = type_traits<T>::is_unsigned::get(x);
		b.is_null = &is_null;
		return std::make_pair(b, type_traits<T>::output_processor::get(x));
	}

	struct Statement : boost::noncopyable {
		Connection& connection;
		MYSQL_STMT* statement;

		struct OutputHelper {
			OutputProcessor post_process;
			my_bool is_null;
		};

		//TODO: Rename to input_parameters
		std::vector<MYSQL_BIND> parameters;
		std::vector<MYSQL_BIND> output_parameters;
		std::vector<OutputHelper> output_helpers;

		Statement(Connection& connection_, std::string const query)
		: connection(connection_)
		, statement(connection.stmt_init())
		{
			prepare(query);
		}

		Statement(Statement&& x)
		: connection(x.connection)
		, statement(std::move(x.statement))
		, parameters(std::move(x.parameters))
		, output_parameters(std::move(x.output_parameters))
		, output_helpers(std::move(x.output_helpers))
		{
			x.statement = nullptr;
		}

		Statement& operator=(Statement&& x){
			std::swap(*this, x);
			return *this;
		}

		~Statement(){
			if(statement != nullptr){
				close();
			}
		}

		inline void check_and_throw(std::string const & function) {
			char const * const error = mysql_stmt_error(statement);
			if(error[0]){
				throw SQLError(function, error);
			}
		}

		template<typename T>
		void bind_parameter(T const & v) {
			parameters.emplace_back(get_mysql_bind(v));
			//auto const& b = parameters.back();
			//auto length = b.buffer_length;
			//char* begin = (char*)b.buffer;
			//char* end = &((char*)b.buffer)[length];
			//COUT << "Bound arg: type: " << b.buffer_type << " data (length: " << length << " ): " << std::string(begin, end) <<  std::endl;
		}

		template<typename T, typename... Tail>
		void bind(T const & v, Tail const &... tail) {
			bind_parameter(v);
			bind(tail...);
		}

		//! Base case for bind
		void bind(){
			if(param_count() < parameters.size()){
				throw TooManyBoundParameters("You've bound too many parameters");
			} else if(param_count() > parameters.size()){
				throw TooFewBoundParameters("You've bound too few parameters");
			}
			bind_param(parameters.data());
		}

		template <typename T>
		void bind_result_element(T& v){
			OutputHelper helper;
			auto res = get_mysql_output_bind(v, helper.is_null);

			output_parameters.emplace_back(res.first);
			helper.post_process = res.second;
			output_helpers.emplace_back(helper);
			assert(output_parameters.size() == output_helpers.size());
		}

		template <typename T, typename ... Tail>
		void bind_results(T& v, Tail& ... tail){
			bind_result_element(v);
			bind_results(tail ...);
		}

		void bind_results(){
			bind_result(output_parameters.data());
		}

		int prepare(std::string const q){
			return rusql::mysql::stmt_prepare(statement, q);
		}

		size_t param_count(){
			return rusql::mysql::stmt_param_count(statement);
		}

		my_bool bind_param(MYSQL_BIND* binds){
			return rusql::mysql::stmt_bind_param(statement, binds);
		}

		my_bool bind_result(MYSQL_BIND* binds){
			return rusql::mysql::stmt_bind_result(statement, binds);
		}

		int fetch(){
			int res = rusql::mysql::stmt_fetch(statement);
			if(res != MYSQL_NO_DATA) {
				// post-process the bind results
				for(unsigned i = 0; i < output_parameters.size(); ++i) {
					MYSQL_BIND &bound = output_parameters.at(i);
					auto &helper = output_helpers.at(i);
					helper.post_process(bound);
				}
			}
			return res;
		}

		int execute(){
			return rusql::mysql::stmt_execute(statement);
		}

		unsigned long long insert_id() {
			return rusql::mysql::stmt_insert_id(statement);
		}

		void store_result() {
			rusql::mysql::stmt_store_result(statement);
		}

		/*! You need to call store_result() before this function returns anything other than 0. This
		 * is a MySQL limitation. */
		unsigned long long num_rows() {
			return rusql::mysql::stmt_num_rows(statement);
		}

		my_bool close(){
			auto const result = rusql::mysql::stmt_close(statement);
			statement = nullptr;
			return result;
		}
	};
}}
<commit_msg>Fix is_null binding since last commit: accidentally bounded a pointer to a temporary instead of a pointer to its permanent copy.<commit_after>#pragma once

#include <boost/noncopyable.hpp>

#include "error_checked.hpp"
#include "type_traits.hpp"

namespace rusql { namespace mysql {
	struct TooFewBoundParameters : SQLError { TooFewBoundParameters(std::string const msg) : SQLError(msg) {} };
	struct TooManyBoundParameters : SQLError { TooManyBoundParameters(std::string const msg) : SQLError(msg) {} };

	template <typename T>
	MYSQL_BIND get_mysql_bind(T const& x){
		MYSQL_BIND b;
		std::memset(&b, 0, sizeof(b));
		b.buffer_type = type_traits<T>::type::get(x);
		b.buffer = type_traits<T>::data::get(const_cast<T&>(x));
		b.buffer_length = type_traits<T>::length::get(x);
		b.is_unsigned = type_traits<T>::is_unsigned::get(x);
		return b;
	}

	template <typename T>
	std::pair<MYSQL_BIND, OutputProcessor> get_mysql_output_bind(T& x, my_bool &is_null){
		MYSQL_BIND b;
		std::memset(&b, 0, sizeof(b));
		b.buffer_type = type_traits<T>::output_type::get(x);
		b.buffer = type_traits<T>::data::get(x);
		b.buffer_length = type_traits<T>::length::get(x);
		b.is_unsigned = type_traits<T>::is_unsigned::get(x);
		b.is_null = &is_null;
		return std::make_pair(b, type_traits<T>::output_processor::get(x));
	}

	struct Statement : boost::noncopyable {
		Connection& connection;
		MYSQL_STMT* statement;

		struct OutputHelper {
			OutputProcessor post_process;
			my_bool is_null;
		};

		//TODO: Rename to input_parameters
		std::vector<MYSQL_BIND> parameters;
		std::vector<MYSQL_BIND> output_parameters;
		std::vector<OutputHelper> output_helpers;

		Statement(Connection& connection_, std::string const query)
		: connection(connection_)
		, statement(connection.stmt_init())
		{
			prepare(query);
		}

		Statement(Statement&& x)
		: connection(x.connection)
		, statement(std::move(x.statement))
		, parameters(std::move(x.parameters))
		, output_parameters(std::move(x.output_parameters))
		, output_helpers(std::move(x.output_helpers))
		{
			x.statement = nullptr;
		}

		Statement& operator=(Statement&& x){
			std::swap(*this, x);
			return *this;
		}

		~Statement(){
			if(statement != nullptr){
				close();
			}
		}

		inline void check_and_throw(std::string const & function) {
			char const * const error = mysql_stmt_error(statement);
			if(error[0]){
				throw SQLError(function, error);
			}
		}

		template<typename T>
		void bind_parameter(T const & v) {
			parameters.emplace_back(get_mysql_bind(v));
			//auto const& b = parameters.back();
			//auto length = b.buffer_length;
			//char* begin = (char*)b.buffer;
			//char* end = &((char*)b.buffer)[length];
			//COUT << "Bound arg: type: " << b.buffer_type << " data (length: " << length << " ): " << std::string(begin, end) <<  std::endl;
		}

		template<typename T, typename... Tail>
		void bind(T const & v, Tail const &... tail) {
			bind_parameter(v);
			bind(tail...);
		}

		//! Base case for bind
		void bind(){
			if(param_count() < parameters.size()){
				throw TooManyBoundParameters("You've bound too many parameters");
			} else if(param_count() > parameters.size()){
				throw TooFewBoundParameters("You've bound too few parameters");
			}
			bind_param(parameters.data());
		}

		template <typename T>
		void bind_result_element(T& v){
			output_helpers.emplace_back(OutputHelper());
			OutputHelper &helper = output_helpers.back();

			auto res = get_mysql_output_bind(v, helper.is_null);
			output_parameters.emplace_back(res.first);
			helper.post_process = res.second;
			assert(output_parameters.size() == output_helpers.size());
		}

		template <typename T, typename ... Tail>
		void bind_results(T& v, Tail& ... tail){
			bind_result_element(v);
			bind_results(tail ...);
		}

		void bind_results(){
			bind_result(output_parameters.data());
		}

		int prepare(std::string const q){
			return rusql::mysql::stmt_prepare(statement, q);
		}

		size_t param_count(){
			return rusql::mysql::stmt_param_count(statement);
		}

		my_bool bind_param(MYSQL_BIND* binds){
			return rusql::mysql::stmt_bind_param(statement, binds);
		}

		my_bool bind_result(MYSQL_BIND* binds){
			return rusql::mysql::stmt_bind_result(statement, binds);
		}

		int fetch(){
			int res = rusql::mysql::stmt_fetch(statement);
			if(res != MYSQL_NO_DATA) {
				// post-process the bind results
				for(unsigned i = 0; i < output_parameters.size(); ++i) {
					MYSQL_BIND &bound = output_parameters.at(i);
					auto &helper = output_helpers.at(i);
					helper.post_process(bound);
				}
			}
			return res;
		}

		int execute(){
			return rusql::mysql::stmt_execute(statement);
		}

		unsigned long long insert_id() {
			return rusql::mysql::stmt_insert_id(statement);
		}

		void store_result() {
			rusql::mysql::stmt_store_result(statement);
		}

		/*! You need to call store_result() before this function returns anything other than 0. This
		 * is a MySQL limitation. */
		unsigned long long num_rows() {
			return rusql::mysql::stmt_num_rows(statement);
		}

		my_bool close(){
			auto const result = rusql::mysql::stmt_close(statement);
			statement = nullptr;
			return result;
		}
	};
}}
<|endoftext|>


<commit_before>//===-- SIMachineFunctionInfo.cpp - SI Machine Function Info -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
/// \file
//===----------------------------------------------------------------------===//

#include "SIMachineFunctionInfo.h"
#include "SIInstrInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"

#define MAX_LANES 64

using namespace llvm;

// Pin the vtable to this file.
void SIMachineFunctionInfo::anchor() {}

SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
  : AMDGPUMachineFunction(MF),
    PSInputAddr(0),
    SpillTracker() { }

static unsigned createLaneVGPR(MachineRegisterInfo &MRI, MachineFunction *MF) {
  unsigned VGPR = MRI.createVirtualRegister(&AMDGPU::VReg_32RegClass);

  // We need to add this register as live out for the function, in order to
  // have the live range calculated directly.
  //
  // When register spilling begins, we have already calculated the live
  // live intervals for all the registers.  Since we are spilling SGPRs to
  // VGPRs, we need to update the Lane VGPR's live interval every time we
  // spill or restore a register.
  //
  // Unfortunately, there is no good way to update the live interval as
  // the TargetInstrInfo callbacks for spilling and restoring don't give
  // us access to the live interval information.
  //
  // We are lucky, though, because the InlineSpiller calls
  // LiveRangeEdit::calculateRegClassAndHint() which iterates through
  // all the new register that have been created when restoring a register
  // and calls LiveIntervals::getInterval(), which creates and computes
  // the live interval for the newly created register.  However, once this
  // live intervals is created, it doesn't change and since we usually reuse
  // the Lane VGPR multiple times, this means any uses after the first aren't
  // added to the live interval.
  //
  // To work around this, we add Lane VGPRs to the functions live out list,
  // so that we can guarantee its live range will cover all of its uses.

  for (MachineBasicBlock &MBB : *MF) {
    if (MBB.back().getOpcode() == AMDGPU::S_ENDPGM) {
      MBB.back().addOperand(*MF, MachineOperand::CreateReg(VGPR, false, true));
      return VGPR;
    }
  }
  MF->getFunction()->getContext().emitError(
      "Could not find S_ENGPGM instrtuction.");
  return VGPR;
}

unsigned SIMachineFunctionInfo::RegSpillTracker::reserveLanes(
    MachineRegisterInfo &MRI, MachineFunction *MF, unsigned NumRegs) {
  unsigned StartLane = CurrentLane;
  CurrentLane += NumRegs;
  if (!LaneVGPR) {
    LaneVGPR = createLaneVGPR(MRI, MF);
  } else {
    if (CurrentLane >= MAX_LANES) {
      StartLane = CurrentLane = 0;
      LaneVGPR = createLaneVGPR(MRI, MF);
    }
  }
  return StartLane;
}

void SIMachineFunctionInfo::RegSpillTracker::addSpilledReg(unsigned FrameIndex,
                                                           unsigned Reg,
                                                           int Lane) {
  SpilledRegisters[FrameIndex] = SpilledReg(Reg, Lane);
}

const SIMachineFunctionInfo::SpilledReg&
SIMachineFunctionInfo::RegSpillTracker::getSpilledReg(unsigned FrameIndex) {
  return SpilledRegisters[FrameIndex];
}
<commit_msg>Fix typo, weird indentation<commit_after>//===-- SIMachineFunctionInfo.cpp - SI Machine Function Info -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
/// \file
//===----------------------------------------------------------------------===//

#include "SIMachineFunctionInfo.h"
#include "SIInstrInfo.h"
#include "SIRegisterInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"

#define MAX_LANES 64

using namespace llvm;

// Pin the vtable to this file.
void SIMachineFunctionInfo::anchor() {}

SIMachineFunctionInfo::SIMachineFunctionInfo(const MachineFunction &MF)
  : AMDGPUMachineFunction(MF),
    PSInputAddr(0),
    SpillTracker() { }

static unsigned createLaneVGPR(MachineRegisterInfo &MRI, MachineFunction *MF) {
  unsigned VGPR = MRI.createVirtualRegister(&AMDGPU::VReg_32RegClass);

  // We need to add this register as live out for the function, in order to
  // have the live range calculated directly.
  //
  // When register spilling begins, we have already calculated the live
  // live intervals for all the registers.  Since we are spilling SGPRs to
  // VGPRs, we need to update the Lane VGPR's live interval every time we
  // spill or restore a register.
  //
  // Unfortunately, there is no good way to update the live interval as
  // the TargetInstrInfo callbacks for spilling and restoring don't give
  // us access to the live interval information.
  //
  // We are lucky, though, because the InlineSpiller calls
  // LiveRangeEdit::calculateRegClassAndHint() which iterates through
  // all the new register that have been created when restoring a register
  // and calls LiveIntervals::getInterval(), which creates and computes
  // the live interval for the newly created register.  However, once this
  // live intervals is created, it doesn't change and since we usually reuse
  // the Lane VGPR multiple times, this means any uses after the first aren't
  // added to the live interval.
  //
  // To work around this, we add Lane VGPRs to the functions live out list,
  // so that we can guarantee its live range will cover all of its uses.

  for (MachineBasicBlock &MBB : *MF) {
    if (MBB.back().getOpcode() == AMDGPU::S_ENDPGM) {
      MBB.back().addOperand(*MF, MachineOperand::CreateReg(VGPR, false, true));
      return VGPR;
    }
  }

  LLVMContext &Ctx = MF->getFunction()->getContext();
  Ctx.emitError("Could not find S_ENDPGM instruction.");

  return VGPR;
}

unsigned SIMachineFunctionInfo::RegSpillTracker::reserveLanes(
    MachineRegisterInfo &MRI, MachineFunction *MF, unsigned NumRegs) {
  unsigned StartLane = CurrentLane;
  CurrentLane += NumRegs;
  if (!LaneVGPR) {
    LaneVGPR = createLaneVGPR(MRI, MF);
  } else {
    if (CurrentLane >= MAX_LANES) {
      StartLane = CurrentLane = 0;
      LaneVGPR = createLaneVGPR(MRI, MF);
    }
  }
  return StartLane;
}

void SIMachineFunctionInfo::RegSpillTracker::addSpilledReg(unsigned FrameIndex,
                                                           unsigned Reg,
                                                           int Lane) {
  SpilledRegisters[FrameIndex] = SpilledReg(Reg, Lane);
}

const SIMachineFunctionInfo::SpilledReg&
SIMachineFunctionInfo::RegSpillTracker::getSpilledReg(unsigned FrameIndex) {
  return SpilledRegisters[FrameIndex];
}
<|endoftext|>


<commit_before>//===--- HeaderIncludes.cpp - Insert/Delete #includes --*- C++ -*----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Tooling/Inclusions/HeaderIncludes.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"

namespace clang {
namespace tooling {
namespace {

LangOptions createLangOpts() {
  LangOptions LangOpts;
  LangOpts.CPlusPlus = 1;
  LangOpts.CPlusPlus11 = 1;
  LangOpts.CPlusPlus14 = 1;
  LangOpts.LineComment = 1;
  LangOpts.CXXOperatorNames = 1;
  LangOpts.Bool = 1;
  LangOpts.ObjC1 = 1;
  LangOpts.ObjC2 = 1;
  LangOpts.MicrosoftExt = 1;    // To get kw___try, kw___finally.
  LangOpts.DeclSpecKeyword = 1; // To get __declspec.
  LangOpts.WChar = 1;           // To get wchar_t
  return LangOpts;
}

// Returns the offset after skipping a sequence of tokens, matched by \p
// GetOffsetAfterSequence, from the start of the code.
// \p GetOffsetAfterSequence should be a function that matches a sequence of
// tokens and returns an offset after the sequence.
unsigned getOffsetAfterTokenSequence(
    StringRef FileName, StringRef Code, const IncludeStyle &Style,
    llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
        GetOffsetAfterSequence) {
  SourceManagerForFile VirtualSM(FileName, Code);
  SourceManager &SM = VirtualSM.get();
  Lexer Lex(SM.getMainFileID(), SM.getBuffer(SM.getMainFileID()), SM,
            createLangOpts());
  Token Tok;
  // Get the first token.
  Lex.LexFromRawLexer(Tok);
  return GetOffsetAfterSequence(SM, Lex, Tok);
}

// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
// \p Tok will be the token after this directive; otherwise, it can be any token
// after the given \p Tok (including \p Tok).
bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
  bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
                 Tok.is(tok::raw_identifier) &&
                 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
                 Tok.is(tok::raw_identifier);
  if (Matched)
    Lex.LexFromRawLexer(Tok);
  return Matched;
}

void skipComments(Lexer &Lex, Token &Tok) {
  while (Tok.is(tok::comment))
    if (Lex.LexFromRawLexer(Tok))
      return;
}

// Returns the offset after header guard directives and any comments
// before/after header guards. If no header guard presents in the code, this
// will returns the offset after skipping all comments from the start of the
// code.
unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
                                               StringRef Code,
                                               const IncludeStyle &Style) {
  return getOffsetAfterTokenSequence(
      FileName, Code, Style,
      [](const SourceManager &SM, Lexer &Lex, Token Tok) {
        skipComments(Lex, Tok);
        unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
        if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
          skipComments(Lex, Tok);
          if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
            return SM.getFileOffset(Tok.getLocation());
        }
        return InitialOffset;
      });
}

// Check if a sequence of tokens is like
//    "#include ("header.h" | <header.h>)".
// If it is, \p Tok will be the token after this directive; otherwise, it can be
// any token after the given \p Tok (including \p Tok).
bool checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
  auto Matched = [&]() {
    Lex.LexFromRawLexer(Tok);
    return true;
  };
  if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
      Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
    if (Lex.LexFromRawLexer(Tok))
      return false;
    if (Tok.is(tok::string_literal))
      return Matched();
    if (Tok.is(tok::less)) {
      while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
      }
      if (Tok.is(tok::greater))
        return Matched();
    }
  }
  return false;
}

// Returns the offset of the last #include directive after which a new
// #include can be inserted. This ignores #include's after the #include block(s)
// in the beginning of a file to avoid inserting headers into code sections
// where new #include's should not be added by default.
// These code sections include:
//      - raw string literals (containing #include).
//      - #if blocks.
//      - Special #include's among declarations (e.g. functions).
//
// If no #include after which a new #include can be inserted, this returns the
// offset after skipping all comments from the start of the code.
// Inserting after an #include is not allowed if it comes after code that is not
// #include (e.g. pre-processing directive that is not #include, declarations).
unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
                                     const IncludeStyle &Style) {
  return getOffsetAfterTokenSequence(
      FileName, Code, Style,
      [](const SourceManager &SM, Lexer &Lex, Token Tok) {
        skipComments(Lex, Tok);
        unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
        while (checkAndConsumeInclusiveDirective(Lex, Tok))
          MaxOffset = SM.getFileOffset(Tok.getLocation());
        return MaxOffset;
      });
}

inline StringRef trimInclude(StringRef IncludeName) {
  return IncludeName.trim("\"<>");
}

const char IncludeRegexPattern[] =
    R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";

} // anonymous namespace

IncludeCategoryManager::IncludeCategoryManager(const IncludeStyle &Style,
                                               StringRef FileName)
    : Style(Style), FileName(FileName) {
  FileStem = llvm::sys::path::stem(FileName);
  for (const auto &Category : Style.IncludeCategories)
    CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
  IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
               FileName.endswith(".cpp") || FileName.endswith(".c++") ||
               FileName.endswith(".cxx") || FileName.endswith(".m") ||
               FileName.endswith(".mm");
}

int IncludeCategoryManager::getIncludePriority(StringRef IncludeName,
                                               bool CheckMainHeader) const {
  int Ret = INT_MAX;
  for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
    if (CategoryRegexs[i].match(IncludeName)) {
      Ret = Style.IncludeCategories[i].Priority;
      break;
    }
  if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
    Ret = 0;
  return Ret;
}

bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const {
  if (!IncludeName.startswith("\""))
    return false;
  StringRef HeaderStem =
      llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
  if (FileStem.startswith(HeaderStem) ||
      FileStem.startswith_lower(HeaderStem)) {
    llvm::Regex MainIncludeRegex((HeaderStem + Style.IncludeIsMainRegex).str(),
                                 llvm::Regex::IgnoreCase);
    if (MainIncludeRegex.match(FileStem))
      return true;
  }
  return false;
}

HeaderIncludes::HeaderIncludes(StringRef FileName, StringRef Code,
                               const IncludeStyle &Style)
    : FileName(FileName), Code(Code), FirstIncludeOffset(-1),
      MinInsertOffset(
          getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style)),
      MaxInsertOffset(MinInsertOffset +
                      getMaxHeaderInsertionOffset(
                          FileName, Code.drop_front(MinInsertOffset), Style)),
      Categories(Style, FileName),
      IncludeRegex(llvm::Regex(IncludeRegexPattern)) {
  // Add 0 for main header and INT_MAX for headers that are not in any
  // category.
  Priorities = {0, INT_MAX};
  for (const auto &Category : Style.IncludeCategories)
    Priorities.insert(Category.Priority);
  SmallVector<StringRef, 32> Lines;
  Code.drop_front(MinInsertOffset).split(Lines, "\n");

  unsigned Offset = MinInsertOffset;
  unsigned NextLineOffset;
  SmallVector<StringRef, 4> Matches;
  for (auto Line : Lines) {
    NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
    if (IncludeRegex.match(Line, &Matches)) {
      // If this is the last line without trailing newline, we need to make
      // sure we don't delete across the file boundary.
      addExistingInclude(
          Include(Matches[2],
                  tooling::Range(
                      Offset, std::min(Line.size() + 1, Code.size() - Offset))),
          NextLineOffset);
    }
    Offset = NextLineOffset;
  }

  // Populate CategoryEndOfssets:
  // - Ensure that CategoryEndOffset[Highest] is always populated.
  // - If CategoryEndOffset[Priority] isn't set, use the next higher value
  // that is set, up to CategoryEndOffset[Highest].
  auto Highest = Priorities.begin();
  if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
    if (FirstIncludeOffset >= 0)
      CategoryEndOffsets[*Highest] = FirstIncludeOffset;
    else
      CategoryEndOffsets[*Highest] = MinInsertOffset;
  }
  // By this point, CategoryEndOffset[Highest] is always set appropriately:
  //  - to an appropriate location before/after existing #includes, or
  //  - to right after the header guard, or
  //  - to the beginning of the file.
  for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
    if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
      CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
}

// \p Offset: the start of the line following this include directive.
void HeaderIncludes::addExistingInclude(Include IncludeToAdd,
                                        unsigned NextLineOffset) {
  auto Iter =
      ExistingIncludes.try_emplace(trimInclude(IncludeToAdd.Name)).first;
  Iter->second.push_back(std::move(IncludeToAdd));
  auto &CurInclude = Iter->second.back();
  // The header name with quotes or angle brackets.
  // Only record the offset of current #include if we can insert after it.
  if (CurInclude.R.getOffset() <= MaxInsertOffset) {
    int Priority = Categories.getIncludePriority(
        CurInclude.Name, /*CheckMainHeader=*/FirstIncludeOffset < 0);
    CategoryEndOffsets[Priority] = NextLineOffset;
    IncludesByPriority[Priority].push_back(&CurInclude);
    if (FirstIncludeOffset < 0)
      FirstIncludeOffset = CurInclude.R.getOffset();
  }
}

llvm::Optional<tooling::Replacement>
HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled) const {
  assert(IncludeName == trimInclude(IncludeName));
  // If a <header> ("header") already exists in code, "header" (<header>) with
  // different quotation will still be inserted.
  // FIXME: figure out if this is the best behavior.
  auto It = ExistingIncludes.find(IncludeName);
  if (It != ExistingIncludes.end())
    for (const auto &Inc : It->second)
      if ((IsAngled && StringRef(Inc.Name).startswith("<")) ||
          (!IsAngled && StringRef(Inc.Name).startswith("\"")))
        return llvm::None;
  std::string Quoted = IsAngled ? ("<" + IncludeName + ">").str()
                                : ("\"" + IncludeName + "\"").str();
  StringRef QuotedName = Quoted;
  int Priority = Categories.getIncludePriority(
      QuotedName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
  auto CatOffset = CategoryEndOffsets.find(Priority);
  assert(CatOffset != CategoryEndOffsets.end());
  unsigned InsertOffset = CatOffset->second; // Fall back offset
  auto Iter = IncludesByPriority.find(Priority);
  if (Iter != IncludesByPriority.end()) {
    for (const auto *Inc : Iter->second) {
      if (QuotedName < Inc->Name) {
        InsertOffset = Inc->R.getOffset();
        break;
      }
    }
  }
  assert(InsertOffset <= Code.size());
  std::string NewInclude = ("#include " + QuotedName + "\n").str();
  // When inserting headers at end of the code, also append '\n' to the code
  // if it does not end with '\n'.
  // FIXME: when inserting multiple #includes at the end of code, only one
  // newline should be added.
  if (InsertOffset == Code.size() && (!Code.empty() && Code.back() != '\n'))
    NewInclude = "\n" + NewInclude;
  return tooling::Replacement(FileName, InsertOffset, 0, NewInclude);
}

tooling::Replacements HeaderIncludes::remove(llvm::StringRef IncludeName,
                                             bool IsAngled) const {
  assert(IncludeName == trimInclude(IncludeName));
  tooling::Replacements Result;
  auto Iter = ExistingIncludes.find(IncludeName);
  if (Iter == ExistingIncludes.end())
    return Result;
  for (const auto &Inc : Iter->second) {
    if ((IsAngled && StringRef(Inc.Name).startswith("\"")) ||
        (!IsAngled && StringRef(Inc.Name).startswith("<")))
      continue;
    llvm::Error Err = Result.add(tooling::Replacement(
        FileName, Inc.R.getOffset(), Inc.R.getLength(), ""));
    if (Err) {
      auto ErrMsg = "Unexpected conflicts in #include deletions: " +
                    llvm::toString(std::move(Err));
      llvm_unreachable(ErrMsg.c_str());
    }
  }
  return Result;
}

} // namespace tooling
} // namespace clang
<commit_msg>[Tooling] Get rid of uses of llvm::Twine::str which is slow. NFC<commit_after>//===--- HeaderIncludes.cpp - Insert/Delete #includes --*- C++ -*----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Tooling/Inclusions/HeaderIncludes.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Lex/Lexer.h"
#include "llvm/Support/FormatVariadic.h"

namespace clang {
namespace tooling {
namespace {

LangOptions createLangOpts() {
  LangOptions LangOpts;
  LangOpts.CPlusPlus = 1;
  LangOpts.CPlusPlus11 = 1;
  LangOpts.CPlusPlus14 = 1;
  LangOpts.LineComment = 1;
  LangOpts.CXXOperatorNames = 1;
  LangOpts.Bool = 1;
  LangOpts.ObjC1 = 1;
  LangOpts.ObjC2 = 1;
  LangOpts.MicrosoftExt = 1;    // To get kw___try, kw___finally.
  LangOpts.DeclSpecKeyword = 1; // To get __declspec.
  LangOpts.WChar = 1;           // To get wchar_t
  return LangOpts;
}

// Returns the offset after skipping a sequence of tokens, matched by \p
// GetOffsetAfterSequence, from the start of the code.
// \p GetOffsetAfterSequence should be a function that matches a sequence of
// tokens and returns an offset after the sequence.
unsigned getOffsetAfterTokenSequence(
    StringRef FileName, StringRef Code, const IncludeStyle &Style,
    llvm::function_ref<unsigned(const SourceManager &, Lexer &, Token &)>
        GetOffsetAfterSequence) {
  SourceManagerForFile VirtualSM(FileName, Code);
  SourceManager &SM = VirtualSM.get();
  Lexer Lex(SM.getMainFileID(), SM.getBuffer(SM.getMainFileID()), SM,
            createLangOpts());
  Token Tok;
  // Get the first token.
  Lex.LexFromRawLexer(Tok);
  return GetOffsetAfterSequence(SM, Lex, Tok);
}

// Check if a sequence of tokens is like "#<Name> <raw_identifier>". If it is,
// \p Tok will be the token after this directive; otherwise, it can be any token
// after the given \p Tok (including \p Tok).
bool checkAndConsumeDirectiveWithName(Lexer &Lex, StringRef Name, Token &Tok) {
  bool Matched = Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
                 Tok.is(tok::raw_identifier) &&
                 Tok.getRawIdentifier() == Name && !Lex.LexFromRawLexer(Tok) &&
                 Tok.is(tok::raw_identifier);
  if (Matched)
    Lex.LexFromRawLexer(Tok);
  return Matched;
}

void skipComments(Lexer &Lex, Token &Tok) {
  while (Tok.is(tok::comment))
    if (Lex.LexFromRawLexer(Tok))
      return;
}

// Returns the offset after header guard directives and any comments
// before/after header guards. If no header guard presents in the code, this
// will returns the offset after skipping all comments from the start of the
// code.
unsigned getOffsetAfterHeaderGuardsAndComments(StringRef FileName,
                                               StringRef Code,
                                               const IncludeStyle &Style) {
  return getOffsetAfterTokenSequence(
      FileName, Code, Style,
      [](const SourceManager &SM, Lexer &Lex, Token Tok) {
        skipComments(Lex, Tok);
        unsigned InitialOffset = SM.getFileOffset(Tok.getLocation());
        if (checkAndConsumeDirectiveWithName(Lex, "ifndef", Tok)) {
          skipComments(Lex, Tok);
          if (checkAndConsumeDirectiveWithName(Lex, "define", Tok))
            return SM.getFileOffset(Tok.getLocation());
        }
        return InitialOffset;
      });
}

// Check if a sequence of tokens is like
//    "#include ("header.h" | <header.h>)".
// If it is, \p Tok will be the token after this directive; otherwise, it can be
// any token after the given \p Tok (including \p Tok).
bool checkAndConsumeInclusiveDirective(Lexer &Lex, Token &Tok) {
  auto Matched = [&]() {
    Lex.LexFromRawLexer(Tok);
    return true;
  };
  if (Tok.is(tok::hash) && !Lex.LexFromRawLexer(Tok) &&
      Tok.is(tok::raw_identifier) && Tok.getRawIdentifier() == "include") {
    if (Lex.LexFromRawLexer(Tok))
      return false;
    if (Tok.is(tok::string_literal))
      return Matched();
    if (Tok.is(tok::less)) {
      while (!Lex.LexFromRawLexer(Tok) && Tok.isNot(tok::greater)) {
      }
      if (Tok.is(tok::greater))
        return Matched();
    }
  }
  return false;
}

// Returns the offset of the last #include directive after which a new
// #include can be inserted. This ignores #include's after the #include block(s)
// in the beginning of a file to avoid inserting headers into code sections
// where new #include's should not be added by default.
// These code sections include:
//      - raw string literals (containing #include).
//      - #if blocks.
//      - Special #include's among declarations (e.g. functions).
//
// If no #include after which a new #include can be inserted, this returns the
// offset after skipping all comments from the start of the code.
// Inserting after an #include is not allowed if it comes after code that is not
// #include (e.g. pre-processing directive that is not #include, declarations).
unsigned getMaxHeaderInsertionOffset(StringRef FileName, StringRef Code,
                                     const IncludeStyle &Style) {
  return getOffsetAfterTokenSequence(
      FileName, Code, Style,
      [](const SourceManager &SM, Lexer &Lex, Token Tok) {
        skipComments(Lex, Tok);
        unsigned MaxOffset = SM.getFileOffset(Tok.getLocation());
        while (checkAndConsumeInclusiveDirective(Lex, Tok))
          MaxOffset = SM.getFileOffset(Tok.getLocation());
        return MaxOffset;
      });
}

inline StringRef trimInclude(StringRef IncludeName) {
  return IncludeName.trim("\"<>");
}

const char IncludeRegexPattern[] =
    R"(^[\t\ ]*#[\t\ ]*(import|include)[^"<]*(["<][^">]*[">]))";

} // anonymous namespace

IncludeCategoryManager::IncludeCategoryManager(const IncludeStyle &Style,
                                               StringRef FileName)
    : Style(Style), FileName(FileName) {
  FileStem = llvm::sys::path::stem(FileName);
  for (const auto &Category : Style.IncludeCategories)
    CategoryRegexs.emplace_back(Category.Regex, llvm::Regex::IgnoreCase);
  IsMainFile = FileName.endswith(".c") || FileName.endswith(".cc") ||
               FileName.endswith(".cpp") || FileName.endswith(".c++") ||
               FileName.endswith(".cxx") || FileName.endswith(".m") ||
               FileName.endswith(".mm");
}

int IncludeCategoryManager::getIncludePriority(StringRef IncludeName,
                                               bool CheckMainHeader) const {
  int Ret = INT_MAX;
  for (unsigned i = 0, e = CategoryRegexs.size(); i != e; ++i)
    if (CategoryRegexs[i].match(IncludeName)) {
      Ret = Style.IncludeCategories[i].Priority;
      break;
    }
  if (CheckMainHeader && IsMainFile && Ret > 0 && isMainHeader(IncludeName))
    Ret = 0;
  return Ret;
}

bool IncludeCategoryManager::isMainHeader(StringRef IncludeName) const {
  if (!IncludeName.startswith("\""))
    return false;
  StringRef HeaderStem =
      llvm::sys::path::stem(IncludeName.drop_front(1).drop_back(1));
  if (FileStem.startswith(HeaderStem) ||
      FileStem.startswith_lower(HeaderStem)) {
    llvm::Regex MainIncludeRegex(HeaderStem.str() + Style.IncludeIsMainRegex,
                                 llvm::Regex::IgnoreCase);
    if (MainIncludeRegex.match(FileStem))
      return true;
  }
  return false;
}

HeaderIncludes::HeaderIncludes(StringRef FileName, StringRef Code,
                               const IncludeStyle &Style)
    : FileName(FileName), Code(Code), FirstIncludeOffset(-1),
      MinInsertOffset(
          getOffsetAfterHeaderGuardsAndComments(FileName, Code, Style)),
      MaxInsertOffset(MinInsertOffset +
                      getMaxHeaderInsertionOffset(
                          FileName, Code.drop_front(MinInsertOffset), Style)),
      Categories(Style, FileName),
      IncludeRegex(llvm::Regex(IncludeRegexPattern)) {
  // Add 0 for main header and INT_MAX for headers that are not in any
  // category.
  Priorities = {0, INT_MAX};
  for (const auto &Category : Style.IncludeCategories)
    Priorities.insert(Category.Priority);
  SmallVector<StringRef, 32> Lines;
  Code.drop_front(MinInsertOffset).split(Lines, "\n");

  unsigned Offset = MinInsertOffset;
  unsigned NextLineOffset;
  SmallVector<StringRef, 4> Matches;
  for (auto Line : Lines) {
    NextLineOffset = std::min(Code.size(), Offset + Line.size() + 1);
    if (IncludeRegex.match(Line, &Matches)) {
      // If this is the last line without trailing newline, we need to make
      // sure we don't delete across the file boundary.
      addExistingInclude(
          Include(Matches[2],
                  tooling::Range(
                      Offset, std::min(Line.size() + 1, Code.size() - Offset))),
          NextLineOffset);
    }
    Offset = NextLineOffset;
  }

  // Populate CategoryEndOfssets:
  // - Ensure that CategoryEndOffset[Highest] is always populated.
  // - If CategoryEndOffset[Priority] isn't set, use the next higher value
  // that is set, up to CategoryEndOffset[Highest].
  auto Highest = Priorities.begin();
  if (CategoryEndOffsets.find(*Highest) == CategoryEndOffsets.end()) {
    if (FirstIncludeOffset >= 0)
      CategoryEndOffsets[*Highest] = FirstIncludeOffset;
    else
      CategoryEndOffsets[*Highest] = MinInsertOffset;
  }
  // By this point, CategoryEndOffset[Highest] is always set appropriately:
  //  - to an appropriate location before/after existing #includes, or
  //  - to right after the header guard, or
  //  - to the beginning of the file.
  for (auto I = ++Priorities.begin(), E = Priorities.end(); I != E; ++I)
    if (CategoryEndOffsets.find(*I) == CategoryEndOffsets.end())
      CategoryEndOffsets[*I] = CategoryEndOffsets[*std::prev(I)];
}

// \p Offset: the start of the line following this include directive.
void HeaderIncludes::addExistingInclude(Include IncludeToAdd,
                                        unsigned NextLineOffset) {
  auto Iter =
      ExistingIncludes.try_emplace(trimInclude(IncludeToAdd.Name)).first;
  Iter->second.push_back(std::move(IncludeToAdd));
  auto &CurInclude = Iter->second.back();
  // The header name with quotes or angle brackets.
  // Only record the offset of current #include if we can insert after it.
  if (CurInclude.R.getOffset() <= MaxInsertOffset) {
    int Priority = Categories.getIncludePriority(
        CurInclude.Name, /*CheckMainHeader=*/FirstIncludeOffset < 0);
    CategoryEndOffsets[Priority] = NextLineOffset;
    IncludesByPriority[Priority].push_back(&CurInclude);
    if (FirstIncludeOffset < 0)
      FirstIncludeOffset = CurInclude.R.getOffset();
  }
}

llvm::Optional<tooling::Replacement>
HeaderIncludes::insert(llvm::StringRef IncludeName, bool IsAngled) const {
  assert(IncludeName == trimInclude(IncludeName));
  // If a <header> ("header") already exists in code, "header" (<header>) with
  // different quotation will still be inserted.
  // FIXME: figure out if this is the best behavior.
  auto It = ExistingIncludes.find(IncludeName);
  if (It != ExistingIncludes.end())
    for (const auto &Inc : It->second)
      if ((IsAngled && StringRef(Inc.Name).startswith("<")) ||
          (!IsAngled && StringRef(Inc.Name).startswith("\"")))
        return llvm::None;
  std::string Quoted =
      llvm::formatv(IsAngled ? "<{0}>" : "\"{0}\"", IncludeName);
  StringRef QuotedName = Quoted;
  int Priority = Categories.getIncludePriority(
      QuotedName, /*CheckMainHeader=*/FirstIncludeOffset < 0);
  auto CatOffset = CategoryEndOffsets.find(Priority);
  assert(CatOffset != CategoryEndOffsets.end());
  unsigned InsertOffset = CatOffset->second; // Fall back offset
  auto Iter = IncludesByPriority.find(Priority);
  if (Iter != IncludesByPriority.end()) {
    for (const auto *Inc : Iter->second) {
      if (QuotedName < Inc->Name) {
        InsertOffset = Inc->R.getOffset();
        break;
      }
    }
  }
  assert(InsertOffset <= Code.size());
  std::string NewInclude = llvm::formatv("#include {0}\n", QuotedName);
  // When inserting headers at end of the code, also append '\n' to the code
  // if it does not end with '\n'.
  // FIXME: when inserting multiple #includes at the end of code, only one
  // newline should be added.
  if (InsertOffset == Code.size() && (!Code.empty() && Code.back() != '\n'))
    NewInclude = "\n" + NewInclude;
  return tooling::Replacement(FileName, InsertOffset, 0, NewInclude);
}

tooling::Replacements HeaderIncludes::remove(llvm::StringRef IncludeName,
                                             bool IsAngled) const {
  assert(IncludeName == trimInclude(IncludeName));
  tooling::Replacements Result;
  auto Iter = ExistingIncludes.find(IncludeName);
  if (Iter == ExistingIncludes.end())
    return Result;
  for (const auto &Inc : Iter->second) {
    if ((IsAngled && StringRef(Inc.Name).startswith("\"")) ||
        (!IsAngled && StringRef(Inc.Name).startswith("<")))
      continue;
    llvm::Error Err = Result.add(tooling::Replacement(
        FileName, Inc.R.getOffset(), Inc.R.getLength(), ""));
    if (Err) {
      auto ErrMsg = "Unexpected conflicts in #include deletions: " +
                    llvm::toString(std::move(Err));
      llvm_unreachable(ErrMsg.c_str());
    }
  }
  return Result;
}

} // namespace tooling
} // namespace clang
<|endoftext|>


<commit_before>//===-- StructRetPromotion.cpp - Promote sret arguments ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass finds functions that return a struct (using a pointer to the struct
// as the first argument of the function, marked with the 'sret' attribute) and
// replaces them with a new function that simply returns each of the elements of
// that struct (using multiple return values).
//
// This pass works under a number of conditions:
//  1. The returned struct must not contain other structs
//  2. The returned struct must only be used to load values from
//  3. The placeholder struct passed in is the result of an alloca
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sretpromotion"
#include "llvm/Transforms/IPO.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

STATISTIC(NumRejectedSRETUses , "Number of sret rejected due to unexpected uses");
STATISTIC(NumSRET , "Number of sret promoted");
namespace {
  /// SRETPromotion - This pass removes sret parameter and updates
  /// function to use multiple return value.
  ///
  struct SRETPromotion : public CallGraphSCCPass {
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      CallGraphSCCPass::getAnalysisUsage(AU);
    }

    virtual bool runOnSCC(std::vector<CallGraphNode *> &SCC);
    static char ID; // Pass identification, replacement for typeid
    SRETPromotion() : CallGraphSCCPass(&ID) {}

  private:
    CallGraphNode *PromoteReturn(CallGraphNode *CGN);
    bool isSafeToUpdateAllCallers(Function *F);
    Function *cloneFunctionBody(Function *F, const StructType *STy);
    CallGraphNode *updateCallSites(Function *F, Function *NF);
    bool nestedStructType(const StructType *STy);
  };
}

char SRETPromotion::ID = 0;
static RegisterPass<SRETPromotion>
X("sretpromotion", "Promote sret arguments to multiple ret values");

Pass *llvm::createStructRetPromotionPass() {
  return new SRETPromotion();
}

bool SRETPromotion::runOnSCC(std::vector<CallGraphNode *> &SCC) {
  bool Changed = false;

  for (unsigned i = 0, e = SCC.size(); i != e; ++i)
    if (CallGraphNode *NewNode = PromoteReturn(SCC[i])) {
      SCC[i] = NewNode;
      Changed = true;
    }

  return Changed;
}

/// PromoteReturn - This method promotes function that uses StructRet paramater
/// into a function that uses multiple return values.
CallGraphNode *SRETPromotion::PromoteReturn(CallGraphNode *CGN) {
  Function *F = CGN->getFunction();

  if (!F || F->isDeclaration() || !F->hasLocalLinkage())
    return 0;

  // Make sure that function returns struct.
  if (F->arg_size() == 0 || !F->hasStructRetAttr() || F->doesNotReturn())
    return 0;

  DEBUG(errs() << "SretPromotion: Looking at sret function "
        << F->getName() << "\n");

  assert(F->getReturnType() == Type::getVoidTy(F->getContext()) &&
         "Invalid function return type");
  Function::arg_iterator AI = F->arg_begin();
  const llvm::PointerType *FArgType = dyn_cast<PointerType>(AI->getType());
  assert(FArgType && "Invalid sret parameter type");
  const llvm::StructType *STy =
    dyn_cast<StructType>(FArgType->getElementType());
  assert(STy && "Invalid sret parameter element type");

  // Check if it is ok to perform this promotion.
  if (isSafeToUpdateAllCallers(F) == false) {
    DEBUG(errs() << "SretPromotion: Not all callers can be updated\n");
    NumRejectedSRETUses++;
    return 0;
  }

  DEBUG(errs() << "SretPromotion: sret argument will be promoted\n");
  NumSRET++;
  // [1] Replace use of sret parameter
  AllocaInst *TheAlloca = new AllocaInst(STy, NULL, "mrv",
                                         F->getEntryBlock().begin());
  Value *NFirstArg = F->arg_begin();
  NFirstArg->replaceAllUsesWith(TheAlloca);

  // [2] Find and replace ret instructions
  for (Function::iterator FI = F->begin(), FE = F->end();  FI != FE; ++FI)
    for(BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
      Instruction *I = BI;
      ++BI;
      if (isa<ReturnInst>(I)) {
        Value *NV = new LoadInst(TheAlloca, "mrv.ld", I);
        ReturnInst *NR = ReturnInst::Create(F->getContext(), NV, I);
        I->replaceAllUsesWith(NR);
        I->eraseFromParent();
      }
    }

  // [3] Create the new function body and insert it into the module.
  Function *NF = cloneFunctionBody(F, STy);

  // [4] Update all call sites to use new function
  CallGraphNode *NF_CFN = updateCallSites(F, NF);

  CallGraph &CG = getAnalysis<CallGraph>();
  NF_CFN->stealCalledFunctionsFrom(CG[F]);

  delete CG.removeFunctionFromModule(F);
  return NF_CFN;
}

// Check if it is ok to perform this promotion.
bool SRETPromotion::isSafeToUpdateAllCallers(Function *F) {

  if (F->use_empty())
    // No users. OK to modify signature.
    return true;

  for (Value::use_iterator FnUseI = F->use_begin(), FnUseE = F->use_end();
       FnUseI != FnUseE; ++FnUseI) {
    // The function is passed in as an argument to (possibly) another function,
    // we can't change it!
    CallSite CS = CallSite::get(*FnUseI);
    Instruction *Call = CS.getInstruction();
    // The function is used by something else than a call or invoke instruction,
    // we can't change it!
    if (!Call || !CS.isCallee(FnUseI))
      return false;
    CallSite::arg_iterator AI = CS.arg_begin();
    Value *FirstArg = *AI;

    if (!isa<AllocaInst>(FirstArg))
      return false;

    // Check FirstArg's users.
    for (Value::use_iterator ArgI = FirstArg->use_begin(),
           ArgE = FirstArg->use_end(); ArgI != ArgE; ++ArgI) {

      // If FirstArg user is a CallInst that does not correspond to current
      // call site then this function F is not suitable for sret promotion.
      if (CallInst *CI = dyn_cast<CallInst>(ArgI)) {
        if (CI != Call)
          return false;
      }
      // If FirstArg user is a GEP whose all users are not LoadInst then
      // this function F is not suitable for sret promotion.
      else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(ArgI)) {
        // TODO : Use dom info and insert PHINodes to collect get results
        // from multiple call sites for this GEP.
        if (GEP->getParent() != Call->getParent())
          return false;
        for (Value::use_iterator GEPI = GEP->use_begin(), GEPE = GEP->use_end();
             GEPI != GEPE; ++GEPI)
          if (!isa<LoadInst>(GEPI))
            return false;
      }
      // Any other FirstArg users make this function unsuitable for sret
      // promotion.
      else
        return false;
    }
  }

  return true;
}

/// cloneFunctionBody - Create a new function based on F and
/// insert it into module. Remove first argument. Use STy as
/// the return type for new function.
Function *SRETPromotion::cloneFunctionBody(Function *F,
                                           const StructType *STy) {

  const FunctionType *FTy = F->getFunctionType();
  std::vector<const Type*> Params;

  // Attributes - Keep track of the parameter attributes for the arguments.
  SmallVector<AttributeWithIndex, 8> AttributesVec;
  const AttrListPtr &PAL = F->getAttributes();

  // Add any return attributes.
  if (Attributes attrs = PAL.getRetAttributes())
    AttributesVec.push_back(AttributeWithIndex::get(0, attrs));

  // Skip first argument.
  Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
  ++I;
  // 0th parameter attribute is reserved for return type.
  // 1th parameter attribute is for first 1st sret argument.
  unsigned ParamIndex = 2;
  while (I != E) {
    Params.push_back(I->getType());
    if (Attributes Attrs = PAL.getParamAttributes(ParamIndex))
      AttributesVec.push_back(AttributeWithIndex::get(ParamIndex - 1, Attrs));
    ++I;
    ++ParamIndex;
  }

  // Add any fn attributes.
  if (Attributes attrs = PAL.getFnAttributes())
    AttributesVec.push_back(AttributeWithIndex::get(~0, attrs));

  FunctionType *NFTy = FunctionType::get(STy, Params, FTy->isVarArg());
  Function *NF = Function::Create(NFTy, F->getLinkage());
  NF->takeName(F);
  NF->copyAttributesFrom(F);
  NF->setAttributes(AttrListPtr::get(AttributesVec.begin(), AttributesVec.end()));
  F->getParent()->getFunctionList().insert(F, NF);
  NF->getBasicBlockList().splice(NF->begin(), F->getBasicBlockList());

  // Replace arguments
  I = F->arg_begin();
  E = F->arg_end();
  Function::arg_iterator NI = NF->arg_begin();
  ++I;
  while (I != E) {
    I->replaceAllUsesWith(NI);
    NI->takeName(I);
    ++I;
    ++NI;
  }

  return NF;
}

/// updateCallSites - Update all sites that call F to use NF.
CallGraphNode *SRETPromotion::updateCallSites(Function *F, Function *NF) {
  CallGraph &CG = getAnalysis<CallGraph>();
  SmallVector<Value*, 16> Args;

  // Attributes - Keep track of the parameter attributes for the arguments.
  SmallVector<AttributeWithIndex, 8> ArgAttrsVec;

  // Get a new callgraph node for NF.
  CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF);

  while (!F->use_empty()) {
    CallSite CS = CallSite::get(*F->use_begin());
    Instruction *Call = CS.getInstruction();

    const AttrListPtr &PAL = F->getAttributes();
    // Add any return attributes.
    if (Attributes attrs = PAL.getRetAttributes())
      ArgAttrsVec.push_back(AttributeWithIndex::get(0, attrs));

    // Copy arguments, however skip first one.
    CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
    Value *FirstCArg = *AI;
    ++AI;
    // 0th parameter attribute is reserved for return type.
    // 1th parameter attribute is for first 1st sret argument.
    unsigned ParamIndex = 2;
    while (AI != AE) {
      Args.push_back(*AI);
      if (Attributes Attrs = PAL.getParamAttributes(ParamIndex))
        ArgAttrsVec.push_back(AttributeWithIndex::get(ParamIndex - 1, Attrs));
      ++ParamIndex;
      ++AI;
    }

    // Add any function attributes.
    if (Attributes attrs = PAL.getFnAttributes())
      ArgAttrsVec.push_back(AttributeWithIndex::get(~0, attrs));

    AttrListPtr NewPAL = AttrListPtr::get(ArgAttrsVec.begin(), ArgAttrsVec.end());

    // Build new call instruction.
    Instruction *New;
    if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
      New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(),
                               Args.begin(), Args.end(), "", Call);
      cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv());
      cast<InvokeInst>(New)->setAttributes(NewPAL);
    } else {
      New = CallInst::Create(NF, Args.begin(), Args.end(), "", Call);
      cast<CallInst>(New)->setCallingConv(CS.getCallingConv());
      cast<CallInst>(New)->setAttributes(NewPAL);
      if (cast<CallInst>(Call)->isTailCall())
        cast<CallInst>(New)->setTailCall();
    }
    Args.clear();
    ArgAttrsVec.clear();
    New->takeName(Call);

    // Update the callgraph to know that the callsite has been transformed.
    CallGraphNode *CalleeNode = CG[Call->getParent()->getParent()];
    CalleeNode->removeCallEdgeFor(Call);
    CalleeNode->addCalledFunction(New, NF_CGN);

    // Update all users of sret parameter to extract value using extractvalue.
    for (Value::use_iterator UI = FirstCArg->use_begin(),
           UE = FirstCArg->use_end(); UI != UE; ) {
      User *U2 = *UI++;
      CallInst *C2 = dyn_cast<CallInst>(U2);
      if (C2 && (C2 == Call))
        continue;

      GetElementPtrInst *UGEP = cast<GetElementPtrInst>(U2);
      ConstantInt *Idx = cast<ConstantInt>(UGEP->getOperand(2));
      Value *GR = ExtractValueInst::Create(New, Idx->getZExtValue(),
                                           "evi", UGEP);
      while(!UGEP->use_empty()) {
        // isSafeToUpdateAllCallers has checked that all GEP uses are
        // LoadInsts
        LoadInst *L = cast<LoadInst>(*UGEP->use_begin());
        L->replaceAllUsesWith(GR);
        L->eraseFromParent();
      }
      UGEP->eraseFromParent();
      continue;
    }
    Call->eraseFromParent();
  }

  return NF_CGN;
}

/// nestedStructType - Return true if STy includes any
/// other aggregate types
bool SRETPromotion::nestedStructType(const StructType *STy) {
  unsigned Num = STy->getNumElements();
  for (unsigned i = 0; i < Num; i++) {
    const Type *Ty = STy->getElementType(i);
    if (!Ty->isSingleValueType() && Ty != Type::getVoidTy(STy->getContext()))
      return true;
  }
  return false;
}
<commit_msg>Change errs() to dbgs().<commit_after>//===-- StructRetPromotion.cpp - Promote sret arguments ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass finds functions that return a struct (using a pointer to the struct
// as the first argument of the function, marked with the 'sret' attribute) and
// replaces them with a new function that simply returns each of the elements of
// that struct (using multiple return values).
//
// This pass works under a number of conditions:
//  1. The returned struct must not contain other structs
//  2. The returned struct must only be used to load values from
//  3. The placeholder struct passed in is the result of an alloca
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sretpromotion"
#include "llvm/Transforms/IPO.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/LLVMContext.h"
#include "llvm/Module.h"
#include "llvm/CallGraphSCCPass.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/CallGraph.h"
#include "llvm/Support/CallSite.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

STATISTIC(NumRejectedSRETUses , "Number of sret rejected due to unexpected uses");
STATISTIC(NumSRET , "Number of sret promoted");
namespace {
  /// SRETPromotion - This pass removes sret parameter and updates
  /// function to use multiple return value.
  ///
  struct SRETPromotion : public CallGraphSCCPass {
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      CallGraphSCCPass::getAnalysisUsage(AU);
    }

    virtual bool runOnSCC(std::vector<CallGraphNode *> &SCC);
    static char ID; // Pass identification, replacement for typeid
    SRETPromotion() : CallGraphSCCPass(&ID) {}

  private:
    CallGraphNode *PromoteReturn(CallGraphNode *CGN);
    bool isSafeToUpdateAllCallers(Function *F);
    Function *cloneFunctionBody(Function *F, const StructType *STy);
    CallGraphNode *updateCallSites(Function *F, Function *NF);
    bool nestedStructType(const StructType *STy);
  };
}

char SRETPromotion::ID = 0;
static RegisterPass<SRETPromotion>
X("sretpromotion", "Promote sret arguments to multiple ret values");

Pass *llvm::createStructRetPromotionPass() {
  return new SRETPromotion();
}

bool SRETPromotion::runOnSCC(std::vector<CallGraphNode *> &SCC) {
  bool Changed = false;

  for (unsigned i = 0, e = SCC.size(); i != e; ++i)
    if (CallGraphNode *NewNode = PromoteReturn(SCC[i])) {
      SCC[i] = NewNode;
      Changed = true;
    }

  return Changed;
}

/// PromoteReturn - This method promotes function that uses StructRet paramater
/// into a function that uses multiple return values.
CallGraphNode *SRETPromotion::PromoteReturn(CallGraphNode *CGN) {
  Function *F = CGN->getFunction();

  if (!F || F->isDeclaration() || !F->hasLocalLinkage())
    return 0;

  // Make sure that function returns struct.
  if (F->arg_size() == 0 || !F->hasStructRetAttr() || F->doesNotReturn())
    return 0;

  DEBUG(dbgs() << "SretPromotion: Looking at sret function "
        << F->getName() << "\n");

  assert(F->getReturnType() == Type::getVoidTy(F->getContext()) &&
         "Invalid function return type");
  Function::arg_iterator AI = F->arg_begin();
  const llvm::PointerType *FArgType = dyn_cast<PointerType>(AI->getType());
  assert(FArgType && "Invalid sret parameter type");
  const llvm::StructType *STy =
    dyn_cast<StructType>(FArgType->getElementType());
  assert(STy && "Invalid sret parameter element type");

  // Check if it is ok to perform this promotion.
  if (isSafeToUpdateAllCallers(F) == false) {
    DEBUG(dbgs() << "SretPromotion: Not all callers can be updated\n");
    NumRejectedSRETUses++;
    return 0;
  }

  DEBUG(dbgs() << "SretPromotion: sret argument will be promoted\n");
  NumSRET++;
  // [1] Replace use of sret parameter
  AllocaInst *TheAlloca = new AllocaInst(STy, NULL, "mrv",
                                         F->getEntryBlock().begin());
  Value *NFirstArg = F->arg_begin();
  NFirstArg->replaceAllUsesWith(TheAlloca);

  // [2] Find and replace ret instructions
  for (Function::iterator FI = F->begin(), FE = F->end();  FI != FE; ++FI)
    for(BasicBlock::iterator BI = FI->begin(), BE = FI->end(); BI != BE; ) {
      Instruction *I = BI;
      ++BI;
      if (isa<ReturnInst>(I)) {
        Value *NV = new LoadInst(TheAlloca, "mrv.ld", I);
        ReturnInst *NR = ReturnInst::Create(F->getContext(), NV, I);
        I->replaceAllUsesWith(NR);
        I->eraseFromParent();
      }
    }

  // [3] Create the new function body and insert it into the module.
  Function *NF = cloneFunctionBody(F, STy);

  // [4] Update all call sites to use new function
  CallGraphNode *NF_CFN = updateCallSites(F, NF);

  CallGraph &CG = getAnalysis<CallGraph>();
  NF_CFN->stealCalledFunctionsFrom(CG[F]);

  delete CG.removeFunctionFromModule(F);
  return NF_CFN;
}

// Check if it is ok to perform this promotion.
bool SRETPromotion::isSafeToUpdateAllCallers(Function *F) {

  if (F->use_empty())
    // No users. OK to modify signature.
    return true;

  for (Value::use_iterator FnUseI = F->use_begin(), FnUseE = F->use_end();
       FnUseI != FnUseE; ++FnUseI) {
    // The function is passed in as an argument to (possibly) another function,
    // we can't change it!
    CallSite CS = CallSite::get(*FnUseI);
    Instruction *Call = CS.getInstruction();
    // The function is used by something else than a call or invoke instruction,
    // we can't change it!
    if (!Call || !CS.isCallee(FnUseI))
      return false;
    CallSite::arg_iterator AI = CS.arg_begin();
    Value *FirstArg = *AI;

    if (!isa<AllocaInst>(FirstArg))
      return false;

    // Check FirstArg's users.
    for (Value::use_iterator ArgI = FirstArg->use_begin(),
           ArgE = FirstArg->use_end(); ArgI != ArgE; ++ArgI) {

      // If FirstArg user is a CallInst that does not correspond to current
      // call site then this function F is not suitable for sret promotion.
      if (CallInst *CI = dyn_cast<CallInst>(ArgI)) {
        if (CI != Call)
          return false;
      }
      // If FirstArg user is a GEP whose all users are not LoadInst then
      // this function F is not suitable for sret promotion.
      else if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(ArgI)) {
        // TODO : Use dom info and insert PHINodes to collect get results
        // from multiple call sites for this GEP.
        if (GEP->getParent() != Call->getParent())
          return false;
        for (Value::use_iterator GEPI = GEP->use_begin(), GEPE = GEP->use_end();
             GEPI != GEPE; ++GEPI)
          if (!isa<LoadInst>(GEPI))
            return false;
      }
      // Any other FirstArg users make this function unsuitable for sret
      // promotion.
      else
        return false;
    }
  }

  return true;
}

/// cloneFunctionBody - Create a new function based on F and
/// insert it into module. Remove first argument. Use STy as
/// the return type for new function.
Function *SRETPromotion::cloneFunctionBody(Function *F,
                                           const StructType *STy) {

  const FunctionType *FTy = F->getFunctionType();
  std::vector<const Type*> Params;

  // Attributes - Keep track of the parameter attributes for the arguments.
  SmallVector<AttributeWithIndex, 8> AttributesVec;
  const AttrListPtr &PAL = F->getAttributes();

  // Add any return attributes.
  if (Attributes attrs = PAL.getRetAttributes())
    AttributesVec.push_back(AttributeWithIndex::get(0, attrs));

  // Skip first argument.
  Function::arg_iterator I = F->arg_begin(), E = F->arg_end();
  ++I;
  // 0th parameter attribute is reserved for return type.
  // 1th parameter attribute is for first 1st sret argument.
  unsigned ParamIndex = 2;
  while (I != E) {
    Params.push_back(I->getType());
    if (Attributes Attrs = PAL.getParamAttributes(ParamIndex))
      AttributesVec.push_back(AttributeWithIndex::get(ParamIndex - 1, Attrs));
    ++I;
    ++ParamIndex;
  }

  // Add any fn attributes.
  if (Attributes attrs = PAL.getFnAttributes())
    AttributesVec.push_back(AttributeWithIndex::get(~0, attrs));

  FunctionType *NFTy = FunctionType::get(STy, Params, FTy->isVarArg());
  Function *NF = Function::Create(NFTy, F->getLinkage());
  NF->takeName(F);
  NF->copyAttributesFrom(F);
  NF->setAttributes(AttrListPtr::get(AttributesVec.begin(), AttributesVec.end()));
  F->getParent()->getFunctionList().insert(F, NF);
  NF->getBasicBlockList().splice(NF->begin(), F->getBasicBlockList());

  // Replace arguments
  I = F->arg_begin();
  E = F->arg_end();
  Function::arg_iterator NI = NF->arg_begin();
  ++I;
  while (I != E) {
    I->replaceAllUsesWith(NI);
    NI->takeName(I);
    ++I;
    ++NI;
  }

  return NF;
}

/// updateCallSites - Update all sites that call F to use NF.
CallGraphNode *SRETPromotion::updateCallSites(Function *F, Function *NF) {
  CallGraph &CG = getAnalysis<CallGraph>();
  SmallVector<Value*, 16> Args;

  // Attributes - Keep track of the parameter attributes for the arguments.
  SmallVector<AttributeWithIndex, 8> ArgAttrsVec;

  // Get a new callgraph node for NF.
  CallGraphNode *NF_CGN = CG.getOrInsertFunction(NF);

  while (!F->use_empty()) {
    CallSite CS = CallSite::get(*F->use_begin());
    Instruction *Call = CS.getInstruction();

    const AttrListPtr &PAL = F->getAttributes();
    // Add any return attributes.
    if (Attributes attrs = PAL.getRetAttributes())
      ArgAttrsVec.push_back(AttributeWithIndex::get(0, attrs));

    // Copy arguments, however skip first one.
    CallSite::arg_iterator AI = CS.arg_begin(), AE = CS.arg_end();
    Value *FirstCArg = *AI;
    ++AI;
    // 0th parameter attribute is reserved for return type.
    // 1th parameter attribute is for first 1st sret argument.
    unsigned ParamIndex = 2;
    while (AI != AE) {
      Args.push_back(*AI);
      if (Attributes Attrs = PAL.getParamAttributes(ParamIndex))
        ArgAttrsVec.push_back(AttributeWithIndex::get(ParamIndex - 1, Attrs));
      ++ParamIndex;
      ++AI;
    }

    // Add any function attributes.
    if (Attributes attrs = PAL.getFnAttributes())
      ArgAttrsVec.push_back(AttributeWithIndex::get(~0, attrs));

    AttrListPtr NewPAL = AttrListPtr::get(ArgAttrsVec.begin(), ArgAttrsVec.end());

    // Build new call instruction.
    Instruction *New;
    if (InvokeInst *II = dyn_cast<InvokeInst>(Call)) {
      New = InvokeInst::Create(NF, II->getNormalDest(), II->getUnwindDest(),
                               Args.begin(), Args.end(), "", Call);
      cast<InvokeInst>(New)->setCallingConv(CS.getCallingConv());
      cast<InvokeInst>(New)->setAttributes(NewPAL);
    } else {
      New = CallInst::Create(NF, Args.begin(), Args.end(), "", Call);
      cast<CallInst>(New)->setCallingConv(CS.getCallingConv());
      cast<CallInst>(New)->setAttributes(NewPAL);
      if (cast<CallInst>(Call)->isTailCall())
        cast<CallInst>(New)->setTailCall();
    }
    Args.clear();
    ArgAttrsVec.clear();
    New->takeName(Call);

    // Update the callgraph to know that the callsite has been transformed.
    CallGraphNode *CalleeNode = CG[Call->getParent()->getParent()];
    CalleeNode->removeCallEdgeFor(Call);
    CalleeNode->addCalledFunction(New, NF_CGN);

    // Update all users of sret parameter to extract value using extractvalue.
    for (Value::use_iterator UI = FirstCArg->use_begin(),
           UE = FirstCArg->use_end(); UI != UE; ) {
      User *U2 = *UI++;
      CallInst *C2 = dyn_cast<CallInst>(U2);
      if (C2 && (C2 == Call))
        continue;

      GetElementPtrInst *UGEP = cast<GetElementPtrInst>(U2);
      ConstantInt *Idx = cast<ConstantInt>(UGEP->getOperand(2));
      Value *GR = ExtractValueInst::Create(New, Idx->getZExtValue(),
                                           "evi", UGEP);
      while(!UGEP->use_empty()) {
        // isSafeToUpdateAllCallers has checked that all GEP uses are
        // LoadInsts
        LoadInst *L = cast<LoadInst>(*UGEP->use_begin());
        L->replaceAllUsesWith(GR);
        L->eraseFromParent();
      }
      UGEP->eraseFromParent();
      continue;
    }
    Call->eraseFromParent();
  }

  return NF_CGN;
}

/// nestedStructType - Return true if STy includes any
/// other aggregate types
bool SRETPromotion::nestedStructType(const StructType *STy) {
  unsigned Num = STy->getNumElements();
  for (unsigned i = 0; i < Num; i++) {
    const Type *Ty = STy->getElementType(i);
    if (!Ty->isSingleValueType() && Ty != Type::getVoidTy(STy->getContext()))
      return true;
  }
  return false;
}
<|endoftext|>