6a9dabd3d0cc78279576e41b548d46813c462d1d
[cacao.git] / src / vm / jit / alpha / emit.c
1 /* src/vm/jit/alpha/emit.c - Alpha code emitter functions
2
3    Copyright (C) 1996-2005, 2006, 2007 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    $Id: emit.c 8211 2007-07-18 19:52:23Z michi $
26
27 */
28
29
30 #include "config.h"
31 #include "vm/types.h"
32
33 #include <assert.h>
34
35 #include "md-abi.h"
36
37 #include "vm/jit/alpha/codegen.h"
38
39 #include "mm/memory.h"
40
41 #include "threads/lock-common.h"
42
43 #include "vm/builtin.h"
44 #include "vm/exceptions.h"
45
46 #include "vm/jit/abi.h"
47 #include "vm/jit/abi-asm.h"
48 #include "vm/jit/asmpart.h"
49 #include "vm/jit/dseg.h"
50 #include "vm/jit/emit-common.h"
51 #include "vm/jit/jit.h"
52 #include "vm/jit/patcher-common.h"
53 #include "vm/jit/replace.h"
54
55 #include "vmcore/options.h"
56
57
58 /* emit_load *******************************************************************
59
60    Emits a possible load of an operand.
61
62 *******************************************************************************/
63
64 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
65 {
66         codegendata  *cd;
67         s4            disp;
68         s4            reg;
69
70         /* get required compiler data */
71
72         cd = jd->cd;
73
74         if (IS_INMEMORY(src->flags)) {
75                 COUNT_SPILLS;
76
77                 disp = src->vv.regoff;
78
79                 switch (src->type) {
80                 case TYPE_INT:
81                 case TYPE_LNG:
82                 case TYPE_ADR:
83                         M_LLD(tempreg, REG_SP, disp);
84                         break;
85                 case TYPE_FLT:
86                 case TYPE_DBL:
87                         M_DLD(tempreg, REG_SP, disp);
88                         break;
89                 default:
90                         vm_abort("emit_load: unknown type %d", src->type);
91                 }
92
93                 reg = tempreg;
94         }
95         else
96                 reg = src->vv.regoff;
97
98         return reg;
99 }
100
101
102 /* emit_store ******************************************************************
103
104    Emit a possible store for the given variable.
105
106 *******************************************************************************/
107
108 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
109 {
110         codegendata  *cd;
111         s4            disp;
112
113         /* get required compiler data */
114
115         cd = jd->cd;
116
117         if (IS_INMEMORY(dst->flags)) {
118                 COUNT_SPILLS;
119
120                 disp = dst->vv.regoff;
121
122                 switch (dst->type) {
123                 case TYPE_INT:
124                 case TYPE_LNG:
125                 case TYPE_ADR:
126                         M_LST(d, REG_SP, disp);
127                         break;
128                 case TYPE_FLT:
129                 case TYPE_DBL:
130                         M_DST(d, REG_SP, disp);
131                         break;
132                 default:
133                         vm_abort("emit_store: unknown type %d", dst->type);
134                 }
135         }
136 }
137
138
139 /* emit_copy *******************************************************************
140
141    Generates a register/memory to register/memory copy.
142
143 *******************************************************************************/
144
145 void emit_copy(jitdata *jd, instruction *iptr)
146 {
147         codegendata *cd;
148         varinfo     *src;
149         varinfo     *dst;
150         s4           s1, d;
151
152         /* get required compiler data */
153
154         cd = jd->cd;
155
156         /* get source and destination variables */
157
158         src = VAROP(iptr->s1);
159         dst = VAROP(iptr->dst);
160
161         if ((src->vv.regoff != dst->vv.regoff) ||
162                 ((src->flags ^ dst->flags) & INMEMORY)) {
163
164                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
165                         /* emit nothing, as the value won't be used anyway */
166                         return;
167                 }
168
169                 /* If one of the variables resides in memory, we can eliminate
170                    the register move from/to the temporary register with the
171                    order of getting the destination register and the load. */
172
173                 if (IS_INMEMORY(src->flags)) {
174                         d  = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
175                         s1 = emit_load(jd, iptr, src, d);
176                 }
177                 else {
178                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
179                         d  = codegen_reg_of_var(iptr->opc, dst, s1);
180                 }
181
182                 if (s1 != d) {
183                         switch (src->type) {
184                         case TYPE_INT:
185                         case TYPE_LNG:
186                         case TYPE_ADR:
187                                 M_MOV(s1, d);
188                                 break;
189                         case TYPE_FLT:
190                         case TYPE_DBL:
191                                 M_FMOV(s1, d);
192                                 break;
193                         default:
194                                 vm_abort("emit_copy: unknown type %d", src->type);
195                         }
196                 }
197
198                 emit_store(jd, iptr, dst, d);
199         }
200 }
201
202
203 /* emit_iconst *****************************************************************
204
205    XXX
206
207 *******************************************************************************/
208
209 void emit_iconst(codegendata *cd, s4 d, s4 value)
210 {
211         s4 disp;
212
213         if ((value >= -32768) && (value <= 32767))
214                 M_LDA_INTERN(d, REG_ZERO, value);
215         else {
216                 disp = dseg_add_s4(cd, value);
217                 M_ILD(d, REG_PV, disp);
218         }
219 }
220
221
222 /* emit_lconst *****************************************************************
223
224    XXX
225
226 *******************************************************************************/
227
228 void emit_lconst(codegendata *cd, s4 d, s8 value)
229 {
230         s4 disp;
231
232         if ((value >= -32768) && (value <= 32767))
233                 M_LDA_INTERN(d, REG_ZERO, value);
234         else {
235                 disp = dseg_add_s8(cd, value);
236                 M_LLD(d, REG_PV, disp);
237         }
238 }
239
240
241 /* emit_branch *****************************************************************
242
243    Emits the code for conditional and unconditional branchs.
244
245 *******************************************************************************/
246
247 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
248 {
249         s4 checkdisp;
250         s4 branchdisp;
251
252         /* calculate the different displacements */
253
254         checkdisp  = (disp - 4);
255         branchdisp = (disp - 4) >> 2;
256
257         /* check which branch to generate */
258
259         if (condition == BRANCH_UNCONDITIONAL) {
260                 /* check displacement for overflow */
261
262                 if ((checkdisp < (s4) 0xffe00000) || (checkdisp > (s4) 0x001fffff)) {
263                         /* if the long-branches flag isn't set yet, do it */
264
265                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
266                                 log_println("setting error");
267                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
268                                                           CODEGENDATA_FLAG_LONGBRANCHES);
269                         }
270
271                         vm_abort("emit_branch: emit unconditional long-branch code");
272                 }
273                 else {
274                         M_BR(branchdisp);
275                 }
276         }
277         else {
278                 /* and displacement for overflow */
279
280                 if ((checkdisp < (s4) 0xffe00000) || (checkdisp > (s4) 0x001fffff)) {
281                         /* if the long-branches flag isn't set yet, do it */
282
283                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
284                                 log_println("setting error");
285                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
286                                                           CODEGENDATA_FLAG_LONGBRANCHES);
287                         }
288
289                         vm_abort("emit_branch: emit conditional long-branch code");
290                 }
291                 else {
292                         switch (condition) {
293                         case BRANCH_EQ:
294                                 M_BEQZ(reg, branchdisp);
295                                 break;
296                         case BRANCH_NE:
297                                 M_BNEZ(reg, branchdisp);
298                                 break;
299                         case BRANCH_LT:
300                                 M_BLTZ(reg, branchdisp);
301                                 break;
302                         case BRANCH_GE:
303                                 M_BGEZ(reg, branchdisp);
304                                 break;
305                         case BRANCH_GT:
306                                 M_BGTZ(reg, branchdisp);
307                                 break;
308                         case BRANCH_LE:
309                                 M_BLEZ(reg, branchdisp);
310                                 break;
311                         default:
312                                 vm_abort("emit_branch: unknown condition %d", condition);
313                         }
314                 }
315         }
316 }
317
318
319 /* emit_arithmetic_check *******************************************************
320
321    Emit an ArithmeticException check.
322
323 *******************************************************************************/
324
325 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
326 {
327         if (INSTRUCTION_MUST_CHECK(iptr)) {
328                 M_BNEZ(reg, 1);
329                 /* Destination register must not be REG_ZERO, because then no
330                    SIGSEGV is thrown. */
331                 M_ALD_INTERN(reg, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
332         }
333 }
334
335
336 /* emit_arrayindexoutofbounds_check ********************************************
337
338    Emit an ArrayIndexOutOfBoundsException check.
339
340 *******************************************************************************/
341
342 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
343 {
344         if (INSTRUCTION_MUST_CHECK(iptr)) {
345                 M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
346                 M_CMPULT(s2, REG_ITMP3, REG_ITMP3);
347                 M_BNEZ(REG_ITMP3, 1);
348                 M_ALD_INTERN(s2, REG_ZERO, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
349         }
350 }
351
352
353 /* emit_classcast_check ********************************************************
354
355    Emit a ClassCastException check.
356
357 *******************************************************************************/
358
359 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
360 {
361         if (INSTRUCTION_MUST_CHECK(iptr)) {
362                 switch (condition) {
363                 case BRANCH_EQ:
364                         M_BNEZ(reg, 1);
365                         break;
366                 case BRANCH_LE:
367                         M_BGTZ(reg, 1);
368                         break;
369                 default:
370                         vm_abort("emit_classcast_check: unknown condition %d", condition);
371                 }
372                 M_ALD_INTERN(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
373         }
374 }
375
376
377 /* emit_nullpointer_check ******************************************************
378
379    Emit a NullPointerException check.
380
381 *******************************************************************************/
382
383 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
384 {
385         if (INSTRUCTION_MUST_CHECK(iptr)) {
386                 M_BNEZ(reg, 1);
387                 /* Destination register must not be REG_ZERO, because then no
388                    SIGSEGV is thrown. */
389                 M_ALD_INTERN(reg, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
390         }
391 }
392
393
394 /* emit_exception_check ********************************************************
395
396    Emit an Exception check.
397
398 *******************************************************************************/
399
400 void emit_exception_check(codegendata *cd, instruction *iptr)
401 {
402         if (INSTRUCTION_MUST_CHECK(iptr)) {
403                 M_BNEZ(REG_RESULT, 1);
404                 /* Destination register must not be REG_ZERO, because then no
405                    SIGSEGV is thrown. */
406                 M_ALD_INTERN(REG_RESULT, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
407         }
408 }
409
410
411 /* emit_patcher_traps **********************************************************
412
413    Generates the code for the patcher traps.
414
415 *******************************************************************************/
416
417 void emit_patcher_traps(jitdata *jd)
418 {
419         codegendata *cd;
420         codeinfo    *code;
421         patchref_t  *pr;
422         u1          *savedmcodeptr;
423         u1          *tmpmcodeptr;
424
425         /* get required compiler data */
426
427         cd =   jd->cd;
428         code = jd->code;
429
430         /* generate patcher traps code */
431
432         for (pr = list_first_unsynced(code->patchers); pr != NULL; pr = list_next_unsynced(code->patchers, pr)) {
433
434                 /* Get machine code which is patched back in later. The
435                    trap is 1 instruction word long. */
436
437                 tmpmcodeptr = (u1 *) (cd->mcodebase + pr->mpc);
438                 pr->mcode = *((u4 *) tmpmcodeptr);
439
440                 /* Patch in the trap to call the signal handler (done at
441                    compile time). */
442
443                 savedmcodeptr = cd->mcodeptr;   /* save current mcodeptr              */
444                 cd->mcodeptr  = tmpmcodeptr;    /* set mcodeptr to patch position     */
445
446                 M_ALD_INTERN(REG_RESULT, REG_ZERO, EXCEPTION_HARDWARE_PATCHER);
447
448                 cd->mcodeptr = savedmcodeptr;   /* restore the current mcodeptr       */
449         }
450 }
451
452
453 /* emit_verbosecall_enter ******************************************************
454
455    Generates the code for the call trace.
456
457 *******************************************************************************/
458
459 #if !defined(NDEBUG)
460 void emit_verbosecall_enter(jitdata *jd)
461 {
462         methodinfo   *m;
463         codegendata  *cd;
464         registerdata *rd;
465         methoddesc   *md;
466         s4            disp;
467         s4            i, t;
468
469         /* get required compiler data */
470
471         m  = jd->m;
472         cd = jd->cd;
473         rd = jd->rd;
474
475         md = m->parseddesc;
476
477         /* mark trace code */
478
479         M_NOP;
480
481         M_LDA(REG_SP, REG_SP, -((ARG_CNT + TMP_CNT + 2) * 8));
482         M_AST(REG_RA, REG_SP, 1 * 8);
483
484         /* save argument registers */
485
486         for (i = 0; i < INT_ARG_CNT; i++)
487                 M_LST(abi_registers_integer_argument[i], REG_SP, (2 + i) * 8);
488
489         for (i = 0; i < FLT_ARG_CNT; i++)
490                 M_DST(abi_registers_float_argument[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
491
492         /* save temporary registers for leaf methods */
493
494         if (jd->isleafmethod) {
495                 for (i = 0; i < INT_TMP_CNT; i++)
496                         M_LST(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
497
498                 for (i = 0; i < FLT_TMP_CNT; i++)
499                         M_DST(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
500         }
501
502         /* load float arguments into integer registers */
503
504         for (i = 0; i < md->paramcount && i < INT_ARG_CNT; i++) {
505                 t = md->paramtypes[i].type;
506
507                 if (IS_FLT_DBL_TYPE(t)) {
508                         if (IS_2_WORD_TYPE(t)) {
509                                 M_DST(abi_registers_float_argument[i], REG_SP, 0 * 8);
510                                 M_LLD(abi_registers_integer_argument[i], REG_SP, 0 * 8);
511                         }
512                         else {
513                                 M_FST(abi_registers_float_argument[i], REG_SP, 0 * 8);
514                                 M_ILD(abi_registers_integer_argument[i], REG_SP, 0 * 8);
515                         }
516                 }
517         }
518
519         disp = dseg_add_address(cd, m);
520         M_ALD(REG_ITMP1, REG_PV, disp);
521         M_AST(REG_ITMP1, REG_SP, 0 * 8);
522         disp = dseg_add_functionptr(cd, builtin_verbosecall_enter);
523         M_ALD(REG_PV, REG_PV, disp);
524         M_JSR(REG_RA, REG_PV);
525         disp = (s4) (cd->mcodeptr - cd->mcodebase);
526         M_LDA(REG_PV, REG_RA, -disp);
527         M_ALD(REG_RA, REG_SP, 1 * 8);
528
529         /* restore argument registers */
530
531         for (i = 0; i < INT_ARG_CNT; i++)
532                 M_LLD(abi_registers_integer_argument[i], REG_SP, (2 + i) * 8);
533
534         for (i = 0; i < FLT_ARG_CNT; i++)
535                 M_DLD(abi_registers_float_argument[i], REG_SP, (2 + INT_ARG_CNT + i) * 8);
536
537         /* restore temporary registers for leaf methods */
538
539         if (jd->isleafmethod) {
540                 for (i = 0; i < INT_TMP_CNT; i++)
541                         M_LLD(rd->tmpintregs[i], REG_SP, (2 + ARG_CNT + i) * 8);
542
543                 for (i = 0; i < FLT_TMP_CNT; i++)
544                         M_DLD(rd->tmpfltregs[i], REG_SP, (2 + ARG_CNT + INT_TMP_CNT + i) * 8);
545         }
546
547         M_LDA(REG_SP, REG_SP, (ARG_CNT + TMP_CNT + 2) * 8);
548
549         /* mark trace code */
550
551         M_NOP;
552 }
553 #endif /* !defined(NDEBUG) */
554
555
556 /* emit_verbosecall_exit *******************************************************
557
558    Generates the code for the call trace.
559
560    void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
561
562 *******************************************************************************/
563
564 #if !defined(NDEBUG)
565 void emit_verbosecall_exit(jitdata *jd)
566 {
567         methodinfo   *m;
568         codegendata  *cd;
569         registerdata *rd;
570         s4            disp;
571
572         /* get required compiler data */
573
574         m  = jd->m;
575         cd = jd->cd;
576         rd = jd->rd;
577
578         /* mark trace code */
579
580         M_NOP;
581
582         M_ASUB_IMM(REG_SP, 4 * 8, REG_SP);
583         M_AST(REG_RA, REG_SP, 0 * 8);
584
585         M_LST(REG_RESULT, REG_SP, 1 * 8);
586         M_DST(REG_FRESULT, REG_SP, 2 * 8);
587
588         M_MOV(REG_RESULT, REG_A0);
589         M_FMOV(REG_FRESULT, REG_FA1);
590         M_FMOV(REG_FRESULT, REG_FA2);
591
592         disp = dseg_add_address(cd, m);
593         M_ALD(REG_A3, REG_PV, disp);
594
595         disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
596         M_ALD(REG_PV, REG_PV, disp);
597         M_JSR(REG_RA, REG_PV);
598         disp = (cd->mcodeptr - cd->mcodebase);
599         M_LDA(REG_PV, REG_RA, -disp);
600
601         M_DLD(REG_FRESULT, REG_SP, 2 * 8);
602         M_LLD(REG_RESULT, REG_SP, 1 * 8);
603
604         M_ALD(REG_RA, REG_SP, 0 * 8);
605         M_AADD_IMM(REG_SP, 4 * 8, REG_SP);
606
607         /* mark trace code */
608
609         M_NOP;
610 }
611 #endif /* !defined(NDEBUG) */
612
613
614 /*
615  * These are local overrides for various environment variables in Emacs.
616  * Please do not remove this and leave it at the end of the file, where
617  * Emacs will automagically detect them.
618  * ---------------------------------------------------------------------
619  * Local variables:
620  * mode: c
621  * indent-tabs-mode: t
622  * c-basic-offset: 4
623  * tab-width: 4
624  * End:
625  * vim:noexpandtab:sw=4:ts=4:
626  */