diff options
author | Zoltan Varga <vargaz@gmail.com> | 2017-02-22 23:06:08 +0300 |
---|---|---|
committer | Zoltan Varga <vargaz@gmail.com> | 2017-02-22 23:08:41 +0300 |
commit | cb947b7a56c09febb89b02b89599c003874b23f3 (patch) | |
tree | 6a7094f236a149c0165aec66984194e23a5cf72a | |
parent | 25a554dc6bd0b4e68a8ff5ca2b4980efd593d790 (diff) |
[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.
-rw-r--r-- | mono/mini/mini-arm.c | 12 | ||||
-rw-r--r-- | mono/mini/mini-arm.h | 2 | ||||
-rw-r--r-- | mono/mini/mini-llvm.c | 10 | ||||
-rw-r--r-- | 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; |