[netcore] Implement more System.Runtime.Intrinsics.X86.Bmi1/Bmi2 (mono/mono#16891)
authorEgor Bogatov <egorbo@gmail.com>
Wed, 18 Sep 2019 19:08:35 +0000 (22:08 +0300)
committerZoltan Varga <vargaz@gmail.com>
Wed, 18 Sep 2019 19:08:35 +0000 (15:08 -0400)
* Implement more BMI1/BMI2

* implement more bmi1 intrinsics

* Update simd-intrinsics-netcore.c

Commit migrated from https://github.com/mono/mono/commit/9a4a62450129deb77b749739d7c01adfdaa5b9dd

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 938efc7..5a9900c 100644 (file)
@@ -330,6 +330,8 @@ typedef enum {
        INTRINS_PEXT_I64,
        INTRINS_PDEP_I32,
        INTRINS_PDEP_I64,
+       INTRINS_BZHI_I32,
+       INTRINS_BZHI_I64,
 #if defined(TARGET_AMD64) || defined(TARGET_X86)
        INTRINS_SSE_PMOVMSKB,
        INTRINS_SSE_PSRLI_W,
@@ -7461,6 +7463,14 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, ins->opcode == OP_CTTZ32 ? INTRINS_CTTZ_I32 : INTRINS_CTTZ_I64), args, 2, "");
                        break;
                }
