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

SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
/*!
 * @file GEN instruction fields and operands
 */

#ifndef GT_INS_FIELDS_H_
#define GT_INS_FIELDS_H_

#include "ged.h"
#include "gt_basic_defs.h"
#include "gt_basic_utils.h"
#include "gt_reg.h"
#include "igt_gen_arch.h"

namespace gtpin
{
#pragma pack(push, 8)

/* ===================================================================================================== */
// Class GtOpcode
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief An attribute that specifies whether and how the instruction modifies flag register
 */
class GtOpcode
{
public:
    constexpr GtOpcode(GED_OPCODE v = GED_OPCODE_INVALID) : _value(v) {}            ///< Conversion constructor
    constexpr operator GED_OPCODE() const { return _value; }                        ///< Conversion operator

    constexpr bool IsValid()       const { return _value != GED_OPCODE_INVALID; }
    const char*    ToString()      const { return GED_GetOpcodeString(_value); }    ///< Return string representation
private:
    Enum32T<GED_OPCODE> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtOpcode);

/* ===================================================================================================== */
// Class GtCondModifier
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief An attribute that specifies whether and how the instruction modifies flag register
 */
class GtCondModifier
{
public:
    constexpr GtCondModifier(GED_COND_MODIFIER v = GED_COND_MODIFIER_INVALID) : _value(v) {} ///< Conversion constructor
    constexpr operator GED_COND_MODIFIER() const { return _value; }                          ///< Conversion operator

    constexpr bool IsValid()       const { return _value != GED_COND_MODIFIER_INVALID; }
    constexpr bool IsNormal()      const { return _value == GED_COND_MODIFIER_Normal; }      ///< Return  true for normal (void) modifier
    const char*    ToString()      const { return GED_GetCondModifierString(_value); }       ///< Return string representation
private:
    Enum32T<GED_COND_MODIFIER> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtCondModifier);

/* ===================================================================================================== */
// Class GtAddrMode
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Addressing mode of the instruction operand
 */
class GtAddrMode
{
public:
    constexpr GtAddrMode(GED_ADDR_MODE v = GED_ADDR_MODE_INVALID) : _value(v) {}        ///< Conversion constructor
    constexpr operator GED_ADDR_MODE() const { return _value; }                         ///< Conversion operator

    constexpr bool IsValid()       const { return _value != GED_ADDR_MODE_INVALID; }
    constexpr bool IsDirect()      const { return _value == GED_ADDR_MODE_Direct; }     ///< Return  true for direct address mode
    constexpr bool IsIndirect()    const { return _value == GED_ADDR_MODE_Indirect; }   ///< Return  true for indirect address mode
    const char*    ToString()      const { return GED_GetAddrModeString(_value); }      ///< Return  true string representation
private:
    Enum32T<GED_ADDR_MODE> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtAddrMode);

/* ===================================================================================================== */
// Class GtSrcModifier
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Modifier of the source operand
 */
class GtSrcModifier
{
public:
    constexpr GtSrcModifier(GED_SRC_MOD v = GED_SRC_MOD_INVALID) : _value(v) {}     ///< Conversion constructor
    constexpr operator GED_SRC_MOD() const { return _value; }                       ///< Conversion operator

    /// Accessors
    constexpr bool IsValid()       const { return _value != GED_SRC_MOD_INVALID; }
    constexpr bool IsNormal()      const { return _value == GED_SRC_MOD_Normal; }   ///< Return  true for normal (void) modifier
    constexpr bool IsNegative()    const { return _value == GED_SRC_MOD_Negative; } ///< Return  rue for negation modifier
    const char*    ToString()      const { return GED_GetSrcModString(_value); }    ///< Return true string representation

    static constexpr GtSrcModifier Normal()     { return GED_SRC_MOD_Normal; }      ///< Make normal modifier
    static constexpr GtSrcModifier Negative()   { return GED_SRC_MOD_Negative; }    ///< Make negation modifier

private:
    Enum32T<GED_SRC_MOD> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtSrcModifier);

/* ===================================================================================================== */
// Class GtThreadCtrl
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Instruction attribute that controls thread switching
 */
class GtThreadCtrl
{
public:
    constexpr GtThreadCtrl(GED_THREAD_CTRL v = GED_THREAD_CTRL_INVALID) : _value(v) {}  ///< Conversion constructor
    constexpr operator GED_THREAD_CTRL() const { return _value; }                       ///< Conversion operator

