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