* configure.ac: New switch for disabling -O2 (--disable-optimizations).
[cacao.git] / src / vm / jit / powerpc64 / emit.c
1 /* src/vm/jit/powerpc64/emit.c - PowerPC64 code emitter functions
2
3    Copyright (C) 1996-2005, 2006, 2007, 2008
4    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
5
6    This file is part of CACAO.
7
8    This program is free software; you can redistribute it and/or
9    modify it under the terms of the GNU General Public License as
10    published by the Free Software Foundation; either version 2, or (at
11    your option) any later version.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23 */
24
25
26 #include "config.h"
27
28 #include <assert.h>
29
30 #include "vm/types.h"
31
32 #include "mm/memory.hpp"
33
34 #include "md-abi.h"
35 #include "vm/jit/powerpc64/codegen.h"
36
37 #include "threads/lock.hpp"
38
39 #include "vm/options.h"
40 #include "vm/vm.hpp"
41
42 #include "vm/jit/abi.h"
43 #include "vm/jit/asmpart.h"
44 #include "vm/jit/emit-common.hpp"
45 #include "vm/jit/jit.hpp"
46 #include "vm/jit/trace.hpp"
47 #include "vm/jit/trap.hpp"
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;
70
71                 if (IS_FLT_DBL_TYPE(src->type)) {
72                         M_DLD(tempreg, REG_SP, disp);
73                 }
74                 else {
75                         M_LLD(tempreg, REG_SP, disp);
76                 }
77
78                 reg = tempreg;
79         }
80         else
81                 reg = src->vv.regoff;
82
83         return reg;
84 }
85
86
87 /* emit_store ******************************************************************
88
89    Emits a possible store to a variable.
90
91 *******************************************************************************/
92
93 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
94 {
95         codegendata  *cd;
96
97         /* get required compiler data */
98
99         cd = jd->cd;
100
101         if (dst->flags & INMEMORY) {
102                 COUNT_SPILLS;
103
104                 if (IS_FLT_DBL_TYPE(dst->type)) {
105                         M_DST(d, REG_SP, dst->vv.regoff);
106                 }
107                 else {
108                         M_LST(d, REG_SP, dst->vv.regoff);
109                 }
110         }
111 }
112
113
114 /* emit_copy *******************************************************************
115
116    Generates a register/memory to register/memory copy.
117
118 *******************************************************************************/
119
120 void emit_copy(jitdata *jd, instruction *iptr)
121 {
122         codegendata *cd;
123         varinfo     *src;
124         varinfo     *dst;
125         s4           s1, d;
126
127         /* get required compiler data */
128
129         cd = jd->cd;
130
131         /* get source and destination variables */
132
133         src = VAROP(iptr->s1);
134         dst = VAROP(iptr->dst);
135
136         if ((src->vv.regoff != dst->vv.regoff) ||
137                 ((src->flags ^ dst->flags) & INMEMORY)) {
138
139                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
140                         /* emit nothing, as the value won't be used anyway */
141                         return;
142                 }
143
144                 /* If one of the variables resides in memory, we can eliminate
145                    the register move from/to the temporary register with the
146                    order of getting the destination register and the load. */
147
148                 if (IS_INMEMORY(src->flags)) {
149                         d  = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
150                         s1 = emit_load(jd, iptr, src, d);
151                 }
152                 else {
153                         s1 = emit_load(jd, iptr, src, REG_IFTMP);
154                         d  = codegen_reg_of_var(iptr->opc, dst, s1);
155                 }
156
157                 if (s1 != d) {
158                         if (IS_FLT_DBL_TYPE(src->type))
159                                 M_FMOV(s1, d);
160                         else
161                                 M_MOV(s1, d);
162                 }
163
164                 emit_store(jd, iptr, dst, d);
165         }
166 }
167
168
169 /* emit_iconst *****************************************************************
170
171    XXX
172
173 *******************************************************************************/
174
175 void emit_iconst(codegendata *cd, s4 d, s4 value)
176 {
177         s4 disp;
178
179         if ((value >= -32768) && (value <= 32767)) {
180                 M_LDA_INTERN(d, REG_ZERO, value);
181         } else {
182                 disp = dseg_add_s4(cd, value);
183                 M_ILD(d, REG_PV, disp);
184         }
185 }
186
187 void emit_lconst(codegendata *cd, s4 d, s8 value)
188 {
189         s4 disp;
190         if ((value >= -32768) && (value <= 32767)) {
191                 M_LDA_INTERN(d, REG_ZERO, value);
192         } else {
193                 disp = dseg_add_s8(cd, value);
194                 M_LLD(d, REG_PV, disp);
195         }
196 }
197
198
199 /**
200  * Emits code updating the condition register by comparing one integer
201  * register to an immediate integer value.
202  */
203 void emit_icmp_imm(codegendata* cd, int reg, int32_t value)
204 {
205         int32_t disp;
206
207         if ((value >= -32768) && (value <= 32767)) {
208                 M_CMPI(reg, value);
209         } else {
210                 assert(reg != REG_ITMP2);
211                 disp = dseg_add_s4(cd, value);
212                 M_ILD(REG_ITMP2, REG_PV, disp);
213                 M_CMP(reg, REG_ITMP2);
214         }
215 }
216
217
218 /**
219  * Generates synchronization code to enter a monitor.
220  */
221 #if defined(ENABLE_THREADS)
222 void emit_monitor_enter(jitdata* jd, int32_t syncslot_offset)
223 {
224         int32_t p;
225
226         // Get required compiler data.
227         methodinfo*  m  = jd->m;
228         codegendata* cd = jd->cd;
229
230 #if !defined (NDEBUG)
231                 if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
232                         M_AADD_IMM(REG_SP, -((LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT) * 8), REG_SP);
233
234                         for (p = 0; p < INT_ARG_CNT; p++)
235                                 M_LST(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + p * 8);
236
237                         for (p = 0; p < FLT_ARG_CNT; p++)
238                                 M_DST(abi_registers_float_argument[p], REG_SP, LA_SIZE + PA_SIZE + (INT_ARG_CNT + p) * 8);
239
240                         /* used for LOCK_monitor_exit, adopt size because we created another stackframe */
241                         syncslot_offset += (LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT) * 8;
242                 }
243 #endif
244
245                 p = dseg_add_functionptr(cd, LOCK_monitor_enter);
246                 M_ALD(REG_ITMP3, REG_PV, p);
247                 M_ALD(REG_ITMP3, REG_ITMP3, 0); /* TOC */
248                 M_MTCTR(REG_ITMP3);
249
250                 /* get or test the lock object */
251
252                 if (m->flags & ACC_STATIC) {
253                         p = dseg_add_address(cd, &m->clazz->object.header);
254                         M_ALD(REG_A0, REG_PV, p);
255                 }
256                 else {
257                         M_TST(REG_A0);
258                         M_BNE(1);
259                         M_ALD_INTERN(REG_ZERO, REG_ZERO, TRAP_NullPointerException);
260                 }
261
262                 M_AST(REG_A0, REG_SP, syncslot_offset);
263                 M_JSR;
264
265 #if !defined(NDEBUG)
266                 if (JITDATA_HAS_FLAG_VERBOSECALL(jd)) {
267                         for (p = 0; p < INT_ARG_CNT; p++)
268                                 M_LLD(abi_registers_integer_argument[p], REG_SP, LA_SIZE + PA_SIZE + p * 8);
269
270                         for (p = 0; p < FLT_ARG_CNT; p++)
271                                 M_DLD(abi_registers_float_argument[p], REG_SP, LA_SIZE + PA_SIZE + (INT_ARG_CNT + p) * 8);
272
273                         M_AADD_IMM(REG_SP, (LA_SIZE_IN_POINTERS + PA_SIZE_IN_POINTERS + ARG_CNT) * 8, REG_SP);
274                 }
275 #endif
276 }
277 #endif
278
279
280 /**
281  * Generates synchronization code to leave a monitor.
282  */
283 #if defined(ENABLE_THREADS)
284 void emit_monitor_exit(jitdata* jd, int32_t syncslot_offset)
285 {
286         int32_t disp;
287
288         // Get required compiler data.
289         methodinfo*  m  = jd->m;
290         codegendata* cd = jd->cd;
291
292         disp = dseg_add_functionptr(cd, LOCK_monitor_exit);
293         M_ALD(REG_ITMP3, REG_PV, disp);
294         M_ALD(REG_ITMP3, REG_ITMP3, 0); /* TOC */
295         M_MTCTR(REG_ITMP3);
296
297         /* we need to save the proper return value */
298
299         methoddesc* md = m->parseddesc;
300
301         switch (md->returntype.type) {
302         case TYPE_LNG:
303         case TYPE_INT:
304         case TYPE_ADR:
305                 /* fall through */
306                 M_LST(REG_RESULT , REG_SP, syncslot_offset + 8);
307                 break;
308         case TYPE_FLT:
309                 M_FST(REG_FRESULT, REG_SP, syncslot_offset + 8);
310                 break;
311         case TYPE_DBL:
312                 M_DST(REG_FRESULT, REG_SP, syncslot_offset + 8);
313                 break;
314         }
315
316         M_ALD(REG_A0, REG_SP, syncslot_offset);
317         M_JSR;
318
319         /* and now restore the proper return value */
320
321         switch (md->returntype.type) {
322         case TYPE_LNG:
323         case TYPE_INT:
324         case TYPE_ADR:
325                 /* fall through */
326                 M_LLD(REG_RESULT , REG_SP, syncslot_offset + 8);
327                 break;
328         case TYPE_FLT:
329                 M_FLD(REG_FRESULT, REG_SP, syncslot_offset + 8);
330                 break;
331         case TYPE_DBL:
332                 M_DLD(REG_FRESULT, REG_SP, syncslot_offset + 8);
333                 break;
334         }
335 }
336 #endif
337
338
339 /* emit_verbosecall_enter ******************************************************
340
341    Generates the code for the call trace.
342
343 *******************************************************************************/
344
345 #if !defined(NDEBUG)
346 void emit_verbosecall_enter(jitdata *jd)
347 {
348         methodinfo   *m;
349         codegendata  *cd;
350         methoddesc   *md;
351         int32_t       paramcount;
352         int32_t       stackframesize;
353         s4            disp;
354         s4            i, s;
355
356         /* get required compiler data */
357
358         m  = jd->m;
359         cd = jd->cd;
360
361         md = m->parseddesc;
362         
363         /* mark trace code */
364
365         M_NOP;
366
367         /* align stack to 16-bytes */
368
369         paramcount = md->paramcount;
370         ALIGN_2(paramcount);
371         stackframesize = LA_SIZE + PA_SIZE + md->paramcount * 8;
372
373         M_MFLR(REG_ZERO);
374         M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
375         M_STDU(REG_SP, REG_SP, -stackframesize);
376
377 #if defined(__DARWIN__)
378         #warning "emit_verbosecall_enter not implemented"
379 #else
380         /* save argument registers */
381
382         for (i = 0; i < md->paramcount; i++) {
383                 if (!md->params[i].inmemory) {
384                         s = md->params[i].regoff;
385
386                         switch (md->paramtypes[i].type) {
387                         case TYPE_ADR:
388                         case TYPE_INT:
389                         case TYPE_LNG:
390                                 M_LST(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
391                                 break;
392                         case TYPE_FLT:
393                         case TYPE_DBL:
394                                 M_DST(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
395                                 break;
396                         }
397                 }
398         }
399 #endif
400
401         disp = dseg_add_address(cd, m);
402         M_ALD(REG_A0, REG_PV, disp);
403         M_AADD_IMM(REG_SP, LA_SIZE+PA_SIZE, REG_A1);
404         M_AADD_IMM(REG_SP, stackframesize + cd->stackframesize * 8, REG_A2);
405         /* call via function descriptor, XXX: what about TOC? */
406         disp = dseg_add_functionptr(cd, trace_java_call_enter);
407         M_ALD(REG_ITMP2, REG_PV, disp);
408         M_ALD(REG_ITMP1, REG_ITMP2, 0);
409         M_MTCTR(REG_ITMP1);
410         M_JSR;
411
412 #if defined(__DARWIN__)
413         #warning "emit_verbosecall_enter not implemented"
414 #else
415         /* restore argument registers */
416
417         for (i = 0; i < md->paramcount; i++) {
418                 if (!md->params[i].inmemory) {
419                         s = md->params[i].regoff;
420
421                         switch (md->paramtypes[i].type) {
422                         case TYPE_ADR:
423                         case TYPE_INT:
424                         case TYPE_LNG:
425                                 M_LLD(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
426                                 break;
427                         case TYPE_FLT:
428                         case TYPE_DBL:
429                                 M_DLD(s, REG_SP, LA_SIZE+PA_SIZE+i*8);
430                                 break;
431                         }
432                 }
433         }
434 #endif
435
436         M_ALD(REG_ZERO, REG_SP, stackframesize + LA_LR_OFFSET);
437         M_MTLR(REG_ZERO);
438         M_LDA(REG_SP, REG_SP, stackframesize);
439
440         /* mark trace code */
441
442         M_NOP;
443 }
444 #endif
445
446
447 /* emit_verbosecall_exit ******************************************************
448
449    Generates the code for the call trace.
450
451 *******************************************************************************/
452
453 #if !defined(NDEBUG)
454 void emit_verbosecall_exit(jitdata *jd)
455 {
456         methodinfo   *m;
457         codegendata  *cd;
458         methoddesc   *md;
459         s4            disp;
460
461         /* get required compiler data */
462
463         m  = jd->m;
464         cd = jd->cd;
465
466         md = m->parseddesc;
467
468         /* mark trace code */
469
470         M_NOP;
471
472         M_MFLR(REG_ZERO);
473         M_LDA(REG_SP, REG_SP, -(LA_SIZE+PA_SIZE+10*8));
474         M_AST(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+1*8);
475
476         /* save return value */
477
478         switch (md->returntype.type) {
479         case TYPE_ADR:
480         case TYPE_INT:
481         case TYPE_LNG:
482                 M_LST(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
483                 break;
484         case TYPE_FLT:
485         case TYPE_DBL:
486                 M_DST(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
487                 break;
488         }
489
490         disp = dseg_add_address(cd, m);
491         M_ALD(REG_A0, REG_PV, disp);
492         M_AADD_IMM(REG_SP, LA_SIZE+PA_SIZE, REG_A1);
493
494         disp = dseg_add_functionptr(cd, trace_java_call_exit);
495         /* call via function descriptor, XXX: what about TOC ? */
496         M_ALD(REG_ITMP2, REG_PV, disp);
497         M_ALD(REG_ITMP2, REG_ITMP2, 0);
498         M_MTCTR(REG_ITMP2);
499         M_JSR;
500
501         /* restore return value */
502
503         switch (md->returntype.type) {
504         case TYPE_ADR:
505         case TYPE_INT:
506         case TYPE_LNG:
507                 M_LLD(REG_RESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
508                 break;
509         case TYPE_FLT:
510         case TYPE_DBL:
511                 M_DLD(REG_FRESULT, REG_SP, LA_SIZE+PA_SIZE+0*8);
512                 break;
513         }
514
515         M_ALD(REG_ZERO, REG_SP, LA_SIZE+PA_SIZE+1*8);
516         M_LDA(REG_SP, REG_SP, LA_SIZE+PA_SIZE+10*8);
517         M_MTLR(REG_ZERO);
518
519         /* mark trace code */
520
521         M_NOP;
522 }
523 #endif
524
525
526 /* emit_branch *****************************************************************
527
528    Emits the code for conditional and unconditional branchs.
529
530 *******************************************************************************/
531
532 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
533 {
534         s4 checkdisp;
535         s4 branchdisp;
536
537         /* calculate the different displacements */
538
539         checkdisp  =  disp + 4;
540         branchdisp = (disp - 4) >> 2;
541
542         /* check which branch to generate */
543
544         if (condition == BRANCH_UNCONDITIONAL) {
545                 /* check displacement for overflow */
546
547                 if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
548                         /* if the long-branches flag isn't set yet, do it */
549
550                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
551                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
552                                                           CODEGENDATA_FLAG_LONGBRANCHES);
553                         }
554
555                         vm_abort("emit_branch: emit unconditional long-branch code");
556                 }
557                 else {
558                         M_BR(branchdisp);
559                 }
560         }
561         else {
562                 /* and displacement for overflow */
563
564                 if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
565                         /* if the long-branches flag isn't set yet, do it */
566
567                         if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
568                                 cd->flags |= (CODEGENDATA_FLAG_ERROR |
569                                                           CODEGENDATA_FLAG_LONGBRANCHES);
570                         }
571
572                         // Subtract 1 instruction from the displacement as the
573                         // actual branch is the second instruction.
574                         checkdisp  = checkdisp - 4;
575                         branchdisp = branchdisp - 1;
576
577                         if ((checkdisp < (int32_t) 0xfe000000) || (checkdisp > (int32_t) 0x01fffffc)) {
578                                 vm_abort("emit_branch: emit conditional long-branch code");
579                         }
580                         else {
581                                 switch (condition) {
582                                 case BRANCH_EQ:
583                                         M_BNE(1);
584                                         M_BR(branchdisp);
585                                         break;
586                                 case BRANCH_NE:
587                                         M_BEQ(1);
588                                         M_BR(branchdisp);
589                                         break;
590                                 case BRANCH_LT:
591                                         M_BGE(1);
592                                         M_BR(branchdisp);
593                                         break;
594                                 case BRANCH_GE:
595                                         M_BLT(1);
596                                         M_BR(branchdisp);
597                                         break;
598                                 case BRANCH_GT:
599                                         M_BLE(1);
600                                         M_BR(branchdisp);
601                                         break;
602                                 case BRANCH_LE:
603                                         M_BGT(1);
604                                         M_BR(branchdisp);
605                                         break;
606                                 case BRANCH_NAN:
607                                         vm_abort("emit_branch: long BRANCH_NAN");
608                                         break;
609                                 default:
610                                         vm_abort("emit_branch: unknown condition %d", condition);
611                                 }
612                         }
613                 }
614                 else {
615                         switch (condition) {
616                         case BRANCH_EQ:
617                                 M_BEQ(branchdisp);
618                                 break;
619                         case BRANCH_NE:
620                                 M_BNE(branchdisp);
621                                 break;
622                         case BRANCH_LT:
623                                 M_BLT(branchdisp);
624                                 break;
625                         case BRANCH_GE:
626                                 M_BGE(branchdisp);
627                                 break;
628                         case BRANCH_GT:
629                                 M_BGT(branchdisp);
630                                 break;
631                         case BRANCH_LE:
632                                 M_BLE(branchdisp);
633                                 break;
634                         case BRANCH_NAN:
635                                 M_BNAN(branchdisp);
636                                 break;
637                         default:
638                                 vm_abort("emit_branch: unknown condition %d", condition);
639                         }
640                 }
641         }
642 }
643
644 /* emit_arrayindexoutofbounds_check ********************************************
645
646    Emit a ArrayIndexOutOfBoundsException check.
647
648 *******************************************************************************/
649
650 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
651 {
652         if (checkbounds) {
653                 M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
654                 M_CMPU(s2, REG_ITMP3);
655                 M_BLT(1);
656                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
657                 M_LWZ(s2, REG_ZERO, TRAP_ArrayIndexOutOfBoundsException);
658         }
659 }
660
661
662 /* emit_arraystore_check *******************************************************
663
664    Emit an ArrayStoreException check.
665
666 *******************************************************************************/
667
668 void emit_arraystore_check(codegendata *cd, instruction *iptr)
669 {
670         if (INSTRUCTION_MUST_CHECK(iptr))       {
671                 M_TST(REG_RESULT);
672                 M_BNE(1);
673                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
674                 M_LWZ(REG_ZERO, REG_ZERO, TRAP_ArrayStoreException);
675         }
676 }
677
678
679 /* emit_arithmetic_check *******************************************************
680
681    Emit an ArithmeticException check.
682
683 *******************************************************************************/
684
685 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
686 {
687         if (INSTRUCTION_MUST_CHECK(iptr))       {
688                 M_TST(reg);
689                 M_BNE(1);
690                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
691                 M_LWZ(REG_ZERO, REG_ZERO, TRAP_ArithmeticException);
692         }
693 }
694
695
696 /* emit_classcast_check ********************************************************
697
698    Emit a ClassCastException check.
699
700 *******************************************************************************/
701
702 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
703 {
704         if (INSTRUCTION_MUST_CHECK(iptr))       {
705                 switch(condition)       {
706                 case BRANCH_LE:
707                         M_BGT(1);
708                         break;
709                 case BRANCH_EQ:
710                         M_BNE(1);
711                         break;
712                 case BRANCH_NE:
713                         M_BEQ(1);
714                         break;
715                 case BRANCH_GT:
716                         M_BLE(1);
717                         break;
718                 default:
719                         vm_abort("emit_classcast_check: unknown condition %d", condition);
720                 }
721
722                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
723                 M_LWZ(s1, REG_ZERO, TRAP_ClassCastException);
724         }
725 }
726
727
728 /* emit_nullpointer_check ******************************************************
729
730    Emit a NullPointerException check.
731
732 *******************************************************************************/
733
734 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
735 {
736         if (INSTRUCTION_MUST_CHECK(iptr))       {
737                 M_TST(reg);
738                 M_BNE(1);
739                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
740                 M_LWZ(REG_ZERO, REG_ZERO, TRAP_NullPointerException);
741         }
742 }
743
744 /* emit_exception_check ********************************************************
745
746    Emit an Exception check.
747
748 *******************************************************************************/
749
750 void emit_exception_check(codegendata *cd, instruction *iptr)
751 {
752         if (INSTRUCTION_MUST_CHECK(iptr))       {
753                 M_TST(REG_RESULT);
754                 M_BNE(1);
755                 /* ALD is 4 byte aligned, ILD 2, onyl LWZ is byte aligned */
756                 M_LWZ(REG_ZERO, REG_ZERO, TRAP_CHECK_EXCEPTION);
757         }
758 }
759
760
761 /* emit_trap_compiler **********************************************************
762
763    Emit a trap instruction which calls the JIT compiler.
764
765 *******************************************************************************/
766
767 void emit_trap_compiler(codegendata *cd)
768 {
769         M_LWZ(REG_METHODPTR, REG_ZERO, TRAP_COMPILER);
770 }
771
772
773 /* emit_trap *******************************************************************
774
775    Emit a trap instruction and return the original machine code.
776
777 *******************************************************************************/
778
779 uint32_t emit_trap(codegendata *cd)
780 {
781         // Get machine code which is patched back in later. The trap is 1
782         // instruction word long.
783         uint32_t mcode = *((uint32_t*) cd->mcodeptr);
784
785         M_ILLEGAL;
786
787         return mcode;
788 }
789
790
791 /**
792  * Emit code to recompute the procedure vector.
793  */
794 void emit_recompute_pv(codegendata *cd)
795 {
796         int32_t disp = (int32_t) (cd->mcodeptr - cd->mcodebase);
797
798         M_MFLR(REG_ITMP1);
799         M_LDA(REG_PV, REG_ITMP1, -disp);
800 }
801
802
803 /*
804  * These are local overrides for various environment variables in Emacs.
805  * Please do not remove this and leave it at the end of the file, where
806  * Emacs will automagically detect them.
807  * ---------------------------------------------------------------------
808  * Local variables:
809  * mode: c
810  * indent-tabs-mode: t
811  * c-basic-offset: 4
812  * tab-width: 4
813  * End:
814  * vim:noexpandtab:sw=4:ts=4:
815  */