From 92ad3c35798668ddf02f22e94d54b14e549252e9 Mon Sep 17 00:00:00 2001 From: Egor Bogatov Date: Thu, 1 Dec 2022 13:00:47 +0100 Subject: [PATCH] Fold some HW nodes for constant input (#78929) --- src/coreclr/jit/assertionprop.cpp | 3 + src/coreclr/jit/valuenum.cpp | 73 ++++++++++++++++++---- src/coreclr/jit/valuenum.h | 3 + .../ConstantFolding/ScalarConstantFoldings.cs | 54 ++++++++++++++++ .../ConstantFolding/ScalarConstantFoldings.csproj | 9 +++ 5 files changed, 130 insertions(+), 12 deletions(-) create mode 100644 src/tests/JIT/HardwareIntrinsics/General/ConstantFolding/ScalarConstantFoldings.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/General/ConstantFolding/ScalarConstantFoldings.csproj diff --git a/src/coreclr/jit/assertionprop.cpp b/src/coreclr/jit/assertionprop.cpp index 59cf0dc..2111644 100644 --- a/src/coreclr/jit/assertionprop.cpp +++ b/src/coreclr/jit/assertionprop.cpp @@ -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; diff --git a/src/coreclr/jit/valuenum.cpp b/src/coreclr/jit/valuenum.cpp index e9dd137..f8be720 100644 --- a/src/coreclr/jit/valuenum.cpp +++ b/src/coreclr/jit/valuenum.cpp @@ -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)); @@ -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) { diff --git a/src/coreclr/jit/valuenum.h b/src/coreclr/jit/valuenum.h index 483641f..c949243 100644 --- a/src/coreclr/jit/valuenum.h +++ b/src/coreclr/jit/valuenum.h @@ -1108,6 +1108,9 @@ public: 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); diff --git a/src/tests/JIT/HardwareIntrinsics/General/ConstantFolding/ScalarConstantFoldings.cs b/src/tests/JIT/HardwareIntrinsics/General/ConstantFolding/ScalarConstantFoldings.cs new file mode 100644 index 0000000..8c0b7cb --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/General/ConstantFolding/ScalarConstantFoldings.cs @@ -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)); + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/General/ConstantFolding/ScalarConstantFoldings.csproj b/src/tests/JIT/HardwareIntrinsics/General/ConstantFolding/ScalarConstantFoldings.csproj new file mode 100644 index 0000000..66d5848 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/General/ConstantFolding/ScalarConstantFoldings.csproj @@ -0,0 +1,9 @@ + + + false + True + + + + + -- 2.7.4