* src/vm/jit/powerpc64/emit.c (emit_copy): Eliminate register move if
[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
44 #include "vm/jit/emit.h"
45 #include "vm/jit/jit.h"
46 #include "vm/jit/powerpc64/codegen.h"
47 #include "vm/builtin.h"
48
49
50 /* code generation functions **************************************************/
51
52 /* emit_load *******************************************************************
53
54    Emits a possible load of an operand.
55
56 *******************************************************************************/
57
58 s4 emit_load(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
59 {
60         codegendata  *cd;
61         s4            disp;
62         s4            reg;
63
64         /* get required compiler data */
65
66         cd = jd->cd;
67
68         if (src->flags & INMEMORY) {
69                 COUNT_SPILLS;
70
71                 disp = src->regoff * 8;
72
73                 if (IS_FLT_DBL_TYPE(src->type)) {
74                         if (IS_2_WORD_TYPE(src->type))
75                                 M_DLD(tempreg, REG_SP, disp);
76                         else
77                                 M_FLD(tempreg, REG_SP, disp);
78
79                 } else {
80                         if (IS_2_WORD_TYPE(src->type))
81                                 M_LLD(tempreg, REG_SP, disp);
82                         else
83                                 M_ILD(tempreg, REG_SP, disp);
84                 }
85
86                 reg = tempreg;
87         } else
88                 reg = src->regoff;
89
90         return reg;
91 }
92
93
94 /* emit_load_s1 ****************************************************************
95
96    Emits a possible load of the first source operand.
97
98 *******************************************************************************/
99
100 s4 emit_load_s1(jitdata *jd, instruction *iptr, s4 tempreg)
101 {
102         stackptr src;
103         s4       reg;
104
105         src = iptr->s1.var;
106
107         reg = emit_load(jd, iptr, src, tempreg);
108
109         return reg;
110 }
111
112
113 /* emit_load_s2 ****************************************************************
114
115    Emits a possible load of the second source operand.
116
117 *******************************************************************************/
118
119 s4 emit_load_s2(jitdata *jd, instruction *iptr, s4 tempreg)
120 {
121         stackptr src;
122         s4       reg;
123
124         src = iptr->sx.s23.s2.var;
125
126         reg = emit_load(jd, iptr, src, tempreg);
127
128         return reg;
129 }
130
131
132 /* emit_load_s3 ****************************************************************
133
134    Emits a possible load of the third source operand.
135
136 *******************************************************************************/
137
138 s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg)
139 {
140         stackptr src;
141         s4       reg;
142
143         src = iptr->sx.s23.s3.var;
144
145         reg = emit_load(jd, iptr, src, tempreg);
146
147         return reg;
148 }
149
150
151
152 /* emit_store ******************************************************************
153
154    Emits a possible store to a variable.
155
156 *******************************************************************************/
157
158 void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
159 {
160         codegendata  *cd;
161
162         /* get required compiler data */
163
164         cd = jd->cd;
165
166         if (dst->flags & INMEMORY) {
167                 COUNT_SPILLS;
168
169                 if (IS_FLT_DBL_TYPE(dst->type)) {
170                         if (IS_2_WORD_TYPE(dst->type))
171                                 M_DST(d, REG_SP, dst->regoff * 8);
172                         else
173                                 M_FST(d, REG_SP, dst->regoff * 8);
174
175                 } else {
176                         M_LST(d, REG_SP, dst->regoff * 8);
177                 }
178         }
179 }
180
181
182 /* emit_store_dst **************************************************************
183
184    Emits a possible store to the destination operand of an instruction.
185
186 *******************************************************************************/
187
188 void emit_store_dst(jitdata *jd, instruction *iptr, s4 d)
189 {
190         emit_store(jd, iptr, iptr->dst.var, d);
191 }
192
193
194 /* emit_copy *******************************************************************
195
196    Generates a register/memory to register/memory copy.
197
198 *******************************************************************************/
199
200 void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
201 {
202         codegendata  *cd;
203         registerdata *rd;
204         s4            s1, d;
205
206         /* get required compiler data */
207
208         cd = jd->cd;
209         rd = jd->rd;
210
211         if ((src->regoff != dst->regoff) ||
212                 ((src->flags ^ dst->flags) & INMEMORY)) {
213
214                 /* If one of the variables resides in memory, we can eliminate
215                    the register move from/to the temporary register with the
216                    order of getting the destination register and the load. */
217
218                 if (IS_INMEMORY(src->flags)) {
219                         d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
220                         s1 = emit_load(jd, iptr, src, d);
221                 }
222                 else {
223                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
224                         d = codegen_reg_of_var(rd, iptr->opc, dst, s1);
225                 }
226
227                 if (s1 != d) {
228                         if (IS_FLT_DBL_TYPE(src->type))
229                                 M_FMOV(s1, d);
230                         else
231                                 M_MOV(s1, d);
232                 }
233
234                 emit_store(jd, iptr, dst, d);
235         }
236 }
237
238
239 /* emit_iconst *****************************************************************
240
241    XXX
242
243 *******************************************************************************/
244
245 void emit_iconst(codegendata *cd, s4 d, s4 value)
246 {
247         s4 disp;
248
249         if ((value >= -32768) && (value <= 32767))
250                 M_LDA_INTERN(d, REG_ZERO, value);
251         else {
252                 disp = dseg_adds4(cd, value);
253                 M_ILD(d, REG_PV, disp);
254         }
255 }
256
257
258 /* emit_verbosecall_enter ******************************************************
259  *
260  *    Generates the code for the call trace.
261  *
262  ********************************************************************************/
263
264 void emit_verbosecall_enter (jitdata *jd)
265 {
266         methodinfo   *m;
267         codegendata  *cd;
268         registerdata *rd;
269         s4 s1, p, t, d;
270 /*      int stack_off; */
271         int stack_size;
272         methoddesc *md;
273
274         /* get required compiler data */
275
276         m  = jd->m;
277         cd = jd->cd;
278         rd = jd->rd;
279
280         md = m->parseddesc;
281         
282         /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
283         /* For Darwin:                                                        */
284         /* TODO                                                               */
285         /* For Linux:                                                         */
286         /* setup stack for TRACE_ARGS_NUM registers                           */
287         /* == LA_SIZE + PA_SIZE + 8 (methodinfo argument) + TRACE_ARGS_NUM*8 + 8 (itmp1)              */
288         
289         /* in nativestubs no Place to save the LR (Link Register) would be needed */
290         /* but since the stack frame has to be aligned the 4 Bytes would have to  */
291         /* be padded again */
292
293 #if defined(__DARWIN__)
294         stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
295 #else
296         stack_size = LA_SIZE + PA_SIZE + 8 + TRACE_ARGS_NUM * 8 + 8;
297 #endif
298
299         /* mark trace code */
300         M_NOP;
301
302         /* save up to TRACE_ARGS_NUM arguments into the reserved stack space */
303 #if 0
304 #if defined(__DARWIN__)
305         /* Copy Params starting from first to Stack                          */
306         /* since TRACE_ARGS == INT_ARG_CNT all used integer argument regs    */ 
307         /* are saved                                                         */
308         p = 0;
309 #else
310         /* Copy Params starting from fifth to Stack (INT_ARG_CNT/2) are in   */
311         /* integer argument regs                                             */
312         /* all integer argument registers have to be saved                   */
313         for (p = 0; p < 8; p++) {
314                 d = rd->argintregs[p];
315                 /* save integer argument registers */
316                 M_LST(d, REG_SP, LA_SIZE + PA_SIZE + 4 * 8 + 8 + p * 8);
317         }
318         p = 4;
319 #endif
320 #endif
321         M_MFLR(REG_ZERO);
322         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
323         M_STDU(REG_SP, REG_SP, -stack_size);
324
325         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
326                 t = md->paramtypes[p].type;
327                 if (IS_INT_LNG_TYPE(t)) {
328                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
329                                 M_LST(rd->argintregs[md->params[p].regoff], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
330                         } else { /* Param on Stack */
331                                 s1 = (md->params[p].regoff + cd->stackframesize) * 8 + stack_size;
332                                 M_LLD(REG_ITMP2, REG_SP, s1);
333                                 M_LST(REG_ITMP2, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
334                         }
335                 } else { /* IS_FLT_DBL_TYPE(t) */
336                         if (!md->params[p].inmemory) { /* in Arg Reg */
337                                 s1 = rd->argfltregs[md->params[p].regoff];
338                                 M_DST(s1, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
339                         } else { /* on Stack */
340                                 /* this should not happen */
341                                 assert(0);
342                         }
343                 }
344         }
345
346         /* load first 4 (==INT_ARG_CNT/2) arguments into integer registers */
347 #if defined(__DARWIN__)
348         for (p = 0; p < 8; p++) {
349                 d = rd->argintregs[p];
350                 M_ILD(d, REG_SP, LA_SIZE + p * 4);
351         }
352 #else
353         /* LINUX */
354         /* Set integer and float argument registers for trace_args call */
355         /* offset to saved integer argument registers                   */
356         for (p = 0; (p < TRACE_ARGS_NUM) && (p < md->paramcount); p++) {
357                 t = md->paramtypes[p].type;
358                 if (IS_INT_LNG_TYPE(t)) {
359                         M_LLD(rd->argintregs[p], REG_SP,LA_SIZE + PA_SIZE + 8 + p * 8);
360                 } else { /* Float/Dbl */
361                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
362                                 /* use reserved Place on Stack (sp + 5 * 16) to copy  */
363                                 /* float/double arg reg to int reg                    */
364                                 s1 = rd->argfltregs[md->params[p].regoff];
365                                 M_MOV(s1, rd->argintregs[p]);
366                         } else  {
367                                 assert(0);
368                         }
369                 }
370         }
371 #endif
372
373         /* put methodinfo pointer on Stackframe */
374         p = dseg_addaddress(cd, m);
375         M_ALD(REG_ITMP1, REG_PV, p);
376 #if defined(__DARWIN__)
377         M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
378 #else
379         if (TRACE_ARGS_NUM == 8)        {
380                 /* need to pass via stack */
381                 M_AST(REG_ITMP1, REG_SP, LA_SIZE + PA_SIZE);
382         } else {
383                 /* pass via register, reg 3 is the first  */
384                 M_MOV(REG_ITMP1, 3 + TRACE_ARGS_NUM);
385         }
386 #endif
387         /* call via function descriptor */
388         /* XXX: what about TOC? */
389         p = dseg_addaddress(cd, builtin_trace_args);
390         M_ALD(REG_ITMP2, REG_PV, p);
391         M_ALD(REG_ITMP1, REG_ITMP2, 0);
392         M_MTCTR(REG_ITMP1);
393         M_JSR;
394
395 #if defined(__DARWIN__)
396         /* restore integer argument registers from the reserved stack space */
397
398         stack_off = LA_SIZE;
399         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++, stack_off += 8) {
400                 t = md->paramtypes[p].type;
401
402                 if (IS_INT_LNG_TYPE(t)) {
403                         if (!md->params[p].inmemory) {
404                                 M_LLD(rd->argintregs[md->params[p].regoff], REG_SP, stack_off);
405                         } else  {
406                                 assert(0);
407                         }
408                 }
409         }
410 #else
411         /* LINUX */
412         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
413                 d = rd->argintregs[p];
414                 /* restore integer argument registers */
415                 M_LLD(d, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
416         }
417 #endif
418         M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
419         M_MTLR(REG_ZERO);
420         M_LDA(REG_SP, REG_SP, stack_size);
421
422         /* mark trace code */
423         M_NOP;
424 }
425
426
427 /* emit_verbosecall_exit ******************************************************
428  *
429  *    Generates the code for the call trace.
430  *
431  ********************************************************************************/
432
433 void emit_verbosecall_exit(jitdata *jd)
434 {
435         codegendata *cd = jd->cd;
436         s4 disp;
437
438         /* mark trace code */
439         M_NOP;
440
441         M_MFLR(REG_ZERO);
442         M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
443         M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
444         M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
445         M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
446
447 #if defined(__DARWIN__)
448         M_MOV(REG_RESULT, jd->rd->argintregs[1]);
449 #else
450         M_MOV(REG_RESULT, jd->rd->argintregs[1]);
451 #endif
452
453         disp = dseg_addaddress(cd, jd->m);
454         M_ALD(jd->rd->argintregs[0], REG_PV, disp);
455
456         M_FLTMOVE(REG_FRESULT, jd->rd->argfltregs[0]);
457         M_FLTMOVE(REG_FRESULT, jd->rd->argfltregs[1]);
458         disp = dseg_addaddress(cd, builtin_displaymethodstop);
459         /* call via function descriptor, XXX: what about TOC ? */
460         M_ALD(REG_ITMP2, REG_PV, disp);
461         M_ALD(REG_ITMP2, REG_ITMP2, 0);
462         M_MTCTR(REG_ITMP2);
463         M_JSR;
464
465         M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
466         M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
467         M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
468         M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
469         M_MTLR(REG_ZERO);
470
471         /* mark trace code */
472         M_NOP;
473 }
474
475
476
477 /*
478  * These are local overrides for various environment variables in Emacs.
479  * Please do not remove this and leave it at the end of the file, where
480  * Emacs will automagically detect them.
481  * ---------------------------------------------------------------------
482  * Local variables:
483  * mode: c
484  * indent-tabs-mode: t
485  * c-basic-offset: 4
486  * tab-width: 4
487  * End:
488  * vim:noexpandtab:sw=4:ts=4:
489  */