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 an SGI 64-bit MIPS with sgi-cc.
22 
23   This calls a C function with an argument list built up using macros
24   defined in avcall.h.
25 
26   SGI MIPS 64-bit Argument Passing Conventions
27 
28   - The entire argument list forms a structure with all the appropriate
29     holes & alignments, and space for this is allocated in the stack frame.
30   - Shorter integers are promoted to longword length (sizeof(long)=8).
31   - Doubles are 1 longword.
32   - Structure arguments are copies embedded in the arglist structure.
33   - The first 8 longwords of the structure are passed in registers $4...$11,
34     except that float arguments are passed in registers $f12...$f19, and
35     that double arguments and structure elements of type double are passed
36     in registers $f12...$f19. (But varargs functions may expect them in the
37     integer registers and we can't tell whether the function is varargs so
38     we pass them both ways.)
39     Remaining longwords are passed on the stack. No stack space is allocated
40     for the first 8 longwords of the structure.
41   - Structure returns of structures > 16 bytes: pointers to caller-allocated
42     space are passed in as the first argument of the list.
43   - Structure returns of structures <= 16 bytes: in the registers $2 (for the
44     first 8 bytes) and $3 (for the next 8 bytes).
45     A structure of 1 or 2 floats or doubles is returned in $f0 and $f2:
46     the first float or double in $f0, the second float or double in $f2.
47   - Integer/pointer returns are in $2, float/double returns in $f0.
48   - The called function expects to see its own address in $25.
49 
50   This file needs to be compiled with gcc for the asm extensions, but the
51   assembly version of it and the header file seem to work with SGI cc.
52   ----------------------------------------------------------------------*/
53 #include "avcall-internal.h"
54 
55 #define RETURN(TYPE,VAL)	(*(TYPE*)l->raddr = (TYPE)(VAL))
56 #define OFFSETOF(struct,member) ((int)&(((struct*)0)->member))
57 
58 int
avcall_call(av_alist * list)59 avcall_call(av_alist* list)
60 {
61   register __avword*	sp	__asm__("$sp");  /* C names for registers */
62   register float	fret	__asm__("$f0");
63   register double	dret	__asm__("$f0");
64 /*register __avrword	iret1	__asm__("$2"); */
65   register __avrword	iret2	__asm__("$3");
66 
67   __av_alist* l = &AV_LIST_INNER(list);
68 
69   __avword* argframe = __builtin_alloca(__AV_ALIST_WORDS * sizeof(__avword)); /* make room for argument list */
70   int arglen = l->aptr - l->args;
71   __avrword iret;
72   int i;
73 
74   if (l->farg_mask)
75     { /* push leading float args */
76       if (l->farg_mask & (1<<0))
77         __asm__("lwc1 $f12,%1(%0)" : : "p" (l), "i" OFFSETOF(__av_alist,fargs[0]));
78       if (l->farg_mask & (1<<1))
79         __asm__("lwc1 $f13,%1(%0)" : : "p" (l), "i" OFFSETOF(__av_alist,fargs[1]));
80       if (l->farg_mask & (1<<2))
81         __asm__("lwc1 $f14,%1(%0)" : : "p" (l), "i" OFFSETOF(__av_alist,fargs[2]));
82       if (l->farg_mask & (1<<3))
83         __asm__("lwc1 $f15,%1(%0)" : : "p" (l), "i" OFFSETOF(__av_alist,fargs[3]));
84       if (l->farg_mask & (1<<4))
85         __asm__("lwc1 $f16,%1(%0)" : : "p" (l), "i" OFFSETOF(__av_alist,fargs[4]));
86       if (l->farg_mask & (1<<5))
87         __asm__("lwc1 $f17,%1(%0)" : : "p" (l), "i" OFFSETOF(__av_alist,fargs[5]));
88       if (l->farg_mask & (1<<6))
89         __asm__("lwc1 $f18,%1(%0)" : : "p" (l), "i" OFFSETOF(__av_alist,fargs[6]));
90       if (l->farg_mask & (1<<7))
91         __asm__("lwc1 $f19,%1(%0)" : : "p" (l), "i" OFFSETOF(__av_alist,fargs[7]));
92     }
93   if (l->darg_mask)
94     { /* push leading double args */
95       __avword* a = l->args;
96       if (l->darg_mask & (1<<0))
97         __asm__("ldc1 $f12,%1(%0)" : : "p" (a), "i" (0 * sizeof (__avword)));
98       if (l->darg_mask & (1<<1))
99         __asm__("ldc1 $f13,%1(%0)" : : "p" (a), "i" (1 * sizeof (__avword)));
100       if (l->darg_mask & (1<<2))
101         __asm__("ldc1 $f14,%1(%0)" : : "p" (a), "i" (2 * sizeof (__avword)));
102       if (l->darg_mask & (1<<3))
103         __asm__("ldc1 $f15,%1(%0)" : : "p" (a), "i" (3 * sizeof (__avword)));
104       if (l->darg_mask & (1<<4))
105         __asm__("ldc1 $f16,%1(%0)" : : "p" (a), "i" (4 * sizeof (__avword)));
106       if (l->darg_mask & (1<<5))
107         __asm__("ldc1 $f17,%1(%0)" : : "p" (a), "i" (5 * sizeof (__avword)));
108       if (l->darg_mask & (1<<6))
109         __asm__("ldc1 $f18,%1(%0)" : : "p" (a), "i" (6 * sizeof (__avword)));
110       if (l->darg_mask & (1<<7))
111         __asm__("ldc1 $f19,%1(%0)" : : "p" (a), "i" (7 * sizeof (__avword)));
112     }
113 
114   for (i = 8; i < arglen; i++)		/* push excess function args */
115     argframe[i-8] = l->args[i];
116 
117 					/* call function with 1st 8 args */
118   __asm__ __volatile__ ("ld $4,%0" : : "m" (l->args[0]) : "$4"); /* arg1 = l->args[0]; */
119   __asm__ __volatile__ ("ld $5,%0" : : "m" (l->args[1]) : "$5"); /* arg1 = l->args[1]; */
120   __asm__ __volatile__ ("ld $6,%0" : : "m" (l->args[2]) : "$6"); /* arg1 = l->args[2]; */
121   __asm__ __volatile__ ("ld $7,%0" : : "m" (l->args[3]) : "$7"); /* arg1 = l->args[3]; */
122   __asm__ __volatile__ ("ld $8,%0" : : "m" (l->args[4]) : "$8"); /* arg1 = l->args[4]; */
123   __asm__ __volatile__ ("ld $9,%0" : : "m" (l->args[5]) : "$9"); /* arg1 = l->args[5]; */
124   __asm__ __volatile__ ("ld $10,%0" : : "m" (l->args[6]) : "$10"); /* arg1 = l->args[6]; */
125   __asm__ __volatile__ ("ld $11,%0" : : "m" (l->args[7]) : "$11"); /* arg1 = l->args[7]; */
126   /* Note: The code of this call ought to put the address of the called function
127      in register $25 before the call.  */
128   iret = (*l->func)();
129 
130   /* save return value */
131   if (l->rtype == __AVvoid) {
132   } else
133   if (l->rtype == __AVchar) {
134     RETURN(char, iret);
135   } else
136   if (l->rtype == __AVschar) {
137     RETURN(signed char, iret);
138   } else
139   if (l->rtype == __AVuchar) {
140     RETURN(unsigned char, iret);
141   } else
142   if (l->rtype == __AVshort) {
143     RETURN(short, iret);
144   } else
145   if (l->rtype == __AVushort) {
146     RETURN(unsigned short, iret);
147   } else
148   if (l->rtype == __AVint) {
149     RETURN(int, iret);
150   } else
151   if (l->rtype == __AVuint) {
152     RETURN(unsigned int, iret);
153   } else
154   if (l->rtype == __AVlong) {
155     RETURN(long, iret);
156   } else
157   if (l->rtype == __AVulong) {
158     RETURN(unsigned long, iret);
159   } else
160   if (l->rtype == __AVlonglong) {
161     RETURN(long long, iret);
162   } else
163   if (l->rtype == __AVulonglong) {
164     RETURN(unsigned long long, iret);
165   } else
166   if (l->rtype == __AVfloat) {
167     RETURN(float, fret);
168   } else
169   if (l->rtype == __AVdouble) {
170     RETURN(double, dret);
171   } else
172   if (l->rtype == __AVvoidp) {
173     RETURN(void*, iret);
174   } else
175   if (l->rtype == __AVstruct) {
176     if (l->flags & __AV_REGISTER_STRUCT_RETURN) {
177       if (l->flags & __AV_GCC_STRUCT_RETURN) {
178         /* gcc returns structs of size 1,2,4,8 in registers. */
179         if (l->rsize == sizeof(char)) {
180           RETURN(char, iret);
181         } else
182         if (l->rsize == sizeof(short)) {
183           RETURN(short, iret);
184         } else
185         if (l->rsize == sizeof(int)) {
186           RETURN(int, iret);
187         } else
188         if (l->rsize == sizeof(long)) {
189           RETURN(long, iret);
190         }
191       } else {
192         /* cc returns structs of size <= 16 in registers. */
193         if (l->rsize > 0 && l->rsize <= 16) {
194           void* raddr = l->raddr;
195           #if 0 /* Unoptimized */
196           if (l->rsize == 1) {
197             #if defined(_MIPSEL)
198             ((unsigned char *)raddr)[0] = (unsigned char)(iret);
199             #else
200             ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
201             #endif
202           } else
203           if (l->rsize == 2) {
204             #if defined(_MIPSEL)
205             ((unsigned char *)raddr)[0] = (unsigned char)(iret);
206             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
207             #else
208             ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
209             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
210             #endif
211           } else
212           if (l->rsize == 3) {
213             #if defined(_MIPSEL)
214             ((unsigned char *)raddr)[0] = (unsigned char)(iret);
215             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
216             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>16);
217             #else
218             ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
219             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
220             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
221             #endif
222           } else
223           if (l->rsize == 4) {
224             #if defined(_MIPSEL)
225             ((unsigned char *)raddr)[0] = (unsigned char)(iret);
226             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
227             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>16);
228             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>24);
229             #else
230             ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
231             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
232             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
233             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
234             #endif
235           } else
236           if (l->rsize == 5) {
237             #if defined(_MIPSEL)
238             ((unsigned char *)raddr)[0] = (unsigned char)(iret);
239             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
240             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>16);
241             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>24);
242             ((unsigned char *)raddr)[4] = (unsigned char)(iret>>32);
243             #else
244             ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
245             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
246             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
247             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
248             ((unsigned char *)raddr)[4] = (unsigned char)(iret>>24);
249             #endif
250           } else
251           if (l->rsize == 6) {
252             #if defined(_MIPSEL)
253             ((unsigned char *)raddr)[0] = (unsigned char)(iret);
254             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
255             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>16);
256             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>24);
257             ((unsigned char *)raddr)[4] = (unsigned char)(iret>>32);
258             ((unsigned char *)raddr)[5] = (unsigned char)(iret>>40);
259             #else
260             ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
261             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
262             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
263             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
264             ((unsigned char *)raddr)[4] = (unsigned char)(iret>>24);
265             ((unsigned char *)raddr)[5] = (unsigned char)(iret>>16);
266             #endif
267           } else
268           if (l->rsize == 7) {
269             #if defined(_MIPSEL)
270             ((unsigned char *)raddr)[0] = (unsigned char)(iret);
271             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
272             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>16);
273             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>24);
274             ((unsigned char *)raddr)[4] = (unsigned char)(iret>>32);
275             ((unsigned char *)raddr)[5] = (unsigned char)(iret>>40);
276             ((unsigned char *)raddr)[6] = (unsigned char)(iret>>48);
277             #else
278             ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
279             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
280             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
281             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
282             ((unsigned char *)raddr)[4] = (unsigned char)(iret>>24);
283             ((unsigned char *)raddr)[5] = (unsigned char)(iret>>16);
284             ((unsigned char *)raddr)[6] = (unsigned char)(iret>>8);
285             #endif
286           } else
287           if (l->rsize >= 8 && l->rsize <= 16) {
288             #if defined(_MIPSEL)
289             ((unsigned char *)raddr)[0] = (unsigned char)(iret);
290             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
291             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>16);
292             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>24);
293             ((unsigned char *)raddr)[4] = (unsigned char)(iret>>32);
294             ((unsigned char *)raddr)[5] = (unsigned char)(iret>>40);
295             ((unsigned char *)raddr)[6] = (unsigned char)(iret>>48);
296             ((unsigned char *)raddr)[7] = (unsigned char)(iret>>56);
297             #else
298             ((unsigned char *)raddr)[0] = (unsigned char)(iret>>56);
299             ((unsigned char *)raddr)[1] = (unsigned char)(iret>>48);
300             ((unsigned char *)raddr)[2] = (unsigned char)(iret>>40);
301             ((unsigned char *)raddr)[3] = (unsigned char)(iret>>32);
302             ((unsigned char *)raddr)[4] = (unsigned char)(iret>>24);
303             ((unsigned char *)raddr)[5] = (unsigned char)(iret>>16);
304             ((unsigned char *)raddr)[6] = (unsigned char)(iret>>8);
305             ((unsigned char *)raddr)[7] = (unsigned char)(iret);
306             #endif
307             if (l->rsize == 8) {
308             } else
309             if (l->rsize == 9) {
310               #if defined(_MIPSEL)
311               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2);
312               #else
313               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
314               #endif
315             } else
316             if (l->rsize == 10) {
317               #if defined(_MIPSEL)
318               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2);
319               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>8);
320               #else
321               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
322               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
323               #endif
324             } else
325             if (l->rsize == 11) {
326               #if defined(_MIPSEL)
327               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2);
328               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>8);
329               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>16);
330               #else
331               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
332               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
333               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
334               #endif
335             } else
336             if (l->rsize == 12) {
337               #if defined(_MIPSEL)
338               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2);
339               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>8);
340               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>16);
341               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>24);
342               #else
343               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
344               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
345               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
346               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
347               #endif
348             } else
349             if (l->rsize == 13) {
350               #if defined(_MIPSEL)
351               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2);
352               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>8);
353               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>16);
354               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>24);
355               ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>32);
356               #else
357               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
358               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
359               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
360               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
361               ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>24);
362               #endif
363             } else
364             if (l->rsize == 14) {
365               #if defined(_MIPSEL)
366               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2);
367               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>8);
368               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>16);
369               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>24);
370               ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>32);
371               ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>40);
372               #else
373               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
374               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
375               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
376               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
377               ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>24);
378               ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>16);
379               #endif
380             } else
381             if (l->rsize == 15) {
382               #if defined(_MIPSEL)
383               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2);
384               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>8);
385               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>16);
386               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>24);
387               ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>32);
388               ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>40);
389               ((unsigned char *)raddr)[8+6] = (unsigned char)(iret2>>48);
390               #else
391               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
392               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
393               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
394               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
395               ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>24);
396               ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>16);
397               ((unsigned char *)raddr)[8+6] = (unsigned char)(iret2>>8);
398               #endif
399             } else
400             if (l->rsize == 16) {
401               #if defined(_MIPSEL)
402               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2);
403               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>8);
404               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>16);
405               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>24);
406               ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>32);
407               ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>40);
408               ((unsigned char *)raddr)[8+6] = (unsigned char)(iret2>>48);
409               ((unsigned char *)raddr)[8+7] = (unsigned char)(iret2>>56);
410               #else
411               ((unsigned char *)raddr)[8+0] = (unsigned char)(iret2>>56);
412               ((unsigned char *)raddr)[8+1] = (unsigned char)(iret2>>48);
413               ((unsigned char *)raddr)[8+2] = (unsigned char)(iret2>>40);
414               ((unsigned char *)raddr)[8+3] = (unsigned char)(iret2>>32);
415               ((unsigned char *)raddr)[8+4] = (unsigned char)(iret2>>24);
416               ((unsigned char *)raddr)[8+5] = (unsigned char)(iret2>>16);
417               ((unsigned char *)raddr)[8+6] = (unsigned char)(iret2>>8);
418               ((unsigned char *)raddr)[8+7] = (unsigned char)(iret2);
419               #endif
420             }
421           }
422           #else /* Optimized: fewer conditional jumps, fewer memory accesses */
423           uintptr_t count = l->rsize; /* > 0, ≤ 2*sizeof(__avrword) */
424           __avrword* wordaddr = (__avrword*)((uintptr_t)raddr & ~(uintptr_t)(sizeof(__avrword)-1));
425           uintptr_t start_offset = (uintptr_t)raddr & (uintptr_t)(sizeof(__avrword)-1); /* ≥ 0, < sizeof(__avrword) */
426           uintptr_t end_offset = start_offset + count; /* > 0, < 3*sizeof(__avrword) */
427           #if defined(_MIPSEL)
428           if (count <= sizeof(__avrword)) {
429             /* Use iret. */
430             if (end_offset <= sizeof(__avrword)) {
431               /* 0 < end_offset ≤ sizeof(__avrword) */
432               __avrword mask0 = ((__avrword)2 << (end_offset*8-1)) - ((__avrword)1 << (start_offset*8));
433               wordaddr[0] ^= (wordaddr[0] ^ (iret << (start_offset*8))) & mask0;
434             } else {
435               /* sizeof(__avrword) < end_offset < 2*sizeof(__avrword), start_offset > 0 */
436               __avrword mask0 = - ((__avrword)1 << (start_offset*8));
437               __avrword mask1 = ((__avrword)2 << (end_offset*8-sizeof(__avrword)*8-1)) - 1;
438               wordaddr[0] ^= (wordaddr[0] ^ (iret << (start_offset*8))) & mask0;
439               wordaddr[1] ^= (wordaddr[1] ^ (iret >> (sizeof(__avrword)*8-start_offset*8))) & mask1;
440             }
441           } else {
442             /* Use iret, iret2. */
443             __avrword mask0 = - ((__avrword)1 << (start_offset*8));
444             wordaddr[0] ^= (wordaddr[0] ^ (iret << (start_offset*8))) & mask0;
445             if (end_offset <= 2*sizeof(__avrword)) {
446               /* sizeof(__avrword) < end_offset ≤ 2*sizeof(__avrword) */
447               __avrword mask1 = ((__avrword)2 << (end_offset*8-sizeof(__avrword)*8-1)) - 1;
448               wordaddr[1] ^= (wordaddr[1] ^ ((iret >> (sizeof(__avrword)*4-start_offset*4) >> (sizeof(__avrword)*4-start_offset*4)) | (iret2 << (start_offset*8)))) & mask1;
449             } else {
450               /* 2*sizeof(__avrword) < end_offset < 3*sizeof(__avrword), start_offset > 0 */
451               __avrword mask2 = ((__avrword)2 << (end_offset*8-2*sizeof(__avrword)*8-1)) - 1;
452               wordaddr[1] = (iret >> (sizeof(__avrword)*8-start_offset*8)) | (iret2 << (start_offset*8));
453               wordaddr[2] ^= (wordaddr[2] ^ (iret2 >> (sizeof(__avrword)*8-start_offset*8))) & mask2;
454             }
455           }
456           #else
457           if (count <= sizeof(__avrword)) {
458             /* Use iret. */
459             if (end_offset <= sizeof(__avrword)) {
460               /* 0 < end_offset ≤ sizeof(__avrword) */
461               __avrword mask0 = ((__avrword)2 << (sizeof(__avrword)*8-start_offset*8-1)) - ((__avrword)1 << (sizeof(__avrword)*8-end_offset*8));
462               wordaddr[0] ^= (wordaddr[0] ^ (iret >> (start_offset*8))) & mask0;
463             } else {
464               /* sizeof(__avrword) < end_offset < 2*sizeof(__avrword), start_offset > 0 */
465               __avrword mask0 = ((__avrword)2 << (sizeof(__avrword)*8-start_offset*8-1)) - 1;
466               __avrword mask1 = - ((__avrword)1 << (2*sizeof(__avrword)*8-end_offset*8));
467               wordaddr[0] ^= (wordaddr[0] ^ (iret >> (start_offset*8))) & mask0;
468               wordaddr[1] ^= (wordaddr[1] ^ (iret << (sizeof(__avrword)*8-start_offset*8))) & mask1;
469             }
470           } else {
471             /* Use iret, iret2. */
472             __avrword mask0 = ((__avrword)2 << (sizeof(__avrword)*8-start_offset*8-1)) - 1;
473             wordaddr[0] ^= (wordaddr[0] ^ (iret >> (start_offset*8))) & mask0;
474             if (end_offset <= 2*sizeof(__avrword)) {
475               /* sizeof(__avrword) < end_offset ≤ 2*sizeof(__avrword) */
476               __avrword mask1 = - ((__avrword)1 << (2*sizeof(__avrword)*8-end_offset*8));
477               wordaddr[1] ^= (wordaddr[1] ^ ((iret << (sizeof(__avrword)*4-start_offset*4) << (sizeof(__avrword)*4-start_offset*4)) | (iret2 >> (start_offset*8)))) & mask1;
478             } else {
479               /* 2*sizeof(__avrword) < end_offset < 3*sizeof(__avrword), start_offset > 0 */
480               __avrword mask2 = - ((__avrword)1 << (3*sizeof(__avrword)*8-end_offset*8));
481               wordaddr[1] = (iret << (sizeof(__avrword)*8-start_offset*8)) | (iret2 >> (start_offset*8));
482               wordaddr[2] ^= (wordaddr[2] ^ (iret2 << (sizeof(__avrword)*8-start_offset*8))) & mask2;
483             }
484           }
485           #endif
486           #endif
487         }
488       }
489     }
490   }
491   return 0;
492 }
493