Add support for the System.Runtime.Intrinsics.X86.Popcnt intrinsics.
authorZoltan Varga <vargaz@gmail.com>
Sat, 17 Aug 2019 13:16:36 +0000 (09:16 -0400)
committerZoltan Varga <vargaz@gmail.com>
Sat, 17 Aug 2019 16:25:59 +0000 (12:25 -0400)
Commit migrated from https://github.com/mono/mono/commit/7418248835be6e3a7397694d1e74248dd5ecdd49

src/mono/mono/mini/mini-llvm.c
src/mono/mono/mini/mini-ops.h
src/mono/mono/mini/simd-intrinsics-netcore.c
src/mono/mono/mini/simd-methods-netcore.h

index 0dfd927..6e54170 100644 (file)
@@ -299,6 +299,8 @@ typedef enum {
        INTRINS_POWF,
        INTRINS_EXPECT_I8,
        INTRINS_EXPECT_I1,
+       INTRINS_CTPOP_I32,
+       INTRINS_CTPOP_I64,
 #if defined(TARGET_AMD64) || defined(TARGET_X86)
        INTRINS_SSE_PMOVMSKB,
        INTRINS_SSE_PSRLI_W,
@@ -7136,7 +7138,6 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        // Maybe convert to 0/1 ?
                        break;
                }
-
                case OP_XBINOP: {
                        switch (ins->inst_c0) {
                        case OP_IADD:
@@ -7171,6 +7172,12 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        }
                        break;
                }
+               case OP_POPCNT32:
+                       values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_CTPOP_I32), &lhs, 1, "");
+                       break;
+               case OP_POPCNT64:
+                       values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_CTPOP_I64), &lhs, 1, "");
+                       break;
 #endif /* SIMD */
 
                case OP_DUMMY_USE:
@@ -8312,6 +8319,16 @@ AddFunc (LLVMModuleRef module, const char *name, LLVMTypeRef ret_type, LLVMTypeR
 }
 
 static inline void
