Support for SIMD Exceptions
authorCarol Eidt <carol.eidt@microsoft.com>
Thu, 9 Jul 2015 23:28:23 +0000 (16:28 -0700)
committerCarol Eidt <carol.eidt@microsoft.com>
Thu, 9 Jul 2015 23:28:23 +0000 (16:28 -0700)
For the CopyTo methods, we need to throw ArgumentOutOfRangeException instead of IndexOutOfRangeException for the initial index value, and then ArgumentException if the number of elements exceeds the remaining elements in the array. To support this, the GenTreeBoundsChk node now has a gtThrowKind field which indicates the kind of throw block it will branch to if the check failes.

This requires new helper calls, which I added to the end of corinfo.h.

[tfs-changeset: 1499475]

18 files changed:
src/inc/corinfo.h
src/inc/jithelpers.h
src/jit/codegen.h
src/jit/codegenarm.cpp
src/jit/codegenarm64.cpp
src/jit/codegencommon.cpp
src/jit/codegenlegacy.cpp
src/jit/codegenxarch.cpp
src/jit/compiler.h
src/jit/compiler.hpp
src/jit/flowgraph.cpp
src/jit/gentree.cpp
src/jit/gentree.h
src/jit/morph.cpp
src/jit/registerfp.cpp
src/jit/simd.cpp
src/jit/stackfp.cpp
src/vm/jithelpers.cpp

index 4417c44..ecc841a 100644 (file)
@@ -545,6 +545,11 @@ enum CorInfoHelpFunc
     CORINFO_HELP_LOOP_CLONE_CHOICE_ADDR, // Return the reference to a counter to decide to take cloned path in debug stress.
     CORINFO_HELP_DEBUG_LOG_LOOP_CLONING, // Print a message that a loop cloning optimization has occurred in debug mode.
 
+#ifndef RYUJIT_CTPBUILD
+    CORINFO_HELP_THROW_ARGUMENTEXCEPTION,           // throw ArgumentException
+    CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, // throw ArgumentOutOfRangeException
+#endif
+
     CORINFO_HELP_COUNT,
 };
 
index ae4080b..f591564 100644 (file)
 // JbTodo:  This helper definition is missing it's MDIL helper counterpart.
     JITHELPER1(CORINFO_HELP_DEBUG_LOG_LOOP_CLONING, JIT_DebugLogLoopCloning, CORINFO_HELP_SIG_REG_ONLY, MDIL_HELP_UNDEF)
 
+#ifndef RYUJIT_CTPBUILD
+    JITHELPER1(CORINFO_HELP_THROW_ARGUMENTEXCEPTION,           JIT_ThrowArgumentException,           CORINFO_HELP_SIG_REG_ONLY, MDIL_HELP_UNDEF)
+    JITHELPER1(CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION, JIT_ThrowArgumentOutOfRangeException, CORINFO_HELP_SIG_REG_ONLY, MDIL_HELP_UNDEF)
+#endif
+
 #undef JITHELPER1
 #undef DYNAMICJITHELPER1
 #undef JITHELPER
index 97f9d3a..99873de 100644 (file)
@@ -276,9 +276,9 @@ protected:
 
     //-------------------------------------------------------------------------
 
-    void                genJumpToThrowHlpBlk(emitJumpKind   jumpKind,
-                                             Compiler::addCodeKind    codeKind,
-                                             GenTreePtr     failBlk = NULL);
+    void                genJumpToThrowHlpBlk(emitJumpKind       jumpKind,
+                                             SpecialCodeKind    codeKind,
+                                             GenTreePtr         failBlk = NULL);
 
     void                genCheckOverflow    (GenTreePtr     tree);
 
index 31315f7..db35662 100644 (file)
@@ -1705,7 +1705,7 @@ CodeGen::genRangeCheck(GenTreePtr  oper)
     genConsumeIfReg(src2);
 
     getEmitter()->emitInsBinary(INS_cmp, emitAttr(TYP_INT), src1, src2);
-    genJumpToThrowHlpBlk(jmpKind, Compiler::ACK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
+    genJumpToThrowHlpBlk(jmpKind, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
 
 }
 
index 1d09945..1166f79 100644 (file)
@@ -2323,7 +2323,7 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
             
             if (divisorOp->IsZero())
             {
-                genJumpToThrowHlpBlk(EJ_je, Compiler::ACK_DIV_BY_ZERO);
+                genJumpToThrowHlpBlk(EJ_je, SCK_DIV_BY_ZERO);
                 // We don't need to generate the sdiv/udiv instruction
             }
             else
@@ -2354,7 +2354,7 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
                     {   
                         // Check if the divisor is zero throw a DivideByZeroException
                         emit->emitIns_R_I(INS_cmp, cmpSize, divisorReg, 0);
-                        genJumpToThrowHlpBlk(EJ_je, Compiler::ACK_DIV_BY_ZERO);
+                        genJumpToThrowHlpBlk(EJ_je, SCK_DIV_BY_ZERO);
 
                         // Check if the divisor is not -1 branch to 'sdivLabel'
                         emit->emitIns_R_I(INS_cmp, cmpSize, divisorReg, -1);
@@ -2372,7 +2372,7 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
                         //
                         emit->emitIns_R_R_R(INS_adds, cmpSize, REG_ZR, dividendReg, dividendReg);
                         inst_JMP(genJumpKindForOper(GT_NE, true), sdivLabel);     // goto sdiv if Z flag is clear
-                        genJumpToThrowHlpBlk(EJ_jo, Compiler::ACK_ARITH_EXCPN);   // if the V flags is set throw ArithmeticException
+                        genJumpToThrowHlpBlk(EJ_jo, SCK_ARITH_EXCPN);   // if the V flags is set throw ArithmeticException
                     }
 
                     genDefineTempLabel(sdivLabel);
@@ -2388,7 +2388,7 @@ CodeGen::genCodeForTreeNode(GenTreePtr treeNode)
                     if (!divisorOp->isContainedIntOrIImmed())
                     {                        
                         emit->emitIns_R_I(INS_cmp, cmpSize, divisorReg, 0);
-                        genJumpToThrowHlpBlk(EJ_je, Compiler::ACK_DIV_BY_ZERO);
+                        genJumpToThrowHlpBlk(EJ_je, SCK_DIV_BY_ZERO);
                     }
 
                     genCodeForBinary(treeNode);         // Generate the udiv instruction
@@ -4167,7 +4167,7 @@ CodeGen::genRangeCheck(GenTreePtr  oper)
         getEmitter()->emitIns_R_R(INS_cmp, EA_4BYTE, src1->gtRegNum, src2->gtRegNum);
     }
 
