<commit_before>/*************************************************************************
 *
 *  $RCSfile: accessibleeventnotifier.cxx,v $
 *
 *  $Revision: 1.6 $
 *
 *  last change: $Author: vg $ $Date: 2003-05-19 12:57:08 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_ACCESSIBLE_EVENT_NOTIFIER
#include <comphelper/accessibleeventnotifier.hxx>
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

#ifndef _COMPHELPER_GUARDING_HXX_
#include <comphelper/guarding.hxx>
#endif

//.........................................................................
namespace comphelper
{
//.........................................................................

    using namespace ::com::sun::star::uno;
    using namespace ::com::sun::star::lang;
    using namespace ::com::sun::star::accessibility;
    using namespace ::comphelper;

    //=====================================================================
    //= AccessibleEventNotifier
    //=====================================================================
    //---------------------------------------------------------------------
    ::osl::Mutex                        AccessibleEventNotifier::s_aMutex;
    AccessibleEventNotifier::ClientMap  AccessibleEventNotifier::s_aClients;

    //---------------------------------------------------------------------
    AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId()
    {
        TClientId nBiggestUsedId = 0;
        TClientId nFreeId = 0;

        // look through all registered clients until we find a "gap" in the ids

        // Note that the following relies on the fact the elements in the map are traveled with
        // ascending keys (aka client ids)

        for (   ClientMap::const_iterator aLookup = s_aClients.begin();
                aLookup != s_aClients.end();
                ++aLookup
            )
        {
            TClientId nCurrent = aLookup->first;
            OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );

            if ( nCurrent - nBiggestUsedId > 1 )
            {   // found a "gap"
                nFreeId = nBiggestUsedId + 1;
                break;
            }

            nBiggestUsedId = nCurrent;
        }

        if ( !nFreeId )
            nFreeId = nBiggestUsedId + 1;

        OSL_ENSURE( s_aClients.end() == s_aClients.find( nFreeId ),
            "AccessibleEventNotifier::generateId: algorithm broken!" );

        return nFreeId;
    }

    //---------------------------------------------------------------------
    AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( )
    {
        ::osl::MutexGuard aGuard( s_aMutex );

        // generate a new client id
        TClientId nNewClientId = generateId( );

        // the event listeners for the new client
        EventListeners* pNewListeners = new EventListeners( s_aMutex );
            // note that we're using our own mutex here, so the listener containers for all
            // our clients share this same mutex.
            // this is a reminiscense to the days where the notifier was asynchronous. Today this is
            // completely nonsense, and potentially slowing down the Office me thinks ...

        // add the client
        s_aClients.insert( ClientMap::value_type( nNewClientId, pNewListeners ) );

        // outta here
        return nNewClientId;
    }

    //---------------------------------------------------------------------
    sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos )
    {
        // look up this client
        _rPos = s_aClients.find( _nClient );
        OSL_ENSURE( s_aClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );

        return ( s_aClients.end() != _rPos );
    }

    //---------------------------------------------------------------------
    void AccessibleEventNotifier::revokeClient( const TClientId _nClient )
    {
        ::osl::MutexGuard aGuard( s_aMutex );

        ClientMap::iterator aClientPos;
        if ( !implLookupClient( _nClient, aClientPos ) )
            // already asserted in implLookupClient
            return;

        // remove it from the clients map
        delete aClientPos->second;
        s_aClients.erase( aClientPos );
    }

    //---------------------------------------------------------------------
    void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient,
            const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) )
    {
        ::osl::MutexGuard aGuard( s_aMutex );

        ClientMap::iterator aClientPos;
        if ( !implLookupClient( _nClient, aClientPos ) )
            // already asserted in implLookupClient
            return;

        // notify the "disposing" event for this client
        EventObject aDisposalEvent;
        aDisposalEvent.Source = _rxEventSource;

        // notify the listeners
        EventListeners* pListeners = aClientPos->second;

        // we do not need the entry in the clients map anymore
        // (do this before actually notifying, because some client implementations have re-entrance
        // problems and call into revokeClient while we are notifying from hereing)
        s_aClients.erase( aClientPos );

        // now really do the notification
        pListeners->disposeAndClear( aDisposalEvent );
        delete pListeners;

    }

    //---------------------------------------------------------------------
    sal_Int32 AccessibleEventNotifier::addEventListener(
        const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
    {
        ::osl::MutexGuard aGuard( s_aMutex );

        ClientMap::iterator aClientPos;
        if ( !implLookupClient( _nClient, aClientPos ) )
            // already asserted in implLookupClient
            return 0;

        if ( _rxListener.is() )
            aClientPos->second->addInterface( _rxListener );

        return aClientPos->second->getLength();
    }

    //---------------------------------------------------------------------
    sal_Int32 AccessibleEventNotifier::removeEventListener(
        const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
    {
        ::osl::MutexGuard aGuard( s_aMutex );

        ClientMap::iterator aClientPos;
        if ( !implLookupClient( _nClient, aClientPos ) )
            // already asserted in implLookupClient
            return 0;

        if ( _rxListener.is() )
            aClientPos->second->removeInterface( _rxListener );

        return aClientPos->second->getLength();
    }

    //---------------------------------------------------------------------
    Sequence< Reference< XInterface > > AccessibleEventNotifier::getEventListeners( const TClientId _nClient ) SAL_THROW( ( ) )
    {
        Sequence< Reference< XInterface > > aListeners;

        ::osl::MutexGuard aGuard( s_aMutex );

        ClientMap::iterator aClientPos;
        if ( implLookupClient( _nClient, aClientPos ) )
            aListeners = aClientPos->second->getElements();

        return aListeners;
    }

    //---------------------------------------------------------------------
    void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) )
    {
        Sequence< Reference< XInterface > > aListeners;

        // --- <mutex lock> -------------------------------
        {
            ::osl::MutexGuard aGuard( s_aMutex );

            ClientMap::iterator aClientPos;
            if ( !implLookupClient( _nClient, aClientPos ) )
                // already asserted in implLookupClient
                return;

            // since we're synchronous, again, we want to notify immediately
            aListeners = aClientPos->second->getElements();
        }
        // --- </mutex lock> ------------------------------

            // default handling: loop through all listeners, and notify them
        const Reference< XInterface >* pListeners = aListeners.getConstArray();
        const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
        while ( pListeners != pListenersEnd )
        {
            try
            {
                static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent );
            }
            catch( const Exception& e )
            {
                e;
                // silent this
                // no assertion, because a broken access remote bridge or something like this
                // can cause this exception
            }
            ++pListeners;
        }
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

<commit_msg>INTEGRATION: CWS tune04 (1.6.120); FILE MERGED 2004/06/14 09:16:48 cmc 1.6.120.1: #i29636# turn global objects into local static data protected with swishy double-locked templated template<commit_after>/*************************************************************************
 *
 *  $RCSfile: accessibleeventnotifier.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: hjs $ $Date: 2004-06-25 17:20:53 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef COMPHELPER_ACCESSIBLE_EVENT_NOTIFIER
#include <comphelper/accessibleeventnotifier.hxx>
#endif

#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
#ifndef INCLUDED_RTL_INSTANCE_HXX
#include <rtl/instance.hxx>
#endif

#ifndef _COMPHELPER_GUARDING_HXX_
#include <comphelper/guarding.hxx>
#endif

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::accessibility;
using namespace ::comphelper;

//=====================================================================
//= AccessibleEventNotifier
//=====================================================================
//---------------------------------------------------------------------
namespace
{
    struct lclMutex
        : public rtl::Static< ::osl::Mutex, lclMutex > {};
    struct Clients
        : public rtl::Static< AccessibleEventNotifier::ClientMap, Clients > {};
}

//.........................................................................
namespace comphelper
{
//.........................................................................

    //---------------------------------------------------------------------
    AccessibleEventNotifier::TClientId AccessibleEventNotifier::generateId()
    {
        TClientId nBiggestUsedId = 0;
        TClientId nFreeId = 0;

        // look through all registered clients until we find a "gap" in the ids

        // Note that the following relies on the fact the elements in the map are traveled with
        // ascending keys (aka client ids)
        AccessibleEventNotifier::ClientMap &rClients = Clients::get();
        for (   ClientMap::const_iterator aLookup = rClients.begin();
                aLookup != rClients.end();
                ++aLookup
            )
        {
            TClientId nCurrent = aLookup->first;
            OSL_ENSURE( nCurrent > nBiggestUsedId, "AccessibleEventNotifier::generateId: map is expected to be sorted ascending!" );

            if ( nCurrent - nBiggestUsedId > 1 )
            {   // found a "gap"
                nFreeId = nBiggestUsedId + 1;
                break;
            }

            nBiggestUsedId = nCurrent;
        }

        if ( !nFreeId )
            nFreeId = nBiggestUsedId + 1;

        OSL_ENSURE( rClients.end() == rClients.find( nFreeId ),
            "AccessibleEventNotifier::generateId: algorithm broken!" );

        return nFreeId;
    }

    //---------------------------------------------------------------------
    AccessibleEventNotifier::TClientId AccessibleEventNotifier::registerClient( )
    {
        ::osl::MutexGuard aGuard( lclMutex::get() );

        // generate a new client id
        TClientId nNewClientId = generateId( );

        // the event listeners for the new client
        EventListeners* pNewListeners = new EventListeners( lclMutex::get() );
            // note that we're using our own mutex here, so the listener containers for all
            // our clients share this same mutex.
            // this is a reminiscense to the days where the notifier was asynchronous. Today this is
            // completely nonsense, and potentially slowing down the Office me thinks ...

        // add the client
        Clients::get().insert( ClientMap::value_type( nNewClientId, pNewListeners ) );

        // outta here
        return nNewClientId;
    }

    //---------------------------------------------------------------------
    sal_Bool AccessibleEventNotifier::implLookupClient( const TClientId _nClient, ClientMap::iterator& _rPos )
    {
        // look up this client
        AccessibleEventNotifier::ClientMap &rClients = Clients::get();
        _rPos = rClients.find( _nClient );
        OSL_ENSURE( rClients.end() != _rPos, "AccessibleEventNotifier::implLookupClient: invalid client id (did you register your client?)!" );

        return ( rClients.end() != _rPos );
    }

    //---------------------------------------------------------------------
    void AccessibleEventNotifier::revokeClient( const TClientId _nClient )
    {
        ::osl::MutexGuard aGuard( lclMutex::get() );

        ClientMap::iterator aClientPos;
        if ( !implLookupClient( _nClient, aClientPos ) )
            // already asserted in implLookupClient
            return;

        // remove it from the clients map
        delete aClientPos->second;
        Clients::get().erase( aClientPos );
    }

    //---------------------------------------------------------------------
    void AccessibleEventNotifier::revokeClientNotifyDisposing( const TClientId _nClient,
            const Reference< XInterface >& _rxEventSource ) SAL_THROW( ( ) )
    {
        ::osl::MutexGuard aGuard( lclMutex::get() );

        ClientMap::iterator aClientPos;
        if ( !implLookupClient( _nClient, aClientPos ) )
            // already asserted in implLookupClient
            return;

        // notify the "disposing" event for this client
        EventObject aDisposalEvent;
        aDisposalEvent.Source = _rxEventSource;

        // notify the listeners
        EventListeners* pListeners = aClientPos->second;

        // we do not need the entry in the clients map anymore
        // (do this before actually notifying, because some client implementations have re-entrance
        // problems and call into revokeClient while we are notifying from hereing)
        Clients::get().erase( aClientPos );

        // now really do the notification
        pListeners->disposeAndClear( aDisposalEvent );
        delete pListeners;

    }

    //---------------------------------------------------------------------
    sal_Int32 AccessibleEventNotifier::addEventListener(
        const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
    {
        ::osl::MutexGuard aGuard( lclMutex::get() );

        ClientMap::iterator aClientPos;
        if ( !implLookupClient( _nClient, aClientPos ) )
            // already asserted in implLookupClient
            return 0;

        if ( _rxListener.is() )
            aClientPos->second->addInterface( _rxListener );

        return aClientPos->second->getLength();
    }

    //---------------------------------------------------------------------
    sal_Int32 AccessibleEventNotifier::removeEventListener(
        const TClientId _nClient, const Reference< XAccessibleEventListener >& _rxListener ) SAL_THROW( ( ) )
    {
        ::osl::MutexGuard aGuard( lclMutex::get() );

        ClientMap::iterator aClientPos;
        if ( !implLookupClient( _nClient, aClientPos ) )
            // already asserted in implLookupClient
            return 0;

        if ( _rxListener.is() )
            aClientPos->second->removeInterface( _rxListener );

        return aClientPos->second->getLength();
    }

    //---------------------------------------------------------------------
    Sequence< Reference< XInterface > > AccessibleEventNotifier::getEventListeners( const TClientId _nClient ) SAL_THROW( ( ) )
    {
        Sequence< Reference< XInterface > > aListeners;

        ::osl::MutexGuard aGuard( lclMutex::get() );

        ClientMap::iterator aClientPos;
        if ( implLookupClient( _nClient, aClientPos ) )
            aListeners = aClientPos->second->getElements();

        return aListeners;
    }

    //---------------------------------------------------------------------
    void AccessibleEventNotifier::addEvent( const TClientId _nClient, const AccessibleEventObject& _rEvent ) SAL_THROW( ( ) )
    {
        Sequence< Reference< XInterface > > aListeners;

        // --- <mutex lock> -------------------------------
        {
            ::osl::MutexGuard aGuard( lclMutex::get() );

            ClientMap::iterator aClientPos;
            if ( !implLookupClient( _nClient, aClientPos ) )
                // already asserted in implLookupClient
                return;

            // since we're synchronous, again, we want to notify immediately
            aListeners = aClientPos->second->getElements();
        }
        // --- </mutex lock> ------------------------------

            // default handling: loop through all listeners, and notify them
        const Reference< XInterface >* pListeners = aListeners.getConstArray();
        const Reference< XInterface >* pListenersEnd = pListeners + aListeners.getLength();
        while ( pListeners != pListenersEnd )
        {
            try
            {
                static_cast< XAccessibleEventListener* >( pListeners->get() )->notifyEvent( _rEvent );
            }
            catch( const Exception& e )
            {
                e;
                // silent this
                // no assertion, because a broken access remote bridge or something like this
                // can cause this exception
            }
            ++pListeners;
        }
    }

//.........................................................................
}   // namespace comphelper
//.........................................................................

<|endoftext|>


<commit_before>#include "torrentdetailscontentview.h"

#include <QMenu>
#include <QFileInfo>
#include <QDir>
#include <QFocusEvent>
#include <QApplication>
#include "utilities/utils.h"
#include "utilities/filesystem_utils.h"
#include "torrentcontentmodel.h"
#include "global_functions.h"

#include <utility>

TorrentDetailsContentView::TorrentDetailsContentView(QWidget* parent /*= 0*/): QTreeView(parent)
{
    setContextMenuPolicy(Qt::CustomContextMenu);
    VERIFY(connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(on_showTreeTorentContextMenu(const QPoint&))));
}

