<commit_before>#include "Pipeline.h"
#include "Processor.h"
#include "display.h"
#include "symtable.h"
#include "sampling.h"

#include <cassert>
#include <cmath>
#include <cctype>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>

using namespace std;

namespace Simulator
{

template <typename T>
static bool IsPowerOfTwo(const T& x)
{
    return (x & (x - 1)) == 0;
}

static RegValue PipeValueToRegValue(RegType type, const PipeValue& v)
{
    RegValue r;
    r.m_state = RST_FULL;
    switch (type)
    {
    case RT_INTEGER: r.m_integer       = v.m_integer.get(v.m_size); break;
    case RT_FLOAT:   r.m_float.integer = v.m_float.toint(v.m_size); break;
    }
    return r;
}

bool Pipeline::ExecuteStage::MemoryWriteBarrier(TID tid) const
{
    Thread& thread = m_threadTable[tid];
    if (thread.dependencies.numPendingWrites != 0)
    {
        // There are pending writes, we need to wait for them
        assert(!thread.waitingForWrites);
        return false;
    }
    return true;
}

Pipeline::PipeAction Pipeline::ExecuteStage::OnCycle()
{
    COMMIT
    {
        // Copy common latch data
        (CommonData&)m_output = m_input;
        m_output.placeSize = m_input.placeSize;

        // Clear memory operation information
        m_output.address = 0;
        m_output.size    = 0;
        
        // Clear remote information
        m_output.Rrc.type = RemoteMessage::MSG_NONE;        
    }
    
    // If we need to suspend on an operand, it'll be in Rav (by the Read Stage)
    // In such a case, we must write them back, because they actually contain the
    // suspend information.
    if (m_input.Rav.m_state != RST_FULL)
    {
        COMMIT
        {
            // Write Rav (with suspend info) back to Rc.
            // The Remote Request information might contain a remote request
            // that will be send by the Writeback stage.
            m_output.Rc  = m_input.Rc;
            m_output.Rcv = m_input.Rav;
            
            // Force a thread switch
            m_output.swch    = true;
            m_output.kill    = false;
            m_output.suspend = SUSPEND_MISSING_DATA;
        }
        return PIPE_FLUSH;
    }
    
    COMMIT
    {
        // Set PC to point to next instruction
        m_output.pc = m_input.pc + sizeof(Instruction);
        
        // Copy input data and set some defaults
        m_output.Rc          = m_input.Rc;
        m_output.suspend     = SUSPEND_NONE;
        m_output.Rcv.m_state = RST_INVALID;
        m_output.Rcv.m_size  = m_input.RcSize;
    }
    
    PipeAction action = ExecuteInstruction();
    if (action != PIPE_STALL)
    {
        // Operation succeeded
        COMMIT
        {
            // We've executed an instruction
            m_op++;
            if (action == PIPE_FLUSH)
            {
                // Pipeline was flushed, thus there's a thread switch
                m_output.swch = true;
                m_output.kill = false;
            }
        }
    }
    
    return action;
}

bool Pipeline::ExecuteStage::ExecAllocate(PlaceID place, RegIndex reg, bool suspend, bool exclusive, Integer flags)
{
    if (place.size == 0)
    {
        // Inherit the parent's place
        place.size = m_input.placeSize;
        place.pid  = (m_parent.GetProcessor().GetPID() / place.size) * place.size;
    }
    
    // Size must be a power of two and ID a multiple of size.
    assert(IsPowerOfTwo(place.size));
    assert((place.pid % place.size) == 0);

    // Verify processor ID
    if (place.pid >= m_parent.GetProcessor().GetGridSize())
    {
        throw SimulationException("Attempting to delegate to a non-existing core");
    }
    
    // Send an allocation request.
    // This will write back the FID to the specified register once the allocation
    // has completed. Even for creates to this core, we do this. Simplifies things.
    COMMIT
    {
        m_output.Rrc.type = RemoteMessage::MSG_ALLOCATE;
        m_output.Rrc.allocate.place          = place;
        m_output.Rrc.allocate.suspend        = suspend;
        m_output.Rrc.allocate.exclusive      = exclusive;
        m_output.Rrc.allocate.type           = (AllocationType)(flags & 3);
        m_output.Rrc.allocate.completion_pid = m_parent.GetProcessor().GetPID();
        m_output.Rrc.allocate.completion_reg = reg;
            
        m_output.Rcv = MAKE_PENDING_PIPEVALUE(m_input.RcSize);
    }
    return true;
}

Pipeline::PipeAction Pipeline::ExecuteStage::SetFamilyProperty(const FID& fid, FamilyProperty property, Integer value)
{
    COMMIT
    {
        m_output.Rrc.type = RemoteMessage::MSG_SET_PROPERTY;
        m_output.Rrc.property.fid   = fid;
        m_output.Rrc.property.type  = property;
        m_output.Rrc.property.value = value;
    }
    return PIPE_CONTINUE;
}

Pipeline::PipeAction Pipeline::ExecuteStage::ExecCreate(const FID& fid, MemAddr address, RegIndex completion)
{
    // Create
    if (!MemoryWriteBarrier(m_input.tid))
    {
        // We need to wait for the pending writes to complete
        COMMIT<commit_msg>[mgsim-load-balancing] Fixed exclusive balanced allocates.<commit_after>#include "Pipeline.h"
#include "Processor.h"
#include "display.h"
#include "symtable.h"
#include "sampling.h"

#include <cassert>
#include <cmath>
#include <cctype>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <fstream>

using namespace std;

namespace Simulator
{

template <typename T>
static bool IsPowerOfTwo(const T& x)
{
    return (x & (x - 1)) == 0;
}

static RegValue PipeValueToRegValue(RegType type, const PipeValue& v)
{
    RegValue r;
    r.m_state = RST_FULL;
    switch (type)
    {
    case RT_INTEGER: r.m_integer       = v.m_integer.get(v.m_size); break;
    case RT_FLOAT:   r.m_float.integer = v.m_float.toint(v.m_size); break;
    }
    return r;
}

bool Pipeline::ExecuteStage::MemoryWriteBarrier(TID tid) const
{
    Thread& thread = m_threadTable[tid];
    if (thread.dependencies.numPendingWrites != 0)
    {
        // There are pending writes, we need to wait for them
        assert(!thread.waitingForWrites);
        return false;
    }
    return true;
}

Pipeline::PipeAction Pipeline::ExecuteStage::OnCycle()
{
    COMMIT
    {
        // Copy common latch data
        (CommonData&)m_output = m_input;
        m_output.placeSize = m_input.placeSize;

        // Clear memory operation information
        m_output.address = 0;
        m_output.size    = 0;
        
        // Clear remote information
        m_output.Rrc.type = RemoteMessage::MSG_NONE;        
    }
    
    // If we need to suspend on an operand, it'll be in Rav (by the Read Stage)
    // In such a case, we must write them back, because they actually contain the
    // suspend information.
    if (m_input.Rav.m_state != RST_FULL)
    {
        COMMIT
        {
            // Write Rav (with suspend info) back to Rc.
            // The Remote Request information might contain a remote request
            // that will be send by the Writeback stage.
            m_output.Rc  = m_input.Rc;
            m_output.Rcv = m_input.Rav;
            
            // Force a thread switch
            m_output.swch    = true;
            m_output.kill    = false;
            m_output.suspend = SUSPEND_MISSING_DATA;
        }
        return PIPE_FLUSH;
    }
    
    COMMIT
    {
        // Set PC to point to next instruction
        m_output.pc = m_input.pc + sizeof(Instruction);
        
        // Copy input data and set some defaults
        m_output.Rc          = m_input.Rc;
        m_output.suspend     = SUSPEND_NONE;
        m_output.Rcv.m_state = RST_INVALID;
        m_output.Rcv.m_size  = m_input.RcSize;
    }
    
    PipeAction action = ExecuteInstruction();
    if (action != PIPE_STALL)
    {
        // Operation succeeded
        COMMIT
        {
            // We've executed an instruction
            m_op++;
            if (action == PIPE_FLUSH)
            {
                // Pipeline was flushed, thus there's a thread switch
                m_output.swch = true;
                m_output.kill = false;
            }
        }
    }
    
    return action;
}

bool Pipeline::ExecuteStage::ExecAllocate(PlaceID place, RegIndex reg, bool suspend, bool exclusive, Integer flags)
{
    if (place.size == 0)
    {
        // Inherit the parent's place
        place.size = m_input.placeSize;
        place.pid  = (m_parent.GetProcessor().GetPID() / place.size) * place.size;
    }
    
    // Size must be a power of two and ID a multiple of size.
    assert(IsPowerOfTwo(place.size));
    assert((place.pid % place.size) == 0);

    // Verify processor ID
    if (place.pid >= m_parent.GetProcessor().GetGridSize())
    {
        throw SimulationException("Attempting to delegate to a non-existing core");
    }
    
    AllocationType type = (AllocationType)(flags & 3);
    if (exclusive && type == ALLOCATE_BALANCED)
    {
        type = ALLOCATE_SINGLE;
        
        OutputWrite("Exclusive single allocate changed at %llx (%s) to exclusive single allocate",
            (unsigned long long)m_input.pc, GetKernel()->GetSymbolTable()[m_input.pc].c_str() );
    }
        
    // Send an allocation request.
    // This will write back the FID to the specified register once the allocation
    // has completed. Even for creates to this core, we do this. Simplifies things.
    COMMIT
    {
        m_output.Rrc.type = RemoteMessage::MSG_ALLOCATE;
        m_output.Rrc.allocate.place          = place;
        m_output.Rrc.allocate.suspend        = suspend;
        m_output.Rrc.allocate.exclusive      = exclusive;
        m_output.Rrc.allocate.type           = type;
        m_output.Rrc.allocate.completion_pid = m_parent.GetProcessor().GetPID();
        m_output.Rrc.allocate.completion_reg = reg;
            
        m_output.Rcv = MAKE_PENDING_PIPEVALUE(m_input.RcSize);
    }
    return true;
}

Pipeline::PipeAction Pipeline::ExecuteStage::SetFamilyProperty(const FID& fid, FamilyProperty property, Integer value)
{
    COMMIT
    {
        m_output.Rrc.type = RemoteMessage::MSG_SET_PROPERTY;
        m_output.Rrc.property.fid   = fid;
        m_output.Rrc.property.type  = property;
        m_output.Rrc.property.value = value;
    }
    return PIPE_CONTINUE;
}

Pipeline::PipeAction Pipeline::ExecuteStage::ExecCreate(const FID& fid, MemAddr address, RegIndex completion)
{
    // Create
    if (!MemoryWriteBarrier(m_input.tid))
    {
        // We need to wait for the pending writes to complete
        COMMIT
{'fraction_non_alphanumeric': 0.09818458321452334, 'fraction_numerical': 0.001520767987833856, 'mean_word_length': 2.1569156915691567, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2808288', 'n_tokens_mistral': 3327, 'n_tokens_neox': 3282, 'n_words': 819}