-    genJumpToThrowHlpBlk(jmpKind, Compiler::ACK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
+    genJumpToThrowHlpBlk(jmpKind, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
 }
 
 //------------------------------------------------------------------------
@@ -4256,7 +4256,7 @@ CodeGen::genCodeForArrIndex(GenTreeArrIndex* arrIndex)
                                 tgtReg,
                                 arrReg,
                                 genOffsetOfMDArrayDimensionSize(elemType, rank, dim));
-    genJumpToThrowHlpBlk(EJ_jae, Compiler::ACK_RNGCHK_FAIL);
+    genJumpToThrowHlpBlk(EJ_jae, SCK_RNGCHK_FAIL);
 
     genProduceReg(arrIndex);
 #else // !0
@@ -5600,7 +5600,7 @@ void CodeGen::genIntToIntCast(GenTreePtr treeNode)
         {
             // We only need to check for a negative value in sourceReg
             emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, 0);
-            genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+            genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
             if (dstType == TYP_ULONG)
             {
                 // cast to TYP_ULONG:
@@ -5618,7 +5618,7 @@ void CodeGen::genIntToIntCast(GenTreePtr treeNode)
             {
                 noway_assert(typeMask != 0);
                 emit->emitIns_R_I(INS_tst, cmpSize, sourceReg, typeMask);
-                genJumpToThrowHlpBlk(EJ_jne, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW);
             }
             else
             {
@@ -5631,12 +5631,12 @@ void CodeGen::genIntToIntCast(GenTreePtr treeNode)
                 noway_assert((typeMin != 0) && (typeMax != 0));
 
                 emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, typeMax);
-                genJumpToThrowHlpBlk(EJ_jg, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jg, SCK_OVERFLOW);
 
                 // Compare with the MIN
 
                 emit->emitIns_R_I(INS_cmp, cmpSize, sourceReg, typeMin);
-                genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
             }
         }
         ins = INS_mov;
@@ -5936,7 +5936,7 @@ CodeGen::genCkfinite(GenTreePtr treeNode)
     inst_RV_IV(INS_cmp, tmpReg, expMask, EA_4BYTE);
 
     // If exponent is all 1's, throw ArithmeticException
-    genJumpToThrowHlpBlk(EJ_je, Compiler::ACK_ARITH_EXCPN);
+    genJumpToThrowHlpBlk(EJ_je, SCK_ARITH_EXCPN);
 
     // if it is a finite value copy it to targetReg
     if (treeNode->gtRegNum != op1->gtRegNum)
index 70bd108..6e8a403 100644 (file)
@@ -2424,7 +2424,7 @@ void                CodeGen::genExitCode(BasicBlock * block)
  */
 
 void            CodeGen::genJumpToThrowHlpBlk(emitJumpKind          jumpKind,
-                                              Compiler::addCodeKind codeKind,
+                                              SpecialCodeKind       codeKind,
                                               GenTreePtr            failBlk)
 {
     if (!compiler->opts.compDbgCode)
@@ -2521,7 +2521,7 @@ void            CodeGen::genCheckOverflow(GenTreePtr tree)
 
     // Jump to the block which will throw the expection
 
-    genJumpToThrowHlpBlk(jumpKind, Compiler::ACK_OVERFLOW);
+    genJumpToThrowHlpBlk(jumpKind, SCK_OVERFLOW);
 }
 
 #if FEATURE_EH_FUNCLETS
index 8fb5a3a..18277f1 100644 (file)
@@ -2000,7 +2000,7 @@ void                CodeGen::genRangeCheck(GenTreePtr  oper)
         /* Generate "jae <fail_label>" */
 
         noway_assert(oper->gtOper == GT_ARR_BOUNDS_CHECK);