void TorrentDetailsContentView::setModel(TorrentContentFilterModel* a_model)
{
    QTreeView::setModel(a_model);

    VERIFY(connect(this, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(on_ItemOpenFolder())));
}

TorrentContentFilterModel* TorrentDetailsContentView::model()
{
    return static_cast<TorrentContentFilterModel*>(QTreeView::model());
}

void TorrentDetailsContentView::on_showTreeTorentContextMenu(const QPoint& pos)
{
    QModelIndex index = indexAt(pos);
    if (index.isValid())
    {
        QMenu menu;
        menu.setObjectName(QStringLiteral("TorrentDetailsContextMenu"));
        menu.addAction(QIcon(), tr("Open in folder"), this, SLOT(on_ItemOpenFolder()));
        menu.addAction(QIcon(), tr("Open File"), this, SLOT(on_ItemOpenFile()));

        menu.exec(QCursor::pos());
    }
}

void TorrentDetailsContentView::on_ItemOpenFolder()
{
    QModelIndex curr_index = selectionModel()->currentIndex();
    if (!curr_index.isValid())
    {
        return;
    }

    TorrentContentModelItem* torrentItem = model()->getTorrentContentModelItem(curr_index);
    QString pathFile = torrentItem->getPath();
    if (pathFile.isEmpty())
    {
        pathFile = torrentItem->getName();
    }
    QString savePath = model()->model()->getSavePath();
    QString filename = savePath + pathFile;
    QFileInfo downloadFile(filename);
    utilities::SelectFile(downloadFile.absoluteFilePath(), downloadFile.dir().path());
}

