Block the hoisting of TYP_STRUCT rvalues in loop hoisting
authorBrian Sullivan <briansul@microsoft.com>
Thu, 4 Apr 2019 20:42:27 +0000 (13:42 -0700)
committerBrian Sullivan <briansul@microsoft.com>
Mon, 8 Apr 2019 22:21:34 +0000 (15:21 -0700)
Added test case GitHub_23739.cs

Commit migrated from https://github.com/dotnet/coreclr/commit/b87e6349c47b416e571ca905539ea3f6e0554ec7

src/coreclr/src/jit/optimizer.cpp
src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.cs [new file with mode: 0644]
src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.csproj [new file with mode: 0644]

index 431f4d5..7749e92 100644 (file)
@@ -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;
+                    }
                 }
             }
         }
diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.cs b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.cs
new file mode 100644 (file)
index 0000000..b75bc51
--- /dev/null
@@ -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;
+    }
+}
diff --git a/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.csproj b/src/coreclr/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.csproj
new file mode 100644 (file)
index 0000000..fb6ae36
--- /dev/null
@@ -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>