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