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];
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
};
static guint16 bmi2_methods [] = {
- //SN_MultiplyNoFlags,
+ SN_MultiplyNoFlags,
SN_ParallelBitDeposit,
SN_ParallelBitExtract,
SN_ZeroHighBits,
}
}
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);
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;
METHOD(TrailingZeroCount)
// BMI2
METHOD(ZeroHighBits)
-//METHOD(MultiplyNoFlags)
+METHOD(MultiplyNoFlags)
METHOD(ParallelBitDeposit)
METHOD(ParallelBitExtract)