0abca2ad64b8f80f23ec256dfe1b3fd576cbe80b
[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 8127 2007-06-21 11:55:56Z 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
139         reguse    = 0;
140         stacksize = 0;
141
142         /* get params field of methoddesc */
143
144         pd = md->params;
145
146         for (i = 0; i < md->paramcount; i++, pd++) {
147                 switch (md->paramtypes[i].type) {
148                 case TYPE_INT:
149                 case TYPE_ADR:
150                 case TYPE_FLT:
151                         if (reguse < INT_ARG_CNT) {
152                                 pd->inmemory = false;
153                                 pd->index    = reguse;
154                                 pd->regoff   = abi_registers_integer_argument[reguse];
155                                 reguse++;
156                         }
157                         else {
158                                 pd->inmemory = true;
159                                 pd->index    = stacksize;
160                                 pd->regoff   = stacksize * 8;
161                                 stacksize++;
162                         }
163                         break;
164
165                 case TYPE_LNG:
166                 case TYPE_DBL:
167                         /* interally we use the EABI */
168
169                         ALIGN_2(reguse);
170
171                         if (reguse < INT_ARG_CNT) {
172                                 pd->inmemory = false;
173 #if defined(__ARMEL__)
174                                 pd->index    = PACK_REGS(reguse, reguse + 1);
175                                 pd->regoff   =
176                                         PACK_REGS(abi_registers_integer_argument[reguse],
177                                                           abi_registers_integer_argument[reguse + 1]);
178 #else
179                                 pd->index    = PACK_REGS(reguse + 1, reguse);
180                                 pd->regoff   =
181                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
182                                                           abi_registers_integer_argument[reguse]);
183 #endif
184                                 reguse += 2;
185                         }
186                         else {
187
188                                 /*ALIGN_2(stacksize);*/
189
190                                 pd->inmemory  = true;
191                                 pd->index     = stacksize;
192                                 pd->regoff    = stacksize * 8;
193                                 /*stacksize    += 2;*/
194                                 stacksize++;
195                         }
196                         break;
197                 }
198         }
199
200         /* Since R0/R1 (==A0/A1) are used for passing return values, this
201            argument register usage has to be regarded, too. */
202
203         if (md->returntype.type != TYPE_VOID) {
204                 if (!IS_2_WORD_TYPE(md->returntype.type)) {
205                         if (reguse < 1)
206                                 reguse = 1;
207                 }
208                 else {
209                         if (reguse < 2)
210                                 reguse = 2;
211                 }
212         }
213
214         /* fill register and stack usage */
215
216         md->argintreguse = reguse;
217         md->argfltreguse = 0;
218         md->memuse       = stacksize;
219 }
220
221
222 /* md_param_alloc_native *******************************************************
223
224    Pre-allocate arguments according the native ABI.
225
226 *******************************************************************************/
227
228 void md_param_alloc_native(methoddesc *md)
229 {
230         paramdesc *pd;
231         s4         i;
232         s4         reguse;
233         s4         stacksize;
234
235         /* set default values */
236
237         reguse    = 0;
238         stacksize = 0;
239
240         /* get params field of methoddesc */
241
242         pd = md->params;
243
244         for (i = 0; i < md->paramcount; i++, pd++) {
245                 switch (md->paramtypes[i].type) {
246                 case TYPE_INT:
247                 case TYPE_ADR:
248                 case TYPE_FLT:
249                         if (reguse < INT_ARG_CNT) {
250                                 pd->inmemory = false;
251                                 pd->index    = -1;
252                                 pd->regoff   = abi_registers_integer_argument[reguse];
253                                 reguse++;
254                         }
255                         else {
256                                 pd->inmemory = true;
257                                 pd->index    = -1;
258                                 pd->regoff   = stacksize * 4;
259                                 stacksize++;
260                         }
261                         break;
262
263                 case TYPE_LNG:
264                 case TYPE_DBL:
265                         if (reguse < (INT_ARG_CNT - 1)) {
266 #if defined(__ARM_EABI__)
267                                 ALIGN_2(reguse);
268 #endif
269                                 pd->inmemory = false;
270 #if defined(__ARMEL__)
271                                 pd->index    = -1;
272                                 pd->regoff   =
273                                         PACK_REGS(abi_registers_integer_argument[reguse],
274                                                           abi_registers_integer_argument[reguse + 1]);
275 #else
276                                 pd->index    = -1;
277                                 pd->regoff   =
278                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
279                                                           abi_registers_integer_argument[reguse]);
280 #endif
281                                 reguse += 2;
282                         }
283 #if !defined(__ARM_EABI__)
284                         else if (reguse < INT_ARG_CNT) {
285                                 pd->inmemory = false;
286 # if defined(__ARMEL__)
287                                 pd->index    = -1;
288                                 pd->regoff   =
289                                         PACK_REGS(abi_registers_integer_argument[reguse],
290                                                           abi_registers_integer_argument[INT_ARG_CNT]);
291 # else
292                                 pd->index    = -1;
293                                 pd->regoff   =
294                                         PACK_REGS(abi_registers_integer_argument[INT_ARG_CNT],
295                                                           abi_registers_integer_argument[reguse]);
296 # endif
297                                 reguse++;
298                                 stacksize++;
299                         }
300 #endif
301                         else {
302 #if defined(__ARM_EABI__)
303                                 ALIGN_2(stacksize);
304 #endif
305                                 pd->inmemory  = true;
306                                 pd->index     = -1;
307                                 pd->regoff    = stacksize * 4;
308                                 reguse        = INT_ARG_CNT;
309                                 stacksize    += 2;
310                         }
311                         break;
312                 }
313         }
314
315         /* Since R0/R1 (==A0/A1) are used for passing return values, this
316            argument register usage has to be regarded, too. */
317
318         if (md->returntype.type != TYPE_VOID) {
319                 if (!IS_2_WORD_TYPE(md->returntype.type)) {
320                         if (reguse < 1)
321                                 reguse = 1;
322                 }
323                 else {
324                         if (reguse < 2)
325                                 reguse = 2;
326                 }
327         }
328
329         /* fill register and stack usage */
330
331         md->argintreguse = reguse;
332         md->argfltreguse = 0;
333         md->memuse       = stacksize;
334 }
335
336
337 /* md_return_alloc *************************************************************
338
339    Precolor the Java Stackelement containing the Return Value, if possible.
340
341    --- in
342    m:                       Methodinfo of current method
343    return_type:             Return Type of the Method (TYPE_INT.. TYPE_ADR)
344                             TYPE_VOID is not allowed!
345    stackslot:               Java Stackslot to contain the Return Value
346
347    --- out
348    if precoloring was possible:
349    VAR(stackslot->varnum)->flags = PREALLOC
350    VAR(stackslot->varnum)->vv.regoff = [REG_RESULT, (REG_RESULT2/REG_RESULT), REG_FRESULT]
351    rd->arg[flt|int]reguse   set to a value according the register usage
352
353 *******************************************************************************/
354
355 void md_return_alloc(jitdata *jd, stackptr stackslot)
356 {
357         methodinfo   *m;
358         registerdata *rd;
359         methoddesc   *md;
360
361         /* get required compiler data */
362
363         m  = jd->m;
364         rd = jd->rd;
365
366         md = m->parseddesc;
367
368         /* In Leafmethods Local Vars holding parameters are precolored to
369            their argument register -> so leafmethods with paramcount > 0
370            could already use R0 == a00! */
371
372         if (!jd->isleafmethod || (md->paramcount == 0)) {
373                 /* Only precolor the stackslot, if it is not a SAVEDVAR <->
374                    has not to survive method invokations. */
375
376                 if (!(stackslot->flags & SAVEDVAR)) {
377 #if !defined(ENABLE_SOFTFLOAT)
378                         /* Stackelements containing float or double values
379                            (TYPE_FLT | TYPE_DBL) cannot be precolored, because we
380                            use integer register to pass return values. (floats:
381                            R0, doubles: R0/R1) */
382
383                         if (!IS_FLT_DBL_TYPE(md->returntype.type)) {
384 #endif
385
386                                 VAR(stackslot->varnum)->flags = PREALLOC;
387
388                                 if (!IS_2_WORD_TYPE(md->returntype.type)) {
389                                         if (rd->argintreguse < 1)
390                                                 rd->argintreguse = 1;
391
392                                         VAR(stackslot->varnum)->vv.regoff = REG_RESULT;
393                                 }
394                                 else {
395                                         if (rd->argintreguse < 2)
396                                                 rd->argintreguse = 2;
397
398                                         VAR(stackslot->varnum)->vv.regoff = REG_RESULT_PACKED;
399                                 }
400
401 #if !defined(ENABLE_SOFTFLOAT)
402                         }
403 #endif
404                 }
405         }
406 }
407
408
409 /*
410  * These are local overrides for various environment variables in Emacs.
411  * Please do not remove this and leave it at the end of the file, where
412  * Emacs will automagically detect them.
413  * ---------------------------------------------------------------------
414  * Local variables:
415  * mode: c
416  * indent-tabs-mode: t
417  * c-basic-offset: 4
418  * tab-width: 4
419  * End:
420  */