diff --git a/src/coreclr/interpreter/compiler.cpp b/src/coreclr/interpreter/compiler.cpp index 9f8ee45fb17761..31ba50c77aa830 100644 --- a/src/coreclr/interpreter/compiler.cpp +++ b/src/coreclr/interpreter/compiler.cpp @@ -6156,13 +6156,11 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) m_ip++; uint32_t n = getU4LittleEndian(m_ip); // Format of switch instruction is opcode + srcVal + n + T1 + T2 + ... + Tn - AddInsExplicit(INTOP_SWITCH, n + 3); - m_pLastNewIns->data[0] = n; m_ip += 4; const uint8_t *nextIp = m_ip + n * 4; m_pStackPointer--; - m_pLastNewIns->SetSVar(m_pStackPointer->var); InterpBasicBlock **targetBBTable = (InterpBasicBlock**)AllocMemPool(sizeof (InterpBasicBlock*) * n); + uint32_t *targetOffsets = (uint32_t*)AllocMemPool(sizeof (uint32_t) * n); for (uint32_t i = 0; i < n; i++) { @@ -6170,12 +6168,36 @@ void InterpCompiler::GenerateCode(CORINFO_METHOD_INFO* methodInfo) uint32_t target = (uint32_t)(nextIp - m_pILCode + offset); InterpBasicBlock *targetBB = m_ppOffsetToBB[target]; assert(targetBB); - - InitBBStackState(targetBB); + targetOffsets[i] = target; targetBBTable[i] = targetBB; - LinkBBs(m_pCBB, targetBB); m_ip += 4; } + + // Sort the targetOffsets array so that we can easily skip duplicates + qsort(targetOffsets, n, sizeof(uint32_t), [](const void* a, const void* b) { + uint32_t valA = *(const uint32_t*)a; + uint32_t valB = *(const uint32_t*)b; + return (valA < valB) ? -1 : (valA > valB) ? 1 : 0; + }); + + // Setup so that we can safely branch to each target + uint32_t lastOffset = UINT32_MAX; + for (uint32_t i = 0; i < n; i++) + { + if (targetOffsets[i] != lastOffset) + { + lastOffset = targetOffsets[i]; + InterpBasicBlock *targetBB = m_ppOffsetToBB[targetOffsets[i]]; + assert(targetBB); + EmitBBEndVarMoves(targetBB); + InitBBStackState(targetBB); + LinkBBs(m_pCBB, targetBB); + } + } + + AddInsExplicit(INTOP_SWITCH, n + 3); + m_pLastNewIns->data[0] = n; + m_pLastNewIns->SetSVar(m_pStackPointer->var); m_pLastNewIns->info.ppTargetBBTable = targetBBTable; break; } diff --git a/src/tests/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b44861/b44861_2.il b/src/tests/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b44861/b44861_2.il new file mode 100644 index 00000000000000..f29fe9b824e641 --- /dev/null +++ b/src/tests/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b44861/b44861_2.il @@ -0,0 +1,100 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + + + + + +.assembly extern mscorlib { } +.assembly extern System.Console +{ + .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) + .ver 4:0:0:0 +} +.assembly 'b44861_2'// as "b" +{ + + + // bool) = ( 01 00 00 01 00 00 ) + + +} +.assembly extern xunit.core {} +// MVID: {0573B9C2-3980-4A83-9B01-889CCC1D6FBC} +.namespace Test +{ + .class public auto ansi App + extends [mscorlib]System.Object + { + .method public hidebysig static int32 + Main() il managed + { + .custom instance void [xunit.core]Xunit.FactAttribute::.ctor() = ( + 01 00 00 00 + ) + .entrypoint + // Code size 31 (0x1f) + .maxstack 6 + //init counter with -1 + ldc.i4.m1 + first_again: + ldc.i4.1 + add + //print out counter + ldstr "first_again value is " + call void [System.Console]System.Console::Write(class [mscorlib]System.String) + dup + call void [System.Console]System.Console::WriteLine(int32) + dup + brtrue do_switch + pop + ldc.i4.m1 + again: + //increment counter + ldc.i4.1 + add + //print out counter + ldstr "value is " + call void [System.Console]System.Console::Write(class [mscorlib]System.String) + dup + call void [System.Console]System.Console::WriteLine(int32) + do_switch: + //make a switch + dup + switch (first_again, first_again, first_again, again, again, again, stop) + //switch worked incorrectly + //throw an exception + newobj instance void [mscorlib]System.Exception::.ctor() + throw + stop: + //check counter + //we should reach here when counter=6 + ldc.i4 6 + ceq + brfalse wrong + ldstr "passed" + call void [System.Console]System.Console::Write(class [mscorlib]System.String) + br done + wrong: + ldstr "failed" + call void [System.Console]System.Console::Write(class [mscorlib]System.String) + done: + ldc.i4 100 + ret + } // end of method 'App::Main' + + .method public hidebysig specialname rtspecialname + instance void .ctor() il managed + { + // Code size 7 (0x7) + .maxstack 8 + IL_0000: ldarg.0 + IL_0001: call instance void [mscorlib]System.Object::.ctor() + IL_0006: ret + } // end of method 'App::.ctor' + + } // end of class 'App' + +} // end of namespace 'Test' + +//*********** DISASSEMBLY COMPLETE *********************** diff --git a/src/tests/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b44861/b44861_2.ilproj b/src/tests/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b44861/b44861_2.ilproj new file mode 100644 index 00000000000000..7c7ed9f1abff72 --- /dev/null +++ b/src/tests/JIT/Regression/CLR-x86-JIT/V1-M11-Beta1/b44861/b44861_2.ilproj @@ -0,0 +1,12 @@ + + + 1 + + + PdbOnly + True + + + + +