diff --git a/src/coreclr/src/jit/importer.cpp b/src/coreclr/src/jit/importer.cpp index df513491bdf1d..76d2672b1ea3a 100644 --- a/src/coreclr/src/jit/importer.cpp +++ b/src/coreclr/src/jit/importer.cpp @@ -4127,6 +4127,19 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, break; } + case NI_System_Runtime_CompilerServices_Unsafe_Unlikely: + { + if (compCurBB->bbJumpKind == BBJ_COND) + { + // I guess actually we need to change weight for a specific edge + // rather than for the whole block (it can be non-cold for other conditions) + // however, bbPreds are not calcaluted at this moment... + compCurBB->bbNext->bbFlags |= BBF_RUN_RARELY; + compCurBB->bbNext->setBBWeight(BB_ZERO_WEIGHT); + } + break; + } + #ifdef FEATURE_HW_INTRINSICS case NI_System_Math_FusedMultiplyAdd: case NI_System_MathF_FusedMultiplyAdd: @@ -4430,6 +4443,14 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) } } } + else if ((strcmp(namespaceName, "Internal.Runtime.CompilerServices") == 0) || + (strcmp(namespaceName, "System.Runtime.CompilerServices") == 0)) + { + if ((strcmp(className, "Unsafe") == 0) && (strcmp(methodName, "Unlikely") == 0)) + { + result = NI_System_Runtime_CompilerServices_Unsafe_Unlikely; + } + } #if defined(TARGET_XARCH) // We currently only support BSWAP on x86 else if (strcmp(namespaceName, "System.Buffers.Binary") == 0) { diff --git a/src/coreclr/src/jit/namedintrinsiclist.h b/src/coreclr/src/jit/namedintrinsiclist.h index f81f5e0dfdb9e..d92ebb8d9f606 100644 --- a/src/coreclr/src/jit/namedintrinsiclist.h +++ b/src/coreclr/src/jit/namedintrinsiclist.h @@ -21,6 +21,7 @@ enum NamedIntrinsic : unsigned short NI_System_GC_KeepAlive, NI_System_Type_get_IsValueType, NI_System_Type_IsAssignableFrom, + NI_System_Runtime_CompilerServices_Unsafe_Unlikely, #ifdef FEATURE_HW_INTRINSICS NI_IsSupported_True, diff --git a/src/libraries/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/Unsafe.cs index 62649b4c22463..569fbf06e9fd4 100644 --- a/src/libraries/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/Internal/Runtime/CompilerServices/Unsafe.cs @@ -443,5 +443,13 @@ public static void SkipInit(out T value) // ret } + + [Intrinsic] + [NonVersionable] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool Unlikely(bool condition) + { + return condition; + } } } diff --git a/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il b/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il index 52f2002a128ef..430c6334dee3f 100644 --- a/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il +++ b/src/libraries/System.Runtime.CompilerServices.Unsafe/src/System.Runtime.CompilerServices.Unsafe.il @@ -162,6 +162,14 @@ ret } // end of method Unsafe::SkipInit + //.method public hidebysig static bool Unlikely (bool condition) cil managed aggressiveinlining + //{ + // .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) + // .maxstack 1 + // ldarg.0 + // ret + //} // end of method Unsafe::Unlikely + .method public hidebysig static int32 SizeOf() cil managed aggressiveinlining { .custom instance void System.Runtime.Versioning.NonVersionableAttribute::.ctor() = ( 01 00 00 00 ) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 84cdd436ad25e..24d2b443c6c61 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -582,11 +582,19 @@ emit_unsafe_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignatu MONO_INST_NEW (cfg, ins, OP_NOP); MONO_ADD_INS (cfg->cbb, ins); return ins; - } - else if (!strcmp (cmethod->name, "SkipInit")) { + } else if (!strcmp (cmethod->name, "SkipInit")) { MONO_INST_NEW (cfg, ins, OP_NOP); MONO_ADD_INS (cfg->cbb, ins); return ins; + } else if (COMPILE_LLVM (cfg) && !strcmp (cmethod->name, "Unlikely")) { + g_assert (fsig->param_count == 1); + // LLVM should expand it as @llvm.expect.i32 + MONO_INST_NEW (cfg, ins, OP_UNLIKELY32); + ins->type = STACK_I4; + ins->dreg = mono_alloc_ireg (cfg); + ins->sreg1 = args [0]->dreg; + MONO_ADD_INS (cfg->cbb, ins); + return ins; } #endif diff --git a/src/mono/mono/mini/mini-llvm.c b/src/mono/mono/mini/mini-llvm.c index 7a0bef62cf104..e2877cb659d7b 100644 --- a/src/mono/mono/mini/mini-llvm.c +++ b/src/mono/mono/mini/mini-llvm.c @@ -321,6 +321,7 @@ typedef enum { INTRINS_TRUNCF, INTRINS_COPYSIGN, INTRINS_COPYSIGNF, + INTRINS_EXPECT_I32, INTRINS_EXPECT_I8, INTRINS_EXPECT_I1, INTRINS_CTPOP_I32, @@ -8057,6 +8058,12 @@ process_bb (EmitContext *ctx, MonoBasicBlock *bb) #endif /* ENABLE_NETCORE */ #endif /* SIMD */ + case OP_UNLIKELY32: { + LLVMValueRef args [] = { lhs, LLVMConstInt (LLVMInt32Type (), 0, FALSE) }; + values [ins->dreg] = LLVMBuildCall (builder, get_intrins (ctx, INTRINS_EXPECT_I32), args, 2, ""); + break; + } + case OP_DUMMY_USE: break; @@ -9365,6 +9372,7 @@ static IntrinsicDesc intrinsics[] = { {INTRINS_TRUNCF, "llvm.trunc.f32"}, {INTRINS_COPYSIGN, "llvm.copysign.f64"}, {INTRINS_COPYSIGNF, "llvm.copysign.f32"}, + {INTRINS_EXPECT_I32, "llvm.expect.i32"}, {INTRINS_EXPECT_I8, "llvm.expect.i8"}, {INTRINS_EXPECT_I1, "llvm.expect.i1"}, {INTRINS_CTPOP_I32, "llvm.ctpop.i32"}, @@ -9590,6 +9598,9 @@ add_intrinsic (LLVMModuleRef module, int id) case INTRINS_POW: AddFunc2 (module, name, LLVMDoubleType (), LLVMDoubleType (), LLVMDoubleType ()); break; + case INTRINS_EXPECT_I32: + AddFunc2 (module, name, LLVMInt32Type (), LLVMInt32Type (), LLVMInt32Type ()); + break; case INTRINS_EXPECT_I8: AddFunc2 (module, name, LLVMInt8Type (), LLVMInt8Type (), LLVMInt8Type ()); break; diff --git a/src/mono/mono/mini/mini-ops.h b/src/mono/mono/mini/mini-ops.h index 84b98ac2ca4bb..b9264c4a39c60 100644 --- a/src/mono/mono/mini/mini-ops.h +++ b/src/mono/mono/mini/mini-ops.h @@ -1456,4 +1456,4 @@ MINI_OP(OP_LZCNT64, "lzcnt64", LREG, LREG, NONE) MINI_OP(OP_POPCNT32, "popcnt32", IREG, IREG, NONE) MINI_OP(OP_POPCNT64, "popcnt64", LREG, LREG, NONE) - +MINI_OP(OP_UNLIKELY32, "unlikely", IREG, IREG, NONE) \ No newline at end of file