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

Copyright (C) 2017-2021 Intel Corporation

SPDX-License-Identifier: MIT

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

#ifndef _BUILDCISAIR_H_
#define _BUILDCISAIR_H_

#include <sstream>
#include <cstdint>

namespace vISA
{
    class Mem_Manager;
    class PlatformInfo;
}
class CisaKernel;
class CisaBinary;
class VISAKernelImpl;
class VISAFunction;

#define YY_DECL int yylex(CISA_IR_Builder *pBuilder)

extern FILE *CISAin;
extern FILE *CISAout;
extern int CISAdebug;

#include "VISABuilderAPIDefinition.h"
#include "inc/common/sku_wa.h"
#include "PlatformInfo.h"

class Options;

class CISA_IR_Builder : public VISABuilder
{
public:
    CISA_IR_Builder(
        TARGET_PLATFORM platform, VISA_BUILDER_OPTION buildOption, vISABuilderMode mode,
        int majorVersion, int minorVersion, const WA_TABLE *pWaTable)
        : mBuildOption(buildOption), m_builderMode(mode), m_mem(4096), m_pWaTable(pWaTable)
    {
        m_platformInfo = vISA::PlatformInfo::LookupPlatformInfo(platform);
        assert(m_platformInfo != nullptr);
        m_header.major_version = majorVersion;
        m_header.minor_version = minorVersion;
        m_header.magic_number = COMMON_ISA_MAGIC_NUM;

        m_cisaBinary = new (m_mem) CisaFramework::CisaBinary(this);
    }

    virtual ~CISA_IR_Builder();

    /**************START VISA BUILDER API*****************************/

    static int CreateBuilder(
        CISA_IR_Builder *&builder,
        vISABuilderMode mode,
        VISA_BUILDER_OPTION buildOption,
        TARGET_PLATFORM platform,
        int numArgs,
        const char* flags[],
        const WA_TABLE *pWaTable = nullptr);
    static int DestroyBuilder(CISA_IR_Builder *builder);
    VISA_BUILDER_API int AddKernel(VISAKernel *& kernel, const char* kernelName) override;
    VISA_BUILDER_API int SetPrevKernel(VISAKernel *& prevKernel) override;
    VISA_BUILDER_API int AddFunction(VISAFunction *& function, const char* functionName) override;
    VISA_BUILDER_API int AddPayloadSection(VISAFunction *& function, const char* functionName) override;
    VISA_BUILDER_API int Compile(const char * isaFileNameint, std::ostream * os = nullptr, bool emit_visa_only = false) override;

    VISA_BUILDER_API void SetOption(vISAOptions option, bool val) override { m_options.setOption(option, val); }
    VISA_BUILDER_API void SetOption(vISAOptions option, uint32_t val) override { m_options.setOption(option, val); }
    VISA_BUILDER_API void SetOption(vISAOptions option, const char *val) override { m_options.setOption(option, val); }

    // Used for inline asm code generation
    VISA_BUILDER_API int ParseVISAText(const std::string& visaText, const std::string& visaTextFile) override;
    VISA_BUILDER_API int ParseVISAText(const std::string& visaFile) override;
    VISA_BUILDER_API std::stringstream& GetAsmTextStream() override { return m_ssIsaAsm; }
    VISA_BUILDER_API VISAKernel* GetVISAKernel(const std::string& kernelName) const override;
    VISA_BUILDER_API int ClearAsmTextStreams() override;

    /**************END VISA BUILDER API*************************/

    string_pool_entry** branch_targets;
    common_isa_header m_header {};

    // the current vISA kernel/function being processed
    VISAKernelImpl *m_kernel;
    VISAKernelImpl *m_prevKernel = nullptr;
    CisaFramework::CisaBinary *m_cisaBinary;
    VISAKernelImpl * get_kernel() const { return m_kernel; }

    std::stringstream& criticalMsgStream()
    {
        return criticalMsg;
    }

    std::string GetCriticalMsg() override
    {
        return criticalMsg.str();
    }

    bool debugParse() const {return m_options.getOption(vISA_DebugParse);}

    int verifyVISAIR();


    static void cat(std::stringstream &ss) { }
    template <typename T, typename...Ts>
    static void cat(std::stringstream &ss, T t, Ts...ts) {
        ss << t;
        cat(ss, ts...);
    }

