Skip to content

Commit

Permalink
Fix ARM and AArch64 ABI
Browse files Browse the repository at this point in the history
Also add related ccall test and test both mutable and immutable types.
  • Loading branch information
yuyichao committed Sep 27, 2016
1 parent 26d6c20 commit c57d988
Show file tree
Hide file tree
Showing 4 changed files with 279 additions and 51 deletions.
42 changes: 37 additions & 5 deletions src/ccall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -409,10 +409,26 @@ Value *llvm_type_rewrite(Value *v, Type *from_type, Type *target_type,
// one or both of from_type and target_type is a VectorType or AggregateType
// LLVM doesn't allow us to cast these values directly, so
// we need to use this alloca copy trick instead
// NOTE: it is assumed that the ABI has ensured that sizeof(from_type) == sizeof(target_type)
Value *mem = emit_static_alloca(target_type, ctx);
builder.CreateStore(v, builder.CreatePointerCast(mem, from_type->getPointerTo()));
return builder.CreateLoad(mem);
// On ARM and AArch64, the ABI requires casting through memory to different
// sizes.
Value *from;
Value *to;
const DataLayout &DL =
#if JL_LLVM_VERSION >= 30600
jl_ExecutionEngine->getDataLayout();
#else
*jl_ExecutionEngine->getDataLayout();
#endif
if (DL.getTypeAllocSize(target_type) >= DL.getTypeAllocSize(from_type)) {
to = emit_static_alloca(target_type, ctx);
from = builder.CreatePointerCast(to, from_type->getPointerTo());
}
else {
from = emit_static_alloca(from_type, ctx);
to = builder.CreatePointerCast(from, target_type->getPointerTo());
}
builder.CreateStore(v, from);
return builder.CreateLoad(to);
}

// --- argument passing and scratch space utilities ---
Expand Down Expand Up @@ -1839,8 +1855,24 @@ static jl_cgval_t emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
jl_cgval_t newst = emit_new_struct(rt, 1, NULL, ctx); // emit a new, empty struct
assert(newst.typ != NULL && "Type was not concrete");
assert(newst.isboxed);
size_t rtsz = jl_datatype_size(rt);
assert(rtsz > 0);
int boxalign = jl_gc_alignment(rtsz);
#ifndef NDEBUG
const DataLayout &DL =
#if JL_LLVM_VERSION >= 30600
jl_ExecutionEngine->getDataLayout();
#else
*jl_ExecutionEngine->getDataLayout();
#endif
// ARM and AArch64 can use a LLVM type larger than the julia
// type. However, the LLVM type size should be no larger than
// the GC allocation size. (multiple of `sizeof(void*)`)
assert(DL.getTypeStoreSize(lrt) <= LLT_ALIGN(jl_datatype_size(rt),
boxalign));
#endif
// copy the data from the return value to the new struct
tbaa_decorate(newst.tbaa, builder.CreateAlignedStore(result, emit_bitcast(newst.V, prt->getPointerTo()), 16)); // julia gc is aligned 16
tbaa_decorate(newst.tbaa, builder.CreateAlignedStore(result, emit_bitcast(newst.V, prt->getPointerTo()), boxalign));
return newst;
}
else if (jlrt != prt) {
Expand Down
29 changes: 29 additions & 0 deletions src/ccalltest.c
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,17 @@ typedef struct {
double a,b,c;
} struct16;

typedef struct {
int8_t a;
int16_t b;
} struct17;

typedef struct {
int8_t a;
int8_t b;
int8_t c;
} struct18;

typedef struct {
jint x;
jint y;
Expand Down Expand Up @@ -467,6 +478,24 @@ JL_DLLEXPORT struct16 test_16(struct16 a, float b) {
return a;
}

JL_DLLEXPORT struct17 test_17(struct17 a, int8_t b) {
//Unpack a struct with non-obvious packing requirements
if (verbose) fprintf(stderr,"%d %d & %d\n", (int)a.a, (int)a.b, (int)b);
a.a += b*1;
a.b -= b*2;
return a;
}

JL_DLLEXPORT struct18 test_18(struct18 a, int8_t b) {
//Unpack a struct with non-obvious packing requirements
if (verbose) fprintf(stderr,"%d %d %d & %d\n",
(int)a.a, (int)a.b, (int)a.c, (int)b);
a.a += b*1;
a.b -= b*2;
a.c += b*3;
return a;
}

// Note for AArch64:
// `i128` is a native type on aarch64 so the type here is wrong.
// However, it happens to have the same calling convention with `[2 x i64]`
Expand Down
21 changes: 21 additions & 0 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,27 @@ static const int jl_gc_sizeclasses[JL_GC_N_POOLS] = {
// 64, 32, 160, 64, 16, 64, 112, 128, bytes lost
};

STATIC_INLINE int jl_gc_alignment(size_t sz)
{
if (sz == 0)
return sizeof(void*);
#ifdef _P64
(void)sz;
return 16;
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
return rtsz < 4 : 8 : 16;
#else
// szclass 8
if (sz < 4)
return 8;
// szclass 12
if (sz < 8)
return 4;
// szclass 16+
return 16;
#endif
}

STATIC_INLINE int JL_CONST_FUNC jl_gc_szclass(size_t sz)
{
#ifdef _P64
Expand Down
Loading

0 comments on commit c57d988

Please sign in to comment.