diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 6a445f280dd9..13c22d79d689 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -9118,6 +9118,22 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, ins->opcode == OP_LSCNT32 ? INTRINS_CTLZ_I32 : INTRINS_CTLZ_I64), args, 2, ""); break; } + case OP_ARM64_SMULH: + case OP_ARM64_UMULH: { + LLVMValueRef op1, op2; + if (ins->opcode == OP_ARM64_SMULH) { + op1 = LLVMBuildSExt (builder, lhs, LLVMInt128Type (), ""); + op2 = LLVMBuildSExt (builder, rhs, LLVMInt128Type (), ""); + } else { + op1 = LLVMBuildZExt (builder, lhs, LLVMInt128Type (), ""); + op2 = LLVMBuildZExt (builder, rhs, LLVMInt128Type (), ""); + } + LLVMValueRef mul = LLVMBuildMul (builder, op1, op2, ""); + LLVMValueRef hi64 = LLVMBuildLShr (builder, mul, + LLVMConstInt (LLVMInt128Type (), 64, FALSE), ""); + values [ins->dreg] = LLVMBuildTrunc (builder, hi64, LLVMInt64Type (), ""); + break; + } #endif case OP_DUMMY_USE: diff --git a/mono/mini/mini-ops.h b/mono/mini/mini-ops.h index e27135d2b6ed..93036193ce11 100644 --- a/mono/mini/mini-ops.h +++ b/mono/mini/mini-ops.h @@ -1579,4 +1579,6 @@ MINI_OP(OP_POPCNT64, "popcnt64", LREG, LREG, NONE) #ifdef TARGET_ARM64 MINI_OP(OP_LSCNT32, "lscnt32", IREG, IREG, NONE) MINI_OP(OP_LSCNT64, "lscnt64", LREG, LREG, NONE) +MINI_OP(OP_ARM64_SMULH, "arm64_smulh", LREG, LREG, LREG) +MINI_OP(OP_ARM64_UMULH, "arm64_umulh", LREG, LREG, LREG) #endif // TARGET_ARM64 diff --git a/mono/mini/simd-intrinsics-netcore.c b/mono/mini/simd-intrinsics-netcore.c index 68f1a5d29682..ddff53783f33 100644 --- a/mono/mini/simd-intrinsics-netcore.c +++ b/mono/mini/simd-intrinsics-netcore.c @@ -807,6 +807,7 @@ emit_invalid_operation (MonoCompile *cfg, const char* message) static SimdIntrinsic armbase_methods [] = { {SN_LeadingSignCount}, {SN_LeadingZeroCount}, + {SN_MultiplyHigh}, {SN_ReverseElementBits}, {SN_get_IsSupported} }; @@ -870,6 +871,9 @@ emit_arm64_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatur return emit_simd_ins_for_sig (cfg, klass, arg0_i32 ? OP_LZCNT32 : OP_LZCNT64, 0, arg0_type, fsig, args); case SN_LeadingSignCount: return emit_simd_ins_for_sig (cfg, klass, arg0_i32 ? OP_LSCNT32 : OP_LSCNT64, 0, arg0_type, fsig, args); + case SN_MultiplyHigh: + return emit_simd_ins_for_sig (cfg, klass, + (arg0_type == MONO_TYPE_I8 ? OP_ARM64_SMULH : OP_ARM64_UMULH), 0, arg0_type, fsig, args); case SN_ReverseElementBits: return emit_simd_ins_for_sig (cfg, klass, (is_64bit ? OP_XOP_I8_I8 : OP_XOP_I4_I4),