From 0b3893512cd9b7e32fae18551538ebdc0564937b Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 21 May 2025 14:31:59 +0200 Subject: [PATCH 1/2] JIT: Fix SysV first/second return register GC info mismatch when generating calls On SysV it is possible to have mixed SIMD/integer return registers for calls. This leads to a case where the first return register is a SIMD register, while the second return register is an integer register. In that particular case, the emitter would get confused and expect GC information for the second return register to refer to `rdx`, when in reality it refers to `rax`. Fix the problem by detecting the case where the second register is `rax`, and communicating the right information back to the emitter. Also add a test case that reliably segfaults under `DOTNET_GCStress=C` without the fix. --- src/coreclr/jit/codegenxarch.cpp | 12 ++++++ .../JitBlue/Runtime_115815/Runtime_115815.cs | 42 +++++++++++++++++++ .../Runtime_115815/Runtime_115815.csproj | 8 ++++ 3 files changed, 62 insertions(+) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.csproj diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 1c17e0b4e1d497..1ff6d6cda12d98 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -6293,6 +6293,18 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA { params.retSize = emitTypeSize(retTypeDesc->GetReturnRegType(0)); params.secondRetSize = emitTypeSize(retTypeDesc->GetReturnRegType(1)); + + if (retTypeDesc->GetABIReturnReg(1, call->GetUnmanagedCallConv()) == REG_INTRET) + { + // If the second return register is REG_INTRET, then the first + // return is expected to be in a SIMD register. + // The emitter has hardcoded belief that params.retSize corresponds to + // REG_INTRET and secondRetSize to REG_INTRET_1, so fix up the + // situation here. + assert(!EA_IS_GCREF_OR_BYREF(params.retSize)); + params.retSize = params.secondRetSize; + params.secondRetSize = EA_UNKNOWN; + } } else { diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.cs b/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.cs new file mode 100644 index 00000000000000..ccd925aac17a74 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.cs @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Threading; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Xunit; + +public class Runtime_115815 +{ + [Fact] + public static void TestEntryPoint() + { + var destination = new KeyValuePair[1_000_000]; + + // loop to make this method fully interruptible + to get into OSR version + for (int i = 0; i < destination.Length; i++) + { + destination[i] = default; + } + + for (int i = 0; i < 5; i++) + { + for (int j = 0; j < destination.Length; j++) + { + destination[j] = GetValue(j); + } + + Thread.Sleep(10); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static KeyValuePair GetValue(int i) + => KeyValuePair.Create(new Container(i.ToString()), (double)i); + + private struct Container + { + public string Name; + public Container(string name) { this.Name = name; } + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.csproj new file mode 100644 index 00000000000000..de6d5e08882e86 --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_115815/Runtime_115815.csproj @@ -0,0 +1,8 @@ + + + True + + + + + From 5d627e22da6a0842304565d1b265c708f1693b1d Mon Sep 17 00:00:00 2001 From: Jakob Botsch Nielsen Date: Wed, 21 May 2025 14:54:01 +0200 Subject: [PATCH 2/2] Run jit-format --- src/coreclr/jit/codegenxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/codegenxarch.cpp b/src/coreclr/jit/codegenxarch.cpp index 1ff6d6cda12d98..40d7f380fb9aaa 100644 --- a/src/coreclr/jit/codegenxarch.cpp +++ b/src/coreclr/jit/codegenxarch.cpp @@ -6302,7 +6302,7 @@ void CodeGen::genCallInstruction(GenTreeCall* call X86_ARG(target_ssize_t stackA // REG_INTRET and secondRetSize to REG_INTRET_1, so fix up the // situation here. assert(!EA_IS_GCREF_OR_BYREF(params.retSize)); - params.retSize = params.secondRetSize; + params.retSize = params.secondRetSize; params.secondRetSize = EA_UNKNOWN; } }