Goose  Artifact [2e47b026a2]

Artifact 2e47b026a2d1e0520b96230de8dd6fe987c7eb9c45987a1b014ee44d6cea197b:

  • File bs/execute/vm.cpp — part of check-in [aee388d9c0] at 2019-08-09 19:54:22 on branch trunk — Cleanup: got rid of the half-assed location and poisoning systems in ir::Terms. (user: achavasse size: 4940)

#include "execute.h"

using namespace empathy;
using namespace empathy::execute;
using namespace empathy::builtins;

uint32_t VM::ms_remainingBranchInstExecutions = 1024;

optional< Value > VM::execute( CFG& cfg )
{
    return execute( cfg.entryBB() );
}

optional< Value > VM::execute( ptr< BasicBlock > bb )
{
    auto pbbBackup = m_pPreviousBB;

    while( bb )
    {
        for( auto&& instr : *bb )
            execute( instr );

        if( !bb->terminator() )
            break;

        m_pPreviousBB = bb;
        bb = execute( *bb->terminator() );
    }

    m_pPreviousBB = pbbBackup;
    return m_frame.retVal();
}

optional< Value > VM::execute( const llr::Instruction& instr )
{
    return visit( [&]( auto&& e )
    {
        return execute( e );
    }, instr.content() );
}

ptr< BasicBlock > VM::execute( const llr::Terminator& terminator )
{
    return visit( [&]( auto&& e )
    {
        return execute( e );
    }, terminator.content() );
}

optional< Value > VM::execute( const ptr< CFG >& ic )
{
    return execute( *ic );
}

optional< Value > VM::execute( const llr::Call& call )
{
    if( !( --ms_remainingBranchInstExecutions ) )
        return nullopt;

    auto func = Evaluate( call.func(), *this );
    if( !func || !func->isConstant() )
    {
        cout << "Execute: function evaluation failed.\n";
        return nullopt;
    }

    const auto& vec = *get< pvec >( call.args() );

    if( IsBuiltinFunc( *func ) )
    {
        auto newVec = vec.transform( [&]( auto&& x ) -> optional< Term >
        {
            auto val = ValueFromIRExpr( x );
            assert( val );

            auto newVal = Evaluate( *val, *this );
            if( !newVal || !newVal->isConstant() )
                return nullopt;

            return ValueToIRExpr( *newVal );
        } );

        if( !newVec )
        {
            cout << "Execute: args evaluation failed.\n";
            return nullopt;
        }

        return ExecuteBuiltinFuncCall( *func, TERM( newVec ) );
    }

    const auto* pFunc = GetFuncLLR( *func );

    if( !pFunc || !pFunc->isValid() )
        return nullopt;

    Frame f;

    llvm::SmallVector< optional< Value >, 8 > args;
    args.reserve( vec.terms().size() );

    for( auto&& a : vec.terms() )
    {
        auto val = ValueFromIRExpr( a );
        assert( val );

        auto newVal = Evaluate( *val, *this );
        if( !newVal|| !newVal->isConstant() )
        {
            cout << "Execute: args evaluation failed.\n";
            return nullopt;
        }

        args.emplace_back( move( *newVal ) );
    }

    f.setArgs( move( args ) );

    swap( m_frame, f );
    auto result = execute( *pFunc->body() );
    swap( m_frame, f );

    return result;
}

optional< Value > VM::ExecuteBuiltinFuncCall( const Value& func, const Term& args )
{
    const auto& f = GetBuiltinFuncWrapper( func );
    return f( args );
}

ptr< BasicBlock > VM::execute( const llr::Ret& r )
{
    if( r.value() )
        m_frame.setRetVal( *Evaluate( *r.value(), *this ) );

    return nullptr;
}

optional< Value > VM::execute( const llr::CreateTemporary& ct )
{
    m_frame.setTemporary( ct.cfgId(), ct.index(), *Evaluate( ct.value(), *this ) );
    return nullopt;
}

optional< Value > VM::execute( const llr::GetTemporary& gt )
{
    const auto* pVal = m_frame.getTemporary( gt.cfgId(), gt.index() );
    assert( pVal );
    if( !pVal )
        return nullopt;
    return *pVal;
}

optional< Value > VM::execute( const llr::GetVar& gv )
{
    const auto* pVal = m_frame.getTemporary( gv.cfgId(), gv.index() );
    assert( pVal );
    if( !pVal )
        return nullopt;

    auto result = Evaluate( **pVal, *this );
    if( !result || !result->isConstant() )
        return nullopt;

    return result;
}

optional< Value > VM::execute( const llr::SetVar& sv )
{
    m_frame.setTemporary( sv.cfgId(), sv.index(), sv.value() );
    return nullopt;
}

optional< Value > VM::execute( const llr::Phi& p )
{
    p.forAllIncomings( [&]( auto&& bb, auto&& val )
    {
        if( bb == m_pPreviousBB )
        {
            m_frame.setTemporary( p.destCfgId(), p.destIndex(), *Evaluate( val, *this ) );
            return false;
        }

        return true;
    } );

    return nullopt;
}

optional< Value > VM::execute( const llr::LoadConstInt& lci )
{
    return ToValue( lci.value() );
}

ptr< BasicBlock > VM::execute( const llr::Branch& b )
{
    if( !( --ms_remainingBranchInstExecutions ) )
        return nullptr;

    return b.dest().lock();
}

ptr< BasicBlock > VM::execute( const llr::CondBranch& cb )
{
    if( !( --ms_remainingBranchInstExecutions ) )
        return nullptr;

    auto cond = Evaluate( cb.cond(), *this );
    if( !cond || !cond->isConstant() )
    {
        cout << "Execute: branch condition evaluation failed.\n";
        return nullptr;
    }

    if( *FromValue< bool >( *cond ) )
        return cb.trueDest().lock();

    return cb.falseDest().lock();
}