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

#include "lldb/lldb-private.h"
#include "lldb/Core/Error.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"

#include "RegisterContextThreadMemory.h"

using namespace lldb;
using namespace lldb_private;

RegisterContextThreadMemory::RegisterContextThreadMemory (Thread &thread,
                                                          lldb::addr_t register_data_addr) :
    RegisterContext (thread, 0),
    m_thread_wp (thread.shared_from_this()),
    m_reg_ctx_sp (),
    m_register_data_addr (register_data_addr),
    m_stop_id(0)
{
}

RegisterContextThreadMemory::~RegisterContextThreadMemory()
{
}

void
RegisterContextThreadMemory::UpdateRegisterContext ()
{
    ThreadSP thread_sp (m_thread_wp.lock());
    if (thread_sp)
    {
        ProcessSP process_sp (thread_sp->GetProcess());

        if (process_sp)
        {
            const uint32_t stop_id = process_sp->GetModID().GetStopID();
            if (m_stop_id != stop_id)
            {
                m_stop_id = stop_id;
                m_reg_ctx_sp.reset();
            }
            if (!m_reg_ctx_sp)
            {
                ThreadSP backing_thread_sp (thread_sp->GetBackingThread());
                if (backing_thread_sp)
                {
                    m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
                }
                else
                {
                    OperatingSystem *os = process_sp->GetOperatingSystem ();
                    if (os->IsOperatingSystemPluginThread (thread_sp))
                        m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS);
                }
            }
        }
    }
    else
    {
        m_reg_ctx_sp.reset();
    }
}

//------------------------------------------------------------------
// Subclasses must override these functions
//------------------------------------------------------------------
void
RegisterContextThreadMemory::InvalidateAllRegisters ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        m_reg_ctx_sp->InvalidateAllRegisters();
}

size_t
RegisterContextThreadMemory::GetRegisterCount ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->GetRegisterCount();
    return 0;
}

const RegisterInfo *
RegisterContextThreadMemory::GetRegisterInfoAtIndex (size_t reg)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
    return NULL;
}

size_t
RegisterContextThreadMemory::GetRegisterSetCount ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->GetRegisterSetCount();
    return 0;
}

const RegisterSet *
RegisterContextThreadMemory::GetRegisterSet (size_t reg_set)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->GetRegisterSet(reg_set);
    return NULL;
}

bool
RegisterContextThreadMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
    return false;
}

bool
RegisterContextThreadMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->WriteRegister (reg_info, reg_value);
    return false;
}

bool
RegisterContextThreadMemory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
    return false;
}

bool
RegisterContextThreadMemory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->WriteAllRegisterValues (data_sp);
    return false;
}

bool
RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP reg_ctx_sp)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
    return false;
}

uint32_t
RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
    return false;
}

uint32_t
RegisterContextThreadMemory::NumSupportedHardwareBreakpoints ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
    return false;
}

uint32_t
RegisterContextThreadMemory::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
    return 0;
}

bool
RegisterContextThreadMemory::ClearHardwareBreakpoint (uint32_t hw_idx)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ClearHardwareBreakpoint (hw_idx);
    return false;
}

uint32_t
RegisterContextThreadMemory::NumSupportedHardwareWatchpoints ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
    return 0;
}

uint32_t
RegisterContextThreadMemory::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
    return 0;
}

bool
RegisterContextThreadMemory::ClearHardwareWatchpoint (uint32_t hw_index)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
    return false;
}

bool
RegisterContextThreadMemory::HardwareSingleStep (bool enable)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->HardwareSingleStep(enable);
    return false;
}

Error
RegisterContextThreadMemory::ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ReadRegisterValueFromMemory (reg_info, src_addr, src_len, reg_value);
    Error error;
    error.SetErrorString("invalid register context");
    return error;
}

Error
RegisterContextThreadMemory::WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->WriteRegisterValueToMemory (reg_info, dst_addr, dst_len, reg_value);
    Error error;
    error.SetErrorString("invalid register context");
    return error;
}
<commit_msg>Clear the register context if our process is no longer alive.<commit_after>//===-- RegisterContextThreadMemory.cpp -------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/lldb-private.h"
#include "lldb/Core/Error.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Thread.h"

#include "RegisterContextThreadMemory.h"

using namespace lldb;
using namespace lldb_private;

RegisterContextThreadMemory::RegisterContextThreadMemory (Thread &thread,
                                                          lldb::addr_t register_data_addr) :
    RegisterContext (thread, 0),
    m_thread_wp (thread.shared_from_this()),
    m_reg_ctx_sp (),
    m_register_data_addr (register_data_addr),
    m_stop_id(0)
{
}

RegisterContextThreadMemory::~RegisterContextThreadMemory()
{
}

void
RegisterContextThreadMemory::UpdateRegisterContext ()
{
    ThreadSP thread_sp (m_thread_wp.lock());
    if (thread_sp)
    {
        ProcessSP process_sp (thread_sp->GetProcess());

        if (process_sp)
        {
            const uint32_t stop_id = process_sp->GetModID().GetStopID();
            if (m_stop_id != stop_id)
            {
                m_stop_id = stop_id;
                m_reg_ctx_sp.reset();
            }
            if (!m_reg_ctx_sp)
            {
                ThreadSP backing_thread_sp (thread_sp->GetBackingThread());
                if (backing_thread_sp)
                {
                    m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
                }
                else
                {
                    OperatingSystem *os = process_sp->GetOperatingSystem ();
                    if (os->IsOperatingSystemPluginThread (thread_sp))
                        m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS);
                }
            }
        }
        else
        {
            m_reg_ctx_sp.reset();
        }
    }
    else
    {
        m_reg_ctx_sp.reset();
    }
}

//------------------------------------------------------------------
// Subclasses must override these functions
//------------------------------------------------------------------
void
RegisterContextThreadMemory::InvalidateAllRegisters ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        m_reg_ctx_sp->InvalidateAllRegisters();
}

size_t
RegisterContextThreadMemory::GetRegisterCount ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->GetRegisterCount();
    return 0;
}

const RegisterInfo *
RegisterContextThreadMemory::GetRegisterInfoAtIndex (size_t reg)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
    return NULL;
}

size_t
RegisterContextThreadMemory::GetRegisterSetCount ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->GetRegisterSetCount();
    return 0;
}

const RegisterSet *
RegisterContextThreadMemory::GetRegisterSet (size_t reg_set)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->GetRegisterSet(reg_set);
    return NULL;
}

bool
RegisterContextThreadMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
    return false;
}

bool
RegisterContextThreadMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->WriteRegister (reg_info, reg_value);
    return false;
}

bool
RegisterContextThreadMemory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
    return false;
}

bool
RegisterContextThreadMemory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->WriteAllRegisterValues (data_sp);
    return false;
}

bool
RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP reg_ctx_sp)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
    return false;
}

uint32_t
RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
    return false;
}

uint32_t
RegisterContextThreadMemory::NumSupportedHardwareBreakpoints ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
    return false;
}

uint32_t
RegisterContextThreadMemory::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
    return 0;
}

bool
RegisterContextThreadMemory::ClearHardwareBreakpoint (uint32_t hw_idx)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ClearHardwareBreakpoint (hw_idx);
    return false;
}

uint32_t
RegisterContextThreadMemory::NumSupportedHardwareWatchpoints ()
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
    return 0;
}

uint32_t
RegisterContextThreadMemory::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
    return 0;
}

bool
RegisterContextThreadMemory::ClearHardwareWatchpoint (uint32_t hw_index)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
    return false;
}

bool
RegisterContextThreadMemory::HardwareSingleStep (bool enable)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->HardwareSingleStep(enable);
    return false;
}

Error
RegisterContextThreadMemory::ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->ReadRegisterValueFromMemory (reg_info, src_addr, src_len, reg_value);
    Error error;
    error.SetErrorString("invalid register context");
    return error;
}

Error
RegisterContextThreadMemory::WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
{
    UpdateRegisterContext ();
    if (m_reg_ctx_sp)
        return m_reg_ctx_sp->WriteRegisterValueToMemory (reg_info, dst_addr, dst_len, reg_value);
    Error error;
    error.SetErrorString("invalid register context");
    return error;
}
<|endoftext|>


