Mercurial > pub > dyncall > dyncall
comparison dyncall/dyncall_aggregate_x64.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 | |
children | a73a5cd50c19 |
comparison
equal
deleted
inserted
replaced
532:d4bf63ab9164 | 533:71c884e610f0 |
---|---|
1 /* | |
2 | |
3 Package: dyncall | |
4 Library: dyncall | |
5 File: dyncall/dyncall_aggregate_x64.c | |
6 Description: | |
7 License: | |
8 | |
9 Copyright (c) 2021-2022 Tassilo Philipp <tphilipp@potion-studios.com> | |
10 | |
11 Permission to use, copy, modify, and distribute this software for any | |
12 purpose with or without fee is hereby granted, provided that the above | |
13 copyright notice and this permission notice appear in all copies. | |
14 | |
15 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
16 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
17 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
18 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
21 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
22 | |
23 */ | |
24 | |
25 | |
26 #if defined(DC_UNIX) | |
27 | |
28 #define DC_ONE_8BYTE 8 | |
29 #define DC_TWO_8BYTES 2*8 | |
30 #define DC_EIGHT_8BYTES 8*8 | |
31 | |
32 /* helper - long long mask with each byte being X */ | |
33 #define LLBYTE(X) ((X)&0xFFULL) | |
34 #define SYSVC_CHECK_ALL_CLASSES(X) ((LLBYTE(X)<<56)|(LLBYTE(X)<<48)|(LLBYTE(X)<<40)|(LLBYTE(X)<<32)|(LLBYTE(X)<<24)|(LLBYTE(X)<<16)|(LLBYTE(X)<<8)|LLBYTE(X)) | |
35 | |
36 | |
37 static DCuchar dc_get_sysv_class_for_8byte(const DCaggr *ag, int index, int base_offset) | |
38 { | |
39 int qword_offset = index * DC_ONE_8BYTE, i; | |
40 DCuchar clz = SYSVC_NONE; | |
41 | |
42 for(i = 0; i < ag->n_fields; i++) { | |
43 const DCfield *f = ag->fields + i; | |
44 DCsize offset = base_offset + f->offset; | |
45 | |
46 /* field outside of qword at index? */ | |
47 if(offset >= (qword_offset + DC_ONE_8BYTE) || (offset + f->size * f->array_len) <= qword_offset) | |
48 continue; | |
49 | |
50 DCuchar new_class = SYSVC_NONE; | |
51 | |
52 switch (f->type) { | |
53 case DC_SIGCHAR_BOOL: | |
54 case DC_SIGCHAR_CHAR: | |
55 case DC_SIGCHAR_UCHAR: | |
56 case DC_SIGCHAR_SHORT: | |
57 case DC_SIGCHAR_USHORT: | |
58 case DC_SIGCHAR_INT: | |
59 case DC_SIGCHAR_UINT: | |
60 case DC_SIGCHAR_LONG: | |
61 case DC_SIGCHAR_ULONG: | |
62 case DC_SIGCHAR_LONGLONG: | |
63 case DC_SIGCHAR_ULONGLONG: | |
64 case DC_SIGCHAR_STRING: | |
65 case DC_SIGCHAR_POINTER: | |
66 new_class = SYSVC_INTEGER; | |
67 break; | |
68 case DC_SIGCHAR_FLOAT: | |
69 case DC_SIGCHAR_DOUBLE: | |
70 new_class = SYSVC_SSE; | |
71 break; | |
72 case DC_SIGCHAR_AGGREGATE: | |
73 new_class = dc_get_sysv_class_for_8byte(f->sub_aggr, index, offset); | |
74 break; | |
75 /*case DClongdouble, DCcomplexfloat DCcomplexdouble DCcomplexlongdouble etc... -> x87/x87up/complexx87 classes @@@AGGR implement */ | |
76 } | |
77 | |
78 if (clz == new_class) | |
79 continue; | |
80 | |
81 if (clz == SYSVC_NONE) | |
82 clz = new_class; | |
83 else if (new_class == SYSVC_NONE) | |
84 continue; | |
85 else if (clz == SYSVC_MEMORY || new_class == SYSVC_MEMORY) | |
86 clz = SYSVC_MEMORY; | |
87 else if (clz == SYSVC_INTEGER || new_class == SYSVC_INTEGER) | |
88 clz = SYSVC_INTEGER; | |
89 /* @@@AGGR implement when implementing x87 types | |
90 else if ((clz & (SYSVC_X87|SYSVC_X87UP|SYSVC_COMPLEX_X87)) || (new_class & (SYSVC_X87|SYSVC_X87UP|SYSVC_COMPLEX_X87))) | |
91 clz = SYSVC_MEMORY;*/ | |
92 else | |
93 clz = SYSVC_SSE; | |
94 } | |
95 | |
96 return clz; | |
97 } | |
98 | |
99 | |
100 static void dc_get_sysv_classes_for_aggr(const DCaggr *ag, DCuchar *classes) | |
101 { | |
102 int i; | |
103 | |
104 #if 1 /* this is the optimized version that only respects types supported by dyncall */ | |
105 | |
106 if(ag->size > DC_TWO_8BYTES) { /* @@@AGGR not checking if a field is unaligned */ | |
107 classes[0] = SYSVC_MEMORY; | |
108 return; | |
109 } | |
110 | |
111 /* abi doc: "If one of the classes is MEMORY, the whole argument is passed in memory." */ | |
112 classes[0] = dc_get_sysv_class_for_8byte(ag, 0, 0); | |
113 if(classes[0] != SYSVC_MEMORY) { | |
114 classes[1] = dc_get_sysv_class_for_8byte(ag, 1, 0); | |
115 if(classes[1] == SYSVC_MEMORY) | |
116 classes[0] = SYSVC_MEMORY; | |
117 else | |
118 classes[2] = SYSVC_NONE; | |
119 } | |
120 /* @@@AGGR what would happen with alignment-enforced padding >= 8? Then no field would cover the eightbyte @@@test */ | |
121 | |
122 #else /* this would be the version following the ABI more closely, to be implemented fully or partly when those types get supported by dyncall */ | |
123 | |
124 /* abi doc: "If the size of an object is larger than eight qwords, or it | |
125 * contains unaligned fields, it has class MEMORY." | |
126 * note: ABI specs <v1.0 (2018) specify "four qwords", instead (b/c _m512 was added, later) */ /* @@@AGGR not checking if a field is unaligned */ | |
127 if(ag->size > DC_EIGHT_8BYTES) { | |
128 classes[0] = SYSVC_MEMORY; | |
129 return; | |
130 } | |
131 | |
132 /* classify fields according to each of max 8 qwords */ | |
133 for(i = 0; i < DC_SYSV_MAX_NUM_CLASSES; ++i) { | |
134 classes[i] = dc_get_sysv_class_for_8byte(ag, i, 0); | |
135 | |
136 /* abi doc: "If one of the classes is MEMORY, the whole argument is passed in memory." */ | |
137 if(classes[i] == SYSVC_MEMORY) { | |
138 classes[0] = SYSVC_MEMORY; | |
139 return; | |
140 } | |
141 | |
142 /* stop eightbyte classification on first SYSVC_NONE returned */ | |
143 /* @@@AGGR what would happen with alignment-enforced padding >= 8? Then no field would cover the eightbyte @@@test */ | |
144 if(classes[i] == SYSVC_NONE) | |
145 break; | |
146 } | |
147 | |
148 /* Do post merger cleanup */ | |
149 | |
150 /* abi doc: "If X87UP is not preceded by X87, the whole argument is passed in memory." */ | |
151 for(i = 1; i < DC_SYSV_MAX_NUM_CLASSES; ++i) { | |
152 if (classes[i-1] == SYSVC_X87 && classes[i] != SYSVC_X87UP) { | |
153 classes[0] = SYSVC_MEMORY; | |
154 return; | |
155 } | |
156 } | |
157 | |
158 /* abi doc: "If the size of the aggregate exceeds two qwords and the first eightbyte isn't | |
159 * SSE or any other eightbyte isn't SSEUP, the whole argument is passed in memory." */ | |
160 if(ag->size > DC_TWO_8BYTES) { | |
161 DClonglong mask = SYSVC_CHECK_ALL_CLASSES(SYSVC_SSEUP|SYSVC_NONE) ^ (LLBYTE(SYSVC_SSE|SYSVC_SSEUP|SYSVC_NONE)<<56); | |
162 if((*(DClonglong*)ag->sysv_classes & mask) != *(DClonglong*)ag->sysv_classes) { | |
163 classes[0] = SYSVC_MEMORY; | |
164 return; | |
165 } | |
166 } | |
167 | |
168 /* abi doc: "If SSEUP is not preceded by SSE or SSEUP, it is converted to SSE." */ | |
169 for(i = 1; i < DC_SYSV_MAX_NUM_CLASSES; ++i) { | |
170 DCuchar clz = classes[i]; | |
171 if(classes[i] == SYSVC_SSEUP && !(classes[i-1] & (SYSVC_SSE|SYSVC_SSEUP))) | |
172 classes[i] = SYSVC_SSE; | |
173 } | |
174 | |
175 #endif | |
176 } | |
177 | |
178 | |
179 void dcFinishAggr(DCaggr *ag) | |
180 { | |
181 dc_get_sysv_classes_for_aggr(ag, ag->sysv_classes); | |
182 | |
183 /* @@@AGGR implement when implementing x87 types | |
184 for(i=0; ag->sysv_classes[i] && i<DC_SYSV_MAX_NUM_CLASSES; ++i) | |
185 assert((ag->sysv_classes[i] & (SYSVC_MEMORY|SYSVC_INTEGER|SYSVC_SSE)) && "Unsupported System V class detected in struct");*/ | |
186 } | |
187 | |
188 #else | |
189 | |
190 void dcFinishAggr(DCaggr *ag) | |
191 { | |
192 } | |
193 | |
194 #endif | |
195 |