Refactor arm32/arm64 per-node codegen into functions (dotnet/coreclr#11377)
authorBruce Forstall <brucefo@microsoft.com>
Thu, 4 May 2017 23:07:26 +0000 (16:07 -0700)
committerGitHub <noreply@github.com>
Thu, 4 May 2017 23:07:26 +0000 (16:07 -0700)
These new functions can sometimes be shared, as they are identical or
virtually so.

In addition, the driver function genCodeForTreeNode() has been
made common.

Commit migrated from https://github.com/dotnet/coreclr/commit/1aa7ca424deb65c510bc8b7e3ee34039c9f0e6a1

src/coreclr/src/jit/codegenarm.cpp
src/coreclr/src/jit/codegenarm64.cpp
src/coreclr/src/jit/codegenarmarch.cpp
src/coreclr/src/jit/codegenlinear.h

index 0795299..320c6d6 100644 (file)
@@ -259,6 +259,11 @@ void CodeGen::genReturn(GenTreePtr treeNode)
     GenTreePtr op1        = treeNode->gtGetOp1();
     var_types  targetType = treeNode->TypeGet();
 
+    // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
+    // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
+    // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
+    assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
+
 #ifdef DEBUG
     if (targetType == TYP_VOID)
     {
@@ -315,398 +320,6 @@ void CodeGen::genReturn(GenTreePtr treeNode)
 }
 
 //------------------------------------------------------------------------
-// genCodeForTreeNode Generate code for a single node in the tree.
-//
-// Preconditions:
-//    All operands have been evaluated.
-//
-void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
-{
-    regNumber targetReg  = treeNode->gtRegNum;
-    var_types targetType = treeNode->TypeGet();
-    emitter*  emit       = getEmitter();
-
-#ifdef DEBUG
-    lastConsumedNode = nullptr;
-    if (compiler->verbose)
-    {
-        unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
-        compiler->gtDispLIRNode(treeNode, "Generating: ");
-    }
-#endif
-
-    // contained nodes are part of their parents for codegen purposes
-    // ex : immediates, most LEAs
-    if (treeNode->isContained())
-    {
-        return;
-    }
-
-    switch (treeNode->gtOper)
-    {
-        case GT_LCLHEAP:
-            genLclHeap(treeNode);
-            break;
-
-        case GT_CNS_INT:
-        case GT_CNS_DBL:
-            genSetRegToConst(targetReg, targetType, treeNode);
-            genProduceReg(treeNode);
-            break;
-
-        case GT_NOT:
-        case GT_NEG:
-            genCodeForNegNot(treeNode);
-            break;
-
-        case GT_OR:
-        case GT_XOR:
-        case GT_AND:
-            assert(varTypeIsIntegralOrI(treeNode));
-            __fallthrough;
-
-        case GT_ADD_LO:
-        case GT_ADD_HI:
-        case GT_SUB_LO:
-        case GT_SUB_HI:
-        case GT_ADD:
-        case GT_SUB:
-        case GT_MUL:
-            genConsumeOperands(treeNode->AsOp());
-            genCodeForBinary(treeNode);
-            break;
-
-        case GT_LSH:
-        case GT_RSH:
-        case GT_RSZ:
-        case GT_ROR:
-            genCodeForShift(treeNode);
-            break;
-
-        case GT_LSH_HI:
-        case GT_RSH_LO:
-            genCodeForShiftLong(treeNode);
-            break;
-
-        case GT_CAST:
-            // Cast is never contained (?)
-            noway_assert(targetReg != REG_NA);
-
-            if (varTypeIsFloating(targetType) && varTypeIsFloating(treeNode->gtOp.gtOp1))
-            {
-                // Casts float/double <--> double/float
-                genFloatToFloatCast(treeNode);
-            }
-            else if (varTypeIsFloating(treeNode->gtOp.gtOp1))
-            {
-                // Casts float/double --> int32/int64
-                genFloatToIntCast(treeNode);
-            }
-            else if (varTypeIsFloating(targetType))
-            {
-                // Casts int32/uint32/int64/uint64 --> float/double
-                genIntToFloatCast(treeNode);
-            }
-            else
-            {
-                // Casts int <--> int
-                genIntToIntCast(treeNode);
-            }
-            // The per-case functions call genProduceReg()
-            break;
-
-        case GT_LCL_FLD_ADDR:
-        case GT_LCL_VAR_ADDR:
-        {
-            // Address of a local var.  This by itself should never be allocated a register.
-            // If it is worth storing the address in a register then it should be cse'ed into
-            // a temp and that would be allocated a register.
-            noway_assert(targetType == TYP_BYREF);
-            noway_assert(!treeNode->InReg());
-
-            inst_RV_TT(INS_lea, targetReg, treeNode, 0, EA_BYREF);
-        }
-            genProduceReg(treeNode);
-            break;
-
-        case GT_LCL_FLD:
-            genCodeForLclFld(treeNode->AsLclFld());
-            break;
-
-        case GT_LCL_VAR:
-            genCodeForLclVar(treeNode->AsLclVar());
-            break;
-
-        case GT_STORE_LCL_FLD:
-            genCodeForStoreLclFld(treeNode->AsLclFld());
-            break;
-
-        case GT_STORE_LCL_VAR:
-            genCodeForStoreLclVar(treeNode->AsLclVar());
-            break;
-
-        case GT_RETFILT:
-            // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in
-            // the return register, if it's not already there. The processing is the same as GT_RETURN.
-            if (targetType != TYP_VOID)
-            {
-                // For filters, the IL spec says the result is type int32. Further, the only specified legal values
-                // are 0 or 1, with the use of other values "undefined".
-                assert(targetType == TYP_INT);
-            }
-
-            __fallthrough;
-
-        case GT_RETURN:
-            genReturn(treeNode);
-            break;
-
-        case GT_LEA:
-            // if we are here, it is the case where there is an LEA that cannot
-            // be folded into a parent instruction
-            genLeaInstruction(treeNode->AsAddrMode());
-            break;
-
-        case GT_IND:
-            genConsumeAddress(treeNode->AsIndir()->Addr());
-            emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(treeNode), targetReg, treeNode->AsIndir());
-            genProduceReg(treeNode);
-            break;
-
-        case GT_MOD:
-        case GT_UDIV:
-        case GT_UMOD:
-            // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
-            // helper call by front-end.  Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
-            // on float/double args.
-            noway_assert(!varTypeIsFloating(treeNode));
-            __fallthrough;
-
-        case GT_DIV:
-        {
-            genConsumeOperands(treeNode->AsOp());
-
-            noway_assert(targetReg != REG_NA);
-
-            GenTreePtr  dst    = treeNode;
-            GenTreePtr  src1   = treeNode->gtGetOp1();
-            GenTreePtr  src2   = treeNode->gtGetOp2();
-            instruction ins    = genGetInsForOper(treeNode->OperGet(), targetType);
-            emitAttr    attr   = emitTypeSize(treeNode);
-            regNumber   result = REG_NA;
-
-            // dst can only be a reg
-            assert(!dst->isContained());
-
-            // src can be only reg
-            assert(!src1->isContained() || !src2->isContained());
-
-            if (varTypeIsFloating(targetType))
-            {
-                // Floating point divide never raises an exception
-
-                emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
-            }
-            else // an signed integer divide operation
-            {
-                // TODO-ARM-Bug: handle zero division exception.
-
-                emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
-            }
-
-            genProduceReg(treeNode);
-        }
-        break;
-
-        case GT_INTRINSIC:
-            genIntrinsic(treeNode);
-            break;
-
-        case GT_EQ:
-        case GT_NE:
-        case GT_LT:
-        case GT_LE:
-        case GT_GE:
-        case GT_GT:
-            genCodeForCompare(treeNode->AsOp());
-            break;
-
-        case GT_JTRUE:
-            genCodeForJumpTrue(treeNode);
-            break;
-
-        case GT_JCC:
-        {
-            GenTreeJumpCC* jcc = treeNode->AsJumpCC();
-
-            assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
-
-            CompareKind  compareKind = ((jcc->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
-            emitJumpKind jumpKind    = genJumpKindForOper(jcc->gtCondition, compareKind);
-
-            inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
-        }
-        break;
-
-        case GT_RETURNTRAP:
-            genCodeForReturnTrap(treeNode->AsOp());
-            break;
-
-        case GT_STOREIND:
-            genCodeForStoreInd(treeNode->AsStoreInd());
-            break;
-
-        case GT_COPY:
-            // This is handled at the time we call genConsumeReg() on the GT_COPY
-            break;
-
-        case GT_LIST:
-        case GT_FIELD_LIST:
-        case GT_ARGPLACE:
-            // Nothing to do
-            break;
-
-        case GT_PUTARG_STK:
-            genPutArgStk(treeNode->AsPutArgStk());
-            break;
-
-        case GT_PUTARG_REG:
-            genPutArgReg(treeNode->AsOp());
-            break;
-
-        case GT_CALL:
-            genCallInstruction(treeNode->AsCall());
-            break;
-
-        case GT_LOCKADD:
-        case GT_XCHG:
-        case GT_XADD:
-            genLockedInstructions(treeNode->AsOp());
-            break;
-
-        case GT_MEMORYBARRIER:
-            instGen_MemoryBarrier();
-            break;
-
-        case GT_CMPXCHG:
-            NYI("GT_CMPXCHG");
-            genProduceReg(treeNode);
-            break;
-
-        case GT_RELOAD:
-            // do nothing - reload is just a marker.
-            // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
-            // into the register specified in this node.
-            break;
-
-        case GT_NOP:
-            break;
-
-        case GT_NO_OP:
-            if (treeNode->gtFlags & GTF_NO_OP_NO)
-            {
-                noway_assert(!"GTF_NO_OP_NO should not be set");
-            }
-            else
-            {
-                instGen(INS_nop);
-            }
-            break;
-
-        case GT_ARR_BOUNDS_CHECK:
-            genRangeCheck(treeNode);
-            break;
-
-        case GT_PHYSREG:
-            if (treeNode->gtRegNum != treeNode->AsPhysReg()->gtSrcReg)
-            {
-                inst_RV_RV(INS_mov, treeNode->gtRegNum, treeNode->AsPhysReg()->gtSrcReg, targetType);
-
-                genTransferRegGCState(treeNode->gtRegNum, treeNode->AsPhysReg()->gtSrcReg);
-            }
-            break;
-
-        case GT_PHYSREGDST:
-            break;
-
-        case GT_NULLCHECK:
-        {
-            assert(!treeNode->gtOp.gtOp1->isContained());
-            regNumber addrReg = genConsumeReg(treeNode->gtOp.gtOp1);
-            emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
-        }
-        break;
-
-        case GT_CATCH_ARG:
-
-            noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
-
-            /* Catch arguments get passed in a register. genCodeForBBlist()
-               would have marked it as holding a GC object, but not used. */
-
-            noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
-            genConsumeReg(treeNode);
-            break;
-
-        case GT_PINVOKE_PROLOG:
-            noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
-
-            // the runtime side requires the codegen here to be consistent
-            emit->emitDisableRandomNops();
-            break;
-
-        case GT_LABEL:
-            genPendingCallLabel       = genCreateTempLabel();
-            treeNode->gtLabel.gtLabBB = genPendingCallLabel;
-            emit->emitIns_J_R(INS_adr, EA_PTRSIZE, genPendingCallLabel, treeNode->gtRegNum);
-            break;
-
-        case GT_CLS_VAR_ADDR:
-            emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
-            genProduceReg(treeNode);
-            break;
-
-        case GT_STORE_DYN_BLK:
-        case GT_STORE_BLK:
-            genCodeForStoreBlk(treeNode->AsBlk());
-            break;
-
-        case GT_JMPTABLE:
-            genJumpTable(treeNode);
-            break;
-
-        case GT_SWITCH_TABLE:
-            genTableBasedSwitch(treeNode);
-            break;
-
-        case GT_ARR_INDEX:
-            genCodeForArrIndex(treeNode->AsArrIndex());
-            break;
-
-        case GT_ARR_OFFSET:
-            genCodeForArrOffset(treeNode->AsArrOffs());
-            break;
-
-        case GT_IL_OFFSET:
-            // Do nothing; these nodes are simply markers for debug info.
-            break;
-
-        default:
-        {
-#ifdef DEBUG
-            char message[256];
-            _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
-                        GenTree::NodeName(treeNode->OperGet()));
-            NYIRAW(message);
-#else
-            NYI("unimplemented node");
-#endif
-        }
-        break;
-    }
-}
-
-//------------------------------------------------------------------------
 // genLockedInstructions: Generate code for the locked operations.
 //
 // Notes:
@@ -1168,45 +781,6 @@ void CodeGen::genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode)
     NYI_ARM("genCodeForInitBlkUnroll");
 }
 