<commit_before>/*
    Command line introspection tool for SMOKE libs
    Copyright (C) 2010 Arno Rehn <arno@arnorehn.de>
    Copyright (C) 2010 Richard Dale <richard.j.dale@gmail.com>

    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; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <QtCore>
#include <QtDebug>

#include <smoke.h>
#include <qtcore_smoke.h>

static QTextStream qOut(stdout);

typedef void (*InitSmokeFn)();
typedef QPair<Smoke::ModuleIndex,int> ClassEntry;

static QList<Smoke*> smokeModules;

static bool showClassNamesOnly;
static bool showParents;
static bool matchPattern;
static bool caseInsensitive;
static QRegExp targetPattern;

static Smoke*
loadSmokeModule(QString moduleName) {
    QFileInfo file(QString("libsmoke") + moduleName);
    QLibrary lib(file.filePath());

    if (moduleName == "qtcore") {
        init_qtcore_Smoke();
        return qtcore_Smoke;
    }

    QString init_name = "init_" + moduleName + "_Smoke";
    InitSmokeFn init = (InitSmokeFn) lib.resolve(init_name.toLatin1());

    if (!init)
        qFatal("Couldn't resolve %s: %s", qPrintable(init_name), qPrintable(lib.errorString()));

    (*init)();

    QString smoke_name = moduleName + "_Smoke";
    Smoke** smoke = (Smoke**) lib.resolve(smoke_name.toLatin1());
    if (!smoke)
        qFatal("Couldn't resolve %s: %s", qPrintable(smoke_name), qPrintable(lib.errorString()));

    return *smoke;
}

static QString
methodToString(Smoke::ModuleIndex methodId)
{
    QString result;
    Smoke * smoke = methodId.smoke;
    Smoke::Method& methodRef = smoke->methods[methodId.index];

    if ((methodRef.flags & Smoke::mf_signal) != 0) {
        result.append("signal ");
    }

    if ((methodRef.flags & Smoke::mf_slot) != 0) {
        result.append("slot ");
    }

    const char * typeName = smoke->types[methodRef.ret].name;

    if ((methodRef.flags & Smoke::mf_enum) != 0) {
        result.append(QString("enum %1::%2")
                            .arg(smoke->classes[methodRef.classId].className)
                            .arg(smoke->methodNames[methodRef.name]) );
        return result;
    }

    if ((methodRef.flags & Smoke::mf_virtual) != 0) {
        result.append("virtual ");
    }

    if ((methodRef.flags & Smoke::mf_static) != 0) {
        result.append("static ");
    }

    if ((methodRef.flags & Smoke::mf_ctor) == 0) {
        result.append((typeName != 0 ? typeName : "void"));
        result.append(" ");
    }

    result.append(  QString("%1::%2(")
                        .arg(smoke->classes[methodRef.classId].className)
                        .arg(smoke->methodNames[methodRef.name]) );

    for (int i = 0; i < methodRef.numArgs; i++) {
        if (i > 0) {
            result.append(", ");
        }

        typeName = smoke->types[smoke->argumentList[methodRef.args+i]].name;
        result.append((typeName != 0 ? typeName : "void"));
    }

    result.append(")");

    if ((methodRef.flags & Smoke::mf_const) != 0) {
        result.append(" const");
    }

    if ((methodRef.flags & Smoke::mf_purevirtual) != 0) {
        result.append(" = 0");
    }

    return result;
}

static QList<ClassEntry>
getAllParents(const Smoke::ModuleIndex& classId, int indent)
{
    Smoke* smoke = classId.smoke;
    QList<ClassEntry> result;

    for (   Smoke::Index * parent = smoke->inheritanceList + smoke->classes[classId.index].parents;
            *parent != 0;
            parent++ )
    {
        Smoke::ModuleIndex parentId = Smoke::findClass(smoke->classes[*parent].className);
        Q_ASSERT(parentId != Smoke::NullModuleIndex);
        result << getAllParents(parentId, indent + 1);
    }

    result << ClassEntry(classId, indent);
    return result;
}

static void
showClass(const Smoke::ModuleIndex& classId, int indent)
{
    if (showClassNamesOnly) {
        QString className = QString::fromLatin1(classId.smoke->classes[classId.index].className);
        if (!matchPattern || targetPattern.indexIn(className) != -1) {
			while (indent > 0) {
				qOut << "  ";
				indent--;
			}
            qOut << className << "\n";
        }

        return;
    }

    Smoke * smoke = classId.smoke;
    Smoke::Index imax = smoke->numMethodMaps;
    Smoke::Index imin = 0, icur = -1, methmin, methmax;
    methmin = -1; methmax = -1; // kill warnings
    int icmp = -1;

    while (imax >= imin) {
        icur = (imin + imax) / 2;
        icmp = smoke->leg(smoke->methodMaps[icur].classId, classId.index);
        if (icmp == 0) {
            Smoke::Index pos = icur;
            while (icur != 0 && smoke->methodMaps[icur-1].classId == classId.index) {
                icur --;
            }

            methmin = icur;
            icur = pos;
            while (icur < imax && smoke->methodMaps[icur+1].classId == classId.index) {
                icur ++;
            }

            methmax = icur;
            break;
        }

        if (icmp > 0) {
            imax = icur - 1;
        } else {
            imin = icur + 1;
        }
    }

    if (icmp == 0) {
        for (Smoke::Index i = methmin ; i <= methmax ; i++) {
            Smoke::Index ix = smoke->methodMaps[i].method;
            if (ix >= 0) {  // single match
                QString method = methodToString(Smoke::ModuleIndex(smoke, ix));
                if (!matchPattern || targetPattern.indexIn(method) != -1) {
                    qOut << method << "\n";
                }
            } else {        // multiple match
                ix = -ix;       // turn into ambiguousMethodList index
                while (smoke->ambiguousMethodList[ix]) {
                    QString method = methodToString(Smoke::ModuleIndex(smoke, smoke->ambiguousMethodList[ix]));
                    if (!matchPattern || targetPattern.indexIn(method) != -1) {
                        qOut << method << "\n";
                    }

                    ix++;
                }
            }
        }
    }
}

#define PRINT_USAGE() \
    qDebug() << "Usage:" << argv[0] << "-r <smoke lib> [-r more smoke libs..] [-c] [-p] [-m pattern] [-i] [<classname(s)>..]"

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);
    QStringList arguments = app.arguments();

    showClassNamesOnly = false;
    showParents = false;
    caseInsensitive = false;
    matchPattern = false;

    if (argc == 1) {
        PRINT_USAGE();
        return 0;
    }

    int i = 1;
    while (i < arguments.length()) {
        if (arguments[i] == QLatin1String("-h") || arguments[i] == QLatin1String("--help")) {
            PRINT_USAGE();
            return 0;
        } else if (arguments[i] == QLatin1String("-r") || arguments[i] == QLatin1String("--require")) {
            i++;
            if (i < arguments.length()) {
                smokeModules << loadSmokeModule(arguments[i]);
            }
            i++;
        } else if (arguments[i] == QLatin1String("-c") || arguments[i] == QLatin1String("--classes")) {
            showClassNamesOnly = true;
            i++;
        } else if (arguments[i] == QLatin1String("-p") || arguments[i] == QLatin1String("--parents")) {
            showParents = true;
            i++;
        } else if (arguments[i] == QLatin1String("-i") || arguments[i] == QLatin1String("--insensitive")) {
            caseInsensitive = true;
            i++;
        } else if (arguments[i] == QLatin1String("-m") || arguments[i] == QLatin1String("--match")) {
            i++;
            if (i < arguments.length()) {
                targetPattern = QRegExp(arguments[i]);
                matchPattern = true;
            }
            i++;
        } else {
            break;
        }
    }

    if (caseInsensitive) {
        targetPattern.setCaseSensitivity(Qt::CaseInsensitive);
    }

    smokeModules << loadSmokeModule("qtcore");

    if (i >= arguments.length()) {
        if (targetPattern.isEmpty()) {
            PRINT_USAGE();
            return 0;
        } else {
            foreach (Smoke * smoke, smokeModules) {
                for (int i = 1; i <= smoke->numClasses; i++) {
                    if (!smoke->classes[i].external) {
                        showClass(Smoke::ModuleIndex(smoke, i), 0);
                    }
                }
            }

            return 0;
        }
    }

    while (i < arguments.length()) {
        QString className = arguments[i];

        Smoke::ModuleIndex classId = Smoke::findClass(className.toLatin1());
        if (classId == Smoke::NullModuleIndex) {
            qFatal("Error: class '%s' not found", className.toLatin1().constData());
        }

        if (showParents) {
            QList<ClassEntry> parents = getAllParents(classId, 0);
            foreach (ClassEntry parent, parents) {
                showClass(parent.first, parent.second);
            }
        } else {
            showClass(classId, 0);
        }

        i++;
    }

    return 0;
}
<commit_msg>* If a method is in a namespace, don't add a 'static' qualifier<commit_after>/*
    Command line introspection tool for SMOKE libs
    Copyright (C) 2010 Arno Rehn <arno@arnorehn.de>
    Copyright (C) 2010 Richard Dale <richard.j.dale@gmail.com>

    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; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include <QtCore>
#include <QtDebug>

#include <smoke.h>
#include <qtcore_smoke.h>

static QTextStream qOut(stdout);

typedef void (*InitSmokeFn)();
typedef QPair<Smoke::ModuleIndex,int> ClassEntry;

static QList<Smoke*> smokeModules;

static bool showClassNamesOnly;
static bool showParents;
static bool matchPattern;
static bool caseInsensitive;
static QRegExp targetPattern;

static Smoke*
loadSmokeModule(QString moduleName) {
    QFileInfo file(QString("libsmoke") + moduleName);
    QLibrary lib(file.filePath());

    if (moduleName == "qtcore") {
        init_qtcore_Smoke();
        return qtcore_Smoke;
    }

    QString init_name = "init_" + moduleName + "_Smoke";
    InitSmokeFn init = (InitSmokeFn) lib.resolve(init_name.toLatin1());

    if (!init)
        qFatal("Couldn't resolve %s: %s", qPrintable(init_name), qPrintable(lib.errorString()));

    (*init)();

    QString smoke_name = moduleName + "_Smoke";
    Smoke** smoke = (Smoke**) lib.resolve(smoke_name.toLatin1());
    if (!smoke)
        qFatal("Couldn't resolve %s: %s", qPrintable(smoke_name), qPrintable(lib.errorString()));

    return *smoke;
}

static QString
methodToString(Smoke::ModuleIndex methodId)
{
    QString result;
    Smoke * smoke = methodId.smoke;
    Smoke::Method& methodRef = smoke->methods[methodId.index];

    if ((methodRef.flags & Smoke::mf_signal) != 0) {
        result.append("signal ");
    }

    if ((methodRef.flags & Smoke::mf_slot) != 0) {
        result.append("slot ");
    }

    const char * typeName = smoke->types[methodRef.ret].name;

    if ((methodRef.flags & Smoke::mf_enum) != 0) {
        result.append(QString("enum %1::%2")
                            .arg(smoke->classes[methodRef.classId].className)
                            .arg(smoke->methodNames[methodRef.name]) );
        return result;
    }

    if ((methodRef.flags & Smoke::mf_virtual) != 0) {
        result.append("virtual ");
    }

    if (	(methodRef.flags & Smoke::mf_static) != 0
            && (smoke->classes[methodRef.classId].flags & Smoke::cf_namespace) == 0 )
    {
        result.append("static ");
    }

    if ((methodRef.flags & Smoke::mf_ctor) == 0) {
        result.append((typeName != 0 ? typeName : "void"));
        result.append(" ");
    }

    result.append(  QString("%1::%2(")
                        .arg(smoke->classes[methodRef.classId].className)
                        .arg(smoke->methodNames[methodRef.name]) );

    for (int i = 0; i < methodRef.numArgs; i++) {
        if (i > 0) {
            result.append(", ");
        }

        typeName = smoke->types[smoke->argumentList[methodRef.args+i]].name;
        result.append((typeName != 0 ? typeName : "void"));
    }

    result.append(")");

    if ((methodRef.flags & Smoke::mf_const) != 0) {
        result.append(" const");
    }

    if ((methodRef.flags & Smoke::mf_purevirtual) != 0) {
        result.append(" = 0");
    }

    return result;
}

static QList<ClassEntry>
getAllParents(const Smoke::ModuleIndex& classId, int indent)
{
    Smoke* smoke = classId.smoke;
    QList<ClassEntry> result;

    for (   Smoke::Index * parent = smoke->inheritanceList + smoke->classes[classId.index].parents;
            *parent != 0;
            parent++ )
    {
        Smoke::ModuleIndex parentId = Smoke::findClass(smoke->classes[*parent].className);
        Q_ASSERT(parentId != Smoke::NullModuleIndex);
        result << getAllParents(parentId, indent + 1);
    }

    result << ClassEntry(classId, indent);
    return result;
}

static void
showClass(const Smoke::ModuleIndex& classId, int indent)
{
    if (showClassNamesOnly) {
        QString className = QString::fromLatin1(classId.smoke->classes[classId.index].className);
        if (!matchPattern || targetPattern.indexIn(className) != -1) {
			while (indent > 0) {
				qOut << "  ";
				indent--;
			}
            qOut << className << "\n";
        }

        return;
    }

    Smoke * smoke = classId.smoke;
    Smoke::Index imax = smoke->numMethodMaps;
    Smoke::Index imin = 0, icur = -1, methmin, methmax;
    methmin = -1; methmax = -1; // kill warnings
    int icmp = -1;

    while (imax >= imin) {
        icur = (imin + imax) / 2;
        icmp = smoke->leg(smoke->methodMaps[icur].classId, classId.index);
        if (icmp == 0) {
            Smoke::Index pos = icur;
            while (icur != 0 && smoke->methodMaps[icur-1].classId == classId.index) {
                icur --;
            }

            methmin = icur;
            icur = pos;
            while (icur < imax && smoke->methodMaps[icur+1].classId == classId.index) {
                icur ++;
            }

            methmax = icur;
            break;
        }

        if (icmp > 0) {
            imax = icur - 1;
        } else {
            imin = icur + 1;
        }
    }

    if (icmp == 0) {
        for (Smoke::Index i = methmin ; i <= methmax ; i++) {
            Smoke::Index ix = smoke->methodMaps[i].method;
            if (ix >= 0) {  // single match
                QString method = methodToString(Smoke::ModuleIndex(smoke, ix));
                if (!matchPattern || targetPattern.indexIn(method) != -1) {
                    qOut << method << "\n";
                }
            } else {        // multiple match
                ix = -ix;       // turn into ambiguousMethodList index
                while (smoke->ambiguousMethodList[ix]) {
                    QString method = methodToString(Smoke::ModuleIndex(smoke, smoke->ambiguousMethodList[ix]));
                    if (!matchPattern || targetPattern.indexIn(method) != -1) {
                        qOut << method << "\n";
                    }

                    ix++;
                }
            }
        }
    }
}

#define PRINT_USAGE() \
    qDebug() << "Usage:" << argv[0] << "-r <smoke lib> [-r more smoke libs..] [-c] [-p] [-m pattern] [-i] [<classname(s)>..]"

int main(int argc, char** argv)
{
    QCoreApplication app(argc, argv);
    QStringList arguments = app.arguments();

    showClassNamesOnly = false;
    showParents = false;
    caseInsensitive = false;
    matchPattern = false;

    if (argc == 1) {
        PRINT_USAGE();
        return 0;
    }

    int i = 1;
    while (i < arguments.length()) {
        if (arguments[i] == QLatin1String("-h") || arguments[i] == QLatin1String("--help")) {
            PRINT_USAGE();
            return 0;
        } else if (arguments[i] == QLatin1String("-r") || arguments[i] == QLatin1String("--require")) {
            i++;
            if (i < arguments.length()) {
                smokeModules << loadSmokeModule(arguments[i]);
            }
            i++;
        } else if (arguments[i] == QLatin1String("-c") || arguments[i] == QLatin1String("--classes")) {
            showClassNamesOnly = true;
            i++;
        } else if (arguments[i] == QLatin1String("-p") || arguments[i] == QLatin1String("--parents")) {
            showParents = true;
            i++;
        } else if (arguments[i] == QLatin1String("-i") || arguments[i] == QLatin1String("--insensitive")) {
            caseInsensitive = true;
            i++;
        } else if (arguments[i] == QLatin1String("-m") || arguments[i] == QLatin1String("--match")) {
            i++;
            if (i < arguments.length()) {
                targetPattern = QRegExp(arguments[i]);
                matchPattern = true;
            }
            i++;
        } else {
            break;
        }
    }

    if (caseInsensitive) {
        targetPattern.setCaseSensitivity(Qt::CaseInsensitive);
    }

    smokeModules << loadSmokeModule("qtcore");

    if (i >= arguments.length()) {
        if (targetPattern.isEmpty()) {
            PRINT_USAGE();
            return 0;
        } else {
            foreach (Smoke * smoke, smokeModules) {
                for (int i = 1; i <= smoke->numClasses; i++) {
                    if (!smoke->classes[i].external) {
                        showClass(Smoke::ModuleIndex(smoke, i), 0);
                    }
                }
            }

            return 0;
        }
    }

    while (i < arguments.length()) {
        QString className = arguments[i];

        Smoke::ModuleIndex classId = Smoke::findClass(className.toLatin1());
        if (classId == Smoke::NullModuleIndex) {
            qFatal("Error: class '%s' not found", className.toLatin1().constData());
        }

        if (showParents) {
            QList<ClassEntry> parents = getAllParents(classId, 0);
            foreach (ClassEntry parent, parents) {
                showClass(parent.first, parent.second);
            }
        } else {
            showClass(classId, 0);
        }

        i++;
    }

    return 0;
}
<|endoftext|>


<commit_before>// @Yue Wang Aug, 2015
//
// Exercise 11.3:
// Write your own version of the word-counting program.
//
// Exercise 11.4:
// Extend your program to ignore case and punctuation.
// For example, “example.” “example, ” and “Example” should
// all increment the same counter.
//

#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <cctype>

using Map = std::map<std::string, std::size_t>;

//for ex11.3
auto count() -> Map
{
    Map counts;
    for (std::string w; std::cin >> w; ++counts[w]);
    return counts;
}

//for ex11.4
auto strip(std::string& str) -> std::string const&
{
    for (auto& ch : str) ch = tolower(ch);
    str.erase(std::remove_if(str.begin(), str.end(), ispunct), str.end());
    return str;
}

//for ex11.4
auto strip_and_count() -> Map
{
    Map counts;
    for (std::string w; std::cin >> w; ++counts[strip(w)]);
    return counts;
}

auto print(Map const& m) -> std::ostream&
{
    for (auto const& kv : m)
        std::cout << kv.first << " : " << kv.second << "\n";
    return std::cout;
}

int main()
{
    std::cout << "[ex11.3] Enter a few words please:\n";
    print( count() );
    std::cin.clear();
    std::cout << "[ex11.4] Enter a few words please:\n";
    print( strip_and_count() );

    return 0;
}
<commit_msg>Update ex11_3_4.cpp<commit_after>// @Yue Wang Aug, 2015
//
// Exercise 11.3:
// Write your own version of the word-counting program.
//
// Exercise 11.4:
// Extend your program to ignore case and punctuation.
// For example, “example.” “example, ” and “Example” should
// all increment the same counter.
//

#include <iostream>
#include <map>
#include <string>
#include <algorithm>
#include <cctype>

using std::string;
using std::cin;
using std::cout;
using std::remove_if;
using Map = std::map<std::string, std::size_t>;

//for ex11.3
auto count()
{
    Map counts;
    for (string w; cin >> w; ++counts[w]);
    return counts;
}

//for ex11.4
auto strip(string& str) -> string const&
{
    for (auto& ch : str) ch = tolower(ch);
    str.erase(remove_if(str.begin(), str.end(), ispunct), str.end());
    return str;
}

//for ex11.4
auto strip_and_count()
{
    Map counts;
    for (string w; cin >> w; ++counts[strip(w)]);
    return counts;
}

auto print(Map const& m)
{
    for (auto const& kv : m)
        cout << kv.first << " : " << kv.second << "\n";
}

int main()
{
    cout << "[ex11.3] Enter a few words please:\n";
    print(count());
    cin.clear();
    cout << "[ex11.4] Enter a few words please:\n";
    print(strip_and_count());

    return 0;
}
<|endoftext|>


<commit_before>#ifndef ADDRESS_HH
#define ADDRESS_HH

#include "error.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <ostream>

namespace fw {

//! union of sockaddr structs
union address_u {
    struct sockaddr sa;
    struct sockaddr_in sa_in;
    struct sockaddr_in6 sa_in6;
    struct sockaddr_storage sa_stor;
};

//! wrapper around sockaddr structures that strives to
//! help make ipv6 support seemless.
struct address {
    union address_u addr;

    //! construct an empty address
    address() {
        clear();
    }

    address(struct sockaddr *a, socklen_t alen) {
        clear();
        memcpy(&addr.sa, a, alen);
    }

    //! \param s address in string format for inet_pton
    //! \param p port in host byte order
    address(const char *s, uint16_t p=0) {
        clear();
        pton(s); // can throw
        port(p);
    }

    //! zeros out the address
    void clear() {
        memset(&addr, 0, sizeof(addr));
        addr.sa.sa_family = AF_INET; // get rid of valgrind warning about unitialized memory
    }

    //! \return sizeof(struct sockaddr_in) or sizeof(struct sockaddr_in6) depending on the value of family()
    socklen_t addrlen() const {
        return family() == AF_INET ? sizeof(addr.sa_in) : sizeof(addr.sa_in6);
    }

    //! \return a struct sockaddr pointer to the backing storage
    struct sockaddr *sockaddr() const {
        // cast away const cause i'm evil
        return (struct sockaddr *)&addr.sa;
    }

    //! sets address family AF_INET or AF_INET6
    void family(int f) { addr.sa.sa_family = f; }
    //! \return AF_INET or AF_INET6
    int family() const { return addr.sa.sa_family; }

    //! sets port
    //! \param p port in host by order
    void port(uint16_t p) {
        if (family() == AF_INET) {
            addr.sa_in.sin_port = htons(p);
        } else if (family() == AF_INET6) {
            addr.sa_in6.sin6_port = htons(p);
        }
    }

    //! returns port in host byte order
    uint16_t port() const {
        return ntohs(family() == AF_INET ? addr.sa_in.sin_port : addr.sa_in6.sin6_port);
    }

    //! wrapper around inet_ntop
    const char *ntop(char *dst, socklen_t size) const {
        const char *rvalue = NULL;
        if (family() == AF_INET) {
            rvalue = inet_ntop(family(), &addr.sa_in.sin_addr, dst, size);
            THROW_ON_NULL(rvalue);
        } else if (family() == AF_INET6) {
            rvalue = inet_ntop(family(), &addr.sa_in6.sin6_addr, dst, size);
            THROW_ON_NULL(rvalue);
        }
        return rvalue;
    }

    //! tries inet_pton() first with AF_INET and then AF_INET6
    void pton(const char *s) {
        if (inet_pton(AF_INET, s, &addr.sa_in.sin_addr) == 1) {
            addr.sa.sa_family = AF_INET;
            return;
        } else if (inet_pton(AF_INET6, s, &addr.sa_in6.sin6_addr) == 1) {
            addr.sa.sa_family = AF_INET6;
            return;
        }
        throw errno_error();
    }

    //! output address in addr:port format
    friend std::ostream &operator<< (std::ostream &out, const address &addr) {
        char buf[INET6_ADDRSTRLEN];
        out << addr.ntop(buf, sizeof(buf)) << ":" << addr.port();
        return out;
    }
};

} // end namespace fw

#endif // ADDRESS_HH

<commit_msg>host:port parsing<commit_after>#ifndef ADDRESS_HH
#define ADDRESS_HH

#include "error.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <ostream>
#include <boost/lexical_cast.hpp>

namespace fw {

inline void parse_host_port(std::string &host, unsigned short &port) {
    size_t pos = host.rfind(':');
    if (pos != std::string::npos) {
        port = boost::lexical_cast<unsigned short>(host.substr(pos+1, -1));
        host = host.substr(0, pos);
    }
}

//! union of sockaddr structs
union address_u {
    struct sockaddr sa;
    struct sockaddr_in sa_in;
    struct sockaddr_in6 sa_in6;
    struct sockaddr_storage sa_stor;
};

//! wrapper around sockaddr structures that strives to
//! help make ipv6 support seemless.
struct address {
    union address_u addr;

    //! construct an empty address
    address() {
        clear();
    }

    address(struct sockaddr *a, socklen_t alen) {
        clear();
        memcpy(&addr.sa, a, alen);
    }

    //! \param s address in string format for inet_pton
    //! \param p port in host byte order
    address(const char *s, uint16_t p=0) {
        clear();
        pton(s); // can throw
        port(p);
    }

    //! zeros out the address
    void clear() {
        memset(&addr, 0, sizeof(addr));
        addr.sa.sa_family = AF_INET; // get rid of valgrind warning about unitialized memory
    }

    //! \return sizeof(struct sockaddr_in) or sizeof(struct sockaddr_in6) depending on the value of family()
    socklen_t addrlen() const {
        return family() == AF_INET ? sizeof(addr.sa_in) : sizeof(addr.sa_in6);
    }

    //! \return a struct sockaddr pointer to the backing storage
    struct sockaddr *sockaddr() const {
        // cast away const cause i'm evil
        return (struct sockaddr *)&addr.sa;
    }

    //! sets address family AF_INET or AF_INET6
    void family(int f) { addr.sa.sa_family = f; }
    //! \return AF_INET or AF_INET6
    int family() const { return addr.sa.sa_family; }

    //! sets port
    //! \param p port in host by order
    void port(uint16_t p) {
        if (family() == AF_INET) {
            addr.sa_in.sin_port = htons(p);
        } else if (family() == AF_INET6) {
            addr.sa_in6.sin6_port = htons(p);
        }
    }

    //! returns port in host byte order
    uint16_t port() const {
        return ntohs(family() == AF_INET ? addr.sa_in.sin_port : addr.sa_in6.sin6_port);
    }

    //! wrapper around inet_ntop
    const char *ntop(char *dst, socklen_t size) const {
        const char *rvalue = NULL;
        if (family() == AF_INET) {
            rvalue = inet_ntop(family(), &addr.sa_in.sin_addr, dst, size);
            THROW_ON_NULL(rvalue);
        } else if (family() == AF_INET6) {
            rvalue = inet_ntop(family(), &addr.sa_in6.sin6_addr, dst, size);
            THROW_ON_NULL(rvalue);
        }
        return rvalue;
    }

    //! tries inet_pton() first with AF_INET and then AF_INET6
    void pton(const char *s) {
        if (inet_pton(AF_INET, s, &addr.sa_in.sin_addr) == 1) {
            addr.sa.sa_family = AF_INET;
            return;
        } else if (inet_pton(AF_INET6, s, &addr.sa_in6.sin6_addr) == 1) {
            addr.sa.sa_family = AF_INET6;
            return;
        }
        throw errno_error();
    }

    //! output address in addr:port format
    friend std::ostream &operator<< (std::ostream &out, const address &addr) {
        char buf[INET6_ADDRSTRLEN];
        out << addr.ntop(buf, sizeof(buf)) << ":" << addr.port();
        return out;
    }
};

} // end namespace fw

#endif // ADDRESS_HH

<|endoftext|>


<commit_before>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 2010 University of Cologne
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include "vvtcpserver.h"
#include "vvtcpsocket.h"
#include "vvmulticast.h"
#include "vvclock.h"
#include "vvtoolshed.h"
#include "vvpthread.h"

using namespace std;

//-------------------------------------------------------------------
// Threads for parallel TCP-Communication
//-------------------------------------------------------------------
class tcpConnection
{
public:
  tcpConnection(string addr, uchar* data, int size)
  {
    _addr = addr;
    _data = data;
    _size = size;
    _done = false;

    // socket connection
    int delim = addr.find_first_of(":");
    string port = addr.substr(delim+1);
    addr = addr.substr(0, delim);
    _socket = new vvTcpSocket();

    if(vvSocket::VV_OK == _socket->connectToHost(addr.c_str(), atoi(port.c_str())))
    {
      _status = true;
      _return = pthread_create( &_thread, NULL, threadMain, this);
    }
    else
    {
      _status = false;
    }
  }

  ~tcpConnection()
  {
    delete _socket;
  }

  static void* threadMain(void* attrib )
  {
    tcpConnection *obj = static_cast<tcpConnection*>(attrib);

    // send data via socket
    if(vvSocket::VV_OK != obj->_socket->write32(obj->_size))
    {
      cout << "Error occured in transfer to " << obj->_addr << "!" << endl;
      return NULL;
    }

    if(vvSocket::VV_OK != obj->_socket->writeData(obj->_data, obj->_size))
    {
      cout << "Error occured in transfer to " << obj->_addr << endl;
    }

    obj->_done = true;
    return NULL;
  }

  bool         _status;
  bool         _done;
  string       _addr;
  uchar       *_data;
  uint         _size;
  int          _return;
  pthread_t    _thread;
  vvTcpSocket *_socket;
};

uchar* generateData(const int size)
{
  // init data to be sent
  cout << "Prepare " << size << " Bytes of random data to be send/checked..." << flush;
  uchar* bar = new uchar[size];

  srand(123456);
  for(int i=0; i<size; i++)
  {
    uchar num = rand() % 256;
    bar[i] = num;
  }
  cout << "done!" << endl;
  return bar;
}

int main(int argc, char** argv)
{
  // don't forget arguments
  if(argc < 2)
  {
    cout << "Start with -sender or -receiver" << endl;
    return 0;
  }

  // ----------------------------------------------------------------
  // Sender
  // ----------------------------------------------------------------
  if(strcmp("-sender", argv[1])== 0)
  {
    cout << "Sender-Mode" << endl;
    cout << "###########" << endl;
    cout << endl;

    // Number of Bytes to be send/received
    uint count = 1024;
    if(NULL != argv[2] && 3 <= argc)
    {
      count = atoi(argv[2]);
    }
    else
    {
      cout << "No number of bytes given. (Default: " << count << ")" << endl;
    }

    uchar* bar = generateData(count);

    // timeout
    double sendTimeout;
    if(NULL != argv[3] && 4 <= argc)
    {
      sendTimeout = atof(argv[3]);
      cout << "Timeout set to " << sendTimeout << endl;
    }
    else
    {
      sendTimeout = -1.0;
    }

    double startTime = vvClock::getTime();

    // Send to all servers
    cout << "Sending to receivers via TCP...";
    std::vector<tcpConnection*> servers;
    for(int i=0; i<argc; i++)
    {
      if(0 == strcmp("-server", argv[i]))
      {
        servers.push_back(new tcpConnection(argv[i+1], bar, count));
        if(false == servers.back()->_status)
        {
          return 1;
        }
        i++;
      }
    }
    bool done = false;
    while(!done)
    {
      vvToolshed::sleep(1);

      done = true;
      for(unsigned int i = 0;i<servers.size(); i++)
      {
        if(false == servers[i]->_done)
        {
          done = false;
          break;
        }
      }
    }
    cout << "ok." << endl << endl;
    cout << "Time needed: " << vvClock::getTime() - startTime << endl;

    cout << endl;

    cout << "Receivers ready?" << endl;
    string tmp;
    cin >> tmp;

    // init Multicaster
    vvMulticast foo = vvMulticast(vvMulticast::VV_SENDER, vvMulticast::VV_VVSOCKET, "224.1.2.3", 50096);

    cout << "Sending to receivers via multicast..." << flush;
    startTime = vvClock::getTime();
    int written = foo.write(reinterpret_cast<const unsigned char*>(bar), count, sendTimeout);
    if(written != count)
      cout << "error!" << endl;
    else
      cout << "ok." << endl;

    cout << "Wait for Collectors answers..." << flush;
    for(unsigned int i = 0;i<servers.size() && count>0; i++)
    {
      char *multidone = new char[6];
      servers[i]->_socket->readString(multidone, 6);
      if(strcmp("done!", multidone) == 0)
        continue;
      else
        cout << "unexpected message from receiver" ;

      delete[] multidone;
    }
    cout << "done" << endl;

    cout << "Time needed: " << vvClock::getTime() - startTime << endl;
    cout << endl;

    delete[] bar;

    return 0;
  }

  // ----------------------------------------------------------------
  // Receiver
  // ----------------------------------------------------------------
  if(strcmp("-receiver", argv[1])== 0)
  {
    cout << "Receiver-Mode" << endl;
    cout << "#############" << endl;
    cout << endl;

    // timeout
    double receiveTimeout;
    if(NULL != argv[3] && 4 <= argc)
    {
      receiveTimeout = atof(argv[3]);
      cout << "Timeout: " << receiveTimeout << endl << endl;
    }
    else
    {
      receiveTimeout = -1.0;
    }

    vvMulticast foo = vvMulticast(vvMulticast::VV_RECEIVER, vvMulticast::VV_VVSOCKET, "224.1.2.3", 50096);

    cout << "Waiting for incoming data on TCP..." << endl;

    vvTcpServer server = vvTcpServer(31050);
    vvTcpSocket *recSocket = server.nextConnection();

    uint tcpSize = recSocket->read32();
    cout << "Expecting " << tcpSize << "Byes...";
    uchar* bartcp = new uchar[tcpSize];
    if(vvSocket::VV_OK == recSocket->readData(bartcp, tcpSize))
      cout << "ok." << endl;
    else
      cout << "error!" << endl;
    cout << endl;

    uchar* bar = generateData(tcpSize);

    cout << "Waiting for incoming data over Multicasting..." << flush;

    uchar* bartext = new uchar[tcpSize];
    int read = foo.read(bartext, tcpSize);

    // Tell sender, that we are done
    recSocket->writeString("done!");

    if(read >= 0)
    {
      cout << "ok." << endl;
      cout << endl;
      cout << "Check data for differences...    ";
      for(int i=0; i<tcpSize;i++)
      {
        if(bar[i] != bartext[i])
        {
          cout << "Failed: Differences found on byte " << i << endl;
          break;
        }
        else if(i % 1024 == 0)
        {
          cout << "\r" << flush;
          cout << "Check data for differences..." << int(100 * float(i)/float(tcpSize)) << "%" << flush;
        }
      }
      cout << endl;
    }
    else
      cout << "error!" << endl;

    delete[] bar;
    delete[] bartext;
    delete[] bartcp;
    delete recSocket;
    return 0;
  }

  cout << "Nothing done..." << endl;

  return 1;
}
<commit_msg>Warning fix<commit_after>// Virvo - Virtual Reality Volume Rendering
// Copyright (C) 2010 University of Cologne
// Contact: Jurgen P. Schulze, jschulze@ucsd.edu
//
// This file is part of Virvo.
//
// Virvo is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library (see license.txt); if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

#include "vvtcpserver.h"
#include "vvtcpsocket.h"
#include "vvmulticast.h"
#include "vvclock.h"
#include "vvtoolshed.h"
#include "vvpthread.h"

using namespace std;

//-------------------------------------------------------------------
// Threads for parallel TCP-Communication
//-------------------------------------------------------------------
class tcpConnection
{
public:
  tcpConnection(string addr, uchar* data, int size)
  {
    _addr = addr;
    _data = data;
    _size = size;
    _done = false;

    // socket connection
    int delim = addr.find_first_of(":");
    string port = addr.substr(delim+1);
    addr = addr.substr(0, delim);
    _socket = new vvTcpSocket();

    if(vvSocket::VV_OK == _socket->connectToHost(addr.c_str(), atoi(port.c_str())))
    {
      _status = true;
      _return = pthread_create( &_thread, NULL, threadMain, this);
    }
    else
    {
      _status = false;
    }
  }

  ~tcpConnection()
  {
    delete _socket;
  }

  static void* threadMain(void* attrib )
  {
    tcpConnection *obj = static_cast<tcpConnection*>(attrib);

    // send data via socket
    if(vvSocket::VV_OK != obj->_socket->write32(obj->_size))
    {
      cout << "Error occured in transfer to " << obj->_addr << "!" << endl;
      return NULL;
    }

    if(vvSocket::VV_OK != obj->_socket->writeData(obj->_data, obj->_size))
    {
      cout << "Error occured in transfer to " << obj->_addr << endl;
    }

    obj->_done = true;
    return NULL;
  }

  bool         _status;
  bool         _done;
  string       _addr;
  uchar       *_data;
  uint         _size;
  int          _return;
  pthread_t    _thread;
  vvTcpSocket *_socket;
};

uchar* generateData(const int size)
{
  // init data to be sent
  cout << "Prepare " << size << " Bytes of random data to be send/checked..." << flush;
  uchar* bar = new uchar[size];

  srand(123456);
  for(int i=0; i<size; i++)
  {
    uchar num = rand() % 256;
    bar[i] = num;
  }
  cout << "done!" << endl;
  return bar;
}

int main(int argc, char** argv)
{
  // don't forget arguments
  if(argc < 2)
  {
    cout << "Start with -sender or -receiver" << endl;
    return 0;
  }

  // ----------------------------------------------------------------
  // Sender
  // ----------------------------------------------------------------
  if(strcmp("-sender", argv[1])== 0)
  {
    cout << "Sender-Mode" << endl;
    cout << "###########" << endl;
    cout << endl;

    // Number of Bytes to be send/received
    uint count = 1024;
    if(NULL != argv[2] && 3 <= argc)
    {
      count = atoi(argv[2]);
    }
    else
    {
      cout << "No number of bytes given. (Default: " << count << ")" << endl;
    }

    uchar* bar = generateData(count);

    // timeout
    double sendTimeout;
    if(NULL != argv[3] && 4 <= argc)
    {
      sendTimeout = atof(argv[3]);
      cout << "Timeout set to " << sendTimeout << endl;
    }
    else
    {
      sendTimeout = -1.0;
    }

    double startTime = vvClock::getTime();

    // Send to all servers
    cout << "Sending to receivers via TCP...";
    std::vector<tcpConnection*> servers;
    for(int i=0; i<argc; i++)
    {
      if(0 == strcmp("-server", argv[i]))
      {
        servers.push_back(new tcpConnection(argv[i+1], bar, count));
        if(false == servers.back()->_status)
        {
          return 1;
        }
        i++;
      }
    }
    bool done = false;
    while(!done)
    {
      vvToolshed::sleep(1);

      done = true;
      for(unsigned int i = 0;i<servers.size(); i++)
      {
        if(false == servers[i]->_done)
        {
          done = false;
          break;
        }
      }
    }
    cout << "ok." << endl << endl;
    cout << "Time needed: " << vvClock::getTime() - startTime << endl;

    cout << endl;

    cout << "Receivers ready?" << endl;
    string tmp;
    cin >> tmp;

    // init Multicaster
    vvMulticast foo = vvMulticast(vvMulticast::VV_SENDER, vvMulticast::VV_VVSOCKET, "224.1.2.3", 50096);

    cout << "Sending to receivers via multicast..." << flush;
    startTime = vvClock::getTime();
    int written = foo.write(reinterpret_cast<const unsigned char*>(bar), count, sendTimeout);
    if(written != count)
      cout << "error!" << endl;
    else
      cout << "ok." << endl;

    cout << "Wait for Collectors answers..." << flush;
    for(unsigned int i = 0;i<servers.size() && count>0; i++)
    {
      char *multidone = new char[6];
      servers[i]->_socket->readString(multidone, 6);
      if(strcmp("done!", multidone) == 0)
        continue;
      else
        cout << "unexpected message from receiver" ;

      delete[] multidone;
    }
    cout << "done" << endl;

    cout << "Time needed: " << vvClock::getTime() - startTime << endl;
    cout << endl;

    delete[] bar;

    return 0;
  }

  // ----------------------------------------------------------------
  // Receiver
  // ----------------------------------------------------------------
  if(strcmp("-receiver", argv[1])== 0)
  {
    cout << "Receiver-Mode" << endl;
    cout << "#############" << endl;
    cout << endl;

    // timeout
    double receiveTimeout;
    if(NULL != argv[3] && 4 <= argc)
    {
      receiveTimeout = atof(argv[3]);
      cout << "Timeout: " << receiveTimeout << endl << endl;
    }
    else
    {
      receiveTimeout = -1.0;
    }

    vvMulticast foo = vvMulticast(vvMulticast::VV_RECEIVER, vvMulticast::VV_VVSOCKET, "224.1.2.3", 50096);

    cout << "Waiting for incoming data on TCP..." << endl;

    vvTcpServer server = vvTcpServer(31050);
    vvTcpSocket *recSocket = server.nextConnection();

    uint tcpSize = recSocket->read32();
    cout << "Expecting " << tcpSize << "Byes...";
    uchar* bartcp = new uchar[tcpSize];
    if(vvSocket::VV_OK == recSocket->readData(bartcp, tcpSize))
      cout << "ok." << endl;
    else
      cout << "error!" << endl;
    cout << endl;

    uchar* bar = generateData(tcpSize);

    cout << "Waiting for incoming data over Multicasting..." << flush;

    uchar* bartext = new uchar[tcpSize];
    int read = foo.read(bartext, tcpSize);

    // Tell sender, that we are done
    recSocket->writeString("done!");

    if(read >= 0)
    {
      cout << "ok." << endl;
      cout << endl;
      cout << "Check data for differences...    ";
      for(uint i=0; i<tcpSize;i++)
      {
        if(bar[i] != bartext[i])
        {
          cout << "Failed: Differences found on byte " << i << endl;
          break;
        }
        else if(i % 1024 == 0)
        {
          cout << "\r" << flush;
          cout << "Check data for differences..." << int(100 * float(i)/float(tcpSize)) << "%" << flush;
        }
      }
      cout << endl;
    }
    else
      cout << "error!" << endl;

    delete[] bar;
    delete[] bartext;
    delete[] bartcp;
    delete recSocket;
    return 0;
  }

  cout << "Nothing done..." << endl;

  return 1;
}
<|endoftext|>


<commit_before>/*!	\file   ConstantPropagationPass.h
	\author Gregory Diamos <gregory.diamos@gatech.edu>
	\date   Friday November 9, 2012
	\brief  The header file for the ConstantPropagationPass class.
*/

