<commit_before>/*
   This file is part of the KDE project
   Copyright (C) 2002-2003 Daniel Molkentin <molkentin@kde.org>
   Copyright (C) 2004-2006 Michael Brade <brade@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This program 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
   General Public License for more details.

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

#include <qpopupmenu.h>
#include <qclipboard.h>

#include <kapplication.h>
#include <kdebug.h>
#include <kaction.h>
#include <kmessagebox.h>

#include <libkdepim/infoextension.h>
#include <libkdepim/sidebarextension.h>

#include "knotes/resourcemanager.h"

#include "knotes_part.h"
#include "knotes_part_p.h"
#include "knotetip.h"

KNotesPart::KNotesPart( QObject *parent, const char *name )
  : DCOPObject( "KNotesIface" ), KParts::ReadOnlyPart( parent, name ),
    mNotesView( new KIconView() ),
    mNoteTip( new KNoteTip( mNotesView ) ),
    mNoteEditDlg( 0 ),
    mManager( new KNotesResourceManager() )
{
  mNoteList.setAutoDelete( true );

  setInstance( new KInstance( "knotes" ) );

  // create the actions
  new KAction( i18n( "&New" ), "knotes", CTRL+Key_N, this, SLOT( newNote() ),
               actionCollection(), "file_new" );
  new KAction( i18n( "Rename..." ), "text", this, SLOT( renameNote() ),
               actionCollection(), "edit_rename" );
  new KAction( i18n( "Delete" ), "editdelete", Key_Delete, this, SLOT( killSelectedNotes() ),
               actionCollection(), "edit_delete" );

  // TODO icons: s/editdelete/knotes_delete/ or the other way round in knotes

  // set the view up
  mNotesView->setSelectionMode( QIconView::Extended );
  mNotesView->setItemsMovable( false );
  mNotesView->setResizeMode( QIconView::Adjust );
  mNotesView->setAutoArrange( true );
  mNotesView->setSorting( true );

  connect( mNotesView, SIGNAL( executed( QIconViewItem* ) ),
           this, SLOT( editNote( QIconViewItem* ) ) );
  connect( mNotesView, SIGNAL( returnPressed( QIconViewItem* ) ),
           this, SLOT( editNote( QIconViewItem* ) ) );
  connect( mNotesView, SIGNAL( itemRenamed( QIconViewItem* ) ),
           this, SLOT( renamedNote( QIconViewItem* ) ) );
  connect( mNotesView, SIGNAL( contextMenuRequested( QIconViewItem*, const QPoint& ) ),
           this, SLOT( popupRMB( QIconViewItem*, const QPoint& ) ) );
  connect( mNotesView, SIGNAL( onItem( QIconViewItem* ) ),
           this, SLOT( slotOnItem( QIconViewItem* ) ) );
  connect( mNotesView, SIGNAL( onViewport() ),
           this, SLOT( slotOnViewport() ) );
  connect( mNotesView, SIGNAL( currentChanged( QIconViewItem* ) ),
           this, SLOT( slotOnCurrentChanged( QIconViewItem* ) ) );

  slotOnCurrentChanged( 0 );

  new KParts::SideBarExtension( mNotesView, this, "NotesSideBarExtension" );

  setWidget( mNotesView );
  setXMLFile( "knotes_part.rc" );

  // connect the resource manager
  connect( mManager, SIGNAL( sigRegisteredNote( KCal::Journal* ) ),
           this, SLOT( createNote( KCal::Journal* ) ) );
  connect( mManager, SIGNAL( sigDeregisteredNote( KCal::Journal* ) ),
           this, SLOT( killNote( KCal::Journal* ) ) );

  // read the notes
  mManager->load();
}

KNotesPart::~KNotesPart()
{
  delete mNoteTip;
  mNoteTip = 0;

  delete mManager;
  mManager = 0;
}

bool KNotesPart::openFile()
{
  return false;
}

// public KNotes DCOP interface implementation

QString KNotesPart::newNote( const QString& name, const QString& text )
{
  // create the new note
  KCal::Journal *journal = new KCal::Journal();

  // new notes have the current date/time as title if none was given
  if ( !name.isEmpty() )
      journal->setSummary( name );
  else
      journal->setSummary( KGlobal::locale()->formatDateTime( QDateTime::currentDateTime() ) );

  // the body of the note
  journal->setDescription( text );

  // Edit the new note if text is empty
  if ( text.isNull() )
  {
    if ( !mNoteEditDlg )
      mNoteEditDlg = new KNoteEditDlg( widget() );

    mNoteEditDlg->setTitle( journal->summary() );
    mNoteEditDlg->setText( journal->description() );

    if ( mNoteEditDlg->exec() == QDialog::Accepted )
    {
      journal->setSummary( mNoteEditDlg->title() );
      journal->setDescription( mNoteEditDlg->text() );
    }
    else
    {
      delete journal;
      return "";
    }
  }

  mManager->addNewNote( journal );
  mManager->save();

  KNotesIconViewItem *note = mNoteList[ journal->uid() ];
  mNotesView->ensureItemVisible( note );
  mNotesView->setCurrentItem( note );

  return journal->uid();
}

QString KNotesPart::newNoteFromClipboard( const QString& name )
{
  const QString& text = KApplication::clipboard()->text();
  return newNote( name, text );
}

void KNotesPart::killNote( const QString& id )
{
  killNote( id, false );
}

void KNotesPart::killNote( const QString& id, bool force )
{
  KNotesIconViewItem *note = mNoteList[ id ];

   if ( note && !force && KMessageBox::warningContinueCancelList( mNotesView,
        i18n( "Do you really want to delete this note?" ),
        mNoteList[ id ]->text(), i18n( "Confirm Delete" ),
        KStdGuiItem::del() ) == KMessageBox::Continue )
   {
     mManager->deleteNote( mNoteList[id]->journal() );
     mManager->save();
   }
}

QString KNotesPart::name( const QString& id ) const
{
  KNotesIconViewItem *note = mNoteList[ id ];
  if ( note )
    return note->text();
  else
    return QString::null;
}

QString KNotesPart::text( const QString& id ) const
{
  KNotesIconViewItem *note = mNoteList[id];
  if ( note )
    return note->journal()->description();
  else
    return QString::null;
}

void KNotesPart::setName( const QString& id, const QString& newName )
{
  KNotesIconViewItem *note = mNoteList[ id ];
  if ( note ) {
    note->setText( newName );
    mManager->save();
  }
}

void KNotesPart::setText( const QString& id, const QString& newText )
{
  KNotesIconViewItem *note = mNoteList[ id ];
  if ( note ) {
    note->journal()->setDescription( newText );
    mManager->save();
  }
}

QMap<QString, QString> KNotesPart::notes() const
{
  QMap<QString, QString> notes;
  QDictIterator<KNotesIconViewItem> it( mNoteList );

  for ( ; it.current(); ++it )
    notes.insert( (*it)->journal()->uid(), (*it)->journal()->description() );

  return notes;
}

// private stuff

void KNotesPart::killSelectedNotes()
{
  QPtrList<KNotesIconViewItem> items;
  QStringList notes;

  KNotesIconViewItem *knivi;
  for ( QIconViewItem *it = mNotesView->firstItem(); it; it = it->nextItem() ) {
    if ( it->isSelected() ) {
      knivi = static_cast<KNotesIconViewItem *>( it );
      items.append( knivi );
      notes.append( knivi->text() );
    }
  }

  if ( items.isEmpty() )
    return;

  int ret = KMessageBox::warningContinueCancelList( mNotesView,
            i18n( "Do you really want to delete this note?",
                  "Do you really want to delete these %n notes?", items.count() ),
            notes, i18n( "Confirm Delete" ),
            KStdGuiItem::del() );

  if ( ret == KMessageBox::Continue ) {
    QPtrListIterator<KNotesIconViewItem> kniviIt( items );
    while ( (knivi = *kniviIt) ) {
      ++kniviIt;
      mManager->deleteNote( knivi->journal() );
    }

    mManager->save();
  }
}

void KNotesPart::popupRMB( QIconViewItem *item, const QPoint& pos )
{
  QPopupMenu *contextMenu = NULL;

  if ( item )
    contextMenu = static_cast<QPopupMenu *>( factory()->container( "note_context", this ) );
  else
    contextMenu = static_cast<QPopupMenu *>( factory()->container( "notepart_context", this ) );

  if ( !contextMenu )
    return;

  contextMenu->popup( pos );
}

void KNotesPart::slotOnItem( QIconViewItem *i )
{
  // TODO: disable (i.e. setNote( QString::null )) when mouse button pressed

  KNotesIconViewItem *item = static_cast<KNotesIconViewItem *>( i );
  mNoteTip->setNote( item );
}

void KNotesPart::slotOnViewport()
{
  mNoteTip->setNote( 0 );
}

// TODO: also with takeItem, clear(),

// create and kill the icon view item corresponding to the note, edit the note

void KNotesPart::createNote( KCal::Journal *journal )
{
  // make sure all fields are existent, initialize them with default values
  QString property = journal->customProperty( "KNotes", "BgColor" );
  if ( property.isNull() )
    journal->setCustomProperty( "KNotes", "BgColor", "#ffff00" );

  property = journal->customProperty( "KNotes", "FgColor" );
  if ( property.isNull() )
    journal->setCustomProperty( "KNotes", "FgColor", "#000000" );

  property = journal->customProperty( "KNotes", "RichText" );
  if ( property.isNull() )
    journal->setCustomProperty( "KNotes", "RichText", "true" );

  mNoteList.insert( journal->uid(), new KNotesIconViewItem( mNotesView, journal ) );
}

void KNotesPart::killNote( KCal::Journal *journal )
{
  mNoteList.remove( journal->uid() );
}

void KNotesPart::editNote( QIconViewItem *item )
{
  if ( !mNoteEditDlg )
    mNoteEditDlg = new KNoteEditDlg( widget() );

  KCal::Journal *journal = static_cast<KNotesIconViewItem *>( item )->journal();

  mNoteEditDlg->setRichText( journal->customProperty( "KNotes", "RichText" ) == "true" );
  mNoteEditDlg->setTitle( journal->summary() );
  mNoteEditDlg->setText( journal->description() );

  if ( mNoteEditDlg->exec() == QDialog::Accepted ) {
    item->setText( mNoteEditDlg->title() );
    journal->setDescription( mNoteEditDlg->text() );
    mManager->save();
  }
}

void KNotesPart::renameNote()
{
  mNotesView->currentItem()->rename();
}

void KNotesPart::renamedNote( QIconViewItem* )
{
  mManager->save();
}

void KNotesPart::slotOnCurrentChanged( QIconViewItem* )
{
  KAction *renameAction = actionCollection()->action( "edit_rename" );
  KAction *deleteAction = actionCollection()->action( "edit_delete" );

  if ( !mNotesView->currentItem() ) {
    renameAction->setEnabled( false );
    deleteAction->setEnabled( false );
  } else {
    renameAction->setEnabled( true );
    deleteAction->setEnabled( true );
  }
}

#include "knotes_part.moc"
#include "knotes_part_p.moc"

<commit_msg>Fix the implementation of killNote(), it did nothing when force == true. Thanks for the report! BUG:127063<commit_after>/*
   This file is part of the KDE project
   Copyright (C) 2002-2003 Daniel Molkentin <molkentin@kde.org>
   Copyright (C) 2004-2006 Michael Brade <brade@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This program 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
   General Public License for more details.

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

#include <qpopupmenu.h>
#include <qclipboard.h>

#include <kapplication.h>
#include <kdebug.h>
#include <kaction.h>
#include <kmessagebox.h>

#include <libkdepim/infoextension.h>
#include <libkdepim/sidebarextension.h>

#include "knotes/resourcemanager.h"

#include "knotes_part.h"
#include "knotes_part_p.h"
#include "knotetip.h"

KNotesPart::KNotesPart( QObject *parent, const char *name )
  : DCOPObject( "KNotesIface" ), KParts::ReadOnlyPart( parent, name ),
    mNotesView( new KIconView() ),
    mNoteTip( new KNoteTip( mNotesView ) ),
    mNoteEditDlg( 0 ),
    mManager( new KNotesResourceManager() )
{
  mNoteList.setAutoDelete( true );

  setInstance( new KInstance( "knotes" ) );

  // create the actions
  new KAction( i18n( "&New" ), "knotes", CTRL+Key_N, this, SLOT( newNote() ),
               actionCollection(), "file_new" );
  new KAction( i18n( "Rename..." ), "text", this, SLOT( renameNote() ),
               actionCollection(), "edit_rename" );
  new KAction( i18n( "Delete" ), "editdelete", Key_Delete, this, SLOT( killSelectedNotes() ),
               actionCollection(), "edit_delete" );

  // TODO icons: s/editdelete/knotes_delete/ or the other way round in knotes

  // set the view up
  mNotesView->setSelectionMode( QIconView::Extended );
  mNotesView->setItemsMovable( false );
  mNotesView->setResizeMode( QIconView::Adjust );
  mNotesView->setAutoArrange( true );
  mNotesView->setSorting( true );

  connect( mNotesView, SIGNAL( executed( QIconViewItem* ) ),
           this, SLOT( editNote( QIconViewItem* ) ) );
  connect( mNotesView, SIGNAL( returnPressed( QIconViewItem* ) ),
           this, SLOT( editNote( QIconViewItem* ) ) );
  connect( mNotesView, SIGNAL( itemRenamed( QIconViewItem* ) ),
           this, SLOT( renamedNote( QIconViewItem* ) ) );
  connect( mNotesView, SIGNAL( contextMenuRequested( QIconViewItem*, const QPoint& ) ),
           this, SLOT( popupRMB( QIconViewItem*, const QPoint& ) ) );
  connect( mNotesView, SIGNAL( onItem( QIconViewItem* ) ),
           this, SLOT( slotOnItem( QIconViewItem* ) ) );
  connect( mNotesView, SIGNAL( onViewport() ),
           this, SLOT( slotOnViewport() ) );
  connect( mNotesView, SIGNAL( currentChanged( QIconViewItem* ) ),
           this, SLOT( slotOnCurrentChanged( QIconViewItem* ) ) );

  slotOnCurrentChanged( 0 );

  new KParts::SideBarExtension( mNotesView, this, "NotesSideBarExtension" );

  setWidget( mNotesView );
  setXMLFile( "knotes_part.rc" );

  // connect the resource manager
  connect( mManager, SIGNAL( sigRegisteredNote( KCal::Journal* ) ),
           this, SLOT( createNote( KCal::Journal* ) ) );
  connect( mManager, SIGNAL( sigDeregisteredNote( KCal::Journal* ) ),
           this, SLOT( killNote( KCal::Journal* ) ) );

  // read the notes
  mManager->load();
}

KNotesPart::~KNotesPart()
{
  delete mNoteTip;
  mNoteTip = 0;

  delete mManager;
  mManager = 0;
}

bool KNotesPart::openFile()
{
  return false;
}

// public KNotes DCOP interface implementation

QString KNotesPart::newNote( const QString& name, const QString& text )
{
  // create the new note
  KCal::Journal *journal = new KCal::Journal();

  // new notes have the current date/time as title if none was given
  if ( !name.isEmpty() )
      journal->setSummary( name );
  else
      journal->setSummary( KGlobal::locale()->formatDateTime( QDateTime::currentDateTime() ) );

  // the body of the note
  journal->setDescription( text );

  // Edit the new note if text is empty
  if ( text.isNull() )
  {
    if ( !mNoteEditDlg )
      mNoteEditDlg = new KNoteEditDlg( widget() );

    mNoteEditDlg->setTitle( journal->summary() );
    mNoteEditDlg->setText( journal->description() );

    if ( mNoteEditDlg->exec() == QDialog::Accepted )
    {
      journal->setSummary( mNoteEditDlg->title() );
      journal->setDescription( mNoteEditDlg->text() );
    }
    else
    {
      delete journal;
      return "";
    }
  }

  mManager->addNewNote( journal );
  mManager->save();

  KNotesIconViewItem *note = mNoteList[ journal->uid() ];
  mNotesView->ensureItemVisible( note );
  mNotesView->setCurrentItem( note );

  return journal->uid();
}

QString KNotesPart::newNoteFromClipboard( const QString& name )
{
  const QString& text = KApplication::clipboard()->text();
  return newNote( name, text );
}

void KNotesPart::killNote( const QString& id )
{
  killNote( id, false );
}

void KNotesPart::killNote( const QString& id, bool force )
{
  KNotesIconViewItem *note = mNoteList[ id ];

  if ( note &&
       ( (!force && KMessageBox::warningContinueCancelList( mNotesView,
                    i18n( "Do you really want to delete this note?" ),
                    mNoteList[ id ]->text(), i18n( "Confirm Delete" ),
                    KStdGuiItem::del() ) == KMessageBox::Continue)
         || force )
     )
  {
    mManager->deleteNote( mNoteList[id]->journal() );
    mManager->save();
  }
}

QString KNotesPart::name( const QString& id ) const
{
  KNotesIconViewItem *note = mNoteList[ id ];
  if ( note )
    return note->text();
  else
    return QString::null;
}

QString KNotesPart::text( const QString& id ) const
{
  KNotesIconViewItem *note = mNoteList[id];
  if ( note )
    return note->journal()->description();
  else
    return QString::null;
}

void KNotesPart::setName( const QString& id, const QString& newName )
{
  KNotesIconViewItem *note = mNoteList[ id ];
  if ( note ) {
    note->setText( newName );
    mManager->save();
  }
}

void KNotesPart::setText( const QString& id, const QString& newText )
{
  KNotesIconViewItem *note = mNoteList[ id ];
  if ( note ) {
    note->journal()->setDescription( newText );
    mManager->save();
  }
}

QMap<QString, QString> KNotesPart::notes() const
{
  QMap<QString, QString> notes;
  QDictIterator<KNotesIconViewItem> it( mNoteList );

  for ( ; it.current(); ++it )
    notes.insert( (*it)->journal()->uid(), (*it)->journal()->summary() );

  return notes;
}

// private stuff

void KNotesPart::killSelectedNotes()
{
  QPtrList<KNotesIconViewItem> items;
  QStringList notes;

  KNotesIconViewItem *knivi;
  for ( QIconViewItem *it = mNotesView->firstItem(); it; it = it->nextItem() ) {
    if ( it->isSelected() ) {
      knivi = static_cast<KNotesIconViewItem *>( it );
      items.append( knivi );
      notes.append( knivi->text() );
    }
  }

  if ( items.isEmpty() )
    return;

  int ret = KMessageBox::warningContinueCancelList( mNotesView,
            i18n( "Do you really want to delete this note?",
                  "Do you really want to delete these %n notes?", items.count() ),
            notes, i18n( "Confirm Delete" ),
            KStdGuiItem::del() );

  if ( ret == KMessageBox::Continue ) {
    QPtrListIterator<KNotesIconViewItem> kniviIt( items );
    while ( (knivi = *kniviIt) ) {
      ++kniviIt;
      mManager->deleteNote( knivi->journal() );
    }

    mManager->save();
  }
}

void KNotesPart::popupRMB( QIconViewItem *item, const QPoint& pos )
{
  QPopupMenu *contextMenu = NULL;

  if ( item )
    contextMenu = static_cast<QPopupMenu *>( factory()->container( "note_context", this ) );
  else
    contextMenu = static_cast<QPopupMenu *>( factory()->container( "notepart_context", this ) );

  if ( !contextMenu )
    return;

  contextMenu->popup( pos );
}

void KNotesPart::slotOnItem( QIconViewItem *i )
{
  // TODO: disable (i.e. setNote( QString::null )) when mouse button pressed

  KNotesIconViewItem *item = static_cast<KNotesIconViewItem *>( i );
  mNoteTip->setNote( item );
}

void KNotesPart::slotOnViewport()
{
  mNoteTip->setNote( 0 );
}

// TODO: also with takeItem, clear(),

// create and kill the icon view item corresponding to the note, edit the note

void KNotesPart::createNote( KCal::Journal *journal )
{
  // make sure all fields are existent, initialize them with default values
  QString property = journal->customProperty( "KNotes", "BgColor" );
  if ( property.isNull() )
    journal->setCustomProperty( "KNotes", "BgColor", "#ffff00" );

  property = journal->customProperty( "KNotes", "FgColor" );
  if ( property.isNull() )
    journal->setCustomProperty( "KNotes", "FgColor", "#000000" );

  property = journal->customProperty( "KNotes", "RichText" );
  if ( property.isNull() )
    journal->setCustomProperty( "KNotes", "RichText", "true" );

  mNoteList.insert( journal->uid(), new KNotesIconViewItem( mNotesView, journal ) );
}

void KNotesPart::killNote( KCal::Journal *journal )
{
  mNoteList.remove( journal->uid() );
}

void KNotesPart::editNote( QIconViewItem *item )
{
  if ( !mNoteEditDlg )
    mNoteEditDlg = new KNoteEditDlg( widget() );

  KCal::Journal *journal = static_cast<KNotesIconViewItem *>( item )->journal();

  mNoteEditDlg->setRichText( journal->customProperty( "KNotes", "RichText" ) == "true" );
  mNoteEditDlg->setTitle( journal->summary() );
  mNoteEditDlg->setText( journal->description() );

  if ( mNoteEditDlg->exec() == QDialog::Accepted ) {
    item->setText( mNoteEditDlg->title() );
    journal->setDescription( mNoteEditDlg->text() );
    mManager->save();
  }
}

void KNotesPart::renameNote()
{
  mNotesView->currentItem()->rename();
}

void KNotesPart::renamedNote( QIconViewItem* )
{
  mManager->save();
}

void KNotesPart::slotOnCurrentChanged( QIconViewItem* )
{
  KAction *renameAction = actionCollection()->action( "edit_rename" );
  KAction *deleteAction = actionCollection()->action( "edit_delete" );

  if ( !mNotesView->currentItem() ) {
    renameAction->setEnabled( false );
    deleteAction->setEnabled( false );
  } else {
    renameAction->setEnabled( true );
    deleteAction->setEnabled( true );
  }
}

#include "knotes_part.moc"
#include "knotes_part_p.moc"

<|endoftext|>


<commit_before>// -------------------------------------------------------------------------
//    @FileName         :   NFCNPCRefreshModule.cpp
//    @Author               :    LvSheng.Huang
//    @Date                 :    2013-10-17
//    @Module               :    NFCNPCRefreshModule

// -------------------------------------------------------------------------

#include "NFCNPCRefreshModule.h"

bool NFCNPCRefreshModule::Init()
{
    return true;
}

bool NFCNPCRefreshModule::Shut()
{
    return true;
}

bool NFCNPCRefreshModule::Execute()
{
    return true;
}

bool NFCNPCRefreshModule::AfterInit()
{
	m_pScheduleModule = pPluginManager->FindModule<NFIScheduleModule>();
	m_pEventModule = pPluginManager->FindModule<NFIEventModule>();
    m_pKernelModule = pPluginManager->FindModule<NFIKernelModule>();
    m_pSceneProcessModule = pPluginManager->FindModule<NFISceneProcessModule>();
    m_pElementModule = pPluginManager->FindModule<NFIElementModule>();
	m_pPackModule = pPluginManager->FindModule<NFIPackModule>();
	m_pLogModule = pPluginManager->FindModule<NFILogModule>();
	m_pLevelModule = pPluginManager->FindModule<NFILevelModule>();
	m_pHeroPropertyModule = pPluginManager->FindModule<NFIHeroPropertyModule>();

	m_pKernelModule->AddClassCallBack(NFrame::NPC::ThisName(), this, &NFCNPCRefreshModule::OnObjectClassEvent);

    return true;
}

int NFCNPCRefreshModule::OnObjectClassEvent( const NFGUID& self, const std::string& strClassName, const CLASS_OBJECT_EVENT eClassEvent, const NFIDataList& var )
{
    NF_SHARE_PTR<NFIObject> pSelf = m_pKernelModule->GetObject(self);
    if (nullptr == pSelf)
    {
        return 1;
    }

    if (strClassName == NFrame::NPC::ThisName())
    {
        if ( CLASS_OBJECT_EVENT::COE_CREATE_LOADDATA == eClassEvent )
        {
            const std::string& strConfigIndex = m_pKernelModule->GetPropertyString(self, NFrame::NPC::ConfigID());
			const std::string& strPropertyID = m_pElementModule->GetPropertyString(strConfigIndex, NFrame::NPC::EffectData());
			const int nNPCType = m_pElementModule->GetPropertyInt(strConfigIndex, NFrame::NPC::NPCType());
			NF_SHARE_PTR<NFIPropertyManager> pSelfPropertyManager = pSelf->GetPropertyManager();

			if (nNPCType == NFMsg::ENPCType::ENPCTYPE_HERO)
			{
				//hero
				NFGUID xMasterID = m_pKernelModule->GetPropertyObject(self, NFrame::NPC::MasterID());
				NF_SHARE_PTR<NFIRecord> pHeroPropertyRecord = m_pKernelModule->FindRecord(xMasterID, NFrame::Player::R_HeroPropertyValue());
				if (pHeroPropertyRecord)
				{
					NFCDataList xHeroPropertyList;
					if (m_pHeroPropertyModule->CalHeroAllProperty(xMasterID, self, xHeroPropertyList))
					{
						for (int i = 0; i < pHeroPropertyRecord->GetCols(); ++i)
						{
							const std::string& strColTag = pHeroPropertyRecord->GetColTag(i);
							const int nValue = xHeroPropertyList.Int(i);
							pSelfPropertyManager->SetPropertyInt(strColTag, nValue);
						}
					}
				}
			}
			else
			{
				//normal npc
				NF_SHARE_PTR<NFIPropertyManager> pConfigPropertyManager = m_pElementModule->GetPropertyManager(strPropertyID);
				if (pConfigPropertyManager)
				{
					std::string strProperName;
					for (NFIProperty* pProperty = pConfigPropertyManager->FirstNude(strProperName); pProperty != NULL; pProperty = pConfigPropertyManager->NextNude(strProperName))
					{
						if (pSelfPropertyManager && strProperName != NFrame::NPC::ID())
						{
							pSelfPropertyManager->SetProperty(pProperty->GetKey(), pProperty->GetValue());
						}
					}
				}
			}

        }
        else if ( CLASS_OBJECT_EVENT::COE_CREATE_HASDATA == eClassEvent )
        {
            const std::string& strConfigID = m_pKernelModule->GetPropertyString(self, NFrame::NPC::ConfigID());
            int nHPMax = m_pElementModule->GetPropertyInt(strConfigID, NFrame::NPC::MAXHP());

            m_pKernelModule->SetPropertyInt(self, NFrame::NPC::HP(), nHPMax);
            m_pKernelModule->AddPropertyCallBack( self, NFrame::NPC::HP(), this, &NFCNPCRefreshModule::OnObjectHPEvent );

			m_pEventModule->AddEventCallBack( self, NFED_ON_OBJECT_BE_KILLED, this, &NFCNPCRefreshModule::OnObjectBeKilled );
        }
    }

    return 0;
}

int NFCNPCRefreshModule::OnObjectHPEvent( const NFGUID& self, const std::string& strPropertyName, const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar)
{
    if ( newVar.GetInt() <= 0 )
    {
        NFGUID identAttacker = m_pKernelModule->GetPropertyObject( self, NFrame::NPC::LastAttacker());
        if (!identAttacker.IsNull())
		{
			m_pEventModule->DoEvent( self, NFED_ON_OBJECT_BE_KILLED, NFCDataList() << identAttacker );

			m_pScheduleModule->AddSchedule( self, "OnDeadDestroyHeart", this, &NFCNPCRefreshModule::OnDeadDestroyHeart, 5.0f, 1 );
        }
    }

    return 0;
}

int NFCNPCRefreshModule::OnDeadDestroyHeart( const NFGUID& self, const std::string& strHeartBeat, const float fTime, const int nCount)
{
    //and create new object
    const std::string& strClassName = m_pKernelModule->GetPropertyString( self, NFrame::NPC::ClassName());
    const std::string& strSeedID = m_pKernelModule->GetPropertyString( self, NFrame::NPC::SeedID());
    const std::string& strConfigID = m_pKernelModule->GetPropertyString( self, NFrame::NPC::ConfigID());
    int nSceneID = m_pKernelModule->GetPropertyInt( self, NFrame::NPC::SceneID());
    int nGroupID = m_pKernelModule->GetPropertyInt( self, NFrame::NPC::GroupID());

    //m_pSceneProcessModule->ClearAll( nSceneID, nGroupID, strSeendID );

	float fSeedX = m_pKernelModule->GetPropertyFloat( self, NFrame::NPC::X());
	float fSeedY = m_pKernelModule->GetPropertyFloat( self, NFrame::NPC::Y());
	float fSeedZ = m_pKernelModule->GetPropertyFloat( self, NFrame::NPC::Z());

    m_pKernelModule->DestroyObject( self );

    NFCDataList arg;
	arg << NFrame::NPC::X() << fSeedX;
    arg << NFrame::NPC::Y() << fSeedY;
    arg << NFrame::NPC::Z() << fSeedZ;
	arg << NFrame::NPC::SeedID() << strSeedID;

	m_pKernelModule->CreateObject( NFGUID(), nSceneID, nGroupID, strClassName, strConfigID, arg );

    return 0;
}

int NFCNPCRefreshModule::OnObjectBeKilled( const NFGUID& self, const NFEventDefine nEventID, const NFIDataList& var )
{
	if ( var.GetCount() == 1 && var.Type( 0 ) == TDATA_OBJECT )
	{
		NFGUID identKiller = var.Object( 0 );
		if ( m_pKernelModule->GetObject( identKiller ) )
		{
			const int nExp = m_pKernelModule->GetPropertyInt( self, NFrame::Player::EXP() );

			m_pLevelModule->AddExp( identKiller, nExp);

			m_pLogModule->LogNormal(NFILogModule::NLL_INFO_NORMAL, identKiller, "Add Exp for kill monster", nExp);
		}
		else
		{
			m_pLogModule->LogObject(NFILogModule::NLL_ERROR_NORMAL, identKiller, "There is no object", __FUNCTION__, __LINE__);
		}
	}

	return 0;
}<commit_msg>remove unused code<commit_after>// -------------------------------------------------------------------------
//    @FileName         :   NFCNPCRefreshModule.cpp
//    @Author               :    LvSheng.Huang
//    @Date                 :    2013-10-17
//    @Module               :    NFCNPCRefreshModule

// -------------------------------------------------------------------------

#include "NFCNPCRefreshModule.h"

bool NFCNPCRefreshModule::Init()
{
    return true;
}

bool NFCNPCRefreshModule::Shut()
{
    return true;
}

bool NFCNPCRefreshModule::Execute()
{
    return true;
}

bool NFCNPCRefreshModule::AfterInit()
{
	m_pScheduleModule = pPluginManager->FindModule<NFIScheduleModule>();
	m_pEventModule = pPluginManager->FindModule<NFIEventModule>();
    m_pKernelModule = pPluginManager->FindModule<NFIKernelModule>();
    m_pSceneProcessModule = pPluginManager->FindModule<NFISceneProcessModule>();
    m_pElementModule = pPluginManager->FindModule<NFIElementModule>();
	m_pPackModule = pPluginManager->FindModule<NFIPackModule>();
	m_pLogModule = pPluginManager->FindModule<NFILogModule>();
	m_pLevelModule = pPluginManager->FindModule<NFILevelModule>();
	m_pHeroPropertyModule = pPluginManager->FindModule<NFIHeroPropertyModule>();

	m_pKernelModule->AddClassCallBack(NFrame::NPC::ThisName(), this, &NFCNPCRefreshModule::OnObjectClassEvent);

    return true;
}

int NFCNPCRefreshModule::OnObjectClassEvent( const NFGUID& self, const std::string& strClassName, const CLASS_OBJECT_EVENT eClassEvent, const NFIDataList& var )
{
    NF_SHARE_PTR<NFIObject> pSelf = m_pKernelModule->GetObject(self);
    if (nullptr == pSelf)
    {
        return 1;
    }

    if (strClassName == NFrame::NPC::ThisName())
    {
        if ( CLASS_OBJECT_EVENT::COE_CREATE_LOADDATA == eClassEvent )
        {
            const std::string& strConfigIndex = m_pKernelModule->GetPropertyString(self, NFrame::NPC::ConfigID());
			const std::string& strPropertyID = m_pElementModule->GetPropertyString(strConfigIndex, NFrame::NPC::EffectData());
			const int nNPCType = m_pElementModule->GetPropertyInt(strConfigIndex, NFrame::NPC::NPCType());
			NF_SHARE_PTR<NFIPropertyManager> pSelfPropertyManager = pSelf->GetPropertyManager();

			if (nNPCType == NFMsg::ENPCType::ENPCTYPE_HERO)
			{
				//hero
				NFGUID xMasterID = m_pKernelModule->GetPropertyObject(self, NFrame::NPC::MasterID());
				NF_SHARE_PTR<NFIRecord> pHeroPropertyRecord = m_pKernelModule->FindRecord(xMasterID, NFrame::Player::R_HeroPropertyValue());
				if (pHeroPropertyRecord)
				{
					NFCDataList xHeroPropertyList;
					if (m_pHeroPropertyModule->CalHeroAllProperty(xMasterID, self, xHeroPropertyList))
					{
						for (int i = 0; i < pHeroPropertyRecord->GetCols(); ++i)
						{
							const std::string& strColTag = pHeroPropertyRecord->GetColTag(i);
							const int nValue = xHeroPropertyList.Int(i);
							pSelfPropertyManager->SetPropertyInt(strColTag, nValue);
						}
					}
				}
			}
        }
        else if ( CLASS_OBJECT_EVENT::COE_CREATE_HASDATA == eClassEvent )
        {
            const std::string& strConfigID = m_pKernelModule->GetPropertyString(self, NFrame::NPC::ConfigID());
            int nHPMax = m_pElementModule->GetPropertyInt(strConfigID, NFrame::NPC::MAXHP());

            m_pKernelModule->SetPropertyInt(self, NFrame::NPC::HP(), nHPMax);

            m_pKernelModule->AddPropertyCallBack( self, NFrame::NPC::HP(), this, &NFCNPCRefreshModule::OnObjectHPEvent );
			m_pEventModule->AddEventCallBack( self, NFED_ON_OBJECT_BE_KILLED, this, &NFCNPCRefreshModule::OnObjectBeKilled );
        }
    }

    return 0;
}

int NFCNPCRefreshModule::OnObjectHPEvent( const NFGUID& self, const std::string& strPropertyName, const NFIDataList::TData& oldVar, const NFIDataList::TData& newVar)
{
    if ( newVar.GetInt() <= 0 )
    {
        NFGUID identAttacker = m_pKernelModule->GetPropertyObject( self, NFrame::NPC::LastAttacker());
        if (!identAttacker.IsNull())
		{
			m_pEventModule->DoEvent( self, NFED_ON_OBJECT_BE_KILLED, NFCDataList() << identAttacker );

			m_pScheduleModule->AddSchedule( self, "OnDeadDestroyHeart", this, &NFCNPCRefreshModule::OnDeadDestroyHeart, 5.0f, 1 );
        }
    }

    return 0;
}

int NFCNPCRefreshModule::OnDeadDestroyHeart( const NFGUID& self, const std::string& strHeartBeat, const float fTime, const int nCount)
{
    //and create new object
    const std::string& strClassName = m_pKernelModule->GetPropertyString( self, NFrame::NPC::ClassName());
    const std::string& strSeedID = m_pKernelModule->GetPropertyString( self, NFrame::NPC::SeedID());
    const std::string& strConfigID = m_pKernelModule->GetPropertyString( self, NFrame::NPC::ConfigID());
    int nSceneID = m_pKernelModule->GetPropertyInt( self, NFrame::NPC::SceneID());
    int nGroupID = m_pKernelModule->GetPropertyInt( self, NFrame::NPC::GroupID());

    //m_pSceneProcessModule->ClearAll( nSceneID, nGroupID, strSeendID );

	float fSeedX = m_pKernelModule->GetPropertyFloat( self, NFrame::NPC::X());
	float fSeedY = m_pKernelModule->GetPropertyFloat( self, NFrame::NPC::Y());
	float fSeedZ = m_pKernelModule->GetPropertyFloat( self, NFrame::NPC::Z());

    m_pKernelModule->DestroyObject( self );

    NFCDataList arg;
	arg << NFrame::NPC::X() << fSeedX;
    arg << NFrame::NPC::Y() << fSeedY;
    arg << NFrame::NPC::Z() << fSeedZ;
	arg << NFrame::NPC::SeedID() << strSeedID;

	m_pKernelModule->CreateObject( NFGUID(), nSceneID, nGroupID, strClassName, strConfigID, arg );

    return 0;
}

int NFCNPCRefreshModule::OnObjectBeKilled( const NFGUID& self, const NFEventDefine nEventID, const NFIDataList& var )
{
	if ( var.GetCount() == 1 && var.Type( 0 ) == TDATA_OBJECT )
	{
		NFGUID identKiller = var.Object( 0 );
		if ( m_pKernelModule->GetObject( identKiller ) )
		{
			const int nExp = m_pKernelModule->GetPropertyInt( self, NFrame::Player::EXP() );

			m_pLevelModule->AddExp( identKiller, nExp);

			m_pLogModule->LogNormal(NFILogModule::NLL_INFO_NORMAL, identKiller, "Add Exp for kill monster", nExp);
		}
		else
		{
			m_pLogModule->LogObject(NFILogModule::NLL_ERROR_NORMAL, identKiller, "There is no object", __FUNCTION__, __LINE__);
		}
	}

	return 0;
}<|endoftext|>


<commit_before>#include "hext/parser.h"

namespace hext {
namespace parser {

parse_error::parse_error(const char * msg)
: std::runtime_error(msg)
{
}

std::vector<rule>
parse_range(const char * begin, const char * end)
{
  lexer lex(begin, end);
  std::vector<token> tokens = lex.lex();
  std::vector<rule> rules;
  rule cur_rule;
  attribute cur_attr;
  int cur_level = 0;

  for( const auto& tok : tokens )
  {
    std::string tok_contents;
    if(
      tok.tok_begin != nullptr &&
      tok.tok_end   != nullptr &&
      tok.tok_begin != tok.tok_end
    )
    {
      assert(tok.tok_begin < tok.tok_end);
      tok_contents.append(tok.tok_begin, tok.tok_end);
    }

    // we expect the lexer to have catched all syntax errors
    // (famous last words)
    switch( tok.tid )
    {
      case TK_ERROR:
        throw parse_error("syntax error");
        break;
      case TK_INDENT:
        ++cur_level;
        break;
      case TK_RULE_BEGIN:
        break;
      case TK_TAG_NAME:
        cur_rule.set_tag_name(tok_contents);
        break;
      case TK_ATTR_NAME:
        cur_attr = attribute();
        cur_attr.set_name(tok_contents);
        cur_attr.set_is_builtin(
          tok_contents.compare(0, 5, "hext-") == 0
        );
        break;
      case TK_ATTR_LITERAL:
        cur_attr.set_is_capture(false);
        cur_attr.set_value(tok_contents);
        cur_rule.append_attribute(cur_attr);
        break;
      case TK_ATTR_CAPTURE:
        cur_attr.set_is_capture(true);
        cur_attr.set_value(tok_contents);
        cur_rule.append_attribute(cur_attr);
        break;
      case TK_RULE_END:
        if( cur_level == 0 || rules.empty() )
        {
          rules.push_back(cur_rule);
        }
        else
        {
          assert(!rules.empty());
          rules.back().append_child(cur_rule, cur_level);
        }
        cur_rule = rule();
        cur_level = 0;
        break;
      case TK_EOF:
        break;
      default:
        assert(false);
        break;
    }

  }

  return rules;
}

std::vector<rule>
parse_file(const char * path)
{
  std::ifstream in;
  in.open(path);

  std::string input(
    (std::istreambuf_iterator<char>(in)),
    std::istreambuf_iterator<char>()
  );
  const char * c_begin = input.c_str();
  const char * c_end = c_begin + input.size();

  return parse_range(c_begin, c_end);
}

} // namespace parser
} // namespace hext

<commit_msg>throw parse_error on unknown token<commit_after>#include "hext/parser.h"

namespace hext {
namespace parser {

parse_error::parse_error(const char * msg)
: std::runtime_error(msg)
{
}

std::vector<rule>
parse_range(const char * begin, const char * end)
{
  lexer lex(begin, end);
  std::vector<token> tokens = lex.lex();
  std::vector<rule> rules;
  rule cur_rule;
  attribute cur_attr;
  int cur_level = 0;

  for( const auto& tok : tokens )
  {
    std::string tok_contents;
    if(
      tok.tok_begin != nullptr &&
      tok.tok_end   != nullptr &&
      tok.tok_begin != tok.tok_end
    )
    {
      assert(tok.tok_begin < tok.tok_end);
      tok_contents.append(tok.tok_begin, tok.tok_end);
    }

    // we expect the lexer to have catched all syntax errors
    // (famous last words)
    switch( tok.tid )
    {
      case TK_ERROR:
        throw parse_error("syntax error");
        break;
      case TK_INDENT:
        ++cur_level;
        break;
      case TK_RULE_BEGIN:
        break;
      case TK_TAG_NAME:
        cur_rule.set_tag_name(tok_contents);
        break;
      case TK_ATTR_NAME:
        cur_attr = attribute();
        cur_attr.set_name(tok_contents);
        cur_attr.set_is_builtin(
          tok_contents.compare(0, 5, "hext-") == 0
        );
        break;
      case TK_ATTR_LITERAL:
        cur_attr.set_is_capture(false);
        cur_attr.set_value(tok_contents);
        cur_rule.append_attribute(cur_attr);
        break;
      case TK_ATTR_CAPTURE:
        cur_attr.set_is_capture(true);
        cur_attr.set_value(tok_contents);
        cur_rule.append_attribute(cur_attr);
        break;
      case TK_RULE_END:
        if( cur_level == 0 || rules.empty() )
        {
          rules.push_back(cur_rule);
        }
        else
        {
          assert(!rules.empty());
          rules.back().append_child(cur_rule, cur_level);
        }
        cur_rule = rule();
        cur_level = 0;
        break;
      case TK_EOF:
        break;
      default:
        throw parse_error("unknown token");
        break;
    }
  }

  return rules;
}

std::vector<rule>
parse_file(const char * path)
{
  std::ifstream in;
  in.open(path);

  std::string input(
    (std::istreambuf_iterator<char>(in)),
    std::istreambuf_iterator<char>()
  );
  const char * c_begin = input.c_str();
  const char * c_end = c_begin + input.size();

  return parse_range(c_begin, c_end);
}

} // namespace parser
} // namespace hext

<|endoftext|>


<commit_before>#include <windows.h>
#include "monitor.h"

bool
Monitor::get_workarea_from_point (POINT point, LPRECT lpworkarea)
{
  HMONITOR monitor = MonitorFromPoint (point, MONITOR_DEFAULTTOPRIMARY);
  return get_workarea_from_monitor (monitor, lpworkarea);
}

bool
Monitor::get_workarea_from_rect (LPCRECT lprc, LPRECT lpworkarea)
{
  HMONITOR monitor = MonitorFromRect (lprc, MONITOR_DEFAULTTOPRIMARY);
  return get_workarea_from_monitor (monitor, lpworkarea);
}

bool
Monitor::get_workarea_from_window (const HWND hwnd, LPRECT lpworkarea)
{
  HMONITOR monitor = MonitorFromWindow (hwnd, MONITOR_DEFAULTTOPRIMARY);
  return get_workarea_from_monitor (monitor, lpworkarea);
}

bool
Monitor::get_workarea_from_monitor (const HMONITOR& monitor, LPRECT lpworkarea)
{
  MONITORINFO info;
  memset (&info, 0, sizeof info);
  info.cbSize = sizeof info;
  if (!GetMonitorInfo(monitor, &info))
    return false;

  *lpworkarea = info.rcWork;
}

Monitor monitor;
<commit_msg>戻り値を返すのを忘れていたのを修正. #56<commit_after>#include <windows.h>
#include "monitor.h"

bool
Monitor::get_workarea_from_point (POINT point, LPRECT lpworkarea)
{
  HMONITOR monitor = MonitorFromPoint (point, MONITOR_DEFAULTTOPRIMARY);
  return get_workarea_from_monitor (monitor, lpworkarea);
}

bool
Monitor::get_workarea_from_rect (LPCRECT lprc, LPRECT lpworkarea)
{
  HMONITOR monitor = MonitorFromRect (lprc, MONITOR_DEFAULTTOPRIMARY);
  return get_workarea_from_monitor (monitor, lpworkarea);
}

bool
Monitor::get_workarea_from_window (const HWND hwnd, LPRECT lpworkarea)
{
  HMONITOR monitor = MonitorFromWindow (hwnd, MONITOR_DEFAULTTOPRIMARY);
  return get_workarea_from_monitor (monitor, lpworkarea);
}

bool
Monitor::get_workarea_from_monitor (const HMONITOR& monitor, LPRECT lpworkarea)
{
  MONITORINFO info;
  memset (&info, 0, sizeof info);
  info.cbSize = sizeof info;
  if (!GetMonitorInfo(monitor, &info))
    return false;

  *lpworkarea = info.rcWork;
  return true;
}

Monitor monitor;
<|endoftext|>


<commit_before>#include "DistanceCalculator.h"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

DistanceCalculator::DistanceCalculator(){
	loadConf();
}

void DistanceCalculator::loadConf(){
	using boost::property_tree::ptree;

	ptree pt;
	try{
		read_ini("distance_conf.ini", pt);
		int confKey = DistanceCalibrator::DISTANCE_CALIBRATOR_STEP;
		for (int i = 0; i < DistanceCalibrator::CONF_SIZE; i++){
			std::ostringstream key;
			key << confKey;
			realDistances[i] = confKey;
			references[i] = pt.get<double>(key.str());
			confKey += DistanceCalibrator::DISTANCE_CALIBRATOR_STEP;
		}
	}
	catch (...){};
}

double DistanceCalculator::getDistance(int centerX, int centerY, int x, int y){
	double dist = DistanceCalibrator::calculateDistance(centerX, centerY, x, y);
	double minDif = INT_MAX;
	int index = 0;
	for (int i = 0; i < DistanceCalibrator::CONF_SIZE; i++){
		double dif = std::abs(references[i] - dist);
		if (dif < minDif){
			index = i;
			minDif = dif;
		}
	}
	return realDistances[index]*4;
//#error get rid of this magic number
}
<commit_msg>smooth distance calculator<commit_after>#include "DistanceCalculator.h"
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/ini_parser.hpp>

DistanceCalculator::DistanceCalculator(){
	loadConf();
}

void DistanceCalculator::loadConf(){
	using boost::property_tree::ptree;

	ptree pt;
	try{
		read_ini("distance_conf.ini", pt);
		int confKey = DistanceCalibrator::DISTANCE_CALIBRATOR_STEP;
		for (int i = 0; i < DistanceCalibrator::CONF_SIZE; i++){
			std::ostringstream key;
			key << confKey;
			realDistances[i] = confKey;
			references[i] = pt.get<double>(key.str());
			confKey += DistanceCalibrator::DISTANCE_CALIBRATOR_STEP;
		}
	}
	catch (...){};
}

double DistanceCalculator::getDistance(int centerX, int centerY, int x, int y){
	double dist = DistanceCalibrator::calculateDistance(centerX, centerY, x, y);
	double minDif = INT_MAX;
	int index = 0;
	for (int i = 1; i < DistanceCalibrator::CONF_SIZE; i++){
		if (references[i] > dist) {
			double how_far_between_two_steps = (dist - references[i - 1]) / (references[i] - references[i - 1]);
			double realdist = realDistances[i - 1] + (realDistances[i] - realDistances[i - 1])*how_far_between_two_steps;
			std::cout << "distance " << dist << " -> " << realdist << std::endl;
			return 4*realdist;
		}
		/*
		double dif = std::abs(references[i] - dist);
		if (dif < minDif){
			index = i;
			minDif = dif;
		}
		*/
	}
	return realDistances[index]*4;