+AddFunc1 (LLVMModuleRef module, const char *name, LLVMTypeRef ret_type, LLVMTypeRef param_type1)
+{
+       LLVMTypeRef param_types [4];
+
+       param_types [0] = param_type1;
+
+       AddFunc (module, name, ret_type, param_types, 1);
+}
+
+static inline void
 AddFunc2 (LLVMModuleRef module, const char *name, LLVMTypeRef ret_type, LLVMTypeRef param_type1, LLVMTypeRef param_type2)
 {
        LLVMTypeRef param_types [4];
@@ -8354,6 +8371,8 @@ static IntrinsicDesc intrinsics[] = {
        {INTRINS_POWF, "llvm.pow.f32"},
        {INTRINS_EXPECT_I8, "llvm.expect.i8"},
        {INTRINS_EXPECT_I1, "llvm.expect.i1"},
+       {INTRINS_CTPOP_I32, "llvm.ctpop.i32"},
+       {INTRINS_CTPOP_I64, "llvm.ctpop.i64"},
 #if defined(TARGET_AMD64) || defined(TARGET_X86)
        {INTRINS_SSE_PMOVMSKB, "llvm.x86.sse2.pmovmskb.128"},
        {INTRINS_SSE_PSRLI_W, "llvm.x86.sse2.psrli.w"},
@@ -8511,6 +8530,12 @@ add_intrinsic (LLVMModuleRef module, int id)
        case INTRINS_EXPECT_I1:
                AddFunc2 (module, name, LLVMInt1Type (), LLVMInt1Type (), LLVMInt1Type ());
                break;
+       case INTRINS_CTPOP_I32:
+               AddFunc1 (module, name, LLVMInt32Type (), LLVMInt32Type ());
+               break;
+       case INTRINS_CTPOP_I64:
+               AddFunc1 (module, name, LLVMInt64Type (), LLVMInt64Type ());
+               break;
 #if defined(TARGET_AMD64) || defined(TARGET_X86)
        case INTRINS_SSE_PMOVMSKB:
                /* pmovmskb */
index 5992595..deec494 100644 (file)
@@ -1362,3 +1362,9 @@ MINI_OP(OP_XCOMPARE, "xcompare", XREG, XREG, XREG)
 MINI_OP(OP_XCOMPARE_FP, "xcompare_fp", XREG, XREG, XREG)
 /* Binary op, inst_c0 contains the operation */
 MINI_OP(OP_XBINOP, "xbinop", XREG, XREG, XREG)
+
+MINI_OP(OP_LZCNT32, "lzcnt32", IREG, IREG, NONE)
+MINI_OP(OP_LZCNT64, "lzcnt64", LREG, LREG, NONE)
+MINI_OP(OP_POPCNT32, "popcnt32", IREG, IREG, NONE)
+MINI_OP(OP_POPCNT64, "popcnt64", LREG, LREG, NONE)
+
index 269eb02..565500a 100644 (file)
@@ -13,6 +13,7 @@
 
 #include "mini.h"
 #include "ir-emit.h"
+#include "llvm-jit.h"
 #include "mono/utils/bsearch.h"
 #include <mono/metadata/abi-details.h>
 #include <mono/metadata/reflection-internals.h>
@@ -393,6 +394,54 @@ emit_sys_numerics_vector_t (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSig
        return NULL;
 }
 
+#ifdef TARGET_AMD64
+
+static guint16 popcnt_methods [] = {
+       SN_PopCount,
+       SN_get_IsSupported
+};
+
+static MonoInst*
+emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
+{
+       const char *class_name;
+       const char *class_ns;
+       MonoInst *ins;
+       int id;
+       gboolean supported, is_64bit;
+       MonoClass *klass = cmethod->klass;
+
+       class_ns = m_class_get_name_space (klass);
+       class_name = m_class_get_name (klass);
+       if (!strcmp (class_name, "Popcnt") || (!strcmp (class_name, "X64") && cmethod->klass->nested_in && !strcmp (m_class_get_name (cmethod->klass->nested_in), "Popcnt"))) {
+               id = lookup_intrins (popcnt_methods, sizeof (popcnt_methods), cmethod);
+               if (id == -1)
+                       return NULL;
+
+               supported = (mono_llvm_get_cpu_features () & MONO_CPU_X86_POPCNT) != 0;
+               is_64bit = !strcmp (class_name, "X64");
+
+               switch (id) {
+               case SN_get_IsSupported:
+                       EMIT_NEW_ICONST (cfg, ins, supported ? 1 : 0);
+                       ins->type = STACK_I4;
+                       return ins;
+               case SN_PopCount:
+                       if (!supported)
+                               return NULL;
+                       MONO_INST_NEW (cfg, ins, is_64bit ? OP_POPCNT64 : OP_POPCNT32);
+                       ins->dreg = alloc_ireg (cfg);
+                       ins->sreg1 = args [0]->dreg;
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       return ins;
+               default:
+                       return NULL;
+               }
+       }
+       return NULL;
+}
+#endif
+
 MonoInst*
 mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -407,6 +456,7 @@ mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
        // FIXME:
        if (cfg->compile_aot)
                return NULL;
+
        class_ns = m_class_get_name_space (cmethod->klass);
        class_name = m_class_get_name (cmethod->klass);
        if (!strcmp (class_ns, "System.Numerics") && !strcmp (class_name, "Vector"))
@@ -418,6 +468,12 @@ mono_emit_simd_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                }
                return ins;
        }
+#ifdef TARGET_AMD64
+       if (cmethod->klass->nested_in)
+               class_ns = m_class_get_name_space (cmethod->klass->nested_in), class_name, cmethod->klass->nested_in;
+       if (!strcmp (class_ns, "System.Runtime.Intrinsics.X86"))
+               return emit_x86_intrinsics (cfg ,cmethod, fsig, args);
+#endif
 
        return NULL;
 }
index f1a98a9..a6a675c 100644 (file)
@@ -4,8 +4,10 @@ SIMD_METHOD("GreaterThan", SN_GreaterThan)
 SIMD_METHOD("LessThan", SN_LessThan)
 SIMD_METHOD("Min", SN_Min)
 SIMD_METHOD("Max", SN_Max)
+SIMD_METHOD("PopCount", SN_PopCount)
 SIMD_METHOD("get_Count", SN_get_Count)
 SIMD_METHOD("get_IsHardwareAccelerated", SN_get_IsHardwareAccelerated)
+SIMD_METHOD("get_IsSupported", SN_get_IsSupported)
 SIMD_METHOD("get_AllOnes", SN_get_AllOnes)
 SIMD_METHOD("get_Item", SN_get_Item)
 SIMD_METHOD("get_One", SN_get_One)