<commit_before>#include "askpassphrasedialog.h"
#include "ui_askpassphrasedialog.h"

#include "guiconstants.h"
#include "walletmodel.h"

#include <QMessageBox>
#include <QPushButton>
#include <QKeyEvent>

extern bool fWalletUnlockStakingOnly;

AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AskPassphraseDialog),
    mode(mode),
    model(0),
    fCapsLock(false)
{
    ui->setupUi(this);
    ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);

    // Setup Caps Lock detection.
    ui->passEdit1->installEventFilter(this);
    ui->passEdit2->installEventFilter(this);
    ui->passEdit3->installEventFilter(this);

    ui->stakingCheckBox->setChecked(fWalletUnlockStakingOnly);

    switch(mode)
    {
        case Encrypt: // Ask passphrase x2
            ui->passLabel1->hide();
            ui->passEdit1->hide();
            ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of 10 or more random characters, or eight or more words."));
            setWindowTitle(tr("Encrypt wallet"));
            break;
        case UnlockStaking:
            ui->stakingCheckBox->setChecked(true);
            ui->stakingCheckBox->show();
            // fallthru
        case Unlock: // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Unlock wallet"));
            break;
        case Decrypt:   // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Decrypt wallet"));
            break;
        case ChangePass: // Ask old passphrase + new passphrase x2
            setWindowTitle(tr("Change passphrase"));
            ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
            break;
    }

    textChanged();
    connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
}

AskPassphraseDialog::~AskPassphraseDialog()
{
    secureClearPassFields();
    delete ui;
}

void AskPassphraseDialog::setModel(WalletModel *model)
{
    this->model = model;
}

void AskPassphraseDialog::accept()
{
    SecureString oldpass, newpass1, newpass2;
    if(!model)
        return;
    oldpass.reserve(MAX_PASSPHRASE_SIZE);
    newpass1.reserve(MAX_PASSPHRASE_SIZE);
    newpass2.reserve(MAX_PASSPHRASE_SIZE);
    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    // Alternately, find a way to make this input mlock()'d to begin with.
    oldpass.assign(ui->passEdit1->text().toStdString().c_str());
    newpass1.assign(ui->passEdit2->text().toStdString().c_str());
    newpass2.assign(ui->passEdit3->text().toStdString().c_str());

    secureClearPassFields();

    switch(mode)
    {
    case Encrypt: {
        if(newpass1.empty() || newpass2.empty())
        {
            // Cannot encrypt with empty passphrase
            break;
        }
        QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
                 tr("Warning: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR COINS!") + "

" + tr("Are you sure you wish to encrypt your wallet?"),
                 QMessageBox::Yes|QMessageBox::Cancel,
                 QMessageBox::Cancel);
        if(retval == QMessageBox::Yes)
        {
            if(newpass1 == newpass2)
            {
                if(model->setWalletEncrypted(true, newpass1))
                {
                    QMessageBox::warning(this, tr("Wallet encrypted"),
                                         "<qt>" +
                                         tr("Okcash will close now to finish the encryption process. "
                                         "Remember that encrypting your wallet cannot fully protect "
                                         "your coins from being stolen by malware infecting your computer.") +
                                         "

" +
                                         tr("IMPORTANT: Any previous backups you have made of your wallet file "
                                         "should be replaced with the newly generated, encrypted wallet file. "
                                         "For security reasons, previous backups of the unencrypted wallet file "
                                         "will become useless as soon as you start using the new, encrypted wallet.") +
                                         "</qt>");
                    QApplication::quit();
                }
                else
                {
                    QMessageBox::critical(this, tr("Wallet encryption failed"),
                                         tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
                }
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The supplied passphrases do not match."));
            }
        }
        else
        {
            QDialog::reject(); // Cancelled
        }
        } break;
    case UnlockStaking:
    case Unlock:
        if(!model->setWalletLocked(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet unlock failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            fWalletUnlockStakingOnly = ui->stakingCheckBox->isChecked();
            QDialog::accept(); // Success
        }
        break;
    case Decrypt:
        if(!model->setWalletEncrypted(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet decryption failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case ChangePass:
        if(newpass1 == newpass2)
        {
            if(model->changePassphrase(oldpass, newpass1))
            {
                QMessageBox::information(this, tr("Wallet encrypted"),
                                     tr("Wallet passphrase was successfully changed."));
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The passphrase entered for the wallet decryption was incorrect."));
            }
        }
        else
        {
            QMessageBox::critical(this, tr("Wallet encryption failed"),
                                 tr("The supplied passphrases do not match."));
        }
        break;
    }
}

void AskPassphraseDialog::textChanged()
{
    // Validate input, set Ok button to enabled when acceptable
    bool acceptable = false;
    switch(mode)
    {
    case Encrypt: // New passphrase x2
        acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    case UnlockStaking:
    case Unlock: // Old passphrase x1
    case Decrypt:
        acceptable = !ui->passEdit1->text().isEmpty();
        break;
    case ChangePass: // Old passphrase x1, new passphrase x2
        acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    }
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
}

bool AskPassphraseDialog::event(QEvent *event)
{
    // Detect Caps Lock key press.
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        if (ke->key() == Qt::Key_CapsLock) {
            fCapsLock = !fCapsLock;
        }
        if (fCapsLock) {
            ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
        } else {
            ui->capsLabel->clear();
        }
    }
    return QWidget::event(event);
}

bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
{
    /* Detect Caps Lock.
     * There is no good OS-independent way to check a key state in Qt, but we
     * can detect Caps Lock by checking for the following condition:
     * Shift key is down and the result is a lower case character, or
     * Shift key is not down and the result is an upper case character.
     */
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        QString str = ke->text();
        if (str.length() != 0) {
            const QChar *psz = str.unicode();
            bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
            if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) {
                fCapsLock = true;
                ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
            } else if (psz->isLetter()) {
                fCapsLock = false;
                ui->capsLabel->clear();
            }
        }
    }
    return QDialog::eventFilter(object, event);
}

void AskPassphraseDialog::secureClearPassFields()
{
    // Attempt to overwrite text so that they do not linger around in memory
    ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
    ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
    ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));

    ui->passEdit1->clear();
    ui->passEdit2->clear();
    ui->passEdit3->clear();
}
<commit_msg>unlock for okcashv2 upgrd<commit_after>#include "askpassphrasedialog.h"
#include "ui_askpassphrasedialog.h"

#include "guiconstants.h"
#include "walletmodel.h"

#include <QMessageBox>
#include <QPushButton>
#include <QKeyEvent>

extern bool fWalletUnlockStakingOnly;
extern bool fWalletUnlockMessagingEnabled;

