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

Block the hoisting of TYP_STRUCT rvalues in loop hoisting #23739

Merged
merged 1 commit into from
Apr 9, 2019
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
32 changes: 21 additions & 11 deletions src/jit/optimizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6885,26 +6885,36 @@ bool Compiler::optHoistLoopExprsForTree(GenTree* tree,
// Tree must be a suitable CSE candidate for us to be able to hoist it.
treeIsHoistable &= optIsCSEcandidate(tree);

// If it's a call, it must be a helper call, and be pure.
// Further, if it may run a cctor, it must be labeled as "Hoistable"
// (meaning it won't run a cctor because the class is not precise-init).
if (treeIsHoistable && tree->OperGet() == GT_CALL)
if (treeIsHoistable)
{
GenTreeCall* call = tree->AsCall();
if (call->gtCallType != CT_HELPER)
// We cannot hoist an r-value of TYP_STRUCT
// as they currently do not carry full descriptors of the struct type
if (tree->TypeGet() == TYP_STRUCT)
{
treeIsHoistable = false;
}
else

// If it's a call, it must be a helper call, and be pure.
// Further, if it may run a cctor, it must be labeled as "Hoistable"
// (meaning it won't run a cctor because the class is not precise-init).
if (tree->OperGet() == GT_CALL)
{
CorInfoHelpFunc helpFunc = eeGetHelperNum(call->gtCallMethHnd);
if (!s_helperCallProperties.IsPure(helpFunc))
GenTreeCall* call = tree->AsCall();
if (call->gtCallType != CT_HELPER)
{
treeIsHoistable = false;
}
else if (s_helperCallProperties.MayRunCctor(helpFunc) && (call->gtFlags & GTF_CALL_HOISTABLE) == 0)
else
{
treeIsHoistable = false;
CorInfoHelpFunc helpFunc = eeGetHelperNum(call->gtCallMethHnd);
if (!s_helperCallProperties.IsPure(helpFunc))
{
treeIsHoistable = false;
}
else if (s_helperCallProperties.MayRunCctor(helpFunc) && (call->gtFlags & GTF_CALL_HOISTABLE) == 0)
{
treeIsHoistable = false;
}
}
}
}
Expand Down
212 changes: 212 additions & 0 deletions tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
// 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;

class GitHub_23739
{
struct Struct1f
{
float a;
}

class Cls1f
{
public Struct1f sf;
}

struct Struct2f
{
float a, b;
}

class Cls2f
{
public Struct2f sf;
}

struct Struct3f
{
float a, b, c;
}

class Cls3f
{
public Struct3f sf;
}

struct Struct4f
{
float a, b, c, d;
}

class Cls4f
{
public Struct4f sf;
}

struct Struct5f
{
float a, b, c, d, e;
}

class Cls5f
{
public Struct5f sf;
}

struct Struct6f
{
float a, b, c, d, e, f;
}

class Cls6f
{
public Struct6f sf;
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Sink<T>(ref T t)
{
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Test1f(Cls1f c)
{
Struct1f l1 = default;
Struct1f l2 = default;
Struct1f l3 = default;

for (int i = 0; i < 10; i++)
{
l1 = c.sf;
l2 = c.sf;
l3 = c.sf;
}

Sink(ref l1);
Sink(ref l2);
Sink(ref l3);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Test2f(Cls2f c)
{
Struct2f l1 = default;
Struct2f l2 = default;
Struct2f l3 = default;

for (int i = 0; i < 10; i++)
{
l1 = c.sf;
l2 = c.sf;
l3 = c.sf;
}

Sink(ref l1);
Sink(ref l2);
Sink(ref l3);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Test3f(Cls3f c)
{
Struct3f l1 = default;
Struct3f l2 = default;
Struct3f l3 = default;

for (int i = 0; i < 10; i++)
{
l1 = c.sf;
l2 = c.sf;
l3 = c.sf;
}

Sink(ref l1);
Sink(ref l2);
Sink(ref l3);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Test4f(Cls4f c)
{
Struct4f l1 = default;
Struct4f l2 = default;
Struct4f l3 = default;

for (int i = 0; i < 10; i++)
{
l1 = c.sf;
l2 = c.sf;
l3 = c.sf;
}

Sink(ref l1);
Sink(ref l2);
Sink(ref l3);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Test5f(Cls5f c)
{
Struct5f l1 = default;
Struct5f l2 = default;
Struct5f l3 = default;

for (int i = 0; i < 10; i++)
{
l1 = c.sf;
l2 = c.sf;
l3 = c.sf;
}

Sink(ref l1);
Sink(ref l2);
Sink(ref l3);
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Test6f(Cls6f c)
{
Struct6f l1 = default;
Struct6f l2 = default;
Struct6f l3 = default;

for (int i = 0; i < 10; i++)
{
l1 = c.sf;
l2 = c.sf;
l3 = c.sf;
}

Sink(ref l1);
Sink(ref l2);
Sink(ref l3);
}

static int Main()
{
Cls1f cls1f = new Cls1f();
Test1f(cls1f);

Cls2f cls2f = new Cls2f();
Test2f(cls2f);

Cls3f cls3f = new Cls3f();
Test3f(cls3f);

Cls4f cls4f = new Cls4f();
Test4f(cls4f);

Cls5f cls5f = new Cls5f();
Test5f(cls5f);

Cls6f cls6f = new Cls6f();
Test6f(cls6f);

return 100;
}
}
18 changes: 18 additions & 0 deletions tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?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)' == '' ">Release</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<AssemblyName>$(MSBuildProjectName)</AssemblyName>
<OutputType>Exe</OutputType>
<DebugType></DebugType>
<Optimize>True</Optimize>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
<PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
</Project>