* src/vm/jit/powerpc64/emit.c (emit_load): New function.
[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    XXX
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                 d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
215                 s1 = emit_load_s1(jd, iptr, src, d);
216
217                 if (IS_FLT_DBL_TYPE(src->type))
218                         M_FLTMOVE(s1, d);
219                 else
220                         M_INTMOVE(s1, d);
221
222                 emit_store(jd, iptr, dst, d);
223         }
224 }
225
226
227 /* emit_iconst *****************************************************************
228
229    XXX
230
231 *******************************************************************************/
232
233 void emit_iconst(codegendata *cd, s4 d, s4 value)
234 {
235         s4 disp;
236
237         if ((value >= -32768) && (value <= 32767))
238                 M_LDA_INTERN(d, REG_ZERO, value);
239         else {
240                 disp = dseg_adds4(cd, value);
241                 M_ILD(d, REG_PV, disp);
242         }
243 }
244
245
246 /* emit_verbosecall_enter ******************************************************
247  *
248  *    Generates the code for the call trace.
249  *
250  ********************************************************************************/
251
252 void emit_verbosecall_enter (jitdata *jd)
253 {
254         methodinfo   *m;
255         codegendata  *cd;
256         registerdata *rd;
257         s4 s1, p, t, d;
258 /*      int stack_off; */
259         int stack_size;
260         methoddesc *md;
261
262         /* get required compiler data */
263
264         m  = jd->m;
265         cd = jd->cd;
266         rd = jd->rd;
267
268         md = m->parseddesc;
269         
270         /* Build up Stackframe for builtin_trace_args call (a multiple of 16) */
271         /* For Darwin:                                                        */
272         /* TODO                                                               */
273         /* For Linux:                                                         */
274         /* setup stack for TRACE_ARGS_NUM registers                           */
275         /* == LA_SIZE + PA_SIZE + 8 (methodinfo argument) + TRACE_ARGS_NUM*8 + 8 (itmp1)              */
276         
277         /* in nativestubs no Place to save the LR (Link Register) would be needed */
278         /* but since the stack frame has to be aligned the 4 Bytes would have to  */
279         /* be padded again */
280
281 #if defined(__DARWIN__)
282         stack_size = LA_SIZE + (TRACE_ARGS_NUM + 1) * 8;
283 #else
284         stack_size = LA_SIZE + PA_SIZE + 8 + TRACE_ARGS_NUM * 8 + 8;
285 #endif
286
287         /* mark trace code */
288         M_NOP;
289
290         /* save up to TRACE_ARGS_NUM arguments into the reserved stack space */
291 #if 0
292 #if defined(__DARWIN__)
293         /* Copy Params starting from first to Stack                          */
294         /* since TRACE_ARGS == INT_ARG_CNT all used integer argument regs    */ 
295         /* are saved                                                         */
296         p = 0;
297 #else
298         /* Copy Params starting from fifth to Stack (INT_ARG_CNT/2) are in   */
299         /* integer argument regs                                             */
300         /* all integer argument registers have to be saved                   */
301         for (p = 0; p < 8; p++) {
302                 d = rd->argintregs[p];
303                 /* save integer argument registers */
304                 M_LST(d, REG_SP, LA_SIZE + PA_SIZE + 4 * 8 + 8 + p * 8);
305         }
306         p = 4;
307 #endif
308 #endif
309         M_MFLR(REG_ZERO);
310         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
311         M_STDU(REG_SP, REG_SP, -stack_size);
312
313         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
314                 t = md->paramtypes[p].type;
315                 if (IS_INT_LNG_TYPE(t)) {
316                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
317                                 M_LST(rd->argintregs[md->params[p].regoff], REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
318                         } else { /* Param on Stack */
319                                 s1 = (md->params[p].regoff + cd->stackframesize) * 8 + stack_size;
320                                 M_LLD(REG_ITMP2, REG_SP, s1);
321                                 M_LST(REG_ITMP2, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
322                         }
323                 } else { /* IS_FLT_DBL_TYPE(t) */
324                         if (!md->params[p].inmemory) { /* in Arg Reg */
325                                 s1 = rd->argfltregs[md->params[p].regoff];
326                                 M_DST(s1, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
327                         } else { /* on Stack */
328                                 /* this should not happen */
329                                 assert(0);
330                         }
331                 }
332         }
333
334         /* load first 4 (==INT_ARG_CNT/2) arguments into integer registers */
335 #if defined(__DARWIN__)
336         for (p = 0; p < 8; p++) {
337                 d = rd->argintregs[p];
338                 M_ILD(d, REG_SP, LA_SIZE + p * 4);
339         }
340 #else
341         /* LINUX */
342         /* Set integer and float argument registers for trace_args call */
343         /* offset to saved integer argument registers                   */
344         for (p = 0; (p < TRACE_ARGS_NUM) && (p < md->paramcount); p++) {
345                 t = md->paramtypes[p].type;
346                 if (IS_INT_LNG_TYPE(t)) {
347                         M_LLD(rd->argintregs[p], REG_SP,LA_SIZE + PA_SIZE + 8 + p * 8);
348                 } else { /* Float/Dbl */
349                         if (!md->params[p].inmemory) { /* Param in Arg Reg */
350                                 /* use reserved Place on Stack (sp + 5 * 16) to copy  */
351                                 /* float/double arg reg to int reg                    */
352                                 s1 = rd->argfltregs[md->params[p].regoff];
353                                 M_MOV(s1, rd->argintregs[p]);
354                         } else  {
355                                 assert(0);
356                         }
357                 }
358         }
359 #endif
360
361         /* put methodinfo pointer on Stackframe */
362         p = dseg_addaddress(cd, m);
363         M_ALD(REG_ITMP1, REG_PV, p);
364 #if defined(__DARWIN__)
365         M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
366 #else
367         if (TRACE_ARGS_NUM == 8)        {
368                 /* need to pass via stack */
369                 M_AST(REG_ITMP1, REG_SP, LA_SIZE + PA_SIZE);
370         } else {
371                 /* pass via register, reg 3 is the first  */
372                 M_MOV(REG_ITMP1, 3 + TRACE_ARGS_NUM);
373         }
374 #endif
375         /* call via function descriptor */
376         /* XXX: what about TOC? */
377         p = dseg_addaddress(cd, builtin_trace_args);
378         M_ALD(REG_ITMP2, REG_PV, p);
379         M_ALD(REG_ITMP1, REG_ITMP2, 0);
380         M_MTCTR(REG_ITMP1);
381         M_JSR;
382
383 #if defined(__DARWIN__)
384         /* restore integer argument registers from the reserved stack space */
385
386         stack_off = LA_SIZE;
387         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++, stack_off += 8) {
388                 t = md->paramtypes[p].type;
389
390                 if (IS_INT_LNG_TYPE(t)) {
391                         if (!md->params[p].inmemory) {
392                                 M_LLD(rd->argintregs[md->params[p].regoff], REG_SP, stack_off);
393                         } else  {
394                                 assert(0);
395                         }
396                 }
397         }
398 #else
399         /* LINUX */
400         for (p = 0; p < md->paramcount && p < TRACE_ARGS_NUM; p++) {
401                 d = rd->argintregs[p];
402                 /* restore integer argument registers */
403                 M_LLD(d, REG_SP, LA_SIZE + PA_SIZE + 8 + p * 8);
404         }
405 #endif
406         M_ALD(REG_ZERO, REG_SP, stack_size + LA_LR_OFFSET);
407         M_MTLR(REG_ZERO);
408         M_LDA(REG_SP, REG_SP, stack_size);
409
410         /* mark trace code */
411         M_NOP;
412 }
413
414
415 /* emit_verbosecall_exit ******************************************************
416  *
417  *    Generates the code for the call trace.
418  *
419  ********************************************************************************/
420
421 void emit_verbosecall_exit(jitdata *jd)
422 {
423         codegendata *cd = jd->cd;
424         s4 disp;
425
426         /* mark trace code */
427         M_NOP;
428
429         M_MFLR(REG_ZERO);
430         M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
431         M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
432         M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
433         M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
434
435 #if defined(__DARWIN__)
436         M_MOV(REG_RESULT, jd->rd->argintregs[1]);
437 #else
438         M_MOV(REG_RESULT, jd->rd->argintregs[1]);
439 #endif
440
441         disp = dseg_addaddress(cd, jd->m);
442         M_ALD(jd->rd->argintregs[0], REG_PV, disp);
443
444         M_FLTMOVE(REG_FRESULT, jd->rd->argfltregs[0]);
445         M_FLTMOVE(REG_FRESULT, jd->rd->argfltregs[1]);
446         disp = dseg_addaddress(cd, builtin_displaymethodstop);
447         /* call via function descriptor, XXX: what about TOC ? */
448         M_ALD(REG_ITMP2, REG_PV, disp);
449         M_ALD(REG_ITMP2, REG_ITMP2, 0);
450         M_MTCTR(REG_ITMP2);
451         M_JSR;
452
453         M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
454         M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+1*8);
455         M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+2*8);
456         M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
457         M_MTLR(REG_ZERO);
458
459         /* mark trace code */
460         M_NOP;
461 }
462
463
464
465 /*
466  * These are local overrides for various environment variables in Emacs.
467  * Please do not remove this and leave it at the end of the file, where
468  * Emacs will automagically detect them.
469  * ---------------------------------------------------------------------
470  * Local variables:
471  * mode: c
472  * indent-tabs-mode: t
473  * c-basic-offset: 4
474  * tab-width: 4
475  * End:
476  * vim:noexpandtab:sw=4:ts=4:
477  */