-void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
-{
-    if (blkOp->gtBlkOpGcUnsafe)
-    {
-        getEmitter()->emitDisableGC();
-    }
-    bool isCopyBlk = blkOp->OperIsCopyBlkOp();
-
-    switch (blkOp->gtBlkOpKind)
-    {
-        case GenTreeBlk::BlkOpKindHelper:
-            if (isCopyBlk)
-            {
-                genCodeForCpBlk(blkOp);
-            }
-            else
-            {
-                genCodeForInitBlk(blkOp);
-            }
-            break;
-        case GenTreeBlk::BlkOpKindUnroll:
-            if (isCopyBlk)
-            {
-                genCodeForCpBlkUnroll(blkOp);
-            }
-            else
-            {
-                genCodeForInitBlkUnroll(blkOp);
-            }
-            break;
-        default:
-            unreached();
-    }
-    if (blkOp->gtBlkOpGcUnsafe)
-    {
-        getEmitter()->emitEnableGC();
-    }
-}
-
 //------------------------------------------------------------------------
 // genCodeForNegNot: Produce code for a GT_NEG/GT_NOT node.
 //
@@ -1486,6 +1060,58 @@ void CodeGen::genLeaInstruction(GenTreeAddrMode* lea)
 }
 
 //------------------------------------------------------------------------
+// genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV/GT_MOD/GT_UMOD node.
+//
+// Arguments:
+//    tree - the node
+//
+void CodeGen::genCodeForDivMod(GenTreeOp* tree)
+{
+    assert(tree->OperIs(GT_DIV, GT_UDIV, GT_MOD, GT_UMOD));
+
+    // We shouldn't be seeing GT_MOD on float/double args as it should get morphed into a
+    // helper call by front-end. Similarly we shouldn't be seeing GT_UDIV and GT_UMOD
+    // on float/double args.
+    noway_assert(tree->OperIs(GT_DIV) || !varTypeIsFloating(tree));
+
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+    emitter*  emit       = getEmitter();
+
+    genConsumeOperands(tree);
+
+    noway_assert(targetReg != REG_NA);
+
+    GenTreePtr  dst    = tree;
+    GenTreePtr  src1   = tree->gtGetOp1();
+    GenTreePtr  src2   = tree->gtGetOp2();
+    instruction ins    = genGetInsForOper(tree->OperGet(), targetType);
+    emitAttr    attr   = emitTypeSize(tree);
+    regNumber   result = REG_NA;
+
+    // dst can only be a reg
+    assert(!dst->isContained());
+
+    // src can be only reg
+    assert(!src1->isContained() || !src2->isContained());
+
+    if (varTypeIsFloating(targetType))
+    {
+        // Floating point divide never raises an exception
+
+        emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
+    }
+    else // an signed integer divide operation
+    {
+        // TODO-ARM-Bug: handle zero division exception.
+
+        emit->emitIns_R_R_R(ins, attr, dst->gtRegNum, src1->gtRegNum, src2->gtRegNum);
+    }
+
+    genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
 // genCodeForCompare: Produce code for a GT_EQ/GT_NE/GT_LT/GT_LE/GT_GE/GT_GT node.
 //
 // Arguments:
@@ -1566,6 +1192,22 @@ void CodeGen::genCodeForCompare(GenTreeOp* tree)
 }
 
 //------------------------------------------------------------------------
+// genCodeForJcc: Produce code for a GT_JCC node.
+//
+// Arguments:
+//    tree - the node
+//
+void CodeGen::genCodeForJcc(GenTreeJumpCC* tree)
+{
+    assert(compiler->compCurBB->bbJumpKind == BBJ_COND);
+
+    CompareKind  compareKind = ((tree->gtFlags & GTF_UNSIGNED) != 0) ? CK_UNSIGNED : CK_SIGNED;
+    emitJumpKind jumpKind    = genJumpKindForOper(tree->gtCondition, compareKind);
+
+    inst_JMP(jumpKind, compiler->compCurBB->bbJumpDest);
+}
+
+//------------------------------------------------------------------------
 // genCodeForReturnTrap: Produce code for a GT_RETURNTRAP node.
 //
 // Arguments:
index 20eb585..8c87bc1 100644 (file)
@@ -1503,18 +1503,13 @@ void CodeGen::genCodeForMulHi(GenTreeOp* treeNode)
     {
         inst_RV_RV(INS_mov, targetReg, REG_RDX, targetType);
     }
