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