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