+
+    genProduceReg(treeNode);
 #else  // !0
     NYI("genCodeForMulHi");
 #endif // !0
 }
 
-// generate code for a DIV or MOD operation
-//
-void CodeGen::genCodeForDivMod(GenTreeOp* treeNode)
-{
-    // unused on ARM64
-}
-
 // Generate code for ADD, SUB, MUL, DIV, UDIV, AND, OR and XOR
 // This method is expected to have called genConsumeOperands() before calling it.
 void CodeGen::genCodeForBinary(GenTree* treeNode)
@@ -1942,6 +1937,11 @@ void CodeGen::genReturn(GenTreePtr treeNode)
     GenTreePtr op1        = treeNode->gtGetOp1();
     var_types  targetType = treeNode->TypeGet();
 
+    // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in the return
+    // register, if it's not already there. The processing is the same as GT_RETURN. For filters, the IL spec says the
+    // result is type int32. Further, the only legal values are 0 or 1; the use of other values is "undefined".
+    assert(!treeNode->OperIs(GT_RETFILT) || (targetType == TYP_VOID) || (targetType == TYP_INT));
+
 #ifdef DEBUG
     if (targetType == TYP_VOID)
     {
@@ -2011,539 +2011,6 @@ void CodeGen::genReturn(GenTreePtr treeNode)
 #endif
 }
 