// Ocelot Includes
#include <ocelot/transforms/interface/ConstantPropagationPass.h>

#include <ocelot/analysis/interface/DataflowGraph.h>

#include <ocelot/ir/interface/IRKernel.h>

// Hydrazine Includes
#include <hydrazine/interface/debug.h>

// Preprocessor Macros
#ifdef REPORT_BASE
#undef REPORT_BASE
#endif

#define REPORT_BASE 0
#define REPORT_PTX  0

namespace transforms
{

ConstantPropagationPass::ConstantPropagationPass()
: KernelPass(Analysis::DataflowGraphAnalysis
	| Analysis::StaticSingleAssignment, "ConstantPropagationPass")
{

}

typedef analysis::DataflowGraph::iterator iterator;
typedef std::unordered_set<iterator>      BlockSet;

static void eliminateRedundantInstructions(analysis::DataflowGraph& dfg,
	BlockSet& blocks, iterator block);

void ConstantPropagationPass::runOnKernel(ir::IRKernel& k)
{
	report("Running constant propagation on kernel " << k.name);

	Analysis* dfgAnalysis = getAnalysis(Analysis::DataflowGraphAnalysis);
	assert(dfgAnalysis != 0);

	analysis::DataflowGraph& dfg =
		*static_cast<analysis::DataflowGraph*>(dfgAnalysis);

	assert(dfg.ssa() != analysis::DataflowGraph::SsaType::None);

	BlockSet blocks;

	report(" Starting by scanning all basic blocks");

	for(iterator block = dfg.begin(); block != dfg.end(); ++block)
	{
		report("  Queueing up BB_" << block->id());
		blocks.insert(block);
	}

	while(!blocks.empty())
	{
		iterator block = *blocks.begin();
		blocks.erase(blocks.begin());

		eliminateRedundantInstructions(dfg, blocks, block);
	}

	report("Finished running dead code elimination on kernel " << k.name);
	reportE(REPORT_PTX, k);

}

typedef analysis::DataflowGraph::InstructionVector InstructionVector;

static bool canRemoveInstruction(iterator block,
	InstructionVector::iterator instruction);
static void propagateValueToSuccessors(analysis::DataflowGraph& dfg,
	BlockSet& blocks, InstructionVector::iterator instruction);

static void eliminateRedundantInstructions(analysis::DataflowGraph& dfg,
	BlockSet& blocks, iterator block)
{
	typedef std::vector<unsigned int> KillList;

	KillList killList;

	report("  Propagating constants through instructions");
	unsigned int index = 0;
	for(auto instruction = block->instructions().begin();
		instruction != block->instructions().end(); ++instruction)
	{
		report("   checking " << instruction->i->toString());
		propagateValueToSuccessors(dfg, blocks, instruction);

		if(canRemoveInstruction(block, instruction))
		{
			report("    value is not used, removed it.");
			killList.push_back(index);

			// schedule the block for more work
			// TODO: do this when we consider values in multiple blocks
		}
		else
		{
			++index;
		}
	}

	for(KillList::iterator killed = killList.begin();
		killed != killList.end(); ++killed)
	{
		dfg.erase(block, *killed);
	}
}

static bool canRemoveInstruction(iterator block,
	InstructionVector::iterator instruction)
{
	ir::PTXInstruction& ptx = *static_cast<ir::PTXInstruction*>(
		instruction->i);

	if(ptx.hasSideEffects()) return false;

	for(auto reg = instruction->d.begin(); reg != instruction->d.end(); ++reg)
	{
		// the reg is alive outside the block
		if(block->aliveOut().count(*reg) != 0) return false;

		auto next = instruction;
		for(++next; next != block->instructions().end(); ++next)
		{
			for(auto source = next->s.begin();
				source != next->s.end(); ++source)
			{
				// found a user in the block
				if(*source->pointer == *reg->pointer) return false;
			}
		}
	}

	// There are no users and the instruction has no side effects
	return true;
}

static bool isOutputConstant(InstructionVector::iterator instruction)
{
	auto ptx = static_cast<ir::PTXInstruction*>(instruction->i);

	if(ptx->hasSideEffects()) return false;

	// The output is not constant if there are register inputs
	if(!instruction->s.empty()) return false;

	ir::PTXOperand* operands[] = {&ptx->a, &ptx->b, &ptx->c, &ptx->pg};

	for(unsigned int i = 0; i < 4; ++i)
	{
		if(operands[i]->addressMode == ir::PTXOperand::Invalid) continue;

		if(operands[i]->isRegister() && operands[i]->type == ir::PTXOperand::pred)
		{
			if(operands[i]->condition == ir::PTXOperand::PT ||
				operands[i]->condition == ir::PTXOperand::nPT)
			{
				continue;
			}
		}

		if(operands[i]->addressMode != ir::PTXOperand::Immediate)
		{
			report("    operand " << operands[i]->toString()
				<< " is not constant.");
			return false;
		}
	}

	return true;
}

static void replaceOperand(ir::PTXInstruction& ptx,
	ir::Instruction::RegisterType registerId,
	const ir::PTXOperand& immediate)
{
	ir::PTXOperand* operands[] = {&ptx.a, &ptx.b, &ptx.c, &ptx.pq,
		&ptx.d};

	unsigned int sources = 4;

	if(ptx.isStore()) ++sources;

	for(unsigned int i = 0; i < sources; ++i)
	{
		auto operand = operands[i];

		if(!operand->isRegister()) continue;

		if(operand->reg != registerId) continue;

		int offset = 0;

		if(operand->addressMode == ir::PTXOperand::Indirect)
		{
			offset = operand->offset;
		}

		*operand = immediate;

		operand->imm_uint += offset;
	}
}

static uint64_t getMask(const ir::PTXOperand& operand)
{
	uint64_t mask = (1ULL << (operand.bytes() * 8)) - 1;

	if(mask == 0) mask = 0xffffffffffffffffULL;

	return mask;
}

static uint64_t getValue(const ir::PTXOperand& operand)
{
	uint64_t value = operand.imm_uint;

	uint64_t mask = getMask(operand);;

	return value & mask;
}

static void setValue(ir::PTXOperand& operand, uint64_t value)
{
	uint64_t mask = getMask(operand);

	operand.imm_uint = value & mask;
}

static ir::PTXOperand computeCvtValue(const ir::PTXInstruction& ptx);
static ir::PTXOperand computeSetPValue(const ir::PTXInstruction& ptx);

static bool computeValue(ir::PTXOperand& result, const ir::PTXInstruction& ptx)
{
	result = ir::PTXOperand(ir::PTXOperand::Immediate, ptx.d.type);

	switch(ptx.opcode)
	{
	case ir::PTXInstruction::Add:
	{
		uint64_t a = getValue(ptx.a);
		uint64_t b = getValue(ptx.b);

		setValue(result, a + b);
		break;
	}
	case ir::PTXInstruction::And:
	{
		uint64_t a = getValue(ptx.a);
		uint64_t b = getValue(ptx.b);

		setValue(result, a & b);
		break;
	}
	case ir::PTXInstruction::Cvt:
	{
		result = computeCvtValue(ptx);
		break;
	}
	case ir::PTXInstruction::Mov:
	{
		setValue(result, getValue(ptx.a));
		break;
	}
	case ir::PTXInstruction::Mul:
	{
		uint64_t a = getValue(ptx.a);
		uint64_t b = getValue(ptx.b);

		assertM(ptx.modifier & ir::PTXInstruction::Lo,
			"Multiply modifier not implemented.");

		setValue(result, a * b);
		break;
	}
	case ir::PTXInstruction::SetP:
	{
		result = computeSetPValue(ptx);
		break;
	}
	case ir::PTXInstruction::Shr:
	{
		uint64_t a = getValue(ptx.a);
		uint64_t b = getValue(ptx.b);

		setValue(result, a >> b);
		break;
	}
	default:
	{
		return false;
	}
	}

	return true;
}

static void propagateValueToSuccessors(analysis::DataflowGraph& dfg,
	BlockSet& blocks, InstructionVector::iterator instruction)
{
	typedef analysis::DataflowGraph::RegisterPointerVector RegisterPointerVector;

	if(!isOutputConstant(instruction))
	{
		report("    output is not constant.");
		return;
	}

	auto ptx = static_cast<ir::PTXInstruction*>(instruction->i);

	if(ptx->isLoad())
	{
		report("    not allowed for loads.");
		return;
	}

	// TODO support instructions with multiple destinations
	if(instruction->d.size() != 1)
	{
		report("    no support for instructions with multiple destinations.");
		return;
	}

	// get the value
	ir::PTXOperand value;

	bool success = computeValue(value, *ptx);

	if(success)
	{
		report("    could not determine the resulting value.");
		return;
	}

	// send it to successors
	auto registerId = *instruction->d.back().pointer;

	auto block = instruction->block;

	for(auto instruction = block->instructions().begin();
		instruction != block->instructions().end(); ++instruction)
	{
		auto ptx = static_cast<ir::PTXInstruction*>(instruction->i);

		RegisterPointerVector newSources;

		for(auto source = instruction->s.begin(); source !=
			instruction->s.end(); ++source)
		{
			if(*source->pointer == registerId)
			{
				report("    updated use by '" << ptx->toString()
					<< "', of r" << registerId);

				replaceOperand(*ptx, registerId, value);
			}
			else
			{
				newSources.push_back(*source);
			}
		}

		instruction->s = std::move(newSources);
	}

	// TODO handle successors in other blocks
}

static bool isTrivialCvt(const ir::PTXInstruction& ptx)
{
	if(ptx.a.type == ptx.type) return true;

	if(ptx.modifier != 0) return false;

	if(ir::PTXOperand::isInt(ptx.type))
	{
		if(ir::PTXOperand::isInt(ptx.type))
		{
			if(ir::PTXOperand::bytes(ptx.type) <=
				ir::PTXOperand::bytes(ptx.a.type))
			{
				return true;
			}

			if(!ir::PTXOperand::isSigned(ptx.type) &&
				!ir::PTXOperand::isSigned(ptx.a.type))
			{
				return true;
			}
		}
	}

	return false;
}

static ir::PTXOperand computeCvtValue(const ir::PTXInstruction& ptx)
{
	ir::PTXOperand result(ir::PTXOperand::Immediate, ptx.d.type);

	if(isTrivialCvt(ptx))
	{
		setValue(result, getValue(ptx.a));
	}

	return result;
}

static ir::PTXOperand computeSetPValue(const ir::PTXInstruction& ptx)
{
	ir::PTXOperand result(ir::PTXOperand::Immediate, ptx.d.type);

	uint64_t a = getValue(ptx.a);
	uint64_t b = getValue(ptx.b);

	switch(ptx.comparisonOperator)
	{
	case ir::PTXInstruction::Eq:
	{
		setValue(result, a == b);
		break;
	}
	default:
	{
		assertM(false, "Not implemented.");
	}
	}

	return result;
}

}