-        genJumpToThrowHlpBlk(EJ_jae, Compiler::ACK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
+        genJumpToThrowHlpBlk(EJ_jae, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
     }
     else
     {
@@ -2027,7 +2027,7 @@ void                CodeGen::genRangeCheck(GenTreePtr  oper)
             /* Generate "cmp [arrRef+LenOffs], ixv" */
             inst_AT_IV(INS_cmp, EA_4BYTE, arrRef, ixv, lenOffset);
             // Generate "jbe <fail_label>"
-            genJumpToThrowHlpBlk(EJ_jbe, Compiler::ACK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
+            genJumpToThrowHlpBlk(EJ_jbe, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
         }
         else if (arrLen->IsCnsIntOrI())
         {
@@ -2035,19 +2035,19 @@ void                CodeGen::genRangeCheck(GenTreePtr  oper)
             // Both are constants; decide at compile time.
             if (!(0 <= ixvFull && ixvFull < lenv))
             {
-                genJumpToThrowHlpBlk(EJ_jmp, Compiler::ACK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
+                genJumpToThrowHlpBlk(EJ_jmp, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
             }
         }
         else if (!indIsInt)
         {
-            genJumpToThrowHlpBlk(EJ_jmp, Compiler::ACK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
+            genJumpToThrowHlpBlk(EJ_jmp, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
         }
         else
         {
              /* Generate "cmp arrLen, ixv" */
             inst_RV_IV(INS_cmp, arrLen->gtRegNum, ixv, EA_4BYTE);
             // Generate "jbe <fail_label>"
-            genJumpToThrowHlpBlk(EJ_jbe, Compiler::ACK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
+            genJumpToThrowHlpBlk(EJ_jbe, SCK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
         }
     }
 
@@ -2266,7 +2266,7 @@ regMaskTP           CodeGen::genMakeAddrArrElem(GenTreePtr      arrElem,
                         compiler->eeGetArrayDataOffset(elemType) + sizeof(int) * dim);
 #endif
 
-        genJumpToThrowHlpBlk(EJ_jae, Compiler::ACK_RNGCHK_FAIL);
+        genJumpToThrowHlpBlk(EJ_jae, SCK_RNGCHK_FAIL);
 
         if (dim == 0)
         {
@@ -6462,7 +6462,7 @@ void                CodeGen::genCodeForMult64(GenTreePtr tree,
         getEmitter()->emitIns_R_I(INS_cmp, EA_4BYTE, regTmpHi, 0);
 
         // Jump to the block which will throw the expection
-        genJumpToThrowHlpBlk(EJ_jne, Compiler::ACK_OVERFLOW);
+        genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW);
 
         // Unlock regLo [and regHi] after generating code for the gtOverflow() case
         //
@@ -10724,7 +10724,7 @@ REG_OK:
                 instGen_Compare_Reg_To_Zero(EA_4BYTE, reg);
                 if (tree->gtFlags & GTF_UNSIGNED)       // conv.ovf.u8.i4       (i4 > 0 and upper bits 0)
                 {
-                    genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+                    genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
                     goto UPPER_BITS_ZERO;
                 }
 
@@ -10767,7 +10767,7 @@ REG_OK:
                     inst_TT_IV(INS_cmp, op1, 0x00000000, 4);
                 }
 
-                genJumpToThrowHlpBlk(EJ_jne, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW);
                 inst_JMP(EJ_jmp, done);
 
                 // If loDWord is negative, hiDWord should be -1 (sign extended loDWord)
@@ -10782,7 +10782,7 @@ REG_OK:
                 {
                     inst_TT_IV(INS_cmp, op1, 0xFFFFFFFFL, 4);
                 }
-                genJumpToThrowHlpBlk(EJ_jne, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW);
 
                 // Done
 
@@ -10803,7 +10803,7 @@ UPPER_BITS_ZERO:
                     inst_TT_IV(INS_cmp, op1, 0, 4);
                 }
 
-                genJumpToThrowHlpBlk(EJ_jne, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW);
                 break;
 
             default:
@@ -11034,7 +11034,7 @@ UPPER_BITS_ZERO:
         if (unsv)
         {
             inst_RV_IV(INS_TEST, reg, typeMask, emitActualTypeSize(baseType));
-            genJumpToThrowHlpBlk(EJ_jne, Compiler::ACK_OVERFLOW);
+            genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW);
         }
         else
         {
@@ -11046,12 +11046,12 @@ UPPER_BITS_ZERO:
             noway_assert(typeMin != DUMMY_INIT(~0) && typeMax != DUMMY_INIT(0));
 
             inst_RV_IV(INS_cmp, reg, typeMax, emitActualTypeSize(baseType));
-            genJumpToThrowHlpBlk(EJ_jg, Compiler::ACK_OVERFLOW);
+            genJumpToThrowHlpBlk(EJ_jg, SCK_OVERFLOW);
 
             // Compare with the MIN
 
             inst_RV_IV(INS_cmp, reg, typeMin, emitActualTypeSize(baseType));
-            genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+            genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
         }
 
         genCodeForTree_DONE(tree, reg);
@@ -13759,7 +13759,7 @@ REG_VAR_LONG:
                     {
                         noway_assert((op2->gtFlags & GTF_UNSIGNED) == 0); // conv.ovf.u8.un should be bashed to conv.u8.un
                         instGen_Compare_Reg_To_Zero(EA_4BYTE, regHi);     // set flags
-                        genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+                        genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
                     }
 
                     /* Move the value into the target */
@@ -15169,7 +15169,7 @@ USE_SAR_FOR_CAST:
                     {
                         regNumber hiReg = genRegPairHi(regPair);
                         instGen_Compare_Reg_To_Zero(EA_4BYTE, hiReg); // set flags
-                        genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+                        genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
                     }
                 }
                 goto DONE;
@@ -15240,7 +15240,7 @@ USE_SAR_FOR_CAST:
                     inst_TT_IV(INS_cmp, op1, 0, sizeof(int));
                 }
 
-                genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
                 goto DONE;
 
             default:
index 9449a75..911e9d0 100644 (file)
@@ -3880,7 +3880,7 @@ CodeGen::genRangeCheck(GenTreePtr  oper)
 #endif //DEBUG
 
     getEmitter()->emitInsBinary(INS_cmp, emitTypeSize(src2->TypeGet()), src1, src2);
-    genJumpToThrowHlpBlk(jmpKind, Compiler::ACK_RNGCHK_FAIL, bndsChk->gtIndRngFailBB);
+    genJumpToThrowHlpBlk(jmpKind, bndsChk->gtThrowKind, bndsChk->gtIndRngFailBB);
 
 }
 
@@ -3965,7 +3965,7 @@ CodeGen::genCodeForArrIndex(GenTreeArrIndex* arrIndex)
                                 tgtReg,
                                 arrReg,
                                 genOffsetOfMDArrayDimensionSize(elemType, rank, dim));
-    genJumpToThrowHlpBlk(EJ_jae, Compiler::ACK_RNGCHK_FAIL);
+    genJumpToThrowHlpBlk(EJ_jae, SCK_RNGCHK_FAIL);
 
     genProduceReg(arrIndex);
 }
@@ -5795,7 +5795,7 @@ void CodeGen::genIntToIntCast(GenTreePtr treeNode)
         {
             // We only need to check for a negative value in sourceReg
             inst_RV_IV(INS_cmp, sourceReg, 0, size);
-            genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+            genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
             if (dstType == TYP_ULONG)
             {
                 // cast from TYP_INT to TYP_ULONG
@@ -5825,13 +5825,13 @@ void CodeGen::genIntToIntCast(GenTreePtr treeNode)
                 {
                     inst_RV_RV(INS_mov, tmpReg, sourceReg, TYP_LONG);        // Move the 64-bit value to a writeable temp reg
                     inst_RV_SH(INS_SHIFT_RIGHT_LOGICAL, size, tmpReg, 32);   // Shift right by 32 bits
-                    genJumpToThrowHlpBlk(EJ_jne, Compiler::ACK_OVERFLOW);    // Thow if result shift is non-zero
+                    genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW);    // Thow if result shift is non-zero
                 }
                 else
                 {
                     noway_assert(typeMask != 0);
                     inst_RV_IV(INS_TEST, sourceReg, typeMask, size);
-                    genJumpToThrowHlpBlk(EJ_jne, Compiler::ACK_OVERFLOW);
+                    genJumpToThrowHlpBlk(EJ_jne, SCK_OVERFLOW);
                 }
             }
             else
@@ -5845,12 +5845,12 @@ void CodeGen::genIntToIntCast(GenTreePtr treeNode)
                 noway_assert((typeMin != 0) && (typeMax != 0));
 
                 inst_RV_IV(INS_cmp, sourceReg, typeMax, size);
-                genJumpToThrowHlpBlk(EJ_jg, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jg, SCK_OVERFLOW);
 
                 // Compare with the MIN
 
                 inst_RV_IV(INS_cmp, sourceReg, typeMin, size);
-                genJumpToThrowHlpBlk(EJ_jl, Compiler::ACK_OVERFLOW);
+                genJumpToThrowHlpBlk(EJ_jl, SCK_OVERFLOW);
             }
         }
 