-/*****************************************************************************
- *
- * Generate code for a single node in the tree.
- * Preconditions: All operands have been evaluated
- *
- */
-void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
-{
-    regNumber targetReg  = treeNode->gtRegNum;
-    var_types targetType = treeNode->TypeGet();
-    emitter*  emit       = getEmitter();
-
-#ifdef DEBUG
-    // Validate that all the operands for the current node are consumed in order.
-    // This is important because LSRA ensures that any necessary copies will be
-    // handled correctly.
-    lastConsumedNode = nullptr;
-    if (compiler->verbose)
-    {
-        unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
-        compiler->gtDispLIRNode(treeNode, "Generating: ");
-    }
-#endif // DEBUG
-
-    // Is this a node whose value is already in a register?  LSRA denotes this by
-    // setting the GTF_REUSE_REG_VAL flag.
-    if (treeNode->IsReuseRegVal())
-    {
-        // For now, this is only used for constant nodes.
-        assert((treeNode->OperGet() == GT_CNS_INT) || (treeNode->OperGet() == GT_CNS_DBL));
-        JITDUMP("  TreeNode is marked ReuseReg\n");
-        return;
-    }
-
-    // contained nodes are part of their parents for codegen purposes
-    // ex : immediates, most LEAs
-    if (treeNode->isContained())
-    {
-        return;
-    }
-
-    switch (treeNode->gtOper)
-    {
-        case GT_START_NONGC:
-            getEmitter()->emitDisableGC();
-            break;
-
-        case GT_PROF_HOOK:
-            // We should be seeing this only if profiler hook is needed
-            noway_assert(compiler->compIsProfilerHookNeeded());
-
-#ifdef PROFILING_SUPPORTED
-            // Right now this node is used only for tail calls. In future if
-            // we intend to use it for Enter or Leave hooks, add a data member
-            // to this node indicating the kind of profiler hook. For example,
-            // helper number can be used.
-            genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
-#endif // PROFILING_SUPPORTED
-            break;
-
-        case GT_LCLHEAP:
-            genLclHeap(treeNode);
-            break;
-
-        case GT_CNS_INT:
-        case GT_CNS_DBL:
-            genSetRegToConst(targetReg, targetType, treeNode);
-            genProduceReg(treeNode);
-            break;
-
-        case GT_NOT:
-        case GT_NEG:
-            genCodeForNegNot(treeNode);
-            break;
-
-        case GT_DIV:
-        case GT_UDIV:
-            genConsumeOperands(treeNode->AsOp());
-
-            if (varTypeIsFloating(targetType))
-            {
-                // Floating point divide never raises an exception
-                genCodeForBinary(treeNode);
-            }
-            else // an integer divide operation
-            {
-                GenTreePtr divisorOp = treeNode->gtGetOp2();
-                emitAttr   size      = EA_ATTR(genTypeSize(genActualType(treeNode->TypeGet())));
-
-                if (divisorOp->IsIntegralConst(0))
-                {
-                    // We unconditionally throw a divide by zero exception
-                    genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);
-
-                    // We still need to call genProduceReg
-                    genProduceReg(treeNode);
-                }
-                else // the divisor is not the constant zero
-                {
-                    regNumber divisorReg = divisorOp->gtRegNum;
-
-                    // Generate the require runtime checks for GT_DIV or GT_UDIV
-                    if (treeNode->gtOper == GT_DIV)
-                    {
-                        BasicBlock* sdivLabel = genCreateTempLabel();
-
-                        // Two possible exceptions:
-                        //     (AnyVal /  0) => DivideByZeroException
-                        //     (MinInt / -1) => ArithmeticException
-                        //
-                        bool checkDividend = true;
-
-                        // Do we have an immediate for the 'divisorOp'?
-                        //
-                        if (divisorOp->IsCnsIntOrI())
-                        {
-                            GenTreeIntConCommon* intConstTree  = divisorOp->AsIntConCommon();
-                            ssize_t              intConstValue = intConstTree->IconValue();
-                            assert(intConstValue != 0); // already checked above by IsIntegralConst(0))
-                            if (intConstValue != -1)
-                            {
-                                checkDividend = false; // We statically know that the dividend is not -1
-                            }
-                        }
-                        else // insert check for divison by zero
-                        {
-                            // Check if the divisor is zero throw a DivideByZeroException
-                            emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
-                            emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
-                            genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
-                        }
-
-                        if (checkDividend)
-                        {
-                            // Check if the divisor is not -1 branch to 'sdivLabel'
-                            emit->emitIns_R_I(INS_cmp, size, divisorReg, -1);
-
-                            emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
-                            inst_JMP(jmpNotEqual, sdivLabel);
-                            // If control flow continues past here the 'divisorReg' is known to be -1
-
-                            regNumber dividendReg = treeNode->gtGetOp1()->gtRegNum;
-                            // At this point the divisor is known to be -1
-                            //
-                            // Issue the 'adds  zr, dividendReg, dividendReg' instruction
-                            // this will set both the Z and V flags only when dividendReg is MinInt
-                            //
-                            emit->emitIns_R_R_R(INS_adds, size, REG_ZR, dividendReg, dividendReg);
-                            inst_JMP(jmpNotEqual, sdivLabel);             // goto sdiv if the Z flag is clear
-                            genJumpToThrowHlpBlk(EJ_vs, SCK_ARITH_EXCPN); // if the V flags is set throw
-                                                                          // ArithmeticException
-
-                            genDefineTempLabel(sdivLabel);
-                        }
-                        genCodeForBinary(treeNode); // Generate the sdiv instruction
-                    }
-                    else // (treeNode->gtOper == GT_UDIV)
-                    {
-                        // Only one possible exception
-                        //     (AnyVal /  0) => DivideByZeroException
-                        //
-                        // Note that division by the constant 0 was already checked for above by the
-                        // op2->IsIntegralConst(0) check
-                        //
-                        if (!divisorOp->IsCnsIntOrI())
-                        {
-                            // divisorOp is not a constant, so it could be zero
-                            //
-                            emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
-                            emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
-                            genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
-                        }
-                        genCodeForBinary(treeNode);
-                    }
-                }
-            }
-            break;
-
-        case GT_OR:
-        case GT_XOR:
-        case GT_AND:
-            assert(varTypeIsIntegralOrI(treeNode));
-            __fallthrough;
-        case GT_ADD:
-        case GT_SUB:
-        case GT_MUL:
-            genConsumeOperands(treeNode->AsOp());
-            genCodeForBinary(treeNode);
-            break;
-
-        case GT_LSH:
-        case GT_RSH:
-        case GT_RSZ:
-        case GT_ROR:
-            genCodeForShift(treeNode);
-            // genCodeForShift() calls genProduceReg()
-            break;
-
-        case GT_CAST:
-            if (varTypeIsFloating(targetType) && varTypeIsFloating(treeNode->gtOp.gtOp1))
-            {
-                // Casts float/double <--> double/float
-                genFloatToFloatCast(treeNode);
-            }
-            else if (varTypeIsFloating(treeNode->gtOp.gtOp1))
-            {
-                // Casts float/double --> int32/int64
-                genFloatToIntCast(treeNode);
-            }
-            else if (varTypeIsFloating(targetType))
-            {
-                // Casts int32/uint32/int64/uint64 --> float/double
-                genIntToFloatCast(treeNode);
-            }
-            else
-            {
-                // Casts int <--> int
-                genIntToIntCast(treeNode);
-            }
-            // The per-case functions call genProduceReg()
-            break;
-
-        case GT_LCL_FLD_ADDR:
-        case GT_LCL_VAR_ADDR:
-            // Address of a local var.  This by itself should never be allocated a register.
-            // If it is worth storing the address in a register then it should be cse'ed into
-            // a temp and that would be allocated a register.
-            noway_assert(targetType == TYP_BYREF);
-            noway_assert(!treeNode->InReg());
-
-            inst_RV_TT(INS_lea, targetReg, treeNode, 0, EA_BYREF);
-            genProduceReg(treeNode);
-            break;
-
-        case GT_LCL_FLD:
-            genCodeForLclFld(treeNode->AsLclFld());
-            break;
-
-        case GT_LCL_VAR:
-            genCodeForLclVar(treeNode->AsLclVar());
-            break;
-
-        case GT_STORE_LCL_FLD:
-            genCodeForStoreLclFld(treeNode->AsLclFld());
-            break;
-
-        case GT_STORE_LCL_VAR:
-            genCodeForStoreLclVar(treeNode->AsLclVar());
-            break;
-
-        case GT_RETFILT:
-            // A void GT_RETFILT is the end of a finally. For non-void filter returns we need to load the result in
-            // the return register, if it's not already there. The processing is the same as GT_RETURN.
-            if (targetType != TYP_VOID)
-            {
-                // For filters, the IL spec says the result is type int32. Further, the only specified legal values
-                // are 0 or 1, with the use of other values "undefined".
-                assert(targetType == TYP_INT);
-            }
-
-            __fallthrough;
-
-        case GT_RETURN:
-            genReturn(treeNode);
-            break;
-
-        case GT_LEA:
-            // if we are here, it is the case where there is an LEA that cannot
-            // be folded into a parent instruction
-            genLeaInstruction(treeNode->AsAddrMode());
-            break;
-
-        case GT_IND:
-            genConsumeAddress(treeNode->AsIndir()->Addr());
-            emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(treeNode), targetReg, treeNode->AsIndir());
-            genProduceReg(treeNode);
-            break;
-
-        case GT_MULHI:
-            genCodeForMulHi(treeNode->AsOp());
-            genProduceReg(treeNode);
-            break;
-
-        case GT_MOD:
-        case GT_UMOD:
-            // Integer MOD should have been morphed into a sequence of sub, mul, div in fgMorph.
-            //
-            // We shouldn't be seeing GT_MOD on float/double as it is morphed into a helper call by front-end.
-            noway_assert(!"Codegen for GT_MOD/GT_UMOD");
-            break;
-
-        case GT_INTRINSIC:
-            genIntrinsic(treeNode);
-            break;
-
-#ifdef FEATURE_SIMD
-        case GT_SIMD:
-            genSIMDIntrinsic(treeNode->AsSIMD());
-            break;
-#endif // FEATURE_SIMD
-
-        case GT_CKFINITE:
-            genCkfinite(treeNode);
-            break;
-
-        case GT_EQ:
-        case GT_NE:
-        case GT_LT:
-        case GT_LE:
-        case GT_GE:
-        case GT_GT:
-            genCodeForCompare(treeNode->AsOp());
-            break;
-
-        case GT_JTRUE:
-            genCodeForJumpTrue(treeNode);
-            break;
-
-        case GT_RETURNTRAP:
-            genCodeForReturnTrap(treeNode->AsOp());
-            break;
-
-        case GT_STOREIND:
-            genCodeForStoreInd(treeNode->AsStoreInd());
-            break;
-
-        case GT_COPY:
-            // This is handled at the time we call genConsumeReg() on the GT_COPY
-            break;
-
-        case GT_SWAP:
-            genCodeForSwap(treeNode->AsOp());
-            break;
-
-        case GT_LIST:
-        case GT_FIELD_LIST:
-        case GT_ARGPLACE:
-            // Nothing to do
-            break;
-
-        case GT_PUTARG_STK:
-            genPutArgStk(treeNode->AsPutArgStk());
-            break;
-
-        case GT_PUTARG_REG:
-            genPutArgReg(treeNode->AsOp());
-            break;
-
-        case GT_CALL:
-            genCallInstruction(treeNode->AsCall());
-            break;
-
-        case GT_JMP:
-            genJmpMethod(treeNode);
-            break;
-
-        case GT_LOCKADD:
-        case GT_XCHG:
-        case GT_XADD:
-            genLockedInstructions(treeNode->AsOp());
-            break;
-
-        case GT_MEMORYBARRIER:
-            instGen_MemoryBarrier();
-            break;
-
-        case GT_CMPXCHG:
-            NYI("GT_CMPXCHG");
-            break;
-
-        case GT_RELOAD:
-            // do nothing - reload is just a marker.
-            // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
-            // into the register specified in this node.
-            break;
-
-        case GT_NOP:
-            break;
-
-        case GT_NO_OP:
-            if (treeNode->gtFlags & GTF_NO_OP_NO)
-            {
-                noway_assert(!"GTF_NO_OP_NO should not be set");
-            }
-            else
-            {
-                instGen(INS_nop);
-            }
-            break;
-
-        case GT_ARR_BOUNDS_CHECK:
-#ifdef FEATURE_SIMD
-        case GT_SIMD_CHK:
-#endif // FEATURE_SIMD
-            genRangeCheck(treeNode);
-            break;
-
-        case GT_PHYSREG:
-            if (targetReg != treeNode->AsPhysReg()->gtSrcReg)
-            {
-                inst_RV_RV(ins_Copy(targetType), targetReg, treeNode->AsPhysReg()->gtSrcReg, targetType);
-
-                genTransferRegGCState(targetReg, treeNode->AsPhysReg()->gtSrcReg);
-            }
-            genProduceReg(treeNode);
-            break;
-
-        case GT_PHYSREGDST:
-            break;
-
-        case GT_NULLCHECK:
-        {
-            assert(!treeNode->gtOp.gtOp1->isContained());
-            regNumber reg = genConsumeReg(treeNode->gtOp.gtOp1);
-            emit->emitIns_R_R_I(INS_ldr, EA_4BYTE, REG_ZR, reg, 0);
-        }
-        break;
-
-        case GT_CATCH_ARG:
-
-            noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
-
-            /* Catch arguments get passed in a register. genCodeForBBlist()
-               would have marked it as holding a GC object, but not used. */
-
-            noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
-            genConsumeReg(treeNode);
-            break;
-
-        case GT_PINVOKE_PROLOG:
-            noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
-
-            // the runtime side requires the codegen here to be consistent
-            emit->emitDisableRandomNops();
-            break;
-
-        case GT_LABEL:
-            genPendingCallLabel       = genCreateTempLabel();
-            treeNode->gtLabel.gtLabBB = genPendingCallLabel;
-
-            // For long address (default): `adrp + add` will be emitted.
-            // For short address (proven later): `adr` will be emitted.
-            emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
-            break;
-
-        case GT_STORE_OBJ:
-            if (treeNode->OperIsCopyBlkOp())
-            {
-                assert(treeNode->AsObj()->gtGcPtrCount != 0);
-                genCodeForCpObj(treeNode->AsObj());
-                break;
-            }
-            __fallthrough;
-
-        case GT_STORE_DYN_BLK:
-        case GT_STORE_BLK:
-        {
-            GenTreeBlk* blkOp = treeNode->AsBlk();
-            if (blkOp->gtBlkOpGcUnsafe)
-            {
-                getEmitter()->emitDisableGC();
-            }
-            bool isCopyBlk = blkOp->OperIsCopyBlkOp();
-
-            switch (blkOp->gtBlkOpKind)
-            {
-                case GenTreeBlk::BlkOpKindHelper:
-                    if (isCopyBlk)
-                    {
-                        genCodeForCpBlk(blkOp);
-                    }
-                    else
-                    {
-                        genCodeForInitBlk(blkOp);
-                    }
-                    break;
-                case GenTreeBlk::BlkOpKindUnroll:
-                    if (isCopyBlk)
-                    {
-                        genCodeForCpBlkUnroll(blkOp);
-                    }
-                    else
-                    {
-                        genCodeForInitBlkUnroll(blkOp);
-                    }
-                    break;
-                default:
-                    unreached();
-            }
-            if (blkOp->gtBlkOpGcUnsafe)
-            {
-                getEmitter()->emitEnableGC();
-            }
-        }
-        break;
-
-        case GT_JMPTABLE:
-            genJumpTable(treeNode);
-            break;
-
-        case GT_SWITCH_TABLE:
-            genTableBasedSwitch(treeNode);
-            break;
-
-        case GT_ARR_INDEX:
-            genCodeForArrIndex(treeNode->AsArrIndex());
-            break;
-
-        case GT_ARR_OFFSET:
-            genCodeForArrOffset(treeNode->AsArrOffs());
-            break;
-
-        case GT_CLS_VAR_ADDR:
-            NYI("GT_CLS_VAR_ADDR");
-            break;
-
-        case GT_IL_OFFSET:
-            // Do nothing; these nodes are simply markers for debug info.
-            break;
-
-        default:
-        {
-#ifdef DEBUG
-            char message[256];
-            _snprintf_s(message, _countof(message), _TRUNCATE, "Unimplemented node type %s\n",
-                        GenTree::NodeName(treeNode->OperGet()));
-#endif
-            assert(!"Unknown node in codegen");
-        }
-        break;
-    }
-}
-
 /***********************************************************************************************
  *  Generate code for localloc
  */
