Skip to content

Commit

Permalink
Merge pull request mono/mono#17031 from EgorBo/bmi-mulx
Browse files Browse the repository at this point in the history
[LLVM] Implement Bmi2.MultiplyNoFlags

Commit migrated from mono/mono@5e30301
  • Loading branch information
imhameed authored Sep 26, 2019
2 parents f38c278 + 4fc25a9 commit 2088be3
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 30 deletions.
18 changes: 18 additions & 0 deletions src/mono/mono/mini/mini-llvm.c
Original file line number Diff line number Diff line change
Expand Up @@ -7507,6 +7507,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];
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/mini/mini-ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
70 changes: 41 additions & 29 deletions src/mono/mono/mini/simd-intrinsics-netcore.c
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ static guint16 bmi1_methods [] = {
};

static guint16 bmi2_methods [] = {
//SN_MultiplyNoFlags,
SN_MultiplyNoFlags,
SN_ParallelBitDeposit,
SN_ParallelBitExtract,
SN_ZeroHighBits,
Expand Down Expand Up @@ -598,8 +598,9 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
if (!supported)
return NULL;
MONO_INST_NEW (cfg, ins, is_64bit ? OP_POPCNT64 : OP_POPCNT32);
ins->dreg = alloc_ireg (cfg);
ins->dreg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
ins->sreg1 = args [0]->dreg;
ins->type = is_64bit ? STACK_I8 : STACK_I4;
MONO_ADD_INS (cfg->cbb, ins);
return ins;
default:
Expand All @@ -623,8 +624,9 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
if (!supported)
return NULL;
MONO_INST_NEW (cfg, ins, is_64bit ? OP_LZCNT64 : OP_LZCNT32);
ins->dreg = alloc_ireg (cfg);
ins->dreg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
ins->sreg1 = args [0]->dreg;
ins->type = is_64bit ? STACK_I8 : STACK_I4;
MONO_ADD_INS (cfg->cbb, ins);
return ins;
default:
Expand All @@ -648,16 +650,16 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
case SN_AndNot: {
// (a ^ -1) & b
// LLVM replaces it with `andn`
int tmp_reg = alloc_preg (cfg);
int result_reg = alloc_preg (cfg);
int tmp_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
int result_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
EMIT_NEW_BIALU_IMM (cfg, ins, is_64bit ? OP_LXOR_IMM : OP_IXOR_IMM, tmp_reg, args [0]->dreg, -1);
EMIT_NEW_BIALU (cfg, ins, is_64bit ? OP_LAND : OP_IAND, result_reg, tmp_reg, args [1]->dreg);
return ins;
}
case SN_BitFieldExtract: {
if (fsig->param_count == 2) {
MONO_INST_NEW (cfg, ins, is_64bit ? OP_BEXTR64 : OP_BEXTR32);
ins->dreg = alloc_ireg (cfg);
ins->dreg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
ins->sreg1 = args [0]->dreg;
ins->sreg2 = args [1]->dreg;
ins->type = is_64bit ? STACK_I8 : STACK_I4;
Expand All @@ -668,47 +670,44 @@ emit_x86_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature
case SN_GetMaskUpToLowestSetBit: {
// x ^ (x - 1)
// LLVM replaces it with `blsmsk`
int tmp_reg = alloc_preg (cfg);
int result_reg = alloc_preg (cfg);
int tmp_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
int result_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (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);
int tmp_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
int result_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (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);
int tmp_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
int result_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
int zero_reg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (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);
ins->dreg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
ins->sreg1 = args [0]->dreg;
ins->type = STACK_I4;
ins->type = is_64bit ? STACK_I8 : STACK_I4;
MONO_ADD_INS (cfg->cbb, ins);
return ins;
default:
g_assert_not_reached ();
}
}
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);
Expand All @@ -721,32 +720,45 @@ 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 = is_64bit ? alloc_lreg (cfg) : 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 = is_64bit ? alloc_lreg (cfg) : 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->dreg = is_64bit ? alloc_lreg (cfg) : 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);
ins->dreg = is_64bit ? alloc_lreg (cfg) : 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_ParallelBitDeposit:
MONO_INST_NEW (cfg, ins, is_64bit ? OP_PDEP64 : OP_PDEP32);
ins->dreg = alloc_ireg (cfg);
ins->dreg = is_64bit ? alloc_lreg (cfg) : alloc_ireg (cfg);
ins->sreg1 = args [0]->dreg;
ins->sreg2 = args [1]->dreg;
ins->type = is_64bit ? STACK_I8 : STACK_I4;
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/simd-methods-netcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@ METHOD(ResetLowestSetBit)
METHOD(TrailingZeroCount)
// BMI2
METHOD(ZeroHighBits)
//METHOD(MultiplyNoFlags)
METHOD(MultiplyNoFlags)
METHOD(ParallelBitDeposit)
METHOD(ParallelBitExtract)

0 comments on commit 2088be3

Please sign in to comment.