diff test/plain/test_aggrs.c @ 533:71c884e610f0

- integration of patches from Raphael Luba, Thekla, Inc.: * integration of aggregate-by-value (struct, union) support patch for x64 (win and sysv) * windows/x64 asm additions to specify how stack unwinds (help for debuggers, exception handling, etc.) * see Changelog for details - new calling convention modes for thiscalls (platform agnostic, was specific before) * new signature character for platform agnostic thiscalls ('*' / DC_SIGCHAR_CC_THISCALL) - dcCallF(), dcVCallF(), dcArgF() and dcVArgF(): * added support for aggregates-by-value (wasn't part of patch) * change that those functions don't implicitly call dcReset() anymore, which was unflexible (breaking change) - added macros to feature test implementation for aggregate-by-value and syscall support - changed libdyncall_s.lib and libdyncallback_s.lib order in callback test makefiles, as some toolchains are picky about order - doc: * man page updates to describe aggregate interface * manual overview changes to highlight platforms with aggregate-by-value support - test/plain: replaced tests w/ old/stale sctruct interface with new aggregate one
author Tassilo Philipp
date Thu, 21 Apr 2022 13:35:47 +0200
parents test/plain/test_structs.c@5fe52b7c6e02
children c477ddd64718
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/plain/test_aggrs.c	Thu Apr 21 13:35:47 2022 +0200
@@ -0,0 +1,516 @@
+/*
+
+ Package: dyncall
+ Library: test
+ File: test/plain/test_aggrs.c
+ Description:
+ License:
+
+   Copyright (c) 2022 Tassilo Philipp <tphilipp@potion-studios.com>
+
+   Permission to use, copy, modify, and distribute this software for any
+   purpose with or without fee is hereby granted, provided that the above
+   copyright notice and this permission notice appear in all copies.
+
+   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+*/
+
+
+
+
+#include "../../dyncall/dyncall.h"
+#include "../../dyncall/dyncall_signature.h"
+#include "../../dyncall/dyncall_aggregate.h"
+#include <stdio.h>
+
+
+#if defined(DC__Feature_AggrByVal)
+
+#if !defined(DC__OS_Win32)
+#  define __cdecl
+#endif
+
+typedef struct {
+	unsigned char a;
+} U8;
+
+typedef struct {
+	unsigned char a;
+	double b;
+} U8_Double;
+
+typedef struct {
+	float a;
+	float b;
+} Float_Float;
+
+typedef struct {
+	double a;
+	unsigned char b;
+} Double_U8;
+
+typedef struct {
+	float f;
+} NestedFloat;
+
+typedef struct {
+	int a;
+	NestedFloat b;
+} Int_NestedFloat;
+
+typedef struct {
+	double f;
+} NestedDouble;
+
+typedef struct {
+	int a;
+	NestedDouble b;
+} Int_NestedDouble;
+
+typedef struct {
+	double a;
+	double b;
+	double c;
+} Three_Double;
+
+typedef struct {
+	int       a;
+	long long b;
+} Int_LongLong;
+
+/* large struct: more than 8 int/ptr and 8 fp args, more than are passed by reg for both win and sysv for example */
+typedef struct {
+	double       a;
+	double       b;
+	double       c;
+	long long    d;
+	char         e;
+	char         f;
+	double       g;
+	double       h;
+	double       i;
+	float        j;
+	int          k;
+	float        l;
+	double       m;
+	short        n;
+	long         o;
+	int          p;
+	unsigned int q;
+	long long    r;
+} More_Than_Regs;
+
+
+static U8               __cdecl fun_return_u8(unsigned char a)                        { U8               r;  r.a = a;                       return r; }
+static U8_Double        __cdecl fun_return_u8_double(unsigned char a, double b)       { U8_Double        r;  r.a = a;  r.b   = b;           return r; }
+static Double_U8        __cdecl fun_return_double_u8(double a, unsigned char b)       { Double_U8        r;  r.a = a;  r.b   = b;           return r; }
+static Int_NestedFloat  __cdecl fun_return_int_nested_float(int a, float b)           { Int_NestedFloat  r;  r.a = a;  r.b.f = b;           return r; }
+static Int_NestedDouble __cdecl fun_return_int_nested_double(int a, double b)         { Int_NestedDouble r;  r.a = a;  r.b.f = b;           return r; }
+static Three_Double     __cdecl fun_return_three_double(double a, double b, double c) { Three_Double     r;  r.a = a;  r.b   = b;  r.c = c; return r; }
+
+
+int testAggrReturns()
+{
+	int ret = 1;
+
+	DCCallVM* vm = dcNewCallVM(4096);
+	dcMode(vm,DC_CALL_C_DEFAULT);
+	{
+		U8 expected = fun_return_u8(5), returned = { 124 };
+
+		DCaggr *s = dcNewAggr(1, sizeof(expected));
+
+		dcAggrField(s, DC_SIGCHAR_UCHAR, offsetof(U8, a), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcBeginCallAggr(vm, s);
+		dcArgChar(vm, expected.a);
+
+		dcCallAggr(vm, (DCpointer) &fun_return_u8, s, &returned);
+
+		dcFreeAggr(s);
+
+		printf("r:{C}  (cdecl): %d\n", (returned.a == expected.a));
+		ret = returned.a == expected.a && ret;
+	}
+	{
+		U8_Double expected = fun_return_u8_double(5, 5.5), returned = { 6, 7.8 };
+
+		DCaggr *s = dcNewAggr(2, sizeof(expected));
+
+		dcAggrField(s, DC_SIGCHAR_UCHAR,  offsetof(U8_Double, a), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(U8_Double, b), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcBeginCallAggr(vm, s);
+		dcArgChar(vm, expected.a);
+		dcArgDouble(vm, expected.b);
+
+		dcCallAggr(vm, (DCpointer) &fun_return_u8_double, s, &returned);
+
+		dcFreeAggr(s);
+
+		printf("r:{Cd}  (cdecl): %d\n", (returned.a == expected.a && returned.b == expected.b));
+		ret = returned.a == expected.a && returned.b == expected.b && ret;
+	}
+	{
+		Double_U8 expected = fun_return_double_u8(5.5, 42), returned = { 6.7, 8 };
+
+		DCaggr *s = dcNewAggr(2, sizeof(expected));
+
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Double_U8, a), 1);
+		dcAggrField(s, DC_SIGCHAR_UCHAR,  offsetof(Double_U8, b), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcBeginCallAggr(vm, s);
+		dcArgDouble(vm, expected.a);
+		dcArgChar(vm, expected.b);
+
+		dcCallAggr(vm, (DCpointer) &fun_return_double_u8, s, &returned);
+
+		dcFreeAggr(s);
+
+		printf("r:{dC}  (cdecl): %d\n", (returned.a == expected.a && returned.b == expected.b));
+		ret = returned.a == expected.a && returned.b == expected.b && ret;
+	}
+	{
+		Int_NestedFloat expected = fun_return_int_nested_float(24, 2.5f), returned = { 25, { 3.5f } };
+		DCaggr *s, *s_;
+
+		s_ = dcNewAggr(1, sizeof(NestedFloat));
+		dcAggrField(s_, DC_SIGCHAR_FLOAT, offsetof(NestedFloat, f), 1);
+		dcCloseAggr(s_);
+
+		s = dcNewAggr(2, sizeof(expected));
+		dcAggrField(s, DC_SIGCHAR_INT, offsetof(Int_NestedFloat, a), 1);
+		dcAggrField(s, DC_SIGCHAR_AGGREGATE, offsetof(Int_NestedFloat, b), 1, s_);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcBeginCallAggr(vm, s);
+		dcArgInt(vm, expected.a);
+		dcArgFloat(vm, expected.b.f);
+
+		dcCallAggr(vm, (DCpointer) &fun_return_int_nested_float, s, &returned);
+
+		dcFreeAggr(s_);
+		dcFreeAggr(s);
+
+		printf("r:{i{f}}  (cdecl): %d\n", (returned.a == expected.a && returned.b.f == expected.b.f));
+		ret = returned.a == expected.a && returned.b.f == expected.b.f && ret;
+	}
+	{
+		Int_NestedDouble expected = fun_return_int_nested_double(24, 2.5), returned = { 25, { 3.5f } };
+		DCaggr *s, *s_;
+
+		s_ = dcNewAggr(1, sizeof(NestedDouble));
+		dcAggrField(s_, DC_SIGCHAR_DOUBLE, offsetof(NestedDouble, f), 1);
+		dcCloseAggr(s_);
+
+		s = dcNewAggr(2, sizeof(expected));
+		dcAggrField(s, DC_SIGCHAR_INT, offsetof(Int_NestedDouble, a), 1);
+		dcAggrField(s, DC_SIGCHAR_AGGREGATE, offsetof(Int_NestedDouble, b), 1, s_);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcBeginCallAggr(vm, s);
+		dcArgInt(vm, expected.a);
+		dcArgDouble(vm, expected.b.f);
+
+		dcCallAggr(vm, (DCpointer) &fun_return_int_nested_double, s, &returned);
+
+		dcFreeAggr(s_);
+		dcFreeAggr(s);
+
+		printf("r:{i{d}}  (cdecl): %d\n", (returned.a == expected.a && returned.b.f == expected.b.f));
+		ret = returned.a == expected.a && returned.b.f == expected.b.f && ret;
+	}
+	{
+		Three_Double expected = fun_return_three_double(1.5, 2.5, 3.5), returned = { 2.5, 3.5, 4.5 };
+
+		DCaggr *s = dcNewAggr(3, sizeof(expected));
+
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, a), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, b), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, c), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcBeginCallAggr(vm, s);
+		dcArgDouble(vm, expected.a);
+		dcArgDouble(vm, expected.b);
+		dcArgDouble(vm, expected.c);
+
+		dcCallAggr(vm, (DCpointer) &fun_return_three_double, s, &returned);
+
+		dcFreeAggr(s);
+
+		printf("r:{ddd}  (cdecl): %d\n", (returned.a == expected.a && returned.b == expected.b && returned.c == expected.c));
+		ret = returned.a == expected.a && returned.b == expected.b && returned.c == expected.c && ret;
+	}
+
+	dcFree(vm);
+
+	return ret;
+}
+
+static double __cdecl fun_take_u8(U8 s)                                                                                { return s.a; }
+static double __cdecl fun_take_u8_double(U8_Double s)                                                                  { return s.a + s.b; }
+static double __cdecl fun_take_float_float(Float_Float s)                                                              { return s.a + s.b; }
+static double __cdecl fun_take_double_u8(Double_U8 s)                                                                  { return s.a + s.b; }
+static double __cdecl fun_take_int_nested_float(Int_NestedFloat s)                                                     { return s.a + s.b.f; }
+static double __cdecl fun_take_int_nested_double(Int_NestedDouble s)                                                   { return s.a + s.b.f; }
+static double __cdecl fun_take_three_double(Three_Double s)                                                            { return s.a + s.b + s.c; }
+static double __cdecl fun_take_mixed_fp(double a, float b, float c, int d, float e, double f, float g, Three_Double s) { return a + 2.*b + 3.*c + 4.*d + 5.*e + 6.*f + 7.*g + 8.*s.a + 9.*s.b + 10.*s.c; }
+static int    __cdecl fun_take_iiiii_il(int a, int b, int c, int d, int e, Int_LongLong f)                             { return a + b + c + d + e + f.a + (int)f.b; }
+static double __cdecl fun_take_more_than_regs(More_Than_Regs s)                                                        { return s.a + s.b + s.c + s.d + s.e + s.f + s.g + s.h + s.i + s.j + s.k + s.l + s.m + s.n + s.o + s.p + s.q + s.r; }
+
+
+int testAggrParameters()
+{
+	int ret = 1;
+
+	DCCallVM* vm = dcNewCallVM(4096);
+	dcMode(vm,DC_CALL_C_DEFAULT);
+	{
+		U8 t = { 5 };
+		double returned;
+
+		DCaggr *s = dcNewAggr(1, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_UCHAR, offsetof(U8, a), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_u8);
+
+		dcFreeAggr(s);
+
+		printf("{C}  (cdecl): %d\n", returned == t.a);
+		ret = returned == t.a && ret;
+	}
+	{
+		U8_Double t = { 5, 5.5 };
+		double returned;
+
+		DCaggr *s = dcNewAggr(2, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_UCHAR,  offsetof(U8_Double, a), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(U8_Double, b), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_u8_double);
+
+		dcFreeAggr(s);
+
+		printf("{Cd}  (cdecl): %d\n", returned == t.a + t.b);
+		ret = returned == t.a + t.b && ret;
+	}
+	{
+		Float_Float t = { 1.5, 5.5 };
+		double returned;
+
+		DCaggr *s = dcNewAggr(2, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_FLOAT, offsetof(Float_Float, a), 1);
+		dcAggrField(s, DC_SIGCHAR_FLOAT, offsetof(Float_Float, b), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_float_float);
+
+		dcFreeAggr(s);
+
+		printf("{ff}  (cdecl): %d\n", returned == t.a + t.b);
+		ret = returned == t.a + t.b && ret;
+	}
+	{
+		Double_U8 t = { 5.5, 42 };
+		double returned;
+
+		DCaggr *s = dcNewAggr(2, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Double_U8, a), 1);
+		dcAggrField(s, DC_SIGCHAR_UCHAR,  offsetof(Double_U8, b), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_double_u8);
+
+		dcFreeAggr(s);
+
+		printf("{dC}  (cdecl): %d\n", returned == t.a + t.b);
+		ret = returned == t.a + t.b && ret;
+	}
+	{
+		Int_NestedFloat t = { 24, { 2.5f } };
+		double returned;
+		DCaggr *s, *s_;
+
+		s_ = dcNewAggr(1, sizeof(NestedFloat));
+		dcAggrField(s_, DC_SIGCHAR_FLOAT, offsetof(NestedFloat, f), 1);
+		dcCloseAggr(s_);
+
+		s = dcNewAggr(2, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_INT, offsetof(Int_NestedFloat, a), 1);
+		dcAggrField(s, DC_SIGCHAR_AGGREGATE, offsetof(Int_NestedFloat, b), 1, s_);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_int_nested_float);
+
+		dcFreeAggr(s_);
+		dcFreeAggr(s);
+
+		printf("{i{f}}  (cdecl): %d\n", returned == t.a + t.b.f);
+		ret = returned == t.a + t.b.f && ret;
+	}
+	{
+		Int_NestedDouble t = { 24, { 2.5} };
+		double returned;
+		DCaggr *s, *s_;
+
+		s_ = dcNewAggr(1, sizeof(NestedDouble));
+		dcAggrField(s_, DC_SIGCHAR_DOUBLE, offsetof(NestedDouble, f), 1);
+		dcCloseAggr(s_);
+
+		s = dcNewAggr(2, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_INT, offsetof(Int_NestedDouble, a), 1);
+		dcAggrField(s, DC_SIGCHAR_AGGREGATE, offsetof(Int_NestedDouble, b), 1, s_);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_int_nested_double);
+
+		dcFreeAggr(s_);
+		dcFreeAggr(s);
+
+		printf("{i{d}}  (cdecl): %d\n", returned == t.a + t.b.f);
+		ret = returned == t.a + t.b.f && ret;
+	}
+	{
+		Three_Double t = { 1.5, 2.5, 3.5 };
+		double returned;
+
+		DCaggr *s = dcNewAggr(3, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, a), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, b), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, c), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_three_double);
+
+		dcFreeAggr(s);
+
+		printf("{fff}  (cdecl): %d\n", returned == t.a + t.b + t.c);
+		ret = returned == t.a + t.b + t.c && ret;
+	}
+	{
+		/* w/ some prev params, so not fitting into float regs anymore (on win and sysv) */
+		Three_Double t = { 1.5, 2.5, 3.5 };
+		double returned;
+
+		DCaggr *s = dcNewAggr(3, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, a), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, b), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE, offsetof(Three_Double, c), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgDouble(vm, 234.4);
+		dcArgFloat(vm, 34.4f);
+		dcArgFloat(vm, 4.0f);
+		dcArgInt(vm, -12);
+		dcArgFloat(vm, -83.9f);
+		dcArgDouble(vm, -.9);
+		dcArgFloat(vm, .6f);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_mixed_fp) + 84.;
+		if(returned < 0.)
+			returned = -returned;
+
+		dcFreeAggr(s);
+
+		printf("dffifdf{fff}  (cdecl): %d\n", returned < .00001);
+		ret = returned < .00001 && ret;
+	}
+	{
+		Int_LongLong t = { -17, 822LL };
+		int returned;
+
+		DCaggr *s = dcNewAggr(2, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_INT,      offsetof(Int_LongLong, a), 1);
+		dcAggrField(s, DC_SIGCHAR_LONGLONG, offsetof(Int_LongLong, b), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgInt(vm, 23);
+		dcArgInt(vm, -211);
+		dcArgInt(vm, 111);
+		dcArgInt(vm, 34);
+		dcArgInt(vm, -19290);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallInt(vm, (DCpointer) &fun_take_iiiii_il);
+
+		dcFreeAggr(s);
+
+		printf("iiiii{il}  (cdecl): %d\n", returned == -18528);
+		ret = returned == -18528 && ret;
+	}
+	{
+		More_Than_Regs t = { 1., 2., 3., 4, 5, 6, 7., 8., 9., 10.f, 11, 12.f, 13., 14, 15, 16, 17, 18 };
+		double returned;
+
+		DCaggr *s = dcNewAggr(18, sizeof(t));
+		dcAggrField(s, DC_SIGCHAR_DOUBLE,   offsetof(More_Than_Regs, a), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE,   offsetof(More_Than_Regs, b), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE,   offsetof(More_Than_Regs, c), 1);
+		dcAggrField(s, DC_SIGCHAR_LONGLONG, offsetof(More_Than_Regs, d), 1);
+		dcAggrField(s, DC_SIGCHAR_CHAR,     offsetof(More_Than_Regs, e), 1);
+		dcAggrField(s, DC_SIGCHAR_CHAR,     offsetof(More_Than_Regs, f), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE,   offsetof(More_Than_Regs, g), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE,   offsetof(More_Than_Regs, h), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE,   offsetof(More_Than_Regs, i), 1);
+		dcAggrField(s, DC_SIGCHAR_FLOAT,    offsetof(More_Than_Regs, j), 1);
+		dcAggrField(s, DC_SIGCHAR_INT,      offsetof(More_Than_Regs, k), 1);
+		dcAggrField(s, DC_SIGCHAR_FLOAT,    offsetof(More_Than_Regs, l), 1);
+		dcAggrField(s, DC_SIGCHAR_DOUBLE,   offsetof(More_Than_Regs, m), 1);
+		dcAggrField(s, DC_SIGCHAR_SHORT,    offsetof(More_Than_Regs, n), 1);
+		dcAggrField(s, DC_SIGCHAR_LONG,     offsetof(More_Than_Regs, o), 1);
+		dcAggrField(s, DC_SIGCHAR_INT,      offsetof(More_Than_Regs, p), 1);
+		dcAggrField(s, DC_SIGCHAR_UINT,     offsetof(More_Than_Regs, q), 1);
+		dcAggrField(s, DC_SIGCHAR_LONGLONG, offsetof(More_Than_Regs, r), 1);
+		dcCloseAggr(s);
+
+		dcReset(vm);
+		dcArgAggr(vm, s, &t);
+		returned = dcCallDouble(vm, (DCpointer) &fun_take_more_than_regs);
+
+		dcFreeAggr(s);
+
+		printf("{dddlccdddfifdsjiIl}  (cdecl): %d\n", returned == 171.);
+		ret = returned == 171. && ret;
+	}
+
+	dcFree(vm);
+
+	return ret;
+}
+
+#endif
+