From 6ed39d93288086706521e84216bc76f5a94abc16 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Fri, 15 Dec 2023 21:33:28 -0500 Subject: [PATCH] [mono] Fix passing of valuetypes with a non-8 byte aligned size on arm64+ios/macos. Part of the fix for https://github.com/dotnet/runtime/issues/96051. --- src/mono/mono/mini/mini-arm64.c | 45 ++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index bdd3d51a844cc..435726f0ff078 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1677,7 +1677,8 @@ add_valuetype (CallInfo *cinfo, ArgInfo *ainfo, MonoType *t, gboolean is_return) } else { ainfo->nfregs_to_skip = FP_PARAM_REGS > cinfo->fr ? FP_PARAM_REGS - cinfo->fr : 0; cinfo->fr = FP_PARAM_REGS; - size = ALIGN_TO (size, 8); + if (!(ios_abi && cinfo->pinvoke)) + size = ALIGN_TO (size, 8); ainfo->storage = ArgVtypeOnStack; cinfo->stack_usage = ALIGN_TO (cinfo->stack_usage, align); ainfo->offset = cinfo->stack_usage; @@ -3240,16 +3241,48 @@ mono_arch_emit_outarg_vt (MonoCompile *cfg, MonoInst *ins, MonoInst *src) } break; } - case ArgVtypeOnStack: - for (i = 0; i < ainfo->size / 8; ++i) { - MONO_INST_NEW (cfg, load, OP_LOADI8_MEMBASE); + case ArgVtypeOnStack: { + int load_opcode = OP_LOADI8_MEMBASE; + int store_opcode = OP_STOREI8_MEMBASE_REG; + int size = 8; + for (i = 0; i < ainfo->size; ++i) { + int left = ainfo->size - i; + if (left < 8) { + switch (left) { + case 7: + case 6: + case 5: + case 4: + load_opcode = OP_LOADI4_MEMBASE; + store_opcode = OP_STOREI4_MEMBASE_REG; + size = 4; + break; + case 3: + case 2: + load_opcode = OP_LOADI2_MEMBASE; + store_opcode = OP_STOREI2_MEMBASE_REG; + size = 2; + break; + case 1: + load_opcode = OP_LOADI1_MEMBASE; + store_opcode = OP_STOREI1_MEMBASE_REG; + size = 1; + break; + default: + g_assert_not_reached (); + break; + } + } + MONO_INST_NEW (cfg, load, load_opcode); load->dreg = mono_alloc_ireg (cfg); load->inst_basereg = src->dreg; - load->inst_offset = i * 8; + load->inst_offset = i; MONO_ADD_INS (cfg->cbb, load); - MONO_EMIT_NEW_STORE_MEMBASE (cfg, OP_STOREI8_MEMBASE_REG, ARMREG_SP, ainfo->offset + (i * 8), load->dreg); + MONO_EMIT_NEW_STORE_MEMBASE (cfg, store_opcode, ARMREG_SP, ainfo->offset + i, load->dreg); + i += size; } break; + } case ArgInSIMDReg: MONO_INST_NEW (cfg, load, OP_LOADX_MEMBASE); load->dreg = mono_alloc_ireg (cfg);