From ec74be5b438c8ff37432aa79a91b640eb3e380bd Mon Sep 17 00:00:00 2001 From: Vlad Brezae Date: Fri, 25 Jun 2021 11:58:52 +0300 Subject: [PATCH] [interp] Don't cprop between vt vars of different sizes Via unsafe code, getting the lower Vector128 from a Vector256 ends up as a move of `sizeof (Vector128)` from a Vector256 var. However, the destination var is not a valid copy of the source var, having a different type --- src/mono/mono/mini/interp/transform.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index e4651250385769..0c4776ac0beebf 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -8508,17 +8508,30 @@ interp_cprop (TransformData *td) } else if (opcode == MINT_LDOBJ_VT) { InterpInst *ldloca = local_defs [sregs [0]].ins; if (ldloca != NULL && ldloca->opcode == MINT_LDLOCA_S) { + int ldsize = ins->data [0]; int local = ldloca->sregs [0]; - // Replace LDLOCA + LDOBJ_VT with MOV_VT - ins->opcode = MINT_MOV_VT; local_ref_count [sregs [0]]--; - sregs [0] = local; + if (ldsize == td->locals [local].size) { + // Replace LDLOCA + LDOBJ_VT with MOV_VT + ins->opcode = MINT_MOV_VT; + sregs [0] = local; + needs_retry = TRUE; + } else { + // This loads just a part of the local valuetype + ins = interp_insert_ins (td, ins, MINT_MOV_OFF); + interp_ins_set_dreg (ins, ins->prev->dreg); + interp_ins_set_sreg (ins, local); + ins->data [0] = 0; + ins->data [1] = MINT_TYPE_VT; + ins->data [2] = ldsize; + + interp_clear_ins (ins->prev); + } if (td->verbose_level) { g_print ("Replace ldloca/ldobj_vt pair :\n\t"); dump_interp_inst (ins); } - needs_retry = TRUE; } } else if (MINT_IS_STFLD (opcode) && ins->data [0] == 0) { InterpInst *ldloca = local_defs [sregs [0]].ins;