* configure.ac (AC_CONFIG_FILES): Moved src/threads/native/Makefile to
[cacao.git] / src / vm / jit / s390 / emit.c
1 /* src/vm/jit/s390/emit.c - s390 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 #include "config.h"
26
27 #include <assert.h>
28 #include <stdint.h>
29
30 #include "mm/memory.h"
31
32 #include "threads/lock-common.h"
33
34 #include "vm/builtin.h"
35 #include "vm/exceptions.h"
36 #include "vm/global.h"
37 #include "vm/jit/abi.h"
38 #include "vm/jit/abi-asm.h"
39 #include "vm/jit/asmpart.h"
40 #include "vm/jit/codegen-common.h"
41 #include "vm/jit/emit-common.h"
42 #include "vm/jit/jit.h"
43 #include "vm/jit/patcher-common.h"
44 #include "vm/jit/replace.h"
45 #include "vm/jit/trace.h"
46 #include "vm/jit/s390/codegen.h"
47 #include "vm/jit/s390/emit.h"
48 #include "vm/jit/s390/md-abi.h"
49 #include "vm/types.h"
50 #include "vmcore/options.h"
51
52 /* emit_load *******************************************************************
53
54    Emits a possible load of an operand.
55
56 *******************************************************************************/
57
58 s4 emit_load(jitdata *jd, instruction *iptr, varinfo *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 (IS_INMEMORY(src->flags)) {
69                 COUNT_SPILLS;
70
71                 disp = src->vv.regoff;
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         }
88         else
89                 reg = src->vv.regoff;
90
91         return reg;
92 }
93
94
95 /* emit_store ******************************************************************
96
97    This function generates the code to store the result of an
98    operation back into a spilled pseudo-variable.  If the
99    pseudo-variable has not been spilled in the first place, this
100    function will generate nothing.
101     
102 *******************************************************************************/
103
104 void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
105 {
106         codegendata *cd;
107
108         /* get required compiler data */
109
110         cd = jd->cd;
111
112         if (IS_INMEMORY(dst->flags)) {
113                 COUNT_SPILLS;
114
115                 if (IS_FLT_DBL_TYPE(dst->type)) {
116                         if (IS_2_WORD_TYPE(dst->type))
117                                 M_DST(d, REG_SP, dst->vv.regoff);
118                         else
119                                 M_FST(d, REG_SP, dst->vv.regoff);
120                 }
121                 else {
122                         if (IS_2_WORD_TYPE(dst->type))
123                                 M_LST(d, REG_SP, dst->vv.regoff);
124                         else
125                                 M_IST(d, REG_SP, dst->vv.regoff);
126                 }
127         }
128 }
129
130
131 /* emit_copy *******************************************************************
132
133    Generates a register/memory to register/memory copy.
134
135 *******************************************************************************/
136
137 void emit_copy(jitdata *jd, instruction *iptr)
138 {
139         codegendata *cd;
140         varinfo     *src;
141         varinfo     *dst;
142         s4           s1, d;
143
144         /* get required compiler data */
145
146         cd = jd->cd;
147
148         /* get source and destination variables */
149
150         src = VAROP(iptr->s1);
151         dst = VAROP(iptr->dst);
152
153         if ((src->vv.regoff != dst->vv.regoff) ||
154                 ((src->flags ^ dst->flags) & INMEMORY)) {
155
156                 if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
157                         /* emit nothing, as the value won't be used anyway */
158                         return;
159                 }
160
161                 if (IS_INMEMORY(src->flags) && IS_INMEMORY(dst->flags)) {
162                         if (IS_2_WORD_TYPE(src->type)) {
163                                 N_MVC(dst->vv.regoff, 8, REG_SP, src->vv.regoff, REG_SP);
164                         } else {
165                                 N_MVC(dst->vv.regoff, 4, REG_SP, src->vv.regoff, REG_SP);
166                         }
167                 } else {
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                                 if (IS_FLT_DBL_TYPE(dst->type)) {
175                                         d = codegen_reg_of_var(iptr->opc, dst, REG_FTMP1);
176                                 } else {
177                                         if (IS_2_WORD_TYPE(dst->type)) {
178                                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
179                                         } else {
180                                                 d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP1);
181                                         }
182                                 }
183                                 s1 = emit_load(jd, iptr, src, d);
184                         }
185                         else {
186                                 if (IS_FLT_DBL_TYPE(src->type)) {
187                                         s1 = emit_load(jd, iptr, src, REG_FTMP1);
188                                 } else {
189                                         if (IS_2_WORD_TYPE(src->type)) {
190                                                 s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
191                                         } else {
192                                                 s1 = emit_load(jd, iptr, src, REG_ITMP1);
193                                         }
194                                 }
195                                 d = codegen_reg_of_var(iptr->opc, dst, s1);
196                         }
197
198                         if (s1 != d) {
199                                 if (IS_FLT_DBL_TYPE(src->type)) {
200                                         M_FMOV(s1, d);
201                                 } else {
202                                         if (IS_2_WORD_TYPE(src->type)) {
203                                                 M_LNGMOVE(s1, d);
204                                         } else {
205                                                 M_MOV(s1, d);
206                                         }
207                                 }
208                         }
209
210                         emit_store(jd, iptr, dst, d);
211                 }
212         }
213 }
214
215 /* emit_trap *******************************************************************
216
217    Emit a trap instruction and return the original machine code.
218
219 *******************************************************************************/
220
221 uint32_t emit_trap(codegendata *cd)
222 {
223         uint32_t mcode;
224
225         /* Get machine code which is patched back in later. The
226            trap is 2 bytes long. */
227
228         mcode = *((u2 *) cd->mcodeptr);
229
230         M_ILL(EXCEPTION_HARDWARE_PATCHER);
231
232         return mcode;
233 }
234
235
236 /* emit_verbosecall_enter ******************************************************
237
238    Generates the code for the call trace.
239
240 *******************************************************************************/
241
242 #if !defined(NDEBUG)
243 void emit_verbosecall_enter(jitdata *jd)
244 {
245         methodinfo   *m;
246         codeinfo     *code;
247         codegendata  *cd;
248         methoddesc   *md;
249         s4            stackframesize;
250         s4            i, off, disp, s;
251
252         m    = jd->m;
253         code = jd->code;
254         cd   = jd->cd;
255
256         md   = m->parseddesc;
257
258         /* mark trace code */
259
260         M_NOP;
261
262         /* allocate stack frame */
263
264         stackframesize = 96 + (md->paramcount * 8);
265
266         /* for leaf methods we need to store unused argument and temporary registers */
267
268         if (code_is_leafmethod(code)) {
269                 stackframesize += (ARG_CNT + TMP_CNT) * 8;
270         }
271
272         /* allocate stack frame */
273
274         M_ASUB_IMM(stackframesize, REG_SP);
275
276         /* store argument registers in array */
277
278         off = 96;
279
280         for (i = 0; i < md->paramcount; i++) {
281                 if (! md->params[i].inmemory) {
282                         s = md->params[i].regoff;
283                         switch (md->paramtypes[i].type) {
284                                 case TYPE_INT:
285                                 case TYPE_ADR:
286                                         M_IST(s, REG_SP, off);
287                                         break;
288                                 case TYPE_LNG:
289                                         M_LST(s, REG_SP, off);
290                                         break;
291                                 case TYPE_FLT:
292                                         M_FST(s, REG_SP, off);
293                                         break;
294                                 case TYPE_DBL:
295                                         M_DST(s, REG_SP, off);
296                                         break;
297                         }
298                 }
299                 off += 8;
300         }
301
302         /* save unused (currently all) argument registers for leaf methods */
303         /* save temporary registers for leaf methods */
304
305         if (code_is_leafmethod(code)) {
306
307                 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
308                         M_IST(abi_registers_integer_argument[i], REG_SP, off);
309                 }
310
311                 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
312                         M_DST(abi_registers_float_argument[i], REG_SP, off);
313                 }
314
315                 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
316                         M_IST(abi_registers_integer_temporary[i], REG_SP, off);
317                 }
318
319                 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
320                         M_DST(abi_registers_float_temporary[i], REG_SP, off);
321                 }
322         }
323
324         /* load arguments for trace_java_call_enter */
325
326         /* methodinfo */
327
328         disp = dseg_add_address(cd, m);
329         M_ALD_DSEG(REG_A0, disp);       
330         /* pointer to argument registers array */
331         M_LDA(REG_A1, REG_SP, 96);
332         /* pointer to on stack arguments */
333         M_LDA(REG_A2, REG_SP, stackframesize + (cd->stackframesize * 8));
334
335         /* call trace_java_call_enter */
336
337         disp = dseg_add_functionptr(cd, trace_java_call_enter);
338         M_ALD_DSEG(REG_ITMP2, disp);
339         M_CALL(REG_ITMP2);
340
341         /* restore used argument registers */
342         /* for leaf methods restore all argument and temporary registers */
343
344         if (code_is_leafmethod(code)) {
345                 off = 96 + (8 * md->paramcount);
346
347                 for (i = 0; i < INT_ARG_CNT; ++i, off += 8) {
348                         M_ILD(abi_registers_integer_argument[i], REG_SP, off);
349                 }
350
351                 for (i = 0; i < FLT_ARG_CNT; ++i, off += 8) {
352                         M_DLD(abi_registers_float_argument[i], REG_SP, off);
353                 }
354
355                 for (i = 0; i < INT_TMP_CNT; ++i, off += 8) {
356                         M_ILD(abi_registers_integer_temporary[i], REG_SP, off);
357                 }
358
359                 for (i = 0; i < FLT_TMP_CNT; ++i, off += 8) {
360                         M_DLD(abi_registers_float_temporary[i], REG_SP, off);
361                 }
362         } else {
363                 off = 96;
364
365                 for (i = 0; i < md->paramcount; i++) {
366                         if (! md->params[i].inmemory) {
367                                 s = md->params[i].regoff;
368                                 switch (md->paramtypes[i].type) {
369                                         case TYPE_INT:
370                                         case TYPE_ADR:
371                                                 M_ILD(s, REG_SP, off);
372                                                 break;
373                                         case TYPE_LNG:
374                                                 M_LLD(s, REG_SP, off);
375                                                 break;
376                                         case TYPE_FLT:
377                                                 M_FLD(s, REG_SP, off);
378                                                 break;
379                                         case TYPE_DBL:
380                                                 M_DLD(s, REG_SP, off);
381                                                 break;
382                                 }
383                         }
384                         off += 8;
385                 }
386         }
387
388         /* remove stack frame */
389
390         M_AADD_IMM(stackframesize, REG_SP);
391
392         /* mark trace code */
393
394         M_NOP;
395
396 }
397 #endif /* !defined(NDEBUG) */
398
399
400 /* emit_verbosecall_exit *******************************************************
401
402    Generates the code for the call trace.
403
404 *******************************************************************************/
405
406 #if !defined(NDEBUG)
407 void emit_verbosecall_exit(jitdata *jd)
408 {
409         methodinfo   *m;
410         codegendata  *cd;
411         s4            disp;
412         s4            stackframesize;
413         s4            off;
414         s4            t;
415
416         m  = jd->m;
417         cd = jd->cd;
418         t = m->parseddesc->returntype.type;
419
420         /* mark trace code */
421
422         M_NOP;
423
424         /* allocate stackframe */
425
426         stackframesize = 96 + (1 * 8);
427         M_ASUB_IMM(stackframesize, REG_SP);
428
429         off = 96;
430
431         /* store return values in array */
432
433         if (IS_INT_LNG_TYPE(t)) {
434                 if (IS_2_WORD_TYPE(t)) {
435                         M_LST(REG_RESULT_PACKED, REG_SP, off);
436                 } else {
437                         M_IST(REG_RESULT, REG_SP, off);
438                 }
439         } else {
440                 M_DST(REG_FRESULT, REG_SP, off);
441         }
442
443         /* call trace_java_call_exit */
444
445         disp = dseg_add_address(cd, m);
446         M_ALD_DSEG(REG_A0, disp);
447         M_LDA(REG_A1, REG_SP, off);
448         disp = dseg_add_functionptr(cd, trace_java_call_exit);
449         M_ALD_DSEG(REG_ITMP2, disp);
450         M_CALL(REG_ITMP2);
451
452         /* restore return value */
453
454         if (IS_INT_LNG_TYPE(t)) {
455                 if (IS_2_WORD_TYPE(t)) {
456                         M_LLD(REG_RESULT_PACKED, REG_SP, off);
457                 } else {
458                         M_ILD(REG_RESULT, REG_SP, off);
459                 }
460         } else {
461                 M_DLD(REG_FRESULT, REG_SP, off);
462         }
463
464         /* remove stackframe */
465
466         M_AADD_IMM(stackframesize, REG_SP);
467
468         /* mark trace code */
469
470         M_NOP;
471 }
472 #endif /* !defined(NDEBUG) */
473
474
475 /* emit_load_high **************************************************************
476
477    Emits a possible load of the high 32-bits of an operand.
478
479 *******************************************************************************/
480
481 s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
482 {
483         codegendata  *cd;
484         s4            disp;
485         s4            reg;
486
487         assert(src->type == TYPE_LNG);
488
489         /* get required compiler data */
490
491         cd = jd->cd;
492
493         if (IS_INMEMORY(src->flags)) {
494                 COUNT_SPILLS;
495
496                 disp = src->vv.regoff;
497
498                 M_ILD(tempreg, REG_SP, disp);
499
500                 reg = tempreg;
501         }
502         else
503                 reg = GET_HIGH_REG(src->vv.regoff);
504
505         return reg;
506 }
507
508 /* emit_load_low ***************************************************************
509
510    Emits a possible load of the low 32-bits of an operand.
511
512 *******************************************************************************/
513
514 s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
515 {
516         codegendata  *cd;
517         s4            disp;
518         s4            reg;
519
520         assert(src->type == TYPE_LNG);
521
522         /* get required compiler data */
523
524         cd = jd->cd;
525
526         if (IS_INMEMORY(src->flags)) {
527                 COUNT_SPILLS;
528
529                 disp = src->vv.regoff;
530
531                 M_ILD(tempreg, REG_SP, disp + 4);
532
533                 reg = tempreg;
534         }
535         else
536                 reg = GET_LOW_REG(src->vv.regoff);
537
538         return reg;
539 }
540
541 s4 emit_load_s1_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
542         codegendata *cd = jd->cd;
543         s4 reg = emit_load_s1(jd, iptr, tempreg);
544         if (reg == notreg) {
545                 if (IS_FLT_DBL_TYPE(VAROP(iptr->s1)->type)) {
546                         M_FMOV(reg, tempreg);
547                 } else {
548                         M_MOV(reg, tempreg);
549                 }
550                 return tempreg;
551         } else {
552                 return reg;
553         }
554 }
555
556 s4 emit_load_s2_but(jitdata *jd, instruction *iptr, s4 tempreg, s4 notreg) {
557         codegendata *cd = jd->cd;
558         s4 reg = emit_load_s2(jd, iptr, tempreg);
559         if (reg == notreg) {
560                 if (IS_FLT_DBL_TYPE(VAROP(iptr->sx.s23.s2)->type)) {
561                         M_FMOV(reg, tempreg);
562                 } else {
563                         M_MOV(reg, tempreg);
564                 }
565                 return tempreg;
566         } else {
567                 return reg;
568         }
569 }
570
571 void emit_copy_dst(jitdata *jd, instruction *iptr, s4 dtmpreg) {
572         codegendata *cd;
573         varinfo *dst;
574         cd = jd->cd;
575         dst = VAROP(iptr->dst);
576         if (! IS_INMEMORY(dst->flags)) {
577                 if (dst->vv.regoff != dtmpreg) {
578                         if (IS_FLT_DBL_TYPE(dst->type)) {
579                                 M_FLTMOVE(dtmpreg, dst->vv.regoff);
580                         } else if (IS_2_WORD_TYPE(dst->type)) {
581                                 M_LNGMOVE(dtmpreg, dst->vv.regoff);
582                         } else {
583                                 M_INTMOVE(dtmpreg, dst->vv.regoff);
584                         }
585                 }
586         }
587 }
588
589 void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt) {
590
591         s4 branchdisp = disp;
592         s4 branchmpc;
593         u1 *ref;
594
595         if (N_VALID_BRANCH(branchdisp)) {
596
597                 /* valid displacement */
598
599                 switch (condition) {
600                         case BRANCH_EQ:
601                                 M_BEQ(branchdisp);
602                                 break;
603                         case BRANCH_NE:
604                                 M_BNE(branchdisp);
605                                 break;
606                         case BRANCH_LT:
607                                 M_BLT(branchdisp);
608                                 break;
609                         case BRANCH_GE:
610                                 M_BGE(branchdisp);
611                                 break;
612                         case BRANCH_GT:
613                                 M_BGT(branchdisp);
614                                 break;
615                         case BRANCH_LE:
616                                 M_BLE(branchdisp);
617                                 break;
618                         case BRANCH_UNCONDITIONAL:
619                                 M_BR(branchdisp);
620                                 break;
621                         default:
622                                 vm_abort("emit_branch: unknown condition %d", condition);
623                 }
624         } else {
625
626                 /* If LONGBRANCHES is not set, the flag and the error flag */
627
628                 if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
629                         cd->flags |= (CODEGENDATA_FLAG_ERROR |
630                                 CODEGENDATA_FLAG_LONGBRANCHES);
631                 }
632
633                 /* If error flag is set, do nothing. The method has to be recompiled. */
634
635                 if (CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd) && CODEGENDATA_HAS_FLAG_ERROR(cd)) {
636                         return;
637                 }
638
639                 /* Patch the displacement to branch over the actual branch manually
640                  * to not get yet more nops.
641                  */
642
643                 branchmpc = cd->mcodeptr - cd->mcodebase;
644                 ref = cd->mcodeptr;
645
646                 switch (condition) {
647                         case BRANCH_EQ:
648                                 M_BNE(0);
649                                 break;
650                         case BRANCH_NE:
651                                 M_BEQ(0);
652                                 break;
653                         case BRANCH_LT:
654                                 M_BGE(0);
655                                 break;
656                         case BRANCH_GE:
657                                 M_BLT(0);
658                                 break;
659                         case BRANCH_GT:
660                                 M_BLE(0);
661                                 break;
662                         case BRANCH_LE:
663                                 M_BGT(0);
664                                 break;
665                         case BRANCH_UNCONDITIONAL:
666                                 /* fall through, no displacement to patch */
667                                 ref = NULL;
668                                 break;
669                         default:
670                                 vm_abort("emit_branch: unknown condition %d", condition);
671                 }
672
673                 /* The actual long branch */
674
675                 disp = dseg_add_s4(cd, branchmpc + disp - N_PV_OFFSET);
676                 M_ILD_DSEG(REG_ITMP2, disp);
677                 M_AADD(REG_PV, REG_ITMP2);
678                 M_JMP(RN, REG_ITMP2);
679
680                 /* Patch back the displacement */
681
682                 N_BRC_BACK_PATCH(ref);
683         }
684 }
685
686 void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg) {
687         if (INSTRUCTION_MUST_CHECK(iptr)) {
688                 M_TEST(reg);
689                 M_BNE(SZ_BRC + SZ_ILL);
690                 M_ILL(EXCEPTION_HARDWARE_ARITHMETIC);
691         }
692 }
693
694 /* emit_arrayindexoutofbounds_check ********************************************
695
696    Emit a ArrayIndexOutOfBoundsException check.
697
698 *******************************************************************************/
699
700 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
701 {
702         if (INSTRUCTION_MUST_CHECK(iptr)) {
703                 /* Size is s4, >= 0
704                  * Do unsigned comparison to catch negative indexes.
705                  */
706                 N_CL(s2, OFFSET(java_array_t, size), RN, s1);
707         M_BLT(SZ_BRC + SZ_ILL);
708                 M_ILL2(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
709         }
710 }
711
712
713 /* emit_arraystore_check *******************************************************
714
715    Emit an ArrayStoreException check.
716
717 *******************************************************************************/
718
719 void emit_arraystore_check(codegendata *cd, instruction *iptr)
720 {
721         if (INSTRUCTION_MUST_CHECK(iptr)) {
722                 M_TEST(REG_RESULT);
723                 M_BNE(SZ_BRC + SZ_ILL);
724                 M_ILL(EXCEPTION_HARDWARE_ARRAYSTORE);
725         }
726 }
727
728
729 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1) {
730         if (INSTRUCTION_MUST_CHECK(iptr)) {
731                 if (reg != RN) {
732                         M_TEST(reg);
733                 }
734                 switch (condition) {
735                         case BRANCH_LE:
736                                 M_BGT(SZ_BRC + SZ_ILL);
737                                 break;
738                         case BRANCH_EQ:
739                                 M_BNE(SZ_BRC + SZ_ILL);
740                                 break;
741                         case BRANCH_GT:
742                                 M_BLE(SZ_BRC + SZ_ILL);
743                                 break;
744                         default:
745                                 vm_abort("emit_classcast_check: unknown condition %d", condition);
746                 }
747                 M_ILL2(s1, EXCEPTION_HARDWARE_CLASSCAST);
748         }
749 }
750
751 void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg) {
752         if (INSTRUCTION_MUST_CHECK(iptr)) {
753                 M_TEST(reg);
754                 M_BNE(SZ_BRC + SZ_ILL);
755                 M_ILL(EXCEPTION_HARDWARE_NULLPOINTER);
756         }
757 }
758
759 void emit_exception_check(codegendata *cd, instruction *iptr) {
760         if (INSTRUCTION_MUST_CHECK(iptr)) {
761                 M_TEST(REG_RESULT);
762                 M_BNE(SZ_BRC + SZ_ILL);
763                 M_ILL(EXCEPTION_HARDWARE_EXCEPTION);
764         }
765 }
766
767 void emit_restore_pv(codegendata *cd) {
768         s4 offset, offset_imm;
769
770         /*
771         N_BASR(REG_PV, RN);
772         disp = (s4) (cd->mcodeptr - cd->mcodebase);
773         M_ASUB_IMM32(disp, REG_ITMP1, REG_PV);
774         */
775
776         /* If the offset from the method start does not fit into an immediate
777          * value, we can't put it into the data segment!
778          */
779
780         /* Displacement from start of method to here */
781
782         offset = (s4) (cd->mcodeptr - cd->mcodebase);
783         offset_imm = -offset - SZ_BASR + N_PV_OFFSET;
784
785         if (N_VALID_IMM(offset_imm)) {
786                 /* Get program counter */
787                 N_BASR(REG_PV, RN);
788                 /* Substract displacement */
789                 M_AADD_IMM(offset_imm, REG_PV);
790         } else {
791                 /* Save program counter and jump over displacement in instruction flow */
792                 N_BRAS(REG_PV, SZ_BRAS + SZ_LONG);
793                 /* Place displacement here */
794                 /* REG_PV points now exactly to this position */
795                 N_LONG(-offset - SZ_BRAS + N_PV_OFFSET);
796                 /* Substract *(REG_PV) from REG_PV */
797                 N_A(REG_PV, 0, RN, REG_PV);
798         }
799 }
800
801 /* emit_trap_compiler **********************************************************
802
803    Emit a trap instruction which calls the JIT compiler.
804
805 *******************************************************************************/
806
807 void emit_trap_compiler(codegendata *cd)
808 {
809         M_ILL2(REG_METHODPTR, EXCEPTION_HARDWARE_COMPILER);
810 }
811
812 /*
813  * These are local overrides for various environment variables in Emacs.
814  * Please do not remove this and leave it at the end of the file, where
815  * Emacs will automagically detect them.
816  * ---------------------------------------------------------------------
817  * Local variables:
818  * mode: c
819  * indent-tabs-mode: t
820  * c-basic-offset: 4
821  * tab-width: 4
822  * End:
823  */