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