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

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

/*!
 * @file Instruction factory interface
 */

#ifndef IGT_INS_FACTORY_H_
#define IGT_INS_FACTORY_H_

#include "ged.h"
#include "gt_basic_defs.h"
#include "gt_reg.h"
#include "igt_ins.h"

namespace gtpin
{
#pragma pack(push, 8)

/* ===================================================================================================== */
// Class IGtInsFactory
/* ===================================================================================================== */
/*! @ingroup GTPIN_GEN_INSTRUCTION
 * @brief Class that defines virtual constructors of IGtIns objects representing various GEN instructions.
 *
 * GTPin tools mainly use IGtInsFactory interface to make instructions for instrumentation procedures.
 * They receive the IGtGenCoder object along with the IGtKernelInstrument object when GTPin invokes the
 * IGtTool::OnKernelBuild function (@see IGtKernelInstrument::Coder().InstructionFactory()).
 * 
 * @par Availability:
 * - IGtTool::OnKernelBuild
 */
class IGtInsFactory
{
/* ===================================================================================================== */
// The implementation of this class is not required to be thread safe. It is intended to be used
// within serialized instrumentation sessions
/* ===================================================================================================== */
public:

    /// Given a GED instruction representation, create the corsponding IGtIns instance
    virtual IGtIns& Make(const ged_ins_t& gedIns) = 0;

    /// Create a copy of the specified instruction
    virtual IGtIns& Make(const IGtIns& ins) = 0;

public:
    /// Construct a common (arithmetic, logic) 1-source instruction: op(execMask) dst<Reg> src0<Reg>
    virtual IGtIns& MakeOpRR(GtOpcode op, const GtDstRegion& dst, const GtRegRegion& src0,
                             GtExecMask execMask = {1}) = 0;

    /// Construct a common (arithmetic, logic) 1-source instruction: op(execMask) dst<Reg> src0<Imm>
    virtual IGtIns& MakeOpRI(GtOpcode op, const GtDstRegion& dst, const GtImm& src0,
                             GtExecMask execMask = {1}) = 0;

    /// Construct a common (arithmetic, logic) 2-source instruction: op(execMask) dst<Reg> src0<Reg> src1<Reg>
    virtual IGtIns& MakeOpRRR(GtOpcode op, const GtDstRegion& dst, const GtRegRegion& src0,
                              const GtRegRegion& src1, GtExecMask execMask = {1}) = 0;

    /// Construct a common (arithmetic, logic) 2-source instruction: op(execMask) dst<Reg> src0<Reg> src1<Imm>
    virtual IGtIns& MakeOpRRI(GtOpcode op, const GtDstRegion& dst, const GtRegRegion& src0,
                              const GtImm& src1, GtExecMask execMask = {1}) = 0;

    /// Construct a common 3-source instruction: op(execMask) dst<Reg> src0<Reg> src1<Reg> src2<Reg>
    virtual IGtIns& MakeOp3Src(GtOpcode op, const GtDstRegion& dst, const GtRegRegion& src0,
                               const GtRegRegion& src1, const GtRegRegion& src2, GtExecMask execMask = {1}) = 0;

    /// Construct an instruction that moves all bytes of src0 to dst. @pre  dst.ElementSize() == src0.ElementSize()
    virtual IGtIns& MakeRegMov(const GtReg& dst, const GtReg& src0) = 0;

    /// Construct an instruction that sets zero value in all bytes of the specified register
    virtual IGtIns& MakeRegZero(const GtReg& reg) = 0;

    /// Construct a CMP instruction: cmp(execMask) cond.flag null src0<Reg> src1<Reg>
    virtual IGtIns& MakeCmp(GtCondModifier cond, const GtReg& flagReg, const GtRegRegion& src0,
                            const GtRegRegion& src1, GtExecMask execMask = {1}) = 0;

    /// Construct a CMP instruction: cmp(execMask) cond.flag null src0<Reg> src1<Imm>
    virtual IGtIns& MakeCmp(GtCondModifier cond, const GtReg& flagReg, const GtRegRegion& src0,
                            const GtImm& src1, GtExecMask execMask = {1}) = 0;

    /// Construct an illegal GEN instruction
    virtual IGtIns& MakeIllegal()       = 0;

    /// Construct a NOP instruction
    virtual IGtIns& MakeNop()           = 0;
    virtual IGtIns& MakeCompactNop()    = 0;

    /*!
     * @brief Construct a SendMessage instruction: send (execMask) dst<Reg> src0<Reg> src1<Reg> exDesc<Imm>, desc<Imm>
     * @note This function ignores GtReg::SubRegNum() and GtReg::ElementSize() in the operands specifications.
     */
    virtual IGtIns& MakeSendMsg(const GtReg& dst, const GtReg& src0, const GtReg& src1,
                                uint32_t exDesc, uint32_t desc, GtExecMask execMask = {1}) = 0;