    constexpr bool IsValid()       const { return _value != GED_THREAD_CTRL_INVALID; }
    constexpr bool IsNormal()      const { return _value == GED_THREAD_CTRL_Normal; }   ///< Return true for normal (void) thread control
    constexpr bool IsAtomic()      const { return _value == GED_THREAD_CTRL_Atomic; }   ///< Return true for atomic thread control
    constexpr bool IsSwitch()      const { return _value == GED_THREAD_CTRL_Switch; }   ///< Return true for thread switch control
    const char*    ToString()      const { return GED_GetThreadCtrlString(_value); }    ///< Return string representation
private:
    Enum32T<GED_THREAD_CTRL> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtThreadCtrl);

/* ===================================================================================================== */
// Class GtPredCtrl
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief An attribute that specifies whether and how the instruction is predicated
 */
class GtPredCtrl
{
public:
    constexpr GtPredCtrl(GED_PRED_CTRL v = GED_PRED_CTRL_INVALID) : _value(v) {}        ///< Conversion constructor
    constexpr operator GED_PRED_CTRL() const { return _value; }                         ///< Conversion operator

    constexpr bool IsValid()       const { return _value != GED_PRED_CTRL_INVALID; }
    constexpr bool IsNormal()      const { return _value == GED_PRED_CTRL_Normal; }     ///< Return true for normal (void) predication
    constexpr bool IsSequential()  const { return _value == GED_PRED_CTRL_Sequential; } ///< Return true for sequential predication
    const char*    ToString()      const { return GED_GetPredCtrlString(_value); }      ///< Return string representation
private:
    Enum32T<GED_PRED_CTRL> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GED_PRED_CTRL);

/* ===================================================================================================== */
// Class GtPredicate
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Arguments of the GEN Predicate Mask calculator
 */
class GtPredicate
{
public:
    inline        GtPredicate();          ///< Invalid predicate
    static inline GtPredicate MakeNone(); ///< Make a predicate that denotes a non-predicated instruction

    /*!
     * @brief Constructor
     * @param[in]   flagReg         Flag register that holds the prediacate value
     * @param[in]   isInverted      Attribute that indicates whether the predicate condition is inverted (true), or not (false)
     * @param[in]   predCtrl        Attribute that specifies whether and how the instruction is predicated 
     */
    inline GtPredicate(const GtReg& flagReg, bool isInverted = false, GtPredCtrl predCtrl = GED_PRED_CTRL_Sequential);

    inline bool         IsValid()       const { return _predCtrl.IsValid(); }
    inline bool         IsNone()        const { return _predCtrl.IsNormal(); }     ///< Return true for normal (void) predicate
    inline bool         IsInverted()    const { return _isInverted; }              ///< Return true, if predicate is inverted
    inline GtPredCtrl   Ctrl()          const { return _predCtrl; }                ///< Return predication control attribute
    inline GtReg        Reg()           const { return _flagReg; }                 ///< Return flag register associated with this predicate
    inline std::string  ToString()      const;                                     ///< Return string representation

    GtPredicate operator!() const { return GtPredicate(_flagReg, !_isInverted, _predCtrl);} ///< Inversion operator
    inline bool operator==(const GtPredicate& other) const;                                 ///< Comparison operator
    inline bool operator<(const GtPredicate& other) const;                                  ///< Comparison operator

private:
    GtPredCtrl   _predCtrl;      ///< A value of the instruction's 'PredCtrl' field
    GtReg        _flagReg;       ///< A flag register associated with the instruction
    bool         _isInverted;    ///< true, if the predicate condition is inverted; false, otherwise
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtPredicate);

/* ===================================================================================================== */
// Class GtExecSize
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Execution size of the instruction
 */
class GtExecSize
{
public:
    constexpr GtExecSize() : _value() {}
    constexpr GtExecSize(uint32_t v) : _value(v) {}         ///< Conversion constructor
    constexpr operator uint32_t() const { return _value; }  ///< Conversion operator

    constexpr bool IsValid() const { return ((_value > 0) && (_value <= 32) && IsPower2(_value)); }

private:
    Uint32Validatable<> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtExecSize);

/* ===================================================================================================== */
// Class GtChannelOffset
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Offset of the execution (channel) mask
 */
class GtChannelOffset
{
public:
    constexpr GtChannelOffset(uint32_t offset = 0) : _offset(offset) {} ///< Conversion constructor
    constexpr operator uint32_t() const { return _offset; }             ///< Conversion operator
    constexpr bool IsValid() const;
private:
    uint32_t _offset;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtChannelOffset);

/* ===================================================================================================== */
// Class GtExecMask
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Execution mask of the instruction
 */
class GtExecMask
{
public:
    inline constexpr GtExecMask() {}                                                                ///< Default constructor
    inline constexpr GtExecMask(GtExecSize execSize) : _execSize(execSize), _channelOffset(0) {}    ///< Conversion constructor

