Added some missing vim modelines.
[cacao.git] / src / vm / jit / arm / md-abi.c
1 /* src/vm/jit/arm/md-abi.c - functions for arm ABI
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27 #include "vm/types.h"
28
29 #include "vm/jit/arm/md-abi.h"
30
31 #include "vm/descriptor.hpp"
32 #include "vm/global.h"
33
34 #include "vm/jit/abi.h"
35
36
37 /* register descripton array **************************************************/
38
39 s4 nregdescint[] = {
40         REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
41         REG_SAV, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
42         REG_END
43 };
44
45 const char *abi_registers_integer_name[] = {
46         "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4",
47         "v5", "t3", "t1", "t2", "ip", "sp", "lr", "pc",
48 };
49
50 const s4 abi_registers_integer_argument[] = {
51         0,  /* a0 */
52         1,  /* a1 */
53         2,  /* a2 */
54         3,  /* a3 */
55         REG_SPLIT,
56 };
57
58 const s4 abi_registers_integer_saved[] = {
59         4,  /* s0 */
60         5,  /* s1 */
61         6,  /* s2 */
62         7,  /* s3 */
63         8,  /* s4 */
64 };
65
66 const s4 abi_registers_integer_temporary[] = {
67         -1,
68 };
69
70
71 #if defined(ENABLE_SOFTFLOAT)
72 s4 nregdescfloat[] = {
73         REG_RES, REG_RES, REG_RES, REG_RES,
74         REG_RES, REG_RES, REG_RES, REG_RES,
75         REG_END
76 };
77 #else
78 /* TODO: FPA register usage conventions */
79 s4 nregdescfloat[] = {
80         REG_TMP, REG_TMP, REG_TMP, REG_TMP,
81         REG_TMP, REG_TMP, REG_RES, REG_RES,
82         REG_END
83 };
84 #endif /* defined(ENABLE_SOFTFLOAT) */
85
86 const s4 abi_registers_float_argument[] = {
87         -1,
88 };
89
90 const s4 abi_registers_float_saved[] = {
91         -1,
92 };
93
94 const s4 abi_registers_float_temporary[] = {
95 #if defined(ENABLE_SOFTFLOAT)
96         -1,
97 #else
98         0,  /* ft0 */
99         1,  /* ft1 */
100         2,  /* ft2 */
101         3,  /* ft3 */
102         4,  /* ft4 */
103         5,  /* ft5 */
104 #endif
105 };
106
107
108 /* md_param_alloc **************************************************************
109
110    Allocate Arguments to Stackslots according the Calling Conventions
111
112    --- in:
113    md->paramcount:           Number of arguments for this method
114    md->paramtypes[].type:    Argument types
115
116    --- out:
117    md->params[].inmemory:    Argument spilled on stack
118    md->params[].regoff:      Stack offset or rd->arg[int|flt]regs index
119    md->memuse:               Stackslots needed for argument spilling
120    md->argintreguse:         max number of integer arguments used
121    md->argfltreguse:         max number of float arguments used
122
123 *******************************************************************************/
124
125 void md_param_alloc(methoddesc *md)
126 {
127         paramdesc *pd;
128         s4         i;
129         s4         reguse;
130         s4         stacksize;
131
132         /* set default values */
133
134         reguse    = 0;
135         stacksize = 0;
136
137         /* get params field of methoddesc */
138
139         pd = md->params;
140
141         for (i = 0; i < md->paramcount; i++, pd++) {
142                 switch (md->paramtypes[i].type) {
143                 case TYPE_INT:
144                 case TYPE_ADR:
145                 case TYPE_FLT:
146                         if (reguse < INT_ARG_CNT) {
147                                 pd->inmemory = false;
148                                 pd->index    = reguse;
149                                 pd->regoff   = abi_registers_integer_argument[reguse];
150                                 reguse++;
151                         }
152                         else {
153                                 pd->inmemory = true;
154                                 pd->index    = stacksize;
155                                 pd->regoff   = stacksize * 8;
156                                 stacksize++;
157                         }
158                         break;
159
160                 case TYPE_LNG:
161                 case TYPE_DBL:
162                         /* interally we use the EABI */
163
164                         ALIGN_2(reguse);
165
166                         if (reguse < INT_ARG_CNT) {
167                                 pd->inmemory = false;
168 #if defined(__ARMEL__)
169                                 pd->index    = PACK_REGS(reguse, reguse + 1);
170                                 pd->regoff   =
171                                         PACK_REGS(abi_registers_integer_argument[reguse],
172                                                           abi_registers_integer_argument[reguse + 1]);
173 #else
174                                 pd->index    = PACK_REGS(reguse + 1, reguse);
175                                 pd->regoff   =
176                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
177                                                           abi_registers_integer_argument[reguse]);
178 #endif
179                                 reguse += 2;
180                         }
181                         else {
182
183                                 /*ALIGN_2(stacksize);*/
184
185                                 pd->inmemory  = true;
186                                 pd->index     = stacksize;
187                                 pd->regoff    = stacksize * 8;
188                                 /*stacksize    += 2;*/
189                                 stacksize++;
190                         }
191                         break;
192                 }
193         }
194
195         /* Since R0/R1 (==A0/A1) are used for passing return values, this
196            argument register usage has to be regarded, too. */
197
198         if (md->returntype.type != TYPE_VOID) {
199                 if (!IS_2_WORD_TYPE(md->returntype.type)) {
200                         if (reguse < 1)
201                                 reguse = 1;
202                 }
203                 else {
204                         if (reguse < 2)
205                                 reguse = 2;
206                 }
207         }
208
209         /* fill register and stack usage */
210
211         md->argintreguse = reguse;
212         md->argfltreguse = 0;
213         md->memuse       = stacksize;
214 }
215
216
217 /* md_param_alloc_native *******************************************************
218
219    Pre-allocate arguments according the native ABI.
220
221 *******************************************************************************/
222
223 void md_param_alloc_native(methoddesc *md)
224 {
225         paramdesc *pd;
226         s4         i;
227         s4         reguse;
228         s4         stacksize;
229
230         /* set default values */
231
232         reguse    = 0;
233         stacksize = 0;
234
235         /* get params field of methoddesc */
236
237         pd = md->params;
238
239         for (i = 0; i < md->paramcount; i++, pd++) {
240                 switch (md->paramtypes[i].type) {
241                 case TYPE_INT:
242                 case TYPE_ADR:
243                 case TYPE_FLT:
244                         if (reguse < INT_ARG_CNT) {
245                                 pd->inmemory = false;
246                                 pd->index    = -1;
247                                 pd->regoff   = abi_registers_integer_argument[reguse];
248                                 reguse++;
249                         }
250                         else {
251                                 pd->inmemory = true;
252                                 pd->index    = -1;
253                                 pd->regoff   = stacksize * 4;
254                                 stacksize++;
255                         }
256                         break;
257
258                 case TYPE_LNG:
259                 case TYPE_DBL:
260                         if (reguse < (INT_ARG_CNT - 1)) {
261 #if defined(__ARM_EABI__)
262                                 ALIGN_2(reguse);
263 #endif
264                                 pd->inmemory = false;
265 #if defined(__ARMEL__)
266                                 pd->index    = -1;
267                                 pd->regoff   =
268                                         PACK_REGS(abi_registers_integer_argument[reguse],
269                                                           abi_registers_integer_argument[reguse + 1]);
270 #else
271                                 pd->index    = -1;
272                                 pd->regoff   =
273                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
274                                                           abi_registers_integer_argument[reguse]);
275 #endif
276                                 reguse += 2;
277                         }
278 #if !defined(__ARM_EABI__)
279                         else if (reguse < INT_ARG_CNT) {
280                                 pd->inmemory = false;
281 # if defined(__ARMEL__)
282                                 pd->index    = -1;
283                                 pd->regoff   =
284                                         PACK_REGS(abi_registers_integer_argument[reguse],
285                                                           abi_registers_integer_argument[INT_ARG_CNT]);
286 # else
287                                 pd->index    = -1;
288                                 pd->regoff   =
289                                         PACK_REGS(abi_registers_integer_argument[INT_ARG_CNT],
290                                                           abi_registers_integer_argument[reguse]);
291 # endif
292                                 reguse++;
293                                 stacksize++;
294                         }
295 #endif
296                         else {
297 #if defined(__ARM_EABI__)
298                                 ALIGN_2(stacksize);
299 #endif
300                                 pd->inmemory  = true;
301                                 pd->index     = -1;
302                                 pd->regoff    = stacksize * 4;
303                                 reguse        = INT_ARG_CNT;
304                                 stacksize    += 2;
305                         }
306                         break;
307                 }
308         }
309
310         /* Since R0/R1 (==A0/A1) are used for passing return values, this
311            argument register usage has to be regarded, too. */
312
313         if (md->returntype.type != TYPE_VOID) {
314                 if (!IS_2_WORD_TYPE(md->returntype.type)) {
315                         if (reguse < 1)
316                                 reguse = 1;
317                 }
318                 else {
319                         if (reguse < 2)
320                                 reguse = 2;
321                 }
322         }
323
324         /* fill register and stack usage */
325
326         md->argintreguse = reguse;
327         md->argfltreguse = 0;
328         md->memuse       = stacksize;
329 }
330
331
332 /* md_return_alloc *************************************************************
333
334    Precolor the Java Stackelement containing the Return Value, if possible.
335
336    --- in
337    m:                       Methodinfo of current method
338    return_type:             Return Type of the Method (TYPE_INT.. TYPE_ADR)
339                             TYPE_VOID is not allowed!
340    stackslot:               Java Stackslot to contain the Return Value
341
342    --- out
343    if precoloring was possible:
344    VAR(stackslot->varnum)->flags = PREALLOC
345    VAR(stackslot->varnum)->vv.regoff = [REG_RESULT, (REG_RESULT2/REG_RESULT), REG_FRESULT]
346    rd->arg[flt|int]reguse   set to a value according the register usage
347
348 *******************************************************************************/
349
350 void md_return_alloc(jitdata *jd, stackelement_t *stackslot)
351 {
352         methodinfo   *m;
353         codeinfo     *code;
354         registerdata *rd;
355         methoddesc   *md;
356
357         /* get required compiler data */
358
359         m    = jd->m;
360         code = jd->code;
361         rd   = jd->rd;
362
363         md = m->parseddesc;
364
365         /* In Leafmethods Local Vars holding parameters are precolored to
366            their argument register -> so leafmethods with paramcount > 0
367            could already use R0 == a00! */
368
369         if (!code_is_leafmethod(code) || (md->paramcount == 0)) {
370                 /* Only precolor the stackslot, if it is not a SAVEDVAR <->
371                    has not to survive method invokations. */
372
373                 if (!(stackslot->flags & SAVEDVAR)) {
374 #if !defined(ENABLE_SOFTFLOAT)
375                         /* Stackelements containing float or double values
376                            (TYPE_FLT | TYPE_DBL) cannot be precolored, because we
377                            use integer register to pass return values. (floats:
378                            R0, doubles: R0/R1) */
379
380                         if (!IS_FLT_DBL_TYPE(md->returntype.type)) {
381 #endif
382
383                                 VAR(stackslot->varnum)->flags = PREALLOC;
384
385                                 if (!IS_2_WORD_TYPE(md->returntype.type)) {
386                                         if (rd->argintreguse < 1)
387                                                 rd->argintreguse = 1;
388
389                                         VAR(stackslot->varnum)->vv.regoff = REG_RESULT;
390                                 }
391                                 else {
392                                         if (rd->argintreguse < 2)
393                                                 rd->argintreguse = 2;
394
395                                         VAR(stackslot->varnum)->vv.regoff = REG_RESULT_PACKED;
396                                 }
397
398 #if !defined(ENABLE_SOFTFLOAT)
399                         }
400 #endif
401                 }
402         }
403 }
404
405
406 /*
407  * These are local overrides for various environment variables in Emacs.
408  * Please do not remove this and leave it at the end of the file, where
409  * Emacs will automagically detect them.
410  * ---------------------------------------------------------------------
411  * Local variables:
412  * mode: c
413  * indent-tabs-mode: t
414  * c-basic-offset: 4
415  * tab-width: 4
416  * End:
417  * vim:noexpandtab:sw=4:ts=4:
418  */