    std::string                 m_errorMessage;
    template <typename...Ts>
    void RecordParseError(int lineNum, Ts...ts)
    {
        if (HasParseError()) // report first only
            return;

        std::stringstream ss;
        if (lineNum > 0)
            ss << "near line " << lineNum << ": ";
        else
            ss << "unknown location: ";

        cat(ss, ts...);
        m_errorMessage = ss.str();
        criticalMsg << m_errorMessage << "\n";
    }
    bool HasParseError() const {return !m_errorMessage.empty();}
    std::string GetParseError() const {return m_errorMessage;}

    template <typename...Ts>
    void RecordParseWarning(int lineNum, Ts...ts)
    {
        std::stringstream ss;
        ss << "near line " << lineNum << ": ";
        cat(ss, ts...);
        m_warnings.push_back(ss.str());
    }

    std::vector<std::string>    m_warnings;
    const std::vector<std::string> &GetWarnings() const {
        return m_warnings;
    }

    /////////////////////////////////////////////////////
    // holds the %DispatchSimdSize attribute
    int    m_dispatchSimdSize = -1;

    const WA_TABLE *getWATable() const { return m_pWaTable; }

    uint8_t getMajorVersion() const { return m_header.major_version; }
    uint8_t getMinorVersion() const { return m_header.minor_version; }

    void CISA_IR_setVersion(unsigned char major_ver, unsigned char minor_ver)
    {
        m_header.major_version = major_ver;
        m_header.minor_version = minor_ver;
    }

    Common_ISA_Input_Class get_input_class(Common_ISA_Var_Class var_class);

    bool CISA_lookup_builtin_constant(int lineNum, const char *symbol, int64_t &val);
    bool CISA_eval_sizeof_decl(int lineNum, const char *arg, int64_t &val);

    VISA_StateOpndHandle *CISA_get_surface_variable(const char *varName, int lineNum);
    VISA_StateOpndHandle *CISA_get_sampler_variable(const char *varName, int lineNum);

    bool CISA_general_variable_decl(
        const char * var_name,
        unsigned int var_elemts_num,
        VISA_Type data_type,
        VISA_Align var_align,
        const char * var_alias_name,
        int var_alias_offset,
        std::vector<attr_gen_struct*>& scope,
        int lineNum);

    bool CISA_addr_variable_decl(
        const char *var_name,
        unsigned int var_elements,
        VISA_Type data_type,
        std::vector<attr_gen_struct*>& scope,
        int lineNum);

    bool CISA_predicate_variable_decl(
        const char *var_name,
        unsigned int var_elements,
        std::vector<attr_gen_struct*>& attrs,
        int lineNum);

    bool CISA_sampler_variable_decl(
        const char *var_name, int num_elts, const char* name, int lineNum);

    bool CISA_surface_variable_decl(
        const char *var_name, int num_elts, const char* name,
        std::vector<attr_gen_struct*>& attrs, int lineNum);

    bool CISA_input_directive(
        const char* var_name, short offset, unsigned short size, int lineNum);

    bool CISA_implicit_input_directive(
        const char * argName, const char * varName,
        short offset, unsigned short size, int lineNum);

    //bool CISA_attr_directive(char* input_name, attribute_info_t* attr);
    bool CISA_attr_directive(const char* input_name, const char* input_var, int lineNum);
    bool CISA_attr_directiveNum(const char* input_name, uint32_t input_var, int lineNum);

    bool CISA_create_label(const char * label_name, int lineNum);
    bool CISA_function_directive(const char* func_name, int lineNum);


    bool CISA_create_arith_instruction(
        VISA_opnd * cisa_pred,
        ISA_Opcode opcode,
        bool  sat,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd * dst_cisa,
        VISA_opnd * src0_cisa,
        VISA_opnd * src1_cisa,
        VISA_opnd * src2_cisa,
        int lineNum);
    bool CISA_create_arith_instruction2(
        VISA_opnd * cisa_pred,
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd * dst_cisa,
        VISA_opnd * src0_cisa,
        VISA_opnd * src1_cisa,
        VISA_opnd * src2_cisa,
        int lineNum);

