diff --git a/src/coreclr/jit/inductionvariableopts.cpp b/src/coreclr/jit/inductionvariableopts.cpp index 3384175eee12ae..86d0d5e8802b9c 100644 --- a/src/coreclr/jit/inductionvariableopts.cpp +++ b/src/coreclr/jit/inductionvariableopts.cpp @@ -433,8 +433,8 @@ void PerLoopInfo::Invalidate(FlowGraphNaturalLoop* loop) // sense that all their predecessors must come from inside the loop. Loop // exit canonicalization guarantees this for regular exit blocks. It is not // guaranteed for exceptional exits, but we do not expect to widen IVs that -// are live into exceptional exits since those are marked DNER which makes it -// unprofitable anyway. +// are live into exceptional exits since those are not register candidates +// (see optWidenPrimaryIV) which makes it unprofitable anyway. // // Note that there may be natural loops that have not had their regular exits // canonicalized at the time when IV opts run, in particular if RBO/assertion @@ -1328,15 +1328,18 @@ bool Compiler::optLocalHasNonLoopUses(unsigned lclNum, FlowGraphNaturalLoop* loo return true; } - if (varDsc->lvDoNotEnregister) + if (!varDsc->lvTracked && !varDsc->lvInSsa) { - // This filters out locals that may be live into exceptional exits. + // We do not have liveness we can use for this untracked local. return true; } - if (!varDsc->lvTracked && !varDsc->lvInSsa) + if (varDsc->lvTracked && varDsc->IsLiveInOutOfHandler()) { - // We do not have liveness we can use for this untracked local. + // The local is live into an EH handler (an exceptional exit). The + // regular exit blocks visited below do not include handlers, and we + // use this as a cheap alternative to checking all EH successors + // of all blocks in the loop. return true; } @@ -1358,6 +1361,25 @@ bool Compiler::optLocalHasNonLoopUses(unsigned lclNum, FlowGraphNaturalLoop* loo return true; } +#ifdef DEBUG + // We currently do not expect to optimize locals that are live into exceptional + // exits. Such IVs are not currently register candidates (EH write-thru is + // only for single def locals) which makes it unprofitable. If this ever + // changes we need some more expansive handling here. + loop->VisitLoopBlocks([=](BasicBlock* block) { + block->VisitAllSuccs(this, [=](BasicBlock* succ) { + if (!loop->ContainsBlock(succ) && bbIsHandlerBeg(succ)) + { + assert(!optLocalIsLiveIntoBlock(lclNum, succ) && "Candidate local is live into exceptional exit"); + } + + return BasicBlockVisit::Continue; + }); + + return BasicBlockVisit::Continue; + }); +#endif + return false; } diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_128392/Runtime_128392.cs b/src/tests/JIT/Regression/JitBlue/Runtime_128392/Runtime_128392.cs new file mode 100644 index 00000000000000..9857cfe457ae8e --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_128392/Runtime_128392.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace Runtime_128392; + +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public static class Runtime_128392 +{ + private static long s_sink; + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void Process(int x) + { + if (x < 0) + { + throw new Exception("boom"); + } + + s_sink += x; + } + + // The loop counter 'i' is updated inside the try and read in the catch handler. + // Induction-variable optimization must not drop the in-loop update of 'i', since + // it is live into the EH handler; otherwise the handler observes a stale value. + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + private static int CountProcessedBeforeThrow(int[] values) + { + int i = 0; + try + { + for (; i < values.Length; i++) + { + Process(values[i]); + } + } + catch (Exception) + { + return i; + } + + return -1; + } + + [Fact] + public static void TestEntryPoint() + { + int[] values = { 0, 1, 2, -1, 4 }; + Assert.Equal(3, CountProcessedBeforeThrow(values)); + } +} diff --git a/src/tests/JIT/Regression/Regression_ro_2.csproj b/src/tests/JIT/Regression/Regression_ro_2.csproj index f8bedd81f9050b..f4bb02ae2ab609 100644 --- a/src/tests/JIT/Regression/Regression_ro_2.csproj +++ b/src/tests/JIT/Regression/Regression_ro_2.csproj @@ -98,6 +98,7 @@ +