AskPassphraseDialog::AskPassphraseDialog(Mode mode, QWidget *parent) :
    QDialog(parent),
    ui(new Ui::AskPassphraseDialog),
    mode(mode),
    model(0),
    fCapsLock(false)
{
    ui->setupUi(this);
    ui->passEdit1->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit2->setMaxLength(MAX_PASSPHRASE_SIZE);
    ui->passEdit3->setMaxLength(MAX_PASSPHRASE_SIZE);

    // Setup Caps Lock detection.
    ui->passEdit1->installEventFilter(this);
    ui->passEdit2->installEventFilter(this);
    ui->passEdit3->installEventFilter(this);

    ui->stakingCheckBox->setChecked(fWalletUnlockStakingOnly);
    ui->messagingCheckBox->setChecked(fWalletUnlockMessagingEnabled);

    switch(mode)
    {
        case Encrypt: // Ask passphrase x2
            ui->passLabel1->hide();
            ui->passEdit1->hide();
            ui->warningLabel->setText(tr("Enter the new passphrase to the wallet.
Please use a passphrase of 10 or more random characters, or eight or more words."));
            setWindowTitle(tr("Encrypt wallet"));
            break;
        case UnlockStaking:
            ui->stakingCheckBox->setChecked(true);
            ui->stakingCheckBox->show();
            // fallthru
        case UnlockMessaging:
            ui->messagingCheckBox->setChecked(true);
            ui->messagingCheckBox->show();

        case Unlock: // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to unlock the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Unlock wallet"));
            break;
        case Decrypt:   // Ask passphrase
            ui->warningLabel->setText(tr("This operation needs your wallet passphrase to decrypt the wallet."));
            ui->passLabel2->hide();
            ui->passEdit2->hide();
            ui->passLabel3->hide();
            ui->passEdit3->hide();
            setWindowTitle(tr("Decrypt wallet"));
            break;
        case ChangePass: // Ask old passphrase + new passphrase x2
            setWindowTitle(tr("Change passphrase"));
            ui->warningLabel->setText(tr("Enter the old and new passphrase to the wallet."));
            break;
    }

    textChanged();
    connect(ui->passEdit1, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit2, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
    connect(ui->passEdit3, SIGNAL(textChanged(QString)), this, SLOT(textChanged()));
}

AskPassphraseDialog::~AskPassphraseDialog()
{
    secureClearPassFields();
    delete ui;
}

void AskPassphraseDialog::setModel(WalletModel *model)
{
    this->model = model;
}

void AskPassphraseDialog::accept()
{
    SecureString oldpass, newpass1, newpass2;
    if(!model)
        return;
    oldpass.reserve(MAX_PASSPHRASE_SIZE);
    newpass1.reserve(MAX_PASSPHRASE_SIZE);
    newpass2.reserve(MAX_PASSPHRASE_SIZE);
    // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
    // Alternately, find a way to make this input mlock()'d to begin with.
    oldpass.assign(ui->passEdit1->text().toStdString().c_str());
    newpass1.assign(ui->passEdit2->text().toStdString().c_str());
    newpass2.assign(ui->passEdit3->text().toStdString().c_str());

    secureClearPassFields();

    switch(mode)
    {
    case Encrypt: {
        if(newpass1.empty() || newpass2.empty())
        {
            // Cannot encrypt with empty passphrase
            break;
        }
        QMessageBox::StandardButton retval = QMessageBox::question(this, tr("Confirm wallet encryption"),
                 tr("Warning: If you encrypt your wallet and lose your passphrase, you will LOSE ALL OF YOUR COINS!") + "

" + tr("Are you sure you wish to encrypt your wallet?"),
                 QMessageBox::Yes|QMessageBox::Cancel,
                 QMessageBox::Cancel);
        if(retval == QMessageBox::Yes)
        {
            if(newpass1 == newpass2)
            {
                if(model->setWalletEncrypted(true, newpass1))
                {
                    QMessageBox::warning(this, tr("Wallet encrypted"),
                                         "<qt>" +
                                         tr("Okcash will close now to finish the encryption process. "
                                         "Remember that encrypting your wallet cannot fully protect "
                                         "your coins from being stolen by malware infecting your computer.") +
                                         "

" +
                                         tr("IMPORTANT: Any previous backups you have made of your wallet file "
                                         "should be replaced with the newly generated, encrypted wallet file. "
                                         "For security reasons, previous backups of the unencrypted wallet file "
                                         "will become useless as soon as you start using the new, encrypted wallet.") +
                                         "</qt>");
                    QApplication::quit();
                }
                else
                {
                    QMessageBox::critical(this, tr("Wallet encryption failed"),
                                         tr("Wallet encryption failed due to an internal error. Your wallet was not encrypted."));
                }
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The supplied passphrases do not match."));
            }
        }
        else
        {
            QDialog::reject(); // Cancelled
        }
        } break;
    case UnlockStaking:
    case Unlock:
        if(!model->setWalletLocked(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet unlock failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            fWalletUnlockStakingOnly = ui->stakingCheckBox->isChecked();
            fWalletUnlockMessagingEnabled = ui->messagingCheckBox->isChecked();
            QDialog::accept(); // Success
        }
        break;
    case Decrypt:
        if(!model->setWalletEncrypted(false, oldpass))
        {
            QMessageBox::critical(this, tr("Wallet decryption failed"),
                                  tr("The passphrase entered for the wallet decryption was incorrect."));
        }
        else
        {
            QDialog::accept(); // Success
        }
        break;
    case ChangePass:
        if(newpass1 == newpass2)
        {
            if(model->changePassphrase(oldpass, newpass1))
            {
                QMessageBox::information(this, tr("Wallet encrypted"),
                                     tr("Wallet passphrase was successfully changed."));
                QDialog::accept(); // Success
            }
            else
            {
                QMessageBox::critical(this, tr("Wallet encryption failed"),
                                     tr("The passphrase entered for the wallet decryption was incorrect."));
            }
        }
        else
        {
            QMessageBox::critical(this, tr("Wallet encryption failed"),
                                 tr("The supplied passphrases do not match."));
        }
        break;
    }
}

void AskPassphraseDialog::textChanged()
{
    // Validate input, set Ok button to enabled when acceptable
    bool acceptable = false;
    switch(mode)
    {
    case Encrypt: // New passphrase x2
        acceptable = !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    case UnlockStaking:
    case Unlock: // Old passphrase x1
    case Decrypt:
        acceptable = !ui->passEdit1->text().isEmpty();
        break;
    case ChangePass: // Old passphrase x1, new passphrase x2
        acceptable = !ui->passEdit1->text().isEmpty() && !ui->passEdit2->text().isEmpty() && !ui->passEdit3->text().isEmpty();
        break;
    }
    ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(acceptable);
}

bool AskPassphraseDialog::event(QEvent *event)
{
    // Detect Caps Lock key press.
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        if (ke->key() == Qt::Key_CapsLock) {
            fCapsLock = !fCapsLock;
        }
        if (fCapsLock) {
            ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
        } else {
            ui->capsLabel->clear();
        }
    }
    return QWidget::event(event);
}

bool AskPassphraseDialog::eventFilter(QObject *object, QEvent *event)
{
    /* Detect Caps Lock.
     * There is no good OS-independent way to check a key state in Qt, but we
     * can detect Caps Lock by checking for the following condition:
     * Shift key is down and the result is a lower case character, or
     * Shift key is not down and the result is an upper case character.
     */
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *ke = static_cast<QKeyEvent *>(event);
        QString str = ke->text();
        if (str.length() != 0) {
            const QChar *psz = str.unicode();
            bool fShift = (ke->modifiers() & Qt::ShiftModifier) != 0;
            if ((fShift && psz->isLower()) || (!fShift && psz->isUpper())) {
                fCapsLock = true;
                ui->capsLabel->setText(tr("Warning: The Caps Lock key is on!"));
            } else if (psz->isLetter()) {
                fCapsLock = false;
                ui->capsLabel->clear();
            }
        }
    }
    return QDialog::eventFilter(object, event);
}

void AskPassphraseDialog::secureClearPassFields()
{
    // Attempt to overwrite text so that they do not linger around in memory
    ui->passEdit1->setText(QString(" ").repeated(ui->passEdit1->text().size()));
    ui->passEdit2->setText(QString(" ").repeated(ui->passEdit2->text().size()));
    ui->passEdit3->setText(QString(" ").repeated(ui->passEdit3->text().size()));

    ui->passEdit1->clear();
    ui->passEdit2->clear();
    ui->passEdit3->clear();
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_TIMESTAMP_HPP
#define REALM_COLUMN_TIMESTAMP_HPP

#include <realm/column.hpp>

namespace realm {

struct Timestamp {
    Timestamp(int64_t seconds, uint32_t nanoseconds) : m_seconds(seconds), m_nanoseconds(nanoseconds), m_is_null(false)
    {
        REALM_ASSERT_3(nanoseconds, <, nanoseconds_per_second);
    }
    Timestamp() : m_is_null(true) { }

    bool is_null() const { return m_is_null; }

    // Note that nullability is handled by query system. These operators are only invoked for non-null dates.
    bool operator==(const Timestamp& rhs) const { return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; }
    bool operator!=(const Timestamp& rhs) const { return m_seconds != rhs.m_seconds || m_nanoseconds != rhs.m_nanoseconds; }
    bool operator>(const Timestamp& rhs) const { return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); }
    bool operator<(const Timestamp& rhs) const { return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); }
    bool operator<=(const Timestamp& rhs) const { return *this < rhs || *this == rhs; }
    bool operator>=(const Timestamp& rhs) const { return *this > rhs || *this == rhs; }
    Timestamp& operator=(const Timestamp& rhs) = default;

    template<class Ch, class Tr>
    friend std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& out, const Timestamp&);

    int64_t m_seconds;
    uint32_t m_nanoseconds;
    bool m_is_null;

    static constexpr uint32_t nanoseconds_per_second = 1000000000;
};

template<class C, class T>
inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const Timestamp& d)
{
    out << "Timestamp(" << d.m_seconds << ", " << d.m_nanoseconds << ")";
    return out;
}

// Inherits from ColumnTemplate to get a compare_values() that can be called without knowing the
// column type
class TimestampColumn : public ColumnBaseSimple, public ColumnTemplate<Timestamp> {
public:
    TimestampColumn(Allocator& alloc, ref_type ref);
    ~TimestampColumn() noexcept override;

    static ref_type create(Allocator& alloc, size_t size = 0);

    /// Get the number of entries in this column. This operation is relatively
    /// slow.
    size_t size() const noexcept override;
    /// Whether or not this column is nullable.
    bool is_nullable() const noexcept override;
    /// Whether or not the value at \a row_ndx is NULL. If the column is not
    /// nullable, always returns false.
    bool is_null(size_t row_ndx) const noexcept override;
    /// Sets the value at \a row_ndx to be NULL.
    /// \throw LogicError Thrown if this column is not nullable.
    void set_null(size_t row_ndx) override;
    void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
    void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                    bool broken_reciprocal_backlinks) override;
    void move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                            bool broken_reciprocal_backlinks) override;
    void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
    void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
    void destroy() noexcept override;

    bool has_search_index() const noexcept final { return bool(m_search_index); }
    StringIndex* get_search_index() noexcept final { return m_search_index.get(); }
    void destroy_search_index() noexcept override;
    void set_search_index_ref(ref_type ref, ArrayParent* parent, size_t ndx_in_parent,
            bool allow_duplicate_values) final;
    void populate_search_index();
    StringIndex* create_search_index() override;

    StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
    ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
    void update_from_parent(size_t old_baseline) noexcept override;
    void set_ndx_in_parent(size_t ndx) noexcept override;
    void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;
#ifdef REALM_DEBUG
    void verify() const override;
    void to_dot(std::ostream&, StringData title = StringData()) const override;
    void do_dump_node_structure(std::ostream&, int level) const override;
    void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;
#endif
    void add(const Timestamp& ts = Timestamp{});
    Timestamp get(size_t row_ndx) const noexcept;
    Timestamp get_val(size_t row_ndx) const noexcept override { return get(row_ndx); }
    void set(size_t row_ndx, const Timestamp& ts);
    bool compare(const TimestampColumn& c) const noexcept;

    Timestamp maximum(size_t& result_index) const;
    Timestamp minimum(size_t& result_index) const;
    size_t count(Timestamp) const;
    void erase(size_t row_ndx, bool is_last);

    template <class Condition>
    size_t find(Timestamp value, size_t begin, size_t end) const noexcept
    {
        // FIXME: Here we can do all sorts of clever optimizations. Use bithack-search on seconds, then for each match check
        // nanoseconds, etc, etc, etc. Lots of possibilities. Below code is naive and slow but works.

        Condition cond;
        for (size_t t = begin; t < end; t++) {
            Timestamp ts = get(t);
            if (cond(ts, value, ts.is_null(), value.is_null()))
                return t;
        }
        return npos;
    }

    typedef Timestamp value_type;

private:
    std::unique_ptr<BpTree<util::Optional<int64_t>>> m_seconds;
    std::unique_ptr<BpTree<int64_t>> m_nanoseconds;

    std::unique_ptr<StringIndex> m_search_index;

    template<class BT>
    class CreateHandler;

    template <class Condition>
    Timestamp minmax(size_t& result_index) const noexcept
    {
        // Condition is realm::Greater for maximum and realm::Less for minimum.
        Timestamp best;
        result_index = npos;

        if (size() > 0) {
            best = get(0);
            result_index = 0;
        }

        for (size_t i = 0; i < size(); ++i) {
            if (Condition()(get(i), best, get(i).is_null(), best.is_null())) {
                best = get(i);
                result_index = i;
            }
        }
        return best;
    }
};

} // namespace realm

#endif // REALM_COLUMN_TIMESTAMP_HPP
<commit_msg>Simplified TimestampColumn::minmax()<commit_after>/*************************************************************************
 *
 * REALM CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2015] Realm Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Realm Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Realm Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Realm Incorporated.
 *
 **************************************************************************/
#ifndef REALM_COLUMN_TIMESTAMP_HPP
#define REALM_COLUMN_TIMESTAMP_HPP

#include <realm/column.hpp>

namespace realm {

struct Timestamp {
    Timestamp(int64_t seconds, uint32_t nanoseconds) : m_seconds(seconds), m_nanoseconds(nanoseconds), m_is_null(false)
    {
        REALM_ASSERT_3(nanoseconds, <, nanoseconds_per_second);
    }
    Timestamp() : m_is_null(true) { }

    bool is_null() const { return m_is_null; }

