Add support of CreateScalarUnsafe() for arm64 intrinsic in JIT (#34579)
authorKunal Pathak <Kunal.Pathak@microsoft.com>
Mon, 27 Apr 2020 23:11:48 +0000 (16:11 -0700)
committerGitHub <noreply@github.com>
Mon, 27 Apr 2020 23:11:48 +0000 (16:11 -0700)
* Intrinsify Vector64.CreateScalarUnsafe() for byte, sbyte, short, ushort, int, uint, long, ulong, float
* Intrinsify Vector128.CreateScalarUnsafe() for byte, sbyte, short, ushort, int, uint, long, ulong, float, long, ulong, double

src/coreclr/src/jit/hwintrinsiccodegenarm64.cpp
src/coreclr/src/jit/hwintrinsiclistarm64.h
src/coreclr/src/jit/lowerarmarch.cpp
src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs

index 70fe9c5..9338cc0 100644 (file)
@@ -449,6 +449,41 @@ void CodeGen::genHWIntrinsic(GenTreeHWIntrinsic* node)
                 }
                 break;
 
+            case NI_Vector64_CreateScalarUnsafe:
+            case NI_Vector128_CreateScalarUnsafe:
+            {
+                if (intrin.op1->isContainedFltOrDblImmed())
+                {
+                    // fmov reg, #imm8
+                    const double dataValue = intrin.op1->AsDblCon()->gtDconVal;
+                    GetEmitter()->emitIns_R_F(ins, emitTypeSize(intrin.baseType), targetReg, dataValue, INS_OPTS_NONE);
+                }
+                else if (varTypeIsFloating(intrin.baseType))
+                {
+                    if (targetReg != op1Reg)
+                    {
+                        // fmov reg1, reg2
+                        GetEmitter()->emitIns_R_R(ins, emitTypeSize(intrin.baseType), targetReg, op1Reg, INS_OPTS_NONE);
+                    }
+                }
+                else
+                {
+                    if (intrin.op1->isContainedIntOrIImmed())
+                    {
+                        // movi/movni reg, #imm8
+                        const ssize_t dataValue = intrin.op1->AsIntCon()->gtIconVal;
+                        GetEmitter()->emitIns_R_I(INS_movi, emitSize, targetReg, dataValue, opt);
+                    }
+                    else
+                    {
+                        // ins reg1[0], reg2
+                        GetEmitter()->emitIns_R_R_I(ins, emitTypeSize(intrin.baseType), targetReg, op1Reg, 0,
+                                                    INS_OPTS_NONE);
+                    }
+                }
+            }
+            break;
+
             default:
                 unreached();
         }
index f210bc0..6a07a01 100644 (file)
@@ -23,6 +23,7 @@ HARDWARE_INTRINSIC(Vector64,        AsSByte,
 HARDWARE_INTRINSIC(Vector64,        AsSingle,                                   8,           1,     {INS_invalid,           INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid},           HW_Category_Helper,                 HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg)
 HARDWARE_INTRINSIC(Vector64,        AsUInt16,                                   8,           1,     {INS_invalid,           INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid},           HW_Category_Helper,                 HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg)
 HARDWARE_INTRINSIC(Vector64,        AsUInt32,                                   8,           1,     {INS_invalid,           INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid},           HW_Category_Helper,                 HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg)
+HARDWARE_INTRINSIC(Vector64,        CreateScalarUnsafe,                         8,           1,     {INS_ins,               INS_ins,            INS_ins,            INS_ins,            INS_ins,            INS_ins,            INS_invalid,        INS_invalid,        INS_fmov,           INS_invalid},           HW_Category_SimpleSIMD,             HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen)
 HARDWARE_INTRINSIC(Vector64,        get_Count,                                  8,           0,     {INS_invalid,           INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid},           HW_Category_Helper,                 HW_Flag_SpecialImport|HW_Flag_NoCodeGen)
 
 // ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
@@ -41,6 +42,7 @@ HARDWARE_INTRINSIC(Vector128,       AsSingle,                                  1
 HARDWARE_INTRINSIC(Vector128,       AsUInt16,                                  16,           1,     {INS_invalid,           INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid},           HW_Category_Helper,                 HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg)
 HARDWARE_INTRINSIC(Vector128,       AsUInt32,                                  16,           1,     {INS_invalid,           INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid},           HW_Category_Helper,                 HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg)
 HARDWARE_INTRINSIC(Vector128,       AsUInt64,                                  16,           1,     {INS_invalid,           INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid},           HW_Category_Helper,                 HW_Flag_SpecialImport|HW_Flag_NoCodeGen|HW_Flag_BaseTypeFromFirstArg)
+HARDWARE_INTRINSIC(Vector128,       CreateScalarUnsafe,                        16,           1,     {INS_ins,               INS_ins,            INS_ins,            INS_ins,            INS_ins,            INS_ins,            INS_ins,            INS_ins,            INS_fmov,           INS_fmov},              HW_Category_SimpleSIMD,             HW_Flag_SupportsContainment|HW_Flag_SpecialCodeGen)
 HARDWARE_INTRINSIC(Vector128,       get_Count,                                 16,           0,     {INS_invalid,           INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid,        INS_invalid},           HW_Category_Helper,                 HW_Flag_SpecialImport|HW_Flag_NoCodeGen)
 
 // ***************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
index 6eee592..4ae61be 100644 (file)
@@ -914,7 +914,29 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node)
                 }
             }
             break;