@@ -2915,6 +2382,122 @@ void CodeGen::genCodeForNegNot(GenTree* tree)
     genProduceReg(tree);
 }
 
+//------------------------------------------------------------------------
+// genCodeForDivMod: Produce code for a GT_DIV/GT_UDIV node. We don't see MOD:
+// (1) integer MOD is morphed into a sequence of sub, mul, div in fgMorph;
+// (2) float/double MOD is morphed into a helper call by front-end.
+//
+// Arguments:
+//    tree - the node
+//
+void CodeGen::genCodeForDivMod(GenTreeOp* tree)
+{
+    assert(tree->OperIs(GT_DIV, GT_UDIV));
+
+    var_types targetType = tree->TypeGet();
+    emitter*  emit       = getEmitter();
+
+    genConsumeOperands(tree);
+
+    if (varTypeIsFloating(targetType))
+    {
+        // Floating point divide never raises an exception
+        genCodeForBinary(tree);
+    }
+    else // an integer divide operation
+    {
+        GenTreePtr divisorOp = tree->gtGetOp2();
+        emitAttr   size      = EA_ATTR(genTypeSize(genActualType(tree->TypeGet())));
+
+        if (divisorOp->IsIntegralConst(0))
+        {
+            // We unconditionally throw a divide by zero exception
+            genJumpToThrowHlpBlk(EJ_jmp, SCK_DIV_BY_ZERO);
+
+            // We still need to call genProduceReg
+            genProduceReg(tree);
+        }
+        else // the divisor is not the constant zero
+        {
+            regNumber divisorReg = divisorOp->gtRegNum;
+
+            // Generate the require runtime checks for GT_DIV or GT_UDIV
+            if (tree->gtOper == GT_DIV)
+            {
+                BasicBlock* sdivLabel = genCreateTempLabel();
+
+                // Two possible exceptions:
+                //     (AnyVal /  0) => DivideByZeroException
+                //     (MinInt / -1) => ArithmeticException
+                //
+                bool checkDividend = true;
+
+                // Do we have an immediate for the 'divisorOp'?
+                //
+                if (divisorOp->IsCnsIntOrI())
+                {
+                    GenTreeIntConCommon* intConstTree  = divisorOp->AsIntConCommon();
+                    ssize_t              intConstValue = intConstTree->IconValue();
+                    assert(intConstValue != 0); // already checked above by IsIntegralConst(0))
+                    if (intConstValue != -1)
+                    {
+                        checkDividend = false; // We statically know that the dividend is not -1
+                    }
+                }
+                else // insert check for divison by zero
+                {
+                    // Check if the divisor is zero throw a DivideByZeroException
+                    emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
+                    emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+                    genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
+                }
+
+                if (checkDividend)
+                {
+                    // Check if the divisor is not -1 branch to 'sdivLabel'
+                    emit->emitIns_R_I(INS_cmp, size, divisorReg, -1);
+
+                    emitJumpKind jmpNotEqual = genJumpKindForOper(GT_NE, CK_SIGNED);
+                    inst_JMP(jmpNotEqual, sdivLabel);
+                    // If control flow continues past here the 'divisorReg' is known to be -1
+
+                    regNumber dividendReg = tree->gtGetOp1()->gtRegNum;
+                    // At this point the divisor is known to be -1
+                    //
+                    // Issue the 'adds  zr, dividendReg, dividendReg' instruction
+                    // this will set both the Z and V flags only when dividendReg is MinInt
+                    //
+                    emit->emitIns_R_R_R(INS_adds, size, REG_ZR, dividendReg, dividendReg);
+                    inst_JMP(jmpNotEqual, sdivLabel);             // goto sdiv if the Z flag is clear
+                    genJumpToThrowHlpBlk(EJ_vs, SCK_ARITH_EXCPN); // if the V flags is set throw
+                                                                  // ArithmeticException
+
+                    genDefineTempLabel(sdivLabel);
+                }
+                genCodeForBinary(tree); // Generate the sdiv instruction
+            }
+            else // (tree->gtOper == GT_UDIV)
+            {
+                // Only one possible exception
+                //     (AnyVal /  0) => DivideByZeroException
+                //
+                // Note that division by the constant 0 was already checked for above by the
+                // op2->IsIntegralConst(0) check
+                //
+                if (!divisorOp->IsCnsIntOrI())
+                {
+                    // divisorOp is not a constant, so it could be zero
+                    //
+                    emit->emitIns_R_I(INS_cmp, size, divisorReg, 0);
+                    emitJumpKind jmpEqual = genJumpKindForOper(GT_EQ, CK_SIGNED);
+                    genJumpToThrowHlpBlk(jmpEqual, SCK_DIV_BY_ZERO);
+                }
+                genCodeForBinary(tree);
+            }
+        }
+    }
+}
+
 // Generate code for InitBlk by performing a loop unroll
 // Preconditions:
 //   a) Both the size and fill byte value are integer constants.
index ae8b4cc..aea4327 100644 (file)
@@ -25,6 +25,378 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 #include "emit.h"
 
 //------------------------------------------------------------------------
