Skip to content

Commit 3adfeeb

Browse files
committed
Fix ARM and AArch64 ABI
Also add related ccall test and test both mutable and immutable types.
1 parent 26d6c20 commit 3adfeeb

File tree

4 files changed

+277
-51
lines changed

4 files changed

+277
-51
lines changed

src/ccall.cpp

+35-5
Original file line numberDiff line numberDiff line change
@@ -409,10 +409,25 @@ Value *llvm_type_rewrite(Value *v, Type *from_type, Type *target_type,
409409
// one or both of from_type and target_type is a VectorType or AggregateType
410410
// LLVM doesn't allow us to cast these values directly, so
411411
// we need to use this alloca copy trick instead
412-
// NOTE: it is assumed that the ABI has ensured that sizeof(from_type) == sizeof(target_type)
413-
Value *mem = emit_static_alloca(target_type, ctx);
414-
builder.CreateStore(v, builder.CreatePointerCast(mem, from_type->getPointerTo()));
415-
return builder.CreateLoad(mem);
412+
// On ARM and AArch64, the ABI requires casting through memory to different
413+
// sizes.
414+
Value *from;
415+
Value *to;
416+
#if JL_LLVM_VERSION >= 30600
417+
const DataLayout &DL = jl_ExecutionEngine->getDataLayout();
418+
#else
419+
const DataLayout &DL = *jl_ExecutionEngine->getDataLayout();
420+
#endif
421+
if (DL.getTypeAllocSize(target_type) >= DL.getTypeAllocSize(from_type)) {
422+
to = emit_static_alloca(target_type, ctx);
423+
from = builder.CreatePointerCast(to, from_type->getPointerTo());
424+
}
425+
else {
426+
from = emit_static_alloca(from_type, ctx);
427+
to = builder.CreatePointerCast(from, target_type->getPointerTo());
428+
}
429+
builder.CreateStore(v, from);
430+
return builder.CreateLoad(to);
416431
}
417432

418433
// --- argument passing and scratch space utilities ---
@@ -1839,8 +1854,23 @@ static jl_cgval_t emit_ccall(jl_value_t **args, size_t nargs, jl_codectx_t *ctx)
18391854
jl_cgval_t newst = emit_new_struct(rt, 1, NULL, ctx); // emit a new, empty struct
18401855
assert(newst.typ != NULL && "Type was not concrete");
18411856
assert(newst.isboxed);
1857+
size_t rtsz = jl_datatype_size(rt);
1858+
assert(rtsz > 0);
1859+
int boxalign = jl_gc_alignment(rtsz);
1860+
#ifndef NDEBUG
1861+
#if JL_LLVM_VERSION >= 30600
1862+
const DataLayout &DL = jl_ExecutionEngine->getDataLayout();
1863+
#else
1864+
const DataLayout &DL = *jl_ExecutionEngine->getDataLayout();
1865+
#endif
1866+
// ARM and AArch64 can use a LLVM type larger than the julia
1867+
// type. However, the LLVM type size should be no larger than
1868+
// the GC allocation size. (multiple of `sizeof(void*)`)
1869+
assert(DL.getTypeStoreSize(lrt) <= LLT_ALIGN(jl_datatype_size(rt),
1870+
boxalign));
1871+
#endif
18421872
// copy the data from the return value to the new struct
1843-
tbaa_decorate(newst.tbaa, builder.CreateAlignedStore(result, emit_bitcast(newst.V, prt->getPointerTo()), 16)); // julia gc is aligned 16
1873+
tbaa_decorate(newst.tbaa, builder.CreateAlignedStore(result, emit_bitcast(newst.V, prt->getPointerTo()), boxalign));
18441874
return newst;
18451875
}
18461876
else if (jlrt != prt) {

src/ccalltest.c

+29
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,17 @@ typedef struct {
191191
double a,b,c;
192192
} struct16;
193193

194+
typedef struct {
195+
int8_t a;
196+
int16_t b;
197+
} struct17;
198+
199+
typedef struct {
200+
int8_t a;
201+
int8_t b;
202+
int8_t c;
203+
} struct18;
204+
194205
typedef struct {
195206
jint x;
196207
jint y;
@@ -467,6 +478,24 @@ JL_DLLEXPORT struct16 test_16(struct16 a, float b) {
467478
return a;
468479
}
469480

481+
JL_DLLEXPORT struct17 test_17(struct17 a, int8_t b) {
482+
//Unpack a struct with non-obvious packing requirements
483+
if (verbose) fprintf(stderr,"%d %d & %d\n", (int)a.a, (int)a.b, (int)b);
484+
a.a += b*1;
485+
a.b -= b*2;
486+
return a;
487+
}
488+
489+
JL_DLLEXPORT struct18 test_18(struct18 a, int8_t b) {
490+
//Unpack a struct with non-obvious packing requirements
491+
if (verbose) fprintf(stderr,"%d %d %d & %d\n",
492+
(int)a.a, (int)a.b, (int)a.c, (int)b);
493+
a.a += b*1;
494+
a.b -= b*2;
495+
a.c += b*3;
496+
return a;
497+
}
498+
470499
// Note for AArch64:
471500
// `i128` is a native type on aarch64 so the type here is wrong.
472501
// However, it happens to have the same calling convention with `[2 x i64]`

src/julia_internal.h

+21
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,27 @@ static const int jl_gc_sizeclasses[JL_GC_N_POOLS] = {
9292
// 64, 32, 160, 64, 16, 64, 112, 128, bytes lost
9393
};
9494

95+
STATIC_INLINE int jl_gc_alignment(size_t sz)
96+
{
97+
if (sz == 0)
98+
return sizeof(void*);
99+
#ifdef _P64
100+
(void)sz;
101+
return 16;
102+
#elif defined(_CPU_ARM_) || defined(_CPU_PPC_)
103+
return sz <= 4 ? 8 : 16;
104+
#else
105+
// szclass 8
106+
if (sz <= 4)
107+
return 8;
108+
// szclass 12
109+
if (sz <= 8)
110+
return 4;
111+
// szclass 16+
112+
return 16;
113+
#endif
114+
}
115+
95116
STATIC_INLINE int JL_CONST_FUNC jl_gc_szclass(size_t sz)
96117
{
97118
#ifdef _P64

0 commit comments

Comments
 (0)