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