+               case OP_BZHI32:
+               case OP_BZHI64: {
+                       LLVMValueRef args [2];
+                       args [0] = lhs;
+                       args [1] = rhs;
+                       values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, ins->opcode == OP_BZHI32 ? INTRINS_BZHI_I32 : INTRINS_BZHI_I64), args, 2, "");
+                       break;
+               }
                case OP_PEXT32:
                case OP_PEXT64: {
                        LLVMValueRef args [2];
@@ -8728,6 +8738,8 @@ static IntrinsicDesc intrinsics[] = {
        {INTRINS_CTLZ_I64, "llvm.ctlz.i64"},
        {INTRINS_CTTZ_I32, "llvm.cttz.i32"},
        {INTRINS_CTTZ_I64, "llvm.cttz.i64"},
+       {INTRINS_BZHI_I32, "llvm.x86.bmi.bzhi.32"},
+       {INTRINS_BZHI_I64, "llvm.x86.bmi.bzhi.64"},
        {INTRINS_PEXT_I32, "llvm.x86.bmi.pext.32"},
        {INTRINS_PEXT_I64, "llvm.x86.bmi.pext.64"},
        {INTRINS_PDEP_I32, "llvm.x86.bmi.pdep.32"},
@@ -8937,15 +8949,13 @@ add_intrinsic (LLVMModuleRef module, int id)
        case INTRINS_CTTZ_I64:
                AddFunc2 (module, name, LLVMInt64Type (), LLVMInt64Type (), LLVMInt1Type ());
                break;
+       case INTRINS_BZHI_I32:
        case INTRINS_PEXT_I32:
-               AddFunc2 (module, name, LLVMInt32Type (), LLVMInt32Type (), LLVMInt32Type ());
-               break;
-       case INTRINS_PEXT_I64:
-               AddFunc2 (module, name, LLVMInt64Type (), LLVMInt64Type (), LLVMInt64Type ());
-               break;
        case INTRINS_PDEP_I32:
                AddFunc2 (module, name, LLVMInt32Type (), LLVMInt32Type (), LLVMInt32Type ());
                break;
+       case INTRINS_BZHI_I64:
+       case INTRINS_PEXT_I64:
        case INTRINS_PDEP_I64:
                AddFunc2 (module, name, LLVMInt64Type (), LLVMInt64Type (), LLVMInt64Type ());
                break;
index 8269879..8b1ef68 100644 (file)
@@ -1401,13 +1401,16 @@ MINI_OP(OP_LZCNT64, "lzcnt64", LREG, LREG, NONE)
 MINI_OP(OP_POPCNT32, "popcnt32", IREG, IREG, NONE)
 MINI_OP(OP_POPCNT64, "popcnt64", LREG, LREG, NONE)
 
+/* Intel BMI1 */
 /* Count trailing zeroes, return 32/64 if the input is 0 */
 MINI_OP(OP_CTTZ32, "cttz32", IREG, IREG, NONE)
 MINI_OP(OP_CTTZ64, "cttz64", LREG, LREG, NONE)
-/* Intel BMI2 PEXT */
+
+/* Intel BMI2 */
+MINI_OP(OP_BZHI32, "bzhi32", IREG, IREG, IREG)
+MINI_OP(OP_BZHI64, "bzhi64", LREG, LREG, LREG)
 MINI_OP(OP_PEXT32, "pext32", IREG, IREG, IREG)
 MINI_OP(OP_PEXT64, "pext64", LREG, LREG, LREG)
-/* Intel BMI2 PDEP */
 MINI_OP(OP_PDEP32, "pdep32", IREG, IREG, IREG)
 MINI_OP(OP_PDEP64, "pdep64", LREG, LREG, LREG)
 
index 9bd6299..9aa1813 100644 (file)
@@ -552,6 +552,9 @@ static guint16 lzcnt_methods [] = {
 };
 
 static guint16 bmi1_methods [] = {
+       SN_ExtractLowestSetBit,
+       SN_GetMaskUpToLowestSetBit,
+       SN_ResetLowestSetBit,
        SN_TrailingZeroCount,
        SN_get_IsSupported,
 };
@@ -559,6 +562,7 @@ static guint16 bmi1_methods [] = {
 static guint16 bmi2_methods [] = {
        SN_ParallelBitDeposit,
        SN_ParallelBitExtract,
+       SN_ZeroHighBits,
        SN_get_IsSupported,
 };
 
@@ -631,6 +635,7 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
                if (!COMPILE_LLVM (cfg))
                        return NULL;
                id = lookup_intrins (bmi1_methods, sizeof (bmi1_methods), cmethod);
+
                g_assert (id != -1);
                supported = (get_cpu_features () & MONO_CPU_X86_BMI1) != 0;
                is_64bit = !strcmp (class_name, "X64");
@@ -640,6 +645,35 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
                        EMIT_NEW_ICONST (cfg, ins, supported ? 1 : 0);
                        ins->type = STACK_I4;
                        return ins;
+               case SN_GetMaskUpToLowestSetBit: {
+                       // x ^ (x - 1)
+                       // LLVM replaces it with `blsmsk`
+                       int tmp_reg = alloc_preg (cfg);
+                       int result_reg = alloc_preg (cfg);
+                       EMIT_NEW_BIALU_IMM (cfg, ins, is_64bit ? OP_LSUB_IMM : OP_ISUB_IMM, tmp_reg, args [0]->dreg, 1);
+                       EMIT_NEW_BIALU (cfg, ins, is_64bit ? OP_LXOR : OP_IXOR, result_reg, args [0]->dreg, tmp_reg);
+                       return ins;
+               }
+               case SN_ResetLowestSetBit: {
+                       // x & (x - 1)
+                       // LLVM replaces it with `blsr`
+                       int tmp_reg = alloc_preg (cfg);
+                       int result_reg = alloc_preg (cfg);
+                       EMIT_NEW_BIALU_IMM (cfg, ins, is_64bit ? OP_LSUB_IMM : OP_ISUB_IMM, tmp_reg, args [0]->dreg, 1);
+                       EMIT_NEW_BIALU (cfg, ins, is_64bit ? OP_LAND : OP_IAND, result_reg, args [0]->dreg, tmp_reg);
+                       return ins;
+               }
+               case SN_ExtractLowestSetBit: {
+                       // x & (0 - x)
+                       // LLVM replaces it with `blsi`
+                       int tmp_reg = alloc_preg (cfg);
+                       int result_reg = alloc_preg (cfg);
+                       int zero_reg = alloc_preg (cfg);
+                       MONO_EMIT_NEW_ICONST (cfg, zero_reg, 0);
+                       EMIT_NEW_BIALU (cfg, ins, is_64bit ? OP_LSUB : OP_ISUB, tmp_reg, zero_reg, args [0]->dreg);
+                       EMIT_NEW_BIALU (cfg, ins, is_64bit ? OP_LAND : OP_IAND, result_reg, args [0]->dreg, tmp_reg);
+                       return ins;
+               }
                case SN_TrailingZeroCount:
                        MONO_INST_NEW (cfg, ins, is_64bit ? OP_CTTZ64 : OP_CTTZ32);
                        ins->dreg = alloc_ireg (cfg);
@@ -667,6 +701,14 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
                        EMIT_NEW_ICONST (cfg, ins, supported ? 1 : 0);
                        ins->type = STACK_I4;
                        return ins;
+               case SN_ZeroHighBits:
+                       MONO_INST_NEW (cfg, ins, is_64bit ? OP_BZHI64 : OP_BZHI32);
+                       ins->dreg = alloc_ireg (cfg);
+                       ins->sreg1 = args [0]->dreg;
+                       ins->sreg2 = args [1]->dreg;
+                       ins->type = is_64bit ? STACK_I8 : STACK_I4;
+                       MONO_ADD_INS (cfg->cbb, ins);
+                       return ins;
                case SN_ParallelBitExtract:
                        MONO_INST_NEW (cfg, ins, is_64bit ? OP_PEXT64 : OP_PEXT32);
                        ins->dreg = alloc_ireg (cfg);
index e0942ea..bde5da8 100644 (file)
@@ -29,12 +29,12 @@ METHOD(op_Subtraction)
 // BMI1
 //METHOD(AndNot)
 //METHOD(BitFieldExtract)
-//METHOD(SIMDExtractLowestSetBit)
-//METHOD(GetMaskUpToLowestSetBit)
-//METHOD(ResetLowestSetBit)
+METHOD(ExtractLowestSetBit)
+METHOD(GetMaskUpToLowestSetBit)
+METHOD(ResetLowestSetBit)
 METHOD(TrailingZeroCount)
 // BMI2
-//METHOD(ZeroHighBits)
+METHOD(ZeroHighBits)
 //METHOD(MultiplyNoFlags)
 METHOD(ParallelBitDeposit)
 METHOD(ParallelBitExtract)