Skip to content

Commit eb09ba9

Browse files
Fix handling of CreateScalarUnsafe for embedded broadcast (#87134)
* Adding a regression test for #87116 * Ensure IsContainableHWIntrinsicOp takes into account whether CreateScalarUnsafe is coming from memory for embedded broadcast
1 parent 54dab73 commit eb09ba9

5 files changed

Lines changed: 86 additions & 5 deletions

File tree

src/coreclr/jit/gentree.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25059,6 +25059,37 @@ bool GenTreeHWIntrinsic::OperIsBroadcastScalar() const
2505925059
#endif
2506025060
}
2506125061

25062+
//------------------------------------------------------------------------
25063+
// OperIsCreateScalarUnsafe: Is this HWIntrinsic a CreateScalarUnsafe node.
25064+
//
25065+
// Return Value:
25066+
// Whether "this" is a CreateScalarUnsafe node.
25067+
//
25068+
bool GenTreeHWIntrinsic::OperIsCreateScalarUnsafe() const
25069+
{
25070+
NamedIntrinsic intrinsicId = GetHWIntrinsicId();
25071+
25072+
switch (intrinsicId)
25073+
{
25074+
#if defined(TARGET_ARM64)
25075+
case NI_Vector64_CreateScalarUnsafe:
25076+
#endif // TARGET_ARM64
25077+
case NI_Vector128_CreateScalarUnsafe:
25078+
#if defined(TARGET_XARCH)
25079+
case NI_Vector256_CreateScalarUnsafe:
25080+
case NI_Vector512_CreateScalarUnsafe:
25081+
#endif // TARGET_XARCH
25082+
{
25083+
return true;
25084+
}
25085+
25086+
default:
25087+
{
25088+
return false;
25089+
}
25090+
}
25091+
}
25092+
2506225093
//------------------------------------------------------------------------------
2506325094
// OperRequiresAsgFlag : Check whether the operation requires GTF_ASG flag regardless
2506425095
// of the children's flags.

src/coreclr/jit/gentree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6245,6 +6245,7 @@ struct GenTreeHWIntrinsic : public GenTreeJitIntrinsic
62456245
bool OperIsMemoryStoreOrBarrier() const;
62466246
bool OperIsEmbBroadcastCompatible() const;
62476247
bool OperIsBroadcastScalar() const;
6248+
bool OperIsCreateScalarUnsafe() const;
62486249

62496250
bool OperRequiresAsgFlag() const;
62506251
bool OperRequiresCallFlag() const;

src/coreclr/jit/lowerxarch.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7599,7 +7599,7 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre
75997599

76007600
GenTree* op1 = hwintrinsic->Op(1);
76017601

7602-
if (IsSafeToContainMem(parentNode, hwintrinsic, op1))
7602+
if (IsInvariantInRange(op1, parentNode, hwintrinsic))
76037603
{
76047604
if (op1->isContained())
76057605
{
@@ -7706,14 +7706,29 @@ bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* parentNode, GenTre
77067706
if (intrinsicId == NI_SSE3_MoveAndDuplicate)
77077707
{
77087708
// NI_SSE3_MoveAndDuplicate is for Vector128<double> only.
7709-
assert(childNode->AsHWIntrinsic()->GetSimdBaseType() == TYP_DOUBLE);
7709+
assert(hwintrinsic->GetSimdBaseType() == TYP_DOUBLE);
77107710
}
7711+
77117712
if (comp->compOpportunisticallyDependsOn(InstructionSet_AVX512F_VL) &&
77127713
parentNode->OperIsEmbBroadcastCompatible())
77137714
{
7714-
GenTree* broadcastOperand = childNode->AsHWIntrinsic()->Op(1);
7715-
bool childSupportsRegOptional;
7716-
if (IsContainableHWIntrinsicOp(childNode->AsHWIntrinsic(), broadcastOperand, &childSupportsRegOptional))
7715+
GenTree* broadcastOperand = hwintrinsic->Op(1);
7716+
7717+
if (broadcastOperand->OperIsHWIntrinsic())
7718+
{
7719+
GenTreeHWIntrinsic* hwintrinsicOperand = broadcastOperand->AsHWIntrinsic();
7720+
7721+
if (hwintrinsicOperand->OperIsCreateScalarUnsafe())
7722+
{
7723+
// CreateScalarUnsafe can contain non-memory operands such as enregistered
7724+
// locals, so we want to check if its operand is containable instead. This
7725+
// will result in such enregistered locals returning `false`.
7726+
broadcastOperand = hwintrinsicOperand->Op(1);
7727+
}
7728+
}
7729+
7730+
bool childSupportsRegOptional;
7731+
if (IsContainableHWIntrinsicOp(hwintrinsic, broadcastOperand, &childSupportsRegOptional))
77177732
{
77187733
return true;
77197734
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Runtime.CompilerServices;
6+
using System.Runtime.Intrinsics;
7+
using Xunit;
8+
9+
public class Runtime_87116
10+
{
11+
[Fact]
12+
public static int Test()
13+
{
14+
return TryVectorAdd(1, 2, 1 + 2) ? 100 : 0;
15+
}
16+
17+
[MethodImpl(MethodImplOptions.NoInlining)]
18+
public static bool TryVectorAdd(float a, float b, float c)
19+
{
20+
Vector128<float> A = Vector128.Create(a);
21+
Vector128<float> B = Vector128.Create(b);
22+
23+
Vector128<float> C = A + B;
24+
return C == Vector128.Create(c);
25+
}
26+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<Optimize>True</Optimize>
4+
</PropertyGroup>
5+
<ItemGroup>
6+
<Compile Include="$(MSBuildProjectName).cs" />
7+
</ItemGroup>
8+
</Project>

0 commit comments

Comments
 (0)