    /*!
     * @brief Construct instruction that atomically accesses data in the profile buffer
     *
     * @param[in]   aop             Opcode of the atomic operation
     * @param[in]   dst             Register that receives output of the atomic operation.
     *                              NullReg() indicates that no output data is requested
     * @param[in]   addrReg         Register that specifies address of data within profile buffer to be modified
     *                              by the atomic operation.
     * @param[in]   src             Register that holds the input data of the atomic operation, or NullReg() if
     *                              this operation has no sources
     * @param[in]   dataType        Type of the SIMD data element the instruction operates on.
     *                              32-bit integers (GED_DATA_TYPE_ud) are supported in all platforms.
     *                              For any other type, check CanAccessAtomically(dataType).
     * @param[in]   execMask        Specifies SIMD data elements to be accesed by the instruction.
     *                              Indirectly, this paramter also specifies the total data size.
     * 
     * @pre addrReg, dst, and src registers are zero-aligned:
     *      GtReg::SubRegNum() == 0 for physical register, and IGtVreg::RequiredSubregNum() == 0 for virtual register.
     *      Virtual registers created by IGtVregFactory::MakeMsgAddrScratch() and IGtVregFactory::MakeMsgDataScratch()
     *      satisfy this requirement.
     */
    virtual IGtIns& MakeAtomicOp(GtAtomicOp aop, const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                 GtDataType dataType, GtExecMask execMask = {1}) = 0;

    /// Return true, if data of the specified type can be accessed atomically in the platform associated with this factory 
    virtual bool CanAccessAtomically(GtDataType dataType) const = 0;

    /// Return GEN model of instructions created by this factory
    virtual const IGtGenModel& GenModel() const = 0;

public:
    // Inline customizations of the virtual factory methods

    //----------------------------------------------------------------------------------------------------
    // 1-source instructions
    //----------------------------------------------------------------------------------------------------
    inline IGtIns& MakeMov(const GtDstRegion& dst, const GtRegRegion& src0, GtExecMask execMask = {1}); ///< Make MOV instruction
    inline IGtIns& MakeMov(const GtDstRegion& dst, const GtImm& src0, GtExecMask execMask = {1});       ///< Make MOV instruction

    inline IGtIns& MakeNot(const GtDstRegion& dst, const GtRegRegion& src0, GtExecMask execMask = {1}); ///< Make NOT instruction
    inline IGtIns& MakeNot(const GtDstRegion& dst, const GtImm& src0, GtExecMask execMask = {1});       ///< Make NOT instruction

    inline IGtIns& MakeCbit(const GtDstRegion& dst, const GtRegRegion& src0, GtExecMask execMask = {1});///< Make CBIT instruction
    inline IGtIns& MakeCbit(const GtDstRegion& dst, const GtImm& src0, GtExecMask execMask = {1});      ///< Make CBIT instruction

