Calling convention bug in AArch64
elliottslaughter opened this issue · comments
Elliott Slaughter commented
Even after #593 we seem to be hitting issues in the calling convention. This issue is to track status so I don't forget what's going on.
Reproducer 1
local c = terralib.includec("stdio.h")
struct S2 {
a : int;
b : double;
c : double;
}
terra f10(a : S2)
c.printf("terra: %d %f %f\n", a.a, a.b, a.c)
return a.a, a.b, a.c
end
terra c10(a : int, b : double, c : double)
return f10(S2 { a, b, c })
end
local x = f10({1,2.5,3.5})
print(x, x._0, x._1, x._2)
local y = c10(1, 2.5, 3.5)
print(y, y._0, y._1, y._2)
assert(x._0 == 1)
assert(x._1 == 2.5)
assert(x._2 == 3.5)
../build/bin/terra cconv.t
Produces:
terra: 0 0.000000 0.000000
cdata<struct _int32_double_double_>: 0x550b6b1688 0 6.9076310043589e-310 1.8046165208518e-312
terra: 1 2.500000 3.500000
cdata<struct _int32_double_double_>: 0x550b6ab668 1 2.5 3.5
cconv.t:22: assertion failed!
Observations:
- LuaJIT calls to Terra functions with struct arguments pass bogus data.
- Can be worked around via a Terra wrapper with scalar arguments (i.e., the Terra calling convention is consistent).
Reproducer 2
#include <stdio.h>
typedef struct S2 {
int a;
double b;
double c;
} S2;
typedef struct R {
int _0;
double _1;
double _2;
} R;
R f10(S2 a) {
printf("c: %d %f %f\n", a.a, a.b, a.c);
R r;
r._0 = a.a;
r._1 = a.b;
r._2 = a.c;
return r;
}
local c = terralib.includecstring [[
#include <stdio.h>
typedef struct S2 {
int a;
double b;
double c;
} S2;
typedef struct R {
int _0;
double _1;
double _2;
} R;
R f10(S2 a);
]]
terralib.linklibrary("libcconv_c.so")
terra c10(x : int, y : double, z : double)
return c.f10(c.S2 { x, y, z })
end
local x = c10(1, 2.5, 3.5)
print(x, x._0, x._1, x._2)
assert(x._0 == 1)
assert(x._1 == 2.5)
assert(x._2 == 3.5)
cc cconv_c.c -o libcconv_c.so -Wall -shared
LD_LIBRARY_PATH=$PWD ../build/bin/terra cconv_c.t
Produces:
Segmentation fault (core dumped)
Observations:
- Moving
f10
into C results in a crash. Note: the shared library is used to disable inlining.
Reproducer 3
local c = terralib.includecstring [[
#include <stdio.h>
typedef struct S2 {
int a;
double b;
double c;
} S2;
typedef struct R {
int _0;
double _1;
double _2;
} R;
R f10(S2 a) {
printf("c: %d %f %f\n", a.a, a.b, a.c);
R r;
r._0 = a.a;
r._1 = a.b;
r._2 = a.c;
return r;
}
]]
terra c10(x : int, y : double, z : double)
return c.f10(c.S2 { x, y, z })
end
local x = c10(1, 2.5, 3.5)
print(x, x._0, x._1, x._2)
assert(x._0 == 1)
assert(x._1 == 2.5)
assert(x._2 == 3.5)
../build/bin/terra cconv_inline.t
Produces:
c: 1 2.500000 3.500000
cdata<struct R>: 0x550b6ea558 1 2.5 3.5
Observations:
- Moving the C function back into
terralib.includecstring
permits inlining, which seems to allow this test to pass.
Reproducer 4
local c = terralib.includecstring [[
#include <stdio.h>
typedef struct S2 {
int a;
double b;
double c;
} S2;
typedef struct R {
int _0;
double _1;
double _2;
} R;
__attribute__ ((noinline))
R f10(S2 a) {
printf("c: %d %f %f\n", a.a, a.b, a.c);
R r;
r._0 = a.a;
r._1 = a.b;
r._2 = a.c;
return r;
}
]]
terra c10(x : int, y : double, z : double)
return c.f10(c.S2 { x, y, z })
end
local x = c10(1, 2.5, 3.5)
print(x, x._0, x._1, x._2)
assert(x._0 == 1)
assert(x._1 == 2.5)
assert(x._2 == 3.5)
../build/bin/terra cconv_noinline.t
Produces:
Segmentation fault (core dumped)
Observation:
- Inlining can be disabled with
__attribute__ ((noinline))
, bringing the crash back.
Recommendations
- Add
__attribute__ ((noinline))
tocconv_more.t
C generated code to ensure we don't miss any similar bugs in the future.
Elliott Slaughter commented
Fixed by #595.