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

Copyright (c) 2017 Intel Corporation

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


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

#include "BuildIR.h"
#include "../Timer.h"

//
// convert src into a direct packed region
//
static G4_SrcRegRegion* operandToDirectSrcRegRegion(
    IR_Builder& builder, G4_Operand* src, G4_ExecSize newSize, G4_ExecSize oldSize)
{
    if (src->isSrcRegRegion())
    {
        G4_SrcRegRegion* srcRegion = src->asSrcRegRegion();
        if (srcRegion->getRegAccess() == IndirGRF)
        {
            G4_Declare* dcl = builder.createTempVarWithNoSpill(newSize, src->getType(), Any);
            if (srcRegion->getRegion()->isRegionWH() && newSize > oldSize)
            {
                // for VxH regions we can't directly broadcast if new exec size is wider
                if (oldSize == g4::SIMD1)
                {
                    srcRegion->setRegion(builder.getRegionScalar());
                    builder.createMov(newSize, builder.Create_Dst_Opnd_From_Dcl(dcl, 1), srcRegion,
                        InstOpt_WriteEnable, true);
                }
                else
                {
                    // ToDo: i think this is needed for all regions
                    auto tmpDst = builder.Create_Dst_Opnd_From_Dcl(dcl, 1);
                    builder.createMov(oldSize, tmpDst, src, InstOpt_WriteEnable, true);
                    auto tmpSrc = builder.createSrcRegRegion(Mod_src_undef, Direct, dcl->getRegVar(), 0, 0,
                        builder.createRegionDesc(0, oldSize, 1), src->getType());
                    builder.createMov(newSize, builder.Create_Dst_Opnd_From_Dcl(dcl, 1), tmpSrc,
                        InstOpt_WriteEnable, true);
                }
            }
            else
            {
                builder.Create_MOV_Inst(dcl, 0, 0, newSize, nullptr, nullptr, src, true);
            }
            return builder.Create_Src_Opnd_From_Dcl(dcl, builder.getRegionStride1());
        }
        return src->asSrcRegRegion();
    }
    else
    {
        // src is an immediate
        MUST_BE_TRUE(src->isImm(), "expected an immediate operand");
        G4_Declare *tmpSrc = builder.createTempVarWithNoSpill(newSize, G4_Operand::GetNonVectorImmType(src->getType()), Any);
        builder.Create_MOV_Inst(tmpSrc, 0, 0, newSize, nullptr, nullptr, src, true);
        return builder.Create_Src_Opnd_From_Dcl(tmpSrc, builder.getRegionStride1());
    }
}

void IR_Builder::expandFdiv(
    G4_ExecSize exsize, G4_Predicate *predOpnd, G4_Sat saturate,
    G4_DstRegRegion *dstOpnd, G4_Operand *src0Opnd, G4_Operand *src1Opnd,
    uint32_t instOpt)
{
    // math.fdiv dst src0 src1
    // -->
    // math.inv tmp src1
    // mul dst src0 tmp
    G4_MathOp mathOp = MATH_INV;
    G4_Type invType = src1Opnd->getType();
    if (IS_VFTYPE(invType))
    {
        invType = Type_F;
    }
    G4_Declare* invResult = createTempVar(exsize, invType, Any);
    G4_DstRegRegion* invDst = Create_Dst_Opnd_From_Dcl(invResult, 1);
    createMathInst(predOpnd, g4::NOSAT, exsize, invDst, src1Opnd, createNullSrc(invType), mathOp, instOpt, true);
    G4_SrcRegRegion* invSrc = Create_Src_Opnd_From_Dcl(invResult, getRegionStride1());
    createInst(duplicateOperand(predOpnd), G4_mul, nullptr, saturate, exsize, dstOpnd, src0Opnd, invSrc, instOpt, true);
}

void IR_Builder::expandPow(
    G4_ExecSize exsize, G4_Predicate *predOpnd, G4_Sat saturate,
    G4_DstRegRegion *dstOpnd, G4_Operand *src0Opnd, G4_Operand *src1Opnd,
    uint32_t instOpt)
{
    // math.pow dst src0 src1
    // -->
    // math.log tmp abs(src0)
    // mul dst tmp tmp src1
    // math.exp dst tmp
    G4_Type mathType = G4_Operand::GetNonVectorImmType(src0Opnd->getType());
    G4_Declare* tmpVar = createTempVar(exsize, mathType, Any);
    G4_DstRegRegion* logDst = Create_Dst_Opnd_From_Dcl(tmpVar, 1);
    G4_Operand* logSrc = src0Opnd;
    // make sure log source is positive
    if (src0Opnd->isSrcRegRegion())
    {
        G4_SrcRegRegion* srcRegion = src0Opnd->asSrcRegRegion();
        switch (srcRegion->getModifier())
        {
        case Mod_src_undef:
            srcRegion->setModifier(Mod_Abs);
            break;
        case Mod_Abs:
            // do nothing
            break;
        default:
        {
            G4_Declare* tmpLogSrc = createTempVar(exsize, src0Opnd->getType(), Any);
            Create_MOV_Inst(tmpLogSrc, 0, 0, exsize, nullptr, nullptr, src0Opnd, false, instOpt);
            logSrc = Create_Src_Opnd_From_Dcl(tmpLogSrc, getRegionStride1());
            logSrc->asSrcRegRegion()->setModifier(Mod_Abs);
        }
        }
    }
    else
    {
        switch (src0Opnd->getType())
        {
        case Type_F:
        {
            float val = src0Opnd->asImm()->getFloat();
            if (val < 0)
            {
                logSrc = createImm(std::abs(val));
            }
            break;
        }
        case Type_HF:
        {
            uint16_t val = (uint16_t) src0Opnd->asImm()->getImm();
            if (val & 0x8000)
            {
                logSrc = createImm(val & 0x7FFFF, Type_HF);
            }
            break;
        }
        case Type_VF:
            // ToDo: what if VF contains negative values?
            break;
        default:
            assert(false && "unexpected src0 type for pow");
        }
    }
    createMathInst(predOpnd, g4::NOSAT, exsize,
        logDst, logSrc, createNullSrc(mathType), MATH_LOG, instOpt, true);
    G4_SrcRegRegion* mulSrc = Create_Src_Opnd_From_Dcl(tmpVar, getRegionStride1());
    G4_DstRegRegion* mulDst = Create_Dst_Opnd_From_Dcl(tmpVar, 1);
    createInst(duplicateOperand(predOpnd), G4_mul,
        nullptr, g4::NOSAT, exsize, mulDst, mulSrc, src1Opnd, instOpt, true);
    G4_SrcRegRegion* expSrc = Create_Src_Opnd_From_Dcl(tmpVar, getRegionStride1());
    createMathInst(duplicateOperand(predOpnd), saturate, exsize, dstOpnd, expSrc, createNullSrc(mathType), MATH_EXP, instOpt, true);
}