    // Note that nullability is handled by query system. These operators are only invoked for non-null dates.
    bool operator==(const Timestamp& rhs) const { return m_seconds == rhs.m_seconds && m_nanoseconds == rhs.m_nanoseconds; }
    bool operator!=(const Timestamp& rhs) const { return m_seconds != rhs.m_seconds || m_nanoseconds != rhs.m_nanoseconds; }
    bool operator>(const Timestamp& rhs) const { return (m_seconds > rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds > rhs.m_nanoseconds); }
    bool operator<(const Timestamp& rhs) const { return (m_seconds < rhs.m_seconds) || (m_seconds == rhs.m_seconds && m_nanoseconds < rhs.m_nanoseconds); }
    bool operator<=(const Timestamp& rhs) const { return *this < rhs || *this == rhs; }
    bool operator>=(const Timestamp& rhs) const { return *this > rhs || *this == rhs; }
    Timestamp& operator=(const Timestamp& rhs) = default;

    template<class Ch, class Tr>
    friend std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& out, const Timestamp&);

    int64_t m_seconds;
    uint32_t m_nanoseconds;
    bool m_is_null;

    static constexpr uint32_t nanoseconds_per_second = 1000000000;
};

template<class C, class T>
inline std::basic_ostream<C, T>& operator<<(std::basic_ostream<C, T>& out, const Timestamp& d)
{
    out << "Timestamp(" << d.m_seconds << ", " << d.m_nanoseconds << ")";
    return out;
}

// Inherits from ColumnTemplate to get a compare_values() that can be called without knowing the
// column type
class TimestampColumn : public ColumnBaseSimple, public ColumnTemplate<Timestamp> {
public:
    TimestampColumn(Allocator& alloc, ref_type ref);
    ~TimestampColumn() noexcept override;

    static ref_type create(Allocator& alloc, size_t size = 0);

    /// Get the number of entries in this column. This operation is relatively
    /// slow.
    size_t size() const noexcept override;
    /// Whether or not this column is nullable.
    bool is_nullable() const noexcept override;
    /// Whether or not the value at \a row_ndx is NULL. If the column is not
    /// nullable, always returns false.
    bool is_null(size_t row_ndx) const noexcept override;
    /// Sets the value at \a row_ndx to be NULL.
    /// \throw LogicError Thrown if this column is not nullable.
    void set_null(size_t row_ndx) override;
    void insert_rows(size_t row_ndx, size_t num_rows_to_insert, size_t prior_num_rows, bool nullable) override;
    void erase_rows(size_t row_ndx, size_t num_rows_to_erase, size_t prior_num_rows,
                    bool broken_reciprocal_backlinks) override;
    void move_last_row_over(size_t row_ndx, size_t prior_num_rows,
                            bool broken_reciprocal_backlinks) override;
    void clear(size_t num_rows, bool broken_reciprocal_backlinks) override;
    void swap_rows(size_t row_ndx_1, size_t row_ndx_2) override;
    void destroy() noexcept override;

    bool has_search_index() const noexcept final { return bool(m_search_index); }
    StringIndex* get_search_index() noexcept final { return m_search_index.get(); }
    void destroy_search_index() noexcept override;
    void set_search_index_ref(ref_type ref, ArrayParent* parent, size_t ndx_in_parent,
            bool allow_duplicate_values) final;
    void populate_search_index();
    StringIndex* create_search_index() override;

    StringData get_index_data(size_t, StringIndex::StringConversionBuffer& buffer) const noexcept override;
    ref_type write(size_t slice_offset, size_t slice_size, size_t table_size, _impl::OutputStream&) const override;
    void update_from_parent(size_t old_baseline) noexcept override;
    void set_ndx_in_parent(size_t ndx) noexcept override;
    void refresh_accessor_tree(size_t new_col_ndx, const Spec&) override;
#ifdef REALM_DEBUG
    void verify() const override;
    void to_dot(std::ostream&, StringData title = StringData()) const override;
    void do_dump_node_structure(std::ostream&, int level) const override;
    void leaf_to_dot(MemRef, ArrayParent*, size_t ndx_in_parent, std::ostream&) const override;
#endif
    void add(const Timestamp& ts = Timestamp{});
    Timestamp get(size_t row_ndx) const noexcept;
    Timestamp get_val(size_t row_ndx) const noexcept override { return get(row_ndx); }
    void set(size_t row_ndx, const Timestamp& ts);
    bool compare(const TimestampColumn& c) const noexcept;

    Timestamp maximum(size_t& result_index) const;
    Timestamp minimum(size_t& result_index) const;
    size_t count(Timestamp) const;
    void erase(size_t row_ndx, bool is_last);

    template <class Condition>
    size_t find(Timestamp value, size_t begin, size_t end) const noexcept
    {
        // FIXME: Here we can do all sorts of clever optimizations. Use bithack-search on seconds, then for each match check
        // nanoseconds, etc, etc, etc. Lots of possibilities. Below code is naive and slow but works.

        Condition cond;
        for (size_t t = begin; t < end; t++) {
            Timestamp ts = get(t);
            if (cond(ts, value, ts.is_null(), value.is_null()))
                return t;
        }
        return npos;
    }

    typedef Timestamp value_type;

private:
    std::unique_ptr<BpTree<util::Optional<int64_t>>> m_seconds;
    std::unique_ptr<BpTree<int64_t>> m_nanoseconds;

    std::unique_ptr<StringIndex> m_search_index;

    template<class BT>
    class CreateHandler;

    template <class Condition>
    Timestamp minmax(size_t& result_index) const noexcept
    {
        // Condition is realm::Greater for maximum and realm::Less for minimum.

        if (size() == 0) {
            result_index = npos;
            return Timestamp();
        }

        Timestamp best = get(0);
        result_index = 0;

        for (size_t i = 1; i < size(); ++i) {
            if (Condition()(get(i), best, get(i).is_null(), best.is_null())) {
                best = get(i);
                result_index = i;
            }
        }
        return best;
    }
};

} // namespace realm

#endif // REALM_COLUMN_TIMESTAMP_HPP
<|endoftext|>


<commit_before>/*
    I actually got tricked into working hard and ended up wasting half a day
    when a such a naive solution works.

    :<
*/

#include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <unordered_set>
#include "prime_util.h"
#include "number_util.h"

void search(
    int N,
    std::vector<int> &primes,
    std::vector<std::vector<int>> &powers,
    std::vector<int> &solution,
    int sum_solution,
    int index,
    std::unordered_set<int> &results)
{
    if (solution.size() == powers.size())
    {
        results.emplace(sum_solution);
        return;
    }

    for (int &power : powers[index])
    {
        if (sum_solution + power >= N)
            break;
        std::vector<int> _solution(solution);
        _solution.emplace_back(power);
        search(N, primes, powers, _solution, sum_solution + power, index + 1, results);
    }
}

int main()
{
    int N = 50000000;
    std::vector<int> primes = util::get_primes(int(std::sqrt(N)));
    std::vector<std::vector<int>> powers = { { }, { }, { } };

    for (int e = 2; e < 5; e++)
    {
        for (int &prime : primes)
        {
            int power = util::mpz_to<int>(util::pow(prime, e));
            if (power > N)
                break;
            powers[e - 2].emplace_back(power);
        }
    }

    std::unordered_set<int> results;
    std::vector<int> solution;
    search(N, primes, powers, solution, 0, 0, results);

    std::cout << results.size();
}
<commit_msg>Enforce const correctness.<commit_after>/*
    I actually got tricked into working hard and ended up wasting half a day
    when a such a naive solution works.

    :<
*/

#include <iostream>
#include <vector>
#include <cmath>
#include <numeric>
#include <unordered_set>
#include "prime_util.h"
#include "number_util.h"

void search(
    int N,
    std::vector<int> const &primes,
    std::vector<std::vector<int>> const &powers,
    std::vector<int> const &solution,
    int sum_solution,
    int index,
    std::unordered_set<int> &results)
{
    if (solution.size() == powers.size())
    {
        results.emplace(sum_solution);
        return;
    }

    for (int const &power : powers[index])
    {
        if (sum_solution + power >= N)
            break;
        std::vector<int> _solution(solution);
        _solution.emplace_back(power);
        search(N, primes, powers, _solution, sum_solution + power, index + 1, results);
    }
}

int main()
{
    int N = 50000000;
    std::vector<int> primes = util::get_primes(int(std::sqrt(N)));
    std::vector<std::vector<int>> powers = { { }, { }, { } };

    for (int e = 2; e < 5; e++)
    {
        for (int &prime : primes)
        {
            int power = util::mpz_to<int>(util::pow(prime, e));
            if (power > N)
                break;
            powers[e - 2].emplace_back(power);
        }
    }

    std::unordered_set<int> results;
    std::vector<int> solution;
    search(N, primes, powers, solution, 0, 0, results);

    std::cout << results.size();
}
<|endoftext|>


<commit_before>class Solution {
public:
    int titleToNumber(string s) {
        int ans=0,mul=1;
        for(int i=s.size()-1;i>=0;i--){
            ans+=(s[i]-'A'+1)*mul;
            mul*=26;
        }
        return ans;
    }
};
<commit_msg>Excel Sheet Column Number<commit_after>class Solution {
public:
    int titleToNumber(string s) {
        int ans=0,mul=1;
        for(int i=s.size()-1;i>=0;i--){
            ans+=(s[i]-'A'+1)*mul;
            mul*=26;
        }
        return ans;
    }
};

<|endoftext|>


<commit_before>#include "Zookeeper.hpp"

Gpu::Gpu() {
	box->cpu->map_io(0xFD000000, PAGE_SIZE, (MMIOReceiver *) this); // 16MB address space
}

uint32_t Gpu::read(uint32_t addr) {
	cout << format("Gpu::read(0x%08x)") % addr << endl;

	switch(addr) {
		case 0xfd100200:
			return 3;
		default:
			return addr;
	}
}

void Gpu::write(uint32_t addr, uint32_t value) {
	if(addr > 0xfd700000 && addr <= 0xfd705000)
		return;
	cout << format("Gpu::write(0x%08x, 0x%08x)") % addr % value << endl;
}
<commit_msg>Reverted constant in Gpu case.<commit_after>#include "Zookeeper.hpp"

Gpu::Gpu() {
	box->cpu->map_io(0xFD000000, 4096, (MMIOReceiver *) this); // 4096 pages * 4KB == 16MB address space
}

uint32_t Gpu::read(uint32_t addr) {
	cout << format("Gpu::read(0x%08x)") % addr << endl;

	switch(addr) {
		case 0xfd100200:
			return 3;
		default:
			return addr;
	}
}

