/*========================== begin_copyright_notice ============================

Copyright (C) 2017-2021 Intel Corporation

SPDX-License-Identifier: MIT

============================= end_copyright_notice ===========================*/

#ifndef _BINARYENCODINGCNL_H_
#define _BINARYENCODINGCNL_H_

#include "FlowGraph.h"
#include "BinaryEncoding.h"

///=--- Definitions for auto-generated header.

#if defined(_WIN32)
#include <windows.h>
#endif
#include "VISADefines.h"

#if !defined(_WIN32)
typedef unsigned char BYTE;
typedef uint32_t  UINT;
#endif
typedef uint64_t QWORD;

#define BITFIELD_RANGE(startbit, endbit)     ((endbit)-(startbit)+1)
#define BITFIELD_BIT(bit)                   1

#if !defined(__ANDROID__)
#define __CONCAT(x,y)   x ## y
#endif
#define __UNIQUENAME(a1, a2)  __CONCAT(a1, a2)
#define UNIQUENAME(__text)    __UNIQUENAME(__text, __COUNTER__)
#define STATIC_ASSERT(e)  typedef char UNIQUENAME(STATIC_ASSERT_)[(e)?1:-1]

#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]

#define __CODEGEN_UNIQUE(field)   UNIQUENAME(field)
#define __CODEGEN_INLINE            inline
#define __CODEGEN_PACKED            _PACKED
#define __CODEGEN_ATTRIBUTES_STRUCTURE

#define __CODEGEN_GET_MACRO()
#define __CODEGEN_SET_MACRO(value)

#define __CODEGEN_DefineDebugCommand(type, ...) inline void DebugCommand(type, ...)
#define __CODEGEN_DebugCommandEnumParam(type, ...)
#define __CODEGEN_DebugCommandUIntParam(type, ...)
#define __CODEGEN_DebugCommandBoolParam(type, ...)
#define __CODEGEN_DefineEnumString(type)  inline void EnumString(type)
#define __CODEGEN_EnumStringValue(value)

// Gen9 defines
#define __CODEGEN_FILE_DIRECTIVES_OPEN
#define __CODEGEN_NAMESPACE_OPEN        namespace G9HDL {
#define __CODEGEN_NAMESPACE_CLOSE       } // namespace G9HDL
#define __CODEGEN_FILE_DIRECTIVES_CLOSE
#define __CODEGEN_ACCESS_SPECIFIER_DEFINITION
#define __CODEGEN_ACCESS_SPECIFIER_METHODS

///=--- Definitions for auto-generated header.
#pragma pack(push, 1)
#include "IGfxHwEuIsaCNL.h"

#include "IGfxHwEuIsaICL.h"


/// \brief Class encapsulating encoding machinery using new auto-generated headers
///
///
namespace vISA
{
class BinaryEncodingCNL : public BinaryEncodingBase
{
public:
    BinaryEncodingCNL(Mem_Manager &m, G4_Kernel& k, std::string fname)
        : BinaryEncodingBase(m, k, fname)
        {}

    virtual ~BinaryEncodingCNL()
    {

    };

    typedef enum { SUCCESS, FAILURE } Status;

    //BinaryEncodingCNL::Status DoAll();
    //void *EmitBinary(uint32_t&);
    void *alloc(size_t size) { return mem.alloc(size); };
    BinaryEncodingCNL::Status DoAllEncoding(G4_INST*);

    virtual void DoAll();

    // Handle CNL+ specific opcode. For common opcode (pre-CNL and CNL+),
    // it invokes base's getEUOpcode().
    G9HDL::EU_OPCODE getEUOpcode(G4_opcode g4opc);

private:

    bool EncodeConditionalBranches(G4_INST *, uint32_t);
    void SetBranchOffsets(G4_INST* inst,
        uint32_t JIP,
        uint32_t UIP = 0);

    ///==------------------------------------------------------------------------
    BinaryEncodingCNL::Status DoAllEncodingWAIT(G4_INST*);
    BinaryEncodingCNL::Status DoAllEncodingJMPI(G4_INST*);
    BinaryEncodingCNL::Status DoAllEncodingCALL(G4_INST*);
    BinaryEncodingCNL::Status DoAllEncodingCF(G4_INST*);
    BinaryEncodingCNL::Status DoAllEncodingSplitSEND(G4_INST*);
        BinaryEncodingCNL::Status EncodeSplitSend(G4_INST*, G9HDL::EU_INSTRUCTION_SENDS&);

    BinaryEncodingCNL::Status DoAllEncodingRegular(G4_INST*);
        void EncodeOneSrcInst(G4_INST*, G9HDL::EU_INSTRUCTION_BASIC_ONE_SRC&);
        void EncodeTwoSrcInst(G4_INST*, G9HDL::EU_INSTRUCTION_BASIC_TWO_SRC&);
        void EncodeThreeSrcInst(G4_INST*, G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC&);
        void EncodeThreeSrcInstAlign1(G4_INST*, G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC&);

    /// 0-th DWORD of instruction, header
    void EncodeInstHeader(G4_INST*, G9HDL::EU_INSTRUCTION_HEADER&);
        /// note: indentation shows that those are subfields of instruction header
        void EncodeOpCode(G4_INST*, G9HDL::EU_INSTRUCTION_HEADER&);
        void EncodeAccessMode(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS_A&);
        void EncodeDepControl(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS_A&);
        void EncodeQtrControl(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS_A&);
        void EncodeThreadControl(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS_A&);
        void EncodeFlagRegPredicate(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS_A&);
        void EncodeExecSize(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS_A&);
        void EncodeCondModifier(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS&);
        void EncodeAccWrCtrl(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS&);
        void EncodeInstModifier(G4_INST*, G9HDL::EU_INSTRUCTION_CONTROLS&);

    /// 1-st DWORD of instruction, header
    void EncodeOperandDst(G4_INST*, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS&);
        void EncodeDstChanEn(G4_INST*,G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS&);
        void EncodeDstRegFile(G4_INST*,G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS&);
        void EncodeDstRegNum(G4_INST *, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS&);
        void EncodeDstArchRegNum(G4_INST *, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS&);
        void EncodeDstIndirectRegNum(G4_INST *, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS&);
        void EncodeDstHorzStride(G4_INST *, G4_DstRegRegion *, G9HDL::EU_INSTRUCTION_OPERAND_CONTROLS&);

    ///==------------------------------------------------------------------------

