Proper x86_64 mnemonics
[cacao.git] / src / vm / jit / powerpc / linux / md-abi.c
1 /* src/vm/jit/powerpc/linux/md-abi.c - functions for PowerPC Linux 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 <assert.h>
29 #include <stdint.h>
30
31 #include "vm/jit/powerpc/linux/md-abi.h"
32
33 #include "vm/global.h"
34
35 #include "vm/jit/abi.h"
36 #include "vm/jit/stack.h"
37
38 #include "vmcore/descriptor.h"
39
40
41 /* register descripton arrays *************************************************/
42
43 int nregdescint[] = {
44         /* zero,      sp, NO(sys),   a0/v0,   a1/v1,      a2,      a3,      a4,   */
45         REG_RES, REG_RES, REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
46
47         /*   a5,      a6,      a7,   itmp1,   itmp2,      pv,      s0,      s1,   */
48         REG_ARG, REG_ARG, REG_ARG, REG_RES, REG_RES, REG_RES, REG_SAV, REG_SAV,
49
50         /*itmp3,      t0,      t1,      t2,      t3,      t4,      t5,      t6,   */
51         REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
52
53         /*   s2,      s3,      s4,      s5,      s6,      s7,      s8,      s9,   */
54         REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
55
56         REG_END
57 };
58
59 const char *abi_registers_integer_name[] = {
60         "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7",
61         "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15",
62         "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
63         "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
64 };
65
66 const int abi_registers_integer_argument[] = {
67         3,  /* a0 */
68         4,  /* a1 */
69         5,  /* a2 */
70         6,  /* a3 */
71         7,  /* a4 */
72         8,  /* a5 */
73         9,  /* a6 */
74         10, /* a7 */
75 };
76
77 const int abi_registers_integer_saved[] = {
78         14, /* s0 */
79         15, /* s1 */
80         24, /* s2 */
81         25, /* s3 */
82         26, /* s4 */
83         27, /* s5 */
84         28, /* s6 */
85         29, /* s7 */
86         30, /* s8 */
87         31, /* s9 */
88 };
89
90 const int abi_registers_integer_temporary[] = {
91         17, /* t0 */
92         18, /* t1 */
93         19, /* t2 */
94         20, /* t3 */
95         21, /* t4 */
96         22, /* t5 */
97         23, /* t6 */
98 };
99
100
101 int nregdescfloat[] = {
102         /*ftmp3,  fa0/v0,     fa1,     fa2,     fa3,     fa4,     fa5,     fa6,   */
103         REG_RES, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG, REG_ARG,
104
105         /*  fa7,     ft0,     ft1,     ft2,     ft3,     ft4,     fs0,     fs1,   */
106         REG_ARG, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_SAV, REG_SAV,
107
108         /*ftmp1,   ftmp2,     ft5,     ft6,     ft7,     ft8,     ft9,    ft10,   */
109         REG_RES, REG_RES, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP, REG_TMP,
110
111         /*  fs2,     fs3,     fs4,     fs5,     fs6,     fs7,     fs8,     fs9    */
112         REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV, REG_SAV,
113
114         REG_END
115 };
116
117
118 const int abi_registers_float_argument[] = {
119         1,  /* fa0  */
120         2,  /* fa1  */
121         3,  /* fa2  */
122         4,  /* fa3  */
123         5,  /* fa4  */
124         6,  /* fa5  */
125         7,  /* fa6  */
126         8,  /* fa7  */
127 };
128
129 const int abi_registers_float_saved[] = {
130         14, /* fs0  */
131         15, /* fs1  */
132         24, /* fs2  */
133         25, /* fs3  */
134         26, /* fs4  */
135         27, /* fs5  */
136         28, /* fs6  */
137         29, /* fs7  */
138         30, /* fs8  */
139         31, /* fs9  */
140 };
141
142 const int abi_registers_float_temporary[] = {
143         9,  /* ft0  */
144         10, /* ft1  */
145         11, /* ft2  */
146         12, /* ft3  */
147         13, /* ft4  */
148         18, /* ft5  */
149         19, /* ft6  */
150         20, /* ft7  */
151         21, /* ft8  */
152         22, /* ft9  */
153         23, /* ft10 */
154 };
155
156
157 /* md_param_alloc **************************************************************
158
159    Allocate Arguments to Stackslots according the Calling Conventions
160
161    --- in
162    md->paramcount:           Number of arguments for this method
163    md->paramtypes[].type:    Argument types
164
165    --- out
166    md->params[].inmemory:    Argument spilled on stack
167    md->params[].regoff:      Stack offset or rd->arg[int|flt]regs index
168    md->memuse:               Stackslots needed for argument spilling
169    md->argintreguse:         max number of integer arguments used
170    md->argfltreguse:         max number of float arguments used
171
172 *******************************************************************************/
173
174 void md_param_alloc(methoddesc *md)
175 {
176         paramdesc *pd;
177         int        i;
178         int        iarg;
179         int        farg;
180         int        stacksize;
181
182         /* set default values */
183
184         iarg = 0;
185         farg = 0;
186         stacksize = LA_SIZE_IN_POINTERS;
187
188         /* get params field of methoddesc */
189
190         pd = md->params;
191
192         for (i = 0; i < md->paramcount; i++, pd++) {
193                 switch (md->paramtypes[i].type) {
194                 case TYPE_INT:
195                 case TYPE_ADR:
196                         if (iarg < INT_ARG_CNT) {
197                                 pd->inmemory = false;
198                                 pd->index    = iarg;
199                                 pd->regoff   = abi_registers_integer_argument[iarg];
200                                 iarg++;
201                         }
202                         else {
203                                 pd->inmemory = true;
204                                 pd->index    = stacksize;
205                                 pd->regoff   = stacksize * 8;
206                                 stacksize++;
207                         }
208                         break;
209
210                 case TYPE_LNG:
211                         if (iarg < INT_ARG_CNT - 1) {
212                                 ALIGN_2(iarg);
213                                 pd->inmemory = false;
214                                 pd->index    = PACK_REGS(iarg + 1, iarg);
215                                 pd->regoff   =
216                                         PACK_REGS(abi_registers_integer_argument[iarg + 1],
217                                                           abi_registers_integer_argument[iarg]);
218                                 iarg += 2;
219                         }
220                         else {
221                                 pd->inmemory = true;
222                                 pd->index    = stacksize;
223                                 pd->regoff   = stacksize * 8;
224                                 iarg         = INT_ARG_CNT;
225                                 stacksize++;
226                         }
227                         break;
228
229                 case TYPE_FLT:
230                 case TYPE_DBL:
231                         if (farg < FLT_ARG_CNT) {
232                                 pd->inmemory = false;
233                                 pd->index    = farg;
234                                 pd->regoff   = abi_registers_float_argument[farg];
235                                 farg++;
236                         }
237                         else {
238                                 pd->inmemory = true;
239                                 pd->index    = stacksize;
240                                 pd->regoff   = stacksize * 8;
241                                 stacksize++;
242                         }
243                         break;
244
245                 default:
246                         assert(0);
247                 }
248         }
249
250         /* Since R3/R4, F1 (==A0/A1, A0) are used for passing return
251            values, this argument register usage has to be regarded,
252            too. */
253
254         if (IS_INT_LNG_TYPE(md->returntype.type)) {
255                 if (iarg < (IS_2_WORD_TYPE(md->returntype.type) ? 2 : 1))
256                         iarg = IS_2_WORD_TYPE(md->returntype.type) ? 2 : 1;
257         }
258         else {
259                 if (IS_FLT_DBL_TYPE(md->returntype.type))
260                         if (farg < 1)
261                                 farg = 1;
262         }
263
264         /* fill register and stack usage */
265
266         md->argintreguse = iarg;
267         md->argfltreguse = farg;
268         md->memuse       = stacksize;
269 }
270
271
272 /* md_param_alloc_native *******************************************************
273
274    Pre-allocate arguments according the native ABI.
275
276 *******************************************************************************/
277
278 void md_param_alloc_native(methoddesc *md)
279 {
280         paramdesc *pd;
281         int        i;
282         int        iarg;
283         int        farg;
284         int        stacksize;
285
286         /* set default values */
287
288         iarg = 0;
289         farg = 0;
290         stacksize = LA_SIZE_IN_POINTERS;
291
292         /* get params field of methoddesc */
293
294         pd = md->params;
295
296         for (i = 0; i < md->paramcount; i++, pd++) {
297                 switch (md->paramtypes[i].type) {
298                 case TYPE_INT:
299                 case TYPE_ADR:
300                         if (iarg < INT_ARG_CNT) {
301                                 pd->inmemory  = false;
302                                 pd->regoff    = abi_registers_integer_argument[iarg];
303                                 iarg++;
304                         }
305                         else {
306                                 pd->inmemory  = true;
307                                 pd->regoff    = stacksize * 4;
308                                 stacksize++;
309                         }
310                         break;
311
312                 case TYPE_LNG:
313                         if (iarg < INT_ARG_CNT - 1) {
314                                 ALIGN_2(iarg);
315                                 pd->inmemory  = false;
316                                 pd->regoff    =
317                                         PACK_REGS(abi_registers_integer_argument[iarg + 1],
318                                                           abi_registers_integer_argument[iarg]);
319                                 iarg += 2;
320                         }
321                         else {
322                                 ALIGN_2(stacksize);
323                                 pd->inmemory  = true;
324                                 pd->regoff    = stacksize * 4;
325                                 iarg          = INT_ARG_CNT;
326                                 stacksize    += 2;
327                         }
328                         break;
329
330                 case TYPE_FLT:
331                         if (farg < FLT_ARG_CNT) {
332                                 pd->inmemory  = false;
333                                 pd->regoff    = abi_registers_float_argument[farg];
334                                 farg++;
335                         }
336                         else {
337                                 pd->inmemory  = true;
338                                 pd->regoff    = stacksize * 4;
339                                 stacksize++;
340                         }
341                         break;
342
343                 case TYPE_DBL:
344                         if (farg < FLT_ARG_CNT) {
345                                 pd->inmemory  = false;
346                                 pd->regoff    = abi_registers_float_argument[farg];
347                                 farg++;
348                         }
349                         else {
350                                 ALIGN_2(stacksize);
351                                 pd->inmemory  = true;
352                                 pd->regoff    = stacksize * 4;
353                                 stacksize    += 2;
354                         }
355                         break;
356
357                 default:
358                         assert(0);
359                 }
360         }
361
362         /* Since R3/R4, F1 (==A0/A1, A0) are used for passing return
363            values, this argument register usage has to be regarded,
364            too. */
365
366         if (IS_INT_LNG_TYPE(md->returntype.type)) {
367                 if (iarg < (IS_2_WORD_TYPE(md->returntype.type) ? 2 : 1))
368                         iarg = IS_2_WORD_TYPE(md->returntype.type) ? 2 : 1;
369         }
370         else {
371                 if (IS_FLT_DBL_TYPE(md->returntype.type))
372                         if (farg < 1)
373                                 farg = 1;
374         }
375
376         /* fill register and stack usage */
377
378         md->argintreguse = iarg;
379         md->argfltreguse = farg;
380         md->memuse       = stacksize;
381 }
382
383
384 /* md_return_alloc *************************************************************
385
386    Precolor the Java Stackelement containing the Return Value, if
387    possible.  (R3==a00 for int/adr, R4/R3 == a01/a00 for long, F1==a00
388    for float/double)
389
390    --- in
391    jd:                      jitdata of the current method
392    stackslot:               Java Stackslot to contain the Return Value
393
394    --- out
395    if precoloring was possible:
396    VAR(stackslot->varnum)->flags       = PREALLOC
397                                      ->regoff      = [REG_RESULT|REG_FRESULT]
398    rd->arg[flt|int]reguse   set to a value according the register usage
399
400    NOTE: Do not pass a LOCALVAR in stackslot->varnum.
401
402 *******************************************************************************/
403
404 void md_return_alloc(jitdata *jd, stackelement_t *stackslot)
405 {
406         methodinfo   *m;
407         codeinfo     *code;
408         registerdata *rd;
409         methoddesc   *md;
410         varinfo      *v;
411
412         /* get required compiler data */
413
414         m    = jd->m;
415         code = jd->code;
416         rd   = jd->rd;
417
418         md = m->parseddesc;
419
420         /* In Leafmethods Local Vars holding parameters are precolored to
421            their argument register -> so leafmethods with paramcount > 0
422            could already use R3 == a00! */
423
424         if (!code_is_leafmethod(code) || (md->paramcount == 0)) {
425                 /* Only precolor the stackslot, if it is not a SAVEDVAR <->
426                    has not to survive method invokations. */
427
428                 if (!(stackslot->flags & SAVEDVAR)) {
429                         v = VAR(stackslot->varnum);
430                         v->flags = PREALLOC;
431
432                         switch (md->returntype.type) {
433                         case TYPE_INT:
434                         case TYPE_ADR:
435                                 if (rd->argintreguse < 1)
436                                         rd->argintreguse = 1;
437
438                                 v->vv.regoff = REG_RESULT;
439                                 break;
440
441                         case TYPE_LNG:
442                                 if (rd->argintreguse < 2)
443                                         rd->argintreguse = 2;
444
445                                 v->vv.regoff = REG_RESULT_PACKED;
446                                 break;
447
448                         case TYPE_FLT:
449                         case TYPE_DBL:
450                                 if (rd->argfltreguse < 1)
451                                         rd->argfltreguse = 1;
452                                 
453                                 v->vv.regoff = REG_FRESULT;
454                                 break;
455                         }
456                 }
457         }
458 }
459
460
461 /*
462  * These are local overrides for various environment variables in Emacs.
463  * Please do not remove this and leave it at the end of the file, where
464  * Emacs will automagically detect them.
465  * ---------------------------------------------------------------------
466  * Local variables:
467  * mode: c
468  * indent-tabs-mode: t
469  * c-basic-offset: 4
470  * tab-width: 4
471  * End:
472  */