    bool CISA_create_mov_instruction(
        VISA_opnd *pred,
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        bool sat,
        VISA_opnd *dst,
        VISA_opnd *src0,
        int lineNum);

    bool CISA_create_mov_instruction(
        VISA_opnd *dst, CISA_GEN_VAR *src0, int lineNum);

    bool CISA_create_movs_instruction(
        VISA_EMask_Ctrl emask,
        ISA_Opcode opcode,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        int lineNum);


    bool CISA_create_branch_instruction(
        VISA_opnd *pred,
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        const char *target_label,
        bool is_fccall,
        int lineNum);


    bool CISA_create_cmp_instruction(
        VISA_Cond_Mod sub_op,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        CISA_GEN_VAR* decl,
        VISA_opnd *src0,
        VISA_opnd *src1,
        int lineNum);

    bool CISA_create_cmp_instruction(
        VISA_Cond_Mod sub_op,
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        VISA_opnd *src1,
        int lineNum);

    bool CISA_create_media_instruction(
        ISA_Opcode opcode,
        MEDIA_LD_mod media_mod,
        int row_off,
        int elem_off,
        unsigned int plane_ID,
        const char * surface_name,
        VISA_opnd *src0,
        VISA_opnd *src1,
        VISA_opnd *raw_dst,
        int lineNum);


    bool CISA_Create_Ret(
        VISA_opnd *pred_opnd,
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned int exec_size,
        int lineNum);

    bool CISA_create_oword_instruction(
        ISA_Opcode opcode,
        bool media_mod,
        unsigned int size,
        const char *surface_name,
        VISA_opnd *src0,
        VISA_opnd *raw_dst_src,
        int lineNum);

    bool CISA_create_svm_block_instruction(
        SVMSubOpcode subopcode,
        unsigned     owords,
        bool         unaligned,
        VISA_opnd*   address,
        VISA_opnd*   srcDst,
        int          line_no);

    bool CISA_create_svm_scatter_instruction(
        VISA_opnd*   pred,
        SVMSubOpcode subopcode,
        VISA_EMask_Ctrl emask,
        unsigned     exec_size,
        unsigned     blockSize,
        unsigned     numBlocks,
        VISA_opnd*   addresses,
        VISA_opnd*   srcDst,
        int          line_no);

    bool CISA_create_svm_atomic_instruction(
        VISA_opnd* pred,
        VISA_EMask_Ctrl emask,
        unsigned   exec_size,
        VISAAtomicOps op,
        unsigned short bitwidth,
        VISA_opnd* addresses,
        VISA_opnd* src0,
        VISA_opnd* src1,
        VISA_opnd* dst,
        int lineNum);

    bool CISA_create_svm_gather4_scaled(
        VISA_opnd              *pred,
        VISA_EMask_Ctrl        eMask,
        unsigned               execSize,
        ChannelMask            chMask,
        VISA_opnd              *address,
        VISA_opnd              *offsets,
        VISA_opnd              *src,
        int                    lineNum);

    bool CISA_create_svm_scatter4_scaled(
        VISA_opnd              *pred,
        VISA_EMask_Ctrl eMask,
        unsigned               execSize,
        ChannelMask            chMask,
        VISA_opnd              *address,
        VISA_opnd              *offsets,
        VISA_opnd              *src,
        int                    lineNum);

    bool CISA_create_address_instruction(
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        VISA_opnd *src1,
        int lineNum);


    bool CISA_create_logic_instruction(
        VISA_opnd *pred,
        ISA_Opcode opcode,
        bool sat,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        VISA_opnd *src1,
        VISA_opnd *src2,
        VISA_opnd *src3,
        int lineNum);

    bool CISA_create_logic_instruction(
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        CISA_GEN_VAR *dst,
        CISA_GEN_VAR *src0,
        CISA_GEN_VAR *src1,
        int lineNum);

    bool CISA_create_math_instruction(
        VISA_opnd *pred,
        ISA_Opcode opcode,
        bool  sat,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        VISA_opnd *src1,
        int lineNum);

    bool CISA_create_setp_instruction(
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        CISA_GEN_VAR *dst,
        VISA_opnd *src0,
        int lineNum);