    //inline void EncodeSrcImmData(G9HDL::EU_INSTRUCTION_SOURCES_IMM32&, G4_Operand *);
    inline void EncodeSrcImm64Data(G9HDL::EU_INSTRUCTION_IMM64_SRC&, G4_Operand *);
    //void insertWaitDst(G4_INST*);

    /// Virtual methods overrides, used by generic (base) methods.
    virtual void SetCompactCtrl (BinInst *mybin, uint32_t value);
    virtual uint32_t GetCompactCtrl(BinInst *mybin);

    ///====----- Inline helpers:

    /// \brief Translates from v-isa reg file enum to HDL reg file type enum
    ///
    static inline G9HDL::REGFILE TranslateVisaToHDLRegFile(RegFile regFile)
    {
        return(G9HDL::REGFILE)regFile;
    }

    /// \brief Translates from v-isa AddrMode enum to HDL ADDRMODE type enum
    ///
    static inline G9HDL::ADDRMODE TranslateVisaToHDLAddrMode(AddrMode addrMode)
    {
        return(G9HDL::ADDRMODE)addrMode;
    }

    /// \brief Packs Arch Reg File and Arch Reg Num into single unsigned short for encoding
    ///
    static inline unsigned short PackArchRegTypeAndArchRegFile(unsigned short RegFile, unsigned short RegNumValue)
    {
        unsigned short EncodedRegNum = RegFile << 4;
        EncodedRegNum = EncodedRegNum | (RegNumValue & 0xF);
        return EncodedRegNum;
    }


public:
    //////////////////////////////////////////////////////////////////////////
    //reviewed
    static inline G9HDL::SRCMOD GetSrcHLDMod(G4_SrcRegRegion *srcRegion)
    {
        uint32_t mod = srcRegion->getModifier();
        G9HDL::SRCMOD srcMod = G9HDL::SRCMOD_NO_MODIFICATION;
        switch (mod) {
        case Mod_Minus_Abs:
            srcMod = G9HDL::SRCMOD_NEGATE_OF_ABS;
            break;
        case Mod_Abs:
            srcMod = G9HDL::SRCMOD_ABS;
            break;
        case Mod_Minus:
            srcMod = G9HDL::SRCMOD_NEGATE;
            break;
        case Mod_Not:
            // same as negate
            srcMod = G9HDL::SRCMOD_NEGATE;
            break;
        case Mod_src_undef:
            // do nothing
            break;
        default:
            MUST_BE_TRUE(false, "unexpected source modifier");
            break;
        }
        return srcMod;
    }
};

//===----------------------------------------------------------------------===//

/// \brief Template class for destination operand encoder
///
/// Template parameter is an auto-header generated struct that
/// performs encoding of destination operand (WORD1) part of instruction.
/// The template and template specialization is used so to isolate the
/// high-level builder logic from underlying encoding mechanism for
/// different kind of instruction types (two-src, three-src etc.)
template<typename T>
class DstOperandEncoder
{
public:
    static void SetCombinedFlagRegSubregNumber(
        T& opndCtl,
        unsigned FlagRegNumValue,
        unsigned FlagRegSubNumValue)
    {
        uint32_t value = 0;
        value = FlagRegNumValue << 1;
        value = value | FlagRegSubNumValue;

        opndCtl.SetFlagRegisterNumberSubregisterNumber(value);
    }
};

template<>
class DstOperandEncoder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC>
{
public:
    static void SetCombinedFlagRegSubregNumber(
        G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC& opndCtl,
        unsigned FlagRegNumValue,
        unsigned FlagRegSubNumValue)
    {
        opndCtl.SetFlagRegisterNumberSubregisterNumber(FlagRegSubNumValue);
        opndCtl.SetFlagRegisterNumber(FlagRegNumValue);
    }
};

template<>
class DstOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC>
{
public:
    static void SetCombinedFlagRegSubregNumber(
        G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC& opndCtl,
        unsigned FlagRegNumValue,
        unsigned FlagRegSubNumValue)
    {
        opndCtl.SetFlagSubregisterNumber(FlagRegSubNumValue);
        opndCtl.SetFlagRegisterNumber(FlagRegNumValue);
    }
};

/// \brief Template-based builder for destination instruction fields.
///
/// Basically those fields whose encoding methods in auto-generated
/// header differ by name/parameters based on the instruction type will need
/// to be encoded through this template.
template<typename T>
class DstBuilder
{
public:

    /// \brief Template based field encoder for mask control (a.k.a. write-enable)
    ///
    /// This one will get template specialized, and is will call suitable field
    /// encoder method for either OPERAND_CONTROLS, three-src, send or sends type
    /// encoding
    static void EncodeMaskCtrl(G4_INST* inst, T& opnds)
    {
        if (inst->isWriteEnableInst())
            opnds.SetMaskctrl(G9HDL::MASKCTRL_WRITE_ALL_CHANNELS);

        if (inst->opcode()==G4_jmpi)
            opnds.SetMaskctrl(G9HDL::MASKCTRL_WRITE_ALL_CHANNELS);
    }