void Gpu::write(uint32_t addr, uint32_t value) {
	if(addr > 0xfd700000 && addr <= 0xfd705000)
		return;
	cout << format("Gpu::write(0x%08x, 0x%08x)") % addr % value << endl;
}
<|endoftext|>


<commit_before>// BUG: this whole thing depends on the specifics of how the clang version I
// am using emits llvm bitcode for the hacky RMC protocol.
// We rely on how basic blocks get named, on the labels forcing things
// into their own basic blocks, and probably will rely on this block
// having one predecessor and one successor. We could probably even
// force those to be empty without too much work by adding more labels...

#include <llvm/Pass.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/InlineAsm.h>
#include <llvm/IR/CFG.h>
#include <llvm/IR/InstIterator.h>
#include <llvm/Transforms/Scalar.h>

#include <llvm/ADT/ArrayRef.h>

#include <llvm/Transforms/Utils/BasicBlockUtils.h>
#include <llvm/Support/raw_ostream.h>

#include <ostream>
#include <fstream>
#include <iostream>
#include <map>
#include <set>

using namespace llvm;

namespace {
#if 0 // I hate you, emacs. Is there a better way to work around this?
}
#endif

/* To do bogus data dependencies, we will emit inline assembly
  instructions. This is sort of tasteless; we should add an intrinsic;
  but it means we don't need to modify llvm. This is what the
  instruction should look like (probably the constraints aren't
  right?):

  %2 = call i32 asm sideeffect "eor $0, $0;", "=r,0"(i32 %1) #2, !srcloc !11

  Also for ctrlisb we do:
  call void asm sideeffect "cmp $0, $0;beq 1f;1: isb", "r,~{memory}"(i32 %1) #2, !srcloc !4

  And for dmb:
  call void asm sideeffect "dmb", "~{memory}"() #2, !srcloc !5

  We can probably do a bogus inline asm on x86 to prevent reordering:
  %2 = call i32 asm sideeffect "", "=r,r,0,~{dirflag},~{fpsr},~{flags}"(i32 %1, i32 %0) #3, !srcloc !9

  What about this makes the right value come out:
    =r specifies an output parameter and the 0 says that that input parameter
    is paired with param 0.

  Hm. Does this *actually* work?? What does "sideeffect" actually mean
  for asm and do we need it.

  --
  Should we emit dmb directly, or try to use llvm's fences?
*/

//// Some auxillary data structures
enum RMCEdgeType {
  VisbilityEdge,
  ExecutionEdge
};

raw_ostream& operator<<(raw_ostream& os, const RMCEdgeType& t) {
  switch (t) {
    case VisbilityEdge:
      os << "v";
      break;
    case ExecutionEdge:
      os << "x";
      break;
    default:
      os << "?";
      break;
  }
  return os;
}

// Info about an RMC edge
struct RMCEdge {
  RMCEdgeType edgeType;
  BasicBlock *src;
  BasicBlock *dst;

  bool operator<(const RMCEdge& rhs) const {
    return std::tie(edgeType, src, dst)
      < std::tie(rhs.edgeType, rhs.src, rhs.dst);
  }

  void print(raw_ostream &os) const {
    // substr(5) is to drop "_rmc_" from the front
    os << src->getName().substr(5) << " -" << edgeType <<
      "-> " << dst->getName().substr(5);
  }
};

raw_ostream& operator<<(raw_ostream& os, const RMCEdge& e) {
  e.print(os);
  return os;
}

///////////////////////////////////////////////////////////////////////////
// Information for a node in the RMC graph.
enum ActionType {
  ActionComplex,
  ActionSimpleRead,
  ActionSimpleWrites, // needs to be paired with a dep
  ActionSimpleRMW
};
struct Action {
  Action(BasicBlock *p_bb) :
    bb(p_bb),
    type(ActionComplex),
    stores(0), loads(0), RMWs(0), calls(0), soleLoad(nullptr) {}
  void operator=(const Action &) LLVM_DELETED_FUNCTION;
  Action(const Action &) LLVM_DELETED_FUNCTION;
  Action(Action &&) = default; // move constructor!

  BasicBlock *bb;

  // Some basic info about what sort of instructions live in the action
  ActionType type;
  int stores;
  int loads;
  int RMWs;
  int calls;
  LoadInst *soleLoad;

  // Edges in the graph.
  // XXX: Would we be better off storing this some other way?
  // a <ptr, type> pair?
  // And should we store v edges in x
  SmallPtrSet<Action *, 2> execEdges;
  SmallPtrSet<Action *, 2> visEdges;
};

enum CutType {
  CutNone,
  CutCtrlIsync, // needs to be paired with a dep
  CutLwsync,
  CutSync
};
struct EdgeCut {
  EdgeCut() : type(CutNone), front(false), read(nullptr) {}
  CutType type;
  bool front;
  Value *read;
};

///////////////////////////////////////////////////////////////////////////
// Code to find all simple paths between two basic blocks.
// Could generalize more to graphs if we wanted, but I don't right
// now.
typedef std::vector<BasicBlock *> Path;
typedef SmallVector<Path, 2> PathList;
typedef SmallPtrSet<BasicBlock *, 8> GreySet;

PathList findAllSimplePaths_(GreySet *grey, BasicBlock *src, BasicBlock *dst) {
  PathList paths;
  if (grey->count(src)) return paths;
  if (src == dst) {
    Path path;
    path.push_back(dst);
    paths.push_back(std::move(path));
    return paths;
  }

  grey->insert(src);

  // Go search all the successors
  for (auto i = succ_begin(src), e = succ_end(src); i != e; i++) {
    PathList subpaths = findAllSimplePaths_(grey, *i, dst);
    std::move(subpaths.begin(), subpaths.end(), back_inserter(paths));
  }

  // Add our step to all of the vectors
  for (auto & path : paths) {
    path.push_back(src);
  }

  // Remove it from the set of things we've seen. We might come
  // through here again.
  // We can't really do any sort of memoization, since in a cyclic
  // graph the possible simple paths depend not just on what node we
  // are on, but our previous path (to avoid looping).
  grey->erase(src);

  return paths;
}

PathList findAllSimplePaths(BasicBlock *src, BasicBlock *dst) {
  GreySet grey;
  return findAllSimplePaths_(&grey, src, dst);
}

void dumpPaths(const PathList &paths) {
  for (auto & path : paths) {
    for (auto block : path) {
      errs() << block->getName() << " <- ";
    }
    errs() << "\n";
  }
}

///////////////////////////////////////////////////////////////////////////
// XXX: This is the wrong way to do this!
bool targetARM = true;
bool targetx86 = false;

// Some llvm nonsense. I should probably find a way to clean this up.
// do we put ~{dirflag},~{fpsr},~{flags} for the x86 ones? don't think so.
Instruction *makeSync(Value *dummy) {
  LLVMContext &C = dummy->getContext();
  FunctionType *f_ty = FunctionType::get(FunctionType::getVoidTy(C), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "dmb", "~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "msync", "~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "sync");
}
Instruction *makeLwsync(Value *dummy) {
  LLVMContext &C = dummy->getContext();
  FunctionType *f_ty = FunctionType::get(FunctionType::getVoidTy(C), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "dmb", "~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "", "~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "lwsync");
}
Instruction *makeCtrlIsync(Value *v) {
  LLVMContext &C = v->getContext();
  FunctionType *f_ty =
    FunctionType::get(FunctionType::getVoidTy(C), v->getType(), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "cmp $0, $0;beq 1f;1: isb", "r,~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "", "r,~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "ctrlisync");
}
// We also need to add a thing for fake data deps, which is more annoying.

///////////////////////////////////////////////////////////////////////////
//// Actual code for the pass

class RMCPass : public FunctionPass {
private:
  std::vector<Action> actions_;
  DenseMap<BasicBlock *, Action *> bb2action_;
  DenseMap<BasicBlock *, EdgeCut> cuts_;

public:
  static char ID;
  RMCPass() : FunctionPass(ID) {

  }
  ~RMCPass() { }
  std::vector<RMCEdge> findEdges(Function &F);
  void buildGraph(std::vector<RMCEdge> &edges, Function &F);
  virtual bool runOnFunction(Function &F);

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.addRequiredID(BreakCriticalEdgesID);
    AU.setPreservesCFG();
  }

};

bool nameMatches(StringRef blockName, StringRef target) {
  StringRef name = "_rmc_" + target.str() + "_";
  if (!blockName.startswith(name)) return false;
  // Now make sure the rest is an int
  APInt dummy;
  return !blockName.drop_front(name.size()).getAsInteger(10, dummy);
}

StringRef getStringArg(Value *v) {
  const Value *g = cast<Constant>(v)->stripPointerCasts();
  const Constant *ptr = cast<GlobalVariable>(g)->getInitializer();
  StringRef str = cast<ConstantDataSequential>(ptr)->getAsString();
  // Drop the '\0' at the end
  return str.drop_back();
}

std::vector<RMCEdge> RMCPass::findEdges(Function &F) {
  std::vector<RMCEdge> edges;

  for (inst_iterator is = inst_begin(F), ie = inst_end(F); is != ie;) {
    // Grab the instruction and advance the iterator at the start, since
    // we might delete the instruction.
    Instruction *i = &*is;
    is++;

    CallInst *load = dyn_cast<CallInst>(i);
    if (!load) continue;
    Function *target = load->getCalledFunction();
    // We look for calls to the bogus function
    // __rmc_edge_register, pull out the information about them,
    // and delete the calls.
    if (!target || target->getName() != "__rmc_edge_register") continue;

    // Pull out what the operands have to be.
    // We just assert if something is wrong, which is not great UX.
    bool isVisibility = cast<ConstantInt>(load->getOperand(0))
      ->getValue().getBoolValue();
    RMCEdgeType edgeType = isVisibility ? VisbilityEdge : ExecutionEdge;
    StringRef srcName = getStringArg(load->getOperand(1));
    StringRef dstName = getStringArg(load->getOperand(2));

    // Since multiple blocks can have the same tag, we search for
    // them by name.
    // We could make this more efficient by building maps but I don't think
    // it is going to matter.
    for (auto & src : F) {
      if (!nameMatches(src.getName(), srcName)) continue;
      for (auto & dst : F) {
        if (!nameMatches(dst.getName(), dstName)) continue;

        edges.push_back({edgeType, &src, &dst});
      }
    }

    // Delete the bogus call.
    i->eraseFromParent();
  }

  return edges;
}