@@ -6216,7 +6216,7 @@ CodeGen::genCkfinite(GenTreePtr treeNode)
     inst_RV_IV(INS_cmp, tmpReg, expMask, EA_4BYTE);
 
     // If exponent is all 1's, throw ArithmeticException
-    genJumpToThrowHlpBlk(EJ_je, Compiler::ACK_ARITH_EXCPN);
+    genJumpToThrowHlpBlk(EJ_je, SCK_ARITH_EXCPN);
 
     // if it is a finite value copy it to targetReg
     if (treeNode->gtRegNum != op1->gtRegNum)
index ddcaa21..12a9d14 100644 (file)
@@ -4367,8 +4367,6 @@ private:
 
     bool                compCanEncodePtrArgCntMax();
 
-    BasicBlock *        fgRngChkTarget      (BasicBlock *   block,
-                                             unsigned       stkDepth);
     void                fgSetRngChkTarget   (GenTreePtr     tree,
                                              bool           delay = true);
 
@@ -4518,39 +4516,34 @@ private:
     //  range checking or explicit calls to enable GC, and so on.
     //
 public:
-    enum        addCodeKind
-    {
-        ACK_NONE,
-        ACK_RNGCHK_FAIL,                // target when range check fails
-        ACK_PAUSE_EXEC,                 // target to stop (e.g. to allow GC)
-        ACK_DIV_BY_ZERO,                // target for divide by zero (Not used on X86/X64)
-        ACK_ARITH_EXCPN,                // target on arithmetic exception
-        ACK_OVERFLOW = ACK_ARITH_EXCPN, // target on overflow
-        ACK_COUNT
-    };
+
 
     struct      AddCodeDsc
     {
-        AddCodeDsc  *   acdNext;
-        BasicBlock  *   acdDstBlk;      // block  to  which we jump
-        unsigned        acdData;
-        addCodeKind     acdKind;        // what kind of a label is this?
-        unsigned short  acdStkLvl;
+        AddCodeDsc  *       acdNext;
+        BasicBlock  *       acdDstBlk;      // block  to  which we jump
+        unsigned            acdData;
+        SpecialCodeKind     acdKind;        // what kind of a special block is this?
+        unsigned short      acdStkLvl;
     };
 private:
-    static unsigned     acdHelper       (addCodeKind    codeKind);
+    static unsigned     acdHelper       (SpecialCodeKind    codeKind);
 
     AddCodeDsc  *       fgAddCodeList;
     bool                fgAddCodeModf;
     bool                fgRngChkThrowAdded;
-    AddCodeDsc  *       fgExcptnTargetCache[ACK_COUNT];
+    AddCodeDsc  *       fgExcptnTargetCache[SCK_COUNT];
+
+    BasicBlock *        fgRngChkTarget      (BasicBlock *    block,
+                                             unsigned           stkDepth,
+                                             SpecialCodeKind    kind);
 
-    BasicBlock *        fgAddCodeRef    (BasicBlock *   srcBlk,
-                                         unsigned       refData,
-                                         addCodeKind    kind,
-                                         unsigned       stkDepth = 0);
+    BasicBlock *        fgAddCodeRef    (BasicBlock *       srcBlk,
+                                         unsigned           refData,
+                                         SpecialCodeKind    kind,
+                                         unsigned           stkDepth = 0);
 public:
-    AddCodeDsc  *       fgFindExcptnTarget(addCodeKind  kind,
+    AddCodeDsc  *       fgFindExcptnTarget(SpecialCodeKind  kind,
                                          unsigned       refData);
 private:
     bool                fgIsCodeAdded   ();
index 08d2a51..501bfb2 100644 (file)
@@ -2826,9 +2826,9 @@ bool                Compiler::fgIsThrowHlpBlk(BasicBlock * block)
     {
         if  (block == add->acdDstBlk)
         {
-            return add->acdKind == ACK_RNGCHK_FAIL ||
-                   add->acdKind == ACK_DIV_BY_ZERO ||
-                   add->acdKind == ACK_OVERFLOW;
+            return add->acdKind == SCK_RNGCHK_FAIL ||
+                   add->acdKind == SCK_DIV_BY_ZERO ||
+                   add->acdKind == SCK_OVERFLOW;
         }
     }
 
@@ -2849,9 +2849,9 @@ unsigned            Compiler::fgThrowHlpBlkStkLevel(BasicBlock *block)
     {
         if  (block == add->acdDstBlk)
         {
-            assert(add->acdKind == ACK_RNGCHK_FAIL ||
-                   add->acdKind == ACK_DIV_BY_ZERO ||
-                   add->acdKind == ACK_OVERFLOW);
+            assert(add->acdKind == SCK_RNGCHK_FAIL ||
+                   add->acdKind == SCK_DIV_BY_ZERO ||
+                   add->acdKind == SCK_OVERFLOW);
             // TODO: bbTgtStkDepth is DEBUG-only.
             // Should we use it regularly and avoid this search.
             assert(block->bbTgtStkDepth == add->acdStkLvl);
index 0463575..62bf787 100644 (file)
@@ -112,7 +112,7 @@ void                Compiler::fgInit()
     fgAddCodeList    = 0;
     fgAddCodeModf    = false;
 
-    for (int i = 0; i < ACK_COUNT; i++)
+    for (int i = 0; i < SCK_COUNT; i++)
     {
         fgExcptnTargetCache[i] = NULL;
     }
@@ -17495,13 +17495,13 @@ BasicBlock*         Compiler::fgNewBBinRegionWorker(BBjumpKinds  jumpKind,
  */
 
 /* static */
-unsigned            Compiler::acdHelper(addCodeKind codeKind)
+unsigned            Compiler::acdHelper(SpecialCodeKind codeKind)
 {
     switch (codeKind)
     {
-    case ACK_RNGCHK_FAIL: return CORINFO_HELP_RNGCHKFAIL;
-    case ACK_DIV_BY_ZERO: return CORINFO_HELP_THROWDIVZERO;
-    case ACK_ARITH_EXCPN: return CORINFO_HELP_OVERFLOW;
+    case SCK_RNGCHK_FAIL: return CORINFO_HELP_RNGCHKFAIL;
+    case SCK_DIV_BY_ZERO: return CORINFO_HELP_THROWDIVZERO;
+    case SCK_ARITH_EXCPN: return CORINFO_HELP_OVERFLOW;
     default: assert(!"Bad codeKind"); return 0;
     }
 }
@@ -17512,10 +17512,10 @@ unsigned            Compiler::acdHelper(addCodeKind codeKind)
  *  the given kind.
  */
 
-BasicBlock*         Compiler::fgAddCodeRef(BasicBlock*  srcBlk,
-                                           unsigned     refData,
-                                           addCodeKind  kind,
-                                           unsigned     stkDepth)
+BasicBlock*         Compiler::fgAddCodeRef(BasicBlock*      srcBlk,
+                                           unsigned         refData,
+                                           SpecialCodeKind  kind,
+                                           unsigned         stkDepth)
 {
     /* For debuggable code, genJumpToThrowHlpBlk() will generate the 'throw'
        code inline. It has to be kept consistent with fgAddCodeRef() */
@@ -17525,14 +17525,16 @@ BasicBlock*         Compiler::fgAddCodeRef(BasicBlock*  srcBlk,
     const static
     BBjumpKinds jumpKinds[] =
     {
-        BBJ_NONE,               // ACK_NONE
-        BBJ_THROW,              // ACK_RNGCHK_FAIL
-        BBJ_ALWAYS,             // ACK_PAUSE_EXEC
-        BBJ_THROW,              // ACK_DIV_BY_ZERO
-        BBJ_THROW,              // ACK_ARITH_EXCP, ACK_OVERFLOW
+        BBJ_NONE,               // SCK_NONE
+        BBJ_THROW,              // SCK_RNGCHK_FAIL
+        BBJ_ALWAYS,             // SCK_PAUSE_EXEC
+        BBJ_THROW,              // SCK_DIV_BY_ZERO
+        BBJ_THROW,              // SCK_ARITH_EXCP, SCK_OVERFLOW
+        BBJ_THROW,              // SCK_ARG_EXCPN
+        BBJ_THROW,              // SCK_ARG_RNG_EXCPN
     };
 
-    noway_assert(sizeof(jumpKinds) == ACK_COUNT); // sanity check
+    noway_assert(sizeof(jumpKinds) == SCK_COUNT); // sanity check
 
     /* First look for an existing entry that matches what we're looking for */
 
@@ -17557,7 +17559,7 @@ BasicBlock*         Compiler::fgAddCodeRef(BasicBlock*  srcBlk,
         }
 #endif // _TARGET_X86_
 
-        goto DONE;
+        return  add->acdDstBlk;
     }
 
     /* We have to allocate a new entry and prepend it to the list */
@@ -17604,22 +17606,16 @@ BasicBlock*         Compiler::fgAddCodeRef(BasicBlock*  srcBlk,
             msgWhere = "handler";
         }
 
-        const char* msg = "";
-        if  (kind == ACK_RNGCHK_FAIL)
-        {
-            msg = " for RNGCHK_FAIL";
-        }
-        else if  (kind == ACK_PAUSE_EXEC)
+        const char* msg;
+        switch (kind)
         {
-            msg = " for PAUSE_EXEC";
-        }
-        else if  (kind == ACK_DIV_BY_ZERO)
-        {
-            msg = " for DIV_BY_ZERO";
-        }
-        else if  (kind == ACK_OVERFLOW)
-        {
-            msg = " for OVERFLOW";
+        case SCK_RNGCHK_FAIL:   msg = " for RNGCHK_FAIL";   break;
+        case SCK_PAUSE_EXEC:    msg = " for PAUSE_EXEC";    break;
+        case SCK_DIV_BY_ZERO:   msg = " for DIV_BY_ZERO";   break;
+        case SCK_OVERFLOW:      msg = " for OVERFLOW";      break;
+        case SCK_ARG_EXCPN:     msg = " for ARG_EXCPN";     break;
+        case SCK_ARG_RNG_EXCPN: msg = " for ARG_RNG_EXCPN"; break;
+        default:                msg = " for ??";            break;
         }
 
         printf("\nfgAddCodeRef -"
@@ -17647,45 +17643,49 @@ BasicBlock*         Compiler::fgAddCodeRef(BasicBlock*  srcBlk,
     /* Now figure out what code to insert */
 
     GenTreeCall* tree;
-    int          helper;
+    int          helper = CORINFO_HELP_UNDEF;
 
     switch (kind)
     {
-    case ACK_RNGCHK_FAIL:   helper = CORINFO_HELP_RNGCHKFAIL;
-                            goto ADD_HELPER_CALL;
-
-    case ACK_DIV_BY_ZERO:   helper = CORINFO_HELP_THROWDIVZERO; 
-                            goto ADD_HELPER_CALL;
+    case SCK_RNGCHK_FAIL:   helper = CORINFO_HELP_RNGCHKFAIL;
+                            break;
 
-    case ACK_ARITH_EXCPN:   helper = CORINFO_HELP_OVERFLOW;
-                            noway_assert(ACK_OVERFLOW == ACK_ARITH_EXCPN);
-                            goto ADD_HELPER_CALL;
+    case SCK_DIV_BY_ZERO:   helper = CORINFO_HELP_THROWDIVZERO; 
+                            break;
 
-ADD_HELPER_CALL:;
+    case SCK_ARITH_EXCPN:   helper = CORINFO_HELP_OVERFLOW;
+                            noway_assert(SCK_OVERFLOW == SCK_ARITH_EXCPN);
+                            break;
 
-        /* Add the appropriate helper call */
+#ifndef RYUJIT_CTPBUILD
+    case SCK_ARG_EXCPN:     helper = CORINFO_HELP_THROW_ARGUMENTEXCEPTION;
+                            break;
 
-        tree = gtNewHelperCallNode(helper, TYP_VOID, GTF_EXCEPT);
-        // There are no args here but fgMorphArgs has side effects 
-        // such as setting the outgoing arg area (which is necessary 
-        // on AMD if there are any calls).
-        tree = fgMorphArgs(tree);
-        break;
+    case SCK_ARG_RNG_EXCPN: helper = CORINFO_HELP_THROW_ARGUMENTOUTOFRANGEEXCEPTION;
+                            break;
+#endif // !RYUJIT_CTPBUILD
 
-//  case ACK_PAUSE_EXEC:
+//  case SCK_PAUSE_EXEC:
 //      noway_assert(!"add code to pause exec");
 
     default:
         noway_assert(!"unexpected code addition kind");
-        return NULL;
+        return nullptr;
     }
 
-    /* Store the tree in the new basic block */
+    noway_assert(helper != CORINFO_HELP_UNDEF);
 
+    // Add the appropriate helper call.
+    tree = gtNewHelperCallNode(helper, TYP_VOID, GTF_EXCEPT);
 
-    fgInsertStmtAtEnd(newBlk, fgNewStmtFromTree(tree));
+    // There are no args here but fgMorphArgs has side effects 
+    // such as setting the outgoing arg area (which is necessary 
+    // on AMD if there are any calls).
+    tree = fgMorphArgs(tree);
 
-DONE:;
+    // Store the tree in the new basic block.
+
+    fgInsertStmtAtEnd(newBlk, fgNewStmtFromTree(tree));
 
     return  add->acdDstBlk;
 }
@@ -17697,7 +17697,7 @@ DONE:;
  * a given type of exception
  */
 
-Compiler::AddCodeDsc*       Compiler::fgFindExcptnTarget(addCodeKind  kind,
+Compiler::AddCodeDsc*       Compiler::fgFindExcptnTarget(SpecialCodeKind  kind,
                                                          unsigned     refData)
 {
     if (!(fgExcptnTargetCache[kind] &&  // Try the cached value first
@@ -17725,7 +17725,7 @@ Compiler::AddCodeDsc*       Compiler::fgFindExcptnTarget(addCodeKind  kind,
  *  range check is to jump to upon failure.
  */
 
-BasicBlock*         Compiler::fgRngChkTarget(BasicBlock* block, unsigned stkDepth)
+BasicBlock*         Compiler::fgRngChkTarget(BasicBlock* block, unsigned stkDepth, SpecialCodeKind kind)
 {
 #ifdef DEBUG
     if (verbose)
@@ -17737,7 +17737,7 @@ BasicBlock*         Compiler::fgRngChkTarget(BasicBlock* block, unsigned stkDept
 
     /* We attach the target label to the containing try block (if any) */
     noway_assert(!compIsForInlining());
-    return  fgAddCodeRef(block, bbThrowIndex(block), ACK_RNGCHK_FAIL, stkDepth);
+    return  fgAddCodeRef(block, bbThrowIndex(block), kind, stkDepth);
 }
 
 // Sequences the tree.
index 4654350..680fb33 100644 (file)
@@ -1380,7 +1380,8 @@ AGAIN:
     case GT_SIMD_CHK:
 #endif // FEATURE_SIMD
         return Compare(op1->gtBoundsChk.gtArrLen, op2->gtBoundsChk.gtArrLen)
-            && Compare(op1->gtBoundsChk.gtIndex, op2->gtBoundsChk.gtIndex);
+            && Compare(op1->gtBoundsChk.gtIndex, op2->gtBoundsChk.gtIndex)
+            && (op1->gtBoundsChk.gtThrowKind == op1->gtBoundsChk.gtThrowKind);
 
     default:
         assert(!"unexpected operator");
@@ -1896,6 +1897,7 @@ AGAIN:
 #endif // FEATURE_SIMD
         hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtArrLen));
         hash = genTreeHashAdd(hash, gtHashValue(tree->gtBoundsChk.gtIndex));
+        hash = genTreeHashAdd(hash, tree->gtBoundsChk.gtThrowKind);
         break;
 
     default:
@@ -6134,7 +6136,8 @@ GenTreePtr          Compiler::gtCloneExpr(GenTree * tree,
             GenTreeBoundsChk(oper,
                              tree->TypeGet(),
                              gtCloneExpr(tree->gtBoundsChk.gtArrLen, addFlags, varNum, varVal),
-                             gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, varNum, varVal));
+                             gtCloneExpr(tree->gtBoundsChk.gtIndex, addFlags, varNum, varVal),
+                             tree->gtBoundsChk.gtThrowKind);
         break;
 
 
@@ -6846,6 +6849,16 @@ Compiler::gtDispNodeName(GenTree *tree)
         if (lea->Index() != NULL) bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "(i*%d)+", lea->gtScale);
         bufp += SimpleSprintf_s(bufp, buf, sizeof(buf), "%d)", lea->gtOffset);
     }
+    else if (tree->gtOper == GT_ARR_BOUNDS_CHECK)
+    {
+        switch(tree->gtBoundsChk.gtThrowKind)
+        {
+        case SCK_RNGCHK_FAIL:   sprintf_s(bufp, sizeof(buf), " %s_Rng", name);    break;
+        case SCK_ARG_EXCPN:     sprintf_s(bufp, sizeof(buf), " %s_Arg", name);    break;
+        case SCK_ARG_RNG_EXCPN: sprintf_s(bufp, sizeof(buf), " %s_ArgRng", name); break;
+        default:                unreached();
+        }
+    }
     else if (tree->gtOverflowEx())
     {
         sprintf_s(bufp, sizeof(buf), " %s_ovfl%c", name, 0);
index d1b2472..ce8a21a 100644 (file)
@@ -41,6 +41,29 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
 #endif // !DEBUG
 #endif // !DEBUGGABLE_GENTREE
 
+// The SpecialCodeKind enum is used to indicate the type of special (unique)
+// target block that will be targeted by an instruction.
+// These are used by:
+//   GenTreeBoundsChk nodes (SCK_RNGCHK_FAIL, SCK_ARG_EXCPN, SCK_ARG_RNG_EXCPN)
+//     - these nodes have a field (gtThrowKind) to indicate which kind
+//   GenTreeOps nodes, for which codegen will generate the branch
+//     - it will use the appropriate kind based on the opcode, though it's not
+//       clear why SCK_OVERFLOW == SCK_ARITH_EXCPN
+// SCK_PAUSE_EXEC is not currently used.
+//   
+enum        SpecialCodeKind
+{
+    SCK_NONE,
+    SCK_RNGCHK_FAIL,                // target when range check fails
+    SCK_PAUSE_EXEC,                 // target to stop (e.g. to allow GC)
+    SCK_DIV_BY_ZERO,                // target for divide by zero (Not used on X86/X64)
+    SCK_ARITH_EXCPN,                // target on arithmetic exception
+    SCK_OVERFLOW = SCK_ARITH_EXCPN, // target on overflow
+    SCK_ARG_EXCPN,                  // target on ArgumentException (currently used only for SIMD intrinsics)
+    SCK_ARG_RNG_EXCPN,              // target on ArgumentOutOfRangeException (currently used only for SIMD intrinsics)
+    SCK_COUNT
+};
+
 /*****************************************************************************/
 
 DECLARE_TYPED_ENUM(genTreeOps,BYTE)
@@ -2595,26 +2618,32 @@ public:
 #endif
 };
 
-// This takes an array length,an index value, and the label to jump to if the index is out of range.
+// This takes:
+// - a comparison value (generally an array length),
+// - an index value, and
+// - the label to jump to if the index is out of range.
+// - the "kind" of the throw block to branch to on failure
 // It generates no result.
 
 struct GenTreeBoundsChk: public GenTree
 {
-    GenTreePtr      gtArrLen;       // An expression for the length of the array being indexed.
-    GenTreePtr      gtIndex;        // The index expression.
+    GenTreePtr              gtArrLen;       // An expression for the length of the array being indexed.
+    GenTreePtr              gtIndex;        // The index expression.
 
-    GenTreePtr      gtIndRngFailBB; // Label to jump to for array-index-out-of-range
+    GenTreePtr              gtIndRngFailBB; // Label to jump to for array-index-out-of-range
+    SpecialCodeKind         gtThrowKind;    // Kind of throw block to branch to on failure
 
     /* Only out-of-ranges at same stack depth can jump to the same label (finding return address is easier)
        For delayed calling of fgSetRngChkTarget() so that the
        optimizer has a chance of eliminating some of the rng checks */
     unsigned        gtStkDepth;
 
-    GenTreeBoundsChk(genTreeOps oper, var_types type, GenTreePtr arrLen, GenTreePtr index) : 
+    GenTreeBoundsChk(genTreeOps oper, var_types type, GenTreePtr arrLen, GenTreePtr index, SpecialCodeKind kind) : 
         GenTree(oper, type), 
         gtArrLen(arrLen), gtIndex(index), 
         gtIndRngFailBB(NULL), 
-        gtStkDepth(0)
+        gtStkDepth(0),
+        gtThrowKind(kind)
         {
             // Effects flags propagate upwards.
             gtFlags |= (arrLen->gtFlags & GTF_ALL_EFFECT);
index bfc637a..6d4f3bb 100644 (file)
@@ -834,7 +834,7 @@ OPTIMIZECAST:
     }
 
     if (tree->gtOverflow())
-        fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), ACK_OVERFLOW, fgPtrArgCntCur);
+        fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
 
     return tree;
 
@@ -3882,7 +3882,8 @@ void                Compiler::fgMoveOpsLeft(GenTreePtr tree)
 void            Compiler::fgSetRngChkTarget(GenTreePtr  tree,
                                             bool        delay)
 {
-    GenTreeBoundsChk* bndsChk = NULL;
+    GenTreeBoundsChk* bndsChk = nullptr;
+    SpecialCodeKind kind = SCK_RNGCHK_FAIL;
 
 #ifdef FEATURE_SIMD
     if ((tree->gtOper == GT_ARR_BOUNDS_CHECK) || (tree->gtOper == GT_SIMD_CHK))
@@ -3891,6 +3892,7 @@ void            Compiler::fgSetRngChkTarget(GenTreePtr  tree,
 #endif // FEATURE_SIMD
     {
         bndsChk = tree->AsBoundsChk();
+        kind = tree->gtBoundsChk.gtThrowKind;
     }
     else
     {
@@ -3939,7 +3941,7 @@ void            Compiler::fgSetRngChkTarget(GenTreePtr  tree,
             unsigned stkDepth = (bndsChk != nullptr) ? bndsChk->gtStkDepth
                                                   : callStkDepth;
 
-            BasicBlock * rngErrBlk = fgRngChkTarget(compCurBB, stkDepth);
+            BasicBlock * rngErrBlk = fgRngChkTarget(compCurBB, stkDepth, kind);
 
             /* Add the label to the indirection node */
 
@@ -4102,7 +4104,7 @@ GenTreePtr          Compiler::fgMorphArrayIndex(GenTreePtr tree)
             arrLen = gtNewCastNode(bndsChkType, arrLen, bndsChkType);
         }
 
-        GenTreeBoundsChk* arrBndsChk    = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, index);
+        GenTreeBoundsChk* arrBndsChk    = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, index, SCK_RNGCHK_FAIL);
 
         bndsChk = arrBndsChk;
 
@@ -9446,13 +9448,13 @@ COMPARE:
         if (!varTypeIsFloating(tree->gtType))
         {
             // Codegen for this instruction needs to be able to throw two exceptions:
-            fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), ACK_OVERFLOW, fgPtrArgCntCur);
-            fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), ACK_DIV_BY_ZERO, fgPtrArgCntCur);
+            fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
+            fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_DIV_BY_ZERO, fgPtrArgCntCur);
         }
         break;
     case GT_UDIV:
         // Codegen for this instruction needs to be able to throw one exception:
-        fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), ACK_DIV_BY_ZERO, fgPtrArgCntCur);
+        fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_DIV_BY_ZERO, fgPtrArgCntCur);
         break;
 #endif
 