    /// \brief Template based field encoder for operant destination type
    ///        Template parameter is the type of encoding mask.
    static void EncodeOperandDstType(G4_INST* inst, T& opnds)
    {
        G4_DstRegRegion* dst = inst->getDst();
        G4_Type regType = dst->asDstRegRegion()->getType();

        switch (regType)
        {    //BXML bug Line 851: bitrange 5-8, should be: 37-40
        case Type_UD:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_UD);
            break;
        case Type_D:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_D);
            break;
        case Type_UW:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_UW);
            break;
        case Type_W:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_W);
            break;
        case Type_UB:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_UB);
            break;
        case Type_B:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_B);
            break;
        case Type_DF:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_DF);
            break;
        case Type_F:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_F);
            break;
        case Type_UQ:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_UQ);
            break;
        case Type_Q:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_Q);
            break;
        case Type_HF:
            opnds.SetDestinationDataType(G11HDL::DSTTYPE_HF);
            break;
        default:
            MUST_BE_TRUE(false, "Encoding error: destination type unknown");
            break;
        }
    }

    /// \brief Template based field encoder for combined destination FlagRegNum and FlagSubRegNum
    ///
    static void EncodeFlagReg(G4_INST* inst, T& opnds)
    {
        bool flagRegNumValid = false;
        unsigned FlagRegNumValue = 0;
        unsigned FlagRegSubNumValue = 0;

        G4_Predicate *pred = inst->getPredicate();
        if (pred)        {
            FlagRegNumValue =
                pred->getBase()->ExRegNum(flagRegNumValid);
            FlagRegSubNumValue = pred->getBase()->asRegVar()->getPhyRegOff();
        }

        G4_CondMod *cModifier = inst->getCondMod();
        if (cModifier)    { // cond modifier
            G4_VarBase* flagReg = cModifier->getBase();
            if (flagReg != NULL)
            {
                FlagRegNumValue = flagReg->ExRegNum(flagRegNumValid);
                FlagRegSubNumValue = flagReg->asRegVar()->getPhyRegOff();
            }
            else
            {
                FlagRegNumValue = 0;
                FlagRegSubNumValue = 0;
            }
        }

        if (pred || cModifier) {

            DstOperandEncoder<T>::SetCombinedFlagRegSubregNumber(opnds, FlagRegNumValue, FlagRegSubNumValue);
        }
    }

    /// \brief Template based field encoder for combined Dst.AddrMode
    ///
    static void EncodeDstAddrMode(G4_INST* inst, T& opnds)
    {
        G4_DstRegRegion* dst = inst->getDst();
        switch (EncodingHelper::GetDstAddrMode(dst))
        {
        case ADDR_MODE_IMMED:
            //same field for align16
            opnds.SetDestinationAddressingMode(G9HDL::ADDRMODE_DIRECT);
            break;
        case ADDR_MODE_INDIR:
            //same field for align16
            opnds.SetDestinationAddressingMode(G9HDL::ADDRMODE_INDIRECT);
            break;
        default:
            MUST_BE_TRUE(false, "Encoding error: addressing mode type unknown");
            break;
        }
    }

};

//===----------------------------------------------------------------------===//



/// \brief Template class for source operand encoder
///
/// There are two template parameters: auto-generated struct type
/// and source operand number that select which source (src0,src1,src2) is
/// being encoded.
///
/// Template parameter is an auto-header generated struct that
/// performs encoding of selected source operand part of instruction.
/// The template and template specialization is used so to isolate the
/// high-level builder logic from underlying encoding mechanism for
/// different kind of instruction types (one-src, two-src, three-src etc.)
/// and different source numbers.
template<typename T, int SrcNum>
class SrcOperandEncoder
{
public:

    static void SetSrcChanSel(T *EuInstructionSources, uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSrcChanSel template specialization not implemented.");
    }

    static void SetSrcChanSel_10(T *EuInstructionSources, uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSrcChanSel_10 template specialization not implemented.");
    }
    static void SetSrcChanSel_32(T *EuInstructionSources, uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSrcChanSel_32 template specialization not implemented.");
    }

    static void SetSourceWidth(T *EuInstructionSources, G9HDL::WIDTH width)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceWidth template specialization not implemented.");
    }

    static void SetSourceHorizontalStride(T *EuInstructionSources, G9HDL::HORZSTRIDE stride)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceHorizontalStride template specialization not implemented.");
    }

    static void SetSourceVerticalStride(T *EuInstructionSources, G9HDL::VERTSTRIDE vertStride)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceVerticalStride template specialization not implemented.");
    }

    static void SetSourceRegisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceRegisterNumber template specialization not implemented.");
    }

    static void SetSourceSpecialAcc(T *EuInstructionSources, uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceSpecialAcc template specialization not implemented.");
    }

    static void SetSourceSubRegisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceSubRegisterNumber template specialization not implemented.");
    }

    static void SetSourceSubregisterNumber44(T *EuInstructionSources,  uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceSubregisterNumber44 template specialization not implemented.");
    }

    static void SetAddressSubregisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetAddressSubregisterNumber template specialization not implemented.");
    }

    static void SetSourceAddressImmediate84(T *EuInstructionSources,  uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceAddressImmediate84 template specialization not implemented.");
    }

    static void SetSourceAddressImmediate90(T *EuInstructionSources,  int32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceAddressImmediate80 template specialization not implemented.");
    }

    static void SetSourceImmediateData(T *EuInstructionSources,  uint32_t value)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceImmediateData template specialization not implemented.");
    }

    static void SetSourceAddressingMode(T *EuInstructionSources,  G9HDL::ADDRMODE addrMode)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceAddressingMode template specialization not implemented.");
    }

    static void SetSourceModifier(T *EuInstructionSources, G9HDL::SRCMOD srcMod)
    {
        MUST_BE_TRUE(false, "SrcOperandEncoder::SetSourceModifier template specialization not implemented.");
    }
};

/// \brief Template specialization for source operand encoder for T, src0
///
template<typename T>
class SrcOperandEncoder<T,0>
{
public:

    static void SetSrcChanSel(T *EuInstructionSources, uint32_t value)
    {
        //first 4 bits
        SetSrcChanSel_10(EuInstructionSources, value & 0xf);
        //second 4 bits
        SetSrcChanSel_32(EuInstructionSources, (value >> 4) & 0xf);
    }

    static void SetSrcChanSel_10(T *EuInstructionSources, uint32_t value)
    {
        EuInstructionSources->SetSource0_SourceChannelSelect30(value);
    }
    static void SetSrcChanSel_32(T *EuInstructionSources, uint32_t value)
    {
        EuInstructionSources->SetSource0_SourceChannelSelect74(value);
    }
    static void SetSourceWidth(T *EuInstructionSources, G9HDL::WIDTH width)
    {
        EuInstructionSources->SetSource0_SourceWidth(width);
    }
    static void SetSourceHorizontalStride(T *EuInstructionSources, G9HDL::HORZSTRIDE stride)
    {
        EuInstructionSources->SetSource0_SourceHorizontalStride (stride);
    }
    static void SetSourceVerticalStride(T *EuInstructionSources, G9HDL::VERTSTRIDE vertStride)
    {
        EuInstructionSources->SetSource0_SourceVerticalStride (vertStride);
    }
    static void SetSourceRegisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource0_SourceRegisterNumber (value);
    }

    static void SetSourceSpecialAcc(T *EuInstructionSources, uint32_t value)
    {
        EuInstructionSources->SetSource0_SourceSubRegisterNumber(value & 0xF);
    }

    static void SetSourceSubRegisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource0_SourceSubRegisterNumber (value);
    }

    static void SetSourceSubregisterNumber44(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource0_SourceSubregisterNumber44 (value);
    }

    static void SetAddressSubregisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource0_AddressSubregisterNumber_0 (value);
    }

    static void SetSourceAddressImmediate84(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource0_SourceAddressImmediate84 (value);
    }

    static void SetSourceAddressImmediate90(T *EuInstructionSources,  int32_t value)
    {
        EuInstructionSources->SetSource0_SourceAddressImmediate80 (value);

        value = value >> 9;
        EuInstructionSources->SetSource0_SourceAddressImmediate9(value);
    }

    static void SetSourceImmediateData(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource0Immediate(value);
    }

    static void SetSourceAddressingMode(T *EuInstructionSources, G9HDL::ADDRMODE addrMode)
    {
        EuInstructionSources->SetSource0_SourceAddressingMode(addrMode);
    }

    static void SetSourceModifier(T *EuInstructionSources, G9HDL::SRCMOD srcMod)
    {
        EuInstructionSources->SetSource0_SourceModifier(srcMod);
    }
};