    bool CISA_create_sel_instruction(
        ISA_Opcode opcode,
        bool sat,
        VISA_opnd *pred,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        VISA_opnd *src1,
        int lineNum);

    bool CISA_create_fminmax_instruction(
        bool minmax,
        ISA_Opcode opcode,
        bool sat,
        VISA_opnd *pred,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        VISA_opnd *src1,
        int lineNum);

    bool CISA_create_scatter_instruction(
        ISA_Opcode opcode,
        int elemNum,
        VISA_EMask_Ctrl emask,
        unsigned elt_size,
        bool modifier,
        const char *surface_name,
        VISA_opnd *global_offset, //global_offset
        VISA_opnd *element_offset, //element_offset
        VISA_opnd *raw_dst_src, //dst/src
        int lineNum);

    bool CISA_create_scatter4_typed_instruction(
        ISA_Opcode opcode,
        VISA_opnd *pred,
        ChannelMask ch_mask,
        VISA_EMask_Ctrl emask,
        unsigned execSize,
        const char* surfaceName,
        VISA_opnd *uOffset,
        VISA_opnd *vOffset,
        VISA_opnd *rOffset,
        VISA_opnd *lod,
        VISA_opnd *dst,
        int lineNum);

    bool CISA_create_scatter4_scaled_instruction(
        ISA_Opcode opcode,
        VISA_opnd *pred,
        VISA_EMask_Ctrl eMask,
        unsigned execSize,
        ChannelMask chMask,
        const char* surfaceName,
        VISA_opnd *globalOffset,
        VISA_opnd *offsets,
        VISA_opnd *dstSrc,
        int lineNum);

    bool CISA_create_scatter_scaled_instruction(
        ISA_Opcode opcode,
        VISA_opnd *pred,
        VISA_EMask_Ctrl eMask,
        unsigned execSize,
        unsigned numBlocks,
        const char* surfaceName,
        VISA_opnd *globalOffset,
        VISA_opnd *offsets,
        VISA_opnd *dstSrc,
        int lineNum);

    bool CISA_create_sync_instruction(ISA_Opcode opcode, int lineNum);

    bool CISA_create_sbarrier_instruction(bool isSignal, int lineNum);

    bool CISA_create_invtri_inst(
        VISA_opnd *pred,
        ISA_Opcode opcode,
        bool  sat,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        int lineNum);

    bool CISA_create_dword_atomic_instruction(
        VISA_opnd *pred,
        VISAAtomicOps subOpc,
        bool is16Bit,
        VISA_EMask_Ctrl eMask,
        unsigned execSize,
        const char *surfaceName,
        VISA_opnd *offsets,
        VISA_opnd *src0,
        VISA_opnd *src1,
        VISA_opnd *dst,
        int lineNum);

    bool CISA_create_typed_atomic_instruction(
        VISA_opnd *pred,
        VISAAtomicOps subOpc,
        bool is16Bit,
        VISA_EMask_Ctrl eMask,
        unsigned execSize,
        const char *surfaceName,
        VISA_opnd *u,
        VISA_opnd *v,
        VISA_opnd *r,
        VISA_opnd *lod,
        VISA_opnd *src0,
        VISA_opnd *src1,
        VISA_opnd *dst,
        int lineNum);

    bool CISA_create_urb_write_3d_instruction(
        VISA_opnd* pred,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        unsigned int num_out,
        unsigned int global_offset,
        VISA_opnd* channel_mask,
        VISA_opnd* urb_handle,
        VISA_opnd* per_slot_offset,
        VISA_opnd* vertex_data,
        int lineNum);

    bool CISA_create_rtwrite_3d_instruction(
        VISA_opnd* pred,
        const char* mode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        const char* surface_name,
        const std::vector<VISA_opnd*>& operands,
        int lineNum);

    bool CISA_create_info_3d_instruction(
        VISASampler3DSubOpCode subOpcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        ChannelMask channel,
        const char* surface_name,
        VISA_opnd* lod,
        VISA_opnd* dst,
        int lineNum);

    bool createSample4Instruction(
        VISA_opnd* pred,
        VISASampler3DSubOpCode subOpcode,
        bool pixelNullMask,
        ChannelMask channels,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd* aoffimmi,
        const char* sampler_name,
        const char* surface_name,
        VISA_opnd* dst,
        unsigned int numParameters,
        VISA_RawOpnd** params,
        int lineNum);

