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

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

/*!
 * @file Declaration of the register allocation interface
 */

#ifndef IGT_REG_ALLOCATOR_H_
#define IGT_REG_ALLOCATOR_H_

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

namespace gtpin
{
#pragma pack(push, 8)

/* ===================================================================================================== */
// Class IGtRegAllocator
/* ===================================================================================================== */
/*! @ingroup GTPIN_REG_ALLOC
 * @brief Register allocation interface
 *
 * Normally, GTPin allocates registers when the tool finishes instrumentation of the original code.
 * This process is triggered automatically, without any tool's guidance.\n
 * The register allocation algorithm analyses register liveness in each instrumentation point, so that
 * the same virtual register can be assigned to different physical registers in different points. However,
 * if needed, the tool can use the IGtRegAllocator interface to allocate physical register (preg) for a
 * virtual register (vreg) globally, so that the same preg will represent vreg in all instrumentation
 * procedures.\n
 * <b>Note, such global assignments restrict flexibility of the register allocator in GTPin, so,
 * in general, using the instrumentation-time register allocation is discouraged. It is only recommended
 * for tools, that need to enforce minimal overhead of a specific instrumentation procedure.</b>
 *
 * @par Availability:
 * - IGtTool::OnKernelBuild
 */
class IGtRegAllocator
{
public:
    /*!
     * @brief Assign an available physical register (preg) to the specified virtual register (vreg)
     *
     * The assignment is global: preg will represent vreg in all instrumentation procedures.
     *
     * @param[in]   vn   Identifier of the virtual register to be assigned
     * @return true - success, false - no appropriate free physical register is found
     */
    virtual bool Reserve(GtVregNum vn) = 0;

    /*!
     * @brief Assign physical registers to all currently defined virtual registers that are not yet assigned
     *
     * The assignments are global: each vreg will be represented by the same preg in all instrumentation procedures.
     *
     * @return true - success,
     *         false - some virtual registers could not be assigned because no appropriate free physical registers are found.
     *         Note, even if the function fails, it attempts to allocate as many vregs as possible.
     */
    virtual bool ReserveAll() = 0;

    /*!
     * @brief Get physical register assigned to the specified virtual register
     * @param[in]   vn   Identifier of the virtual register being queried
     * @return  Physical register allocated for the specified virtual register.
     *          Return nullptr, if this virtual register is not (yet) reserved.
     */
    virtual const GtReg* GetReserved(GtVregNum vn) const = 0;

    /*!
     * @brief Remove assignment of a physical register to the specified virtual register, if any
     * @param[in]   vn   Identifier of the virtual register to be released
     */
    virtual void ReleaseReserved(GtVregNum vn) = 0;

    /// @brief Remove all physical-to-virtual register assignments
    virtual void ReleaseAllReserved() = 0;

    /*!
     * @brief Assign physical registers to all virtual registers used in the specified procedure.
     * @param[in]   proc   Procedure in which vregs should be allocated
     * @return true - success,
     *         false - virtual operands could not be assigned because no appropriate free physical registers are found.
     *         Note, if the function fails, the state of register allocations remains unchaged.
     */
    virtual bool ReserveVregOperands(const IGtGenProcedure& proc) = 0;

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

#pragma pack(pop)
}
#endif