    //----------------------------------------------------------------------------------------------------
    // 2-source instructions
    //----------------------------------------------------------------------------------------------------
    inline IGtIns& MakeAdd(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1}); ///< Make ADD instruction
    inline IGtIns& MakeAdd(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});       ///< Make ADD instruction

    inline IGtIns& MakeAddc(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1});///< Make ADDC instruction
    inline IGtIns& MakeAddc(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});      ///< Make ADDC instruction

    inline IGtIns& MakeAnd(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1}); ///< Make AND instruction
    inline IGtIns& MakeAnd(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});       ///< Make AND instruction

    inline IGtIns& MakeOr(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1});  ///< Make OR instruction
    inline IGtIns& MakeOr(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});        ///< Make OR instruction

    inline IGtIns& MakeXor(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1}); ///< Make XOR instruction
    inline IGtIns& MakeXor(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});       ///< Make XOR instruction

    inline IGtIns& MakeShr(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1}); ///< Make SHR instruction
    inline IGtIns& MakeShr(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});       ///< Make SHR instruction

    inline IGtIns& MakeShl(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1}); ///< Make SHL instruction
    inline IGtIns& MakeShl(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});       ///< Make SHL instruction

    inline IGtIns& MakeMul(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1}); ///< Make MUL instruction
    inline IGtIns& MakeMul(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});       ///< Make MUL instruction

    inline IGtIns& MakeSel(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1}); ///< Make SEL instruction
    inline IGtIns& MakeSel(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});       ///< Make SEL instruction

    inline IGtIns& MakeSub(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask = {1}); ///< Make SUB instruction
    inline IGtIns& MakeSub(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask = {1});       ///< Make SUB instruction

    //----------------------------------------------------------------------------------------------------
    // 3-source instructions
    //----------------------------------------------------------------------------------------------------
    inline IGtIns& MakeCsel(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, const GtRegRegion& src2,
                            GtExecMask execMask = {1});                                                                          ///< Make CSEL instruction

    //----------------------------------------------------------------------------------------------------
    // Atomic instructions
    //----------------------------------------------------------------------------------------------------

    /// Construct instruction that atomically increments the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicInc(const GtReg& dst, const GtReg& addrReg,
                                 GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically decrements the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicDec(const GtReg& dst, const GtReg& addrReg,
                                 GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically stores the bitwise AND of 'src' value and [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicAnd(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                 GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically stores the bitwise OR of 'src' value and [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicOr(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically stores the bitwise XOR of 'src' value and [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicXor(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                 GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically adds 'src' value to the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicAdd(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                 GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically substracts 'src' value from the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicSub(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                 GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically stores the signed MAX of 'src' value and the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicImax(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                  GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically stores the signed MIN of 'src' value and the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicImin(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                  GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically stores the unsigned MAX of 'src' value and the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicUmax(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                  GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically stores the unsigned MIN of 'src' value and the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicUmin(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                  GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically exchanges 'src' value with the [addrReg] value in the profile buffer
    inline IGtIns& MakeAtomicXchg(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                  GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

    /// Construct instruction that atomically stores 'src' value at the [addrReg] location in the profile buffer
    inline IGtIns& MakeAtomicStore(const GtReg& addrReg, const GtReg& src,
                                   GtDataType dataType = GED_DATA_TYPE_ud, GtExecMask execMask = {1});

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

/* ===================================================================================================== */
// IGtInsFactory: implementation of inline methods 
/* ===================================================================================================== */
IGtIns& IGtInsFactory::MakeMov(const GtDstRegion& dst, const GtRegRegion& src0, GtExecMask execMask)
{
    return MakeOpRR(GED_OPCODE_mov, dst, src0, execMask);
}
IGtIns& IGtInsFactory::MakeMov(const GtDstRegion& dst, const GtImm& src0, GtExecMask execMask)
{
    return MakeOpRI(GED_OPCODE_mov, dst, src0, execMask);
}
IGtIns& IGtInsFactory::MakeNot(const GtDstRegion& dst, const GtRegRegion& src0, GtExecMask execMask)
{
    return MakeOpRR(GED_OPCODE_not, dst, src0, execMask);
}
IGtIns& IGtInsFactory::MakeNot(const GtDstRegion& dst, const GtImm& src0, GtExecMask execMask)
{
    return MakeOpRI(GED_OPCODE_not, dst, src0, execMask);
}
IGtIns& IGtInsFactory::MakeCbit(const GtDstRegion& dst, const GtRegRegion& src0, GtExecMask execMask)
{
    return MakeOpRR(GED_OPCODE_cbit, dst, src0, execMask);
}
IGtIns& IGtInsFactory::MakeCbit(const GtDstRegion& dst, const GtImm& src0, GtExecMask execMask)
{
    return MakeOpRI(GED_OPCODE_cbit, dst, src0, execMask);
}

IGtIns& IGtInsFactory::MakeAdd(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_add, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeAdd(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_add, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeAddc(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_addc, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeAddc(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_addc, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeAnd(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_and, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeAnd(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_and, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeOr(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_or, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeOr(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_or, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeXor(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_xor, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeXor(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_xor, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeShr(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_shr, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeShr(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_shr, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeShl(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_shl, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeShl(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_shl, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeMul(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_mul, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeMul(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_mul, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeSel(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    return MakeOpRRR(GED_OPCODE_sel, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeSel(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeOpRRI(GED_OPCODE_sel, dst, src0, src1, execMask);
}
IGtIns& IGtInsFactory::MakeSub(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, GtExecMask execMask)
{
    IGtIns& ins = MakeAdd(dst, src0, src1, execMask);
    ins.SetSrcModifier(1, GED_SRC_MOD_Negative);
    return ins;
}
IGtIns& IGtInsFactory::MakeSub(const GtDstRegion& dst, const GtRegRegion& src0, const GtImm& src1, GtExecMask execMask)
{
    return MakeAdd(dst, src0, GtImm(-int64_t(src1.Value()), src1.DataType()), execMask);
}

IGtIns& IGtInsFactory::MakeCsel(const GtDstRegion& dst, const GtRegRegion& src0, const GtRegRegion& src1, const GtRegRegion& src2,
                                GtExecMask execMask)
{
    return MakeOp3Src(GED_OPCODE_csel, dst, src0, src1, src2, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicInc(const GtReg& dst, const GtReg& addrReg, GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_INC, dst, addrReg, NullReg(), dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicDec(const GtReg& dst, const GtReg& addrReg, GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_DEC, dst, addrReg, NullReg(), dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicAnd(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                     GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_AND, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicOr(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                    GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_OR, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicXor(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                       GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_XOR, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicAdd(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                     GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_ADD, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicSub(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                     GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_SUB, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicImax(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                        GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_IMAX, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicImin(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                      GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_IMIN, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicUmax(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                      GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_UMAX, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicUmin(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                      GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_UMIN, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicXchg(const GtReg& dst, const GtReg& addrReg, const GtReg& src,
                                      GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_MOV, dst, addrReg, src, dataType, execMask);
}

IGtIns& IGtInsFactory::MakeAtomicStore(const GtReg& addrReg, const GtReg& src, GtDataType dataType, GtExecMask execMask)
{
    return MakeAtomicOp(GED_ATOMIC_OPERATION_TYPE_AOP_MOV, NullReg(), addrReg, src, dataType, execMask);
}

#pragma pack(pop)
}
#endif