+// genCodeForTreeNode Generate code for a single node in the tree.
+//
+// Preconditions:
+//    All operands have been evaluated.
+//
+void CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
+{
+    regNumber targetReg  = treeNode->gtRegNum;
+    var_types targetType = treeNode->TypeGet();
+    emitter*  emit       = getEmitter();
+
+#ifdef DEBUG
+    // Validate that all the operands for the current node are consumed in order.
+    // This is important because LSRA ensures that any necessary copies will be
+    // handled correctly.
+    lastConsumedNode = nullptr;
+    if (compiler->verbose)
+    {
+        unsigned seqNum = treeNode->gtSeqNum; // Useful for setting a conditional break in Visual Studio
+        compiler->gtDispLIRNode(treeNode, "Generating: ");
+    }
+#endif // DEBUG
+
+#ifdef _TARGET_ARM64_ // TODO-ARM: is this applicable to ARM32?
+    // Is this a node whose value is already in a register?  LSRA denotes this by
+    // setting the GTF_REUSE_REG_VAL flag.
+    if (treeNode->IsReuseRegVal())
+    {
+        // For now, this is only used for constant nodes.
+        assert((treeNode->OperGet() == GT_CNS_INT) || (treeNode->OperGet() == GT_CNS_DBL));
+        JITDUMP("  TreeNode is marked ReuseReg\n");
+        return;
+    }
+#endif // _TARGET_ARM64_
+
+    // contained nodes are part of their parents for codegen purposes
+    // ex : immediates, most LEAs
+    if (treeNode->isContained())
+    {
+        return;
+    }
+
+    switch (treeNode->gtOper)
+    {
+#ifdef _TARGET_ARM64_
+
+        case GT_START_NONGC:
+            getEmitter()->emitDisableGC();
+            break;
+
+        case GT_PROF_HOOK:
+            // We should be seeing this only if profiler hook is needed
+            noway_assert(compiler->compIsProfilerHookNeeded());
+
+#ifdef PROFILING_SUPPORTED
+            // Right now this node is used only for tail calls. In future if
+            // we intend to use it for Enter or Leave hooks, add a data member
+            // to this node indicating the kind of profiler hook. For example,
+            // helper number can be used.
+            genProfilingLeaveCallback(CORINFO_HELP_PROF_FCN_TAILCALL);
+#endif // PROFILING_SUPPORTED
+            break;
+
+#endif // _TARGET_ARM64_
+
+        case GT_LCLHEAP:
+            genLclHeap(treeNode);
+            break;
+
+        case GT_CNS_INT:
+        case GT_CNS_DBL:
+            genSetRegToConst(targetReg, targetType, treeNode);
+            genProduceReg(treeNode);
+            break;
+
+        case GT_NOT:
+        case GT_NEG:
+            genCodeForNegNot(treeNode);
+            break;
+
+        case GT_MOD:
+        case GT_UMOD:
+        case GT_DIV:
+        case GT_UDIV:
+            genCodeForDivMod(treeNode->AsOp());
+            break;
+
+        case GT_OR:
+        case GT_XOR:
+        case GT_AND:
+            assert(varTypeIsIntegralOrI(treeNode));
+
+            __fallthrough;
+
+#ifdef _TARGET_ARM_
+        case GT_ADD_LO:
+        case GT_ADD_HI:
+        case GT_SUB_LO:
+        case GT_SUB_HI:
+#endif // _TARGET_ARM_
+
+        case GT_ADD:
+        case GT_SUB:
+        case GT_MUL:
+            genConsumeOperands(treeNode->AsOp());
+            genCodeForBinary(treeNode);
+            break;
+
+        case GT_LSH:
+        case GT_RSH:
+        case GT_RSZ:
+        case GT_ROR:
+            genCodeForShift(treeNode);
+            break;
+
+#ifdef _TARGET_ARM_
+
+        case GT_LSH_HI:
+        case GT_RSH_LO:
+            genCodeForShiftLong(treeNode);
+            break;
+
+#endif // _TARGET_ARM_
+
+        case GT_CAST:
+            genCodeForCast(treeNode->AsOp());
+            break;
+
+        case GT_LCL_FLD_ADDR:
+        case GT_LCL_VAR_ADDR:
+            genCodeForLclAddr(treeNode);
+            break;
+
+        case GT_LCL_FLD:
+            genCodeForLclFld(treeNode->AsLclFld());
+            break;
+
+        case GT_LCL_VAR:
+            genCodeForLclVar(treeNode->AsLclVar());
+            break;
+
+        case GT_STORE_LCL_FLD:
+            genCodeForStoreLclFld(treeNode->AsLclFld());
+            break;
+
+        case GT_STORE_LCL_VAR:
+            genCodeForStoreLclVar(treeNode->AsLclVar());
+            break;
+
+        case GT_RETFILT:
+        case GT_RETURN:
+            genReturn(treeNode);
+            break;
+
+        case GT_LEA:
+            // if we are here, it is the case where there is an LEA that cannot
+            // be folded into a parent instruction
+            genLeaInstruction(treeNode->AsAddrMode());
+            break;
+
+        case GT_IND:
+            genCodeForIndir(treeNode->AsIndir());
+            break;
+
+#ifdef _TARGET_ARM64_
+
+        case GT_MULHI:
+            genCodeForMulHi(treeNode->AsOp());
+            break;
+
+        case GT_CKFINITE:
+            genCkfinite(treeNode);
+            break;
+
+        case GT_SWAP:
+            genCodeForSwap(treeNode->AsOp());
+            break;
+
+        case GT_JMP:
+            genJmpMethod(treeNode);
+            break;
+
+#endif // _TARGET_ARM64_
+
+        case GT_INTRINSIC:
+            genIntrinsic(treeNode);
+            break;
+
+#ifdef FEATURE_SIMD
+        case GT_SIMD:
+            genSIMDIntrinsic(treeNode->AsSIMD());
+            break;
+#endif // FEATURE_SIMD
+
+        case GT_EQ:
+        case GT_NE:
+        case GT_LT:
+        case GT_LE:
+        case GT_GE:
+        case GT_GT:
+            genCodeForCompare(treeNode->AsOp());
+            break;
+
+        case GT_JTRUE:
+            genCodeForJumpTrue(treeNode);
+            break;
+
+#ifdef _TARGET_ARM_
+
+        case GT_JCC:
+            genCodeForJcc(treeNode->AsJumpCC());
+            break;
+
+#endif // _TARGET_ARM_
+
+        case GT_RETURNTRAP:
+            genCodeForReturnTrap(treeNode->AsOp());
+            break;
+
+        case GT_STOREIND:
+            genCodeForStoreInd(treeNode->AsStoreInd());
+            break;
+
+        case GT_COPY:
+            // This is handled at the time we call genConsumeReg() on the GT_COPY
+            break;
+
+        case GT_LIST:
+        case GT_FIELD_LIST:
+        case GT_ARGPLACE:
+            // Nothing to do
+            break;
+
+        case GT_PUTARG_STK:
+            genPutArgStk(treeNode->AsPutArgStk());
+            break;
+
+        case GT_PUTARG_REG:
+            genPutArgReg(treeNode->AsOp());
+            break;
+
+        case GT_CALL:
+            genCallInstruction(treeNode->AsCall());
+            break;
+
+        case GT_LOCKADD:
+        case GT_XCHG:
+        case GT_XADD:
+            genLockedInstructions(treeNode->AsOp());
+            break;
+
+        case GT_MEMORYBARRIER:
+            instGen_MemoryBarrier();
+            break;
+
+        case GT_CMPXCHG:
+            NYI("GT_CMPXCHG");
+            break;
+
+        case GT_RELOAD:
+            // do nothing - reload is just a marker.
+            // The parent node will call genConsumeReg on this which will trigger the unspill of this node's child
+            // into the register specified in this node.
+            break;
+
+        case GT_NOP:
+            break;
+
+        case GT_NO_OP:
+            if (treeNode->gtFlags & GTF_NO_OP_NO)
+            {
+                noway_assert(!"GTF_NO_OP_NO should not be set");
+            }
+            else
+            {
+                instGen(INS_nop);
+            }
+            break;
+
+        case GT_ARR_BOUNDS_CHECK:
+#ifdef FEATURE_SIMD
+        case GT_SIMD_CHK:
+#endif // FEATURE_SIMD
+            genRangeCheck(treeNode);
+            break;
+
+        case GT_PHYSREG:
+            genCodeForPhysReg(treeNode->AsPhysReg());
+            break;
+
+        case GT_PHYSREGDST:
+            break;
+
+        case GT_NULLCHECK:
+            genCodeForNullCheck(treeNode->AsOp());
+            break;
+
+        case GT_CATCH_ARG:
+
+            noway_assert(handlerGetsXcptnObj(compiler->compCurBB->bbCatchTyp));
+
+            /* Catch arguments get passed in a register. genCodeForBBlist()
+               would have marked it as holding a GC object, but not used. */
+
+            noway_assert(gcInfo.gcRegGCrefSetCur & RBM_EXCEPTION_OBJECT);
+            genConsumeReg(treeNode);
+            break;
+
+        case GT_PINVOKE_PROLOG:
+            noway_assert(((gcInfo.gcRegGCrefSetCur | gcInfo.gcRegByrefSetCur) & ~fullIntArgRegMask()) == 0);
+
+            // the runtime side requires the codegen here to be consistent
+            emit->emitDisableRandomNops();
+            break;
+
+        case GT_LABEL:
+            genPendingCallLabel       = genCreateTempLabel();
+            treeNode->gtLabel.gtLabBB = genPendingCallLabel;
+            emit->emitIns_R_L(INS_adr, EA_PTRSIZE, genPendingCallLabel, targetReg);
+            break;
+
+        case GT_STORE_OBJ:
+        case GT_STORE_DYN_BLK:
+        case GT_STORE_BLK:
+            genCodeForStoreBlk(treeNode->AsBlk());
+            break;
+
+        case GT_JMPTABLE:
+            genJumpTable(treeNode);
+            break;
+
+        case GT_SWITCH_TABLE:
+            genTableBasedSwitch(treeNode);
+            break;
+
+        case GT_ARR_INDEX:
+            genCodeForArrIndex(treeNode->AsArrIndex());
+            break;
+
+        case GT_ARR_OFFSET:
+            genCodeForArrOffset(treeNode->AsArrOffs());
+            break;
+
+#ifdef _TARGET_ARM_
+
+        case GT_CLS_VAR_ADDR:
+            emit->emitIns_R_C(INS_lea, EA_PTRSIZE, targetReg, treeNode->gtClsVar.gtClsVarHnd, 0);
+            genProduceReg(treeNode);
+            break;
+
+#endif // _TARGET_ARM_
+
+        case GT_IL_OFFSET:
+            // Do nothing; these nodes are simply markers for debug info.
+            break;
+
+        default:
+        {
+#ifdef DEBUG
+            char message[256];
+            _snprintf_s(message, _countof(message), _TRUNCATE, "NYI: Unimplemented node type %s",
+                        GenTree::NodeName(treeNode->OperGet()));
+            NYIRAW(message);
+#else
+            NYI("unimplemented node");
+#endif
+        }
+        break;
+    }
+}
+
+//------------------------------------------------------------------------
 // genSetRegToIcon: Generate code that will set the given register to the integer constant.
 //
 void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFlags flags)
