Merged revisions 7707-7722 via svnmerge from
[cacao.git] / src / vm / jit / mips / md-abi.c
1 /* src/vm/jit/mips/md-abi.c - functions for MIPS 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 7713 2007-04-15 21:49:48Z twisti $
26
27 */
28
29
30 #include "config.h"
31 #include "vm/types.h"
32
33 #include "vm/jit/mips/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 #if SIZEOF_VOID_P == 8
45
46 /* MIPS64 */
47
48 s4 nregdescint[] = {
49         REG_RES, REG_RES, REG_RET, REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
50         REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
51         REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
52         REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
53         REG_END
54 };
55
56 const char *abi_registers_integer_name[] = {
57         "zero",  "at",    "v0",    "v1",    "a0",    "a1",    "a2",    "a3",
58         "a4",    "a5",    "a6",    "a7",    "t0",    "t1",    "t2",    "t3",
59         "s0",    "s1",    "s2",    "s3",    "s4",    "s5",    "s6",    "s7",
60         "t8",    "t9",    "k0",    "k1",    "gp",    "sp",    "s8",    "ra"
61 };
62
63 const s4 abi_registers_integer_argument[] = {
64         4,  /* a0  */
65         5,  /* a1  */
66         6,  /* a2  */
67         7,  /* a3  */
68         8,  /* a4  */
69         9,  /* a5  */
70         10, /* a6  */
71         11, /* a7  */
72 };
73
74 const s4 abi_registers_integer_saved[] = {
75         16, /* s0  */
76         17, /* s1  */
77         18, /* s2  */
78         19, /* s3  */
79         20, /* s4  */
80         21, /* s5  */
81         22, /* s6  */
82         23, /* s7  */
83 };
84
85 const s4 abi_registers_integer_temporary[] = {
86         12, /* t0  */
87         13, /* t1  */
88         14, /* t2  */
89         15, /* t3  */
90         24, /* t4  */
91 };
92
93
94 s4 nregdescfloat[] = {
95         /*  fv0,   ftmp1,   ftmp2,   ftmp3,     ft0,     ft1,     ft2,     ft3,   */
96         REG_RET, REG_RES, REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
97
98         /*  ft4,     ft5,     ft6,     ft7,     fa0,     fa1,     fa2,     fa3,   */
99         REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
100
101         /*  fa4,     fa5,     fa6,     fa7,     ft8,     ft9,    ft10,    ft11,   */
102         REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
103
104         /*  fs0,    ft12,     fs1,    ft13,     fs2,    ft14,     fs3     ft15    */
105         REG_SAV, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP,
106
107         REG_END
108 };
109
110 const s4 abi_registers_float_argument[] = {
111         12, /* fa0  */
112         13, /* fa1  */
113         14, /* fa2  */
114         15, /* fa3  */
115         16, /* fa4  */
116         17, /* fa5  */
117         18, /* fa6  */
118         19, /* fa7  */
119 };
120
121 const s4 abi_registers_float_saved[] = {
122         24, /* fs0  */
123         26, /* fs1  */
124         28, /* fs2  */
125         30, /* fs3  */
126 };
127
128 const s4 abi_registers_float_temporary[] = {
129         4,  /* ft0  */
130         5,  /* ft1  */
131         6,  /* ft2  */
132         7,  /* ft3  */
133         8,  /* ft4  */
134         9,  /* ft5  */
135         10, /* ft6  */
136         11, /* ft7  */
137         20, /* ft8  */
138         21, /* ft9  */
139         22, /* ft10 */
140         23, /* ft11 */
141         25, /* ft12 */
142         27, /* ft13 */
143         29, /* ft14 */
144         31, /* ft15 */
145 };
146
147 #else /* SIZEOF_VOID_P == 8 */
148
149 /* MIPS32 */
150
151 s4 nregdescint[] = {
152         /* zero,   itmp1,      v0,      v1,      a0,      a1,      a2,      a3,   */
153         REG_RES, REG_RES, REG_RET, REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
154
155         /*   t0,      t1,      t2,      t3,      t4,      t5,      t6,      t7,   */
156         REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
157
158         /*   s0,      s1,      s2,      s3,      s4,      s5,      s6,      s7,   */
159         REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
160
161         /*itmp2,   itmp3, k0(sys), k1(sys),      gp,      sp,      pv,      ra    */
162         REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
163
164         REG_END
165 };
166
167 const char *abi_registers_integer_name[] = {
168         "zero",  "at",    "v0",    "v1",    "a0",    "a1",    "a2",    "a3",
169         "a4",    "a5",    "a6",    "a7",    "t0",    "t1",    "t2",    "t3",
170         "s0",    "s1",    "s2",    "s3",    "s4",    "s5",    "s6",    "s7",
171         "t8",    "t9",    "k0",    "k1",    "gp",    "sp",    "s8",    "ra"
172 };
173
174 const s4 abi_registers_integer_argument[] = {
175         4,  /* a0  */
176         5,  /* a1  */
177         6,  /* a2  */
178         7,  /* a3  */
179 };
180
181 const s4 abi_registers_integer_saved[] = {
182         16, /* s0  */
183         17, /* s1  */
184         18, /* s2  */
185         19, /* s3  */
186         20, /* s4  */
187         21, /* s5  */
188         22, /* s6  */
189         23, /* s7  */
190 };
191
192 const s4 abi_registers_integer_temporary[] = {
193         8,  /* t0  */
194         9,  /* t1  */
195         10, /* t2  */
196         11, /* t3  */
197         12, /* t4  */
198         13, /* t5  */
199         14, /* t6  */
200         15, /* t7  */
201 };
202
203
204 #if !defined(ENABLE_SOFT_FLOAT)
205
206 s4 nregdescfloat[] = {
207         /*  fv0,            ftmp1,            ftmp2,            ftmp3,            */
208         REG_RET, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
209
210         /*  ft0,              ft1,              fa0,              fa1,            */
211         REG_TMP, REG_RES, REG_TMP, REG_RES, REG_ARG, REG_RES, REG_ARG, REG_RES,
212
213         /*  ft2,              ft3,              fs0,              fs1,            */
214         REG_TMP, REG_RES, REG_TMP, REG_RES, REG_SAV, REG_RES, REG_SAV, REG_RES,
215
216         /*  fs2,              fs3,              fs4,              fs5             */
217         REG_SAV, REG_RES, REG_SAV, REG_RES, REG_SAV, REG_RES, REG_SAV, REG_RES,
218
219         REG_END
220 };
221
222 const s4 abi_registers_float_argument[] = {
223         12, /* fa0  */
224         14, /* fa1  */
225 };
226
227 const s4 abi_registers_float_saved[] = {
228         20, /* fs0  */
229         22, /* fs1  */
230         24, /* fs2  */
231         26, /* fs3  */
232         28, /* fs4  */
233         30, /* fs5  */
234 };
235
236 const s4 abi_registers_float_temporary[] = {
237         8,  /* ft0  */
238         10, /* ft1  */
239         16, /* ft2  */
240         18, /* ft3  */
241 };
242
243
244 #else /* !defined(ENABLE_SOFT_FLOAT) */
245
246 s4 nregdescfloat[] = {
247         REG_END
248 };
249
250 #endif /* !defined(ENABLE_SOFT_FLOAT) */
251
252 #endif /* SIZEOF_VOID_P == 8 */
253
254
255 /* md_param_alloc **************************************************************
256
257    Pre-allocate arguments according to the internal JIT ABI.
258
259 *******************************************************************************/
260
261 void md_param_alloc(methoddesc *md)
262 {
263         paramdesc *pd;
264         s4         i;
265         s4         reguse;
266         s4         stacksize;
267 #if SIZEOF_VOID_P == 4 && !defined(ENABLE_SOFT_FLOAT)
268         s4         t;
269         bool       a0_is_float;
270 #endif
271
272         /* set default values */
273
274         reguse      = 0;
275         stacksize   = 0;
276 #if SIZEOF_VOID_P == 4 && !defined(ENABLE_SOFT_FLOAT)
277         a0_is_float = false;
278 #endif
279
280         /* get params field of methoddesc */
281
282         pd = md->params;
283
284         for (i = 0; i < md->paramcount; i++, pd++) {
285 #if SIZEOF_VOID_P == 8
286
287                 switch (md->paramtypes[i].type) {
288                 case TYPE_INT:
289                 case TYPE_ADR:
290                 case TYPE_LNG:
291                         if (i < INT_ARG_CNT) {
292                                 pd->inmemory = false;
293                                 pd->regoff   = abi_registers_integer_argument[reguse];
294                                 reguse++;
295                                 md->argintreguse = reguse;
296                         }
297                         else {
298                                 pd->inmemory = true;
299                                 pd->regoff   = stacksize;
300                                 stacksize++;
301                         }
302                         break;
303                 case TYPE_FLT:
304                 case TYPE_DBL:
305                         if (i < FLT_ARG_CNT) {
306                                 pd->inmemory = false;
307                                 pd->regoff   = abi_registers_float_argument[reguse];
308                                 reguse++;
309                                 md->argfltreguse = reguse;
310                         }
311                         else {
312                                 pd->inmemory = true;
313                                 pd->regoff   = stacksize;
314                                 stacksize++;
315                         }
316                         break;
317                 }
318
319                 /* register type is the same as java type */
320
321                 pd->type = md->paramtypes[i].type;
322
323 #else /* SIZEOF_VOID_P == 8 */
324
325 #if !defined(ENABLE_SOFT_FLOAT)
326
327 #define ALIGN_2_WORD(s)    ((s) & 1) ? ++(s) : (s)
328
329                 t = md->paramtypes[i].type;
330
331                 if (IS_FLT_DBL_TYPE(t) &&
332                         ((i == 0) ||
333                          ((i == 1) && IS_FLT_DBL_TYPE(md->paramtypes[0].type)))) {
334                         if (IS_2_WORD_TYPE(t)) {
335                                 pd->type   = TYPE_DBL;
336                                 pd->regoff = abi_registers_float_argument[reguse];
337                                 reguse++;
338                                 stacksize += 2;
339                         }
340                         else {
341                                 pd->type   = TYPE_FLT;
342                                 pd->regoff = abi_registers_float_argument[reguse];
343                                 reguse++;
344                                 stacksize++;
345                         }
346                         md->argfltreguse = reguse;
347                         a0_is_float = true;
348                 }
349                 else {
350                         if (IS_2_WORD_TYPE(t)) {
351                                 ALIGN_2_WORD(reguse);
352                                 pd->type = TYPE_LNG;
353
354                                 if (reguse < INT_ARG_CNT) {
355                                         pd->inmemory = false;
356 # if WORDS_BIGENDIAN == 1
357                                         pd->regoff   =
358                                                 PACK_REGS(abi_registers_integer_argument[reguse + 1],
359                                                                   abi_registers_integer_argument[reguse]);
360 # else
361                                         pd->regoff   =
362                                                 PACK_REGS(abi_registers_integer_argument[reguse],
363                                                                   abi_registers_integer_argument[reguse + 1]);
364 # endif
365                                         reguse += 2;
366                                         md->argintreguse = reguse;
367                                 }
368                                 else {
369                                         pd->inmemory = true;
370                                         pd->regoff   = ALIGN_2_WORD(stacksize);
371                                 }
372                                 stacksize += 2;
373                         }
374                         else {
375                                 pd->type = TYPE_INT;
376
377                                 if (reguse < INT_ARG_CNT) {
378                                         pd->inmemory = false;
379                                         pd->regoff   = abi_registers_integer_argument[reguse];
380                                         reguse++;
381                                         md->argintreguse = reguse;
382                                 }
383                                 else {
384                                         pd->inmemory = true;
385                                         pd->regoff   = stacksize;
386                                 }
387                                 stacksize++;
388                         }
389                 }
390
391 #else /* !defined(ENABLE_SOFT_FLOAT) */
392 #error never actually tested!
393
394                 switch (md->paramtypes[i].type) {
395                 case TYPE_INT:
396                 case TYPE_ADR:
397                 case TYPE_FLT:
398                         pd->type = TYPE_INT;
399
400                         if (i < INT_ARG_CNT) {
401                                 pd->inmemory = false;
402                                 pd->regoff   = abi_registers_integer_argument[reguse];
403                                 reguse++;
404                                 md->argintreguse = reguse;
405                         }
406                         else {
407                                 pd->inmemory = true;
408                                 pd->regoff   = stacksize;
409                         }
410                         stacksize++;
411                         break;
412                 case TYPE_LNG:
413                 case TYPE_DBL:
414                         pd->type = TYPE_LNG;
415
416                         if (i < INT_ARG_CNT) {
417                                 pd->inmemory = false;
418 #if WORDS_BIGENDIAN == 1
419                                 pd->regoff   =
420                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
421                                                           abi_registers_integer_argument[reguse]);
422 #else
423                                 pd->regoff   =
424                                         PACK_REGS(abi_registers_integer_argument[reguse],
425                                                           abi_registers_integer_argument[reguse + 1]);
426 #endif
427                                 reguse += 2;
428                                 md->argintreguse = reguse;
429                         }
430                         else {
431                                 pd->inmemory = true;
432                                 pd->regoff   = stacksize;
433                         }
434                         stacksize += 2;
435                         break;
436                 }
437
438
439 #endif /* !defined(ENABLE_SOFT_FLOAT) */
440
441 #endif /* SIZEOF_VOID_P == 8 */
442         }
443
444         /* fill register and stack usage */
445
446         md->memuse = stacksize;
447 }
448
449
450 /* md_param_alloc_native *******************************************************
451
452    Pre-allocate arguments according the native ABI.
453
454 *******************************************************************************/
455
456 void md_param_alloc_native(methoddesc *md)
457 {
458         /* On MIPS we use the same ABI for JIT method calls as for native
459            method calls. */
460
461         md_param_alloc(md);
462 }
463
464
465 /* md_return_alloc *************************************************************
466
467    Precolor the Java Stackelement containing the Return Value. Since
468    mips has a dedicated return register (not an reused arg or reserved
469    reg), this is striaghtforward possible, as long, as this
470    stackelement does not have to survive a method invokation
471    (SAVEDVAR)
472
473    --- in
474    jd:                      jitdata of the current method
475    stackslot:               Java Stackslot to contain the Return Value
476    
477    --- out
478    if precoloring was possible:
479    VAR(stackslot->varnum)->flags       = PREALLOC
480                                      ->regoff      = [REG_RESULT|REG_FRESULT]
481
482 *******************************************************************************/
483
484 void md_return_alloc(jitdata *jd, stackptr stackslot)
485 {
486         methodinfo *m;
487         methoddesc *md;
488
489         /* get required compiler data */
490
491         m = jd->m;
492
493         md = m->parseddesc;
494
495         /* Only precolor the stackslot, if it is not a SAVEDVAR <-> has
496            not to survive method invokations. */
497
498         if (!(stackslot->flags & SAVEDVAR)) {
499                 VAR(stackslot->varnum)->flags = PREALLOC;
500
501                 if (IS_INT_LNG_TYPE(md->returntype.type)) {
502 #if SIZEOF_VOID_P == 4
503                         if (IS_2_WORD_TYPE(md->returntype.type))
504                                 VAR(stackslot->varnum)->vv.regoff = REG_RESULT_PACKED;
505                         else
506 #endif
507                                 VAR(stackslot->varnum)->vv.regoff = REG_RESULT;
508                 }
509                 else
510                         VAR(stackslot->varnum)->vv.regoff = REG_FRESULT;
511         }
512 }
513
514
515 /*
516  * These are local overrides for various environment variables in Emacs.
517  * Please do not remove this and leave it at the end of the file, where
518  * Emacs will automagically detect them.
519  * ---------------------------------------------------------------------
520  * Local variables:
521  * mode: c
522  * indent-tabs-mode: t
523  * c-basic-offset: 4
524  * tab-width: 4
525  * End:
526  */