//#error get rid of this magic number
}
<|endoftext|>


<commit_before>/* EmulationDevice.cc - accessing accelerator memory as memory mapped region.

   Copyright (c) 2021 Pekka Jääskeläinen / Tampere University

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to
   deal in the Software without restriction, including without limitation the
   rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   sell copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.
*/

#include "EmulationDevice.h"

#include "EmulationRegion.h"
#include "accel-shared.h"

#include <unistd.h>
#include <iostream>

EmulationDevice::EmulationDevice() {

    // The principle of the emulator is that instead of mmapping a real
    // accelerator, we just allocate a regular array, which corresponds
    // to the mmap. The accel_emulate function is working in another thread
    // and will fill that array and respond to the driver asynchronously.
    // The driver doesn't really need to know about emulating except
    // in the initial mapping of the accelerator
    E.emulating_address = calloc(1, EMULATING_MAX_SIZE);
    assert(E.emulating_address != NULL && "Emulating calloc failed\n");

    // Create emulator thread
    E.emulate_exit_called = 0;
    E.emulate_init_done = 0;
    pthread_create(&emulate_thread, NULL, emulate_accel, &E);
    while (!E.emulate_init_done)
      ; // Wait for the thread to initialize
    POCL_MSG_PRINT_INFO("accel: started emulating\n");

    ControlMemory =
        new EmulationRegion((size_t)E.emulating_address, ACCEL_DEFAULT_CTRL_SIZE);

    discoverDeviceParameters();

    InstructionMemory = new EmulationRegion(imem_start, imem_size);
    CQMemory = new EmulationRegion(cq_start, cq_size);
    DataMemory = new EmulationRegion(dmem_start, dmem_size);
}

