From cb947b7a56c09febb89b02b89599c003874b23f3 Mon Sep 17 00:00:00 2001 From: Zoltan Varga Date: Wed, 22 Feb 2017 15:06:08 -0500 Subject: [PATCH] [arm] Fix the passing of structs with 8 byte alignment with llvm on armeabi, they need to be passed as an int64 array to let llvm know that it might need to insert a dummy argument so they are passed in a even register pair. Fixes #52548. --- mono/mini/mini-arm.c | 12 +++++++++++- mono/mini/mini-arm.h | 2 +- mono/mini/mini-llvm.c | 10 ++++++++-- mono/mini/mini.h | 2 +- 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/mono/mini/mini-arm.c b/mono/mini/mini-arm.c index 42715480b00..f85644d42ca 100644 --- a/mono/mini/mini-arm.c +++ b/mono/mini/mini-arm.c @@ -1515,6 +1515,7 @@ get_call_info (MonoMemPool *mp, MonoMethodSignature *sig) nwords = (align_size + sizeof (gpointer) -1 ) / sizeof (gpointer); ainfo->storage = RegTypeStructByVal; ainfo->struct_size = size; + ainfo->align = align; /* FIXME: align stack_size if needed */ if (eabi_supported) { if (align >= 8 && (gr & 1)) @@ -2166,7 +2167,16 @@ mono_arch_get_llvm_call_info (MonoCompile *cfg, MonoMethodSignature *sig) break; case RegTypeStructByVal: lainfo->storage = LLVMArgAsIArgs; - lainfo->nslots = ainfo->struct_size / sizeof (gpointer); + if (eabi_supported && ainfo->align == 8) { + /* LLVM models this by passing an int64 array */ + lainfo->nslots = ALIGN_TO (ainfo->struct_size, 8) / 8; + lainfo->esize = 8; + } else { + lainfo->nslots = ainfo->struct_size / sizeof (gpointer); + lainfo->esize = 4; + } + + printf ("D: %d\n", ainfo->align); break; case RegTypeStructByAddr: case RegTypeStructByAddrOnStack: diff --git a/mono/mini/mini-arm.h b/mono/mini/mini-arm.h index 28678638b6c..31194f2e60d 100644 --- a/mono/mini/mini-arm.h +++ b/mono/mini/mini-arm.h @@ -208,7 +208,7 @@ typedef struct { guint8 reg; ArgStorage storage; /* RegTypeStructByVal */ - gint32 struct_size; + gint32 struct_size, align; guint8 size : 4; /* 1, 2, 4, 8, or regs used by RegTypeStructByVal */ } ArgInfo; diff --git a/mono/mini/mini-llvm.c b/mono/mini/mini-llvm.c index 563607f8c0f..745c29f13e4 100644 --- a/mono/mini/mini-llvm.c +++ b/mono/mini/mini-llvm.c @@ -1431,7 +1431,10 @@ sig_to_llvm_sig_full (EmitContext *ctx, MonoMethodSignature *sig, LLVMCallInfo * pindex ++; break; case LLVMArgAsIArgs: - param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots); + if (ainfo->esize == 8) + param_types [pindex] = LLVMArrayType (LLVMInt64Type (), ainfo->nslots); + else + param_types [pindex] = LLVMArrayType (IntPtrType (), ainfo->nslots); pindex ++; break; case LLVMArgVtypeByRef: @@ -3490,7 +3493,10 @@ process_call (EmitContext *ctx, MonoBasicBlock *bb, LLVMBuilderRef *builder_ref, } case LLVMArgAsIArgs: g_assert (addresses [reg]); - args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), ""); + if (ainfo->esize == 8) + args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (LLVMInt64Type (), ainfo->nslots), 0)), ""); + else + args [pindex] = LLVMBuildLoad (ctx->builder, convert (ctx, addresses [reg], LLVMPointerType (LLVMArrayType (IntPtrType (), ainfo->nslots), 0)), ""); break; case LLVMArgVtypeAsScalar: g_assert_not_reached (); diff --git a/mono/mini/mini.h b/mono/mini/mini.h index 25316da3245..d8e9f9ca547 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -826,7 +826,7 @@ typedef struct { * in the structure. */ int nslots; - /* Only if storage == LLVMArgAsFpArgs/LLVMArgFpStruct (4/8) */ + /* Only if storage == LLVMArgAsIArgs/LLVMArgAsFpArgs/LLVMArgFpStruct (4/8) */ int esize; /* Parameter index in the LLVM signature */ int pindex; -- 2.25.1