void TorrentDetailsContentView::on_ItemOpenFile()
{
    QModelIndex curr_index = selectionModel()->currentIndex();
    if (!curr_index.isValid())
    {
        return;
    }

    TorrentContentModelItem* torrentItem = model()->getTorrentContentModelItem(curr_index);
    QString pathFile = torrentItem->getPath();
    QString savePath = model()->model()->getSavePath();
    QString filename = savePath + pathFile;
    if (torrentItem->isFolder() || !QFile::exists(filename))
    {
        return;
    }

    global_functions::openFile(filename);
}

bool TorrentDetailsContentView::event(QEvent *event)
{
    if (event->type() == QEvent::FocusOut
        && static_cast<QFocusEvent*>(event)->reason() == Qt::MouseFocusReason)
    {
        if (QWidget *widget = QApplication::focusWidget())
        {
            const QModelIndexList selectedRows = selectionModel()->selectedRows(TorrentContentModelItem::COL_PRIO);
            for (const auto& idx : qAsConst(selectedRows))
            {
                if (indexWidget(idx) == widget)
                {
                    return QAbstractScrollArea::event(event);
                }
            }
        }
    }

    return QTreeView::event(event);
}

void TorrentDetailsContentView::commitData(QWidget *editor)
{
    QModelIndexList selectedRows = selectionModel()->selectedRows(TorrentContentModelItem::COL_PRIO);
    for (const auto& idx : qAsConst(selectedRows))
    {
        if (indexWidget(idx) == editor)
        {
            model()->setSelectedRows(std::move(selectedRows));
            break;
        }
    }

    QTreeView::commitData(editor);

    model()->setSelectedRows(QModelIndexList());
}
<commit_msg>context menu items fixed<commit_after>#include "torrentdetailscontentview.h"

#include <QMenu>
#include <QFileInfo>
#include <QDir>
#include <QFocusEvent>
#include <QApplication>
#include "utilities/utils.h"
#include "utilities/filesystem_utils.h"
#include "torrentcontentmodel.h"
#include "global_functions.h"

#include <utility>

TorrentDetailsContentView::TorrentDetailsContentView(QWidget* parent /*= 0*/): QTreeView(parent)
{
    setContextMenuPolicy(Qt::CustomContextMenu);
    VERIFY(connect(this, SIGNAL(customContextMenuRequested(const QPoint&)), SLOT(on_showTreeTorentContextMenu(const QPoint&))));
}

void TorrentDetailsContentView::setModel(TorrentContentFilterModel* a_model)
{
    QTreeView::setModel(a_model);

    VERIFY(connect(this, SIGNAL(doubleClicked(const QModelIndex&)), SLOT(on_ItemOpenFolder())));
}

TorrentContentFilterModel* TorrentDetailsContentView::model()
{
    return static_cast<TorrentContentFilterModel*>(QTreeView::model());
}

void TorrentDetailsContentView::on_showTreeTorentContextMenu(const QPoint& pos)
{
    QModelIndex index = indexAt(pos);
    if (!index.isValid())
    {
        return;
    }

    TorrentContentModelItem* torrentItem = model()->getTorrentContentModelItem(index);
    QMenu menu;
    menu.setObjectName(QStringLiteral("TorrentDetailsContextMenu"));
    menu.addAction(QIcon(), tr("Open in folder"), this, SLOT(on_ItemOpenFolder()));
    if (!torrentItem->isFolder())
    {
        menu.addAction(QIcon(), tr("Open File"), this, SLOT(on_ItemOpenFile()));
    }

    menu.exec(QCursor::pos());
}

void TorrentDetailsContentView::on_ItemOpenFolder()
{
    QModelIndex curr_index = selectionModel()->currentIndex();
    if (!curr_index.isValid())
    {
        return;
    }

    TorrentContentModelItem* torrentItem = model()->getTorrentContentModelItem(curr_index);
    QString pathFile = torrentItem->getPath();
    if (pathFile.isEmpty())
    {
        pathFile = torrentItem->getName();
    }
    QString savePath = model()->model()->getSavePath();
    QString filename = savePath + pathFile;
    QFileInfo downloadFile(filename);
    utilities::SelectFile(downloadFile.absoluteFilePath(), downloadFile.dir().path());
}

void TorrentDetailsContentView::on_ItemOpenFile()
{
    QModelIndex curr_index = selectionModel()->currentIndex();
    if (!curr_index.isValid())
    {
        return;
    }

    TorrentContentModelItem* torrentItem = model()->getTorrentContentModelItem(curr_index);
    QString pathFile = torrentItem->getPath();
    QString savePath = model()->model()->getSavePath();
    QString filename = savePath + pathFile;
    if (torrentItem->isFolder() || !QFile::exists(filename))
    {
        return;
    }

    global_functions::openFile(filename);
}

bool TorrentDetailsContentView::event(QEvent *event)
{
    if (event->type() == QEvent::FocusOut
        && static_cast<QFocusEvent*>(event)->reason() == Qt::MouseFocusReason)
    {
        if (QWidget *widget = QApplication::focusWidget())
        {
            const QModelIndexList selectedRows = selectionModel()->selectedRows(TorrentContentModelItem::COL_PRIO);
            for (const auto& idx : qAsConst(selectedRows))
            {
                if (indexWidget(idx) == widget)
                {
                    return QAbstractScrollArea::event(event);
                }
            }
        }
    }

    return QTreeView::event(event);
}

void TorrentDetailsContentView::commitData(QWidget *editor)
{
    QModelIndexList selectedRows = selectionModel()->selectedRows(TorrentContentModelItem::COL_PRIO);
    for (const auto& idx : qAsConst(selectedRows))
    {
        if (indexWidget(idx) == editor)
        {
            model()->setSelectedRows(std::move(selectedRows));
            break;
        }
    }

    QTreeView::commitData(editor);

    model()->setSelectedRows(QModelIndexList());
}
<|endoftext|>


