From 8bf0780805b973e0bf0381c86704a625cfc7287f Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 5 Feb 2025 12:29:34 -0800 Subject: [PATCH 1/5] Have mono handle ConvertToIntegerNative for Double and Single --- src/mono/mono/mini/intrinsics.c | 57 +++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 41c5be9c82022c..1d85f39d588849 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -2322,6 +2322,63 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign return ins; } } + } else if ((cmethod->klass == mono_defaults.double_class) || (cmethod->klass == mono_defaults.single_class)) { + MonoGenericContext *method_context = mono_method_get_context (cmethod); + if (!strcmp (cmethod->name, "ConvertToIntegerNative") && + method_context != NULL && + method_context->method_inst->type_argc == 1) { + int opcode = 0; + MonoTypeEnum tto_type = method_context->method_inst->type_argv [0]->type; + MonoStackType tto_stack = STACK_I4; + switch (tto_type) { + case MONO_TYPE_I1: + opcode = OP_FCONV_TO_I1; + break; + case MONO_TYPE_I2: + opcode = OP_FCONV_TO_I2; + break; +#if TARGET_SIZEOF_VOID_P == 4 + case MONO_TYPE_I: +#endif + case MONO_TYPE_I4: + opcode = OP_FCONV_TO_I4; + break; +#if TARGET_SIZEOF_VOID_P == 8 + case MONO_TYPE_I: +#endif + case MONO_TYPE_I8: + opcode = OP_FCONV_TO_I8; + tto_stack = STACK_I8; + break; + case MONO_TYPE_U1: + opcode = OP_FCONV_TO_U1; + break; + case MONO_TYPE_U2: + opcode = OP_FCONV_TO_U2; + break; +#if TARGET_SIZEOF_VOID_P == 4 + case MONO_TYPE_U: +#endif + case MONO_TYPE_U4: + opcode = OP_FCONV_TO_U4; + break; +#if TARGET_SIZEOF_VOID_P == 8 + case MONO_TYPE_U: +#endif + case MONO_TYPE_U8: + opcode = OP_FCONV_TO_U8; + tto_stack = STACK_I8; + break; + default: return NULL; + } + + if (opcode != 0) { + int ireg = mono_alloc_ireg (cfg); + EMIT_NEW_UNALU (cfg, ins, opcode, ireg, args [0]->dreg); + ins->type = tto_stack; + return ins; + } + } } ins = mono_emit_simd_intrinsics (cfg, cmethod, fsig, args); From e90351fbe389922f0ea90ed292de0f61dc9f88a6 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 6 Feb 2025 09:38:07 -0800 Subject: [PATCH 2/5] Ensure indirect calls on Mono produce the expected result for ConvertToInteger native --- src/libraries/System.Private.CoreLib/src/System/Double.cs | 3 --- src/libraries/System.Private.CoreLib/src/System/Single.cs | 3 --- 2 files changed, 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index a5adb8057f6a5e..fe89ca49146caf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -665,15 +665,12 @@ public static TInteger ConvertToInteger(double value) public static TInteger ConvertToIntegerNative(double value) where TInteger : IBinaryInteger { -#if !MONO if (typeof(TInteger).IsPrimitive) { // We need this to be recursive so indirect calls (delegates // for example) produce the same result as direct invocation return ConvertToIntegerNative(value); } -#endif - return TInteger.CreateSaturating(value); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index ef991d4aea3ea0..ce37952076f6b8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -660,15 +660,12 @@ public static TInteger ConvertToInteger(float value) public static TInteger ConvertToIntegerNative(float value) where TInteger : IBinaryInteger { -#if !MONO if (typeof(TInteger).IsPrimitive) { // We need this to be recursive so indirect calls (delegates // for example) produce the same result as direct invocation return ConvertToIntegerNative(value); } -#endif - return TInteger.CreateSaturating(value); } From c0d450e8f12a311e8697c9a55973f2b5a7fac0f5 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 6 Feb 2025 11:54:01 -0800 Subject: [PATCH 3/5] Ensure the mono interpreter also handles ConvertToIntegerNative for double and single --- src/mono/mono/mini/interp/transform.c | 49 ++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 53ca6d2a10804a..04bf096566f838 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2676,7 +2676,54 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas !strncmp ("Vector", klass_name, 6) && !strcmp (tm, "get_IsHardwareAccelerated"))) { *op = MINT_LDC_I4_0; - } + } else if ((target_method->klass == mono_defaults.double_class) || (target_method->klass == mono_defaults.single_class)) { + MonoGenericContext *method_context = mono_method_get_context (target_method); + bool isDouble = target_method->klass == mono_defaults.double_class; + if (!strcmp (tm, "ConvertToIntegerNative") && + method_context != NULL && + method_context->method_inst->type_argc == 1) { + MonoTypeEnum tto_type = method_context->method_inst->type_argv [0]->type; + switch (tto_type) { + case MONO_TYPE_I1: + *op = isDouble ? MINT_CONV_I1_R8 : MINT_CONV_I1_R4; + break; + case MONO_TYPE_I2: + *op = isDouble ? MINT_CONV_I2_R8 : MINT_CONV_I2_R4; + break; +#if TARGET_SIZEOF_VOID_P == 4 + case MONO_TYPE_I: +#endif + case MONO_TYPE_I4: + *op = isDouble ? MINT_CONV_I4_R8 : MINT_CONV_I4_R4; + break; +#if TARGET_SIZEOF_VOID_P == 8 + case MONO_TYPE_I: +#endif + case MONO_TYPE_I8: + *op = isDouble ? MINT_CONV_I8_R8 : MINT_CONV_I8_R4; + break; + case MONO_TYPE_U1: + *op = isDouble ? MINT_CONV_U1_R8 : MINT_CONV_U1_R4; + break; + case MONO_TYPE_U2: + *op = isDouble ? MINT_CONV_U2_R8 : MINT_CONV_U2_R4; + break; +#if TARGET_SIZEOF_VOID_P == 4 + case MONO_TYPE_U: +#endif + case MONO_TYPE_U4: + *op = isDouble ? MINT_CONV_U4_R8 : MINT_CONV_U4_R4; + break; +#if TARGET_SIZEOF_VOID_P == 8 + case MONO_TYPE_U: +#endif + case MONO_TYPE_U8: + *op = isDouble ? MINT_CONV_U8_R8 : MINT_CONV_U8_R4; + break; + default: return FALSE; + } + } + } return FALSE; } From 4a263b9db8388c054c9794085d1614493fd971f9 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 7 Feb 2025 05:34:14 -0800 Subject: [PATCH 4/5] Ensure mono uses OP_RCONV_TO_* for Single.ConvertIntegerToNative --- src/mono/mono/mini/intrinsics.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 1d85f39d588849..2cdb452b2f9c61 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -2324,6 +2324,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign } } else if ((cmethod->klass == mono_defaults.double_class) || (cmethod->klass == mono_defaults.single_class)) { MonoGenericContext *method_context = mono_method_get_context (cmethod); + bool isDouble = cmethod->klass == mono_defaults.double_class; if (!strcmp (cmethod->name, "ConvertToIntegerNative") && method_context != NULL && method_context->method_inst->type_argc == 1) { @@ -2332,41 +2333,41 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign MonoStackType tto_stack = STACK_I4; switch (tto_type) { case MONO_TYPE_I1: - opcode = OP_FCONV_TO_I1; + opcode = isDouble ? OP_FCONV_TO_I1 : OP_RCONV_TO_I1; break; case MONO_TYPE_I2: - opcode = OP_FCONV_TO_I2; + opcode = isDouble ? OP_FCONV_TO_I2 : OP_RCONV_TO_I2; break; #if TARGET_SIZEOF_VOID_P == 4 case MONO_TYPE_I: #endif case MONO_TYPE_I4: - opcode = OP_FCONV_TO_I4; + opcode = isDouble ? OP_FCONV_TO_I4 : OP_RCONV_TO_I4; break; #if TARGET_SIZEOF_VOID_P == 8 case MONO_TYPE_I: #endif case MONO_TYPE_I8: - opcode = OP_FCONV_TO_I8; + opcode = isDouble ? OP_FCONV_TO_I8 : OP_RCONV_TO_I8; tto_stack = STACK_I8; break; case MONO_TYPE_U1: - opcode = OP_FCONV_TO_U1; + opcode = isDouble ? OP_FCONV_TO_U1 : OP_RCONV_TO_U1; break; case MONO_TYPE_U2: - opcode = OP_FCONV_TO_U2; + opcode = isDouble ? OP_FCONV_TO_U2 : OP_RCONV_TO_U2; break; #if TARGET_SIZEOF_VOID_P == 4 case MONO_TYPE_U: #endif case MONO_TYPE_U4: - opcode = OP_FCONV_TO_U4; + opcode = isDouble ? OP_FCONV_TO_U4 : OP_RCONV_TO_U4; break; #if TARGET_SIZEOF_VOID_P == 8 case MONO_TYPE_U: #endif case MONO_TYPE_U8: - opcode = OP_FCONV_TO_U8; + opcode = isDouble ? OP_FCONV_TO_U8 : OP_RCONV_TO_U8; tto_stack = STACK_I8; break; default: return NULL; From 6f6a197d771491ea58a83eb42c9738825ef090fc Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 7 Feb 2025 10:04:10 -0800 Subject: [PATCH 5/5] Ensure we decompose the opcode to support ones that are emulated --- src/mono/mono/mini/intrinsics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 2cdb452b2f9c61..1b2c85c64bf744 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -2377,7 +2377,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign int ireg = mono_alloc_ireg (cfg); EMIT_NEW_UNALU (cfg, ins, opcode, ireg, args [0]->dreg); ins->type = tto_stack; - return ins; + return mono_decompose_opcode(cfg, ins); } } }