    bool create3DLoadInstruction(
        VISA_opnd* pred,
        VISASampler3DSubOpCode subOpcode,
        bool pixelNullMask,
        ChannelMask channels,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd* aoffimmi,
        const char* surface_name,
        VISA_opnd* dst,
        unsigned int numParameters,
        VISA_RawOpnd** params,
        int lineNum);

    bool create3DSampleInstruction(
        VISA_opnd* pred,
        VISASampler3DSubOpCode subOpcode,
        bool pixelNullMask,
        bool cpsEnable,
        bool uniformSampler,
        ChannelMask channels,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd* aoffimmi,
        const char* sampler_name,
        const char* surface_name,
        VISA_opnd* dst,
        unsigned int numParameters,
        VISA_RawOpnd** params,
        int lineNum);

    bool CISA_create_sample_instruction(
        ISA_Opcode opcode,
        ChannelMask channel,
        int simd_mode,
        const char* sampler_name,
        const char* surface_name,
        VISA_opnd *u_opnd,
        VISA_opnd *v_opnd,
        VISA_opnd *r_opnd,
        VISA_opnd *dst,
        int lineNum);

    bool CISA_create_avs_instruction(
        ChannelMask channel,
        const char* surface_name,
        const char* sampler_name,
        VISA_opnd *u_offset,
        VISA_opnd *v_offset,
        VISA_opnd *deltaU,
        VISA_opnd *deltaV,
        VISA_opnd *u2d,
        VISA_opnd *groupID,
        VISA_opnd *verticalBlockNumber,
        OutputFormatControl cntrl,
        VISA_opnd *v2d,
        AVSExecMode execMode,
        VISA_opnd *iefbypass,
        VISA_opnd *dst,
        int lineNum);

    bool CISA_create_sampleunorm_instruction(
        ISA_Opcode opcode,
        ChannelMask channel,
        CHANNEL_OUTPUT_FORMAT out,
        const char* sampler_dcl,
        const char* surface_dcl,
        VISA_opnd *src0,
        VISA_opnd *src1,
        VISA_opnd *src2,
        VISA_opnd *src3,
        VISA_opnd *dst,
        int lineNum);

    bool CISA_create_vme_ime_instruction(
        ISA_Opcode opcode,
        unsigned char stream_mode,
        unsigned char searchCtrl,
        VISA_opnd *input_opnd,
        VISA_opnd *ime_input_opnd,
        const char* surface_name,
        VISA_opnd *ref0_opnd,
        VISA_opnd *ref1_opnd,
        VISA_opnd *costCenter_opnd,
        VISA_opnd *dst_opnd,
        int lineNum);

    bool CISA_create_vme_sic_instruction(
        ISA_Opcode opcode,
        VISA_opnd *input_opnd,
        VISA_opnd *sic_input_opnd,
        const char* surface_name,
        VISA_opnd *dst,
        int lineNum);

    bool CISA_create_vme_fbr_instruction(
        ISA_Opcode opcode,
        VISA_opnd *input_opnd,
        VISA_opnd *fbr_input_opnd,
        const char* surface_name,
        VISA_opnd* fbrMbMode,
        VISA_opnd* fbrSubMbShape,
        VISA_opnd* fbrSubPredMode,
        VISA_opnd *dst,
        int lineNum);

    bool CISA_create_switch_instruction(
        ISA_Opcode opcode,
        unsigned exec_size,
        VISA_opnd *indexOpnd,
        const std::deque<const char*>& labels,
        int lineNum);

    bool CISA_create_fcall_instruction(
        VISA_opnd *pred_opnd,
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        const char* funcName,
        unsigned arg_size,
        unsigned return_size,
        int lineNum);

    bool CISA_create_ifcall_instruction(
        VISA_opnd *pred_opnd,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd* funcAddr,
        unsigned arg_size,
        unsigned return_size,
        int lineNum);

    bool CISA_create_faddr_instruction(
        const char* sym_name, VISA_opnd* dst, int lineNum);