EmulationDevice::~EmulationDevice() {
    POCL_MSG_PRINT_INFO("accel: freeing emulated accel");
    E.emulate_exit_called = 1; // signal for the emulator to stop
    pthread_join(emulate_thread, NULL);
    free((void *)E.emulating_address); // from
                                        // calloc(emulating_address)
}

/*
 * AlmaIF v1 based accel emulator
 * Base_address is a preallocated emulation array that corresponds to the
 * memory map of the accelerator
 * Does operations 0,1,2,3,4
 * */
void *emulate_accel(void *E_void) {

  emulation_data_t *E = (emulation_data_t *)E_void;
  void *base_address = E->emulating_address;

  uint32_t ctrl_size = 1024;
  uint32_t imem_size = 0;
  uint32_t dmem_size = EMULATING_MAX_SIZE * 3 / 4;
  // The accelerator can choose the size of the queue (must be a power-of-two)
  // Can be even 1, to make the packet handling easiest with static offsets
  uint32_t queue_length = 3;
  uint32_t cqmem_size = (queue_length + 1) * AQL_PACKET_LENGTH;

  // The accelerator can set the starting addresses
  // Even the order can be changed if the accelerator wants to
  // Here packing the memory regions tighly as an example.
  uintptr_t imem_start = (uintptr_t)base_address + ctrl_size;
  uintptr_t cqmem_start = imem_start + imem_size;
  uintptr_t dmem_start = cqmem_start + cqmem_size;

  volatile uint32_t *Control = (uint32_t *)base_address;
  volatile uint8_t *Instruction = (uint8_t *)imem_start;
  volatile uint32_t *CQ = (uint32_t *)cqmem_start;
  volatile uint8_t *Data = (uint8_t *)dmem_start;

  // Set initial values for info registers:
  Control[ACCEL_INFO_DEV_CLASS / 4] = 0xE; // Unused
  Control[ACCEL_INFO_DEV_ID / 4] = 0;      // Unused
  Control[ACCEL_INFO_IF_TYPE / 4] = 3;
  Control[ACCEL_INFO_CORE_COUNT / 4] = 1;
  Control[ACCEL_INFO_CTRL_SIZE / 4] = 1024;

#define PTR_SIZE sizeof(uint32_t *)
  Control[ACCEL_INFO_PTR_SIZE / 4] = PTR_SIZE;

  // The emulation doesn't use Instruction/Configuration memory. This memory
  // space is a place to write accelerator specific configuration values
  // that are written BEFORE hw reset is deasserted.
  // E.g. program binaries of a processor-based accelerator
  Control[ACCEL_INFO_IMEM_SIZE / 4] = 0;
  Control[ACCEL_INFO_IMEM_START_LOW / 4] = (uint32_t)imem_start;
  Control[ACCEL_INFO_IMEM_START_HIGH / 4] = (uint32_t)(imem_start >> 32);

  Control[ACCEL_INFO_CQMEM_SIZE_LOW / 4] = cqmem_size;
  Control[ACCEL_INFO_CQMEM_START_LOW / 4] = (uint32_t)cqmem_start;
  Control[ACCEL_INFO_CQMEM_START_HIGH / 4] = (uint32_t)(cqmem_start >> 32);

  Control[ACCEL_INFO_DMEM_SIZE_LOW / 4] = dmem_size;
  Control[ACCEL_INFO_DMEM_START_LOW / 4] = (uint32_t)dmem_start;
  Control[ACCEL_INFO_DMEM_START_HIGH / 4] = (uint32_t)(dmem_start >> 32);

  uint32_t feature_flags_low = ACCEL_FF_BIT_AXI_MASTER;
  Control[ACCEL_INFO_FEATURE_FLAGS_LOW / 4] = feature_flags_low;

  // Signal the driver that the initial values are set
  // (in hardware this signal is probably not needed, since the values are
  // initialized in hw reset)
  E->emulate_init_done = 1;
  POCL_MSG_PRINT_INFO("accel emulate: Emulator initialized");

  int read_iter = 0;
  CQ[ACCEL_CQ_READ / 4] = read_iter;
  CQ[ACCEL_CQ_LENGTH / 4] = queue_length;

  // Accelerator is in infinite loop to process the commands
  // For emulating purposes we include the exit signal that the driver can
  // use to terminate the emulating thread. In hw this could be
  // a while(1) loop.
  while (!E->emulate_exit_called) {

    // Don't start computing anything before soft reset is lifted.
    // (This could probably be outside of the loop)
    int reset = Control[ACCEL_CONTROL_REG_COMMAND / 4];
    if (reset != ACCEL_CONTINUE_CMD) {
      continue;
    }

    // Compute packet location
    uint32_t packet_loc = ((read_iter % queue_length) + 1) * AQL_PACKET_LENGTH;
    struct AQLDispatchPacket *packet =
        (struct AQLDispatchPacket *)(CQ + packet_loc/4);

    // The driver will mark the packet as not INVALID when it wants us to
    // compute it
    if (packet->header == AQL_PACKET_INVALID) {
      continue;
    }

    uint16_t header = packet->header;
    if (header & (1 << AQL_PACKET_BARRIER_AND)) {
      struct AQLAndPacket *andPacket = (struct AQLAndPacket *)packet;
      POCL_MSG_PRINT_INFO("accel emulate: Found valid AND packet from location "
                          "%u, starting parsing:",
                          packet_loc);
      for (int i = 0; i < AQL_MAX_SIGNAL_COUNT; i++) {
        uint32_t *signal = (uint32_t *)(andPacket->dep_signals[i]);
        if (signal != NULL) {
          while (*signal == 0) {
            usleep(100);
          }
        }
      }
      POCL_MSG_PRINT_INFO("accel emulate: And packet done\n");
    }
    else if (header & (1 << AQL_PACKET_KERNEL_DISPATCH)) {
      POCL_MSG_PRINT_INFO("accel emulate: Found valid kernel dispatch packet from location "
                          "%u, starting parsing:",
                          packet_loc);
      POCL_MSG_PRINT_INFO("accel emulate: kernargs are at 0x%zx\n",
                          packet->kernarg_address);
      // Find the 3 pointers
      // Pointer size can be different on different systems
      // Also the endianness might need some attention in the real case.

      union args_u {
        uint32_t *ptrs[3];
        uint8_t values[3 * PTR_SIZE];
      } args;
      for (int i = 0; i < 3; i++) {
        for (int k = 0; k < PTR_SIZE; k++) {
          args.values[PTR_SIZE * i + k] =
              *(uint8_t *)(packet->kernarg_address + PTR_SIZE * i + k);
        }
      }
      uint32_t *arg0 = args.ptrs[0];
      uint32_t *arg1 = args.ptrs[1];
      uint32_t *arg2 = args.ptrs[2];

      POCL_MSG_PRINT_INFO("accel emulate: FOUND args arg0=%p, arg1=%p, arg2=%p\n",
                          arg0, arg1, arg2);

      // Check how many dimensions are in use, and set the unused ones to 1.
      int dim_x = packet->grid_size_x;
      int dim_y = (packet->dimensions >= 2) ? (packet->grid_size_y) : 1;
      int dim_z = (packet->dimensions == 3) ? (packet->grid_size_z) : 1;

      int red_count = 0;
      POCL_MSG_PRINT_INFO(
          "accel emulate: Parsing done: starting loops with dims (%i,%i,%i)",
          dim_x, dim_y, dim_z);
      for (int x = 0; x < dim_x; x++) {
        for (int y = 0; y < dim_y; y++) {
          for (int z = 0; z < dim_z; z++) {
            // Linearize grid
            int idx = x * dim_y * dim_z + y * dim_z + z;
            // Do the operation based on the kernel_object (integer id)
            switch (packet->kernel_object) {
            case (POCL_CDBI_COPY_I8):
              arg1[idx] = arg0[idx];
              break;
            case (POCL_CDBI_ADD_I32):
              arg2[idx] = arg0[idx] + arg1[idx];
              break;
            case (POCL_CDBI_MUL_I32):
              arg2[idx] = arg0[idx] * arg1[idx];
              break;
            case (POCL_CDBI_COUNTRED):
              uint32_t pixel = arg0[idx];
              uint8_t pixel_r = pixel & 0xFF;
              if (pixel_r > 100) {
                red_count++;
              }
            }
          }
        }
      }
      if (packet->kernel_object == POCL_CDBI_LEDBLINK) {
        std::cout << "Emulation blinking " << dim_x << " led(s) at interval "
                  << arg0[0] << " us " << arg1[0] << " times" << std::endl;
      }
      if (packet->kernel_object == POCL_CDBI_COUNTRED) {
        arg1[0] = red_count;
      }

      POCL_MSG_PRINT_INFO("accel emulate: Kernel done");
    }

    // Completion signal is given as absolute address
    if (packet->completion_signal) {
      *(uint32_t *)packet->completion_signal = 1;
    }
    packet->header = AQL_PACKET_INVALID;

    read_iter++; // move on to the next AQL packet
    CQ[ACCEL_CQ_READ / 4] = read_iter;
  }

  return NULL;
}
<commit_msg>emulation device: sleep if there's nothing to do<commit_after>/* EmulationDevice.cc - accessing accelerator memory as memory mapped region.

   Copyright (c) 2021 Pekka Jääskeläinen / Tampere University

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to
   deal in the Software without restriction, including without limitation the
   rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   sell copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.
