From 6f1e03f1bfa04e00627173e51790df700438443e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 2 Jan 2022 20:20:00 -0600 Subject: [PATCH] [release/6.0] Do not promote struct locals with holes (#62738) * Make sure the combined field size matches the struct size * Fix the condition * Update test and include containHoles condition Co-authored-by: Kunal Pathak --- src/coreclr/jit/lclvars.cpp | 9 ++- .../JitBlue/Runtime_62597/Runtime_62597.cs | 70 ++++++++++++++++++++++ .../JitBlue/Runtime_62597/Runtime_62597.csproj | 13 ++++ 3 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_62597/Runtime_62597.cs create mode 100644 src/tests/JIT/Regression/JitBlue/Runtime_62597/Runtime_62597.csproj diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index df083c7..6b70323 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -2103,8 +2103,13 @@ bool Compiler::StructPromotionHelper::ShouldPromoteStructVar(unsigned lclNum) // multiple registers? if (compiler->lvaIsMultiregStruct(varDsc, compiler->info.compIsVarArgs)) { - if ((structPromotionInfo.fieldCnt != 2) && - !((structPromotionInfo.fieldCnt == 1) && varTypeIsSIMD(structPromotionInfo.fields[0].fldType))) + if (structPromotionInfo.containsHoles && structPromotionInfo.customLayout) + { + JITDUMP("Not promoting multi-reg struct local V%02u with holes.\n", lclNum); + shouldPromote = false; + } + else if ((structPromotionInfo.fieldCnt != 2) && + !((structPromotionInfo.fieldCnt == 1) && varTypeIsSIMD(structPromotionInfo.fields[0].fldType))) { JITDUMP("Not promoting multireg struct local V%02u, because lvIsParam is true, #fields != 2 and it's " "not a single SIMD.\n", diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_62597/Runtime_62597.cs b/src/tests/JIT/Regression/JitBlue/Runtime_62597/Runtime_62597.cs new file mode 100644 index 0000000..fb3ccef --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_62597/Runtime_62597.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// +// Note: In below test case, we were not honoring the fact that the explicit struct size +// of struct is 32 bytes while the only 2 fields it has is just 2 bytes. In such case, +// we would pass partial struct value. +using System; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Text; + +[StructLayout(LayoutKind.Explicit, Size = 32)] +public readonly unsafe struct SmallString +{ + [FieldOffset(0)] private readonly byte _length; + [FieldOffset(1)] private readonly byte _firstByte; + + public SmallString(string value) + { + fixed (char* srcPtr = value) + fixed (byte* destPtr = &_firstByte) + { + Encoding.ASCII.GetBytes(srcPtr, value.Length, destPtr, value.Length); + } + + _length = (byte)value.Length; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public byte Dump() + { + fixed (byte* ptr = &_firstByte) + { + byte* next = ptr + 1; + return *next; + } + } +} + +public static class Program +{ + static int result = 0; + public static int Main() + { + var value = new SmallString("foobar"); + + TheTest(value); + + return result; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static void TheTest(SmallString foo) + { + Execute(foo); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + public static object Execute(SmallString foo) + { + byte value = foo.Dump(); + // 111 corresponds to the ASCII code of 2nd characted of string "foobar" i.e. ASCII value of 'o'. + if (value == 111) + { + result = 100; + } + return new StringBuilder(); + } +} diff --git a/src/tests/JIT/Regression/JitBlue/Runtime_62597/Runtime_62597.csproj b/src/tests/JIT/Regression/JitBlue/Runtime_62597/Runtime_62597.csproj new file mode 100644 index 0000000..e822a8b --- /dev/null +++ b/src/tests/JIT/Regression/JitBlue/Runtime_62597/Runtime_62597.csproj @@ -0,0 +1,13 @@ + + + Exe + True + + + None + True + + + + + \ No newline at end of file -- 2.7.4