    /*!
     * @brief Construct execution mask for the specified execution size and the channel offset
     */
    inline constexpr GtExecMask(GtExecSize execSize, GtChannelOffset channelOffset);

    inline constexpr bool             IsValid()       const { return (_execSize.IsValid() && _channelOffset.IsValid()); }
    inline constexpr GtExecSize       ExecSize()      const { return _execSize; }                   ///< Return execution size
    inline constexpr GtChannelOffset  ChannelOffset() const { return _channelOffset; }              ///< Return channel offset

    inline  uint32_t Bits() const;                          ///< Return 32-bit mask of instruction channels
    inline  bool Includes(uint32_t bitMask) const;          ///< Return true, if this execution mask includes all bits of 'bitMask'
    inline  bool Includes(const GtExecMask execMask) const; ///< Return true if this execution mask includes 'execMask' bits

private:
    GtExecSize      _execSize;
    GtChannelOffset _channelOffset;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtExecMask);

/* ===================================================================================================== */
// Class GtSfid
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Shared Function ID
 */
class GtSfid
{
public:
    constexpr GtSfid(GED_SFID v = GED_SFID_INVALID) : _value(v) {}  ///< Conversion constructor
    constexpr operator GED_SFID() const { return _value; }          ///< Conversion operator

    constexpr bool      IsValid()                 const { return _value != GED_SFID_INVALID; }
    inline    bool      IsMemorySurface()         const; ///< Return true for the memory port
    inline    bool      IsMemorySurfaceReadOnly() const; ///< Return true for the memory port that supports only read operations
    inline    bool      IsMemorySurfaceWritable() const; ///< Return true for the memory port that supports write operations
    inline    bool      IsSlm()                   const; ///< Return true for the Shared Local Memory port
    inline    bool      IsUrb()                   const; ///< Return true for the Unified Return Buffer port
    inline    bool      IsLsc()                   const; ///< Return true for an LSC (Load-Store Cache) memory port
    inline    bool      IsSampler()               const; ///< Return true for the Sampler Shared Function
    inline const char*  ToString()                const; ///< Return string representation
private:
    Enum32T<GED_SFID> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtSfid);

/* ===================================================================================================== */
// Class MathFC
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Math Function Control
 */
class GtMathFC
{
public:
    constexpr GtMathFC(GED_MATH_FC v = GED_MATH_FC_INVALID) : _value(v) {}  ///< Conversion constructor
    constexpr operator GED_MATH_FC() const { return _value; }       ///< Conversion operator
    constexpr bool     IsValid()     const { return _value != GED_MATH_FC_INVALID; }
private:
    Enum32T<GED_MATH_FC> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtMathFC);

/* ===================================================================================================== */
// Class GtMessageType
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief SEND message type
 */
class GtMessageType
{
public:
    constexpr GtMessageType(GED_MESSAGE_TYPE v = GED_MESSAGE_TYPE_INVALID) : _value(v) {}       ///< Conversion constructor
    constexpr operator GED_MESSAGE_TYPE() const { return _value; }                              ///< Conversion operator

    constexpr bool         IsValid()   const { return _value != GED_MESSAGE_TYPE_INVALID; }
    inline    bool         IsAtomic()  const;
    inline    const char*  ToString()  const { return GED_GetMessageTypeString(_value); }       ///< Return string representation
private:
    Enum32T<GED_MESSAGE_TYPE> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtMessageType);

/* ===================================================================================================== */
// Class GtAtomicOp
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Type of the atomic operation
 */
class GtAtomicOp
{
public:
    constexpr GtAtomicOp(GED_ATOMIC_OPERATION_TYPE v = GED_ATOMIC_OPERATION_TYPE_INVALID) : _value(v) {} ///< Conversion constructor
    constexpr operator GED_ATOMIC_OPERATION_TYPE() const { return _value; }                              ///< Conversion operator

    constexpr bool      IsValid()   const { return _value != GED_ATOMIC_OPERATION_TYPE_INVALID; }
    inline const char*  ToString()  const { return GED_GetAtomicOperationTypeString(_value); }           ///< Return string representation
private:
    Enum32T<GED_ATOMIC_OPERATION_TYPE> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtAtomicOp);

/* ===================================================================================================== */
// Class GtDataType
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Data type of the instruction operand
 */
class GtDataType
{
public:
    constexpr GtDataType(GED_DATA_TYPE v = GED_DATA_TYPE_INVALID) : _value(v) {}                ///< Conversion constructor
    constexpr operator GED_DATA_TYPE() const { return _value; }                                 ///< Conversion operator