*/

#include "EmulationDevice.h"

#include "EmulationRegion.h"
#include "accel-shared.h"

#include <unistd.h>
#include <iostream>

EmulationDevice::EmulationDevice() {

    // The principle of the emulator is that instead of mmapping a real
    // accelerator, we just allocate a regular array, which corresponds
    // to the mmap. The accel_emulate function is working in another thread
    // and will fill that array and respond to the driver asynchronously.
    // The driver doesn't really need to know about emulating except
    // in the initial mapping of the accelerator
    E.emulating_address = calloc(1, EMULATING_MAX_SIZE);
    assert(E.emulating_address != NULL && "Emulating calloc failed\n");

    // Create emulator thread
    E.emulate_exit_called = 0;
    E.emulate_init_done = 0;
    pthread_create(&emulate_thread, NULL, emulate_accel, &E);
    while (!E.emulate_init_done)
      ; // Wait for the thread to initialize
    POCL_MSG_PRINT_INFO("accel: started emulating\n");

    ControlMemory =
        new EmulationRegion((size_t)E.emulating_address, ACCEL_DEFAULT_CTRL_SIZE);

    discoverDeviceParameters();

    InstructionMemory = new EmulationRegion(imem_start, imem_size);
    CQMemory = new EmulationRegion(cq_start, cq_size);
    DataMemory = new EmulationRegion(dmem_start, dmem_size);
}

