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

SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
/*!
 * @file Control flow graph (CFG) interface
 */

#ifndef IGT_CFG_H_
#define IGT_CFG_H_

#include "gt_basic_defs.h"
#include "igt_ins.h"

namespace gtpin
{
#pragma pack(push, 8)

class IGtIns;                                           ///< Abstract representation of the GEN instruction
class IGtBbl;                                           ///< Class that represents a basic block in CFG
class IGtFunction;                                      ///< Class that represents a function in CFG
class IGtEdge;                                          ///< Class that represents a CFG edge

/*! @addtogroup GTPIN_CFG 
    @{
 */
using BblId        = Uint32Validatable<struct _BblId>;          ///< Identifier of a basic block in CFG
using FunctionId   = Uint32Validatable<struct _FunctionId>;     ///< Identifier of a function in CFG
using ImgOffset    = Uint32Validatable<struct _ImgOffset>;      ///< Offset within an image
using ElfSectionId = Uint32Validatable<struct _ElfSectionId>;   ///< Identifier of a section in ELF
using ElfSymbolId  = Uint32Validatable<struct _ElfSymbolId>;    ///< Identifier of a symbol in ELF

using InsSpan      = Span<const IGtIns* const>;        ///< Sequence of pointers to instructions
using BblSpan      = Span<const IGtBbl* const>;        ///< Sequence of pointers to basic blocks
using FunctionSpan = Span<const IGtFunction* const>;   ///< Sequence of pointers to functions
using EdgeSpan     = Span<const IGtEdge* const>;       ///< Sequence of pointers to edges between basic blocks
/*! @} */

/* ===================================================================================================== */
// Class IGtBbl
/* ===================================================================================================== */
/*! @ingroup GTPIN_CFG
 *  @brief Class that represents a basic block in the Control Flow Graph
 * 
 * @par Availability:
 * - IGtTool::OnKernelBuild
 */
class IGtBbl
{
public:
    virtual BblId           Id()             const = 0; ///< Return unique identifier of this BBL
    virtual uint32_t        Size()           const = 0; ///< Return size of this BBL in bytes

    virtual bool            IsEntry()        const = 0; ///< Return true if this BBL is an entry point to CFG
    virtual bool            IsEot()          const = 0; ///< Return true if this BBL ends with a EOT instruction
    virtual bool            HasFallThrough() const = 0; ///< Return true if this BBL has fall-through path

    virtual InsSpan         Instructions()   const = 0; ///< Return sequence of instructions in this BBL
    virtual bool            IsEmpty()        const = 0; ///< Return true, if this BBL ia empty
    virtual uint32_t        NumIns()         const = 0; ///< Return number of instructions in this BBL
    virtual const IGtIns&   FirstIns()       const = 0; ///< Return first instruction @pre BBL is not empty
    virtual const IGtIns&   LastIns()        const = 0; ///< Return last instruction @pre BBL is not empty