@@ -51,6 +423,8 @@ void CodeGen::genSetRegToIcon(regNumber reg, ssize_t val, var_types type, insFla
 //
 void CodeGen::genIntrinsic(GenTreePtr treeNode)
 {
+    assert(treeNode->OperIs(GT_INTRINSIC));
+
     // Both operand and its result must be of the same floating point type.
     GenTreePtr srcNode = treeNode->gtOp.gtOp1;
     assert(varTypeIsFloating(srcNode));
@@ -459,7 +833,7 @@ void CodeGen::genPutArgStk(GenTreePutArgStk* treeNode)
 // genPutArgReg - generate code for a GT_PUTARG_REG node
 //
 // Arguments
-//    treeNode - the GT_PUTARG_REG node
+//    tree - the GT_PUTARG_REG node
 //
 // Return value:
 //    None
@@ -607,6 +981,54 @@ void CodeGen::genRangeCheck(GenTreePtr oper)
     genJumpToThrowHlpBlk(jmpKind, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
 }
 
+//---------------------------------------------------------------------
+// genCodeForPhysReg - generate code for a GT_PHYSREG node
+//
+// Arguments
+//    tree - the GT_PHYSREG node
+//
+// Return value:
+//    None
+//
+void CodeGen::genCodeForPhysReg(GenTreePhysReg* tree)
+{
+    assert(tree->OperIs(GT_PHYSREG));
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+
+    if (targetReg != tree->gtSrcReg)
+    {
+        inst_RV_RV(ins_Copy(targetType), targetReg, tree->gtSrcReg, targetType);
+        genTransferRegGCState(targetReg, tree->gtSrcReg);
+    }
+
+    genProduceReg(tree);
+}
+
+//---------------------------------------------------------------------
+// genCodeForNullCheck - generate code for a GT_NULLCHECK node
+//
+// Arguments
+//    tree - the GT_NULLCHECK node
+//
+// Return value:
+//    None
+//
+void CodeGen::genCodeForNullCheck(GenTreeOp* tree)
+{
+    assert(tree->OperIs(GT_NULLCHECK));
+    assert(!tree->gtOp1->isContained());
+    regNumber addrReg = genConsumeReg(tree->gtOp1);
+
+#ifdef _TARGET_ARM64_
+    regNumber targetReg = REG_ZR;
+#else
+    regNumber targetReg = tree->gtRegNum;
+#endif
+
+    getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, targetReg, addrReg, 0);
+}
+
 //------------------------------------------------------------------------
 // genOffsetOfMDArrayLowerBound: Returns the offset from the Array object to the
 //   lower bound for the given dimension.
@@ -815,6 +1237,68 @@ void CodeGen::genCodeForShift(GenTreePtr tree)
 }
 
 //------------------------------------------------------------------------
+// genCodeForCast: Generates the code for GT_CAST.
+//
+// Arguments:
+//    tree - the GT_CAST node.
+//
+void CodeGen::genCodeForCast(GenTreeOp* tree)
+{
+    assert(tree->OperIs(GT_CAST));
+
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+
+    // Cast is never contained (?)
+    noway_assert(targetReg != REG_NA);
+
+    if (varTypeIsFloating(targetType) && varTypeIsFloating(tree->gtOp1))
+    {
+        // Casts float/double <--> double/float
+        genFloatToFloatCast(tree);
+    }
+    else if (varTypeIsFloating(tree->gtOp1))
+    {
+        // Casts float/double --> int32/int64
+        genFloatToIntCast(tree);
+    }
+    else if (varTypeIsFloating(targetType))
+    {
+        // Casts int32/uint32/int64/uint64 --> float/double
+        genIntToFloatCast(tree);
+    }
+    else
+    {
+        // Casts int <--> int
+        genIntToIntCast(tree);
+    }
+    // The per-case functions call genProduceReg()
+}
+
+//------------------------------------------------------------------------
+// genCodeForLclAddr: Generates the code for GT_LCL_FLD_ADDR/GT_LCL_VAR_ADDR.
+//
+// Arguments:
+//    tree - the node.
+//
+void CodeGen::genCodeForLclAddr(GenTree* tree)
+{
+    assert(tree->OperIs(GT_LCL_FLD_ADDR, GT_LCL_VAR_ADDR));
+
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+
+    // Address of a local var.  This by itself should never be allocated a register.
+    // If it is worth storing the address in a register then it should be cse'ed into
+    // a temp and that would be allocated a register.
+    noway_assert(targetType == TYP_BYREF);
+    noway_assert(!tree->InReg());
+
+    inst_RV_TT(INS_lea, targetReg, tree, 0, EA_BYREF);
+    genProduceReg(tree);
+}
+
+//------------------------------------------------------------------------
 // genCodeForLclFld: Produce code for a GT_LCL_FLD node.
 //
 // Arguments:
@@ -822,6 +1306,8 @@ void CodeGen::genCodeForShift(GenTreePtr tree)
 //
 void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
 {
+    assert(tree->OperIs(GT_LCL_FLD));
+
     var_types targetType = tree->TypeGet();
     regNumber targetReg  = tree->gtRegNum;
     emitter*  emit       = getEmitter();
@@ -856,6 +1342,25 @@ void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
     genProduceReg(tree);
 }
 
+//------------------------------------------------------------------------
+// genCodeForIndir: Produce code for a GT_IND node.
+//
+// Arguments:
+//    tree - the GT_IND node
+//
+void CodeGen::genCodeForIndir(GenTreeIndir* tree)
+{
+    assert(tree->OperIs(GT_IND));
+
+    var_types targetType = tree->TypeGet();
+    regNumber targetReg  = tree->gtRegNum;
+    emitter*  emit       = getEmitter();
+
+    genConsumeAddress(tree->Addr());
+    emit->emitInsLoadStoreOp(ins_Load(targetType), emitTypeSize(tree), targetReg, tree);
+    genProduceReg(tree);
+}
+
 // Generate code for a CpBlk node by the means of the VM memcpy helper call
 // Preconditions:
 // a) The size argument of the CpBlk is not an integer constant
@@ -1833,6 +2338,69 @@ void CodeGen::genCodeForJumpTrue(GenTreePtr tree)
     }
 }
 
+//------------------------------------------------------------------------
+// genCodeForStoreBlk: Produce code for a GT_STORE_OBJ/GT_STORE_DYN_BLK/GT_STORE_BLK node.
+//
+// Arguments:
+//    tree - the node
+//
+void CodeGen::genCodeForStoreBlk(GenTreeBlk* blkOp)
+{
+    assert(blkOp->OperIs(GT_STORE_OBJ, GT_STORE_DYN_BLK, GT_STORE_BLK));
+
+#ifdef _TARGET_ARM_
+    NYI_IF(blkOp->OperIs(GT_STORE_OBJ), "GT_STORE_OBJ");
+#endif // _TARGET_ARM_
+
+#ifndef _TARGET_ARM_ // NYI for ARM
+    if (blkOp->OperIs(GT_STORE_OBJ) && blkOp->OperIsCopyBlkOp())
+    {
+        assert(blkOp->AsObj()->gtGcPtrCount != 0);
+        genCodeForCpObj(blkOp->AsObj());
+        return;
+    }
+#endif // !_TARGET_ARM_
+
+    if (blkOp->gtBlkOpGcUnsafe)
+    {
+        getEmitter()->emitDisableGC();
+    }
+    bool isCopyBlk = blkOp->OperIsCopyBlkOp();
+
+    switch (blkOp->gtBlkOpKind)
+    {
+        case GenTreeBlk::BlkOpKindHelper:
+            if (isCopyBlk)
+            {
+                genCodeForCpBlk(blkOp);
+            }
+            else
+            {
+                genCodeForInitBlk(blkOp);
+            }
+            break;
+
+        case GenTreeBlk::BlkOpKindUnroll:
+            if (isCopyBlk)
+            {
+                genCodeForCpBlkUnroll(blkOp);
+            }
+            else
+            {
+                genCodeForInitBlkUnroll(blkOp);
+            }
+            break;
+
+        default:
+            unreached();
+    }
+
+    if (blkOp->gtBlkOpGcUnsafe)
+    {
+        getEmitter()->emitEnableGC();
+    }
+}
+
 #endif // _TARGET_ARMARCH_
 
 #endif // !LEGACY_BACKEND