    constexpr bool      IsValid()   const { return _value != GED_DATA_TYPE_INVALID; }
    inline uint32_t     Size()      const;                                                      ///< Return Size of the data type, in bytes
    inline bool         IsInteger() const;                                                      ///< Return true for integer data type
    inline const char*  ToString()  const { return GED_GetDataTypeString(_value); }             ///< Return string representation

    static inline GtDataType MakeInt(uint32_t size);    ///< Return signed integer type of the specified size in bytes. @pre size = 1, 2, 4 or 8
    static inline GtDataType MakeUint(uint32_t size);   ///< Return unsigned integer type of the specified size in bytes. @pre size = 1, 2, 4 or 8

private:
    Enum32T<GED_DATA_TYPE> _value;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtDataType);

/* ===================================================================================================== */
// Register region
/* ===================================================================================================== */
/*! @addtogroup GTPIN_GEN_ARCH 
    @{
 */
/// Vertical stride in the register region
using GtVertStride = Uint32Validatable<struct _GtVertStride>;

/// Number of elements in the register region's row
using GtWidth = Uint32Validatable<struct _GtWidth>;

/// Horizontal stride in the register region
using GtHorzStride = Uint32Validatable<struct _GtHorzStride>;

/// Structure that specifies striding scheme of the register region
struct GtStride
{
    /// Default constructor
    constexpr GtStride() = default;

    /// Construct a GtStride object for the specified vertical stride, width, and the horizontal stride
    constexpr GtStride(GtVertStride v, GtWidth w, GtHorzStride h) : vert(v), width(w), horz(h) {}

    /// Return true if this object represents a valid striding scheme of the register region
    constexpr bool IsValid() const { return (vert.IsValid() && width.IsValid() && horz.IsValid()); }

    GtVertStride    vert;
    GtWidth         width;
    GtHorzStride    horz;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtStride);

/// Return striding scheme for scalar register region
inline GtStride ScalarStride() { return GtStride(0, 1, 0); }
/*! @} */

/* ===================================================================================================== */
// Class GtRegRegion
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Register operand of the GEN instruction. Defines the register region accessed by the instruction
 */
class GtRegRegion
{
public:
    /// Default constructor
    inline GtRegRegion();

    /*!
     * @brief Construct an integer register region with the direct addressing mode, specified origin and
     * the striding scheme.
     * 
     * The region gets an unsigned integer type whose size is reg.ElementSize().
     * 
     * @param[in]   reg         The origin element of the register region
     * @param[in]   stride      The striding scheme of the register region
     */ 
    inline GtRegRegion(const GtReg& reg, const GtStride& stride = ScalarStride());

    /*!
     * @brief Construct a register region with the direct addressing mode, specified origin, striding scheme
     * and element type.
     * 
     * @param[in]   reg         The origin element of the register region
     * @param[in]   stride      The striding scheme of the register region
     * @param[in]   dataType    The type of the region's data element
     * @post Reg().ElementSize() == dataType.Size()
     */
    inline GtRegRegion(const GtReg& reg, const GtStride& stride, GtDataType dataType);

    /*!
     * @brief Construct a register region with the specified addressing mode, origin, striding scheme
     * and element type.
     * 
     * @param[in]   reg         In the direct addressing mode, the origin element of the register region.
     *                          In the indirect addressing mode, an ARF register that addresses the origin
     *                          of the register region in GRF
     * @param[in]   stride      The striding scheme of the register region
     * @param[in]   dataType    The type of the region's data element
     * @param[in]   addrMode    The addresing mode of the register region, either direct or indirect
     * @param[in]   addrImm     Address immediate offset - a signed integer, added to subregister of the indirectly
     *                          addressed GRF register. Ignored in the direct addressing mode.
     * @pre !addrMode.IsIndirect() || reg.IsAddrReg()
     * @post addrMode.IsIndirect() || (Reg().ElementSize() == dataType.Size())
     */
    inline GtRegRegion(const GtReg& reg, const GtStride& stride, GtDataType dataType, GtAddrMode addrMode,
                       int32_t addrImm = 0);

