Windows on ARM64: Support Visual Studio ABI sret mechanism for non-trivial data types (#289)
* Add objc_msgSend_stret2 * Guard and Export objc_msgSend_stret2 * Remove architecture hackery in CMake * Add objc_msgSend test for WoA64 * Add doc comment for objc_msgSend_stret2main
parent
51b9a076f0
commit
dc031d2741
@ -1,16 +0,0 @@
|
|||||||
// detect_arch.c
|
|
||||||
#if defined(__aarch64__)
|
|
||||||
#error aarch64
|
|
||||||
#elif defined(__arm__)
|
|
||||||
#error arm
|
|
||||||
#elif defined(__i386__)
|
|
||||||
#error i386
|
|
||||||
#elif defined(__x86_64__)
|
|
||||||
#error x86_64
|
|
||||||
#elif defined(__powerpc64__)
|
|
||||||
#error powerpc64
|
|
||||||
#elif defined(__powerpc__)
|
|
||||||
#error powerpc
|
|
||||||
#else
|
|
||||||
#error unknown
|
|
||||||
#endif
|
|
||||||
@ -0,0 +1,148 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include "../objc/runtime.h"
|
||||||
|
#include "../objc/hooks.h"
|
||||||
|
|
||||||
|
// Pass and return for type size <= 8 bytes.
|
||||||
|
struct S1 {
|
||||||
|
int a[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pass and return hfa <= 8 bytes
|
||||||
|
struct F1 {
|
||||||
|
float a[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pass and return type size <= 16 bytes
|
||||||
|
struct S2 {
|
||||||
|
int a[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pass and return for type size > 16 bytes.
|
||||||
|
struct S3 {
|
||||||
|
int a[5];
|
||||||
|
};
|
||||||
|
|
||||||
|
// Pass and return aggregate (of size < 16 bytes) with non-trivial destructor.
|
||||||
|
// Sret and inreg: Returned in x0
|
||||||
|
struct S4 {
|
||||||
|
int a[3];
|
||||||
|
~S4();
|
||||||
|
};
|
||||||
|
S4::~S4() {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass and return an object with a user-provided constructor (passed directly,
|
||||||
|
// returned indirectly)
|
||||||
|
struct S5 {
|
||||||
|
S5();
|
||||||
|
int x;
|
||||||
|
};
|
||||||
|
S5::S5() {
|
||||||
|
x = 42;
|
||||||
|
}
|
||||||
|
|
||||||
|
Class TestCls;
|
||||||
|
#ifdef __has_attribute
|
||||||
|
#if __has_attribute(objc_root_class)
|
||||||
|
__attribute__((objc_root_class))
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
@interface MsgTest { id isa; } @end
|
||||||
|
@implementation MsgTest
|
||||||
|
+ (S1) smallS1 {
|
||||||
|
assert(TestCls == self);
|
||||||
|
assert(strcmp("smallS1", sel_getName(_cmd)) == 0);
|
||||||
|
|
||||||
|
S1 x;
|
||||||
|
x.a[0] = 0;
|
||||||
|
x.a[1] = 1;
|
||||||
|
return x;
|
||||||
|
|
||||||
|
}
|
||||||
|
+ (F1) smallF1 {
|
||||||
|
assert(TestCls == self);
|
||||||
|
assert(strcmp("smallF1", sel_getName(_cmd)) == 0);
|
||||||
|
|
||||||
|
F1 x;
|
||||||
|
x.a[0] = 0.2f;
|
||||||
|
x.a[1] = 0.5f;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
+ (S2) smallS2 {
|
||||||
|
assert(TestCls == self);
|
||||||
|
assert(strcmp("smallS2", sel_getName(_cmd)) == 0);
|
||||||
|
|
||||||
|
S2 x;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
x.a[i] = i;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
+ (S3) stretS3 {
|
||||||
|
assert(TestCls == self);
|
||||||
|
assert(strcmp("stretS3", sel_getName(_cmd)) == 0);
|
||||||
|
|
||||||
|
S3 x;
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
x.a[i] = i;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
+ (S4) stretInRegS4 {
|
||||||
|
assert(TestCls == self);
|
||||||
|
assert(strcmp("stretInRegS4", sel_getName(_cmd)) == 0);
|
||||||
|
|
||||||
|
S4 x;
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
x.a[i] = i;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
+ (S5) stretInRegS5 {
|
||||||
|
assert(TestCls == self);
|
||||||
|
assert(strcmp("stretInRegS5", sel_getName(_cmd)) == 0);
|
||||||
|
|
||||||
|
return S5();
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
#ifdef __GNUSTEP_MSGSEND__
|
||||||
|
TestCls = objc_getClass("MsgTest");
|
||||||
|
|
||||||
|
// Returned in x0
|
||||||
|
S1 ret = ((S1(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallS1));
|
||||||
|
assert(ret.a[0] == 0);
|
||||||
|
assert(ret.a[1] == 1);
|
||||||
|
|
||||||
|
F1 retF1 = ((F1(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallF1));
|
||||||
|
assert(retF1.a[0] == 0.2f);
|
||||||
|
assert(retF1.a[1] == 0.5f);
|
||||||
|
|
||||||
|
// Returned in x0 and x1
|
||||||
|
S2 ret2 = ((S2(*)(id, SEL))objc_msgSend)(TestCls, @selector(smallS2));
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
assert(ret2.a[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indirect result register x8 used
|
||||||
|
S3 ret3 = ((S3(*)(id, SEL))objc_msgSend_stret)(TestCls, @selector(stretS3));
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
assert(ret3.a[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stret with inreg. Returned in x0.
|
||||||
|
S4 ret4 = ((S4(*)(id, SEL))objc_msgSend_stret2)(TestCls, @selector(stretInRegS4));
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
assert(ret4.a[i] == i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stret with inreg. Returned in x0.
|
||||||
|
S5 ret5 = ((S5(*)(id, SEL))objc_msgSend_stret2)(TestCls, @selector(stretInRegS5));
|
||||||
|
assert(ret5.x == 42);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#endif // __GNUSTEP_MSGSEND__
|
||||||
|
return 77;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue