* Removed all Id tags.
[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 R. Grafl, A. Krall, C. Kruegel,
4    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
5    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
6    J. Wenninger, Institut f. Computersprachen - TU Wien
7
8    This file is part of CACAO.
9
10    This program is free software; you can redistribute it and/or
11    modify it under the terms of the GNU General Public License as
12    published by the Free Software Foundation; either version 2, or (at
13    your option) any later version.
14
15    This program is distributed in the hope that it will be useful, but
16    WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18    General Public License for more details.
19
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23    02110-1301, USA.
24
25 */
26
27
28 #include "config.h"
29 #include "vm/types.h"
30
31 #include "vm/jit/arm/md-abi.h"
32
33 #include "vm/global.h"
34
35 #include "vm/jit/abi.h"
36
37 #include "vmcore/descriptor.h"
38
39
40 /* register descripton array **************************************************/
41
42 s4 nregdescint[] = {
43         REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
44         REG_SAV, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
45         REG_END
46 };
47
48 const char *abi_registers_integer_name[] = {
49         "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4",
50         "v5", "t3", "t1", "t2", "ip", "sp", "lr", "pc",
51 };
52
53 const s4 abi_registers_integer_argument[] = {
54         0,  /* a0 */
55         1,  /* a1 */
56         2,  /* a2 */
57         3,  /* a3 */
58         REG_SPLIT,
59 };
60
61 const s4 abi_registers_integer_saved[] = {
62         4,  /* s0 */
63         5,  /* s1 */
64         6,  /* s2 */
65         7,  /* s3 */
66         8,  /* s4 */
67 };
68
69 const s4 abi_registers_integer_temporary[] = {
70         -1,
71 };
72
73
74 #if defined(ENABLE_SOFTFLOAT)
75 s4 nregdescfloat[] = {
76         REG_RES, REG_RES, REG_RES, REG_RES,
77         REG_RES, REG_RES, REG_RES, REG_RES,
78         REG_END
79 };
80 #else
81 /* TODO: FPA register usage conventions */
82 s4 nregdescfloat[] = {
83         REG_TMP, REG_TMP, REG_TMP, REG_TMP,
84         REG_TMP, REG_TMP, REG_RES, REG_RES,
85         REG_END
86 };
87 #endif /* defined(ENABLE_SOFTFLOAT) */
88
89 const s4 abi_registers_float_argument[] = {
90         -1,
91 };
92
93 const s4 abi_registers_float_saved[] = {
94         -1,
95 };
96
97 const s4 abi_registers_float_temporary[] = {
98 #if defined(ENABLE_SOFTFLOAT)
99         -1,
100 #else
101         0,  /* ft0 */
102         1,  /* ft1 */
103         2,  /* ft2 */
104         3,  /* ft3 */
105         4,  /* ft4 */
106         5,  /* ft5 */
107 #endif
108 };
109
110
111 /* md_param_alloc **************************************************************
112
113    Allocate Arguments to Stackslots according the Calling Conventions
114
115    --- in:
116    md->paramcount:           Number of arguments for this method
117    md->paramtypes[].type:    Argument types
118
119    --- out:
120    md->params[].inmemory:    Argument spilled on stack
121    md->params[].regoff:      Stack offset or rd->arg[int|flt]regs index
122    md->memuse:               Stackslots needed for argument spilling
123    md->argintreguse:         max number of integer arguments used
124    md->argfltreguse:         max number of float arguments used
125
126 *******************************************************************************/
127
128 void md_param_alloc(methoddesc *md)
129 {
130         paramdesc *pd;
131         s4         i;
132         s4         reguse;
133         s4         stacksize;
134
135         /* set default values */
136
137         reguse    = 0;
138         stacksize = 0;
139
140         /* get params field of methoddesc */
141
142         pd = md->params;
143
144         for (i = 0; i < md->paramcount; i++, pd++) {
145                 switch (md->paramtypes[i].type) {
146                 case TYPE_INT:
147                 case TYPE_ADR:
148                 case TYPE_FLT:
149                         if (reguse < INT_ARG_CNT) {
150                                 pd->inmemory = false;
151                                 pd->index    = reguse;
152                                 pd->regoff   = abi_registers_integer_argument[reguse];
153                                 reguse++;
154                         }
155                         else {
156                                 pd->inmemory = true;
157                                 pd->index    = stacksize;
158                                 pd->regoff   = stacksize * 8;
159                                 stacksize++;
160                         }
161                         break;
162
163                 case TYPE_LNG:
164                 case TYPE_DBL:
165                         /* interally we use the EABI */
166
167                         ALIGN_2(reguse);
168
169                         if (reguse < INT_ARG_CNT) {
170                                 pd->inmemory = false;
171 #if defined(__ARMEL__)
172                                 pd->index    = PACK_REGS(reguse, reguse + 1);
173                                 pd->regoff   =
174                                         PACK_REGS(abi_registers_integer_argument[reguse],
175                                                           abi_registers_integer_argument[reguse + 1]);
176 #else
177                                 pd->index    = PACK_REGS(reguse + 1, reguse);
178                                 pd->regoff   =
179                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
180                                                           abi_registers_integer_argument[reguse]);
181 #endif
182                                 reguse += 2;
183                         }
184                         else {
185
186                                 /*ALIGN_2(stacksize);*/
187
188                                 pd->inmemory  = true;
189                                 pd->index     = stacksize;
190                                 pd->regoff    = stacksize * 8;
191                                 /*stacksize    += 2;*/
192                                 stacksize++;
193                         }
194                         break;
195                 }
196         }
197
198         /* Since R0/R1 (==A0/A1) are used for passing return values, this
199            argument register usage has to be regarded, too. */
200
201         if (md->returntype.type != TYPE_VOID) {
202                 if (!IS_2_WORD_TYPE(md->returntype.type)) {
203                         if (reguse < 1)
204                                 reguse = 1;
205                 }
206                 else {
207                         if (reguse < 2)
208                                 reguse = 2;
209                 }
210         }
211
212         /* fill register and stack usage */
213
214         md->argintreguse = reguse;
215         md->argfltreguse = 0;
216         md->memuse       = stacksize;
217 }
218
219
220 /* md_param_alloc_native *******************************************************
221
222    Pre-allocate arguments according the native ABI.
223
224 *******************************************************************************/
225
226 void md_param_alloc_native(methoddesc *md)
227 {
228         paramdesc *pd;
229         s4         i;
230         s4         reguse;
231         s4         stacksize;
232
233         /* set default values */
234
235         reguse    = 0;
236         stacksize = 0;
237
238         /* get params field of methoddesc */
239
240         pd = md->params;
241
242         for (i = 0; i < md->paramcount; i++, pd++) {
243                 switch (md->paramtypes[i].type) {
244                 case TYPE_INT:
245                 case TYPE_ADR:
246                 case TYPE_FLT:
247                         if (reguse < INT_ARG_CNT) {
248                                 pd->inmemory = false;
249                                 pd->index    = -1;
250                                 pd->regoff   = abi_registers_integer_argument[reguse];
251                                 reguse++;
252                         }
253                         else {
254                                 pd->inmemory = true;
255                                 pd->index    = -1;
256                                 pd->regoff   = stacksize * 4;
257                                 stacksize++;
258                         }
259                         break;
260
261                 case TYPE_LNG:
262                 case TYPE_DBL:
263                         if (reguse < (INT_ARG_CNT - 1)) {
264 #if defined(__ARM_EABI__)
265                                 ALIGN_2(reguse);
266 #endif
267                                 pd->inmemory = false;
268 #if defined(__ARMEL__)
269                                 pd->index    = -1;
270                                 pd->regoff   =
271                                         PACK_REGS(abi_registers_integer_argument[reguse],
272                                                           abi_registers_integer_argument[reguse + 1]);
273 #else
274                                 pd->index    = -1;
275                                 pd->regoff   =
276                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
277                                                           abi_registers_integer_argument[reguse]);
278 #endif
279                                 reguse += 2;
280                         }
281 #if !defined(__ARM_EABI__)
282                         else if (reguse < INT_ARG_CNT) {
283                                 pd->inmemory = false;
284 # if defined(__ARMEL__)
285                                 pd->index    = -1;
286                                 pd->regoff   =
287                                         PACK_REGS(abi_registers_integer_argument[reguse],
288                                                           abi_registers_integer_argument[INT_ARG_CNT]);
289 # else
290                                 pd->index    = -1;
291                                 pd->regoff   =
292                                         PACK_REGS(abi_registers_integer_argument[INT_ARG_CNT],
293                                                           abi_registers_integer_argument[reguse]);
294 # endif
295                                 reguse++;
296                                 stacksize++;
297                         }
298 #endif
299                         else {
300 #if defined(__ARM_EABI__)
301                                 ALIGN_2(stacksize);
302 #endif
303                                 pd->inmemory  = true;
304                                 pd->index     = -1;
305                                 pd->regoff    = stacksize * 4;
306                                 reguse        = INT_ARG_CNT;
307                                 stacksize    += 2;
308                         }
309                         break;
310                 }
311         }
312
313         /* Since R0/R1 (==A0/A1) are used for passing return values, this
314            argument register usage has to be regarded, too. */
315
316         if (md->returntype.type != TYPE_VOID) {
317                 if (!IS_2_WORD_TYPE(md->returntype.type)) {
318                         if (reguse < 1)
319                                 reguse = 1;
320                 }
321                 else {
322                         if (reguse < 2)
323                                 reguse = 2;
324                 }
325         }
326
327         /* fill register and stack usage */
328
329         md->argintreguse = reguse;
330         md->argfltreguse = 0;
331         md->memuse       = stacksize;
332 }
333
334
335 /* md_return_alloc *************************************************************
336
337    Precolor the Java Stackelement containing the Return Value, if possible.
338
339    --- in
340    m:                       Methodinfo of current method
341    return_type:             Return Type of the Method (TYPE_INT.. TYPE_ADR)
342                             TYPE_VOID is not allowed!
343    stackslot:               Java Stackslot to contain the Return Value
344
345    --- out
346    if precoloring was possible:
347    VAR(stackslot->varnum)->flags = PREALLOC
348    VAR(stackslot->varnum)->vv.regoff = [REG_RESULT, (REG_RESULT2/REG_RESULT), REG_FRESULT]
349    rd->arg[flt|int]reguse   set to a value according the register usage
350
351 *******************************************************************************/
352
353 void md_return_alloc(jitdata *jd, stackptr stackslot)
354 {
355         methodinfo   *m;
356         registerdata *rd;
357         methoddesc   *md;
358
359         /* get required compiler data */
360
361         m  = jd->m;
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 (!jd->isleafmethod || (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  */