void analyzeAction(Action &info) {
  LoadInst *soleLoad = nullptr;
  for (auto & i : *info.bb) {
    if (LoadInst *load = dyn_cast<LoadInst>(&i)) {
      info.loads++;
      soleLoad = load;
    } else if (isa<StoreInst>(i)) {
      info.stores++;
    // What else counts as a call? I'm counting fences I guess.
    } else if (isa<CallInst>(i) || isa<FenceInst>(i)) {
      info.calls++;
    } else if (isa<AtomicCmpXchgInst>(i) || isa<AtomicRMWInst>(i)) {
      info.RMWs++;
    }
  }
  // Try to characterize what this action does.
  // These categories might not be the best.
  if (info.loads == 1 && info.stores+info.calls+info.RMWs == 0) {
    info.soleLoad = soleLoad;
    info.type = ActionSimpleRead;
  } else if (info.stores >= 1 && info.loads+info.calls+info.RMWs == 0) {
    info.type = ActionSimpleWrites;
  } else if (info.RMWs == 1 && info.stores+info.loads+info.calls == 0) {
    info.type = ActionSimpleRMW;
  } else {
    info.type = ActionComplex;
  }
}

void RMCPass::buildGraph(std::vector<RMCEdge> &edges, Function &F) {
  // First, collect all the basic blocks with edges attached to them
  SmallPtrSet<BasicBlock *, 8> basicBlocks;
  for (auto & edge : edges) {
    basicBlocks.insert(edge.src);
    basicBlocks.insert(edge.dst);
  }

  // Now, make the vector of actions and a mapping from BasicBlock *.
  actions_.reserve(basicBlocks.size());
  for (auto bb : basicBlocks) {
    actions_.emplace_back(bb);
    bb2action_[bb] = &actions_.back();
  }

  // Analyze the instructions in actions to see what they do.
  for (auto & action : actions_) {
    analyzeAction(action);
  }

  // Build our list of edges into a more explicit graph
  for (auto & edge : edges) {
    Action *src = bb2action_[edge.src];
    Action *dst = bb2action_[edge.dst];
    if (edge.edgeType == VisbilityEdge) {
      src->visEdges.insert(dst);
    } else {
      src->execEdges.insert(dst);
    }
  }
}

bool RMCPass::runOnFunction(Function &F) {
  auto edges = findEdges(F);
  if (edges.empty()) return false;

  for (auto & edge : edges) {
    errs() << "Found an edge: " << edge << "\n";
  }

  buildGraph(edges, F);

  // Clear our data structures to save memory, make things clean for
  // future runs.
  actions_.clear();
  bb2action_.clear();
  cuts_.clear();

  return true;
}

char RMCPass::ID = 0;
RegisterPass<RMCPass> X("rmc-pass", "RMC");
}
<commit_msg>Refactor clearing of data structures.<commit_after>// BUG: this whole thing depends on the specifics of how the clang version I
// am using emits llvm bitcode for the hacky RMC protocol.
// We rely on how basic blocks get named, on the labels forcing things
// into their own basic blocks, and probably will rely on this block
// having one predecessor and one successor. We could probably even
// force those to be empty without too much work by adding more labels...

#include <llvm/Pass.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/InlineAsm.h>
#include <llvm/IR/CFG.h>
#include <llvm/IR/InstIterator.h>
#include <llvm/Transforms/Scalar.h>

#include <llvm/ADT/ArrayRef.h>

#include <llvm/Transforms/Utils/BasicBlockUtils.h>
#include <llvm/Support/raw_ostream.h>

#include <ostream>
#include <fstream>
#include <iostream>
#include <map>
#include <set>

using namespace llvm;

namespace {
#if 0 // I hate you, emacs. Is there a better way to work around this?
}
#endif

/* To do bogus data dependencies, we will emit inline assembly
  instructions. This is sort of tasteless; we should add an intrinsic;
  but it means we don't need to modify llvm. This is what the
  instruction should look like (probably the constraints aren't
  right?):

  %2 = call i32 asm sideeffect "eor $0, $0;", "=r,0"(i32 %1) #2, !srcloc !11

  Also for ctrlisb we do:
  call void asm sideeffect "cmp $0, $0;beq 1f;1: isb", "r,~{memory}"(i32 %1) #2, !srcloc !4

  And for dmb:
  call void asm sideeffect "dmb", "~{memory}"() #2, !srcloc !5

  We can probably do a bogus inline asm on x86 to prevent reordering:
  %2 = call i32 asm sideeffect "", "=r,r,0,~{dirflag},~{fpsr},~{flags}"(i32 %1, i32 %0) #3, !srcloc !9

  What about this makes the right value come out:
    =r specifies an output parameter and the 0 says that that input parameter
    is paired with param 0.

  Hm. Does this *actually* work?? What does "sideeffect" actually mean
  for asm and do we need it.

  --
  Should we emit dmb directly, or try to use llvm's fences?
*/

//// Some auxillary data structures
enum RMCEdgeType {
  VisbilityEdge,
  ExecutionEdge
};

raw_ostream& operator<<(raw_ostream& os, const RMCEdgeType& t) {
  switch (t) {
    case VisbilityEdge:
      os << "v";
      break;
    case ExecutionEdge:
      os << "x";
      break;
    default:
      os << "?";
      break;
  }
  return os;
}

// Info about an RMC edge
struct RMCEdge {
  RMCEdgeType edgeType;
  BasicBlock *src;
  BasicBlock *dst;

  bool operator<(const RMCEdge& rhs) const {
    return std::tie(edgeType, src, dst)
      < std::tie(rhs.edgeType, rhs.src, rhs.dst);
  }

  void print(raw_ostream &os) const {
    // substr(5) is to drop "_rmc_" from the front
    os << src->getName().substr(5) << " -" << edgeType <<
      "-> " << dst->getName().substr(5);
  }
};

raw_ostream& operator<<(raw_ostream& os, const RMCEdge& e) {
  e.print(os);
  return os;
}

///////////////////////////////////////////////////////////////////////////
// Information for a node in the RMC graph.
enum ActionType {
  ActionComplex,
  ActionSimpleRead,
  ActionSimpleWrites, // needs to be paired with a dep
  ActionSimpleRMW
};
struct Action {
  Action(BasicBlock *p_bb) :
    bb(p_bb),
    type(ActionComplex),
    stores(0), loads(0), RMWs(0), calls(0), soleLoad(nullptr) {}
  void operator=(const Action &) LLVM_DELETED_FUNCTION;
  Action(const Action &) LLVM_DELETED_FUNCTION;
  Action(Action &&) = default; // move constructor!

  BasicBlock *bb;

  // Some basic info about what sort of instructions live in the action
  ActionType type;
  int stores;
  int loads;
  int RMWs;
  int calls;
  LoadInst *soleLoad;

  // Edges in the graph.
  // XXX: Would we be better off storing this some other way?
  // a <ptr, type> pair?
  // And should we store v edges in x
  SmallPtrSet<Action *, 2> execEdges;
  SmallPtrSet<Action *, 2> visEdges;
};

enum CutType {
  CutNone,
  CutCtrlIsync, // needs to be paired with a dep
  CutLwsync,
  CutSync
};
struct EdgeCut {
  EdgeCut() : type(CutNone), front(false), read(nullptr) {}
  CutType type;
  bool front;
  Value *read;
};

///////////////////////////////////////////////////////////////////////////
// Code to find all simple paths between two basic blocks.
// Could generalize more to graphs if we wanted, but I don't right
// now.
typedef std::vector<BasicBlock *> Path;
typedef SmallVector<Path, 2> PathList;
typedef SmallPtrSet<BasicBlock *, 8> GreySet;

PathList findAllSimplePaths_(GreySet *grey, BasicBlock *src, BasicBlock *dst) {
  PathList paths;
  if (grey->count(src)) return paths;
  if (src == dst) {
    Path path;
    path.push_back(dst);
    paths.push_back(std::move(path));
    return paths;
  }

  grey->insert(src);

  // Go search all the successors
  for (auto i = succ_begin(src), e = succ_end(src); i != e; i++) {
    PathList subpaths = findAllSimplePaths_(grey, *i, dst);
    std::move(subpaths.begin(), subpaths.end(), back_inserter(paths));
  }

  // Add our step to all of the vectors
  for (auto & path : paths) {
    path.push_back(src);
  }

  // Remove it from the set of things we've seen. We might come
  // through here again.
  // We can't really do any sort of memoization, since in a cyclic
  // graph the possible simple paths depend not just on what node we
  // are on, but our previous path (to avoid looping).
  grey->erase(src);

  return paths;
}

PathList findAllSimplePaths(BasicBlock *src, BasicBlock *dst) {
  GreySet grey;
  return findAllSimplePaths_(&grey, src, dst);
}

void dumpPaths(const PathList &paths) {
  for (auto & path : paths) {
    for (auto block : path) {
      errs() << block->getName() << " <- ";
    }
    errs() << "\n";
  }
}

///////////////////////////////////////////////////////////////////////////
// XXX: This is the wrong way to do this!
bool targetARM = true;
bool targetx86 = false;

// Some llvm nonsense. I should probably find a way to clean this up.
// do we put ~{dirflag},~{fpsr},~{flags} for the x86 ones? don't think so.
Instruction *makeSync(Value *dummy) {
  LLVMContext &C = dummy->getContext();
  FunctionType *f_ty = FunctionType::get(FunctionType::getVoidTy(C), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "dmb", "~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "msync", "~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "sync");
}
Instruction *makeLwsync(Value *dummy) {
  LLVMContext &C = dummy->getContext();
  FunctionType *f_ty = FunctionType::get(FunctionType::getVoidTy(C), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "dmb", "~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "", "~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "lwsync");
}
Instruction *makeCtrlIsync(Value *v) {
  LLVMContext &C = v->getContext();
  FunctionType *f_ty =
    FunctionType::get(FunctionType::getVoidTy(C), v->getType(), false);
  InlineAsm *a;
  if (targetARM) {
    a = InlineAsm::get(f_ty, "cmp $0, $0;beq 1f;1: isb", "r,~{memory}", true);
  } else if (targetx86) {
    a = InlineAsm::get(f_ty, "", "r,~{memory}", true);
  } else {
    assert(false && "invalid target");
  }
  return CallInst::Create(a, None, "ctrlisync");
}
// We also need to add a thing for fake data deps, which is more annoying.

///////////////////////////////////////////////////////////////////////////
//// Actual code for the pass

class RMCPass : public FunctionPass {
private:
  std::vector<Action> actions_;
  DenseMap<BasicBlock *, Action *> bb2action_;
  DenseMap<BasicBlock *, EdgeCut> cuts_;

public:
  static char ID;
  RMCPass() : FunctionPass(ID) {

  }
  ~RMCPass() { }
  std::vector<RMCEdge> findEdges(Function &F);
  void buildGraph(std::vector<RMCEdge> &edges, Function &F);
  virtual bool runOnFunction(Function &F);