    virtual EdgeSpan        IncomingEdges()  const = 0; ///< Return sequence of incoming edges
    virtual EdgeSpan        OutgoingEdges()  const = 0; ///< Return sequence of outgoing edges

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

/* ===================================================================================================== */
// Class IGtFunction
/* ===================================================================================================== */
/*! @ingroup GTPIN_CFG
 *  @brief Class that represents a function in the Control Flow Graph
 * 
 * @par Availability:
 * - IGtTool::OnKernelBuild
 */
class IGtFunction
{
public:
    virtual FunctionId   Id()              const = 0;  ///< Return unique identifier of this function
    virtual GtCoreString Name()            const = 0;  ///< Return name of the function 
    virtual uint32_t     Size()            const = 0;  ///< Return code size of the function in bytes
    virtual bool         IsKernelMain()    const = 0;  ///< Return true for the kernel's main function
    virtual ElfSectionId SectionId()       const = 0;  ///< Return identifier of the ELF section, this function belongs to
    virtual ImgOffset    OffsetInSection() const = 0;  ///< Return offset of the function within the ELF section
    virtual BblSpan      Bbls()            const = 0;  ///< Return sequence of basic blocks in the fallthrough order

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

/* ===================================================================================================== */
// Class IGtEdge
/* ===================================================================================================== */
/*! @ingroup GTPIN_CFG
 *  @brief Class that represents an edge between basic blocks of the Control Flow Graph
 * 
 * @par Availability:
 * - IGtTool::OnKernelBuild
 */
class IGtEdge
{
public:
    virtual const IGtBbl&   SrcBbl()        const = 0;  ///< Return source BBL of this edge
    virtual const IGtBbl&   DstBbl()        const = 0;  ///< Return destination BBL of this edge
    virtual bool            IsFallThrough() const = 0;  ///< Return true for the fallthrough edge

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

/* ===================================================================================================== */
// Class IGtCfg
/* ===================================================================================================== */
/*! @ingroup GTPIN_CFG
 *  @brief Class that represents a control flow graph (CFG) and provides the code traversal interface
 * 
 * @par Availability:
 * - IGtTool::OnKernelBuild
 */
class IGtCfg
{
public:
    virtual BblSpan         Bbls()          const = 0;  ///< Return sequence of basic blocks in the fallthrough order
    virtual FunctionSpan    Functions()     const = 0;  ///< Return sequence of functions in this CFG 
    virtual BblSpan         EntryBbls()     const = 0;  ///< Return sequence of entry basic blocks
    virtual BblSpan         ExitBbls()      const = 0;  ///< Return sequence of EOT basic blocks
    virtual bool            IsEmpty()       const = 0;  ///< Return true, if this CFG is empty
    virtual uint32_t        NumBbls()       const = 0;  ///< Return number of BBLs in this CFG
    virtual uint32_t        NumFunctions()  const = 0;  ///< Return number of functions in this CFG

    /// Given identifier of an instruction, return reference to the corresponding IGtIns object. @pre insId.IsValid()
    virtual const IGtIns& GetInstruction(InsId insId) const = 0;

    /// Given identifier of a basic block, return reference to the corresponding IGtBbl object. @pre bblId.IsValid()
    virtual const IGtBbl& GetBbl(BblId bblId) const = 0;

    /// Given identifier of a function, return reference to the corresponding IGtFunction object. @pre funcId.IsValid()
    virtual const IGtFunction& GetFunction(FunctionId funcId) const = 0;

    /*!
     * @brief Get basic block the specified instruction belongs to
     * @pre ins.Id().IsValid()
     * @return reference to the requested basic block
     */
    virtual const IGtBbl& GetBbl(const IGtIns& ins) const = 0;

    /*!
     * @brief Get function that contains the specified instruction
     * @return Pointer to the requested function, or null pointer if such function is not found
     */
    virtual const IGtFunction* FindFunction(const IGtIns& ins) const = 0;

    /*!
     * @brief Get the main kernel function
     * @pre This CFG is not empty
     * @return Reference to the main kernel function
     */
    virtual const IGtFunction&  GetMainFunction() const = 0;

    /*!
     * @brief Get the offset of the specified instruction within the function it belongs to
     * @return Offset of the specified instruction relative to the beginning of the function it belongs to.
     *         For instruction that does not belong to any function of this CFG, the returned value is
     *         ImgOffset::Invalid().
     */
    virtual ImgOffset GetInstructionOffsetInFunction(const IGtIns& ins) const = 0;

    /*!
     * @brief Get the offset of the specified instruction within the kernel binary
     * @return Offset of the specified instruction within the kernel binary, as provided by the IgtKernel::Binary()
     *         function. For instruction that does not belong to this CFG, the returned value is ImgOffset::Invalid().
     * 
     * @note   This function should not be used to associate IGtIns object with the corresponding instruction
     *         in the program's ELF, because it does not indicate which ELF section contains this instruction.
     *         Instead, GetFunction() and GetInstructionOffsetInFunction() functions can be used to look up ELF
     *         information associated with the instruction.
     *         
     * @note   For monolithic kernels that consist of a single (main) function, both GetInstructionOffsetInFunction() and
     *         GetInstructionOffset() return the same value
     */
    virtual ImgOffset GetInstructionOffset(const IGtIns& ins) const = 0;

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

#pragma pack(pop)
}
#endif
