Implement Lzcnt hw intrinsics
authorEgor Bogatov <egorbo@gmail.com>
Mon, 26 Aug 2019 18:08:53 +0000 (21:08 +0300)
committerEgor Bogatov <egorbo@gmail.com>
Mon, 26 Aug 2019 18:08:53 +0000 (21:08 +0300)
Commit migrated from https://github.com/mono/mono/commit/044d1519bdf40f37ec06128dd383c21157dc3c0e

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

index 8ea0050..4672962 100644 (file)
@@ -465,6 +465,8 @@ mono_llvm_get_cpu_features (void)
                if (llvm::sys::getHostCPUFeatures(HostFeatures)) {
                        if (HostFeatures ["popcnt"])
                                f |= MONO_CPU_X86_POPCNT;
+                       if (HostFeatures ["lzcnt"])
+                               f |= MONO_CPU_X86_LZCNT;
                        if (HostFeatures ["avx"])
                                f |= MONO_CPU_X86_AVX;
                        if (HostFeatures ["bmi"])
index cdbb13a..b672119 100644 (file)
@@ -303,6 +303,8 @@ typedef enum {
        INTRINS_EXPECT_I1,
        INTRINS_CTPOP_I32,
        INTRINS_CTPOP_I64,
+       INTRINS_CTLZ_I32,
+       INTRINS_CTLZ_I64,
        INTRINS_CTTZ_I32,
        INTRINS_CTTZ_I64,
        INTRINS_PEXT_I32,
@@ -7216,6 +7218,12 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                case OP_POPCNT64:
                        values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_CTPOP_I64), &lhs, 1, "");
                        break;
+               case OP_LZCNT32:
+                       values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_CTLZ_I32), &lhs, 1, "");
+                       break;
+               case OP_LZCNT64:
+                       values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_CTLZ_I64), &lhs, 1, "");
+                       break;
                case OP_CTTZ32:
                case OP_CTTZ64: {
                        LLVMValueRef args [2];
@@ -8462,6 +8470,8 @@ static IntrinsicDesc intrinsics[] = {
        {INTRINS_EXPECT_I1, "llvm.expect.i1"},
        {INTRINS_CTPOP_I32, "llvm.ctpop.i32"},
        {INTRINS_CTPOP_I64, "llvm.ctpop.i64"},
+       {INTRINS_CTLZ_I32, "llvm.ctlz.i32"},
+       {INTRINS_CTLZ_I64, "llvm.ctlz.i64"},
        {INTRINS_CTTZ_I32, "llvm.cttz.i32"},
        {INTRINS_CTTZ_I64, "llvm.cttz.i64"},
        {INTRINS_PEXT_I32, "llvm.x86.bmi.pext.32"},
@@ -8625,9 +8635,11 @@ add_intrinsic (LLVMModuleRef module, int id)
        case INTRINS_EXPECT_I1:
                AddFunc2 (module, name, LLVMInt1Type (), LLVMInt1Type (), LLVMInt1Type ());
                break;
+       case INTRINS_CTLZ_I32:
        case INTRINS_CTPOP_I32:
                AddFunc1 (module, name, LLVMInt32Type (), LLVMInt32Type ());
                break;
+       case INTRINS_CTLZ_I64:
        case INTRINS_CTPOP_I64:
                AddFunc1 (module, name, LLVMInt64Type (), LLVMInt64Type ());
                break;
index abfe8e2..796406a 100644 (file)
@@ -437,6 +437,11 @@ static guint16 popcnt_methods [] = {
        SN_get_IsSupported
 };
 
+static guint16 lzcnt_methods [] = {
+       SN_LeadingZeroCount,
+       SN_get_IsSupported
+};
+
 static guint16 bmi1_methods [] = {
        SN_TrailingZeroCount,
        SN_get_IsSupported,
@@ -485,6 +490,31 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
                        return NULL;
                }
        }
+       if (!strcmp (class_name, "Lzcnt") || (!strcmp (class_name, "X64") && cmethod->klass->nested_in && !strcmp (m_class_get_name (cmethod->klass->nested_in), "Lzcnt"))) {
+               id = lookup_intrins (lzcnt_methods, sizeof (lzcnt_methods), cmethod);
+               if (id == -1)
+                       return NULL;
+
+               supported = (get_cpu_features () & MONO_CPU_X86_LZCNT) != 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_LeadingZeroCount:
+                       if (!supported)
+                               return NULL;
+                       MONO_INST_NEW (cfg, ins, is_64bit ? OP_LZCNT64 : OP_LZCNT32);
+                       ins->dreg = alloc_ireg (cfg);
+                       ins->sreg1 = args [0]->dreg;
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       return ins;
+               default:
+                       return NULL;
+               }
+       }
        if (!strcmp (class_name, "Bmi1") || (!strcmp (class_name, "X64") && cmethod->klass->nested_in && !strcmp (m_class_get_name (cmethod->klass->nested_in), "Bmi1"))) {
                // We only support the subset used by corelib
                if (m_class_get_image (cfg->method->klass) != mono_get_corlib ())
index a4af28d..e15e237 100644 (file)
@@ -5,6 +5,7 @@ METHOD(LessThan)
 METHOD(Min)
 METHOD(Max)
 METHOD(PopCount)
+METHOD(LeadingZeroCount)
 METHOD(get_Count)
 METHOD(get_IsHardwareAccelerated)
 METHOD(get_IsSupported)