  void getAnalysisUsage(AnalysisUsage &AU) const override {
    AU.addRequiredID(BreakCriticalEdgesID);
    AU.setPreservesCFG();
  }

  // Clear our data structures to save memory, make things clean for
  // future runs.
  void clear() {
    actions_.clear();
    bb2action_.clear();
    cuts_.clear();
  }
};

bool nameMatches(StringRef blockName, StringRef target) {
  StringRef name = "_rmc_" + target.str() + "_";
  if (!blockName.startswith(name)) return false;
  // Now make sure the rest is an int
  APInt dummy;
  return !blockName.drop_front(name.size()).getAsInteger(10, dummy);
}

StringRef getStringArg(Value *v) {
  const Value *g = cast<Constant>(v)->stripPointerCasts();
  const Constant *ptr = cast<GlobalVariable>(g)->getInitializer();
  StringRef str = cast<ConstantDataSequential>(ptr)->getAsString();
  // Drop the '\0' at the end
  return str.drop_back();
}

std::vector<RMCEdge> RMCPass::findEdges(Function &F) {
  std::vector<RMCEdge> edges;

  for (inst_iterator is = inst_begin(F), ie = inst_end(F); is != ie;) {
    // Grab the instruction and advance the iterator at the start, since
    // we might delete the instruction.
    Instruction *i = &*is;
    is++;

    CallInst *load = dyn_cast<CallInst>(i);
    if (!load) continue;
    Function *target = load->getCalledFunction();
    // We look for calls to the bogus function
    // __rmc_edge_register, pull out the information about them,
    // and delete the calls.
    if (!target || target->getName() != "__rmc_edge_register") continue;

    // Pull out what the operands have to be.
    // We just assert if something is wrong, which is not great UX.
    bool isVisibility = cast<ConstantInt>(load->getOperand(0))
      ->getValue().getBoolValue();
    RMCEdgeType edgeType = isVisibility ? VisbilityEdge : ExecutionEdge;
    StringRef srcName = getStringArg(load->getOperand(1));
    StringRef dstName = getStringArg(load->getOperand(2));

    // Since multiple blocks can have the same tag, we search for
    // them by name.
    // We could make this more efficient by building maps but I don't think
    // it is going to matter.
    for (auto & src : F) {
      if (!nameMatches(src.getName(), srcName)) continue;
      for (auto & dst : F) {
        if (!nameMatches(dst.getName(), dstName)) continue;

        edges.push_back({edgeType, &src, &dst});
      }
    }

    // Delete the bogus call.
    i->eraseFromParent();
  }

  return edges;
}

void analyzeAction(Action &info) {
  LoadInst *soleLoad = nullptr;
  for (auto & i : *info.bb) {
    if (LoadInst *load = dyn_cast<LoadInst>(&i)) {
      info.loads++;
      soleLoad = load;
    } else if (isa<StoreInst>(i)) {
      info.stores++;
    // What else counts as a call? I'm counting fences I guess.
    } else if (isa<CallInst>(i) || isa<FenceInst>(i)) {
      info.calls++;
    } else if (isa<AtomicCmpXchgInst>(i) || isa<AtomicRMWInst>(i)) {
      info.RMWs++;
    }
  }
  // Try to characterize what this action does.
  // These categories might not be the best.
  if (info.loads == 1 && info.stores+info.calls+info.RMWs == 0) {
    info.soleLoad = soleLoad;
    info.type = ActionSimpleRead;
  } else if (info.stores >= 1 && info.loads+info.calls+info.RMWs == 0) {
    info.type = ActionSimpleWrites;
  } else if (info.RMWs == 1 && info.stores+info.loads+info.calls == 0) {
    info.type = ActionSimpleRMW;
  } else {
    info.type = ActionComplex;
  }
}

void RMCPass::buildGraph(std::vector<RMCEdge> &edges, Function &F) {
  // First, collect all the basic blocks with edges attached to them
  SmallPtrSet<BasicBlock *, 8> basicBlocks;
  for (auto & edge : edges) {
    basicBlocks.insert(edge.src);
    basicBlocks.insert(edge.dst);
  }

  // Now, make the vector of actions and a mapping from BasicBlock *.
  actions_.reserve(basicBlocks.size());
  for (auto bb : basicBlocks) {
    actions_.emplace_back(bb);
    bb2action_[bb] = &actions_.back();
  }

  // Analyze the instructions in actions to see what they do.
  for (auto & action : actions_) {
    analyzeAction(action);
  }

  // Build our list of edges into a more explicit graph
  for (auto & edge : edges) {
    Action *src = bb2action_[edge.src];
    Action *dst = bb2action_[edge.dst];
    if (edge.edgeType == VisbilityEdge) {
      src->visEdges.insert(dst);
    } else {
      src->execEdges.insert(dst);
    }
  }
}

bool RMCPass::runOnFunction(Function &F) {
  auto edges = findEdges(F);
  if (edges.empty()) return false;

  for (auto & edge : edges) {
    errs() << "Found an edge: " << edge << "\n";
  }

  buildGraph(edges, F);

  clear();
  return true;
}

char RMCPass::ID = 0;
RegisterPass<RMCPass> X("rmc-pass", "RMC");
}
<|endoftext|>


<commit_before>#include "mn101.hpp"
#include <srarea.hpp>

typedef enum {
    OPG_NONE = 0,
    OPG_D_SRC,
    OPG_D_DST,
    OPG_DW_SRC,
    OPG_DW_DST,
    OPG_D0_DW_DST, //#
    OPG_D1_DW_DST, //#
    OPG_A_8, //#
    OPG_A_SRC, //#
    OPG_A_DST, //#
    OPG_IMM4,
    OPG_IMM4_S,
    OPG_IMM8, //#
    OPG_IMM8_S, //#
    OPG_IMM12, //#
    OPG_IMM16, //#
    OPG_IO8, //#
    OPG_BRANCH4,
    OPG_BRANCH7,
    OPG_BRANCH11,
    OPG_BRANCH18, //#
    OPG_BRANCH20, //#
    OPG_CALL12, //#
    OPG_CALL16, //#
    OPG_CALL18, //#
    OPG_CALL20, //#
    OPG_CALLTBL4, //#
    OPG_REG_SP,
    OPG_REG_PSW, //#
    OPG_REG_HA, //#
    OPG_BITPOS, //#
    OPG_REP3, //#

    OPGF_RELATIVE = 0x100,//#
    OPGF_LOAD = 0X200,//#
    OPGF_SHOWAT_0 = 0x1000, //#
    OPGF_SHOWAT_1 = 0x2000,
    OPGF_SHOWAT_2 = 0x3000,
    OPGF_SHOWAT_MASK = 0x7000

} opgen_t;

#define FLAG_SRCOFF_SP 0x01
#define FLAG_DSTOFF_SP 0x02

typedef struct
{
    uchar code;
    uchar mask;
    ins_enum_t mnemonic;
    uint32 op[3];

} parseinfo_t;

static parseinfo_t parseTable[] = {
#include "parsetable0.gen.c"
};

static parseinfo_t parseTableExtension2[] = {
#include "parsetable1.gen.c"
};

static parseinfo_t parseTableExtension3[] = {
#include "parsetable2.gen.c"
};

static struct parseState_t
{
    ea_t pc;
    ea_t ptr;
    uint32 code;
    uchar sz;
    uchar insbyte;

    void reset()
    {
        code = 0;
        sz = 0;
        uchar H = get_segreg(cmd.ea, rVh);
        ptr = pc = (cmd.ea << 1) + H;
    }

    uint32 fetchNibble()
    {
        uchar nibble;
        if (ptr & 1)
            nibble = get_byte(ptr >> 1) >> 4;
        else
            nibble = get_byte(ptr >> 1) & 0xF;

        QASSERT(256, nibble <= 0xF);
        code = (code << 4) | nibble;
        sz++;
        ptr++;
        return nibble;
    }

    // This is unaligned byte fetch. Note it is not the same as 2x fetchNibble()
    uint32 fetchByte()
    {
        uchar byte;
        if (ptr & 1)
            byte = (get_byte(ptr >> 1) >> 4) | (get_byte((ptr >> 1)+1) << 4);
        else
            byte = get_byte(ptr >> 1);

        code = (code << 8) | byte;
        sz += 2;
        ptr += 2;
        return byte;
    }

    bool compareMask(const parseinfo_t *pi)
    {
        if ((code & pi->mask) == pi->code)
        {
            // Save the first two nibbles for operands parsing
            insbyte = code;
            return true;
        }
        return false;
    }

} parseState;

static void setCodeAddrValue(op_t &op, ea_t addr)
{
    op.addr = addr >> 1;
    op.value = addr;
}

#define IOTOP 0x3F00
#define SRVT 0x4080
#define SIGN_EXTEND(nbits, val) (((val) << (32 - (nbits))) >> (32 - (nbits)))