EmulationDevice::~EmulationDevice() {
    POCL_MSG_PRINT_INFO("accel: freeing emulated accel");
    E.emulate_exit_called = 1; // signal for the emulator to stop
    pthread_join(emulate_thread, NULL);
    free((void *)E.emulating_address); // from
                                        // calloc(emulating_address)
}

/*
 * AlmaIF v1 based accel emulator
 * Base_address is a preallocated emulation array that corresponds to the
 * memory map of the accelerator
 * Does operations 0,1,2,3,4
 * */
void *emulate_accel(void *E_void) {

  emulation_data_t *E = (emulation_data_t *)E_void;
  void *base_address = E->emulating_address;

  uint32_t ctrl_size = 1024;
  uint32_t imem_size = 0;
  uint32_t dmem_size = EMULATING_MAX_SIZE * 3 / 4;
  // The accelerator can choose the size of the queue (must be a power-of-two)
  // Can be even 1, to make the packet handling easiest with static offsets
  uint32_t queue_length = 3;
  uint32_t cqmem_size = (queue_length + 1) * AQL_PACKET_LENGTH;

  // The accelerator can set the starting addresses
  // Even the order can be changed if the accelerator wants to
  // Here packing the memory regions tighly as an example.
  uintptr_t imem_start = (uintptr_t)base_address + ctrl_size;
  uintptr_t cqmem_start = imem_start + imem_size;
  uintptr_t dmem_start = cqmem_start + cqmem_size;

  volatile uint32_t *Control = (uint32_t *)base_address;
  volatile uint8_t *Instruction = (uint8_t *)imem_start;
  volatile uint32_t *CQ = (uint32_t *)cqmem_start;
  volatile uint8_t *Data = (uint8_t *)dmem_start;

  // Set initial values for info registers:
  Control[ACCEL_INFO_DEV_CLASS / 4] = 0xE; // Unused
  Control[ACCEL_INFO_DEV_ID / 4] = 0;      // Unused
  Control[ACCEL_INFO_IF_TYPE / 4] = 3;
  Control[ACCEL_INFO_CORE_COUNT / 4] = 1;
  Control[ACCEL_INFO_CTRL_SIZE / 4] = 1024;

#define PTR_SIZE sizeof(uint32_t *)
  Control[ACCEL_INFO_PTR_SIZE / 4] = PTR_SIZE;

  // The emulation doesn't use Instruction/Configuration memory. This memory
  // space is a place to write accelerator specific configuration values
  // that are written BEFORE hw reset is deasserted.
  // E.g. program binaries of a processor-based accelerator
  Control[ACCEL_INFO_IMEM_SIZE / 4] = 0;
  Control[ACCEL_INFO_IMEM_START_LOW / 4] = (uint32_t)imem_start;
  Control[ACCEL_INFO_IMEM_START_HIGH / 4] = (uint32_t)(imem_start >> 32);

  Control[ACCEL_INFO_CQMEM_SIZE_LOW / 4] = cqmem_size;
  Control[ACCEL_INFO_CQMEM_START_LOW / 4] = (uint32_t)cqmem_start;
  Control[ACCEL_INFO_CQMEM_START_HIGH / 4] = (uint32_t)(cqmem_start >> 32);

  Control[ACCEL_INFO_DMEM_SIZE_LOW / 4] = dmem_size;
  Control[ACCEL_INFO_DMEM_START_LOW / 4] = (uint32_t)dmem_start;
  Control[ACCEL_INFO_DMEM_START_HIGH / 4] = (uint32_t)(dmem_start >> 32);

  uint32_t feature_flags_low = ACCEL_FF_BIT_AXI_MASTER;
  Control[ACCEL_INFO_FEATURE_FLAGS_LOW / 4] = feature_flags_low;

  // Signal the driver that the initial values are set
  // (in hardware this signal is probably not needed, since the values are
  // initialized in hw reset)
  E->emulate_init_done = 1;
  POCL_MSG_PRINT_INFO("accel emulate: Emulator initialized");

  int read_iter = 0;
  CQ[ACCEL_CQ_READ / 4] = read_iter;
  CQ[ACCEL_CQ_LENGTH / 4] = queue_length;

  // Accelerator is in infinite loop to process the commands
  // For emulating purposes we include the exit signal that the driver can
  // use to terminate the emulating thread. In hw this could be
  // a while(1) loop.
  while (!E->emulate_exit_called) {

    // Don't start computing anything before soft reset is lifted.
    // (This could probably be outside of the loop)
    int reset = Control[ACCEL_CONTROL_REG_COMMAND / 4];
    if (reset != ACCEL_CONTINUE_CMD) {
      usleep(2000);
      continue;
    }

    // Compute packet location
    uint32_t packet_loc = ((read_iter % queue_length) + 1) * AQL_PACKET_LENGTH;
    struct AQLDispatchPacket *packet =
        (struct AQLDispatchPacket *)(CQ + packet_loc/4);

    // The driver will mark the packet as not INVALID when it wants us to
    // compute it
    if (packet->header == AQL_PACKET_INVALID) {
      usleep(2000);
      continue;
    }

    uint16_t header = packet->header;
    if (header & (1 << AQL_PACKET_BARRIER_AND)) {
      struct AQLAndPacket *andPacket = (struct AQLAndPacket *)packet;
      POCL_MSG_PRINT_INFO("accel emulate: Found valid AND packet from location "
                          "%u, starting parsing:",
                          packet_loc);
      for (int i = 0; i < AQL_MAX_SIGNAL_COUNT; i++) {
        uint32_t *signal = (uint32_t *)(andPacket->dep_signals[i]);
        if (signal != NULL) {
          while (*signal == 0) {
            usleep(100);
          }
        }
      }
      POCL_MSG_PRINT_INFO("accel emulate: And packet done\n");
    }
    else if (header & (1 << AQL_PACKET_KERNEL_DISPATCH)) {
      POCL_MSG_PRINT_INFO("accel emulate: Found valid kernel dispatch packet from location "
                          "%u, starting parsing:",
                          packet_loc);
      POCL_MSG_PRINT_INFO("accel emulate: kernargs are at 0x%zx\n",
                          packet->kernarg_address);
      // Find the 3 pointers
      // Pointer size can be different on different systems
      // Also the endianness might need some attention in the real case.

      union args_u {
        uint32_t *ptrs[3];
        uint8_t values[3 * PTR_SIZE];
      } args;
      for (int i = 0; i < 3; i++) {
        for (int k = 0; k < PTR_SIZE; k++) {
          args.values[PTR_SIZE * i + k] =
              *(uint8_t *)(packet->kernarg_address + PTR_SIZE * i + k);
        }
      }
      uint32_t *arg0 = args.ptrs[0];
      uint32_t *arg1 = args.ptrs[1];
      uint32_t *arg2 = args.ptrs[2];

      POCL_MSG_PRINT_INFO("accel emulate: FOUND args arg0=%p, arg1=%p, arg2=%p\n",
                          arg0, arg1, arg2);

      // Check how many dimensions are in use, and set the unused ones to 1.
      int dim_x = packet->grid_size_x;
      int dim_y = (packet->dimensions >= 2) ? (packet->grid_size_y) : 1;
      int dim_z = (packet->dimensions == 3) ? (packet->grid_size_z) : 1;

      int red_count = 0;
      POCL_MSG_PRINT_INFO(
          "accel emulate: Parsing done: starting loops with dims (%i,%i,%i)",
          dim_x, dim_y, dim_z);
      for (int x = 0; x < dim_x; x++) {
        for (int y = 0; y < dim_y; y++) {
          for (int z = 0; z < dim_z; z++) {
            // Linearize grid
            int idx = x * dim_y * dim_z + y * dim_z + z;
            // Do the operation based on the kernel_object (integer id)
            switch (packet->kernel_object) {
            case (POCL_CDBI_COPY_I8):
              arg1[idx] = arg0[idx];
              break;
            case (POCL_CDBI_ADD_I32):
              arg2[idx] = arg0[idx] + arg1[idx];
              break;
            case (POCL_CDBI_MUL_I32):
              arg2[idx] = arg0[idx] * arg1[idx];
              break;
            case (POCL_CDBI_COUNTRED):
              uint32_t pixel = arg0[idx];
              uint8_t pixel_r = pixel & 0xFF;
              if (pixel_r > 100) {
                red_count++;
              }
            }
          }
        }
      }
      if (packet->kernel_object == POCL_CDBI_LEDBLINK) {
        std::cout << "Emulation blinking " << dim_x << " led(s) at interval "
                  << arg0[0] << " us " << arg1[0] << " times" << std::endl;
      }
      if (packet->kernel_object == POCL_CDBI_COUNTRED) {
        arg1[0] = red_count;
      }

      POCL_MSG_PRINT_INFO("accel emulate: Kernel done");
    }

    // Completion signal is given as absolute address
    if (packet->completion_signal) {
      *(uint32_t *)packet->completion_signal = 1;
    }
    packet->header = AQL_PACKET_INVALID;

    read_iter++; // move on to the next AQL packet
    CQ[ACCEL_CQ_READ / 4] = read_iter;
  }

  return NULL;
}
<|endoftext|>


