From 81b0ec5019627e7a65715adb874f02621d6babfa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 15 Sep 2026 17:10:53 +0000 Subject: [PATCH 1/2] Initial plan From a3e6a916a27faf04f45eaae26bfa8d14bc2efee9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 15 Sep 2026 17:39:08 +0000 Subject: [PATCH 2/2] Preserve receiver evaluation order in Span indexer intrinsics Co-authored-by: EgorBo <523221+EgorBo@users.noreply.github.com> --- src/coreclr/jit/importercalls.cpp | 4 +- .../JIT/Regression_ro_2/Runtime_133963.cs | 80 +++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 src/tests/JIT/Regression_ro_2/Runtime_133963.cs diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 7b849454fc00ff..e93a17e6c9b33c 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -4069,7 +4069,7 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, isReadOnly ? "ReadOnly" : "", eeGetClassName(spanElemHnd), elemSize); GenTree* index = impPopStack().val; - GenTree* ptrToSpan = impPopStack().val; + GenTree* ptrToSpan = impStackTop().val; GenTree* indexClone = nullptr; GenTree* ptrToSpanClone = nullptr; assert(genActualType(index) == TYP_INT); @@ -4086,8 +4086,10 @@ GenTree* Compiler::impIntrinsic(CORINFO_CLASS_HANDLE clsHnd, #endif // defined(DEBUG) // We need to use both index and ptr-to-span twice, so clone or spill. + // Keep ptr-to-span on the stack so it is evaluated before any index spill. index = impCloneExpr(index, &indexClone, CHECK_SPILL_ALL, nullptr DEBUGARG("Span.get_Item index")); + ptrToSpan = impPopStack().val; if (impIsAddressInLocal(ptrToSpan)) { ptrToSpanClone = gtCloneExpr(ptrToSpan); diff --git a/src/tests/JIT/Regression_ro_2/Runtime_133963.cs b/src/tests/JIT/Regression_ro_2/Runtime_133963.cs new file mode 100644 index 00000000000000..f6a65d74910448 --- /dev/null +++ b/src/tests/JIT/Regression_ro_2/Runtime_133963.cs @@ -0,0 +1,80 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_133963 +{ + private static int s_index; + + [Theory] + [InlineData(false, 0)] + [InlineData(true, 0)] + [InlineData(false, 1)] + [InlineData(true, 1)] + [InlineData(false, 2)] + [InlineData(true, 2)] + [InlineData(false, 3)] + [InlineData(true, 3)] + public static void TestEntryPoint(bool readOnly, int testCase) + { + int[] data = { 10, 20 }; + Func test = () => readOnly ? TestReadOnlySpan(data, testCase) : TestSpan(data, testCase); + + s_index = 0; + if (testCase == 2) + { + Assert.Throws(() => test()); + } + else + { + Assert.Equal(20, test()); + } + Assert.Equal(testCase == 1 ? 2 : 1, s_index); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref Span GetSpan(ref Span span) + { + s_index++; + return ref span; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static ref ReadOnlySpan GetReadOnlySpan(ref ReadOnlySpan span) + { + s_index++; + return ref span; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static int GetIndex() => s_index++; + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + private static int TestSpan(int[] data, int testCase) + { + Span span = data; + return testCase switch + { + 0 => GetSpan(ref span)[s_index], + 1 => GetSpan(ref span)[GetIndex()], + 2 => GetSpan(ref span)[1 / (s_index - 1)], + _ => s_index + GetSpan(ref span)[s_index], + }; + } + + [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.AggressiveOptimization)] + private static int TestReadOnlySpan(int[] data, int testCase) + { + ReadOnlySpan span = data; + return testCase switch + { + 0 => GetReadOnlySpan(ref span)[s_index], + 1 => GetReadOnlySpan(ref span)[GetIndex()], + 2 => GetReadOnlySpan(ref span)[1 / (s_index - 1)], + _ => s_index + GetReadOnlySpan(ref span)[s_index], + }; + } +}