diff --git a/src/jit/optimizer.cpp b/src/jit/optimizer.cpp index 431f4d5ab1e6..7749e928ba5f 100644 --- a/src/jit/optimizer.cpp +++ b/src/jit/optimizer.cpp @@ -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/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.cs b/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.cs new file mode 100644 index 000000000000..b75bc5156850 --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.cs @@ -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(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/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.csproj new file mode 100644 index 000000000000..fb6ae363ebee --- /dev/null +++ b/tests/src/JIT/Regression/JitBlue/GitHub_23739/GitHub_23739.csproj @@ -0,0 +1,18 @@ + + + + + Release + AnyCPU + $(MSBuildProjectName) + Exe + + True + True + + + + + + +