@@ -9484,7 +9486,7 @@ CM_OVF_OP:
 
             // Add the excptn-throwing basic block to jump to on overflow
 
-            fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), ACK_OVERFLOW, fgPtrArgCntCur);
+            fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_OVERFLOW, fgPtrArgCntCur);
 
             // We can't do any commutative morphing for overflow instructions
 
@@ -9746,7 +9748,7 @@ CM_ADD_OP:
 
         noway_assert(varTypeIsFloating(op1->TypeGet()));
 
-        fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), ACK_ARITH_EXCPN, fgPtrArgCntCur);
+        fgAddCodeRef(compCurBB, bbThrowIndex(compCurBB), SCK_ARITH_EXCPN, fgPtrArgCntCur);
         break;
 
     case GT_IND:
index d75d92b..39d619a 100644 (file)
@@ -315,7 +315,7 @@ void CodeGen::genFloatCheckFinite(GenTree *tree, RegSet::RegisterPreference *pre
     inst_RV_IV(INS_cmp, reg, expMask, EA_4BYTE);
 
     // If exponent was all 1's, we need to throw ArithExcep
-    genJumpToThrowHlpBlk(EJ_je, Compiler::ACK_ARITH_EXCPN);
+    genJumpToThrowHlpBlk(EJ_je, SCK_ARITH_EXCPN);
 
     genCodeForTreeFloat_DONE(tree, op1->gtRegNum);
 }
