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