    inline bool            IsValid()    const { return _reg.IsValid(); }///< Return true for a valid register region
    inline GtRegFileType   Type()       const { return _reg.Type(); }   ///< Return type of the register region
    inline const GtReg&    Reg()        const { return _reg; }          ///< Return origin of the register region
    inline const GtStride& Stride()     const { return _stride; }       ///< Return striding scheme of the register region
    inline GtDataType      DataType()   const { return _dataType; }     ///< Return type of the element in the register region
    inline GtAddrMode      AddrMode()   const { return _addrMode; }     ///< Return addressing mode of the register region
    inline int32_t         AddrImm()    const { return _addrImm; }      ///< Return address immediate offset

private:
    GtReg       _reg;
    GtStride    _stride;
    GtDataType  _dataType;
    GtAddrMode  _addrMode;
    int32_t     _addrImm;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtRegRegion);

/*! @ingroup GTPIN_GEN_ARCH
 * @brief Construct a scalar register region with the specified origin and element type
 */
inline GtRegRegion ScalarRegion(const GtReg& reg, GtDataType dataType)
{
    return GtRegRegion(reg, ScalarStride(), dataType);
}

/* ===================================================================================================== */
// Class GtDstRegion
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Destination operand of the GEN instruction.
 * 
 * The destination operand is only allowed to have a one-dimensional region (vector or scalar).
 * The width of the vector equals the execution size of the instruction.
 * Only horizontal stride is required in the GtStride specification.
 */
class GtDstRegion
{
public:
    GtDstRegion() = default;    ///< Default constructor

    /*!
     * @brief Construct a destination register region with the direct addressing mode, specified origin and
     * the horizontal stride.
     * 
     * The region gets unsigned integer type whose size is reg.ElementSize().
     * 
     * @param[in]   reg         The origin element of the destination region
     * @param[in]   hStride     The horizontal stride of the destination region
     */
    inline GtDstRegion(const GtReg& reg, GtHorzStride hStride = 1);

    /*!
     * @brief Construct a destination register region with the direct addressing mode, specified origin,
     * horizontal stride and element type.
     * 
     * @param[in]   reg         The origin element of the destination region
     * @param[in]   hStride     The horizontal stride of the destination region
     * @param[in]   dataType    The type of the element in the destination region
     * @post Reg().ElementSize() == dataType.Size().
     */
    inline GtDstRegion(const GtReg& reg, GtHorzStride hStride, GtDataType dataType);

    /*!
     * @brief Construct a destination region with the specified addressing mode, origin, horizontal stride
     * and element type.
     * 
     * @param[in]   reg         In the direct addressing mode, the origin element of the destination region.
     *                          In the indirect addressing mode, an ARF register that addresses the origin
     *                          of the destination region in GRF.
     * @param[in]   hStride     The horizontal stride of the destination region
     * @param[in]   dataType    The type of the region's data element
     * @param[in]   addrMode    The addresing mode of the register region, either direct or indirect
     * @param[in]   addrImm     Address immediate offset - a signed integer, added to subregister of the indirectly
     *                          addressed GRF register. Ignored in the direct addressing mode.
     * @pre !addrMode.IsIndirect() || reg.IsAddrReg()
     * @post addrMode.IsIndirect() || (Reg().ElementSize() == dataType.Size())
     */
    inline GtDstRegion(const GtReg& reg, GtHorzStride hStride, GtDataType dataType, GtAddrMode addrMode,
                       int32_t addrImm = 0);

    inline bool            IsValid()    const { return _reg.IsValid(); }///< Return true for a valid register region
    inline GtRegFileType   Type()       const { return _reg.Type(); }   ///< Return type of the register region
    inline const GtReg&    Reg()        const { return _reg; }          ///< Return origin of the destination region
    inline GtHorzStride    HorzStride() const { return _hStride; }      ///< Return horizontal stride of the destination region
    inline GtDataType      DataType()   const { return _dataType; }     ///< Return type of the element in the destination region
    inline GtAddrMode      AddrMode()   const { return _addrMode; }     ///< Return addressing mode of the register region
    inline int32_t         AddrImm()    const { return _addrImm; }      ///< Return address immediate offset

private:
    GtReg           _reg;
    GtHorzStride    _hStride;
    GtDataType      _dataType;
    GtAddrMode      _addrMode;
    int32_t         _addrImm;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtDstRegion);

/* ===================================================================================================== */
// Class GtImm
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 * @brief Immediate operand of the GEN instruction
 */
class GtImm
{
public:
    constexpr GtImm() : _value(0) {}    ///< Default constructor

    /*!
     * @brief Construct immediate operand with the specified type and value.
     * @note Extension of signed integer value to 64 bit must preserve sign of the value.
     *       GtImmS32() can be helpful in defining signed 32-bit immediate operands.
     */
    constexpr GtImm(uint64_t value, GtDataType dataType = GED_DATA_TYPE_ud) : _value(value), _dataType(dataType) {}