static bool parseOperand(op_t &op, int type)
{
    uchar v;
    signed int imm;
    signed char imm8;
    switch (type)
    {
    case OPG_NONE:
        break;
    case OPG_D_SRC:
        v = (parseState.insbyte & 0xC) >> 2;
        op.type = o_reg;
        op.reg = OP_REG_D + v;
        break;
    case OPG_D_DST:
        v = parseState.insbyte & 0x3;
        op.type = o_reg;
        op.reg = OP_REG_D + v;
        break;
    case OPG_DW_SRC:
        v = (parseState.insbyte & 0x2) >> 1;
        op.type = o_reg;
        op.reg = OP_REG_DW + v;
        break;
    case OPG_DW_DST:
        v = parseState.insbyte & 0x1;
        op.type = o_reg;
        op.reg = OP_REG_DW + v;
        break;
    case OPG_D0_DW_DST:
    case OPG_D1_DW_DST:
        v = parseState.insbyte & 0x1;
        op.type = o_reg;
        op.reg = OP_REG_D + v * 2;
        if (type == OPG_D1_DW_DST)
            op.reg++;
        break;
    case OPG_A_8:
        v = (parseState.insbyte & 0x4) >> 2;
        op.type = o_reg;
        op.reg = OP_REG_A + v;
        break;
    case OPG_A_SRC:
        v = (parseState.insbyte & 0x2) >> 1;
        op.type = o_reg;
        op.reg = OP_REG_A + v;
        break;
    case OPG_A_DST:
        v = parseState.insbyte & 0x1;
        op.type = o_reg;
        op.reg = OP_REG_A + v;
        break;

    case OPG_IMM4:
    case OPG_IMM4_S:
        imm = parseState.fetchNibble();
        if (type == OPG_IMM4_S)
        {
            imm = SIGN_EXTEND(4, imm);
            op.flags |= OF_NUMBER;
        }
        op.addr = op.value = imm;
        op.type = o_imm;
        op.dtyp = dt_byte;
        break;
    case OPG_IMM8:
    case OPG_IMM8_S:
        imm = parseState.fetchByte();
        if (type == OPG_IMM8_S)
        {
            imm = SIGN_EXTEND(8, imm);
            op.flags |= OF_NUMBER;
        }
        op.addr = op.value = imm;
        op.type = o_imm;
        op.dtyp = dt_byte;
        break;
    case OPG_IMM12:
        imm = parseState.fetchByte();
        imm |= parseState.fetchNibble() << 8;
        op.addr = op.value = imm;
        op.type = o_imm;
        op.dtyp = dt_word;
        break;
    case OPG_IMM16:
        imm = parseState.fetchByte();
        imm |= parseState.fetchByte() << 8;
        op.addr = op.value = imm;
        op.type = o_imm;
        op.dtyp = dt_word;
        //op.flags |= OF_NUMBER;
        break;
    case OPG_IO8:
        imm = parseState.fetchByte();
        op.addr = op.value = IOTOP + imm;
        op.type = o_mem;
        op.dtyp = dt_byte;
        break;

    case OPG_BRANCH4:
        imm = parseState.fetchNibble();
        imm = SIGN_EXTEND(4, imm);
        imm = (imm << 1) | (parseState.insbyte & 1); // Extract H
        setCodeAddrValue(op, parseState.pc + imm + parseState.sz);
        op.type = o_near;
        break;
    case OPG_BRANCH7:
        imm8 = parseState.fetchByte(); //Signed imm#8
        setCodeAddrValue(op, parseState.pc + imm8 + parseState.sz);
        op.type = o_near;
        break;
    case OPG_BRANCH11:
        imm = parseState.fetchByte() | (parseState.fetchNibble() << 8); //Signed imm#12
        imm = SIGN_EXTEND(12, imm);
        setCodeAddrValue(op, parseState.pc + imm + parseState.sz);
        op.type = o_near;
        break;
    case OPG_BRANCH18:
    case OPG_CALL18:
        imm = parseState.fetchByte() | (parseState.fetchByte() << 8);
        imm |= (parseState.insbyte & 0x6) << 15; //aa
        imm = (imm << 1) | (parseState.insbyte & 0x1); //H
        setCodeAddrValue(op, imm);
        op.type = o_near;
        break;
    case OPG_BRANCH20:
    case OPG_CALL20:
        v = parseState.fetchByte();
        imm = parseState.fetchByte() | (parseState.fetchByte() << 8);
        imm |= (v & 0x1E) << 15; //Bbbb
        imm = (imm << 1) | (v & 0x1); //H
        setCodeAddrValue(op, imm);
        op.type = o_near;
        break;

    case OPG_CALL12:
        imm = parseState.fetchByte() | (parseState.fetchNibble() << 8);
        imm = SIGN_EXTEND(12, imm);
        imm = (imm << 1) | (parseState.insbyte & 0x1); //H
        setCodeAddrValue(op, parseState.pc + imm + parseState.sz);
        op.type = o_near;
        break;
    case OPG_CALL16:
        imm = parseState.fetchByte() | (parseState.fetchByte() << 8);
        imm = SIGN_EXTEND(16, imm);
        imm = (imm << 1) | (parseState.insbyte & 0x1); //H
        setCodeAddrValue(op, parseState.pc + imm + parseState.sz);
        op.type = o_near;
        break;
    case OPG_CALLTBL4:
        imm = parseState.fetchNibble();
        setCodeAddrValue(op, SRVT + (imm << 2));
        op.type = o_mem;
        break;

    case OPG_REG_SP:
        op.type = o_reg;
        op.reg = OP_REG_SP;
        break;
    case OPG_REG_PSW:
        op.type = o_reg;
        op.reg = OP_REG_PSW;
        break;
    case OPG_REG_HA:
        op.type = o_reg;
        op.reg = OP_REG_HA;
        break;

    case OPG_BITPOS:
    case OPG_REP3:
        imm = parseState.insbyte & 0x7;
        if (type == OPG_BITPOS)
            op.type = o_bitpos;
        else
            op.type = o_imm;
        op.value = imm;
        break;

    default:
        QASSERT(257, 0);
    }

    return true;
}

static void mergeOps(op_t &src, op_t &dst)
{
    QASSERT(258, &src != &dst);

    dst.type = src.type;
    QASSERT(258, dst.reg == OP_REG_NONE);
    dst.reg = src.reg;
    dst.addr += src.addr;
    dst.value += src.value;
    dst.flags |= src.flags;
    dst.dtyp = src.dtyp;

    src.type = 0;
    src.reg = 0;
    src.addr = 0;
    src.value = 0;
    src.flags = 0;
    src.dtyp = 0;
}

static bool parseInstruction(const parseinfo_t *pTable, size_t tblSize)
{
    const parseinfo_t *ins;
    for (size_t i = 0; i < tblSize; i++)
    {
        ins = &pTable[i];
        if (parseState.compareMask(ins))
        {
            cmd.itype = ins->mnemonic;
            int opidx = -1;
            for (int j = 0; j < 3; j++)
            {
                opidx = (ins->op[j] & OPGF_SHOWAT_MASK) >> 12;
                if (opidx != 0)
                    opidx--;
                else
                    opidx = j;
                parseOperand(cmd.Operands[opidx], ins->op[j] & 0xFF);
                if ((ins->op[j] & OPGF_LOAD) != 0)
                {
                    if (cmd.Operands[opidx].type == o_reg)
                        cmd.Operands[opidx].type = o_phrase;
                    else if (cmd.Operands[opidx].type == o_imm)
                        cmd.Operands[opidx].type = o_mem;
                }
                if ((ins->op[j] & OPGF_RELATIVE) != 0)
                {
                    cmd.Operands[opidx].type = o_displ;
                    cmd.Operands[opidx].addr = cmd.Operands[opidx].value;
                }
            }

            // Merge displacement ops
            int dstidx = 0;
            for (int srcidx = 0; srcidx < 3; srcidx++)
            {
                if (cmd.Operands[srcidx].type == o_displ)
                {
                    dstidx--;
                }
                if (srcidx != dstidx)
                {
                    mergeOps(cmd.Operands[srcidx], cmd.Operands[dstidx]);
                }
                dstidx++;
            }

            return true;
        }
    }

    return false;
}

int idaapi mn101_ana(void)
{
    bool decoded;
    parseState.reset();

    // Get the first byte of instruction
    uchar extension = parseState.fetchNibble();

    // Handle extension codes
    switch (extension)
    {
    case 0x3:
        parseState.fetchNibble();
        parseState.fetchNibble();
        decoded = parseInstruction(parseTableExtension3, qnumber(parseTableExtension3));
        break;
    case 0x2:

        parseState.fetchNibble();
        parseState.fetchNibble();
        decoded = parseInstruction(parseTableExtension2, qnumber(parseTableExtension2));
        break;
    default:
        parseState.fetchNibble();
        decoded = parseInstruction(parseTable, qnumber(parseTable));
        break;
    }

    if (!decoded)
        return 0;

    // Compiler generally aligns the size of return instructions by a byte
    //TODO: maybe add a user option for this
    if (cmd.itype == INS_RTS || cmd.itype == INS_RTI)
    {
        if ((parseState.sz + parseState.pc) & 1) ++parseState.sz;
        cmd.segpref = 0;
    }
    else
    {
        // cmd.segpref would hold 1 if the last byte was only partially consumed
        cmd.segpref = parseState.ptr & 1;
    }

    // Update the command size
    cmd.size = (parseState.sz + (parseState.pc & 1)) / 2;

    return(cmd.size);
}
<commit_msg>Added an assert and fixed MSVC warning<commit_after>#include "mn101.hpp"
#include <srarea.hpp>

typedef enum {
    OPG_NONE = 0,
    OPG_D_SRC,
    OPG_D_DST,
    OPG_DW_SRC,
    OPG_DW_DST,
    OPG_D0_DW_DST, //#
    OPG_D1_DW_DST, //#
    OPG_A_8, //#
    OPG_A_SRC, //#
    OPG_A_DST, //#
    OPG_IMM4,
    OPG_IMM4_S,
    OPG_IMM8, //#
    OPG_IMM8_S, //#
    OPG_IMM12, //#
    OPG_IMM16, //#
    OPG_IO8, //#
    OPG_BRANCH4,
    OPG_BRANCH7,
    OPG_BRANCH11,
    OPG_BRANCH18, //#
    OPG_BRANCH20, //#
    OPG_CALL12, //#
    OPG_CALL16, //#
    OPG_CALL18, //#
    OPG_CALL20, //#
    OPG_CALLTBL4, //#
    OPG_REG_SP,
    OPG_REG_PSW, //#
    OPG_REG_HA, //#
    OPG_BITPOS, //#
    OPG_REP3, //#

    OPGF_RELATIVE = 0x100,//#
    OPGF_LOAD = 0X200,//#
    OPGF_SHOWAT_0 = 0x1000, //#
    OPGF_SHOWAT_1 = 0x2000,
    OPGF_SHOWAT_2 = 0x3000,
    OPGF_SHOWAT_MASK = 0x7000

} opgen_t;

#define FLAG_SRCOFF_SP 0x01
#define FLAG_DSTOFF_SP 0x02

typedef struct
{
    uchar code;
    uchar mask;
    ins_enum_t mnemonic;
    uint32 op[3];

} parseinfo_t;

static parseinfo_t parseTable[] = {
#include "parsetable0.gen.c"
};

static parseinfo_t parseTableExtension2[] = {
#include "parsetable1.gen.c"
};

static parseinfo_t parseTableExtension3[] = {
#include "parsetable2.gen.c"
};

static struct parseState_t
{
    ea_t pc;
    ea_t ptr;
    uint32 code;
    uchar sz;
    uchar insbyte;

    void reset()
    {
        code = 0;
        sz = 0;
        uchar H = get_segreg(cmd.ea, rVh);
        ptr = pc = (cmd.ea << 1) + H;
    }

    uint32 fetchNibble()
    {
        uchar nibble;
        if (ptr & 1)
            nibble = get_byte(ptr >> 1) >> 4;
        else
            nibble = get_byte(ptr >> 1) & 0xF;

        QASSERT(256, nibble <= 0xF);
        code = (code << 4) | nibble;
        sz++;
        ptr++;
        return nibble;
    }