int IR_Builder::translateVISAArithmeticDoubleInst(
    ISA_Opcode opcode, VISA_Exec_Size executionSize,
    VISA_EMask_Ctrl emask, G4_Predicate *predOpnd, G4_Sat saturate,
    G4_DstRegRegion *dstOpnd, G4_Operand *src0Opnd, G4_Operand *src1Opnd)
{
    TIME_SCOPE(VISA_BUILDER_IR_CONSTRUCTION);

    G4_INST* inst = nullptr;
    G4_ExecSize instExecSize = toExecSize(executionSize);
    G4_ExecSize exsize = g4::SIMD4;
    const RegionDesc *srcRegionDesc = getRegionStride1();
    const RegionDesc *rdAlign16 = getRegionStride1();
    uint8_t element_size;       // element_size is set according to instExecSize
    unsigned int loopCount;

    G4_Imm *dbl_constant_0 = createDFImm(0.0);
    G4_Imm *dbl_constant_1 = createDFImm(1.0);

    if (instExecSize == 1 || instExecSize == 4)
    {
        element_size = 4;
        loopCount = 1;
    }
    else
    {
        element_size = instExecSize;
        exsize = std::min(instExecSize, G4_ExecSize(getFP64MadmExecSize()));
        loopCount = instExecSize / exsize;
    }

    G4_InstOpts instOpt = Get_Gen4_Emask(emask, exsize);

    // pred and conModifier
    G4_Declare *tmpFlag = createTempFlag(1);
    G4_Predicate_Control predCtrlValue = PRED_DEFAULT;

    // temp registers
    G4_Declare *t6  = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t7  = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t8  = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t9  = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t10 = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t11 = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t12 = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t13 = createTempVarWithNoSpill(element_size, Type_DF, Any);

    bool hasDefaultRoundDenorm = getOption(vISA_hasRNEandDenorm);
    // cr0.0 register
    G4_Declare *regCR0 = createTempVarWithNoSpill(1, Type_UD, Any);
    G4_DstRegRegion regDstCR0(Direct, phyregpool.getCr0Reg(), 0, 0, 1, Type_UD);
    G4_SrcRegRegion regSrcCR0(Mod_src_undef, Direct, phyregpool.getCr0Reg() ,0, 0, getRegionScalar(), Type_UD);

    // r0 = 0.0:df, r1 = 1.0:df
    G4_Declare *t0  = getImmDcl(dbl_constant_0, element_size);
    G4_Declare *t1  = getImmDcl(dbl_constant_1, element_size);

    inst = createPseudoKills({ t6, t7, t8, t9, t10, t11, t12, t13, tmpFlag }, PseudoKillType::Src);

    G4_SrcRegRegion tsrc0(Mod_src_undef, Direct, t0->getRegVar(), 0, 0, srcRegionDesc, Type_DF);
    G4_SrcRegRegion tsrc1(Mod_src_undef, Direct, t1->getRegVar(), 0, 0, srcRegionDesc, Type_DF);

    if (!src0Opnd)
    {
        // those are for drcp
        G4_SrcRegRegion valueOneScalarReg(Mod_src_undef, Direct, t1->getRegVar(), 0, 0, getRegionScalar(), Type_DF);
        G4_Operand* valueOneOpnd = createSrcRegRegion(valueOneScalarReg); // it is used in drcp
        src0Opnd = valueOneOpnd;
    }

    bool noDstMove = exsize == 8 && !saturate && !predOpnd && isOpndAligned(dstOpnd, getGRFSize()) &&
        dstOpnd->getRegAccess() == Direct && dstOpnd->getHorzStride() == 1;
    if (noDstMove && (dstOpnd->getTopDcl() == src0Opnd->getTopDcl() || dstOpnd->getTopDcl() == src1Opnd->getTopDcl()))
    {
        noDstMove = false;
    }

    G4_SrcRegRegion* src0RR = operandToDirectSrcRegRegion(*this, src0Opnd, G4_ExecSize(element_size), instExecSize);
    G4_SrcRegRegion* src1RR = operandToDirectSrcRegRegion(*this, src1Opnd, G4_ExecSize(element_size), instExecSize);

    // src operand registers
    G4_DstRegRegion tdst_src0(Direct, t6->getRegVar(), 0, 0, 1, Type_DF);
    G4_DstRegRegion tdst_src1(Direct, t7->getRegVar(), 0, 0, 1, Type_DF);

    bool needsSrc0Move = src0RR->isScalar() || src0RR->getModifier() != Mod_src_undef;
    if (needsSrc0Move)
    {
        if (opcode == ISA_DIV || opcode == ISA_DIVM)
        {
            G4_DstRegRegion *t6_dst_src0_opnd = createDstRegRegion(tdst_src0);
            inst = createMov(G4_ExecSize(element_size), t6_dst_src0_opnd, src0RR,
                instOpt, true); // mov (element_size) t6_dst_src0_opnd, src0RR {Q1/N1}
        }
    }
    bool needsSrc1Move = src1RR->isScalar() || src1RR->getModifier() != Mod_src_undef;
    if (needsSrc1Move)
    {
        G4_DstRegRegion *t7_dst_src1_opnd = createDstRegRegion(tdst_src1);
        inst = createMov(G4_ExecSize(element_size), t7_dst_src1_opnd, src1RR,
            instOpt, true); // mov (element_size) t7_dst_src1_opnd, src1RR {Q1/N1}
    }

    // each madm only handles 4 channel double data
    VISA_EMask_Ctrl currEMask = emask;
    for (uint16_t regIndex = 0; currEMask != vISA_NUM_EMASK && regIndex < loopCount;
        ++regIndex, currEMask = Get_Next_EMask(currEMask, exsize))
    {
        instOpt = Get_Gen4_Emask(currEMask, exsize);
        instOpt |= isNoMask(emask) ? InstOpt_WriteEnable : 0; // setting channels for non-mad insts
        unsigned int madmInstOpt = instOpt; // setting channels for mad insts

        G4_DstRegRegion tdst6(Direct, t6->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst7(Direct, t7->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst8(Direct, noDstMove ? dstOpnd->getBase() : t8->getRegVar(),
            noDstMove ? dstOpnd->getRegOff() + regIndex : regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst9(Direct, t9->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst10(Direct, t10->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst11(Direct, t11->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst12(Direct, t12->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst13(Direct, t13->getRegVar(), regIndex, 0, 1, Type_DF);

        /* below 2 are prepared for G4_math with Align16, so the region 2;2,1 is used not 4;4,1.*/
        G4_SrcRegRegion tsrc6_0(Mod_src_undef, Direct, t6->getRegVar(), regIndex, 0, rdAlign16, Type_DF);
        G4_SrcRegRegion tsrc7_0(Mod_src_undef, Direct, t7->getRegVar(), regIndex, 0, rdAlign16, Type_DF);

        G4_SrcRegRegion tsrc6(Mod_src_undef, Direct, t6->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc7(Mod_src_undef, Direct, t7->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc8(Mod_src_undef, Direct, noDstMove ? dstOpnd->getBase() : t8->getRegVar(),
            noDstMove ? dstOpnd->getRegOff() + regIndex : regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc9(Mod_src_undef, Direct, t9->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc10(Mod_src_undef, Direct, t10->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc11(Mod_src_undef, Direct, t11->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc12(Mod_src_undef, Direct, t12->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc13(Mod_src_undef, Direct, t13->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);

        G4_DstRegRegion *t8DstOpnd0 = createDstRegRegion(tdst8);
        G4_DstRegRegion *t8DstOpnd1 = createDstRegRegion(tdst8);
        G4_DstRegRegion *t8DstOpnd2 = createDstRegRegion(tdst8);
        G4_DstRegRegion *t9DstOpnd0 = createDstRegRegion(tdst9);
        G4_DstRegRegion *t9DstOpnd1 = createDstRegRegion(tdst9);
        G4_DstRegRegion *t10DstOpnd0 = createDstRegRegion(tdst10);
        G4_DstRegRegion *t11DstOpnd0 = createDstRegRegion(tdst11);
        G4_DstRegRegion *t11DstOpnd1 = createDstRegRegion(tdst11);
        G4_DstRegRegion *t12DstOpnd0 = createDstRegRegion(tdst12);
        G4_DstRegRegion *t12DstOpnd1 = createDstRegRegion(tdst12);
        G4_DstRegRegion *t13DstOpnd0 = createDstRegRegion(tdst13);


        // src oprands passed by function calls
        // for INV instruction, src0 should be 1, contant value.
        /* below 2 are prepared for G4_math with Align16, so the region 2;2,1 is used not 4;4,1.*/
        G4_SrcRegRegion fsrc0_0(Mod_src_undef, Direct, src0RR->getBase(), src0RR->getRegOff() + ((opcode == ISA_INV) ? 0 : regIndex), 0, rdAlign16, Type_DF);
        G4_SrcRegRegion fsrc1_0(Mod_src_undef, Direct, src1RR->getBase(), src1RR->getRegOff() + regIndex, 0, rdAlign16, Type_DF);

        G4_SrcRegRegion fsrc0(Mod_src_undef, Direct, src0RR->getBase(), src0RR->getRegOff() + ((opcode == ISA_INV) ? 0 : regIndex), 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion fsrc1(Mod_src_undef, Direct, src1RR->getBase(), src1RR->getRegOff() + regIndex, 0, srcRegionDesc, Type_DF);

        G4_SrcRegRegion *t6SrcOpnd0 = NULL;
        G4_SrcRegRegion *t6SrcOpnd1 = NULL;
        G4_SrcRegRegion *t6SrcOpnd2 = NULL;
        G4_SrcRegRegion *t6SrcOpnd3 = NULL;
        G4_SrcRegRegion *t7SrcOpnd0 = NULL;
        G4_SrcRegRegion *t8SrcOpnd0x0 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t8SrcOpnd0x1 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t8SrcOpnd0x2 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t8SrcOpnd0x3 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t8SrcOpnd0x4 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t8SrcOpnd1 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t9SrcOpnd0x0 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd0x1 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd1x0 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd1x1 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t10SrcOpnd0 = createSrcRegRegion(tsrc10);
        G4_SrcRegRegion *t10SrcOpnd1 = createSrcRegRegion(tsrc10);
        G4_SrcRegRegion *t11SrcOpnd0 = createSrcRegRegion(tsrc11);
        G4_SrcRegRegion *t11SrcOpnd1 = createSrcRegRegion(tsrc11);
        G4_SrcRegRegion *t12SrcOpnd0x0 = createSrcRegRegion(tsrc12);
        G4_SrcRegRegion *t12SrcOpnd0x1 = createSrcRegRegion(tsrc12);
        G4_SrcRegRegion *t12SrcOpnd0x2 = createSrcRegRegion(tsrc12);
        G4_SrcRegRegion *t12SrcOpnd0x3 = createSrcRegRegion(tsrc12);
        G4_SrcRegRegion *t12SrcOpnd1 = createSrcRegRegion(tsrc12);
        G4_SrcRegRegion *t13SrcOpnd0 = createSrcRegRegion(tsrc13);

        if (!hasDefaultRoundDenorm)
        {
            G4_DstRegRegion *cr0DstRegOpndForAndInst = createDstRegRegion(regDstCR0);
            G4_DstRegRegion *cr0DstRegOpndForOrInst = createDstRegRegion(regDstCR0);
            G4_SrcRegRegion *cr0SrcRegOpndForSaveInst = createSrcRegRegion(regSrcCR0);
            G4_SrcRegRegion *cr0SrcRegOpndForAndInst = createSrcRegRegion(regSrcCR0);
            G4_SrcRegRegion *cr0SrcRegOpndForOrInst = createSrcRegRegion(regSrcCR0);
            auto tmpDstRegOpndForCR0 = Create_Dst_Opnd_From_Dcl(regCR0, 1);

            // save cr0.0
            inst = createMov(g4::SIMD1, tmpDstRegOpndForCR0, cr0SrcRegOpndForSaveInst,
                InstOpt_WriteEnable, true);

            // set rounding mod in CR0 to RNE
            inst = createBinOp(G4_and, g4::SIMD1, cr0DstRegOpndForAndInst, cr0SrcRegOpndForAndInst,
                createImm(0xffffffcf, Type_UD), InstOpt_WriteEnable, true);

            // set double precision denorm mode to 1
            inst = createBinOp(G4_or, g4::SIMD1, cr0DstRegOpndForOrInst, cr0SrcRegOpndForOrInst,
                createImm(0x40, Type_UD), InstOpt_WriteEnable, true);
        }

        if (needsSrc0Move)
        {
            if (opcode == ISA_INV)
            {
                t6SrcOpnd0 = createSrcRegRegion(fsrc0_0);
                t6SrcOpnd1 = createSrcRegRegion(fsrc0);
                t6SrcOpnd2 = createSrcRegRegion(fsrc0);
                t6SrcOpnd3 = createSrcRegRegion(fsrc0);
            }
            else
            {
                t6SrcOpnd0 = createSrcRegRegion(tsrc6_0);
                t6SrcOpnd1 = createSrcRegRegion(tsrc6);
                t6SrcOpnd2 = createSrcRegRegion(tsrc6);
                t6SrcOpnd3 = createSrcRegRegion(tsrc6);
            }
        }
        else
        {
            t6SrcOpnd0 = createSrcRegRegion(fsrc0_0);
            t6SrcOpnd1 = createSrcRegRegion(fsrc0);
            t6SrcOpnd2 = createSrcRegRegion(fsrc0);
            t6SrcOpnd3 = createSrcRegRegion(fsrc0);
        }

        if (needsSrc1Move)
        {
            t7SrcOpnd0 = createSrcRegRegion(tsrc7_0);
        }
        else
        {
            t7SrcOpnd0 = createSrcRegRegion(fsrc1_0);
        }

        // create -r7.noacc
        G4_SrcRegRegion tsrc7_neg(Mod_Minus,
            t7SrcOpnd0->getRegAccess(),
            t7SrcOpnd0->getBase(),
            t7SrcOpnd0->getRegOff(),
            t7SrcOpnd0->getSubRegOff(),
            t7SrcOpnd0->getRegion(),
            t7SrcOpnd0->getType());
        G4_SrcRegRegion *t7SrcOpndNeg0 = createSrcRegRegion(tsrc7_neg);
        G4_SrcRegRegion *t7SrcOpndNeg1 = createSrcRegRegion(tsrc7_neg);
        G4_SrcRegRegion *t7SrcOpndNeg2 = createSrcRegRegion(tsrc7_neg);
        G4_SrcRegRegion *t7SrcOpndNeg3 = createSrcRegRegion(tsrc7_neg);

        // math.e0.f0.0 (4) r8.acc2 r6.noacc r7.noacc 0xe {Align16, N1/N2}
        t8DstOpnd0->setAccRegSel(ACC2);
        t6SrcOpnd0->setAccRegSel(NOACC);
        t7SrcOpnd0->setAccRegSel(NOACC);
        inst = createMathInst(NULL, g4::NOSAT, exsize, t8DstOpnd0, t6SrcOpnd0,
            t7SrcOpnd0, MATH_INVM, madmInstOpt, true);
        G4_CondMod *condModOverflow = createCondMod(Mod_o, tmpFlag->getRegVar(), 0);
        inst->setCondMod(condModOverflow);

        bool generateIf = true;

        if (generateIf)
        {
            // if
            G4_Predicate *predicateFlagReg = createPredicate(PredState_Minus, tmpFlag->getRegVar(), 0, predCtrlValue);
            inst = createIf(predicateFlagReg, exsize, instOpt);
        }
        {
            // madm (4) r9.acc3 r0.noacc r6.noacc r8.acc2 {Align16, N1/N2}
            G4_SrcRegRegion *t0SrcOpnd = createSrcRegRegion(tsrc0);
            t9DstOpnd0->setAccRegSel(ACC3);
            t0SrcOpnd->setAccRegSel(NOACC);
            t6SrcOpnd1->setAccRegSel(NOACC);
            t8SrcOpnd0x0->setAccRegSel(ACC2);
            inst = createMadm(exsize,
                t9DstOpnd0, t0SrcOpnd,
                t6SrcOpnd1, t8SrcOpnd0x0, madmInstOpt);

            // madm (4) r10.acc4 r1.noacc -r7.noacc r8.acc2 {Align16, N1/N2}
            G4_SrcRegRegion *t1SrcOpnd0 = createSrcRegRegion(tsrc1);
            t10DstOpnd0->setAccRegSel(ACC4);
            t1SrcOpnd0->setAccRegSel(NOACC);
            t7SrcOpndNeg0->setAccRegSel(NOACC);
            t8SrcOpnd0x1->setAccRegSel(ACC2);
            inst = createMadm(exsize,
                t10DstOpnd0, t1SrcOpnd0,
                t7SrcOpndNeg0, t8SrcOpnd0x1, madmInstOpt);

            // madm (4) r11.acc5 r6.noacc -r7.noacc r9.acc3 {Align16, N1/N2}
            t11DstOpnd0->setAccRegSel(ACC5);
            t6SrcOpnd2->setAccRegSel(NOACC);
            t7SrcOpndNeg1->setAccRegSel(NOACC);
            t9SrcOpnd0x0->setAccRegSel(ACC3);
            inst = createMadm(exsize,
                t11DstOpnd0, t6SrcOpnd2,
                t7SrcOpndNeg1, t9SrcOpnd0x0, madmInstOpt);

            // madm (4) r12.acc6 r8.acc2 r10.acc4 r8.acc2 {Align16, N1/N2}
            t12DstOpnd0->setAccRegSel(ACC6);
            t8SrcOpnd0x2->setAccRegSel(ACC2);
            t10SrcOpnd0->setAccRegSel(ACC4);
            t8SrcOpnd0x3->setAccRegSel(ACC2);
            inst = createMadm(exsize,
                t12DstOpnd0, t8SrcOpnd0x2,
                t10SrcOpnd0, t8SrcOpnd0x3, madmInstOpt);

            // madm (4) r13.acc7 r1.noacc -r7.noacc r12.acc6 {Align16, N1/N2}
            G4_SrcRegRegion *t1SrcOpnd1 = createSrcRegRegion(tsrc1);
            t13DstOpnd0->setAccRegSel(ACC7);
            t1SrcOpnd1->setAccRegSel(NOACC);
            t7SrcOpndNeg2->setAccRegSel(NOACC);
            t12SrcOpnd0x0->setAccRegSel(ACC6);
            inst = createMadm(exsize,
                t13DstOpnd0, t1SrcOpnd1,
                t7SrcOpndNeg2, t12SrcOpnd0x0, madmInstOpt);

            // madm (4) r8.acc8 r8.acc2 r10.acc4 r12.acc6 {Align16, N1/N2}
            t8DstOpnd1->setAccRegSel(ACC8);
            t8SrcOpnd0x4->setAccRegSel(ACC2);
            t10SrcOpnd1->setAccRegSel(ACC4);
            t12SrcOpnd0x1->setAccRegSel(ACC6);
            inst = createMadm(exsize,
                t8DstOpnd1, t8SrcOpnd0x4,
                t10SrcOpnd1, t12SrcOpnd0x1, madmInstOpt);

            // madm (4) r9.acc9 r9.acc3 r11.acc5 r12.acc6 {Align16, N1/N2}
            t9DstOpnd1->setAccRegSel(ACC9);
            t9SrcOpnd0x1->setAccRegSel(ACC3);
            t11SrcOpnd0->setAccRegSel(ACC5);
            t12SrcOpnd0x2->setAccRegSel(ACC6);
            inst = createMadm(exsize,
                t9DstOpnd1, t9SrcOpnd0x1,
                t11SrcOpnd0, t12SrcOpnd0x2, madmInstOpt);

            // madm (4) r12.acc2 r12.acc6 r8.acc8 r13.acc7 {Align16, N1/N2}
            t12DstOpnd1->setAccRegSel(ACC2);
            t12SrcOpnd0x3->setAccRegSel(ACC6);
            t8SrcOpnd1->setAccRegSel(ACC8);
            t13SrcOpnd0->setAccRegSel(ACC7);
            inst = createMadm(exsize, t12DstOpnd1, t12SrcOpnd0x3,
                t8SrcOpnd1, t13SrcOpnd0, madmInstOpt);

            // madm (4) r11.acc3 r6.noacc -r7.noacc r9.acc9 {Align16, N1/N2}
            t11DstOpnd1->setAccRegSel(ACC3);
            t6SrcOpnd3->setAccRegSel(NOACC);
            t7SrcOpndNeg3->setAccRegSel(NOACC);
            t9SrcOpnd1x0->setAccRegSel(ACC9);
            inst = createMadm(exsize, t11DstOpnd1, t6SrcOpnd3,
                t7SrcOpndNeg3, t9SrcOpnd1x0, madmInstOpt);

            if (!hasDefaultRoundDenorm)
            {
                G4_DstRegRegion *cr0DstRegOpndForRestoreIfInst = createDstRegRegion(regDstCR0);
                auto tmpSrcOpndForCR0OnIf = Create_Src_Opnd_From_Dcl(regCR0, getRegionScalar());
                // restore cr0.0
                inst = createMov(g4::SIMD1, cr0DstRegOpndForRestoreIfInst, tmpSrcOpndForCR0OnIf,
                    InstOpt_WriteEnable, true);
            }

            // madm (4) r8.noacc r9.acc9 r11.acc3 r12.acc2 {Align16, N1/N2}
            t8DstOpnd2->setAccRegSel(NOACC);
            t9SrcOpnd1x1->setAccRegSel(ACC9);
            t11SrcOpnd1->setAccRegSel(ACC3);
            t12SrcOpnd1->setAccRegSel(ACC2);
            inst = createMadm(exsize,
                t8DstOpnd2, t9SrcOpnd1x1,
                t11SrcOpnd1, t12SrcOpnd1, madmInstOpt);
        }

        if (generateIf && !hasDefaultRoundDenorm)
        {
            // else (8) {Q1/Q2}
            inst = createElse(exsize, instOpt);

            // restore cr0.0 {NoMask}
            G4_DstRegRegion *cr0DstRegOpndForRestoreElseInst = createDstRegRegion(regDstCR0);
            auto tmpSrcOpndForCR0OnElse = Create_Src_Opnd_From_Dcl(regCR0, getRegionScalar());
            inst = createMov(g4::SIMD1, cr0DstRegOpndForRestoreElseInst, tmpSrcOpndForCR0OnElse,
                InstOpt_WriteEnable, true);
        }

        if (generateIf)
        {
            // endif (8) {Q1/Q2}
            inst = createEndif(exsize, instOpt);
        }
    }; //for loop

    if (!noDstMove)
    {
        // make final copy to dst
        // dst = r8:df     mov (instExecSize) dstOpnd, t8_src_opnd_final {Q1/N1}
        // final result is at r8.noacc
        G4_SrcRegRegion tsrc8_final(Mod_src_undef, Direct, t8->getRegVar(), 0, 0, getRegionStride1(), Type_DF);
        G4_SrcRegRegion *t8_src_opnd_final = createSrcRegRegion(tsrc8_final);
        t8_src_opnd_final->setAccRegSel(ACC_UNDEFINED);
        inst = createInst(
            predOpnd, G4_mov, nullptr, saturate, instExecSize,
            dstOpnd, t8_src_opnd_final, NULL,
            Get_Gen4_Emask(emask, instExecSize), true);
    }

    return VISA_SUCCESS;
}

int IR_Builder::translateVISAArithmeticSingleDivideIEEEInst(
    ISA_Opcode opcode, VISA_Exec_Size executionSize,
    VISA_EMask_Ctrl emask, G4_Predicate *predOpnd,
    G4_Sat saturate, G4_CondMod* condMod,
    G4_DstRegRegion *dstOpnd, G4_Operand *src0Opnd, G4_Operand *src1Opnd)
{
    TIME_SCOPE(VISA_BUILDER_IR_CONSTRUCTION);

    G4_INST* inst;
    G4_ExecSize instExecSize = toExecSize(executionSize);
    uint8_t element_size = 8; // element_size is changed according to insstExecSize
    G4_ExecSize exsize = getNativeExecSize(); // exsize is a constant and never changed
    unsigned int loopCount = 1;
    G4_InstOpts instOpt = Get_Gen4_Emask(emask, exsize); // for those execution size: element_size before the loop
    G4_InstOpts madmInstOpt = Get_Gen4_Emask(emask, exsize); // only used in the loop
    const RegionDesc *srcRegionDesc = getRegionStride1();

    G4_Imm *flt_constant_0 = createImm(float(0.0));
    G4_Imm *flt_constant_1 = createImm(float(1.0));
    if (instExecSize <= exsize)
    {
        element_size = exsize;
        loopCount = 1;
    }
    else
    {
        element_size = instExecSize;
        instOpt = Get_Gen4_Emask(emask, instExecSize);
        loopCount = instExecSize / exsize;
    }

    // pred and conModifier
    G4_Declare *tmpFlag = createTempFlag(1);
    G4_Predicate_Control predCtrlValue = PRED_DEFAULT;

    // temp registers
    G4_Declare *t1  = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t4  = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t6  = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t8  = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t9  = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t10 = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t11 = createTempVarWithNoSpill(element_size, Type_F, Any);

    // cr0.0 register
    G4_Declare *regCR0  = createTempVarWithNoSpill(1, Type_UD, Any);

    // 0.0:f and 1.0:f constants
    G4_Declare *t2 = getImmDcl(flt_constant_0, exsize);
    G4_Declare *t5 = getImmDcl(flt_constant_1, exsize);

    inst = createPseudoKills({ t1, t4, t6, t8, t9, t10, t11, tmpFlag }, PseudoKillType::Src);

    // those are for drcp
    G4_SrcRegRegion valueOneScalarReg(Mod_src_undef, Direct, t2->getRegVar(), 0, 0, getRegionScalar(), Type_F);
    G4_Operand *valueOneOpnd = createSrcRegRegion(valueOneScalarReg); // it is used in drcp

    if (src0Opnd == NULL)
    {
        src0Opnd = valueOneOpnd;
    }

    G4_SrcRegRegion* src0RR = operandToDirectSrcRegRegion(*this, src0Opnd, G4_ExecSize(element_size), instExecSize);
    G4_SrcRegRegion* src1RR = operandToDirectSrcRegRegion(*this, src1Opnd, G4_ExecSize(element_size), instExecSize);

    if (src0RR->isScalar() || src0RR->getModifier() != Mod_src_undef)
    {
        G4_DstRegRegion *tmp = Create_Dst_Opnd_From_Dcl(t6, 1);
        inst = createMov(G4_ExecSize(element_size), tmp, src0RR,
            instOpt, true); // mov (element_size) t6, src0RR {Q1/H1}
        src0RR = Create_Src_Opnd_From_Dcl(t6, getRegionStride1());
    }
    if (src1RR->isScalar() || src1RR->getModifier() != Mod_src_undef)
    {
        G4_DstRegRegion *tmp = Create_Dst_Opnd_From_Dcl(t4, 1);
        inst = createMov(G4_ExecSize(element_size), tmp, src1RR,
            instOpt, true); // mov (element_size) t4, src1RR {Q1/H1}
        src1RR = Create_Src_Opnd_From_Dcl(t4, getRegionStride1());
    }

    // cr0.0 register
    bool hasDefaultRoundDenorm = getOption(vISA_hasRNEandDenorm);
    G4_DstRegRegion regDstCR0(Direct, phyregpool.getCr0Reg(), 0, 0, 1, Type_UD);
    G4_SrcRegRegion regSrcCR0(Mod_src_undef, Direct, phyregpool.getCr0Reg(), 0, 0, getRegionScalar(), Type_UD);

    // t2 and t5 are constants
    G4_SrcRegRegion tsrc2(Mod_src_undef, Direct, t2->getRegVar(), 0, 0, srcRegionDesc, Type_F);
    G4_SrcRegRegion tsrc5(Mod_src_undef, Direct, t5->getRegVar(), 0, 0, srcRegionDesc, Type_F);

    G4_SrcRegRegion tsrc8_final(Mod_src_undef, Direct, t8->getRegVar(), 0, 0,
        getRegionStride1(), t8->getElemType());
    G4_SrcRegRegion *t8_src_opnd_final = createSrcRegRegion(tsrc8_final);

    VISA_EMask_Ctrl currEMask = emask;
    for (uint16_t regIndex = 0; currEMask != vISA_NUM_EMASK && regIndex < loopCount;
        ++regIndex, currEMask = Get_Next_EMask(currEMask, exsize))
    {
        // set Q1 for insts within the 1st loop and Q2 for the 2nd, if inside SIMD CF
        instOpt = Get_Gen4_Emask(currEMask, exsize);
        instOpt |= isNoMask(emask) ? InstOpt_WriteEnable : 0; // setting channels for non-mad insts
        madmInstOpt = instOpt; // setting channels for mad insts

                               //1, 6, 8, 9, 10, 11
        G4_DstRegRegion tdst1(Direct, t1->getRegVar(), regIndex, 0, 1, Type_F);
        G4_DstRegRegion tdst6(Direct, t6->getRegVar(), regIndex, 0, 1, Type_F);
        G4_DstRegRegion tdst8(Direct, t8->getRegVar(), regIndex, 0, 1, Type_F);
        G4_DstRegRegion tdst9(Direct, t9->getRegVar(), regIndex, 0, 1, Type_F);
        G4_DstRegRegion tdst10(Direct, t10->getRegVar(), regIndex, 0, 1, Type_F);
        G4_DstRegRegion tdst11(Direct, t11->getRegVar(), regIndex, 0, 1, Type_F);

        G4_SrcRegRegion tsrc1(Mod_src_undef, Direct, t1->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc4(Mod_src_undef, Direct, t4->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc6(Mod_src_undef, Direct, t6->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc8(Mod_src_undef, Direct, t8->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc9(Mod_src_undef, Direct, t9->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc10(Mod_src_undef, Direct, t10->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc11(Mod_src_undef, Direct, t11->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);

        G4_DstRegRegion *t8DstOpnd0 = createDstRegRegion(tdst8);
        G4_DstRegRegion *t9DstOpnd0 = createDstRegRegion(tdst9);
        G4_DstRegRegion *t10DstOpnd0 = createDstRegRegion(tdst10);
        G4_DstRegRegion *t1DstOpnd0 = createDstRegRegion(tdst1);
        G4_DstRegRegion *t11DstOpnd0 = createDstRegRegion(tdst11);
        G4_DstRegRegion *t9DstOpnd1 = createDstRegRegion(tdst9);
        G4_DstRegRegion *t6DstOpnd0 = createDstRegRegion(tdst6);
        G4_DstRegRegion *t8DstOpnd1 = createDstRegRegion(tdst8);

        // src oprands passed by function calls
        G4_SrcRegRegion fsrc0(Mod_src_undef, Direct, src0RR->getBase(), src0RR->getRegOff() + regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion fsrc1(Mod_src_undef, Direct, src1RR->getBase(), src1RR->getRegOff() + regIndex, 0, srcRegionDesc, Type_F);

        G4_SrcRegRegion *t4SrcOpnd0 = NULL;
        G4_SrcRegRegion *t6SrcOpnd0 = NULL;
        G4_SrcRegRegion *t6SrcOpnd1 = NULL;
        G4_SrcRegRegion *t6SrcOpnd2 = NULL;
        G4_SrcRegRegion *t6SrcOpnd3 = NULL;

        G4_SrcRegRegion *t1SrcOpnd0 = createSrcRegRegion(tsrc1);
        G4_SrcRegRegion *t1SrcOpnd1 = createSrcRegRegion(tsrc1);
        G4_SrcRegRegion *t6SrcOpnd4 = createSrcRegRegion(tsrc6);
        G4_SrcRegRegion *t8SrcOpnd0x0 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t8SrcOpnd0x1 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t8SrcOpnd0x2 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t8SrcOpnd0x3 = createSrcRegRegion(tsrc8);
        G4_SrcRegRegion *t9SrcOpnd0x0 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd0x1 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd1x0 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd1x1 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t10SrcOpnd0 = createSrcRegRegion(tsrc10);
        G4_SrcRegRegion *t11SrcOpnd0 = createSrcRegRegion(tsrc11);

        if (!hasDefaultRoundDenorm)
        {
            G4_DstRegRegion *cr0DstRegOpndForAndInst = createDstRegRegion(regDstCR0);
            G4_SrcRegRegion *cr0SrcRegOpndForSaveInst = createSrcRegRegion(regSrcCR0);
            G4_SrcRegRegion *cr0SrcRegOpndForAndInst = createSrcRegRegion(regSrcCR0);

            // save cr0.0: mov (1) r116.2<1>:ud cr0.0<0;1,0>:ud {NoMask}
            inst = createMov(g4::SIMD1, Create_Dst_Opnd_From_Dcl(regCR0, 1),
                cr0SrcRegOpndForSaveInst, InstOpt_WriteEnable, true);

            // set rounding mod in CR0 to RNE: and (1) cr0.0<1>:ud cr0.0<0;1,0>:ud 0xffffffcf:ud {NoMask}
            inst = createInst(NULL, G4_and, NULL, g4::NOSAT, g4::SIMD1,
                cr0DstRegOpndForAndInst, cr0SrcRegOpndForAndInst,
                createImm(0xffffffcf, Type_UD), InstOpt_WriteEnable, true);
            // set single denorm to 1: (W) or (1|M0) cr0.0<1>:ud cr0.0<0;1,0>:ud 0x80:ud
            inst = createInst(nullptr, G4_or, nullptr, g4::NOSAT, g4::SIMD1,
                createDstRegRegion(regDstCR0),
                createSrcRegRegion(regSrcCR0),
                createImm(0x80, Type_UW),
                InstOpt_WriteEnable, true);
        }

        t6SrcOpnd0 = createSrcRegRegion(fsrc0);
        t6SrcOpnd1 = createSrcRegRegion(fsrc0);
        t6SrcOpnd2 = createSrcRegRegion(fsrc0);
        t6SrcOpnd3 = createSrcRegRegion(fsrc0);

        t4SrcOpnd0 = createSrcRegRegion(fsrc1);


        // create -r4.noacc
        G4_SrcRegRegion tsrc4_neg(Mod_Minus,
            t4SrcOpnd0->getRegAccess(),
            t4SrcOpnd0->getBase(),
            t4SrcOpnd0->getRegOff(),
            t4SrcOpnd0->getSubRegOff(),
            t4SrcOpnd0->getRegion(),
            t4SrcOpnd0->getType());
        G4_SrcRegRegion *t4SrcOpndNeg0 = createSrcRegRegion(tsrc4_neg);
        G4_SrcRegRegion *t4SrcOpndNeg1 = createSrcRegRegion(tsrc4_neg);
        G4_SrcRegRegion *t4SrcOpndNeg2 = createSrcRegRegion(tsrc4_neg);

        // math.e0.f0.0 (8) r8.acc2 r6.noacc r4.noacc 0xe {Align16, Q1/Q2}
        t8DstOpnd0->setAccRegSel(ACC2);
        t6SrcOpnd0->setAccRegSel(NOACC);
        t4SrcOpnd0->setAccRegSel(NOACC);
        inst = createMathInst(nullptr, g4::NOSAT, exsize,
            t8DstOpnd0, t6SrcOpnd0,
            t4SrcOpnd0, MATH_INVM, madmInstOpt, true);
        G4_CondMod *condModOverflow = createCondMod(Mod_o, tmpFlag->getRegVar(), 0);
        inst->setCondMod(condModOverflow);

        // (-f0.1) if (8) k0__AUTO_GENERATED_IF_LABEL__0 k0__AUTO_GENERATED_ELSE_LABEL__1 {Q1/Q2}
        G4_Predicate *predicateFlagReg = createPredicate(PredState_Minus, tmpFlag->getRegVar(), 0, predCtrlValue);
        inst = createIf(predicateFlagReg, exsize, instOpt);

        // madm (8) r9.acc3 r2.noacc r6.noacc r8.acc2 {Align16, Q1/Q2}
        G4_SrcRegRegion *t2SrcOpnd = createSrcRegRegion(tsrc2);
        t9DstOpnd0->setAccRegSel(ACC3);
        t2SrcOpnd->setAccRegSel(NOACC);
        t6SrcOpnd1->setAccRegSel(NOACC);
        t8SrcOpnd0x0->setAccRegSel(ACC2);
        inst = createMadm(exsize,
            t9DstOpnd0, t2SrcOpnd,
            t6SrcOpnd1, t8SrcOpnd0x0, madmInstOpt);

        // madm (8) r10.acc4 r5.noacc -r4.noacc r8.acc2 {Align16, Q1/Q2}
        G4_SrcRegRegion *t5SrcOpnd0 = createSrcRegRegion(tsrc5);
        t10DstOpnd0->setAccRegSel(ACC4);
        t5SrcOpnd0->setAccRegSel(NOACC);
        t4SrcOpndNeg0->setAccRegSel(NOACC);
        t8SrcOpnd0x1->setAccRegSel(ACC2);
        inst = createMadm(exsize,
            t10DstOpnd0, t5SrcOpnd0,
            t4SrcOpndNeg0, t8SrcOpnd0x1, madmInstOpt);

        // madm (8) r1.acc5 r8.acc2 r10.acc4 r8.acc2 {Align16, Q1/Q2}
        t1DstOpnd0->setAccRegSel(ACC5);
        t8SrcOpnd0x2->setAccRegSel(ACC2);
        t10SrcOpnd0->setAccRegSel(ACC4);
        t8SrcOpnd0x3->setAccRegSel(ACC2);
        inst = createMadm(exsize,
            t1DstOpnd0, t8SrcOpnd0x2,
            t10SrcOpnd0, t8SrcOpnd0x3, madmInstOpt);


        // madm (8) r11.acc6 r6.noacc -r4.noacc r9.acc3 {Align16, Q1/Q2}
        t11DstOpnd0->setAccRegSel(ACC6);
        t6SrcOpnd2->setAccRegSel(NOACC);
        t4SrcOpndNeg1->setAccRegSel(NOACC);
        t9SrcOpnd0x0->setAccRegSel(ACC3);
        inst = createMadm(exsize,
            t11DstOpnd0, t6SrcOpnd2,
            t4SrcOpndNeg1, t9SrcOpnd0x0, madmInstOpt);


        // madm (8) r9.acc7 r9.acc3 r11.acc6 r1.acc5 {Align16, Q1/Q2}
        t9DstOpnd1->setAccRegSel(ACC7);
        t9SrcOpnd0x1->setAccRegSel(ACC3);
        t11SrcOpnd0->setAccRegSel(ACC6);
        t1SrcOpnd0->setAccRegSel(ACC5);
        inst = createMadm(exsize,
            t9DstOpnd1, t9SrcOpnd0x1,
            t11SrcOpnd0, t1SrcOpnd0, madmInstOpt);


        // madm (8) r6.acc8 r6.noacc -r4.noacc r9.acc7 {Align16, Q1/Q2}
        t6DstOpnd0->setAccRegSel(ACC8);
        t6SrcOpnd3->setAccRegSel(NOACC);
        t4SrcOpndNeg2->setAccRegSel(NOACC);
        t9SrcOpnd1x0->setAccRegSel(ACC7);
        inst = createMadm(exsize,
            t6DstOpnd0, t6SrcOpnd3,
            t4SrcOpndNeg2, t9SrcOpnd1x0, madmInstOpt);

        if (!hasDefaultRoundDenorm)
        {
            // restore cr0.0: mov (1) cr0.0<1>:ud r116.1<0;1,0>:ud {NoMask}
            inst = createMov(g4::SIMD1, createDstRegRegion(regDstCR0),
                Create_Src_Opnd_From_Dcl(regCR0, getRegionScalar()), InstOpt_WriteEnable, true);
        }

        // madm (8) r8.noacc r9.acc7 r6.acc8 r1.acc5 {Align16, Q1/Q2}
        t8DstOpnd1->setAccRegSel(NOACC);
        t9SrcOpnd1x1->setAccRegSel(ACC7);
        t6SrcOpnd4->setAccRegSel(ACC8);
        t1SrcOpnd1->setAccRegSel(ACC5);
        inst = createMadm(exsize,
            t8DstOpnd1, t9SrcOpnd1x1,
            t6SrcOpnd4, t1SrcOpnd1, madmInstOpt);

        if (!hasDefaultRoundDenorm)
        {
            // else (8) k0__AUTO_GENERATED_ELSE_LABEL__1 k0__AUTO_GENERATED_ELSE_LABEL__1 {Q1/Q2}
            inst = createElse(exsize, instOpt);

            // restore cr0.0: mov (1) cr0.0<1>:ud r116.2<0;1,0>:ud {NoMask}
            inst = createMov(g4::SIMD1, createDstRegRegion(regDstCR0),
                Create_Src_Opnd_From_Dcl(regCR0, getRegionScalar()), InstOpt_WriteEnable, true);
        }

        // endif (8) {Q1/Q2}
        inst = createEndif(exsize, instOpt);
    };

    // make final copy to dst
    // dst = r8:f  mov (instExecSize) r20.0<1>:f r110.0<8;8,1>:f {Q1/H1}
    t8_src_opnd_final->setAccRegSel(ACC_UNDEFINED);
    inst = createInst(predOpnd, G4_mov, condMod, saturate, instExecSize, dstOpnd, t8_src_opnd_final,
        NULL, Get_Gen4_Emask(emask, instExecSize), true);

    return VISA_SUCCESS;
}

int IR_Builder::translateVISAArithmeticSingleSQRTIEEEInst(
    ISA_Opcode opcode, VISA_Exec_Size executionSize,
    VISA_EMask_Ctrl emask, G4_Predicate *predOpnd,
    G4_Sat saturate, G4_CondMod* condMod, G4_DstRegRegion *dstOpnd, G4_Operand *src0Opnd)
{
    TIME_SCOPE(VISA_BUILDER_IR_CONSTRUCTION);

    G4_INST* inst;
    unsigned madmInstOpt = 0;
    G4_ExecSize instExecSize = toExecSize(executionSize);
    G4_ExecSize element_size = g4::SIMD8; // element_size is dynamic, changed according to instExecSize
    const G4_ExecSize exsize = getNativeExecSize();
    unsigned int loopCount = 1;
    G4_InstOpts instOpt = Get_Gen4_Emask(emask, exsize); // for those insts of execution size of element_size
    const RegionDesc *srcRegionDesc = getRegionStride1();

    G4_Imm *flt_constant_0 = createImm(float(0.0));
    G4_Imm *flt_constant_05 = createImm(float(0.5));
    if (instExecSize <= exsize)
    {
        element_size = exsize;
        loopCount = 1;
    }
    else
    {
        element_size = instExecSize;
        instOpt = Get_Gen4_Emask(emask, instExecSize);
        loopCount = instExecSize / exsize;
    }

    // pred and conModifier
    G4_Declare *tmpFlag = createTempFlag(instExecSize == 32 ? 2 : 1);
    G4_Predicate_Control predCtrlValue = PRED_DEFAULT;

    // temp registers
    G4_Declare *t6  = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t7  = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t9  = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t10 = createTempVarWithNoSpill(element_size, Type_F, Any);
    G4_Declare *t11 = createTempVarWithNoSpill(element_size, Type_F, Any);

    // cr0.0 register
    G4_Declare *regCR0  = createTempVarWithNoSpill(1, Type_UD, Any);

    // 0.0:f and 0.5:f constants
    G4_Declare* t0 = getImmDcl(flt_constant_0, exsize);
    G4_Declare *t8 = getImmDcl(flt_constant_05, exsize);

    inst = createPseudoKills ({ t6, t7, t9, t10, t11, tmpFlag }, PseudoKillType::Src);

    G4_SrcRegRegion* src0RR = operandToDirectSrcRegRegion(*this, src0Opnd, element_size, instExecSize);

    if (src0RR->isScalar() || src0RR->getModifier() != Mod_src_undef)
    {
        // expand src0 to vector src
        G4_DstRegRegion *t6_dst_src0_opnd = Create_Dst_Opnd_From_Dcl(t6, 1);
        inst = createMov(element_size, t6_dst_src0_opnd, src0RR,
            instOpt, true); // mov (element_size) t6, src0RR {Q1/H1}

        src0RR = Create_Src_Opnd_From_Dcl(t6, getRegionStride1());
    }

    // cr0.0 register
    bool hasDefaultRoundDenorm = getOption(vISA_hasRNEandDenorm);
    G4_DstRegRegion regDstCR0(Direct, phyregpool.getCr0Reg(), 0, 0, 1, Type_UD);
    G4_SrcRegRegion regSrcCR0(Mod_src_undef, Direct, phyregpool.getCr0Reg(), 0, 0, getRegionScalar(), Type_UD);

    G4_SrcRegRegion tsrc0(Mod_src_undef, Direct, t0->getRegVar(), 0, 0, srcRegionDesc, Type_F);
    G4_SrcRegRegion tsrc8(Mod_src_undef, Direct, t8->getRegVar(), 0, 0, srcRegionDesc, Type_F);


    G4_SrcRegRegion tsrc7_final(Mod_src_undef, Direct, t7->getRegVar(), 0, 0,
        getRegionStride1(), t7->getElemType());
    G4_SrcRegRegion *t7_src_opnd_final = createSrcRegRegion(tsrc7_final);

    VISA_EMask_Ctrl currEMask = emask;
    for (uint16_t regIndex = 0; currEMask != vISA_NUM_EMASK && regIndex < loopCount;
        ++regIndex, currEMask = Get_Next_EMask(currEMask, exsize))
    {
        instOpt = Get_Gen4_Emask(currEMask, exsize);
        instOpt |= isNoMask(emask) ? InstOpt_WriteEnable : 0;
        madmInstOpt = instOpt;

        //7, 9, 10, 11
        G4_DstRegRegion tdst7(Direct, t7->getRegVar(), regIndex, 0, 1, Type_F);
        G4_DstRegRegion tdst9(Direct, t9->getRegVar(), regIndex, 0, 1, Type_F);
        G4_DstRegRegion tdst10(Direct, t10->getRegVar(), regIndex, 0, 1, Type_F);
        G4_DstRegRegion tdst11(Direct, t11->getRegVar(), regIndex, 0, 1, Type_F);

        G4_SrcRegRegion tsrc7(Mod_src_undef, Direct, t7->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc9(Mod_src_undef, Direct, t9->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc10(Mod_src_undef, Direct, t10->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);
        G4_SrcRegRegion tsrc11(Mod_src_undef, Direct, t11->getRegVar(), regIndex, 0, srcRegionDesc, Type_F);

        G4_DstRegRegion *t7DstOpnd0 = createDstRegRegion(tdst7);
        G4_DstRegRegion *t7DstOpnd1 = createDstRegRegion(tdst7);
        G4_DstRegRegion *t7DstOpnd2 = createDstRegRegion(tdst7);
        G4_DstRegRegion *t9DstOpnd0 = createDstRegRegion(tdst9);
        G4_DstRegRegion *t9DstOpnd1 = createDstRegRegion(tdst9);
        G4_DstRegRegion *t10DstOpnd0 = createDstRegRegion(tdst10);
        G4_DstRegRegion *t10DstOpnd1 = createDstRegRegion(tdst10);
        G4_DstRegRegion *t11DstOpnd0 = createDstRegRegion(tdst11);

        // src oprands passed by function calls
        G4_SrcRegRegion fsrc0(Mod_src_undef, Direct, src0RR->getBase(), src0RR->getRegOff() + regIndex, 0, srcRegionDesc, Type_F);

        G4_SrcRegRegion *t6SrcOpnd0 = NULL;
        G4_SrcRegRegion *t6SrcOpnd1 = NULL;
        G4_SrcRegRegion *t6SrcOpnd2 = NULL;

        G4_SrcRegRegion *t7SrcOpnd0 = createSrcRegRegion(tsrc7);
        G4_SrcRegRegion *t7SrcOpnd1 = createSrcRegRegion(tsrc7);
        G4_SrcRegRegion *t7SrcOpnd2x0 = createSrcRegRegion(tsrc7);
        G4_SrcRegRegion *t7SrcOpnd2x1 = createSrcRegRegion(tsrc7);
        G4_SrcRegRegion *t7SrcOpnd3 = createSrcRegRegion(tsrc7);

        G4_SrcRegRegion *t9SrcOpnd0 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd1x0 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd1x1 = createSrcRegRegion(tsrc9);
        G4_SrcRegRegion *t9SrcOpnd2 = createSrcRegRegion(tsrc9);

        G4_SrcRegRegion *t10SrcOpnd0 = createSrcRegRegion(tsrc10);
        G4_SrcRegRegion *t10SrcOpnd1 = createSrcRegRegion(tsrc10);
        G4_SrcRegRegion *t10SrcOpnd2 = createSrcRegRegion(tsrc10);

        G4_SrcRegRegion *t11SrcOpnd0 = createSrcRegRegion(tsrc11);
        G4_SrcRegRegion *t11SrcOpnd1x0 = createSrcRegRegion(tsrc11);
        G4_SrcRegRegion *t11SrcOpnd1x1 = createSrcRegRegion(tsrc11);

        if (!hasDefaultRoundDenorm)
        {
            G4_DstRegRegion *cr0DstRegOpndForAndInst = createDstRegRegion(regDstCR0);
            G4_SrcRegRegion *cr0SrcRegOpndForSaveInst = createSrcRegRegion(regSrcCR0);
            G4_SrcRegRegion *cr0SrcRegOpndForAndInst = createSrcRegRegion(regSrcCR0);

            // save cr0.0: mov (1) r116.2<1>:ud cr0.0<0;1,0>:ud {NoMask}
            inst = createMov(g4::SIMD1, Create_Dst_Opnd_From_Dcl(regCR0, 1),
                cr0SrcRegOpndForSaveInst, InstOpt_WriteEnable, true);

            // set rounding mod in CR0 to RNE: and (1) cr0.0<1>:ud cr0.0<0;1,0>:ud 0xffffffcf:ud {NoMask}
            inst = createBinOp(G4_and, g4::SIMD1, cr0DstRegOpndForAndInst, cr0SrcRegOpndForAndInst,
                createImm(0xffffffcf, Type_UD), InstOpt_WriteEnable, true);
            // set single denorm to 1: (W) or (1|M0) cr0.0<1>:ud cr0.0<0;1,0>:ud 0x80:ud
            inst = createBinOp(G4_or, g4::SIMD1, createDstRegRegion(regDstCR0),
                createSrcRegRegion(regSrcCR0), createImm(0x80, Type_UW), InstOpt_WriteEnable, true);
        }

        t6SrcOpnd0 = createSrcRegRegion(fsrc0);
        t6SrcOpnd1 = createSrcRegRegion(fsrc0);
        t6SrcOpnd2 = createSrcRegRegion(fsrc0);

        //math.eo.f0.0 (8) r7.acc2 r6.noacc null 0xF {Aligned16, Q1/Q2}
        t7DstOpnd0->setAccRegSel(ACC2);
        t6SrcOpnd0->setAccRegSel(NOACC);

        G4_SrcRegRegion *null_src_opnd = createNullSrc(Type_F);

        inst = createMathInst(NULL, g4::NOSAT, exsize, t7DstOpnd0, t6SrcOpnd0,
            null_src_opnd, MATH_RSQRTM, madmInstOpt, true);
        G4_CondMod *condModOverflow = createCondMod(Mod_o, tmpFlag->getRegVar(), 0);
        inst->setCondMod(condModOverflow);

        // (-f1.0) if (8) k0__AUTO_GENERATED_IF_LABEL__0 k0__AUTO_GENERATED_IF_LABEL__0 {Q1/Q2}
        G4_Predicate *predicateFlagReg = createPredicate(PredState_Minus, tmpFlag->getRegVar(), 0, predCtrlValue);
        inst = createIf(predicateFlagReg, exsize, instOpt);


        //madm (8) r9.acc3 r0.noacc r8.noacc r7.acc2 {Aligned16, Q1/Q2}
        G4_SrcRegRegion *t0SrcOpnd0 = createSrcRegRegion(tsrc0);
        G4_SrcRegRegion *t8SrcOpnd0 = createSrcRegRegion(tsrc8);
        t9DstOpnd0->setAccRegSel(ACC3);
        t0SrcOpnd0->setAccRegSel(NOACC);
        t8SrcOpnd0->setAccRegSel(NOACC);
        t7SrcOpnd0->setAccRegSel(ACC2);
        inst = createMadm( exsize, t9DstOpnd0, t0SrcOpnd0,
            t8SrcOpnd0, t7SrcOpnd0, madmInstOpt);


        //madm (8) r11.acc4 r0.noacc r6.noacc r7.acc2 {Aligned16, Q1/Q2}
        G4_SrcRegRegion *t0SrcOpnd1 = createSrcRegRegion(tsrc0);
        t11DstOpnd0->setAccRegSel(ACC4);
        t0SrcOpnd1->setAccRegSel(NOACC);
        t6SrcOpnd1->setAccRegSel(NOACC);
        t7SrcOpnd1->setAccRegSel(ACC2);
        inst = createMadm(exsize, t11DstOpnd0, t0SrcOpnd1,
            t6SrcOpnd1, t7SrcOpnd1, madmInstOpt);


        // create -r11.noacc
        G4_SrcRegRegion tsrc11_neg(Mod_Minus,
            t11SrcOpnd0->getRegAccess(),
            t11SrcOpnd0->getBase(),
            t11SrcOpnd0->getRegOff(),
            t11SrcOpnd0->getSubRegOff(),
            t11SrcOpnd0->getRegion(),
            t11SrcOpnd0->getType());
        G4_SrcRegRegion *t11SrcOpndNeg0 = createSrcRegRegion(tsrc11_neg);
        //madm (8) r10.acc5 r8.noacc -r11.acc4 r9.acc3 {Aligned16, Q1/Q2}
        G4_SrcRegRegion *t8SrcOpnd1 = createSrcRegRegion(tsrc8);
        t10DstOpnd0->setAccRegSel(ACC5);
        t8SrcOpnd1->setAccRegSel(NOACC);
        t11SrcOpndNeg0->setAccRegSel(ACC4);
        t9SrcOpnd0->setAccRegSel(ACC3);
        inst = createMadm(exsize, t10DstOpnd0, t8SrcOpnd1,
            t11SrcOpndNeg0, t9SrcOpnd0, madmInstOpt);


        //madm (8) r9.acc6 r9.acc3 r10.acc5 r9.acc3 {Aligned16, Q1/Q2}
        t9DstOpnd1->setAccRegSel(ACC6);
        t9SrcOpnd1x0->setAccRegSel(ACC3);
        t10SrcOpnd0->setAccRegSel(ACC5);
        t9SrcOpnd1x1->setAccRegSel(ACC3);
        inst = createMadm( exsize, t9DstOpnd1, t9SrcOpnd1x0,
            t10SrcOpnd0, t9SrcOpnd1x1, madmInstOpt);


        //madm (8) r7.acc7 r11.acc4 r10.acc5 r11.acc4 {Aligned16, Q1/Q2}
        t7DstOpnd1->setAccRegSel(ACC7);
        t11SrcOpnd1x0->setAccRegSel(ACC4);
        t10SrcOpnd1->setAccRegSel(ACC5);
        t11SrcOpnd1x1->setAccRegSel(ACC4);
        inst = createMadm(exsize, t7DstOpnd1, t11SrcOpnd1x0,
            t10SrcOpnd1, t11SrcOpnd1x1, madmInstOpt);


        // create -r7.noacc
        G4_SrcRegRegion tsrc7_neg(Mod_Minus,
            t7SrcOpnd2x0->getRegAccess(),
            t7SrcOpnd2x0->getBase(),
            t7SrcOpnd2x0->getRegOff(),
            t7SrcOpnd2x0->getSubRegOff(),
            t7SrcOpnd2x0->getRegion(),
            t7SrcOpnd2x0->getType());
        G4_SrcRegRegion *t7SrcOpndNeg0 = createSrcRegRegion(tsrc7_neg);
        //madm (8) r10.acc8 r6.noacc -r7.acc7 r7.acc7 {Aligned16, Q1/Q2}
        t10DstOpnd1->setAccRegSel(ACC8);
        t6SrcOpnd2->setAccRegSel(NOACC);
        t7SrcOpndNeg0->setAccRegSel(ACC7);
        t7SrcOpnd2x1->setAccRegSel(ACC7);
        inst = createMadm( exsize, t10DstOpnd1, t6SrcOpnd2,
            t7SrcOpndNeg0, t7SrcOpnd2x1, madmInstOpt);

        if (!hasDefaultRoundDenorm)
        {
            // restore cr0.0: mov (1) cr0.0<1>:ud r116.1<0;1,0>:ud {NoMask}
            inst = createMov(g4::SIMD1, createDstRegRegion(regDstCR0),
                Create_Src_Opnd_From_Dcl(regCR0, getRegionScalar()), InstOpt_WriteEnable, true);
        }

        //madm (8) r7.noacc r7.acc7 r9.acc6 r10.acc8 {Aligned16, Q1/Q2}
        t7DstOpnd2->setAccRegSel(NOACC);
        t7SrcOpnd3->setAccRegSel(ACC7);
        t9SrcOpnd2->setAccRegSel(ACC6);
        t10SrcOpnd2->setAccRegSel(ACC8);
        inst = createMadm(exsize, t7DstOpnd2, t7SrcOpnd3,
            t9SrcOpnd2, t10SrcOpnd2, madmInstOpt);

        if (!hasDefaultRoundDenorm)
        {
            // else (exsize) k0__AUTO_GENERATED_ELSE_LABEL__1 k0__AUTO_GENERATED_ELSE_LABEL__1 {Q1/Q2}
            inst = createElse(exsize, instOpt);

            // restore cr0.0: mov (1) cr0.0<1>:ud r116.2<0;1,0>:ud {NoMask}
            inst = createMov(g4::SIMD1, createDstRegRegion(regDstCR0),
                Create_Src_Opnd_From_Dcl(regCR0, getRegionScalar()), InstOpt_WriteEnable, true);
        }

        // endif (exsize) {Q1/Q2}
        inst = createEndif(exsize, instOpt);
    };

    // make final copy to dst
    // dst = r8:df   mov (instExecSize) r86.0<1>:f r8.0<8;8,1>:f {Q1/H1}
    t7_src_opnd_final->setAccRegSel(ACC_UNDEFINED);
    inst = createInst(predOpnd, G4_mov, condMod, saturate, instExecSize, dstOpnd, t7_src_opnd_final,
        NULL, Get_Gen4_Emask(emask, instExecSize), true);

    return VISA_SUCCESS;
}


int IR_Builder::translateVISAArithmeticDoubleSQRTInst(
    ISA_Opcode opcode, VISA_Exec_Size executionSize,
    VISA_EMask_Ctrl emask, G4_Predicate *predOpnd,
    G4_Sat saturate, G4_CondMod* condMod,
    G4_DstRegRegion *dstOpnd, G4_Operand *src0Opnd)
{
    TIME_SCOPE(VISA_BUILDER_IR_CONSTRUCTION);

    G4_INST* inst;
    G4_ExecSize instExecSize = toExecSize(executionSize);
    G4_ExecSize exsize = g4::SIMD4;

    const RegionDesc *srcRegionDesc = getRegionStride1();
    const RegionDesc *rdAlign16 = getRegionStride1();
    unsigned int loopCount;
    G4_ExecSize element_size {0};   // element_size is set according to instExecSize

    G4_DstRegRegion *dst0 = nullptr;
    G4_SrcRegRegion *src0 = nullptr;
    G4_SrcRegRegion *src1 = nullptr;
    G4_SrcRegRegion *src2 = nullptr;
    G4_SrcRegRegion *neg_src1 = nullptr;

    G4_Imm *immData = nullptr;

    if (instExecSize == 1 || instExecSize == 4)
    {
        element_size = g4::SIMD4;
        loopCount = 1;
    }
    else
    {
        element_size = instExecSize;
        exsize = std::min(instExecSize, G4_ExecSize(getFP64MadmExecSize()));
        loopCount = instExecSize / exsize;
    }

    bool noDstMove = exsize == 8 && !saturate && !predOpnd && isOpndAligned(dstOpnd, getGRFSize()) &&
        dstOpnd->getRegAccess() == Direct && dstOpnd->getHorzStride() == 1;
    if (noDstMove && dstOpnd->getTopDcl() == src0Opnd->getTopDcl())
    {
        noDstMove = false;
    }

    unsigned int instOpt = Get_Gen4_Emask(emask, exsize);

    // pred and conModifier
    G4_Declare *flagReg = createTempFlag(instExecSize == 32 ? 2 : 1);
    G4_Predicate_Control predCtrlValue = PRED_DEFAULT;

    // temp registers
    G4_Declare *t0 = getImmDcl(createDFImm(0.0), element_size);
    G4_Declare *t1 = getImmDcl(createDFImm(1.0), element_size);
    G4_Declare *t2 = getImmDcl(createDFImm(0.5), element_size);
    G4_Declare* t3 = getImmDcl(createDFImm(1.5), element_size);
    G4_Declare *t6  = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t7  = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t8  = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t9  = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t10 = createTempVarWithNoSpill(element_size, Type_DF, Any);
    G4_Declare *t11 = createTempVarWithNoSpill(element_size, Type_DF, Any);

    inst = createPseudoKills({t6, t7, t8, t9, t10, t11, flagReg }, PseudoKillType::Src);

    G4_SrcRegRegion* src0RR = operandToDirectSrcRegRegion(*this, src0Opnd, element_size, instExecSize);

    bool IsSrc0Moved = src0RR->getRegion()->isScalar() || src0RR->getModifier() != Mod_src_undef;
    if (IsSrc0Moved)
    {
        // expand scale src0 to vector src
        dst0 = Create_Dst_Opnd_From_Dcl(t6, 1);
        // mov (element_size) t6_dst_src0_opnd, src0RR {Q1/H1}
        inst = createMov(element_size, dst0, src0RR, instOpt, true);
    }

    bool hasDefaultRoundDenorm = getOption(vISA_hasRNEandDenorm);
    // cr0.0 register
    G4_DstRegRegion regDstCR0(Direct, phyregpool.getCr0Reg(), 0, 0, 1, Type_UD);
    G4_SrcRegRegion regSrcCR0(Mod_src_undef, Direct, phyregpool.getCr0Reg(), 0, 0, getRegionScalar(), Type_UD);

    // temporary reg for saving/restoring cr0.0
    G4_Declare *tmpRegCR0 = createTempVarWithNoSpill(1, Type_UD, Any);

    // constants

    // r0 = 0.0:df, r1 = 1.0:df, r2(r8) = 0.5:df, r3 = 1.5:df
    // NOTE: 'NoMask' is required as constants are required for splitting
    // parts. Once they are in diverged branches, it won't be properly
    // initialized without 'NoMask'.

    // one GRF
    G4_SrcRegRegion csrc0(Mod_src_undef, Direct, t0->getRegVar(), 0, 0, srcRegionDesc, Type_DF);
    G4_SrcRegRegion csrc1(Mod_src_undef, Direct, t1->getRegVar(), 0, 0, srcRegionDesc, Type_DF);
    G4_SrcRegRegion csrc2(Mod_src_undef, Direct, t2->getRegVar(), 0, 0, srcRegionDesc, Type_DF);
    G4_SrcRegRegion csrc3(Mod_src_undef, Direct, t3->getRegVar(), 0, 0, srcRegionDesc, Type_DF);

    // each madm only handles 4 channel double data
    VISA_EMask_Ctrl currEMask = emask;
    for (uint16_t regIndex = 0; currEMask != vISA_NUM_EMASK && regIndex < loopCount;
        ++regIndex, currEMask = Get_Next_EMask(currEMask, exsize))
    {
        instOpt = Get_Gen4_Emask(currEMask, exsize);
        instOpt |= isNoMask(emask) ? InstOpt_WriteEnable : 0; // setting channels for non-mad insts
        unsigned int madmInstOpt = instOpt; // setting channels for mad insts

                                            // dst : 7, 8, 9, 10 11
        G4_DstRegRegion tdst7(Direct, noDstMove ? dstOpnd->getBase() : t7->getRegVar(),
            noDstMove ? dstOpnd->getRegOff() + regIndex : regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst8(Direct, t8->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst9(Direct, t9->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst10(Direct, t10->getRegVar(), regIndex, 0, 1, Type_DF);
        G4_DstRegRegion tdst11(Direct, t11->getRegVar(), regIndex, 0, 1, Type_DF);

        // source of inst.
        G4_SrcRegRegion fsrc0_math(Mod_src_undef, Direct, src0RR->getBase(), src0RR->getRegOff() + regIndex, 0, rdAlign16, Type_DF);


        // src : 6, 7, 8, 9, 10, 11
        G4_SrcRegRegion fsrc0(Mod_src_undef, Direct, src0RR->getBase(), src0RR->getRegOff() + regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc6(Mod_src_undef, Direct, t6->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc7(Mod_src_undef, Direct, noDstMove ? dstOpnd->getBase() : t7->getRegVar(),
            noDstMove ? dstOpnd->getRegOff() + regIndex : regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc8(Mod_src_undef, Direct, t8->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc9(Mod_src_undef, Direct, t9->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc10(Mod_src_undef, Direct, t10->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);
        G4_SrcRegRegion tsrc11(Mod_src_undef, Direct, t11->getRegVar(), regIndex, 0, srcRegionDesc, Type_DF);

        if (!hasDefaultRoundDenorm)
        {
            // save cr0.0
            dst0 = Create_Dst_Opnd_From_Dcl(tmpRegCR0, 1);
            src0 = createSrcRegRegion(regSrcCR0);
            // mov (1) r108.0<1>:ud cr0.0<0;1,0>:ud {NoMask}
            inst = createMov(g4::SIMD1, dst0, src0, InstOpt_WriteEnable, true);


            // set rounding mod in CR0 to RNE
            dst0 = createDstRegRegion(regDstCR0);
            src0 = createSrcRegRegion(regSrcCR0);
            immData = createImm(0xffffffcf, Type_UD);
            // and (1) cr0.0<0;1,0>:ud cr0.0<0;1,0>:ud 0xffffffcf:ud {NoMask}
            inst = createBinOp(G4_and, g4::SIMD1, dst0, src0, immData, InstOpt_WriteEnable, true);


            // set double precision denorm mode to 1
            dst0 = createDstRegRegion(regDstCR0);
            src0 = createSrcRegRegion(regSrcCR0);
            immData = createImm(0x40, Type_UD);
            // or (1) cr0.0<0;1,0>:ud cr0.0<0;1,0>:ud 0x40:ud {NoMask}
            inst = createBinOp(G4_or, g4::SIMD1, dst0, src0, immData, InstOpt_WriteEnable, true);
        }

        // math.e0.f0.0 (4) r7.acc2 r6.noacc NULL 0xf {Align16, N1/N2}
        dst0 = createDstRegRegion(tdst7); dst0->setAccRegSel(ACC2);
        if (IsSrc0Moved)
        {
            // use t6, but need to adjust the offset since unlike the orig source t6 is zero-based.
            src0 = createSrcRegRegion(Mod_src_undef, Direct, t6->getRegVar(), regIndex, 0, rdAlign16, Type_DF);
        }
        else
        {
            src0 = createSrcRegRegion(fsrc0_math);
        }
        src0->setAccRegSel(NOACC);
        src1 = createNullSrc(Type_DF);
        G4_CondMod* condModOverflow = createCondMod(Mod_o, flagReg->getRegVar(), 0);
        inst = createMathInst(NULL, g4::NOSAT, exsize, dst0, src0, src1, MATH_RSQRTM, madmInstOpt, true);
        inst->setCondMod(condModOverflow);

        bool generateIf = true;

        if (generateIf)
        {
            // if
            G4_Predicate *predicateFlagReg = createPredicate(PredState_Minus, flagReg->getRegVar(), 0, predCtrlValue);
            inst = createIf(predicateFlagReg, exsize, instOpt);
        }

        {
            // madm (4) r9.acc3 r0.noacc r2(r8).noacc r7.acc2 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst9); dst0->setAccRegSel(ACC3);
            src0 = createSrcRegRegion(csrc0); src0->setAccRegSel(NOACC);
            src1 = createSrcRegRegion(csrc2); src1->setAccRegSel(NOACC);
            src2 = createSrcRegRegion(tsrc7); src2->setAccRegSel(ACC2);
            inst = createMadm(exsize,
                dst0, src0, src1, src2, madmInstOpt);

            // madm (4) r11.acc4 r0.noacc r6.noacc r7.acc2 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst11); dst0->setAccRegSel(ACC4);
            src0 = createSrcRegRegion(csrc0); src0->setAccRegSel(NOACC);
            if (IsSrc0Moved)
            {
                src1 = createSrcRegRegion(tsrc6);
            }
            else
            {
                src1 = createSrcRegRegion(fsrc0);
            }
            src1->setAccRegSel(NOACC);
            src2 = createSrcRegRegion(tsrc7); src2->setAccRegSel(ACC2);
            inst = createMadm(exsize,
                dst0, src0, src1, src2, madmInstOpt);

            // madm (4) r10.acc5 r2(r8).noacc -r11.acc4 r9.acc3 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst10); dst0->setAccRegSel(ACC5);
            src0 = createSrcRegRegion(csrc2); src0->setAccRegSel(NOACC);
            src1 = createSrcRegRegion(tsrc11); src1->setAccRegSel(ACC4);
            src2 = createSrcRegRegion(tsrc9); src2->setAccRegSel(ACC3);
            G4_SrcRegRegion neg_srcRegion(Mod_Minus,
                src1->getRegAccess(),
                src1->getBase(),
                src1->getRegOff(),
                src1->getSubRegOff(),
                src1->getRegion(),
                src1->getType());
            neg_src1 = createSrcRegRegion(neg_srcRegion);
            neg_src1->setAccRegSel(src1->getAccRegSel());
            inst = createMadm(exsize,
                dst0, src0, neg_src1, src2, madmInstOpt);

            // madm (4) r8.acc7 r1.noacc r3.noacc r10.acc5 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst8); dst0->setAccRegSel(ACC7);
            src0 = createSrcRegRegion(csrc1); src0->setAccRegSel(NOACC);
            src1 = createSrcRegRegion(csrc3); src1->setAccRegSel(NOACC);
            src2 = createSrcRegRegion(tsrc10); src2->setAccRegSel(ACC5);
            inst = createMadm(exsize,
                dst0, src0, src1, src2, madmInstOpt);

            // madm (4) r7.acc8 r0.noacc r10.acc5 r11.acc4 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst7); dst0->setAccRegSel(ACC8);
            src0 = createSrcRegRegion(csrc0); src0->setAccRegSel(NOACC);
            src1 = createSrcRegRegion(tsrc10); src1->setAccRegSel(ACC5);
            src2 = createSrcRegRegion(tsrc11); src2->setAccRegSel(ACC4);
            inst = createMadm(exsize,
                dst0, src0, src1, src2, madmInstOpt);

            // madm (4) r10.acc9 r0.noacc r10.acc5 r9.acc3 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst10); dst0->setAccRegSel(ACC9);
            src0 = createSrcRegRegion(csrc0); src0->setAccRegSel(NOACC);
            src1 = createSrcRegRegion(tsrc10); src1->setAccRegSel(ACC5);
            src2 = createSrcRegRegion(tsrc9); src2->setAccRegSel(ACC3);
            inst = createMadm(exsize,
                dst0, src0, src1, src2, madmInstOpt);

            // madm (4) r7.acc8 r11.acc4 r8.acc7 r7.acc8 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst7); dst0->setAccRegSel(ACC8);
            src0 = createSrcRegRegion(tsrc11); src0->setAccRegSel(ACC4);
            src1 = createSrcRegRegion(tsrc8); src1->setAccRegSel(ACC7);
            src2 = createSrcRegRegion(tsrc7); src2->setAccRegSel(ACC8);
            inst = createMadm(exsize,
                dst0, src0, src1, src2, madmInstOpt);

            // madm (4) r8.acc7 r9.acc3 r8.acc7 r10.acc9 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst8); dst0->setAccRegSel(ACC7);
            src0 = createSrcRegRegion(tsrc9); src0->setAccRegSel(ACC3);
            src1 = createSrcRegRegion(tsrc8); src1->setAccRegSel(ACC7);
            src2 = createSrcRegRegion(tsrc10); src2->setAccRegSel(ACC9);
            inst = createMadm(exsize,
                dst0, src0, src1, src2, madmInstOpt);

            // madm (4) r9.acc3 r6.noacc -r7.acc8 r7.acc8 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst9); dst0->setAccRegSel(ACC3);
            if (IsSrc0Moved)
            {
                src0 = createSrcRegRegion(tsrc6);
            }
            else
            {
                src0 = createSrcRegRegion(fsrc0);
            }
            src0->setAccRegSel(NOACC);
            src1 = createSrcRegRegion(tsrc7); src1->setAccRegSel(ACC8);
            src2 = createSrcRegRegion(tsrc7); src2->setAccRegSel(ACC8);
            G4_SrcRegRegion neg_srcRegion1(Mod_Minus,
                src1->getRegAccess(),
                src1->getBase(),
                src1->getRegOff(),
                src1->getSubRegOff(),
                src1->getRegion(),
                src1->getType());
            neg_src1 = createSrcRegRegion(neg_srcRegion1);
            neg_src1->setAccRegSel(src1->getAccRegSel());
            inst = createMadm(exsize,
                dst0, src0, neg_src1, src2, madmInstOpt);

            if (!hasDefaultRoundDenorm)
            {
                // restore cr0.0
                dst0 = createDstRegRegion(regDstCR0);
                src0 = Create_Src_Opnd_From_Dcl(tmpRegCR0, getRegionScalar());
                // mov (1) cr0.0<0;1,0>:ud r108.0<1>:ud {NoMask}
                inst = createMov(g4::SIMD1, dst0, src0, InstOpt_WriteEnable, true);
            }

            // madm (4) r7.noacc r7.acc8 r9.acc3 r8.acc7 {Align16, N1/N2}
            dst0 = createDstRegRegion(tdst7); dst0->setAccRegSel(NOACC);
            src0 = createSrcRegRegion(tsrc7); src0->setAccRegSel(ACC8);
            src1 = createSrcRegRegion(tsrc9); src1->setAccRegSel(ACC3);
            src2 = createSrcRegRegion(tsrc8); src2->setAccRegSel(ACC7);
            inst = createMadm(exsize,
                dst0, src0, src1, src2, madmInstOpt);

        }


        if (generateIf && !hasDefaultRoundDenorm)
        {
            // else (8) {Q1/Q2}
            inst = createElse(exsize, instOpt);

            // restore cr0.0 {NoMask}
            dst0 = createDstRegRegion(regDstCR0);
            src0 = Create_Src_Opnd_From_Dcl(tmpRegCR0, getRegionScalar());
            // mov (1) cr0.0<0;1,0>:ud r108.0<1>:ud {NoMask}
            inst = createMov(g4::SIMD1, dst0, src0, InstOpt_WriteEnable, true);
        }

        if (generateIf)
        {
            // endif (8) {Q1/Q2}
            inst = createEndif(exsize, instOpt);
        }
    };

    if (!noDstMove)
    {
        // make final copy to dst
        // src = r7:df
        // final result is at r7.noacc
        G4_SrcRegRegion tsrc7_final(Mod_src_undef, Direct, t7->getRegVar(), 0, 0, getRegionStride1(), t7->getElemType());
        G4_SrcRegRegion *t7_src_opnd_final = createSrcRegRegion(tsrc7_final); t7_src_opnd_final->setAccRegSel(ACC_UNDEFINED);
        // mov (instExecSize) r20.0<1>:df r7.0<8;8,1>:df {Q1/H1}
        inst = createInst(
            predOpnd, G4_mov, condMod, saturate, instExecSize,
            dstOpnd, t7_src_opnd_final, nullptr, Get_Gen4_Emask(emask, instExecSize), true);
    }

    return VISA_SUCCESS;
}
