Skip to content

Commit

Permalink
Fold some HW nodes for constant input (#78929)
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorBo authored Dec 1, 2022
1 parent 69cdbf1 commit 92ad3c3
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 12 deletions.
3 changes: 3 additions & 0 deletions src/coreclr/jit/assertionprop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6119,6 +6119,9 @@ Compiler::fgWalkResult Compiler::optVNConstantPropCurStmt(BasicBlock* block, Sta
case GT_NEG:
case GT_CAST:
case GT_INTRINSIC:
#ifdef FEATURE_HW_INTRINSICS
case GT_HWINTRINSIC:
#endif
case GT_ARR_LENGTH:
break;

Expand Down
73 changes: 61 additions & 12 deletions src/coreclr/jit/valuenum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6001,6 +6001,59 @@ void ValueNumStore::SetVNIsCheckedBound(ValueNum vn)
m_checkedBoundVNs.AddOrUpdate(vn, true);
}

#ifdef FEATURE_HW_INTRINSICS
ValueNum ValueNumStore::EvalHWIntrinsicFunUnary(
var_types type, NamedIntrinsic ni, VNFunc func, ValueNum arg0VN, bool encodeResultType, ValueNum resultTypeVN)
{
if (IsVNConstant(arg0VN))
{
switch (ni)
{
#ifdef TARGET_ARM64
case NI_ArmBase_LeadingZeroCount:
#else
case NI_LZCNT_LeadingZeroCount:
#endif
{
UINT32 cns = (UINT32)GetConstantInt32(arg0VN);
int lzc = 0;
while (cns != 0)
{
cns = cns >> 1;
lzc++;
}
return VNForIntCon(32 - lzc);
}

#ifdef TARGET_ARM64
case NI_ArmBase_Arm64_LeadingZeroCount:
#else
case NI_LZCNT_X64_LeadingZeroCount:
#endif
{
UINT64 cns = (UINT64)GetConstantInt64(arg0VN);
int lzc = 0;
while (cns != 0)
{
cns = cns >> 1;
lzc++;
}
return VNForIntCon(64 - lzc);
}

default:
break;
}
}

if (encodeResultType)
{
return VNForFunc(type, func, arg0VN, resultTypeVN);
}
return VNForFunc(type, func, arg0VN);
}
#endif

ValueNum ValueNumStore::EvalMathFuncUnary(var_types typ, NamedIntrinsic gtMathFN, ValueNum arg0VN)
{
assert(arg0VN == VNNormalValue(arg0VN));
Expand Down Expand Up @@ -9769,25 +9822,21 @@ void Compiler::fgValueNumberHWIntrinsic(GenTreeHWIntrinsic* tree)

if (tree->GetOperandCount() == 1)
{
excSetPair = op1Xvnp;
ValueNum normalLVN =
vnStore->EvalHWIntrinsicFunUnary(tree->TypeGet(), intrinsicId, func, op1vnp.GetLiberal(),
encodeResultType, resultTypeVNPair.GetLiberal());
ValueNum normalCVN =
vnStore->EvalHWIntrinsicFunUnary(tree->TypeGet(), intrinsicId, func, op1vnp.GetConservative(),
encodeResultType, resultTypeVNPair.GetConservative());

if (encodeResultType)
{
normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp, resultTypeVNPair);
assert((vnStore->VNFuncArity(func) == 2) || isVariableNumArgs);
}
else
{
normalPair = vnStore->VNPairForFunc(tree->TypeGet(), func, op1vnp);
assert((vnStore->VNFuncArity(func) == 1) || isVariableNumArgs);
}
normalPair = ValueNumPair(normalLVN, normalCVN);
excSetPair = op1Xvnp;
}
else
{
ValueNumPair op2vnp;
ValueNumPair op2Xvnp;
getOperandVNs(tree->Op(2), &op2vnp, &op2Xvnp);

excSetPair = vnStore->VNPExcSetUnion(op1Xvnp, op2Xvnp);
if (encodeResultType)
{
Expand Down
3 changes: 3 additions & 0 deletions src/coreclr/jit/valuenum.h
Original file line number Diff line number Diff line change
Expand Up @@ -1108,6 +1108,9 @@ class ValueNumStore
EvalMathFuncBinary(typ, mthFunc, arg0VNP.GetConservative(), arg1VNP.GetConservative()));
}

ValueNum EvalHWIntrinsicFunUnary(
var_types type, NamedIntrinsic ni, VNFunc func, ValueNum arg0VN, bool encodeResultType, ValueNum resultTypeVN);

// Returns "true" iff "vn" represents a function application.
bool IsVNFunc(ValueNum vn);

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using Xunit;

public class ScalarConstantFoldings
{
[Fact]
public static void LeadingZeroCountTests()
{
if (Lzcnt.IsSupported)
{
Assert.Equal(32U, Lzcnt.LeadingZeroCount(0));
Assert.Equal(31U, Lzcnt.LeadingZeroCount(1));
Assert.Equal(17U, Lzcnt.LeadingZeroCount(31400));
Assert.Equal(0U, Lzcnt.LeadingZeroCount(1U << 31));
Assert.Equal(0U, Lzcnt.LeadingZeroCount(uint.MaxValue));
Assert.Equal(0U, Lzcnt.LeadingZeroCount(uint.MaxValue - 1));
}
if (Lzcnt.X64.IsSupported)
{
Assert.Equal(64UL, Lzcnt.X64.LeadingZeroCount(0));
Assert.Equal(63UL, Lzcnt.X64.LeadingZeroCount(1));
Assert.Equal(49UL, Lzcnt.X64.LeadingZeroCount(31400));
Assert.Equal(32UL, Lzcnt.X64.LeadingZeroCount(1UL << 31));
Assert.Equal(0UL, Lzcnt.X64.LeadingZeroCount(1UL << 63));
Assert.Equal(0UL, Lzcnt.X64.LeadingZeroCount(ulong.MaxValue));
Assert.Equal(0UL, Lzcnt.X64.LeadingZeroCount(ulong.MaxValue - 1));
}
if (ArmBase.IsSupported)
{
Assert.Equal(32, ArmBase.LeadingZeroCount(0));
Assert.Equal(31, ArmBase.LeadingZeroCount(1));
Assert.Equal(17, ArmBase.LeadingZeroCount(31400));
Assert.Equal(0, ArmBase.LeadingZeroCount(1U << 31));
Assert.Equal(0, ArmBase.LeadingZeroCount(uint.MaxValue));
Assert.Equal(0, ArmBase.LeadingZeroCount(uint.MaxValue - 1));
}
if (ArmBase.Arm64.IsSupported)
{
Assert.Equal(64, ArmBase.Arm64.LeadingZeroCount(0));
Assert.Equal(63, ArmBase.Arm64.LeadingZeroCount(1));
Assert.Equal(49, ArmBase.Arm64.LeadingZeroCount(31400));
Assert.Equal(32, ArmBase.Arm64.LeadingZeroCount(1UL << 31));
Assert.Equal(0, ArmBase.Arm64.LeadingZeroCount(1UL << 63));
Assert.Equal(0, ArmBase.Arm64.LeadingZeroCount(ulong.MaxValue));
Assert.Equal(0, ArmBase.Arm64.LeadingZeroCount(ulong.MaxValue - 1));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<BuildAsStandalone>false</BuildAsStandalone>
<Optimize>True</Optimize>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildProjectName).cs" />
</ItemGroup>
</Project>

0 comments on commit 92ad3c3

Please sign in to comment.