/// \brief Template specialization for source operand encoder for 3-src instruction
///        type in align16 mode, SRC 0
///
template<>
class SrcOperandEncoder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC,0>
{
public:

    static void SetSrcChanSel(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, uint32_t value)
    {
        threeSrc->SetSource0_SourceSwizzle(value);
    }

    static void SetSourceModifier(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, G9HDL::SRCMOD srcMod)
    {
        threeSrc->SetSource0_SourceModifier(srcMod);
    }

    static void SrcReplicateControl(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, G9HDL::REPCTRL repCtrl)
    {
        threeSrc->SetSource0_SourceReplicateControl(repCtrl);
    }

    static void SetSourceRegisterNumber(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource0_SourceRegisterNumber(value);
    }

    static void SetSourceSubregisterNumber42(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource0_SourceSubregisterNumber42(value);
    }

    static void SetSourceSubregisterNumber1(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource0_SourceSubregisterNumber1(value);
    }


};

/// \brief Template specialization for source operand encoder for 3-src instruction
///        type in align16 mode, SRC 1
///
template<>
class SrcOperandEncoder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC,1>
{
public:

    static void SetSrcChanSel(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, uint32_t value)
    {
        threeSrc->SetSource1_SourceSwizzle(value);
    }

    static void SetSourceModifier(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, G9HDL::SRCMOD srcMod)
    {
        threeSrc->SetSource1_SourceModifier(srcMod);
    }

    static void SrcReplicateControl(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, G9HDL::REPCTRL repCtrl)
    {
        threeSrc->SetSource1_SourceReplicateControl(repCtrl);
    }

    static void SetSourceRegisterNumber(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource1_SourceRegisterNumber(value);
    }

    static void SetSourceSubregisterNumber42(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource1_SourceSubregisterNumber42(value);
    }

    static void SetSourceSubregisterNumber1(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource1_SourceSubregisterNumber1(value);
    }


};

/// \brief Template specialization for source operand encoder for 3-src instruction
///        type in align16 mode, SRC 2
///
template<>
class SrcOperandEncoder<G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC,2>
{
public:

    static void SetSrcChanSel(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, uint32_t value)
    {
        threeSrc->SetSource2_SourceSwizzle(value);
    }

    static void SetSourceModifier(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, G9HDL::SRCMOD srcMod)
    {
        threeSrc->SetSource2_SourceModifier(srcMod);
    }

    static void SrcReplicateControl(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc, G9HDL::REPCTRL repCtrl)
    {
        threeSrc->SetSource2_SourceReplicateControl(repCtrl);
    }

    static void SetSourceRegisterNumber(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource2_SourceRegisterNumber(value);
    }

    static void SetSourceSubregisterNumber42(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource2_SourceSubregisterNumber42(value);
    }

    static void SetSourceSubregisterNumber1(G9HDL::EU_INSTRUCTION_BASIC_THREE_SRC *threeSrc,  uint32_t value)
    {
        threeSrc->SetSource2_SourceSubregisterNumber1(value);
    }


};

/// \brief Template specialization for source operand encoder for T, src1
///
template<typename T>
class SrcOperandEncoder<T,1>
{
public:

    static void SetSrcChanSel(T *EuInstructionSources, uint32_t value)
    {
        //first 4 bits
        SetSrcChanSel_10(EuInstructionSources, value & 0xf);
        //second 4 bits
        SetSrcChanSel_32(EuInstructionSources, (value >> 4) & 0xf);
    }

    static void SetSrcChanSel_10(T *EuInstructionSources, uint32_t value)
    {
        EuInstructionSources->SetSource1_SourceChannelSelect30(value);
    }
    static void SetSrcChanSel_32(T *EuInstructionSources, uint32_t value)
    {
        EuInstructionSources->SetSource1_SourceChannelSelect74(value);
    }
    static void SetSourceWidth(T *EuInstructionSources, G9HDL::WIDTH width)
    {
        EuInstructionSources->SetSource1_SourceWidth(width);
    }
    static void SetSourceHorizontalStride(T *EuInstructionSources, G9HDL::HORZSTRIDE stride)
    {
        EuInstructionSources->SetSource1_SourceHorizontalStride(stride);
    }
    static void SetSourceVerticalStride(T *EuInstructionSources, G9HDL::VERTSTRIDE vertStride)
    {
        EuInstructionSources->SetSource1_SourceVerticalStride (vertStride);
    }

    static void SetSourceRegisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource1_SourceRegisterNumber (value);
    }

    static void SetSourceSpecialAcc(T *EuInstructionSources, uint32_t value)
    {
        EuInstructionSources->SetSource1_SourceSubRegisterNumber(value & 0xF);
    }

    static void SetSourceSubRegisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource1_SourceSubRegisterNumber (value);
    }

    static void SetSourceSubregisterNumber44(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource1_SourceSubregisterNumber44 (value);
    }

    static void SetAddressSubregisterNumber(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource1_AddressSubregisterNumber (value);
    }

    static void SetSourceAddressImmediate84(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource1_SourceAddressImmediate84 (value);
    }

    static void SetSourceAddressImmediate90(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource1_SourceAddressImmediate80 (value);
        value = value >> 9;
        EuInstructionSources->SetSource1_SourceAddressImmediate9(value);
    }

    static void SetSourceImmediateData(T *EuInstructionSources,  uint32_t value)
    {
        EuInstructionSources->SetSource1Immediate(value);
    }

    static void SetSourceAddressingMode(T *EuInstructionSources, G9HDL::ADDRMODE addrMode)
    {
        EuInstructionSources->SetSource1_SourceAddressingMode(addrMode);
    }

    static void SetSourceModifier(T *EuInstructionSources, G9HDL::SRCMOD srcMod)
    {
        EuInstructionSources->SetSource1_SourceModifier(srcMod);
    }

};