<commit_before>/*
 * Copyright 2009-2017 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <votca/csg/nblistgrid_3body.h>

namespace votca { namespace csg {

void NBListGrid_3Body::Generate(BeadList &list1, BeadList &list2, BeadList &list3, bool do_exclusions)
{
    BeadList::iterator iter;
    _do_exclusions = do_exclusions;
    if(list1.empty()) return;
    if(list2.empty()) return;
    if(list3.empty()) return;

    //check if all bead lists "have" the same topology
    assert(list1.getTopology() == list2.getTopology());
    assert(list1.getTopology() == list3.getTopology());
    assert(list2.getTopology() == list3.getTopology());
    Topology *top = _top = list1.getTopology();

    InitializeGrid(top->getBox());

    // Add all beads of list1 to _beads1
    for(iter = list1.begin(); iter != list1.end(); ++iter)
        getCell((*iter)->getPos())._beads1.push_back(*iter);

    // Add all beads of list2 to _beads2
    for(iter = list2.begin(); iter != list2.end(); ++iter)
        getCell((*iter)->getPos())._beads2.push_back(*iter);

    // Add all beads of list2 to _beads3
    for(iter = list3.begin(); iter != list3.end(); ++iter)
        getCell((*iter)->getPos())._beads3.push_back(*iter);

    //loop over beads of list 1 again to get the correlations
    for(iter = list1.begin(); iter != list1.end(); ++iter) {
        cell_t &cell = getCell((*iter)->getPos());
        TestBead(cell, *iter);
    }

}

void NBListGrid_3Body::Generate(BeadList &list1, BeadList &list2, bool do_exclusions)
{
    BeadList::iterator iter;
    _do_exclusions = do_exclusions;
    if(list1.empty()) return;
    if(list2.empty()) return;

    //check if both bead lists "have" the same topology
    assert(list1.getTopology() == list2.getTopology());
    Topology *top = _top = list1.getTopology();

    InitializeGrid(top->getBox());

    // Add all beads of list1 to _beads1
    for(iter = list1.begin(); iter != list1.end(); ++iter)
        getCell((*iter)->getPos())._beads1.push_back(*iter);

    // Add all beads of list2 to _beads2
    for(iter = list2.begin(); iter != list2.end(); ++iter)
        getCell((*iter)->getPos())._beads2.push_back(*iter);

    //In this case type2 and type3 are the same
    for(vector<cell_t>::iterator iter = _grid.begin(); iter != _grid.end(); ++iter){
        (*iter)._beads3 = (*iter)._beads2;
    }

    //loop over beads of list 1 again to get the correlations
    for(iter = list1.begin(); iter != list1.end(); ++iter) {
        cell_t &cell = getCell((*iter)->getPos());
        TestBead(cell, *iter);
    }
}

void NBListGrid_3Body::Generate(BeadList &list, bool do_exclusions)
{
    BeadList::iterator iter;
    _do_exclusions = do_exclusions;
    if(list.empty()) return;

    Topology *top = _top = list.getTopology();

    InitializeGrid(top->getBox());

    // Add all beads of list to all! bead lists of the cell
    for(iter = list.begin(); iter != list.end(); ++iter)
        getCell((*iter)->getPos())._beads1.push_back(*iter);

    for(vector<cell_t>::iterator iter = _grid.begin(); iter != _grid.end(); ++iter){
        (*iter)._beads2 = (*iter)._beads1;
        (*iter)._beads3 = (*iter)._beads1;
    }

    //loop over beads again to get the correlations (as all of the same type here)
    for(iter = list.begin(); iter != list.end(); ++iter) {
        cell_t &cell = getCell((*iter)->getPos());
        TestBead(cell, *iter);
    }
}

void NBListGrid_3Body::InitializeGrid(const matrix &box)
{
    _box_a = box.getCol(0);
    _box_b = box.getCol(1);
    _box_c = box.getCol(2);

    // create plane normals
    _norm_a = _box_b ^ _box_c;
    _norm_b = _box_c ^ _box_a;
    _norm_c = _box_a ^ _box_b;

    _norm_a.normalize();
    _norm_b.normalize();
    _norm_c.normalize();

    double la = _box_a * _norm_a;
    double lb = _box_b * _norm_b;
    double lc = _box_c * _norm_c;

    // calculate grid size, each grid has to be at least size of cut-off
    _box_Na = max((int)(fabs(la/_cutoff)), 1);
    _box_Nb = max((int)(fabs(lb/_cutoff)), 1);
    _box_Nc = max((int)(fabs(lc/_cutoff)), 1);

    _norm_a = _norm_a / (_box_a*_norm_a)*(double)_box_Na;
    _norm_b = _norm_b / (_box_b*_norm_b)*(double)_box_Nb;
    _norm_c = _norm_c / (_box_c*_norm_c)*(double)_box_Nc;

    //cout << "grid size: " << _box_Na << "x" << _box_Nb << "x" << _box_Nc << endl;
    _grid.resize(_box_Na*_box_Nb*_box_Nc);

    int a1,a2,b1,b2,c1,c2;

    a1 = b1 = c1 = -1;
    a2 = b2 = c2 = 1;

    if(_box_Na < 3) a2 = 0;
    if(_box_Nb < 3) b2 = 0;
    if(_box_Nc < 3) c2 = 0;

    if(_box_Na < 2) a1 = 0;
    if(_box_Nb < 2) b1 = 0;
    if(_box_Nc < 2) c1 = 0;

    // wow, setting up the neighbours is an ugly for construct!
    // loop from N..2*N to avoid if and only use %
    for(int a=_box_Na; a<2*_box_Na; ++a)
        for(int b=_box_Nb; b<2*_box_Nb; ++b)
            for(int c=_box_Nc; c<2*_box_Nc; ++c) {
                cell_t &cell = getCell(a%_box_Na, b%_box_Nb, c%_box_Nc);
                for(int aa=a+a1; aa<=a+a2; ++aa)
                    for(int bb=b+b1; bb<=b+b2; ++bb)
                        for(int cc=c+c1; cc<=c+c2; ++cc) {
                            cell_t *c = &getCell(aa%_box_Na, bb%_box_Nb, cc%_box_Nc);
                            //test: for 3body algorithm: each cell is a neighbor of its own !!!
                            //if(c == &cell) continue; // ignore self
                            cell._neighbours.push_back(
                                &getCell(aa%_box_Na, bb%_box_Nb, cc%_box_Nc)
                            );
                        }
            }
}

NBListGrid_3Body::cell_t &NBListGrid_3Body::getCell(const vec &r)
{
    int a = (int)floor(r*_norm_a);
    int b = (int)floor(r*_norm_b);
    int c = (int)floor(r*_norm_c);

    if(a<0) a = _box_Na + a%_box_Na;
    a %= _box_Na;

    if(b<0)
      b = _box_Nb + b%_box_Nb;
    b %= _box_Nb;

    if(c<0) c = _box_Nc + c%_box_Nc;
    c %= _box_Nc;

    return getCell(a,b,c);
 }

void NBListGrid_3Body::TestBead(NBListGrid_3Body::cell_t &cell, Bead *bead)
{
    BeadList::iterator iter2;
    BeadList::iterator iter3;
    vec u = bead->getPos();

    //loop over all neighbors (this now includes the cell itself!) to iterate over all beads of type2 of the cell and its neighbors
    for(vector<cell_t*>::iterator iterc2=cell._neighbours.begin(); iterc2!=cell._neighbours.end(); ++iterc2) {
        for(iter2=(*(*iterc2))._beads2.begin(); iter2!=(*(*iterc2))._beads2.end(); ++iter2) {

            if(bead == *iter2) {
                continue;
            }

            //loop again over all neighbors (this now includes the cell itself!) to iterate over all beads of type3 of the cell and its neighbors
            for(vector<cell_t*>::iterator iterc3=cell._neighbours.begin(); iterc3!=cell._neighbours.end(); ++iterc3) {
                for(iter3=(*(*iterc3))._beads3.begin(); iter3!=(*(*iterc3))._beads3.end(); ++iter3) {

                    //do not include the same beads twice in one triple!
                    if(bead == *iter3) {
                        continue;
                    }
                    if(*iter2 == *iter3) {
                        continue;
                    }

                    vec v = (*iter2)->getPos();
                    vec z = (*iter3)->getPos();

                    vec r12 = _top->BCShortestConnection(u, v);
                    vec r13 = _top->BCShortestConnection(u, z);
                    vec r23 = _top->BCShortestConnection(v, z);
                    double d12 = abs(r12);
                    double d13 = abs(r13);
                    double d23 = abs(r23);

                    //to do: at the moment use only one cutoff value
                    //to do: so far only check the distance between bead 1 (central bead) and bead2 and bead 3
                    if( (d12 < _cutoff) && (d13 < _cutoff) ){
                    /// experimental: at the moment exclude interaction as soon as one of the three pairs (1,2) (1,3) (2,3) is excluded!
                    if(_do_exclusions)
                        if( (_top->getExclusions().IsExcluded(bead, *iter2)) || (_top->getExclusions().IsExcluded(bead, *iter3)) || (_top->getExclusions().IsExcluded(*iter2, *iter3)) ) {
                            continue;
                        }
                    if((*_match_function)(bead, *iter2, *iter3, r12, r13, r23, d12, d13, d23))
                        if(!FindTriple(bead, *iter2, *iter3))
                            AddTriple( _triple_creator(bead, *iter2, *iter3, r12, r13, r23));
                    }

                }

            }

        }
    }

}

}}
<commit_msg>Update nblistgrid_3body.cc<commit_after>/*
 * Copyright 2009-2017 The VOTCA Development Team (http://www.votca.org)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <votca/csg/nblistgrid_3body.h>

namespace votca { namespace csg {

void NBListGrid_3Body::Generate(BeadList &list1, BeadList &list2, BeadList &list3, bool do_exclusions)
{
    BeadList::iterator iter;
    _do_exclusions = do_exclusions;
    if(list1.empty()) return;
    if(list2.empty()) return;
    if(list3.empty()) return;

    //check if all bead lists "have" the same topology
    assert(list1.getTopology() == list2.getTopology());
    assert(list1.getTopology() == list3.getTopology());
    assert(list2.getTopology() == list3.getTopology());
    Topology *top = _top = list1.getTopology();

    InitializeGrid(top->getBox());

    // Add all beads of list1 to _beads1
    for(iter = list1.begin(); iter != list1.end(); ++iter)
        getCell((*iter)->getPos())._beads1.push_back(*iter);

    // Add all beads of list2 to _beads2
    for(iter = list2.begin(); iter != list2.end(); ++iter)
        getCell((*iter)->getPos())._beads2.push_back(*iter);

    // Add all beads of list2 to _beads3
    for(iter = list3.begin(); iter != list3.end(); ++iter)
        getCell((*iter)->getPos())._beads3.push_back(*iter);

    //loop over beads of list 1 again to get the correlations
    for(iter = list1.begin(); iter != list1.end(); ++iter) {
        cell_t &cell = getCell((*iter)->getPos());
        TestBead(cell, *iter);
    }

}

void NBListGrid_3Body::Generate(BeadList &list1, BeadList &list2, bool do_exclusions)
{
    BeadList::iterator iter;
    _do_exclusions = do_exclusions;
    if(list1.empty()) return;
    if(list2.empty()) return;

    //check if both bead lists "have" the same topology
    assert(list1.getTopology() == list2.getTopology());
    Topology *top = _top = list1.getTopology();

    InitializeGrid(top->getBox());

    // Add all beads of list1 to _beads1
    for(iter = list1.begin(); iter != list1.end(); ++iter)
        getCell((*iter)->getPos())._beads1.push_back(*iter);

    // Add all beads of list2 to _beads2
    for(iter = list2.begin(); iter != list2.end(); ++iter)
        getCell((*iter)->getPos())._beads2.push_back(*iter);

    //In this case type2 and type3 are the same
    for(vector<cell_t>::iterator iter = _grid.begin(); iter != _grid.end(); ++iter){
        (*iter)._beads3 = (*iter)._beads2;
    }

    //loop over beads of list 1 again to get the correlations
    for(iter = list1.begin(); iter != list1.end(); ++iter) {
        cell_t &cell = getCell((*iter)->getPos());
        TestBead(cell, *iter);
    }
}

void NBListGrid_3Body::Generate(BeadList &list, bool do_exclusions)
{
    BeadList::iterator iter;
    _do_exclusions = do_exclusions;
    if(list.empty()) return;

    Topology *top = _top = list.getTopology();

    InitializeGrid(top->getBox());

    // Add all beads of list to all! bead lists of the cell
    for(iter = list.begin(); iter != list.end(); ++iter)
        getCell((*iter)->getPos())._beads1.push_back(*iter);

    for(vector<cell_t>::iterator iter = _grid.begin(); iter != _grid.end(); ++iter){
        (*iter)._beads2 = (*iter)._beads1;
        (*iter)._beads3 = (*iter)._beads1;
    }

    //loop over beads again to get the correlations (as all of the same type here)
    for(iter = list.begin(); iter != list.end(); ++iter) {
        cell_t &cell = getCell((*iter)->getPos());
        TestBead(cell, *iter);
    }
}

void NBListGrid_3Body::InitializeGrid(const matrix &box)
{
    _box_a = box.getCol(0);
    _box_b = box.getCol(1);
    _box_c = box.getCol(2);

    // create plane normals
    _norm_a = _box_b ^ _box_c;
    _norm_b = _box_c ^ _box_a;
    _norm_c = _box_a ^ _box_b;

    _norm_a.normalize();
    _norm_b.normalize();
    _norm_c.normalize();

    double la = _box_a * _norm_a;
    double lb = _box_b * _norm_b;
    double lc = _box_c * _norm_c;

    // calculate grid size, each grid has to be at least size of cut-off
    _box_Na = max((int)(fabs(la/_cutoff)), 1);
    _box_Nb = max((int)(fabs(lb/_cutoff)), 1);
    _box_Nc = max((int)(fabs(lc/_cutoff)), 1);

    _norm_a = _norm_a / (_box_a*_norm_a)*(double)_box_Na;
    _norm_b = _norm_b / (_box_b*_norm_b)*(double)_box_Nb;
    _norm_c = _norm_c / (_box_c*_norm_c)*(double)_box_Nc;

    //cout << "grid size: " << _box_Na << "x" << _box_Nb << "x" << _box_Nc << endl;
    _grid.resize(_box_Na*_box_Nb*_box_Nc);

    int a1,a2,b1,b2,c1,c2;

    a1 = b1 = c1 = -1;
    a2 = b2 = c2 = 1;

    if(_box_Na < 3) a2 = 0;
    if(_box_Nb < 3) b2 = 0;
    if(_box_Nc < 3) c2 = 0;

    if(_box_Na < 2) a1 = 0;
    if(_box_Nb < 2) b1 = 0;
    if(_box_Nc < 2) c1 = 0;

    // wow, setting up the neighbours is an ugly for construct!
    // loop from N..2*N to avoid if and only use %
    for(int a=_box_Na; a<2*_box_Na; ++a)
        for(int b=_box_Nb; b<2*_box_Nb; ++b)
            for(int c=_box_Nc; c<2*_box_Nc; ++c) {
                cell_t &cell = getCell(a%_box_Na, b%_box_Nb, c%_box_Nc);
                for(int aa=a+a1; aa<=a+a2; ++aa)
                    for(int bb=b+b1; bb<=b+b2; ++bb)
                        for(int cc=c+c1; cc<=c+c2; ++cc) {
                            cell_t *c = &getCell(aa%_box_Na, bb%_box_Nb, cc%_box_Nc);
                            //test: for 3body algorithm: each cell is a neighbor of its own !!!
                            cell._neighbours.push_back(
                                &getCell(aa%_box_Na, bb%_box_Nb, cc%_box_Nc)
                            );
                        }
            }
}

NBListGrid_3Body::cell_t &NBListGrid_3Body::getCell(const vec &r)
{
    int a = (int)floor(r*_norm_a);
    int b = (int)floor(r*_norm_b);
    int c = (int)floor(r*_norm_c);

    if(a<0) a = _box_Na + a%_box_Na;
    a %= _box_Na;

    if(b<0)
      b = _box_Nb + b%_box_Nb;
    b %= _box_Nb;

    if(c<0) c = _box_Nc + c%_box_Nc;
    c %= _box_Nc;

    return getCell(a,b,c);
 }

void NBListGrid_3Body::TestBead(NBListGrid_3Body::cell_t &cell, Bead *bead)
{
    BeadList::iterator iter2;
    BeadList::iterator iter3;
    vec u = bead->getPos();

    //loop over all neighbors (this now includes the cell itself!) to iterate over all beads of type2 of the cell and its neighbors
    for(vector<cell_t*>::iterator iterc2=cell._neighbours.begin(); iterc2!=cell._neighbours.end(); ++iterc2) {
        for(iter2=(*(*iterc2))._beads2.begin(); iter2!=(*(*iterc2))._beads2.end(); ++iter2) {

            if(bead == *iter2) {
                continue;
            }

            //loop again over all neighbors (this now includes the cell itself!) to iterate over all beads of type3 of the cell and its neighbors
            for(vector<cell_t*>::iterator iterc3=cell._neighbours.begin(); iterc3!=cell._neighbours.end(); ++iterc3) {
                for(iter3=(*(*iterc3))._beads3.begin(); iter3!=(*(*iterc3))._beads3.end(); ++iter3) {

                    //do not include the same beads twice in one triple!
                    if(bead == *iter3) {
                        continue;
                    }
                    if(*iter2 == *iter3) {
                        continue;
                    }

                    vec v = (*iter2)->getPos();
                    vec z = (*iter3)->getPos();

                    vec r12 = _top->BCShortestConnection(u, v);
                    vec r13 = _top->BCShortestConnection(u, z);
                    vec r23 = _top->BCShortestConnection(v, z);
                    double d12 = abs(r12);
                    double d13 = abs(r13);
                    double d23 = abs(r23);

                    //to do: at the moment use only one cutoff value
                    //to do: so far only check the distance between bead 1 (central bead) and bead2 and bead 3
                    if( (d12 < _cutoff) && (d13 < _cutoff) ){
                    /// experimental: at the moment exclude interaction as soon as one of the three pairs (1,2) (1,3) (2,3) is excluded!
                    if(_do_exclusions)
                        if( (_top->getExclusions().IsExcluded(bead, *iter2)) || (_top->getExclusions().IsExcluded(bead, *iter3)) || (_top->getExclusions().IsExcluded(*iter2, *iter3)) ) {
                            continue;
                        }
                    if((*_match_function)(bead, *iter2, *iter3, r12, r13, r23, d12, d13, d23))
                        if(!FindTriple(bead, *iter2, *iter3))
                            AddTriple( _triple_creator(bead, *iter2, *iter3, r12, r13, r23));
                    }

                }

            }

        }
    }

}

}}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <boost/optional.hpp>

#include "Utils.hpp"

#include "ltac/PeepholeOptimizer.hpp"

#include "mtac/Utils.hpp"

using namespace eddic;

//TODO Comment every optimization

void optimize_statement(ltac::Statement& statement){
    if(boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::MOV){
            //MOV reg, 0 can be transformed into XOR reg, reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::XOR;
                instruction->arg2 = instruction->arg1;

                return;
            }
        }

        if(instruction->op == ltac::Operator::ADD){
            //ADD reg, 1 can be transformed into INC reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                return;
            }

            //ADD reg, -1 can be transformed into DEC reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                return;
            }
        }

        if(instruction->op == ltac::Operator::SUB){
            //SUB reg, 1 can be transformed into DEC reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                return;
            }

            //SUB reg, -1 can be transformed into INC reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                return;
            }
        }

        if(instruction->op == ltac::Operator::MUL){
            //Optimize multiplications with SHIFTs or LEAs
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::is<int>(*instruction->arg2)){
                int constant = boost::get<int>(*instruction->arg2);

                auto reg = boost::get<ltac::Register>(*instruction->arg1);

                if(isPowerOfTwo(constant)){
                    instruction->op = ltac::Operator::SHIFT_LEFT;
                    instruction->arg2 = powerOfTwo(constant);

                    return;
                }

                if(constant == 3){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 2, 0);

                    return;
                }

                if(constant == 5){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 4, 0);

                    return;
                }

                if(constant == 9){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 8, 0);

                    return;
                }
            }
        }

        if(instruction->op == ltac::Operator::CMP_INT){
            //Optimize comparisons with 0 with or reg, reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::OR;
                instruction->arg2 = instruction->arg1;

                return;
            }
        }
    }
}

void single_statement_optimizations(std::shared_ptr<ltac::Program> program){
    for(auto& function : program->functions){
        for(auto& statement : function->getStatements()){
            optimize_statement(statement);
        }
    }
}

void multiple_statement_optimizations(std::shared_ptr<ltac::Program> program){
    for(auto& function : program->functions){
        auto& statements = function->getStatements();

        for(size_t i = 1; i < statements.size(); ++i){
            auto& s1 = statements[i -  1];
            auto& s2 = statements[i];

            if(mtac::is<std::shared_ptr<ltac::Instruction>>(s1) && mtac::is<std::shared_ptr<ltac::Instruction>>(s2)){
                auto& i1 = boost::get<std::shared_ptr<ltac::Instruction>>(s1);
                auto& i2 = boost::get<std::shared_ptr<ltac::Instruction>>(s2);

                if(i1->op == ltac::Operator::LEAVE && i2->op == ltac::Operator::LEAVE){
                    i2->op = ltac::Operator::NOP;
                }
            }
        }
    }
}

void eddic::ltac::optimize(std::shared_ptr<ltac::Program> program){
    single_statement_optimizations(program);
    multiple_statement_optimizations(program);
}
<commit_msg>Combine FREE_STACK Together a MOV reg, reg is useless<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <boost/optional.hpp>

#include "Utils.hpp"

#include "ltac/PeepholeOptimizer.hpp"

#include "mtac/Utils.hpp"

using namespace eddic;

//TODO Comment every optimization

void optimize_statement(ltac::Statement& statement){
    if(boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::MOV){
            //MOV reg, 0 can be transformed into XOR reg, reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::XOR;
                instruction->arg2 = instruction->arg1;

                return;
            }

            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::is<ltac::Register>(*instruction->arg2)){
                auto& reg1 = boost::get<ltac::Register>(*instruction->arg1);
                auto& reg2 = boost::get<ltac::Register>(*instruction->arg2);

                //MOV reg, reg is useless
                if(reg1 == reg2){
                    instruction->op = ltac::Operator::NOP;
                    instruction->arg1.reset();
                    instruction->arg2.reset();
                }
            }
        }

        if(instruction->op == ltac::Operator::ADD){
            //ADD reg, 1 can be transformed into INC reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                return;
            }

            //ADD reg, -1 can be transformed into DEC reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                return;
            }
        }

        if(instruction->op == ltac::Operator::SUB){
            //SUB reg, 1 can be transformed into DEC reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                return;
            }

            //SUB reg, -1 can be transformed into INC reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                return;
            }
        }

        if(instruction->op == ltac::Operator::MUL){
            //Optimize multiplications with SHIFTs or LEAs
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::is<int>(*instruction->arg2)){
                int constant = boost::get<int>(*instruction->arg2);

                auto reg = boost::get<ltac::Register>(*instruction->arg1);

                if(isPowerOfTwo(constant)){
                    instruction->op = ltac::Operator::SHIFT_LEFT;
                    instruction->arg2 = powerOfTwo(constant);

                    return;
                }

                if(constant == 3){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 2, 0);

                    return;
                }

                if(constant == 5){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 4, 0);

                    return;
                }

                if(constant == 9){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 8, 0);

                    return;
                }
            }
        }

        if(instruction->op == ltac::Operator::CMP_INT){
            //Optimize comparisons with 0 with or reg, reg
            if(mtac::is<ltac::Register>(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::OR;
                instruction->arg2 = instruction->arg1;

                return;
            }
        }
    }
}

void single_statement_optimizations(std::shared_ptr<ltac::Program> program){
    for(auto& function : program->functions){
        for(auto& statement : function->getStatements()){
            optimize_statement(statement);
        }
    }
}

void multiple_statement_optimizations(std::shared_ptr<ltac::Program> program){
    for(auto& function : program->functions){
        auto& statements = function->getStatements();

        for(size_t i = 1; i < statements.size(); ++i){
            auto& s1 = statements[i -  1];
            auto& s2 = statements[i];

            if(mtac::is<std::shared_ptr<ltac::Instruction>>(s1) && mtac::is<std::shared_ptr<ltac::Instruction>>(s2)){
                auto& i1 = boost::get<std::shared_ptr<ltac::Instruction>>(s1);
                auto& i2 = boost::get<std::shared_ptr<ltac::Instruction>>(s2);

                //The seconde LEAVE is dead
                if(i1->op == ltac::Operator::LEAVE && i2->op == ltac::Operator::LEAVE){
                    i2->op = ltac::Operator::NOP;
                }

                //Combine two FREE STACK into one
                if(i1->op == ltac::Operator::FREE_STACK && i2->op == ltac::Operator::FREE_STACK){
                    i1->arg1 = boost::get<int>(*i1->arg1) + boost::get<int>(*i2->arg1);
                    i2->arg1.reset();
                    i2->op = ltac::Operator::NOP;
                }
            }
        }
    }
}

void eddic::ltac::optimize(std::shared_ptr<ltac::Program> program){
    single_statement_optimizations(program);
    multiple_statement_optimizations(program);
}
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <boost/optional.hpp>

#include "Utils.hpp"
#include "PerfsTimer.hpp"

#include "ltac/PeepholeOptimizer.hpp"

#include "mtac/Utils.hpp"

using namespace eddic;

template<typename T>
inline bool is_reg(T value){
    return mtac::is<ltac::Register>(value);
}

inline void optimize_statement(ltac::Statement& statement){
    if(boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::MOV){
            //MOV reg, 0 can be transformed into XOR reg, reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::XOR;
                instruction->arg2 = instruction->arg1;

                return;
            }

            if(is_reg(*instruction->arg1) && is_reg(*instruction->arg2)){
                auto& reg1 = boost::get<ltac::Register>(*instruction->arg1);
                auto& reg2 = boost::get<ltac::Register>(*instruction->arg2);

                //MOV reg, reg is useless
                if(reg1 == reg2){
                    instruction->op = ltac::Operator::NOP;
                    instruction->arg1.reset();
                    instruction->arg2.reset();
                }
            }
        }

        if(instruction->op == ltac::Operator::ADD){
            //ADD reg, 1 can be transformed into INC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                return;
            }

            //ADD reg, -1 can be transformed into DEC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                return;
            }
        }

        if(instruction->op == ltac::Operator::SUB){
            //SUB reg, 1 can be transformed into DEC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                return;
            }

            //SUB reg, -1 can be transformed into INC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                return;
            }
        }

        if(instruction->op == ltac::Operator::MUL){
            //Optimize multiplications with SHIFTs or LEAs
            if(is_reg(*instruction->arg1) && mtac::is<int>(*instruction->arg2)){
                int constant = boost::get<int>(*instruction->arg2);

                auto reg = boost::get<ltac::Register>(*instruction->arg1);

                if(isPowerOfTwo(constant)){
                    instruction->op = ltac::Operator::SHIFT_LEFT;
                    instruction->arg2 = powerOfTwo(constant);

                    return;
                }

                if(constant == 3){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 2, 0);

                    return;
                }

                if(constant == 5){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 4, 0);

                    return;
                }

                if(constant == 9){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 8, 0);

                    return;
                }
            }
        }

        if(instruction->op == ltac::Operator::CMP_INT){
            //Optimize comparisons with 0 with or reg, reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::OR;
                instruction->arg2 = instruction->arg1;

                return;
            }
        }
    }
}

inline void multiple_statement_optimizations(ltac::Statement& s1, ltac::Statement& s2){
    if(mtac::is<std::shared_ptr<ltac::Instruction>>(s1) && mtac::is<std::shared_ptr<ltac::Instruction>>(s2)){
        auto& i1 = boost::get<std::shared_ptr<ltac::Instruction>>(s1);
        auto& i2 = boost::get<std::shared_ptr<ltac::Instruction>>(s2);

        //The seconde LEAVE is dead
        if(i1->op == ltac::Operator::LEAVE && i2->op == ltac::Operator::LEAVE){
            i2->op = ltac::Operator::NOP;
        }

        //Combine two FREE STACK into one
        if(i1->op == ltac::Operator::FREE_STACK && i2->op == ltac::Operator::FREE_STACK){
            i1->arg1 = boost::get<int>(*i1->arg1) + boost::get<int>(*i2->arg1);
            i2->arg1.reset();
            i2->op = ltac::Operator::NOP;
        }

        if(i1->op == ltac::Operator::MOV && i2->op == ltac::Operator::MOV){
            if(is_reg(*i1->arg1) && is_reg(*i1->arg2) && is_reg(*i2->arg1) && is_reg(*i2->arg2)){
                auto reg11 = boost::get<ltac::Register>(*i1->arg1);
                auto reg12 = boost::get<ltac::Register>(*i1->arg2);
                auto reg21 = boost::get<ltac::Register>(*i2->arg1);
                auto reg22 = boost::get<ltac::Register>(*i2->arg2);

                //cross MOV (ir4 = ir5, ir5 = ir4), keep only the first
                if (reg11 == reg22 && reg12 == reg21){
                    i2->op = ltac::Operator::NOP;
                }
            } else if(is_reg(*i1->arg1) && is_reg(*i2->arg1)){
                auto reg11 = boost::get<ltac::Register>(*i1->arg1);
                auto reg21 = boost::get<ltac::Register>(*i2->arg1);

                //Two MOV to the same register => keep only last MOV
                if(reg11 == reg21){
                    i1->op = ltac::Operator::NOP;
                }
            } else if(is_reg(*i1->arg1) && is_reg(*i2->arg2)){
                if(boost::get<ltac::Address>(&*i1->arg2) && boost::get<ltac::Address>(&*i2->arg1)){
                    if(boost::get<ltac::Address>(*i1->arg2) == boost::get<ltac::Address>(*i2->arg1)){
                        i2->op = ltac::Operator::NOP;
                        i2->arg1.reset();
                        i2->arg2.reset();
                    }
                }
            } else if(is_reg(*i1->arg2) && is_reg(*i2->arg1)){
                if(boost::get<ltac::Address>(&*i1->arg1) && boost::get<ltac::Address>(&*i2->arg2)){
                    if(boost::get<ltac::Address>(*i1->arg1) == boost::get<ltac::Address>(*i2->arg2)){
                        i2->op = ltac::Operator::NOP;
                        i2->arg1.reset();
                        i2->arg2.reset();
                    }
                }
            }
        }

        if(i1->op == ltac::Operator::MOV && i2->op == ltac::Operator::ADD){
            if(is_reg(*i1->arg1) && is_reg(*i2->arg1)){
                if(boost::get<ltac::Register>(*i1->arg1) == boost::get<ltac::Register>(*i2->arg1)){
                    if(boost::get<ltac::Register>(&*i1->arg2) && boost::get<int>(&*i2->arg2)){
                        i2->op = ltac::Operator::LEA;
                        i2->arg2 = ltac::Address(boost::get<ltac::Register>(*i1->arg2), boost::get<int>(*i2->arg2));

                        i1->op = ltac::Operator::NOP;
                        i1->arg1.reset();
                        i1->arg2.reset();
                    } else if(boost::get<std::string>(&*i1->arg2) && boost::get<int>(&*i2->arg2)){
                        i2->op = ltac::Operator::LEA;
                        i2->arg2 = ltac::Address(boost::get<std::string>(*i1->arg2), boost::get<int>(*i2->arg2));

                        i1->op = ltac::Operator::NOP;
                        i1->arg1.reset();
                        i1->arg2.reset();
                    }
                }
            }
        }
    }
}

inline bool is_nop(ltac::Statement& statement){
    if(mtac::is<std::shared_ptr<ltac::Instruction>>(statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::NOP){
            return true;
        }
    }

    return false;
}

void basic_optimizations(std::shared_ptr<ltac::Function> function){
    auto& statements = function->getStatements();

    auto it = statements.begin();
    auto end = statements.end() - 1;

    while(it != end){
        auto& s1 = *it;
        auto& s2 = *(it + 1);

        //Optimizations that looks at only one statement
        optimize_statement(s1);

        //Optimizations that looks at several statements at once
        multiple_statement_optimizations(s1, s2);

        if(is_nop(s1)){
            it = statements.erase(it);
            end = statements.end() - 1;

            continue;
        }

        ++it;
    }
}

void eddic::ltac::optimize(std::shared_ptr<ltac::Program> program){
    PerfsTimer("Peephole optimizations", true);

    //TODO Make something comparable to the optimization model for MTAC
    for(int i = 0; i < 2; ++i){
        for(auto& function : program->functions){
            basic_optimizations(function);
        }
    }
}
<commit_msg>Improve the optimization model for the peephole optimizer<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2011.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <iostream>
#include <boost/optional.hpp>

#include "Utils.hpp"
#include "PerfsTimer.hpp"

#include "ltac/PeepholeOptimizer.hpp"

#include "mtac/Utils.hpp"

using namespace eddic;

template<typename T>
inline bool is_reg(T value){
    return mtac::is<ltac::Register>(value);
}

inline bool optimize_statement(ltac::Statement& statement){
    if(boost::get<std::shared_ptr<ltac::Instruction>>(&statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::MOV){
            //MOV reg, 0 can be transformed into XOR reg, reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::XOR;
                instruction->arg2 = instruction->arg1;

                return true;
            }

            if(is_reg(*instruction->arg1) && is_reg(*instruction->arg2)){
                auto& reg1 = boost::get<ltac::Register>(*instruction->arg1);
                auto& reg2 = boost::get<ltac::Register>(*instruction->arg2);

                //MOV reg, reg is useless
                if(reg1 == reg2){
                    instruction->op = ltac::Operator::NOP;
                    instruction->arg1.reset();
                    instruction->arg2.reset();

                    return true;
                }
            }
        }

        if(instruction->op == ltac::Operator::ADD){
            //ADD reg, 1 can be transformed into INC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                    return true;
            }

            //ADD reg, -1 can be transformed into DEC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                    return true;
            }
        }

        if(instruction->op == ltac::Operator::SUB){
            //SUB reg, 1 can be transformed into DEC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 1)){
                instruction->op = ltac::Operator::DEC;
                instruction->arg2.reset();

                    return true;
            }

            //SUB reg, -1 can be transformed into INC reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, -1)){
                instruction->op = ltac::Operator::INC;
                instruction->arg2.reset();

                    return true;
            }
        }

        if(instruction->op == ltac::Operator::MUL){
            //Optimize multiplications with SHIFTs or LEAs
            if(is_reg(*instruction->arg1) && mtac::is<int>(*instruction->arg2)){
                int constant = boost::get<int>(*instruction->arg2);

                auto reg = boost::get<ltac::Register>(*instruction->arg1);

                if(isPowerOfTwo(constant)){
                    instruction->op = ltac::Operator::SHIFT_LEFT;
                    instruction->arg2 = powerOfTwo(constant);

                    return true;
                }

                if(constant == 3){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 2, 0);

                    return true;
                }

                if(constant == 5){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 4, 0);

                    return true;
                }

                if(constant == 9){
                    instruction->op = ltac::Operator::LEA;
                    instruction->arg2 = ltac::Address(reg, reg, 8, 0);

                    return true;
                }
            }
        }

        if(instruction->op == ltac::Operator::CMP_INT){
            //Optimize comparisons with 0 with or reg, reg
            if(is_reg(*instruction->arg1) && mtac::equals<int>(*instruction->arg2, 0)){
                instruction->op = ltac::Operator::OR;
                instruction->arg2 = instruction->arg1;

                    return true;
            }
        }
    }

    return false;
}

inline bool multiple_statement_optimizations(ltac::Statement& s1, ltac::Statement& s2){
    if(mtac::is<std::shared_ptr<ltac::Instruction>>(s1) && mtac::is<std::shared_ptr<ltac::Instruction>>(s2)){
        auto& i1 = boost::get<std::shared_ptr<ltac::Instruction>>(s1);
        auto& i2 = boost::get<std::shared_ptr<ltac::Instruction>>(s2);

        //The seconde LEAVE is dead
        if(i1->op == ltac::Operator::LEAVE && i2->op == ltac::Operator::LEAVE){
            i2->op = ltac::Operator::NOP;

            return true;
        }

        //Combine two FREE STACK into one
        if(i1->op == ltac::Operator::FREE_STACK && i2->op == ltac::Operator::FREE_STACK){
            i1->arg1 = boost::get<int>(*i1->arg1) + boost::get<int>(*i2->arg1);

            i2->op = ltac::Operator::NOP;
            i2->arg1.reset();

            return true;
        }

        if(i1->op == ltac::Operator::MOV && i2->op == ltac::Operator::MOV){
            if(is_reg(*i1->arg1) && is_reg(*i1->arg2) && is_reg(*i2->arg1) && is_reg(*i2->arg2)){
                auto reg11 = boost::get<ltac::Register>(*i1->arg1);
                auto reg12 = boost::get<ltac::Register>(*i1->arg2);
                auto reg21 = boost::get<ltac::Register>(*i2->arg1);
                auto reg22 = boost::get<ltac::Register>(*i2->arg2);

                //cross MOV (ir4 = ir5, ir5 = ir4), keep only the first
                if (reg11 == reg22 && reg12 == reg21){
                    i2->op = ltac::Operator::NOP;

                    return true;
                }
            } else if(is_reg(*i1->arg1) && is_reg(*i2->arg1)){
                auto reg11 = boost::get<ltac::Register>(*i1->arg1);
                auto reg21 = boost::get<ltac::Register>(*i2->arg1);

                //Two MOV to the same register => keep only last MOV
                if(reg11 == reg21){
                    i1->op = ltac::Operator::NOP;

                    return true;
                }
            } else if(is_reg(*i1->arg1) && is_reg(*i2->arg2)){
                if(boost::get<ltac::Address>(&*i1->arg2) && boost::get<ltac::Address>(&*i2->arg1)){
                    if(boost::get<ltac::Address>(*i1->arg2) == boost::get<ltac::Address>(*i2->arg1)){
                        i2->op = ltac::Operator::NOP;
                        i2->arg1.reset();
                        i2->arg2.reset();

                        return true;
                    }
                }
            } else if(is_reg(*i1->arg2) && is_reg(*i2->arg1)){
                if(boost::get<ltac::Address>(&*i1->arg1) && boost::get<ltac::Address>(&*i2->arg2)){
                    if(boost::get<ltac::Address>(*i1->arg1) == boost::get<ltac::Address>(*i2->arg2)){
                        i2->op = ltac::Operator::NOP;
                        i2->arg1.reset();
                        i2->arg2.reset();

                        return true;
                    }
                }
            }
        }

        if(i1->op == ltac::Operator::MOV && i2->op == ltac::Operator::ADD){
            if(is_reg(*i1->arg1) && is_reg(*i2->arg1)){
                if(boost::get<ltac::Register>(*i1->arg1) == boost::get<ltac::Register>(*i2->arg1)){
                    if(boost::get<ltac::Register>(&*i1->arg2) && boost::get<int>(&*i2->arg2)){
                        i2->op = ltac::Operator::LEA;
                        i2->arg2 = ltac::Address(boost::get<ltac::Register>(*i1->arg2), boost::get<int>(*i2->arg2));

                        i1->op = ltac::Operator::NOP;
                        i1->arg1.reset();
                        i1->arg2.reset();

                        return true;
                    } else if(boost::get<std::string>(&*i1->arg2) && boost::get<int>(&*i2->arg2)){
                        i2->op = ltac::Operator::LEA;
                        i2->arg2 = ltac::Address(boost::get<std::string>(*i1->arg2), boost::get<int>(*i2->arg2));

                        i1->op = ltac::Operator::NOP;
                        i1->arg1.reset();
                        i1->arg2.reset();

                        return true;
                    }
                }
            }
        }
    }

    return false;
}

inline bool is_nop(ltac::Statement& statement){
    if(mtac::is<std::shared_ptr<ltac::Instruction>>(statement)){
        auto instruction = boost::get<std::shared_ptr<ltac::Instruction>>(statement);

        if(instruction->op == ltac::Operator::NOP){
            return true;
        }
    }

    return false;
}

bool basic_optimizations(std::shared_ptr<ltac::Function> function){
    auto& statements = function->getStatements();

    auto it = statements.begin();
    auto end = statements.end() - 1;

    bool optimized = false;

    while(it != end){
        auto& s1 = *it;
        auto& s2 = *(it + 1);

        //Optimizations that looks at only one statement
        optimized |= optimize_statement(s1);

        //Optimizations that looks at several statements at once
        optimized |= multiple_statement_optimizations(s1, s2);

        if(is_nop(s1)){
            it = statements.erase(it);
            end = statements.end() - 1;

            continue;
        }

        ++it;
    }

    return optimized;
}

void eddic::ltac::optimize(std::shared_ptr<ltac::Program> program){
    PerfsTimer("Peephole optimizations", true);

    for(auto& function : program->functions){
        bool optimized;
        do {
            optimized = false;

            optimized |= basic_optimizations(function);
        } while(optimized);
    }
}
<|endoftext|>