Implement Bmi2.MultiplyNoFlags
authorEgorBo <egorbo@gmail.com>
Wed, 25 Sep 2019 01:04:38 +0000 (04:04 +0300)
committerEgorBo <egorbo@gmail.com>
Wed, 25 Sep 2019 01:04:38 +0000 (04:04 +0300)
Commit migrated from https://github.com/mono/mono/commit/ba471607a32e0117d83fd3ffd1f50f51d18ac5e6

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 2661c85..2a94084 100644 (file)
@@ -7503,6 +7503,24 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb)
                        values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, ins->opcode == OP_BZHI32 ? INTRINS_BZHI_I32 : INTRINS_BZHI_I64), args, 2, "");
                        break;
                }
+               case OP_MULX_H32:
+               case OP_MULX_H64:
+               case OP_MULX_HL32:
+               case OP_MULX_HL64: {
+                       gboolean is_64 = ins->opcode == OP_MULX_H64 || ins->opcode == OP_MULX_HL64;
+                       gboolean only_high = ins->opcode == OP_MULX_H32 || ins->opcode == OP_MULX_H64;
+                       LLVMValueRef lx = LLVMBuildZExt (ctx->builder, lhs, LLVMInt128Type (), "");
+                       LLVMValueRef rx = LLVMBuildZExt (ctx->builder, rhs, LLVMInt128Type (), "");
+                       LLVMValueRef mulx = LLVMBuildMul (ctx->builder, lx, rx, "");
+                       if (!only_high) {
+                               LLVMValueRef lowx = LLVMBuildTrunc (ctx->builder, mulx, is_64 ? LLVMInt64Type () : LLVMInt32Type (), "");
+                               LLVMBuildStore (ctx->builder, lowx, values [ins->sreg3]);
+                       }
+                       LLVMValueRef shift = LLVMConstInt (LLVMInt128Type (), is_64 ? 64 : 32, FALSE);
+                       LLVMValueRef highx = LLVMBuildLShr (ctx->builder, mulx, shift, "");
+                       values [ins->dreg] = LLVMBuildTrunc (ctx->builder, highx, is_64 ? LLVMInt64Type () : LLVMInt32Type (), "");
+                       break;
+               }
                case OP_PEXT32:
                case OP_PEXT64: {
                        LLVMValueRef args [2];
index 377bc0c..9208b48 100644 (file)
@@ -1024,6 +1024,10 @@ MINI_OP(OP_PEXT32, "pext32", IREG, IREG, IREG)
 MINI_OP(OP_PEXT64, "pext64", LREG, LREG, LREG)
 MINI_OP(OP_PDEP32, "pdep32", IREG, IREG, IREG)
 MINI_OP(OP_PDEP64, "pdep64", LREG, LREG, LREG)
+MINI_OP(OP_MULX_H32, "mulxh32", IREG, IREG, IREG)
+MINI_OP(OP_MULX_H64, "mulxh64", LREG, LREG, LREG)
+MINI_OP3(OP_MULX_HL32, "mulxhl32", IREG, IREG, IREG, IREG)
+MINI_OP3(OP_MULX_HL64, "mulxhl64", LREG, LREG, LREG, LREG)
 
 #endif
 
index dd9620b..8877758 100644 (file)
@@ -562,7 +562,7 @@ static guint16 bmi1_methods [] = {
 };
 
 static guint16 bmi2_methods [] = {
-       //SN_MultiplyNoFlags,
+       SN_MultiplyNoFlags,
        SN_ParallelBitDeposit,
        SN_ParallelBitExtract,
        SN_ZeroHighBits,
@@ -706,9 +706,6 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
                }
        }
        if (!strcmp (class_name, "Bmi2") || (!strcmp (class_name, "X64") && cmethod->klass->nested_in && !strcmp (m_class_get_name (cmethod->klass->nested_in), "Bmi2"))) {
-               // We only support the subset used by corelib. Remove this check once MultiplyNoFlags is implemented.
-               if (m_class_get_image (cfg->method->klass) != mono_get_corlib ())
-                       return NULL;
                if (!COMPILE_LLVM (cfg))
                        return NULL;
                id = lookup_intrins (bmi2_methods, sizeof (bmi2_methods), cmethod);
@@ -721,14 +718,27 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
                        EMIT_NEW_ICONST (cfg, ins, supported ? 1 : 0);
                        ins->type = STACK_I4;
                        return ins;
-               //case SN_MultiplyNoFlags:
-                       //// TODO: implement using _mulx_u32/u64:
-                       //// ulong MultiplyNoFlags(ulong left, ulong right)
-                       //// ulong MultiplyNoFlags(ulong left, ulong right, ulong* low) => MultiplyNoFlags(left, right, low);
-                       //// uint MultiplyNoFlags(uint left, uint right)
-                       //// uint MultiplyNoFlags(uint left, uint right, uint* low)
-                       //return NULL;
-               //case SN_ZeroHighBits:
+               case SN_MultiplyNoFlags:
+                       if (fsig->param_count == 2) {
+                               MONO_INST_NEW (cfg, ins, is_64bit ? OP_MULX_H64 : OP_MULX_H32);
+                               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);
+                       } else if (fsig->param_count == 3) {
+                               MONO_INST_NEW (cfg, ins, is_64bit ? OP_MULX_HL64 : OP_MULX_HL32);
+                               ins->dreg = alloc_ireg (cfg);
+                               ins->sreg1 = args [0]->dreg;
+                               ins->sreg2 = args [1]->dreg;
+                               ins->sreg3 = args [2]->dreg;
+                               ins->type = is_64bit ? STACK_I8 : STACK_I4;
+                               MONO_ADD_INS (cfg->cbb, ins);
+                       } else {
+                               g_assert_not_reached ();
+                       }
+                       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;
index 4fa2af2..41e61b0 100644 (file)
@@ -35,6 +35,6 @@ METHOD(ResetLowestSetBit)
 METHOD(TrailingZeroCount)
 // BMI2
 METHOD(ZeroHighBits)
-//METHOD(MultiplyNoFlags)
+METHOD(MultiplyNoFlags)
 METHOD(ParallelBitDeposit)
 METHOD(ParallelBitExtract)