<commit_before>#ifndef SIMDIFY
#define SIMDIFY

//
// C++, C++11 checks
//
#ifndef __cplusplus
#error "Simdify requires C++."
#endif

#if defined(_MSC_VER) && _MSC_VER < 1600
#error "Simdify requires Visual Studio 2010."
#endif

#if !defined(_MSC_VER) && __cplusplus < 201103L && !defined(__GXX_EXPERIMENTAL_CXX0X__)
#error "Simdify requires C++11. Please use the setting '-std=c++0x' or '-std=c++11'."
#endif

//
// fix MSVC borked SSE macros (ICC has got them right though)
//
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)

#if defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
#define __SSE__
#endif

#if defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
#define __SSE2__
#endif

#if defined(__AVX__)
#define __SSE3__
#define __SSSE3__
#define __SSE4_1__
#define __SSE4_2__
#endif // __AVX__

#endif // _MSC_VER

//
// include all supported SIMD types
// use the SIMDIFY_NEED_* macros to force the include
//
#if defined(__AVX__) || defined(SIMDIFY_NEED_AVX)
#include "impl/avx.hpp"
#endif

#if defined(__SSE2__) || defined(SIMDIFY_NEED_SSE)
#include "impl/sse.hpp"
#endif

#if 1 || defined(SIMDIFY_NEED_FLT)
#include "impl/flt.hpp"
#endif

//
// set some (successfully loaded) SIMD type as simd_t
// use SIMDIFY_PREFER_* to use a specific type
//
namespace simd {
#if defined(SIMDIFY_PREFER_AVX) && defined(SIMDIFY_AVX)
using simd_t = avx;
#elif defined(SIMDIFY_PREFER_SSE) && defined(SIMDIFY_SSE)
using simd_t = sse;
#elif defined(SIMDIFY_PREFER_FLT) && defined(SIMDIFY_FLT)
using simd_t = flt;
#elif defined(SIMDIFY_AVX)
using simd_t = avx;
#elif defined(SIMDIFY_SSE)
using simd_t = sse;
#elif defined(SIMDIFY_FLT)
using simd_t = flt;
#else
#error "Simdify could not determine a suitable SIMD type as simd_t."
#endif
}

#endif // SIMDIFY
<commit_msg>Added convenience shorthands simd::T, simd::W<commit_after>#ifndef SIMDIFY
#define SIMDIFY

//
// C++, C++11 checks
//
#ifndef __cplusplus
#error "Simdify requires C++."
#endif

#if defined(_MSC_VER) && _MSC_VER < 1600
#error "Simdify requires Visual Studio 2010."
#endif

#if !defined(_MSC_VER) && __cplusplus < 201103L && !defined(__GXX_EXPERIMENTAL_CXX0X__)
#error "Simdify requires C++11. Please use the setting '-std=c++0x' or '-std=c++11'."
#endif

//
// fix MSVC borked SSE macros (ICC has got them right though)
//
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)

#if defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1)
#define __SSE__
#endif

#if defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 2)
#define __SSE2__
#endif

#if defined(__AVX__)
#define __SSE3__
#define __SSSE3__
#define __SSE4_1__
#define __SSE4_2__
#endif // __AVX__

#endif // _MSC_VER

//
// include all supported SIMD types
// use the SIMDIFY_NEED_* macros to force the include
//
#if defined(__AVX__) || defined(SIMDIFY_NEED_AVX)
#include "impl/avx.hpp"
#endif

#if defined(__SSE2__) || defined(SIMDIFY_NEED_SSE)
#include "impl/sse.hpp"
#endif

#if 1 || defined(SIMDIFY_NEED_FLT)
#include "impl/flt.hpp"
#endif

//
// set some (successfully loaded) SIMD type as simd_t
// use SIMDIFY_PREFER_* to use a specific type
//
namespace simd {
#if defined(SIMDIFY_PREFER_AVX) && defined(SIMDIFY_AVX)
    using simd_t = avx;
#elif defined(SIMDIFY_PREFER_SSE) && defined(SIMDIFY_SSE)
    using simd_t = sse;
#elif defined(SIMDIFY_PREFER_FLT) && defined(SIMDIFY_FLT)
    using simd_t = flt;
#elif defined(SIMDIFY_AVX)
    using simd_t = avx;
#elif defined(SIMDIFY_SSE)
    using simd_t = sse;
#elif defined(SIMDIFY_FLT)
    using simd_t = flt;
#else
#error "Simdify could not determine a suitable SIMD type as simd_t."
#endif

