/*========================== begin_copyright_notice ============================
Copyright (C) 2021-2026 Intel Corporation

SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/

/*!
 * @file Factory of virtual registers
 */

#ifndef IGT_VREG_FACTORY_H_
#define IGT_VREG_FACTORY_H_

#include "gt_basic_defs.h"
#include "igt_vreg.h"

namespace gtpin
{
#pragma pack(push, 8)

/* ===================================================================================================== */
// Class IGtVregFactory
/* ===================================================================================================== */
/*! @ingroup GTPIN_REG_ALLOC 
 * @brief Factory and container of virtual registers
 * 
 * @par Availability:
 * - IGtTool::OnKernelBuild
 */
class IGtVregFactory
{
/* ===================================================================================================== */
// The implementation of this class is not required to be thread safe. It is intended to be used
// within serialized instrumentation sessions
/* ===================================================================================================== */
public:
    /*!
     * @brief Create a new virtual register with the specified properties and store it in the factory's container
     * @param[in]   type        Type of the register.
     * @param[in]   flags       Combination of VREG_FLAG values
     * @param[in]   subRegNum   If valid, specifies required subregister number for this vreg. Invalid value
     *                          means that this vreg has no restriction on physical subregister number assignment
     * @return Reference to the new virtual register
     * @pre Size of the virtual register, as implied by its type, should not exceed maximum size of physical
     *      registers in the GEN model, associated with the factory (see IGtGenModel::GrfRegSize()).
     */
    virtual const IGtVreg& Make(GtVregType type = VREG_TYPE_DWORD,
                                uint32_t flags = VREG_FLAG_NONE,
                                GtSubRegNum subRegNum  = GtSubRegNum::Invalid()) = 0;

    /*!
     * @brief Get virtual register with the specified ordinal number.
     * @param[in]   vn      Ordinal number of the virtual register
     * @pre Contains(vn)
     * @return The requested virtual register
     */
    virtual const IGtVreg& Get(GtVregNum vn) const = 0;

    /*!
     * @brief Get a special virtual register intended to hold address of the profile buffer in GPU
     * 
     * The returned register could be invalid, if GPU platform of this factory does not use a register
     * to hold pointer to the profile buffer. For example, some GPU platforms pass the buffer address
     * in a binding table entry rather than in a GRF register.\n
     * GTPin initializes this register at entry to the kernel. It is assumed that instrumentation procedures
     * do not modify the value of this register, and use it as a read-only virtual register.
     */
    virtual const IGtVreg& GetProfileBufferAddrVreg() const = 0;

    /*!
     * @brief Check to see if a virtual register with the specified ordinal number exists
     * @param[in]   vn      Ordinal number of the virtual register
     * @return true, if this container holds a virtual register with the specified ordinal number
     */
    virtual bool Contains(GtVregNum vn) const = 0;

    /// Return number of virtual registers in this container
    virtual uint32_t Size() const = 0;

    /// Remove all virtual registers created by this factory
    virtual void Clear() = 0;

    // Factory methods for popular register types
    /* ===================================================================================================== */

    /// Return Virtual register of the specified type, zero-initialized on entry to the kernel
    virtual const IGtVreg& MakeCounter(GtVregType type = VREG_TYPE_DWORD) = 0;

    /// Return Scratch virtual register of the specified type
    virtual const IGtVreg& MakeScratch(GtVregType type = VREG_TYPE_DWORD) = 0;

    /// Return Scratch virtual register of the specified type, intended to hold a SEND message address payload
    virtual const IGtVreg& MakeMsgAddrScratch(GtVregType type = VREG_TYPE_PTR) = 0;

    /// Return Scratch virtual register of the specified type, intended to hold a SEND message data payload
    virtual const IGtVreg& MakeMsgDataScratch(GtVregType type = VREG_TYPE_DWORD) = 0;

    /// Given vreg type, return the register size in bytes
    virtual uint32_t GetVregSize(GtVregType type) const = 0;

protected:
    /// @internal Protected destructor
    virtual ~IGtVregFactory() = default;
};
GTPIN_ASSERT_PURE_ABSTRACT(IGtVregFactory);

#pragma pack(pop)
}
#endif