<commit_msg>BUG: Inverted condition in constant propagation pass.<commit_after>/*!	\file   ConstantPropagationPass.h
	\author Gregory Diamos <gregory.diamos@gatech.edu>
	\date   Friday November 9, 2012
	\brief  The header file for the ConstantPropagationPass class.
*/

// Ocelot Includes
#include <ocelot/transforms/interface/ConstantPropagationPass.h>

#include <ocelot/analysis/interface/DataflowGraph.h>

#include <ocelot/ir/interface/IRKernel.h>

// Hydrazine Includes
#include <hydrazine/interface/debug.h>

// Preprocessor Macros
#ifdef REPORT_BASE
#undef REPORT_BASE
#endif

#define REPORT_BASE 1
#define REPORT_PTX  0

namespace transforms
{

ConstantPropagationPass::ConstantPropagationPass()
: KernelPass(Analysis::DataflowGraphAnalysis
	| Analysis::StaticSingleAssignment, "ConstantPropagationPass")
{

}

typedef analysis::DataflowGraph::iterator iterator;
typedef std::unordered_set<iterator>      BlockSet;

static void eliminateRedundantInstructions(analysis::DataflowGraph& dfg,
	BlockSet& blocks, iterator block);

void ConstantPropagationPass::runOnKernel(ir::IRKernel& k)
{
	report("Running constant propagation on kernel " << k.name);

	Analysis* dfgAnalysis = getAnalysis(Analysis::DataflowGraphAnalysis);
	assert(dfgAnalysis != 0);

	analysis::DataflowGraph& dfg =
		*static_cast<analysis::DataflowGraph*>(dfgAnalysis);

	assert(dfg.ssa() != analysis::DataflowGraph::SsaType::None);

	BlockSet blocks;

	report(" Starting by scanning all basic blocks");

	for(iterator block = dfg.begin(); block != dfg.end(); ++block)
	{
		report("  Queueing up BB_" << block->id());
		blocks.insert(block);
	}

	while(!blocks.empty())
	{
		iterator block = *blocks.begin();
		blocks.erase(blocks.begin());

		eliminateRedundantInstructions(dfg, blocks, block);
	}

	report("Finished running dead code elimination on kernel " << k.name);
	reportE(REPORT_PTX, k);

}

typedef analysis::DataflowGraph::InstructionVector InstructionVector;

static bool canRemoveInstruction(iterator block,
	InstructionVector::iterator instruction);
static void propagateValueToSuccessors(analysis::DataflowGraph& dfg,
	BlockSet& blocks, InstructionVector::iterator instruction);

static void eliminateRedundantInstructions(analysis::DataflowGraph& dfg,
	BlockSet& blocks, iterator block)
{
	typedef std::vector<unsigned int> KillList;

	KillList killList;

	report("  Propagating constants through instructions");
	unsigned int index = 0;
	for(auto instruction = block->instructions().begin();
		instruction != block->instructions().end(); ++instruction)
	{
		report("   checking " << instruction->i->toString());
		propagateValueToSuccessors(dfg, blocks, instruction);

		if(canRemoveInstruction(block, instruction))
		{
			report("    value is not used, removed it.");
			killList.push_back(index);

			// schedule the block for more work
			// TODO: do this when we consider values in multiple blocks
		}
		else
		{
			++index;
		}
	}

	for(KillList::iterator killed = killList.begin();
		killed != killList.end(); ++killed)
	{
		dfg.erase(block, *killed);
	}
}

static bool canRemoveInstruction(iterator block,
	InstructionVector::iterator instruction)
{
	ir::PTXInstruction& ptx = *static_cast<ir::PTXInstruction*>(
		instruction->i);

	if(ptx.hasSideEffects()) return false;

	for(auto reg = instruction->d.begin(); reg != instruction->d.end(); ++reg)
	{
		// the reg is alive outside the block
		if(block->aliveOut().count(*reg) != 0) return false;

		auto next = instruction;
		for(++next; next != block->instructions().end(); ++next)
		{
			for(auto source = next->s.begin();
				source != next->s.end(); ++source)
			{
				// found a user in the block
				if(*source->pointer == *reg->pointer) return false;
			}
		}
	}

	// There are no users and the instruction has no side effects
	return true;
}

static bool isOutputConstant(InstructionVector::iterator instruction)
{
	auto ptx = static_cast<ir::PTXInstruction*>(instruction->i);

	if(ptx->hasSideEffects()) return false;

	// The output is not constant if there are register inputs
	if(!instruction->s.empty()) return false;

	ir::PTXOperand* operands[] = {&ptx->a, &ptx->b, &ptx->c, &ptx->pg};

	for(unsigned int i = 0; i < 4; ++i)
	{
		if(operands[i]->addressMode == ir::PTXOperand::Invalid) continue;

		if(operands[i]->isRegister() && operands[i]->type == ir::PTXOperand::pred)
		{
			if(operands[i]->condition == ir::PTXOperand::PT ||
				operands[i]->condition == ir::PTXOperand::nPT)
			{
				continue;
			}
		}

		if(operands[i]->addressMode != ir::PTXOperand::Immediate)
		{
			report("    operand " << operands[i]->toString()
				<< " is not constant.");
			return false;
		}
	}

	return true;
}

static void replaceOperand(ir::PTXInstruction& ptx,
	ir::Instruction::RegisterType registerId,
	const ir::PTXOperand& immediate)
{
	ir::PTXOperand* operands[] = {&ptx.a, &ptx.b, &ptx.c, &ptx.pq,
		&ptx.d};

	unsigned int sources = 4;

	if(ptx.isStore()) ++sources;

	for(unsigned int i = 0; i < sources; ++i)
	{
		auto operand = operands[i];

		if(!operand->isRegister()) continue;

		if(operand->reg != registerId) continue;

		int offset = 0;

		if(operand->addressMode == ir::PTXOperand::Indirect)
		{
			offset = operand->offset;
		}

		*operand = immediate;

		operand->imm_uint += offset;
	}
}

static uint64_t getMask(const ir::PTXOperand& operand)
{
	uint64_t mask = (1ULL << (operand.bytes() * 8)) - 1;

	if(mask == 0) mask = 0xffffffffffffffffULL;

	return mask;
}

static uint64_t getValue(const ir::PTXOperand& operand)
{
	uint64_t value = operand.imm_uint;

	uint64_t mask = getMask(operand);;

	return value & mask;
}

static void setValue(ir::PTXOperand& operand, uint64_t value)
{
	uint64_t mask = getMask(operand);

	operand.imm_uint = value & mask;
}

static ir::PTXOperand computeCvtValue(const ir::PTXInstruction& ptx);
static ir::PTXOperand computeSetPValue(const ir::PTXInstruction& ptx);

static bool computeValue(ir::PTXOperand& result, const ir::PTXInstruction& ptx)
{
	result = ir::PTXOperand(ir::PTXOperand::Immediate, ptx.d.type);

	switch(ptx.opcode)
	{
	case ir::PTXInstruction::Add:
	{
		uint64_t a = getValue(ptx.a);
		uint64_t b = getValue(ptx.b);

		setValue(result, a + b);
		break;
	}
	case ir::PTXInstruction::And:
	{
		uint64_t a = getValue(ptx.a);
		uint64_t b = getValue(ptx.b);

		setValue(result, a & b);
		break;
	}
	case ir::PTXInstruction::Cvt:
	{
		result = computeCvtValue(ptx);
		break;
	}
	case ir::PTXInstruction::Mov:
	{
		setValue(result, getValue(ptx.a));
		break;
	}
	case ir::PTXInstruction::Mul:
	{
		uint64_t a = getValue(ptx.a);
		uint64_t b = getValue(ptx.b);

		assertM(ptx.modifier & ir::PTXInstruction::Lo,
			"Multiply modifier not implemented.");

		setValue(result, a * b);
		break;
	}
	case ir::PTXInstruction::SetP:
	{
		result = computeSetPValue(ptx);
		break;
	}
	case ir::PTXInstruction::Shr:
	{
		uint64_t a = getValue(ptx.a);
		uint64_t b = getValue(ptx.b);

		setValue(result, a >> b);
		break;
	}
	default:
	{
		return false;
	}
	}

	return true;
}

static void propagateValueToSuccessors(analysis::DataflowGraph& dfg,
	BlockSet& blocks, InstructionVector::iterator instruction)
{
	typedef analysis::DataflowGraph::RegisterPointerVector RegisterPointerVector;

	if(!isOutputConstant(instruction))
	{
		report("    output is not constant.");
		return;
	}

	auto ptx = static_cast<ir::PTXInstruction*>(instruction->i);

	if(ptx->isLoad())
	{
		report("    not allowed for loads.");
		return;
	}

	// TODO support instructions with multiple destinations
	if(instruction->d.size() != 1)
	{
		report("    no support for instructions with multiple destinations.");
		return;
	}

	// get the value
	ir::PTXOperand value;

	bool success = computeValue(value, *ptx);

	if(!success)
	{
		report("    could not determine the resulting value.");
		return;
	}

	// send it to successors
	auto registerId = *instruction->d.back().pointer;

	auto block = instruction->block;

	for(auto instruction = block->instructions().begin();
		instruction != block->instructions().end(); ++instruction)
	{
		auto ptx = static_cast<ir::PTXInstruction*>(instruction->i);

		RegisterPointerVector newSources;

		for(auto source = instruction->s.begin(); source !=
			instruction->s.end(); ++source)
		{
			if(*source->pointer == registerId)
			{
				report("    updated use by '" << ptx->toString()
					<< "', of r" << registerId);

				replaceOperand(*ptx, registerId, value);
			}
			else
			{
				newSources.push_back(*source);
			}
		}

		instruction->s = std::move(newSources);
	}

	// TODO handle successors in other blocks
}

static bool isTrivialCvt(const ir::PTXInstruction& ptx)
{
	if(ptx.a.type == ptx.type) return true;

	if(ptx.modifier != 0) return false;

	if(ir::PTXOperand::isInt(ptx.type))
	{
		if(ir::PTXOperand::isInt(ptx.type))
		{
			if(ir::PTXOperand::bytes(ptx.type) <=
				ir::PTXOperand::bytes(ptx.a.type))
			{
				return true;
			}

			if(!ir::PTXOperand::isSigned(ptx.type) &&
				!ir::PTXOperand::isSigned(ptx.a.type))
			{
				return true;
			}
		}
	}

	return false;
}

static ir::PTXOperand computeCvtValue(const ir::PTXInstruction& ptx)
{
	ir::PTXOperand result(ir::PTXOperand::Immediate, ptx.d.type);

	if(isTrivialCvt(ptx))
	{
		setValue(result, getValue(ptx.a));
	}

	return result;
}

static ir::PTXOperand computeSetPValue(const ir::PTXInstruction& ptx)
{
	ir::PTXOperand result(ir::PTXOperand::Immediate, ptx.d.type);

	uint64_t a = getValue(ptx.a);
	uint64_t b = getValue(ptx.b);

	switch(ptx.comparisonOperator)
	{
	case ir::PTXInstruction::Eq:
	{
		setValue(result, a == b);
		break;
	}
	default:
	{
		assertM(false, "Not implemented.");
	}
	}

	return result;
}

}

<|endoftext|>