da2af84aaae52957cb26bee8dd77ec23638f0339
[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, 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
28 #include <stdarg.h>
29 #include <stdint.h>
30
31 #include "vm/types.h"
32
33 #include "vm/jit/mips/md-abi.h"
34
35 #include "mm/memory.hpp"
36
37 #include "vm/descriptor.hpp"
38 #include "vm/global.h"
39 #include "vm/method.hpp"
40
41 #include "vm/jit/abi.h"
42 #include "vm/jit/stack.h"
43
44
45 /* register descripton array **************************************************/
46
47 #if SIZEOF_VOID_P == 8
48
49 /* MIPS64 */
50
51 s4 nregdescint[] = {
52         REG_RES, REG_RES, REG_RET, REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
53         REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
54         REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
55         REG_TMP, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
56         REG_END
57 };
58
59 const char *abi_registers_integer_name[] = {
60         "zero",  "at",    "v0",    "v1",    "a0",    "a1",    "a2",    "a3",
61         "a4",    "a5",    "a6",    "a7",    "t0",    "t1",    "t2",    "t3",
62         "s0",    "s1",    "s2",    "s3",    "s4",    "s5",    "s6",    "s7",
63         "t8",    "t9",    "k0",    "k1",    "gp",    "sp",    "s8",    "ra"
64 };
65
66 const s4 abi_registers_integer_argument[] = {
67         4,  /* a0  */
68         5,  /* a1  */
69         6,  /* a2  */
70         7,  /* a3  */
71         8,  /* a4  */
72         9,  /* a5  */
73         10, /* a6  */
74         11, /* a7  */
75 };
76
77 const s4 abi_registers_integer_saved[] = {
78         16, /* s0  */
79         17, /* s1  */
80         18, /* s2  */
81         19, /* s3  */
82         20, /* s4  */
83         21, /* s5  */
84         22, /* s6  */
85         23, /* s7  */
86 };
87
88 const s4 abi_registers_integer_temporary[] = {
89         12, /* t0  */
90         13, /* t1  */
91         14, /* t2  */
92         15, /* t3  */
93         24, /* t4  */
94 };
95
96
97 s4 nregdescfloat[] = {
98         /*  fv0,   ftmp1,   ftmp2,   ftmp3,     ft0,     ft1,     ft2,     ft3,   */
99         REG_RET, REG_RES, REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
100
101         /*  ft4,     ft5,     ft6,     ft7,     fa0,     fa1,     fa2,     fa3,   */
102         REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
103
104         /*  fa4,     fa5,     fa6,     fa7,     ft8,     ft9,    ft10,    ft11,   */
105         REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
106
107         /*  fs0,    ft12,     fs1,    ft13,     fs2,    ft14,     fs3     ft15    */
108         REG_SAV, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP, REG_SAV, REG_TMP,
109
110         REG_END
111 };
112
113 const s4 abi_registers_float_argument[] = {
114         12, /* fa0  */
115         13, /* fa1  */
116         14, /* fa2  */
117         15, /* fa3  */
118         16, /* fa4  */
119         17, /* fa5  */
120         18, /* fa6  */
121         19, /* fa7  */
122 };
123
124 const s4 abi_registers_float_saved[] = {
125         24, /* fs0  */
126         26, /* fs1  */
127         28, /* fs2  */
128         30, /* fs3  */
129 };
130
131 const s4 abi_registers_float_temporary[] = {
132         4,  /* ft0  */
133         5,  /* ft1  */
134         6,  /* ft2  */
135         7,  /* ft3  */
136         8,  /* ft4  */
137         9,  /* ft5  */
138         10, /* ft6  */
139         11, /* ft7  */
140         20, /* ft8  */
141         21, /* ft9  */
142         22, /* ft10 */
143         23, /* ft11 */
144         25, /* ft12 */
145         27, /* ft13 */
146         29, /* ft14 */
147         31, /* ft15 */
148 };
149
150 #else /* SIZEOF_VOID_P == 8 */
151
152 /* MIPS32 */
153
154 s4 nregdescint[] = {
155         /* zero,   itmp1,      v0,      v1,      a0,      a1,      a2,      a3,   */
156         REG_RES, REG_RES, REG_RET, REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
157
158         /*   t0,      t1,      t2,      t3,      t4,      t5,      t6,      t7,   */
159         REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
160
161         /*   s0,      s1,      s2,      s3,      s4,      s5,      s6,      s7,   */
162         REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
163
164         /*itmp2,   itmp3, k0(sys), k1(sys),      gp,      sp,      pv,      ra    */
165         REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
166
167         REG_END
168 };
169
170 const char *abi_registers_integer_name[] = {
171         "zero",  "at",    "v0",    "v1",    "a0",    "a1",    "a2",    "a3",
172         "a4",    "a5",    "a6",    "a7",    "t0",    "t1",    "t2",    "t3",
173         "s0",    "s1",    "s2",    "s3",    "s4",    "s5",    "s6",    "s7",
174         "t8",    "t9",    "k0",    "k1",    "gp",    "sp",    "s8",    "ra"
175 };
176
177 const s4 abi_registers_integer_argument[] = {
178         4,  /* a0  */
179         5,  /* a1  */
180         6,  /* a2  */
181         7,  /* a3  */
182 };
183
184 const s4 abi_registers_integer_saved[] = {
185         16, /* s0  */
186         17, /* s1  */
187         18, /* s2  */
188         19, /* s3  */
189         20, /* s4  */
190         21, /* s5  */
191         22, /* s6  */
192         23, /* s7  */
193 };
194
195 const s4 abi_registers_integer_temporary[] = {
196         8,  /* t0  */
197         9,  /* t1  */
198         10, /* t2  */
199         11, /* t3  */
200         12, /* t4  */
201         13, /* t5  */
202         14, /* t6  */
203         15, /* t7  */
204 };
205
206
207 #if !defined(ENABLE_SOFT_FLOAT)
208
209 s4 nregdescfloat[] = {
210         /*  fv0,            ftmp1,            ftmp2,            ftmp3,            */
211         REG_RET, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES, REG_RES,
212
213         /*  ft0,              ft1,              fa0,              fa1,            */
214         REG_TMP, REG_RES, REG_TMP, REG_RES, REG_ARG, REG_RES, REG_ARG, REG_RES,
215
216         /*  ft2,              ft3,              fs0,              fs1,            */
217         REG_TMP, REG_RES, REG_TMP, REG_RES, REG_SAV, REG_RES, REG_SAV, REG_RES,
218
219         /*  fs2,              fs3,              fs4,              fs5             */
220         REG_SAV, REG_RES, REG_SAV, REG_RES, REG_SAV, REG_RES, REG_SAV, REG_RES,
221
222         REG_END
223 };
224
225 const s4 abi_registers_float_argument[] = {
226         12, /* fa0  */
227         14, /* fa1  */
228 };
229
230 const s4 abi_registers_float_saved[] = {
231         20, /* fs0  */
232         22, /* fs1  */
233         24, /* fs2  */
234         26, /* fs3  */
235         28, /* fs4  */
236         30, /* fs5  */
237 };
238
239 const s4 abi_registers_float_temporary[] = {
240         8,  /* ft0  */
241         10, /* ft1  */
242         16, /* ft2  */
243         18, /* ft3  */
244 };
245
246
247 #else /* !defined(ENABLE_SOFT_FLOAT) */
248
249 s4 nregdescfloat[] = {
250         REG_END
251 };
252
253 #endif /* !defined(ENABLE_SOFT_FLOAT) */
254
255 #endif /* SIZEOF_VOID_P == 8 */
256
257
258 /* md_param_alloc **************************************************************
259
260    Pre-allocate arguments according to the internal JIT ABI.
261
262 *******************************************************************************/
263
264 void md_param_alloc(methoddesc *md)
265 {
266         paramdesc *pd;
267         s4         i;
268         s4         reguse;
269         s4         stacksize;
270
271         /* set default values */
272
273         reguse      = 0;
274         stacksize   = 0;
275
276         /* get params field of methoddesc */
277
278         pd = md->params;
279
280 #if SIZEOF_VOID_P == 8
281
282         for (i = 0; i < md->paramcount; i++, pd++) {
283                 switch (md->paramtypes[i].type) {
284                 case TYPE_INT:
285                 case TYPE_ADR:
286                 case TYPE_LNG:
287                         if (reguse < INT_ARG_CNT) {
288                                 pd->inmemory = false;
289                                 pd->regoff   = abi_registers_integer_argument[reguse];
290                                 reguse++;
291                                 md->argintreguse = reguse;
292                         }
293                         else {
294                                 pd->inmemory = true;
295                                 pd->regoff   = stacksize * 8;
296                                 stacksize++;
297                         }
298                         break;
299
300                 case TYPE_FLT:
301                 case TYPE_DBL:
302                         if (reguse < FLT_ARG_CNT) {
303                                 pd->inmemory = false;
304                                 pd->regoff   = abi_registers_float_argument[reguse];
305                                 reguse++;
306                                 md->argfltreguse = reguse;
307                         }
308                         else {
309                                 pd->inmemory = true;
310                                 pd->regoff   = stacksize * 8;
311                                 stacksize++;
312                         }
313                         break;
314                 }
315
316                 /* register type is the same as java type */
317
318                 pd->type = md->paramtypes[i].type;
319         }
320
321 #else /* SIZEOF_VOID_P == 8 */
322
323 # if !defined(ENABLE_SOFT_FLOAT)
324
325         /* Set stacksize to 2, as 4 32-bit argument registers can be
326            stored. */
327         /* XXX maybe this should be done in stack.c? */
328
329         stacksize = 2;
330
331         for (i = 0; i < md->paramcount; i++, pd++) {
332                 switch (md->paramtypes[i].type) {
333                 case TYPE_INT:
334                 case TYPE_ADR:
335                         if (reguse < INT_ARG_CNT) {
336                                 pd->inmemory = false;
337                                 pd->index    = reguse;
338                                 pd->regoff   = abi_registers_integer_argument[reguse];
339                                 reguse++;
340                                 md->argintreguse = reguse;
341                         }
342                         else {
343                                 pd->inmemory = true;
344                                 pd->index    = stacksize;
345                                 pd->regoff   = stacksize * 8;
346                                 stacksize++;
347                         }
348                         break;
349
350                 case TYPE_LNG:
351                         ALIGN_2(reguse);
352
353                         if (reguse < INT_ARG_CNT) {
354                                 pd->inmemory = false;
355 #  if WORDS_BIGENDIAN == 1
356                                 pd->index    = PACK_REGS(reguse + 1, reguse);
357                                 pd->regoff   =
358                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
359                                                           abi_registers_integer_argument[reguse]);
360 #  else
361                                 pd->index    = PACK_REGS(reguse, reguse + 1);
362                                 pd->regoff   =
363                                         PACK_REGS(abi_registers_integer_argument[reguse],
364                                                           abi_registers_integer_argument[reguse + 1]);
365 #  endif
366                                 reguse += 2;
367                                 md->argintreguse = reguse;
368                         }
369                         else {
370                                 pd->inmemory = true;
371                                 pd->index    = stacksize;
372                                 pd->regoff   = stacksize * 8;
373                                 stacksize++;
374                         }
375                         break;
376
377                 case TYPE_FLT:
378                 case TYPE_DBL:
379                         if (reguse < FLT_ARG_CNT) {
380                                 pd->inmemory = false;
381                                 pd->index    = reguse;
382                                 pd->regoff   = abi_registers_float_argument[reguse];
383                                 reguse++;
384                                 md->argfltreguse = reguse;
385                         }
386                         else {
387                                 pd->inmemory = true;
388                                 pd->index    = stacksize;
389                                 pd->regoff   = stacksize * 8;
390                                 stacksize++;
391                         }
392                         break;
393                 }
394
395                 /* register type is the same as java type */
396
397                 pd->type = md->paramtypes[i].type;
398         }
399
400 # else /* !defined(ENABLE_SOFT_FLOAT) */
401 #  error never actually tested!
402
403         for (i = 0; i < md->paramcount; i++, pd++) {
404                 switch (md->paramtypes[i].type) {
405                 case TYPE_INT:
406                 case TYPE_ADR:
407                 case TYPE_FLT:
408                         pd->type = TYPE_INT;
409
410                         if (reguse < INT_ARG_CNT) {
411                                 pd->inmemory = false;
412                                 pd->regoff   = abi_registers_integer_argument[reguse];
413                                 reguse++;
414                                 md->argintreguse = reguse;
415                         }
416                         else {
417                                 pd->inmemory = true;
418                                 pd->regoff   = stacksize * 8;
419                         }
420                         stacksize++;
421                         break;
422
423                 case TYPE_LNG:
424                 case TYPE_DBL:
425                         pd->type = TYPE_LNG;
426
427                         if (reguse < INT_ARG_CNT) {
428                                 pd->inmemory = false;
429 #  if WORDS_BIGENDIAN == 1
430                                 pd->regoff   =
431                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
432                                                           abi_registers_integer_argument[reguse]);
433 #  else
434                                 pd->regoff   =
435                                         PACK_REGS(abi_registers_integer_argument[reguse],
436                                                           abi_registers_integer_argument[reguse + 1]);
437 #  endif
438                                 reguse += 2;
439                                 md->argintreguse = reguse;
440                         }
441                         else {
442                                 pd->inmemory = true;
443                                 pd->regoff   = stacksize * 8;
444                         }
445                         stacksize += 2;
446                         break;
447                 }
448         }
449
450 # endif /* !defined(ENABLE_SOFT_FLOAT) */
451 #endif /* SIZEOF_VOID_P == 8 */
452
453         /* fill register and stack usage */
454
455         md->memuse = stacksize;
456 }
457
458
459 /* md_param_alloc_native *******************************************************
460
461    Pre-allocate arguments according the native ABI.
462
463 *******************************************************************************/
464
465 void md_param_alloc_native(methoddesc *md)
466 {
467 #if SIZEOF_VOID_P == 8
468
469         /* On MIPS n64 we use the same ABI for JIT method calls as for
470            native method calls. */
471
472         md_param_alloc(md);
473
474 #else /* SIZEOF_VOID_P == 8 */
475
476         paramdesc *pd;
477         s4         i;
478         s4         reguse;
479         s4         stacksize;
480 # if !defined(ENABLE_SOFT_FLOAT)
481         s4         t;
482         bool       a0_is_float;
483 # endif
484
485         /* set default values */
486
487         reguse      = 0;
488         stacksize   = 0;
489 # if !defined(ENABLE_SOFT_FLOAT)
490         a0_is_float = false;
491 # endif
492
493         /* get params field of methoddesc */
494
495         pd = md->params;
496
497 # if !defined(ENABLE_SOFT_FLOAT)
498
499         for (i = 0; i < md->paramcount; i++, pd++) {
500                 t = md->paramtypes[i].type;
501
502                 if (IS_FLT_DBL_TYPE(t) &&
503                         ((i == 0) ||
504                          ((i == 1) && IS_FLT_DBL_TYPE(md->paramtypes[0].type)))) {
505                         if (IS_2_WORD_TYPE(t)) {
506                                 pd->type   = TYPE_DBL;
507                                 pd->regoff = abi_registers_float_argument[reguse];
508                                 reguse++;
509                                 stacksize += 2;
510                         }
511                         else {
512                                 pd->type   = TYPE_FLT;
513                                 pd->regoff = abi_registers_float_argument[reguse];
514                                 reguse++;
515                                 stacksize++;
516                         }
517                         md->argfltreguse = reguse;
518                         a0_is_float = true;
519                 }
520                 else {
521                         if (IS_2_WORD_TYPE(t)) {
522                                 ALIGN_2(reguse);
523                                 pd->type = TYPE_LNG;
524
525                                 if (reguse < INT_ARG_CNT) {
526                                         pd->inmemory = false;
527 #  if WORDS_BIGENDIAN == 1
528                                         pd->regoff   =
529                                                 PACK_REGS(abi_registers_integer_argument[reguse + 1],
530                                                                   abi_registers_integer_argument[reguse]);
531 #  else
532                                         pd->regoff   =
533                                                 PACK_REGS(abi_registers_integer_argument[reguse],
534                                                                   abi_registers_integer_argument[reguse + 1]);
535 #  endif
536                                         reguse += 2;
537                                         md->argintreguse = reguse;
538                                 }
539                                 else {
540                                         ALIGN_2(stacksize);
541
542                                         pd->inmemory = true;
543                                         pd->regoff   = stacksize * 4;
544                                 }
545                                 stacksize += 2;
546                         }
547                         else {
548                                 pd->type = TYPE_INT;
549
550                                 if (reguse < INT_ARG_CNT) {
551                                         pd->inmemory = false;
552                                         pd->regoff   = abi_registers_integer_argument[reguse];
553                                         reguse++;
554                                         md->argintreguse = reguse;
555                                 }
556                                 else {
557                                         pd->inmemory = true;
558                                         pd->regoff   = stacksize * 4;
559                                 }
560                                 stacksize++;
561                         }
562                 }
563         }
564
565 # else /* !defined(ENABLE_SOFT_FLOAT) */
566 #  error never actually tested!
567
568         for (i = 0; i < md->paramcount; i++, pd++) {
569                 switch (md->paramtypes[i].type) {
570                 case TYPE_INT:
571                 case TYPE_ADR:
572                 case TYPE_FLT:
573                         pd->type = TYPE_INT;
574
575                         if (i < INT_ARG_CNT) {
576                                 pd->inmemory = false;
577                                 pd->regoff   = abi_registers_integer_argument[reguse];
578                                 reguse++;
579                                 md->argintreguse = reguse;
580                         }
581                         else {
582                                 pd->inmemory = true;
583                                 pd->regoff   = stacksize * 4;
584                         }
585                         stacksize++;
586                         break;
587                 case TYPE_LNG:
588                 case TYPE_DBL:
589                         pd->type = TYPE_LNG;
590
591                         if (i < INT_ARG_CNT) {
592                                 pd->inmemory = false;
593 #  if WORDS_BIGENDIAN == 1
594                                 pd->regoff   =
595                                         PACK_REGS(abi_registers_integer_argument[reguse + 1],
596                                                           abi_registers_integer_argument[reguse]);
597 #  else
598                                 pd->regoff   =
599                                         PACK_REGS(abi_registers_integer_argument[reguse],
600                                                           abi_registers_integer_argument[reguse + 1]);
601 #  endif
602                                 reguse += 2;
603                                 md->argintreguse = reguse;
604                         }
605                         else {
606                                 pd->inmemory = true;
607                                 pd->regoff   = stacksize * 4;
608                         }
609                         stacksize += 2;
610                         break;
611                 }
612         }
613
614 # endif /* !defined(ENABLE_SOFT_FLOAT) */
615
616         /* fill register and stack usage */
617
618         md->memuse = stacksize;
619
620 #endif /* SIZEOF_VOID_P == 8 */
621 }
622
623
624 /* md_return_alloc *************************************************************
625
626    Precolor the Java Stackelement containing the Return Value. Since
627    mips has a dedicated return register (not an reused arg or reserved
628    reg), this is striaghtforward possible, as long, as this
629    stackelement does not have to survive a method invokation
630    (SAVEDVAR)
631
632    --- in
633    jd:                      jitdata of the current method
634    stackslot:               Java Stackslot to contain the Return Value
635    
636    --- out
637    if precoloring was possible:
638    VAR(stackslot->varnum)->flags       = PREALLOC
639                                      ->regoff      = [REG_RESULT|REG_FRESULT]
640
641 *******************************************************************************/
642
643 void md_return_alloc(jitdata *jd, stackelement_t *stackslot)
644 {
645         methodinfo *m;
646         methoddesc *md;
647
648         /* get required compiler data */
649
650         m = jd->m;
651
652         md = m->parseddesc;
653
654         /* Only precolor the stackslot, if it is not a SAVEDVAR <-> has
655            not to survive method invokations. */
656
657         if (!(stackslot->flags & SAVEDVAR)) {
658                 VAR(stackslot->varnum)->flags = PREALLOC;
659
660                 if (IS_INT_LNG_TYPE(md->returntype.type)) {
661 #if SIZEOF_VOID_P == 4
662                         if (IS_2_WORD_TYPE(md->returntype.type))
663                                 VAR(stackslot->varnum)->vv.regoff = REG_RESULT_PACKED;
664                         else
665 #endif
666                                 VAR(stackslot->varnum)->vv.regoff = REG_RESULT;
667                 }
668                 else
669                         VAR(stackslot->varnum)->vv.regoff = REG_FRESULT;
670         }
671 }
672
673
674 /*
675  * These are local overrides for various environment variables in Emacs.
676  * Please do not remove this and leave it at the end of the file, where
677  * Emacs will automagically detect them.
678  * ---------------------------------------------------------------------
679  * Local variables:
680  * mode: c
681  * indent-tabs-mode: t
682  * c-basic-offset: 4
683  * tab-width: 4
684  * End:
685  */