index d0281a0..3bd0eac 100644 (file)
@@ -11,9 +11,7 @@
 #ifndef LEGACY_BACKEND // Not necessary (it's this way in the #include location), but helpful to IntelliSense
 
 void genSetRegToConst(regNumber targetReg, var_types targetType, GenTreePtr tree);
-
 void genCodeForTreeNode(GenTreePtr treeNode);
-
 void genCodeForBinary(GenTreePtr treeNode);
 
 #if defined(_TARGET_X86_)
@@ -21,11 +19,8 @@ void genCodeForLongUMod(GenTreeOp* node);
 #endif // _TARGET_X86_
 
 void genCodeForDivMod(GenTreeOp* treeNode);
-
 void genCodeForMulHi(GenTreeOp* treeNode);
-
 void genLeaInstruction(GenTreeAddrMode* lea);
-
 void genSetRegToCond(regNumber dstReg, GenTreePtr tree);
 
 #if !defined(_TARGET_64BIT_)
@@ -33,21 +28,13 @@ void genLongToIntCast(GenTreePtr treeNode);
 #endif
 
 void genIntToIntCast(GenTreePtr treeNode);
-
 void genFloatToFloatCast(GenTreePtr treeNode);
-
 void genFloatToIntCast(GenTreePtr treeNode);
-
 void genIntToFloatCast(GenTreePtr treeNode);
-
 void genCkfinite(GenTreePtr treeNode);
-
 void genCodeForCompare(GenTreeOp* tree);
-
 void genIntrinsic(GenTreePtr treeNode);
-
 void genPutArgStk(GenTreePutArgStk* treeNode);
-
 void genPutArgReg(GenTreeOp* tree);
 
 #if defined(_TARGET_XARCH_)
@@ -59,7 +46,6 @@ unsigned getFirstArgWithStackSlot();
 #endif // _TARGET_XARCH_ || _TARGET_ARM64_
 
 void genCompareFloat(GenTreePtr treeNode);
-
 void genCompareInt(GenTreePtr treeNode);
 
 #if !defined(_TARGET_64BIT_)
@@ -94,7 +80,6 @@ void genSIMDIntrinsicGetItem(GenTreeSIMD* simdNode);
 void genSIMDIntrinsicShuffleSSE2(GenTreeSIMD* simdNode);
 void genSIMDIntrinsicUpperSave(GenTreeSIMD* simdNode);
 void genSIMDIntrinsicUpperRestore(GenTreeSIMD* simdNode);
-
 void genSIMDIntrinsic(GenTreeSIMD* simdNode);
 void genSIMDCheck(GenTree* treeNode);
 
@@ -122,11 +107,8 @@ void genStoreLongLclVar(GenTree* treeNode);
 #endif // !defined(_TARGET_64BIT_)
 
 void genProduceReg(GenTree* tree);
-
 void genUnspillRegIfNeeded(GenTree* tree);
-
 regNumber genConsumeReg(GenTree* tree);
-
 void genCopyRegIfNeeded(GenTree* tree, regNumber needReg);
 void genConsumeRegAndCopy(GenTree* tree, regNumber needReg);
 
@@ -139,13 +121,9 @@ void genConsumeIfReg(GenTreePtr tree)
 }
 
 void genRegCopy(GenTreePtr tree);
-
 void genTransferRegGCState(regNumber dst, regNumber src);
-
 void genConsumeAddress(GenTree* addr);
-
 void genConsumeAddrMode(GenTreeAddrMode* mode);
-
 void genSetBlockSize(GenTreeBlk* blkNode, regNumber sizeReg);
 void genConsumeBlockSrc(GenTreeBlk* blkNode);
 void genSetBlockSrc(GenTreeBlk* blkNode, regNumber srcReg);
@@ -156,13 +134,9 @@ void genConsumePutStructArgStk(GenTreePutArgStk* putArgStkNode, regNumber dstReg
 #endif // FEATURE_PUT_STRUCT_ARG_STK
 
 void genConsumeRegs(GenTree* tree);
-
 void genConsumeOperands(GenTreeOp* tree);
-
 void genEmitGSCookieCheck(bool pushReg);
-
 void genSetRegToIcon(regNumber reg, ssize_t val, var_types type = TYP_INT, insFlags flags = INS_FLAGS_DONT_CARE);
-
 void genCodeForShift(GenTreePtr tree);
 
 #if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
@@ -173,29 +147,24 @@ void genCodeForShiftLong(GenTreePtr tree);
 void genCodeForShiftRMW(GenTreeStoreInd* storeInd);
 #endif // _TARGET_XARCH_
 
+void genCodeForCast(GenTreeOp* tree);
+void genCodeForLclAddr(GenTree* tree);
+void genCodeForIndir(GenTreeIndir* tree);
 void genCodeForNegNot(GenTree* tree);
-
 void genCodeForLclVar(GenTreeLclVar* tree);
-
 void genCodeForLclFld(GenTreeLclFld* tree);
-
 void genCodeForStoreLclFld(GenTreeLclFld* tree);
-
 void genCodeForStoreLclVar(GenTreeLclVar* tree);
-
 void genCodeForReturnTrap(GenTreeOp* tree);
-
+void genCodeForJcc(GenTreeJumpCC* tree);
 void genCodeForStoreInd(GenTreeStoreInd* tree);
-
 void genCodeForSwap(GenTreeOp* tree);
-
 void genCodeForCpObj(GenTreeObj* cpObjNode);
-
 void genCodeForCpBlk(GenTreeBlk* cpBlkNode);
-
 void genCodeForCpBlkRepMovs(GenTreeBlk* cpBlkNode);
-
 void genCodeForCpBlkUnroll(GenTreeBlk* cpBlkNode);
+void genCodeForPhysReg(GenTreePhysReg* tree);
+void genCodeForNullCheck(GenTreeOp* tree);
 
 void genAlignStackBeforeCall(GenTreePutArgStk* putArgStk);
 void genAlignStackBeforeCall(GenTreeCall* call);
@@ -254,43 +223,27 @@ void genStoreRegToStackArg(var_types type, regNumber reg, int offset);
 #endif // FEATURE_PUT_STRUCT_ARG_STK
 
 void genCodeForLoadOffset(instruction ins, emitAttr size, regNumber dst, GenTree* base, unsigned offset);
-
 void genCodeForStoreOffset(instruction ins, emitAttr size, regNumber src, GenTree* base, unsigned offset);
 
 #ifdef _TARGET_ARM64_
 void genCodeForLoadPairOffset(regNumber dst, regNumber dst2, GenTree* base, unsigned offset);
-
 void genCodeForStorePairOffset(regNumber src, regNumber src2, GenTree* base, unsigned offset);
 #endif // _TARGET_ARM64_
 
 void genCodeForStoreBlk(GenTreeBlk* storeBlkNode);
-
 void genCodeForInitBlk(GenTreeBlk* initBlkNode);
-
 void genCodeForInitBlkRepStos(GenTreeBlk* initBlkNode);
-
 void genCodeForInitBlkUnroll(GenTreeBlk* initBlkNode);
-
 void genJumpTable(GenTree* tree);
-
 void genTableBasedSwitch(GenTree* tree);
-
 void genCodeForArrIndex(GenTreeArrIndex* treeNode);
-
 void genCodeForArrOffset(GenTreeArrOffs* treeNode);
-
 instruction genGetInsForOper(genTreeOps oper, var_types type);
-
 void genStoreInd(GenTreePtr node);
-
 bool genEmitOptimizedGCWriteBarrier(GCInfo::WriteBarrierForm writeBarrierForm, GenTree* addr, GenTree* data);
-
 void genCallInstruction(GenTreeCall* call);
-
 void genJmpMethod(GenTreePtr jmp);
-
 BasicBlock* genCallFinally(BasicBlock* block);
-
 void genCodeForJumpTrue(GenTreePtr tree);
 
 #if FEATURE_EH_FUNCLETS
@@ -305,7 +258,6 @@ void genMultiRegCallStoreToLocal(GenTreePtr treeNode);
 bool isStructReturn(GenTreePtr treeNode);
 void genStructReturn(GenTreePtr treeNode);
 
-// Codegen for GT_RETURN.
 void genReturn(GenTreePtr treeNode);
 
 void genLclHeap(GenTreePtr tree);