/// \brief Template specialization for source operand encoder for 3-src instruction
///        type in align1 mode, SRC 0
///
template<>
class SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 0>
{
public:

    static void SetSourceHorizontalStride(G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC *EuInstructionSources, G9HDL::HORZSTRIDE stride)
    {
        EuInstructionSources->SetSource0HorizontalStride(stride);
    }
    static void SetSourceVerticalStride(G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC *EuInstructionSources, G9HDL::TERNARYALIGN1VERTSTRIDE vertStride)
    {
        EuInstructionSources->SetSource0VerticalStride(vertStride);
    }
};

/// \brief Template specialization for source operand encoder for 3-src instruction
///        type in align1 mode, SRC 1
///
template<>
class SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 1>
{
public:

    static void SetSourceHorizontalStride(G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC *EuInstructionSources, G9HDL::HORZSTRIDE stride)
    {
        EuInstructionSources->SetSource1HorizontalStride(stride);
    }
    static void SetSourceVerticalStride(G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC *EuInstructionSources, G9HDL::TERNARYALIGN1VERTSTRIDE vertStride)
    {
        EuInstructionSources->SetSource1VerticalStride(vertStride);
    }

};

/// \brief Template specialization for source operand encoder for 3-src instruction
///        type in align1 mode, SRC 2
///
template<>
class SrcOperandEncoder<G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC, 2>
{
public:

    static void SetSourceHorizontalStride(G9HDL::EU_INSTRUCTION_ALIGN1_THREE_SRC *EuInstructionSources, G9HDL::HORZSTRIDE stride)
    {
        EuInstructionSources->SetSource2HorizontalStride(stride);
    }
};


/// \brief Template-based builder for source instruction fields.
///
/// Builder is parametrized by two template parameters, one of which
/// is the type of the auto-generated header class, and other is source
/// number that is to be encoded
template<typename T, int SrcNum>
class SrcBuilder
{
public:

    /// \brief Template based field encoder for Src[SrcNum].AddrMode
    ///
    static void EncodeSrcAddrMode(T *EuInstructionSources,
                                  G4_INST* inst,
                                  G4_Operand *src0)
    {
        if (src0->asSrcRegRegion()->getRegAccess() == Direct)
        {
            SrcOperandEncoder<T,SrcNum>::
                SetSourceAddressingMode(EuInstructionSources, G9HDL::ADDRMODE_DIRECT);
        } else {
            SrcOperandEncoder<T,SrcNum>::
                SetSourceAddressingMode(EuInstructionSources, G9HDL::ADDRMODE_INDIRECT);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for RegNum field for 3src instruction types
    ///
    static void EncodeSrcRegNum3Src(
        G4_INST* inst,
        G4_Operand *src0,
        T& sourcesReg)
    {
        if (EncodingHelper::GetSrcRegFile(src0) != REG_FILE_A &&
             EncodingHelper::GetSrcAddrMode(src0) == ADDR_MODE_IMMED)
        {
            uint32_t byteAddress = src0->getLinearizedStart();

            //repCtrl is only set for 3src instructions
            //if (inst->isAligned1Inst() || repControl)
            //TODO: how do we understand this commented line (from original EncodeSrc0RegNum) ?
            // in 3src, bits 83 - 73 encode (73-75):3 subreg, and (76-83):8 bits regnum, dword aligned
            if (inst->isAligned1Inst())
            {
                MUST_BE_TRUE(false, "align1 not allowed for 3src instructions");
            } else { //align 16
                //register number: 256 bit (32 byte) aligned part of an address
                //sub-register number: first/second 16 byte part of 32 byte address. Encoded with 1 bit.
                // 9876543210
                // regn|xxxy0
                //dword aligned

                SrcOperandEncoder<T, SrcNum>::SetSourceRegisterNumber (&sourcesReg, byteAddress >> 5);
                //it will be shifted to right within setter method
                SrcOperandEncoder<T, SrcNum>::SetSourceSubregisterNumber42 (&sourcesReg, byteAddress & 0x1f);
                SrcOperandEncoder<T, SrcNum>::SetSourceSubregisterNumber1 (&sourcesReg, (byteAddress >> 1) & 0x1);
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for replicate control field
    ///        of 3src instruction types
    ///
    static void Encode3SrcReplicateControl(
        T *myBin,
        G4_SrcRegRegion *srcRegion)
    {
        const char *swizzle = srcRegion->getSwizzle();
        if (swizzle[0] == 'r')
            SrcOperandEncoder<T, SrcNum>::SrcReplicateControl(myBin, G9HDL::REPCTRL_REPLICATE_ACROSS_ALL_CHANNELS);
        else
            SrcOperandEncoder<T, SrcNum>::SrcReplicateControl(myBin, G9HDL::REPCTRL_NO_REPLICATION);
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for ChanSel
    ///
    static void EncodeSrcChanSelect(
        T *myBin,
        G4_INST* inst,
        G4_Operand *src0,
        G4_SrcRegRegion *srcRegion)
    {
        bool ChanSelectValid = false;

        // encode acc2~acc9 if it is valid
        if (src0->isAccRegValid() && inst->getPlatform() < GENX_ICLLP)
        {
            if (inst->opcode() == G4_madm ||
                (inst->isMath() && (inst->asMathInst()->getMathCtrl() == MATH_INVM || inst->asMathInst()->getMathCtrl() == MATH_RSQRTM)))
            {
                uint32_t value = src0->getAccRegSel();
                SrcOperandEncoder<T, SrcNum>::SetSrcChanSel(myBin, value);
                return;
            }
            ASSERT_USER(false, "acc2~acc7 were set on wrong instruction");
        }

        const char *swizzle = srcRegion->getSwizzle();
        if (swizzle[0] != '\0' && swizzle[0] != 'r') {
            ChanSelectValid = true;
            ChanSel ch0 = EncodingHelper::GetSrcChannelSelectValue(srcRegion, 0);
            ChanSel ch1 = EncodingHelper::GetSrcChannelSelectValue(srcRegion, 1);
            ChanSel ch2 = EncodingHelper::GetSrcChannelSelectValue(srcRegion, 2);
            ChanSel ch3 = EncodingHelper::GetSrcChannelSelectValue(srcRegion, 3);
            uint32_t value = 0;

            if (ch0 != CHAN_SEL_UNDEF)
                value = ch0;
            if (ch1 != CHAN_SEL_UNDEF)
                value = value | (ch1 << 2);

            uint32_t value2 = 0;

            //value = 0;
            if (ch2 != CHAN_SEL_UNDEF)
                value2 = ch2;
            if (ch3 != CHAN_SEL_UNDEF)
                value2 = value2 | (ch3 << 2);

            SrcOperandEncoder<T, SrcNum>::SetSrcChanSel(myBin, value | (value2 << 4));
        }

        if (!ChanSelectValid       &
            inst->isAligned16Inst())
        {
            uint32_t value = 0;
            value = CHAN_SEL_X;
            value = value | (CHAN_SEL_Y << 2);

            uint32_t value2 = 0;
            //value = 0;
            value2 = CHAN_SEL_Z;
            value2 = value2 | (CHAN_SEL_W << 2);

            SrcOperandEncoder<T, SrcNum>::SetSrcChanSel(myBin, value | (value2 << 4));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for SrcMod
    ///
    static void EncodeSrcModifier(
        G4_INST* inst,
        G4_Operand *src0,
        T& sourcesReg)
    {
        G4_SrcRegRegion *srcRegion = src0->asSrcRegRegion();
        {
            SrcOperandEncoder<T, SrcNum>::
                SetSourceModifier(&sourcesReg, BinaryEncodingCNL::GetSrcHLDMod(srcRegion));
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for Src[SrcNum].Width
    ///
    static bool EncodeSrcWidth(
        G4_INST *inst, T *mybin, const RegionDesc *rd, G4_Operand *src)
    {
        bool WidthValid = false;
        if (inst->isAligned16Inst()) return false;

        if (rd)
        {
            if (rd->width != UNDEFINED_SHORT)
            {
                WidthValid = true;
            }

            switch (rd->width)
            {
            case 1:
                SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_1_ELEMENTS);
                break;
            case 2:
                SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_2_ELEMENTS);
                break;
            case 4:
                SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_4_ELEMENTS);
                break;
            case 8:
                SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_8_ELEMENTS);
                break;
            case 16:
                SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_16_ELEMENTS);
                break;
            case UNDEFINED_SHORT: break;
            default: MUST_BE_TRUE(false, "wrong width for src0!"); break;
            }

        }

        // apply default width
        if (!WidthValid)
        {
            if (EncodingHelper::isSrcSubRegNumValid(src))
            {
                SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_1_ELEMENTS);
            }
            else
            {
                switch (GetEncodeExecSize(inst))
                {
                case ES_1_CHANNEL:
                    SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_1_ELEMENTS);
                    break;
                case ES_2_CHANNELS:
                    SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_2_ELEMENTS);
                    break;
                case ES_4_CHANNELS:
                    SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_4_ELEMENTS);
                    break;
                case ES_8_CHANNELS:
                case ES_16_CHANNELS:
                    SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_8_ELEMENTS);
                    break;
                case ES_32_CHANNELS:
                    SrcOperandEncoder<T, SrcNum>::SetSourceWidth(mybin, G9HDL::WIDTH_16_ELEMENTS);
                    break;
                }
            }
        }

        return WidthValid;
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for Src[SrcNum].HorzStride
    ///
    static bool EncodeSrcHorzStride(
        G4_INST *inst, T *mybin, const RegionDesc *rd, G4_Operand *src0)
    {
        // For Align16 instruction (SIMD4), treat <HorzStride> as <VertStride>
        // For Align16 source operand disable HorzStride
        bool HorzStrideValid = false;  // undef
        if (inst->isAligned16Inst()) return false;

        if (rd)  {
            if (rd->horzStride != UNDEFINED_SHORT)
            {
                HorzStrideValid = true;
            }
            switch (rd->horzStride)
            {
            case 0:
                SrcOperandEncoder<T, SrcNum>::SetSourceHorizontalStride(mybin, G9HDL::HORZSTRIDE_0_ELEMENTS);
                break;
            case 1:
                SrcOperandEncoder<T, SrcNum>::SetSourceHorizontalStride(mybin, G9HDL::HORZSTRIDE_1_ELEMENTS);
                break;
            case 2:
                SrcOperandEncoder<T, SrcNum>::SetSourceHorizontalStride(mybin, G9HDL::HORZSTRIDE_2_ELEMENTS);
                break;
            case 4:
                SrcOperandEncoder<T, SrcNum>::SetSourceHorizontalStride(mybin, G9HDL::HORZSTRIDE_4_ELEMENTS);
                break;
            case UNDEFINED_SHORT: break;
            default: MUST_BE_TRUE(false, "wrong horizontal stride for src0!"); break;
            }
        }
        // apply default horizontal stride
        if (!HorzStrideValid)
        {
            if (EncodingHelper::isSrcSubRegNumValid(src0))
                SrcOperandEncoder<T, SrcNum>::SetSourceHorizontalStride(mybin, G9HDL::HORZSTRIDE_0_ELEMENTS);
            else {
                switch (GetEncodeExecSize(inst))
                {
                case ES_1_CHANNEL:
                    SrcOperandEncoder<T, SrcNum>::SetSourceHorizontalStride(mybin, G9HDL::HORZSTRIDE_0_ELEMENTS);
                    break;
                case ES_2_CHANNELS:
                case ES_4_CHANNELS:
                case ES_8_CHANNELS:
                case ES_16_CHANNELS:
                case ES_32_CHANNELS:
                    SrcOperandEncoder<T, SrcNum>::SetSourceHorizontalStride(mybin, G9HDL::HORZSTRIDE_1_ELEMENTS);
                    break;
                }
            }
        } // end of valid horz stride
        return HorzStrideValid;
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for Src[SrcNum].VertStride
    ///
    static void EncodeSrcVertStride(
        G4_INST *inst,
        T *mybin,
        const RegionDesc *rd,
        G4_Operand *src0,
        const bool WidthValid,
        const bool HorzStrideValid)
    {
        bool VertStrideValid = false; // undef
        unsigned short VertStrideValue = UNDEFINED_SHORT, HorzStrideValue = 0;

        if (rd)
        {
            VertStrideValue = rd->vertStride;
            HorzStrideValue = rd->horzStride;
            if (VertStrideValue != UNDEFINED_SHORT)
            {
                VertStrideValid = true;
            }

            switch (VertStrideValue)
            {
            case 0:
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_0_ELEMENTS);
                break;
            case 1:
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_1_ELEMENT);
                break;
            case 2:
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_2_ELEMENTS);
                break;
            case 4:
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_4_ELEMENTS);
                break;
            case 8:
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_8_ELEMENTS);
                break;
            case 16:
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_16_ELEMENTS);
                break;
            case 32:
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_32_ELEMENTS);
                break;
            case UNDEFINED_SHORT: break;
            default: MUST_BE_TRUE(false, "wrong vertical stride for src0!"); break;
            }

        }

        //apply default vertical stride below
        if (!WidthValid             &&
            !HorzStrideValid        &&
            !VertStrideValid        &&
            src0)
        {
            VertStrideValid = true;
            if (EncodingHelper::isSrcSubRegNumValid(src0))
            {
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_0_ELEMENTS);
            }
            else
            {
                if (inst->isAligned1Inst())
                {
                    switch (GetEncodeExecSize(inst))
                    {
                    case ES_1_CHANNEL:
                        SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_0_ELEMENTS);
                        break;
                    case ES_2_CHANNELS:
                        SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_2_ELEMENTS);
                        break;
                    case ES_4_CHANNELS:
                        SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_4_ELEMENTS);
                        break;
                    case ES_8_CHANNELS:
                    case ES_16_CHANNELS:
                        SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_8_ELEMENTS);
                        break;
                    case ES_32_CHANNELS:
                        SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_16_ELEMENTS);
                        break;
                    }
                }
                else
                {
                    SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_4_ELEMENTS);
                }
            }
        }

        //Do some post processing, if none of the previous cases was true.
        if (VertStrideValid) {}
        else if (inst->isAligned16Inst())
        {
            //FIXME: should this be ever valid?
            //we cannot be setting horz stride in align16 instructions!!!
            if (HorzStrideValid  && HorzStrideValue == 0)
            {
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_0_ELEMENTS);
            }
            else if (HorzStrideValid  && HorzStrideValue == 4)
            {
                SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_4_ELEMENTS);
            }
        }
        else if (EncodingHelper::GetSrcAddrMode(src0) == ADDR_MODE_INDIR) { //indirect
            SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(mybin, G9HDL::VERTSTRIDE_VXH_OR_VX1_MODE);
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for source immediate based addressing
    ///        RegNum. It encodes RegNum for non-ARF based register files.
    static void EncodeSrcRegNum(
        G4_INST* inst,
        G4_Operand *src0,
        T& sourcesReg)
    {
        if (EncodingHelper::GetSrcRegFile(src0) != REG_FILE_A &&
             EncodingHelper::GetSrcAddrMode(src0) == ADDR_MODE_IMMED)
        {
            //bool repControl = EncodingHelper::GetRepControl(src0);
            uint32_t byteAddress = src0->getLinearizedStart();

            //repCtrl is only set for 3src instructions
            //if (inst->isAligned1Inst() || repControl)
            //TODO: how do we understand this commented line (from original EncodeSrc0RegNum) ?
            // in 3src, bits 83 - 73 encode (73-75):3 subreg, and (76-83):8 bits regnum, dword aligned
            if (inst->isAligned1Inst())
            {

                //register number: 256 bit (32 byte) aligned part of an address
                //sub-register number: address (5 bits encoding) within a 32 byte GRF
                // 9876543210
                // regn|subre

                SrcOperandEncoder<T, SrcNum>::SetSourceRegisterNumber (&sourcesReg, byteAddress >> 5);
                if (inst->getPlatform() >= GENX_ICLLP && src0->isAccRegValid())
                {
                    MUST_BE_TRUE((byteAddress & 0x1F) == 0, "subreg must be 0 for source with special accumulator");
                    SrcOperandEncoder<T, SrcNum>::SetSourceSpecialAcc(&sourcesReg, src0->getAccRegSel());
                }
                else
                {
                    SrcOperandEncoder<T, SrcNum>::SetSourceSubRegisterNumber (&sourcesReg, byteAddress & 0x1F);
                }
            } else { //align 16
                //register number: 256 bit (32 byte) aligned part of an address
                //sub-register number: first/second 16 byte part of 32 byte address. Encoded with 1 bit.
                // 9876543210
                // regn|x0000

                SrcOperandEncoder<T, SrcNum>::SetSourceRegisterNumber (&sourcesReg, byteAddress >> 5);
                SrcOperandEncoder<T, SrcNum>::SetSourceSubregisterNumber44 (&sourcesReg, (byteAddress >> 4) & 0x1);
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for source architecture RegNum and SubRegNum encoding
    ///
    /// essentially, this encoding is split in three parts:
    /// setting reg num : arch reg file + arch reg number
    /// setting sub-reg-num
    /// here, we fuse two original methods into one: EncodeDstArchRegNum and EncodeDstRegFile for ARF
    static void EncodeSrcArchRegNum(
        G4_INST* inst,
        G4_SrcRegRegion *src,
        T& sourcesReg)
    {
        if (EncodingHelper::GetSrcRegFile(src) == REG_FILE_A  &&
             EncodingHelper::GetSrcAddrMode(src) == ADDR_MODE_IMMED)
        {
            if (EncodingHelper::GetSrcArchRegType(src) != ARCH_REG_FILE_NULL)
            {
                //EncodeSrc0RegFile, SetSrc0ArchRegFile- corresponding functionality
                bool valid;

                unsigned short RegFile = (unsigned short)EncodingHelper::GetSrcArchRegType(src); //4 bits
                unsigned short RegNumValue = src->ExRegNum(valid);

                // 7654|3210
                // RegF|RegNumVal
                unsigned short EncodedRegNum = RegFile << 4;
                EncodedRegNum = EncodedRegNum | (RegNumValue & 0xF);

                //encode 'packed' arch reg file + reg number. Both for align16 and align1, immediate mode.
                SrcOperandEncoder<T, SrcNum>::SetSourceRegisterNumber (&sourcesReg, EncodedRegNum);

                bool subValid;
                unsigned short RegSubNumValue = src->ExSubRegNum(subValid);
                unsigned short ElementSizeValue = EncodingHelper::GetElementSizeValue(src);
                uint32_t regOffset = RegSubNumValue * ElementSizeValue;

                if (inst->isAligned1Inst())
                {
                    //sub-register number: 32 byte address (5 bits encoding) within a GRF
                    SrcOperandEncoder<T, SrcNum>::SetSourceSubRegisterNumber (&sourcesReg,regOffset);
                } else { //align 16
                    //sub-register number: first/second 16 byte part of 32 byte address. Encoded with 1 bit.
                    // 9876543210
                    // regn|x0000
                    SrcOperandEncoder<T, SrcNum>::SetSourceSubregisterNumber44 (&sourcesReg, (regOffset >> 4) & 0x1);
                }
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for source indirect RegNum and SubRegNum encoding
    ///
    /// Essentially it sets address subregister number alltogether with immediate offset
    static void EncodeSrcIndirectRegNum(
        G4_INST* inst,
        G4_SrcRegRegion *src,
        T& sourcesReg)
    {
        if (EncodingHelper::GetSrcRegFile(src)==REG_FILE_R)
        {
            if (EncodingHelper::GetSrcAddrMode(src) == ADDR_MODE_INDIR)
            { // Indirect
                bool subValid;
                unsigned short IndAddrRegSubNumValue = 0;
                short IndAddrImmedValue = 0;

                IndAddrRegSubNumValue = src->ExIndSubRegNum(subValid);
                IndAddrImmedValue = src->ExIndImmVal();

                //SetSrc0IdxRegNum(mybin, IndAddrRegSubNumValue);
                //the same is for align16
                SrcOperandEncoder<T, SrcNum>::SetAddressSubregisterNumber(&sourcesReg, IndAddrRegSubNumValue);

                /* Set the indirect address immediate value. */
                if (inst->isAligned1Inst())
                {
                    //bits [0-8]
                    SrcOperandEncoder<T, SrcNum>::SetSourceAddressImmediate90(&sourcesReg, IndAddrImmedValue);
                }  else  { //here we are setting align16
                    //bits [4-8]
                    SrcOperandEncoder<T, SrcNum>::SetSourceAddressImmediate84(&sourcesReg, IndAddrImmedValue / BYTES_PER_OWORD);
                }
            }
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based aggregate encoder for all source related
    ///        fields (width,stride, regnum, modifier, chan-sel) for both align1 and
    ///        align16 modes.
    static void EncodeEuInstructionSourcesReg(
        G4_INST* inst,
        G4_Operand *src,
        T& sourcesReg)
    {
        if (src->isSrcRegRegion())
        {
            G4_SrcRegRegion *srcRegion = src->asSrcRegRegion();
            const RegionDesc *rd = srcRegion->getRegion();

            SrcBuilder<T, SrcNum>::EncodeSrcAddrMode(&sourcesReg, inst, src);
            if (inst->isAligned16Inst())
            {
                SrcBuilder<T, SrcNum>::EncodeSrcChanSelect(&sourcesReg, inst, src, srcRegion);
            }
            SrcBuilder<T, SrcNum>::EncodeSrcModifier(inst, src, sourcesReg);
            if (!inst->isSend())
            {
                bool WidthValid =
                    SrcBuilder<T, SrcNum>::EncodeSrcWidth(inst, &sourcesReg, rd, src);
                bool HorzStrideValid = SrcBuilder<T, SrcNum>::EncodeSrcHorzStride(inst, &sourcesReg, rd, src);
                SrcBuilder<T, SrcNum>::EncodeSrcVertStride(inst, &sourcesReg, rd, src, WidthValid, HorzStrideValid);
            }
            SrcBuilder<T, SrcNum>::EncodeSrcRegNum(inst, src, sourcesReg);
            SrcBuilder<T, SrcNum>::EncodeSrcArchRegNum(inst, src->asSrcRegRegion(), sourcesReg);
            SrcBuilder<T, SrcNum>::EncodeSrcIndirectRegNum(inst, src->asSrcRegRegion(), sourcesReg);
        } //if
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based sets NULL Register for source.
    static void EncodeEuInstructionNullSourcesReg(
        G4_INST* inst,
        G4_Operand *src,
        T& sourcesReg)
    {
        if (src->isSrcRegRegion())
        {
            SrcOperandEncoder<T, SrcNum>::SetSourceAddressingMode(&sourcesReg, G9HDL::ADDRMODE_DIRECT);

            SrcOperandEncoder<T, SrcNum>::SetSourceWidth(&sourcesReg, G9HDL::WIDTH_1_ELEMENTS);
            SrcOperandEncoder<T, SrcNum>::SetSourceHorizontalStride(&sourcesReg, G9HDL::HORZSTRIDE_0_ELEMENTS);
            SrcOperandEncoder<T, SrcNum>::SetSourceVerticalStride(&sourcesReg, G9HDL::VERTSTRIDE_0_ELEMENTS);
        }
        else
        {
            ASSERT_USER(false, "Invalid NULL register source.");
        }
    }

    //////////////////////////////////////////////////////////////////////////
    /// \brief Template based field encoder for encoding source immediate 32 bit data
    ///
    static void EncodeSrcImmData(
        T& immSource, G4_Operand *src)
    {

        G4_Imm *isrc = (G4_Imm *)src->asImm();
        if ( IS_WTYPE(src->getType()))
        {
            uint32_t val = (uint32_t) isrc->getInt();
            uint32_t data = (val << 16) | (val & 0xffff);
            SrcOperandEncoder<T, SrcNum>::
                SetSourceImmediateData(&immSource, data);
        }
        else if (src->getType() == Type_F)
        {
            float val = (float)(isrc->getFloat());
            SrcOperandEncoder<T, SrcNum>::
                SetSourceImmediateData(&immSource, *(uint32_t*)&(val));

        } else {
            SrcOperandEncoder<T, SrcNum>::
                SetSourceImmediateData(&immSource, (uint32_t)isrc->getInt());
        }
    }
};
}
inline void vISA::BinaryEncodingCNL::EncodeSrcImm64Data(
    G9HDL::EU_INSTRUCTION_IMM64_SRC& imm64SourceInstruction, vISA::G4_Operand *src)
{

    vISA::G4_Imm *isrc = (vISA::G4_Imm *)src->asImm();

    if (src->getType() == Type_DF)
    {
        imm64SourceInstruction.SetSource((uint64_t)isrc->getImm());
    }
    else if (src->getType() == Type_Q  || src->getType() == Type_UQ)
    {
        //Q/UQ immediates must be the only source
        int64_t val = isrc->getInt();
        imm64SourceInstruction.SetSource(*(uint64_t*)&(val));
    }
}

#pragma pack(pop)

#endif
