Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

JIT: fix regression when returning struct with no fields on SysV #18708

Merged
merged 1 commit into from
Jun 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions src/jit/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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)
{
Expand All @@ -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

Expand All @@ -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
Expand Down
65 changes: 65 additions & 0 deletions tests/src/JIT/Regression/JitBlue/GitHub_18522/GitHub_18522_8.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
<OutputType>Exe</OutputType>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
</PropertyGroup>
<!-- Default configurations to help VS understand the configurations -->
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
<ItemGroup>
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
<Visible>False</Visible>
</CodeAnalysisDependentAssemblyPaths>
</ItemGroup>
<PropertyGroup>
<DebugType></DebugType>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
<PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
</Project>