1 /**
2 Copyright 1993 Bill Triggs <Bill.Triggs@inrialpes.fr>
3 Copyright 1995-2021 Bruno Haible <bruno@clisp.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17 **/
18 /*----------------------------------------------------------------------
19 !!! THIS ROUTINE MUST BE COMPILED gcc -O !!!
20
21 Foreign function interface for a Sparc v9 in 64-bit mode with gcc.
22
23 This calls a C function with an argument list built up using macros
24 defined in avcall.h.
25
26 Sparc 64-bit Argument Passing Conventions
27
28 The argument registers are laid out as an array of 16 elements
29 and arguments are added sequentially. The first 6 int args and up to the
30 first 16 fp args (depending on size) are passed in regs.
31
32 Slot Stack Integral Float Float in structure Double Long Double
33 ---- ----- -------- ----- ------------------ ------ -----------
34 15 [SP+248] %f31 %f30,%f31 %d30
35 14 [SP+240] %f29 %f28,%f29 %d28 %q28
36 13 [SP+232] %f27 %f26,%f27 %d26
37 12 [SP+224] %f25 %f24,%f25 %d24 %q24
38 11 [SP+216] %f23 %f22,%f23 %d22
39 10 [SP+208] %f21 %f20,%f21 %d20 %q20
40 9 [SP+200] %f19 %f18,%f19 %d18
41 8 [SP+192] %f17 %f16,%f17 %d16 %q16
42 7 [SP+184] %f15 %f14,%f15 %d14
43 6 [SP+176] %f13 %f12,%f13 %d12 %q12
44 5 [SP+168] %o5 %f11 %f10,%f11 %d10
45 4 [SP+160] %o4 %f9 %f8,%f9 %d8 %q8
46 3 [SP+152] %o3 %f7 %f6,%f7 %d6
47 2 [SP+144] %o2 %f5 %f4,%f5 %d4 %q4
48 1 [SP+136] %o1 %f3 %f2,%f3 %d2
49 0 [SP+128] %o0 %f1 %f0,%f1 %d0 %q0
50
51 Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise.
52
53 Integral arguments are always passed as 64 bit quantities appropriately
54 extended.
55
56 Passing of floating point values is handled as follows.
57 If a prototype is in scope:
58 If the value is in a named argument (i.e. not a stdarg function or a
59 value not part of the ‘...’) then the value is passed in the appropriate
60 fp reg.
61 If the value is part of the ‘...’ and is passed in one of the first 6
62 slots then the value is passed in the appropriate int reg.
63 If the value is part of the ‘...’ and is not passed in one of the first 6
64 slots then the value is passed in memory.
65 If a prototype is not in scope:
66 If the value is one of the first 6 arguments the value is passed in the
67 appropriate integer reg and the appropriate fp reg.
68 If the value is not one of the first 6 arguments the value is passed in
69 the appropriate fp reg and in memory.
70
71 Remaining arguments are pushed onto the stack starting at a fixed offset
72 Space is left on the stack frame for temporary storage of the register
73 arguments as well.
74
75 Integers shorter than ‘long’ are always promoted to word-length
76 (zero-extended or sign-extended, according to their type). Structures
77 <= 16 bytes are passed embedded in the argument sequence; bigger structures
78 are passed by reference.
79
80 Integers and pointers are returned in o0, floats in f0, doubles in
81 f0/f1. If the function returns a structure a pointer to space
82 allocated by the caller is pushed onto the stack immediately
83 before the function arguments. Structures <= 32 bytes are returned in
84 registers (integer/float/double registers, as appropriate).
85
86 Long doubles are 16-byte aligned, but we don't deal with this here, so
87 we assume 8-byte alignment for everything.
88
89 ----------------------------------------------------------------------*/
90 #include "avcall-internal.h"
91
92 #define RETURN(TYPE,VAL) (*(TYPE*)l->raddr = (TYPE)(VAL))
93 #define OFFSETOF(struct,member) ((int)&(((struct*)0)->member))
94
95 register __avrword o0 __asm__("%o0");
96 register __avrword o1 __asm__("%o1");
97 register __avrword o2 __asm__("%o2");
98 register __avrword o3 __asm__("%o3");
99 register __avrword o4 __asm__("%o4");
100 register __avrword o5 __asm__("%o5");
101
102 int
avcall_call(av_alist * list)103 avcall_call(av_alist* list)
104 {
105 register __avword* sp __asm__("%sp"); /* C names for registers */
106 register float fret __asm__("%f0"); /* %f0 */
107 register double dret __asm__("%f0"); /* %f0,%f1 */
108
109 __av_alist* l = &AV_LIST_INNER(list);
110
111 __avword trampoline[6]; /* room for a trampoline */
112 int arglen = l->aptr - l->args;
113 __avrword iret;
114
115 if (l->darg_mask) {
116 /* push leading float/double args */
117 __avword* a = l->args;
118 if (l->darg_mask & (1<<0))
119 __asm__("ldd [%0+%1],%%f0" : : "p" (a), "i" (0 * sizeof (__avword)));
120 if (l->darg_mask & (1<<1))
121 __asm__("ldd [%0+%1],%%f2" : : "p" (a), "i" (1 * sizeof (__avword)));
122 if (l->darg_mask & (1<<2))
123 __asm__("ldd [%0+%1],%%f4" : : "p" (a), "i" (2 * sizeof (__avword)));
124 if (l->darg_mask & (1<<3))
125 __asm__("ldd [%0+%1],%%f6" : : "p" (a), "i" (3 * sizeof (__avword)));
126 if (l->darg_mask & (1<<4))
127 __asm__("ldd [%0+%1],%%f8" : : "p" (a), "i" (4 * sizeof (__avword)));
128 if (l->darg_mask & (1<<5))
129 __asm__("ldd [%0+%1],%%f10" : : "p" (a), "i" (5 * sizeof (__avword)));
130 if (l->darg_mask & (1<<6))
131 __asm__("ldd [%0+%1],%%f12" : : "p" (a), "i" (6 * sizeof (__avword)));
132 if (l->darg_mask & (1<<7))
133 __asm__("ldd [%0+%1],%%f14" : : "p" (a), "i" (7 * sizeof (__avword)));
134 if (l->darg_mask & (1<<8))
135 __asm__("ldd [%0+%1],%%f16" : : "p" (a), "i" (8 * sizeof (__avword)));
136 if (l->darg_mask & (1<<9))
137 __asm__("ldd [%0+%1],%%f18" : : "p" (a), "i" (9 * sizeof (__avword)));
138 if (l->darg_mask & (1<<10))
139 __asm__("ldd [%0+%1],%%f20" : : "p" (a), "i" (10 * sizeof (__avword)));
140 if (l->darg_mask & (1<<11))
141 __asm__("ldd [%0+%1],%%f22" : : "p" (a), "i" (11 * sizeof (__avword)));
142 if (l->darg_mask & (1<<12))
143 __asm__("ldd [%0+%1],%%f24" : : "p" (a), "i" (12 * sizeof (__avword)));
144 if (l->darg_mask & (1<<13))
145 __asm__("ldd [%0+%1],%%f26" : : "p" (a), "i" (13 * sizeof (__avword)));
146 if (l->darg_mask & (1<<14))
147 __asm__("ldd [%0+%1],%%f28" : : "p" (a), "i" (14 * sizeof (__avword)));
148 if (l->darg_mask & (1<<15))
149 __asm__("ldd [%0+%1],%%f30" : : "p" (a), "i" (15 * sizeof (__avword)));
150 }
151
152 if (arglen > 6) {
153 /* alloca space is separated from the extra outgoing args area by
154 * the area for compiler temps (addressable with postive offsets from sp)
155 * but they shouldn't be needed for this function, so, effectively,
156 * space returned by alloca is safe to use as the area for extra args.
157 */
158 void *extra_args_area = __builtin_alloca(sizeof(__avword) * (arglen - 6));
159 __avword *argframe = (__avword *)extra_args_area - 6;
160 #if 0
161 /* "by construction" */
162 assert(argframe == (void *)((unsigned long)(sp + 16)+2047));
163 #endif
164
165 int i;
166 for (i = 6; i < arglen; i++) /* push excess function args */
167 argframe[i] = l->args[i];
168 }
169
170 /* call function with 1st 6 args */
171 iret = ({ register __avrword iretreg __asm__ ("%o0");
172 iretreg = (*l->func)(l->args[0], l->args[1], l->args[2],
173 l->args[3], l->args[4], l->args[5]);
174 asm __volatile__("nop"); /* struct returning functions skip this instruction */
175 iretreg;
176 });
177
178 /* save return value */
179 if (l->rtype == __AVvoid) {
180 } else
181 if (l->rtype == __AVchar) {
182 RETURN(char, iret);
183 } else
184 if (l->rtype == __AVschar) {
185 RETURN(signed char, iret);
186 } else
187 if (l->rtype == __AVuchar) {
188 RETURN(unsigned char, iret);
189 } else
190 if (l->rtype == __AVshort) {
191 RETURN(short, iret);
192 } else
193 if (l->rtype == __AVushort) {
194 RETURN(unsigned short, iret);
195 } else
196 if (l->rtype == __AVint) {
197 RETURN(int, iret);
198 } else
199 if (l->rtype == __AVuint) {
200 RETURN(unsigned int, iret);
201 } else
202 if (l->rtype == __AVlong) {
203 RETURN(long, iret);
204 } else
205 if (l->rtype == __AVulong) {
206 RETURN(unsigned long, iret);
207 } else
208 if (l->rtype == __AVlonglong) {
209 RETURN(long long, iret);
210 } else
211 if (l->rtype == __AVulonglong) {
212 RETURN(unsigned long long, iret);
213 } else
214 if (l->rtype == __AVfloat) {
215 RETURN(float, fret);
216 } else
217 if (l->rtype == __AVdouble) {
218 RETURN(double, dret);
219 } else
220 if (l->rtype == __AVvoidp) {
221 RETURN(void*, iret);
222 } else
223 if (l->rtype == __AVstruct) {
224 if (l->flags & __AV_REGISTER_STRUCT_RETURN) {
225 /* Return structs of size <= 32 in registers. */
226 #define iret2 o1
227 #define iret3 o2
228 #define iret4 o3
229 if (l->rsize > 0 && l->rsize <= 32) {
230 void* raddr = l->raddr;
231 #if 0 /* Unoptimized */
232 if (l->rsize == 1) {
233 ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
234 } else
235 if (l->rsize == 2) {
236 ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
237 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
238 } else
239 if (l->rsize == 3) {
240 ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
241 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
242 ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
243 } else
244 if (l->rsize == 4) {
245 ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
246 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
247 ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
248 ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
249 } else
250 if (l->rsize == 5) {
251 ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
252 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
253 ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
254 ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
255 ((unsigned char *)raddr)[4] = (unsigned char)(iret>>24);
256 } else
257 if (l->rsize == 6) {
258 ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
259 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
260 ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
261 ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
262 ((unsigned char *)raddr)[4] = (unsigned char)(iret>>24);
263 ((unsigned char *)raddr)[5] = (unsigned char)(iret>>16);
264 } else
265 if (l->rsize == 7) {
266 ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
267 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
268 ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
269 ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
270 ((unsigned char *)raddr)[4] = (unsigned char)(iret>>24);
271 ((unsigned char *)raddr)[5] = (unsigned char)(iret>>16);
272 ((unsigned char *)raddr)[6] = (unsigned char)(iret>>8);
273 } else
274 if (l->rsize >= 8 && l->rsize <= 32) {
275 ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
276 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
277 ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
278 ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
279 ((unsigned char *)raddr)[4] = (unsigned char)(iret>>24);
280 ((unsigned char *)raddr)[5] = (unsigned char)(iret>>16);
281 ((unsigned char *)raddr)[6] = (unsigned char)(iret>>8);
282 ((unsigned char *)raddr)[7] = (unsigned char)(iret);
283 if (l->rsize == 8) {
284 } else
285 if (l->rsize == 9) {
286 ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
287 } else
288 if (l->rsize == 10) {
289 ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
290 ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
291 } else
292 if (l->rsize == 11) {
293 ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
294 ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
295 ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
296 } else
297 if (l->rsize == 12) {
298 ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
299 ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
300 ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
301 ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
302 } else
303 if (l->rsize == 13) {
304 ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
305 ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
306 ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
307 ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
308 ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>24);
309 } else
310 if (l->rsize == 14) {
311 ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
312 ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
313 ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
314 ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
315 ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>24);
316 ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>16);
317 } else
318 if (l->rsize == 15) {
319 ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
320 ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
321 ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
322 ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
323 ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>24);
324 ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>16);
325 ((unsigned char *)raddr)[8+6] = (unsigned char)(iret2>>8);
326 } else
327 if (l->rsize >= 16 && l->rsize <= 32) {
328 ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
329 ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
330 ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
331 ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
332 ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>24);
333 ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>16);
334 ((unsigned char *)raddr)[8+6] = (unsigned char)(iret2>>8);
335 ((unsigned char *)raddr)[8+7] = (unsigned char)(iret2);
336 if (l->rsize == 16) {
337 } else
338 if (l->rsize == 17) {
339 ((unsigned char *)raddr)[16+0] = (unsigned char)(iret3>>56);
340 } else
341 if (l->rsize == 18) {
342 ((unsigned char *)raddr)[16+0] = (unsigned char)(iret3>>56);
343 ((unsigned char *)raddr)[16+1] = (unsigned char)(iret3>>48);
344 } else
345 if (l->rsize == 19) {
346 ((unsigned char *)raddr)[16+0] = (unsigned char)(iret3>>56);
347 ((unsigned char *)raddr)[16+1] = (unsigned char)(iret3>>48);
348 ((unsigned char *)raddr)[16+2] = (unsigned char)(iret3>>40);
349 } else
350 if (l->rsize == 20) {
351 ((unsigned char *)raddr)[16+0] = (unsigned char)(iret3>>56);
352 ((unsigned char *)raddr)[16+1] = (unsigned char)(iret3>>48);
353 ((unsigned char *)raddr)[16+2] = (unsigned char)(iret3>>40);
354 ((unsigned char *)raddr)[16+3] = (unsigned char)(iret3>>32);
355 } else
356 if (l->rsize == 21) {
357 ((unsigned char *)raddr)[16+0] = (unsigned char)(iret3>>56);
358 ((unsigned char *)raddr)[16+1] = (unsigned char)(iret3>>48);
359 ((unsigned char *)raddr)[16+2] = (unsigned char)(iret3>>40);
360 ((unsigned char *)raddr)[16+3] = (unsigned char)(iret3>>32);
361 ((unsigned char *)raddr)[16+4] = (unsigned char)(iret3>>24);
362 } else
363 if (l->rsize == 22) {
364 ((unsigned char *)raddr)[16+0] = (unsigned char)(iret3>>56);
365 ((unsigned char *)raddr)[16+1] = (unsigned char)(iret3>>48);
366 ((unsigned char *)raddr)[16+2] = (unsigned char)(iret3>>40);
367 ((unsigned char *)raddr)[16+3] = (unsigned char)(iret3>>32);
368 ((unsigned char *)raddr)[16+4] = (unsigned char)(iret3>>24);
369 ((unsigned char *)raddr)[16+5] = (unsigned char)(iret3>>16);
370 } else
371 if (l->rsize == 23) {
372 ((unsigned char *)raddr)[16+0] = (unsigned char)(iret3>>56);
373 ((unsigned char *)raddr)[16+1] = (unsigned char)(iret3>>48);
374 ((unsigned char *)raddr)[16+2] = (unsigned char)(iret3>>40);
375 ((unsigned char *)raddr)[16+3] = (unsigned char)(iret3>>32);
376 ((unsigned char *)raddr)[16+4] = (unsigned char)(iret3>>24);
377 ((unsigned char *)raddr)[16+5] = (unsigned char)(iret3>>16);
378 ((unsigned char *)raddr)[16+6] = (unsigned char)(iret3>>8);
379 } else
380 if (l->rsize >= 24 && l->rsize <= 32) {
381 ((unsigned char *)raddr)[16+0] = (unsigned char)(iret3>>56);
382 ((unsigned char *)raddr)[16+1] = (unsigned char)(iret3>>48);
383 ((unsigned char *)raddr)[16+2] = (unsigned char)(iret3>>40);
384 ((unsigned char *)raddr)[16+3] = (unsigned char)(iret3>>32);
385 ((unsigned char *)raddr)[16+4] = (unsigned char)(iret3>>24);
386 ((unsigned char *)raddr)[16+5] = (unsigned char)(iret3>>16);
387 ((unsigned char *)raddr)[16+6] = (unsigned char)(iret3>>8);
388 ((unsigned char *)raddr)[16+7] = (unsigned char)(iret3);
389 if (l->rsize == 24) {
390 } else
391 if (l->rsize == 25) {
392 ((unsigned char *)raddr)[24+0] = (unsigned char)(iret4>>56);
393 } else
394 if (l->rsize == 26) {
395 ((unsigned char *)raddr)[24+0] = (unsigned char)(iret4>>56);
396 ((unsigned char *)raddr)[24+1] = (unsigned char)(iret4>>48);
397 } else
398 if (l->rsize == 27) {
399 ((unsigned char *)raddr)[24+0] = (unsigned char)(iret4>>56);
400 ((unsigned char *)raddr)[24+1] = (unsigned char)(iret4>>48);
401 ((unsigned char *)raddr)[24+2] = (unsigned char)(iret4>>40);
402 } else
403 if (l->rsize == 28) {
404 ((unsigned char *)raddr)[24+0] = (unsigned char)(iret4>>56);
405 ((unsigned char *)raddr)[24+1] = (unsigned char)(iret4>>48);
406 ((unsigned char *)raddr)[24+2] = (unsigned char)(iret4>>40);
407 ((unsigned char *)raddr)[24+3] = (unsigned char)(iret4>>32);
408 } else
409 if (l->rsize == 29) {
410 ((unsigned char *)raddr)[24+0] = (unsigned char)(iret4>>56);
411 ((unsigned char *)raddr)[24+1] = (unsigned char)(iret4>>48);
412 ((unsigned char *)raddr)[24+2] = (unsigned char)(iret4>>40);
413 ((unsigned char *)raddr)[24+3] = (unsigned char)(iret4>>32);
414 ((unsigned char *)raddr)[24+4] = (unsigned char)(iret4>>24);
415 } else
416 if (l->rsize == 30) {
417 ((unsigned char *)raddr)[24+0] = (unsigned char)(iret4>>56);
418 ((unsigned char *)raddr)[24+1] = (unsigned char)(iret4>>48);
419 ((unsigned char *)raddr)[24+2] = (unsigned char)(iret4>>40);
420 ((unsigned char *)raddr)[24+3] = (unsigned char)(iret4>>32);
421 ((unsigned char *)raddr)[24+4] = (unsigned char)(iret4>>24);
422 ((unsigned char *)raddr)[24+5] = (unsigned char)(iret4>>16);
423 } else
424 if (l->rsize == 31) {
425 ((unsigned char *)raddr)[24+0] = (unsigned char)(iret4>>56);
426 ((unsigned char *)raddr)[24+1] = (unsigned char)(iret4>>48);
427 ((unsigned char *)raddr)[24+2] = (unsigned char)(iret4>>40);
428 ((unsigned char *)raddr)[24+3] = (unsigned char)(iret4>>32);
429 ((unsigned char *)raddr)[24+4] = (unsigned char)(iret4>>24);
430 ((unsigned char *)raddr)[24+5] = (unsigned char)(iret4>>16);
431 ((unsigned char *)raddr)[24+6] = (unsigned char)(iret4>>8);
432 } else
433 if (l->rsize == 32) {
434 ((unsigned char *)raddr)[24+0] = (unsigned char)(iret4>>56);
435 ((unsigned char *)raddr)[24+1] = (unsigned char)(iret4>>48);
436 ((unsigned char *)raddr)[24+2] = (unsigned char)(iret4>>40);
437 ((unsigned char *)raddr)[24+3] = (unsigned char)(iret4>>32);
438 ((unsigned char *)raddr)[24+4] = (unsigned char)(iret4>>24);
439 ((unsigned char *)raddr)[24+5] = (unsigned char)(iret4>>16);
440 ((unsigned char *)raddr)[24+6] = (unsigned char)(iret4>>8);
441 ((unsigned char *)raddr)[24+7] = (unsigned char)(iret4);
442 }
443 }
444 }
445 }
446 #else /* Optimized: fewer conditional jumps, fewer memory accesses */
447 uintptr_t count = l->rsize; /* > 0, ≤ 4*sizeof(__avrword) */
448 __avrword* wordaddr = (__avrword*)((uintptr_t)raddr & ~(uintptr_t)(sizeof(__avrword)-1));
449 uintptr_t start_offset = (uintptr_t)raddr & (uintptr_t)(sizeof(__avrword)-1); /* ≥ 0, < sizeof(__avrword) */
450 uintptr_t end_offset = start_offset + count; /* > 0, < 5*sizeof(__avrword) */
451 if (count <= sizeof(__avrword)) {
452 /* Use iret. */
453 if (end_offset <= sizeof(__avrword)) {
454 /* 0 < end_offset ≤ sizeof(__avrword) */
455 __avrword mask0 = ((__avrword)2 << (sizeof(__avrword)*8-start_offset*8-1)) - ((__avrword)1 << (sizeof(__avrword)*8-end_offset*8));
456 wordaddr[0] ^= (wordaddr[0] ^ (iret >> (start_offset*8))) & mask0;
457 } else {
458 /* sizeof(__avrword) < end_offset < 2*sizeof(__avrword), start_offset > 0 */
459 __avrword mask0 = ((__avrword)2 << (sizeof(__avrword)*8-start_offset*8-1)) - 1;
460 __avrword mask1 = - ((__avrword)1 << (2*sizeof(__avrword)*8-end_offset*8));
461 wordaddr[0] ^= (wordaddr[0] ^ (iret >> (start_offset*8))) & mask0;
462 wordaddr[1] ^= (wordaddr[1] ^ (iret << (sizeof(__avrword)*8-start_offset*8))) & mask1;
463 }
464 } else if (count <= 2*sizeof(__avrword)) {
465 /* Use iret, iret2. */
466 __avrword mask0 = ((__avrword)2 << (sizeof(__avrword)*8-start_offset*8-1)) - 1;
467 wordaddr[0] ^= (wordaddr[0] ^ (iret >> (start_offset*8))) & mask0;
468 if (end_offset <= 2*sizeof(__avrword)) {
469 /* sizeof(__avrword) < end_offset ≤ 2*sizeof(__avrword) */
470 __avrword mask1 = - ((__avrword)1 << (2*sizeof(__avrword)*8-end_offset*8));
471 wordaddr[1] ^= (wordaddr[1] ^ ((iret << (sizeof(__avrword)*4-start_offset*4) << (sizeof(__avrword)*4-start_offset*4)) | (iret2 >> (start_offset*8)))) & mask1;
472 } else {
473 /* 2*sizeof(__avrword) < end_offset < 3*sizeof(__avrword), start_offset > 0 */
474 __avrword mask2 = - ((__avrword)1 << (3*sizeof(__avrword)*8-end_offset*8));
475 wordaddr[1] = (iret << (sizeof(__avrword)*8-start_offset*8)) | (iret2 >> (start_offset*8));
476 wordaddr[2] ^= (wordaddr[2] ^ (iret2 << (sizeof(__avrword)*8-start_offset*8))) & mask2;
477 }
478 } else if (count <= 3*sizeof(__avrword)) {
479 /* Use iret, iret2, iret3. */
480 __avrword mask0 = ((__avrword)2 << (sizeof(__avrword)*8-start_offset*8-1)) - 1;
481 wordaddr[0] ^= (wordaddr[0] ^ (iret >> (start_offset*8))) & mask0;
482 if (end_offset <= 3*sizeof(__avrword)) {
483 /* 2*sizeof(__avrword) < end_offset ≤ 3*sizeof(__avrword) */
484 __avrword mask2 = - ((__avrword)1 << (3*sizeof(__avrword)*8-end_offset*8));
485 wordaddr[1] = (iret << (sizeof(__avrword)*4-start_offset*4) << (sizeof(__avrword)*4-start_offset*4)) | (iret2 >> (start_offset*8));
486 wordaddr[2] ^= (wordaddr[2] ^ ((iret2 << (sizeof(__avrword)*4-start_offset*4) << (sizeof(__avrword)*4-start_offset*4)) | (iret3 >> (start_offset*8)))) & mask2;
487 } else {
488 /* 3*sizeof(__avrword) < end_offset < 4*sizeof(__avrword), start_offset > 0 */
489 __avrword mask3 = - ((__avrword)1 << (4*sizeof(__avrword)*8-end_offset*8));
490 wordaddr[1] = (iret << (sizeof(__avrword)*8-start_offset*8)) | (iret2 >> (start_offset*8));
491 wordaddr[2] = (iret2 << (sizeof(__avrword)*8-start_offset*8)) | (iret3 >> (start_offset*8));
492 wordaddr[3] ^= (wordaddr[3] ^ (iret3 << (sizeof(__avrword)*8-start_offset*8))) & mask3;
493 }
494 } else {
495 /* Use iret, iret2, iret3, iret4. */
496 __avrword mask0 = ((__avrword)2 << (sizeof(__avrword)*8-start_offset*8-1)) - 1;
497 wordaddr[0] ^= (wordaddr[0] ^ (iret >> (start_offset*8))) & mask0;
498 if (end_offset <= 4*sizeof(__avrword)) {
499 /* 3*sizeof(__avrword) < end_offset ≤ 4*sizeof(__avrword) */
500 __avrword mask3 = - ((__avrword)1 << (4*sizeof(__avrword)*8-end_offset*8));
501 wordaddr[1] = (iret << (sizeof(__avrword)*4-start_offset*4) << (sizeof(__avrword)*4-start_offset*4)) | (iret2 >> (start_offset*8));
502 wordaddr[2] = (iret2 << (sizeof(__avrword)*4-start_offset*4) << (sizeof(__avrword)*4-start_offset*4)) | (iret3 >> (start_offset*8));
503 wordaddr[3] ^= (wordaddr[3] ^ ((iret3 << (sizeof(__avrword)*4-start_offset*4) << (sizeof(__avrword)*4-start_offset*4)) | (iret4 >> (start_offset*8)))) & mask3;
504 } else {
505 /* 4*sizeof(__avrword) < end_offset < 5*sizeof(__avrword), start_offset > 0 */
506 __avrword mask4 = - ((__avrword)1 << (5*sizeof(__avrword)*8-end_offset*8));
507 wordaddr[1] = (iret << (sizeof(__avrword)*8-start_offset*8)) | (iret2 >> (start_offset*8));
508 wordaddr[2] = (iret2 << (sizeof(__avrword)*8-start_offset*8)) | (iret3 >> (start_offset*8));
509 wordaddr[3] = (iret3 << (sizeof(__avrword)*8-start_offset*8)) | (iret4 >> (start_offset*8));
510 wordaddr[4] ^= (wordaddr[4] ^ (iret4 << (sizeof(__avrword)*8-start_offset*8))) & mask4;
511 }
512 }
513 #endif
514 }
515 }
516 }
517 return 0;
518 }
519