    // This is unaligned byte fetch. Note it is not the same as 2x fetchNibble()
    uint32 fetchByte()
    {
        uchar byte;
        if (ptr & 1)
            byte = (get_byte(ptr >> 1) >> 4) | (get_byte((ptr >> 1)+1) << 4);
        else
            byte = get_byte(ptr >> 1);

        code = (code << 8) | byte;
        sz += 2;
        ptr += 2;
        return byte;
    }

    bool compareMask(const parseinfo_t *pi)
    {
        if ((code & pi->mask) == pi->code)
        {
            // Save the first two nibbles for operands parsing
            insbyte = code;
            return true;
        }
        return false;
    }

} parseState;

static void setCodeAddrValue(op_t &op, ea_t addr)
{
    op.addr = addr >> 1;
    op.value = addr;
}

#define IOTOP 0x3F00
#define SRVT 0x4080
#define SIGN_EXTEND(nbits, val) (((val) << (32 - (nbits))) >> (32 - (nbits)))

static bool parseOperand(op_t &op, int type)
{
    uchar v;
    signed int imm;
    signed char imm8;
    switch (type)
    {
    case OPG_NONE:
        break;
    case OPG_D_SRC:
        v = (parseState.insbyte & 0xC) >> 2;
        op.type = o_reg;
        op.reg = OP_REG_D + v;
        break;
    case OPG_D_DST:
        v = parseState.insbyte & 0x3;
        op.type = o_reg;
        op.reg = OP_REG_D + v;
        break;
    case OPG_DW_SRC:
        v = (parseState.insbyte & 0x2) >> 1;
        op.type = o_reg;
        op.reg = OP_REG_DW + v;
        break;
    case OPG_DW_DST:
        v = parseState.insbyte & 0x1;
        op.type = o_reg;
        op.reg = OP_REG_DW + v;
        break;
    case OPG_D0_DW_DST:
    case OPG_D1_DW_DST:
        v = parseState.insbyte & 0x1;
        op.type = o_reg;
        op.reg = OP_REG_D + v * 2;
        if (type == OPG_D1_DW_DST)
            op.reg++;
        break;
    case OPG_A_8:
        v = (parseState.insbyte & 0x4) >> 2;
        op.type = o_reg;
        op.reg = OP_REG_A + v;
        break;
    case OPG_A_SRC:
        v = (parseState.insbyte & 0x2) >> 1;
        op.type = o_reg;
        op.reg = OP_REG_A + v;
        break;
    case OPG_A_DST:
        v = parseState.insbyte & 0x1;
        op.type = o_reg;
        op.reg = OP_REG_A + v;
        break;

    case OPG_IMM4:
    case OPG_IMM4_S:
        imm = parseState.fetchNibble();
        if (type == OPG_IMM4_S)
        {
            imm = SIGN_EXTEND(4, imm);
            op.flags |= OF_NUMBER;
        }
        op.addr = op.value = imm;
        op.type = o_imm;
        op.dtyp = dt_byte;
        break;
    case OPG_IMM8:
    case OPG_IMM8_S:
        imm = parseState.fetchByte();
        if (type == OPG_IMM8_S)
        {
            imm = SIGN_EXTEND(8, imm);
            op.flags |= OF_NUMBER;
        }
        op.addr = op.value = imm;
        op.type = o_imm;
        op.dtyp = dt_byte;
        break;
    case OPG_IMM12:
        imm = parseState.fetchByte();
        imm |= parseState.fetchNibble() << 8;
        op.addr = op.value = imm;
        op.type = o_imm;
        op.dtyp = dt_word;
        break;
    case OPG_IMM16:
        imm = parseState.fetchByte();
        imm |= parseState.fetchByte() << 8;
        op.addr = op.value = imm;
        op.type = o_imm;
        op.dtyp = dt_word;
        //op.flags |= OF_NUMBER;
        break;
    case OPG_IO8:
        imm = parseState.fetchByte();
        op.addr = op.value = IOTOP + imm;
        op.type = o_mem;
        op.dtyp = dt_byte;
        break;

    case OPG_BRANCH4:
        imm = parseState.fetchNibble();
        imm = SIGN_EXTEND(4, imm);
        imm = (imm << 1) | (parseState.insbyte & 1); // Extract H
        setCodeAddrValue(op, parseState.pc + imm + parseState.sz);
        op.type = o_near;
        break;
    case OPG_BRANCH7:
        imm8 = parseState.fetchByte(); //Signed imm#8
        setCodeAddrValue(op, parseState.pc + imm8 + parseState.sz);
        op.type = o_near;
        break;
    case OPG_BRANCH11:
        imm = parseState.fetchByte() | (parseState.fetchNibble() << 8); //Signed imm#12
        imm = SIGN_EXTEND(12, imm);
        setCodeAddrValue(op, parseState.pc + imm + parseState.sz);
        op.type = o_near;
        break;
    case OPG_BRANCH18:
    case OPG_CALL18:
        imm = parseState.fetchByte() | (parseState.fetchByte() << 8);
        imm |= (parseState.insbyte & 0x6) << 15; //aa
        imm = (imm << 1) | (parseState.insbyte & 0x1); //H
        setCodeAddrValue(op, imm);
        op.type = o_near;
        break;
    case OPG_BRANCH20:
    case OPG_CALL20:
        v = parseState.fetchByte();
        imm = parseState.fetchByte() | (parseState.fetchByte() << 8);
        imm |= (v & 0x1E) << 15; //Bbbb
        imm = (imm << 1) | (v & 0x1); //H
        setCodeAddrValue(op, imm);
        op.type = o_near;
        break;

    case OPG_CALL12:
        imm = parseState.fetchByte() | (parseState.fetchNibble() << 8);
        imm = SIGN_EXTEND(12, imm);
        imm = (imm << 1) | (parseState.insbyte & 0x1); //H
        setCodeAddrValue(op, parseState.pc + imm + parseState.sz);
        op.type = o_near;
        break;
    case OPG_CALL16:
        imm = parseState.fetchByte() | (parseState.fetchByte() << 8);
        imm = SIGN_EXTEND(16, imm);
        imm = (imm << 1) | (parseState.insbyte & 0x1); //H
        setCodeAddrValue(op, parseState.pc + imm + parseState.sz);
        op.type = o_near;
        break;
    case OPG_CALLTBL4:
        imm = parseState.fetchNibble();
        setCodeAddrValue(op, SRVT + (imm << 2));
        op.type = o_mem;
        break;

    case OPG_REG_SP:
        op.type = o_reg;
        op.reg = OP_REG_SP;
        break;
    case OPG_REG_PSW:
        op.type = o_reg;
        op.reg = OP_REG_PSW;
        break;
    case OPG_REG_HA:
        op.type = o_reg;
        op.reg = OP_REG_HA;
        break;

    case OPG_BITPOS:
    case OPG_REP3:
        imm = parseState.insbyte & 0x7;
        if (type == OPG_BITPOS)
            op.type = o_bitpos;
        else
            op.type = o_imm;
        op.value = imm;
        break;

    default:
        QASSERT(257, 0);
    }

    return true;
}

static void mergeOps(op_t &src, op_t &dst)
{
    QASSERT(258, &src != &dst);

    dst.type = src.type;
    QASSERT(258, dst.reg == OP_REG_NONE);
    dst.reg = src.reg;
    dst.addr += src.addr;
    dst.value += src.value;
    dst.flags |= src.flags;
    dst.dtyp = src.dtyp;

    src.type = 0;
    src.reg = 0;
    src.addr = 0;
    src.value = 0;
    src.flags = 0;
    src.dtyp = 0;
}

static bool parseInstruction(const parseinfo_t *pTable, size_t tblSize)
{
    const parseinfo_t *ins;
    for (size_t i = 0; i < tblSize; i++)
    {
        ins = &pTable[i];
        if (parseState.compareMask(ins))
        {
            cmd.itype = ins->mnemonic;
            int opidx = -1;
            for (int j = 0; j < 3; j++)
            {
                opidx = (ins->op[j] & OPGF_SHOWAT_MASK) >> 12;
                if (opidx != 0)
                    opidx--;
                else
                    opidx = j;
                parseOperand(cmd.Operands[opidx], ins->op[j] & 0xFF);
                if ((ins->op[j] & OPGF_LOAD) != 0)
                {
                    if (cmd.Operands[opidx].type == o_reg)
                        cmd.Operands[opidx].type = o_phrase;
                    else if (cmd.Operands[opidx].type == o_imm)
                        cmd.Operands[opidx].type = o_mem;
                }
                if ((ins->op[j] & OPGF_RELATIVE) != 0)
                {
                    cmd.Operands[opidx].type = o_displ;
                    cmd.Operands[opidx].addr = cmd.Operands[opidx].value;
                }
            }

            // Merge displacement ops
            int dstidx = 0;
            for (int srcidx = 0; srcidx < 3; srcidx++)
            {
                if (cmd.Operands[srcidx].type == o_displ)
                {
                    QASSERT(258, dstidx > 0);
                    dstidx--;
                }
                if (srcidx != dstidx)
                {
                    mergeOps(cmd.Operands[srcidx], cmd.Operands[dstidx]);
                }
                dstidx++;
            }

            return true;
        }
    }

    return false;
}

int idaapi mn101_ana(void)
{
    bool decoded;
    parseState.reset();

    // Get the first byte of instruction
    uchar extension = parseState.fetchNibble();

    // Handle extension codes
    switch (extension)
    {
    case 0x3:
        parseState.fetchNibble();
        parseState.fetchNibble();
        decoded = parseInstruction(parseTableExtension3, qnumber(parseTableExtension3));
        break;
    case 0x2:

        parseState.fetchNibble();
        parseState.fetchNibble();
        decoded = parseInstruction(parseTableExtension2, qnumber(parseTableExtension2));
        break;
    default:
        parseState.fetchNibble();
        decoded = parseInstruction(parseTable, qnumber(parseTable));
        break;
    }

    if (!decoded)
        return 0;

    // Compiler generally aligns the size of return instructions by a byte
    //TODO: maybe add a user option for this
    if (cmd.itype == INS_RTS || cmd.itype == INS_RTI)
    {
        if ((parseState.sz + parseState.pc) & 1) ++parseState.sz;
        cmd.segpref = 0;
    }
    else
    {
        // cmd.segpref would hold 1 if the last byte was only partially consumed
        cmd.segpref = parseState.ptr & 1;
    }

    // Update the command size
    cmd.size = (parseState.sz + (parseState.pc & 1)) / 2;

    return(cmd.size);
}
<|endoftext|>