    constexpr bool IsValid()          const { return _dataType.IsValid(); }   ///< Return true for a valid immediate operand
    constexpr GtDataType DataType()   const { return _dataType; }             ///< Return type of the operand

    /*!
     * @brief Return Value of the immediate operand
     * @note Explicit casting of immediate value to an appropriate C type is a caller's responsibility.
     */
    constexpr uint64_t Value()    const { return _value; }
    constexpr operator uint64_t() const { return Value(); } ///< @copydoc Value()

private:
    uint64_t     _value;
    GtDataType   _dataType;
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtImm);

/* ===================================================================================================== */
// Class GtSystolicInfo
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_ARCH
 *  @brief Properties/attributes of the systolic array instruction
 */
class GtSystolicInfo
{
public:
    inline        GtSystolicInfo();          ///< Invalid systolic info

    /*!
     * @brief Constructor
     * @param[in]   rcount          Rcount field
     * @param[in]   sdepth          Sdepth field
     * @param[in]   opsPerChannel   Number of operations per channel
     * @param[in]   src1Precision   Precision in bits of src1
     * @param[in]   src2Precision   Precision in bits of src2
     */
    inline GtSystolicInfo(uint32_t rcount,
                          uint32_t sdepth,
                          uint32_t opsPerChannel,
                          uint32_t src1Precision,
                          uint32_t src2Precision);

    constexpr bool        IsValid()     const { return _rCount.IsValid(); } ///< Return true for a valid systolic info