    bool CISA_create_raw_send_instruction(
        ISA_Opcode opcode,
        unsigned char modifier,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *pred,
        unsigned int exMsgDesc,
        unsigned char srcSize,
        unsigned char dstSize,
        VISA_opnd *Desc,
        VISA_opnd *src,
        VISA_opnd *dst,
        int lineNum);
    bool CISA_create_raw_sends_instruction(
        ISA_Opcode opcode,
        unsigned char modifier,
        bool hasEOT,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *pred,
        VISA_opnd *exMsgDesc,
        unsigned char ffid,
        unsigned char src0Size,
        unsigned char src1Size,
        unsigned char dstSize,
        VISA_opnd *Desc,
        VISA_opnd *src0,
        VISA_opnd *src1,
        VISA_opnd *dst,
        int lineNum);
    bool CISA_create_fence_instruction(ISA_Opcode opcode, unsigned char mode, int lineNum);
    bool CISA_create_wait_instruction(VISA_opnd* mask, int lineNum);
    bool CISA_create_yield_instruction(ISA_Opcode opcode, int lineNum);

    bool CISA_create_lifetime_inst(unsigned char startOrEnd, const char* src, int lineNum);

    bool CISA_create_FILE_instruction(ISA_Opcode opcode, const char * file_name, int lineNum);
    bool CISA_create_LOC_instruction(ISA_Opcode opcode, unsigned int loc, int lineNum);
    bool CISA_create_NO_OPND_instruction(ISA_Opcode opcode, int lineNum);

    void CISA_post_file_parse();

    VISA_opnd * CISA_create_gen_src_operand(
        const char* var_name, short v_stride, short width, short h_stride,
        unsigned char row_offset, unsigned char col_offset, VISA_Modifier mod, int lineNum);
    VISA_opnd * CISA_dst_general_operand(
        const char * var_name, unsigned char roff, unsigned char sroff,
        unsigned short hstride,
        int lineNum);
    attr_gen_struct* CISA_Create_Attr(const char* AttrName, int64_t I64Val, const char* CStrVal);
    VISA_opnd * CISA_create_immed(uint64_t value, VISA_Type type, int lineNum);
    VISA_opnd * CISA_create_float_immed(double value, VISA_Type type, int lineNum);
    CISA_GEN_VAR * CISA_find_decl(const char * var_name);
    VISA_opnd * CISA_set_address_operand(
        CISA_GEN_VAR * cisa_decl, unsigned char offset, short width, bool isDst, int lineNum);
    VISA_opnd * CISA_set_address_expression(CISA_GEN_VAR *cisa_decl, short offset, int lineNum);
    VISA_opnd * CISA_create_indirect(
        CISA_GEN_VAR * cisa_decl, VISA_Modifier mod, unsigned short row_offset,
        unsigned char col_offset, unsigned short immedOffset,
        unsigned short vertical_stride, unsigned short width,
        unsigned short horizontal_stride, VISA_Type type, int lineNum);
    VISA_opnd * CISA_create_indirect_dst(
        CISA_GEN_VAR * cisa_decl,VISA_Modifier mod, unsigned short row_offset,
        unsigned char col_offset, unsigned short immedOffset,
        unsigned short horizontal_stride, VISA_Type type, int lineNum);
    VISA_opnd * CISA_create_state_operand(
        const char * var_name, unsigned char offset, int lineNum, bool isDst);
    VISA_opnd * CISA_create_predicate_operand(
        CISA_GEN_VAR * var, VISA_PREDICATE_STATE state,
        VISA_PREDICATE_CONTROL pred_cntrl, int lineNum);
    VISA_opnd * CISA_create_RAW_NULL_operand(int lineNum);
    VISA_opnd * CISA_create_RAW_operand(
        const char * var_name, unsigned short offset, int lineNum);

    bool addAllVarAttributes(
        CISA_GEN_VAR* GenVar, std::vector<attr_gen_struct*>& Attrs, int linueNum);

    void CISA_push_decl_scope();
    void CISA_pop_decl_scope();

    unsigned short get_hash_key(const char* str);
    string_pool_entry** new_string_pool();
    string_pool_entry * string_pool_lookup(string_pool_entry **spool, const char *str);
    bool string_pool_lookup_and_insert(
        string_pool_entry **spool, const char *str,
        Common_ISA_Var_Class type, VISA_Type data_type);