+        case NI_Vector64_CreateScalarUnsafe:
+        case NI_Vector128_CreateScalarUnsafe:
+            if (intrin.op1->IsCnsIntOrI())
+            {
+                const ssize_t dataValue = intrin.op1->AsIntCon()->gtIconVal;
+
+                if (comp->GetEmitter()->emitIns_valid_imm_for_movi(dataValue, emitActualTypeSize(intrin.baseType)))
+                {
+                    MakeSrcContained(node, intrin.op1);
+                }
+            }
+            else if (intrin.op1->IsCnsFltOrDbl())
+            {
+                assert(varTypeIsFloating(intrin.baseType));
 
+                const double dataValue = intrin.op1->AsDblCon()->gtDconVal;
+
+                if (comp->GetEmitter()->emitIns_valid_imm_for_fmov(dataValue))
+                {
+                    MakeSrcContained(node, intrin.op1);
+                }
+            }
+            break;
         default:
             unreached();
     }
index b1f1645..a4f3fae 100644 (file)
@@ -522,6 +522,7 @@ namespace System.Runtime.Intrinsics
         /// <summary>Creates a new <see cref="Vector64{Byte}" /> instance with the first element initialized to the specified value and the remaining elements left uninitialized.</summary>
         /// <param name="value">The value that element 0 will be initialized to.</param>
         /// <returns>A new <see cref="Vector64{Byte}" /> instance with the first element initialized to <paramref name="value"/> and the remaining elements left uninitialized.</returns>
+        [Intrinsic]
         public static unsafe Vector64<byte> CreateScalarUnsafe(byte value)
         {
             // This relies on us stripping the "init" flag from the ".locals"
@@ -535,6 +536,7 @@ namespace System.Runtime.Intrinsics
         /// <summary>Creates a new <see cref="Vector64{Int16}" /> instance with the first element initialized to the specified value and the remaining elements left uninitialized.</summary>
         /// <param name="value">The value that element 0 will be initialized to.</param>
         /// <returns>A new <see cref="Vector64{Int16}" /> instance with the first element initialized to <paramref name="value"/> and the remaining elements left uninitialized.</returns>
+        [Intrinsic]
         public static unsafe Vector64<short> CreateScalarUnsafe(short value)
         {
             // This relies on us stripping the "init" flag from the ".locals"
@@ -548,6 +550,7 @@ namespace System.Runtime.Intrinsics
         /// <summary>Creates a new <see cref="Vector64{Int32}" /> instance with the first element initialized to the specified value and the remaining elements left uninitialized.</summary>
         /// <param name="value">The value that element 0 will be initialized to.</param>
         /// <returns>A new <see cref="Vector64{Int32}" /> instance with the first element initialized to <paramref name="value"/> and the remaining elements left uninitialized.</returns>
+        [Intrinsic]
         public static unsafe Vector64<int> CreateScalarUnsafe(int value)
         {
             // This relies on us stripping the "init" flag from the ".locals"
@@ -562,6 +565,7 @@ namespace System.Runtime.Intrinsics
         /// <param name="value">The value that element 0 will be initialized to.</param>
         /// <returns>A new <see cref="Vector64{SByte}" /> instance with the first element initialized to <paramref name="value"/> and the remaining elements left uninitialized.</returns>
         [CLSCompliant(false)]
+        [Intrinsic]
         public static unsafe Vector64<sbyte> CreateScalarUnsafe(sbyte value)
         {
             // This relies on us stripping the "init" flag from the ".locals"
@@ -575,6 +579,7 @@ namespace System.Runtime.Intrinsics
         /// <summary>Creates a new <see cref="Vector64{Single}" /> instance with the first element initialized to the specified value and the remaining elements left uninitialized.</summary>
         /// <param name="value">The value that element 0 will be initialized to.</param>
         /// <returns>A new <see cref="Vector64{Single}" /> instance with the first element initialized to <paramref name="value"/> and the remaining elements left uninitialized.</returns>
+        [Intrinsic]
         public static unsafe Vector64<float> CreateScalarUnsafe(float value)
         {
             // This relies on us stripping the "init" flag from the ".locals"
@@ -589,6 +594,7 @@ namespace System.Runtime.Intrinsics
         /// <param name="value">The value that element 0 will be initialized to.</param>
         /// <returns>A new <see cref="Vector64{UInt16}" /> instance with the first element initialized to <paramref name="value"/> and the remaining elements left uninitialized.</returns>
         [CLSCompliant(false)]
+        [Intrinsic]
         public static unsafe Vector64<ushort> CreateScalarUnsafe(ushort value)
         {
             // This relies on us stripping the "init" flag from the ".locals"
@@ -603,6 +609,7 @@ namespace System.Runtime.Intrinsics
         /// <param name="value">The value that element 0 will be initialized to.</param>
         /// <returns>A new <see cref="Vector64{UInt32}" /> instance with the first element initialized to <paramref name="value"/> and the remaining elements left uninitialized.</returns>
         [CLSCompliant(false)]
+        [Intrinsic]
         public static unsafe Vector64<uint> CreateScalarUnsafe(uint value)
         {
             // This relies on us stripping the "init" flag from the ".locals"