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 Foreign function interface for a Linux riscv32 with ILP32 ABI.
20
21 This calls a C function with an argument list built up using macros
22 defined in avcall.h.
23
24 RISC-V Argument Passing Conventions are documented in
25 https://people.eecs.berkeley.edu/~krste/papers/riscv-spec-v2.1.pdf
26 chapter 20.
27 ----------------------------------------------------------------------*/
28 #include "avcall-internal.h"
29
30 #define RETURN(TYPE,VAL) (*(TYPE*)l->raddr = (TYPE)(VAL))
31
32 register __avrword iarg1 __asm__("a0");
33 register __avrword iarg2 __asm__("a1");
34 register __avrword iarg3 __asm__("a2");
35 register __avrword iarg4 __asm__("a3");
36 register __avrword iarg5 __asm__("a4");
37 register __avrword iarg6 __asm__("a5");
38 register __avrword iarg7 __asm__("a6");
39 register __avrword iarg8 __asm__("a7");
40
41 register float farg1 __asm__("fa0");
42 register float farg2 __asm__("fa1");
43 register float farg3 __asm__("fa2");
44 register float farg4 __asm__("fa3");
45 register float farg5 __asm__("fa4");
46 register float farg6 __asm__("fa5");
47 register float farg7 __asm__("fa6");
48 register float farg8 __asm__("fa7");
49
50 register double darg1 __asm__("fa0");
51 register double darg2 __asm__("fa1");
52 register double darg3 __asm__("fa2");
53 register double darg4 __asm__("fa3");
54 register double darg5 __asm__("fa4");
55 register double darg6 __asm__("fa5");
56 register double darg7 __asm__("fa6");
57 register double darg8 __asm__("fa7");
58
59 int
avcall_call(av_alist * list)60 avcall_call(av_alist* list)
61 {
62 register __avrword iretreg __asm__("a0");
63 register __avrword iret2reg __asm__("a1");
64 register double dret __asm__("fa0");
65
66 __av_alist* l = &AV_LIST_INNER(list);
67
68 __avword* argframe = __builtin_alloca(__AV_ALIST_WORDS * sizeof(__avword)); /* make room for argument list */
69 int arglen = l->aptr - l->args;
70 unsigned int fanum = l->fanum;
71
72 {
73 int i;
74 for (i = 8; i < arglen; i++) /* push function args onto stack */
75 argframe[i-8] = l->args[i];
76 }
77
78 /* Put up to 8 integer args into registers. */
79 if (arglen >= 1) {
80 iarg1 = l->args[0];
81 if (arglen >= 2) {
82 iarg2 = l->args[1];
83 if (arglen >= 3) {
84 iarg3 = l->args[2];
85 if (arglen >= 4) {
86 iarg4 = l->args[3];
87 if (arglen >= 5) {
88 iarg5 = l->args[4];
89 if (arglen >= 6) {
90 iarg6 = l->args[5];
91 if (arglen >= 7) {
92 iarg7 = l->args[6];
93 if (arglen >= 8) {
94 iarg8 = l->args[7];
95 }
96 }
97 }
98 }
99 }
100 }
101 }
102 }
103
104 /* Put upto 8 floating-point args into registers. */
105 if (fanum >= 1) {
106 if (l->darg_mask & (1 << 0)) darg1 = l->dargs[0];
107 else if (l->farg_mask & (1 << 0)) farg1 = l->fargs[0];
108 if (fanum >= 2) {
109 if (l->darg_mask & (1 << 1)) darg2 = l->dargs[1];
110 else if (l->farg_mask & (1 << 1)) farg2 = l->fargs[1];
111 if (fanum >= 3) {
112 if (l->darg_mask & (1 << 2)) darg3 = l->dargs[2];
113 else if (l->farg_mask & (1 << 2)) farg3 = l->fargs[2];
114 if (fanum >= 4) {
115 if (l->darg_mask & (1 << 3)) darg4 = l->dargs[3];
116 else if (l->farg_mask & (1 << 3)) farg4 = l->fargs[3];
117 if (fanum >= 5) {
118 if (l->darg_mask & (1 << 4)) darg5 = l->dargs[4];
119 else if (l->farg_mask & (1 << 4)) farg5 = l->fargs[4];
120 if (fanum >= 6) {
121 if (l->darg_mask & (1 << 5)) darg6 = l->dargs[5];
122 else if (l->farg_mask & (1 << 5)) farg6 = l->fargs[5];
123 if (fanum >= 7) {
124 if (l->darg_mask & (1 << 6)) darg7 = l->dargs[6];
125 else if (l->farg_mask & (1 << 6)) farg7 = l->fargs[6];
126 if (fanum >= 8) {
127 if (l->darg_mask & (1 << 7)) darg8 = l->dargs[7];
128 else if (l->farg_mask & (1 << 7)) farg8 = l->fargs[7];
129 }
130 }
131 }
132 }
133 }
134 }
135 }
136 }
137
138 /* Call function. */
139 if (l->rtype == __AVfloat) {
140 *(float*)l->raddr = (*(float(*)())l->func)();
141 } else
142 if (l->rtype == __AVdouble) {
143 *(double*)l->raddr = (*(double(*)())l->func)();
144 } else {
145 __avrword iret, iret2;
146
147 iret = (*l->func)();
148 iret2 = iret2reg;
149
150 /* save return value */
151 if (l->rtype == __AVvoid) {
152 } else
153 if (l->rtype == __AVchar) {
154 RETURN(char, iret);
155 } else
156 if (l->rtype == __AVschar) {
157 RETURN(signed char, iret);
158 } else
159 if (l->rtype == __AVuchar) {
160 RETURN(unsigned char, iret);
161 } else
162 if (l->rtype == __AVshort) {
163 RETURN(short, iret);
164 } else
165 if (l->rtype == __AVushort) {
166 RETURN(unsigned short, iret);
167 } else
168 if (l->rtype == __AVint) {
169 RETURN(int, iret);
170 } else
171 if (l->rtype == __AVuint) {
172 RETURN(unsigned int, iret);
173 } else
174 if (l->rtype == __AVlong) {
175 RETURN(long, iret);
176 } else
177 if (l->rtype == __AVulong) {
178 RETURN(unsigned long, iret);
179 } else
180 if (l->rtype == __AVlonglong || l->rtype == __AVulonglong) {
181 void* raddr = l->raddr;
182 ((__avrword*)raddr)[0] = iret;
183 ((__avrword*)raddr)[1] = iret2;
184 } else
185 /* see above
186 if (l->rtype == __AVfloat) {
187 } else
188 if (l->rtype == __AVdouble) {
189 } else
190 */
191 if (l->rtype == __AVvoidp) {
192 RETURN(void*, iret);
193 } else
194 if (l->rtype == __AVstruct) {
195 if (l->flags & __AV_SMALL_STRUCT_RETURN) {
196 /* Return structs of size <= 8 in registers. */
197 if (l->rsize > 0 && l->rsize <= 8) {
198 void* raddr = l->raddr;
199 #if 0 /* Unoptimized */
200 if (l->rsize == 1) {
201 ((unsigned char *)raddr)[0] = (unsigned char)(iret);
202 } else
203 if (l->rsize == 2) {
204 ((unsigned char *)raddr)[0] = (unsigned char)(iret);
205 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
206 } else
207 if (l->rsize == 3) {
208 ((unsigned char *)raddr)[0] = (unsigned char)(iret);
209 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
210 ((unsigned char *)raddr)[2] = (unsigned char)(iret>>16);
211 } else
212 if (l->rsize >= 4 && l->rsize <= 8) {
213 ((unsigned char *)raddr)[0] = (unsigned char)(iret);
214 ((unsigned char *)raddr)[1] = (unsigned char)(iret>>8);
215 ((unsigned char *)raddr)[2] = (unsigned char)(iret>>16);
216 ((unsigned char *)raddr)[3] = (unsigned char)(iret>>24);
217 if (l->rsize == 4) {
218 } else
219 if (l->rsize == 5) {
220 ((unsigned char *)raddr)[4+0] = (unsigned char)(iret2);
221 } else
222 if (l->rsize == 6) {
223 ((unsigned char *)raddr)[4+0] = (unsigned char)(iret2);
224 ((unsigned char *)raddr)[4+1] = (unsigned char)(iret2>>8);
225 } else
226 if (l->rsize == 7) {
227 ((unsigned char *)raddr)[4+0] = (unsigned char)(iret2);
228 ((unsigned char *)raddr)[4+1] = (unsigned char)(iret2>>8);
229 ((unsigned char *)raddr)[4+2] = (unsigned char)(iret2>>16);
230 } else
231 if (l->rsize == 8) {
232 ((unsigned char *)raddr)[4+0] = (unsigned char)(iret2);
233 ((unsigned char *)raddr)[4+1] = (unsigned char)(iret2>>8);
234 ((unsigned char *)raddr)[4+2] = (unsigned char)(iret2>>16);
235 ((unsigned char *)raddr)[4+3] = (unsigned char)(iret2>>24);
236 }
237 }
238 #else /* Optimized: fewer conditional jumps, fewer memory accesses */
239 uintptr_t count = l->rsize; /* > 0, ≤ 2*sizeof(__avrword) */
240 __avrword* wordaddr = (__avrword*)((uintptr_t)raddr & ~(uintptr_t)(sizeof(__avrword)-1));
241 uintptr_t start_offset = (uintptr_t)raddr & (uintptr_t)(sizeof(__avrword)-1); /* ≥ 0, < sizeof(__avrword) */
242 uintptr_t end_offset = start_offset + count; /* > 0, < 3*sizeof(__avrword) */
243 if (count <= sizeof(__avrword)) {
244 /* Use iret. */
245 if (end_offset <= sizeof(__avrword)) {
246 /* 0 < end_offset ≤ sizeof(__avrword) */
247 __avrword mask0 = ((__avrword)2 << (end_offset*8-1)) - ((__avrword)1 << (start_offset*8));
248 wordaddr[0] ^= (wordaddr[0] ^ (iret << (start_offset*8))) & mask0;
249 } else {
250 /* sizeof(__avrword) < end_offset < 2*sizeof(__avrword), start_offset > 0 */
251 __avrword mask0 = - ((__avrword)1 << (start_offset*8));
252 __avrword mask1 = ((__avrword)2 << (end_offset*8-sizeof(__avrword)*8-1)) - 1;
253 wordaddr[0] ^= (wordaddr[0] ^ (iret << (start_offset*8))) & mask0;
254 wordaddr[1] ^= (wordaddr[1] ^ (iret >> (sizeof(__avrword)*8-start_offset*8))) & mask1;
255 }
256 } else {
257 /* Use iret, iret2. */
258 __avrword mask0 = - ((__avrword)1 << (start_offset*8));
259 wordaddr[0] ^= (wordaddr[0] ^ (iret << (start_offset*8))) & mask0;
260 if (end_offset <= 2*sizeof(__avrword)) {
261 /* sizeof(__avrword) < end_offset ≤ 2*sizeof(__avrword) */
262 __avrword mask1 = ((__avrword)2 << (end_offset*8-sizeof(__avrword)*8-1)) - 1;
263 wordaddr[1] ^= (wordaddr[1] ^ ((iret >> (sizeof(__avrword)*4-start_offset*4) >> (sizeof(__avrword)*4-start_offset*4)) | (iret2 << (start_offset*8)))) & mask1;
264 } else {
265 /* 2*sizeof(__avrword) < end_offset < 3*sizeof(__avrword), start_offset > 0 */
266 __avrword mask2 = ((__avrword)2 << (end_offset*8-2*sizeof(__avrword)*8-1)) - 1;
267 wordaddr[1] = (iret >> (sizeof(__avrword)*8-start_offset*8)) | (iret2 << (start_offset*8));
268 wordaddr[2] ^= (wordaddr[2] ^ (iret2 >> (sizeof(__avrword)*8-start_offset*8))) & mask2;
269 }
270 }
271 #endif
272 }
273 }
274 }
275 }
276 return 0;
277 }
278