From: Rodrigo Kumpera Date: Thu, 10 Aug 2017 22:22:07 +0000 (-0700) Subject: [mini] Emit widen ops when storing to locals of size < 4. Fixes #58379. X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=85270afe5115736daa61d11d47e06608b92dbaea [mini] Emit widen ops when storing to locals of size < 4. Fixes #58379. --- diff --git a/mono/mini/iltests.il b/mono/mini/iltests.il index 09c94309b70..eede67eb3df 100644 --- a/mono/mini/iltests.il +++ b/mono/mini/iltests.il @@ -2896,4 +2896,58 @@ END: IL_0018: ldloc.0 ret } + + .field private static int32 byte_val + .field private static int32 short_val + + .method public static int32 test_0_implicit_widen_or_local_stores () cil managed + { + .maxstack 1 + .locals init ( + unsigned int8 V_0, + int8 V_1, + int16 V_2, + unsigned int16 V_3) + + ldc.i4 256 + stsfld int32 Tests::byte_val + ldc.i4 65536 + stsfld int32 Tests::short_val + + ldsfld int32 Tests::byte_val + stloc.0 + ldloc.0 + brfalse L_0 + + ldc.i4.1 + ret +L_0: + ldsfld int32 Tests::byte_val + stloc.1 + ldloc.1 + conv.i4 + brfalse L_1 + + ldc.i4.2 + ret +L_1: + ldsfld int32 Tests::short_val + stloc.2 + ldloc.2 + brfalse L_2 + + ldc.i4.3 + ret +L_2: + ldsfld int32 Tests::short_val + stloc.3 + ldloc.3 + brfalse L_3 + + ldc.i4.4 + ret +L_3: + ldc.i4.0 + ret + } } diff --git a/mono/mini/method-to-ir.c b/mono/mini/method-to-ir.c index 07585ad2f82..96754600764 100644 --- a/mono/mini/method-to-ir.c +++ b/mono/mini/method-to-ir.c @@ -6607,10 +6607,78 @@ set_exception_type_from_invalid_il (MonoCompile *cfg, MonoMethod *method, unsign cfg->headers_to_free = g_slist_prepend_mempool (cfg->mempool, cfg->headers_to_free, header); } +static guint32 +mono_type_to_stloc_coerce (MonoType *type) +{ + if (type->byref) + return 0; + + type = mini_get_underlying_type (type); +handle_enum: + switch (type->type) { + case MONO_TYPE_I1: + return OP_ICONV_TO_I1; + case MONO_TYPE_U1: + return OP_ICONV_TO_U1; + case MONO_TYPE_I2: + return OP_ICONV_TO_I2; + case MONO_TYPE_U2: + return OP_ICONV_TO_U2; + case MONO_TYPE_I4: + case MONO_TYPE_U4: + case MONO_TYPE_I: + case MONO_TYPE_U: + case MONO_TYPE_PTR: + case MONO_TYPE_FNPTR: + case MONO_TYPE_CLASS: + case MONO_TYPE_STRING: + case MONO_TYPE_OBJECT: + case MONO_TYPE_SZARRAY: + case MONO_TYPE_ARRAY: + case MONO_TYPE_I8: + case MONO_TYPE_U8: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_TYPEDBYREF: + case MONO_TYPE_GENERICINST: + return 0; + case MONO_TYPE_VALUETYPE: + if (type->data.klass->enumtype) { + type = mono_class_enum_basetype (type->data.klass); + goto handle_enum; + } + return 0; + case MONO_TYPE_VAR: + case MONO_TYPE_MVAR: //TODO I believe we don't need to handle gsharedvt as there won't be match and, for example, u1 is not covariant to u32 + return 0; + default: + g_error ("unknown type 0x%02x in mono_type_to_stloc_coerce", type->type); + } + return -1; +} + static void emit_stloc_ir (MonoCompile *cfg, MonoInst **sp, MonoMethodHeader *header, int n) { MonoInst *ins; + guint32 coerce_op = mono_type_to_stloc_coerce (header->locals [n]); + + if (coerce_op) { + if (cfg->cbb->last_ins == sp [0] && sp [0]->opcode == coerce_op) { + if (cfg->verbose_level > 2) + printf ("Found existing coercing that is enough\n"); + } else { + MONO_INST_NEW (cfg, ins, coerce_op); + ins->dreg = alloc_ireg (cfg); + ins->sreg1 = sp [0]->dreg; + ins->type = STACK_I4; + ins->klass = mono_class_from_mono_type (header->locals [n]); + MONO_ADD_INS (cfg->cbb, ins); + *sp = mono_decompose_opcode (cfg, ins); + } + } + + guint32 opcode = mono_type_to_regmove (cfg, header->locals [n]); if ((opcode == OP_MOVE) && cfg->cbb->last_ins == sp [0] && ((sp [0]->opcode == OP_ICONST) || (sp [0]->opcode == OP_I8CONST))) {