    // getKernels - get all kernels and functions added into this builder
    std::list<VISAKernelImpl*>& getKernels() { return m_kernelsAndFunctions; }

    const VISAKernelImpl* getKernel(const std::string& name) const;

    Options m_options;
    std::stringstream m_ssIsaAsm;

    void setGtpinInit(void* buf) { gtpin_init = buf; }
    void* getGtpinInit() { return gtpin_init; }

    const vISA::PlatformInfo* getPlatformInfo() const { return m_platformInfo; }
    TARGET_PLATFORM getPlatform() const { return m_platformInfo->platform; }
    Options* getOptions() { return &m_options; }
    VISA_BUILDER_OPTION getBuilderOption() const { return mBuildOption; }
    vISABuilderMode getBuilderMode() const { return m_builderMode; }

    bool CISA_create_dpas_instruction(
        ISA_Opcode opcode,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd * dst_cisa,
        VISA_opnd * src0_cisa,
        VISA_opnd * src1_cisa,
        VISA_opnd * src2_cisa,
        GenPrecision A,
        GenPrecision W,
        uint8_t D,
        uint8_t C,
        int lineNum);

    bool CISA_create_bfn_instruction(
        VISA_opnd * pred,
        uint8_t func_ctrl,
        bool sat,
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd * dst_cisa,
        VISA_opnd * src0_cisa,
        VISA_opnd * src1_cisa,
        VISA_opnd * src2_cisa,
        int lineNum);

    bool CISA_create_qword_scatter_instruction(
        ISA_Opcode opcode,
        VISA_opnd *pred,
        VISA_EMask_Ctrl eMask,
        unsigned execSize,
        unsigned numBlocks,
        const char* surfaceName,
        VISA_opnd *offsets,
        VISA_opnd *dstSrc,
        int lineNum);

    bool CISA_create_bf_cvt_instruction(
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd *dst,
        VISA_opnd *src0,
        int lineNum);

    bool CISA_create_lsc_untyped_inst(
        VISA_opnd               *pred,
        LSC_OP                   opcode,
        LSC_SFID                 sfid,
        LSC_CACHE_OPTS           caching,
        VISA_Exec_Size           execSize,
        VISA_EMask_Ctrl          emask,
        LSC_ADDR                 addr,
        LSC_DATA_SHAPE           dataShape,
        VISA_opnd               *surface,
        VISA_opnd               *dst,
        VISA_opnd               *src0,
        VISA_opnd               *src1,
        VISA_opnd               *src2,
        int                      lineNum);
    bool CISA_create_lsc_untyped_strided_inst(
        VISA_opnd               *pred,
        LSC_OP                   opcode,
        LSC_SFID                 sfid,
        LSC_CACHE_OPTS           caching,
        VISA_Exec_Size           execSize,
        VISA_EMask_Ctrl          emask,
        LSC_ADDR                 addr,
        LSC_DATA_SHAPE           dataShape,
        VISA_opnd               *surface,
        VISA_opnd               *dstData,
        VISA_opnd               *src0AddrBase,
        VISA_opnd               *src0AddrPitch,
        VISA_opnd               *src1Data,
        int                      lineNum);
    bool CISA_create_lsc_untyped_block2d_inst(
        VISA_opnd               *pred,
        LSC_OP                   opcode,
        LSC_SFID                 sfid,
        LSC_CACHE_OPTS           caching,
        VISA_Exec_Size           execSize,
        VISA_EMask_Ctrl          emask,
        LSC_DATA_SHAPE_BLOCK2D   dataShape,
        VISA_opnd               *dstData,
        VISA_opnd               *src0Addrs[LSC_BLOCK2D_ADDR_PARAMS], // {base,surfW,surfH,surfP,x,y}
        VISA_opnd               *src1Data,
        int                      lineNum);
    bool CISA_create_lsc_typed_inst(
        VISA_opnd               *pred,
        LSC_OP                   opcode,
        LSC_SFID                 sfid,
        LSC_CACHE_OPTS           caching,
        VISA_Exec_Size           execSize,
        VISA_EMask_Ctrl          emask,
        LSC_ADDR_TYPE            addrModel,
        LSC_ADDR_SIZE            addrSize,
        LSC_DATA_SHAPE           dataShape,
        VISA_opnd               *surface,
        VISA_opnd               *dst_data,
        VISA_opnd               *src0_Us,
        VISA_opnd               *src0_Vs,
        VISA_opnd               *src0_Rs,
        VISA_opnd               *src0_LODs,
        VISA_opnd               *src1_data,
        VISA_opnd               *src2_data,
        int                      lineNum);
    bool CISA_create_lsc_fence(
        LSC_SFID                 lscSfid,
        LSC_FENCE_OP             fence,
        LSC_SCOPE                scope,
        int                      lineNum);

