From 87f781387c345bd308d7a7ae55de2b1a7430b160 Mon Sep 17 00:00:00 2001 From: Andy Ayers Date: Fri, 29 Jun 2018 03:01:57 -0700 Subject: [PATCH] JIT: fix regression when returning struct with no fields on SysV The runtime classifies such structs as being returned by reference, so we need to follow suit in the jit. If the classifier says the value can't be returned in a register, then so be it. Add a test case. --- src/jit/compiler.cpp | 13 +++- .../JitBlue/GitHub_18522/GitHub_18522_8.cs | 65 +++++++++++++++++++ .../GitHub_18522/GitHub_18522_8.csproj | 34 ++++++++++ 3 files changed, 109 insertions(+), 3 deletions(-) create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.cs create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.csproj diff --git a/src/jit/compiler.cpp b/src/jit/compiler.cpp index 5e8088d2c476..170cf389978e 100644 --- a/src/jit/compiler.cpp +++ b/src/jit/compiler.cpp @@ -992,8 +992,9 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, structPassingKind* wbReturnStruct /* = nullptr */, unsigned structSize /* = 0 */) { - var_types useType = TYP_UNKNOWN; - structPassingKind howToReturnStruct = SPK_Unknown; // We must change this before we return + var_types useType = TYP_UNKNOWN; + structPassingKind howToReturnStruct = SPK_Unknown; // We must change this before we return + bool canReturnInRegister = true; assert(clsHnd != NO_CLASS_HANDLE); @@ -1013,6 +1014,7 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, if (structDesc.eightByteCount == 1) { assert(structSize <= sizeof(double)); + assert(structDesc.passedInRegisters); if (structDesc.eightByteClassifications[0] == SystemVClassificationTypeSSE) { @@ -1022,6 +1024,11 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, howToReturnStruct = SPK_PrimitiveType; } } + else + { + // Return classification is not always size based... + canReturnInRegister = structDesc.passedInRegisters; + } #endif // UNIX_AMD64_ABI @@ -1031,7 +1038,7 @@ var_types Compiler::getReturnTypeForStruct(CORINFO_CLASS_HANDLE clsHnd, // The largest primitive type is 8 bytes (TYP_DOUBLE) // so we can skip calling getPrimitiveTypeForStruct when we // have a struct that is larger than that. - if ((useType == TYP_UNKNOWN) && (structSize <= sizeof(double))) + if (canReturnInRegister && (useType == TYP_UNKNOWN) && (structSize <= sizeof(double))) { // We set the "primitive" useType based upon the structSize // and also examine the clsHnd to see if it is an HFA of count one diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.cs b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.cs new file mode 100644 index 000000000000..9bd91be9125e --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; + +// Based on +// Original generated by Fuzzlyn on 2018-06-20 00:58:58 +// Seed: 11049252875418439527 +// Reduced from 97.5 KiB to 0.5 KiB +// Debug: Outputs -1 +// Release: Outputs -65536 + +// Similar to other variants but using an empty (~ 1 byte) struct +// (which oddly enough currently is returned by ref) + +struct S0 +{ +} + +struct S1 +{ + public S0 F3; + public sbyte F4; + public short F0; + public S1(sbyte f4): this() + { + F4 = f4; + } +} + +public class GitHub_18522_8 +{ + static S1 s_6; + static S1[] s_13 = new S1[]{new S1(-1)}; + public static int Main() + { + // When generating code for the x64 SysV ABI, the jit was + // incorrectly typing the return type from M16, and so + // inadvertently overwriting the F4 field of s_13[0] on return + // from the call. + // + // Here we make sure we properly handle the failed inline case. + s_13[0].F3 = M16(); + return s_13[0].F4 == -1 ? 100 : 0; + } + + static S0 M16() + { + // This bit of code is intended to allow M16 to be an + // inline candidate that ultimately does not get inlined. + short x = 0; + for (int i = 0; i < 10; i++) + { + for (int j = 0; j < 10; j++) + { + x++; + } + } + s_6.F0 = x; + + return s_6.F3; + } +} diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.csproj new file mode 100644 index 000000000000..95aba995a255 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.csproj @@ -0,0 +1,34 @@ + + + + + Debug + AnyCPU + $(MSBuildProjectName) + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + + True + + + + + + + + + +