From: Mike Danes Date: Tue, 22 Mar 2016 21:14:38 +0000 (+0200) Subject: Add support for multi-dimensional array initialization X-Git-Tag: submit/tizen/20210909.063632~11030^2~10199^2~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=ac0e309c1e95e1009b58701851833b8775c18d20;p=platform%2Fupstream%2Fdotnet%2Fruntime.git Add support for multi-dimensional array initialization This extends impInitializeArrayIntrinsic to support MD arrays in addition to SD arrays. This includes support for SD arrays which are created via CORINFO_HELP_NEW_MDARR when the lower bound is not specified or known to be 0. The generated code is similar to the code generated for the SD arrays, for example: call CORINFO_HELP_NEW_MDARR mov rdx, 0x202AB822050 lea rcx, bword ptr [rax+32] vmovdqu ymm0, qword ptr [rdx] vmovdqu qword ptr [rcx], ymm0 mov r8d, dword ptr [rdx+16] mov dword ptr [rcx+16], r8d Commit migrated from https://github.com/dotnet/coreclr/commit/9c635bde59d979cd3359e5e12d743839481b38be --- diff --git a/src/coreclr/src/jit/compiler.h b/src/coreclr/src/jit/compiler.h index 2a0d4ee..81a2bd0 100644 --- a/src/coreclr/src/jit/compiler.h +++ b/src/coreclr/src/jit/compiler.h @@ -6397,7 +6397,10 @@ public : CORINFO_EE_INFO * eeGetEEInfo(); + // Gets the offset of a SDArray's first element unsigned eeGetArrayDataOffset(var_types type); + // Gets the offset of a MDArray's first element + unsigned eeGetMDArrayDataOffset(var_types type, unsigned rank); GenTreePtr eeGetPInvokeCookie(CORINFO_SIG_INFO *szMetaSig); diff --git a/src/coreclr/src/jit/ee_il_dll.cpp b/src/coreclr/src/jit/ee_il_dll.cpp index 787c311..f51e452 100755 --- a/src/coreclr/src/jit/ee_il_dll.cpp +++ b/src/coreclr/src/jit/ee_il_dll.cpp @@ -494,7 +494,14 @@ GenTreePtr Compiler::eeGetPInvokeCookie(CORINFO_SIG_INFO *szMetaSig) return gtNewIconEmbHndNode(cookie, pCookie, GTF_ICON_PINVKI_HDL); } -/*****************************************************************************/ +//------------------------------------------------------------------------ +// eeGetArrayDataOffset: Gets the offset of a SDArray's first element +// +// Arguments: +// type - The array element type +// +// Return Value: +// The offset to the first array element. unsigned Compiler::eeGetArrayDataOffset(var_types type) { @@ -502,6 +509,27 @@ unsigned Compiler::eeGetArrayDataOffset(var_types type) : offsetof(CORINFO_Array, u1Elems); } +//------------------------------------------------------------------------ +// eeGetMDArrayDataOffset: Gets the offset of a MDArray's first element +// +// Arguments: +// type - The array element type +// rank - The array rank +// +// Return Value: +// The offset to the first array element. +// +// Assumptions: +// The rank should be greater than 0. + +unsigned Compiler::eeGetMDArrayDataOffset(var_types type, unsigned rank) +{ + assert(rank > 0); + // Note that below we're specifically using genTypeSize(TYP_INT) because array + // indices are not native int. + return eeGetArrayDataOffset(type) + 2 * genTypeSize(TYP_INT) * rank; +} + /*****************************************************************************/ void Compiler::eeGetStmtOffsets() diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp old mode 100755 new mode 100644 index 5a3bcf8..3e67afd --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -2666,23 +2666,30 @@ BOOL Compiler::impLocAllocOnStack() return(FALSE); } -/*****************************************************************************/ +//------------------------------------------------------------------------ +// impInitializeArrayIntrinsic: Attempts to replace a call to InitializeArray +// with a GT_COPYBLK node. +// +// Arguments: +// sig - The InitializeArray signature. +// +// Return Value: +// A pointer to the newly create GT_COPYBLK node if the replacement succeeds or +// nullptr otherwise. +// +// Notes: +// The function recognizes the following IL pattern: +// ldc or a list of ldc / +// newarr or newobj +// dup +// ldtoken +// call InitializeArray +// The lower bounds need not be constant except when the array rank is 1. +// The function recognizes all kinds of arrays thus enabling a small runtime +// such as CoreRT to skip providing an implementation for InitializeArray. GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO * sig) { - // - // The IL for array initialization looks like the following: - // - // ldc - // newarr - // dup - // ldtoken - // call InitializeArray - // - // We will try to implement it using a GT_COPYBLK node to avoid the - // runtime call to the helper. - // - assert(sig->numArgs == 2); GenTreePtr fieldTokenNode = impStackTop(0).val; @@ -2767,6 +2774,9 @@ GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO * sig) // // Verify that it is one of the new array helpers. // + + bool isMDArray = false; + if (newArrayCall->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_DIRECT) && newArrayCall->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_OBJ) && newArrayCall->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEWARR_1_VC) && @@ -2776,57 +2786,177 @@ GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO * sig) #endif ) { - // - // In order to simplify the code, we won't support the multi-dim - // case. Instead we simply return NULL, and the caller will insert - // a run-time call to the helper. Note that we can't assert - // failure here, because this is a valid case. - // + if (newArrayCall->gtCall.gtCallMethHnd != eeFindHelper(CORINFO_HELP_NEW_MDARR)) + return nullptr; - return NULL; + isMDArray = true; } + CORINFO_CLASS_HANDLE arrayClsHnd = (CORINFO_CLASS_HANDLE) newArrayCall->gtCall.compileTimeHelperArgumentHandle; // - // Make sure there are exactly two arguments: the array class and - // the number of elements. + // Make sure we found a compile time handle to the array // - GenTreePtr arrayLengthNode; + if (!arrayClsHnd) + return nullptr; - GenTreeArgList* args = newArrayCall->gtCall.gtCallArgs; -#ifdef FEATURE_READYTORUN_COMPILER - if (newArrayCall->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_NEWARR_1)) + unsigned rank; + S_UINT32 numElements; + + if (isMDArray) { - // Array length is 1st argument for readytorun helper - arrayLengthNode = args->Current(); + rank = info.compCompHnd->getArrayRank(arrayClsHnd); + + if (rank == 0) + return nullptr; + + GenTreeArgList* args = newArrayCall->gtCall.gtCallArgs; + GenTreeArgList* numArgsArg = nullptr; + GenTreeArgList* beginArgs = nullptr; + GenTreeArgList* endArgs = nullptr; + + if (Target::g_tgtArgOrder == Target::ARG_ORDER_R2L) + { + numArgsArg = args->Rest(); + + if (numArgsArg != nullptr) + beginArgs = numArgsArg->Rest(); + } + else + { + beginArgs = args; + + for (GenTreeArgList* arg = args; arg != nullptr; arg = arg->Rest()) + { + bool isSecondToLast = (arg->Rest() != nullptr) && (arg->Rest()->Rest() == nullptr); + + if (isSecondToLast) + { + numArgsArg = arg; + endArgs = arg; + break; + } + } + } + + // + // The number of arguments should be a constant between 1 and 64. The rank can't be 0 + // so at least one length must be present and the rank can't exceed 32 so there can + // be at most 64 arguments - 32 lengths and 32 lower bounds. + // + + if ((beginArgs == nullptr) || + (numArgsArg == nullptr) || + (numArgsArg->Current()->OperGet() != GT_CNS_INT) || + (numArgsArg->Current()->AsIntCon()->IconValue() < 1) || + (numArgsArg->Current()->AsIntCon()->IconValue() > 64)) + { + return nullptr; + } + + unsigned numArgs = static_cast(numArgsArg->Current()->AsIntCon()->IconValue()); + bool lowerBoundsSpecified; + + if (numArgs == rank * 2) + { + lowerBoundsSpecified = true; + } + else if (numArgs == rank) + { + lowerBoundsSpecified = false; + + // + // If the rank is 1 and a lower bound isn't specified then the runtime creates + // a SDArray. Note that even if a lower bound is specified it can be 0 and then + // we get a SDArray as well, see the for loop below. + // + + if (rank == 1) + isMDArray = false; + } + else + { + return nullptr; + } + + // + // The rank is known to be at least 1 so we can start with numElements being 1 + // to avoid the need to special case the first dimension. + // + + numElements = S_UINT32(1); + + for (GenTreeArgList* arg = beginArgs; arg != endArgs; arg = arg->Rest()) + { + if (lowerBoundsSpecified) + { + // + // In general lower bounds can be ignored because they're not needed to + // calculate the total number of elements. But for single dimensional arrays + // we need to know if the lower bound is 0 because in this case the runtime + // creates a SDArray and this affects the way the array data offset is calculated. + // + + if (rank == 1) + { + GenTree* lowerBoundNode = arg->Current(); + + if (lowerBoundNode->OperGet() != GT_CNS_INT) + return nullptr; + + if (lowerBoundNode->AsIntCon()->IconValue() == 0) + isMDArray = false; + } + + arg = arg->Rest(); + } + + GenTree* lengthNode = arg->Current(); + + if (lengthNode->OperGet() != GT_CNS_INT) + return nullptr; + + numElements *= S_SIZE_T(lengthNode->AsIntCon()->IconValue()); + } } else -#endif { - // Array length is 2nd argument for regular helper - arrayLengthNode = args->Rest()->Current(); - } + // + // Make sure there are exactly two arguments: the array class and + // the number of elements. + // - // - // Make sure that the number of elements look valid. - // - if (arrayLengthNode->gtOper != GT_CNS_INT) - { - return NULL; - } + GenTreePtr arrayLengthNode; - S_UINT32 numElements = S_SIZE_T(arrayLengthNode->gtIntCon.gtIconVal); - CORINFO_CLASS_HANDLE arrayClsHnd = (CORINFO_CLASS_HANDLE) newArrayCall->gtCall.compileTimeHelperArgumentHandle; + GenTreeArgList* args = newArrayCall->gtCall.gtCallArgs; +#ifdef FEATURE_READYTORUN_COMPILER + if (newArrayCall->gtCall.gtCallMethHnd == eeFindHelper(CORINFO_HELP_READYTORUN_NEWARR_1)) + { + // Array length is 1st argument for readytorun helper + arrayLengthNode = args->Current(); + } + else +#endif + { + // Array length is 2nd argument for regular helper + arrayLengthNode = args->Rest()->Current(); + } - // - // Make sure we found a compile time handle to the array - // + // + // Make sure that the number of elements look valid. + // + if (arrayLengthNode->gtOper != GT_CNS_INT) + { + return NULL; + } - if (!arrayClsHnd || - !info.compCompHnd->isSDArray(arrayClsHnd)) - { - return NULL; + numElements = S_SIZE_T(arrayLengthNode->gtIntCon.gtIconVal); + + if (!info.compCompHnd->isSDArray(arrayClsHnd)) + { + return NULL; + } } CORINFO_CLASS_HANDLE elemClsHnd; @@ -2868,10 +2998,24 @@ GenTreePtr Compiler::impInitializeArrayIntrinsic(CORINFO_SIG_INFO * sig) impPopStack(); impPopStack(); - GenTreePtr dst = gtNewOperNode(GT_ADDR, - TYP_BYREF, - gtNewIndexRef(elementType, arrayLocalNode, gtNewIconNode(0))); + GenTreePtr dst; + if (isMDArray) + { + unsigned dataOffset = eeGetMDArrayDataOffset(elementType, rank); + + dst = gtNewOperNode(GT_ADD, + TYP_BYREF, + arrayLocalNode, + gtNewIconNode(dataOffset, TYP_I_IMPL)); + } + else + { + dst = gtNewOperNode(GT_ADDR, + TYP_BYREF, + gtNewIndexRef(elementType, arrayLocalNode, gtNewIconNode(0))); + } + return gtNewBlkOpNode(GT_COPYBLK, dst, // dst gtNewIconHandleNode((size_t) initData, GTF_ICON_STATIC_HDL), // src diff --git a/src/coreclr/src/jit/instr.cpp b/src/coreclr/src/jit/instr.cpp index 3dd10f2..4fb23f6 100644 --- a/src/coreclr/src/jit/instr.cpp +++ b/src/coreclr/src/jit/instr.cpp @@ -580,8 +580,7 @@ void CodeGen::instGetAddrMode(GenTreePtr addr, else *indScale = 0; - *cns = compiler->eeGetArrayDataOffset(addr->gtArrElem.gtArrElemType) - + 2 * sizeof(int) * addr->gtArrElem.gtArrRank; + *cns = compiler->eeGetMDArrayDataOffset(addr->gtArrElem.gtArrElemType, addr->gtArrElem.gtArrRank); } else if (addr->gtOper == GT_LEA) { diff --git a/src/coreclr/src/jit/lower.cpp b/src/coreclr/src/jit/lower.cpp index d76ce8c..da34404 100755 --- a/src/coreclr/src/jit/lower.cpp +++ b/src/coreclr/src/jit/lower.cpp @@ -3689,8 +3689,7 @@ Lowering::LowerArrElem(GenTree **ppTree, Compiler::fgWalkData* data) // Generate the LEA and make it reverse evaluation, because we want to evaluate the index expression before the base. GenTreePtr leaBase = comp->gtClone(arrObjNode); unsigned scale = arrElem->gtArrElem.gtArrElemSize; - // Note that below we're specifically using genTypeSize(TYP_INT) because array indices are not native int. - unsigned offset = comp->eeGetArrayDataOffset(arrElem->gtArrElem.gtArrElemType) + 2 * genTypeSize(TYP_INT) * arrElem->gtArrElem.gtArrRank; + unsigned offset = comp->eeGetMDArrayDataOffset(arrElem->gtArrElem.gtArrElemType, arrElem->gtArrElem.gtArrRank); GenTreePtr leaIndexNode = prevArrOffs; if (!jitIsScaleIndexMul(scale)) { diff --git a/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/_il_dbginitializearray.ilproj b/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/_il_dbginitializearray.ilproj new file mode 100644 index 0000000..466865d --- /dev/null +++ b/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/_il_dbginitializearray.ilproj @@ -0,0 +1,23 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages + ..\..\ + 7a9bfb7d + Full + false + + + + + + + + \ No newline at end of file diff --git a/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/_il_relinitializearray.ilproj b/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/_il_relinitializearray.ilproj new file mode 100644 index 0000000..689b3e0 --- /dev/null +++ b/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/_il_relinitializearray.ilproj @@ -0,0 +1,22 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + $(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages + ..\..\ + 7a9bfb7d + true + + + + + + + + \ No newline at end of file diff --git a/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/initializearray.il b/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/initializearray.il new file mode 100644 index 0000000..256c2be --- /dev/null +++ b/src/coreclr/tests/src/JIT/Methodical/Arrays/misc/initializearray.il @@ -0,0 +1,640 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +.assembly extern mscorlib +{ + .publickeytoken = (B7 7A 5C 56 19 34 E0 89) + .ver 4:0:0:0 +} +.assembly initializearray +{ + .hash algorithm 0x00008004 + .ver 0:0:0:0 +} +.module initializearray.exe +.imagebase 0x00400000 +.file alignment 0x00000200 +.stackreserve 0x00100000 +.subsystem 0x0003 // WINDOWS_CUI +.corflags 0x00000001 // ILONLY + +.class private auto ansi beforefieldinit InitializeArray extends [mscorlib]System.Object +{ + .method private hidebysig static int32 Main() cil managed + { + .entrypoint + .maxstack 8 + + call bool InitializeArray::SZArray_Int64_5_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::SZArray_Int64_6_InvalidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int16_10_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int16_0_10_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int16_11_InvalidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int8_8x10_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int8_10x10_InvalidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Float32_4x5_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Float32_5x5_InvalidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int8_2_4x3_5_ValidInitializationTest() + brfalse.s fail + + call bool InitializeArray::MDArray_Int8_2_5x3_5_InvalidInitializationTest() + brfalse.s fail + + ldc.i4.s 100 + ret + + fail: + ldc.i4.s 0 + ret + } + + .method private hidebysig static bool SZArray_Int64_5_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int64[] InitializeArray::SZArray_Initialize_Int64_5() + call int64[] InitializeArray::SZArray_Initialize_Int64_5_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int64[] SZArray_Initialize_Int64_5() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 5 + newarr int64 + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize40' 'ArrayInitializers'::'InitializerField40' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int64[] SZArray_Initialize_Int64_5_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4 5 + newarr int64 + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize40' 'ArrayInitializers'::'InitializerField40' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool SZArray_Int64_6_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4 11 + newarr int64 + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + + .method private hidebysig static bool MDArray_Int16_10_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int16[0...] InitializeArray::MDArray_Initialize_Int16_10() + call int16[0...] InitializeArray::MDArray_Initialize_Int16_10_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int16[0...] MDArray_Initialize_Int16_10() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 10 + newobj instance void int16[0...]::.ctor(int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int16[0...] MDArray_Initialize_Int16_10_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4 10 + newobj instance void int16[0...]::.ctor(int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool MDArray_Int16_11_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4 11 + newobj instance void int16[0...]::.ctor(int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + + .method private hidebysig static bool MDArray_Int16_0_10_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int16[...] InitializeArray::MDArray_Initialize_Int16_0_10() + call int16[...] InitializeArray::MDArray_Initialize_Int16_0_10_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int16[...] MDArray_Initialize_Int16_0_10() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 0 + ldc.i4 10 + newobj instance void int16[...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int16[...] MDArray_Initialize_Int16_0_10_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4 0 + ldc.i4 10 + newobj instance void int16[...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + + .method private hidebysig static bool MDArray_Int8_8x10_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int8[0..., 0...] InitializeArray::MDArray_Initialize_Int8_8x10() + call int8[0..., 0...] InitializeArray::MDArray_Initialize_Int8_8x10_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int8[0..., 0...] MDArray_Initialize_Int8_8x10() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 8 + ldc.i4 10 + newobj instance void int8 [0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int8[0..., 0...] MDArray_Initialize_Int8_8x10_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4 8 + ldc.i4 10 + newobj instance void int8[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool MDArray_Int8_10x10_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4 10 + ldc.i4 10 + newobj instance void int8[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + + .method private hidebysig static bool MDArray_Float32_4x5_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call float32[0..., 0...] InitializeArray::MDArray_Initialize_Float32_4x5() + call float32[0..., 0...] InitializeArray::MDArray_Initialize_Float32_4x5_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static float32[0..., 0...] MDArray_Initialize_Float32_4x5_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4.4 + ldc.i4.5 + newobj instance void float32[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static float32[0..., 0...] MDArray_Initialize_Float32_4x5() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4 4 + ldc.i4 5 + newobj instance void float32[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool MDArray_Float32_5x5_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4 5 + ldc.i4 5 + newobj instance void float32[0..., 0...]::.ctor(int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'ArrayInitializers'::'InitializerField80' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + + .method private hidebysig static bool MDArray_Int8_2_4x3_5_ValidInitializationTest() cil managed noinlining + { + .maxstack 8 + call int8[..., ...] InitializeArray::MDArray_Initialize_Int8_2_4x3_5() + call int8[..., ...] InitializeArray::MDArray_Initialize_Int8_2_4x3_5_Optimized() + call bool InitializeArray::ArrayEquals(class [mscorlib]System.Array, class [mscorlib]System.Array) + ret + } + + .method private hidebysig static int8[..., ...] MDArray_Initialize_Int8_2_4x3_5() cil managed noinlining nooptimization + { + .maxstack 8 + ldc.i4.2 + ldc.i4.4 + ldc.i4.3 + ldc.i4.5 + newobj instance void int8 [..., ...]::.ctor(int32, int32, int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static int8[..., ...] MDArray_Initialize_Int8_2_4x3_5_Optimized() cil managed noinlining + { + .maxstack 8 + ldc.i4.2 + ldc.i4.4 + ldc.i4.3 + ldc.i4.5 + newobj instance void int8[..., ...]::.ctor(int32, int32, int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + ret + } + + .method private hidebysig static bool MDArray_Int8_2_5x3_5_InvalidInitializationTest() cil managed noinlining + { + .maxstack 8 + .locals init (int32 exitCode) + .try + { + ldc.i4.2 + ldc.i4.5 + ldc.i4.3 + ldc.i4.5 + newobj instance void int8[..., ...]::.ctor(int32, int32, int32, int32) + dup + ldtoken field valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'ArrayInitializers'::'InitializerField20' + call void[mscorlib]System.Runtime.CompilerServices.RuntimeHelpers::InitializeArray(class [mscorlib]System.Array, valuetype[mscorlib] System.RuntimeFieldHandle) + pop + ldc.i4 0 + stloc.0 + leave exit + } + catch [mscorlib]System.ArgumentException + { + pop + ldc.i4 1 + stloc.0 + leave exit + } + + exit: + ldloc.0 + ret + } + +// +// ArrayEquals was generated from the following C# code: +// +//static bool ArrayEquals(Array x, Array y) +//{ +// if (x.Rank != y.Rank) +// return false; + +// var lower = new int[x.Rank]; +// var indices = new int[x.Rank]; +// var upper = new int[x.Rank]; + +// for (int i = 0; i < indices.Length; i++) +// { +// if (x.GetLowerBound(i) != y.GetLowerBound(i)) +// return false; +// if (x.GetLength(i) != y.GetLength(i)) +// return false; +// lower[i] = x.GetLowerBound(i); +// indices[i] = lower[i]; +// upper[i] = lower[i] + x.GetLength(i); +// } + +// while (true) +// { +// if (!object.Equals(x.GetValue(indices), y.GetValue(indices))) +// return false; + +// int i = 0; +// indices[i]++; + +// while (indices[i] >= upper[i]) +// { +// indices[i] = lower[i]; +// i++; + +// if (i >= indices.Length) +// return true; + +// indices[i]++; +// } +// } +//} + + .method private hidebysig static bool ArrayEquals(class [mscorlib]System.Array x, class [mscorlib]System.Array y) cil managed + { + .maxstack 5 + .locals init ( + [0] int32[] lower, + [1] int32[] indices, + [2] int32[] upper, + [3] int32 i, + [4] int32 V_4) + L_0000: ldarg.0 + L_0001: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_0006: ldarg.1 + L_0007: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_000c: beq.s L_0010 + L_000e: ldc.i4.0 + L_000f: ret + L_0010: ldarg.0 + L_0011: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_0016: newarr int32 + L_001b: stloc.0 + L_001c: ldarg.0 + L_001d: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_0022: newarr int32 + L_0027: stloc.1 + L_0028: ldarg.0 + L_0029: callvirt instance int32 [mscorlib]System.Array::get_Rank() + L_002e: newarr int32 + L_0033: stloc.2 + L_0034: ldc.i4.0 + L_0035: stloc.3 + L_0036: br.s L_007e + L_0038: ldarg.0 + L_0039: ldloc.3 + L_003a: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + L_003f: ldarg.1 + L_0040: ldloc.3 + L_0041: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + L_0046: beq.s L_004a + L_0048: ldc.i4.0 + L_0049: ret + L_004a: ldarg.0 + L_004b: ldloc.3 + L_004c: callvirt instance int32 [mscorlib]System.Array::GetLength(int32) + L_0051: ldarg.1 + L_0052: ldloc.3 + L_0053: callvirt instance int32 [mscorlib]System.Array::GetLength(int32) + L_0058: beq.s L_005c + L_005a: ldc.i4.0 + L_005b: ret + L_005c: ldloc.0 + L_005d: ldloc.3 + L_005e: ldarg.0 + L_005f: ldloc.3 + L_0060: callvirt instance int32 [mscorlib]System.Array::GetLowerBound(int32) + L_0065: stelem.i4 + L_0066: ldloc.1 + L_0067: ldloc.3 + L_0068: ldloc.0 + L_0069: ldloc.3 + L_006a: ldelem.i4 + L_006b: stelem.i4 + L_006c: ldloc.2 + L_006d: ldloc.3 + L_006e: ldloc.0 + L_006f: ldloc.3 + L_0070: ldelem.i4 + L_0071: ldarg.0 + L_0072: ldloc.3 + L_0073: callvirt instance int32 [mscorlib]System.Array::GetLength(int32) + L_0078: add + L_0079: stelem.i4 + L_007a: ldloc.3 + L_007b: ldc.i4.1 + L_007c: add + L_007d: stloc.3 + L_007e: ldloc.3 + L_007f: ldloc.1 + L_0080: ldlen + L_0081: conv.i4 + L_0082: blt.s L_0038 + L_0084: ldarg.0 + L_0085: ldloc.1 + L_0086: callvirt instance object [mscorlib]System.Array::GetValue(int32[]) + L_008b: ldarg.1 + L_008c: ldloc.1 + L_008d: callvirt instance object [mscorlib]System.Array::GetValue(int32[]) + L_0092: call bool [mscorlib]System.Object::Equals(object, object) + L_0097: brtrue.s L_009b + L_0099: ldc.i4.0 + L_009a: ret + L_009b: ldc.i4.0 + L_009c: stloc.s V_4 + L_009e: ldloc.1 + L_009f: ldloc.s V_4 + L_00a1: ldelema int32 + L_00a6: dup + L_00a7: ldind.i4 + L_00a8: ldc.i4.1 + L_00a9: add + L_00aa: stind.i4 + L_00ab: br.s L_00d1 + L_00ad: ldloc.1 + L_00ae: ldloc.s V_4 + L_00b0: ldloc.0 + L_00b1: ldloc.s V_4 + L_00b3: ldelem.i4 + L_00b4: stelem.i4 + L_00b5: ldloc.s V_4 + L_00b7: ldc.i4.1 + L_00b8: add + L_00b9: stloc.s V_4 + L_00bb: ldloc.s V_4 + L_00bd: ldloc.1 + L_00be: ldlen + L_00bf: conv.i4 + L_00c0: blt.s L_00c4 + L_00c2: ldc.i4.1 + L_00c3: ret + L_00c4: ldloc.1 + L_00c5: ldloc.s V_4 + L_00c7: ldelema int32 + L_00cc: dup + L_00cd: ldind.i4 + L_00ce: ldc.i4.1 + L_00cf: add + L_00d0: stind.i4 + L_00d1: ldloc.1 + L_00d2: ldloc.s V_4 + L_00d4: ldelem.i4 + L_00d5: ldloc.2 + L_00d6: ldloc.s V_4 + L_00d8: ldelem.i4 + L_00d9: bge.s L_00ad + L_00db: br.s L_0084 + } + + .method public hidebysig specialname rtspecialname instance void .ctor() cil managed + { + .maxstack 8 + ldarg.0 + call instance void [mscorlib]System.Object::.ctor() + ret + } +} + +.class private auto ansi 'ArrayInitializers' extends [mscorlib]System.Object +{ + .class explicit ansi sealed nested private 'StaticArrayInitTypeSize20' extends [mscorlib]System.ValueType + { + .pack 1 + .size 20 + } + + .class explicit ansi sealed nested private 'StaticArrayInitTypeSize40' extends [mscorlib]System.ValueType + { + .pack 1 + .size 40 + } + + .class explicit ansi sealed nested private 'StaticArrayInitTypeSize80' extends [mscorlib]System.ValueType + { + .pack 1 + .size 80 + } + + .field static assembly valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize20' 'InitializerField20' at InitializerField20Data + .field static assembly valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize40' 'InitializerField40' at InitializerField40Data + .field static assembly valuetype 'ArrayInitializers'/'StaticArrayInitTypeSize80' 'InitializerField80' at InitializerField80Data +} + +.data cil InitializerField20Data = bytearray (01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14) + +.data cil InitializerField40Data = bytearray (01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 + 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28) + +.data cil InitializerField80Data = bytearray (01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 + 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 + 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C + 3D 3E 3F 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50)