    uint32_t              RepeatCount()    const { return _rCount; };       ///< @return Rcount filed of systolic array instruction
    uint32_t              Depth()          const { return _sDepth; };       ///< @return Sdepth field of systolic array instruction
    uint32_t              OpsPerChannel()  const { return _opsPerChannel; };///< @return Number of operations per channel of systolic array instruction and zero otherwise
    inline uint32_t       SrcPrecisionInBits(uint32_t index) const;         ///< @return Precision in bits of Src1 or Src2 operand of systolic array instruction and zero otherwise

private:
    Uint32Validatable<>  _rCount;         ///< Rcount field of systolic array instruction
    Uint32Validatable<>  _sDepth;         ///< Sdepth field of systolic array instruction
    uint32_t             _opsPerChannel;  ///< Number of operations per channel of systolic array instruction and zero otherwise
    uint32_t             _src1Precision;  ///< Precision in bits of Src1 operand of systolic array instruction and zero otherwise
    uint32_t             _src2Precision;  ///< Precision in bits of Src2 operand of systolic array instruction and zero otherwise
};
GTPIN_ASSERT_STANDARD_LAYOUT(GtSystolicInfo);

/*! @ingroup GTPIN_GEN_ARCH
 * @brief Construct immediate operand of GED_DATA_TYPE_ud type (unsigned 32-bit integer)
 */
inline constexpr GtImm GtImmU32(uint32_t value) { return GtImm(value, GED_DATA_TYPE_ud); }

/*! @ingroup GTPIN_GEN_ARCH
 * @brief Construct immediate operand of GED_DATA_TYPE_d type (signed 32-bit integer)
 */
inline constexpr GtImm GtImmS32(int32_t value) { return GtImm(int64_t(value), GED_DATA_TYPE_d); }

/* ===================================================================================================== */
// GtSystolicInfo implementation
/* ===================================================================================================== */
GtSystolicInfo::GtSystolicInfo() : _rCount(), _sDepth(), _opsPerChannel(0), _src1Precision(0), _src2Precision(0) {}

GtSystolicInfo::GtSystolicInfo(uint32_t rcount,
                               uint32_t sdepth,
                               uint32_t opsPerChannel,
                               uint32_t src1Precision,
                               uint32_t src2Precision) :
                               _rCount(rcount), _sDepth(sdepth), _opsPerChannel(opsPerChannel), _src1Precision(src1Precision), _src2Precision(src2Precision) {}

uint32_t GtSystolicInfo::SrcPrecisionInBits(uint32_t index) const
{
    switch (index) {
    case 1: return _src1Precision;
    case 2: return _src2Precision;
    default: return 0;
    }
}
/* ===================================================================================================== */
// GtPredicate implementation
/* ===================================================================================================== */
GtPredicate::GtPredicate() : _isInverted(false) {}

GtPredicate::GtPredicate(const GtReg& flagReg, bool isInverted, GtPredCtrl predCtrl) :
    _predCtrl(predCtrl), _flagReg(flagReg), _isInverted(isInverted) {}

GtPredicate GtPredicate::MakeNone() { return {FlagReg(0), false, GED_PRED_CTRL_Normal}; }

std::string GtPredicate::ToString() const
{
    std::string invStr = GED_GetPredInvString(IsInverted() ? GED_PRED_INV_Invert : GED_PRED_INV_Normal);
    return std::string(Ctrl().ToString()) + ", " + invStr + ", " + Reg().ToString();
}

/* ===================================================================================================== */
// GtChannelOffset implementation
/* ===================================================================================================== */
constexpr bool GtChannelOffset::IsValid() const
{
    return ((_offset < 32) && ((_offset % 4) == 0));
}

/* ===================================================================================================== */
// GtExecMask implementation
/* ===================================================================================================== */
constexpr GtExecMask::GtExecMask(GtExecSize execSize, GtChannelOffset channelOffset) :
    _execSize(execSize), _channelOffset(channelOffset) {}

uint32_t GtExecMask::Bits() const
{
    return  (_execSize.IsValid() ? BitMask<uint32_t>(_channelOffset, _channelOffset + _execSize - 1) : ~0);
}

bool GtExecMask::Includes(uint32_t bitMask) const           { return ((bitMask & ~Bits()) == 0); }
bool GtExecMask::Includes(const GtExecMask execMask) const  { return ((execMask.Bits() & ~Bits()) == 0); }

/* ===================================================================================================== */
// GtPredicate implementation
/* ===================================================================================================== */
bool GtPredicate::operator==(const GtPredicate& other) const
{
    GED_PRED_CTRL ctrl      = _predCtrl;
    GED_PRED_CTRL otherCtrl = other._predCtrl;

    return  ((ctrl == otherCtrl) && (_flagReg  == other._flagReg)  && (_isInverted == other._isInverted));
}

bool GtPredicate::operator<(const GtPredicate& other) const
{
    GED_PRED_CTRL ctrl      = _predCtrl;
    GED_PRED_CTRL otherCtrl = other._predCtrl;

    return  ((ctrl < otherCtrl)             || ((ctrl == otherCtrl)          &&
             ((_flagReg  < other._flagReg)  || ((_flagReg == other._flagReg) &&
             (_isInverted < other._isInverted)))));
}

/* ===================================================================================================== */
// GtSfid implementation
/* ===================================================================================================== */
bool GtSfid::IsSampler() const
{
    return (_value == GED_SFID_SAMPLER) || (_value == GED_SFID_DP_SAMPLER);
}

bool GtSfid::IsUrb() const
{
    return (_value == GED_SFID_URB);
}

bool GtSfid::IsSlm() const
{
    return (_value == GED_SFID_SLM);
}

bool GtSfid::IsMemorySurface() const
{
    return GetGenArch().IsMemorySurface(_value);
}

bool GtSfid::IsMemorySurfaceReadOnly() const
{
    return GetGenArch().IsMemorySurfaceReadOnly(_value);
}

bool GtSfid::IsMemorySurfaceWritable() const
{
    return GetGenArch().IsMemorySurfaceWritable(_value);
}

bool GtSfid::IsLsc() const
{
    switch (_value)
    {
    case GED_SFID_UGM:
    case GED_SFID_TGM:
    case GED_SFID_SLM:
    case GED_SFID_UGML:
        return true;
    default:
        return false;
    }
}

const char* GtSfid::ToString() const
{
    return GED_GetSFIDString(_value);
}

/* ===================================================================================================== */
// GtMessageType implementation
/* ===================================================================================================== */
bool GtMessageType::IsAtomic() const
{
    return GetGenArch().IsAtomicMemoryAccess(_value);
}

/* ===================================================================================================== */
// GtDataType implementation
/* ===================================================================================================== */
bool GtDataType::IsInteger() const
{
    // Get quick answer for most popular data types
    switch (_value)
    {
    case GED_DATA_TYPE_ud:
    case GED_DATA_TYPE_d:
    case GED_DATA_TYPE_uw:
    case GED_DATA_TYPE_w:
    case GED_DATA_TYPE_ub:
    case GED_DATA_TYPE_b:
    case GED_DATA_TYPE_uq:
    case GED_DATA_TYPE_q:
    case GED_DATA_TYPE_uv:
    case GED_DATA_TYPE_v:
        return true;

    case GED_DATA_TYPE_df:
    case GED_DATA_TYPE_f: 
    case GED_DATA_TYPE_hf:
    case GED_DATA_TYPE_vf:
    case GED_DATA_TYPE_nf:
        return false;

    default:
        // IGtGenArch::IsIntegerDataType() handles all data types and supports experimental GED models
        return GetGenArch().IsIntegerDataType(_value);
    }
}

uint32_t GtDataType::Size() const
{
    // Get quick answer for most popular data types
    switch (_value)
    {
    case GED_DATA_TYPE_INVALID: return 0;
    case GED_DATA_TYPE_ud:      return 4;
    case GED_DATA_TYPE_d:       return 4;
    case GED_DATA_TYPE_uw:      return 2;
    case GED_DATA_TYPE_w:       return 2;
    case GED_DATA_TYPE_ub:      return 1;
    case GED_DATA_TYPE_b:       return 1;
    case GED_DATA_TYPE_df:      return 8;
    case GED_DATA_TYPE_f:       return 4;
    case GED_DATA_TYPE_uq:      return 8;
    case GED_DATA_TYPE_q:       return 8;
    case GED_DATA_TYPE_hf:      return 2;
    case GED_DATA_TYPE_uv:      return 4;
    case GED_DATA_TYPE_vf:      return 4;
    case GED_DATA_TYPE_v:       return 4;
    case GED_DATA_TYPE_nf:      return 4;
    default:
        // IGtGenArch::IsIntegerDataType() handles all data types and supports experimental GED models
        return GetGenArch().DataElementSize(_value);
    }
}

GtDataType GtDataType::MakeInt(uint32_t size)
{
    switch (size)
    {
    case 1:  return GED_DATA_TYPE_b;
    case 2:  return GED_DATA_TYPE_w;
    case 4:  return GED_DATA_TYPE_d;
    case 8:  return GED_DATA_TYPE_q;
    default: return GED_DATA_TYPE_INVALID;
    }
}

GtDataType GtDataType::MakeUint(uint32_t size)
{
    switch (size)
    {
    case 1:  return GED_DATA_TYPE_ub;
    case 2:  return GED_DATA_TYPE_uw;
    case 4:  return GED_DATA_TYPE_ud;
    case 8:  return GED_DATA_TYPE_uq;
    default: return GED_DATA_TYPE_INVALID;
    }
}
/* ===================================================================================================== */
// GtRegRegion implementation
/* ===================================================================================================== */
GtRegRegion::GtRegRegion() : _addrImm(0) {}

GtRegRegion::GtRegRegion(const GtReg& reg, const GtStride& stride) :
    _reg(reg), _stride(stride), _dataType(GtDataType::MakeUint(reg.ElementSize())),
    _addrMode(GED_ADDR_MODE_Direct), _addrImm(0) {}

GtRegRegion::GtRegRegion(const GtReg& reg, const GtStride& stride, GtDataType dataType) :
    _reg(reg), _stride(stride), _dataType(dataType), _addrMode(GED_ADDR_MODE_Direct), _addrImm(0)
{
    _reg.Resize(_dataType.Size());
}

GtRegRegion::GtRegRegion(const GtReg& reg, const GtStride& stride, GtDataType dataType, GtAddrMode addrMode, int32_t addrImm) :
    _reg(reg), _stride(stride), _dataType(dataType), _addrMode(addrMode), _addrImm(addrImm)
{
    if (_addrMode.IsIndirect())
    {
        GTPIN_ASSERT(reg.IsAddrReg());
    }
    else
    {
        _reg.Resize(_dataType.Size());
    }
}

/* ===================================================================================================== */
// GtDstRegion implementation
/* ===================================================================================================== */
GtDstRegion::GtDstRegion(const GtReg& reg, GtHorzStride hStride) :
    _reg(reg), _hStride(hStride), _dataType(GtDataType::MakeUint(reg.ElementSize())),
    _addrMode(GED_ADDR_MODE_Direct), _addrImm(0) {}

GtDstRegion::GtDstRegion(const GtReg& reg, GtHorzStride hStride, GtDataType dataType) :
    _reg(reg), _hStride(hStride), _dataType(dataType), _addrMode(GED_ADDR_MODE_Direct), _addrImm(0)
{
    _reg.Resize(_dataType.Size());
}

GtDstRegion::GtDstRegion(const GtReg& reg, GtHorzStride hStride, GtDataType dataType, GtAddrMode addrMode, int32_t addrImm) :
    _reg(reg), _hStride(hStride), _dataType(dataType), _addrMode(addrMode), _addrImm(addrImm)
{
    if (_addrMode.IsIndirect())
    {
        GTPIN_ASSERT(reg.IsAddrReg());
    }
    else
    {
        _reg.Resize(_dataType.Size());
    }
}

#pragma pack(pop)
}
#endif