    //
    // convenience shorthands
    //
    using T = simd_t;
    const auto W = simd_t::W;

}

#endif // SIMDIFY
<|endoftext|>


<commit_before>//===- ExecutionEngine.cpp - MLIR Execution engine and utils --------------===//
//
// Copyright 2019 The MLIR Authors.
//
// 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.
// =============================================================================
//
// This file implements the execution engine for MLIR modules based on LLVM Orc
// JIT engine.
//
//===----------------------------------------------------------------------===//
#include "mlir/ExecutionEngine/ExecutionEngine.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/Module.h"
#include "mlir/LLVMIR/Transforms.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Transforms/Passes.h"

#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/TargetRegistry.h"

using namespace mlir;
using llvm::Error;
using llvm::Expected;

namespace {
// Memory manager for the JIT's objectLayer.  Its main goal is to fallback to
// resolving functions in the current process if they cannot be resolved in the
// JIT-compiled modules.
class MemoryManager : public llvm::SectionMemoryManager {
public:
  MemoryManager(llvm::orc::ExecutionSession &execSession)
      : session(execSession) {}

  // Resolve the named symbol.  First, try looking it up in the main library of
  // the execution session.  If there is no such symbol, try looking it up in
  // the current process (for example, if it is a standard library function).
  // Return `nullptr` if lookup fails.
  llvm::JITSymbol findSymbol(const std::string &name) override {
    auto mainLibSymbol = session.lookup({&session.getMainJITDylib()}, name);
    if (mainLibSymbol)
      return mainLibSymbol.get();
    auto address = llvm::RTDyldMemoryManager::getSymbolAddressInProcess(name);
    if (!address) {
      llvm::errs() << "Could not look up: " << name << '\n';
      return nullptr;
    }
    return llvm::JITSymbol(address, llvm::JITSymbolFlags::Exported);
  }

private:
  llvm::orc::ExecutionSession &session;
};
} // end anonymous namespace

namespace mlir {
namespace impl {
// Simple layered Orc JIT compilation engine.
class OrcJIT {
public:
  using IRTransformer = std::function<Error(llvm::Module *)>;

  // Construct a JIT engine for the target host defined by `machineBuilder`,
  // using the data layout provided as `dataLayout`.
  // Setup the object layer to use our custom memory manager in order to resolve
  // calls to library functions present in the process.
  OrcJIT(llvm::orc::JITTargetMachineBuilder machineBuilder,
         llvm::DataLayout layout, IRTransformer transform)
      : irTransformer(transform),
        objectLayer(
            session,
            [this]() { return llvm::make_unique<MemoryManager>(session); }),
        compileLayer(
            session, objectLayer,
            llvm::orc::ConcurrentIRCompiler(std::move(machineBuilder))),
        transformLayer(session, compileLayer, makeIRTransformFunction()),
        dataLayout(layout), mangler(session, this->dataLayout),
        threadSafeCtx(llvm::make_unique<llvm::LLVMContext>()) {
    session.getMainJITDylib().setGenerator(
        cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
            layout)));
  }

  // Create a JIT engine for the current host.
  static Expected<std::unique_ptr<OrcJIT>>
  createDefault(IRTransformer transformer) {
    auto machineBuilder = llvm::orc::JITTargetMachineBuilder::detectHost();
    if (!machineBuilder)
      return machineBuilder.takeError();

    auto dataLayout = machineBuilder->getDefaultDataLayoutForTarget();
    if (!dataLayout)
      return dataLayout.takeError();

    return llvm::make_unique<OrcJIT>(std::move(*machineBuilder),
                                     std::move(*dataLayout), transformer);
  }

  // Add an LLVM module to the main library managed by the JIT engine.
  Error addModule(std::unique_ptr<llvm::Module> M) {
    return transformLayer.add(
        session.getMainJITDylib(),
        llvm::orc::ThreadSafeModule(std::move(M), threadSafeCtx));
  }

  // Lookup a symbol in the main library managed by the JIT engine.
  Expected<llvm::JITEvaluatedSymbol> lookup(StringRef Name) {
    return session.lookup({&session.getMainJITDylib()}, mangler(Name.str()));
  }

private:
  // Wrap the `irTransformer` into a function that can be called by the
  // IRTranformLayer.  If `irTransformer` is not set up, return the module as is
  // without errors.
  llvm::orc::IRTransformLayer::TransformFunction makeIRTransformFunction() {
    return [this](llvm::orc::ThreadSafeModule module,
                  const llvm::orc::MaterializationResponsibility &resp)
               -> Expected<llvm::orc::ThreadSafeModule> {
      (void)resp;
      if (!irTransformer)
        return std::move(module);
      if (Error err = irTransformer(module.getModule()))
        return std::move(err);
      return std::move(module);
    };
  }

  IRTransformer irTransformer;
  llvm::orc::ExecutionSession session;
  llvm::orc::RTDyldObjectLinkingLayer objectLayer;
  llvm::orc::IRCompileLayer compileLayer;
  llvm::orc::IRTransformLayer transformLayer;
  llvm::DataLayout dataLayout;
  llvm::orc::MangleAndInterner mangler;
  llvm::orc::ThreadSafeContext threadSafeCtx;
};
} // end namespace impl
} // namespace mlir

// Wrap a string into an llvm::StringError.
static inline Error make_string_error(const llvm::Twine &message) {
  return llvm::make_error<llvm::StringError>(message.str(),
                                             llvm::inconvertibleErrorCode());
}

// Given a list of PassRegistryEntry coming from a higher level, populates the
// given pass manager and appends the default set of required passes to lower to
// LLVMIR.
// Currently, these passes are:
// - constant folding
// - CSE
// - canonicalization
// - affine lowering
static void getDefaultPasses(
    PassManager &manager,
    const std::vector<const mlir::PassRegistryEntry *> &mlirPassRegistryList) {
  // Run each of the passes that were selected.
  for (const auto *passEntry : mlirPassRegistryList)
    passEntry->addToPipeline(manager);

  // Append the extra passes for lowering to MLIR.
  manager.addPass(mlir::createCanonicalizerPass());
  manager.addPass(mlir::createCSEPass());
  manager.addPass(mlir::createCanonicalizerPass());
  manager.addPass(mlir::createLowerAffinePass());
  manager.addPass(mlir::createConvertToLLVMIRPass());
}

// Setup LLVM target triple from the current machine.
bool ExecutionEngine::setupTargetTriple(llvm::Module *llvmModule) {
  // Setup the machine properties from the current architecture.
  auto targetTriple = llvm::sys::getDefaultTargetTriple();
  std::string errorMessage;
  auto target = llvm::TargetRegistry::lookupTarget(targetTriple, errorMessage);
  if (!target) {
    llvm::errs() << "NO target: " << errorMessage << "\n";
    return true;
  }
  auto machine =
      target->createTargetMachine(targetTriple, "generic", "", {}, {});
  llvmModule->setDataLayout(machine->createDataLayout());
  llvmModule->setTargetTriple(targetTriple);
  return false;
}

static std::string makePackedFunctionName(StringRef name) {
  return "_mlir_" + name.str();
}

// For each function in the LLVM module, define an interface function that wraps
// all the arguments of the original function and all its results into an i8**
// pointer to provide a unified invocation interface.
void packFunctionArguments(llvm::Module *module) {
  auto &ctx = module->getContext();
  llvm::IRBuilder<> builder(ctx);
  llvm::DenseSet<llvm::Function *> interfaceFunctions;
  for (auto &func : module->getFunctionList()) {
    if (func.isDeclaration()) {
      continue;
    }
    if (interfaceFunctions.count(&func)) {
      continue;
    }

    // Given a function `foo(<...>)`, define the interface function
    // `mlir_foo(i8**)`.
    auto newType = llvm::FunctionType::get(
        builder.getVoidTy(), builder.getInt8PtrTy()->getPointerTo(),
        /*isVarArg=*/false);
    auto newName = makePackedFunctionName(func.getName());
    auto funcCst = module->getOrInsertFunction(newName, newType);
    llvm::Function *interfaceFunc =
        llvm::cast<llvm::Function>(funcCst.getCallee());
    interfaceFunctions.insert(interfaceFunc);

    // Extract the arguments from the type-erased argument list and cast them to
    // the proper types.
    auto bb = llvm::BasicBlock::Create(ctx);
    bb->insertInto(interfaceFunc);
    builder.SetInsertPoint(bb);
    llvm::Value *argList = interfaceFunc->arg_begin();
    llvm::SmallVector<llvm::Value *, 8> args;
    args.reserve(llvm::size(func.args()));
    for (auto &indexedArg : llvm::enumerate(func.args())) {
      llvm::Value *argIndex = llvm::Constant::getIntegerValue(
          builder.getInt64Ty(), llvm::APInt(64, indexedArg.index()));
      llvm::Value *argPtrPtr = builder.CreateGEP(argList, argIndex);
      llvm::Value *argPtr = builder.CreateLoad(argPtrPtr);
      argPtr = builder.CreateBitCast(
          argPtr, indexedArg.value().getType()->getPointerTo());
      llvm::Value *arg = builder.CreateLoad(argPtr);
      args.push_back(arg);
    }

    // Call the implementation function with the extracted arguments.
    llvm::Value *result = builder.CreateCall(&func, args);

    // Assuming the result is one value, potentially of type `void`.
    if (!result->getType()->isVoidTy()) {
      llvm::Value *retIndex = llvm::Constant::getIntegerValue(
          builder.getInt64Ty(), llvm::APInt(64, llvm::size(func.args())));
      llvm::Value *retPtrPtr = builder.CreateGEP(argList, retIndex);
      llvm::Value *retPtr = builder.CreateLoad(retPtrPtr);
      retPtr = builder.CreateBitCast(retPtr, result->getType()->getPointerTo());
      builder.CreateStore(result, retPtr);
    }

    // The interface function returns void.
    builder.CreateRetVoid();
  }
}

// Out of line for PIMPL unique_ptr.
ExecutionEngine::~ExecutionEngine() = default;

Expected<std::unique_ptr<ExecutionEngine>> ExecutionEngine::create(
    Module *m, PassManager *pm,
    std::function<llvm::Error(llvm::Module *)> transformer) {
  auto engine = llvm::make_unique<ExecutionEngine>();
  auto expectedJIT = impl::OrcJIT::createDefault(transformer);
  if (!expectedJIT)
    return expectedJIT.takeError();

  if (pm && failed(pm->run(m)))
    return make_string_error("passes failed");

  auto llvmModule = translateModuleToLLVMIR(*m);
  if (!llvmModule)
    return make_string_error("could not convert to LLVM IR");
  // FIXME: the triple should be passed to the translation or dialect conversion
  // instead of this.  Currently, the LLVM module created above has no triple
  // associated with it.
  setupTargetTriple(llvmModule.get());
  packFunctionArguments(llvmModule.get());

  if (auto err = (*expectedJIT)->addModule(std::move(llvmModule)))
    return std::move(err);
  engine->jit = std::move(*expectedJIT);

  return std::move(engine);
}

Expected<std::unique_ptr<ExecutionEngine>> ExecutionEngine::create(
    Module *m, std::function<llvm::Error(llvm::Module *)> transformer) {
  // Construct and run the default MLIR pipeline.
  PassManager manager;
  getDefaultPasses(manager, {});
  return create(m, &manager, transformer);
}

Expected<void (*)(void **)> ExecutionEngine::lookup(StringRef name) const {
  auto expectedSymbol = jit->lookup(makePackedFunctionName(name));
  if (!expectedSymbol)
    return expectedSymbol.takeError();
  auto rawFPtr = expectedSymbol->getAddress();
  auto fptr = reinterpret_cast<void (*)(void **)>(rawFPtr);
  if (!fptr)
    return make_string_error("looked up function is null");
  return fptr;
}