    bool CISA_create_fcvt_instruction(
        VISA_EMask_Ctrl emask,
        unsigned exec_size,
        VISA_opnd* dst,
        VISA_opnd* src0,
        int lineNum);

    bool CISA_create_nbarrier(
        bool isWait, VISA_opnd *barrierId, VISA_opnd *threadCount, int lineNum);


private:
    const vISA::PlatformInfo* m_platformInfo;

    vISA::Mem_Manager m_mem;
    const VISA_BUILDER_OPTION mBuildOption;
    // FIXME: we need to make 3D/media per kernel instead of per builder
    const vISABuilderMode m_builderMode;

    unsigned int m_kernel_count = 0;
    unsigned int m_function_count = 0;

    // list of kernels and functions added to this builder
    std::list<VISAKernelImpl *> m_kernelsAndFunctions;
    // for cases of several kernels/functions in one CisaBuilder
    // we need to keep a mapping of kernels to names
    // to make GetVISAKernel() work
    std::map<std::string, VISAKernelImpl *> m_nameToKernel;

    std::map<std::string, vISA::G4_Kernel*> functionsNameMap;
    vISA::G4_Kernel* GetCallerKernel(vISA::G4_INST*);
    vISA::G4_Kernel* GetCalleeKernel(vISA::G4_INST*);

    // To collect call related info for LinkTimeOptimization
    void CollectCallSites(
            std::list<VISAKernelImpl *>& functions,
            std::unordered_map<vISA::G4_Kernel*, std::list<std::list<vISA::G4_INST*>::iterator>>& callSites,
            std::list<std::list<vISA::G4_INST*>::iterator>& sgInvokeList);

    // Sanity check to see if sg.invoke list is properly added from front-end
    // We don't support:
    //   1. sg.invoke callsite is a indirect call
    //   2. sg.invoke callsite is inside a recursion
    void CheckHazardFeatures(
            std::list<std::list<vISA::G4_INST*>::iterator>& sgInvokeList,
            std::unordered_map<vISA::G4_Kernel*, std::list<std::list<vISA::G4_INST*>::iterator>>& callSites);

    // Reset hasStackCalls if all calls in a function are converted to subroutine calls or inlined
    void ResetHasStackCall(
            std::list<std::list<vISA::G4_INST*>::iterator>& sgInvokeList,
            std::unordered_map<vISA::G4_Kernel*, std::list<std::list<vISA::G4_INST*>::iterator>>& callSites);

    // Remove sgInvoke functions out of function list to avoid redundant compilation
    void RemoveOptimizingFunction(
            std::list<VISAKernelImpl *>& functions,
            const std::list<std::list<vISA::G4_INST*>::iterator>& sgInvokeList);

    // Create callee to a set of callsites map
    void ProcessSgInvokeList(
            const std::list<std::list<vISA::G4_INST*>::iterator>& sgInvokeList,
            std::unordered_map<vISA::G4_Kernel*, std::list<std::list<vISA::G4_INST*>::iterator>>& callee2Callers);

    // Perform LinkTimeOptimization for call related transformations
    void LinkTimeOptimization(
            std::unordered_map<vISA::G4_Kernel*, std::list<std::list<vISA::G4_INST*>::iterator>>& callee2Callers,
            uint32_t options);

    void emitFCPatchFile();

    const WA_TABLE *m_pWaTable;
    bool needsToFreeWATable = false;

    void* gtpin_init = nullptr;

    // important messages that we should relay to the user
    // (things like if RA is spilling, etc.)
    std::stringstream criticalMsg;
};

#endif