index d94e01c..f733259 100644 (file)
@@ -1703,7 +1703,7 @@ GenTreePtr Compiler::createAddressNodeForSIMDInit(GenTreePtr tree, unsigned simd
         unsigned arrayElementsCount = simdSize / genTypeSize(baseType);
         checkIndexExpr = new (this, GT_CNS_INT) GenTreeIntCon(TYP_INT,  indexVal + arrayElementsCount - 1);
         GenTreeArrLen*       arrLen     = new (this, GT_ARR_LENGTH) GenTreeArrLen(TYP_INT, arrayRef, (int)offsetof(CORINFO_Array, length));
-        GenTreeBoundsChk*    arrBndsChk = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, checkIndexExpr);
+        GenTreeBoundsChk*    arrBndsChk = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, checkIndexExpr, SCK_RNGCHK_FAIL);
 
         offset += offsetof(CORINFO_Array, u1Elems);
         byrefNode = gtNewOperNode(GT_COMMA, arrayRef->TypeGet(), arrBndsChk, gtCloneExpr(arrayRef));
@@ -2113,7 +2113,11 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE                   opcode,
             // (This constructor takes only the zero-based arrays.)
             // We will add one or two bounds checks:
             // 1. If we have an index, we must do a check on that first.
-            // 2. We need to generate a check for the last array element we will access.
+            //    We can't combine it with the index + vectorLength check because
+            //    a. It might be negative, and b. It may need to raise a different exception
+            //    (captured as SCK_ARG_RNG_EXCPN for CopyTo and SCK_RNGCHK_FAIL for Init). 
+            // 2. We need to generate a check (SCK_ARG_EXCPN for CopyTo and SCK_RNGCHK_FAIL for Init)
+            //    for the last array element we will access.
             //    We'll either check against (vectorLength - 1) or (index + vectorLength - 1).
 
             GenTree* checkIndexExpr = new (this, GT_CNS_INT) GenTreeIntCon(TYP_INT, vectorLength - 1);
