* src/vm/jit/mips/emit.c (emit_copy): Eliminate register move if one
[cacao.git] / src / vm / jit / mips / emit.c
1 /* src/vm/jit/mips/emit.c - MIPS 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 "vm/types.h"
39
40 #include "md-abi.h"
41
42 #include "vm/jit/mips/codegen.h"
43
44 #if defined(ENABLE_THREADS)
45 # include "threads/native/lock.h"
46 #endif
47
48 #include "vm/exceptions.h"
49 #include "vm/stringlocal.h" /* XXX for gen_resolvebranch */
50 #include "vm/jit/abi-asm.h"
51 #include "vm/jit/asmpart.h"
52 #include "vm/jit/dseg.h"
53 #include "vm/jit/emit.h"
54 #include "vm/jit/jit.h"
55 #include "vm/jit/replace.h"
56
57
58 /* code generation functions **************************************************/
59
60 /* emit_load *******************************************************************
61
62    Emits a possible load of an operand.
63
64 *******************************************************************************/
65
66 s4 emit_load(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
67 {
68         codegendata  *cd;
69         s4            disp;
70         s4            reg;
71
72         /* get required compiler data */
73
74         cd = jd->cd;
75
76         if (src->flags & INMEMORY) {
77                 COUNT_SPILLS;
78
79                 disp = src->regoff * 8;
80
81                 if (IS_FLT_DBL_TYPE(src->type)) {
82                         if (IS_2_WORD_TYPE(src->type))
83                                 M_DLD(tempreg, REG_SP, disp);
84                         else
85                                 M_FLD(tempreg, REG_SP, disp);
86                 }
87                 else
88                         M_LLD(tempreg, REG_SP, disp);
89
90                 reg = tempreg;
91         }
92         else
93                 reg = src->regoff;
94
95         return reg;
96 }
97
98 /* emit_load_s1 ****************************************************************
99
100    Emits a possible load of the first source operand.
101
102 *******************************************************************************/
103
104 s4 emit_load_s1(jitdata *jd, instruction *iptr, s4 tempreg)
105 {
106         stackptr src;
107         s4       reg;
108
109         src = iptr->s1.var;
110
111         reg = emit_load(jd, iptr, src, tempreg);
112
113         return reg;
114 }
115
116
117 /* emit_load_s2 ****************************************************************
118
119    Emits a possible load of the second source operand.
120
121 *******************************************************************************/
122
123 s4 emit_load_s2(jitdata *jd, instruction *iptr, s4 tempreg)
124 {
125         stackptr src;
126         s4       reg;
127
128         src = iptr->sx.s23.s2.var;
129
130         reg = emit_load(jd, iptr, src, tempreg);
131
132         return reg;
133 }
134
135
136 /* emit_load_s3 ****************************************************************
137
138    Emits a possible load of the third source operand.
139
140 *******************************************************************************/
141
142 s4 emit_load_s3(jitdata *jd, instruction *iptr, s4 tempreg)
143 {
144         stackptr src;
145         s4       reg;
146
147         src = iptr->sx.s23.s3.var;
148
149         reg = emit_load(jd, iptr, src, tempreg);
150
151         return reg;
152 }
153
154
155 /* emit_store ******************************************************************
156
157    Emits a possible store to variable.
158
159 *******************************************************************************/
160
161 void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
162 {
163         codegendata  *cd;
164         s4            disp;
165
166         /* get required compiler data */
167
168         cd = jd->cd;
169
170         if (dst->flags & INMEMORY) {
171                 COUNT_SPILLS;
172
173                 disp = dst->regoff * 8;
174
175                 if (IS_FLT_DBL_TYPE(dst->type)) {
176                         if (IS_2_WORD_TYPE(dst->type))
177                                 M_DST(d, REG_SP, disp);
178                         else
179                                 M_FST(d, REG_SP, disp);
180                 } else
181                         M_LST(d, REG_SP, disp);
182         }
183 }
184
185 /* emit_store_dst **************************************************************
186
187    Emits a possible store to the destination operand of an instruction.
188
189 *******************************************************************************/
190
191 void emit_store_dst(jitdata *jd, instruction *iptr, s4 d)
192 {
193         emit_store(jd, iptr, iptr->dst.var, d);
194 }
195
196
197 /* emit_copy *******************************************************************
198
199    Generates a register/memory to register/memory copy.
200
201 *******************************************************************************/
202
203 void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
204 {
205         codegendata  *cd;
206         registerdata *rd;
207         s4            s1, d;
208
209         /* get required compiler data */
210
211         cd = jd->cd;
212         rd = jd->rd;
213
214         if ((src->regoff != dst->regoff) ||
215                 ((src->flags ^ dst->flags) & INMEMORY)) {
216
217                 /* If one of the variables resides in memory, we can eliminate
218                    the register move from/to the temporary register with the
219                    order of getting the destination register and the load. */
220
221                 if (IS_INMEMORY(src->flags)) {
222                         d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
223                         s1 = emit_load(jd, iptr, src, d);
224                 }
225                 else {
226                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
227                         d = codegen_reg_of_var(rd, iptr->opc, dst, s1);
228                 }
229
230                 if (s1 != d) {
231                         if (IS_FLT_DBL_TYPE(src->type)) {
232                                 if (IS_2_WORD_TYPE(src->type))
233                                         M_DMOV(s1, d);
234                                 else
235                                         M_FMOV(s1, d);
236                         }
237                         else
238                                 M_MOV(s1, d);
239                 }
240
241                 emit_store(jd, iptr, dst, d);
242         }
243 }
244
245
246 /* emit_iconst *****************************************************************
247
248    XXX
249
250 *******************************************************************************/
251
252 void emit_iconst(codegendata *cd, s4 d, s4 value)
253 {
254         s4 disp;
255
256     if ((value >= -32768) && (value <= 32767))
257         M_IADD_IMM(REG_ZERO, value, d);
258         else if ((value >= 0) && (value <= 0xffff))
259         M_OR_IMM(REG_ZERO, value, d);
260         else {
261         disp = dseg_adds4(cd, value);
262         M_ILD(d, REG_PV, disp);
263     }
264 }
265
266
267 /* emit_lconst *****************************************************************
268
269    XXX
270
271 *******************************************************************************/
272
273 void emit_lconst(codegendata *cd, s4 d, s8 value)
274 {
275         s4 disp;
276
277         if ((value >= -32768) && (value <= 32767))
278                 M_LADD_IMM(REG_ZERO, value, d);
279         else if ((value >= 0) && (value <= 0xffff))
280                 M_OR_IMM(REG_ZERO, value, d);
281         else {
282                 disp = dseg_adds8(cd, value);
283                 M_LLD(d, REG_PV, disp);
284         }
285 }
286
287
288 /* emit_exception_stubs ********************************************************
289
290    Generates the code for the exception stubs.
291
292 *******************************************************************************/
293
294 void emit_exception_stubs(jitdata *jd)
295 {
296         codegendata  *cd;
297         registerdata *rd;
298         exceptionref *eref;
299         s4            targetdisp;
300         s4            disp;
301
302         /* get required compiler data */
303
304         cd = jd->cd;
305         rd = jd->rd;
306
307         /* generate exception stubs */
308
309         targetdisp = 0;
310
311         for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
312                 gen_resolvebranch(cd->mcodebase + eref->branchpos, 
313                                                   eref->branchpos, cd->mcodeptr - cd->mcodebase);
314
315                 MCODECHECK(100);
316
317                 /* Check if the exception is an
318                    ArrayIndexOutOfBoundsException.  If so, move index register
319                    into REG_ITMP1. */
320
321                 if (eref->reg != -1)
322                         M_MOV(eref->reg, REG_ITMP1);
323
324                 /* calcuate exception address */
325
326                 M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4);
327
328                 /* move function to call into REG_ITMP3 */
329
330                 disp = dseg_addaddress(cd, eref->function);
331                 M_ALD(REG_ITMP3, REG_PV, disp);
332
333                 if (targetdisp == 0) {
334                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
335
336                         M_MOV(REG_PV, rd->argintregs[0]);
337                         M_MOV(REG_SP, rd->argintregs[1]);
338
339                         if (jd->isleafmethod)
340                                 M_MOV(REG_RA, rd->argintregs[2]);
341                         else
342                                 M_ALD(rd->argintregs[2],
343                                           REG_SP, cd->stackframesize * 8 - SIZEOF_VOID_P);
344
345                         M_MOV(REG_ITMP2_XPC, rd->argintregs[3]);
346                         M_MOV(REG_ITMP1, rd->argintregs[4]);
347
348                         M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
349                         M_AST(REG_ITMP2_XPC, REG_SP, 0 * 8);
350
351                         if (jd->isleafmethod)
352                                 M_AST(REG_RA, REG_SP, 1 * 8);
353
354                         M_JSR(REG_RA, REG_ITMP3);
355                         M_NOP;
356                         M_MOV(REG_RESULT, REG_ITMP1_XPTR);
357
358                         if (jd->isleafmethod)
359                                 M_ALD(REG_RA, REG_SP, 1 * 8);
360
361                         M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
362                         M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
363
364                         disp = dseg_addaddress(cd, asm_handle_exception);
365                         M_ALD(REG_ITMP3, REG_PV, disp);
366                         M_JMP(REG_ITMP3);
367                         M_NOP;
368                 }
369                 else {
370                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
371                                 (((u4 *) cd->mcodeptr) + 1);
372
373                         M_BR(disp);
374                         M_NOP;
375                 }
376         }
377 }
378
379
380 /* emit_patcher_stubs **********************************************************
381
382    Generates the code for the patcher stubs.
383
384 *******************************************************************************/
385
386 void emit_patcher_stubs(jitdata *jd)
387 {
388         codegendata *cd;
389         patchref    *pref;
390         u4           mcode[2];
391         u1          *savedmcodeptr;
392         u1          *tmpmcodeptr;
393         s4           targetdisp;
394         s4           disp;
395
396         /* get required compiler data */
397
398         cd = jd->cd;
399
400         /* generate code patching stub call code */
401
402         targetdisp = 0;
403
404         for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
405                 /* check code segment size */
406
407                 MCODECHECK(100);
408
409                 /* Get machine code which is patched back in later. The
410                    call is 2 instruction words long. */
411
412                 tmpmcodeptr = (u1 *) (cd->mcodebase + pref->branchpos);
413
414                 /* We use 2 loads here as an unaligned 8-byte read on 64-bit
415                    MIPS causes a SIGSEGV and using the same code for both
416                    architectures is much better. */
417
418                 mcode[0] = ((u4 *) tmpmcodeptr)[0];
419                 mcode[1] = ((u4 *) tmpmcodeptr)[1];
420
421                 /* Patch in the call to call the following code (done at
422                    compile time). */
423
424                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr          */
425                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position */
426
427                 disp = ((u4 *) savedmcodeptr) - (((u4 *) tmpmcodeptr) + 1);
428
429                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
430                         *exceptionptr =
431                                 new_internalerror("Jump offset is out of range: %d > +/-%d",
432                                                                   disp, 0x00007fff);
433                         return;
434                 }
435
436                 M_BR(disp);
437                 M_NOP;
438
439                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr   */
440
441                 /* create stack frame */
442
443                 M_ASUB_IMM(REG_SP, 6 * 8, REG_SP);
444
445                 /* calculate return address and move it onto the stack */
446
447                 M_LDA(REG_ITMP3, REG_PV, pref->branchpos);
448                 M_AST(REG_ITMP3, REG_SP, 5 * 8);
449
450                 /* move pointer to java_objectheader onto stack */
451
452 #if defined(ENABLE_THREADS)
453                 /* create a virtual java_objectheader */
454
455                 (void) dseg_addaddress(cd, NULL);                          /* flcword */
456                 (void) dseg_addaddress(cd, lock_get_initial_lock_word());
457                 disp = dseg_addaddress(cd, NULL);                          /* vftbl   */
458
459                 M_LDA(REG_ITMP3, REG_PV, disp);
460                 M_AST(REG_ITMP3, REG_SP, 4 * 8);
461 #else
462                 /* do nothing */
463 #endif
464
465                 /* move machine code onto stack */
466
467                 disp = dseg_adds4(cd, mcode[0]);
468                 M_ILD(REG_ITMP3, REG_PV, disp);
469                 M_IST(REG_ITMP3, REG_SP, 3 * 8);
470
471                 disp = dseg_adds4(cd, mcode[1]);
472                 M_ILD(REG_ITMP3, REG_PV, disp);
473                 M_IST(REG_ITMP3, REG_SP, 3 * 8 + 4);
474
475                 /* move class/method/field reference onto stack */
476
477                 disp = dseg_addaddress(cd, pref->ref);
478                 M_ALD(REG_ITMP3, REG_PV, disp);
479                 M_AST(REG_ITMP3, REG_SP, 2 * 8);
480
481                 /* move data segment displacement onto stack */
482
483                 disp = dseg_adds4(cd, pref->disp);
484                 M_ILD(REG_ITMP3, REG_PV, disp);
485                 M_IST(REG_ITMP3, REG_SP, 1 * 8);
486
487                 /* move patcher function pointer onto stack */
488
489                 disp = dseg_addaddress(cd, pref->patcher);
490                 M_ALD(REG_ITMP3, REG_PV, disp);
491                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
492
493                 if (targetdisp == 0) {
494                         targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
495
496                         disp = dseg_addaddress(cd, asm_patcher_wrapper);
497                         M_ALD(REG_ITMP3, REG_PV, disp);
498                         M_JMP(REG_ITMP3);
499                         M_NOP;
500                 }
501                 else {
502                         disp = (((u4 *) cd->mcodebase) + targetdisp) -
503                                 (((u4 *) cd->mcodeptr) + 1);
504
505                         M_BR(disp);
506                         M_NOP;
507                 }
508         }
509 }
510
511
512 /* emit_replacement_stubs ******************************************************
513
514    Generates the code for the replacement stubs.
515
516 *******************************************************************************/
517
518 void emit_replacement_stubs(jitdata *jd)
519 {
520         codegendata *cd;
521         codeinfo    *code;
522         rplpoint    *rplp;
523         u1          *savedmcodeptr;
524         s4           disp;
525         s4           i;
526
527         /* get required compiler data */
528
529         cd   = jd->cd;
530         code = jd->code;
531
532         rplp = code->rplpoints;
533
534         for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
535                 /* check code segment size */
536
537                 MCODECHECK(100);
538
539                 /* note start of stub code */
540
541                 rplp->outcode = (u1 *) (ptrint) (cd->mcodeptr - cd->mcodebase);
542
543                 /* make machine code for patching */
544
545                 savedmcodeptr = cd->mcodeptr;
546                 cd->mcodeptr  = (u1 *) &(rplp->mcode);
547
548                 disp = (ptrint) ((s4 *) rplp->outcode - (s4 *) rplp->pc) - 1;
549
550                 if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
551                         *exceptionptr =
552                                 new_internalerror("Jump offset is out of range: %d > +/-%d",
553                                                                   disp, 0x00007fff);
554                         return;
555                 }
556
557                 M_BR(disp);
558                 M_NOP; /* delay slot */
559
560                 cd->mcodeptr = savedmcodeptr;
561
562                 /* create stack frame - 16-byte aligned */
563
564                 M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
565
566                 /* push address of `rplpoint` struct */
567
568                 disp = dseg_addaddress(cd, rplp);
569                 M_ALD(REG_ITMP3, REG_PV, disp);
570                 M_AST(REG_ITMP3, REG_SP, 0 * 8);
571
572                 /* jump to replacement function */
573
574                 disp = dseg_addaddress(cd, asm_replacement_out);
575                 M_ALD(REG_ITMP3, REG_PV, disp);
576                 M_JMP(REG_ITMP3);
577                 M_NOP; /* delay slot */
578         }
579 }
580
581
582 /* emit_verbosecall_enter ******************************************************
583
584    Generates the code for the call trace.
585
586 *******************************************************************************/
587
588 #if !defined(NDEBUG)
589 void emit_verbosecall_enter(jitdata *jd)
590 {
591         methodinfo   *m;
592         codegendata  *cd;
593         registerdata *rd;
594         methoddesc   *md;
595         s4            disp;
596         s4            i, t;
597
598         /* get required compiler data */
599
600         m  = jd->m;
601         cd = jd->cd;
602         rd = jd->rd;
603
604         md = m->parseddesc;
605
606         /* mark trace code */
607
608         M_NOP;
609
610         M_LDA(REG_SP, REG_SP, -(2 + ARG_CNT + TMP_CNT) * 8);
611         M_AST(REG_RA, REG_SP, 1 * 8);
612
613         /* save argument registers */
614
615         for (i = 0; i < INT_ARG_CNT; i++)
616                 M_LST(rd->argintregs[i], REG_SP, (2 + i) * 8);
617
618         for (i = 0; i < FLT_ARG_CNT; i++)
619                 M_DST(rd->argfltregs[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
620
621         /* save temporary registers for leaf methods */
622
623         if (jd->isleafmethod) {
624                 for (i = 0; i < INT_TMP_CNT; i++)
625                         M_LST(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
626
627                 for (i = 0; i < FLT_TMP_CNT; i++)
628                         M_DST(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
629         }
630
631         /* load float arguments into integer registers */
632
633         for (i = 0; i < md->paramcount && i < INT_ARG_CNT; i++) {
634                 t = md->paramtypes[i].type;
635
636                 if (IS_FLT_DBL_TYPE(t)) {
637                         if (IS_2_WORD_TYPE(t)) {
638                                 M_DST(rd->argfltregs[i], REG_SP, 0 * 8);
639                                 M_LLD(rd->argintregs[i], REG_SP, 0 * 8);
640                         }
641                         else {
642                                 M_FST(rd->argfltregs[i], REG_SP, 0 * 8);
643                                 M_ILD(rd->argintregs[i], REG_SP, 0 * 8);
644                         }
645                 }
646         }
647
648         disp = dseg_addaddress(cd, m);
649         M_ALD(REG_ITMP1, REG_PV, disp);
650         M_AST(REG_ITMP1, REG_SP, 0 * 8);
651         disp = dseg_addaddress(cd, builtin_trace_args);
652         M_ALD(REG_ITMP3, REG_PV, disp);
653         M_JSR(REG_RA, REG_ITMP3);
654         M_NOP;
655
656         /* restore argument registers */
657
658         for (i = 0; i < INT_ARG_CNT; i++)
659                 M_LLD(rd->argintregs[i], REG_SP, (2 + i) * 8);
660
661         for (i = 0; i < FLT_ARG_CNT; i++)
662                 M_DLD(rd->argfltregs[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
663
664         /* restore temporary registers for leaf methods */
665
666         if (jd->isleafmethod) {
667                 for (i = 0; i < INT_TMP_CNT; i++)
668                         M_LLD(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
669
670                 for (i = 0; i < FLT_TMP_CNT; i++)
671                         M_DLD(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
672         }
673
674         M_ALD(REG_RA, REG_SP, 1 * 8);
675         M_LDA(REG_SP, REG_SP, (2 + ARG_CNT + TMP_CNT) * 8);
676
677         /* mark trace code */
678
679         M_NOP;
680 }
681 #endif /* !defined(NDEBUG) */
682
683
684 /* emit_verbosecall_exit *******************************************************
685
686    Generates the code for the call trace.
687
688 *******************************************************************************/
689
690 #if !defined(NDEBUG)
691 void emit_verbosecall_exit(jitdata *jd)
692 {
693         methodinfo   *m;
694         codegendata  *cd;
695         registerdata *rd;
696         s4            disp;
697
698         /* get required compiler data */
699
700         m  = jd->m;
701         cd = jd->cd;
702         rd = jd->rd;
703
704         /* mark trace code */
705
706         M_NOP;
707
708         M_LDA(REG_SP, REG_SP, -4 * 8);              /* keep stack 16-byte aligned */
709         M_LST(REG_RA, REG_SP, 0 * 8);
710
711         M_LST(REG_RESULT, REG_SP, 1 * 8);
712         M_DST(REG_FRESULT, REG_SP, 2 * 8);
713
714         disp = dseg_addaddress(cd, m);
715         M_ALD(rd->argintregs[0], REG_PV, disp);
716
717         M_MOV(REG_RESULT, rd->argintregs[1]);
718         M_DMOV(REG_FRESULT, rd->argfltregs[2]);
719         M_FMOV(REG_FRESULT, rd->argfltregs[3]);
720
721         disp = dseg_addaddress(cd, builtin_displaymethodstop);
722         M_ALD(REG_ITMP3, REG_PV, disp);
723         M_JSR(REG_RA, REG_ITMP3);
724         M_NOP;
725
726         M_DLD(REG_FRESULT, REG_SP, 2 * 8);
727         M_LLD(REG_RESULT, REG_SP, 1 * 8);
728
729         M_LLD(REG_RA, REG_SP, 0 * 8);
730         M_LDA(REG_SP, REG_SP, 4 * 8);
731
732         /* mark trace code */
733
734         M_NOP;
735 }
736 #endif /* !defined(NDEBUG) */
737
738
739 /*
740  * These are local overrides for various environment variables in Emacs.
741  * Please do not remove this and leave it at the end of the file, where
742  * Emacs will automagically detect them.
743  * ---------------------------------------------------------------------
744  * Local variables:
745  * mode: c
746  * indent-tabs-mode: t
747  * c-basic-offset: 4
748  * tab-width: 4
749  * End:
750  * vim:noexpandtab:sw=4:ts=4:
751  */