* src/vm/jit/powerpc64/emit.c (emit_verbosecall_enter):
[cacao.git] / src / vm / jit / powerpc64 / emit.c
1 /* src/vm/jit/powerpc64/emit.c - PowerPC code emitter functions
2
3    Copyright (C) 1996-2005, 2006 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    Contact: cacao@cacaojvm.org
26
27    Authors: Christian Thalinger
28
29    Changes:
30
31    $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $
32
33 */
34
35
36 #include "config.h"
37
38 #include <assert.h>
39
40 #include "vm/types.h"
41
42 #include "md-abi.h"
43 #include "vm/jit/powerpc64/codegen.h"
44
45 #include "vm/builtin.h"
46 #include "vm/jit/emit-common.h"
47 #include "vm/jit/jit.h"
48
49
50 /* emit_load *******************************************************************
51
52    Emits a possible load of an operand.
53
54 *******************************************************************************/
55
56 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
57 {
58         codegendata  *cd;
59         s4            disp;
60         s4            reg;
61
62         /* get required compiler data */
63
64         cd = jd->cd;
65
66         if (src->flags & INMEMORY) {
67                 COUNT_SPILLS;
68
69                 disp = src->vv.regoff * 8;
70
71                 if (IS_FLT_DBL_TYPE(src->type)) {
72                         if (IS_2_WORD_TYPE(src->type))
73                                 M_DLD(tempreg, REG_SP, disp);
74                         else
75                                 M_FLD(tempreg, REG_SP, disp);
76                 }
77                 else {
78                 /*      if (IS_2_WORD_TYPE(src->type))
79                                 M_LLD(tempreg, REG_SP, disp);
80                         else
81                                 M_ILD(tempreg, REG_SP, disp);
82                 */
83                         M_LLD(tempreg, REG_SP, disp);
84                 }
85
86                 reg = tempreg;
87         }
88         else
89                 reg = src->vv.regoff;
90
91         return reg;
92 }
93
94
95 /* emit_store ******************************************************************
96
97    Emits a possible store to a variable.
98
99 *******************************************************************************/
100
101 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
102 {
103         codegendata  *cd;
104
105         /* get required compiler data */
106
107         cd = jd->cd;
108
109         if (dst->flags & INMEMORY) {
110                 COUNT_SPILLS;
111
112                 if (IS_FLT_DBL_TYPE(dst->type)) {
113                         if (IS_2_WORD_TYPE(dst->type))
114                                 M_DST(d, REG_SP, dst->vv.regoff * 8);
115                         else
116                                 M_FST(d, REG_SP, dst->vv.regoff * 8);
117                 }
118                 else {
119                         M_LST(d, REG_SP, dst->vv.regoff * 8);
120                 }
121         }
122 }
123
124
125 /* emit_copy *******************************************************************
126
127    Generates a register/memory to register/memory copy.
128
129 *******************************************************************************/
130
131 void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
132 {
133         codegendata  *cd;
134         registerdata *rd;
135         s4            s1, d;
136
137         /* get required compiler data */
138
139         cd = jd->cd;
140         rd = jd->rd;
141
142         if ((src->vv.regoff != dst->vv.regoff) ||
143                 ((src->flags ^ dst->flags) & INMEMORY)) {
144
145                 /* If one of the variables resides in memory, we can eliminate
146                    the register move from/to the temporary register with the
147                    order of getting the destination register and the load. */
148
149                 if (IS_INMEMORY(src->flags)) {
150                         d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
151                         s1 = emit_load(jd, iptr, src, d);
152                 }
153                 else {
154                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
155                         d = codegen_reg_of_var(iptr->opc, dst, s1);
156                 }
157
158                 if (s1 != d) {
159                         if (IS_FLT_DBL_TYPE(src->type))
160                                 M_FMOV(s1, d);
161                         else
162                                 M_MOV(s1, d);
163                 }
164
165                 emit_store(jd, iptr, dst, d);
166         }
167 }
168
169
170 /* emit_iconst *****************************************************************
171
172    XXX
173
174 *******************************************************************************/
175
176 void emit_iconst(codegendata *cd, s4 d, s4 value)
177 {
178         s4 disp;
179
180         if ((value >= -32768) && (value <= 32767)) {
181                 M_LDA_INTERN(d, REG_ZERO, value);
182         } else {
183                 disp = dseg_adds4(cd, value);
184                 M_ILD(d, REG_PV, disp);
185         }
186 }
187
188 void emit_lconst(codegendata *cd, s4 d, s8 value)
189 {
190         s4 disp;
191         if ((value >= -32768) && (value <= 32767)) {
192                 M_LDA_INTERN(d, REG_ZERO, value);
193         } else {
194                 disp = dseg_adds8(cd, value);
195                 M_LLD(d, REG_PV, disp);
196         }
197 }
198
199
200 /* emit_verbosecall_enter ******************************************************
201  *
202  *    Generates the code for the call trace.
203  *
204  ********************************************************************************/
205
206 void emit_verbosecall_enter (jitdata *jd)
207 {
208         methodinfo   *m;
209         codegendata  *cd;
210         registerdata *rd;
211         s4 s1, p, t;
212         int stack_size;
213         methoddesc *md;
214
215         /* get required compiler data */
216
217         m  = jd->m;
218         cd = jd->cd;
219         rd = jd->rd;
220
221         md = m->parseddesc;
222         
223         /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
224         /* For Darwin:                                                        */
225         /* TODO                                                               */
226         /* For Linux:                                                         */
227         /* setup stack for TRACE_ARGS_NUM registers                           */
228         /* == LA_SIZE + PA_SIZE + 8 (methodinfo argument) + TRACE_ARGS_NUM*8 + 8 (itmp1)              */
229         
230         /* in nativestubs no Place to save the LR (Link Register) would be needed */
231         /* but since the stack frame has to be aligned the 4 Bytes would have to  */
232         /* be padded again */
233
234 #if defined(__DARWIN__)
235         stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
236 #else
237         stack_size = LA_SIZE + PA_SIZE + 8 + TRACE_ARGS_NUM * 8 + 8;
238 #endif
239
240         /* mark trace code */
241         M_NOP;
242
243         M_MFLR(REG_ZERO);
244         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
245         M_STDU(REG_SP, REG_SP, -stack_size);
246
247         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
248                 t = md->paramtypes[p].type;
249                 if (IS_INT_LNG_TYPE(t)) {
250                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
251                                 M_LST(rd->argintregs[md->params[p].regoff], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
252                         } else { /* Param on Stack */
253                                 s1 = (md->params[p].regoff + cd->stackframesize) * 8 + stack_size;
254                                 M_LLD(REG_ITMP2, REG_SP, s1);
255                                 M_LST(REG_ITMP2, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
256                         }
257                 } else { /* IS_FLT_DBL_TYPE(t) */
258                         if (!md->params[p].inmemory) { /* in Arg Reg */
259                                 s1 = rd->argfltregs[md->params[p].regoff];
260                                 M_DST(s1, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
261                         } else { /* on Stack */
262                                 /* this should not happen */
263                                 assert(0);
264                         }
265                 }
266         }
267
268 #if defined(__DARWIN__)
269         #warning "emit_verbosecall_enter not implemented"
270 #else
271         /* LINUX */
272         /* Set integer and float argument registers for trace_args call */
273         /* offset to saved integer argument registers                   */
274         for (p = 0; (p < TRACE_ARGS_NUM) && (p < md->paramcount); p++) {
275                 t = md->paramtypes[p].type;
276                 if (IS_INT_LNG_TYPE(t)) {
277                         M_LLD(rd->argintregs[p], REG_SP,LA_SIZE + PA_SIZE + 8 + p * 8);
278                 } else { /* Float/Dbl */
279                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
280                                 /* use reserved Place on Stack (sp + 5 * 16) to copy  */
281                                 /* float/double arg reg to int reg                    */
282                                 s1 = rd->argfltregs[md->params[p].regoff];
283                                 M_MOV(s1, rd->argintregs[p]);
284                         } else  {
285                                 assert(0);
286                         }
287                 }
288         }
289 #endif
290
291         /* put methodinfo pointer on Stackframe */
292         p = dseg_addaddress(cd, m);
293         M_ALD(REG_ITMP1, REG_PV, p);
294 #if defined(__DARWIN__)
295         M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
296 #else
297         if (TRACE_ARGS_NUM == 8)        {
298                 /* need to pass via stack */
299                 M_AST(REG_ITMP1, REG_SP, LA_SIZE + PA_SIZE);
300         } else {
301                 /* pass via register, reg 3 is the first  */
302                 M_MOV(REG_ITMP1, 3 + TRACE_ARGS_NUM);
303         }
304 #endif
305         /* call via function descriptor */
306         /* XXX: what about TOC? */
307         p = dseg_addaddress(cd, builtin_trace_args);
308         M_ALD(REG_ITMP2, REG_PV, p);
309         M_ALD(REG_ITMP1, REG_ITMP2, 0);
310         M_MTCTR(REG_ITMP1);
311         M_JSR;
312
313 #if defined(__DARWIN__)
314         #warning "emit_verbosecall_enter not implemented"
315 #else
316         /* LINUX */
317         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
318                 t = md->paramtypes[p].type;
319                 if (IS_INT_LNG_TYPE(t)) {
320                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
321                                 /* restore integer argument registers */
322                                 M_LLD(rd->argintregs[p], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
323                         } else {
324                                 assert(0);      /* TODO: implement this */
325                         }
326                 } else { /* FLT/DBL */
327                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
328                                 M_DLD(rd->argfltregs[md->params[p].regoff], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
329                         } else {
330                                 assert(0); /* this shoudl never happen */
331                         }
332                         
333                 }
334         }
335 #endif
336         M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
337         M_MTLR(REG_ZERO);
338         M_LDA(REG_SP, REG_SP, stack_size);
339
340         /* mark trace code */
341         M_NOP;
342 }
343
344
345 /* emit_verbosecall_exit ******************************************************
346  *
347  *    Generates the code for the call trace.
348  *
349  ********************************************************************************/
350
351 void emit_verbosecall_exit(jitdata *jd)
352 {
353         codegendata *cd = jd->cd;
354         s4 disp;
355
356         /* mark trace code */
357         M_NOP;
358
359         M_MFLR(REG_ZERO);
360         M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
361         M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
362         M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
363         M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
364
365 #if defined(__DARWIN__)
366         M_MOV(REG_RESULT, jd->rd->argintregs[1]);
367 #else
368         M_MOV(REG_RESULT, jd->rd->argintregs[1]);
369 #endif
370
371         disp = dseg_addaddress(cd, jd->m);
372         M_ALD(jd->rd->argintregs[0], REG_PV, disp);
373
374         M_FLTMOVE(REG_FRESULT, jd->rd->argfltregs[0]);
375         M_FLTMOVE(REG_FRESULT, jd->rd->argfltregs[1]);
376         disp = dseg_addaddress(cd, builtin_displaymethodstop);
377         /* call via function descriptor, XXX: what about TOC ? */
378         M_ALD(REG_ITMP2, REG_PV, disp);
379         M_ALD(REG_ITMP2, REG_ITMP2, 0);
380         M_MTCTR(REG_ITMP2);
381         M_JSR;
382
383         M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
384         M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
385         M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
386         M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
387         M_MTLR(REG_ZERO);
388
389         /* mark trace code */
390         M_NOP;
391 }
392
393
394
395 /*
396  * These are local overrides for various environment variables in Emacs.
397  * Please do not remove this and leave it at the end of the file, where
398  * Emacs will automagically detect them.
399  * ---------------------------------------------------------------------
400  * Local variables:
401  * mode: c
402  * indent-tabs-mode: t
403  * c-basic-offset: 4
404  * tab-width: 4
405  * End:
406  * vim:noexpandtab:sw=4:ts=4:
407  */