@@ -2154,6 +2158,16 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE                   opcode,
 
             if (op3 != nullptr)
             {
+                SpecialCodeKind op3CheckKind;
+                if (simdIntrinsicID == SIMDIntrinsicInitArrayX)
+                {
+                    op3CheckKind = SCK_RNGCHK_FAIL;
+                }
+                else
+                {
+                    assert(simdIntrinsicID == SIMDIntrinsicCopyToArrayX);
+                    op3CheckKind = SCK_ARG_RNG_EXCPN;
+                }
                 // We need to use the original expression on this, which is the first check.
                 GenTree* arrayRefForArgRngChk = arrayRefForArgChk;
                 // Then we clone the clone we just made for the next check.
@@ -2171,7 +2185,7 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE                   opcode,
                 }
 
                 GenTreeArrLen* arrLen = new (this, GT_ARR_LENGTH) GenTreeArrLen(TYP_INT, arrayRefForArgRngChk, (int)offsetof(CORINFO_Array, length));
-                argRngChk = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, index);
+                argRngChk = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, index, op3CheckKind);
                 // Now, clone op3 to create another node for the argChk
                 GenTree* index2 = gtCloneExpr(op3);
                 assert(index != nullptr);
@@ -2180,8 +2194,17 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE                   opcode,
 
             // Insert a bounds check for index + offset - 1.
             // This must be a "normal" array.
+            SpecialCodeKind op2CheckKind;
+            if (simdIntrinsicID == SIMDIntrinsicInitArray || simdIntrinsicID == SIMDIntrinsicInitArrayX)
+            {
+                op2CheckKind = SCK_RNGCHK_FAIL;
+            }
+            else
+            {
+                op2CheckKind = SCK_ARG_EXCPN;
+            }
             GenTreeArrLen*       arrLen     = new (this, GT_ARR_LENGTH) GenTreeArrLen(TYP_INT, arrayRefForArgChk, (int)offsetof(CORINFO_Array, length));
-            GenTreeBoundsChk*    argChk = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, checkIndexExpr);
+            GenTreeBoundsChk*    argChk = new (this, GT_ARR_BOUNDS_CHECK) GenTreeBoundsChk(GT_ARR_BOUNDS_CHECK, TYP_VOID, arrLen, checkIndexExpr, op2CheckKind);
 
             // Create a GT_COMMA tree for the bounds check(s).
             op2 = gtNewOperNode(GT_COMMA, op2->TypeGet(), argChk, op2);
@@ -2405,7 +2428,7 @@ GenTreePtr Compiler::impSIMDIntrinsic(OPCODE                   opcode,
                 }
 
                 GenTree* lengthNode = new (this, GT_CNS_INT) GenTreeIntCon(TYP_INT, vectorLength);
-                GenTreeBoundsChk* simdChk = new (this, GT_SIMD_CHK) GenTreeBoundsChk(GT_SIMD_CHK, TYP_VOID, lengthNode, index);
+                GenTreeBoundsChk* simdChk = new (this, GT_SIMD_CHK) GenTreeBoundsChk(GT_SIMD_CHK, TYP_VOID, lengthNode, index, SCK_RNGCHK_FAIL);
 
                 // Create a GT_COMMA tree for the bounds check.
                 op2 = gtNewOperNode(GT_COMMA, op2->TypeGet(), simdChk, op2);
index a939da1..05bfba7 100644 (file)
@@ -2426,7 +2426,7 @@ void CodeGen::genCodeForTreeStackFP_SmpOp(GenTreePtr     tree)
             inst_RV_IV(INS_cmp, reg, expMask, EA_4BYTE);
 
             // If exponent was all 1's, we need to throw ArithExcep
-            genJumpToThrowHlpBlk(EJ_je, Compiler::ACK_ARITH_EXCPN);
+            genJumpToThrowHlpBlk(EJ_je, SCK_ARITH_EXCPN);
 
             genUpdateLife(tree);         
 
index 01b6715..2e29715 100644 (file)
@@ -5158,6 +5158,42 @@ HCIMPL0(void, JIT_RngChkFail)
 HCIMPLEND
 
 /*********************************************************************/
+HCIMPL0(void, JIT_ThrowArgumentException)
+{
+    FCALL_CONTRACT;
+
+    /* Make no assumptions about the current machine state */
+    ResetCurrentContext();
+
+    FC_GC_POLL_NOT_NEEDED();    // throws always open up for GC
+
+    HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION);    // Set up a frame
+
+    COMPlusThrow(kArgumentException);
+
+    HELPER_METHOD_FRAME_END();
+}
+HCIMPLEND
+
+/*********************************************************************/
+HCIMPL0(void, JIT_ThrowArgumentOutOfRangeException)
+{
+    FCALL_CONTRACT;
+
+    /* Make no assumptions about the current machine state */
+    ResetCurrentContext();
+
+    FC_GC_POLL_NOT_NEEDED();    // throws always open up for GC
+
+    HELPER_METHOD_FRAME_BEGIN_ATTRIB_NOPOLL(Frame::FRAME_ATTR_EXCEPTION);    // Set up a frame
+
+    COMPlusThrow(kArgumentOutOfRangeException);
+
+    HELPER_METHOD_FRAME_END();
+}
+HCIMPLEND
+
+/*********************************************************************/
 HCIMPL0(void, JIT_Overflow)
 {
     FCALL_CONTRACT;