llvm::Error ExecutionEngine::invoke(StringRef name,
                                    MutableArrayRef<void *> args) {
  auto expectedFPtr = lookup(name);
  if (!expectedFPtr)
    return expectedFPtr.takeError();
  auto fptr = *expectedFPtr;

  (*fptr)(args.data());

  return llvm::Error::success();
}
<commit_msg>    ExecutionEngine: update to reflect LLVM API changes<commit_after>//===- ExecutionEngine.cpp - MLIR Execution engine and utils --------------===//
//
// Copyright 2019 The MLIR Authors.
//
// 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.
// =============================================================================
//
// This file implements the execution engine for MLIR modules based on LLVM Orc
// JIT engine.
//
//===----------------------------------------------------------------------===//
#include "mlir/ExecutionEngine/ExecutionEngine.h"
#include "mlir/IR/Function.h"
#include "mlir/IR/Module.h"
#include "mlir/LLVMIR/Transforms.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Target/LLVMIR.h"
#include "mlir/Transforms/Passes.h"

#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
#include "llvm/ExecutionEngine/Orc/IRTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/TargetRegistry.h"

using namespace mlir;
using llvm::Error;
using llvm::Expected;

namespace {
// Memory manager for the JIT's objectLayer.  Its main goal is to fallback to
// resolving functions in the current process if they cannot be resolved in the
// JIT-compiled modules.
class MemoryManager : public llvm::SectionMemoryManager {
public:
  MemoryManager(llvm::orc::ExecutionSession &execSession)
      : session(execSession) {}

  // Resolve the named symbol.  First, try looking it up in the main library of
  // the execution session.  If there is no such symbol, try looking it up in
  // the current process (for example, if it is a standard library function).
  // Return `nullptr` if lookup fails.
  llvm::JITSymbol findSymbol(const std::string &name) override {
    auto mainLibSymbol = session.lookup({&session.getMainJITDylib()}, name);
    if (mainLibSymbol)
      return mainLibSymbol.get();
    auto address = llvm::RTDyldMemoryManager::getSymbolAddressInProcess(name);
    if (!address) {
      llvm::errs() << "Could not look up: " << name << '\n';
      return nullptr;
    }
    return llvm::JITSymbol(address, llvm::JITSymbolFlags::Exported);
  }

private:
  llvm::orc::ExecutionSession &session;
};
} // end anonymous namespace

namespace mlir {
namespace impl {
// Simple layered Orc JIT compilation engine.
class OrcJIT {
public:
  using IRTransformer = std::function<Error(llvm::Module *)>;

  // Construct a JIT engine for the target host defined by `machineBuilder`,
  // using the data layout provided as `dataLayout`.
  // Setup the object layer to use our custom memory manager in order to resolve
  // calls to library functions present in the process.
  OrcJIT(llvm::orc::JITTargetMachineBuilder machineBuilder,
         llvm::DataLayout layout, IRTransformer transform)
      : irTransformer(transform),
        objectLayer(
            session,
            [this]() { return llvm::make_unique<MemoryManager>(session); }),
        compileLayer(
            session, objectLayer,
            llvm::orc::ConcurrentIRCompiler(std::move(machineBuilder))),
        transformLayer(session, compileLayer, makeIRTransformFunction()),
        dataLayout(layout), mangler(session, this->dataLayout),
        threadSafeCtx(llvm::make_unique<llvm::LLVMContext>()) {
    session.getMainJITDylib().setGenerator(
        cantFail(llvm::orc::DynamicLibrarySearchGenerator::GetForCurrentProcess(
            layout.getGlobalPrefix())));
  }

  // Create a JIT engine for the current host.
  static Expected<std::unique_ptr<OrcJIT>>
  createDefault(IRTransformer transformer) {
    auto machineBuilder = llvm::orc::JITTargetMachineBuilder::detectHost();
    if (!machineBuilder)
      return machineBuilder.takeError();

    auto dataLayout = machineBuilder->getDefaultDataLayoutForTarget();
    if (!dataLayout)
      return dataLayout.takeError();

    return llvm::make_unique<OrcJIT>(std::move(*machineBuilder),
                                     std::move(*dataLayout), transformer);
  }

  // Add an LLVM module to the main library managed by the JIT engine.
  Error addModule(std::unique_ptr<llvm::Module> M) {
    return transformLayer.add(
        session.getMainJITDylib(),
        llvm::orc::ThreadSafeModule(std::move(M), threadSafeCtx));
  }

  // Lookup a symbol in the main library managed by the JIT engine.
  Expected<llvm::JITEvaluatedSymbol> lookup(StringRef Name) {
    return session.lookup({&session.getMainJITDylib()}, mangler(Name.str()));
  }

private:
  // Wrap the `irTransformer` into a function that can be called by the
  // IRTranformLayer.  If `irTransformer` is not set up, return the module as is
  // without errors.
  llvm::orc::IRTransformLayer::TransformFunction makeIRTransformFunction() {
    return [this](llvm::orc::ThreadSafeModule module,
                  const llvm::orc::MaterializationResponsibility &resp)
               -> Expected<llvm::orc::ThreadSafeModule> {
      (void)resp;
      if (!irTransformer)
        return std::move(module);
      if (Error err = irTransformer(module.getModule()))
        return std::move(err);
      return std::move(module);
    };
  }

  IRTransformer irTransformer;
  llvm::orc::ExecutionSession session;
  llvm::orc::RTDyldObjectLinkingLayer objectLayer;
  llvm::orc::IRCompileLayer compileLayer;
  llvm::orc::IRTransformLayer transformLayer;
  llvm::DataLayout dataLayout;
  llvm::orc::MangleAndInterner mangler;
  llvm::orc::ThreadSafeContext threadSafeCtx;
};
} // end namespace impl
} // namespace mlir

// Wrap a string into an llvm::StringError.
static inline Error make_string_error(const llvm::Twine &message) {
  return llvm::make_error<llvm::StringError>(message.str(),
                                             llvm::inconvertibleErrorCode());
}

// Given a list of PassRegistryEntry coming from a higher level, populates the
// given pass manager and appends the default set of required passes to lower to
// LLVMIR.
// Currently, these passes are:
// - constant folding
// - CSE
// - canonicalization
// - affine lowering
static void getDefaultPasses(
    PassManager &manager,
    const std::vector<const mlir::PassRegistryEntry *> &mlirPassRegistryList) {
  // Run each of the passes that were selected.
  for (const auto *passEntry : mlirPassRegistryList)
    passEntry->addToPipeline(manager);

  // Append the extra passes for lowering to MLIR.
  manager.addPass(mlir::createCanonicalizerPass());
  manager.addPass(mlir::createCSEPass());
  manager.addPass(mlir::createCanonicalizerPass());
  manager.addPass(mlir::createLowerAffinePass());
  manager.addPass(mlir::createConvertToLLVMIRPass());
}

// Setup LLVM target triple from the current machine.
bool ExecutionEngine::setupTargetTriple(llvm::Module *llvmModule) {
  // Setup the machine properties from the current architecture.
  auto targetTriple = llvm::sys::getDefaultTargetTriple();
  std::string errorMessage;
  auto target = llvm::TargetRegistry::lookupTarget(targetTriple, errorMessage);
  if (!target) {
    llvm::errs() << "NO target: " << errorMessage << "\n";
    return true;
  }
  auto machine =
      target->createTargetMachine(targetTriple, "generic", "", {}, {});
  llvmModule->setDataLayout(machine->createDataLayout());
  llvmModule->setTargetTriple(targetTriple);
  return false;
}

static std::string makePackedFunctionName(StringRef name) {
  return "_mlir_" + name.str();
}

// For each function in the LLVM module, define an interface function that wraps
// all the arguments of the original function and all its results into an i8**
// pointer to provide a unified invocation interface.
void packFunctionArguments(llvm::Module *module) {
  auto &ctx = module->getContext();
  llvm::IRBuilder<> builder(ctx);
  llvm::DenseSet<llvm::Function *> interfaceFunctions;
  for (auto &func : module->getFunctionList()) {
    if (func.isDeclaration()) {
      continue;
    }
    if (interfaceFunctions.count(&func)) {
      continue;
    }

    // Given a function `foo(<...>)`, define the interface function
    // `mlir_foo(i8**)`.
    auto newType = llvm::FunctionType::get(
        builder.getVoidTy(), builder.getInt8PtrTy()->getPointerTo(),
        /*isVarArg=*/false);
    auto newName = makePackedFunctionName(func.getName());
    auto funcCst = module->getOrInsertFunction(newName, newType);
    llvm::Function *interfaceFunc =
        llvm::cast<llvm::Function>(funcCst.getCallee());
    interfaceFunctions.insert(interfaceFunc);

    // Extract the arguments from the type-erased argument list and cast them to
    // the proper types.
    auto bb = llvm::BasicBlock::Create(ctx);
    bb->insertInto(interfaceFunc);
    builder.SetInsertPoint(bb);
    llvm::Value *argList = interfaceFunc->arg_begin();
    llvm::SmallVector<llvm::Value *, 8> args;
    args.reserve(llvm::size(func.args()));
    for (auto &indexedArg : llvm::enumerate(func.args())) {
      llvm::Value *argIndex = llvm::Constant::getIntegerValue(
          builder.getInt64Ty(), llvm::APInt(64, indexedArg.index()));
      llvm::Value *argPtrPtr = builder.CreateGEP(argList, argIndex);
      llvm::Value *argPtr = builder.CreateLoad(argPtrPtr);
      argPtr = builder.CreateBitCast(
          argPtr, indexedArg.value().getType()->getPointerTo());
      llvm::Value *arg = builder.CreateLoad(argPtr);
      args.push_back(arg);
    }

    // Call the implementation function with the extracted arguments.
    llvm::Value *result = builder.CreateCall(&func, args);

    // Assuming the result is one value, potentially of type `void`.
    if (!result->getType()->isVoidTy()) {
      llvm::Value *retIndex = llvm::Constant::getIntegerValue(
          builder.getInt64Ty(), llvm::APInt(64, llvm::size(func.args())));
      llvm::Value *retPtrPtr = builder.CreateGEP(argList, retIndex);
      llvm::Value *retPtr = builder.CreateLoad(retPtrPtr);
      retPtr = builder.CreateBitCast(retPtr, result->getType()->getPointerTo());
      builder.CreateStore(result, retPtr);
    }

    // The interface function returns void.
    builder.CreateRetVoid();
  }
}

// Out of line for PIMPL unique_ptr.
ExecutionEngine::~ExecutionEngine() = default;

Expected<std::unique_ptr<ExecutionEngine>> ExecutionEngine::create(
    Module *m, PassManager *pm,
    std::function<llvm::Error(llvm::Module *)> transformer) {
  auto engine = llvm::make_unique<ExecutionEngine>();
  auto expectedJIT = impl::OrcJIT::createDefault(transformer);
  if (!expectedJIT)
    return expectedJIT.takeError();

  if (pm && failed(pm->run(m)))
    return make_string_error("passes failed");

  auto llvmModule = translateModuleToLLVMIR(*m);
  if (!llvmModule)
    return make_string_error("could not convert to LLVM IR");
  // FIXME: the triple should be passed to the translation or dialect conversion
  // instead of this.  Currently, the LLVM module created above has no triple
  // associated with it.
  setupTargetTriple(llvmModule.get());
  packFunctionArguments(llvmModule.get());

  if (auto err = (*expectedJIT)->addModule(std::move(llvmModule)))
    return std::move(err);
  engine->jit = std::move(*expectedJIT);

  return std::move(engine);
}

Expected<std::unique_ptr<ExecutionEngine>> ExecutionEngine::create(
    Module *m, std::function<llvm::Error(llvm::Module *)> transformer) {
  // Construct and run the default MLIR pipeline.
  PassManager manager;
  getDefaultPasses(manager, {});
  return create(m, &manager, transformer);
}

Expected<void (*)(void **)> ExecutionEngine::lookup(StringRef name) const {
  auto expectedSymbol = jit->lookup(makePackedFunctionName(name));
  if (!expectedSymbol)
    return expectedSymbol.takeError();
  auto rawFPtr = expectedSymbol->getAddress();
  auto fptr = reinterpret_cast<void (*)(void **)>(rawFPtr);
  if (!fptr)
    return make_string_error("looked up function is null");
  return fptr;
}

llvm::Error ExecutionEngine::invoke(StringRef name,
                                    MutableArrayRef<void *> args) {
  auto expectedFPtr = lookup(name);
  if (!expectedFPtr)
    return expectedFPtr.takeError();
  auto fptr = *expectedFPtr;

  (*fptr)(args.data());

  return llvm::Error::success();
}
<|endoftext|>