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